-module(nori@cli). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/nori/cli.gleam"). -export([main/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( " CLI module for the OpenAPI library.\n" "\n" " Provides `generate`, `bundle`, and `validate` commands.\n" " Run with: `gleam run -m nori/cli`\n" ). -file("src/nori/cli.gleam", 254). -spec apply_output_override(nori@config:target_config(), binary()) -> nori@config:target_config(). apply_output_override(Tc, Output_override) -> case Output_override of <<""/utf8>> -> Tc; Dir -> {target_config, erlang:element(2, Tc), Dir, erlang:element(4, Tc), erlang:element(5, Tc)} end. -file("src/nori/cli.gleam", 264). -spec suffix(nori@config:target_config(), binary(), binary()) -> binary(). suffix(Tc, Base, Ext) -> case erlang:element(4, Tc) of true -> <<<>/binary, Ext/binary>>; false -> <> end. -file("src/nori/cli.gleam", 271). -spec ts_config_from_options(nori@config:target_config()) -> nori@codegen@typescript@types:config(). ts_config_from_options(Tc) -> Use_exports = case gleam_stdlib:map_get( erlang:element(5, Tc), <<"use_exports"/utf8>> ) of {ok, <<"true"/utf8>>} -> true; _ -> true end, Use_interfaces = case gleam_stdlib:map_get( erlang:element(5, Tc), <<"use_interfaces"/utf8>> ) of {ok, <<"true"/utf8>>} -> true; {ok, <<"false"/utf8>>} -> false; _ -> false end, Readonly_properties = case gleam_stdlib:map_get( erlang:element(5, Tc), <<"readonly_properties"/utf8>> ) of {ok, <<"true"/utf8>>} -> true; _ -> false end, {config, Use_exports, Use_interfaces, Readonly_properties}. -file("src/nori/cli.gleam", 356). -spec drop_prefix(binary(), binary()) -> binary(). drop_prefix(S, Prefix) -> case gleam_stdlib:string_starts_with(S, Prefix) of true -> gleam@string:drop_start(S, string:length(Prefix)); false -> S end. -file("src/nori/cli.gleam", 363). -spec drop_suffix(binary(), binary()) -> binary(). drop_suffix(S, Suffix) -> case gleam_stdlib:string_ends_with(S, Suffix) of true -> gleam@string:drop_end(S, string:length(Suffix)); false -> S end. -file("src/nori/cli.gleam", 331). ?DOC( " Derive a Gleam module prefix from the configured output directory.\n" "\n" " Looks for a `src/` segment anywhere in the path and takes everything after\n" " it (Gleam module paths are rooted at `src/`). Falls back to stripping a\n" " leading `./` if no `src/` is found.\n" "\n" " Examples:\n" " \"./src/generated\" -> \"generated\"\n" " \"src/generated\" -> \"generated\"\n" " \"/tmp/proj/src/api/gen\" -> \"api/gen\"\n" " \"./generated\" -> \"generated\" (no src/ — strip leading ./)\n" " \"src\" or \"./src\" -> \"\" (top-level — no prefix)\n" "\n" " Returning \"\" disables real-import emission and falls back to a comment hint.\n" ). -spec derive_module_prefix(binary()) -> binary(). derive_module_prefix(Dir) -> Trimmed = begin _pipe = Dir, _pipe@1 = gleam@string:trim(_pipe), drop_suffix(_pipe@1, <<"/"/utf8>>) end, Parts = gleam@string:split(Trimmed, <<"/src/"/utf8>>), case Parts of [_] -> case (Trimmed =:= <<"src"/utf8>>) orelse (Trimmed =:= <<"./src"/utf8>>) of true -> <<""/utf8>>; false -> _pipe@2 = Trimmed, _pipe@3 = drop_prefix(_pipe@2, <<"./"/utf8>>), drop_prefix(_pipe@3, <<"/"/utf8>>) end; _ -> _pipe@4 = Parts, _pipe@5 = gleam@list:last(_pipe@4), gleam@result:unwrap(_pipe@5, <<""/utf8>>) end. -file("src/nori/cli.gleam", 292). -spec generate_gleam(nori@codegen@ir:codegen_i_r(), nori@config:target_config()) -> list(nori@codegen@plugin:generated_file()). generate_gleam(Codegen_ir, Tc) -> Module_prefix = derive_module_prefix(erlang:element(3, Tc)), [{generated_file, <<<<(erlang:element(3, Tc))/binary, "/"/utf8>>/binary, (suffix(Tc, <<"types"/utf8>>, <<".gleam"/utf8>>))/binary>>, nori@codegen@gleam_types:generate(Codegen_ir)}, {generated_file, <<<<(erlang:element(3, Tc))/binary, "/"/utf8>>/binary, (suffix(Tc, <<"client"/utf8>>, <<".gleam"/utf8>>))/binary>>, nori@codegen@gleam_client:generate(Codegen_ir, Module_prefix)}, {generated_file, <<<<(erlang:element(3, Tc))/binary, "/"/utf8>>/binary, (suffix(Tc, <<"routes"/utf8>>, <<".gleam"/utf8>>))/binary>>, nori@codegen@gleam_routes:generate(Codegen_ir, Module_prefix)}, {generated_file, <<<<(erlang:element(3, Tc))/binary, "/"/utf8>>/binary, (suffix(Tc, <<"middleware"/utf8>>, <<".gleam"/utf8>>))/binary>>, nori@codegen@gleam_middleware:generate(Codegen_ir, Module_prefix)}]. -file("src/nori/cli.gleam", 370). -spec generate_typescript( nori@codegen@ir:codegen_i_r(), nori@config:target_config() ) -> list(nori@codegen@plugin:generated_file()). generate_typescript(Codegen_ir, Tc) -> _ = ts_config_from_options(Tc), [{generated_file, <<<<(erlang:element(3, Tc))/binary, "/"/utf8>>/binary, (suffix(Tc, <<"types"/utf8>>, <<".ts"/utf8>>))/binary>>, nori@codegen@typescript@types:generate(Codegen_ir)}, {generated_file, <<<<(erlang:element(3, Tc))/binary, "/"/utf8>>/binary, (suffix(Tc, <<"client"/utf8>>, <<".ts"/utf8>>))/binary>>, nori@codegen@typescript@fetch_client:generate(Codegen_ir)}]. -file("src/nori/cli.gleam", 387). -spec generate_react_query( nori@codegen@ir:codegen_i_r(), nori@config:target_config(), nori@config:target_config() ) -> list(nori@codegen@plugin:generated_file()). generate_react_query(Codegen_ir, Tc, Ts_tc) -> lists:append( [generate_typescript(Codegen_ir, Ts_tc), [{generated_file, <<<<(erlang:element(3, Tc))/binary, "/"/utf8>>/binary, (suffix(Tc, <<"hooks"/utf8>>, <<".ts"/utf8>>))/binary>>, nori@codegen@typescript@react_query:generate(Codegen_ir)}]] ). -file("src/nori/cli.gleam", 403). -spec generate_swr( nori@codegen@ir:codegen_i_r(), nori@config:target_config(), nori@config:target_config() ) -> list(nori@codegen@plugin:generated_file()). generate_swr(Codegen_ir, Tc, Ts_tc) -> lists:append( [generate_typescript(Codegen_ir, Ts_tc), [{generated_file, <<<<(erlang:element(3, Tc))/binary, "/"/utf8>>/binary, (suffix(Tc, <<"swr-hooks"/utf8>>, <<".ts"/utf8>>))/binary>>, nori@codegen@typescript@swr:generate(Codegen_ir)}]] ). -file("src/nori/cli.gleam", 419). -spec generate_fetch( nori@codegen@ir:codegen_i_r(), nori@config:target_config(), nori@config:target_config() ) -> list(nori@codegen@plugin:generated_file()). generate_fetch(Codegen_ir, _, Ts_tc) -> generate_typescript(Codegen_ir, Ts_tc). -file("src/nori/cli.gleam", 218). -spec generate_all_enabled( nori@codegen@ir:codegen_i_r(), nori@config:config(), binary() ) -> list(nori@codegen@plugin:generated_file()). generate_all_enabled(Codegen_ir, Cfg, Output_override) -> Out = erlang:element(3, Cfg), Gleam_tc = apply_output_override(erlang:element(2, Out), Output_override), Ts_tc = apply_output_override(erlang:element(3, Out), Output_override), Rq_tc = apply_output_override(erlang:element(4, Out), Output_override), Swr_tc = apply_output_override(erlang:element(5, Out), Output_override), Fetch_tc = apply_output_override(erlang:element(6, Out), Output_override), lists:append([case erlang:element(2, Gleam_tc) of true -> generate_gleam(Codegen_ir, Gleam_tc); false -> [] end, case erlang:element(2, Ts_tc) of true -> generate_typescript(Codegen_ir, Ts_tc); false -> [] end, case erlang:element(2, Rq_tc) of true -> generate_react_query(Codegen_ir, Rq_tc, Ts_tc); false -> [] end, case erlang:element(2, Swr_tc) of true -> generate_swr(Codegen_ir, Swr_tc, Ts_tc); false -> [] end, case erlang:element(2, Fetch_tc) of true -> generate_fetch(Codegen_ir, Fetch_tc, Ts_tc); false -> [] end]). -file("src/nori/cli.gleam", 175). -spec generate_files_from_config( nori@codegen@ir:codegen_i_r(), nori@config:config(), binary(), binary() ) -> list(nori@codegen@plugin:generated_file()). generate_files_from_config(Codegen_ir, Cfg, Target_override, Output_override) -> case Target_override of <<""/utf8>> -> generate_all_enabled(Codegen_ir, Cfg, Output_override); <<"all"/utf8>> -> generate_all_enabled(Codegen_ir, Cfg, Output_override); <<"gleam"/utf8>> -> generate_gleam( Codegen_ir, apply_output_override( erlang:element(2, erlang:element(3, Cfg)), Output_override ) ); <<"typescript"/utf8>> -> generate_typescript( Codegen_ir, apply_output_override( erlang:element(3, erlang:element(3, Cfg)), Output_override ) ); <<"react-query"/utf8>> -> generate_react_query( Codegen_ir, apply_output_override( erlang:element(4, erlang:element(3, Cfg)), Output_override ), apply_output_override( erlang:element(3, erlang:element(3, Cfg)), Output_override ) ); <<"swr"/utf8>> -> generate_swr( Codegen_ir, apply_output_override( erlang:element(5, erlang:element(3, Cfg)), Output_override ), apply_output_override( erlang:element(3, erlang:element(3, Cfg)), Output_override ) ); <<"fetch"/utf8>> -> generate_fetch( Codegen_ir, apply_output_override( erlang:element(6, erlang:element(3, Cfg)), Output_override ), apply_output_override( erlang:element(3, erlang:element(3, Cfg)), Output_override ) ); _ -> gleam_stdlib:println( <<"Unknown target: "/utf8, Target_override/binary>> ), [] end. -file("src/nori/cli.gleam", 445). -spec get_directory(binary()) -> binary(). get_directory(Path) -> Parts = gleam@string:split(Path, <<"/"/utf8>>), case erlang:length(Parts) of N when N > 1 -> _pipe = Parts, _pipe@1 = gleam@list:take(_pipe, N - 1), gleam@string:join(_pipe@1, <<"/"/utf8>>); _ -> <<"."/utf8>> end. -file("src/nori/cli.gleam", 427). -spec write_generated_files(list(nori@codegen@plugin:generated_file())) -> nil. write_generated_files(Files) -> gleam@list:each( Files, fun(File) -> Full_path = erlang:element(2, File), Dir = get_directory(Full_path), case simplifile:create_directory_all(Dir) of {ok, _} -> nil; {error, _} -> nil end, case simplifile:write(Full_path, erlang:element(3, File)) of {ok, _} -> gleam_stdlib:println(<<" Wrote: "/utf8, Full_path/binary>>); {error, _} -> gleam_stdlib:println( <<" Error writing: "/utf8, Full_path/binary>> ) end end ). -file("src/nori/cli.gleam", 49). -spec generate_command() -> glint:command(nil). generate_command() -> glint:command_help( <<"Generate code from an OpenAPI spec.\n\n"/utf8, "Targets: gleam, typescript, react-query, swr, fetch, all"/utf8>>, fun() -> glint:flag( begin _pipe = glint:string_flag(<<"target"/utf8>>), _pipe@1 = glint:flag_default(_pipe, <<""/utf8>>), glint:flag_help( _pipe@1, <<"Target: gleam, typescript, react-query, swr, fetch, all"/utf8>> ) end, fun(Target) -> glint:flag( begin _pipe@2 = glint:string_flag(<<"output"/utf8>>), _pipe@3 = glint:flag_default(_pipe@2, <<""/utf8>>), glint:flag_help( _pipe@3, <<"Output directory for generated files"/utf8>> ) end, fun(Output) -> glint:flag( begin _pipe@4 = glint:string_flag( <<"config"/utf8>> ), _pipe@5 = glint:flag_default( _pipe@4, <<"nori.config.yaml"/utf8>> ), glint:flag_help( _pipe@5, <<"Path to config file"/utf8>> ) end, fun(Config_path) -> glint:flag( begin _pipe@6 = glint:string_flag( <<"spec"/utf8>> ), _pipe@7 = glint:flag_default( _pipe@6, <<""/utf8>> ), glint:flag_help( _pipe@7, <<"Path to OpenAPI spec file (overrides config)"/utf8>> ) end, fun(Spec_arg) -> glint:flag( begin _pipe@8 = glint:bool_flag( <<"allow-unsupported"/utf8>> ), _pipe@9 = glint:flag_default( _pipe@8, false ), glint:flag_help( _pipe@9, <<"Generate even if the spec uses capabilities nori does not support yet (output may be incomplete)"/utf8>> ) end, fun(Allow_unsupported) -> glint:command( fun(_, _, Flags) -> Target_val@1 = case Target( Flags ) of {ok, Target_val} -> Target_val; _assert_fail -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"nori/cli"/utf8>>, function => <<"generate_command"/utf8>>, line => 85, value => _assert_fail, start => 2635, 'end' => 2676, pattern_start => 2646, pattern_end => 2660} ) end, Output_dir@1 = case Output( Flags ) of {ok, Output_dir} -> Output_dir; _assert_fail@1 -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"nori/cli"/utf8>>, function => <<"generate_command"/utf8>>, line => 86, value => _assert_fail@1, start => 2679, 'end' => 2720, pattern_start => 2690, pattern_end => 2704} ) end, Config_file@1 = case Config_path( Flags ) of {ok, Config_file} -> Config_file; _assert_fail@2 -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"nori/cli"/utf8>>, function => <<"generate_command"/utf8>>, line => 87, value => _assert_fail@2, start => 2723, 'end' => 2770, pattern_start => 2734, pattern_end => 2749} ) end, Spec_override@1 = case Spec_arg( Flags ) of {ok, Spec_override} -> Spec_override; _assert_fail@3 -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"nori/cli"/utf8>>, function => <<"generate_command"/utf8>>, line => 88, value => _assert_fail@3, start => 2773, 'end' => 2819, pattern_start => 2784, pattern_end => 2801} ) end, Allow_unsupported_val@1 = case Allow_unsupported( Flags ) of {ok, Allow_unsupported_val} -> Allow_unsupported_val; _assert_fail@4 -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"nori/cli"/utf8>>, function => <<"generate_command"/utf8>>, line => 89, value => _assert_fail@4, start => 2822, 'end' => 2885, pattern_start => 2833, pattern_end => 2858} ) end, Cfg = case nori@config:load( Config_file@1 ) of {ok, C} -> C; {error, _} -> nori@config:default( ) end, Spec = case Spec_override@1 of <<""/utf8>> -> erlang:element( 2, Cfg ); S -> S end, gleam_stdlib:println( <<"Parsing spec: "/utf8, Spec/binary>> ), case nori@yaml:parse_file( Spec ) of {error, Err} -> gleam_stdlib:println( <<"Error: Failed to parse spec file"/utf8>> ), case Err of {file_error, Path, Msg} -> gleam_stdlib:println( <<<<<<" File error ("/utf8, Path/binary>>/binary, "): "/utf8>>/binary, Msg/binary>> ); {yaml_syntax_error, Msg@1} -> gleam_stdlib:println( <<" YAML syntax error: "/utf8, Msg@1/binary>> ); {yaml_decode_error, _} -> gleam_stdlib:println( <<" Failed to decode OpenAPI document"/utf8>> ) end; {ok, Doc} -> Proceed = case nori@capability:check( Doc ) of {ok, _} -> true; {error, Issues} -> gleam_stdlib:println( <<""/utf8>> ), gleam_stdlib:println( <<<<<<"Spec uses "/utf8, (erlang:integer_to_binary( erlang:length( Issues ) ))/binary>>/binary, " unsupported capabilit"/utf8>>/binary, (case erlang:length( Issues ) of 1 -> <<"y:"/utf8>>; _ -> <<"ies:"/utf8>> end)/binary>> ), gleam@list:each( Issues, fun( Issue ) -> gleam_stdlib:println( nori@capability:issue_to_string( Issue ) ) end ), gleam_stdlib:println( <<""/utf8>> ), case Allow_unsupported_val@1 of true -> gleam_stdlib:println( <<"Continuing anyway (--allow-unsupported); generated code may be incomplete."/utf8>> ), true; false -> gleam_stdlib:println( <<"Aborting. Pass --allow-unsupported to generate with degraded output."/utf8>> ), false end end, case Proceed of false -> nil; true -> gleam_stdlib:println( <<"Building IR..."/utf8>> ), Codegen_ir = nori@codegen@ir_builder:build( Doc ), Files = generate_files_from_config( Codegen_ir, Cfg, Target_val@1, Output_dir@1 ), case Files of [] -> gleam_stdlib:println( <<"No files generated. Check your target or config."/utf8>> ); _ -> write_generated_files( Files ), gleam_stdlib:println( <<<<"Generated "/utf8, (erlang:integer_to_binary( erlang:length( Files ) ))/binary>>/binary, " file(s)"/utf8>> ) end end end end ) end ) end ) end ) end ) end ) end ). -file("src/nori/cli.gleam", 512). -spec write_init_file(binary(), binary()) -> nil. write_init_file(Path, Content) -> case simplifile_erl:is_file(Path) of {ok, true} -> gleam_stdlib:println(<<" Exists: "/utf8, Path/binary>>); _ -> case simplifile:write(Path, Content) of {ok, _} -> gleam_stdlib:println(<<" Created: "/utf8, Path/binary>>); {error, _} -> gleam_stdlib:println( <<" Error creating "/utf8, Path/binary>> ) end end. -file("src/nori/cli.gleam", 524). -spec init_config() -> binary(). init_config() -> <<"# nori.config.yaml — Configuration for OpenAPI code generation # # Run: gleam run -m nori/cli -- generate # Docs: See nori.config.example.yaml for all options # Path to your OpenAPI spec spec: ./nori.yaml # Output configuration per target output: gleam: enabled: true dir: ./src/generated generated_suffix: false typescript: enabled: true dir: ./src/api generated_suffix: true use_interfaces: true use_exports: true readonly_properties: false react_query: enabled: false swr: enabled: false fetch: enabled: false "/utf8>>. -file("src/nori/cli.gleam", 559). -spec init_openapi_spec() -> binary(). init_openapi_spec() -> <<"openapi: \"3.1.0\" info: title: My API version: \"1.0.0\" description: Your API description here servers: - url: http://localhost:3000 paths: /health: get: operationId: healthCheck summary: Health check responses: \"200\": description: OK content: application/json: schema: type: object properties: ok: type: boolean required: - ok "/utf8>>. -file("src/nori/cli.gleam", 587). -spec init_ts_types_template() -> binary(). init_ts_types_template() -> <<"// Generated by nori - Do not edit manually // // Edit templates/typescript_types.hbs to customize this output. // Available context variables: // types[] — list of type definitions // .is_record — true for object types (has .fields[]) // .is_enum — true for enum types (has .enum_values) // .is_union — true for union types (has .union_members) // .is_alias — true for type aliases (has .alias_target) // .name — type name (PascalCase) // .description — optional JSDoc description // .use_exports — whether to add 'export' keyword // .use_interfaces — whether to use 'interface' vs 'type' // fields[] — list of fields (inside is_record) // .name — field name // .ts_type — TypeScript type string // .optional — true if field is optional (adds ?) // .readonly — true if readonly modifier {{#each types}} {{#if is_record}} {{#if has_description}} /** {{description}} */ {{/if}} {{#if use_exports}}export {{/if}}{{#if use_interfaces}}interface {{name}} { {{/if}}{{#unless use_interfaces}}type {{name}} = { {{/unless}}{{#each fields}} {{#if readonly}}readonly {{/if}}{{name}}{{#if optional}}?{{/if}}: {{ts_type}}; {{/each}} } {{/if}} {{#if is_enum}} {{#if has_description}} /** {{description}} */ {{/if}} {{#if use_exports}}export {{/if}}type {{name}} = {{enum_values}}; {{/if}} {{#if is_union}} {{#if has_description}} /** {{description}} */ {{/if}} {{#if use_exports}}export {{/if}}type {{name}} = {{union_members}}; {{/if}} {{#if is_alias}} {{#if has_description}} /** {{description}} */ {{/if}} {{#if use_exports}}export {{/if}}type {{name}} = {{alias_target}}; {{/if}} {{/each}} "/utf8>>. -file("src/nori/cli.gleam", 641). -spec init_ts_client_template() -> binary(). init_ts_client_template() -> <<"// Generated by nori - Do not edit manually // // Edit templates/typescript_client.hbs to customize this output. // Available context variables: // type_imports — import statement for types // config_type — ClientConfig interface definition // create_client — configure() factory function // functions[] — list of endpoint functions // .function_text — complete function source code {{type_imports}} {{config_type}} {{create_client}} {{#each functions}} {{function_text}} {{/each}} "/utf8>>. -file("src/nori/cli.gleam", 665). -spec init_ts_react_query_template() -> binary(). init_ts_react_query_template() -> <<"// Generated by nori - Do not edit manually // // Edit templates/typescript_react_query.hbs to customize this output. // Available context variables: // rq_imports — import { useQuery, useMutation } from '@tanstack/react-query' // type_imports — import types // client_imports — import client functions // key_factories[] — query key factory objects // .factory_text — complete factory source code // hooks[] — list of hook functions // .hook_text — complete hook source code {{rq_imports}} {{type_imports}} {{client_imports}} {{#if has_factories}} {{#each key_factories}} {{factory_text}} {{/each}} {{/if}} {{#each hooks}} {{hook_text}} {{/each}} "/utf8>>. -file("src/nori/cli.gleam", 695). -spec init_ts_swr_template() -> binary(). init_ts_swr_template() -> <<"// Generated by nori - Do not edit manually // // Edit templates/typescript_swr.hbs to customize this output. // Available context variables: // swr_imports — import useSWR from 'swr' // type_imports — import types // client_imports — import client functions // hooks[] — list of hook functions // .hook_text — complete hook source code {{swr_imports}} {{type_imports}} {{client_imports}} {{#each hooks}} {{hook_text}} {{/each}} "/utf8>>. -file("src/nori/cli.gleam", 460). -spec init_command() -> glint:command(nil). init_command() -> glint:command_help( <<"Initialize OpenAPI code generation in a Gleam project.\n\n"/utf8, "Creates config file, templates directory, and a starter spec."/utf8>>, fun() -> glint:command( fun(_, _, _) -> gleam_stdlib:println( <<"Initializing OpenAPI code generation..."/utf8>> ), case simplifile_erl:is_file(<<"nori.config.yaml"/utf8>>) of {ok, true} -> gleam_stdlib:println( <<" Exists: nori.config.yaml"/utf8>> ); _ -> case simplifile:write( <<"nori.config.yaml"/utf8>>, init_config() ) of {ok, _} -> gleam_stdlib:println( <<" Created: nori.config.yaml"/utf8>> ); {error, _} -> gleam_stdlib:println( <<" Error creating nori.config.yaml"/utf8>> ) end end, case simplifile:create_directory_all(<<"templates"/utf8>>) of {ok, _} -> nil; {error, _} -> nil end, write_init_file( <<"templates/typescript_types.hbs"/utf8>>, init_ts_types_template() ), write_init_file( <<"templates/typescript_client.hbs"/utf8>>, init_ts_client_template() ), write_init_file( <<"templates/typescript_react_query.hbs"/utf8>>, init_ts_react_query_template() ), write_init_file( <<"templates/typescript_swr.hbs"/utf8>>, init_ts_swr_template() ), case simplifile_erl:is_file(<<"nori.yaml"/utf8>>) of {ok, true} -> gleam_stdlib:println(<<" Exists: nori.yaml"/utf8>>); _ -> case simplifile:write( <<"nori.yaml"/utf8>>, init_openapi_spec() ) of {ok, _} -> gleam_stdlib:println( <<" Created: nori.yaml"/utf8>> ); {error, _} -> gleam_stdlib:println( <<" Error creating nori.yaml"/utf8>> ) end end, gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"Done! Next steps:"/utf8>>), gleam_stdlib:println( <<" 1. Edit nori.yaml with your API spec"/utf8>> ), gleam_stdlib:println( <<" 2. Edit nori.config.yaml to configure output"/utf8>> ), gleam_stdlib:println( <<" 3. Run: gleam run -m nori/cli -- generate"/utf8>> ), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println( <<"Customize templates in templates/*.hbs to change generated code."/utf8>> ) end ) end ). -file("src/nori/cli.gleam", 721). -spec bundle_command() -> glint:command(nil). bundle_command() -> glint:command_help( <<"Bundle a multi-file OpenAPI spec into a single file."/utf8>>, fun() -> glint:named_arg( <<"spec-path"/utf8>>, fun(Spec_path) -> glint:flag( begin _pipe = glint:string_flag(<<"output"/utf8>>), _pipe@1 = glint:flag_default( _pipe, <<"nori.gen.yaml"/utf8>> ), glint:flag_help( _pipe@1, <<"Output file path for the bundled spec"/utf8>> ) end, fun(Output) -> glint:command( fun(Named, _, Flags) -> Spec = Spec_path(Named), Output_file@1 = case Output(Flags) of {ok, Output_file} -> Output_file; _assert_fail -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"nori/cli"/utf8>>, function => <<"bundle_command"/utf8>>, line => 734, value => _assert_fail, start => 20460, 'end' => 20502, pattern_start => 20471, pattern_end => 20486} ) end, gleam_stdlib:println( <<"Bundling spec: "/utf8, Spec/binary>> ), case nori@bundler:bundle(Spec) of {error, Err} -> gleam_stdlib:println( <<"Error: Failed to bundle spec"/utf8>> ), case Err of {resolve_error, _} -> gleam_stdlib:println( <<" Reference resolution failed"/utf8>> ); {decode_error, Msg} -> gleam_stdlib:println( <<" Decode error: "/utf8, Msg/binary>> ) end; {ok, Yaml_str} -> case simplifile:write( Output_file@1, Yaml_str ) of {ok, _} -> gleam_stdlib:println( <<"Bundled spec written to: "/utf8, Output_file@1/binary>> ); {error, _} -> gleam_stdlib:println( <<"Error: Failed to write output file: "/utf8, Output_file@1/binary>> ) end end end ) end ) end ) end ). -file("src/nori/cli.gleam", 760). -spec validate_command() -> glint:command(nil). validate_command() -> glint:command_help( <<"Validate an OpenAPI spec."/utf8>>, fun() -> glint:named_arg( <<"spec-path"/utf8>>, fun(Spec_path) -> glint:command( fun(Named, _, _) -> Spec = Spec_path(Named), gleam_stdlib:println( <<"Validating spec: "/utf8, Spec/binary>> ), case nori@yaml:parse_file(Spec) of {error, Err} -> gleam_stdlib:println( <<"Error: Failed to parse spec file"/utf8>> ), case Err of {file_error, Path, Msg} -> gleam_stdlib:println( <<<<<<" File error ("/utf8, Path/binary>>/binary, "): "/utf8>>/binary, Msg/binary>> ); {yaml_syntax_error, Msg@1} -> gleam_stdlib:println( <<" YAML syntax error: "/utf8, Msg@1/binary>> ); {yaml_decode_error, _} -> gleam_stdlib:println( <<" Failed to decode OpenAPI document"/utf8>> ) end; {ok, Doc} -> case nori@validator:validate(Doc) of valid -> gleam_stdlib:println( <<"Spec is valid."/utf8>> ); {invalid, Errors} -> gleam_stdlib:println( <<<<"Spec has "/utf8, (erlang:integer_to_binary( erlang:length( Errors ) ))/binary>>/binary, " validation error(s):"/utf8>> ), gleam@list:each( Errors, fun(Err@1) -> gleam_stdlib:println( <<" - "/utf8, (nori@validator@errors:to_string( Err@1 ))/binary>> ) end ) end, case nori@capability:check(Doc) of {ok, _} -> nil; {error, Issues} -> gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println( <<<<<<"Spec uses "/utf8, (erlang:integer_to_binary( erlang:length( Issues ) ))/binary>>/binary, " unsupported capabilit"/utf8>>/binary, (case erlang:length(Issues) of 1 -> <<"y:"/utf8>>; _ -> <<"ies:"/utf8>> end)/binary>> ), gleam@list:each( Issues, fun(Issue) -> gleam_stdlib:println( nori@capability:issue_to_string( Issue ) ) end ) end end end ) end ) end ). -file("src/nori/cli.gleam", 33). -spec main() -> nil. main() -> _pipe = glint:new(), _pipe@1 = glint:with_name(_pipe, <<"nori/cli"/utf8>>), _pipe@2 = glint:as_module(_pipe@1), _pipe@3 = glint:pretty_help(_pipe@2, glint:default_pretty_help()), _pipe@4 = glint:add(_pipe@3, [<<"init"/utf8>>], init_command()), _pipe@5 = glint:add(_pipe@4, [<<"generate"/utf8>>], generate_command()), _pipe@6 = glint:add(_pipe@5, [<<"bundle"/utf8>>], bundle_command()), _pipe@7 = glint:add(_pipe@6, [<<"validate"/utf8>>], validate_command()), glint:run(_pipe@7, erlang:element(4, argv:load())).