@o3co/ts.hocon 1.5.0 → 1.5.2
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 +262 -17
- package/dist/index.js +262 -17
- package/dist/zod.cjs +262 -17
- package/dist/zod.js +262 -17
- package/package.json +1 -1
package/dist/zod.cjs
CHANGED
|
@@ -329,6 +329,192 @@ function mergeUnresolved(receiver, fallback) {
|
|
|
329
329
|
return result;
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
+
// src/internal/resolver/fold-self-ref.ts
|
|
333
|
+
function substFullKey(s) {
|
|
334
|
+
return stringSegmentsToKey(s.segments.map((seg) => seg.text));
|
|
335
|
+
}
|
|
336
|
+
function stringSegmentsToKey(segments) {
|
|
337
|
+
return segments.map((t) => {
|
|
338
|
+
if (t === "" || /[^a-zA-Z0-9\-_]/.test(t)) {
|
|
339
|
+
return `"${t.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
340
|
+
}
|
|
341
|
+
return t;
|
|
342
|
+
}).join(".");
|
|
343
|
+
}
|
|
344
|
+
function containsSelfRef(v, fullKey) {
|
|
345
|
+
if (isSubst(v)) return substFullKey(v) === fullKey;
|
|
346
|
+
if (isConcat(v)) return v.nodes.some((n) => containsSelfRef(n, fullKey));
|
|
347
|
+
if (isAppend(v)) {
|
|
348
|
+
return containsSelfRef(v.existing, fullKey) || containsSelfRef(v.elem, fullKey);
|
|
349
|
+
}
|
|
350
|
+
if (isResObj(v)) {
|
|
351
|
+
for (const f of v.fields.values()) {
|
|
352
|
+
if (containsSelfRef(f, fullKey)) return true;
|
|
353
|
+
}
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
const hv = v;
|
|
357
|
+
if (hv.kind === "array") {
|
|
358
|
+
return hv.items.some((item) => containsSelfRef(item, fullKey));
|
|
359
|
+
}
|
|
360
|
+
if (hv.kind === "object") {
|
|
361
|
+
for (const f of hv.fields.values()) {
|
|
362
|
+
if (containsSelfRef(f, fullKey)) return true;
|
|
363
|
+
}
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
function foldSelfRef(v, fullKey, replacement) {
|
|
369
|
+
if (isSubst(v)) {
|
|
370
|
+
return substFullKey(v) === fullKey ? replacement : v;
|
|
371
|
+
}
|
|
372
|
+
if (isConcat(v)) {
|
|
373
|
+
return {
|
|
374
|
+
_kind: "concat-placeholder",
|
|
375
|
+
nodes: v.nodes.map((n) => foldSelfRef(n, fullKey, replacement)),
|
|
376
|
+
line: v.line,
|
|
377
|
+
col: v.col
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
if (isAppend(v)) {
|
|
381
|
+
return {
|
|
382
|
+
_kind: "append-placeholder",
|
|
383
|
+
existing: foldSelfRef(v.existing, fullKey, replacement),
|
|
384
|
+
elem: foldSelfRef(v.elem, fullKey, replacement)
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
if (isResObj(v)) {
|
|
388
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
389
|
+
for (const [k, val] of v.fields) {
|
|
390
|
+
newFields.set(k, foldSelfRef(val, fullKey, replacement));
|
|
391
|
+
}
|
|
392
|
+
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues) };
|
|
393
|
+
}
|
|
394
|
+
const hv = v;
|
|
395
|
+
if (hv.kind === "array") {
|
|
396
|
+
return {
|
|
397
|
+
kind: "array",
|
|
398
|
+
items: hv.items.map((item) => foldSelfRef(item, fullKey, replacement))
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
if (hv.kind === "object") {
|
|
402
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
403
|
+
for (const [k, val] of hv.fields) {
|
|
404
|
+
newFields.set(k, foldSelfRef(val, fullKey, replacement));
|
|
405
|
+
}
|
|
406
|
+
return { kind: "object", fields: newFields };
|
|
407
|
+
}
|
|
408
|
+
return v;
|
|
409
|
+
}
|
|
410
|
+
function foldOrSkipPrior(prior, fullKey, old) {
|
|
411
|
+
if (!containsSelfRef(prior, fullKey)) return cloneResolverValue(prior);
|
|
412
|
+
if (old === void 0) return void 0;
|
|
413
|
+
return foldSelfRef(prior, fullKey, old);
|
|
414
|
+
}
|
|
415
|
+
function cloneResolverValue(v) {
|
|
416
|
+
if (isSubst(v)) {
|
|
417
|
+
return {
|
|
418
|
+
_kind: "subst-placeholder",
|
|
419
|
+
segments: v.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
|
|
420
|
+
optional: v.optional,
|
|
421
|
+
listSuffix: v.listSuffix,
|
|
422
|
+
line: v.line,
|
|
423
|
+
col: v.col,
|
|
424
|
+
prefixLen: v.prefixLen
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
if (isConcat(v)) {
|
|
428
|
+
return {
|
|
429
|
+
_kind: "concat-placeholder",
|
|
430
|
+
nodes: v.nodes.map((n) => cloneResolverValue(n)),
|
|
431
|
+
line: v.line,
|
|
432
|
+
col: v.col
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
if (isResObj(v)) {
|
|
436
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
437
|
+
for (const [k, val] of v.fields) newFields.set(k, cloneResolverValue(val));
|
|
438
|
+
const newPriors = /* @__PURE__ */ new Map();
|
|
439
|
+
for (const [k, val] of v.priorValues) newPriors.set(k, cloneResolverValue(val));
|
|
440
|
+
return { _kind: "res-obj", fields: newFields, priorValues: newPriors };
|
|
441
|
+
}
|
|
442
|
+
if (isAppend(v)) {
|
|
443
|
+
return {
|
|
444
|
+
_kind: "append-placeholder",
|
|
445
|
+
existing: cloneResolverValue(v.existing),
|
|
446
|
+
elem: cloneResolverValue(v.elem)
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
const hv = v;
|
|
450
|
+
if (hv.kind === "array") {
|
|
451
|
+
return {
|
|
452
|
+
kind: "array",
|
|
453
|
+
items: hv.items.map((item) => cloneResolverValue(item))
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
if (hv.kind === "object") {
|
|
457
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
458
|
+
for (const [k, val] of hv.fields) {
|
|
459
|
+
newFields.set(k, cloneResolverValue(val));
|
|
460
|
+
}
|
|
461
|
+
return { kind: "object", fields: newFields };
|
|
462
|
+
}
|
|
463
|
+
return hv;
|
|
464
|
+
}
|
|
465
|
+
function foldNestedSelfRefs(v, pathPrefix) {
|
|
466
|
+
if (!isResObj(v)) return v;
|
|
467
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
468
|
+
for (const [k, fieldVal] of v.fields) {
|
|
469
|
+
const childPath = [...pathPrefix, k];
|
|
470
|
+
const fullKey = stringSegmentsToKey(childPath);
|
|
471
|
+
const folded = foldNestedSelfRefs(fieldVal, childPath);
|
|
472
|
+
let finalVal = folded;
|
|
473
|
+
if (containsSelfRef(folded, fullKey)) {
|
|
474
|
+
const leafPrior = v.priorValues.get(k);
|
|
475
|
+
if (leafPrior !== void 0) {
|
|
476
|
+
const leafPriorFolded = foldNestedSelfRefs(leafPrior, childPath);
|
|
477
|
+
finalVal = foldSelfRef(folded, fullKey, leafPriorFolded);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
newFields.set(k, finalVal);
|
|
481
|
+
}
|
|
482
|
+
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues) };
|
|
483
|
+
}
|
|
484
|
+
function containsSubstByPath(v, target) {
|
|
485
|
+
if (isSubst(v)) return segmentsTextEqual(v.segments, target);
|
|
486
|
+
if (isConcat(v)) return v.nodes.some((n) => containsSubstByPath(n, target));
|
|
487
|
+
if (isAppend(v)) {
|
|
488
|
+
return containsSubstByPath(v.existing, target) || containsSubstByPath(v.elem, target);
|
|
489
|
+
}
|
|
490
|
+
if (isResObj(v)) {
|
|
491
|
+
for (const f of v.fields.values()) {
|
|
492
|
+
if (containsSubstByPath(f, target)) return true;
|
|
493
|
+
}
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
496
|
+
const hv = v;
|
|
497
|
+
if (hv.kind === "array") {
|
|
498
|
+
return hv.items.some((item) => containsSubstByPath(item, target));
|
|
499
|
+
}
|
|
500
|
+
if (hv.kind === "object") {
|
|
501
|
+
for (const f of hv.fields.values()) {
|
|
502
|
+
if (containsSubstByPath(f, target)) return true;
|
|
503
|
+
}
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
function segmentsTextEqual(a, b) {
|
|
509
|
+
if (a.length !== b.length) return false;
|
|
510
|
+
for (let i = 0; i < a.length; i++) {
|
|
511
|
+
const ai = a[i];
|
|
512
|
+
const bi = b[i];
|
|
513
|
+
if (ai === void 0 || bi === void 0 || ai.text !== bi.text) return false;
|
|
514
|
+
}
|
|
515
|
+
return true;
|
|
516
|
+
}
|
|
517
|
+
|
|
332
518
|
// src/internal/resolver/utils.ts
|
|
333
519
|
function segmentsToKey(segments) {
|
|
334
520
|
return segments.map((s) => {
|
|
@@ -370,13 +556,22 @@ function deepMergeHoconValues(base, overlay) {
|
|
|
370
556
|
}
|
|
371
557
|
return { kind: "object", fields: merged };
|
|
372
558
|
}
|
|
373
|
-
function deepMergeResObjInto(dst, src) {
|
|
559
|
+
function deepMergeResObjInto(dst, src, pathPrefix = []) {
|
|
374
560
|
for (const [k, srcVal] of src.fields) {
|
|
561
|
+
const childPrefix = [...pathPrefix, k];
|
|
562
|
+
const fullKey = stringSegmentsToKey(childPrefix);
|
|
375
563
|
const dstVal = dst.fields.get(k);
|
|
376
564
|
if (dstVal !== void 0 && isResObj(dstVal) && isResObj(srcVal)) {
|
|
377
|
-
|
|
565
|
+
const priorExisting = dst.priorValues.get(k);
|
|
566
|
+
const prior = foldOrSkipPrior(dstVal, fullKey, priorExisting);
|
|
567
|
+
if (prior !== void 0) dst.priorValues.set(k, prior);
|
|
568
|
+
deepMergeResObjInto(dstVal, srcVal, childPrefix);
|
|
378
569
|
} else {
|
|
379
|
-
if (dstVal !== void 0)
|
|
570
|
+
if (dstVal !== void 0) {
|
|
571
|
+
const priorExisting = dst.priorValues.get(k);
|
|
572
|
+
const prior = foldOrSkipPrior(dstVal, fullKey, priorExisting);
|
|
573
|
+
if (prior !== void 0) dst.priorValues.set(k, prior);
|
|
574
|
+
}
|
|
380
575
|
dst.fields.set(k, srcVal);
|
|
381
576
|
}
|
|
382
577
|
}
|
|
@@ -1387,7 +1582,7 @@ var IncludeLoader = class {
|
|
|
1387
1582
|
for (const ext of probeExts) {
|
|
1388
1583
|
const obj = this.loadSingle(`${absPath}${ext}`);
|
|
1389
1584
|
if (obj !== void 0) {
|
|
1390
|
-
deepMergeResObjInto(merged, obj);
|
|
1585
|
+
deepMergeResObjInto(merged, obj, []);
|
|
1391
1586
|
foundAny = true;
|
|
1392
1587
|
}
|
|
1393
1588
|
}
|
|
@@ -1420,7 +1615,7 @@ var IncludeLoader = class {
|
|
|
1420
1615
|
for (const ext of probeExts) {
|
|
1421
1616
|
const obj = await this.loadSingleAsync(`${absPath}${ext}`);
|
|
1422
1617
|
if (obj !== void 0) {
|
|
1423
|
-
deepMergeResObjInto(merged, obj);
|
|
1618
|
+
deepMergeResObjInto(merged, obj, []);
|
|
1424
1619
|
foundAny = true;
|
|
1425
1620
|
}
|
|
1426
1621
|
}
|
|
@@ -1592,7 +1787,7 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1592
1787
|
if (pathPrefix.length > 0) {
|
|
1593
1788
|
this.relativizeResObj(included, pathPrefix);
|
|
1594
1789
|
}
|
|
1595
|
-
deepMergeResObjInto(obj, included);
|
|
1790
|
+
deepMergeResObjInto(obj, included, pathPrefix);
|
|
1596
1791
|
return;
|
|
1597
1792
|
}
|
|
1598
1793
|
const [head, ...tail] = field.key;
|
|
@@ -1607,12 +1802,27 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1607
1802
|
return;
|
|
1608
1803
|
}
|
|
1609
1804
|
const childPrefix = [...pathPrefix, head];
|
|
1805
|
+
const fullKey = stringSegmentsToKey(childPrefix);
|
|
1610
1806
|
if (field.append) {
|
|
1611
1807
|
const existing2 = obj.fields.get(head) ?? { kind: "array", items: [] };
|
|
1612
|
-
obj.priorValues.
|
|
1808
|
+
const oldPrior = obj.priorValues.get(head);
|
|
1809
|
+
const folded = foldOrSkipPrior(existing2, fullKey, oldPrior);
|
|
1810
|
+
if (folded !== void 0) obj.priorValues.set(head, folded);
|
|
1613
1811
|
obj.fields.set(head, {
|
|
1614
1812
|
_kind: "append-placeholder",
|
|
1615
|
-
existing
|
|
1813
|
+
// Use the folded existing (self-ref-free) for the Append. When the
|
|
1814
|
+
// fold returned undefined (self-ref present but no old prior),
|
|
1815
|
+
// fall back to the original existing — resolveSubst will then
|
|
1816
|
+
// raise the "self-ref with no prior value" error at resolve time,
|
|
1817
|
+
// matching the pre-fix behaviour for that edge case.
|
|
1818
|
+
//
|
|
1819
|
+
// Clone `folded` again so the Append.existing and priorValues[head]
|
|
1820
|
+
// do not share the same Subst/Concat references — relativizeResObj
|
|
1821
|
+
// walks BOTH `fields` and `priorValues` and mutates Subst.segments
|
|
1822
|
+
// in place, so a shared reference would get its prefix applied
|
|
1823
|
+
// twice (resulting in e.g. `${outer.outer.base}` instead of
|
|
1824
|
+
// `${outer.base}`). Codex review on PR #131.
|
|
1825
|
+
existing: folded !== void 0 ? cloneResolverValue(folded) : existing2,
|
|
1616
1826
|
elem: this.astToResolverValue(field.value, childPrefix)
|
|
1617
1827
|
});
|
|
1618
1828
|
return;
|
|
@@ -1620,10 +1830,13 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1620
1830
|
const existing = obj.fields.get(head);
|
|
1621
1831
|
const newVal = this.astToResolverValue(field.value, childPrefix);
|
|
1622
1832
|
if (existing !== void 0) {
|
|
1623
|
-
|
|
1833
|
+
const exFolded = foldNestedSelfRefs(existing, childPrefix);
|
|
1834
|
+
const oldPrior = obj.priorValues.get(head);
|
|
1835
|
+
const prior = foldOrSkipPrior(exFolded, fullKey, oldPrior);
|
|
1836
|
+
if (prior !== void 0) obj.priorValues.set(head, prior);
|
|
1624
1837
|
}
|
|
1625
1838
|
if (existing !== void 0 && isResObj(existing) && isResObj(newVal)) {
|
|
1626
|
-
deepMergeResObjInto(existing, newVal);
|
|
1839
|
+
deepMergeResObjInto(existing, newVal, childPrefix);
|
|
1627
1840
|
return;
|
|
1628
1841
|
}
|
|
1629
1842
|
obj.fields.set(head, newVal);
|
|
@@ -1640,7 +1853,7 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1640
1853
|
if (pathPrefix.length > 0) {
|
|
1641
1854
|
this.relativizeResObj(included, pathPrefix);
|
|
1642
1855
|
}
|
|
1643
|
-
deepMergeResObjInto(obj, included);
|
|
1856
|
+
deepMergeResObjInto(obj, included, pathPrefix);
|
|
1644
1857
|
return;
|
|
1645
1858
|
}
|
|
1646
1859
|
const [head, ...tail] = field.key;
|
|
@@ -1655,12 +1868,15 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1655
1868
|
return;
|
|
1656
1869
|
}
|
|
1657
1870
|
const childPrefix = [...pathPrefix, head];
|
|
1871
|
+
const fullKey = stringSegmentsToKey(childPrefix);
|
|
1658
1872
|
if (field.append) {
|
|
1659
1873
|
const existing2 = obj.fields.get(head) ?? { kind: "array", items: [] };
|
|
1660
|
-
obj.priorValues.
|
|
1874
|
+
const oldPrior = obj.priorValues.get(head);
|
|
1875
|
+
const folded = foldOrSkipPrior(existing2, fullKey, oldPrior);
|
|
1876
|
+
if (folded !== void 0) obj.priorValues.set(head, folded);
|
|
1661
1877
|
obj.fields.set(head, {
|
|
1662
1878
|
_kind: "append-placeholder",
|
|
1663
|
-
existing: existing2,
|
|
1879
|
+
existing: folded !== void 0 ? cloneResolverValue(folded) : existing2,
|
|
1664
1880
|
elem: await this.astToResolverValueAsync(field.value, childPrefix)
|
|
1665
1881
|
});
|
|
1666
1882
|
return;
|
|
@@ -1668,10 +1884,13 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1668
1884
|
const existing = obj.fields.get(head);
|
|
1669
1885
|
const newVal = await this.astToResolverValueAsync(field.value, childPrefix);
|
|
1670
1886
|
if (existing !== void 0) {
|
|
1671
|
-
|
|
1887
|
+
const exFolded = foldNestedSelfRefs(existing, childPrefix);
|
|
1888
|
+
const oldPrior = obj.priorValues.get(head);
|
|
1889
|
+
const prior = foldOrSkipPrior(exFolded, fullKey, oldPrior);
|
|
1890
|
+
if (prior !== void 0) obj.priorValues.set(head, prior);
|
|
1672
1891
|
}
|
|
1673
1892
|
if (existing !== void 0 && isResObj(existing) && isResObj(newVal)) {
|
|
1674
|
-
deepMergeResObjInto(existing, newVal);
|
|
1893
|
+
deepMergeResObjInto(existing, newVal, childPrefix);
|
|
1675
1894
|
return;
|
|
1676
1895
|
}
|
|
1677
1896
|
obj.fields.set(head, newVal);
|
|
@@ -1803,6 +2022,23 @@ var SubstitutionResolver = class {
|
|
|
1803
2022
|
// narrower than path-equality. Spec amendment deferred to a follow-up
|
|
1804
2023
|
// xx.hocon PR (see Phase 6 #3f close-out notes).
|
|
1805
2024
|
this.resolvingConcats = /* @__PURE__ */ new WeakSet();
|
|
2025
|
+
// Path stack tracking the full dotted path of the field currently being
|
|
2026
|
+
// assigned in `resolveResObj`. Leaf keys are pushed on entry to each
|
|
2027
|
+
// `(key, val)` iteration and popped on exit, so nested objects build up
|
|
2028
|
+
// the full path (e.g. `["o", "history"]` while resolving `o.history`).
|
|
2029
|
+
//
|
|
2030
|
+
// Used to tighten self-ref detection at the L192 found-lookup site:
|
|
2031
|
+
// a substitution `${X}` whose looked-up value contains a Subst pointing
|
|
2032
|
+
// at `X` is only a true self-reference when the field currently being
|
|
2033
|
+
// assigned is `X` (or a descendant of `X`). Without this guard, an
|
|
2034
|
+
// external lookup like `b = ${o}` (where o has a self-referential
|
|
2035
|
+
// field) would mis-fire and short-circuit to o's prior, returning the
|
|
2036
|
+
// wrong value for b. The is_owner gate (rfp prefix-matches s.segments)
|
|
2037
|
+
// narrows the check to the owner case only.
|
|
2038
|
+
//
|
|
2039
|
+
// Cross-impl with rs.hocon v1.5.1's resolving_field_path (same purpose,
|
|
2040
|
+
// same prefix-match semantics).
|
|
2041
|
+
this.resolvingFieldPath = [];
|
|
1806
2042
|
}
|
|
1807
2043
|
/** Returns a prefix for error messages, including origin info when set. */
|
|
1808
2044
|
originPrefix() {
|
|
@@ -1814,7 +2050,13 @@ var SubstitutionResolver = class {
|
|
|
1814
2050
|
resolveResObj(obj) {
|
|
1815
2051
|
const result = /* @__PURE__ */ new Map();
|
|
1816
2052
|
for (const [key, val] of obj.fields) {
|
|
1817
|
-
|
|
2053
|
+
this.resolvingFieldPath.push(key);
|
|
2054
|
+
let resolved;
|
|
2055
|
+
try {
|
|
2056
|
+
resolved = this.resolveVal(val, obj);
|
|
2057
|
+
} finally {
|
|
2058
|
+
this.resolvingFieldPath.pop();
|
|
2059
|
+
}
|
|
1818
2060
|
if (resolved !== void 0) {
|
|
1819
2061
|
if (resolved.kind === "object") {
|
|
1820
2062
|
const prior = obj.priorValues.get(key);
|
|
@@ -1904,7 +2146,10 @@ var SubstitutionResolver = class {
|
|
|
1904
2146
|
try {
|
|
1905
2147
|
const found = lookupPath(this.root, s.segments);
|
|
1906
2148
|
if (found !== void 0) {
|
|
1907
|
-
|
|
2149
|
+
const rfp = this.resolvingFieldPath;
|
|
2150
|
+
const isOwner = rfp.length >= s.segments.length && s.segments.every((seg, i) => rfp[i] === seg.text);
|
|
2151
|
+
const isSelfRef = isConcat(found) && this.resolvingConcats.has(found) || isOwner && containsSubstByPath(found, s.segments);
|
|
2152
|
+
if (isSelfRef) {
|
|
1908
2153
|
let prior;
|
|
1909
2154
|
if (s.segments.length > 1) {
|
|
1910
2155
|
const leafSeg = s.segments[s.segments.length - 1]?.text ?? "";
|