@o3co/ts.hocon 1.10.0 → 1.11.0

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