@o3co/ts.hocon 1.11.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 +19 -10
- package/dist/adapters/env.cjs +471 -82
- package/dist/adapters/env.d.cts +1 -1
- package/dist/adapters/env.d.ts +1 -1
- package/dist/adapters/env.js +471 -82
- 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 +448 -81
- package/dist/adapters/jsonc.d.cts +13 -2
- package/dist/adapters/jsonc.d.ts +13 -2
- package/dist/adapters/jsonc.js +448 -81
- package/dist/adapters/properties.cjs +457 -81
- package/dist/adapters/properties.d.cts +1 -1
- package/dist/adapters/properties.d.ts +1 -1
- package/dist/adapters/properties.js +457 -81
- package/dist/adapters/toml.cjs +451 -81
- package/dist/adapters/toml.d.cts +3 -2
- package/dist/adapters/toml.d.ts +3 -2
- package/dist/adapters/toml.js +451 -81
- package/dist/adapters/yaml.cjs +461 -82
- package/dist/adapters/yaml.d.cts +3 -2
- package/dist/adapters/yaml.d.ts +3 -2
- package/dist/adapters/yaml.js +461 -82
- 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 +491 -97
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +491 -97
- package/dist/zod.cjs +486 -91
- package/dist/zod.d.cts +1 -1
- package/dist/zod.d.ts +1 -1
- package/dist/zod.js +486 -91
- 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;
|
|
@@ -1530,6 +1671,28 @@ function stripBom(input) {
|
|
|
1530
1671
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
1531
1672
|
}
|
|
1532
1673
|
|
|
1674
|
+
// src/internal/depth.ts
|
|
1675
|
+
var MAX_PATH_SEGMENTS = 64;
|
|
1676
|
+
function tooDeep(segments) {
|
|
1677
|
+
return segments > MAX_PATH_SEGMENTS;
|
|
1678
|
+
}
|
|
1679
|
+
function guardStackDepth(fn, wrap) {
|
|
1680
|
+
try {
|
|
1681
|
+
return fn();
|
|
1682
|
+
} catch (e) {
|
|
1683
|
+
if (!isStackOverflow(e)) throw e;
|
|
1684
|
+
throw wrap(STACK_MESSAGE);
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
1688
|
+
function isStackOverflow(e) {
|
|
1689
|
+
if (!(e instanceof RangeError)) return false;
|
|
1690
|
+
const m = e.message.toLowerCase();
|
|
1691
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
1692
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
1693
|
+
m.includes("stack overflow");
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1533
1696
|
// src/internal/properties/properties.ts
|
|
1534
1697
|
function parseProperties(input) {
|
|
1535
1698
|
const pairs = [];
|
|
@@ -1537,7 +1700,15 @@ function parseProperties(input) {
|
|
|
1537
1700
|
const [rawKey, rawValue] = splitKeyValue(text);
|
|
1538
1701
|
const key = unescapeProps(rawKey, line);
|
|
1539
1702
|
if (key === "") continue;
|
|
1540
|
-
|
|
1703
|
+
const segments = key.split(".");
|
|
1704
|
+
if (tooDeep(segments.length)) {
|
|
1705
|
+
throw new ParseError(
|
|
1706
|
+
`key maps to a path ${segments.length} segments deep, over the limit of ${MAX_PATH_SEGMENTS}`,
|
|
1707
|
+
line,
|
|
1708
|
+
1
|
|
1709
|
+
);
|
|
1710
|
+
}
|
|
1711
|
+
pairs.push([segments, unescapeProps(rawValue, line)]);
|
|
1541
1712
|
}
|
|
1542
1713
|
return nestPairs(pairs);
|
|
1543
1714
|
}
|
|
@@ -2256,6 +2427,12 @@ var SubstitutionResolver = class {
|
|
|
2256
2427
|
// Cross-impl with rs.hocon v1.5.1's resolving_field_path (same purpose,
|
|
2257
2428
|
// same prefix-match semantics).
|
|
2258
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();
|
|
2259
2436
|
}
|
|
2260
2437
|
/** Returns a prefix for error messages, including origin info when set. */
|
|
2261
2438
|
originPrefix() {
|
|
@@ -2270,46 +2447,57 @@ var SubstitutionResolver = class {
|
|
|
2270
2447
|
this.resolvingFieldPath.push(key);
|
|
2271
2448
|
const fullCacheKey = stringSegmentsToKey(this.resolvingFieldPath);
|
|
2272
2449
|
this.cache.delete(fullCacheKey);
|
|
2273
|
-
let resolved;
|
|
2274
2450
|
try {
|
|
2275
|
-
resolved = this.resolveVal(val, obj);
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
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 {
|
|
2281
2473
|
const prior = obj.priorValues.get(key);
|
|
2282
2474
|
if (prior !== void 0) {
|
|
2283
2475
|
const priorResolved = this.resolveVal(prior, obj);
|
|
2284
|
-
if (priorResolved !== void 0
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
);
|
|
2289
|
-
result.set(key, finalValue);
|
|
2290
|
-
this.cache.set(fullCacheKey, finalValue);
|
|
2291
|
-
this.cacheDescendants(fullCacheKey, finalValue);
|
|
2292
|
-
continue;
|
|
2476
|
+
if (priorResolved !== void 0) {
|
|
2477
|
+
result.set(key, priorResolved);
|
|
2478
|
+
this.cache.set(fullCacheKey, priorResolved);
|
|
2479
|
+
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
2293
2480
|
}
|
|
2294
2481
|
}
|
|
2295
2482
|
}
|
|
2296
|
-
|
|
2297
|
-
this.
|
|
2298
|
-
this.cacheDescendants(fullCacheKey, resolved);
|
|
2299
|
-
} else {
|
|
2300
|
-
const prior = obj.priorValues.get(key);
|
|
2301
|
-
if (prior !== void 0) {
|
|
2302
|
-
const priorResolved = this.resolveVal(prior, obj);
|
|
2303
|
-
if (priorResolved !== void 0) {
|
|
2304
|
-
result.set(key, priorResolved);
|
|
2305
|
-
this.cache.set(fullCacheKey, priorResolved);
|
|
2306
|
-
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
2307
|
-
}
|
|
2308
|
-
}
|
|
2483
|
+
} finally {
|
|
2484
|
+
this.resolvingFieldPath.pop();
|
|
2309
2485
|
}
|
|
2310
2486
|
}
|
|
2311
2487
|
return { kind: "object", fields: result };
|
|
2312
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
|
+
}
|
|
2313
2501
|
cacheDescendants(prefix, value) {
|
|
2314
2502
|
if (value.kind !== "object") return;
|
|
2315
2503
|
for (const [key, child] of value.fields) {
|
|
@@ -2332,17 +2520,59 @@ var SubstitutionResolver = class {
|
|
|
2332
2520
|
if (isResObj(v)) return this.resolveResObj(v);
|
|
2333
2521
|
const hv = v;
|
|
2334
2522
|
if (hv.kind === "array") {
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
)
|
|
2340
|
-
}
|
|
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 };
|
|
2341
2530
|
}
|
|
2342
2531
|
return hv;
|
|
2343
2532
|
}
|
|
2344
2533
|
resolveSubst(s, scope) {
|
|
2345
|
-
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
|
+
}
|
|
2346
2576
|
const key = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
2347
2577
|
if (this.cache.has(key)) return this.cache.get(key);
|
|
2348
2578
|
if (this.resolving.has(key)) {
|
|
@@ -2669,6 +2899,121 @@ function resolve2(ast, opts) {
|
|
|
2669
2899
|
return resolveTree(tree, { ...opts, useSystemEnvironment: true, allowUnresolved: false });
|
|
2670
2900
|
}
|
|
2671
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
|
+
|
|
2672
3017
|
// src/config.ts
|
|
2673
3018
|
var Config = class _Config {
|
|
2674
3019
|
constructor(root, opts) {
|
|
@@ -2974,6 +3319,36 @@ var Config = class _Config {
|
|
|
2974
3319
|
toObject(opts) {
|
|
2975
3320
|
return hoconToJs(this.root, opts?.nullPrototype === true);
|
|
2976
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
|
+
}
|
|
2977
3352
|
/**
|
|
2978
3353
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
2979
3354
|
* JSON (sorted keys, no whitespace). Used by Layer-2 fixture tests to compare
|
|
@@ -3216,10 +3591,30 @@ function buildResolveContext(input, opts) {
|
|
|
3216
3591
|
return { ast, resolveOpts };
|
|
3217
3592
|
}
|
|
3218
3593
|
function parse(input, opts = {}) {
|
|
3594
|
+
return parseStringWithOptions(input, opts);
|
|
3595
|
+
}
|
|
3596
|
+
function parseStringWithOptions(input, opts = {}) {
|
|
3597
|
+
return guardStackDepth(
|
|
3598
|
+
() => parseStringInner(input, opts),
|
|
3599
|
+
(msg) => new ParseError(msg, 1, 1, opts.originDescription)
|
|
3600
|
+
);
|
|
3601
|
+
}
|
|
3602
|
+
function parseStringInner(input, opts) {
|
|
3603
|
+
const resolveSubstitutions = opts.resolveSubstitutions ?? true;
|
|
3219
3604
|
const { ast, resolveOpts } = buildResolveContext(input, opts);
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3605
|
+
if (resolveSubstitutions) {
|
|
3606
|
+
const value = resolve2(ast, resolveOpts);
|
|
3607
|
+
if (value.kind !== "object") throw new Error("resolved value is not an object");
|
|
3608
|
+
return new Config(value, { resolved: true, originDescription: opts.originDescription });
|
|
3609
|
+
}
|
|
3610
|
+
const tree = buildTree(ast, resolveOpts);
|
|
3611
|
+
const hasPlaceholders = containsPlaceholders(tree);
|
|
3612
|
+
return Config._fromUnresolvedResObj(tree, {
|
|
3613
|
+
parseBaseDir: opts.baseDir,
|
|
3614
|
+
originDescription: opts.originDescription,
|
|
3615
|
+
resolved: !hasPlaceholders,
|
|
3616
|
+
resolveOpts
|
|
3617
|
+
});
|
|
3223
3618
|
}
|
|
3224
3619
|
function parseFile(filePath, opts = {}) {
|
|
3225
3620
|
if (typeof process === "undefined" && !opts.readFileSync) {
|