@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.
@@ -1,4 +1,4 @@
1
- import { C as Config } from '../config-PdhVgeLS.js';
1
+ import { C as Config } from '../config-Dlq6rF3w.js';
2
2
 
3
3
  /**
4
4
  * Read JSON with comments and trailing commas — the dialect VS Code and
@@ -10,15 +10,46 @@ import { C as Config } from '../config-PdhVgeLS.js';
10
10
  * of its own.)
11
11
  *
12
12
  * Comments and trailing commas are removed and `JSON.parse` does the rest, so
13
- * the accepted grammar is otherwise exactly the platform's JSON.
13
+ * the accepted grammar is otherwise exactly the platform's JSON. A comment is
14
+ * replaced by whitespace rather than deleted, so it separates the tokens around
15
+ * it and `{"a":1/*x*\/2}` is a syntax error rather than `{"a":12}` (F3.2).
14
16
  *
15
- * See docs/specs/format-ingestion-mapping.md items F3.x in the hocon scope.
17
+ * Integers are ingested losslessly (F0.5): a literal too wide for a JS `number`
18
+ * keeps its digits — `getString` returns them exactly — and one outside int64
19
+ * is refused instead of being rounded. `getNumber` and `toObject` still apply
20
+ * the JS number model, as they do for HOCON's own literals, so read large
21
+ * identifiers with `getString`.
22
+ *
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
16
35
  */
17
36
  declare function parseJsonc(input: string, originDescription?: string): Config;
18
37
  /**
19
38
  * Remove `//` line comments and block comments, leaving string literals alone.
20
- * Newlines inside removed spans are kept so JSON.parse still reports useful
21
- * positions.
39
+ *
40
+ * F3.2: a comment is replaced by *whitespace*, never the empty string — it must
41
+ * keep separating the tokens around it, so a `1`, a block comment and a `2` stay
42
+ * two tokens and fail the JSON decode instead of silently reading as `12`.
43
+ * Newlines inside a removed span are kept so JSON.parse still reports useful
44
+ * positions; a span with no newline becomes a single space.
45
+ *
46
+ * A `//` comment ends at **LF or CR** (F3.2), and at nothing else. Stopping only
47
+ * at LF let a CR-terminated comment eat the rest of the line, and the
48
+ * trailing-comma pass then tidied the remains into valid JSON — so
49
+ * `{"a":1,//c\r"b":2,\n"c":3}` decoded as `{"a":1,"c":3}`, losing a key with no
50
+ * error at all. Stopping at U+2028/U+2029 would be the mirror-image mistake:
51
+ * ending a comment the dialect's own parser is still inside, so the document
52
+ * would mean something different here than in VS Code. See {@link isLineBreak}.
22
53
  */
23
54
  declare function stripComments(src: string): string;
24
55
 
@@ -513,7 +513,33 @@ function deepMergeHoconValues(base, overlay) {
513
513
  // src/internal/resolver/include-loader.ts
514
514
  import { createRequire } from "module";
515
515
  import * as nodePath from "path";
516
- var _require = createRequire(import.meta.url);
516
+ import { pathToFileURL } from "url";
517
+
518
+ // src/internal/strip-bom.ts
519
+ function stripBom(input) {
520
+ return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
521
+ }
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
+ }
517
543
 
518
544
  // src/value/numeric-array.ts
519
545
  function numericObjectToArray(value) {
@@ -1102,10 +1128,10 @@ var Config = class _Config {
1102
1128
  }
1103
1129
  if (v.kind === "object") {
1104
1130
  const converted = numericObjectToArray(v);
1105
- if (converted !== null) return converted.map(hoconToJs);
1131
+ if (converted !== null) return converted.map((item) => hoconToJs(item));
1106
1132
  }
1107
1133
  if (v.kind !== "array") throw new ConfigError(`expected array at ${path}`, path);
1108
- return v.items.map(hoconToJs);
1134
+ return v.items.map((item) => hoconToJs(item));
1109
1135
  }
1110
1136
  has(path) {
1111
1137
  return this.lookupNode(path) !== void 0;
@@ -1233,8 +1259,52 @@ var Config = class _Config {
1233
1259
  originDescription: this._originDescription
1234
1260
  });
1235
1261
  }
