@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.js
CHANGED
|
@@ -237,55 +237,6 @@ var NotResolvedError = class extends ConfigError {
|
|
|
237
237
|
}
|
|
238
238
|
};
|
|
239
239
|
|
|
240
|
-
// src/internal/resolver/types.ts
|
|
241
|
-
var separatorValues = /* @__PURE__ */ new WeakSet();
|
|
242
|
-
function isSubst(v) {
|
|
243
|
-
return v._kind === "subst-placeholder";
|
|
244
|
-
}
|
|
245
|
-
function isConcat(v) {
|
|
246
|
-
return v._kind === "concat-placeholder";
|
|
247
|
-
}
|
|
248
|
-
function isAppend(v) {
|
|
249
|
-
return v._kind === "append-placeholder";
|
|
250
|
-
}
|
|
251
|
-
function isResObj(v) {
|
|
252
|
-
return v._kind === "res-obj";
|
|
253
|
-
}
|
|
254
|
-
function makeResObj() {
|
|
255
|
-
return { _kind: "res-obj", fields: /* @__PURE__ */ new Map(), priorValues: /* @__PURE__ */ new Map() };
|
|
256
|
-
}
|
|
257
|
-
function mergeUnresolved(receiver, fallback) {
|
|
258
|
-
const result = makeResObj();
|
|
259
|
-
for (const [k, v] of fallback.fields) {
|
|
260
|
-
result.fields.set(k, v);
|
|
261
|
-
}
|
|
262
|
-
for (const [k, v] of fallback.priorValues) {
|
|
263
|
-
result.priorValues.set(k, v);
|
|
264
|
-
}
|
|
265
|
-
for (const [k, rv] of receiver.fields) {
|
|
266
|
-
const existing = result.fields.get(k);
|
|
267
|
-
if (existing !== void 0) {
|
|
268
|
-
const recPrior = receiver.priorValues.get(k);
|
|
269
|
-
if (recPrior !== void 0 && !isResObj(recPrior)) {
|
|
270
|
-
result.fields.set(k, rv);
|
|
271
|
-
continue;
|
|
272
|
-
}
|
|
273
|
-
if (isResObj(rv) && isResObj(existing)) {
|
|
274
|
-
result.fields.set(k, mergeUnresolved(rv, existing));
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
277
|
-
result.priorValues.set(k, existing);
|
|
278
|
-
}
|
|
279
|
-
result.fields.set(k, rv);
|
|
280
|
-
}
|
|
281
|
-
for (const [k, v] of receiver.priorValues) {
|
|
282
|
-
if (receiver.fields.has(k)) {
|
|
283
|
-
result.priorValues.set(k, v);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
return result;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
240
|
// src/internal/resolver/fold-self-ref.ts
|
|
290
241
|
function substFullKey(s) {
|
|
291
242
|
return stringSegmentsToKey(s.segments.map((seg) => seg.text));
|
|
@@ -299,11 +250,8 @@ function stringSegmentsToKey(segments) {
|
|
|
299
250
|
}).join(".");
|
|
300
251
|
}
|
|
301
252
|
function containsSelfRef(v, fullKey) {
|
|
302
|
-
if (isSubst(v)) return substFullKey(v) === fullKey;
|
|
253
|
+
if (isSubst(v)) return !v.knownAbsent && substFullKey(v) === fullKey;
|
|
303
254
|
if (isConcat(v)) return v.nodes.some((n) => containsSelfRef(n, fullKey));
|
|
304
|
-
if (isAppend(v)) {
|
|
305
|
-
return containsSelfRef(v.existing, fullKey) || containsSelfRef(v.elem, fullKey);
|
|
306
|
-
}
|
|
307
255
|
if (isResObj(v)) {
|
|
308
256
|
for (const f of v.fields.values()) {
|
|
309
257
|
if (containsSelfRef(f, fullKey)) return true;
|
|
@@ -334,19 +282,12 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
334
282
|
col: v.col
|
|
335
283
|
};
|
|
336
284
|
}
|
|
337
|
-
if (isAppend(v)) {
|
|
338
|
-
return {
|
|
339
|
-
_kind: "append-placeholder",
|
|
340
|
-
existing: foldSelfRef(v.existing, fullKey, replacement),
|
|
341
|
-
elem: foldSelfRef(v.elem, fullKey, replacement)
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
285
|
if (isResObj(v)) {
|
|
345
286
|
const newFields = /* @__PURE__ */ new Map();
|
|
346
287
|
for (const [k, val] of v.fields) {
|
|
347
288
|
newFields.set(k, foldSelfRef(val, fullKey, replacement));
|
|
348
289
|
}
|
|
349
|
-
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues) };
|
|
290
|
+
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
350
291
|
}
|
|
351
292
|
const hv = v;
|
|
352
293
|
if (hv.kind === "array") {
|
|
@@ -364,17 +305,106 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
364
305
|
}
|
|
365
306
|
return v;
|
|
366
307
|
}
|
|
308
|
+
function foldKnownAbsentSelfRef(v, fullKey, replacement) {
|
|
309
|
+
if (isSubst(v)) {
|
|
310
|
+
return v.knownAbsent && substFullKey(v) === fullKey ? replacement : v;
|
|
311
|
+
}
|
|
312
|
+
if (isConcat(v)) {
|
|
313
|
+
return {
|
|
314
|
+
_kind: "concat-placeholder",
|
|
315
|
+
nodes: v.nodes.map((n) => foldKnownAbsentSelfRef(n, fullKey, replacement)),
|
|
316
|
+
line: v.line,
|
|
317
|
+
col: v.col
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
if (isResObj(v)) {
|
|
321
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
322
|
+
for (const [k, val] of v.fields) {
|
|
323
|
+
newFields.set(k, foldKnownAbsentSelfRef(val, fullKey, replacement));
|
|
324
|
+
}
|
|
325
|
+
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
326
|
+
}
|
|
327
|
+
const hv = v;
|
|
328
|
+
if (hv.kind === "array") {
|
|
329
|
+
return {
|
|
330
|
+
kind: "array",
|
|
331
|
+
items: hv.items.map((item) => foldKnownAbsentSelfRef(item, fullKey, replacement))
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
if (hv.kind === "object") {
|
|
335
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
336
|
+
for (const [k, val] of hv.fields) {
|
|
337
|
+
newFields.set(k, foldKnownAbsentSelfRef(val, fullKey, replacement));
|
|
338
|
+
}
|
|
339
|
+
return { kind: "object", fields: newFields };
|
|
340
|
+
}
|
|
341
|
+
return v;
|
|
342
|
+
}
|
|
367
343
|
function foldOrSkipPrior(prior, fullKey, old) {
|
|
368
344
|
if (!containsSelfRef(prior, fullKey)) return cloneResolverValue(prior);
|
|
369
|
-
if (old === void 0) return
|
|
345
|
+
if (old === void 0) return foldOptionalSelfRefAbsent(prior, fullKey);
|
|
370
346
|
return foldSelfRef(prior, fullKey, old);
|
|
371
347
|
}
|
|
348
|
+
function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
349
|
+
if (isSubst(v) && substFullKey(v) === fullKey) {
|
|
350
|
+
if (!v.optional) return void 0;
|
|
351
|
+
return {
|
|
352
|
+
_kind: "subst-placeholder",
|
|
353
|
+
segments: v.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
|
|
354
|
+
optional: v.optional,
|
|
355
|
+
knownAbsent: true,
|
|
356
|
+
listSuffix: v.listSuffix,
|
|
357
|
+
line: v.line,
|
|
358
|
+
col: v.col,
|
|
359
|
+
prefixLen: v.prefixLen
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
if (isConcat(v)) {
|
|
363
|
+
const nodes = [];
|
|
364
|
+
for (const node of v.nodes) {
|
|
365
|
+
const folded = foldOptionalSelfRefAbsent(node, fullKey);
|
|
366
|
+
if (folded === void 0) return void 0;
|
|
367
|
+
nodes.push(folded);
|
|
368
|
+
}
|
|
369
|
+
return { _kind: "concat-placeholder", nodes, line: v.line, col: v.col };
|
|
370
|
+
}
|
|
371
|
+
if (isResObj(v)) {
|
|
372
|
+
const fields = /* @__PURE__ */ new Map();
|
|
373
|
+
for (const [key, value] of v.fields) {
|
|
374
|
+
const folded = foldOptionalSelfRefAbsent(value, fullKey);
|
|
375
|
+
if (folded === void 0) return void 0;
|
|
376
|
+
fields.set(key, folded);
|
|
377
|
+
}
|
|
378
|
+
return { _kind: "res-obj", fields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
379
|
+
}
|
|
380
|
+
const hv = v;
|
|
381
|
+
if (hv.kind === "array") {
|
|
382
|
+
const items = [];
|
|
383
|
+
for (const item of hv.items) {
|
|
384
|
+
const folded = foldOptionalSelfRefAbsent(item, fullKey);
|
|
385
|
+
if (folded === void 0) return void 0;
|
|
386
|
+
items.push(folded);
|
|
387
|
+
}
|
|
388
|
+
return { kind: "array", items };
|
|
389
|
+
}
|
|
390
|
+
if (hv.kind === "object") {
|
|
391
|
+
const fields = /* @__PURE__ */ new Map();
|
|
392
|
+
for (const [key, value] of hv.fields) {
|
|
393
|
+
const folded = foldOptionalSelfRefAbsent(value, fullKey);
|
|
394
|
+
if (folded === void 0) return void 0;
|
|
395
|
+
fields.set(key, folded);
|
|
396
|
+
}
|
|
397
|
+
return { kind: "object", fields };
|
|
398
|
+
}
|
|
399
|
+
return cloneResolverValue(v);
|
|
400
|
+
}
|
|
372
401
|
function cloneResolverValue(v) {
|
|
373
402
|
if (isSubst(v)) {
|
|
374
403
|
return {
|
|
375
404
|
_kind: "subst-placeholder",
|
|
376
405
|
segments: v.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
|
|
377
406
|
optional: v.optional,
|
|
407
|
+
knownAbsent: v.knownAbsent,
|
|
378
408
|
listSuffix: v.listSuffix,
|
|
379
409
|
line: v.line,
|
|
380
410
|
col: v.col,
|
|
@@ -394,14 +424,7 @@ function cloneResolverValue(v) {
|
|
|
394
424
|
for (const [k, val] of v.fields) newFields.set(k, cloneResolverValue(val));
|
|
395
425
|
const newPriors = /* @__PURE__ */ new Map();
|
|
396
426
|
for (const [k, val] of v.priorValues) newPriors.set(k, cloneResolverValue(val));
|
|
397
|
-
return { _kind: "res-obj", fields: newFields, priorValues: newPriors };
|
|
398
|
-
}
|
|
399
|
-
if (isAppend(v)) {
|
|
400
|
-
return {
|
|
401
|
-
_kind: "append-placeholder",
|
|
402
|
-
existing: cloneResolverValue(v.existing),
|
|
403
|
-
elem: cloneResolverValue(v.elem)
|
|
404
|
-
};
|
|
427
|
+
return { _kind: "res-obj", fields: newFields, priorValues: newPriors, resetKeys: new Set(v.resetKeys) };
|
|
405
428
|
}
|
|
406
429
|
const hv = v;
|
|
407
430
|
if (hv.kind === "array") {
|
|
@@ -436,14 +459,11 @@ function foldNestedSelfRefs(v, pathPrefix) {
|
|
|
436
459
|
}
|
|
437
460
|
newFields.set(k, finalVal);
|
|
438
461
|
}
|
|
439
|
-
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues) };
|
|
462
|
+
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
440
463
|
}
|
|
441
464
|
function containsSubstByPath(v, target) {
|
|
442
|
-
if (isSubst(v)) return segmentsTextEqual(v.segments, target);
|
|
465
|
+
if (isSubst(v)) return !v.knownAbsent && segmentsTextEqual(v.segments, target);
|
|
443
466
|
if (isConcat(v)) return v.nodes.some((n) => containsSubstByPath(n, target));
|
|
444
|
-
if (isAppend(v)) {
|
|
445
|
-
return containsSubstByPath(v.existing, target) || containsSubstByPath(v.elem, target);
|
|
446
|
-
}
|
|
447
467
|
if (isResObj(v)) {
|
|
448
468
|
for (const f of v.fields.values()) {
|
|
449
469
|
if (containsSubstByPath(f, target)) return true;
|
|
@@ -472,6 +492,53 @@ function segmentsTextEqual(a, b) {
|
|
|
472
492
|
return true;
|
|
473
493
|
}
|
|
474
494
|
|
|
495
|
+
// src/internal/resolver/types.ts
|
|
496
|
+
var separatorValues = /* @__PURE__ */ new WeakSet();
|
|
497
|
+
function isSubst(v) {
|
|
498
|
+
return v._kind === "subst-placeholder";
|
|
499
|
+
}
|
|
500
|
+
function isConcat(v) {
|
|
501
|
+
return v._kind === "concat-placeholder";
|
|
502
|
+
}
|
|
503
|
+
function isResObj(v) {
|
|
504
|
+
return v._kind === "res-obj";
|
|
505
|
+
}
|
|
506
|
+
function makeResObj() {
|
|
507
|
+
return { _kind: "res-obj", fields: /* @__PURE__ */ new Map(), priorValues: /* @__PURE__ */ new Map(), resetKeys: /* @__PURE__ */ new Set() };
|
|
508
|
+
}
|
|
509
|
+
function mergeUnresolved(receiver, fallback) {
|
|
510
|
+
const result = makeResObj();
|
|
511
|
+
for (const [k, v] of fallback.fields) {
|
|
512
|
+
result.fields.set(k, v);
|
|
513
|
+
}
|
|
514
|
+
for (const [k, v] of fallback.priorValues) {
|
|
515
|
+
result.priorValues.set(k, v);
|
|
516
|
+
}
|
|
517
|
+
for (const [k, rv] of receiver.fields) {
|
|
518
|
+
const existing = result.fields.get(k);
|
|
519
|
+
if (existing !== void 0) {
|
|
520
|
+
const recPrior = receiver.priorValues.get(k);
|
|
521
|
+
if (recPrior !== void 0 && !isResObj(recPrior)) {
|
|
522
|
+
result.fields.set(k, rv);
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
if (isResObj(rv) && isResObj(existing)) {
|
|
526
|
+
result.fields.set(k, mergeUnresolved(rv, existing));
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
const foldedPrior = foldOrSkipPrior(existing, k, void 0);
|
|
530
|
+
if (foldedPrior !== void 0) result.priorValues.set(k, foldedPrior);
|
|
531
|
+
}
|
|
532
|
+
result.fields.set(k, rv);
|
|
533
|
+
}
|
|
534
|
+
for (const [k, v] of receiver.priorValues) {
|
|
535
|
+
if (receiver.fields.has(k)) {
|
|
536
|
+
result.priorValues.set(k, v);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
return result;
|
|
540
|
+
}
|
|
541
|
+
|
|
475
542
|
// src/internal/resolver/utils.ts
|
|
476
543
|
function segmentsToKey(segments) {
|
|
477
544
|
return segments.map((s) => {
|
|
@@ -525,9 +592,19 @@ function deepMergeResObjInto(dst, src, pathPrefix = []) {
|
|
|
525
592
|
deepMergeResObjInto(dstVal, srcVal, childPrefix);
|
|
526
593
|
} else {
|
|
527
594
|
if (dstVal !== void 0) {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
595
|
+
if (src.resetKeys.has(k)) {
|
|
596
|
+
dst.priorValues.delete(k);
|
|
597
|
+
} else {
|
|
598
|
+
const dstFolded = foldOrSkipPrior(dstVal, fullKey, dst.priorValues.get(k));
|
|
599
|
+
if (dstFolded !== void 0) {
|
|
600
|
+
const srcPrior = src.priorValues.get(k);
|
|
601
|
+
if (srcPrior !== void 0) {
|
|
602
|
+
dst.priorValues.set(k, foldKnownAbsentSelfRef(srcPrior, fullKey, dstFolded));
|
|
603
|
+
} else {
|
|
604
|
+
dst.priorValues.set(k, dstFolded);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
531
608
|
}
|
|
532
609
|
dst.fields.set(k, srcVal);
|
|
533
610
|
}
|
|
@@ -537,6 +614,7 @@ function deepMergeResObjInto(dst, src, pathPrefix = []) {
|
|
|
537
614
|
dst.priorValues.set(k, srcPrior);
|
|
538
615
|
}
|
|
539
616
|
}
|
|
617
|
+
for (const k of src.resetKeys) dst.resetKeys.add(k);
|
|
540
618
|
}
|
|
541
619
|
function hoconValueToResObj(hv) {
|
|
542
620
|
const obj = makeResObj();
|
|
@@ -606,6 +684,11 @@ var Lexer = class {
|
|
|
606
684
|
this.line = 1;
|
|
607
685
|
this.col = 1;
|
|
608
686
|
this.hadSpace = false;
|
|
687
|
+
// Accumulates literal whitespace chars consumed between tokens. Reset on every
|
|
688
|
+
// token push. Used so the parser can preserve path-expression whitespace
|
|
689
|
+
// (xx.hocon#42, E13) — e.g. tab vs space adjacent to dots in key paths.
|
|
690
|
+
// Comment text is NOT accumulated; only the actual WS chars.
|
|
691
|
+
this.whitespaceBuffer = "";
|
|
609
692
|
this.tokens = [];
|
|
610
693
|
if (input.charCodeAt(0) === 65279) this.input = input.slice(1);
|
|
611
694
|
}
|
|
@@ -621,6 +704,7 @@ var Lexer = class {
|
|
|
621
704
|
continue;
|
|
622
705
|
}
|
|
623
706
|
if (isHoconWhitespace(ch)) {
|
|
707
|
+
this.whitespaceBuffer += ch;
|
|
624
708
|
this.advance();
|
|
625
709
|
this.hadSpace = true;
|
|
626
710
|
continue;
|
|
@@ -712,7 +796,7 @@ var Lexer = class {
|
|
|
712
796
|
}
|
|
713
797
|
throw new ParseError(`unexpected character: ${JSON.stringify(ch)}`, sl, sc);
|
|
714
798
|
}
|
|
715
|
-
this.tokens.push({ kind: "eof", value: "", line: this.line, col: this.col, isQuoted: false, precedingSpace: false });
|
|
799
|
+
this.tokens.push({ kind: "eof", value: "", line: this.line, col: this.col, isQuoted: false, precedingSpace: false, precedingWhitespace: "" });
|
|
716
800
|
return this.tokens;
|
|
717
801
|
}
|
|
718
802
|
peek(offset = 0) {
|
|
@@ -729,12 +813,14 @@ var Lexer = class {
|
|
|
729
813
|
return ch;
|
|
730
814
|
}
|
|
731
815
|
push(kind, value, l, c, isQuoted = false) {
|
|
732
|
-
this.tokens.push({ kind, value, line: l, col: c, isQuoted, precedingSpace: this.hadSpace });
|
|
816
|
+
this.tokens.push({ kind, value, line: l, col: c, isQuoted, precedingSpace: this.hadSpace, precedingWhitespace: this.whitespaceBuffer });
|
|
733
817
|
this.hadSpace = false;
|
|
818
|
+
this.whitespaceBuffer = "";
|
|
734
819
|
}
|
|
735
820
|
pushSubst(payload, value, l, c) {
|
|
736
|
-
this.tokens.push({ kind: "subst", value, line: l, col: c, isQuoted: false, precedingSpace: this.hadSpace, subst: payload });
|
|
821
|
+
this.tokens.push({ kind: "subst", value, line: l, col: c, isQuoted: false, precedingSpace: this.hadSpace, precedingWhitespace: this.whitespaceBuffer, subst: payload });
|
|
737
822
|
this.hadSpace = false;
|
|
823
|
+
this.whitespaceBuffer = "";
|
|
738
824
|
}
|
|
739
825
|
/**
|
|
740
826
|
* Read body of a quoted string. Opening `"` must already be consumed.
|
|
@@ -980,7 +1066,7 @@ function isUnquotedContinue(ch, nextFn) {
|
|
|
980
1066
|
}
|
|
981
1067
|
|
|
982
1068
|
// src/internal/parser/parser.ts
|
|
983
|
-
var EOF_TOKEN = { kind: "eof", value: "", line: 0, col: 0, isQuoted: false, precedingSpace: false, subst: void 0 };
|
|
1069
|
+
var EOF_TOKEN = { kind: "eof", value: "", line: 0, col: 0, isQuoted: false, precedingSpace: false, precedingWhitespace: "", subst: void 0 };
|
|
984
1070
|
var Parser = class {
|
|
985
1071
|
constructor(tokens) {
|
|
986
1072
|
this.tokens = tokens;
|
|
@@ -1093,13 +1179,17 @@ var Parser = class {
|
|
|
1093
1179
|
let trailingDot = false;
|
|
1094
1180
|
let firstWasQuoted = false;
|
|
1095
1181
|
let spaceConcat = false;
|
|
1182
|
+
let postDotPrefix = "";
|
|
1096
1183
|
while (true) {
|
|
1097
1184
|
const t = this.peek();
|
|
1098
1185
|
if (t.kind === "string") {
|
|
1099
1186
|
this.advance();
|
|
1100
1187
|
if (segments.length === 0) firstWasQuoted = true;
|
|
1101
1188
|
if (spaceConcat) {
|
|
1102
|
-
segments[segments.length - 1] = `${segments[segments.length - 1]}
|
|
1189
|
+
segments[segments.length - 1] = `${segments[segments.length - 1]}${t.precedingWhitespace}${t.value}`;
|
|
1190
|
+
} else if (postDotPrefix !== "") {
|
|
1191
|
+
segments.push(`${postDotPrefix}${t.value}`);
|
|
1192
|
+
postDotPrefix = "";
|
|
1103
1193
|
} else {
|
|
1104
1194
|
segments.push(t.value);
|
|
1105
1195
|
}
|
|
@@ -1109,24 +1199,23 @@ var Parser = class {
|
|
|
1109
1199
|
const raw = t.value.startsWith(".") && segments.length > 0 && !t.precedingSpace ? t.value.slice(1) : t.value;
|
|
1110
1200
|
const parts = raw.split(".");
|
|
1111
1201
|
const filtered = parts.filter((s) => s.length > 0);
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
const after = seg.length >= 2 ? JSON.stringify(seg[1]) : "EOF";
|
|
1115
|
-
throw new ParseError(
|
|
1116
|
-
`unquoted key segment cannot begin with '-' unless followed by a digit (got '-' then ${after} in ${JSON.stringify(seg)}, HOCON.md L270-276)`,
|
|
1117
|
-
t.line,
|
|
1118
|
-
t.col
|
|
1119
|
-
);
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1122
|
-
if (spaceConcat && filtered.length > 0) {
|
|
1202
|
+
if (spaceConcat) {
|
|
1203
|
+
segments[segments.length - 1] = `${segments[segments.length - 1]}${t.precedingWhitespace}`;
|
|
1123
1204
|
if (raw.startsWith(".")) {
|
|
1124
1205
|
segments.push(...filtered);
|
|
1125
|
-
} else {
|
|
1206
|
+
} else if (filtered.length > 0) {
|
|
1126
1207
|
const [head, ...tail] = filtered;
|
|
1127
|
-
segments[segments.length - 1] = `${segments[segments.length - 1]}
|
|
1208
|
+
segments[segments.length - 1] = `${segments[segments.length - 1]}${head}`;
|
|
1128
1209
|
segments.push(...tail);
|
|
1129
1210
|
}
|
|
1211
|
+
} else if (postDotPrefix !== "" && raw.startsWith(".")) {
|
|
1212
|
+
segments.push(postDotPrefix);
|
|
1213
|
+
postDotPrefix = "";
|
|
1214
|
+
segments.push(...filtered);
|
|
1215
|
+
} else if (postDotPrefix !== "" && filtered.length > 0) {
|
|
1216
|
+
const [head, ...tail] = filtered;
|
|
1217
|
+
segments.push(`${postDotPrefix}${head}`, ...tail);
|
|
1218
|
+
postDotPrefix = "";
|
|
1130
1219
|
} else {
|
|
1131
1220
|
segments.push(...filtered);
|
|
1132
1221
|
}
|
|
@@ -1136,11 +1225,23 @@ var Parser = class {
|
|
|
1136
1225
|
break;
|
|
1137
1226
|
}
|
|
1138
1227
|
spaceConcat = false;
|
|
1139
|
-
if (trailingDot)
|
|
1228
|
+
if (trailingDot) {
|
|
1229
|
+
const next2 = this.peek();
|
|
1230
|
+
if ((next2.kind === "unquoted" || next2.kind === "string") && next2.precedingWhitespace.length > 0) {
|
|
1231
|
+
postDotPrefix = next2.precedingWhitespace;
|
|
1232
|
+
} else {
|
|
1233
|
+
postDotPrefix = "";
|
|
1234
|
+
}
|
|
1235
|
+
continue;
|
|
1236
|
+
}
|
|
1140
1237
|
const next = this.peek();
|
|
1141
1238
|
if (next.kind === "unquoted" && next.value === "." && !next.precedingSpace) {
|
|
1142
1239
|
this.advance();
|
|
1143
1240
|
trailingDot = true;
|
|
1241
|
+
const afterDot = this.peek();
|
|
1242
|
+
if ((afterDot.kind === "unquoted" || afterDot.kind === "string") && afterDot.precedingWhitespace.length > 0) {
|
|
1243
|
+
postDotPrefix = afterDot.precedingWhitespace;
|
|
1244
|
+
}
|
|
1144
1245
|
continue;
|
|
1145
1246
|
}
|
|
1146
1247
|
if (next.kind === "unquoted" && next.value.startsWith(".") && !next.precedingSpace) {
|
|
@@ -1153,6 +1254,14 @@ var Parser = class {
|
|
|
1153
1254
|
}
|
|
1154
1255
|
break;
|
|
1155
1256
|
}
|
|
1257
|
+
if (trailingDot) {
|
|
1258
|
+
const here = this.peek();
|
|
1259
|
+
throw new ParseError(
|
|
1260
|
+
`path has a trailing period '.' \u2014 empty key segment not allowed (HOCON.md path rules)`,
|
|
1261
|
+
here.line,
|
|
1262
|
+
here.col
|
|
1263
|
+
);
|
|
1264
|
+
}
|
|
1156
1265
|
return { segments, firstWasQuoted };
|
|
1157
1266
|
}
|
|
1158
1267
|
parseInclude() {
|
|
@@ -1325,7 +1434,8 @@ var Parser = class {
|
|
|
1325
1434
|
break;
|
|
1326
1435
|
}
|
|
1327
1436
|
if (hadSpace) {
|
|
1328
|
-
|
|
1437
|
+
const sep = t.precedingWhitespace.length > 0 ? t.precedingWhitespace : " ";
|
|
1438
|
+
parts.push({ kind: "scalar", raw: sep, valueType: "string", pos: { line: t.line, col: t.col }, _separator: true });
|
|
1329
1439
|
}
|
|
1330
1440
|
parts.push(node);
|
|
1331
1441
|
}
|
|
@@ -1760,35 +1870,19 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1760
1870
|
const childPrefix = [...pathPrefix, head];
|
|
1761
1871
|
const fullKey = stringSegmentsToKey(childPrefix);
|
|
1762
1872
|
if (field.append) {
|
|
1763
|
-
const
|
|
1764
|
-
|
|
1765
|
-
const folded = foldOrSkipPrior(existing2, fullKey, oldPrior);
|
|
1766
|
-
if (folded !== void 0) obj.priorValues.set(head, folded);
|
|
1767
|
-
obj.fields.set(head, {
|
|
1768
|
-
_kind: "append-placeholder",
|
|
1769
|
-
// Use the folded existing (self-ref-free) for the Append. When the
|
|
1770
|
-
// fold returned undefined (self-ref present but no old prior),
|
|
1771
|
-
// fall back to the original existing — resolveSubst will then
|
|
1772
|
-
// raise the "self-ref with no prior value" error at resolve time,
|
|
1773
|
-
// matching the pre-fix behaviour for that edge case.
|
|
1774
|
-
//
|
|
1775
|
-
// Clone `folded` again so the Append.existing and priorValues[head]
|
|
1776
|
-
// do not share the same Subst/Concat references — relativizeResObj
|
|
1777
|
-
// walks BOTH `fields` and `priorValues` and mutates Subst.segments
|
|
1778
|
-
// in place, so a shared reference would get its prefix applied
|
|
1779
|
-
// twice (resulting in e.g. `${outer.outer.base}` instead of
|
|
1780
|
-
// `${outer.base}`). Codex review on PR #131.
|
|
1781
|
-
existing: folded !== void 0 ? cloneResolverValue(folded) : existing2,
|
|
1782
|
-
elem: this.astToResolverValue(field.value, childPrefix)
|
|
1783
|
-
});
|
|
1873
|
+
const synthetic = this.desugarAppend(field, childPrefix);
|
|
1874
|
+
this.applyField(obj, synthetic, pathPrefix);
|
|
1784
1875
|
return;
|
|
1785
1876
|
}
|
|
1786
1877
|
const existing = obj.fields.get(head);
|
|
1787
1878
|
const newVal = this.astToResolverValue(field.value, childPrefix);
|
|
1879
|
+
if (!containsSelfRef(newVal, fullKey)) {
|
|
1880
|
+
obj.resetKeys.add(head);
|
|
1881
|
+
}
|
|
1788
1882
|
if (existing !== void 0) {
|
|
1789
|
-
const exFolded = foldNestedSelfRefs(existing, childPrefix);
|
|
1790
1883
|
const oldPrior = obj.priorValues.get(head);
|
|
1791
|
-
const
|
|
1884
|
+
const priorInput = isResObj(existing) ? foldNestedSelfRefs(existing, childPrefix) : existing;
|
|
1885
|
+
const prior = foldOrSkipPrior(priorInput, fullKey, oldPrior);
|
|
1792
1886
|
if (prior !== void 0) obj.priorValues.set(head, prior);
|
|
1793
1887
|
}
|
|
1794
1888
|
if (existing !== void 0 && isResObj(existing) && isResObj(newVal)) {
|
|
@@ -1826,23 +1920,19 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1826
1920
|
const childPrefix = [...pathPrefix, head];
|
|
1827
1921
|
const fullKey = stringSegmentsToKey(childPrefix);
|
|
1828
1922
|
if (field.append) {
|
|
1829
|
-
const
|
|
1830
|
-
|
|
1831
|
-
const folded = foldOrSkipPrior(existing2, fullKey, oldPrior);
|
|
1832
|
-
if (folded !== void 0) obj.priorValues.set(head, folded);
|
|
1833
|
-
obj.fields.set(head, {
|
|
1834
|
-
_kind: "append-placeholder",
|
|
1835
|
-
existing: folded !== void 0 ? cloneResolverValue(folded) : existing2,
|
|
1836
|
-
elem: await this.astToResolverValueAsync(field.value, childPrefix)
|
|
1837
|
-
});
|
|
1923
|
+
const synthetic = this.desugarAppend(field, childPrefix);
|
|
1924
|
+
await this.applyFieldAsync(obj, synthetic, pathPrefix);
|
|
1838
1925
|
return;
|
|
1839
1926
|
}
|
|
1840
1927
|
const existing = obj.fields.get(head);
|
|
1841
1928
|
const newVal = await this.astToResolverValueAsync(field.value, childPrefix);
|
|
1929
|
+
if (!containsSelfRef(newVal, fullKey)) {
|
|
1930
|
+
obj.resetKeys.add(head);
|
|
1931
|
+
}
|
|
1842
1932
|
if (existing !== void 0) {
|
|
1843
|
-
const exFolded = foldNestedSelfRefs(existing, childPrefix);
|
|
1844
1933
|
const oldPrior = obj.priorValues.get(head);
|
|
1845
|
-
const
|
|
1934
|
+
const priorInput = isResObj(existing) ? foldNestedSelfRefs(existing, childPrefix) : existing;
|
|
1935
|
+
const prior = foldOrSkipPrior(priorInput, fullKey, oldPrior);
|
|
1846
1936
|
if (prior !== void 0) obj.priorValues.set(head, prior);
|
|
1847
1937
|
}
|
|
1848
1938
|
if (existing !== void 0 && isResObj(existing) && isResObj(newVal)) {
|
|
@@ -1851,6 +1941,21 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1851
1941
|
}
|
|
1852
1942
|
obj.fields.set(head, newVal);
|
|
1853
1943
|
}
|
|
1944
|
+
/** Builds the `key = ${?fullkey} [value]` field that `key += value` desugars
|
|
1945
|
+
* to (S13b.2, HOCON.md L732). `childPrefix` is the field's fully-qualified
|
|
1946
|
+
* path (pathPrefix + key), so a nested `srv { items += x }` references
|
|
1947
|
+
* `${?srv.items}`; include relativization rewrites it under a mount prefix.
|
|
1948
|
+
* `field.key` is already single-segment here (multi-segment keys are split
|
|
1949
|
+
* into nested objects upstream). Returns a NEW AstField (append=false);
|
|
1950
|
+
* positions inherit from the original field so resolve-time errors (the
|
|
1951
|
+
* S13b.2 non-array check, now via the scalar+array concat) keep a location. */
|
|
1952
|
+
desugarAppend(field, childPrefix) {
|
|
1953
|
+
const segments = childPrefix.map((text) => ({ text, line: field.pos.line, col: field.pos.col }));
|
|
1954
|
+
const subst = { kind: "subst", segments, optional: true, listSuffix: false, pos: field.pos };
|
|
1955
|
+
const elemArray = { kind: "array", items: [field.value], pos: field.pos };
|
|
1956
|
+
const synthetic = { kind: "concat", nodes: [subst, elemArray], pos: field.pos };
|
|
1957
|
+
return { key: field.key, value: synthetic, append: false, pos: field.pos };
|
|
1958
|
+
}
|
|
1854
1959
|
astToResolverValue(ast, pathPrefix) {
|
|
1855
1960
|
switch (ast.kind) {
|
|
1856
1961
|
case "scalar": {
|
|
@@ -1865,7 +1970,7 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1865
1970
|
return inner;
|
|
1866
1971
|
}
|
|
1867
1972
|
case "subst":
|
|
1868
|
-
return { _kind: "subst-placeholder", segments: ast.segments, optional: ast.optional, listSuffix: ast.listSuffix, line: ast.pos.line, col: ast.pos.col, prefixLen: 0 };
|
|
1973
|
+
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 };
|
|
1869
1974
|
case "concat":
|
|
1870
1975
|
return { _kind: "concat-placeholder", nodes: ast.nodes.map((n) => this.astToResolverValue(n, pathPrefix)), line: ast.pos.line, col: ast.pos.col };
|
|
1871
1976
|
case "include":
|
|
@@ -1889,7 +1994,7 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1889
1994
|
case "object":
|
|
1890
1995
|
return await this.buildAsync(ast, pathPrefix);
|
|
1891
1996
|
case "subst":
|
|
1892
|
-
return { _kind: "subst-placeholder", segments: ast.segments, optional: ast.optional, listSuffix: ast.listSuffix, line: ast.pos.line, col: ast.pos.col, prefixLen: 0 };
|
|
1997
|
+
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 };
|
|
1893
1998
|
case "concat": {
|
|
1894
1999
|
const nodes = [];
|
|
1895
2000
|
for (const n of ast.nodes) {
|
|
@@ -1915,11 +2020,6 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1915
2020
|
}
|
|
1916
2021
|
return;
|
|
1917
2022
|
}
|
|
1918
|
-
if (isAppend(val)) {
|
|
1919
|
-
this.relativizeSubstPaths(val.existing, prefixSegments);
|
|
1920
|
-
this.relativizeSubstPaths(val.elem, prefixSegments);
|
|
1921
|
-
return;
|
|
1922
|
-
}
|
|
1923
2023
|
if (isResObj(val)) {
|
|
1924
2024
|
this.relativizeResObj(val, prefixSegments);
|
|
1925
2025
|
return;
|
|
@@ -2007,6 +2107,8 @@ var SubstitutionResolver = class {
|
|
|
2007
2107
|
const result = /* @__PURE__ */ new Map();
|
|
2008
2108
|
for (const [key, val] of obj.fields) {
|
|
2009
2109
|
this.resolvingFieldPath.push(key);
|
|
2110
|
+
const fullCacheKey = stringSegmentsToKey(this.resolvingFieldPath);
|
|
2111
|
+
this.cache.delete(fullCacheKey);
|
|
2010
2112
|
let resolved;
|
|
2011
2113
|
try {
|
|
2012
2114
|
resolved = this.resolveVal(val, obj);
|
|
@@ -2019,28 +2121,42 @@ var SubstitutionResolver = class {
|
|
|
2019
2121
|
if (prior !== void 0) {
|
|
2020
2122
|
const priorResolved = this.resolveVal(prior, obj);
|
|
2021
2123
|
if (priorResolved !== void 0 && priorResolved.kind === "object") {
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
priorResolved,
|
|
2026
|
-
resolved
|
|
2027
|
-
)
|
|
2124
|
+
const finalValue = deepMergeHoconValues(
|
|
2125
|
+
priorResolved,
|
|
2126
|
+
resolved
|
|
2028
2127
|
);
|
|
2128
|
+
result.set(key, finalValue);
|
|
2129
|
+
this.cache.set(fullCacheKey, finalValue);
|
|
2130
|
+
this.cacheDescendants(fullCacheKey, finalValue);
|
|
2029
2131
|
continue;
|
|
2030
2132
|
}
|
|
2031
2133
|
}
|
|
2032
2134
|
}
|
|
2033
2135
|
result.set(key, resolved);
|
|
2136
|
+
this.cache.set(fullCacheKey, resolved);
|
|
2137
|
+
this.cacheDescendants(fullCacheKey, resolved);
|
|
2034
2138
|
} else {
|
|
2035
2139
|
const prior = obj.priorValues.get(key);
|
|
2036
2140
|
if (prior !== void 0) {
|
|
2037
2141
|
const priorResolved = this.resolveVal(prior, obj);
|
|
2038
|
-
if (priorResolved !== void 0)
|
|
2142
|
+
if (priorResolved !== void 0) {
|
|
2143
|
+
result.set(key, priorResolved);
|
|
2144
|
+
this.cache.set(fullCacheKey, priorResolved);
|
|
2145
|
+
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
2146
|
+
}
|
|
2039
2147
|
}
|
|
2040
2148
|
}
|
|
2041
2149
|
}
|
|
2042
2150
|
return { kind: "object", fields: result };
|
|
2043
2151
|
}
|
|
2152
|
+
cacheDescendants(prefix, value) {
|
|
2153
|
+
if (value.kind !== "object") return;
|
|
2154
|
+
for (const [key, child] of value.fields) {
|
|
2155
|
+
const childKey = `${prefix}.${stringSegmentsToKey([key])}`;
|
|
2156
|
+
this.cache.set(childKey, child);
|
|
2157
|
+
this.cacheDescendants(childKey, child);
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2044
2160
|
resolveVal(v, scope) {
|
|
2045
2161
|
if (isSubst(v)) return this.resolveSubst(v, scope);
|
|
2046
2162
|
if (isConcat(v)) {
|
|
@@ -2052,7 +2168,6 @@ var SubstitutionResolver = class {
|
|
|
2052
2168
|
this.resolvingConcats.delete(v);
|
|
2053
2169
|
}
|
|
2054
2170
|
}
|
|
2055
|
-
if (isAppend(v)) return this.resolveAppend(v, scope);
|
|
2056
2171
|
if (isResObj(v)) return this.resolveResObj(v);
|
|
2057
2172
|
const hv = v;
|
|
2058
2173
|
if (hv.kind === "array") {
|
|
@@ -2066,6 +2181,7 @@ var SubstitutionResolver = class {
|
|
|
2066
2181
|
return hv;
|
|
2067
2182
|
}
|
|
2068
2183
|
resolveSubst(s, scope) {
|
|
2184
|
+
if (s.knownAbsent) return void 0;
|
|
2069
2185
|
const key = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
2070
2186
|
if (this.cache.has(key)) return this.cache.get(key);
|
|
2071
2187
|
if (this.resolving.has(key)) {
|
|
@@ -2158,6 +2274,28 @@ var SubstitutionResolver = class {
|
|
|
2158
2274
|
if (result !== void 0) this.cache.set(key, result);
|
|
2159
2275
|
return result;
|
|
2160
2276
|
}
|
|
2277
|
+
if (s.prefixLen > 0 && s.segments.length > s.prefixLen) {
|
|
2278
|
+
const originalSegments = s.segments.slice(s.prefixLen);
|
|
2279
|
+
const fallbackFound = lookupPath(this.root, originalSegments);
|
|
2280
|
+
if (fallbackFound !== void 0) {
|
|
2281
|
+
let result = this.resolveVal(fallbackFound, scope);
|
|
2282
|
+
if (originalSegments.length === 1 && result !== void 0 && result.kind === "object") {
|
|
2283
|
+
const rootSeg = originalSegments[0]?.text ?? "";
|
|
2284
|
+
const prior = this.root.priorValues.get(rootSeg);
|
|
2285
|
+
if (prior !== void 0) {
|
|
2286
|
+
const priorResolved = this.resolveVal(prior, scope);
|
|
2287
|
+
if (priorResolved !== void 0 && priorResolved.kind === "object") {
|
|
2288
|
+
result = deepMergeHoconValues(
|
|
2289
|
+
priorResolved,
|
|
2290
|
+
result
|
|
2291
|
+
);
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
if (result !== void 0) this.cache.set(key, result);
|
|
2296
|
+
return result;
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2161
2299
|
if (s.listSuffix && this.opts.useSystemEnvironment !== false) {
|
|
2162
2300
|
const result = this.resolveEnvList(s);
|
|
2163
2301
|
if (result !== void 0) {
|
|
@@ -2314,38 +2452,6 @@ var SubstitutionResolver = class {
|
|
|
2314
2452
|
}
|
|
2315
2453
|
return folded;
|
|
2316
2454
|
}
|
|
2317
|
-
resolveAppend(a, scope) {
|
|
2318
|
-
const existing = this.resolveVal(a.existing, scope) ?? { kind: "array", items: [] };
|
|
2319
|
-
if (this.opts.allowUnresolved && (isSubst(existing) || isConcat(existing) || isAppend(existing))) {
|
|
2320
|
-
return a;
|
|
2321
|
-
}
|
|
2322
|
-
const elem = this.resolveVal(a.elem, scope);
|
|
2323
|
-
let priorItems;
|
|
2324
|
-
if (existing.kind === "array") {
|
|
2325
|
-
priorItems = existing.items;
|
|
2326
|
-
} else if (existing.kind === "object") {
|
|
2327
|
-
const converted = numericObjectToArray(existing);
|
|
2328
|
-
if (converted === null) {
|
|
2329
|
-
throw new ResolveError(
|
|
2330
|
-
`'+=' on non-array value: prior value is object with non-numeric keys (spec L732)`,
|
|
2331
|
-
"",
|
|
2332
|
-
0,
|
|
2333
|
-
0
|
|
2334
|
-
);
|
|
2335
|
-
}
|
|
2336
|
-
priorItems = converted;
|
|
2337
|
-
} else {
|
|
2338
|
-
throw new ResolveError(
|
|
2339
|
-
`'+=' on non-array value: prior value is ${existing.kind} (spec L732)`,
|
|
2340
|
-
"",
|
|
2341
|
-
0,
|
|
2342
|
-
0
|
|
2343
|
-
);
|
|
2344
|
-
}
|
|
2345
|
-
const items = [...priorItems];
|
|
2346
|
-
if (elem !== void 0) items.push(elem);
|
|
2347
|
-
return { kind: "array", items };
|
|
2348
|
-
}
|
|
2349
2455
|
};
|
|
2350
2456
|
|
|
2351
2457
|
// src/internal/resolver/resolver.ts
|
|
@@ -2363,7 +2469,7 @@ function containsPlaceholders(tree) {
|
|
|
2363
2469
|
}
|
|
2364
2470
|
function valContainsPlaceholders(v) {
|
|
2365
2471
|
const rv = v;
|
|
2366
|
-
if (isSubst(rv) || isConcat(rv)
|
|
2472
|
+
if (isSubst(rv) || isConcat(rv)) return true;
|
|
2367
2473
|
if (isResObj(rv)) return containsPlaceholders(rv);
|
|
2368
2474
|
const hv = v;
|
|
2369
2475
|
if (hv?.kind === "array") {
|
|
@@ -2374,7 +2480,7 @@ function valContainsPlaceholders(v) {
|
|
|
2374
2480
|
function buildPartialHoconFromResObj(tree) {
|
|
2375
2481
|
const fields = /* @__PURE__ */ new Map();
|
|
2376
2482
|
for (const [k, v] of tree.fields) {
|
|
2377
|
-
if (!isSubst(v) && !isConcat(v)
|
|
2483
|
+
if (!isSubst(v) && !isConcat(v)) {
|
|
2378
2484
|
if (isResObj(v)) {
|
|
2379
2485
|
fields.set(k, buildPartialHoconFromResObj(v));
|
|
2380
2486
|
} else {
|
|
@@ -2767,7 +2873,7 @@ function hoconToJs(v) {
|
|
|
2767
2873
|
function resObjToKeyShape(tree) {
|
|
2768
2874
|
const fields = /* @__PURE__ */ new Map();
|
|
2769
2875
|
for (const [k, v] of tree.fields) {
|
|
2770
|
-
if (isSubst(v) || isConcat(v)
|
|
2876
|
+
if (isSubst(v) || isConcat(v)) {
|
|
2771
2877
|
fields.set(k, { kind: "scalar", raw: "", valueType: "null" });
|
|
2772
2878
|
} else if (isResObj(v)) {
|
|
2773
2879
|
fields.set(k, resObjToKeyShape(v));
|
|
@@ -2781,7 +2887,7 @@ function stripPlaceholderFields(v) {
|
|
|
2781
2887
|
const fields = /* @__PURE__ */ new Map();
|
|
2782
2888
|
let hadPlaceholders = false;
|
|
2783
2889
|
for (const [k, val] of v.fields) {
|
|
2784
|
-
if (val._kind === "subst-placeholder" || val._kind === "concat-placeholder"
|
|
2890
|
+
if (val._kind === "subst-placeholder" || val._kind === "concat-placeholder") {
|
|
2785
2891
|
hadPlaceholders = true;
|
|
2786
2892
|
} else if (val.kind === "object") {
|
|
2787
2893
|
const inner = stripPlaceholderFields(val);
|