@o3co/ts.hocon 1.11.0 → 1.12.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 +13 -8
- package/dist/adapters/env.cjs +52 -3
- package/dist/adapters/env.js +52 -3
- package/dist/adapters/jsonc.cjs +29 -2
- package/dist/adapters/jsonc.d.cts +12 -1
- package/dist/adapters/jsonc.d.ts +12 -1
- package/dist/adapters/jsonc.js +29 -2
- package/dist/adapters/properties.cjs +38 -2
- package/dist/adapters/properties.js +38 -2
- package/dist/adapters/toml.cjs +32 -2
- package/dist/adapters/toml.d.cts +2 -1
- package/dist/adapters/toml.d.ts +2 -1
- package/dist/adapters/toml.js +32 -2
- package/dist/adapters/yaml.cjs +42 -3
- package/dist/adapters/yaml.d.cts +2 -1
- package/dist/adapters/yaml.d.ts +2 -1
- package/dist/adapters/yaml.js +42 -3
- package/dist/index.cjs +59 -10
- package/dist/index.js +59 -10
- package/dist/zod.cjs +54 -4
- package/dist/zod.js +54 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -265,12 +265,12 @@ Supported byte units: `B`, `KB`/`KiB`, `MB`/`MiB`, `GB`/`GiB`, `TB`/`TiB` (and l
|
|
|
265
265
|
|
|
266
266
|
## Spec Compliance
|
|
267
267
|
|
|
268
|
-
Conformance against the [Lightbend HOCON specification](https://github.com/lightbend/config/blob/main/HOCON.md) is tracked at item granularity in [`docs/spec-compliance.md`](docs/spec-compliance.md).
|
|
268
|
+
Conformance against the [Lightbend HOCON specification](https://github.com/lightbend/config/blob/main/HOCON.md) is tracked at item granularity in [`docs/spec-compliance.md`](docs/spec-compliance.md), which is the source these rates are computed from — `tests/docs.test.ts` recomputes them and fails the build if this table drifts. See [`xx.hocon/docs/compliance-matrix.md`](https://github.com/o3co/xx.hocon/blob/main/docs/compliance-matrix.md) for the cross-implementation roll-up.
|
|
269
269
|
|
|
270
270
|
| Metric | Status |
|
|
271
271
|
| ------------------------------------- | ------------- |
|
|
272
|
-
| Spec total (incl. out-of-scope) | **
|
|
273
|
-
| In-scope only | **
|
|
272
|
+
| Spec total (incl. out-of-scope) | **89.3%** |
|
|
273
|
+
| In-scope only | **99.2%** |
|
|
274
274
|
| Lightbend `test01`–`test13` suite | 13/13 passing |
|
|
275
275
|
|
|
276
276
|
**Extra-spec conventions (E-series) — implementation status:**
|
|
@@ -289,10 +289,6 @@ Supported since v0.2.0 (P1):
|
|
|
289
289
|
|
|
290
290
|
- `.properties` file parsing
|
|
291
291
|
|
|
292
|
-
### Stricter than Lightbend
|
|
293
|
-
|
|
294
|
-
- **S8.6 leading-hyphen rejection** (Unreleased): `a = -foo`, `a = -bar`, `a = -` etc. now raise a lex error per HOCON.md L270–276, where Lightbend silently falls back to unquoted strings. Mitigation: quote the value (`a = "-foo"`). See [CHANGELOG](CHANGELOG.md#unreleased) and [`docs/spec-compliance.md`](docs/spec-compliance.md) §S8.6.
|
|
295
|
-
|
|
296
292
|
## Performance
|
|
297
293
|
|
|
298
294
|
### ts.hocon Parsing Cost
|
|
@@ -325,7 +321,7 @@ For typical application configs (loaded once at startup), the parsing cost is ne
|
|
|
325
321
|
|
|
326
322
|
### Feature Comparison with node-config
|
|
327
323
|
|
|
328
|
-
|
|
324
|
+
Feature-level comparison with [node-config](https://github.com/node-config/node-config) **v4.4.2** reading JSON config files, as of 2026-07-26:
|
|
329
325
|
|
|
330
326
|
| Feature | ts.hocon | node-config (JSON) |
|
|
331
327
|
|---|---|---|
|
|
@@ -498,6 +494,15 @@ When parsing untrusted HOCON input, be aware of:
|
|
|
498
494
|
- **Path traversal in includes:** a relative `include` path resolves against `baseDir` and can climb out of it with `..` segments to reach sensitive files such as `/etc/passwd`. Use a custom `readFileSync`/`readFile` that validates paths if parsing untrusted input.
|
|
499
495
|
- **Input size:** The parser has no built-in input size limit. For untrusted input, validate size before calling `parse()`.
|
|
500
496
|
- **Include depth:** Limited to 50 levels to prevent stack overflow from deep include chains.
|
|
497
|
+
- **Mapped path depth:** an environment variable's `__` segments and a
|
|
498
|
+
`.properties` dotted key are limited to 64 segments. One name produces one
|
|
499
|
+
arbitrarily deep chain, so without the cap a single long variable name was
|
|
500
|
+
enough to exhaust the stack. rs.hocon and py.hocon cap the same mapping at 64.
|
|
501
|
+
- **Document nesting depth:** not capped. A document nested past what the
|
|
502
|
+
engine's stack holds fails as `ParseError` or `ConfigError` — never as a bare
|
|
503
|
+
`RangeError` — but the depth at which that happens depends on how deep the
|
|
504
|
+
calling code already is, so validate size before parsing untrusted input (see
|
|
505
|
+
above) rather than relying on a fixed level.
|
|
501
506
|
- **Prototype pollution:** keys named `__proto__`, `constructor` or `prototype`
|
|
502
507
|
are **kept as ordinary keys** — a `.properties` file or environment variable
|
|
503
508
|
may legitimately use them, and dropping them would be silent data loss.
|
package/dist/adapters/env.cjs
CHANGED
|
@@ -557,6 +557,31 @@ function stripBom(input) {
|
|
|
557
557
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
558
558
|
}
|
|
559
559
|
|
|
560
|
+
// src/internal/depth.ts
|
|
561
|
+
var MAX_PATH_SEGMENTS = 64;
|
|
562
|
+
function tooDeep(segments) {
|
|
563
|
+
return segments > MAX_PATH_SEGMENTS;
|
|
564
|
+
}
|
|
565
|
+
function guardStackDepth(fn, wrap) {
|
|
566
|
+
try {
|
|
567
|
+
return fn();
|
|
568
|
+
} catch (e) {
|
|
569
|
+
if (!isStackOverflow(e)) throw e;
|
|
570
|
+
throw wrap(STACK_MESSAGE);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
574
|
+
function isStackOverflow(e) {
|
|
575
|
+
if (!(e instanceof RangeError)) return false;
|
|
576
|
+
const m = e.message.toLowerCase();
|
|
577
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
578
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
579
|
+
m.includes("stack overflow");
|
|
580
|
+
}
|
|
581
|
+
function depthError(message) {
|
|
582
|
+
return new ConfigError(message, "");
|
|
583
|
+
}
|
|
584
|
+
|
|
560
585
|
// src/internal/properties/properties.ts
|
|
561
586
|
function nestPairs(pairs) {
|
|
562
587
|
const root = /* @__PURE__ */ Object.create(null);
|
|
@@ -1570,7 +1595,10 @@ function normalizeLeadingZeroNumber(raw) {
|
|
|
1570
1595
|
|
|
1571
1596
|
// src/value-factory.ts
|
|
1572
1597
|
function fromMap(values, originDescription) {
|
|
1573
|
-
const fields =
|
|
1598
|
+
const fields = guardStackDepth(
|
|
1599
|
+
() => coerceObject(values, ""),
|
|
1600
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
1601
|
+
);
|
|
1574
1602
|
const root = { kind: "object", fields };
|
|
1575
1603
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1576
1604
|
}
|
|
@@ -1670,13 +1698,14 @@ function parseDotEnv(input, opts = {}) {
|
|
|
1670
1698
|
for (let i = 0; i < lines.length; i++) {
|
|
1671
1699
|
const raw = (lines[i] ?? "").trim();
|
|
1672
1700
|
if (raw === "" || raw.startsWith("#")) continue;
|
|
1673
|
-
const line =
|
|
1701
|
+
const line = stripExport(raw);
|
|
1674
1702
|
const eq = line.indexOf("=");
|
|
1675
1703
|
if (eq === -1) throw new ConfigError(`${origin}:${i + 1}: expected NAME=value`, "");
|
|
1676
1704
|
const name = line.slice(0, eq).trim();
|
|
1677
1705
|
if (name === "") throw new ConfigError(`${origin}:${i + 1}: empty variable name`, "");
|
|
1678
|
-
const value = dotEnvValue(line.slice(eq + 1).replace(/^[ \t]+/, ""), origin, i + 1, name);
|
|
1679
1706
|
if (!name.startsWith(prefix)) continue;
|
|
1707
|
+
checkName(name, origin, i + 1);
|
|
1708
|
+
const value = dotEnvValue(line.slice(eq + 1).replace(/^[ \t]+/, ""), origin, i + 1, name);
|
|
1680
1709
|
pairs.push([toPath(name.slice(prefix.length)), value]);
|
|
1681
1710
|
}
|
|
1682
1711
|
return fromMap(nestPairs(pairs), origin);
|
|
@@ -1686,6 +1715,12 @@ function toPath(name) {
|
|
|
1686
1715
|
if (segs.some((s) => s === "")) {
|
|
1687
1716
|
throw new ConfigError(`env: "${name}" produces an empty path segment`, name);
|
|
1688
1717
|
}
|
|
1718
|
+
if (tooDeep(segs.length)) {
|
|
1719
|
+
throw new ConfigError(
|
|
1720
|
+
`env: "${name}" maps to a path ${segs.length} segments deep, over the limit of ${MAX_PATH_SEGMENTS}`,
|
|
1721
|
+
name
|
|
1722
|
+
);
|
|
1723
|
+
}
|
|
1689
1724
|
return segs;
|
|
1690
1725
|
}
|
|
1691
1726
|
function asciiLower(s) {
|
|
@@ -1731,6 +1766,20 @@ function dotEnvValue(v, origin, line, name) {
|
|
|
1731
1766
|
}
|
|
1732
1767
|
return trimmed;
|
|
1733
1768
|
}
|
|
1769
|
+
function stripExport(line) {
|
|
1770
|
+
const m = /^export[ \t]+/.exec(line);
|
|
1771
|
+
return m ? line.slice(m[0].length) : line;
|
|
1772
|
+
}
|
|
1773
|
+
function checkName(name, origin, line) {
|
|
1774
|
+
const bad = /\p{White_Space}|#/u.exec(name);
|
|
1775
|
+
if (bad) {
|
|
1776
|
+
const what = bad[0] === "#" ? "'#'" : "whitespace";
|
|
1777
|
+
throw new ConfigError(
|
|
1778
|
+
`${origin}:${line}: variable name "${name}" contains ${what}; the line is not NAME=value (spec F1.7)`,
|
|
1779
|
+
name
|
|
1780
|
+
);
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1734
1783
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1735
1784
|
0 && (module.exports = {
|
|
1736
1785
|
loadEnv,
|
package/dist/adapters/env.js
CHANGED
|
@@ -520,6 +520,31 @@ function stripBom(input) {
|
|
|
520
520
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
521
521
|
}
|
|
522
522
|
|
|
523
|
+
// src/internal/depth.ts
|
|
524
|
+
var MAX_PATH_SEGMENTS = 64;
|
|
525
|
+
function tooDeep(segments) {
|
|
526
|
+
return segments > MAX_PATH_SEGMENTS;
|
|
527
|
+
}
|
|
528
|
+
function guardStackDepth(fn, wrap) {
|
|
529
|
+
try {
|
|
530
|
+
return fn();
|
|
531
|
+
} catch (e) {
|
|
532
|
+
if (!isStackOverflow(e)) throw e;
|
|
533
|
+
throw wrap(STACK_MESSAGE);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
537
|
+
function isStackOverflow(e) {
|
|
538
|
+
if (!(e instanceof RangeError)) return false;
|
|
539
|
+
const m = e.message.toLowerCase();
|
|
540
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
541
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
542
|
+
m.includes("stack overflow");
|
|
543
|
+
}
|
|
544
|
+
function depthError(message) {
|
|
545
|
+
return new ConfigError(message, "");
|
|
546
|
+
}
|
|
547
|
+
|
|
523
548
|
// src/internal/properties/properties.ts
|
|
524
549
|
function nestPairs(pairs) {
|
|
525
550
|
const root = /* @__PURE__ */ Object.create(null);
|
|
@@ -1533,7 +1558,10 @@ function normalizeLeadingZeroNumber(raw) {
|
|
|
1533
1558
|
|
|
1534
1559
|
// src/value-factory.ts
|
|
1535
1560
|
function fromMap(values, originDescription) {
|
|
1536
|
-
const fields =
|
|
1561
|
+
const fields = guardStackDepth(
|
|
1562
|
+
() => coerceObject(values, ""),
|
|
1563
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
1564
|
+
);
|
|
1537
1565
|
const root = { kind: "object", fields };
|
|
1538
1566
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1539
1567
|
}
|
|
@@ -1633,13 +1661,14 @@ function parseDotEnv(input, opts = {}) {
|
|
|
1633
1661
|
for (let i = 0; i < lines.length; i++) {
|
|
1634
1662
|
const raw = (lines[i] ?? "").trim();
|
|
1635
1663
|
if (raw === "" || raw.startsWith("#")) continue;
|
|
1636
|
-
const line =
|
|
1664
|
+
const line = stripExport(raw);
|
|
1637
1665
|
const eq = line.indexOf("=");
|
|
1638
1666
|
if (eq === -1) throw new ConfigError(`${origin}:${i + 1}: expected NAME=value`, "");
|
|
1639
1667
|
const name = line.slice(0, eq).trim();
|
|
1640
1668
|
if (name === "") throw new ConfigError(`${origin}:${i + 1}: empty variable name`, "");
|
|
1641
|
-
const value = dotEnvValue(line.slice(eq + 1).replace(/^[ \t]+/, ""), origin, i + 1, name);
|
|
1642
1669
|
if (!name.startsWith(prefix)) continue;
|
|
1670
|
+
checkName(name, origin, i + 1);
|
|
1671
|
+
const value = dotEnvValue(line.slice(eq + 1).replace(/^[ \t]+/, ""), origin, i + 1, name);
|
|
1643
1672
|
pairs.push([toPath(name.slice(prefix.length)), value]);
|
|
1644
1673
|
}
|
|
1645
1674
|
return fromMap(nestPairs(pairs), origin);
|
|
@@ -1649,6 +1678,12 @@ function toPath(name) {
|
|
|
1649
1678
|
if (segs.some((s) => s === "")) {
|
|
1650
1679
|
throw new ConfigError(`env: "${name}" produces an empty path segment`, name);
|
|
1651
1680
|
}
|
|
1681
|
+
if (tooDeep(segs.length)) {
|
|
1682
|
+
throw new ConfigError(
|
|
1683
|
+
`env: "${name}" maps to a path ${segs.length} segments deep, over the limit of ${MAX_PATH_SEGMENTS}`,
|
|
1684
|
+
name
|
|
1685
|
+
);
|
|
1686
|
+
}
|
|
1652
1687
|
return segs;
|
|
1653
1688
|
}
|
|
1654
1689
|
function asciiLower(s) {
|
|
@@ -1694,6 +1729,20 @@ function dotEnvValue(v, origin, line, name) {
|
|
|
1694
1729
|
}
|
|
1695
1730
|
return trimmed;
|
|
1696
1731
|
}
|
|
1732
|
+
function stripExport(line) {
|
|
1733
|
+
const m = /^export[ \t]+/.exec(line);
|
|
1734
|
+
return m ? line.slice(m[0].length) : line;
|
|
1735
|
+
}
|
|
1736
|
+
function checkName(name, origin, line) {
|
|
1737
|
+
const bad = /\p{White_Space}|#/u.exec(name);
|
|
1738
|
+
if (bad) {
|
|
1739
|
+
const what = bad[0] === "#" ? "'#'" : "whitespace";
|
|
1740
|
+
throw new ConfigError(
|
|
1741
|
+
`${origin}:${line}: variable name "${name}" contains ${what}; the line is not NAME=value (spec F1.7)`,
|
|
1742
|
+
name
|
|
1743
|
+
);
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1697
1746
|
export {
|
|
1698
1747
|
loadEnv,
|
|
1699
1748
|
parseDotEnv
|
package/dist/adapters/jsonc.cjs
CHANGED
|
@@ -557,6 +557,27 @@ function stripBom(input) {
|
|
|
557
557
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
558
558
|
}
|
|
559
559
|
|
|
560
|
+
// src/internal/depth.ts
|
|
561
|
+
function guardStackDepth(fn, wrap) {
|
|
562
|
+
try {
|
|
563
|
+
return fn();
|
|
564
|
+
} catch (e) {
|
|
565
|
+
if (!isStackOverflow(e)) throw e;
|
|
566
|
+
throw wrap(STACK_MESSAGE);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
570
|
+
function isStackOverflow(e) {
|
|
571
|
+
if (!(e instanceof RangeError)) return false;
|
|
572
|
+
const m = e.message.toLowerCase();
|
|
573
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
574
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
575
|
+
m.includes("stack overflow");
|
|
576
|
+
}
|
|
577
|
+
function depthError(message) {
|
|
578
|
+
return new ConfigError(message, "");
|
|
579
|
+
}
|
|
580
|
+
|
|
560
581
|
// src/value/numeric-array.ts
|
|
561
582
|
function numericObjectToArray(value) {
|
|
562
583
|
if (value.kind !== "object") return null;
|
|
@@ -1535,7 +1556,10 @@ function normalizeLeadingZeroNumber(raw) {
|
|
|
1535
1556
|
|
|
1536
1557
|
// src/value-factory.ts
|
|
1537
1558
|
function fromMap(values, originDescription) {
|
|
1538
|
-
const fields =
|
|
1559
|
+
const fields = guardStackDepth(
|
|
1560
|
+
() => coerceObject(values, ""),
|
|
1561
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
1562
|
+
);
|
|
1539
1563
|
const root = { kind: "object", fields };
|
|
1540
1564
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1541
1565
|
}
|
|
@@ -1600,7 +1624,10 @@ function coerceValue(v, atPath) {
|
|
|
1600
1624
|
|
|
1601
1625
|
// src/adapters/jsonc.ts
|
|
1602
1626
|
function parseJsonc(input, originDescription) {
|
|
1603
|
-
const doc =
|
|
1627
|
+
const doc = guardStackDepth(
|
|
1628
|
+
() => JSON.parse(stripTrailingCommas(stripComments(stripBom(input))), bigIntReviver),
|
|
1629
|
+
(msg) => depthError(`jsonc: ${msg}`)
|
|
1630
|
+
);
|
|
1604
1631
|
if (doc === null || typeof doc !== "object" || Array.isArray(doc)) {
|
|
1605
1632
|
throw new ConfigError(
|
|
1606
1633
|
`jsonc: document root is ${Array.isArray(doc) ? "an array" : typeof doc}, but a config root must be an object (spec F0.3)`,
|
|
@@ -20,7 +20,18 @@ import { C as Config } from '../config-Dlq6rF3w.cjs';
|
|
|
20
20
|
* the JS number model, as they do for HOCON's own literals, so read large
|
|
21
21
|
* identifiers with `getString`.
|
|
22
22
|
*
|
|
23
|
-
*
|
|
23
|
+
* **An unpaired `\uXXXX` surrogate is accepted here and refused by go.hocon,
|
|
24
|
+
* py.hocon and rs.hocon** (F3.5). That is deliberate, and the same divergence
|
|
25
|
+
* the properties adapter already carries under F2.8: a JavaScript string is
|
|
26
|
+
* UTF-16, like Java's, so it holds a lone surrogate natively and round-trips it.
|
|
27
|
+
* A Go or Rust string cannot hold one at all — Go silently substituted U+FFFD
|
|
28
|
+
* until F3.5 — and a Python `str` can hold one but cannot encode it as UTF-8,
|
|
29
|
+
* so all three refuse rather than defer the failure. Refusing here would mean
|
|
30
|
+
* this spec overriding the host language rather than protecting the user; see
|
|
31
|
+
* S1.2.6 for the class.
|
|
32
|
+
*
|
|
33
|
+
* See the F3.x items in the format-ingestion mapping spec:
|
|
34
|
+
* https://github.com/o3co/xx.hocon/blob/main/docs/format-ingestion-mapping.md
|
|
24
35
|
*/
|
|
25
36
|
declare function parseJsonc(input: string, originDescription?: string): Config;
|
|
26
37
|
/**
|
package/dist/adapters/jsonc.d.ts
CHANGED
|
@@ -20,7 +20,18 @@ import { C as Config } from '../config-Dlq6rF3w.js';
|
|
|
20
20
|
* the JS number model, as they do for HOCON's own literals, so read large
|
|
21
21
|
* identifiers with `getString`.
|
|
22
22
|
*
|
|
23
|
-
*
|
|
23
|
+
* **An unpaired `\uXXXX` surrogate is accepted here and refused by go.hocon,
|
|
24
|
+
* py.hocon and rs.hocon** (F3.5). That is deliberate, and the same divergence
|
|
25
|
+
* the properties adapter already carries under F2.8: a JavaScript string is
|
|
26
|
+
* UTF-16, like Java's, so it holds a lone surrogate natively and round-trips it.
|
|
27
|
+
* A Go or Rust string cannot hold one at all — Go silently substituted U+FFFD
|
|
28
|
+
* until F3.5 — and a Python `str` can hold one but cannot encode it as UTF-8,
|
|
29
|
+
* so all three refuse rather than defer the failure. Refusing here would mean
|
|
30
|
+
* this spec overriding the host language rather than protecting the user; see
|
|
31
|
+
* S1.2.6 for the class.
|
|
32
|
+
*
|
|
33
|
+
* See the F3.x items in the format-ingestion mapping spec:
|
|
34
|
+
* https://github.com/o3co/xx.hocon/blob/main/docs/format-ingestion-mapping.md
|
|
24
35
|
*/
|
|
25
36
|
declare function parseJsonc(input: string, originDescription?: string): Config;
|
|
26
37
|
/**
|
package/dist/adapters/jsonc.js
CHANGED
|
@@ -520,6 +520,27 @@ function stripBom(input) {
|
|
|
520
520
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
521
521
|
}
|
|
522
522
|
|
|
523
|
+
// src/internal/depth.ts
|
|
524
|
+
function guardStackDepth(fn, wrap) {
|
|
525
|
+
try {
|
|
526
|
+
return fn();
|
|
527
|
+
} catch (e) {
|
|
528
|
+
if (!isStackOverflow(e)) throw e;
|
|
529
|
+
throw wrap(STACK_MESSAGE);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
533
|
+
function isStackOverflow(e) {
|
|
534
|
+
if (!(e instanceof RangeError)) return false;
|
|
535
|
+
const m = e.message.toLowerCase();
|
|
536
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
537
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
538
|
+
m.includes("stack overflow");
|
|
539
|
+
}
|
|
540
|
+
function depthError(message) {
|
|
541
|
+
return new ConfigError(message, "");
|
|
542
|
+
}
|
|
543
|
+
|
|
523
544
|
// src/value/numeric-array.ts
|
|
524
545
|
function numericObjectToArray(value) {
|
|
525
546
|
if (value.kind !== "object") return null;
|
|
@@ -1498,7 +1519,10 @@ function normalizeLeadingZeroNumber(raw) {
|
|
|
1498
1519
|
|
|
1499
1520
|
// src/value-factory.ts
|
|
1500
1521
|
function fromMap(values, originDescription) {
|
|
1501
|
-
const fields =
|
|
1522
|
+
const fields = guardStackDepth(
|
|
1523
|
+
() => coerceObject(values, ""),
|
|
1524
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
1525
|
+
);
|
|
1502
1526
|
const root = { kind: "object", fields };
|
|
1503
1527
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1504
1528
|
}
|
|
@@ -1563,7 +1587,10 @@ function coerceValue(v, atPath) {
|
|
|
1563
1587
|
|
|
1564
1588
|
// src/adapters/jsonc.ts
|
|
1565
1589
|
function parseJsonc(input, originDescription) {
|
|
1566
|
-
const doc =
|
|
1590
|
+
const doc = guardStackDepth(
|
|
1591
|
+
() => JSON.parse(stripTrailingCommas(stripComments(stripBom(input))), bigIntReviver),
|
|
1592
|
+
(msg) => depthError(`jsonc: ${msg}`)
|
|
1593
|
+
);
|
|
1567
1594
|
if (doc === null || typeof doc !== "object" || Array.isArray(doc)) {
|
|
1568
1595
|
throw new ConfigError(
|
|
1569
1596
|
`jsonc: document root is ${Array.isArray(doc) ? "an array" : typeof doc}, but a config root must be an object (spec F0.3)`,
|
|
@@ -565,6 +565,31 @@ function stripBom(input) {
|
|
|
565
565
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
566
566
|
}
|
|
567
567
|
|
|
568
|
+
// src/internal/depth.ts
|
|
569
|
+
var MAX_PATH_SEGMENTS = 64;
|
|
570
|
+
function tooDeep(segments) {
|
|
571
|
+
return segments > MAX_PATH_SEGMENTS;
|
|
572
|
+
}
|
|
573
|
+
function guardStackDepth(fn, wrap) {
|
|
574
|
+
try {
|
|
575
|
+
return fn();
|
|
576
|
+
} catch (e) {
|
|
577
|
+
if (!isStackOverflow(e)) throw e;
|
|
578
|
+
throw wrap(STACK_MESSAGE);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
582
|
+
function isStackOverflow(e) {
|
|
583
|
+
if (!(e instanceof RangeError)) return false;
|
|
584
|
+
const m = e.message.toLowerCase();
|
|
585
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
586
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
587
|
+
m.includes("stack overflow");
|
|
588
|
+
}
|
|
589
|
+
function depthError(message) {
|
|
590
|
+
return new ConfigError(message, "");
|
|
591
|
+
}
|
|
592
|
+
|
|
568
593
|
// src/internal/properties/properties.ts
|
|
569
594
|
function parseProperties(input) {
|
|
570
595
|
const pairs = [];
|
|
@@ -572,7 +597,15 @@ function parseProperties(input) {
|
|
|
572
597
|
const [rawKey, rawValue] = splitKeyValue(text);
|
|
573
598
|
const key = unescapeProps(rawKey, line);
|
|
574
599
|
if (key === "") continue;
|
|
575
|
-
|
|
600
|
+
const segments = key.split(".");
|
|
601
|
+
if (tooDeep(segments.length)) {
|
|
602
|
+
throw new ParseError(
|
|
603
|
+
`key maps to a path ${segments.length} segments deep, over the limit of ${MAX_PATH_SEGMENTS}`,
|
|
604
|
+
line,
|
|
605
|
+
1
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
pairs.push([segments, unescapeProps(rawValue, line)]);
|
|
576
609
|
}
|
|
577
610
|
return nestPairs(pairs);
|
|
578
611
|
}
|
|
@@ -1671,7 +1704,10 @@ function normalizeLeadingZeroNumber(raw) {
|
|
|
1671
1704
|
|
|
1672
1705
|
// src/value-factory.ts
|
|
1673
1706
|
function fromMap(values, originDescription) {
|
|
1674
|
-
const fields =
|
|
1707
|
+
const fields = guardStackDepth(
|
|
1708
|
+
() => coerceObject(values, ""),
|
|
1709
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
1710
|
+
);
|
|
1675
1711
|
const root = { kind: "object", fields };
|
|
1676
1712
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1677
1713
|
}
|
|
@@ -529,6 +529,31 @@ function stripBom(input) {
|
|
|
529
529
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
530
530
|
}
|
|
531
531
|
|
|
532
|
+
// src/internal/depth.ts
|
|
533
|
+
var MAX_PATH_SEGMENTS = 64;
|
|
534
|
+
function tooDeep(segments) {
|
|
535
|
+
return segments > MAX_PATH_SEGMENTS;
|
|
536
|
+
}
|
|
537
|
+
function guardStackDepth(fn, wrap) {
|
|
538
|
+
try {
|
|
539
|
+
return fn();
|
|
540
|
+
} catch (e) {
|
|
541
|
+
if (!isStackOverflow(e)) throw e;
|
|
542
|
+
throw wrap(STACK_MESSAGE);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
546
|
+
function isStackOverflow(e) {
|
|
547
|
+
if (!(e instanceof RangeError)) return false;
|
|
548
|
+
const m = e.message.toLowerCase();
|
|
549
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
550
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
551
|
+
m.includes("stack overflow");
|
|
552
|
+
}
|
|
553
|
+
function depthError(message) {
|
|
554
|
+
return new ConfigError(message, "");
|
|
555
|
+
}
|
|
556
|
+
|
|
532
557
|
// src/internal/properties/properties.ts
|
|
533
558
|
function parseProperties(input) {
|
|
534
559
|
const pairs = [];
|
|
@@ -536,7 +561,15 @@ function parseProperties(input) {
|
|
|
536
561
|
const [rawKey, rawValue] = splitKeyValue(text);
|
|
537
562
|
const key = unescapeProps(rawKey, line);
|
|
538
563
|
if (key === "") continue;
|
|
539
|
-
|
|
564
|
+
const segments = key.split(".");
|
|
565
|
+
if (tooDeep(segments.length)) {
|
|
566
|
+
throw new ParseError(
|
|
567
|
+
`key maps to a path ${segments.length} segments deep, over the limit of ${MAX_PATH_SEGMENTS}`,
|
|
568
|
+
line,
|
|
569
|
+
1
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
pairs.push([segments, unescapeProps(rawValue, line)]);
|
|
540
573
|
}
|
|
541
574
|
return nestPairs(pairs);
|
|
542
575
|
}
|
|
@@ -1635,7 +1668,10 @@ function normalizeLeadingZeroNumber(raw) {
|
|
|
1635
1668
|
|
|
1636
1669
|
// src/value-factory.ts
|
|
1637
1670
|
function fromMap(values, originDescription) {
|
|
1638
|
-
const fields =
|
|
1671
|
+
const fields = guardStackDepth(
|
|
1672
|
+
() => coerceObject(values, ""),
|
|
1673
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
1674
|
+
);
|
|
1639
1675
|
const root = { kind: "object", fields };
|
|
1640
1676
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1641
1677
|
}
|
package/dist/adapters/toml.cjs
CHANGED
|
@@ -557,6 +557,27 @@ function stripBom(input) {
|
|
|
557
557
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
558
558
|
}
|
|
559
559
|
|
|
560
|
+
// src/internal/depth.ts
|
|
561
|
+
function guardStackDepth(fn, wrap) {
|
|
562
|
+
try {
|
|
563
|
+
return fn();
|
|
564
|
+
} catch (e) {
|
|
565
|
+
if (!isStackOverflow(e)) throw e;
|
|
566
|
+
throw wrap(STACK_MESSAGE);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
570
|
+
function isStackOverflow(e) {
|
|
571
|
+
if (!(e instanceof RangeError)) return false;
|
|
572
|
+
const m = e.message.toLowerCase();
|
|
573
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
574
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
575
|
+
m.includes("stack overflow");
|
|
576
|
+
}
|
|
577
|
+
function depthError(message) {
|
|
578
|
+
return new ConfigError(message, "");
|
|
579
|
+
}
|
|
580
|
+
|
|
560
581
|
// src/value/numeric-array.ts
|
|
561
582
|
function numericObjectToArray(value) {
|
|
562
583
|
if (value.kind !== "object") return null;
|
|
@@ -1535,7 +1556,10 @@ function normalizeLeadingZeroNumber(raw) {
|
|
|
1535
1556
|
|
|
1536
1557
|
// src/value-factory.ts
|
|
1537
1558
|
function fromMap(values, originDescription) {
|
|
1538
|
-
const fields =
|
|
1559
|
+
const fields = guardStackDepth(
|
|
1560
|
+
() => coerceObject(values, ""),
|
|
1561
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
1562
|
+
);
|
|
1539
1563
|
const root = { kind: "object", fields };
|
|
1540
1564
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1541
1565
|
}
|
|
@@ -1601,7 +1625,13 @@ function coerceValue(v, atPath) {
|
|
|
1601
1625
|
// src/adapters/toml.ts
|
|
1602
1626
|
function parseTomlConfig(input, originDescription) {
|
|
1603
1627
|
const doc = (0, import_smol_toml.parse)(stripBom(input));
|
|
1604
|
-
return fromMap(
|
|
1628
|
+
return fromMap(
|
|
1629
|
+
guardStackDepth(
|
|
1630
|
+
() => convert(doc, ""),
|
|
1631
|
+
(msg) => depthError(`toml: ${msg}`)
|
|
1632
|
+
),
|
|
1633
|
+
originDescription
|
|
1634
|
+
);
|
|
1605
1635
|
}
|
|
1606
1636
|
function convert(v, atPath) {
|
|
1607
1637
|
if (Array.isArray(v)) return v.map((e, i) => convert(e, `${atPath}[${i}]`));
|
package/dist/adapters/toml.d.cts
CHANGED
|
@@ -11,7 +11,8 @@ import { C as Config } from '../config-Dlq6rF3w.cjs';
|
|
|
11
11
|
* the safe-integer range is an error here rather than silently rounded — go's
|
|
12
12
|
* adapter accepts those, its int64 being wide enough (spec F0.5).
|
|
13
13
|
*
|
|
14
|
-
* See
|
|
14
|
+
* See the F4.x items in the format-ingestion mapping spec:
|
|
15
|
+
* https://github.com/o3co/xx.hocon/blob/main/docs/format-ingestion-mapping.md
|
|
15
16
|
*/
|
|
16
17
|
declare function parseTomlConfig(input: string, originDescription?: string): Config;
|
|
17
18
|
|
package/dist/adapters/toml.d.ts
CHANGED
|
@@ -11,7 +11,8 @@ import { C as Config } from '../config-Dlq6rF3w.js';
|
|
|
11
11
|
* the safe-integer range is an error here rather than silently rounded — go's
|
|
12
12
|
* adapter accepts those, its int64 being wide enough (spec F0.5).
|
|
13
13
|
*
|
|
14
|
-
* See
|
|
14
|
+
* See the F4.x items in the format-ingestion mapping spec:
|
|
15
|
+
* https://github.com/o3co/xx.hocon/blob/main/docs/format-ingestion-mapping.md
|
|
15
16
|
*/
|
|
16
17
|
declare function parseTomlConfig(input: string, originDescription?: string): Config;
|
|
17
18
|
|
package/dist/adapters/toml.js
CHANGED
|
@@ -523,6 +523,27 @@ function stripBom(input) {
|
|
|
523
523
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
524
524
|
}
|
|
525
525
|
|
|
526
|
+
// src/internal/depth.ts
|
|
527
|
+
function guardStackDepth(fn, wrap) {
|
|
528
|
+
try {
|
|
529
|
+
return fn();
|
|
530
|
+
} catch (e) {
|
|
531
|
+
if (!isStackOverflow(e)) throw e;
|
|
532
|
+
throw wrap(STACK_MESSAGE);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
536
|
+
function isStackOverflow(e) {
|
|
537
|
+
if (!(e instanceof RangeError)) return false;
|
|
538
|
+
const m = e.message.toLowerCase();
|
|
539
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
540
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
541
|
+
m.includes("stack overflow");
|
|
542
|
+
}
|
|
543
|
+
function depthError(message) {
|
|
544
|
+
return new ConfigError(message, "");
|
|
545
|
+
}
|
|
546
|
+
|
|
526
547
|
// src/value/numeric-array.ts
|
|
527
548
|
function numericObjectToArray(value) {
|
|
528
549
|
if (value.kind !== "object") return null;
|
|
@@ -1501,7 +1522,10 @@ function normalizeLeadingZeroNumber(raw) {
|
|
|
1501
1522
|
|
|
1502
1523
|
// src/value-factory.ts
|
|
1503
1524
|
function fromMap(values, originDescription) {
|
|
1504
|
-
const fields =
|
|
1525
|
+
const fields = guardStackDepth(
|
|
1526
|
+
() => coerceObject(values, ""),
|
|
1527
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
1528
|
+
);
|
|
1505
1529
|
const root = { kind: "object", fields };
|
|
1506
1530
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1507
1531
|
}
|
|
@@ -1567,7 +1591,13 @@ function coerceValue(v, atPath) {
|
|
|
1567
1591
|
// src/adapters/toml.ts
|
|
1568
1592
|
function parseTomlConfig(input, originDescription) {
|
|
1569
1593
|
const doc = parseToml(stripBom(input));
|
|
1570
|
-
return fromMap(
|
|
1594
|
+
return fromMap(
|
|
1595
|
+
guardStackDepth(
|
|
1596
|
+
() => convert(doc, ""),
|
|
1597
|
+
(msg) => depthError(`toml: ${msg}`)
|
|
1598
|
+
),
|
|
1599
|
+
originDescription
|
|
1600
|
+
);
|
|
1571
1601
|
}
|
|
1572
1602
|
function convert(v, atPath) {
|
|
1573
1603
|
if (Array.isArray(v)) return v.map((e, i) => convert(e, `${atPath}[${i}]`));
|
package/dist/adapters/yaml.cjs
CHANGED
|
@@ -558,6 +558,27 @@ function stripBom(input) {
|
|
|
558
558
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
559
559
|
}
|
|
560
560
|
|
|
561
|
+
// src/internal/depth.ts
|
|
562
|
+
function guardStackDepth(fn, wrap) {
|
|
563
|
+
try {
|
|
564
|
+
return fn();
|
|
565
|
+
} catch (e) {
|
|
566
|
+
if (!isStackOverflow(e)) throw e;
|
|
567
|
+
throw wrap(STACK_MESSAGE);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
571
|
+
function isStackOverflow(e) {
|
|
572
|
+
if (!(e instanceof RangeError)) return false;
|
|
573
|
+
const m = e.message.toLowerCase();
|
|
574
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
575
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
576
|
+
m.includes("stack overflow");
|
|
577
|
+
}
|
|
578
|
+
function depthError(message) {
|
|
579
|
+
return new ConfigError(message, "");
|
|
580
|
+
}
|
|
581
|
+
|
|
561
582
|
// src/value/numeric-array.ts
|
|
562
583
|
function numericObjectToArray(value) {
|
|
563
584
|
if (value.kind !== "object") return null;
|
|
@@ -1536,7 +1557,10 @@ function normalizeLeadingZeroNumber(raw) {
|
|
|
1536
1557
|
|
|
1537
1558
|
// src/value-factory.ts
|
|
1538
1559
|
function fromMap(values, originDescription) {
|
|
1539
|
-
const fields =
|
|
1560
|
+
const fields = guardStackDepth(
|
|
1561
|
+
() => coerceObject(values, ""),
|
|
1562
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
1563
|
+
);
|
|
1540
1564
|
const root = { kind: "object", fields };
|
|
1541
1565
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1542
1566
|
}
|
|
@@ -1613,11 +1637,14 @@ function parseYaml(input, originDescription) {
|
|
|
1613
1637
|
if (doc.errors.length > 0) {
|
|
1614
1638
|
throw new ConfigError(`yaml: ${doc.errors[0]?.message ?? "parse error"}`, "");
|
|
1615
1639
|
}
|
|
1616
|
-
return fromYamlValue(doc.toJS({ mapAsMap:
|
|
1640
|
+
return fromYamlValue(doc.toJS({ mapAsMap: true }), originDescription);
|
|
1617
1641
|
}
|
|
1618
1642
|
function fromYamlValue(value, originDescription) {
|
|
1619
1643
|
if (value === null || value === void 0) return fromMap({}, originDescription);
|
|
1620
|
-
const normalized =
|
|
1644
|
+
const normalized = guardStackDepth(
|
|
1645
|
+
() => convert(value, ""),
|
|
1646
|
+
(msg) => depthError(`yaml: ${msg}`)
|
|
1647
|
+
);
|
|
1621
1648
|
if (typeof normalized !== "object" || normalized === null || Array.isArray(normalized)) {
|
|
1622
1649
|
throw new ConfigError(
|
|
1623
1650
|
`yaml: document root is ${Array.isArray(normalized) ? "an array" : typeof normalized}, but a config root must be an object (spec F0.3)`,
|
|
@@ -1633,6 +1660,7 @@ function convert(v, atPath) {
|
|
|
1633
1660
|
}
|
|
1634
1661
|
if (v instanceof Map) {
|
|
1635
1662
|
const entries = [];
|
|
1663
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1636
1664
|
for (const [k, e] of v) {
|
|
1637
1665
|
if (k !== null && typeof k === "object") {
|
|
1638
1666
|
throw new ConfigError(
|
|
@@ -1641,6 +1669,13 @@ function convert(v, atPath) {
|
|
|
1641
1669
|
);
|
|
1642
1670
|
}
|
|
1643
1671
|
const key = String(k);
|
|
1672
|
+
if (seen.has(key)) {
|
|
1673
|
+
throw new ConfigError(
|
|
1674
|
+
`yaml: sibling mapping keys ${keyForm(seen.get(key))} and ${keyForm(k)} both give the key "${key}"${atPath === "" ? "" : ` at "${atPath}"`}; rename one of them, because one of the two values would otherwise be lost. Quoting a non-string key helps only where that changes the key text, as 0x10 does and 1 does not (spec F5.3)`,
|
|
1675
|
+
atPath
|
|
1676
|
+
);
|
|
1677
|
+
}
|
|
1678
|
+
seen.set(key, k);
|
|
1644
1679
|
entries.push([key, convert(e, atPath === "" ? key : `${atPath}.${key}`)]);
|
|
1645
1680
|
}
|
|
1646
1681
|
return Object.fromEntries(entries);
|
|
@@ -1674,6 +1709,10 @@ function bytesToBase64(bytes) {
|
|
|
1674
1709
|
}
|
|
1675
1710
|
return btoa(binary);
|
|
1676
1711
|
}
|
|
1712
|
+
function keyForm(k) {
|
|
1713
|
+
if (typeof k === "string") return JSON.stringify(k);
|
|
1714
|
+
return `${String(k)} (${k === null ? "null" : typeof k})`;
|
|
1715
|
+
}
|
|
1677
1716
|
var MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);
|
|
1678
1717
|
var MIN_SAFE = BigInt(Number.MIN_SAFE_INTEGER);
|
|
1679
1718
|
function isSafeIntegerBigInt(v) {
|
package/dist/adapters/yaml.d.cts
CHANGED
|
@@ -29,7 +29,8 @@ import { C as Config } from '../config-Dlq6rF3w.cjs';
|
|
|
29
29
|
* than rounded. `getNumber` and `toObject` still apply the JS number model, so
|
|
30
30
|
* read large identifiers with `getString`.
|
|
31
31
|
*
|
|
32
|
-
* See
|
|
32
|
+
* See the F5.x items in the format-ingestion mapping spec:
|
|
33
|
+
* https://github.com/o3co/xx.hocon/blob/main/docs/format-ingestion-mapping.md
|
|
33
34
|
*/
|
|
34
35
|
declare function parseYaml(input: string, originDescription?: string): Config;
|
|
35
36
|
/**
|
package/dist/adapters/yaml.d.ts
CHANGED
|
@@ -29,7 +29,8 @@ import { C as Config } from '../config-Dlq6rF3w.js';
|
|
|
29
29
|
* than rounded. `getNumber` and `toObject` still apply the JS number model, so
|
|
30
30
|
* read large identifiers with `getString`.
|
|
31
31
|
*
|
|
32
|
-
* See
|
|
32
|
+
* See the F5.x items in the format-ingestion mapping spec:
|
|
33
|
+
* https://github.com/o3co/xx.hocon/blob/main/docs/format-ingestion-mapping.md
|
|
33
34
|
*/
|
|
34
35
|
declare function parseYaml(input: string, originDescription?: string): Config;
|
|
35
36
|
/**
|
package/dist/adapters/yaml.js
CHANGED
|
@@ -523,6 +523,27 @@ function stripBom(input) {
|
|
|
523
523
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
524
524
|
}
|
|
525
525
|
|
|
526
|
+
// src/internal/depth.ts
|
|
527
|
+
function guardStackDepth(fn, wrap) {
|
|
528
|
+
try {
|
|
529
|
+
return fn();
|
|
530
|
+
} catch (e) {
|
|
531
|
+
if (!isStackOverflow(e)) throw e;
|
|
532
|
+
throw wrap(STACK_MESSAGE);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
536
|
+
function isStackOverflow(e) {
|
|
537
|
+
if (!(e instanceof RangeError)) return false;
|
|
538
|
+
const m = e.message.toLowerCase();
|
|
539
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
540
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
541
|
+
m.includes("stack overflow");
|
|
542
|
+
}
|
|
543
|
+
function depthError(message) {
|
|
544
|
+
return new ConfigError(message, "");
|
|
545
|
+
}
|
|
546
|
+
|
|
526
547
|
// src/value/numeric-array.ts
|
|
527
548
|
function numericObjectToArray(value) {
|
|
528
549
|
if (value.kind !== "object") return null;
|
|
@@ -1501,7 +1522,10 @@ function normalizeLeadingZeroNumber(raw) {
|
|
|
1501
1522
|
|
|
1502
1523
|
// src/value-factory.ts
|
|
1503
1524
|
function fromMap(values, originDescription) {
|
|
1504
|
-
const fields =
|
|
1525
|
+
const fields = guardStackDepth(
|
|
1526
|
+
() => coerceObject(values, ""),
|
|
1527
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
1528
|
+
);
|
|
1505
1529
|
const root = { kind: "object", fields };
|
|
1506
1530
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1507
1531
|
}
|
|
@@ -1578,11 +1602,14 @@ function parseYaml(input, originDescription) {
|
|
|
1578
1602
|
if (doc.errors.length > 0) {
|
|
1579
1603
|
throw new ConfigError(`yaml: ${doc.errors[0]?.message ?? "parse error"}`, "");
|
|
1580
1604
|
}
|
|
1581
|
-
return fromYamlValue(doc.toJS({ mapAsMap:
|
|
1605
|
+
return fromYamlValue(doc.toJS({ mapAsMap: true }), originDescription);
|
|
1582
1606
|
}
|
|
1583
1607
|
function fromYamlValue(value, originDescription) {
|
|
1584
1608
|
if (value === null || value === void 0) return fromMap({}, originDescription);
|
|
1585
|
-
const normalized =
|
|
1609
|
+
const normalized = guardStackDepth(
|
|
1610
|
+
() => convert(value, ""),
|
|
1611
|
+
(msg) => depthError(`yaml: ${msg}`)
|
|
1612
|
+
);
|
|
1586
1613
|
if (typeof normalized !== "object" || normalized === null || Array.isArray(normalized)) {
|
|
1587
1614
|
throw new ConfigError(
|
|
1588
1615
|
`yaml: document root is ${Array.isArray(normalized) ? "an array" : typeof normalized}, but a config root must be an object (spec F0.3)`,
|
|
@@ -1598,6 +1625,7 @@ function convert(v, atPath) {
|
|
|
1598
1625
|
}
|
|
1599
1626
|
if (v instanceof Map) {
|
|
1600
1627
|
const entries = [];
|
|
1628
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1601
1629
|
for (const [k, e] of v) {
|
|
1602
1630
|
if (k !== null && typeof k === "object") {
|
|
1603
1631
|
throw new ConfigError(
|
|
@@ -1606,6 +1634,13 @@ function convert(v, atPath) {
|
|
|
1606
1634
|
);
|
|
1607
1635
|
}
|
|
1608
1636
|
const key = String(k);
|
|
1637
|
+
if (seen.has(key)) {
|
|
1638
|
+
throw new ConfigError(
|
|
1639
|
+
`yaml: sibling mapping keys ${keyForm(seen.get(key))} and ${keyForm(k)} both give the key "${key}"${atPath === "" ? "" : ` at "${atPath}"`}; rename one of them, because one of the two values would otherwise be lost. Quoting a non-string key helps only where that changes the key text, as 0x10 does and 1 does not (spec F5.3)`,
|
|
1640
|
+
atPath
|
|
1641
|
+
);
|
|
1642
|
+
}
|
|
1643
|
+
seen.set(key, k);
|
|
1609
1644
|
entries.push([key, convert(e, atPath === "" ? key : `${atPath}.${key}`)]);
|
|
1610
1645
|
}
|
|
1611
1646
|
return Object.fromEntries(entries);
|
|
@@ -1639,6 +1674,10 @@ function bytesToBase64(bytes) {
|
|
|
1639
1674
|
}
|
|
1640
1675
|
return btoa(binary);
|
|
1641
1676
|
}
|
|
1677
|
+
function keyForm(k) {
|
|
1678
|
+
if (typeof k === "string") return JSON.stringify(k);
|
|
1679
|
+
return `${String(k)} (${k === null ? "null" : typeof k})`;
|
|
1680
|
+
}
|
|
1642
1681
|
var MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);
|
|
1643
1682
|
var MIN_SAFE = BigInt(Number.MIN_SAFE_INTEGER);
|
|
1644
1683
|
function isSafeIntegerBigInt(v) {
|
package/dist/index.cjs
CHANGED
|
@@ -1548,6 +1548,39 @@ function stripBom(input) {
|
|
|
1548
1548
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
1549
1549
|
}
|
|
1550
1550
|
|
|
1551
|
+
// src/internal/depth.ts
|
|
1552
|
+
var MAX_PATH_SEGMENTS = 64;
|
|
1553
|
+
function tooDeep(segments) {
|
|
1554
|
+
return segments > MAX_PATH_SEGMENTS;
|
|
1555
|
+
}
|
|
1556
|
+
function guardStackDepth(fn, wrap) {
|
|
1557
|
+
try {
|
|
1558
|
+
return fn();
|
|
1559
|
+
} catch (e) {
|
|
1560
|
+
if (!isStackOverflow(e)) throw e;
|
|
1561
|
+
throw wrap(STACK_MESSAGE);
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
1565
|
+
function isStackOverflow(e) {
|
|
1566
|
+
if (!(e instanceof RangeError)) return false;
|
|
1567
|
+
const m = e.message.toLowerCase();
|
|
1568
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
1569
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
1570
|
+
m.includes("stack overflow");
|
|
1571
|
+
}
|
|
1572
|
+
function depthError(message) {
|
|
1573
|
+
return new ConfigError(message, "");
|
|
1574
|
+
}
|
|
1575
|
+
async function guardStackDepthAsync(fn, wrap) {
|
|
1576
|
+
try {
|
|
1577
|
+
return await fn();
|
|
1578
|
+
} catch (e) {
|
|
1579
|
+
if (!isStackOverflow(e)) throw e;
|
|
1580
|
+
throw wrap(STACK_MESSAGE);
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1551
1584
|
// src/internal/properties/properties.ts
|
|
1552
1585
|
function parseProperties(input) {
|
|
1553
1586
|
const pairs = [];
|
|
@@ -1555,7 +1588,15 @@ function parseProperties(input) {
|
|
|
1555
1588
|
const [rawKey, rawValue] = splitKeyValue(text);
|
|
1556
1589
|
const key = unescapeProps(rawKey, line);
|
|
1557
1590
|
if (key === "") continue;
|
|
1558
|
-
|
|
1591
|
+
const segments = key.split(".");
|
|
1592
|
+
if (tooDeep(segments.length)) {
|
|
1593
|
+
throw new ParseError(
|
|
1594
|
+
`key maps to a path ${segments.length} segments deep, over the limit of ${MAX_PATH_SEGMENTS}`,
|
|
1595
|
+
line,
|
|
1596
|
+
1
|
|
1597
|
+
);
|
|
1598
|
+
}
|
|
1599
|
+
pairs.push([segments, unescapeProps(rawValue, line)]);
|
|
1559
1600
|
}
|
|
1560
1601
|
return nestPairs(pairs);
|
|
1561
1602
|
}
|
|
@@ -3249,13 +3290,16 @@ function buildResolveContext(input, opts) {
|
|
|
3249
3290
|
return { ast, resolveOpts };
|
|
3250
3291
|
}
|
|
3251
3292
|
function parse(input, opts = {}) {
|
|
3252
|
-
|
|
3253
|
-
const value = resolve2(ast, resolveOpts);
|
|
3254
|
-
if (value.kind !== "object") throw new Error("resolved value is not an object");
|
|
3255
|
-
return new Config(value, { resolved: true, originDescription: opts.originDescription });
|
|
3293
|
+
return parseStringWithOptions(input, opts);
|
|
3256
3294
|
}
|
|
3257
3295
|
var parseString = parse;
|
|
3258
3296
|
function parseStringWithOptions(input, opts = {}) {
|
|
3297
|
+
return guardStackDepth(
|
|
3298
|
+
() => parseStringInner(input, opts),
|
|
3299
|
+
(msg) => new ParseError(msg, 1, 1, opts.originDescription)
|
|
3300
|
+
);
|
|
3301
|
+
}
|
|
3302
|
+
function parseStringInner(input, opts) {
|
|
3259
3303
|
const resolveSubstitutions = opts.resolveSubstitutions ?? true;
|
|
3260
3304
|
const { ast, resolveOpts } = buildResolveContext(input, opts);
|
|
3261
3305
|
if (resolveSubstitutions) {
|
|
@@ -3286,10 +3330,12 @@ function parseFileWithOptions(filePath, opts = {}) {
|
|
|
3286
3330
|
});
|
|
3287
3331
|
}
|
|
3288
3332
|
async function parseAsync(input, opts = {}) {
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3333
|
+
return guardStackDepthAsync(async () => {
|
|
3334
|
+
const { ast, resolveOpts } = buildResolveContext(input, opts);
|
|
3335
|
+
const value = await resolveAsync(ast, resolveOpts);
|
|
3336
|
+
if (value.kind !== "object") throw new Error("resolved value is not an object");
|
|
3337
|
+
return new Config(value);
|
|
3338
|
+
}, (msg) => new ParseError(msg, 1, 1, opts.originDescription));
|
|
3293
3339
|
}
|
|
3294
3340
|
function parseFile(filePath, opts = {}) {
|
|
3295
3341
|
if (typeof process === "undefined" && !opts.readFileSync) {
|
|
@@ -3350,7 +3396,10 @@ function isNull(v) {
|
|
|
3350
3396
|
|
|
3351
3397
|
// src/value-factory.ts
|
|
3352
3398
|
function fromMap(values, originDescription) {
|
|
3353
|
-
const fields =
|
|
3399
|
+
const fields = guardStackDepth(
|
|
3400
|
+
() => coerceObject(values, ""),
|
|
3401
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
3402
|
+
);
|
|
3354
3403
|
const root = { kind: "object", fields };
|
|
3355
3404
|
return Config._fromResolvedValue(root, { originDescription });
|
|
3356
3405
|
}
|
package/dist/index.js
CHANGED
|
@@ -1494,6 +1494,39 @@ function stripBom(input) {
|
|
|
1494
1494
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
1495
1495
|
}
|
|
1496
1496
|
|
|
1497
|
+
// src/internal/depth.ts
|
|
1498
|
+
var MAX_PATH_SEGMENTS = 64;
|
|
1499
|
+
function tooDeep(segments) {
|
|
1500
|
+
return segments > MAX_PATH_SEGMENTS;
|
|
1501
|
+
}
|
|
1502
|
+
function guardStackDepth(fn, wrap) {
|
|
1503
|
+
try {
|
|
1504
|
+
return fn();
|
|
1505
|
+
} catch (e) {
|
|
1506
|
+
if (!isStackOverflow(e)) throw e;
|
|
1507
|
+
throw wrap(STACK_MESSAGE);
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
1511
|
+
function isStackOverflow(e) {
|
|
1512
|
+
if (!(e instanceof RangeError)) return false;
|
|
1513
|
+
const m = e.message.toLowerCase();
|
|
1514
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
1515
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
1516
|
+
m.includes("stack overflow");
|
|
1517
|
+
}
|
|
1518
|
+
function depthError(message) {
|
|
1519
|
+
return new ConfigError(message, "");
|
|
1520
|
+
}
|
|
1521
|
+
async function guardStackDepthAsync(fn, wrap) {
|
|
1522
|
+
try {
|
|
1523
|
+
return await fn();
|
|
1524
|
+
} catch (e) {
|
|
1525
|
+
if (!isStackOverflow(e)) throw e;
|
|
1526
|
+
throw wrap(STACK_MESSAGE);
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1497
1530
|
// src/internal/properties/properties.ts
|
|
1498
1531
|
function parseProperties(input) {
|
|
1499
1532
|
const pairs = [];
|
|
@@ -1501,7 +1534,15 @@ function parseProperties(input) {
|
|
|
1501
1534
|
const [rawKey, rawValue] = splitKeyValue(text);
|
|
1502
1535
|
const key = unescapeProps(rawKey, line);
|
|
1503
1536
|
if (key === "") continue;
|
|
1504
|
-
|
|
1537
|
+
const segments = key.split(".");
|
|
1538
|
+
if (tooDeep(segments.length)) {
|
|
1539
|
+
throw new ParseError(
|
|
1540
|
+
`key maps to a path ${segments.length} segments deep, over the limit of ${MAX_PATH_SEGMENTS}`,
|
|
1541
|
+
line,
|
|
1542
|
+
1
|
|
1543
|
+
);
|
|
1544
|
+
}
|
|
1545
|
+
pairs.push([segments, unescapeProps(rawValue, line)]);
|
|
1505
1546
|
}
|
|
1506
1547
|
return nestPairs(pairs);
|
|
1507
1548
|
}
|
|
@@ -3194,13 +3235,16 @@ function buildResolveContext(input, opts) {
|
|
|
3194
3235
|
return { ast, resolveOpts };
|
|
3195
3236
|
}
|
|
3196
3237
|
function parse(input, opts = {}) {
|
|
3197
|
-
|
|
3198
|
-
const value = resolve2(ast, resolveOpts);
|
|
3199
|
-
if (value.kind !== "object") throw new Error("resolved value is not an object");
|
|
3200
|
-
return new Config(value, { resolved: true, originDescription: opts.originDescription });
|
|
3238
|
+
return parseStringWithOptions(input, opts);
|
|
3201
3239
|
}
|
|
3202
3240
|
var parseString = parse;
|
|
3203
3241
|
function parseStringWithOptions(input, opts = {}) {
|
|
3242
|
+
return guardStackDepth(
|
|
3243
|
+
() => parseStringInner(input, opts),
|
|
3244
|
+
(msg) => new ParseError(msg, 1, 1, opts.originDescription)
|
|
3245
|
+
);
|
|
3246
|
+
}
|
|
3247
|
+
function parseStringInner(input, opts) {
|
|
3204
3248
|
const resolveSubstitutions = opts.resolveSubstitutions ?? true;
|
|
3205
3249
|
const { ast, resolveOpts } = buildResolveContext(input, opts);
|
|
3206
3250
|
if (resolveSubstitutions) {
|
|
@@ -3231,10 +3275,12 @@ function parseFileWithOptions(filePath, opts = {}) {
|
|
|
3231
3275
|
});
|
|
3232
3276
|
}
|
|
3233
3277
|
async function parseAsync(input, opts = {}) {
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3278
|
+
return guardStackDepthAsync(async () => {
|
|
3279
|
+
const { ast, resolveOpts } = buildResolveContext(input, opts);
|
|
3280
|
+
const value = await resolveAsync(ast, resolveOpts);
|
|
3281
|
+
if (value.kind !== "object") throw new Error("resolved value is not an object");
|
|
3282
|
+
return new Config(value);
|
|
3283
|
+
}, (msg) => new ParseError(msg, 1, 1, opts.originDescription));
|
|
3238
3284
|
}
|
|
3239
3285
|
function parseFile(filePath, opts = {}) {
|
|
3240
3286
|
if (typeof process === "undefined" && !opts.readFileSync) {
|
|
@@ -3295,7 +3341,10 @@ function isNull(v) {
|
|
|
3295
3341
|
|
|
3296
3342
|
// src/value-factory.ts
|
|
3297
3343
|
function fromMap(values, originDescription) {
|
|
3298
|
-
const fields =
|
|
3344
|
+
const fields = guardStackDepth(
|
|
3345
|
+
() => coerceObject(values, ""),
|
|
3346
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
3347
|
+
);
|
|
3299
3348
|
const root = { kind: "object", fields };
|
|
3300
3349
|
return Config._fromResolvedValue(root, { originDescription });
|
|
3301
3350
|
}
|
package/dist/zod.cjs
CHANGED
|
@@ -1530,6 +1530,28 @@ function stripBom(input) {
|
|
|
1530
1530
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
1531
1531
|
}
|
|
1532
1532
|
|
|
1533
|
+
// src/internal/depth.ts
|
|
1534
|
+
var MAX_PATH_SEGMENTS = 64;
|
|
1535
|
+
function tooDeep(segments) {
|
|
1536
|
+
return segments > MAX_PATH_SEGMENTS;
|
|
1537
|
+
}
|
|
1538
|
+
function guardStackDepth(fn, wrap) {
|
|
1539
|
+
try {
|
|
1540
|
+
return fn();
|
|
1541
|
+
} catch (e) {
|
|
1542
|
+
if (!isStackOverflow(e)) throw e;
|
|
1543
|
+
throw wrap(STACK_MESSAGE);
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
1547
|
+
function isStackOverflow(e) {
|
|
1548
|
+
if (!(e instanceof RangeError)) return false;
|
|
1549
|
+
const m = e.message.toLowerCase();
|
|
1550
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
1551
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
1552
|
+
m.includes("stack overflow");
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1533
1555
|
// src/internal/properties/properties.ts
|
|
1534
1556
|
function parseProperties(input) {
|
|
1535
1557
|
const pairs = [];
|
|
@@ -1537,7 +1559,15 @@ function parseProperties(input) {
|
|
|
1537
1559
|
const [rawKey, rawValue] = splitKeyValue(text);
|
|
1538
1560
|
const key = unescapeProps(rawKey, line);
|
|
1539
1561
|
if (key === "") continue;
|
|
1540
|
-
|
|
1562
|
+
const segments = key.split(".");
|
|
1563
|
+
if (tooDeep(segments.length)) {
|
|
1564
|
+
throw new ParseError(
|
|
1565
|
+
`key maps to a path ${segments.length} segments deep, over the limit of ${MAX_PATH_SEGMENTS}`,
|
|
1566
|
+
line,
|
|
1567
|
+
1
|
|
1568
|
+
);
|
|
1569
|
+
}
|
|
1570
|
+
pairs.push([segments, unescapeProps(rawValue, line)]);
|
|
1541
1571
|
}
|
|
1542
1572
|
return nestPairs(pairs);
|
|
1543
1573
|
}
|
|
@@ -3216,10 +3246,30 @@ function buildResolveContext(input, opts) {
|
|
|
3216
3246
|
return { ast, resolveOpts };
|
|
3217
3247
|
}
|
|
3218
3248
|
function parse(input, opts = {}) {
|
|
3249
|
+
return parseStringWithOptions(input, opts);
|
|
3250
|
+
}
|
|
3251
|
+
function parseStringWithOptions(input, opts = {}) {
|
|
3252
|
+
return guardStackDepth(
|
|
3253
|
+
() => parseStringInner(input, opts),
|
|
3254
|
+
(msg) => new ParseError(msg, 1, 1, opts.originDescription)
|
|
3255
|
+
);
|
|
3256
|
+
}
|
|
3257
|
+
function parseStringInner(input, opts) {
|
|
3258
|
+
const resolveSubstitutions = opts.resolveSubstitutions ?? true;
|
|
3219
3259
|
const { ast, resolveOpts } = buildResolveContext(input, opts);
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3260
|
+
if (resolveSubstitutions) {
|
|
3261
|
+
const value = resolve2(ast, resolveOpts);
|
|
3262
|
+
if (value.kind !== "object") throw new Error("resolved value is not an object");
|
|
3263
|
+
return new Config(value, { resolved: true, originDescription: opts.originDescription });
|
|
3264
|
+
}
|
|
3265
|
+
const tree = buildTree(ast, resolveOpts);
|
|
3266
|
+
const hasPlaceholders = containsPlaceholders(tree);
|
|
3267
|
+
return Config._fromUnresolvedResObj(tree, {
|
|
3268
|
+
parseBaseDir: opts.baseDir,
|
|
3269
|
+
originDescription: opts.originDescription,
|
|
3270
|
+
resolved: !hasPlaceholders,
|
|
3271
|
+
resolveOpts
|
|
3272
|
+
});
|
|
3223
3273
|
}
|
|
3224
3274
|
function parseFile(filePath, opts = {}) {
|
|
3225
3275
|
if (typeof process === "undefined" && !opts.readFileSync) {
|
package/dist/zod.js
CHANGED
|
@@ -1498,6 +1498,28 @@ function stripBom(input) {
|
|
|
1498
1498
|
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
1499
1499
|
}
|
|
1500
1500
|
|
|
1501
|
+
// src/internal/depth.ts
|
|
1502
|
+
var MAX_PATH_SEGMENTS = 64;
|
|
1503
|
+
function tooDeep(segments) {
|
|
1504
|
+
return segments > MAX_PATH_SEGMENTS;
|
|
1505
|
+
}
|
|
1506
|
+
function guardStackDepth(fn, wrap) {
|
|
1507
|
+
try {
|
|
1508
|
+
return fn();
|
|
1509
|
+
} catch (e) {
|
|
1510
|
+
if (!isStackOverflow(e)) throw e;
|
|
1511
|
+
throw wrap(STACK_MESSAGE);
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
var STACK_MESSAGE = "input is nested too deeply for this engine's stack, or contains a cycle (flatten the document, or break the cycle)";
|
|
1515
|
+
function isStackOverflow(e) {
|
|
1516
|
+
if (!(e instanceof RangeError)) return false;
|
|
1517
|
+
const m = e.message.toLowerCase();
|
|
1518
|
+
return m.includes("call stack") || // V8: "Maximum call stack size exceeded"
|
|
1519
|
+
m.includes("recursion") || // SpiderMonkey: "too much recursion"
|
|
1520
|
+
m.includes("stack overflow");
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1501
1523
|
// src/internal/properties/properties.ts
|
|
1502
1524
|
function parseProperties(input) {
|
|
1503
1525
|
const pairs = [];
|
|
@@ -1505,7 +1527,15 @@ function parseProperties(input) {
|
|
|
1505
1527
|
const [rawKey, rawValue] = splitKeyValue(text);
|
|
1506
1528
|
const key = unescapeProps(rawKey, line);
|
|
1507
1529
|
if (key === "") continue;
|
|
1508
|
-
|
|
1530
|
+
const segments = key.split(".");
|
|
1531
|
+
if (tooDeep(segments.length)) {
|
|
1532
|
+
throw new ParseError(
|
|
1533
|
+
`key maps to a path ${segments.length} segments deep, over the limit of ${MAX_PATH_SEGMENTS}`,
|
|
1534
|
+
line,
|
|
1535
|
+
1
|
|
1536
|
+
);
|
|
1537
|
+
}
|
|
1538
|
+
pairs.push([segments, unescapeProps(rawValue, line)]);
|
|
1509
1539
|
}
|
|
1510
1540
|
return nestPairs(pairs);
|
|
1511
1541
|
}
|
|
@@ -3183,10 +3213,30 @@ function buildResolveContext(input, opts) {
|
|
|
3183
3213
|
return { ast, resolveOpts };
|
|
3184
3214
|
}
|
|
3185
3215
|
function parse(input, opts = {}) {
|
|
3216
|
+
return parseStringWithOptions(input, opts);
|
|
3217
|
+
}
|
|
3218
|
+
function parseStringWithOptions(input, opts = {}) {
|
|
3219
|
+
return guardStackDepth(
|
|
3220
|
+
() => parseStringInner(input, opts),
|
|
3221
|
+
(msg) => new ParseError(msg, 1, 1, opts.originDescription)
|
|
3222
|
+
);
|
|
3223
|
+
}
|
|
3224
|
+
function parseStringInner(input, opts) {
|
|
3225
|
+
const resolveSubstitutions = opts.resolveSubstitutions ?? true;
|
|
3186
3226
|
const { ast, resolveOpts } = buildResolveContext(input, opts);
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3227
|
+
if (resolveSubstitutions) {
|
|
3228
|
+
const value = resolve2(ast, resolveOpts);
|
|
3229
|
+
if (value.kind !== "object") throw new Error("resolved value is not an object");
|
|
3230
|
+
return new Config(value, { resolved: true, originDescription: opts.originDescription });
|
|
3231
|
+
}
|
|
3232
|
+
const tree = buildTree(ast, resolveOpts);
|
|
3233
|
+
const hasPlaceholders = containsPlaceholders(tree);
|
|
3234
|
+
return Config._fromUnresolvedResObj(tree, {
|
|
3235
|
+
parseBaseDir: opts.baseDir,
|
|
3236
|
+
originDescription: opts.originDescription,
|
|
3237
|
+
resolved: !hasPlaceholders,
|
|
3238
|
+
resolveOpts
|
|
3239
|
+
});
|
|
3190
3240
|
}
|
|
3191
3241
|
function parseFile(filePath, opts = {}) {
|
|
3192
3242
|
if (typeof process === "undefined" && !opts.readFileSync) {
|