Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

json-parser

Package Overview
Dependencies
Maintainers
1
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

json-parser - npm Package Compare versions

Comparing version 2.1.2 to 3.0.0

4

package.json
{
"name": "json-parser",
"version": "2.1.2",
"version": "3.0.0",
"description": "JSON parser to parse JSON object and MAINTAIN comments.",

@@ -56,4 +56,4 @@ "main": "src/index.js",

"dependencies": {
"esprima": "^4.0.1"
"comment-json": "^2.0.4"
}
}

@@ -8,11 +8,4 @@ [![Build Status](https://travis-ci.org/kaelzhang/node-json-parser.svg?branch=master)](https://travis-ci.org/kaelzhang/node-json-parser)

This is a very low level module. For most situations, recommend to use [`comment-json`](https://www.npmjs.org/package/comment-json) instead.
Since `3.0.0`, `json-parser` depends on `comment-json`, and directly use the `parse` method of `comment-json`
## What's new in `2.x`
`json-parser@2.x` brings some breaking changes by completely refactoring with [`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol)s
- supports comments everywhere, yes, **EVERYWHERE** in a JSON file, eventually 😆
- fixes the known issue about comments inside arrays.
## Install

@@ -35,201 +28,6 @@

- **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.
- **remove_comments?** `boolean = false` If true, the parsed JSON Object won't contain comments
For details, see [https://github.com/kaelzhang/node-comment-json#parse](https://github.com/kaelzhang/node-comment-json#parse)
Returns `object | string | number | boolean | null` corresponding to the given JSON text.
content
```js
/**
before-all
*/
// before-all
{
// before
/* before */
"foo" /* after-prop:foo */ : // after-comma:foo
1 // after-value:foo
// after-value:foo
, // after-comma:foo
// after-comma: foo
"bar": [ // before
// before
"baz" // after-value:0
// after-value:0
, // after-comma: 0
"quux"
// after-value:1
] // after-value:bar
// after-value:bar
}
// after-all
```
```js
console.log(parse(content))
```
And the result will be:
```js
{
// Comments before the JSON object
[Symbol.for('before-all')]: [{
type: 'BlockComment',
value: '\n before-all\n ',
inline: false
}, {
type: 'LineComment',
value: ' before-all',
inline: false
}],
...
[Symbol.for('after-prop:foo')]: [{
type: 'BlockComment',
value: ' after-prop:foo ',
inline: true
}],
// The real value
foo: 1,
bar: [
"baz",
"quux,
// The property of the array
[Symbol.for('after-value:0')]: [{
type: 'LineComment',
value: ' after-value:0',
inline: true
}, ...],
...
]
}
```
There are **SEVEN** kinds of symbol properties:
```js
// comment tokens before the JSON object
Symbol.for('before-all')
// comment tokens before any properties/items inside an object/array
Symbol.for('before')
// comment tokens after property key `prop` and before colon(`:`)
Symbol.for(`after-prop:${prop}`)
// comment tokens after the colon(`:`) of property `prop` and before property value
Symbol.for(`after-colon:${prop}`)
// comment tokens after the value of property `prop`/the item of index `prop`
// and before the key-value/item delimiter(`,`)
Symbol.for(`after-value:${prop}`)
// comment tokens after the comma of `prop`-value pair
// and before the next key-value pair/item
Symbol.for(`after-comma:${prop}`)
// comment tokens after the JSON object
Symbol.for('after-all')
```
And the value of each symbol property is an **array** of `CommentToken`
```ts
interface CommentToken {
type: 'BlockComment' | 'LineComment'
// The content of the comment, including whitespaces and line breaks
value: string
// If the start location is the same line as the previous token,
// then `inline` is `true`
inline: boolean
}
```
### Parse into an object without comments
```js
console.log(parse(content, null, true))
```
And the result will be:
```js
{
foo: 1,
bar: [
"baz",
"quux"
]
}
```
### Special cases
```js
const parsed = parse(`
// comment
1
`)
console.log(parsed === 1)
// false
```
If we parse a JSON of primative type with `remove_comments:false`, then the return value of `parse()` will be of object type.
The value of `parsed` is equivalent to:
```js
const parsed = new Number(1)
parsed[Symbol.for('before-all')] = [{
type: 'LineComment',
value: ' comment',
inline: false
}]
```
Which is similar for:
- `Boolean` type
- `String` type
For example
```js
const parsed = parse(`
"foo" /* comment */
`)
```
Which is equivalent to
```js
const parsed = new String('foo')
parsed[Symbol.for('after-all')] = [{
type: 'BlockComment',
value: ' comment ',
inline: true
}]
```
But there is one exception:
```js
const parsed = parse(`
// comment
null
`)
console.log(parsed === null) // true
```
## License
MIT

@@ -1,328 +0,3 @@

// JSON formatting
const {parse, tokenize} = require('comment-json')
const esprima = require('esprima')
const tokenize = code => esprima.tokenize(code, {
comment: true,
loc: true
})
const UNDEFINED = undefined
const previous_hosts = []
let comments_host = null
const previous_props = []
let last_prop
let remove_comments = false
let inline = false
let tokens = null
let last = null
let current = null
let index
let reviver = null
const clean = () => {
previous_props.length =
previous_hosts.length = 0
last = null
last_prop = UNDEFINED
}
const free = () => {
clean()
tokens.length = 0
comments_host =
tokens =
last =
current =
reviver = null
}
const PREFIX_BEFORE_ALL = 'before-all'
const PREFIX_BEFORE = 'before'
const PREFIX_AFTER_PROP = 'after-prop'
const PREFIX_AFTER_COLON = 'after-colon'
const PREFIX_AFTER_COMMA = 'after-comma'
const PREFIX_AFTER_VALUE = 'after-value'
const PREFIX_AFTER_ALL = 'after-all'
const symbolFor = prefix => Symbol.for(
last_prop !== UNDEFINED
? `${prefix}:${last_prop}`
: prefix
)
const transform = (k, v) => reviver
? reviver(k, v)
: v
const unexpected = () => {
const error = new SyntaxError(`Unexpected token ${current.value.slice(0, 1)}`)
Object.assign(error, current.loc.start)
throw error
}
const unexpected_end = () => {
const error = new SyntaxError('Unexpected end of JSON input')
Object.assign(error, last
? last.loc.end
// Empty string
: {
line: 1,
column: 0
})
throw error
}
const next = () => {
const new_token = tokens[++ index]
inline = current
&& new_token
&& current.loc.end.line === new_token.loc.start.line
|| false
last = current
current = new_token
}
const type = () => {
if (!current) {
unexpected_end()
}
return current.type === 'Punctuator'
? current.value
: current.type
}
const is = t => type() === t
const expect = a => {
if (!is(a)) {
unexpected()
}
}
const set_comments_host = new_host => {
previous_hosts.push(comments_host)
comments_host = new_host
}
const restore_comments_host = () => {
comments_host = previous_hosts.pop()
}
const parse_comments = prefix => {
const comments = []
while (
current
&& (
is('LineComment')
|| is('BlockComment')
)
) {
const comment = {
...current,
inline
}
delete comment.loc
comments.push(comment)
next()
}
if (remove_comments) {
return
}
if (comments.length) {
comments_host[symbolFor(prefix)] = comments
}
}
const set_prop = (prop, push) => {
if (push) {
previous_props.push(last_prop)
}
last_prop = prop
}
const restore_prop = () => {
last_prop = previous_props.pop()
}
const parse_object = () => {
const obj = {}
set_comments_host(obj)
set_prop(UNDEFINED, true)
let started
let name
parse_comments(PREFIX_BEFORE)
while (!is('}')) {
if (started) {
// key-value pair delimiter
expect(',')
next()
parse_comments(PREFIX_AFTER_COMMA)
}
started = true
expect('String')
name = JSON.parse(current.value)
set_prop(name)
next()
parse_comments(PREFIX_AFTER_PROP)
expect(':')
next()
parse_comments(PREFIX_AFTER_COLON)
obj[name] = transform(name, walk())
parse_comments(PREFIX_AFTER_VALUE)
}
// bypass }
next()
last_prop = undefined
restore_comments_host()
restore_prop()
return obj
}
const parse_array = () => {
const array = []
set_comments_host(array)
set_prop(UNDEFINED, true)
let started
let i = 0
parse_comments(PREFIX_BEFORE)
while (!is(']')) {
if (started) {
expect(',')
next()
parse_comments(PREFIX_AFTER_COMMA)
}
started = true
set_prop(i)
array[i] = transform(i, walk())
parse_comments(PREFIX_AFTER_VALUE)
i ++
}
next()
last_prop = undefined
restore_comments_host()
restore_prop()
return array
}
function walk () {
let tt = type()
if (tt === '{') {
next()
return parse_object()
}
if (tt === '[') {
next()
return parse_array()
}
let negative = ''
// -1
if (tt === '-') {
next()
tt = type()
negative = '-'
}
let v
switch (tt) {
case 'String':
case 'Boolean':
case 'Null':
case 'Numeric':
v = current.value
next()
return JSON.parse(negative + v)
default:
}
}
const isObject = subject => Object(subject) === subject
const parse = (code, rev, no_comments) => {
clean()
tokens = tokenize(code)
reviver = rev
remove_comments = no_comments
if (!tokens.length) {
unexpected_end()
}
index = - 1
next()
set_comments_host({})
parse_comments(PREFIX_BEFORE_ALL)
let result = walk()
parse_comments(PREFIX_AFTER_ALL)
if (current) {
unexpected()
}
if (!no_comments && result !== null) {
if (!isObject(result)) {
// 1 -> new Number(1)
// true -> new Boolean(1)
// "foo" -> new String("foo")
// eslint-disable-next-line no-new-object
result = new Object(result)
}
Object.assign(result, comments_host)
}
restore_comments_host()
// reviver
result = transform('', result)
free()
return result
}
module.exports = {

@@ -329,0 +4,0 @@ parse,

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc