@o3co/ts.hocon 1.10.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 +90 -2
- package/dist/adapters/env.cjs +98 -28
- package/dist/adapters/env.d.cts +16 -1
- package/dist/adapters/env.d.ts +16 -1
- package/dist/adapters/env.js +98 -27
- package/dist/adapters/jsonc.cjs +120 -17
- package/dist/adapters/jsonc.d.cts +24 -4
- package/dist/adapters/jsonc.d.ts +24 -4
- package/dist/adapters/jsonc.js +120 -16
- package/dist/adapters/properties.cjs +87 -24
- package/dist/adapters/properties.d.cts +6 -1
- package/dist/adapters/properties.d.ts +6 -1
- package/dist/adapters/properties.js +87 -23
- package/dist/adapters/toml.cjs +79 -20
- package/dist/adapters/toml.d.cts +1 -1
- package/dist/adapters/toml.d.ts +1 -1
- package/dist/adapters/toml.js +79 -19
- package/dist/adapters/yaml.cjs +100 -24
- package/dist/adapters/yaml.d.cts +10 -2
- package/dist/adapters/yaml.d.ts +10 -2
- package/dist/adapters/yaml.js +100 -23
- package/dist/{config-PdhVgeLS.d.cts → config-Dlq6rF3w.d.cts} +47 -1
- package/dist/{config-PdhVgeLS.d.ts → config-Dlq6rF3w.d.ts} +47 -1
- package/dist/index.cjs +104 -22
- package/dist/index.d.cts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +111 -22
- package/dist/zod.cjs +100 -20
- package/dist/zod.d.cts +1 -1
- package/dist/zod.d.ts +1 -1
- package/dist/zod.js +107 -20
- package/package.json +58 -22
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) {
|
|
@@ -1481,25 +1489,39 @@ function parseTokens(tokens) {
|
|
|
1481
1489
|
return new Parser(tokens).parse();
|
|
1482
1490
|
}
|
|
1483
1491
|
|
|
1492
|
+
// src/internal/strip-bom.ts
|
|
1493
|
+
function stripBom(input) {
|
|
1494
|
+
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1484
1497
|
// src/internal/properties/properties.ts
|
|
1485
1498
|
function parseProperties(input) {
|
|
1486
1499
|
const pairs = [];
|
|
1487
|
-
for (const { text, line } of logicalLines(input)) {
|
|
1500
|
+
for (const { text, line } of logicalLines(stripBom(input))) {
|
|
1488
1501
|
const [rawKey, rawValue] = splitKeyValue(text);
|
|
1489
1502
|
const key = unescapeProps(rawKey, line);
|
|
1490
1503
|
if (key === "") continue;
|
|
1491
|
-
pairs.push([key, unescapeProps(rawValue, line)]);
|
|
1504
|
+
pairs.push([key.split("."), unescapeProps(rawValue, line)]);
|
|
1492
1505
|
}
|
|
1493
1506
|
return nestPairs(pairs);
|
|
1494
1507
|
}
|
|
1495
1508
|
function nestPairs(pairs) {
|
|
1496
1509
|
const root = /* @__PURE__ */ Object.create(null);
|
|
1497
|
-
const sorted = [...pairs].sort(([a], [b]) => a
|
|
1498
|
-
for (const [
|
|
1499
|
-
setNested(root,
|
|
1510
|
+
const sorted = [...pairs].sort(([a], [b]) => compareSegments(a, b));
|
|
1511
|
+
for (const [segments, value] of sorted) {
|
|
1512
|
+
setNested(root, segments, value);
|
|
1500
1513
|
}
|
|
1501
1514
|
return root;
|
|
1502
1515
|
}
|
|
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
|
+
}
|
|
1503
1525
|
function logicalLines(input) {
|
|
1504
1526
|
const natural = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
1505
1527
|
const out = [];
|
|
@@ -1586,19 +1608,16 @@ function unescapeProps(s, line) {
|
|
|
1586
1608
|
}
|
|
1587
1609
|
return out;
|
|
1588
1610
|
}
|
|
1589
|
-
var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1590
1611
|
function setNested(obj, segments, value) {
|
|
1591
1612
|
let current = obj;
|
|
1592
1613
|
for (let i = 0; i < segments.length - 1; i++) {
|
|
1593
1614
|
const seg = segments[i];
|
|
1594
|
-
if (seg === void 0 || DANGEROUS_KEYS.has(seg)) return;
|
|
1595
1615
|
if (!(seg in current) || typeof current[seg] !== "object" || current[seg] === null) {
|
|
1596
1616
|
current[seg] = /* @__PURE__ */ Object.create(null);
|
|
1597
1617
|
}
|
|
1598
1618
|
current = current[seg];
|
|
1599
1619
|
}
|
|
1600
1620
|
const last = segments[segments.length - 1];
|
|
1601
|
-
if (last === void 0 || DANGEROUS_KEYS.has(last)) return;
|
|
1602
1621
|
if (typeof current[last] === "object" && current[last] !== null) return;
|
|
1603
1622
|
current[last] = value;
|
|
1604
1623
|
}
|
|
@@ -1619,7 +1638,22 @@ function recordToHoconValue(obj) {
|
|
|
1619
1638
|
}
|
|
1620
1639
|
|
|
1621
1640
|
// src/internal/resolver/include-loader.ts
|
|
1622
|
-
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
|
+
}
|
|
1623
1657
|
function isPnpPath(p) {
|
|
1624
1658
|
return p.includes(".yarn/cache") || p.includes(".pnp.cjs") || p.includes(".pnp.loader");
|
|
1625
1659
|
}
|
|
@@ -1675,7 +1709,7 @@ function defaultPackageResolver(identifier, file, includingFile, baseDir, resolv
|
|
|
1675
1709
|
const from = resolveFrom ? Array.isArray(resolveFrom) ? resolveFrom : [resolveFrom] : baseDir ? [baseDir] : includingFile ? [nodePath.dirname(includingFile)] : [process.cwd()];
|
|
1676
1710
|
let resolved;
|
|
1677
1711
|
try {
|
|
1678
|
-
resolved =
|
|
1712
|
+
resolved = getRequire().resolve(`${identifier}/${file}`, { paths: from });
|
|
1679
1713
|
} catch {
|
|
1680
1714
|
throw new PackageLookupError(
|
|
1681
1715
|
`include package("${identifier}", "${file}"): module not found (starting from: ${from.join(", ")})`,
|
|
@@ -2729,10 +2763,10 @@ var Config = class _Config {
|
|
|
2729
2763
|
}
|
|
2730
2764
|
if (v.kind === "object") {
|
|
2731
2765
|
const converted = numericObjectToArray(v);
|
|
2732
|
-
if (converted !== null) return converted.map(hoconToJs);
|
|
2766
|
+
if (converted !== null) return converted.map((item) => hoconToJs(item));
|
|
2733
2767
|
}
|
|
2734
2768
|
if (v.kind !== "array") throw new ConfigError(`expected array at ${path2}`, path2);
|
|
2735
|
-
return v.items.map(hoconToJs);
|
|
2769
|
+
return v.items.map((item) => hoconToJs(item));
|
|
2736
2770
|
}
|
|
2737
2771
|
has(path2) {
|
|
2738
2772
|
return this.lookupNode(path2) !== void 0;
|
|
@@ -2860,8 +2894,52 @@ var Config = class _Config {
|
|
|
2860
2894
|
originDescription: this._originDescription
|
|
2861
2895
|
});
|
|
2862
2896
|
}
|
|
2863
|
-
|
|
2864
|
-
|
|
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);
|
|
2865
2943
|
}
|
|
2866
2944
|
/**
|
|
2867
2945
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
@@ -2973,16 +3051,25 @@ function scalarToJs(raw, valueType) {
|
|
|
2973
3051
|
return raw;
|
|
2974
3052
|
}
|
|
2975
3053
|
}
|
|
2976
|
-
function hoconToJs(v) {
|
|
3054
|
+
function hoconToJs(v, nullPrototype = false) {
|
|
2977
3055
|
switch (v.kind) {
|
|
2978
3056
|
case "scalar":
|
|
2979
3057
|
return scalarToJs(v.raw, v.valueType);
|
|
2980
3058
|
case "array":
|
|
2981
|
-
return v.items.map(hoconToJs);
|
|
3059
|
+
return v.items.map((item) => hoconToJs(item, nullPrototype));
|
|
2982
3060
|
case "object": {
|
|
2983
|
-
const
|
|
2984
|
-
|
|
2985
|
-
|
|
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);
|
|
2986
3073
|
}
|
|
2987
3074
|
}
|
|
2988
3075
|
}
|
|
@@ -3216,6 +3303,8 @@ function empty(originDescription) {
|
|
|
3216
3303
|
const root = { kind: "object", fields: /* @__PURE__ */ new Map() };
|
|
3217
3304
|
return Config._fromResolvedValue(root, { originDescription });
|
|
3218
3305
|
}
|
|
3306
|
+
var INT64_MAX = 9223372036854775807n;
|
|
3307
|
+
var INT64_MIN = -9223372036854775808n;
|
|
3219
3308
|
function coerceObject(obj, atPath) {
|
|
3220
3309
|
const fields = /* @__PURE__ */ new Map();
|
|
3221
3310
|
for (const [k, v] of Object.entries(obj)) {
|
|
@@ -3244,14 +3333,14 @@ function coerceValue(v, atPath) {
|
|
|
3244
3333
|
atPath
|
|
3245
3334
|
);
|
|
3246
3335
|
}
|
|
3247
|
-
return { kind: "scalar", raw: String(v), valueType: "number" };
|
|
3336
|
+
return { kind: "scalar", raw: Object.is(v, -0) ? "-0" : String(v), valueType: "number" };
|
|
3248
3337
|
}
|
|
3249
3338
|
case "boolean":
|
|
3250
3339
|
return { kind: "scalar", raw: v ? "true" : "false", valueType: "boolean" };
|
|
3251
3340
|
case "bigint": {
|
|
3252
|
-
if (v >
|
|
3341
|
+
if (v > INT64_MAX || v < INT64_MIN) {
|
|
3253
3342
|
throw new ConfigError(
|
|
3254
|
-
`fromMap:
|
|
3343
|
+
`fromMap: integer ${v} is out of int64 range (HOCON integers are int64; spec F0.5) at path "${atPath}"`,
|
|
3255
3344
|
atPath
|
|
3256
3345
|
);
|
|
3257
3346
|
}
|
package/dist/zod.cjs
CHANGED
|
@@ -682,6 +682,7 @@ function isFileNotFoundError(e) {
|
|
|
682
682
|
// src/internal/resolver/include-loader.ts
|
|
683
683
|
var import_node_module = require("module");
|
|
684
684
|
var nodePath = __toESM(require("path"), 1);
|
|
685
|
+
var import_node_url = require("url");
|
|
685
686
|
|
|
686
687
|
// src/internal/lexer/lexer.ts
|
|
687
688
|
function isHoconWhitespace(ch) {
|
|
@@ -1524,25 +1525,39 @@ function parseTokens(tokens) {
|
|
|
1524
1525
|
return new Parser(tokens).parse();
|
|
1525
1526
|
}
|
|
1526
1527
|
|
|
1528
|
+
// src/internal/strip-bom.ts
|
|
1529
|
+
function stripBom(input) {
|
|
1530
|
+
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1527
1533
|
// src/internal/properties/properties.ts
|
|
1528
1534
|
function parseProperties(input) {
|
|
1529
1535
|
const pairs = [];
|
|
1530
|
-
for (const { text, line } of logicalLines(input)) {
|
|
1536
|
+
for (const { text, line } of logicalLines(stripBom(input))) {
|
|
1531
1537
|
const [rawKey, rawValue] = splitKeyValue(text);
|
|
1532
1538
|
const key = unescapeProps(rawKey, line);
|
|
1533
1539
|
if (key === "") continue;
|
|
1534
|
-
pairs.push([key, unescapeProps(rawValue, line)]);
|
|
1540
|
+
pairs.push([key.split("."), unescapeProps(rawValue, line)]);
|
|
1535
1541
|
}
|
|
1536
1542
|
return nestPairs(pairs);
|
|
1537
1543
|
}
|
|
1538
1544
|
function nestPairs(pairs) {
|
|
1539
1545
|
const root = /* @__PURE__ */ Object.create(null);
|
|
1540
|
-
const sorted = [...pairs].sort(([a], [b]) => a
|
|
1541
|
-
for (const [
|
|
1542
|
-
setNested(root,
|
|
1546
|
+
const sorted = [...pairs].sort(([a], [b]) => compareSegments(a, b));
|
|
1547
|
+
for (const [segments, value] of sorted) {
|
|
1548
|
+
setNested(root, segments, value);
|
|
1543
1549
|
}
|
|
1544
1550
|
return root;
|
|
1545
1551
|
}
|
|
1552
|
+
function compareSegments(a, b) {
|
|
1553
|
+
const n = Math.min(a.length, b.length);
|
|
1554
|
+
for (let i = 0; i < n; i++) {
|
|
1555
|
+
const x = a[i];
|
|
1556
|
+
const y = b[i];
|
|
1557
|
+
if (x !== y) return x < y ? -1 : 1;
|
|
1558
|
+
}
|
|
1559
|
+
return a.length - b.length;
|
|
1560
|
+
}
|
|
1546
1561
|
function logicalLines(input) {
|
|
1547
1562
|
const natural = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
1548
1563
|
const out = [];
|
|
@@ -1629,19 +1644,16 @@ function unescapeProps(s, line) {
|
|
|
1629
1644
|
}
|
|
1630
1645
|
return out;
|
|
1631
1646
|
}
|
|
1632
|
-
var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1633
1647
|
function setNested(obj, segments, value) {
|
|
1634
1648
|
let current = obj;
|
|
1635
1649
|
for (let i = 0; i < segments.length - 1; i++) {
|
|
1636
1650
|
const seg = segments[i];
|
|
1637
|
-
if (seg === void 0 || DANGEROUS_KEYS.has(seg)) return;
|
|
1638
1651
|
if (!(seg in current) || typeof current[seg] !== "object" || current[seg] === null) {
|
|
1639
1652
|
current[seg] = /* @__PURE__ */ Object.create(null);
|
|
1640
1653
|
}
|
|
1641
1654
|
current = current[seg];
|
|
1642
1655
|
}
|
|
1643
1656
|
const last = segments[segments.length - 1];
|
|
1644
|
-
if (last === void 0 || DANGEROUS_KEYS.has(last)) return;
|
|
1645
1657
|
if (typeof current[last] === "object" && current[last] !== null) return;
|
|
1646
1658
|
current[last] = value;
|
|
1647
1659
|
}
|
|
@@ -1663,7 +1675,22 @@ function recordToHoconValue(obj) {
|
|
|
1663
1675
|
|
|
1664
1676
|
// src/internal/resolver/include-loader.ts
|
|
1665
1677
|
var import_meta = {};
|
|
1666
|
-
var _require
|
|
1678
|
+
var _require;
|
|
1679
|
+
function getRequire() {
|
|
1680
|
+
if (_require === void 0) {
|
|
1681
|
+
_require = pickRequire(
|
|
1682
|
+
typeof require === "function" ? require : void 0,
|
|
1683
|
+
import_meta.url
|
|
1684
|
+
);
|
|
1685
|
+
}
|
|
1686
|
+
return _require;
|
|
1687
|
+
}
|
|
1688
|
+
function pickRequire(candidate, metaUrl) {
|
|
1689
|
+
if (typeof candidate?.resolve === "function") {
|
|
1690
|
+
return candidate;
|
|
1691
|
+
}
|
|
1692
|
+
return (0, import_node_module.createRequire)(metaUrl ?? (0, import_node_url.pathToFileURL)(nodePath.join(process.cwd(), "noop.js")));
|
|
1693
|
+
}
|
|
1667
1694
|
function isPnpPath(p) {
|
|
1668
1695
|
return p.includes(".yarn/cache") || p.includes(".pnp.cjs") || p.includes(".pnp.loader");
|
|
1669
1696
|
}
|
|
@@ -1719,7 +1746,7 @@ function defaultPackageResolver(identifier, file, includingFile, baseDir, resolv
|
|
|
1719
1746
|
const from = resolveFrom ? Array.isArray(resolveFrom) ? resolveFrom : [resolveFrom] : baseDir ? [baseDir] : includingFile ? [nodePath.dirname(includingFile)] : [process.cwd()];
|
|
1720
1747
|
let resolved;
|
|
1721
1748
|
try {
|
|
1722
|
-
resolved =
|
|
1749
|
+
resolved = getRequire().resolve(`${identifier}/${file}`, { paths: from });
|
|
1723
1750
|
} catch {
|
|
1724
1751
|
throw new PackageLookupError(
|
|
1725
1752
|
`include package("${identifier}", "${file}"): module not found (starting from: ${from.join(", ")})`,
|
|
@@ -2769,10 +2796,10 @@ var Config = class _Config {
|
|
|
2769
2796
|
}
|
|
2770
2797
|
if (v.kind === "object") {
|
|
2771
2798
|
const converted = numericObjectToArray(v);
|
|
2772
|
-
if (converted !== null) return converted.map(hoconToJs);
|
|
2799
|
+
if (converted !== null) return converted.map((item) => hoconToJs(item));
|
|
2773
2800
|
}
|
|
2774
2801
|
if (v.kind !== "array") throw new ConfigError(`expected array at ${path2}`, path2);
|
|
2775
|
-
return v.items.map(hoconToJs);
|
|
2802
|
+
return v.items.map((item) => hoconToJs(item));
|
|
2776
2803
|
}
|
|
2777
2804
|
has(path2) {
|
|
2778
2805
|
return this.lookupNode(path2) !== void 0;
|
|
@@ -2900,8 +2927,52 @@ var Config = class _Config {
|
|
|
2900
2927
|
originDescription: this._originDescription
|
|
2901
2928
|
});
|
|
2902
2929
|
}
|
|
2903
|
-
|
|
2904
|
-
|
|
2930
|
+
/**
|
|
2931
|
+
* The whole config as plain JS data: objects, arrays, strings, numbers,
|
|
2932
|
+
* booleans and `null`.
|
|
2933
|
+
*
|
|
2934
|
+
* Keys are reproduced exactly as the config carries them, `__proto__`,
|
|
2935
|
+
* `constructor` and `prototype` included: each is defined as an **own data
|
|
2936
|
+
* property**, so the returned object's prototype is always
|
|
2937
|
+
* `Object.prototype`, and this call writes nothing to the global one.
|
|
2938
|
+
*
|
|
2939
|
+
* ### Passing the result to other code
|
|
2940
|
+
*
|
|
2941
|
+
* A config file — especially a `.properties` file or an env namespace you
|
|
2942
|
+
* merged in — can therefore hand you an own `__proto__` key, and what happens
|
|
2943
|
+
* next depends entirely on how the consumer copies it:
|
|
2944
|
+
*
|
|
2945
|
+
* ```ts
|
|
2946
|
+
* const data = cfg.toObject()
|
|
2947
|
+
* { ...data } // safe — own properties are copied as data
|
|
2948
|
+
* structuredClone(data) // safe
|
|
2949
|
+
* Object.assign({}, data) // NOT safe — [[Set]] on the {} target hits
|
|
2950
|
+
* // Object.prototype's __proto__ setter: the key
|
|
2951
|
+
* // vanishes and config data becomes the result's
|
|
2952
|
+
* // prototype
|
|
2953
|
+
* deepMerge({}, data) // NOT safe — a naive recursive merge reads
|
|
2954
|
+
* // target['__proto__'], gets Object.prototype,
|
|
2955
|
+
* // and writes to it: global pollution
|
|
2956
|
+
* for (const k in data) … // prefer Object.entries / Object.keys
|
|
2957
|
+
* ```
|
|
2958
|
+
*
|
|
2959
|
+
* Those two hazards come from the **destination** object's prototype, so no
|
|
2960
|
+
* option here can disarm them — copy with spread or `structuredClone` instead.
|
|
2961
|
+
*
|
|
2962
|
+
* What `{ nullPrototype: true }` does give you is a result that inherits
|
|
2963
|
+
* nothing: every object comes back with a `null` prototype, so reading
|
|
2964
|
+
* `x.__proto__`, `x.constructor` or `x.toString` yields config data or
|
|
2965
|
+
* `undefined` rather than something from `Object.prototype`, and code that
|
|
2966
|
+
* merges *into* this object cannot climb out of it. Keys are all still
|
|
2967
|
+
* present. The trade-off is the usual one for prototype-less objects: not
|
|
2968
|
+
* `instanceof Object`, and no `hasOwnProperty` of their own.
|
|
2969
|
+
*
|
|
2970
|
+
* Numbers follow the JS number model, so an integer wider than 2^53 rounds
|
|
2971
|
+
* here even when the config holds it exactly — read those with
|
|
2972
|
+
* {@link Config.getString} instead.
|
|
2973
|
+
*/
|
|
2974
|
+
toObject(opts) {
|
|
2975
|
+
return hoconToJs(this.root, opts?.nullPrototype === true);
|
|
2905
2976
|
}
|
|
2906
2977
|
/**
|
|
2907
2978
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
@@ -3013,16 +3084,25 @@ function scalarToJs(raw, valueType) {
|
|
|
3013
3084
|
return raw;
|
|
3014
3085
|
}
|
|
3015
3086
|
}
|
|
3016
|
-
function hoconToJs(v) {
|
|
3087
|
+
function hoconToJs(v, nullPrototype = false) {
|
|
3017
3088
|
switch (v.kind) {
|
|
3018
3089
|
case "scalar":
|
|
3019
3090
|
return scalarToJs(v.raw, v.valueType);
|
|
3020
3091
|
case "array":
|
|
3021
|
-
return v.items.map(hoconToJs);
|
|
3092
|
+
return v.items.map((item) => hoconToJs(item, nullPrototype));
|
|
3022
3093
|
case "object": {
|
|
3023
|
-
const
|
|
3024
|
-
|
|
3025
|
-
|
|
3094
|
+
const entries = Array.from(v.fields, ([k, val]) => [k, hoconToJs(val, nullPrototype)]);
|
|
3095
|
+
if (nullPrototype) {
|
|
3096
|
+
const obj = /* @__PURE__ */ Object.create(null);
|
|
3097
|
+
for (const [k, val] of entries) Object.defineProperty(obj, k, {
|
|
3098
|
+
value: val,
|
|
3099
|
+
writable: true,
|
|
3100
|
+
enumerable: true,
|
|
3101
|
+
configurable: true
|
|
3102
|
+
});
|
|
3103
|
+
return obj;
|
|
3104
|
+
}
|
|
3105
|
+
return Object.fromEntries(entries);
|
|
3026
3106
|
}
|
|
3027
3107
|
}
|
|
3028
3108
|
}
|
|
@@ -3213,7 +3293,7 @@ function coerceValue(value, schema) {
|
|
|
3213
3293
|
const obj = value;
|
|
3214
3294
|
const result = { ...obj };
|
|
3215
3295
|
for (const key of Object.keys(shape)) {
|
|
3216
|
-
if (key
|
|
3296
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
3217
3297
|
result[key] = coerceValue(obj[key], shape[key]);
|
|
3218
3298
|
}
|
|
3219
3299
|
}
|
package/dist/zod.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ZodType } from 'zod';
|
|
2
|
-
import { C as Config, a as ParseOptions } from './config-
|
|
2
|
+
import { C as Config, a as ParseOptions } from './config-Dlq6rF3w.cjs';
|
|
3
3
|
|
|
4
4
|
declare function validate<T>(config: Config, schema: ZodType<T>): T;
|
|
5
5
|
declare function getValidated<T>(config: Config, path: string, schema: ZodType<T>): T;
|
package/dist/zod.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ZodType } from 'zod';
|
|
2
|
-
import { C as Config, a as ParseOptions } from './config-
|
|
2
|
+
import { C as Config, a as ParseOptions } from './config-Dlq6rF3w.js';
|
|
3
3
|
|
|
4
4
|
declare function validate<T>(config: Config, schema: ZodType<T>): T;
|
|
5
5
|
declare function getValidated<T>(config: Config, path: string, schema: ZodType<T>): T;
|