@o3co/ts.hocon 1.10.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.ja.md +129 -1
- package/README.md +103 -10
- package/dist/adapters/env.cjs +150 -31
- package/dist/adapters/env.d.cts +16 -1
- package/dist/adapters/env.d.ts +16 -1
- package/dist/adapters/env.js +150 -30
- package/dist/adapters/jsonc.cjs +148 -18
- package/dist/adapters/jsonc.d.cts +36 -5
- package/dist/adapters/jsonc.d.ts +36 -5
- package/dist/adapters/jsonc.js +148 -17
- package/dist/adapters/properties.cjs +124 -25
- package/dist/adapters/properties.d.cts +6 -1
- package/dist/adapters/properties.d.ts +6 -1
- package/dist/adapters/properties.js +124 -24
- package/dist/adapters/toml.cjs +111 -22
- package/dist/adapters/toml.d.cts +3 -2
- package/dist/adapters/toml.d.ts +3 -2
- package/dist/adapters/toml.js +111 -21
- package/dist/adapters/yaml.cjs +142 -27
- package/dist/adapters/yaml.d.cts +12 -3
- package/dist/adapters/yaml.d.ts +12 -3
- package/dist/adapters/yaml.js +142 -26
- 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 +162 -31
- package/dist/index.d.cts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +169 -31
- package/dist/zod.cjs +153 -23
- package/dist/zod.d.cts +1 -1
- package/dist/zod.d.ts +1 -1
- package/dist/zod.js +160 -23
- package/package.json +58 -22
|
@@ -522,26 +522,74 @@ function deepMergeHoconValues(base, overlay) {
|
|
|
522
522
|
// src/internal/resolver/include-loader.ts
|
|
523
523
|
import { createRequire } from "module";
|
|
524
524
|
import * as nodePath from "path";
|
|
525
|
+
import { pathToFileURL } from "url";
|
|
526
|
+
|
|
527
|
+
// src/internal/strip-bom.ts
|
|
528
|
+
function stripBom(input) {
|
|
529
|
+
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
530
|
+
}
|
|
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
|
+
}
|
|
525
556
|
|
|
526
557
|
// src/internal/properties/properties.ts
|
|
527
558
|
function parseProperties(input) {
|
|
528
559
|
const pairs = [];
|
|
529
|
-
for (const { text, line } of logicalLines(input)) {
|
|
560
|
+
for (const { text, line } of logicalLines(stripBom(input))) {
|
|
530
561
|
const [rawKey, rawValue] = splitKeyValue(text);
|
|
531
562
|
const key = unescapeProps(rawKey, line);
|
|
532
563
|
if (key === "") continue;
|
|
533
|
-
|
|
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)]);
|
|
534
573
|
}
|
|
535
574
|
return nestPairs(pairs);
|
|
536
575
|
}
|
|
537
576
|
function nestPairs(pairs) {
|
|
538
577
|
const root = /* @__PURE__ */ Object.create(null);
|
|
539
|
-
const sorted = [...pairs].sort(([a], [b]) => a
|
|
540
|
-
for (const [
|
|
541
|
-
setNested(root,
|
|
578
|
+
const sorted = [...pairs].sort(([a], [b]) => compareSegments(a, b));
|
|
579
|
+
for (const [segments, value] of sorted) {
|
|
580
|
+
setNested(root, segments, value);
|
|
542
581
|
}
|
|
543
582
|
return root;
|
|
544
583
|
}
|
|
584
|
+
function compareSegments(a, b) {
|
|
585
|
+
const n = Math.min(a.length, b.length);
|
|
586
|
+
for (let i = 0; i < n; i++) {
|
|
587
|
+
const x = a[i];
|
|
588
|
+
const y = b[i];
|
|
589
|
+
if (x !== y) return x < y ? -1 : 1;
|
|
590
|
+
}
|
|
591
|
+
return a.length - b.length;
|
|
592
|
+
}
|
|
545
593
|
function logicalLines(input) {
|
|
546
594
|
const natural = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
547
595
|
const out = [];
|
|
@@ -628,26 +676,20 @@ function unescapeProps(s, line) {
|
|
|
628
676
|
}
|
|
629
677
|
return out;
|
|
630
678
|
}
|
|
631
|
-
var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
632
679
|
function setNested(obj, segments, value) {
|
|
633
680
|
let current = obj;
|
|
634
681
|
for (let i = 0; i < segments.length - 1; i++) {
|
|
635
682
|
const seg = segments[i];
|
|
636
|
-
if (seg === void 0 || DANGEROUS_KEYS.has(seg)) return;
|
|
637
683
|
if (!(seg in current) || typeof current[seg] !== "object" || current[seg] === null) {
|
|
638
684
|
current[seg] = /* @__PURE__ */ Object.create(null);
|
|
639
685
|
}
|
|
640
686
|
current = current[seg];
|
|
641
687
|
}
|
|
642
688
|
const last = segments[segments.length - 1];
|
|
643
|
-
if (last === void 0 || DANGEROUS_KEYS.has(last)) return;
|
|
644
689
|
if (typeof current[last] === "object" && current[last] !== null) return;
|
|
645
690
|
current[last] = value;
|
|
646
691
|
}
|
|
647
692
|
|
|
648
|
-
// src/internal/resolver/include-loader.ts
|
|
649
|
-
var _require = createRequire(import.meta.url);
|
|
650
|
-
|
|
651
693
|
// src/value/numeric-array.ts
|
|
652
694
|
function numericObjectToArray(value) {
|
|
653
695
|
if (value.kind !== "object") return null;
|
|
@@ -1235,10 +1277,10 @@ var Config = class _Config {
|
|
|
1235
1277
|
}
|
|
1236
1278
|
if (v.kind === "object") {
|
|
1237
1279
|
const converted = numericObjectToArray(v);
|
|
1238
|
-
if (converted !== null) return converted.map(hoconToJs);
|
|
1280
|
+
if (converted !== null) return converted.map((item) => hoconToJs(item));
|
|
1239
1281
|
}
|
|
1240
1282
|
if (v.kind !== "array") throw new ConfigError(`expected array at ${path}`, path);
|
|
1241
|
-
return v.items.map(hoconToJs);
|
|
1283
|
+
return v.items.map((item) => hoconToJs(item));
|
|
1242
1284
|
}
|
|
1243
1285
|
has(path) {
|
|
1244
1286
|
return this.lookupNode(path) !== void 0;
|
|
@@ -1366,8 +1408,52 @@ var Config = class _Config {
|
|
|
1366
1408
|
originDescription: this._originDescription
|
|
1367
1409
|
});
|
|
1368
1410
|
}
|
|
1369
|
-
|
|
1370
|
-
|
|
1411
|
+
/**
|
|
1412
|
+
* The whole config as plain JS data: objects, arrays, strings, numbers,
|
|
1413
|
+
* booleans and `null`.
|
|
1414
|
+
*
|
|
1415
|
+
* Keys are reproduced exactly as the config carries them, `__proto__`,
|
|
1416
|
+
* `constructor` and `prototype` included: each is defined as an **own data
|
|
1417
|
+
* property**, so the returned object's prototype is always
|
|
1418
|
+
* `Object.prototype`, and this call writes nothing to the global one.
|
|
1419
|
+
*
|
|
1420
|
+
* ### Passing the result to other code
|
|
1421
|
+
*
|
|
1422
|
+
* A config file — especially a `.properties` file or an env namespace you
|
|
1423
|
+
* merged in — can therefore hand you an own `__proto__` key, and what happens
|
|
1424
|
+
* next depends entirely on how the consumer copies it:
|
|
1425
|
+
*
|
|
1426
|
+
* ```ts
|
|
1427
|
+
* const data = cfg.toObject()
|
|
1428
|
+
* { ...data } // safe — own properties are copied as data
|
|
1429
|
+
* structuredClone(data) // safe
|
|
1430
|
+
* Object.assign({}, data) // NOT safe — [[Set]] on the {} target hits
|
|
1431
|
+
* // Object.prototype's __proto__ setter: the key
|
|
1432
|
+
* // vanishes and config data becomes the result's
|
|
1433
|
+
* // prototype
|
|
1434
|
+
* deepMerge({}, data) // NOT safe — a naive recursive merge reads
|
|
1435
|
+
* // target['__proto__'], gets Object.prototype,
|
|
1436
|
+
* // and writes to it: global pollution
|
|
1437
|
+
* for (const k in data) … // prefer Object.entries / Object.keys
|
|
1438
|
+
* ```
|
|
1439
|
+
*
|
|
1440
|
+
* Those two hazards come from the **destination** object's prototype, so no
|
|
1441
|
+
* option here can disarm them — copy with spread or `structuredClone` instead.
|
|
1442
|
+
*
|
|
1443
|
+
* What `{ nullPrototype: true }` does give you is a result that inherits
|
|
1444
|
+
* nothing: every object comes back with a `null` prototype, so reading
|
|
1445
|
+
* `x.__proto__`, `x.constructor` or `x.toString` yields config data or
|
|
1446
|
+
* `undefined` rather than something from `Object.prototype`, and code that
|
|
1447
|
+
* merges *into* this object cannot climb out of it. Keys are all still
|
|
1448
|
+
* present. The trade-off is the usual one for prototype-less objects: not
|
|
1449
|
+
* `instanceof Object`, and no `hasOwnProperty` of their own.
|
|
1450
|
+
*
|
|
1451
|
+
* Numbers follow the JS number model, so an integer wider than 2^53 rounds
|
|
1452
|
+
* here even when the config holds it exactly — read those with
|
|
1453
|
+
* {@link Config.getString} instead.
|
|
1454
|
+
*/
|
|
1455
|
+
toObject(opts) {
|
|
1456
|
+
return hoconToJs(this.root, opts?.nullPrototype === true);
|
|
1371
1457
|
}
|
|
1372
1458
|
/**
|
|
1373
1459
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
@@ -1479,16 +1565,25 @@ function scalarToJs(raw, valueType) {
|
|
|
1479
1565
|
return raw;
|
|
1480
1566
|
}
|
|
1481
1567
|
}
|
|
1482
|
-
function hoconToJs(v) {
|
|
1568
|
+
function hoconToJs(v, nullPrototype = false) {
|
|
1483
1569
|
switch (v.kind) {
|
|
1484
1570
|
case "scalar":
|
|
1485
1571
|
return scalarToJs(v.raw, v.valueType);
|
|
1486
1572
|
case "array":
|
|
1487
|
-
return v.items.map(hoconToJs);
|
|
1573
|
+
return v.items.map((item) => hoconToJs(item, nullPrototype));
|
|
1488
1574
|
case "object": {
|
|
1489
|
-
const
|
|
1490
|
-
|
|
1491
|
-
|
|
1575
|
+
const entries = Array.from(v.fields, ([k, val]) => [k, hoconToJs(val, nullPrototype)]);
|
|
1576
|
+
if (nullPrototype) {
|
|
1577
|
+
const obj = /* @__PURE__ */ Object.create(null);
|
|
1578
|
+
for (const [k, val] of entries) Object.defineProperty(obj, k, {
|
|
1579
|
+
value: val,
|
|
1580
|
+
writable: true,
|
|
1581
|
+
enumerable: true,
|
|
1582
|
+
configurable: true
|
|
1583
|
+
});
|
|
1584
|
+
return obj;
|
|
1585
|
+
}
|
|
1586
|
+
return Object.fromEntries(entries);
|
|
1492
1587
|
}
|
|
1493
1588
|
}
|
|
1494
1589
|
}
|
|
@@ -1573,10 +1668,15 @@ function normalizeLeadingZeroNumber(raw) {
|
|
|
1573
1668
|
|
|
1574
1669
|
// src/value-factory.ts
|
|
1575
1670
|
function fromMap(values, originDescription) {
|
|
1576
|
-
const fields =
|
|
1671
|
+
const fields = guardStackDepth(
|
|
1672
|
+
() => coerceObject(values, ""),
|
|
1673
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
1674
|
+
);
|
|
1577
1675
|
const root = { kind: "object", fields };
|
|
1578
1676
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1579
1677
|
}
|
|
1678
|
+
var INT64_MAX = 9223372036854775807n;
|
|
1679
|
+
var INT64_MIN = -9223372036854775808n;
|
|
1580
1680
|
function coerceObject(obj, atPath) {
|
|
1581
1681
|
const fields = /* @__PURE__ */ new Map();
|
|
1582
1682
|
for (const [k, v] of Object.entries(obj)) {
|
|
@@ -1605,14 +1705,14 @@ function coerceValue(v, atPath) {
|
|
|
1605
1705
|
atPath
|
|
1606
1706
|
);
|
|
1607
1707
|
}
|
|
1608
|
-
return { kind: "scalar", raw: String(v), valueType: "number" };
|
|
1708
|
+
return { kind: "scalar", raw: Object.is(v, -0) ? "-0" : String(v), valueType: "number" };
|
|
1609
1709
|
}
|
|
1610
1710
|
case "boolean":
|
|
1611
1711
|
return { kind: "scalar", raw: v ? "true" : "false", valueType: "boolean" };
|
|
1612
1712
|
case "bigint": {
|
|
1613
|
-
if (v >
|
|
1713
|
+
if (v > INT64_MAX || v < INT64_MIN) {
|
|
1614
1714
|
throw new ConfigError(
|
|
1615
|
-
`fromMap:
|
|
1715
|
+
`fromMap: integer ${v} is out of int64 range (HOCON integers are int64; spec F0.5) at path "${atPath}"`,
|
|
1616
1716
|
atPath
|
|
1617
1717
|
);
|
|
1618
1718
|
}
|
package/dist/adapters/toml.cjs
CHANGED
|
@@ -550,8 +550,33 @@ function deepMergeHoconValues(base, overlay) {
|
|
|
550
550
|
// src/internal/resolver/include-loader.ts
|
|
551
551
|
var import_node_module = require("module");
|
|
552
552
|
var nodePath = __toESM(require("path"), 1);
|
|
553
|
-
var
|
|
554
|
-
|
|
553
|
+
var import_node_url = require("url");
|
|
554
|
+
|
|
555
|
+
// src/internal/strip-bom.ts
|
|
556
|
+
function stripBom(input) {
|
|
557
|
+
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
558
|
+
}
|
|
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
|
+
}
|
|
555
580
|
|
|
556
581
|
// src/value/numeric-array.ts
|
|
557
582
|
function numericObjectToArray(value) {
|
|
@@ -1140,10 +1165,10 @@ var Config = class _Config {
|
|
|
1140
1165
|
}
|
|
1141
1166
|
if (v.kind === "object") {
|
|
1142
1167
|
const converted = numericObjectToArray(v);
|
|
1143
|
-
if (converted !== null) return converted.map(hoconToJs);
|
|
1168
|
+
if (converted !== null) return converted.map((item) => hoconToJs(item));
|
|
1144
1169
|
}
|
|
1145
1170
|
if (v.kind !== "array") throw new ConfigError(`expected array at ${path}`, path);
|
|
1146
|
-
return v.items.map(hoconToJs);
|
|
1171
|
+
return v.items.map((item) => hoconToJs(item));
|
|
1147
1172
|
}
|
|
1148
1173
|
has(path) {
|
|
1149
1174
|
return this.lookupNode(path) !== void 0;
|
|
@@ -1271,8 +1296,52 @@ var Config = class _Config {
|
|
|
1271
1296
|
originDescription: this._originDescription
|
|
1272
1297
|
});
|
|
1273
1298
|
}
|
|
1274
|
-
|
|
1275
|
-
|
|
1299
|
+
/**
|
|
1300
|
+
* The whole config as plain JS data: objects, arrays, strings, numbers,
|
|
1301
|
+
* booleans and `null`.
|
|
1302
|
+
*
|
|
1303
|
+
* Keys are reproduced exactly as the config carries them, `__proto__`,
|
|
1304
|
+
* `constructor` and `prototype` included: each is defined as an **own data
|
|
1305
|
+
* property**, so the returned object's prototype is always
|
|
1306
|
+
* `Object.prototype`, and this call writes nothing to the global one.
|
|
1307
|
+
*
|
|
1308
|
+
* ### Passing the result to other code
|
|
1309
|
+
*
|
|
1310
|
+
* A config file — especially a `.properties` file or an env namespace you
|
|
1311
|
+
* merged in — can therefore hand you an own `__proto__` key, and what happens
|
|
1312
|
+
* next depends entirely on how the consumer copies it:
|
|
1313
|
+
*
|
|
1314
|
+
* ```ts
|
|
1315
|
+
* const data = cfg.toObject()
|
|
1316
|
+
* { ...data } // safe — own properties are copied as data
|
|
1317
|
+
* structuredClone(data) // safe
|
|
1318
|
+
* Object.assign({}, data) // NOT safe — [[Set]] on the {} target hits
|
|
1319
|
+
* // Object.prototype's __proto__ setter: the key
|
|
1320
|
+
* // vanishes and config data becomes the result's
|
|
1321
|
+
* // prototype
|
|
1322
|
+
* deepMerge({}, data) // NOT safe — a naive recursive merge reads
|
|
1323
|
+
* // target['__proto__'], gets Object.prototype,
|
|
1324
|
+
* // and writes to it: global pollution
|
|
1325
|
+
* for (const k in data) … // prefer Object.entries / Object.keys
|
|
1326
|
+
* ```
|
|
1327
|
+
*
|
|
1328
|
+
* Those two hazards come from the **destination** object's prototype, so no
|
|
1329
|
+
* option here can disarm them — copy with spread or `structuredClone` instead.
|
|
1330
|
+
*
|
|
1331
|
+
* What `{ nullPrototype: true }` does give you is a result that inherits
|
|
1332
|
+
* nothing: every object comes back with a `null` prototype, so reading
|
|
1333
|
+
* `x.__proto__`, `x.constructor` or `x.toString` yields config data or
|
|
1334
|
+
* `undefined` rather than something from `Object.prototype`, and code that
|
|
1335
|
+
* merges *into* this object cannot climb out of it. Keys are all still
|
|
1336
|
+
* present. The trade-off is the usual one for prototype-less objects: not
|
|
1337
|
+
* `instanceof Object`, and no `hasOwnProperty` of their own.
|
|
1338
|
+
*
|
|
1339
|
+
* Numbers follow the JS number model, so an integer wider than 2^53 rounds
|
|
1340
|
+
* here even when the config holds it exactly — read those with
|
|
1341
|
+
* {@link Config.getString} instead.
|
|
1342
|
+
*/
|
|
1343
|
+
toObject(opts) {
|
|
1344
|
+
return hoconToJs(this.root, opts?.nullPrototype === true);
|
|
1276
1345
|
}
|
|
1277
1346
|
/**
|
|
1278
1347
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
@@ -1384,16 +1453,25 @@ function scalarToJs(raw, valueType) {
|
|
|
1384
1453
|
return raw;
|
|
1385
1454
|
}
|
|
1386
1455
|
}
|
|
1387
|
-
function hoconToJs(v) {
|
|
1456
|
+
function hoconToJs(v, nullPrototype = false) {
|
|
1388
1457
|
switch (v.kind) {
|
|
1389
1458
|
case "scalar":
|
|
1390
1459
|
return scalarToJs(v.raw, v.valueType);
|
|
1391
1460
|
case "array":
|
|
1392
|
-
return v.items.map(hoconToJs);
|
|
1461
|
+
return v.items.map((item) => hoconToJs(item, nullPrototype));
|
|
1393
1462
|
case "object": {
|
|
1394
|
-
const
|
|
1395
|
-
|
|
1396
|
-
|
|
1463
|
+
const entries = Array.from(v.fields, ([k, val]) => [k, hoconToJs(val, nullPrototype)]);
|
|
1464
|
+
if (nullPrototype) {
|
|
1465
|
+
const obj = /* @__PURE__ */ Object.create(null);
|
|
1466
|
+
for (const [k, val] of entries) Object.defineProperty(obj, k, {
|
|
1467
|
+
value: val,
|
|
1468
|
+
writable: true,
|
|
1469
|
+
enumerable: true,
|
|
1470
|
+
configurable: true
|
|
1471
|
+
});
|
|
1472
|
+
return obj;
|
|
1473
|
+
}
|
|
1474
|
+
return Object.fromEntries(entries);
|
|
1397
1475
|
}
|
|
1398
1476
|
}
|
|
1399
1477
|
}
|
|
@@ -1478,10 +1556,15 @@ function normalizeLeadingZeroNumber(raw) {
|
|
|
1478
1556
|
|
|
1479
1557
|
// src/value-factory.ts
|
|
1480
1558
|
function fromMap(values, originDescription) {
|
|
1481
|
-
const fields =
|
|
1559
|
+
const fields = guardStackDepth(
|
|
1560
|
+
() => coerceObject(values, ""),
|
|
1561
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
1562
|
+
);
|
|
1482
1563
|
const root = { kind: "object", fields };
|
|
1483
1564
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1484
1565
|
}
|
|
1566
|
+
var INT64_MAX = 9223372036854775807n;
|
|
1567
|
+
var INT64_MIN = -9223372036854775808n;
|
|
1485
1568
|
function coerceObject(obj, atPath) {
|
|
1486
1569
|
const fields = /* @__PURE__ */ new Map();
|
|
1487
1570
|
for (const [k, v] of Object.entries(obj)) {
|
|
@@ -1510,14 +1593,14 @@ function coerceValue(v, atPath) {
|
|
|
1510
1593
|
atPath
|
|
1511
1594
|
);
|
|
1512
1595
|
}
|
|
1513
|
-
return { kind: "scalar", raw: String(v), valueType: "number" };
|
|
1596
|
+
return { kind: "scalar", raw: Object.is(v, -0) ? "-0" : String(v), valueType: "number" };
|
|
1514
1597
|
}
|
|
1515
1598
|
case "boolean":
|
|
1516
1599
|
return { kind: "scalar", raw: v ? "true" : "false", valueType: "boolean" };
|
|
1517
1600
|
case "bigint": {
|
|
1518
|
-
if (v >
|
|
1601
|
+
if (v > INT64_MAX || v < INT64_MIN) {
|
|
1519
1602
|
throw new ConfigError(
|
|
1520
|
-
`fromMap:
|
|
1603
|
+
`fromMap: integer ${v} is out of int64 range (HOCON integers are int64; spec F0.5) at path "${atPath}"`,
|
|
1521
1604
|
atPath
|
|
1522
1605
|
);
|
|
1523
1606
|
}
|
|
@@ -1541,8 +1624,14 @@ function coerceValue(v, atPath) {
|
|
|
1541
1624
|
|
|
1542
1625
|
// src/adapters/toml.ts
|
|
1543
1626
|
function parseTomlConfig(input, originDescription) {
|
|
1544
|
-
const doc = (0, import_smol_toml.parse)(input);
|
|
1545
|
-
return fromMap(
|
|
1627
|
+
const doc = (0, import_smol_toml.parse)(stripBom(input));
|
|
1628
|
+
return fromMap(
|
|
1629
|
+
guardStackDepth(
|
|
1630
|
+
() => convert(doc, ""),
|
|
1631
|
+
(msg) => depthError(`toml: ${msg}`)
|
|
1632
|
+
),
|
|
1633
|
+
originDescription
|
|
1634
|
+
);
|
|
1546
1635
|
}
|
|
1547
1636
|
function convert(v, atPath) {
|
|
1548
1637
|
if (Array.isArray(v)) return v.map((e, i) => convert(e, `${atPath}[${i}]`));
|
|
@@ -1550,11 +1639,11 @@ function convert(v, atPath) {
|
|
|
1550
1639
|
return v.toISOString().replace(/\.(\d*?)0+(?=Z?$)/, (_m, keep) => keep ? `.${keep}` : "");
|
|
1551
1640
|
}
|
|
1552
1641
|
if (v !== null && typeof v === "object") {
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1642
|
+
return Object.fromEntries(
|
|
1643
|
+
Object.entries(v).map(
|
|
1644
|
+
([k, e]) => [k, convert(e, atPath === "" ? k : `${atPath}.${k}`)]
|
|
1645
|
+
)
|
|
1646
|
+
);
|
|
1558
1647
|
}
|
|
1559
1648
|
if (typeof v === "number" && !Number.isFinite(v)) {
|
|
1560
1649
|
throw new ConfigError(
|
package/dist/adapters/toml.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as Config } from '../config-
|
|
1
|
+
import { C as Config } from '../config-Dlq6rF3w.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Read a TOML document as HOCON config, via `smol-toml`.
|
|
@@ -11,7 +11,8 @@ import { C as Config } from '../config-PdhVgeLS.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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as Config } from '../config-
|
|
1
|
+
import { C as Config } from '../config-Dlq6rF3w.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Read a TOML document as HOCON config, via `smol-toml`.
|
|
@@ -11,7 +11,8 @@ import { C as Config } from '../config-PdhVgeLS.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
|
@@ -516,7 +516,33 @@ function deepMergeHoconValues(base, overlay) {
|
|
|
516
516
|
// src/internal/resolver/include-loader.ts
|
|
517
517
|
import { createRequire } from "module";
|
|
518
518
|
import * as nodePath from "path";
|
|
519
|
-
|
|
519
|
+
import { pathToFileURL } from "url";
|
|
520
|
+
|
|
521
|
+
// src/internal/strip-bom.ts
|
|
522
|
+
function stripBom(input) {
|
|
523
|
+
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
524
|
+
}
|
|
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
|
+
}
|
|
520
546
|
|
|
521
547
|
// src/value/numeric-array.ts
|
|
522
548
|
function numericObjectToArray(value) {
|
|
@@ -1105,10 +1131,10 @@ var Config = class _Config {
|
|
|
1105
1131
|
}
|
|
1106
1132
|
if (v.kind === "object") {
|
|
1107
1133
|
const converted = numericObjectToArray(v);
|
|
1108
|
-
if (converted !== null) return converted.map(hoconToJs);
|
|
1134
|
+
if (converted !== null) return converted.map((item) => hoconToJs(item));
|
|
1109
1135
|
}
|
|
1110
1136
|
if (v.kind !== "array") throw new ConfigError(`expected array at ${path}`, path);
|
|
1111
|
-
return v.items.map(hoconToJs);
|
|
1137
|
+
return v.items.map((item) => hoconToJs(item));
|
|
1112
1138
|
}
|
|
1113
1139
|
has(path) {
|
|
1114
1140
|
return this.lookupNode(path) !== void 0;
|
|
@@ -1236,8 +1262,52 @@ var Config = class _Config {
|
|
|
1236
1262
|
originDescription: this._originDescription
|
|
1237
1263
|
});
|
|
1238
1264
|
}
|
|
1239
|
-
|
|
1240
|
-
|
|
1265
|
+
/**
|
|
1266
|
+
* The whole config as plain JS data: objects, arrays, strings, numbers,
|
|
1267
|
+
* booleans and `null`.
|
|
1268
|
+
*
|
|
1269
|
+
* Keys are reproduced exactly as the config carries them, `__proto__`,
|
|
1270
|
+
* `constructor` and `prototype` included: each is defined as an **own data
|
|
1271
|
+
* property**, so the returned object's prototype is always
|
|
1272
|
+
* `Object.prototype`, and this call writes nothing to the global one.
|
|
1273
|
+
*
|
|
1274
|
+
* ### Passing the result to other code
|
|
1275
|
+
*
|
|
1276
|
+
* A config file — especially a `.properties` file or an env namespace you
|
|
1277
|
+
* merged in — can therefore hand you an own `__proto__` key, and what happens
|
|
1278
|
+
* next depends entirely on how the consumer copies it:
|
|
1279
|
+
*
|
|
1280
|
+
* ```ts
|
|
1281
|
+
* const data = cfg.toObject()
|
|
1282
|
+
* { ...data } // safe — own properties are copied as data
|
|
1283
|
+
* structuredClone(data) // safe
|
|
1284
|
+
* Object.assign({}, data) // NOT safe — [[Set]] on the {} target hits
|
|
1285
|
+
* // Object.prototype's __proto__ setter: the key
|
|
1286
|
+
* // vanishes and config data becomes the result's
|
|
1287
|
+
* // prototype
|
|
1288
|
+
* deepMerge({}, data) // NOT safe — a naive recursive merge reads
|
|
1289
|
+
* // target['__proto__'], gets Object.prototype,
|
|
1290
|
+
* // and writes to it: global pollution
|
|
1291
|
+
* for (const k in data) … // prefer Object.entries / Object.keys
|
|
1292
|
+
* ```
|
|
1293
|
+
*
|
|
1294
|
+
* Those two hazards come from the **destination** object's prototype, so no
|
|
1295
|
+
* option here can disarm them — copy with spread or `structuredClone` instead.
|
|
1296
|
+
*
|
|
1297
|
+
* What `{ nullPrototype: true }` does give you is a result that inherits
|
|
1298
|
+
* nothing: every object comes back with a `null` prototype, so reading
|
|
1299
|
+
* `x.__proto__`, `x.constructor` or `x.toString` yields config data or
|
|
1300
|
+
* `undefined` rather than something from `Object.prototype`, and code that
|
|
1301
|
+
* merges *into* this object cannot climb out of it. Keys are all still
|
|
1302
|
+
* present. The trade-off is the usual one for prototype-less objects: not
|
|
1303
|
+
* `instanceof Object`, and no `hasOwnProperty` of their own.
|
|
1304
|
+
*
|
|
1305
|
+
* Numbers follow the JS number model, so an integer wider than 2^53 rounds
|
|
1306
|
+
* here even when the config holds it exactly — read those with
|
|
1307
|
+
* {@link Config.getString} instead.
|
|
1308
|
+
*/
|
|
1309
|
+
toObject(opts) {
|
|
1310
|
+
return hoconToJs(this.root, opts?.nullPrototype === true);
|
|
1241
1311
|
}
|
|
1242
1312
|
/**
|
|
1243
1313
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
@@ -1349,16 +1419,25 @@ function scalarToJs(raw, valueType) {
|
|
|
1349
1419
|
return raw;
|
|
1350
1420
|
}
|
|
1351
1421
|
}
|
|
1352
|
-
function hoconToJs(v) {
|
|
1422
|
+
function hoconToJs(v, nullPrototype = false) {
|
|
1353
1423
|
switch (v.kind) {
|
|
1354
1424
|
case "scalar":
|
|
1355
1425
|
return scalarToJs(v.raw, v.valueType);
|
|
1356
1426
|
case "array":
|
|
1357
|
-
return v.items.map(hoconToJs);
|
|
1427
|
+
return v.items.map((item) => hoconToJs(item, nullPrototype));
|
|
1358
1428
|
case "object": {
|
|
1359
|
-
const
|
|
1360
|
-
|
|
1361
|
-
|
|
1429
|
+
const entries = Array.from(v.fields, ([k, val]) => [k, hoconToJs(val, nullPrototype)]);
|
|
1430
|
+
if (nullPrototype) {
|
|
1431
|
+
const obj = /* @__PURE__ */ Object.create(null);
|
|
1432
|
+
for (const [k, val] of entries) Object.defineProperty(obj, k, {
|
|
1433
|
+
value: val,
|
|
1434
|
+
writable: true,
|
|
1435
|
+
enumerable: true,
|
|
1436
|
+
configurable: true
|
|
1437
|
+
});
|
|
1438
|
+
return obj;
|
|
1439
|
+
}
|
|
1440
|
+
return Object.fromEntries(entries);
|
|
1362
1441
|
}
|
|
1363
1442
|
}
|
|
1364
1443
|
}
|
|
@@ -1443,10 +1522,15 @@ function normalizeLeadingZeroNumber(raw) {
|
|
|
1443
1522
|
|
|
1444
1523
|
// src/value-factory.ts
|
|
1445
1524
|
function fromMap(values, originDescription) {
|
|
1446
|
-
const fields =
|
|
1525
|
+
const fields = guardStackDepth(
|
|
1526
|
+
() => coerceObject(values, ""),
|
|
1527
|
+
(msg) => depthError(`fromMap: ${msg}`)
|
|
1528
|
+
);
|
|
1447
1529
|
const root = { kind: "object", fields };
|
|
1448
1530
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1449
1531
|
}
|
|
1532
|
+
var INT64_MAX = 9223372036854775807n;
|
|
1533
|
+
var INT64_MIN = -9223372036854775808n;
|
|
1450
1534
|
function coerceObject(obj, atPath) {
|
|
1451
1535
|
const fields = /* @__PURE__ */ new Map();
|
|
1452
1536
|
for (const [k, v] of Object.entries(obj)) {
|
|
@@ -1475,14 +1559,14 @@ function coerceValue(v, atPath) {
|
|
|
1475
1559
|
atPath
|
|
1476
1560
|
);
|
|
1477
1561
|
}
|
|
1478
|
-
return { kind: "scalar", raw: String(v), valueType: "number" };
|
|
1562
|
+
return { kind: "scalar", raw: Object.is(v, -0) ? "-0" : String(v), valueType: "number" };
|
|
1479
1563
|
}
|
|
1480
1564
|
case "boolean":
|
|
1481
1565
|
return { kind: "scalar", raw: v ? "true" : "false", valueType: "boolean" };
|
|
1482
1566
|
case "bigint": {
|
|
1483
|
-
if (v >
|
|
1567
|
+
if (v > INT64_MAX || v < INT64_MIN) {
|
|
1484
1568
|
throw new ConfigError(
|
|
1485
|
-
`fromMap:
|
|
1569
|
+
`fromMap: integer ${v} is out of int64 range (HOCON integers are int64; spec F0.5) at path "${atPath}"`,
|
|
1486
1570
|
atPath
|
|
1487
1571
|
);
|
|
1488
1572
|
}
|
|
@@ -1506,8 +1590,14 @@ function coerceValue(v, atPath) {
|
|
|
1506
1590
|
|
|
1507
1591
|
// src/adapters/toml.ts
|
|
1508
1592
|
function parseTomlConfig(input, originDescription) {
|
|
1509
|
-
const doc = parseToml(input);
|
|
1510
|
-
return fromMap(
|
|
1593
|
+
const doc = parseToml(stripBom(input));
|
|
1594
|
+
return fromMap(
|
|
1595
|
+
guardStackDepth(
|
|
1596
|
+
() => convert(doc, ""),
|
|
1597
|
+
(msg) => depthError(`toml: ${msg}`)
|
|
1598
|
+
),
|
|
1599
|
+
originDescription
|
|
1600
|
+
);
|
|
1511
1601
|
}
|
|
1512
1602
|
function convert(v, atPath) {
|
|
1513
1603
|
if (Array.isArray(v)) return v.map((e, i) => convert(e, `${atPath}[${i}]`));
|
|
@@ -1515,11 +1605,11 @@ function convert(v, atPath) {
|
|
|
1515
1605
|
return v.toISOString().replace(/\.(\d*?)0+(?=Z?$)/, (_m, keep) => keep ? `.${keep}` : "");
|
|
1516
1606
|
}
|
|
1517
1607
|
if (v !== null && typeof v === "object") {
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1608
|
+
return Object.fromEntries(
|
|
1609
|
+
Object.entries(v).map(
|
|
1610
|
+
([k, e]) => [k, convert(e, atPath === "" ? k : `${atPath}.${k}`)]
|
|
1611
|
+
)
|
|
1612
|
+
);
|
|
1523
1613
|
}
|
|
1524
1614
|
if (typeof v === "number" && !Number.isFinite(v)) {
|
|
1525
1615
|
throw new ConfigError(
|