Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
module.exports = {
parserOptions: {
// To support BigInt
ecmaVersion: 2020
},
extends: require.resolve('@ostai/eslint-config'),
rules: {
'no-underscore-dangle': 0,
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ parse(text, reviver? = null, remove_comments? = false)

- **text** `string` The string to parse as JSON. See the [JSON](http://json.org/) object for a description of JSON syntax.
- **reviver?** `Function() | null` Default to `null`. It acts the same as the second parameter of [`JSON.parse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse). If a function, prescribes how the value originally produced by parsing is transformed, before being returned.
- `comment-json` also passes the 3rd parameter `context` to the function `reviver`, as described in https://github.com/tc39/proposal-json-parse-with-source, which will be useful to parse a JSON string with `BigInt` values.
- **remove_comments?** `boolean = false` If true, the comments won't be maintained, which is often used when we want to get a clean object.

Returns `CommentJSONValue` (`object | string | number | boolean | null`) corresponding to the given JSON text.
Expand Down Expand Up @@ -591,6 +592,12 @@ And it will print:
}
```

## Dealing with `BigInt`s

> Advanced Section

`comment-json` implements the TC39 proposal [proposal-json-parse-with-source](https://github.com/tc39/proposal-json-parse-with-source)

## License

[MIT](LICENSE)
Expand Down
36 changes: 26 additions & 10 deletions src/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ const symbolFor = prefix => Symbol.for(
: prefix
)

const transform = (k, v) => reviver
? reviver(k, v)
: v
const transform = (k, {value, context = {}}) => reviver
? reviver(k, value, context)
: value

const unexpected = () => {
const error = new SyntaxError(`Unexpected token '${current.value.slice(0, 1)}', "${current_code}" is not valid JSON`)
Expand Down Expand Up @@ -370,12 +370,16 @@ function walk () {

if (tt === CURLY_BRACKET_OPEN) {
next()
return parse_object()
return {
value: parse_object()
}
}

if (tt === BRACKET_OPEN) {
next()
return parse_array()
return {
value: parse_array()
}
}

let negative = EMPTY
Expand All @@ -388,6 +392,7 @@ function walk () {
}

let v
let source

switch (tt) {
case 'String':
Expand All @@ -396,8 +401,17 @@ function walk () {
case 'Numeric':
v = current.value
next()
return JSON.parse(negative + v)

source = negative + v
return {
value: JSON.parse(source),
context: {
source
}
}
default:
// => unexpected token
return {}
}
}

Expand All @@ -423,14 +437,19 @@ const parse = (code, rev, no_comments) => {

parse_comments(PREFIX_BEFORE_ALL)

let result = walk()
const final = walk()

parse_comments(PREFIX_AFTER_ALL)

if (current) {
unexpected()
}

// reviver
let result = transform('', final)

// We should run reviver before the checks below,
// otherwise the comment info will be lost
if (!no_comments && result !== null) {
if (!isObject(result)) {
// 1 -> new Number(1)
Expand All @@ -446,9 +465,6 @@ const parse = (code, rev, no_comments) => {

restore_comments_host()

// reviver
result = transform('', result)

free()

return result
Expand Down
35 changes: 33 additions & 2 deletions test/parse.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,25 @@
t.is(l.value, 'l')
t.is(l.inline, false)
}
},
{
d: 'reviver for BigInt',
s: `{
// big int
"a":9007199254740999
}`,
o: '{"a":9007199254740999}',
r: (k, v, {source}) => /^[0-9]+$/.test(source) ? BigInt(source) : v,

Check failure on line 323 in test/parse.test.js

View workflow job for this annotation

GitHub Actions / build (22.x)

'BigInt' is not defined

Check failure on line 323 in test/parse.test.js

View workflow job for this annotation

GitHub Actions / build (24.x)

'BigInt' is not defined

Check failure on line 323 in test/parse.test.js

View workflow job for this annotation

GitHub Actions / build (24.x)

'BigInt' is not defined

Check failure on line 323 in test/parse.test.js

View workflow job for this annotation

GitHub Actions / build (22.x)

'BigInt' is not defined

Check failure on line 323 in test/parse.test.js

View workflow job for this annotation

GitHub Actions / build (20.x)

'BigInt' is not defined
e (t, obj) {
// eslint-disable-next-line
t.is(obj.a, 9007199254740999n)

const [comment] = obj[Symbol.for('before:a')]

t.is(comment.value, ' big int')
t.is(comment.inline, false)
t.is(comment.type, 'LineComment')
}
}
]

Expand All @@ -320,12 +339,24 @@
? test.only
: test

// - d: description
// - r: reviver
// - s: source
// - o: equivalent JSON string of s with comments removed
// - e: the expect function to test the result
tt(c.d, t => {
c.e(t, parser.parse(c.s))
c.e(
t,
c.r
// reviver
? parser.parse(c.s, c.r)
: parser.parse(c.s))
})

tt(`${c.d}, removes comments`, t => {
t.deepEqual(parser.parse(c.s, null, true), parser.parse(c.o))
c.r
? t.deepEqual(parser.parse(c.s, c.r, true), parser.parse(c.o, c.r))
: t.deepEqual(parser.parse(c.s, null, true), parser.parse(c.o))
})
})

Expand Down
Loading