@powerlines/schema 0.11.81 → 0.11.82
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/_virtual/_rolldown/runtime.cjs +29 -0
- package/dist/bundle.cjs +49 -0
- package/dist/bundle.d.cts +21 -0
- package/dist/bundle.d.cts.map +1 -0
- package/dist/bundle.d.mts +21 -0
- package/dist/bundle.d.mts.map +1 -0
- package/dist/bundle.mjs +48 -0
- package/dist/bundle.mjs.map +1 -0
- package/dist/codegen.cjs +312 -0
- package/dist/codegen.d.cts +67 -0
- package/dist/codegen.d.cts.map +1 -0
- package/dist/codegen.d.mts +67 -0
- package/dist/codegen.d.mts.map +1 -0
- package/dist/codegen.mjs +306 -0
- package/dist/codegen.mjs.map +1 -0
- package/dist/constants.cjs +61 -0
- package/dist/constants.d.cts +17 -0
- package/dist/constants.d.cts.map +1 -0
- package/dist/constants.d.mts +17 -0
- package/dist/constants.d.mts.map +1 -0
- package/dist/constants.mjs +57 -0
- package/dist/constants.mjs.map +1 -0
- package/dist/extract.cjs +482 -0
- package/dist/extract.d.cts +125 -0
- package/dist/extract.d.cts.map +1 -0
- package/dist/extract.d.mts +125 -0
- package/dist/extract.d.mts.map +1 -0
- package/dist/extract.mjs +472 -0
- package/dist/extract.mjs.map +1 -0
- package/dist/helpers.cjs +241 -0
- package/dist/helpers.d.cts +121 -0
- package/dist/helpers.d.cts.map +1 -0
- package/dist/helpers.d.mts +121 -0
- package/dist/helpers.d.mts.map +1 -0
- package/dist/helpers.mjs +234 -0
- package/dist/helpers.mjs.map +1 -0
- package/dist/index.cjs +95 -2434
- package/dist/index.d.cts +11 -1892
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +11 -1892
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +12 -2321
- package/dist/metadata.cjs +53 -0
- package/dist/metadata.d.cts +31 -0
- package/dist/metadata.d.cts.map +1 -0
- package/dist/metadata.d.mts +31 -0
- package/dist/metadata.d.mts.map +1 -0
- package/dist/metadata.mjs +52 -0
- package/dist/metadata.mjs.map +1 -0
- package/dist/persistence.cjs +74 -0
- package/dist/persistence.d.cts +47 -0
- package/dist/persistence.d.cts.map +1 -0
- package/dist/persistence.d.mts +47 -0
- package/dist/persistence.d.mts.map +1 -0
- package/dist/persistence.mjs +71 -0
- package/dist/persistence.mjs.map +1 -0
- package/dist/reflection.cjs +426 -0
- package/dist/reflection.d.cts +11 -0
- package/dist/reflection.d.cts.map +1 -0
- package/dist/reflection.d.mts +11 -0
- package/dist/reflection.d.mts.map +1 -0
- package/dist/reflection.mjs +425 -0
- package/dist/reflection.mjs.map +1 -0
- package/dist/resolve.cjs +105 -0
- package/dist/resolve.d.cts +36 -0
- package/dist/resolve.d.cts.map +1 -0
- package/dist/resolve.d.mts +36 -0
- package/dist/resolve.d.mts.map +1 -0
- package/dist/resolve.mjs +102 -0
- package/dist/resolve.mjs.map +1 -0
- package/dist/type-checks.cjs +633 -0
- package/dist/type-checks.d.cts +316 -0
- package/dist/type-checks.d.cts.map +1 -0
- package/dist/type-checks.d.mts +316 -0
- package/dist/type-checks.d.mts.map +1 -0
- package/dist/type-checks.mjs +594 -0
- package/dist/type-checks.mjs.map +1 -0
- package/dist/types.d.cts +1152 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.mts +1152 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/validate.cjs +27 -0
- package/dist/validate.mjs +25 -0
- package/dist/validate.mjs.map +1 -0
- package/package.json +6 -6
- package/dist/index.mjs.map +0 -1
package/dist/helpers.mjs
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { VALID_SOURCE_FILE_EXTENSIONS } from "./constants.mjs";
|
|
2
|
+
import { readSchemaTypes } from "./metadata.mjs";
|
|
3
|
+
import { isJsonSchema, isJsonSchemaObject, isSchema } from "./type-checks.mjs";
|
|
4
|
+
import { isSetObject } from "@stryke/type-checks";
|
|
5
|
+
import { getUnique } from "@stryke/helpers/get-unique";
|
|
6
|
+
import { findFileExtensionSafe } from "@stryke/path/find";
|
|
7
|
+
|
|
8
|
+
//#region src/helpers.ts
|
|
9
|
+
/**
|
|
10
|
+
* Retrieves the JSON Schema from a Schema wrapper or returns the input if it's already a JSON Schema.
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* This function checks if the input is a Schema wrapper (an object with a `schema` property) and returns the `schema` if it is. If the input is already a JSON Schema, it returns it directly. This allows for flexibility in handling both raw JSON Schema objects and wrapped schemas without needing to check the type at every usage point.
|
|
14
|
+
*
|
|
15
|
+
* @param input - The input which can be either a Schema wrapper or a JSON Schema object.
|
|
16
|
+
* @returns The JSON Schema object.
|
|
17
|
+
* @throws Will throw a TypeError if the input is neither a valid Schema wrapper nor a valid JSON Schema object.
|
|
18
|
+
*/
|
|
19
|
+
function getJsonSchema(input) {
|
|
20
|
+
const schema = isSchema(input) ? input.schema : input;
|
|
21
|
+
if (!isJsonSchema(schema)) throw new TypeError(`The provided input is not a valid JSON Schema`);
|
|
22
|
+
return schema;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Retrieves the JSON Schema in Object form from a Schema wrapper or returns the input if it's already a JSON Schema.
|
|
26
|
+
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* This function checks if the input is a Schema wrapper (an object with a `schema` property) and returns the `schema` if it is. If the input is already a JSON Schema object, it returns it directly. This allows for flexibility in handling both raw JSON Schema objects and wrapped schemas without needing to check the type at every usage point.
|
|
29
|
+
*
|
|
30
|
+
* @param input - The input which can be either a Schema wrapper or a JSON Schema object.
|
|
31
|
+
* @returns The JSON Schema object.
|
|
32
|
+
* @throws Will throw a TypeError if the input is neither a valid Schema wrapper nor a valid JSON Schema object.
|
|
33
|
+
*/
|
|
34
|
+
function getJsonSchemaObject(input) {
|
|
35
|
+
const schema = getJsonSchema(input);
|
|
36
|
+
if (!isJsonSchemaObject(schema)) throw new TypeError(`The provided input is not a valid JSON Schema object`);
|
|
37
|
+
return schema;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Extracts object properties from a JSON Schema object form.
|
|
41
|
+
*
|
|
42
|
+
* @remarks
|
|
43
|
+
* This function returns an empty object if the schema is not an object form or if it has no properties.
|
|
44
|
+
*
|
|
45
|
+
* @param obj - The JSON Schema object form or a Schema wrapper to extract properties from.
|
|
46
|
+
* @returns An object mapping property names to their corresponding JSON Schema fragments, including metadata.
|
|
47
|
+
*/
|
|
48
|
+
function getProperties(obj) {
|
|
49
|
+
const properties = {};
|
|
50
|
+
const schema = getJsonSchemaObject(obj);
|
|
51
|
+
if (!isSetObject(schema.properties)) return properties;
|
|
52
|
+
for (const [key, value] of Object.entries(schema.properties)) {
|
|
53
|
+
const propertySchema = {};
|
|
54
|
+
if (typeof value !== "boolean") Object.assign(propertySchema, value);
|
|
55
|
+
properties[key] = {
|
|
56
|
+
...propertySchema,
|
|
57
|
+
name: key,
|
|
58
|
+
required: !isPropertyOptional(schema, key),
|
|
59
|
+
default: schema.default?.[key] ?? propertySchema.default
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return properties;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Returns object properties as an array.
|
|
66
|
+
*
|
|
67
|
+
* @remarks
|
|
68
|
+
* This is a convenience function that extracts properties using `getProperties` and returns them as an array.
|
|
69
|
+
*
|
|
70
|
+
* @param obj - The JSON Schema object form or a Schema wrapper to extract properties from.
|
|
71
|
+
* @returns An array of JSON Schema fragments representing the properties, each including metadata.
|
|
72
|
+
*/
|
|
73
|
+
function getPropertiesList(obj) {
|
|
74
|
+
return Object.values(getProperties(obj));
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Adds a property to a JSON Schema object form.
|
|
78
|
+
*
|
|
79
|
+
* @remarks
|
|
80
|
+
* This function modifies the provided schema in place by adding a new property with the specified name and schema. It also updates the `required` array based on the `optional` flag of the property. If the property is marked as optional, it will be removed from the `required` array; otherwise, it will be added to it.
|
|
81
|
+
*
|
|
82
|
+
* @param obj - The JSON Schema object form or a Schema wrapper to which the property should be added.
|
|
83
|
+
* @param name - The name of the property to add.
|
|
84
|
+
* @param property - The JSON Schema fragment representing the property's schema, including metadata.
|
|
85
|
+
* @throws Will throw an error if the provided schema is not an object form.
|
|
86
|
+
*/
|
|
87
|
+
function addProperty(obj, name, property) {
|
|
88
|
+
const schema = getJsonSchemaObject(obj);
|
|
89
|
+
schema.properties ??= {};
|
|
90
|
+
schema.required ??= [];
|
|
91
|
+
schema.properties[name] = {
|
|
92
|
+
...property,
|
|
93
|
+
name
|
|
94
|
+
};
|
|
95
|
+
if (!schema.required.includes(name)) schema.required.push(name);
|
|
96
|
+
if (schema.required.length === 0) delete schema.required;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Keywords whose values are a flat record of named JSON Schema fragments.
|
|
100
|
+
* Each child schema is merged recursively with its counterpart.
|
|
101
|
+
*/
|
|
102
|
+
const SCHEMA_RECORD_KEYWORDS = new Set([
|
|
103
|
+
"properties",
|
|
104
|
+
"patternProperties",
|
|
105
|
+
"$defs",
|
|
106
|
+
"definitions",
|
|
107
|
+
"dependentSchemas"
|
|
108
|
+
]);
|
|
109
|
+
/**
|
|
110
|
+
* Keywords whose value is a single JSON Schema fragment that should be
|
|
111
|
+
* recursively merged when both sides define it.
|
|
112
|
+
*/
|
|
113
|
+
const SCHEMA_SINGLE_KEYWORDS = new Set([
|
|
114
|
+
"if",
|
|
115
|
+
"then",
|
|
116
|
+
"else",
|
|
117
|
+
"not",
|
|
118
|
+
"contains",
|
|
119
|
+
"items",
|
|
120
|
+
"additionalProperties",
|
|
121
|
+
"unevaluatedProperties",
|
|
122
|
+
"propertyNames",
|
|
123
|
+
"unevaluatedItems"
|
|
124
|
+
]);
|
|
125
|
+
/**
|
|
126
|
+
* Keywords whose values are arrays of JSON Schema fragments that should be
|
|
127
|
+
* concatenated (rather than overridden) during a merge.
|
|
128
|
+
*/
|
|
129
|
+
const SCHEMA_ARRAY_CONCAT_KEYWORDS = new Set([
|
|
130
|
+
"allOf",
|
|
131
|
+
"anyOf",
|
|
132
|
+
"oneOf"
|
|
133
|
+
]);
|
|
134
|
+
/**
|
|
135
|
+
* Recursively merges two JSON Schema fragments. `override` wins for any scalar
|
|
136
|
+
* key that both schemas define, while structured keywords are handled
|
|
137
|
+
* specially:
|
|
138
|
+
*
|
|
139
|
+
* - `properties`, `patternProperties`, `$defs`, `definitions`,
|
|
140
|
+
* `dependentSchemas` — each matching child schema is merged recursively.
|
|
141
|
+
* - `allOf`, `anyOf`, `oneOf` — arrays are concatenated.
|
|
142
|
+
* - `if`, `then`, `else`, `not`, `contains`, `items`,
|
|
143
|
+
* `additionalProperties`, `unevaluatedProperties`, `propertyNames`,
|
|
144
|
+
* `unevaluatedItems` — merged recursively when both sides are schemas.
|
|
145
|
+
* - `required` — arrays are unioned and deduplicated.
|
|
146
|
+
*/
|
|
147
|
+
function mergeTwo(base, override) {
|
|
148
|
+
const result = { ...base };
|
|
149
|
+
for (const [key, overrideValue] of Object.entries(override)) {
|
|
150
|
+
const baseValue = result[key];
|
|
151
|
+
if (key === "required") result[key] = getUnique([...Array.isArray(baseValue) ? baseValue : [], ...Array.isArray(overrideValue) ? overrideValue : []]);
|
|
152
|
+
else if (SCHEMA_RECORD_KEYWORDS.has(key) && isSetObject(baseValue) && isSetObject(overrideValue)) {
|
|
153
|
+
const merged = { ...baseValue };
|
|
154
|
+
for (const [childKey, childOverride] of Object.entries(overrideValue)) {
|
|
155
|
+
const childBase = merged[childKey];
|
|
156
|
+
merged[childKey] = isJsonSchema(childBase) && isJsonSchema(childOverride) ? mergeTwo(childBase, childOverride) : childOverride;
|
|
157
|
+
}
|
|
158
|
+
result[key] = merged;
|
|
159
|
+
} else if (SCHEMA_ARRAY_CONCAT_KEYWORDS.has(key) && Array.isArray(baseValue) && Array.isArray(overrideValue)) result[key] = [...baseValue, ...overrideValue];
|
|
160
|
+
else if (SCHEMA_SINGLE_KEYWORDS.has(key) && isJsonSchema(baseValue) && isJsonSchema(overrideValue)) result[key] = mergeTwo(baseValue, overrideValue);
|
|
161
|
+
else result[key] = overrideValue;
|
|
162
|
+
}
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Merges multiple JSON Schemas into one.
|
|
167
|
+
*
|
|
168
|
+
* @remarks
|
|
169
|
+
* This function takes multiple JSON Schemas or Schema wrappers and merges them
|
|
170
|
+
* into a single JSON Schema object. Later schemas in the argument list take
|
|
171
|
+
* precedence over earlier ones for scalar conflicts.
|
|
172
|
+
*
|
|
173
|
+
* Structured keywords are merged recursively:
|
|
174
|
+
* - Named child schemas (`properties`, `$defs`, etc.) are merged
|
|
175
|
+
* per-property via recursive calls to `merge`.
|
|
176
|
+
* - Composition arrays (`allOf`, `anyOf`, `oneOf`) are concatenated.
|
|
177
|
+
* - Single-schema keywords (`if`, `then`, `else`, `not`, `items`, etc.)
|
|
178
|
+
* are merged recursively when both sides define them.
|
|
179
|
+
* - `required` arrays are unioned and deduplicated.
|
|
180
|
+
*
|
|
181
|
+
* @param schemas - An array of JSON Schemas or Schema wrappers to merge.
|
|
182
|
+
* @returns A new JSON Schema that is the result of merging all input schemas.
|
|
183
|
+
*/
|
|
184
|
+
function merge(...schemas) {
|
|
185
|
+
const jsonSchemas = schemas.map((s) => getJsonSchema(s));
|
|
186
|
+
if (jsonSchemas.length === 0) return {};
|
|
187
|
+
return jsonSchemas.reduce((acc, schema) => {
|
|
188
|
+
const accType = acc.type;
|
|
189
|
+
const schemaType = schema.type;
|
|
190
|
+
if (accType && schemaType && accType !== schemaType) return schema;
|
|
191
|
+
return mergeTwo(acc, schema);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Returns whether a JSON Schema fragment accepts `null`.
|
|
196
|
+
*
|
|
197
|
+
* @remarks
|
|
198
|
+
* This is true if the schema has `nullable: true` or if its `type` includes `"null"`.
|
|
199
|
+
*
|
|
200
|
+
* @param schema - The JSON Schema fragment to check.
|
|
201
|
+
* @returns `true` if the schema accepts `null`, otherwise `false`.
|
|
202
|
+
*/
|
|
203
|
+
function isSchemaNullable(schema) {
|
|
204
|
+
if (!isSetObject(schema)) return false;
|
|
205
|
+
if (schema.nullable === true) return true;
|
|
206
|
+
return readSchemaTypes(schema).includes("null");
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Returns whether an object property is optional (not listed in `required`).
|
|
210
|
+
*
|
|
211
|
+
* @remarks
|
|
212
|
+
* In JSON Schema, object properties are optional by default unless they are listed in the `required` array of the parent schema. This function checks whether a given property name is not included in the `required` array of its parent schema, indicating that it is optional.
|
|
213
|
+
*
|
|
214
|
+
* @param parent - The parent JSON Schema object containing the property.
|
|
215
|
+
* @param propertyName - The name of the property to check for optionality.
|
|
216
|
+
* @returns `true` if the property is optional, otherwise `false`.
|
|
217
|
+
*/
|
|
218
|
+
function isPropertyOptional(parent, propertyName) {
|
|
219
|
+
if (!parent.properties?.[propertyName]) throw new Error(`The property "${propertyName}" does not exist in the parent schema.`);
|
|
220
|
+
return !(parent.required ?? []).includes(propertyName);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Checks if a given file name has a valid schema input file extension.
|
|
224
|
+
*
|
|
225
|
+
* @param fileName - The file name to check for a valid schema input extension.
|
|
226
|
+
* @returns `true` if the file name has a valid schema input extension, otherwise `false`.
|
|
227
|
+
*/
|
|
228
|
+
function isValidSchemaInputFile(fileName) {
|
|
229
|
+
return VALID_SOURCE_FILE_EXTENSIONS.includes(findFileExtensionSafe(fileName));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
//#endregion
|
|
233
|
+
export { addProperty, getJsonSchema, getJsonSchemaObject, getProperties, getPropertiesList, isPropertyOptional, isSchemaNullable, isValidSchemaInputFile, merge };
|
|
234
|
+
//# sourceMappingURL=helpers.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.mjs","names":["baseObj"],"sources":["../src/helpers.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Powerlines\n\n This code was released as part of the Powerlines project. Powerlines\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/powerlines.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/powerlines\n Documentation: https://docs.stormsoftware.com/projects/powerlines\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { getUnique } from \"@stryke/helpers/get-unique\";\nimport { findFileExtensionSafe } from \"@stryke/path/find\";\nimport { isSetObject } from \"@stryke/type-checks\";\nimport { VALID_SOURCE_FILE_EXTENSIONS } from \"./constants\";\nimport { readSchemaTypes } from \"./metadata\";\nimport { isJsonSchema, isJsonSchemaObject, isSchema } from \"./type-checks\";\nimport { JsonSchema, JsonSchemaLike, JsonSchemaObject, Schema } from \"./types\";\n\nexport type GetPropertiesResult = JsonSchema & {\n name: string;\n required: boolean;\n default?: unknown;\n};\n\n/**\n * Retrieves the JSON Schema from a Schema wrapper or returns the input if it's already a JSON Schema.\n *\n * @remarks\n * This function checks if the input is a Schema wrapper (an object with a `schema` property) and returns the `schema` if it is. If the input is already a JSON Schema, it returns it directly. This allows for flexibility in handling both raw JSON Schema objects and wrapped schemas without needing to check the type at every usage point.\n *\n * @param input - The input which can be either a Schema wrapper or a JSON Schema object.\n * @returns The JSON Schema object.\n * @throws Will throw a TypeError if the input is neither a valid Schema wrapper nor a valid JSON Schema object.\n */\nexport function getJsonSchema(input: Schema | JsonSchema): JsonSchema {\n const schema = isSchema(input) ? input.schema : input;\n if (!isJsonSchema(schema)) {\n throw new TypeError(`The provided input is not a valid JSON Schema`);\n }\n\n return schema;\n}\n\n/**\n * Retrieves the JSON Schema in Object form from a Schema wrapper or returns the input if it's already a JSON Schema.\n *\n * @remarks\n * This function checks if the input is a Schema wrapper (an object with a `schema` property) and returns the `schema` if it is. If the input is already a JSON Schema object, it returns it directly. This allows for flexibility in handling both raw JSON Schema objects and wrapped schemas without needing to check the type at every usage point.\n *\n * @param input - The input which can be either a Schema wrapper or a JSON Schema object.\n * @returns The JSON Schema object.\n * @throws Will throw a TypeError if the input is neither a valid Schema wrapper nor a valid JSON Schema object.\n */\nexport function getJsonSchemaObject(\n input: Schema | JsonSchema\n): JsonSchemaObject {\n const schema = getJsonSchema(input);\n if (!isJsonSchemaObject(schema)) {\n throw new TypeError(`The provided input is not a valid JSON Schema object`);\n }\n\n return schema;\n}\n\n/**\n * Extracts object properties from a JSON Schema object form.\n *\n * @remarks\n * This function returns an empty object if the schema is not an object form or if it has no properties.\n *\n * @param obj - The JSON Schema object form or a Schema wrapper to extract properties from.\n * @returns An object mapping property names to their corresponding JSON Schema fragments, including metadata.\n */\nexport function getProperties(\n obj: Schema | JsonSchemaObject\n): Record<\n string,\n JsonSchema & { name: string; required: boolean; default?: unknown }\n> {\n const properties: Record<\n string,\n JsonSchema & { name: string; required: boolean; default?: unknown }\n > = {};\n\n const schema = getJsonSchemaObject(obj);\n if (!isSetObject(schema.properties)) {\n return properties;\n }\n\n for (const [key, value] of Object.entries(schema.properties)) {\n const propertySchema: Record<string, unknown> = {};\n\n if (typeof value !== \"boolean\") {\n Object.assign(propertySchema, value);\n }\n\n properties[key] = {\n ...propertySchema,\n name: key,\n required: !isPropertyOptional(schema, key),\n default: schema.default?.[key] ?? propertySchema.default\n };\n }\n\n return properties;\n}\n\n/**\n * Returns object properties as an array.\n *\n * @remarks\n * This is a convenience function that extracts properties using `getProperties` and returns them as an array.\n *\n * @param obj - The JSON Schema object form or a Schema wrapper to extract properties from.\n * @returns An array of JSON Schema fragments representing the properties, each including metadata.\n */\nexport function getPropertiesList(obj: Schema | JsonSchemaObject) {\n return Object.values(getProperties(obj));\n}\n\n/**\n * Adds a property to a JSON Schema object form.\n *\n * @remarks\n * This function modifies the provided schema in place by adding a new property with the specified name and schema. It also updates the `required` array based on the `optional` flag of the property. If the property is marked as optional, it will be removed from the `required` array; otherwise, it will be added to it.\n *\n * @param obj - The JSON Schema object form or a Schema wrapper to which the property should be added.\n * @param name - The name of the property to add.\n * @param property - The JSON Schema fragment representing the property's schema, including metadata.\n * @throws Will throw an error if the provided schema is not an object form.\n */\nexport function addProperty(\n obj: Schema | JsonSchemaObject,\n name: string,\n property: JsonSchema\n): void {\n const schema = getJsonSchemaObject(obj);\n\n schema.properties ??= {};\n schema.required ??= [];\n\n schema.properties[name] = { ...property, name };\n if (!schema.required.includes(name)) {\n schema.required.push(name);\n }\n\n if (schema.required.length === 0) {\n delete schema.required;\n }\n}\n\n/**\n * Keywords whose values are a flat record of named JSON Schema fragments.\n * Each child schema is merged recursively with its counterpart.\n */\nconst SCHEMA_RECORD_KEYWORDS = new Set([\n \"properties\",\n \"patternProperties\",\n \"$defs\",\n \"definitions\",\n \"dependentSchemas\"\n]);\n\n/**\n * Keywords whose value is a single JSON Schema fragment that should be\n * recursively merged when both sides define it.\n */\nconst SCHEMA_SINGLE_KEYWORDS = new Set([\n \"if\",\n \"then\",\n \"else\",\n \"not\",\n \"contains\",\n \"items\",\n \"additionalProperties\",\n \"unevaluatedProperties\",\n \"propertyNames\",\n \"unevaluatedItems\"\n]);\n\n/**\n * Keywords whose values are arrays of JSON Schema fragments that should be\n * concatenated (rather than overridden) during a merge.\n */\nconst SCHEMA_ARRAY_CONCAT_KEYWORDS = new Set([\"allOf\", \"anyOf\", \"oneOf\"]);\n\n/**\n * Recursively merges two JSON Schema fragments. `override` wins for any scalar\n * key that both schemas define, while structured keywords are handled\n * specially:\n *\n * - `properties`, `patternProperties`, `$defs`, `definitions`,\n * `dependentSchemas` — each matching child schema is merged recursively.\n * - `allOf`, `anyOf`, `oneOf` — arrays are concatenated.\n * - `if`, `then`, `else`, `not`, `contains`, `items`,\n * `additionalProperties`, `unevaluatedProperties`, `propertyNames`,\n * `unevaluatedItems` — merged recursively when both sides are schemas.\n * - `required` — arrays are unioned and deduplicated.\n */\nfunction mergeTwo(base: JsonSchema, override: JsonSchema): JsonSchema {\n const baseObj = base as Record<string, unknown>;\n const result: Record<string, unknown> = { ...baseObj };\n\n for (const [key, overrideValue] of Object.entries(\n override as Record<string, unknown>\n )) {\n const baseValue = result[key];\n\n if (key === \"required\") {\n result[key] = getUnique([\n ...(Array.isArray(baseValue) ? (baseValue as string[]) : []),\n ...(Array.isArray(overrideValue) ? (overrideValue as string[]) : [])\n ]);\n } else if (\n SCHEMA_RECORD_KEYWORDS.has(key) &&\n isSetObject(baseValue) &&\n isSetObject(overrideValue)\n ) {\n const merged: Record<string, unknown> = {\n ...(baseValue as Record<string, unknown>)\n };\n for (const [childKey, childOverride] of Object.entries(\n overrideValue as Record<string, unknown>\n )) {\n const childBase = merged[childKey];\n merged[childKey] =\n isJsonSchema(childBase) && isJsonSchema(childOverride)\n ? mergeTwo(childBase, childOverride)\n : childOverride;\n }\n result[key] = merged;\n } else if (\n SCHEMA_ARRAY_CONCAT_KEYWORDS.has(key) &&\n Array.isArray(baseValue) &&\n Array.isArray(overrideValue)\n ) {\n result[key] = [\n ...(baseValue as JsonSchema[]),\n ...(overrideValue as JsonSchema[])\n ];\n } else if (\n SCHEMA_SINGLE_KEYWORDS.has(key) &&\n isJsonSchema(baseValue) &&\n isJsonSchema(overrideValue)\n ) {\n result[key] = mergeTwo(baseValue, overrideValue);\n } else {\n result[key] = overrideValue;\n }\n }\n\n return result;\n}\n\n/**\n * Merges multiple JSON Schemas into one.\n *\n * @remarks\n * This function takes multiple JSON Schemas or Schema wrappers and merges them\n * into a single JSON Schema object. Later schemas in the argument list take\n * precedence over earlier ones for scalar conflicts.\n *\n * Structured keywords are merged recursively:\n * - Named child schemas (`properties`, `$defs`, etc.) are merged\n * per-property via recursive calls to `merge`.\n * - Composition arrays (`allOf`, `anyOf`, `oneOf`) are concatenated.\n * - Single-schema keywords (`if`, `then`, `else`, `not`, `items`, etc.)\n * are merged recursively when both sides define them.\n * - `required` arrays are unioned and deduplicated.\n *\n * @param schemas - An array of JSON Schemas or Schema wrappers to merge.\n * @returns A new JSON Schema that is the result of merging all input schemas.\n */\nexport function merge(...schemas: (JsonSchema | Schema)[]): JsonSchema {\n const jsonSchemas = schemas.map(s => getJsonSchema(s));\n if (jsonSchemas.length === 0) {\n return {};\n }\n\n return jsonSchemas.reduce((acc, schema) => {\n const accType = (acc as JsonSchemaLike).type;\n const schemaType = (schema as JsonSchemaLike).type;\n\n if (accType && schemaType && accType !== schemaType) {\n // Incompatible types — the later schema wins entirely.\n return schema;\n }\n\n return mergeTwo(acc, schema);\n });\n}\n\n/**\n * Returns whether a JSON Schema fragment accepts `null`.\n *\n * @remarks\n * This is true if the schema has `nullable: true` or if its `type` includes `\"null\"`.\n *\n * @param schema - The JSON Schema fragment to check.\n * @returns `true` if the schema accepts `null`, otherwise `false`.\n */\nexport function isSchemaNullable(schema?: JsonSchema): boolean {\n if (!isSetObject(schema)) {\n return false;\n }\n\n if ((schema as { nullable?: true }).nullable === true) {\n return true;\n }\n\n return readSchemaTypes(schema).includes(\"null\");\n}\n\n/**\n * Returns whether an object property is optional (not listed in `required`).\n *\n * @remarks\n * In JSON Schema, object properties are optional by default unless they are listed in the `required` array of the parent schema. This function checks whether a given property name is not included in the `required` array of its parent schema, indicating that it is optional.\n *\n * @param parent - The parent JSON Schema object containing the property.\n * @param propertyName - The name of the property to check for optionality.\n * @returns `true` if the property is optional, otherwise `false`.\n */\nexport function isPropertyOptional(\n parent: JsonSchemaObject,\n propertyName: string\n): boolean {\n if (!parent.properties?.[propertyName]) {\n throw new Error(\n `The property \"${propertyName}\" does not exist in the parent schema.`\n );\n }\n\n return !(parent.required ?? []).includes(propertyName);\n}\n\n/**\n * Checks if a given file name has a valid schema input file extension.\n *\n * @param fileName - The file name to check for a valid schema input extension.\n * @returns `true` if the file name has a valid schema input extension, otherwise `false`.\n */\nexport function isValidSchemaInputFile(fileName: string): boolean {\n return VALID_SOURCE_FILE_EXTENSIONS.includes(findFileExtensionSafe(fileName));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA0CA,SAAgB,cAAc,OAAwC;CACpE,MAAM,SAAS,SAAS,KAAK,IAAI,MAAM,SAAS;CAChD,IAAI,CAAC,aAAa,MAAM,GACtB,MAAM,IAAI,UAAU,+CAA+C;CAGrE,OAAO;AACT;;;;;;;;;;;AAYA,SAAgB,oBACd,OACkB;CAClB,MAAM,SAAS,cAAc,KAAK;CAClC,IAAI,CAAC,mBAAmB,MAAM,GAC5B,MAAM,IAAI,UAAU,sDAAsD;CAG5E,OAAO;AACT;;;;;;;;;;AAWA,SAAgB,cACd,KAIA;CACA,MAAM,aAGF,CAAC;CAEL,MAAM,SAAS,oBAAoB,GAAG;CACtC,IAAI,CAAC,YAAY,OAAO,UAAU,GAChC,OAAO;CAGT,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,UAAU,GAAG;EAC5D,MAAM,iBAA0C,CAAC;EAEjD,IAAI,OAAO,UAAU,WACnB,OAAO,OAAO,gBAAgB,KAAK;EAGrC,WAAW,OAAO;GAChB,GAAG;GACH,MAAM;GACN,UAAU,CAAC,mBAAmB,QAAQ,GAAG;GACzC,SAAS,OAAO,UAAU,QAAQ,eAAe;EACnD;CACF;CAEA,OAAO;AACT;;;;;;;;;;AAWA,SAAgB,kBAAkB,KAAgC;CAChE,OAAO,OAAO,OAAO,cAAc,GAAG,CAAC;AACzC;;;;;;;;;;;;AAaA,SAAgB,YACd,KACA,MACA,UACM;CACN,MAAM,SAAS,oBAAoB,GAAG;CAEtC,OAAO,eAAe,CAAC;CACvB,OAAO,aAAa,CAAC;CAErB,OAAO,WAAW,QAAQ;EAAE,GAAG;EAAU;CAAK;CAC9C,IAAI,CAAC,OAAO,SAAS,SAAS,IAAI,GAChC,OAAO,SAAS,KAAK,IAAI;CAG3B,IAAI,OAAO,SAAS,WAAW,GAC7B,OAAO,OAAO;AAElB;;;;;AAMA,MAAM,yBAAyB,IAAI,IAAI;CACrC;CACA;CACA;CACA;CACA;AACF,CAAC;;;;;AAMD,MAAM,yBAAyB,IAAI,IAAI;CACrC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;;;;AAMD,MAAM,+BAA+B,IAAI,IAAI;CAAC;CAAS;CAAS;AAAO,CAAC;;;;;;;;;;;;;;AAexE,SAAS,SAAS,MAAkB,UAAkC;CAEpE,MAAM,SAAkC,EAAE,GAAGA,KAAQ;CAErD,KAAK,MAAM,CAAC,KAAK,kBAAkB,OAAO,QACxC,QACF,GAAG;EACD,MAAM,YAAY,OAAO;EAEzB,IAAI,QAAQ,YACV,OAAO,OAAO,UAAU,CACtB,GAAI,MAAM,QAAQ,SAAS,IAAK,YAAyB,CAAC,GAC1D,GAAI,MAAM,QAAQ,aAAa,IAAK,gBAA6B,CAAC,CACpE,CAAC;OACI,IACL,uBAAuB,IAAI,GAAG,KAC9B,YAAY,SAAS,KACrB,YAAY,aAAa,GACzB;GACA,MAAM,SAAkC,EACtC,GAAI,UACN;GACA,KAAK,MAAM,CAAC,UAAU,kBAAkB,OAAO,QAC7C,aACF,GAAG;IACD,MAAM,YAAY,OAAO;IACzB,OAAO,YACL,aAAa,SAAS,KAAK,aAAa,aAAa,IACjD,SAAS,WAAW,aAAa,IACjC;GACR;GACA,OAAO,OAAO;EAChB,OAAO,IACL,6BAA6B,IAAI,GAAG,KACpC,MAAM,QAAQ,SAAS,KACvB,MAAM,QAAQ,aAAa,GAE3B,OAAO,OAAO,CACZ,GAAI,WACJ,GAAI,aACN;OACK,IACL,uBAAuB,IAAI,GAAG,KAC9B,aAAa,SAAS,KACtB,aAAa,aAAa,GAE1B,OAAO,OAAO,SAAS,WAAW,aAAa;OAE/C,OAAO,OAAO;CAElB;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,MAAM,GAAG,SAA8C;CACrE,MAAM,cAAc,QAAQ,KAAI,MAAK,cAAc,CAAC,CAAC;CACrD,IAAI,YAAY,WAAW,GACzB,OAAO,CAAC;CAGV,OAAO,YAAY,QAAQ,KAAK,WAAW;EACzC,MAAM,UAAW,IAAuB;EACxC,MAAM,aAAc,OAA0B;EAE9C,IAAI,WAAW,cAAc,YAAY,YAEvC,OAAO;EAGT,OAAO,SAAS,KAAK,MAAM;CAC7B,CAAC;AACH;;;;;;;;;;AAWA,SAAgB,iBAAiB,QAA8B;CAC7D,IAAI,CAAC,YAAY,MAAM,GACrB,OAAO;CAGT,IAAK,OAA+B,aAAa,MAC/C,OAAO;CAGT,OAAO,gBAAgB,MAAM,EAAE,SAAS,MAAM;AAChD;;;;;;;;;;;AAYA,SAAgB,mBACd,QACA,cACS;CACT,IAAI,CAAC,OAAO,aAAa,eACvB,MAAM,IAAI,MACR,iBAAiB,aAAa,uCAChC;CAGF,OAAO,EAAE,OAAO,YAAY,CAAC,GAAG,SAAS,YAAY;AACvD;;;;;;;AAQA,SAAgB,uBAAuB,UAA2B;CAChE,OAAO,6BAA6B,SAAS,sBAAsB,QAAQ,CAAC;AAC9E"}
|