🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

jju

Package Overview
Dependencies
Maintainers
1
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jju - npm Package Compare versions

Comparing version
1.2.0
to
1.2.1
+1
-1
package.json

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

{"name":"jju","version":"1.2.0","description":"a set of utilities to work with JSON / JSON5 documents","author":{"name":"Alex Kocharin","email":"alex@kocharin.ru"},"repository":{"type":"git","url":"git://github.com/rlidwka/jju"},"bugs":{"url":"https://github.com/rlidwka/jju/issues"},"homepage":"http://rlidwka.github.io/jju/","devDependencies":{"mocha":">=1.21.0","js-yaml":">=3.1.0","eslint":"~0.4.2"},"scripts":{"test":"mocha test/*.js","lint":"eslint -c ./.eslint.yaml ./lib"},"keywords":["json","json5","parser","serializer","data"],"publishConfig":{"registry":"https://registry.npmjs.org/"},"license":{"type":"WTFPL","url":"http://www.wtfpl.net/txt/copying/"}}
{"name":"jju","version":"1.2.1","description":"a set of utilities to work with JSON / JSON5 documents","author":{"name":"Alex Kocharin","email":"alex@kocharin.ru"},"repository":{"type":"git","url":"git://github.com/rlidwka/jju"},"bugs":{"url":"https://github.com/rlidwka/jju/issues"},"homepage":"http://rlidwka.github.io/jju/","devDependencies":{"mocha":">=1.21.0","js-yaml":">=3.1.0","eslint":"~0.4.2"},"scripts":{"test":"mocha test/*.js","lint":"eslint -c ./.eslint.yaml ./lib"},"keywords":["json","json5","parser","serializer","data"],"publishConfig":{"registry":"https://registry.npmjs.org/"},"license":{"type":"WTFPL","url":"http://www.wtfpl.net/txt/copying/"}}

@@ -6,3 +6,3 @@ # use "yapm install ." if you're installing this from git repository

version: 1.2.0
version: 1.2.1
description: a set of utilities to work with JSON / JSON5 documents

@@ -9,0 +9,0 @@

