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

comment-json

Package Overview
Dependencies
Maintainers
1
Versions
55
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

comment-json - npm Package Compare versions

Comparing version 2.0.9 to 2.1.0

3

package.json
{
"name": "comment-json",
"version": "2.0.9",
"version": "2.1.0",
"description": "Parse and stringify JSON with comments. It will retain comments even after saved!",

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

"esprima": "^4.0.1",
"has-own-prop": "^2.0.0",
"repeat-string": "^1.6.1"
}
}

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

## How?
`comment-json` parse JSON strings with comments and save comment tokens into [symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) properties.
For JSON array with comments, `comment-json` extends the vanilla `Array` object into [`CommentArray`](#commentarray) whose instances could handle comments changes even after a comment array is modified.
## Install

@@ -58,3 +64,4 @@

parse,
stringify
stringify,
assign
} = require('comment-json')

@@ -316,4 +323,104 @@ const fs = require('fs')

## assign(target: object, source?: object, keys?: Array<string>)
- **target** `object` the target object
- **source?** `object` the source object. This parameter is optional but it is silly to not pass this argument.
- **keys?** `Array<string>` If not specified, all enumerable own properties of `source` will be used.
This method is used to copy the enumerable own properties and their corresponding comment symbol properties to the target object.
```js
const parsed = parse(`{
// This is a comment
"foo": "bar"
}`)
const obj = assign({
bar: 'baz'
}, parsed)
stringify(obj, null, 2)
// {
// "bar": "baz",
// // This is a comment
// "foo": "bar"
// }
```
## `CommentArray`
> Advanced Section
All arrays of the parsed object are `CommentArray`s.
The constructor of `CommentArray` could be accessed by:
```js
const {CommentArray} = require('comment-json')
```
If we modify a comment array, its comment symbol properties could be handled automatically.
```js
const parsed = parse(`{
"foo": [
// bar
"bar",
// baz,
"baz"
]
}`)
parsed.foo.unshift('qux')
stringify(parsed, null, 2)
// {
// "foo": [
// "qux",
// // bar
// "bar",
// // baz
// "baz"
// ]
// }
```
Oh yeah! 😆
But pay attention, if you reassign the property of a comment array with a normal array, all comments will be gone:
```js
parsed.foo = ['quux'].concat(parsed.foo)
stringify(parsed, null, 2)
// {
// "foo": [
// "quux",
// "qux",
// "bar",
// "baz"
// ]
// }
// Whoooops!! 😩 Comments are gone
```
Instead, we should:
```js
parsed.foo = new CommentArray('quux').concat(parsed.foo)
stringify(parsed, null, 2)
// {
// "foo": [
// "quux",
// "qux",
// // bar
// "bar",
// // baz
// "baz"
// ]
// }
```
## License
[MIT](LICENSE)

@@ -1,3 +0,307 @@

