@o3co/ts.hocon 1.12.0 → 1.13.0
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/README.ja.md +7 -5
- package/README.md +8 -4
- package/dist/adapters/env.cjs +419 -79
- package/dist/adapters/env.d.cts +1 -1
- package/dist/adapters/env.d.ts +1 -1
- package/dist/adapters/env.js +419 -79
- package/dist/adapters/json5.cjs +2450 -0
- package/dist/adapters/json5.d.cts +47 -0
- package/dist/adapters/json5.d.ts +47 -0
- package/dist/adapters/json5.js +2413 -0
- package/dist/adapters/jsonc.cjs +419 -79
- package/dist/adapters/jsonc.d.cts +1 -1
- package/dist/adapters/jsonc.d.ts +1 -1
- package/dist/adapters/jsonc.js +419 -79
- package/dist/adapters/properties.cjs +419 -79
- package/dist/adapters/properties.d.cts +1 -1
- package/dist/adapters/properties.d.ts +1 -1
- package/dist/adapters/properties.js +419 -79
- package/dist/adapters/toml.cjs +419 -79
- package/dist/adapters/toml.d.cts +1 -1
- package/dist/adapters/toml.d.ts +1 -1
- package/dist/adapters/toml.js +419 -79
- package/dist/adapters/yaml.cjs +419 -79
- package/dist/adapters/yaml.d.cts +1 -1
- package/dist/adapters/yaml.d.ts +1 -1
- package/dist/adapters/yaml.js +419 -79
- package/dist/{config-Dlq6rF3w.d.cts → config-6sApTEMM.d.cts} +22 -0
- package/dist/{config-Dlq6rF3w.d.ts → config-6sApTEMM.d.ts} +22 -0
- package/dist/index.cjs +432 -87
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +432 -87
- package/dist/zod.cjs +432 -87
- package/dist/zod.d.cts +1 -1
- package/dist/zod.d.ts +1 -1
- package/dist/zod.js +432 -87
- package/package.json +12 -2
package/dist/index.cjs
CHANGED
|
@@ -95,13 +95,22 @@ function coerceNumber(value) {
|
|
|
95
95
|
return Number(value);
|
|
96
96
|
}
|
|
97
97
|
var DURATION_UNITS = {
|
|
98
|
+
// S19.1–S19.3: the bare nano/micro/milli (+plural) aliases are part of the
|
|
99
|
+
// spec's unit lists (HOCON.md L1307–L1309) and accepted by Lightbend
|
|
100
|
+
// (typesafe-config 1.4.6 probe, 2026-08-18); they were missing here.
|
|
98
101
|
ns: 1e-6,
|
|
102
|
+
nano: 1e-6,
|
|
103
|
+
nanos: 1e-6,
|
|
99
104
|
nanosecond: 1e-6,
|
|
100
105
|
nanoseconds: 1e-6,
|
|
101
106
|
us: 1e-3,
|
|
107
|
+
micro: 1e-3,
|
|
108
|
+
micros: 1e-3,
|
|
102
109
|
microsecond: 1e-3,
|
|
103
110
|
microseconds: 1e-3,
|
|
104
111
|
ms: 1,
|
|
112
|
+
milli: 1,
|
|
113
|
+
millis: 1,
|
|
105
114
|
millisecond: 1,
|
|
106
115
|
milliseconds: 1,
|
|
107
116
|
s: 1e3,
|
|
@@ -153,37 +162,76 @@ function parseDuration(value, outputUnit = "ms") {
|
|
|
153
162
|
return ms / divisor;
|
|
154
163
|
}
|
|
155
164
|
var BYTE_UNITS = {
|
|
165
|
+
// S21.1–S21.4 — the EXACT Lightbend/typesafe-config unit set (1.4.6 probe,
|
|
166
|
+
// 2026-08-18). Multi-letter units are case-sensitive: the SI decimal short
|
|
167
|
+
// form is `kB` (NOT `KB`/`kb` — Lightbend rejects both), higher decimals
|
|
168
|
+
// are `MB`…`YB`, binary prefixes are `Ki`/`KiB`…`Yi`/`YiB` with capital
|
|
169
|
+
// first letter, and long forms are lowercase only (`kilobyte`, never
|
|
170
|
+
// `Kilobyte`). Only the bare byte unit (`B`/`b`) and the single-letter
|
|
171
|
+
// -Xmx forms accept both cases. The old case-insensitive fallback and the
|
|
172
|
+
// lowercase alias rows accepted spellings Lightbend rejects — removed.
|
|
156
173
|
B: 1,
|
|
174
|
+
b: 1,
|
|
157
175
|
byte: 1,
|
|
158
176
|
bytes: 1,
|
|
159
|
-
|
|
177
|
+
kB: 1e3,
|
|
160
178
|
kilobyte: 1e3,
|
|
161
179
|
kilobytes: 1e3,
|
|
162
|
-
KiB: 1024,
|
|
163
|
-
kibibyte: 1024,
|
|
164
|
-
kibibytes: 1024,
|
|
165
180
|
MB: 1e6,
|
|
166
181
|
megabyte: 1e6,
|
|
167
182
|
megabytes: 1e6,
|
|
168
|
-
MiB: 1048576,
|
|
169
|
-
mebibyte: 1048576,
|
|
170
|
-
mebibytes: 1048576,
|
|
171
183
|
GB: 1e9,
|
|
172
184
|
gigabyte: 1e9,
|
|
173
185
|
gigabytes: 1e9,
|
|
174
|
-
GiB: 1073741824,
|
|
175
|
-
gibibyte: 1073741824,
|
|
176
|
-
gibibytes: 1073741824,
|
|
177
186
|
TB: 1e12,
|
|
178
187
|
terabyte: 1e12,
|
|
179
188
|
terabytes: 1e12,
|
|
189
|
+
PB: 1e15,
|
|
190
|
+
petabyte: 1e15,
|
|
191
|
+
petabytes: 1e15,
|
|
192
|
+
EB: 1e18,
|
|
193
|
+
exabyte: 1e18,
|
|
194
|
+
exabytes: 1e18,
|
|
195
|
+
ZB: 1e21,
|
|
196
|
+
zettabyte: 1e21,
|
|
197
|
+
zettabytes: 1e21,
|
|
198
|
+
YB: 1e24,
|
|
199
|
+
yottabyte: 1e24,
|
|
200
|
+
yottabytes: 1e24,
|
|
201
|
+
Ki: 1024,
|
|
202
|
+
KiB: 1024,
|
|
203
|
+
kibibyte: 1024,
|
|
204
|
+
kibibytes: 1024,
|
|
205
|
+
Mi: 1048576,
|
|
206
|
+
MiB: 1048576,
|
|
207
|
+
mebibyte: 1048576,
|
|
208
|
+
mebibytes: 1048576,
|
|
209
|
+
Gi: 1073741824,
|
|
210
|
+
GiB: 1073741824,
|
|
211
|
+
gibibyte: 1073741824,
|
|
212
|
+
gibibytes: 1073741824,
|
|
213
|
+
Ti: 1099511627776,
|
|
180
214
|
TiB: 1099511627776,
|
|
181
215
|
tebibyte: 1099511627776,
|
|
182
216
|
tebibytes: 1099511627776,
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
217
|
+
Pi: 1024 ** 5,
|
|
218
|
+
PiB: 1024 ** 5,
|
|
219
|
+
pebibyte: 1024 ** 5,
|
|
220
|
+
pebibytes: 1024 ** 5,
|
|
221
|
+
Ei: 1024 ** 6,
|
|
222
|
+
EiB: 1024 ** 6,
|
|
223
|
+
exbibyte: 1024 ** 6,
|
|
224
|
+
exbibytes: 1024 ** 6,
|
|
225
|
+
Zi: 1024 ** 7,
|
|
226
|
+
ZiB: 1024 ** 7,
|
|
227
|
+
zebibyte: 1024 ** 7,
|
|
228
|
+
zebibytes: 1024 ** 7,
|
|
229
|
+
Yi: 1024 ** 8,
|
|
230
|
+
YiB: 1024 ** 8,
|
|
231
|
+
yobibyte: 1024 ** 8,
|
|
232
|
+
yobibytes: 1024 ** 8,
|
|
233
|
+
// S21.4 — single-letter abbreviations → powers of two (java -Xmx
|
|
234
|
+
// convention); Lightbend accepts BOTH cases here, through the full ladder.
|
|
187
235
|
K: 1024,
|
|
188
236
|
k: 1024,
|
|
189
237
|
M: 1024 ** 2,
|
|
@@ -196,16 +244,10 @@ var BYTE_UNITS = {
|
|
|
196
244
|
p: 1024 ** 5,
|
|
197
245
|
E: 1024 ** 6,
|
|
198
246
|
e: 1024 ** 6,
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
mb: 1e6,
|
|
204
|
-
mib: 1048576,
|
|
205
|
-
gb: 1e9,
|
|
206
|
-
gib: 1073741824,
|
|
207
|
-
tb: 1e12,
|
|
208
|
-
tib: 1099511627776
|
|
247
|
+
Z: 1024 ** 7,
|
|
248
|
+
z: 1024 ** 7,
|
|
249
|
+
Y: 1024 ** 8,
|
|
250
|
+
y: 1024 ** 8
|
|
209
251
|
};
|
|
210
252
|
var OUTPUT_BYTE_UNITS = {
|
|
211
253
|
B: 1,
|
|
@@ -243,10 +285,7 @@ function parseBytes(value, outputUnit = "B") {
|
|
|
243
285
|
}
|
|
244
286
|
return bytes2 / divisor;
|
|
245
287
|
}
|
|
246
|
-
|
|
247
|
-
if (mult === void 0) {
|
|
248
|
-
mult = BYTE_UNITS[unit.toLowerCase()];
|
|
249
|
-
}
|
|
288
|
+
const mult = BYTE_UNITS[unit];
|
|
250
289
|
if (mult === void 0) return NaN;
|
|
251
290
|
const bytes = num * mult;
|
|
252
291
|
if (Math.abs(bytes) > Number.MAX_SAFE_INTEGER) {
|
|
@@ -310,35 +349,114 @@ function stringSegmentsToKey(segments) {
|
|
|
310
349
|
return t;
|
|
311
350
|
}).join(".");
|
|
312
351
|
}
|
|
352
|
+
function prefixSelfRefRemainder(s, fullKey) {
|
|
353
|
+
const texts = s.segments.map((seg) => seg.text);
|
|
354
|
+
if (!stringSegmentsToKey(texts).startsWith(fullKey + ".")) return null;
|
|
355
|
+
for (let n = 1; n < texts.length; n++) {
|
|
356
|
+
if (stringSegmentsToKey(texts.slice(0, n)) === fullKey) return texts.slice(n);
|
|
357
|
+
}
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
function navigateResolverValue(v, remainder) {
|
|
361
|
+
let cur = v;
|
|
362
|
+
for (const seg of remainder) {
|
|
363
|
+
if (isSubst(cur) || isConcat(cur)) return null;
|
|
364
|
+
if (isResObj(cur)) {
|
|
365
|
+
const next = cur.fields.get(seg);
|
|
366
|
+
if (next === void 0) return void 0;
|
|
367
|
+
cur = next;
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
const hv = cur;
|
|
371
|
+
if (hv.kind === "object") {
|
|
372
|
+
const next = hv.fields.get(seg);
|
|
373
|
+
if (next === void 0) return void 0;
|
|
374
|
+
cur = next;
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
return void 0;
|
|
378
|
+
}
|
|
379
|
+
return cur;
|
|
380
|
+
}
|
|
381
|
+
function foldPrefixSelfRef(s, replacement, remainder) {
|
|
382
|
+
const navigated = navigateResolverValue(replacement, remainder);
|
|
383
|
+
if (navigated === null) return s;
|
|
384
|
+
if (navigated === void 0) {
|
|
385
|
+
return {
|
|
386
|
+
_kind: "subst-placeholder",
|
|
387
|
+
segments: s.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
|
|
388
|
+
optional: s.optional,
|
|
389
|
+
knownAbsent: true,
|
|
390
|
+
listSuffix: s.listSuffix,
|
|
391
|
+
line: s.line,
|
|
392
|
+
col: s.col,
|
|
393
|
+
prefixLen: s.prefixLen
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
return cloneResolverValue(navigated);
|
|
397
|
+
}
|
|
398
|
+
function mergeResObjLayers(base, top) {
|
|
399
|
+
const fields = new Map(base.fields);
|
|
400
|
+
for (const [k, tv] of top.fields) {
|
|
401
|
+
const bv = fields.get(k);
|
|
402
|
+
if (bv !== void 0 && isResObj(bv) && isResObj(tv)) {
|
|
403
|
+
fields.set(k, mergeResObjLayers(bv, tv));
|
|
404
|
+
} else {
|
|
405
|
+
fields.set(k, tv);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
const priorValues = new Map(base.priorValues);
|
|
409
|
+
for (const [k, pv] of top.priorValues) priorValues.set(k, pv);
|
|
410
|
+
const resetKeys = new Set(base.resetKeys);
|
|
411
|
+
for (const k of top.resetKeys) resetKeys.add(k);
|
|
412
|
+
return {
|
|
413
|
+
_kind: "res-obj",
|
|
414
|
+
fields,
|
|
415
|
+
priorValues,
|
|
416
|
+
resetKeys
|
|
417
|
+
};
|
|
418
|
+
}
|
|
313
419
|
function containsSelfRef(v, fullKey) {
|
|
314
|
-
|
|
315
|
-
|
|
420
|
+
return containsSelfRefInner(v, fullKey, true);
|
|
421
|
+
}
|
|
422
|
+
function containsSelfRefInner(v, fullKey, allowPrefix) {
|
|
423
|
+
if (isSubst(v))
|
|
424
|
+
return !v.knownAbsent && (substFullKey(v) === fullKey || allowPrefix && prefixSelfRefRemainder(v, fullKey) !== null);
|
|
425
|
+
if (isConcat(v)) return v.nodes.some((n) => containsSelfRefInner(n, fullKey, allowPrefix));
|
|
316
426
|
if (isResObj(v)) {
|
|
317
427
|
for (const f of v.fields.values()) {
|
|
318
|
-
if (
|
|
428
|
+
if (containsSelfRefInner(f, fullKey, false)) return true;
|
|
319
429
|
}
|
|
320
430
|
return false;
|
|
321
431
|
}
|
|
322
432
|
const hv = v;
|
|
323
433
|
if (hv.kind === "array") {
|
|
324
|
-
return hv.items.some((item) =>
|
|
434
|
+
return hv.items.some((item) => containsSelfRefInner(item, fullKey, allowPrefix));
|
|
325
435
|
}
|
|
326
436
|
if (hv.kind === "object") {
|
|
327
437
|
for (const f of hv.fields.values()) {
|
|
328
|
-
if (
|
|
438
|
+
if (containsSelfRefInner(f, fullKey, false)) return true;
|
|
329
439
|
}
|
|
330
440
|
return false;
|
|
331
441
|
}
|
|
332
442
|
return false;
|
|
333
443
|
}
|
|
334
444
|
function foldSelfRef(v, fullKey, replacement) {
|
|
445
|
+
return foldSelfRefInner(v, fullKey, replacement, true);
|
|
446
|
+
}
|
|
447
|
+
function foldSelfRefInner(v, fullKey, replacement, allowPrefix) {
|
|
335
448
|
if (isSubst(v)) {
|
|
336
|
-
|
|
449
|
+
if (substFullKey(v) === fullKey) return replacement;
|
|
450
|
+
if (allowPrefix) {
|
|
451
|
+
const remainder = prefixSelfRefRemainder(v, fullKey);
|
|
452
|
+
if (remainder !== null) return foldPrefixSelfRef(v, replacement, remainder);
|
|
453
|
+
}
|
|
454
|
+
return v;
|
|
337
455
|
}
|
|
338
456
|
if (isConcat(v)) {
|
|
339
457
|
return {
|
|
340
458
|
_kind: "concat-placeholder",
|
|
341
|
-
nodes: v.nodes.map((n) =>
|
|
459
|
+
nodes: v.nodes.map((n) => foldSelfRefInner(n, fullKey, replacement, allowPrefix)),
|
|
342
460
|
line: v.line,
|
|
343
461
|
col: v.col
|
|
344
462
|
};
|
|
@@ -346,7 +464,7 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
346
464
|
if (isResObj(v)) {
|
|
347
465
|
const newFields = /* @__PURE__ */ new Map();
|
|
348
466
|
for (const [k, val] of v.fields) {
|
|
349
|
-
newFields.set(k,
|
|
467
|
+
newFields.set(k, foldSelfRefInner(val, fullKey, replacement, false));
|
|
350
468
|
}
|
|
351
469
|
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
352
470
|
}
|
|
@@ -354,13 +472,15 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
354
472
|
if (hv.kind === "array") {
|
|
355
473
|
return {
|
|
356
474
|
kind: "array",
|
|
357
|
-
items: hv.items.map(
|
|
475
|
+
items: hv.items.map(
|
|
476
|
+
(item) => foldSelfRefInner(item, fullKey, replacement, allowPrefix)
|
|
477
|
+
)
|
|
358
478
|
};
|
|
359
479
|
}
|
|
360
480
|
if (hv.kind === "object") {
|
|
361
481
|
const newFields = /* @__PURE__ */ new Map();
|
|
362
482
|
for (const [k, val] of hv.fields) {
|
|
363
|
-
newFields.set(k,
|
|
483
|
+
newFields.set(k, foldSelfRefInner(val, fullKey, replacement, false));
|
|
364
484
|
}
|
|
365
485
|
return { kind: "object", fields: newFields };
|
|
366
486
|
}
|
|
@@ -404,10 +524,26 @@ function foldKnownAbsentSelfRef(v, fullKey, replacement) {
|
|
|
404
524
|
function foldOrSkipPrior(prior, fullKey, old) {
|
|
405
525
|
if (!containsSelfRef(prior, fullKey)) return cloneResolverValue(prior);
|
|
406
526
|
if (old === void 0) return foldOptionalSelfRefAbsent(prior, fullKey);
|
|
527
|
+
if (isSubst(prior)) {
|
|
528
|
+
const remainder = prefixSelfRefRemainder(prior, fullKey);
|
|
529
|
+
if (remainder !== null) {
|
|
530
|
+
const navigated = navigateResolverValue(old, remainder);
|
|
531
|
+
if (navigated === void 0 && prior.optional) return cloneResolverValue(old);
|
|
532
|
+
if (navigated !== null && navigated !== void 0 && isResObj(navigated) && isResObj(old)) {
|
|
533
|
+
return mergeResObjLayers(
|
|
534
|
+
cloneResolverValue(old),
|
|
535
|
+
cloneResolverValue(navigated)
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
407
540
|
return foldSelfRef(prior, fullKey, old);
|
|
408
541
|
}
|
|
409
542
|
function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
410
|
-
|
|
543
|
+
return foldOptionalSelfRefAbsentInner(v, fullKey, true);
|
|
544
|
+
}
|
|
545
|
+
function foldOptionalSelfRefAbsentInner(v, fullKey, allowPrefix) {
|
|
546
|
+
if (isSubst(v) && (substFullKey(v) === fullKey || allowPrefix && prefixSelfRefRemainder(v, fullKey) !== null)) {
|
|
411
547
|
if (!v.optional) return void 0;
|
|
412
548
|
return {
|
|
413
549
|
_kind: "subst-placeholder",
|
|
@@ -423,7 +559,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
423
559
|
if (isConcat(v)) {
|
|
424
560
|
const nodes = [];
|
|
425
561
|
for (const node of v.nodes) {
|
|
426
|
-
const folded =
|
|
562
|
+
const folded = foldOptionalSelfRefAbsentInner(node, fullKey, allowPrefix);
|
|
427
563
|
if (folded === void 0) return void 0;
|
|
428
564
|
nodes.push(folded);
|
|
429
565
|
}
|
|
@@ -432,7 +568,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
432
568
|
if (isResObj(v)) {
|
|
433
569
|
const fields = /* @__PURE__ */ new Map();
|
|
434
570
|
for (const [key, value] of v.fields) {
|
|
435
|
-
const folded =
|
|
571
|
+
const folded = foldOptionalSelfRefAbsentInner(value, fullKey, false);
|
|
436
572
|
if (folded === void 0) return void 0;
|
|
437
573
|
fields.set(key, folded);
|
|
438
574
|
}
|
|
@@ -442,7 +578,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
442
578
|
if (hv.kind === "array") {
|
|
443
579
|
const items = [];
|
|
444
580
|
for (const item of hv.items) {
|
|
445
|
-
const folded =
|
|
581
|
+
const folded = foldOptionalSelfRefAbsentInner(item, fullKey, allowPrefix);
|
|
446
582
|
if (folded === void 0) return void 0;
|
|
447
583
|
items.push(folded);
|
|
448
584
|
}
|
|
@@ -451,7 +587,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
451
587
|
if (hv.kind === "object") {
|
|
452
588
|
const fields = /* @__PURE__ */ new Map();
|
|
453
589
|
for (const [key, value] of hv.fields) {
|
|
454
|
-
const folded =
|
|
590
|
+
const folded = foldOptionalSelfRefAbsentInner(value, fullKey, false);
|
|
455
591
|
if (folded === void 0) return void 0;
|
|
456
592
|
fields.set(key, folded);
|
|
457
593
|
}
|
|
@@ -824,7 +960,6 @@ var Lexer = class {
|
|
|
824
960
|
if (!closed) {
|
|
825
961
|
throw new ParseError("unterminated triple-quoted string", sl, sc);
|
|
826
962
|
}
|
|
827
|
-
if (value.startsWith("\n")) value = value.slice(1);
|
|
828
963
|
this.push("triple_string", value, sl, sc, true);
|
|
829
964
|
continue;
|
|
830
965
|
}
|
|
@@ -1141,9 +1276,9 @@ var Parser = class {
|
|
|
1141
1276
|
}
|
|
1142
1277
|
}
|
|
1143
1278
|
this.skip("newline");
|
|
1144
|
-
const
|
|
1145
|
-
if (
|
|
1146
|
-
throw new ParseError(`Unexpected token '${
|
|
1279
|
+
const remaining2 = this.peek();
|
|
1280
|
+
if (remaining2.kind !== "eof") {
|
|
1281
|
+
throw new ParseError(`Unexpected token '${remaining2.value}' after closing brace`, remaining2.line, remaining2.col);
|
|
1147
1282
|
}
|
|
1148
1283
|
return { kind: "object", fields: allFields, pos: first.pos };
|
|
1149
1284
|
}
|
|
@@ -1151,13 +1286,19 @@ var Parser = class {
|
|
|
1151
1286
|
this.advance();
|
|
1152
1287
|
const arr = this.parseArray();
|
|
1153
1288
|
this.skip("newline");
|
|
1154
|
-
const
|
|
1155
|
-
if (
|
|
1156
|
-
throw new ParseError(`Unexpected token '${
|
|
1289
|
+
const remaining2 = this.peek();
|
|
1290
|
+
if (remaining2.kind !== "eof") {
|
|
1291
|
+
throw new ParseError(`Unexpected token '${remaining2.value}' after root array`, remaining2.line, remaining2.col);
|
|
1157
1292
|
}
|
|
1158
1293
|
return { ...arr, pos: { line: t.line, col: t.col } };
|
|
1159
1294
|
}
|
|
1160
|
-
|
|
1295
|
+
const root = this.parseObject(false);
|
|
1296
|
+
this.skip("newline");
|
|
1297
|
+
const remaining = this.peek();
|
|
1298
|
+
if (remaining.kind !== "eof") {
|
|
1299
|
+
throw new ParseError(`Unexpected token '${remaining.value}' after root content`, remaining.line, remaining.col);
|
|
1300
|
+
}
|
|
1301
|
+
return root;
|
|
1161
1302
|
}
|
|
1162
1303
|
peek(offset = 0) {
|
|
1163
1304
|
return this.tokens[this.pos + offset] ?? EOF_TOKEN;
|
|
@@ -2315,6 +2456,12 @@ var SubstitutionResolver = class {
|
|
|
2315
2456
|
// Cross-impl with rs.hocon v1.5.1's resolving_field_path (same purpose,
|
|
2316
2457
|
// same prefix-match semantics).
|
|
2317
2458
|
this.resolvingFieldPath = [];
|
|
2459
|
+
// S13a.12 recursion guard: field keys whose prior is currently being
|
|
2460
|
+
// resolved through the prefix-self-ref branch. Saved priors are
|
|
2461
|
+
// prefix-self-ref-free by the fold invariant, so re-entry only happens on
|
|
2462
|
+
// a shape the fold could not see through (a live subst mid-navigation) —
|
|
2463
|
+
// report it as a cycle instead of recursing forever.
|
|
2464
|
+
this.resolvingPrefixPriors = /* @__PURE__ */ new Set();
|
|
2318
2465
|
}
|
|
2319
2466
|
/** Returns a prefix for error messages, including origin info when set. */
|
|
2320
2467
|
originPrefix() {
|
|
@@ -2329,46 +2476,57 @@ var SubstitutionResolver = class {
|
|
|
2329
2476
|
this.resolvingFieldPath.push(key);
|
|
2330
2477
|
const fullCacheKey = stringSegmentsToKey(this.resolvingFieldPath);
|
|
2331
2478
|
this.cache.delete(fullCacheKey);
|
|
2332
|
-
let resolved;
|
|
2333
2479
|
try {
|
|
2334
|
-
resolved = this.resolveVal(val, obj);
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2480
|
+
const resolved = this.resolveVal(val, obj);
|
|
2481
|
+
if (resolved !== void 0) {
|
|
2482
|
+
if (resolved.kind === "object") {
|
|
2483
|
+
const prior = obj.priorValues.get(key);
|
|
2484
|
+
if (prior !== void 0) {
|
|
2485
|
+
const priorResolved = this.resolveVal(prior, obj);
|
|
2486
|
+
if (priorResolved !== void 0 && priorResolved.kind === "object") {
|
|
2487
|
+
const finalValue = deepMergeHoconValues(
|
|
2488
|
+
priorResolved,
|
|
2489
|
+
resolved
|
|
2490
|
+
);
|
|
2491
|
+
result.set(key, finalValue);
|
|
2492
|
+
this.cache.set(fullCacheKey, finalValue);
|
|
2493
|
+
this.cacheDescendants(fullCacheKey, finalValue);
|
|
2494
|
+
continue;
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2498
|
+
result.set(key, resolved);
|
|
2499
|
+
this.cache.set(fullCacheKey, resolved);
|
|
2500
|
+
this.cacheDescendants(fullCacheKey, resolved);
|
|
2501
|
+
} else {
|
|
2340
2502
|
const prior = obj.priorValues.get(key);
|
|
2341
2503
|
if (prior !== void 0) {
|
|
2342
2504
|
const priorResolved = this.resolveVal(prior, obj);
|
|
2343
|
-
if (priorResolved !== void 0
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
);
|
|
2348
|
-
result.set(key, finalValue);
|
|
2349
|
-
this.cache.set(fullCacheKey, finalValue);
|
|
2350
|
-
this.cacheDescendants(fullCacheKey, finalValue);
|
|
2351
|
-
continue;
|
|
2505
|
+
if (priorResolved !== void 0) {
|
|
2506
|
+
result.set(key, priorResolved);
|
|
2507
|
+
this.cache.set(fullCacheKey, priorResolved);
|
|
2508
|
+
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
2352
2509
|
}
|
|
2353
2510
|
}
|
|
2354
2511
|
}
|
|
2355
|
-
|
|
2356
|
-
this.
|
|
2357
|
-
this.cacheDescendants(fullCacheKey, resolved);
|
|
2358
|
-
} else {
|
|
2359
|
-
const prior = obj.priorValues.get(key);
|
|
2360
|
-
if (prior !== void 0) {
|
|
2361
|
-
const priorResolved = this.resolveVal(prior, obj);
|
|
2362
|
-
if (priorResolved !== void 0) {
|
|
2363
|
-
result.set(key, priorResolved);
|
|
2364
|
-
this.cache.set(fullCacheKey, priorResolved);
|
|
2365
|
-
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
2366
|
-
}
|
|
2367
|
-
}
|
|
2512
|
+
} finally {
|
|
2513
|
+
this.resolvingFieldPath.pop();
|
|
2368
2514
|
}
|
|
2369
2515
|
}
|
|
2370
2516
|
return { kind: "object", fields: result };
|
|
2371
2517
|
}
|
|
2518
|
+
/** S13a.12: walk resolved-object fields by segment text. A missing segment
|
|
2519
|
+
* or a walk into a scalar/array is path-absent → undefined. */
|
|
2520
|
+
navigateResolved(v, remainder) {
|
|
2521
|
+
let cur = v;
|
|
2522
|
+
for (const seg of remainder) {
|
|
2523
|
+
if (cur.kind !== "object") return void 0;
|
|
2524
|
+
const next = cur.fields.get(seg);
|
|
2525
|
+
if (next === void 0) return void 0;
|
|
2526
|
+
cur = next;
|
|
2527
|
+
}
|
|
2528
|
+
return cur;
|
|
2529
|
+
}
|
|
2372
2530
|
cacheDescendants(prefix, value) {
|
|
2373
2531
|
if (value.kind !== "object") return;
|
|
2374
2532
|
for (const [key, child] of value.fields) {
|
|
@@ -2391,17 +2549,59 @@ var SubstitutionResolver = class {
|
|
|
2391
2549
|
if (isResObj(v)) return this.resolveResObj(v);
|
|
2392
2550
|
const hv = v;
|
|
2393
2551
|
if (hv.kind === "array") {
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
)
|
|
2399
|
-
}
|
|
2552
|
+
const items = [];
|
|
2553
|
+
for (const item of hv.items) {
|
|
2554
|
+
const resolved = this.resolveVal(item, scope);
|
|
2555
|
+
if (resolved === void 0) continue;
|
|
2556
|
+
items.push(resolved);
|
|
2557
|
+
}
|
|
2558
|
+
return { kind: "array", items };
|
|
2400
2559
|
}
|
|
2401
2560
|
return hv;
|
|
2402
2561
|
}
|
|
2403
2562
|
resolveSubst(s, scope) {
|
|
2404
|
-
if (s.knownAbsent)
|
|
2563
|
+
if (s.knownAbsent) {
|
|
2564
|
+
if (!s.optional) {
|
|
2565
|
+
if (this.opts.allowUnresolved) return s;
|
|
2566
|
+
const k = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
2567
|
+
throw new ResolveError(
|
|
2568
|
+
`${this.originPrefix()}could not resolve substitution: \${${k}}`,
|
|
2569
|
+
k,
|
|
2570
|
+
s.line,
|
|
2571
|
+
s.col
|
|
2572
|
+
);
|
|
2573
|
+
}
|
|
2574
|
+
return void 0;
|
|
2575
|
+
}
|
|
2576
|
+
{
|
|
2577
|
+
const rfp = this.resolvingFieldPath;
|
|
2578
|
+
const sTexts = s.segments.map((seg) => seg.text);
|
|
2579
|
+
if (rfp.length > 0 && rfp.length < sTexts.length && stringSegmentsToKey(sTexts.slice(0, rfp.length)) === stringSegmentsToKey(rfp)) {
|
|
2580
|
+
const guardKey = stringSegmentsToKey(rfp);
|
|
2581
|
+
const prior = scope.priorValues.get(rfp[rfp.length - 1]);
|
|
2582
|
+
if (prior !== void 0 && !this.resolvingPrefixPriors.has(guardKey)) {
|
|
2583
|
+
this.resolvingPrefixPriors.add(guardKey);
|
|
2584
|
+
try {
|
|
2585
|
+
const priorResolved = this.resolveVal(prior, scope);
|
|
2586
|
+
if (priorResolved !== void 0) {
|
|
2587
|
+
const navigated = this.navigateResolved(priorResolved, sTexts.slice(rfp.length));
|
|
2588
|
+
if (navigated !== void 0) return navigated;
|
|
2589
|
+
}
|
|
2590
|
+
} finally {
|
|
2591
|
+
this.resolvingPrefixPriors.delete(guardKey);
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
if (s.optional) return void 0;
|
|
2595
|
+
if (this.opts.allowUnresolved) return s;
|
|
2596
|
+
const k = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
2597
|
+
throw new ResolveError(
|
|
2598
|
+
`${this.originPrefix()}could not resolve substitution: \${${k}}`,
|
|
2599
|
+
k,
|
|
2600
|
+
s.line,
|
|
2601
|
+
s.col
|
|
2602
|
+
);
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2405
2605
|
const key = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
2406
2606
|
if (this.cache.has(key)) return this.cache.get(key);
|
|
2407
2607
|
if (this.resolving.has(key)) {
|
|
@@ -2732,6 +2932,121 @@ async function resolveAsync(ast, opts) {
|
|
|
2732
2932
|
return resolveTree(root, { ...opts, useSystemEnvironment: true, allowUnresolved: false });
|
|
2733
2933
|
}
|
|
2734
2934
|
|
|
2935
|
+
// src/render-hocon.ts
|
|
2936
|
+
function renderHoconFromRoot(root) {
|
|
2937
|
+
const out = [];
|
|
2938
|
+
renderObjectBody(out, root, 0);
|
|
2939
|
+
return out.join("");
|
|
2940
|
+
}
|
|
2941
|
+
function renderObjectBody(out, o, depth) {
|
|
2942
|
+
const indent = " ".repeat(depth);
|
|
2943
|
+
for (const [k, v] of o.fields) {
|
|
2944
|
+
out.push(indent, renderKey(k));
|
|
2945
|
+
if (v.kind === "object") {
|
|
2946
|
+
out.push(" {");
|
|
2947
|
+
if (v.fields.size === 0) {
|
|
2948
|
+
out.push("}\n");
|
|
2949
|
+
continue;
|
|
2950
|
+
}
|
|
2951
|
+
out.push("\n");
|
|
2952
|
+
renderObjectBody(out, v, depth + 1);
|
|
2953
|
+
out.push(indent, "}\n");
|
|
2954
|
+
} else {
|
|
2955
|
+
out.push(" = ");
|
|
2956
|
+
renderValue(out, v, depth);
|
|
2957
|
+
out.push("\n");
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
function renderValue(out, v, depth) {
|
|
2962
|
+
switch (v.kind) {
|
|
2963
|
+
case "object": {
|
|
2964
|
+
if (v.fields.size === 0) {
|
|
2965
|
+
out.push("{}");
|
|
2966
|
+
return;
|
|
2967
|
+
}
|
|
2968
|
+
out.push("{\n");
|
|
2969
|
+
renderObjectBody(out, v, depth + 1);
|
|
2970
|
+
out.push(" ".repeat(depth), "}");
|
|
2971
|
+
return;
|
|
2972
|
+
}
|
|
2973
|
+
case "array":
|
|
2974
|
+
renderArray(out, v, depth);
|
|
2975
|
+
return;
|
|
2976
|
+
case "scalar":
|
|
2977
|
+
out.push(renderScalar(v));
|
|
2978
|
+
return;
|
|
2979
|
+
default:
|
|
2980
|
+
throw new ConfigError(
|
|
2981
|
+
"renderHocon: unrenderable value (config must be resolved data)",
|
|
2982
|
+
""
|
|
2983
|
+
);
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
function renderArray(out, a, depth) {
|
|
2987
|
+
if (a.items.length === 0) {
|
|
2988
|
+
out.push("[]");
|
|
2989
|
+
return;
|
|
2990
|
+
}
|
|
2991
|
+
const inner = " ".repeat(depth + 1);
|
|
2992
|
+
out.push("[\n");
|
|
2993
|
+
for (const e of a.items) {
|
|
2994
|
+
out.push(inner);
|
|
2995
|
+
renderValue(out, e, depth + 1);
|
|
2996
|
+
out.push("\n");
|
|
2997
|
+
}
|
|
2998
|
+
out.push(" ".repeat(depth), "]");
|
|
2999
|
+
}
|
|
3000
|
+
function renderScalar(s) {
|
|
3001
|
+
switch (s.valueType) {
|
|
3002
|
+
case "null":
|
|
3003
|
+
return "null";
|
|
3004
|
+
case "boolean":
|
|
3005
|
+
case "number":
|
|
3006
|
+
return s.raw;
|
|
3007
|
+
case "string":
|
|
3008
|
+
return renderString(s.raw);
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
var SAFE_UNQUOTED_KEY = /^[A-Za-z0-9_-]+$/;
|
|
3012
|
+
function renderKey(k) {
|
|
3013
|
+
if (k === "include") return quoteString(k);
|
|
3014
|
+
return SAFE_UNQUOTED_KEY.test(k) ? k : quoteString(k);
|
|
3015
|
+
}
|
|
3016
|
+
var SAFE_BARE_STRING = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
3017
|
+
var STRING_KEYWORDS = /* @__PURE__ */ new Set(["true", "false", "null", "yes", "no", "on", "off"]);
|
|
3018
|
+
function renderString(s) {
|
|
3019
|
+
return SAFE_BARE_STRING.test(s) && !STRING_KEYWORDS.has(s.toLowerCase()) ? s : quoteString(s);
|
|
3020
|
+
}
|
|
3021
|
+
function quoteString(s) {
|
|
3022
|
+
if (s.includes("\n") && !s.includes("\r") && !s.includes('"""') && !s.endsWith('"')) {
|
|
3023
|
+
return `"""${s}"""`;
|
|
3024
|
+
}
|
|
3025
|
+
let b = '"';
|
|
3026
|
+
for (const ch of s) {
|
|
3027
|
+
switch (ch) {
|
|
3028
|
+
case '"':
|
|
3029
|
+
b += '\\"';
|
|
3030
|
+
break;
|
|
3031
|
+
case "\\":
|
|
3032
|
+
b += "\\\\";
|
|
3033
|
+
break;
|
|
3034
|
+
case "\n":
|
|
3035
|
+
b += "\\n";
|
|
3036
|
+
break;
|
|
3037
|
+
case "\r":
|
|
3038
|
+
b += "\\r";
|
|
3039
|
+
break;
|
|
3040
|
+
case " ":
|
|
3041
|
+
b += "\\t";
|
|
3042
|
+
break;
|
|
3043
|
+
default:
|
|
3044
|
+
b += ch;
|
|
3045
|
+
}
|
|
3046
|
+
}
|
|
3047
|
+
return b + '"';
|
|
3048
|
+
}
|
|
3049
|
+
|
|
2735
3050
|
// src/config.ts
|
|
2736
3051
|
var Config = class _Config {
|
|
2737
3052
|
constructor(root, opts) {
|
|
@@ -3037,6 +3352,36 @@ var Config = class _Config {
|
|
|
3037
3352
|
toObject(opts) {
|
|
3038
3353
|
return hoconToJs(this.root, opts?.nullPrototype === true);
|
|
3039
3354
|
}
|
|
3355
|
+
/**
|
|
3356
|
+
* Renders this resolved Config as HOCON text (E18; lockstep with go.hocon's
|
|
3357
|
+
* `Config.RenderHOCON`, v1.11.0).
|
|
3358
|
+
*
|
|
3359
|
+
* The output round-trips: parsing it back yields the same value tree. That
|
|
3360
|
+
* is the correctness contract, not byte-for-byte formatting — a scalar is
|
|
3361
|
+
* quoted whenever leaving it bare would re-parse as a different type (a
|
|
3362
|
+
* string `"8080"` becomes `"8080"`, not `8080`), and left bare only when it
|
|
3363
|
+
* provably cannot.
|
|
3364
|
+
*
|
|
3365
|
+
* The Config must be resolved and hold only data (objects, arrays, string /
|
|
3366
|
+
* number / boolean / null scalars) — exactly what {@link fromMap} and the
|
|
3367
|
+
* format adapters produce. An unresolved placeholder throws
|
|
3368
|
+
* {@link ConfigError}; substitutions have no textual round trip through a
|
|
3369
|
+
* value tree.
|
|
3370
|
+
*
|
|
3371
|
+
* The root object's fields are emitted without enclosing braces, nested
|
|
3372
|
+
* objects as `key { … }`, arrays as newline-separated `[ … ]`, indented two
|
|
3373
|
+
* spaces. Source comments are not represented — a value tree does not carry
|
|
3374
|
+
* them.
|
|
3375
|
+
*/
|
|
3376
|
+
renderHocon() {
|
|
3377
|
+
if (!this._resolved) {
|
|
3378
|
+
throw new ConfigError(
|
|
3379
|
+
"renderHocon: unrenderable unresolved substitution (config must be resolved data)",
|
|
3380
|
+
""
|
|
3381
|
+
);
|
|
3382
|
+
}
|
|
3383
|
+
return renderHoconFromRoot(this.root);
|
|
3384
|
+
}
|
|
3040
3385
|
/**
|
|
3041
3386
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
3042
3387
|
* JSON (sorted keys, no whitespace). Used by Layer-2 fixture tests to compare
|