root = true
[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
[{.,}*.{js,json,json5,yml,yaml}]
indent_style = space
indent_size = 2
[*.md]
indent_style = space
indent_size = 4
trim_trailing_whitespace = false
[Makefile]
indent_style = tab
#!/usr/bin/env node
var Benchmark = require('benchmark')
var YAML = require('js-yaml')
var JJU = require('../')
var JSON5 = require('json5')
var suite = new Benchmark.Suite
var sample
sample = require('fs').readFileSync(__dirname + '/../package.yaml')
sample = YAML.safeLoad(sample)
sample = JSON.stringify(sample)
var functions = {
'JSON': function(x) { JSON.parse(x) },
'JSON5': function(x) { JSON5.parse(x) },
'JJU': function(x) { JJU.parse(x) },
'JS-YAML': function(x) { YAML.safeLoad(x) },
}
for (var name in functions) {
with ({ fn: functions[name] }) {
suite.add(name, {
onCycle: function onCycle(event) {
process.stdout.write('\r\033[2K - ' + event.target)
},
fn: function () {
fn(sample)
},
})
}
}
console.log()
suite.on('cycle', function(event) {
console.log('\r\033[2K + ' + String(event.target))
})
.run()
process.on('exit', function() { console.log() })
{
"name": "benchmarks",
"private": true,
"dependencies": {
"json5": "*",
"js-yaml": "*",
"benchmark": "*"
}
}
JSON5 grammar expressed in EBNF form.
PS: I don't know what is appropriate syntax highlighter for this, so I'm using "modula2" because why not. I also inserted <ZWSP> after backslash to preserve syntax highlighting, this character has nothing to do with actual JSON5 syntax and should be ignored.
```modula2
json5_text = expression_with_whitespace
expression_with_whitespace = [white_space] , expression , [white_space]
expression = literal
| array_literal
| object_literal
literal = null_literal
| boolean_literal
| signed_numeric_literal
| string_literal
null_literal = 'null'
boolean_literal = 'true'
| 'false'
(* Source Characters *)
source_character = .
(* any Unicode code unit *)
line_terminator = <LF>
| <CR>
| <LS>
| <PS>
line_terminator_sequence = <LF>
| <CR>
| <LS>
| <PS>
| <CR> , <LF>
white_space = white_space_element
| white_space , white_space_element
white_space_element = white_space_character
| comment
white_space_character = <TAB>
| <VT>
| <FF>
| <SP>
| <NBSP>
| <BOM>
| <USP>
comment = multi_line_comment
| single_line_comment
multi_line_comment = '/*' , [multi_line_comment_chars] , '*/'
multi_line_comment_chars = (source_character - '*') , [multi_line_comment_chars]
| '*' , [post_asterisk_comment_chars]
post_asterisk_comment_chars = (source_character - ('*' | '/')) , [multi_line_comment_chars]
| '*' , [post_asterisk_comment_chars]
single_line_comment = '//' , [single_line_comment_chars]
single_line_comment_chars = single_line_comment_char , single_line_comment_chars
single_line_comment_char = source_character - line_terminator
(* Character classes *)
decimal_digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
non_zero_digit = decimal_digit - '0'
hex_digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 'a'
| 'b' | 'c' | 'd' | 'e' | 'f' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
ascii_letter = ascii_letter_lowercase
| ascii_letter_uppercase
ascii_letter_lowercase = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i'
| 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r'
| 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z'
ascii_letter_uppercase = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I'
| 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R'
| 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z'
(* Numeric Literals *)
signed_numeric_literal = '-' , numeric_literal
| '+' , numeric_literal
| numeric_literal
numeric_literal = decimal_literal
| hex_integer_literal
| non_finite_literal
non_finite_literal = 'Infinity'
| 'NaN'
decimal_literal = decimal_integer_literal , '.' , [decimal_digits] , [exponent_part]
| '.' , decimal_digits , [exponent_part]
| decimal_integer_literal , [exponent_part]
decimal_integer_literal = '0'
| non_zero_digit , [decimal_digits]
decimal_digits = decimal_digit
| decimal_digits , decimal_digit
exponent_part = exponent_indicator , signed_integer
exponent_indicator = 'e' | 'E'
signed_integer = decimal_digits
| '+' , decimal_digits
| '-' , decimal_digits
hex_integer_literal = '0x' , hex_digit
| '0X' , hex_digit
| hex_integer_literal , hex_digit
(* String Literals *)
string_literal = '"' , [double_string_characters] , '"'
| "'" , [single_string_characters] , "'"
double_string_characters = double_string_character , [double_string_characters]
single_string_characters = single_string_character , [single_string_characters]
double_string_character = source_character - ('"' | '\​' | line_terminator)
| '\​' , escape_sequence
| line_continuation
single_string_character = source_character - ("'" | '\​' | line_terminator)
| '\​' , escape_sequence
| line_continuation
line_continuation = '\​' , line_terminator_sequence
escape_sequence = character_escape_sequence
| '0'
| hex_escape_sequence
| unicode_escape_sequence
character_escape_sequence = single_escape_character
| non_escape_character
single_escape_character = '"' | "'" | '\​' | 'b' | 'f' | 'n' | 'r' | 't' | 'v'
non_escape_character = source_character - (escape_character | line_terminator)
escape_character = single_escape_character
| decimal_digit
| 'x'
| 'u'
hex_escape_sequence = 'x' , hex_digit , hex_digit
unicode_escape_sequence = 'u' , hex_digit , hex_digit , hex_digit , hex_digit
(* Array Literals *)
array_literal = '[' , [white_space] , ']'
| '[' , [white_space] , element_list , ']'
| '[' , [white_space] , element_list , ',' , [white_space] , ']'
element_list = expression , [white_space]
| element_list , ',' , [white_space] , expression , [white_space]
(* Object Literals *)
object_literal = '{' , [white_space] , '}'
| '{' , [white_space] , property_name_and_value_list , '}'
| '{' , [white_space] , property_name_and_value_list , ',' , '}'
property_name_and_value_list = property_assignment , [white_space]
| property_name_and_value_list , [white_space] , ',' , [white_space] , property_assignment , [white_space]
property_assignment = property_name , [white_space] , ':' , [white_space] , expression
property_name = identifier_name
| string_literal
| numeric_literal
identifier_name = identifier_start
| identifier_name , identifier_part
identifier_start = unicode_letter
| '$'
| '_'
| '\​' , unicode_escape_sequence
identifier_part = identifier_start
| unicode_combining_mark
| unicode_digit
| unicode_connector_punctuation
| <ZWNJ>
| <ZWJ>
unicode_letter = ascii_letter
(* + any character in the Unicode categories "Uppercase letter (Lu)", "Lowercase letter (Ll)", "Titlecase letter (Lt)", "Modifier letter (Lm)", "Other letter (Lo)", or "Letter number (Nl)" *)
unicode_combining_mark =
(* + any character in the Unicode categories "Non-spacing mark (Mn)" or "Combining spacing mark (Mc)" *)
unicode_digit = decimal_digit
(* + any character in the Unicode category "Decimal number (Nd)" *)
unicode_connector_punctuation =
(* + any character in the Unicode category "Connector punctuation (Pc)" *)
```
## JSON5 syntax
We 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:
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
This is a language that defines data structures only, so following notes/restrictions are applied:
- Literals (NullLiteral, BooleanLiteral, NumericLiteral, StringLiteral) are allowed.
- Compatibility syntax is not supported, which means octal literals are forbidden.
- ArrayLiterals and allowed, but instead of AssignmentExpressions you can only use other allowed Literals, ArrayLiterals and ObjectLiterals. Elisions are currently not supported.
- ObjectLiterals and allowed, but instead of AssignmentExpressions you can only use other allowed Literals, ArrayLiterals and ObjectLiterals. Setters and getters are forbidden.
- All other primary expressions ("this", Identifier, Expression) are forbidden.
- Two unary expressions ('-' and '+') allowed before NumericLiterals.
- Any data that has a number type can be represented, including +0, -0, +Infinity, -Infinity and NaN.
- "undefined" is forbidden, use null instead if applicable.
- Comments and whitespace are defined according to spec.
Main authority here is ES5 spec, so strict backward JSON compatibility is not guaranteed.
If you're unsure whether a behaviour of this library is a bug or not, you can run this test:
```javascript
JSON5.parse(String(something))
```
Should always be equal to:
```javascript
eval('(function(){return ('+String(something)+'\n)\n})()')
```
If `something` meets all rules above. Parens and newlines in the example above are carefully placed so comments and another newlines will work properly, so don't look so impressed about that.
## Weirdness of JSON5
These are the parts that I don't particulary like, but see no good way to fix:
- no elisions, `[,,,] -> [null,null,null]`
- `[Object], [Circular]` aren't parsed
- no way of nicely representing multiline strings
- unicode property names are way to hard to implement
- Date and other custom objects
- incompatible with YAML (at least comments)
# vi:set ts=2 sts=2 sw=2 et:
#
# Copyright (c) JD 2456730 Alex Kocharin <alex@kocharin.ru>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# The original file is available here:
# https://github.com/rlidwka/jju/tree/master/test/portable-json5-tests.yaml
#
# ----------------------------------------------------------------------------
#
# Portable JSON5 test suite.
#
# This file contains an actual YAML data and it may include fancy syntax.
# If your platform does not support YAML, you might wish to pre-process it
# using a generic YAML parser.
#
%YAML 1.2
---
#
# "input" is an arbitrary JSON5 you have to parse
# "output" is a normalized JSON you have to compare your result with,
# or !error (null) if your input should result in parser error
#
# Types of tests:
#
# - basic - Tests that every JSON5 parser should pass.
#
# - advanced - Tests that bring close compatibility with javascript. Not
# strictly required, but nice to have for completeness.
#
# - extra - Extra test cases you can follow at your discretion.
#
# Questionable features like elisions go to extra. All valid javascript, but
# invalid json5 also goes to extra. Feel free to ignore this section if you
# want to. Thus, eval(input) is a complete json5 parser, that should pass all
# basic and advanced tests.
#
# Basic types in minimal form
# ---------------------------
type-no-data:
type: extra
output: !error
input: ''
type-null:
type: basic
output: null
input: >
null
# undefined is not supported,
# null should be used instead
type-no-undefined:
type: extra
output: !error
input: >
undefined
type-no-raw:
type: extra
output: !error
input: >
foobar
type-bool-true:
type: basic
output: true
input: >
true
type-bool-false:
type: basic
output: false
input: >
false
type-number:
type: basic
output: 0
input: >
0
type-string:
type: basic
output: ""
input: >
""
type-object:
type: basic
output: {}
input: >
{}
type-array:
type: basic
output: []
input: >
[]
# Numbers: special
# ----------------
# note: it's hard to test this
# just add `1/x < 0` check in your code somewhere
num-negative-zero:
type: extra
output: -0.0
input: >
-0
num-nan:
type: basic
output: .nan
input: >
NaN
num-signed-nan:
type: basic
output: .nan
input: >
+NaN
num-positive-inf:
type: basic
output: +.inf
input: >
Infinity
num-negative-inf:
type: basic
output: -.inf
input: >
-Infinity
num-inf-exact-case:
type: extra
output: !error
input: >
INFINITY
# Numbers: hexadecimal
# --------------------
num-hex-zero:
type: basic
output: 0
input: >
0x0
num-cut-hex:
type: basic
output: !error
input: >
0x
num-all-hex:
type: basic
output: 12841684683518
input: >
0xBADF00DCAFE
num-mixed-case:
type: basic
output: 3735928559
input: >
0xDeAdBEef
num-signed-hex:
type: advanced
output: 31
input: >
+0x1F
num-negative-hex:
type: advanced
output: -31
input: >
-0x1f
num-bad-hex:
type: advanced
output: !error
input: >
0xBADxF00D
num-no-hex-float:
type: advanced
output: !error
input: >
0x12.345
# this is not actually an exponent :)
num-hex-exponent:
type: advanced
output: 4836
input: >
0x0012e4
# Numbers: octal
# --------------
# Octals are primarily used in config files
# to set up a file mask (like 0777)
#
# Note: they will have 0o12345 syntax instead
# of 012345 in the ES6, so we'll need to switch
# as well in the future
num-octal:
type: extra
output: 342391
input: >
01234567
num-octal-zeroes:
type: extra
output: -24000
input: >
-000000056700
num-bad-octal:
type: extra
output: !error
input: >
012345678
num-no-octal-float:
type: extra
output: !error
input: >
012.345
num-no-octal-exp:
type: extra
output: !error
input: >
0123e4
# Numbers: floating point
# -----------------------
num-float:
type: basic
output: 123.456
input: >
123.456
num-signed-foat:
type: basic
output: -0.00098765
input: >
-0.00098765
num-omit-trailing-mantissa:
type: basic
output: 1234000
input: >
1234.e3
num-omit-leading-mantissa:
type: advanced
output: -123.4
input: >
-.1234e3
num-bad-float:
type: advanced
output: !error
input: >
0.12.345
num-bad-sum:
type: extra
output: !error
input: >
0.12+345
num-uc-exp:
type: advanced
output: -1230000
input: >
-123E+4
num-float-exp:
type: basic
output: 123000
input: >
0.0123e7
num-bad-exp:
type: extra
output: !error
input: >
123e7.3
num-bad-char:
type: extra
output: !error
input: >
123a456
num-no-exp:
type: advanced
output: !error
input: >
123e
num-zero-exp:
type: advanced
output: -0.0
input: >
-.00e-0
num-dec-base-signed-exp:
type: advanced
output: 0.00000123
input: >
1230000E-012
# String: quotes
# --------------
string-double-quotes:
type: basic
output: foobar
input: >
"foobar"
string-single-quotes:
type: basic
output: foobar
input: >
'foobar'
string-open:
type: basic
output: !error
input: >
"\\\\\\\\\\\\\"
string-not-open:
type: basic
output: "\\\\\\\\\\\\\\"
input: >
"\\\\\\\\\\\\\\"
string-continuation:
type: advanced
output: " foo bar "
input: >
" foo \
bar \
"
string-win-continuation:
type: advanced
output: "foobar"
input: "'foo\\\r\nbar'"
string-win-reverse-continuation:
type: advanced
output: !error
input: "'foo\\\n\rbar'"
string-unicode-continuation:
type: advanced
output: "foobarbaz"
input: "'foo\\\u2028bar\\\u2029baz'"
string-multi-bad-continuation:
type: advanced
output: !error
input: >
foo\
bar
string-bad-ending:
type: basic
output: !error
input: "'foo\rbar'"
string-bad-ending-2028:
type: advanced
output: !error
input: "'foo\u2028bar'"
string-bad-ending-2029:
type: advanced
output: !error
input: "'foo\u2029bar'"
string-literal-unicode:
type: advanced
output: "foo\uFEFF\u2030bar\u1234"
input: "'foo\uFEFF\u2030bar\u1234'"
string-control-char:
type: advanced
output: "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f"
input: "'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f'"
# String: escape sequences
# ------------------------
string-octal-escape:
type: extra
output: "\x1b[1;32mhi\x1b[m??"
input: >
'\033[1;32mhi\033[m\077\077'
string-octal-two-digits:
type: extra
output: "\n\x1c\x2e\x07890\x01"
input: >
'\12\34\56\78\90\1'
string-octal-three-digits:
type: extra
output: "\n34.78\xff 0"
input: >
'\01234\5678\377\400'
string-hex-escape:
type: extra
output: "\x01\x23\xab\xcd\xef"
input: >
"\x01\x23\xab\xCd\xEF"
# \0 is *not* an octal escape sequence,
# and is allowed even in strict mode
string-zero-point:
type: basic
output: "\0"
input: >
'\0'
string-escape-double-quotes:
type: basic
output: "\"''"
input: >
"\"'\'"
string-escape-single-quotes:
type: basic
output: " '\"\" "
input: >
' \'"\" '
string-escape-json-chars:
type: basic
output: "\\\/\b\f\n\r\t"
input: >
"\\\/\b\f\n\r\t"
# this character was left out of
# json spec for whatever reason
string-escape-slash-v:
type: basic
output: "\v"
input: >
"\v"
string-unicode-escape:
type: basic
output: "\u0000\uffffx\ufeff\u1234\u9f6a\u2028\uabcd"
input: >
"\u0000\uFFFFx\uFeFf\u1234\u9F6a\u2028\uabcd"
string-arbitrary-escape:
type: advanced
output: "X12Uqwe\r\tyiopasd\fghjklzc\u000b\b\nm9 "
input: >
'\X12\U\q\w\e\r\t\y\i\o\p\a\s\d\f\g\h\j\k\l\z\c\v\b\n\m\9\ '
string-bad-unicode:
type: advanced
output: !error
input: >
'\uEFGH'
string-incomplete-unicode:
type: advanced
output: !error
input: >
'\u$'
string-bad-hex:
type: advanced
output: !error
input: >
'\xFG'
string-incomplete-hex:
type: advanced
output: !error
input: >
'\x$'
# Object literals
# ---------------
object-nested:
type: basic
output: {q:{'w':{"e":[1]}}}
input: |
{q:{'w':{"e":[1]}}}
object-trailing-comma:
type: basic
output: {foo: 'bar'}
input: |
{foo: 'bar',}
object-leading-comma-style:
type: basic
output: {q: 1,w: 2,e: 3}
input: |
{ q: 1
, w: 2
, e: 3
}
object-incomplete:
type: basic
output: !error
input: |
{q:1,w:2,{}
object-isnt-array:
type: basic
output: !error
input: |
{1,2}
object-no-single-comma:
type: basic
output: !error
input: |
{,}
object-no-elisions:
type: basic
output: !error
input: |
{q:1,,w:2}
# Objects: keys
# -------------
object-singlequoted:
type: basic
output: {q: 1,w: 2,e: 3}
input: |
{'q':1,'w':2,'e':3}
object-doublequoted:
type: basic
output: {q: 1,w: 2,e: 3}
input: |
{"q":1,"w":2,"e":3}
object-unquoted:
type: basic
output: {$FOO_bar123: 'baz'}
input: >
{$FOO_bar123: 'baz'}
object-no-first-digit:
type: advanced
output: !error
input: >
{123foo: bar}
object-unquoted-unicode:
type: advanced
output: {"\u1f04\u03bb\u03c6\u03b1": baz}
input: "{\u1f04\u03bb\u03c6\u03b1:'baz'}"
object-unicode-escape-key:
type: advanced
output: {foo: 'bar', "\u1f04\u03bb\u03c6\u03b1": baz, "qwe\u1f04rty": quux}
input: |
{foo:'bar', \u1f04\u03bb\u03c6\u03b1:'baz', qwe\u1f04rty: "quux"}
object-no-raw-literal:
type: extra
output: !error
input: |
{foo: bar}
object-bad-literal:
type: advanced
output: !error
input: |
{foo-bar: 123}
object-no-space-in-key:
type: advanced
output: !error
input: |
{foo bar: 123}
object-no-comment-in-key:
type: advanced
output: !error
input: |
{foo/*bar*/baz: 123}
object-float-keys:
type: advanced
output: {'1': 'one', '3.1415': 'pi'}
input: |
{1:'one', 3.1415:'pi'}
object-no-negative:
type: advanced
output: !error
input: |
{-5: 123}
object-exponent-keys:
type: advanced
output: {'1': 'exp', '1000': 'pos', '0.001': 'neg'}
input: |
{1e0: 'exp', 1e+3: 'pos', 1e-3: 'neg'}
object-octal-keys:
type: extra
output: {'668': 1}
input: |
{01234: 1}
object-hex-keys:
type: advanced
output: {'51966': 1}
input: |
{0xCAFE: 1}
object-null-keys:
type: basic
output: {'null': null}
input: |
{null: null}
object-no-array-keys:
type: extra
output: !error
input: |
{[]: 123}
object-no-empty-keys:
type: basic
output: !error
input: |
{: 123}
object-empty-string-key:
type: basic
output: {s: {'': 1}, m: {'': 2}}
input: |
{s: {'': 1}, m: {"": 2}}
object-bad-unicode-space:
type: advanced
output: !error
input: |
{ \u0020foobar: 123 }
object-bad-unicode-dash:
type: advanced
output: !error
input: |
{ foo\u002dbar: 123}
object-incomplete-unicode-sequence:
type: advanced
output: !error
input: |
{ foo\u12f: 123 }
object-double-escape:
type: advanced
output: !error
input: |
{ foo\\u1234bar: 123 }
object-we-arent-es3:
type: basic
output: {new: 1, delete: 2, throw: 3}
input: |
{new: 1, delete: 2, throw: 3}
object-last-digits:
type: basic
output: {$123e2: 1, abc123: 2}
input: |
{$123e2: 1, abc123: 2}
object-unicode-in-string:
type: advanced
output: {"\uff13qwe": 123}
input: |
{"\uff13qwe": 123}
object-unicode-esc-in-string:
type: advanced
output: {"\\uff13qwe": 123}
input: |
{"\\uff13qwe": 123}
object-unicode-digits-first-esc:
type: advanced
output: !error
input: |
{\uff13qwe: 123}
object-unicode-digits-first-lit:
type: advanced
output: !error
input: "{\uff13qwe: 123}"
object-unicode-weirdness-esc:
type: advanced
output: {"digit\uff13": 1, "comb\u094F": 2, "punct\u2040": 3, "zwnj\u200C": 4}
input: |
{digit\uff13: 1, comb\u094F: 2, punct\u2040: 3, zwnj\u200C: 4}
object-unicode-weirdness-lit:
type: advanced
output: {"digit\uff13": 1, "comb\u094F": 2, "punct\u2040": 3, "zwnj\u200C": 4}
input: "{digit\uff13: 1, comb\u094F: 2, punct\u2040: 3, zwnj\u200C: 4}"
# Array literals
# --------------
array-all-types:
type: basic
output: [1.2,"3,4",{},[],null,+.inf]
input: |
[1.2,"3,4",{},[],null,Infinity]
array-trailing-comma:
type: basic
output: [1,2,3,4]
input: |
[1,2,3,4,]
array-leading-comma-style:
type: basic
output: [quux,foo,bar,baz]
input: |
[ 'quux'
, 'foo'
, 'bar'
, 'baz'
]
array-incomplete:
type: basic
output: !error
input: |
[1,2,3,[]
array-nested:
type: basic
output: [[[[[[]]]]],[[],[]]]
input: |
[[[[[[/*[]*/]]]]],[[],[]]]
array-isnt-object:
type: extra
output: !error
input: |
[1:2]
array-no-single-comma:
type: extra
output: !error
input: |
[,]
array-no-elisions:
type: extra
output: !error
input: |
[1,,2,3]
# Comments
# --------
comment-single:
type: basic
output: foobar
input: |
// blahblah
"foobar"
// another one
comment-multi:
type: basic
output: foobar
input: |
/*
* 123
*/
"foobar"
/**/
comment-single-newlines:
type: advanced
output: [ 123, 456, 789 ]
input: "[// foo\r123,// bar\u2028456,// baz\u2029789]"
comment-inside:
type: advanced
output: [123, '// foo', '/* bar']
input: >
[
/*
" // */ 123, // ",
"// foo",
'/* bar',
]
comment-in-token:
type: advanced
output: !error
input:
123/*comment*/456
comment-java-style:
type: basic
output: 123
input:
/*****************/
123
/****************/
comment-object:
type: basic
output: {q: 123}
input: /**/{/**/q/**/:/**/123/**/,/**/}//
# Whitespace
# ----------
ws-no-whitespace:
type: basic
output: {"foo":bar,bar:["qwe",null,[],{}],"baz":123}
input: '{foo:"bar","bar":["qwe",null,[],{}],"baz":123}'
ws-allow-prefix:
type: basic
output: 123
input: " \t123"
ws-unicode-spaces:
type: advanced
output: { foo : 123 }
input: "
\u0020\u00A0\uFEFF
{
\x09\x0A\x0B\x0C\x0D\u1680\u180E
foo
\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A
:
\u2028\u2029\u202F\u205F\u3000
123
\uFEFF
}"
ws-unicode-newlines:
type: advanced
output: [ 123, 456 ]
input: "
[
\u000D
123,
\u2028
456,
\u2029
]
"
# Multiple tokens
# ---------------
multi-string-nospace:
type: basic
output: !error
input: '"foo""bar"'
multi-string:
type: basic
output: !error
input: '"foo" "bar"'
# note: valid javascript
multi-array:
type: extra
output: !error
input: '[0] [0]'
multi-object:
type: basic
output: !error
input: '{} {}'
...
var _assert = require('assert')
var analyze = require('../').analyze
function addTest(a, b) {
if (typeof(describe) === 'function') {
it('test_analyze: ' + a + ' == ' + b, function() {
_assert.equal(a, b)
})
} else {
_assert.equal(a, b)
}
}
var t = analyze(JSON.stringify(require('os').networkInterfaces()))
addTest(t.has_whitespace, false)
addTest(t.has_comments, false)
addTest(t.has_newlines, false)
addTest(t.newline, '\n')
addTest(t.quote, '"')
addTest(t.quote_keys, true)
addTest(t.indent, '')
var t = analyze(JSON.stringify(require('os').networkInterfaces(), null, 2))
addTest(t.has_whitespace, true)
addTest(t.has_comments, false)
addTest(t.has_newlines, true)
addTest(t.newline, '\n')
addTest(t.quote, '"')
addTest(t.quote_keys, true)
addTest(t.indent, ' ')
var t = analyze(JSON.stringify(require('os').networkInterfaces(), null, 3))
addTest(t.indent, ' ')
var t = analyze(JSON.stringify(require('os').networkInterfaces(), null, '\t'))
addTest(t.indent, '\t')
var t = analyze(JSON.stringify(require('os').networkInterfaces(), null, 3).replace(/\n/g, '\r\n'))
addTest(t.indent, ' ')
addTest(t.newline, '\r\n')
var t = analyze(JSON.stringify(require('os').networkInterfaces()).replace(/"/g, "'"))
addTest(t.quote, "'")
addTest(t.quote_keys, true)
var t = analyze("{foo:'bar', 'bar':\"baz\", 'baz':\"quux\"}")
addTest(t.quote, "'")
addTest(t.quote_keys, false)
var t = analyze("{foo:'bar', \"bar\":'baz', \"baz\":\"quux\"}")
addTest(t.quote, '"')
addTest(t.quote_keys, false)
var assert = require('assert')
var create = require('../lib/document').Document
var jju = require('..')
var str = '{ x\r\n:\n1, y: {"..z.": 123, t: null, s:"123", a:[ 1,2,{x:3},] }}\n'
var d = create(str)
assert.equal(d + '', str)
assert.deepEqual(d.get(''), {x:1,y:{'..z.':123,t:null,s:'123',a:[1,2,{x:3}]}})
assert.deepEqual(d.get('x'), 1)
assert.deepEqual(d.get('x.x'), undefined)
assert.deepEqual(d.get('x.x.x.x'), undefined)
assert.strictEqual(d.get('y.x'), undefined)
assert.deepEqual(d.get('y.s'), '123')
assert.strictEqual(d.get('y.t'), null)
assert.strictEqual(d.get('y.t.x'), undefined)
assert.equal(d.has(''), true)
assert.equal(d.has('x'), true)
assert.equal(d.has('x.x'), false)
assert.equal(d.has('x.x.x.x'), false)
assert.equal(d.has('y.x'), false)
assert.equal(d.has('y'), true)
assert.equal(d.has('y.s'), true)
assert.equal(d.has('y.t'), true)
assert.equal(d.has('a'), false)
// arrays
assert.deepEqual(d.get('y.a'), [1,2,{x:3}])
assert.deepEqual(d.get('y.a.0'), 1)
assert.deepEqual(d.get('y.a.2.x'), 3)
assert.deepEqual(d.get('y.a.10'), undefined)
assert.deepEqual(d.has('y.a.0'), true)
assert.deepEqual(d.has('y.a.10'), false)
assert.deepEqual(d.get('y.a.2'), {x:3})
assert.deepEqual(d.get('y.a.-1'), undefined)
// controversial
assert.strictEqual(d.get('y.s.0'), undefined)
assert.equal(d.has('y.s.0'), false)
// paths
assert.deepEqual(d.get([]), {x:1,y:{'..z.':123,t:null,s:'123',a:[1,2,{x:3}]}})
assert.strictEqual(d.has([]), true)
assert.strictEqual(d.get(['y','..z.']), 123)
assert.strictEqual(d.has(['y','..z.']), true)
assert.deepEqual(d.get(['y','a',2,'x']), 3)
assert.deepEqual(create('[1]').set(0, 4).get(''), [4])
assert.deepEqual(create('[1]').set(1, 4).get(''), [1,4])
assert.deepEqual(create('[1]').has(0), true)
assert.deepEqual(create('[1]').has(1), false)
assert.deepEqual(create('[1]').get(0), 1)
// invalid paths
assert.throws(function() { create('[1]').set(null, 4) }, /invalid path type/i)
assert.throws(function() { create('[1]').set({}, 4) }, /invalid path type/i)
assert.throws(function() { create('[1]').set(/./, 4) }, /invalid path type/i)
assert.throws(function() { create('[1]').set(function(){}, 4) }, /invalid path type/i)
assert.throws(function() { create('[1]').set(false, 4) }, /invalid path type/i)
assert.throws(function() { create('[1]').set(undefined, 4) }, /invalid path type/i)
// set root
assert.strictEqual(create(str).set('', 4).get(''), 4)
assert.strictEqual(create(str).set('', null).get(''), null)
assert.strictEqual(create(str).set('', {x:4}).get('x'), 4)
assert.deepEqual(create(str).set('', [1,2,3]).get(''), [1,2,3])
assert.strictEqual(create('1').set('', 4).get(''), 4)
assert.strictEqual(create('null').set('', 4).get(''), 4)
assert.strictEqual(create('[]').set('', 4).get(''), 4)
assert.strictEqual(create('{}').set('', 4).get(''), 4)
// set 1st level
assert.deepEqual(create('{}').set('x', 4).get('x'), 4)
assert.deepEqual(create('{a:{b:[]}}').set('a.b.0', 4).get('a'), {b:[4]})
//assert.deepEqual(create('1').set('x', 4).get('x'), 4)
//assert.deepEqual(create('null').set('x', 4).get('x'), 4)
// array: boundaries
assert.strictEqual(create('[]').set('0', 4).get('0'), 4)
assert.strictEqual(create('[1,2,3]').set('2', 4).get('2'), 4)
assert.strictEqual(create('[1,2,3]').set('3', 4).get('3'), 4)
// various error cases
assert.throws(function() { create('1').set('x', 4) }, /set key .* of an non-object/)
assert.throws(function() { create('null').set('x', 4) }, /set key .* of an non-object/)
assert.throws(function() { create('[]').set('x', 4) }, /set key .* of an array/)
assert.throws(function() { create('""').set('x', 4) }, /set key .* of an non-object/)
assert.throws(function() { create('{}').set('x.x.x', 4) }, /set key .* of an non-object/)
assert.throws(function() { create('1').set('1', 4) }, /set key .* of an non-object/)
assert.throws(function() { create('null').set('1', 4) }, /set key .* of an non-object/)
assert.throws(function() { create('""').set('1', 4) }, /set key .* of an non-object/)
assert.throws(function() { create('[]').set('-1', 4) }, /set key .* of an array/)
assert.throws(function() { create('[]').set('1', 4) }, /set key .* out of bounds/)
assert.throws(function() { create('[1,2,3]').set('4', 4) }, /set key .* out of bounds/)
assert.throws(function() { create('{a:{b:[]}}').set('a.b.x', 4) }, /set key .* of an array/)
// unsetting stuff
assert.throws(function() { create('[]').unset('') }, /can't remove root document/)
// arrays: handling spaces correctly
assert.equal(create("[]").set(0,{})+"", '[{}]')
assert.equal(create("[0]").set(1,{})+"", '[0,{}]')
assert.equal(create("[0,]").set(1,{})+"", '[0,{},]')
assert.equal(create("[ ]").set(0,{})+"", '[{} ]')
assert.equal(create("[ 0 , ]").set(1,{})+"", '[ 0 , {}, ]')
assert.equal(create("[ 0 ]").set(1,{})+"", '[ 0, {} ]')
assert.equal(create("{}").set('y',{})+"", '{"y":{}}')
assert.equal(create("{x:1}").set('y',{})+"", '{x:1,y:{}}')
assert.equal(create("{x:1,}").set('y',{})+"", '{x:1,y:{},}')
assert.equal(create("{ }").set('y',{})+"", '{"y":{} }')
assert.equal(create("{ x:1 , }").set('y',{})+"", '{ x:1 , y:{}, }')
assert.equal(create("{ x:1 }").set('y',{})+"", '{ x:1, y:{} }')
// deleting elements
assert.throws(function() { create('[]').unset('0') }, /unset key .* out of bounds/)
assert.throws(function() { create('[1,2]').unset('2') }, /unset key .* out of bounds/)
assert.throws(function() { create('[1,2,3]').unset('0') }, /in the middle of an array/)
// CommonJS assert spec is "awesome"
assert.deepEqual(create('[1,2]').unset('1').get(''), [1])
assert.deepEqual(create('[1,2]').unset('1').get('').length, 1)
assert.deepEqual(create('[1,2,3]').unset('2').unset('1').get(''), [1])
assert.deepEqual(create('[1,2,3]').unset('2').unset('1').get('').length, 1)
assert.deepEqual(create('[1]').unset('0').get(''), [])
assert.deepEqual(create('[1]').unset('0').get('').length, 0)
assert.deepEqual(create('{x:{y:"z"}, z:4}').unset('x').get(''), {z:4})
assert.throws(function() { create('[1,2]').unset('') }, /root/)
// getting crazy
//assert.deepEqual(create(str).set('a.b.c.d.e', 1).get('a'), {b:{c:{d:{e:1}}}})
// update: arrays
assert.deepEqual(create("[1]").update([2,3])+"", '[2,3]')
assert.deepEqual(create("[1]").update([2,3,4])+"", '[2,3,4]')
assert.deepEqual(create("[]").update([2])+"", '[2]')
assert.deepEqual(create("[2]").update([])+"", '[]')
assert.deepEqual(create("[2,3,4]").update([2,3])+"", '[2,3]')
assert.deepEqual(create("[2,3,4]").update([])+"", '[]')
assert.deepEqual(create("[]").update([2,3,4])+"", '[2,3,4]')
assert.deepEqual(create(" /*zz*/ [ 2 , 3 , 4 ] /*xx*/ ").update([])+"", ' /*zz*/ [ ] /*xx*/ ')
assert.deepEqual(create(" /*zz*/ [ ] /*xx*/ ").update([2,3,4])+"", ' /*zz*/ [2,3,4 ] /*xx*/ ')
// update: objects
assert.deepEqual(create("{x:1}").update({x:1,y:2,z:3})+"", '{x:1,y:2,z:3}')
assert.deepEqual(create("{x:1}").update({x:2,z:3,t:4})+"", '{x:2,z:3,t:4}')
assert.deepEqual(create("{}").update({x:1,y:2})+"", '{"x":1,"y":2}')
assert.deepEqual(create("{x:1}").update({})+"", '{}')
assert.deepEqual(create("{x:1,y:2}").update({x:1})+"", '{x:1}')
assert.deepEqual(create(" /*zz*/ { x /*a*/ : /*b*/ 2 , y:3 , z //\n: 4 } /*xx*/ ").update({})+"", ' /*zz*/ { } /*xx*/ ')
assert.deepEqual(create(" /*zz*/ { } /*xx*/ ").update({x: 2, y: 3, z: 4})+"", ' /*zz*/ {"x":2,"y":3,"z":4 } /*xx*/ ')
// remove trailing comma
assert.deepEqual(create("{x:1,}").update({})+"", '{}')
assert.deepEqual(create("[0,]").update([])+"", '[]')
assert.deepEqual(create("[0 /*z*/ , /*z*/]").update([])+"", '[ /*z*/]')
// mode
assert.equal(create('{"test":123}', {mode:'json'}).update({q:1,w:2})+'', '{"q":1,"w":2}')
assert.equal(create('{1:2}').update({ a: 1, b: [1,2], c: 3})+'', '{a:1,b:[1,2],c:3}')
// undef
//assert.throws(function(){ jju.update(undefined, undefined) }, /root doc/)
assert.equal(jju.update(undefined, undefined), '')
assert.equal(jju.update(undefined, 42), '42')
assert.equal(jju.update(undefined, {x: 5}), '{"x":5}')
/*
* real test
*/
var upd = { name: 'yapm',
version: '0.6.0',
description: 'npm wrapper allowing to use package.yaml instead of package.json',
author: { name: 'Alex Kocharin', email: 'alex@kocharin.ru' },
keywords:
[ 'package manager',
'modules',
'install',
'package.yaml',
'package.json5',
'yaml',
'json5',
'npm' ],
preferGlobal: true,
homepage: 'https://npmjs.org/doc/',
repository: { type: 'git', url: 'https://github.com/rlidwka/yapm' },
bugs: { url: 'http://github.com/rlidwka/yapm/issues' },
main: './yapm.js',
bin: { yapm: './yapm.js' },
dependencies: { npm: '*', 'js-yaml': '*', through: '*', 'json5-utils': '*' },
devDependencies: { async: '*' },
optionalDependencies: { 'yaml-update': '*' },
test_nonascii: 'тест' }
assert.deepEqual(create(create('{"garbage":"garbage"}').update(upd)).get(''), upd)
assert.deepEqual(JSON.parse(create('{"garbage":"garbage"}', {mode:'json',legacy:true}).update(upd)), upd)
//console.log(create('{"garbage":"garbage"}').update(upd)+'')
//assert.deepEqual(create(" [ ] //").set(0,{})+"" [ ,{}] //
//node -e 'console.log(require("./document").Document("{}").set("",[1,2,3])+"")'[1, 2, 3]
//alex@elu:~/json5-utils/lib$ node -e 'console.log(require("./document").Document("[]").set("0",[1,2,3]).get(""))'
//[ [ 1, 2, 3 ] ]
/*assert.equal(create('"test"').get(''), 'test')
assert.equal(create('"test"').get([]), 'test')
assert.equal(create('"test"').get(false), 'test')
assert.equal(create(undefined).get(''), undefined)
//assert.equal(create('"test"').set('', 'foo').toString(), '"foo"')
*/
var assert = require('assert')
var parse = require('../').parse
function addTest(arg, row, col, errRegExp) {
var fn = function() {
try {
parse(arg)
} catch(err) {
if (row !== undefined) assert.equal(err.row, row, 'wrong row: ' + err.row)
if (col !== undefined) assert.equal(err.column, col, 'wrong column: ' + err.column)
if (errRegExp) assert(errRegExp.exec(err.message))
return
}
throw Error("no error")
}
if (typeof(describe) === 'function') {
it('test_errors: ' + JSON.stringify(arg), fn)
} else {
fn()
}
}
// semicolon will be unexpected, so it indicates an error position
addTest(';', 1, 1)
addTest('\n\n\n;', 4, 1)
addTest('\r\n;', 2, 1)
addTest('\n\r;', 3, 1)
addTest('\n\u2028;', 3, 1)
addTest('\n\u2029;', 3, 1)
addTest('[\n1\n,\n;', 4, 1)
addTest('{\n;', 2, 1)
addTest('{\n1\n:\n;', 4, 1)
addTest('.e3', 1, 3, /"\.e3"/)
// line continuations
addTest('["\\\n",\n;', 3, 1)
addTest('["\\\r\n",\n;', 3, 1)
addTest('["\\\u2028",\n;', 3, 1)
addTest('["\\\u2029",\n;', 3, 1)
// bareword rewind
addTest('nulz', 1, 1)
// no data
addTest(' ', 1, 3, /No data.*whitespace/)
addTest('blah', 1, 1, /Unexpected token 'b'/)
addTest('', 1, 1, /No data.*empty input/)
try {
parse('{{{{{{{{{')
} catch(err) {
var x = err.stack.match(/parseObject/g)
assert(!x || x.length < 2, "shouldn't blow up the stack with internal calls")
}
var assert = require('assert')
var parse = require('../').parse
function addTest(arg, bulk) {
function fn_json5() {
//console.log('testing: ', arg)
try {
var x = parse(arg)
} catch(err) {
x = 'fail'
}
try {
var z = eval('(function(){"use strict"\nreturn ('+String(arg)+'\n)\n})()')
} catch(err) {
z = 'fail'
}
assert.deepEqual(x, z)
}
function fn_strict() {
//console.log('testing: ', arg)
try {
var x = parse(arg, {mode: 'json'})
} catch(err) {
x = 'fail'
}
try {
var z = JSON.parse(arg)
} catch(err) {
z = 'fail'
}
assert.deepEqual(x, z)
}
if (typeof(describe) === 'function' && !bulk) {
it('test_parse_json5: ' + JSON.stringify(arg), fn_json5)
it('test_parse_strict: ' + JSON.stringify(arg), fn_strict)
} else {
fn_json5()
fn_strict()
}
}
addTest('"\\uaaaa\\u0000\\uFFFF\\uFaAb"')
addTest(' "\\xaa\\x00\xFF\xFa\0\0" ')
addTest('"\\\'\\"\\b\\f\\t\\n\\r\\v"')
addTest('"\\q\\w\\e\\r\\t\\y\\\\i\\o\\p\\[\\/\\\\"')
addTest('"\\\n\\\r\n\\\n"')
addTest('\'\\\n\\\r\n\\\n\'')
addTest(' null')
addTest('true ')
addTest('false')
addTest(' Infinity ')
addTest('+Infinity')
addTest('[]')
addTest('[ 0xA2, 0X024324AaBf]')
addTest('-0x12')
addTest(' [1,2,3,4,5]')
addTest('[1,2,3,4,5,] ')
addTest('[1e-13]')
addTest('[null, true, false]')
addTest(' [1,2,"3,4,",5,]')
addTest('[ 1,\n2,"3,4," \r\n,\n5,]')
addTest('[ 1 , 2 , 3 , 4 , 5 , ]')
addTest('{} ')
addTest('{"2":1,"3":null,}')
addTest('{ "2 " : 1 , "3":null , }')
addTest('{ \"2\" : 25e245 , \"3\": 23 }')
addTest('{"2":1,"3":nul,}')
addTest('{:1,"3":nul,}')
addTest('[1,2] // ssssssssss 3,4,5,] ')
addTest('[1,2 , // ssssssssss \n//xxx\n3,4,5,] ')
addTest('[1,2 /* ssssssssss 3,4,*/ /* */ , 5 ] ')
addTest('[1,2 /* ssssssssss 3,4,*/ /* * , 5 ] ')
addTest('{"3":1,"3":,}')
addTest('{ чйуач:1, щцкшчлм : 4,}')
addTest('{ qef-:1 }')
addTest('{ $$$:1 , ___: 3}')
addTest('{3:1,2:1}')
addTest('{3.4e3:1}')
addTest('{-3e3:1}')
addTest('{+3e3:1}')
addTest('{.3e3:1}')
for (var i=0; i<200; i++) {
addTest('"' + String.fromCharCode(i) + '"', true)
}
// strict JSON test cases
addTest('"\\xaa"')
addTest('"\\0"')
addTest('"\0"')
addTest('"\\v"')
addTest('{null: 123}')
addTest("{'null': 123}")
assert.throws(function() {
parse('0o')
})
assert.strictEqual(parse('01234567'), 342391)
assert.strictEqual(parse('0o1234567'), 342391)
// undef
assert.strictEqual(parse(undefined), undefined)
// whitespaces
addTest('[1,\r\n2,\r3,\n]')
'\u0020\u00A0\uFEFF\x09\x0A\x0B\x0C\x0D\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000'.split('').forEach(function(x) {
addTest(x+'[1,'+x+'2]'+x)
addTest('"'+x+'"'+x)
})
'\u000A\u000D\u2028\u2029'.split('').forEach(function(x) {
addTest(x+'[1,'+x+'2]'+x)
addTest('"\\'+x+'"'+x)
})
/* weird ES6 stuff, not working
if (process.version > 'v0.11.7') {
assert(Array.isArray(parse('{__proto__:[]}').__proto__))
assert.equal(parse('{__proto__:{xxx:5}}').xxx, undefined)
assert.equal(parse('{__proto__:{xxx:5}}').__proto__.xxx, 5)
var o1 = parse('{"__proto__":[]}')
assert.deepEqual([], o1.__proto__)
assert.deepEqual(["__proto__"], Object.keys(o1))
assert.deepEqual([], Object.getOwnPropertyDescriptor(o1, "__proto__").value)
assert.deepEqual(["__proto__"], Object.getOwnPropertyNames(o1))
assert(o1.hasOwnProperty("__proto__"))
assert(Object.prototype.isPrototypeOf(o1))
// Parse a non-object value as __proto__.
var o2 = JSON.parse('{"__proto__":5}')
assert.deepEqual(5, o2.__proto__)
assert.deepEqual(["__proto__"], Object.keys(o2))
assert.deepEqual(5, Object.getOwnPropertyDescriptor(o2, "__proto__").value)
assert.deepEqual(["__proto__"], Object.getOwnPropertyNames(o2))
assert(o2.hasOwnProperty("__proto__"))
assert(Object.prototype.isPrototypeOf(o2))
}*/
assert.throws(parse.bind(null, "{-1:42}"))
for (var i=0; i<100; i++) {
var str = '-01.e'.split('')
var rnd = [1,2,3,4,5].map(function(x) {
x = ~~(Math.random()*str.length)
return str[x]
}).join('')
try {
var x = parse(rnd)
} catch(err) {
x = 'fail'
}
try {
var y = JSON.parse(rnd)
} catch(err) {
y = 'fail'
}
try {
var z = eval(rnd)
} catch(err) {
z = 'fail'
}
//console.log(rnd, x, y, z)
if (x !== y && x !== z) throw 'ERROR'
}
var assert = require('assert')
var FS = require('fs')
var YAML = require('js-yaml')
var jju = require('../')
function addTest(name, fn) {
if (typeof(describe) === 'function') {
it(name, fn)
} else {
fn()
}
}
var schema = YAML.Schema.create([
new YAML.Type('!error', {
kind: 'scalar',
resolve: function (state) {
//state.result = null
return true
},
})
])
var tests = YAML.safeLoad(FS.readFileSync(__dirname + '/portable-json5-tests.yaml', 'utf8'), {
schema: schema
})
if (!Object.is) {
Object.defineProperty(Object, 'is', {
value: function(x, y) {
if (x === y) {
return x !== 0 || 1 / x === 1 / y;
}
return x !== x && y !== y;
},
configurable: true,
enumerable: false,
writable: true,
})
}
for (var k in tests) {
;(function(k) {
addTest(k, function() {
try {
var result = jju.parse(tests[k].input)
} catch(err) {
result = null
}
// need deepStrictEqual
if (typeof(result) === 'object') {
assert.deepEqual(result, tests[k].output)
} else {
assert(Object.is(result, tests[k].output), String(result) + ' == ' + tests[k].output)
}
})
})(k)
}
var assert = require('assert')
var parse = require('../').parse
var stringify = require('../').stringify
function deepEqual(x, y) {
if (Number.isNaN(x)) {
return assert(Number.isNaN(y))
}
assert.deepEqual(x, y)
}
function addTest(arg, arg2, arg3) {
function fn() {
deepEqual(parse(stringify(arg)), arg2 === undefined ? arg : arg2)
if (arg !== undefined) deepEqual(JSON.parse(stringify(arg, {mode: 'json', indent: false})), (arg3 === undefined ? (arg2 === undefined ? arg : arg2) : arg3))
}
if (typeof(describe) === 'function') {
it('test_stringify: ' + JSON.stringify(arg), fn)
} else {
fn()
}
}
addTest(0)
addTest(-0)
addTest(NaN, undefined, null)
addTest(Infinity, undefined, null)
addTest(-Infinity, undefined, null)
addTest(123)
addTest(19508130958019385.135135)
addTest(-2e123)
addTest(null)
addTest(undefined)
addTest([])
addTest([,,,,,,,], [null,null,null,null,null,null,null])
addTest([undefined,null,1,2,3,], [null,null,1,2,3])
addTest([[[[]]],[[]]])
addTest({})
addTest({1:2,3:4})
addTest({1:{1:{1:{1:4}}}, 3:4})
addTest({1:undefined, 3:undefined}, {})
addTest(new Number(4), 4)
addTest(new Boolean(true), true)
addTest(new String('xqefxef'), 'xqefxef')
addTest(new Boolean(), false)
var r='';for (var i=0; i<5000; i++) {r+=String.fromCharCode(i)}
addTest(r)
assert.equal("[1, 2, 3]", stringify([1, 2, 3], {indent: 1}))
assert.equal("[1, 2, 3]", stringify([1, 2, 3], {indent: 2}))
var oddball = Object(42)
oddball.__proto__ = { __proto__: null }
assert.equal('{}', stringify(oddball))
/* this WILL throw
var falseNum = Object("37")
falseNum.__proto__ = Number.prototype
assert.equal("{0: '3', 1: '7'}", stringify(falseNum))*/
assert.equal(stringify(Infinity), 'Infinity')
assert.equal(stringify(Infinity, {mode: 'json'}), 'null')
assert.equal(stringify(NaN), 'NaN')
assert.equal(stringify(NaN, {mode: 'json'}), 'null')
assert.equal(stringify(-0), '-0')
assert.equal(stringify('test', null), "'test'")
var array = [""]
var expected = "''"
for (var i = 0; i < 1000; i++) {
array.push("")
expected = "''," + expected
}
expected = '[' + expected + ']'
assert.equal(expected, stringify(array, {indent: false}))
assert.strictEqual(stringify([1,2,3], function(){}), undefined)
// don't stringify prototype
assert.equal('{a: 1}', stringify({a:1,__proto__:{b:2}}))
// sort keys tests
assert.equal('{a: 1, b: 2, z: 3}', stringify({b:2,a:1,z:3}, {sort_keys: 1}))
assert.equal('{a: 1, b: {a: 2, b: 5, c: 1}, z: 3}', stringify({b:{c:1,a:2,b:5},a:1,z:3}, {sort_keys: 1}))
assert.equal('{a: [3, 5, 1], b: 2, z: 3}', stringify({b:2,a:[3,5,1],z:3}, {sort_keys: 1}))
assert.equal('{b: 2, a: 1, z: 3}', stringify({b:2,a:1,z:3}, {sort_keys: 0}))
var assert = require('assert')
var parse = require('../').parse
function tokenize(arg) {
var result = []
parse(arg, {_tokenize: function(smth) {
result.push(smth)
}})
assert.deepEqual(result.map(function(x){return x.raw}).join(''), arg)
return result
}
function addTest(x, exp) {
function fn(){assert.deepEqual(tokenize(x), exp)}
if (typeof(describe) === 'function') {
it('test_tokenize: ' + JSON.stringify(x), fn)
} else {
fn()
}
}
addTest('123', [ { raw: '123', value: 123, type: 'literal', stack: [] }])
addTest(' /* zz */\r\n true /* zz */\n',
[ { raw: ' ', type: 'whitespace', stack: [] },
{ raw: '/* zz */', type: 'comment', stack: [] },
{ raw: '\r\n', type: 'newline', stack: [] },
{ raw: ' ', type: 'whitespace', stack: [] },
{ raw: 'true', type: 'literal', value: true, stack: [] },
{ raw: ' ', type: 'whitespace', stack: [] },
{ raw: '/* zz */', type: 'comment', stack: [] },
{ raw: '\n', type: 'newline', stack: [] } ])
addTest('{q:123, w : /*zz*/\n\r 345 } ',
[ { raw: '{', type: 'separator', stack: [] },
{ raw: 'q', type: 'key', value: 'q', stack: [] },
{ raw: ':', type: 'separator', stack: [] },
{ raw: '123', type: 'literal', value: 123, stack: ['q'] },
{ raw: ',', type: 'separator', stack: [] },
{ raw: ' ', type: 'whitespace', stack: [] },
{ raw: 'w', type: 'key', value: 'w', stack: [] },
{ raw: ' ', type: 'whitespace', stack: [] },
{ raw: ':', type: 'separator', stack: [] },
{ raw: ' ', type: 'whitespace', stack: [] },
{ raw: '/*zz*/', type: 'comment', stack: [] },
{ raw: '\n', type: 'newline', stack: [] },
{ raw: '\r', type: 'newline', stack: [] },
{ raw: ' ', type: 'whitespace', stack: [] },
{ raw: '345', type: 'literal', value: 345, stack: ['w'] },
{ raw: ' ', type: 'whitespace', stack: [] },
{ raw: '}', type: 'separator', stack: [] },
{ raw: ' ', type: 'whitespace', stack: [] } ])
addTest('null /* */// xxx\n//xxx',
[ { raw: 'null', type: 'literal', value: null, stack: [] },
{ raw: ' ', type: 'whitespace', stack: [] },
{ raw: '/* */', type: 'comment', stack: [] },
{ raw: '// xxx', type: 'comment', stack: [] },
{ raw: '\n', type: 'newline', stack: [] },
{ raw: '//xxx', type: 'comment', stack: [] } ])
addTest('[1,2,[[],[1]],{},{1:2},{q:{q:{}}},]',
[ { raw: '[', type: 'separator', stack: [] },
{ raw: '1', type: 'literal', value: 1, stack: [0] },
{ raw: ',', type: 'separator', stack: [] },
{ raw: '2', type: 'literal', value: 2, stack: [1] },
{ raw: ',', type: 'separator', stack: [] },
{ raw: '[', type: 'separator', stack: [2] },
{ raw: '[', type: 'separator', stack: [2,0] },
{ raw: ']', type: 'separator', stack: [2,0] },
{ raw: ',', type: 'separator', stack: [2] },
{ raw: '[', type: 'separator', stack: [2,1] },
{ raw: '1', type: 'literal', value: 1, stack: [2,1,0] },
{ raw: ']', type: 'separator', stack: [2,1] },
{ raw: ']', type: 'separator', stack: [2] },
{ raw: ',', type: 'separator', stack: [] },
{ raw: '{', type: 'separator', stack: [3] },
{ raw: '}', type: 'separator', stack: [3] },
{ raw: ',', type: 'separator', stack: [] },
{ raw: '{', type: 'separator', stack: [4] },
{ raw: '1', type: 'key', value: 1, stack: [4] },
{ raw: ':', type: 'separator', stack: [4] },
{ raw: '2', type: 'literal', value: 2, stack: [4,'1'] },
{ raw: '}', type: 'separator', stack: [4] },
{ raw: ',', type: 'separator', stack: [] },
{ raw: '{', type: 'separator', stack: [5] },
{ raw: 'q', type: 'key', value: 'q', stack: [5] },
{ raw: ':', type: 'separator', stack: [5] },
{ raw: '{', type: 'separator', stack: [5,'q'] },
{ raw: 'q', type: 'key', value: 'q', stack: [5,'q'] },
{ raw: ':', type: 'separator', stack: [5,'q'] },
{ raw: '{', type: 'separator', stack: [5,'q','q'] },
{ raw: '}', type: 'separator', stack: [5,'q','q'] },
{ raw: '}', type: 'separator', stack: [5,'q'] },
{ raw: '}', type: 'separator', stack: [5] },
{ raw: ',', type: 'separator', stack: [] },
{ raw: ']', type: 'separator', stack: [] } ])
var assert = require('assert')
var FS = require('fs')
var YAML = require('js-yaml')
var jju = require('../')
function addTest(name, fn) {
if (typeof(describe) === 'function') {
it(name, fn)
} else {
fn()
}
}
FS.readdirSync(__dirname + '/update').filter(function(file) {
return file.match(/^[^\.].*\.yaml$/)
}).forEach(function(file) {
addTest('update: ' + file, function() {
var test = YAML.load(FS.readFileSync(__dirname + '/update/' + file, 'utf8'))
assert.strictEqual(test.test(jju, test.input), test.output)
})
})
input: |
{ "name": "just-a-demo",
"version": "0.1.2",
"description": "blahblahblah",
"main": "test.js",
"scripts": { "test": "echo \"Error: no test specified\" && exit 1" },
"author": "John Doe <whoever@google.com>",
"license": "BSD-2-Clause" }
output: |
{ "name": "just-a-demo",
"version": "0.1.2",
"description": "blahblahblah",
"main": "test.js",
"scripts": { "test": "echo \"Error: no test specified\" && exit 1" },
"author": {
"name": "John Doe",
"email": "whoever@google.com"
},
"license": "BSD-2-Clause" }
test: !!js/function |
function(jju, input) {
obj = jju.parse(input)
obj.author = {
name: 'John Doe',
email: 'whoever@google.com',
}
return jju.update(input, obj)
}
input: |
{
"foo": {
"bar": {
"baz": {
"quux": "4"
}
}
}
}
output: |
{
"foo": {
"bar": {
"baz": {
"quux": "4"
},
"qwe": {
"rty": {
"aaa": {
"bbb": 1
}
}
}
}
}
}
test: !!js/function |
function(jju, input) {
obj = jju.parse(input)
obj.foo.bar.qwe = {rty: {aaa: {bbb: 1}}}
return jju.update(input, obj, {mode:'json'})
}
input: |
{
"name": "test",
"version": "0.0.0",
"dependencies": {
"foo": "1.2.x",
"bar": ">= 1"
},
"bundleDependencies": [
"foo",
"bar"
],
"license": "BSD-2-Clause"
}
output: |
{
"name": "test",
"version": "0.0.0",
"dependencies": {
"foo": "1.2.x"
},
"bundleDependencies": [
"foo"
],
"license": "BSD-2-Clause"
}
test: !!js/function |
function(jju, input) {
obj = jju.parse(input)
obj.bundleDependencies.pop()
delete obj.dependencies.bar
return jju.update(input, obj, {mode:'json'})
}
input: |
{
"name": "test",
"version": "0.0.0",
"bundleDependencies": [
"foo",
"bar"
],
"license": "BSD-2-Clause"
}
output: |
{
"name": "test",
"version": "0.0.0",
"bundleDependencies": [
"foo",
"bar",
"baz",
"quux"
],
"license": "BSD-2-Clause"
}
test: !!js/function |
function(jju, input) {
obj = jju.parse(input)
obj.bundleDependencies.push('baz')
obj.bundleDependencies.push('quux')
return jju.update(input, obj, {mode:'json'})
}
input: |
{
"name": "test",
"version": "0.0.0",
"dependencies": {
"foobar": "*",
"bazquux": ">= 1.1.1"
},
"license": "BSD-2-Clause"
}
output: |
{
"name": "test",
"version": "0.0.0",
"dependencies": {
"foobar": "*",
"bazquux": ">= 1.1.1",
"whatever": "1.2.x",
"qwerty": "1"
},
"license": "BSD-2-Clause"
}
test: !!js/function |
function(jju, input) {
obj = jju.parse(input)
obj.dependencies.whatever = '1.2.x'
obj.dependencies.qwerty = '1'
return jju.update(input, obj, {mode:'json'})
}
input: |
{ "name":"npm-test-array-bin"
, "version":"1.2.5"
, "bin": [ "bin/array-bin" ]
, "scripts": { "test": "node test.js" } }
# less than ideal, I know...
output: |
{ "name":"npm-test-array-bin"
, "version":"1.2.5"
, "bin": {"array-bin":"bin/array-bin"}
, "scripts": { "test": "node test.js" }, "readme": "just an npm test\n", "readmeFilename": "README", "description": "just an npm test", "_id": "npm-test-array-bin@1.2.5", "dist": {"shasum":"9c426a1bd55e98718ab4ddcc01fa57ea83c649f1"}, "_from": "npm-test-array-bin/" }
test: !!js/function |
function(jju, input) {
obj =
{ name: 'npm-test-array-bin',
version: '1.2.5',
bin: { 'array-bin': 'bin/array-bin' },
scripts: { test: 'node test.js' },
readme: 'just an npm test\n',
readmeFilename: 'README',
description: 'just an npm test',
_id: 'npm-test-array-bin@1.2.5',
dist: { shasum: '9c426a1bd55e98718ab4ddcc01fa57ea83c649f1' },
_from: 'npm-test-array-bin/' }
return jju.update(input, obj)
}
input: |
// vim:syntax=javascript
{
name: 'yapm',
version: '1.1.0-1325', // upstream npm@1.3.25
description: 'A package manager for node (npm fork)',
}
output: |
// vim:syntax=javascript
{
name: 'yapm',
version: '1.1.0-1325', // upstream npm@1.3.25
description: 'A package manager for node (npm fork)',
_id: 'yapm@1.1.0-1325',
dist: {
shasum: 'd5aa31c1ad00c1e7e57e07cea1b22c1806a47111',
},
_from: './zzz',
}
test: !!js/function |
function(jju, input) {
var upd = {
"name": "yapm",
"version": "1.1.0-1325",
"description": "A package manager for node (npm fork)",
"_id": "yapm@1.1.0-1325",
"dist": {
"shasum": "d5aa31c1ad00c1e7e57e07cea1b22c1806a47111"
},
"_from": "./zzz"
}
return jju.update(input, upd)
}

Sorry, the diff of this file is not supported yet