@o3co/ts.hocon 1.3.0 → 1.4.1
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 +1109 -360
- package/dist/index.d.cts +45 -2
- package/dist/index.d.ts +45 -2
- package/dist/index.js +1098 -359
- package/dist/zod.cjs +829 -200
- package/dist/zod.d.cts +1 -1
- package/dist/zod.d.ts +1 -1
- package/dist/zod.js +828 -200
- package/package.json +3 -1
- package/dist/parse-nNbyqnOh.d.cts +0 -53
- package/dist/parse-nNbyqnOh.d.ts +0 -53
package/dist/index.cjs
CHANGED
|
@@ -32,12 +32,21 @@ var src_exports = {};
|
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
Config: () => Config,
|
|
34
34
|
ConfigError: () => ConfigError,
|
|
35
|
+
NotResolvedError: () => NotResolvedError,
|
|
36
|
+
PackageLookupError: () => PackageLookupError,
|
|
35
37
|
ParseError: () => ParseError,
|
|
36
38
|
ResolveError: () => ResolveError,
|
|
39
|
+
defaultParseOptions: () => defaultParseOptions,
|
|
40
|
+
defaultResolveOptions: () => defaultResolveOptions,
|
|
41
|
+
empty: () => empty,
|
|
42
|
+
fromMap: () => fromMap,
|
|
37
43
|
parse: () => parse,
|
|
38
44
|
parseAsync: () => parseAsync,
|
|
39
45
|
parseFile: () => parseFile,
|
|
40
|
-
parseFileAsync: () => parseFileAsync
|
|
46
|
+
parseFileAsync: () => parseFileAsync,
|
|
47
|
+
parseFileWithOptions: () => parseFileWithOptions,
|
|
48
|
+
parseString: () => parseString,
|
|
49
|
+
parseStringWithOptions: () => parseStringWithOptions
|
|
41
50
|
});
|
|
42
51
|
module.exports = __toCommonJS(src_exports);
|
|
43
52
|
|
|
@@ -258,6 +267,14 @@ var ResolveError = class extends Error {
|
|
|
258
267
|
this.name = "ResolveError";
|
|
259
268
|
}
|
|
260
269
|
};
|
|
270
|
+
var PackageLookupError = class extends ResolveError {
|
|
271
|
+
constructor(message, identifier, packageFile, line, col) {
|
|
272
|
+
super(message, `${identifier}/${packageFile}`, line, col);
|
|
273
|
+
this.identifier = identifier;
|
|
274
|
+
this.packageFile = packageFile;
|
|
275
|
+
this.name = "PackageLookupError";
|
|
276
|
+
}
|
|
277
|
+
};
|
|
261
278
|
var ConfigError = class extends Error {
|
|
262
279
|
constructor(message, path2) {
|
|
263
280
|
super(message);
|
|
@@ -265,191 +282,155 @@ var ConfigError = class extends Error {
|
|
|
265
282
|
this.name = "ConfigError";
|
|
266
283
|
}
|
|
267
284
|
};
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
if (value.fields.size === 0) return null;
|
|
273
|
-
const canonicalInt = /^(0|[1-9][0-9]*)$/;
|
|
274
|
-
const eligible = [];
|
|
275
|
-
for (const [key, val] of value.fields) {
|
|
276
|
-
if (!canonicalInt.test(key)) continue;
|
|
277
|
-
const n = Number(key);
|
|
278
|
-
if (!Number.isInteger(n) || n > 2147483647) continue;
|
|
279
|
-
eligible.push({ n, v: val });
|
|
285
|
+
var NotResolvedError = class extends ConfigError {
|
|
286
|
+
constructor(path2) {
|
|
287
|
+
super(`value at path "${path2}" is not resolved (call resolve() first)`, path2);
|
|
288
|
+
this.name = "NotResolvedError";
|
|
280
289
|
}
|
|
281
|
-
|
|
282
|
-
eligible.sort((a, b) => a.n - b.n);
|
|
283
|
-
return eligible.map((e) => e.v);
|
|
284
|
-
}
|
|
290
|
+
};
|
|
285
291
|
|
|
286
|
-
// src/
|
|
287
|
-
var
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
const v = this.requireScalar(path2);
|
|
308
|
-
const coerced = coerceBoolean(v.raw);
|
|
309
|
-
if (coerced !== void 0) return coerced;
|
|
310
|
-
throw new ConfigError(`expected boolean at ${path2}, got ${v.valueType}`, path2);
|
|
292
|
+
// src/internal/resolver/types.ts
|
|
293
|
+
var separatorValues = /* @__PURE__ */ new WeakSet();
|
|
294
|
+
function isSubst(v) {
|
|
295
|
+
return v._kind === "subst-placeholder";
|
|
296
|
+
}
|
|
297
|
+
function isConcat(v) {
|
|
298
|
+
return v._kind === "concat-placeholder";
|
|
299
|
+
}
|
|
300
|
+
function isAppend(v) {
|
|
301
|
+
return v._kind === "append-placeholder";
|
|
302
|
+
}
|
|
303
|
+
function isResObj(v) {
|
|
304
|
+
return v._kind === "res-obj";
|
|
305
|
+
}
|
|
306
|
+
function makeResObj() {
|
|
307
|
+
return { _kind: "res-obj", fields: /* @__PURE__ */ new Map(), priorValues: /* @__PURE__ */ new Map() };
|
|
308
|
+
}
|
|
309
|
+
function mergeUnresolved(receiver, fallback) {
|
|
310
|
+
const result = makeResObj();
|
|
311
|
+
for (const [k, v] of fallback.fields) {
|
|
312
|
+
result.fields.set(k, v);
|
|
311
313
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
if (v.valueType !== "string" && v.valueType !== "number") {
|
|
315
|
-
throw new ConfigError(`expected duration at ${path2}, got ${v.valueType}`, path2);
|
|
316
|
-
}
|
|
317
|
-
const result = parseDuration(v.raw, unit);
|
|
318
|
-
if (Number.isNaN(result)) throw new ConfigError(`invalid duration at ${path2}: ${JSON.stringify(v.raw)}`, path2);
|
|
319
|
-
return result;
|
|
314
|
+
for (const [k, v] of fallback.priorValues) {
|
|
315
|
+
result.priorValues.set(k, v);
|
|
320
316
|
}
|
|
321
|
-
|
|
322
|
-
const
|
|
323
|
-
if (
|
|
324
|
-
|
|
317
|
+
for (const [k, rv] of receiver.fields) {
|
|
318
|
+
const existing = result.fields.get(k);
|
|
319
|
+
if (existing !== void 0) {
|
|
320
|
+
const recPrior = receiver.priorValues.get(k);
|
|
321
|
+
if (recPrior !== void 0 && !isResObj(recPrior)) {
|
|
322
|
+
result.fields.set(k, rv);
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
if (isResObj(rv) && isResObj(existing)) {
|
|
326
|
+
result.fields.set(k, mergeUnresolved(rv, existing));
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
result.priorValues.set(k, existing);
|
|
325
330
|
}
|
|
326
|
-
|
|
327
|
-
if (Number.isNaN(result)) throw new ConfigError(`invalid byte size at ${path2}: ${JSON.stringify(v.raw)}`, path2);
|
|
328
|
-
if (result < 0) throw new ConfigError(`byte size must be non-negative at ${path2}: ${JSON.stringify(v.raw)}`, path2);
|
|
329
|
-
return result;
|
|
330
|
-
}
|
|
331
|
-
getConfig(path2) {
|
|
332
|
-
const v = this.lookupNode(path2);
|
|
333
|
-
if (v === void 0) throw new ConfigError(`path not found: ${path2}`, path2);
|
|
334
|
-
if (v.kind !== "object") throw new ConfigError(`expected object at ${path2}`, path2);
|
|
335
|
-
return new _Config(v);
|
|
331
|
+
result.fields.set(k, rv);
|
|
336
332
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
if (v.kind === "object") {
|
|
341
|
-
const converted = numericObjectToArray(v);
|
|
342
|
-
if (converted !== null) return converted.map(hoconToJs);
|
|
333
|
+
for (const [k, v] of receiver.priorValues) {
|
|
334
|
+
if (receiver.fields.has(k)) {
|
|
335
|
+
result.priorValues.set(k, v);
|
|
343
336
|
}
|
|
344
|
-
if (v.kind !== "array") throw new ConfigError(`expected array at ${path2}`, path2);
|
|
345
|
-
return v.items.map(hoconToJs);
|
|
346
|
-
}
|
|
347
|
-
has(path2) {
|
|
348
|
-
return this.lookupNode(path2) !== void 0;
|
|
349
|
-
}
|
|
350
|
-
keys() {
|
|
351
|
-
return [...this.root.fields.keys()];
|
|
352
|
-
}
|
|
353
|
-
withFallback(fallback) {
|
|
354
|
-
const merged = deepMergeHocon(this.root, fallback.root);
|
|
355
|
-
return new _Config(merged);
|
|
356
337
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
if (next === void 0) return void 0;
|
|
367
|
-
current = next;
|
|
338
|
+
return result;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// src/internal/resolver/utils.ts
|
|
342
|
+
function segmentsToKey(segments) {
|
|
343
|
+
return segments.map((s) => {
|
|
344
|
+
const t = s.text;
|
|
345
|
+
if (t === "" || /[^a-zA-Z0-9\-_]/.test(t)) {
|
|
346
|
+
return `"${t.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
368
347
|
}
|
|
369
|
-
return
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
348
|
+
return t;
|
|
349
|
+
}).join(".");
|
|
350
|
+
}
|
|
351
|
+
function lookupPath(root, segments) {
|
|
352
|
+
const [head, ...tail] = segments;
|
|
353
|
+
if (head === void 0) return void 0;
|
|
354
|
+
const key = head.text;
|
|
355
|
+
const val = root.fields.get(key);
|
|
356
|
+
if (val === void 0) return void 0;
|
|
357
|
+
if (tail.length === 0) return val;
|
|
358
|
+
if (isResObj(val)) return lookupPath(val, tail);
|
|
359
|
+
return void 0;
|
|
360
|
+
}
|
|
361
|
+
function lookupResObj(root, segments) {
|
|
362
|
+
let cur = root;
|
|
363
|
+
for (const seg of segments) {
|
|
364
|
+
const val = cur.fields.get(seg.text);
|
|
365
|
+
if (val === void 0 || !isResObj(val)) return void 0;
|
|
366
|
+
cur = val;
|
|
376
367
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
let closed = false;
|
|
386
|
-
while (i < path2.length) {
|
|
387
|
-
const ch = path2[i];
|
|
388
|
-
if (ch === "\\" && i + 1 < path2.length) {
|
|
389
|
-
const next = path2[i + 1];
|
|
390
|
-
segment += next;
|
|
391
|
-
i += 2;
|
|
392
|
-
continue;
|
|
393
|
-
}
|
|
394
|
-
if (ch === '"') {
|
|
395
|
-
closed = true;
|
|
396
|
-
i++;
|
|
397
|
-
break;
|
|
398
|
-
}
|
|
399
|
-
segment += ch;
|
|
400
|
-
i++;
|
|
401
|
-
}
|
|
402
|
-
if (!closed) throw new ConfigError(`unterminated quoted path segment: ${path2}`, path2);
|
|
403
|
-
segments.push(segment);
|
|
404
|
-
if (i < path2.length && path2[i] === ".") i++;
|
|
368
|
+
return cur;
|
|
369
|
+
}
|
|
370
|
+
function deepMergeHoconValues(base, overlay) {
|
|
371
|
+
const merged = new Map(base.fields);
|
|
372
|
+
for (const [k, v] of overlay.fields) {
|
|
373
|
+
const existing = merged.get(k);
|
|
374
|
+
if (existing?.kind === "object" && v.kind === "object") {
|
|
375
|
+
merged.set(k, deepMergeHoconValues(existing, v));
|
|
405
376
|
} else {
|
|
406
|
-
|
|
407
|
-
if (dot === -1) {
|
|
408
|
-
segments.push(path2.slice(i));
|
|
409
|
-
break;
|
|
410
|
-
}
|
|
411
|
-
segments.push(path2.slice(i, dot));
|
|
412
|
-
i = dot + 1;
|
|
377
|
+
merged.set(k, v);
|
|
413
378
|
}
|
|
414
379
|
}
|
|
415
|
-
return
|
|
380
|
+
return { kind: "object", fields: merged };
|
|
416
381
|
}
|
|
417
|
-
function
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
return raw;
|
|
382
|
+
function deepMergeResObjInto(dst, src) {
|
|
383
|
+
for (const [k, srcVal] of src.fields) {
|
|
384
|
+
const dstVal = dst.fields.get(k);
|
|
385
|
+
if (dstVal !== void 0 && isResObj(dstVal) && isResObj(srcVal)) {
|
|
386
|
+
deepMergeResObjInto(dstVal, srcVal);
|
|
387
|
+
} else {
|
|
388
|
+
if (dstVal !== void 0) dst.priorValues.set(k, dstVal);
|
|
389
|
+
dst.fields.set(k, srcVal);
|
|
390
|
+
}
|
|
427
391
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
case "scalar":
|
|
432
|
-
return scalarToJs(v.raw, v.valueType);
|
|
433
|
-
case "array":
|
|
434
|
-
return v.items.map(hoconToJs);
|
|
435
|
-
case "object": {
|
|
436
|
-
const obj = {};
|
|
437
|
-
for (const [k, val] of v.fields) obj[k] = hoconToJs(val);
|
|
438
|
-
return obj;
|
|
392
|
+
for (const [k, srcPrior] of src.priorValues) {
|
|
393
|
+
if (!dst.priorValues.has(k)) {
|
|
394
|
+
dst.priorValues.set(k, srcPrior);
|
|
439
395
|
}
|
|
440
396
|
}
|
|
441
397
|
}
|
|
442
|
-
function
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
if (
|
|
447
|
-
|
|
398
|
+
function hoconValueToResObj(hv) {
|
|
399
|
+
const obj = makeResObj();
|
|
400
|
+
if (hv.kind !== "object") return obj;
|
|
401
|
+
for (const [key, val] of hv.fields) {
|
|
402
|
+
if (val.kind === "object") {
|
|
403
|
+
obj.fields.set(key, hoconValueToResObj(val));
|
|
448
404
|
} else {
|
|
449
|
-
|
|
405
|
+
obj.fields.set(key, val);
|
|
450
406
|
}
|
|
451
407
|
}
|
|
452
|
-
return
|
|
408
|
+
return obj;
|
|
409
|
+
}
|
|
410
|
+
function isFileNotFoundError(e) {
|
|
411
|
+
if (!(e instanceof Error)) return false;
|
|
412
|
+
const code = e.code;
|
|
413
|
+
if (code === "ENOENT" || code === "MODULE_NOT_FOUND") return true;
|
|
414
|
+
const msg = e.message.toLowerCase();
|
|
415
|
+
return msg.includes("not found") || msg.includes("no such file") || msg.includes("enoent");
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// src/internal/resolver/include-loader.ts
|
|
419
|
+
var import_node_module = require("module");
|
|
420
|
+
var nodePath = __toESM(require("path"), 1);
|
|
421
|
+
|
|
422
|
+
// src/internal/parser/empty-check.ts
|
|
423
|
+
function hasContentTokens(tokens) {
|
|
424
|
+
return tokens.some((t) => t.kind !== "eof" && t.kind !== "newline");
|
|
425
|
+
}
|
|
426
|
+
function assertNonEmptyDocument(tokens, sourceDescriptor) {
|
|
427
|
+
if (!hasContentTokens(tokens)) {
|
|
428
|
+
throw new ParseError(
|
|
429
|
+
`empty file is not a valid HOCON document (HOCON.md L130): ${sourceDescriptor}`,
|
|
430
|
+
1,
|
|
431
|
+
1
|
|
432
|
+
);
|
|
433
|
+
}
|
|
453
434
|
}
|
|
454
435
|
|
|
455
436
|
// src/internal/lexer/lexer.ts
|
|
@@ -1015,58 +996,137 @@ var Parser = class {
|
|
|
1015
996
|
const p = this.currentPos();
|
|
1016
997
|
this.skip("newline");
|
|
1017
998
|
const t = this.peek();
|
|
1018
|
-
let path2;
|
|
1019
|
-
let required = false;
|
|
1020
|
-
let isFile = false;
|
|
1021
999
|
if (t.kind === "unquoted" && (t.value === "required(" || t.value === "required" || t.value.startsWith("required("))) {
|
|
1022
1000
|
if (t.value === "required") {
|
|
1023
|
-
const
|
|
1024
|
-
if (
|
|
1001
|
+
const next = this.peek(1);
|
|
1002
|
+
if (next.kind !== "unquoted" || !next.value.startsWith("(")) {
|
|
1025
1003
|
throw new ParseError("include required must be followed by (", t.line, t.col);
|
|
1026
1004
|
}
|
|
1027
1005
|
}
|
|
1028
|
-
required = true;
|
|
1029
1006
|
this.advance();
|
|
1030
1007
|
const innerPrefix = t.value.startsWith("required(") ? t.value.slice("required(".length) : "";
|
|
1031
|
-
if (innerPrefix.startsWith("url") || innerPrefix.startsWith("classpath")) {
|
|
1008
|
+
if (innerPrefix === "url" || innerPrefix.startsWith("url(") || innerPrefix === "classpath" || innerPrefix.startsWith("classpath(")) {
|
|
1032
1009
|
throw new ParseError("include url(...) and classpath(...) are not supported", t.line, t.col);
|
|
1033
1010
|
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1011
|
+
const nextTok = this.peek();
|
|
1012
|
+
if (innerPrefix === "package" || innerPrefix.startsWith("package(") || innerPrefix === "" && nextTok.kind === "unquoted" && (nextTok.value === "package(" || nextTok.value.startsWith("package("))) {
|
|
1013
|
+
const consumePackageToken = innerPrefix === "";
|
|
1014
|
+
const { qualifier, path: path3 } = this.parsePackageArgs(consumePackageToken);
|
|
1015
|
+
return this.makeIncludeField(qualifier, path3, true, p);
|
|
1036
1016
|
}
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1017
|
+
if (innerPrefix === "file" || innerPrefix.startsWith("file(") || innerPrefix === "" && nextTok.kind === "unquoted" && (nextTok.value === "file(" || nextTok.value === "file")) {
|
|
1018
|
+
if (innerPrefix === "") {
|
|
1019
|
+
this.advance();
|
|
1020
|
+
}
|
|
1021
|
+
const path3 = this.parseQuotedPathSkipWrapper(t);
|
|
1022
|
+
return this.makeIncludeField({ kind: "file" }, path3, true, p);
|
|
1023
|
+
}
|
|
1024
|
+
if (innerPrefix === "" && nextTok.kind === "unquoted" && (nextTok.value === "url" || nextTok.value.startsWith("url(") || nextTok.value === "classpath" || nextTok.value.startsWith("classpath("))) {
|
|
1025
|
+
throw new ParseError("include url(...) and classpath(...) are not supported", nextTok.line, nextTok.col);
|
|
1026
|
+
}
|
|
1027
|
+
if (innerPrefix !== "") {
|
|
1028
|
+
if (innerPrefix === ")") {
|
|
1029
|
+
throw new ParseError("include required(...) must contain a path", t.line, t.col);
|
|
1030
|
+
}
|
|
1031
|
+
const name = innerPrefix.replace(/\(.*$/, "").replace(/\).*$/, "");
|
|
1032
|
+
throw new ParseError(`unknown include qualifier inside required(): "${name}"`, t.line, t.col);
|
|
1033
|
+
}
|
|
1034
|
+
const path2 = this.parseQuotedPathSkipWrapper(t);
|
|
1035
|
+
return this.makeIncludeField({ kind: "bare" }, path2, true, p);
|
|
1036
|
+
}
|
|
1037
|
+
if (t.kind === "string") {
|
|
1038
|
+
const path2 = this.advance().value;
|
|
1039
|
+
return this.makeIncludeField({ kind: "bare" }, path2, false, p);
|
|
1040
|
+
}
|
|
1041
|
+
if (t.kind === "unquoted" && (t.value === "file(" || t.value === "file")) {
|
|
1052
1042
|
this.advance();
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1043
|
+
const path2 = this.parseQuotedPathSkipWrapper(t);
|
|
1044
|
+
return this.makeIncludeField({ kind: "file" }, path2, false, p);
|
|
1045
|
+
}
|
|
1046
|
+
if (t.kind === "unquoted" && (t.value === "package(" || t.value.startsWith("package("))) {
|
|
1047
|
+
const { qualifier, path: path2 } = this.parsePackageArgs();
|
|
1048
|
+
return this.makeIncludeField(qualifier, path2, false, p);
|
|
1049
|
+
}
|
|
1050
|
+
if (t.kind === "unquoted" && (t.value === "url" || t.value.startsWith("url("))) {
|
|
1058
1051
|
throw new ParseError("include url(...) is not supported", t.line, t.col);
|
|
1059
|
-
}
|
|
1052
|
+
}
|
|
1053
|
+
if (t.kind === "unquoted" && (t.value === "classpath" || t.value.startsWith("classpath("))) {
|
|
1060
1054
|
throw new ParseError("include classpath(...) is not supported", t.line, t.col);
|
|
1061
|
-
} else {
|
|
1062
|
-
throw new ParseError(`expected include path, got ${t.kind}`, t.line, t.col);
|
|
1063
1055
|
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1056
|
+
throw new ParseError(`expected include path, got ${t.kind}`, t.line, t.col);
|
|
1057
|
+
}
|
|
1058
|
+
makeIncludeField(qualifier, path2, required, pos) {
|
|
1059
|
+
return { key: [], value: { kind: "include", qualifier, path: path2, required, pos }, append: false, pos };
|
|
1060
|
+
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Skip past include-syntax wrapper tokens to find the quoted path string.
|
|
1063
|
+
* Strict: only allows `(`, `)`, and bare qualifier keywords (file / file( /
|
|
1064
|
+
* package / package( / url / url( / classpath / classpath() between the
|
|
1065
|
+
* directive and the quoted path. Anything else is a parse error rather than
|
|
1066
|
+
* silently swallowed (see ts#113).
|
|
1067
|
+
*/
|
|
1068
|
+
parseQuotedPathSkipWrapper(errTok) {
|
|
1069
|
+
while (this.isIncludeWrapperToken(this.peek())) this.advance();
|
|
1070
|
+
if (this.peek().kind !== "string") {
|
|
1071
|
+
const tok = this.peek();
|
|
1072
|
+
if (tok.kind === "eof") throw new ParseError("expected include path", errTok.line, errTok.col);
|
|
1073
|
+
const desc = tok.kind === "unquoted" ? `unquoted "${tok.value}"` : tok.kind;
|
|
1074
|
+
throw new ParseError(`expected quoted include path, got ${desc}`, tok.line, tok.col);
|
|
1075
|
+
}
|
|
1076
|
+
const path2 = this.advance().value;
|
|
1077
|
+
while (this.peek().kind === "unquoted" && (this.peek().value === ")" || this.peek().value === "))")) {
|
|
1078
|
+
this.advance();
|
|
1079
|
+
}
|
|
1080
|
+
const after = this.peek();
|
|
1081
|
+
if (after.kind !== "newline" && after.kind !== "rbrace" && after.kind !== "eof" && after.kind !== "comma") {
|
|
1082
|
+
const desc = after.kind === "unquoted" ? `unquoted "${after.value}"` : after.kind;
|
|
1083
|
+
throw new ParseError(`unexpected token after include path: ${desc}`, after.line, after.col);
|
|
1084
|
+
}
|
|
1085
|
+
return path2;
|
|
1086
|
+
}
|
|
1087
|
+
isIncludeWrapperToken(tok) {
|
|
1088
|
+
return tok.kind === "unquoted" && tok.value === "(";
|
|
1089
|
+
}
|
|
1090
|
+
/**
|
|
1091
|
+
* Parse the body of `package("identifier", "file")`.
|
|
1092
|
+
*
|
|
1093
|
+
* @param consumePackageToken - When true (default), the current token is `package(` and
|
|
1094
|
+
* must be consumed first. When false, the lexer already bundled `package(` into the
|
|
1095
|
+
* preceding token (e.g. `required(package("`), so we are already positioned at the
|
|
1096
|
+
* first string argument.
|
|
1097
|
+
*/
|
|
1098
|
+
parsePackageArgs(consumePackageToken = true) {
|
|
1099
|
+
const pkgTok = consumePackageToken ? this.advance() : this.peek();
|
|
1100
|
+
this.skip("newline");
|
|
1101
|
+
const idTok = this.peek();
|
|
1102
|
+
if (idTok.kind !== "string") {
|
|
1103
|
+
throw new ParseError("include package: expected quoted identifier as first argument", pkgTok.line, pkgTok.col);
|
|
1104
|
+
}
|
|
1105
|
+
const identifier = this.advance().value;
|
|
1106
|
+
this.skip("newline");
|
|
1107
|
+
if (this.peek().kind !== "comma") {
|
|
1108
|
+
const after = this.peek();
|
|
1109
|
+
throw new ParseError(
|
|
1110
|
+
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",
|
|
1111
|
+
pkgTok.line,
|
|
1112
|
+
pkgTok.col
|
|
1113
|
+
);
|
|
1114
|
+
}
|
|
1115
|
+
this.advance();
|
|
1116
|
+
this.skip("newline");
|
|
1117
|
+
const fileTok = this.peek();
|
|
1118
|
+
if (fileTok.kind !== "string") {
|
|
1119
|
+
throw new ParseError(
|
|
1120
|
+
"include package: requires exactly two arguments (identifier, file) \u2014 one-arg form is not supported",
|
|
1121
|
+
pkgTok.line,
|
|
1122
|
+
pkgTok.col
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
1125
|
+
const filePath = this.advance().value;
|
|
1126
|
+
while (this.peek().kind !== "newline" && this.peek().kind !== "rbrace" && this.peek().kind !== "eof" && this.peek().kind !== "comma") {
|
|
1127
|
+
this.advance();
|
|
1128
|
+
}
|
|
1129
|
+
return { qualifier: { kind: "package", identifier }, path: filePath };
|
|
1070
1130
|
}
|
|
1071
1131
|
parseValue() {
|
|
1072
1132
|
const p = this.currentPos();
|
|
@@ -1107,7 +1167,9 @@ var Parser = class {
|
|
|
1107
1167
|
parts.push(node);
|
|
1108
1168
|
}
|
|
1109
1169
|
if (parts.length === 0) throw new ParseError("expected value", this.peek().line, this.peek().col);
|
|
1110
|
-
if (parts.length === 1)
|
|
1170
|
+
if (parts.length === 1) {
|
|
1171
|
+
return parts[0];
|
|
1172
|
+
}
|
|
1111
1173
|
return { kind: "concat", nodes: parts, pos: p };
|
|
1112
1174
|
}
|
|
1113
1175
|
parseArray() {
|
|
@@ -1139,118 +1201,6 @@ function parseTokens(tokens) {
|
|
|
1139
1201
|
return new Parser(tokens).parse();
|
|
1140
1202
|
}
|
|
1141
1203
|
|
|
1142
|
-
// src/internal/parser/empty-check.ts
|
|
1143
|
-
function hasContentTokens(tokens) {
|
|
1144
|
-
return tokens.some((t) => t.kind !== "eof" && t.kind !== "newline");
|
|
1145
|
-
}
|
|
1146
|
-
function assertNonEmptyDocument(tokens, sourceDescriptor) {
|
|
1147
|
-
if (!hasContentTokens(tokens)) {
|
|
1148
|
-
throw new ParseError(
|
|
1149
|
-
`empty file is not a valid HOCON document (HOCON.md L130): ${sourceDescriptor}`,
|
|
1150
|
-
1,
|
|
1151
|
-
1
|
|
1152
|
-
);
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
// src/internal/resolver/types.ts
|
|
1157
|
-
var separatorValues = /* @__PURE__ */ new WeakSet();
|
|
1158
|
-
function isSubst(v) {
|
|
1159
|
-
return v._kind === "subst-placeholder";
|
|
1160
|
-
}
|
|
1161
|
-
function isConcat(v) {
|
|
1162
|
-
return v._kind === "concat-placeholder";
|
|
1163
|
-
}
|
|
1164
|
-
function isAppend(v) {
|
|
1165
|
-
return v._kind === "append-placeholder";
|
|
1166
|
-
}
|
|
1167
|
-
function isResObj(v) {
|
|
1168
|
-
return v._kind === "res-obj";
|
|
1169
|
-
}
|
|
1170
|
-
function makeResObj() {
|
|
1171
|
-
return { _kind: "res-obj", fields: /* @__PURE__ */ new Map(), priorValues: /* @__PURE__ */ new Map() };
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
// src/internal/resolver/utils.ts
|
|
1175
|
-
function segmentsToKey(segments) {
|
|
1176
|
-
return segments.map((s) => {
|
|
1177
|
-
const t = s.text;
|
|
1178
|
-
if (t === "" || /[^a-zA-Z0-9\-_]/.test(t)) {
|
|
1179
|
-
return `"${t.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
1180
|
-
}
|
|
1181
|
-
return t;
|
|
1182
|
-
}).join(".");
|
|
1183
|
-
}
|
|
1184
|
-
function lookupPath(root, segments) {
|
|
1185
|
-
const [head, ...tail] = segments;
|
|
1186
|
-
if (head === void 0) return void 0;
|
|
1187
|
-
const key = head.text;
|
|
1188
|
-
const val = root.fields.get(key);
|
|
1189
|
-
if (val === void 0) return void 0;
|
|
1190
|
-
if (tail.length === 0) return val;
|
|
1191
|
-
if (isResObj(val)) return lookupPath(val, tail);
|
|
1192
|
-
return void 0;
|
|
1193
|
-
}
|
|
1194
|
-
function lookupResObj(root, segments) {
|
|
1195
|
-
let cur = root;
|
|
1196
|
-
for (const seg of segments) {
|
|
1197
|
-
const val = cur.fields.get(seg.text);
|
|
1198
|
-
if (val === void 0 || !isResObj(val)) return void 0;
|
|
1199
|
-
cur = val;
|
|
1200
|
-
}
|
|
1201
|
-
return cur;
|
|
1202
|
-
}
|
|
1203
|
-
function deepMergeHoconValues(base, overlay) {
|
|
1204
|
-
const merged = new Map(base.fields);
|
|
1205
|
-
for (const [k, v] of overlay.fields) {
|
|
1206
|
-
const existing = merged.get(k);
|
|
1207
|
-
if (existing?.kind === "object" && v.kind === "object") {
|
|
1208
|
-
merged.set(k, deepMergeHoconValues(existing, v));
|
|
1209
|
-
} else {
|
|
1210
|
-
merged.set(k, v);
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
return { kind: "object", fields: merged };
|
|
1214
|
-
}
|
|
1215
|
-
function deepMergeResObjInto(dst, src) {
|
|
1216
|
-
for (const [k, srcVal] of src.fields) {
|
|
1217
|
-
const dstVal = dst.fields.get(k);
|
|
1218
|
-
if (dstVal !== void 0 && isResObj(dstVal) && isResObj(srcVal)) {
|
|
1219
|
-
deepMergeResObjInto(dstVal, srcVal);
|
|
1220
|
-
} else {
|
|
1221
|
-
if (dstVal !== void 0) dst.priorValues.set(k, dstVal);
|
|
1222
|
-
dst.fields.set(k, srcVal);
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
for (const [k, srcPrior] of src.priorValues) {
|
|
1226
|
-
if (!dst.priorValues.has(k)) {
|
|
1227
|
-
dst.priorValues.set(k, srcPrior);
|
|
1228
|
-
}
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
function hoconValueToResObj(hv) {
|
|
1232
|
-
const obj = makeResObj();
|
|
1233
|
-
if (hv.kind !== "object") return obj;
|
|
1234
|
-
for (const [key, val] of hv.fields) {
|
|
1235
|
-
if (val.kind === "object") {
|
|
1236
|
-
obj.fields.set(key, hoconValueToResObj(val));
|
|
1237
|
-
} else {
|
|
1238
|
-
obj.fields.set(key, val);
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1241
|
-
return obj;
|
|
1242
|
-
}
|
|
1243
|
-
function isFileNotFoundError(e) {
|
|
1244
|
-
if (!(e instanceof Error)) return false;
|
|
1245
|
-
const code = e.code;
|
|
1246
|
-
if (code === "ENOENT" || code === "MODULE_NOT_FOUND") return true;
|
|
1247
|
-
const msg = e.message.toLowerCase();
|
|
1248
|
-
return msg.includes("not found") || msg.includes("no such file") || msg.includes("enoent");
|
|
1249
|
-
}
|
|
1250
|
-
|
|
1251
|
-
// src/internal/resolver/include-loader.ts
|
|
1252
|
-
var nodePath = __toESM(require("path"), 1);
|
|
1253
|
-
|
|
1254
1204
|
// src/internal/properties/properties.ts
|
|
1255
1205
|
function parseProperties(input) {
|
|
1256
1206
|
const root = /* @__PURE__ */ Object.create(null);
|
|
@@ -1310,6 +1260,85 @@ function recordToHoconValue(obj) {
|
|
|
1310
1260
|
}
|
|
1311
1261
|
|
|
1312
1262
|
// src/internal/resolver/include-loader.ts
|
|
1263
|
+
var import_meta = {};
|
|
1264
|
+
var _require = (0, import_node_module.createRequire)(import_meta.url);
|
|
1265
|
+
function isPnpPath(p) {
|
|
1266
|
+
return p.includes(".yarn/cache") || p.includes(".pnp.cjs") || p.includes(".pnp.loader");
|
|
1267
|
+
}
|
|
1268
|
+
function validatePackageFile(file, identifier) {
|
|
1269
|
+
if (file.length === 0) {
|
|
1270
|
+
throw new ParseError(`include package("${identifier}", ...): file argument must be non-empty`, 0, 0);
|
|
1271
|
+
}
|
|
1272
|
+
if (file.includes("\\")) {
|
|
1273
|
+
throw new ParseError(
|
|
1274
|
+
`include package("${identifier}", "${file}"): backslash not allowed in file argument (use forward slash)`,
|
|
1275
|
+
0,
|
|
1276
|
+
0
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
if (file.startsWith("/")) {
|
|
1280
|
+
throw new ParseError(
|
|
1281
|
+
`include package("${identifier}", "${file}"): absolute path not allowed in file argument`,
|
|
1282
|
+
0,
|
|
1283
|
+
0
|
|
1284
|
+
);
|
|
1285
|
+
}
|
|
1286
|
+
if (/(?:^|\/)\.\.?(?:\/|$)/u.test(file)) {
|
|
1287
|
+
throw new ParseError(
|
|
1288
|
+
`include package("${identifier}", "${file}"): path traversal (. or ..) not allowed in file argument`,
|
|
1289
|
+
0,
|
|
1290
|
+
0
|
|
1291
|
+
);
|
|
1292
|
+
}
|
|
1293
|
+
if (file.includes("//")) {
|
|
1294
|
+
throw new ParseError(
|
|
1295
|
+
`include package("${identifier}", "${file}"): consecutive slashes not allowed in file argument`,
|
|
1296
|
+
0,
|
|
1297
|
+
0
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
function validatePackageIdentifier(identifier) {
|
|
1302
|
+
if (identifier.length === 0) {
|
|
1303
|
+
throw new ParseError("include package: identifier argument must be non-empty", 0, 0);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
function defaultPackageResolver(identifier, file, includingFile, baseDir, resolveFrom) {
|
|
1307
|
+
const from = resolveFrom ? Array.isArray(resolveFrom) ? resolveFrom : [resolveFrom] : baseDir ? [baseDir] : includingFile ? [nodePath.dirname(includingFile)] : [process.cwd()];
|
|
1308
|
+
let resolved;
|
|
1309
|
+
try {
|
|
1310
|
+
resolved = _require.resolve(`${identifier}/${file}`, { paths: from });
|
|
1311
|
+
} catch {
|
|
1312
|
+
throw new PackageLookupError(
|
|
1313
|
+
`include package("${identifier}", "${file}"): module not found (starting from: ${from.join(", ")})`,
|
|
1314
|
+
identifier,
|
|
1315
|
+
file,
|
|
1316
|
+
0,
|
|
1317
|
+
0
|
|
1318
|
+
);
|
|
1319
|
+
}
|
|
1320
|
+
if (isPnpPath(resolved)) {
|
|
1321
|
+
throw new ResolveError(
|
|
1322
|
+
`include package("${identifier}", "${file}"): Yarn Berry PnP store paths are not supported. Provide a custom packageResolver option to handle PnP resolution.`,
|
|
1323
|
+
`${identifier}/${file}`,
|
|
1324
|
+
0,
|
|
1325
|
+
0
|
|
1326
|
+
);
|
|
1327
|
+
}
|
|
1328
|
+
const fileParts = file.split("/");
|
|
1329
|
+
const expectedBasename = fileParts[fileParts.length - 1] ?? file;
|
|
1330
|
+
const resolvedBasename = nodePath.basename(resolved);
|
|
1331
|
+
if (resolvedBasename !== expectedBasename) {
|
|
1332
|
+
throw new PackageLookupError(
|
|
1333
|
+
`include package("${identifier}", "${file}"): case mismatch \u2014 resolved "${resolvedBasename}" but expected "${expectedBasename}" (E11 decision 5: case-sensitive)`,
|
|
1334
|
+
identifier,
|
|
1335
|
+
file,
|
|
1336
|
+
0,
|
|
1337
|
+
0
|
|
1338
|
+
);
|
|
1339
|
+
}
|
|
1340
|
+
return resolved;
|
|
1341
|
+
}
|
|
1313
1342
|
var IncludeLoader = class {
|
|
1314
1343
|
constructor(opts) {
|
|
1315
1344
|
this.opts = opts;
|
|
@@ -1389,8 +1418,77 @@ var IncludeLoader = class {
|
|
|
1389
1418
|
}
|
|
1390
1419
|
return merged;
|
|
1391
1420
|
}
|
|
1421
|
+
/**
|
|
1422
|
+
* Resolve and load `include package("identifier", "file")`.
|
|
1423
|
+
* Validates the identifier and file arguments, resolves via the package resolver,
|
|
1424
|
+
* performs cycle detection using a JSON-serialised cycle key, and parses the content.
|
|
1425
|
+
*/
|
|
1426
|
+
// `required` is reserved for future optional-package semantics (E11 decision 7);
|
|
1427
|
+
// currently all package lookup failures throw regardless of this flag.
|
|
1428
|
+
loadPackage(identifier, file, _required) {
|
|
1429
|
+
validatePackageIdentifier(identifier);
|
|
1430
|
+
validatePackageFile(file, identifier);
|
|
1431
|
+
const { includeStack = [], baseDir, resolveFrom, packageResolver, readFileSync: readFileSync2 } = this.opts;
|
|
1432
|
+
const cycleKey = JSON.stringify(["package", identifier, file]);
|
|
1433
|
+
if (includeStack.includes(cycleKey)) {
|
|
1434
|
+
throw new ResolveError(
|
|
1435
|
+
`circular include: package("${identifier}", "${file}")`,
|
|
1436
|
+
`${identifier}/${file}`,
|
|
1437
|
+
0,
|
|
1438
|
+
0
|
|
1439
|
+
);
|
|
1440
|
+
}
|
|
1441
|
+
if (includeStack.length >= 50) {
|
|
1442
|
+
throw new ResolveError(`include depth limit exceeded (max 50)`, `${identifier}/${file}`, 0, 0);
|
|
1443
|
+
}
|
|
1444
|
+
const resolver = packageResolver ?? ((id, f, includingFile, bDir) => defaultPackageResolver(id, f, includingFile, bDir, resolveFrom));
|
|
1445
|
+
const resolvedPath = resolver(identifier, file, void 0, baseDir);
|
|
1446
|
+
const content = readFileSync2(resolvedPath);
|
|
1447
|
+
if (content.length === 0) return makeResObj();
|
|
1448
|
+
const tokens = tokenize(content);
|
|
1449
|
+
assertNonEmptyDocument(tokens, resolvedPath);
|
|
1450
|
+
const ast = parseTokens(tokens);
|
|
1451
|
+
return this.onBuildResObj(ast, {
|
|
1452
|
+
...this.opts,
|
|
1453
|
+
baseDir: nodePath.dirname(resolvedPath),
|
|
1454
|
+
includeStack: [...includeStack, cycleKey]
|
|
1455
|
+
});
|
|
1456
|
+
}
|
|
1457
|
+
/**
|
|
1458
|
+
* Async variant of `loadPackage`.
|
|
1459
|
+
*/
|
|
1460
|
+
async loadPackageAsync(identifier, file, _required) {
|
|
1461
|
+
validatePackageIdentifier(identifier);
|
|
1462
|
+
validatePackageFile(file, identifier);
|
|
1463
|
+
const { includeStack = [], baseDir, resolveFrom, packageResolver, readFile, readFileSync: readFileSync2 } = this.opts;
|
|
1464
|
+
const cycleKey = JSON.stringify(["package", identifier, file]);
|
|
1465
|
+
if (includeStack.includes(cycleKey)) {
|
|
1466
|
+
throw new ResolveError(
|
|
1467
|
+
`circular include: package("${identifier}", "${file}")`,
|
|
1468
|
+
`${identifier}/${file}`,
|
|
1469
|
+
0,
|
|
1470
|
+
0
|
|
1471
|
+
);
|
|
1472
|
+
}
|
|
1473
|
+
if (includeStack.length >= 50) {
|
|
1474
|
+
throw new ResolveError(`include depth limit exceeded (max 50)`, `${identifier}/${file}`, 0, 0);
|
|
1475
|
+
}
|
|
1476
|
+
const resolver = packageResolver ?? ((id, f, includingFile, bDir) => defaultPackageResolver(id, f, includingFile, bDir, resolveFrom));
|
|
1477
|
+
const resolvedPath = resolver(identifier, file, void 0, baseDir);
|
|
1478
|
+
const read = readFile ? async (p) => readFile(p) : async (p) => readFileSync2(p);
|
|
1479
|
+
const content = await read(resolvedPath);
|
|
1480
|
+
if (content.length === 0) return makeResObj();
|
|
1481
|
+
const tokens = tokenize(content);
|
|
1482
|
+
assertNonEmptyDocument(tokens, resolvedPath);
|
|
1483
|
+
const ast = parseTokens(tokens);
|
|
1484
|
+
return this.onBuildResObjAsync(ast, {
|
|
1485
|
+
...this.opts,
|
|
1486
|
+
baseDir: nodePath.dirname(resolvedPath),
|
|
1487
|
+
includeStack: [...includeStack, cycleKey]
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1392
1490
|
loadSingle(candidate) {
|
|
1393
|
-
const { readFileSync: readFileSync2, includeStack = []
|
|
1491
|
+
const { readFileSync: readFileSync2, includeStack = [] } = this.opts;
|
|
1394
1492
|
if (includeStack.includes(candidate)) {
|
|
1395
1493
|
throw new ResolveError(`circular include: ${candidate}`, candidate, 0, 0);
|
|
1396
1494
|
}
|
|
@@ -1405,17 +1503,18 @@ var IncludeLoader = class {
|
|
|
1405
1503
|
return hoconValueToResObj(propertiesToHoconValue(content));
|
|
1406
1504
|
}
|
|
1407
1505
|
const tokens = tokenize(content);
|
|
1408
|
-
|
|
1506
|
+
if (!hasContentTokens(tokens)) {
|
|
1507
|
+
return makeResObj();
|
|
1508
|
+
}
|
|
1409
1509
|
const ast = parseTokens(tokens);
|
|
1410
1510
|
return this.onBuildResObj(ast, {
|
|
1411
|
-
|
|
1511
|
+
...this.opts,
|
|
1412
1512
|
baseDir: nodePath.dirname(candidate),
|
|
1413
|
-
readFileSync: readFileSync2,
|
|
1414
1513
|
includeStack: [...includeStack, candidate]
|
|
1415
1514
|
});
|
|
1416
1515
|
}
|
|
1417
1516
|
async loadSingleAsync(candidate) {
|
|
1418
|
-
const { readFile, readFileSync: readFileSync2, includeStack = []
|
|
1517
|
+
const { readFile, readFileSync: readFileSync2, includeStack = [] } = this.opts;
|
|
1419
1518
|
const read = readFile ? async (p) => readFile(p) : async (p) => readFileSync2(p);
|
|
1420
1519
|
if (includeStack.includes(candidate)) {
|
|
1421
1520
|
throw new ResolveError(`circular include: ${candidate}`, candidate, 0, 0);
|
|
@@ -1431,13 +1530,13 @@ var IncludeLoader = class {
|
|
|
1431
1530
|
return hoconValueToResObj(propertiesToHoconValue(content));
|
|
1432
1531
|
}
|
|
1433
1532
|
const tokens = tokenize(content);
|
|
1434
|
-
|
|
1533
|
+
if (!hasContentTokens(tokens)) {
|
|
1534
|
+
return makeResObj();
|
|
1535
|
+
}
|
|
1435
1536
|
const ast = parseTokens(tokens);
|
|
1436
1537
|
return this.onBuildResObjAsync(ast, {
|
|
1437
|
-
|
|
1538
|
+
...this.opts,
|
|
1438
1539
|
baseDir: nodePath.dirname(candidate),
|
|
1439
|
-
readFileSync: readFileSync2,
|
|
1440
|
-
readFile,
|
|
1441
1540
|
includeStack: [...includeStack, candidate]
|
|
1442
1541
|
});
|
|
1443
1542
|
}
|
|
@@ -1446,7 +1545,6 @@ var IncludeLoader = class {
|
|
|
1446
1545
|
// src/internal/resolver/structure-builder.ts
|
|
1447
1546
|
var StructureBuilder = class _StructureBuilder {
|
|
1448
1547
|
constructor(opts) {
|
|
1449
|
-
this.opts = opts;
|
|
1450
1548
|
this.loader = new IncludeLoader(opts);
|
|
1451
1549
|
this.loader.onBuildResObj = (a, o) => new _StructureBuilder(o).build(a);
|
|
1452
1550
|
this.loader.onBuildResObjAsync = async (a, o) => new _StructureBuilder(o).buildAsync(a);
|
|
@@ -1473,7 +1571,13 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1473
1571
|
}
|
|
1474
1572
|
applyField(obj, field, pathPrefix) {
|
|
1475
1573
|
if (field.key.length === 0 && field.value.kind === "include") {
|
|
1476
|
-
const
|
|
1574
|
+
const { qualifier, path: path2, required } = field.value;
|
|
1575
|
+
let included;
|
|
1576
|
+
if (qualifier.kind === "package") {
|
|
1577
|
+
included = this.loader.loadPackage(qualifier.identifier, path2, required);
|
|
1578
|
+
} else {
|
|
1579
|
+
included = this.loader.load(path2, required, qualifier.kind === "file");
|
|
1580
|
+
}
|
|
1477
1581
|
if (pathPrefix.length > 0) {
|
|
1478
1582
|
this.relativizeResObj(included, pathPrefix);
|
|
1479
1583
|
}
|
|
@@ -1515,7 +1619,13 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1515
1619
|
}
|
|
1516
1620
|
async applyFieldAsync(obj, field, pathPrefix) {
|
|
1517
1621
|
if (field.key.length === 0 && field.value.kind === "include") {
|
|
1518
|
-
const
|
|
1622
|
+
const { qualifier, path: path2, required } = field.value;
|
|
1623
|
+
let included;
|
|
1624
|
+
if (qualifier.kind === "package") {
|
|
1625
|
+
included = await this.loader.loadPackageAsync(qualifier.identifier, path2, required);
|
|
1626
|
+
} else {
|
|
1627
|
+
included = await this.loader.loadAsync(path2, required, qualifier.kind === "file");
|
|
1628
|
+
}
|
|
1519
1629
|
if (pathPrefix.length > 0) {
|
|
1520
1630
|
this.relativizeResObj(included, pathPrefix);
|
|
1521
1631
|
}
|
|
@@ -1645,6 +1755,23 @@ var StructureBuilder = class _StructureBuilder {
|
|
|
1645
1755
|
}
|
|
1646
1756
|
};
|
|
1647
1757
|
|
|
1758
|
+
// src/value/numeric-array.ts
|
|
1759
|
+
function numericObjectToArray(value) {
|
|
1760
|
+
if (value.kind !== "object") return null;
|
|
1761
|
+
if (value.fields.size === 0) return null;
|
|
1762
|
+
const canonicalInt = /^(0|[1-9][0-9]*)$/;
|
|
1763
|
+
const eligible = [];
|
|
1764
|
+
for (const [key, val] of value.fields) {
|
|
1765
|
+
if (!canonicalInt.test(key)) continue;
|
|
1766
|
+
const n = Number(key);
|
|
1767
|
+
if (!Number.isInteger(n) || n > 2147483647) continue;
|
|
1768
|
+
eligible.push({ n, v: val });
|
|
1769
|
+
}
|
|
1770
|
+
if (eligible.length === 0) return null;
|
|
1771
|
+
eligible.sort((a, b) => a.n - b.n);
|
|
1772
|
+
return eligible.map((e) => e.v);
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1648
1775
|
// src/internal/resolver/substitution-resolver.ts
|
|
1649
1776
|
var SubstitutionResolver = class {
|
|
1650
1777
|
constructor(root, opts) {
|
|
@@ -1666,6 +1793,10 @@ var SubstitutionResolver = class {
|
|
|
1666
1793
|
// xx.hocon PR (see Phase 6 #3f close-out notes).
|
|
1667
1794
|
this.resolvingConcats = /* @__PURE__ */ new WeakSet();
|
|
1668
1795
|
}
|
|
1796
|
+
/** Returns a prefix for error messages, including origin info when set. */
|
|
1797
|
+
originPrefix() {
|
|
1798
|
+
return this.opts.originDescription ? `${this.opts.originDescription}: ` : "";
|
|
1799
|
+
}
|
|
1669
1800
|
resolve() {
|
|
1670
1801
|
return this.resolveResObj(this.root);
|
|
1671
1802
|
}
|
|
@@ -1706,7 +1837,8 @@ var SubstitutionResolver = class {
|
|
|
1706
1837
|
if (isConcat(v)) {
|
|
1707
1838
|
this.resolvingConcats.add(v);
|
|
1708
1839
|
try {
|
|
1709
|
-
|
|
1840
|
+
const concatResult = this.resolveConcat(v.nodes, scope, v.line, v.col);
|
|
1841
|
+
return concatResult;
|
|
1710
1842
|
} finally {
|
|
1711
1843
|
this.resolvingConcats.delete(v);
|
|
1712
1844
|
}
|
|
@@ -1751,7 +1883,7 @@ var SubstitutionResolver = class {
|
|
|
1751
1883
|
}
|
|
1752
1884
|
if (s.optional) return void 0;
|
|
1753
1885
|
throw new ResolveError(
|
|
1754
|
-
`circular substitution: ${key}`,
|
|
1886
|
+
this.originPrefix() + `circular substitution: ${key}`,
|
|
1755
1887
|
key,
|
|
1756
1888
|
s.line,
|
|
1757
1889
|
s.col
|
|
@@ -1781,7 +1913,7 @@ var SubstitutionResolver = class {
|
|
|
1781
1913
|
}
|
|
1782
1914
|
if (s.optional) return void 0;
|
|
1783
1915
|
throw new ResolveError(
|
|
1784
|
-
|
|
1916
|
+
`${this.originPrefix()}could not resolve substitution: \${${key}}`,
|
|
1785
1917
|
key,
|
|
1786
1918
|
s.line,
|
|
1787
1919
|
s.col
|
|
@@ -1814,7 +1946,7 @@ var SubstitutionResolver = class {
|
|
|
1814
1946
|
if (result !== void 0) this.cache.set(key, result);
|
|
1815
1947
|
return result;
|
|
1816
1948
|
}
|
|
1817
|
-
if (s.listSuffix) {
|
|
1949
|
+
if (s.listSuffix && this.opts.useSystemEnvironment !== false) {
|
|
1818
1950
|
const result = this.resolveEnvList(s);
|
|
1819
1951
|
if (result !== void 0) {
|
|
1820
1952
|
this.cache.set(key, result);
|
|
@@ -1823,22 +1955,36 @@ var SubstitutionResolver = class {
|
|
|
1823
1955
|
if (s.optional) return void 0;
|
|
1824
1956
|
const envBase = s.segments.map((seg) => seg.text).join(".");
|
|
1825
1957
|
throw new ResolveError(
|
|
1826
|
-
|
|
1958
|
+
`${this.originPrefix()}could not resolve substitution: \${${key}} (no environment variables ${envBase}_0, ${envBase}_1, \u2026 set)`,
|
|
1959
|
+
key,
|
|
1960
|
+
s.line,
|
|
1961
|
+
s.col
|
|
1962
|
+
);
|
|
1963
|
+
} else if (s.listSuffix) {
|
|
1964
|
+
if (s.optional) return void 0;
|
|
1965
|
+
if (this.opts.allowUnresolved) return s;
|
|
1966
|
+
throw new ResolveError(
|
|
1967
|
+
`${this.originPrefix()}could not resolve substitution: \${${key}}`,
|
|
1827
1968
|
key,
|
|
1828
1969
|
s.line,
|
|
1829
1970
|
s.col
|
|
1830
1971
|
);
|
|
1831
1972
|
}
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1973
|
+
if (this.opts.useSystemEnvironment !== false) {
|
|
1974
|
+
const envKey = s.segments.map((seg) => seg.text).join(".");
|
|
1975
|
+
const envVal = this.opts.env[envKey] ?? (s.prefixLen > 0 ? this.opts.env[s.segments.slice(s.prefixLen).map((seg) => seg.text).join(".")] : void 0);
|
|
1976
|
+
if (envVal !== void 0) {
|
|
1977
|
+
const result = { kind: "scalar", raw: envVal, valueType: "string" };
|
|
1978
|
+
this.cache.set(key, result);
|
|
1979
|
+
return result;
|
|
1980
|
+
}
|
|
1838
1981
|
}
|
|
1839
1982
|
if (s.optional) return void 0;
|
|
1983
|
+
if (this.opts.allowUnresolved) {
|
|
1984
|
+
return s;
|
|
1985
|
+
}
|
|
1840
1986
|
throw new ResolveError(
|
|
1841
|
-
|
|
1987
|
+
`${this.originPrefix()}could not resolve substitution: \${${key}}`,
|
|
1842
1988
|
key,
|
|
1843
1989
|
s.line,
|
|
1844
1990
|
s.col
|
|
@@ -1883,8 +2029,16 @@ var SubstitutionResolver = class {
|
|
|
1883
2029
|
return [full, bare];
|
|
1884
2030
|
}
|
|
1885
2031
|
resolveConcat(nodes, scope, line = 0, col = 0) {
|
|
1886
|
-
const
|
|
1887
|
-
if (
|
|
2032
|
+
const rawResolved = nodes.map((n) => this.resolveVal(n, scope));
|
|
2033
|
+
if (this.opts.allowUnresolved) {
|
|
2034
|
+
for (const v of rawResolved) {
|
|
2035
|
+
if (v !== void 0 && isSubst(v)) {
|
|
2036
|
+
return v;
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
const resolved = rawResolved.filter((v) => v !== void 0);
|
|
2041
|
+
if (resolved.length === 0) return void 0;
|
|
1888
2042
|
if (resolved.length === 1) return resolved[0];
|
|
1889
2043
|
const nonSep = resolved.filter((v) => !separatorValues.has(v));
|
|
1890
2044
|
if (nonSep.length === 0) {
|
|
@@ -1958,24 +2112,509 @@ var SubstitutionResolver = class {
|
|
|
1958
2112
|
};
|
|
1959
2113
|
|
|
1960
2114
|
// src/internal/resolver/resolver.ts
|
|
1961
|
-
function
|
|
1962
|
-
|
|
1963
|
-
return new SubstitutionResolver(root, opts).resolve();
|
|
2115
|
+
function buildTree(ast, opts) {
|
|
2116
|
+
return new StructureBuilder(opts).build(ast);
|
|
1964
2117
|
}
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
return new SubstitutionResolver(root, opts).resolve();
|
|
2118
|
+
function resolveTree(tree, opts) {
|
|
2119
|
+
return new SubstitutionResolver(tree, opts).resolve();
|
|
1968
2120
|
}
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
if (opts.env !== void 0) return opts.env;
|
|
1975
|
-
if (typeof process !== "undefined" && process.env) return process.env;
|
|
1976
|
-
return {};
|
|
2121
|
+
function containsPlaceholders(tree) {
|
|
2122
|
+
for (const val of tree.fields.values()) {
|
|
2123
|
+
if (valContainsPlaceholders(val)) return true;
|
|
2124
|
+
}
|
|
2125
|
+
return false;
|
|
1977
2126
|
}
|
|
1978
|
-
function
|
|
2127
|
+
function valContainsPlaceholders(v) {
|
|
2128
|
+
const rv = v;
|
|
2129
|
+
if (isSubst(rv) || isConcat(rv) || isAppend(rv)) return true;
|
|
2130
|
+
if (isResObj(rv)) return containsPlaceholders(rv);
|
|
2131
|
+
const hv = v;
|
|
2132
|
+
if (hv?.kind === "array") {
|
|
2133
|
+
return hv.items.some((item) => valContainsPlaceholders(item));
|
|
2134
|
+
}
|
|
2135
|
+
return false;
|
|
2136
|
+
}
|
|
2137
|
+
function buildPartialHoconFromResObj(tree) {
|
|
2138
|
+
const fields = /* @__PURE__ */ new Map();
|
|
2139
|
+
for (const [k, v] of tree.fields) {
|
|
2140
|
+
if (!isSubst(v) && !isConcat(v) && !isAppend(v)) {
|
|
2141
|
+
if (isResObj(v)) {
|
|
2142
|
+
fields.set(k, buildPartialHoconFromResObj(v));
|
|
2143
|
+
} else {
|
|
2144
|
+
if (!valContainsPlaceholders(v)) {
|
|
2145
|
+
fields.set(k, v);
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
return { kind: "object", fields };
|
|
2151
|
+
}
|
|
2152
|
+
function hoconValueToResObj2(value) {
|
|
2153
|
+
const obj = makeResObj();
|
|
2154
|
+
for (const [k, v] of value.fields) {
|
|
2155
|
+
if (v.kind === "object") {
|
|
2156
|
+
obj.fields.set(k, hoconValueToResObj2(v));
|
|
2157
|
+
} else {
|
|
2158
|
+
obj.fields.set(k, v);
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
return obj;
|
|
2162
|
+
}
|
|
2163
|
+
function resolve2(ast, opts) {
|
|
2164
|
+
const tree = buildTree(ast, opts);
|
|
2165
|
+
return resolveTree(tree, { ...opts, useSystemEnvironment: true, allowUnresolved: false });
|
|
2166
|
+
}
|
|
2167
|
+
async function resolveAsync(ast, opts) {
|
|
2168
|
+
const root = await new StructureBuilder(opts).buildAsync(ast);
|
|
2169
|
+
return resolveTree(root, { ...opts, useSystemEnvironment: true, allowUnresolved: false });
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
// src/config.ts
|
|
2173
|
+
var Config = class _Config {
|
|
2174
|
+
constructor(root, opts) {
|
|
2175
|
+
this.root = root;
|
|
2176
|
+
this._resolved = opts?.resolved ?? true;
|
|
2177
|
+
this._parseBaseDir = opts?.parseBaseDir;
|
|
2178
|
+
this._originDescription = opts?.originDescription;
|
|
2179
|
+
this._resObjRoot = opts?.resObjRoot;
|
|
2180
|
+
this._resolveOpts = opts?.resolveOpts;
|
|
2181
|
+
}
|
|
2182
|
+
/** Returns true when the Config's value tree contains no unresolved
|
|
2183
|
+
* substitution placeholders. Whole-config granularity (E12 decision 11). */
|
|
2184
|
+
isResolved() {
|
|
2185
|
+
return this._resolved;
|
|
2186
|
+
}
|
|
2187
|
+
/** @internal Test-only: construct a resolved Config from a HoconValue. */
|
|
2188
|
+
static _fromResolvedValue(root, opts) {
|
|
2189
|
+
return new _Config(root, { resolved: true, originDescription: opts?.originDescription });
|
|
2190
|
+
}
|
|
2191
|
+
/** @internal Construct an unresolved Config carrying a ResObj tree.
|
|
2192
|
+
* Used by parseStringWithOptions (deferred path) in T6. */
|
|
2193
|
+
static _fromUnresolvedResObj(tree, opts) {
|
|
2194
|
+
const partialRoot = buildPartialHoconFromResObj(tree);
|
|
2195
|
+
return new _Config(partialRoot, {
|
|
2196
|
+
resolved: opts.resolved,
|
|
2197
|
+
parseBaseDir: opts.parseBaseDir,
|
|
2198
|
+
originDescription: opts.originDescription,
|
|
2199
|
+
resObjRoot: tree,
|
|
2200
|
+
resolveOpts: opts.resolveOpts
|
|
2201
|
+
});
|
|
2202
|
+
}
|
|
2203
|
+
get(path2) {
|
|
2204
|
+
const v = this.lookupNode(path2);
|
|
2205
|
+
if (v === void 0) return void 0;
|
|
2206
|
+
return hoconToJs(v);
|
|
2207
|
+
}
|
|
2208
|
+
getString(path2) {
|
|
2209
|
+
const v = this.requireScalar(path2);
|
|
2210
|
+
return v.raw;
|
|
2211
|
+
}
|
|
2212
|
+
getNumber(path2) {
|
|
2213
|
+
const v = this.requireScalar(path2);
|
|
2214
|
+
const coerced = coerceNumber(v.raw);
|
|
2215
|
+
if (coerced !== void 0) return coerced;
|
|
2216
|
+
throw new ConfigError(`expected number at ${path2}, got ${v.valueType}`, path2);
|
|
2217
|
+
}
|
|
2218
|
+
getBoolean(path2) {
|
|
2219
|
+
const v = this.requireScalar(path2);
|
|
2220
|
+
const coerced = coerceBoolean(v.raw);
|
|
2221
|
+
if (coerced !== void 0) return coerced;
|
|
2222
|
+
throw new ConfigError(`expected boolean at ${path2}, got ${v.valueType}`, path2);
|
|
2223
|
+
}
|
|
2224
|
+
getDuration(path2, unit) {
|
|
2225
|
+
const v = this.requireScalar(path2);
|
|
2226
|
+
if (v.valueType !== "string" && v.valueType !== "number") {
|
|
2227
|
+
throw new ConfigError(`expected duration at ${path2}, got ${v.valueType}`, path2);
|
|
2228
|
+
}
|
|
2229
|
+
const result = parseDuration(v.raw, unit);
|
|
2230
|
+
if (Number.isNaN(result)) throw new ConfigError(`invalid duration at ${path2}: ${JSON.stringify(v.raw)}`, path2);
|
|
2231
|
+
return result;
|
|
2232
|
+
}
|
|
2233
|
+
getBytes(path2, unit) {
|
|
2234
|
+
const v = this.requireScalar(path2);
|
|
2235
|
+
if (v.valueType !== "string" && v.valueType !== "number") {
|
|
2236
|
+
throw new ConfigError(`expected byte size at ${path2}, got ${v.valueType}`, path2);
|
|
2237
|
+
}
|
|
2238
|
+
const result = parseBytes(v.raw, unit);
|
|
2239
|
+
if (Number.isNaN(result)) throw new ConfigError(`invalid byte size at ${path2}: ${JSON.stringify(v.raw)}`, path2);
|
|
2240
|
+
if (result < 0) throw new ConfigError(`byte size must be non-negative at ${path2}: ${JSON.stringify(v.raw)}`, path2);
|
|
2241
|
+
return result;
|
|
2242
|
+
}
|
|
2243
|
+
getConfig(path2) {
|
|
2244
|
+
const v = this.lookupNode(path2);
|
|
2245
|
+
if (v === void 0) {
|
|
2246
|
+
if (!this._resolved && this._resObjRootSubtreeHasPlaceholders(path2)) {
|
|
2247
|
+
throw new NotResolvedError(path2);
|
|
2248
|
+
}
|
|
2249
|
+
throw new ConfigError(`path not found: ${path2}`, path2);
|
|
2250
|
+
}
|
|
2251
|
+
if (v.kind !== "object") throw new ConfigError(`expected object at ${path2}`, path2);
|
|
2252
|
+
if (!this._resolved && this._resObjRootSubtreeHasPlaceholders(path2)) {
|
|
2253
|
+
throw new NotResolvedError(path2);
|
|
2254
|
+
}
|
|
2255
|
+
return new _Config(v, { resolved: this._resolved });
|
|
2256
|
+
}
|
|
2257
|
+
getList(path2) {
|
|
2258
|
+
const v = this.lookupNode(path2);
|
|
2259
|
+
if (v === void 0) {
|
|
2260
|
+
if (!this._resolved && this._resObjRootSubtreeHasPlaceholders(path2)) {
|
|
2261
|
+
throw new NotResolvedError(path2);
|
|
2262
|
+
}
|
|
2263
|
+
throw new ConfigError(`path not found: ${path2}`, path2);
|
|
2264
|
+
}
|
|
2265
|
+
if (!this._resolved && this._resObjRootSubtreeHasPlaceholders(path2)) {
|
|
2266
|
+
throw new NotResolvedError(path2);
|
|
2267
|
+
}
|
|
2268
|
+
if (v.kind === "object") {
|
|
2269
|
+
const converted = numericObjectToArray(v);
|
|
2270
|
+
if (converted !== null) return converted.map(hoconToJs);
|
|
2271
|
+
}
|
|
2272
|
+
if (v.kind !== "array") throw new ConfigError(`expected array at ${path2}`, path2);
|
|
2273
|
+
return v.items.map(hoconToJs);
|
|
2274
|
+
}
|
|
2275
|
+
has(path2) {
|
|
2276
|
+
return this.lookupNode(path2) !== void 0;
|
|
2277
|
+
}
|
|
2278
|
+
keys() {
|
|
2279
|
+
return [...this.root.fields.keys()];
|
|
2280
|
+
}
|
|
2281
|
+
withFallback(fallback) {
|
|
2282
|
+
if (fallback == null) return this;
|
|
2283
|
+
const selfTree = this._resObjRoot ?? hoconValueToResObj2(this.root);
|
|
2284
|
+
const fbTree = fallback._resObjRoot ?? hoconValueToResObj2(fallback.root);
|
|
2285
|
+
const merged = mergeUnresolved(selfTree, fbTree);
|
|
2286
|
+
const hasPlaceholders = containsPlaceholders(merged);
|
|
2287
|
+
const partialRoot = buildPartialHoconFromResObj(merged);
|
|
2288
|
+
return new _Config(partialRoot, {
|
|
2289
|
+
resolved: !hasPlaceholders,
|
|
2290
|
+
parseBaseDir: this._parseBaseDir,
|
|
2291
|
+
originDescription: this._originDescription,
|
|
2292
|
+
resObjRoot: merged,
|
|
2293
|
+
resolveOpts: this._resolveOpts ?? fallback._resolveOpts
|
|
2294
|
+
});
|
|
2295
|
+
}
|
|
2296
|
+
/**
|
|
2297
|
+
* Runs substitution resolution (phase 2) on the stored unresolved tree.
|
|
2298
|
+
* Idempotent: calling resolve() on an already-resolved Config returns an
|
|
2299
|
+
* equivalent resolved Config.
|
|
2300
|
+
*
|
|
2301
|
+
* opts.allowUnresolved (default false) — when true, leaves unresolved
|
|
2302
|
+
* non-optional placeholders in place rather than throwing.
|
|
2303
|
+
* opts.useSystemEnvironment (default true) — when false, env var lookups
|
|
2304
|
+
* are suppressed (hermetic resolution).
|
|
2305
|
+
*
|
|
2306
|
+
* E12 decision 3.
|
|
2307
|
+
*/
|
|
2308
|
+
resolve(opts = {}) {
|
|
2309
|
+
if (this._resolved) {
|
|
2310
|
+
return new _Config(this.root, {
|
|
2311
|
+
resolved: true,
|
|
2312
|
+
parseBaseDir: this._parseBaseDir,
|
|
2313
|
+
originDescription: this._originDescription
|
|
2314
|
+
});
|
|
2315
|
+
}
|
|
2316
|
+
const tree = this._resObjRoot;
|
|
2317
|
+
if (!tree) {
|
|
2318
|
+
return new _Config(this.root, { resolved: true });
|
|
2319
|
+
}
|
|
2320
|
+
const resolveOpts = {
|
|
2321
|
+
...this._resolveOpts ?? { env: {}, baseDir: void 0, readFileSync: () => {
|
|
2322
|
+
throw new Error("no files");
|
|
2323
|
+
} },
|
|
2324
|
+
allowUnresolved: opts.allowUnresolved ?? false,
|
|
2325
|
+
useSystemEnvironment: opts.useSystemEnvironment ?? true,
|
|
2326
|
+
originDescription: this._originDescription
|
|
2327
|
+
};
|
|
2328
|
+
const resolved = resolveTree(tree, resolveOpts);
|
|
2329
|
+
if (resolved.kind !== "object") throw new Error("resolve: expected object root");
|
|
2330
|
+
if (opts.allowUnresolved) {
|
|
2331
|
+
const { stripped, hadPlaceholders } = stripPlaceholderFields(resolved);
|
|
2332
|
+
return new _Config(stripped, {
|
|
2333
|
+
resolved: !hadPlaceholders,
|
|
2334
|
+
parseBaseDir: this._parseBaseDir,
|
|
2335
|
+
originDescription: this._originDescription,
|
|
2336
|
+
resObjRoot: hadPlaceholders ? tree : void 0,
|
|
2337
|
+
resolveOpts: hadPlaceholders ? resolveOpts : void 0
|
|
2338
|
+
});
|
|
2339
|
+
}
|
|
2340
|
+
return new _Config(resolved, {
|
|
2341
|
+
resolved: true,
|
|
2342
|
+
parseBaseDir: this._parseBaseDir,
|
|
2343
|
+
originDescription: this._originDescription
|
|
2344
|
+
});
|
|
2345
|
+
}
|
|
2346
|
+
/**
|
|
2347
|
+
* Resolves receiver substitutions using source as lookup context.
|
|
2348
|
+
* Source's keys are NOT merged into the result — differs from
|
|
2349
|
+
* `this.withFallback(source).resolve()` which includes source keys.
|
|
2350
|
+
*
|
|
2351
|
+
* Precondition (E12 decision 10): source must be resolved. If
|
|
2352
|
+
* source.isResolved() is false, throws NotResolvedError.
|
|
2353
|
+
*
|
|
2354
|
+
* On an already-resolved receiver, resolveWith is a no-op (returns an
|
|
2355
|
+
* equivalent resolved Config, source keys not included).
|
|
2356
|
+
*
|
|
2357
|
+
* E12 decisions 9, 10.
|
|
2358
|
+
*/
|
|
2359
|
+
resolveWith(source, opts = {}) {
|
|
2360
|
+
if (!source.isResolved()) {
|
|
2361
|
+
throw new NotResolvedError("source");
|
|
2362
|
+
}
|
|
2363
|
+
if (this._resolved) {
|
|
2364
|
+
return new _Config(this.root, {
|
|
2365
|
+
resolved: true,
|
|
2366
|
+
parseBaseDir: this._parseBaseDir,
|
|
2367
|
+
originDescription: this._originDescription
|
|
2368
|
+
});
|
|
2369
|
+
}
|
|
2370
|
+
const receiverTree = this._resObjRoot ?? hoconValueToResObj2(this.root);
|
|
2371
|
+
const srcTree = hoconValueToResObj2(source.root);
|
|
2372
|
+
const merged = mergeUnresolved(receiverTree, srcTree);
|
|
2373
|
+
const resolveOpts = {
|
|
2374
|
+
...this._resolveOpts ?? { env: {}, baseDir: void 0, readFileSync: () => {
|
|
2375
|
+
throw new Error("no files");
|
|
2376
|
+
} },
|
|
2377
|
+
allowUnresolved: opts.allowUnresolved ?? false,
|
|
2378
|
+
useSystemEnvironment: opts.useSystemEnvironment ?? true,
|
|
2379
|
+
originDescription: this._originDescription
|
|
2380
|
+
};
|
|
2381
|
+
const resolved = resolveTree(merged, resolveOpts);
|
|
2382
|
+
if (resolved.kind !== "object") throw new Error("resolveWith: expected object root");
|
|
2383
|
+
const receiverShapeForFilter = resObjToKeyShape(receiverTree);
|
|
2384
|
+
const filtered = filterByReceiverShape(resolved, receiverShapeForFilter);
|
|
2385
|
+
if (opts.allowUnresolved) {
|
|
2386
|
+
const { stripped, hadPlaceholders } = stripPlaceholderFields(filtered);
|
|
2387
|
+
return new _Config(stripped, {
|
|
2388
|
+
resolved: !hadPlaceholders,
|
|
2389
|
+
parseBaseDir: this._parseBaseDir,
|
|
2390
|
+
originDescription: this._originDescription,
|
|
2391
|
+
resObjRoot: hadPlaceholders ? receiverTree : void 0,
|
|
2392
|
+
resolveOpts: hadPlaceholders ? resolveOpts : void 0
|
|
2393
|
+
});
|
|
2394
|
+
}
|
|
2395
|
+
return new _Config(filtered, {
|
|
2396
|
+
resolved: true,
|
|
2397
|
+
parseBaseDir: this._parseBaseDir,
|
|
2398
|
+
originDescription: this._originDescription
|
|
2399
|
+
});
|
|
2400
|
+
}
|
|
2401
|
+
toObject() {
|
|
2402
|
+
return hoconToJs(this.root);
|
|
2403
|
+
}
|
|
2404
|
+
/**
|
|
2405
|
+
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
2406
|
+
* JSON (sorted keys, no whitespace). Used by Layer-2 fixture tests to compare
|
|
2407
|
+
* against Lightbend ground truth. NOT part of the public API.
|
|
2408
|
+
*
|
|
2409
|
+
* Throws if the Config is unresolved (contains placeholders).
|
|
2410
|
+
*/
|
|
2411
|
+
_renderJSONForTest() {
|
|
2412
|
+
return renderHoconAsJSON(this.root);
|
|
2413
|
+
}
|
|
2414
|
+
lookupNode(path2) {
|
|
2415
|
+
const segments = splitConfigPath(path2);
|
|
2416
|
+
let current = this.root;
|
|
2417
|
+
for (const seg of segments) {
|
|
2418
|
+
if (current.kind !== "object") return void 0;
|
|
2419
|
+
const next = current.fields.get(seg);
|
|
2420
|
+
if (next === void 0) return void 0;
|
|
2421
|
+
current = next;
|
|
2422
|
+
}
|
|
2423
|
+
return current;
|
|
2424
|
+
}
|
|
2425
|
+
/**
|
|
2426
|
+
* _resObjRootSubtreeHasPlaceholders — walk _resObjRoot to the given path and
|
|
2427
|
+
* return true if the subtree there contains any unresolved placeholder.
|
|
2428
|
+
* Used by getConfig / getList (T2) to detect transitive unresolved placeholders
|
|
2429
|
+
* in object / array subtrees that would otherwise appear to be "resolved" in the
|
|
2430
|
+
* partial HoconValue root (because individual leaf fields are omitted rather than
|
|
2431
|
+
* the whole subtree when their value is a direct placeholder scalar, but object
|
|
2432
|
+
* sub-containers are retained in the partial root with the placeholder-keyed
|
|
2433
|
+
* fields omitted from them — so the object appears "present but empty-ish").
|
|
2434
|
+
*/
|
|
2435
|
+
_resObjRootSubtreeHasPlaceholders(path2) {
|
|
2436
|
+
const tree = this._resObjRoot;
|
|
2437
|
+
if (!tree) return false;
|
|
2438
|
+
const segments = splitConfigPath(path2);
|
|
2439
|
+
let cur = tree;
|
|
2440
|
+
for (const seg of segments) {
|
|
2441
|
+
const val = cur.fields.get(seg);
|
|
2442
|
+
if (val === void 0) return false;
|
|
2443
|
+
if (isResObj(val)) {
|
|
2444
|
+
cur = val;
|
|
2445
|
+
} else {
|
|
2446
|
+
return valContainsPlaceholders(val);
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2449
|
+
return containsPlaceholders(cur);
|
|
2450
|
+
}
|
|
2451
|
+
requireScalar(path2) {
|
|
2452
|
+
const v = this.lookupNode(path2);
|
|
2453
|
+
if (v === void 0) {
|
|
2454
|
+
if (!this._resolved && this._resObjRootSubtreeHasPlaceholders(path2)) {
|
|
2455
|
+
throw new NotResolvedError(path2);
|
|
2456
|
+
}
|
|
2457
|
+
throw new ConfigError(`path not found: ${path2}`, path2);
|
|
2458
|
+
}
|
|
2459
|
+
if (v.kind !== "scalar") throw new ConfigError(`expected scalar at ${path2}, got ${v.kind}`, path2);
|
|
2460
|
+
return v;
|
|
2461
|
+
}
|
|
2462
|
+
};
|
|
2463
|
+
function splitConfigPath(path2) {
|
|
2464
|
+
const segments = [];
|
|
2465
|
+
let i = 0;
|
|
2466
|
+
while (i < path2.length) {
|
|
2467
|
+
if (path2[i] === '"') {
|
|
2468
|
+
i++;
|
|
2469
|
+
let segment = "";
|
|
2470
|
+
let closed = false;
|
|
2471
|
+
while (i < path2.length) {
|
|
2472
|
+
const ch = path2[i];
|
|
2473
|
+
if (ch === "\\" && i + 1 < path2.length) {
|
|
2474
|
+
const next = path2[i + 1];
|
|
2475
|
+
segment += next;
|
|
2476
|
+
i += 2;
|
|
2477
|
+
continue;
|
|
2478
|
+
}
|
|
2479
|
+
if (ch === '"') {
|
|
2480
|
+
closed = true;
|
|
2481
|
+
i++;
|
|
2482
|
+
break;
|
|
2483
|
+
}
|
|
2484
|
+
segment += ch;
|
|
2485
|
+
i++;
|
|
2486
|
+
}
|
|
2487
|
+
if (!closed) throw new ConfigError(`unterminated quoted path segment: ${path2}`, path2);
|
|
2488
|
+
segments.push(segment);
|
|
2489
|
+
if (i < path2.length && path2[i] === ".") i++;
|
|
2490
|
+
} else {
|
|
2491
|
+
const dot = path2.indexOf(".", i);
|
|
2492
|
+
if (dot === -1) {
|
|
2493
|
+
segments.push(path2.slice(i));
|
|
2494
|
+
break;
|
|
2495
|
+
}
|
|
2496
|
+
segments.push(path2.slice(i, dot));
|
|
2497
|
+
i = dot + 1;
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
return segments;
|
|
2501
|
+
}
|
|
2502
|
+
function scalarToJs(raw, valueType) {
|
|
2503
|
+
switch (valueType) {
|
|
2504
|
+
case "null":
|
|
2505
|
+
return null;
|
|
2506
|
+
case "boolean":
|
|
2507
|
+
return raw === "true";
|
|
2508
|
+
case "number":
|
|
2509
|
+
return Number(raw);
|
|
2510
|
+
case "string":
|
|
2511
|
+
return raw;
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
function hoconToJs(v) {
|
|
2515
|
+
switch (v.kind) {
|
|
2516
|
+
case "scalar":
|
|
2517
|
+
return scalarToJs(v.raw, v.valueType);
|
|
2518
|
+
case "array":
|
|
2519
|
+
return v.items.map(hoconToJs);
|
|
2520
|
+
case "object": {
|
|
2521
|
+
const obj = /* @__PURE__ */ Object.create(null);
|
|
2522
|
+
for (const [k, val] of v.fields) obj[k] = hoconToJs(val);
|
|
2523
|
+
return Object.assign({}, obj);
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
function resObjToKeyShape(tree) {
|
|
2528
|
+
const fields = /* @__PURE__ */ new Map();
|
|
2529
|
+
for (const [k, v] of tree.fields) {
|
|
2530
|
+
if (isSubst(v) || isConcat(v) || isAppend(v)) {
|
|
2531
|
+
fields.set(k, { kind: "scalar", raw: "", valueType: "null" });
|
|
2532
|
+
} else if (isResObj(v)) {
|
|
2533
|
+
fields.set(k, resObjToKeyShape(v));
|
|
2534
|
+
} else {
|
|
2535
|
+
fields.set(k, v);
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
return { kind: "object", fields };
|
|
2539
|
+
}
|
|
2540
|
+
function stripPlaceholderFields(v) {
|
|
2541
|
+
const fields = /* @__PURE__ */ new Map();
|
|
2542
|
+
let hadPlaceholders = false;
|
|
2543
|
+
for (const [k, val] of v.fields) {
|
|
2544
|
+
if (val._kind === "subst-placeholder" || val._kind === "concat-placeholder" || val._kind === "append-placeholder") {
|
|
2545
|
+
hadPlaceholders = true;
|
|
2546
|
+
} else if (val.kind === "object") {
|
|
2547
|
+
const inner = stripPlaceholderFields(val);
|
|
2548
|
+
if (inner.hadPlaceholders) hadPlaceholders = true;
|
|
2549
|
+
fields.set(k, inner.stripped);
|
|
2550
|
+
} else {
|
|
2551
|
+
fields.set(k, val);
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
return { stripped: { kind: "object", fields }, hadPlaceholders };
|
|
2555
|
+
}
|
|
2556
|
+
function filterByReceiverShape(resolved, receiverShape) {
|
|
2557
|
+
const fields = /* @__PURE__ */ new Map();
|
|
2558
|
+
for (const [k, rv] of resolved.fields) {
|
|
2559
|
+
if (!receiverShape.fields.has(k)) continue;
|
|
2560
|
+
const receiverVal = receiverShape.fields.get(k);
|
|
2561
|
+
if (rv.kind === "object" && receiverVal.kind === "object") {
|
|
2562
|
+
fields.set(k, filterByReceiverShape(rv, receiverVal));
|
|
2563
|
+
} else {
|
|
2564
|
+
fields.set(k, rv);
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
return { kind: "object", fields };
|
|
2568
|
+
}
|
|
2569
|
+
function renderHoconAsJSON(v) {
|
|
2570
|
+
switch (v.kind) {
|
|
2571
|
+
case "scalar": {
|
|
2572
|
+
switch (v.valueType) {
|
|
2573
|
+
case "null":
|
|
2574
|
+
return "null";
|
|
2575
|
+
case "boolean":
|
|
2576
|
+
return v.raw;
|
|
2577
|
+
case "number": {
|
|
2578
|
+
const n = Number(v.raw);
|
|
2579
|
+
if (Number.isFinite(n)) return v.raw;
|
|
2580
|
+
return JSON.stringify(v.raw);
|
|
2581
|
+
}
|
|
2582
|
+
case "string":
|
|
2583
|
+
return JSON.stringify(v.raw);
|
|
2584
|
+
}
|
|
2585
|
+
break;
|
|
2586
|
+
}
|
|
2587
|
+
case "array": {
|
|
2588
|
+
const items = v.items.map(renderHoconAsJSON);
|
|
2589
|
+
return `[${items.join(",")}]`;
|
|
2590
|
+
}
|
|
2591
|
+
case "object": {
|
|
2592
|
+
const keys = [...v.fields.keys()].sort();
|
|
2593
|
+
const pairs = keys.map((k) => {
|
|
2594
|
+
const val = v.fields.get(k);
|
|
2595
|
+
return `${JSON.stringify(k)}:${renderHoconAsJSON(val)}`;
|
|
2596
|
+
});
|
|
2597
|
+
return `{${pairs.join(",")}}`;
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
throw new Error(`renderHoconAsJSON: unsupported value kind (unresolved placeholder?)`);
|
|
2601
|
+
}
|
|
2602
|
+
|
|
2603
|
+
// src/parse.ts
|
|
2604
|
+
var fs = __toESM(require("fs"), 1);
|
|
2605
|
+
var path = __toESM(require("path"), 1);
|
|
2606
|
+
function defaultParseOptions() {
|
|
2607
|
+
return { resolveSubstitutions: true };
|
|
2608
|
+
}
|
|
2609
|
+
function defaultResolveOptions() {
|
|
2610
|
+
return { useSystemEnvironment: true, allowUnresolved: false };
|
|
2611
|
+
}
|
|
2612
|
+
function getEnv(opts) {
|
|
2613
|
+
if (opts.env !== void 0) return opts.env;
|
|
2614
|
+
if (typeof process !== "undefined" && process.env) return process.env;
|
|
2615
|
+
return {};
|
|
2616
|
+
}
|
|
2617
|
+
function defaultReadFileSync(filePath) {
|
|
1979
2618
|
return fs.readFileSync(filePath, "utf-8");
|
|
1980
2619
|
}
|
|
1981
2620
|
async function defaultReadFile(filePath) {
|
|
@@ -1989,7 +2628,10 @@ function buildResolveContext(input, opts) {
|
|
|
1989
2628
|
env: getEnv(opts),
|
|
1990
2629
|
baseDir: opts.baseDir,
|
|
1991
2630
|
readFileSync: opts.readFileSync ?? defaultReadFileSync,
|
|
1992
|
-
readFile: opts.readFile
|
|
2631
|
+
readFile: opts.readFile,
|
|
2632
|
+
originDescription: opts.originDescription,
|
|
2633
|
+
resolveFrom: opts.resolveFrom,
|
|
2634
|
+
packageResolver: opts.packageResolver
|
|
1993
2635
|
};
|
|
1994
2636
|
return { ast, resolveOpts };
|
|
1995
2637
|
}
|
|
@@ -1997,7 +2639,38 @@ function parse(input, opts = {}) {
|
|
|
1997
2639
|
const { ast, resolveOpts } = buildResolveContext(input, opts);
|
|
1998
2640
|
const value = resolve2(ast, resolveOpts);
|
|
1999
2641
|
if (value.kind !== "object") throw new Error("resolved value is not an object");
|
|
2000
|
-
return new Config(value);
|
|
2642
|
+
return new Config(value, { resolved: true, originDescription: opts.originDescription });
|
|
2643
|
+
}
|
|
2644
|
+
var parseString = parse;
|
|
2645
|
+
function parseStringWithOptions(input, opts = {}) {
|
|
2646
|
+
const resolveSubstitutions = opts.resolveSubstitutions ?? true;
|
|
2647
|
+
const { ast, resolveOpts } = buildResolveContext(input, opts);
|
|
2648
|
+
if (resolveSubstitutions) {
|
|
2649
|
+
const value = resolve2(ast, resolveOpts);
|
|
2650
|
+
if (value.kind !== "object") throw new Error("resolved value is not an object");
|
|
2651
|
+
return new Config(value, { resolved: true, originDescription: opts.originDescription });
|
|
2652
|
+
}
|
|
2653
|
+
const tree = buildTree(ast, resolveOpts);
|
|
2654
|
+
const hasPlaceholders = containsPlaceholders(tree);
|
|
2655
|
+
return Config._fromUnresolvedResObj(tree, {
|
|
2656
|
+
parseBaseDir: opts.baseDir,
|
|
2657
|
+
originDescription: opts.originDescription,
|
|
2658
|
+
resolved: !hasPlaceholders,
|
|
2659
|
+
resolveOpts
|
|
2660
|
+
});
|
|
2661
|
+
}
|
|
2662
|
+
function parseFileWithOptions(filePath, opts = {}) {
|
|
2663
|
+
if (typeof process === "undefined" && !opts.readFileSync) {
|
|
2664
|
+
throw new Error("parseFileWithOptions is not supported in browser environments without opts.readFileSync.");
|
|
2665
|
+
}
|
|
2666
|
+
const resolvedPath = path.resolve(filePath);
|
|
2667
|
+
const readFileSync2 = opts.readFileSync ?? defaultReadFileSync;
|
|
2668
|
+
const input = readFileSync2(resolvedPath);
|
|
2669
|
+
return parseStringWithOptions(input, {
|
|
2670
|
+
...opts,
|
|
2671
|
+
baseDir: opts.baseDir ?? path.dirname(resolvedPath),
|
|
2672
|
+
readFileSync: readFileSync2
|
|
2673
|
+
});
|
|
2001
2674
|
}
|
|
2002
2675
|
async function parseAsync(input, opts = {}) {
|
|
2003
2676
|
const { ast, resolveOpts } = buildResolveContext(input, opts);
|
|
@@ -2032,14 +2705,90 @@ async function parseFileAsync(filePath, opts = {}) {
|
|
|
2032
2705
|
readFileSync: opts.readFileSync ?? defaultReadFileSync
|
|
2033
2706
|
});
|
|
2034
2707
|
}
|
|
2708
|
+
|
|
2709
|
+
// src/value-factory.ts
|
|
2710
|
+
function fromMap(values, originDescription) {
|
|
2711
|
+
const fields = coerceObject(values, "");
|
|
2712
|
+
const root = { kind: "object", fields };
|
|
2713
|
+
return Config._fromResolvedValue(root, { originDescription });
|
|
2714
|
+
}
|
|
2715
|
+
function empty(originDescription) {
|
|
2716
|
+
const root = { kind: "object", fields: /* @__PURE__ */ new Map() };
|
|
2717
|
+
return Config._fromResolvedValue(root, { originDescription });
|
|
2718
|
+
}
|
|
2719
|
+
function coerceObject(obj, atPath) {
|
|
2720
|
+
const fields = /* @__PURE__ */ new Map();
|
|
2721
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
2722
|
+
const childPath = atPath ? `${atPath}.${k}` : k;
|
|
2723
|
+
fields.set(k, coerceValue(v, childPath));
|
|
2724
|
+
}
|
|
2725
|
+
return fields;
|
|
2726
|
+
}
|
|
2727
|
+
function coerceValue(v, atPath) {
|
|
2728
|
+
if (v === null) {
|
|
2729
|
+
return { kind: "scalar", raw: "null", valueType: "null" };
|
|
2730
|
+
}
|
|
2731
|
+
if (v === void 0) {
|
|
2732
|
+
throw new ConfigError(
|
|
2733
|
+
`fromMap: undefined is not a valid HOCON value at path "${atPath}"`,
|
|
2734
|
+
atPath
|
|
2735
|
+
);
|
|
2736
|
+
}
|
|
2737
|
+
switch (typeof v) {
|
|
2738
|
+
case "string":
|
|
2739
|
+
return { kind: "scalar", raw: v, valueType: "string" };
|
|
2740
|
+
case "number": {
|
|
2741
|
+
if (Number.isNaN(v) || !Number.isFinite(v)) {
|
|
2742
|
+
throw new ConfigError(
|
|
2743
|
+
`fromMap: ${v} is not representable in HOCON (NaN/Infinity not allowed) at path "${atPath}"`,
|
|
2744
|
+
atPath
|
|
2745
|
+
);
|
|
2746
|
+
}
|
|
2747
|
+
return { kind: "scalar", raw: String(v), valueType: "number" };
|
|
2748
|
+
}
|
|
2749
|
+
case "boolean":
|
|
2750
|
+
return { kind: "scalar", raw: v ? "true" : "false", valueType: "boolean" };
|
|
2751
|
+
case "bigint": {
|
|
2752
|
+
if (v > BigInt(Number.MAX_SAFE_INTEGER) || v < BigInt(Number.MIN_SAFE_INTEGER)) {
|
|
2753
|
+
throw new ConfigError(
|
|
2754
|
+
`fromMap: bigint ${v} exceeds Number.MAX_SAFE_INTEGER (not representable as HOCON number) at path "${atPath}"`,
|
|
2755
|
+
atPath
|
|
2756
|
+
);
|
|
2757
|
+
}
|
|
2758
|
+
return { kind: "scalar", raw: String(v), valueType: "number" };
|
|
2759
|
+
}
|
|
2760
|
+
case "object": {
|
|
2761
|
+
if (Array.isArray(v)) {
|
|
2762
|
+
const items = v.map((item, i) => coerceValue(item, `${atPath}[${i}]`));
|
|
2763
|
+
return { kind: "array", items };
|
|
2764
|
+
}
|
|
2765
|
+
const fields = coerceObject(v, atPath);
|
|
2766
|
+
return { kind: "object", fields };
|
|
2767
|
+
}
|
|
2768
|
+
default:
|
|
2769
|
+
throw new ConfigError(
|
|
2770
|
+
`fromMap: unsupported value type "${typeof v}" at path "${atPath}"`,
|
|
2771
|
+
atPath
|
|
2772
|
+
);
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2035
2775
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2036
2776
|
0 && (module.exports = {
|
|
2037
2777
|
Config,
|
|
2038
2778
|
ConfigError,
|
|
2779
|
+
NotResolvedError,
|
|
2780
|
+
PackageLookupError,
|
|
2039
2781
|
ParseError,
|
|
2040
2782
|
ResolveError,
|
|
2783
|
+
defaultParseOptions,
|
|
2784
|
+
defaultResolveOptions,
|
|
2785
|
+
empty,
|
|
2786
|
+
fromMap,
|
|
2041
2787
|
parse,
|
|
2042
2788
|
parseAsync,
|
|
2043
2789
|
parseFile,
|
|
2044
|
-
parseFileAsync
|
|
2790
|
+
parseFileAsync,
|
|
2791
|
+
parseFileWithOptions,
|
|
2792
|
+
parseString,
|
|
2793
|
+
parseStringWithOptions
|
|
2045
2794
|
});
|