1236
- toObject() {
1237
- return hoconToJs(this.root);
1262
+ /**
1263
+ * The whole config as plain JS data: objects, arrays, strings, numbers,
1264
+ * booleans and `null`.
1265
+ *
1266
+ * Keys are reproduced exactly as the config carries them, `__proto__`,
1267
+ * `constructor` and `prototype` included: each is defined as an **own data
1268
+ * property**, so the returned object's prototype is always
1269
+ * `Object.prototype`, and this call writes nothing to the global one.
1270
+ *
1271
+ * ### Passing the result to other code
1272
+ *
1273
+ * A config file — especially a `.properties` file or an env namespace you
1274
+ * merged in — can therefore hand you an own `__proto__` key, and what happens
1275
+ * next depends entirely on how the consumer copies it:
1276
+ *
1277
+ * ```ts
1278
+ * const data = cfg.toObject()
1279
+ * { ...data } // safe — own properties are copied as data
1280
+ * structuredClone(data) // safe
1281
+ * Object.assign({}, data) // NOT safe — [[Set]] on the {} target hits
1282
+ * // Object.prototype's __proto__ setter: the key
1283
+ * // vanishes and config data becomes the result's
1284
+ * // prototype
1285
+ * deepMerge({}, data) // NOT safe — a naive recursive merge reads
1286
+ * // target['__proto__'], gets Object.prototype,
1287
+ * // and writes to it: global pollution
1288
+ * for (const k in data) … // prefer Object.entries / Object.keys
1289
+ * ```
1290
+ *
1291
+ * Those two hazards come from the **destination** object's prototype, so no
1292
+ * option here can disarm them — copy with spread or `structuredClone` instead.
1293
+ *
1294
+ * What `{ nullPrototype: true }` does give you is a result that inherits
1295
+ * nothing: every object comes back with a `null` prototype, so reading
1296
+ * `x.__proto__`, `x.constructor` or `x.toString` yields config data or
1297
+ * `undefined` rather than something from `Object.prototype`, and code that
1298
+ * merges *into* this object cannot climb out of it. Keys are all still
1299
+ * present. The trade-off is the usual one for prototype-less objects: not
1300
+ * `instanceof Object`, and no `hasOwnProperty` of their own.
1301
+ *
1302
+ * Numbers follow the JS number model, so an integer wider than 2^53 rounds
1303
+ * here even when the config holds it exactly — read those with
1304
+ * {@link Config.getString} instead.
1305
+ */
1306
+ toObject(opts) {
1307
+ return hoconToJs(this.root, opts?.nullPrototype === true);
1238
1308
  }
1239
1309
  /**
1240
1310
  * @internal Test-only: renders this resolved Config's value tree as canonical
@@ -1346,16 +1416,25 @@ function scalarToJs(raw, valueType) {
1346
1416
  return raw;
1347
1417
  }
1348
1418
  }
1349
- function hoconToJs(v) {
1419
+ function hoconToJs(v, nullPrototype = false) {
1350
1420
  switch (v.kind) {
1351
1421
  case "scalar":
1352
1422
  return scalarToJs(v.raw, v.valueType);
1353
1423
  case "array":
1354
- return v.items.map(hoconToJs);
1424
+ return v.items.map((item) => hoconToJs(item, nullPrototype));
1355
1425
  case "object": {
1356
- const obj = /* @__PURE__ */ Object.create(null);
1357
- for (const [k, val] of v.fields) obj[k] = hoconToJs(val);
1358
- return Object.assign({}, obj);
1426
+ const entries = Array.from(v.fields, ([k, val]) => [k, hoconToJs(val, nullPrototype)]);
1427
+ if (nullPrototype) {
1428
+ const obj = /* @__PURE__ */ Object.create(null);
1429
+ for (const [k, val] of entries) Object.defineProperty(obj, k, {
1430
+ value: val,
1431
+ writable: true,
1432
+ enumerable: true,
1433
+ configurable: true
1434
+ });
1435
+ return obj;
1436
+ }
1437
+ return Object.fromEntries(entries);
1359
1438
  }
1360
1439
  }
1361
1440
  }
