Current section

Files

Jump to
oaspec src oaspec@generate.erl
Raw

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
).