Packages
oaspec
0.10.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]).
-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())}.
-file("src/oaspec/generate.gleam", 105).
?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) ->
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,
erlang:element(6, 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,
erlang:element(6, Cfg)
)
end,
Validation_issues = begin
_pipe@3 = oaspec@codegen@validate:validate(Ctx),
oaspec@codegen@validate:filter_by_mode(
_pipe@3,
erlang:element(6, Cfg)
)
end,
Blocking_errors = oaspec@codegen@validate:errors_only(
Validation_issues
),
Validation_warnings = oaspec@codegen@validate:warnings_only(
Validation_issues
),
case gleam@list:is_empty(Blocking_errors) of
false ->
{error, {validation_errors, Blocking_errors}};
true ->
Warnings = lists:append(
[Capability_warnings,
Preserved_warnings,
Validation_warnings]
),
{ok, {validation_summary, Spec_title, Warnings}}
end
end)
end
).
-file("src/oaspec/generate.gleam", 170).
?DOC(" Generate shared files (types, decoders, encoders, middleware, guards).\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),
Middleware_files = oaspec@codegen@middleware:generate(Ctx),
Guard_files = oaspec@codegen@guards:generate(Ctx),
lists:append([Type_files, Decoder_files, Middleware_files, Guard_files]).
-file("src/oaspec/generate.gleam", 156).
?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 erlang:element(6, erlang:element(3, Ctx)) of
server ->
oaspec@codegen@server:generate(Ctx);
both ->
oaspec@codegen@server:generate(Ctx);
client ->
[]
end,
Client_files = case erlang:element(6, erlang:element(3, 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", 42).
?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) ->
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,
erlang:element(6, 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,
erlang:element(6, Cfg)
)
end,
Validation_issues = begin
_pipe@3 = oaspec@codegen@validate:validate(Ctx),
oaspec@codegen@validate:filter_by_mode(
_pipe@3,
erlang:element(6, Cfg)
)
end,
Blocking_errors = oaspec@codegen@validate:errors_only(
Validation_issues
),
Validation_warnings = oaspec@codegen@validate:warnings_only(
Validation_issues
),
case gleam@list:is_empty(Blocking_errors) of
false ->
{error, {validation_errors, Blocking_errors}};
true ->
Files = generate_all_files(Ctx),
Warnings = lists:append(
[Capability_warnings,
Preserved_warnings,
Validation_warnings]
),
{ok,
{generation_summary,
Files,
Spec_title,
Warnings}}
end
end)
end
).