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

json5-utils

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

json5-utils - npm Package Compare versions

Comparing version 0.2.1 to 0.3.0

lib/document.js

104

lib/parse.js

@@ -72,4 +72,24 @@ /*

, position = 0
, opt_nullproto = options.duplicate_keys !== 'throw' && options.duplicate_keys !== 'ignore'
var valueStart = function() {}
var valueEnd = function(v) {return v}
if (options._structure) {
;(function() {
var indent
valueStart = function() {
}
valueEnd = function(v) {
if (v === undefined) return undefined
return {
indent: indent,
value: v,
}
}
})()
}
function fail(msg) {

@@ -117,9 +137,12 @@ var column = position - linestart

} else if (chr === '"' || (chr === '\'' && !legacy)) {
return parseString(chr)
valueStart()
return valueEnd(parseString(chr))
} else if (chr === '{') {
return parseObject()
valueStart()
return valueEnd(parseObject())
} else if (chr === '[') {
return parseArray()
valueStart()
return valueEnd(parseArray())

@@ -132,15 +155,19 @@ } else if (chr === '-'

) {
return parseNumber(is_key)
valueStart()
return valueEnd(parseNumber(is_key))
} else if (chr === 'n' && !is_key) {
valueStart()
parseKeyword('null')
return null
return valueEnd(null)
} else if (chr === 't' && !is_key) {
valueStart()
parseKeyword('true')
return true
return valueEnd(true)
} else if (chr === 'f' && !is_key) {
valueStart()
parseKeyword('false')
return false
return valueEnd(false)

@@ -157,2 +184,3 @@ } else if (chr === '/'

// unicode char or a unicode sequence
valueStart()
var rollback = position - 1

@@ -163,5 +191,5 @@ var result = parseIdentifier()

position = rollback
return
return valueEnd(undefined)
} else {
return result
return valueEnd(result)
}

@@ -217,3 +245,3 @@

function parseObject() {
var result = opt_nullproto ? Object.create(null) : {}
var result = options.null_prototype ? Object.create(null) : {}

@@ -248,8 +276,14 @@ while (position < length) {

} else {
Object.defineProperty(result, item1, {
value: item2,
enumerable: true,
configurable: true,
writable: true,
})
if (typeof(options.reviver) === 'function') {
item2 = options.reviver.call(null, item1, item2)
}
if (item2 !== undefined) {
Object.defineProperty(result, item1, {
value: item2,
enumerable: true,
configurable: true,
writable: true,
})
}
}

@@ -291,3 +325,11 @@

if (item !== undefined) {
result.push(item)
if (typeof(options.reviver) === 'function') {
item = options.reviver.call(null, String(result.length), item)
}
if (item === undefined) {
result.length++
item = true // hack for check below, not included into result
} else {
result.push(item)
}
}

@@ -499,2 +541,5 @@

if (result2 === undefined && position >= length) {
if (typeof(options.reviver) === 'function') {
result = options.reviver.call(null, '', result)
}
return result

@@ -510,3 +555,20 @@ } else {

/*
* parse(text, options)
* or
* parse(text, reviver)
*
* where:
* text - string
* options - object
* reviver - function
*/
module.exports.parse = function parseJSON(input, options) {
// support legacy functions
if (typeof(options) === 'function') {
options = {
reviver: options
}
}
if (input === undefined) {

@@ -524,4 +586,10 @@ // parse(stringify(x)) should be equal x

if (options.duplicate_keys === 'throw' || options.duplicate_keys === 'ignore') {
if (options.null_prototype == null) {
options.null_prototype = true
}
}
return parse(input, options)
}

91

lib/stringify.js

@@ -40,3 +40,3 @@ /*

function _stringify(object, options, indentLvl, currentKey) {
function _stringify(object, options, recursiveLvl, currentKey) {
var opt_json = options.mode === 'json'

@@ -64,3 +64,3 @@ /*

var result = ''
var count = indentLvl + (add || 0)
var count = recursiveLvl + (add || 0)
for (var i=0; i<count; i++) result += options.indent

@@ -184,3 +184,3 @@ return result + str + (add ? '\n' : '')

for (var i=0; i<object.length; i++) {
var t = _stringify(object[i], options, indentLvl+1, String(i))
var t = _stringify(object[i], options, recursiveLvl+1, String(i))
if (t === undefined) t = 'null'

@@ -193,11 +193,18 @@ len += t.length + 2

braces = '{}'
for (var key in object) {
if (!hasOwnProperty.call(object, key)) continue
var t = _stringify(object[key], options, indentLvl+1, key)
if (t !== undefined) {
t = _stringify_key(key) + ':' + (options.indent ? ' ' : '') + t + ','
len += t.length + 1
result.push(t)
var fn = function(key) {
if (hasOwnProperty.call(object, key)) {
var t = _stringify(object[key], options, recursiveLvl+1, key)
if (t !== undefined) {
t = _stringify_key(key) + ':' + (options.indent ? ' ' : '') + t + ','
len += t.length + 1
result.push(t)
}
}
}
if (Array.isArray(options.replacer)) {
for (var i=0; i<options.replacer.length; i++) fn(options.replacer[i])
} else {
for (var key in object) fn(key)
}
}

@@ -208,3 +215,4 @@

// anything in the middle depends on indentation level
if (options.indent && (len > 68 - indentLvl * 4 || len > 48) ) {
len -= 2
if (options.indent && (len > options._splitMax - recursiveLvl * options.indent.length || len > options._splitMin) ) {
// remove trailing comma in multiline if asked to

@@ -234,2 +242,6 @@ if (options.no_trailing_comma && result.length) {

function _stringify_nonobject(object) {
if (typeof(options.replacer) === 'function') {
object = options.replacer.call(null, currentKey, object)
}
switch(typeof(object)) {

@@ -272,7 +284,8 @@ case 'string':

if (typeof(object.toJSON5) === 'function' && options.mode !== 'json') {
object = object.toJSON5(currentKey)
var t
if (typeof(t = object.toJSON5) === 'function' && options.mode !== 'json') {
object = t.call(object, currentKey)
} else if (typeof(object.toJSON) === 'function') {
object = object.toJSON(currentKey)
} else if (typeof(t = object.toJSON) === 'function') {
object = t.call(object, currentKey)
}

@@ -292,2 +305,7 @@

} else {
if (typeof(options.replacer) === 'function') {
object = options.replacer.call(null, currentKey, object)
if (typeof(object) !== 'object') return _stringify_nonobject(object)
}
return _stringify_object(object)

@@ -300,4 +318,26 @@ }

module.exports.stringify = function stringifyJSON(object, options) {
if (options == null) options = {}
/*
* stringify(value, options)
* or
* stringify(value, replacer, space)
*
* where:
* value - anything
* options - object
* replacer - function or array
* space - boolean or number or string
*/
module.exports.stringify = function stringifyJSON(object, options, _space) {
// support legacy syntax
if (typeof(options) === 'function' || Array.isArray(options)) {
options = {
replacer: options
}
} else if (typeof(options) === 'object') {
// nothing to do
} else {
options = {}
}
if (_space != null) options.indent = _space
if (options.indent == null) options.indent = '\t'

@@ -319,6 +359,16 @@ if (options.quote == null) options.quote = "'"

// why would anyone use such objects?
if (typeof(options.indent) === 'object') {
if (options.indent.constructor === Number
|| options.indent.constructor === Boolean
|| options.indent.constructor === String)
options.indent = options.indent.valueOf()
}
// gap is capped at 10 characters
if (typeof(options.indent) === 'number') {
if (options.indent >= 0 && options.indent < 11) {
options.indent = Array(~~options.indent+1).join(' ')
if (options.indent >= 0) {
options.indent = Array(Math.min(~~options.indent, 10) + 1).join(' ')
} else {
options.indent = false
}

@@ -329,4 +379,7 @@ } else if (typeof(options.indent) === 'string') {

if (options._splitMin == null) options._splitMin = 50
if (options._splitMax == null) options._splitMax = 70
return _stringify(object, options, 0, '')
}

@@ -1,1 +0,1 @@

{"name":"json5-utils","version":"0.2.1","description":"JSON and JSON5 parsers done right","author":{"name":"Alex Kocharin","email":"alex@kocharin.ru"},"repository":{"type":"git","url":"git://github.com/rlidwka/json5-utils"},"bugs":{"url":"https://github.com/rlidwka/json5-utils/issues"},"main":"parse.js","scripts":{"test":"node test/test.js"},"keywords":["json","json5","parser"],"license":"WTFPL"}
{"name":"json5-utils","version":"0.3.0","description":"JSON/JSON5 parser and serializer","author":{"name":"Alex Kocharin","email":"alex@kocharin.ru"},"repository":{"type":"git","url":"git://github.com/rlidwka/json5-utils"},"bugs":{"url":"https://github.com/rlidwka/json5-utils/issues"},"main":"parse.js","scripts":{"test":"node test/test.js"},"keywords":["json","json5","parser"],"license":"WTFPL"}

@@ -0,2 +1,154 @@

JSON5-utils - JSON/JSON5 parser and serializer for JavaScript.
## Installation
```
npm install json5-utils
```
## Usage
```javascript
var JSON5 = require('json5-utils')
```
### JSON5.parse() function
```javascript
/*
* Main syntax:
*
* `text` - text to parse, type: String
* `options` - parser options, type: Object
*/
JSON5.parse(text[, options])
// compatibility syntax
JSON5.parse(text[, reviver])
```
Options:
- duplicate\_keys - what to do with duplicate keys (String, default="throw")
- "ignore" - ignore duplicate keys, including inherited ones
- "throw" - throw SyntaxError in case of duplicate keys, including inherited ones
- "replace" - replace duplicate keys, this is the default JSON.parse behaviour, unsafe
```javascript
// 'ignore' will cause duplicated keys to be ignored:
parse('{q: 1, q: 2}', {duplicate_keys: 'ignore'}) == {q: 1}
parse('{hasOwnProperty: 1}', {duplicate_keys: 'ignore'}) == {}
parse('{hasOwnProperty: 1, x: 2}', {duplicate_keys: 'ignore'}).hasOwnProperty('x') == true
// 'throw' will cause SyntaxError in these cases:
parse('{q: 1, q: 2}', {duplicate_keys: 'throw'}) == SyntaxError
parse('{hasOwnProperty: 1}', {duplicate_keys: 'throw'}) == SyntaxError
// 'replace' will replace duplicated keys with new ones:
parse('{q: 1, q: 2}', {duplicate_keys: 'throw'}) == {q: 2}
parse('{hasOwnProperty: 1}', {duplicate_keys: 'throw'}) == {hasOwnProperty: 1}
parse('{hasOwnProperty: 1, x: 2}', {duplicate_keys: 'ignore'}).hasOwnProperty('x') == TypeError
```
- null\_prototype - create object as Object.create(null) instead of '{}' (Boolean)
if `duplicate_keys != 'replace'`, default is **false**
if `duplicate_keys == 'replace'`, default is **true**
It is usually unsafe and not recommended to change this option to false in the last case.
- reviver - reviver function - Function
This function should follow JSON specification
### JSON5.stringify() function
```javascript
/*
* Main syntax:
*
* `value` - value to serialize, type: *
* `options` - serializer options, type: Object
*/
JSON5.stringify(value[, options])
// compatibility syntax
JSON5.stringify(value[, replacer [, indent])
```
Options:
- ascii - output ascii only (Boolean, default=false)
If this option is enabled, output will not have any characters except of 0x20-0x7f.
- indent - indentation (String, Number or Boolean, default='\t')
This option follows JSON specification.
- quote - enquoting char (String, "'" or '"', default="'")
- quote\_keys - whether keys quoting in objects is required or not (String, default=false)
If you want `{"q": 1}` instead of `{q: 1}`, set it to true.
- replacer - replacer function or array (Function or Array)
This option follows JSON specification.
- no\_trailing\_comma = don't output trailing comma (Boolean, default=false)
If this option is set, arrays like this `[1,2,3,]` will never be generated. Otherwise they may be generated for pretty printing.
- mode - operation mode, set it to 'json' if you want correct json in the output (String)
Currently it's either 'json' or something else. If it is 'json', following options are implied:
- options.quote = '"'
- options.no\_trailing\_comma = true
- options.quote\_keys = true
- '\x' literals are not used
## Advantages over existing JSON libraries
In a few cases it makes sense to use this module instead of built-in JSON methods.
Parser:
- better error reporting with source code and line numbers
In case of syntax error, JSON.parse does not return any good information to the user. This module does:
```
$ node -e 'require("json5-utils").parse("[1,1,1,1,invalid]")'
SyntaxError: Unexpected token 'i' at 0:9
[1,1,1,1,invalid]
^
```
This module is about 5 times slower, so if user experience matters to you more than performance, use this module. If you're working with a lot of machine-generated data, use JSON.parse instead.
Stringifier:
- util.inspect-like pretty printing
This module behaves more smart when dealing with object and arrays, and does not always print newlines in them:
```
$ node -e 'console.log(require("./").stringify([[,,,],,,[,,,,]], {mode:"json"}))'
[
[null, null, null],
null,
null,
[null, null, null, null]
]
```
JSON.stringify will split this into 15 lines, and it's hard to read.
Yet again, this feature comes with a performance hit, so if user experience matters to you more than performance, use this module. If your JSON will be consumed by machines, use JSON.stringify instead.
As a rule of thumb, if you use "space" argument to indent your JSON, you'd better use this module instead.
## JSON5 syntax
I support slighly modified version of JSON5, see https://groups.google.com/forum/#!topic/json5/3DjClVYI6Wg
I started from ES5 specification and added a set of additional restrictions on top of ES5 spec. So I'd expect my implementation to be much closer to javascript. It's no longer an extension of json, but a reduction of ecmascript, which was my original intent.
This JSON5 version is a subset of ES5 language, specification is here:

@@ -20,2 +172,3 @@

If you're unsure whether a behaviour of this library is a bug or not, you can run this test:

@@ -35,32 +188,7 @@

## Options
parse(string, options):
## Weirdness of JSON5
stringify(object, options):
- ascii - output ascii only (bool, default=false)
- indent - indentation (string or number, default='\t')
- quote - enquoting char (string, "'" or '"', default="'")
These are the parts that I don't particulary like, but see no good way to fix:
## Modes of operation
TODO: not yet working
- simple:
no custom datatypes
no .toJSON/.toJSON5
for serializing simple json-compatible objects only (i.e. user-generated data)
- full
custom datatypes
.toJSON/.toJSON5 present (prototype only)
for representing arbitrary data structures as close as possible
- json:
no custom datatypes
.toJSON present
json compatible
## Weirdness of JSON5
- no elisions, `[,,,] -> [null,null,null]`

@@ -70,5 +198,9 @@ - `[Object], [Circular]` aren't parsed

- unicode property names are way to hard to implement
- Date and other custom objects
- incompatible with YAML (at least comments)
## Unicode support
This version fully support unicode. But if you're writing JSON5 implementation and don't want to support it, you should follow these guidelines:
```javascript

@@ -88,1 +220,2 @@ // 27 whitespace characters (unicode defines 26 characters, and ES5 spec also adds \uFEFF as a whitespace)

@@ -70,1 +70,4 @@

assert.equal(expected, stringify(array, {indent: false}))
assert.strictEqual(stringify([1,2,3], function(){}), undefined)

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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