@o3co/ts.hocon 0.1.2 → 0.1.5

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/dist/zod.cjs CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,25 +17,945 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
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
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/zod.ts
21
31
  var zod_exports = {};
22
32
  __export(zod_exports, {
23
33
  getValidated: () => getValidated,
34
+ parseFileWithSchema: () => parseFileWithSchema,
35
+ parseWithSchema: () => parseWithSchema,
24
36
  validate: () => validate
25
37
  });
26
38
  module.exports = __toCommonJS(zod_exports);
39
+
40
+ // src/coerce.ts
41
+ var TRUTHY = /* @__PURE__ */ new Set(["true", "yes", "on"]);
42
+ var FALSY = /* @__PURE__ */ new Set(["false", "no", "off"]);
43
+ function coerceBoolean(value) {
44
+ const lower = value.toLowerCase();
45
+ if (TRUTHY.has(lower)) return true;
46
+ if (FALSY.has(lower)) return false;
47
+ return void 0;
48
+ }
49
+ function coerceNumber(value) {
50
+ if (!/^-?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/.test(value)) return void 0;
51
+ return Number(value);
52
+ }
53
+
54
+ // src/errors.ts
55
+ var ParseError = class extends Error {
56
+ constructor(message, line, col, file) {
57
+ super(message);
58
+ this.line = line;
59
+ this.col = col;
60
+ this.file = file;
61
+ this.name = "ParseError";
62
+ }
63
+ };
64
+ var ResolveError = class extends Error {
65
+ constructor(message, path2, line, col, file) {
66
+ super(message);
67
+ this.path = path2;
68
+ this.line = line;
69
+ this.col = col;
70
+ this.file = file;
71
+ this.name = "ResolveError";
72
+ }
73
+ };
74
+ var ConfigError = class extends Error {
75
+ constructor(message, path2) {
76
+ super(message);
77
+ this.path = path2;
78
+ this.name = "ConfigError";
79
+ }
80
+ };
81
+
82
+ // src/internal/lexer/lexer.ts
83
+ function tokenize(input) {
84
+ if (input.charCodeAt(0) === 65279) input = input.slice(1);
85
+ const tokens = [];
86
+ let pos = 0;
87
+ let line = 1;
88
+ let col = 1;
89
+ let hadSpace = false;
90
+ function peek(offset = 0) {
91
+ return input[pos + offset] ?? "";
92
+ }
93
+ function advance() {
94
+ const ch = input[pos++] ?? "";
95
+ if (ch === "\n") {
96
+ line++;
97
+ col = 1;
98
+ } else {
99
+ col++;
100
+ }
101
+ return ch;
102
+ }
103
+ function push(kind, value, l, c, isQuoted = false) {
104
+ tokens.push({ kind, value, line: l, col: c, isQuoted, precedingSpace: hadSpace });
105
+ hadSpace = false;
106
+ }
107
+ while (pos < input.length) {
108
+ const sl = line, sc = col;
109
+ const ch = peek();
110
+ if (ch === " " || ch === " " || ch === "\r") {
111
+ advance();
112
+ hadSpace = true;
113
+ continue;
114
+ }
115
+ if (ch === "\n") {
116
+ advance();
117
+ if (tokens[tokens.length - 1]?.kind !== "newline") {
118
+ push("newline", "\n", sl, sc);
119
+ }
120
+ continue;
121
+ }
122
+ if (ch === "/" && peek(1) === "/") {
123
+ while (pos < input.length && peek() !== "\n") advance();
124
+ hadSpace = true;
125
+ continue;
126
+ }
127
+ if (ch === "#") {
128
+ while (pos < input.length && peek() !== "\n") advance();
129
+ hadSpace = true;
130
+ continue;
131
+ }
132
+ const single = { "{": "lbrace", "}": "rbrace", "[": "lbracket", "]": "rbracket", ",": "comma", ":": "colon" };
133
+ if (ch in single) {
134
+ advance();
135
+ push(single[ch], ch, sl, sc);
136
+ continue;
137
+ }
138
+ if (ch === "=") {
139
+ advance();
140
+ push("equals", "=", sl, sc);
141
+ continue;
142
+ }
143
+ if (ch === "+" && peek(1) === "=") {
144
+ advance();
145
+ advance();
146
+ push("plus_equals", "+=", sl, sc);
147
+ continue;
148
+ }
149
+ if (ch === "$" && peek(1) === "{") {
150
+ advance();
151
+ advance();
152
+ const optional = peek() === "?";
153
+ if (optional) advance();
154
+ let path2 = "";
155
+ while (pos < input.length && peek() !== "}") {
156
+ if (peek() === "\n") throw new ParseError("unterminated substitution", sl, sc);
157
+ path2 += advance();
158
+ }
159
+ if (peek() !== "}") throw new ParseError("unterminated substitution", sl, sc);
160
+ advance();
161
+ push(optional ? "opt_subst" : "subst", path2.trim(), sl, sc);
162
+ continue;
163
+ }
164
+ if (ch === '"' && peek(1) === '"' && peek(2) === '"') {
165
+ advance();
166
+ advance();
167
+ advance();
168
+ let value = "";
169
+ while (pos < input.length) {
170
+ if (peek() === '"') {
171
+ let quoteCount = 0;
172
+ while (pos < input.length && peek() === '"') {
173
+ quoteCount++;
174
+ advance();
175
+ }
176
+ if (quoteCount >= 3) {
177
+ for (let i = 0; i < quoteCount - 3; i++) value += '"';
178
+ break;
179
+ }
180
+ for (let i = 0; i < quoteCount; i++) value += '"';
181
+ continue;
182
+ }
183
+ value += advance();
184
+ }
185
+ if (value.startsWith("\n")) value = value.slice(1);
186
+ push("triple_string", value, sl, sc, true);
187
+ continue;
188
+ }
189
+ if (ch === '"') {
190
+ advance();
191
+ let value = "";
192
+ while (pos < input.length && peek() !== '"') {
193
+ if (peek() === "\n") throw new ParseError("unterminated string", sl, sc);
194
+ if (peek() === "\\") {
195
+ advance();
196
+ const esc = advance();
197
+ switch (esc) {
198
+ case "n":
199
+ value += "\n";
200
+ break;
201
+ case "t":
202
+ value += " ";
203
+ break;
204
+ case "r":
205
+ value += "\r";
206
+ break;
207
+ case '"':
208
+ value += '"';
209
+ break;
210
+ case "\\":
211
+ value += "\\";
212
+ break;
213
+ case "/":
214
+ value += "/";
215
+ break;
216
+ case "b":
217
+ value += "\b";
218
+ break;
219
+ case "f":
220
+ value += "\f";
221
+ break;
222
+ case "u": {
223
+ const hex = input.slice(pos, pos + 4);
224
+ value += String.fromCharCode(parseInt(hex, 16));
225
+ for (let i = 0; i < 4; i++) advance();
226
+ break;
227
+ }
228
+ default:
229
+ value += esc;
230
+ }
231
+ } else {
232
+ value += advance();
233
+ }
234
+ }
235
+ if (peek() !== '"') throw new ParseError("unterminated string", sl, sc);
236
+ advance();
237
+ push("string", value, sl, sc, true);
238
+ continue;
239
+ }
240
+ if (isUnquotedStart(ch)) {
241
+ let value = "";
242
+ while (pos < input.length && isUnquotedContinue(peek(), () => peek(1))) {
243
+ value += advance();
244
+ }
245
+ push("unquoted", value.trimEnd(), sl, sc);
246
+ continue;
247
+ }
248
+ throw new ParseError(`unexpected character: ${JSON.stringify(ch)}`, sl, sc);
249
+ }
250
+ tokens.push({ kind: "eof", value: "", line, col, isQuoted: false, precedingSpace: false });
251
+ return tokens;
252
+ }
253
+ function isUnquotedStart(ch) {
254
+ return ch !== "" && !'{}[],:=+#\n\r "$'.includes(ch);
255
+ }
256
+ function isUnquotedContinue(ch, nextFn) {
257
+ if (ch === "" || '{}[],:=\n\r #"$'.includes(ch) || ch === " ") return false;
258
+ if (ch === "+" && nextFn() === "=") return false;
259
+ if (ch === "/" && nextFn() === "/") return false;
260
+ return true;
261
+ }
262
+
263
+ // src/internal/parser/parser.ts
264
+ function parseTokens(tokens) {
265
+ let pos = 0;
266
+ function peek() {
267
+ return tokens[pos] ?? { kind: "eof", value: "", line: 0, col: 0, isQuoted: false, precedingSpace: false };
268
+ }
269
+ function advance() {
270
+ const t2 = tokens[pos];
271
+ if (pos < tokens.length) pos++;
272
+ return t2 ?? { kind: "eof", value: "", line: 0, col: 0, isQuoted: false, precedingSpace: false };
273
+ }
274
+ function skip(...kinds) {
275
+ while (kinds.includes(peek().kind)) advance();
276
+ }
277
+ function currentPos() {
278
+ const t2 = peek();
279
+ return { line: t2.line, col: t2.col };
280
+ }
281
+ function parseObject(expectClosingBrace) {
282
+ const p = currentPos();
283
+ const fields = [];
284
+ while (true) {
285
+ skip("newline");
286
+ const t2 = peek();
287
+ if (t2.kind === "eof" || t2.kind === "rbrace") break;
288
+ if (t2.kind === "unquoted" && t2.value === "include") {
289
+ advance();
290
+ fields.push(parseInclude());
291
+ skip("newline");
292
+ if (peek().kind === "comma") advance();
293
+ skip("newline");
294
+ continue;
295
+ }
296
+ const keyPos = currentPos();
297
+ const key = parseKey();
298
+ skip("newline");
299
+ let append = false;
300
+ const sep = peek();
301
+ if (sep.kind === "equals") advance();
302
+ else if (sep.kind === "plus_equals") {
303
+ advance();
304
+ append = true;
305
+ } else if (sep.kind === "colon") advance();
306
+ else if (sep.kind === "lbrace") {
307
+ } else if (sep.kind !== "newline" && sep.kind !== "eof") {
308
+ throw new ParseError(`unexpected token after key: ${sep.kind}`, sep.line, sep.col);
309
+ }
310
+ skip("newline");
311
+ const value = parseValue();
312
+ fields.push({ key, value, append, pos: keyPos });
313
+ skip("newline");
314
+ if (peek().kind === "comma") advance();
315
+ skip("newline");
316
+ }
317
+ if (expectClosingBrace) {
318
+ const t2 = peek();
319
+ if (t2.kind !== "rbrace") throw new ParseError("expected }", t2.line, t2.col);
320
+ advance();
321
+ }
322
+ return { kind: "object", fields, pos: p };
323
+ }
324
+ function parseKey() {
325
+ const segments = [];
326
+ let trailingDot = false;
327
+ while (true) {
328
+ const t2 = peek();
329
+ if (t2.kind === "string") {
330
+ advance();
331
+ segments.push(t2.value);
332
+ trailingDot = false;
333
+ } else if (t2.kind === "unquoted") {
334
+ advance();
335
+ const parts = t2.value.split(".");
336
+ const filtered = parts.filter((s) => s.length > 0);
337
+ segments.push(...filtered);
338
+ trailingDot = t2.value.endsWith(".");
339
+ } else {
340
+ if (segments.length === 0) throw new ParseError(`expected key, got ${t2.kind}`, t2.line, t2.col);
341
+ break;
342
+ }
343
+ if (trailingDot) continue;
344
+ const next = peek();
345
+ if (next.kind === "unquoted" && next.value === "." && !next.precedingSpace) {
346
+ advance();
347
+ trailingDot = true;
348
+ continue;
349
+ }
350
+ break;
351
+ }
352
+ return segments;
353
+ }
354
+ function parseInclude() {
355
+ const p = currentPos();
356
+ skip("newline");
357
+ const t2 = peek();
358
+ let path2;
359
+ if (t2.kind === "string") {
360
+ path2 = advance().value;
361
+ } else if (t2.kind === "unquoted" && (t2.value === "file(" || t2.value === "file")) {
362
+ advance();
363
+ while (peek().kind !== "string" && peek().kind !== "eof") advance();
364
+ if (peek().kind === "eof") throw new ParseError("expected include path", t2.line, t2.col);
365
+ path2 = advance().value;
366
+ while (peek().kind !== "newline" && peek().kind !== "rbrace" && peek().kind !== "eof") advance();
367
+ } else {
368
+ throw new ParseError(`expected include path, got ${t2.kind}`, t2.line, t2.col);
369
+ }
370
+ return {
371
+ key: [],
372
+ value: { kind: "include", path: path2, pos: p },
373
+ append: false,
374
+ pos: p
375
+ };
376
+ }
377
+ function parseValue() {
378
+ const p = currentPos();
379
+ const parts = [];
380
+ while (true) {
381
+ const t2 = peek();
382
+ if (t2.kind === "eof" || t2.kind === "newline" || t2.kind === "rbrace" || t2.kind === "rbracket" || t2.kind === "comma") break;
383
+ const hadSpace = t2.precedingSpace && parts.length > 0;
384
+ let node;
385
+ if (t2.kind === "lbrace") {
386
+ advance();
387
+ node = parseObject(true);
388
+ } else if (t2.kind === "lbracket") {
389
+ advance();
390
+ node = parseArray();
391
+ } else if (t2.kind === "subst" || t2.kind === "opt_subst") {
392
+ advance();
393
+ node = { kind: "subst", path: t2.value, optional: t2.kind === "opt_subst", pos: { line: t2.line, col: t2.col } };
394
+ } else if (t2.kind === "string" || t2.kind === "triple_string") {
395
+ advance();
396
+ node = { kind: "scalar", value: t2.value, pos: { line: t2.line, col: t2.col } };
397
+ } else if (t2.kind === "unquoted") {
398
+ advance();
399
+ node = { kind: "scalar", value: parseScalarValue(t2.value), pos: { line: t2.line, col: t2.col } };
400
+ } else if ((t2.kind === "colon" || t2.kind === "equals") && parts.length > 0) {
401
+ advance();
402
+ node = { kind: "scalar", value: t2.value, pos: { line: t2.line, col: t2.col } };
403
+ } else {
404
+ break;
405
+ }
406
+ if (hadSpace) {
407
+ parts.push({ kind: "scalar", value: " ", pos: { line: t2.line, col: t2.col } });
408
+ }
409
+ parts.push(node);
410
+ }
411
+ if (parts.length === 0) throw new ParseError("expected value", peek().line, peek().col);
412
+ if (parts.length === 1) return parts[0];
413
+ return { kind: "concat", nodes: parts, pos: p };
414
+ }
415
+ function parseArray() {
416
+ const p = currentPos();
417
+ const items = [];
418
+ while (true) {
419
+ skip("newline");
420
+ if (peek().kind === "rbracket" || peek().kind === "eof") break;
421
+ items.push(parseValue());
422
+ skip("newline");
423
+ if (peek().kind === "comma") advance();
424
+ skip("newline");
425
+ }
426
+ const t2 = peek();
427
+ if (t2.kind !== "rbracket") throw new ParseError("expected ]", t2.line, t2.col);
428
+ advance();
429
+ return { kind: "array", items, pos: p };
430
+ }
431
+ function parseScalarValue(raw) {
432
+ if (raw === "true") return true;
433
+ if (raw === "false") return false;
434
+ if (raw === "null") return null;
435
+ const n = Number(raw);
436
+ if (!isNaN(n) && raw.trim() !== "") return n;
437
+ return raw;
438
+ }
439
+ skip("newline");
440
+ const t = peek();
441
+ if (t.kind === "lbrace") {
442
+ advance();
443
+ return parseObject(true);
444
+ }
445
+ return parseObject(false);
446
+ }
447
+
448
+ // src/internal/resolver/resolver.ts
449
+ var nodePath = __toESM(require("path"), 1);
450
+ function isSubst(v) {
451
+ return v._kind === "subst-placeholder";
452
+ }
453
+ function isConcat(v) {
454
+ return v._kind === "concat-placeholder";
455
+ }
456
+ function isAppend(v) {
457
+ return v._kind === "append-placeholder";
458
+ }
459
+ function isResObj(v) {
460
+ return v._kind === "res-obj";
461
+ }
462
+ function makeResObj() {
463
+ return { _kind: "res-obj", fields: /* @__PURE__ */ new Map(), priorValues: /* @__PURE__ */ new Map() };
464
+ }
465
+ function resolve2(ast, opts) {
466
+ const root = buildResObj(ast, opts);
467
+ const resolving = /* @__PURE__ */ new Set();
468
+ const resolvedCache = /* @__PURE__ */ new Map();
469
+ return resolveResObj(root, root, resolving, resolvedCache, opts);
470
+ }
471
+ function buildResObj(ast, opts) {
472
+ if (ast.kind !== "object") {
473
+ throw new ResolveError("root AST must be an object", "", ast.pos.line, ast.pos.col);
474
+ }
475
+ const obj = makeResObj();
476
+ for (const field of ast.fields) {
477
+ applyField(obj, field, opts);
478
+ }
479
+ return obj;
480
+ }
481
+ function applyField(obj, field, opts) {
482
+ if (field.key.length === 0 && field.value.kind === "include") {
483
+ const included = loadInclude(field.value.path, opts);
484
+ deepMergeResObjInto(obj, included);
485
+ return;
486
+ }
487
+ const [head, ...tail] = field.key;
488
+ if (!head) return;
489
+ if (tail.length > 0) {
490
+ const syntheticAst = {
491
+ kind: "object",
492
+ fields: [{ key: tail, value: field.value, append: field.append, pos: field.pos }],
493
+ pos: field.pos
494
+ };
495
+ applyField(obj, { key: [head], value: syntheticAst, append: false, pos: field.pos }, opts);
496
+ return;
497
+ }
498
+ if (field.append) {
499
+ const existing2 = obj.fields.get(head) ?? { kind: "array", items: [] };
500
+ obj.priorValues.set(head, existing2);
501
+ obj.fields.set(head, {
502
+ _kind: "append-placeholder",
503
+ existing: existing2,
504
+ elem: astToResolverValue(field.value, opts)
505
+ });
506
+ return;
507
+ }
508
+ const existing = obj.fields.get(head);
509
+ const newVal = astToResolverValue(field.value, opts);
510
+ if (existing !== void 0) {
511
+ obj.priorValues.set(head, existing);
512
+ }
513
+ if (existing !== void 0 && isResObj(existing) && isResObj(newVal)) {
514
+ deepMergeResObjInto(existing, newVal);
515
+ return;
516
+ }
517
+ obj.fields.set(head, newVal);
518
+ }
519
+ function astToResolverValue(ast, opts) {
520
+ switch (ast.kind) {
521
+ case "scalar":
522
+ return { kind: "scalar", value: ast.value };
523
+ case "array":
524
+ return { kind: "array", items: ast.items.map((i) => astToResolverValue(i, opts)) };
525
+ case "object": {
526
+ const inner = buildResObj(ast, opts);
527
+ return inner;
528
+ }
529
+ case "subst":
530
+ return { _kind: "subst-placeholder", path: ast.path, optional: ast.optional, line: ast.pos.line, col: ast.pos.col };
531
+ case "concat":
532
+ return { _kind: "concat-placeholder", nodes: ast.nodes.map((n) => astToResolverValue(n, opts)) };
533
+ case "include":
534
+ return { kind: "scalar", value: null };
535
+ }
536
+ }
537
+ function deepMergeResObjInto(dst, src) {
538
+ for (const [k, srcVal] of src.fields) {
539
+ const dstVal = dst.fields.get(k);
540
+ if (dstVal !== void 0 && isResObj(dstVal) && isResObj(srcVal)) {
541
+ deepMergeResObjInto(dstVal, srcVal);
542
+ } else {
543
+ if (dstVal !== void 0) dst.priorValues.set(k, dstVal);
544
+ dst.fields.set(k, srcVal);
545
+ }
546
+ }
547
+ }
548
+ function resolveResObj(obj, root, resolving, resolvedCache, opts) {
549
+ const result = /* @__PURE__ */ new Map();
550
+ for (const [key, val] of obj.fields) {
551
+ const resolved = resolveVal(val, obj, root, resolving, resolvedCache, opts);
552
+ if (resolved !== void 0) {
553
+ result.set(key, resolved);
554
+ } else {
555
+ const prior = obj.priorValues.get(key);
556
+ if (prior !== void 0) {
557
+ const priorResolved = resolveVal(prior, obj, root, resolving, resolvedCache, opts);
558
+ if (priorResolved !== void 0) result.set(key, priorResolved);
559
+ }
560
+ }
561
+ }
562
+ return { kind: "object", fields: result };
563
+ }
564
+ function resolveVal(v, scope, root, resolving, resolvedCache, opts) {
565
+ if (isSubst(v)) return resolveSubst(v, scope, root, resolving, resolvedCache, opts);
566
+ if (isConcat(v)) return resolveConcat(v.nodes, scope, root, resolving, resolvedCache, opts);
567
+ if (isAppend(v)) return resolveAppend(v, scope, root, resolving, resolvedCache, opts);
568
+ if (isResObj(v)) return resolveResObj(v, root, resolving, resolvedCache, opts);
569
+ const hv = v;
570
+ if (hv.kind === "array") {
571
+ return {
572
+ kind: "array",
573
+ items: hv.items.map(
574
+ (item) => resolveVal(item, scope, root, resolving, resolvedCache, opts) ?? { kind: "scalar", value: null }
575
+ )
576
+ };
577
+ }
578
+ return hv;
579
+ }
580
+ function resolveSubst(s, scope, root, resolving, resolvedCache, opts) {
581
+ if (resolvedCache.has(s.path)) return resolvedCache.get(s.path);
582
+ if (resolving.has(s.path)) {
583
+ const rootSeg = parseSubstPath(s.path)[0] ?? "";
584
+ const prior = scope.priorValues.get(rootSeg) ?? root.priorValues.get(rootSeg);
585
+ if (prior !== void 0) {
586
+ return resolveVal(prior, scope, root, new Set(resolving), resolvedCache, opts);
587
+ }
588
+ if (s.optional) return void 0;
589
+ throw new ResolveError(`circular substitution: ${s.path}`, s.path, s.line, s.col);
590
+ }
591
+ resolving.add(s.path);
592
+ try {
593
+ const found = lookupPath(root, parseSubstPath(s.path));
594
+ if (found !== void 0) {
595
+ if (isSubst(found) || isConcat(found)) {
596
+ const rootSeg = parseSubstPath(s.path)[0] ?? "";
597
+ const prior = scope.priorValues.get(rootSeg) ?? root.priorValues.get(rootSeg);
598
+ if (prior !== void 0) {
599
+ const result2 = resolveVal(prior, scope, root, resolving, resolvedCache, opts);
600
+ if (result2 !== void 0) resolvedCache.set(s.path, result2);
601
+ return result2;
602
+ }
603
+ }
604
+ const result = resolveVal(found, scope, root, resolving, resolvedCache, opts);
605
+ if (result !== void 0) resolvedCache.set(s.path, result);
606
+ return result;
607
+ }
608
+ const envVal = opts.env[s.path];
609
+ if (envVal !== void 0) {
610
+ const result = { kind: "scalar", value: envVal };
611
+ resolvedCache.set(s.path, result);
612
+ return result;
613
+ }
614
+ if (s.optional) return void 0;
615
+ throw new ResolveError(`could not resolve substitution: \${${s.path}}`, s.path, s.line, s.col);
616
+ } finally {
617
+ resolving.delete(s.path);
618
+ }
619
+ }
620
+ function resolveConcat(nodes, scope, root, resolving, resolvedCache, opts) {
621
+ const resolved = nodes.map((n) => resolveVal(n, scope, root, resolving, resolvedCache, opts)).filter((v) => v !== void 0);
622
+ if (resolved.length === 0) return { kind: "scalar", value: null };
623
+ if (resolved.length === 1) return resolved[0];
624
+ if (resolved.every((v) => v.kind === "object")) {
625
+ const merged = /* @__PURE__ */ new Map();
626
+ for (const v of resolved) {
627
+ if (v.kind === "object") {
628
+ for (const [k, val] of v.fields) {
629
+ merged.set(k, val);
630
+ }
631
+ }
632
+ }
633
+ return { kind: "object", fields: merged };
634
+ }
635
+ if (resolved.some((v) => v.kind === "array")) {
636
+ const items = [];
637
+ for (const v of resolved) {
638
+ if (v.kind === "array") items.push(...v.items);
639
+ else items.push(v);
640
+ }
641
+ return { kind: "array", items };
642
+ }
643
+ const str = resolved.map((v) => v.kind === "scalar" ? String(v.value) : JSON.stringify(v)).join("");
644
+ return { kind: "scalar", value: str };
645
+ }
646
+ function resolveAppend(a, scope, root, resolving, resolvedCache, opts) {
647
+ const existing = resolveVal(a.existing, scope, root, resolving, resolvedCache, opts) ?? { kind: "array", items: [] };
648
+ const elem = resolveVal(a.elem, scope, root, resolving, resolvedCache, opts);
649
+ const items = existing.kind === "array" ? [...existing.items] : [existing];
650
+ if (elem !== void 0) items.push(elem);
651
+ return { kind: "array", items };
652
+ }
653
+ function lookupPath(root, segments) {
654
+ const [head, ...tail] = segments;
655
+ if (head === void 0 || head === "") {
656
+ if (segments.length > 0) {
657
+ const val2 = root.fields.get("");
658
+ if (val2 === void 0) return void 0;
659
+ if (tail.length === 0) return val2;
660
+ if (isResObj(val2)) return lookupPath(val2, tail);
661
+ return void 0;
662
+ }
663
+ return void 0;
664
+ }
665
+ const val = root.fields.get(head);
666
+ if (val === void 0) return void 0;
667
+ if (tail.length === 0) return val;
668
+ if (isResObj(val)) return lookupPath(val, tail);
669
+ return void 0;
670
+ }
671
+ function parseSubstPath(raw) {
672
+ const segments = [];
673
+ let i = 0;
674
+ while (i < raw.length) {
675
+ while (i < raw.length && (raw[i] === " " || raw[i] === " ")) i++;
676
+ if (i >= raw.length) break;
677
+ if (raw[i] === '"') {
678
+ i++;
679
+ let seg = "";
680
+ while (i < raw.length && raw[i] !== '"') {
681
+ seg += raw[i];
682
+ i++;
683
+ }
684
+ if (i < raw.length) i++;
685
+ segments.push(seg);
686
+ while (i < raw.length && (raw[i] === " " || raw[i] === " ")) i++;
687
+ if (i < raw.length && raw[i] === ".") i++;
688
+ } else if (raw[i] === ".") {
689
+ segments.push("");
690
+ i++;
691
+ } else {
692
+ let seg = "";
693
+ while (i < raw.length && raw[i] !== ".") {
694
+ seg += raw[i];
695
+ i++;
696
+ }
697
+ segments.push(seg.trim());
698
+ if (i < raw.length && raw[i] === ".") i++;
699
+ }
700
+ }
701
+ return segments;
702
+ }
703
+ function loadInclude(includePath, opts) {
704
+ const { baseDir, readFileSync: readFileSync2, includeStack = [], env } = opts;
705
+ const absPath = baseDir ? nodePath.resolve(baseDir, includePath) : nodePath.resolve(includePath);
706
+ if (includeStack.includes(absPath)) {
707
+ throw new ResolveError(`circular include: ${absPath}`, absPath, 0, 0);
708
+ }
709
+ const candidates = [absPath];
710
+ if (!absPath.endsWith(".conf") && !absPath.endsWith(".json") && !absPath.endsWith(".properties")) {
711
+ candidates.push(absPath + ".conf", absPath + ".json");
712
+ }
713
+ for (const candidate of candidates) {
714
+ let content;
715
+ try {
716
+ content = readFileSync2(candidate);
717
+ } catch {
718
+ continue;
719
+ }
720
+ if (includeStack.includes(candidate)) {
721
+ throw new ResolveError(`circular include: ${candidate}`, candidate, 0, 0);
722
+ }
723
+ const ast = parseTokens(tokenize(content));
724
+ return buildResObj(ast, {
725
+ env,
726
+ baseDir: nodePath.dirname(candidate),
727
+ readFileSync: readFileSync2,
728
+ includeStack: [...includeStack, candidate]
729
+ });
730
+ }
731
+ return makeResObj();
732
+ }
733
+
734
+ // src/config.ts
735
+ var Config = class _Config {
736
+ constructor(root) {
737
+ this.root = root;
738
+ }
739
+ get(path2) {
740
+ const v = this.lookupNode(path2);
741
+ if (v === void 0) return void 0;
742
+ return hoconToJs(v);
743
+ }
744
+ getString(path2) {
745
+ const v = this.requireScalar(path2);
746
+ if (typeof v !== "string") throw new ConfigError(`expected string at ${path2}, got ${typeof v}`, path2);
747
+ return v;
748
+ }
749
+ getNumber(path2) {
750
+ const v = this.requireScalar(path2);
751
+ if (typeof v === "number") return v;
752
+ if (typeof v === "string") {
753
+ const coerced = coerceNumber(v);
754
+ if (coerced !== void 0) return coerced;
755
+ }
756
+ throw new ConfigError(`expected number at ${path2}, got ${typeof v}`, path2);
757
+ }
758
+ getBoolean(path2) {
759
+ const v = this.requireScalar(path2);
760
+ if (typeof v === "boolean") return v;
761
+ if (typeof v === "string") {
762
+ const coerced = coerceBoolean(v);
763
+ if (coerced !== void 0) return coerced;
764
+ }
765
+ throw new ConfigError(`expected boolean at ${path2}, got ${typeof v}`, path2);
766
+ }
767
+ getConfig(path2) {
768
+ const v = this.lookupNode(path2);
769
+ if (v === void 0) throw new ConfigError(`path not found: ${path2}`, path2);
770
+ if (v.kind !== "object") throw new ConfigError(`expected object at ${path2}`, path2);
771
+ return new _Config(v);
772
+ }
773
+ getList(path2) {
774
+ const v = this.lookupNode(path2);
775
+ if (v === void 0) throw new ConfigError(`path not found: ${path2}`, path2);
776
+ if (v.kind !== "array") throw new ConfigError(`expected array at ${path2}`, path2);
777
+ return v.items.map(hoconToJs);
778
+ }
779
+ has(path2) {
780
+ return this.lookupNode(path2) !== void 0;
781
+ }
782
+ keys() {
783
+ return [...this.root.fields.keys()];
784
+ }
785
+ withFallback(fallback) {
786
+ const merged = deepMergeHocon(this.root, fallback.root);
787
+ return new _Config(merged);
788
+ }
789
+ toObject() {
790
+ return hoconToJs(this.root);
791
+ }
792
+ lookupNode(path2) {
793
+ const segments = path2.split(".");
794
+ let current = this.root;
795
+ for (const seg of segments) {
796
+ if (current.kind !== "object") return void 0;
797
+ const next = current.fields.get(seg);
798
+ if (next === void 0) return void 0;
799
+ current = next;
800
+ }
801
+ return current;
802
+ }
803
+ requireScalar(path2) {
804
+ const v = this.lookupNode(path2);
805
+ if (v === void 0) throw new ConfigError(`path not found: ${path2}`, path2);
806
+ if (v.kind !== "scalar") throw new ConfigError(`expected scalar at ${path2}, got ${v.kind}`, path2);
807
+ return v.value;
808
+ }
809
+ };
810
+ function hoconToJs(v) {
811
+ switch (v.kind) {
812
+ case "scalar":
813
+ return v.value;
814
+ case "array":
815
+ return v.items.map(hoconToJs);
816
+ case "object": {
817
+ const obj = {};
818
+ for (const [k, val] of v.fields) obj[k] = hoconToJs(val);
819
+ return obj;
820
+ }
821
+ }
822
+ }
823
+ function deepMergeHocon(receiver, fallback) {
824
+ const merged = new Map(fallback.fields);
825
+ for (const [k, v] of receiver.fields) {
826
+ const fb = merged.get(k);
827
+ if (fb?.kind === "object" && v.kind === "object") {
828
+ merged.set(k, deepMergeHocon(v, fb));
829
+ } else {
830
+ merged.set(k, v);
831
+ }
832
+ }
833
+ return { kind: "object", fields: merged };
834
+ }
835
+
836
+ // src/parse.ts
837
+ var fs = __toESM(require("fs"), 1);
838
+ var path = __toESM(require("path"), 1);
839
+ function getEnv(opts) {
840
+ if (opts.env !== void 0) return opts.env;
841
+ if (typeof process !== "undefined" && process.env) return process.env;
842
+ return {};
843
+ }
844
+ function defaultReadFileSync(filePath) {
845
+ return fs.readFileSync(filePath, "utf-8");
846
+ }
847
+ function parse(input, opts = {}) {
848
+ const tokens = tokenize(input);
849
+ const ast = parseTokens(tokens);
850
+ const resolveOpts = {
851
+ env: getEnv(opts),
852
+ baseDir: opts.baseDir,
853
+ readFileSync: opts.readFileSync ?? defaultReadFileSync
854
+ };
855
+ const value = resolve2(ast, resolveOpts);
856
+ if (value.kind !== "object") throw new Error("resolved value is not an object");
857
+ return new Config(value);
858
+ }
859
+ function parseFile(filePath, opts = {}) {
860
+ if (typeof process === "undefined" && !opts.readFileSync) {
861
+ throw new Error("parseFile is not supported in browser environments. Provide opts.readFileSync or use parse() instead.");
862
+ }
863
+ const resolvedPath = path.resolve(filePath);
864
+ const readFileSync2 = opts.readFileSync ?? defaultReadFileSync;
865
+ const input = readFileSync2(resolvedPath);
866
+ return parse(input, {
867
+ ...opts,
868
+ baseDir: opts.baseDir ?? path.dirname(resolvedPath),
869
+ readFileSync: readFileSync2
870
+ });
871
+ }
872
+
873
+ // src/zod.ts
27
874
  function validate(config, schema) {
28
875
  const plain = config.toObject();
29
- return schema.parse(plain);
876
+ const coerced = coerceValue(plain, schema);
877
+ return schema.parse(coerced);
878
+ }
879
+ function getValidated(config, path2, schema) {
880
+ const val = config.get(path2);
881
+ const coerced = coerceValue(val, schema);
882
+ return schema.parse(coerced);
883
+ }
884
+ function getDefType(schema) {
885
+ const zod = schema._zod;
886
+ return zod?.def?.type;
30
887
  }
