@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
|
@@ -34,13 +34,22 @@ function coerceNumber(value) {
|
|
|
34
34
|
return Number(value);
|
|
35
35
|
}
|
|
36
36
|
var DURATION_UNITS = {
|
|
37
|
+
// S19.1–S19.3: the bare nano/micro/milli (+plural) aliases are part of the
|
|
38
|
+
// spec's unit lists (HOCON.md L1307–L1309) and accepted by Lightbend
|
|
39
|
+
// (typesafe-config 1.4.6 probe, 2026-08-18); they were missing here.
|
|
37
40
|
ns: 1e-6,
|
|
41
|
+
nano: 1e-6,
|
|
42
|
+
nanos: 1e-6,
|
|
38
43
|
nanosecond: 1e-6,
|
|
39
44
|
nanoseconds: 1e-6,
|
|
40
45
|
us: 1e-3,
|
|
46
|
+
micro: 1e-3,
|
|
47
|
+
micros: 1e-3,
|
|
41
48
|
microsecond: 1e-3,
|
|
42
49
|
microseconds: 1e-3,
|
|
43
50
|
ms: 1,
|
|
51
|
+
milli: 1,
|
|
52
|
+
millis: 1,
|
|
44
53
|
millisecond: 1,
|
|
45
54
|
milliseconds: 1,
|
|
46
55
|
s: 1e3,
|
|
@@ -92,37 +101,76 @@ function parseDuration(value, outputUnit = "ms") {
|
|
|
92
101
|
return ms / divisor;
|
|
93
102
|
}
|
|
94
103
|
var BYTE_UNITS = {
|
|
104
|
+
// S21.1–S21.4 — the EXACT Lightbend/typesafe-config unit set (1.4.6 probe,
|
|
105
|
+
// 2026-08-18). Multi-letter units are case-sensitive: the SI decimal short
|
|
106
|
+
// form is `kB` (NOT `KB`/`kb` — Lightbend rejects both), higher decimals
|
|
107
|
+
// are `MB`…`YB`, binary prefixes are `Ki`/`KiB`…`Yi`/`YiB` with capital
|
|
108
|
+
// first letter, and long forms are lowercase only (`kilobyte`, never
|
|
109
|
+
// `Kilobyte`). Only the bare byte unit (`B`/`b`) and the single-letter
|
|
110
|
+
// -Xmx forms accept both cases. The old case-insensitive fallback and the
|
|
111
|
+
// lowercase alias rows accepted spellings Lightbend rejects — removed.
|
|
95
112
|
B: 1,
|
|
113
|
+
b: 1,
|
|
96
114
|
byte: 1,
|
|
97
115
|
bytes: 1,
|
|
98
|
-
|
|
116
|
+
kB: 1e3,
|
|
99
117
|
kilobyte: 1e3,
|
|
100
118
|
kilobytes: 1e3,
|
|
101
|
-
KiB: 1024,
|
|
102
|
-
kibibyte: 1024,
|
|
103
|
-
kibibytes: 1024,
|
|
104
119
|
MB: 1e6,
|
|
105
120
|
megabyte: 1e6,
|
|
106
121
|
megabytes: 1e6,
|
|
107
|
-
MiB: 1048576,
|
|
108
|
-
mebibyte: 1048576,
|
|
109
|
-
mebibytes: 1048576,
|
|
110
122
|
GB: 1e9,
|
|
111
123
|
gigabyte: 1e9,
|
|
112
124
|
gigabytes: 1e9,
|
|
113
|
-
GiB: 1073741824,
|
|
114
|
-
gibibyte: 1073741824,
|
|
115
|
-
gibibytes: 1073741824,
|
|
116
125
|
TB: 1e12,
|
|
117
126
|
terabyte: 1e12,
|
|
118
127
|
terabytes: 1e12,
|
|
128
|
+
PB: 1e15,
|
|
129
|
+
petabyte: 1e15,
|
|
130
|
+
petabytes: 1e15,
|
|
131
|
+
EB: 1e18,
|
|
132
|
+
exabyte: 1e18,
|
|
133
|
+
exabytes: 1e18,
|
|
134
|
+
ZB: 1e21,
|
|
135
|
+
zettabyte: 1e21,
|
|
136
|
+
zettabytes: 1e21,
|
|
137
|
+
YB: 1e24,
|
|
138
|
+
yottabyte: 1e24,
|
|
139
|
+
yottabytes: 1e24,
|
|
140
|
+
Ki: 1024,
|
|
141
|
+
KiB: 1024,
|
|
142
|
+
kibibyte: 1024,
|
|
143
|
+
kibibytes: 1024,
|
|
144
|
+
Mi: 1048576,
|
|
145
|
+
MiB: 1048576,
|
|
146
|
+
mebibyte: 1048576,
|
|
147
|
+
mebibytes: 1048576,
|
|
148
|
+
Gi: 1073741824,
|
|
149
|
+
GiB: 1073741824,
|
|
150
|
+
gibibyte: 1073741824,
|
|
151
|
+
gibibytes: 1073741824,
|
|
152
|
+
Ti: 1099511627776,
|
|
119
153
|
TiB: 1099511627776,
|
|
120
154
|
tebibyte: 1099511627776,
|
|
121
155
|
tebibytes: 1099511627776,
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
156
|
+
Pi: 1024 ** 5,
|
|
157
|
+
PiB: 1024 ** 5,
|
|
158
|
+
pebibyte: 1024 ** 5,
|
|
159
|
+
pebibytes: 1024 ** 5,
|
|
160
|
+
Ei: 1024 ** 6,
|
|
161
|
+
EiB: 1024 ** 6,
|
|
162
|
+
exbibyte: 1024 ** 6,
|
|
163
|
+
exbibytes: 1024 ** 6,
|
|
164
|
+
Zi: 1024 ** 7,
|
|
165
|
+
ZiB: 1024 ** 7,
|
|
166
|
+
zebibyte: 1024 ** 7,
|
|
167
|
+
zebibytes: 1024 ** 7,
|
|
168
|
+
Yi: 1024 ** 8,
|
|
169
|
+
YiB: 1024 ** 8,
|
|
170
|
+
yobibyte: 1024 ** 8,
|
|
171
|
+
yobibytes: 1024 ** 8,
|
|
172
|
+
// S21.4 — single-letter abbreviations → powers of two (java -Xmx
|
|
173
|
+
// convention); Lightbend accepts BOTH cases here, through the full ladder.
|
|
126
174
|
K: 1024,
|
|
127
175
|
k: 1024,
|
|
128
176
|
M: 1024 ** 2,
|
|
@@ -135,16 +183,10 @@ var BYTE_UNITS = {
|
|
|
135
183
|
p: 1024 ** 5,
|
|
136
184
|
E: 1024 ** 6,
|
|
137
185
|
e: 1024 ** 6,
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
mb: 1e6,
|
|
143
|
-
mib: 1048576,
|
|
144
|
-
gb: 1e9,
|
|
145
|
-
gib: 1073741824,
|
|
146
|
-
tb: 1e12,
|
|
147
|
-
tib: 1099511627776
|
|
186
|
+
Z: 1024 ** 7,
|
|
187
|
+
z: 1024 ** 7,
|
|
188
|
+
Y: 1024 ** 8,
|
|
189
|
+
y: 1024 ** 8
|
|
148
190
|
};
|
|
149
191
|
var OUTPUT_BYTE_UNITS = {
|
|
150
192
|
B: 1,
|
|
@@ -182,10 +224,7 @@ function parseBytes(value, outputUnit = "B") {
|
|
|
182
224
|
}
|
|
183
225
|
return bytes2 / divisor;
|
|
184
226
|
}
|
|
185
|
-
|
|
186
|
-
if (mult === void 0) {
|
|
187
|
-
mult = BYTE_UNITS[unit.toLowerCase()];
|
|
188
|
-
}
|
|
227
|
+
const mult = BYTE_UNITS[unit];
|
|
189
228
|
if (mult === void 0) return NaN;
|
|
190
229
|
const bytes = num * mult;
|
|
191
230
|
if (Math.abs(bytes) > Number.MAX_SAFE_INTEGER) {
|
|
@@ -241,35 +280,114 @@ function stringSegmentsToKey(segments) {
|
|
|
241
280
|
return t;
|
|
242
281
|
}).join(".");
|
|
243
282
|
}
|
|
283
|
+
function prefixSelfRefRemainder(s, fullKey) {
|
|
284
|
+
const texts = s.segments.map((seg) => seg.text);
|
|
285
|
+
if (!stringSegmentsToKey(texts).startsWith(fullKey + ".")) return null;
|
|
286
|
+
for (let n = 1; n < texts.length; n++) {
|
|
287
|
+
if (stringSegmentsToKey(texts.slice(0, n)) === fullKey) return texts.slice(n);
|
|
288
|
+
}
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
function navigateResolverValue(v, remainder) {
|
|
292
|
+
let cur = v;
|
|
293
|
+
for (const seg of remainder) {
|
|
294
|
+
if (isSubst(cur) || isConcat(cur)) return null;
|
|
295
|
+
if (isResObj(cur)) {
|
|
296
|
+
const next = cur.fields.get(seg);
|
|
297
|
+
if (next === void 0) return void 0;
|
|
298
|
+
cur = next;
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
const hv = cur;
|
|
302
|
+
if (hv.kind === "object") {
|
|
303
|
+
const next = hv.fields.get(seg);
|
|
304
|
+
if (next === void 0) return void 0;
|
|
305
|
+
cur = next;
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
return void 0;
|
|
309
|
+
}
|
|
310
|
+
return cur;
|
|
311
|
+
}
|
|
312
|
+
function foldPrefixSelfRef(s, replacement, remainder) {
|
|
313
|
+
const navigated = navigateResolverValue(replacement, remainder);
|
|
314
|
+
if (navigated === null) return s;
|
|
315
|
+
if (navigated === void 0) {
|
|
316
|
+
return {
|
|
317
|
+
_kind: "subst-placeholder",
|
|
318
|
+
segments: s.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
|
|
319
|
+
optional: s.optional,
|
|
320
|
+
knownAbsent: true,
|
|
321
|
+
listSuffix: s.listSuffix,
|
|
322
|
+
line: s.line,
|
|
323
|
+
col: s.col,
|
|
324
|
+
prefixLen: s.prefixLen
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
return cloneResolverValue(navigated);
|
|
328
|
+
}
|
|
329
|
+
function mergeResObjLayers(base, top) {
|
|
330
|
+
const fields = new Map(base.fields);
|
|
331
|
+
for (const [k, tv] of top.fields) {
|
|
332
|
+
const bv = fields.get(k);
|
|
333
|
+
if (bv !== void 0 && isResObj(bv) && isResObj(tv)) {
|
|
334
|
+
fields.set(k, mergeResObjLayers(bv, tv));
|
|
335
|
+
} else {
|
|
336
|
+
fields.set(k, tv);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
const priorValues = new Map(base.priorValues);
|
|
340
|
+
for (const [k, pv] of top.priorValues) priorValues.set(k, pv);
|
|
341
|
+
const resetKeys = new Set(base.resetKeys);
|
|
342
|
+
for (const k of top.resetKeys) resetKeys.add(k);
|
|
343
|
+
return {
|
|
344
|
+
_kind: "res-obj",
|
|
345
|
+
fields,
|
|
346
|
+
priorValues,
|
|
347
|
+
resetKeys
|
|
348
|
+
};
|
|
349
|
+
}
|
|
244
350
|
function containsSelfRef(v, fullKey) {
|
|
245
|
-
|
|
246
|
-
|
|
351
|
+
return containsSelfRefInner(v, fullKey, true);
|
|
352
|
+
}
|
|
353
|
+
function containsSelfRefInner(v, fullKey, allowPrefix) {
|
|
354
|
+
if (isSubst(v))
|
|
355
|
+
return !v.knownAbsent && (substFullKey(v) === fullKey || allowPrefix && prefixSelfRefRemainder(v, fullKey) !== null);
|
|
356
|
+
if (isConcat(v)) return v.nodes.some((n) => containsSelfRefInner(n, fullKey, allowPrefix));
|
|
247
357
|
if (isResObj(v)) {
|
|
248
358
|
for (const f of v.fields.values()) {
|
|
249
|
-
if (
|
|
359
|
+
if (containsSelfRefInner(f, fullKey, false)) return true;
|
|
250
360
|
}
|
|
251
361
|
return false;
|
|
252
362
|
}
|
|
253
363
|
const hv = v;
|
|
254
364
|
if (hv.kind === "array") {
|
|
255
|
-
return hv.items.some((item) =>
|
|
365
|
+
return hv.items.some((item) => containsSelfRefInner(item, fullKey, allowPrefix));
|
|
256
366
|
}
|
|
257
367
|
if (hv.kind === "object") {
|
|
258
368
|
for (const f of hv.fields.values()) {
|
|
259
|
-
if (
|
|
369
|
+
if (containsSelfRefInner(f, fullKey, false)) return true;
|
|
260
370
|
}
|
|
261
371
|
return false;
|
|
262
372
|
}
|
|
263
373
|
return false;
|
|
264
374
|
}
|
|
265
375
|
function foldSelfRef(v, fullKey, replacement) {
|
|
376
|
+
return foldSelfRefInner(v, fullKey, replacement, true);
|
|
377
|
+
}
|
|
378
|
+
function foldSelfRefInner(v, fullKey, replacement, allowPrefix) {
|
|
266
379
|
if (isSubst(v)) {
|
|
267
|
-
|
|
380
|
+
if (substFullKey(v) === fullKey) return replacement;
|
|
381
|
+
if (allowPrefix) {
|
|
382
|
+
const remainder = prefixSelfRefRemainder(v, fullKey);
|
|
383
|
+
if (remainder !== null) return foldPrefixSelfRef(v, replacement, remainder);
|
|
384
|
+
}
|
|
385
|
+
return v;
|
|
268
386
|
}
|
|
269
387
|
if (isConcat(v)) {
|
|
270
388
|
return {
|
|
271
389
|
_kind: "concat-placeholder",
|
|
272
|
-
nodes: v.nodes.map((n) =>
|
|
390
|
+
nodes: v.nodes.map((n) => foldSelfRefInner(n, fullKey, replacement, allowPrefix)),
|
|
273
391
|
line: v.line,
|
|
274
392
|
col: v.col
|
|
275
393
|
};
|
|
@@ -277,7 +395,7 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
277
395
|
if (isResObj(v)) {
|
|
278
396
|
const newFields = /* @__PURE__ */ new Map();
|
|
279
397
|
for (const [k, val] of v.fields) {
|
|
280
|
-
newFields.set(k,
|
|
398
|
+
newFields.set(k, foldSelfRefInner(val, fullKey, replacement, false));
|
|
281
399
|
}
|
|
282
400
|
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
283
401
|
}
|
|
@@ -285,13 +403,15 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
285
403
|
if (hv.kind === "array") {
|
|
286
404
|
return {
|
|
287
405
|
kind: "array",
|
|
288
|
-
items: hv.items.map(
|
|
406
|
+
items: hv.items.map(
|
|
407
|
+
(item) => foldSelfRefInner(item, fullKey, replacement, allowPrefix)
|
|
408
|
+
)
|
|
289
409
|
};
|
|
290
410
|
}
|
|
291
411
|
if (hv.kind === "object") {
|
|
292
412
|
const newFields = /* @__PURE__ */ new Map();
|
|
293
413
|
for (const [k, val] of hv.fields) {
|
|
294
|
-
newFields.set(k,
|
|
414
|
+
newFields.set(k, foldSelfRefInner(val, fullKey, replacement, false));
|
|
295
415
|
}
|
|
296
416
|
return { kind: "object", fields: newFields };
|
|
297
417
|
}
|
|
@@ -300,10 +420,26 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
300
420
|
function foldOrSkipPrior(prior, fullKey, old) {
|
|
301
421
|
if (!containsSelfRef(prior, fullKey)) return cloneResolverValue(prior);
|
|
302
422
|
if (old === void 0) return foldOptionalSelfRefAbsent(prior, fullKey);
|
|
423
|
+
if (isSubst(prior)) {
|
|
424
|
+
const remainder = prefixSelfRefRemainder(prior, fullKey);
|
|
425
|
+
if (remainder !== null) {
|
|
426
|
+
const navigated = navigateResolverValue(old, remainder);
|
|
427
|
+
if (navigated === void 0 && prior.optional) return cloneResolverValue(old);
|
|
428
|
+
if (navigated !== null && navigated !== void 0 && isResObj(navigated) && isResObj(old)) {
|
|
429
|
+
return mergeResObjLayers(
|
|
430
|
+
cloneResolverValue(old),
|
|
431
|
+
cloneResolverValue(navigated)
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
303
436
|
return foldSelfRef(prior, fullKey, old);
|
|
304
437
|
}
|
|
305
438
|
function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
306
|
-
|
|
439
|
+
return foldOptionalSelfRefAbsentInner(v, fullKey, true);
|
|
440
|
+
}
|
|
441
|
+
function foldOptionalSelfRefAbsentInner(v, fullKey, allowPrefix) {
|
|
442
|
+
if (isSubst(v) && (substFullKey(v) === fullKey || allowPrefix && prefixSelfRefRemainder(v, fullKey) !== null)) {
|
|
307
443
|
if (!v.optional) return void 0;
|
|
308
444
|
return {
|
|
309
445
|
_kind: "subst-placeholder",
|
|
@@ -319,7 +455,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
319
455
|
if (isConcat(v)) {
|
|
320
456
|
const nodes = [];
|
|
321
457
|
for (const node of v.nodes) {
|
|
322
|
-
const folded =
|
|
458
|
+
const folded = foldOptionalSelfRefAbsentInner(node, fullKey, allowPrefix);
|
|
323
459
|
if (folded === void 0) return void 0;
|
|
324
460
|
nodes.push(folded);
|
|
325
461
|
}
|
|
@@ -328,7 +464,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
328
464
|
if (isResObj(v)) {
|
|
329
465
|
const fields = /* @__PURE__ */ new Map();
|
|
330
466
|
for (const [key, value] of v.fields) {
|
|
331
|
-
const folded =
|
|
467
|
+
const folded = foldOptionalSelfRefAbsentInner(value, fullKey, false);
|
|
332
468
|
if (folded === void 0) return void 0;
|
|
333
469
|
fields.set(key, folded);
|
|
334
470
|
}
|
|
@@ -338,7 +474,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
338
474
|
if (hv.kind === "array") {
|
|
339
475
|
const items = [];
|
|
340
476
|
for (const item of hv.items) {
|
|
341
|
-
const folded =
|
|
477
|
+
const folded = foldOptionalSelfRefAbsentInner(item, fullKey, allowPrefix);
|
|
342
478
|
if (folded === void 0) return void 0;
|
|
343
479
|
items.push(folded);
|
|
344
480
|
}
|
|
@@ -347,7 +483,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
347
483
|
if (hv.kind === "object") {
|
|
348
484
|
const fields = /* @__PURE__ */ new Map();
|
|
349
485
|
for (const [key, value] of hv.fields) {
|
|
350
|
-
const folded =
|
|
486
|
+
const folded = foldOptionalSelfRefAbsentInner(value, fullKey, false);
|
|
351
487
|
if (folded === void 0) return void 0;
|
|
352
488
|
fields.set(key, folded);
|
|
353
489
|
}
|
|
@@ -529,6 +665,31 @@ function stripBom(input) {
|
|
|
529
665
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
530
666
|
}
|
|
531
667
|
|
|
668
|
+
// src/internal/depth.ts
|
|
669
|
+
var MAX_PATH_SEGMENTS = 64;
|
|
670
|
+
function tooDeep(segments) {
|
|
671
|
+
return segments > MAX_PATH_SEGMENTS;
|
|
672
|
+
}
|
|
673
|
+
function guardStackDepth(fn, wrap) {
|
|
674
|
+
try {
|
|
675
|
+
return fn();
|
|
676
|
+
} catch (e) {
|
|
677
|
+
if (!isStackOverflow(e)) throw e;
|
|
678
|
+
throw wrap(STACK_MESSAGE);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
682
|
+
function isStackOverflow(e) {
|
|
683
|
+
if (!(e instanceof RangeError)) return false;
|
|
684
|
+
const m = e.message.toLowerCase();
|
|
685
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
686
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
687
|
+
m.includes("stack overflow");
|
|
688
|
+
}
|
|
689
|
+
function depthError(message) {
|
|
690
|
+
return new ConfigError(message, "");
|
|
691
|
+
}
|
|
692
|
+
|
|
532
693
|
// src/internal/properties/properties.ts
|
|
533
694
|
function parseProperties(input) {
|
|
534
695
|
const pairs = [];
|
|
@@ -536,7 +697,15 @@ function parseProperties(input) {
|
|
|
536
697
|
const [rawKey, rawValue] = splitKeyValue(text);
|
|
537
698
|
const key = unescapeProps(rawKey, line);
|
|
538
699
|
if (key === "") continue;
|
|
539
|
-
|
|
700
|
+
const segments = key.split(".");
|
|
701
|
+
if (tooDeep(segments.length)) {
|
|
702
|
+
throw new ParseError(
|
|
703
|
+
`key maps to a path ${segments.length} segments deep, over the limit of ${MAX_PATH_SEGMENTS}`,
|
|
704
|
+
line,
|
|
705
|
+
1
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
pairs.push([segments, unescapeProps(rawValue, line)]);
|
|
540
709
|
}
|
|
541
710
|
return nestPairs(pairs);
|
|
542
711
|
}
|
|
@@ -711,6 +880,12 @@ var SubstitutionResolver = class {
|
|
|
711
880
|
// Cross-impl with rs.hocon v1.5.1's resolving_field_path (same purpose,
|
|
712
881
|
// same prefix-match semantics).
|
|
713
882
|
this.resolvingFieldPath = [];
|
|
883
|
+
// S13a.12 recursion guard: field keys whose prior is currently being
|
|
884
|
+
// resolved through the prefix-self-ref branch. Saved priors are
|
|
885
|
+
// prefix-self-ref-free by the fold invariant, so re-entry only happens on
|
|
886
|
+
// a shape the fold could not see through (a live subst mid-navigation) —
|
|
887
|
+
// report it as a cycle instead of recursing forever.
|
|
888
|
+
this.resolvingPrefixPriors = /* @__PURE__ */ new Set();
|
|
714
889
|
}
|
|
715
890
|
/** Returns a prefix for error messages, including origin info when set. */
|
|
716
891
|
originPrefix() {
|
|
@@ -725,46 +900,57 @@ var SubstitutionResolver = class {
|
|
|
725
900
|
this.resolvingFieldPath.push(key);
|
|
726
901
|
const fullCacheKey = stringSegmentsToKey(this.resolvingFieldPath);
|
|
727
902
|
this.cache.delete(fullCacheKey);
|
|
728
|
-
let resolved;
|
|
729
903
|
try {
|
|
730
|
-
resolved = this.resolveVal(val, obj);
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
904
|
+
const resolved = this.resolveVal(val, obj);
|
|
905
|
+
if (resolved !== void 0) {
|
|
906
|
+
if (resolved.kind === "object") {
|
|
907
|
+
const prior = obj.priorValues.get(key);
|
|
908
|
+
if (prior !== void 0) {
|
|
909
|
+
const priorResolved = this.resolveVal(prior, obj);
|
|
910
|
+
if (priorResolved !== void 0 && priorResolved.kind === "object") {
|
|
911
|
+
const finalValue = deepMergeHoconValues(
|
|
912
|
+
priorResolved,
|
|
913
|
+
resolved
|
|
914
|
+
);
|
|
915
|
+
result.set(key, finalValue);
|
|
916
|
+
this.cache.set(fullCacheKey, finalValue);
|
|
917
|
+
this.cacheDescendants(fullCacheKey, finalValue);
|
|
918
|
+
continue;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
result.set(key, resolved);
|
|
923
|
+
this.cache.set(fullCacheKey, resolved);
|
|
924
|
+
this.cacheDescendants(fullCacheKey, resolved);
|
|
925
|
+
} else {
|
|
736
926
|
const prior = obj.priorValues.get(key);
|
|
737
927
|
if (prior !== void 0) {
|
|
738
928
|
const priorResolved = this.resolveVal(prior, obj);
|
|
739
|
-
if (priorResolved !== void 0
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
);
|
|
744
|
-
result.set(key, finalValue);
|
|
745
|
-
this.cache.set(fullCacheKey, finalValue);
|
|
746
|
-
this.cacheDescendants(fullCacheKey, finalValue);
|
|
747
|
-
continue;
|
|
929
|
+
if (priorResolved !== void 0) {
|
|
930
|
+
result.set(key, priorResolved);
|
|
931
|
+
this.cache.set(fullCacheKey, priorResolved);
|
|
932
|
+
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
748
933
|
}
|
|
749
934
|
}
|
|
750
935
|
}
|
|
751
|
-
|
|
752
|
-
this.
|
|
753
|
-
this.cacheDescendants(fullCacheKey, resolved);
|
|
754
|
-
} else {
|
|
755
|
-
const prior = obj.priorValues.get(key);
|
|
756
|
-
if (prior !== void 0) {
|
|
757
|
-
const priorResolved = this.resolveVal(prior, obj);
|
|
758
|
-
if (priorResolved !== void 0) {
|
|
759
|
-
result.set(key, priorResolved);
|
|
760
|
-
this.cache.set(fullCacheKey, priorResolved);
|
|
761
|
-
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
762
|
-
}
|
|
763
|
-
}
|
|
936
|
+
} finally {
|
|
937
|
+
this.resolvingFieldPath.pop();
|
|
764
938
|
}
|
|
765
939
|
}
|
|
766
940
|
return { kind: "object", fields: result };
|
|
767
941
|
}
|
|
942
|
+
/** S13a.12: walk resolved-object fields by segment text. A missing segment
|
|
943
|
+
* or a walk into a scalar/array is path-absent → undefined. */
|
|
944
|
+
navigateResolved(v, remainder) {
|
|
945
|
+
let cur = v;
|
|
946
|
+
for (const seg of remainder) {
|
|
947
|
+
if (cur.kind !== "object") return void 0;
|
|
948
|
+
const next = cur.fields.get(seg);
|
|
949
|
+
if (next === void 0) return void 0;
|
|
950
|
+
cur = next;
|
|
951
|
+
}
|
|
952
|
+
return cur;
|
|
953
|
+
}
|
|
768
954
|
cacheDescendants(prefix, value) {
|
|
769
955
|
if (value.kind !== "object") return;
|
|
770
956
|
for (const [key, child] of value.fields) {
|
|
@@ -787,17 +973,59 @@ var SubstitutionResolver = class {
|
|
|
787
973
|
if (isResObj(v)) return this.resolveResObj(v);
|
|
788
974
|
const hv = v;
|
|
789
975
|
if (hv.kind === "array") {
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
)
|
|
795
|
-
}
|
|
976
|
+
const items = [];
|
|
977
|
+
for (const item of hv.items) {
|
|
978
|
+
const resolved = this.resolveVal(item, scope);
|
|
979
|
+
if (resolved === void 0) continue;
|
|
980
|
+
items.push(resolved);
|
|
981
|
+
}
|
|
982
|
+
return { kind: "array", items };
|
|
796
983
|
}
|
|
797
984
|
return hv;
|
|
798
985
|
}
|
|
799
986
|
resolveSubst(s, scope) {
|
|
800
|
-
if (s.knownAbsent)
|
|
987
|
+
if (s.knownAbsent) {
|
|
988
|
+
if (!s.optional) {
|
|
989
|
+
if (this.opts.allowUnresolved) return s;
|
|
990
|
+
const k = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
991
|
+
throw new ResolveError(
|
|
992
|
+
`${this.originPrefix()}could not resolve substitution: \${${k}}`,
|
|
993
|
+
k,
|
|
994
|
+
s.line,
|
|
995
|
+
s.col
|
|
996
|
+
);
|
|
997
|
+
}
|
|
998
|
+
return void 0;
|
|
999
|
+
}
|
|
1000
|
+
{
|
|
1001
|
+
const rfp = this.resolvingFieldPath;
|
|
1002
|
+
const sTexts = s.segments.map((seg) => seg.text);
|
|
1003
|
+
if (rfp.length > 0 && rfp.length < sTexts.length && stringSegmentsToKey(sTexts.slice(0, rfp.length)) === stringSegmentsToKey(rfp)) {
|
|
1004
|
+
const guardKey = stringSegmentsToKey(rfp);
|
|
1005
|
+
const prior = scope.priorValues.get(rfp[rfp.length - 1]);
|
|
1006
|
+
if (prior !== void 0 && !this.resolvingPrefixPriors.has(guardKey)) {
|
|
1007
|
+
this.resolvingPrefixPriors.add(guardKey);
|
|
1008
|
+
try {
|
|
1009
|
+
const priorResolved = this.resolveVal(prior, scope);
|
|
1010
|
+
if (priorResolved !== void 0) {
|
|
1011
|
+
const navigated = this.navigateResolved(priorResolved, sTexts.slice(rfp.length));
|
|
1012
|
+
if (navigated !== void 0) return navigated;
|
|
1013
|
+
}
|
|
1014
|
+
} finally {
|
|
1015
|
+
this.resolvingPrefixPriors.delete(guardKey);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
if (s.optional) return void 0;
|
|
1019
|
+
if (this.opts.allowUnresolved) return s;
|
|
1020
|
+
const k = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
1021
|
+
throw new ResolveError(
|
|
1022
|
+
`${this.originPrefix()}could not resolve substitution: \${${k}}`,
|
|
1023
|
+
k,
|
|
1024
|
+
s.line,
|
|
1025
|
+
s.col
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
801
1029
|
const key = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
802
1030
|
if (this.cache.has(key)) return this.cache.get(key);
|
|
803
1031
|
if (this.resolving.has(key)) {
|
|
@@ -1117,6 +1345,121 @@ function hoconValueToResObj2(value) {
|
|
|
1117
1345
|
return obj;
|
|
1118
1346
|
}
|
|
1119
1347
|
|
|
1348
|
+
// src/render-hocon.ts
|
|
1349
|
+
function renderHoconFromRoot(root) {
|
|
1350
|
+
const out = [];
|
|
1351
|
+
renderObjectBody(out, root, 0);
|
|
1352
|
+
return out.join("");
|
|
1353
|
+
}
|
|
1354
|
+
function renderObjectBody(out, o, depth) {
|
|
1355
|
+
const indent = " ".repeat(depth);
|
|
1356
|
+
for (const [k, v] of o.fields) {
|
|
1357
|
+
out.push(indent, renderKey(k));
|
|
1358
|
+
if (v.kind === "object") {
|
|
1359
|
+
out.push(" {");
|
|
1360
|
+
if (v.fields.size === 0) {
|
|
1361
|
+
out.push("}\n");
|
|
1362
|
+
continue;
|
|
1363
|
+
}
|
|
1364
|
+
out.push("\n");
|
|
1365
|
+
renderObjectBody(out, v, depth + 1);
|
|
1366
|
+
out.push(indent, "}\n");
|
|
1367
|
+
} else {
|
|
1368
|
+
out.push(" = ");
|
|
1369
|
+
renderValue(out, v, depth);
|
|
1370
|
+
out.push("\n");
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
function renderValue(out, v, depth) {
|
|
1375
|
+
switch (v.kind) {
|
|
1376
|
+
case "object": {
|
|
1377
|
+
if (v.fields.size === 0) {
|
|
1378
|
+
out.push("{}");
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
out.push("{\n");
|
|
1382
|
+
renderObjectBody(out, v, depth + 1);
|
|
1383
|
+
out.push(" ".repeat(depth), "}");
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
case "array":
|
|
1387
|
+
renderArray(out, v, depth);
|
|
1388
|
+
return;
|
|
1389
|
+
case "scalar":
|
|
1390
|
+
out.push(renderScalar(v));
|
|
1391
|
+
return;
|
|
1392
|
+
default:
|
|
1393
|
+
throw new ConfigError(
|
|
1394
|
+
"renderHocon: unrenderable value (config must be resolved data)",
|
|
1395
|
+
""
|
|
1396
|
+
);
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
function renderArray(out, a, depth) {
|
|
1400
|
+
if (a.items.length === 0) {
|
|
1401
|
+
out.push("[]");
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1404
|
+
const inner = " ".repeat(depth + 1);
|
|
1405
|
+
out.push("[\n");
|
|
1406
|
+
for (const e of a.items) {
|
|
1407
|
+
out.push(inner);
|
|
1408
|
+
renderValue(out, e, depth + 1);
|
|
1409
|
+
out.push("\n");
|
|
1410
|
+
}
|
|
1411
|
+
out.push(" ".repeat(depth), "]");
|
|
1412
|
+
}
|
|
1413
|
+
function renderScalar(s) {
|
|
1414
|
+
switch (s.valueType) {
|
|
1415
|
+
case "null":
|
|
1416
|
+
return "null";
|
|
1417
|
+
case "boolean":
|
|
1418
|
+
case "number":
|
|
1419
|
+
return s.raw;
|
|
1420
|
+
case "string":
|
|
1421
|
+
return renderString(s.raw);
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
var SAFE_UNQUOTED_KEY = /^[A-Za-z0-9_-]+$/;
|
|
1425
|
+
function renderKey(k) {
|
|
1426
|
+
if (k === "include") return quoteString(k);
|
|
1427
|
+
return SAFE_UNQUOTED_KEY.test(k) ? k : quoteString(k);
|
|
1428
|
+
}
|
|
1429
|
+
var SAFE_BARE_STRING = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
1430
|
+
var STRING_KEYWORDS = /* @__PURE__ */ new Set(["true", "false", "null", "yes", "no", "on", "off"]);
|
|
1431
|
+
function renderString(s) {
|
|
1432
|
+
return SAFE_BARE_STRING.test(s) && !STRING_KEYWORDS.has(s.toLowerCase()) ? s : quoteString(s);
|
|
1433
|
+
}
|
|
1434
|
+
function quoteString(s) {
|
|
1435
|
+
if (s.includes("\n") && !s.includes("\r") && !s.includes('"""') && !s.endsWith('"')) {
|
|
1436
|
+
return `"""${s}"""`;
|
|
1437
|
+
}
|
|
1438
|
+
let b = '"';
|
|
1439
|
+
for (const ch of s) {
|
|
1440
|
+
switch (ch) {
|
|
1441
|
+
case '"':
|
|
1442
|
+
b += '\\"';
|
|
1443
|
+
break;
|
|
1444
|
+
case "\\":
|
|
1445
|
+
b += "\\\\";
|
|
1446
|
+
break;
|
|
1447
|
+
case "\n":
|
|
1448
|
+
b += "\\n";
|
|
1449
|
+
break;
|
|
1450
|
+
case "\r":
|
|
1451
|
+
b += "\\r";
|
|
1452
|
+
break;
|
|
1453
|
+
case " ":
|
|
1454
|
+
b += "\\t";
|
|
1455
|
+
break;
|
|
1456
|
+
default:
|
|
1457
|
+
b += ch;
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
return b + '"';
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1120
1463
|
// src/config.ts
|
|
1121
1464
|
var Config = class _Config {
|
|
1122
1465
|
constructor(root, opts) {
|
|
@@ -1422,6 +1765,36 @@ var Config = class _Config {
|
|
|
1422
1765
|
toObject(opts) {
|
|
1423
1766
|
return hoconToJs(this.root, opts?.nullPrototype === true);
|
|
1424
1767
|
}
|
|
1768
|
+
/**
|
|
1769
|
+
* Renders this resolved Config as HOCON text (E18; lockstep with go.hocon's
|
|
1770
|
+
* `Config.RenderHOCON`, v1.11.0).
|
|
1771
|
+
*
|
|
1772
|
+
* The output round-trips: parsing it back yields the same value tree. That
|
|
1773
|
+
* is the correctness contract, not byte-for-byte formatting — a scalar is
|
|
1774
|
+
* quoted whenever leaving it bare would re-parse as a different type (a
|
|
1775
|
+
* string `"8080"` becomes `"8080"`, not `8080`), and left bare only when it
|
|
1776
|
+
* provably cannot.
|
|
1777
|
+
*
|
|
1778
|
+
* The Config must be resolved and hold only data (objects, arrays, string /
|
|
1779
|
+
* number / boolean / null scalars) — exactly what {@link fromMap} and the
|
|
1780
|
+
* format adapters produce. An unresolved placeholder throws
|
|
1781
|
+
* {@link ConfigError}; substitutions have no textual round trip through a
|
|
1782
|
+
* value tree.
|
|
1783
|
+
*
|
|
1784
|
+
* The root object's fields are emitted without enclosing braces, nested
|
|
1785
|
+
* objects as `key { … }`, arrays as newline-separated `[ … ]`, indented two
|
|
1786
|
+
* spaces. Source comments are not represented — a value tree does not carry
|
|
1787
|
+
* them.
|
|
1788
|
+
*/
|
|
1789
|
+
renderHocon() {
|
|
1790
|
+
if (!this._resolved) {
|
|
1791
|
+
throw new ConfigError(
|
|
1792
|
+
"renderHocon: unrenderable unresolved substitution (config must be resolved data)",
|
|
1793
|
+
""
|
|
1794
|
+
);
|
|
1795
|
+
}
|
|
1796
|
+
return renderHoconFromRoot(this.root);
|
|
1797
|
+
}
|
|
1425
1798
|
/**
|
|
1426
1799
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
1427
1800
|
* JSON (sorted keys, no whitespace). Used by Layer-2 fixture tests to compare
|
|
@@ -1635,7 +2008,10 @@ function normalizeLeadingZeroNumber(raw) {
|
|
|
1635
2008
|
|
|
1636
2009
|
// src/value-factory.ts
|
|
1637
2010
|
function fromMap(values, originDescription) {
|
|
1638
|
-
const fields =
|
|
2011
|
+
const fields = guardStackDepth(
|
|
2012
|
+
() => coerceObject(values, ""),
|
|
2013
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
2014
|
+
);
|
|
1639
2015
|
const root = { kind: "object", fields };
|
|
1640
2016
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1641
2017
|
}
|