@o3co/ts.hocon 1.10.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +129 -1
- package/README.md +90 -2
- package/dist/adapters/env.cjs +98 -28
- package/dist/adapters/env.d.cts +16 -1
- package/dist/adapters/env.d.ts +16 -1
- package/dist/adapters/env.js +98 -27
- package/dist/adapters/jsonc.cjs +120 -17
- package/dist/adapters/jsonc.d.cts +24 -4
- package/dist/adapters/jsonc.d.ts +24 -4
- package/dist/adapters/jsonc.js +120 -16
- package/dist/adapters/properties.cjs +87 -24
- package/dist/adapters/properties.d.cts +6 -1
- package/dist/adapters/properties.d.ts +6 -1
- package/dist/adapters/properties.js +87 -23
- package/dist/adapters/toml.cjs +79 -20
- package/dist/adapters/toml.d.cts +1 -1
- package/dist/adapters/toml.d.ts +1 -1
- package/dist/adapters/toml.js +79 -19
- package/dist/adapters/yaml.cjs +100 -24
- package/dist/adapters/yaml.d.cts +10 -2
- package/dist/adapters/yaml.d.ts +10 -2
- package/dist/adapters/yaml.js +100 -23
- package/dist/{config-PdhVgeLS.d.cts → config-Dlq6rF3w.d.cts} +47 -1
- package/dist/{config-PdhVgeLS.d.ts → config-Dlq6rF3w.d.ts} +47 -1
- package/dist/index.cjs +104 -22
- package/dist/index.d.cts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +111 -22
- package/dist/zod.cjs +100 -20
- package/dist/zod.d.cts +1 -1
- package/dist/zod.d.ts +1 -1
- package/dist/zod.js +107 -20
- package/package.json +58 -22
package/dist/adapters/toml.cjs
CHANGED
|
@@ -550,8 +550,12 @@ 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
|
+
}
|
|
555
559
|
|
|
556
560
|
// src/value/numeric-array.ts
|
|
557
561
|
function numericObjectToArray(value) {
|
|
@@ -1140,10 +1144,10 @@ var Config = class _Config {
|
|
|
1140
1144
|
}
|
|
1141
1145
|
if (v.kind === "object") {
|
|
1142
1146
|
const converted = numericObjectToArray(v);
|
|
1143
|
-
if (converted !== null) return converted.map(hoconToJs);
|
|
1147
|
+
if (converted !== null) return converted.map((item) => hoconToJs(item));
|
|
1144
1148
|
}
|
|
1145
1149
|
if (v.kind !== "array") throw new ConfigError(`expected array at ${path}`, path);
|
|
1146
|
-
return v.items.map(hoconToJs);
|
|
1150
|
+
return v.items.map((item) => hoconToJs(item));
|
|
1147
1151
|
}
|
|
1148
1152
|
has(path) {
|
|
1149
1153
|
return this.lookupNode(path) !== void 0;
|
|
@@ -1271,8 +1275,52 @@ var Config = class _Config {
|
|
|
1271
1275
|
originDescription: this._originDescription
|
|
1272
1276
|
});
|
|
1273
1277
|
}
|
|
1274
|
-
|
|
1275
|
-
|
|
1278
|
+
/**
|
|
1279
|
+
* The whole config as plain JS data: objects, arrays, strings, numbers,
|
|
1280
|
+
* booleans and `null`.
|
|
1281
|
+
*
|
|
1282
|
+
* Keys are reproduced exactly as the config carries them, `__proto__`,
|
|
1283
|
+
* `constructor` and `prototype` included: each is defined as an **own data
|
|
1284
|
+
* property**, so the returned object's prototype is always
|
|
1285
|
+
* `Object.prototype`, and this call writes nothing to the global one.
|
|
1286
|
+
*
|
|
1287
|
+
* ### Passing the result to other code
|
|
1288
|
+
*
|
|
1289
|
+
* A config file — especially a `.properties` file or an env namespace you
|
|
1290
|
+
* merged in — can therefore hand you an own `__proto__` key, and what happens
|
|
1291
|
+
* next depends entirely on how the consumer copies it:
|
|
1292
|
+
*
|
|
1293
|
+
* ```ts
|
|
1294
|
+
* const data = cfg.toObject()
|
|
1295
|
+
* { ...data } // safe — own properties are copied as data
|
|
1296
|
+
* structuredClone(data) // safe
|
|
1297
|
+
* Object.assign({}, data) // NOT safe — [[Set]] on the {} target hits
|
|
1298
|
+
* // Object.prototype's __proto__ setter: the key
|
|
1299
|
+
* // vanishes and config data becomes the result's
|
|
1300
|
+
* // prototype
|
|
1301
|
+
* deepMerge({}, data) // NOT safe — a naive recursive merge reads
|
|
1302
|
+
* // target['__proto__'], gets Object.prototype,
|
|
1303
|
+
* // and writes to it: global pollution
|
|
1304
|
+
* for (const k in data) … // prefer Object.entries / Object.keys
|
|
1305
|
+
* ```
|
|
1306
|
+
*
|
|
1307
|
+
* Those two hazards come from the **destination** object's prototype, so no
|
|
1308
|
+
* option here can disarm them — copy with spread or `structuredClone` instead.
|
|
1309
|
+
*
|
|
1310
|
+
* What `{ nullPrototype: true }` does give you is a result that inherits
|
|
1311
|
+
* nothing: every object comes back with a `null` prototype, so reading
|
|
1312
|
+
* `x.__proto__`, `x.constructor` or `x.toString` yields config data or
|
|
1313
|
+
* `undefined` rather than something from `Object.prototype`, and code that
|
|
1314
|
+
* merges *into* this object cannot climb out of it. Keys are all still
|
|
1315
|
+
* present. The trade-off is the usual one for prototype-less objects: not
|
|
1316
|
+
* `instanceof Object`, and no `hasOwnProperty` of their own.
|
|
1317
|
+
*
|
|
1318
|
+
* Numbers follow the JS number model, so an integer wider than 2^53 rounds
|
|
1319
|
+
* here even when the config holds it exactly — read those with
|
|
1320
|
+
* {@link Config.getString} instead.
|
|
1321
|
+
*/
|
|
1322
|
+
toObject(opts) {
|
|
1323
|
+
return hoconToJs(this.root, opts?.nullPrototype === true);
|
|
1276
1324
|
}
|
|
1277
1325
|
/**
|
|
1278
1326
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
@@ -1384,16 +1432,25 @@ function scalarToJs(raw, valueType) {
|
|
|
1384
1432
|
return raw;
|
|
1385
1433
|
}
|
|
1386
1434
|
}
|
|
1387
|
-
function hoconToJs(v) {
|
|
1435
|
+
function hoconToJs(v, nullPrototype = false) {
|
|
1388
1436
|
switch (v.kind) {
|
|
1389
1437
|
case "scalar":
|
|
1390
1438
|
return scalarToJs(v.raw, v.valueType);
|
|
1391
1439
|
case "array":
|
|
1392
|
-
return v.items.map(hoconToJs);
|
|
1440
|
+
return v.items.map((item) => hoconToJs(item, nullPrototype));
|
|
1393
1441
|
case "object": {
|
|
1394
|
-
const
|
|
1395
|
-
|
|
1396
|
-
|
|
1442
|
+
const entries = Array.from(v.fields, ([k, val]) => [k, hoconToJs(val, nullPrototype)]);
|
|
1443
|
+
if (nullPrototype) {
|
|
1444
|
+
const obj = /* @__PURE__ */ Object.create(null);
|
|
1445
|
+
for (const [k, val] of entries) Object.defineProperty(obj, k, {
|
|
1446
|
+
value: val,
|
|
1447
|
+
writable: true,
|
|
1448
|
+
enumerable: true,
|
|
1449
|
+
configurable: true
|
|
1450
|
+
});
|
|
1451
|
+
return obj;
|
|
1452
|
+
}
|
|
1453
|
+
return Object.fromEntries(entries);
|
|
1397
1454
|
}
|
|
1398
1455
|
}
|
|
1399
1456
|
}
|
|
@@ -1482,6 +1539,8 @@ function fromMap(values, originDescription) {
|
|
|
1482
1539
|
const root = { kind: "object", fields };
|
|
1483
1540
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1484
1541
|
}
|
|
1542
|
+
var INT64_MAX = 9223372036854775807n;
|
|
1543
|
+
var INT64_MIN = -9223372036854775808n;
|
|
1485
1544
|
function coerceObject(obj, atPath) {
|
|
1486
1545
|
const fields = /* @__PURE__ */ new Map();
|
|
1487
1546
|
for (const [k, v] of Object.entries(obj)) {
|
|
@@ -1510,14 +1569,14 @@ function coerceValue(v, atPath) {
|
|
|
1510
1569
|
atPath
|
|
1511
1570
|
);
|
|
1512
1571
|
}
|
|
1513
|
-
return { kind: "scalar", raw: String(v), valueType: "number" };
|
|
1572
|
+
return { kind: "scalar", raw: Object.is(v, -0) ? "-0" : String(v), valueType: "number" };
|
|
1514
1573
|
}
|
|
1515
1574
|
case "boolean":
|
|
1516
1575
|
return { kind: "scalar", raw: v ? "true" : "false", valueType: "boolean" };
|
|
1517
1576
|
case "bigint": {
|
|
1518
|
-
if (v >
|
|
1577
|
+
if (v > INT64_MAX || v < INT64_MIN) {
|
|
1519
1578
|
throw new ConfigError(
|
|
1520
|
-
`fromMap:
|
|
1579
|
+
`fromMap: integer ${v} is out of int64 range (HOCON integers are int64; spec F0.5) at path "${atPath}"`,
|
|
1521
1580
|
atPath
|
|
1522
1581
|
);
|
|
1523
1582
|
}
|
|
@@ -1541,7 +1600,7 @@ function coerceValue(v, atPath) {
|
|
|
1541
1600
|
|
|
1542
1601
|
// src/adapters/toml.ts
|
|
1543
1602
|
function parseTomlConfig(input, originDescription) {
|
|
1544
|
-
const doc = (0, import_smol_toml.parse)(input);
|
|
1603
|
+
const doc = (0, import_smol_toml.parse)(stripBom(input));
|
|
1545
1604
|
return fromMap(convert(doc, ""), originDescription);
|
|
1546
1605
|
}
|
|
1547
1606
|
function convert(v, atPath) {
|
|
@@ -1550,11 +1609,11 @@ function convert(v, atPath) {
|
|
|
1550
1609
|
return v.toISOString().replace(/\.(\d*?)0+(?=Z?$)/, (_m, keep) => keep ? `.${keep}` : "");
|
|
1551
1610
|
}
|
|
1552
1611
|
if (v !== null && typeof v === "object") {
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1612
|
+
return Object.fromEntries(
|
|
1613
|
+
Object.entries(v).map(
|
|
1614
|
+
([k, e]) => [k, convert(e, atPath === "" ? k : `${atPath}.${k}`)]
|
|
1615
|
+
)
|
|
1616
|
+
);
|
|
1558
1617
|
}
|
|
1559
1618
|
if (typeof v === "number" && !Number.isFinite(v)) {
|
|
1560
1619
|
throw new ConfigError(
|
package/dist/adapters/toml.d.cts
CHANGED
package/dist/adapters/toml.d.ts
CHANGED
package/dist/adapters/toml.js
CHANGED
|
@@ -516,7 +516,12 @@ 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
|
+
}
|
|
520
525
|
|
|
521
526
|
// src/value/numeric-array.ts
|
|
522
527
|
function numericObjectToArray(value) {
|
|
@@ -1105,10 +1110,10 @@ var Config = class _Config {
|
|
|
1105
1110
|
}
|
|
1106
1111
|
if (v.kind === "object") {
|
|
1107
1112
|
const converted = numericObjectToArray(v);
|
|
1108
|
-
if (converted !== null) return converted.map(hoconToJs);
|
|
1113
|
+
if (converted !== null) return converted.map((item) => hoconToJs(item));
|
|
1109
1114
|
}
|
|
1110
1115
|
if (v.kind !== "array") throw new ConfigError(`expected array at ${path}`, path);
|
|
1111
|
-
return v.items.map(hoconToJs);
|
|
1116
|
+
return v.items.map((item) => hoconToJs(item));
|
|
1112
1117
|
}
|
|
1113
1118
|
has(path) {
|
|
1114
1119
|
return this.lookupNode(path) !== void 0;
|
|
@@ -1236,8 +1241,52 @@ var Config = class _Config {
|
|
|
1236
1241
|
originDescription: this._originDescription
|
|
1237
1242
|
});
|
|
1238
1243
|
}
|
|
1239
|
-
|
|
1240
|
-
|
|
1244
|
+
/**
|
|
1245
|
+
* The whole config as plain JS data: objects, arrays, strings, numbers,
|
|
1246
|
+
* booleans and `null`.
|
|
1247
|
+
*
|
|
1248
|
+
* Keys are reproduced exactly as the config carries them, `__proto__`,
|
|
1249
|
+
* `constructor` and `prototype` included: each is defined as an **own data
|
|
1250
|
+
* property**, so the returned object's prototype is always
|
|
1251
|
+
* `Object.prototype`, and this call writes nothing to the global one.
|
|
1252
|
+
*
|
|
1253
|
+
* ### Passing the result to other code
|
|
1254
|
+
*
|
|
1255
|
+
* A config file — especially a `.properties` file or an env namespace you
|
|
1256
|
+
* merged in — can therefore hand you an own `__proto__` key, and what happens
|
|
1257
|
+
* next depends entirely on how the consumer copies it:
|
|
1258
|
+
*
|
|
1259
|
+
* ```ts
|
|
1260
|
+
* const data = cfg.toObject()
|
|
1261
|
+
* { ...data } // safe — own properties are copied as data
|
|
1262
|
+
* structuredClone(data) // safe
|
|
1263
|
+
* Object.assign({}, data) // NOT safe — [[Set]] on the {} target hits
|
|
1264
|
+
* // Object.prototype's __proto__ setter: the key
|
|
1265
|
+
* // vanishes and config data becomes the result's
|
|
1266
|
+
* // prototype
|
|
1267
|
+
* deepMerge({}, data) // NOT safe — a naive recursive merge reads
|
|
1268
|
+
* // target['__proto__'], gets Object.prototype,
|
|
1269
|
+
* // and writes to it: global pollution
|
|
1270
|
+
* for (const k in data) … // prefer Object.entries / Object.keys
|
|
1271
|
+
* ```
|
|
1272
|
+
*
|
|
1273
|
+
* Those two hazards come from the **destination** object's prototype, so no
|
|
1274
|
+
* option here can disarm them — copy with spread or `structuredClone` instead.
|
|
1275
|
+
*
|
|
1276
|
+
* What `{ nullPrototype: true }` does give you is a result that inherits
|
|
1277
|
+
* nothing: every object comes back with a `null` prototype, so reading
|
|
1278
|
+
* `x.__proto__`, `x.constructor` or `x.toString` yields config data or
|
|
1279
|
+
* `undefined` rather than something from `Object.prototype`, and code that
|
|
1280
|
+
* merges *into* this object cannot climb out of it. Keys are all still
|
|
1281
|
+
* present. The trade-off is the usual one for prototype-less objects: not
|
|
1282
|
+
* `instanceof Object`, and no `hasOwnProperty` of their own.
|
|
1283
|
+
*
|
|
1284
|
+
* Numbers follow the JS number model, so an integer wider than 2^53 rounds
|
|
1285
|
+
* here even when the config holds it exactly — read those with
|
|
1286
|
+
* {@link Config.getString} instead.
|
|
1287
|
+
*/
|
|
1288
|
+
toObject(opts) {
|
|
1289
|
+
return hoconToJs(this.root, opts?.nullPrototype === true);
|
|
1241
1290
|
}
|
|
1242
1291
|
/**
|
|
1243
1292
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
@@ -1349,16 +1398,25 @@ function scalarToJs(raw, valueType) {
|
|
|
1349
1398
|
return raw;
|
|
1350
1399
|
}
|
|
1351
1400
|
}
|
|
1352
|
-
function hoconToJs(v) {
|
|
1401
|
+
function hoconToJs(v, nullPrototype = false) {
|
|
1353
1402
|
switch (v.kind) {
|
|
1354
1403
|
case "scalar":
|
|
1355
1404
|
return scalarToJs(v.raw, v.valueType);
|
|
1356
1405
|
case "array":
|
|
1357
|
-
return v.items.map(hoconToJs);
|
|
1406
|
+
return v.items.map((item) => hoconToJs(item, nullPrototype));
|
|
1358
1407
|
case "object": {
|
|
1359
|
-
const
|
|
1360
|
-
|
|
1361
|
-
|
|
1408
|
+
const entries = Array.from(v.fields, ([k, val]) => [k, hoconToJs(val, nullPrototype)]);
|
|
1409
|
+
if (nullPrototype) {
|
|
1410
|
+
const obj = /* @__PURE__ */ Object.create(null);
|
|
1411
|
+
for (const [k, val] of entries) Object.defineProperty(obj, k, {
|
|
1412
|
+
value: val,
|
|
1413
|
+
writable: true,
|
|
1414
|
+
enumerable: true,
|
|
1415
|
+
configurable: true
|
|
1416
|
+
});
|
|
1417
|
+
return obj;
|
|
1418
|
+
}
|
|
1419
|
+
return Object.fromEntries(entries);
|
|
1362
1420
|
}
|
|
1363
1421
|
}
|
|
1364
1422
|
}
|
|
@@ -1447,6 +1505,8 @@ function fromMap(values, originDescription) {
|
|
|
1447
1505
|
const root = { kind: "object", fields };
|
|
1448
1506
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1449
1507
|
}
|
|
1508
|
+
var INT64_MAX = 9223372036854775807n;
|
|
1509
|
+
var INT64_MIN = -9223372036854775808n;
|
|
1450
1510
|
function coerceObject(obj, atPath) {
|
|
1451
1511
|
const fields = /* @__PURE__ */ new Map();
|
|
1452
1512
|
for (const [k, v] of Object.entries(obj)) {
|
|
@@ -1475,14 +1535,14 @@ function coerceValue(v, atPath) {
|
|
|
1475
1535
|
atPath
|
|
1476
1536
|
);
|
|
1477
1537
|
}
|
|
1478
|
-
return { kind: "scalar", raw: String(v), valueType: "number" };
|
|
1538
|
+
return { kind: "scalar", raw: Object.is(v, -0) ? "-0" : String(v), valueType: "number" };
|
|
1479
1539
|
}
|
|
1480
1540
|
case "boolean":
|
|
1481
1541
|
return { kind: "scalar", raw: v ? "true" : "false", valueType: "boolean" };
|
|
1482
1542
|
case "bigint": {
|
|
1483
|
-
if (v >
|
|
1543
|
+
if (v > INT64_MAX || v < INT64_MIN) {
|
|
1484
1544
|
throw new ConfigError(
|
|
1485
|
-
`fromMap:
|
|
1545
|
+
`fromMap: integer ${v} is out of int64 range (HOCON integers are int64; spec F0.5) at path "${atPath}"`,
|
|
1486
1546
|
atPath
|
|
1487
1547
|
);
|
|
1488
1548
|
}
|
|
@@ -1506,7 +1566,7 @@ function coerceValue(v, atPath) {
|
|
|
1506
1566
|
|
|
1507
1567
|
// src/adapters/toml.ts
|
|
1508
1568
|
function parseTomlConfig(input, originDescription) {
|
|
1509
|
-
const doc = parseToml(input);
|
|
1569
|
+
const doc = parseToml(stripBom(input));
|
|
1510
1570
|
return fromMap(convert(doc, ""), originDescription);
|
|
1511
1571
|
}
|
|
1512
1572
|
function convert(v, atPath) {
|
|
@@ -1515,11 +1575,11 @@ function convert(v, atPath) {
|
|
|
1515
1575
|
return v.toISOString().replace(/\.(\d*?)0+(?=Z?$)/, (_m, keep) => keep ? `.${keep}` : "");
|
|
1516
1576
|
}
|
|
1517
1577
|
if (v !== null && typeof v === "object") {
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1578
|
+
return Object.fromEntries(
|
|
1579
|
+
Object.entries(v).map(
|
|
1580
|
+
([k, e]) => [k, convert(e, atPath === "" ? k : `${atPath}.${k}`)]
|
|
1581
|
+
)
|
|
1582
|
+
);
|
|
1523
1583
|
}
|
|
1524
1584
|
if (typeof v === "number" && !Number.isFinite(v)) {
|
|
1525
1585
|
throw new ConfigError(
|
package/dist/adapters/yaml.cjs
CHANGED
|
@@ -551,8 +551,12 @@ function deepMergeHoconValues(base, overlay) {
|
|
|
551
551
|
// src/internal/resolver/include-loader.ts
|
|
552
552
|
var import_node_module = require("module");
|
|
553
553
|
var nodePath = __toESM(require("path"), 1);
|
|
554
|
-
var
|
|
555
|
-
|
|
554
|
+
var import_node_url = require("url");
|
|
555
|
+
|
|
556
|
+
// src/internal/strip-bom.ts
|
|
557
|
+
function stripBom(input) {
|
|
558
|
+
return input.charCodeAt(0) === 65279 ? input.slice(1) : input;
|
|
559
|
+
}
|
|
556
560
|
|
|
557
561
|
// src/value/numeric-array.ts
|
|
558
562
|
function numericObjectToArray(value) {
|
|
@@ -1141,10 +1145,10 @@ var Config = class _Config {
|
|
|
1141
1145
|
}
|
|
1142
1146
|
if (v.kind === "object") {
|
|
1143
1147
|
const converted = numericObjectToArray(v);
|
|
1144
|
-
if (converted !== null) return converted.map(hoconToJs);
|
|
1148
|
+
if (converted !== null) return converted.map((item) => hoconToJs(item));
|
|
1145
1149
|
}
|
|
1146
1150
|
if (v.kind !== "array") throw new ConfigError(`expected array at ${path}`, path);
|
|
1147
|
-
return v.items.map(hoconToJs);
|
|
1151
|
+
return v.items.map((item) => hoconToJs(item));
|
|
1148
1152
|
}
|
|
1149
1153
|
has(path) {
|
|
1150
1154
|
return this.lookupNode(path) !== void 0;
|
|
@@ -1272,8 +1276,52 @@ var Config = class _Config {
|
|
|
1272
1276
|
originDescription: this._originDescription
|
|
1273
1277
|
});
|
|
1274
1278
|
}
|
|
1275
|
-
|
|
1276
|
-
|
|
1279
|
+
/**
|
|
1280
|
+
* The whole config as plain JS data: objects, arrays, strings, numbers,
|
|
1281
|
+
* booleans and `null`.
|
|
1282
|
+
*
|
|
1283
|
+
* Keys are reproduced exactly as the config carries them, `__proto__`,
|
|
1284
|
+
* `constructor` and `prototype` included: each is defined as an **own data
|
|
1285
|
+
* property**, so the returned object's prototype is always
|
|
1286
|
+
* `Object.prototype`, and this call writes nothing to the global one.
|
|
1287
|
+
*
|
|
1288
|
+
* ### Passing the result to other code
|
|
1289
|
+
*
|
|
1290
|
+
* A config file — especially a `.properties` file or an env namespace you
|
|
1291
|
+
* merged in — can therefore hand you an own `__proto__` key, and what happens
|
|
1292
|
+
* next depends entirely on how the consumer copies it:
|
|
1293
|
+
*
|
|
1294
|
+
* ```ts
|
|
1295
|
+
* const data = cfg.toObject()
|
|
1296
|
+
* { ...data } // safe — own properties are copied as data
|
|
1297
|
+
* structuredClone(data) // safe
|
|
1298
|
+
* Object.assign({}, data) // NOT safe — [[Set]] on the {} target hits
|
|
1299
|
+
* // Object.prototype's __proto__ setter: the key
|
|
1300
|
+
* // vanishes and config data becomes the result's
|
|
1301
|
+
* // prototype
|
|
1302
|
+
* deepMerge({}, data) // NOT safe — a naive recursive merge reads
|
|
1303
|
+
* // target['__proto__'], gets Object.prototype,
|
|
1304
|
+
* // and writes to it: global pollution
|
|
1305
|
+
* for (const k in data) … // prefer Object.entries / Object.keys
|
|
1306
|
+
* ```
|
|
1307
|
+
*
|
|
1308
|
+
* Those two hazards come from the **destination** object's prototype, so no
|
|
1309
|
+
* option here can disarm them — copy with spread or `structuredClone` instead.
|
|
1310
|
+
*
|
|
1311
|
+
* What `{ nullPrototype: true }` does give you is a result that inherits
|
|
1312
|
+
* nothing: every object comes back with a `null` prototype, so reading
|
|
1313
|
+
* `x.__proto__`, `x.constructor` or `x.toString` yields config data or
|
|
1314
|
+
* `undefined` rather than something from `Object.prototype`, and code that
|
|
1315
|
+
* merges *into* this object cannot climb out of it. Keys are all still
|
|
1316
|
+
* present. The trade-off is the usual one for prototype-less objects: not
|
|
1317
|
+
* `instanceof Object`, and no `hasOwnProperty` of their own.
|
|
1318
|
+
*
|
|
1319
|
+
* Numbers follow the JS number model, so an integer wider than 2^53 rounds
|
|
1320
|
+
* here even when the config holds it exactly — read those with
|
|
1321
|
+
* {@link Config.getString} instead.
|
|
1322
|
+
*/
|
|
1323
|
+
toObject(opts) {
|
|
1324
|
+
return hoconToJs(this.root, opts?.nullPrototype === true);
|
|
1277
1325
|
}
|
|
1278
1326
|
/**
|
|
1279
1327
|
* @internal Test-only: renders this resolved Config's value tree as canonical
|
|
@@ -1385,16 +1433,25 @@ function scalarToJs(raw, valueType) {
|
|
|
1385
1433
|
return raw;
|
|
1386
1434
|
}
|
|
1387
1435
|
}
|
|
1388
|
-
function hoconToJs(v) {
|
|
1436
|
+
function hoconToJs(v, nullPrototype = false) {
|
|
1389
1437
|
switch (v.kind) {
|
|
1390
1438
|
case "scalar":
|
|
1391
1439
|
return scalarToJs(v.raw, v.valueType);
|
|
1392
1440
|
case "array":
|
|
1393
|
-
return v.items.map(hoconToJs);
|
|
1441
|
+
return v.items.map((item) => hoconToJs(item, nullPrototype));
|
|
1394
1442
|
case "object": {
|
|
1395
|
-
const
|
|
1396
|
-
|
|
1397
|
-
|
|
1443
|
+
const entries = Array.from(v.fields, ([k, val]) => [k, hoconToJs(val, nullPrototype)]);
|
|
1444
|
+
if (nullPrototype) {
|
|
1445
|
+
const obj = /* @__PURE__ */ Object.create(null);
|
|
1446
|
+
for (const [k, val] of entries) Object.defineProperty(obj, k, {
|
|
1447
|
+
value: val,
|
|
1448
|
+
writable: true,
|
|
1449
|
+
enumerable: true,
|
|
1450
|
+
configurable: true
|
|
1451
|
+
});
|
|
1452
|
+
return obj;
|
|
1453
|
+
}
|
|
1454
|
+
return Object.fromEntries(entries);
|
|
1398
1455
|
}
|
|
1399
1456
|
}
|
|
1400
1457
|
}
|
|
@@ -1483,6 +1540,8 @@ function fromMap(values, originDescription) {
|
|
|
1483
1540
|
const root = { kind: "object", fields };
|
|
1484
1541
|
return Config._fromResolvedValue(root, { originDescription });
|
|
1485
1542
|
}
|
|
1543
|
+
var INT64_MAX = 9223372036854775807n;
|
|
1544
|
+
var INT64_MIN = -9223372036854775808n;
|
|
1486
1545
|
function coerceObject(obj, atPath) {
|
|
1487
1546
|
const fields = /* @__PURE__ */ new Map();
|
|
1488
1547
|
for (const [k, v] of Object.entries(obj)) {
|
|
@@ -1511,14 +1570,14 @@ function coerceValue(v, atPath) {
|
|
|
1511
1570
|
atPath
|
|
1512
1571
|
);
|
|
1513
1572
|
}
|
|
1514
|
-
return { kind: "scalar", raw: String(v), valueType: "number" };
|
|
1573
|
+
return { kind: "scalar", raw: Object.is(v, -0) ? "-0" : String(v), valueType: "number" };
|
|
1515
1574
|
}
|
|
1516
1575
|
case "boolean":
|
|
1517
1576
|
return { kind: "scalar", raw: v ? "true" : "false", valueType: "boolean" };
|
|
1518
1577
|
case "bigint": {
|
|
1519
|
-
if (v >
|
|
1578
|
+
if (v > INT64_MAX || v < INT64_MIN) {
|
|
1520
1579
|
throw new ConfigError(
|
|
1521
|
-
`fromMap:
|
|
1580
|
+
`fromMap: integer ${v} is out of int64 range (HOCON integers are int64; spec F0.5) at path "${atPath}"`,
|
|
1522
1581
|
atPath
|
|
1523
1582
|
);
|
|
1524
1583
|
}
|
|
@@ -1542,7 +1601,7 @@ function coerceValue(v, atPath) {
|
|
|
1542
1601
|
|
|
1543
1602
|
// src/adapters/yaml.ts
|
|
1544
1603
|
function parseYaml(input, originDescription) {
|
|
1545
|
-
const docs = import_yaml.default.parseAllDocuments(input, { version: "1.2", merge: true });
|
|
1604
|
+
const docs = import_yaml.default.parseAllDocuments(stripBom(input), { version: "1.2", merge: true, intAsBigInt: true });
|
|
1546
1605
|
if (docs.length > 1) {
|
|
1547
1606
|
throw new ConfigError(
|
|
1548
1607
|
"yaml: multi-document streams are not supported (spec F5.7); a config is one document",
|
|
@@ -1573,7 +1632,7 @@ function convert(v, atPath) {
|
|
|
1573
1632
|
return v.toISOString();
|
|
1574
1633
|
}
|
|
1575
1634
|
if (v instanceof Map) {
|
|
1576
|
-
const
|
|
1635
|
+
const entries = [];
|
|
1577
1636
|
for (const [k, e] of v) {
|
|
1578
1637
|
if (k !== null && typeof k === "object") {
|
|
1579
1638
|
throw new ConfigError(
|
|
@@ -1581,19 +1640,20 @@ function convert(v, atPath) {
|
|
|
1581
1640
|
atPath
|
|
1582
1641
|
);
|
|
1583
1642
|
}
|
|
1584
|
-
|
|
1643
|
+
const key = String(k);
|
|
1644
|
+
entries.push([key, convert(e, atPath === "" ? key : `${atPath}.${key}`)]);
|
|
1585
1645
|
}
|
|
1586
|
-
return
|
|
1646
|
+
return Object.fromEntries(entries);
|
|
1587
1647
|
}
|
|
1588
1648
|
if (v instanceof Uint8Array) {
|
|
1589
|
-
return
|
|
1649
|
+
return bytesToBase64(v);
|
|
1590
1650
|
}
|
|
1591
1651
|
if (v !== null && typeof v === "object") {
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1652
|
+
return Object.fromEntries(
|
|
1653
|
+
Object.entries(v).map(
|
|
1654
|
+
([k, e]) => [k, convert(e, atPath === "" ? k : `${atPath}.${k}`)]
|
|
1655
|
+
)
|
|
1656
|
+
);
|
|
1597
1657
|
}
|
|
1598
1658
|
if (typeof v === "number" && !Number.isFinite(v)) {
|
|
1599
1659
|
throw new ConfigError(
|
|
@@ -1601,8 +1661,24 @@ function convert(v, atPath) {
|
|
|
1601
1661
|
atPath
|
|
1602
1662
|
);
|
|
1603
1663
|
}
|
|
1664
|
+
if (typeof v === "bigint") {
|
|
1665
|
+
return isSafeIntegerBigInt(v) ? Number(v) : v;
|
|
1666
|
+
}
|
|
1604
1667
|
return v;
|
|
1605
1668
|
}
|
|
1669
|
+
function bytesToBase64(bytes) {
|
|
1670
|
+
const CHUNK = 32768;
|
|
1671
|
+
let binary = "";
|
|
1672
|
+
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
1673
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
|
|
1674
|
+
}
|
|
1675
|
+
return btoa(binary);
|
|
1676
|
+
}
|
|
1677
|
+
var MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);
|
|
1678
|
+
var MIN_SAFE = BigInt(Number.MIN_SAFE_INTEGER);
|
|
1679
|
+
function isSafeIntegerBigInt(v) {
|
|
1680
|
+
return v <= MAX_SAFE && v >= MIN_SAFE;
|
|
1681
|
+
}
|
|
1606
1682
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1607
1683
|
0 && (module.exports = {
|
|
1608
1684
|
fromYamlValue,
|
package/dist/adapters/yaml.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 YAML document as HOCON config.
|
|
@@ -23,6 +23,12 @@ import { C as Config } from '../config-PdhVgeLS.cjs';
|
|
|
23
23
|
* const cfg = fromYamlValue(jsy.load(src), 'their-file.yml')
|
|
24
24
|
* ```
|
|
25
25
|
*
|
|
26
|
+
* Integers are ingested losslessly (F0.5): the document is decoded with
|
|
27
|
+
* `intAsBigInt`, so a literal too wide for a JS `number` keeps its digits —
|
|
28
|
+
* `getString` returns them exactly — and one outside int64 is refused rather
|
|
29
|
+
* than rounded. `getNumber` and `toObject` still apply the JS number model, so
|
|
30
|
+
* read large identifiers with `getString`.
|
|
31
|
+
*
|
|
26
32
|
* See docs/specs/format-ingestion-mapping.md items F5.x in the hocon scope.
|
|
27
33
|
*/
|
|
28
34
|
declare function parseYaml(input: string, originDescription?: string): Config;
|
|
@@ -36,7 +42,9 @@ declare function parseYaml(input: string, originDescription?: string): Config;
|
|
|
36
42
|
* only the default one: a `Map` (eemeli with `mapAsMap`) has its scalar keys
|
|
37
43
|
* stringified per F5.3, a `Date` (js-yaml 4 timestamps) becomes its ISO string
|
|
38
44
|
* — the same reasoning as F4.2 for TOML dates — and a `Uint8Array` becomes
|
|
39
|
-
* base64 (F5.5).
|
|
45
|
+
* base64 (F5.5), at any size. A `bigint` (a library decoding integers widely)
|
|
46
|
+
* narrows to a number where a double is exact and otherwise keeps its digits,
|
|
47
|
+
* bounded by int64 (F0.5).
|
|
40
48
|
*/
|
|
41
49
|
declare function fromYamlValue(value: unknown, originDescription?: string): Config;
|
|
42
50
|
|
package/dist/adapters/yaml.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 YAML document as HOCON config.
|
|
@@ -23,6 +23,12 @@ import { C as Config } from '../config-PdhVgeLS.js';
|
|
|
23
23
|
* const cfg = fromYamlValue(jsy.load(src), 'their-file.yml')
|
|
24
24
|
* ```
|
|
25
25
|
*
|
|
26
|
+
* Integers are ingested losslessly (F0.5): the document is decoded with
|
|
27
|
+
* `intAsBigInt`, so a literal too wide for a JS `number` keeps its digits —
|
|
28
|
+
* `getString` returns them exactly — and one outside int64 is refused rather
|
|
29
|
+
* than rounded. `getNumber` and `toObject` still apply the JS number model, so
|
|
30
|
+
* read large identifiers with `getString`.
|
|
31
|
+
*
|
|
26
32
|
* See docs/specs/format-ingestion-mapping.md items F5.x in the hocon scope.
|
|
27
33
|
*/
|
|
28
34
|
declare function parseYaml(input: string, originDescription?: string): Config;
|
|
@@ -36,7 +42,9 @@ declare function parseYaml(input: string, originDescription?: string): Config;
|
|
|
36
42
|
* only the default one: a `Map` (eemeli with `mapAsMap`) has its scalar keys
|
|
37
43
|
* stringified per F5.3, a `Date` (js-yaml 4 timestamps) becomes its ISO string
|
|
38
44
|
* — the same reasoning as F4.2 for TOML dates — and a `Uint8Array` becomes
|
|
39
|
-
* base64 (F5.5).
|
|
45
|
+
* base64 (F5.5), at any size. A `bigint` (a library decoding integers widely)
|
|
46
|
+
* narrows to a number where a double is exact and otherwise keeps its digits,
|
|
47
|
+
* bounded by int64 (F0.5).
|
|
40
48
|
*/
|
|
41
49
|
declare function fromYamlValue(value: unknown, originDescription?: string): Config;
|
|
42
50
|
|