@power-plant/schema 0.0.25 → 0.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/codegen.mjs CHANGED
@@ -1,5 +1,294 @@
1
- import{E as e,N as t,a as n,c as r,m as i,rt as a,u as o,z as s}from"./helpers-s2Zqtb-K.mjs";import{isSetString as c}from"@stryke/type-checks/is-set-string";import{isInteger as l,isObject as u,isSetArray as d,isString as f}from"@stryke/type-checks";import{list as p}from"@stryke/string-format/list";import{toBool as m}from"@stryke/convert/to-bool";import{camelCase as h}from"@stryke/string-format/camel-case";import{isBoolean as g}from"@stryke/type-checks/is-boolean";import{isNull as _}from"@stryke/type-checks/is-null";import{isNumber as v}from"@stryke/type-checks/is-number";import{isUndefined as y}from"@stryke/type-checks/is-undefined";function b(e,t){return y(e)?`undefined`:_(e)?`null`:t===`boolean`||g(e)?String(m(e)):t===`number`||v(e)?Number.parseFloat(String(e)).toLocaleString(void 0,{maximumFractionDigits:20}):t===`integer`?Number.parseInt(String(e)).toLocaleString():t===`string`||t===`object`||t===`array`?JSON.stringify(e):String(e)}function x(o){if(!o)return`unknown`;if(typeof o==`boolean`)return o?`unknown`:`never`;if(t(o)&&c(o.name))return o.name;let s=o;if(c(s.$ref))return/^#\/(?:definitions|\$defs)\/(.+)$/.exec(s.$ref)?.[1]??s.$ref;if(e(o)&&!y(o.const))return JSON.stringify(c(o.const)?o.const.replaceAll(/^['"`]|['"`]$/g,``):o.const);let l=a(o);if(l)return l===`integer`||l===`number`?`number`:l;if(s.type===`array`&&Array.isArray(s.enum))return s.enum.map(e=>JSON.stringify(e)).join(` | `);if(s.const!==void 0)return JSON.stringify(s.const);if(s.type===`array`||s.items)return`${x(Array.isArray(s.items)?s.items[0]:s.items)}[]`;if(s.type===`object`||s.properties||s.additionalProperties){if(i(s.additionalProperties))return`{ [key: string]: ${x(s.additionalProperties)} }`;if(t(s)){let e=s.required??[];return`{ ${n(s).map(t=>{let n=!e.includes(t.name)||r(t)?`${e.includes(t.name)?``:`?`}${r(t)?` | null`:``}`:``;return`${t.name}${n}: ${x(t)}`}).join(`;
2
- `)} }`}}return s.oneOf||s.anyOf?(s.oneOf??s.anyOf??[]).map(e=>x(e)).join(` | `):s.allOf?`object`:`unknown`}function S(e){return _(e)?`null`:g(e)?`boolean`:l(e)?`integer`:v(e)?`number`:f(e)?`string`:u(e)?`object`:Array.isArray(e)?`array`:void 0}function C(e){return/^#\/(?:definitions|\$defs)\/(.+)$/.exec(e)?.[1]}function w(e){let t=e.replace(/[^\w$]/gu,`_`);return`parse_${/^\d/u.test(t)?`_${t}`:t}`}function T(e){let t=e.type;return Array.isArray(t)?[...t]:t?[t]:[]}function E(e,t){return`${e} + ${JSON.stringify(t)}`}function D(e,l={}){let u=e,f=typeof u==`boolean`?{}:{...u.definitions,...u.$defs},m={};function g(e){let t=m[e]??0;return m[e]=t+1,`${e}${t>0?`${t}`:``}`}function _(e,t,n,i,a=`errors`){if(typeof e==`boolean`)return e?[`${i} = ${t};`]:[`${a}.push({ path: ${n}, failure: "No value is allowed at this location" });`,`${i} = ${t};`];if(c(e.$ref)){let r=C(e.$ref);return r&&r in f?[`${i} = ${w(r)}(${t}, ${n}, ${a});`]:[`${i} = ${t};`]}let o=g(e.name?`${h(e.name)}Value`:`value`),s=g(e.name?`${h(e.name)}Path`:`path`),u=[`const ${o} = ${t};`,`const ${s} = ${n};`];return!l.ignoreDefaults&&e.default!==void 0?(u.push(`if (${o} === undefined${e.type===`string`?` || ${o} === ""`:e.type===`number`||e.type===`integer`?` || Number.isNaN(${o})`:``}) {`,` ${i} = ${JSON.stringify(e.default)};`,`} else {`),r(e)?(u.push(` if (${o} === null) {`,` ${i} = null;`,` } else {`),u.push(...v(e,o,s,i,a)),u.push(` }`)):u.push(...v(e,o,s,i,a)),u.push(`}`),u):(u.push(`if (${o} === undefined) {`,` ${a}.push({ path: ${s}, failure: "A value is required" });`,` ${i} = ${o};`,`} else {`),r(e)?(u.push(` if (${o} === null) {`,` ${i} = null;`,` } else {`),u.push(...v(e,o,s,i,a)),u.push(` }`)):u.push(...v(e,o,s,i,a)),u.push(`}`),u)}function v(e,t,n,r,i){let s=[];if(e.const!==void 0){let a=JSON.stringify(e.const);return s.push(`if (${e.type===`string`?t:`JSON.stringify(${t})`} !== ${a}) { ${i}.push({ path: ${n}, failure: "Expected the constant value " + ${a} }); }`,`${r} = ${a};`),s}if(Array.isArray(e.enum)){let a=JSON.stringify(e.enum);return s.push(`if (!${a}.some(allowed => JSON.stringify(allowed) === JSON.stringify(${t}))) { ${i}.push({ path: ${n}, failure: \`Expected one of: ${p(e.enum.map(e=>JSON.stringify(e)),{conjunction:`or`})}, instead received: \${JSON.stringify(${t})}\` }); }`,`${r} = ${t};`),s}if(Array.isArray(e.oneOf)||Array.isArray(e.anyOf)){let a=e.oneOf??e.anyOf??[],o=g(e.name?`${h(e.name)}Matched`:`matched`);s.push(`let ${o} = false;`);for(let i of a){let a=g(e.name?`${h(e.name)}BranchErrors`:`branchErrors`),c=g(e.name?`${h(e.name)}BranchResult`:`branchResult`);s.push(`if (!${o}) {`),s.push(` const ${a}: { path: string; failure: string }[] = [];`,` let ${c};`),s.push(..._(i,t,n,c,a)),s.push(` if (${a}.length === 0) {`,` ${r} = ${c};`,` ${o} = true;`,` }`,`}`)}return s.push(`if (!${o}) {`,` ${i}.push({ path: ${n}, failure: \`The provided value \${JSON.stringify(${t})} does not match the allowed schemas\` });`,` ${r} = ${t};`,`}`),s}if(Array.isArray(e.allOf)){let{allOf:a,...c}=e,l=o(c,...a);return s.push(..._(l,t,n,r,i)),s}let c=T(e);switch(a(e)??c.find(e=>e!==`null`)??(e.properties?`object`:e.items?`array`:void 0)){case`object`:s.push(...y(e,t,n,r,i));break;case`array`:s.push(...b(e,t,n,r,i));break;case`string`:s.push(`if (typeof ${t} === "string") {`,` ${r} = ${t};`,`} else if (typeof ${t} === "number" || typeof ${t} === "boolean") {`,` ${r} = String(${t});`,`} else {`,` ${i}.push({ path: ${n}, failure: "Expected a string value" });`,` ${r} = ${t};`,`}`);break;case`integer`:s.push(`if (typeof ${t} === "number" && Number.isInteger(${t})) {`,` ${r} = ${t};`,`} else if (typeof ${t} === "string" && ${t}.trim() !== "" && Number.isInteger(Number(${t}))) {`,` ${r} = Number(${t});`,`} else if (typeof ${t} === "boolean") {`,` ${r} = ${t} ? 1 : 0;`,`} else {`,` ${i}.push({ path: ${n}, failure: "Expected an integer value" });`,` ${r} = ${t};`,`}`);break;case`number`:s.push(`if (typeof ${t} === "number") {`,` ${r} = ${t};`,`} else if (typeof ${t} === "string" && ${t}.trim() !== "" && !Number.isNaN(Number(${t}))) {`,` ${r} = Number(${t});`,`} else if (typeof ${t} === "boolean") {`,` ${r} = ${t} ? 1 : 0;`,`} else {`,` ${i}.push({ path: ${n}, failure: "Expected a number value" });`,` ${r} = ${t};`,`}`);break;case`boolean`:s.push(`if (typeof ${t} === "boolean") {`,` ${r} = ${t};`,`} else if ((typeof ${t} === "string" && (${t}.toLowerCase() === "true" || ${t}.toLowerCase() === "t" || ${t}.toLowerCase() === "yes" || ${t}.toLowerCase() === "y" || (!Number.isNaN(Number.parseInt(${t})) && Number.parseInt(${t}) > 0))) || (typeof ${t} === "number" && ${t} > 0)) {`,` ${r} = true;`,`} else if ((typeof ${t} === "string" && (${t}.toLowerCase() === "false" || ${t}.toLowerCase() === "f" || ${t}.toLowerCase() === "no" || ${t}.toLowerCase() === "n" || (!Number.isNaN(Number.parseInt(${t})) && Number.parseInt(${t}) <= 0))) || (typeof ${t} === "number" && ${t} <= 0)) {`,` ${r} = false;`,`} else {`,` ${i}.push({ path: ${n}, failure: "Expected a boolean value" });`,` ${r} = ${t};`,`}`);break;case`null`:s.push(`if (${t} === null) {`,` ${r} = null;`,`} else {`,` ${i}.push({ path: ${n}, failure: "Expected a null value" });`,` ${r} = ${t};`,`}`);break;case void 0:default:s.push(`${r} = ${t};`);break}return s}function y(e,r,a,o,c){let l=x(e),u=[`if (typeof ${r} !== "object" || ${r} === null || Array.isArray(${r})) {`,` ${c}.push({ path: ${a}, failure: "Expected an object value" });`,` ${o} = ${r};`,`} else {`],f=g(l||e.name?`${h(l||e.name)}Schema`:`schema`);if(u.push(`const ${f} = {} as Record<string, any>`),t(e)){let t=new Set;for(let i of n(e)){t.add(i.name);let e;d(i.alias)?(e=`(${i.alias.map(e=>`${r}[${JSON.stringify(e)}]`).join(` ${s(i)?`||`:`??`} `)} ${s(i)?`||`:`??`} ${r}[${JSON.stringify(i.name)}])`,i.alias.forEach(e=>t.add(e))):e=`${r}[${JSON.stringify(i.name)}]`;let n=E(a,`.${i.name}`),o=g(i.name?`${h(i.name)}Property`:`property`),l=i.default===void 0?i.required?`${c}.push({ path: ${n}, failure: "Required property is missing" });`:``:`${f}[${JSON.stringify(i.name)}] = ${JSON.stringify(i.default)};`;u.push(` if (${e} !== undefined) {`,` let ${o};`),u.push(..._(i,e,n,o,c)),u.push(`${f}[${JSON.stringify(i.name)}] = ${o};`),l?u.push(`} else { ${l} }`):u.push(`}`)}let o=e.additionalProperties;if(i(o)){let n=g(l||e.name?`${h(l||e.name)}AdditionalProperties`:`additionalProperties`);u.push(` for (const key of Object.keys(${r})) {`,` if (${JSON.stringify([...t])}.includes(key)) { continue; }`,` let ${n};`),u.push(..._(o,`${r}[key]`,`${a} + "." + key`,n,c)),u.push(`${f}[key] = ${n};`,`}`)}else o!==!1&&u.push(` for (const key of Object.keys(${r})) {`,` if (${JSON.stringify([...t])}.includes(key)) { continue; }`,` ${f}[key] = ${r}[key];`,`}`)}return u.push(`${o} = ${f};`,`}`),u}function b(e,t,n,r,i){let a=[`if (!Array.isArray(${t})) {`,` ${i}.push({ path: ${n}, failure: "Expected an array value" });`,` ${r} = ${t};`,`} else {`],o=g(e.name?`${h(e.name)}Array`:`array`);a.push(`const ${o}: unknown[] = [];`);let s=e.prefixItems??(Array.isArray(e.items)?e.items:void 0);if(s){let c=Array.isArray(e.items)?void 0:e.items;return a.push(` for (let index = 0; index < ${t}.length; index += 1) {`,` const item = ${t}[index];`,` let itemResult;`),s.forEach((e,t)=>{a.push(` ${t===0?`if`:`else if`} (index === ${t}) {`),a.push(..._(e,`item`,E(n,`[${t}]`),`itemResult`,i)),a.push(`}`)}),c?(a.push(`else {`),a.push(..._(c,`item`,`${n} + "[" + index + "]"`,`itemResult`,i)),a.push(`}`)):a.push(`else { itemResult = item; }`),a.push(` ${o}.push(itemResult);`,` }`,` ${r} = ${o};`,`}`),a}let c=e.items??!0;return a.push(` for (let index = 0; index < ${t}.length; index += 1) {`,` const item = ${t}[index];`,` let itemResult;`),a.push(..._(c,`item`,`${n} + "[" + index + "]"`,`itemResult`,i)),a.push(` ${o}.push(itemResult);`,` }`,` ${r} = ${o};`,`}`),a}return`/**
1
+ import { E as isJsonSchemaLiteral, N as isJsonSchemaObject, a as getPropertiesList, c as isSchemaNullable, m as isJsonSchema, rt as getPrimarySchemaType, u as merge, z as isJsonSchemaString } from "./helpers-reqtcaa8.mjs";
2
+ import { isSetString } from "@stryke/type-checks/is-set-string";
3
+ import { isInteger, isObject, isSetArray, isString } from "@stryke/type-checks";
4
+ import { list } from "@stryke/string-format/list";
5
+ import { toBool } from "@stryke/convert/to-bool";
6
+ import { camelCase } from "@stryke/string-format/camel-case";
7
+ import { isBoolean as isBoolean$1 } from "@stryke/type-checks/is-boolean";
8
+ import { isNull } from "@stryke/type-checks/is-null";
9
+ import { isNumber } from "@stryke/type-checks/is-number";
10
+ import { isUndefined } from "@stryke/type-checks/is-undefined";
11
+
12
+ //#region src/codegen.ts
13
+ /**
14
+ * Stringifies a value for generated TypeScript code.
15
+ */
16
+ function stringifyValue(value, type) {
17
+ return isUndefined(value) ? "undefined" : isNull(value) ? "null" : type === "boolean" || isBoolean$1(value) ? String(toBool(value)) : type === "number" || isNumber(value) ? Number.parseFloat(String(value)).toLocaleString(void 0, { maximumFractionDigits: 20 }) : type === "integer" ? Number.parseInt(String(value)).toLocaleString() : type === "string" || type === "object" || type === "array" ? JSON.stringify(value) : String(value);
18
+ }
19
+ /**
20
+ * Stringifies a JSON Schema fragment into a TypeScript-like type string.
21
+ */
22
+ function stringifyType(schema) {
23
+ if (!schema) return "unknown";
24
+ if (typeof schema === "boolean") return schema ? "unknown" : "never";
25
+ if (isJsonSchemaObject(schema) && isSetString(schema.name)) return schema.name;
26
+ const objectSchema = schema;
27
+ if (isSetString(objectSchema.$ref)) return /^#\/(?:definitions|\$defs)\/(.+)$/.exec(objectSchema.$ref)?.[1] ?? objectSchema.$ref;
28
+ if (isJsonSchemaLiteral(schema) && !isUndefined(schema.const)) return JSON.stringify(isSetString(schema.const) ? schema.const.replaceAll(/^['"`]|['"`]$/g, "") : schema.const);
29
+ const primaryType = getPrimarySchemaType(schema);
30
+ if (primaryType) {
31
+ if (primaryType === "integer" || primaryType === "number") return "number";
32
+ return primaryType;
33
+ }
34
+ if (objectSchema.type === "array" && Array.isArray(objectSchema.enum)) return objectSchema.enum.map((value) => JSON.stringify(value)).join(" | ");
35
+ if (objectSchema.const !== void 0) return JSON.stringify(objectSchema.const);
36
+ if (objectSchema.type === "array" || objectSchema.items) return `${stringifyType(Array.isArray(objectSchema.items) ? objectSchema.items[0] : objectSchema.items)}[]`;
37
+ if (objectSchema.type === "object" || objectSchema.properties || objectSchema.additionalProperties) {
38
+ if (isJsonSchema(objectSchema.additionalProperties)) return `{ [key: string]: ${stringifyType(objectSchema.additionalProperties)} }`;
39
+ if (isJsonSchemaObject(objectSchema)) {
40
+ const required = objectSchema.required ?? [];
41
+ return `{ ${getPropertiesList(objectSchema).map((property) => {
42
+ const suffix = !required.includes(property.name) || isSchemaNullable(property) ? `${!required.includes(property.name) ? "?" : ""}${isSchemaNullable(property) ? " | null" : ""}` : "";
43
+ return `${property.name}${suffix}: ${stringifyType(property)}`;
44
+ }).join(";\n")} }`;
45
+ }
46
+ }
47
+ if (objectSchema.oneOf || objectSchema.anyOf) return (objectSchema.oneOf ?? objectSchema.anyOf ?? []).map((branch) => stringifyType(branch)).join(" | ");
48
+ if (objectSchema.allOf) return "object";
49
+ return "unknown";
50
+ }
51
+ /**
52
+ * Returns a string type representation of a value based on its type and an optional JSON Schema primitive type hint.
53
+ *
54
+ * @param value - The value whose type is to be represented as a string.
55
+ * @returns A string representation of the value's type, which may be influenced by the provided JSON Schema primitive type hint. The function handles various JavaScript types and formats them accordingly, including special handling for `undefined`, `null`, booleans, numbers (with formatting), strings, objects, and arrays. If a specific type hint is provided, it will take precedence in determining the string representation of the value.
56
+ */
57
+ function getJsonSchemaType(value) {
58
+ return isNull(value) ? "null" : isBoolean$1(value) ? "boolean" : isInteger(value) ? "integer" : isNumber(value) ? "number" : isString(value) ? "string" : isObject(value) ? "object" : Array.isArray(value) ? "array" : void 0;
59
+ }
60
+ /**
61
+ * Resolves a local JSON Schema `$ref` (e.g. `#/$defs/Name`) to the referenced definition name.
62
+ */
63
+ function resolveLocalRefName(ref) {
64
+ return /^#\/(?:definitions|\$defs)\/(.+)$/.exec(ref)?.[1];
65
+ }
66
+ /**
67
+ * Converts an arbitrary definition name into a safe JavaScript identifier suffix.
68
+ */
69
+ function toParserIdentifier(name) {
70
+ const cleaned = name.replace(/[^\w$]/gu, "_");
71
+ return `parse_${/^\d/u.test(cleaned) ? `_${cleaned}` : cleaned}`;
72
+ }
73
+ /**
74
+ * Returns the list of JSON Schema `type` keyword values declared on a fragment,
75
+ * preserving `object` and `array` (which {@link readSchemaTypes} intentionally drops).
76
+ */
77
+ function readDeclaredTypes(schema) {
78
+ const type = schema.type;
79
+ if (Array.isArray(type)) return [...type];
80
+ return type ? [type] : [];
81
+ }
82
+ /**
83
+ * Generates a JavaScript expression that builds a path string for a child element.
84
+ */
85
+ function childPath(pathExpr, segment) {
86
+ return `${pathExpr} + ${JSON.stringify(segment)}`;
87
+ }
88
+ /**
89
+ * Generates standalone parser code for a JSON Schema.
90
+ *
91
+ * @remarks
92
+ * The generated `parse` function reads an arbitrary input value and converts it into the shape described by the schema. It walks the schema recursively to:
93
+ * - Resolve local `$ref` pointers (`#/$defs/*` and `#/definitions/*`) into dedicated parser functions so recursive schemas are supported,
94
+ * - If {@link GenerateParserCodeOptions.ignoreDefaults | options.ignoreDefaults} is not `true`, apply `default` values for object properties (and root/array values) that are missing from the input,
95
+ * - Coerce primitive values to the declared type (for example `"42"` to `42` for an `integer` schema, or `1` to `true` for a `boolean` schema),
96
+ * - Validate `const`, `enum`, `oneOf`/`anyOf` and `allOf` constraints, and
97
+ * - Collect detailed, path-aware errors and throw a `Error` when the input cannot be converted into a valid value.
98
+ *
99
+ * @param schema - The JSON Schema to generate parser code for.
100
+ * @param options - Options to customize the generated code. By default, the generated code will apply default values from the schema for missing properties and root/array values. Set `options.ignoreDefaults` to `true` to disable default value application.
101
+ * @returns The generated standalone parser code as a string.
102
+ */
103
+ function generateParserCode(schema, options = {}) {
104
+ const rootSchema = typeof schema === "boolean" ? schema : schema;
105
+ const definitions = typeof rootSchema === "boolean" ? {} : {
106
+ ...rootSchema.definitions,
107
+ ...rootSchema.$defs
108
+ };
109
+ const tempCounter = {};
110
+ function nextTemp(prefix) {
111
+ const id = tempCounter[prefix] ?? 0;
112
+ tempCounter[prefix] = id + 1;
113
+ return `${prefix}${id > 0 ? `${id}` : ""}`;
114
+ }
115
+ /**
116
+ * Generates inline parsing statements for a schema fragment.
117
+ */
118
+ function generateStatements(fragment, valueExpr, pathExpr, targetVar, errorsVar = "errors") {
119
+ if (typeof fragment === "boolean") return fragment ? [`${targetVar} = ${valueExpr};`] : [`${errorsVar}.push({ path: ${pathExpr}, failure: "No value is allowed at this location" });`, `${targetVar} = ${valueExpr};`];
120
+ if (isSetString(fragment.$ref)) {
121
+ const refName = resolveLocalRefName(fragment.$ref);
122
+ if (refName && refName in definitions) return [`${targetVar} = ${toParserIdentifier(refName)}(${valueExpr}, ${pathExpr}, ${errorsVar});`];
123
+ return [`${targetVar} = ${valueExpr};`];
124
+ }
125
+ const valueVar = nextTemp(fragment.name ? `${camelCase(fragment.name)}Value` : "value");
126
+ const pathVar = nextTemp(fragment.name ? `${camelCase(fragment.name)}Path` : "path");
127
+ const lines = [`const ${valueVar} = ${valueExpr};`, `const ${pathVar} = ${pathExpr};`];
128
+ if (!options.ignoreDefaults && fragment.default !== void 0) {
129
+ lines.push(`if (${valueVar} === undefined${fragment.type === "string" ? ` || ${valueVar} === ""` : fragment.type === "number" || fragment.type === "integer" ? ` || Number.isNaN(${valueVar})` : ""}) {`, ` ${targetVar} = ${JSON.stringify(fragment.default)};`, `} else {`);
130
+ if (isSchemaNullable(fragment)) {
131
+ lines.push(` if (${valueVar} === null) {`, ` ${targetVar} = null;`, ` } else {`);
132
+ lines.push(...generateCoreStatements(fragment, valueVar, pathVar, targetVar, errorsVar));
133
+ lines.push(` }`);
134
+ } else lines.push(...generateCoreStatements(fragment, valueVar, pathVar, targetVar, errorsVar));
135
+ lines.push(`}`);
136
+ return lines;
137
+ }
138
+ lines.push(`if (${valueVar} === undefined) {`, ` ${errorsVar}.push({ path: ${pathVar}, failure: "A value is required" });`, ` ${targetVar} = ${valueVar};`, `} else {`);
139
+ if (isSchemaNullable(fragment)) {
140
+ lines.push(` if (${valueVar} === null) {`, ` ${targetVar} = null;`, ` } else {`);
141
+ lines.push(...generateCoreStatements(fragment, valueVar, pathVar, targetVar, errorsVar));
142
+ lines.push(` }`);
143
+ } else lines.push(...generateCoreStatements(fragment, valueVar, pathVar, targetVar, errorsVar));
144
+ lines.push(`}`);
145
+ return lines;
146
+ }
147
+ /**
148
+ * Generates inline parsing statements assuming `value` is already defined.
149
+ */
150
+ function generateCoreStatements(schema, valueVar, pathVar, targetVar, errorsVar) {
151
+ const lines = [];
152
+ if (schema.const !== void 0) {
153
+ const constValue = JSON.stringify(schema.const);
154
+ lines.push(`if (${schema.type === "string" ? valueVar : `JSON.stringify(${valueVar})`} !== ${constValue}) { ${errorsVar}.push({ path: ${pathVar}, failure: "Expected the constant value " + ${constValue} }); }`, `${targetVar} = ${constValue};`);
155
+ return lines;
156
+ }
157
+ if (Array.isArray(schema.enum)) {
158
+ const enumValues = JSON.stringify(schema.enum);
159
+ lines.push(`if (!${enumValues}.some(allowed => JSON.stringify(allowed) === JSON.stringify(${valueVar}))) { ${errorsVar}.push({ path: ${pathVar}, failure: \`Expected one of: ${list(schema.enum.map((value) => JSON.stringify(value)), { conjunction: "or" })}, instead received: \${JSON.stringify(${valueVar})}\` }); }`, `${targetVar} = ${valueVar};`);
160
+ return lines;
161
+ }
162
+ if (Array.isArray(schema.oneOf) || Array.isArray(schema.anyOf)) {
163
+ const branches = schema.oneOf ?? schema.anyOf ?? [];
164
+ const matchedVar = nextTemp(schema.name ? `${camelCase(schema.name)}Matched` : "matched");
165
+ lines.push(`let ${matchedVar} = false;`);
166
+ for (const branch of branches) {
167
+ const branchErrorsVar = nextTemp(schema.name ? `${camelCase(schema.name)}BranchErrors` : "branchErrors");
168
+ const branchResultVar = nextTemp(schema.name ? `${camelCase(schema.name)}BranchResult` : "branchResult");
169
+ lines.push(`if (!${matchedVar}) {`);
170
+ lines.push(` const ${branchErrorsVar}: { path: string; failure: string }[] = [];`, ` let ${branchResultVar};`);
171
+ lines.push(...generateStatements(branch, valueVar, pathVar, branchResultVar, branchErrorsVar));
172
+ lines.push(` if (${branchErrorsVar}.length === 0) {`, ` ${targetVar} = ${branchResultVar};`, ` ${matchedVar} = true;`, ` }`, `}`);
173
+ }
174
+ lines.push(`if (!${matchedVar}) {`, ` ${errorsVar}.push({ path: ${pathVar}, failure: \`The provided value \${JSON.stringify(${valueVar})} does not match the allowed schemas\` });`, ` ${targetVar} = ${valueVar};`, `}`);
175
+ return lines;
176
+ }
177
+ if (Array.isArray(schema.allOf)) {
178
+ const { allOf, ...rest } = schema;
179
+ const merged = merge(rest, ...allOf);
180
+ lines.push(...generateStatements(merged, valueVar, pathVar, targetVar, errorsVar));
181
+ return lines;
182
+ }
183
+ const declaredTypes = readDeclaredTypes(schema);
184
+ switch (getPrimarySchemaType(schema) ?? declaredTypes.find((type) => type !== "null") ?? (schema.properties ? "object" : schema.items ? "array" : void 0)) {
185
+ case "object":
186
+ lines.push(...generateObjectStatements(schema, valueVar, pathVar, targetVar, errorsVar));
187
+ break;
188
+ case "array":
189
+ lines.push(...generateArrayStatements(schema, valueVar, pathVar, targetVar, errorsVar));
190
+ break;
191
+ case "string":
192
+ lines.push(`if (typeof ${valueVar} === "string") {`, ` ${targetVar} = ${valueVar};`, `} else if (typeof ${valueVar} === "number" || typeof ${valueVar} === "boolean") {`, ` ${targetVar} = String(${valueVar});`, `} else {`, ` ${errorsVar}.push({ path: ${pathVar}, failure: "Expected a string value" });`, ` ${targetVar} = ${valueVar};`, `}`);
193
+ break;
194
+ case "integer":
195
+ lines.push(`if (typeof ${valueVar} === "number" && Number.isInteger(${valueVar})) {`, ` ${targetVar} = ${valueVar};`, `} else if (typeof ${valueVar} === "string" && ${valueVar}.trim() !== "" && Number.isInteger(Number(${valueVar}))) {`, ` ${targetVar} = Number(${valueVar});`, `} else if (typeof ${valueVar} === "boolean") {`, ` ${targetVar} = ${valueVar} ? 1 : 0;`, `} else {`, ` ${errorsVar}.push({ path: ${pathVar}, failure: "Expected an integer value" });`, ` ${targetVar} = ${valueVar};`, `}`);
196
+ break;
197
+ case "number":
198
+ lines.push(`if (typeof ${valueVar} === "number") {`, ` ${targetVar} = ${valueVar};`, `} else if (typeof ${valueVar} === "string" && ${valueVar}.trim() !== "" && !Number.isNaN(Number(${valueVar}))) {`, ` ${targetVar} = Number(${valueVar});`, `} else if (typeof ${valueVar} === "boolean") {`, ` ${targetVar} = ${valueVar} ? 1 : 0;`, `} else {`, ` ${errorsVar}.push({ path: ${pathVar}, failure: "Expected a number value" });`, ` ${targetVar} = ${valueVar};`, `}`);
199
+ break;
200
+ case "boolean":
201
+ lines.push(`if (typeof ${valueVar} === "boolean") {`, ` ${targetVar} = ${valueVar};`, `} else if ((typeof ${valueVar} === "string" && (${valueVar}.toLowerCase() === "true" || ${valueVar}.toLowerCase() === "t" || ${valueVar}.toLowerCase() === "yes" || ${valueVar}.toLowerCase() === "y" || (!Number.isNaN(Number.parseInt(${valueVar})) && Number.parseInt(${valueVar}) > 0))) || (typeof ${valueVar} === "number" && ${valueVar} > 0)) {`, ` ${targetVar} = true;`, `} else if ((typeof ${valueVar} === "string" && (${valueVar}.toLowerCase() === "false" || ${valueVar}.toLowerCase() === "f" || ${valueVar}.toLowerCase() === "no" || ${valueVar}.toLowerCase() === "n" || (!Number.isNaN(Number.parseInt(${valueVar})) && Number.parseInt(${valueVar}) <= 0))) || (typeof ${valueVar} === "number" && ${valueVar} <= 0)) {`, ` ${targetVar} = false;`, `} else {`, ` ${errorsVar}.push({ path: ${pathVar}, failure: "Expected a boolean value" });`, ` ${targetVar} = ${valueVar};`, `}`);
202
+ break;
203
+ case "null":
204
+ lines.push(`if (${valueVar} === null) {`, ` ${targetVar} = null;`, `} else {`, ` ${errorsVar}.push({ path: ${pathVar}, failure: "Expected a null value" });`, ` ${targetVar} = ${valueVar};`, `}`);
205
+ break;
206
+ case void 0:
207
+ default:
208
+ lines.push(`${targetVar} = ${valueVar};`);
209
+ break;
210
+ }
211
+ return lines;
212
+ }
213
+ /**
214
+ * Generates the parsing statements for an `object` schema, applying property defaults and recursing into each declared property.
215
+ */
216
+ function generateObjectStatements(schema, valueVar, pathVar, targetVar, errorsVar) {
217
+ const type = stringifyType(schema);
218
+ const lines = [
219
+ `if (typeof ${valueVar} !== "object" || ${valueVar} === null || Array.isArray(${valueVar})) {`,
220
+ ` ${errorsVar}.push({ path: ${pathVar}, failure: "Expected an object value" });`,
221
+ ` ${targetVar} = ${valueVar};`,
222
+ `} else {`
223
+ ];
224
+ const resultVar = nextTemp(type || schema.name ? `${camelCase(type || schema.name)}Schema` : "schema");
225
+ lines.push(`const ${resultVar} = {} as Record<string, any>`);
226
+ if (isJsonSchemaObject(schema)) {
227
+ const propertyNames = /* @__PURE__ */ new Set();
228
+ for (const property of getPropertiesList(schema)) {
229
+ propertyNames.add(property.name);
230
+ let accessor;
231
+ if (isSetArray(property.alias)) {
232
+ accessor = `(${property.alias.map((alias) => `${valueVar}[${JSON.stringify(alias)}]`).join(` ${isJsonSchemaString(property) ? "||" : "??"} `)} ${isJsonSchemaString(property) ? "||" : "??"} ${valueVar}[${JSON.stringify(property.name)}])`;
233
+ property.alias.forEach((alias) => propertyNames.add(alias));
234
+ } else accessor = `${valueVar}[${JSON.stringify(property.name)}]`;
235
+ const propertyPath = childPath(pathVar, `.${property.name}`);
236
+ const propertyVar = nextTemp(property.name ? `${camelCase(property.name)}Property` : "property");
237
+ const missingBranch = property.default !== void 0 ? `${resultVar}[${JSON.stringify(property.name)}] = ${JSON.stringify(property.default)};` : property.required ? `${errorsVar}.push({ path: ${propertyPath}, failure: "Required property is missing" });` : "";
238
+ lines.push(` if (${accessor} !== undefined) {`, ` let ${propertyVar};`);
239
+ lines.push(...generateStatements(property, accessor, propertyPath, propertyVar, errorsVar));
240
+ lines.push(`${resultVar}[${JSON.stringify(property.name)}] = ${propertyVar};`);
241
+ if (missingBranch) lines.push(`} else { ${missingBranch} }`);
242
+ else lines.push("}");
243
+ }
244
+ const additional = schema.additionalProperties;
245
+ if (isJsonSchema(additional)) {
246
+ const additionalVar = nextTemp(type || schema.name ? `${camelCase(type || schema.name)}AdditionalProperties` : "additionalProperties");
247
+ lines.push(` for (const key of Object.keys(${valueVar})) {`, ` if (${JSON.stringify([...propertyNames])}.includes(key)) { continue; }`, ` let ${additionalVar};`);
248
+ lines.push(...generateStatements(additional, `${valueVar}[key]`, `${pathVar} + "." + key`, additionalVar, errorsVar));
249
+ lines.push(`${resultVar}[key] = ${additionalVar};`, `}`);
250
+ } else if (additional !== false) lines.push(` for (const key of Object.keys(${valueVar})) {`, ` if (${JSON.stringify([...propertyNames])}.includes(key)) { continue; }`, ` ${resultVar}[key] = ${valueVar}[key];`, `}`);
251
+ }
252
+ lines.push(`${targetVar} = ${resultVar};`, `}`);
253
+ return lines;
254
+ }
255
+ /**
256
+ * Generates the parsing statements for an `array` schema, recursing into each
257
+ * item (supporting both list and tuple `items`/`prefixItems` forms).
258
+ */
259
+ function generateArrayStatements(schema, valueVar, pathVar, targetVar, errorsVar) {
260
+ const lines = [
261
+ `if (!Array.isArray(${valueVar})) {`,
262
+ ` ${errorsVar}.push({ path: ${pathVar}, failure: "Expected an array value" });`,
263
+ ` ${targetVar} = ${valueVar};`,
264
+ `} else {`
265
+ ];
266
+ const resultVar = nextTemp(schema.name ? `${camelCase(schema.name)}Array` : "array");
267
+ lines.push(`const ${resultVar}: unknown[] = [];`);
268
+ const tupleItems = schema.prefixItems ?? (Array.isArray(schema.items) ? schema.items : void 0);
269
+ if (tupleItems) {
270
+ const listItems = !Array.isArray(schema.items) ? schema.items : void 0;
271
+ lines.push(` for (let index = 0; index < ${valueVar}.length; index += 1) {`, ` const item = ${valueVar}[index];`, ` let itemResult;`);
272
+ tupleItems.forEach((item, index) => {
273
+ lines.push(` ${index === 0 ? "if" : "else if"} (index === ${index}) {`);
274
+ lines.push(...generateStatements(item, "item", childPath(pathVar, `[${index}]`), "itemResult", errorsVar));
275
+ lines.push("}");
276
+ });
277
+ if (listItems) {
278
+ lines.push("else {");
279
+ lines.push(...generateStatements(listItems, "item", `${pathVar} + "[" + index + "]"`, "itemResult", errorsVar));
280
+ lines.push("}");
281
+ } else lines.push("else { itemResult = item; }");
282
+ lines.push(` ${resultVar}.push(itemResult);`, ` }`, ` ${targetVar} = ${resultVar};`, `}`);
283
+ return lines;
284
+ }
285
+ const itemSchema = schema.items ?? true;
286
+ lines.push(` for (let index = 0; index < ${valueVar}.length; index += 1) {`, ` const item = ${valueVar}[index];`, ` let itemResult;`);
287
+ lines.push(...generateStatements(itemSchema, "item", `${pathVar} + "[" + index + "]"`, "itemResult", errorsVar));
288
+ lines.push(` ${resultVar}.push(itemResult);`, ` }`, ` ${targetVar} = ${resultVar};`, `}`);
289
+ return lines;
290
+ }
291
+ return `/**
3
292
  * Parser error constructor function.
4
293
  */
5
294
  function ParserError(path, failure) {
@@ -24,15 +313,12 @@ export class ParserError extends Error {
24
313
  }
25
314
  }
26
315
 
27
- ${Object.entries(f).map(([e,t])=>`function ${w(e)}(inputValue, inputPath, errors) {
316
+ ${Object.entries(definitions).map(([name, definition]) => `function ${toParserIdentifier(name)}(inputValue, inputPath, errors) {
28
317
  let result;
29
- ${_(t,`inputValue`,`inputPath`,`result`,`errors`).join(`
30
- `)}
318
+ ${generateStatements(definition, "inputValue", "inputPath", "result", "errors").join("\n")}
31
319
 
32
320
  return result;
33
- }`).join(`
34
-
35
- `)}
321
+ }`).join("\n\n")}
36
322
 
37
323
  /**
38
324
  * Safely parses an input value into the type described by the JSON Schema, returning an array of validation errors when the value cannot be converted into a valid result.
@@ -47,8 +333,7 @@ export function parseSafe(inputValue) {
47
333
  const errors = [];
48
334
 
49
335
  let result;
50
- ${_(e,`inputValue`,`"$"`,`result`,`errors`).join(`
51
- `)}
336
+ ${generateStatements(schema, "inputValue", "\"$\"", "result", "errors").join("\n")}
52
337
 
53
338
  if (errors.length > 0) {
54
339
  return errors;
@@ -74,5 +359,9 @@ export function parse(inputValue) {
74
359
  }
75
360
 
76
361
  return result;
77
- }`}export{D as generateParserCode,S as getJsonSchemaType,x as stringifyType,b as stringifyValue};
362
+ }`;
363
+ }
364
+
365
+ //#endregion
366
+ export { generateParserCode, getJsonSchemaType, stringifyType, stringifyValue };
78
367
  //# sourceMappingURL=codegen.mjs.map
@@ -0,0 +1,128 @@
1
+
2
+ //#region src/constants.ts
3
+ const JsonSchemaTypeNames = {
4
+ STRING: "string",
5
+ NUMBER: "number",
6
+ INTEGER: "integer",
7
+ BOOLEAN: "boolean",
8
+ NULL: "null",
9
+ OBJECT: "object",
10
+ ARRAY: "array"
11
+ };
12
+ const JSON_SCHEMA_PRIMITIVE_TYPES = [
13
+ JsonSchemaTypeNames.STRING,
14
+ JsonSchemaTypeNames.NUMBER,
15
+ JsonSchemaTypeNames.INTEGER,
16
+ JsonSchemaTypeNames.BOOLEAN,
17
+ JsonSchemaTypeNames.NULL
18
+ ];
19
+ const JSON_SCHEMA_TYPES = [
20
+ ...JSON_SCHEMA_PRIMITIVE_TYPES,
21
+ JsonSchemaTypeNames.ARRAY,
22
+ JsonSchemaTypeNames.OBJECT
23
+ ];
24
+ const JSON_SCHEMA_METADATA_KEYS = [
25
+ "$id",
26
+ "$schema",
27
+ "$vocabulary",
28
+ "$comment",
29
+ "$anchor",
30
+ "$defs",
31
+ "$dynamicRef",
32
+ "$dynamicAnchor",
33
+ "alias",
34
+ "deprecated",
35
+ "description",
36
+ "title",
37
+ "docs",
38
+ "examples",
39
+ "hidden",
40
+ "ignore",
41
+ "internal",
42
+ "name",
43
+ "readOnly",
44
+ "runtime",
45
+ "tags",
46
+ "version",
47
+ "writeOnly"
48
+ ];
49
+ /**
50
+ * Keywords whose values are a flat record of named JSON Schema fragments.
51
+ * Each child schema is merged recursively with its counterpart.
52
+ */
53
+ const SCHEMA_RECORD_KEYWORDS = /* @__PURE__ */ new Set([
54
+ "properties",
55
+ "patternProperties",
56
+ "$defs",
57
+ "definitions",
58
+ "dependentSchemas"
59
+ ]);
60
+ /**
61
+ * Keywords whose value is a single JSON Schema fragment that should be
62
+ * recursively merged when both sides define it.
63
+ */
64
+ const SCHEMA_SINGLE_KEYWORDS = /* @__PURE__ */ new Set([
65
+ "if",
66
+ "then",
67
+ "else",
68
+ "not",
69
+ "contains",
70
+ "items",
71
+ "additionalProperties",
72
+ "unevaluatedProperties",
73
+ "propertyNames",
74
+ "unevaluatedItems"
75
+ ]);
76
+ /**
77
+ * Keywords whose values are arrays of JSON Schema fragments that should be
78
+ * concatenated (rather than overridden) during a merge.
79
+ */
80
+ const SCHEMA_ARRAY_CONCAT_KEYWORDS = /* @__PURE__ */ new Set([
81
+ "allOf",
82
+ "anyOf",
83
+ "oneOf"
84
+ ]);
85
+
86
+ //#endregion
87
+ Object.defineProperty(exports, 'JSON_SCHEMA_METADATA_KEYS', {
88
+ enumerable: true,
89
+ get: function () {
90
+ return JSON_SCHEMA_METADATA_KEYS;
91
+ }
92
+ });
93
+ Object.defineProperty(exports, 'JSON_SCHEMA_PRIMITIVE_TYPES', {
94
+ enumerable: true,
95
+ get: function () {
96
+ return JSON_SCHEMA_PRIMITIVE_TYPES;
97
+ }
98
+ });
99
+ Object.defineProperty(exports, 'JSON_SCHEMA_TYPES', {
100
+ enumerable: true,
101
+ get: function () {
102
+ return JSON_SCHEMA_TYPES;
103
+ }
104
+ });
105
+ Object.defineProperty(exports, 'JsonSchemaTypeNames', {
106
+ enumerable: true,
107
+ get: function () {
108
+ return JsonSchemaTypeNames;
109
+ }
110
+ });
111
+ Object.defineProperty(exports, 'SCHEMA_ARRAY_CONCAT_KEYWORDS', {
112
+ enumerable: true,
113
+ get: function () {
114
+ return SCHEMA_ARRAY_CONCAT_KEYWORDS;
115
+ }
116
+ });
117
+ Object.defineProperty(exports, 'SCHEMA_RECORD_KEYWORDS', {
118
+ enumerable: true,
119
+ get: function () {
120
+ return SCHEMA_RECORD_KEYWORDS;
121
+ }
122
+ });
123
+ Object.defineProperty(exports, 'SCHEMA_SINGLE_KEYWORDS', {
124
+ enumerable: true,
125
+ get: function () {
126
+ return SCHEMA_SINGLE_KEYWORDS;
127
+ }
128
+ });
@@ -0,0 +1,87 @@
1
+ //#region src/constants.ts
2
+ const JsonSchemaTypeNames = {
3
+ STRING: "string",
4
+ NUMBER: "number",
5
+ INTEGER: "integer",
6
+ BOOLEAN: "boolean",
7
+ NULL: "null",
8
+ OBJECT: "object",
9
+ ARRAY: "array"
10
+ };
11
+ const JSON_SCHEMA_PRIMITIVE_TYPES = [
12
+ JsonSchemaTypeNames.STRING,
13
+ JsonSchemaTypeNames.NUMBER,
14
+ JsonSchemaTypeNames.INTEGER,
15
+ JsonSchemaTypeNames.BOOLEAN,
16
+ JsonSchemaTypeNames.NULL
17
+ ];
18
+ const JSON_SCHEMA_TYPES = [
19
+ ...JSON_SCHEMA_PRIMITIVE_TYPES,
20
+ JsonSchemaTypeNames.ARRAY,
21
+ JsonSchemaTypeNames.OBJECT
22
+ ];
23
+ const JSON_SCHEMA_METADATA_KEYS = [
24
+ "$id",
25
+ "$schema",
26
+ "$vocabulary",
27
+ "$comment",
28
+ "$anchor",
29
+ "$defs",
30
+ "$dynamicRef",
31
+ "$dynamicAnchor",
32
+ "alias",
33
+ "deprecated",
34
+ "description",
35
+ "title",
36
+ "docs",
37
+ "examples",
38
+ "hidden",
39
+ "ignore",
40
+ "internal",
41
+ "name",
42
+ "readOnly",
43
+ "runtime",
44
+ "tags",
45
+ "version",
46
+ "writeOnly"
47
+ ];
48
+ /**
49
+ * Keywords whose values are a flat record of named JSON Schema fragments.
50
+ * Each child schema is merged recursively with its counterpart.
51
+ */
52
+ const SCHEMA_RECORD_KEYWORDS = /* @__PURE__ */ new Set([
53
+ "properties",
54
+ "patternProperties",
55
+ "$defs",
56
+ "definitions",
57
+ "dependentSchemas"
58
+ ]);
59
+ /**
60
+ * Keywords whose value is a single JSON Schema fragment that should be
61
+ * recursively merged when both sides define it.
62
+ */
63
+ const SCHEMA_SINGLE_KEYWORDS = /* @__PURE__ */ new Set([
64
+ "if",
65
+ "then",
66
+ "else",
67
+ "not",
68
+ "contains",
69
+ "items",
70
+ "additionalProperties",
71
+ "unevaluatedProperties",
72
+ "propertyNames",
73
+ "unevaluatedItems"
74
+ ]);
75
+ /**
76
+ * Keywords whose values are arrays of JSON Schema fragments that should be
77
+ * concatenated (rather than overridden) during a merge.
78
+ */
79
+ const SCHEMA_ARRAY_CONCAT_KEYWORDS = /* @__PURE__ */ new Set([
80
+ "allOf",
81
+ "anyOf",
82
+ "oneOf"
83
+ ]);
84
+
85
+ //#endregion
86
+ export { SCHEMA_ARRAY_CONCAT_KEYWORDS as a, JsonSchemaTypeNames as i, JSON_SCHEMA_PRIMITIVE_TYPES as n, SCHEMA_RECORD_KEYWORDS as o, JSON_SCHEMA_TYPES as r, SCHEMA_SINGLE_KEYWORDS as s, JSON_SCHEMA_METADATA_KEYS as t };
87
+ //# sourceMappingURL=constants-COGt3eeW.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants-COGt3eeW.mjs","names":[],"sources":[],"mappings":""}