Packages
oaspec
0.22.0
0.68.0
0.67.0
0.66.0
0.65.0
0.64.0
0.63.0
0.62.0
0.61.0
0.60.0
0.59.0
0.58.1
0.58.0
0.57.0
0.56.0
0.55.0
0.54.0
0.53.0
0.52.0
0.51.0
0.50.0
0.49.0
0.48.0
0.47.0
0.46.0
0.45.0
0.44.0
0.43.0
0.42.0
0.41.0
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.0
0.30.0
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.0
0.9.0
0.8.0
0.7.0
0.6.3
0.6.1
0.6.0
0.5.0
0.4.0
0.3.0
0.1.3
Generate Gleam code from OpenAPI 3.x specifications
Current section
Files
Jump to
Current section
Files
src/oaspec@generate.erl
-module(oaspec@generate).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/oaspec/generate.gleam").
-export([validate_only/2, generate_all_files/1, generate/2]).
-export_type([generation_summary/0, validation_summary/0, generate_error/0, prepared_context/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.
-type generation_summary() :: {generation_summary,
list(oaspec@codegen@context:generated_file()),
binary(),
list(oaspec@openapi@diagnostic:diagnostic())}.
-type validation_summary() :: {validation_summary,
binary(),
list(oaspec@openapi@diagnostic:diagnostic())}.
-type generate_error() :: {validation_errors,
list(oaspec@openapi@diagnostic:diagnostic())}.
-type prepared_context() :: {prepared_context,
oaspec@codegen@context:context(),
binary(),
list(oaspec@openapi@diagnostic:diagnostic())}.
-file("src/oaspec/generate.gleam", 47).
?DOC(
" Shared pipeline: normalize → resolve → capability_check → hoist → dedup → validate.\n"
" Returns a validated context with accumulated warnings, or errors.\n"
).
-spec prepare_context(
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved()),
oaspec@config:config()
) -> {ok, prepared_context()} | {error, generate_error()}.
prepare_context(Spec, Cfg) ->
Spec_title = <<<<(erlang:element(2, erlang:element(3, Spec)))/binary,
" v"/utf8>>/binary,
(erlang:element(4, erlang:element(3, Spec)))/binary>>,
Spec@1 = oaspec@openapi@normalize:normalize(Spec),
gleam@result:'try'(
begin
_pipe = oaspec@openapi@resolve:resolve(Spec@1),
gleam@result:map_error(
_pipe,
fun(Errors) -> {validation_errors, Errors} end
)
end,
fun(Spec@2) ->
Capability_issues = begin
_pipe@1 = oaspec@openapi@capability_check:check(Spec@2),
oaspec@codegen@validate:filter_by_mode(
_pipe@1,
oaspec@config:mode(Cfg)
)
end,
Capability_errors = oaspec@codegen@validate:errors_only(
Capability_issues
),
Capability_warnings = oaspec@codegen@validate:warnings_only(
Capability_issues
),
gleam@result:'try'(case gleam@list:is_empty(Capability_errors) of
false ->
{error, {validation_errors, Capability_errors}};
true ->
{ok, nil}
end, fun(_) ->
Spec@3 = oaspec@openapi@hoist:hoist(Spec@2),
Spec@4 = oaspec@openapi@dedup:dedup(Spec@3),
Ctx = oaspec@codegen@context:new(Spec@4, Cfg),
Preserved_warnings = begin
_pipe@2 = oaspec@openapi@capability_check:check_preserved(
Ctx
),
oaspec@openapi@diagnostic:filter_by_mode(
_pipe@2,
oaspec@config:mode(Cfg)
)
end,
Validation_issues = begin
_pipe@3 = oaspec@codegen@validate:validate(Ctx),
oaspec@codegen@validate:filter_by_mode(
_pipe@3,
oaspec@config:mode(Cfg)
)
end,
Blocking_errors = oaspec@codegen@validate:errors_only(
Validation_issues
),
Validation_warnings = oaspec@codegen@validate:warnings_only(
Validation_issues
),
gleam@result:'try'(
case gleam@list:is_empty(Blocking_errors) of
false ->
{error, {validation_errors, Blocking_errors}};
true ->
{ok, nil}
end,
fun(_) ->
Warnings = lists:append(
[Capability_warnings,
Preserved_warnings,
Validation_warnings]
),
{ok, {prepared_context, Ctx, Spec_title, Warnings}}
end
)
end)
end
).
-file("src/oaspec/generate.gleam", 121).
?DOC(
" Validation-only pipeline: parse → normalize → resolve → capability_check → hoist → dedup → validate.\n"
" Runs the same checks as generate() but skips code generation and file writing.\n"
).
-spec validate_only(
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved()),
oaspec@config:config()
) -> {ok, validation_summary()} | {error, generate_error()}.
validate_only(Spec, Cfg) ->
gleam@result:'try'(
prepare_context(Spec, Cfg),
fun(Prepared) ->
{ok,
{validation_summary,
erlang:element(3, Prepared),
erlang:element(4, Prepared)}}
end
).
-file("src/oaspec/generate.gleam", 153).
?DOC(
" Generate shared files (types, decoders, encoders, guards).\n"
"\n"
" `middleware.gleam` used to be emitted here too, but its `Handler` shape\n"
" did not actually compose with the generated client or server APIs (see\n"
" issue #116). It is no longer part of the default generated surface;\n"
" the `oaspec/codegen/middleware` module is kept only as a library-level\n"
" helper for consumers who want to assemble their own middleware chain.\n"
).
-spec generate_shared(oaspec@codegen@context:context()) -> list(oaspec@codegen@context:generated_file()).
generate_shared(Ctx) ->
Type_files = oaspec@codegen@types:generate(Ctx),
Decoder_files = oaspec@codegen@decoders:generate(Ctx),
Encoder_files = oaspec@codegen@encoders:generate(Ctx),
Guard_files = oaspec@codegen@guards:generate(Ctx),
lists:append([Type_files, Decoder_files, Encoder_files, Guard_files]).
-file("src/oaspec/generate.gleam", 133).
?DOC(" Pure file generation: produce all GeneratedFile values without any IO.\n").
-spec generate_all_files(oaspec@codegen@context:context()) -> list(oaspec@codegen@context:generated_file()).
generate_all_files(Ctx) ->
Shared = generate_shared(Ctx),
Server_files = case oaspec@config:mode(oaspec@codegen@context:config(Ctx)) of
server ->
oaspec@codegen@server:generate(Ctx);
both ->
oaspec@codegen@server:generate(Ctx);
client ->
[]
end,
Client_files = case oaspec@config:mode(oaspec@codegen@context:config(Ctx)) of
client ->
oaspec@codegen@client:generate(Ctx);
both ->
oaspec@codegen@client:generate(Ctx);
server ->
[]
end,
lists:append([Shared, Server_files, Client_files]).
-file("src/oaspec/generate.gleam", 106).
?DOC(
" Pure generation pipeline: parse → normalize → resolve → capability_check → hoist → dedup → validate → codegen.\n"
" Takes an already-parsed spec and config; returns generated files or errors.\n"
" Does not perform IO — callers handle writing files and printing output.\n"
).
-spec generate(
oaspec@openapi@spec:open_api_spec(oaspec@openapi@spec:unresolved()),
oaspec@config:config()
) -> {ok, generation_summary()} | {error, generate_error()}.
generate(Spec, Cfg) ->
gleam@result:'try'(
prepare_context(Spec, Cfg),
fun(Prepared) ->
Files = generate_all_files(erlang:element(2, Prepared)),
{ok,
{generation_summary,
Files,
erlang:element(3, Prepared),
erlang:element(4, Prepared)}}
end
).