31
- function getValidated(config, path, schema) {
32
- const val = config.get(path);
33
- return schema.parse(val);
888
+ function getInnerSchema(schema) {
889
+ const def = schema._zod?.def;
890
+ return def?.innerType ?? def?.schema;
891
+ }
892
+ function getObjectShape(schema) {
893
+ const shape = schema._zod?.def?.shape;
894
+ return typeof shape === "object" && shape !== null ? shape : void 0;
895
+ }
896
+ function getArrayElement(schema) {
897
+ return schema._zod?.def?.element;
898
+ }
899
+ function parseWithSchema(input, schema, opts) {
900
+ const config = parse(input, opts);
901
+ return validate(config, schema);
902
+ }
903
+ function parseFileWithSchema(filePath, schema, opts) {
904
+ const config = parseFile(filePath, opts);
905
+ return validate(config, schema);
906
+ }
907
+ function coerceValue(value, schema) {
908
+ if (value === null || value === void 0) return value;
909
+ const defType = getDefType(schema);
910
+ if (!defType) return value;
911
+ switch (defType) {
912
+ case "boolean":
913
+ if (typeof value === "string") {
914
+ const coerced = coerceBoolean(value);
915
+ return coerced !== void 0 ? coerced : value;
916
+ }
917
+ return value;
918
+ case "number":
919
+ if (typeof value === "string") {
920
+ const coerced = coerceNumber(value);
921
+ return coerced !== void 0 ? coerced : value;
922
+ }
923
+ return value;
924
+ case "object": {
925
+ if (typeof value !== "object" || Array.isArray(value)) return value;
926
+ const shape = getObjectShape(schema);
927
+ if (!shape) return value;
928
+ const obj = value;
929
+ const result = { ...obj };
930
+ for (const key of Object.keys(shape)) {
931
+ if (key in obj) {
932
+ result[key] = coerceValue(obj[key], shape[key]);
933
+ }
934
+ }
935
+ return result;
936
+ }
937
+ case "array": {
938
+ if (!Array.isArray(value)) return value;
939
+ const elementSchema = getArrayElement(schema);
940
+ if (!elementSchema) return value;
941
+ return value.map((item) => coerceValue(item, elementSchema));
942
+ }
943
+ case "optional":
944
+ case "nullable":
945
+ case "default":
946
+ case "catch":
947
+ case "readonly": {
948
+ const inner = getInnerSchema(schema);
949
+ return inner ? coerceValue(value, inner) : value;
950
+ }
951
+ default:
952
+ return value;
953
+ }
34
954
  }
35
955
  // Annotate the CommonJS export names for ESM import in node:
36
956
  0 && (module.exports = {
37
957
  getValidated,
958
+ parseFileWithSchema,
959
+ parseWithSchema,
38
960
  validate
39
961
  });