├── test ├── assets │ ├── pass4_result.hjson │ ├── pass4_result.json │ ├── failJSON29_test.json │ ├── failJSON30_test.json │ ├── failJSON16_test.json │ ├── failJSON31_test.json │ ├── pass4_test.json │ ├── failJSON08_test.json │ ├── failJSON33_test.json │ ├── empty_result.hjson │ ├── failJSON02_test.json │ ├── failJSON23_test.json │ ├── failJSON28_test.json │ ├── empty_result.json │ ├── empty_test.hjson │ ├── failJSON05_test.json │ ├── failJSON06_test.json │ ├── failJSON07_test.json │ ├── failJSON19_test.json │ ├── failJSON20_test.json │ ├── passSingle_result.hjson │ ├── passSingle_test.hjson │ ├── failJSON11_test.json │ ├── failJSON12_test.json │ ├── failJSON14_test.json │ ├── passSingle_result.json │ ├── failJSON15_test.json │ ├── failJSON17_test.json │ ├── failJSON21_test.json │ ├── failJSON22_test.json │ ├── failJSON26_test.json │ ├── failJSON32_test.json │ ├── failJSON13_test.json │ ├── failKey4_test.hjson │ ├── failKey2_test.hjson │ ├── failKey3_test.hjson │ ├── failKey5_test.hjson │ ├── pass2_test.json │ ├── failKey1_test.hjson │ ├── failMLStr1_test.hjson │ ├── failObj2_test.hjson │ ├── mltabs_result.json │ ├── extra │ │ ├── notabs_result.hjson │ │ ├── notabs_result.json │ │ ├── notabs_test.json │ │ ├── root_testmeta.hjson │ │ ├── separator_testmeta.hjson │ │ ├── notabs_testmeta.hjson │ │ ├── root_result.hjson │ │ ├── root_result.json │ │ ├── root_test.hjson │ │ ├── separator_test.json │ │ ├── separator_result.json │ │ └── separator_result.hjson │ ├── failCharset1_test.hjson │ ├── failJSON10_test.json │ ├── failStr1a_test.hjson │ ├── failStr1b_test.hjson │ ├── failStr2a_test.hjson │ ├── failStr2b_test.hjson │ ├── failStr3a_test.hjson │ ├── failStr3b_test.hjson │ ├── failStr4a_test.hjson │ ├── failStr4b_test.hjson │ ├── failStr5a_test.hjson │ ├── failStr5b_test.hjson │ ├── failStr6a_test.hjson │ ├── failStr6b_test.hjson │ ├── failStr8a_test.hjson │ ├── mltabs_test.json │ ├── stringify │ │ ├── quotes_strings_ml_test.json │ │ ├── quotes_strings_ml_result.hjson │ │ ├── quotes_strings_ml_result.json │ │ ├── quotes_all_testmeta.hjson │ │ ├── quotes_always_testmeta.hjson │ │ ├── quotes_keys_testmeta.hjson │ │ ├── quotes_strings_testmeta.hjson │ │ ├── quotes_strings_ml_testmeta.hjson │ │ ├── quotes_all_test.hjson │ │ ├── quotes_keys_test.hjson │ │ ├── quotes_strings_test.hjson │ │ ├── quotes_all_result.json │ │ ├── quotes_always_result.json │ │ ├── quotes_keys_result.json │ │ ├── quotes_strings_result.json │ │ ├── quotes_always_result.hjson │ │ ├── quotes_keys_result.hjson │ │ ├── quotes_strings_result.hjson │ │ ├── quotes_all_result.hjson │ │ └── quotes_always_test.hjson │ ├── failObj1_test.hjson │ ├── failObj3_test.hjson │ ├── failStr1c_test.hjson │ ├── failStr1d_test.hjson │ ├── failStr2c_test.hjson │ ├── failStr2d_test.hjson │ ├── failStr3c_test.hjson │ ├── failStr3d_test.hjson │ ├── failStr4c_test.hjson │ ├── failStr4d_test.hjson │ ├── failStr5c_test.hjson │ ├── failStr5d_test.hjson │ ├── failJSON34_test.json │ ├── failStr7a_test.hjson │ ├── mltabs_result.hjson │ ├── trail_result.hjson │ ├── trail_result.json │ ├── oa_result.hjson │ ├── oa_test.hjson │ ├── oa_result.json │ ├── pass3_result.hjson │ ├── pass3_result.json │ ├── pass3_test.json │ ├── failStr6c_test.hjson │ ├── failStr6d_test.hjson │ ├── trail_test.hjson │ ├── charset2_result.hjson │ ├── charset2_result.json │ ├── charset2_test.hjson │ ├── charset_result.hjson │ ├── charset_result.json │ ├── charset_test.hjson │ ├── kan_result.hjson │ ├── kan_result.json │ ├── keys_result.hjson │ ├── kan_test.hjson │ ├── strings2_result.hjson │ ├── comments_result.hjson │ ├── strings2_result.json │ ├── keys_result.json │ ├── strings2_test.hjson │ ├── comments_result.json │ ├── keys_test.hjson │ ├── pass2_result.hjson │ ├── pass2_result.json │ ├── stringify1_result.hjson │ ├── stringify1_test.hjson │ ├── stringify1_result.json │ ├── comments_test.hjson │ ├── strings_result.json │ ├── strings_result.hjson │ ├── pass1_result.hjson │ ├── strings_test.hjson │ ├── pass1_result.json │ ├── pass1_test.json │ └── testlist.txt └── test.js ├── .gitignore ├── lib ├── hjson-version.js ├── require-config.js ├── hjson-common.js ├── hjson-dsf.js ├── hjson.js ├── hjson-comments.js ├── hjson-parse.js └── hjson-stringify.js ├── .npmignore ├── bin ├── .eslintrc.json └── hjson ├── sample ├── package.json ├── sample.js └── test.hjson ├── .travis.yml ├── .editorconfig ├── .eslintrc.json ├── LICENSE ├── package.json ├── history.md ├── README.md └── bundle ├── hjson.min.js └── hjson.js /test/assets/pass4_result.hjson: -------------------------------------------------------------------------------- 1 | 10 -------------------------------------------------------------------------------- /test/assets/pass4_result.json: -------------------------------------------------------------------------------- 1 | 10 -------------------------------------------------------------------------------- /test/assets/failJSON29_test.json: -------------------------------------------------------------------------------- 1 | [0e] -------------------------------------------------------------------------------- /test/assets/failJSON30_test.json: -------------------------------------------------------------------------------- 1 | [0e+] -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage/ 3 | -------------------------------------------------------------------------------- /test/assets/failJSON16_test.json: -------------------------------------------------------------------------------- 1 | [\naked] -------------------------------------------------------------------------------- /test/assets/failJSON31_test.json: -------------------------------------------------------------------------------- 1 | [0e+-1] -------------------------------------------------------------------------------- /test/assets/pass4_test.json: -------------------------------------------------------------------------------- 1 | 2 | 10 3 | -------------------------------------------------------------------------------- /lib/hjson-version.js: -------------------------------------------------------------------------------- 1 | module.exports="3.2.1"; 2 | -------------------------------------------------------------------------------- /test/assets/failJSON08_test.json: -------------------------------------------------------------------------------- 1 | ["Extra close"]] -------------------------------------------------------------------------------- /test/assets/failJSON33_test.json: -------------------------------------------------------------------------------- 1 | ["mismatch"} -------------------------------------------------------------------------------- /test/assets/empty_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | "": empty 3 | } -------------------------------------------------------------------------------- /test/assets/failJSON02_test.json: -------------------------------------------------------------------------------- 1 | ["Unclosed array" -------------------------------------------------------------------------------- /test/assets/failJSON23_test.json: -------------------------------------------------------------------------------- 1 | ["Bad value", truth] -------------------------------------------------------------------------------- /test/assets/failJSON28_test.json: -------------------------------------------------------------------------------- 1 | ["line\ 2 | break"] -------------------------------------------------------------------------------- /test/assets/empty_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "": "empty" 3 | } -------------------------------------------------------------------------------- /test/assets/empty_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | "": empty 3 | } 4 | -------------------------------------------------------------------------------- /test/assets/failJSON05_test.json: -------------------------------------------------------------------------------- 1 | ["double extra comma",,] -------------------------------------------------------------------------------- /test/assets/failJSON06_test.json: -------------------------------------------------------------------------------- 1 | [ , "<-- missing value"] -------------------------------------------------------------------------------- /test/assets/failJSON07_test.json: -------------------------------------------------------------------------------- 1 | ["Comma after the close"], -------------------------------------------------------------------------------- /test/assets/failJSON19_test.json: -------------------------------------------------------------------------------- 1 | {"Missing colon" null} -------------------------------------------------------------------------------- /test/assets/failJSON20_test.json: -------------------------------------------------------------------------------- 1 | {"Double colon":: null} -------------------------------------------------------------------------------- /test/assets/passSingle_result.hjson: -------------------------------------------------------------------------------- 1 | allow quoteless strings -------------------------------------------------------------------------------- /test/assets/passSingle_test.hjson: -------------------------------------------------------------------------------- 1 | allow quoteless strings -------------------------------------------------------------------------------- /test/assets/failJSON11_test.json: -------------------------------------------------------------------------------- 1 | {"Illegal expression": 1 + 2} -------------------------------------------------------------------------------- /test/assets/failJSON12_test.json: -------------------------------------------------------------------------------- 1 | {"Illegal invocation": alert()} -------------------------------------------------------------------------------- /test/assets/failJSON14_test.json: -------------------------------------------------------------------------------- 1 | {"Numbers cannot be hex": 0x14} -------------------------------------------------------------------------------- /test/assets/passSingle_result.json: -------------------------------------------------------------------------------- 1 | "allow quoteless strings" -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | _* 2 | \#* 3 | .* 4 | sample/ 5 | coverage/ 6 | test/ 7 | -------------------------------------------------------------------------------- /test/assets/failJSON15_test.json: -------------------------------------------------------------------------------- 1 | ["Illegal backslash escape: \x15"] -------------------------------------------------------------------------------- /test/assets/failJSON17_test.json: -------------------------------------------------------------------------------- 1 | ["Illegal backslash escape: \017"] -------------------------------------------------------------------------------- /test/assets/failJSON21_test.json: -------------------------------------------------------------------------------- 1 | {"Comma instead of colon", null} -------------------------------------------------------------------------------- /test/assets/failJSON22_test.json: -------------------------------------------------------------------------------- 1 | ["Colon instead of comma": false] -------------------------------------------------------------------------------- /test/assets/failJSON26_test.json: -------------------------------------------------------------------------------- 1 | ["tab\ character\ in\ string\ "] -------------------------------------------------------------------------------- /test/assets/failJSON32_test.json: -------------------------------------------------------------------------------- 1 | {"Comma instead if closing brace": true, -------------------------------------------------------------------------------- /test/assets/failJSON13_test.json: -------------------------------------------------------------------------------- 1 | {"Numbers cannot have leading zeroes": 013} -------------------------------------------------------------------------------- /test/assets/failKey4_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid name 3 | : 0 4 | } 5 | -------------------------------------------------------------------------------- /bin/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-console": "off" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/assets/failKey2_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid name 3 | {name: 0 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/failKey3_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid name 3 | key,name: 0 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/failKey5_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid name 3 | '''foo''': 0 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/pass2_test.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /test/assets/failKey1_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid name 3 | wrong name: 0 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/failMLStr1_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid multiline string 3 | ml: ''' 4 | -------------------------------------------------------------------------------- /test/assets/failObj2_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid obj 3 | noEnd 4 | { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /test/assets/mltabs_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar\tjoe\noki\tdoki\n\t\ttwo tabs" 3 | } -------------------------------------------------------------------------------- /test/assets/extra/notabs_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | foo: "bar\tjoe\noki\tdoki\n\t\ttwo tabs" 3 | } -------------------------------------------------------------------------------- /test/assets/extra/notabs_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar\tjoe\noki\tdoki\n\t\ttwo tabs" 3 | } -------------------------------------------------------------------------------- /test/assets/extra/notabs_test.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar\tjoe\noki\tdoki\n\t\ttwo tabs" 3 | } -------------------------------------------------------------------------------- /test/assets/failCharset1_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid \u char 3 | char: "\uxxxx" 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/failJSON10_test.json: -------------------------------------------------------------------------------- 1 | {"Extra value after close": true} "misplaced quoted value" -------------------------------------------------------------------------------- /test/assets/failStr1a_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid quoteless string 3 | ql: ] 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/failStr1b_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid quoteless string 3 | ql: ]x 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/failStr2a_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid quoteless string 3 | ql: } 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/failStr2b_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid quoteless string 3 | ql: }x 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/failStr3a_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid quoteless string 3 | ql: { 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/failStr3b_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid quoteless string 3 | ql: {x 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/failStr4a_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid quoteless string 3 | ql: [ 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/failStr4b_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid quoteless string 3 | ql: [x 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/failStr5a_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid quoteless string 3 | ql: : 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/failStr5b_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid quoteless string 3 | ql: :x 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/failStr6a_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid quoteless string 3 | ql: , 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/failStr6b_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid quoteless string 3 | ql: ,x 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/failStr8a_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid ml-string 3 | foo : ""'text''' 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/mltabs_test.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar\tjoe\noki\tdoki\n\t\ttwo tabs" 3 | } 4 | -------------------------------------------------------------------------------- /test/assets/stringify/quotes_strings_ml_test.json: -------------------------------------------------------------------------------- 1 | { 2 | "unicorn": "foo\nbar\nrainbow" 3 | } -------------------------------------------------------------------------------- /test/assets/failObj1_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid obj 3 | noDelimiter 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/assets/failObj3_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # missing key 3 | 4 | [ 5 | test 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /test/assets/failStr1c_test.hjson: -------------------------------------------------------------------------------- 1 | [ 2 | foo 3 | # invalid quoteless string 4 | ] 5 | ] 6 | -------------------------------------------------------------------------------- /test/assets/failStr1d_test.hjson: -------------------------------------------------------------------------------- 1 | [ 2 | foo 3 | # invalid quoteless string 4 | ]x 5 | ] 6 | -------------------------------------------------------------------------------- /test/assets/failStr2c_test.hjson: -------------------------------------------------------------------------------- 1 | [ 2 | foo 3 | # invalid quoteless string 4 | } 5 | ] 6 | -------------------------------------------------------------------------------- /test/assets/failStr2d_test.hjson: -------------------------------------------------------------------------------- 1 | [ 2 | foo 3 | # invalid quoteless string 4 | }x 5 | ] 6 | -------------------------------------------------------------------------------- /test/assets/failStr3c_test.hjson: -------------------------------------------------------------------------------- 1 | [ 2 | foo 3 | # invalid quoteless string 4 | { 5 | ] 6 | -------------------------------------------------------------------------------- /test/assets/failStr3d_test.hjson: -------------------------------------------------------------------------------- 1 | [ 2 | foo 3 | # invalid quoteless string 4 | {x 5 | ] 6 | -------------------------------------------------------------------------------- /test/assets/failStr4c_test.hjson: -------------------------------------------------------------------------------- 1 | [ 2 | foo 3 | # invalid quoteless string 4 | [ 5 | ] 6 | -------------------------------------------------------------------------------- /test/assets/failStr4d_test.hjson: -------------------------------------------------------------------------------- 1 | [ 2 | foo 3 | # invalid quoteless string 4 | [x 5 | ] 6 | -------------------------------------------------------------------------------- /test/assets/failStr5c_test.hjson: -------------------------------------------------------------------------------- 1 | [ 2 | foo 3 | # invalid quoteless string 4 | : 5 | ] 6 | -------------------------------------------------------------------------------- /test/assets/failStr5d_test.hjson: -------------------------------------------------------------------------------- 1 | [ 2 | foo 3 | # invalid quoteless string 4 | :x 5 | ] 6 | -------------------------------------------------------------------------------- /test/assets/stringify/quotes_strings_ml_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | unicorn: "foo\nbar\nrainbow" 3 | } -------------------------------------------------------------------------------- /test/assets/stringify/quotes_strings_ml_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "unicorn": "foo\nbar\nrainbow" 3 | } -------------------------------------------------------------------------------- /test/assets/extra/root_testmeta.hjson: -------------------------------------------------------------------------------- 1 | { 2 | options: { 3 | legacyRoot: true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/assets/extra/separator_testmeta.hjson: -------------------------------------------------------------------------------- 1 | { 2 | options: { 3 | separator: true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/assets/stringify/quotes_all_testmeta.hjson: -------------------------------------------------------------------------------- 1 | { 2 | options: { 3 | quotes: "all" 4 | } 5 | } -------------------------------------------------------------------------------- /test/assets/extra/notabs_testmeta.hjson: -------------------------------------------------------------------------------- 1 | { 2 | options: { 3 | multiline: no-tabs 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/assets/failJSON34_test.json: -------------------------------------------------------------------------------- 1 | A quoteless string is OK, 2 | but two must be contained in an array. 3 | -------------------------------------------------------------------------------- /test/assets/stringify/quotes_always_testmeta.hjson: -------------------------------------------------------------------------------- 1 | { 2 | options: { 3 | quotes: "always" 4 | } 5 | } -------------------------------------------------------------------------------- /test/assets/stringify/quotes_keys_testmeta.hjson: -------------------------------------------------------------------------------- 1 | { 2 | options: { 3 | quotes: "keys" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /sample/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "dependencies": { 4 | "hjson": "^2.3.0" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/assets/failStr7a_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # invalid string containing a newline 3 | foo : " 4 | " 5 | } 6 | -------------------------------------------------------------------------------- /test/assets/stringify/quotes_strings_testmeta.hjson: -------------------------------------------------------------------------------- 1 | { 2 | options: { 3 | quotes: "strings" 4 | } 5 | } -------------------------------------------------------------------------------- /test/assets/extra/root_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | database: 3 | { 4 | host: 127.0.0.1 5 | port: 555 6 | } 7 | } -------------------------------------------------------------------------------- /test/assets/extra/root_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "host": "127.0.0.1", 4 | "port": 555 5 | } 6 | } -------------------------------------------------------------------------------- /test/assets/stringify/quotes_strings_ml_testmeta.hjson: -------------------------------------------------------------------------------- 1 | { 2 | options: { 3 | quotes: strings 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/assets/mltabs_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | foo: 3 | ''' 4 | bar joe 5 | oki doki 6 | two tabs 7 | ''' 8 | } -------------------------------------------------------------------------------- /test/assets/extra/root_test.hjson: -------------------------------------------------------------------------------- 1 | // a object with the root braces omitted 2 | database: 3 | { 4 | host: 127.0.0.1 5 | port: 555 6 | } 7 | -------------------------------------------------------------------------------- /test/assets/trail_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | foo: 0 -- this string starts at 0 and ends at 1, preceding and trailing whitespace is ignored -- 1 3 | } -------------------------------------------------------------------------------- /test/assets/trail_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "0 -- this string starts at 0 and ends at 1, preceding and trailing whitespace is ignored -- 1" 3 | } -------------------------------------------------------------------------------- /test/assets/extra/separator_test.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar", 3 | "unicorn": "rainbow", 4 | "cat": 1, 5 | "hello": [ 6 | "world", 7 | "!" 8 | ] 9 | } -------------------------------------------------------------------------------- /test/assets/oa_result.hjson: -------------------------------------------------------------------------------- 1 | [ 2 | a 3 | {} 4 | {} 5 | [] 6 | [] 7 | { 8 | b: 1 9 | c: [] 10 | d: {} 11 | } 12 | [] 13 | ] -------------------------------------------------------------------------------- /test/assets/oa_test.hjson: -------------------------------------------------------------------------------- 1 | [ 2 | a 3 | {} 4 | {} 5 | [] 6 | [] 7 | { 8 | b: 1 9 | c: [] 10 | d: {} 11 | } 12 | [] 13 | ] 14 | -------------------------------------------------------------------------------- /test/assets/stringify/quotes_all_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar", 3 | "unicorn": "rainbow", 4 | "cat": 1, 5 | "hello": [ 6 | "world", 7 | "!" 8 | ] 9 | } -------------------------------------------------------------------------------- /test/assets/stringify/quotes_keys_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar", 3 | "unicorn": "rainbow", 4 | "cat": 1, 5 | "hello": [ 6 | "world", 7 | "!" 8 | ] 9 | } -------------------------------------------------------------------------------- /test/assets/extra/separator_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar", 3 | "unicorn": "rainbow", 4 | "cat": 1, 5 | "hello": [ 6 | "world", 7 | "!" 8 | ] 9 | } -------------------------------------------------------------------------------- /test/assets/stringify/quotes_strings_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar", 3 | "unicorn": "rainbow", 4 | "cat": 1, 5 | "hello": [ 6 | "world", 7 | "!" 8 | ] 9 | } -------------------------------------------------------------------------------- /test/assets/extra/separator_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | foo: "bar", 3 | unicorn: "rainbow", 4 | cat: 1, 5 | hello: 6 | [ 7 | "world", 8 | "!" 9 | ] 10 | } -------------------------------------------------------------------------------- /test/assets/oa_result.json: -------------------------------------------------------------------------------- 1 | [ 2 | "a", 3 | {}, 4 | {}, 5 | [], 6 | [], 7 | { 8 | "b": 1, 9 | "c": [], 10 | "d": {} 11 | }, 12 | [] 13 | ] -------------------------------------------------------------------------------- /test/assets/stringify/quotes_all_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar", 3 | "unicorn": "rainbow", 4 | "cat": 1, 5 | "hello": [ 6 | "world", 7 | "!" 8 | ] 9 | } -------------------------------------------------------------------------------- /test/assets/stringify/quotes_always_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar", 3 | "unicorn": "rainbow", 4 | "cat": 1, 5 | "hello": [ 6 | "world", 7 | "!" 8 | ] 9 | } -------------------------------------------------------------------------------- /test/assets/stringify/quotes_keys_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar", 3 | "unicorn": "rainbow", 4 | "cat": 1, 5 | "hello": [ 6 | "world", 7 | "!" 8 | ] 9 | } -------------------------------------------------------------------------------- /test/assets/stringify/quotes_strings_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar", 3 | "unicorn": "rainbow", 4 | "cat": 1, 5 | "hello": [ 6 | "world", 7 | "!" 8 | ] 9 | } -------------------------------------------------------------------------------- /test/assets/stringify/quotes_always_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | foo: "bar" 3 | unicorn: "rainbow" 4 | cat: 1 5 | hello: 6 | [ 7 | "world" 8 | "!" 9 | ] 10 | } -------------------------------------------------------------------------------- /test/assets/stringify/quotes_keys_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | "foo": bar 3 | "unicorn": rainbow 4 | "cat": 1 5 | "hello": 6 | [ 7 | world 8 | ! 9 | ] 10 | } -------------------------------------------------------------------------------- /test/assets/stringify/quotes_strings_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | foo: "bar" 3 | unicorn: "rainbow" 4 | cat: 1 5 | hello: 6 | [ 7 | "world" 8 | "!" 9 | ] 10 | } -------------------------------------------------------------------------------- /test/assets/stringify/quotes_all_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar" 3 | "unicorn": "rainbow" 4 | "cat": 1 5 | "hello": 6 | [ 7 | "world" 8 | "!" 9 | ] 10 | } -------------------------------------------------------------------------------- /test/assets/pass3_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | "JSON Test Pattern pass3": 3 | { 4 | "The outermost value": must be an object or array. 5 | "In this test": It is an object. 6 | } 7 | } -------------------------------------------------------------------------------- /test/assets/pass3_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "JSON Test Pattern pass3": { 3 | "The outermost value": "must be an object or array.", 4 | "In this test": "It is an object." 5 | } 6 | } -------------------------------------------------------------------------------- /test/assets/pass3_test.json: -------------------------------------------------------------------------------- 1 | { 2 | "JSON Test Pattern pass3": { 3 | "The outermost value": "must be an object or array.", 4 | "In this test": "It is an object." 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/assets/failStr6c_test.hjson: -------------------------------------------------------------------------------- 1 | [ 2 | # invalid quoteless string 3 | # note that if there were a preceding value the comma would 4 | # be allowed/ignored as a separator/trailing comma 5 | , 6 | ] 7 | -------------------------------------------------------------------------------- /test/assets/failStr6d_test.hjson: -------------------------------------------------------------------------------- 1 | [ 2 | # invalid quoteless string 3 | # note that if there were a preceding value the comma would 4 | # be allowed/ignored as a separator/trailing comma 5 | ,x 6 | ] 7 | -------------------------------------------------------------------------------- /test/assets/stringify/quotes_always_test.hjson: -------------------------------------------------------------------------------- 1 | // Test if `always` keeps working as before 2 | { 3 | "foo": "bar", 4 | "unicorn": "rainbow", 5 | "cat": 1, 6 | "hello": [ 7 | "world", 8 | "!" 9 | ] 10 | } -------------------------------------------------------------------------------- /test/assets/trail_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | // the following line contains trailing whitespace: 3 | foo: 0 -- this string starts at 0 and ends at 1, preceding and trailing whitespace is ignored -- 1 4 | } 5 | -------------------------------------------------------------------------------- /test/assets/charset2_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | uescape: "\u0000,\u0001,\uffff" 3 | French: ° î â ê Î Â Ê é É è à ù È À Ù ë Ë ç Ç œ « » 4 | German: ä Ä ö Ö ü Ü ß 5 | Italian: ° é ç à è ì ò ù À È Ì Ò Ù 6 | Spanish: ñ Ñ ü Ü á é í ó ú Á É Í Ó Ú º ¿ ¡ 7 | hex: ģ䕧覫췯ꯍ 8 | } -------------------------------------------------------------------------------- /test/assets/charset2_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "uescape": "\u0000,\u0001,￿", 3 | "French": "° î â ê Î Â Ê é É è à ù È À Ù ë Ë ç Ç œ « »", 4 | "German": "ä Ä ö Ö ü Ü ß", 5 | "Italian": "° é ç à è ì ò ù À È Ì Ò Ù", 6 | "Spanish": "ñ Ñ ü Ü á é í ó ú Á É Í Ó Ú º ¿ ¡", 7 | "hex": "ģ䕧覫췯ꯍ" 8 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - node 4 | - "8" 5 | - "7" 6 | - "6" 7 | - "5" 8 | - "4" 9 | - "0.12" 10 | - "0.11" 11 | - "0.10" 12 | script: 13 | - npm install 14 | - if [[ $TRAVIS_NODE_VERSION == 0* ]]; then npm test; else npm run build; fi 15 | 16 | -------------------------------------------------------------------------------- /test/assets/charset2_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | uescape: "\u0000,\u0001,\uffff" 3 | French: ° î â ê Î Â Ê é É è à ù È À Ù ë Ë ç Ç œ « » 4 | German: ä Ä ö Ö ü Ü ß 5 | Italian: ° é ç à è ì ò ù À È Ì Ò Ù 6 | Spanish: ñ Ñ ü Ü á é í ó ú Á É Í Ó Ú º ¿ ¡ 7 | hex: "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A" 8 | } 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | 2 | # EditorConfig http://EditorConfig.org 3 | root = true 4 | 5 | [*] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | 9 | [*.{js,hjson,json}] 10 | charset = utf-8 11 | 12 | [{*.js,*.json,bin/*}] 13 | indent_style = space 14 | indent_size = 2 15 | 16 | # no style is set for Hjson test files 17 | # as some require tabs 18 | 19 | -------------------------------------------------------------------------------- /test/assets/charset_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | ql-ascii: ! "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ 3 | js-ascii: ! "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ 4 | ml-ascii: ! "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ 5 | } -------------------------------------------------------------------------------- /test/assets/charset_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "ql-ascii": "! \"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", 3 | "js-ascii": "! \"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", 4 | "ml-ascii": "! \"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" 5 | } -------------------------------------------------------------------------------- /lib/require-config.js: -------------------------------------------------------------------------------- 1 | var fs=require("fs"); 2 | var Hjson=require("./hjson"); 3 | 4 | // allows you to require a hjson file, e.g.: 5 | // require("hjson/lib/require-config"); 6 | // var cfg=require("./test.hjson"); 7 | 8 | require.extensions[".hjson"]=function(module, filename) { 9 | var content=fs.readFileSync(filename, "utf8"); 10 | module.exports=Hjson.parse(content); 11 | }; 12 | -------------------------------------------------------------------------------- /test/assets/charset_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | ql-ascii: ! "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ 3 | js-ascii: "! \"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" 4 | ml-ascii: 5 | ''' 6 | ! "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ 7 | ''' 8 | } 9 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "node": true 5 | }, 6 | "extends": "eslint:recommended", 7 | "rules": { 8 | "indent": [ 9 | "error", 10 | 2, 11 | { "SwitchCase": 1 } 12 | ], 13 | "linebreak-style": [ 14 | "error", 15 | "unix" 16 | ], 17 | "semi": [ 18 | "error", 19 | "always" 20 | ], 21 | "no-empty": "off" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/assets/kan_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | numbers: 3 | [ 4 | 0 5 | 0 6 | 0 7 | 42 8 | 42.1 9 | -5 10 | -5.1 11 | 1701 12 | -1701 13 | 12.345 14 | -12.345 15 | ] 16 | native: 17 | [ 18 | true 19 | true 20 | false 21 | false 22 | null 23 | null 24 | ] 25 | strings: 26 | [ 27 | x 0 28 | .0 29 | 00 30 | 01 31 | 0 0 0 32 | 42 x 33 | 42.1 asdf 34 | 1.2.3 35 | -5 0 - 36 | -5.1 -- 37 | 17.01e2 + 38 | -17.01e2 : 39 | 12345e-3 @ 40 | -12345e-3 $ 41 | true true 42 | x true 43 | false false 44 | x false 45 | null null 46 | x null 47 | ] 48 | } -------------------------------------------------------------------------------- /sample/sample.js: -------------------------------------------------------------------------------- 1 | 2 | var Hjson=require("hjson"); 3 | var fs=require("fs"); 4 | var text=fs.readFileSync("test.hjson", "utf8"); 5 | 6 | // parse either JSON or Hjson 7 | var data=Hjson.parse(text); 8 | console.log(data.hello); 9 | console.log(); 10 | 11 | // convert to JSON 12 | console.log("--- JSON output:"); 13 | console.log(JSON.stringify(data, null, 2)); 14 | console.log(); 15 | 16 | // convert to Hjson 17 | console.log("\n--- Hjson output:"); 18 | console.log(Hjson.stringify(data)); 19 | 20 | // parse, keep whitespace and comments 21 | data=Hjson.rt.parse(text); 22 | 23 | // modify like you normally would 24 | data.foo="text"; 25 | 26 | console.log("\n--- Hjson output with comments:"); 27 | console.log(Hjson.rt.stringify(data)); 28 | -------------------------------------------------------------------------------- /test/assets/kan_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "numbers": [ 3 | 0, 4 | 0, 5 | 0, 6 | 42, 7 | 42.1, 8 | -5, 9 | -5.1, 10 | 1701, 11 | -1701, 12 | 12.345, 13 | -12.345 14 | ], 15 | "native": [ 16 | true, 17 | true, 18 | false, 19 | false, 20 | null, 21 | null 22 | ], 23 | "strings": [ 24 | "x 0", 25 | ".0", 26 | "00", 27 | "01", 28 | "0 0 0", 29 | "42 x", 30 | "42.1 asdf", 31 | "1.2.3", 32 | "-5 0 -", 33 | "-5.1 --", 34 | "17.01e2 +", 35 | "-17.01e2 :", 36 | "12345e-3 @", 37 | "-12345e-3 $", 38 | "true true", 39 | "x true", 40 | "false false", 41 | "x false", 42 | "null null", 43 | "x null" 44 | ] 45 | } -------------------------------------------------------------------------------- /test/assets/keys_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | unquoted_key: test 3 | _unquoted: test 4 | test-key: test 5 | -test: test 6 | .key: test 7 | trailing: test 8 | trailing2: test 9 | "#c1": test 10 | "foo#bar": test 11 | "//bar": test 12 | "foo//bar": test 13 | "/*foo*/": test 14 | "foo/*foo*/bar": test 15 | "/*": test 16 | "foo/*bar": test 17 | "\"": test 18 | "foo\"bar": test 19 | "'''": test 20 | "foo'''bar": test 21 | "'": test 22 | "'foo": test 23 | "foo'bar": test 24 | ":": test 25 | "foo:bar": test 26 | "{": test 27 | "foo{bar": test 28 | "}": test 29 | "foo}bar": test 30 | "[": test 31 | "foo[bar": test 32 | "]": test 33 | "foo]bar": test 34 | nl1: test 35 | nl2: test 36 | nl3: test 37 | } -------------------------------------------------------------------------------- /test/assets/kan_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # the comma forces a whitespace check 3 | numbers: 4 | [ 5 | 0 6 | 0 , 7 | -0 8 | 42 , 9 | 42.1 , 10 | -5 11 | -5.1 12 | 17.01e2 13 | -17.01e2 14 | 12345e-3 , 15 | -12345e-3 , 16 | ] 17 | native: 18 | [ 19 | true , 20 | true 21 | false , 22 | false 23 | null , 24 | null 25 | ] 26 | strings: 27 | [ 28 | x 0 29 | .0 30 | 00 31 | 01 32 | 0 0 0 33 | 42 x 34 | 42.1 asdf 35 | 1.2.3 36 | -5 0 - 37 | -5.1 -- 38 | 17.01e2 + 39 | -17.01e2 : 40 | 12345e-3 @ 41 | -12345e-3 $ 42 | true true 43 | x true 44 | false false 45 | x false 46 | null null 47 | x null 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /test/assets/strings2_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | key1: a key in single quotes 3 | "key 2": a key in single quotes 4 | "key \"": a key in single quotes 5 | text: 6 | [ 7 | single quoted string 8 | '''You need quotes for escapes''' 9 | " untrimmed " 10 | "untrimmed " 11 | containing " double quotes 12 | containing " double quotes 13 | containing " double quotes 14 | '''"containing more " double quotes"''' 15 | containing ' single quotes 16 | containing ' single quotes 17 | containing ' single quotes 18 | "'containing more ' single quotes'" 19 | "'containing more ' single quotes'" 20 | "\n" 21 | " \n" 22 | "\n \n \n \n" 23 | "\t\n" 24 | ] 25 | foo3a: asdf''' 26 | foo3b: "'''asdf" 27 | foo4a: "asdf'''\nasdf" 28 | foo4b: "asdf\n'''asdf" 29 | } -------------------------------------------------------------------------------- /test/assets/comments_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | foo1: This is a string value. # part of the string 3 | foo2: This is a string value. 4 | bar1: This is a string value. // part of the string 5 | bar2: This is a string value. 6 | foobar1: This is a string value./* part of the string */ 7 | foobar2: This is a string value. 8 | rem1: "# test" 9 | rem2: "// test" 10 | rem3: "/* test */" 11 | num1: 0 12 | num2: 0 13 | num3: 2 14 | true1: true 15 | true2: true 16 | true3: true 17 | false1: false 18 | false2: false 19 | false3: false 20 | null1: null 21 | null2: null 22 | null3: null 23 | str1: 00 # part of the string 24 | str2: 00.0 // part of the string 25 | str3: 02 /* part of the string */ 26 | URL1: http://example.com 27 | URL2: http://example.com 28 | URL3: http://example.com 29 | URL4: http://example.com 30 | } -------------------------------------------------------------------------------- /test/assets/strings2_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "key1": "a key in single quotes", 3 | "key 2": "a key in single quotes", 4 | "key \"": "a key in single quotes", 5 | "text": [ 6 | "single quoted string", 7 | "You need quotes\tfor escapes", 8 | " untrimmed ", 9 | "untrimmed ", 10 | "containing \" double quotes", 11 | "containing \" double quotes", 12 | "containing \" double quotes", 13 | "\"containing more \" double quotes\"", 14 | "containing ' single quotes", 15 | "containing ' single quotes", 16 | "containing ' single quotes", 17 | "'containing more ' single quotes'", 18 | "'containing more ' single quotes'", 19 | "\n", 20 | " \n", 21 | "\n \n \n \n", 22 | "\t\n" 23 | ], 24 | "foo3a": "asdf'''", 25 | "foo3b": "'''asdf", 26 | "foo4a": "asdf'''\nasdf", 27 | "foo4b": "asdf\n'''asdf" 28 | } -------------------------------------------------------------------------------- /test/assets/keys_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "unquoted_key": "test", 3 | "_unquoted": "test", 4 | "test-key": "test", 5 | "-test": "test", 6 | ".key": "test", 7 | "trailing": "test", 8 | "trailing2": "test", 9 | "#c1": "test", 10 | "foo#bar": "test", 11 | "//bar": "test", 12 | "foo//bar": "test", 13 | "/*foo*/": "test", 14 | "foo/*foo*/bar": "test", 15 | "/*": "test", 16 | "foo/*bar": "test", 17 | "\"": "test", 18 | "foo\"bar": "test", 19 | "'''": "test", 20 | "foo'''bar": "test", 21 | "'": "test", 22 | "'foo": "test", 23 | "foo'bar": "test", 24 | ":": "test", 25 | "foo:bar": "test", 26 | "{": "test", 27 | "foo{bar": "test", 28 | "}": "test", 29 | "foo}bar": "test", 30 | "[": "test", 31 | "foo[bar": "test", 32 | "]": "test", 33 | "foo]bar": "test", 34 | "nl1": "test", 35 | "nl2": "test", 36 | "nl3": "test" 37 | } -------------------------------------------------------------------------------- /test/assets/strings2_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # Hjson 3 allows the use of single quotes 3 | 4 | 'key1': a key in single quotes 5 | 'key 2': a key in single quotes 6 | 'key "': a key in single quotes 7 | 8 | text: [ 9 | 'single quoted string' 10 | 'You need quotes\tfor escapes' 11 | ' untrimmed ' 12 | 'untrimmed ' 13 | 'containing " double quotes' 14 | 'containing \" double quotes' 15 | "containing \" double quotes" 16 | '"containing more " double quotes"' 17 | 'containing \' single quotes' 18 | "containing ' single quotes" 19 | "containing \' single quotes" 20 | "'containing more ' single quotes'" 21 | "\'containing more \' single quotes\'" 22 | 23 | '\n' 24 | ' \n' 25 | '\n \n \n \n' 26 | '\t\n' 27 | ] 28 | 29 | # escapes/no escape 30 | 31 | foo3a: 'asdf\'\'\'' 32 | foo3b: '\'\'\'asdf' 33 | 34 | foo4a: 'asdf\'\'\'\nasdf' 35 | foo4b: 'asdf\n\'\'\'asdf' 36 | } 37 | -------------------------------------------------------------------------------- /test/assets/comments_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo1": "This is a string value. # part of the string", 3 | "foo2": "This is a string value.", 4 | "bar1": "This is a string value. // part of the string", 5 | "bar2": "This is a string value.", 6 | "foobar1": "This is a string value./* part of the string */", 7 | "foobar2": "This is a string value.", 8 | "rem1": "# test", 9 | "rem2": "// test", 10 | "rem3": "/* test */", 11 | "num1": 0, 12 | "num2": 0, 13 | "num3": 2, 14 | "true1": true, 15 | "true2": true, 16 | "true3": true, 17 | "false1": false, 18 | "false2": false, 19 | "false3": false, 20 | "null1": null, 21 | "null2": null, 22 | "null3": null, 23 | "str1": "00 # part of the string", 24 | "str2": "00.0 // part of the string", 25 | "str3": "02 /* part of the string */", 26 | "URL1": "http://example.com", 27 | "URL2": "http://example.com", 28 | "URL3": "http://example.com", 29 | "URL4": "http://example.com" 30 | } -------------------------------------------------------------------------------- /test/assets/keys_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # unquoted keys 3 | unquoted_key: test 4 | _unquoted: test 5 | test-key: test 6 | -test: test 7 | .key: test 8 | # trailing spaces in key names are ignored 9 | trailing : test 10 | trailing2 : test 11 | # comment char in key name 12 | "#c1": test 13 | "foo#bar": test 14 | "//bar": test 15 | "foo//bar": test 16 | "/*foo*/": test 17 | "foo/*foo*/bar": test 18 | "/*": test 19 | "foo/*bar": test 20 | # quotes in key name 21 | "\"": test 22 | "foo\"bar": test 23 | "'''": test 24 | "foo'''bar": test 25 | "'": test 26 | "'foo": test 27 | "foo'bar": test 28 | # control char in key name 29 | ":": test 30 | "foo:bar": test 31 | "{": test 32 | "foo{bar": test 33 | "}": test 34 | "foo}bar": test 35 | "[": test 36 | "foo[bar": test 37 | "]": test 38 | "foo]bar": test 39 | # newline 40 | nl1: 41 | test 42 | nl2 43 | : 44 | test 45 | 46 | nl3 47 | 48 | : 49 | 50 | test 51 | } 52 | -------------------------------------------------------------------------------- /test/assets/pass2_result.hjson: -------------------------------------------------------------------------------- 1 | [ 2 | [ 3 | [ 4 | [ 5 | [ 6 | [ 7 | [ 8 | [ 9 | [ 10 | [ 11 | [ 12 | [ 13 | [ 14 | [ 15 | [ 16 | [ 17 | [ 18 | [ 19 | [ 20 | Not too deep 21 | ] 22 | ] 23 | ] 24 | ] 25 | ] 26 | ] 27 | ] 28 | ] 29 | ] 30 | ] 31 | ] 32 | ] 33 | ] 34 | ] 35 | ] 36 | ] 37 | ] 38 | ] 39 | ] -------------------------------------------------------------------------------- /test/assets/pass2_result.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 3 | [ 4 | [ 5 | [ 6 | [ 7 | [ 8 | [ 9 | [ 10 | [ 11 | [ 12 | [ 13 | [ 14 | [ 15 | [ 16 | [ 17 | [ 18 | [ 19 | [ 20 | "Not too deep" 21 | ] 22 | ] 23 | ] 24 | ] 25 | ] 26 | ] 27 | ] 28 | ] 29 | ] 30 | ] 31 | ] 32 | ] 33 | ] 34 | ] 35 | ] 36 | ] 37 | ] 38 | ] 39 | ] -------------------------------------------------------------------------------- /test/assets/stringify1_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | quotes: 3 | { 4 | num1: "1,2" 5 | num2: "-1.1 ," 6 | num3: "1e10 ,2" 7 | num4: "-1e-10," 8 | kw1: "true," 9 | kw2: "false ," 10 | kw3: "null,123" 11 | close1: "1}" 12 | close1b: "1 }" 13 | close2: "1]" 14 | close2b: "1 ]" 15 | close3: "1," 16 | close3b: "1 ," 17 | comment1: "1#str" 18 | comment2: "1//str" 19 | comment3: "1/*str*/" 20 | punc1: "{" 21 | punc1b: "{foo" 22 | punc2: "}" 23 | punc2b: "}foo" 24 | punc3: "[" 25 | punc3b: "[foo" 26 | punc4: "]" 27 | punc4b: "]foo" 28 | punc5: "," 29 | punc5b: ",foo" 30 | punc6: ":" 31 | punc6b: ":foo" 32 | } 33 | noquotes: 34 | { 35 | num0: .1,2 36 | num1: 1.1.1,2 37 | num2: -.1, 38 | num3: 1e10e,2 39 | num4: -1e--10, 40 | kw1: true1, 41 | kw2: false0, 42 | kw3: null0, 43 | close1: a} 44 | close2: a] 45 | comment1: a#str 46 | comment2: a//str 47 | comment3: a/*str*/ 48 | } 49 | } -------------------------------------------------------------------------------- /sample/test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # comments are treated like whitespace - they are not parsed 3 | 4 | hello: Hello Human! 5 | 6 | // js style comment 7 | 8 | /* 9 | multiline comment 10 | multiline comment 11 | */ 12 | 13 | # text 14 | text: This is a valid string value. 15 | quote: "You need quotes\tfor escapes" 16 | otherwise:
life without escapes is bliss!
17 | 18 | # keys 19 | abc-123: no quotes for keys 20 | 21 | # comma 22 | commas: "can be omitted at the end of the line" 23 | but: [ 1, 2, 3 ] # not between elements on the same line 24 | trailing: [ 1, 2, 3, ] # a trailing comma is OK 25 | 26 | # multiline string 27 | multiline: 28 | ''' 29 | first line 30 | indented line 31 | third line 32 | ''' 33 | 34 | # numbers, keywords and arrays work just like in JSON 35 | number: 5 36 | negative: -4.2 37 | yes: true 38 | no: false 39 | null: null 40 | array: [ 1, 2 ] 41 | array2: [ 42 | 1 43 | 2 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /test/assets/stringify1_test.hjson: -------------------------------------------------------------------------------- 1 | // test if stringify produces correct output 2 | { 3 | quotes: 4 | { 5 | num1: "1,2" 6 | num2: "-1.1 ," 7 | num3: "1e10 ,2" 8 | num4: "-1e-10," 9 | kw1: "true," 10 | kw2: "false ," 11 | kw3: "null,123" 12 | close1: "1}" 13 | close1b: "1 }" 14 | close2: "1]" 15 | close2b: "1 ]" 16 | close3: "1," 17 | close3b: "1 ," 18 | comment1: "1#str" 19 | comment2: "1//str" 20 | comment3: "1/*str*/" 21 | punc1: "{" 22 | punc1b: "{foo" 23 | punc2: "}" 24 | punc2b: "}foo" 25 | punc3: "[" 26 | punc3b: "[foo" 27 | punc4: "]" 28 | punc4b: "]foo" 29 | punc5: "," 30 | punc5b: ",foo" 31 | punc6: ":" 32 | punc6b: ":foo" 33 | } 34 | noquotes: 35 | { 36 | num0: ".1,2" 37 | num1: "1.1.1,2" 38 | num2: "-.1," 39 | num3: "1e10e,2" 40 | num4: "-1e--10," 41 | kw1: "true1," 42 | kw2: "false0," 43 | kw3: "null0," 44 | close1: "a}" 45 | close2: "a]" 46 | comment1: "a#str" 47 | comment2: "a//str" 48 | comment3: "a/*str*/" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/assets/stringify1_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "quotes": { 3 | "num1": "1,2", 4 | "num2": "-1.1 ,", 5 | "num3": "1e10 ,2", 6 | "num4": "-1e-10,", 7 | "kw1": "true,", 8 | "kw2": "false ,", 9 | "kw3": "null,123", 10 | "close1": "1}", 11 | "close1b": "1 }", 12 | "close2": "1]", 13 | "close2b": "1 ]", 14 | "close3": "1,", 15 | "close3b": "1 ,", 16 | "comment1": "1#str", 17 | "comment2": "1//str", 18 | "comment3": "1/*str*/", 19 | "punc1": "{", 20 | "punc1b": "{foo", 21 | "punc2": "}", 22 | "punc2b": "}foo", 23 | "punc3": "[", 24 | "punc3b": "[foo", 25 | "punc4": "]", 26 | "punc4b": "]foo", 27 | "punc5": ",", 28 | "punc5b": ",foo", 29 | "punc6": ":", 30 | "punc6b": ":foo" 31 | }, 32 | "noquotes": { 33 | "num0": ".1,2", 34 | "num1": "1.1.1,2", 35 | "num2": "-.1,", 36 | "num3": "1e10e,2", 37 | "num4": "-1e--10,", 38 | "kw1": "true1,", 39 | "kw2": "false0,", 40 | "kw3": "null0,", 41 | "close1": "a}", 42 | "close2": "a]", 43 | "comment1": "a#str", 44 | "comment2": "a//str", 45 | "comment3": "a/*str*/" 46 | } 47 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2017 Christian Zangl 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/assets/comments_test.hjson: -------------------------------------------------------------------------------- 1 | // test 2 | # all 3 | // comment 4 | /* 5 | styles 6 | */ 7 | # with lf 8 | 9 | 10 | 11 | # ! 12 | 13 | { 14 | # hjson style comment 15 | foo1: This is a string value. # part of the string 16 | foo2: "This is a string value." # a comment 17 | 18 | // js style comment 19 | bar1: This is a string value. // part of the string 20 | bar2: "This is a string value." // a comment 21 | 22 | /* js block style comments */foobar1:/* more */This is a string value./* part of the string */ 23 | /* js block style comments */foobar2:/* more */"This is a string value."/* a comment */ 24 | 25 | rem1: "# test" 26 | rem2: "// test" 27 | rem3: "/* test */" 28 | 29 | num1: 0 # comment 30 | num2: 0.0 // comment 31 | num3: 2 /* comment */ 32 | 33 | true1: true # comment 34 | true2: true // comment 35 | true3: true /* comment */ 36 | 37 | false1: false # comment 38 | false2: false // comment 39 | false3: false /* comment */ 40 | 41 | null1: null # comment 42 | null2: null // comment 43 | null3: null /* comment */ 44 | 45 | str1: 00 # part of the string 46 | str2: 00.0 // part of the string 47 | str3: 02 /* part of the string */ 48 | 49 | # this causes problems with the syntax definitions for some editors: 50 | URL1: "http://example.com", 51 | "URL2": "http://example.com", 52 | URL3: http://example.com 53 | "URL4": http://example.com 54 | } 55 | -------------------------------------------------------------------------------- /test/assets/strings_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "This is a valid string value.", 3 | "text2": "a \\ is just a \\", 4 | "text3": "You need quotes\tfor escapes", 5 | "text4a": " untrimmed ", 6 | "text4b": " untrimmed", 7 | "text4c": "untrimmed ", 8 | "notml1": "\n", 9 | "notml2": " \n", 10 | "notml3": "\n \n \n \n", 11 | "notml4": "\t\n", 12 | "multiline1": "first line\n indented line\nlast line", 13 | "multiline2": "first line\n indented line\nlast line", 14 | "multiline3": "first line\n indented line\nlast line\n", 15 | "foo1a": "asdf\\\"'a\\s\\w", 16 | "foo1b": "asdf\\\"'a\\s\\w", 17 | "foo1c": "asdf\\\"'a\\s\\w", 18 | "foo2a": "\"asdf\"", 19 | "foo2b": "\"asdf\"", 20 | "foo3a": "asdf'''", 21 | "foo3b": "'''asdf", 22 | "foo4a": "asdf'''\nasdf", 23 | "foo4b": "asdf\n'''asdf", 24 | "arr": [ 25 | "one", 26 | "two", 27 | "three", 28 | "four" 29 | ], 30 | "not": { 31 | "number": 5, 32 | "negative": -4.2, 33 | "yes": true, 34 | "no": false, 35 | "null": null, 36 | "array": [ 37 | 1, 38 | 2, 39 | 3, 40 | 4, 41 | 5, 42 | 6, 43 | 7, 44 | 8, 45 | 9, 46 | 0, 47 | -1, 48 | 0.5 49 | ] 50 | }, 51 | "special": { 52 | "true": "true", 53 | "false": "false", 54 | "null": "null", 55 | "one": "1", 56 | "two": "2", 57 | "minus": "-3" 58 | } 59 | } -------------------------------------------------------------------------------- /test/assets/strings_result.hjson: -------------------------------------------------------------------------------- 1 | { 2 | text1: This is a valid string value. 3 | text2: a \ is just a \ 4 | text3: '''You need quotes for escapes''' 5 | text4a: " untrimmed " 6 | text4b: " untrimmed" 7 | text4c: "untrimmed " 8 | notml1: "\n" 9 | notml2: " \n" 10 | notml3: "\n \n \n \n" 11 | notml4: "\t\n" 12 | multiline1: 13 | ''' 14 | first line 15 | indented line 16 | last line 17 | ''' 18 | multiline2: 19 | ''' 20 | first line 21 | indented line 22 | last line 23 | ''' 24 | multiline3: 25 | ''' 26 | first line 27 | indented line 28 | last line 29 | 30 | ''' 31 | foo1a: asdf\"'a\s\w 32 | foo1b: asdf\"'a\s\w 33 | foo1c: asdf\"'a\s\w 34 | foo2a: '''"asdf"''' 35 | foo2b: '''"asdf"''' 36 | foo3a: asdf''' 37 | foo3b: "'''asdf" 38 | foo4a: "asdf'''\nasdf" 39 | foo4b: "asdf\n'''asdf" 40 | arr: 41 | [ 42 | one 43 | two 44 | three 45 | four 46 | ] 47 | not: 48 | { 49 | number: 5 50 | negative: -4.2 51 | yes: true 52 | no: false 53 | null: null 54 | array: 55 | [ 56 | 1 57 | 2 58 | 3 59 | 4 60 | 5 61 | 6 62 | 7 63 | 8 64 | 9 65 | 0 66 | -1 67 | 0.5 68 | ] 69 | } 70 | special: 71 | { 72 | true: "true" 73 | false: "false" 74 | null: "null" 75 | one: "1" 76 | two: "2" 77 | minus: "-3" 78 | } 79 | } -------------------------------------------------------------------------------- /test/assets/pass1_result.hjson: -------------------------------------------------------------------------------- 1 | [ 2 | JSON Test Pattern pass1 3 | { 4 | "object with 1 member": 5 | [ 6 | array with 1 element 7 | ] 8 | } 9 | {} 10 | [] 11 | -42 12 | true 13 | false 14 | null 15 | { 16 | integer: 1234567890 17 | real: -9876.54321 18 | e: 1.23456789e-13 19 | E: 1.23456789e+34 20 | -: 2.3456789012e+76 21 | zero: 0 22 | one: 1 23 | space: " " 24 | quote: '''"''' 25 | backslash: \ 26 | controls: "\b\f\n\r\t" 27 | slash: / & / 28 | alpha: abcdefghijklmnopqrstuvwyz 29 | ALPHA: ABCDEFGHIJKLMNOPQRSTUVWYZ 30 | digit: 0123456789 31 | 0123456789: digit 32 | special: `1~!@#$%^&*()_+-={':[,]}|;.? 33 | hex: ģ䕧覫췯ꯍ 34 | true: true 35 | false: false 36 | null: null 37 | array: [] 38 | object: {} 39 | address: 50 St. James Street 40 | url: http://www.JSON.org/ 41 | comment: "// /* */": " " 43 | " s p a c e d ": 44 | [ 45 | 1 46 | 2 47 | 3 48 | 4 49 | 5 50 | 6 51 | 7 52 | ] 53 | compact: 54 | [ 55 | 1 56 | 2 57 | 3 58 | 4 59 | 5 60 | 6 61 | 7 62 | ] 63 | jsontext: '''{"object with 1 member":["array with 1 element"]}''' 64 | quotes: " " %22 0x22 034 " 65 | "/\\\"쫾몾ꮘﳞ볚\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?": A key can be any string 66 | } 67 | 0.5 68 | 98.6 69 | 99.44 70 | 1066 71 | 10 72 | 1 73 | 0.1 74 | 1 75 | 2 76 | 2 77 | rosebud 78 | ] -------------------------------------------------------------------------------- /test/assets/strings_test.hjson: -------------------------------------------------------------------------------- 1 | { 2 | # simple 3 | 4 | text1: This is a valid string value. 5 | text2:a \ is just a \ 6 | 7 | text3: "You need quotes\tfor escapes" 8 | 9 | text4a: " untrimmed " 10 | text4b: " untrimmed" 11 | text4c: "untrimmed " 12 | 13 | notml1: "\n" 14 | notml2: " \n" 15 | notml3: "\n \n \n \n" 16 | notml4: "\t\n" 17 | 18 | # multiline string 19 | 20 | multiline1: 21 | ''' 22 | first line 23 | indented line 24 | last line 25 | ''' 26 | 27 | multiline2: 28 | '''first line 29 | indented line 30 | last line''' 31 | 32 | multiline3: 33 | ''' 34 | first line 35 | indented line 36 | last line 37 | 38 | ''' # trailing lf 39 | 40 | # escapes/no escape 41 | 42 | foo1a: asdf\"'a\s\w 43 | foo1b: '''asdf\"'a\s\w''' 44 | foo1c: "asdf\\\"'a\\s\\w" 45 | 46 | foo2a: "\"asdf\"" 47 | foo2b: '''"asdf"''' 48 | 49 | foo3a: "asdf'''" 50 | foo3b: "'''asdf" 51 | 52 | foo4a: "asdf'''\nasdf" 53 | foo4b: "asdf\n'''asdf" 54 | 55 | # in arrays 56 | arr: 57 | [ 58 | one 59 | two 60 | "three" 61 | '''four''' 62 | ] 63 | 64 | # not strings 65 | not: 66 | { 67 | number: 5 68 | negative: -4.2 69 | yes: true 70 | no: false 71 | null: null 72 | array: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, -1, 0.5 ] 73 | } 74 | 75 | # special quoted 76 | special: 77 | { 78 | true: "true" 79 | false: "false" 80 | null: "null" 81 | one: "1" 82 | two: "2" 83 | minus: "-3" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /test/assets/pass1_result.json: -------------------------------------------------------------------------------- 1 | [ 2 | "JSON Test Pattern pass1", 3 | { 4 | "object with 1 member": [ 5 | "array with 1 element" 6 | ] 7 | }, 8 | {}, 9 | [], 10 | -42, 11 | true, 12 | false, 13 | null, 14 | { 15 | "integer": 1234567890, 16 | "real": -9876.54321, 17 | "e": 1.23456789e-13, 18 | "E": 1.23456789e+34, 19 | "-": 2.3456789012e+76, 20 | "zero": 0, 21 | "one": 1, 22 | "space": " ", 23 | "quote": "\"", 24 | "backslash": "\\", 25 | "controls": "\b\f\n\r\t", 26 | "slash": "/ & /", 27 | "alpha": "abcdefghijklmnopqrstuvwyz", 28 | "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", 29 | "digit": "0123456789", 30 | "0123456789": "digit", 31 | "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", 32 | "hex": "ģ䕧覫췯ꯍ", 33 | "true": true, 34 | "false": false, 35 | "null": null, 36 | "array": [], 37 | "object": {}, 38 | "address": "50 St. James Street", 39 | "url": "http://www.JSON.org/", 40 | "comment": "// /* */": " ", 42 | " s p a c e d ": [ 43 | 1, 44 | 2, 45 | 3, 46 | 4, 47 | 5, 48 | 6, 49 | 7 50 | ], 51 | "compact": [ 52 | 1, 53 | 2, 54 | 3, 55 | 4, 56 | 5, 57 | 6, 58 | 7 59 | ], 60 | "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", 61 | "quotes": "" \" %22 0x22 034 "", 62 | "/\\\"쫾몾ꮘﳞ볚\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?": "A key can be any string" 63 | }, 64 | 0.5, 65 | 98.6, 66 | 99.44, 67 | 1066, 68 | 10, 69 | 1, 70 | 0.1, 71 | 1, 72 | 2, 73 | 2, 74 | "rosebud" 75 | ] -------------------------------------------------------------------------------- /test/assets/pass1_test.json: -------------------------------------------------------------------------------- 1 | [ 2 | "JSON Test Pattern pass1", 3 | {"object with 1 member":["array with 1 element"]}, 4 | {}, 5 | [], 6 | -42, 7 | true, 8 | false, 9 | null, 10 | { 11 | "integer": 1234567890, 12 | "real": -9876.543210, 13 | "e": 0.123456789e-12, 14 | "E": 1.234567890E+34, 15 | "-": 23456789012E66, 16 | "zero": 0, 17 | "one": 1, 18 | "space": " ", 19 | "quote": "\"", 20 | "backslash": "\\", 21 | "controls": "\b\f\n\r\t", 22 | "slash": "/ & \/", 23 | "alpha": "abcdefghijklmnopqrstuvwyz", 24 | "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", 25 | "digit": "0123456789", 26 | "0123456789": "digit", 27 | "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", 28 | "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", 29 | "true": true, 30 | "false": false, 31 | "null": null, 32 | "array":[ ], 33 | "object":{ }, 34 | "address": "50 St. James Street", 35 | "url": "http://www.JSON.org/", 36 | "comment": "// /* */": " ", 38 | " s p a c e d " :[1,2 , 3 39 | 40 | , 41 | 42 | 4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], 43 | "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", 44 | "quotes": "" \u0022 %22 0x22 034 "", 45 | "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" 46 | : "A key can be any string" 47 | }, 48 | 0.5 ,98.6 49 | , 50 | 99.44 51 | , 52 | 53 | 1066, 54 | 1e1, 55 | 0.1e1, 56 | 1e-1, 57 | 1e00,2e+00,2e-00 58 | ,"rosebud"] -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hjson", 3 | "description": "A user interface for JSON.", 4 | "main": "./lib/hjson.js", 5 | "author": "Christian Zangl", 6 | "version": "3.2.2", 7 | "keywords": [ 8 | "json", 9 | "comments", 10 | "config", 11 | "hjson", 12 | "parser", 13 | "serializer", 14 | "human" 15 | ], 16 | "bin": { 17 | "hjson": "./bin/hjson" 18 | }, 19 | "scripts": { 20 | "test": "node ./test/test.js", 21 | "lint": "node_modules/eslint/bin/eslint.js -f unix bin/hjson lib/*.js", 22 | "build_v1": "node -e 'console.log(\"module.exports=\\\"\"+eval(\"(\"+process.argv[1]+\")\").version+\"\\\";\");' -- \"`cat package.json`\" > lib/hjson-version.js", 23 | "build_v2": "node -e 'var v=\" * Hjson v\"+eval(\"(\"+process.argv[1]+\")\").version; if (v!==process.argv[2]) throw new Error(\"ver\");' -- \"`cat package.json`\" \"`grep -E '\\* Hjson v.*$' lib/hjson.js`\"", 24 | "build_bundle": "node_modules/browserify/bin/cmd.js -p browserify-header --ignore os -s Hjson -o bundle/hjson.js lib/hjson.js", 25 | "build_min": "node node_modules/uglify-js/bin/uglifyjs bundle/hjson.js --comments=/^!/ -c -m -o bundle/hjson.min.js", 26 | "build": "npm run build_v1 && npm run build_v2 && npm run test && npm run lint && npm run build_bundle && npm run build_min" 27 | }, 28 | "homepage": "https://hjson.github.io", 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/hjson/hjson-js.git" 32 | }, 33 | "bugs": { 34 | "url": "https://github.com/hjson/hjson-js/issues" 35 | }, 36 | "license": "MIT", 37 | "devDependencies": { 38 | "browserify": "^13.3.0", 39 | "browserify-header": "0.9.2", 40 | "eslint": "^3.13.1", 41 | "uglify-js": "^2.7.5" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/assets/testlist.txt: -------------------------------------------------------------------------------- 1 | charset2_test.hjson 2 | charset_test.hjson 3 | comments_test.hjson 4 | empty_test.hjson 5 | failCharset1_test.hjson 6 | failJSON02_test.json 7 | failJSON05_test.json 8 | failJSON06_test.json 9 | failJSON07_test.json 10 | failJSON08_test.json 11 | failJSON10_test.json 12 | failJSON11_test.json 13 | failJSON12_test.json 14 | failJSON13_test.json 15 | failJSON14_test.json 16 | failJSON15_test.json 17 | failJSON16_test.json 18 | failJSON17_test.json 19 | failJSON19_test.json 20 | failJSON20_test.json 21 | failJSON21_test.json 22 | failJSON22_test.json 23 | failJSON23_test.json 24 | failJSON26_test.json 25 | failJSON28_test.json 26 | failJSON29_test.json 27 | failJSON30_test.json 28 | failJSON31_test.json 29 | failJSON32_test.json 30 | failJSON33_test.json 31 | failJSON34_test.json 32 | failKey1_test.hjson 33 | failKey2_test.hjson 34 | failKey3_test.hjson 35 | failKey4_test.hjson 36 | failKey5_test.hjson 37 | failMLStr1_test.hjson 38 | failObj1_test.hjson 39 | failObj2_test.hjson 40 | failObj3_test.hjson 41 | failStr1a_test.hjson 42 | failStr1b_test.hjson 43 | failStr1c_test.hjson 44 | failStr1d_test.hjson 45 | failStr2a_test.hjson 46 | failStr2b_test.hjson 47 | failStr2c_test.hjson 48 | failStr2d_test.hjson 49 | failStr3a_test.hjson 50 | failStr3b_test.hjson 51 | failStr3c_test.hjson 52 | failStr3d_test.hjson 53 | failStr4a_test.hjson 54 | failStr4b_test.hjson 55 | failStr4c_test.hjson 56 | failStr4d_test.hjson 57 | failStr5a_test.hjson 58 | failStr5b_test.hjson 59 | failStr5c_test.hjson 60 | failStr5d_test.hjson 61 | failStr6a_test.hjson 62 | failStr6b_test.hjson 63 | failStr6c_test.hjson 64 | failStr6d_test.hjson 65 | failStr7a_test.hjson 66 | failStr8a_test.hjson 67 | kan_test.hjson 68 | keys_test.hjson 69 | mltabs_test.json 70 | oa_test.hjson 71 | pass1_test.json 72 | pass2_test.json 73 | pass3_test.json 74 | pass4_test.json 75 | passSingle_test.hjson 76 | stringify1_test.hjson 77 | strings2_test.hjson 78 | strings_test.hjson 79 | trail_test.hjson 80 | stringify/quotes_all_test.hjson 81 | stringify/quotes_always_test.hjson 82 | stringify/quotes_keys_test.hjson 83 | stringify/quotes_strings_ml_test.json 84 | stringify/quotes_strings_test.hjson 85 | extra/notabs_test.json 86 | extra/root_test.hjson 87 | extra/separator_test.json -------------------------------------------------------------------------------- /lib/hjson-common.js: -------------------------------------------------------------------------------- 1 | /* Hjson https://hjson.github.io */ 2 | "use strict"; 3 | 4 | var os=require('os'); // will be {} when used in a browser 5 | 6 | function tryParseNumber(text, stopAtNext) { 7 | 8 | // try to parse a number 9 | 10 | var number, string = '', leadingZeros = 0, testLeading = true; 11 | var at = 0; 12 | var ch; 13 | function next() { 14 | ch = text.charAt(at); 15 | at++; 16 | return ch; 17 | } 18 | 19 | next(); 20 | if (ch === '-') { 21 | string = '-'; 22 | next(); 23 | } 24 | while (ch >= '0' && ch <= '9') { 25 | if (testLeading) { 26 | if (ch == '0') leadingZeros++; 27 | else testLeading = false; 28 | } 29 | string += ch; 30 | next(); 31 | } 32 | if (testLeading) leadingZeros--; // single 0 is allowed 33 | if (ch === '.') { 34 | string += '.'; 35 | while (next() && ch >= '0' && ch <= '9') 36 | string += ch; 37 | } 38 | if (ch === 'e' || ch === 'E') { 39 | string += ch; 40 | next(); 41 | if (ch === '-' || ch === '+') { 42 | string += ch; 43 | next(); 44 | } 45 | while (ch >= '0' && ch <= '9') { 46 | string += ch; 47 | next(); 48 | } 49 | } 50 | 51 | // skip white/to (newline) 52 | while (ch && ch <= ' ') next(); 53 | 54 | if (stopAtNext) { 55 | // end scan if we find a punctuator character like ,}] or a comment 56 | if (ch === ',' || ch === '}' || ch === ']' || 57 | ch === '#' || ch === '/' && (text[at] === '/' || text[at] === '*')) ch = 0; 58 | } 59 | 60 | number = +string; 61 | if (ch || leadingZeros || !isFinite(number)) return undefined; 62 | else return number; 63 | } 64 | 65 | function createComment(value, comment) { 66 | if (Object.defineProperty) Object.defineProperty(value, "__COMMENTS__", { enumerable: false, writable: true }); 67 | return (value.__COMMENTS__ = comment||{}); 68 | } 69 | 70 | function removeComment(value) { 71 | Object.defineProperty(value, "__COMMENTS__", { value: undefined }); 72 | } 73 | 74 | function getComment(value) { 75 | return value.__COMMENTS__; 76 | } 77 | 78 | function forceComment(text) { 79 | if (!text) return ""; 80 | var a = text.split('\n'); 81 | var str, i, j, len; 82 | for (j = 0; j < a.length; j++) { 83 | str = a[j]; 84 | len = str.length; 85 | for (i = 0; i < len; i++) { 86 | var c = str[i]; 87 | if (c === '#') break; 88 | else if (c === '/' && (str[i+1] === '/' || str[i+1] === '*')) { 89 | if (str[i+1] === '*') j = a.length; // assume /**/ covers whole block, bail out 90 | break; 91 | } 92 | else if (c > ' ') { 93 | a[j] = '# ' + str; 94 | break; 95 | } 96 | } 97 | } 98 | return a.join('\n'); 99 | } 100 | 101 | module.exports = { 102 | EOL: os.EOL || '\n', 103 | tryParseNumber: tryParseNumber, 104 | createComment: createComment, 105 | removeComment: removeComment, 106 | getComment: getComment, 107 | forceComment: forceComment, 108 | }; 109 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | 2 | var Hjson = require(".."); 3 | var fs = require("fs"); 4 | var path = require("path"); 5 | var rootDir = path.normalize(path.join(__dirname, "assets")); 6 | 7 | var args={}, argv=[]; 8 | process.argv.slice(2).forEach(function(x) { if (x[0]==="-") { var i=x.indexOf("="); args[x.substr(1, i>0?i-1:undefined)]=i>0?x.substr(i+1):true; } else argv.push(x); }); 9 | 10 | var filter=argv[0]; 11 | var success=true; 12 | var defaultOptions = { legacyRoot: false }; 13 | 14 | function failErr(name, type, s1, s2, msg) { 15 | msg=msg||" "+name+" "+type+" FAILED!"; 16 | console.log(msg); 17 | if (s1 || s2) { 18 | var i=0; 19 | while (i0?i-1:undefined)]=i>0?x.substr(i+1):true; } 12 | else if (x[0]==="+") { i=x.indexOf("="); args[x.substr(0, i>0?i:undefined)]=i>0?x.substr(i+1):true; } 13 | else argv.push(x); 14 | }); 15 | 16 | if (args["-help"] || args["?"] || args.h) { 17 | console.error("Hjson, the Human JSON."); 18 | console.error(); 19 | console.error("Usage:"); 20 | console.error(" hjson [OPTIONS]"); 21 | console.error(" hjson [OPTIONS] INPUT"); 22 | console.error(" hjson (-h | --help | -?)"); 23 | console.error(" hjson (-V | --version)"); 24 | console.error(); 25 | console.error("INPUT can be in JSON or Hjson format. If no file is given it will read from stdin."); 26 | console.error("The default is to output as Hjson."); 27 | console.error(); 28 | console.error("Options:"); 29 | console.error(" (-j | -json) output as formatted JSON."); 30 | console.error(" (-c | -json=compact) output as JSON."); 31 | console.error("Options for Hjson output:"); 32 | console.error(" -sl output the opening brace on the same line"); 33 | console.error(" -quote quote all strings"); 34 | console.error(" -quote=all quote keys as well"); 35 | console.error(" -js output in JavaScript/JSON compatible format"); 36 | console.error(" can be used with -rt and // comments"); 37 | console.error(" -rt round trip comments"); 38 | console.error(" -nocol disable colors"); 39 | console.error(" -cond=n set condense option (default 60, 0 to disable)"); 40 | console.error(""); 41 | console.error("Domain specific formats are optional extensions to Hjson and can be enabled with the following options:"); 42 | Object.keys(Hjson.dsf).forEach(function(name) { 43 | console.error(" +"+name+": "+Hjson.dsf[name].description); 44 | }); 45 | return 0; 46 | } 47 | else if (args.V || args["-version"]) { 48 | console.log("Hjson.js " + Hjson.version); 49 | return 0; 50 | } 51 | 52 | if (args["+math"]) dsf.push(Hjson.dsf.math()); 53 | if (args["+date"]) dsf.push(Hjson.dsf.date({free:false})); 54 | if (args["+hex"]) dsf.push(Hjson.dsf.hex({out:false})); 55 | 56 | var text; 57 | if (argv.length) { 58 | text=fs.readFileSync(argv[0], "utf8"); 59 | convert(text); 60 | } 61 | else { 62 | var stdin = process.openStdin(); 63 | stdin.setEncoding('utf-8'); 64 | text = ''; 65 | stdin.on('data', function(chunk) { text += chunk; }); 66 | stdin.on('end', function() { convert(text); }); 67 | } 68 | 69 | function convert(text) { 70 | var obj; 71 | try { obj=Hjson.parse(text, { keepWsc: args.rt, dsf: dsf }); } 72 | catch (e) { 73 | console.error(e.toString()); 74 | if (e.hint) console.error("\nhint: "+e.hint); 75 | process.exit(1); // set exit code 76 | return; 77 | } 78 | 79 | var result; 80 | if (args.c || args.json==="compact") result = JSON.stringify(obj); 81 | else if (args.j || args.json) result = JSON.stringify(obj, null, 2); 82 | else { 83 | if (args.js) args.quote="all"; 84 | if (args.quote===true) args.quote="strings"; 85 | result = Hjson.stringify(obj, { 86 | condense: args.cond || 60, 87 | bracesSameLine: args.sl, 88 | quotes: args.quote, 89 | separator: args.js, 90 | keepWsc: args.rt, 91 | colors: !args.nocol && process.stdout.isTTY, 92 | dsf: dsf, 93 | }); 94 | } 95 | 96 | process.stdout.write(result + os.EOL); 97 | } 98 | 99 | -------------------------------------------------------------------------------- /history.md: -------------------------------------------------------------------------------- 1 | # hjson-js History 2 | 3 | - v3.2.1 4 | - fix stringifying with comments 5 | - v3.2.0 6 | - add `sortProps` option to deterministically sort object properties 7 | - v3.1.1 8 | - set exit code for cli tool 9 | - v3.1.0 10 | - add condense mode for stringify 11 | - v3.0.2 12 | - fix stringify for keys containing single quotes 13 | - v3.0.1 14 | - add option to turn off legacy support for omitting root braces 15 | - v3.0.0 16 | - add support for single quoted strings 17 | - v2.4.3 18 | - fix throw error on string containing newline 19 | - v2.4.2 20 | - add error hint for incorrect single quotes 21 | - v2.4.1 22 | - fix tty colors 23 | - v2.4.0 24 | - new stringify options: 25 | - quotes for keys and strings (SamVerschueren) 26 | - comma separator (SamVerschueren) 27 | - multiline strings output (hmalphettes) 28 | - v2.3.1 29 | - add comments api (merge/extract) 30 | - v2.3.0 31 | - improved comment round trip 32 | - v2.2.0 33 | - stringify will always emit root braces 34 | - v2.1.0 35 | - add DSF (domain specific formats), experimental 36 | - refactor, use browserify for output (see bundle) 37 | - fix emit root braces by default (was off) 38 | - v2.0.8 (not released) 39 | - v2.0.7 40 | - added stringify color option (CLI) 41 | - v2.0.6 42 | - show better messages for parsing errors on a root object without braces 43 | - include error hint when a missing closing } or ] is part of a string 44 | - v2.0.5 45 | - fix stringify for strings staring with a punctuator char 46 | - v2.0.4 47 | - move to hjson org 48 | - v2.0.3 49 | - fix stringify regression 50 | - add test 51 | - v2.0.2 52 | - remove obsoletes 53 | - v2.0.1 54 | - simpler stringify 55 | - v2.0.0 56 | - add stricter check for {}[],: at the start of a quoteless string 57 | - v1.8.4 58 | - fix multiline stringify 59 | - v1.8.3 60 | - fix stringify for key names containing comments/control characters 61 | - v1.8.2 62 | - better parse for single JSON values 63 | - v1.8.1 64 | - detect EOF when looking for a key name 65 | - v1.7.6 66 | - fix trailing whitespace in keyname 67 | - v1.7.4 68 | - fix trailing space in quoteless strings 69 | - fix default braces 70 | - v1.7.3 71 | - fix root check 72 | - better error messages 73 | - v1.7.2 74 | - fixed stringify, see hjson/hjson#29 75 | - optional root braces, see hjson/hjson#28 76 | - v1.6.3 77 | - added stringify options 78 | - v1.6.1 79 | - fixed stringify with options===null 80 | - v1.6.0 81 | - Added `rt` (roundtrip) shortcut. 82 | - v1.5.0 83 | - Added support for the simplified syntax for keys. Previously only alphanumeric keys were allowed without quotes. 84 | - Fixed multiline strings: OS/file independent (EOL is always `\n`). Also the last LF is removed. 85 | - v1.4.0 86 | - Changed the browser interface to match the node api (which didn't change). 87 | - Fixed parse for leading zeros ("00") and trailing comments. 88 | - Fixed stringify for /**/ and // 89 | - Added more test cases. 90 | - v1.3.0 91 | - Added support for the simplified syntax. 92 | - v1.2.0 93 | - Added old fashioned /**/ comments. 94 | - Fixed the missing EOL (cli only). 95 | - v1.1.0 96 | - add // support 97 | - v1.0.2 98 | - stringify bug fixes 99 | - v1.0.0 100 | - Switched to v1 for semver. 101 | - Adds editing support via the `{ keepWsc: true }` option. 102 | - Removes stringify(value, replacer, space) replacer support 103 | - You can still use this syntax but replacer will no longer be called. This was removed in favor of editing support and because replacer provided an incomplete solution. 104 | -------------------------------------------------------------------------------- /lib/hjson-dsf.js: -------------------------------------------------------------------------------- 1 | /* Hjson https://hjson.github.io */ 2 | "use strict"; 3 | 4 | function loadDsf(col, type) { 5 | 6 | if (Object.prototype.toString.apply(col) !== '[object Array]') { 7 | if (col) throw new Error("dsf option must contain an array!"); 8 | else return nopDsf; 9 | } else if (col.length === 0) return nopDsf; 10 | 11 | var dsf = []; 12 | function isFunction(f) { return {}.toString.call(f) === '[object Function]'; } 13 | 14 | col.forEach(function(x) { 15 | if (!x.name || !isFunction(x.parse) || !isFunction(x.stringify)) 16 | throw new Error("extension does not match the DSF interface"); 17 | dsf.push(function() { 18 | try { 19 | if (type == "parse") { 20 | return x.parse.apply(null, arguments); 21 | } else if (type == "stringify") { 22 | var res=x.stringify.apply(null, arguments); 23 | // check result 24 | if (res !== undefined && (typeof res !== "string" || 25 | res.length === 0 || 26 | res[0] === '"' || 27 | [].some.call(res, function(c) { return isInvalidDsfChar(c); }))) 28 | throw new Error("value may not be empty, start with a quote or contain a punctuator character except colon: " + res); 29 | return res; 30 | } else throw new Error("Invalid type"); 31 | } catch (e) { 32 | throw new Error("DSF-"+x.name+" failed; "+e.message); 33 | } 34 | }); 35 | }); 36 | 37 | return runDsf.bind(null, dsf); 38 | } 39 | 40 | function runDsf(dsf, value) { 41 | if (dsf) { 42 | for (var i = 0; i < dsf.length; i++) { 43 | var res = dsf[i](value); 44 | if (res !== undefined) return res; 45 | } 46 | } 47 | } 48 | 49 | function nopDsf(/*value*/) { 50 | } 51 | 52 | function isInvalidDsfChar(c) { 53 | return c === '{' || c === '}' || c === '[' || c === ']' || c === ','; 54 | } 55 | 56 | 57 | function math(/*opt*/) { 58 | return { 59 | name: "math", 60 | parse: function (value) { 61 | switch (value) { 62 | case "+inf": 63 | case "inf": 64 | case "+Inf": 65 | case "Inf": return Infinity; 66 | case "-inf": 67 | case "-Inf": return -Infinity; 68 | case "nan": 69 | case "NaN": return NaN; 70 | } 71 | }, 72 | stringify: function (value) { 73 | if (typeof value !== 'number') return; 74 | if (1 / value === -Infinity) return "-0"; // 0 === -0 75 | if (value === Infinity) return "Inf"; 76 | if (value === -Infinity) return "-Inf"; 77 | if (isNaN(value)) return "NaN"; 78 | }, 79 | }; 80 | } 81 | math.description="support for Inf/inf, -Inf/-inf, Nan/naN and -0"; 82 | 83 | function hex(opt) { 84 | var out=opt && opt.out; 85 | return { 86 | name: "hex", 87 | parse: function (value) { 88 | if (/^0x[0-9A-Fa-f]+$/.test(value)) 89 | return parseInt(value, 16); 90 | }, 91 | stringify: function (value) { 92 | if (out && Number.isInteger(value)) 93 | return "0x"+value.toString(16); 94 | }, 95 | }; 96 | } 97 | hex.description="parse hexadecimal numbers prefixed with 0x"; 98 | 99 | function date(/*opt*/) { 100 | return { 101 | name: "date", 102 | parse: function (value) { 103 | if (/^\d{4}-\d{2}-\d{2}$/.test(value) || 104 | /^\d{4}-\d{2}-\d{2}T\d{2}\:\d{2}\:\d{2}(?:.\d+)(?:Z|[+-]\d{2}:\d{2})$/.test(value)) { 105 | var dt = Date.parse(value); 106 | if (!isNaN(dt)) return new Date(dt); 107 | } 108 | }, 109 | stringify: function (value) { 110 | if (Object.prototype.toString.call(value) === '[object Date]') { 111 | var dt = value.toISOString(); 112 | if (dt.indexOf("T00:00:00.000Z", dt.length - 14) !== -1) return dt.substr(0, 10); 113 | else return dt; 114 | } 115 | }, 116 | }; 117 | } 118 | date.description="support ISO dates"; 119 | 120 | module.exports = { 121 | loadDsf: loadDsf, 122 | std: { 123 | math: math, 124 | hex: hex, 125 | date: date, 126 | }, 127 | }; 128 | -------------------------------------------------------------------------------- /lib/hjson.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Hjson v3.2.1 3 | * https://hjson.github.io 4 | * 5 | * Copyright 2014-2017 Christian Zangl, MIT license 6 | * Details and documentation: 7 | * https://github.com/hjson/hjson-js 8 | * 9 | * This code is based on the the JSON version by Douglas Crockford: 10 | * https://github.com/douglascrockford/JSON-js (json_parse.js, json2.js) 11 | */ 12 | 13 | /* 14 | 15 | This file creates a Hjson object: 16 | 17 | 18 | Hjson.parse(text, options) 19 | 20 | options { 21 | keepWsc boolean, keep white space and comments. This is useful 22 | if you want to edit an hjson file and save it while 23 | preserving comments (default false) 24 | 25 | dsf array of DSF (see Hjson.dsf) 26 | 27 | legacyRoot boolean, support omitting root braces (default true) 28 | } 29 | 30 | This method parses Hjson text to produce an object or array. 31 | It can throw a SyntaxError exception. 32 | 33 | 34 | Hjson.stringify(value, options) 35 | 36 | value any JavaScript value, usually an object or array. 37 | 38 | options { all options are 39 | 40 | keepWsc boolean, keep white space. See parse. 41 | 42 | condense integer, will try to fit objects/arrays onto one line 43 | when the output is shorter than condense characters 44 | and the fragment contains no comments. Default 0 (off). 45 | 46 | bracesSameLine 47 | boolean, makes braces appear on the same line as the key 48 | name. Default false. 49 | 50 | quotes string, controls how strings are displayed. 51 | setting separator implies "strings" 52 | "min" - no quotes whenever possible (default) 53 | "keys" - use quotes around keys 54 | "strings" - use quotes around string values 55 | "all" - use quotes around keys and string values 56 | 57 | multiline string, controls how multiline strings are displayed. 58 | setting quotes implies "off" 59 | "std" - strings containing \n are shown in 60 | multiline format (default) 61 | "no-tabs" - like std but disallow tabs 62 | "off" - show in JSON format 63 | 64 | separator boolean, output a comma separator between elements. Default false. 65 | 66 | space specifies the indentation of nested structures. If it is 67 | a number, it will specify the number of spaces to indent 68 | at each level. If it is a string (such as '\t' or ' '), 69 | it contains the characters used to indent at each level. 70 | 71 | eol specifies the EOL sequence (default is set by 72 | Hjson.setEndOfLine()) 73 | 74 | colors boolean, output ascii color codes 75 | 76 | dsf array of DSF (see Hjson.dsf) 77 | 78 | emitRootBraces 79 | obsolete: will always emit braces 80 | 81 | sortProps 82 | When serializing objects into hjson, order the keys based on 83 | their UTF-16 code units order 84 | } 85 | 86 | This method produces Hjson text from a JavaScript value. 87 | 88 | Values that do not have JSON representations, such as undefined or 89 | functions, will not be serialized. Such values in objects will be 90 | dropped; in arrays they will be replaced with null. 91 | stringify(undefined) returns undefined. 92 | 93 | 94 | Hjson.endOfLine() 95 | Hjson.setEndOfLine(eol) 96 | 97 | Gets or sets the stringify EOL sequence ('\n' or '\r\n'). 98 | When running with node.js this defaults to os.EOL. 99 | 100 | 101 | Hjson.rt { parse, stringify } 102 | 103 | This is a shortcut to roundtrip your comments when reading and updating 104 | a config file. It is the same as specifying the keepWsc option for the 105 | parse and stringify functions. 106 | 107 | 108 | Hjson.version 109 | 110 | The version of this library. 111 | 112 | 113 | Hjson.dsf 114 | 115 | Domain specific formats are extensions to the Hjson syntax (see 116 | hjson.github.io). These formats will be parsed and made available to 117 | the application in place of strings (e.g. enable math to allow 118 | NaN values). 119 | 120 | Hjson.dsf ontains standard DSFs that can be passed to parse 121 | and stringify. 122 | 123 | 124 | Hjson.dsf.math() 125 | 126 | Enables support for Inf/inf, -Inf/-inf, Nan/naN and -0. 127 | Will output as Inf, -Inf, NaN and -0. 128 | 129 | 130 | Hjson.dsf.hex(options) 131 | 132 | Parse hexadecimal numbers prefixed with 0x. 133 | set options.out = true to stringify _all_ integers as hex. 134 | 135 | 136 | Hjson.dsf.date(options) 137 | 138 | support ISO dates 139 | 140 | 141 | This is a reference implementation. You are free to copy, modify, or 142 | redistribute. 143 | 144 | */ 145 | 146 | "use strict"; 147 | 148 | var common = require("./hjson-common"); 149 | var version = require("./hjson-version"); 150 | var parse = require("./hjson-parse"); 151 | var stringify = require("./hjson-stringify"); 152 | var comments = require("./hjson-comments"); 153 | var dsf = require("./hjson-dsf"); 154 | 155 | module.exports={ 156 | 157 | parse: parse, 158 | stringify: stringify, 159 | 160 | endOfLine: function() { return common.EOL; }, 161 | setEndOfLine: function(eol) { 162 | if (eol === '\n' || eol === '\r\n') common.EOL = eol; 163 | }, 164 | 165 | version: version, 166 | 167 | // round trip shortcut 168 | rt: { 169 | parse: function(text, options) { 170 | (options=options||{}).keepWsc=true; 171 | return parse(text, options); 172 | }, 173 | stringify: function(value, options) { 174 | (options=options||{}).keepWsc=true; 175 | return stringify(value, options); 176 | }, 177 | }, 178 | 179 | comments: comments, 180 | 181 | dsf: dsf.std, 182 | 183 | }; 184 | -------------------------------------------------------------------------------- /lib/hjson-comments.js: -------------------------------------------------------------------------------- 1 | /* Hjson https://hjson.github.io */ 2 | "use strict"; 3 | 4 | var common=require("./hjson-common"); 5 | 6 | function makeComment(b, a, x) { 7 | var c; 8 | if (b) c={ b: b }; 9 | if (a) (c=c||{}).a=a; 10 | if (x) (c=c||{}).x=x; 11 | return c; 12 | } 13 | 14 | function extractComments(value, root) { 15 | 16 | if (value===null || typeof value!=='object') return; 17 | var comments=common.getComment(value); 18 | if (comments) common.removeComment(value); 19 | 20 | var i, length; // loop 21 | var any, res; 22 | if (Object.prototype.toString.apply(value) === '[object Array]') { 23 | res={ a: {} }; 24 | for (i=0, length=value.length; i0) { 82 | var text=rootComment(value, null, 1); 83 | text+="\n# Orphaned comments:\n"; 84 | dropped.forEach(function(c) { 85 | text+=("# "+c.path.join('/')+": "+mergeStr(c.b, c.a, c.e)).replace("\n", "\\n ")+"\n"; 86 | }); 87 | rootComment(value, text, 1); 88 | } 89 | } 90 | 91 | function saveComment(res, key, item, col) { 92 | var c=makeComment(item?item[0]:undefined, item?item[1]:undefined, col); 93 | if (c) res[key]=c; 94 | return c; 95 | } 96 | 97 | function droppedComment(path, c) { 98 | var res=makeComment(c.b, c.a); 99 | res.path=path; 100 | return res; 101 | } 102 | 103 | function dropAll(comments, dropped, path) { 104 | 105 | if (!comments) return; 106 | 107 | var i, length; // loop 108 | 109 | if (comments.a) { 110 | 111 | for (i=0, length=comments.a.length; i test.json` to convert to JSON 88 | - run `hjson test.json > test.hjson` to convert to Hjson 89 | - run `hjson test.json` to view colorized output 90 | 91 | 92 | # API 93 | 94 | The API is the same for the browser and node.js version. 95 | 96 | **NOTE that the DSF api is considered experimental** 97 | 98 | ### Hjson.parse(text, options) 99 | 100 | This method parses *JSON* or *Hjson* text to produce an object or array. 101 | 102 | - *text*: the string to parse as JSON or Hjson 103 | - *options*: object 104 | - *keepWsc*: boolean, keep white space and comments. This is useful if you want to edit an hjson file and save it while preserving comments (default false) 105 | 106 | ### Hjson.stringify(value, options) 107 | 108 | This method produces Hjson text from a JavaScript value. 109 | 110 | - *value*: any JavaScript value, usually an object or array. 111 | - *options*: object 112 | - *keepWsc*: boolean, keep white space. See parse. 113 | - *condense*: integer, will try to fit objects/arrays onto one line. Default 0 (off). 114 | - *bracesSameLine*: boolean, makes braces appear on the same line as the key name. Default false. 115 | - *emitRootBraces*: boolean, show braces for the root object. Default true. 116 | - *quotes*: string, controls how strings are displayed. (setting separator implies "strings") 117 | - "min": no quotes whenever possible (default) 118 | - "keys": use quotes around keys 119 | - "strings": use quotes around string values 120 | - "all": use quotes around keys and string values 121 | - *multiline*: string, controls how multiline strings are displayed. (setting quotes implies "off") 122 | - "std": strings containing \n are shown in multiline format (default) 123 | - "no-tabs": like std but disallow tabs 124 | - "off": show in JSON format 125 | - *separator*: boolean, output a comma separator between elements. Default false 126 | - *space*: specifies the indentation of nested structures. If it is a number, it will specify the number of spaces to indent at each level. If it is a string (such as '\t' or ' '), it contains the characters used to indent at each level. 127 | - *eol*: specifies the EOL sequence (default is set by Hjson.setEndOfLine()) 128 | - *colors*: boolean, output ascii color codes 129 | - *sortProps*: boolean, when serializing objects into hjson, order the keys based on their UTF-16 code units order. Default false. 130 | 131 | ### Hjson.endOfLine(), .setEndOfLine(eol) 132 | 133 | Gets or sets the stringify EOL sequence ('\n' or '\r\n'). When running with node.js this defaults to os.EOL. 134 | 135 | ### Hjson.rt { parse, stringify } 136 | 137 | This is a shortcut to roundtrip your comments when reading and updating a config file. It is the same as specifying the keepWsc option for the parse and stringify functions. 138 | 139 | ### Hjson.version 140 | 141 | The version number. 142 | 143 | ### require-hook 144 | 145 | Require a config file directly. 146 | 147 | ``` 148 | require("hjson/lib/require-config"); 149 | var cfg=require("./config.hjson"); 150 | ``` 151 | 152 | ## modify & keep comments 153 | 154 | You can modify a Hjson file and keep the whitespace & comments intact (round trip). This is useful if an app updates its config file. 155 | 156 | ``` 157 | // parse, keep whitespace and comments 158 | // (they are stored in a non enumerable __COMMENTS__ member) 159 | var data = Hjson.rt.parse(text); 160 | 161 | // modify like you normally would 162 | data.foo = "text"; 163 | 164 | // convert back to Hjson 165 | console.log(Hjson.rt.stringify(data)); 166 | ``` 167 | # Build 168 | 169 | To run all tests and create the bundle output, first install the dev dependencies with `npm i` and then run `npm run build`. 170 | 171 | # History 172 | 173 | [see history.md](history.md) 174 | 175 | -------------------------------------------------------------------------------- /lib/hjson-parse.js: -------------------------------------------------------------------------------- 1 | /* Hjson https://hjson.github.io */ 2 | "use strict"; 3 | 4 | module.exports = function(source, opt) { 5 | 6 | var common = require("./hjson-common"); 7 | var dsf = require("./hjson-dsf"); 8 | 9 | var text; 10 | var at; // The index of the current character 11 | var ch; // The current character 12 | var escapee = { 13 | '"': '"', 14 | "'": "'", 15 | '\\': '\\', 16 | '/': '/', 17 | b: '\b', 18 | f: '\f', 19 | n: '\n', 20 | r: '\r', 21 | t: '\t' 22 | }; 23 | 24 | var keepComments; 25 | var runDsf; // domain specific formats 26 | 27 | function resetAt() { 28 | at = 0; 29 | ch = ' '; 30 | } 31 | 32 | function isPunctuatorChar(c) { 33 | return c === '{' || c === '}' || c === '[' || c === ']' || c === ',' || c === ':'; 34 | } 35 | 36 | // Call error when something is wrong. 37 | function error(m) { 38 | var i, col=0, line=1; 39 | for (i = at-1; i > 0 && text[i] !== '\n'; i--, col++) {} 40 | for (; i > 0; i--) if (text[i] === '\n') line++; 41 | throw new Error(m + " at line " + line + "," + col + " >>>" + text.substr(at-col, 20) + " ..."); 42 | } 43 | 44 | function next() { 45 | // get the next character. 46 | ch = text.charAt(at); 47 | at++; 48 | return ch; 49 | } 50 | 51 | function peek(offs) { 52 | // range check is not required 53 | return text.charAt(at + offs); 54 | } 55 | 56 | function string(allowML) { 57 | // Parse a string value. 58 | // callers make sure that (ch === '"' || ch === "'") 59 | var string = ''; 60 | 61 | // When parsing for string values, we must look for "/' and \ characters. 62 | var exitCh = ch; 63 | while (next()) { 64 | if (ch === exitCh) { 65 | next(); 66 | if (allowML && exitCh === "'" && ch === "'" && string.length === 0) { 67 | // ''' indicates a multiline string 68 | next(); 69 | return mlString(); 70 | } else return string; 71 | } 72 | if (ch === '\\') { 73 | next(); 74 | if (ch === 'u') { 75 | var uffff = 0; 76 | for (var i = 0; i < 4; i++) { 77 | next(); 78 | var c = ch.charCodeAt(0), hex; 79 | if (ch >= '0' && ch <= '9') hex = c - 48; 80 | else if (ch >= 'a' && ch <= 'f') hex = c - 97 + 0xa; 81 | else if (ch >= 'A' && ch <= 'F') hex = c - 65 + 0xa; 82 | else error("Bad \\u char " + ch); 83 | uffff = uffff * 16 + hex; 84 | } 85 | string += String.fromCharCode(uffff); 86 | } else if (typeof escapee[ch] === 'string') { 87 | string += escapee[ch]; 88 | } else break; 89 | } else if (ch === '\n' || ch === '\r') { 90 | error("Bad string containing newline"); 91 | } else { 92 | string += ch; 93 | } 94 | } 95 | error("Bad string"); 96 | } 97 | 98 | function mlString() { 99 | // Parse a multiline string value. 100 | var string = '', triple = 0; 101 | 102 | // we are at ''' +1 - get indent 103 | var indent = 0; 104 | for (;;) { 105 | var c=peek(-indent-5); 106 | if (!c || c === '\n') break; 107 | indent++; 108 | } 109 | 110 | function skipIndent() { 111 | var skip = indent; 112 | while (ch && ch <= ' ' && ch !== '\n' && skip-- > 0) next(); 113 | } 114 | 115 | // skip white/to (newline) 116 | while (ch && ch <= ' ' && ch !== '\n') next(); 117 | if (ch === '\n') { next(); skipIndent(); } 118 | 119 | // When parsing multiline string values, we must look for ' characters. 120 | for (;;) { 121 | if (!ch) { 122 | error("Bad multiline string"); 123 | } else if (ch === '\'') { 124 | triple++; 125 | next(); 126 | if (triple === 3) { 127 | if (string.slice(-1) === '\n') string=string.slice(0, -1); // remove last EOL 128 | return string; 129 | } else continue; 130 | } else { 131 | while (triple > 0) { 132 | string += '\''; 133 | triple--; 134 | } 135 | } 136 | if (ch === '\n') { 137 | string += '\n'; 138 | next(); 139 | skipIndent(); 140 | } else { 141 | if (ch !== '\r') string += ch; 142 | next(); 143 | } 144 | } 145 | } 146 | 147 | function keyname() { 148 | // quotes for keys are optional in Hjson 149 | // unless they include {}[],: or whitespace. 150 | 151 | if (ch === '"' || ch === "'") return string(false); 152 | 153 | var name = "", start = at, space = -1; 154 | for (;;) { 155 | if (ch === ':') { 156 | if (!name) error("Found ':' but no key name (for an empty key name use quotes)"); 157 | else if (space >=0 && space !== name.length) { at = start + space; error("Found whitespace in your key name (use quotes to include)"); } 158 | return name; 159 | } else if (ch <= ' ') { 160 | if (!ch) error("Found EOF while looking for a key name (check your syntax)"); 161 | else if (space < 0) space = name.length; 162 | } else if (isPunctuatorChar(ch)) { 163 | error("Found '" + ch + "' where a key name was expected (check your syntax or use quotes if the key name includes {}[],: or whitespace)"); 164 | } else { 165 | name += ch; 166 | } 167 | next(); 168 | } 169 | } 170 | 171 | function white() { 172 | while (ch) { 173 | // Skip whitespace. 174 | while (ch && ch <= ' ') next(); 175 | // Hjson allows comments 176 | if (ch === '#' || ch === '/' && peek(0) === '/') { 177 | while (ch && ch !== '\n') next(); 178 | } else if (ch === '/' && peek(0) === '*') { 179 | next(); next(); 180 | while (ch && !(ch === '*' && peek(0) === '/')) next(); 181 | if (ch) { next(); next(); } 182 | } else break; 183 | } 184 | } 185 | 186 | function tfnns() { 187 | // Hjson strings can be quoteless 188 | // returns string, true, false, or null. 189 | var value = ch; 190 | if (isPunctuatorChar(ch)) 191 | error("Found a punctuator character '" + ch + "' when expecting a quoteless string (check your syntax)"); 192 | 193 | for(;;) { 194 | next(); 195 | // (detection of ml strings was moved to string()) 196 | var isEol = ch === '\r' || ch === '\n' || ch === ''; 197 | if (isEol || 198 | ch === ',' || ch === '}' || ch === ']' || 199 | ch === '#' || 200 | ch === '/' && (peek(0) === '/' || peek(0) === '*') 201 | ) { 202 | // this tests for the case of {true|false|null|num} 203 | // followed by { ',' | '}' | ']' | '#' | '//' | '/*' } 204 | // which needs to be parsed as the specified value 205 | var chf = value[0]; 206 | switch (chf) { 207 | case 'f': if (value.trim() === "false") return false; break; 208 | case 'n': if (value.trim() === "null") return null; break; 209 | case 't': if (value.trim() === "true") return true; break; 210 | default: 211 | if (chf === '-' || chf >= '0' && chf <= '9') { 212 | var n = common.tryParseNumber(value); 213 | if (n !== undefined) return n; 214 | } 215 | } 216 | if (isEol) { 217 | // remove any whitespace at the end (ignored in quoteless strings) 218 | value = value.trim(); 219 | var dsfValue = runDsf(value); 220 | return dsfValue !== undefined ? dsfValue : value; 221 | } 222 | } 223 | value += ch; 224 | } 225 | } 226 | 227 | function getComment(cAt, first) { 228 | var i; 229 | cAt--; 230 | // remove trailing whitespace 231 | // but only up to EOL 232 | for (i = at - 2; i > cAt && text[i] <= ' ' && text[i] !== '\n'; i--); 233 | if (text[i] === '\n') i--; 234 | if (text[i] === '\r') i--; 235 | var res = text.substr(cAt, i-cAt+1); 236 | // return if we find anything other than whitespace 237 | for (i = 0; i < res.length; i++) { 238 | if (res[i] > ' ') { 239 | var j = res.indexOf('\n'); 240 | if (j >= 0) { 241 | var c = [res.substr(0, j), res.substr(j+1)]; 242 | if (first && c[0].trim().length === 0) c.shift(); 243 | return c; 244 | } else return [res]; 245 | } 246 | } 247 | return []; 248 | } 249 | 250 | function errorClosingHint(value) { 251 | function search(value, ch) { 252 | var i, k, length, res; 253 | switch (typeof value) { 254 | case 'string': 255 | if (value.indexOf(ch) >= 0) res = value; 256 | break; 257 | case 'object': 258 | if (Object.prototype.toString.apply(value) === '[object Array]') { 259 | for (i = 0, length = value.length; i < length; i++) { 260 | res=search(value[i], ch) || res; 261 | } 262 | } else { 263 | for (k in value) { 264 | if (!Object.prototype.hasOwnProperty.call(value, k)) continue; 265 | res=search(value[k], ch) || res; 266 | } 267 | } 268 | } 269 | return res; 270 | } 271 | 272 | function report(ch) { 273 | var possibleErr=search(value, ch); 274 | if (possibleErr) { 275 | return "found '"+ch+"' in a string value, your mistake could be with:\n"+ 276 | " > "+possibleErr+"\n"+ 277 | " (unquoted strings contain everything up to the next line!)"; 278 | } else return ""; 279 | } 280 | 281 | return report('}') || report(']'); 282 | } 283 | 284 | function array() { 285 | // Parse an array value. 286 | // assuming ch === '[' 287 | 288 | var array = []; 289 | var comments, cAt, nextComment; 290 | try { 291 | if (keepComments) comments = common.createComment(array, { a: [] }); 292 | 293 | next(); 294 | cAt = at; 295 | white(); 296 | if (comments) nextComment = getComment(cAt, true).join('\n'); 297 | if (ch === ']') { 298 | next(); 299 | if (comments) comments.e = [nextComment]; 300 | return array; // empty array 301 | } 302 | 303 | while (ch) { 304 | array.push(value()); 305 | cAt = at; 306 | white(); 307 | // in Hjson the comma is optional and trailing commas are allowed 308 | // note that we do not keep comments before the , if there are any 309 | if (ch === ',') { next(); cAt = at; white(); } 310 | if (comments) { 311 | var c = getComment(cAt); 312 | comments.a.push([nextComment||"", c[0]||""]); 313 | nextComment = c[1]; 314 | } 315 | if (ch === ']') { 316 | next(); 317 | if (comments) comments.a[comments.a.length-1][1] += nextComment||""; 318 | return array; 319 | } 320 | white(); 321 | } 322 | 323 | error("End of input while parsing an array (missing ']')"); 324 | } catch (e) { 325 | e.hint=e.hint||errorClosingHint(array); 326 | throw e; 327 | } 328 | } 329 | 330 | function object(withoutBraces) { 331 | // Parse an object value. 332 | 333 | var key = "", object = {}; 334 | var comments, cAt, nextComment; 335 | 336 | try { 337 | if (keepComments) comments = common.createComment(object, { c: {}, o: [] }); 338 | 339 | if (!withoutBraces) { 340 | // assuming ch === '{' 341 | next(); 342 | cAt = at; 343 | } else cAt = 1; 344 | 345 | white(); 346 | if (comments) nextComment = getComment(cAt, true).join('\n'); 347 | if (ch === '}' && !withoutBraces) { 348 | if (comments) comments.e = [nextComment]; 349 | next(); 350 | return object; // empty object 351 | } 352 | while (ch) { 353 | key = keyname(); 354 | white(); 355 | if (ch !== ':') error("Expected ':' instead of '" + ch + "'"); 356 | next(); 357 | // duplicate keys overwrite the previous value 358 | object[key] = value(); 359 | cAt = at; 360 | white(); 361 | // in Hjson the comma is optional and trailing commas are allowed 362 | // note that we do not keep comments before the , if there are any 363 | if (ch === ',') { next(); cAt = at; white(); } 364 | if (comments) { 365 | var c = getComment(cAt); 366 | comments.c[key] = [nextComment||"", c[0]||""]; 367 | nextComment = c[1]; 368 | comments.o.push(key); 369 | } 370 | if (ch === '}' && !withoutBraces) { 371 | next(); 372 | if (comments) comments.c[key][1] += nextComment||""; 373 | return object; 374 | } 375 | white(); 376 | } 377 | 378 | if (withoutBraces) return object; 379 | else error("End of input while parsing an object (missing '}')"); 380 | } catch (e) { 381 | e.hint=e.hint||errorClosingHint(object); 382 | throw e; 383 | } 384 | } 385 | 386 | function value() { 387 | // Parse a Hjson value. It could be an object, an array, a string, a number or a word. 388 | 389 | white(); 390 | switch (ch) { 391 | case '{': return object(); 392 | case '[': return array(); 393 | case "'": 394 | case '"': return string(true); 395 | default: return tfnns(); 396 | } 397 | } 398 | 399 | function checkTrailing(v, c) { 400 | var cAt = at; 401 | white(); 402 | if (ch) error("Syntax error, found trailing characters"); 403 | if (keepComments) { 404 | var b = c.join('\n'), a = getComment(cAt).join('\n'); 405 | if (a || b) { 406 | var comments = common.createComment(v, common.getComment(v)); 407 | comments.r = [b, a]; 408 | } 409 | } 410 | return v; 411 | } 412 | 413 | function rootValue() { 414 | white(); 415 | var c = keepComments ? getComment(1) : null; 416 | switch (ch) { 417 | case '{': return checkTrailing(object(), c); 418 | case '[': return checkTrailing(array(), c); 419 | default: return checkTrailing(value(), c); 420 | } 421 | } 422 | 423 | function legacyRootValue() { 424 | // Braces for the root object are optional 425 | white(); 426 | var c = keepComments ? getComment(1) : null; 427 | switch (ch) { 428 | case '{': return checkTrailing(object(), c); 429 | case '[': return checkTrailing(array(), c); 430 | } 431 | 432 | try { 433 | // assume we have a root object without braces 434 | return checkTrailing(object(true), c); 435 | } catch (e) { 436 | // test if we are dealing with a single JSON value instead (true/false/null/num/"") 437 | resetAt(); 438 | try { return checkTrailing(value(), c); } 439 | catch (e2) { throw e; } // throw original error 440 | } 441 | } 442 | 443 | if (typeof source!=="string") throw new Error("source is not a string"); 444 | var dsfDef = null; 445 | var legacyRoot = true; 446 | if (opt && typeof opt === 'object') { 447 | keepComments = opt.keepWsc; 448 | dsfDef = opt.dsf; 449 | legacyRoot = opt.legacyRoot !== false; // default true 450 | } 451 | runDsf = dsf.loadDsf(dsfDef, "parse"); 452 | text = source; 453 | resetAt(); 454 | return legacyRoot ? legacyRootValue() : rootValue(); 455 | }; 456 | -------------------------------------------------------------------------------- /lib/hjson-stringify.js: -------------------------------------------------------------------------------- 1 | /* Hjson https://hjson.github.io */ 2 | "use strict"; 3 | 4 | module.exports = function(data, opt) { 5 | 6 | var common = require("./hjson-common"); 7 | var dsf = require("./hjson-dsf"); 8 | 9 | var plainToken = { 10 | obj: [ '{', '}' ], 11 | arr: [ '[', ']' ], 12 | key: [ '', '' ], 13 | qkey: [ '"', '"' ], 14 | col: [ ':', '' ], 15 | com: [ ',', '' ], 16 | str: [ '', '' ], 17 | qstr: [ '"', '"' ], 18 | mstr: [ "'''", "'''" ], 19 | num: [ '', '' ], 20 | lit: [ '', '' ], 21 | dsf: [ '', '' ], 22 | esc: [ '\\', '' ], 23 | uni: [ '\\u', '' ], 24 | rem: [ '', '' ], 25 | }; 26 | 27 | // options 28 | var eol = common.EOL; 29 | var indent = ' '; 30 | var keepComments = false; 31 | var bracesSameLine = false; 32 | var quoteKeys = false; 33 | var quoteStrings = false; 34 | var condense = 0; 35 | var multiline = 1; // std=1, no-tabs=2, off=0 36 | var separator = ''; // comma separator 37 | var dsfDef = null; 38 | var sortProps = false; 39 | var token = plainToken; 40 | 41 | if (opt && typeof opt === 'object') { 42 | opt.quotes = opt.quotes === 'always' ? 'strings' : opt.quotes; // legacy 43 | 44 | if (opt.eol === '\n' || opt.eol === '\r\n') eol = opt.eol; 45 | keepComments = opt.keepWsc; 46 | condense = opt.condense || 0; 47 | bracesSameLine = opt.bracesSameLine; 48 | quoteKeys = opt.quotes === 'all' || opt.quotes === 'keys'; 49 | quoteStrings = opt.quotes === 'all' || opt.quotes === 'strings' || opt.separator === true; 50 | if (quoteStrings || opt.multiline == 'off') multiline = 0; 51 | else multiline = opt.multiline == 'no-tabs' ? 2 : 1; 52 | separator = opt.separator === true ? token.com[0] : ''; 53 | dsfDef = opt.dsf; 54 | sortProps = opt.sortProps; 55 | 56 | // If the space parameter is a number, make an indent string containing that 57 | // many spaces. If it is a string, it will be used as the indent string. 58 | 59 | if (typeof opt.space === 'number') { 60 | indent = new Array(opt.space + 1).join(' '); 61 | } else if (typeof opt.space === 'string') { 62 | indent = opt.space; 63 | } 64 | 65 | if (opt.colors === true) { 66 | token = { 67 | obj: [ '\x1b[37m{\x1b[0m', '\x1b[37m}\x1b[0m' ], 68 | arr: [ '\x1b[37m[\x1b[0m', '\x1b[37m]\x1b[0m' ], 69 | key: [ '\x1b[33m', '\x1b[0m' ], 70 | qkey: [ '\x1b[33m"', '"\x1b[0m' ], 71 | col: [ '\x1b[37m:\x1b[0m', '' ], 72 | com: [ '\x1b[37m,\x1b[0m', '' ], 73 | str: [ '\x1b[37;1m', '\x1b[0m' ], 74 | qstr: [ '\x1b[37;1m"', '"\x1b[0m' ], 75 | mstr: [ "\x1b[37;1m'''", "'''\x1b[0m" ], 76 | num: [ '\x1b[36;1m', '\x1b[0m' ], 77 | lit: [ '\x1b[36m', '\x1b[0m' ], 78 | dsf: [ '\x1b[37m', '\x1b[0m' ], 79 | esc: [ '\x1b[31m\\', '\x1b[0m' ], 80 | uni: [ '\x1b[31m\\u', '\x1b[0m' ], 81 | rem: [ '\x1b[35m', '\x1b[0m' ], 82 | }; 83 | } 84 | 85 | var i, ckeys=Object.keys(plainToken); 86 | for (i = ckeys.length - 1; i >= 0; i--) { 87 | var k = ckeys[i]; 88 | token[k].push(plainToken[k][0].length, plainToken[k][1].length); 89 | } 90 | } 91 | 92 | // 93 | var runDsf; // domain specific formats 94 | 95 | var commonRange='\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff'; 96 | // needsEscape tests if the string can be written without escapes 97 | var needsEscape = new RegExp('[\\\\\\"\x00-\x1f'+commonRange+']', 'g'); 98 | // needsQuotes tests if the string can be written as a quoteless string (like needsEscape but without \\ and \") 99 | var needsQuotes = new RegExp('^\\s|^"|^\'|^#|^\\/\\*|^\\/\\/|^\\{|^\\}|^\\[|^\\]|^:|^,|\\s$|[\x00-\x1f'+commonRange+']', 'g'); 100 | // needsEscapeML tests if the string can be written as a multiline string (like needsEscape but without \n, \r, \\, \", \t unless multines is 'std') 101 | var needsEscapeML = new RegExp('\'\'\'|^[\\s]+$|[\x00-'+(multiline === 2 ? '\x09' : '\x08')+'\x0b\x0c\x0e-\x1f'+commonRange+']', 'g'); 102 | // starts with a keyword and optionally is followed by a comment 103 | var startsWithKeyword = new RegExp('^(true|false|null)\\s*((,|\\]|\\}|#|//|/\\*).*)?$'); 104 | var meta = { 105 | // table of character substitutions 106 | '\b': 'b', 107 | '\t': 't', 108 | '\n': 'n', 109 | '\f': 'f', 110 | '\r': 'r', 111 | '"' : '"', 112 | '\\': '\\' 113 | }; 114 | var needsEscapeName = /[,\{\[\}\]\s:#"']|\/\/|\/\*/; 115 | var gap = ''; 116 | // 117 | var wrapLen = 0; 118 | 119 | function wrap(tk, v) { 120 | wrapLen += tk[0].length + tk[1].length - tk[2] - tk[3]; 121 | return tk[0] + v + tk[1]; 122 | } 123 | 124 | function quoteReplace(string) { 125 | return string.replace(needsEscape, function (a) { 126 | var c = meta[a]; 127 | if (typeof c === 'string') return wrap(token.esc, c); 128 | else return wrap(token.uni, ('0000' + a.charCodeAt(0).toString(16)).slice(-4)); 129 | }); 130 | } 131 | 132 | function quote(string, gap, hasComment, isRootObject) { 133 | if (!string) return wrap(token.qstr, ''); 134 | 135 | needsQuotes.lastIndex = 0; 136 | startsWithKeyword.lastIndex = 0; 137 | 138 | // Check if we can insert this string without quotes 139 | // see hjson syntax (must not parse as true, false, null or number) 140 | 141 | if (quoteStrings || hasComment || 142 | needsQuotes.test(string) || 143 | common.tryParseNumber(string, true) !== undefined || 144 | startsWithKeyword.test(string)) { 145 | 146 | // If the string contains no control characters, no quote characters, and no 147 | // backslash characters, then we can safely slap some quotes around it. 148 | // Otherwise we first check if the string can be expressed in multiline 149 | // format or we must replace the offending characters with safe escape 150 | // sequences. 151 | 152 | needsEscape.lastIndex = 0; 153 | needsEscapeML.lastIndex = 0; 154 | if (!needsEscape.test(string)) return wrap(token.qstr, string); 155 | else if (!needsEscapeML.test(string) && !isRootObject && multiline) return mlString(string, gap); 156 | else return wrap(token.qstr, quoteReplace(string)); 157 | } else { 158 | // return without quotes 159 | return wrap(token.str, string); 160 | } 161 | } 162 | 163 | function mlString(string, gap) { 164 | // wrap the string into the ''' (multiline) format 165 | 166 | var i, a = string.replace(/\r/g, "").split('\n'); 167 | gap += indent; 168 | 169 | if (a.length === 1) { 170 | // The string contains only a single line. We still use the multiline 171 | // format as it avoids escaping the \ character (e.g. when used in a 172 | // regex). 173 | return wrap(token.mstr, a[0]); 174 | } else { 175 | var res = eol + gap + token.mstr[0]; 176 | for (i = 0; i < a.length; i++) { 177 | res += eol; 178 | if (a[i]) res += gap + a[i]; 179 | } 180 | return res + eol + gap + token.mstr[1]; 181 | } 182 | } 183 | 184 | function quoteKey(name) { 185 | if (!name) return '""'; 186 | 187 | // Check if we can insert this key without quotes 188 | 189 | if (quoteKeys || needsEscapeName.test(name)) { 190 | needsEscape.lastIndex = 0; 191 | return wrap(token.qkey, needsEscape.test(name) ? quoteReplace(name) : name); 192 | } else { 193 | // return without quotes 194 | return wrap(token.key, name); 195 | } 196 | } 197 | 198 | function str(value, hasComment, noIndent, isRootObject) { 199 | // Produce a string from value. 200 | 201 | function startsWithNL(str) { return str && str[str[0] === '\r' ? 1 : 0] === '\n'; } 202 | function commentOnThisLine(str) { return str && !startsWithNL(str); } 203 | function makeComment(str, prefix, trim) { 204 | if (!str) return ""; 205 | str = common.forceComment(str); 206 | var i, len = str.length; 207 | for (i = 0; i < len && str[i] <= ' '; i++) {} 208 | if (trim && i > 0) str = str.substr(i); 209 | if (i < len) return prefix + wrap(token.rem, str); 210 | else return str; 211 | } 212 | 213 | // What happens next depends on the value's type. 214 | 215 | // check for DSF 216 | var dsfValue = runDsf(value); 217 | if (dsfValue !== undefined) return wrap(token.dsf, dsfValue); 218 | 219 | switch (typeof value) { 220 | case 'string': 221 | return quote(value, gap, hasComment, isRootObject); 222 | 223 | case 'number': 224 | // JSON numbers must be finite. Encode non-finite numbers as null. 225 | return isFinite(value) ? wrap(token.num, String(value)) : wrap(token.lit, 'null'); 226 | 227 | case 'boolean': 228 | return wrap(token.lit, String(value)); 229 | 230 | case 'object': 231 | // If the type is 'object', we might be dealing with an object or an array or 232 | // null. 233 | 234 | // Due to a specification blunder in ECMAScript, typeof null is 'object', 235 | // so watch out for that case. 236 | 237 | if (!value) return wrap(token.lit, 'null'); 238 | 239 | var comments; // whitespace & comments 240 | if (keepComments) comments = common.getComment(value); 241 | 242 | var isArray = Object.prototype.toString.apply(value) === '[object Array]'; 243 | 244 | // Make an array to hold the partial results of stringifying this object value. 245 | var mind = gap; 246 | gap += indent; 247 | var eolMind = eol + mind; 248 | var eolGap = eol + gap; 249 | var prefix = noIndent || bracesSameLine ? '' : eolMind; 250 | var partial = []; 251 | var setsep; 252 | // condense helpers: 253 | var cpartial = condense ? [] : null; 254 | var saveQuoteStrings = quoteStrings, saveMultiline = multiline; 255 | var iseparator = separator ? '' : token.com[0]; 256 | var cwrapLen = 0; 257 | 258 | var i, length; // loop 259 | var k, v, vs; // key, value 260 | var c, ca; 261 | var res, cres; 262 | 263 | if (isArray) { 264 | // The value is an array. Stringify every element. Use null as a placeholder 265 | // for non-JSON values. 266 | 267 | for (i = 0, length = value.length; i < length; i++) { 268 | setsep = i < length -1; 269 | if (comments) { 270 | c = comments.a[i]||[]; 271 | ca = commentOnThisLine(c[1]); 272 | partial.push(makeComment(c[0], "\n") + eolGap); 273 | if (cpartial && (c[0] || c[1] || ca)) cpartial = null; 274 | } 275 | else partial.push(eolGap); 276 | wrapLen = 0; 277 | v = value[i]; 278 | partial.push(str(v, comments ? ca : false, true) + (setsep ? separator : '')); 279 | if (cpartial) { 280 | // prepare the condensed version 281 | switch (typeof v) { 282 | case 'string': 283 | wrapLen = 0; 284 | quoteStrings = true; multiline = 0; 285 | cpartial.push(str(v, false, true) + (setsep ? token.com[0] : '')); 286 | quoteStrings = saveQuoteStrings; multiline = saveMultiline; 287 | break; 288 | case 'object': if (v) { cpartial = null; break; } // falls through 289 | default: cpartial.push(partial[partial.length - 1] + (setsep ? iseparator : '')); break; 290 | } 291 | if (setsep) wrapLen += token.com[0].length - token.com[2]; 292 | cwrapLen += wrapLen; 293 | } 294 | if (comments && c[1]) partial.push(makeComment(c[1], ca ? " " : "\n", ca)); 295 | } 296 | 297 | if (length === 0) { 298 | // when empty 299 | if (comments && comments.e) partial.push(makeComment(comments.e[0], "\n") + eolMind); 300 | } 301 | else partial.push(eolMind); 302 | 303 | // Join all of the elements together, separated with newline, and wrap them in 304 | // brackets. 305 | 306 | if (partial.length === 0) res = wrap(token.arr, ''); 307 | else { 308 | res = prefix + wrap(token.arr, partial.join('')); 309 | // try if the condensed version can fit (parent key name is not included) 310 | if (cpartial) { 311 | cres = cpartial.join(' '); 312 | if (cres.length - cwrapLen <= condense) res = wrap(token.arr, cres); 313 | } 314 | } 315 | } else { 316 | // Otherwise, iterate through all of the keys in the object. 317 | var commentKeys = comments ? comments.o.slice() : []; 318 | var objectKeys = []; 319 | for (k in value) { 320 | if (Object.prototype.hasOwnProperty.call(value, k) && commentKeys.indexOf(k) < 0) 321 | objectKeys.push(k); 322 | } 323 | if(sortProps) { 324 | objectKeys.sort(); 325 | } 326 | var keys = commentKeys.concat(objectKeys); 327 | 328 | for (i = 0, length = keys.length; i < length; i++) { 329 | setsep = i < length - 1; 330 | k = keys[i]; 331 | if (comments) { 332 | c = comments.c[k]||[]; 333 | ca = commentOnThisLine(c[1]); 334 | partial.push(makeComment(c[0], "\n") + eolGap); 335 | if (cpartial && (c[0] || c[1] || ca)) cpartial = null; 336 | } 337 | else partial.push(eolGap); 338 | 339 | wrapLen = 0; 340 | v = value[k]; 341 | vs = str(v, comments && ca); 342 | partial.push(quoteKey(k) + token.col[0] + (startsWithNL(vs) ? '' : ' ') + vs + (setsep ? separator : '')); 343 | if (comments && c[1]) partial.push(makeComment(c[1], ca ? " " : "\n", ca)); 344 | if (cpartial) { 345 | // prepare the condensed version 346 | switch (typeof v) { 347 | case 'string': 348 | wrapLen = 0; 349 | quoteStrings = true; multiline = 0; 350 | vs = str(v, false); 351 | quoteStrings = saveQuoteStrings; multiline = saveMultiline; 352 | cpartial.push(quoteKey(k) + token.col[0] + ' ' + vs + (setsep ? token.com[0] : '')); 353 | break; 354 | case 'object': if (v) { cpartial = null; break; } // falls through 355 | default: cpartial.push(partial[partial.length - 1] + (setsep ? iseparator : '')); break; 356 | } 357 | wrapLen += token.col[0].length - token.col[2]; 358 | if (setsep) wrapLen += token.com[0].length - token.com[2]; 359 | cwrapLen += wrapLen; 360 | } 361 | } 362 | if (length === 0) { 363 | // when empty 364 | if (comments && comments.e) partial.push(makeComment(comments.e[0], "\n") + eolMind); 365 | } 366 | else partial.push(eolMind); 367 | 368 | // Join all of the member texts together, separated with newlines 369 | if (partial.length === 0) { 370 | res = wrap(token.obj, ''); 371 | } else { 372 | // and wrap them in braces 373 | res = prefix + wrap(token.obj, partial.join('')); 374 | // try if the condensed version can fit 375 | if (cpartial) { 376 | cres = cpartial.join(' '); 377 | if (cres.length - cwrapLen <= condense) res = wrap(token.obj, cres); 378 | } 379 | } 380 | } 381 | 382 | gap = mind; 383 | return res; 384 | } 385 | } 386 | 387 | 388 | runDsf = dsf.loadDsf(dsfDef, 'stringify'); 389 | 390 | var res = ""; 391 | var comments = keepComments ? comments = (common.getComment(data) || {}).r : null; 392 | if (comments && comments[0]) res = comments[0] + '\n'; 393 | 394 | // get the result of stringifying the data. 395 | res += str(data, null, true, true); 396 | 397 | if (comments) res += comments[1]||""; 398 | 399 | return res; 400 | }; 401 | -------------------------------------------------------------------------------- /bundle/hjson.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Hjson v3.2.1 3 | * https://hjson.github.io 4 | * 5 | * Copyright 2014-2017 Christian Zangl, MIT license 6 | * Details and documentation: 7 | * https://github.com/hjson/hjson-js 8 | * 9 | * This code is based on the the JSON version by Douglas Crockford: 10 | * https://github.com/douglascrockford/JSON-js (json_parse.js, json2.js) 11 | */ 12 | !function(n){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=n();else if("function"==typeof define&&define.amd)define([],n);else{var r;r="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,r.Hjson=n()}}(function(){return function(){function n(r,e,t){function o(a,s){if(!e[a]){if(!r[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(i)return i(a,!0);var f=new Error("Cannot find module '"+a+"'");throw f.code="MODULE_NOT_FOUND",f}var c=e[a]={exports:{}};r[a][0].call(c.exports,function(n){return o(r[a][1][n]||n)},c,c.exports,n,r,e,t)}return e[a].exports}for(var i="function"==typeof require&&require,a=0;a0){var t=l(r,null,1);t+="\n# Orphaned comments:\n",e.forEach(function(n){t+=("# "+n.path.join("/")+": "+i(n.b,n.a,n.e)).replace("\n","\\n ")+"\n"}),l(r,t,1)}}function s(n,r,e,o){var i=t(e?e[0]:void 0,e?e[1]:void 0,o);return i&&(n[r]=i),i}function u(n,r){var e=t(r.b,r.a);return e.path=n,e}function f(n,r,e){if(n){var t,o;if(n.a)for(t=0,o=n.a.length;t="0"&&o<="9";)s&&("0"==o?a++:s=!1),i+=o,e();if(s&&a--,"."===o)for(i+=".";e()&&o>="0"&&o<="9";)i+=o;if("e"===o||"E"===o)for(i+=o,e(),"-"!==o&&"+"!==o||(i+=o,e());o>="0"&&o<="9";)i+=o,e();for(;o&&o<=" ";)e();return r&&(","!==o&&"}"!==o&&"]"!==o&&"#"!==o&&("/"!==o||"/"!==n[u]&&"*"!==n[u])||(o=0)),t=+i,o||a||!isFinite(t)?void 0:t}function o(n,r){return Object.defineProperty&&Object.defineProperty(n,"__COMMENTS__",{enumerable:!1,writable:!0}),n.__COMMENTS__=r||{}}function i(n){Object.defineProperty(n,"__COMMENTS__",{value:void 0})}function a(n){return n.__COMMENTS__}function s(n){if(!n)return"";var r,e,t,o,i=n.split("\n");for(t=0;t" "){i[t]="# "+r;break}}return i.join("\n")}var u=n("os");r.exports={EOL:u.EOL||"\n",tryParseNumber:t,createComment:o,removeComment:i,getComment:a,forceComment:s}},{os:8}],3:[function(n,r,e){"use strict";function t(n,r){function e(n){return"[object Function]"==={}.toString.call(n)}if("[object Array]"!==Object.prototype.toString.apply(n)){if(n)throw new Error("dsf option must contain an array!");return i}if(0===n.length)return i;var t=[];return n.forEach(function(n){if(!n.name||!e(n.parse)||!e(n.stringify))throw new Error("extension does not match the DSF interface");t.push(function(){try{if("parse"==r)return n.parse.apply(null,arguments);if("stringify"==r){var e=n.stringify.apply(null,arguments);if(void 0!==e&&("string"!=typeof e||0===e.length||'"'===e[0]||[].some.call(e,function(n){return a(n)})))throw new Error("value may not be empty, start with a quote or contain a punctuator character except colon: "+e);return e}throw new Error("Invalid type")}catch(r){throw new Error("DSF-"+n.name+" failed; "+r.message)}})}),o.bind(null,t)}function o(n,r){if(n)for(var e=0;e0&&"\n"!==b[r];r--,e++);for(;r>0;r--)"\n"===b[r]&&t++;throw new Error(n+" at line "+t+","+e+" >>>"+b.substr(j-e,20)+" ...")}function a(){return w=b.charAt(j),j++,w}function s(n){return b.charAt(j+n)}function u(n){for(var r="",e=w;a();){if(w===e)return a(),n&&"'"===e&&"'"===w&&0===r.length?(a(),f()):r;if("\\"===w)if(a(),"u"===w){for(var t=0,o=0;o<4;o++){a();var s,u=w.charCodeAt(0);w>="0"&&w<="9"?s=u-48:w>="a"&&w<="f"?s=u-97+10:w>="A"&&w<="F"?s=u-65+10:i("Bad \\u char "+w),t=16*t+s}r+=String.fromCharCode(t)}else{if("string"!=typeof C[w])break;r+=C[w]}else"\n"===w||"\r"===w?i("Bad string containing newline"):r+=w}i("Bad string")}function f(){function n(){for(var n=t;w&&w<=" "&&"\n"!==w&&n-- >0;)a()}for(var r="",e=0,t=0;;){var o=s(-t-5);if(!o||"\n"===o)break;t++}for(;w&&w<=" "&&"\n"!==w;)a();for("\n"===w&&(a(),n());;){if(w){if("'"===w){if(e++,a(),3===e)return"\n"===r.slice(-1)&&(r=r.slice(0,-1)),r;continue}for(;e>0;)r+="'",e--}else i("Bad multiline string");"\n"===w?(r+="\n",a(),n()):("\r"!==w&&(r+=w),a())}}function c(){if('"'===w||"'"===w)return u(!1);for(var n="",r=j,e=-1;;){if(":"===w)return n?e>=0&&e!==n.length&&(j=r+e,i("Found whitespace in your key name (use quotes to include)")):i("Found ':' but no key name (for an empty key name use quotes)"),n;w<=" "?w?e<0&&(e=n.length):i("Found EOF while looking for a key name (check your syntax)"):o(w)?i("Found '"+w+"' where a key name was expected (check your syntax or use quotes if the key name includes {}[],: or whitespace)"):n+=w,a()}}function l(){for(;w;){for(;w&&w<=" ";)a();if("#"===w||"/"===w&&"/"===s(0))for(;w&&"\n"!==w;)a();else{if("/"!==w||"*"!==s(0))break;for(a(),a();w&&("*"!==w||"/"!==s(0));)a();w&&(a(),a())}}}function h(){var n=w;for(o(w)&&i("Found a punctuator character '"+w+"' when expecting a quoteless string (check your syntax)");;){a();var r="\r"===w||"\n"===w||""===w;if(r||","===w||"}"===w||"]"===w||"#"===w||"/"===w&&("/"===s(0)||"*"===s(0))){var e=n[0];switch(e){case"f":if("false"===n.trim())return!1;break;case"n":if("null"===n.trim())return null;break;case"t":if("true"===n.trim())return!0;break;default:if("-"===e||e>="0"&&e<="9"){var t=k.tryParseNumber(n);if(void 0!==t)return t}}if(r){n=n.trim();var u=O(n);return void 0!==u?u:n}}n+=w}}function p(n,r){var e;for(n--,e=j-2;e>n&&b[e]<=" "&&"\n"!==b[e];e--);"\n"===b[e]&&e--,"\r"===b[e]&&e--;var t=b.substr(n,e-n+1);for(e=0;e" "){var o=t.indexOf("\n");if(o>=0){var i=[t.substr(0,o),t.substr(o+1)];return r&&0===i[0].trim().length&&i.shift(),i}return[t]}return[]}function m(n){function r(n,e){var t,o,i,a;switch(typeof n){case"string":n.indexOf(e)>=0&&(a=n);break;case"object":if("[object Array]"===Object.prototype.toString.apply(n))for(t=0,i=n.length;t "+t+"\n (unquoted strings contain everything up to the next line!)":""}return e("}")||e("]")}function d(){var n,r,e,t=[];try{if(x&&(n=k.createComment(t,{a:[]})),a(),r=j,l(),n&&(e=p(r,!0).join("\n")),"]"===w)return a(),n&&(n.e=[e]),t;for(;w;){if(t.push(v()),r=j,l(),","===w&&(a(),r=j,l()),n){var o=p(r);n.a.push([e||"",o[0]||""]),e=o[1]}if("]"===w)return a(),n&&(n.a[n.a.length-1][1]+=e||""),t;l()}i("End of input while parsing an array (missing ']')")}catch(n){throw n.hint=n.hint||m(t),n}}function g(n){var r,e,t,o="",s={};try{if(x&&(r=k.createComment(s,{c:{},o:[]})),n?e=1:(a(),e=j),l(),r&&(t=p(e,!0).join("\n")),"}"===w&&!n)return r&&(r.e=[t]),a(),s;for(;w;){if(o=c(),l(),":"!==w&&i("Expected ':' instead of '"+w+"'"),a(),s[o]=v(),e=j,l(),","===w&&(a(),e=j,l()),r){var u=p(e);r.c[o]=[t||"",u[0]||""],t=u[1],r.o.push(o)}if("}"===w&&!n)return a(),r&&(r.c[o][1]+=t||""),s;l()}if(n)return s;i("End of input while parsing an object (missing '}')")}catch(n){throw n.hint=n.hint||m(s),n}}function v(){switch(l(),w){case"{":return g();case"[":return d();case"'":case'"':return u(!0);default:return h()}}function y(n,r){var e=j;if(l(),w&&i("Syntax error, found trailing characters"),x){var t=r.join("\n"),o=p(e).join("\n");if(o||t){k.createComment(n,k.getComment(n)).r=[t,o]}}return n}var b,j,w,x,O,k=n("./hjson-common"),E=n("./hjson-dsf"),C={'"':'"',"'":"'","\\":"\\","/":"/",b:"\b",f:"\f",n:"\n",r:"\r",t:"\t"};if("string"!=typeof r)throw new Error("source is not a string");var q=null,S=!0;return e&&"object"==typeof e&&(x=e.keepWsc,q=e.dsf,S=!1!==e.legacyRoot),O=E.loadDsf(q,"parse"),b=r,t(),S?function(){l();var n=x?p(1):null;switch(w){case"{":return y(g(),n);case"[":return y(d(),n)}try{return y(g(!0),n)}catch(r){t();try{return y(v(),n)}catch(n){throw r}}}():function(){l();var n=x?p(1):null;switch(w){case"{":return y(g(),n);case"[":return y(d(),n);default:return y(v(),n)}}()}},{"./hjson-common":2,"./hjson-dsf":3}],5:[function(n,r,e){"use strict";r.exports=function(r,e){function t(n,r){return L+=n[0].length+n[1].length-n[2]-n[3],n[0]+r+n[1]}function o(n){return n.replace(N,function(n){var r=A[n];return"string"==typeof r?t(O.esc,r):t(O.uni,("0000"+n.charCodeAt(0).toString(16)).slice(-4))})}function i(n,r,e,i){return n?(I.lastIndex=0,F.lastIndex=0,v||e||I.test(n)||void 0!==f.tryParseNumber(n,!0)||F.test(n)?(N.lastIndex=0,_.lastIndex=0,N.test(n)?_.test(n)||i||!b?t(O.qstr,o(n)):a(n,r):t(O.qstr,n)):t(O.str,n)):t(O.qstr,"")}function a(n,r){var e,o=n.replace(/\r/g,"").split("\n");if(r+=p,1===o.length)return t(O.mstr,o[0]);var i=h+r+O.mstr[0];for(e=0;e0&&(n=n.substr(o)),o=0;k--){var C=E[k];O[C].push(l[C][0].length,l[C][1].length)}}var q,S="-Ÿ­؀-؄܏឴឵‌-‏\u2028- ⁠-\ufeff￰-￿",N=new RegExp('[\\\\\\"\0-'+S+"]","g"),I=new RegExp("^\\s|^\"|^'|^#|^\\/\\*|^\\/\\/|^\\{|^\\}|^\\[|^\\]|^:|^,|\\s$|[\0-"+S+"]","g"),_=new RegExp("'''|^[\\s]+$|[\0-"+(2===b?"\t":"\b")+"\v\f-"+S+"]","g"),F=new RegExp("^(true|false|null)\\s*((,|\\]|\\}|#|//|/\\*).*)?$"),A={"\b":"b","\t":"t","\n":"n","\f":"f","\r":"r",'"':'"',"\\":"\\"},P=/[,\{\[\}\]\s:#"']|\/\/|\/\*/,D="",L=0;q=c.loadDsf(w,"stringify");var M="",T=m?T=(f.getComment(r)||{}).r:null;return T&&T[0]&&(M=T[0]+"\n"),M+=u(r,null,!0,!0),T&&(M+=T[1]||""),M}},{"./hjson-common":2,"./hjson-dsf":3}],6:[function(n,r,e){r.exports="3.2.1"},{}],7:[function(n,r,e){/*! 13 | * Hjson v3.2.1 14 | * https://hjson.github.io 15 | * 16 | * Copyright 2014-2017 Christian Zangl, MIT license 17 | * Details and documentation: 18 | * https://github.com/hjson/hjson-js 19 | * 20 | * This code is based on the the JSON version by Douglas Crockford: 21 | * https://github.com/douglascrockford/JSON-js (json_parse.js, json2.js) 22 | */ 23 | "use strict";var t=n("./hjson-common"),o=n("./hjson-version"),i=n("./hjson-parse"),a=n("./hjson-stringify"),s=n("./hjson-comments"),u=n("./hjson-dsf");r.exports={parse:i,stringify:a,endOfLine:function(){return t.EOL},setEndOfLine:function(n){"\n"!==n&&"\r\n"!==n||(t.EOL=n)},version:o,rt:{parse:function(n,r){return(r=r||{}).keepWsc=!0,i(n,r)},stringify:function(n,r){return(r=r||{}).keepWsc=!0,a(n,r)}},comments:s,dsf:u.std}},{"./hjson-comments":1,"./hjson-common":2,"./hjson-dsf":3,"./hjson-parse":4,"./hjson-stringify":5,"./hjson-version":6}],8:[function(n,r,e){},{}]},{},[7])(7)}); 24 | -------------------------------------------------------------------------------- /bundle/hjson.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Hjson v3.2.1 3 | * https://hjson.github.io 4 | * 5 | * Copyright 2014-2017 Christian Zangl, MIT license 6 | * Details and documentation: 7 | * https://github.com/hjson/hjson-js 8 | * 9 | * This code is based on the the JSON version by Douglas Crockford: 10 | * https://github.com/douglascrockford/JSON-js (json_parse.js, json2.js) 11 | */ 12 | 13 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f();}else if(typeof define==="function"&&define.amd){define([],f);}else{var g;if(typeof window!=="undefined"){g=window;}else if(typeof global!=="undefined"){g=global;}else if(typeof self!=="undefined"){g=self;}else{g=this;}g.Hjson = f();}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a;}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r);},p,p.exports,r,e,n,t);}return n[i].exports;}for(var u="function"==typeof require&&require,i=0;i0) { 95 | var text=rootComment(value, null, 1); 96 | text+="\n# Orphaned comments:\n"; 97 | dropped.forEach(function(c) { 98 | text+=("# "+c.path.join('/')+": "+mergeStr(c.b, c.a, c.e)).replace("\n", "\\n ")+"\n"; 99 | }); 100 | rootComment(value, text, 1); 101 | } 102 | } 103 | 104 | function saveComment(res, key, item, col) { 105 | var c=makeComment(item?item[0]:undefined, item?item[1]:undefined, col); 106 | if (c) res[key]=c; 107 | return c; 108 | } 109 | 110 | function droppedComment(path, c) { 111 | var res=makeComment(c.b, c.a); 112 | res.path=path; 113 | return res; 114 | } 115 | 116 | function dropAll(comments, dropped, path) { 117 | 118 | if (!comments) return; 119 | 120 | var i, length; // loop 121 | 122 | if (comments.a) { 123 | 124 | for (i=0, length=comments.a.length; i= '0' && ch <= '9') { 242 | if (testLeading) { 243 | if (ch == '0') leadingZeros++; 244 | else testLeading = false; 245 | } 246 | string += ch; 247 | next(); 248 | } 249 | if (testLeading) leadingZeros--; // single 0 is allowed 250 | if (ch === '.') { 251 | string += '.'; 252 | while (next() && ch >= '0' && ch <= '9') 253 | string += ch; 254 | } 255 | if (ch === 'e' || ch === 'E') { 256 | string += ch; 257 | next(); 258 | if (ch === '-' || ch === '+') { 259 | string += ch; 260 | next(); 261 | } 262 | while (ch >= '0' && ch <= '9') { 263 | string += ch; 264 | next(); 265 | } 266 | } 267 | 268 | // skip white/to (newline) 269 | while (ch && ch <= ' ') next(); 270 | 271 | if (stopAtNext) { 272 | // end scan if we find a punctuator character like ,}] or a comment 273 | if (ch === ',' || ch === '}' || ch === ']' || 274 | ch === '#' || ch === '/' && (text[at] === '/' || text[at] === '*')) ch = 0; 275 | } 276 | 277 | number = +string; 278 | if (ch || leadingZeros || !isFinite(number)) return undefined; 279 | else return number; 280 | } 281 | 282 | function createComment(value, comment) { 283 | if (Object.defineProperty) Object.defineProperty(value, "__COMMENTS__", { enumerable: false, writable: true }); 284 | return (value.__COMMENTS__ = comment||{}); 285 | } 286 | 287 | function removeComment(value) { 288 | Object.defineProperty(value, "__COMMENTS__", { value: undefined }); 289 | } 290 | 291 | function getComment(value) { 292 | return value.__COMMENTS__; 293 | } 294 | 295 | function forceComment(text) { 296 | if (!text) return ""; 297 | var a = text.split('\n'); 298 | var str, i, j, len; 299 | for (j = 0; j < a.length; j++) { 300 | str = a[j]; 301 | len = str.length; 302 | for (i = 0; i < len; i++) { 303 | var c = str[i]; 304 | if (c === '#') break; 305 | else if (c === '/' && (str[i+1] === '/' || str[i+1] === '*')) { 306 | if (str[i+1] === '*') j = a.length; // assume /**/ covers whole block, bail out 307 | break; 308 | } 309 | else if (c > ' ') { 310 | a[j] = '# ' + str; 311 | break; 312 | } 313 | } 314 | } 315 | return a.join('\n'); 316 | } 317 | 318 | module.exports = { 319 | EOL: os.EOL || '\n', 320 | tryParseNumber: tryParseNumber, 321 | createComment: createComment, 322 | removeComment: removeComment, 323 | getComment: getComment, 324 | forceComment: forceComment, 325 | }; 326 | 327 | },{"os":8}],3:[function(require,module,exports){ 328 | /* Hjson https://hjson.github.io */ 329 | "use strict"; 330 | 331 | function loadDsf(col, type) { 332 | 333 | if (Object.prototype.toString.apply(col) !== '[object Array]') { 334 | if (col) throw new Error("dsf option must contain an array!"); 335 | else return nopDsf; 336 | } else if (col.length === 0) return nopDsf; 337 | 338 | var dsf = []; 339 | function isFunction(f) { return {}.toString.call(f) === '[object Function]'; } 340 | 341 | col.forEach(function(x) { 342 | if (!x.name || !isFunction(x.parse) || !isFunction(x.stringify)) 343 | throw new Error("extension does not match the DSF interface"); 344 | dsf.push(function() { 345 | try { 346 | if (type == "parse") { 347 | return x.parse.apply(null, arguments); 348 | } else if (type == "stringify") { 349 | var res=x.stringify.apply(null, arguments); 350 | // check result 351 | if (res !== undefined && (typeof res !== "string" || 352 | res.length === 0 || 353 | res[0] === '"' || 354 | [].some.call(res, function(c) { return isInvalidDsfChar(c); }))) 355 | throw new Error("value may not be empty, start with a quote or contain a punctuator character except colon: " + res); 356 | return res; 357 | } else throw new Error("Invalid type"); 358 | } catch (e) { 359 | throw new Error("DSF-"+x.name+" failed; "+e.message); 360 | } 361 | }); 362 | }); 363 | 364 | return runDsf.bind(null, dsf); 365 | } 366 | 367 | function runDsf(dsf, value) { 368 | if (dsf) { 369 | for (var i = 0; i < dsf.length; i++) { 370 | var res = dsf[i](value); 371 | if (res !== undefined) return res; 372 | } 373 | } 374 | } 375 | 376 | function nopDsf(/*value*/) { 377 | } 378 | 379 | function isInvalidDsfChar(c) { 380 | return c === '{' || c === '}' || c === '[' || c === ']' || c === ','; 381 | } 382 | 383 | 384 | function math(/*opt*/) { 385 | return { 386 | name: "math", 387 | parse: function (value) { 388 | switch (value) { 389 | case "+inf": 390 | case "inf": 391 | case "+Inf": 392 | case "Inf": return Infinity; 393 | case "-inf": 394 | case "-Inf": return -Infinity; 395 | case "nan": 396 | case "NaN": return NaN; 397 | } 398 | }, 399 | stringify: function (value) { 400 | if (typeof value !== 'number') return; 401 | if (1 / value === -Infinity) return "-0"; // 0 === -0 402 | if (value === Infinity) return "Inf"; 403 | if (value === -Infinity) return "-Inf"; 404 | if (isNaN(value)) return "NaN"; 405 | }, 406 | }; 407 | } 408 | math.description="support for Inf/inf, -Inf/-inf, Nan/naN and -0"; 409 | 410 | function hex(opt) { 411 | var out=opt && opt.out; 412 | return { 413 | name: "hex", 414 | parse: function (value) { 415 | if (/^0x[0-9A-Fa-f]+$/.test(value)) 416 | return parseInt(value, 16); 417 | }, 418 | stringify: function (value) { 419 | if (out && Number.isInteger(value)) 420 | return "0x"+value.toString(16); 421 | }, 422 | }; 423 | } 424 | hex.description="parse hexadecimal numbers prefixed with 0x"; 425 | 426 | function date(/*opt*/) { 427 | return { 428 | name: "date", 429 | parse: function (value) { 430 | if (/^\d{4}-\d{2}-\d{2}$/.test(value) || 431 | /^\d{4}-\d{2}-\d{2}T\d{2}\:\d{2}\:\d{2}(?:.\d+)(?:Z|[+-]\d{2}:\d{2})$/.test(value)) { 432 | var dt = Date.parse(value); 433 | if (!isNaN(dt)) return new Date(dt); 434 | } 435 | }, 436 | stringify: function (value) { 437 | if (Object.prototype.toString.call(value) === '[object Date]') { 438 | var dt = value.toISOString(); 439 | if (dt.indexOf("T00:00:00.000Z", dt.length - 14) !== -1) return dt.substr(0, 10); 440 | else return dt; 441 | } 442 | }, 443 | }; 444 | } 445 | date.description="support ISO dates"; 446 | 447 | module.exports = { 448 | loadDsf: loadDsf, 449 | std: { 450 | math: math, 451 | hex: hex, 452 | date: date, 453 | }, 454 | }; 455 | 456 | },{}],4:[function(require,module,exports){ 457 | /* Hjson https://hjson.github.io */ 458 | "use strict"; 459 | 460 | module.exports = function(source, opt) { 461 | 462 | var common = require("./hjson-common"); 463 | var dsf = require("./hjson-dsf"); 464 | 465 | var text; 466 | var at; // The index of the current character 467 | var ch; // The current character 468 | var escapee = { 469 | '"': '"', 470 | "'": "'", 471 | '\\': '\\', 472 | '/': '/', 473 | b: '\b', 474 | f: '\f', 475 | n: '\n', 476 | r: '\r', 477 | t: '\t' 478 | }; 479 | 480 | var keepComments; 481 | var runDsf; // domain specific formats 482 | 483 | function resetAt() { 484 | at = 0; 485 | ch = ' '; 486 | } 487 | 488 | function isPunctuatorChar(c) { 489 | return c === '{' || c === '}' || c === '[' || c === ']' || c === ',' || c === ':'; 490 | } 491 | 492 | // Call error when something is wrong. 493 | function error(m) { 494 | var i, col=0, line=1; 495 | for (i = at-1; i > 0 && text[i] !== '\n'; i--, col++) {} 496 | for (; i > 0; i--) if (text[i] === '\n') line++; 497 | throw new Error(m + " at line " + line + "," + col + " >>>" + text.substr(at-col, 20) + " ..."); 498 | } 499 | 500 | function next() { 501 | // get the next character. 502 | ch = text.charAt(at); 503 | at++; 504 | return ch; 505 | } 506 | 507 | function peek(offs) { 508 | // range check is not required 509 | return text.charAt(at + offs); 510 | } 511 | 512 | function string(allowML) { 513 | // Parse a string value. 514 | // callers make sure that (ch === '"' || ch === "'") 515 | var string = ''; 516 | 517 | // When parsing for string values, we must look for "/' and \ characters. 518 | var exitCh = ch; 519 | while (next()) { 520 | if (ch === exitCh) { 521 | next(); 522 | if (allowML && exitCh === "'" && ch === "'" && string.length === 0) { 523 | // ''' indicates a multiline string 524 | next(); 525 | return mlString(); 526 | } else return string; 527 | } 528 | if (ch === '\\') { 529 | next(); 530 | if (ch === 'u') { 531 | var uffff = 0; 532 | for (var i = 0; i < 4; i++) { 533 | next(); 534 | var c = ch.charCodeAt(0), hex; 535 | if (ch >= '0' && ch <= '9') hex = c - 48; 536 | else if (ch >= 'a' && ch <= 'f') hex = c - 97 + 0xa; 537 | else if (ch >= 'A' && ch <= 'F') hex = c - 65 + 0xa; 538 | else error("Bad \\u char " + ch); 539 | uffff = uffff * 16 + hex; 540 | } 541 | string += String.fromCharCode(uffff); 542 | } else if (typeof escapee[ch] === 'string') { 543 | string += escapee[ch]; 544 | } else break; 545 | } else if (ch === '\n' || ch === '\r') { 546 | error("Bad string containing newline"); 547 | } else { 548 | string += ch; 549 | } 550 | } 551 | error("Bad string"); 552 | } 553 | 554 | function mlString() { 555 | // Parse a multiline string value. 556 | var string = '', triple = 0; 557 | 558 | // we are at ''' +1 - get indent 559 | var indent = 0; 560 | for (;;) { 561 | var c=peek(-indent-5); 562 | if (!c || c === '\n') break; 563 | indent++; 564 | } 565 | 566 | function skipIndent() { 567 | var skip = indent; 568 | while (ch && ch <= ' ' && ch !== '\n' && skip-- > 0) next(); 569 | } 570 | 571 | // skip white/to (newline) 572 | while (ch && ch <= ' ' && ch !== '\n') next(); 573 | if (ch === '\n') { next(); skipIndent(); } 574 | 575 | // When parsing multiline string values, we must look for ' characters. 576 | for (;;) { 577 | if (!ch) { 578 | error("Bad multiline string"); 579 | } else if (ch === '\'') { 580 | triple++; 581 | next(); 582 | if (triple === 3) { 583 | if (string.slice(-1) === '\n') string=string.slice(0, -1); // remove last EOL 584 | return string; 585 | } else continue; 586 | } else { 587 | while (triple > 0) { 588 | string += '\''; 589 | triple--; 590 | } 591 | } 592 | if (ch === '\n') { 593 | string += '\n'; 594 | next(); 595 | skipIndent(); 596 | } else { 597 | if (ch !== '\r') string += ch; 598 | next(); 599 | } 600 | } 601 | } 602 | 603 | function keyname() { 604 | // quotes for keys are optional in Hjson 605 | // unless they include {}[],: or whitespace. 606 | 607 | if (ch === '"' || ch === "'") return string(false); 608 | 609 | var name = "", start = at, space = -1; 610 | for (;;) { 611 | if (ch === ':') { 612 | if (!name) error("Found ':' but no key name (for an empty key name use quotes)"); 613 | else if (space >=0 && space !== name.length) { at = start + space; error("Found whitespace in your key name (use quotes to include)"); } 614 | return name; 615 | } else if (ch <= ' ') { 616 | if (!ch) error("Found EOF while looking for a key name (check your syntax)"); 617 | else if (space < 0) space = name.length; 618 | } else if (isPunctuatorChar(ch)) { 619 | error("Found '" + ch + "' where a key name was expected (check your syntax or use quotes if the key name includes {}[],: or whitespace)"); 620 | } else { 621 | name += ch; 622 | } 623 | next(); 624 | } 625 | } 626 | 627 | function white() { 628 | while (ch) { 629 | // Skip whitespace. 630 | while (ch && ch <= ' ') next(); 631 | // Hjson allows comments 632 | if (ch === '#' || ch === '/' && peek(0) === '/') { 633 | while (ch && ch !== '\n') next(); 634 | } else if (ch === '/' && peek(0) === '*') { 635 | next(); next(); 636 | while (ch && !(ch === '*' && peek(0) === '/')) next(); 637 | if (ch) { next(); next(); } 638 | } else break; 639 | } 640 | } 641 | 642 | function tfnns() { 643 | // Hjson strings can be quoteless 644 | // returns string, true, false, or null. 645 | var value = ch; 646 | if (isPunctuatorChar(ch)) 647 | error("Found a punctuator character '" + ch + "' when expecting a quoteless string (check your syntax)"); 648 | 649 | for(;;) { 650 | next(); 651 | // (detection of ml strings was moved to string()) 652 | var isEol = ch === '\r' || ch === '\n' || ch === ''; 653 | if (isEol || 654 | ch === ',' || ch === '}' || ch === ']' || 655 | ch === '#' || 656 | ch === '/' && (peek(0) === '/' || peek(0) === '*') 657 | ) { 658 | // this tests for the case of {true|false|null|num} 659 | // followed by { ',' | '}' | ']' | '#' | '//' | '/*' } 660 | // which needs to be parsed as the specified value 661 | var chf = value[0]; 662 | switch (chf) { 663 | case 'f': if (value.trim() === "false") return false; break; 664 | case 'n': if (value.trim() === "null") return null; break; 665 | case 't': if (value.trim() === "true") return true; break; 666 | default: 667 | if (chf === '-' || chf >= '0' && chf <= '9') { 668 | var n = common.tryParseNumber(value); 669 | if (n !== undefined) return n; 670 | } 671 | } 672 | if (isEol) { 673 | // remove any whitespace at the end (ignored in quoteless strings) 674 | value = value.trim(); 675 | var dsfValue = runDsf(value); 676 | return dsfValue !== undefined ? dsfValue : value; 677 | } 678 | } 679 | value += ch; 680 | } 681 | } 682 | 683 | function getComment(cAt, first) { 684 | var i; 685 | cAt--; 686 | // remove trailing whitespace 687 | // but only up to EOL 688 | for (i = at - 2; i > cAt && text[i] <= ' ' && text[i] !== '\n'; i--); 689 | if (text[i] === '\n') i--; 690 | if (text[i] === '\r') i--; 691 | var res = text.substr(cAt, i-cAt+1); 692 | // return if we find anything other than whitespace 693 | for (i = 0; i < res.length; i++) { 694 | if (res[i] > ' ') { 695 | var j = res.indexOf('\n'); 696 | if (j >= 0) { 697 | var c = [res.substr(0, j), res.substr(j+1)]; 698 | if (first && c[0].trim().length === 0) c.shift(); 699 | return c; 700 | } else return [res]; 701 | } 702 | } 703 | return []; 704 | } 705 | 706 | function errorClosingHint(value) { 707 | function search(value, ch) { 708 | var i, k, length, res; 709 | switch (typeof value) { 710 | case 'string': 711 | if (value.indexOf(ch) >= 0) res = value; 712 | break; 713 | case 'object': 714 | if (Object.prototype.toString.apply(value) === '[object Array]') { 715 | for (i = 0, length = value.length; i < length; i++) { 716 | res=search(value[i], ch) || res; 717 | } 718 | } else { 719 | for (k in value) { 720 | if (!Object.prototype.hasOwnProperty.call(value, k)) continue; 721 | res=search(value[k], ch) || res; 722 | } 723 | } 724 | } 725 | return res; 726 | } 727 | 728 | function report(ch) { 729 | var possibleErr=search(value, ch); 730 | if (possibleErr) { 731 | return "found '"+ch+"' in a string value, your mistake could be with:\n"+ 732 | " > "+possibleErr+"\n"+ 733 | " (unquoted strings contain everything up to the next line!)"; 734 | } else return ""; 735 | } 736 | 737 | return report('}') || report(']'); 738 | } 739 | 740 | function array() { 741 | // Parse an array value. 742 | // assuming ch === '[' 743 | 744 | var array = []; 745 | var comments, cAt, nextComment; 746 | try { 747 | if (keepComments) comments = common.createComment(array, { a: [] }); 748 | 749 | next(); 750 | cAt = at; 751 | white(); 752 | if (comments) nextComment = getComment(cAt, true).join('\n'); 753 | if (ch === ']') { 754 | next(); 755 | if (comments) comments.e = [nextComment]; 756 | return array; // empty array 757 | } 758 | 759 | while (ch) { 760 | array.push(value()); 761 | cAt = at; 762 | white(); 763 | // in Hjson the comma is optional and trailing commas are allowed 764 | // note that we do not keep comments before the , if there are any 765 | if (ch === ',') { next(); cAt = at; white(); } 766 | if (comments) { 767 | var c = getComment(cAt); 768 | comments.a.push([nextComment||"", c[0]||""]); 769 | nextComment = c[1]; 770 | } 771 | if (ch === ']') { 772 | next(); 773 | if (comments) comments.a[comments.a.length-1][1] += nextComment||""; 774 | return array; 775 | } 776 | white(); 777 | } 778 | 779 | error("End of input while parsing an array (missing ']')"); 780 | } catch (e) { 781 | e.hint=e.hint||errorClosingHint(array); 782 | throw e; 783 | } 784 | } 785 | 786 | function object(withoutBraces) { 787 | // Parse an object value. 788 | 789 | var key = "", object = {}; 790 | var comments, cAt, nextComment; 791 | 792 | try { 793 | if (keepComments) comments = common.createComment(object, { c: {}, o: [] }); 794 | 795 | if (!withoutBraces) { 796 | // assuming ch === '{' 797 | next(); 798 | cAt = at; 799 | } else cAt = 1; 800 | 801 | white(); 802 | if (comments) nextComment = getComment(cAt, true).join('\n'); 803 | if (ch === '}' && !withoutBraces) { 804 | if (comments) comments.e = [nextComment]; 805 | next(); 806 | return object; // empty object 807 | } 808 | while (ch) { 809 | key = keyname(); 810 | white(); 811 | if (ch !== ':') error("Expected ':' instead of '" + ch + "'"); 812 | next(); 813 | // duplicate keys overwrite the previous value 814 | object[key] = value(); 815 | cAt = at; 816 | white(); 817 | // in Hjson the comma is optional and trailing commas are allowed 818 | // note that we do not keep comments before the , if there are any 819 | if (ch === ',') { next(); cAt = at; white(); } 820 | if (comments) { 821 | var c = getComment(cAt); 822 | comments.c[key] = [nextComment||"", c[0]||""]; 823 | nextComment = c[1]; 824 | comments.o.push(key); 825 | } 826 | if (ch === '}' && !withoutBraces) { 827 | next(); 828 | if (comments) comments.c[key][1] += nextComment||""; 829 | return object; 830 | } 831 | white(); 832 | } 833 | 834 | if (withoutBraces) return object; 835 | else error("End of input while parsing an object (missing '}')"); 836 | } catch (e) { 837 | e.hint=e.hint||errorClosingHint(object); 838 | throw e; 839 | } 840 | } 841 | 842 | function value() { 843 | // Parse a Hjson value. It could be an object, an array, a string, a number or a word. 844 | 845 | white(); 846 | switch (ch) { 847 | case '{': return object(); 848 | case '[': return array(); 849 | case "'": 850 | case '"': return string(true); 851 | default: return tfnns(); 852 | } 853 | } 854 | 855 | function checkTrailing(v, c) { 856 | var cAt = at; 857 | white(); 858 | if (ch) error("Syntax error, found trailing characters"); 859 | if (keepComments) { 860 | var b = c.join('\n'), a = getComment(cAt).join('\n'); 861 | if (a || b) { 862 | var comments = common.createComment(v, common.getComment(v)); 863 | comments.r = [b, a]; 864 | } 865 | } 866 | return v; 867 | } 868 | 869 | function rootValue() { 870 | white(); 871 | var c = keepComments ? getComment(1) : null; 872 | switch (ch) { 873 | case '{': return checkTrailing(object(), c); 874 | case '[': return checkTrailing(array(), c); 875 | default: return checkTrailing(value(), c); 876 | } 877 | } 878 | 879 | function legacyRootValue() { 880 | // Braces for the root object are optional 881 | white(); 882 | var c = keepComments ? getComment(1) : null; 883 | switch (ch) { 884 | case '{': return checkTrailing(object(), c); 885 | case '[': return checkTrailing(array(), c); 886 | } 887 | 888 | try { 889 | // assume we have a root object without braces 890 | return checkTrailing(object(true), c); 891 | } catch (e) { 892 | // test if we are dealing with a single JSON value instead (true/false/null/num/"") 893 | resetAt(); 894 | try { return checkTrailing(value(), c); } 895 | catch (e2) { throw e; } // throw original error 896 | } 897 | } 898 | 899 | if (typeof source!=="string") throw new Error("source is not a string"); 900 | var dsfDef = null; 901 | var legacyRoot = true; 902 | if (opt && typeof opt === 'object') { 903 | keepComments = opt.keepWsc; 904 | dsfDef = opt.dsf; 905 | legacyRoot = opt.legacyRoot !== false; // default true 906 | } 907 | runDsf = dsf.loadDsf(dsfDef, "parse"); 908 | text = source; 909 | resetAt(); 910 | return legacyRoot ? legacyRootValue() : rootValue(); 911 | }; 912 | 913 | },{"./hjson-common":2,"./hjson-dsf":3}],5:[function(require,module,exports){ 914 | /* Hjson https://hjson.github.io */ 915 | "use strict"; 916 | 917 | module.exports = function(data, opt) { 918 | 919 | var common = require("./hjson-common"); 920 | var dsf = require("./hjson-dsf"); 921 | 922 | var plainToken = { 923 | obj: [ '{', '}' ], 924 | arr: [ '[', ']' ], 925 | key: [ '', '' ], 926 | qkey: [ '"', '"' ], 927 | col: [ ':', '' ], 928 | com: [ ',', '' ], 929 | str: [ '', '' ], 930 | qstr: [ '"', '"' ], 931 | mstr: [ "'''", "'''" ], 932 | num: [ '', '' ], 933 | lit: [ '', '' ], 934 | dsf: [ '', '' ], 935 | esc: [ '\\', '' ], 936 | uni: [ '\\u', '' ], 937 | rem: [ '', '' ], 938 | }; 939 | 940 | // options 941 | var eol = common.EOL; 942 | var indent = ' '; 943 | var keepComments = false; 944 | var bracesSameLine = false; 945 | var quoteKeys = false; 946 | var quoteStrings = false; 947 | var condense = 0; 948 | var multiline = 1; // std=1, no-tabs=2, off=0 949 | var separator = ''; // comma separator 950 | var dsfDef = null; 951 | var sortProps = false; 952 | var token = plainToken; 953 | 954 | if (opt && typeof opt === 'object') { 955 | opt.quotes = opt.quotes === 'always' ? 'strings' : opt.quotes; // legacy 956 | 957 | if (opt.eol === '\n' || opt.eol === '\r\n') eol = opt.eol; 958 | keepComments = opt.keepWsc; 959 | condense = opt.condense || 0; 960 | bracesSameLine = opt.bracesSameLine; 961 | quoteKeys = opt.quotes === 'all' || opt.quotes === 'keys'; 962 | quoteStrings = opt.quotes === 'all' || opt.quotes === 'strings' || opt.separator === true; 963 | if (quoteStrings || opt.multiline == 'off') multiline = 0; 964 | else multiline = opt.multiline == 'no-tabs' ? 2 : 1; 965 | separator = opt.separator === true ? token.com[0] : ''; 966 | dsfDef = opt.dsf; 967 | sortProps = opt.sortProps; 968 | 969 | // If the space parameter is a number, make an indent string containing that 970 | // many spaces. If it is a string, it will be used as the indent string. 971 | 972 | if (typeof opt.space === 'number') { 973 | indent = new Array(opt.space + 1).join(' '); 974 | } else if (typeof opt.space === 'string') { 975 | indent = opt.space; 976 | } 977 | 978 | if (opt.colors === true) { 979 | token = { 980 | obj: [ '\x1b[37m{\x1b[0m', '\x1b[37m}\x1b[0m' ], 981 | arr: [ '\x1b[37m[\x1b[0m', '\x1b[37m]\x1b[0m' ], 982 | key: [ '\x1b[33m', '\x1b[0m' ], 983 | qkey: [ '\x1b[33m"', '"\x1b[0m' ], 984 | col: [ '\x1b[37m:\x1b[0m', '' ], 985 | com: [ '\x1b[37m,\x1b[0m', '' ], 986 | str: [ '\x1b[37;1m', '\x1b[0m' ], 987 | qstr: [ '\x1b[37;1m"', '"\x1b[0m' ], 988 | mstr: [ "\x1b[37;1m'''", "'''\x1b[0m" ], 989 | num: [ '\x1b[36;1m', '\x1b[0m' ], 990 | lit: [ '\x1b[36m', '\x1b[0m' ], 991 | dsf: [ '\x1b[37m', '\x1b[0m' ], 992 | esc: [ '\x1b[31m\\', '\x1b[0m' ], 993 | uni: [ '\x1b[31m\\u', '\x1b[0m' ], 994 | rem: [ '\x1b[35m', '\x1b[0m' ], 995 | }; 996 | } 997 | 998 | var i, ckeys=Object.keys(plainToken); 999 | for (i = ckeys.length - 1; i >= 0; i--) { 1000 | var k = ckeys[i]; 1001 | token[k].push(plainToken[k][0].length, plainToken[k][1].length); 1002 | } 1003 | } 1004 | 1005 | // 1006 | var runDsf; // domain specific formats 1007 | 1008 | var commonRange='\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff'; 1009 | // needsEscape tests if the string can be written without escapes 1010 | var needsEscape = new RegExp('[\\\\\\"\x00-\x1f'+commonRange+']', 'g'); 1011 | // needsQuotes tests if the string can be written as a quoteless string (like needsEscape but without \\ and \") 1012 | var needsQuotes = new RegExp('^\\s|^"|^\'|^#|^\\/\\*|^\\/\\/|^\\{|^\\}|^\\[|^\\]|^:|^,|\\s$|[\x00-\x1f'+commonRange+']', 'g'); 1013 | // needsEscapeML tests if the string can be written as a multiline string (like needsEscape but without \n, \r, \\, \", \t unless multines is 'std') 1014 | var needsEscapeML = new RegExp('\'\'\'|^[\\s]+$|[\x00-'+(multiline === 2 ? '\x09' : '\x08')+'\x0b\x0c\x0e-\x1f'+commonRange+']', 'g'); 1015 | // starts with a keyword and optionally is followed by a comment 1016 | var startsWithKeyword = new RegExp('^(true|false|null)\\s*((,|\\]|\\}|#|//|/\\*).*)?$'); 1017 | var meta = { 1018 | // table of character substitutions 1019 | '\b': 'b', 1020 | '\t': 't', 1021 | '\n': 'n', 1022 | '\f': 'f', 1023 | '\r': 'r', 1024 | '"' : '"', 1025 | '\\': '\\' 1026 | }; 1027 | var needsEscapeName = /[,\{\[\}\]\s:#"']|\/\/|\/\*/; 1028 | var gap = ''; 1029 | // 1030 | var wrapLen = 0; 1031 | 1032 | function wrap(tk, v) { 1033 | wrapLen += tk[0].length + tk[1].length - tk[2] - tk[3]; 1034 | return tk[0] + v + tk[1]; 1035 | } 1036 | 1037 | function quoteReplace(string) { 1038 | return string.replace(needsEscape, function (a) { 1039 | var c = meta[a]; 1040 | if (typeof c === 'string') return wrap(token.esc, c); 1041 | else return wrap(token.uni, ('0000' + a.charCodeAt(0).toString(16)).slice(-4)); 1042 | }); 1043 | } 1044 | 1045 | function quote(string, gap, hasComment, isRootObject) { 1046 | if (!string) return wrap(token.qstr, ''); 1047 | 1048 | needsQuotes.lastIndex = 0; 1049 | startsWithKeyword.lastIndex = 0; 1050 | 1051 | // Check if we can insert this string without quotes 1052 | // see hjson syntax (must not parse as true, false, null or number) 1053 | 1054 | if (quoteStrings || hasComment || 1055 | needsQuotes.test(string) || 1056 | common.tryParseNumber(string, true) !== undefined || 1057 | startsWithKeyword.test(string)) { 1058 | 1059 | // If the string contains no control characters, no quote characters, and no 1060 | // backslash characters, then we can safely slap some quotes around it. 1061 | // Otherwise we first check if the string can be expressed in multiline 1062 | // format or we must replace the offending characters with safe escape 1063 | // sequences. 1064 | 1065 | needsEscape.lastIndex = 0; 1066 | needsEscapeML.lastIndex = 0; 1067 | if (!needsEscape.test(string)) return wrap(token.qstr, string); 1068 | else if (!needsEscapeML.test(string) && !isRootObject && multiline) return mlString(string, gap); 1069 | else return wrap(token.qstr, quoteReplace(string)); 1070 | } else { 1071 | // return without quotes 1072 | return wrap(token.str, string); 1073 | } 1074 | } 1075 | 1076 | function mlString(string, gap) { 1077 | // wrap the string into the ''' (multiline) format 1078 | 1079 | var i, a = string.replace(/\r/g, "").split('\n'); 1080 | gap += indent; 1081 | 1082 | if (a.length === 1) { 1083 | // The string contains only a single line. We still use the multiline 1084 | // format as it avoids escaping the \ character (e.g. when used in a 1085 | // regex). 1086 | return wrap(token.mstr, a[0]); 1087 | } else { 1088 | var res = eol + gap + token.mstr[0]; 1089 | for (i = 0; i < a.length; i++) { 1090 | res += eol; 1091 | if (a[i]) res += gap + a[i]; 1092 | } 1093 | return res + eol + gap + token.mstr[1]; 1094 | } 1095 | } 1096 | 1097 | function quoteKey(name) { 1098 | if (!name) return '""'; 1099 | 1100 | // Check if we can insert this key without quotes 1101 | 1102 | if (quoteKeys || needsEscapeName.test(name)) { 1103 | needsEscape.lastIndex = 0; 1104 | return wrap(token.qkey, needsEscape.test(name) ? quoteReplace(name) : name); 1105 | } else { 1106 | // return without quotes 1107 | return wrap(token.key, name); 1108 | } 1109 | } 1110 | 1111 | function str(value, hasComment, noIndent, isRootObject) { 1112 | // Produce a string from value. 1113 | 1114 | function startsWithNL(str) { return str && str[str[0] === '\r' ? 1 : 0] === '\n'; } 1115 | function commentOnThisLine(str) { return str && !startsWithNL(str); } 1116 | function makeComment(str, prefix, trim) { 1117 | if (!str) return ""; 1118 | str = common.forceComment(str); 1119 | var i, len = str.length; 1120 | for (i = 0; i < len && str[i] <= ' '; i++) {} 1121 | if (trim && i > 0) str = str.substr(i); 1122 | if (i < len) return prefix + wrap(token.rem, str); 1123 | else return str; 1124 | } 1125 | 1126 | // What happens next depends on the value's type. 1127 | 1128 | // check for DSF 1129 | var dsfValue = runDsf(value); 1130 | if (dsfValue !== undefined) return wrap(token.dsf, dsfValue); 1131 | 1132 | switch (typeof value) { 1133 | case 'string': 1134 | return quote(value, gap, hasComment, isRootObject); 1135 | 1136 | case 'number': 1137 | // JSON numbers must be finite. Encode non-finite numbers as null. 1138 | return isFinite(value) ? wrap(token.num, String(value)) : wrap(token.lit, 'null'); 1139 | 1140 | case 'boolean': 1141 | return wrap(token.lit, String(value)); 1142 | 1143 | case 'object': 1144 | // If the type is 'object', we might be dealing with an object or an array or 1145 | // null. 1146 | 1147 | // Due to a specification blunder in ECMAScript, typeof null is 'object', 1148 | // so watch out for that case. 1149 | 1150 | if (!value) return wrap(token.lit, 'null'); 1151 | 1152 | var comments; // whitespace & comments 1153 | if (keepComments) comments = common.getComment(value); 1154 | 1155 | var isArray = Object.prototype.toString.apply(value) === '[object Array]'; 1156 | 1157 | // Make an array to hold the partial results of stringifying this object value. 1158 | var mind = gap; 1159 | gap += indent; 1160 | var eolMind = eol + mind; 1161 | var eolGap = eol + gap; 1162 | var prefix = noIndent || bracesSameLine ? '' : eolMind; 1163 | var partial = []; 1164 | var setsep; 1165 | // condense helpers: 1166 | var cpartial = condense ? [] : null; 1167 | var saveQuoteStrings = quoteStrings, saveMultiline = multiline; 1168 | var iseparator = separator ? '' : token.com[0]; 1169 | var cwrapLen = 0; 1170 | 1171 | var i, length; // loop 1172 | var k, v, vs; // key, value 1173 | var c, ca; 1174 | var res, cres; 1175 | 1176 | if (isArray) { 1177 | // The value is an array. Stringify every element. Use null as a placeholder 1178 | // for non-JSON values. 1179 | 1180 | for (i = 0, length = value.length; i < length; i++) { 1181 | setsep = i < length -1; 1182 | if (comments) { 1183 | c = comments.a[i]||[]; 1184 | ca = commentOnThisLine(c[1]); 1185 | partial.push(makeComment(c[0], "\n") + eolGap); 1186 | if (cpartial && (c[0] || c[1] || ca)) cpartial = null; 1187 | } 1188 | else partial.push(eolGap); 1189 | wrapLen = 0; 1190 | v = value[i]; 1191 | partial.push(str(v, comments ? ca : false, true) + (setsep ? separator : '')); 1192 | if (cpartial) { 1193 | // prepare the condensed version 1194 | switch (typeof v) { 1195 | case 'string': 1196 | wrapLen = 0; 1197 | quoteStrings = true; multiline = 0; 1198 | cpartial.push(str(v, false, true) + (setsep ? token.com[0] : '')); 1199 | quoteStrings = saveQuoteStrings; multiline = saveMultiline; 1200 | break; 1201 | case 'object': if (v) { cpartial = null; break; } // falls through 1202 | default: cpartial.push(partial[partial.length - 1] + (setsep ? iseparator : '')); break; 1203 | } 1204 | if (setsep) wrapLen += token.com[0].length - token.com[2]; 1205 | cwrapLen += wrapLen; 1206 | } 1207 | if (comments && c[1]) partial.push(makeComment(c[1], ca ? " " : "\n", ca)); 1208 | } 1209 | 1210 | if (length === 0) { 1211 | // when empty 1212 | if (comments && comments.e) partial.push(makeComment(comments.e[0], "\n") + eolMind); 1213 | } 1214 | else partial.push(eolMind); 1215 | 1216 | // Join all of the elements together, separated with newline, and wrap them in 1217 | // brackets. 1218 | 1219 | if (partial.length === 0) res = wrap(token.arr, ''); 1220 | else { 1221 | res = prefix + wrap(token.arr, partial.join('')); 1222 | // try if the condensed version can fit (parent key name is not included) 1223 | if (cpartial) { 1224 | cres = cpartial.join(' '); 1225 | if (cres.length - cwrapLen <= condense) res = wrap(token.arr, cres); 1226 | } 1227 | } 1228 | } else { 1229 | // Otherwise, iterate through all of the keys in the object. 1230 | var commentKeys = comments ? comments.o.slice() : []; 1231 | var objectKeys = []; 1232 | for (k in value) { 1233 | if (Object.prototype.hasOwnProperty.call(value, k) && commentKeys.indexOf(k) < 0) 1234 | objectKeys.push(k); 1235 | } 1236 | if(sortProps) { 1237 | objectKeys.sort(); 1238 | } 1239 | var keys = commentKeys.concat(objectKeys); 1240 | 1241 | for (i = 0, length = keys.length; i < length; i++) { 1242 | setsep = i < length - 1; 1243 | k = keys[i]; 1244 | if (comments) { 1245 | c = comments.c[k]||[]; 1246 | ca = commentOnThisLine(c[1]); 1247 | partial.push(makeComment(c[0], "\n") + eolGap); 1248 | if (cpartial && (c[0] || c[1] || ca)) cpartial = null; 1249 | } 1250 | else partial.push(eolGap); 1251 | 1252 | wrapLen = 0; 1253 | v = value[k]; 1254 | vs = str(v, comments && ca); 1255 | partial.push(quoteKey(k) + token.col[0] + (startsWithNL(vs) ? '' : ' ') + vs + (setsep ? separator : '')); 1256 | if (comments && c[1]) partial.push(makeComment(c[1], ca ? " " : "\n", ca)); 1257 | if (cpartial) { 1258 | // prepare the condensed version 1259 | switch (typeof v) { 1260 | case 'string': 1261 | wrapLen = 0; 1262 | quoteStrings = true; multiline = 0; 1263 | vs = str(v, false); 1264 | quoteStrings = saveQuoteStrings; multiline = saveMultiline; 1265 | cpartial.push(quoteKey(k) + token.col[0] + ' ' + vs + (setsep ? token.com[0] : '')); 1266 | break; 1267 | case 'object': if (v) { cpartial = null; break; } // falls through 1268 | default: cpartial.push(partial[partial.length - 1] + (setsep ? iseparator : '')); break; 1269 | } 1270 | wrapLen += token.col[0].length - token.col[2]; 1271 | if (setsep) wrapLen += token.com[0].length - token.com[2]; 1272 | cwrapLen += wrapLen; 1273 | } 1274 | } 1275 | if (length === 0) { 1276 | // when empty 1277 | if (comments && comments.e) partial.push(makeComment(comments.e[0], "\n") + eolMind); 1278 | } 1279 | else partial.push(eolMind); 1280 | 1281 | // Join all of the member texts together, separated with newlines 1282 | if (partial.length === 0) { 1283 | res = wrap(token.obj, ''); 1284 | } else { 1285 | // and wrap them in braces 1286 | res = prefix + wrap(token.obj, partial.join('')); 1287 | // try if the condensed version can fit 1288 | if (cpartial) { 1289 | cres = cpartial.join(' '); 1290 | if (cres.length - cwrapLen <= condense) res = wrap(token.obj, cres); 1291 | } 1292 | } 1293 | } 1294 | 1295 | gap = mind; 1296 | return res; 1297 | } 1298 | } 1299 | 1300 | 1301 | runDsf = dsf.loadDsf(dsfDef, 'stringify'); 1302 | 1303 | var res = ""; 1304 | var comments = keepComments ? comments = (common.getComment(data) || {}).r : null; 1305 | if (comments && comments[0]) res = comments[0] + '\n'; 1306 | 1307 | // get the result of stringifying the data. 1308 | res += str(data, null, true, true); 1309 | 1310 | if (comments) res += comments[1]||""; 1311 | 1312 | return res; 1313 | }; 1314 | 1315 | },{"./hjson-common":2,"./hjson-dsf":3}],6:[function(require,module,exports){ 1316 | module.exports="3.2.1"; 1317 | 1318 | },{}],7:[function(require,module,exports){ 1319 | /*! 1320 | * Hjson v3.2.1 1321 | * https://hjson.github.io 1322 | * 1323 | * Copyright 2014-2017 Christian Zangl, MIT license 1324 | * Details and documentation: 1325 | * https://github.com/hjson/hjson-js 1326 | * 1327 | * This code is based on the the JSON version by Douglas Crockford: 1328 | * https://github.com/douglascrockford/JSON-js (json_parse.js, json2.js) 1329 | */ 1330 | 1331 | /* 1332 | 1333 | This file creates a Hjson object: 1334 | 1335 | 1336 | Hjson.parse(text, options) 1337 | 1338 | options { 1339 | keepWsc boolean, keep white space and comments. This is useful 1340 | if you want to edit an hjson file and save it while 1341 | preserving comments (default false) 1342 | 1343 | dsf array of DSF (see Hjson.dsf) 1344 | 1345 | legacyRoot boolean, support omitting root braces (default true) 1346 | } 1347 | 1348 | This method parses Hjson text to produce an object or array. 1349 | It can throw a SyntaxError exception. 1350 | 1351 | 1352 | Hjson.stringify(value, options) 1353 | 1354 | value any JavaScript value, usually an object or array. 1355 | 1356 | options { all options are 1357 | 1358 | keepWsc boolean, keep white space. See parse. 1359 | 1360 | condense integer, will try to fit objects/arrays onto one line 1361 | when the output is shorter than condense characters 1362 | and the fragment contains no comments. Default 0 (off). 1363 | 1364 | bracesSameLine 1365 | boolean, makes braces appear on the same line as the key 1366 | name. Default false. 1367 | 1368 | quotes string, controls how strings are displayed. 1369 | setting separator implies "strings" 1370 | "min" - no quotes whenever possible (default) 1371 | "keys" - use quotes around keys 1372 | "strings" - use quotes around string values 1373 | "all" - use quotes around keys and string values 1374 | 1375 | multiline string, controls how multiline strings are displayed. 1376 | setting quotes implies "off" 1377 | "std" - strings containing \n are shown in 1378 | multiline format (default) 1379 | "no-tabs" - like std but disallow tabs 1380 | "off" - show in JSON format 1381 | 1382 | separator boolean, output a comma separator between elements. Default false. 1383 | 1384 | space specifies the indentation of nested structures. If it is 1385 | a number, it will specify the number of spaces to indent 1386 | at each level. If it is a string (such as '\t' or ' '), 1387 | it contains the characters used to indent at each level. 1388 | 1389 | eol specifies the EOL sequence (default is set by 1390 | Hjson.setEndOfLine()) 1391 | 1392 | colors boolean, output ascii color codes 1393 | 1394 | dsf array of DSF (see Hjson.dsf) 1395 | 1396 | emitRootBraces 1397 | obsolete: will always emit braces 1398 | 1399 | sortProps 1400 | When serializing objects into hjson, order the keys based on 1401 | their UTF-16 code units order 1402 | } 1403 | 1404 | This method produces Hjson text from a JavaScript value. 1405 | 1406 | Values that do not have JSON representations, such as undefined or 1407 | functions, will not be serialized. Such values in objects will be 1408 | dropped; in arrays they will be replaced with null. 1409 | stringify(undefined) returns undefined. 1410 | 1411 | 1412 | Hjson.endOfLine() 1413 | Hjson.setEndOfLine(eol) 1414 | 1415 | Gets or sets the stringify EOL sequence ('\n' or '\r\n'). 1416 | When running with node.js this defaults to os.EOL. 1417 | 1418 | 1419 | Hjson.rt { parse, stringify } 1420 | 1421 | This is a shortcut to roundtrip your comments when reading and updating 1422 | a config file. It is the same as specifying the keepWsc option for the 1423 | parse and stringify functions. 1424 | 1425 | 1426 | Hjson.version 1427 | 1428 | The version of this library. 1429 | 1430 | 1431 | Hjson.dsf 1432 | 1433 | Domain specific formats are extensions to the Hjson syntax (see 1434 | hjson.github.io). These formats will be parsed and made available to 1435 | the application in place of strings (e.g. enable math to allow 1436 | NaN values). 1437 | 1438 | Hjson.dsf ontains standard DSFs that can be passed to parse 1439 | and stringify. 1440 | 1441 | 1442 | Hjson.dsf.math() 1443 | 1444 | Enables support for Inf/inf, -Inf/-inf, Nan/naN and -0. 1445 | Will output as Inf, -Inf, NaN and -0. 1446 | 1447 | 1448 | Hjson.dsf.hex(options) 1449 | 1450 | Parse hexadecimal numbers prefixed with 0x. 1451 | set options.out = true to stringify _all_ integers as hex. 1452 | 1453 | 1454 | Hjson.dsf.date(options) 1455 | 1456 | support ISO dates 1457 | 1458 | 1459 | This is a reference implementation. You are free to copy, modify, or 1460 | redistribute. 1461 | 1462 | */ 1463 | 1464 | "use strict"; 1465 | 1466 | var common = require("./hjson-common"); 1467 | var version = require("./hjson-version"); 1468 | var parse = require("./hjson-parse"); 1469 | var stringify = require("./hjson-stringify"); 1470 | var comments = require("./hjson-comments"); 1471 | var dsf = require("./hjson-dsf"); 1472 | 1473 | module.exports={ 1474 | 1475 | parse: parse, 1476 | stringify: stringify, 1477 | 1478 | endOfLine: function() { return common.EOL; }, 1479 | setEndOfLine: function(eol) { 1480 | if (eol === '\n' || eol === '\r\n') common.EOL = eol; 1481 | }, 1482 | 1483 | version: version, 1484 | 1485 | // round trip shortcut 1486 | rt: { 1487 | parse: function(text, options) { 1488 | (options=options||{}).keepWsc=true; 1489 | return parse(text, options); 1490 | }, 1491 | stringify: function(value, options) { 1492 | (options=options||{}).keepWsc=true; 1493 | return stringify(value, options); 1494 | }, 1495 | }, 1496 | 1497 | comments: comments, 1498 | 1499 | dsf: dsf.std, 1500 | 1501 | }; 1502 | 1503 | },{"./hjson-comments":1,"./hjson-common":2,"./hjson-dsf":3,"./hjson-parse":4,"./hjson-stringify":5,"./hjson-version":6}],8:[function(require,module,exports){ 1504 | 1505 | },{}]},{},[7])(7); 1506 | }); 1507 | --------------------------------------------------------------------------------