-module(jscheam). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -define(FILEPATH, "src/jscheam.gleam"). -export([prop/2, optional/1, description/2, string/0, integer/0, boolean/0, float/0, null/0, array/1, union/1, enum/2, pattern/2, object/1, allow_additional_props/1, disallow_additional_props/1, constrain_additional_props/2, to_json/1]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -file("src/jscheam.gleam", 13). ?DOC( " Creates a property with the specified name and type\n" " Properties are required by default\n" ). -spec prop(binary(), jscheam@property:type()) -> jscheam@property:property(). prop(Name, Property_type) -> {property, Name, Property_type, true, none, []}. -file("src/jscheam.gleam", 24). ?DOC(" Makes a property optional (not required in the schema)\n"). -spec optional(jscheam@property:property()) -> jscheam@property:property(). optional(Property) -> _record = Property, {property, erlang:element(2, _record), erlang:element(3, _record), false, erlang:element(5, _record), erlang:element(6, _record)}. -file("src/jscheam.gleam", 29). ?DOC(" Adds a description to a property for documentation purposes\n"). -spec description(jscheam@property:property(), binary()) -> jscheam@property:property(). description(Property, Desc) -> _record = Property, {property, erlang:element(2, _record), erlang:element(3, _record), erlang:element(4, _record), {some, Desc}, erlang:element(6, _record)}. -file("src/jscheam.gleam", 35). ?DOC(" Creates a string type for JSON Schema\n"). -spec string() -> jscheam@property:type(). string() -> string. -file("src/jscheam.gleam", 40). ?DOC(" Creates an integer/number type for JSON Schema\n"). -spec integer() -> jscheam@property:type(). integer() -> integer. -file("src/jscheam.gleam", 45). ?DOC(" Creates a boolean type for JSON Schema\n"). -spec boolean() -> jscheam@property:type(). boolean() -> boolean. -file("src/jscheam.gleam", 50). ?DOC(" Creates a float/number type for JSON Schema\n"). -spec float() -> jscheam@property:type(). float() -> float. -file("src/jscheam.gleam", 55). ?DOC(" Creates a null type for JSON Schema\n"). -spec null() -> jscheam@property:type(). null() -> null. -file("src/jscheam.gleam", 60). ?DOC(" Creates an array type with the specified item type\n"). -spec array(jscheam@property:type()) -> jscheam@property:type(). array(Item_type) -> {array, Item_type}. -file("src/jscheam.gleam", 66). ?DOC( " Creates a union type that accepts multiple types (e.g., string or null)\n" " Example: union([string(), null()]) creates a schema that accepts both strings and null values\n" ). -spec union(list(jscheam@property:type())) -> jscheam@property:type(). union(Types) -> {union, Types}. -file("src/jscheam.gleam", 72). ?DOC( " Adds an enum constraint to a property that restricts values to a fixed set\n" " Example: prop(\"color\", string()) |> enum(enum_strings([\"red\", \"green\", \"blue\"]))\n" ). -spec enum(jscheam@property:property(), list(gleam@json:json())) -> jscheam@property:property(). enum(Property, Values) -> New_constraint = {enum, Values}, _record = Property, {property, erlang:element(2, _record), erlang:element(3, _record), erlang:element(4, _record), erlang:element(5, _record), [New_constraint | erlang:element(6, Property)]}. -file("src/jscheam.gleam", 79). ?DOC( " Adds a pattern constraint to a property that restricts values to match a regex pattern\n" " Example: prop(\"phone\", string()) |> pattern(\"^(\\\\([0-9]{3}\\\\))?[0-9]{3}-[0-9]{4}$\")\n" ). -spec pattern(jscheam@property:property(), binary()) -> jscheam@property:property(). pattern(Property, Regex) -> New_constraint = {pattern, Regex}, _record = Property, {property, erlang:element(2, _record), erlang:element(3, _record), erlang:element(4, _record), erlang:element(5, _record), [New_constraint | erlang:element(6, Property)]}. -file("src/jscheam.gleam", 86). ?DOC( " Creates an object type with the specified properties\n" " By default allows any additional properties (JSON Schema default behavior - omits the field)\n" ). -spec object(list(jscheam@property:property())) -> jscheam@property:type(). object(Properties) -> {object, Properties, allow_any}. -file("src/jscheam.gleam", 91). ?DOC(" Explicitly allows any additional properties (outputs \"additionalProperties\": true)\n"). -spec allow_additional_props(jscheam@property:type()) -> jscheam@property:type(). allow_additional_props(Object_type) -> case Object_type of {object, Props, _} -> {object, Props, allow_explicit}; _ -> Object_type end. -file("src/jscheam.gleam", 100). ?DOC(" Disallows additional properties (outputs \"additionalProperties\": false)\n"). -spec disallow_additional_props(jscheam@property:type()) -> jscheam@property:type(). disallow_additional_props(Object_type) -> case Object_type of {object, Props, _} -> {object, Props, disallow}; _ -> Object_type end. -file("src/jscheam.gleam", 109). ?DOC(" Constrains additional properties to conform to the specified schema\n"). -spec constrain_additional_props( jscheam@property:type(), jscheam@property:type() ) -> jscheam@property:type(). constrain_additional_props(Object_type, Schema) -> case Object_type of {object, Props, _} -> {object, Props, {schema, Schema}}; _ -> Object_type end. -file("src/jscheam.gleam", 131). -spec type_to_type_string(jscheam@property:type()) -> binary(). type_to_type_string(Property_type) -> case Property_type of string -> <<"string"/utf8>>; integer -> <<"number"/utf8>>; boolean -> <<"boolean"/utf8>>; null -> <<"null"/utf8>>; float -> <<"number"/utf8>>; {object, _, _} -> <<"object"/utf8>>; {array, _} -> <<"array"/utf8>>; {union, _} -> erlang:error(#{gleam_error => panic, message => <<"Union types should not be converted to single type strings"/utf8>>, file => <>, module => <<"jscheam"/utf8>>, function => <<"type_to_type_string"/utf8>>, line => 141}) end. -file("src/jscheam.gleam", 234). -spec add_single_constraint_field( list({binary(), gleam@json:json()}), jscheam@property:constraint() ) -> list({binary(), gleam@json:json()}). add_single_constraint_field(Fields, Constraint) -> case Constraint of {enum, Values} -> [{<<"enum"/utf8>>, gleam@json:array(Values, fun(X) -> X end)} | Fields]; {pattern, Regex} -> [{<<"pattern"/utf8>>, gleam@json:string(Regex)} | Fields] end. -file("src/jscheam.gleam", 220). -spec add_constraint_fields( list({binary(), gleam@json:json()}), list(jscheam@property:constraint()) ) -> list({binary(), gleam@json:json()}). add_constraint_fields(Base_fields, Constraints) -> case Constraints of [] -> Base_fields; [Constraint | Rest] -> Fields_with_constraint = add_single_constraint_field( Base_fields, Constraint ), add_constraint_fields(Fields_with_constraint, Rest) end. -file("src/jscheam.gleam", 247). -spec fields_to_required(list(jscheam@property:property())) -> gleam@json:json(). fields_to_required(Fields) -> Required_fields = gleam@list:filter( Fields, fun(Property) -> {property, _, _, Is_required, _, _} = Property, Is_required end ), Names = gleam@list:map( Required_fields, fun(Property@1) -> {property, Name, _, _, _, _} = Property@1, gleam@json:string(Name) end ), gleam@json:array(Names, fun(X) -> X end). -file("src/jscheam.gleam", 145). -spec type_to_json_value(jscheam@property:type()) -> gleam@json:json(). type_to_json_value(Property_type) -> case Property_type of string -> gleam@json:object( [{<<"type"/utf8>>, gleam@json:string(type_to_type_string(Property_type))}] ); integer -> gleam@json:object( [{<<"type"/utf8>>, gleam@json:string(type_to_type_string(Property_type))}] ); boolean -> gleam@json:object( [{<<"type"/utf8>>, gleam@json:string(type_to_type_string(Property_type))}] ); null -> gleam@json:object( [{<<"type"/utf8>>, gleam@json:string(type_to_type_string(Property_type))}] ); float -> gleam@json:object( [{<<"type"/utf8>>, gleam@json:string(type_to_type_string(Property_type))}] ); {object, Props, Add_props} -> Properties_json = begin _pipe = gleam@list:map(Props, fun property_to_field/1), gleam@json:object(_pipe) end, Required_json = fields_to_required(Props), Additional_props_fields = additional_properties_to_json(Add_props), Base_fields = [{<<"type"/utf8>>, gleam@json:string(type_to_type_string(Property_type))}, {<<"properties"/utf8>>, Properties_json}, {<<"required"/utf8>>, Required_json}], gleam@json:object( lists:append(Base_fields, Additional_props_fields) ); {array, Item_type} -> gleam@json:object( [{<<"type"/utf8>>, gleam@json:string(type_to_type_string(Property_type))}, {<<"items"/utf8>>, type_to_json_value(Item_type)}] ); {union, Types} -> Type_strings = gleam@list:map(Types, fun type_to_type_string/1), gleam@json:object( [{<<"type"/utf8>>, gleam@json:array(Type_strings, fun gleam@json:string/1)}] ) end. -file("src/jscheam.gleam", 117). -spec additional_properties_to_json(jscheam@property:additional_properties()) -> list({binary(), gleam@json:json()}). additional_properties_to_json(Add_props) -> case Add_props of allow_any -> []; allow_explicit -> [{<<"additionalProperties"/utf8>>, gleam@json:bool(true)}]; disallow -> [{<<"additionalProperties"/utf8>>, gleam@json:bool(false)}]; {schema, Schema_type} -> [{<<"additionalProperties"/utf8>>, type_to_json_value(Schema_type)}] end. -file("src/jscheam.gleam", 276). ?DOC( " Converts a Type to a JSON Schema document\n" " This is the main function to generate JSON Schema from your type definitions\n" ). -spec to_json(jscheam@property:type()) -> gleam@json:json(). to_json(Object_type) -> type_to_json_value(Object_type). -file("src/jscheam.gleam", 191). -spec get_base_type_fields(jscheam@property:type()) -> list({binary(), gleam@json:json()}). get_base_type_fields(Property_type) -> case Property_type of string -> [{<<"type"/utf8>>, gleam@json:string(type_to_type_string(Property_type))}]; integer -> [{<<"type"/utf8>>, gleam@json:string(type_to_type_string(Property_type))}]; boolean -> [{<<"type"/utf8>>, gleam@json:string(type_to_type_string(Property_type))}]; null -> [{<<"type"/utf8>>, gleam@json:string(type_to_type_string(Property_type))}]; float -> [{<<"type"/utf8>>, gleam@json:string(type_to_type_string(Property_type))}]; {array, Item_type} -> [{<<"type"/utf8>>, gleam@json:string(type_to_type_string(Property_type))}, {<<"items"/utf8>>, type_to_json_value(Item_type)}]; {object, Props, Add_props} -> Properties_json = begin _pipe = gleam@list:map(Props, fun property_to_field/1), gleam@json:object(_pipe) end, Required_json = fields_to_required(Props), Additional_props_fields = additional_properties_to_json(Add_props), Base_fields = [{<<"type"/utf8>>, gleam@json:string(type_to_type_string(Property_type))}, {<<"properties"/utf8>>, Properties_json}, {<<"required"/utf8>>, Required_json}], lists:append(Base_fields, Additional_props_fields); {union, Types} -> Type_strings = gleam@list:map(Types, fun type_to_type_string/1), [{<<"type"/utf8>>, gleam@json:array(Type_strings, fun gleam@json:string/1)}] end. -file("src/jscheam.gleam", 174). -spec property_to_field(jscheam@property:property()) -> {binary(), gleam@json:json()}. property_to_field(Property) -> {property, Name, Property_type, _, Description, Constraints} = Property, Base_fields = get_base_type_fields(Property_type), Fields_with_constraints = add_constraint_fields(Base_fields, Constraints), Final_fields = case Description of {some, Desc} -> [{<<"description"/utf8>>, gleam@json:string(Desc)} | Fields_with_constraints]; none -> Fields_with_constraints end, {Name, gleam@json:object(Final_fields)}.