smol-toml 1.3.3 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -3
- package/dist/date.js +3 -1
- package/dist/extract.d.ts +3 -2
- package/dist/extract.js +6 -6
- package/dist/index.cjs +50 -54
- package/dist/index.d.ts +4 -1
- package/dist/parse.d.ts +10 -4
- package/dist/parse.js +2 -3
- package/dist/primitive.d.ts +2 -1
- package/dist/primitive.js +27 -21
- package/dist/stringify.d.ts +2 -1
- package/dist/stringify.js +20 -19
- package/dist/struct.d.ts +4 -3
- package/dist/struct.js +17 -25
- package/dist/util.d.ts +9 -3
- package/dist/util.js +1 -4
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -16,6 +16,9 @@ parser didn't feel too out of place.
|
|
|
16
16
|
|
|
17
17
|
*[insert xkcd 927]*
|
|
18
18
|
|
|
19
|
+
Nowadays, smol-toml is the most downloaded TOML parser on npm thanks to its quality. From frameworks to tooling, it
|
|
20
|
+
has been battle-tested and is actively used in production systems.
|
|
21
|
+
|
|
19
22
|
smol-toml passes most of the tests from the [`toml-test` suite](https://github.com/toml-lang/toml-test); use the
|
|
20
23
|
`run-toml-test.bash` script to run the tests. Due to the nature of JavaScript and the limits of the language,
|
|
21
24
|
it doesn't pass certain tests, namely:
|
|
@@ -24,7 +27,9 @@ it doesn't pass certain tests, namely:
|
|
|
24
27
|
- Certain invalid dates are not rejected
|
|
25
28
|
- For instance, `2023-02-30` would be accepted and parsed as `2023-03-02`. While additional checks could be performed
|
|
26
29
|
to reject these, they've not been added for performance reasons.
|
|
27
|
-
|
|
30
|
+
|
|
31
|
+
Please also note that by default, the behavior regarding integers doesn't preserve type information, nor does it allow
|
|
32
|
+
deserializing integers larger than 53 bits. See [Integers](#integers).
|
|
28
33
|
|
|
29
34
|
You can see a list of all tests smol-toml fails (and the reason why it fails these) in the list of skipped tests in
|
|
30
35
|
`run-toml-test.bash`. Note that some failures are *not* specification violations per-se. For instance, the TOML spec
|
|
@@ -59,11 +64,42 @@ A few notes on the `stringify` function:
|
|
|
59
64
|
- `undefined` and `null` values on objects are ignored (does not produce a key/value).
|
|
60
65
|
- `undefined` and `null` values in arrays are **rejected**.
|
|
61
66
|
- Functions, classes and symbols are **rejected**.
|
|
62
|
-
- floats will be serialized as integers if they don't have a decimal part.
|
|
67
|
+
- By default, floats will be serialized as integers if they don't have a decimal part. See [Integers](#integers)
|
|
63
68
|
- `stringify(parse('a = 1.0')) === 'a = 1'`
|
|
64
69
|
- JS `Date` will be serialized as Offset Date Time
|
|
65
70
|
- Use the [`TomlDate` object](#dates) for representing other types.
|
|
66
71
|
|
|
72
|
+
### Integers
|
|
73
|
+
When parsing, both integers and floats are read as plain JavaScript numbers, which essentially are floats. This means
|
|
74
|
+
loss of type information, and makes it impossible to safely represent integers beyond 53 bits.
|
|
75
|
+
|
|
76
|
+
When serializing, numbers without a decimal part are serialized as integers. This allows in most cases to preserve
|
|
77
|
+
whether a number is an integer or not, but fails to preserve type information for numbers like `1.0`.
|
|
78
|
+
|
|
79
|
+
#### Enabling BigInt support and type preservation
|
|
80
|
+
To parse integers beyond 53 bits, it's possible to tell the parser to return all integers as BigInt. This will
|
|
81
|
+
therefore preserve the type information at the cost of using a slightly more expensive container.
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
import { parse } from 'smol-toml'
|
|
85
|
+
|
|
86
|
+
const doc = '...'
|
|
87
|
+
const parsed = parse(doc, { integersAsBigInt: true })
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
If you want to keep numbers for integers that can safely be represented as a JavaScript number, you can pass
|
|
91
|
+
`"asNeeded"` instead.
|
|
92
|
+
|
|
93
|
+
To get end-to-end type preservation, you can tell the serializer to always treat numbers as floating point numbers.
|
|
94
|
+
Then, only BigInts will be serialized as integers and numbers without a decimal part will still be serialized as float.
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
import { stringify } from 'smol-toml'
|
|
98
|
+
|
|
99
|
+
const obj = { ... }
|
|
100
|
+
const toml = stringify(obj, { numbersAsFloat: true })
|
|
101
|
+
```
|
|
102
|
+
|
|
67
103
|
### Dates
|
|
68
104
|
`smol-toml` uses an extended `Date` object to represent all types of TOML Dates. In the future, `smol-toml` will use
|
|
69
105
|
objects from the Temporal proposal, but for now we're stuck with the legacy Date object.
|
|
@@ -107,6 +143,10 @@ const localTime = TomlDate.wrapAsLocalTime(jsDate)
|
|
|
107
143
|
```
|
|
108
144
|
|
|
109
145
|
## Performance
|
|
146
|
+
> [!NOTE]
|
|
147
|
+
> These benchmarks are starting to get a bit old. They will be updated in the (hopefully near) future to better
|
|
148
|
+
> reflect numbers of the latest version of smol-toml on the latest version of Node.js.
|
|
149
|
+
|
|
110
150
|
A note on these performance numbers: in some highly synthetic tests, other parsers such as `fast-toml` greatly
|
|
111
151
|
outperform other parsers, mostly due to their lack of compliance with the spec. For example, to parse a string,
|
|
112
152
|
`fast-toml` skips the entire string while `smol-toml` does validate the string, costing a fair share of performance.
|
|
@@ -187,7 +227,7 @@ I initially tried to benchmark `toml-nodejs`, but the 0.3.0 package is broken.
|
|
|
187
227
|
I initially reported this to the library author, but the author decided to
|
|
188
228
|
- a) advise to use a custom loader (via *experimental* flag) to circumvent the invalid imports.
|
|
189
229
|
- Said flag, `--experimental-specifier-resolution`, has been removed in Node v20.
|
|
190
|
-
- b) [delete the issue](https://github.com/huan231/toml-nodejs/issues/12) when pointed out links to the
|
|
230
|
+
- b) [delete the issue](https://github.com/huan231/toml-nodejs/issues/12) when pointed out links to the Node.js
|
|
191
231
|
documentation about the flag removal and standard resolution algorithm.
|
|
192
232
|
|
|
193
233
|
For the reference anyway, `toml-nodejs` (with proper imports) is ~8x slower on both parse benchmark with:
|
package/dist/date.js
CHANGED
|
@@ -42,7 +42,9 @@ export class TomlDate extends Date {
|
|
|
42
42
|
date = `0000-01-01T${date}`;
|
|
43
43
|
}
|
|
44
44
|
hasTime = !!match[2];
|
|
45
|
-
//
|
|
45
|
+
// Make sure to use T instead of a space. Breaks in case of extreme values otherwise.
|
|
46
|
+
hasTime && date[10] === ' ' && (date = date.replace(' ', 'T'));
|
|
47
|
+
// Do not allow rollover hours.
|
|
46
48
|
if (match[2] && +match[2] > 23) {
|
|
47
49
|
date = '';
|
|
48
50
|
}
|
package/dist/extract.d.ts
CHANGED
|
@@ -25,5 +25,6 @@
|
|
|
25
25
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
26
26
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
|
-
import { type
|
|
29
|
-
|
|
28
|
+
import { type IntegersAsBigInt } from './primitive.js';
|
|
29
|
+
import { type TomlValue } from './util.js';
|
|
30
|
+
export declare function extractValue(str: string, ptr: number, end: string | undefined, depth: number, integersAsBigInt: IntegersAsBigInt): [TomlValue, number];
|
package/dist/extract.js
CHANGED
|
@@ -50,7 +50,7 @@ function sliceAndTrimEndOf(str, startPtr, endPtr, allowNewLines) {
|
|
|
50
50
|
}
|
|
51
51
|
return [trimmed, commentIdx];
|
|
52
52
|
}
|
|
53
|
-
export function extractValue(str, ptr, end, depth
|
|
53
|
+
export function extractValue(str, ptr, end, depth, integersAsBigInt) {
|
|
54
54
|
if (depth === 0) {
|
|
55
55
|
throw new TomlError('document contains excessively nested structures. aborting.', {
|
|
56
56
|
toml: str,
|
|
@@ -60,10 +60,10 @@ export function extractValue(str, ptr, end, depth = -1) {
|
|
|
60
60
|
let c = str[ptr];
|
|
61
61
|
if (c === '[' || c === '{') {
|
|
62
62
|
let [value, endPtr] = c === '['
|
|
63
|
-
? parseArray(str, ptr, depth)
|
|
64
|
-
: parseInlineTable(str, ptr, depth);
|
|
65
|
-
let newPtr = skipUntil(str, endPtr, ',', end);
|
|
66
|
-
if (end === '}') {
|
|
63
|
+
? parseArray(str, ptr, depth, integersAsBigInt)
|
|
64
|
+
: parseInlineTable(str, ptr, depth, integersAsBigInt);
|
|
65
|
+
let newPtr = end ? skipUntil(str, endPtr, ',', end) : endPtr;
|
|
66
|
+
if (endPtr - newPtr && end === '}') {
|
|
67
67
|
let nextNewLine = indexOfNewline(str, endPtr, newPtr);
|
|
68
68
|
if (nextNewLine > -1) {
|
|
69
69
|
throw new TomlError('newlines are not allowed in inline tables', {
|
|
@@ -103,7 +103,7 @@ export function extractValue(str, ptr, end, depth = -1) {
|
|
|
103
103
|
endPtr += +(str[endPtr] === ',');
|
|
104
104
|
}
|
|
105
105
|
return [
|
|
106
|
-
parseValue(slice[0], str, ptr),
|
|
106
|
+
parseValue(slice[0], str, ptr, integersAsBigInt),
|
|
107
107
|
endPtr,
|
|
108
108
|
];
|
|
109
109
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -108,9 +108,7 @@ function skipUntil(str, ptr, sep, end, banNewLines = false) {
|
|
|
108
108
|
i = indexOfNewline(str, i);
|
|
109
109
|
} else if (c === sep) {
|
|
110
110
|
return i + 1;
|
|
111
|
-
} else if (c === end) {
|
|
112
|
-
return i;
|
|
113
|
-
} else if (banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
|
|
111
|
+
} else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
|
|
114
112
|
return i;
|
|
115
113
|
}
|
|
116
114
|
}
|
|
@@ -156,6 +154,7 @@ var TomlDate = class _TomlDate extends Date {
|
|
|
156
154
|
date = `0000-01-01T${date}`;
|
|
157
155
|
}
|
|
158
156
|
hasTime = !!match[2];
|
|
157
|
+
hasTime && date[10] === " " && (date = date.replace(" ", "T"));
|
|
159
158
|
if (match[2] && +match[2] > 23) {
|
|
160
159
|
date = "";
|
|
161
160
|
} else {
|
|
@@ -316,7 +315,7 @@ function parseString(str, ptr = 0, endPtr = str.length) {
|
|
|
316
315
|
}
|
|
317
316
|
return parsed + str.slice(sliceStart, endPtr - 1);
|
|
318
317
|
}
|
|
319
|
-
function parseValue(value, toml, ptr) {
|
|
318
|
+
function parseValue(value, toml, ptr, integersAsBigInt) {
|
|
320
319
|
if (value === "true")
|
|
321
320
|
return true;
|
|
322
321
|
if (value === "false")
|
|
@@ -328,31 +327,36 @@ function parseValue(value, toml, ptr) {
|
|
|
328
327
|
if (value === "nan" || value === "+nan" || value === "-nan")
|
|
329
328
|
return NaN;
|
|
330
329
|
if (value === "-0")
|
|
331
|
-
return 0;
|
|
332
|
-
let isInt;
|
|
333
|
-
if (
|
|
330
|
+
return integersAsBigInt ? 0n : 0;
|
|
331
|
+
let isInt = INT_REGEX.test(value);
|
|
332
|
+
if (isInt || FLOAT_REGEX.test(value)) {
|
|
334
333
|
if (LEADING_ZERO.test(value)) {
|
|
335
334
|
throw new TomlError("leading zeroes are not allowed", {
|
|
336
335
|
toml,
|
|
337
336
|
ptr
|
|
338
337
|
});
|
|
339
338
|
}
|
|
340
|
-
|
|
339
|
+
value = value.replace(/_/g, "");
|
|
340
|
+
let numeric = +value;
|
|
341
341
|
if (isNaN(numeric)) {
|
|
342
342
|
throw new TomlError("invalid number", {
|
|
343
343
|
toml,
|
|
344
344
|
ptr
|
|
345
345
|
});
|
|
346
346
|
}
|
|
347
|
-
if (isInt
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
347
|
+
if (isInt) {
|
|
348
|
+
if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) {
|
|
349
|
+
throw new TomlError("integer value cannot be represented losslessly", {
|
|
350
|
+
toml,
|
|
351
|
+
ptr
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
if (isInt || integersAsBigInt)
|
|
355
|
+
numeric = BigInt(value);
|
|
352
356
|
}
|
|
353
357
|
return numeric;
|
|
354
358
|
}
|
|
355
|
-
|
|
359
|
+
const date = new TomlDate(value);
|
|
356
360
|
if (!date.isValid()) {
|
|
357
361
|
throw new TomlError("invalid value", {
|
|
358
362
|
toml,
|
|
@@ -382,7 +386,7 @@ function sliceAndTrimEndOf(str, startPtr, endPtr, allowNewLines) {
|
|
|
382
386
|
}
|
|
383
387
|
return [trimmed, commentIdx];
|
|
384
388
|
}
|
|
385
|
-
function extractValue(str, ptr, end, depth
|
|
389
|
+
function extractValue(str, ptr, end, depth, integersAsBigInt) {
|
|
386
390
|
if (depth === 0) {
|
|
387
391
|
throw new TomlError("document contains excessively nested structures. aborting.", {
|
|
388
392
|
toml: str,
|
|
@@ -391,9 +395,9 @@ function extractValue(str, ptr, end, depth = -1) {
|
|
|
391
395
|
}
|
|
392
396
|
let c = str[ptr];
|
|
393
397
|
if (c === "[" || c === "{") {
|
|
394
|
-
let [value, endPtr2] = c === "[" ? parseArray(str, ptr, depth) : parseInlineTable(str, ptr, depth);
|
|
395
|
-
let newPtr = skipUntil(str, endPtr2, ",", end);
|
|
396
|
-
if (end === "}") {
|
|
398
|
+
let [value, endPtr2] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt);
|
|
399
|
+
let newPtr = end ? skipUntil(str, endPtr2, ",", end) : endPtr2;
|
|
400
|
+
if (endPtr2 - newPtr && end === "}") {
|
|
397
401
|
let nextNewLine = indexOfNewline(str, endPtr2, newPtr);
|
|
398
402
|
if (nextNewLine > -1) {
|
|
399
403
|
throw new TomlError("newlines are not allowed in inline tables", {
|
|
@@ -433,7 +437,7 @@ function extractValue(str, ptr, end, depth = -1) {
|
|
|
433
437
|
endPtr += +(str[endPtr] === ",");
|
|
434
438
|
}
|
|
435
439
|
return [
|
|
436
|
-
parseValue(slice[0], str, ptr),
|
|
440
|
+
parseValue(slice[0], str, ptr, integersAsBigInt),
|
|
437
441
|
endPtr
|
|
438
442
|
];
|
|
439
443
|
}
|
|
@@ -507,28 +511,20 @@ function parseKey(str, ptr, end = "=") {
|
|
|
507
511
|
} while (dot + 1 && dot < endPtr);
|
|
508
512
|
return [parsed, skipVoid(str, endPtr + 1, true, true)];
|
|
509
513
|
}
|
|
510
|
-
function parseInlineTable(str, ptr, depth
|
|
514
|
+
function parseInlineTable(str, ptr, depth, integersAsBigInt) {
|
|
511
515
|
let res = {};
|
|
512
516
|
let seen = /* @__PURE__ */ new Set();
|
|
513
517
|
let c;
|
|
514
518
|
let comma = 0;
|
|
515
519
|
ptr++;
|
|
516
520
|
while ((c = str[ptr++]) !== "}" && c) {
|
|
521
|
+
let err = { toml: str, ptr: ptr - 1 };
|
|
517
522
|
if (c === "\n") {
|
|
518
|
-
throw new TomlError("newlines are not allowed in inline tables",
|
|
519
|
-
toml: str,
|
|
520
|
-
ptr: ptr - 1
|
|
521
|
-
});
|
|
523
|
+
throw new TomlError("newlines are not allowed in inline tables", err);
|
|
522
524
|
} else if (c === "#") {
|
|
523
|
-
throw new TomlError("inline tables cannot contain comments",
|
|
524
|
-
toml: str,
|
|
525
|
-
ptr: ptr - 1
|
|
526
|
-
});
|
|
525
|
+
throw new TomlError("inline tables cannot contain comments", err);
|
|
527
526
|
} else if (c === ",") {
|
|
528
|
-
throw new TomlError("expected key-value, found comma",
|
|
529
|
-
toml: str,
|
|
530
|
-
ptr: ptr - 1
|
|
531
|
-
});
|
|
527
|
+
throw new TomlError("expected key-value, found comma", err);
|
|
532
528
|
} else if (c !== " " && c !== " ") {
|
|
533
529
|
let k;
|
|
534
530
|
let t = res;
|
|
@@ -554,7 +550,7 @@ function parseInlineTable(str, ptr, depth = -1) {
|
|
|
554
550
|
ptr
|
|
555
551
|
});
|
|
556
552
|
}
|
|
557
|
-
let [value, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1);
|
|
553
|
+
let [value, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1, integersAsBigInt);
|
|
558
554
|
seen.add(value);
|
|
559
555
|
t[k] = value;
|
|
560
556
|
ptr = valueEndPtr;
|
|
@@ -575,7 +571,7 @@ function parseInlineTable(str, ptr, depth = -1) {
|
|
|
575
571
|
}
|
|
576
572
|
return [res, ptr];
|
|
577
573
|
}
|
|
578
|
-
function parseArray(str, ptr, depth
|
|
574
|
+
function parseArray(str, ptr, depth, integersAsBigInt) {
|
|
579
575
|
let res = [];
|
|
580
576
|
let c;
|
|
581
577
|
ptr++;
|
|
@@ -588,7 +584,7 @@ function parseArray(str, ptr, depth = -1) {
|
|
|
588
584
|
} else if (c === "#")
|
|
589
585
|
ptr = skipComment(str, ptr);
|
|
590
586
|
else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
|
|
591
|
-
let e = extractValue(str, ptr - 1, "]", depth - 1);
|
|
587
|
+
let e = extractValue(str, ptr - 1, "]", depth - 1, integersAsBigInt);
|
|
592
588
|
res.push(e[0]);
|
|
593
589
|
ptr = e[1];
|
|
594
590
|
}
|
|
@@ -662,8 +658,7 @@ function peekTable(key, table, meta, type) {
|
|
|
662
658
|
}
|
|
663
659
|
return [k, t, state.c];
|
|
664
660
|
}
|
|
665
|
-
function parse(toml,
|
|
666
|
-
let maxDepth = opts?.maxDepth ?? 1e3;
|
|
661
|
+
function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
|
|
667
662
|
let res = {};
|
|
668
663
|
let meta = {};
|
|
669
664
|
let tbl = res;
|
|
@@ -712,7 +707,7 @@ function parse(toml, opts) {
|
|
|
712
707
|
ptr
|
|
713
708
|
});
|
|
714
709
|
}
|
|
715
|
-
let v = extractValue(toml, k[1], void 0, maxDepth);
|
|
710
|
+
let v = extractValue(toml, k[1], void 0, maxDepth, integersAsBigInt);
|
|
716
711
|
p[1][p[0]] = v[0];
|
|
717
712
|
ptr = v[1];
|
|
718
713
|
}
|
|
@@ -750,7 +745,7 @@ function isArrayOfTables(obj) {
|
|
|
750
745
|
function formatString(s) {
|
|
751
746
|
return JSON.stringify(s).replace(/\x7f/g, "\\u007f");
|
|
752
747
|
}
|
|
753
|
-
function stringifyValue(val, type, depth) {
|
|
748
|
+
function stringifyValue(val, type, depth, numberAsFloat) {
|
|
754
749
|
if (depth === 0) {
|
|
755
750
|
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
756
751
|
}
|
|
@@ -761,6 +756,8 @@ function stringifyValue(val, type, depth) {
|
|
|
761
756
|
return "inf";
|
|
762
757
|
if (val === -Infinity)
|
|
763
758
|
return "-inf";
|
|
759
|
+
if (numberAsFloat && Number.isInteger(val))
|
|
760
|
+
return val.toFixed(1);
|
|
764
761
|
return val.toString();
|
|
765
762
|
}
|
|
766
763
|
if (type === "bigint" || type === "boolean") {
|
|
@@ -776,13 +773,13 @@ function stringifyValue(val, type, depth) {
|
|
|
776
773
|
return val.toISOString();
|
|
777
774
|
}
|
|
778
775
|
if (type === "object") {
|
|
779
|
-
return stringifyInlineTable(val, depth);
|
|
776
|
+
return stringifyInlineTable(val, depth, numberAsFloat);
|
|
780
777
|
}
|
|
781
778
|
if (type === "array") {
|
|
782
|
-
return stringifyArray(val, depth);
|
|
779
|
+
return stringifyArray(val, depth, numberAsFloat);
|
|
783
780
|
}
|
|
784
781
|
}
|
|
785
|
-
function stringifyInlineTable(obj, depth) {
|
|
782
|
+
function stringifyInlineTable(obj, depth, numberAsFloat) {
|
|
786
783
|
let keys = Object.keys(obj);
|
|
787
784
|
if (keys.length === 0)
|
|
788
785
|
return "{}";
|
|
@@ -793,11 +790,11 @@ function stringifyInlineTable(obj, depth) {
|
|
|
793
790
|
res += ", ";
|
|
794
791
|
res += BARE_KEY.test(k) ? k : formatString(k);
|
|
795
792
|
res += " = ";
|
|
796
|
-
res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1);
|
|
793
|
+
res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat);
|
|
797
794
|
}
|
|
798
795
|
return res + " }";
|
|
799
796
|
}
|
|
800
|
-
function stringifyArray(array, depth) {
|
|
797
|
+
function stringifyArray(array, depth, numberAsFloat) {
|
|
801
798
|
if (array.length === 0)
|
|
802
799
|
return "[]";
|
|
803
800
|
let res = "[ ";
|
|
@@ -807,11 +804,11 @@ function stringifyArray(array, depth) {
|
|
|
807
804
|
if (array[i] === null || array[i] === void 0) {
|
|
808
805
|
throw new TypeError("arrays cannot contain null or undefined values");
|
|
809
806
|
}
|
|
810
|
-
res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1);
|
|
807
|
+
res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1, numberAsFloat);
|
|
811
808
|
}
|
|
812
809
|
return res + " ]";
|
|
813
810
|
}
|
|
814
|
-
function stringifyArrayTable(array, key, depth) {
|
|
811
|
+
function stringifyArrayTable(array, key, depth, numberAsFloat) {
|
|
815
812
|
if (depth === 0) {
|
|
816
813
|
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
817
814
|
}
|
|
@@ -819,12 +816,12 @@ function stringifyArrayTable(array, key, depth) {
|
|
|
819
816
|
for (let i = 0; i < array.length; i++) {
|
|
820
817
|
res += `[[${key}]]
|
|
821
818
|
`;
|
|
822
|
-
res += stringifyTable(array[i], key, depth);
|
|
819
|
+
res += stringifyTable(array[i], key, depth, numberAsFloat);
|
|
823
820
|
res += "\n\n";
|
|
824
821
|
}
|
|
825
822
|
return res;
|
|
826
823
|
}
|
|
827
|
-
function stringifyTable(obj, prefix, depth) {
|
|
824
|
+
function stringifyTable(obj, prefix, depth, numberAsFloat) {
|
|
828
825
|
if (depth === 0) {
|
|
829
826
|
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
830
827
|
}
|
|
@@ -840,17 +837,17 @@ function stringifyTable(obj, prefix, depth) {
|
|
|
840
837
|
}
|
|
841
838
|
let key = BARE_KEY.test(k) ? k : formatString(k);
|
|
842
839
|
if (type === "array" && isArrayOfTables(obj[k])) {
|
|
843
|
-
tables += stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1);
|
|
840
|
+
tables += stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat);
|
|
844
841
|
} else if (type === "object") {
|
|
845
842
|
let tblKey = prefix ? `${prefix}.${key}` : key;
|
|
846
843
|
tables += `[${tblKey}]
|
|
847
844
|
`;
|
|
848
|
-
tables += stringifyTable(obj[k], tblKey, depth - 1);
|
|
845
|
+
tables += stringifyTable(obj[k], tblKey, depth - 1, numberAsFloat);
|
|
849
846
|
tables += "\n\n";
|
|
850
847
|
} else {
|
|
851
848
|
preamble += key;
|
|
852
849
|
preamble += " = ";
|
|
853
|
-
preamble += stringifyValue(obj[k], type, depth);
|
|
850
|
+
preamble += stringifyValue(obj[k], type, depth, numberAsFloat);
|
|
854
851
|
preamble += "\n";
|
|
855
852
|
}
|
|
856
853
|
}
|
|
@@ -858,12 +855,11 @@ function stringifyTable(obj, prefix, depth) {
|
|
|
858
855
|
return `${preamble}
|
|
859
856
|
${tables}`.trim();
|
|
860
857
|
}
|
|
861
|
-
function stringify(obj,
|
|
858
|
+
function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
|
862
859
|
if (extendedTypeOf(obj) !== "object") {
|
|
863
860
|
throw new TypeError("stringify can only be called with an object");
|
|
864
861
|
}
|
|
865
|
-
|
|
866
|
-
return stringifyTable(obj, "", maxDepth);
|
|
862
|
+
return stringifyTable(obj, "", maxDepth, numbersAsFloat);
|
|
867
863
|
}
|
|
868
864
|
|
|
869
865
|
// dist/index.js
|
package/dist/index.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ import { parse } from './parse.js';
|
|
|
29
29
|
import { stringify } from './stringify.js';
|
|
30
30
|
import { TomlDate } from './date.js';
|
|
31
31
|
import { TomlError } from './error.js';
|
|
32
|
-
export type {
|
|
32
|
+
export type { TomlValue, TomlTable, TomlValueWithoutBigInt, TomlTableWithoutBigInt } from './util.js';
|
|
33
33
|
declare const _default: {
|
|
34
34
|
parse: typeof parse;
|
|
35
35
|
stringify: typeof stringify;
|
|
@@ -38,3 +38,6 @@ declare const _default: {
|
|
|
38
38
|
};
|
|
39
39
|
export default _default;
|
|
40
40
|
export { parse, stringify, TomlDate, TomlError };
|
|
41
|
+
export type {
|
|
42
|
+
/** @deprecated use TomlValue instead */
|
|
43
|
+
TomlValue as TomlPrimitive } from './util.js';
|
package/dist/parse.d.ts
CHANGED
|
@@ -25,7 +25,13 @@
|
|
|
25
25
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
26
26
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
import type { IntegersAsBigInt } from './primitive.js';
|
|
29
|
+
import { type TomlTable, type TomlTableWithoutBigInt } from './util.js';
|
|
30
|
+
export interface ParseOptions {
|
|
31
|
+
maxDepth?: number;
|
|
32
|
+
integersAsBigInt?: IntegersAsBigInt;
|
|
33
|
+
}
|
|
34
|
+
export declare function parse(toml: string, options?: ParseOptions & {
|
|
35
|
+
integersAsBigInt: Exclude<IntegersAsBigInt, undefined | false>;
|
|
36
|
+
}): TomlTable;
|
|
37
|
+
export declare function parse(toml: string, options?: ParseOptions): TomlTableWithoutBigInt;
|
package/dist/parse.js
CHANGED
|
@@ -93,8 +93,7 @@ function peekTable(key, table, meta, type) {
|
|
|
93
93
|
}
|
|
94
94
|
return [k, t, state.c];
|
|
95
95
|
}
|
|
96
|
-
export function parse(toml,
|
|
97
|
-
let maxDepth = opts?.maxDepth ?? 1000;
|
|
96
|
+
export function parse(toml, { maxDepth = 1000, integersAsBigInt } = {}) {
|
|
98
97
|
let res = {};
|
|
99
98
|
let meta = {};
|
|
100
99
|
let tbl = res;
|
|
@@ -132,7 +131,7 @@ export function parse(toml, opts) {
|
|
|
132
131
|
ptr: ptr,
|
|
133
132
|
});
|
|
134
133
|
}
|
|
135
|
-
let v = extractValue(toml, k[1], void 0, maxDepth);
|
|
134
|
+
let v = extractValue(toml, k[1], void 0, maxDepth, integersAsBigInt);
|
|
136
135
|
p[1][p[0]] = v[0];
|
|
137
136
|
ptr = v[1];
|
|
138
137
|
}
|
package/dist/primitive.d.ts
CHANGED
|
@@ -27,4 +27,5 @@
|
|
|
27
27
|
*/
|
|
28
28
|
import { TomlDate } from './date.js';
|
|
29
29
|
export declare function parseString(str: string, ptr?: number, endPtr?: number): string;
|
|
30
|
-
export
|
|
30
|
+
export type IntegersAsBigInt = undefined | boolean | 'asNeeded';
|
|
31
|
+
export declare function parseValue(value: string, toml: string, ptr: number, integersAsBigInt: IntegersAsBigInt): boolean | number | bigint | TomlDate;
|
package/dist/primitive.js
CHANGED
|
@@ -42,7 +42,7 @@ let ESC_MAP = {
|
|
|
42
42
|
'\\': '\\',
|
|
43
43
|
};
|
|
44
44
|
export function parseString(str, ptr = 0, endPtr = str.length) {
|
|
45
|
-
let isLiteral = str[ptr] ===
|
|
45
|
+
let isLiteral = str[ptr] === '\'';
|
|
46
46
|
let isMultiline = str[ptr++] === str[ptr] && str[ptr] === str[ptr + 1];
|
|
47
47
|
if (isMultiline) {
|
|
48
48
|
endPtr -= 2;
|
|
@@ -61,14 +61,14 @@ export function parseString(str, ptr = 0, endPtr = str.length) {
|
|
|
61
61
|
if (!isMultiline) {
|
|
62
62
|
throw new TomlError('newlines are not allowed in strings', {
|
|
63
63
|
toml: str,
|
|
64
|
-
ptr: ptr - 1
|
|
64
|
+
ptr: ptr - 1,
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
else if ((c < '\x20' && c !== '\t') || c === '\x7f') {
|
|
69
69
|
throw new TomlError('control characters are not allowed in strings', {
|
|
70
70
|
toml: str,
|
|
71
|
-
ptr: ptr - 1
|
|
71
|
+
ptr: ptr - 1,
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
74
|
if (isEscape) {
|
|
@@ -79,7 +79,7 @@ export function parseString(str, ptr = 0, endPtr = str.length) {
|
|
|
79
79
|
if (!ESCAPE_REGEX.test(code)) {
|
|
80
80
|
throw new TomlError('invalid unicode escape', {
|
|
81
81
|
toml: str,
|
|
82
|
-
ptr: tmp
|
|
82
|
+
ptr: tmp,
|
|
83
83
|
});
|
|
84
84
|
}
|
|
85
85
|
try {
|
|
@@ -88,7 +88,7 @@ export function parseString(str, ptr = 0, endPtr = str.length) {
|
|
|
88
88
|
catch {
|
|
89
89
|
throw new TomlError('invalid unicode escape', {
|
|
90
90
|
toml: str,
|
|
91
|
-
ptr: tmp
|
|
91
|
+
ptr: tmp,
|
|
92
92
|
});
|
|
93
93
|
}
|
|
94
94
|
}
|
|
@@ -98,7 +98,7 @@ export function parseString(str, ptr = 0, endPtr = str.length) {
|
|
|
98
98
|
if (str[ptr] !== '\n' && str[ptr] !== '\r') {
|
|
99
99
|
throw new TomlError('invalid escape: only line-ending whitespace may be escaped', {
|
|
100
100
|
toml: str,
|
|
101
|
-
ptr: tmp
|
|
101
|
+
ptr: tmp,
|
|
102
102
|
});
|
|
103
103
|
}
|
|
104
104
|
ptr = skipVoid(str, ptr);
|
|
@@ -110,7 +110,7 @@ export function parseString(str, ptr = 0, endPtr = str.length) {
|
|
|
110
110
|
else {
|
|
111
111
|
throw new TomlError('unrecognized escape sequence', {
|
|
112
112
|
toml: str,
|
|
113
|
-
ptr: tmp
|
|
113
|
+
ptr: tmp,
|
|
114
114
|
});
|
|
115
115
|
}
|
|
116
116
|
sliceStart = ptr;
|
|
@@ -123,7 +123,7 @@ export function parseString(str, ptr = 0, endPtr = str.length) {
|
|
|
123
123
|
}
|
|
124
124
|
return parsed + str.slice(sliceStart, endPtr - 1);
|
|
125
125
|
}
|
|
126
|
-
export function parseValue(value, toml, ptr) {
|
|
126
|
+
export function parseValue(value, toml, ptr, integersAsBigInt) {
|
|
127
127
|
// Constant values
|
|
128
128
|
if (value === 'true')
|
|
129
129
|
return true;
|
|
@@ -135,37 +135,43 @@ export function parseValue(value, toml, ptr) {
|
|
|
135
135
|
return Infinity;
|
|
136
136
|
if (value === 'nan' || value === '+nan' || value === '-nan')
|
|
137
137
|
return NaN;
|
|
138
|
+
// Avoid FP representation of -0
|
|
138
139
|
if (value === '-0')
|
|
139
|
-
return
|
|
140
|
+
return integersAsBigInt ? 0n : 0;
|
|
140
141
|
// Numbers
|
|
141
|
-
let isInt;
|
|
142
|
-
if (
|
|
142
|
+
let isInt = INT_REGEX.test(value);
|
|
143
|
+
if (isInt || FLOAT_REGEX.test(value)) {
|
|
143
144
|
if (LEADING_ZERO.test(value)) {
|
|
144
145
|
throw new TomlError('leading zeroes are not allowed', {
|
|
145
146
|
toml: toml,
|
|
146
|
-
ptr: ptr
|
|
147
|
+
ptr: ptr,
|
|
147
148
|
});
|
|
148
149
|
}
|
|
149
|
-
|
|
150
|
+
value = value.replace(/_/g, '');
|
|
151
|
+
let numeric = +value;
|
|
150
152
|
if (isNaN(numeric)) {
|
|
151
153
|
throw new TomlError('invalid number', {
|
|
152
154
|
toml: toml,
|
|
153
|
-
ptr: ptr
|
|
155
|
+
ptr: ptr,
|
|
154
156
|
});
|
|
155
157
|
}
|
|
156
|
-
if (isInt
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
if (isInt) {
|
|
159
|
+
if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) {
|
|
160
|
+
throw new TomlError('integer value cannot be represented losslessly', {
|
|
161
|
+
toml: toml,
|
|
162
|
+
ptr: ptr,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (isInt || integersAsBigInt)
|
|
166
|
+
numeric = BigInt(value);
|
|
161
167
|
}
|
|
162
168
|
return numeric;
|
|
163
169
|
}
|
|
164
|
-
|
|
170
|
+
const date = new TomlDate(value);
|
|
165
171
|
if (!date.isValid()) {
|
|
166
172
|
throw new TomlError('invalid value', {
|
|
167
173
|
toml: toml,
|
|
168
|
-
ptr: ptr
|
|
174
|
+
ptr: ptr,
|
|
169
175
|
});
|
|
170
176
|
}
|
|
171
177
|
return date;
|
package/dist/stringify.d.ts
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
26
26
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
|
-
export declare function stringify(obj: any,
|
|
28
|
+
export declare function stringify(obj: any, { maxDepth, numbersAsFloat }?: {
|
|
29
29
|
maxDepth?: number;
|
|
30
|
+
numbersAsFloat?: boolean;
|
|
30
31
|
}): string;
|
package/dist/stringify.js
CHANGED
|
@@ -46,9 +46,9 @@ function isArrayOfTables(obj) {
|
|
|
46
46
|
function formatString(s) {
|
|
47
47
|
return JSON.stringify(s).replace(/\x7f/g, '\\u007f');
|
|
48
48
|
}
|
|
49
|
-
function stringifyValue(val, type, depth) {
|
|
49
|
+
function stringifyValue(val, type, depth, numberAsFloat) {
|
|
50
50
|
if (depth === 0) {
|
|
51
|
-
throw new Error(
|
|
51
|
+
throw new Error('Could not stringify the object: maximum object depth exceeded');
|
|
52
52
|
}
|
|
53
53
|
if (type === 'number') {
|
|
54
54
|
if (isNaN(val))
|
|
@@ -57,6 +57,8 @@ function stringifyValue(val, type, depth) {
|
|
|
57
57
|
return 'inf';
|
|
58
58
|
if (val === -Infinity)
|
|
59
59
|
return '-inf';
|
|
60
|
+
if (numberAsFloat && Number.isInteger(val))
|
|
61
|
+
return val.toFixed(1);
|
|
60
62
|
return val.toString();
|
|
61
63
|
}
|
|
62
64
|
if (type === 'bigint' || type === 'boolean') {
|
|
@@ -72,13 +74,13 @@ function stringifyValue(val, type, depth) {
|
|
|
72
74
|
return val.toISOString();
|
|
73
75
|
}
|
|
74
76
|
if (type === 'object') {
|
|
75
|
-
return stringifyInlineTable(val, depth);
|
|
77
|
+
return stringifyInlineTable(val, depth, numberAsFloat);
|
|
76
78
|
}
|
|
77
79
|
if (type === 'array') {
|
|
78
|
-
return stringifyArray(val, depth);
|
|
80
|
+
return stringifyArray(val, depth, numberAsFloat);
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
|
-
function stringifyInlineTable(obj, depth) {
|
|
83
|
+
function stringifyInlineTable(obj, depth, numberAsFloat) {
|
|
82
84
|
let keys = Object.keys(obj);
|
|
83
85
|
if (keys.length === 0)
|
|
84
86
|
return '{}';
|
|
@@ -89,11 +91,11 @@ function stringifyInlineTable(obj, depth) {
|
|
|
89
91
|
res += ', ';
|
|
90
92
|
res += BARE_KEY.test(k) ? k : formatString(k);
|
|
91
93
|
res += ' = ';
|
|
92
|
-
res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1);
|
|
94
|
+
res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat);
|
|
93
95
|
}
|
|
94
96
|
return res + ' }';
|
|
95
97
|
}
|
|
96
|
-
function stringifyArray(array, depth) {
|
|
98
|
+
function stringifyArray(array, depth, numberAsFloat) {
|
|
97
99
|
if (array.length === 0)
|
|
98
100
|
return '[]';
|
|
99
101
|
let res = '[ ';
|
|
@@ -103,25 +105,25 @@ function stringifyArray(array, depth) {
|
|
|
103
105
|
if (array[i] === null || array[i] === void 0) {
|
|
104
106
|
throw new TypeError('arrays cannot contain null or undefined values');
|
|
105
107
|
}
|
|
106
|
-
res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1);
|
|
108
|
+
res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1, numberAsFloat);
|
|
107
109
|
}
|
|
108
110
|
return res + ' ]';
|
|
109
111
|
}
|
|
110
|
-
function stringifyArrayTable(array, key, depth) {
|
|
112
|
+
function stringifyArrayTable(array, key, depth, numberAsFloat) {
|
|
111
113
|
if (depth === 0) {
|
|
112
|
-
throw new Error(
|
|
114
|
+
throw new Error('Could not stringify the object: maximum object depth exceeded');
|
|
113
115
|
}
|
|
114
116
|
let res = '';
|
|
115
117
|
for (let i = 0; i < array.length; i++) {
|
|
116
118
|
res += `[[${key}]]\n`;
|
|
117
|
-
res += stringifyTable(array[i], key, depth);
|
|
119
|
+
res += stringifyTable(array[i], key, depth, numberAsFloat);
|
|
118
120
|
res += '\n\n';
|
|
119
121
|
}
|
|
120
122
|
return res;
|
|
121
123
|
}
|
|
122
|
-
function stringifyTable(obj, prefix, depth) {
|
|
124
|
+
function stringifyTable(obj, prefix, depth, numberAsFloat) {
|
|
123
125
|
if (depth === 0) {
|
|
124
|
-
throw new Error(
|
|
126
|
+
throw new Error('Could not stringify the object: maximum object depth exceeded');
|
|
125
127
|
}
|
|
126
128
|
let preamble = '';
|
|
127
129
|
let tables = '';
|
|
@@ -135,28 +137,27 @@ function stringifyTable(obj, prefix, depth) {
|
|
|
135
137
|
}
|
|
136
138
|
let key = BARE_KEY.test(k) ? k : formatString(k);
|
|
137
139
|
if (type === 'array' && isArrayOfTables(obj[k])) {
|
|
138
|
-
tables += stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1);
|
|
140
|
+
tables += stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat);
|
|
139
141
|
}
|
|
140
142
|
else if (type === 'object') {
|
|
141
143
|
let tblKey = prefix ? `${prefix}.${key}` : key;
|
|
142
144
|
tables += `[${tblKey}]\n`;
|
|
143
|
-
tables += stringifyTable(obj[k], tblKey, depth - 1);
|
|
145
|
+
tables += stringifyTable(obj[k], tblKey, depth - 1, numberAsFloat);
|
|
144
146
|
tables += '\n\n';
|
|
145
147
|
}
|
|
146
148
|
else {
|
|
147
149
|
preamble += key;
|
|
148
150
|
preamble += ' = ';
|
|
149
|
-
preamble += stringifyValue(obj[k], type, depth);
|
|
151
|
+
preamble += stringifyValue(obj[k], type, depth, numberAsFloat);
|
|
150
152
|
preamble += '\n';
|
|
151
153
|
}
|
|
152
154
|
}
|
|
153
155
|
}
|
|
154
156
|
return `${preamble}\n${tables}`.trim();
|
|
155
157
|
}
|
|
156
|
-
export function stringify(obj,
|
|
158
|
+
export function stringify(obj, { maxDepth = 1000, numbersAsFloat = false } = {}) {
|
|
157
159
|
if (extendedTypeOf(obj) !== 'object') {
|
|
158
160
|
throw new TypeError('stringify can only be called with an object');
|
|
159
161
|
}
|
|
160
|
-
|
|
161
|
-
return stringifyTable(obj, '', maxDepth);
|
|
162
|
+
return stringifyTable(obj, '', maxDepth, numbersAsFloat);
|
|
162
163
|
}
|
package/dist/struct.d.ts
CHANGED
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
26
26
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
|
-
import { type
|
|
28
|
+
import { type IntegersAsBigInt } from './primitive.js';
|
|
29
|
+
import { type TomlTable, type TomlValue } from './util.js';
|
|
29
30
|
export declare function parseKey(str: string, ptr: number, end?: string): [string[], number];
|
|
30
|
-
export declare function parseInlineTable(str: string, ptr: number, depth
|
|
31
|
-
export declare function parseArray(str: string, ptr: number, depth
|
|
31
|
+
export declare function parseInlineTable(str: string, ptr: number, depth: number, integersAsBigInt: IntegersAsBigInt): [TomlTable, number];
|
|
32
|
+
export declare function parseArray(str: string, ptr: number, depth: number, integersAsBigInt: IntegersAsBigInt): [TomlValue[], number];
|
package/dist/struct.js
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
*/
|
|
28
28
|
import { parseString } from './primitive.js';
|
|
29
29
|
import { extractValue } from './extract.js';
|
|
30
|
-
import {
|
|
30
|
+
import { getStringEnd, indexOfNewline, skipComment, skipVoid } from './util.js';
|
|
31
31
|
import { TomlError } from './error.js';
|
|
32
32
|
let KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
|
|
33
33
|
export function parseKey(str, ptr, end = '=') {
|
|
@@ -37,7 +37,7 @@ export function parseKey(str, ptr, end = '=') {
|
|
|
37
37
|
if (endPtr < 0) {
|
|
38
38
|
throw new TomlError('incomplete key-value: cannot find end of key', {
|
|
39
39
|
toml: str,
|
|
40
|
-
ptr: ptr
|
|
40
|
+
ptr: ptr,
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
43
|
do {
|
|
@@ -45,7 +45,7 @@ export function parseKey(str, ptr, end = '=') {
|
|
|
45
45
|
// If it's whitespace, ignore
|
|
46
46
|
if (c !== ' ' && c !== '\t') {
|
|
47
47
|
// If it's a string
|
|
48
|
-
if (c === '"' || c ===
|
|
48
|
+
if (c === '"' || c === '\'') {
|
|
49
49
|
if (c === str[ptr + 1] && c === str[ptr + 2]) {
|
|
50
50
|
throw new TomlError('multiline strings are not allowed in keys', {
|
|
51
51
|
toml: str,
|
|
@@ -102,30 +102,22 @@ export function parseKey(str, ptr, end = '=') {
|
|
|
102
102
|
} while (dot + 1 && dot < endPtr);
|
|
103
103
|
return [parsed, skipVoid(str, endPtr + 1, true, true)];
|
|
104
104
|
}
|
|
105
|
-
export function parseInlineTable(str, ptr, depth
|
|
105
|
+
export function parseInlineTable(str, ptr, depth, integersAsBigInt) {
|
|
106
106
|
let res = {};
|
|
107
107
|
let seen = new Set();
|
|
108
108
|
let c;
|
|
109
109
|
let comma = 0;
|
|
110
110
|
ptr++;
|
|
111
111
|
while ((c = str[ptr++]) !== '}' && c) {
|
|
112
|
+
let err = { toml: str, ptr: ptr - 1 };
|
|
112
113
|
if (c === '\n') {
|
|
113
|
-
throw new TomlError('newlines are not allowed in inline tables',
|
|
114
|
-
toml: str,
|
|
115
|
-
ptr: ptr - 1
|
|
116
|
-
});
|
|
114
|
+
throw new TomlError('newlines are not allowed in inline tables', err);
|
|
117
115
|
}
|
|
118
116
|
else if (c === '#') {
|
|
119
|
-
throw new TomlError('inline tables cannot contain comments',
|
|
120
|
-
toml: str,
|
|
121
|
-
ptr: ptr - 1
|
|
122
|
-
});
|
|
117
|
+
throw new TomlError('inline tables cannot contain comments', err);
|
|
123
118
|
}
|
|
124
119
|
else if (c === ',') {
|
|
125
|
-
throw new TomlError('expected key-value, found comma',
|
|
126
|
-
toml: str,
|
|
127
|
-
ptr: ptr - 1
|
|
128
|
-
});
|
|
120
|
+
throw new TomlError('expected key-value, found comma', err);
|
|
129
121
|
}
|
|
130
122
|
else if (c !== ' ' && c !== '\t') {
|
|
131
123
|
let k;
|
|
@@ -139,7 +131,7 @@ export function parseInlineTable(str, ptr, depth = -1) {
|
|
|
139
131
|
if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== 'object' || seen.has(t[k]))) {
|
|
140
132
|
throw new TomlError('trying to redefine an already defined value', {
|
|
141
133
|
toml: str,
|
|
142
|
-
ptr: ptr
|
|
134
|
+
ptr: ptr,
|
|
143
135
|
});
|
|
144
136
|
}
|
|
145
137
|
if (!hasOwn && k === '__proto__') {
|
|
@@ -149,10 +141,10 @@ export function parseInlineTable(str, ptr, depth = -1) {
|
|
|
149
141
|
if (hasOwn) {
|
|
150
142
|
throw new TomlError('trying to redefine an already defined value', {
|
|
151
143
|
toml: str,
|
|
152
|
-
ptr: ptr
|
|
144
|
+
ptr: ptr,
|
|
153
145
|
});
|
|
154
146
|
}
|
|
155
|
-
let [value, valueEndPtr] = extractValue(str, keyEndPtr, '}', depth - 1);
|
|
147
|
+
let [value, valueEndPtr] = extractValue(str, keyEndPtr, '}', depth - 1, integersAsBigInt);
|
|
156
148
|
seen.add(value);
|
|
157
149
|
t[k] = value;
|
|
158
150
|
ptr = valueEndPtr;
|
|
@@ -162,18 +154,18 @@ export function parseInlineTable(str, ptr, depth = -1) {
|
|
|
162
154
|
if (comma) {
|
|
163
155
|
throw new TomlError('trailing commas are not allowed in inline tables', {
|
|
164
156
|
toml: str,
|
|
165
|
-
ptr: comma
|
|
157
|
+
ptr: comma,
|
|
166
158
|
});
|
|
167
159
|
}
|
|
168
160
|
if (!c) {
|
|
169
161
|
throw new TomlError('unfinished table encountered', {
|
|
170
162
|
toml: str,
|
|
171
|
-
ptr: ptr
|
|
163
|
+
ptr: ptr,
|
|
172
164
|
});
|
|
173
165
|
}
|
|
174
166
|
return [res, ptr];
|
|
175
167
|
}
|
|
176
|
-
export function parseArray(str, ptr, depth
|
|
168
|
+
export function parseArray(str, ptr, depth, integersAsBigInt) {
|
|
177
169
|
let res = [];
|
|
178
170
|
let c;
|
|
179
171
|
ptr++;
|
|
@@ -181,13 +173,13 @@ export function parseArray(str, ptr, depth = -1) {
|
|
|
181
173
|
if (c === ',') {
|
|
182
174
|
throw new TomlError('expected value, found comma', {
|
|
183
175
|
toml: str,
|
|
184
|
-
ptr: ptr - 1
|
|
176
|
+
ptr: ptr - 1,
|
|
185
177
|
});
|
|
186
178
|
}
|
|
187
179
|
else if (c === '#')
|
|
188
180
|
ptr = skipComment(str, ptr);
|
|
189
181
|
else if (c !== ' ' && c !== '\t' && c !== '\n' && c !== '\r') {
|
|
190
|
-
let e = extractValue(str, ptr - 1, ']', depth - 1);
|
|
182
|
+
let e = extractValue(str, ptr - 1, ']', depth - 1, integersAsBigInt);
|
|
191
183
|
res.push(e[0]);
|
|
192
184
|
ptr = e[1];
|
|
193
185
|
}
|
|
@@ -195,7 +187,7 @@ export function parseArray(str, ptr, depth = -1) {
|
|
|
195
187
|
if (!c) {
|
|
196
188
|
throw new TomlError('unfinished array encountered', {
|
|
197
189
|
toml: str,
|
|
198
|
-
ptr: ptr
|
|
190
|
+
ptr: ptr,
|
|
199
191
|
});
|
|
200
192
|
}
|
|
201
193
|
return [res, ptr];
|
package/dist/util.d.ts
CHANGED
|
@@ -26,9 +26,15 @@
|
|
|
26
26
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
28
|
import type { TomlDate } from './date.js';
|
|
29
|
-
export type TomlPrimitive = string | number |
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
export type TomlPrimitive = string | number | bigint | boolean | TomlDate;
|
|
30
|
+
export type TomlTable = {
|
|
31
|
+
[key: string]: TomlValue;
|
|
32
|
+
};
|
|
33
|
+
export type TomlValue = TomlPrimitive | TomlValue[] | TomlTable;
|
|
34
|
+
export type TomlTableWithoutBigInt = {
|
|
35
|
+
[key: string]: TomlValueWithoutBigInt;
|
|
36
|
+
};
|
|
37
|
+
export type TomlValueWithoutBigInt = Exclude<TomlPrimitive, bigint> | TomlValueWithoutBigInt[] | TomlTableWithoutBigInt;
|
|
32
38
|
export declare function indexOfNewline(str: string, start?: number, end?: number): number;
|
|
33
39
|
export declare function skipComment(str: string, ptr: number): number;
|
|
34
40
|
export declare function skipVoid(str: string, ptr: number, banNewLines?: boolean, banComments?: boolean): number;
|
package/dist/util.js
CHANGED
|
@@ -69,10 +69,7 @@ export function skipUntil(str, ptr, sep, end, banNewLines = false) {
|
|
|
69
69
|
else if (c === sep) {
|
|
70
70
|
return i + 1;
|
|
71
71
|
}
|
|
72
|
-
else if (c === end) {
|
|
73
|
-
return i;
|
|
74
|
-
}
|
|
75
|
-
else if (banNewLines && (c === '\n' || c === '\r' && str[i + 1] === '\n')) {
|
|
72
|
+
else if (c === end || (banNewLines && (c === '\n' || (c === '\r' && str[i + 1] === '\n')))) {
|
|
76
73
|
return i;
|
|
77
74
|
}
|
|
78
75
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smol-toml",
|
|
3
3
|
"license": "BSD-3-Clause",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.4.0",
|
|
5
5
|
"description": "A small, fast, and correct TOML parser/serializer",
|
|
6
6
|
"author": "Cynthia <cyyynthia@borkenware.com>",
|
|
7
7
|
"repository": "github:squirrelchat/smol-toml",
|
|
@@ -19,15 +19,15 @@
|
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@iarna/toml": "3.0.0",
|
|
21
21
|
"@ltd/j-toml": "^1.38.0",
|
|
22
|
-
"@tsconfig/node-lts": "^22.0.
|
|
22
|
+
"@tsconfig/node-lts": "^22.0.2",
|
|
23
23
|
"@tsconfig/strictest": "^2.0.5",
|
|
24
|
-
"@types/node": "^
|
|
25
|
-
"@vitest/ui": "^3.
|
|
26
|
-
"esbuild": "^0.25.
|
|
24
|
+
"@types/node": "^24.0.7",
|
|
25
|
+
"@vitest/ui": "^3.2.4",
|
|
26
|
+
"esbuild": "^0.25.5",
|
|
27
27
|
"fast-toml": "^0.5.4",
|
|
28
|
-
"pin-github-action": "^3.
|
|
28
|
+
"pin-github-action": "^3.4.0",
|
|
29
29
|
"typescript": "^5.8.3",
|
|
30
|
-
"vitest": "^3.
|
|
30
|
+
"vitest": "^3.2.4"
|
|
31
31
|
},
|
|
32
32
|
"main": "./dist/index.cjs",
|
|
33
33
|
"module": "./dist/index.js",
|