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