-module(oaspec@openapi@resolver). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/oaspec/openapi/resolver.gleam"). -export([ref_to_name/1, resolve_schema_ref/2, resolve_schema_refs_in_schema/2]). -export_type([resolve_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 resolve_error() :: {unresolved_ref, binary()} | {circular_ref, binary()}. -file("src/oaspec/openapi/resolver.gleam", 21). ?DOC( " Resolve a $ref string to its schema name.\n" " Example: \"#/components/schemas/User\" -> \"User\"\n" ). -spec ref_to_name(binary()) -> binary(). ref_to_name(Ref) -> _pipe = Ref, _pipe@1 = gleam@string:split(_pipe, <<"/"/utf8>>), _pipe@2 = gleam@list:last(_pipe@1), gleam@result:unwrap(_pipe@2, <<"Unknown"/utf8>>). -file("src/oaspec/openapi/resolver.gleam", 38). ?DOC(" Internal resolver that tracks visited refs for cycle detection.\n"). -spec resolve_schema_ref_with_seen( oaspec@openapi@schema:schema_ref(), oaspec@openapi@spec:open_api_spec(), gleam@set:set(binary()) ) -> {ok, oaspec@openapi@schema:schema_object()} | {error, resolve_error()}. resolve_schema_ref_with_seen(Schema_ref, Spec, Seen) -> case Schema_ref of {inline, Schema} -> {ok, Schema}; {reference, Ref} -> case gleam@set:contains(Seen, Ref) of true -> {error, {circular_ref, Ref}}; false -> New_seen = gleam@set:insert(Seen, Ref), case erlang:element(5, Spec) of {some, Components} -> Name = ref_to_name(Ref), case gleam_stdlib:map_get( erlang:element(2, Components), Name ) of {ok, {inline, Schema@1}} -> {ok, Schema@1}; {ok, {reference, Inner_ref}} -> resolve_schema_ref_with_seen( {reference, Inner_ref}, Spec, New_seen ); {error, _} -> {error, {unresolved_ref, Ref}} end; none -> {error, {unresolved_ref, Ref}} end end end. -file("src/oaspec/openapi/resolver.gleam", 30). ?DOC( " Resolve a SchemaRef to a SchemaObject, looking up $ref in components.\n" " Tracks seen refs to detect circular references.\n" ). -spec resolve_schema_ref( oaspec@openapi@schema:schema_ref(), oaspec@openapi@spec:open_api_spec() ) -> {ok, oaspec@openapi@schema:schema_object()} | {error, resolve_error()}. resolve_schema_ref(Schema_ref, Spec) -> resolve_schema_ref_with_seen(Schema_ref, Spec, gleam@set:new()). -file("src/oaspec/openapi/resolver.gleam", 126). ?DOC(" Try to resolve a single ref, keeping it as-is if resolution fails.\n"). -spec resolve_one_ref( oaspec@openapi@schema:schema_ref(), oaspec@openapi@spec:open_api_spec() ) -> oaspec@openapi@schema:schema_ref(). resolve_one_ref(Schema_ref, Spec) -> case Schema_ref of {reference, Ref} -> case resolve_schema_ref(Schema_ref, Spec) of {ok, Schema} -> {inline, Schema}; {error, _} -> {reference, Ref} end; Inline -> Inline end. -file("src/oaspec/openapi/resolver.gleam", 138). ?DOC(" Map a list of schema refs, resolving each.\n"). -spec list_map_ref( list(oaspec@openapi@schema:schema_ref()), oaspec@openapi@spec:open_api_spec() ) -> list(oaspec@openapi@schema:schema_ref()). list_map_ref(Refs, Spec) -> gleam@list:map(Refs, fun(R) -> resolve_one_ref(R, Spec) end). -file("src/oaspec/openapi/resolver.gleam", 73). ?DOC(" Resolve all $ref in a schema object's nested schemas (one level).\n"). -spec resolve_schema_refs_in_schema( oaspec@openapi@schema:schema_object(), oaspec@openapi@spec:open_api_spec() ) -> oaspec@openapi@schema:schema_object(). resolve_schema_refs_in_schema(Schema, Spec) -> case Schema of {object_schema, Description, Properties, Required, Additional_properties, Additional_properties_untyped, Nullable} -> Resolved_props = gleam@dict:map_values( Properties, fun(_, V) -> resolve_one_ref(V, Spec) end ), Resolved_ap = case Additional_properties of {some, Ap} -> {some, resolve_one_ref(Ap, Spec)}; none -> none end, {object_schema, Description, Resolved_props, Required, Resolved_ap, Additional_properties_untyped, Nullable}; {array_schema, Description@1, Items, Min_items, Max_items, Nullable@1} -> {array_schema, Description@1, resolve_one_ref(Items, Spec), Min_items, Max_items, Nullable@1}; {all_of_schema, Description@2, Schemas} -> Resolved = list_map_ref(Schemas, Spec), {all_of_schema, Description@2, Resolved}; {one_of_schema, Description@3, Schemas@1, Discriminator} -> Resolved@1 = list_map_ref(Schemas@1, Spec), {one_of_schema, Description@3, Resolved@1, Discriminator}; {any_of_schema, Description@4, Schemas@2} -> Resolved@2 = list_map_ref(Schemas@2, Spec), {any_of_schema, Description@4, Resolved@2}; Other -> Other end.