@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.
@@ -0,0 +1,2450 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/adapters/json5.ts
31
+ var json5_exports = {};
32
+ __export(json5_exports, {
33
+ parseJson5: () => parseJson5
34
+ });
35
+ module.exports = __toCommonJS(json5_exports);
36
+
37
+ // src/coerce.ts
38
+ var DECIMAL_NUMBER_RE = /^-?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/;
39
+ function isHoconWs(cp) {
40
+ if (cp === 9 || cp === 10 || cp === 11 || cp === 12 || cp === 13) return true;
41
+ if (cp >= 28 && cp <= 31) return true;
42
+ if (cp === 32 || cp === 160 || cp === 65279) return true;
43
+ if (cp === 5760) return true;
44
+ if (cp >= 8192 && cp <= 8202) return true;
45
+ if (cp === 8232 || cp === 8233 || cp === 8239 || cp === 8287) return true;
46
+ if (cp === 12288) return true;
47
+ return false;
48
+ }
49
+ function trimHoconWs(s) {
50
+ let start = 0;
51
+ let end = s.length;
52
+ while (start < end && isHoconWs(s.charCodeAt(start))) {
53
+ start++;
54
+ }
55
+ while (end > start && isHoconWs(s.charCodeAt(end - 1))) {
56
+ end--;
57
+ }
58
+ return s.slice(start, end);
59
+ }
60
+ var TRUTHY = /* @__PURE__ */ new Set(["true", "yes", "on"]);
61
+ var FALSY = /* @__PURE__ */ new Set(["false", "no", "off"]);
62
+ function coerceBoolean(value) {
63
+ const lower = value.toLowerCase();
64
+ if (TRUTHY.has(lower)) return true;
65
+ if (FALSY.has(lower)) return false;
66
+ return void 0;
67
+ }
68
+ function coerceNumber(value) {
69
+ if (!DECIMAL_NUMBER_RE.test(value)) return void 0;
70
+ return Number(value);
71
+ }
72
+ var DURATION_UNITS = {
73
+ // S19.1–S19.3: the bare nano/micro/milli (+plural) aliases are part of the
74
+ // spec's unit lists (HOCON.md L1307–L1309) and accepted by Lightbend
75
+ // (typesafe-config 1.4.6 probe, 2026-08-18); they were missing here.
76
+ ns: 1e-6,
77
+ nano: 1e-6,
78
+ nanos: 1e-6,
79
+ nanosecond: 1e-6,
80
+ nanoseconds: 1e-6,
81
+ us: 1e-3,
82
+ micro: 1e-3,
83
+ micros: 1e-3,
84
+ microsecond: 1e-3,
85
+ microseconds: 1e-3,
86
+ ms: 1,
87
+ milli: 1,
88
+ millis: 1,
89
+ millisecond: 1,
90
+ milliseconds: 1,
91
+ s: 1e3,
92
+ second: 1e3,
93
+ seconds: 1e3,
94
+ m: 6e4,
95
+ minute: 6e4,
96
+ minutes: 6e4,
97
+ h: 36e5,
98
+ hour: 36e5,
99
+ hours: 36e5,
100
+ d: 864e5,
101
+ day: 864e5,
102
+ days: 864e5
103
+ };
104
+ var OUTPUT_DURATION_UNITS = {
105
+ ns: 1e-6,
106
+ us: 1e-3,
107
+ ms: 1,
108
+ s: 1e3,
109
+ m: 6e4,
110
+ h: 36e5,
111
+ d: 864e5
112
+ };
113
+ function parseDuration(value, outputUnit = "ms") {
114
+ const trimmed = trimHoconWs(value);
115
+ let i = 0;
116
+ while (i < trimmed.length) {
117
+ const ch = trimmed[i];
118
+ if (i === 0 && (ch === "-" || ch === "+")) {
119
+ i++;
120
+ continue;
121
+ }
122
+ if (ch !== "." && (ch < "0" || ch > "9")) break;
123
+ i++;
124
+ }
125
+ if (i === 0) return NaN;
126
+ const num = Number(trimmed.slice(0, i));
127
+ if (Number.isNaN(num)) return NaN;
128
+ const unit = trimHoconWs(trimmed.slice(i));
129
+ const divisor = OUTPUT_DURATION_UNITS[outputUnit];
130
+ if (divisor === void 0) return NaN;
131
+ if (unit === "") {
132
+ return num / divisor;
133
+ }
134
+ const mult = DURATION_UNITS[unit];
135
+ if (mult === void 0) return NaN;
136
+ const ms = num * mult;
137
+ return ms / divisor;
138
+ }
139
+ var BYTE_UNITS = {
140
+ // S21.1–S21.4 — the EXACT Lightbend/typesafe-config unit set (1.4.6 probe,
141
+ // 2026-08-18). Multi-letter units are case-sensitive: the SI decimal short
142
+ // form is `kB` (NOT `KB`/`kb` — Lightbend rejects both), higher decimals
143
+ // are `MB`…`YB`, binary prefixes are `Ki`/`KiB`…`Yi`/`YiB` with capital
144
+ // first letter, and long forms are lowercase only (`kilobyte`, never
145
+ // `Kilobyte`). Only the bare byte unit (`B`/`b`) and the single-letter
146
+ // -Xmx forms accept both cases. The old case-insensitive fallback and the
147
+ // lowercase alias rows accepted spellings Lightbend rejects — removed.
148
+ B: 1,
149
+ b: 1,
150
+ byte: 1,
151
+ bytes: 1,
152
+ kB: 1e3,
153
+ kilobyte: 1e3,
154
+ kilobytes: 1e3,
155
+ MB: 1e6,
156
+ megabyte: 1e6,
157
+ megabytes: 1e6,
158
+ GB: 1e9,
159
+ gigabyte: 1e9,
160
+ gigabytes: 1e9,
161
+ TB: 1e12,
162
+ terabyte: 1e12,
163
+ terabytes: 1e12,
164
+ PB: 1e15,
165
+ petabyte: 1e15,
166
+ petabytes: 1e15,
167
+ EB: 1e18,
168
+ exabyte: 1e18,
169
+ exabytes: 1e18,
170
+ ZB: 1e21,
171
+ zettabyte: 1e21,
172
+ zettabytes: 1e21,
173
+ YB: 1e24,
174
+ yottabyte: 1e24,
175
+ yottabytes: 1e24,
176
+ Ki: 1024,
177
+ KiB: 1024,
178
+ kibibyte: 1024,
179
+ kibibytes: 1024,
180
+ Mi: 1048576,
181
+ MiB: 1048576,
182
+ mebibyte: 1048576,
183
+ mebibytes: 1048576,
184
+ Gi: 1073741824,
185
+ GiB: 1073741824,
186
+ gibibyte: 1073741824,
187
+ gibibytes: 1073741824,
188
+ Ti: 1099511627776,
189
+ TiB: 1099511627776,
190
+ tebibyte: 1099511627776,
191
+ tebibytes: 1099511627776,
192
+ Pi: 1024 ** 5,
193
+ PiB: 1024 ** 5,
194
+ pebibyte: 1024 ** 5,
195
+ pebibytes: 1024 ** 5,
196
+ Ei: 1024 ** 6,
197
+ EiB: 1024 ** 6,
198
+ exbibyte: 1024 ** 6,
199
+ exbibytes: 1024 ** 6,
200
+ Zi: 1024 ** 7,
201
+ ZiB: 1024 ** 7,
202
+ zebibyte: 1024 ** 7,
203
+ zebibytes: 1024 ** 7,
204
+ Yi: 1024 ** 8,
205
+ YiB: 1024 ** 8,
206
+ yobibyte: 1024 ** 8,
207
+ yobibytes: 1024 ** 8,
208
+ // S21.4 — single-letter abbreviations → powers of two (java -Xmx
209
+ // convention); Lightbend accepts BOTH cases here, through the full ladder.
210
+ K: 1024,
211
+ k: 1024,
212
+ M: 1024 ** 2,
213
+ m: 1024 ** 2,
214
+ G: 1024 ** 3,
215
+ g: 1024 ** 3,
216
+ T: 1024 ** 4,
217
+ t: 1024 ** 4,
218
+ P: 1024 ** 5,
219
+ p: 1024 ** 5,
220
+ E: 1024 ** 6,
221
+ e: 1024 ** 6,
222
+ Z: 1024 ** 7,
223
+ z: 1024 ** 7,
224
+ Y: 1024 ** 8,
225
+ y: 1024 ** 8
226
+ };
227
+ var OUTPUT_BYTE_UNITS = {
228
+ B: 1,
229
+ KB: 1e3,
230
+ KiB: 1024,
231
+ MB: 1e6,
232
+ MiB: 1048576,
233
+ GB: 1e9,
234
+ GiB: 1073741824,
235
+ TB: 1e12,
236
+ TiB: 1099511627776
237
+ };
238
+ function parseBytes(value, outputUnit = "B") {
239
+ const trimmed = trimHoconWs(value);
240
+ let i = 0;
241
+ while (i < trimmed.length) {
242
+ const ch = trimmed[i];
243
+ if (i === 0 && (ch === "-" || ch === "+")) {
244
+ i++;
245
+ continue;
246
+ }
247
+ if (ch !== "." && (ch < "0" || ch > "9")) break;
248
+ i++;
249
+ }
250
+ if (i === 0) return NaN;
251
+ const num = Number(trimmed.slice(0, i));
252
+ if (Number.isNaN(num)) return NaN;
253
+ const unit = trimHoconWs(trimmed.slice(i));
254
+ const divisor = OUTPUT_BYTE_UNITS[outputUnit];
255
+ if (divisor === void 0) return NaN;
256
+ if (unit === "") {
257
+ const bytes2 = Math.trunc(num);
258
+ if (Math.abs(bytes2) > Number.MAX_SAFE_INTEGER) {
259
+ throw new RangeError("byte size overflows representable range (max 2^53-1 bytes)");
260
+ }
261
+ return bytes2 / divisor;
262
+ }
263
+ const mult = BYTE_UNITS[unit];
264
+ if (mult === void 0) return NaN;
265
+ const bytes = num * mult;
266
+ if (Math.abs(bytes) > Number.MAX_SAFE_INTEGER) {
267
+ throw new RangeError("byte size overflows representable range (max 2^53-1 bytes)");
268
+ }
269
+ const result = bytes / divisor;
270
+ return outputUnit === "B" ? Math.round(result) : result;
271
+ }
272
+
273
+ // src/errors.ts
274
+ var ResolveError = class extends Error {
275
+ constructor(message, path, line, col, file) {
276
+ super(message);
277
+ this.path = path;
278
+ this.line = line;
279
+ this.col = col;
280
+ this.file = file;
281
+ this.name = "ResolveError";
282
+ }
283
+ };
284
+ var ConfigError = class extends Error {
285
+ constructor(message, path) {
286
+ super(message);
287
+ this.path = path;
288
+ this.name = "ConfigError";
289
+ }
290
+ };
291
+ var NotResolvedError = class extends ConfigError {
292
+ constructor(path) {
293
+ super(`value at path "${path}" is not resolved (call resolve() first)`, path);
294
+ this.name = "NotResolvedError";
295
+ }
296
+ };
297
+
298
+ // src/internal/resolver/fold-self-ref.ts
299
+ function substFullKey(s) {
300
+ return stringSegmentsToKey(s.segments.map((seg) => seg.text));
301
+ }
302
+ function stringSegmentsToKey(segments) {
303
+ return segments.map((t) => {
304
+ if (t === "" || /[^a-zA-Z0-9\-_]/.test(t)) {
305
+ return `"${t.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
306
+ }
307
+ return t;
308
+ }).join(".");
309
+ }
310
+ function prefixSelfRefRemainder(s, fullKey) {
311
+ const texts = s.segments.map((seg) => seg.text);
312
+ if (!stringSegmentsToKey(texts).startsWith(fullKey + ".")) return null;
313
+ for (let n = 1; n < texts.length; n++) {
314
+ if (stringSegmentsToKey(texts.slice(0, n)) === fullKey) return texts.slice(n);
315
+ }
316
+ return null;
317
+ }
318
+ function navigateResolverValue(v, remainder) {
319
+ let cur = v;
320
+ for (const seg of remainder) {
321
+ if (isSubst(cur) || isConcat(cur)) return null;
322
+ if (isResObj(cur)) {
323
+ const next = cur.fields.get(seg);
324
+ if (next === void 0) return void 0;
325
+ cur = next;
326
+ continue;
327
+ }
328
+ const hv = cur;
329
+ if (hv.kind === "object") {
330
+ const next = hv.fields.get(seg);
331
+ if (next === void 0) return void 0;
332
+ cur = next;
333
+ continue;
334
+ }
335
+ return void 0;
336
+ }
337
+ return cur;
338
+ }
339
+ function foldPrefixSelfRef(s, replacement, remainder) {
340
+ const navigated = navigateResolverValue(replacement, remainder);
341
+ if (navigated === null) return s;
342
+ if (navigated === void 0) {
343
+ return {
344
+ _kind: "subst-placeholder",
345
+ segments: s.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
346
+ optional: s.optional,
347
+ knownAbsent: true,
348
+ listSuffix: s.listSuffix,
349
+ line: s.line,
350
+ col: s.col,
351
+ prefixLen: s.prefixLen
352
+ };
353
+ }
354
+ return cloneResolverValue(navigated);
355
+ }
356
+ function mergeResObjLayers(base, top) {
357
+ const fields = new Map(base.fields);
358
+ for (const [k, tv] of top.fields) {
359
+ const bv = fields.get(k);
360
+ if (bv !== void 0 && isResObj(bv) && isResObj(tv)) {
361
+ fields.set(k, mergeResObjLayers(bv, tv));
362
+ } else {
363
+ fields.set(k, tv);
364
+ }
365
+ }
366
+ const priorValues = new Map(base.priorValues);
367
+ for (const [k, pv] of top.priorValues) priorValues.set(k, pv);
368
+ const resetKeys = new Set(base.resetKeys);
369
+ for (const k of top.resetKeys) resetKeys.add(k);
370
+ return {
371
+ _kind: "res-obj",
372
+ fields,
373
+ priorValues,
374
+ resetKeys
375
+ };
376
+ }
377
+ function containsSelfRef(v, fullKey) {
378
+ return containsSelfRefInner(v, fullKey, true);
379
+ }
380
+ function containsSelfRefInner(v, fullKey, allowPrefix) {
381
+ if (isSubst(v))
382
+ return !v.knownAbsent && (substFullKey(v) === fullKey || allowPrefix && prefixSelfRefRemainder(v, fullKey) !== null);
383
+ if (isConcat(v)) return v.nodes.some((n) => containsSelfRefInner(n, fullKey, allowPrefix));
384
+ if (isResObj(v)) {
385
+ for (const f of v.fields.values()) {
386
+ if (containsSelfRefInner(f, fullKey, false)) return true;
387
+ }
388
+ return false;
389
+ }
390
+ const hv = v;
391
+ if (hv.kind === "array") {
392
+ return hv.items.some((item) => containsSelfRefInner(item, fullKey, allowPrefix));
393
+ }
394
+ if (hv.kind === "object") {
395
+ for (const f of hv.fields.values()) {
396
+ if (containsSelfRefInner(f, fullKey, false)) return true;
397
+ }
398
+ return false;
399
+ }
400
+ return false;
401
+ }
402
+ function foldSelfRef(v, fullKey, replacement) {
403
+ return foldSelfRefInner(v, fullKey, replacement, true);
404
+ }
405
+ function foldSelfRefInner(v, fullKey, replacement, allowPrefix) {
406
+ if (isSubst(v)) {
407
+ if (substFullKey(v) === fullKey) return replacement;
408
+ if (allowPrefix) {
409
+ const remainder = prefixSelfRefRemainder(v, fullKey);
410
+ if (remainder !== null) return foldPrefixSelfRef(v, replacement, remainder);
411
+ }
412
+ return v;
413
+ }
414
+ if (isConcat(v)) {
415
+ return {
416
+ _kind: "concat-placeholder",
417
+ nodes: v.nodes.map((n) => foldSelfRefInner(n, fullKey, replacement, allowPrefix)),
418
+ line: v.line,
419
+ col: v.col
420
+ };
421
+ }
422
+ if (isResObj(v)) {
423
+ const newFields = /* @__PURE__ */ new Map();
424
+ for (const [k, val] of v.fields) {
425
+ newFields.set(k, foldSelfRefInner(val, fullKey, replacement, false));
426
+ }
427
+ return { _kind: "res-obj", fields: newFields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
428
+ }
429
+ const hv = v;
430
+ if (hv.kind === "array") {
431
+ return {
432
+ kind: "array",
433
+ items: hv.items.map(
434
+ (item) => foldSelfRefInner(item, fullKey, replacement, allowPrefix)
435
+ )
436
+ };
437
+ }
438
+ if (hv.kind === "object") {
439
+ const newFields = /* @__PURE__ */ new Map();
440
+ for (const [k, val] of hv.fields) {
441
+ newFields.set(k, foldSelfRefInner(val, fullKey, replacement, false));
442
+ }
443
+ return { kind: "object", fields: newFields };
444
+ }
445
+ return v;
446
+ }
447
+ function foldOrSkipPrior(prior, fullKey, old) {
448
+ if (!containsSelfRef(prior, fullKey)) return cloneResolverValue(prior);
449
+ if (old === void 0) return foldOptionalSelfRefAbsent(prior, fullKey);
450
+ if (isSubst(prior)) {
451
+ const remainder = prefixSelfRefRemainder(prior, fullKey);
452
+ if (remainder !== null) {
453
+ const navigated = navigateResolverValue(old, remainder);
454
+ if (navigated === void 0 && prior.optional) return cloneResolverValue(old);
455
+ if (navigated !== null && navigated !== void 0 && isResObj(navigated) && isResObj(old)) {
456
+ return mergeResObjLayers(
457
+ cloneResolverValue(old),
458
+ cloneResolverValue(navigated)
459
+ );
460
+ }
461
+ }
462
+ }
463
+ return foldSelfRef(prior, fullKey, old);
464
+ }
465
+ function foldOptionalSelfRefAbsent(v, fullKey) {
466
+ return foldOptionalSelfRefAbsentInner(v, fullKey, true);
467
+ }
468
+ function foldOptionalSelfRefAbsentInner(v, fullKey, allowPrefix) {
469
+ if (isSubst(v) && (substFullKey(v) === fullKey || allowPrefix && prefixSelfRefRemainder(v, fullKey) !== null)) {
470
+ if (!v.optional) return void 0;
471
+ return {
472
+ _kind: "subst-placeholder",
473
+ segments: v.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
474
+ optional: v.optional,
475
+ knownAbsent: true,
476
+ listSuffix: v.listSuffix,
477
+ line: v.line,
478
+ col: v.col,
479
+ prefixLen: v.prefixLen
480
+ };
481
+ }
482
+ if (isConcat(v)) {
483
+ const nodes = [];
484
+ for (const node of v.nodes) {
485
+ const folded = foldOptionalSelfRefAbsentInner(node, fullKey, allowPrefix);
486
+ if (folded === void 0) return void 0;
487
+ nodes.push(folded);
488
+ }
489
+ return { _kind: "concat-placeholder", nodes, line: v.line, col: v.col };
490
+ }
491
+ if (isResObj(v)) {
492
+ const fields = /* @__PURE__ */ new Map();
493
+ for (const [key, value] of v.fields) {
494
+ const folded = foldOptionalSelfRefAbsentInner(value, fullKey, false);
495
+ if (folded === void 0) return void 0;
496
+ fields.set(key, folded);
497
+ }
498
+ return { _kind: "res-obj", fields, priorValues: new Map(v.priorValues), resetKeys: new Set(v.resetKeys) };
499
+ }
500
+ const hv = v;
501
+ if (hv.kind === "array") {
502
+ const items = [];
503
+ for (const item of hv.items) {
504
+ const folded = foldOptionalSelfRefAbsentInner(item, fullKey, allowPrefix);
505
+ if (folded === void 0) return void 0;
506
+ items.push(folded);
507
+ }
508
+ return { kind: "array", items };
509
+ }
510
+ if (hv.kind === "object") {
511
+ const fields = /* @__PURE__ */ new Map();
512
+ for (const [key, value] of hv.fields) {
513
+ const folded = foldOptionalSelfRefAbsentInner(value, fullKey, false);
514
+ if (folded === void 0) return void 0;
515
+ fields.set(key, folded);
516
+ }
517
+ return { kind: "object", fields };
518
+ }
519
+ return cloneResolverValue(v);
520
+ }
521
+ function cloneResolverValue(v) {
522
+ if (isSubst(v)) {
523
+ return {
524
+ _kind: "subst-placeholder",
525
+ segments: v.segments.map((seg) => ({ text: seg.text, line: seg.line, col: seg.col })),
526
+ optional: v.optional,
527
+ knownAbsent: v.knownAbsent,
528
+ listSuffix: v.listSuffix,
529
+ line: v.line,
530
+ col: v.col,
531
+ prefixLen: v.prefixLen
532
+ };
533
+ }
534
+ if (isConcat(v)) {
535
+ return {
536
+ _kind: "concat-placeholder",
537
+ nodes: v.nodes.map((n) => cloneResolverValue(n)),
538
+ line: v.line,
539
+ col: v.col
540
+ };
541
+ }
542
+ if (isResObj(v)) {
543
+ const newFields = /* @__PURE__ */ new Map();
544
+ for (const [k, val] of v.fields) newFields.set(k, cloneResolverValue(val));
545
+ const newPriors = /* @__PURE__ */ new Map();
546
+ for (const [k, val] of v.priorValues) newPriors.set(k, cloneResolverValue(val));
547
+ return { _kind: "res-obj", fields: newFields, priorValues: newPriors, resetKeys: new Set(v.resetKeys) };
548
+ }
549
+ const hv = v;
550
+ if (hv.kind === "array") {
551
+ return {
552
+ kind: "array",
553
+ items: hv.items.map((item) => cloneResolverValue(item))
554
+ };
555
+ }
556
+ if (hv.kind === "object") {
557
+ const newFields = /* @__PURE__ */ new Map();
558
+ for (const [k, val] of hv.fields) {
559
+ newFields.set(k, cloneResolverValue(val));
560
+ }
561
+ return { kind: "object", fields: newFields };
562
+ }
563
+ return hv;
564
+ }
565
+ function containsSubstByPath(v, target) {
566
+ if (isSubst(v)) return !v.knownAbsent && segmentsTextEqual(v.segments, target);
567
+ if (isConcat(v)) return v.nodes.some((n) => containsSubstByPath(n, target));
568
+ if (isResObj(v)) {
569
+ for (const f of v.fields.values()) {
570
+ if (containsSubstByPath(f, target)) return true;
571
+ }
572
+ return false;
573
+ }
574
+ const hv = v;
575
+ if (hv.kind === "array") {
576
+ return hv.items.some((item) => containsSubstByPath(item, target));
577
+ }
578
+ if (hv.kind === "object") {
579
+ for (const f of hv.fields.values()) {
580
+ if (containsSubstByPath(f, target)) return true;
581
+ }
582
+ return false;
583
+ }
584
+ return false;
585
+ }
586
+ function segmentsTextEqual(a, b) {
587
+ if (a.length !== b.length) return false;
588
+ for (let i = 0; i < a.length; i++) {
589
+ const ai = a[i];
590
+ const bi = b[i];
591
+ if (ai === void 0 || bi === void 0 || ai.text !== bi.text) return false;
592
+ }
593
+ return true;
594
+ }
595
+
596
+ // src/internal/resolver/types.ts
597
+ var separatorValues = /* @__PURE__ */ new WeakSet();
598
+ function isSubst(v) {
599
+ return v._kind === "subst-placeholder";
600
+ }
601
+ function isConcat(v) {
602
+ return v._kind === "concat-placeholder";
603
+ }
604
+ function isResObj(v) {
605
+ return v._kind === "res-obj";
606
+ }
607
+ function makeResObj() {
608
+ return { _kind: "res-obj", fields: /* @__PURE__ */ new Map(), priorValues: /* @__PURE__ */ new Map(), resetKeys: /* @__PURE__ */ new Set() };
609
+ }
610
+ function mergeUnresolved(receiver, fallback) {
611
+ const result = makeResObj();
612
+ for (const [k, v] of fallback.fields) {
613
+ result.fields.set(k, v);
614
+ }
615
+ for (const [k, v] of fallback.priorValues) {
616
+ result.priorValues.set(k, v);
617
+ }
618
+ for (const [k, rv] of receiver.fields) {
619
+ const existing = result.fields.get(k);
620
+ if (existing !== void 0) {
621
+ const recPrior = receiver.priorValues.get(k);
622
+ if (recPrior !== void 0 && !isResObj(recPrior)) {
623
+ result.fields.set(k, rv);
624
+ continue;
625
+ }
626
+ if (isResObj(rv) && isResObj(existing)) {
627
+ result.fields.set(k, mergeUnresolved(rv, existing));
628
+ continue;
629
+ }
630
+ const foldedPrior = foldOrSkipPrior(existing, k, void 0);
631
+ if (foldedPrior !== void 0) result.priorValues.set(k, foldedPrior);
632
+ }
633
+ result.fields.set(k, rv);
634
+ }
635
+ for (const [k, v] of receiver.priorValues) {
636
+ if (receiver.fields.has(k)) {
637
+ result.priorValues.set(k, v);
638
+ }
639
+ }
640
+ return result;
641
+ }
642
+
643
+ // src/internal/resolver/utils.ts
644
+ function segmentsToKey(segments) {
645
+ return segments.map((s) => {
646
+ const t = s.text;
647
+ if (t === "" || /[^a-zA-Z0-9\-_]/.test(t)) {
648
+ return `"${t.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
649
+ }
650
+ return t;
651
+ }).join(".");
652
+ }
653
+ function lookupPath(root, segments) {
654
+ const [head, ...tail] = segments;
655
+ if (head === void 0) return void 0;
656
+ const key = head.text;
657
+ const val = root.fields.get(key);
658
+ if (val === void 0) return void 0;
659
+ if (tail.length === 0) return val;
660
+ if (isResObj(val)) return lookupPath(val, tail);
661
+ return void 0;
662
+ }
663
+ function lookupResObj(root, segments) {
664
+ let cur = root;
665
+ for (const seg of segments) {
666
+ const val = cur.fields.get(seg.text);
667
+ if (val === void 0 || !isResObj(val)) return void 0;
668
+ cur = val;
669
+ }
670
+ return cur;
671
+ }
672
+ function deepMergeHoconValues(base, overlay) {
673
+ const merged = new Map(base.fields);
674
+ for (const [k, v] of overlay.fields) {
675
+ const existing = merged.get(k);
676
+ if (existing?.kind === "object" && v.kind === "object") {
677
+ merged.set(k, deepMergeHoconValues(existing, v));
678
+ } else {
679
+ merged.set(k, v);
680
+ }
681
+ }
682
+ return { kind: "object", fields: merged };
683
+ }
684
+
685
+ // src/internal/resolver/include-loader.ts
686
+ var import_node_module = require("module");
687
+ var nodePath = __toESM(require("path"), 1);
688
+ var import_node_url = require("url");
689
+
690
+ // src/internal/strip-bom.ts
691
+ function stripBom(input) {
692
+ return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
693
+ }
694
+
695
+ // src/internal/depth.ts
696
+ function guardStackDepth(fn, wrap) {
697
+ try {
698
+ return fn();
699
+ } catch (e) {
700
+ if (!isStackOverflow(e)) throw e;
701
+ throw wrap(STACK_MESSAGE);
702
+ }
703
+ }
704
+ var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
705
+ function isStackOverflow(e) {
706
+ if (!(e instanceof RangeError)) return false;
707
+ const m = e.message.toLowerCase();
708
+ return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
709
+ m.includes("recursion") || // SpiderMonkey: "too much recursion"
710
+ m.includes("stack overflow");
711
+ }
712
+ function depthError(message) {
713
+ return new ConfigError(message, "");
714
+ }
715
+
716
+ // src/value/numeric-array.ts
717
+ function numericObjectToArray(value) {
718
+ if (value.kind !== "object") return null;
719
+ if (value.fields.size === 0) return null;
720
+ const canonicalInt = /^(0|[1-9][0-9]*)$/;
721
+ const eligible = [];
722
+ for (const [key, val] of value.fields) {
723
+ if (!canonicalInt.test(key)) continue;
724
+ const n = Number(key);
725
+ if (!Number.isInteger(n) || n > 2147483647) continue;
726
+ eligible.push({ n, v: val });
727
+ }
728
+ if (eligible.length === 0) return null;
729
+ eligible.sort((a, b) => a.n - b.n);
730
+ return eligible.map((e) => e.v);
731
+ }
732
+
733
+ // src/internal/resolver/substitution-resolver.ts
734
+ var SubstitutionResolver = class {
735
+ constructor(root, opts) {
736
+ this.root = root;
737
+ this.opts = opts;
738
+ this.resolving = /* @__PURE__ */ new Set();
739
+ this.cache = /* @__PURE__ */ new Map();
740
+ // Tracks ConcatPlaceholder nodes currently being iterated by resolveConcat.
741
+ // Used by isSelfRef detection: fires only when found === a concat currently
742
+ // mid-iteration (i.e. we are inside found's own resolution), preventing the
743
+ // "foofoo" double-count without misfiring when an external field looks up the
744
+ // same concat via a substitution (multi-reviewer convergence fix).
745
+ //
746
+ // Spec deviation: the S13a.13 spec ★1 decision #1 specified path-equality
747
+ // preservation for self-ref detection. Round-2 multi-agent-review surfaced a
748
+ // false-positive on external lookups (`a = ${?a}foo; b = ${a}`), so the
749
+ // criterion was tightened to node-membership-in-iterating-set — strictly
750
+ // narrower than path-equality. Spec amendment deferred to a follow-up
751
+ // xx.hocon PR (see Phase 6 #3f close-out notes).
752
+ this.resolvingConcats = /* @__PURE__ */ new WeakSet();
753
+ // Path stack tracking the full dotted path of the field currently being
754
+ // assigned in `resolveResObj`. Leaf keys are pushed on entry to each
755
+ // `(key, val)` iteration and popped on exit, so nested objects build up
756
+ // the full path (e.g. `["o", "history"]` while resolving `o.history`).
757
+ //
758
+ // Used to tighten self-ref detection at the L192 found-lookup site:
759
+ // a substitution `${X}` whose looked-up value contains a Subst pointing
760
+ // at `X` is only a true self-reference when the field currently being
761
+ // assigned is `X` (or a descendant of `X`). Without this guard, an
762
+ // external lookup like `b = ${o}` (where o has a self-referential
763
+ // field) would mis-fire and short-circuit to o's prior, returning the
764
+ // wrong value for b. The is_owner gate (rfp prefix-matches s.segments)
765
+ // narrows the check to the owner case only.
766
+ //
767
+ // Cross-impl with rs.hocon v1.5.1's resolving_field_path (same purpose,
768
+ // same prefix-match semantics).
769
+ this.resolvingFieldPath = [];
770
+ // S13a.12 recursion guard: field keys whose prior is currently being
771
+ // resolved through the prefix-self-ref branch. Saved priors are
772
+ // prefix-self-ref-free by the fold invariant, so re-entry only happens on
773
+ // a shape the fold could not see through (a live subst mid-navigation) —
774
+ // report it as a cycle instead of recursing forever.
775
+ this.resolvingPrefixPriors = /* @__PURE__ */ new Set();
776
+ }
777
+ /** Returns a prefix for error messages, including origin info when set. */
778
+ originPrefix() {
779
+ return this.opts.originDescription ? `${this.opts.originDescription}: ` : "";
780
+ }
781
+ resolve() {
782
+ return this.resolveResObj(this.root);
783
+ }
784
+ resolveResObj(obj) {
785
+ const result = /* @__PURE__ */ new Map();
786
+ for (const [key, val] of obj.fields) {
787
+ this.resolvingFieldPath.push(key);
788
+ const fullCacheKey = stringSegmentsToKey(this.resolvingFieldPath);
789
+ this.cache.delete(fullCacheKey);
790
+ try {
791
+ const resolved = this.resolveVal(val, obj);
792
+ if (resolved !== void 0) {
793
+ if (resolved.kind === "object") {
794
+ const prior = obj.priorValues.get(key);
795
+ if (prior !== void 0) {
796
+ const priorResolved = this.resolveVal(prior, obj);
797
+ if (priorResolved !== void 0 && priorResolved.kind === "object") {
798
+ const finalValue = deepMergeHoconValues(
799
+ priorResolved,
800
+ resolved
801
+ );
802
+ result.set(key, finalValue);
803
+ this.cache.set(fullCacheKey, finalValue);
804
+ this.cacheDescendants(fullCacheKey, finalValue);
805
+ continue;
806
+ }
807
+ }
808
+ }
809
+ result.set(key, resolved);
810
+ this.cache.set(fullCacheKey, resolved);
811
+ this.cacheDescendants(fullCacheKey, resolved);
812
+ } else {
813
+ const prior = obj.priorValues.get(key);
814
+ if (prior !== void 0) {
815
+ const priorResolved = this.resolveVal(prior, obj);
816
+ if (priorResolved !== void 0) {
817
+ result.set(key, priorResolved);
818
+ this.cache.set(fullCacheKey, priorResolved);
819
+ this.cacheDescendants(fullCacheKey, priorResolved);
820
+ }
821
+ }
822
+ }
823
+ } finally {
824
+ this.resolvingFieldPath.pop();
825
+ }
826
+ }
827
+ return { kind: "object", fields: result };
828
+ }
829
+ /** S13a.12: walk resolved-object fields by segment text. A missing segment
830
+ * or a walk into a scalar/array is path-absent → undefined. */
831
+ navigateResolved(v, remainder) {
832
+ let cur = v;
833
+ for (const seg of remainder) {
834
+ if (cur.kind !== "object") return void 0;
835
+ const next = cur.fields.get(seg);
836
+ if (next === void 0) return void 0;
837
+ cur = next;
838
+ }
839
+ return cur;
840
+ }
841
+ cacheDescendants(prefix, value) {
842
+ if (value.kind !== "object") return;
843
+ for (const [key, child] of value.fields) {
844
+ const childKey = `${prefix}.${stringSegmentsToKey([key])}`;
845
+ this.cache.set(childKey, child);
846
+ this.cacheDescendants(childKey, child);
847
+ }
848
+ }
849
+ resolveVal(v, scope) {
850
+ if (isSubst(v)) return this.resolveSubst(v, scope);
851
+ if (isConcat(v)) {
852
+ this.resolvingConcats.add(v);
853
+ try {
854
+ const concatResult = this.resolveConcat(v.nodes, scope, v.line, v.col);
855
+ return concatResult;
856
+ } finally {
857
+ this.resolvingConcats.delete(v);
858
+ }
859
+ }
860
+ if (isResObj(v)) return this.resolveResObj(v);
861
+ const hv = v;
862
+ if (hv.kind === "array") {
863
+ const items = [];
864
+ for (const item of hv.items) {
865
+ const resolved = this.resolveVal(item, scope);
866
+ if (resolved === void 0) continue;
867
+ items.push(resolved);
868
+ }
869
+ return { kind: "array", items };
870
+ }
871
+ return hv;
872
+ }
873
+ resolveSubst(s, scope) {
874
+ if (s.knownAbsent) {
875
+ if (!s.optional) {
876
+ if (this.opts.allowUnresolved) return s;
877
+ const k = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
878
+ throw new ResolveError(
879
+ `${this.originPrefix()}could not resolve substitution: \${${k}}`,
880
+ k,
881
+ s.line,
882
+ s.col
883
+ );
884
+ }
885
+ return void 0;
886
+ }
887
+ {
888
+ const rfp = this.resolvingFieldPath;
889
+ const sTexts = s.segments.map((seg) => seg.text);
890
+ if (rfp.length > 0 && rfp.length < sTexts.length && stringSegmentsToKey(sTexts.slice(0, rfp.length)) === stringSegmentsToKey(rfp)) {
891
+ const guardKey = stringSegmentsToKey(rfp);
892
+ const prior = scope.priorValues.get(rfp[rfp.length - 1]);
893
+ if (prior !== void 0 && !this.resolvingPrefixPriors.has(guardKey)) {
894
+ this.resolvingPrefixPriors.add(guardKey);
895
+ try {
896
+ const priorResolved = this.resolveVal(prior, scope);
897
+ if (priorResolved !== void 0) {
898
+ const navigated = this.navigateResolved(priorResolved, sTexts.slice(rfp.length));
899
+ if (navigated !== void 0) return navigated;
900
+ }
901
+ } finally {
902
+ this.resolvingPrefixPriors.delete(guardKey);
903
+ }
904
+ }
905
+ if (s.optional) return void 0;
906
+ if (this.opts.allowUnresolved) return s;
907
+ const k = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
908
+ throw new ResolveError(
909
+ `${this.originPrefix()}could not resolve substitution: \${${k}}`,
910
+ k,
911
+ s.line,
912
+ s.col
913
+ );
914
+ }
915
+ }
916
+ const key = s.listSuffix ? `${segmentsToKey(s.segments)}[]` : segmentsToKey(s.segments);
917
+ if (this.cache.has(key)) return this.cache.get(key);
918
+ if (this.resolving.has(key)) {
919
+ let prior;
920
+ if (s.segments.length > 1) {
921
+ const leafSeg = s.segments[s.segments.length - 1]?.text ?? "";
922
+ const parentScope = lookupResObj(
923
+ this.root,
924
+ s.segments.slice(0, s.segments.length - 1)
925
+ );
926
+ prior = parentScope?.priorValues.get(leafSeg);
927
+ } else {
928
+ const rootSeg = s.segments[0]?.text ?? "";
929
+ prior = scope.priorValues.get(rootSeg) ?? this.root.priorValues.get(rootSeg);
930
+ }
931
+ if (prior !== void 0) {
932
+ const saved = this.resolving;
933
+ this.resolving = new Set(saved);
934
+ try {
935
+ return this.resolveVal(prior, scope);
936
+ } finally {
937
+ this.resolving = saved;
938
+ }
939
+ }
940
+ if (s.optional) return void 0;
941
+ throw new ResolveError(
942
+ this.originPrefix() + `circular substitution: ${key}`,
943
+ key,
944
+ s.line,
945
+ s.col
946
+ );
947
+ }
948
+ this.resolving.add(key);
949
+ try {
950
+ const found = lookupPath(this.root, s.segments);
951
+ if (found !== void 0) {
952
+ const rfp = this.resolvingFieldPath;
953
+ const isOwner = rfp.length >= s.segments.length && s.segments.every((seg, i) => rfp[i] === seg.text);
954
+ const isSelfRef = isConcat(found) && this.resolvingConcats.has(found) || isOwner && containsSubstByPath(found, s.segments);
955
+ if (isSelfRef) {
956
+ let prior;
957
+ if (s.segments.length > 1) {
958
+ const leafSeg = s.segments[s.segments.length - 1]?.text ?? "";
959
+ const parentScope = lookupResObj(
960
+ this.root,
961
+ s.segments.slice(0, s.segments.length - 1)
962
+ );
963
+ prior = parentScope?.priorValues.get(leafSeg);
964
+ } else {
965
+ const rootSeg = s.segments[0]?.text ?? "";
966
+ prior = scope.priorValues.get(rootSeg) ?? this.root.priorValues.get(rootSeg);
967
+ }
968
+ if (prior !== void 0) {
969
+ const result2 = this.resolveVal(prior, scope);
970
+ if (result2 !== void 0) this.cache.set(key, result2);
971
+ return result2;
972
+ }
973
+ if (s.optional) return void 0;
974
+ throw new ResolveError(
975
+ `${this.originPrefix()}could not resolve substitution: \${${key}}`,
976
+ key,
977
+ s.line,
978
+ s.col
979
+ );
980
+ }
981
+ let result = this.resolveVal(found, scope);
982
+ const effectiveLen = s.segments.length - s.prefixLen;
983
+ if (effectiveLen === 1 && result !== void 0 && result.kind === "object") {
984
+ const leafSeg = s.segments[s.segments.length - 1]?.text ?? "";
985
+ let prior;
986
+ if (s.prefixLen > 0) {
987
+ const parentScope = lookupResObj(
988
+ this.root,
989
+ s.segments.slice(0, s.segments.length - 1)
990
+ );
991
+ prior = parentScope?.priorValues.get(leafSeg);
992
+ } else {
993
+ prior = scope.priorValues.get(leafSeg) ?? this.root.priorValues.get(leafSeg);
994
+ }
995
+ if (prior !== void 0) {
996
+ const priorResolved = this.resolveVal(prior, scope);
997
+ if (priorResolved !== void 0 && priorResolved.kind === "object") {
998
+ result = deepMergeHoconValues(
999
+ priorResolved,
1000
+ result
1001
+ );
1002
+ }
1003
+ }
1004
+ }
1005
+ if (result !== void 0) this.cache.set(key, result);
1006
+ return result;
1007
+ }
1008
+ if (s.prefixLen > 0 && s.segments.length > s.prefixLen) {
1009
+ const originalSegments = s.segments.slice(s.prefixLen);
1010
+ const fallbackFound = lookupPath(this.root, originalSegments);
1011
+ if (fallbackFound !== void 0) {
1012
+ let result = this.resolveVal(fallbackFound, scope);
1013
+ if (originalSegments.length === 1 && result !== void 0 && result.kind === "object") {
1014
+ const rootSeg = originalSegments[0]?.text ?? "";
1015
+ const prior = this.root.priorValues.get(rootSeg);
1016
+ if (prior !== void 0) {
1017
+ const priorResolved = this.resolveVal(prior, scope);
1018
+ if (priorResolved !== void 0 && priorResolved.kind === "object") {
1019
+ result = deepMergeHoconValues(
1020
+ priorResolved,
1021
+ result
1022
+ );
1023
+ }
1024
+ }
1025
+ }
1026
+ if (result !== void 0) this.cache.set(key, result);
1027
+ return result;
1028
+ }
1029
+ }
1030
+ if (s.listSuffix && this.opts.useSystemEnvironment !== false) {
1031
+ const result = this.resolveEnvList(s);
1032
+ if (result !== void 0) {
1033
+ this.cache.set(key, result);
1034
+ return result;
1035
+ }
1036
+ if (s.optional) return void 0;
1037
+ const envBase = s.segments.map((seg) => seg.text).join(".");
1038
+ throw new ResolveError(
1039
+ `${this.originPrefix()}could not resolve substitution: \${${key}} (no environment variables ${envBase}_0, ${envBase}_1, \u2026 set)`,
1040
+ key,
1041
+ s.line,
1042
+ s.col
1043
+ );
1044
+ } else if (s.listSuffix) {
1045
+ if (s.optional) return void 0;
1046
+ if (this.opts.allowUnresolved) return s;
1047
+ throw new ResolveError(
1048
+ `${this.originPrefix()}could not resolve substitution: \${${key}}`,
1049
+ key,
1050
+ s.line,
1051
+ s.col
1052
+ );
1053
+ }
1054
+ if (this.opts.useSystemEnvironment !== false) {
1055
+ const envKey = s.segments.map((seg) => seg.text).join(".");
1056
+ const envVal = this.opts.env[envKey] ?? (s.prefixLen > 0 ? this.opts.env[s.segments.slice(s.prefixLen).map((seg) => seg.text).join(".")] : void 0);
1057
+ if (envVal !== void 0) {
1058
+ const result = { kind: "scalar", raw: envVal, valueType: "string" };
1059
+ this.cache.set(key, result);
1060
+ return result;
1061
+ }
1062
+ }
1063
+ if (s.optional) return void 0;
1064
+ if (this.opts.allowUnresolved) {
1065
+ return s;
1066
+ }
1067
+ throw new ResolveError(
1068
+ `${this.originPrefix()}could not resolve substitution: \${${key}}`,
1069
+ key,
1070
+ s.line,
1071
+ s.col
1072
+ );
1073
+ } finally {
1074
+ this.resolving.delete(key);
1075
+ }
1076
+ }
1077
+ /**
1078
+ * S13c: scan environment for NAME_0, NAME_1, … and return an Array<Scalar(String)>.
1079
+ *
1080
+ * Candidate bases follow the same fully-qualified→bare order used by the scalar
1081
+ * env fallback. The first base whose _0 key is present wins entirely — no
1082
+ * cross-base merging (spec §Relativized fallback precedence rules).
1083
+ *
1084
+ * Returns the HoconValue Array if any candidate base has _0, or undefined if
1085
+ * none do (caller applies optional/required handling).
1086
+ */
1087
+ resolveEnvList(s) {
1088
+ const bases = this.candidateBases(s);
1089
+ for (const base of bases) {
1090
+ const key0 = base + "_0";
1091
+ if (!(key0 in this.opts.env)) continue;
1092
+ const items = [];
1093
+ for (let i = 0; ; i++) {
1094
+ const k = base + "_" + i;
1095
+ if (!(k in this.opts.env)) break;
1096
+ items.push({ kind: "scalar", raw: this.opts.env[k], valueType: "string" });
1097
+ }
1098
+ return { kind: "array", items };
1099
+ }
1100
+ return void 0;
1101
+ }
1102
+ /**
1103
+ * Return the candidate base names for env-var-list lookup, in precedence order.
1104
+ * Mirrors the fully-qualified→bare fallback used by the scalar env path.
1105
+ */
1106
+ candidateBases(s) {
1107
+ const full = s.segments.map((seg) => seg.text).join(".");
1108
+ if (s.prefixLen === 0) return [full];
1109
+ const bare = s.segments.slice(s.prefixLen).map((seg) => seg.text).join(".");
1110
+ return [full, bare];
1111
+ }
1112
+ resolveConcat(nodes, scope, line = 0, col = 0) {
1113
+ const rawResolved = nodes.map((n) => this.resolveVal(n, scope));
1114
+ if (this.opts.allowUnresolved) {
1115
+ for (const v of rawResolved) {
1116
+ if (v !== void 0 && isSubst(v)) {
1117
+ return v;
1118
+ }
1119
+ }
1120
+ }
1121
+ const resolved = rawResolved.filter((v) => v !== void 0);
1122
+ if (resolved.length === 0) return void 0;
1123
+ if (resolved.length === 1) return resolved[0];
1124
+ const nonSep = resolved.filter((v) => !separatorValues.has(v));
1125
+ if (nonSep.length === 0) {
1126
+ const str = resolved.map((v) => v.kind === "scalar" ? v.raw : JSON.stringify(v)).join("");
1127
+ return { kind: "scalar", raw: str, valueType: "string" };
1128
+ }
1129
+ const joinPair = (left, right) => {
1130
+ if (left.kind === "object" && right.kind === "object") {
1131
+ return deepMergeHoconValues(left, right);
1132
+ }
1133
+ if (left.kind === "array" && right.kind === "object") {
1134
+ const converted = numericObjectToArray(right);
1135
+ if (converted !== null) {
1136
+ return { kind: "array", items: [...left.items, ...converted] };
1137
+ }
1138
+ throw new ResolveError(
1139
+ "cannot concatenate array with object: value concatenation requires same-kind operands (S10.4)",
1140
+ "",
1141
+ line,
1142
+ col
1143
+ );
1144
+ }
1145
+ if (left.kind === "object" && right.kind === "array") {
1146
+ const converted = numericObjectToArray(left);
1147
+ if (converted !== null) {
1148
+ return { kind: "array", items: [...converted, ...right.items] };
1149
+ }
1150
+ throw new ResolveError(
1151
+ "cannot concatenate object with array: value concatenation requires same-kind operands (S10.4)",
1152
+ "",
1153
+ line,
1154
+ col
1155
+ );
1156
+ }
1157
+ if (left.kind === "array" && right.kind === "array") {
1158
+ return { kind: "array", items: [...left.items, ...right.items] };
1159
+ }
1160
+ if (left.kind === "array" || right.kind === "array") {
1161
+ throw new ResolveError(
1162
+ `cannot concatenate ${left.kind} with ${right.kind}: arrays and objects may not appear in string value concatenation (S10.13)`,
1163
+ "",
1164
+ line,
1165
+ col
1166
+ );
1167
+ }
1168
+ if (left.kind === "object" || right.kind === "object") {
1169
+ throw new ResolveError(
1170
+ `cannot concatenate ${left.kind} with ${right.kind}: arrays and objects may not appear in string value concatenation (S10.13)`,
1171
+ "",
1172
+ line,
1173
+ col
1174
+ );
1175
+ }
1176
+ return { kind: "scalar", raw: left.raw + right.raw, valueType: "string" };
1177
+ };
1178
+ const [head, ...tail] = nonSep;
1179
+ const folded = tail.reduce(joinPair, head);
1180
+ if (folded.kind === "scalar") {
1181
+ const str = resolved.map((v) => v.kind === "scalar" ? v.raw : JSON.stringify(v)).join("");
1182
+ return { kind: "scalar", raw: str, valueType: "string" };
1183
+ }
1184
+ return folded;
1185
+ }
1186
+ };
1187
+
1188
+ // src/internal/resolver/resolver.ts
1189
+ function resolveTree(tree, opts) {
1190
+ return new SubstitutionResolver(tree, opts).resolve();
1191
+ }
1192
+ function containsPlaceholders(tree) {
1193
+ for (const val of tree.fields.values()) {
1194
+ if (valContainsPlaceholders(val)) return true;
1195
+ }
1196
+ return false;
1197
+ }
1198
+ function valContainsPlaceholders(v) {
1199
+ const rv = v;
1200
+ if (isSubst(rv) || isConcat(rv)) return true;
1201
+ if (isResObj(rv)) return containsPlaceholders(rv);
1202
+ const hv = v;
1203
+ if (hv?.kind === "array") {
1204
+ return hv.items.some((item) => valContainsPlaceholders(item));
1205
+ }
1206
+ return false;
1207
+ }
1208
+ function buildPartialHoconFromResObj(tree) {
1209
+ const fields = /* @__PURE__ */ new Map();
1210
+ for (const [k, v] of tree.fields) {
1211
+ if (!isSubst(v) && !isConcat(v)) {
1212
+ if (isResObj(v)) {
1213
+ fields.set(k, buildPartialHoconFromResObj(v));
1214
+ } else {
1215
+ if (!valContainsPlaceholders(v)) {
1216
+ fields.set(k, v);
1217
+ }
1218
+ }
1219
+ }
1220
+ }
1221
+ return { kind: "object", fields };
1222
+ }
1223
+ function hoconValueToResObj2(value) {
1224
+ const obj = makeResObj();
1225
+ for (const [k, v] of value.fields) {
1226
+ if (v.kind === "object") {
1227
+ obj.fields.set(k, hoconValueToResObj2(v));
1228
+ } else {
1229
+ obj.fields.set(k, v);
1230
+ }
1231
+ }
1232
+ return obj;
1233
+ }
1234
+
1235
+ // src/render-hocon.ts
1236
+ function renderHoconFromRoot(root) {
1237
+ const out = [];
1238
+ renderObjectBody(out, root, 0);
1239
+ return out.join("");
1240
+ }
1241
+ function renderObjectBody(out, o, depth) {
1242
+ const indent = " ".repeat(depth);
1243
+ for (const [k, v] of o.fields) {
1244
+ out.push(indent, renderKey(k));
1245
+ if (v.kind === "object") {
1246
+ out.push(" {");
1247
+ if (v.fields.size === 0) {
1248
+ out.push("}\n");
1249
+ continue;
1250
+ }
1251
+ out.push("\n");
1252
+ renderObjectBody(out, v, depth + 1);
1253
+ out.push(indent, "}\n");
1254
+ } else {
1255
+ out.push(" = ");
1256
+ renderValue(out, v, depth);
1257
+ out.push("\n");
1258
+ }
1259
+ }
1260
+ }
1261
+ function renderValue(out, v, depth) {
1262
+ switch (v.kind) {
1263
+ case "object": {
1264
+ if (v.fields.size === 0) {
1265
+ out.push("{}");
1266
+ return;
1267
+ }
1268
+ out.push("{\n");
1269
+ renderObjectBody(out, v, depth + 1);
1270
+ out.push(" ".repeat(depth), "}");
1271
+ return;
1272
+ }
1273
+ case "array":
1274
+ renderArray(out, v, depth);
1275
+ return;
1276
+ case "scalar":
1277
+ out.push(renderScalar(v));
1278
+ return;
1279
+ default:
1280
+ throw new ConfigError(
1281
+ "renderHocon: unrenderable value (config must be resolved data)",
1282
+ ""
1283
+ );
1284
+ }
1285
+ }
1286
+ function renderArray(out, a, depth) {
1287
+ if (a.items.length === 0) {
1288
+ out.push("[]");
1289
+ return;
1290
+ }
1291
+ const inner = " ".repeat(depth + 1);
1292
+ out.push("[\n");
1293
+ for (const e of a.items) {
1294
+ out.push(inner);
1295
+ renderValue(out, e, depth + 1);
1296
+ out.push("\n");
1297
+ }
1298
+ out.push(" ".repeat(depth), "]");
1299
+ }
1300
+ function renderScalar(s) {
1301
+ switch (s.valueType) {
1302
+ case "null":
1303
+ return "null";
1304
+ case "boolean":
1305
+ case "number":
1306
+ return s.raw;
1307
+ case "string":
1308
+ return renderString(s.raw);
1309
+ }
1310
+ }
1311
+ var SAFE_UNQUOTED_KEY = /^[A-Za-z0-9_-]+$/;
1312
+ function renderKey(k) {
1313
+ if (k === "include") return quoteString(k);
1314
+ return SAFE_UNQUOTED_KEY.test(k) ? k : quoteString(k);
1315
+ }
1316
+ var SAFE_BARE_STRING = /^[A-Za-z][A-Za-z0-9_-]*$/;
1317
+ var STRING_KEYWORDS = /* @__PURE__ */ new Set(["true", "false", "null", "yes", "no", "on", "off"]);
1318
+ function renderString(s) {
1319
+ return SAFE_BARE_STRING.test(s) && !STRING_KEYWORDS.has(s.toLowerCase()) ? s : quoteString(s);
1320
+ }
1321
+ function quoteString(s) {
1322
+ if (s.includes("\n") && !s.includes("\r") && !s.includes('"""') && !s.endsWith('"')) {
1323
+ return `"""${s}"""`;
1324
+ }
1325
+ let b = '"';
1326
+ for (const ch of s) {
1327
+ switch (ch) {
1328
+ case '"':
1329
+ b += '\\"';
1330
+ break;
1331
+ case "\\":
1332
+ b += "\\\\";
1333
+ break;
1334
+ case "\n":
1335
+ b += "\\n";
1336
+ break;
1337
+ case "\r":
1338
+ b += "\\r";
1339
+ break;
1340
+ case " ":
1341
+ b += "\\t";
1342
+ break;
1343
+ default:
1344
+ b += ch;
1345
+ }
1346
+ }
1347
+ return b + '"';
1348
+ }
1349
+
1350
+ // src/config.ts
1351
+ var Config = class _Config {
1352
+ constructor(root, opts) {
1353
+ this.root = root;
1354
+ this._resolved = opts?.resolved ?? true;
1355
+ this._parseBaseDir = opts?.parseBaseDir;
1356
+ this._originDescription = opts?.originDescription;
1357
+ this._resObjRoot = opts?.resObjRoot;
1358
+ this._resolveOpts = opts?.resolveOpts;
1359
+ }
1360
+ /** Returns true when the Config's value tree contains no unresolved
1361
+ * substitution placeholders. Whole-config granularity (E12 decision 11). */
1362
+ isResolved() {
1363
+ return this._resolved;
1364
+ }
1365
+ /** @internal Test-only: construct a resolved Config from a HoconValue. */
1366
+ static _fromResolvedValue(root, opts) {
1367
+ return new _Config(root, { resolved: true, originDescription: opts?.originDescription });
1368
+ }
1369
+ /** @internal Construct an unresolved Config carrying a ResObj tree.
1370
+ * Used by parseStringWithOptions (deferred path) in T6. */
1371
+ static _fromUnresolvedResObj(tree, opts) {
1372
+ const partialRoot = buildPartialHoconFromResObj(tree);
1373
+ return new _Config(partialRoot, {
1374
+ resolved: opts.resolved,
1375
+ parseBaseDir: opts.parseBaseDir,
1376
+ originDescription: opts.originDescription,
1377
+ resObjRoot: tree,
1378
+ resolveOpts: opts.resolveOpts
1379
+ });
1380
+ }
1381
+ get(path) {
1382
+ const v = this.lookupNode(path);
1383
+ if (v === void 0) return void 0;
1384
+ return hoconToJs(v);
1385
+ }
1386
+ /**
1387
+ * Returns the raw {@link HoconValue} node at `path` as a deeply-immutable
1388
+ * {@link ReadonlyHoconValue} view, or `undefined` if the path is absent. Unlike
1389
+ * `get` (which decodes to a plain JS value), this exposes the value tree for
1390
+ * structural introspection via the `value.ts` accessors (`asString`, `asObject`,
1391
+ * `isScalar`, …).
1392
+ *
1393
+ * `getValue('')` returns the root object node.
1394
+ *
1395
+ * Throws {@link NotResolvedError} when the node (or its subtree) is unresolved:
1396
+ * the `HoconValue` union has no placeholder variant, so an unresolved value
1397
+ * cannot be represented. This matches `getConfig` / `getList`.
1398
+ */
1399
+ getValue(path) {
1400
+ const v = this.lookupNode(path);
1401
+ if (v === void 0) {
1402
+ if (!this._resolved && this._resObjRootSubtreeHasPlaceholders(path)) {
1403
+ throw new NotResolvedError(path);
1404
+ }
1405
+ return void 0;
1406
+ }
1407
+ if (v.kind !== "scalar" && !this._resolved && this._resObjRootSubtreeHasPlaceholders(path)) {
1408
+ throw new NotResolvedError(path);
1409
+ }
1410
+ return v;
1411
+ }
1412
+ getString(path) {
1413
+ const v = this.requireScalar(path);
1414
+ if (v.valueType === "null") {
1415
+ throw new ConfigError(`expected string at ${path}, got ${v.valueType}`, path);
1416
+ }
1417
+ return v.raw;
1418
+ }
1419
+ getNumber(path) {
1420
+ const v = this.requireScalar(path);
1421
+ const coerced = coerceNumber(v.raw);
1422
+ if (coerced !== void 0) return coerced;
1423
+ throw new ConfigError(`expected number at ${path}, got ${v.valueType}`, path);
1424
+ }
1425
+ getBoolean(path) {
1426
+ const v = this.requireScalar(path);
1427
+ const coerced = coerceBoolean(v.raw);
1428
+ if (coerced !== void 0) return coerced;
1429
+ throw new ConfigError(`expected boolean at ${path}, got ${v.valueType}`, path);
1430
+ }
1431
+ getDuration(path, unit) {
1432
+ const v = this.requireScalar(path);
1433
+ if (v.valueType !== "string" && v.valueType !== "number") {
1434
+ throw new ConfigError(`expected duration at ${path}, got ${v.valueType}`, path);
1435
+ }
1436
+ const result = parseDuration(v.raw, unit);
1437
+ if (Number.isNaN(result)) throw new ConfigError(`invalid duration at ${path}: ${JSON.stringify(v.raw)}`, path);
1438
+ return result;
1439
+ }
1440
+ getBytes(path, unit) {
1441
+ const v = this.requireScalar(path);
1442
+ if (v.valueType !== "string" && v.valueType !== "number") {
1443
+ throw new ConfigError(`expected byte size at ${path}, got ${v.valueType}`, path);
1444
+ }
1445
+ const result = parseBytes(v.raw, unit);
1446
+ if (Number.isNaN(result)) throw new ConfigError(`invalid byte size at ${path}: ${JSON.stringify(v.raw)}`, path);
1447
+ if (result < 0) throw new ConfigError(`byte size must be non-negative at ${path}: ${JSON.stringify(v.raw)}`, path);
1448
+ return result;
1449
+ }
1450
+ getConfig(path) {
1451
+ const v = this.lookupNode(path);
1452
+ if (v === void 0) {
1453
+ if (!this._resolved && this._resObjRootSubtreeHasPlaceholders(path)) {
1454
+ throw new NotResolvedError(path);
1455
+ }
1456
+ throw new ConfigError(`path not found: ${path}`, path);
1457
+ }
1458
+ if (v.kind !== "object") throw new ConfigError(`expected object at ${path}`, path);
1459
+ if (!this._resolved && this._resObjRootSubtreeHasPlaceholders(path)) {
1460
+ throw new NotResolvedError(path);
1461
+ }
1462
+ return new _Config(v, { resolved: this._resolved });
1463
+ }
1464
+ getList(path) {
1465
+ const v = this.lookupNode(path);
1466
+ if (v === void 0) {
1467
+ if (!this._resolved && this._resObjRootSubtreeHasPlaceholders(path)) {
1468
+ throw new NotResolvedError(path);
1469
+ }
1470
+ throw new ConfigError(`path not found: ${path}`, path);
1471
+ }
1472
+ if (!this._resolved && this._resObjRootSubtreeHasPlaceholders(path)) {
1473
+ throw new NotResolvedError(path);
1474
+ }
1475
+ if (v.kind === "object") {
1476
+ const converted = numericObjectToArray(v);
1477
+ if (converted !== null) return converted.map((item) => hoconToJs(item));
1478
+ }
1479
+ if (v.kind !== "array") throw new ConfigError(`expected array at ${path}`, path);
1480
+ return v.items.map((item) => hoconToJs(item));
1481
+ }
1482
+ has(path) {
1483
+ return this.lookupNode(path) !== void 0;
1484
+ }
1485
+ keys() {
1486
+ return [...this.root.fields.keys()];
1487
+ }
1488
+ withFallback(fallback) {
1489
+ if (fallback == null) return this;
1490
+ const selfTree = this._resObjRoot ?? hoconValueToResObj2(this.root);
1491
+ const fbTree = fallback._resObjRoot ?? hoconValueToResObj2(fallback.root);
1492
+ const merged = mergeUnresolved(selfTree, fbTree);
1493
+ const hasPlaceholders = containsPlaceholders(merged);
1494
+ const partialRoot = buildPartialHoconFromResObj(merged);
1495
+ return new _Config(partialRoot, {
1496
+ resolved: !hasPlaceholders,
1497
+ parseBaseDir: this._parseBaseDir,
1498
+ originDescription: this._originDescription,
1499
+ resObjRoot: merged,
1500
+ resolveOpts: this._resolveOpts ?? fallback._resolveOpts
1501
+ });
1502
+ }
1503
+ /**
1504
+ * Runs substitution resolution (phase 2) on the stored unresolved tree.
1505
+ * Idempotent: calling resolve() on an already-resolved Config returns an
1506
+ * equivalent resolved Config.
1507
+ *
1508
+ * opts.allowUnresolved (default false) — when true, leaves unresolved
1509
+ * non-optional placeholders in place rather than throwing.
1510
+ * opts.useSystemEnvironment (default true) — when false, env var lookups
1511
+ * are suppressed (hermetic resolution).
1512
+ *
1513
+ * E12 decision 3.
1514
+ */
1515
+ resolve(opts = {}) {
1516
+ if (this._resolved) {
1517
+ return new _Config(this.root, {
1518
+ resolved: true,
1519
+ parseBaseDir: this._parseBaseDir,
1520
+ originDescription: this._originDescription
1521
+ });
1522
+ }
1523
+ const tree = this._resObjRoot;
1524
+ if (!tree) {
1525
+ return new _Config(this.root, { resolved: true });
1526
+ }
1527
+ const resolveOpts = {
1528
+ ...this._resolveOpts ?? { env: {}, baseDir: void 0, readFileSync: () => {
1529
+ throw new Error("no files");
1530
+ } },
1531
+ allowUnresolved: opts.allowUnresolved ?? false,
1532
+ useSystemEnvironment: opts.useSystemEnvironment ?? true,
1533
+ originDescription: this._originDescription
1534
+ };
1535
+ const resolved = resolveTree(tree, resolveOpts);
1536
+ if (resolved.kind !== "object") throw new Error("resolve: expected object root");
1537
+ if (opts.allowUnresolved) {
1538
+ const { stripped, hadPlaceholders } = stripPlaceholderFields(resolved);
1539
+ return new _Config(stripped, {
1540
+ resolved: !hadPlaceholders,
1541
+ parseBaseDir: this._parseBaseDir,
1542
+ originDescription: this._originDescription,
1543
+ resObjRoot: hadPlaceholders ? tree : void 0,
1544
+ resolveOpts: hadPlaceholders ? resolveOpts : void 0
1545
+ });
1546
+ }
1547
+ return new _Config(resolved, {
1548
+ resolved: true,
1549
+ parseBaseDir: this._parseBaseDir,
1550
+ originDescription: this._originDescription
1551
+ });
1552
+ }
1553
+ /**
1554
+ * Resolves receiver substitutions using source as lookup context.
1555
+ * Source's keys are NOT merged into the result — differs from
1556
+ * `this.withFallback(source).resolve()` which includes source keys.
1557
+ *
1558
+ * Precondition (E12 decision 10): source must be resolved. If
1559
+ * source.isResolved() is false, throws NotResolvedError.
1560
+ *
1561
+ * On an already-resolved receiver, resolveWith is a no-op (returns an
1562
+ * equivalent resolved Config, source keys not included).
1563
+ *
1564
+ * E12 decisions 9, 10.
1565
+ */
1566
+ resolveWith(source, opts = {}) {
1567
+ if (!source.isResolved()) {
1568
+ throw new NotResolvedError("source");
1569
+ }
1570
+ if (this._resolved) {
1571
+ return new _Config(this.root, {
1572
+ resolved: true,
1573
+ parseBaseDir: this._parseBaseDir,
1574
+ originDescription: this._originDescription
1575
+ });
1576
+ }
1577
+ const receiverTree = this._resObjRoot ?? hoconValueToResObj2(this.root);
1578
+ const srcTree = hoconValueToResObj2(source.root);
1579
+ const merged = mergeUnresolved(receiverTree, srcTree);
1580
+ const resolveOpts = {
1581
+ ...this._resolveOpts ?? { env: {}, baseDir: void 0, readFileSync: () => {
1582
+ throw new Error("no files");
1583
+ } },
1584
+ allowUnresolved: opts.allowUnresolved ?? false,
1585
+ useSystemEnvironment: opts.useSystemEnvironment ?? true,
1586
+ originDescription: this._originDescription
1587
+ };
1588
+ const resolved = resolveTree(merged, resolveOpts);
1589
+ if (resolved.kind !== "object") throw new Error("resolveWith: expected object root");
1590
+ const receiverShapeForFilter = resObjToKeyShape(receiverTree);
1591
+ const filtered = filterByReceiverShape(resolved, receiverShapeForFilter);
1592
+ if (opts.allowUnresolved) {
1593
+ const { stripped, hadPlaceholders } = stripPlaceholderFields(filtered);
1594
+ return new _Config(stripped, {
1595
+ resolved: !hadPlaceholders,
1596
+ parseBaseDir: this._parseBaseDir,
1597
+ originDescription: this._originDescription,
1598
+ resObjRoot: hadPlaceholders ? receiverTree : void 0,
1599
+ resolveOpts: hadPlaceholders ? resolveOpts : void 0
1600
+ });
1601
+ }
1602
+ return new _Config(filtered, {
1603
+ resolved: true,
1604
+ parseBaseDir: this._parseBaseDir,
1605
+ originDescription: this._originDescription
1606
+ });
1607
+ }
1608
+ /**
1609
+ * The whole config as plain JS data: objects, arrays, strings, numbers,
1610
+ * booleans and `null`.
1611
+ *
1612
+ * Keys are reproduced exactly as the config carries them, `__proto__`,
1613
+ * `constructor` and `prototype` included: each is defined as an **own data
1614
+ * property**, so the returned object's prototype is always
1615
+ * `Object.prototype`, and this call writes nothing to the global one.
1616
+ *
1617
+ * ### Passing the result to other code
1618
+ *
1619
+ * A config file — especially a `.properties` file or an env namespace you
1620
+ * merged in — can therefore hand you an own `__proto__` key, and what happens
1621
+ * next depends entirely on how the consumer copies it:
1622
+ *
1623
+ * ```ts
1624
+ * const data = cfg.toObject()
1625
+ * { ...data } // safe — own properties are copied as data
1626
+ * structuredClone(data) // safe
1627
+ * Object.assign({}, data) // NOT safe — [[Set]] on the {} target hits
1628
+ * // Object.prototype's __proto__ setter: the key
1629
+ * // vanishes and config data becomes the result's
1630
+ * // prototype
1631
+ * deepMerge({}, data) // NOT safe — a naive recursive merge reads
1632
+ * // target['__proto__'], gets Object.prototype,
1633
+ * // and writes to it: global pollution
1634
+ * for (const k in data) … // prefer Object.entries / Object.keys
1635
+ * ```
1636
+ *
1637
+ * Those two hazards come from the **destination** object's prototype, so no
1638
+ * option here can disarm them — copy with spread or `structuredClone` instead.
1639
+ *
1640
+ * What `{ nullPrototype: true }` does give you is a result that inherits
1641
+ * nothing: every object comes back with a `null` prototype, so reading
1642
+ * `x.__proto__`, `x.constructor` or `x.toString` yields config data or
1643
+ * `undefined` rather than something from `Object.prototype`, and code that
1644
+ * merges *into* this object cannot climb out of it. Keys are all still
1645
+ * present. The trade-off is the usual one for prototype-less objects: not
1646
+ * `instanceof Object`, and no `hasOwnProperty` of their own.
1647
+ *
1648
+ * Numbers follow the JS number model, so an integer wider than 2^53 rounds
1649
+ * here even when the config holds it exactly — read those with
1650
+ * {@link Config.getString} instead.
1651
+ */
1652
+ toObject(opts) {
1653
+ return hoconToJs(this.root, opts?.nullPrototype === true);
1654
+ }
1655
+ /**
1656
+ * Renders this resolved Config as HOCON text (E18; lockstep with go.hocon's
1657
+ * `Config.RenderHOCON`, v1.11.0).
1658
+ *
1659
+ * The output round-trips: parsing it back yields the same value tree. That
1660
+ * is the correctness contract, not byte-for-byte formatting — a scalar is
1661
+ * quoted whenever leaving it bare would re-parse as a different type (a
1662
+ * string `"8080"` becomes `"8080"`, not `8080`), and left bare only when it
1663
+ * provably cannot.
1664
+ *
1665
+ * The Config must be resolved and hold only data (objects, arrays, string /
1666
+ * number / boolean / null scalars) — exactly what {@link fromMap} and the
1667
+ * format adapters produce. An unresolved placeholder throws
1668
+ * {@link ConfigError}; substitutions have no textual round trip through a
1669
+ * value tree.
1670
+ *
1671
+ * The root object's fields are emitted without enclosing braces, nested
1672
+ * objects as `key { … }`, arrays as newline-separated `[ … ]`, indented two
1673
+ * spaces. Source comments are not represented — a value tree does not carry
1674
+ * them.
1675
+ */
1676
+ renderHocon() {
1677
+ if (!this._resolved) {
1678
+ throw new ConfigError(
1679
+ "renderHocon: unrenderable unresolved substitution (config must be resolved data)",
1680
+ ""
1681
+ );
1682
+ }
1683
+ return renderHoconFromRoot(this.root);
1684
+ }
1685
+ /**
1686
+ * @internal Test-only: renders this resolved Config's value tree as canonical
1687
+ * JSON (sorted keys, no whitespace). Used by Layer-2 fixture tests to compare
1688
+ * against Lightbend ground truth. NOT part of the public API.
1689
+ *
1690
+ * Throws if the Config is unresolved (contains placeholders).
1691
+ */
1692
+ _renderJSONForTest() {
1693
+ return renderHoconAsJSON(this.root);
1694
+ }
1695
+ lookupNode(path) {
1696
+ const segments = splitConfigPath(path);
1697
+ let current = this.root;
1698
+ for (const seg of segments) {
1699
+ if (current.kind !== "object") return void 0;
1700
+ const next = current.fields.get(seg);
1701
+ if (next === void 0) return void 0;
1702
+ current = next;
1703
+ }
1704
+ return current;
1705
+ }
1706
+ /**
1707
+ * _resObjRootSubtreeHasPlaceholders — walk _resObjRoot to the given path and
1708
+ * return true if the subtree there contains any unresolved placeholder.
1709
+ * Used by getConfig / getList (T2) to detect transitive unresolved placeholders
1710
+ * in object / array subtrees that would otherwise appear to be "resolved" in the
1711
+ * partial HoconValue root (because individual leaf fields are omitted rather than
1712
+ * the whole subtree when their value is a direct placeholder scalar, but object
1713
+ * sub-containers are retained in the partial root with the placeholder-keyed
1714
+ * fields omitted from them — so the object appears "present but empty-ish").
1715
+ */
1716
+ _resObjRootSubtreeHasPlaceholders(path) {
1717
+ const tree = this._resObjRoot;
1718
+ if (!tree) return false;
1719
+ const segments = splitConfigPath(path);
1720
+ let cur = tree;
1721
+ for (const seg of segments) {
1722
+ const val = cur.fields.get(seg);
1723
+ if (val === void 0) return false;
1724
+ if (isResObj(val)) {
1725
+ cur = val;
1726
+ } else {
1727
+ return valContainsPlaceholders(val);
1728
+ }
1729
+ }
1730
+ return containsPlaceholders(cur);
1731
+ }
1732
+ requireScalar(path) {
1733
+ const v = this.lookupNode(path);
1734
+ if (v === void 0) {
1735
+ if (!this._resolved && this._resObjRootSubtreeHasPlaceholders(path)) {
1736
+ throw new NotResolvedError(path);
1737
+ }
1738
+ throw new ConfigError(`path not found: ${path}`, path);
1739
+ }
1740
+ if (v.kind !== "scalar") throw new ConfigError(`expected scalar at ${path}, got ${v.kind}`, path);
1741
+ return v;
1742
+ }
1743
+ };
1744
+ function splitConfigPath(path) {
1745
+ const segments = [];
1746
+ let i = 0;
1747
+ while (i < path.length) {
1748
+ if (path[i] === '"') {
1749
+ i++;
1750
+ let segment = "";
1751
+ let closed = false;
1752
+ while (i < path.length) {
1753
+ const ch = path[i];
1754
+ if (ch === "\\" && i + 1 < path.length) {
1755
+ const next = path[i + 1];
1756
+ segment += next;
1757
+ i += 2;
1758
+ continue;
1759
+ }
1760
+ if (ch === '"') {
1761
+ closed = true;
1762
+ i++;
1763
+ break;
1764
+ }
1765
+ segment += ch;
1766
+ i++;
1767
+ }
1768
+ if (!closed) throw new ConfigError(`unterminated quoted path segment: ${path}`, path);
1769
+ segments.push(segment);
1770
+ if (i < path.length && path[i] === ".") i++;
1771
+ } else {
1772
+ const dot = path.indexOf(".", i);
1773
+ if (dot === -1) {
1774
+ segments.push(path.slice(i));
1775
+ break;
1776
+ }
1777
+ segments.push(path.slice(i, dot));
1778
+ i = dot + 1;
1779
+ }
1780
+ }
1781
+ return segments;
1782
+ }
1783
+ function scalarToJs(raw, valueType) {
1784
+ switch (valueType) {
1785
+ case "null":
1786
+ return null;
1787
+ case "boolean":
1788
+ return raw === "true";
1789
+ case "number":
1790
+ return Number(raw);
1791
+ case "string":
1792
+ return raw;
1793
+ }
1794
+ }
1795
+ function hoconToJs(v, nullPrototype = false) {
1796
+ switch (v.kind) {
1797
+ case "scalar":
1798
+ return scalarToJs(v.raw, v.valueType);
1799
+ case "array":
1800
+ return v.items.map((item) => hoconToJs(item, nullPrototype));
1801
+ case "object": {
1802
+ const entries = Array.from(v.fields, ([k, val]) => [k, hoconToJs(val, nullPrototype)]);
1803
+ if (nullPrototype) {
1804
+ const obj = /* @__PURE__ */ Object.create(null);
1805
+ for (const [k, val] of entries) Object.defineProperty(obj, k, {
1806
+ value: val,
1807
+ writable: true,
1808
+ enumerable: true,
1809
+ configurable: true
1810
+ });
1811
+ return obj;
1812
+ }
1813
+ return Object.fromEntries(entries);
1814
+ }
1815
+ }
1816
+ }
1817
+ function resObjToKeyShape(tree) {
1818
+ const fields = /* @__PURE__ */ new Map();
1819
+ for (const [k, v] of tree.fields) {
1820
+ if (isSubst(v) || isConcat(v)) {
1821
+ fields.set(k, { kind: "scalar", raw: "", valueType: "null" });
1822
+ } else if (isResObj(v)) {
1823
+ fields.set(k, resObjToKeyShape(v));
1824
+ } else {
1825
+ fields.set(k, v);
1826
+ }
1827
+ }
1828
+ return { kind: "object", fields };
1829
+ }
1830
+ function stripPlaceholderFields(v) {
1831
+ const fields = /* @__PURE__ */ new Map();
1832
+ let hadPlaceholders = false;
1833
+ for (const [k, val] of v.fields) {
1834
+ if (val._kind === "subst-placeholder" || val._kind === "concat-placeholder") {
1835
+ hadPlaceholders = true;
1836
+ } else if (val.kind === "object") {
1837
+ const inner = stripPlaceholderFields(val);
1838
+ if (inner.hadPlaceholders) hadPlaceholders = true;
1839
+ fields.set(k, inner.stripped);
1840
+ } else {
1841
+ fields.set(k, val);
1842
+ }
1843
+ }
1844
+ return { stripped: { kind: "object", fields }, hadPlaceholders };
1845
+ }
1846
+ function filterByReceiverShape(resolved, receiverShape) {
1847
+ const fields = /* @__PURE__ */ new Map();
1848
+ for (const [k, rv] of resolved.fields) {
1849
+ if (!receiverShape.fields.has(k)) continue;
1850
+ const receiverVal = receiverShape.fields.get(k);
1851
+ if (rv.kind === "object" && receiverVal.kind === "object") {
1852
+ fields.set(k, filterByReceiverShape(rv, receiverVal));
1853
+ } else {
1854
+ fields.set(k, rv);
1855
+ }
1856
+ }
1857
+ return { kind: "object", fields };
1858
+ }
1859
+ function renderHoconAsJSON(v) {
1860
+ switch (v.kind) {
1861
+ case "scalar": {
1862
+ switch (v.valueType) {
1863
+ case "null":
1864
+ return "null";
1865
+ case "boolean":
1866
+ return v.raw;
1867
+ case "number": {
1868
+ const norm = normalizeLeadingZeroNumber(v.raw);
1869
+ return JSON_NUMBER_RE.test(norm) ? norm : JSON.stringify(v.raw);
1870
+ }
1871
+ case "string":
1872
+ return JSON.stringify(v.raw);
1873
+ }
1874
+ break;
1875
+ }
1876
+ case "array": {
1877
+ const items = v.items.map(renderHoconAsJSON);
1878
+ return `[${items.join(",")}]`;
1879
+ }
1880
+ case "object": {
1881
+ const keys = [...v.fields.keys()].sort();
1882
+ const pairs = keys.map((k) => {
1883
+ const val = v.fields.get(k);
1884
+ return `${JSON.stringify(k)}:${renderHoconAsJSON(val)}`;
1885
+ });
1886
+ return `{${pairs.join(",")}}`;
1887
+ }
1888
+ }
1889
+ throw new Error(`renderHoconAsJSON: unsupported value kind (unresolved placeholder?)`);
1890
+ }
1891
+ var JSON_NUMBER_RE = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
1892
+ function normalizeLeadingZeroNumber(raw) {
1893
+ return raw.replace(/^([+-]?)0+(\d)/, "$1$2");
1894
+ }
1895
+
1896
+ // src/value-factory.ts
1897
+ function fromMap(values, originDescription) {
1898
+ const fields = guardStackDepth(
1899
+ () => coerceObject(values, ""),
1900
+ (msg) => depthError(`fromMap: ${msg}`)
1901
+ );
1902
+ const root = { kind: "object", fields };
1903
+ return Config._fromResolvedValue(root, { originDescription });
1904
+ }
1905
+ var INT64_MAX = 9223372036854775807n;
1906
+ var INT64_MIN = -9223372036854775808n;
1907
+ function coerceObject(obj, atPath) {
1908
+ const fields = /* @__PURE__ */ new Map();
1909
+ for (const [k, v] of Object.entries(obj)) {
1910
+ const childPath = atPath ? `${atPath}.${k}` : k;
1911
+ fields.set(k, coerceValue(v, childPath));
1912
+ }
1913
+ return fields;
1914
+ }
1915
+ function coerceValue(v, atPath) {
1916
+ if (v === null) {
1917
+ return { kind: "scalar", raw: "null", valueType: "null" };
1918
+ }
1919
+ if (v === void 0) {
1920
+ throw new ConfigError(
1921
+ `fromMap: undefined is not a valid HOCON value at path "${atPath}"`,
1922
+ atPath
1923
+ );
1924
+ }
1925
+ switch (typeof v) {
1926
+ case "string":
1927
+ return { kind: "scalar", raw: v, valueType: "string" };
1928
+ case "number": {
1929
+ if (Number.isNaN(v) || !Number.isFinite(v)) {
1930
+ throw new ConfigError(
1931
+ `fromMap: ${v} is not representable in HOCON (NaN/Infinity not allowed) at path "${atPath}"`,
1932
+ atPath
1933
+ );
1934
+ }
1935
+ return { kind: "scalar", raw: Object.is(v, -0) ? "-0" : String(v), valueType: "number" };
1936
+ }
1937
+ case "boolean":
1938
+ return { kind: "scalar", raw: v ? "true" : "false", valueType: "boolean" };
1939
+ case "bigint": {
1940
+ if (v > INT64_MAX || v < INT64_MIN) {
1941
+ throw new ConfigError(
1942
+ `fromMap: integer ${v} is out of int64 range (HOCON integers are int64; spec F0.5) at path "${atPath}"`,
1943
+ atPath
1944
+ );
1945
+ }
1946
+ return { kind: "scalar", raw: String(v), valueType: "number" };
1947
+ }
1948
+ case "object": {
1949
+ if (Array.isArray(v)) {
1950
+ const items = v.map((item, i) => coerceValue(item, `${atPath}[${i}]`));
1951
+ return { kind: "array", items };
1952
+ }
1953
+ const fields = coerceObject(v, atPath);
1954
+ return { kind: "object", fields };
1955
+ }
1956
+ default:
1957
+ throw new ConfigError(
1958
+ `fromMap: unsupported value type "${typeof v}" at path "${atPath}"`,
1959
+ atPath
1960
+ );
1961
+ }
1962
+ }
1963
+
1964
+ // src/adapters/json5.ts
1965
+ function parseJson5(input, originDescription) {
1966
+ const p = new Parser(stripBom(input), originDescription);
1967
+ const doc = guardStackDepth(
1968
+ () => p.parseDocument(),
1969
+ (msg) => depthError(`json5: ${describe(originDescription)}: ${msg}`)
1970
+ );
1971
+ if (doc === null || typeof doc !== "object" || Array.isArray(doc)) {
1972
+ throw new ConfigError(
1973
+ `json5: ${describe(originDescription)}: document root is ${rootKind(doc)}, but a config root must be an object (spec F0.3)`,
1974
+ ""
1975
+ );
1976
+ }
1977
+ return fromMap(doc, originDescription);
1978
+ }
1979
+ function describe(origin) {
1980
+ return origin === void 0 || origin === "" ? "document" : origin;
1981
+ }
1982
+ function rootKind(doc) {
1983
+ if (doc === null) return "null";
1984
+ if (Array.isArray(doc)) return "an array";
1985
+ return typeof doc;
1986
+ }
1987
+ var INT64_MAX2 = 9223372036854775807n;
1988
+ var INT64_MIN2 = -9223372036854775808n;
1989
+ function isLineTerminator(cp) {
1990
+ return cp === 10 || cp === 13 || cp === 8232 || cp === 8233;
1991
+ }
1992
+ var ZS_RE = /^\p{Zs}$/u;
1993
+ function isJson5Space(cp) {
1994
+ switch (cp) {
1995
+ case 9:
1996
+ case 11:
1997
+ case 12:
1998
+ case 32:
1999
+ case 160:
2000
+ case 65279:
2001
+ return true;
2002
+ default:
2003
+ return ZS_RE.test(String.fromCodePoint(cp));
2004
+ }
2005
+ }
2006
+ var IDENT_START_RE = /^[\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nl}]$/u;
2007
+ var IDENT_PART_EXTRA_RE = /^[\p{Mn}\p{Mc}\p{Nd}\p{Pc}]$/u;
2008
+ function isIdentStart(cp) {
2009
+ return cp === 36 || cp === 95 || IDENT_START_RE.test(String.fromCodePoint(cp));
2010
+ }
2011
+ function isIdentPart(cp) {
2012
+ return isIdentStart(cp) || cp === 8204 || cp === 8205 || IDENT_PART_EXTRA_RE.test(String.fromCodePoint(cp));
2013
+ }
2014
+ function continuesIdentifier(s, i) {
2015
+ if (i >= s.length) return false;
2016
+ return isIdentPart(s.codePointAt(i));
2017
+ }
2018
+ function isHexDigit(c) {
2019
+ return c >= "0" && c <= "9" || c >= "a" && c <= "f" || c >= "A" && c <= "F";
2020
+ }
2021
+ var hex4 = (cp) => cp.toString(16).toUpperCase().padStart(4, "0");
2022
+ function isPlainObject(v) {
2023
+ return typeof v === "object" && v !== null && !Array.isArray(v);
2024
+ }
2025
+ function mergeObjects(dst, src) {
2026
+ const out = /* @__PURE__ */ Object.create(null);
2027
+ for (const [k, v] of Object.entries(dst)) out[k] = v;
2028
+ for (const [k, v] of Object.entries(src)) {
2029
+ const prev = k in out ? out[k] : void 0;
2030
+ if (prev !== void 0 && isPlainObject(prev) && isPlainObject(v)) {
2031
+ out[k] = mergeObjects(prev, v);
2032
+ } else {
2033
+ out[k] = v;
2034
+ }
2035
+ }
2036
+ return out;
2037
+ }
2038
+ var Parser = class {
2039
+ // code unit offset where the current line starts
2040
+ constructor(src, origin) {
2041
+ this.src = src;
2042
+ this.origin = origin;
2043
+ this.pos = 0;
2044
+ // UTF-16 code unit offset
2045
+ this.line = 0;
2046
+ // 0-based; reported 1-based
2047
+ this.lineAt = 0;
2048
+ }
2049
+ errf(msg) {
2050
+ const col = [...this.src.slice(this.lineAt, this.pos)].length + 1;
2051
+ return new ConfigError(
2052
+ `json5: ${describe(this.origin)}: line ${this.line + 1} col ${col}: ${msg}`,
2053
+ ""
2054
+ );
2055
+ }
2056
+ /** The code point at `pos` (caller guarantees `pos < src.length`). */
2057
+ rune() {
2058
+ const cp = this.src.codePointAt(this.pos);
2059
+ return { cp, size: cp > 65535 ? 2 : 1 };
2060
+ }
2061
+ advance(cp, size) {
2062
+ this.pos += size;
2063
+ if (isLineTerminator(cp)) {
2064
+ if (cp === 13 && this.src[this.pos] === "\n") this.pos++;
2065
+ this.line++;
2066
+ this.lineAt = this.pos;
2067
+ }
2068
+ }
2069
+ /**
2070
+ * Parse exactly one JSON5 value, allowing only whitespace and comments after
2071
+ * it (the F3.2 strictness rule).
2072
+ */
2073
+ parseDocument() {
2074
+ this.skipSpace();
2075
+ const v = this.parseValue();
2076
+ this.skipSpace();
2077
+ if (this.pos < this.src.length) {
2078
+ throw this.errf("unexpected content after top-level value");
2079
+ }
2080
+ return v;
2081
+ }
2082
+ /** Consume whitespace, line terminators, and both comment forms. */
2083
+ skipSpace() {
2084
+ while (this.pos < this.src.length) {
2085
+ const { cp, size } = this.rune();
2086
+ if (isJson5Space(cp) || isLineTerminator(cp)) {
2087
+ this.advance(cp, size);
2088
+ continue;
2089
+ }
2090
+ if (cp === 47 && this.src[this.pos + 1] === "/") {
2091
+ this.pos += 2;
2092
+ while (this.pos < this.src.length) {
2093
+ const cp2 = this.src.codePointAt(this.pos);
2094
+ if (isLineTerminator(cp2)) break;
2095
+ this.pos += cp2 > 65535 ? 2 : 1;
2096
+ }
2097
+ continue;
2098
+ }
2099
+ if (cp === 47 && this.src[this.pos + 1] === "*") {
2100
+ this.pos += 2;
2101
+ let closed = false;
2102
+ while (this.pos < this.src.length) {
2103
+ const r2 = this.rune();
2104
+ if (r2.cp === 42 && this.src[this.pos + 1] === "/") {
2105
+ this.pos += 2;
2106
+ closed = true;
2107
+ break;
2108
+ }
2109
+ this.advance(r2.cp, r2.size);
2110
+ }
2111
+ if (!closed) throw this.errf("unterminated /* comment");
2112
+ continue;
2113
+ }
2114
+ return;
2115
+ }
2116
+ }
2117
+ parseValue() {
2118
+ if (this.pos >= this.src.length) {
2119
+ throw this.errf("unexpected end of input, expected a value");
2120
+ }
2121
+ const c = this.src[this.pos];
2122
+ if (c === "{") return this.parseObject();
2123
+ if (c === "[") return this.parseArray();
2124
+ if (c === '"' || c === "'") return this.parseString(c);
2125
+ if (c === "+" || c === "-" || c === "." || c >= "0" && c <= "9") return this.parseNumber();
2126
+ return this.parseKeyword();
2127
+ }
2128
+ /**
2129
+ * Handle true/false/null, and reject Infinity/NaN by name so the error
2130
+ * explains itself (spec F0.6).
2131
+ */
2132
+ parseKeyword() {
2133
+ const rest = this.src.slice(this.pos);
2134
+ for (const [kw, v] of [
2135
+ ["true", true],
2136
+ ["false", false],
2137
+ ["null", null]
2138
+ ]) {
2139
+ if (rest.startsWith(kw) && !continuesIdentifier(rest, kw.length)) {
2140
+ this.pos += kw.length;
2141
+ return v;
2142
+ }
2143
+ }
2144
+ for (const kw of ["Infinity", "NaN"]) {
2145
+ if (rest.startsWith(kw) && !continuesIdentifier(rest, kw.length)) {
2146
+ throw this.errf(`${kw} is not representable in the HOCON number model (spec F0.6)`);
2147
+ }
2148
+ }
2149
+ const first = String.fromCodePoint(rest.codePointAt(0));
2150
+ throw this.errf(`unexpected character ${JSON.stringify(first)}`);
2151
+ }
2152
+ // ── Objects and arrays ──────────────────────────────────────────────────────
2153
+ parseObject() {
2154
+ this.pos++;
2155
+ const obj = /* @__PURE__ */ Object.create(null);
2156
+ for (; ; ) {
2157
+ this.skipSpace();
2158
+ if (this.pos >= this.src.length) throw this.errf("unterminated object, expected '}'");
2159
+ if (this.src[this.pos] === "}") {
2160
+ this.pos++;
2161
+ return obj;
2162
+ }
2163
+ const key = this.parseMemberName();
2164
+ this.skipSpace();
2165
+ if (this.pos >= this.src.length || this.src[this.pos] !== ":") {
2166
+ throw this.errf(`expected ':' after object key ${JSON.stringify(key)}`);
2167
+ }
2168
+ this.pos++;
2169
+ this.skipSpace();
2170
+ let val = this.parseValue();
2171
+ if (key in obj) {
2172
+ const prev = obj[key];
2173
+ if (isPlainObject(prev) && isPlainObject(val)) val = mergeObjects(prev, val);
2174
+ }
2175
+ obj[key] = val;
2176
+ this.skipSpace();
2177
+ if (this.pos >= this.src.length) throw this.errf("unterminated object, expected ',' or '}'");
2178
+ const c = this.src[this.pos];
2179
+ if (c === ",") {
2180
+ this.pos++;
2181
+ } else if (c === "}") {
2182
+ this.pos++;
2183
+ return obj;
2184
+ } else {
2185
+ throw this.errf("expected ',' or '}' in object");
2186
+ }
2187
+ }
2188
+ }
2189
+ parseArray() {
2190
+ this.pos++;
2191
+ const arr = [];
2192
+ for (; ; ) {
2193
+ this.skipSpace();
2194
+ if (this.pos >= this.src.length) throw this.errf("unterminated array, expected ']'");
2195
+ if (this.src[this.pos] === "]") {
2196
+ this.pos++;
2197
+ return arr;
2198
+ }
2199
+ arr.push(this.parseValue());
2200
+ this.skipSpace();
2201
+ if (this.pos >= this.src.length) throw this.errf("unterminated array, expected ',' or ']'");
2202
+ const c = this.src[this.pos];
2203
+ if (c === ",") {
2204
+ this.pos++;
2205
+ } else if (c === "]") {
2206
+ this.pos++;
2207
+ return arr;
2208
+ } else {
2209
+ throw this.errf("expected ',' or ']' in array");
2210
+ }
2211
+ }
2212
+ }
2213
+ // ── Member names (quoted or ES5 IdentifierName) ─────────────────────────────
2214
+ parseMemberName() {
2215
+ const c = this.src[this.pos];
2216
+ if (c === '"' || c === "'") return this.parseString(c);
2217
+ return this.parseIdentifier();
2218
+ }
2219
+ /**
2220
+ * Scan an ES5 IdentifierName, honouring `\uXXXX` escapes in the name (the
2221
+ * escaped codepoint must itself be a legal identifier character for its
2222
+ * position, per ES5 — `1` cannot start a key).
2223
+ */
2224
+ parseIdentifier() {
2225
+ let name = "";
2226
+ let first = true;
2227
+ while (this.pos < this.src.length) {
2228
+ const r = this.rune();
2229
+ let cp = r.cp;
2230
+ let escaped = false;
2231
+ if (cp === 92) {
2232
+ if (this.src[this.pos + 1] !== "u") {
2233
+ throw this.errf("only \\uXXXX escapes are allowed in identifiers");
2234
+ }
2235
+ this.pos += 2;
2236
+ cp = this.readHex4();
2237
+ escaped = true;
2238
+ }
2239
+ const legal = first ? isIdentStart(cp) : isIdentPart(cp);
2240
+ if (!legal) {
2241
+ if (escaped) {
2242
+ throw this.errf(`escape \\u${hex4(cp)} is not a valid identifier character here`);
2243
+ }
2244
+ if (first) {
2245
+ throw this.errf(`expected an object key, got ${JSON.stringify(String.fromCodePoint(cp))}`);
2246
+ }
2247
+ break;
2248
+ }
2249
+ name += String.fromCodePoint(cp);
2250
+ if (!escaped) this.pos += r.size;
2251
+ first = false;
2252
+ }
2253
+ if (name.length === 0) throw this.errf("expected an object key");
2254
+ return name;
2255
+ }
2256
+ /** Read exactly four hex digits at `pos` and return the code point. */
2257
+ readHex4() {
2258
+ if (this.pos + 4 > this.src.length) throw this.errf("truncated \\u escape");
2259
+ const quad = this.src.slice(this.pos, this.pos + 4);
2260
+ if (!/^[0-9a-fA-F]{4}$/.test(quad)) {
2261
+ throw this.errf(`invalid \\u escape ${JSON.stringify("\\u" + quad)}`);
2262
+ }
2263
+ this.pos += 4;
2264
+ return parseInt(quad, 16);
2265
+ }
2266
+ // ── Strings ─────────────────────────────────────────────────────────────────
2267
+ /**
2268
+ * Scan a single- or double-quoted JSON5 string. `quote` is the opening quote
2269
+ * character. JSON5 differences from JSON: either quote character, `\xHH`
2270
+ * escapes, `\v`, `\0`, line continuations (backslash before a line
2271
+ * terminator, including CRLF as one), any other non-digit character escaping
2272
+ * to itself, and unescaped LS/PS allowed inside the string.
2273
+ */
2274
+ parseString(quote) {
2275
+ this.pos++;
2276
+ let out = "";
2277
+ for (; ; ) {
2278
+ if (this.pos >= this.src.length) throw this.errf("unterminated string");
2279
+ const { cp, size } = this.rune();
2280
+ if (this.src[this.pos] === quote) {
2281
+ this.pos++;
2282
+ return out;
2283
+ }
2284
+ if (cp === 10 || cp === 13) {
2285
+ throw this.errf("unescaped line terminator in string");
2286
+ }
2287
+ if (cp === 92) {
2288
+ this.pos++;
2289
+ out += this.readEscape();
2290
+ continue;
2291
+ }
2292
+ out += this.src.slice(this.pos, this.pos + size);
2293
+ this.advance(cp, size);
2294
+ }
2295
+ }
2296
+ /**
2297
+ * Consume one escape sequence (the backslash is already consumed) and return
2298
+ * its value.
2299
+ */
2300
+ readEscape() {
2301
+ if (this.pos >= this.src.length) throw this.errf("unterminated escape sequence");
2302
+ const { cp, size } = this.rune();
2303
+ if (isLineTerminator(cp)) {
2304
+ this.advance(cp, size);
2305
+ return "";
2306
+ }
2307
+ const ch = String.fromCodePoint(cp);
2308
+ switch (ch) {
2309
+ case "n":
2310
+ this.pos++;
2311
+ return "\n";
2312
+ case "t":
2313
+ this.pos++;
2314
+ return " ";
2315
+ case "r":
2316
+ this.pos++;
2317
+ return "\r";
2318
+ case "b":
2319
+ this.pos++;
2320
+ return "\b";
2321
+ case "f":
2322
+ this.pos++;
2323
+ return "\f";
2324
+ case "v":
2325
+ this.pos++;
2326
+ return "\v";
2327
+ case "0": {
2328
+ const next = this.src[this.pos + 1];
2329
+ if (next !== void 0 && next >= "0" && next <= "9") {
2330
+ throw this.errf("octal escape sequences are not allowed");
2331
+ }
2332
+ this.pos++;
2333
+ return "\0";
2334
+ }
2335
+ case "1":
2336
+ case "2":
2337
+ case "3":
2338
+ case "4":
2339
+ case "5":
2340
+ case "6":
2341
+ case "7":
2342
+ case "8":
2343
+ case "9":
2344
+ throw this.errf(`escape \\${ch} is not allowed (digits cannot be escaped)`);
2345
+ case "x": {
2346
+ this.pos++;
2347
+ if (this.pos + 2 > this.src.length) throw this.errf("truncated \\x escape");
2348
+ const hh = this.src.slice(this.pos, this.pos + 2);
2349
+ if (!/^[0-9a-fA-F]{2}$/.test(hh)) throw this.errf("invalid \\x escape");
2350
+ this.pos += 2;
2351
+ return String.fromCharCode(parseInt(hh, 16));
2352
+ }
2353
+ case "u": {
2354
+ this.pos++;
2355
+ const hi = this.readHex4();
2356
+ if (hi >= 55296 && hi <= 57343) {
2357
+ if (this.pos + 6 <= this.src.length && this.src[this.pos] === "\\" && this.src[this.pos + 1] === "u") {
2358
+ this.pos += 2;
2359
+ const lo = this.readHex4();
2360
+ if (hi <= 56319 && lo >= 56320 && lo <= 57343) {
2361
+ return String.fromCodePoint(65536 + (hi - 55296 << 10) + (lo - 56320));
2362
+ }
2363
+ throw this.errf(`unpaired \\u${hex4(hi)} surrogate (spec F3.5)`);
2364
+ }
2365
+ throw this.errf(`unpaired \\u${hex4(hi)} surrogate (spec F3.5)`);
2366
+ }
2367
+ return String.fromCharCode(hi);
2368
+ }
2369
+ default:
2370
+ this.advance(cp, size);
2371
+ return ch;
2372
+ }
2373
+ }
2374
+ // ── Numbers ─────────────────────────────────────────────────────────────────
2375
+ /**
2376
+ * Scan a JSON5 numeric literal: optional sign, then a hex integer or a
2377
+ * decimal with optional leading/trailing point and exponent. Signed
2378
+ * Infinity/NaN are routed to the F0.6 error here.
2379
+ */
2380
+ parseNumber() {
2381
+ const start = this.pos;
2382
+ let neg = false;
2383
+ const sign = this.src[this.pos];
2384
+ if (sign === "+" || sign === "-") {
2385
+ neg = sign === "-";
2386
+ this.pos++;
2387
+ }
2388
+ const rest = this.src.slice(this.pos);
2389
+ for (const kw of ["Infinity", "NaN"]) {
2390
+ if (rest.startsWith(kw) && !continuesIdentifier(rest, kw.length)) {
2391
+ throw this.errf(`${kw} is not representable in the HOCON number model (spec F0.6)`);
2392
+ }
2393
+ }
2394
+ if (rest.startsWith("0x") || rest.startsWith("0X")) {
2395
+ this.pos += 2;
2396
+ const ds = this.pos;
2397
+ while (this.pos < this.src.length && isHexDigit(this.src[this.pos])) this.pos++;
2398
+ if (this.pos === ds) throw this.errf("hex literal needs at least one digit");
2399
+ const mag = BigInt("0x" + this.src.slice(ds, this.pos));
2400
+ const limit = neg ? 1n << 63n : (1n << 63n) - 1n;
2401
+ if (mag > limit) {
2402
+ throw this.errf(`integer ${this.src.slice(start, this.pos)} does not fit in int64 (spec F0.5)`);
2403
+ }
2404
+ if (neg && mag === 0n) return -0;
2405
+ return integerValue(neg ? -mag : mag);
2406
+ }
2407
+ let sawDigit = false;
2408
+ let sawDot = false;
2409
+ let sawExp = false;
2410
+ while (this.pos < this.src.length) {
2411
+ const c = this.src[this.pos];
2412
+ if (c >= "0" && c <= "9") {
2413
+ sawDigit = true;
2414
+ } else if (c === "." && !sawDot && !sawExp) {
2415
+ sawDot = true;
2416
+ } else if ((c === "e" || c === "E") && sawDigit && !sawExp) {
2417
+ sawExp = true;
2418
+ const n = this.src[this.pos + 1];
2419
+ if (n === "+" || n === "-") this.pos++;
2420
+ } else {
2421
+ break;
2422
+ }
2423
+ this.pos++;
2424
+ }
2425
+ const text = this.src.slice(start, this.pos);
2426
+ if (!sawDigit) throw this.errf(`malformed number ${JSON.stringify(text)}`);
2427
+ if (sawDot || sawExp) {
2428
+ const f = Number(text);
2429
+ if (Number.isNaN(f) || !Number.isFinite(f)) {
2430
+ throw this.errf(`malformed number ${JSON.stringify(text)}`);
2431
+ }
2432
+ return f;
2433
+ }
2434
+ const digits = text.startsWith("+") ? text.slice(1) : text;
2435
+ const i = BigInt(digits);
2436
+ if (i > INT64_MAX2 || i < INT64_MIN2) {
2437
+ throw this.errf(`integer ${text} does not fit in int64 (spec F0.5)`);
2438
+ }
2439
+ if (i >= -9007199254740991n && i <= 9007199254740991n) return Number(digits);
2440
+ return i;
2441
+ }
2442
+ };
2443
+ function integerValue(v) {
2444
+ if (v >= -9007199254740991n && v <= 9007199254740991n) return Number(v);
2445
+ return v;
2446
+ }
2447
+ // Annotate the CommonJS export names for ESM import in node:
2448
+ 0 && (module.exports = {
2449
+ parseJson5
2450
+ });