@schema-ts/core 0.1.3 → 0.1.4
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/index.cjs +176 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -11
- package/dist/index.d.ts +58 -11
- package/dist/index.js +176 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1334,7 +1334,7 @@ function validateSchema(schema, value, instancePath = "", schemaPath = "#", fast
|
|
|
1334
1334
|
}
|
|
1335
1335
|
|
|
1336
1336
|
// src/effective.ts
|
|
1337
|
-
function resolveEffectiveSchema(validator, schema, value, keywordLocation, instanceLocation) {
|
|
1337
|
+
function resolveEffectiveSchema(validator, schema, value, keywordLocation, instanceLocation, isRequired = true) {
|
|
1338
1338
|
let effective = schema;
|
|
1339
1339
|
if (effective.if) {
|
|
1340
1340
|
const output = validator.validate(
|
|
@@ -1438,6 +1438,13 @@ function resolveEffectiveSchema(validator, schema, value, keywordLocation, insta
|
|
|
1438
1438
|
} else {
|
|
1439
1439
|
type = detectSchemaType(value);
|
|
1440
1440
|
}
|
|
1441
|
+
if (!isRequired && value === void 0) {
|
|
1442
|
+
return {
|
|
1443
|
+
effectiveSchema: effective,
|
|
1444
|
+
type,
|
|
1445
|
+
error: void 0
|
|
1446
|
+
};
|
|
1447
|
+
}
|
|
1441
1448
|
const validationOutput = validator.validate(
|
|
1442
1449
|
effective,
|
|
1443
1450
|
value,
|
|
@@ -1780,16 +1787,17 @@ function getSubSchema(schema, key) {
|
|
|
1780
1787
|
}
|
|
1781
1788
|
|
|
1782
1789
|
// src/default.ts
|
|
1783
|
-
function getDefaultValue(schema,
|
|
1790
|
+
function getDefaultValue(schema, options = {}) {
|
|
1791
|
+
const { value, strategy = "explicit" } = options;
|
|
1784
1792
|
if (value === void 0) {
|
|
1785
1793
|
if (schema.const !== void 0) return schema.const;
|
|
1786
1794
|
if (schema.default !== void 0) return schema.default;
|
|
1787
|
-
if (strategy === "explicit") return void 0;
|
|
1788
1795
|
}
|
|
1789
1796
|
const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
|
|
1790
1797
|
if (type === "object" || !type && schema.properties) {
|
|
1791
1798
|
let obj;
|
|
1792
1799
|
if (value === void 0) {
|
|
1800
|
+
if (strategy === "explicit") return void 0;
|
|
1793
1801
|
obj = {};
|
|
1794
1802
|
} else if (typeof value === "object" && value !== null) {
|
|
1795
1803
|
obj = value;
|
|
@@ -1799,9 +1807,9 @@ function getDefaultValue(schema, value, strategy = "explicit") {
|
|
|
1799
1807
|
if (schema.properties) {
|
|
1800
1808
|
for (const [key, subschema] of Object.entries(schema.properties)) {
|
|
1801
1809
|
if (obj[key] !== void 0) {
|
|
1802
|
-
obj[key] = getDefaultValue(subschema, obj[key], strategy);
|
|
1810
|
+
obj[key] = getDefaultValue(subschema, { value: obj[key], strategy });
|
|
1803
1811
|
} else if (schema.required?.includes(key)) {
|
|
1804
|
-
obj[key] = getDefaultValue(subschema,
|
|
1812
|
+
obj[key] = getDefaultValue(subschema, { strategy });
|
|
1805
1813
|
}
|
|
1806
1814
|
}
|
|
1807
1815
|
}
|
|
@@ -1810,6 +1818,7 @@ function getDefaultValue(schema, value, strategy = "explicit") {
|
|
|
1810
1818
|
if (type === "array") {
|
|
1811
1819
|
let arr;
|
|
1812
1820
|
if (value === void 0) {
|
|
1821
|
+
if (strategy === "explicit") return void 0;
|
|
1813
1822
|
arr = [];
|
|
1814
1823
|
} else if (Array.isArray(value)) {
|
|
1815
1824
|
arr = value;
|
|
@@ -1819,16 +1828,19 @@ function getDefaultValue(schema, value, strategy = "explicit") {
|
|
|
1819
1828
|
if (schema.prefixItems) {
|
|
1820
1829
|
schema.prefixItems.forEach((subschema, index) => {
|
|
1821
1830
|
if (index < arr.length) {
|
|
1822
|
-
arr[index] = getDefaultValue(subschema,
|
|
1831
|
+
arr[index] = getDefaultValue(subschema, {
|
|
1832
|
+
value: arr[index],
|
|
1833
|
+
strategy
|
|
1834
|
+
});
|
|
1823
1835
|
} else if (value === void 0) {
|
|
1824
|
-
arr.push(getDefaultValue(subschema,
|
|
1836
|
+
arr.push(getDefaultValue(subschema, { strategy }));
|
|
1825
1837
|
}
|
|
1826
1838
|
});
|
|
1827
1839
|
}
|
|
1828
1840
|
if (value !== void 0 && schema.items) {
|
|
1829
1841
|
const startIndex = schema.prefixItems ? schema.prefixItems.length : 0;
|
|
1830
1842
|
for (let i = startIndex; i < arr.length; i++) {
|
|
1831
|
-
arr[i] = getDefaultValue(schema.items, arr[i], strategy);
|
|
1843
|
+
arr[i] = getDefaultValue(schema.items, { value: arr[i], strategy });
|
|
1832
1844
|
}
|
|
1833
1845
|
}
|
|
1834
1846
|
return arr;
|
|
@@ -1836,6 +1848,9 @@ function getDefaultValue(schema, value, strategy = "explicit") {
|
|
|
1836
1848
|
if (value !== void 0) {
|
|
1837
1849
|
return value;
|
|
1838
1850
|
}
|
|
1851
|
+
if (strategy === "explicit") {
|
|
1852
|
+
return void 0;
|
|
1853
|
+
}
|
|
1839
1854
|
switch (type) {
|
|
1840
1855
|
case "string":
|
|
1841
1856
|
return "";
|
|
@@ -2059,7 +2074,11 @@ var SchemaRuntime = class {
|
|
|
2059
2074
|
constructor(validator, schema, value, options = {}) {
|
|
2060
2075
|
this.validator = validator;
|
|
2061
2076
|
this.value = value;
|
|
2062
|
-
this.options = {
|
|
2077
|
+
this.options = {
|
|
2078
|
+
autoFillDefaults: "explicit",
|
|
2079
|
+
removeEmptyContainers: "auto",
|
|
2080
|
+
...options
|
|
2081
|
+
};
|
|
2063
2082
|
const normalized = normalizeSchema(schema);
|
|
2064
2083
|
this.rootSchema = dereferenceSchemaDeep(normalized, normalized);
|
|
2065
2084
|
this.root = this.createEmptyNode("", "#");
|
|
@@ -2113,12 +2132,15 @@ var SchemaRuntime = class {
|
|
|
2113
2132
|
return {
|
|
2114
2133
|
type: "null",
|
|
2115
2134
|
schema: {},
|
|
2135
|
+
// Placeholder, will be set in buildNode
|
|
2116
2136
|
version: -1,
|
|
2137
|
+
// -1 indicates initial construction (not yet built)
|
|
2117
2138
|
instanceLocation,
|
|
2118
2139
|
keywordLocation,
|
|
2119
2140
|
originalSchema: {},
|
|
2120
2141
|
canRemove: false,
|
|
2121
2142
|
canAdd: false,
|
|
2143
|
+
isRequired: false,
|
|
2122
2144
|
children: []
|
|
2123
2145
|
};
|
|
2124
2146
|
}
|
|
@@ -2256,9 +2278,29 @@ var SchemaRuntime = class {
|
|
|
2256
2278
|
}
|
|
2257
2279
|
return setJsonPointer(this.value, normalizedPath, value);
|
|
2258
2280
|
}
|
|
2281
|
+
/**
|
|
2282
|
+
* Internal method to remove a value at a path.
|
|
2283
|
+
* Shared logic for removeValue and setValue(undefined).
|
|
2284
|
+
* @param path - The normalized path to remove
|
|
2285
|
+
* @param canRemove - Whether the removal is allowed (pre-checked by caller)
|
|
2286
|
+
* @returns true if successful, false if removal failed
|
|
2287
|
+
*/
|
|
2288
|
+
removeValueInternal(path) {
|
|
2289
|
+
const success = removeJsonPointer(this.value, path);
|
|
2290
|
+
if (!success) {
|
|
2291
|
+
return false;
|
|
2292
|
+
}
|
|
2293
|
+
const lastSlash = path.lastIndexOf("/");
|
|
2294
|
+
const parentPath = lastSlash <= 0 ? ROOT_PATH : path.substring(0, lastSlash);
|
|
2295
|
+
const reconcilePath = this.cleanupEmptyContainers(parentPath);
|
|
2296
|
+
this.reconcile(reconcilePath);
|
|
2297
|
+
this.notify({ type: "value", path: reconcilePath });
|
|
2298
|
+
return true;
|
|
2299
|
+
}
|
|
2259
2300
|
/**
|
|
2260
2301
|
* Remove a node at the specified path.
|
|
2261
2302
|
* This deletes the value from the data structure (array splice or object delete).
|
|
2303
|
+
* After removal, may also remove empty parent containers based on removeEmptyContainers option.
|
|
2262
2304
|
* @param path - The path to remove
|
|
2263
2305
|
* @returns true if successful, false if the path cannot be removed
|
|
2264
2306
|
*/
|
|
@@ -2271,15 +2313,54 @@ var SchemaRuntime = class {
|
|
|
2271
2313
|
if (!node || !node.canRemove) {
|
|
2272
2314
|
return false;
|
|
2273
2315
|
}
|
|
2274
|
-
|
|
2316
|
+
return this.removeValueInternal(normalizedPath);
|
|
2317
|
+
}
|
|
2318
|
+
/**
|
|
2319
|
+
* Clean up empty parent containers after element removal.
|
|
2320
|
+
* Recursively removes empty arrays/objects based on removeEmptyContainers option.
|
|
2321
|
+
* @param path - The path to check for empty container
|
|
2322
|
+
* @returns The topmost parent path for reconciliation
|
|
2323
|
+
*/
|
|
2324
|
+
cleanupEmptyContainers(path) {
|
|
2325
|
+
const strategy = this.options.removeEmptyContainers;
|
|
2326
|
+
if (strategy === "never" || path === ROOT_PATH) {
|
|
2327
|
+
return path;
|
|
2328
|
+
}
|
|
2329
|
+
const node = this.findNode(path);
|
|
2330
|
+
if (!node) {
|
|
2331
|
+
return path;
|
|
2332
|
+
}
|
|
2333
|
+
const value = this.getValue(path);
|
|
2334
|
+
const isEmpty = Array.isArray(value) && value.length === 0 || value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 0;
|
|
2335
|
+
if (!isEmpty) {
|
|
2336
|
+
return path;
|
|
2337
|
+
}
|
|
2338
|
+
const shouldRemove = strategy === "always" || strategy === "auto" && !node.isRequired;
|
|
2339
|
+
if (!shouldRemove) {
|
|
2340
|
+
return path;
|
|
2341
|
+
}
|
|
2342
|
+
const success = removeJsonPointer(this.value, path);
|
|
2275
2343
|
if (!success) {
|
|
2276
|
-
return
|
|
2344
|
+
return path;
|
|
2277
2345
|
}
|
|
2278
|
-
const lastSlash =
|
|
2279
|
-
const parentPath = lastSlash <= 0 ? ROOT_PATH :
|
|
2280
|
-
this.
|
|
2281
|
-
|
|
2282
|
-
|
|
2346
|
+
const lastSlash = path.lastIndexOf("/");
|
|
2347
|
+
const parentPath = lastSlash <= 0 ? ROOT_PATH : path.substring(0, lastSlash);
|
|
2348
|
+
return this.cleanupEmptyContainers(parentPath);
|
|
2349
|
+
}
|
|
2350
|
+
/**
|
|
2351
|
+
* Get default value for a schema, respecting autoFillDefaults option.
|
|
2352
|
+
* Falls back to 'always' strategy if configured strategy returns undefined.
|
|
2353
|
+
*/
|
|
2354
|
+
getDefaultValueForAdd(schema) {
|
|
2355
|
+
const strategy = this.options.autoFillDefaults;
|
|
2356
|
+
let defaultValue;
|
|
2357
|
+
if (strategy && strategy !== "never") {
|
|
2358
|
+
defaultValue = getDefaultValue(schema, { strategy });
|
|
2359
|
+
}
|
|
2360
|
+
if (defaultValue === void 0) {
|
|
2361
|
+
defaultValue = getDefaultValue(schema, { strategy: "always" });
|
|
2362
|
+
}
|
|
2363
|
+
return defaultValue;
|
|
2283
2364
|
}
|
|
2284
2365
|
/**
|
|
2285
2366
|
* Add a new child to an array or object at the specified parent path.
|
|
@@ -2322,7 +2403,7 @@ var SchemaRuntime = class {
|
|
|
2322
2403
|
if (!keywordLocationToken) {
|
|
2323
2404
|
return false;
|
|
2324
2405
|
}
|
|
2325
|
-
const defaultValue = initialValue !== void 0 ? initialValue :
|
|
2406
|
+
const defaultValue = initialValue !== void 0 ? initialValue : this.getDefaultValueForAdd(subschema);
|
|
2326
2407
|
const itemPath = jsonPointerJoin(normalizedPath, String(newIndex));
|
|
2327
2408
|
const success = setJsonPointer(this.value, itemPath, defaultValue);
|
|
2328
2409
|
if (!success) return false;
|
|
@@ -2340,7 +2421,7 @@ var SchemaRuntime = class {
|
|
|
2340
2421
|
if (!keywordLocationToken) {
|
|
2341
2422
|
return false;
|
|
2342
2423
|
}
|
|
2343
|
-
const defaultValue = initialValue !== void 0 ? initialValue :
|
|
2424
|
+
const defaultValue = initialValue !== void 0 ? initialValue : this.getDefaultValueForAdd(subschema);
|
|
2344
2425
|
const propertyPath = jsonPointerJoin(normalizedPath, key);
|
|
2345
2426
|
const success = setJsonPointer(this.value, propertyPath, defaultValue);
|
|
2346
2427
|
if (!success) return false;
|
|
@@ -2355,16 +2436,26 @@ var SchemaRuntime = class {
|
|
|
2355
2436
|
* Creates intermediate containers (objects/arrays) as needed.
|
|
2356
2437
|
* Triggers reconciliation and notifies subscribers.
|
|
2357
2438
|
*
|
|
2439
|
+
* When value is undefined and the field is not required, the field will be
|
|
2440
|
+
* removed from the parent container (similar to removeValue behavior).
|
|
2441
|
+
*
|
|
2358
2442
|
* @param path - The JSON Pointer path (e.g., "/user/name", "" for root)
|
|
2359
|
-
* @param value - The new value to set
|
|
2443
|
+
* @param value - The new value to set. If undefined and field is optional, removes the field.
|
|
2360
2444
|
* @returns true if successful, false if the path cannot be set
|
|
2361
2445
|
*
|
|
2362
2446
|
* @example
|
|
2363
2447
|
* runtime.setValue("/name", "Bob"); // set name to "Bob"
|
|
2364
2448
|
* runtime.setValue("", { name: "Alice" }); // replace entire root value
|
|
2449
|
+
* runtime.setValue("/optional", undefined); // remove optional field
|
|
2365
2450
|
*/
|
|
2366
2451
|
setValue(path, value) {
|
|
2367
2452
|
const normalizedPath = normalizeRootPath(path);
|
|
2453
|
+
if (value === void 0 && normalizedPath !== ROOT_PATH) {
|
|
2454
|
+
const node = this.findNode(normalizedPath);
|
|
2455
|
+
if (node && !node.isRequired) {
|
|
2456
|
+
return this.removeValueInternal(normalizedPath);
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2368
2459
|
const success = this.setValueAtPath(normalizedPath, value);
|
|
2369
2460
|
if (!success) return false;
|
|
2370
2461
|
this.reconcile(normalizedPath);
|
|
@@ -2430,29 +2521,56 @@ var SchemaRuntime = class {
|
|
|
2430
2521
|
* This handles cases like if-then-else where new properties with defaults
|
|
2431
2522
|
* may appear when conditions change.
|
|
2432
2523
|
*
|
|
2524
|
+
* Container initialization rules:
|
|
2525
|
+
* - Root node is always considered required and will be initialized if it has defaults or required properties
|
|
2526
|
+
* - Nested containers are initialized only if they are in parent's required array
|
|
2527
|
+
*
|
|
2433
2528
|
* @param instanceLocation - The path to the node
|
|
2434
2529
|
* @param newSchema - The new effective schema
|
|
2435
2530
|
* @param type - The schema type
|
|
2531
|
+
* @param isRequired - Whether this node is required by its parent
|
|
2436
2532
|
*/
|
|
2437
|
-
applySchemaDefaults(instanceLocation, newSchema, type) {
|
|
2438
|
-
|
|
2533
|
+
applySchemaDefaults(instanceLocation, newSchema, type, isRequired = true) {
|
|
2534
|
+
const strategy = this.options.autoFillDefaults;
|
|
2535
|
+
if (strategy === "never") {
|
|
2439
2536
|
return;
|
|
2440
2537
|
}
|
|
2441
|
-
|
|
2538
|
+
let value = this.getValue(instanceLocation);
|
|
2539
|
+
const isRoot = instanceLocation === ROOT_PATH;
|
|
2442
2540
|
if (type === "object" && newSchema.properties) {
|
|
2541
|
+
const requiredSet = new Set(newSchema.required || []);
|
|
2542
|
+
const hasAnyDefaults = Object.entries(newSchema.properties).some(
|
|
2543
|
+
([key, subschema]) => {
|
|
2544
|
+
const defaultValue = getDefaultValue(subschema, { strategy });
|
|
2545
|
+
if (defaultValue !== void 0) return true;
|
|
2546
|
+
const isChildRequired = requiredSet.has(key);
|
|
2547
|
+
if (isChildRequired && (subschema.type === "object" || subschema.type === "array")) {
|
|
2548
|
+
return true;
|
|
2549
|
+
}
|
|
2550
|
+
return false;
|
|
2551
|
+
}
|
|
2552
|
+
);
|
|
2553
|
+
const shouldInitialize = (value === void 0 || value === null) && hasAnyDefaults && (isRoot || isRequired);
|
|
2554
|
+
if (shouldInitialize) {
|
|
2555
|
+
value = {};
|
|
2556
|
+
this.setValueAtPath(normalizeRootPath(instanceLocation), value);
|
|
2557
|
+
}
|
|
2443
2558
|
const obj = value && typeof value === "object" ? value : null;
|
|
2444
2559
|
if (!obj) return;
|
|
2445
2560
|
for (const [key, subschema] of Object.entries(newSchema.properties)) {
|
|
2446
2561
|
const hasValue = obj[key] !== void 0;
|
|
2562
|
+
const isChildRequired = requiredSet.has(key);
|
|
2447
2563
|
if (!hasValue) {
|
|
2448
|
-
const defaultValue = getDefaultValue(
|
|
2449
|
-
subschema,
|
|
2450
|
-
void 0,
|
|
2451
|
-
this.options.autoFillDefaults
|
|
2452
|
-
);
|
|
2564
|
+
const defaultValue = getDefaultValue(subschema, { strategy });
|
|
2453
2565
|
if (defaultValue !== void 0) {
|
|
2454
2566
|
const propertyPath = jsonPointerJoin(instanceLocation, key);
|
|
2455
2567
|
setJsonPointer(this.value, propertyPath, defaultValue);
|
|
2568
|
+
} else if (isChildRequired && subschema.type === "object") {
|
|
2569
|
+
const propertyPath = jsonPointerJoin(instanceLocation, key);
|
|
2570
|
+
setJsonPointer(this.value, propertyPath, {});
|
|
2571
|
+
} else if (isChildRequired && subschema.type === "array") {
|
|
2572
|
+
const propertyPath = jsonPointerJoin(instanceLocation, key);
|
|
2573
|
+
setJsonPointer(this.value, propertyPath, []);
|
|
2456
2574
|
}
|
|
2457
2575
|
}
|
|
2458
2576
|
}
|
|
@@ -2464,11 +2582,7 @@ var SchemaRuntime = class {
|
|
|
2464
2582
|
for (let i = 0; i < newSchema.prefixItems.length; i++) {
|
|
2465
2583
|
if (arr[i] === void 0) {
|
|
2466
2584
|
const itemSchema = newSchema.prefixItems[i];
|
|
2467
|
-
const defaultValue = getDefaultValue(
|
|
2468
|
-
itemSchema,
|
|
2469
|
-
void 0,
|
|
2470
|
-
this.options.autoFillDefaults
|
|
2471
|
-
);
|
|
2585
|
+
const defaultValue = getDefaultValue(itemSchema, { strategy });
|
|
2472
2586
|
if (defaultValue !== void 0) {
|
|
2473
2587
|
const itemPath = jsonPointerJoin(instanceLocation, String(i));
|
|
2474
2588
|
setJsonPointer(this.value, itemPath, defaultValue);
|
|
@@ -2492,7 +2606,7 @@ var SchemaRuntime = class {
|
|
|
2492
2606
|
}
|
|
2493
2607
|
}
|
|
2494
2608
|
const newChildren = [];
|
|
2495
|
-
const processChild = (childKey, childSchema, childkeywordLocation, canRemove = false) => {
|
|
2609
|
+
const processChild = (childKey, childSchema, childkeywordLocation, canRemove = false, isRequired = false) => {
|
|
2496
2610
|
const childinstanceLocation = jsonPointerJoin(instanceLocation, childKey);
|
|
2497
2611
|
let childNode = oldChildrenMap.get(childinstanceLocation);
|
|
2498
2612
|
if (childNode) {
|
|
@@ -2505,7 +2619,8 @@ var SchemaRuntime = class {
|
|
|
2505
2619
|
);
|
|
2506
2620
|
}
|
|
2507
2621
|
childNode.canRemove = canRemove;
|
|
2508
|
-
|
|
2622
|
+
childNode.isRequired = isRequired;
|
|
2623
|
+
this.buildNode(childNode, childSchema, { ...options, isRequired });
|
|
2509
2624
|
newChildren.push(childNode);
|
|
2510
2625
|
};
|
|
2511
2626
|
switch (type) {
|
|
@@ -2518,11 +2633,13 @@ var SchemaRuntime = class {
|
|
|
2518
2633
|
effectiveSchema.properties
|
|
2519
2634
|
)) {
|
|
2520
2635
|
processedKeys.add(key);
|
|
2636
|
+
const isChildRequired = effectiveSchema.required?.includes(key) ?? false;
|
|
2521
2637
|
processChild(
|
|
2522
2638
|
key,
|
|
2523
2639
|
subschema,
|
|
2524
2640
|
`${keywordLocation}/properties/${key}`,
|
|
2525
|
-
false
|
|
2641
|
+
false,
|
|
2642
|
+
isChildRequired
|
|
2526
2643
|
);
|
|
2527
2644
|
}
|
|
2528
2645
|
}
|
|
@@ -2537,7 +2654,9 @@ var SchemaRuntime = class {
|
|
|
2537
2654
|
key,
|
|
2538
2655
|
subschema,
|
|
2539
2656
|
`${keywordLocation}/patternProperties/${jsonPointerEscape(pattern)}`,
|
|
2540
|
-
true
|
|
2657
|
+
true,
|
|
2658
|
+
false
|
|
2659
|
+
// patternProperties are never required
|
|
2541
2660
|
);
|
|
2542
2661
|
}
|
|
2543
2662
|
}
|
|
@@ -2551,7 +2670,9 @@ var SchemaRuntime = class {
|
|
|
2551
2670
|
key,
|
|
2552
2671
|
subschema,
|
|
2553
2672
|
`${keywordLocation}/additionalProperties`,
|
|
2554
|
-
true
|
|
2673
|
+
true,
|
|
2674
|
+
false
|
|
2675
|
+
// additionalProperties are never required
|
|
2555
2676
|
);
|
|
2556
2677
|
}
|
|
2557
2678
|
}
|
|
@@ -2569,7 +2690,9 @@ var SchemaRuntime = class {
|
|
|
2569
2690
|
String(i),
|
|
2570
2691
|
effectiveSchema.prefixItems[i],
|
|
2571
2692
|
`${keywordLocation}/prefixItems/${i}`,
|
|
2572
|
-
false
|
|
2693
|
+
false,
|
|
2694
|
+
true
|
|
2695
|
+
// array items are always considered required
|
|
2573
2696
|
);
|
|
2574
2697
|
}
|
|
2575
2698
|
}
|
|
@@ -2579,7 +2702,9 @@ var SchemaRuntime = class {
|
|
|
2579
2702
|
String(i),
|
|
2580
2703
|
effectiveSchema.items,
|
|
2581
2704
|
`${keywordLocation}/items`,
|
|
2705
|
+
true,
|
|
2582
2706
|
true
|
|
2707
|
+
// array items are always considered required
|
|
2583
2708
|
);
|
|
2584
2709
|
}
|
|
2585
2710
|
}
|
|
@@ -2596,6 +2721,7 @@ var SchemaRuntime = class {
|
|
|
2596
2721
|
* Build/update a FieldNode in place.
|
|
2597
2722
|
* Updates the node's schema, type, error, and children based on the current value.
|
|
2598
2723
|
* @param schema - Optional. If provided, updates node.originalSchema. Otherwise uses existing.
|
|
2724
|
+
* @param isRequired - Whether this node is required by its parent schema.
|
|
2599
2725
|
*/
|
|
2600
2726
|
buildNode(node, schema, options = {}) {
|
|
2601
2727
|
const { keywordLocation, instanceLocation } = node;
|
|
@@ -2613,17 +2739,25 @@ var SchemaRuntime = class {
|
|
|
2613
2739
|
if (schemaChanged) {
|
|
2614
2740
|
this.updateNodeDependencies(node, schema);
|
|
2615
2741
|
}
|
|
2742
|
+
const isRequired = options.isRequired ?? true;
|
|
2616
2743
|
const { type, effectiveSchema, error } = resolveEffectiveSchema(
|
|
2617
2744
|
this.validator,
|
|
2618
2745
|
node.originalSchema,
|
|
2619
2746
|
value,
|
|
2620
2747
|
keywordLocation,
|
|
2621
|
-
instanceLocation
|
|
2748
|
+
instanceLocation,
|
|
2749
|
+
isRequired
|
|
2622
2750
|
);
|
|
2623
|
-
const
|
|
2624
|
-
const
|
|
2751
|
+
const isInitialBuild = node.version === -1;
|
|
2752
|
+
const effectiveSchemaChanged = isInitialBuild || !deepEqual(effectiveSchema, node.schema) || type !== node.type;
|
|
2753
|
+
const errorChanged = isInitialBuild || !deepEqual(error, node.error);
|
|
2625
2754
|
if (effectiveSchemaChanged) {
|
|
2626
|
-
this.applySchemaDefaults(
|
|
2755
|
+
this.applySchemaDefaults(
|
|
2756
|
+
instanceLocation,
|
|
2757
|
+
effectiveSchema,
|
|
2758
|
+
type,
|
|
2759
|
+
isRequired
|
|
2760
|
+
);
|
|
2627
2761
|
}
|
|
2628
2762
|
node.schema = effectiveSchema;
|
|
2629
2763
|
node.type = type;
|