@o3co/ts.hocon 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -6
- package/dist/config-BwjvKeZ5.d.cts +271 -0
- package/dist/config-BwjvKeZ5.d.ts +271 -0
- package/dist/index.cjs +1105 -360
- package/dist/index.d.cts +45 -2
- package/dist/index.d.ts +45 -2
- package/dist/index.js +1094 -359
- package/dist/zod.cjs +823 -198
- package/dist/zod.d.cts +1 -1
- package/dist/zod.d.ts +1 -1
- package/dist/zod.js +822 -198
- package/package.json +3 -1
- package/dist/parse-nNbyqnOh.d.cts +0 -53
- package/dist/parse-nNbyqnOh.d.ts +0 -53
package/dist/zod.cjs
CHANGED
|
@@ -234,6 +234,10 @@ function parseBytes(value, outputUnit = "B") {
|
|
|
234
234
|
return outputUnit === "B" ? Math.round(result) : result;
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
+
// src/parse.ts
|
|
238
|
+
var fs = __toESM(require("fs"), 1);
|
|
239
|
+
var path = __toESM(require("path"), 1);
|
|
240
|
+
|
|
237
241
|
// src/errors.ts
|
|
238
242
|
var ParseError = class extends Error {
|
|
239
243
|
constructor(message, line, col, file) {
|
|
@@ -254,6 +258,14 @@ var ResolveError = class extends Error {
|
|
|
254
258
|
this.name = "ResolveError";
|
|
255
259
|
}
|
|
256
260
|
};
|
|
261
|
+
var PackageLookupError = class extends ResolveError {
|
|
262
|
+
constructor(message, identifier, packageFile, line, col) {
|
|
263
|
+
super(message, `${identifier}/${packageFile}`, line, col);
|
|
264
|
+
this.identifier = identifier;
|
|
265
|
+
this.packageFile = packageFile;
|
|
266
|
+
this.name = "PackageLookupError";
|
|
267
|
+
}
|
|
268
|
+
};
|
|
257
269
|
var ConfigError = class extends Error {
|
|
258
270
|
constructor(message, path2) {
|
|
259
271
|
super(message);
|
|
@@ -261,6 +273,156 @@ var ConfigError = class extends Error {
|
|
|
261
273
|
this.name = "ConfigError";
|
|
262
274
|
}
|
|
263
275
|
};
|
|
276
|
+
var NotResolvedError = class extends ConfigError {
|
|
277
|
+
constructor(path2) {
|
|
278
|
+
super(`value at path "${path2}" is not resolved (call resolve() first)`, path2);
|
|
279
|
+
this.name = "NotResolvedError";
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
// src/internal/resolver/types.ts
|
|
284
|
+
var separatorValues = /* @__PURE__ */ new WeakSet();
|
|
285
|
+
function isSubst(v) {
|
|
286
|
+
return v._kind === "subst-placeholder";
|
|
287
|
+
}
|
|
288
|
+
function isConcat(v) {
|
|
289
|
+
return v._kind === "concat-placeholder";
|
|
290
|
+
}
|
|
291
|
+
function isAppend(v) {
|
|
292
|
+
return v._kind === "append-placeholder";
|
|
293
|
+
}
|
|
294
|
+
function isResObj(v) {
|
|
295
|
+
return v._kind === "res-obj";
|
|
296
|
+
}
|
|
297
|
+
function makeResObj() {
|
|
298
|
+
return { _kind: "res-obj", fields: /* @__PURE__ */ new Map(), priorValues: /* @__PURE__ */ new Map() };
|
|
299
|
+
}
|
|
300
|
+
function mergeUnresolved(receiver, fallback) {
|
|
301
|
+
const result = makeResObj();
|
|
302
|
+
for (const [k, v] of fallback.fields) {
|
|
303
|
+
result.fields.set(k, v);
|
|
304
|
+
}
|
|
305
|
+
for (const [k, v] of fallback.priorValues) {
|
|
306
|
+
result.priorValues.set(k, v);
|
|
307
|
+
}
|
|
308
|
+
for (const [k, rv] of receiver.fields) {
|
|
309
|
+
const existing = result.fields.get(k);
|
|
310
|
+
if (existing !== void 0) {
|
|
311
|
+
const recPrior = receiver.priorValues.get(k);
|
|
312
|
+
if (recPrior !== void 0 && !isResObj(recPrior)) {
|
|
313
|
+
result.fields.set(k, rv);
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
if (isResObj(rv) && isResObj(existing)) {
|
|
317
|
+
result.fields.set(k, mergeUnresolved(rv, existing));
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
result.priorValues.set(k, existing);
|
|
321
|
+
}
|
|
322
|
+
result.fields.set(k, rv);
|
|
323
|
+
}
|
|
324
|
+
for (const [k, v] of receiver.priorValues) {
|
|
325
|
+
if (receiver.fields.has(k)) {
|
|
326
|
+
result.priorValues.set(k, v);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return result;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// src/internal/resolver/utils.ts
|
|
333
|
+
function segmentsToKey(segments) {
|
|
334
|
+
return segments.map((s) => {
|
|
335
|
+
const t = s.text;
|
|
336
|
+
if (t === "" || /[^a-zA-Z0-9\-_]/.test(t)) {
|
|
337
|
+
return `"${t.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
338
|
+
}
|
|
339
|
+
return t;
|
|
340
|
+
}).join(".");
|
|
341
|
+
}
|
|
342
|
+
function lookupPath(root, segments) {
|
|
343
|
+
const [head, ...tail] = segments;
|
|
344
|
+
if (head === void 0) return void 0;
|
|
345
|
+
const key = head.text;
|
|
346
|
+
const val = root.fields.get(key);
|
|
347
|
+
if (val === void 0) return void 0;
|
|
348
|
+
if (tail.length === 0) return val;
|
|
349
|
+
if (isResObj(val)) return lookupPath(val, tail);
|
|
350
|
+
return void 0;
|
|
351
|
+
}
|
|
352
|
+
function lookupResObj(root, segments) {
|
|
353
|
+
let cur = root;
|
|
354
|
+
for (const seg of segments) {
|
|
355
|
+
const val = cur.fields.get(seg.text);
|
|
356
|
+
if (val === void 0 || !isResObj(val)) return void 0;
|
|
357
|
+
cur = val;
|
|
358
|
+
}
|
|
359
|
+
return cur;
|
|
360
|
+
}
|
|
361
|
+
function deepMergeHoconValues(base, overlay) {
|
|
362
|
+
const merged = new Map(base.fields);
|
|
363
|
+
for (const [k, v] of overlay.fields) {
|
|
364
|
+
const existing = merged.get(k);
|
|
365
|
+
if (existing?.kind === "object" && v.kind === "object") {
|
|
366
|
+
merged.set(k, deepMergeHoconValues(existing, v));
|
|
367
|
+
} else {
|
|
368
|
+
merged.set(k, v);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return { kind: "object", fields: merged };
|
|
372
|
+
}
|
|
373
|
+
function deepMergeResObjInto(dst, src) {
|
|
374
|
+
for (const [k, srcVal] of src.fields) {
|
|
375
|
+
const dstVal = dst.fields.get(k);
|
|
376
|
+
if (dstVal !== void 0 && isResObj(dstVal) && isResObj(srcVal)) {
|
|
377
|
+
deepMergeResObjInto(dstVal, srcVal);
|
|
378
|
+
} else {
|
|
379
|
+
if (dstVal !== void 0) dst.priorValues.set(k, dstVal);
|
|
380
|
+
dst.fields.set(k, srcVal);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
for (const [k, srcPrior] of src.priorValues) {
|
|
384
|
+
if (!dst.priorValues.has(k)) {
|
|
385
|
+
dst.priorValues.set(k, srcPrior);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
function hoconValueToResObj(hv) {
|
|
390
|
+
const obj = makeResObj();
|
|
391
|
+
if (hv.kind !== "object") return obj;
|
|
392
|
+
for (const [key, val] of hv.fields) {
|
|
393
|
+
if (val.kind === "object") {
|
|
394
|
+
obj.fields.set(key, hoconValueToResObj(val));
|
|
395
|
+
} else {
|
|
396
|
+
obj.fields.set(key, val);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return obj;
|
|
400
|
+
}
|
|
401
|
+
function isFileNotFoundError(e) {
|
|
402
|
+
if (!(e instanceof Error)) return false;
|
|
403
|
+
const code = e.code;
|
|
404
|
+
if (code === "ENOENT" || code === "MODULE_NOT_FOUND") return true;
|
|
405
|
+
const msg = e.message.toLowerCase();
|
|
406
|
+
return msg.includes("not found") || msg.includes("no such file") || msg.includes("enoent");
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// src/internal/resolver/include-loader.ts
|
|
410
|
+
var import_node_module = require("module");
|
|
411
|
+
var nodePath = __toESM(require("path"), 1);
|
|
412
|
+
|
|
413
|
+
// src/internal/parser/empty-check.ts
|
|
414
|
+
function hasContentTokens(tokens) {
|
|
415
|
+
return tokens.some((t) => t.kind !== "eof" && t.kind !== "newline");
|
|
416
|
+
}
|
|
417
|
+
function assertNonEmptyDocument(tokens, sourceDescriptor) {
|
|
418
|
+
if (!hasContentTokens(tokens)) {
|
|
419
|
+
throw new ParseError(
|
|
420
|
+
`empty file is not a valid HOCON document (HOCON.md L130): ${sourceDescriptor}`,
|
|
421
|
+
1,
|
|
422
|
+
1
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
264
426
|
|
|
265
427
|
// src/internal/lexer/lexer.ts
|
|
266
428
|
function isHoconWhitespace(ch) {
|
|
@@ -825,58 +987,137 @@ var Parser = class {
|
|
|
825
987
|
const p = this.currentPos();
|
|
826
988
|
this.skip("newline");
|
|
827
989
|
const t = this.peek();
|
|
828
|
-
let path2;
|
|
829
|
-
let required = false;
|
|
830
|
-
let isFile = false;
|
|
831
990
|
if (t.kind === "unquoted" && (t.value === "required(" || t.value === "required" || t.value.startsWith("required("))) {
|
|
832
991
|
if (t.value === "required") {
|
|
833
|
-
const
|
|
834
|
-
if (
|
|
992
|
+
const next = this.peek(1);
|
|
993
|
+
if (next.kind !== "unquoted" || !next.value.startsWith("(")) {
|
|
835
994
|
throw new ParseError("include required must be followed by (", t.line, t.col);
|
|
836
995
|
}
|
|
837
996
|
}
|
|
838
|
-
required = true;
|
|
839
997
|
this.advance();
|
|
840
998
|
const innerPrefix = t.value.startsWith("required(") ? t.value.slice("required(".length) : "";
|
|
841
|
-
if (innerPrefix.startsWith("url") || innerPrefix.startsWith("classpath")) {
|
|
999
|
+
if (innerPrefix === "url" || innerPrefix.startsWith("url(") || innerPrefix === "classpath" || innerPrefix.startsWith("classpath(")) {
|
|
842
1000
|
throw new ParseError("include url(...) and classpath(...) are not supported", t.line, t.col);
|
|
843
1001
|
}
|
|
844
|
-
|
|
845
|
-
|
|
1002
|
+
const nextTok = this.peek();
|
|
1003
|
+
if (innerPrefix === "package" || innerPrefix.startsWith("package(") || innerPrefix === "" && nextTok.kind === "unquoted" && (nextTok.value === "package(" || nextTok.value.startsWith("package("))) {
|
|
1004
|
+
const consumePackageToken = innerPrefix === "";
|
|
1005
|
+
const { qualifier, path: path3 } = this.parsePackageArgs(consumePackageToken);
|
|
1006
|
+
return this.makeIncludeField(qualifier, path3, true, p);
|
|
846
1007
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
1008
|
+
if (innerPrefix === "file" || innerPrefix.startsWith("file(") || innerPrefix === "" && nextTok.kind === "unquoted" && (nextTok.value === "file(" || nextTok.value === "file")) {
|
|
1009
|
+
if (innerPrefix === "") {
|
|
1010
|
+
this.advance();
|
|
1011
|
+
}
|
|
1012
|
+
const path3 = this.parseQuotedPathSkipWrapper(t);
|
|
1013
|
+
return this.makeIncludeField({ kind: "file" }, path3, true, p);
|
|
1014
|
+
}
|
|
1015
|
+
if (innerPrefix === "" && nextTok.kind === "unquoted" && (nextTok.value === "url" || nextTok.value.startsWith("url(") || nextTok.value === "classpath" || nextTok.value.startsWith("classpath("))) {
|
|
1016
|
+
throw new ParseError("include url(...) and classpath(...) are not supported", nextTok.line, nextTok.col);
|
|
1017
|
+
}
|
|
1018
|
+
if (innerPrefix !== "") {
|
|
1019
|
+
if (innerPrefix === ")") {
|
|
1020
|
+
throw new ParseError("include required(...) must contain a path", t.line, t.col);
|
|
1021
|
+
}
|
|
1022
|
+
const name = innerPrefix.replace(/\(.*$/, "").replace(/\).*$/, "");
|
|
1023
|
+
throw new ParseError(`unknown include qualifier inside required(): "${name}"`, t.line, t.col);
|
|
1024
|
+
}
|
|
1025
|
+
const path2 = this.parseQuotedPathSkipWrapper(t);
|
|
1026
|
+
return this.makeIncludeField({ kind: "bare" }, path2, true, p);
|
|
1027
|
+
}
|
|
1028
|
+
if (t.kind === "string") {
|
|
1029
|
+
const path2 = this.advance().value;
|
|
1030
|
+
return this.makeIncludeField({ kind: "bare" }, path2, false, p);
|
|
1031
|
+
}
|
|
1032
|
+
if (t.kind === "unquoted" && (t.value === "file(" || t.value === "file")) {
|
|
862
1033
|
this.advance();
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
1034
|
+
const path2 = this.parseQuotedPathSkipWrapper(t);
|
|
1035
|
+
return this.makeIncludeField({ kind: "file" }, path2, false, p);
|
|
1036
|
+
}
|
|
1037
|
+
if (t.kind === "unquoted" && (t.value === "package(" || t.value.startsWith("package("))) {
|
|
1038
|
+
const { qualifier, path: path2 } = this.parsePackageArgs();
|
|
1039
|
+
return this.makeIncludeField(qualifier, path2, false, p);
|
|
1040
|
+
}
|
|
1041
|
+
if (t.kind === "unquoted" && (t.value === "url" || t.value.startsWith("url("))) {
|
|
868
1042
|
throw new ParseError("include url(...) is not supported", t.line, t.col);
|
|
869
|
-
}
|
|
1043
|
+
}
|
|
1044
|
+
if (t.kind === "unquoted" && (t.value === "classpath" || t.value.startsWith("classpath("))) {
|
|
870
1045
|
throw new ParseError("include classpath(...) is not supported", t.line, t.col);
|
|
871
|
-
} else {
|
|
872
|
-
throw new ParseError(`expected include path, got ${t.kind}`, t.line, t.col);
|
|
873
1046
|
}
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
1047
|
+
throw new ParseError(`expected include path, got ${t.kind}`, t.line, t.col);
|
|
1048
|
+
}
|
|
1049
|
+
makeIncludeField(qualifier, path2, required, pos) {
|
|
1050
|
+
return { key: [], value: { kind: "include", qualifier, path: path2, required, pos }, append: false, pos };
|
|
1051
|
+
}
|
|
1052
|
+
/**
|
|
1053
|
+
* Skip past include-syntax wrapper tokens to find the quoted path string.
|
|
1054
|
+
* Strict: only allows `(`, `)`, and bare qualifier keywords (file / file( /
|
|
1055
|
+
* package / package( / url / url( / classpath / classpath() between the
|
|
1056
|
+
* directive and the quoted path. Anything else is a parse error rather than
|
|
1057
|
+
* silently swallowed (see ts#113).
|
|
1058
|
+
*/
|
|
1059
|
+
parseQuotedPathSkipWrapper(errTok) {
|
|
1060
|
+
while (this.isIncludeWrapperToken(this.peek())) this.advance();
|
|
1061
|
+
if (this.peek().kind !== "string") {
|
|
1062
|
+
const tok = this.peek();
|
|
1063
|
+
if (tok.kind === "eof") throw new ParseError("expected include path", errTok.line, errTok.col);
|
|
1064
|
+
const desc = tok.kind === "unquoted" ? `unquoted "${tok.value}"` : tok.kind;
|
|
1065
|
+
throw new ParseError(`expected quoted include path, got ${desc}`, tok.line, tok.col);
|
|
1066
|
+
}
|
|
1067
|
+
const path2 = this.advance().value;
|
|
1068
|
+
while (this.peek().kind === "unquoted" && (this.peek().value === ")" || this.peek().value === "))")) {
|
|
1069
|
+
this.advance();
|
|
1070
|
+
}
|
|
1071
|
+
const after = this.peek();
|
|
1072
|
+
if (after.kind !== "newline" && after.kind !== "rbrace" && after.kind !== "eof" && after.kind !== "comma") {
|
|
1073
|
+
const desc = after.kind === "unquoted" ? `unquoted "${after.value}"` : after.kind;
|
|
1074
|
+
throw new ParseError(`unexpected token after include path: ${desc}`, after.line, after.col);
|
|
1075
|
+
}
|
|
1076
|
+
return path2;
|
|
1077
|
+
}
|
|
1078
|
+
isIncludeWrapperToken(tok) {
|
|
1079
|
+
return tok.kind === "unquoted" && tok.value === "(";
|
|
1080
|
+
}
|
|
1081
|
+
/**
|
|
1082
|
+
* Parse the body of `package("identifier", "file")`.
|
|
1083
|
+
*
|
|
1084
|
+
* @param consumePackageToken - When true (default), the current token is `package(` and
|
|
1085
|
+
* must be consumed first. When false, the lexer already bundled `package(` into the
|
|
1086
|
+
* preceding token (e.g. `required(package("`), so we are already positioned at the
|
|
1087
|
+
* first string argument.
|
|
1088
|
+
*/
|
|
1089
|
+
parsePackageArgs(consumePackageToken = true) {
|
|
1090
|
+
const pkgTok = consumePackageToken ? this.advance() : this.peek();
|
|
1091
|
+
this.skip("newline");
|
|
1092
|
+
const idTok = this.peek();
|
|
1093
|
+
if (idTok.kind !== "string") {
|
|
1094
|
+
throw new ParseError("include package: expected quoted identifier as first argument", pkgTok.line, pkgTok.col);
|
|
1095
|
+
}
|
|
1096
|
+
const identifier = this.advance().value;
|
|
1097
|
+
this.skip("newline");
|
|
1098
|
+
if (this.peek().kind !== "comma") {
|
|
1099
|
+
const after = this.peek();
|
|
1100
|
+
throw new ParseError(
|
|
1101
|
+
after.kind === "string" ? "include package: missing comma between identifier and file arguments" : "include package: requires exactly two arguments (identifier, file) \u2014 one-arg form is not supported",
|
|
1102
|
+
pkgTok.line,
|
|
1103
|
+
pkgTok.col
|
|
1104
|
+
);
|
|
1105
|
+
}
|
|
1106
|
+
this.advance();
|
|
1107
|
+
this.skip("newline");
|
|
1108
|
+
const fileTok = this.peek();
|
|
1109
|
+
if (fileTok.kind !== "string") {
|
|
1110
|
+
throw new ParseError(
|
|
1111
|
+
"include package: requires exactly two arguments (identifier, file) \u2014 one-arg form is not supported",
|
|
1112
|
+
pkgTok.line,
|
|
1113
|
+
pkgTok.col
|
|
1114
|
+
);
|
|
1115
|
+
}
|
|
1116
|
+
const filePath = this.advance().value;
|
|
1117
|
+
while (this.peek().kind !== "newline" && this.peek().kind !== "rbrace" && this.peek().kind !== "eof" && this.peek().kind !== "comma") {
|
|
1118
|
+
this.advance();
|
|
1119
|
+
}
|
|
1120
|
+
return { qualifier: { kind: "package", identifier }, path: filePath };
|
|
880
1121
|
}
|
|
881
1122
|
parseValue() {
|
|
882
1123
|
const p = this.currentPos();
|
|
@@ -917,7 +1158,9 @@ var Parser = class {
|
|
|
917
1158
|
parts.push(node);
|
|
918
1159
|
}
|
|
919
1160
|
if (parts.length === 0) throw new ParseError("expected value", this.peek().line, this.peek().col);
|
|
920
|
-
if (parts.length === 1)
|
|
1161
|
+
if (parts.length === 1) {
|
|
1162
|
+
return parts[0];
|
|
1163
|
+
}
|
|
921
1164
|
return { kind: "concat", nodes: parts, pos: p };
|
|
922
1165
|
}
|
|
923
1166
|
parseArray() {
|
|
@@ -949,118 +1192,6 @@ function parseTokens(tokens) {
|
|
|
949
1192
|
return new Parser(tokens).parse();
|
|
950
1193
|
}
|
|
951
1194
|
|
|
952
|
-
// src/internal/parser/empty-check.ts
|
|
953
|
-
function hasContentTokens(tokens) {
|
|
954
|
-
return tokens.some((t) => t.kind !== "eof" && t.kind !== "newline");
|
|
955
|
-
}
|
|
956
|
-
function assertNonEmptyDocument(tokens, sourceDescriptor) {
|
|
957
|
-
if (!hasContentTokens(tokens)) {
|
|
958
|
-
throw new ParseError(
|
|
959
|
-
`empty file is not a valid HOCON document (HOCON.md L130): ${sourceDescriptor}`,
|
|
960
|
-
1,
|
|
961
|
-
1
|
|
962
|
-
);
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
// src/internal/resolver/types.ts
|
|
967
|
-
var separatorValues = /* @__PURE__ */ new WeakSet();
|
|
968
|
-
function isSubst(v) {
|
|
969
|
-
return v._kind === "subst-placeholder";
|
|
970
|
-
}
|
|
971
|
-
function isConcat(v) {
|
|
972
|
-
return v._kind === "concat-placeholder";
|
|
973
|
-
}
|
|
974
|
-
function isAppend(v) {
|
|
975
|
-
return v._kind === "append-placeholder";
|
|
976
|
-
}
|
|
977
|
-
function isResObj(v) {
|
|
978
|
-
return v._kind === "res-obj";
|
|
979
|
-
}
|
|
980
|
-
function makeResObj() {
|
|
981
|
-
return { _kind: "res-obj", fields: /* @__PURE__ */ new Map(), priorValues: /* @__PURE__ */ new Map() };
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
// src/internal/resolver/utils.ts
|
|
985
|
-
function segmentsToKey(segments) {
|
|
986
|
-
return segments.map((s) => {
|
|
987
|
-
const t = s.text;
|
|
988
|
-
if (t === "" || /[^a-zA-Z0-9\-_]/.test(t)) {
|
|
989
|
-
return `"${t.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
990
|
-
}
|
|
991
|
-
return t;
|
|
992
|
-
}).join(".");
|
|
993
|
-
}
|
|
994
|
-
function lookupPath(root, segments) {
|
|
995
|
-
const [head, ...tail] = segments;
|
|
996
|
-
if (head === void 0) return void 0;
|
|
997
|
-
const key = head.text;
|
|
998
|
-
const val = root.fields.get(key);
|
|
999
|
-
if (val === void 0) return void 0;
|
|
1000
|
-
if (tail.length === 0) return val;
|
|
1001
|
-
if (isResObj(val)) return lookupPath(val, tail);
|
|
1002
|
-
return void 0;
|
|
1003
|
-
}
|
|
1004
|
-
function lookupResObj(root, segments) {
|
|
1005
|
-
let cur = root;
|
|
1006
|
-
for (const seg of segments) {
|
|
1007
|
-
const val = cur.fields.get(seg.text);
|
|
1008
|
-
if (val === void 0 || !isResObj(val)) return void 0;
|
|
1009
|
-
cur = val;
|
|
1010
|
-
}
|
|
1011
|
-
return cur;
|
|
1012
|
-
}
|
|
1013
|
-
function deepMergeHoconValues(base, overlay) {
|
|
1014
|
-
const merged = new Map(base.fields);
|
|
1015
|
-
for (const [k, v] of overlay.fields) {
|
|
1016
|
-
const existing = merged.get(k);
|
|
1017
|
-
if (existing?.kind === "object" && v.kind === "object") {
|
|
1018
|
-
merged.set(k, deepMergeHoconValues(existing, v));
|
|
1019
|
-
} else {
|
|
1020
|
-
merged.set(k, v);
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
return { kind: "object", fields: merged };
|
|
1024
|
-
}
|
|
1025
|
-
function deepMergeResObjInto(dst, src) {
|
|
1026
|
-
for (const [k, srcVal] of src.fields) {
|
|
1027
|
-
const dstVal = dst.fields.get(k);
|
|
1028
|
-
if (dstVal !== void 0 && isResObj(dstVal) && isResObj(srcVal)) {
|
|
1029
|
-
deepMergeResObjInto(dstVal, srcVal);
|
|
1030
|
-
} else {
|
|
1031
|
-
if (dstVal !== void 0) dst.priorValues.set(k, dstVal);
|
|
1032
|
-
dst.fields.set(k, srcVal);
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
for (const [k, srcPrior] of src.priorValues) {
|
|
1036
|
-
if (!dst.priorValues.has(k)) {
|
|
1037
|
-
dst.priorValues.set(k, srcPrior);
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
function hoconValueToResObj(hv) {
|
|
1042
|
-
const obj = makeResObj();
|
|
1043
|
-
if (hv.kind !== "object") return obj;
|
|
1044
|
-
for (const [key, val] of hv.fields) {
|
|
1045
|
-
if (val.kind === "object") {
|
|
1046
|
-
obj.fields.set(key, hoconValueToResObj(val));
|
|
1047
|
-
} else {
|
|
1048
|
-
obj.fields.set(key, val);
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
return obj;
|
|
1052
|
-
}
|
|
1053
|
-
function isFileNotFoundError(e) {
|
|
1054
|
-
if (!(e instanceof Error)) return false;
|
|
1055
|
-
const code = e.code;
|
|
1056
|
-
if (code === "ENOENT" || code === "MODULE_NOT_FOUND") return true;
|
|
1057
|
-
const msg = e.message.toLowerCase();
|
|
1058
|
-
return msg.includes("not found") || msg.includes("no such file") || msg.includes("enoent");
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
// src/internal/resolver/include-loader.ts
|
|
1062
|
-
var nodePath = __toESM(require("path"), 1);
|
|
1063
|
-
|
|
1064
1195
|
// src/internal/properties/properties.ts
|
|
1065
1196
|
function parseProperties(input) {
|
|
1066
1197
|
const root = /* @__PURE__ */ Object.create(null);
|
|
@@ -1120,6 +1251,85 @@ function recordToHoconValue(obj) {
|
|
|
1120
1251
|
}
|
|
1121
1252
|
|
|
1122
1253
|
// src/internal/resolver/include-loader.ts
|
|
1254
|
+
var import_meta = {};
|
|
1255
|
+
var _require = (0, import_node_module.createRequire)(import_meta.url);
|
|
1256
|
+
function isPnpPath(p) {
|
|
1257
|
+
return p.includes(".yarn/cache") || p.includes(".pnp.cjs") || p.includes(".pnp.loader");
|
|
1258
|
+
}
|
|
1259
|
+
function validatePackageFile(file, identifier) {
|
|
1260
|
+
if (file.length === 0) {
|
|
1261
|
+
throw new ParseError(`include package("${identifier}", ...): file argument must be non-empty`, 0, 0);
|
|
1262
|
+
}
|
|
1263
|
+
if (file.includes("\\")) {
|
|
1264
|
+
throw new ParseError(
|
|
1265
|
+
`include package("${identifier}", "${file}"): backslash not allowed in file argument (use forward slash)`,
|
|
1266
|
+
0,
|
|
1267
|
+
0
|
|
1268
|
+
);
|
|
1269
|
+
}
|
|
1270
|
+
if (file.startsWith("/")) {
|
|
1271
|
+
throw new ParseError(
|
|
1272
|
+
`include package("${identifier}", "${file}"): absolute path not allowed in file argument`,
|
|
1273
|
+
0,
|
|
1274
|
+
0
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
if (/(?:^|\/)\.\.?(?:\/|$)/u.test(file)) {
|
|
1278
|
+
throw new ParseError(
|
|
1279
|
+
`include package("${identifier}", "${file}"): path traversal (. or ..) not allowed in file argument`,
|
|
1280
|
+
0,
|
|
1281
|
+
0
|
|
1282
|
+
);
|
|
1283
|
+
}
|
|
1284
|
+
if (file.includes("//")) {
|
|
1285
|
+
throw new ParseError(
|
|
1286
|
+
`include package("${identifier}", "${file}"): consecutive slashes not allowed in file argument`,
|
|
1287
|
+
0,
|
|
1288
|
+
0
|
|
1289
|
+
);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
function validatePackageIdentifier(identifier) {
|
|
1293
|
+
if (identifier.length === 0) {
|
|
1294
|
+
throw new ParseError("include package: identifier argument must be non-empty", 0, 0);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
function defaultPackageResolver(identifier, file, includingFile, baseDir, resolveFrom) {
|
|
1298
|
+
const from = resolveFrom ? Array.isArray(resolveFrom) ? resolveFrom : [resolveFrom] : baseDir ? [baseDir] : includingFile ? [nodePath.dirname(includingFile)] : [process.cwd()];
|
|
1299
|
+
let resolved;
|
|
1300
|
+
try {
|
|
1301
|
+
resolved = _require.resolve(`${identifier}/${file}`, { paths: from });
|
|
1302
|
+
} catch {
|
|
1303
|
+
throw new PackageLookupError(
|
|
1304
|
+
`include package("${identifier}", "${file}"): module not found (starting from: ${from.join(", ")})`,
|
|
1305
|
+
identifier,
|
|
1306
|
+
file,
|
|
1307
|
+
0,
|
|
1308
|
+
0
|
|
1309
|
+
);
|
|
1310
|
+
}
|
|
1311
|
+
if (isPnpPath(resolved)) {
|
|
1312
|
+
throw new ResolveError(
|
|
1313
|
+
`include package("${identifier}", "${file}"): Yarn Berry PnP store paths are not supported. Provide a custom packageResolver option to handle PnP resolution.`,
|
|
1314
|
+
`${identifier}/${file}`,
|
|
1315
|
+
0,
|
|
1316
|
+
0
|
|
1317
|
+
);
|
|
1318
|
+
}
|
|
1319
|
+
const fileParts = file.split("/");
|
|
1320
|
+
const expectedBasename = fileParts[fileParts.length - 1] ?? file;
|
|
1321
|
+
const resolvedBasename = nodePath.basename(resolved);
|
|
1322
|
+
if (resolvedBasename !== expectedBasename) {
|
|
1323
|
+
throw new PackageLookupError(
|
|
1324
|
+
`include package("${identifier}", "${file}"): case mismatch \u2014 resolved "${resolvedBasename}" but expected "${expectedBasename}" (E11 decision 5: case-sensitive)`,
|
|
1325
|
+
identifier,
|
|
1326
|
+
file,
|
|
1327
|
+
0,
|
|
1328
|
+
0
|
|
1329
|
+
);
|
|
1330
|
+
}
|
|
1331
|
+
return resolved;
|
|
1332
|
+
}
|
|
1123
1333
|
var IncludeLoader = class {
|
|
1124
1334
|
constructor(opts) {
|
|
1125
1335
|
this.opts = opts;
|
|
@@ -1199,8 +1409,77 @@ var IncludeLoader = class {
|
|
|
1199
1409
|
}
|
|
1200
1410
|
return merged;
|
|
1201
1411
|
}
|
|
1412
|
+
/**
|
|
1413
|
+
* Resolve and load `include package("identifier", "file")`.
|
|
1414
|
+
* Validates the identifier and file arguments, resolves via the package resolver,
|
|
1415
|
+
* performs cycle detection using a JSON-serialised cycle key, and parses the content.
|
|
1416
|
+
*/
|
|
1417
|
+
// `required` is reserved for future optional-package semantics (E11 decision 7);
|
|
1418
|
+
// currently all package lookup failures throw regardless of this flag.
|
|
1419
|
+
loadPackage(identifier, file, _required) {
|
|
1420
|
+
validatePackageIdentifier(identifier);
|
|
1421
|
+
validatePackageFile(file, identifier);
|
|
1422
|
+
const { includeStack = [], baseDir, resolveFrom, packageResolver, readFileSync: readFileSync2 } = this.opts;
|
|
1423
|
+
const cycleKey = JSON.stringify(["package", identifier, file]);
|
|
1424
|
+
if (includeStack.includes(cycleKey)) {
|
|
1425
|
+
throw new ResolveError(
|
|
1426
|
+
`circular include: package("${identifier}", "${file}")`,
|
|
1427
|
+
`${identifier}/${file}`,
|
|
1428
|
+
0,
|
|
1429
|
+
0
|
|
1430
|
+
);
|
|
1431
|
+
}
|
|
1432
|
+
if (includeStack.length >= 50) {
|
|
1433
|
+
throw new ResolveError(`include depth limit exceeded (max 50)`, `${identifier}/${file}`, 0, 0);
|
|
1434
|
+
}
|
|
1435
|
+
const resolver = packageResolver ?? ((id, f, includingFile, bDir) => defaultPackageResolver(id, f, includingFile, bDir, resolveFrom));
|
|
1436
|
+
const resolvedPath = resolver(identifier, file, void 0, baseDir);
|
|
1437
|
+
const content = readFileSync2(resolvedPath);
|
|
1438
|
+
if (content.length === 0) return makeResObj();
|
|
1439
|
+
const tokens = tokenize(content);
|
|
1440
|
+
assertNonEmptyDocument(tokens, resolvedPath);
|
|
1441
|
+
const ast = parseTokens(tokens);
|
|
1442
|
+
return this.onBuildResObj(ast, {
|
|
1443
|
+
...this.opts,
|
|
1444
|
+
baseDir: nodePath.dirname(resolvedPath),
|
|
1445
|
+
includeStack: [...includeStack, cycleKey]
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
/**
|
|
1449
|
+
* Async variant of `loadPackage`.
|
|
1450
|
+
*/
|
|
1451
|
+
async loadPackageAsync(identifier, file, _required) {
|
|
1452
|
+
validatePackageIdentifier(identifier);
|
|
1453
|
+
validatePackageFile(file, identifier);
|
|
1454
|
+
const { includeStack = [], baseDir, resolveFrom, packageResolver, readFile, readFileSync: readFileSync2 } = this.opts;
|
|
1455
|
+
const cycleKey = JSON.stringify(["package", identifier, file]);
|
|
1456
|
+
if (includeStack.includes(cycleKey)) {
|
|
1457
|
+
throw new ResolveError(
|
|
1458
|
+
`circular include: package("${identifier}", "${file}")`,
|
|
1459
|
+
`${identifier}/${file}`,
|
|
1460
|
+
0,
|
|
1461
|
+
0
|
|
1462
|
+
);
|
|
1463
|
+
}
|
|
1464
|
+
if (includeStack.length >= 50) {
|
|
1465
|
+
throw new ResolveError(`include depth limit exceeded (max 50)`, `${identifier}/${file}`, 0, 0);
|
|
1466
|
+
}
|
|
1467
|
+
const resolver = packageResolver ?? ((id, f, includingFile, bDir) => defaultPackageResolver(id, f, includingFile, bDir, resolveFrom));
|
|
1468
|
+
const resolvedPath = resolver(identifier, file, void 0, baseDir);
|
|
1469
|
+
const read = readFile ? async (p) => readFile(p) : async (p) => readFileSync2(p);
|
|
1470
|
+
const content = await read(resolvedPath);
|
|
1471
|
+
if (content.length === 0) return makeResObj();
|
|
1472
|
+
const tokens = tokenize(content);
|
|
1473
|
+
assertNonEmptyDocument(tokens, resolvedPath);
|
|
1474
|
+
const ast = parseTokens(tokens);
|
|
1475
|
+
return this.onBuildResObjAsync(ast, {
|
|
1476
|
+
...this.opts,
|
|
1477
|
+
baseDir: nodePath.dirname(resolvedPath),
|
|
1478
|
+
includeStack: [...includeStack, cycleKey]
|
|
1479
|
+
});
|
|
1480
|
+
}
|
|
1202
1481
|
loadSingle(candidate) {
|
|
1203
|
-
const { readFileSync: readFileSync2, includeStack = []
|
|
1482
|
+
const { readFileSync: readFileSync2, includeStack = [] } = this.opts;
|
|
1204
1483
|
if (includeStack.includes(candidate)) {
|
|
1205
1484
|
throw new ResolveError(`circular include: ${candidate}`, candidate, 0, 0);
|
|
1206
1485
|
}
|
|
@@ -1218,14 +1497,13 @@ var IncludeLoader = class {
|
|
|
1218
1497
|
assertNonEmptyDocument(tokens, candidate);
|
|
1219
1498
|
const ast = parseTokens(tokens);
|
|
1220
1499
|
return this.onBuildResObj(ast, {
|
|
1221
|
-
|
|
1500
|
+
...this.opts,
|
|
1222
1501
|
baseDir: nodePath.dirname(candidate),
|
|
1223
|
-
readFileSync: readFileSync2,
|
|
1224
1502
|
includeStack: [...includeStack, candidate]
|
|
1225
1503
|
});
|
|
1226
1504
|
}
|
|
1227
1505
|
async loadSingleAsync(candidate) {
|
|
1228
|
-
const { readFile, readFileSync: readFileSync2, includeStack = []
|
|
1506
|
+
const { readFile, readFileSync: readFileSync2, includeStack = [] } = this.opts;
|
|
1229
1507
|
const read = readFile ? async (p) => readFile(p) : async (p) => readFileSync2(p);
|
|
1230
1508
|
if (includeStack.includes(candidate)) {
|
|
1231
1509
|
throw new ResolveError(`circular include: ${candidate}`, candidate, 0, 0);
|
|
@@ -1244,10 +1522,8 @@ var IncludeLoader = class {
|
|
|
1244
1522
|
assertNonEmptyDocument(tokens, candidate);
|
|
1245
1523
|
const ast = parseTokens(tokens);
|
|
1246
1524
|
return this.onBuildResObjAsync(ast, {
|
|
1247
|
-
|
|
1525
|
+
...this.opts,
|
|
1248
1526
|
baseDir: nodePath.dirname(candidate),
|
|
1249
|
-
readFileSync: readFileSync2,
|
|
1250
|
-
readFile,
|
|
1251
1527
|
includeStack: [...includeStack, candidate]
|
|
1252
1528
|
});
|
|
1253
1529
|
}
|
|
@@ -1256,7 +1532,6 @@ var IncludeLoader = class {
|
|
|
1256
1532
|
// src/internal/resolver/structure-builder.ts
|
|
1257
1533
|
var StructureBuilder = class _StructureBuilder {
|
|
1258
1534
|
constructor(opts) {
|
|
1259
|
-
this.opts = opts;
|
|
1260
1535
|
this.loader = new IncludeLoader(opts);
|
|
1261
1536
|
this.loader.onBuildResObj = (a, o) => new _StructureBuilder(o).build(a);
|
|
1262
1537
|
this.loader.onBuildResObjAsync = async (a, o) => new _StructureBuilder(o).buildAsync(a);
|
|
@@ -1283,7 +1558,13 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1283
1558
|
}
|
|
1284
1559
|
applyField(obj, field, pathPrefix) {
|
|
1285
1560
|
if (field.key.length === 0 && field.value.kind === "include") {
|
|
1286
|
-
const
|
|
1561
|
+
const { qualifier, path: path2, required } = field.value;
|
|
1562
|
+
let included;
|
|
1563
|
+
if (qualifier.kind === "package") {
|
|
1564
|
+
included = this.loader.loadPackage(qualifier.identifier, path2, required);
|
|
1565
|
+
} else {
|
|
1566
|
+
included = this.loader.load(path2, required, qualifier.kind === "file");
|
|
1567
|
+
}
|
|
1287
1568
|
if (pathPrefix.length > 0) {
|
|
1288
1569
|
this.relativizeResObj(included, pathPrefix);
|
|
1289
1570
|
}
|
|
@@ -1325,7 +1606,13 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1325
1606
|
}
|
|
1326
1607
|
async applyFieldAsync(obj, field, pathPrefix) {
|
|
1327
1608
|
if (field.key.length === 0 && field.value.kind === "include") {
|
|
1328
|
-
const
|
|
1609
|
+
const { qualifier, path: path2, required } = field.value;
|
|
1610
|
+
let included;
|
|
1611
|
+
if (qualifier.kind === "package") {
|
|
1612
|
+
included = await this.loader.loadPackageAsync(qualifier.identifier, path2, required);
|
|
1613
|
+
} else {
|
|
1614
|
+
included = await this.loader.loadAsync(path2, required, qualifier.kind === "file");
|
|
1615
|
+
}
|
|
1329
1616
|
if (pathPrefix.length > 0) {
|
|
1330
1617
|
this.relativizeResObj(included, pathPrefix);
|
|
1331
1618
|
}
|
|
@@ -1493,6 +1780,10 @@ var SubstitutionResolver = class {
|
|
|
1493
1780
|
// xx.hocon PR (see Phase 6 #3f close-out notes).
|
|
1494
1781
|
this.resolvingConcats = /* @__PURE__ */ new WeakSet();
|
|
1495
1782
|
}
|
|
1783
|
+
/** Returns a prefix for error messages, including origin info when set. */
|
|
1784
|
+
originPrefix() {
|
|
1785
|
+
return this.opts.originDescription ? `${this.opts.originDescription}: ` : "";
|
|
1786
|
+
}
|
|
1496
1787
|
resolve() {
|
|
1497
1788
|
return this.resolveResObj(this.root);
|
|
1498
1789
|
}
|
|
@@ -1533,7 +1824,8 @@ var SubstitutionResolver = class {
|
|
|
1533
1824
|
if (isConcat(v)) {
|
|
1534
1825
|
this.resolvingConcats.add(v);
|
|
1535
1826
|
try {
|
|
1536
|
-
|
|
1827
|
+
const concatResult = this.resolveConcat(v.nodes, scope, v.line, v.col);
|
|
1828
|
+
return concatResult;
|
|
1537
1829
|
} finally {
|
|
1538
1830
|
this.resolvingConcats.delete(v);
|
|
1539
1831
|
}
|
|
@@ -1578,7 +1870,7 @@ var SubstitutionResolver = class {
|
|
|
1578
1870
|
}
|
|
1579
1871
|
if (s.optional) return void 0;
|
|
1580
1872
|
throw new ResolveError(
|
|
1581
|
-
`circular substitution: ${key}`,
|
|
1873
|
+
this.originPrefix() + `circular substitution: ${key}`,
|
|
1582
1874
|
key,
|
|
1583
1875
|
s.line,
|
|
1584
1876
|
s.col
|
|
@@ -1608,7 +1900,7 @@ var SubstitutionResolver = class {
|
|
|
1608
1900
|
}
|
|
1609
1901
|
if (s.optional) return void 0;
|
|
1610
1902
|
throw new ResolveError(
|
|
1611
|
-
|
|
1903
|
+
`${this.originPrefix()}could not resolve substitution: \${${key}}`,
|
|
1612
1904
|
key,
|
|
1613
1905
|
s.line,
|
|
1614
1906
|
s.col
|
|
@@ -1641,7 +1933,7 @@ var SubstitutionResolver = class {
|
|
|
1641
1933
|
if (result !== void 0) this.cache.set(key, result);
|
|
1642
1934
|
return result;
|
|
1643
1935
|
}
|
|
1644
|
-
if (s.listSuffix) {
|
|
1936
|
+
if (s.listSuffix && this.opts.useSystemEnvironment !== false) {
|
|
1645
1937
|
const result = this.resolveEnvList(s);
|
|
1646
1938
|
if (result !== void 0) {
|
|
1647
1939
|
this.cache.set(key, result);
|
|
@@ -1650,22 +1942,36 @@ var SubstitutionResolver = class {
|
|
|
1650
1942
|
if (s.optional) return void 0;
|
|
1651
1943
|
const envBase = s.segments.map((seg) => seg.text).join(".");
|
|
1652
1944
|
throw new ResolveError(
|
|
1653
|
-
|
|
1945
|
+
`${this.originPrefix()}could not resolve substitution: \${${key}} (no environment variables ${envBase}_0, ${envBase}_1, \u2026 set)`,
|
|
1946
|
+
key,
|
|
1947
|
+
s.line,
|
|
1948
|
+
s.col
|
|
1949
|
+
);
|
|
1950
|
+
} else if (s.listSuffix) {
|
|
1951
|
+
if (s.optional) return void 0;
|
|
1952
|
+
if (this.opts.allowUnresolved) return s;
|
|
1953
|
+
throw new ResolveError(
|
|
1954
|
+
`${this.originPrefix()}could not resolve substitution: \${${key}}`,
|
|
1654
1955
|
key,
|
|
1655
1956
|
s.line,
|
|
1656
1957
|
s.col
|
|
1657
1958
|
);
|
|
1658
1959
|
}
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1960
|
+
if (this.opts.useSystemEnvironment !== false) {
|
|
1961
|
+
const envKey = s.segments.map((seg) => seg.text).join(".");
|
|
1962
|
+
const envVal = this.opts.env[envKey] ?? (s.prefixLen > 0 ? this.opts.env[s.segments.slice(s.prefixLen).map((seg) => seg.text).join(".")] : void 0);
|
|
1963
|
+
if (envVal !== void 0) {
|
|
1964
|
+
const result = { kind: "scalar", raw: envVal, valueType: "string" };
|
|
1965
|
+
this.cache.set(key, result);
|
|
1966
|
+
return result;
|
|
1967
|
+
}
|
|
1665
1968
|
}
|
|
1666
1969
|
if (s.optional) return void 0;
|
|
1970
|
+
if (this.opts.allowUnresolved) {
|
|
1971
|
+
return s;
|
|
1972
|
+
}
|
|
1667
1973
|
throw new ResolveError(
|
|
1668
|
-
|
|
1974
|
+
`${this.originPrefix()}could not resolve substitution: \${${key}}`,
|
|
1669
1975
|
key,
|
|
1670
1976
|
s.line,
|
|
1671
1977
|
s.col
|
|
@@ -1710,8 +2016,16 @@ var SubstitutionResolver = class {
|
|
|
1710
2016
|
return [full, bare];
|
|
1711
2017
|
}
|
|
1712
2018
|
resolveConcat(nodes, scope, line = 0, col = 0) {
|
|
1713
|
-
const
|
|
1714
|
-
if (
|
|
2019
|
+
const rawResolved = nodes.map((n) => this.resolveVal(n, scope));
|
|
2020
|
+
if (this.opts.allowUnresolved) {
|
|
2021
|
+
for (const v of rawResolved) {
|
|
2022
|
+
if (v !== void 0 && isSubst(v)) {
|
|
2023
|
+
return v;
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
const resolved = rawResolved.filter((v) => v !== void 0);
|
|
2028
|
+
if (resolved.length === 0) return void 0;
|
|
1715
2029
|
if (resolved.length === 1) return resolved[0];
|
|
1716
2030
|
const nonSep = resolved.filter((v) => !separatorValues.has(v));
|
|
1717
2031
|
if (nonSep.length === 0) {
|
|
@@ -1785,15 +2099,89 @@ var SubstitutionResolver = class {
|
|
|
1785
2099
|
};
|
|
1786
2100
|
|
|
1787
2101
|
// src/internal/resolver/resolver.ts
|
|
2102
|
+
function buildTree(ast, opts) {
|
|
2103
|
+
return new StructureBuilder(opts).build(ast);
|
|
2104
|
+
}
|
|
2105
|
+
function resolveTree(tree, opts) {
|
|
2106
|
+
return new SubstitutionResolver(tree, opts).resolve();
|
|
2107
|
+
}
|
|
2108
|
+
function containsPlaceholders(tree) {
|
|
2109
|
+
for (const val of tree.fields.values()) {
|
|
2110
|
+
if (valContainsPlaceholders(val)) return true;
|
|
2111
|
+
}
|
|
2112
|
+
return false;
|
|
2113
|
+
}
|
|
2114
|
+
function valContainsPlaceholders(v) {
|
|
2115
|
+
const rv = v;
|
|
2116
|
+
if (isSubst(rv) || isConcat(rv) || isAppend(rv)) return true;
|
|
2117
|
+
if (isResObj(rv)) return containsPlaceholders(rv);
|
|
2118
|
+
const hv = v;
|
|
2119
|
+
if (hv?.kind === "array") {
|
|
2120
|
+
return hv.items.some((item) => valContainsPlaceholders(item));
|
|
2121
|
+
}
|
|
2122
|
+
return false;
|
|
2123
|
+
}
|
|
2124
|
+
function buildPartialHoconFromResObj(tree) {
|
|
2125
|
+
const fields = /* @__PURE__ */ new Map();
|
|
2126
|
+
for (const [k, v] of tree.fields) {
|
|
2127
|
+
if (!isSubst(v) && !isConcat(v) && !isAppend(v)) {
|
|
2128
|
+
if (isResObj(v)) {
|
|
2129
|
+
fields.set(k, buildPartialHoconFromResObj(v));
|
|
2130
|
+
} else {
|
|
2131
|
+
if (!valContainsPlaceholders(v)) {
|
|
2132
|
+
fields.set(k, v);
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
return { kind: "object", fields };
|
|
2138
|
+
}
|
|
2139
|
+
function hoconValueToResObj2(value) {
|
|
2140
|
+
const obj = makeResObj();
|
|
2141
|
+
for (const [k, v] of value.fields) {
|
|
2142
|
+
if (v.kind === "object") {
|
|
2143
|
+
obj.fields.set(k, hoconValueToResObj2(v));
|
|
2144
|
+
} else {
|
|
2145
|
+
obj.fields.set(k, v);
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
return obj;
|
|
2149
|
+
}
|
|
1788
2150
|
function resolve2(ast, opts) {
|
|
1789
|
-
const
|
|
1790
|
-
return
|
|
2151
|
+
const tree = buildTree(ast, opts);
|
|
2152
|
+
return resolveTree(tree, { ...opts, useSystemEnvironment: true, allowUnresolved: false });
|
|
1791
2153
|
}
|
|
1792
2154
|
|
|
1793
2155
|
// src/config.ts
|
|
1794
2156
|
var Config = class _Config {
|
|
1795
|
-
constructor(root) {
|
|
2157
|
+
constructor(root, opts) {
|
|
1796
2158
|
this.root = root;
|
|
2159
|
+
this._resolved = opts?.resolved ?? true;
|
|
2160
|
+
this._parseBaseDir = opts?.parseBaseDir;
|
|
2161
|
+
this._originDescription = opts?.originDescription;
|
|
2162
|
+
this._resObjRoot = opts?.resObjRoot;
|
|
2163
|
+
this._resolveOpts = opts?.resolveOpts;
|
|
2164
|
+
}
|
|
2165
|
+
/** Returns true when the Config's value tree contains no unresolved
|
|
2166
|
+
* substitution placeholders. Whole-config granularity (E12 decision 11). */
|
|
2167
|
+
isResolved() {
|
|
2168
|
+
return this._resolved;
|
|
2169
|
+
}
|
|
2170
|
+
/** @internal Test-only: construct a resolved Config from a HoconValue. */
|
|
2171
|
+
static _fromResolvedValue(root, opts) {
|
|
2172
|
+
return new _Config(root, { resolved: true, originDescription: opts?.originDescription });
|
|
2173
|
+
}
|
|
2174
|
+
/** @internal Construct an unresolved Config carrying a ResObj tree.
|
|
2175
|
+
* Used by parseStringWithOptions (deferred path) in T6. */
|
|
2176
|
+
static _fromUnresolvedResObj(tree, opts) {
|
|
2177
|
+
const partialRoot = buildPartialHoconFromResObj(tree);
|
|
2178
|
+
return new _Config(partialRoot, {
|
|
2179
|
+
resolved: opts.resolved,
|
|
2180
|
+
parseBaseDir: opts.parseBaseDir,
|
|
2181
|
+
originDescription: opts.originDescription,
|
|
2182
|
+
resObjRoot: tree,
|
|
2183
|
+
resolveOpts: opts.resolveOpts
|
|
2184
|
+
});
|
|
1797
2185
|
}
|
|
1798
2186
|
get(path2) {
|
|
1799
2187
|
const v = this.lookupNode(path2);
|
|
@@ -1837,13 +2225,29 @@ var Config = class _Config {
|
|
|
1837
2225
|
}
|
|
1838
2226
|
getConfig(path2) {
|
|
1839
2227
|
const v = this.lookupNode(path2);
|
|
1840
|
-
if (v === void 0)
|
|
2228
|
+
if (v === void 0) {
|
|
2229
|
+
if (!this._resolved && this._resObjRootSubtreeHasPlaceholders(path2)) {
|
|
2230
|
+
throw new NotResolvedError(path2);
|
|
2231
|
+
}
|
|
2232
|
+
throw new ConfigError(`path not found: ${path2}`, path2);
|
|
2233
|
+
}
|
|
1841
2234
|
if (v.kind !== "object") throw new ConfigError(`expected object at ${path2}`, path2);
|
|
1842
|
-
|
|
2235
|
+
if (!this._resolved && this._resObjRootSubtreeHasPlaceholders(path2)) {
|
|
2236
|
+
throw new NotResolvedError(path2);
|
|
2237
|
+
}
|
|
2238
|
+
return new _Config(v, { resolved: this._resolved });
|
|
1843
2239
|
}
|
|
1844
2240
|
getList(path2) {
|
|
1845
2241
|
const v = this.lookupNode(path2);
|
|
1846
|
-
if (v === void 0)
|
|
2242
|
+
if (v === void 0) {
|
|
2243
|
+
if (!this._resolved && this._resObjRootSubtreeHasPlaceholders(path2)) {
|
|
2244
|
+
throw new NotResolvedError(path2);
|
|
2245
|
+
}
|
|
2246
|
+
throw new ConfigError(`path not found: ${path2}`, path2);
|
|
2247
|
+
}
|
|
2248
|
+
if (!this._resolved && this._resObjRootSubtreeHasPlaceholders(path2)) {
|
|
2249
|
+
throw new NotResolvedError(path2);
|
|
2250
|
+
}
|
|
1847
2251
|
if (v.kind === "object") {
|
|
1848
2252
|
const converted = numericObjectToArray(v);
|
|
1849
2253
|
if (converted !== null) return converted.map(hoconToJs);
|
|
@@ -1858,12 +2262,138 @@ var Config = class _Config {
|
|
|
1858
2262
|
return [...this.root.fields.keys()];
|
|
1859
2263
|
}
|
|
1860
2264
|
withFallback(fallback) {
|
|
1861
|
-
|
|
1862
|
-
|
|
2265
|
+
if (fallback == null) return this;
|
|
2266
|
+
const selfTree = this._resObjRoot ?? hoconValueToResObj2(this.root);
|
|
2267
|
+
const fbTree = fallback._resObjRoot ?? hoconValueToResObj2(fallback.root);
|
|
2268
|
+
const merged = mergeUnresolved(selfTree, fbTree);
|
|
2269
|
+
const hasPlaceholders = containsPlaceholders(merged);
|
|
2270
|
+
const partialRoot = buildPartialHoconFromResObj(merged);
|
|
2271
|
+
return new _Config(partialRoot, {
|
|
2272
|
+
resolved: !hasPlaceholders,
|
|
2273
|
+
parseBaseDir: this._parseBaseDir,
|
|
2274
|
+
originDescription: this._originDescription,
|
|
2275
|
+
resObjRoot: merged,
|
|
2276
|
+
resolveOpts: this._resolveOpts ?? fallback._resolveOpts
|
|
2277
|
+
});
|
|
2278
|
+
}
|
|
2279
|
+
/**
|
|
2280
|
+
* Runs substitution resolution (phase 2) on the stored unresolved tree.
|
|
2281
|
+
* Idempotent: calling resolve() on an already-resolved Config returns an
|
|
2282
|
+
* equivalent resolved Config.
|
|
2283
|
+
*
|
|
2284
|
+
* opts.allowUnresolved (default false) — when true, leaves unresolved
|
|
2285
|
+
* non-optional placeholders in place rather than throwing.
|
|
2286
|
+
* opts.useSystemEnvironment (default true) — when false, env var lookups
|
|
2287
|
+
* are suppressed (hermetic resolution).
|
|
2288
|
+
*
|
|
2289
|
+
* E12 decision 3.
|
|
2290
|
+
*/
|
|
2291
|
+
resolve(opts = {}) {
|
|
2292
|
+
if (this._resolved) {
|
|
2293
|
+
return new _Config(this.root, {
|
|
2294
|
+
resolved: true,
|
|
2295
|
+
parseBaseDir: this._parseBaseDir,
|
|
2296
|
+
originDescription: this._originDescription
|
|
2297
|
+
});
|
|
2298
|
+
}
|
|
2299
|
+
const tree = this._resObjRoot;
|
|
2300
|
+
if (!tree) {
|
|
2301
|
+
return new _Config(this.root, { resolved: true });
|
|
2302
|
+
}
|
|
2303
|
+
const resolveOpts = {
|
|
2304
|
+
...this._resolveOpts ?? { env: {}, baseDir: void 0, readFileSync: () => {
|
|
2305
|
+
throw new Error("no files");
|
|
2306
|
+
} },
|
|
2307
|
+
allowUnresolved: opts.allowUnresolved ?? false,
|
|
2308
|
+
useSystemEnvironment: opts.useSystemEnvironment ?? true,
|
|
2309
|
+
originDescription: this._originDescription
|
|
2310
|
+
};
|
|
2311
|
+
const resolved = resolveTree(tree, resolveOpts);
|
|
2312
|
+
if (resolved.kind !== "object") throw new Error("resolve: expected object root");
|
|
2313
|
+
if (opts.allowUnresolved) {
|
|
2314
|
+
const { stripped, hadPlaceholders } = stripPlaceholderFields(resolved);
|
|
2315
|
+
return new _Config(stripped, {
|
|
2316
|
+
resolved: !hadPlaceholders,
|
|
2317
|
+
parseBaseDir: this._parseBaseDir,
|
|
2318
|
+
originDescription: this._originDescription,
|
|
2319
|
+
resObjRoot: hadPlaceholders ? tree : void 0,
|
|
2320
|
+
resolveOpts: hadPlaceholders ? resolveOpts : void 0
|
|
2321
|
+
});
|
|
2322
|
+
}
|
|
2323
|
+
return new _Config(resolved, {
|
|
2324
|
+
resolved: true,
|
|
2325
|
+
parseBaseDir: this._parseBaseDir,
|
|
2326
|
+
originDescription: this._originDescription
|
|
2327
|
+
});
|
|
2328
|
+
}
|
|
2329
|
+
/**
|
|
2330
|
+
* Resolves receiver substitutions using source as lookup context.
|
|
2331
|
+
* Source's keys are NOT merged into the result — differs from
|
|
2332
|
+
* `this.withFallback(source).resolve()` which includes source keys.
|
|
2333
|
+
*
|
|
2334
|
+
* Precondition (E12 decision 10): source must be resolved. If
|
|
2335
|
+
* source.isResolved() is false, throws NotResolvedError.
|
|
2336
|
+
*
|
|
2337
|
+
* On an already-resolved receiver, resolveWith is a no-op (returns an
|
|
2338
|
+
* equivalent resolved Config, source keys not included).
|
|
2339
|
+
*
|
|
2340
|
+
* E12 decisions 9, 10.
|
|
2341
|
+
*/
|
|
2342
|
+
resolveWith(source, opts = {}) {
|
|
2343
|
+
if (!source.isResolved()) {
|
|
2344
|
+
throw new NotResolvedError("source");
|
|
2345
|
+
}
|
|
2346
|
+
if (this._resolved) {
|
|
2347
|
+
return new _Config(this.root, {
|
|
2348
|
+
resolved: true,
|
|
2349
|
+
parseBaseDir: this._parseBaseDir,
|
|
2350
|
+
originDescription: this._originDescription
|
|
2351
|
+
});
|
|
2352
|
+
}
|
|
2353
|
+
const receiverTree = this._resObjRoot ?? hoconValueToResObj2(this.root);
|
|
2354
|
+
const srcTree = hoconValueToResObj2(source.root);
|
|
2355
|
+
const merged = mergeUnresolved(receiverTree, srcTree);
|
|
2356
|
+
const resolveOpts = {
|
|
2357
|
+
...this._resolveOpts ?? { env: {}, baseDir: void 0, readFileSync: () => {
|
|
2358
|
+
throw new Error("no files");
|
|
2359
|
+
} },
|
|
2360
|
+
allowUnresolved: opts.allowUnresolved ?? false,
|
|
2361
|
+
useSystemEnvironment: opts.useSystemEnvironment ?? true,
|
|
2362
|
+
originDescription: this._originDescription
|
|
2363
|
+
};
|
|
2364
|
+
const resolved = resolveTree(merged, resolveOpts);
|
|
2365
|
+
if (resolved.kind !== "object") throw new Error("resolveWith: expected object root");
|
|
2366
|
+
const receiverShapeForFilter = resObjToKeyShape(receiverTree);
|
|
2367
|
+
const filtered = filterByReceiverShape(resolved, receiverShapeForFilter);
|
|
2368
|
+
if (opts.allowUnresolved) {
|
|
2369
|
+
const { stripped, hadPlaceholders } = stripPlaceholderFields(filtered);
|
|
2370
|
+
return new _Config(stripped, {
|
|
2371
|
+
resolved: !hadPlaceholders,
|
|
2372
|
+
parseBaseDir: this._parseBaseDir,
|
|
2373
|
+
originDescription: this._originDescription,
|
|
2374
|
+
resObjRoot: hadPlaceholders ? receiverTree : void 0,
|
|
2375
|
+
resolveOpts: hadPlaceholders ? resolveOpts : void 0
|
|
2376
|
+
});
|
|
2377
|
+
}
|
|
2378
|
+
return new _Config(filtered, {
|
|
2379
|
+
resolved: true,
|
|
2380
|
+
parseBaseDir: this._parseBaseDir,
|
|
2381
|
+
originDescription: this._originDescription
|
|
2382
|
+
});
|
|
1863
2383
|
}
|
|
1864
2384
|
toObject() {
|
|
1865
2385
|
return hoconToJs(this.root);
|
|
1866
2386
|
}
|
|
2387
|
+
/**
|
|
2388
|
+
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
2389
|
+
* JSON (sorted keys, no whitespace). Used by Layer-2 fixture tests to compare
|
|
2390
|
+
* against Lightbend ground truth. NOT part of the public API.
|
|
2391
|
+
*
|
|
2392
|
+
* Throws if the Config is unresolved (contains placeholders).
|
|
2393
|
+
*/
|
|
2394
|
+
_renderJSONForTest() {
|
|
2395
|
+
return renderHoconAsJSON(this.root);
|
|
2396
|
+
}
|
|
1867
2397
|
lookupNode(path2) {
|
|
1868
2398
|
const segments = splitConfigPath(path2);
|
|
1869
2399
|
let current = this.root;
|
|
@@ -1875,9 +2405,40 @@ var Config = class _Config {
|
|
|
1875
2405
|
}
|
|
1876
2406
|
return current;
|
|
1877
2407
|
}
|
|
2408
|
+
/**
|
|
2409
|
+
* _resObjRootSubtreeHasPlaceholders — walk _resObjRoot to the given path and
|
|
2410
|
+
* return true if the subtree there contains any unresolved placeholder.
|
|
2411
|
+
* Used by getConfig / getList (T2) to detect transitive unresolved placeholders
|
|
2412
|
+
* in object / array subtrees that would otherwise appear to be "resolved" in the
|
|
2413
|
+
* partial HoconValue root (because individual leaf fields are omitted rather than
|
|
2414
|
+
* the whole subtree when their value is a direct placeholder scalar, but object
|
|
2415
|
+
* sub-containers are retained in the partial root with the placeholder-keyed
|
|
2416
|
+
* fields omitted from them — so the object appears "present but empty-ish").
|
|
2417
|
+
*/
|
|
2418
|
+
_resObjRootSubtreeHasPlaceholders(path2) {
|
|
2419
|
+
const tree = this._resObjRoot;
|
|
2420
|
+
if (!tree) return false;
|
|
2421
|
+
const segments = splitConfigPath(path2);
|
|
2422
|
+
let cur = tree;
|
|
2423
|
+
for (const seg of segments) {
|
|
2424
|
+
const val = cur.fields.get(seg);
|
|
2425
|
+
if (val === void 0) return false;
|
|
2426
|
+
if (isResObj(val)) {
|
|
2427
|
+
cur = val;
|
|
2428
|
+
} else {
|
|
2429
|
+
return valContainsPlaceholders(val);
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
return containsPlaceholders(cur);
|
|
2433
|
+
}
|
|
1878
2434
|
requireScalar(path2) {
|
|
1879
2435
|
const v = this.lookupNode(path2);
|
|
1880
|
-
if (v === void 0)
|
|
2436
|
+
if (v === void 0) {
|
|
2437
|
+
if (!this._resolved && this._resObjRootSubtreeHasPlaceholders(path2)) {
|
|
2438
|
+
throw new NotResolvedError(path2);
|
|
2439
|
+
}
|
|
2440
|
+
throw new ConfigError(`path not found: ${path2}`, path2);
|
|
2441
|
+
}
|
|
1881
2442
|
if (v.kind !== "scalar") throw new ConfigError(`expected scalar at ${path2}, got ${v.kind}`, path2);
|
|
1882
2443
|
return v;
|
|
1883
2444
|
}
|
|
@@ -1940,28 +2501,89 @@ function hoconToJs(v) {
|
|
|
1940
2501
|
case "array":
|
|
1941
2502
|
return v.items.map(hoconToJs);
|
|
1942
2503
|
case "object": {
|
|
1943
|
-
const obj =
|
|
2504
|
+
const obj = /* @__PURE__ */ Object.create(null);
|
|
1944
2505
|
for (const [k, val] of v.fields) obj[k] = hoconToJs(val);
|
|
1945
|
-
return obj;
|
|
2506
|
+
return Object.assign({}, obj);
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
function resObjToKeyShape(tree) {
|
|
2511
|
+
const fields = /* @__PURE__ */ new Map();
|
|
2512
|
+
for (const [k, v] of tree.fields) {
|
|
2513
|
+
if (isSubst(v) || isConcat(v) || isAppend(v)) {
|
|
2514
|
+
fields.set(k, { kind: "scalar", raw: "", valueType: "null" });
|
|
2515
|
+
} else if (isResObj(v)) {
|
|
2516
|
+
fields.set(k, resObjToKeyShape(v));
|
|
2517
|
+
} else {
|
|
2518
|
+
fields.set(k, v);
|
|
1946
2519
|
}
|
|
1947
2520
|
}
|
|
2521
|
+
return { kind: "object", fields };
|
|
1948
2522
|
}
|
|
1949
|
-
function
|
|
1950
|
-
const
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
if (
|
|
1954
|
-
|
|
2523
|
+
function stripPlaceholderFields(v) {
|
|
2524
|
+
const fields = /* @__PURE__ */ new Map();
|
|
2525
|
+
let hadPlaceholders = false;
|
|
2526
|
+
for (const [k, val] of v.fields) {
|
|
2527
|
+
if (val._kind === "subst-placeholder" || val._kind === "concat-placeholder" || val._kind === "append-placeholder") {
|
|
2528
|
+
hadPlaceholders = true;
|
|
2529
|
+
} else if (val.kind === "object") {
|
|
2530
|
+
const inner = stripPlaceholderFields(val);
|
|
2531
|
+
if (inner.hadPlaceholders) hadPlaceholders = true;
|
|
2532
|
+
fields.set(k, inner.stripped);
|
|
1955
2533
|
} else {
|
|
1956
|
-
|
|
2534
|
+
fields.set(k, val);
|
|
1957
2535
|
}
|
|
1958
2536
|
}
|
|
1959
|
-
return { kind: "object", fields
|
|
2537
|
+
return { stripped: { kind: "object", fields }, hadPlaceholders };
|
|
2538
|
+
}
|
|
2539
|
+
function filterByReceiverShape(resolved, receiverShape) {
|
|
2540
|
+
const fields = /* @__PURE__ */ new Map();
|
|
2541
|
+
for (const [k, rv] of resolved.fields) {
|
|
2542
|
+
if (!receiverShape.fields.has(k)) continue;
|
|
2543
|
+
const receiverVal = receiverShape.fields.get(k);
|
|
2544
|
+
if (rv.kind === "object" && receiverVal.kind === "object") {
|
|
2545
|
+
fields.set(k, filterByReceiverShape(rv, receiverVal));
|
|
2546
|
+
} else {
|
|
2547
|
+
fields.set(k, rv);
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
return { kind: "object", fields };
|
|
2551
|
+
}
|
|
2552
|
+
function renderHoconAsJSON(v) {
|
|
2553
|
+
switch (v.kind) {
|
|
2554
|
+
case "scalar": {
|
|
2555
|
+
switch (v.valueType) {
|
|
2556
|
+
case "null":
|
|
2557
|
+
return "null";
|
|
2558
|
+
case "boolean":
|
|
2559
|
+
return v.raw;
|
|
2560
|
+
case "number": {
|
|
2561
|
+
const n = Number(v.raw);
|
|
2562
|
+
if (Number.isFinite(n)) return v.raw;
|
|
2563
|
+
return JSON.stringify(v.raw);
|
|
2564
|
+
}
|
|
2565
|
+
case "string":
|
|
2566
|
+
return JSON.stringify(v.raw);
|
|
2567
|
+
}
|
|
2568
|
+
break;
|
|
2569
|
+
}
|
|
2570
|
+
case "array": {
|
|
2571
|
+
const items = v.items.map(renderHoconAsJSON);
|
|
2572
|
+
return `[${items.join(",")}]`;
|
|
2573
|
+
}
|
|
2574
|
+
case "object": {
|
|
2575
|
+
const keys = [...v.fields.keys()].sort();
|
|
2576
|
+
const pairs = keys.map((k) => {
|
|
2577
|
+
const val = v.fields.get(k);
|
|
2578
|
+
return `${JSON.stringify(k)}:${renderHoconAsJSON(val)}`;
|
|
2579
|
+
});
|
|
2580
|
+
return `{${pairs.join(",")}}`;
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
throw new Error(`renderHoconAsJSON: unsupported value kind (unresolved placeholder?)`);
|
|
1960
2584
|
}
|
|
1961
2585
|
|
|
1962
2586
|
// src/parse.ts
|
|
1963
|
-
var fs = __toESM(require("fs"), 1);
|
|
1964
|
-
var path = __toESM(require("path"), 1);
|
|
1965
2587
|
function getEnv(opts) {
|
|
1966
2588
|
if (opts.env !== void 0) return opts.env;
|
|
1967
2589
|
if (typeof process !== "undefined" && process.env) return process.env;
|
|
@@ -1978,7 +2600,10 @@ function buildResolveContext(input, opts) {
|
|
|
1978
2600
|
env: getEnv(opts),
|
|
1979
2601
|
baseDir: opts.baseDir,
|
|
1980
2602
|
readFileSync: opts.readFileSync ?? defaultReadFileSync,
|
|
1981
|
-
readFile: opts.readFile
|
|
2603
|
+
readFile: opts.readFile,
|
|
2604
|
+
originDescription: opts.originDescription,
|
|
2605
|
+
resolveFrom: opts.resolveFrom,
|
|
2606
|
+
packageResolver: opts.packageResolver
|
|
1982
2607
|
};
|
|
1983
2608
|
return { ast, resolveOpts };
|
|
1984
2609
|
}
|
|
@@ -1986,7 +2611,7 @@ function parse(input, opts = {}) {
|
|
|
1986
2611
|
const { ast, resolveOpts } = buildResolveContext(input, opts);
|
|
1987
2612
|
const value = resolve2(ast, resolveOpts);
|
|
1988
2613
|
if (value.kind !== "object") throw new Error("resolved value is not an object");
|
|
1989
|
-
return new Config(value);
|
|
2614
|
+
return new Config(value, { resolved: true, originDescription: opts.originDescription });
|
|
1990
2615
|
}
|
|
1991
2616
|
function parseFile(filePath, opts = {}) {
|
|
1992
2617
|
if (typeof process === "undefined" && !opts.readFileSync) {
|