@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/zod.cjs
CHANGED
|
@@ -73,13 +73,22 @@ function coerceNumber(value) {
|
|
|
73
73
|
return Number(value);
|
|
74
74
|
}
|
|
75
75
|
var DURATION_UNITS = {
|
|
76
|
+
// S19.1–S19.3: the bare nano/micro/milli (+plural) aliases are part of the
|
|
77
|
+
// spec's unit lists (HOCON.md L1307–L1309) and accepted by Lightbend
|
|
78
|
+
// (typesafe-config 1.4.6 probe, 2026-08-18); they were missing here.
|
|
76
79
|
ns: 1e-6,
|
|
80
|
+
nano: 1e-6,
|
|
81
|
+
nanos: 1e-6,
|
|
77
82
|
nanosecond: 1e-6,
|
|
78
83
|
nanoseconds: 1e-6,
|
|
79
84
|
us: 1e-3,
|
|
85
|
+
micro: 1e-3,
|
|
86
|
+
micros: 1e-3,
|
|
80
87
|
microsecond: 1e-3,
|
|
81
88
|
microseconds: 1e-3,
|
|
82
89
|
ms: 1,
|
|
90
|
+
milli: 1,
|
|
91
|
+
millis: 1,
|
|
83
92
|
millisecond: 1,
|
|
84
93
|
milliseconds: 1,
|
|
85
94
|
s: 1e3,
|
|
@@ -131,37 +140,76 @@ function parseDuration(value, outputUnit = "ms") {
|
|
|
131
140
|
return ms / divisor;
|
|
132
141
|
}
|
|
133
142
|
var BYTE_UNITS = {
|
|
143
|
+
// S21.1–S21.4 — the EXACT Lightbend/typesafe-config unit set (1.4.6 probe,
|
|
144
|
+
// 2026-08-18). Multi-letter units are case-sensitive: the SI decimal short
|
|
145
|
+
// form is `kB` (NOT `KB`/`kb` — Lightbend rejects both), higher decimals
|
|
146
|
+
// are `MB`…`YB`, binary prefixes are `Ki`/`KiB`…`Yi`/`YiB` with capital
|
|
147
|
+
// first letter, and long forms are lowercase only (`kilobyte`, never
|
|
148
|
+
// `Kilobyte`). Only the bare byte unit (`B`/`b`) and the single-letter
|
|
149
|
+
// -Xmx forms accept both cases. The old case-insensitive fallback and the
|
|
150
|
+
// lowercase alias rows accepted spellings Lightbend rejects — removed.
|
|
134
151
|
B: 1,
|
|
152
|
+
b: 1,
|
|
135
153
|
byte: 1,
|
|
136
154
|
bytes: 1,
|
|
137
|
-
|
|
155
|
+
kB: 1e3,
|
|
138
156
|
kilobyte: 1e3,
|
|
139
157
|
kilobytes: 1e3,
|
|
140
|
-
KiB: 1024,
|
|
141
|
-
kibibyte: 1024,
|
|
142
|
-
kibibytes: 1024,
|
|
143
158
|
MB: 1e6,
|
|
144
159
|
megabyte: 1e6,
|
|
145
160
|
megabytes: 1e6,
|
|
146
|
-
MiB: 1048576,
|
|
147
|
-
mebibyte: 1048576,
|
|
148
|
-
mebibytes: 1048576,
|
|
149
161
|
GB: 1e9,
|
|
150
162
|
gigabyte: 1e9,
|
|
151
163
|
gigabytes: 1e9,
|
|
152
|
-
GiB: 1073741824,
|
|
153
|
-
gibibyte: 1073741824,
|
|
154
|
-
gibibytes: 1073741824,
|
|
155
164
|
TB: 1e12,
|
|
156
165
|
terabyte: 1e12,
|
|
157
166
|
terabytes: 1e12,
|
|
167
|
+
PB: 1e15,
|
|
168
|
+
petabyte: 1e15,
|
|
169
|
+
petabytes: 1e15,
|
|
170
|
+
EB: 1e18,
|
|
171
|
+
exabyte: 1e18,
|
|
172
|
+
exabytes: 1e18,
|
|
173
|
+
ZB: 1e21,
|
|
174
|
+
zettabyte: 1e21,
|
|
175
|
+
zettabytes: 1e21,
|
|
176
|
+
YB: 1e24,
|
|
177
|
+
yottabyte: 1e24,
|
|
178
|
+
yottabytes: 1e24,
|
|
179
|
+
Ki: 1024,
|
|
180
|
+
KiB: 1024,
|
|
181
|
+
kibibyte: 1024,
|
|
182
|
+
kibibytes: 1024,
|
|
183
|
+
Mi: 1048576,
|
|
184
|
+
MiB: 1048576,
|
|
185
|
+
mebibyte: 1048576,
|
|
186
|
+
mebibytes: 1048576,
|
|
187
|
+
Gi: 1073741824,
|
|
188
|
+
GiB: 1073741824,
|
|
189
|
+
gibibyte: 1073741824,
|
|
190
|
+
gibibytes: 1073741824,
|
|
191
|
+
Ti: 1099511627776,
|
|
158
192
|
TiB: 1099511627776,
|
|
159
193
|
tebibyte: 1099511627776,
|
|
160
194
|
tebibytes: 1099511627776,
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
195
|
+
Pi: 1024 ** 5,
|
|
196
|
+
PiB: 1024 ** 5,
|
|
197
|
+
pebibyte: 1024 ** 5,
|
|
198
|
+
pebibytes: 1024 ** 5,
|
|
199
|
+
Ei: 1024 ** 6,
|
|
200
|
+
EiB: 1024 ** 6,
|
|
201
|
+
exbibyte: 1024 ** 6,
|
|
202
|
+
exbibytes: 1024 ** 6,
|
|
203
|
+
Zi: 1024 ** 7,
|
|
204
|
+
ZiB: 1024 ** 7,
|
|
205
|
+
zebibyte: 1024 ** 7,
|
|
206
|
+
zebibytes: 1024 ** 7,
|
|
207
|
+
Yi: 1024 ** 8,
|
|
208
|
+
YiB: 1024 ** 8,
|
|
209
|
+
yobibyte: 1024 ** 8,
|
|
210
|
+
yobibytes: 1024 ** 8,
|
|
211
|
+
// S21.4 — single-letter abbreviations → powers of two (java -Xmx
|
|
212
|
+
// convention); Lightbend accepts BOTH cases here, through the full ladder.
|
|
165
213
|
K: 1024,
|
|
166
214
|
k: 1024,
|
|
167
215
|
M: 1024 ** 2,
|
|
@@ -174,16 +222,10 @@ var BYTE_UNITS = {
|
|
|
174
222
|
p: 1024 ** 5,
|
|
175
223
|
E: 1024 ** 6,
|
|
176
224
|
e: 1024 ** 6,
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
mb: 1e6,
|
|
182
|
-
mib: 1048576,
|
|
183
|
-
gb: 1e9,
|
|
184
|
-
gib: 1073741824,
|
|
185
|
-
tb: 1e12,
|
|
186
|
-
tib: 1099511627776
|
|
225
|
+
Z: 1024 ** 7,
|
|
226
|
+
z: 1024 ** 7,
|
|
227
|
+
Y: 1024 ** 8,
|
|
228
|
+
y: 1024 ** 8
|
|
187
229
|
};
|
|
188
230
|
var OUTPUT_BYTE_UNITS = {
|
|
189
231
|
B: 1,
|
|
@@ -221,10 +263,7 @@ function parseBytes(value, outputUnit = "B") {
|
|
|
221
263
|
}
|
|
222
264
|
return bytes2 / divisor;
|
|
223
265
|
}
|
|
224
|
-
|
|
225
|
-
if (mult === void 0) {
|
|
226
|
-
mult = BYTE_UNITS[unit.toLowerCase()];
|
|
227
|
-
}
|
|
266
|
+
const mult = BYTE_UNITS[unit];
|
|
228
267
|
if (mult === void 0) return NaN;
|
|
229
268
|
const bytes = num * mult;
|
|
230
269
|
if (Math.abs(bytes) > Number.MAX_SAFE_INTEGER) {
|
|
@@ -292,35 +331,114 @@ function stringSegmentsToKey(segments) {
|
|
|
292
331
|
return t;
|
|
293
332
|
}).join(".");
|
|
294
333
|
}
|
|
334
|
+
function prefixSelfRefRemainder(s, fullKey) {
|
|
335
|
+
const texts = s.segments.map((seg) => seg.text);
|
|
336
|
+
if (!stringSegmentsToKey(texts).startsWith(fullKey + ".")) return null;
|
|
337
|
+
for (let n = 1; n < texts.length; n++) {
|
|
338
|
+
if (stringSegmentsToKey(texts.slice(0, n)) === fullKey) return texts.slice(n);
|
|
339
|
+
}
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
function navigateResolverValue(v, remainder) {
|
|
343
|
+
let cur = v;
|
|
344
|
+
for (const seg of remainder) {
|
|
345
|
+
if (isSubst(cur) || isConcat(cur)) return null;
|
|
346
|
+
if (isResObj(cur)) {
|
|
347
|
+
const next = cur.fields.get(seg);
|
|
348
|
+
if (next === void 0) return void 0;
|
|
349
|
+
cur = next;
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
const hv = cur;
|
|
353
|
+
if (hv.kind === "object") {
|
|
354
|
+
const next = hv.fields.get(seg);
|
|
355
|
+
if (next === void 0) return void 0;
|
|
356
|
+
cur = next;
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
return void 0;
|
|
360
|
+
}
|
|
361
|
+
return cur;
|
|
362
|
+
}
|
|
363
|
+
function foldPrefixSelfRef(s, replacement, remainder) {
|
|
364
|
+
const navigated = navigateResolverValue(replacement, remainder);
|
|
365
|
+
if (navigated === null) return s;
|
|
366
|
+
if (navigated === void 0) {
|
|
367
|
+
return {
|
|
368
|
+
_kind: "subst-placeholder",
|
|
369
|
+
segments: s.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
|
|
370
|
+
optional: s.optional,
|
|
371
|
+
knownAbsent: true,
|
|
372
|
+
listSuffix: s.listSuffix,
|
|
373
|
+
line: s.line,
|
|
374
|
+
col: s.col,
|
|
375
|
+
prefixLen: s.prefixLen
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
return cloneResolverValue(navigated);
|
|
379
|
+
}
|
|
380
|
+
function mergeResObjLayers(base, top) {
|
|
381
|
+
const fields = new Map(base.fields);
|
|
382
|
+
for (const [k, tv] of top.fields) {
|
|
383
|
+
const bv = fields.get(k);
|
|
384
|
+
if (bv !== void 0 && isResObj(bv) && isResObj(tv)) {
|
|
385
|
+
fields.set(k, mergeResObjLayers(bv, tv));
|
|
386
|
+
} else {
|
|
387
|
+
fields.set(k, tv);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
const priorValues = new Map(base.priorValues);
|
|
391
|
+
for (const [k, pv] of top.priorValues) priorValues.set(k, pv);
|
|
392
|
+
const resetKeys = new Set(base.resetKeys);
|
|
393
|
+
for (const k of top.resetKeys) resetKeys.add(k);
|
|
394
|
+
return {
|
|
395
|
+
_kind: "res-obj",
|
|
396
|
+
fields,
|
|
397
|
+
priorValues,
|
|
398
|
+
resetKeys
|
|
399
|
+
};
|
|
400
|
+
}
|
|
295
401
|
function containsSelfRef(v, fullKey) {
|
|
296
|
-
|
|
297
|
-
|
|
402
|
+
return containsSelfRefInner(v, fullKey, true);
|
|
403
|
+
}
|
|
404
|
+
function containsSelfRefInner(v, fullKey, allowPrefix) {
|
|
405
|
+
if (isSubst(v))
|
|
406
|
+
return !v.knownAbsent && (substFullKey(v) === fullKey || allowPrefix && prefixSelfRefRemainder(v, fullKey) !== null);
|
|
407
|
+
if (isConcat(v)) return v.nodes.some((n) => containsSelfRefInner(n, fullKey, allowPrefix));
|
|
298
408
|
if (isResObj(v)) {
|
|
299
409
|
for (const f of v.fields.values()) {
|
|
300
|
-
if (
|
|
410
|
+
if (containsSelfRefInner(f, fullKey, false)) return true;
|
|
301
411
|
}
|
|
302
412
|
return false;
|
|
303
413
|
}
|
|
304
414
|
const hv = v;
|
|
305
415
|
if (hv.kind === "array") {
|
|
306
|
-
return hv.items.some((item) =>
|
|
416
|
+
return hv.items.some((item) => containsSelfRefInner(item, fullKey, allowPrefix));
|
|
307
417
|
}
|
|
308
418
|
if (hv.kind === "object") {
|
|
309
419
|
for (const f of hv.fields.values()) {
|
|
310
|
-
if (
|
|
420
|
+
if (containsSelfRefInner(f, fullKey, false)) return true;
|
|
311
421
|
}
|
|
312
422
|
return false;
|
|
313
423
|
}
|
|
314
424
|
return false;
|
|
315
425
|
}
|
|
316
426
|
function foldSelfRef(v, fullKey, replacement) {
|
|
427
|
+
return foldSelfRefInner(v, fullKey, replacement, true);
|
|
428
|
+
}
|
|
429
|
+
function foldSelfRefInner(v, fullKey, replacement, allowPrefix) {
|
|
317
430
|
if (isSubst(v)) {
|
|
318
|
-
|
|
431
|
+
if (substFullKey(v) === fullKey) return replacement;
|
|
432
|
+
if (allowPrefix) {
|
|
433
|
+
const remainder = prefixSelfRefRemainder(v, fullKey);
|
|
434
|
+
if (remainder !== null) return foldPrefixSelfRef(v, replacement, remainder);
|
|
435
|
+
}
|
|
436
|
+
return v;
|
|
319
437
|
}
|
|
320
438
|
if (isConcat(v)) {
|
|
321
439
|
return {
|
|
322
440
|
_kind: "concat-placeholder",
|
|
323
|
-
nodes: v.nodes.map((n) =>
|
|
441
|
+
nodes: v.nodes.map((n) => foldSelfRefInner(n, fullKey, replacement, allowPrefix)),
|
|
324
442
|
line: v.line,
|
|
325
443
|
col: v.col
|
|
326
444
|
};
|
|
@@ -328,7 +446,7 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
328
446
|
if (isResObj(v)) {
|
|
329
447
|
const newFields = /* @__PURE__ */ new Map();
|
|
330
448
|
for (const [k, val] of v.fields) {
|
|
331
|
-
newFields.set(k,
|
|
449
|
+
newFields.set(k, foldSelfRefInner(val, fullKey, replacement, false));
|
|
332
450
|
}
|
|
333
451
|
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
334
452
|
}
|
|
@@ -336,13 +454,15 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
336
454
|
if (hv.kind === "array") {
|
|
337
455
|
return {
|
|
338
456
|
kind: "array",
|
|
339
|
-
items: hv.items.map(
|
|
457
|
+
items: hv.items.map(
|
|
458
|
+
(item) => foldSelfRefInner(item, fullKey, replacement, allowPrefix)
|
|
459
|
+
)
|
|
340
460
|
};
|
|
341
461
|
}
|
|
342
462
|
if (hv.kind === "object") {
|
|
343
463
|
const newFields = /* @__PURE__ */ new Map();
|
|
344
464
|
for (const [k, val] of hv.fields) {
|
|
345
|
-
newFields.set(k,
|
|
465
|
+
newFields.set(k, foldSelfRefInner(val, fullKey, replacement, false));
|
|
346
466
|
}
|
|
347
467
|
return { kind: "object", fields: newFields };
|
|
348
468
|
}
|
|
@@ -386,10 +506,26 @@ function foldKnownAbsentSelfRef(v, fullKey, replacement) {
|
|
|
386
506
|
function foldOrSkipPrior(prior, fullKey, old) {
|
|
387
507
|
if (!containsSelfRef(prior, fullKey)) return cloneResolverValue(prior);
|
|
388
508
|
if (old === void 0) return foldOptionalSelfRefAbsent(prior, fullKey);
|
|
509
|
+
if (isSubst(prior)) {
|
|
510
|
+
const remainder = prefixSelfRefRemainder(prior, fullKey);
|
|
511
|
+
if (remainder !== null) {
|
|
512
|
+
const navigated = navigateResolverValue(old, remainder);
|
|
513
|
+
if (navigated === void 0 && prior.optional) return cloneResolverValue(old);
|
|
514
|
+
if (navigated !== null && navigated !== void 0 && isResObj(navigated) && isResObj(old)) {
|
|
515
|
+
return mergeResObjLayers(
|
|
516
|
+
cloneResolverValue(old),
|
|
517
|
+
cloneResolverValue(navigated)
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
389
522
|
return foldSelfRef(prior, fullKey, old);
|
|
390
523
|
}
|
|
391
524
|
function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
392
|
-
|
|
525
|
+
return foldOptionalSelfRefAbsentInner(v, fullKey, true);
|
|
526
|
+
}
|
|
527
|
+
function foldOptionalSelfRefAbsentInner(v, fullKey, allowPrefix) {
|
|
528
|
+
if (isSubst(v) && (substFullKey(v) === fullKey || allowPrefix && prefixSelfRefRemainder(v, fullKey) !== null)) {
|
|
393
529
|
if (!v.optional) return void 0;
|
|
394
530
|
return {
|
|
395
531
|
_kind: "subst-placeholder",
|
|
@@ -405,7 +541,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
405
541
|
if (isConcat(v)) {
|
|
406
542
|
const nodes = [];
|
|
407
543
|
for (const node of v.nodes) {
|
|
408
|
-
const folded =
|
|
544
|
+
const folded = foldOptionalSelfRefAbsentInner(node, fullKey, allowPrefix);
|
|
409
545
|
if (folded === void 0) return void 0;
|
|
410
546
|
nodes.push(folded);
|
|
411
547
|
}
|
|
@@ -414,7 +550,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
414
550
|
if (isResObj(v)) {
|
|
415
551
|
const fields = /* @__PURE__ */ new Map();
|
|
416
552
|
for (const [key, value] of v.fields) {
|
|
417
|
-
const folded =
|
|
553
|
+
const folded = foldOptionalSelfRefAbsentInner(value, fullKey, false);
|
|
418
554
|
if (folded === void 0) return void 0;
|
|
419
555
|
fields.set(key, folded);
|
|
420
556
|
}
|
|
@@ -424,7 +560,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
424
560
|
if (hv.kind === "array") {
|
|
425
561
|
const items = [];
|
|
426
562
|
for (const item of hv.items) {
|
|
427
|
-
const folded =
|
|
563
|
+
const folded = foldOptionalSelfRefAbsentInner(item, fullKey, allowPrefix);
|
|
428
564
|
if (folded === void 0) return void 0;
|
|
429
565
|
items.push(folded);
|
|
430
566
|
}
|
|
@@ -433,7 +569,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
433
569
|
if (hv.kind === "object") {
|
|
434
570
|
const fields = /* @__PURE__ */ new Map();
|
|
435
571
|
for (const [key, value] of hv.fields) {
|
|
436
|
-
const folded =
|
|
572
|
+
const folded = foldOptionalSelfRefAbsentInner(value, fullKey, false);
|
|
437
573
|
if (folded === void 0) return void 0;
|
|
438
574
|
fields.set(key, folded);
|
|
439
575
|
}
|
|
@@ -806,7 +942,6 @@ var Lexer = class {
|
|
|
806
942
|
if (!closed) {
|
|
807
943
|
throw new ParseError("unterminated triple-quoted string", sl, sc);
|
|
808
944
|
}
|
|
809
|
-
if (value.startsWith("\n")) value = value.slice(1);
|
|
810
945
|
this.push("triple_string", value, sl, sc, true);
|
|
811
946
|
continue;
|
|
812
947
|
}
|
|
@@ -1123,9 +1258,9 @@ var Parser = class {
|
|
|
1123
1258
|
}
|
|
1124
1259
|
}
|
|
1125
1260
|
this.skip("newline");
|
|
1126
|
-
const
|
|
1127
|
-
if (
|
|
1128
|
-
throw new ParseError(`Unexpected token '${
|
|
1261
|
+
const remaining2 = this.peek();
|
|
1262
|
+
if (remaining2.kind !== "eof") {
|
|
1263
|
+
throw new ParseError(`Unexpected token '${remaining2.value}' after closing brace`, remaining2.line, remaining2.col);
|
|
1129
1264
|
}
|
|
1130
1265
|
return { kind: "object", fields: allFields, pos: first.pos };
|
|
1131
1266
|
}
|
|
@@ -1133,13 +1268,19 @@ var Parser = class {
|
|
|
1133
1268
|
this.advance();
|
|
1134
1269
|
const arr = this.parseArray();
|
|
1135
1270
|
this.skip("newline");
|
|
1136
|
-
const
|
|
1137
|
-
if (
|
|
1138
|
-
throw new ParseError(`Unexpected token '${
|
|
1271
|
+
const remaining2 = this.peek();
|
|
1272
|
+
if (remaining2.kind !== "eof") {
|
|
1273
|
+
throw new ParseError(`Unexpected token '${remaining2.value}' after root array`, remaining2.line, remaining2.col);
|
|
1139
1274
|
}
|
|
1140
1275
|
return { ...arr, pos: { line: t.line, col: t.col } };
|
|
1141
1276
|
}
|
|
1142
|
-
|
|
1277
|
+
const root = this.parseObject(false);
|
|
1278
|
+
this.skip("newline");
|
|
1279
|
+
const remaining = this.peek();
|
|
1280
|
+
if (remaining.kind !== "eof") {
|
|
1281
|
+
throw new ParseError(`Unexpected token '${remaining.value}' after root content`, remaining.line, remaining.col);
|
|
1282
|
+
}
|
|
1283
|
+
return root;
|
|
1143
1284
|
}
|
|
1144
1285
|
peek(offset = 0) {
|
|
1145
1286
|
return this.tokens[this.pos + offset] ?? EOF_TOKEN;
|
|
@@ -2286,6 +2427,12 @@ var SubstitutionResolver = class {
|
|
|
2286
2427
|
// Cross-impl with rs.hocon v1.5.1's resolving_field_path (same purpose,
|
|
2287
2428
|
// same prefix-match semantics).
|
|
2288
2429
|
this.resolvingFieldPath = [];
|
|
2430
|
+
// S13a.12 recursion guard: field keys whose prior is currently being
|
|
2431
|
+
// resolved through the prefix-self-ref branch. Saved priors are
|
|
2432
|
+
// prefix-self-ref-free by the fold invariant, so re-entry only happens on
|
|
2433
|
+
// a shape the fold could not see through (a live subst mid-navigation) —
|
|
2434
|
+
// report it as a cycle instead of recursing forever.
|
|
2435
|
+
this.resolvingPrefixPriors = /* @__PURE__ */ new Set();
|
|
2289
2436
|
}
|
|
2290
2437
|
/** Returns a prefix for error messages, including origin info when set. */
|
|
2291
2438
|
originPrefix() {
|
|
@@ -2300,46 +2447,57 @@ var SubstitutionResolver = class {
|
|
|
2300
2447
|
this.resolvingFieldPath.push(key);
|
|
2301
2448
|
const fullCacheKey = stringSegmentsToKey(this.resolvingFieldPath);
|
|
2302
2449
|
this.cache.delete(fullCacheKey);
|
|
2303
|
-
let resolved;
|
|
2304
2450
|
try {
|
|
2305
|
-
resolved = this.resolveVal(val, obj);
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2451
|
+
const resolved = this.resolveVal(val, obj);
|
|
2452
|
+
if (resolved !== void 0) {
|
|
2453
|
+
if (resolved.kind === "object") {
|
|
2454
|
+
const prior = obj.priorValues.get(key);
|
|
2455
|
+
if (prior !== void 0) {
|
|
2456
|
+
const priorResolved = this.resolveVal(prior, obj);
|
|
2457
|
+
if (priorResolved !== void 0 && priorResolved.kind === "object") {
|
|
2458
|
+
const finalValue = deepMergeHoconValues(
|
|
2459
|
+
priorResolved,
|
|
2460
|
+
resolved
|
|
2461
|
+
);
|
|
2462
|
+
result.set(key, finalValue);
|
|
2463
|
+
this.cache.set(fullCacheKey, finalValue);
|
|
2464
|
+
this.cacheDescendants(fullCacheKey, finalValue);
|
|
2465
|
+
continue;
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
result.set(key, resolved);
|
|
2470
|
+
this.cache.set(fullCacheKey, resolved);
|
|
2471
|
+
this.cacheDescendants(fullCacheKey, resolved);
|
|
2472
|
+
} else {
|
|
2311
2473
|
const prior = obj.priorValues.get(key);
|
|
2312
2474
|
if (prior !== void 0) {
|
|
2313
2475
|
const priorResolved = this.resolveVal(prior, obj);
|
|
2314
|
-
if (priorResolved !== void 0
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
);
|
|
2319
|
-
result.set(key, finalValue);
|
|
2320
|
-
this.cache.set(fullCacheKey, finalValue);
|
|
2321
|
-
this.cacheDescendants(fullCacheKey, finalValue);
|
|
2322
|
-
continue;
|
|
2476
|
+
if (priorResolved !== void 0) {
|
|
2477
|
+
result.set(key, priorResolved);
|
|
2478
|
+
this.cache.set(fullCacheKey, priorResolved);
|
|
2479
|
+
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
2323
2480
|
}
|
|
2324
2481
|
}
|
|
2325
2482
|
}
|
|
2326
|
-
|
|
2327
|
-
this.
|
|
2328
|
-
this.cacheDescendants(fullCacheKey, resolved);
|
|
2329
|
-
} else {
|
|
2330
|
-
const prior = obj.priorValues.get(key);
|
|
2331
|
-
if (prior !== void 0) {
|
|
2332
|
-
const priorResolved = this.resolveVal(prior, obj);
|
|
2333
|
-
if (priorResolved !== void 0) {
|
|
2334
|
-
result.set(key, priorResolved);
|
|
2335
|
-
this.cache.set(fullCacheKey, priorResolved);
|
|
2336
|
-
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
2337
|
-
}
|
|
2338
|
-
}
|
|
2483
|
+
} finally {
|
|
2484
|
+
this.resolvingFieldPath.pop();
|
|
2339
2485
|
}
|
|
2340
2486
|
}
|
|
2341
2487
|
return { kind: "object", fields: result };
|
|
2342
2488
|
}
|
|
2489
|
+
/** S13a.12: walk resolved-object fields by segment text. A missing segment
|
|
2490
|
+
* or a walk into a scalar/array is path-absent → undefined. */
|
|
2491
|
+
navigateResolved(v, remainder) {
|
|
2492
|
+
let cur = v;
|
|
2493
|
+
for (const seg of remainder) {
|
|
2494
|
+
if (cur.kind !== "object") return void 0;
|
|
2495
|
+
const next = cur.fields.get(seg);
|
|
2496
|
+
if (next === void 0) return void 0;
|
|
2497
|
+
cur = next;
|
|
2498
|
+
}
|
|
2499
|
+
return cur;
|
|
2500
|
+
}
|
|
2343
2501
|
cacheDescendants(prefix, value) {
|
|
2344
2502
|
if (value.kind !== "object") return;
|
|
2345
2503
|
for (const [key, child] of value.fields) {
|
|
@@ -2362,17 +2520,59 @@ var SubstitutionResolver = class {
|
|
|
2362
2520
|
if (isResObj(v)) return this.resolveResObj(v);
|
|
2363
2521
|
const hv = v;
|
|
2364
2522
|
if (hv.kind === "array") {
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
)
|
|
2370
|
-
}
|
|
2523
|
+
const items = [];
|
|
2524
|
+
for (const item of hv.items) {
|
|
2525
|
+
const resolved = this.resolveVal(item, scope);
|
|
2526
|
+
if (resolved === void 0) continue;
|
|
2527
|
+
items.push(resolved);
|
|
2528
|
+
}
|
|
2529
|
+
return { kind: "array", items };
|
|
2371
2530
|
}
|
|
2372
2531
|
return hv;
|
|
2373
2532
|
}
|
|
2374
2533
|
resolveSubst(s, scope) {
|
|
2375
|
-
if (s.knownAbsent)
|
|
2534
|
+
if (s.knownAbsent) {
|
|
2535
|
+
if (!s.optional) {
|
|
2536
|
+
if (this.opts.allowUnresolved) return s;
|
|
2537
|
+
const k = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
2538
|
+
throw new ResolveError(
|
|
2539
|
+
`${this.originPrefix()}could not resolve substitution: \${${k}}`,
|
|
2540
|
+
k,
|
|
2541
|
+
s.line,
|
|
2542
|
+
s.col
|
|
2543
|
+
);
|
|
2544
|
+
}
|
|
2545
|
+
return void 0;
|
|
2546
|
+
}
|
|
2547
|
+
{
|
|
2548
|
+
const rfp = this.resolvingFieldPath;
|
|
2549
|
+
const sTexts = s.segments.map((seg) => seg.text);
|
|
2550
|
+
if (rfp.length > 0 && rfp.length < sTexts.length && stringSegmentsToKey(sTexts.slice(0, rfp.length)) === stringSegmentsToKey(rfp)) {
|
|
2551
|
+
const guardKey = stringSegmentsToKey(rfp);
|
|
2552
|
+
const prior = scope.priorValues.get(rfp[rfp.length - 1]);
|
|
2553
|
+
if (prior !== void 0 && !this.resolvingPrefixPriors.has(guardKey)) {
|
|
2554
|
+
this.resolvingPrefixPriors.add(guardKey);
|
|
2555
|
+
try {
|
|
2556
|
+
const priorResolved = this.resolveVal(prior, scope);
|
|
2557
|
+
if (priorResolved !== void 0) {
|
|
2558
|
+
const navigated = this.navigateResolved(priorResolved, sTexts.slice(rfp.length));
|
|
2559
|
+
if (navigated !== void 0) return navigated;
|
|
2560
|
+
}
|
|
2561
|
+
} finally {
|
|
2562
|
+
this.resolvingPrefixPriors.delete(guardKey);
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
if (s.optional) return void 0;
|
|
2566
|
+
if (this.opts.allowUnresolved) return s;
|
|
2567
|
+
const k = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
2568
|
+
throw new ResolveError(
|
|
2569
|
+
`${this.originPrefix()}could not resolve substitution: \${${k}}`,
|
|
2570
|
+
k,
|
|
2571
|
+
s.line,
|
|
2572
|
+
s.col
|
|
2573
|
+
);
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2376
2576
|
const key = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
2377
2577
|
if (this.cache.has(key)) return this.cache.get(key);
|
|
2378
2578
|
if (this.resolving.has(key)) {
|
|
@@ -2699,6 +2899,121 @@ function resolve2(ast, opts) {
|
|
|
2699
2899
|
return resolveTree(tree, { ...opts, useSystemEnvironment: true, allowUnresolved: false });
|
|
2700
2900
|
}
|
|
2701
2901
|
|
|
2902
|
+
// src/render-hocon.ts
|
|
2903
|
+
function renderHoconFromRoot(root) {
|
|
2904
|
+
const out = [];
|
|
2905
|
+
renderObjectBody(out, root, 0);
|
|
2906
|
+
return out.join("");
|
|
2907
|
+
}
|
|
2908
|
+
function renderObjectBody(out, o, depth) {
|
|
2909
|
+
const indent = " ".repeat(depth);
|
|
2910
|
+
for (const [k, v] of o.fields) {
|
|
2911
|
+
out.push(indent, renderKey(k));
|
|
2912
|
+
if (v.kind === "object") {
|
|
2913
|
+
out.push(" {");
|
|
2914
|
+
if (v.fields.size === 0) {
|
|
2915
|
+
out.push("}\n");
|
|
2916
|
+
continue;
|
|
2917
|
+
}
|
|
2918
|
+
out.push("\n");
|
|
2919
|
+
renderObjectBody(out, v, depth + 1);
|
|
2920
|
+
out.push(indent, "}\n");
|
|
2921
|
+
} else {
|
|
2922
|
+
out.push(" = ");
|
|
2923
|
+
renderValue(out, v, depth);
|
|
2924
|
+
out.push("\n");
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
function renderValue(out, v, depth) {
|
|
2929
|
+
switch (v.kind) {
|
|
2930
|
+
case "object": {
|
|
2931
|
+
if (v.fields.size === 0) {
|
|
2932
|
+
out.push("{}");
|
|
2933
|
+
return;
|
|
2934
|
+
}
|
|
2935
|
+
out.push("{\n");
|
|
2936
|
+
renderObjectBody(out, v, depth + 1);
|
|
2937
|
+
out.push(" ".repeat(depth), "}");
|
|
2938
|
+
return;
|
|
2939
|
+
}
|
|
2940
|
+
case "array":
|
|
2941
|
+
renderArray(out, v, depth);
|
|
2942
|
+
return;
|
|
2943
|
+
case "scalar":
|
|
2944
|
+
out.push(renderScalar(v));
|
|
2945
|
+
return;
|
|
2946
|
+
default:
|
|
2947
|
+
throw new ConfigError(
|
|
2948
|
+
"renderHocon: unrenderable value (config must be resolved data)",
|
|
2949
|
+
""
|
|
2950
|
+
);
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
function renderArray(out, a, depth) {
|
|
2954
|
+
if (a.items.length === 0) {
|
|
2955
|
+
out.push("[]");
|
|
2956
|
+
return;
|
|
2957
|
+
}
|
|
2958
|
+
const inner = " ".repeat(depth + 1);
|
|
2959
|
+
out.push("[\n");
|
|
2960
|
+
for (const e of a.items) {
|
|
2961
|
+
out.push(inner);
|
|
2962
|
+
renderValue(out, e, depth + 1);
|
|
2963
|
+
out.push("\n");
|
|
2964
|
+
}
|
|
2965
|
+
out.push(" ".repeat(depth), "]");
|
|
2966
|
+
}
|
|
2967
|
+
function renderScalar(s) {
|
|
2968
|
+
switch (s.valueType) {
|
|
2969
|
+
case "null":
|
|
2970
|
+
return "null";
|
|
2971
|
+
case "boolean":
|
|
2972
|
+
case "number":
|
|
2973
|
+
return s.raw;
|
|
2974
|
+
case "string":
|
|
2975
|
+
return renderString(s.raw);
|
|
2976
|
+
}
|
|
2977
|
+
}
|
|
2978
|
+
var SAFE_UNQUOTED_KEY = /^[A-Za-z0-9_-]+$/;
|
|
2979
|
+
function renderKey(k) {
|
|
2980
|
+
if (k === "include") return quoteString(k);
|
|
2981
|
+
return SAFE_UNQUOTED_KEY.test(k) ? k : quoteString(k);
|
|
2982
|
+
}
|
|
2983
|
+
var SAFE_BARE_STRING = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
2984
|
+
var STRING_KEYWORDS = /* @__PURE__ */ new Set(["true", "false", "null", "yes", "no", "on", "off"]);
|
|
2985
|
+
function renderString(s) {
|
|
2986
|
+
return SAFE_BARE_STRING.test(s) && !STRING_KEYWORDS.has(s.toLowerCase()) ? s : quoteString(s);
|
|
2987
|
+
}
|
|
2988
|
+
function quoteString(s) {
|
|
2989
|
+
if (s.includes("\n") && !s.includes("\r") && !s.includes('"""') && !s.endsWith('"')) {
|
|
2990
|
+
return `"""${s}"""`;
|
|
2991
|
+
}
|
|
2992
|
+
let b = '"';
|
|
2993
|
+
for (const ch of s) {
|
|
2994
|
+
switch (ch) {
|
|
2995
|
+
case '"':
|
|
2996
|
+
b += '\\"';
|
|
2997
|
+
break;
|
|
2998
|
+
case "\\":
|
|
2999
|
+
b += "\\\\";
|
|
3000
|
+
break;
|
|
3001
|
+
case "\n":
|
|
3002
|
+
b += "\\n";
|
|
3003
|
+
break;
|
|
3004
|
+
case "\r":
|
|
3005
|
+
b += "\\r";
|
|
3006
|
+
break;
|
|
3007
|
+
case " ":
|
|
3008
|
+
b += "\\t";
|
|
3009
|
+
break;
|
|
3010
|
+
default:
|
|
3011
|
+
b += ch;
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
3014
|
+
return b + '"';
|
|
3015
|
+
}
|
|
3016
|
+
|
|
2702
3017
|
// src/config.ts
|
|
2703
3018
|
var Config = class _Config {
|
|
2704
3019
|
constructor(root, opts) {
|
|
@@ -3004,6 +3319,36 @@ var Config = class _Config {
|
|
|
3004
3319
|
toObject(opts) {
|
|
3005
3320
|
return hoconToJs(this.root, opts?.nullPrototype === true);
|
|
3006
3321
|
}
|
|
3322
|
+
/**
|
|
3323
|
+
* Renders this resolved Config as HOCON text (E18; lockstep with go.hocon's
|
|
3324
|
+
* `Config.RenderHOCON`, v1.11.0).
|
|
3325
|
+
*
|
|
3326
|
+
* The output round-trips: parsing it back yields the same value tree. That
|
|
3327
|
+
* is the correctness contract, not byte-for-byte formatting — a scalar is
|
|
3328
|
+
* quoted whenever leaving it bare would re-parse as a different type (a
|
|
3329
|
+
* string `"8080"` becomes `"8080"`, not `8080`), and left bare only when it
|
|
3330
|
+
* provably cannot.
|
|
3331
|
+
*
|
|
3332
|
+
* The Config must be resolved and hold only data (objects, arrays, string /
|
|
3333
|
+
* number / boolean / null scalars) — exactly what {@link fromMap} and the
|
|
3334
|
+
* format adapters produce. An unresolved placeholder throws
|
|
3335
|
+
* {@link ConfigError}; substitutions have no textual round trip through a
|
|
3336
|
+
* value tree.
|
|
3337
|
+
*
|
|
3338
|
+
* The root object's fields are emitted without enclosing braces, nested
|
|
3339
|
+
* objects as `key { … }`, arrays as newline-separated `[ … ]`, indented two
|
|
3340
|
+
* spaces. Source comments are not represented — a value tree does not carry
|
|
3341
|
+
* them.
|
|
3342
|
+
*/
|
|
3343
|
+
renderHocon() {
|
|
3344
|
+
if (!this._resolved) {
|
|
3345
|
+
throw new ConfigError(
|
|
3346
|
+
"renderHocon: unrenderable unresolved substitution (config must be resolved data)",
|
|
3347
|
+
""
|
|
3348
|
+
);
|
|
3349
|
+
}
|
|
3350
|
+
return renderHoconFromRoot(this.root);
|
|
3351
|
+
}
|
|
3007
3352
|
/**
|
|
3008
3353
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
3009
3354
|
* JSON (sorted keys, no whitespace). Used by Layer-2 fixture tests to compare
|