-module(oaspec@config). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/oaspec/config.gleam"). -export([new/6, input/1, output_server/1, output_client/1, package/1, mode/1, validate/1, parse_mode/1, with_mode/2, with_validate/2, with_output/2, validate_output_package_match/1, error_to_string/1, load/1]). -export_type([config/0, generate_mode/0, config_error/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. -opaque config() :: {config, binary(), binary(), binary(), binary(), generate_mode(), boolean()}. -type generate_mode() :: server | client | both. -type config_error() :: {file_not_found, binary()} | {file_read_error, binary(), binary()} | {parse_error, binary()} | {missing_field, binary()} | {invalid_value, binary(), binary()}. -file("src/oaspec/config.gleam", 28). ?DOC( " Construct a new `Config` from its six fields. Prefer `load/1` in\n" " production code; `new/6` is primarily for tests and ad-hoc tooling\n" " that assembles a config in memory.\n" ). -spec new(binary(), binary(), binary(), binary(), generate_mode(), boolean()) -> config(). new(Input, Output_server, Output_client, Package, Mode, Validate) -> {config, Input, Output_server, Output_client, Package, Mode, Validate}. -file("src/oaspec/config.gleam", 40). ?DOC(" Path to the OpenAPI spec this config was built for.\n"). -spec input(config()) -> binary(). input(Cfg) -> erlang:element(2, Cfg). -file("src/oaspec/config.gleam", 45). ?DOC(" Output directory for server-side generated files.\n"). -spec output_server(config()) -> binary(). output_server(Cfg) -> erlang:element(3, Cfg). -file("src/oaspec/config.gleam", 50). ?DOC(" Output directory for client-side generated files.\n"). -spec output_client(config()) -> binary(). output_client(Cfg) -> erlang:element(4, Cfg). -file("src/oaspec/config.gleam", 55). ?DOC(" Gleam package name (module prefix) for generated files.\n"). -spec package(config()) -> binary(). package(Cfg) -> erlang:element(5, Cfg). -file("src/oaspec/config.gleam", 60). ?DOC(" Generation mode: server, client, or both.\n"). -spec mode(config()) -> generate_mode(). mode(Cfg) -> erlang:element(6, Cfg). -file("src/oaspec/config.gleam", 65). ?DOC(" Whether guard-based runtime validation is enabled.\n"). -spec validate(config()) -> boolean(). validate(Cfg) -> erlang:element(7, Cfg). -file("src/oaspec/config.gleam", 86). ?DOC(" Parse a mode string into GenerateMode.\n"). -spec parse_mode(binary()) -> {ok, generate_mode()} | {error, config_error()}. parse_mode(Mode) -> case Mode of <<"server"/utf8>> -> {ok, server}; <<"client"/utf8>> -> {ok, client}; <<"both"/utf8>> -> {ok, both}; _ -> {error, {invalid_value, <<"mode"/utf8>>, <<"must be one of: server, client, both"/utf8>>}} end. -file("src/oaspec/config.gleam", 184). ?DOC(" Apply CLI overrides to a config.\n"). -spec with_mode(config(), generate_mode()) -> config(). with_mode(Config, Mode) -> {config, erlang:element(2, Config), erlang:element(3, Config), erlang:element(4, Config), erlang:element(5, Config), Mode, erlang:element(7, Config)}. -file("src/oaspec/config.gleam", 189). ?DOC(" Apply validation mode override.\n"). -spec with_validate(config(), boolean()) -> config(). with_validate(Config, Validate) -> {config, erlang:element(2, Config), erlang:element(3, Config), erlang:element(4, Config), erlang:element(5, Config), erlang:element(6, Config), Validate}. -file("src/oaspec/config.gleam", 195). ?DOC( " Apply output base directory override.\n" " Derives server/client paths as / and _client/.\n" ). -spec with_output(config(), gleam@option:option(binary())) -> config(). with_output(Config, Output) -> case Output of {some, Dir} -> {config, erlang:element(2, Config), <<<>/binary, (erlang:element(5, Config))/binary>>, <<<>/binary, (erlang:element(5, Config))/binary>>, erlang:element(5, Config), erlang:element(6, Config), erlang:element(7, Config)}; none -> Config end. -file("src/oaspec/config.gleam", 247). ?DOC(" Get the basename of a path (last segment after /).\n"). -spec basename(binary()) -> binary(). basename(Path) -> _pipe = Path, _pipe@1 = gleam@string:split(_pipe, <<"/"/utf8>>), _pipe@2 = gleam@list:last(_pipe@1), gleam@result:unwrap(_pipe@2, <<""/utf8>>). -file("src/oaspec/config.gleam", 209). ?DOC( " Validate that output directory basenames match the package name.\n" " Gleam imports require `import /types`, so the directory must match.\n" ). -spec validate_output_package_match(config()) -> {ok, nil} | {error, config_error()}. validate_output_package_match(Config) -> _pipe = case erlang:element(6, Config) of server -> case basename(erlang:element(3, Config)) =:= erlang:element( 5, Config ) of true -> {ok, nil}; false -> {error, {invalid_value, <<"output.server"/utf8>>, <<<<<<<<"Directory basename '"/utf8, (basename(erlang:element(3, Config)))/binary>>/binary, "' must match package '"/utf8>>/binary, (erlang:element(5, Config))/binary>>/binary, "'"/utf8>>}} end; both -> case basename(erlang:element(3, Config)) =:= erlang:element( 5, Config ) of true -> {ok, nil}; false -> {error, {invalid_value, <<"output.server"/utf8>>, <<<<<<<<"Directory basename '"/utf8, (basename(erlang:element(3, Config)))/binary>>/binary, "' must match package '"/utf8>>/binary, (erlang:element(5, Config))/binary>>/binary, "'"/utf8>>}} end; client -> {ok, nil} end, gleam@result:'try'(_pipe, fun(_) -> case erlang:element(6, Config) of client -> case basename(erlang:element(4, Config)) =:= erlang:element( 5, Config ) of true -> {ok, nil}; false -> {error, {invalid_value, <<"output.client"/utf8>>, <<<<<<<<"Directory basename '"/utf8, (basename( erlang:element( 4, Config ) ))/binary>>/binary, "' must match package '"/utf8>>/binary, (erlang:element(5, Config))/binary>>/binary, "'"/utf8>>}} end; both -> case basename(erlang:element(4, Config)) =:= erlang:element( 5, Config ) of true -> {ok, nil}; false -> {error, {invalid_value, <<"output.client"/utf8>>, <<<<<<<<"Directory basename '"/utf8, (basename( erlang:element( 4, Config ) ))/binary>>/binary, "' must match package '"/utf8>>/binary, (erlang:element(5, Config))/binary>>/binary, "'"/utf8>>}} end; server -> {ok, nil} end end). -file("src/oaspec/config.gleam", 255). ?DOC(" Convert config error to a human-readable string.\n"). -spec error_to_string(config_error()) -> binary(). error_to_string(Error) -> case Error of {file_not_found, Path} -> <<"Config file not found: "/utf8, Path/binary>>; {file_read_error, Path@1, Detail} -> <<<<<<"Error reading config file "/utf8, Path@1/binary>>/binary, ": "/utf8>>/binary, Detail/binary>>; {parse_error, Detail@1} -> <<"Config parse error: "/utf8, Detail@1/binary>>; {missing_field, Field} -> <<"Missing required config field: "/utf8, Field/binary>>; {invalid_value, Field@1, Detail@2} -> <<<<<<"Invalid value for "/utf8, Field@1/binary>>/binary, ": "/utf8>>/binary, Detail@2/binary>> end. -file("src/oaspec/config.gleam", 268). ?DOC(" Extract a nested string value from YAML like output.server.\n"). -spec extract_nested_string(yay:node_(), binary(), binary()) -> gleam@option:option(binary()). extract_nested_string(Root, Key1, Key2) -> case yay:select_sugar( Root, <<<>/binary, Key2/binary>> ) of {ok, {node_str, Value}} -> {some, Value}; _ -> none end. -file("src/oaspec/config.gleam", 280). ?DOC(" Convert a yay YAML error to string.\n"). -spec yaml_error_to_string(yay:yaml_error()) -> binary(). yaml_error_to_string(Error) -> case Error of unexpected_parsing_error -> <<"Unexpected parsing error"/utf8>>; {parsing_error, Msg, _} -> Msg end. -file("src/oaspec/config.gleam", 100). ?DOC(" Load config from a YAML file.\n"). -spec load(binary()) -> {ok, config()} | {error, config_error()}. load(Path) -> gleam@result:'try'( begin _pipe = simplifile:read(Path), gleam@result:map_error(_pipe, fun(E) -> case E of enoent -> {file_not_found, Path}; _ -> {file_read_error, Path, <<"Failed to read file: "/utf8, (simplifile:describe_error(E))/binary>>} end end) end, fun(Content) -> gleam@result:'try'( begin _pipe@1 = yaml_ffi:parse_string(Content), gleam@result:map_error( _pipe@1, fun(E@1) -> {parse_error, <<"YAML parse error: "/utf8, (yaml_error_to_string(E@1))/binary>>} end ) end, fun(Docs) -> gleam@result:'try'(case Docs of [First | _] -> {ok, First}; [] -> {error, {parse_error, <<"Empty YAML document"/utf8>>}} end, fun(Doc) -> Root = yay:document_root(Doc), gleam@result:'try'( begin _pipe@2 = yay:extract_string( Root, <<"input"/utf8>> ), gleam@result:map_error( _pipe@2, fun(_) -> {missing_field, <<"input"/utf8>>} end ) end, fun(Input) -> Package = begin _pipe@3 = yay:extract_optional_string( Root, <<"package"/utf8>> ), _pipe@4 = gleam@result:unwrap( _pipe@3, none ), gleam@option:unwrap( _pipe@4, <<"api"/utf8>> ) end, Output_dir = begin _pipe@5 = extract_nested_string( Root, <<"output"/utf8>>, <<"dir"/utf8>> ), gleam@option:unwrap( _pipe@5, <<"./gen"/utf8>> ) end, Output_server = begin _pipe@6 = extract_nested_string( Root, <<"output"/utf8>>, <<"server"/utf8>> ), gleam@option:unwrap( _pipe@6, <<<>/binary, Package/binary>> ) end, Output_client = begin _pipe@7 = extract_nested_string( Root, <<"output"/utf8>>, <<"client"/utf8>> ), gleam@option:unwrap( _pipe@7, <<<>/binary, Package/binary>> ) end, gleam@result:'try'( case begin _pipe@8 = yay:extract_optional_string( Root, <<"mode"/utf8>> ), gleam@result:unwrap(_pipe@8, none) end of {some, <<"server"/utf8>>} -> {ok, server}; {some, <<"client"/utf8>>} -> {ok, client}; {some, <<"both"/utf8>>} -> {ok, both}; none -> {ok, both}; {some, Other} -> {error, {invalid_value, <<"mode"/utf8>>, <<<<"must be one of: server, client, both (got: "/utf8, Other/binary>>/binary, ")"/utf8>>}} end, fun(Mode) -> gleam@result:'try'( case yay:select_sugar( Root, <<"validate"/utf8>> ) of {ok, {node_bool, true}} -> {ok, true}; {ok, {node_str, <<"true"/utf8>>}} -> {ok, true}; {ok, {node_bool, false}} -> {ok, false}; {ok, {node_str, <<"false"/utf8>>}} -> {ok, false}; {error, _} -> {ok, false}; {ok, _} -> {error, {invalid_value, <<"validate"/utf8>>, <<"must be a boolean (true or false)"/utf8>>}} end, fun(Validate) -> {ok, {config, Input, Output_server, Output_client, Package, Mode, Validate}} end ) end ) end ) end) end ) end ).