json-6 1.1.4 → 1.1.6
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 +222 -21
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/import.d.mts +2 -0
- package/dist/import.d.mts.map +1 -0
- package/dist/index-esm.d.mts +3 -0
- package/dist/index-esm.d.mts.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3283 -2120
- package/dist/index.min.js +1 -1
- package/dist/index.min.mjs +1 -1
- package/dist/index.mjs +1706 -1615
- package/dist/json6.d.ts +157 -0
- package/dist/json6.d.ts.map +1 -0
- package/dist/register.d.mts +2 -0
- package/dist/register.d.mts.map +1 -0
- package/dist/require.d.ts +3 -0
- package/dist/require.d.ts.map +1 -0
- package/lib/globals.d.ts +7 -0
- package/lib/import.mjs +30 -82
- package/lib/index-esm.mjs +3 -0
- package/lib/json6.js +665 -222
- package/lib/register.mjs +11 -0
- package/lib/require.js +6 -0
- package/package.json +53 -9
package/README.md
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
# JSON6 – JSON for Humans
|
|
2
2
|
|
|
3
|
-
[](https://travis-ci.com/d3x0r/JSON6)
|
|
4
|
-
|
|
5
|
-
[](https://gitter.im/sack-vfs/json6?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
|
6
3
|
|
|
7
4
|
*Documentation base cloned from JSON5 project https://github.com/json5/json5*
|
|
8
5
|
|
|
@@ -57,10 +54,6 @@ JSON6’s aim is to remain close to JSON and JavaScript.
|
|
|
57
54
|
The following is the exact list of additions to JSON’s syntax introduced by
|
|
58
55
|
JSON6. **All of these are optional**, and **MOST of these come from ES5/6**.
|
|
59
56
|
|
|
60
|
-
## Caveats
|
|
61
|
-
|
|
62
|
-
Does not include stringify, instead falling back to original (internal) JSON.stringify.
|
|
63
|
-
This will cause problems maintaining undefined, Infinity and NaN type values.
|
|
64
57
|
|
|
65
58
|
### Summary of Changes from JSON5
|
|
66
59
|
|
|
@@ -73,12 +66,13 @@ JSON6 includes all features of JSON5 plus the following.
|
|
|
73
66
|
- Arrays - empty members
|
|
74
67
|
- Streaming reader interface
|
|
75
68
|
- (Twice the speed of JSON5; subjective)
|
|
69
|
+
- Opt-in [`esStrictCompatible`](#options) mode that narrows the grammar to a subset of ECMAScript strict mode (see [Why might you wish to enable ECMAScript compatibility?](#why-might-you-wish-to-enable-ecmascript-compatibility)).
|
|
76
70
|
|
|
77
71
|
### Objects
|
|
78
72
|
|
|
79
|
-
- Object keys can be unquoted if they do not have ':', ']', '[', '{', '}', ',', any quote or whitespace; keywords will be interpreted as strings.
|
|
73
|
+
- Object keys can be unquoted if they do not have ':', ']', '[', '{', '}', ',', any quote or whitespace; keywords will be interpreted as strings. Under the opt-in [`esStrictCompatible`](#options) mode an unquoted key must additionally be a valid ECMAScript identifier name (or a number), so characters such as `-`, `\`, `&`, `+`, `*` and `|` then require quoting.
|
|
80
74
|
|
|
81
|
-
- Object keys can be single-quoted, (**JSON6**) or back-tick quoted; any valid string
|
|
75
|
+
- Object keys can be single-quoted, (**JSON6**) or back-tick quoted (the latter is rejected under [`esStrictCompatible`](#options)); any valid string
|
|
82
76
|
|
|
83
77
|
- Object keys can be double-quoted (original JSON).
|
|
84
78
|
|
|
@@ -103,10 +97,13 @@ JSON6 includes all features of JSON5 plus the following.
|
|
|
103
97
|
- Strings can be split across multiple lines; just prefix each newline with a
|
|
104
98
|
backslash. [ES5 [§7.8.4](http://es5.github.com/#x7.8.4)]
|
|
105
99
|
|
|
106
|
-
- (**JSON6**) all strings
|
|
107
|
-
|
|
100
|
+
- (**JSON6**) all strings keep every character between the start and end, so single-, double-, and
|
|
101
|
+
back-tick-quoted strings may all span multiple lines with the newlines preserved. If you do not want the
|
|
102
|
+
newlines they can be escaped as previously mentioned. (Under the opt-in [`esStrictCompatible`](#options)
|
|
103
|
+
mode a literal, unescaped line terminator is rejected inside `'`/`"` strings — but still allowed inside
|
|
104
|
+
back-ticks — so those strings stay valid ECMAScript.)
|
|
108
105
|
|
|
109
|
-
- (**JSON5+?**) Strings can have characters emitted using 1 byte hex, interpreted as a utf8 codepoint `\xNN`, 2 and only 2 hex digits must follow `\x`; they may be 4 byte unicode characters `\uUUUU`, 4 and only 4 hex digits must follow `\u`; higher codepoints can be specified with `\u{HHHHH}`, (where H is a hex digit) This is permissive and may accept a single hex digit between `{` and `}`. All other standard escape sequeneces are also recognized. Any character that is not recognized as a valid escape character is emitted without the leading escape slash ( for example, `"\012"` will parse as `"012"`
|
|
106
|
+
- (**JSON5+?**) Strings can have characters emitted using 1 byte hex, interpreted as a utf8 codepoint `\xNN`, 2 and only 2 hex digits must follow `\x`; they may be 4 byte unicode characters `\uUUUU`, 4 and only 4 hex digits must follow `\u`; higher codepoints can be specified with `\u{HHHHH}`, (where H is a hex digit) This is permissive and may accept a single hex digit between `{` and `}`. All other standard escape sequeneces are also recognized. Any character that is not recognized as a valid escape character is emitted without the leading escape slash ( for example, `"\012"` will parse as `"\0" + "12"`). (Under the opt-in [`esStrictCompatible`](#options) mode a legacy octal escape such as `"\012"` or `"\1"` is rejected.)
|
|
110
107
|
|
|
111
108
|
- (**JSON6**) The interpretation of newline is dynamic treating `\r`, `\n`, and `\r\n` as valid combinations of line ending whitespace. The `\` will behave approrpriately on those combinations. Mixed line endings like `\n\r?` or `\n\r\n?` are two line endings; 1 for newline, 1 for the \r(follwed by any character), and 1 for the newline, and 1 for the \r\n pair in the second case.
|
|
112
109
|
|
|
@@ -120,7 +117,7 @@ JSON6 includes all features of JSON5 plus the following.
|
|
|
120
117
|
|
|
121
118
|
- (**JSON6**) Numbers can be octal (base 8). (0o prefix)
|
|
122
119
|
|
|
123
|
-
- (**JSON6**) Decimal Numbers can have leading zeros. (0 prefix followed by more numbers, without a decimal)
|
|
120
|
+
- (**JSON6**) Decimal Numbers can have leading zeros. (0 prefix followed by more numbers, without a decimal) `0123` is `123`, not octal `83`; see [Leading 0 Octal](#leading-0-octal). (Rejected under the opt-in [`esStrictCompatible`](#options) mode, where ECMAScript treats it as legacy octal.)
|
|
124
121
|
|
|
125
122
|
- Numbers can begin or end with a (leading or trailing) decimal point.
|
|
126
123
|
|
|
@@ -128,7 +125,7 @@ JSON6 includes all features of JSON5 plus the following.
|
|
|
128
125
|
|
|
129
126
|
- Numbers can begin with an explicit plus sign.
|
|
130
127
|
|
|
131
|
-
- Numbers can begin with multiple minus signs
|
|
128
|
+
- (**JSON6**) Numbers can begin with multiple minus signs (for example `'----123' === 123`). (Two or more consecutive signs are rejected under the opt-in [`esStrictCompatible`](#options) mode.)
|
|
132
129
|
|
|
133
130
|
### Keyword Values
|
|
134
131
|
|
|
@@ -138,7 +135,7 @@ JSON6 includes all features of JSON5 plus the following.
|
|
|
138
135
|
### Comments
|
|
139
136
|
|
|
140
137
|
- Both inline (single-line using '//' (todo:or '#'?) ) and block (multi-line using \/\* \*\/ ) comments are allowed.
|
|
141
|
-
- `//` comments end at a `\r` or `\n` character; They MAY also end at the end of a document
|
|
138
|
+
- `//` comments end at a `\r` or `\n` character; They MAY also end at the end of a document (pass `{ warnWithCommentWithoutEOL: true }` to log a warning when that happens).
|
|
142
139
|
- `/*` comments should be closed before the end of a document or stream flush.
|
|
143
140
|
- `/` followed by anything else other than `/` or `*` is an error.
|
|
144
141
|
|
|
@@ -269,15 +266,129 @@ var str = JSON6.stringify(obj); /* uses JSON stringify, so don't have to replace
|
|
|
269
266
|
|
|
270
267
|
|JSON6 Methods | parameters | Description |
|
|
271
268
|
|-----|-----|-----|
|
|
272
|
-
|parse| (string [,reviver]) | supports all of the JSON6 features listed above, as well as the native [`reviver` argument][json-parse]. |
|
|
273
|
-
|stringify | (
|
|
269
|
+
|parse| (string [,reviver] [,options]) | supports all of the JSON6 features listed above, as well as the native [`reviver` argument][json-parse]. See [Options](#options) for `options`. |
|
|
270
|
+
|stringify | (value [,replacer] [,space] [,options]) | converts object to JSON. [stringify][json-stringify]. `options.sortKeys` (default `true`) can be set to `false` to keep an object's own key order instead of sorting it. |
|
|
274
271
|
|escape | ( string ) | substitutes ", \, ', and ` with backslashed sequences. (prevent 'JSON injection') |
|
|
275
|
-
|begin| (cb [,reviver] ) | create a JSON6 stream processor. cb is called with (value) for each value decoded from input given with write(). Optional reviver is called with each object before being passed to callback. |
|
|
272
|
+
|begin| (cb [,reviver] [,options] ) | create a JSON6 stream processor. cb is called with (value) for each value decoded from input given with write(). Optional reviver is called with each object before being passed to callback. `options` are the same as for `parse` and stay in effect across a bare `reset()`. |
|
|
273
|
+
|
|
274
|
+
`JSON6.stringifier()` returns a reusable stringifier object whose `sortKeys`
|
|
275
|
+
(default `true`) and `ignoreNonEnumerable` (default `false`) properties can
|
|
276
|
+
also be set directly:
|
|
277
|
+
|
|
278
|
+
```js
|
|
279
|
+
const stringifier = JSON6.stringifier();
|
|
280
|
+
stringifier.sortKeys = false;
|
|
281
|
+
stringifier.stringify({ z: 1, a: 2 }); // '{z:1,a:2}' -- own key order kept
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Options
|
|
285
|
+
|
|
286
|
+
`parse`, `begin`, and `reset` take an optional trailing `options` object.
|
|
287
|
+
**Every option is off by default**, so out of the box JSON6 accepts its full
|
|
288
|
+
historical grammar.
|
|
276
289
|
|
|
290
|
+
| Option | Default | Effect |
|
|
291
|
+
|:---|:---|:---|
|
|
292
|
+
| `esStrictCompatible` | `false` | When `true`, narrow the accepted grammar to a subset of **ECMAScript strict mode**, so anything that parses can be pasted into a module or `eval`'d unchanged (if trusted or using `forbidTemplateSubstitution: true`). Rejects: legacy-octal / leading-zero numbers (`0123`); legacy octal string escapes (`"\012"`, `"\1"`..`"\9"`); literal (unescaped) line terminators inside `'`/`"` strings — back-tick strings still allow them; back-tick-quoted object keys; unquoted object keys that are neither identifiers nor numbers (`{a-b: 1}`); and two or more consecutive unary `+`/`-` signs (`--5`). |
|
|
293
|
+
| `forbidTemplateSubstitution` | `false` | When `true`, reject an unescaped `${` inside a back-tick-quoted string, so a document cannot silently turn into a template-literal substitution if it is later evaluated as JavaScript. Independent of `esStrictCompatible`. |
|
|
294
|
+
| `normalizeNumericKeys` | `false` | When `true`, an unquoted object key that parses as a number is replaced with `String(Number(key))`, so `{1e3: true}` gives the key `"1000"` instead of the source text `"1e3"` — matching what a JavaScript object literal produces. Independent of `esStrictCompatible`. `Number()` parses a leading-zero digit string like `"0123"` as decimal (`123`), while a real (sloppy-mode) JavaScript numeric literal `0123` is legacy octal (`83`); combine with `esStrictCompatible` (which forbids leading-zero numbers outright) to avoid that mismatch. |
|
|
295
|
+
| `warnWithCommentWithoutEOL` | `false` | When `true`, a `//` comment that runs to the end of the document with no terminating line break logs a `console` warning. The input is accepted either way. |
|
|
296
|
+
|
|
297
|
+
Strict mode is the yardstick because modules, classes, and any `"use strict"`
|
|
298
|
+
code are always strict; constructs that are legal only in "sloppy" mode (the
|
|
299
|
+
legacy octal escape `"\1"`, or `"\9"` which sloppy mode silently reduces to
|
|
300
|
+
`"9"`) are still rejected by `esStrictCompatible`.
|
|
301
|
+
|
|
302
|
+
A numeric object key keeps its source text rather than JavaScript's normalized
|
|
303
|
+
form, so `{1e3:1}` gives the key `"1e3"` here but `"1000"` in JavaScript (where
|
|
304
|
+
a NumericLiteral key is converted through its numeric value). This applies
|
|
305
|
+
under `esStrictCompatible` too: the "same meaning when pasted" guarantee is
|
|
306
|
+
about what parses, not about the exact key string produced by each parser.
|
|
307
|
+
Turn on `normalizeNumericKeys` to close that specific gap.
|
|
308
|
+
|
|
309
|
+
```js
|
|
310
|
+
JSON6.parse("{'a-b': 0123}"); // { 'a-b': 123 } (default)
|
|
311
|
+
JSON6.parse("{'a-b': 0123}", null, { esStrictCompatible: true }); // throws
|
|
312
|
+
JSON6.parse("`total: ${x}`"); // 'total: ${x}' (default)
|
|
313
|
+
JSON6.parse("`total: ${x}`", null, { forbidTemplateSubstitution: true }); // throws
|
|
314
|
+
JSON6.parse("{1e3: true}"); // { '1e3': true } (default)
|
|
315
|
+
JSON6.parse("{1e3: true}", null, { normalizeNumericKeys: true }); // { '1000': true }
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
`begin(cb, reviver, options)` applies the options to the stream; a bare
|
|
319
|
+
`reset()` keeps them, while `reset(options)` replaces them.
|
|
277
320
|
|
|
278
321
|
[json-parse]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
|
|
279
322
|
[json-stringify]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
|
|
280
323
|
|
|
324
|
+
#### Why the default is *not* strict
|
|
325
|
+
|
|
326
|
+
The extensions exist because they make hand-written data less noisy, and for
|
|
327
|
+
a data format — which is read and edited far more than it is pasted into
|
|
328
|
+
code — that often matters more than JavaScript-parseability:
|
|
329
|
+
|
|
330
|
+
- **Leading zeros align columns.** `[ 001, 002, 010, 100 ]` or a table of
|
|
331
|
+
`id: 0042` reads better than ragged values. `Number()` already treats
|
|
332
|
+
`"0123"` as `123`, so nothing is ambiguous; only a *source-code lexer*
|
|
333
|
+
would see octal. (See [Leading 0 Octal](#leading-0-octal).)
|
|
334
|
+
- **Literal newlines in ordinary strings are the obvious behavior.** Most
|
|
335
|
+
people expect a quote to keep running until the closing quote; requiring a
|
|
336
|
+
trailing `\` on every line, or switching to back-ticks, is friction with no
|
|
337
|
+
payoff when the file is never going to be executed.
|
|
338
|
+
- **Punctuation in unquoted keys.** `content-type`, `x-api-key`,
|
|
339
|
+
`feature.flag` and the like are extremely common config keys; quoting every
|
|
340
|
+
one of them is the exact verbosity JSON6 set out to remove.
|
|
341
|
+
- **`--5`, `+8`, stray signs.** Forgiving sign handling means
|
|
342
|
+
machine-generated output and quick hand edits parse without complaint.
|
|
343
|
+
- **`${...}` as plain text.** In a data file there is no interpolation to
|
|
344
|
+
worry about, so `` `price: ${amount}` `` is just a string; forbidding it
|
|
345
|
+
only helps if the file will later be evaluated as code.
|
|
346
|
+
|
|
347
|
+
If a given file (or project) is meant to double as JavaScript, turn on
|
|
348
|
+
`esStrictCompatible` and the parser will hold it to that stricter bar;
|
|
349
|
+
otherwise the friendlier grammar is the point.
|
|
350
|
+
|
|
351
|
+
#### Why might you wish to enable ECMAScript compatibility?
|
|
352
|
+
|
|
353
|
+
JSON6 offers the potential for a `.json6` document to also be a valid
|
|
354
|
+
JavaScript value literal. Turning on `esStrictCompatible` keeps that true
|
|
355
|
+
in every context, and that can buy a lot:
|
|
356
|
+
|
|
357
|
+
- **Paste-compatibility, both directions.** You can copy a logged object
|
|
358
|
+
(`console.log(obj)`) straight into a `.json6` file, and paste a `.json6`
|
|
359
|
+
file into a `.js` module, `eval` it, or rename it to a JS config
|
|
360
|
+
(`module.exports = { … }`) without edits or `SyntaxError`s. A config
|
|
361
|
+
authored in JSON6 can "graduate" to a real JS module the day it needs a
|
|
362
|
+
computed value.
|
|
363
|
+
- **No silent changes of meaning.** The dangerous cases aren't the ones that
|
|
364
|
+
error — they're the ones that don't. `0123` is `123` in JSON6 but octal
|
|
365
|
+
`83` in sloppy JS; `` `total: ${x}` `` is a literal string here but a
|
|
366
|
+
substitution in JS; `--5` is `5` here but decrement-nonsense elsewhere. An
|
|
367
|
+
ES-compatible subset removes these by construction.
|
|
368
|
+
- **Existing tooling just works.** Editors, syntax highlighters, bracket
|
|
369
|
+
matchers, Prettier, ESLint, and AST libraries (acorn, Babel, TypeScript)
|
|
370
|
+
already understand ES. If `.json6` is an ES subset, all of that applies for
|
|
371
|
+
free, and authors of new tools that touch `.json6` are far less likely to
|
|
372
|
+
get an edge case subtly wrong.
|
|
373
|
+
- **Familiarity, not a new dialect.** Developers already know the rules;
|
|
374
|
+
there is no "…but JSON6 also allows backtick keys and `&` in identifiers"
|
|
375
|
+
to learn, and fewer typos that happen to parse as something unintended.
|
|
376
|
+
- **Interoperability instead of fragmentation.** Other parsers in the
|
|
377
|
+
ecosystem (e.g. `eslint-plugin-jsonc`, which already reads some JSON6) can
|
|
378
|
+
be built on an ES grammar; every deviation is a place two implementations
|
|
379
|
+
can disagree.
|
|
380
|
+
- **Forward compatibility.** TC39 periodically assigns meaning to
|
|
381
|
+
previously-free syntax. A grammar that stays inside today's ES is less
|
|
382
|
+
likely to collide with tomorrow's. JSON itself learned this: the
|
|
383
|
+
U+2028/U+2029 portability bug was fixed in ES2019 by making JSON a
|
|
384
|
+
syntactic subset of ES.
|
|
385
|
+
- **It's the direction the standards went.** The accepted
|
|
386
|
+
[tc39 JSON-superset proposal](https://github.com/tc39/proposal-json-superset)
|
|
387
|
+
made the same argument from the other side.
|
|
388
|
+
- **Cheaper correctness.** The parser can be checked against a reference: if
|
|
389
|
+
V8/`acorn` accepts the text and produces value *v*, JSON6 should too. A
|
|
390
|
+
narrower grammar is also less to audit.
|
|
391
|
+
|
|
281
392
|
### JSON6 Streaming
|
|
282
393
|
|
|
283
394
|
A Parser that returns objects as they are encountered in a stream can be created. `JSON.begin( dataCallback, reviver );` The callback is called for each complete object in a stream of data that is passed.
|
|
@@ -289,7 +400,7 @@ A Parser that returns objects as they are encountered in a stream can be created
|
|
|
289
400
|
| write | (string) | Parse string passed and as objects are found, invoke the callback passed to `begin()` Objects are passed through optional reviver function passed to `begin()`. |
|
|
290
401
|
| \_write | (string,completeAtEnd) | Low level routine used internally. This does the work of parsing the passed string. Returns 0 if no object completed, 1 if there is no more data, and an object was completd, returns 2 if there is more data and a parsed object is found. if completedAtEnd is true, dangling values are returned, for example "1234" isn't known to be completed, more of the number might follow in another buffer; if completeAtEnd is passed, this iwll return as number 1234. Passing empty arguments steps to the next buffered input value. |
|
|
291
402
|
| value | () | Returns the currently completed object. Used to get the completed object after calling \_write. |
|
|
292
|
-
| reset | () | If `write()` or `\_write()` throws an exception, no further objects will be parsed becuase internal status is false, this resets the internal status to allow continuing using the existing parser. ( May require some work to actually work for complex cases) |
|
|
403
|
+
| reset | ( [options] ) | If `write()` or `\_write()` throws an exception, no further objects will be parsed becuase internal status is false, this resets the internal status to allow continuing using the existing parser. ( May require some work to actually work for complex cases) With no argument the options passed to `begin()` stay in effect; pass an `options` object to change them. |
|
|
293
404
|
|
|
294
405
|
|
|
295
406
|
```js
|
|
@@ -339,6 +450,18 @@ require('./path/to/foo'); // tries foo.json6 after foo.js, foo.json, etc.
|
|
|
339
450
|
require('./path/to/bar.json6');
|
|
340
451
|
```
|
|
341
452
|
|
|
453
|
+
For ES modules, register the loader hooks before your program starts (Node 20.6 or newer):
|
|
454
|
+
|
|
455
|
+
```sh
|
|
456
|
+
node --import json-6/lib/register.mjs app.mjs
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
```js
|
|
460
|
+
import config from './path/to/bar.json6';
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
On older Node versions the same hooks can be applied with `--experimental-loader json-6/lib/import.mjs`.
|
|
464
|
+
|
|
342
465
|
This module also provides a `json6` executable (requires Node) for converting
|
|
343
466
|
JSON6 files to JSON:
|
|
344
467
|
|
|
@@ -394,6 +517,13 @@ npm test
|
|
|
394
517
|
As the `package.json6` file states, be sure to run `npm run build` on changes
|
|
395
518
|
to `package.json6`, since npm requires `package.json`.
|
|
396
519
|
|
|
520
|
+
The parser source is `src/json6.js`; it is the only hand-edited file. `npm run build`
|
|
521
|
+
generates `lib/json6.js` from it with the package version stamped in
|
|
522
|
+
(`build/src-to-lib.js`), regenerates `package.json`, and then produces `dist/`
|
|
523
|
+
(rollup bundles and TypeScript declarations). Edits made directly in `lib/` are
|
|
524
|
+
overwritten on the next build. `lib/json6.js` is committed so that a checkout works
|
|
525
|
+
without a build step; `dist/` is not.
|
|
526
|
+
|
|
397
527
|
Feel free to [file issues](https://github.com/d3x0r/json6/issues) and submit
|
|
398
528
|
[pull requests](https://github.com/d3x0r/JSON6/pulls) — contributions are
|
|
399
529
|
welcome. If you do submit a pull request, please be sure to add or update the
|
|
@@ -408,9 +538,80 @@ switch the test command which is run, the older platforms were removed from test
|
|
|
408
538
|
The product of this should run on very old platforms also, especially `node_modules/json-6/dist/index.min.js`.
|
|
409
539
|
|
|
410
540
|
|
|
411
|
-
##
|
|
541
|
+
## Leading 0 Octal
|
|
412
542
|
|
|
413
|
-
|
|
543
|
+
A number with a leading `0` followed by more digits is decimal. `0123` is `123`. It is not octal (`83`), and it is not an error. (The opt-in [`esStrictCompatible`](#options) mode is the exception: it rejects the token, matching ECMAScript strict mode.)
|
|
544
|
+
|
|
545
|
+
The rationale: JSON6 is a data format, not source code. The leading-zero-means-octal convention lives in
|
|
546
|
+
*source code lexers* (C, C++, Java, Perl, Ruby, Go, shell, Python 2, sloppy-mode JavaScript). Every
|
|
547
|
+
*text-to-number conversion* routine, which is what a parser of a data format is, reads a leading zero as
|
|
548
|
+
just another decimal digit: `Number("0123")`, `parseInt("0123", 10)`, `parseFloat("0123")`, Python's
|
|
549
|
+
`int("0123")`, C's `strtol(s, 0, 10)` and `strtod()`, and Java's `Integer.parseInt("0123")` all give `123`.
|
|
550
|
+
None of them have ever produced `83`.
|
|
551
|
+
|
|
552
|
+
So the rule is simple, and it is the same rule that already governs the other number forms: **a numeric
|
|
553
|
+
token means what `Number()` says it means.** `Number("0x1F")` is `31`, `Number("0o17")` is `15`,
|
|
554
|
+
`Number("0b101")` is `5`, and `Number("0123")` is `123`. Legacy octal is the only interpretation
|
|
555
|
+
`Number()` has never accepted. The only places JSON6 departs from `Number()` are deliberate readability
|
|
556
|
+
extensions: `_` digit separators and a leading or trailing `.`.
|
|
557
|
+
|
|
558
|
+
The alternatives were considered and rejected:
|
|
559
|
+
|
|
560
|
+
- **Octal** silently changes the value, disagrees with `Number()`, and nobody hand-writing a
|
|
561
|
+
configuration file expects `0123` to be `83`. Anyone who actually wants octal has `0o123`.
|
|
562
|
+
- **Rejecting** leading zeros is what JSON, JSON5, strict-mode JavaScript, Python 3, and Rust do. It
|
|
563
|
+
loses nothing on the stringify side, since no serializer emits them, but it is strictly less friendly
|
|
564
|
+
for hand-written files where zero padding is used for alignment, such as `[ 001, 002, 010 ]`.
|
|
565
|
+
|
|
566
|
+
This is a deliberate divergence from ECMAScript strict mode, where `0123` is a syntax error. A `.json6`
|
|
567
|
+
document that uses leading zeros is therefore not valid JavaScript source; the same is true of JSON6's
|
|
568
|
+
other extensions. [JSOX](https://github.com/d3x0r/JSOX) takes the same stance. Callers who need the
|
|
569
|
+
JavaScript-subset guarantee can turn on [`esStrictCompatible`](#options).
|
|
570
|
+
|
|
571
|
+
## Changelog
|
|
572
|
+
- 1.1.7(pre)
|
|
573
|
+
- 1.1.6
|
|
574
|
+
- Fix the shipped `dist/json6.d.ts`: tsc emitted `export =` next to `export type` lines, which TypeScript 5.x rejects (TS2309) for any consumer compiling without `skipLibCheck`. The types now live in a namespace merged with the export (#60).
|
|
575
|
+
- `normalizeNumericKeys` parse option: an unquoted numeric key becomes `String(Number(key))`, so `{1e3:1}` gives key `"1000"` as a JS object literal would (#59).
|
|
576
|
+
- Error positions are now right: the column no longer starts one too high, numbers no longer count their terminator twice, `_` digit separators are counted, and lines are counted inside comments and strings and for CR, LS and PS as well as LF.
|
|
577
|
+
- `stringify` emits arrays as arrays; they used to go through the object path and come out as `{"0":..,"1":..}`. Holes stay holes (`[1,,3]`), `undefined` stays `undefined`, and a trailing hole keeps its comma so it survives a round trip.
|
|
578
|
+
- `stringify` always quotes string values (#57); only object keys use the bare-identifier rule.
|
|
579
|
+
- Malformed input that used to be silently accepted now throws:
|
|
580
|
+
- two values with no separator (`[1 2]` returned `[2]`),
|
|
581
|
+
- an object field name with no value (`{a}` and `{"a"}` returned `{}`),
|
|
582
|
+
- an incomplete keyword (`tru` returned `undefined`, `[tru]` returned `[]`); a truncated keyword is still fine as an object key,
|
|
583
|
+
- a sign with no number after it (`-` returned `undefined`),
|
|
584
|
+
- a malformed number (`1e`, `.5.`, `0x` returned `NaN`),
|
|
585
|
+
- a document with no value at all (empty, whitespace, or only comments) from `parse()`; `parse("undefined")` still returns `undefined`.
|
|
586
|
+
- `begin()` no longer needs a callback; `write()` throws if there is none, since values can only leave it through the callback.
|
|
587
|
+
- `parse()` restores its nested-parser level when it throws.
|
|
588
|
+
- Vertical tab (U+000B), form feed (U+000C), line separator (U+2028) and paragraph separator (U+2029) are whitespace between tokens, as in ECMAScript; U+2028/U+2029 also end a `//` comment.
|
|
589
|
+
- Remove no stringifier cavaet from documentation.
|
|
590
|
+
- `parse` / `begin` / `reset` now take an `options` argument ([#46](https://github.com/d3x0r/JSON6/issues/46)).
|
|
591
|
+
All options are off by default, so the historical grammar is unchanged.
|
|
592
|
+
- `esStrictCompatible` restricts the grammar to a subset of ECMAScript strict mode:
|
|
593
|
+
it rejects leading-zero / legacy-octal numbers, legacy octal string escapes
|
|
594
|
+
(`"\1"`..`"\9"`), literal line terminators inside `'`/`"` strings, backtick-quoted
|
|
595
|
+
object keys, non-identifier unquoted keys, and two or more consecutive `+`/`-` signs.
|
|
596
|
+
- `forbidTemplateSubstitution` rejects an unescaped `${` inside a backtick string.
|
|
597
|
+
- `warnWithCommentWithoutEOL` restores the console warning for a `//` comment that
|
|
598
|
+
ends the document without a line break (now silent by default).
|
|
599
|
+
- `stringify` gains an opt-out `sortKeys` option (and a matching `sortKeys` property on
|
|
600
|
+
`JSON6.stringifier()`); default `true` preserves the historical sorted-key output.
|
|
601
|
+
- `esStrictCompatible` no longer rejects two inputs that are valid ES strict mode:
|
|
602
|
+
a literal U+2028/U+2029 inside a `'`/`"` string (legal since ES2019), and an
|
|
603
|
+
unquoted numeric key using a numeric separator (`{1_000:1}`).
|
|
604
|
+
- `normalizeNumericKeys` normalizes an unquoted numeric object key to
|
|
605
|
+
`String(Number(key))` (so `{1e3:1}` gives the key `"1000"`, matching
|
|
606
|
+
JavaScript's object-literal key conversion), closing the "same meaning
|
|
607
|
+
when pasted" gap `esStrictCompatible` left around numeric keys.
|
|
608
|
+
- 1.1.5
|
|
609
|
+
- TypeScript declarations are generated from JSDoc during `npm run build` and shipped in `dist/` (#55).
|
|
610
|
+
- ESM loader for `.json6` moved to the `module.register()` API; `lib/register.mjs` added.
|
|
611
|
+
- Fix package `exports`: ESM entry pointed at a file that was never built; `lib/require`, `lib/import.mjs`, and `lib/register.mjs` subpaths were unreachable.
|
|
612
|
+
- `lib/json6.js` can again be loaded directly with a `<script>` tag.
|
|
613
|
+
- Parser source moved to `src/json6.js`; `lib/json6.js` is generated by `npm run build` with the package version stamped in, so `JSON6.version` can no longer drift from `package.json`.
|
|
614
|
+
- Document the rationale for leading-zero numbers being decimal.
|
|
414
615
|
- 1.1.4
|
|
415
616
|
- fixes benchmark test for hex number conversion
|
|
416
617
|
- 1.1.3
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../lib/cli.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import.d.mts","sourceRoot":"","sources":["../lib/import.mjs"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-esm.d.mts","sourceRoot":"","sources":["../lib/index-esm.mjs"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAC;eAEhB,KAAK"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
declare const _exports: {
|
|
2
|
+
escape: (string: string) => string;
|
|
3
|
+
begin: (cb?: (value: unknown) => void, reviver?: import("./json6.js").Json6Reviver | undefined, options?: import("./json6.js").Json6ParseOptions) => {
|
|
4
|
+
finalError(): void;
|
|
5
|
+
value(): unknown;
|
|
6
|
+
reset(resetOptions?: import("./json6.js").Json6ParseOptions): void;
|
|
7
|
+
write(msg?: unknown): void;
|
|
8
|
+
_write(msg?: string | undefined | null, complete_at_end?: boolean): number;
|
|
9
|
+
};
|
|
10
|
+
parse: (msg: unknown, reviver?: import("./json6.js").Json6Reviver, options?: import("./json6.js").Json6ParseOptions) => unknown;
|
|
11
|
+
stringifierActive: import("./json6.js").Json6Stringifier | null;
|
|
12
|
+
stringifier: () => {
|
|
13
|
+
stringify(o?: unknown, r?: import("./json6.js").Json6Replacer, s?: string | number | null, as?: string): string | undefined;
|
|
14
|
+
setQuote(q: string): void;
|
|
15
|
+
ignoreNonEnumerable: boolean;
|
|
16
|
+
sortKeys: boolean;
|
|
17
|
+
};
|
|
18
|
+
stringify: (object: unknown, replacer?: import("./json6.js").Json6Replacer, space?: string | number, options?: import("./json6.js").Json6StringifyOptions) => string | undefined;
|
|
19
|
+
version: string;
|
|
20
|
+
};
|
|
21
|
+
export = _exports;
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.js"],"names":[],"mappings":""}
|