@o3co/ts.hocon 1.9.0 → 1.11.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.ja.md +129 -1
- package/README.md +122 -2
- package/dist/adapters/env.cjs +1738 -0
- package/dist/adapters/env.d.cts +56 -0
- package/dist/adapters/env.d.ts +56 -0
- package/dist/adapters/env.js +1700 -0
- package/dist/adapters/jsonc.cjs +1716 -0
- package/dist/adapters/jsonc.d.cts +45 -0
- package/dist/adapters/jsonc.d.ts +45 -0
- package/dist/adapters/jsonc.js +1678 -0
- package/dist/adapters/properties.cjs +1744 -0
- package/dist/adapters/properties.d.cts +32 -0
- package/dist/adapters/properties.d.ts +32 -0
- package/dist/adapters/properties.js +1707 -0
- package/dist/adapters/toml.cjs +1629 -0
- package/dist/adapters/toml.d.cts +18 -0
- package/dist/adapters/toml.d.ts +18 -0
- package/dist/adapters/toml.js +1594 -0
- package/dist/adapters/yaml.cjs +1686 -0
- package/dist/adapters/yaml.d.cts +51 -0
- package/dist/adapters/yaml.d.ts +51 -0
- package/dist/adapters/yaml.js +1650 -0
- package/dist/{config-D27s3_aG.d.cts → config-Dlq6rF3w.d.cts} +50 -4
- package/dist/{config-D27s3_aG.d.ts → config-Dlq6rF3w.d.ts} +50 -4
- package/dist/index.cjs +207 -35
- package/dist/index.d.cts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +214 -35
- package/dist/zod.cjs +203 -33
- package/dist/zod.d.cts +1 -1
- package/dist/zod.d.ts +1 -1
- package/dist/zod.js +210 -33
- package/package.json +89 -19
package/dist/index.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
1
8
|
// src/coerce.ts
|
|
2
9
|
var DECIMAL_NUMBER_RE = /^-?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/;
|
|
3
10
|
function isHoconWs(cp) {
|
|
@@ -639,6 +646,7 @@ function isFileNotFoundError(e) {
|
|
|
639
646
|
// src/internal/resolver/include-loader.ts
|
|
640
647
|
import { createRequire } from "module";
|
|
641
648
|
import * as nodePath from "path";
|
|
649
|
+
import { pathToFileURL } from "url";
|
|
642
650
|
|
|
643
651
|
// src/internal/lexer/lexer.ts
|
|
644
652
|
function isHoconWhitespace(ch) {
|
|
@@ -1040,12 +1048,12 @@ function isDecimalDigit(ch) {
|
|
|
1040
1048
|
}
|
|
1041
1049
|
function isUnquotedStart(ch) {
|
|
1042
1050
|
if (ch === "" || isHoconWhitespace(ch)) return false;
|
|
1043
|
-
if ('{}[],:=+#"
|
|
1051
|
+
if ('{}[],:=+#"$?!@*&^`\\'.includes(ch)) return false;
|
|
1044
1052
|
return true;
|
|
1045
1053
|
}
|
|
1046
1054
|
function isUnquotedContinue(ch, nextFn) {
|
|
1047
1055
|
if (ch === "" || isHoconWhitespace(ch)) return false;
|
|
1048
|
-
if ('{}[],:=#"
|
|
1056
|
+
if ('{}[],:=#"$?!@*&^`\\'.includes(ch)) return false;
|
|
1049
1057
|
if (ch === "+" && nextFn() === "=") return false;
|
|
1050
1058
|
if (ch === "/" && nextFn() === "/") return false;
|
|
1051
1059
|
return true;
|
|
@@ -1194,6 +1202,17 @@ var Parser = class {
|
|
|
1194
1202
|
this.advance();
|
|
1195
1203
|
const raw = t.value.startsWith(".") && segments.length > 0 && !t.precedingSpace ? t.value.slice(1) : t.value;
|
|
1196
1204
|
const parts = raw.split(".");
|
|
1205
|
+
const leadingDotIsSeparator = spaceConcat || postDotPrefix !== "";
|
|
1206
|
+
for (let i = 0; i < parts.length; i++) {
|
|
1207
|
+
if (parts[i] !== "") continue;
|
|
1208
|
+
if (i === parts.length - 1) continue;
|
|
1209
|
+
if (i === 0 && leadingDotIsSeparator) continue;
|
|
1210
|
+
throw new ParseError(
|
|
1211
|
+
`path has ${i === 0 ? "a leading period '.'" : "two adjacent periods '.'"} \u2014 empty key segment not allowed, use quoted "" (HOCON.md path rules)`,
|
|
1212
|
+
t.line,
|
|
1213
|
+
t.col
|
|
1214
|
+
);
|
|
1215
|
+
}
|
|
1197
1216
|
const filtered = parts.filter((s) => s.length > 0);
|
|
1198
1217
|
if (spaceConcat) {
|
|
1199
1218
|
segments[segments.length - 1] = `${segments[segments.length - 1]}${t.precedingWhitespace}`;
|
|
@@ -1470,45 +1489,135 @@ function parseTokens(tokens) {
|
|
|
1470
1489
|
return new Parser(tokens).parse();
|
|
1471
1490
|
}
|
|
1472
1491
|
|
|
1492
|
+
// src/internal/strip-bom.ts
|
|
1493
|
+
function stripBom(input) {
|
|
1494
|
+
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1473
1497
|
// src/internal/properties/properties.ts
|
|
1474
1498
|
function parseProperties(input) {
|
|
1475
|
-
const root = /* @__PURE__ */ Object.create(null);
|
|
1476
1499
|
const pairs = [];
|
|
1477
|
-
for (const line of input
|
|
1478
|
-
const
|
|
1479
|
-
|
|
1480
|
-
const sepIdx = findSeparator(trimmed);
|
|
1481
|
-
if (sepIdx === -1) continue;
|
|
1482
|
-
const key = trimmed.slice(0, sepIdx).trim();
|
|
1483
|
-
const value = trimmed.slice(sepIdx + 1).trim();
|
|
1500
|
+
for (const { text, line } of logicalLines(stripBom(input))) {
|
|
1501
|
+
const [rawKey, rawValue] = splitKeyValue(text);
|
|
1502
|
+
const key = unescapeProps(rawKey, line);
|
|
1484
1503
|
if (key === "") continue;
|
|
1485
|
-
pairs.push([key,
|
|
1504
|
+
pairs.push([key.split("."), unescapeProps(rawValue, line)]);
|
|
1486
1505
|
}
|
|
1487
|
-
pairs
|
|
1488
|
-
|
|
1489
|
-
|
|
1506
|
+
return nestPairs(pairs);
|
|
1507
|
+
}
|
|
1508
|
+
function nestPairs(pairs) {
|
|
1509
|
+
const root = /* @__PURE__ */ Object.create(null);
|
|
1510
|
+
const sorted = [...pairs].sort(([a], [b]) => compareSegments(a, b));
|
|
1511
|
+
for (const [segments, value] of sorted) {
|
|
1512
|
+
setNested(root, segments, value);
|
|
1490
1513
|
}
|
|
1491
1514
|
return root;
|
|
1492
1515
|
}
|
|
1493
|
-
function
|
|
1494
|
-
|
|
1495
|
-
|
|
1516
|
+
function compareSegments(a, b) {
|
|
1517
|
+
const n = Math.min(a.length, b.length);
|
|
1518
|
+
for (let i = 0; i < n; i++) {
|
|
1519
|
+
const x = a[i];
|
|
1520
|
+
const y = b[i];
|
|
1521
|
+
if (x !== y) return x < y ? -1 : 1;
|
|
1522
|
+
}
|
|
1523
|
+
return a.length - b.length;
|
|
1524
|
+
}
|
|
1525
|
+
function logicalLines(input) {
|
|
1526
|
+
const natural = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
1527
|
+
const out = [];
|
|
1528
|
+
for (let i = 0; i < natural.length; i++) {
|
|
1529
|
+
let text = trimLeadingSpace(natural[i] ?? "");
|
|
1530
|
+
if (text === "" || text.startsWith("#") || text.startsWith("!")) continue;
|
|
1531
|
+
const start = i + 1;
|
|
1532
|
+
while (endsWithContinuation(text)) {
|
|
1533
|
+
text = text.slice(0, -1);
|
|
1534
|
+
if (i + 1 >= natural.length) break;
|
|
1535
|
+
i++;
|
|
1536
|
+
text += trimLeadingSpace(natural[i] ?? "");
|
|
1537
|
+
}
|
|
1538
|
+
out.push({ text, line: start });
|
|
1496
1539
|
}
|
|
1497
|
-
return
|
|
1540
|
+
return out;
|
|
1541
|
+
}
|
|
1542
|
+
function trimLeadingSpace(s) {
|
|
1543
|
+
return s.replace(/^[ \t\f]+/, "");
|
|
1544
|
+
}
|
|
1545
|
+
function endsWithContinuation(line) {
|
|
1546
|
+
let n = 0;
|
|
1547
|
+
for (let i = line.length - 1; i >= 0 && line[i] === "\\"; i--) n++;
|
|
1548
|
+
return n % 2 === 1;
|
|
1549
|
+
}
|
|
1550
|
+
function splitKeyValue(line) {
|
|
1551
|
+
let key = "";
|
|
1552
|
+
let i = 0;
|
|
1553
|
+
for (; i < line.length; i++) {
|
|
1554
|
+
const c = line[i];
|
|
1555
|
+
if (c === "\\" && i + 1 < line.length) {
|
|
1556
|
+
key += c + line[i + 1];
|
|
1557
|
+
i++;
|
|
1558
|
+
continue;
|
|
1559
|
+
}
|
|
1560
|
+
if (c === "=" || c === ":" || isPropsSpace(c)) break;
|
|
1561
|
+
key += c;
|
|
1562
|
+
}
|
|
1563
|
+
while (i < line.length && isPropsSpace(line[i])) i++;
|
|
1564
|
+
if (i < line.length && (line[i] === "=" || line[i] === ":")) {
|
|
1565
|
+
i++;
|
|
1566
|
+
while (i < line.length && isPropsSpace(line[i])) i++;
|
|
1567
|
+
}
|
|
1568
|
+
return [key, line.slice(i)];
|
|
1569
|
+
}
|
|
1570
|
+
function isPropsSpace(c) {
|
|
1571
|
+
return c === " " || c === " " || c === "\f";
|
|
1572
|
+
}
|
|
1573
|
+
function unescapeProps(s, line) {
|
|
1574
|
+
let out = "";
|
|
1575
|
+
for (let i = 0; i < s.length; i++) {
|
|
1576
|
+
if (s[i] !== "\\") {
|
|
1577
|
+
out += s[i];
|
|
1578
|
+
continue;
|
|
1579
|
+
}
|
|
1580
|
+
i++;
|
|
1581
|
+
if (i >= s.length) break;
|
|
1582
|
+
const e = s[i];
|
|
1583
|
+
switch (e) {
|
|
1584
|
+
case "t":
|
|
1585
|
+
out += " ";
|
|
1586
|
+
break;
|
|
1587
|
+
case "n":
|
|
1588
|
+
out += "\n";
|
|
1589
|
+
break;
|
|
1590
|
+
case "r":
|
|
1591
|
+
out += "\r";
|
|
1592
|
+
break;
|
|
1593
|
+
case "f":
|
|
1594
|
+
out += "\f";
|
|
1595
|
+
break;
|
|
1596
|
+
case "u": {
|
|
1597
|
+
const hex = s.slice(i + 1, i + 5);
|
|
1598
|
+
if (!/^[0-9a-fA-F]{4}$/.test(hex)) {
|
|
1599
|
+
throw new ParseError(`malformed \\u escape in .properties: \\u${hex}`, line, i + 1);
|
|
1600
|
+
}
|
|
1601
|
+
out += String.fromCharCode(parseInt(hex, 16));
|
|
1602
|
+
i += 4;
|
|
1603
|
+
break;
|
|
1604
|
+
}
|
|
1605
|
+
default:
|
|
1606
|
+
out += e;
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
return out;
|
|
1498
1610
|
}
|
|
1499
|
-
var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1500
1611
|
function setNested(obj, segments, value) {
|
|
1501
1612
|
let current = obj;
|
|
1502
1613
|
for (let i = 0; i < segments.length - 1; i++) {
|
|
1503
1614
|
const seg = segments[i];
|
|
1504
|
-
if (seg === void 0 || DANGEROUS_KEYS.has(seg)) return;
|
|
1505
1615
|
if (!(seg in current) || typeof current[seg] !== "object" || current[seg] === null) {
|
|
1506
1616
|
current[seg] = /* @__PURE__ */ Object.create(null);
|
|
1507
1617
|
}
|
|
1508
1618
|
current = current[seg];
|
|
1509
1619
|
}
|
|
1510
1620
|
const last = segments[segments.length - 1];
|
|
1511
|
-
if (last === void 0 || DANGEROUS_KEYS.has(last)) return;
|
|
1512
1621
|
if (typeof current[last] === "object" && current[last] !== null) return;
|
|
1513
1622
|
current[last] = value;
|
|
1514
1623
|
}
|
|
@@ -1529,7 +1638,22 @@ function recordToHoconValue(obj) {
|
|
|
1529
1638
|
}
|
|
1530
1639
|
|
|
1531
1640
|
// src/internal/resolver/include-loader.ts
|
|
1532
|
-
var _require
|
|
1641
|
+
var _require;
|
|
1642
|
+
function getRequire() {
|
|
1643
|
+
if (_require === void 0) {
|
|
1644
|
+
_require = pickRequire(
|
|
1645
|
+
typeof __require === "function" ? __require : void 0,
|
|
1646
|
+
import.meta.url
|
|
1647
|
+
);
|
|
1648
|
+
}
|
|
1649
|
+
return _require;
|
|
1650
|
+
}
|
|
1651
|
+
function pickRequire(candidate, metaUrl) {
|
|
1652
|
+
if (typeof candidate?.resolve === "function") {
|
|
1653
|
+
return candidate;
|
|
1654
|
+
}
|
|
1655
|
+
return createRequire(metaUrl ?? pathToFileURL(nodePath.join(process.cwd(), "noop.js")));
|
|
1656
|
+
}
|
|
1533
1657
|
function isPnpPath(p) {
|
|
1534
1658
|
return p.includes(".yarn/cache") || p.includes(".pnp.cjs") || p.includes(".pnp.loader");
|
|
1535
1659
|
}
|
|
@@ -1585,7 +1709,7 @@ function defaultPackageResolver(identifier, file, includingFile, baseDir, resolv
|
|
|
1585
1709
|
const from = resolveFrom ? Array.isArray(resolveFrom) ? resolveFrom : [resolveFrom] : baseDir ? [baseDir] : includingFile ? [nodePath.dirname(includingFile)] : [process.cwd()];
|
|
1586
1710
|
let resolved;
|
|
1587
1711
|
try {
|
|
1588
|
-
resolved =
|
|
1712
|
+
resolved = getRequire().resolve(`${identifier}/${file}`, { paths: from });
|
|
1589
1713
|
} catch {
|
|
1590
1714
|
throw new PackageLookupError(
|
|
1591
1715
|
`include package("${identifier}", "${file}"): module not found (starting from: ${from.join(", ")})`,
|
|
@@ -2639,10 +2763,10 @@ var Config = class _Config {
|
|
|
2639
2763
|
}
|
|
2640
2764
|
if (v.kind === "object") {
|
|
2641
2765
|
const converted = numericObjectToArray(v);
|
|
2642
|
-
if (converted !== null) return converted.map(hoconToJs);
|
|
2766
|
+
if (converted !== null) return converted.map((item) => hoconToJs(item));
|
|
2643
2767
|
}
|
|
2644
2768
|
if (v.kind !== "array") throw new ConfigError(`expected array at ${path2}`, path2);
|
|
2645
|
-
return v.items.map(hoconToJs);
|
|
2769
|
+
return v.items.map((item) => hoconToJs(item));
|
|
2646
2770
|
}
|
|
2647
2771
|
has(path2) {
|
|
2648
2772
|
return this.lookupNode(path2) !== void 0;
|
|
@@ -2770,8 +2894,52 @@ var Config = class _Config {
|
|
|
2770
2894
|
originDescription: this._originDescription
|
|
2771
2895
|
});
|
|
2772
2896
|
}
|
|
2773
|
-
|
|
2774
|
-
|
|
2897
|
+
/**
|
|
2898
|
+
* The whole config as plain JS data: objects, arrays, strings, numbers,
|
|
2899
|
+
* booleans and `null`.
|
|
2900
|
+
*
|
|
2901
|
+
* Keys are reproduced exactly as the config carries them, `__proto__`,
|
|
2902
|
+
* `constructor` and `prototype` included: each is defined as an **own data
|
|
2903
|
+
* property**, so the returned object's prototype is always
|
|
2904
|
+
* `Object.prototype`, and this call writes nothing to the global one.
|
|
2905
|
+
*
|
|
2906
|
+
* ### Passing the result to other code
|
|
2907
|
+
*
|
|
2908
|
+
* A config file — especially a `.properties` file or an env namespace you
|
|
2909
|
+
* merged in — can therefore hand you an own `__proto__` key, and what happens
|
|
2910
|
+
* next depends entirely on how the consumer copies it:
|
|
2911
|
+
*
|
|
2912
|
+
* ```ts
|
|
2913
|
+
* const data = cfg.toObject()
|
|
2914
|
+
* { ...data } // safe — own properties are copied as data
|
|
2915
|
+
* structuredClone(data) // safe
|
|
2916
|
+
* Object.assign({}, data) // NOT safe — [[Set]] on the {} target hits
|
|
2917
|
+
* // Object.prototype's __proto__ setter: the key
|
|
2918
|
+
* // vanishes and config data becomes the result's
|
|
2919
|
+
* // prototype
|
|
2920
|
+
* deepMerge({}, data) // NOT safe — a naive recursive merge reads
|
|
2921
|
+
* // target['__proto__'], gets Object.prototype,
|
|
2922
|
+
* // and writes to it: global pollution
|
|
2923
|
+
* for (const k in data) … // prefer Object.entries / Object.keys
|
|
2924
|
+
* ```
|
|
2925
|
+
*
|
|
2926
|
+
* Those two hazards come from the **destination** object's prototype, so no
|
|
2927
|
+
* option here can disarm them — copy with spread or `structuredClone` instead.
|
|
2928
|
+
*
|
|
2929
|
+
* What `{ nullPrototype: true }` does give you is a result that inherits
|
|
2930
|
+
* nothing: every object comes back with a `null` prototype, so reading
|
|
2931
|
+
* `x.__proto__`, `x.constructor` or `x.toString` yields config data or
|
|
2932
|
+
* `undefined` rather than something from `Object.prototype`, and code that
|
|
2933
|
+
* merges *into* this object cannot climb out of it. Keys are all still
|
|
2934
|
+
* present. The trade-off is the usual one for prototype-less objects: not
|
|
2935
|
+
* `instanceof Object`, and no `hasOwnProperty` of their own.
|
|
2936
|
+
*
|
|
2937
|
+
* Numbers follow the JS number model, so an integer wider than 2^53 rounds
|
|
2938
|
+
* here even when the config holds it exactly — read those with
|
|
2939
|
+
* {@link Config.getString} instead.
|
|
2940
|
+
*/
|
|
2941
|
+
toObject(opts) {
|
|
2942
|
+
return hoconToJs(this.root, opts?.nullPrototype === true);
|
|
2775
2943
|
}
|
|
2776
2944
|
/**
|
|
2777
2945
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
@@ -2883,16 +3051,25 @@ function scalarToJs(raw, valueType) {
|
|
|
2883
3051
|
return raw;
|
|
2884
3052
|
}
|
|
2885
3053
|
}
|
|
2886
|
-
function hoconToJs(v) {
|
|
3054
|
+
function hoconToJs(v, nullPrototype = false) {
|
|
2887
3055
|
switch (v.kind) {
|
|
2888
3056
|
case "scalar":
|
|
2889
3057
|
return scalarToJs(v.raw, v.valueType);
|
|
2890
3058
|
case "array":
|
|
2891
|
-
return v.items.map(hoconToJs);
|
|
3059
|
+
return v.items.map((item) => hoconToJs(item, nullPrototype));
|
|
2892
3060
|
case "object": {
|
|
2893
|
-
const
|
|
2894
|
-
|
|
2895
|
-
|
|
3061
|
+
const entries = Array.from(v.fields, ([k, val]) => [k, hoconToJs(val, nullPrototype)]);
|
|
3062
|
+
if (nullPrototype) {
|
|
3063
|
+
const obj = /* @__PURE__ */ Object.create(null);
|
|
3064
|
+
for (const [k, val] of entries) Object.defineProperty(obj, k, {
|
|
3065
|
+
value: val,
|
|
3066
|
+
writable: true,
|
|
3067
|
+
enumerable: true,
|
|
3068
|
+
configurable: true
|
|
3069
|
+
});
|
|
3070
|
+
return obj;
|
|
3071
|
+
}
|
|
3072
|
+
return Object.fromEntries(entries);
|
|
2896
3073
|
}
|
|
2897
3074
|
}
|
|
2898
3075
|
}
|
|
@@ -3126,6 +3303,8 @@ function empty(originDescription) {
|
|
|
3126
3303
|
const root = { kind: "object", fields: /* @__PURE__ */ new Map() };
|
|
3127
3304
|
return Config._fromResolvedValue(root, { originDescription });
|
|
3128
3305
|
}
|
|
3306
|
+
var INT64_MAX = 9223372036854775807n;
|
|
3307
|
+
var INT64_MIN = -9223372036854775808n;
|
|
3129
3308
|
function coerceObject(obj, atPath) {
|
|
3130
3309
|
const fields = /* @__PURE__ */ new Map();
|
|
3131
3310
|
for (const [k, v] of Object.entries(obj)) {
|
|
@@ -3154,14 +3333,14 @@ function coerceValue(v, atPath) {
|
|
|
3154
3333
|
atPath
|
|
3155
3334
|
);
|
|
3156
3335
|
}
|
|
3157
|
-
return { kind: "scalar", raw: String(v), valueType: "number" };
|
|
3336
|
+
return { kind: "scalar", raw: Object.is(v, -0) ? "-0" : String(v), valueType: "number" };
|
|
3158
3337
|
}
|
|
3159
3338
|
case "boolean":
|
|
3160
3339
|
return { kind: "scalar", raw: v ? "true" : "false", valueType: "boolean" };
|
|
3161
3340
|
case "bigint": {
|
|
3162
|
-
if (v >
|
|
3341
|
+
if (v > INT64_MAX || v < INT64_MIN) {
|
|
3163
3342
|
throw new ConfigError(
|
|
3164
|
-
`fromMap:
|
|
3343
|
+
`fromMap: integer ${v} is out of int64 range (HOCON integers are int64; spec F0.5) at path "${atPath}"`,
|
|
3165
3344
|
atPath
|
|
3166
3345
|
);
|
|
3167
3346
|
}
|