@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/zod.js
CHANGED
|
@@ -241,55 +241,6 @@ var NotResolvedError = class extends ConfigError {
|
|
|
241
241
|
}
|
|
242
242
|
};
|
|
243
243
|
|
|
244
|
-
// src/internal/resolver/types.ts
|
|
245
|
-
var separatorValues = /* @__PURE__ */ new WeakSet();
|
|
246
|
-
function isSubst(v) {
|
|
247
|
-
return v._kind === "subst-placeholder";
|
|
248
|
-
}
|
|
249
|
-
function isConcat(v) {
|
|
250
|
-
return v._kind === "concat-placeholder";
|
|
251
|
-
}
|
|
252
|
-
function isAppend(v) {
|
|
253
|
-
return v._kind === "append-placeholder";
|
|
254
|
-
}
|
|
255
|
-
function isResObj(v) {
|
|
256
|
-
return v._kind === "res-obj";
|
|
257
|
-
}
|
|
258
|
-
function makeResObj() {
|
|
259
|
-
return { _kind: "res-obj", fields: /* @__PURE__ */ new Map(), priorValues: /* @__PURE__ */ new Map() };
|
|
260
|
-
}
|
|
261
|
-
function mergeUnresolved(receiver, fallback) {
|
|
262
|
-
const result = makeResObj();
|
|
263
|
-
for (const [k, v] of fallback.fields) {
|
|
264
|
-
result.fields.set(k, v);
|
|
265
|
-
}
|
|
266
|
-
for (const [k, v] of fallback.priorValues) {
|
|
267
|
-
result.priorValues.set(k, v);
|
|
268
|
-
}
|
|
269
|
-
for (const [k, rv] of receiver.fields) {
|
|
270
|
-
const existing = result.fields.get(k);
|
|
271
|
-
if (existing !== void 0) {
|
|
272
|
-
const recPrior = receiver.priorValues.get(k);
|
|
273
|
-
if (recPrior !== void 0 && !isResObj(recPrior)) {
|
|
274
|
-
result.fields.set(k, rv);
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
277
|
-
if (isResObj(rv) && isResObj(existing)) {
|
|
278
|
-
result.fields.set(k, mergeUnresolved(rv, existing));
|
|
279
|
-
continue;
|
|
280
|
-
}
|
|
281
|
-
result.priorValues.set(k, existing);
|
|
282
|
-
}
|
|
283
|
-
result.fields.set(k, rv);
|
|
284
|
-
}
|
|
285
|
-
for (const [k, v] of receiver.priorValues) {
|
|
286
|
-
if (receiver.fields.has(k)) {
|
|
287
|
-
result.priorValues.set(k, v);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
return result;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
244
|
// src/internal/resolver/fold-self-ref.ts
|
|
294
245
|
function substFullKey(s) {
|
|
295
246
|
return stringSegmentsToKey(s.segments.map((seg) => seg.text));
|
|
@@ -303,11 +254,8 @@ function stringSegmentsToKey(segments) {
|
|
|
303
254
|
}).join(".");
|
|
304
255
|
}
|
|
305
256
|
function containsSelfRef(v, fullKey) {
|
|
306
|
-
if (isSubst(v)) return substFullKey(v) === fullKey;
|
|
257
|
+
if (isSubst(v)) return !v.knownAbsent && substFullKey(v) === fullKey;
|
|
307
258
|
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
259
|
if (isResObj(v)) {
|
|
312
260
|
for (const f of v.fields.values()) {
|
|
313
261
|
if (containsSelfRef(f, fullKey)) return true;
|
|
@@ -338,19 +286,12 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
338
286
|
col: v.col
|
|
339
287
|
};
|
|
340
288
|
}
|
|
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
289
|
if (isResObj(v)) {
|
|
349
290
|
const newFields = /* @__PURE__ */ new Map();
|
|
350
291
|
for (const [k, val] of v.fields) {
|
|
351
292
|
newFields.set(k, foldSelfRef(val, fullKey, replacement));
|
|
352
293
|
}
|
|
353
|
-
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues) };
|
|
294
|
+
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
354
295
|
}
|
|
355
296
|
const hv = v;
|
|
356
297
|
if (hv.kind === "array") {
|
|
@@ -368,17 +309,106 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
368
309
|
}
|
|
369
310
|
return v;
|
|
370
311
|
}
|
|
312
|
+
function foldKnownAbsentSelfRef(v, fullKey, replacement) {
|
|
313
|
+
if (isSubst(v)) {
|
|
314
|
+
return v.knownAbsent && substFullKey(v) === fullKey ? replacement : v;
|
|
315
|
+
}
|
|
316
|
+
if (isConcat(v)) {
|
|
317
|
+
return {
|
|
318
|
+
_kind: "concat-placeholder",
|
|
319
|
+
nodes: v.nodes.map((n) => foldKnownAbsentSelfRef(n, fullKey, replacement)),
|
|
320
|
+
line: v.line,
|
|
321
|
+
col: v.col
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
if (isResObj(v)) {
|
|
325
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
326
|
+
for (const [k, val] of v.fields) {
|
|
327
|
+
newFields.set(k, foldKnownAbsentSelfRef(val, fullKey, replacement));
|
|
328
|
+
}
|
|
329
|
+
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
330
|
+
}
|
|
331
|
+
const hv = v;
|
|
332
|
+
if (hv.kind === "array") {
|
|
333
|
+
return {
|
|
334
|
+
kind: "array",
|
|
335
|
+
items: hv.items.map((item) => foldKnownAbsentSelfRef(item, fullKey, replacement))
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
if (hv.kind === "object") {
|
|
339
|
+
const newFields = /* @__PURE__ */ new Map();
|
|
340
|
+
for (const [k, val] of hv.fields) {
|
|
341
|
+
newFields.set(k, foldKnownAbsentSelfRef(val, fullKey, replacement));
|
|
342
|
+
}
|
|
343
|
+
return { kind: "object", fields: newFields };
|
|
344
|
+
}
|
|
345
|
+
return v;
|
|
346
|
+
}
|
|
371
347
|
function foldOrSkipPrior(prior, fullKey, old) {
|
|
372
348
|
if (!containsSelfRef(prior, fullKey)) return cloneResolverValue(prior);
|
|
373
|
-
if (old === void 0) return
|
|
349
|
+
if (old === void 0) return foldOptionalSelfRefAbsent(prior, fullKey);
|
|
374
350
|
return foldSelfRef(prior, fullKey, old);
|
|
375
351
|
}
|
|
352
|
+
function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
353
|
+
if (isSubst(v) && substFullKey(v) === fullKey) {
|
|
354
|
+
if (!v.optional) return void 0;
|
|
355
|
+
return {
|
|
356
|
+
_kind: "subst-placeholder",
|
|
357
|
+
segments: v.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
|
|
358
|
+
optional: v.optional,
|
|
359
|
+
knownAbsent: true,
|
|
360
|
+
listSuffix: v.listSuffix,
|
|
361
|
+
line: v.line,
|
|
362
|
+
col: v.col,
|
|
363
|
+
prefixLen: v.prefixLen
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
if (isConcat(v)) {
|
|
367
|
+
const nodes = [];
|
|
368
|
+
for (const node of v.nodes) {
|
|
369
|
+
const folded = foldOptionalSelfRefAbsent(node, fullKey);
|
|
370
|
+
if (folded === void 0) return void 0;
|
|
371
|
+
nodes.push(folded);
|
|
372
|
+
}
|
|
373
|
+
return { _kind: "concat-placeholder", nodes, line: v.line, col: v.col };
|
|
374
|
+
}
|
|
375
|
+
if (isResObj(v)) {
|
|
376
|
+
const fields = /* @__PURE__ */ new Map();
|
|
377
|
+
for (const [key, value] of v.fields) {
|
|
378
|
+
const folded = foldOptionalSelfRefAbsent(value, fullKey);
|
|
379
|
+
if (folded === void 0) return void 0;
|
|
380
|
+
fields.set(key, folded);
|
|
381
|
+
}
|
|
382
|
+
return { _kind: "res-obj", fields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
383
|
+
}
|
|
384
|
+
const hv = v;
|
|
385
|
+
if (hv.kind === "array") {
|
|
386
|
+
const items = [];
|
|
387
|
+
for (const item of hv.items) {
|
|
388
|
+
const folded = foldOptionalSelfRefAbsent(item, fullKey);
|
|
389
|
+
if (folded === void 0) return void 0;
|
|
390
|
+
items.push(folded);
|
|
391
|
+
}
|
|
392
|
+
return { kind: "array", items };
|
|
393
|
+
}
|
|
394
|
+
if (hv.kind === "object") {
|
|
395
|
+
const fields = /* @__PURE__ */ new Map();
|
|
396
|
+
for (const [key, value] of hv.fields) {
|
|
397
|
+
const folded = foldOptionalSelfRefAbsent(value, fullKey);
|
|
398
|
+
if (folded === void 0) return void 0;
|
|
399
|
+
fields.set(key, folded);
|
|
400
|
+
}
|
|
401
|
+
return { kind: "object", fields };
|
|
402
|
+
}
|
|
403
|
+
return cloneResolverValue(v);
|
|
404
|
+
}
|
|
376
405
|
function cloneResolverValue(v) {
|
|
377
406
|
if (isSubst(v)) {
|
|
378
407
|
return {
|
|
379
408
|
_kind: "subst-placeholder",
|
|
380
409
|
segments: v.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
|
|
381
410
|
optional: v.optional,
|
|
411
|
+
knownAbsent: v.knownAbsent,
|
|
382
412
|
listSuffix: v.listSuffix,
|
|
383
413
|
line: v.line,
|
|
384
414
|
col: v.col,
|
|
@@ -398,14 +428,7 @@ function cloneResolverValue(v) {
|
|
|
398
428
|
for (const [k, val] of v.fields) newFields.set(k, cloneResolverValue(val));
|
|
399
429
|
const newPriors = /* @__PURE__ */ new Map();
|
|
400
430
|
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
|
-
};
|
|
431
|
+
return { _kind: "res-obj", fields: newFields, priorValues: newPriors, resetKeys: new Set(v.resetKeys) };
|
|
409
432
|
}
|
|
410
433
|
const hv = v;
|
|
411
434
|
if (hv.kind === "array") {
|
|
@@ -440,14 +463,11 @@ function foldNestedSelfRefs(v, pathPrefix) {
|
|
|
440
463
|
}
|
|
441
464
|
newFields.set(k, finalVal);
|
|
442
465
|
}
|
|
443
|
-
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues) };
|
|
466
|
+
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
444
467
|
}
|
|
445
468
|
function containsSubstByPath(v, target) {
|
|
446
|
-
if (isSubst(v)) return segmentsTextEqual(v.segments, target);
|
|
469
|
+
if (isSubst(v)) return !v.knownAbsent && segmentsTextEqual(v.segments, target);
|
|
447
470
|
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
471
|
if (isResObj(v)) {
|
|
452
472
|
for (const f of v.fields.values()) {
|
|
453
473
|
if (containsSubstByPath(f, target)) return true;
|
|
@@ -476,6 +496,53 @@ function segmentsTextEqual(a, b) {
|
|
|
476
496
|
return true;
|
|
477
497
|
}
|
|
478
498
|
|
|
499
|
+
// src/internal/resolver/types.ts
|
|
500
|
+
var separatorValues = /* @__PURE__ */ new WeakSet();
|
|
501
|
+
function isSubst(v) {
|
|
502
|
+
return v._kind === "subst-placeholder";
|
|
503
|
+
}
|
|
504
|
+
function isConcat(v) {
|
|
505
|
+
return v._kind === "concat-placeholder";
|
|
506
|
+
}
|
|
507
|
+
function isResObj(v) {
|
|
508
|
+
return v._kind === "res-obj";
|
|
509
|
+
}
|
|
510
|
+
function makeResObj() {
|
|
511
|
+
return { _kind: "res-obj", fields: /* @__PURE__ */ new Map(), priorValues: /* @__PURE__ */ new Map(), resetKeys: /* @__PURE__ */ new Set() };
|
|
512
|
+
}
|
|
513
|
+
function mergeUnresolved(receiver, fallback) {
|
|
514
|
+
const result = makeResObj();
|
|
515
|
+
for (const [k, v] of fallback.fields) {
|
|
516
|
+
result.fields.set(k, v);
|
|
517
|
+
}
|
|
518
|
+
for (const [k, v] of fallback.priorValues) {
|
|
519
|
+
result.priorValues.set(k, v);
|
|
520
|
+
}
|
|
521
|
+
for (const [k, rv] of receiver.fields) {
|
|
522
|
+
const existing = result.fields.get(k);
|
|
523
|
+
if (existing !== void 0) {
|
|
524
|
+
const recPrior = receiver.priorValues.get(k);
|
|
525
|
+
if (recPrior !== void 0 && !isResObj(recPrior)) {
|
|
526
|
+
result.fields.set(k, rv);
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
if (isResObj(rv) && isResObj(existing)) {
|
|
530
|
+
result.fields.set(k, mergeUnresolved(rv, existing));
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
const foldedPrior = foldOrSkipPrior(existing, k, void 0);
|
|
534
|
+
if (foldedPrior !== void 0) result.priorValues.set(k, foldedPrior);
|
|
535
|
+
}
|
|
536
|
+
result.fields.set(k, rv);
|
|
537
|
+
}
|
|
538
|
+
for (const [k, v] of receiver.priorValues) {
|
|
539
|
+
if (receiver.fields.has(k)) {
|
|
540
|
+
result.priorValues.set(k, v);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return result;
|
|
544
|
+
}
|
|
545
|
+
|
|
479
546
|
// src/internal/resolver/utils.ts
|
|
480
547
|
function segmentsToKey(segments) {
|
|
481
548
|
return segments.map((s) => {
|
|
@@ -529,9 +596,19 @@ function deepMergeResObjInto(dst, src, pathPrefix = []) {
|
|
|
529
596
|
deepMergeResObjInto(dstVal, srcVal, childPrefix);
|
|
530
597
|
} else {
|
|
531
598
|
if (dstVal !== void 0) {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
599
|
+
if (src.resetKeys.has(k)) {
|
|
600
|
+
dst.priorValues.delete(k);
|
|
601
|
+
} else {
|
|
602
|
+
const dstFolded = foldOrSkipPrior(dstVal, fullKey, dst.priorValues.get(k));
|
|
603
|
+
if (dstFolded !== void 0) {
|
|
604
|
+
const srcPrior = src.priorValues.get(k);
|
|
605
|
+
if (srcPrior !== void 0) {
|
|
606
|
+
dst.priorValues.set(k, foldKnownAbsentSelfRef(srcPrior, fullKey, dstFolded));
|
|
607
|
+
} else {
|
|
608
|
+
dst.priorValues.set(k, dstFolded);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
535
612
|
}
|
|
536
613
|
dst.fields.set(k, srcVal);
|
|
537
614
|
}
|
|
@@ -541,6 +618,7 @@ function deepMergeResObjInto(dst, src, pathPrefix = []) {
|
|
|
541
618
|
dst.priorValues.set(k, srcPrior);
|
|
542
619
|
}
|
|
543
620
|
}
|
|
621
|
+
for (const k of src.resetKeys) dst.resetKeys.add(k);
|
|
544
622
|
}
|
|
545
623
|
function hoconValueToResObj(hv) {
|
|
546
624
|
const obj = makeResObj();
|
|
@@ -610,6 +688,11 @@ var Lexer = class {
|
|
|
610
688
|
this.line = 1;
|
|
611
689
|
this.col = 1;
|
|
612
690
|
this.hadSpace = false;
|
|
691
|
+
// Accumulates literal whitespace chars consumed between tokens. Reset on every
|
|
692
|
+
// token push. Used so the parser can preserve path-expression whitespace
|
|
693
|
+
// (xx.hocon#42, E13) — e.g. tab vs space adjacent to dots in key paths.
|
|
694
|
+
// Comment text is NOT accumulated; only the actual WS chars.
|
|
695
|
+
this.whitespaceBuffer = "";
|
|
613
696
|
this.tokens = [];
|
|
614
697
|
if (input.charCodeAt(0) === 65279) this.input = input.slice(1);
|
|
615
698
|
}
|
|
@@ -625,6 +708,7 @@ var Lexer = class {
|
|
|
625
708
|
continue;
|
|
626
709
|
}
|
|
627
710
|
if (isHoconWhitespace(ch)) {
|
|
711
|
+
this.whitespaceBuffer += ch;
|
|
628
712
|
this.advance();
|
|
629
713
|
this.hadSpace = true;
|
|
630
714
|
continue;
|
|
@@ -716,7 +800,7 @@ var Lexer = class {
|
|
|
716
800
|
}
|
|
717
801
|
throw new ParseError(`unexpected character: ${JSON.stringify(ch)}`, sl, sc);
|
|
718
802
|
}
|
|
719
|
-
this.tokens.push({ kind: "eof", value: "", line: this.line, col: this.col, isQuoted: false, precedingSpace: false });
|
|
803
|
+
this.tokens.push({ kind: "eof", value: "", line: this.line, col: this.col, isQuoted: false, precedingSpace: false, precedingWhitespace: "" });
|
|
720
804
|
return this.tokens;
|
|
721
805
|
}
|
|
722
806
|
peek(offset = 0) {
|
|
@@ -733,12 +817,14 @@ var Lexer = class {
|
|
|
733
817
|
return ch;
|
|
734
818
|
}
|
|
735
819
|
push(kind, value, l, c, isQuoted = false) {
|
|
736
|
-
this.tokens.push({ kind, value, line: l, col: c, isQuoted, precedingSpace: this.hadSpace });
|
|
820
|
+
this.tokens.push({ kind, value, line: l, col: c, isQuoted, precedingSpace: this.hadSpace, precedingWhitespace: this.whitespaceBuffer });
|
|
737
821
|
this.hadSpace = false;
|
|
822
|
+
this.whitespaceBuffer = "";
|
|
738
823
|
}
|
|
739
824
|
pushSubst(payload, value, l, c) {
|
|
740
|
-
this.tokens.push({ kind: "subst", value, line: l, col: c, isQuoted: false, precedingSpace: this.hadSpace, subst: payload });
|
|
825
|
+
this.tokens.push({ kind: "subst", value, line: l, col: c, isQuoted: false, precedingSpace: this.hadSpace, precedingWhitespace: this.whitespaceBuffer, subst: payload });
|
|
741
826
|
this.hadSpace = false;
|
|
827
|
+
this.whitespaceBuffer = "";
|
|
742
828
|
}
|
|
743
829
|
/**
|
|
744
830
|
* Read body of a quoted string. Opening `"` must already be consumed.
|
|
@@ -984,7 +1070,7 @@ function isUnquotedContinue(ch, nextFn) {
|
|
|
984
1070
|
}
|
|
985
1071
|
|
|
986
1072
|
// src/internal/parser/parser.ts
|
|
987
|
-
var EOF_TOKEN = { kind: "eof", value: "", line: 0, col: 0, isQuoted: false, precedingSpace: false, subst: void 0 };
|
|
1073
|
+
var EOF_TOKEN = { kind: "eof", value: "", line: 0, col: 0, isQuoted: false, precedingSpace: false, precedingWhitespace: "", subst: void 0 };
|
|
988
1074
|
var Parser = class {
|
|
989
1075
|
constructor(tokens) {
|
|
990
1076
|
this.tokens = tokens;
|
|
@@ -1097,13 +1183,17 @@ var Parser = class {
|
|
|
1097
1183
|
let trailingDot = false;
|
|
1098
1184
|
let firstWasQuoted = false;
|
|
1099
1185
|
let spaceConcat = false;
|
|
1186
|
+
let postDotPrefix = "";
|
|
1100
1187
|
while (true) {
|
|
1101
1188
|
const t = this.peek();
|
|
1102
1189
|
if (t.kind === "string") {
|
|
1103
1190
|
this.advance();
|
|
1104
1191
|
if (segments.length === 0) firstWasQuoted = true;
|
|
1105
1192
|
if (spaceConcat) {
|
|
1106
|
-
segments[segments.length - 1] = `${segments[segments.length - 1]}
|
|
1193
|
+
segments[segments.length - 1] = `${segments[segments.length - 1]}${t.precedingWhitespace}${t.value}`;
|
|
1194
|
+
} else if (postDotPrefix !== "") {
|
|
1195
|
+
segments.push(`${postDotPrefix}${t.value}`);
|
|
1196
|
+
postDotPrefix = "";
|
|
1107
1197
|
} else {
|
|
1108
1198
|
segments.push(t.value);
|
|
1109
1199
|
}
|
|
@@ -1113,24 +1203,23 @@ var Parser = class {
|
|
|
1113
1203
|
const raw = t.value.startsWith(".") && segments.length > 0 && !t.precedingSpace ? t.value.slice(1) : t.value;
|
|
1114
1204
|
const parts = raw.split(".");
|
|
1115
1205
|
const filtered = parts.filter((s) => s.length > 0);
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
const after = seg.length >= 2 ? JSON.stringify(seg[1]) : "EOF";
|
|
1119
|
-
throw new ParseError(
|
|
1120
|
-
`unquoted key segment cannot begin with '-' unless followed by a digit (got '-' then ${after} in ${JSON.stringify(seg)}, HOCON.md L270-276)`,
|
|
1121
|
-
t.line,
|
|
1122
|
-
t.col
|
|
1123
|
-
);
|
|
1124
|
-
}
|
|
1125
|
-
}
|
|
1126
|
-
if (spaceConcat && filtered.length > 0) {
|
|
1206
|
+
if (spaceConcat) {
|
|
1207
|
+
segments[segments.length - 1] = `${segments[segments.length - 1]}${t.precedingWhitespace}`;
|
|
1127
1208
|
if (raw.startsWith(".")) {
|
|
1128
1209
|
segments.push(...filtered);
|
|
1129
|
-
} else {
|
|
1210
|
+
} else if (filtered.length > 0) {
|
|
1130
1211
|
const [head, ...tail] = filtered;
|
|
1131
|
-
segments[segments.length - 1] = `${segments[segments.length - 1]}
|
|
1212
|
+
segments[segments.length - 1] = `${segments[segments.length - 1]}${head}`;
|
|
1132
1213
|
segments.push(...tail);
|
|
1133
1214
|
}
|
|
1215
|
+
} else if (postDotPrefix !== "" && raw.startsWith(".")) {
|
|
1216
|
+
segments.push(postDotPrefix);
|
|
1217
|
+
postDotPrefix = "";
|
|
1218
|
+
segments.push(...filtered);
|
|
1219
|
+
} else if (postDotPrefix !== "" && filtered.length > 0) {
|
|
1220
|
+
const [head, ...tail] = filtered;
|
|
1221
|
+
segments.push(`${postDotPrefix}${head}`, ...tail);
|
|
1222
|
+
postDotPrefix = "";
|
|
1134
1223
|
} else {
|
|
1135
1224
|
segments.push(...filtered);
|
|
1136
1225
|
}
|
|
@@ -1140,11 +1229,23 @@ var Parser = class {
|
|
|
1140
1229
|
break;
|
|
1141
1230
|
}
|
|
1142
1231
|
spaceConcat = false;
|
|
1143
|
-
if (trailingDot)
|
|
1232
|
+
if (trailingDot) {
|
|
1233
|
+
const next2 = this.peek();
|
|
1234
|
+
if ((next2.kind === "unquoted" || next2.kind === "string") && next2.precedingWhitespace.length > 0) {
|
|
1235
|
+
postDotPrefix = next2.precedingWhitespace;
|
|
1236
|
+
} else {
|
|
1237
|
+
postDotPrefix = "";
|
|
1238
|
+
}
|
|
1239
|
+
continue;
|
|
1240
|
+
}
|
|
1144
1241
|
const next = this.peek();
|
|
1145
1242
|
if (next.kind === "unquoted" && next.value === "." && !next.precedingSpace) {
|
|
1146
1243
|
this.advance();
|
|
1147
1244
|
trailingDot = true;
|
|
1245
|
+
const afterDot = this.peek();
|
|
1246
|
+
if ((afterDot.kind === "unquoted" || afterDot.kind === "string") && afterDot.precedingWhitespace.length > 0) {
|
|
1247
|
+
postDotPrefix = afterDot.precedingWhitespace;
|
|
1248
|
+
}
|
|
1148
1249
|
continue;
|
|
1149
1250
|
}
|
|
1150
1251
|
if (next.kind === "unquoted" && next.value.startsWith(".") && !next.precedingSpace) {
|
|
@@ -1157,6 +1258,14 @@ var Parser = class {
|
|
|
1157
1258
|
}
|
|
1158
1259
|
break;
|
|
1159
1260
|
}
|
|
1261
|
+
if (trailingDot) {
|
|
1262
|
+
const here = this.peek();
|
|
1263
|
+
throw new ParseError(
|
|
1264
|
+
`path has a trailing period '.' \u2014 empty key segment not allowed (HOCON.md path rules)`,
|
|
1265
|
+
here.line,
|
|
1266
|
+
here.col
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1160
1269
|
return { segments, firstWasQuoted };
|
|
1161
1270
|
}
|
|
1162
1271
|
parseInclude() {
|
|
@@ -1329,7 +1438,8 @@ var Parser = class {
|
|
|
1329
1438
|
break;
|
|
1330
1439
|
}
|
|
1331
1440
|
if (hadSpace) {
|
|
1332
|
-
|
|
1441
|
+
const sep = t.precedingWhitespace.length > 0 ? t.precedingWhitespace : " ";
|
|
1442
|
+
parts.push({ kind: "scalar", raw: sep, valueType: "string", pos: { line: t.line, col: t.col }, _separator: true });
|
|
1333
1443
|
}
|
|
1334
1444
|
parts.push(node);
|
|
1335
1445
|
}
|
|
@@ -1764,35 +1874,19 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1764
1874
|
const childPrefix = [...pathPrefix, head];
|
|
1765
1875
|
const fullKey = stringSegmentsToKey(childPrefix);
|
|
1766
1876
|
if (field.append) {
|
|
1767
|
-
const
|
|
1768
|
-
|
|
1769
|
-
const folded = foldOrSkipPrior(existing2, fullKey, oldPrior);
|
|
1770
|
-
if (folded !== void 0) obj.priorValues.set(head, folded);
|
|
1771
|
-
obj.fields.set(head, {
|
|
1772
|
-
_kind: "append-placeholder",
|
|
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,
|
|
1786
|
-
elem: this.astToResolverValue(field.value, childPrefix)
|
|
1787
|
-
});
|
|
1877
|
+
const synthetic = this.desugarAppend(field, childPrefix);
|
|
1878
|
+
this.applyField(obj, synthetic, pathPrefix);
|
|
1788
1879
|
return;
|
|
1789
1880
|
}
|
|
1790
1881
|
const existing = obj.fields.get(head);
|
|
1791
1882
|
const newVal = this.astToResolverValue(field.value, childPrefix);
|
|
1883
|
+
if (!containsSelfRef(newVal, fullKey)) {
|
|
1884
|
+
obj.resetKeys.add(head);
|
|
1885
|
+
}
|
|
1792
1886
|
if (existing !== void 0) {
|
|
1793
|
-
const exFolded = foldNestedSelfRefs(existing, childPrefix);
|
|
1794
1887
|
const oldPrior = obj.priorValues.get(head);
|
|
1795
|
-
const
|
|
1888
|
+
const priorInput = isResObj(existing) ? foldNestedSelfRefs(existing, childPrefix) : existing;
|
|
1889
|
+
const prior = foldOrSkipPrior(priorInput, fullKey, oldPrior);
|
|
1796
1890
|
if (prior !== void 0) obj.priorValues.set(head, prior);
|
|
1797
1891
|
}
|
|
1798
1892
|
if (existing !== void 0 && isResObj(existing) && isResObj(newVal)) {
|
|
@@ -1830,23 +1924,19 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1830
1924
|
const childPrefix = [...pathPrefix, head];
|
|
1831
1925
|
const fullKey = stringSegmentsToKey(childPrefix);
|
|
1832
1926
|
if (field.append) {
|
|
1833
|
-
const
|
|
1834
|
-
|
|
1835
|
-
const folded = foldOrSkipPrior(existing2, fullKey, oldPrior);
|
|
1836
|
-
if (folded !== void 0) obj.priorValues.set(head, folded);
|
|
1837
|
-
obj.fields.set(head, {
|
|
1838
|
-
_kind: "append-placeholder",
|
|
1839
|
-
existing: folded !== void 0 ? cloneResolverValue(folded) : existing2,
|
|
1840
|
-
elem: await this.astToResolverValueAsync(field.value, childPrefix)
|
|
1841
|
-
});
|
|
1927
|
+
const synthetic = this.desugarAppend(field, childPrefix);
|
|
1928
|
+
await this.applyFieldAsync(obj, synthetic, pathPrefix);
|
|
1842
1929
|
return;
|
|
1843
1930
|
}
|
|
1844
1931
|
const existing = obj.fields.get(head);
|
|
1845
1932
|
const newVal = await this.astToResolverValueAsync(field.value, childPrefix);
|
|
1933
|
+
if (!containsSelfRef(newVal, fullKey)) {
|
|
1934
|
+
obj.resetKeys.add(head);
|
|
1935
|
+
}
|
|
1846
1936
|
if (existing !== void 0) {
|
|
1847
|
-
const exFolded = foldNestedSelfRefs(existing, childPrefix);
|
|
1848
1937
|
const oldPrior = obj.priorValues.get(head);
|
|
1849
|
-
const
|
|
1938
|
+
const priorInput = isResObj(existing) ? foldNestedSelfRefs(existing, childPrefix) : existing;
|
|
1939
|
+
const prior = foldOrSkipPrior(priorInput, fullKey, oldPrior);
|
|
1850
1940
|
if (prior !== void 0) obj.priorValues.set(head, prior);
|
|
1851
1941
|
}
|
|
1852
1942
|
if (existing !== void 0 && isResObj(existing) && isResObj(newVal)) {
|
|
@@ -1855,6 +1945,21 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1855
1945
|
}
|
|
1856
1946
|
obj.fields.set(head, newVal);
|
|
1857
1947
|
}
|
|
1948
|
+
/** Builds the `key = ${?fullkey} [value]` field that `key += value` desugars
|
|
1949
|
+
* to (S13b.2, HOCON.md L732). `childPrefix` is the field's fully-qualified
|
|
1950
|
+
* path (pathPrefix + key), so a nested `srv { items += x }` references
|
|
1951
|
+
* `${?srv.items}`; include relativization rewrites it under a mount prefix.
|
|
1952
|
+
* `field.key` is already single-segment here (multi-segment keys are split
|
|
1953
|
+
* into nested objects upstream). Returns a NEW AstField (append=false);
|
|
1954
|
+
* positions inherit from the original field so resolve-time errors (the
|
|
1955
|
+
* S13b.2 non-array check, now via the scalar+array concat) keep a location. */
|
|
1956
|
+
desugarAppend(field, childPrefix) {
|
|
1957
|
+
const segments = childPrefix.map((text) => ({ text, line: field.pos.line, col: field.pos.col }));
|
|
1958
|
+
const subst = { kind: "subst", segments, optional: true, listSuffix: false, pos: field.pos };
|
|
1959
|
+
const elemArray = { kind: "array", items: [field.value], pos: field.pos };
|
|
1960
|
+
const synthetic = { kind: "concat", nodes: [subst, elemArray], pos: field.pos };
|
|
1961
|
+
return { key: field.key, value: synthetic, append: false, pos: field.pos };
|
|
1962
|
+
}
|
|
1858
1963
|
astToResolverValue(ast, pathPrefix) {
|
|
1859
1964
|
switch (ast.kind) {
|
|
1860
1965
|
case "scalar": {
|
|
@@ -1869,7 +1974,7 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1869
1974
|
return inner;
|
|
1870
1975
|
}
|
|
1871
1976
|
case "subst":
|
|
1872
|
-
return { _kind: "subst-placeholder", segments: ast.segments, optional: ast.optional, listSuffix: ast.listSuffix, line: ast.pos.line, col: ast.pos.col, prefixLen: 0 };
|
|
1977
|
+
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 };
|
|
1873
1978
|
case "concat":
|
|
1874
1979
|
return { _kind: "concat-placeholder", nodes: ast.nodes.map((n) => this.astToResolverValue(n, pathPrefix)), line: ast.pos.line, col: ast.pos.col };
|
|
1875
1980
|
case "include":
|
|
@@ -1893,7 +1998,7 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1893
1998
|
case "object":
|
|
1894
1999
|
return await this.buildAsync(ast, pathPrefix);
|
|
1895
2000
|
case "subst":
|
|
1896
|
-
return { _kind: "subst-placeholder", segments: ast.segments, optional: ast.optional, listSuffix: ast.listSuffix, line: ast.pos.line, col: ast.pos.col, prefixLen: 0 };
|
|
2001
|
+
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 };
|
|
1897
2002
|
case "concat": {
|
|
1898
2003
|
const nodes = [];
|
|
1899
2004
|
for (const n of ast.nodes) {
|
|
@@ -1919,11 +2024,6 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1919
2024
|
}
|
|
1920
2025
|
return;
|
|
1921
2026
|
}
|
|
1922
|
-
if (isAppend(val)) {
|
|
1923
|
-
this.relativizeSubstPaths(val.existing, prefixSegments);
|
|
1924
|
-
this.relativizeSubstPaths(val.elem, prefixSegments);
|
|
1925
|
-
return;
|
|
1926
|
-
}
|
|
1927
2027
|
if (isResObj(val)) {
|
|
1928
2028
|
this.relativizeResObj(val, prefixSegments);
|
|
1929
2029
|
return;
|
|
@@ -2011,6 +2111,8 @@ var SubstitutionResolver = class {
|
|
|
2011
2111
|
const result = /* @__PURE__ */ new Map();
|
|
2012
2112
|
for (const [key, val] of obj.fields) {
|
|
2013
2113
|
this.resolvingFieldPath.push(key);
|
|
2114
|
+
const fullCacheKey = stringSegmentsToKey(this.resolvingFieldPath);
|
|
2115
|
+
this.cache.delete(fullCacheKey);
|
|
2014
2116
|
let resolved;
|
|
2015
2117
|
try {
|
|
2016
2118
|
resolved = this.resolveVal(val, obj);
|
|
@@ -2023,28 +2125,42 @@ var SubstitutionResolver = class {
|
|
|
2023
2125
|
if (prior !== void 0) {
|
|
2024
2126
|
const priorResolved = this.resolveVal(prior, obj);
|
|
2025
2127
|
if (priorResolved !== void 0 && priorResolved.kind === "object") {
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
priorResolved,
|
|
2030
|
-
resolved
|
|
2031
|
-
)
|
|
2128
|
+
const finalValue = deepMergeHoconValues(
|
|
2129
|
+
priorResolved,
|
|
2130
|
+
resolved
|
|
2032
2131
|
);
|
|
2132
|
+
result.set(key, finalValue);
|
|
2133
|
+
this.cache.set(fullCacheKey, finalValue);
|
|
2134
|
+
this.cacheDescendants(fullCacheKey, finalValue);
|
|
2033
2135
|
continue;
|
|
2034
2136
|
}
|
|
2035
2137
|
}
|
|
2036
2138
|
}
|
|
2037
2139
|
result.set(key, resolved);
|
|
2140
|
+
this.cache.set(fullCacheKey, resolved);
|
|
2141
|
+
this.cacheDescendants(fullCacheKey, resolved);
|
|
2038
2142
|
} else {
|
|
2039
2143
|
const prior = obj.priorValues.get(key);
|
|
2040
2144
|
if (prior !== void 0) {
|
|
2041
2145
|
const priorResolved = this.resolveVal(prior, obj);
|
|
2042
|
-
if (priorResolved !== void 0)
|
|
2146
|
+
if (priorResolved !== void 0) {
|
|
2147
|
+
result.set(key, priorResolved);
|
|
2148
|
+
this.cache.set(fullCacheKey, priorResolved);
|
|
2149
|
+
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
2150
|
+
}
|
|
2043
2151
|
}
|
|
2044
2152
|
}
|
|
2045
2153
|
}
|
|
2046
2154
|
return { kind: "object", fields: result };
|
|
2047
2155
|
}
|
|
2156
|
+
cacheDescendants(prefix, value) {
|
|
2157
|
+
if (value.kind !== "object") return;
|
|
2158
|
+
for (const [key, child] of value.fields) {
|
|
2159
|
+
const childKey = `${prefix}.${stringSegmentsToKey([key])}`;
|
|
2160
|
+
this.cache.set(childKey, child);
|
|
2161
|
+
this.cacheDescendants(childKey, child);
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2048
2164
|
resolveVal(v, scope) {
|
|
2049
2165
|
if (isSubst(v)) return this.resolveSubst(v, scope);
|
|
2050
2166
|
if (isConcat(v)) {
|
|
@@ -2056,7 +2172,6 @@ var SubstitutionResolver = class {
|
|
|
2056
2172
|
this.resolvingConcats.delete(v);
|
|
2057
2173
|
}
|
|
2058
2174
|
}
|
|
2059
|
-
if (isAppend(v)) return this.resolveAppend(v, scope);
|
|
2060
2175
|
if (isResObj(v)) return this.resolveResObj(v);
|
|
2061
2176
|
const hv = v;
|
|
2062
2177
|
if (hv.kind === "array") {
|
|
@@ -2070,6 +2185,7 @@ var SubstitutionResolver = class {
|
|
|
2070
2185
|
return hv;
|
|
2071
2186
|
}
|
|
2072
2187
|
resolveSubst(s, scope) {
|
|
2188
|
+
if (s.knownAbsent) return void 0;
|
|
2073
2189
|
const key = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
2074
2190
|
if (this.cache.has(key)) return this.cache.get(key);
|
|
2075
2191
|
if (this.resolving.has(key)) {
|
|
@@ -2162,6 +2278,28 @@ var SubstitutionResolver = class {
|
|
|
2162
2278
|
if (result !== void 0) this.cache.set(key, result);
|
|
2163
2279
|
return result;
|
|
2164
2280
|
}
|
|
2281
|
+
if (s.prefixLen > 0 && s.segments.length > s.prefixLen) {
|
|
2282
|
+
const originalSegments = s.segments.slice(s.prefixLen);
|
|
2283
|
+
const fallbackFound = lookupPath(this.root, originalSegments);
|
|
2284
|
+
if (fallbackFound !== void 0) {
|
|
2285
|
+
let result = this.resolveVal(fallbackFound, scope);
|
|
2286
|
+
if (originalSegments.length === 1 && result !== void 0 && result.kind === "object") {
|
|
2287
|
+
const rootSeg = originalSegments[0]?.text ?? "";
|
|
2288
|
+
const prior = this.root.priorValues.get(rootSeg);
|
|
2289
|
+
if (prior !== void 0) {
|
|
2290
|
+
const priorResolved = this.resolveVal(prior, scope);
|
|
2291
|
+
if (priorResolved !== void 0 && priorResolved.kind === "object") {
|
|
2292
|
+
result = deepMergeHoconValues(
|
|
2293
|
+
priorResolved,
|
|
2294
|
+
result
|
|
2295
|
+
);
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
if (result !== void 0) this.cache.set(key, result);
|
|
2300
|
+
return result;
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2165
2303
|
if (s.listSuffix && this.opts.useSystemEnvironment !== false) {
|
|
2166
2304
|
const result = this.resolveEnvList(s);
|
|
2167
2305
|
if (result !== void 0) {
|
|
@@ -2318,38 +2456,6 @@ var SubstitutionResolver = class {
|
|
|
2318
2456
|
}
|
|
2319
2457
|
return folded;
|
|
2320
2458
|
}
|
|
2321
|
-
resolveAppend(a, scope) {
|
|
2322
|
-
const existing = this.resolveVal(a.existing, scope) ?? { kind: "array", items: [] };
|
|
2323
|
-
if (this.opts.allowUnresolved && (isSubst(existing) || isConcat(existing) || isAppend(existing))) {
|
|
2324
|
-
return a;
|
|
2325
|
-
}
|
|
2326
|
-
const elem = this.resolveVal(a.elem, scope);
|
|
2327
|
-
let priorItems;
|
|
2328
|
-
if (existing.kind === "array") {
|
|
2329
|
-
priorItems = existing.items;
|
|
2330
|
-
} else if (existing.kind === "object") {
|
|
2331
|
-
const converted = numericObjectToArray(existing);
|
|
2332
|
-
if (converted === null) {
|
|
2333
|
-
throw new ResolveError(
|
|
2334
|
-
`'+=' on non-array value: prior value is object with non-numeric keys (spec L732)`,
|
|
2335
|
-
"",
|
|
2336
|
-
0,
|
|
2337
|
-
0
|
|
2338
|
-
);
|
|
2339
|
-
}
|
|
2340
|
-
priorItems = converted;
|
|
2341
|
-
} else {
|
|
2342
|
-
throw new ResolveError(
|
|
2343
|
-
`'+=' on non-array value: prior value is ${existing.kind} (spec L732)`,
|
|
2344
|
-
"",
|
|
2345
|
-
0,
|
|
2346
|
-
0
|
|
2347
|
-
);
|
|
2348
|
-
}
|
|
2349
|
-
const items = [...priorItems];
|
|
2350
|
-
if (elem !== void 0) items.push(elem);
|
|
2351
|
-
return { kind: "array", items };
|
|
2352
|
-
}
|
|
2353
2459
|
};
|
|
2354
2460
|
|
|
2355
2461
|
// src/internal/resolver/resolver.ts
|
|
@@ -2367,7 +2473,7 @@ function containsPlaceholders(tree) {
|
|
|
2367
2473
|
}
|
|
2368
2474
|
function valContainsPlaceholders(v) {
|
|
2369
2475
|
const rv = v;
|
|
2370
|
-
if (isSubst(rv) || isConcat(rv)
|
|
2476
|
+
if (isSubst(rv) || isConcat(rv)) return true;
|
|
2371
2477
|
if (isResObj(rv)) return containsPlaceholders(rv);
|
|
2372
2478
|
const hv = v;
|
|
2373
2479
|
if (hv?.kind === "array") {
|
|
@@ -2378,7 +2484,7 @@ function valContainsPlaceholders(v) {
|
|
|
2378
2484
|
function buildPartialHoconFromResObj(tree) {
|
|
2379
2485
|
const fields = /* @__PURE__ */ new Map();
|
|
2380
2486
|
for (const [k, v] of tree.fields) {
|
|
2381
|
-
if (!isSubst(v) && !isConcat(v)
|
|
2487
|
+
if (!isSubst(v) && !isConcat(v)) {
|
|
2382
2488
|
if (isResObj(v)) {
|
|
2383
2489
|
fields.set(k, buildPartialHoconFromResObj(v));
|
|
2384
2490
|
} 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);
|