🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

comment-json

Package Overview
Dependencies
Maintainers
1
Versions
64
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
4.6.2
to
5.0.0
+33
-3
index.d.ts

@@ -64,3 +64,8 @@ // Original from DefinitelyTyped. Thanks a million

export interface CommentToken {
export interface BlankLineToken {
type: 'BlankLine'
inline: false
}
export interface CommentLineToken {
type: 'BlockComment' | 'LineComment'

@@ -78,2 +83,4 @@ /** The content of the comment, including whitespaces and line breaks */

export type CommentToken = BlankLineToken | CommentLineToken
export interface CommentLocation {

@@ -97,2 +104,7 @@ /** The start location begins at the `//` or `/*` symbol */

export interface ParseOptions {
no_comments?: boolean
no_blank_lines?: boolean
}
/**

@@ -108,3 +120,3 @@ * Converts a JavaScript Object Notation (JSON) string into an object.

reviver?: Reviver | null,
removesComments?: boolean
removesComments?: boolean | ParseOptions
): CommentJSONValue

@@ -125,3 +137,3 @@

reviver?: Reviver | null,
removesComments?: boolean
removesComments?: boolean | ParseOptions
): T

@@ -203,1 +215,19 @@

): void
/**
* Remove blank lines from all comment positions recursively.
* @param target The target object to remove blank lines from
*/
export function removeBlankLines(
target: CommentJSONValue
): void
/**
* Remove blank lines from a specific location.
* @param target The target object to remove blank lines from
* @param location The comment location to remove blank lines from
*/
export function removeBlankLines(
target: CommentJSONValue,
location: CommentPosition
): void
+1
-1
{
"name": "comment-json",
"version": "4.6.2",
"version": "5.0.0",
"description": "Parse and stringify JSON with comments. It will retain comments even after saved!",

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

@@ -35,2 +35,3 @@ [![Build Status](https://github.com/kaelzhang/node-comment-json/actions/workflows/nodejs.yml/badge.svg)](https://github.com/kaelzhang/node-comment-json/actions/workflows/nodejs.yml)

- [removeComments](#removecommentstarget-object-location-object)
- [removeBlankLines](#removeblanklinestarget-object-location-object)
- [CommentArray](#commentarray)

@@ -80,3 +81,4 @@ - [Change Logs](https://github.com/kaelzhang/node-comment-json/releases)

moveComments,
removeComments
removeComments,
removeBlankLines
} = require('comment-json')

@@ -129,3 +131,10 @@ const fs = require('fs')

```ts
parse(text, reviver? = null, remove_comments? = false)
parse(
text,
reviver? = null,
options? = false | {
no_comments?: boolean,
no_blank_lines?: boolean
}
)
: object | string | number | boolean | null

@@ -137,3 +146,6 @@ ```

- `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.
- **options?** `boolean | object = false`
- passing `true` is the backward-compatible shorthand of `{ no_comments: true }`
- **options.no_comments?** `boolean = false` If true, `LineComment` and `BlockComment` tokens won't be maintained.
- **options.no_blank_lines?** `boolean = false` If true, `BlankLine` tokens won't be generated.

@@ -288,3 +300,10 @@ Returns `CommentJSONValue` (`object | string | number | boolean | null`) corresponding to the given JSON text.

```ts
interface CommentToken {
type CommentToken = BlankLineToken | CommentLineToken
interface BlankLineToken {
type: 'BlankLine'
inline: false
}
interface CommentLineToken {
type: 'BlockComment' | 'LineComment'

@@ -297,4 +316,5 @@ // The content of the comment, including whitespaces and line breaks

// But pay attention that,
// locations will NOT be maintained when stringified
// `loc` is kept for real comments only.
// It will NOT be maintained when stringified, and blank lines are rendered
// from explicit `BlankLine` tokens instead of inferred from `loc`.
loc: CommentLocation

@@ -316,2 +336,5 @@ }

Each physical empty line is represented by an explicit `BlankLine` token, so
`stringify()` no longer infers empty lines from `loc`.
### Query comments in TypeScript

@@ -337,6 +360,9 @@

### Parse into an object without comments
### Parse into an object without comments and/or blank lines
```js
console.log(parse(content, null, true))
console.log(parse(content, null, {
no_comments: true,
no_blank_lines: true
}))
```

@@ -368,3 +394,3 @@

If we parse a JSON of primative type with `remove_comments:false`, then the return value of `parse()` will be of object type.
If we parse a JSON of primative type with `no_comments:false`, then the return value of `parse()` will be of object type.

@@ -679,2 +705,52 @@ The value of `parsed` is equivalent to:

## removeBlankLines(target: object, location?: object)
- **target** `object` The target object to remove blank lines from.
- **location?** `object` Optional specific comment location to clean.
- **location.where** `CommentPrefix` The comment position (e.g., 'before', 'after', 'before-all', etc.).
- **location.key?** `string` The property key for property-specific comments. Omit for non-property comments.
This method removes only `BlankLine` tokens. Real comments stay in place.
### Remove blank lines recursively
```js
const {parse, stringify, removeBlankLines} = require('comment-json')
const obj = parse(`{
// before foo
"foo": 1,
"bar": 2
}`)
removeBlankLines(obj)
console.log(stringify(obj, null, 2))
// {
// // before foo
// "foo": 1,
// "bar": 2
// }
```
### Remove blank lines from one location
```js
const obj = parse(`{
// before foo
"foo": 1
}`)
removeBlankLines(obj, { where: 'before', key: 'foo' })
console.log(stringify(obj, null, 2))
// {
// // before foo
// "foo": 1
// }
```
## `CommentArray`

@@ -681,0 +757,0 @@

@@ -38,4 +38,2 @@ const PREFIX_BEFORE = 'before'

const LINE_BREAKS_BEFORE = new WeakMap()
const LINE_BREAKS_AFTER = new WeakMap()
const RAW_STRING_LITERALS = new WeakMap()

@@ -192,2 +190,59 @@

const is_comment_symbol = subject => {
const key = Symbol.keyFor(subject)
return is_string(key)
&& (
NON_PROP_SYMBOL_PREFIXES.includes(key)
|| PROP_SYMBOL_PREFIXES.some(prefix => key.indexOf(prefix + COLON) === 0)
)
}
const remove_blank_line_tokens = comments => {
let write = 0
let removed = false
comments.forEach(comment => {
if (comment && comment.type === 'BlankLine') {
removed = true
return
}
comments[write ++] = comment
})
comments.length = write
return removed
}
const remove_blank_lines_from_prop = (target, prop) => {
if (!Object.hasOwn(target, prop)) {
return
}
const comments = target[prop]
if (!Array.isArray(comments) || !remove_blank_line_tokens(comments)) {
return
}
if (!comments.length) {
delete target[prop]
}
}
const remove_blank_lines_deep = target => {
Object.getOwnPropertySymbols(target).forEach(prop => {
if (is_comment_symbol(prop)) {
remove_blank_lines_from_prop(target, prop)
}
})
Object.keys(target).forEach(key => {
const value = target[key]
if (is_object(value)) {
remove_blank_lines_deep(value)
}
})
}
const is_raw_json = typeof JSON.isRawJSON === 'function'

@@ -200,15 +255,2 @@ // For backward compatibility,

const set_comment_line_breaks = (comment, before, after) => {
if (is_number(before) && before >= 0) {
LINE_BREAKS_BEFORE.set(comment, before)
}
if (is_number(after) && after >= 0) {
LINE_BREAKS_AFTER.set(comment, after)
}
}
const get_comment_line_breaks_before = comment => LINE_BREAKS_BEFORE.get(comment)
const get_comment_line_breaks_after = comment => LINE_BREAKS_AFTER.get(comment)
module.exports = {

@@ -251,5 +293,2 @@ PROP_SYMBOL_PREFIXES,

get_raw_string_literal,
set_comment_line_breaks,
get_comment_line_breaks_before,
get_comment_line_breaks_after,

@@ -433,3 +472,35 @@ /**

delete target[prop]
},
/**
* Remove blank lines from a specific location or recursively from an object.
*
* @param {Object} target The target object to remove blank lines from.
* @param {Object} [location] The comment location to remove blank lines from.
* @param {string} location.where The comment position (e.g., 'before',
* 'after', 'before-all', etc.).
* @param {string} [location.key] The property key for property-specific
* comments. Omit for non-property comments.
*
* @throws {TypeError} If target is not an object.
* @throws {RangeError} If where parameter is invalid or incompatible with key.
*/
removeBlankLines (target, location) {
if (!is_object(target)) {
throw new TypeError('target must be an object')
}
if (location === UNDEFINED) {
remove_blank_lines_deep(target)
return
}
const {
where,
key
} = location
const prop = symbol_checked(where, key)
remove_blank_lines_from_prop(target, prop)
}
}

@@ -16,3 +16,4 @@ const {parse, tokenize} = require('./parse')

moveComments,
removeComments
removeComments,
removeBlankLines
} = require('./common')

@@ -37,3 +38,4 @@

moveComments,
removeComments
removeComments,
removeBlankLines
}

@@ -34,3 +34,2 @@ // JSON formatting

set_raw_string_literal,
set_comment_line_breaks,
assign_non_prop_comments

@@ -64,2 +63,3 @@ } = require('./common')

let remove_comments = false
let remove_blank_lines = false
let inline = false

@@ -71,2 +71,3 @@ let tokens = null

let reviver = null
let source_line_count = 0

@@ -80,2 +81,3 @@ const clean = () => {

last_prop = UNDEFINED
remove_blank_lines = false
}

@@ -96,2 +98,3 @@

current_code = UNDEFINED
source_line_count = 0
}

@@ -172,2 +175,39 @@

const create_blank_line = () => ({
type: 'BlankLine',
inline: false
})
const append_blank_lines = (comments, from_line, to_line) => {
if (remove_blank_lines) {
return
}
let blank_lines = Math.max(0, to_line - from_line - 1)
while (blank_lines -- > 0) {
comments.push(create_blank_line())
}
}
const normalize_parse_options = options => {
if (typeof options === 'boolean') {
return {
no_comments: options,
no_blank_lines: false
}
}
if (!is_object(options)) {
return {
no_comments: false,
no_blank_lines: false
}
}
return {
no_comments: !!options.no_comments,
no_blank_lines: !!options.no_blank_lines
}
}
const assign_after_comments = () => {

@@ -217,2 +257,5 @@ if (!unassigned_comments) {

const comments = []
let previous_line = last
? last.loc.end.line
: 0

@@ -226,2 +269,4 @@ while (

) {
append_blank_lines(comments, previous_line, current.loc.start.line)
const comment = {

@@ -231,14 +276,4 @@ ...current,

}
const previous_line = last
? last.loc.end.line
: 1
set_comment_line_breaks(
comment,
Math.max(0, comment.loc.start.line - previous_line)
)
// delete comment.loc
comments.push(comment)
previous_line = comment.loc.end.line

@@ -248,22 +283,19 @@ next()

const {length} = comments
if (length) {
const comment = comments[length - 1]
const current_line = current
append_blank_lines(
comments,
previous_line,
current
? current.loc.start.line
: comment.loc.end.line
: source_line_count
)
set_comment_line_breaks(
comment,
undefined,
Math.max(0, current_line - comment.loc.end.line)
)
}
if (remove_comments) {
return
for (let i = comments.length - 1; i >= 0; i --) {
if (comments[i].type !== 'BlankLine') {
comments.splice(i, 1)
}
}
}
if (!length) {
if (!comments.length) {
return

@@ -497,10 +529,17 @@ }

*/
const parse = (code, rev, no_comments) => {
const parse = (code, rev, options) => {
// Clean variables in closure
clean()
const {
no_comments,
no_blank_lines
} = normalize_parse_options(options)
current_code = code
source_line_count = code.split('\n').length
tokens = tokenize(code)
reviver = rev
remove_comments = no_comments
remove_blank_lines = no_blank_lines

@@ -507,0 +546,0 @@ if (!tokens.length) {

@@ -25,5 +25,2 @@ const {

get_raw_string_literal,
get_comment_line_breaks_before,
get_comment_line_breaks_after,
is_raw_json

@@ -49,40 +46,17 @@ } = require('./common')

const repeat_line_breaks = (line_breaks, gap) => (LF + gap).repeat(line_breaks)
const read_line_breaks = line_breaks => is_number(line_breaks) && line_breaks >= 0
? line_breaks
: null
const read_line_breaks_from_loc = (previous_comment, comment) => {
if (
!previous_comment
|| !previous_comment.loc
|| !comment.loc
) {
return null
}
const is_inline_whitespace = char => char === SPACE || char === '\t'
const count_trailing_line_breaks = str => {
let i = str.length
let count = 0
const {end} = previous_comment.loc
const {start} = comment.loc
while (i > 0) {
while (i > 0 && is_inline_whitespace(str[i - 1])) {
i --
}
if (
!end
|| !start
|| !is_number(end.line)
|| !is_number(start.line)
) {
return null
}
if (i === 0 || str[i - 1] !== LF) {
return count
}
const line_breaks = start.line - end.line
return line_breaks >= 0
? line_breaks
: null
}
const count_trailing_line_breaks = (str, gap) => {
const unit = LF + gap
const {length} = unit
let i = str.length
let count = 0
while (i >= length && str.slice(i - length, i) === unit) {
i -= length
i --
count ++

@@ -103,5 +77,11 @@ }

let str = EMPTY
let blank_lines = 0
let last_comment = null
comments.forEach((comment, i) => {
if (comment.type === 'BlankLine') {
blank_lines ++
return
}
const {

@@ -113,16 +93,6 @@ inline,

let line_breaks_before = read_line_breaks(
get_comment_line_breaks_before(comment)
)
const line_breaks_before = blank_lines > 0
? blank_lines + (inline ? 0 : 1)
: null
if (line_breaks_before === null) {
line_breaks_before = read_line_breaks_from_loc(last_comment, comment)
}
if (line_breaks_before === null) {
line_breaks_before = inline
? 0
: 1
}
const delimiter = line_breaks_before > 0

@@ -133,3 +103,3 @@ ? repeat_line_breaks(line_breaks_before, deeper_gap)

// The first comment at the very beginning of the source.
: i === 0
: i === 0 && symbol_tag === PREFIX_BEFORE_ALL && deeper_gap === EMPTY
? EMPTY

@@ -142,5 +112,12 @@ : LF + deeper_gap

blank_lines = 0
last_comment = comment
})
if (!last_comment) {
return blank_lines
? repeat_line_breaks(blank_lines + 1, deeper_gap)
: EMPTY
}
const default_line_breaks_after = display_block

@@ -152,6 +129,5 @@ // line comment should always end with a LF

const line_breaks_after = Math.max(
default_line_breaks_after,
read_line_breaks(get_comment_line_breaks_after(last_comment)) || 0
)
const line_breaks_after = blank_lines > 0
? blank_lines + 1
: default_line_breaks_after

@@ -178,3 +154,3 @@ return str + repeat_line_breaks(line_breaks_after, deeper_gap)

: one.trimRight() + repeat_line_breaks(
Math.max(1, count_trailing_line_breaks(one, gap)),
Math.max(1, count_trailing_line_breaks(one)),
gap

@@ -184,3 +160,3 @@ )

? two.trimRight() + repeat_line_breaks(
Math.max(1, count_trailing_line_breaks(two, gap)),
Math.max(1, count_trailing_line_breaks(two)),
gap

@@ -412,2 +388,7 @@ )

const normalize_blank_lines = str =>
typeof str === 'string'
? str.replace(/\n[ \t]+(?=\n)/g, '\n')
: str
/**

@@ -469,3 +450,3 @@ * Converts a JavaScript value to a JavaScript Object Notation (JSON) string

return is_object(value)
const output = is_object(value)
? process_comments(value, PREFIX_BEFORE_ALL, EMPTY, true).trimLeft()

@@ -475,2 +456,4 @@ + str

: str
return normalize_blank_lines(output)
}