@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/adapters/env.js
CHANGED
|
@@ -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) {
|
|
@@ -232,35 +271,114 @@ function stringSegmentsToKey(segments) {
|
|
|
232
271
|
return t;
|
|
233
272
|
}).join(".");
|
|
234
273
|
}
|
|
274
|
+
function prefixSelfRefRemainder(s, fullKey) {
|
|
275
|
+
const texts = s.segments.map((seg) => seg.text);
|
|
276
|
+
if (!stringSegmentsToKey(texts).startsWith(fullKey + ".")) return null;
|
|
277
|
+
for (let n = 1; n < texts.length; n++) {
|
|
278
|
+
if (stringSegmentsToKey(texts.slice(0, n)) === fullKey) return texts.slice(n);
|
|
279
|
+
}
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
function navigateResolverValue(v, remainder) {
|
|
283
|
+
let cur = v;
|
|
284
|
+
for (const seg of remainder) {
|
|
285
|
+
if (isSubst(cur) || isConcat(cur)) return null;
|
|
286
|
+
if (isResObj(cur)) {
|
|
287
|
+
const next = cur.fields.get(seg);
|
|
288
|
+
if (next === void 0) return void 0;
|
|
289
|
+
cur = next;
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
const hv = cur;
|
|
293
|
+
if (hv.kind === "object") {
|
|
294
|
+
const next = hv.fields.get(seg);
|
|
295
|
+
if (next === void 0) return void 0;
|
|
296
|
+
cur = next;
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
return void 0;
|
|
300
|
+
}
|
|
301
|
+
return cur;
|
|
302
|
+
}
|
|
303
|
+
function foldPrefixSelfRef(s, replacement, remainder) {
|
|
304
|
+
const navigated = navigateResolverValue(replacement, remainder);
|
|
305
|
+
if (navigated === null) return s;
|
|
306
|
+
if (navigated === void 0) {
|
|
307
|
+
return {
|
|
308
|
+
_kind: "subst-placeholder",
|
|
309
|
+
segments: s.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
|
|
310
|
+
optional: s.optional,
|
|
311
|
+
knownAbsent: true,
|
|
312
|
+
listSuffix: s.listSuffix,
|
|
313
|
+
line: s.line,
|
|
314
|
+
col: s.col,
|
|
315
|
+
prefixLen: s.prefixLen
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
return cloneResolverValue(navigated);
|
|
319
|
+
}
|
|
320
|
+
function mergeResObjLayers(base, top) {
|
|
321
|
+
const fields = new Map(base.fields);
|
|
322
|
+
for (const [k, tv] of top.fields) {
|
|
323
|
+
const bv = fields.get(k);
|
|
324
|
+
if (bv !== void 0 && isResObj(bv) && isResObj(tv)) {
|
|
325
|
+
fields.set(k, mergeResObjLayers(bv, tv));
|
|
326
|
+
} else {
|
|
327
|
+
fields.set(k, tv);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
const priorValues = new Map(base.priorValues);
|
|
331
|
+
for (const [k, pv] of top.priorValues) priorValues.set(k, pv);
|
|
332
|
+
const resetKeys = new Set(base.resetKeys);
|
|
333
|
+
for (const k of top.resetKeys) resetKeys.add(k);
|
|
334
|
+
return {
|
|
335
|
+
_kind: "res-obj",
|
|
336
|
+
fields,
|
|
337
|
+
priorValues,
|
|
338
|
+
resetKeys
|
|
339
|
+
};
|
|
340
|
+
}
|
|
235
341
|
function containsSelfRef(v, fullKey) {
|
|
236
|
-
|
|
237
|
-
|
|
342
|
+
return containsSelfRefInner(v, fullKey, true);
|
|
343
|
+
}
|
|
344
|
+
function containsSelfRefInner(v, fullKey, allowPrefix) {
|
|
345
|
+
if (isSubst(v))
|
|
346
|
+
return !v.knownAbsent && (substFullKey(v) === fullKey || allowPrefix && prefixSelfRefRemainder(v, fullKey) !== null);
|
|
347
|
+
if (isConcat(v)) return v.nodes.some((n) => containsSelfRefInner(n, fullKey, allowPrefix));
|
|
238
348
|
if (isResObj(v)) {
|
|
239
349
|
for (const f of v.fields.values()) {
|
|
240
|
-
if (
|
|
350
|
+
if (containsSelfRefInner(f, fullKey, false)) return true;
|
|
241
351
|
}
|
|
242
352
|
return false;
|
|
243
353
|
}
|
|
244
354
|
const hv = v;
|
|
245
355
|
if (hv.kind === "array") {
|
|
246
|
-
return hv.items.some((item) =>
|
|
356
|
+
return hv.items.some((item) => containsSelfRefInner(item, fullKey, allowPrefix));
|
|
247
357
|
}
|
|
248
358
|
if (hv.kind === "object") {
|
|
249
359
|
for (const f of hv.fields.values()) {
|
|
250
|
-
if (
|
|
360
|
+
if (containsSelfRefInner(f, fullKey, false)) return true;
|
|
251
361
|
}
|
|
252
362
|
return false;
|
|
253
363
|
}
|
|
254
364
|
return false;
|
|
255
365
|
}
|
|
256
366
|
function foldSelfRef(v, fullKey, replacement) {
|
|
367
|
+
return foldSelfRefInner(v, fullKey, replacement, true);
|
|
368
|
+
}
|
|
369
|
+
function foldSelfRefInner(v, fullKey, replacement, allowPrefix) {
|
|
257
370
|
if (isSubst(v)) {
|
|
258
|
-
|
|
371
|
+
if (substFullKey(v) === fullKey) return replacement;
|
|
372
|
+
if (allowPrefix) {
|
|
373
|
+
const remainder = prefixSelfRefRemainder(v, fullKey);
|
|
374
|
+
if (remainder !== null) return foldPrefixSelfRef(v, replacement, remainder);
|
|
375
|
+
}
|
|
376
|
+
return v;
|
|
259
377
|
}
|
|
260
378
|
if (isConcat(v)) {
|
|
261
379
|
return {
|
|
262
380
|
_kind: "concat-placeholder",
|
|
263
|
-
nodes: v.nodes.map((n) =>
|
|
381
|
+
nodes: v.nodes.map((n) => foldSelfRefInner(n, fullKey, replacement, allowPrefix)),
|
|
264
382
|
line: v.line,
|
|
265
383
|
col: v.col
|
|
266
384
|
};
|
|
@@ -268,7 +386,7 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
268
386
|
if (isResObj(v)) {
|
|
269
387
|
const newFields = /* @__PURE__ */ new Map();
|
|
270
388
|
for (const [k, val] of v.fields) {
|
|
271
|
-
newFields.set(k,
|
|
389
|
+
newFields.set(k, foldSelfRefInner(val, fullKey, replacement, false));
|
|
272
390
|
}
|
|
273
391
|
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
274
392
|
}
|
|
@@ -276,13 +394,15 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
276
394
|
if (hv.kind === "array") {
|
|
277
395
|
return {
|
|
278
396
|
kind: "array",
|
|
279
|
-
items: hv.items.map(
|
|
397
|
+
items: hv.items.map(
|
|
398
|
+
(item) => foldSelfRefInner(item, fullKey, replacement, allowPrefix)
|
|
399
|
+
)
|
|
280
400
|
};
|
|
281
401
|
}
|
|
282
402
|
if (hv.kind === "object") {
|
|
283
403
|
const newFields = /* @__PURE__ */ new Map();
|
|
284
404
|
for (const [k, val] of hv.fields) {
|
|
285
|
-
newFields.set(k,
|
|
405
|
+
newFields.set(k, foldSelfRefInner(val, fullKey, replacement, false));
|
|
286
406
|
}
|
|
287
407
|
return { kind: "object", fields: newFields };
|
|
288
408
|
}
|
|
@@ -291,10 +411,26 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
291
411
|
function foldOrSkipPrior(prior, fullKey, old) {
|
|
292
412
|
if (!containsSelfRef(prior, fullKey)) return cloneResolverValue(prior);
|
|
293
413
|
if (old === void 0) return foldOptionalSelfRefAbsent(prior, fullKey);
|
|
414
|
+
if (isSubst(prior)) {
|
|
415
|
+
const remainder = prefixSelfRefRemainder(prior, fullKey);
|
|
416
|
+
if (remainder !== null) {
|
|
417
|
+
const navigated = navigateResolverValue(old, remainder);
|
|
418
|
+
if (navigated === void 0 && prior.optional) return cloneResolverValue(old);
|
|
419
|
+
if (navigated !== null && navigated !== void 0 && isResObj(navigated) && isResObj(old)) {
|
|
420
|
+
return mergeResObjLayers(
|
|
421
|
+
cloneResolverValue(old),
|
|
422
|
+
cloneResolverValue(navigated)
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
294
427
|
return foldSelfRef(prior, fullKey, old);
|
|
295
428
|
}
|
|
296
429
|
function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
297
|
-
|
|
430
|
+
return foldOptionalSelfRefAbsentInner(v, fullKey, true);
|
|
431
|
+
}
|
|
432
|
+
function foldOptionalSelfRefAbsentInner(v, fullKey, allowPrefix) {
|
|
433
|
+
if (isSubst(v) && (substFullKey(v) === fullKey || allowPrefix && prefixSelfRefRemainder(v, fullKey) !== null)) {
|
|
298
434
|
if (!v.optional) return void 0;
|
|
299
435
|
return {
|
|
300
436
|
_kind: "subst-placeholder",
|
|
@@ -310,7 +446,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
310
446
|
if (isConcat(v)) {
|
|
311
447
|
const nodes = [];
|
|
312
448
|
for (const node of v.nodes) {
|
|
313
|
-
const folded =
|
|
449
|
+
const folded = foldOptionalSelfRefAbsentInner(node, fullKey, allowPrefix);
|
|
314
450
|
if (folded === void 0) return void 0;
|
|
315
451
|
nodes.push(folded);
|
|
316
452
|
}
|
|
@@ -319,7 +455,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
319
455
|
if (isResObj(v)) {
|
|
320
456
|
const fields = /* @__PURE__ */ new Map();
|
|
321
457
|
for (const [key, value] of v.fields) {
|
|
322
|
-
const folded =
|
|
458
|
+
const folded = foldOptionalSelfRefAbsentInner(value, fullKey, false);
|
|
323
459
|
if (folded === void 0) return void 0;
|
|
324
460
|
fields.set(key, folded);
|
|
325
461
|
}
|
|
@@ -329,7 +465,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
329
465
|
if (hv.kind === "array") {
|
|
330
466
|
const items = [];
|
|
331
467
|
for (const item of hv.items) {
|
|
332
|
-
const folded =
|
|
468
|
+
const folded = foldOptionalSelfRefAbsentInner(item, fullKey, allowPrefix);
|
|
333
469
|
if (folded === void 0) return void 0;
|
|
334
470
|
items.push(folded);
|
|
335
471
|
}
|
|
@@ -338,7 +474,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
338
474
|
if (hv.kind === "object") {
|
|
339
475
|
const fields = /* @__PURE__ */ new Map();
|
|
340
476
|
for (const [key, value] of hv.fields) {
|
|
341
|
-
const folded =
|
|
477
|
+
const folded = foldOptionalSelfRefAbsentInner(value, fullKey, false);
|
|
342
478
|
if (folded === void 0) return void 0;
|
|
343
479
|
fields.set(key, folded);
|
|
344
480
|
}
|
|
@@ -520,6 +656,31 @@ function stripBom(input) {
|
|
|
520
656
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
521
657
|
}
|
|
522
658
|
|
|
659
|
+
// src/internal/depth.ts
|
|
660
|
+
var MAX_PATH_SEGMENTS = 64;
|
|
661
|
+
function tooDeep(segments) {
|
|
662
|
+
return segments > MAX_PATH_SEGMENTS;
|
|
663
|
+
}
|
|
664
|
+
function guardStackDepth(fn, wrap) {
|
|
665
|
+
try {
|
|
666
|
+
return fn();
|
|
667
|
+
} catch (e) {
|
|
668
|
+
if (!isStackOverflow(e)) throw e;
|
|
669
|
+
throw wrap(STACK_MESSAGE);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
673
|
+
function isStackOverflow(e) {
|
|
674
|
+
if (!(e instanceof RangeError)) return false;
|
|
675
|
+
const m = e.message.toLowerCase();
|
|
676
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
677
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
678
|
+
m.includes("stack overflow");
|
|
679
|
+
}
|
|
680
|
+
function depthError(message) {
|
|
681
|
+
return new ConfigError(message, "");
|
|
682
|
+
}
|
|
683
|
+
|
|
523
684
|
// src/internal/properties/properties.ts
|
|
524
685
|
function nestPairs(pairs) {
|
|
525
686
|
const root = /* @__PURE__ */ Object.create(null);
|
|
@@ -609,6 +770,12 @@ var SubstitutionResolver = class {
|
|
|
609
770
|
// Cross-impl with rs.hocon v1.5.1's resolving_field_path (same purpose,
|
|
610
771
|
// same prefix-match semantics).
|
|
611
772
|
this.resolvingFieldPath = [];
|
|
773
|
+
// S13a.12 recursion guard: field keys whose prior is currently being
|
|
774
|
+
// resolved through the prefix-self-ref branch. Saved priors are
|
|
775
|
+
// prefix-self-ref-free by the fold invariant, so re-entry only happens on
|
|
776
|
+
// a shape the fold could not see through (a live subst mid-navigation) —
|
|
777
|
+
// report it as a cycle instead of recursing forever.
|
|
778
|
+
this.resolvingPrefixPriors = /* @__PURE__ */ new Set();
|
|
612
779
|
}
|
|
613
780
|
/** Returns a prefix for error messages, including origin info when set. */
|
|
614
781
|
originPrefix() {
|
|
@@ -623,46 +790,57 @@ var SubstitutionResolver = class {
|
|
|
623
790
|
this.resolvingFieldPath.push(key);
|
|
624
791
|
const fullCacheKey = stringSegmentsToKey(this.resolvingFieldPath);
|
|
625
792
|
this.cache.delete(fullCacheKey);
|
|
626
|
-
let resolved;
|
|
627
793
|
try {
|
|
628
|
-
resolved = this.resolveVal(val, obj);
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
794
|
+
const resolved = this.resolveVal(val, obj);
|
|
795
|
+
if (resolved !== void 0) {
|
|
796
|
+
if (resolved.kind === "object") {
|
|
797
|
+
const prior = obj.priorValues.get(key);
|
|
798
|
+
if (prior !== void 0) {
|
|
799
|
+
const priorResolved = this.resolveVal(prior, obj);
|
|
800
|
+
if (priorResolved !== void 0 && priorResolved.kind === "object") {
|
|
801
|
+
const finalValue = deepMergeHoconValues(
|
|
802
|
+
priorResolved,
|
|
803
|
+
resolved
|
|
804
|
+
);
|
|
805
|
+
result.set(key, finalValue);
|
|
806
|
+
this.cache.set(fullCacheKey, finalValue);
|
|
807
|
+
this.cacheDescendants(fullCacheKey, finalValue);
|
|
808
|
+
continue;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
result.set(key, resolved);
|
|
813
|
+
this.cache.set(fullCacheKey, resolved);
|
|
814
|
+
this.cacheDescendants(fullCacheKey, resolved);
|
|
815
|
+
} else {
|
|
634
816
|
const prior = obj.priorValues.get(key);
|
|
635
817
|
if (prior !== void 0) {
|
|
636
818
|
const priorResolved = this.resolveVal(prior, obj);
|
|
637
|
-
if (priorResolved !== void 0
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
);
|
|
642
|
-
result.set(key, finalValue);
|
|
643
|
-
this.cache.set(fullCacheKey, finalValue);
|
|
644
|
-
this.cacheDescendants(fullCacheKey, finalValue);
|
|
645
|
-
continue;
|
|
819
|
+
if (priorResolved !== void 0) {
|
|
820
|
+
result.set(key, priorResolved);
|
|
821
|
+
this.cache.set(fullCacheKey, priorResolved);
|
|
822
|
+
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
646
823
|
}
|
|
647
824
|
}
|
|
648
825
|
}
|
|
649
|
-
|
|
650
|
-
this.
|
|
651
|
-
this.cacheDescendants(fullCacheKey, resolved);
|
|
652
|
-
} else {
|
|
653
|
-
const prior = obj.priorValues.get(key);
|
|
654
|
-
if (prior !== void 0) {
|
|
655
|
-
const priorResolved = this.resolveVal(prior, obj);
|
|
656
|
-
if (priorResolved !== void 0) {
|
|
657
|
-
result.set(key, priorResolved);
|
|
658
|
-
this.cache.set(fullCacheKey, priorResolved);
|
|
659
|
-
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
660
|
-
}
|
|
661
|
-
}
|
|
826
|
+
} finally {
|
|
827
|
+
this.resolvingFieldPath.pop();
|
|
662
828
|
}
|
|
663
829
|
}
|
|
664
830
|
return { kind: "object", fields: result };
|
|
665
831
|
}
|
|
832
|
+
/** S13a.12: walk resolved-object fields by segment text. A missing segment
|
|
833
|
+
* or a walk into a scalar/array is path-absent → undefined. */
|
|
834
|
+
navigateResolved(v, remainder) {
|
|
835
|
+
let cur = v;
|
|
836
|
+
for (const seg of remainder) {
|
|
837
|
+
if (cur.kind !== "object") return void 0;
|
|
838
|
+
const next = cur.fields.get(seg);
|
|
839
|
+
if (next === void 0) return void 0;
|
|
840
|
+
cur = next;
|
|
841
|
+
}
|
|
842
|
+
return cur;
|
|
843
|
+
}
|
|
666
844
|
cacheDescendants(prefix, value) {
|
|
667
845
|
if (value.kind !== "object") return;
|
|
668
846
|
for (const [key, child] of value.fields) {
|
|
@@ -685,17 +863,59 @@ var SubstitutionResolver = class {
|
|
|
685
863
|
if (isResObj(v)) return this.resolveResObj(v);
|
|
686
864
|
const hv = v;
|
|
687
865
|
if (hv.kind === "array") {
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
)
|
|
693
|
-
}
|
|
866
|
+
const items = [];
|
|
867
|
+
for (const item of hv.items) {
|
|
868
|
+
const resolved = this.resolveVal(item, scope);
|
|
869
|
+
if (resolved === void 0) continue;
|
|
870
|
+
items.push(resolved);
|
|
871
|
+
}
|
|
872
|
+
return { kind: "array", items };
|
|
694
873
|
}
|
|
695
874
|
return hv;
|
|
696
875
|
}
|
|
697
876
|
resolveSubst(s, scope) {
|
|
698
|
-
if (s.knownAbsent)
|
|
877
|
+
if (s.knownAbsent) {
|
|
878
|
+
if (!s.optional) {
|
|
879
|
+
if (this.opts.allowUnresolved) return s;
|
|
880
|
+
const k = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
881
|
+
throw new ResolveError(
|
|
882
|
+
`${this.originPrefix()}could not resolve substitution: \${${k}}`,
|
|
883
|
+
k,
|
|
884
|
+
s.line,
|
|
885
|
+
s.col
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
return void 0;
|
|
889
|
+
}
|
|
890
|
+
{
|
|
891
|
+
const rfp = this.resolvingFieldPath;
|
|
892
|
+
const sTexts = s.segments.map((seg) => seg.text);
|
|
893
|
+
if (rfp.length > 0 && rfp.length < sTexts.length && stringSegmentsToKey(sTexts.slice(0, rfp.length)) === stringSegmentsToKey(rfp)) {
|
|
894
|
+
const guardKey = stringSegmentsToKey(rfp);
|
|
895
|
+
const prior = scope.priorValues.get(rfp[rfp.length - 1]);
|
|
896
|
+
if (prior !== void 0 && !this.resolvingPrefixPriors.has(guardKey)) {
|
|
897
|
+
this.resolvingPrefixPriors.add(guardKey);
|
|
898
|
+
try {
|
|
899
|
+
const priorResolved = this.resolveVal(prior, scope);
|
|
900
|
+
if (priorResolved !== void 0) {
|
|
901
|
+
const navigated = this.navigateResolved(priorResolved, sTexts.slice(rfp.length));
|
|
902
|
+
if (navigated !== void 0) return navigated;
|
|
903
|
+
}
|
|
904
|
+
} finally {
|
|
905
|
+
this.resolvingPrefixPriors.delete(guardKey);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
if (s.optional) return void 0;
|
|
909
|
+
if (this.opts.allowUnresolved) return s;
|
|
910
|
+
const k = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
911
|
+
throw new ResolveError(
|
|
912
|
+
`${this.originPrefix()}could not resolve substitution: \${${k}}`,
|
|
913
|
+
k,
|
|
914
|
+
s.line,
|
|
915
|
+
s.col
|
|
916
|
+
);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
699
919
|
const key = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
700
920
|
if (this.cache.has(key)) return this.cache.get(key);
|
|
701
921
|
if (this.resolving.has(key)) {
|
|
@@ -1015,6 +1235,121 @@ function hoconValueToResObj2(value) {
|
|
|
1015
1235
|
return obj;
|
|
1016
1236
|
}
|
|
1017
1237
|
|
|
1238
|
+
// src/render-hocon.ts
|
|
1239
|
+
function renderHoconFromRoot(root) {
|
|
1240
|
+
const out = [];
|
|
1241
|
+
renderObjectBody(out, root, 0);
|
|
1242
|
+
return out.join("");
|
|
1243
|
+
}
|
|
1244
|
+
function renderObjectBody(out, o, depth) {
|
|
1245
|
+
const indent = " ".repeat(depth);
|
|
1246
|
+
for (const [k, v] of o.fields) {
|
|
1247
|
+
out.push(indent, renderKey(k));
|
|
1248
|
+
if (v.kind === "object") {
|
|
1249
|
+
out.push(" {");
|
|
1250
|
+
if (v.fields.size === 0) {
|
|
1251
|
+
out.push("}\n");
|
|
1252
|
+
continue;
|
|
1253
|
+
}
|
|
1254
|
+
out.push("\n");
|
|
1255
|
+
renderObjectBody(out, v, depth + 1);
|
|
1256
|
+
out.push(indent, "}\n");
|
|
1257
|
+
} else {
|
|
1258
|
+
out.push(" = ");
|
|
1259
|
+
renderValue(out, v, depth);
|
|
1260
|
+
out.push("\n");
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
function renderValue(out, v, depth) {
|
|
1265
|
+
switch (v.kind) {
|
|
1266
|
+
case "object": {
|
|
1267
|
+
if (v.fields.size === 0) {
|
|
1268
|
+
out.push("{}");
|
|
1269
|
+
return;
|
|
1270
|
+
}
|
|
1271
|
+
out.push("{\n");
|
|
1272
|
+
renderObjectBody(out, v, depth + 1);
|
|
1273
|
+
out.push(" ".repeat(depth), "}");
|
|
1274
|
+
return;
|
|
1275
|
+
}
|
|
1276
|
+
case "array":
|
|
1277
|
+
renderArray(out, v, depth);
|
|
1278
|
+
return;
|
|
1279
|
+
case "scalar":
|
|
1280
|
+
out.push(renderScalar(v));
|
|
1281
|
+
return;
|
|
1282
|
+
default:
|
|
1283
|
+
throw new ConfigError(
|
|
1284
|
+
"renderHocon: unrenderable value (config must be resolved data)",
|
|
1285
|
+
""
|
|
1286
|
+
);
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
function renderArray(out, a, depth) {
|
|
1290
|
+
if (a.items.length === 0) {
|
|
1291
|
+
out.push("[]");
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
const inner = " ".repeat(depth + 1);
|
|
1295
|
+
out.push("[\n");
|
|
1296
|
+
for (const e of a.items) {
|
|
1297
|
+
out.push(inner);
|
|
1298
|
+
renderValue(out, e, depth + 1);
|
|
1299
|
+
out.push("\n");
|
|
1300
|
+
}
|
|
1301
|
+
out.push(" ".repeat(depth), "]");
|
|
1302
|
+
}
|
|
1303
|
+
function renderScalar(s) {
|
|
1304
|
+
switch (s.valueType) {
|
|
1305
|
+
case "null":
|
|
1306
|
+
return "null";
|
|
1307
|
+
case "boolean":
|
|
1308
|
+
case "number":
|
|
1309
|
+
return s.raw;
|
|
1310
|
+
case "string":
|
|
1311
|
+
return renderString(s.raw);
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
var SAFE_UNQUOTED_KEY = /^[A-Za-z0-9_-]+$/;
|
|
1315
|
+
function renderKey(k) {
|
|
1316
|
+
if (k === "include") return quoteString(k);
|
|
1317
|
+
return SAFE_UNQUOTED_KEY.test(k) ? k : quoteString(k);
|
|
1318
|
+
}
|
|
1319
|
+
var SAFE_BARE_STRING = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
1320
|
+
var STRING_KEYWORDS = /* @__PURE__ */ new Set(["true", "false", "null", "yes", "no", "on", "off"]);
|
|
1321
|
+
function renderString(s) {
|
|
1322
|
+
return SAFE_BARE_STRING.test(s) && !STRING_KEYWORDS.has(s.toLowerCase()) ? s : quoteString(s);
|
|
1323
|
+
}
|
|
1324
|
+
function quoteString(s) {
|
|
1325
|
+
if (s.includes("\n") && !s.includes("\r") && !s.includes('"""') && !s.endsWith('"')) {
|
|
1326
|
+
return `"""${s}"""`;
|
|
1327
|
+
}
|
|
1328
|
+
let b = '"';
|
|
1329
|
+
for (const ch of s) {
|
|
1330
|
+
switch (ch) {
|
|
1331
|
+
case '"':
|
|
1332
|
+
b += '\\"';
|
|
1333
|
+
break;
|
|
1334
|
+
case "\\":
|
|
1335
|
+
b += "\\\\";
|
|
1336
|
+
break;
|
|
1337
|
+
case "\n":
|
|
1338
|
+
b += "\\n";
|
|
1339
|
+
break;
|
|
1340
|
+
case "\r":
|
|
1341
|
+
b += "\\r";
|
|
1342
|
+
break;
|
|
1343
|
+
case " ":
|
|
1344
|
+
b += "\\t";
|
|
1345
|
+
break;
|
|
1346
|
+
default:
|
|
1347
|
+
b += ch;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
return b + '"';
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1018
1353
|
// src/config.ts
|
|
1019
1354
|
var Config = class _Config {
|
|
1020
1355
|
constructor(root, opts) {
|
|
@@ -1320,6 +1655,36 @@ var Config = class _Config {
|
|
|
1320
1655
|
toObject(opts) {
|
|
1321
1656
|
return hoconToJs(this.root, opts?.nullPrototype === true);
|
|
1322
1657
|
}
|
|
1658
|
+
/**
|
|
1659
|
+
* Renders this resolved Config as HOCON text (E18; lockstep with go.hocon's
|
|
1660
|
+
* `Config.RenderHOCON`, v1.11.0).
|
|
1661
|
+
*
|
|
1662
|
+
* The output round-trips: parsing it back yields the same value tree. That
|
|
1663
|
+
* is the correctness contract, not byte-for-byte formatting — a scalar is
|
|
1664
|
+
* quoted whenever leaving it bare would re-parse as a different type (a
|
|
1665
|
+
* string `"8080"` becomes `"8080"`, not `8080`), and left bare only when it
|
|
1666
|
+
* provably cannot.
|
|
1667
|
+
*
|
|
1668
|
+
* The Config must be resolved and hold only data (objects, arrays, string /
|
|
1669
|
+
* number / boolean / null scalars) — exactly what {@link fromMap} and the
|
|
1670
|
+
* format adapters produce. An unresolved placeholder throws
|
|
1671
|
+
* {@link ConfigError}; substitutions have no textual round trip through a
|
|
1672
|
+
* value tree.
|
|
1673
|
+
*
|
|
1674
|
+
* The root object's fields are emitted without enclosing braces, nested
|
|
1675
|
+
* objects as `key { … }`, arrays as newline-separated `[ … ]`, indented two
|
|
1676
|
+
* spaces. Source comments are not represented — a value tree does not carry
|
|
1677
|
+
* them.
|
|
1678
|
+
*/
|
|
1679
|
+
renderHocon() {
|
|
1680
|
+
if (!this._resolved) {
|
|
1681
|
+
throw new ConfigError(
|
|
1682
|
+
"renderHocon: unrenderable unresolved substitution (config must be resolved data)",
|
|
1683
|
+
""
|
|
1684
|
+
);
|
|
1685
|
+
}
|
|
1686
|
+
return renderHoconFromRoot(this.root);
|
|
1687
|
+
}
|
|
1323
1688
|
/**
|
|
1324
1689
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
1325
1690
|
* JSON (sorted keys, no whitespace). Used by Layer-2 fixture tests to compare
|
|
@@ -1533,7 +1898,10 @@ function normalizeLeadingZeroNumber(raw) {
|
|
|
1533
1898
|
|
|
1534
1899
|
// src/value-factory.ts
|
|
1535
1900
|
function fromMap(values, originDescription) {
|
|
1536
|
-
const fields =
|
|
1901
|
+
const fields = guardStackDepth(
|
|
1902
|
+
() => coerceObject(values, ""),
|
|
1903
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
1904
|
+
);
|
|
1537
1905
|
const root = { kind: "object", fields };
|
|
1538
1906
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1539
1907
|
}
|
|
@@ -1633,13 +2001,14 @@ function parseDotEnv(input, opts = {}) {
|
|
|
1633
2001
|
for (let i = 0; i < lines.length; i++) {
|
|
1634
2002
|
const raw = (lines[i] ?? "").trim();
|
|
1635
2003
|
if (raw === "" || raw.startsWith("#")) continue;
|
|
1636
|
-
const line =
|
|
2004
|
+
const line = stripExport(raw);
|
|
1637
2005
|
const eq = line.indexOf("=");
|
|
1638
2006
|
if (eq === -1) throw new ConfigError(`${origin}:${i + 1}: expected NAME=value`, "");
|
|
1639
2007
|
const name = line.slice(0, eq).trim();
|
|
1640
2008
|
if (name === "") throw new ConfigError(`${origin}:${i + 1}: empty variable name`, "");
|
|
1641
|
-
const value = dotEnvValue(line.slice(eq + 1).replace(/^[ \t]+/, ""), origin, i + 1, name);
|
|
1642
2009
|
if (!name.startsWith(prefix)) continue;
|
|
2010
|
+
checkName(name, origin, i + 1);
|
|
2011
|
+
const value = dotEnvValue(line.slice(eq + 1).replace(/^[ \t]+/, ""), origin, i + 1, name);
|
|
1643
2012
|
pairs.push([toPath(name.slice(prefix.length)), value]);
|
|
1644
2013
|
}
|
|
1645
2014
|
return fromMap(nestPairs(pairs), origin);
|
|
@@ -1649,6 +2018,12 @@ function toPath(name) {
|
|
|
1649
2018
|
if (segs.some((s) => s === "")) {
|
|
1650
2019
|
throw new ConfigError(`env: "${name}" produces an empty path segment`, name);
|
|
1651
2020
|
}
|
|
2021
|
+
if (tooDeep(segs.length)) {
|
|
2022
|
+
throw new ConfigError(
|
|
2023
|
+
`env: "${name}" maps to a path ${segs.length} segments deep, over the limit of ${MAX_PATH_SEGMENTS}`,
|
|
2024
|
+
name
|
|
2025
|
+
);
|
|
2026
|
+
}
|
|
1652
2027
|
return segs;
|
|
1653
2028
|
}
|
|
1654
2029
|
function asciiLower(s) {
|
|
@@ -1694,6 +2069,20 @@ function dotEnvValue(v, origin, line, name) {
|
|
|
1694
2069
|
}
|
|
1695
2070
|
return trimmed;
|
|
1696
2071
|
}
|
|
2072
|
+
function stripExport(line) {
|
|
2073
|
+
const m = /^export[ \t]+/.exec(line);
|
|
2074
|
+
return m ? line.slice(m[0].length) : line;
|
|
2075
|
+
}
|
|
2076
|
+
function checkName(name, origin, line) {
|
|
2077
|
+
const bad = /\p{White_Space}|#/u.exec(name);
|
|
2078
|
+
if (bad) {
|
|
2079
|
+
const what = bad[0] === "#" ? "'#'" : "whitespace";
|
|
2080
|
+
throw new ConfigError(
|
|
2081
|
+
`${origin}:${line}: variable name "${name}" contains ${what}; the line is not NAME=value (spec F1.7)`,
|
|
2082
|
+
name
|
|
2083
|
+
);
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
1697
2086
|
export {
|
|
1698
2087
|
loadEnv,
|
|
1699
2088
|
parseDotEnv
|