@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.js
CHANGED
|
@@ -41,13 +41,22 @@ function coerceNumber(value) {
|
|
|
41
41
|
return Number(value);
|
|
42
42
|
}
|
|
43
43
|
var DURATION_UNITS = {
|
|
44
|
+
// S19.1–S19.3: the bare nano/micro/milli (+plural) aliases are part of the
|
|
45
|
+
// spec's unit lists (HOCON.md L1307–L1309) and accepted by Lightbend
|
|
46
|
+
// (typesafe-config 1.4.6 probe, 2026-08-18); they were missing here.
|
|
44
47
|
ns: 1e-6,
|
|
48
|
+
nano: 1e-6,
|
|
49
|
+
nanos: 1e-6,
|
|
45
50
|
nanosecond: 1e-6,
|
|
46
51
|
nanoseconds: 1e-6,
|
|
47
52
|
us: 1e-3,
|
|
53
|
+
micro: 1e-3,
|
|
54
|
+
micros: 1e-3,
|
|
48
55
|
microsecond: 1e-3,
|
|
49
56
|
microseconds: 1e-3,
|
|
50
57
|
ms: 1,
|
|
58
|
+
milli: 1,
|
|
59
|
+
millis: 1,
|
|
51
60
|
millisecond: 1,
|
|
52
61
|
milliseconds: 1,
|
|
53
62
|
s: 1e3,
|
|
@@ -99,37 +108,76 @@ function parseDuration(value, outputUnit = "ms") {
|
|
|
99
108
|
return ms / divisor;
|
|
100
109
|
}
|
|
101
110
|
var BYTE_UNITS = {
|
|
111
|
+
// S21.1–S21.4 — the EXACT Lightbend/typesafe-config unit set (1.4.6 probe,
|
|
112
|
+
// 2026-08-18). Multi-letter units are case-sensitive: the SI decimal short
|
|
113
|
+
// form is `kB` (NOT `KB`/`kb` — Lightbend rejects both), higher decimals
|
|
114
|
+
// are `MB`…`YB`, binary prefixes are `Ki`/`KiB`…`Yi`/`YiB` with capital
|
|
115
|
+
// first letter, and long forms are lowercase only (`kilobyte`, never
|
|
116
|
+
// `Kilobyte`). Only the bare byte unit (`B`/`b`) and the single-letter
|
|
117
|
+
// -Xmx forms accept both cases. The old case-insensitive fallback and the
|
|
118
|
+
// lowercase alias rows accepted spellings Lightbend rejects — removed.
|
|
102
119
|
B: 1,
|
|
120
|
+
b: 1,
|
|
103
121
|
byte: 1,
|
|
104
122
|
bytes: 1,
|
|
105
|
-
|
|
123
|
+
kB: 1e3,
|
|
106
124
|
kilobyte: 1e3,
|
|
107
125
|
kilobytes: 1e3,
|
|
108
|
-
KiB: 1024,
|
|
109
|
-
kibibyte: 1024,
|
|
110
|
-
kibibytes: 1024,
|
|
111
126
|
MB: 1e6,
|
|
112
127
|
megabyte: 1e6,
|
|
113
128
|
megabytes: 1e6,
|
|
114
|
-
MiB: 1048576,
|
|
115
|
-
mebibyte: 1048576,
|
|
116
|
-
mebibytes: 1048576,
|
|
117
129
|
GB: 1e9,
|
|
118
130
|
gigabyte: 1e9,
|
|
119
131
|
gigabytes: 1e9,
|
|
120
|
-
GiB: 1073741824,
|
|
121
|
-
gibibyte: 1073741824,
|
|
122
|
-
gibibytes: 1073741824,
|
|
123
132
|
TB: 1e12,
|
|
124
133
|
terabyte: 1e12,
|
|
125
134
|
terabytes: 1e12,
|
|
135
|
+
PB: 1e15,
|
|
136
|
+
petabyte: 1e15,
|
|
137
|
+
petabytes: 1e15,
|
|
138
|
+
EB: 1e18,
|
|
139
|
+
exabyte: 1e18,
|
|
140
|
+
exabytes: 1e18,
|
|
141
|
+
ZB: 1e21,
|
|
142
|
+
zettabyte: 1e21,
|
|
143
|
+
zettabytes: 1e21,
|
|
144
|
+
YB: 1e24,
|
|
145
|
+
yottabyte: 1e24,
|
|
146
|
+
yottabytes: 1e24,
|
|
147
|
+
Ki: 1024,
|
|
148
|
+
KiB: 1024,
|
|
149
|
+
kibibyte: 1024,
|
|
150
|
+
kibibytes: 1024,
|
|
151
|
+
Mi: 1048576,
|
|
152
|
+
MiB: 1048576,
|
|
153
|
+
mebibyte: 1048576,
|
|
154
|
+
mebibytes: 1048576,
|
|
155
|
+
Gi: 1073741824,
|
|
156
|
+
GiB: 1073741824,
|
|
157
|
+
gibibyte: 1073741824,
|
|
158
|
+
gibibytes: 1073741824,
|
|
159
|
+
Ti: 1099511627776,
|
|
126
160
|
TiB: 1099511627776,
|
|
127
161
|
tebibyte: 1099511627776,
|
|
128
162
|
tebibytes: 1099511627776,
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
163
|
+
Pi: 1024 ** 5,
|
|
164
|
+
PiB: 1024 ** 5,
|
|
165
|
+
pebibyte: 1024 ** 5,
|
|
166
|
+
pebibytes: 1024 ** 5,
|
|
167
|
+
Ei: 1024 ** 6,
|
|
168
|
+
EiB: 1024 ** 6,
|
|
169
|
+
exbibyte: 1024 ** 6,
|
|
170
|
+
exbibytes: 1024 ** 6,
|
|
171
|
+
Zi: 1024 ** 7,
|
|
172
|
+
ZiB: 1024 ** 7,
|
|
173
|
+
zebibyte: 1024 ** 7,
|
|
174
|
+
zebibytes: 1024 ** 7,
|
|
175
|
+
Yi: 1024 ** 8,
|
|
176
|
+
YiB: 1024 ** 8,
|
|
177
|
+
yobibyte: 1024 ** 8,
|
|
178
|
+
yobibytes: 1024 ** 8,
|
|
179
|
+
// S21.4 — single-letter abbreviations → powers of two (java -Xmx
|
|
180
|
+
// convention); Lightbend accepts BOTH cases here, through the full ladder.
|
|
133
181
|
K: 1024,
|
|
134
182
|
k: 1024,
|
|
135
183
|
M: 1024 ** 2,
|
|
@@ -142,16 +190,10 @@ var BYTE_UNITS = {
|
|
|
142
190
|
p: 1024 ** 5,
|
|
143
191
|
E: 1024 ** 6,
|
|
144
192
|
e: 1024 ** 6,
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
mb: 1e6,
|
|
150
|
-
mib: 1048576,
|
|
151
|
-
gb: 1e9,
|
|
152
|
-
gib: 1073741824,
|
|
153
|
-
tb: 1e12,
|
|
154
|
-
tib: 1099511627776
|
|
193
|
+
Z: 1024 ** 7,
|
|
194
|
+
z: 1024 ** 7,
|
|
195
|
+
Y: 1024 ** 8,
|
|
196
|
+
y: 1024 ** 8
|
|
155
197
|
};
|
|
156
198
|
var OUTPUT_BYTE_UNITS = {
|
|
157
199
|
B: 1,
|
|
@@ -189,10 +231,7 @@ function parseBytes(value, outputUnit = "B") {
|
|
|
189
231
|
}
|
|
190
232
|
return bytes2 / divisor;
|
|
191
233
|
}
|
|
192
|
-
|
|
193
|
-
if (mult === void 0) {
|
|
194
|
-
mult = BYTE_UNITS[unit.toLowerCase()];
|
|
195
|
-
}
|
|
234
|
+
const mult = BYTE_UNITS[unit];
|
|
196
235
|
if (mult === void 0) return NaN;
|
|
197
236
|
const bytes = num * mult;
|
|
198
237
|
if (Math.abs(bytes) > Number.MAX_SAFE_INTEGER) {
|
|
@@ -260,35 +299,114 @@ function stringSegmentsToKey(segments) {
|
|
|
260
299
|
return t;
|
|
261
300
|
}).join(".");
|
|
262
301
|
}
|
|
302
|
+
function prefixSelfRefRemainder(s, fullKey) {
|
|
303
|
+
const texts = s.segments.map((seg) => seg.text);
|
|
304
|
+
if (!stringSegmentsToKey(texts).startsWith(fullKey + ".")) return null;
|
|
305
|
+
for (let n = 1; n < texts.length; n++) {
|
|
306
|
+
if (stringSegmentsToKey(texts.slice(0, n)) === fullKey) return texts.slice(n);
|
|
307
|
+
}
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
function navigateResolverValue(v, remainder) {
|
|
311
|
+
let cur = v;
|
|
312
|
+
for (const seg of remainder) {
|
|
313
|
+
if (isSubst(cur) || isConcat(cur)) return null;
|
|
314
|
+
if (isResObj(cur)) {
|
|
315
|
+
const next = cur.fields.get(seg);
|
|
316
|
+
if (next === void 0) return void 0;
|
|
317
|
+
cur = next;
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
const hv = cur;
|
|
321
|
+
if (hv.kind === "object") {
|
|
322
|
+
const next = hv.fields.get(seg);
|
|
323
|
+
if (next === void 0) return void 0;
|
|
324
|
+
cur = next;
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
return void 0;
|
|
328
|
+
}
|
|
329
|
+
return cur;
|
|
330
|
+
}
|
|
331
|
+
function foldPrefixSelfRef(s, replacement, remainder) {
|
|
332
|
+
const navigated = navigateResolverValue(replacement, remainder);
|
|
333
|
+
if (navigated === null) return s;
|
|
334
|
+
if (navigated === void 0) {
|
|
335
|
+
return {
|
|
336
|
+
_kind: "subst-placeholder",
|
|
337
|
+
segments: s.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
|
|
338
|
+
optional: s.optional,
|
|
339
|
+
knownAbsent: true,
|
|
340
|
+
listSuffix: s.listSuffix,
|
|
341
|
+
line: s.line,
|
|
342
|
+
col: s.col,
|
|
343
|
+
prefixLen: s.prefixLen
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
return cloneResolverValue(navigated);
|
|
347
|
+
}
|
|
348
|
+
function mergeResObjLayers(base, top) {
|
|
349
|
+
const fields = new Map(base.fields);
|
|
350
|
+
for (const [k, tv] of top.fields) {
|
|
351
|
+
const bv = fields.get(k);
|
|
352
|
+
if (bv !== void 0 && isResObj(bv) && isResObj(tv)) {
|
|
353
|
+
fields.set(k, mergeResObjLayers(bv, tv));
|
|
354
|
+
} else {
|
|
355
|
+
fields.set(k, tv);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
const priorValues = new Map(base.priorValues);
|
|
359
|
+
for (const [k, pv] of top.priorValues) priorValues.set(k, pv);
|
|
360
|
+
const resetKeys = new Set(base.resetKeys);
|
|
361
|
+
for (const k of top.resetKeys) resetKeys.add(k);
|
|
362
|
+
return {
|
|
363
|
+
_kind: "res-obj",
|
|
364
|
+
fields,
|
|
365
|
+
priorValues,
|
|
366
|
+
resetKeys
|
|
367
|
+
};
|
|
368
|
+
}
|
|
263
369
|
function containsSelfRef(v, fullKey) {
|
|
264
|
-
|
|
265
|
-
|
|
370
|
+
return containsSelfRefInner(v, fullKey, true);
|
|
371
|
+
}
|
|
372
|
+
function containsSelfRefInner(v, fullKey, allowPrefix) {
|
|
373
|
+
if (isSubst(v))
|
|
374
|
+
return !v.knownAbsent && (substFullKey(v) === fullKey || allowPrefix && prefixSelfRefRemainder(v, fullKey) !== null);
|
|
375
|
+
if (isConcat(v)) return v.nodes.some((n) => containsSelfRefInner(n, fullKey, allowPrefix));
|
|
266
376
|
if (isResObj(v)) {
|
|
267
377
|
for (const f of v.fields.values()) {
|
|
268
|
-
if (
|
|
378
|
+
if (containsSelfRefInner(f, fullKey, false)) return true;
|
|
269
379
|
}
|
|
270
380
|
return false;
|
|
271
381
|
}
|
|
272
382
|
const hv = v;
|
|
273
383
|
if (hv.kind === "array") {
|
|
274
|
-
return hv.items.some((item) =>
|
|
384
|
+
return hv.items.some((item) => containsSelfRefInner(item, fullKey, allowPrefix));
|
|
275
385
|
}
|
|
276
386
|
if (hv.kind === "object") {
|
|
277
387
|
for (const f of hv.fields.values()) {
|
|
278
|
-
if (
|
|
388
|
+
if (containsSelfRefInner(f, fullKey, false)) return true;
|
|
279
389
|
}
|
|
280
390
|
return false;
|
|
281
391
|
}
|
|
282
392
|
return false;
|
|
283
393
|
}
|
|
284
394
|
function foldSelfRef(v, fullKey, replacement) {
|
|
395
|
+
return foldSelfRefInner(v, fullKey, replacement, true);
|
|
396
|
+
}
|
|
397
|
+
function foldSelfRefInner(v, fullKey, replacement, allowPrefix) {
|
|
285
398
|
if (isSubst(v)) {
|
|
286
|
-
|
|
399
|
+
if (substFullKey(v) === fullKey) return replacement;
|
|
400
|
+
if (allowPrefix) {
|
|
401
|
+
const remainder = prefixSelfRefRemainder(v, fullKey);
|
|
402
|
+
if (remainder !== null) return foldPrefixSelfRef(v, replacement, remainder);
|
|
403
|
+
}
|
|
404
|
+
return v;
|
|
287
405
|
}
|
|
288
406
|
if (isConcat(v)) {
|
|
289
407
|
return {
|
|
290
408
|
_kind: "concat-placeholder",
|
|
291
|
-
nodes: v.nodes.map((n) =>
|
|
409
|
+
nodes: v.nodes.map((n) => foldSelfRefInner(n, fullKey, replacement, allowPrefix)),
|
|
292
410
|
line: v.line,
|
|
293
411
|
col: v.col
|
|
294
412
|
};
|
|
@@ -296,7 +414,7 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
296
414
|
if (isResObj(v)) {
|
|
297
415
|
const newFields = /* @__PURE__ */ new Map();
|
|
298
416
|
for (const [k, val] of v.fields) {
|
|
299
|
-
newFields.set(k,
|
|
417
|
+
newFields.set(k, foldSelfRefInner(val, fullKey, replacement, false));
|
|
300
418
|
}
|
|
301
419
|
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
302
420
|
}
|
|
@@ -304,13 +422,15 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
304
422
|
if (hv.kind === "array") {
|
|
305
423
|
return {
|
|
306
424
|
kind: "array",
|
|
307
|
-
items: hv.items.map(
|
|
425
|
+
items: hv.items.map(
|
|
426
|
+
(item) => foldSelfRefInner(item, fullKey, replacement, allowPrefix)
|
|
427
|
+
)
|
|
308
428
|
};
|
|
309
429
|
}
|
|
310
430
|
if (hv.kind === "object") {
|
|
311
431
|
const newFields = /* @__PURE__ */ new Map();
|
|
312
432
|
for (const [k, val] of hv.fields) {
|
|
313
|
-
newFields.set(k,
|
|
433
|
+
newFields.set(k, foldSelfRefInner(val, fullKey, replacement, false));
|
|
314
434
|
}
|
|
315
435
|
return { kind: "object", fields: newFields };
|
|
316
436
|
}
|
|
@@ -354,10 +474,26 @@ function foldKnownAbsentSelfRef(v, fullKey, replacement) {
|
|
|
354
474
|
function foldOrSkipPrior(prior, fullKey, old) {
|
|
355
475
|
if (!containsSelfRef(prior, fullKey)) return cloneResolverValue(prior);
|
|
356
476
|
if (old === void 0) return foldOptionalSelfRefAbsent(prior, fullKey);
|
|
477
|
+
if (isSubst(prior)) {
|
|
478
|
+
const remainder = prefixSelfRefRemainder(prior, fullKey);
|
|
479
|
+
if (remainder !== null) {
|
|
480
|
+
const navigated = navigateResolverValue(old, remainder);
|
|
481
|
+
if (navigated === void 0 && prior.optional) return cloneResolverValue(old);
|
|
482
|
+
if (navigated !== null && navigated !== void 0 && isResObj(navigated) && isResObj(old)) {
|
|
483
|
+
return mergeResObjLayers(
|
|
484
|
+
cloneResolverValue(old),
|
|
485
|
+
cloneResolverValue(navigated)
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
357
490
|
return foldSelfRef(prior, fullKey, old);
|
|
358
491
|
}
|
|
359
492
|
function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
360
|
-
|
|
493
|
+
return foldOptionalSelfRefAbsentInner(v, fullKey, true);
|
|
494
|
+
}
|
|
495
|
+
function foldOptionalSelfRefAbsentInner(v, fullKey, allowPrefix) {
|
|
496
|
+
if (isSubst(v) && (substFullKey(v) === fullKey || allowPrefix && prefixSelfRefRemainder(v, fullKey) !== null)) {
|
|
361
497
|
if (!v.optional) return void 0;
|
|
362
498
|
return {
|
|
363
499
|
_kind: "subst-placeholder",
|
|
@@ -373,7 +509,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
373
509
|
if (isConcat(v)) {
|
|
374
510
|
const nodes = [];
|
|
375
511
|
for (const node of v.nodes) {
|
|
376
|
-
const folded =
|
|
512
|
+
const folded = foldOptionalSelfRefAbsentInner(node, fullKey, allowPrefix);
|
|
377
513
|
if (folded === void 0) return void 0;
|
|
378
514
|
nodes.push(folded);
|
|
379
515
|
}
|
|
@@ -382,7 +518,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
382
518
|
if (isResObj(v)) {
|
|
383
519
|
const fields = /* @__PURE__ */ new Map();
|
|
384
520
|
for (const [key, value] of v.fields) {
|
|
385
|
-
const folded =
|
|
521
|
+
const folded = foldOptionalSelfRefAbsentInner(value, fullKey, false);
|
|
386
522
|
if (folded === void 0) return void 0;
|
|
387
523
|
fields.set(key, folded);
|
|
388
524
|
}
|
|
@@ -392,7 +528,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
392
528
|
if (hv.kind === "array") {
|
|
393
529
|
const items = [];
|
|
394
530
|
for (const item of hv.items) {
|
|
395
|
-
const folded =
|
|
531
|
+
const folded = foldOptionalSelfRefAbsentInner(item, fullKey, allowPrefix);
|
|
396
532
|
if (folded === void 0) return void 0;
|
|
397
533
|
items.push(folded);
|
|
398
534
|
}
|
|
@@ -401,7 +537,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
401
537
|
if (hv.kind === "object") {
|
|
402
538
|
const fields = /* @__PURE__ */ new Map();
|
|
403
539
|
for (const [key, value] of hv.fields) {
|
|
404
|
-
const folded =
|
|
540
|
+
const folded = foldOptionalSelfRefAbsentInner(value, fullKey, false);
|
|
405
541
|
if (folded === void 0) return void 0;
|
|
406
542
|
fields.set(key, folded);
|
|
407
543
|
}
|
|
@@ -774,7 +910,6 @@ var Lexer = class {
|
|
|
774
910
|
if (!closed) {
|
|
775
911
|
throw new ParseError("unterminated triple-quoted string", sl, sc);
|
|
776
912
|
}
|
|
777
|
-
if (value.startsWith("\n")) value = value.slice(1);
|
|
778
913
|
this.push("triple_string", value, sl, sc, true);
|
|
779
914
|
continue;
|
|
780
915
|
}
|
|
@@ -1091,9 +1226,9 @@ var Parser = class {
|
|
|
1091
1226
|
}
|
|
1092
1227
|
}
|
|
1093
1228
|
this.skip("newline");
|
|
1094
|
-
const
|
|
1095
|
-
if (
|
|
1096
|
-
throw new ParseError(`Unexpected token '${
|
|
1229
|
+
const remaining2 = this.peek();
|
|
1230
|
+
if (remaining2.kind !== "eof") {
|
|
1231
|
+
throw new ParseError(`Unexpected token '${remaining2.value}' after closing brace`, remaining2.line, remaining2.col);
|
|
1097
1232
|
}
|
|
1098
1233
|
return { kind: "object", fields: allFields, pos: first.pos };
|
|
1099
1234
|
}
|
|
@@ -1101,13 +1236,19 @@ var Parser = class {
|
|
|
1101
1236
|
this.advance();
|
|
1102
1237
|
const arr = this.parseArray();
|
|
1103
1238
|
this.skip("newline");
|
|
1104
|
-
const
|
|
1105
|
-
if (
|
|
1106
|
-
throw new ParseError(`Unexpected token '${
|
|
1239
|
+
const remaining2 = this.peek();
|
|
1240
|
+
if (remaining2.kind !== "eof") {
|
|
1241
|
+
throw new ParseError(`Unexpected token '${remaining2.value}' after root array`, remaining2.line, remaining2.col);
|
|
1107
1242
|
}
|
|
1108
1243
|
return { ...arr, pos: { line: t.line, col: t.col } };
|
|
1109
1244
|
}
|
|
1110
|
-
|
|
1245
|
+
const root = this.parseObject(false);
|
|
1246
|
+
this.skip("newline");
|
|
1247
|
+
const remaining = this.peek();
|
|
1248
|
+
if (remaining.kind !== "eof") {
|
|
1249
|
+
throw new ParseError(`Unexpected token '${remaining.value}' after root content`, remaining.line, remaining.col);
|
|
1250
|
+
}
|
|
1251
|
+
return root;
|
|
1111
1252
|
}
|
|
1112
1253
|
peek(offset = 0) {
|
|
1113
1254
|
return this.tokens[this.pos + offset] ?? EOF_TOKEN;
|
|
@@ -1498,6 +1639,28 @@ function stripBom(input) {
|
|
|
1498
1639
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
1499
1640
|
}
|
|
1500
1641
|
|
|
1642
|
+
// src/internal/depth.ts
|
|
1643
|
+
var MAX_PATH_SEGMENTS = 64;
|
|
1644
|
+
function tooDeep(segments) {
|
|
1645
|
+
return segments > MAX_PATH_SEGMENTS;
|
|
1646
|
+
}
|
|
1647
|
+
function guardStackDepth(fn, wrap) {
|
|
1648
|
+
try {
|
|
1649
|
+
return fn();
|
|
1650
|
+
} catch (e) {
|
|
1651
|
+
if (!isStackOverflow(e)) throw e;
|
|
1652
|
+
throw wrap(STACK_MESSAGE);
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
1656
|
+
function isStackOverflow(e) {
|
|
1657
|
+
if (!(e instanceof RangeError)) return false;
|
|
1658
|
+
const m = e.message.toLowerCase();
|
|
1659
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
1660
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
1661
|
+
m.includes("stack overflow");
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1501
1664
|
// src/internal/properties/properties.ts
|
|
1502
1665
|
function parseProperties(input) {
|
|
1503
1666
|
const pairs = [];
|
|
@@ -1505,7 +1668,15 @@ function parseProperties(input) {
|
|
|
1505
1668
|
const [rawKey, rawValue] = splitKeyValue(text);
|
|
1506
1669
|
const key = unescapeProps(rawKey, line);
|
|
1507
1670
|
if (key === "") continue;
|
|
1508
|
-
|
|
1671
|
+
const segments = key.split(".");
|
|
1672
|
+
if (tooDeep(segments.length)) {
|
|
1673
|
+
throw new ParseError(
|
|
1674
|
+
`key maps to a path ${segments.length} segments deep, over the limit of ${MAX_PATH_SEGMENTS}`,
|
|
1675
|
+
line,
|
|
1676
|
+
1
|
|
1677
|
+
);
|
|
1678
|
+
}
|
|
1679
|
+
pairs.push([segments, unescapeProps(rawValue, line)]);
|
|
1509
1680
|
}
|
|
1510
1681
|
return nestPairs(pairs);
|
|
1511
1682
|
}
|
|
@@ -2223,6 +2394,12 @@ var SubstitutionResolver = class {
|
|
|
2223
2394
|
// Cross-impl with rs.hocon v1.5.1's resolving_field_path (same purpose,
|
|
2224
2395
|
// same prefix-match semantics).
|
|
2225
2396
|
this.resolvingFieldPath = [];
|
|
2397
|
+
// S13a.12 recursion guard: field keys whose prior is currently being
|
|
2398
|
+
// resolved through the prefix-self-ref branch. Saved priors are
|
|
2399
|
+
// prefix-self-ref-free by the fold invariant, so re-entry only happens on
|
|
2400
|
+
// a shape the fold could not see through (a live subst mid-navigation) —
|
|
2401
|
+
// report it as a cycle instead of recursing forever.
|
|
2402
|
+
this.resolvingPrefixPriors = /* @__PURE__ */ new Set();
|
|
2226
2403
|
}
|
|
2227
2404
|
/** Returns a prefix for error messages, including origin info when set. */
|
|
2228
2405
|
originPrefix() {
|
|
@@ -2237,46 +2414,57 @@ var SubstitutionResolver = class {
|
|
|
2237
2414
|
this.resolvingFieldPath.push(key);
|
|
2238
2415
|
const fullCacheKey = stringSegmentsToKey(this.resolvingFieldPath);
|
|
2239
2416
|
this.cache.delete(fullCacheKey);
|
|
2240
|
-
let resolved;
|
|
2241
2417
|
try {
|
|
2242
|
-
resolved = this.resolveVal(val, obj);
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2418
|
+
const resolved = this.resolveVal(val, obj);
|
|
2419
|
+
if (resolved !== void 0) {
|
|
2420
|
+
if (resolved.kind === "object") {
|
|
2421
|
+
const prior = obj.priorValues.get(key);
|
|
2422
|
+
if (prior !== void 0) {
|
|
2423
|
+
const priorResolved = this.resolveVal(prior, obj);
|
|
2424
|
+
if (priorResolved !== void 0 && priorResolved.kind === "object") {
|
|
2425
|
+
const finalValue = deepMergeHoconValues(
|
|
2426
|
+
priorResolved,
|
|
2427
|
+
resolved
|
|
2428
|
+
);
|
|
2429
|
+
result.set(key, finalValue);
|
|
2430
|
+
this.cache.set(fullCacheKey, finalValue);
|
|
2431
|
+
this.cacheDescendants(fullCacheKey, finalValue);
|
|
2432
|
+
continue;
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
result.set(key, resolved);
|
|
2437
|
+
this.cache.set(fullCacheKey, resolved);
|
|
2438
|
+
this.cacheDescendants(fullCacheKey, resolved);
|
|
2439
|
+
} else {
|
|
2248
2440
|
const prior = obj.priorValues.get(key);
|
|
2249
2441
|
if (prior !== void 0) {
|
|
2250
2442
|
const priorResolved = this.resolveVal(prior, obj);
|
|
2251
|
-
if (priorResolved !== void 0
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
);
|
|
2256
|
-
result.set(key, finalValue);
|
|
2257
|
-
this.cache.set(fullCacheKey, finalValue);
|
|
2258
|
-
this.cacheDescendants(fullCacheKey, finalValue);
|
|
2259
|
-
continue;
|
|
2443
|
+
if (priorResolved !== void 0) {
|
|
2444
|
+
result.set(key, priorResolved);
|
|
2445
|
+
this.cache.set(fullCacheKey, priorResolved);
|
|
2446
|
+
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
2260
2447
|
}
|
|
2261
2448
|
}
|
|
2262
2449
|
}
|
|
2263
|
-
|
|
2264
|
-
this.
|
|
2265
|
-
this.cacheDescendants(fullCacheKey, resolved);
|
|
2266
|
-
} else {
|
|
2267
|
-
const prior = obj.priorValues.get(key);
|
|
2268
|
-
if (prior !== void 0) {
|
|
2269
|
-
const priorResolved = this.resolveVal(prior, obj);
|
|
2270
|
-
if (priorResolved !== void 0) {
|
|
2271
|
-
result.set(key, priorResolved);
|
|
2272
|
-
this.cache.set(fullCacheKey, priorResolved);
|
|
2273
|
-
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
2274
|
-
}
|
|
2275
|
-
}
|
|
2450
|
+
} finally {
|
|
2451
|
+
this.resolvingFieldPath.pop();
|
|
2276
2452
|
}
|
|
2277
2453
|
}
|
|
2278
2454
|
return { kind: "object", fields: result };
|
|
2279
2455
|
}
|
|
2456
|
+
/** S13a.12: walk resolved-object fields by segment text. A missing segment
|
|
2457
|
+
* or a walk into a scalar/array is path-absent → undefined. */
|
|
2458
|
+
navigateResolved(v, remainder) {
|
|
2459
|
+
let cur = v;
|
|
2460
|
+
for (const seg of remainder) {
|
|
2461
|
+
if (cur.kind !== "object") return void 0;
|
|
2462
|
+
const next = cur.fields.get(seg);
|
|
2463
|
+
if (next === void 0) return void 0;
|
|
2464
|
+
cur = next;
|
|
2465
|
+
}
|
|
2466
|
+
return cur;
|
|
2467
|
+
}
|
|
2280
2468
|
cacheDescendants(prefix, value) {
|
|
2281
2469
|
if (value.kind !== "object") return;
|
|
2282
2470
|
for (const [key, child] of value.fields) {
|
|
@@ -2299,17 +2487,59 @@ var SubstitutionResolver = class {
|
|
|
2299
2487
|
if (isResObj(v)) return this.resolveResObj(v);
|
|
2300
2488
|
const hv = v;
|
|
2301
2489
|
if (hv.kind === "array") {
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
)
|
|
2307
|
-
}
|
|
2490
|
+
const items = [];
|
|
2491
|
+
for (const item of hv.items) {
|
|
2492
|
+
const resolved = this.resolveVal(item, scope);
|
|
2493
|
+
if (resolved === void 0) continue;
|
|
2494
|
+
items.push(resolved);
|
|
2495
|
+
}
|
|
2496
|
+
return { kind: "array", items };
|
|
2308
2497
|
}
|
|
2309
2498
|
return hv;
|
|
2310
2499
|
}
|
|
2311
2500
|
resolveSubst(s, scope) {
|
|
2312
|
-
if (s.knownAbsent)
|
|
2501
|
+
if (s.knownAbsent) {
|
|
2502
|
+
if (!s.optional) {
|
|
2503
|
+
if (this.opts.allowUnresolved) return s;
|
|
2504
|
+
const k = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
2505
|
+
throw new ResolveError(
|
|
2506
|
+
`${this.originPrefix()}could not resolve substitution: \${${k}}`,
|
|
2507
|
+
k,
|
|
2508
|
+
s.line,
|
|
2509
|
+
s.col
|
|
2510
|
+
);
|
|
2511
|
+
}
|
|
2512
|
+
return void 0;
|
|
2513
|
+
}
|
|
2514
|
+
{
|
|
2515
|
+
const rfp = this.resolvingFieldPath;
|
|
2516
|
+
const sTexts = s.segments.map((seg) => seg.text);
|
|
2517
|
+
if (rfp.length > 0 && rfp.length < sTexts.length && stringSegmentsToKey(sTexts.slice(0, rfp.length)) === stringSegmentsToKey(rfp)) {
|
|
2518
|
+
const guardKey = stringSegmentsToKey(rfp);
|
|
2519
|
+
const prior = scope.priorValues.get(rfp[rfp.length - 1]);
|
|
2520
|
+
if (prior !== void 0 && !this.resolvingPrefixPriors.has(guardKey)) {
|
|
2521
|
+
this.resolvingPrefixPriors.add(guardKey);
|
|
2522
|
+
try {
|
|
2523
|
+
const priorResolved = this.resolveVal(prior, scope);
|
|
2524
|
+
if (priorResolved !== void 0) {
|
|
2525
|
+
const navigated = this.navigateResolved(priorResolved, sTexts.slice(rfp.length));
|
|
2526
|
+
if (navigated !== void 0) return navigated;
|
|
2527
|
+
}
|
|
2528
|
+
} finally {
|
|
2529
|
+
this.resolvingPrefixPriors.delete(guardKey);
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
if (s.optional) return void 0;
|
|
2533
|
+
if (this.opts.allowUnresolved) return s;
|
|
2534
|
+
const k = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
2535
|
+
throw new ResolveError(
|
|
2536
|
+
`${this.originPrefix()}could not resolve substitution: \${${k}}`,
|
|
2537
|
+
k,
|
|
2538
|
+
s.line,
|
|
2539
|
+
s.col
|
|
2540
|
+
);
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2313
2543
|
const key = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
2314
2544
|
if (this.cache.has(key)) return this.cache.get(key);
|
|
2315
2545
|
if (this.resolving.has(key)) {
|
|
@@ -2636,6 +2866,121 @@ function resolve2(ast, opts) {
|
|
|
2636
2866
|
return resolveTree(tree, { ...opts, useSystemEnvironment: true, allowUnresolved: false });
|
|
2637
2867
|
}
|
|
2638
2868
|
|
|
2869
|
+
// src/render-hocon.ts
|
|
2870
|
+
function renderHoconFromRoot(root) {
|
|
2871
|
+
const out = [];
|
|
2872
|
+
renderObjectBody(out, root, 0);
|
|
2873
|
+
return out.join("");
|
|
2874
|
+
}
|
|
2875
|
+
function renderObjectBody(out, o, depth) {
|
|
2876
|
+
const indent = " ".repeat(depth);
|
|
2877
|
+
for (const [k, v] of o.fields) {
|
|
2878
|
+
out.push(indent, renderKey(k));
|
|
2879
|
+
if (v.kind === "object") {
|
|
2880
|
+
out.push(" {");
|
|
2881
|
+
if (v.fields.size === 0) {
|
|
2882
|
+
out.push("}\n");
|
|
2883
|
+
continue;
|
|
2884
|
+
}
|
|
2885
|
+
out.push("\n");
|
|
2886
|
+
renderObjectBody(out, v, depth + 1);
|
|
2887
|
+
out.push(indent, "}\n");
|
|
2888
|
+
} else {
|
|
2889
|
+
out.push(" = ");
|
|
2890
|
+
renderValue(out, v, depth);
|
|
2891
|
+
out.push("\n");
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2895
|
+
function renderValue(out, v, depth) {
|
|
2896
|
+
switch (v.kind) {
|
|
2897
|
+
case "object": {
|
|
2898
|
+
if (v.fields.size === 0) {
|
|
2899
|
+
out.push("{}");
|
|
2900
|
+
return;
|
|
2901
|
+
}
|
|
2902
|
+
out.push("{\n");
|
|
2903
|
+
renderObjectBody(out, v, depth + 1);
|
|
2904
|
+
out.push(" ".repeat(depth), "}");
|
|
2905
|
+
return;
|
|
2906
|
+
}
|
|
2907
|
+
case "array":
|
|
2908
|
+
renderArray(out, v, depth);
|
|
2909
|
+
return;
|
|
2910
|
+
case "scalar":
|
|
2911
|
+
out.push(renderScalar(v));
|
|
2912
|
+
return;
|
|
2913
|
+
default:
|
|
2914
|
+
throw new ConfigError(
|
|
2915
|
+
"renderHocon: unrenderable value (config must be resolved data)",
|
|
2916
|
+
""
|
|
2917
|
+
);
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
function renderArray(out, a, depth) {
|
|
2921
|
+
if (a.items.length === 0) {
|
|
2922
|
+
out.push("[]");
|
|
2923
|
+
return;
|
|
2924
|
+
}
|
|
2925
|
+
const inner = " ".repeat(depth + 1);
|
|
2926
|
+
out.push("[\n");
|
|
2927
|
+
for (const e of a.items) {
|
|
2928
|
+
out.push(inner);
|
|
2929
|
+
renderValue(out, e, depth + 1);
|
|
2930
|
+
out.push("\n");
|
|
2931
|
+
}
|
|
2932
|
+
out.push(" ".repeat(depth), "]");
|
|
2933
|
+
}
|
|
2934
|
+
function renderScalar(s) {
|
|
2935
|
+
switch (s.valueType) {
|
|
2936
|
+
case "null":
|
|
2937
|
+
return "null";
|
|
2938
|
+
case "boolean":
|
|
2939
|
+
case "number":
|
|
2940
|
+
return s.raw;
|
|
2941
|
+
case "string":
|
|
2942
|
+
return renderString(s.raw);
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
var SAFE_UNQUOTED_KEY = /^[A-Za-z0-9_-]+$/;
|
|
2946
|
+
function renderKey(k) {
|
|
2947
|
+
if (k === "include") return quoteString(k);
|
|
2948
|
+
return SAFE_UNQUOTED_KEY.test(k) ? k : quoteString(k);
|
|
2949
|
+
}
|
|
2950
|
+
var SAFE_BARE_STRING = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
2951
|
+
var STRING_KEYWORDS = /* @__PURE__ */ new Set(["true", "false", "null", "yes", "no", "on", "off"]);
|
|
2952
|
+
function renderString(s) {
|
|
2953
|
+
return SAFE_BARE_STRING.test(s) && !STRING_KEYWORDS.has(s.toLowerCase()) ? s : quoteString(s);
|
|
2954
|
+
}
|
|
2955
|
+
function quoteString(s) {
|
|
2956
|
+
if (s.includes("\n") && !s.includes("\r") && !s.includes('"""') && !s.endsWith('"')) {
|
|
2957
|
+
return `"""${s}"""`;
|
|
2958
|
+
}
|
|
2959
|
+
let b = '"';
|
|
2960
|
+
for (const ch of s) {
|
|
2961
|
+
switch (ch) {
|
|
2962
|
+
case '"':
|
|
2963
|
+
b += '\\"';
|
|
2964
|
+
break;
|
|
2965
|
+
case "\\":
|
|
2966
|
+
b += "\\\\";
|
|
2967
|
+
break;
|
|
2968
|
+
case "\n":
|
|
2969
|
+
b += "\\n";
|
|
2970
|
+
break;
|
|
2971
|
+
case "\r":
|
|
2972
|
+
b += "\\r";
|
|
2973
|
+
break;
|
|
2974
|
+
case " ":
|
|
2975
|
+
b += "\\t";
|
|
2976
|
+
break;
|
|
2977
|
+
default:
|
|
2978
|
+
b += ch;
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2981
|
+
return b + '"';
|
|
2982
|
+
}
|
|
2983
|
+
|
|
2639
2984
|
// src/config.ts
|
|
2640
2985
|
var Config = class _Config {
|
|
2641
2986
|
constructor(root, opts) {
|
|
@@ -2941,6 +3286,36 @@ var Config = class _Config {
|
|
|
2941
3286
|
toObject(opts) {
|
|
2942
3287
|
return hoconToJs(this.root, opts?.nullPrototype === true);
|
|
2943
3288
|
}
|
|
3289
|
+
/**
|
|
3290
|
+
* Renders this resolved Config as HOCON text (E18; lockstep with go.hocon's
|
|
3291
|
+
* `Config.RenderHOCON`, v1.11.0).
|
|
3292
|
+
*
|
|
3293
|
+
* The output round-trips: parsing it back yields the same value tree. That
|
|
3294
|
+
* is the correctness contract, not byte-for-byte formatting — a scalar is
|
|
3295
|
+
* quoted whenever leaving it bare would re-parse as a different type (a
|
|
3296
|
+
* string `"8080"` becomes `"8080"`, not `8080`), and left bare only when it
|
|
3297
|
+
* provably cannot.
|
|
3298
|
+
*
|
|
3299
|
+
* The Config must be resolved and hold only data (objects, arrays, string /
|
|
3300
|
+
* number / boolean / null scalars) — exactly what {@link fromMap} and the
|
|
3301
|
+
* format adapters produce. An unresolved placeholder throws
|
|
3302
|
+
* {@link ConfigError}; substitutions have no textual round trip through a
|
|
3303
|
+
* value tree.
|
|
3304
|
+
*
|
|
3305
|
+
* The root object's fields are emitted without enclosing braces, nested
|
|
3306
|
+
* objects as `key { … }`, arrays as newline-separated `[ … ]`, indented two
|
|
3307
|
+
* spaces. Source comments are not represented — a value tree does not carry
|
|
3308
|
+
* them.
|
|
3309
|
+
*/
|
|
3310
|
+
renderHocon() {
|
|
3311
|
+
if (!this._resolved) {
|
|
3312
|
+
throw new ConfigError(
|
|
3313
|
+
"renderHocon: unrenderable unresolved substitution (config must be resolved data)",
|
|
3314
|
+
""
|
|
3315
|
+
);
|
|
3316
|
+
}
|
|
3317
|
+
return renderHoconFromRoot(this.root);
|
|
3318
|
+
}
|
|
2944
3319
|
/**
|
|
2945
3320
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
2946
3321
|
* JSON (sorted keys, no whitespace). Used by Layer-2 fixture tests to compare
|
|
@@ -3183,10 +3558,30 @@ function buildResolveContext(input, opts) {
|
|
|
3183
3558
|
return { ast, resolveOpts };
|
|
3184
3559
|
}
|
|
3185
3560
|
function parse(input, opts = {}) {
|
|
3561
|
+
return parseStringWithOptions(input, opts);
|
|
3562
|
+
}
|
|
3563
|
+
function parseStringWithOptions(input, opts = {}) {
|
|
3564
|
+
return guardStackDepth(
|
|
3565
|
+
() => parseStringInner(input, opts),
|
|
3566
|
+
(msg) => new ParseError(msg, 1, 1, opts.originDescription)
|
|
3567
|
+
);
|
|
3568
|
+
}
|
|
3569
|
+
function parseStringInner(input, opts) {
|
|
3570
|
+
const resolveSubstitutions = opts.resolveSubstitutions ?? true;
|
|
3186
3571
|
const { ast, resolveOpts } = buildResolveContext(input, opts);
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3572
|
+
if (resolveSubstitutions) {
|
|
3573
|
+
const value = resolve2(ast, resolveOpts);
|
|
3574
|
+
if (value.kind !== "object") throw new Error("resolved value is not an object");
|
|
3575
|
+
return new Config(value, { resolved: true, originDescription: opts.originDescription });
|
|
3576
|
+
}
|
|
3577
|
+
const tree = buildTree(ast, resolveOpts);
|
|
3578
|
+
const hasPlaceholders = containsPlaceholders(tree);
|
|
3579
|
+
return Config._fromUnresolvedResObj(tree, {
|
|
3580
|
+
parseBaseDir: opts.baseDir,
|
|
3581
|
+
originDescription: opts.originDescription,
|
|
3582
|
+
resolved: !hasPlaceholders,
|
|
3583
|
+
resolveOpts
|
|
3584
|
+
});
|
|
3190
3585
|
}
|
|
3191
3586
|
function parseFile(filePath, opts = {}) {
|
|
3192
3587
|
if (typeof process === "undefined" && !opts.readFileSync) {
|