@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.js
CHANGED
|
@@ -290,6 +290,192 @@ function mergeUnresolved(receiver, fallback) {
|
|
|
290
290
|
return result;
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
+
// src/internal/resolver/fold-self-ref.ts
|
|
294
|
+
function substFullKey(s) {
|
|
295
|
+
return stringSegmentsToKey(s.segments.map((seg) => seg.text));
|
|
296
|
+
}
|
|
297
|
+
function stringSegmentsToKey(segments) {
|
|
298
|
+
return segments.map((t) => {
|
|
299
|
+
if (t === "" || /[^a-zA-Z0-9\-_]/.test(t)) {
|
|
300
|
+
return `"${t.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
301
|
+
}
|
|
302
|
+
return t;
|
|
303
|
+
}).join(".");
|
|
304
|
+
}
|
|
305
|
+
function containsSelfRef(v, fullKey) {
|
|
306
|
+
if (isSubst(v)) return substFullKey(v) === fullKey;
|
|
307
|
+
if (isConcat(v)) return v.nodes.some((n) => containsSelfRef(n, fullKey));
|
|
308
|
+
if (isAppend(v)) {
|
|
309
|
+
return containsSelfRef(v.existing, fullKey) || containsSelfRef(v.elem, fullKey);
|
|
310
|
+
}
|
|
311
|
+
if (isResObj(v)) {
|
|
312
|
+
for (const f of v.fields.values()) {
|
|
313
|
+
if (containsSelfRef(f, fullKey)) return true;
|
|
314
|
+
}
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
const hv = v;
|
|
318
|
+
if (hv.kind === "array") {
|
|
319
|
+
return hv.items.some((item) => containsSelfRef(item, fullKey));
|
|
320
|
+
}
|
|
321
|
+
if (hv.kind === "object") {
|
|
322
|
+
for (const f of hv.fields.values()) {
|
|
323
|
+
if (containsSelfRef(f, fullKey)) return true;
|
|
324
|
+
}
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
function foldSelfRef(v, fullKey, replacement) {
|
|
330
|
+
if (isSubst(v)) {
|
|
331
|
+
return substFullKey(v) === fullKey ? replacement : v;
|
|
332
|
+
}
|
|
333
|
+
if (isConcat(v)) {
|
|
334
|
+
return {
|
|
335
|
+
_kind: "concat-placeholder",
|
|
336
|
+
nodes: v.nodes.map((n) => foldSelfRef(n, fullKey, replacement)),
|
|
337
|
+
line: v.line,
|
|
338
|
+
col: v.col
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
if (isAppend(v)) {
|
|
342
|
+
return {
|
|
343
|
+
_kind: "append-placeholder",
|
|
344
|
+
existing: foldSelfRef(v.existing, fullKey, replacement),
|
|
345
|
+
elem: foldSelfRef(v.elem, fullKey, replacement)
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
if (isResObj(v)) {
|
|
349
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
350
|
+
for (const [k, val] of v.fields) {
|
|
351
|
+
newFields.set(k, foldSelfRef(val, fullKey, replacement));
|
|
352
|
+
}
|
|
353
|
+
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues) };
|
|
354
|
+
}
|
|
355
|
+
const hv = v;
|
|
356
|
+
if (hv.kind === "array") {
|
|
357
|
+
return {
|
|
358
|
+
kind: "array",
|
|
359
|
+
items: hv.items.map((item) => foldSelfRef(item, fullKey, replacement))
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
if (hv.kind === "object") {
|
|
363
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
364
|
+
for (const [k, val] of hv.fields) {
|
|
365
|
+
newFields.set(k, foldSelfRef(val, fullKey, replacement));
|
|
366
|
+
}
|
|
367
|
+
return { kind: "object", fields: newFields };
|
|
368
|
+
}
|
|
369
|
+
return v;
|
|
370
|
+
}
|
|
371
|
+
function foldOrSkipPrior(prior, fullKey, old) {
|
|
372
|
+
if (!containsSelfRef(prior, fullKey)) return cloneResolverValue(prior);
|
|
373
|
+
if (old === void 0) return void 0;
|
|
374
|
+
return foldSelfRef(prior, fullKey, old);
|
|
375
|
+
}
|
|
376
|
+
function cloneResolverValue(v) {
|
|
377
|
+
if (isSubst(v)) {
|
|
378
|
+
return {
|
|
379
|
+
_kind: "subst-placeholder",
|
|
380
|
+
segments: v.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
|
|
381
|
+
optional: v.optional,
|
|
382
|
+
listSuffix: v.listSuffix,
|
|
383
|
+
line: v.line,
|
|
384
|
+
col: v.col,
|
|
385
|
+
prefixLen: v.prefixLen
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
if (isConcat(v)) {
|
|
389
|
+
return {
|
|
390
|
+
_kind: "concat-placeholder",
|
|
391
|
+
nodes: v.nodes.map((n) => cloneResolverValue(n)),
|
|
392
|
+
line: v.line,
|
|
393
|
+
col: v.col
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
if (isResObj(v)) {
|
|
397
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
398
|
+
for (const [k, val] of v.fields) newFields.set(k, cloneResolverValue(val));
|
|
399
|
+
const newPriors = /* @__PURE__ */ new Map();
|
|
400
|
+
for (const [k, val] of v.priorValues) newPriors.set(k, cloneResolverValue(val));
|
|
401
|
+
return { _kind: "res-obj", fields: newFields, priorValues: newPriors };
|
|
402
|
+
}
|
|
403
|
+
if (isAppend(v)) {
|
|
404
|
+
return {
|
|
405
|
+
_kind: "append-placeholder",
|
|
406
|
+
existing: cloneResolverValue(v.existing),
|
|
407
|
+
elem: cloneResolverValue(v.elem)
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
const hv = v;
|
|
411
|
+
if (hv.kind === "array") {
|
|
412
|
+
return {
|
|
413
|
+
kind: "array",
|
|
414
|
+
items: hv.items.map((item) => cloneResolverValue(item))
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
if (hv.kind === "object") {
|
|
418
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
419
|
+
for (const [k, val] of hv.fields) {
|
|
420
|
+
newFields.set(k, cloneResolverValue(val));
|
|
421
|
+
}
|
|
422
|
+
return { kind: "object", fields: newFields };
|
|
423
|
+
}
|
|
424
|
+
return hv;
|
|
425
|
+
}
|
|
426
|
+
function foldNestedSelfRefs(v, pathPrefix) {
|
|
427
|
+
if (!isResObj(v)) return v;
|
|
428
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
429
|
+
for (const [k, fieldVal] of v.fields) {
|
|
430
|
+
const childPath = [...pathPrefix, k];
|
|
431
|
+
const fullKey = stringSegmentsToKey(childPath);
|
|
432
|
+
const folded = foldNestedSelfRefs(fieldVal, childPath);
|
|
433
|
+
let finalVal = folded;
|
|
434
|
+
if (containsSelfRef(folded, fullKey)) {
|
|
435
|
+
const leafPrior = v.priorValues.get(k);
|
|
436
|
+
if (leafPrior !== void 0) {
|
|
437
|
+
const leafPriorFolded = foldNestedSelfRefs(leafPrior, childPath);
|
|
438
|
+
finalVal = foldSelfRef(folded, fullKey, leafPriorFolded);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
newFields.set(k, finalVal);
|
|
442
|
+
}
|
|
443
|
+
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues) };
|
|
444
|
+
}
|
|
445
|
+
function containsSubstByPath(v, target) {
|
|
446
|
+
if (isSubst(v)) return segmentsTextEqual(v.segments, target);
|
|
447
|
+
if (isConcat(v)) return v.nodes.some((n) => containsSubstByPath(n, target));
|
|
448
|
+
if (isAppend(v)) {
|
|
449
|
+
return containsSubstByPath(v.existing, target) || containsSubstByPath(v.elem, target);
|
|
450
|
+
}
|
|
451
|
+
if (isResObj(v)) {
|
|
452
|
+
for (const f of v.fields.values()) {
|
|
453
|
+
if (containsSubstByPath(f, target)) return true;
|
|
454
|
+
}
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
const hv = v;
|
|
458
|
+
if (hv.kind === "array") {
|
|
459
|
+
return hv.items.some((item) => containsSubstByPath(item, target));
|
|
460
|
+
}
|
|
461
|
+
if (hv.kind === "object") {
|
|
462
|
+
for (const f of hv.fields.values()) {
|
|
463
|
+
if (containsSubstByPath(f, target)) return true;
|
|
464
|
+
}
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
return false;
|
|
468
|
+
}
|
|
469
|
+
function segmentsTextEqual(a, b) {
|
|
470
|
+
if (a.length !== b.length) return false;
|
|
471
|
+
for (let i = 0; i < a.length; i++) {
|
|
472
|
+
const ai = a[i];
|
|
473
|
+
const bi = b[i];
|
|
474
|
+
if (ai === void 0 || bi === void 0 || ai.text !== bi.text) return false;
|
|
475
|
+
}
|
|
476
|
+
return true;
|
|
477
|
+
}
|
|
478
|
+
|
|
293
479
|
// src/internal/resolver/utils.ts
|
|
294
480
|
function segmentsToKey(segments) {
|
|
295
481
|
return segments.map((s) => {
|
|
@@ -331,13 +517,22 @@ function deepMergeHoconValues(base, overlay) {
|
|
|
331
517
|
}
|
|
332
518
|
return { kind: "object", fields: merged };
|
|
333
519
|
}
|
|
334
|
-
function deepMergeResObjInto(dst, src) {
|
|
520
|
+
function deepMergeResObjInto(dst, src, pathPrefix = []) {
|
|
335
521
|
for (const [k, srcVal] of src.fields) {
|
|
522
|
+
const childPrefix = [...pathPrefix, k];
|
|
523
|
+
const fullKey = stringSegmentsToKey(childPrefix);
|
|
336
524
|
const dstVal = dst.fields.get(k);
|
|
337
525
|
if (dstVal !== void 0 && isResObj(dstVal) && isResObj(srcVal)) {
|
|
338
|
-
|
|
526
|
+
const priorExisting = dst.priorValues.get(k);
|
|
527
|
+
const prior = foldOrSkipPrior(dstVal, fullKey, priorExisting);
|
|
528
|
+
if (prior !== void 0) dst.priorValues.set(k, prior);
|
|
529
|
+
deepMergeResObjInto(dstVal, srcVal, childPrefix);
|
|
339
530
|
} else {
|
|
340
|
-
if (dstVal !== void 0)
|
|
531
|
+
if (dstVal !== void 0) {
|
|
532
|
+
const priorExisting = dst.priorValues.get(k);
|
|
533
|
+
const prior = foldOrSkipPrior(dstVal, fullKey, priorExisting);
|
|
534
|
+
if (prior !== void 0) dst.priorValues.set(k, prior);
|
|
535
|
+
}
|
|
341
536
|
dst.fields.set(k, srcVal);
|
|
342
537
|
}
|
|
343
538
|
}
|
|
@@ -1347,7 +1542,7 @@ var IncludeLoader = class {
|
|
|
1347
1542
|
for (const ext of probeExts) {
|
|
1348
1543
|
const obj = this.loadSingle(`${absPath}${ext}`);
|
|
1349
1544
|
if (obj !== void 0) {
|
|
1350
|
-
deepMergeResObjInto(merged, obj);
|
|
1545
|
+
deepMergeResObjInto(merged, obj, []);
|
|
1351
1546
|
foundAny = true;
|
|
1352
1547
|
}
|
|
1353
1548
|
}
|
|
@@ -1380,7 +1575,7 @@ var IncludeLoader = class {
|
|
|
1380
1575
|
for (const ext of probeExts) {
|
|
1381
1576
|
const obj = await this.loadSingleAsync(`${absPath}${ext}`);
|
|
1382
1577
|
if (obj !== void 0) {
|
|
1383
|
-
deepMergeResObjInto(merged, obj);
|
|
1578
|
+
deepMergeResObjInto(merged, obj, []);
|
|
1384
1579
|
foundAny = true;
|
|
1385
1580
|
}
|
|
1386
1581
|
}
|
|
@@ -1552,7 +1747,7 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1552
1747
|
if (pathPrefix.length > 0) {
|
|
1553
1748
|
this.relativizeResObj(included, pathPrefix);
|
|
1554
1749
|
}
|
|
1555
|
-
deepMergeResObjInto(obj, included);
|
|
1750
|
+
deepMergeResObjInto(obj, included, pathPrefix);
|
|
1556
1751
|
return;
|
|
1557
1752
|
}
|
|
1558
1753
|
const [head, ...tail] = field.key;
|
|
@@ -1567,12 +1762,27 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1567
1762
|
return;
|
|
1568
1763
|
}
|
|
1569
1764
|
const childPrefix = [...pathPrefix, head];
|
|
1765
|
+
const fullKey = stringSegmentsToKey(childPrefix);
|
|
1570
1766
|
if (field.append) {
|
|
1571
1767
|
const existing2 = obj.fields.get(head) ?? { kind: "array", items: [] };
|
|
1572
|
-
obj.priorValues.
|
|
1768
|
+
const oldPrior = obj.priorValues.get(head);
|
|
1769
|
+
const folded = foldOrSkipPrior(existing2, fullKey, oldPrior);
|
|
1770
|
+
if (folded !== void 0) obj.priorValues.set(head, folded);
|
|
1573
1771
|
obj.fields.set(head, {
|
|
1574
1772
|
_kind: "append-placeholder",
|
|
1575
|
-
existing
|
|
1773
|
+
// Use the folded existing (self-ref-free) for the Append. When the
|
|
1774
|
+
// fold returned undefined (self-ref present but no old prior),
|
|
1775
|
+
// fall back to the original existing — resolveSubst will then
|
|
1776
|
+
// raise the "self-ref with no prior value" error at resolve time,
|
|
1777
|
+
// matching the pre-fix behaviour for that edge case.
|
|
1778
|
+
//
|
|
1779
|
+
// Clone `folded` again so the Append.existing and priorValues[head]
|
|
1780
|
+
// do not share the same Subst/Concat references — relativizeResObj
|
|
1781
|
+
// walks BOTH `fields` and `priorValues` and mutates Subst.segments
|
|
1782
|
+
// in place, so a shared reference would get its prefix applied
|
|
1783
|
+
// twice (resulting in e.g. `${outer.outer.base}` instead of
|
|
1784
|
+
// `${outer.base}`). Codex review on PR #131.
|
|
1785
|
+
existing: folded !== void 0 ? cloneResolverValue(folded) : existing2,
|
|
1576
1786
|
elem: this.astToResolverValue(field.value, childPrefix)
|
|
1577
1787
|
});
|
|
1578
1788
|
return;
|
|
@@ -1580,10 +1790,13 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1580
1790
|
const existing = obj.fields.get(head);
|
|
1581
1791
|
const newVal = this.astToResolverValue(field.value, childPrefix);
|
|
1582
1792
|
if (existing !== void 0) {
|
|
1583
|
-
|
|
1793
|
+
const exFolded = foldNestedSelfRefs(existing, childPrefix);
|
|
1794
|
+
const oldPrior = obj.priorValues.get(head);
|
|
1795
|
+
const prior = foldOrSkipPrior(exFolded, fullKey, oldPrior);
|
|
1796
|
+
if (prior !== void 0) obj.priorValues.set(head, prior);
|
|
1584
1797
|
}
|
|
1585
1798
|
if (existing !== void 0 && isResObj(existing) && isResObj(newVal)) {
|
|
1586
|
-
deepMergeResObjInto(existing, newVal);
|
|
1799
|
+
deepMergeResObjInto(existing, newVal, childPrefix);
|
|
1587
1800
|
return;
|
|
1588
1801
|
}
|
|
1589
1802
|
obj.fields.set(head, newVal);
|
|
@@ -1600,7 +1813,7 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1600
1813
|
if (pathPrefix.length > 0) {
|
|
1601
1814
|
this.relativizeResObj(included, pathPrefix);
|
|
1602
1815
|
}
|
|
1603
|
-
deepMergeResObjInto(obj, included);
|
|
1816
|
+
deepMergeResObjInto(obj, included, pathPrefix);
|
|
1604
1817
|
return;
|
|
1605
1818
|
}
|
|
1606
1819
|
const [head, ...tail] = field.key;
|
|
@@ -1615,12 +1828,15 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1615
1828
|
return;
|
|
1616
1829
|
}
|
|
1617
1830
|
const childPrefix = [...pathPrefix, head];
|
|
1831
|
+
const fullKey = stringSegmentsToKey(childPrefix);
|
|
1618
1832
|
if (field.append) {
|
|
1619
1833
|
const existing2 = obj.fields.get(head) ?? { kind: "array", items: [] };
|
|
1620
|
-
obj.priorValues.
|
|
1834
|
+
const oldPrior = obj.priorValues.get(head);
|
|
1835
|
+
const folded = foldOrSkipPrior(existing2, fullKey, oldPrior);
|
|
1836
|
+
if (folded !== void 0) obj.priorValues.set(head, folded);
|
|
1621
1837
|
obj.fields.set(head, {
|
|
1622
1838
|
_kind: "append-placeholder",
|
|
1623
|
-
existing: existing2,
|
|
1839
|
+
existing: folded !== void 0 ? cloneResolverValue(folded) : existing2,
|
|
1624
1840
|
elem: await this.astToResolverValueAsync(field.value, childPrefix)
|
|
1625
1841
|
});
|
|
1626
1842
|
return;
|
|
@@ -1628,10 +1844,13 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1628
1844
|
const existing = obj.fields.get(head);
|
|
1629
1845
|
const newVal = await this.astToResolverValueAsync(field.value, childPrefix);
|
|
1630
1846
|
if (existing !== void 0) {
|
|
1631
|
-
|
|
1847
|
+
const exFolded = foldNestedSelfRefs(existing, childPrefix);
|
|
1848
|
+
const oldPrior = obj.priorValues.get(head);
|
|
1849
|
+
const prior = foldOrSkipPrior(exFolded, fullKey, oldPrior);
|
|
1850
|
+
if (prior !== void 0) obj.priorValues.set(head, prior);
|
|
1632
1851
|
}
|
|
1633
1852
|
if (existing !== void 0 && isResObj(existing) && isResObj(newVal)) {
|
|
1634
|
-
deepMergeResObjInto(existing, newVal);
|
|
1853
|
+
deepMergeResObjInto(existing, newVal, childPrefix);
|
|
1635
1854
|
return;
|
|
1636
1855
|
}
|
|
1637
1856
|
obj.fields.set(head, newVal);
|
|
@@ -1763,6 +1982,23 @@ var SubstitutionResolver = class {
|
|
|
1763
1982
|
// narrower than path-equality. Spec amendment deferred to a follow-up
|
|
1764
1983
|
// xx.hocon PR (see Phase 6 #3f close-out notes).
|
|
1765
1984
|
this.resolvingConcats = /* @__PURE__ */ new WeakSet();
|
|
1985
|
+
// Path stack tracking the full dotted path of the field currently being
|
|
1986
|
+
// assigned in `resolveResObj`. Leaf keys are pushed on entry to each
|
|
1987
|
+
// `(key, val)` iteration and popped on exit, so nested objects build up
|
|
1988
|
+
// the full path (e.g. `["o", "history"]` while resolving `o.history`).
|
|
1989
|
+
//
|
|
1990
|
+
// Used to tighten self-ref detection at the L192 found-lookup site:
|
|
1991
|
+
// a substitution `${X}` whose looked-up value contains a Subst pointing
|
|
1992
|
+
// at `X` is only a true self-reference when the field currently being
|
|
1993
|
+
// assigned is `X` (or a descendant of `X`). Without this guard, an
|
|
1994
|
+
// external lookup like `b = ${o}` (where o has a self-referential
|
|
1995
|
+
// field) would mis-fire and short-circuit to o's prior, returning the
|
|
1996
|
+
// wrong value for b. The is_owner gate (rfp prefix-matches s.segments)
|
|
1997
|
+
// narrows the check to the owner case only.
|
|
1998
|
+
//
|
|
1999
|
+
// Cross-impl with rs.hocon v1.5.1's resolving_field_path (same purpose,
|
|
2000
|
+
// same prefix-match semantics).
|
|
2001
|
+
this.resolvingFieldPath = [];
|
|
1766
2002
|
}
|
|
1767
2003
|
/** Returns a prefix for error messages, including origin info when set. */
|
|
1768
2004
|
originPrefix() {
|
|
@@ -1774,7 +2010,13 @@ var SubstitutionResolver = class {
|
|
|
1774
2010
|
resolveResObj(obj) {
|
|
1775
2011
|
const result = /* @__PURE__ */ new Map();
|
|
1776
2012
|
for (const [key, val] of obj.fields) {
|
|
1777
|
-
|
|
2013
|
+
this.resolvingFieldPath.push(key);
|
|
2014
|
+
let resolved;
|
|
2015
|
+
try {
|
|
2016
|
+
resolved = this.resolveVal(val, obj);
|
|
2017
|
+
} finally {
|
|
2018
|
+
this.resolvingFieldPath.pop();
|
|
2019
|
+
}
|
|
1778
2020
|
if (resolved !== void 0) {
|
|
1779
2021
|
if (resolved.kind === "object") {
|
|
1780
2022
|
const prior = obj.priorValues.get(key);
|
|
@@ -1864,7 +2106,10 @@ var SubstitutionResolver = class {
|
|
|
1864
2106
|
try {
|
|
1865
2107
|
const found = lookupPath(this.root, s.segments);
|
|
1866
2108
|
if (found !== void 0) {
|
|
1867
|
-
|
|
2109
|
+
const rfp = this.resolvingFieldPath;
|
|
2110
|
+
const isOwner = rfp.length >= s.segments.length && s.segments.every((seg, i) => rfp[i] === seg.text);
|
|
2111
|
+
const isSelfRef = isConcat(found) && this.resolvingConcats.has(found) || isOwner && containsSubstByPath(found, s.segments);
|
|
2112
|
+
if (isSelfRef) {
|
|
1868
2113
|
let prior;
|
|
1869
2114
|
if (s.segments.length > 1) {
|
|
1870
2115
|
const leafSeg = s.segments[s.segments.length - 1]?.text ?? "";
|