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