-module(aws@internal@ini). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/aws/internal/ini.gleam"). -export([parse/1, get_property/3]). -export_type([parse_error/0, line_kind/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Minimal INI parser, sized for the AWS shared credentials file and the\n" " flat parts of `~/.aws/config`. Supports the subset:\n" "\n" " - `[section-name]` headers\n" " - `key = value` properties (whitespace around `=` trimmed)\n" " - `#` and `;` whole-line comments\n" " - blank lines\n" "\n" " Out of scope for now (we'll grow into these when SSO and assume-role\n" " providers need them):\n" "\n" " - line continuation for multi-line values\n" " - sub-properties (nested key/value inside a property)\n" " - inline `#`/`;` comments mid-value\n" "\n" " Errors carry the offending line number so the surfaced message can\n" " point the user at the broken line of their credentials file.\n" ). -type parse_error() :: {parse_error, integer(), binary()}. -type line_kind() :: blank | comment | {section, binary()} | {property, binary(), binary()} | {malformed, binary()}. -file("src/aws/internal/ini.gleam", 123). -spec commit_section( binary(), gleam@dict:dict(binary(), binary()), gleam@dict:dict(binary(), gleam@dict:dict(binary(), binary())) ) -> gleam@dict:dict(binary(), gleam@dict:dict(binary(), binary())). commit_section(Name, Props, Ini) -> case Name of <<""/utf8>> -> Ini; _ -> gleam@dict:insert(Ini, Name, Props) end. -file("src/aws/internal/ini.gleam", 109). -spec classify_property(binary()) -> line_kind(). classify_property(Line) -> case gleam@string:split_once(Line, <<"="/utf8>>) of {error, _} -> {malformed, <<"expected 'key = value'"/utf8>>}; {ok, {Key, Value}} -> Key@1 = gleam@string:trim(Key), Value@1 = gleam@string:trim(Value), case Key@1 of <<""/utf8>> -> {malformed, <<"property name is empty"/utf8>>}; _ -> {property, Key@1, Value@1} end end. -file("src/aws/internal/ini.gleam", 97). -spec classify_section(binary()) -> line_kind(). classify_section(Line) -> case gleam_stdlib:string_ends_with(Line, <<"]"/utf8>>) of false -> {malformed, <<"section header missing closing ']'"/utf8>>}; true -> Inner = gleam@string:slice(Line, 1, string:length(Line) - 2), {section, gleam@string:trim(Inner)} end. -file("src/aws/internal/ini.gleam", 85). -spec classify(binary()) -> line_kind(). classify(Line) -> case Line of <<""/utf8>> -> blank; _ -> case gleam@string:slice(Line, 0, 1) of <<"#"/utf8>> -> comment; <<";"/utf8>> -> comment; <<"["/utf8>> -> classify_section(Line); _ -> classify_property(Line) end end. -file("src/aws/internal/ini.gleam", 39). -spec parse_lines( list({integer(), binary()}), binary(), gleam@dict:dict(binary(), binary()), gleam@dict:dict(binary(), gleam@dict:dict(binary(), binary())) ) -> {ok, gleam@dict:dict(binary(), gleam@dict:dict(binary(), binary()))} | {error, parse_error()}. parse_lines(Lines, Current_section, Current_props, Ini) -> case Lines of [] -> {ok, commit_section(Current_section, Current_props, Ini)}; [{Line_no, Raw} | Rest] -> Trimmed = gleam@string:trim(Raw), case classify(Trimmed) of blank -> parse_lines(Rest, Current_section, Current_props, Ini); comment -> parse_lines(Rest, Current_section, Current_props, Ini); {section, Name} -> New_ini = commit_section( Current_section, Current_props, Ini ), parse_lines(Rest, Name, maps:new(), New_ini); {property, Key, Value} -> case Current_section of <<""/utf8>> -> {error, {parse_error, Line_no, <<<<"property '"/utf8, Key/binary>>/binary, "' outside any section"/utf8>>}}; _ -> parse_lines( Rest, Current_section, gleam@dict:insert(Current_props, Key, Value), Ini ) end; {malformed, Message} -> {error, {parse_error, Line_no, Message}} end end. -file("src/aws/internal/ini.gleam", 32). -spec parse(binary()) -> {ok, gleam@dict:dict(binary(), gleam@dict:dict(binary(), binary()))} | {error, parse_error()}. parse(Text) -> _pipe = Text, _pipe@1 = gleam@string:split(_pipe, <<"\n"/utf8>>), _pipe@2 = gleam@list:index_map(_pipe@1, fun(Line, I) -> {I + 1, Line} end), parse_lines(_pipe@2, <<""/utf8>>, maps:new(), maps:new()). -file("src/aws/internal/ini.gleam", 131). ?DOC(" Look up a single property value inside a section.\n"). -spec get_property( gleam@dict:dict(binary(), gleam@dict:dict(binary(), binary())), binary(), binary() ) -> {ok, binary()} | {error, nil}. get_property(Ini, Section, Key) -> gleam@result:'try'( gleam_stdlib:map_get(Ini, Section), fun(Props) -> gleam_stdlib:map_get(Props, Key) end ).