@o3co/ts.hocon 1.5.2 → 1.6.1
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/{config-BwjvKeZ5.d.cts → config-DCSLXkNY.d.cts} +11 -6
- package/dist/{config-BwjvKeZ5.d.ts → config-DCSLXkNY.d.ts} +11 -6
- package/dist/index.cjs +289 -183
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +289 -183
- package/dist/zod.cjs +289 -183
- package/dist/zod.d.cts +1 -1
- package/dist/zod.d.ts +1 -1
- package/dist/zod.js +289 -183
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -289,55 +289,6 @@ var NotResolvedError = class extends ConfigError {
|
|
|
289
289
|
}
|
|
290
290
|
};
|
|
291
291
|
|
|
292
|
-
// src/internal/resolver/types.ts
|
|
293
|
-
var separatorValues = /* @__PURE__ */ new WeakSet();
|
|
294
|
-
function isSubst(v) {
|
|
295
|
-
return v._kind === "subst-placeholder";
|
|
296
|
-
}
|
|
297
|
-
function isConcat(v) {
|
|
298
|
-
return v._kind === "concat-placeholder";
|
|
299
|
-
}
|
|
300
|
-
function isAppend(v) {
|
|
301
|
-
return v._kind === "append-placeholder";
|
|
302
|
-
}
|
|
303
|
-
function isResObj(v) {
|
|
304
|
-
return v._kind === "res-obj";
|
|
305
|
-
}
|
|
306
|
-
function makeResObj() {
|
|
307
|
-
return { _kind: "res-obj", fields: /* @__PURE__ */ new Map(), priorValues: /* @__PURE__ */ new Map() };
|
|
308
|
-
}
|
|
309
|
-
function mergeUnresolved(receiver, fallback) {
|
|
310
|
-
const result = makeResObj();
|
|
311
|
-
for (const [k, v] of fallback.fields) {
|
|
312
|
-
result.fields.set(k, v);
|
|
313
|
-
}
|
|
314
|
-
for (const [k, v] of fallback.priorValues) {
|
|
315
|
-
result.priorValues.set(k, v);
|
|
316
|
-
}
|
|
317
|
-
for (const [k, rv] of receiver.fields) {
|
|
318
|
-
const existing = result.fields.get(k);
|
|
319
|
-
if (existing !== void 0) {
|
|
320
|
-
const recPrior = receiver.priorValues.get(k);
|
|
321
|
-
if (recPrior !== void 0 && !isResObj(recPrior)) {
|
|
322
|
-
result.fields.set(k, rv);
|
|
323
|
-
continue;
|
|
324
|
-
}
|
|
325
|
-
if (isResObj(rv) && isResObj(existing)) {
|
|
326
|
-
result.fields.set(k, mergeUnresolved(rv, existing));
|
|
327
|
-
continue;
|
|
328
|
-
}
|
|
329
|
-
result.priorValues.set(k, existing);
|
|
330
|
-
}
|
|
331
|
-
result.fields.set(k, rv);
|
|
332
|
-
}
|
|
333
|
-
for (const [k, v] of receiver.priorValues) {
|
|
334
|
-
if (receiver.fields.has(k)) {
|
|
335
|
-
result.priorValues.set(k, v);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
return result;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
292
|
// src/internal/resolver/fold-self-ref.ts
|
|
342
293
|
function substFullKey(s) {
|
|
343
294
|
return stringSegmentsToKey(s.segments.map((seg) => seg.text));
|
|
@@ -351,11 +302,8 @@ function stringSegmentsToKey(segments) {
|
|
|
351
302
|
}).join(".");
|
|
352
303
|
}
|
|
353
304
|
function containsSelfRef(v, fullKey) {
|
|
354
|
-
if (isSubst(v)) return substFullKey(v) === fullKey;
|
|
305
|
+
if (isSubst(v)) return !v.knownAbsent && substFullKey(v) === fullKey;
|
|
355
306
|
if (isConcat(v)) return v.nodes.some((n) => containsSelfRef(n, fullKey));
|
|
356
|
-
if (isAppend(v)) {
|
|
357
|
-
return containsSelfRef(v.existing, fullKey) || containsSelfRef(v.elem, fullKey);
|
|
358
|
-
}
|
|
359
307
|
if (isResObj(v)) {
|
|
360
308
|
for (const f of v.fields.values()) {
|
|
361
309
|
if (containsSelfRef(f, fullKey)) return true;
|
|
@@ -386,19 +334,12 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
386
334
|
col: v.col
|
|
387
335
|
};
|
|
388
336
|
}
|
|
389
|
-
if (isAppend(v)) {
|
|
390
|
-
return {
|
|
391
|
-
_kind: "append-placeholder",
|
|
392
|
-
existing: foldSelfRef(v.existing, fullKey, replacement),
|
|
393
|
-
elem: foldSelfRef(v.elem, fullKey, replacement)
|
|
394
|
-
};
|
|
395
|
-
}
|
|
396
337
|
if (isResObj(v)) {
|
|
397
338
|
const newFields = /* @__PURE__ */ new Map();
|
|
398
339
|
for (const [k, val] of v.fields) {
|
|
399
340
|
newFields.set(k, foldSelfRef(val, fullKey, replacement));
|
|
400
341
|
}
|
|
401
|
-
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues) };
|
|
342
|
+
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
402
343
|
}
|
|
403
344
|
const hv = v;
|
|
404
345
|
if (hv.kind === "array") {
|
|
@@ -416,17 +357,106 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
416
357
|
}
|
|
417
358
|
return v;
|
|
418
359
|
}
|
|
360
|
+
function foldKnownAbsentSelfRef(v, fullKey, replacement) {
|
|
361
|
+
if (isSubst(v)) {
|
|
362
|
+
return v.knownAbsent && substFullKey(v) === fullKey ? replacement : v;
|
|
363
|
+
}
|
|
364
|
+
if (isConcat(v)) {
|
|
365
|
+
return {
|
|
366
|
+
_kind: "concat-placeholder",
|
|
367
|
+
nodes: v.nodes.map((n) => foldKnownAbsentSelfRef(n, fullKey, replacement)),
|
|
368
|
+
line: v.line,
|
|
369
|
+
col: v.col
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
if (isResObj(v)) {
|
|
373
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
374
|
+
for (const [k, val] of v.fields) {
|
|
375
|
+
newFields.set(k, foldKnownAbsentSelfRef(val, fullKey, replacement));
|
|
376
|
+
}
|
|
377
|
+
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
378
|
+
}
|
|
379
|
+
const hv = v;
|
|
380
|
+
if (hv.kind === "array") {
|
|
381
|
+
return {
|
|
382
|
+
kind: "array",
|
|
383
|
+
items: hv.items.map((item) => foldKnownAbsentSelfRef(item, fullKey, replacement))
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
if (hv.kind === "object") {
|
|
387
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
388
|
+
for (const [k, val] of hv.fields) {
|
|
389
|
+
newFields.set(k, foldKnownAbsentSelfRef(val, fullKey, replacement));
|
|
390
|
+
}
|
|
391
|
+
return { kind: "object", fields: newFields };
|
|
392
|
+
}
|
|
393
|
+
return v;
|
|
394
|
+
}
|
|
419
395
|
function foldOrSkipPrior(prior, fullKey, old) {
|
|
420
396
|
if (!containsSelfRef(prior, fullKey)) return cloneResolverValue(prior);
|
|
421
|
-
if (old === void 0) return
|
|
397
|
+
if (old === void 0) return foldOptionalSelfRefAbsent(prior, fullKey);
|
|
422
398
|
return foldSelfRef(prior, fullKey, old);
|
|
423
399
|
}
|
|
400
|
+
function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
401
|
+
if (isSubst(v) && substFullKey(v) === fullKey) {
|
|
402
|
+
if (!v.optional) return void 0;
|
|
403
|
+
return {
|
|
404
|
+
_kind: "subst-placeholder",
|
|
405
|
+
segments: v.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
|
|
406
|
+
optional: v.optional,
|
|
407
|
+
knownAbsent: true,
|
|
408
|
+
listSuffix: v.listSuffix,
|
|
409
|
+
line: v.line,
|
|
410
|
+
col: v.col,
|
|
411
|
+
prefixLen: v.prefixLen
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
if (isConcat(v)) {
|
|
415
|
+
const nodes = [];
|
|
416
|
+
for (const node of v.nodes) {
|
|
417
|
+
const folded = foldOptionalSelfRefAbsent(node, fullKey);
|
|
418
|
+
if (folded === void 0) return void 0;
|
|
419
|
+
nodes.push(folded);
|
|
420
|
+
}
|
|
421
|
+
return { _kind: "concat-placeholder", nodes, line: v.line, col: v.col };
|
|
422
|
+
}
|
|
423
|
+
if (isResObj(v)) {
|
|
424
|
+
const fields = /* @__PURE__ */ new Map();
|
|
425
|
+
for (const [key, value] of v.fields) {
|
|
426
|
+
const folded = foldOptionalSelfRefAbsent(value, fullKey);
|
|
427
|
+
if (folded === void 0) return void 0;
|
|
428
|
+
fields.set(key, folded);
|
|
429
|
+
}
|
|
430
|
+
return { _kind: "res-obj", fields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
431
|
+
}
|
|
432
|
+
const hv = v;
|
|
433
|
+
if (hv.kind === "array") {
|
|
434
|
+
const items = [];
|
|
435
|
+
for (const item of hv.items) {
|
|
436
|
+
const folded = foldOptionalSelfRefAbsent(item, fullKey);
|
|
437
|
+
if (folded === void 0) return void 0;
|
|
438
|
+
items.push(folded);
|
|
439
|
+
}
|
|
440
|
+
return { kind: "array", items };
|
|
441
|
+
}
|
|
442
|
+
if (hv.kind === "object") {
|
|
443
|
+
const fields = /* @__PURE__ */ new Map();
|
|
444
|
+
for (const [key, value] of hv.fields) {
|
|
445
|
+
const folded = foldOptionalSelfRefAbsent(value, fullKey);
|
|
446
|
+
if (folded === void 0) return void 0;
|
|
447
|
+
fields.set(key, folded);
|
|
448
|
+
}
|
|
449
|
+
return { kind: "object", fields };
|
|
450
|
+
}
|
|
451
|
+
return cloneResolverValue(v);
|
|
452
|
+
}
|
|
424
453
|
function cloneResolverValue(v) {
|
|
425
454
|
if (isSubst(v)) {
|
|
426
455
|
return {
|
|
427
456
|
_kind: "subst-placeholder",
|
|
428
457
|
segments: v.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
|
|
429
458
|
optional: v.optional,
|
|
459
|
+
knownAbsent: v.knownAbsent,
|
|
430
460
|
listSuffix: v.listSuffix,
|
|
431
461
|
line: v.line,
|
|
432
462
|
col: v.col,
|
|
@@ -446,14 +476,7 @@ function cloneResolverValue(v) {
|
|
|
446
476
|
for (const [k, val] of v.fields) newFields.set(k, cloneResolverValue(val));
|
|
447
477
|
const newPriors = /* @__PURE__ */ new Map();
|
|
448
478
|
for (const [k, val] of v.priorValues) newPriors.set(k, cloneResolverValue(val));
|
|
449
|
-
return { _kind: "res-obj", fields: newFields, priorValues: newPriors };
|
|
450
|
-
}
|
|
451
|
-
if (isAppend(v)) {
|
|
452
|
-
return {
|
|
453
|
-
_kind: "append-placeholder",
|
|
454
|
-
existing: cloneResolverValue(v.existing),
|
|
455
|
-
elem: cloneResolverValue(v.elem)
|
|
456
|
-
};
|
|
479
|
+
return { _kind: "res-obj", fields: newFields, priorValues: newPriors, resetKeys: new Set(v.resetKeys) };
|
|
457
480
|
}
|
|
458
481
|
const hv = v;
|
|
459
482
|
if (hv.kind === "array") {
|
|
@@ -488,14 +511,11 @@ function foldNestedSelfRefs(v, pathPrefix) {
|
|
|
488
511
|
}
|
|
489
512
|
newFields.set(k, finalVal);
|
|
490
513
|
}
|
|
491
|
-
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues) };
|
|
514
|
+
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
492
515
|
}
|
|
493
516
|
function containsSubstByPath(v, target) {
|
|
494
|
-
if (isSubst(v)) return segmentsTextEqual(v.segments, target);
|
|
517
|
+
if (isSubst(v)) return !v.knownAbsent && segmentsTextEqual(v.segments, target);
|
|
495
518
|
if (isConcat(v)) return v.nodes.some((n) => containsSubstByPath(n, target));
|
|
496
|
-
if (isAppend(v)) {
|
|
497
|
-
return containsSubstByPath(v.existing, target) || containsSubstByPath(v.elem, target);
|
|
498
|
-
}
|
|
499
519
|
if (isResObj(v)) {
|
|
500
520
|
for (const f of v.fields.values()) {
|
|
501
521
|
if (containsSubstByPath(f, target)) return true;
|
|
@@ -524,6 +544,53 @@ function segmentsTextEqual(a, b) {
|
|
|
524
544
|
return true;
|
|
525
545
|
}
|
|
526
546
|
|
|
547
|
+
// src/internal/resolver/types.ts
|
|
548
|
+
var separatorValues = /* @__PURE__ */ new WeakSet();
|
|
549
|
+
function isSubst(v) {
|
|
550
|
+
return v._kind === "subst-placeholder";
|
|
551
|
+
}
|
|
552
|
+
function isConcat(v) {
|
|
553
|
+
return v._kind === "concat-placeholder";
|
|
554
|
+
}
|
|
555
|
+
function isResObj(v) {
|
|
556
|
+
return v._kind === "res-obj";
|
|
557
|
+
}
|
|
558
|
+
function makeResObj() {
|
|
559
|
+
return { _kind: "res-obj", fields: /* @__PURE__ */ new Map(), priorValues: /* @__PURE__ */ new Map(), resetKeys: /* @__PURE__ */ new Set() };
|
|
560
|
+
}
|
|
561
|
+
function mergeUnresolved(receiver, fallback) {
|
|
562
|
+
const result = makeResObj();
|
|
563
|
+
for (const [k, v] of fallback.fields) {
|
|
564
|
+
result.fields.set(k, v);
|
|
565
|
+
}
|
|
566
|
+
for (const [k, v] of fallback.priorValues) {
|
|
567
|
+
result.priorValues.set(k, v);
|
|
568
|
+
}
|
|
569
|
+
for (const [k, rv] of receiver.fields) {
|
|
570
|
+
const existing = result.fields.get(k);
|
|
571
|
+
if (existing !== void 0) {
|
|
572
|
+
const recPrior = receiver.priorValues.get(k);
|
|
573
|
+
if (recPrior !== void 0 && !isResObj(recPrior)) {
|
|
574
|
+
result.fields.set(k, rv);
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
if (isResObj(rv) && isResObj(existing)) {
|
|
578
|
+
result.fields.set(k, mergeUnresolved(rv, existing));
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
const foldedPrior = foldOrSkipPrior(existing, k, void 0);
|
|
582
|
+
if (foldedPrior !== void 0) result.priorValues.set(k, foldedPrior);
|
|
583
|
+
}
|
|
584
|
+
result.fields.set(k, rv);
|
|
585
|
+
}
|
|
586
|
+
for (const [k, v] of receiver.priorValues) {
|
|
587
|
+
if (receiver.fields.has(k)) {
|
|
588
|
+
result.priorValues.set(k, v);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return result;
|
|
592
|
+
}
|
|
593
|
+
|
|
527
594
|
// src/internal/resolver/utils.ts
|
|
528
595
|
function segmentsToKey(segments) {
|
|
529
596
|
return segments.map((s) => {
|
|
@@ -577,9 +644,19 @@ function deepMergeResObjInto(dst, src, pathPrefix = []) {
|
|
|
577
644
|
deepMergeResObjInto(dstVal, srcVal, childPrefix);
|
|
578
645
|
} else {
|
|
579
646
|
if (dstVal !== void 0) {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
647
|
+
if (src.resetKeys.has(k)) {
|
|
648
|
+
dst.priorValues.delete(k);
|
|
649
|
+
} else {
|
|
650
|
+
const dstFolded = foldOrSkipPrior(dstVal, fullKey, dst.priorValues.get(k));
|
|
651
|
+
if (dstFolded !== void 0) {
|
|
652
|
+
const srcPrior = src.priorValues.get(k);
|
|
653
|
+
if (srcPrior !== void 0) {
|
|
654
|
+
dst.priorValues.set(k, foldKnownAbsentSelfRef(srcPrior, fullKey, dstFolded));
|
|
655
|
+
} else {
|
|
656
|
+
dst.priorValues.set(k, dstFolded);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
583
660
|
}
|
|
584
661
|
dst.fields.set(k, srcVal);
|
|
585
662
|
}
|
|
@@ -589,6 +666,7 @@ function deepMergeResObjInto(dst, src, pathPrefix = []) {
|
|
|
589
666
|
dst.priorValues.set(k, srcPrior);
|
|
590
667
|
}
|
|
591
668
|
}
|
|
669
|
+
for (const k of src.resetKeys) dst.resetKeys.add(k);
|
|
592
670
|
}
|
|
593
671
|
function hoconValueToResObj(hv) {
|
|
594
672
|
const obj = makeResObj();
|
|
@@ -658,6 +736,11 @@ var Lexer = class {
|
|
|
658
736
|
this.line = 1;
|
|
659
737
|
this.col = 1;
|
|
660
738
|
this.hadSpace = false;
|
|
739
|
+
// Accumulates literal whitespace chars consumed between tokens. Reset on every
|
|
740
|
+
// token push. Used so the parser can preserve path-expression whitespace
|
|
741
|
+
// (xx.hocon#42, E13) — e.g. tab vs space adjacent to dots in key paths.
|
|
742
|
+
// Comment text is NOT accumulated; only the actual WS chars.
|
|
743
|
+
this.whitespaceBuffer = "";
|
|
661
744
|
this.tokens = [];
|
|
662
745
|
if (input.charCodeAt(0) === 65279) this.input = input.slice(1);
|
|
663
746
|
}
|
|
@@ -673,6 +756,7 @@ var Lexer = class {
|
|
|
673
756
|
continue;
|
|
674
757
|
}
|
|
675
758
|
if (isHoconWhitespace(ch)) {
|
|
759
|
+
this.whitespaceBuffer += ch;
|
|
676
760
|
this.advance();
|
|
677
761
|
this.hadSpace = true;
|
|
678
762
|
continue;
|
|
@@ -764,7 +848,7 @@ var Lexer = class {
|
|
|
764
848
|
}
|
|
765
849
|
throw new ParseError(`unexpected character: ${JSON.stringify(ch)}`, sl, sc);
|
|
766
850
|
}
|
|
767
|
-
this.tokens.push({ kind: "eof", value: "", line: this.line, col: this.col, isQuoted: false, precedingSpace: false });
|
|
851
|
+
this.tokens.push({ kind: "eof", value: "", line: this.line, col: this.col, isQuoted: false, precedingSpace: false, precedingWhitespace: "" });
|
|
768
852
|
return this.tokens;
|
|
769
853
|
}
|
|
770
854
|
peek(offset = 0) {
|
|
@@ -781,12 +865,14 @@ var Lexer = class {
|
|
|
781
865
|
return ch;
|
|
782
866
|
}
|
|
783
867
|
push(kind, value, l, c, isQuoted = false) {
|
|
784
|
-
this.tokens.push({ kind, value, line: l, col: c, isQuoted, precedingSpace: this.hadSpace });
|
|
868
|
+
this.tokens.push({ kind, value, line: l, col: c, isQuoted, precedingSpace: this.hadSpace, precedingWhitespace: this.whitespaceBuffer });
|
|
785
869
|
this.hadSpace = false;
|
|
870
|
+
this.whitespaceBuffer = "";
|
|
786
871
|
}
|
|
787
872
|
pushSubst(payload, value, l, c) {
|
|
788
|
-
this.tokens.push({ kind: "subst", value, line: l, col: c, isQuoted: false, precedingSpace: this.hadSpace, subst: payload });
|
|
873
|
+
this.tokens.push({ kind: "subst", value, line: l, col: c, isQuoted: false, precedingSpace: this.hadSpace, precedingWhitespace: this.whitespaceBuffer, subst: payload });
|
|
789
874
|
this.hadSpace = false;
|
|
875
|
+
this.whitespaceBuffer = "";
|
|
790
876
|
}
|
|
791
877
|
/**
|
|
792
878
|
* Read body of a quoted string. Opening `"` must already be consumed.
|
|
@@ -1032,7 +1118,7 @@ function isUnquotedContinue(ch, nextFn) {
|
|
|
1032
1118
|
}
|
|
1033
1119
|
|
|
1034
1120
|
// src/internal/parser/parser.ts
|
|
1035
|
-
var EOF_TOKEN = { kind: "eof", value: "", line: 0, col: 0, isQuoted: false, precedingSpace: false, subst: void 0 };
|
|
1121
|
+
var EOF_TOKEN = { kind: "eof", value: "", line: 0, col: 0, isQuoted: false, precedingSpace: false, precedingWhitespace: "", subst: void 0 };
|
|
1036
1122
|
var Parser = class {
|
|
1037
1123
|
constructor(tokens) {
|
|
1038
1124
|
this.tokens = tokens;
|
|
@@ -1145,13 +1231,17 @@ var Parser = class {
|
|
|
1145
1231
|
let trailingDot = false;
|
|
1146
1232
|
let firstWasQuoted = false;
|
|
1147
1233
|
let spaceConcat = false;
|
|
1234
|
+
let postDotPrefix = "";
|
|
1148
1235
|
while (true) {
|
|
1149
1236
|
const t = this.peek();
|
|
1150
1237
|
if (t.kind === "string") {
|
|
1151
1238
|
this.advance();
|
|
1152
1239
|
if (segments.length === 0) firstWasQuoted = true;
|
|
1153
1240
|
if (spaceConcat) {
|
|
1154
|
-
segments[segments.length - 1] = `${segments[segments.length - 1]}
|
|
1241
|
+
segments[segments.length - 1] = `${segments[segments.length - 1]}${t.precedingWhitespace}${t.value}`;
|
|
1242
|
+
} else if (postDotPrefix !== "") {
|
|
1243
|
+
segments.push(`${postDotPrefix}${t.value}`);
|
|
1244
|
+
postDotPrefix = "";
|
|
1155
1245
|
} else {
|
|
1156
1246
|
segments.push(t.value);
|
|
1157
1247
|
}
|
|
@@ -1161,24 +1251,23 @@ var Parser = class {
|
|
|
1161
1251
|
const raw = t.value.startsWith(".") && segments.length > 0 && !t.precedingSpace ? t.value.slice(1) : t.value;
|
|
1162
1252
|
const parts = raw.split(".");
|
|
1163
1253
|
const filtered = parts.filter((s) => s.length > 0);
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
const after = seg.length >= 2 ? JSON.stringify(seg[1]) : "EOF";
|
|
1167
|
-
throw new ParseError(
|
|
1168
|
-
`unquoted key segment cannot begin with '-' unless followed by a digit (got '-' then ${after} in ${JSON.stringify(seg)}, HOCON.md L270-276)`,
|
|
1169
|
-
t.line,
|
|
1170
|
-
t.col
|
|
1171
|
-
);
|
|
1172
|
-
}
|
|
1173
|
-
}
|
|
1174
|
-
if (spaceConcat && filtered.length > 0) {
|
|
1254
|
+
if (spaceConcat) {
|
|
1255
|
+
segments[segments.length - 1] = `${segments[segments.length - 1]}${t.precedingWhitespace}`;
|
|
1175
1256
|
if (raw.startsWith(".")) {
|
|
1176
1257
|
segments.push(...filtered);
|
|
1177
|
-
} else {
|
|
1258
|
+
} else if (filtered.length > 0) {
|
|
1178
1259
|
const [head, ...tail] = filtered;
|
|
1179
|
-
segments[segments.length - 1] = `${segments[segments.length - 1]}
|
|
1260
|
+
segments[segments.length - 1] = `${segments[segments.length - 1]}${head}`;
|
|
1180
1261
|
segments.push(...tail);
|
|
1181
1262
|
}
|
|
1263
|
+
} else if (postDotPrefix !== "" && raw.startsWith(".")) {
|
|
1264
|
+
segments.push(postDotPrefix);
|
|
1265
|
+
postDotPrefix = "";
|
|
1266
|
+
segments.push(...filtered);
|
|
1267
|
+
} else if (postDotPrefix !== "" && filtered.length > 0) {
|
|
1268
|
+
const [head, ...tail] = filtered;
|
|
1269
|
+
segments.push(`${postDotPrefix}${head}`, ...tail);
|
|
1270
|
+
postDotPrefix = "";
|
|
1182
1271
|
} else {
|
|
1183
1272
|
segments.push(...filtered);
|
|
1184
1273
|
}
|
|
@@ -1188,11 +1277,23 @@ var Parser = class {
|
|
|
1188
1277
|
break;
|
|
1189
1278
|
}
|
|
1190
1279
|
spaceConcat = false;
|
|
1191
|
-
if (trailingDot)
|
|
1280
|
+
if (trailingDot) {
|
|
1281
|
+
const next2 = this.peek();
|
|
1282
|
+
if ((next2.kind === "unquoted" || next2.kind === "string") && next2.precedingWhitespace.length > 0) {
|
|
1283
|
+
postDotPrefix = next2.precedingWhitespace;
|
|
1284
|
+
} else {
|
|
1285
|
+
postDotPrefix = "";
|
|
1286
|
+
}
|
|
1287
|
+
continue;
|
|
1288
|
+
}
|
|
1192
1289
|
const next = this.peek();
|
|
1193
1290
|
if (next.kind === "unquoted" && next.value === "." && !next.precedingSpace) {
|
|
1194
1291
|
this.advance();
|
|
1195
1292
|
trailingDot = true;
|
|
1293
|
+
const afterDot = this.peek();
|
|
1294
|
+
if ((afterDot.kind === "unquoted" || afterDot.kind === "string") && afterDot.precedingWhitespace.length > 0) {
|
|
1295
|
+
postDotPrefix = afterDot.precedingWhitespace;
|
|
1296
|
+
}
|
|
1196
1297
|
continue;
|
|
1197
1298
|
}
|
|
1198
1299
|
if (next.kind === "unquoted" && next.value.startsWith(".") && !next.precedingSpace) {
|
|
@@ -1205,6 +1306,14 @@ var Parser = class {
|
|
|
1205
1306
|
}
|
|
1206
1307
|
break;
|
|
1207
1308
|
}
|
|
1309
|
+
if (trailingDot) {
|
|
1310
|
+
const here = this.peek();
|
|
1311
|
+
throw new ParseError(
|
|
1312
|
+
`path has a trailing period '.' \u2014 empty key segment not allowed (HOCON.md path rules)`,
|
|
1313
|
+
here.line,
|
|
1314
|
+
here.col
|
|
1315
|
+
);
|
|
1316
|
+
}
|
|
1208
1317
|
return { segments, firstWasQuoted };
|
|
1209
1318
|
}
|
|
1210
1319
|
parseInclude() {
|
|
@@ -1377,7 +1486,8 @@ var Parser = class {
|
|
|
1377
1486
|
break;
|
|
1378
1487
|
}
|
|
1379
1488
|
if (hadSpace) {
|
|
1380
|
-
|
|
1489
|
+
const sep = t.precedingWhitespace.length > 0 ? t.precedingWhitespace : " ";
|
|
1490
|
+
parts.push({ kind: "scalar", raw: sep, valueType: "string", pos: { line: t.line, col: t.col }, _separator: true });
|
|
1381
1491
|
}
|
|
1382
1492
|
parts.push(node);
|
|
1383
1493
|
}
|
|
@@ -1813,35 +1923,19 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1813
1923
|
const childPrefix = [...pathPrefix, head];
|
|
1814
1924
|
const fullKey = stringSegmentsToKey(childPrefix);
|
|
1815
1925
|
if (field.append) {
|
|
1816
|
-
const
|
|
1817
|
-
|
|
1818
|
-
const folded = foldOrSkipPrior(existing2, fullKey, oldPrior);
|
|
1819
|
-
if (folded !== void 0) obj.priorValues.set(head, folded);
|
|
1820
|
-
obj.fields.set(head, {
|
|
1821
|
-
_kind: "append-placeholder",
|
|
1822
|
-
// Use the folded existing (self-ref-free) for the Append. When the
|
|
1823
|
-
// fold returned undefined (self-ref present but no old prior),
|
|
1824
|
-
// fall back to the original existing — resolveSubst will then
|
|
1825
|
-
// raise the "self-ref with no prior value" error at resolve time,
|
|
1826
|
-
// matching the pre-fix behaviour for that edge case.
|
|
1827
|
-
//
|
|
1828
|
-
// Clone `folded` again so the Append.existing and priorValues[head]
|
|
1829
|
-
// do not share the same Subst/Concat references — relativizeResObj
|
|
1830
|
-
// walks BOTH `fields` and `priorValues` and mutates Subst.segments
|
|
1831
|
-
// in place, so a shared reference would get its prefix applied
|
|
1832
|
-
// twice (resulting in e.g. `${outer.outer.base}` instead of
|
|
1833
|
-
// `${outer.base}`). Codex review on PR #131.
|
|
1834
|
-
existing: folded !== void 0 ? cloneResolverValue(folded) : existing2,
|
|
1835
|
-
elem: this.astToResolverValue(field.value, childPrefix)
|
|
1836
|
-
});
|
|
1926
|
+
const synthetic = this.desugarAppend(field, childPrefix);
|
|
1927
|
+
this.applyField(obj, synthetic, pathPrefix);
|
|
1837
1928
|
return;
|
|
1838
1929
|
}
|
|
1839
1930
|
const existing = obj.fields.get(head);
|
|
1840
1931
|
const newVal = this.astToResolverValue(field.value, childPrefix);
|
|
1932
|
+
if (!containsSelfRef(newVal, fullKey)) {
|
|
1933
|
+
obj.resetKeys.add(head);
|
|
1934
|
+
}
|
|
1841
1935
|
if (existing !== void 0) {
|
|
1842
|
-
const exFolded = foldNestedSelfRefs(existing, childPrefix);
|
|
1843
1936
|
const oldPrior = obj.priorValues.get(head);
|
|
1844
|
-
const
|
|
1937
|
+
const priorInput = isResObj(existing) ? foldNestedSelfRefs(existing, childPrefix) : existing;
|
|
1938
|
+
const prior = foldOrSkipPrior(priorInput, fullKey, oldPrior);
|
|
1845
1939
|
if (prior !== void 0) obj.priorValues.set(head, prior);
|
|
1846
1940
|
}
|
|
1847
1941
|
if (existing !== void 0 && isResObj(existing) && isResObj(newVal)) {
|
|
@@ -1879,23 +1973,19 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1879
1973
|
const childPrefix = [...pathPrefix, head];
|
|
1880
1974
|
const fullKey = stringSegmentsToKey(childPrefix);
|
|
1881
1975
|
if (field.append) {
|
|
1882
|
-
const
|
|
1883
|
-
|
|
1884
|
-
const folded = foldOrSkipPrior(existing2, fullKey, oldPrior);
|
|
1885
|
-
if (folded !== void 0) obj.priorValues.set(head, folded);
|
|
1886
|
-
obj.fields.set(head, {
|
|
1887
|
-
_kind: "append-placeholder",
|
|
1888
|
-
existing: folded !== void 0 ? cloneResolverValue(folded) : existing2,
|
|
1889
|
-
elem: await this.astToResolverValueAsync(field.value, childPrefix)
|
|
1890
|
-
});
|
|
1976
|
+
const synthetic = this.desugarAppend(field, childPrefix);
|
|
1977
|
+
await this.applyFieldAsync(obj, synthetic, pathPrefix);
|
|
1891
1978
|
return;
|
|
1892
1979
|
}
|
|
1893
1980
|
const existing = obj.fields.get(head);
|
|
1894
1981
|
const newVal = await this.astToResolverValueAsync(field.value, childPrefix);
|
|
1982
|
+
if (!containsSelfRef(newVal, fullKey)) {
|
|
1983
|
+
obj.resetKeys.add(head);
|
|
1984
|
+
}
|
|
1895
1985
|
if (existing !== void 0) {
|
|
1896
|
-
const exFolded = foldNestedSelfRefs(existing, childPrefix);
|
|
1897
1986
|
const oldPrior = obj.priorValues.get(head);
|
|
1898
|
-
const
|
|
1987
|
+
const priorInput = isResObj(existing) ? foldNestedSelfRefs(existing, childPrefix) : existing;
|
|
1988
|
+
const prior = foldOrSkipPrior(priorInput, fullKey, oldPrior);
|
|
1899
1989
|
if (prior !== void 0) obj.priorValues.set(head, prior);
|
|
1900
1990
|
}
|
|
1901
1991
|
if (existing !== void 0 && isResObj(existing) && isResObj(newVal)) {
|
|
@@ -1904,6 +1994,21 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1904
1994
|
}
|
|
1905
1995
|
obj.fields.set(head, newVal);
|
|
1906
1996
|
}
|
|
1997
|
+
/** Builds the `key = ${?fullkey} [value]` field that `key += value` desugars
|
|
1998
|
+
* to (S13b.2, HOCON.md L732). `childPrefix` is the field's fully-qualified
|
|
1999
|
+
* path (pathPrefix + key), so a nested `srv { items += x }` references
|
|
2000
|
+
* `${?srv.items}`; include relativization rewrites it under a mount prefix.
|
|
2001
|
+
* `field.key` is already single-segment here (multi-segment keys are split
|
|
2002
|
+
* into nested objects upstream). Returns a NEW AstField (append=false);
|
|
2003
|
+
* positions inherit from the original field so resolve-time errors (the
|
|
2004
|
+
* S13b.2 non-array check, now via the scalar+array concat) keep a location. */
|
|
2005
|
+
desugarAppend(field, childPrefix) {
|
|
2006
|
+
const segments = childPrefix.map((text) => ({ text, line: field.pos.line, col: field.pos.col }));
|
|
2007
|
+
const subst = { kind: "subst", segments, optional: true, listSuffix: false, pos: field.pos };
|
|
2008
|
+
const elemArray = { kind: "array", items: [field.value], pos: field.pos };
|
|
2009
|
+
const synthetic = { kind: "concat", nodes: [subst, elemArray], pos: field.pos };
|
|
2010
|
+
return { key: field.key, value: synthetic, append: false, pos: field.pos };
|
|
2011
|
+
}
|
|
1907
2012
|
astToResolverValue(ast, pathPrefix) {
|
|
1908
2013
|
switch (ast.kind) {
|
|
1909
2014
|
case "scalar": {
|
|
@@ -1918,7 +2023,7 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1918
2023
|
return inner;
|
|
1919
2024
|
}
|
|
1920
2025
|
case "subst":
|
|
1921
|
-
return { _kind: "subst-placeholder", segments: ast.segments, optional: ast.optional, listSuffix: ast.listSuffix, line: ast.pos.line, col: ast.pos.col, prefixLen: 0 };
|
|
2026
|
+
return { _kind: "subst-placeholder", segments: ast.segments, optional: ast.optional, knownAbsent: false, listSuffix: ast.listSuffix, line: ast.pos.line, col: ast.pos.col, prefixLen: 0 };
|
|
1922
2027
|
case "concat":
|
|
1923
2028
|
return { _kind: "concat-placeholder", nodes: ast.nodes.map((n) => this.astToResolverValue(n, pathPrefix)), line: ast.pos.line, col: ast.pos.col };
|
|
1924
2029
|
case "include":
|
|
@@ -1942,7 +2047,7 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1942
2047
|
case "object":
|
|
1943
2048
|
return await this.buildAsync(ast, pathPrefix);
|
|
1944
2049
|
case "subst":
|
|
1945
|
-
return { _kind: "subst-placeholder", segments: ast.segments, optional: ast.optional, listSuffix: ast.listSuffix, line: ast.pos.line, col: ast.pos.col, prefixLen: 0 };
|
|
2050
|
+
return { _kind: "subst-placeholder", segments: ast.segments, optional: ast.optional, knownAbsent: false, listSuffix: ast.listSuffix, line: ast.pos.line, col: ast.pos.col, prefixLen: 0 };
|
|
1946
2051
|
case "concat": {
|
|
1947
2052
|
const nodes = [];
|
|
1948
2053
|
for (const n of ast.nodes) {
|
|
@@ -1968,11 +2073,6 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1968
2073
|
}
|
|
1969
2074
|
return;
|
|
1970
2075
|
}
|
|
1971
|
-
if (isAppend(val)) {
|
|
1972
|
-
this.relativizeSubstPaths(val.existing, prefixSegments);
|
|
1973
|
-
this.relativizeSubstPaths(val.elem, prefixSegments);
|
|
1974
|
-
return;
|
|
1975
|
-
}
|
|
1976
2076
|
if (isResObj(val)) {
|
|
1977
2077
|
this.relativizeResObj(val, prefixSegments);
|
|
1978
2078
|
return;
|
|
@@ -2060,6 +2160,8 @@ var SubstitutionResolver = class {
|
|
|
2060
2160
|
const result = /* @__PURE__ */ new Map();
|
|
2061
2161
|
for (const [key, val] of obj.fields) {
|
|
2062
2162
|
this.resolvingFieldPath.push(key);
|
|
2163
|
+
const fullCacheKey = stringSegmentsToKey(this.resolvingFieldPath);
|
|
2164
|
+
this.cache.delete(fullCacheKey);
|
|
2063
2165
|
let resolved;
|
|
2064
2166
|
try {
|
|
2065
2167
|
resolved = this.resolveVal(val, obj);
|
|
@@ -2072,28 +2174,42 @@ var SubstitutionResolver = class {
|
|
|
2072
2174
|
if (prior !== void 0) {
|
|
2073
2175
|
const priorResolved = this.resolveVal(prior, obj);
|
|
2074
2176
|
if (priorResolved !== void 0 && priorResolved.kind === "object") {
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
priorResolved,
|
|
2079
|
-
resolved
|
|
2080
|
-
)
|
|
2177
|
+
const finalValue = deepMergeHoconValues(
|
|
2178
|
+
priorResolved,
|
|
2179
|
+
resolved
|
|
2081
2180
|
);
|
|
2181
|
+
result.set(key, finalValue);
|
|
2182
|
+
this.cache.set(fullCacheKey, finalValue);
|
|
2183
|
+
this.cacheDescendants(fullCacheKey, finalValue);
|
|
2082
2184
|
continue;
|
|
2083
2185
|
}
|
|
2084
2186
|
}
|
|
2085
2187
|
}
|
|
2086
2188
|
result.set(key, resolved);
|
|
2189
|
+
this.cache.set(fullCacheKey, resolved);
|
|
2190
|
+
this.cacheDescendants(fullCacheKey, resolved);
|
|
2087
2191
|
} else {
|
|
2088
2192
|
const prior = obj.priorValues.get(key);
|
|
2089
2193
|
if (prior !== void 0) {
|
|
2090
2194
|
const priorResolved = this.resolveVal(prior, obj);
|
|
2091
|
-
if (priorResolved !== void 0)
|
|
2195
|
+
if (priorResolved !== void 0) {
|
|
2196
|
+
result.set(key, priorResolved);
|
|
2197
|
+
this.cache.set(fullCacheKey, priorResolved);
|
|
2198
|
+
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
2199
|
+
}
|
|
2092
2200
|
}
|
|
2093
2201
|
}
|
|
2094
2202
|
}
|
|
2095
2203
|
return { kind: "object", fields: result };
|
|
2096
2204
|
}
|
|
2205
|
+
cacheDescendants(prefix, value) {
|
|
2206
|
+
if (value.kind !== "object") return;
|
|
2207
|
+
for (const [key, child] of value.fields) {
|
|
2208
|
+
const childKey = `${prefix}.${stringSegmentsToKey([key])}`;
|
|
2209
|
+
this.cache.set(childKey, child);
|
|
2210
|
+
this.cacheDescendants(childKey, child);
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2097
2213
|
resolveVal(v, scope) {
|
|
2098
2214
|
if (isSubst(v)) return this.resolveSubst(v, scope);
|
|
2099
2215
|
if (isConcat(v)) {
|
|
@@ -2105,7 +2221,6 @@ var SubstitutionResolver = class {
|
|
|
2105
2221
|
this.resolvingConcats.delete(v);
|
|
2106
2222
|
}
|
|
2107
2223
|
}
|
|
2108
|
-
if (isAppend(v)) return this.resolveAppend(v, scope);
|
|
2109
2224
|
if (isResObj(v)) return this.resolveResObj(v);
|
|
2110
2225
|
const hv = v;
|
|
2111
2226
|
if (hv.kind === "array") {
|
|
@@ -2119,6 +2234,7 @@ var SubstitutionResolver = class {
|
|
|
2119
2234
|
return hv;
|
|
2120
2235
|
}
|
|
2121
2236
|
resolveSubst(s, scope) {
|
|
2237
|
+
if (s.knownAbsent) return void 0;
|
|
2122
2238
|
const key = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
2123
2239
|
if (this.cache.has(key)) return this.cache.get(key);
|
|
2124
2240
|
if (this.resolving.has(key)) {
|
|
@@ -2211,6 +2327,28 @@ var SubstitutionResolver = class {
|
|
|
2211
2327
|
if (result !== void 0) this.cache.set(key, result);
|
|
2212
2328
|
return result;
|
|
2213
2329
|
}
|
|
2330
|
+
if (s.prefixLen > 0 && s.segments.length > s.prefixLen) {
|
|
2331
|
+
const originalSegments = s.segments.slice(s.prefixLen);
|
|
2332
|
+
const fallbackFound = lookupPath(this.root, originalSegments);
|
|
2333
|
+
if (fallbackFound !== void 0) {
|
|
2334
|
+
let result = this.resolveVal(fallbackFound, scope);
|
|
2335
|
+
if (originalSegments.length === 1 && result !== void 0 && result.kind === "object") {
|
|
2336
|
+
const rootSeg = originalSegments[0]?.text ?? "";
|
|
2337
|
+
const prior = this.root.priorValues.get(rootSeg);
|
|
2338
|
+
if (prior !== void 0) {
|
|
2339
|
+
const priorResolved = this.resolveVal(prior, scope);
|
|
2340
|
+
if (priorResolved !== void 0 && priorResolved.kind === "object") {
|
|
2341
|
+
result = deepMergeHoconValues(
|
|
2342
|
+
priorResolved,
|
|
2343
|
+
result
|
|
2344
|
+
);
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
if (result !== void 0) this.cache.set(key, result);
|
|
2349
|
+
return result;
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2214
2352
|
if (s.listSuffix && this.opts.useSystemEnvironment !== false) {
|
|
2215
2353
|
const result = this.resolveEnvList(s);
|
|
2216
2354
|
if (result !== void 0) {
|
|
@@ -2367,38 +2505,6 @@ var SubstitutionResolver = class {
|
|
|
2367
2505
|
}
|
|
2368
2506
|
return folded;
|
|
2369
2507
|
}
|
|
2370
|
-
resolveAppend(a, scope) {
|
|
2371
|
-
const existing = this.resolveVal(a.existing, scope) ?? { kind: "array", items: [] };
|
|
2372
|
-
if (this.opts.allowUnresolved && (isSubst(existing) || isConcat(existing) || isAppend(existing))) {
|
|
2373
|
-
return a;
|
|
2374
|
-
}
|
|
2375
|
-
const elem = this.resolveVal(a.elem, scope);
|
|
2376
|
-
let priorItems;
|
|
2377
|
-
if (existing.kind === "array") {
|
|
2378
|
-
priorItems = existing.items;
|
|
2379
|
-
} else if (existing.kind === "object") {
|
|
2380
|
-
const converted = numericObjectToArray(existing);
|
|
2381
|
-
if (converted === null) {
|
|
2382
|
-
throw new ResolveError(
|
|
2383
|
-
`'+=' on non-array value: prior value is object with non-numeric keys (spec L732)`,
|
|
2384
|
-
"",
|
|
2385
|
-
0,
|
|
2386
|
-
0
|
|
2387
|
-
);
|
|
2388
|
-
}
|
|
2389
|
-
priorItems = converted;
|
|
2390
|
-
} else {
|
|
2391
|
-
throw new ResolveError(
|
|
2392
|
-
`'+=' on non-array value: prior value is ${existing.kind} (spec L732)`,
|
|
2393
|
-
"",
|
|
2394
|
-
0,
|
|
2395
|
-
0
|
|
2396
|
-
);
|
|
2397
|
-
}
|
|
2398
|
-
const items = [...priorItems];
|
|
2399
|
-
if (elem !== void 0) items.push(elem);
|
|
2400
|
-
return { kind: "array", items };
|
|
2401
|
-
}
|
|
2402
2508
|
};
|
|
2403
2509
|
|
|
2404
2510
|
// src/internal/resolver/resolver.ts
|
|
@@ -2416,7 +2522,7 @@ function containsPlaceholders(tree) {
|
|
|
2416
2522
|
}
|
|
2417
2523
|
function valContainsPlaceholders(v) {
|
|
2418
2524
|
const rv = v;
|
|
2419
|
-
if (isSubst(rv) || isConcat(rv)
|
|
2525
|
+
if (isSubst(rv) || isConcat(rv)) return true;
|
|
2420
2526
|
if (isResObj(rv)) return containsPlaceholders(rv);
|
|
2421
2527
|
const hv = v;
|
|
2422
2528
|
if (hv?.kind === "array") {
|
|
@@ -2427,7 +2533,7 @@ function valContainsPlaceholders(v) {
|
|
|
2427
2533
|
function buildPartialHoconFromResObj(tree) {
|
|
2428
2534
|
const fields = /* @__PURE__ */ new Map();
|
|
2429
2535
|
for (const [k, v] of tree.fields) {
|
|
2430
|
-
if (!isSubst(v) && !isConcat(v)
|
|
2536
|
+
if (!isSubst(v) && !isConcat(v)) {
|
|
2431
2537
|
if (isResObj(v)) {
|
|
2432
2538
|
fields.set(k, buildPartialHoconFromResObj(v));
|
|
2433
2539
|
} else {
|
|
@@ -2820,7 +2926,7 @@ function hoconToJs(v) {
|
|
|
2820
2926
|
function resObjToKeyShape(tree) {
|
|
2821
2927
|
const fields = /* @__PURE__ */ new Map();
|
|
2822
2928
|
for (const [k, v] of tree.fields) {
|
|
2823
|
-
if (isSubst(v) || isConcat(v)
|
|
2929
|
+
if (isSubst(v) || isConcat(v)) {
|
|
2824
2930
|
fields.set(k, { kind: "scalar", raw: "", valueType: "null" });
|
|
2825
2931
|
} else if (isResObj(v)) {
|
|
2826
2932
|
fields.set(k, resObjToKeyShape(v));
|
|
@@ -2834,7 +2940,7 @@ function stripPlaceholderFields(v) {
|
|
|
2834
2940
|
const fields = /* @__PURE__ */ new Map();
|
|
2835
2941
|
let hadPlaceholders = false;
|
|
2836
2942
|
for (const [k, val] of v.fields) {
|
|
2837
|
-
if (val._kind === "subst-placeholder" || val._kind === "concat-placeholder"
|
|
2943
|
+
if (val._kind === "subst-placeholder" || val._kind === "concat-placeholder") {
|
|
2838
2944
|
hadPlaceholders = true;
|
|
2839
2945
|
} else if (val.kind === "object") {
|
|
2840
2946
|
const inner = stripPlaceholderFields(val);
|