@o3co/ts.hocon 1.8.0 → 1.10.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 +38 -5
- package/dist/adapters/env.cjs +1668 -0
- package/dist/adapters/env.d.cts +41 -0
- package/dist/adapters/env.d.ts +41 -0
- package/dist/adapters/env.js +1629 -0
- package/dist/adapters/jsonc.cjs +1613 -0
- package/dist/adapters/jsonc.d.cts +25 -0
- package/dist/adapters/jsonc.d.ts +25 -0
- package/dist/adapters/jsonc.js +1574 -0
- package/dist/adapters/properties.cjs +1681 -0
- package/dist/adapters/properties.d.cts +27 -0
- package/dist/adapters/properties.d.ts +27 -0
- package/dist/adapters/properties.js +1643 -0
- package/dist/adapters/toml.cjs +1570 -0
- package/dist/adapters/toml.d.cts +18 -0
- package/dist/adapters/toml.d.ts +18 -0
- package/dist/adapters/toml.js +1534 -0
- package/dist/adapters/yaml.cjs +1610 -0
- package/dist/adapters/yaml.d.cts +43 -0
- package/dist/adapters/yaml.d.ts +43 -0
- package/dist/adapters/yaml.js +1573 -0
- package/dist/index.cjs +139 -43
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +139 -43
- package/dist/zod.cjs +139 -43
- package/dist/zod.d.cts +1 -1
- package/dist/zod.d.ts +1 -1
- package/dist/zod.js +139 -43
- package/package.json +44 -9
- package/dist/{config-D27s3_aG.d.cts → config-PdhVgeLS.d.cts} +3 -3
- package/dist/{config-D27s3_aG.d.ts → config-PdhVgeLS.d.ts} +3 -3
package/dist/index.cjs
CHANGED
|
@@ -141,7 +141,7 @@ function parseDuration(value, outputUnit = "ms") {
|
|
|
141
141
|
if (i === 0) return NaN;
|
|
142
142
|
const num = Number(trimmed.slice(0, i));
|
|
143
143
|
if (Number.isNaN(num)) return NaN;
|
|
144
|
-
const unit = trimHoconWs(trimmed.slice(i))
|
|
144
|
+
const unit = trimHoconWs(trimmed.slice(i));
|
|
145
145
|
const divisor = OUTPUT_DURATION_UNITS[outputUnit];
|
|
146
146
|
if (divisor === void 0) return NaN;
|
|
147
147
|
if (unit === "") {
|
|
@@ -701,20 +701,6 @@ function isFileNotFoundError(e) {
|
|
|
701
701
|
var import_node_module = require("module");
|
|
702
702
|
var nodePath = __toESM(require("path"), 1);
|
|
703
703
|
|
|
704
|
-
// src/internal/parser/empty-check.ts
|
|
705
|
-
function hasContentTokens(tokens) {
|
|
706
|
-
return tokens.some((t) => t.kind !== "eof" && t.kind !== "newline");
|
|
707
|
-
}
|
|
708
|
-
function assertNonEmptyDocument(tokens, sourceDescriptor) {
|
|
709
|
-
if (!hasContentTokens(tokens)) {
|
|
710
|
-
throw new ParseError(
|
|
711
|
-
`empty file is not a valid HOCON document (HOCON.md L130): ${sourceDescriptor}`,
|
|
712
|
-
1,
|
|
713
|
-
1
|
|
714
|
-
);
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
|
|
718
704
|
// src/internal/lexer/lexer.ts
|
|
719
705
|
function isHoconWhitespace(ch) {
|
|
720
706
|
const cp = ch.codePointAt(0) ?? -1;
|
|
@@ -1115,12 +1101,12 @@ function isDecimalDigit(ch) {
|
|
|
1115
1101
|
}
|
|
1116
1102
|
function isUnquotedStart(ch) {
|
|
1117
1103
|
if (ch === "" || isHoconWhitespace(ch)) return false;
|
|
1118
|
-
if ('{}[],:=+#"
|
|
1104
|
+
if ('{}[],:=+#"$?!@*&^`\\'.includes(ch)) return false;
|
|
1119
1105
|
return true;
|
|
1120
1106
|
}
|
|
1121
1107
|
function isUnquotedContinue(ch, nextFn) {
|
|
1122
1108
|
if (ch === "" || isHoconWhitespace(ch)) return false;
|
|
1123
|
-
if ('{}[],:=#"
|
|
1109
|
+
if ('{}[],:=#"$?!@*&^`\\'.includes(ch)) return false;
|
|
1124
1110
|
if (ch === "+" && nextFn() === "=") return false;
|
|
1125
1111
|
if (ch === "/" && nextFn() === "/") return false;
|
|
1126
1112
|
return true;
|
|
@@ -1160,6 +1146,16 @@ var Parser = class {
|
|
|
1160
1146
|
}
|
|
1161
1147
|
return { kind: "object", fields: allFields, pos: first.pos };
|
|
1162
1148
|
}
|
|
1149
|
+
if (t.kind === "lbracket") {
|
|
1150
|
+
this.advance();
|
|
1151
|
+
const arr = this.parseArray();
|
|
1152
|
+
this.skip("newline");
|
|
1153
|
+
const remaining = this.peek();
|
|
1154
|
+
if (remaining.kind !== "eof") {
|
|
1155
|
+
throw new ParseError(`Unexpected token '${remaining.value}' after root array`, remaining.line, remaining.col);
|
|
1156
|
+
}
|
|
1157
|
+
return { ...arr, pos: { line: t.line, col: t.col } };
|
|
1158
|
+
}
|
|
1163
1159
|
return this.parseObject(false);
|
|
1164
1160
|
}
|
|
1165
1161
|
peek(offset = 0) {
|
|
@@ -1259,6 +1255,17 @@ var Parser = class {
|
|
|
1259
1255
|
this.advance();
|
|
1260
1256
|
const raw = t.value.startsWith(".") && segments.length > 0 && !t.precedingSpace ? t.value.slice(1) : t.value;
|
|
1261
1257
|
const parts = raw.split(".");
|
|
1258
|
+
const leadingDotIsSeparator = spaceConcat || postDotPrefix !== "";
|
|
1259
|
+
for (let i = 0; i < parts.length; i++) {
|
|
1260
|
+
if (parts[i] !== "") continue;
|
|
1261
|
+
if (i === parts.length - 1) continue;
|
|
1262
|
+
if (i === 0 && leadingDotIsSeparator) continue;
|
|
1263
|
+
throw new ParseError(
|
|
1264
|
+
`path has ${i === 0 ? "a leading period '.'" : "two adjacent periods '.'"} \u2014 empty key segment not allowed, use quoted "" (HOCON.md path rules)`,
|
|
1265
|
+
t.line,
|
|
1266
|
+
t.col
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1262
1269
|
const filtered = parts.filter((s) => s.length > 0);
|
|
1263
1270
|
if (spaceConcat) {
|
|
1264
1271
|
segments[segments.length - 1] = `${segments[segments.length - 1]}${t.precedingWhitespace}`;
|
|
@@ -1537,29 +1544,108 @@ function parseTokens(tokens) {
|
|
|
1537
1544
|
|
|
1538
1545
|
// src/internal/properties/properties.ts
|
|
1539
1546
|
function parseProperties(input) {
|
|
1540
|
-
const root = /* @__PURE__ */ Object.create(null);
|
|
1541
1547
|
const pairs = [];
|
|
1542
|
-
for (const line of input
|
|
1543
|
-
const
|
|
1544
|
-
|
|
1545
|
-
const sepIdx = findSeparator(trimmed);
|
|
1546
|
-
if (sepIdx === -1) continue;
|
|
1547
|
-
const key = trimmed.slice(0, sepIdx).trim();
|
|
1548
|
-
const value = trimmed.slice(sepIdx + 1).trim();
|
|
1548
|
+
for (const { text, line } of logicalLines(input)) {
|
|
1549
|
+
const [rawKey, rawValue] = splitKeyValue(text);
|
|
1550
|
+
const key = unescapeProps(rawKey, line);
|
|
1549
1551
|
if (key === "") continue;
|
|
1550
|
-
pairs.push([key,
|
|
1552
|
+
pairs.push([key, unescapeProps(rawValue, line)]);
|
|
1551
1553
|
}
|
|
1552
|
-
pairs
|
|
1553
|
-
|
|
1554
|
+
return nestPairs(pairs);
|
|
1555
|
+
}
|
|
1556
|
+
function nestPairs(pairs) {
|
|
1557
|
+
const root = /* @__PURE__ */ Object.create(null);
|
|
1558
|
+
const sorted = [...pairs].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
1559
|
+
for (const [key, value] of sorted) {
|
|
1554
1560
|
setNested(root, key.split("."), value);
|
|
1555
1561
|
}
|
|
1556
1562
|
return root;
|
|
1557
1563
|
}
|
|
1558
|
-
function
|
|
1559
|
-
|
|
1560
|
-
|
|
1564
|
+
function logicalLines(input) {
|
|
1565
|
+
const natural = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
1566
|
+
const out = [];
|
|
1567
|
+
for (let i = 0; i < natural.length; i++) {
|
|
1568
|
+
let text = trimLeadingSpace(natural[i] ?? "");
|
|
1569
|
+
if (text === "" || text.startsWith("#") || text.startsWith("!")) continue;
|
|
1570
|
+
const start = i + 1;
|
|
1571
|
+
while (endsWithContinuation(text)) {
|
|
1572
|
+
text = text.slice(0, -1);
|
|
1573
|
+
if (i + 1 >= natural.length) break;
|
|
1574
|
+
i++;
|
|
1575
|
+
text += trimLeadingSpace(natural[i] ?? "");
|
|
1576
|
+
}
|
|
1577
|
+
out.push({ text, line: start });
|
|
1578
|
+
}
|
|
1579
|
+
return out;
|
|
1580
|
+
}
|
|
1581
|
+
function trimLeadingSpace(s) {
|
|
1582
|
+
return s.replace(/^[ \t\f]+/, "");
|
|
1583
|
+
}
|
|
1584
|
+
function endsWithContinuation(line) {
|
|
1585
|
+
let n = 0;
|
|
1586
|
+
for (let i = line.length - 1; i >= 0 && line[i] === "\\"; i--) n++;
|
|
1587
|
+
return n % 2 === 1;
|
|
1588
|
+
}
|
|
1589
|
+
function splitKeyValue(line) {
|
|
1590
|
+
let key = "";
|
|
1591
|
+
let i = 0;
|
|
1592
|
+
for (; i < line.length; i++) {
|
|
1593
|
+
const c = line[i];
|
|
1594
|
+
if (c === "\\" && i + 1 < line.length) {
|
|
1595
|
+
key += c + line[i + 1];
|
|
1596
|
+
i++;
|
|
1597
|
+
continue;
|
|
1598
|
+
}
|
|
1599
|
+
if (c === "=" || c === ":" || isPropsSpace(c)) break;
|
|
1600
|
+
key += c;
|
|
1601
|
+
}
|
|
1602
|
+
while (i < line.length && isPropsSpace(line[i])) i++;
|
|
1603
|
+
if (i < line.length && (line[i] === "=" || line[i] === ":")) {
|
|
1604
|
+
i++;
|
|
1605
|
+
while (i < line.length && isPropsSpace(line[i])) i++;
|
|
1606
|
+
}
|
|
1607
|
+
return [key, line.slice(i)];
|
|
1608
|
+
}
|
|
1609
|
+
function isPropsSpace(c) {
|
|
1610
|
+
return c === " " || c === " " || c === "\f";
|
|
1611
|
+
}
|
|
1612
|
+
function unescapeProps(s, line) {
|
|
1613
|
+
let out = "";
|
|
1614
|
+
for (let i = 0; i < s.length; i++) {
|
|
1615
|
+
if (s[i] !== "\\") {
|
|
1616
|
+
out += s[i];
|
|
1617
|
+
continue;
|
|
1618
|
+
}
|
|
1619
|
+
i++;
|
|
1620
|
+
if (i >= s.length) break;
|
|
1621
|
+
const e = s[i];
|
|
1622
|
+
switch (e) {
|
|
1623
|
+
case "t":
|
|
1624
|
+
out += " ";
|
|
1625
|
+
break;
|
|
1626
|
+
case "n":
|
|
1627
|
+
out += "\n";
|
|
1628
|
+
break;
|
|
1629
|
+
case "r":
|
|
1630
|
+
out += "\r";
|
|
1631
|
+
break;
|
|
1632
|
+
case "f":
|
|
1633
|
+
out += "\f";
|
|
1634
|
+
break;
|
|
1635
|
+
case "u": {
|
|
1636
|
+
const hex = s.slice(i + 1, i + 5);
|
|
1637
|
+
if (!/^[0-9a-fA-F]{4}$/.test(hex)) {
|
|
1638
|
+
throw new ParseError(`malformed \\u escape in .properties: \\u${hex}`, line, i + 1);
|
|
1639
|
+
}
|
|
1640
|
+
out += String.fromCharCode(parseInt(hex, 16));
|
|
1641
|
+
i += 4;
|
|
1642
|
+
break;
|
|
1643
|
+
}
|
|
1644
|
+
default:
|
|
1645
|
+
out += e;
|
|
1646
|
+
}
|
|
1561
1647
|
}
|
|
1562
|
-
return
|
|
1648
|
+
return out;
|
|
1563
1649
|
}
|
|
1564
1650
|
var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1565
1651
|
function setNested(obj, segments, value) {
|
|
@@ -1599,6 +1685,16 @@ var _require = (0, import_node_module.createRequire)(import_meta.url);
|
|
|
1599
1685
|
function isPnpPath(p) {
|
|
1600
1686
|
return p.includes(".yarn/cache") || p.includes(".pnp.cjs") || p.includes(".pnp.loader");
|
|
1601
1687
|
}
|
|
1688
|
+
function assertObjectRootedInclude(ast, sourcePath) {
|
|
1689
|
+
if (ast.kind === "array") {
|
|
1690
|
+
throw new ResolveError(
|
|
1691
|
+
`included file has array at file root \u2014 an included file must contain an object, not an array (HOCON.md L993-994): ${sourcePath}`,
|
|
1692
|
+
sourcePath,
|
|
1693
|
+
ast.pos.line,
|
|
1694
|
+
ast.pos.col
|
|
1695
|
+
);
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1602
1698
|
function validatePackageFile(file, identifier) {
|
|
1603
1699
|
if (file.length === 0) {
|
|
1604
1700
|
throw new ParseError(`include package("${identifier}", ...): file argument must be non-empty`, 0, 0);
|
|
@@ -1778,10 +1874,9 @@ var IncludeLoader = class {
|
|
|
1778
1874
|
const resolver = packageResolver ?? ((id, f, includingFile, bDir) => defaultPackageResolver(id, f, includingFile, bDir, resolveFrom));
|
|
1779
1875
|
const resolvedPath = resolver(identifier, file, void 0, baseDir);
|
|
1780
1876
|
const content = readFileSync2(resolvedPath);
|
|
1781
|
-
if (content.length === 0) return makeResObj();
|
|
1782
1877
|
const tokens = tokenize(content);
|
|
1783
|
-
assertNonEmptyDocument(tokens, resolvedPath);
|
|
1784
1878
|
const ast = parseTokens(tokens);
|
|
1879
|
+
assertObjectRootedInclude(ast, resolvedPath);
|
|
1785
1880
|
return this.onBuildResObj(ast, {
|
|
1786
1881
|
...this.opts,
|
|
1787
1882
|
baseDir: nodePath.dirname(resolvedPath),
|
|
@@ -1811,10 +1906,9 @@ var IncludeLoader = class {
|
|
|
1811
1906
|
const resolvedPath = resolver(identifier, file, void 0, baseDir);
|
|
1812
1907
|
const read = readFile ? async (p) => readFile(p) : async (p) => readFileSync2(p);
|
|
1813
1908
|
const content = await read(resolvedPath);
|
|
1814
|
-
if (content.length === 0) return makeResObj();
|
|
1815
1909
|
const tokens = tokenize(content);
|
|
1816
|
-
assertNonEmptyDocument(tokens, resolvedPath);
|
|
1817
1910
|
const ast = parseTokens(tokens);
|
|
1911
|
+
assertObjectRootedInclude(ast, resolvedPath);
|
|
1818
1912
|
return this.onBuildResObjAsync(ast, {
|
|
1819
1913
|
...this.opts,
|
|
1820
1914
|
baseDir: nodePath.dirname(resolvedPath),
|
|
@@ -1837,10 +1931,8 @@ var IncludeLoader = class {
|
|
|
1837
1931
|
return hoconValueToResObj(propertiesToHoconValue(content));
|
|
1838
1932
|
}
|
|
1839
1933
|
const tokens = tokenize(content);
|
|
1840
|
-
if (!hasContentTokens(tokens)) {
|
|
1841
|
-
return makeResObj();
|
|
1842
|
-
}
|
|
1843
1934
|
const ast = parseTokens(tokens);
|
|
1935
|
+
assertObjectRootedInclude(ast, candidate);
|
|
1844
1936
|
return this.onBuildResObj(ast, {
|
|
1845
1937
|
...this.opts,
|
|
1846
1938
|
baseDir: nodePath.dirname(candidate),
|
|
@@ -1864,10 +1956,8 @@ var IncludeLoader = class {
|
|
|
1864
1956
|
return hoconValueToResObj(propertiesToHoconValue(content));
|
|
1865
1957
|
}
|
|
1866
1958
|
const tokens = tokenize(content);
|
|
1867
|
-
if (!hasContentTokens(tokens)) {
|
|
1868
|
-
return makeResObj();
|
|
1869
|
-
}
|
|
1870
1959
|
const ast = parseTokens(tokens);
|
|
1960
|
+
assertObjectRootedInclude(ast, candidate);
|
|
1871
1961
|
return this.onBuildResObjAsync(ast, {
|
|
1872
1962
|
...this.opts,
|
|
1873
1963
|
baseDir: nodePath.dirname(candidate),
|
|
@@ -3059,8 +3149,14 @@ async function defaultReadFile(filePath) {
|
|
|
3059
3149
|
}
|
|
3060
3150
|
function buildResolveContext(input, opts) {
|
|
3061
3151
|
const tokens = tokenize(input);
|
|
3062
|
-
assertNonEmptyDocument(tokens, "input");
|
|
3063
3152
|
const ast = parseTokens(tokens);
|
|
3153
|
+
if (ast.kind === "array") {
|
|
3154
|
+
const origin = opts.originDescription ?? "input";
|
|
3155
|
+
throw new ConfigError(
|
|
3156
|
+
`${origin}: ${ast.pos.line}:${ast.pos.col}: document has type array rather than object at file root (HOCON.md L989-991); the Config API requires an object root`,
|
|
3157
|
+
""
|
|
3158
|
+
);
|
|
3159
|
+
}
|
|
3064
3160
|
const resolveOpts = {
|
|
3065
3161
|
env: getEnv(opts),
|
|
3066
3162
|
baseDir: opts.baseDir,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as Config } from './config-
|
|
2
|
-
export { B as ByteUnit, D as DurationUnit, H as HoconValue, P as PackageResolver, a as ParseOptions, R as ReadonlyHoconValue, b as ResolveOptions, S as ScalarValueType, c as asArray, d as asBoolean, e as asNumber, f as asObject, g as asString, h as defaultParseOptions, i as defaultResolveOptions, j as isArray, k as isNull, l as isObject, m as isScalar, p as parse, n as parseAsync, o as parseFile, q as parseFileAsync, r as parseFileWithOptions, s as parseString, t as parseStringWithOptions } from './config-
|
|
1
|
+
import { C as Config } from './config-PdhVgeLS.cjs';
|
|
2
|
+
export { B as ByteUnit, D as DurationUnit, H as HoconValue, P as PackageResolver, a as ParseOptions, R as ReadonlyHoconValue, b as ResolveOptions, S as ScalarValueType, c as asArray, d as asBoolean, e as asNumber, f as asObject, g as asString, h as defaultParseOptions, i as defaultResolveOptions, j as isArray, k as isNull, l as isObject, m as isScalar, p as parse, n as parseAsync, o as parseFile, q as parseFileAsync, r as parseFileWithOptions, s as parseString, t as parseStringWithOptions } from './config-PdhVgeLS.cjs';
|
|
3
3
|
|
|
4
4
|
declare class ParseError extends Error {
|
|
5
5
|
readonly line: number;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as Config } from './config-
|
|
2
|
-
export { B as ByteUnit, D as DurationUnit, H as HoconValue, P as PackageResolver, a as ParseOptions, R as ReadonlyHoconValue, b as ResolveOptions, S as ScalarValueType, c as asArray, d as asBoolean, e as asNumber, f as asObject, g as asString, h as defaultParseOptions, i as defaultResolveOptions, j as isArray, k as isNull, l as isObject, m as isScalar, p as parse, n as parseAsync, o as parseFile, q as parseFileAsync, r as parseFileWithOptions, s as parseString, t as parseStringWithOptions } from './config-
|
|
1
|
+
import { C as Config } from './config-PdhVgeLS.js';
|
|
2
|
+
export { B as ByteUnit, D as DurationUnit, H as HoconValue, P as PackageResolver, a as ParseOptions, R as ReadonlyHoconValue, b as ResolveOptions, S as ScalarValueType, c as asArray, d as asBoolean, e as asNumber, f as asObject, g as asString, h as defaultParseOptions, i as defaultResolveOptions, j as isArray, k as isNull, l as isObject, m as isScalar, p as parse, n as parseAsync, o as parseFile, q as parseFileAsync, r as parseFileWithOptions, s as parseString, t as parseStringWithOptions } from './config-PdhVgeLS.js';
|
|
3
3
|
|
|
4
4
|
declare class ParseError extends Error {
|
|
5
5
|
readonly line: number;
|
package/dist/index.js
CHANGED
|
@@ -80,7 +80,7 @@ function parseDuration(value, outputUnit = "ms") {
|
|
|
80
80
|
if (i === 0) return NaN;
|
|
81
81
|
const num = Number(trimmed.slice(0, i));
|
|
82
82
|
if (Number.isNaN(num)) return NaN;
|
|
83
|
-
const unit = trimHoconWs(trimmed.slice(i))
|
|
83
|
+
const unit = trimHoconWs(trimmed.slice(i));
|
|
84
84
|
const divisor = OUTPUT_DURATION_UNITS[outputUnit];
|
|
85
85
|
if (divisor === void 0) return NaN;
|
|
86
86
|
if (unit === "") {
|
|
@@ -640,20 +640,6 @@ function isFileNotFoundError(e) {
|
|
|
640
640
|
import { createRequire } from "module";
|
|
641
641
|
import * as nodePath from "path";
|
|
642
642
|
|
|
643
|
-
// src/internal/parser/empty-check.ts
|
|
644
|
-
function hasContentTokens(tokens) {
|
|
645
|
-
return tokens.some((t) => t.kind !== "eof" && t.kind !== "newline");
|
|
646
|
-
}
|
|
647
|
-
function assertNonEmptyDocument(tokens, sourceDescriptor) {
|
|
648
|
-
if (!hasContentTokens(tokens)) {
|
|
649
|
-
throw new ParseError(
|
|
650
|
-
`empty file is not a valid HOCON document (HOCON.md L130): ${sourceDescriptor}`,
|
|
651
|
-
1,
|
|
652
|
-
1
|
|
653
|
-
);
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
|
|
657
643
|
// src/internal/lexer/lexer.ts
|
|
658
644
|
function isHoconWhitespace(ch) {
|
|
659
645
|
const cp = ch.codePointAt(0) ?? -1;
|
|
@@ -1054,12 +1040,12 @@ function isDecimalDigit(ch) {
|
|
|
1054
1040
|
}
|
|
1055
1041
|
function isUnquotedStart(ch) {
|
|
1056
1042
|
if (ch === "" || isHoconWhitespace(ch)) return false;
|
|
1057
|
-
if ('{}[],:=+#"
|
|
1043
|
+
if ('{}[],:=+#"$?!@*&^`\\'.includes(ch)) return false;
|
|
1058
1044
|
return true;
|
|
1059
1045
|
}
|
|
1060
1046
|
function isUnquotedContinue(ch, nextFn) {
|
|
1061
1047
|
if (ch === "" || isHoconWhitespace(ch)) return false;
|
|
1062
|
-
if ('{}[],:=#"
|
|
1048
|
+
if ('{}[],:=#"$?!@*&^`\\'.includes(ch)) return false;
|
|
1063
1049
|
if (ch === "+" && nextFn() === "=") return false;
|
|
1064
1050
|
if (ch === "/" && nextFn() === "/") return false;
|
|
1065
1051
|
return true;
|
|
@@ -1099,6 +1085,16 @@ var Parser = class {
|
|
|
1099
1085
|
}
|
|
1100
1086
|
return { kind: "object", fields: allFields, pos: first.pos };
|
|
1101
1087
|
}
|
|
1088
|
+
if (t.kind === "lbracket") {
|
|
1089
|
+
this.advance();
|
|
1090
|
+
const arr = this.parseArray();
|
|
1091
|
+
this.skip("newline");
|
|
1092
|
+
const remaining = this.peek();
|
|
1093
|
+
if (remaining.kind !== "eof") {
|
|
1094
|
+
throw new ParseError(`Unexpected token '${remaining.value}' after root array`, remaining.line, remaining.col);
|
|
1095
|
+
}
|
|
1096
|
+
return { ...arr, pos: { line: t.line, col: t.col } };
|
|
1097
|
+
}
|
|
1102
1098
|
return this.parseObject(false);
|
|
1103
1099
|
}
|
|
1104
1100
|
peek(offset = 0) {
|
|
@@ -1198,6 +1194,17 @@ var Parser = class {
|
|
|
1198
1194
|
this.advance();
|
|
1199
1195
|
const raw = t.value.startsWith(".") && segments.length > 0 && !t.precedingSpace ? t.value.slice(1) : t.value;
|
|
1200
1196
|
const parts = raw.split(".");
|
|
1197
|
+
const leadingDotIsSeparator = spaceConcat || postDotPrefix !== "";
|
|
1198
|
+
for (let i = 0; i < parts.length; i++) {
|
|
1199
|
+
if (parts[i] !== "") continue;
|
|
1200
|
+
if (i === parts.length - 1) continue;
|
|
1201
|
+
if (i === 0 && leadingDotIsSeparator) continue;
|
|
1202
|
+
throw new ParseError(
|
|
1203
|
+
`path has ${i === 0 ? "a leading period '.'" : "two adjacent periods '.'"} \u2014 empty key segment not allowed, use quoted "" (HOCON.md path rules)`,
|
|
1204
|
+
t.line,
|
|
1205
|
+
t.col
|
|
1206
|
+
);
|
|
1207
|
+
}
|
|
1201
1208
|
const filtered = parts.filter((s) => s.length > 0);
|
|
1202
1209
|
if (spaceConcat) {
|
|
1203
1210
|
segments[segments.length - 1] = `${segments[segments.length - 1]}${t.precedingWhitespace}`;
|
|
@@ -1476,29 +1483,108 @@ function parseTokens(tokens) {
|
|
|
1476
1483
|
|
|
1477
1484
|
// src/internal/properties/properties.ts
|
|
1478
1485
|
function parseProperties(input) {
|
|
1479
|
-
const root = /* @__PURE__ */ Object.create(null);
|
|
1480
1486
|
const pairs = [];
|
|
1481
|
-
for (const line of input
|
|
1482
|
-
const
|
|
1483
|
-
|
|
1484
|
-
const sepIdx = findSeparator(trimmed);
|
|
1485
|
-
if (sepIdx === -1) continue;
|
|
1486
|
-
const key = trimmed.slice(0, sepIdx).trim();
|
|
1487
|
-
const value = trimmed.slice(sepIdx + 1).trim();
|
|
1487
|
+
for (const { text, line } of logicalLines(input)) {
|
|
1488
|
+
const [rawKey, rawValue] = splitKeyValue(text);
|
|
1489
|
+
const key = unescapeProps(rawKey, line);
|
|
1488
1490
|
if (key === "") continue;
|
|
1489
|
-
pairs.push([key,
|
|
1491
|
+
pairs.push([key, unescapeProps(rawValue, line)]);
|
|
1490
1492
|
}
|
|
1491
|
-
pairs
|
|
1492
|
-
|
|
1493
|
+
return nestPairs(pairs);
|
|
1494
|
+
}
|
|
1495
|
+
function nestPairs(pairs) {
|
|
1496
|
+
const root = /* @__PURE__ */ Object.create(null);
|
|
1497
|
+
const sorted = [...pairs].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
1498
|
+
for (const [key, value] of sorted) {
|
|
1493
1499
|
setNested(root, key.split("."), value);
|
|
1494
1500
|
}
|
|
1495
1501
|
return root;
|
|
1496
1502
|
}
|
|
1497
|
-
function
|
|
1498
|
-
|
|
1499
|
-
|
|
1503
|
+
function logicalLines(input) {
|
|
1504
|
+
const natural = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
1505
|
+
const out = [];
|
|
1506
|
+
for (let i = 0; i < natural.length; i++) {
|
|
1507
|
+
let text = trimLeadingSpace(natural[i] ?? "");
|
|
1508
|
+
if (text === "" || text.startsWith("#") || text.startsWith("!")) continue;
|
|
1509
|
+
const start = i + 1;
|
|
1510
|
+
while (endsWithContinuation(text)) {
|
|
1511
|
+
text = text.slice(0, -1);
|
|
1512
|
+
if (i + 1 >= natural.length) break;
|
|
1513
|
+
i++;
|
|
1514
|
+
text += trimLeadingSpace(natural[i] ?? "");
|
|
1515
|
+
}
|
|
1516
|
+
out.push({ text, line: start });
|
|
1517
|
+
}
|
|
1518
|
+
return out;
|
|
1519
|
+
}
|
|
1520
|
+
function trimLeadingSpace(s) {
|
|
1521
|
+
return s.replace(/^[ \t\f]+/, "");
|
|
1522
|
+
}
|
|
1523
|
+
function endsWithContinuation(line) {
|
|
1524
|
+
let n = 0;
|
|
1525
|
+
for (let i = line.length - 1; i >= 0 && line[i] === "\\"; i--) n++;
|
|
1526
|
+
return n % 2 === 1;
|
|
1527
|
+
}
|
|
1528
|
+
function splitKeyValue(line) {
|
|
1529
|
+
let key = "";
|
|
1530
|
+
let i = 0;
|
|
1531
|
+
for (; i < line.length; i++) {
|
|
1532
|
+
const c = line[i];
|
|
1533
|
+
if (c === "\\" && i + 1 < line.length) {
|
|
1534
|
+
key += c + line[i + 1];
|
|
1535
|
+
i++;
|
|
1536
|
+
continue;
|
|
1537
|
+
}
|
|
1538
|
+
if (c === "=" || c === ":" || isPropsSpace(c)) break;
|
|
1539
|
+
key += c;
|
|
1540
|
+
}
|
|
1541
|
+
while (i < line.length && isPropsSpace(line[i])) i++;
|
|
1542
|
+
if (i < line.length && (line[i] === "=" || line[i] === ":")) {
|
|
1543
|
+
i++;
|
|
1544
|
+
while (i < line.length && isPropsSpace(line[i])) i++;
|
|
1545
|
+
}
|
|
1546
|
+
return [key, line.slice(i)];
|
|
1547
|
+
}
|
|
1548
|
+
function isPropsSpace(c) {
|
|
1549
|
+
return c === " " || c === " " || c === "\f";
|
|
1550
|
+
}
|
|
1551
|
+
function unescapeProps(s, line) {
|
|
1552
|
+
let out = "";
|
|
1553
|
+
for (let i = 0; i < s.length; i++) {
|
|
1554
|
+
if (s[i] !== "\\") {
|
|
1555
|
+
out += s[i];
|
|
1556
|
+
continue;
|
|
1557
|
+
}
|
|
1558
|
+
i++;
|
|
1559
|
+
if (i >= s.length) break;
|
|
1560
|
+
const e = s[i];
|
|
1561
|
+
switch (e) {
|
|
1562
|
+
case "t":
|
|
1563
|
+
out += " ";
|
|
1564
|
+
break;
|
|
1565
|
+
case "n":
|
|
1566
|
+
out += "\n";
|
|
1567
|
+
break;
|
|
1568
|
+
case "r":
|
|
1569
|
+
out += "\r";
|
|
1570
|
+
break;
|
|
1571
|
+
case "f":
|
|
1572
|
+
out += "\f";
|
|
1573
|
+
break;
|
|
1574
|
+
case "u": {
|
|
1575
|
+
const hex = s.slice(i + 1, i + 5);
|
|
1576
|
+
if (!/^[0-9a-fA-F]{4}$/.test(hex)) {
|
|
1577
|
+
throw new ParseError(`malformed \\u escape in .properties: \\u${hex}`, line, i + 1);
|
|
1578
|
+
}
|
|
1579
|
+
out += String.fromCharCode(parseInt(hex, 16));
|
|
1580
|
+
i += 4;
|
|
1581
|
+
break;
|
|
1582
|
+
}
|
|
1583
|
+
default:
|
|
1584
|
+
out += e;
|
|
1585
|
+
}
|
|
1500
1586
|
}
|
|
1501
|
-
return
|
|
1587
|
+
return out;
|
|
1502
1588
|
}
|
|
1503
1589
|
var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1504
1590
|
function setNested(obj, segments, value) {
|
|
@@ -1537,6 +1623,16 @@ var _require = createRequire(import.meta.url);
|
|
|
1537
1623
|
function isPnpPath(p) {
|
|
1538
1624
|
return p.includes(".yarn/cache") || p.includes(".pnp.cjs") || p.includes(".pnp.loader");
|
|
1539
1625
|
}
|
|
1626
|
+
function assertObjectRootedInclude(ast, sourcePath) {
|
|
1627
|
+
if (ast.kind === "array") {
|
|
1628
|
+
throw new ResolveError(
|
|
1629
|
+
`included file has array at file root \u2014 an included file must contain an object, not an array (HOCON.md L993-994): ${sourcePath}`,
|
|
1630
|
+
sourcePath,
|
|
1631
|
+
ast.pos.line,
|
|
1632
|
+
ast.pos.col
|
|
1633
|
+
);
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1540
1636
|
function validatePackageFile(file, identifier) {
|
|
1541
1637
|
if (file.length === 0) {
|
|
1542
1638
|
throw new ParseError(`include package("${identifier}", ...): file argument must be non-empty`, 0, 0);
|
|
@@ -1716,10 +1812,9 @@ var IncludeLoader = class {
|
|
|
1716
1812
|
const resolver = packageResolver ?? ((id, f, includingFile, bDir) => defaultPackageResolver(id, f, includingFile, bDir, resolveFrom));
|
|
1717
1813
|
const resolvedPath = resolver(identifier, file, void 0, baseDir);
|
|
1718
1814
|
const content = readFileSync2(resolvedPath);
|
|
1719
|
-
if (content.length === 0) return makeResObj();
|
|
1720
1815
|
const tokens = tokenize(content);
|
|
1721
|
-
assertNonEmptyDocument(tokens, resolvedPath);
|
|
1722
1816
|
const ast = parseTokens(tokens);
|
|
1817
|
+
assertObjectRootedInclude(ast, resolvedPath);
|
|
1723
1818
|
return this.onBuildResObj(ast, {
|
|
1724
1819
|
...this.opts,
|
|
1725
1820
|
baseDir: nodePath.dirname(resolvedPath),
|
|
@@ -1749,10 +1844,9 @@ var IncludeLoader = class {
|
|
|
1749
1844
|
const resolvedPath = resolver(identifier, file, void 0, baseDir);
|
|
1750
1845
|
const read = readFile ? async (p) => readFile(p) : async (p) => readFileSync2(p);
|
|
1751
1846
|
const content = await read(resolvedPath);
|
|
1752
|
-
if (content.length === 0) return makeResObj();
|
|
1753
1847
|
const tokens = tokenize(content);
|
|
1754
|
-
assertNonEmptyDocument(tokens, resolvedPath);
|
|
1755
1848
|
const ast = parseTokens(tokens);
|
|
1849
|
+
assertObjectRootedInclude(ast, resolvedPath);
|
|
1756
1850
|
return this.onBuildResObjAsync(ast, {
|
|
1757
1851
|
...this.opts,
|
|
1758
1852
|
baseDir: nodePath.dirname(resolvedPath),
|
|
@@ -1775,10 +1869,8 @@ var IncludeLoader = class {
|
|
|
1775
1869
|
return hoconValueToResObj(propertiesToHoconValue(content));
|
|
1776
1870
|
}
|
|
1777
1871
|
const tokens = tokenize(content);
|
|
1778
|
-
if (!hasContentTokens(tokens)) {
|
|
1779
|
-
return makeResObj();
|
|
1780
|
-
}
|
|
1781
1872
|
const ast = parseTokens(tokens);
|
|
1873
|
+
assertObjectRootedInclude(ast, candidate);
|
|
1782
1874
|
return this.onBuildResObj(ast, {
|
|
1783
1875
|
...this.opts,
|
|
1784
1876
|
baseDir: nodePath.dirname(candidate),
|
|
@@ -1802,10 +1894,8 @@ var IncludeLoader = class {
|
|
|
1802
1894
|
return hoconValueToResObj(propertiesToHoconValue(content));
|
|
1803
1895
|
}
|
|
1804
1896
|
const tokens = tokenize(content);
|
|
1805
|
-
if (!hasContentTokens(tokens)) {
|
|
1806
|
-
return makeResObj();
|
|
1807
|
-
}
|
|
1808
1897
|
const ast = parseTokens(tokens);
|
|
1898
|
+
assertObjectRootedInclude(ast, candidate);
|
|
1809
1899
|
return this.onBuildResObjAsync(ast, {
|
|
1810
1900
|
...this.opts,
|
|
1811
1901
|
baseDir: nodePath.dirname(candidate),
|
|
@@ -2997,8 +3087,14 @@ async function defaultReadFile(filePath) {
|
|
|
2997
3087
|
}
|
|
2998
3088
|
function buildResolveContext(input, opts) {
|
|
2999
3089
|
const tokens = tokenize(input);
|
|
3000
|
-
assertNonEmptyDocument(tokens, "input");
|
|
3001
3090
|
const ast = parseTokens(tokens);
|
|
3091
|
+
if (ast.kind === "array") {
|
|
3092
|
+
const origin = opts.originDescription ?? "input";
|
|
3093
|
+
throw new ConfigError(
|
|
3094
|
+
`${origin}: ${ast.pos.line}:${ast.pos.col}: document has type array rather than object at file root (HOCON.md L989-991); the Config API requires an object root`,
|
|
3095
|
+
""
|
|
3096
|
+
);
|
|
3097
|
+
}
|
|
3002
3098
|
const resolveOpts = {
|
|
3003
3099
|
env: getEnv(opts),
|
|
3004
3100
|
baseDir: opts.baseDir,
|