Fix build errors and add complete dialyzer specs
- Remove erlc_paths and erlc_include_path from mix.exs (leftover from Gleam) - Add comprehensive dialyzer specs to Encoding module - Add missing dialyzer specs to EncodingUtils module - Ensure all public and private functions have proper type specifications This fixes the Docker build error about undefined erlc_paths function and ensures full dialyzer compliance. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
865fc90871
commit
648402a610
3 changed files with 28 additions and 2 deletions
|
|
@ -9,17 +9,20 @@ defmodule Aprsme.Encoding do
|
||||||
Sanitizes a binary to ensure it can be safely JSON encoded.
|
Sanitizes a binary to ensure it can be safely JSON encoded.
|
||||||
Handles latin1 conversion and removes control characters.
|
Handles latin1 conversion and removes control characters.
|
||||||
"""
|
"""
|
||||||
|
@spec sanitize_string(binary()) :: binary()
|
||||||
def sanitize_string(input) when is_binary(input) do
|
def sanitize_string(input) when is_binary(input) do
|
||||||
input
|
input
|
||||||
|> try_utf8_conversion()
|
|> try_utf8_conversion()
|
||||||
|> clean_control_characters()
|
|> clean_control_characters()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec sanitize_string(any()) :: binary()
|
||||||
def sanitize_string(_), do: ""
|
def sanitize_string(_), do: ""
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Type-safe float conversion with validation
|
Type-safe float conversion with validation
|
||||||
"""
|
"""
|
||||||
|
@spec to_float_safe(binary()) :: {:ok, float()} | nil
|
||||||
def to_float_safe(value) when is_binary(value) do
|
def to_float_safe(value) when is_binary(value) do
|
||||||
sanitized = value
|
sanitized = value
|
||||||
|> String.trim()
|
|> String.trim()
|
||||||
|
|
@ -33,20 +36,24 @@ defmodule Aprsme.Encoding do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec to_float_safe(any()) :: nil
|
||||||
def to_float_safe(_), do: nil
|
def to_float_safe(_), do: nil
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Convert binary to hex string
|
Convert binary to hex string
|
||||||
"""
|
"""
|
||||||
|
@spec to_hex(binary()) :: binary()
|
||||||
def to_hex(input) when is_binary(input) do
|
def to_hex(input) when is_binary(input) do
|
||||||
Base.encode16(input)
|
Base.encode16(input)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec to_hex(any()) :: binary()
|
||||||
def to_hex(_), do: ""
|
def to_hex(_), do: ""
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Check if a value looks like it has weather data
|
Check if a value looks like it has weather data
|
||||||
"""
|
"""
|
||||||
|
@spec has_weather_data(any(), any(), any(), any()) :: boolean()
|
||||||
def has_weather_data(temperature, humidity, wind_speed, pressure) do
|
def has_weather_data(temperature, humidity, wind_speed, pressure) do
|
||||||
not is_nil(temperature) or
|
not is_nil(temperature) or
|
||||||
not is_nil(humidity) or
|
not is_nil(humidity) or
|
||||||
|
|
@ -57,6 +64,12 @@ defmodule Aprsme.Encoding do
|
||||||
@doc """
|
@doc """
|
||||||
Get encoding information about a binary
|
Get encoding information about a binary
|
||||||
"""
|
"""
|
||||||
|
@spec encoding_info(binary()) :: %{
|
||||||
|
valid_utf8: boolean(),
|
||||||
|
byte_count: non_neg_integer(),
|
||||||
|
char_count: non_neg_integer() | nil,
|
||||||
|
invalid_at: non_neg_integer() | nil
|
||||||
|
}
|
||||||
def encoding_info(input) when is_binary(input) do
|
def encoding_info(input) when is_binary(input) do
|
||||||
byte_count = byte_size(input)
|
byte_count = byte_size(input)
|
||||||
|
|
||||||
|
|
@ -79,6 +92,12 @@ defmodule Aprsme.Encoding do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec encoding_info(any()) :: %{
|
||||||
|
valid_utf8: boolean(),
|
||||||
|
byte_count: non_neg_integer(),
|
||||||
|
char_count: nil,
|
||||||
|
invalid_at: nil
|
||||||
|
}
|
||||||
def encoding_info(_) do
|
def encoding_info(_) do
|
||||||
%{
|
%{
|
||||||
valid_utf8: false,
|
valid_utf8: false,
|
||||||
|
|
@ -90,6 +109,7 @@ defmodule Aprsme.Encoding do
|
||||||
|
|
||||||
# Private functions
|
# Private functions
|
||||||
|
|
||||||
|
@spec try_utf8_conversion(binary()) :: binary()
|
||||||
defp try_utf8_conversion(input) do
|
defp try_utf8_conversion(input) do
|
||||||
if String.valid?(input) do
|
if String.valid?(input) do
|
||||||
input
|
input
|
||||||
|
|
@ -99,6 +119,7 @@ defmodule Aprsme.Encoding do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec latin1_to_utf8(binary()) :: binary()
|
||||||
defp latin1_to_utf8(input) do
|
defp latin1_to_utf8(input) do
|
||||||
try do
|
try do
|
||||||
input
|
input
|
||||||
|
|
@ -110,6 +131,7 @@ defmodule Aprsme.Encoding do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec latin1_char_to_utf8(0..255) :: binary()
|
||||||
defp latin1_char_to_utf8(byte) when byte <= 127 do
|
defp latin1_char_to_utf8(byte) when byte <= 127 do
|
||||||
<<byte>>
|
<<byte>>
|
||||||
end
|
end
|
||||||
|
|
@ -120,6 +142,7 @@ defmodule Aprsme.Encoding do
|
||||||
<<0xC0 + div(byte, 64), 0x80 + rem(byte, 64)>>
|
<<0xC0 + div(byte, 64), 0x80 + rem(byte, 64)>>
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec clean_control_characters(binary()) :: binary()
|
||||||
defp clean_control_characters(s) do
|
defp clean_control_characters(s) do
|
||||||
s
|
s
|
||||||
|> String.graphemes()
|
|> String.graphemes()
|
||||||
|
|
@ -128,6 +151,7 @@ defmodule Aprsme.Encoding do
|
||||||
|> String.trim()
|
|> String.trim()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec valid_grapheme?(String.grapheme()) :: boolean()
|
||||||
defp valid_grapheme?(grapheme) do
|
defp valid_grapheme?(grapheme) do
|
||||||
case String.to_charlist(grapheme) do
|
case String.to_charlist(grapheme) do
|
||||||
[cp] ->
|
[cp] ->
|
||||||
|
|
@ -148,6 +172,7 @@ defmodule Aprsme.Encoding do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec find_invalid_byte_position(binary()) :: non_neg_integer() | nil
|
||||||
defp find_invalid_byte_position(input) do
|
defp find_invalid_byte_position(input) do
|
||||||
input
|
input
|
||||||
|> :binary.bin_to_list()
|
|> :binary.bin_to_list()
|
||||||
|
|
@ -159,6 +184,7 @@ defmodule Aprsme.Encoding do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec valid_utf8_continuation?(binary(), non_neg_integer()) :: boolean()
|
||||||
defp valid_utf8_continuation?(binary, pos) do
|
defp valid_utf8_continuation?(binary, pos) do
|
||||||
try do
|
try do
|
||||||
<<_::binary-size(pos), char::utf8, _::binary>> = binary
|
<<_::binary-size(pos), char::utf8, _::binary>> = binary
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ defmodule Aprsme.EncodingUtils do
|
||||||
def to_float(_), do: nil
|
def to_float(_), do: nil
|
||||||
|
|
||||||
# Helper to check if a float is finite (not infinity or NaN)
|
# Helper to check if a float is finite (not infinity or NaN)
|
||||||
|
@spec finite_float?(any()) :: boolean()
|
||||||
defp finite_float?(float) when is_float(float) do
|
defp finite_float?(float) when is_float(float) do
|
||||||
# In Elixir, we can't have infinity or NaN in regular floats
|
# In Elixir, we can't have infinity or NaN in regular floats
|
||||||
# This function is kept for defensive programming
|
# This function is kept for defensive programming
|
||||||
|
|
@ -319,6 +320,7 @@ defmodule Aprsme.EncodingUtils do
|
||||||
|
|
||||||
def sanitize_data_extended(data_extended), do: data_extended
|
def sanitize_data_extended(data_extended), do: data_extended
|
||||||
|
|
||||||
|
@spec sanitize_map_value(any()) :: any()
|
||||||
defp sanitize_map_value(val) when is_binary(val), do: sanitize_string(val)
|
defp sanitize_map_value(val) when is_binary(val), do: sanitize_string(val)
|
||||||
defp sanitize_map_value(val), do: val
|
defp sanitize_map_value(val), do: val
|
||||||
|
|
||||||
|
|
|
||||||
2
mix.exs
2
mix.exs
|
|
@ -9,8 +9,6 @@ defmodule Aprsme.MixProject do
|
||||||
archives: [],
|
archives: [],
|
||||||
compilers: Mix.compilers(),
|
compilers: Mix.compilers(),
|
||||||
elixirc_paths: elixirc_paths(Mix.env()),
|
elixirc_paths: elixirc_paths(Mix.env()),
|
||||||
erlc_paths: erlc_paths(Mix.env()),
|
|
||||||
erlc_include_path: "build/#{Mix.env()}/erlang/aprsme/include",
|
|
||||||
start_permanent: Mix.env() == :prod,
|
start_permanent: Mix.env() == :prod,
|
||||||
aliases: aliases(),
|
aliases: aliases(),
|
||||||
deps: deps(),
|
deps: deps(),
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue