@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
|
@@ -70,13 +70,22 @@ function coerceNumber(value) {
|
|
|
70
70
|
return Number(value);
|
|
71
71
|
}
|
|
72
72
|
var DURATION_UNITS = {
|
|
73
|
+
// S19.1–S19.3: the bare nano/micro/milli (+plural) aliases are part of the
|
|
74
|
+
// spec's unit lists (HOCON.md L1307–L1309) and accepted by Lightbend
|
|
75
|
+
// (typesafe-config 1.4.6 probe, 2026-08-18); they were missing here.
|
|
73
76
|
ns: 1e-6,
|
|
77
|
+
nano: 1e-6,
|
|
78
|
+
nanos: 1e-6,
|
|
74
79
|
nanosecond: 1e-6,
|
|
75
80
|
nanoseconds: 1e-6,
|
|
76
81
|
us: 1e-3,
|
|
82
|
+
micro: 1e-3,
|
|
83
|
+
micros: 1e-3,
|
|
77
84
|
microsecond: 1e-3,
|
|
78
85
|
microseconds: 1e-3,
|
|
79
86
|
ms: 1,
|
|
87
|
+
milli: 1,
|
|
88
|
+
millis: 1,
|
|
80
89
|
millisecond: 1,
|
|
81
90
|
milliseconds: 1,
|
|
82
91
|
s: 1e3,
|
|
@@ -128,37 +137,76 @@ function parseDuration(value, outputUnit = "ms") {
|
|
|
128
137
|
return ms / divisor;
|
|
129
138
|
}
|
|
130
139
|
var BYTE_UNITS = {
|
|
140
|
+
// S21.1–S21.4 — the EXACT Lightbend/typesafe-config unit set (1.4.6 probe,
|
|
141
|
+
// 2026-08-18). Multi-letter units are case-sensitive: the SI decimal short
|
|
142
|
+
// form is `kB` (NOT `KB`/`kb` — Lightbend rejects both), higher decimals
|
|
143
|
+
// are `MB`…`YB`, binary prefixes are `Ki`/`KiB`…`Yi`/`YiB` with capital
|
|
144
|
+
// first letter, and long forms are lowercase only (`kilobyte`, never
|
|
145
|
+
// `Kilobyte`). Only the bare byte unit (`B`/`b`) and the single-letter
|
|
146
|
+
// -Xmx forms accept both cases. The old case-insensitive fallback and the
|
|
147
|
+
// lowercase alias rows accepted spellings Lightbend rejects — removed.
|
|
131
148
|
B: 1,
|
|
149
|
+
b: 1,
|
|
132
150
|
byte: 1,
|
|
133
151
|
bytes: 1,
|
|
134
|
-
|
|
152
|
+
kB: 1e3,
|
|
135
153
|
kilobyte: 1e3,
|
|
136
154
|
kilobytes: 1e3,
|
|
137
|
-
KiB: 1024,
|
|
138
|
-
kibibyte: 1024,
|
|
139
|
-
kibibytes: 1024,
|
|
140
155
|
MB: 1e6,
|
|
141
156
|
megabyte: 1e6,
|
|
142
157
|
megabytes: 1e6,
|
|
143
|
-
MiB: 1048576,
|
|
144
|
-
mebibyte: 1048576,
|
|
145
|
-
mebibytes: 1048576,
|
|
146
158
|
GB: 1e9,
|
|
147
159
|
gigabyte: 1e9,
|
|
148
160
|
gigabytes: 1e9,
|
|
149
|
-
GiB: 1073741824,
|
|
150
|
-
gibibyte: 1073741824,
|
|
151
|
-
gibibytes: 1073741824,
|
|
152
161
|
TB: 1e12,
|
|
153
162
|
terabyte: 1e12,
|
|
154
163
|
terabytes: 1e12,
|
|
164
|
+
PB: 1e15,
|
|
165
|
+
petabyte: 1e15,
|
|
166
|
+
petabytes: 1e15,
|
|
167
|
+
EB: 1e18,
|
|
168
|
+
exabyte: 1e18,
|
|
169
|
+
exabytes: 1e18,
|
|
170
|
+
ZB: 1e21,
|
|
171
|
+
zettabyte: 1e21,
|
|
172
|
+
zettabytes: 1e21,
|
|
173
|
+
YB: 1e24,
|
|
174
|
+
yottabyte: 1e24,
|
|
175
|
+
yottabytes: 1e24,
|
|
176
|
+
Ki: 1024,
|
|
177
|
+
KiB: 1024,
|
|
178
|
+
kibibyte: 1024,
|
|
179
|
+
kibibytes: 1024,
|
|
180
|
+
Mi: 1048576,
|
|
181
|
+
MiB: 1048576,
|
|
182
|
+
mebibyte: 1048576,
|
|
183
|
+
mebibytes: 1048576,
|
|
184
|
+
Gi: 1073741824,
|
|
185
|
+
GiB: 1073741824,
|
|
186
|
+
gibibyte: 1073741824,
|
|
187
|
+
gibibytes: 1073741824,
|
|
188
|
+
Ti: 1099511627776,
|
|
155
189
|
TiB: 1099511627776,
|
|
156
190
|
tebibyte: 1099511627776,
|
|
157
191
|
tebibytes: 1099511627776,
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
192
|
+
Pi: 1024 ** 5,
|
|
193
|
+
PiB: 1024 ** 5,
|
|
194
|
+
pebibyte: 1024 ** 5,
|
|
195
|
+
pebibytes: 1024 ** 5,
|
|
196
|
+
Ei: 1024 ** 6,
|
|
197
|
+
EiB: 1024 ** 6,
|
|
198
|
+
exbibyte: 1024 ** 6,
|
|
199
|
+
exbibytes: 1024 ** 6,
|
|
200
|
+
Zi: 1024 ** 7,
|
|
201
|
+
ZiB: 1024 ** 7,
|
|
202
|
+
zebibyte: 1024 ** 7,
|
|
203
|
+
zebibytes: 1024 ** 7,
|
|
204
|
+
Yi: 1024 ** 8,
|
|
205
|
+
YiB: 1024 ** 8,
|
|
206
|
+
yobibyte: 1024 ** 8,
|
|
207
|
+
yobibytes: 1024 ** 8,
|
|
208
|
+
// S21.4 — single-letter abbreviations → powers of two (java -Xmx
|
|
209
|
+
// convention); Lightbend accepts BOTH cases here, through the full ladder.
|
|
162
210
|
K: 1024,
|
|
163
211
|
k: 1024,
|
|
164
212
|
M: 1024 ** 2,
|
|
@@ -171,16 +219,10 @@ var BYTE_UNITS = {
|
|
|
171
219
|
p: 1024 ** 5,
|
|
172
220
|
E: 1024 ** 6,
|
|
173
221
|
e: 1024 ** 6,
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
mb: 1e6,
|
|
179
|
-
mib: 1048576,
|
|
180
|
-
gb: 1e9,
|
|
181
|
-
gib: 1073741824,
|
|
182
|
-
tb: 1e12,
|
|
183
|
-
tib: 1099511627776
|
|
222
|
+
Z: 1024 ** 7,
|
|
223
|
+
z: 1024 ** 7,
|
|
224
|
+
Y: 1024 ** 8,
|
|
225
|
+
y: 1024 ** 8
|
|
184
226
|
};
|
|
185
227
|
var OUTPUT_BYTE_UNITS = {
|
|
186
228
|
B: 1,
|
|
@@ -218,10 +260,7 @@ function parseBytes(value, outputUnit = "B") {
|
|
|
218
260
|
}
|
|
219
261
|
return bytes2 / divisor;
|
|
220
262
|
}
|
|
221
|
-
|
|
222
|
-
if (mult === void 0) {
|
|
223
|
-
mult = BYTE_UNITS[unit.toLowerCase()];
|
|
224
|
-
}
|
|
263
|
+
const mult = BYTE_UNITS[unit];
|
|
225
264
|
if (mult === void 0) return NaN;
|
|
226
265
|
const bytes = num * mult;
|
|
227
266
|
if (Math.abs(bytes) > Number.MAX_SAFE_INTEGER) {
|
|
@@ -277,35 +316,114 @@ function stringSegmentsToKey(segments) {
|
|
|
277
316
|
return t;
|
|
278
317
|
}).join(".");
|
|
279
318
|
}
|
|
319
|
+
function prefixSelfRefRemainder(s, fullKey) {
|
|
320
|
+
const texts = s.segments.map((seg) => seg.text);
|
|
321
|
+
if (!stringSegmentsToKey(texts).startsWith(fullKey + ".")) return null;
|
|
322
|
+
for (let n = 1; n < texts.length; n++) {
|
|
323
|
+
if (stringSegmentsToKey(texts.slice(0, n)) === fullKey) return texts.slice(n);
|
|
324
|
+
}
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
function navigateResolverValue(v, remainder) {
|
|
328
|
+
let cur = v;
|
|
329
|
+
for (const seg of remainder) {
|
|
330
|
+
if (isSubst(cur) || isConcat(cur)) return null;
|
|
331
|
+
if (isResObj(cur)) {
|
|
332
|
+
const next = cur.fields.get(seg);
|
|
333
|
+
if (next === void 0) return void 0;
|
|
334
|
+
cur = next;
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
const hv = cur;
|
|
338
|
+
if (hv.kind === "object") {
|
|
339
|
+
const next = hv.fields.get(seg);
|
|
340
|
+
if (next === void 0) return void 0;
|
|
341
|
+
cur = next;
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
return void 0;
|
|
345
|
+
}
|
|
346
|
+
return cur;
|
|
347
|
+
}
|
|
348
|
+
function foldPrefixSelfRef(s, replacement, remainder) {
|
|
349
|
+
const navigated = navigateResolverValue(replacement, remainder);
|
|
350
|
+
if (navigated === null) return s;
|
|
351
|
+
if (navigated === void 0) {
|
|
352
|
+
return {
|
|
353
|
+
_kind: "subst-placeholder",
|
|
354
|
+
segments: s.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
|
|
355
|
+
optional: s.optional,
|
|
356
|
+
knownAbsent: true,
|
|
357
|
+
listSuffix: s.listSuffix,
|
|
358
|
+
line: s.line,
|
|
359
|
+
col: s.col,
|
|
360
|
+
prefixLen: s.prefixLen
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
return cloneResolverValue(navigated);
|
|
364
|
+
}
|
|
365
|
+
function mergeResObjLayers(base, top) {
|
|
366
|
+
const fields = new Map(base.fields);
|
|
367
|
+
for (const [k, tv] of top.fields) {
|
|
368
|
+
const bv = fields.get(k);
|
|
369
|
+
if (bv !== void 0 && isResObj(bv) && isResObj(tv)) {
|
|
370
|
+
fields.set(k, mergeResObjLayers(bv, tv));
|
|
371
|
+
} else {
|
|
372
|
+
fields.set(k, tv);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
const priorValues = new Map(base.priorValues);
|
|
376
|
+
for (const [k, pv] of top.priorValues) priorValues.set(k, pv);
|
|
377
|
+
const resetKeys = new Set(base.resetKeys);
|
|
378
|
+
for (const k of top.resetKeys) resetKeys.add(k);
|
|
379
|
+
return {
|
|
380
|
+
_kind: "res-obj",
|
|
381
|
+
fields,
|
|
382
|
+
priorValues,
|
|
383
|
+
resetKeys
|
|
384
|
+
};
|
|
385
|
+
}
|
|
280
386
|
function containsSelfRef(v, fullKey) {
|
|
281
|
-
|
|
282
|
-
|
|
387
|
+
return containsSelfRefInner(v, fullKey, true);
|
|
388
|
+
}
|
|
389
|
+
function containsSelfRefInner(v, fullKey, allowPrefix) {
|
|
390
|
+
if (isSubst(v))
|
|
391
|
+
return !v.knownAbsent && (substFullKey(v) === fullKey || allowPrefix && prefixSelfRefRemainder(v, fullKey) !== null);
|
|
392
|
+
if (isConcat(v)) return v.nodes.some((n) => containsSelfRefInner(n, fullKey, allowPrefix));
|
|
283
393
|
if (isResObj(v)) {
|
|
284
394
|
for (const f of v.fields.values()) {
|
|
285
|
-
if (
|
|
395
|
+
if (containsSelfRefInner(f, fullKey, false)) return true;
|
|
286
396
|
}
|
|
287
397
|
return false;
|
|
288
398
|
}
|
|
289
399
|
const hv = v;
|
|
290
400
|
if (hv.kind === "array") {
|
|
291
|
-
return hv.items.some((item) =>
|
|
401
|
+
return hv.items.some((item) => containsSelfRefInner(item, fullKey, allowPrefix));
|
|
292
402
|
}
|
|
293
403
|
if (hv.kind === "object") {
|
|
294
404
|
for (const f of hv.fields.values()) {
|
|
295
|
-
if (
|
|
405
|
+
if (containsSelfRefInner(f, fullKey, false)) return true;
|
|
296
406
|
}
|
|
297
407
|
return false;
|
|
298
408
|
}
|
|
299
409
|
return false;
|
|
300
410
|
}
|
|
301
411
|
function foldSelfRef(v, fullKey, replacement) {
|
|
412
|
+
return foldSelfRefInner(v, fullKey, replacement, true);
|
|
413
|
+
}
|
|
414
|
+
function foldSelfRefInner(v, fullKey, replacement, allowPrefix) {
|
|
302
415
|
if (isSubst(v)) {
|
|
303
|
-
|
|
416
|
+
if (substFullKey(v) === fullKey) return replacement;
|
|
417
|
+
if (allowPrefix) {
|
|
418
|
+
const remainder = prefixSelfRefRemainder(v, fullKey);
|
|
419
|
+
if (remainder !== null) return foldPrefixSelfRef(v, replacement, remainder);
|
|
420
|
+
}
|
|
421
|
+
return v;
|
|
304
422
|
}
|
|
305
423
|
if (isConcat(v)) {
|
|
306
424
|
return {
|
|
307
425
|
_kind: "concat-placeholder",
|
|
308
|
-
nodes: v.nodes.map((n) =>
|
|
426
|
+
nodes: v.nodes.map((n) => foldSelfRefInner(n, fullKey, replacement, allowPrefix)),
|
|
309
427
|
line: v.line,
|
|
310
428
|
col: v.col
|
|
311
429
|
};
|
|
@@ -313,7 +431,7 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
313
431
|
if (isResObj(v)) {
|
|
314
432
|
const newFields = /* @__PURE__ */ new Map();
|
|
315
433
|
for (const [k, val] of v.fields) {
|
|
316
|
-
newFields.set(k,
|
|
434
|
+
newFields.set(k, foldSelfRefInner(val, fullKey, replacement, false));
|
|
317
435
|
}
|
|
318
436
|
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
319
437
|
}
|
|
@@ -321,13 +439,15 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
321
439
|
if (hv.kind === "array") {
|
|
322
440
|
return {
|
|
323
441
|
kind: "array",
|
|
324
|
-
items: hv.items.map(
|
|
442
|
+
items: hv.items.map(
|
|
443
|
+
(item) => foldSelfRefInner(item, fullKey, replacement, allowPrefix)
|
|
444
|
+
)
|
|
325
445
|
};
|
|
326
446
|
}
|
|
327
447
|
if (hv.kind === "object") {
|
|
328
448
|
const newFields = /* @__PURE__ */ new Map();
|
|
329
449
|
for (const [k, val] of hv.fields) {
|
|
330
|
-
newFields.set(k,
|
|
450
|
+
newFields.set(k, foldSelfRefInner(val, fullKey, replacement, false));
|
|
331
451
|
}
|
|
332
452
|
return { kind: "object", fields: newFields };
|
|
333
453
|
}
|
|
@@ -336,10 +456,26 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
336
456
|
function foldOrSkipPrior(prior, fullKey, old) {
|
|
337
457
|
if (!containsSelfRef(prior, fullKey)) return cloneResolverValue(prior);
|
|
338
458
|
if (old === void 0) return foldOptionalSelfRefAbsent(prior, fullKey);
|
|
459
|
+
if (isSubst(prior)) {
|
|
460
|
+
const remainder = prefixSelfRefRemainder(prior, fullKey);
|
|
461
|
+
if (remainder !== null) {
|
|
462
|
+
const navigated = navigateResolverValue(old, remainder);
|
|
463
|
+
if (navigated === void 0 && prior.optional) return cloneResolverValue(old);
|
|
464
|
+
if (navigated !== null && navigated !== void 0 && isResObj(navigated) && isResObj(old)) {
|
|
465
|
+
return mergeResObjLayers(
|
|
466
|
+
cloneResolverValue(old),
|
|
467
|
+
cloneResolverValue(navigated)
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
339
472
|
return foldSelfRef(prior, fullKey, old);
|
|
340
473
|
}
|
|
341
474
|
function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
342
|
-
|
|
475
|
+
return foldOptionalSelfRefAbsentInner(v, fullKey, true);
|
|
476
|
+
}
|
|
477
|
+
function foldOptionalSelfRefAbsentInner(v, fullKey, allowPrefix) {
|
|
478
|
+
if (isSubst(v) && (substFullKey(v) === fullKey || allowPrefix && prefixSelfRefRemainder(v, fullKey) !== null)) {
|
|
343
479
|
if (!v.optional) return void 0;
|
|
344
480
|
return {
|
|
345
481
|
_kind: "subst-placeholder",
|
|
@@ -355,7 +491,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
355
491
|
if (isConcat(v)) {
|
|
356
492
|
const nodes = [];
|
|
357
493
|
for (const node of v.nodes) {
|
|
358
|
-
const folded =
|
|
494
|
+
const folded = foldOptionalSelfRefAbsentInner(node, fullKey, allowPrefix);
|
|
359
495
|
if (folded === void 0) return void 0;
|
|
360
496
|
nodes.push(folded);
|
|
361
497
|
}
|
|
@@ -364,7 +500,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
364
500
|
if (isResObj(v)) {
|
|
365
501
|
const fields = /* @__PURE__ */ new Map();
|
|
366
502
|
for (const [key, value] of v.fields) {
|
|
367
|
-
const folded =
|
|
503
|
+
const folded = foldOptionalSelfRefAbsentInner(value, fullKey, false);
|
|
368
504
|
if (folded === void 0) return void 0;
|
|
369
505
|
fields.set(key, folded);
|
|
370
506
|
}
|
|
@@ -374,7 +510,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
374
510
|
if (hv.kind === "array") {
|
|
375
511
|
const items = [];
|
|
376
512
|
for (const item of hv.items) {
|
|
377
|
-
const folded =
|
|
513
|
+
const folded = foldOptionalSelfRefAbsentInner(item, fullKey, allowPrefix);
|
|
378
514
|
if (folded === void 0) return void 0;
|
|
379
515
|
items.push(folded);
|
|
380
516
|
}
|
|
@@ -383,7 +519,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
383
519
|
if (hv.kind === "object") {
|
|
384
520
|
const fields = /* @__PURE__ */ new Map();
|
|
385
521
|
for (const [key, value] of hv.fields) {
|
|
386
|
-
const folded =
|
|
522
|
+
const folded = foldOptionalSelfRefAbsentInner(value, fullKey, false);
|
|
387
523
|
if (folded === void 0) return void 0;
|
|
388
524
|
fields.set(key, folded);
|
|
389
525
|
}
|
|
@@ -565,6 +701,31 @@ function stripBom(input) {
|
|
|
565
701
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
566
702
|
}
|
|
567
703
|
|
|
704
|
+
// src/internal/depth.ts
|
|
705
|
+
var MAX_PATH_SEGMENTS = 64;
|
|
706
|
+
function tooDeep(segments) {
|
|
707
|
+
return segments > MAX_PATH_SEGMENTS;
|
|
708
|
+
}
|
|
709
|
+
function guardStackDepth(fn, wrap) {
|
|
710
|
+
try {
|
|
711
|
+
return fn();
|
|
712
|
+
} catch (e) {
|
|
713
|
+
if (!isStackOverflow(e)) throw e;
|
|
714
|
+
throw wrap(STACK_MESSAGE);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
718
|
+
function isStackOverflow(e) {
|
|
719
|
+
if (!(e instanceof RangeError)) return false;
|
|
720
|
+
const m = e.message.toLowerCase();
|
|
721
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
722
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
723
|
+
m.includes("stack overflow");
|
|
724
|
+
}
|
|
725
|
+
function depthError(message) {
|
|
726
|
+
return new ConfigError(message, "");
|
|
727
|
+
}
|
|
728
|
+
|
|
568
729
|
// src/internal/properties/properties.ts
|
|
569
730
|
function parseProperties(input) {
|
|
570
731
|
const pairs = [];
|
|
@@ -572,7 +733,15 @@ function parseProperties(input) {
|
|
|
572
733
|
const [rawKey, rawValue] = splitKeyValue(text);
|
|
573
734
|
const key = unescapeProps(rawKey, line);
|
|
574
735
|
if (key === "") continue;
|
|
575
|
-
|
|
736
|
+
const segments = key.split(".");
|
|
737
|
+
if (tooDeep(segments.length)) {
|
|
738
|
+
throw new ParseError(
|
|
739
|
+
`key maps to a path ${segments.length} segments deep, over the limit of ${MAX_PATH_SEGMENTS}`,
|
|
740
|
+
line,
|
|
741
|
+
1
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
pairs.push([segments, unescapeProps(rawValue, line)]);
|
|
576
745
|
}
|
|
577
746
|
return nestPairs(pairs);
|
|
578
747
|
}
|
|
@@ -747,6 +916,12 @@ var SubstitutionResolver = class {
|
|
|
747
916
|
// Cross-impl with rs.hocon v1.5.1's resolving_field_path (same purpose,
|
|
748
917
|
// same prefix-match semantics).
|
|
749
918
|
this.resolvingFieldPath = [];
|
|
919
|
+
// S13a.12 recursion guard: field keys whose prior is currently being
|
|
920
|
+
// resolved through the prefix-self-ref branch. Saved priors are
|
|
921
|
+
// prefix-self-ref-free by the fold invariant, so re-entry only happens on
|
|
922
|
+
// a shape the fold could not see through (a live subst mid-navigation) —
|
|
923
|
+
// report it as a cycle instead of recursing forever.
|
|
924
|
+
this.resolvingPrefixPriors = /* @__PURE__ */ new Set();
|
|
750
925
|
}
|
|
751
926
|
/** Returns a prefix for error messages, including origin info when set. */
|
|
752
927
|
originPrefix() {
|
|
@@ -761,46 +936,57 @@ var SubstitutionResolver = class {
|
|
|
761
936
|
this.resolvingFieldPath.push(key);
|
|
762
937
|
const fullCacheKey = stringSegmentsToKey(this.resolvingFieldPath);
|
|
763
938
|
this.cache.delete(fullCacheKey);
|
|
764
|
-
let resolved;
|
|
765
939
|
try {
|
|
766
|
-
resolved = this.resolveVal(val, obj);
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
940
|
+
const resolved = this.resolveVal(val, obj);
|
|
941
|
+
if (resolved !== void 0) {
|
|
942
|
+
if (resolved.kind === "object") {
|
|
943
|
+
const prior = obj.priorValues.get(key);
|
|
944
|
+
if (prior !== void 0) {
|
|
945
|
+
const priorResolved = this.resolveVal(prior, obj);
|
|
946
|
+
if (priorResolved !== void 0 && priorResolved.kind === "object") {
|
|
947
|
+
const finalValue = deepMergeHoconValues(
|
|
948
|
+
priorResolved,
|
|
949
|
+
resolved
|
|
950
|
+
);
|
|
951
|
+
result.set(key, finalValue);
|
|
952
|
+
this.cache.set(fullCacheKey, finalValue);
|
|
953
|
+
this.cacheDescendants(fullCacheKey, finalValue);
|
|
954
|
+
continue;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
result.set(key, resolved);
|
|
959
|
+
this.cache.set(fullCacheKey, resolved);
|
|
960
|
+
this.cacheDescendants(fullCacheKey, resolved);
|
|
961
|
+
} else {
|
|
772
962
|
const prior = obj.priorValues.get(key);
|
|
773
963
|
if (prior !== void 0) {
|
|
774
964
|
const priorResolved = this.resolveVal(prior, obj);
|
|
775
|
-
if (priorResolved !== void 0
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
);
|
|
780
|
-
result.set(key, finalValue);
|
|
781
|
-
this.cache.set(fullCacheKey, finalValue);
|
|
782
|
-
this.cacheDescendants(fullCacheKey, finalValue);
|
|
783
|
-
continue;
|
|
965
|
+
if (priorResolved !== void 0) {
|
|
966
|
+
result.set(key, priorResolved);
|
|
967
|
+
this.cache.set(fullCacheKey, priorResolved);
|
|
968
|
+
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
784
969
|
}
|
|
785
970
|
}
|
|
786
971
|
}
|
|
787
|
-
|
|
788
|
-
this.
|
|
789
|
-
this.cacheDescendants(fullCacheKey, resolved);
|
|
790
|
-
} else {
|
|
791
|
-
const prior = obj.priorValues.get(key);
|
|
792
|
-
if (prior !== void 0) {
|
|
793
|
-
const priorResolved = this.resolveVal(prior, obj);
|
|
794
|
-
if (priorResolved !== void 0) {
|
|
795
|
-
result.set(key, priorResolved);
|
|
796
|
-
this.cache.set(fullCacheKey, priorResolved);
|
|
797
|
-
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
798
|
-
}
|
|
799
|
-
}
|
|
972
|
+
} finally {
|
|
973
|
+
this.resolvingFieldPath.pop();
|
|
800
974
|
}
|
|
801
975
|
}
|
|
802
976
|
return { kind: "object", fields: result };
|
|
803
977
|
}
|
|
978
|
+
/** S13a.12: walk resolved-object fields by segment text. A missing segment
|
|
979
|
+
* or a walk into a scalar/array is path-absent → undefined. */
|
|
980
|
+
navigateResolved(v, remainder) {
|
|
981
|
+
let cur = v;
|
|
982
|
+
for (const seg of remainder) {
|
|
983
|
+
if (cur.kind !== "object") return void 0;
|
|
984
|
+
const next = cur.fields.get(seg);
|
|
985
|
+
if (next === void 0) return void 0;
|
|
986
|
+
cur = next;
|
|
987
|
+
}
|
|
988
|
+
return cur;
|
|
989
|
+
}
|
|
804
990
|
cacheDescendants(prefix, value) {
|
|
805
991
|
if (value.kind !== "object") return;
|
|
806
992
|
for (const [key, child] of value.fields) {
|
|
@@ -823,17 +1009,59 @@ var SubstitutionResolver = class {
|
|
|
823
1009
|
if (isResObj(v)) return this.resolveResObj(v);
|
|
824
1010
|
const hv = v;
|
|
825
1011
|
if (hv.kind === "array") {
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
)
|
|
831
|
-
}
|
|
1012
|
+
const items = [];
|
|
1013
|
+
for (const item of hv.items) {
|
|
1014
|
+
const resolved = this.resolveVal(item, scope);
|
|
1015
|
+
if (resolved === void 0) continue;
|
|
1016
|
+
items.push(resolved);
|
|
1017
|
+
}
|
|
1018
|
+
return { kind: "array", items };
|
|
832
1019
|
}
|
|
833
1020
|
return hv;
|
|
834
1021
|
}
|
|
835
1022
|
resolveSubst(s, scope) {
|
|
836
|
-
if (s.knownAbsent)
|
|
1023
|
+
if (s.knownAbsent) {
|
|
1024
|
+
if (!s.optional) {
|
|
1025
|
+
if (this.opts.allowUnresolved) return s;
|
|
1026
|
+
const k = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
1027
|
+
throw new ResolveError(
|
|
1028
|
+
`${this.originPrefix()}could not resolve substitution: \${${k}}`,
|
|
1029
|
+
k,
|
|
1030
|
+
s.line,
|
|
1031
|
+
s.col
|
|
1032
|
+
);
|
|
1033
|
+
}
|
|
1034
|
+
return void 0;
|
|
1035
|
+
}
|
|
1036
|
+
{
|
|
1037
|
+
const rfp = this.resolvingFieldPath;
|
|
1038
|
+
const sTexts = s.segments.map((seg) => seg.text);
|
|
1039
|
+
if (rfp.length > 0 && rfp.length < sTexts.length && stringSegmentsToKey(sTexts.slice(0, rfp.length)) === stringSegmentsToKey(rfp)) {
|
|
1040
|
+
const guardKey = stringSegmentsToKey(rfp);
|
|
1041
|
+
const prior = scope.priorValues.get(rfp[rfp.length - 1]);
|
|
1042
|
+
if (prior !== void 0 && !this.resolvingPrefixPriors.has(guardKey)) {
|
|
1043
|
+
this.resolvingPrefixPriors.add(guardKey);
|
|
1044
|
+
try {
|
|
1045
|
+
const priorResolved = this.resolveVal(prior, scope);
|
|
1046
|
+
if (priorResolved !== void 0) {
|
|
1047
|
+
const navigated = this.navigateResolved(priorResolved, sTexts.slice(rfp.length));
|
|
1048
|
+
if (navigated !== void 0) return navigated;
|
|
1049
|
+
}
|
|
1050
|
+
} finally {
|
|
1051
|
+
this.resolvingPrefixPriors.delete(guardKey);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
if (s.optional) return void 0;
|
|
1055
|
+
if (this.opts.allowUnresolved) return s;
|
|
1056
|
+
const k = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
1057
|
+
throw new ResolveError(
|
|
1058
|
+
`${this.originPrefix()}could not resolve substitution: \${${k}}`,
|
|
1059
|
+
k,
|
|
1060
|
+
s.line,
|
|
1061
|
+
s.col
|
|
1062
|
+
);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
837
1065
|
const key = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
838
1066
|
if (this.cache.has(key)) return this.cache.get(key);
|
|
839
1067
|
if (this.resolving.has(key)) {
|
|
@@ -1153,6 +1381,121 @@ function hoconValueToResObj2(value) {
|
|
|
1153
1381
|
return obj;
|
|
1154
1382
|
}
|
|
1155
1383
|
|
|
1384
|
+
// src/render-hocon.ts
|
|
1385
|
+
function renderHoconFromRoot(root) {
|
|
1386
|
+
const out = [];
|
|
1387
|
+
renderObjectBody(out, root, 0);
|
|
1388
|
+
return out.join("");
|
|
1389
|
+
}
|
|
1390
|
+
function renderObjectBody(out, o, depth) {
|
|
1391
|
+
const indent = " ".repeat(depth);
|
|
1392
|
+
for (const [k, v] of o.fields) {
|
|
1393
|
+
out.push(indent, renderKey(k));
|
|
1394
|
+
if (v.kind === "object") {
|
|
1395
|
+
out.push(" {");
|
|
1396
|
+
if (v.fields.size === 0) {
|
|
1397
|
+
out.push("}\n");
|
|
1398
|
+
continue;
|
|
1399
|
+
}
|
|
1400
|
+
out.push("\n");
|
|
1401
|
+
renderObjectBody(out, v, depth + 1);
|
|
1402
|
+
out.push(indent, "}\n");
|
|
1403
|
+
} else {
|
|
1404
|
+
out.push(" = ");
|
|
1405
|
+
renderValue(out, v, depth);
|
|
1406
|
+
out.push("\n");
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
function renderValue(out, v, depth) {
|
|
1411
|
+
switch (v.kind) {
|
|
1412
|
+
case "object": {
|
|
1413
|
+
if (v.fields.size === 0) {
|
|
1414
|
+
out.push("{}");
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1417
|
+
out.push("{\n");
|
|
1418
|
+
renderObjectBody(out, v, depth + 1);
|
|
1419
|
+
out.push(" ".repeat(depth), "}");
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1422
|
+
case "array":
|
|
1423
|
+
renderArray(out, v, depth);
|
|
1424
|
+
return;
|
|
1425
|
+
case "scalar":
|
|
1426
|
+
out.push(renderScalar(v));
|
|
1427
|
+
return;
|
|
1428
|
+
default:
|
|
1429
|
+
throw new ConfigError(
|
|
1430
|
+
"renderHocon: unrenderable value (config must be resolved data)",
|
|
1431
|
+
""
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
function renderArray(out, a, depth) {
|
|
1436
|
+
if (a.items.length === 0) {
|
|
1437
|
+
out.push("[]");
|
|
1438
|
+
return;
|
|
1439
|
+
}
|
|
1440
|
+
const inner = " ".repeat(depth + 1);
|
|
1441
|
+
out.push("[\n");
|
|
1442
|
+
for (const e of a.items) {
|
|
1443
|
+
out.push(inner);
|
|
1444
|
+
renderValue(out, e, depth + 1);
|
|
1445
|
+
out.push("\n");
|
|
1446
|
+
}
|
|
1447
|
+
out.push(" ".repeat(depth), "]");
|
|
1448
|
+
}
|
|
1449
|
+
function renderScalar(s) {
|
|
1450
|
+
switch (s.valueType) {
|
|
1451
|
+
case "null":
|
|
1452
|
+
return "null";
|
|
1453
|
+
case "boolean":
|
|
1454
|
+
case "number":
|
|
1455
|
+
return s.raw;
|
|
1456
|
+
case "string":
|
|
1457
|
+
return renderString(s.raw);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
var SAFE_UNQUOTED_KEY = /^[A-Za-z0-9_-]+$/;
|
|
1461
|
+
function renderKey(k) {
|
|
1462
|
+
if (k === "include") return quoteString(k);
|
|
1463
|
+
return SAFE_UNQUOTED_KEY.test(k) ? k : quoteString(k);
|
|
1464
|
+
}
|
|
1465
|
+
var SAFE_BARE_STRING = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
1466
|
+
var STRING_KEYWORDS = /* @__PURE__ */ new Set(["true", "false", "null", "yes", "no", "on", "off"]);
|
|
1467
|
+
function renderString(s) {
|
|
1468
|
+
return SAFE_BARE_STRING.test(s) && !STRING_KEYWORDS.has(s.toLowerCase()) ? s : quoteString(s);
|
|
1469
|
+
}
|
|
1470
|
+
function quoteString(s) {
|
|
1471
|
+
if (s.includes("\n") && !s.includes("\r") && !s.includes('"""') && !s.endsWith('"')) {
|
|
1472
|
+
return `"""${s}"""`;
|
|
1473
|
+
}
|
|
1474
|
+
let b = '"';
|
|
1475
|
+
for (const ch of s) {
|
|
1476
|
+
switch (ch) {
|
|
1477
|
+
case '"':
|
|
1478
|
+
b += '\\"';
|
|
1479
|
+
break;
|
|
1480
|
+
case "\\":
|
|
1481
|
+
b += "\\\\";
|
|
1482
|
+
break;
|
|
1483
|
+
case "\n":
|
|
1484
|
+
b += "\\n";
|
|
1485
|
+
break;
|
|
1486
|
+
case "\r":
|
|
1487
|
+
b += "\\r";
|
|
1488
|
+
break;
|
|
1489
|
+
case " ":
|
|
1490
|
+
b += "\\t";
|
|
1491
|
+
break;
|
|
1492
|
+
default:
|
|
1493
|
+
b += ch;
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
return b + '"';
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1156
1499
|
// src/config.ts
|
|
1157
1500
|
var Config = class _Config {
|
|
1158
1501
|
constructor(root, opts) {
|
|
@@ -1458,6 +1801,36 @@ var Config = class _Config {
|
|
|
1458
1801
|
toObject(opts) {
|
|
1459
1802
|
return hoconToJs(this.root, opts?.nullPrototype === true);
|
|
1460
1803
|
}
|
|
1804
|
+
/**
|
|
1805
|
+
* Renders this resolved Config as HOCON text (E18; lockstep with go.hocon's
|
|
1806
|
+
* `Config.RenderHOCON`, v1.11.0).
|
|
1807
|
+
*
|
|
1808
|
+
* The output round-trips: parsing it back yields the same value tree. That
|
|
1809
|
+
* is the correctness contract, not byte-for-byte formatting — a scalar is
|
|
1810
|
+
* quoted whenever leaving it bare would re-parse as a different type (a
|
|
1811
|
+
* string `"8080"` becomes `"8080"`, not `8080`), and left bare only when it
|
|
1812
|
+
* provably cannot.
|
|
1813
|
+
*
|
|
1814
|
+
* The Config must be resolved and hold only data (objects, arrays, string /
|
|
1815
|
+
* number / boolean / null scalars) — exactly what {@link fromMap} and the
|
|
1816
|
+
* format adapters produce. An unresolved placeholder throws
|
|
1817
|
+
* {@link ConfigError}; substitutions have no textual round trip through a
|
|
1818
|
+
* value tree.
|
|
1819
|
+
*
|
|
1820
|
+
* The root object's fields are emitted without enclosing braces, nested
|
|
1821
|
+
* objects as `key { … }`, arrays as newline-separated `[ … ]`, indented two
|
|
1822
|
+
* spaces. Source comments are not represented — a value tree does not carry
|
|
1823
|
+
* them.
|
|
1824
|
+
*/
|
|
1825
|
+
renderHocon() {
|
|
1826
|
+
if (!this._resolved) {
|
|
1827
|
+
throw new ConfigError(
|
|
1828
|
+
"renderHocon: unrenderable unresolved substitution (config must be resolved data)",
|
|
1829
|
+
""
|
|
1830
|
+
);
|
|
1831
|
+
}
|
|
1832
|
+
return renderHoconFromRoot(this.root);
|
|
1833
|
+
}
|
|
1461
1834
|
/**
|
|
1462
1835
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
1463
1836
|
* JSON (sorted keys, no whitespace). Used by Layer-2 fixture tests to compare
|
|
@@ -1671,7 +2044,10 @@ function normalizeLeadingZeroNumber(raw) {
|
|
|
1671
2044
|
|
|
1672
2045
|
// src/value-factory.ts
|
|
1673
2046
|
function fromMap(values, originDescription) {
|
|
1674
|
-
const fields =
|
|
2047
|
+
const fields = guardStackDepth(
|
|
2048
|
+
() => coerceObject(values, ""),
|
|
2049
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
2050
|
+
);
|
|
1675
2051
|
const root = { kind: "object", fields };
|
|
1676
2052
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1677
2053
|
}
|