@schema-ts/core 0.1.3 → 0.1.5
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 +608 -306
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +220 -85
- package/dist/index.d.ts +220 -85
- package/dist/index.js +604 -307
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -144,6 +144,10 @@ function setJsonPointer(obj, jsonPointer, value) {
|
|
|
144
144
|
}
|
|
145
145
|
return true;
|
|
146
146
|
}
|
|
147
|
+
function getJsonPointerParent(path) {
|
|
148
|
+
const lastSlash = path.lastIndexOf("/");
|
|
149
|
+
return lastSlash <= 0 ? "" : path.substring(0, lastSlash);
|
|
150
|
+
}
|
|
147
151
|
function get(obj, path) {
|
|
148
152
|
let current = obj;
|
|
149
153
|
for (const segment of path) {
|
|
@@ -463,6 +467,11 @@ function detectSchemaDraft(schema) {
|
|
|
463
467
|
}
|
|
464
468
|
|
|
465
469
|
// src/normalize.ts
|
|
470
|
+
var DraftNormalizer = class {
|
|
471
|
+
normalize(schema) {
|
|
472
|
+
return normalizeSchema(schema);
|
|
473
|
+
}
|
|
474
|
+
};
|
|
466
475
|
function normalizeSchema(schema, options = {}) {
|
|
467
476
|
if (typeof schema === "boolean") {
|
|
468
477
|
return schema ? {} : { not: {} };
|
|
@@ -546,8 +555,6 @@ function normalizeDraft07(schema) {
|
|
|
546
555
|
} else {
|
|
547
556
|
delete legacy.items;
|
|
548
557
|
}
|
|
549
|
-
} else if ("additionalItems" in legacy) {
|
|
550
|
-
delete legacy.additionalItems;
|
|
551
558
|
}
|
|
552
559
|
if ("dependencies" in legacy) {
|
|
553
560
|
const deps = legacy.dependencies;
|
|
@@ -623,18 +630,16 @@ function normalizeNestedSchemas(schema, options) {
|
|
|
623
630
|
}
|
|
624
631
|
if (schema.properties) {
|
|
625
632
|
schema.properties = Object.fromEntries(
|
|
626
|
-
Object.entries(schema.properties).
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
])
|
|
633
|
+
Object.entries(schema.properties).filter(
|
|
634
|
+
([_, subSchema]) => subSchema !== null && subSchema !== void 0
|
|
635
|
+
).map(([key, subSchema]) => [key, normalizeSchema(subSchema, options)])
|
|
630
636
|
);
|
|
631
637
|
}
|
|
632
638
|
if (schema.patternProperties) {
|
|
633
639
|
schema.patternProperties = Object.fromEntries(
|
|
634
|
-
Object.entries(schema.patternProperties).
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
])
|
|
640
|
+
Object.entries(schema.patternProperties).filter(
|
|
641
|
+
([_, subSchema]) => subSchema !== null && subSchema !== void 0
|
|
642
|
+
).map(([key, subSchema]) => [key, normalizeSchema(subSchema, options)])
|
|
638
643
|
);
|
|
639
644
|
}
|
|
640
645
|
if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
|
|
@@ -677,10 +682,9 @@ function normalizeNestedSchemas(schema, options) {
|
|
|
677
682
|
}
|
|
678
683
|
if (schema.dependentSchemas) {
|
|
679
684
|
schema.dependentSchemas = Object.fromEntries(
|
|
680
|
-
Object.entries(schema.dependentSchemas).
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
])
|
|
685
|
+
Object.entries(schema.dependentSchemas).filter(
|
|
686
|
+
([_, subSchema]) => subSchema !== null && subSchema !== void 0
|
|
687
|
+
).map(([key, subSchema]) => [key, normalizeSchema(subSchema, options)])
|
|
684
688
|
);
|
|
685
689
|
}
|
|
686
690
|
if (schema.unevaluatedItems) {
|
|
@@ -699,6 +703,120 @@ function normalizeNestedSchemas(schema, options) {
|
|
|
699
703
|
schema.contentSchema = normalizeSchema(schema.contentSchema, options);
|
|
700
704
|
}
|
|
701
705
|
}
|
|
706
|
+
var BetterNormalizer = class {
|
|
707
|
+
/**
|
|
708
|
+
* Performs the normalization process:
|
|
709
|
+
* 1. Base draft normalization (DraftNormalizer)
|
|
710
|
+
* 2. Enhanced default value completion (Better logic)
|
|
711
|
+
*/
|
|
712
|
+
normalize(schema) {
|
|
713
|
+
const normalized = normalizeSchema(schema);
|
|
714
|
+
this.defaultSchema(normalized);
|
|
715
|
+
return normalized;
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Recursively processes all sub-nodes of the schema, applying default rules.
|
|
719
|
+
*/
|
|
720
|
+
default(schema, forceRequired = false) {
|
|
721
|
+
this.defaultSchema(schema.if, true);
|
|
722
|
+
this.defaultSchema(schema.then);
|
|
723
|
+
this.defaultSchema(schema.else);
|
|
724
|
+
schema.anyOf?.forEach((s) => this.defaultSchema(s));
|
|
725
|
+
schema.oneOf?.forEach((s) => this.defaultSchema(s));
|
|
726
|
+
schema.allOf?.forEach((s) => this.defaultSchema(s));
|
|
727
|
+
this.defaultSchemaMap(schema.properties, forceRequired);
|
|
728
|
+
this.defaultSchemaMap(schema.patternProperties, forceRequired);
|
|
729
|
+
this.defaultSchema(schema.additionalProperties, forceRequired);
|
|
730
|
+
this.defaultSchema(schema.propertyNames);
|
|
731
|
+
this.defaultSchemaMap(schema.dependentSchemas, true);
|
|
732
|
+
this.defaultSchema(schema.items);
|
|
733
|
+
schema.prefixItems?.forEach((s) => this.defaultSchema(s));
|
|
734
|
+
this.defaultSchema(schema.contains);
|
|
735
|
+
this.defaultSchema(schema.unevaluatedItems);
|
|
736
|
+
this.defaultSchema(schema.unevaluatedProperties);
|
|
737
|
+
this.defaultSchema(schema.contentSchema);
|
|
738
|
+
return schema;
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Batch processes Record-type sub-schemas.
|
|
742
|
+
*/
|
|
743
|
+
defaultSchemaMap(kvs, forceRequired = false) {
|
|
744
|
+
if (!kvs) {
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
Object.entries(kvs).forEach(([_, value]) => {
|
|
748
|
+
this.defaultSchema(value, forceRequired);
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Applies inference and heuristic rules to a single schema object.
|
|
753
|
+
* Includes:
|
|
754
|
+
* - `type` inference based on properties (object/array)
|
|
755
|
+
* - Automatically setting properties with `const`/`default`/`enum` as `required`
|
|
756
|
+
* - Handling `required` fields from OpenAPI `discriminator`
|
|
757
|
+
* - Handling `x-required` and `x-kubernetes-patch-merge-key`
|
|
758
|
+
*/
|
|
759
|
+
defaultSchema(schema, forceRequired = false) {
|
|
760
|
+
if (!schema || typeof schema === "boolean") {
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
if (!schema.type) {
|
|
764
|
+
if (schema.properties || schema.patternProperties || schema.additionalProperties) {
|
|
765
|
+
schema.type = "object";
|
|
766
|
+
} else if (schema.items || schema.prefixItems || schema.additionalItems) {
|
|
767
|
+
schema.type = "array";
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
if (schema.patternProperties && schema.minProperties === void 0) {
|
|
771
|
+
schema.minProperties = 1;
|
|
772
|
+
}
|
|
773
|
+
if (schema.required === void 0) {
|
|
774
|
+
const required = [];
|
|
775
|
+
for (const [key, value] of Object.entries(schema.properties || {})) {
|
|
776
|
+
if (forceRequired || value.const !== void 0 || Array.isArray(value.enum) && value.enum.length > 0) {
|
|
777
|
+
required.push(key);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
if (required.length > 0) {
|
|
781
|
+
schema.required = required;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
const discriminator = toObject(schema.discriminator);
|
|
785
|
+
if (discriminator.propertyName) {
|
|
786
|
+
if (typeof discriminator.propertyName === "string") {
|
|
787
|
+
if (schema.required === void 0) {
|
|
788
|
+
schema.required = [discriminator.propertyName];
|
|
789
|
+
} else if (!schema.required.includes(discriminator.propertyName)) {
|
|
790
|
+
schema.required.push(discriminator.propertyName);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
for (const [key, value] of Object.entries(schema.properties || {})) {
|
|
795
|
+
if (value["x-required"] === true) {
|
|
796
|
+
if (schema.required === void 0) {
|
|
797
|
+
schema.required = [key];
|
|
798
|
+
} else if (!schema.required.includes(key)) {
|
|
799
|
+
schema.required.push(key);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
const mergeKey = schema["x-kubernetes-patch-merge-key"];
|
|
804
|
+
if (typeof mergeKey === "string" && typeof schema.items === "object" && schema.items !== null) {
|
|
805
|
+
const items = schema.items;
|
|
806
|
+
if (!items.required) items.required = [];
|
|
807
|
+
if (!items.required.includes(mergeKey)) {
|
|
808
|
+
items.required.push(mergeKey);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
this.default(schema, forceRequired);
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
function toObject(val) {
|
|
815
|
+
if (typeof val === "object" && val !== null) {
|
|
816
|
+
return val;
|
|
817
|
+
}
|
|
818
|
+
return {};
|
|
819
|
+
}
|
|
702
820
|
|
|
703
821
|
// src/validate.ts
|
|
704
822
|
var Validator = class {
|
|
@@ -1332,14 +1450,15 @@ function validateSchema(schema, value, instancePath = "", schemaPath = "#", fast
|
|
|
1332
1450
|
}
|
|
1333
1451
|
|
|
1334
1452
|
// src/effective.ts
|
|
1335
|
-
function resolveEffectiveSchema(validator, schema, value, keywordLocation, instanceLocation) {
|
|
1453
|
+
function resolveEffectiveSchema(validator, schema, value, keywordLocation, instanceLocation, validate = false) {
|
|
1336
1454
|
let effective = schema;
|
|
1337
1455
|
if (effective.if) {
|
|
1338
1456
|
const output = validator.validate(
|
|
1339
1457
|
effective.if,
|
|
1340
1458
|
value,
|
|
1341
1459
|
`${keywordLocation}/if`,
|
|
1342
|
-
instanceLocation
|
|
1460
|
+
instanceLocation,
|
|
1461
|
+
{ fastFail: true }
|
|
1343
1462
|
);
|
|
1344
1463
|
if (output.valid) {
|
|
1345
1464
|
if (effective.then) {
|
|
@@ -1348,9 +1467,14 @@ function resolveEffectiveSchema(validator, schema, value, keywordLocation, insta
|
|
|
1348
1467
|
effective.then,
|
|
1349
1468
|
value,
|
|
1350
1469
|
`${keywordLocation}/then`,
|
|
1351
|
-
instanceLocation
|
|
1470
|
+
instanceLocation,
|
|
1471
|
+
validate
|
|
1472
|
+
);
|
|
1473
|
+
effective = mergeSchema(
|
|
1474
|
+
effective,
|
|
1475
|
+
res.effectiveSchema,
|
|
1476
|
+
`${keywordLocation}/then`
|
|
1352
1477
|
);
|
|
1353
|
-
effective = mergeSchema(effective, res.effectiveSchema);
|
|
1354
1478
|
}
|
|
1355
1479
|
} else {
|
|
1356
1480
|
if (effective.else) {
|
|
@@ -1359,9 +1483,14 @@ function resolveEffectiveSchema(validator, schema, value, keywordLocation, insta
|
|
|
1359
1483
|
effective.else,
|
|
1360
1484
|
value,
|
|
1361
1485
|
`${keywordLocation}/else`,
|
|
1362
|
-
instanceLocation
|
|
1486
|
+
instanceLocation,
|
|
1487
|
+
validate
|
|
1488
|
+
);
|
|
1489
|
+
effective = mergeSchema(
|
|
1490
|
+
effective,
|
|
1491
|
+
res.effectiveSchema,
|
|
1492
|
+
`${keywordLocation}/else`
|
|
1363
1493
|
);
|
|
1364
|
-
effective = mergeSchema(effective, res.effectiveSchema);
|
|
1365
1494
|
}
|
|
1366
1495
|
}
|
|
1367
1496
|
const { if: _, then: __, else: ___, ...rest } = effective;
|
|
@@ -1369,24 +1498,31 @@ function resolveEffectiveSchema(validator, schema, value, keywordLocation, insta
|
|
|
1369
1498
|
}
|
|
1370
1499
|
if (effective.allOf) {
|
|
1371
1500
|
for (const [index, subschema] of effective.allOf.entries()) {
|
|
1501
|
+
const subKeywordLocation = `${keywordLocation}/allOf/${index}`;
|
|
1372
1502
|
const res = resolveEffectiveSchema(
|
|
1373
1503
|
validator,
|
|
1374
1504
|
subschema,
|
|
1375
1505
|
value,
|
|
1376
|
-
|
|
1377
|
-
instanceLocation
|
|
1506
|
+
subKeywordLocation,
|
|
1507
|
+
instanceLocation,
|
|
1508
|
+
validate
|
|
1509
|
+
);
|
|
1510
|
+
effective = mergeSchema(
|
|
1511
|
+
effective,
|
|
1512
|
+
res.effectiveSchema,
|
|
1513
|
+
subKeywordLocation
|
|
1378
1514
|
);
|
|
1379
|
-
effective = mergeSchema(effective, res.effectiveSchema);
|
|
1380
1515
|
}
|
|
1381
1516
|
const { allOf: _, ...rest } = effective;
|
|
1382
1517
|
effective = rest;
|
|
1383
1518
|
}
|
|
1384
1519
|
if (effective.anyOf) {
|
|
1385
1520
|
for (const [index, subschema] of effective.anyOf.entries()) {
|
|
1521
|
+
const subKeywordLocation = `${keywordLocation}/anyOf/${index}`;
|
|
1386
1522
|
const output = validator.validate(
|
|
1387
1523
|
subschema,
|
|
1388
1524
|
value,
|
|
1389
|
-
|
|
1525
|
+
subKeywordLocation,
|
|
1390
1526
|
instanceLocation
|
|
1391
1527
|
);
|
|
1392
1528
|
if (output.valid) {
|
|
@@ -1394,10 +1530,15 @@ function resolveEffectiveSchema(validator, schema, value, keywordLocation, insta
|
|
|
1394
1530
|
validator,
|
|
1395
1531
|
subschema,
|
|
1396
1532
|
value,
|
|
1397
|
-
|
|
1398
|
-
instanceLocation
|
|
1533
|
+
subKeywordLocation,
|
|
1534
|
+
instanceLocation,
|
|
1535
|
+
validate
|
|
1536
|
+
);
|
|
1537
|
+
effective = mergeSchema(
|
|
1538
|
+
effective,
|
|
1539
|
+
res.effectiveSchema,
|
|
1540
|
+
subKeywordLocation
|
|
1399
1541
|
);
|
|
1400
|
-
effective = mergeSchema(effective, res.effectiveSchema);
|
|
1401
1542
|
}
|
|
1402
1543
|
}
|
|
1403
1544
|
const { anyOf: _, ...rest } = effective;
|
|
@@ -1406,6 +1547,7 @@ function resolveEffectiveSchema(validator, schema, value, keywordLocation, insta
|
|
|
1406
1547
|
if (effective.oneOf) {
|
|
1407
1548
|
let validCount = 0;
|
|
1408
1549
|
let lastValidSchema = null;
|
|
1550
|
+
let lastValidIndex = -1;
|
|
1409
1551
|
for (const [index, subschema] of effective.oneOf.entries()) {
|
|
1410
1552
|
const output = validator.validate(
|
|
1411
1553
|
subschema,
|
|
@@ -1416,10 +1558,15 @@ function resolveEffectiveSchema(validator, schema, value, keywordLocation, insta
|
|
|
1416
1558
|
if (output.valid) {
|
|
1417
1559
|
validCount++;
|
|
1418
1560
|
lastValidSchema = subschema;
|
|
1561
|
+
lastValidIndex = index;
|
|
1419
1562
|
}
|
|
1420
1563
|
}
|
|
1421
1564
|
if (validCount === 1 && lastValidSchema) {
|
|
1422
|
-
effective = mergeSchema(
|
|
1565
|
+
effective = mergeSchema(
|
|
1566
|
+
effective,
|
|
1567
|
+
lastValidSchema,
|
|
1568
|
+
`${keywordLocation}/oneOf/${lastValidIndex}`
|
|
1569
|
+
);
|
|
1423
1570
|
}
|
|
1424
1571
|
const { oneOf: _, ...rest } = effective;
|
|
1425
1572
|
effective = rest;
|
|
@@ -1436,6 +1583,13 @@ function resolveEffectiveSchema(validator, schema, value, keywordLocation, insta
|
|
|
1436
1583
|
} else {
|
|
1437
1584
|
type = detectSchemaType(value);
|
|
1438
1585
|
}
|
|
1586
|
+
if (!validate) {
|
|
1587
|
+
return {
|
|
1588
|
+
effectiveSchema: effective,
|
|
1589
|
+
type,
|
|
1590
|
+
error: void 0
|
|
1591
|
+
};
|
|
1592
|
+
}
|
|
1439
1593
|
const validationOutput = validator.validate(
|
|
1440
1594
|
effective,
|
|
1441
1595
|
value,
|
|
@@ -1469,25 +1623,42 @@ function mergeSchemaArrays(a, b) {
|
|
|
1469
1623
|
if (b === void 0) return a;
|
|
1470
1624
|
return [...a, ...b];
|
|
1471
1625
|
}
|
|
1472
|
-
function mergeSchemaMap(base, override) {
|
|
1473
|
-
if (base === void 0)
|
|
1626
|
+
function mergeSchemaMap(base, override, overrideOrigin) {
|
|
1627
|
+
if (base === void 0) {
|
|
1628
|
+
if (override === void 0) return void 0;
|
|
1629
|
+
if (overrideOrigin) {
|
|
1630
|
+
const result = {};
|
|
1631
|
+
for (const [key, schema] of Object.entries(override)) {
|
|
1632
|
+
result[key] = {
|
|
1633
|
+
...schema,
|
|
1634
|
+
"x-origin-keyword": `${overrideOrigin}/${key}`
|
|
1635
|
+
};
|
|
1636
|
+
}
|
|
1637
|
+
return result;
|
|
1638
|
+
}
|
|
1639
|
+
return override;
|
|
1640
|
+
}
|
|
1474
1641
|
if (override === void 0) return base;
|
|
1475
1642
|
const merged = { ...base };
|
|
1476
1643
|
for (const [key, schema] of Object.entries(override)) {
|
|
1644
|
+
const childOrigin = overrideOrigin ? `${overrideOrigin}/${key}` : void 0;
|
|
1477
1645
|
if (merged[key]) {
|
|
1478
|
-
merged[key] = mergeSchema(merged[key], schema);
|
|
1646
|
+
merged[key] = mergeSchema(merged[key], schema, childOrigin);
|
|
1479
1647
|
} else {
|
|
1480
|
-
merged[key] = schema;
|
|
1648
|
+
merged[key] = childOrigin ? { ...schema, "x-origin-keyword": childOrigin } : schema;
|
|
1481
1649
|
}
|
|
1482
1650
|
}
|
|
1483
1651
|
return merged;
|
|
1484
1652
|
}
|
|
1485
|
-
function mergeSchema(base, override) {
|
|
1653
|
+
function mergeSchema(base, override, overrideOrigin) {
|
|
1486
1654
|
if (!override) return base;
|
|
1487
1655
|
const merged = {
|
|
1488
1656
|
...base,
|
|
1489
1657
|
...override
|
|
1490
1658
|
};
|
|
1659
|
+
if (overrideOrigin) {
|
|
1660
|
+
merged["x-origin-keyword"] = overrideOrigin;
|
|
1661
|
+
}
|
|
1491
1662
|
if (base.$defs || override.$defs) {
|
|
1492
1663
|
merged.$defs = {
|
|
1493
1664
|
...base.$defs,
|
|
@@ -1508,23 +1679,31 @@ function mergeSchema(base, override) {
|
|
|
1508
1679
|
...override.dependentRequired
|
|
1509
1680
|
};
|
|
1510
1681
|
}
|
|
1511
|
-
const
|
|
1682
|
+
const propertiesOrigin = overrideOrigin ? `${overrideOrigin}/properties` : void 0;
|
|
1683
|
+
const mergedProperties = mergeSchemaMap(
|
|
1684
|
+
base.properties,
|
|
1685
|
+
override.properties,
|
|
1686
|
+
propertiesOrigin
|
|
1687
|
+
);
|
|
1512
1688
|
if (mergedProperties !== void 0) {
|
|
1513
1689
|
merged.properties = mergedProperties;
|
|
1514
1690
|
}
|
|
1691
|
+
const patternPropertiesOrigin = overrideOrigin ? `${overrideOrigin}/patternProperties` : void 0;
|
|
1515
1692
|
const mergedPatternProperties = mergeSchemaMap(
|
|
1516
1693
|
base.patternProperties,
|
|
1517
|
-
override.patternProperties
|
|
1694
|
+
override.patternProperties,
|
|
1695
|
+
patternPropertiesOrigin
|
|
1518
1696
|
);
|
|
1519
1697
|
if (mergedPatternProperties !== void 0) {
|
|
1520
1698
|
merged.patternProperties = mergedPatternProperties;
|
|
1521
1699
|
}
|
|
1700
|
+
const itemsOrigin = overrideOrigin ? `${overrideOrigin}/items` : void 0;
|
|
1522
1701
|
if (base.items && override.items) {
|
|
1523
|
-
merged.items = mergeSchema(base.items, override.items);
|
|
1702
|
+
merged.items = mergeSchema(base.items, override.items, itemsOrigin);
|
|
1524
1703
|
} else if (base.items) {
|
|
1525
1704
|
merged.items = base.items;
|
|
1526
1705
|
} else if (override.items) {
|
|
1527
|
-
merged.items = override.items;
|
|
1706
|
+
merged.items = itemsOrigin ? { ...override.items, "x-origin-keyword": itemsOrigin } : override.items;
|
|
1528
1707
|
}
|
|
1529
1708
|
if (base.prefixItems || override.prefixItems) {
|
|
1530
1709
|
merged.prefixItems = [];
|
|
@@ -1535,13 +1714,17 @@ function mergeSchema(base, override) {
|
|
|
1535
1714
|
for (let i = 0; i < len; i++) {
|
|
1536
1715
|
const baseSchema = base.prefixItems?.[i];
|
|
1537
1716
|
const overrideSchema = override.prefixItems?.[i];
|
|
1717
|
+
const prefixItemOrigin = overrideOrigin ? `${overrideOrigin}/prefixItems/${i}` : void 0;
|
|
1538
1718
|
if (baseSchema && overrideSchema) {
|
|
1539
|
-
merged.prefixItems.push(
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1719
|
+
merged.prefixItems.push(
|
|
1720
|
+
mergeSchema(baseSchema, overrideSchema, prefixItemOrigin)
|
|
1721
|
+
);
|
|
1722
|
+
} else if (overrideSchema) {
|
|
1723
|
+
merged.prefixItems.push(
|
|
1724
|
+
prefixItemOrigin ? { ...overrideSchema, "x-origin-keyword": prefixItemOrigin } : overrideSchema
|
|
1725
|
+
);
|
|
1726
|
+
} else if (baseSchema) {
|
|
1727
|
+
merged.prefixItems.push(baseSchema);
|
|
1545
1728
|
}
|
|
1546
1729
|
}
|
|
1547
1730
|
}
|
|
@@ -1552,9 +1735,11 @@ function mergeSchema(base, override) {
|
|
|
1552
1735
|
merged[keyword] = mergedArray;
|
|
1553
1736
|
}
|
|
1554
1737
|
}
|
|
1738
|
+
const dependentSchemasOrigin = overrideOrigin ? `${overrideOrigin}/dependentSchemas` : void 0;
|
|
1555
1739
|
const mergedDependentSchemas = mergeSchemaMap(
|
|
1556
1740
|
base.dependentSchemas,
|
|
1557
|
-
override.dependentSchemas
|
|
1741
|
+
override.dependentSchemas,
|
|
1742
|
+
dependentSchemasOrigin
|
|
1558
1743
|
);
|
|
1559
1744
|
if (mergedDependentSchemas !== void 0) {
|
|
1560
1745
|
merged.dependentSchemas = mergedDependentSchemas;
|
|
@@ -1733,7 +1918,8 @@ function getSubSchema(schema, key) {
|
|
|
1733
1918
|
if (schema.properties && schema.properties[key]) {
|
|
1734
1919
|
return {
|
|
1735
1920
|
schema: schema.properties[key],
|
|
1736
|
-
keywordLocationToken: `properties/${key}
|
|
1921
|
+
keywordLocationToken: `properties/${key}`,
|
|
1922
|
+
required: schema.required?.includes(key) || false
|
|
1737
1923
|
};
|
|
1738
1924
|
}
|
|
1739
1925
|
if (schema.patternProperties) {
|
|
@@ -1743,7 +1929,8 @@ function getSubSchema(schema, key) {
|
|
|
1743
1929
|
if (safeRegexTest(pattern, key)) {
|
|
1744
1930
|
return {
|
|
1745
1931
|
schema: subschema,
|
|
1746
|
-
keywordLocationToken: `patternProperties/${pattern}
|
|
1932
|
+
keywordLocationToken: `patternProperties/${pattern}`,
|
|
1933
|
+
required: false
|
|
1747
1934
|
};
|
|
1748
1935
|
}
|
|
1749
1936
|
}
|
|
@@ -1751,7 +1938,8 @@ function getSubSchema(schema, key) {
|
|
|
1751
1938
|
if (schema.additionalProperties !== void 0 && schema.additionalProperties !== false) {
|
|
1752
1939
|
return {
|
|
1753
1940
|
schema: typeof schema.additionalProperties === "object" ? schema.additionalProperties : {},
|
|
1754
|
-
keywordLocationToken: "additionalProperties"
|
|
1941
|
+
keywordLocationToken: "additionalProperties",
|
|
1942
|
+
required: false
|
|
1755
1943
|
};
|
|
1756
1944
|
}
|
|
1757
1945
|
if (schema.items || schema.prefixItems) {
|
|
@@ -1760,94 +1948,124 @@ function getSubSchema(schema, key) {
|
|
|
1760
1948
|
if (schema.prefixItems && index < schema.prefixItems.length) {
|
|
1761
1949
|
return {
|
|
1762
1950
|
schema: schema.prefixItems[index],
|
|
1763
|
-
keywordLocationToken: `prefixItems/${index}
|
|
1951
|
+
keywordLocationToken: `prefixItems/${index}`,
|
|
1952
|
+
required: true
|
|
1953
|
+
// prefixItems are always required
|
|
1764
1954
|
};
|
|
1765
1955
|
}
|
|
1766
1956
|
if (schema.items) {
|
|
1767
1957
|
return {
|
|
1768
1958
|
schema: schema.items,
|
|
1769
|
-
keywordLocationToken: "items"
|
|
1959
|
+
keywordLocationToken: "items",
|
|
1960
|
+
// items beyond prefixItems are not required by default
|
|
1961
|
+
// but usually new item is considered required to hold the place
|
|
1962
|
+
required: true
|
|
1770
1963
|
};
|
|
1771
1964
|
}
|
|
1772
1965
|
}
|
|
1773
1966
|
}
|
|
1774
1967
|
return {
|
|
1775
1968
|
schema: {},
|
|
1776
|
-
keywordLocationToken: ""
|
|
1969
|
+
keywordLocationToken: "",
|
|
1970
|
+
required: false
|
|
1777
1971
|
};
|
|
1778
1972
|
}
|
|
1779
1973
|
|
|
1780
1974
|
// src/default.ts
|
|
1781
|
-
function
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
if (
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
obj =
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
if (schema.properties) {
|
|
1798
|
-
for (const [key, subschema] of Object.entries(schema.properties)) {
|
|
1799
|
-
if (obj[key] !== void 0) {
|
|
1800
|
-
obj[key] = getDefaultValue(subschema, obj[key], strategy);
|
|
1801
|
-
} else if (schema.required?.includes(key)) {
|
|
1802
|
-
obj[key] = getDefaultValue(subschema, void 0, strategy);
|
|
1975
|
+
function typeNullable(schema) {
|
|
1976
|
+
const types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
|
|
1977
|
+
const nullable = types.includes("null");
|
|
1978
|
+
const type = types.find((t) => t !== "null");
|
|
1979
|
+
return [type, nullable];
|
|
1980
|
+
}
|
|
1981
|
+
function getDefaultValue(schema, required = false) {
|
|
1982
|
+
if (schema.const !== void 0) return schema.const;
|
|
1983
|
+
if (schema.default !== void 0) return schema.default;
|
|
1984
|
+
const [type, nullable] = typeNullable(schema);
|
|
1985
|
+
switch (type) {
|
|
1986
|
+
case "object": {
|
|
1987
|
+
const obj = {};
|
|
1988
|
+
for (const [key, subschema] of Object.entries(schema.properties || {})) {
|
|
1989
|
+
if (schema.required?.includes(key)) {
|
|
1990
|
+
obj[key] = getDefaultValue(subschema, true);
|
|
1803
1991
|
}
|
|
1804
1992
|
}
|
|
1993
|
+
if (Object.keys(obj).length === 0) {
|
|
1994
|
+
return required ? nullable ? null : {} : void 0;
|
|
1995
|
+
}
|
|
1996
|
+
return obj;
|
|
1805
1997
|
}
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
if (value === void 0) {
|
|
1811
|
-
arr = [];
|
|
1812
|
-
} else if (Array.isArray(value)) {
|
|
1813
|
-
arr = value;
|
|
1814
|
-
} else {
|
|
1815
|
-
return value;
|
|
1816
|
-
}
|
|
1817
|
-
if (schema.prefixItems) {
|
|
1818
|
-
schema.prefixItems.forEach((subschema, index) => {
|
|
1819
|
-
if (index < arr.length) {
|
|
1820
|
-
arr[index] = getDefaultValue(subschema, arr[index], strategy);
|
|
1821
|
-
} else if (value === void 0) {
|
|
1822
|
-
arr.push(getDefaultValue(subschema, void 0, strategy));
|
|
1823
|
-
}
|
|
1998
|
+
case "array": {
|
|
1999
|
+
const arr = [];
|
|
2000
|
+
schema.prefixItems?.forEach((subschema) => {
|
|
2001
|
+
arr.push(getDefaultValue(subschema, true));
|
|
1824
2002
|
});
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
const startIndex = schema.prefixItems ? schema.prefixItems.length : 0;
|
|
1828
|
-
for (let i = startIndex; i < arr.length; i++) {
|
|
1829
|
-
arr[i] = getDefaultValue(schema.items, arr[i], strategy);
|
|
2003
|
+
if (arr.length === 0) {
|
|
2004
|
+
return required ? nullable ? null : [] : void 0;
|
|
1830
2005
|
}
|
|
2006
|
+
return arr;
|
|
1831
2007
|
}
|
|
1832
|
-
return arr;
|
|
1833
|
-
}
|
|
1834
|
-
if (value !== void 0) {
|
|
1835
|
-
return value;
|
|
1836
|
-
}
|
|
1837
|
-
switch (type) {
|
|
1838
2008
|
case "string":
|
|
1839
|
-
return "";
|
|
2009
|
+
return required ? nullable ? null : "" : void 0;
|
|
1840
2010
|
case "number":
|
|
2011
|
+
return required ? nullable ? null : 0 : void 0;
|
|
1841
2012
|
case "integer":
|
|
1842
|
-
return 0;
|
|
2013
|
+
return required ? nullable ? null : 0 : void 0;
|
|
1843
2014
|
case "boolean":
|
|
1844
|
-
return false;
|
|
2015
|
+
return required ? nullable ? null : false : void 0;
|
|
1845
2016
|
case "null":
|
|
1846
2017
|
return null;
|
|
1847
2018
|
default:
|
|
1848
2019
|
return void 0;
|
|
1849
2020
|
}
|
|
1850
2021
|
}
|
|
2022
|
+
function applyDefaults(type, value, schema, required = false) {
|
|
2023
|
+
if (value === void 0) {
|
|
2024
|
+
if (!required) {
|
|
2025
|
+
return [value, false];
|
|
2026
|
+
}
|
|
2027
|
+
const defaultValue = getDefaultValue(schema, required);
|
|
2028
|
+
return [defaultValue, defaultValue !== void 0];
|
|
2029
|
+
}
|
|
2030
|
+
const [_, nullable] = typeNullable(schema);
|
|
2031
|
+
if (nullable && value === null) {
|
|
2032
|
+
return [null, false];
|
|
2033
|
+
}
|
|
2034
|
+
let changed = false;
|
|
2035
|
+
if (type === "object") {
|
|
2036
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
2037
|
+
return [value, false];
|
|
2038
|
+
}
|
|
2039
|
+
const obj = value;
|
|
2040
|
+
for (const [key, subschema] of Object.entries(schema.properties || {})) {
|
|
2041
|
+
if (obj[key] !== void 0) continue;
|
|
2042
|
+
if (schema.required?.includes(key) || subschema.default) {
|
|
2043
|
+
const defaultValue = getDefaultValue(subschema, required);
|
|
2044
|
+
if (defaultValue !== void 0) {
|
|
2045
|
+
obj[key] = defaultValue;
|
|
2046
|
+
changed = true;
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
return [obj, changed];
|
|
2051
|
+
}
|
|
2052
|
+
if (type === "array") {
|
|
2053
|
+
if (!Array.isArray(value)) {
|
|
2054
|
+
return [value, false];
|
|
2055
|
+
}
|
|
2056
|
+
const arr = value;
|
|
2057
|
+
schema.prefixItems?.forEach((subschema, index) => {
|
|
2058
|
+
if (arr[index] !== void 0) return;
|
|
2059
|
+
const defaultValue = getDefaultValue(subschema, true);
|
|
2060
|
+
if (defaultValue !== void 0) {
|
|
2061
|
+
arr[index] = defaultValue;
|
|
2062
|
+
changed = true;
|
|
2063
|
+
}
|
|
2064
|
+
});
|
|
2065
|
+
return [arr, changed];
|
|
2066
|
+
}
|
|
2067
|
+
return [value, false];
|
|
2068
|
+
}
|
|
1851
2069
|
|
|
1852
2070
|
// src/dependency.ts
|
|
1853
2071
|
function collectDependencies(schema, instanceLocation) {
|
|
@@ -2009,12 +2227,8 @@ function extractReferencedPaths(conditionSchema, basePath = "", depth = 0) {
|
|
|
2009
2227
|
}
|
|
2010
2228
|
}
|
|
2011
2229
|
}
|
|
2012
|
-
if (schema.
|
|
2013
|
-
|
|
2014
|
-
const keyPath = basePath ? `${basePath}/${key}` : `/${key}`;
|
|
2015
|
-
paths.push(keyPath);
|
|
2016
|
-
paths.push(...extractReferencedPaths(subSchema, basePath, depth + 1));
|
|
2017
|
-
}
|
|
2230
|
+
if (schema.not) {
|
|
2231
|
+
paths.push(...extractReferencedPaths(schema.not, basePath, depth + 1));
|
|
2018
2232
|
}
|
|
2019
2233
|
if (schema.contains) {
|
|
2020
2234
|
paths.push(basePath || "/");
|
|
@@ -2024,12 +2238,9 @@ function extractReferencedPaths(conditionSchema, basePath = "", depth = 0) {
|
|
|
2024
2238
|
}
|
|
2025
2239
|
|
|
2026
2240
|
// src/render.ts
|
|
2027
|
-
var ROOT_PATH = "";
|
|
2028
|
-
function normalizeRootPath(path) {
|
|
2029
|
-
return path === "#" ? ROOT_PATH : path;
|
|
2030
|
-
}
|
|
2031
2241
|
var SchemaRuntime = class {
|
|
2032
2242
|
validator;
|
|
2243
|
+
normalizer;
|
|
2033
2244
|
watchers = {};
|
|
2034
2245
|
globalWatchers = /* @__PURE__ */ new Set();
|
|
2035
2246
|
// Reverse dependency index: path -> nodes that depend on this path's value
|
|
@@ -2056,13 +2267,30 @@ var SchemaRuntime = class {
|
|
|
2056
2267
|
*/
|
|
2057
2268
|
constructor(validator, schema, value, options = {}) {
|
|
2058
2269
|
this.validator = validator;
|
|
2270
|
+
this.options = {
|
|
2271
|
+
fillDefaults: "auto",
|
|
2272
|
+
removeEmptyContainers: "auto",
|
|
2273
|
+
...options
|
|
2274
|
+
};
|
|
2275
|
+
this.normalizer = options.schemaNormalizer || new DraftNormalizer();
|
|
2059
2276
|
this.value = value;
|
|
2060
|
-
this.
|
|
2061
|
-
|
|
2062
|
-
this.
|
|
2277
|
+
this.rootSchema = this.resolveSchema(schema);
|
|
2278
|
+
this.root = this.createEmptyNode("", "#");
|
|
2279
|
+
this.buildNode(this.root, this.rootSchema);
|
|
2280
|
+
}
|
|
2281
|
+
resolveSchema(schema) {
|
|
2282
|
+
const normalized = this.normalizer.normalize(schema);
|
|
2283
|
+
const dereferenced = dereferenceSchemaDeep(normalized, normalized);
|
|
2284
|
+
return dereferenced;
|
|
2285
|
+
}
|
|
2286
|
+
/**
|
|
2287
|
+
* Update the entire schema.
|
|
2288
|
+
* This triggers a full rebuild of the node tree while preserving the current value.
|
|
2289
|
+
*/
|
|
2290
|
+
setSchema(schema) {
|
|
2291
|
+
this.rootSchema = this.resolveSchema(schema);
|
|
2063
2292
|
this.root = this.createEmptyNode("", "#");
|
|
2064
2293
|
this.buildNode(this.root, this.rootSchema);
|
|
2065
|
-
this.notify({ type: "schema", path: ROOT_PATH });
|
|
2066
2294
|
}
|
|
2067
2295
|
/**
|
|
2068
2296
|
* Register a node as dependent on a path
|
|
@@ -2111,13 +2339,17 @@ var SchemaRuntime = class {
|
|
|
2111
2339
|
return {
|
|
2112
2340
|
type: "null",
|
|
2113
2341
|
schema: {},
|
|
2342
|
+
// Placeholder, will be set in buildNode
|
|
2114
2343
|
version: -1,
|
|
2344
|
+
// -1 indicates initial construction (not yet built)
|
|
2115
2345
|
instanceLocation,
|
|
2116
2346
|
keywordLocation,
|
|
2117
2347
|
originalSchema: {},
|
|
2118
2348
|
canRemove: false,
|
|
2119
2349
|
canAdd: false,
|
|
2120
|
-
|
|
2350
|
+
required: false,
|
|
2351
|
+
children: [],
|
|
2352
|
+
activated: false
|
|
2121
2353
|
};
|
|
2122
2354
|
}
|
|
2123
2355
|
/**
|
|
@@ -2125,13 +2357,12 @@ var SchemaRuntime = class {
|
|
|
2125
2357
|
* Uses findNearestExistingNode to find the target node (or parent if path doesn't exist).
|
|
2126
2358
|
* Only rebuilds the affected subtree, not the entire tree.
|
|
2127
2359
|
*/
|
|
2128
|
-
reconcile(path) {
|
|
2129
|
-
const
|
|
2130
|
-
const targetNode = this.findNearestExistingNode(normalizedPath);
|
|
2360
|
+
reconcile(path, config = {}) {
|
|
2361
|
+
const targetNode = this.findNearestExistingNode(path);
|
|
2131
2362
|
if (!targetNode) {
|
|
2132
2363
|
return;
|
|
2133
2364
|
}
|
|
2134
|
-
this.buildNode(targetNode, targetNode.originalSchema);
|
|
2365
|
+
this.buildNode(targetNode, targetNode.originalSchema, config);
|
|
2135
2366
|
}
|
|
2136
2367
|
/**
|
|
2137
2368
|
* Get the current version number.
|
|
@@ -2158,17 +2389,16 @@ var SchemaRuntime = class {
|
|
|
2158
2389
|
* // Later: unsubscribe();
|
|
2159
2390
|
*/
|
|
2160
2391
|
subscribe(path, cb) {
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
this.watchers[normalizedPath] = /* @__PURE__ */ new Set();
|
|
2392
|
+
if (!this.watchers[path]) {
|
|
2393
|
+
this.watchers[path] = /* @__PURE__ */ new Set();
|
|
2164
2394
|
}
|
|
2165
|
-
this.watchers[
|
|
2395
|
+
this.watchers[path].add(cb);
|
|
2166
2396
|
return () => {
|
|
2167
|
-
const watcherSet = this.watchers[
|
|
2397
|
+
const watcherSet = this.watchers[path];
|
|
2168
2398
|
if (watcherSet) {
|
|
2169
2399
|
watcherSet.delete(cb);
|
|
2170
2400
|
if (watcherSet.size === 0) {
|
|
2171
|
-
delete this.watchers[
|
|
2401
|
+
delete this.watchers[path];
|
|
2172
2402
|
}
|
|
2173
2403
|
}
|
|
2174
2404
|
};
|
|
@@ -2194,8 +2424,7 @@ var SchemaRuntime = class {
|
|
|
2194
2424
|
*/
|
|
2195
2425
|
notify(event) {
|
|
2196
2426
|
this.version++;
|
|
2197
|
-
const
|
|
2198
|
-
const watchers = this.watchers[normalizedPath];
|
|
2427
|
+
const watchers = this.watchers[event.path];
|
|
2199
2428
|
if (watchers) {
|
|
2200
2429
|
for (const cb of watchers) {
|
|
2201
2430
|
try {
|
|
@@ -2213,17 +2442,6 @@ var SchemaRuntime = class {
|
|
|
2213
2442
|
}
|
|
2214
2443
|
}
|
|
2215
2444
|
}
|
|
2216
|
-
/**
|
|
2217
|
-
* Update the entire schema.
|
|
2218
|
-
* This triggers a full rebuild of the node tree while preserving the current value.
|
|
2219
|
-
*/
|
|
2220
|
-
setSchema(schema) {
|
|
2221
|
-
const normalized = normalizeSchema(schema);
|
|
2222
|
-
this.rootSchema = dereferenceSchemaDeep(normalized, normalized);
|
|
2223
|
-
this.root = this.createEmptyNode("", "#");
|
|
2224
|
-
this.buildNode(this.root, this.rootSchema);
|
|
2225
|
-
this.notify({ type: "schema", path: ROOT_PATH });
|
|
2226
|
-
}
|
|
2227
2445
|
/**
|
|
2228
2446
|
* Get the value at a specific path.
|
|
2229
2447
|
*
|
|
@@ -2235,48 +2453,149 @@ var SchemaRuntime = class {
|
|
|
2235
2453
|
* runtime.getValue("/name"); // returns value at /name
|
|
2236
2454
|
*/
|
|
2237
2455
|
getValue(path) {
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2456
|
+
if (path === "" || path === "#") {
|
|
2457
|
+
return this.value;
|
|
2458
|
+
}
|
|
2459
|
+
return getJsonPointer(this.value, path);
|
|
2241
2460
|
}
|
|
2242
2461
|
/**
|
|
2243
2462
|
* Internal helper to set a value at a normalized path.
|
|
2244
2463
|
* Handles both root and non-root paths.
|
|
2245
2464
|
*
|
|
2246
|
-
* @param
|
|
2465
|
+
* @param path - The JSON Pointer path
|
|
2247
2466
|
* @param value - The value to set
|
|
2248
2467
|
* @returns true if successful, false if the path cannot be set
|
|
2249
2468
|
*/
|
|
2250
|
-
|
|
2251
|
-
if (
|
|
2469
|
+
setJsonPointer(path, value) {
|
|
2470
|
+
if (path === "" || path === "#") {
|
|
2252
2471
|
this.value = value;
|
|
2253
2472
|
return true;
|
|
2254
2473
|
}
|
|
2255
|
-
|
|
2474
|
+
if (!this.value) {
|
|
2475
|
+
this.value = {};
|
|
2476
|
+
}
|
|
2477
|
+
return setJsonPointer(this.value, path, value);
|
|
2478
|
+
}
|
|
2479
|
+
/**
|
|
2480
|
+
* Internal method to remove a value at a path.
|
|
2481
|
+
* Shared logic for removeValue and setValue(undefined).
|
|
2482
|
+
* @param path - The normalized path to remove
|
|
2483
|
+
* @param canRemove - Whether the removal is allowed (pre-checked by caller)
|
|
2484
|
+
* @returns true if successful, false if removal failed
|
|
2485
|
+
*/
|
|
2486
|
+
removeValueInternal(path) {
|
|
2487
|
+
const success = removeJsonPointer(this.value, path);
|
|
2488
|
+
if (!success) {
|
|
2489
|
+
return false;
|
|
2490
|
+
}
|
|
2491
|
+
const reconcilePath = this.cleanupEmptyContainers(
|
|
2492
|
+
getJsonPointerParent(path)
|
|
2493
|
+
);
|
|
2494
|
+
this.reconcile(reconcilePath);
|
|
2495
|
+
this.notify({ type: "value", path: reconcilePath });
|
|
2496
|
+
return true;
|
|
2256
2497
|
}
|
|
2257
2498
|
/**
|
|
2258
2499
|
* Remove a node at the specified path.
|
|
2259
2500
|
* This deletes the value from the data structure (array splice or object delete).
|
|
2501
|
+
* After removal, may also remove empty parent containers based on removeEmptyContainers option.
|
|
2260
2502
|
* @param path - The path to remove
|
|
2261
2503
|
* @returns true if successful, false if the path cannot be removed
|
|
2262
2504
|
*/
|
|
2263
2505
|
removeValue(path) {
|
|
2264
|
-
|
|
2265
|
-
|
|
2506
|
+
return this.removeValueInternal(path);
|
|
2507
|
+
}
|
|
2508
|
+
/**
|
|
2509
|
+
* Clean up empty parent containers after element removal.
|
|
2510
|
+
* Recursively removes empty arrays/objects based on removeEmptyContainers option.
|
|
2511
|
+
* @param path - The path to check for empty container
|
|
2512
|
+
* @returns The topmost parent path changed
|
|
2513
|
+
*/
|
|
2514
|
+
cleanupEmptyContainers(path) {
|
|
2515
|
+
const strategy = this.options.removeEmptyContainers;
|
|
2516
|
+
if (strategy === "never") {
|
|
2517
|
+
return "";
|
|
2518
|
+
}
|
|
2519
|
+
const node = this.getNode(path);
|
|
2520
|
+
if (!node) {
|
|
2521
|
+
return path;
|
|
2522
|
+
}
|
|
2523
|
+
const value = this.getValue(path);
|
|
2524
|
+
const isEmpty = value === null || typeof value === "object" && Object.keys(value).length === 0;
|
|
2525
|
+
if (!isEmpty) {
|
|
2526
|
+
return path;
|
|
2527
|
+
}
|
|
2528
|
+
const shouldRemove = strategy === "auto" && !node.required;
|
|
2529
|
+
if (!shouldRemove) {
|
|
2530
|
+
return path;
|
|
2531
|
+
}
|
|
2532
|
+
const success = removeJsonPointer(this.value, path);
|
|
2533
|
+
if (!success) {
|
|
2534
|
+
return path;
|
|
2535
|
+
}
|
|
2536
|
+
return this.cleanupEmptyContainers(getJsonPointerParent(path));
|
|
2537
|
+
}
|
|
2538
|
+
/**
|
|
2539
|
+
* Get default value for a schema, respecting autoFillDefaults option.
|
|
2540
|
+
* Falls back to 'always' strategy if configured strategy returns undefined.
|
|
2541
|
+
* If still undefined (e.g., schema has no type), falls back to null as a valid JSON value.
|
|
2542
|
+
*/
|
|
2543
|
+
newDefaultValue(schema, required) {
|
|
2544
|
+
const strategy = this.options.fillDefaults;
|
|
2545
|
+
if (strategy === "never") {
|
|
2546
|
+
return void 0;
|
|
2547
|
+
}
|
|
2548
|
+
return getDefaultValue(schema, required);
|
|
2549
|
+
}
|
|
2550
|
+
addObjectProperty(parent, parentValue, propertyName, propertyValue) {
|
|
2551
|
+
if (!propertyName) {
|
|
2266
2552
|
return false;
|
|
2267
2553
|
}
|
|
2268
|
-
|
|
2269
|
-
|
|
2554
|
+
if (parentValue === void 0 || parentValue === null) {
|
|
2555
|
+
parentValue = {};
|
|
2556
|
+
this.setJsonPointer(parent.instanceLocation, parentValue);
|
|
2557
|
+
}
|
|
2558
|
+
if (typeof parentValue !== "object") {
|
|
2270
2559
|
return false;
|
|
2271
2560
|
}
|
|
2272
|
-
const
|
|
2273
|
-
|
|
2561
|
+
const { schema, keywordLocationToken, required } = getSubSchema(
|
|
2562
|
+
parent.schema,
|
|
2563
|
+
propertyName
|
|
2564
|
+
);
|
|
2565
|
+
if (!keywordLocationToken) {
|
|
2274
2566
|
return false;
|
|
2275
2567
|
}
|
|
2276
|
-
const
|
|
2277
|
-
const
|
|
2278
|
-
this.
|
|
2279
|
-
|
|
2568
|
+
const defaultValue = propertyValue !== void 0 ? propertyValue : this.newDefaultValue(schema, required);
|
|
2569
|
+
const propertyPath = jsonPointerJoin(parent.instanceLocation, propertyName);
|
|
2570
|
+
const success = setJsonPointer(this.value, propertyPath, defaultValue);
|
|
2571
|
+
if (!success) return false;
|
|
2572
|
+
this.reconcile(parent.instanceLocation);
|
|
2573
|
+
this.notify({ type: "value", path: parent.instanceLocation });
|
|
2574
|
+
return true;
|
|
2575
|
+
}
|
|
2576
|
+
addArrayItem(parent, parentValue, initialValue) {
|
|
2577
|
+
if (parentValue === void 0 || parentValue === null) {
|
|
2578
|
+
parentValue = [];
|
|
2579
|
+
this.setJsonPointer(parent.instanceLocation, parentValue);
|
|
2580
|
+
}
|
|
2581
|
+
if (!Array.isArray(parentValue)) {
|
|
2582
|
+
return false;
|
|
2583
|
+
}
|
|
2584
|
+
const newItemIndex = String(parentValue.length);
|
|
2585
|
+
const {
|
|
2586
|
+
schema: subschema,
|
|
2587
|
+
keywordLocationToken,
|
|
2588
|
+
required
|
|
2589
|
+
} = getSubSchema(parent.schema, newItemIndex);
|
|
2590
|
+
if (!keywordLocationToken) {
|
|
2591
|
+
return false;
|
|
2592
|
+
}
|
|
2593
|
+
const defaultValue = initialValue !== void 0 ? initialValue : this.newDefaultValue(subschema, required);
|
|
2594
|
+
const itemPath = jsonPointerJoin(parent.instanceLocation, newItemIndex);
|
|
2595
|
+
const success = setJsonPointer(this.value, itemPath, defaultValue);
|
|
2596
|
+
if (!success) return false;
|
|
2597
|
+
this.reconcile(parent.instanceLocation);
|
|
2598
|
+
this.notify({ type: "value", path: parent.instanceLocation });
|
|
2280
2599
|
return true;
|
|
2281
2600
|
}
|
|
2282
2601
|
/**
|
|
@@ -2288,63 +2607,19 @@ var SchemaRuntime = class {
|
|
|
2288
2607
|
* @param initialValue - Optional initial value to set. If not provided, uses default from schema.
|
|
2289
2608
|
* @returns true if successful, false if cannot add
|
|
2290
2609
|
*/
|
|
2291
|
-
|
|
2292
|
-
const
|
|
2293
|
-
const parentNode = this.findNode(normalizedPath);
|
|
2610
|
+
addChild(parentPath, key, initialValue) {
|
|
2611
|
+
const parentNode = this.getNode(parentPath);
|
|
2294
2612
|
if (!parentNode || !parentNode.canAdd) {
|
|
2295
2613
|
return false;
|
|
2296
2614
|
}
|
|
2297
|
-
|
|
2298
|
-
const parentSchema = parentNode.schema;
|
|
2615
|
+
const parentValue = this.getValue(parentPath);
|
|
2299
2616
|
if (parentNode.type === "array") {
|
|
2300
|
-
|
|
2301
|
-
parentValue = [];
|
|
2302
|
-
this.setValueAtPath(normalizedPath, parentValue);
|
|
2303
|
-
} else {
|
|
2304
|
-
return false;
|
|
2305
|
-
}
|
|
2617
|
+
return this.addArrayItem(parentNode, parentValue, initialValue);
|
|
2306
2618
|
} else if (parentNode.type === "object") {
|
|
2307
|
-
if (parentValue && typeof parentValue === "object") ; else if (parentValue === void 0 || parentValue === null) {
|
|
2308
|
-
parentValue = {};
|
|
2309
|
-
this.setValueAtPath(normalizedPath, parentValue);
|
|
2310
|
-
} else {
|
|
2311
|
-
return false;
|
|
2312
|
-
}
|
|
2313
|
-
}
|
|
2314
|
-
if (parentNode.type === "array" && Array.isArray(parentValue)) {
|
|
2315
|
-
const newIndex = parentValue.length;
|
|
2316
|
-
const { schema: subschema, keywordLocationToken } = getSubSchema(
|
|
2317
|
-
parentSchema,
|
|
2318
|
-
String(newIndex)
|
|
2319
|
-
);
|
|
2320
|
-
if (!keywordLocationToken) {
|
|
2321
|
-
return false;
|
|
2322
|
-
}
|
|
2323
|
-
const defaultValue = initialValue !== void 0 ? initialValue : getDefaultValue(subschema);
|
|
2324
|
-
const itemPath = jsonPointerJoin(normalizedPath, String(newIndex));
|
|
2325
|
-
const success = setJsonPointer(this.value, itemPath, defaultValue);
|
|
2326
|
-
if (!success) return false;
|
|
2327
|
-
this.reconcile(normalizedPath);
|
|
2328
|
-
this.notify({ type: "value", path: normalizedPath });
|
|
2329
|
-
return true;
|
|
2330
|
-
} else if (parentNode.type === "object" && typeof parentValue === "object") {
|
|
2331
2619
|
if (!key) {
|
|
2332
2620
|
return false;
|
|
2333
2621
|
}
|
|
2334
|
-
|
|
2335
|
-
parentSchema,
|
|
2336
|
-
key
|
|
2337
|
-
);
|
|
2338
|
-
if (!keywordLocationToken) {
|
|
2339
|
-
return false;
|
|
2340
|
-
}
|
|
2341
|
-
const defaultValue = initialValue !== void 0 ? initialValue : getDefaultValue(subschema);
|
|
2342
|
-
const propertyPath = jsonPointerJoin(normalizedPath, key);
|
|
2343
|
-
const success = setJsonPointer(this.value, propertyPath, defaultValue);
|
|
2344
|
-
if (!success) return false;
|
|
2345
|
-
this.reconcile(normalizedPath);
|
|
2346
|
-
this.notify({ type: "value", path: normalizedPath });
|
|
2347
|
-
return true;
|
|
2622
|
+
return this.addObjectProperty(parentNode, parentValue, key, initialValue);
|
|
2348
2623
|
}
|
|
2349
2624
|
return false;
|
|
2350
2625
|
}
|
|
@@ -2353,37 +2628,42 @@ var SchemaRuntime = class {
|
|
|
2353
2628
|
* Creates intermediate containers (objects/arrays) as needed.
|
|
2354
2629
|
* Triggers reconciliation and notifies subscribers.
|
|
2355
2630
|
*
|
|
2631
|
+
* When value is undefined and the field is not required, the field will be
|
|
2632
|
+
* removed from the parent container (similar to removeValue behavior).
|
|
2633
|
+
*
|
|
2356
2634
|
* @param path - The JSON Pointer path (e.g., "/user/name", "" for root)
|
|
2357
|
-
* @param value - The new value to set
|
|
2635
|
+
* @param value - The new value to set. If undefined and field is optional, removes the field.
|
|
2358
2636
|
* @returns true if successful, false if the path cannot be set
|
|
2359
2637
|
*
|
|
2360
2638
|
* @example
|
|
2361
2639
|
* runtime.setValue("/name", "Bob"); // set name to "Bob"
|
|
2362
2640
|
* runtime.setValue("", { name: "Alice" }); // replace entire root value
|
|
2641
|
+
* runtime.setValue("/optional", undefined); // remove optional field
|
|
2363
2642
|
*/
|
|
2364
2643
|
setValue(path, value) {
|
|
2365
|
-
|
|
2366
|
-
|
|
2644
|
+
if (value === void 0) {
|
|
2645
|
+
return this.removeValueInternal(path);
|
|
2646
|
+
}
|
|
2647
|
+
const success = this.setJsonPointer(path, value);
|
|
2367
2648
|
if (!success) return false;
|
|
2368
|
-
this.reconcile(
|
|
2369
|
-
this.notify({ type: "value", path
|
|
2649
|
+
this.reconcile(path);
|
|
2650
|
+
this.notify({ type: "value", path });
|
|
2370
2651
|
return true;
|
|
2371
2652
|
}
|
|
2372
2653
|
/**
|
|
2373
|
-
*
|
|
2654
|
+
* Get the FieldNode at a specific path.
|
|
2374
2655
|
* Returns the node tree representation that includes schema, type, error, and children.
|
|
2375
2656
|
*
|
|
2376
2657
|
* @param path - The JSON Pointer path (e.g., "/user/name", "" for root)
|
|
2377
2658
|
* @returns The FieldNode at the path, or undefined if not found
|
|
2378
2659
|
*
|
|
2379
2660
|
* @example
|
|
2380
|
-
* const node = runtime.
|
|
2661
|
+
* const node = runtime.getNode("/name");
|
|
2381
2662
|
* console.log(node?.schema, node?.type, node?.error);
|
|
2382
2663
|
*/
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
const segments = parseJsonPointer(normalizedPath);
|
|
2664
|
+
getNode(path) {
|
|
2665
|
+
if (path === "") return this.root;
|
|
2666
|
+
const segments = parseJsonPointer(path);
|
|
2387
2667
|
let current = this.root;
|
|
2388
2668
|
for (const segment of segments) {
|
|
2389
2669
|
if (!current?.children) return void 0;
|
|
@@ -2397,23 +2677,28 @@ var SchemaRuntime = class {
|
|
|
2397
2677
|
return current;
|
|
2398
2678
|
}
|
|
2399
2679
|
findNearestExistingNode(path) {
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
const node = this.findNode(currentPath);
|
|
2680
|
+
let currentPath = path;
|
|
2681
|
+
while (currentPath) {
|
|
2682
|
+
const node = this.getNode(currentPath);
|
|
2404
2683
|
if (node) return node;
|
|
2405
|
-
|
|
2406
|
-
currentPath = lastSlash <= 0 ? ROOT_PATH : currentPath.substring(0, lastSlash);
|
|
2684
|
+
currentPath = getJsonPointerParent(currentPath);
|
|
2407
2685
|
}
|
|
2408
2686
|
return this.root;
|
|
2409
2687
|
}
|
|
2688
|
+
validate(path) {
|
|
2689
|
+
const node = this.getNode(path);
|
|
2690
|
+
if (node) {
|
|
2691
|
+
this.buildNode(node, void 0, { setActivated: true });
|
|
2692
|
+
}
|
|
2693
|
+
this.reconcile(path);
|
|
2694
|
+
this.notify({ type: "value", path });
|
|
2695
|
+
}
|
|
2410
2696
|
/**
|
|
2411
2697
|
* Update node dependencies when schema changes.
|
|
2412
2698
|
* Unregisters old dependencies and registers new ones.
|
|
2413
2699
|
*/
|
|
2414
2700
|
updateNodeDependencies(node, schema) {
|
|
2415
2701
|
const { instanceLocation } = node;
|
|
2416
|
-
node.originalSchema = schema;
|
|
2417
2702
|
const dependencies = collectDependencies(schema, instanceLocation);
|
|
2418
2703
|
for (const depPath of node.dependencies || []) {
|
|
2419
2704
|
this.unregisterDependent(depPath, node);
|
|
@@ -2428,53 +2713,38 @@ var SchemaRuntime = class {
|
|
|
2428
2713
|
* This handles cases like if-then-else where new properties with defaults
|
|
2429
2714
|
* may appear when conditions change.
|
|
2430
2715
|
*
|
|
2716
|
+
* Container initialization rules:
|
|
2717
|
+
* - Required containers will be initialized if it has defaults or required properties
|
|
2718
|
+
* - Nested containers are initialized only if they are in parent's required array
|
|
2719
|
+
*
|
|
2431
2720
|
* @param instanceLocation - The path to the node
|
|
2432
2721
|
* @param newSchema - The new effective schema
|
|
2433
2722
|
* @param type - The schema type
|
|
2723
|
+
* @param required - Whether this node is required by its parent
|
|
2434
2724
|
*/
|
|
2435
|
-
applySchemaDefaults(instanceLocation, newSchema, type) {
|
|
2436
|
-
|
|
2725
|
+
applySchemaDefaults(instanceLocation, newSchema, type, required = true) {
|
|
2726
|
+
const strategy = this.options.fillDefaults;
|
|
2727
|
+
if (strategy === "never") {
|
|
2437
2728
|
return;
|
|
2438
2729
|
}
|
|
2439
2730
|
const value = this.getValue(instanceLocation);
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
for (const [key, subschema] of Object.entries(newSchema.properties)) {
|
|
2444
|
-
const hasValue = obj[key] !== void 0;
|
|
2445
|
-
if (!hasValue) {
|
|
2446
|
-
const defaultValue = getDefaultValue(
|
|
2447
|
-
subschema,
|
|
2448
|
-
void 0,
|
|
2449
|
-
this.options.autoFillDefaults
|
|
2450
|
-
);
|
|
2451
|
-
if (defaultValue !== void 0) {
|
|
2452
|
-
const propertyPath = jsonPointerJoin(instanceLocation, key);
|
|
2453
|
-
setJsonPointer(this.value, propertyPath, defaultValue);
|
|
2454
|
-
}
|
|
2455
|
-
}
|
|
2456
|
-
}
|
|
2457
|
-
return;
|
|
2458
|
-
}
|
|
2459
|
-
if (type === "array" && newSchema.prefixItems) {
|
|
2460
|
-
const arr = Array.isArray(value) ? value : null;
|
|
2461
|
-
if (!arr) return;
|
|
2462
|
-
for (let i = 0; i < newSchema.prefixItems.length; i++) {
|
|
2463
|
-
if (arr[i] === void 0) {
|
|
2464
|
-
const itemSchema = newSchema.prefixItems[i];
|
|
2465
|
-
const defaultValue = getDefaultValue(
|
|
2466
|
-
itemSchema,
|
|
2467
|
-
void 0,
|
|
2468
|
-
this.options.autoFillDefaults
|
|
2469
|
-
);
|
|
2470
|
-
if (defaultValue !== void 0) {
|
|
2471
|
-
const itemPath = jsonPointerJoin(instanceLocation, String(i));
|
|
2472
|
-
setJsonPointer(this.value, itemPath, defaultValue);
|
|
2473
|
-
}
|
|
2474
|
-
}
|
|
2475
|
-
}
|
|
2731
|
+
const [newValue, changed] = applyDefaults(type, value, newSchema, required);
|
|
2732
|
+
if (changed) {
|
|
2733
|
+
this.setJsonPointer(instanceLocation, newValue);
|
|
2476
2734
|
}
|
|
2477
2735
|
}
|
|
2736
|
+
/**
|
|
2737
|
+
* Sort property entries by x-order.
|
|
2738
|
+
* Properties with lower x-order values come first.
|
|
2739
|
+
* Properties without x-order are placed at the end.
|
|
2740
|
+
*/
|
|
2741
|
+
sortPropertiesByOrder(entries) {
|
|
2742
|
+
return entries.sort(([, schemaA], [, schemaB]) => {
|
|
2743
|
+
const orderA = typeof schemaA["x-order"] === "number" ? schemaA["x-order"] : Infinity;
|
|
2744
|
+
const orderB = typeof schemaB["x-order"] === "number" ? schemaB["x-order"] : Infinity;
|
|
2745
|
+
return orderA - orderB;
|
|
2746
|
+
});
|
|
2747
|
+
}
|
|
2478
2748
|
/**
|
|
2479
2749
|
* Build children for object and array nodes.
|
|
2480
2750
|
* Reuses existing child nodes where possible.
|
|
@@ -2483,44 +2753,48 @@ var SchemaRuntime = class {
|
|
|
2483
2753
|
const { keywordLocation, instanceLocation } = node;
|
|
2484
2754
|
const effectiveSchema = node.schema;
|
|
2485
2755
|
const type = node.type;
|
|
2756
|
+
const processedKeys = /* @__PURE__ */ new Set();
|
|
2757
|
+
const newChildren = [];
|
|
2486
2758
|
const oldChildrenMap = /* @__PURE__ */ new Map();
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
oldChildrenMap.set(child.instanceLocation, child);
|
|
2490
|
-
}
|
|
2759
|
+
for (const child of node.children || []) {
|
|
2760
|
+
oldChildrenMap.set(child.instanceLocation, child);
|
|
2491
2761
|
}
|
|
2492
|
-
const
|
|
2493
|
-
const processChild = (childKey, childSchema, childkeywordLocation, canRemove = false) => {
|
|
2762
|
+
const processChild = (childKey, childSchema, childkeywordLocation, canRemove = false, isRequired = false) => {
|
|
2494
2763
|
const childinstanceLocation = jsonPointerJoin(instanceLocation, childKey);
|
|
2764
|
+
if (processedKeys.has(childinstanceLocation)) {
|
|
2765
|
+
return;
|
|
2766
|
+
}
|
|
2767
|
+
processedKeys.add(childinstanceLocation);
|
|
2495
2768
|
let childNode = oldChildrenMap.get(childinstanceLocation);
|
|
2496
|
-
if (childNode) {
|
|
2497
|
-
oldChildrenMap.delete(childinstanceLocation);
|
|
2498
|
-
childNode.keywordLocation = childkeywordLocation;
|
|
2499
|
-
} else {
|
|
2769
|
+
if (!childNode) {
|
|
2500
2770
|
childNode = this.createEmptyNode(
|
|
2501
2771
|
childinstanceLocation,
|
|
2502
2772
|
childkeywordLocation
|
|
2503
2773
|
);
|
|
2504
2774
|
}
|
|
2775
|
+
childNode.keywordLocation = childkeywordLocation;
|
|
2776
|
+
childNode.originKeywordLocation = typeof childSchema["x-origin-keyword"] === "string" ? childSchema["x-origin-keyword"] : childkeywordLocation;
|
|
2505
2777
|
childNode.canRemove = canRemove;
|
|
2506
|
-
|
|
2778
|
+
childNode.required = isRequired;
|
|
2779
|
+
this.buildNode(childNode, childSchema, { ...options });
|
|
2507
2780
|
newChildren.push(childNode);
|
|
2508
2781
|
};
|
|
2509
2782
|
switch (type) {
|
|
2510
2783
|
case "object": {
|
|
2511
2784
|
const valueKeys = value && typeof value === "object" ? Object.keys(value) : [];
|
|
2512
|
-
|
|
2513
|
-
node.canAdd = !!effectiveSchema.additionalProperties;
|
|
2785
|
+
node.canAdd = !!effectiveSchema.additionalProperties || !!effectiveSchema.patternProperties;
|
|
2514
2786
|
if (effectiveSchema.properties) {
|
|
2515
|
-
|
|
2516
|
-
effectiveSchema.properties
|
|
2517
|
-
)
|
|
2518
|
-
|
|
2787
|
+
const propertyEntries = this.sortPropertiesByOrder(
|
|
2788
|
+
Object.entries(effectiveSchema.properties)
|
|
2789
|
+
);
|
|
2790
|
+
for (const [key, subschema] of propertyEntries) {
|
|
2791
|
+
const isChildRequired = effectiveSchema.required?.includes(key) ?? false;
|
|
2519
2792
|
processChild(
|
|
2520
2793
|
key,
|
|
2521
2794
|
subschema,
|
|
2522
2795
|
`${keywordLocation}/properties/${key}`,
|
|
2523
|
-
false
|
|
2796
|
+
false,
|
|
2797
|
+
isChildRequired
|
|
2524
2798
|
);
|
|
2525
2799
|
}
|
|
2526
2800
|
}
|
|
@@ -2529,13 +2803,14 @@ var SchemaRuntime = class {
|
|
|
2529
2803
|
effectiveSchema.patternProperties
|
|
2530
2804
|
)) {
|
|
2531
2805
|
for (const key of valueKeys) {
|
|
2532
|
-
if (safeRegexTest(pattern, key)
|
|
2533
|
-
processedKeys.add(key);
|
|
2806
|
+
if (safeRegexTest(pattern, key)) {
|
|
2534
2807
|
processChild(
|
|
2535
2808
|
key,
|
|
2536
2809
|
subschema,
|
|
2537
2810
|
`${keywordLocation}/patternProperties/${jsonPointerEscape(pattern)}`,
|
|
2538
|
-
true
|
|
2811
|
+
true,
|
|
2812
|
+
false
|
|
2813
|
+
// patternProperties are never required
|
|
2539
2814
|
);
|
|
2540
2815
|
}
|
|
2541
2816
|
}
|
|
@@ -2544,14 +2819,14 @@ var SchemaRuntime = class {
|
|
|
2544
2819
|
if (effectiveSchema.additionalProperties) {
|
|
2545
2820
|
const subschema = typeof effectiveSchema.additionalProperties === "object" ? effectiveSchema.additionalProperties : {};
|
|
2546
2821
|
for (const key of valueKeys) {
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2822
|
+
processChild(
|
|
2823
|
+
key,
|
|
2824
|
+
subschema,
|
|
2825
|
+
`${keywordLocation}/additionalProperties`,
|
|
2826
|
+
true,
|
|
2827
|
+
false
|
|
2828
|
+
// additionalProperties are never required
|
|
2829
|
+
);
|
|
2555
2830
|
}
|
|
2556
2831
|
}
|
|
2557
2832
|
break;
|
|
@@ -2567,7 +2842,9 @@ var SchemaRuntime = class {
|
|
|
2567
2842
|
String(i),
|
|
2568
2843
|
effectiveSchema.prefixItems[i],
|
|
2569
2844
|
`${keywordLocation}/prefixItems/${i}`,
|
|
2570
|
-
false
|
|
2845
|
+
false,
|
|
2846
|
+
true
|
|
2847
|
+
// array prefix items are always considered required
|
|
2571
2848
|
);
|
|
2572
2849
|
}
|
|
2573
2850
|
}
|
|
@@ -2577,7 +2854,9 @@ var SchemaRuntime = class {
|
|
|
2577
2854
|
String(i),
|
|
2578
2855
|
effectiveSchema.items,
|
|
2579
2856
|
`${keywordLocation}/items`,
|
|
2857
|
+
true,
|
|
2580
2858
|
true
|
|
2859
|
+
// array items are always considered required
|
|
2581
2860
|
);
|
|
2582
2861
|
}
|
|
2583
2862
|
}
|
|
@@ -2585,8 +2864,10 @@ var SchemaRuntime = class {
|
|
|
2585
2864
|
break;
|
|
2586
2865
|
}
|
|
2587
2866
|
}
|
|
2588
|
-
for (const
|
|
2589
|
-
|
|
2867
|
+
for (const [location, child] of oldChildrenMap) {
|
|
2868
|
+
if (!processedKeys.has(location)) {
|
|
2869
|
+
this.unregisterNodeDependencies(child);
|
|
2870
|
+
}
|
|
2590
2871
|
}
|
|
2591
2872
|
node.children = newChildren;
|
|
2592
2873
|
}
|
|
@@ -2594,10 +2875,14 @@ var SchemaRuntime = class {
|
|
|
2594
2875
|
* Build/update a FieldNode in place.
|
|
2595
2876
|
* Updates the node's schema, type, error, and children based on the current value.
|
|
2596
2877
|
* @param schema - Optional. If provided, updates node.originalSchema. Otherwise uses existing.
|
|
2878
|
+
* @param isRequired - Whether this node is required by its parent schema.
|
|
2597
2879
|
*/
|
|
2598
2880
|
buildNode(node, schema, options = {}) {
|
|
2599
2881
|
const { keywordLocation, instanceLocation } = node;
|
|
2600
2882
|
const value = this.getValue(instanceLocation);
|
|
2883
|
+
if (options.setActivated) {
|
|
2884
|
+
node.activated = true;
|
|
2885
|
+
}
|
|
2601
2886
|
if (this.updatingNodes.has(instanceLocation)) {
|
|
2602
2887
|
return;
|
|
2603
2888
|
}
|
|
@@ -2609,6 +2894,7 @@ var SchemaRuntime = class {
|
|
|
2609
2894
|
try {
|
|
2610
2895
|
const schemaChanged = schema !== void 0 && !deepEqual(schema, node.originalSchema);
|
|
2611
2896
|
if (schemaChanged) {
|
|
2897
|
+
node.originalSchema = schema;
|
|
2612
2898
|
this.updateNodeDependencies(node, schema);
|
|
2613
2899
|
}
|
|
2614
2900
|
const { type, effectiveSchema, error } = resolveEffectiveSchema(
|
|
@@ -2616,41 +2902,52 @@ var SchemaRuntime = class {
|
|
|
2616
2902
|
node.originalSchema,
|
|
2617
2903
|
value,
|
|
2618
2904
|
keywordLocation,
|
|
2619
|
-
instanceLocation
|
|
2905
|
+
instanceLocation,
|
|
2906
|
+
node.activated
|
|
2620
2907
|
);
|
|
2621
2908
|
const effectiveSchemaChanged = !deepEqual(effectiveSchema, node.schema) || type !== node.type;
|
|
2622
2909
|
const errorChanged = !deepEqual(error, node.error);
|
|
2623
2910
|
if (effectiveSchemaChanged) {
|
|
2624
|
-
this.applySchemaDefaults(
|
|
2911
|
+
this.applySchemaDefaults(
|
|
2912
|
+
instanceLocation,
|
|
2913
|
+
effectiveSchema,
|
|
2914
|
+
type,
|
|
2915
|
+
node.required
|
|
2916
|
+
);
|
|
2625
2917
|
}
|
|
2626
2918
|
node.schema = effectiveSchema;
|
|
2627
2919
|
node.type = type;
|
|
2628
2920
|
node.error = error;
|
|
2629
2921
|
node.version++;
|
|
2630
2922
|
const currentValue = this.getValue(instanceLocation);
|
|
2631
|
-
this.buildNodeChildren(node, currentValue, {
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
this.notify({ type: "error", path: instanceLocation });
|
|
2637
|
-
}
|
|
2923
|
+
this.buildNodeChildren(node, currentValue, {
|
|
2924
|
+
setActivated: options.setActivated || void 0,
|
|
2925
|
+
// propagate activation
|
|
2926
|
+
updatedNodes
|
|
2927
|
+
});
|
|
2638
2928
|
updatedNodes.add(instanceLocation);
|
|
2639
2929
|
const dependentNodes = this.dependentsMap.get(instanceLocation);
|
|
2640
2930
|
if (dependentNodes) {
|
|
2641
2931
|
for (const dependentNode of dependentNodes) {
|
|
2642
2932
|
this.buildNode(dependentNode, void 0, {
|
|
2643
|
-
|
|
2933
|
+
setActivated: void 0,
|
|
2934
|
+
// do not change dependent node activation state
|
|
2644
2935
|
updatedNodes
|
|
2645
2936
|
});
|
|
2646
2937
|
}
|
|
2647
2938
|
}
|
|
2939
|
+
if (effectiveSchemaChanged) {
|
|
2940
|
+
this.notify({ type: "schema", path: instanceLocation });
|
|
2941
|
+
}
|
|
2942
|
+
if (errorChanged) {
|
|
2943
|
+
this.notify({ type: "error", path: instanceLocation });
|
|
2944
|
+
}
|
|
2648
2945
|
} finally {
|
|
2649
2946
|
this.updatingNodes.delete(instanceLocation);
|
|
2650
2947
|
}
|
|
2651
2948
|
}
|
|
2652
2949
|
};
|
|
2653
2950
|
|
|
2654
|
-
export { DRAFT_URIS, MESSAGES, SchemaRuntime, StringFormatValidator, Validator, collectDependencies, deepEqual, defaultErrorFormatter, detectSchemaDraft, detectSchemaType, extractReferencedPaths, get, getDefaultValue, getJsonPointer, jsonPointerEscape, jsonPointerJoin, jsonPointerUnescape, matchSchemaType, normalizeSchema, parseJsonPointer, removeJsonPointer, resolveAbsolutePath, safeRegexTest, setJsonPointer, stringFormatValidator, validateSchema };
|
|
2951
|
+
export { BetterNormalizer, DRAFT_URIS, DraftNormalizer, MESSAGES, SchemaRuntime, StringFormatValidator, Validator, applyDefaults, collectDependencies, deepEqual, defaultErrorFormatter, detectSchemaDraft, detectSchemaType, extractReferencedPaths, get, getDefaultValue, getJsonPointer, getJsonPointerParent, jsonPointerEscape, jsonPointerJoin, jsonPointerUnescape, matchSchemaType, normalizeSchema, parseJsonPointer, removeJsonPointer, resolveAbsolutePath, safeRegexTest, setJsonPointer, stringFormatValidator, typeNullable, validateSchema };
|
|
2655
2952
|
//# sourceMappingURL=index.js.map
|
|
2656
2953
|
//# sourceMappingURL=index.js.map
|