@o3co/ts.hocon 1.12.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 +8 -4
- package/dist/adapters/env.cjs +419 -79
- package/dist/adapters/env.d.cts +1 -1
- package/dist/adapters/env.d.ts +1 -1
- package/dist/adapters/env.js +419 -79
- 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 +419 -79
- package/dist/adapters/jsonc.d.cts +1 -1
- package/dist/adapters/jsonc.d.ts +1 -1
- package/dist/adapters/jsonc.js +419 -79
- package/dist/adapters/properties.cjs +419 -79
- package/dist/adapters/properties.d.cts +1 -1
- package/dist/adapters/properties.d.ts +1 -1
- package/dist/adapters/properties.js +419 -79
- package/dist/adapters/toml.cjs +419 -79
- package/dist/adapters/toml.d.cts +1 -1
- package/dist/adapters/toml.d.ts +1 -1
- package/dist/adapters/toml.js +419 -79
- package/dist/adapters/yaml.cjs +419 -79
- package/dist/adapters/yaml.d.cts +1 -1
- package/dist/adapters/yaml.d.ts +1 -1
- package/dist/adapters/yaml.js +419 -79
- 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 +432 -87
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +432 -87
- package/dist/zod.cjs +432 -87
- package/dist/zod.d.cts +1 -1
- package/dist/zod.d.ts +1 -1
- package/dist/zod.js +432 -87
- package/package.json +12 -2
package/dist/index.js
CHANGED
|
@@ -41,13 +41,22 @@ function coerceNumber(value) {
|
|
|
41
41
|
return Number(value);
|
|
42
42
|
}
|
|
43
43
|
var DURATION_UNITS = {
|
|
44
|
+
// S19.1–S19.3: the bare nano/micro/milli (+plural) aliases are part of the
|
|
45
|
+
// spec's unit lists (HOCON.md L1307–L1309) and accepted by Lightbend
|
|
46
|
+
// (typesafe-config 1.4.6 probe, 2026-08-18); they were missing here.
|
|
44
47
|
ns: 1e-6,
|
|
48
|
+
nano: 1e-6,
|
|
49
|
+
nanos: 1e-6,
|
|
45
50
|
nanosecond: 1e-6,
|
|
46
51
|
nanoseconds: 1e-6,
|
|
47
52
|
us: 1e-3,
|
|
53
|
+
micro: 1e-3,
|
|
54
|
+
micros: 1e-3,
|
|
48
55
|
microsecond: 1e-3,
|
|
49
56
|
microseconds: 1e-3,
|
|
50
57
|
ms: 1,
|
|
58
|
+
milli: 1,
|
|
59
|
+
millis: 1,
|
|
51
60
|
millisecond: 1,
|
|
52
61
|
milliseconds: 1,
|
|
53
62
|
s: 1e3,
|
|
@@ -99,37 +108,76 @@ function parseDuration(value, outputUnit = "ms") {
|
|
|
99
108
|
return ms / divisor;
|
|
100
109
|
}
|
|
101
110
|
var BYTE_UNITS = {
|
|
111
|
+
// S21.1–S21.4 — the EXACT Lightbend/typesafe-config unit set (1.4.6 probe,
|
|
112
|
+
// 2026-08-18). Multi-letter units are case-sensitive: the SI decimal short
|
|
113
|
+
// form is `kB` (NOT `KB`/`kb` — Lightbend rejects both), higher decimals
|
|
114
|
+
// are `MB`…`YB`, binary prefixes are `Ki`/`KiB`…`Yi`/`YiB` with capital
|
|
115
|
+
// first letter, and long forms are lowercase only (`kilobyte`, never
|
|
116
|
+
// `Kilobyte`). Only the bare byte unit (`B`/`b`) and the single-letter
|
|
117
|
+
// -Xmx forms accept both cases. The old case-insensitive fallback and the
|
|
118
|
+
// lowercase alias rows accepted spellings Lightbend rejects — removed.
|
|
102
119
|
B: 1,
|
|
120
|
+
b: 1,
|
|
103
121
|
byte: 1,
|
|
104
122
|
bytes: 1,
|
|
105
|
-
|
|
123
|
+
kB: 1e3,
|
|
106
124
|
kilobyte: 1e3,
|
|
107
125
|
kilobytes: 1e3,
|
|
108
|
-
KiB: 1024,
|
|
109
|
-
kibibyte: 1024,
|
|
110
|
-
kibibytes: 1024,
|
|
111
126
|
MB: 1e6,
|
|
112
127
|
megabyte: 1e6,
|
|
113
128
|
megabytes: 1e6,
|
|
114
|
-
MiB: 1048576,
|
|
115
|
-
mebibyte: 1048576,
|
|
116
|
-
mebibytes: 1048576,
|
|
117
129
|
GB: 1e9,
|
|
118
130
|
gigabyte: 1e9,
|
|
119
131
|
gigabytes: 1e9,
|
|
120
|
-
GiB: 1073741824,
|
|
121
|
-
gibibyte: 1073741824,
|
|
122
|
-
gibibytes: 1073741824,
|
|
123
132
|
TB: 1e12,
|
|
124
133
|
terabyte: 1e12,
|
|
125
134
|
terabytes: 1e12,
|
|
135
|
+
PB: 1e15,
|
|
136
|
+
petabyte: 1e15,
|
|
137
|
+
petabytes: 1e15,
|
|
138
|
+
EB: 1e18,
|
|
139
|
+
exabyte: 1e18,
|
|
140
|
+
exabytes: 1e18,
|
|
141
|
+
ZB: 1e21,
|
|
142
|
+
zettabyte: 1e21,
|
|
143
|
+
zettabytes: 1e21,
|
|
144
|
+
YB: 1e24,
|
|
145
|
+
yottabyte: 1e24,
|
|
146
|
+
yottabytes: 1e24,
|
|
147
|
+
Ki: 1024,
|
|
148
|
+
KiB: 1024,
|
|
149
|
+
kibibyte: 1024,
|
|
150
|
+
kibibytes: 1024,
|
|
151
|
+
Mi: 1048576,
|
|
152
|
+
MiB: 1048576,
|
|
153
|
+
mebibyte: 1048576,
|
|
154
|
+
mebibytes: 1048576,
|
|
155
|
+
Gi: 1073741824,
|
|
156
|
+
GiB: 1073741824,
|
|
157
|
+
gibibyte: 1073741824,
|
|
158
|
+
gibibytes: 1073741824,
|
|
159
|
+
Ti: 1099511627776,
|
|
126
160
|
TiB: 1099511627776,
|
|
127
161
|
tebibyte: 1099511627776,
|
|
128
162
|
tebibytes: 1099511627776,
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
163
|
+
Pi: 1024 ** 5,
|
|
164
|
+
PiB: 1024 ** 5,
|
|
165
|
+
pebibyte: 1024 ** 5,
|
|
166
|
+
pebibytes: 1024 ** 5,
|
|
167
|
+
Ei: 1024 ** 6,
|
|
168
|
+
EiB: 1024 ** 6,
|
|
169
|
+
exbibyte: 1024 ** 6,
|
|
170
|
+
exbibytes: 1024 ** 6,
|
|
171
|
+
Zi: 1024 ** 7,
|
|
172
|
+
ZiB: 1024 ** 7,
|
|
173
|
+
zebibyte: 1024 ** 7,
|
|
174
|
+
zebibytes: 1024 ** 7,
|
|
175
|
+
Yi: 1024 ** 8,
|
|
176
|
+
YiB: 1024 ** 8,
|
|
177
|
+
yobibyte: 1024 ** 8,
|
|
178
|
+
yobibytes: 1024 ** 8,
|
|
179
|
+
// S21.4 — single-letter abbreviations → powers of two (java -Xmx
|
|
180
|
+
// convention); Lightbend accepts BOTH cases here, through the full ladder.
|
|
133
181
|
K: 1024,
|
|
134
182
|
k: 1024,
|
|
135
183
|
M: 1024 ** 2,
|
|
@@ -142,16 +190,10 @@ var BYTE_UNITS = {
|
|
|
142
190
|
p: 1024 ** 5,
|
|
143
191
|
E: 1024 ** 6,
|
|
144
192
|
e: 1024 ** 6,
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
mb: 1e6,
|
|
150
|
-
mib: 1048576,
|
|
151
|
-
gb: 1e9,
|
|
152
|
-
gib: 1073741824,
|
|
153
|
-
tb: 1e12,
|
|
154
|
-
tib: 1099511627776
|
|
193
|
+
Z: 1024 ** 7,
|
|
194
|
+
z: 1024 ** 7,
|
|
195
|
+
Y: 1024 ** 8,
|
|
196
|
+
y: 1024 ** 8
|
|
155
197
|
};
|
|
156
198
|
var OUTPUT_BYTE_UNITS = {
|
|
157
199
|
B: 1,
|
|
@@ -189,10 +231,7 @@ function parseBytes(value, outputUnit = "B") {
|
|
|
189
231
|
}
|
|
190
232
|
return bytes2 / divisor;
|
|
191
233
|
}
|
|
192
|
-
|
|
193
|
-
if (mult === void 0) {
|
|
194
|
-
mult = BYTE_UNITS[unit.toLowerCase()];
|
|
195
|
-
}
|
|
234
|
+
const mult = BYTE_UNITS[unit];
|
|
196
235
|
if (mult === void 0) return NaN;
|
|
197
236
|
const bytes = num * mult;
|
|
198
237
|
if (Math.abs(bytes) > Number.MAX_SAFE_INTEGER) {
|
|
@@ -256,35 +295,114 @@ function stringSegmentsToKey(segments) {
|
|
|
256
295
|
return t;
|
|
257
296
|
}).join(".");
|
|
258
297
|
}
|
|
298
|
+
function prefixSelfRefRemainder(s, fullKey) {
|
|
299
|
+
const texts = s.segments.map((seg) => seg.text);
|
|
300
|
+
if (!stringSegmentsToKey(texts).startsWith(fullKey + ".")) return null;
|
|
301
|
+
for (let n = 1; n < texts.length; n++) {
|
|
302
|
+
if (stringSegmentsToKey(texts.slice(0, n)) === fullKey) return texts.slice(n);
|
|
303
|
+
}
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
function navigateResolverValue(v, remainder) {
|
|
307
|
+
let cur = v;
|
|
308
|
+
for (const seg of remainder) {
|
|
309
|
+
if (isSubst(cur) || isConcat(cur)) return null;
|
|
310
|
+
if (isResObj(cur)) {
|
|
311
|
+
const next = cur.fields.get(seg);
|
|
312
|
+
if (next === void 0) return void 0;
|
|
313
|
+
cur = next;
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
const hv = cur;
|
|
317
|
+
if (hv.kind === "object") {
|
|
318
|
+
const next = hv.fields.get(seg);
|
|
319
|
+
if (next === void 0) return void 0;
|
|
320
|
+
cur = next;
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
return void 0;
|
|
324
|
+
}
|
|
325
|
+
return cur;
|
|
326
|
+
}
|
|
327
|
+
function foldPrefixSelfRef(s, replacement, remainder) {
|
|
328
|
+
const navigated = navigateResolverValue(replacement, remainder);
|
|
329
|
+
if (navigated === null) return s;
|
|
330
|
+
if (navigated === void 0) {
|
|
331
|
+
return {
|
|
332
|
+
_kind: "subst-placeholder",
|
|
333
|
+
segments: s.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
|
|
334
|
+
optional: s.optional,
|
|
335
|
+
knownAbsent: true,
|
|
336
|
+
listSuffix: s.listSuffix,
|
|
337
|
+
line: s.line,
|
|
338
|
+
col: s.col,
|
|
339
|
+
prefixLen: s.prefixLen
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
return cloneResolverValue(navigated);
|
|
343
|
+
}
|
|
344
|
+
function mergeResObjLayers(base, top) {
|
|
345
|
+
const fields = new Map(base.fields);
|
|
346
|
+
for (const [k, tv] of top.fields) {
|
|
347
|
+
const bv = fields.get(k);
|
|
348
|
+
if (bv !== void 0 && isResObj(bv) && isResObj(tv)) {
|
|
349
|
+
fields.set(k, mergeResObjLayers(bv, tv));
|
|
350
|
+
} else {
|
|
351
|
+
fields.set(k, tv);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const priorValues = new Map(base.priorValues);
|
|
355
|
+
for (const [k, pv] of top.priorValues) priorValues.set(k, pv);
|
|
356
|
+
const resetKeys = new Set(base.resetKeys);
|
|
357
|
+
for (const k of top.resetKeys) resetKeys.add(k);
|
|
358
|
+
return {
|
|
359
|
+
_kind: "res-obj",
|
|
360
|
+
fields,
|
|
361
|
+
priorValues,
|
|
362
|
+
resetKeys
|
|
363
|
+
};
|
|
364
|
+
}
|
|
259
365
|
function containsSelfRef(v, fullKey) {
|
|
260
|
-
|
|
261
|
-
|
|
366
|
+
return containsSelfRefInner(v, fullKey, true);
|
|
367
|
+
}
|
|
368
|
+
function containsSelfRefInner(v, fullKey, allowPrefix) {
|
|
369
|
+
if (isSubst(v))
|
|
370
|
+
return !v.knownAbsent && (substFullKey(v) === fullKey || allowPrefix && prefixSelfRefRemainder(v, fullKey) !== null);
|
|
371
|
+
if (isConcat(v)) return v.nodes.some((n) => containsSelfRefInner(n, fullKey, allowPrefix));
|
|
262
372
|
if (isResObj(v)) {
|
|
263
373
|
for (const f of v.fields.values()) {
|
|
264
|
-
if (
|
|
374
|
+
if (containsSelfRefInner(f, fullKey, false)) return true;
|
|
265
375
|
}
|
|
266
376
|
return false;
|
|
267
377
|
}
|
|
268
378
|
const hv = v;
|
|
269
379
|
if (hv.kind === "array") {
|
|
270
|
-
return hv.items.some((item) =>
|
|
380
|
+
return hv.items.some((item) => containsSelfRefInner(item, fullKey, allowPrefix));
|
|
271
381
|
}
|
|
272
382
|
if (hv.kind === "object") {
|
|
273
383
|
for (const f of hv.fields.values()) {
|
|
274
|
-
if (
|
|
384
|
+
if (containsSelfRefInner(f, fullKey, false)) return true;
|
|
275
385
|
}
|
|
276
386
|
return false;
|
|
277
387
|
}
|
|
278
388
|
return false;
|
|
279
389
|
}
|
|
280
390
|
function foldSelfRef(v, fullKey, replacement) {
|
|
391
|
+
return foldSelfRefInner(v, fullKey, replacement, true);
|
|
392
|
+
}
|
|
393
|
+
function foldSelfRefInner(v, fullKey, replacement, allowPrefix) {
|
|
281
394
|
if (isSubst(v)) {
|
|
282
|
-
|
|
395
|
+
if (substFullKey(v) === fullKey) return replacement;
|
|
396
|
+
if (allowPrefix) {
|
|
397
|
+
const remainder = prefixSelfRefRemainder(v, fullKey);
|
|
398
|
+
if (remainder !== null) return foldPrefixSelfRef(v, replacement, remainder);
|
|
399
|
+
}
|
|
400
|
+
return v;
|
|
283
401
|
}
|
|
284
402
|
if (isConcat(v)) {
|
|
285
403
|
return {
|
|
286
404
|
_kind: "concat-placeholder",
|
|
287
|
-
nodes: v.nodes.map((n) =>
|
|
405
|
+
nodes: v.nodes.map((n) => foldSelfRefInner(n, fullKey, replacement, allowPrefix)),
|
|
288
406
|
line: v.line,
|
|
289
407
|
col: v.col
|
|
290
408
|
};
|
|
@@ -292,7 +410,7 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
292
410
|
if (isResObj(v)) {
|
|
293
411
|
const newFields = /* @__PURE__ */ new Map();
|
|
294
412
|
for (const [k, val] of v.fields) {
|
|
295
|
-
newFields.set(k,
|
|
413
|
+
newFields.set(k, foldSelfRefInner(val, fullKey, replacement, false));
|
|
296
414
|
}
|
|
297
415
|
return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
|
|
298
416
|
}
|
|
@@ -300,13 +418,15 @@ function foldSelfRef(v, fullKey, replacement) {
|
|
|
300
418
|
if (hv.kind === "array") {
|
|
301
419
|
return {
|
|
302
420
|
kind: "array",
|
|
303
|
-
items: hv.items.map(
|
|
421
|
+
items: hv.items.map(
|
|
422
|
+
(item) => foldSelfRefInner(item, fullKey, replacement, allowPrefix)
|
|
423
|
+
)
|
|
304
424
|
};
|
|
305
425
|
}
|
|
306
426
|
if (hv.kind === "object") {
|
|
307
427
|
const newFields = /* @__PURE__ */ new Map();
|
|
308
428
|
for (const [k, val] of hv.fields) {
|
|
309
|
-
newFields.set(k,
|
|
429
|
+
newFields.set(k, foldSelfRefInner(val, fullKey, replacement, false));
|
|
310
430
|
}
|
|
311
431
|
return { kind: "object", fields: newFields };
|
|
312
432
|
}
|
|
@@ -350,10 +470,26 @@ function foldKnownAbsentSelfRef(v, fullKey, replacement) {
|
|
|
350
470
|
function foldOrSkipPrior(prior, fullKey, old) {
|
|
351
471
|
if (!containsSelfRef(prior, fullKey)) return cloneResolverValue(prior);
|
|
352
472
|
if (old === void 0) return foldOptionalSelfRefAbsent(prior, fullKey);
|
|
473
|
+
if (isSubst(prior)) {
|
|
474
|
+
const remainder = prefixSelfRefRemainder(prior, fullKey);
|
|
475
|
+
if (remainder !== null) {
|
|
476
|
+
const navigated = navigateResolverValue(old, remainder);
|
|
477
|
+
if (navigated === void 0 && prior.optional) return cloneResolverValue(old);
|
|
478
|
+
if (navigated !== null && navigated !== void 0 && isResObj(navigated) && isResObj(old)) {
|
|
479
|
+
return mergeResObjLayers(
|
|
480
|
+
cloneResolverValue(old),
|
|
481
|
+
cloneResolverValue(navigated)
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
353
486
|
return foldSelfRef(prior, fullKey, old);
|
|
354
487
|
}
|
|
355
488
|
function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
356
|
-
|
|
489
|
+
return foldOptionalSelfRefAbsentInner(v, fullKey, true);
|
|
490
|
+
}
|
|
491
|
+
function foldOptionalSelfRefAbsentInner(v, fullKey, allowPrefix) {
|
|
492
|
+
if (isSubst(v) && (substFullKey(v) === fullKey || allowPrefix && prefixSelfRefRemainder(v, fullKey) !== null)) {
|
|
357
493
|
if (!v.optional) return void 0;
|
|
358
494
|
return {
|
|
359
495
|
_kind: "subst-placeholder",
|
|
@@ -369,7 +505,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
369
505
|
if (isConcat(v)) {
|
|
370
506
|
const nodes = [];
|
|
371
507
|
for (const node of v.nodes) {
|
|
372
|
-
const folded =
|
|
508
|
+
const folded = foldOptionalSelfRefAbsentInner(node, fullKey, allowPrefix);
|
|
373
509
|
if (folded === void 0) return void 0;
|
|
374
510
|
nodes.push(folded);
|
|
375
511
|
}
|
|
@@ -378,7 +514,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
378
514
|
if (isResObj(v)) {
|
|
379
515
|
const fields = /* @__PURE__ */ new Map();
|
|
380
516
|
for (const [key, value] of v.fields) {
|
|
381
|
-
const folded =
|
|
517
|
+
const folded = foldOptionalSelfRefAbsentInner(value, fullKey, false);
|
|
382
518
|
if (folded === void 0) return void 0;
|
|
383
519
|
fields.set(key, folded);
|
|
384
520
|
}
|
|
@@ -388,7 +524,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
388
524
|
if (hv.kind === "array") {
|
|
389
525
|
const items = [];
|
|
390
526
|
for (const item of hv.items) {
|
|
391
|
-
const folded =
|
|
527
|
+
const folded = foldOptionalSelfRefAbsentInner(item, fullKey, allowPrefix);
|
|
392
528
|
if (folded === void 0) return void 0;
|
|
393
529
|
items.push(folded);
|
|
394
530
|
}
|
|
@@ -397,7 +533,7 @@ function foldOptionalSelfRefAbsent(v, fullKey) {
|
|
|
397
533
|
if (hv.kind === "object") {
|
|
398
534
|
const fields = /* @__PURE__ */ new Map();
|
|
399
535
|
for (const [key, value] of hv.fields) {
|
|
400
|
-
const folded =
|
|
536
|
+
const folded = foldOptionalSelfRefAbsentInner(value, fullKey, false);
|
|
401
537
|
if (folded === void 0) return void 0;
|
|
402
538
|
fields.set(key, folded);
|
|
403
539
|
}
|
|
@@ -770,7 +906,6 @@ var Lexer = class {
|
|
|
770
906
|
if (!closed) {
|
|
771
907
|
throw new ParseError("unterminated triple-quoted string", sl, sc);
|
|
772
908
|
}
|
|
773
|
-
if (value.startsWith("\n")) value = value.slice(1);
|
|
774
909
|
this.push("triple_string", value, sl, sc, true);
|
|
775
910
|
continue;
|
|
776
911
|
}
|
|
@@ -1087,9 +1222,9 @@ var Parser = class {
|
|
|
1087
1222
|
}
|
|
1088
1223
|
}
|
|
1089
1224
|
this.skip("newline");
|
|
1090
|
-
const
|
|
1091
|
-
if (
|
|
1092
|
-
throw new ParseError(`Unexpected token '${
|
|
1225
|
+
const remaining2 = this.peek();
|
|
1226
|
+
if (remaining2.kind !== "eof") {
|
|
1227
|
+
throw new ParseError(`Unexpected token '${remaining2.value}' after closing brace`, remaining2.line, remaining2.col);
|
|
1093
1228
|
}
|
|
1094
1229
|
return { kind: "object", fields: allFields, pos: first.pos };
|
|
1095
1230
|
}
|
|
@@ -1097,13 +1232,19 @@ var Parser = class {
|
|
|
1097
1232
|
this.advance();
|
|
1098
1233
|
const arr = this.parseArray();
|
|
1099
1234
|
this.skip("newline");
|
|
1100
|
-
const
|
|
1101
|
-
if (
|
|
1102
|
-
throw new ParseError(`Unexpected token '${
|
|
1235
|
+
const remaining2 = this.peek();
|
|
1236
|
+
if (remaining2.kind !== "eof") {
|
|
1237
|
+
throw new ParseError(`Unexpected token '${remaining2.value}' after root array`, remaining2.line, remaining2.col);
|
|
1103
1238
|
}
|
|
1104
1239
|
return { ...arr, pos: { line: t.line, col: t.col } };
|
|
1105
1240
|
}
|
|
1106
|
-
|
|
1241
|
+
const root = this.parseObject(false);
|
|
1242
|
+
this.skip("newline");
|
|
1243
|
+
const remaining = this.peek();
|
|
1244
|
+
if (remaining.kind !== "eof") {
|
|
1245
|
+
throw new ParseError(`Unexpected token '${remaining.value}' after root content`, remaining.line, remaining.col);
|
|
1246
|
+
}
|
|
1247
|
+
return root;
|
|
1107
1248
|
}
|
|
1108
1249
|
peek(offset = 0) {
|
|
1109
1250
|
return this.tokens[this.pos + offset] ?? EOF_TOKEN;
|
|
@@ -2260,6 +2401,12 @@ var SubstitutionResolver = class {
|
|
|
2260
2401
|
// Cross-impl with rs.hocon v1.5.1's resolving_field_path (same purpose,
|
|
2261
2402
|
// same prefix-match semantics).
|
|
2262
2403
|
this.resolvingFieldPath = [];
|
|
2404
|
+
// S13a.12 recursion guard: field keys whose prior is currently being
|
|
2405
|
+
// resolved through the prefix-self-ref branch. Saved priors are
|
|
2406
|
+
// prefix-self-ref-free by the fold invariant, so re-entry only happens on
|
|
2407
|
+
// a shape the fold could not see through (a live subst mid-navigation) —
|
|
2408
|
+
// report it as a cycle instead of recursing forever.
|
|
2409
|
+
this.resolvingPrefixPriors = /* @__PURE__ */ new Set();
|
|
2263
2410
|
}
|
|
2264
2411
|
/** Returns a prefix for error messages, including origin info when set. */
|
|
2265
2412
|
originPrefix() {
|
|
@@ -2274,46 +2421,57 @@ var SubstitutionResolver = class {
|
|
|
2274
2421
|
this.resolvingFieldPath.push(key);
|
|
2275
2422
|
const fullCacheKey = stringSegmentsToKey(this.resolvingFieldPath);
|
|
2276
2423
|
this.cache.delete(fullCacheKey);
|
|
2277
|
-
let resolved;
|
|
2278
2424
|
try {
|
|
2279
|
-
resolved = this.resolveVal(val, obj);
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2425
|
+
const resolved = this.resolveVal(val, obj);
|
|
2426
|
+
if (resolved !== void 0) {
|
|
2427
|
+
if (resolved.kind === "object") {
|
|
2428
|
+
const prior = obj.priorValues.get(key);
|
|
2429
|
+
if (prior !== void 0) {
|
|
2430
|
+
const priorResolved = this.resolveVal(prior, obj);
|
|
2431
|
+
if (priorResolved !== void 0 && priorResolved.kind === "object") {
|
|
2432
|
+
const finalValue = deepMergeHoconValues(
|
|
2433
|
+
priorResolved,
|
|
2434
|
+
resolved
|
|
2435
|
+
);
|
|
2436
|
+
result.set(key, finalValue);
|
|
2437
|
+
this.cache.set(fullCacheKey, finalValue);
|
|
2438
|
+
this.cacheDescendants(fullCacheKey, finalValue);
|
|
2439
|
+
continue;
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2443
|
+
result.set(key, resolved);
|
|
2444
|
+
this.cache.set(fullCacheKey, resolved);
|
|
2445
|
+
this.cacheDescendants(fullCacheKey, resolved);
|
|
2446
|
+
} else {
|
|
2285
2447
|
const prior = obj.priorValues.get(key);
|
|
2286
2448
|
if (prior !== void 0) {
|
|
2287
2449
|
const priorResolved = this.resolveVal(prior, obj);
|
|
2288
|
-
if (priorResolved !== void 0
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
);
|
|
2293
|
-
result.set(key, finalValue);
|
|
2294
|
-
this.cache.set(fullCacheKey, finalValue);
|
|
2295
|
-
this.cacheDescendants(fullCacheKey, finalValue);
|
|
2296
|
-
continue;
|
|
2450
|
+
if (priorResolved !== void 0) {
|
|
2451
|
+
result.set(key, priorResolved);
|
|
2452
|
+
this.cache.set(fullCacheKey, priorResolved);
|
|
2453
|
+
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
2297
2454
|
}
|
|
2298
2455
|
}
|
|
2299
2456
|
}
|
|
2300
|
-
|
|
2301
|
-
this.
|
|
2302
|
-
this.cacheDescendants(fullCacheKey, resolved);
|
|
2303
|
-
} else {
|
|
2304
|
-
const prior = obj.priorValues.get(key);
|
|
2305
|
-
if (prior !== void 0) {
|
|
2306
|
-
const priorResolved = this.resolveVal(prior, obj);
|
|
2307
|
-
if (priorResolved !== void 0) {
|
|
2308
|
-
result.set(key, priorResolved);
|
|
2309
|
-
this.cache.set(fullCacheKey, priorResolved);
|
|
2310
|
-
this.cacheDescendants(fullCacheKey, priorResolved);
|
|
2311
|
-
}
|
|
2312
|
-
}
|
|
2457
|
+
} finally {
|
|
2458
|
+
this.resolvingFieldPath.pop();
|
|
2313
2459
|
}
|
|
2314
2460
|
}
|
|
2315
2461
|
return { kind: "object", fields: result };
|
|
2316
2462
|
}
|
|
2463
|
+
/** S13a.12: walk resolved-object fields by segment text. A missing segment
|
|
2464
|
+
* or a walk into a scalar/array is path-absent → undefined. */
|
|
2465
|
+
navigateResolved(v, remainder) {
|
|
2466
|
+
let cur = v;
|
|
2467
|
+
for (const seg of remainder) {
|
|
2468
|
+
if (cur.kind !== "object") return void 0;
|
|
2469
|
+
const next = cur.fields.get(seg);
|
|
2470
|
+
if (next === void 0) return void 0;
|
|
2471
|
+
cur = next;
|
|
2472
|
+
}
|
|
2473
|
+
return cur;
|
|
2474
|
+
}
|
|
2317
2475
|
cacheDescendants(prefix, value) {
|
|
2318
2476
|
if (value.kind !== "object") return;
|
|
2319
2477
|
for (const [key, child] of value.fields) {
|
|
@@ -2336,17 +2494,59 @@ var SubstitutionResolver = class {
|
|
|
2336
2494
|
if (isResObj(v)) return this.resolveResObj(v);
|
|
2337
2495
|
const hv = v;
|
|
2338
2496
|
if (hv.kind === "array") {
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
)
|
|
2344
|
-
}
|
|
2497
|
+
const items = [];
|
|
2498
|
+
for (const item of hv.items) {
|
|
2499
|
+
const resolved = this.resolveVal(item, scope);
|
|
2500
|
+
if (resolved === void 0) continue;
|
|
2501
|
+
items.push(resolved);
|
|
2502
|
+
}
|
|
2503
|
+
return { kind: "array", items };
|
|
2345
2504
|
}
|
|
2346
2505
|
return hv;
|
|
2347
2506
|
}
|
|
2348
2507
|
resolveSubst(s, scope) {
|
|
2349
|
-
if (s.knownAbsent)
|
|
2508
|
+
if (s.knownAbsent) {
|
|
2509
|
+
if (!s.optional) {
|
|
2510
|
+
if (this.opts.allowUnresolved) return s;
|
|
2511
|
+
const k = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
2512
|
+
throw new ResolveError(
|
|
2513
|
+
`${this.originPrefix()}could not resolve substitution: \${${k}}`,
|
|
2514
|
+
k,
|
|
2515
|
+
s.line,
|
|
2516
|
+
s.col
|
|
2517
|
+
);
|
|
2518
|
+
}
|
|
2519
|
+
return void 0;
|
|
2520
|
+
}
|
|
2521
|
+
{
|
|
2522
|
+
const rfp = this.resolvingFieldPath;
|
|
2523
|
+
const sTexts = s.segments.map((seg) => seg.text);
|
|
2524
|
+
if (rfp.length > 0 && rfp.length < sTexts.length && stringSegmentsToKey(sTexts.slice(0, rfp.length)) === stringSegmentsToKey(rfp)) {
|
|
2525
|
+
const guardKey = stringSegmentsToKey(rfp);
|
|
2526
|
+
const prior = scope.priorValues.get(rfp[rfp.length - 1]);
|
|
2527
|
+
if (prior !== void 0 && !this.resolvingPrefixPriors.has(guardKey)) {
|
|
2528
|
+
this.resolvingPrefixPriors.add(guardKey);
|
|
2529
|
+
try {
|
|
2530
|
+
const priorResolved = this.resolveVal(prior, scope);
|
|
2531
|
+
if (priorResolved !== void 0) {
|
|
2532
|
+
const navigated = this.navigateResolved(priorResolved, sTexts.slice(rfp.length));
|
|
2533
|
+
if (navigated !== void 0) return navigated;
|
|
2534
|
+
}
|
|
2535
|
+
} finally {
|
|
2536
|
+
this.resolvingPrefixPriors.delete(guardKey);
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
if (s.optional) return void 0;
|
|
2540
|
+
if (this.opts.allowUnresolved) return s;
|
|
2541
|
+
const k = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
2542
|
+
throw new ResolveError(
|
|
2543
|
+
`${this.originPrefix()}could not resolve substitution: \${${k}}`,
|
|
2544
|
+
k,
|
|
2545
|
+
s.line,
|
|
2546
|
+
s.col
|
|
2547
|
+
);
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2350
2550
|
const key = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
|
|
2351
2551
|
if (this.cache.has(key)) return this.cache.get(key);
|
|
2352
2552
|
if (this.resolving.has(key)) {
|
|
@@ -2677,6 +2877,121 @@ async function resolveAsync(ast, opts) {
|
|
|
2677
2877
|
return resolveTree(root, { ...opts, useSystemEnvironment: true, allowUnresolved: false });
|
|
2678
2878
|
}
|
|
2679
2879
|
|
|
2880
|
+
// src/render-hocon.ts
|
|
2881
|
+
function renderHoconFromRoot(root) {
|
|
2882
|
+
const out = [];
|
|
2883
|
+
renderObjectBody(out, root, 0);
|
|
2884
|
+
return out.join("");
|
|
2885
|
+
}
|
|
2886
|
+
function renderObjectBody(out, o, depth) {
|
|
2887
|
+
const indent = " ".repeat(depth);
|
|
2888
|
+
for (const [k, v] of o.fields) {
|
|
2889
|
+
out.push(indent, renderKey(k));
|
|
2890
|
+
if (v.kind === "object") {
|
|
2891
|
+
out.push(" {");
|
|
2892
|
+
if (v.fields.size === 0) {
|
|
2893
|
+
out.push("}\n");
|
|
2894
|
+
continue;
|
|
2895
|
+
}
|
|
2896
|
+
out.push("\n");
|
|
2897
|
+
renderObjectBody(out, v, depth + 1);
|
|
2898
|
+
out.push(indent, "}\n");
|
|
2899
|
+
} else {
|
|
2900
|
+
out.push(" = ");
|
|
2901
|
+
renderValue(out, v, depth);
|
|
2902
|
+
out.push("\n");
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
}
|
|
2906
|
+
function renderValue(out, v, depth) {
|
|
2907
|
+
switch (v.kind) {
|
|
2908
|
+
case "object": {
|
|
2909
|
+
if (v.fields.size === 0) {
|
|
2910
|
+
out.push("{}");
|
|
2911
|
+
return;
|
|
2912
|
+
}
|
|
2913
|
+
out.push("{\n");
|
|
2914
|
+
renderObjectBody(out, v, depth + 1);
|
|
2915
|
+
out.push(" ".repeat(depth), "}");
|
|
2916
|
+
return;
|
|
2917
|
+
}
|
|
2918
|
+
case "array":
|
|
2919
|
+
renderArray(out, v, depth);
|
|
2920
|
+
return;
|
|
2921
|
+
case "scalar":
|
|
2922
|
+
out.push(renderScalar(v));
|
|
2923
|
+
return;
|
|
2924
|
+
default:
|
|
2925
|
+
throw new ConfigError(
|
|
2926
|
+
"renderHocon: unrenderable value (config must be resolved data)",
|
|
2927
|
+
""
|
|
2928
|
+
);
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2931
|
+
function renderArray(out, a, depth) {
|
|
2932
|
+
if (a.items.length === 0) {
|
|
2933
|
+
out.push("[]");
|
|
2934
|
+
return;
|
|
2935
|
+
}
|
|
2936
|
+
const inner = " ".repeat(depth + 1);
|
|
2937
|
+
out.push("[\n");
|
|
2938
|
+
for (const e of a.items) {
|
|
2939
|
+
out.push(inner);
|
|
2940
|
+
renderValue(out, e, depth + 1);
|
|
2941
|
+
out.push("\n");
|
|
2942
|
+
}
|
|
2943
|
+
out.push(" ".repeat(depth), "]");
|
|
2944
|
+
}
|
|
2945
|
+
function renderScalar(s) {
|
|
2946
|
+
switch (s.valueType) {
|
|
2947
|
+
case "null":
|
|
2948
|
+
return "null";
|
|
2949
|
+
case "boolean":
|
|
2950
|
+
case "number":
|
|
2951
|
+
return s.raw;
|
|
2952
|
+
case "string":
|
|
2953
|
+
return renderString(s.raw);
|
|
2954
|
+
}
|
|
2955
|
+
}
|
|
2956
|
+
var SAFE_UNQUOTED_KEY = /^[A-Za-z0-9_-]+$/;
|
|
2957
|
+
function renderKey(k) {
|
|
2958
|
+
if (k === "include") return quoteString(k);
|
|
2959
|
+
return SAFE_UNQUOTED_KEY.test(k) ? k : quoteString(k);
|
|
2960
|
+
}
|
|
2961
|
+
var SAFE_BARE_STRING = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
2962
|
+
var STRING_KEYWORDS = /* @__PURE__ */ new Set(["true", "false", "null", "yes", "no", "on", "off"]);
|
|
2963
|
+
function renderString(s) {
|
|
2964
|
+
return SAFE_BARE_STRING.test(s) && !STRING_KEYWORDS.has(s.toLowerCase()) ? s : quoteString(s);
|
|
2965
|
+
}
|
|
2966
|
+
function quoteString(s) {
|
|
2967
|
+
if (s.includes("\n") && !s.includes("\r") && !s.includes('"""') && !s.endsWith('"')) {
|
|
2968
|
+
return `"""${s}"""`;
|
|
2969
|
+
}
|
|
2970
|
+
let b = '"';
|
|
2971
|
+
for (const ch of s) {
|
|
2972
|
+
switch (ch) {
|
|
2973
|
+
case '"':
|
|
2974
|
+
b += '\\"';
|
|
2975
|
+
break;
|
|
2976
|
+
case "\\":
|
|
2977
|
+
b += "\\\\";
|
|
2978
|
+
break;
|
|
2979
|
+
case "\n":
|
|
2980
|
+
b += "\\n";
|
|
2981
|
+
break;
|
|
2982
|
+
case "\r":
|
|
2983
|
+
b += "\\r";
|
|
2984
|
+
break;
|
|
2985
|
+
case " ":
|
|
2986
|
+
b += "\\t";
|
|
2987
|
+
break;
|
|
2988
|
+
default:
|
|
2989
|
+
b += ch;
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
2992
|
+
return b + '"';
|
|
2993
|
+
}
|
|
2994
|
+
|
|
2680
2995
|
// src/config.ts
|
|
2681
2996
|
var Config = class _Config {
|
|
2682
2997
|
constructor(root, opts) {
|
|
@@ -2982,6 +3297,36 @@ var Config = class _Config {
|
|
|
2982
3297
|
toObject(opts) {
|
|
2983
3298
|
return hoconToJs(this.root, opts?.nullPrototype === true);
|
|
2984
3299
|
}
|
|
3300
|
+
/**
|
|
3301
|
+
* Renders this resolved Config as HOCON text (E18; lockstep with go.hocon's
|
|
3302
|
+
* `Config.RenderHOCON`, v1.11.0).
|
|
3303
|
+
*
|
|
3304
|
+
* The output round-trips: parsing it back yields the same value tree. That
|
|
3305
|
+
* is the correctness contract, not byte-for-byte formatting — a scalar is
|
|
3306
|
+
* quoted whenever leaving it bare would re-parse as a different type (a
|
|
3307
|
+
* string `"8080"` becomes `"8080"`, not `8080`), and left bare only when it
|
|
3308
|
+
* provably cannot.
|
|
3309
|
+
*
|
|
3310
|
+
* The Config must be resolved and hold only data (objects, arrays, string /
|
|
3311
|
+
* number / boolean / null scalars) — exactly what {@link fromMap} and the
|
|
3312
|
+
* format adapters produce. An unresolved placeholder throws
|
|
3313
|
+
* {@link ConfigError}; substitutions have no textual round trip through a
|
|
3314
|
+
* value tree.
|
|
3315
|
+
*
|
|
3316
|
+
* The root object's fields are emitted without enclosing braces, nested
|
|
3317
|
+
* objects as `key { … }`, arrays as newline-separated `[ … ]`, indented two
|
|
3318
|
+
* spaces. Source comments are not represented — a value tree does not carry
|
|
3319
|
+
* them.
|
|
3320
|
+
*/
|
|
3321
|
+
renderHocon() {
|
|
3322
|
+
if (!this._resolved) {
|
|
3323
|
+
throw new ConfigError(
|
|
3324
|
+
"renderHocon: unrenderable unresolved substitution (config must be resolved data)",
|
|
3325
|
+
""
|
|
3326
|
+
);
|
|
3327
|
+
}
|
|
3328
|
+
return renderHoconFromRoot(this.root);
|
|
3329
|
+
}
|
|
2985
3330
|
/**
|
|
2986
3331
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
2987
3332
|
* JSON (sorted keys, no whitespace). Used by Layer-2 fixture tests to compare
|