const splice = (array) => {
const hasOwnProperty = require('has-own-prop')
const {isObject, isArray} = require('core-util-is')
const PREFIX_BEFORE = 'before'
const PREFIX_AFTER_PROP = 'after-prop'
const PREFIX_AFTER_COLON = 'after-colon'
const PREFIX_AFTER_VALUE = 'after-value'
const SYMBOL_PREFIXES = [
PREFIX_BEFORE,
PREFIX_AFTER_PROP,
PREFIX_AFTER_COLON,
PREFIX_AFTER_VALUE
]
const COLON = ':'
const UNDEFINED = undefined
const symbol = (prefix, key) => Symbol.for(prefix + COLON + key)
const assign_comments = (
target, source, target_key, source_key, prefix, remove_source
) => {
const source_prop = symbol(prefix, source_key)
if (!hasOwnProperty(source, source_prop)) {
return
}
const target_prop = target_key === source_key
? source_prop
: symbol(prefix, target_key)
target[target_prop] = source[source_prop]
if (remove_source) {
delete source[source_prop]
}
}
// Assign keys and comments
const assign = (target, source, keys) => {
keys.forEach(key => {
if (!hasOwnProperty(source, key)) {
return
}
target[key] = source[key]
SYMBOL_PREFIXES.forEach(prefix => {
assign_comments(target, source, key, key, prefix)
})
})
return target
}
const swap_comments = (array, from, to) => {
if (from === to) {
return
}
SYMBOL_PREFIXES.forEach(prefix => {
const target_prop = symbol(prefix, to)
if (!hasOwnProperty(array, target_prop)) {
assign_comments(array, array, to, from, prefix)
return
}
const comments = array[target_prop]
assign_comments(array, array, to, from, prefix)
array[symbol(prefix, from)] = comments
})
}
const reverse_comments = array => {
const {length} = array
let i = 0
const max = length / 2
for (; i < max; i ++) {
swap_comments(array, i, length - i - 1)
}
}
const move_comment = (target, source, i, offset, remove) => {
SYMBOL_PREFIXES.forEach(prefix => {
assign_comments(target, source, i + offset, i, prefix, remove)
})
}
const move_comments = (
// `Array` target array
target,
// `Array` source array
source,
// `number` start index
start,
// `number` number of indexes to move
count,
// `number` offset to move
offset,
// `boolean` whether should remove the comments from source
remove
) => {
if (offset > 0) {
let i = count
// | count | offset |
// source: -------------
// target: -------------
// | remove |
// => remove === offset
// From [count - 1, 0]
while (i -- > 0) {
move_comment(target, source, start + i, offset, remove && i < offset)
}
return
}
let i = 0
const min_remove = count + offset
// | remove | count |
// -------------
// -------------
// | offset |
// From [0, count - 1]
while (i < count) {
const ii = i ++
move_comment(target, source, start + ii, offset, remove && i >= min_remove)
}
}
class CommentArray extends Array {
// - deleteCount + items.length
// We should avoid `splice(begin, deleteCount, ...items)`,
// because `splice(0, undefined)` is not equivalent to `splice(0)`,
// as well as:
// - slice
splice (...args) {
const {length} = this
const ret = super.splice(...args)
// If no element removed, just skip moving comments.
// This is also used as argument type checking
if (!ret.length) {
return ret
}
// JavaScript syntax is silly
// eslint-disable-next-line prefer-const
let [begin, deleteCount, ...items] = args
if (begin < 0) {
begin += length
}
if (arguments.length === 1) {
deleteCount = length - begin
} else {
deleteCount = Math.min(length - begin, deleteCount)
}
const {
length: item_length
} = items
// itemsToDelete: -
// itemsToAdd: +
// | dc | count |
// =======-------------============
// =======++++++============
// | il |
const offset = item_length - deleteCount
const start = begin + deleteCount
const count = length - start
move_comments(this, this, start, count, offset, true)
return ret
}
slice (...args) {
const {length} = this
const array = super.slice(...args)
if (!array.length) {
return new CommentArray()
}
let [begin, before] = args
// Ref:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
if (before === UNDEFINED) {
before = length
} else if (before < 0) {
before += length
}
if (begin < 0) {
begin += length
} else if (begin === UNDEFINED) {
begin = 0
}
move_comments(array, this, begin, before - begin, - begin)
return array
}
unshift (...items) {
const {length} = this
const ret = super.unshift(...items)
const {
length: items_length
} = items
if (items_length > 0) {
move_comments(this, this, 0, length, items_length, true)
}
return ret
}
shift () {
const ret = super.shift()
const {length} = this
move_comments(this, this, 1, length, - 1, true)
return ret
}
reverse () {
super.reverse()
reverse_comments(this)
return this
}
pop () {
const ret = super.pop()
// Removes comments
const {length} = this
SYMBOL_PREFIXES.forEach(prefix => {
const prop = symbol(prefix, length)
delete this[prop]
})
return ret
}
concat (...items) {
let {length} = this
const ret = super.concat(...items)
if (!items.length) {
return ret
}
items.forEach(item => {
const prev = length
length += isArray(item)
? item.length
: 1
if (!(item instanceof CommentArray)) {
return
}
move_comments(ret, item, 0, item.length, prev)
})
return ret
}
}
module.exports = {
CommentArray,
assign (target, source, keys) {
if (!isObject(target)) {
throw new TypeError('Cannot convert undefined or null to object')
}
if (!isObject(source)) {
return target
}
if (keys === UNDEFINED) {
keys = Object.keys(source)
} else if (!isArray(keys)) {
throw new TypeError('keys must be array or undefined')
}
return assign(target, source, keys)
},
PREFIX_BEFORE,
PREFIX_AFTER_PROP,
PREFIX_AFTER_COLON,
PREFIX_AFTER_VALUE,
COLON,
UNDEFINED
}
const {parse, tokenize} = require('./parse')
const stringify = require('./stringify')
const {CommentArray, assign} = require('./array')

@@ -7,3 +8,6 @@ module.exports = {

stringify,
tokenize
tokenize,
CommentArray,
assign
}

@@ -5,2 +5,13 @@ // JSON formatting

const {
CommentArray,
PREFIX_BEFORE,
PREFIX_AFTER_PROP,
PREFIX_AFTER_COLON,
PREFIX_AFTER_VALUE,
COLON,
UNDEFINED
} = require('./array')
const tokenize = code => esprima.tokenize(code, {

@@ -11,4 +22,2 @@ comment: true,

const UNDEFINED = undefined
const previous_hosts = []

@@ -51,6 +60,2 @@ let comments_host = 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_VALUE = 'after-value'
const PREFIX_AFTER = 'after'

@@ -63,3 +68,2 @@ const PREFIX_AFTER_ALL = 'after-all'

const CURLY_BRACKET_CLOSE = '}'
const COLON = ':'
const COMMA = ','

@@ -250,3 +254,3 @@ const EMPTY = ''

const parse_array = () => {
const array = []
const array = new CommentArray()
set_comments_host(array)

@@ -253,0 +257,0 @@ set_prop(UNDEFINED, true)

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