JSPM

  • Created
  • Published
  • Downloads 6375881
  • Score
    100M100P100Q200245F
  • License MIT

Parse and stringify JSON with comments. It will retain comments even when after saved!

Package Exports

  • comment-json

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (comment-json) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Build Status Coverage

comment-json

  • Parse JSON strings with comments into JavaScript objects and MAINTAIN comments
    • supports comments everywhere, yes, EVERYWHERE in a JSON file, eventually 😆
    • fixes the known issue about comments inside arrays.
  • Stringify the objects into JSON strings with comments if there are

The usage of comment-json is exactly the same as the vanilla JSON object.

Install

$ npm i comment-json

Usage

package.json:

{
  // package name
  "name": "comment-json"
}
const {
  parse,
  stringify
} = require('comment-json')
const fs = require('fs')

const obj = parse(fs.readFileSync('package.json').toString())

console.log(obj.name) // comment-json

stringify(obj, null, 2)
// Will be the same as package.json,
// which will be very useful if we use a json file to store configurations.

parse()

parse(text, reviver? = null, remove_comments? = false)
  : object | string | number | boolean | null
  • text string The string to parse as JSON. See the JSON object for a description of JSON syntax.
  • reviver? Function() | null Default to null. It acts the same as the second parameter of 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 comments won't be maintained, which is often used when we want to get a clean object.

Returns object | string | number | boolean | null corresponding to the given JSON text.

If the content is:

/**
 before-all
 */
// before-all
{ // before:foo
  // before:foo
  /* before:foo */
  "foo" /* after-prop:foo */: // after-comma:foo
  1 // after-value:foo
  // after-value:foo
  , // before:bar
  // before:bar
  "bar": [ // before:0
    // before:0
    "baz" // after-value:0
    // after-value:0
    , // before:1
    "quux"
    // after-value:1
  ] // after-value:bar
  // after-value:bar
}
// after-all
const parsed = parse(content)
console.log(parsed)

And the result will be:

{
  // 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 EIGHT kinds of symbol properties:

Symbol.for('before-all')

// If all things inside an object or an array are comments
Symbol.for('before')

// comment tokens before
// - a property of an object
// - an item of an array
// and before the previous comma(`,`) or the opening bracket(`{` or `[`)
Symbol.for(`before:${prop}`)

// 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` inside an object
// - the item of index `prop` inside an array
// and before the next key-value/item delimiter(`,`)
// or the closing bracket(`}` or `]`)
Symbol.for(`after-value:${prop}`)

// if comments after
// - the last key-value:pair of an object
// - the last item of an array
Symbol.for('after')

Symbol.for('after-all')

And the value of each symbol property is an array of CommentToken

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

console.log(parse(content, null, true))

And the result will be:

{
  foo: 1,
  bar: [
    "baz",
    "quux"
  ]
}

Special cases

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:

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

const parsed = parse(`
"foo" /* comment */
`)

Which is equivalent to

const parsed = new String('foo')

parsed[Symbol.for('after-all')] = [{
  type: 'BlockComment',
  value: ' comment ',
  inline: true
}]

But there is one exception:

const parsed = parse(`
// comment
null
`)

console.log(parsed === null) // true

stringify()

stringify(object: any, replacer?, space?): string

The arguments are the same as the vanilla JSON.stringify.

And it does the similar thing as the vanilla one, but also deal with extra properties and convert them into comments.

console.log(stringify(parsed, null, 2))
// Exactly the same as `content`

space

If space is not specified, or the space is an empty string, the result of stringify() will have no comments.

For the case above:

console.log(stringify(result)) // {"a":1}
console.log(stringify(result, null, 2)) // is the same as `code`

License

MIT