@@ -1440,10 +1519,15 @@ function normalizeLeadingZeroNumber(raw) {
1440
1519
 
1441
1520
  // src/value-factory.ts
1442
1521
  function fromMap(values, originDescription) {
1443
- const fields = coerceObject(values, "");
1522
+ const fields = guardStackDepth(
1523
+ () => coerceObject(values, ""),
1524
+ (msg) => depthError(`fromMap: ${msg}`)
1525
+ );
1444
1526
  const root = { kind: "object", fields };
1445
1527
  return Config._fromResolvedValue(root, { originDescription });
1446
1528
  }
1529
+ var INT64_MAX = 9223372036854775807n;
1530
+ var INT64_MIN = -9223372036854775808n;
1447
1531
  function coerceObject(obj, atPath) {
1448
1532
  const fields = /* @__PURE__ */ new Map();
1449
1533
  for (const [k, v] of Object.entries(obj)) {
@@ -1472,14 +1556,14 @@ function coerceValue(v, atPath) {
1472
1556
  atPath
1473
1557
  );
1474
1558
  }
1475
- return { kind: "scalar", raw: String(v), valueType: "number" };
1559
+ return { kind: "scalar", raw: Object.is(v, -0) ? "-0" : String(v), valueType: "number" };
1476
1560
  }
1477
1561
  case "boolean":
1478
1562
  return { kind: "scalar", raw: v ? "true" : "false", valueType: "boolean" };
1479
1563
  case "bigint": {
1480
- if (v > BigInt(Number.MAX_SAFE_INTEGER) || v < BigInt(Number.MIN_SAFE_INTEGER)) {
1564
+ if (v > INT64_MAX || v < INT64_MIN) {
1481
1565
  throw new ConfigError(
1482
- `fromMap: bigint ${v} exceeds Number.MAX_SAFE_INTEGER (not representable as HOCON number) at path "${atPath}"`,
1566
+ `fromMap: integer ${v} is out of int64 range (HOCON integers are int64; spec F0.5) at path "${atPath}"`,
1483
1567
  atPath
1484
1568
  );
1485
1569
  }
@@ -1503,7 +1587,10 @@ function coerceValue(v, atPath) {
1503
1587
 
1504
1588
  // src/adapters/jsonc.ts
1505
1589
  function parseJsonc(input, originDescription) {
1506
- const doc = JSON.parse(stripTrailingCommas(stripComments(input)));
1590
+ const doc = guardStackDepth(
1591
+ () => JSON.parse(stripTrailingCommas(stripComments(stripBom(input))), bigIntReviver),
1592
+ (msg) => depthError(`jsonc: ${msg}`)
1593
+ );
1507
1594
  if (doc === null || typeof doc !== "object" || Array.isArray(doc)) {
1508
1595
  throw new ConfigError(
1509
1596
  `jsonc: document root is ${Array.isArray(doc) ? "an array" : typeof doc}, but a config root must be an object (spec F0.3)`,
@@ -1512,6 +1599,50 @@ function parseJsonc(input, originDescription) {
1512
1599
  }
1513
1600
  return fromMap(doc, originDescription);
1514
1601
  }
1602
+ function isIntegerLiteral(source) {
1603
+ return !/[.eE]/.test(source);
1604
+ }
1605
+ var HAS_SOURCE_TEXT_ACCESS = (() => {
1606
+ let seen;
1607
+ JSON.parse("1", function(_k, v, context) {
1608
+ seen = context?.source;
1609
+ return v;
1610
+ });
1611
+ return seen !== void 0;
1612
+ })();
1613
+ function bigIntReviver(key, value, context) {
1614
+ if (typeof value !== "number" || Number.isSafeInteger(value)) return value;
1615
+ const source = context?.source;
1616
+ if (source === void 0) {
1617
+ if (!Number.isInteger(value)) return value;
1618
+ throw new ConfigError(
1619
+ `jsonc: the integer at "${key || "<root>"}" needs more precision than a JS number holds, and this runtime does not expose JSON.parse source text (${HAS_SOURCE_TEXT_ACCESS ? "unexpected \u2014 the capability probe said otherwise" : "requires Node >= 22 or an engine with JSON.parse source access"}), so it cannot be read losslessly (spec F0.5)`,
1620
+ key
1621
+ );
1622
+ }
1623
+ if (!isIntegerLiteral(source)) return value;
1624
+ return BigInt(source);
1625
+ }
1626
+ function isLineBreak(c) {
1627
+ return c === "\n" || c === "\r";
1628
+ }
1629
+ function lineBreaksOf(span) {
1630
+ let out = "";
1631
+ for (let i = 0; i < span.length; i++) {
1632
+ const c = span[i];
1633
+ if (c === "\r") {
1634
+ if (span[i + 1] === "\n") {
1635
+ out += "\r\n";
1636
+ i++;
1637
+ } else {
1638
+ out += "\r";
1639
+ }
1640
+ } else if (c === "\n") {
1641
+ out += "\n";
1642
+ }
1643
+ }
1644
+ return out;
1645
+ }
1515
1646
  function stripComments(src) {
1516
1647
  let out = "";
1517
1648
  for (let i = 0; i < src.length; ) {
@@ -1523,13 +1654,13 @@ function stripComments(src) {
1523
1654
  continue;
1524
1655
  }
1525
1656
  if (c === "/" && src[i + 1] === "/") {
1526
- while (i < src.length && src[i] !== "\n") i++;
1657
+ while (i < src.length && !isLineBreak(src[i])) i++;
1527
1658
  continue;
1528
1659
  }
1529
1660
  if (c === "/" && src[i + 1] === "*") {
1530
1661
  const end = src.indexOf("*/", i + 2);
1531
1662
  if (end === -1) throw new ConfigError("jsonc: unterminated block comment", "");
1532
- for (const ch of src.slice(i, end + 2)) if (ch === "\n") out += "\n";
1663
+ out += lineBreaksOf(src.slice(i, end + 2)) || " ";
1533
1664
  i = end + 2;
1534
1665
  continue;
1535
1666
  }
@@ -558,26 +558,74 @@ function deepMergeHoconValues(base, overlay) {
558
558
  // src/internal/resolver/include-loader.ts
559
559
  var import_node_module = require("module");
560
560
  var nodePath = __toESM(require("path"), 1);
561
+ var import_node_url = require("url");
562
+
563
+ // src/internal/strip-bom.ts
564
+ function stripBom(input) {
565
+ return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
566
+ }
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
+ }
561
592
 
562
593
  // src/internal/properties/properties.ts
563
594
  function parseProperties(input) {
564
595
  const pairs = [];
565
- for (const { text, line } of logicalLines(input)) {
596
+ for (const { text, line } of logicalLines(stripBom(input))) {
566
597
  const [rawKey, rawValue] = splitKeyValue(text);
567
598
  const key = unescapeProps(rawKey, line);
568
599
  if (key === "") continue;
569
- pairs.push([key, unescapeProps(rawValue, line)]);
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)]);
570
609
  }
571
610
  return nestPairs(pairs);
572
611
  }
573
612
  function nestPairs(pairs) {
574
613
  const root = /* @__PURE__ */ Object.create(null);
575
- const sorted = [...pairs].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
576
- for (const [key, value] of sorted) {
577
- setNested(root, key.split("."), value);
614
+ const sorted = [...pairs].sort(([a], [b]) => compareSegments(a, b));
615
+ for (const [segments, value] of sorted) {
616
+ setNested(root, segments, value);
578
617
  }
579
618
  return root;
580
619
  }
620
+ function compareSegments(a, b) {
621
+ const n = Math.min(a.length, b.length);
622
+ for (let i = 0; i < n; i++) {
623
+ const x = a[i];
624
+ const y = b[i];
625
+ if (x !== y) return x < y ? -1 : 1;
626
+ }
627
+ return a.length - b.length;
628
+ }
581
629
  function logicalLines(input) {
582
630
  const natural = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
583
631
  const out = [];
@@ -664,27 +712,20 @@ function unescapeProps(s, line) {
664
712
  }
665
713
  return out;
666
714
  }
667
- var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
668
715
  function setNested(obj, segments, value) {
669
716
  let current = obj;
670
717
  for (let i = 0; i < segments.length - 1; i++) {
671
718
  const seg = segments[i];
672
- if (seg === void 0 || DANGEROUS_KEYS.has(seg)) return;
673
719
  if (!(seg in current) || typeof current[seg] !== "object" || current[seg] === null) {
674
720
  current[seg] = /* @__PURE__ */ Object.create(null);
675
721
  }
676
722
  current = current[seg];
677
723
  }
678
724
  const last = segments[segments.length - 1];
679
- if (last === void 0 || DANGEROUS_KEYS.has(last)) return;
680
725
  if (typeof current[last] === "object" && current[last] !== null) return;
681
726
  current[last] = value;
682
727
  }
683
728
 
684
- // src/internal/resolver/include-loader.ts
685
- var import_meta = {};
686
- var _require = (0, import_node_module.createRequire)(import_meta.url);
687
-
688
729
  // src/value/numeric-array.ts
689
730
  function numericObjectToArray(value) {
690
731
  if (value.kind !== "object") return null;
@@ -1272,10 +1313,10 @@ var Config = class _Config {
1272
1313
  }
1273
1314
  if (v.kind === "object") {
1274
1315
  const converted = numericObjectToArray(v);
1275
- if (converted !== null) return converted.map(hoconToJs);
1316
+ if (converted !== null) return converted.map((item) => hoconToJs(item));
1276
1317
  }
1277
1318
  if (v.kind !== "array") throw new ConfigError(`expected array at ${path}`, path);
1278
- return v.items.map(hoconToJs);
1319
+ return v.items.map((item) => hoconToJs(item));
1279
1320
  }
1280
1321
  has(path) {
1281
1322
  return this.lookupNode(path) !== void 0;
@@ -1403,8 +1444,52 @@ var Config = class _Config {
1403
1444
  originDescription: this._originDescription
1404
1445
  });
1405
1446
  }
1406
- toObject() {
1407
- return hoconToJs(this.root);
1447
+ /**
1448
+ * The whole config as plain JS data: objects, arrays, strings, numbers,
1449
+ * booleans and `null`.
1450
+ *
1451
+ * Keys are reproduced exactly as the config carries them, `__proto__`,
1452
+ * `constructor` and `prototype` included: each is defined as an **own data
1453
+ * property**, so the returned object's prototype is always
1454
+ * `Object.prototype`, and this call writes nothing to the global one.
1455
+ *
1456
+ * ### Passing the result to other code
1457
+ *
1458
+ * A config file — especially a `.properties` file or an env namespace you
1459
+ * merged in — can therefore hand you an own `__proto__` key, and what happens
1460
+ * next depends entirely on how the consumer copies it:
1461
+ *
1462
+ * ```ts
1463
+ * const data = cfg.toObject()
1464
+ * { ...data } // safe — own properties are copied as data
1465
+ * structuredClone(data) // safe
1466
+ * Object.assign({}, data) // NOT safe — [[Set]] on the {} target hits
1467
+ * // Object.prototype's __proto__ setter: the key
1468
+ * // vanishes and config data becomes the result's
1469
+ * // prototype
1470
+ * deepMerge({}, data) // NOT safe — a naive recursive merge reads
1471
+ * // target['__proto__'], gets Object.prototype,
1472
+ * // and writes to it: global pollution
1473
+ * for (const k in data) … // prefer Object.entries / Object.keys
1474
+ * ```
1475
+ *
1476
+ * Those two hazards come from the **destination** object's prototype, so no
1477
+ * option here can disarm them — copy with spread or `structuredClone` instead.
1478
+ *
1479
+ * What `{ nullPrototype: true }` does give you is a result that inherits
1480
+ * nothing: every object comes back with a `null` prototype, so reading
1481
+ * `x.__proto__`, `x.constructor` or `x.toString` yields config data or
1482
+ * `undefined` rather than something from `Object.prototype`, and code that
1483
+ * merges *into* this object cannot climb out of it. Keys are all still
1484
+ * present. The trade-off is the usual one for prototype-less objects: not
1485
+ * `instanceof Object`, and no `hasOwnProperty` of their own.
1486
+ *
1487
+ * Numbers follow the JS number model, so an integer wider than 2^53 rounds
1488
+ * here even when the config holds it exactly — read those with
1489
+ * {@link Config.getString} instead.
1490
+ */
1491
+ toObject(opts) {
1492
+ return hoconToJs(this.root, opts?.nullPrototype === true);
1408
1493
  }
1409
1494
  /**
1410
1495
  * @internal Test-only: renders this resolved Config's value tree as canonical
@@ -1516,16 +1601,25 @@ function scalarToJs(raw, valueType) {
1516
1601
  return raw;
1517
1602
  }
1518
1603
  }
1519
- function hoconToJs(v) {
1604
+ function hoconToJs(v, nullPrototype = false) {
1520
1605
  switch (v.kind) {
1521
1606
  case "scalar":
1522
1607
  return scalarToJs(v.raw, v.valueType);
1523
1608
  case "array":
1524
- return v.items.map(hoconToJs);
1609
+ return v.items.map((item) => hoconToJs(item, nullPrototype));
1525
1610
  case "object": {
1526
- const obj = /* @__PURE__ */ Object.create(null);
1527
- for (const [k, val] of v.fields) obj[k] = hoconToJs(val);
1528
- return Object.assign({}, obj);
1611
+ const entries = Array.from(v.fields, ([k, val]) => [k, hoconToJs(val, nullPrototype)]);
1612
+ if (nullPrototype) {
1613
+ const obj = /* @__PURE__ */ Object.create(null);
1614
+ for (const [k, val] of entries) Object.defineProperty(obj, k, {
1615
+ value: val,
1616
+ writable: true,
1617
+ enumerable: true,
1618
+ configurable: true
1619
+ });
1620
+ return obj;
1621
+ }
1622
+ return Object.fromEntries(entries);
1529
1623
  }
1530
1624
  }
1531
1625
  }
@@ -1610,10 +1704,15 @@ function normalizeLeadingZeroNumber(raw) {
1610
1704
 
1611
1705
  // src/value-factory.ts
1612
1706
  function fromMap(values, originDescription) {
1613
- const fields = coerceObject(values, "");
1707
+ const fields = guardStackDepth(
1708
+ () => coerceObject(values, ""),
1709
+ (msg) => depthError(`fromMap: ${msg}`)
1710
+ );
1614
1711
  const root = { kind: "object", fields };
1615
1712
  return Config._fromResolvedValue(root, { originDescription });
1616
1713
  }
1714
+ var INT64_MAX = 9223372036854775807n;
1715
+ var INT64_MIN = -9223372036854775808n;
1617
1716
  function coerceObject(obj, atPath) {
1618
1717
  const fields = /* @__PURE__ */ new Map();
1619
1718
  for (const [k, v] of Object.entries(obj)) {
@@ -1642,14 +1741,14 @@ function coerceValue(v, atPath) {
1642
1741
  atPath
1643
1742
  );
1644
1743
  }
1645
- return { kind: "scalar", raw: String(v), valueType: "number" };
1744
+ return { kind: "scalar", raw: Object.is(v, -0) ? "-0" : String(v), valueType: "number" };
1646
1745
  }
1647
1746
  case "boolean":
1648
1747
  return { kind: "scalar", raw: v ? "true" : "false", valueType: "boolean" };
1649
1748
  case "bigint": {
1650
- if (v > BigInt(Number.MAX_SAFE_INTEGER) || v < BigInt(Number.MIN_SAFE_INTEGER)) {
1749
+ if (v > INT64_MAX || v < INT64_MIN) {
1651
1750
  throw new ConfigError(
1652
- `fromMap: bigint ${v} exceeds Number.MAX_SAFE_INTEGER (not representable as HOCON number) at path "${atPath}"`,
1751
+ `fromMap: integer ${v} is out of int64 range (HOCON integers are int64; spec F0.5) at path "${atPath}"`,
1653
1752
  atPath
1654
1753
  );
1655
1754
  }
@@ -1,4 +1,4 @@
1
- import { C as Config } from '../config-PdhVgeLS.cjs';
1
+ import { C as Config } from '../config-Dlq6rF3w.cjs';
2
2
 
3
3
  /**
4
4
  * Read a `java.util.Properties` file as HOCON config.
@@ -19,6 +19,11 @@ import { C as Config } from '../config-PdhVgeLS.cjs';
19
19
  * A `${a.b}` in a value stays that literal text — the file belongs to another
20
20
  * program that never agreed to HOCON's syntax (spec F0.2).
21
21
  *
22
+ * Dotted keys nest (F2.1), and every key is preserved — `__proto__`,
23
+ * `constructor` and `prototype` included (F2.9). They arrive as ordinary keys:
24
+ * the tree is built on null-prototype objects and `toObject()` defines own
25
+ * properties, so nothing can reach `Object.prototype`.
26
+ *
22
27
  * Shares its syntax layer with `include "x.properties"`, so the two cannot
23
28
  * drift apart.
24
29
  */
@@ -1,4 +1,4 @@
1
- import { C as Config } from '../config-PdhVgeLS.js';
1
+ import { C as Config } from '../config-Dlq6rF3w.js';
2
2
 
3
3
  /**
4
4
  * Read a `java.util.Properties` file as HOCON config.
@@ -19,6 +19,11 @@ import { C as Config } from '../config-PdhVgeLS.js';
19
19
  * A `${a.b}` in a value stays that literal text — the file belongs to another
20
20
  * program that never agreed to HOCON's syntax (spec F0.2).
21
21
  *
22
+ * Dotted keys nest (F2.1), and every key is preserved — `__proto__`,
23
+ * `constructor` and `prototype` included (F2.9). They arrive as ordinary keys:
24
+ * the tree is built on null-prototype objects and `toObject()` defines own
25
+ * properties, so nothing can reach `Object.prototype`.
26
+ *
22
27
  * Shares its syntax layer with `include "x.properties"`, so the two cannot
23
28
  * drift apart.
24
29
  */