Repository: aseemk/json5 Branch: main Commit: b935d4a280ea Files: 38 Total size: 137.2 KB Directory structure: gitextract_m1gwni37/ ├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .github/ │ ├── issue_template.md │ └── pull_request_template.md ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── SECURITY.md ├── build/ │ ├── es5.js │ ├── package.js │ └── unicode.js ├── lib/ │ ├── cli.js │ ├── index.d.ts │ ├── index.js │ ├── parse.d.ts │ ├── parse.js │ ├── register.js │ ├── require.js │ ├── stringify.d.ts │ ├── stringify.js │ ├── unicode.d.ts │ ├── unicode.js │ ├── util.d.ts │ └── util.js ├── package.json ├── package.json5 ├── rollup.config.js └── test/ ├── cli.js ├── errors.js ├── invalid.json5 ├── parse.js ├── require.js ├── stringify.js └── test.json5 ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ # EditorConfig is awesome: http://EditorConfig.org root = true [*] indent_style = space indent_size = 4 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [package.json] indent_size = 2 [*.md] indent_size = 2 trim_trailing_whitespace = false [*.yml] indent_size = 2 ================================================ FILE: .eslintignore ================================================ coverage/ dist/ ================================================ FILE: .eslintrc.json ================================================ { "root": true, "extends": [ "standard", "plugin:node/recommended" ], "rules": { "array-bracket-spacing": [ "error", "never" ], "arrow-parens": [ "error", "as-needed" ], "comma-dangle": [ "error", "always-multiline" ], "indent": [ "error", 4 ], "no-process-exit": "off", "object-curly-spacing": [ "error", "never" ] } } ================================================ FILE: .github/issue_template.md ================================================ If you are reporting a security vulnerability, please do not submit an issue. Instead, follow the guidelines described in our [security policy](../blob/main/SECURITY.md). If you are submitting a bug report because you are receiving an error or because this project is incompatible with the [official JSON5 specification][spec], please continue. If you are submitting a feature request or code improvement that is compatible with the [official JSON5 specification][spec], please continue. > An example of this is adding a `quote` option to `stringify()` that allows the > user to chose which quote character is used. If you are submitting a feature request or code improvement that is *incompatible* with the [official JSON5 specification][spec], please open an issue on the [specification repository](https://github.com/json5/json5-spec) instead. > An example of this is adding first class support for `Date` or `RegExp` > objects to the JSON5 format. This is outside the scope of this project. [spec]: https://json5.github.io/json5-spec/ Thank you for your cooperation. You may delete this message and the instructions above. ================================================ FILE: .github/pull_request_template.md ================================================ If you are patching a security vulnerability, please do not submit a pull request. Instead, follow the guidelines described in our [security policy](../blob/main/SECURITY.md). If you are submitting a bug fix for an error or fixing an incompatibility with the [official JSON5 specification][spec], please continue. If you are submitting a feature request or code improvement that is compatible with the [official JSON5 specification][spec], please continue. > An example of this is adding a `quote` option to `stringify()` that allows the > user to chose which quote character is used. If you are submitting a feature request or code improvement that is *incompatible* with the [official JSON5 specification][spec], please open a pull request on the [specification repository](https://github.com/json5/json5-spec) instead. > An example of this is adding first class support for `Date` or `RegExp` > objects to the JSON5 format. This is outside the scope of this project. [spec]: https://json5.github.io/json5-spec/ Thank you for your cooperation. You may delete this message and the instructions above. ================================================ FILE: .gitignore ================================================ # Logs logs *.log npm-debug.log* # Runtime data pids *.pid *.seed # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # nyc test coverage .nyc_output # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # node-waf configuration .lock-wscript # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules jspm_packages # Optional npm cache directory .npm # Optional REPL history .node_repl_history .vscode/ dist/ test/output.json test/test.json ================================================ FILE: .travis.yml ================================================ language: node_js node_js: - "11" - "10" - "8" ================================================ FILE: CHANGELOG.md ================================================ ### Unreleased [[code][c-unreleased], [diff][d-unreleased]] [c-unreleased]: https://github.com/json5/json5/tree/main [d-unreleased]: https://github.com/json5/json5/compare/v2.2.3...HEAD ### v2.2.3 [[code][c2.2.3], [diff][d2.2.3]] [c2.2.3]: https://github.com/json5/json5/tree/v2.2.3 [d2.2.3]: https://github.com/json5/json5/compare/v2.2.2...v2.2.3 - Fix: json5@2.2.3 is now the 'latest' release according to npm instead of v1.0.2. ([#299]) ### v2.2.2 [[code][c2.2.2], [diff][d2.2.2]] [c2.2.2]: https://github.com/json5/json5/tree/v2.2.2 [d2.2.2]: https://github.com/json5/json5/compare/v2.2.1...v2.2.2 - Fix: Properties with the name `__proto__` are added to objects and arrays. ([#199]) This also fixes a prototype pollution vulnerability reported by Jonathan Gregson! ([#295]). ### v2.2.1 [[code][c2.2.1], [diff][d2.2.1]] [c2.2.1]: https://github.com/json5/json5/tree/v2.2.1 [d2.2.1]: https://github.com/json5/json5/compare/v2.2.0...v2.2.1 - Fix: Removed dependence on minimist to patch CVE-2021-44906. ([#266]) ### v2.2.0 [[code][c2.2.0], [diff][d2.2.0]] [c2.2.0]: https://github.com/json5/json5/tree/v2.2.0 [d2.2.0]: https://github.com/json5/json5/compare/v2.1.3...v2.2.0 - New: Accurate and documented TypeScript declarations are now included. There is no need to install `@types/json5`. ([#236], [#244]) ### v2.1.3 [[code][c2.1.3], [diff][d2.1.3]] [c2.1.3]: https://github.com/json5/json5/tree/v2.1.3 [d2.1.3]: https://github.com/json5/json5/compare/v2.1.2...v2.1.3 - Fix: An out of memory bug when parsing numbers has been fixed. ([#228], [#229]) ### v2.1.2 [[code][c2.1.2], [diff][d2.1.2]] [c2.1.2]: https://github.com/json5/json5/tree/v2.1.2 [d2.1.2]: https://github.com/json5/json5/compare/v2.1.1...v2.1.2 - Fix: Bump `minimist` to `v1.2.5`. ([#222]) ### v2.1.1 [[code][c2.1.1], [diff][d2.1.1]] [c2.1.1]: https://github.com/json5/json5/tree/v2.1.1 [d2.1.1]: https://github.com/json5/json5/compare/v2.0.1...v2.1.1 - New: `package.json` and `package.json5` include a `module` property so bundlers like webpack, rollup and parcel can take advantage of the ES Module build. ([#208]) - Fix: `stringify` outputs `\0` as `\\x00` when followed by a digit. ([#210]) - Fix: Spelling mistakes have been fixed. ([#196]) ### v2.1.0 [[code][c2.1.0], [diff][d2.1.0]] [c2.1.0]: https://github.com/json5/json5/tree/v2.1.0 [d2.1.0]: https://github.com/json5/json5/compare/v2.0.1...v2.1.0 - New: The `index.mjs` and `index.min.mjs` browser builds in the `dist` directory support ES6 modules. ([#187]) ### v2.0.1 [[code][c2.0.1], [diff][d2.0.1]] [c2.0.1]: https://github.com/json5/json5/tree/v2.0.1 [d2.0.1]: https://github.com/json5/json5/compare/v2.0.0...v2.0.1 - Fix: The browser builds in the `dist` directory support ES5. ([#182]) ### v2.0.0 [[code][c2.0.0], [diff][d2.0.0]] [c2.0.0]: https://github.com/json5/json5/tree/v2.0.0 [d2.0.0]: https://github.com/json5/json5/compare/v1.0.1...v2.0.0 - **Major**: JSON5 officially supports Node.js v6 and later. Support for Node.js v4 has been dropped. Since Node.js v6 supports ES5 features, the code has been rewritten in native ES5, and the dependence on Babel has been eliminated. - New: Support for Unicode 10 has been added. - New: The test framework has been migrated from Mocha to Tap. - New: The browser build at `dist/index.js` is no longer minified by default. A minified version is available at `dist/index.min.js`. ([#181]) - Fix: The warning has been made clearer when line and paragraph separators are used in strings. - Fix: `package.json5` has been restored, and it is automatically generated and committed when the version is bumped. A new `build-package` NPM script has been added to facilitate this. ### v1.0.1 [[code][c1.0.1], [diff][d1.0.1]] [c1.0.1]: https://github.com/json5/json5/tree/v1.0.1 [d1.0.1]: https://github.com/json5/json5/compare/v1.0.0...v1.0.1 This release includes a bug fix and minor change. - Fix: `parse` throws on unclosed objects and arrays. - New: `package.json5` has been removed until an easier way to keep it in sync with `package.json` is found. ### v1.0.0 [[code][c1.0.0], [diff][d1.0.0]] [c1.0.0]: https://github.com/json5/json5/tree/v1.0.0 [d1.0.0]: https://github.com/json5/json5/compare/v0.5.1...v1.0.0 This release includes major internal changes and public API enhancements. - **Major**: JSON5 officially supports Node.js v4 and later. Support for Node.js v0.10 and v0.12 have been dropped. - New: Unicode property names and Unicode escapes in property names are supported. ([#1]) - New: `stringify` outputs trailing commas in objects and arrays when a `space` option is provided. ([#66]) - New: JSON5 allows line and paragraph separator characters (U+2028 and U+2029) in strings in order to be compatible with JSON. However, ES5 does not allow these characters in strings, so JSON5 gives a warning when they are parsed and escapes them when they are stringified. ([#70]) - New: `stringify` accepts an options object as its second argument. The supported options are `replacer`, `space`, and a new `quote` option that specifies the quote character used in strings. ([#71]) - New: The CLI supports STDIN and STDOUT and adds `--out-file`, `--space`, and `--validate` options. See `json5 --help` for more information. ([#72], [#84], and [#108]) - New: In addition to the white space characters space `\t`, `\v`, `\f`, `\n`, `\r`, and `\xA0`, the additional white space characters `\u2028`, `\u2029`, and all other characters in the Space Separator Unicode category are allowed. - New: In addition to the character escapes `\'`, `\"`, `\\`, `\b`, `\f`, `\n`, `\r`, and `\t`, the additional character escapes `\v` and `\0`, hexadecimal escapes like `\x0F`, and unnecessary escapes like `\a` are allowed in string values and string property names. - New: `stringify` outputs strings with single quotes by default but intelligently uses double quotes if there are more single quotes than double quotes inside the string. (i.e. `stringify('Stay here.')` outputs `'Stay here.'` while `stringify('Let\'s go.')` outputs `"Let's go."`) - New: When a character is not allowed in a string, `stringify` outputs a character escape like `\t` when available, a hexadecimal escape like `\x0F` when the Unicode code point is less than 256, or a Unicode character escape like `\u01FF`, in that order. - New: `stringify` checks for a `toJSON5` method on objects and, if it exists, stringifies its return value instead of the object. `toJSON5` overrides `toJSON` if they both exist. - New: To `require` or `import` JSON5 files, use `require('json5/lib/register')` or `import 'json5/lib/register'`. Previous versions used `json5/lib/require`, which still exists for backward compatibility but is deprecated and will give a warning. - New: To use JSON5 in browsers, use the file at `dist/index.js` or `https://unpkg.com/json5@^1.0.0`. - Fix: `stringify` properly outputs `Infinity` and `NaN`. ([#67]) - Fix: `isWord` no longer becomes a property of `JSON5` after calling `stringify`. ([#68] and [#89]) - Fix: `stringify` no longer throws when an object does not have a `prototype`. ([#154]) - Fix: `stringify` properly handles the `key` argument of `toJSON(key)` methods. `toJSON5(key)` follows this pattern. - Fix: `stringify` accepts `Number` and `String` objects as its `space` argument. - Fix: In addition to a function, `stringify` also accepts an array of keys to include in the output as its `replacer` argument. Numbers, `Number` objects, and `String` objects will be converted to a string if they are given as array values. ### v0.5.1 [[code][c0.5.1], [diff][d0.5.1]] [c0.5.1]: https://github.com/json5/json5/tree/v0.5.1 [d0.5.1]: https://github.com/json5/json5/compare/v0.5.0...v0.5.1 This release includes a minor fix for indentations when stringifying empty arrays. - Fix: Indents no longer appear in empty arrays when stringified. ([#134]) ### v0.5.0 [[code][c0.5.0], [diff][d0.5.0]] [c0.5.0]: https://github.com/json5/json5/tree/v0.5.0 [d0.5.0]: https://github.com/json5/json5/compare/v0.4.0...v0.5.0 This release includes major internal changes and public API enhancements. - **Major:** JSON5 officially supports Node.js v4 LTS and v5. Support for Node.js v0.6 and v0.8 have been dropped, while support for v0.10 and v0.12 remain. - Fix: YUI Compressor no longer fails when compressing json5.js. ([#97]) - New: `parse` and the CLI provide line and column numbers when displaying error messages. ([#101]; awesome work by [@amb26].) ### v0.4.0 [[code][c0.4.0], [diff][d0.4.0]] [c0.4.0]: https://github.com/json5/json5/tree/v0.4.0 [d0.4.0]: https://github.com/json5/json5/compare/v0.2.0...v0.4.0 Note that v0.3.0 was tagged, but never published to npm, so this v0.4.0 changelog entry includes v0.3.0 features. This is a massive release that adds `stringify` support, among other things. - **Major:** `JSON5.stringify()` now exists! This method is analogous to the native `JSON.stringify()`; it just avoids quoting keys where possible. See the [usage documentation](./README.md#usage) for more. ([#32]; huge thanks and props [@aeisenberg]!) - New: `NaN` and `-NaN` are now allowed number literals. ([#30]; thanks [@rowanhill].) - New: Duplicate object keys are now allowed; the last value is used. This is the same behavior as JSON. ([#57]; thanks [@jordanbtucker].) - Fix: Properly handle various whitespace and newline cases now. E.g. JSON5 now properly supports escaped CR and CRLF newlines in strings, and JSON5 now accepts the same whitespace as JSON (stricter than ES5). ([#58], [#60], and [#63]; thanks [@jordanbtucker].) - New: Negative hexadecimal numbers (e.g. `-0xC8`) are allowed again. (They were disallowed in v0.2.0; see below.) It turns out they *are* valid in ES5, so JSON5 supports them now too. ([#36]; thanks [@jordanbtucker]!) ### v0.2.0 [[code][c0.2.0], [diff][d0.2.0]] [c0.2.0]: https://github.com/json5/json5/tree/v0.2.0 [d0.2.0]: https://github.com/json5/json5/compare/v0.1.0...v0.2.0 This release fixes some bugs and adds some more utility features to help you express data more easily: - **Breaking:** Negative hexadecimal numbers (e.g. `-0xC8`) are rejected now. While V8 (e.g. Chrome and Node) supported them, it turns out they're invalid in ES5. This has been [fixed in V8][v8-hex-fix] (and by extension, Chrome and Node), so JSON5 officially rejects them now, too. ([#36]) - New: Trailing decimal points in decimal numbers are allowed again. (They were disallowed in v0.1.0; see below.) They're allowed by ES5, and differentiating between integers and floats may make sense on some platforms. ([#16]; thanks [@Midar].) - New: `Infinity` and `-Infinity` are now allowed number literals. ([#30]; thanks [@pepkin88].) - New: Plus signs (`+`) in front of numbers are now allowed, since it can be helpful in some contexts to explicitly mark numbers as positive. (E.g. when a property represents changes or deltas.) - Fix: unescaped newlines in strings are rejected now. ([#24]; thanks [@Midar].) ### v0.1.0 [[code][c0.1.0], [diff][d0.1.0]] [c0.1.0]: https://github.com/json5/json5/tree/v0.1.0 [d0.1.0]: https://github.com/json5/json5/compare/v0.0.1...v0.1.0 This release tightens JSON5 support and adds helpful utility features: - New: Support hexadecimal numbers. (Thanks [@MaxNanasy].) - Fix: Reject octal numbers properly now. Previously, they were accepted but improperly parsed as base-10 numbers. (Thanks [@MaxNanasy].) - **Breaking:** Reject "noctal" numbers now (base-10 numbers that begin with a leading zero). These are disallowed by both JSON5 and JSON, as well as by ES5's strict mode. (Thanks [@MaxNanasy].) - New: Support leading decimal points in decimal numbers. (Thanks [@MaxNanasy].) - **Breaking:** Reject trailing decimal points in decimal numbers now. These are disallowed by both JSON5 and JSON. (Thanks [@MaxNanasy].) - **Breaking:** Reject omitted elements in arrays now. These are disallowed by both JSON5 and JSON. - Fix: Throw proper `SyntaxError` instances on errors now. - New: Add Node.js `require()` hook. Register via `json5/lib/require`. - New: Add Node.js `json5` executable to compile JSON5 files to JSON. ### v0.0.1 [[code][c0.0.1], [diff][d0.0.1]] [c0.0.1]: https://github.com/json5/json5/tree/v0.0.1 [d0.0.1]: https://github.com/json5/json5/compare/v0.0.0...v0.0.1 This was the first implementation of this JSON5 parser. - Support unquoted object keys, including reserved words. Unicode characters and escape sequences aren't yet supported. - Support single-quoted strings. - Support multi-line strings. - Support trailing commas in arrays and objects. - Support comments, both inline and block. ### v0.0.0 [[code](https://github.com/json5/json5/tree/v0.0.0)] Let's consider this to be Douglas Crockford's original [json_parse.js] — a parser for the regular JSON format. [json_parse.js]: https://github.com/douglascrockford/JSON-js/blob/master/json_parse.js [v8-hex-fix]: http://code.google.com/p/v8/issues/detail?id=2240 [@MaxNanasy]: https://github.com/MaxNanasy [@Midar]: https://github.com/Midar [@pepkin88]: https://github.com/pepkin88 [@rowanhill]: https://github.com/rowanhill [@aeisenberg]: https://github.com/aeisenberg [@jordanbtucker]: https://github.com/jordanbtucker [@amb26]: https://github.com/amb26 [#1]: https://github.com/json5/json5/issues/1 [#16]: https://github.com/json5/json5/issues/16 [#24]: https://github.com/json5/json5/issues/24 [#30]: https://github.com/json5/json5/issues/30 [#32]: https://github.com/json5/json5/issues/32 [#36]: https://github.com/json5/json5/issues/36 [#57]: https://github.com/json5/json5/issues/57 [#58]: https://github.com/json5/json5/pull/58 [#60]: https://github.com/json5/json5/pull/60 [#63]: https://github.com/json5/json5/pull/63 [#66]: https://github.com/json5/json5/issues/66 [#67]: https://github.com/json5/json5/issues/67 [#68]: https://github.com/json5/json5/issues/68 [#70]: https://github.com/json5/json5/issues/70 [#71]: https://github.com/json5/json5/issues/71 [#72]: https://github.com/json5/json5/issues/72 [#84]: https://github.com/json5/json5/pull/84 [#89]: https://github.com/json5/json5/pull/89 [#97]: https://github.com/json5/json5/pull/97 [#101]: https://github.com/json5/json5/pull/101 [#108]: https://github.com/json5/json5/pull/108 [#134]: https://github.com/json5/json5/pull/134 [#154]: https://github.com/json5/json5/issues/154 [#181]: https://github.com/json5/json5/issues/181 [#182]: https://github.com/json5/json5/issues/182 [#187]: https://github.com/json5/json5/issues/187 [#196]: https://github.com/json5/json5/issues/196 [#199]: https://github.com/json5/json5/issues/199 [#208]: https://github.com/json5/json5/issues/208 [#210]: https://github.com/json5/json5/issues/210 [#222]: https://github.com/json5/json5/issues/222 [#228]: https://github.com/json5/json5/issues/228 [#229]: https://github.com/json5/json5/issues/229 [#236]: https://github.com/json5/json5/issues/236 [#244]: https://github.com/json5/json5/issues/244 [#266]: https://github.com/json5/json5/issues/266 [#295]: https://github.com/json5/json5/issues/295 [#299]: https://github.com/json5/json5/issues/299 ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to JSON5 We're glad you're interested in contributing to JSON5. ## Development ```sh git clone https://github.com/json5/json5 cd json5 npm install ``` When contributing code, please write relevant tests and run `npm test` and `npm run lint` before submitting pull requests. Please use an editor that supports [EditorConfig](http://editorconfig.org/). ## Issues To report bugs or request features regarding the JSON5 data format, please submit an issue to the [official specification repository](https://github.com/json5/json5-spec). To report bugs or request features regarding the JavaScript implementation of JSON5, please submit an issue to this repository. ================================================ FILE: LICENSE.md ================================================ MIT License Copyright (c) 2012-2018 Aseem Kishore, and [others]. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. [others]: https://github.com/json5/json5/contributors ================================================ FILE: README.md ================================================ # JSON5 – JSON for Humans [![Build Status](https://app.travis-ci.com/json5/json5.svg?branch=main)][Build Status] [![Coverage Status](https://coveralls.io/repos/github/json5/json5/badge.svg)][Coverage Status] JSON5 is an extension to the popular [JSON] file format that aims to be easier to **write and maintain _by hand_ (e.g. for config files)**. It is _not intended_ to be used for machine-to-machine communication. (Keep using JSON or other file formats for that. 🙂) JSON5 was started in 2012, and as of 2022, now gets **[>65M downloads/week](https://www.npmjs.com/package/json5)**, ranks in the **[top 0.1%](https://gist.github.com/anvaka/8e8fa57c7ee1350e3491)** of the most depended-upon packages on npm, and has been adopted by major projects like **[Chromium](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/platform/runtime_enabled_features.json5;drc=5de823b36e68fd99009a29281b17bc3a1d6b329c), [Next.js](https://github.com/vercel/next.js/blob/b88f20c90bf4659b8ad5cb2a27956005eac2c7e8/packages/next/lib/find-config.ts#L43-L46), [Babel](https://babeljs.io/docs/en/config-files#supported-file-extensions), [Retool](https://community.retool.com/t/i-am-attempting-to-append-several-text-fields-to-a-google-sheet-but-receiving-a-json5-invalid-character-error/7626), [WebStorm](https://www.jetbrains.com/help/webstorm/json.html), and [more](https://github.com/json5/json5/wiki/In-the-Wild)**. It's also natively supported on **[Apple platforms](https://developer.apple.com/documentation/foundation/jsondecoder/3766916-allowsjson5)** like **macOS** and **iOS**. Formally, the **[JSON5 Data Interchange Format](https://spec.json5.org/)** is a superset of JSON (so valid JSON files will always be valid JSON5 files) that expands its syntax to include some productions from [ECMAScript 5.1] (ES5). It's also a _subset_ of ES5, so valid JSON5 files will always be valid ES5.[*](#ecmascript-compatibility) This JavaScript library is a reference implementation for JSON5 parsing and serialization, and is directly used in many of the popular projects mentioned above (where e.g. extreme performance isn't necessary), but others have created [many other libraries](https://github.com/json5/json5/wiki/In-the-Wild) across many other platforms. [Build Status]: https://app.travis-ci.com/json5/json5 [Coverage Status]: https://coveralls.io/github/json5/json5 [JSON]: https://tools.ietf.org/html/rfc7159 [ECMAScript 5.1]: https://www.ecma-international.org/ecma-262/5.1/ ## Summary of Features The following ECMAScript 5.1 features, which are not supported in JSON, have been extended to JSON5. ### Objects - Object keys may be an ECMAScript 5.1 _[IdentifierName]_. - Objects may have a single trailing comma. ### Arrays - Arrays may have a single trailing comma. ### Strings - Strings may be single quoted. - Strings may span multiple lines by escaping new line characters. - Strings may include character escapes. ### Numbers - Numbers may be hexadecimal. - Numbers may have a leading or trailing decimal point. - Numbers may be [IEEE 754] positive infinity, negative infinity, and NaN. - Numbers may begin with an explicit plus sign. ### Comments - Single and multi-line comments are allowed. ### White Space - Additional white space characters are allowed. [IdentifierName]: https://www.ecma-international.org/ecma-262/5.1/#sec-7.6 [IEEE 754]: http://ieeexplore.ieee.org/servlet/opac?punumber=4610933 ## Example Kitchen-sink example: ```js { // comments unquoted: 'and you can quote me on that', singleQuotes: 'I can use "double quotes" here', lineBreaks: "Look, Mom! \ No \\n's!", hexadecimal: 0xdecaf, leadingDecimalPoint: .8675309, andTrailing: 8675309., positiveSign: +1, trailingComma: 'in objects', andIn: ['arrays',], "backwardsCompatible": "with JSON", } ``` A more real-world example is [this config file](https://github.com/chromium/chromium/blob/feb3c9f670515edf9a88f185301cbd7794ee3e52/third_party/blink/renderer/platform/runtime_enabled_features.json5) from the Chromium/Blink project. ## Specification For a detailed explanation of the JSON5 format, please read the [official specification](https://json5.github.io/json5-spec/). ## Installation and Usage ### Node.js ```sh npm install json5 ``` #### CommonJS ```js const JSON5 = require('json5') ``` #### Modules ```js import JSON5 from 'json5' ``` ### Browsers #### UMD ```html ``` #### Modules ```html ``` ## API The JSON5 API is compatible with the [JSON API]. [JSON API]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON ### JSON5.parse() Parses a JSON5 string, constructing the JavaScript value or object described by the string. An optional reviver function can be provided to perform a transformation on the resulting object before it is returned. #### Syntax JSON5.parse(text[, reviver]) #### Parameters - `text`: The string to parse as JSON5. - `reviver`: If a function, this prescribes how the value originally produced by parsing is transformed, before being returned. #### Return value The object corresponding to the given JSON5 text. ### JSON5.stringify() Converts a JavaScript value to a JSON5 string, optionally replacing values if a replacer function is specified, or optionally including only the specified properties if a replacer array is specified. #### Syntax JSON5.stringify(value[, replacer[, space]]) JSON5.stringify(value[, options]) #### Parameters - `value`: The value to convert to a JSON5 string. - `replacer`: A function that alters the behavior of the stringification process, or an array of String and Number objects that serve as a whitelist for selecting/filtering the properties of the value object to be included in the JSON5 string. If this value is null or not provided, all properties of the object are included in the resulting JSON5 string. - `space`: A String or Number object that's used to insert white space into the output JSON5 string for readability purposes. If this is a Number, it indicates the number of space characters to use as white space; this number is capped at 10 (if it is greater, the value is just 10). Values less than 1 indicate that no space should be used. If this is a String, the string (or the first 10 characters of the string, if it's longer than that) is used as white space. If this parameter is not provided (or is null), no white space is used. If white space is used, trailing commas will be used in objects and arrays. - `options`: An object with the following properties: - `replacer`: Same as the `replacer` parameter. - `space`: Same as the `space` parameter. - `quote`: A String representing the quote character to use when serializing strings. #### Return value A JSON5 string representing the value. ### Node.js `require()` JSON5 files When using Node.js, you can `require()` JSON5 files by adding the following statement. ```js require('json5/lib/register') ``` Then you can load a JSON5 file with a Node.js `require()` statement. For example: ```js const config = require('./config.json5') ``` ## CLI Since JSON is more widely used than JSON5, this package includes a CLI for converting JSON5 to JSON and for validating the syntax of JSON5 documents. ### Installation ```sh npm install --global json5 ``` ### Usage ```sh json5 [options] ``` If `` is not provided, then STDIN is used. #### Options: - `-s`, `--space`: The number of spaces to indent or `t` for tabs - `-o`, `--out-file [file]`: Output to the specified file, otherwise STDOUT - `-v`, `--validate`: Validate JSON5 but do not output JSON - `-V`, `--version`: Output the version number - `-h`, `--help`: Output usage information ## Contributing ### Development ```sh git clone https://github.com/json5/json5 cd json5 npm install ``` When contributing code, please write relevant tests and run `npm test` and `npm run lint` before submitting pull requests. Please use an editor that supports [EditorConfig](http://editorconfig.org/). ### Issues To report bugs or request features regarding the JSON5 **data format**, please submit an issue to the official **[_specification_ repository](https://github.com/json5/json5-spec)**. Note that we will never add any features that make JSON5 incompatible with ES5; that compatibility is a fundamental premise of JSON5.[*](#ecmascript-compatibility) To report bugs or request features regarding this **JavaScript implementation** of JSON5, please submit an issue to **_this_ repository**. ### Security Vulnerabilities and Disclosures To report a security vulnerability, please follow the follow the guidelines described in our [security policy](./SECURITY.md). ## ECMAScript Compatibility While JSON5 aims to be fully compatible with ES5, there is one exception where both JSON and JSON5 are not. Both JSON and JSON5 allow unescaped line and paragraph separator characters (U+2028 and U+2029) in strings, however ES5 does not. A [proposal](https://github.com/tc39/proposal-json-superset) to allow these characters in strings was adopted into ES2019, making JSON and JSON5 fully compatible with ES2019. ## License MIT. See [LICENSE.md](./LICENSE.md) for details. ## Credits [Aseem Kishore](https://github.com/aseemk) founded this project. He wrote a [blog post](https://aseemk.substack.com/p/ignore-the-f-ing-haters-json5) about the journey and lessons learned 10 years in. [Michael Bolin](http://bolinfest.com/) independently arrived at and published some of these same ideas with awesome explanations and detail. Recommended reading: [Suggested Improvements to JSON](http://bolinfest.com/essays/json.html) [Douglas Crockford](http://www.crockford.com/) of course designed and built JSON, but his state machine diagrams on the [JSON website](http://json.org/), as cheesy as it may sound, gave us motivation and confidence that building a new parser to implement these ideas was within reach! The original implementation of JSON5 was also modeled directly off of Doug’s open-source [json_parse.js] parser. We’re grateful for that clean and well-documented code. [json_parse.js]: https://github.com/douglascrockford/JSON-js/blob/03157639c7a7cddd2e9f032537f346f1a87c0f6d/json_parse.js [Max Nanasy](https://github.com/MaxNanasy) has been an early and prolific supporter, contributing multiple patches and ideas. [Andrew Eisenberg](https://github.com/aeisenberg) contributed the original `stringify` method. [Jordan Tucker](https://github.com/jordanbtucker) has aligned JSON5 more closely with ES5, wrote the official JSON5 specification, completely rewrote the codebase from the ground up, and is actively maintaining this project. ================================================ FILE: SECURITY.md ================================================ # JSON5 Security Policy We take security seriously. Responsible reporting and disclosure of security vulnerabilities is important for the protection and privacy of our users. If you discover any security vulnerabilities, please follow these guidelines. Published security advisories are available on our [GitHub Security Advisories] page. To report a vulnerability, please draft a [new security advisory on GitHub]. Any fields that you are unsure of or don't understand can be left at their default values. The important part is that the vulnerability is reported. Once the security advisory draft has been created, we will validate the vulnerability and coordinate with you to fix it, release a patch, and responsibly disclose the vulnerability to the public. Read GitHub's documentation on [privately reporting a security vulnerability] for details. If you are unable to draft a security advisory, or if you need help or have security related questions, please send an email to [security@json5.org]. Please do not report undisclosed vulnerabilities on public sites or forums, including GitHub issues and pull requests. Reporting vulnerabilities to the public could allow attackers to exploit vulnerable applications before we have been able to release a patch and before applications have had time to install the patch. Once we have released a patch and sufficient time has passed for applications to install the patch, we will disclose the vulnerability to the public, at which time you will be free to publish details of the vulnerability on public sites and forums. If you have a fix for a security vulnerability, please do not submit a GitHub pull request. Instead, report the vulnerability as described in this policy. Once we have verified the vulnerability, we can create a [temporary private fork] to collaborate on a patch. We appreciate your cooperation in helping keep our users safe by following this policy. [github security advisories]: https://github.com/json5/json5/security/advisories [new security advisory on github]: https://github.com/json5/json5/security/advisories/new [privately reporting a security vulnerability]: https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability [security@json5.org]: mailto:security@json5.org [temporary private fork]: https://docs.github.com/en/code-security/security-advisories/repository-security-advisories/collaborating-in-a-temporary-private-fork-to-resolve-a-repository-security-vulnerability ================================================ FILE: build/es5.js ================================================ require('core-js/fn/string/code-point-at') require('core-js/fn/string/from-code-point') const JSON5 = require('../lib') module.exports = JSON5 ================================================ FILE: build/package.js ================================================ const fs = require('fs') const path = require('path') const JSON5 = require('../lib') const pkg = require('../package.json') let pkg5 = '// This is a generated file. Do not edit.\n' pkg5 += pkg5 = JSON5.stringify(pkg, null, 2) fs.writeFileSync(path.resolve(__dirname, '..', 'package.json5'), pkg5) ================================================ FILE: build/unicode.js ================================================ /* eslint-disable camelcase */ const fs = require('fs') const path = require('path') const regenerate = require('regenerate') const libDir = 'lib' const Space_Separator = regenerate() .add(require('unicode-10.0.0/General_Category/Space_Separator/code-points')) .remove('\t', '\v', '\f', ' ', '\u00A0', '\uFEFF') const ID_Start = regenerate() .add(require('unicode-10.0.0/General_Category/Uppercase_Letter/code-points')) .add(require('unicode-10.0.0/General_Category/Lowercase_Letter/code-points')) .add(require('unicode-10.0.0/General_Category/Titlecase_Letter/code-points')) .add(require('unicode-10.0.0/General_Category/Modifier_Letter/code-points')) .add(require('unicode-10.0.0/General_Category/Other_Letter/code-points')) .add(require('unicode-10.0.0/General_Category/Letter_Number/code-points')) .remove('$', '_') .removeRange('A', 'Z') .removeRange('a', 'z') const ID_Continue = regenerate() .add(ID_Start) .add(require('unicode-10.0.0/General_Category/Nonspacing_Mark/code-points')) .add(require('unicode-10.0.0/General_Category/Spacing_Mark/code-points')) .add(require('unicode-10.0.0/General_Category/Decimal_Number/code-points')) .add(require('unicode-10.0.0/General_Category/Connector_Punctuation/code-points')) .remove('$', '_') .removeRange('0', '9') .removeRange('A', 'Z') .removeRange('a', 'z') const outDir = libDir const outPath = path.join(outDir, 'unicode.js') if (!fs.existsSync(outDir)) { fs.mkdirSync(outDir) } const data = { Space_Separator, ID_Start, ID_Continue, } let es6 = '// This is a generated file. Do not edit.\n' es6 += Object.keys(data).map(key => `module.exports.${key} = /${data[key]}/\n`).join('') fs.writeFileSync(outPath, es6) ================================================ FILE: lib/cli.js ================================================ #!/usr/bin/env node const fs = require('fs') const path = require('path') const pkg = require('../package.json') const JSON5 = require('./') const argv = parseArgs() if (argv.version) { version() } else if (argv.help) { usage() } else { const inFilename = argv.defaults[0] let readStream if (inFilename) { readStream = fs.createReadStream(inFilename) } else { readStream = process.stdin } let json5 = '' readStream.on('data', data => { json5 += data }) readStream.on('end', () => { let space if (argv.space === 't' || argv.space === 'tab') { space = '\t' } else { space = Number(argv.space) } let value try { value = JSON5.parse(json5) if (!argv.validate) { const json = JSON.stringify(value, null, space) let writeStream // --convert is for backward compatibility with v0.5.1. If // specified with and not --out-file, then a file with // the same name but with a .json extension will be written. if (argv.convert && inFilename && !argv.outFile) { const parsedFilename = path.parse(inFilename) const outFilename = path.format( Object.assign( parsedFilename, {base: path.basename(parsedFilename.base, parsedFilename.ext) + '.json'} ) ) writeStream = fs.createWriteStream(outFilename) } else if (argv.outFile) { writeStream = fs.createWriteStream(argv.outFile) } else { writeStream = process.stdout } writeStream.write(json) } } catch (err) { console.error(err.message) process.exit(1) } }) } function parseArgs () { let convert let space let validate let outFile let version let help const defaults = [] const args = process.argv.slice(2) for (let i = 0; i < args.length; i++) { const arg = args[i] switch (arg) { case '--convert': case '-c': convert = true break case '--space': case '-s': space = args[++i] break case '--validate': case '-v': validate = true break case '--out-file': case '-o': outFile = args[++i] break case '--version': case '-V': version = true break case '--help': case '-h': help = true break default: defaults.push(arg) break } } return { convert, space, validate, outFile, version, help, defaults, } } function version () { console.log(pkg.version) } function usage () { console.log( ` Usage: json5 [options] If is not provided, then STDIN is used. Options: -s, --space The number of spaces to indent or 't' for tabs -o, --out-file [file] Output to the specified file, otherwise STDOUT -v, --validate Validate JSON5 but do not output JSON -V, --version Output the version number -h, --help Output usage information` ) } ================================================ FILE: lib/index.d.ts ================================================ import parse = require('./parse') import stringify = require('./stringify') export {parse, stringify} ================================================ FILE: lib/index.js ================================================ const parse = require('./parse') const stringify = require('./stringify') const JSON5 = { parse, stringify, } module.exports = JSON5 ================================================ FILE: lib/parse.d.ts ================================================ /** * Parses a JSON5 string, constructing the JavaScript value or object described * by the string. * @template T The type of the return value. * @param text The string to parse as JSON5. * @param reviver A function that prescribes how the value originally produced * by parsing is transformed before being returned. * @returns The JavaScript value converted from the JSON5 string. */ declare function parse( text: string, reviver?: ((this: any, key: string, value: any) => any) | null, ): T export = parse ================================================ FILE: lib/parse.js ================================================ const util = require('./util') let source let parseState let stack let pos let line let column let token let key let root module.exports = function parse (text, reviver) { source = String(text) parseState = 'start' stack = [] pos = 0 line = 1 column = 0 token = undefined key = undefined root = undefined do { token = lex() // This code is unreachable. // if (!parseStates[parseState]) { // throw invalidParseState() // } parseStates[parseState]() } while (token.type !== 'eof') if (typeof reviver === 'function') { return internalize({'': root}, '', reviver) } return root } function internalize (holder, name, reviver) { const value = holder[name] if (value != null && typeof value === 'object') { if (Array.isArray(value)) { for (let i = 0; i < value.length; i++) { const key = String(i) const replacement = internalize(value, key, reviver) if (replacement === undefined) { delete value[key] } else { Object.defineProperty(value, key, { value: replacement, writable: true, enumerable: true, configurable: true, }) } } } else { for (const key in value) { const replacement = internalize(value, key, reviver) if (replacement === undefined) { delete value[key] } else { Object.defineProperty(value, key, { value: replacement, writable: true, enumerable: true, configurable: true, }) } } } } return reviver.call(holder, name, value) } let lexState let buffer let doubleQuote let sign let c function lex () { lexState = 'default' buffer = '' doubleQuote = false sign = 1 for (;;) { c = peek() // This code is unreachable. // if (!lexStates[lexState]) { // throw invalidLexState(lexState) // } const token = lexStates[lexState]() if (token) { return token } } } function peek () { if (source[pos]) { return String.fromCodePoint(source.codePointAt(pos)) } } function read () { const c = peek() if (c === '\n') { line++ column = 0 } else if (c) { column += c.length } else { column++ } if (c) { pos += c.length } return c } const lexStates = { default () { switch (c) { case '\t': case '\v': case '\f': case ' ': case '\u00A0': case '\uFEFF': case '\n': case '\r': case '\u2028': case '\u2029': read() return case '/': read() lexState = 'comment' return case undefined: read() return newToken('eof') } if (util.isSpaceSeparator(c)) { read() return } // This code is unreachable. // if (!lexStates[parseState]) { // throw invalidLexState(parseState) // } return lexStates[parseState]() }, comment () { switch (c) { case '*': read() lexState = 'multiLineComment' return case '/': read() lexState = 'singleLineComment' return } throw invalidChar(read()) }, multiLineComment () { switch (c) { case '*': read() lexState = 'multiLineCommentAsterisk' return case undefined: throw invalidChar(read()) } read() }, multiLineCommentAsterisk () { switch (c) { case '*': read() return case '/': read() lexState = 'default' return case undefined: throw invalidChar(read()) } read() lexState = 'multiLineComment' }, singleLineComment () { switch (c) { case '\n': case '\r': case '\u2028': case '\u2029': read() lexState = 'default' return case undefined: read() return newToken('eof') } read() }, value () { switch (c) { case '{': case '[': return newToken('punctuator', read()) case 'n': read() literal('ull') return newToken('null', null) case 't': read() literal('rue') return newToken('boolean', true) case 'f': read() literal('alse') return newToken('boolean', false) case '-': case '+': if (read() === '-') { sign = -1 } lexState = 'sign' return case '.': buffer = read() lexState = 'decimalPointLeading' return case '0': buffer = read() lexState = 'zero' return case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': buffer = read() lexState = 'decimalInteger' return case 'I': read() literal('nfinity') return newToken('numeric', Infinity) case 'N': read() literal('aN') return newToken('numeric', NaN) case '"': case "'": doubleQuote = (read() === '"') buffer = '' lexState = 'string' return } throw invalidChar(read()) }, identifierNameStartEscape () { if (c !== 'u') { throw invalidChar(read()) } read() const u = unicodeEscape() switch (u) { case '$': case '_': break default: if (!util.isIdStartChar(u)) { throw invalidIdentifier() } break } buffer += u lexState = 'identifierName' }, identifierName () { switch (c) { case '$': case '_': case '\u200C': case '\u200D': buffer += read() return case '\\': read() lexState = 'identifierNameEscape' return } if (util.isIdContinueChar(c)) { buffer += read() return } return newToken('identifier', buffer) }, identifierNameEscape () { if (c !== 'u') { throw invalidChar(read()) } read() const u = unicodeEscape() switch (u) { case '$': case '_': case '\u200C': case '\u200D': break default: if (!util.isIdContinueChar(u)) { throw invalidIdentifier() } break } buffer += u lexState = 'identifierName' }, sign () { switch (c) { case '.': buffer = read() lexState = 'decimalPointLeading' return case '0': buffer = read() lexState = 'zero' return case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': buffer = read() lexState = 'decimalInteger' return case 'I': read() literal('nfinity') return newToken('numeric', sign * Infinity) case 'N': read() literal('aN') return newToken('numeric', NaN) } throw invalidChar(read()) }, zero () { switch (c) { case '.': buffer += read() lexState = 'decimalPoint' return case 'e': case 'E': buffer += read() lexState = 'decimalExponent' return case 'x': case 'X': buffer += read() lexState = 'hexadecimal' return } return newToken('numeric', sign * 0) }, decimalInteger () { switch (c) { case '.': buffer += read() lexState = 'decimalPoint' return case 'e': case 'E': buffer += read() lexState = 'decimalExponent' return } if (util.isDigit(c)) { buffer += read() return } return newToken('numeric', sign * Number(buffer)) }, decimalPointLeading () { if (util.isDigit(c)) { buffer += read() lexState = 'decimalFraction' return } throw invalidChar(read()) }, decimalPoint () { switch (c) { case 'e': case 'E': buffer += read() lexState = 'decimalExponent' return } if (util.isDigit(c)) { buffer += read() lexState = 'decimalFraction' return } return newToken('numeric', sign * Number(buffer)) }, decimalFraction () { switch (c) { case 'e': case 'E': buffer += read() lexState = 'decimalExponent' return } if (util.isDigit(c)) { buffer += read() return } return newToken('numeric', sign * Number(buffer)) }, decimalExponent () { switch (c) { case '+': case '-': buffer += read() lexState = 'decimalExponentSign' return } if (util.isDigit(c)) { buffer += read() lexState = 'decimalExponentInteger' return } throw invalidChar(read()) }, decimalExponentSign () { if (util.isDigit(c)) { buffer += read() lexState = 'decimalExponentInteger' return } throw invalidChar(read()) }, decimalExponentInteger () { if (util.isDigit(c)) { buffer += read() return } return newToken('numeric', sign * Number(buffer)) }, hexadecimal () { if (util.isHexDigit(c)) { buffer += read() lexState = 'hexadecimalInteger' return } throw invalidChar(read()) }, hexadecimalInteger () { if (util.isHexDigit(c)) { buffer += read() return } return newToken('numeric', sign * Number(buffer)) }, string () { switch (c) { case '\\': read() buffer += escape() return case '"': if (doubleQuote) { read() return newToken('string', buffer) } buffer += read() return case "'": if (!doubleQuote) { read() return newToken('string', buffer) } buffer += read() return case '\n': case '\r': throw invalidChar(read()) case '\u2028': case '\u2029': separatorChar(c) break case undefined: throw invalidChar(read()) } buffer += read() }, start () { switch (c) { case '{': case '[': return newToken('punctuator', read()) // This code is unreachable since the default lexState handles eof. // case undefined: // return newToken('eof') } lexState = 'value' }, beforePropertyName () { switch (c) { case '$': case '_': buffer = read() lexState = 'identifierName' return case '\\': read() lexState = 'identifierNameStartEscape' return case '}': return newToken('punctuator', read()) case '"': case "'": doubleQuote = (read() === '"') lexState = 'string' return } if (util.isIdStartChar(c)) { buffer += read() lexState = 'identifierName' return } throw invalidChar(read()) }, afterPropertyName () { if (c === ':') { return newToken('punctuator', read()) } throw invalidChar(read()) }, beforePropertyValue () { lexState = 'value' }, afterPropertyValue () { switch (c) { case ',': case '}': return newToken('punctuator', read()) } throw invalidChar(read()) }, beforeArrayValue () { if (c === ']') { return newToken('punctuator', read()) } lexState = 'value' }, afterArrayValue () { switch (c) { case ',': case ']': return newToken('punctuator', read()) } throw invalidChar(read()) }, end () { // This code is unreachable since it's handled by the default lexState. // if (c === undefined) { // read() // return newToken('eof') // } throw invalidChar(read()) }, } function newToken (type, value) { return { type, value, line, column, } } function literal (s) { for (const c of s) { const p = peek() if (p !== c) { throw invalidChar(read()) } read() } } function escape () { const c = peek() switch (c) { case 'b': read() return '\b' case 'f': read() return '\f' case 'n': read() return '\n' case 'r': read() return '\r' case 't': read() return '\t' case 'v': read() return '\v' case '0': read() if (util.isDigit(peek())) { throw invalidChar(read()) } return '\0' case 'x': read() return hexEscape() case 'u': read() return unicodeEscape() case '\n': case '\u2028': case '\u2029': read() return '' case '\r': read() if (peek() === '\n') { read() } return '' case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': throw invalidChar(read()) case undefined: throw invalidChar(read()) } return read() } function hexEscape () { let buffer = '' let c = peek() if (!util.isHexDigit(c)) { throw invalidChar(read()) } buffer += read() c = peek() if (!util.isHexDigit(c)) { throw invalidChar(read()) } buffer += read() return String.fromCodePoint(parseInt(buffer, 16)) } function unicodeEscape () { let buffer = '' let count = 4 while (count-- > 0) { const c = peek() if (!util.isHexDigit(c)) { throw invalidChar(read()) } buffer += read() } return String.fromCodePoint(parseInt(buffer, 16)) } const parseStates = { start () { if (token.type === 'eof') { throw invalidEOF() } push() }, beforePropertyName () { switch (token.type) { case 'identifier': case 'string': key = token.value parseState = 'afterPropertyName' return case 'punctuator': // This code is unreachable since it's handled by the lexState. // if (token.value !== '}') { // throw invalidToken() // } pop() return case 'eof': throw invalidEOF() } // This code is unreachable since it's handled by the lexState. // throw invalidToken() }, afterPropertyName () { // This code is unreachable since it's handled by the lexState. // if (token.type !== 'punctuator' || token.value !== ':') { // throw invalidToken() // } if (token.type === 'eof') { throw invalidEOF() } parseState = 'beforePropertyValue' }, beforePropertyValue () { if (token.type === 'eof') { throw invalidEOF() } push() }, beforeArrayValue () { if (token.type === 'eof') { throw invalidEOF() } if (token.type === 'punctuator' && token.value === ']') { pop() return } push() }, afterPropertyValue () { // This code is unreachable since it's handled by the lexState. // if (token.type !== 'punctuator') { // throw invalidToken() // } if (token.type === 'eof') { throw invalidEOF() } switch (token.value) { case ',': parseState = 'beforePropertyName' return case '}': pop() } // This code is unreachable since it's handled by the lexState. // throw invalidToken() }, afterArrayValue () { // This code is unreachable since it's handled by the lexState. // if (token.type !== 'punctuator') { // throw invalidToken() // } if (token.type === 'eof') { throw invalidEOF() } switch (token.value) { case ',': parseState = 'beforeArrayValue' return case ']': pop() } // This code is unreachable since it's handled by the lexState. // throw invalidToken() }, end () { // This code is unreachable since it's handled by the lexState. // if (token.type !== 'eof') { // throw invalidToken() // } }, } function push () { let value switch (token.type) { case 'punctuator': switch (token.value) { case '{': value = {} break case '[': value = [] break } break case 'null': case 'boolean': case 'numeric': case 'string': value = token.value break // This code is unreachable. // default: // throw invalidToken() } if (root === undefined) { root = value } else { const parent = stack[stack.length - 1] if (Array.isArray(parent)) { parent.push(value) } else { Object.defineProperty(parent, key, { value, writable: true, enumerable: true, configurable: true, }) } } if (value !== null && typeof value === 'object') { stack.push(value) if (Array.isArray(value)) { parseState = 'beforeArrayValue' } else { parseState = 'beforePropertyName' } } else { const current = stack[stack.length - 1] if (current == null) { parseState = 'end' } else if (Array.isArray(current)) { parseState = 'afterArrayValue' } else { parseState = 'afterPropertyValue' } } } function pop () { stack.pop() const current = stack[stack.length - 1] if (current == null) { parseState = 'end' } else if (Array.isArray(current)) { parseState = 'afterArrayValue' } else { parseState = 'afterPropertyValue' } } // This code is unreachable. // function invalidParseState () { // return new Error(`JSON5: invalid parse state '${parseState}'`) // } // This code is unreachable. // function invalidLexState (state) { // return new Error(`JSON5: invalid lex state '${state}'`) // } function invalidChar (c) { if (c === undefined) { return syntaxError(`JSON5: invalid end of input at ${line}:${column}`) } return syntaxError(`JSON5: invalid character '${formatChar(c)}' at ${line}:${column}`) } function invalidEOF () { return syntaxError(`JSON5: invalid end of input at ${line}:${column}`) } // This code is unreachable. // function invalidToken () { // if (token.type === 'eof') { // return syntaxError(`JSON5: invalid end of input at ${line}:${column}`) // } // const c = String.fromCodePoint(token.value.codePointAt(0)) // return syntaxError(`JSON5: invalid character '${formatChar(c)}' at ${line}:${column}`) // } function invalidIdentifier () { column -= 5 return syntaxError(`JSON5: invalid identifier character at ${line}:${column}`) } function separatorChar (c) { console.warn(`JSON5: '${formatChar(c)}' in strings is not valid ECMAScript; consider escaping`) } function formatChar (c) { const replacements = { "'": "\\'", '"': '\\"', '\\': '\\\\', '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t', '\v': '\\v', '\0': '\\0', '\u2028': '\\u2028', '\u2029': '\\u2029', } if (replacements[c]) { return replacements[c] } if (c < ' ') { const hexString = c.charCodeAt(0).toString(16) return '\\x' + ('00' + hexString).substring(hexString.length) } return c } function syntaxError (message) { const err = new SyntaxError(message) err.lineNumber = line err.columnNumber = column return err } ================================================ FILE: lib/register.js ================================================ const fs = require('fs') const JSON5 = require('./') // eslint-disable-next-line node/no-deprecated-api require.extensions['.json5'] = function (module, filename) { const content = fs.readFileSync(filename, 'utf8') try { module.exports = JSON5.parse(content) } catch (err) { err.message = filename + ': ' + err.message throw err } } ================================================ FILE: lib/require.js ================================================ // This file is for backward compatibility with v0.5.1. require('./register') console.warn("'json5/require' is deprecated. Please use 'json5/register' instead.") ================================================ FILE: lib/stringify.d.ts ================================================ declare type StringifyOptions = { /** * A function that alters the behavior of the stringification process, or an * array of String and Number objects that serve as a allowlist for * selecting/filtering the properties of the value object to be included in * the JSON5 string. If this value is null or not provided, all properties * of the object are included in the resulting JSON5 string. */ replacer?: | ((this: any, key: string, value: any) => any) | (string | number)[] | null /** * A String or Number object that's used to insert white space into the * output JSON5 string for readability purposes. If this is a Number, it * indicates the number of space characters to use as white space; this * number is capped at 10 (if it is greater, the value is just 10). Values * less than 1 indicate that no space should be used. If this is a String, * the string (or the first 10 characters of the string, if it's longer than * that) is used as white space. If this parameter is not provided (or is * null), no white space is used. If white space is used, trailing commas * will be used in objects and arrays. */ space?: string | number | null /** * A String representing the quote character to use when serializing * strings. */ quote?: string | null } /** * Converts a JavaScript value to a JSON5 string. * @param value The value to convert to a JSON5 string. * @param replacer A function that alters the behavior of the stringification * process. If this value is null or not provided, all properties of the object * are included in the resulting JSON5 string. * @param space A String or Number object that's used to insert white space into * the output JSON5 string for readability purposes. If this is a Number, it * indicates the number of space characters to use as white space; this number * is capped at 10 (if it is greater, the value is just 10). Values less than 1 * indicate that no space should be used. If this is a String, the string (or * the first 10 characters of the string, if it's longer than that) is used as * white space. If this parameter is not provided (or is null), no white space * is used. If white space is used, trailing commas will be used in objects and * arrays. * @returns The JSON5 string converted from the JavaScript value. */ declare function stringify( value: any, replacer?: ((this: any, key: string, value: any) => any) | null, space?: string | number | null, ): string /** * Converts a JavaScript value to a JSON5 string. * @param value The value to convert to a JSON5 string. * @param replacer An array of String and Number objects that serve as a * allowlist for selecting/filtering the properties of the value object to be * included in the JSON5 string. If this value is null or not provided, all * properties of the object are included in the resulting JSON5 string. * @param space A String or Number object that's used to insert white space into * the output JSON5 string for readability purposes. If this is a Number, it * indicates the number of space characters to use as white space; this number * is capped at 10 (if it is greater, the value is just 10). Values less than 1 * indicate that no space should be used. If this is a String, the string (or * the first 10 characters of the string, if it's longer than that) is used as * white space. If this parameter is not provided (or is null), no white space * is used. If white space is used, trailing commas will be used in objects and * arrays. * @returns The JSON5 string converted from the JavaScript value. */ declare function stringify( value: any, replacer: (string | number)[], space?: string | number | null, ): string /** * Converts a JavaScript value to a JSON5 string. * @param value The value to convert to a JSON5 string. * @param options An object specifying options. * @returns The JSON5 string converted from the JavaScript value. */ declare function stringify(value: any, options: StringifyOptions): string export = stringify ================================================ FILE: lib/stringify.js ================================================ const util = require('./util') module.exports = function stringify (value, replacer, space) { const stack = [] let indent = '' let propertyList let replacerFunc let gap = '' let quote if ( replacer != null && typeof replacer === 'object' && !Array.isArray(replacer) ) { space = replacer.space quote = replacer.quote replacer = replacer.replacer } if (typeof replacer === 'function') { replacerFunc = replacer } else if (Array.isArray(replacer)) { propertyList = [] for (const v of replacer) { let item if (typeof v === 'string') { item = v } else if ( typeof v === 'number' || v instanceof String || v instanceof Number ) { item = String(v) } if (item !== undefined && propertyList.indexOf(item) < 0) { propertyList.push(item) } } } if (space instanceof Number) { space = Number(space) } else if (space instanceof String) { space = String(space) } if (typeof space === 'number') { if (space > 0) { space = Math.min(10, Math.floor(space)) gap = ' '.substr(0, space) } } else if (typeof space === 'string') { gap = space.substr(0, 10) } return serializeProperty('', {'': value}) function serializeProperty (key, holder) { let value = holder[key] if (value != null) { if (typeof value.toJSON5 === 'function') { value = value.toJSON5(key) } else if (typeof value.toJSON === 'function') { value = value.toJSON(key) } } if (replacerFunc) { value = replacerFunc.call(holder, key, value) } if (value instanceof Number) { value = Number(value) } else if (value instanceof String) { value = String(value) } else if (value instanceof Boolean) { value = value.valueOf() } switch (value) { case null: return 'null' case true: return 'true' case false: return 'false' } if (typeof value === 'string') { return quoteString(value, false) } if (typeof value === 'number') { return String(value) } if (typeof value === 'object') { return Array.isArray(value) ? serializeArray(value) : serializeObject(value) } return undefined } function quoteString (value) { const quotes = { "'": 0.1, '"': 0.2, } const replacements = { "'": "\\'", '"': '\\"', '\\': '\\\\', '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t', '\v': '\\v', '\0': '\\0', '\u2028': '\\u2028', '\u2029': '\\u2029', } let product = '' for (let i = 0; i < value.length; i++) { const c = value[i] switch (c) { case "'": case '"': quotes[c]++ product += c continue case '\0': if (util.isDigit(value[i + 1])) { product += '\\x00' continue } } if (replacements[c]) { product += replacements[c] continue } if (c < ' ') { let hexString = c.charCodeAt(0).toString(16) product += '\\x' + ('00' + hexString).substring(hexString.length) continue } product += c } const quoteChar = quote || Object.keys(quotes).reduce((a, b) => (quotes[a] < quotes[b]) ? a : b) product = product.replace(new RegExp(quoteChar, 'g'), replacements[quoteChar]) return quoteChar + product + quoteChar } function serializeObject (value) { if (stack.indexOf(value) >= 0) { throw TypeError('Converting circular structure to JSON5') } stack.push(value) let stepback = indent indent = indent + gap let keys = propertyList || Object.keys(value) let partial = [] for (const key of keys) { const propertyString = serializeProperty(key, value) if (propertyString !== undefined) { let member = serializeKey(key) + ':' if (gap !== '') { member += ' ' } member += propertyString partial.push(member) } } let final if (partial.length === 0) { final = '{}' } else { let properties if (gap === '') { properties = partial.join(',') final = '{' + properties + '}' } else { let separator = ',\n' + indent properties = partial.join(separator) final = '{\n' + indent + properties + ',\n' + stepback + '}' } } stack.pop() indent = stepback return final } function serializeKey (key) { if (key.length === 0) { return quoteString(key, true) } const firstChar = String.fromCodePoint(key.codePointAt(0)) if (!util.isIdStartChar(firstChar)) { return quoteString(key, true) } for (let i = firstChar.length; i < key.length; i++) { if (!util.isIdContinueChar(String.fromCodePoint(key.codePointAt(i)))) { return quoteString(key, true) } } return key } function serializeArray (value) { if (stack.indexOf(value) >= 0) { throw TypeError('Converting circular structure to JSON5') } stack.push(value) let stepback = indent indent = indent + gap let partial = [] for (let i = 0; i < value.length; i++) { const propertyString = serializeProperty(String(i), value) partial.push((propertyString !== undefined) ? propertyString : 'null') } let final if (partial.length === 0) { final = '[]' } else { if (gap === '') { let properties = partial.join(',') final = '[' + properties + ']' } else { let separator = ',\n' + indent let properties = partial.join(separator) final = '[\n' + indent + properties + ',\n' + stepback + ']' } } stack.pop() indent = stepback return final } } ================================================ FILE: lib/unicode.d.ts ================================================ export declare const Space_Separator: RegExp export declare const ID_Start: RegExp export declare const ID_Continue: RegExp ================================================ FILE: lib/unicode.js ================================================ // This is a generated file. Do not edit. module.exports.Space_Separator = /[\u1680\u2000-\u200A\u202F\u205F\u3000]/ module.exports.ID_Start = /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE83\uDE86-\uDE89\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]/ module.exports.ID_Continue = /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u08D4-\u08E1\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u09FC\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9-\u0AFF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C80-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D00-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D54-\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1CD0-\u1CD2\u1CD4-\u1CF9\u1D00-\u1DF9\u1DFB-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C5\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF2D-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE3E\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC00-\uDC4A\uDC50-\uDC59\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDE00-\uDE3E\uDE47\uDE50-\uDE83\uDE86-\uDE99\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC36\uDC38-\uDC40\uDC50-\uDC59\uDC72-\uDC8F\uDC92-\uDCA7\uDCA9-\uDCB6\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD36\uDD3A\uDD3C\uDD3D\uDD3F-\uDD47\uDD50-\uDD59]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD838[\uDC00-\uDC06\uDC08-\uDC18\uDC1B-\uDC21\uDC23\uDC24\uDC26-\uDC2A]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6\uDD00-\uDD4A\uDD50-\uDD59]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/ ================================================ FILE: lib/util.d.ts ================================================ export declare function isSpaceSeparator(c?: string): boolean export declare function isIdStartChar(c?: string): boolean export declare function isIdContinueChar(c?: string): boolean export declare function isDigit(c?: string): boolean export declare function isHexDigit(c?: string): boolean ================================================ FILE: lib/util.js ================================================ const unicode = require('../lib/unicode') module.exports = { isSpaceSeparator (c) { return typeof c === 'string' && unicode.Space_Separator.test(c) }, isIdStartChar (c) { return typeof c === 'string' && ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c === '$') || (c === '_') || unicode.ID_Start.test(c) ) }, isIdContinueChar (c) { return typeof c === 'string' && ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c === '$') || (c === '_') || (c === '\u200C') || (c === '\u200D') || unicode.ID_Continue.test(c) ) }, isDigit (c) { return typeof c === 'string' && /[0-9]/.test(c) }, isHexDigit (c) { return typeof c === 'string' && /[0-9A-Fa-f]/.test(c) }, } ================================================ FILE: package.json ================================================ { "name": "json5", "version": "2.2.3", "description": "JSON for Humans", "main": "lib/index.js", "module": "dist/index.mjs", "bin": "lib/cli.js", "browser": "dist/index.js", "types": "lib/index.d.ts", "files": [ "lib/", "dist/" ], "engines": { "node": ">=6" }, "scripts": { "build": "rollup -c", "build-package": "node build/package.js", "build-unicode": "node build/unicode.js", "coverage": "tap --coverage-report html test", "lint": "eslint --fix .", "lint-report": "eslint .", "prepublishOnly": "npm run production", "preversion": "npm run production", "production": "run-s test build", "tap": "tap -Rspec --100 test", "test": "run-s lint-report tap", "version": "npm run build-package && git add package.json5" }, "repository": { "type": "git", "url": "git+https://github.com/json5/json5.git" }, "keywords": [ "json", "json5", "es5", "es2015", "ecmascript" ], "author": "Aseem Kishore ", "contributors": [ "Max Nanasy ", "Andrew Eisenberg ", "Jordan Tucker " ], "license": "MIT", "bugs": { "url": "https://github.com/json5/json5/issues" }, "homepage": "http://json5.org/", "devDependencies": { "core-js": "^2.6.5", "eslint": "^5.15.3", "eslint-config-standard": "^12.0.0", "eslint-plugin-import": "^2.16.0", "eslint-plugin-node": "^8.0.1", "eslint-plugin-promise": "^4.0.1", "eslint-plugin-standard": "^4.0.0", "npm-run-all": "^4.1.5", "regenerate": "^1.4.0", "rollup": "^0.64.1", "rollup-plugin-buble": "^0.19.6", "rollup-plugin-commonjs": "^9.2.1", "rollup-plugin-node-resolve": "^3.4.0", "rollup-plugin-terser": "^1.0.1", "sinon": "^6.3.5", "tap": "^12.6.0", "unicode-10.0.0": "^0.7.5" } } ================================================ FILE: package.json5 ================================================ // This is a generated file. Do not edit. { name: 'json5', version: '2.2.3', description: 'JSON for Humans', main: 'lib/index.js', module: 'dist/index.mjs', bin: 'lib/cli.js', browser: 'dist/index.js', types: 'lib/index.d.ts', files: [ 'lib/', 'dist/', ], engines: { node: '>=6', }, scripts: { build: 'rollup -c', 'build-package': 'node build/package.js', 'build-unicode': 'node build/unicode.js', coverage: 'tap --coverage-report html test', lint: 'eslint --fix .', 'lint-report': 'eslint .', prepublishOnly: 'npm run production', preversion: 'npm run production', production: 'run-s test build', tap: 'tap -Rspec --100 test', test: 'run-s lint-report tap', version: 'npm run build-package && git add package.json5', }, repository: { type: 'git', url: 'git+https://github.com/json5/json5.git', }, keywords: [ 'json', 'json5', 'es5', 'es2015', 'ecmascript', ], author: 'Aseem Kishore ', contributors: [ 'Max Nanasy ', 'Andrew Eisenberg ', 'Jordan Tucker ', ], license: 'MIT', bugs: { url: 'https://github.com/json5/json5/issues', }, homepage: 'http://json5.org/', devDependencies: { 'core-js': '^2.6.5', eslint: '^5.15.3', 'eslint-config-standard': '^12.0.0', 'eslint-plugin-import': '^2.16.0', 'eslint-plugin-node': '^8.0.1', 'eslint-plugin-promise': '^4.0.1', 'eslint-plugin-standard': '^4.0.0', 'npm-run-all': '^4.1.5', regenerate: '^1.4.0', rollup: '^0.64.1', 'rollup-plugin-buble': '^0.19.6', 'rollup-plugin-commonjs': '^9.2.1', 'rollup-plugin-node-resolve': '^3.4.0', 'rollup-plugin-terser': '^1.0.1', sinon: '^6.3.5', tap: '^12.6.0', 'unicode-10.0.0': '^0.7.5', }, } ================================================ FILE: rollup.config.js ================================================ const resolve = require('rollup-plugin-node-resolve') const commonjs = require('rollup-plugin-commonjs') const buble = require('rollup-plugin-buble') const terser = require('rollup-plugin-terser').terser const pkg = require('./package.json') module.exports = [ // ES5 Non-minified { input: 'build/es5.js', output: { file: pkg.browser, format: 'umd', name: 'JSON5', }, plugins: [ resolve(), commonjs(), buble({transforms: {dangerousForOf: true}}), ], }, // ES5 Minified { input: 'build/es5.js', output: { file: pkg.browser.replace(/\.js$/, '.min.js'), format: 'umd', name: 'JSON5', }, plugins: [ resolve(), commonjs(), buble({transforms: {dangerousForOf: true}}), terser(), ], }, // ES6 Modules Non-minified { input: 'lib/index.js', output: { file: pkg.browser.replace(/\.js$/, '.mjs'), format: 'esm', }, plugins: [ resolve(), commonjs(), ], }, // ES6 Modules Minified { input: 'lib/index.js', output: { file: pkg.browser.replace(/\.js$/, '.min.mjs'), format: 'esm', }, plugins: [ resolve(), commonjs(), terser(), ], }, ] ================================================ FILE: test/cli.js ================================================ const assert = require('assert') const child = require('child_process') const fs = require('fs') const path = require('path') const pkg = require('../package.json') const cliPath = path.resolve(__dirname, '../lib/cli.js') const t = require('tap') t.test('CLI', t => { t.test('converts JSON5 to JSON from stdin to stdout', t => { const proc = child.spawn(process.execPath, [cliPath]) let output = '' proc.stdout.on('data', data => { output += data }) proc.stdout.on('end', () => { assert.strictEqual(output, '{"a":1,"b":2}') t.end() }) fs.createReadStream(path.resolve(__dirname, 'test.json5')).pipe(proc.stdin) }) t.test('reads from the specified file', t => { const proc = child.spawn( process.execPath, [ cliPath, path.resolve(__dirname, 'test.json5'), ] ) let output = '' proc.stdout.on('data', data => { output += data }) proc.stdout.on('end', () => { assert.strictEqual(output, '{"a":1,"b":2}') t.end() }) }) t.test('indents output with the number of spaces specified with -s', t => { const proc = child.spawn( process.execPath, [ cliPath, path.resolve(__dirname, 'test.json5'), '-s', '4', ] ) let output = '' proc.stdout.on('data', data => { output += data }) proc.stdout.on('end', () => { assert.strictEqual(output, '{\n "a": 1,\n "b": 2\n}') t.end() }) }) t.test('indents output with the number of spaces specified with --space', t => { const proc = child.spawn( process.execPath, [ cliPath, path.resolve(__dirname, 'test.json5'), '--space', '4', ] ) let output = '' proc.stdout.on('data', data => { output += data }) proc.stdout.on('end', () => { assert.strictEqual(output, '{\n "a": 1,\n "b": 2\n}') t.end() }) }) t.test('indents output with tabs when specified with -s', t => { const proc = child.spawn( process.execPath, [ cliPath, path.resolve(__dirname, 'test.json5'), '-s', 't', ] ) let output = '' proc.stdout.on('data', data => { output += data }) proc.stdout.on('end', () => { assert.strictEqual(output, '{\n\t"a": 1,\n\t"b": 2\n}') t.end() }) }) t.test('outputs to the specified file with -o', t => { const proc = child.spawn( process.execPath, [ cliPath, path.resolve(__dirname, 'test.json5'), '-o', path.resolve(__dirname, 'output.json'), ] ) proc.on('exit', () => { assert.strictEqual( fs.readFileSync( path.resolve(__dirname, 'output.json'), 'utf8' ), '{"a":1,"b":2}' ) t.end() }) t.tearDown(() => { try { fs.unlinkSync(path.resolve(__dirname, 'output.json')) } catch (err) {} }) }) t.test('outputs to the specified file with --out-file', t => { const proc = child.spawn( process.execPath, [ cliPath, path.resolve(__dirname, 'test.json5'), '--out-file', path.resolve(__dirname, 'output.json'), ] ) proc.on('exit', () => { assert.strictEqual( fs.readFileSync( path.resolve(__dirname, 'output.json'), 'utf8' ), '{"a":1,"b":2}' ) t.end() }) t.tearDown(() => { try { fs.unlinkSync(path.resolve(__dirname, 'output.json')) } catch (err) {} }) }) t.test('validates valid JSON5 files with -v', t => { const proc = child.spawn( process.execPath, [ cliPath, path.resolve(__dirname, 'test.json5'), '-v', ] ) proc.on('exit', code => { assert.strictEqual(code, 0) t.end() }) }) t.test('validates valid JSON5 files with --validate', t => { const proc = child.spawn( process.execPath, [ cliPath, path.resolve(__dirname, 'test.json5'), '--validate', ] ) proc.on('exit', code => { assert.strictEqual(code, 0) t.end() }) }) t.test('validates invalid JSON5 files with -v', t => { const proc = child.spawn( process.execPath, [ cliPath, path.resolve(__dirname, 'invalid.json5'), '-v', ] ) let error = '' proc.stderr.on('data', data => { error += data }) proc.stderr.on('end', () => { assert.strictEqual(error, "JSON5: invalid character 'a' at 1:1\n") }) proc.on('exit', code => { assert.strictEqual(code, 1) t.end() }) }) t.test('outputs the version number when specified with -V', t => { const proc = child.spawn(process.execPath, [cliPath, '-V']) let output = '' proc.stdout.on('data', data => { output += data }) proc.stdout.on('end', () => { assert.strictEqual(output, pkg.version + '\n') t.end() }) }) t.test('outputs the version number when specified with --version', t => { const proc = child.spawn(process.execPath, [cliPath, '--version']) let output = '' proc.stdout.on('data', data => { output += data }) proc.stdout.on('end', () => { assert.strictEqual(output, pkg.version + '\n') t.end() }) }) t.test('outputs usage information when specified with -h', t => { const proc = child.spawn(process.execPath, [cliPath, '-h']) let output = '' proc.stdout.on('data', data => { output += data }) proc.stdout.on('end', () => { assert(/Usage/.test(output)) t.end() }) }) t.test('outputs usage information when specified with --help', t => { const proc = child.spawn(process.execPath, [cliPath, '--help']) let output = '' proc.stdout.on('data', data => { output += data }) proc.stdout.on('end', () => { assert(/Usage/.test(output)) t.end() }) }) t.test('is backward compatible with v0.5.1 with -c', t => { const proc = child.spawn( process.execPath, [ cliPath, '-c', path.resolve(__dirname, 'test.json5'), ] ) proc.on('exit', () => { assert.strictEqual( fs.readFileSync( path.resolve(__dirname, 'test.json'), 'utf8' ), '{"a":1,"b":2}' ) t.end() }) t.tearDown(() => { try { fs.unlinkSync(path.resolve(__dirname, 'test.json')) } catch (err) {} }) }) t.test('is backward compatible with v0.5.1 with --convert', t => { const proc = child.spawn( process.execPath, [ cliPath, '--convert', path.resolve(__dirname, 'test.json5'), ] ) proc.on('exit', () => { assert.strictEqual( fs.readFileSync( path.resolve(__dirname, 'test.json'), 'utf8' ), '{"a":1,"b":2}' ) t.end() }) t.tearDown(() => { try { fs.unlinkSync(path.resolve(__dirname, 'test.json')) } catch (err) {} }) }) t.end() }) ================================================ FILE: test/errors.js ================================================ const JSON5 = require('../lib') const t = require('tap') t.test('JSON5', t => { t.test('#parse()', t => { t.test('errors', t => { t.throws( () => { JSON5.parse('') }, { message: /^JSON5: invalid end of input/, lineNumber: 1, columnNumber: 1, }, 'throws on empty documents' ) t.throws( () => { JSON5.parse('//a') }, { message: /^JSON5: invalid end of input/, lineNumber: 1, columnNumber: 4, }, 'throws on documents with only comments' ) t.throws( () => { JSON5.parse('/a') }, { message: /^JSON5: invalid character 'a'/, lineNumber: 1, columnNumber: 2, }, 'throws on incomplete single line comments' ) t.throws( () => { JSON5.parse('/*') }, { message: /^JSON5: invalid end of input/, lineNumber: 1, columnNumber: 3, }, 'throws on unterminated multiline comments' ) t.throws( () => { JSON5.parse('/**') }, { message: /^JSON5: invalid end of input/, lineNumber: 1, columnNumber: 4, }, 'throws on unterminated multiline comment closings' ) t.throws( () => { JSON5.parse('a') }, { message: /^JSON5: invalid character 'a'/, lineNumber: 1, columnNumber: 1, }, 'throws on invalid characters in values' ) t.throws( () => { JSON5.parse('{\\a:1}') }, { message: /^JSON5: invalid character 'a'/, lineNumber: 1, columnNumber: 3, }, 'throws on invalid characters in identifier start escapes' ) t.throws( () => { JSON5.parse('{\\u0021:1}') }, { message: /^JSON5: invalid identifier character/, lineNumber: 1, columnNumber: 2, }, 'throws on invalid identifier start characters' ) t.throws( () => { JSON5.parse('{a\\a:1}') }, { message: /^JSON5: invalid character 'a'/, lineNumber: 1, columnNumber: 4, }, 'throws on invalid characters in identifier continue escapes' ) t.throws( () => { JSON5.parse('{a\\u0021:1}') }, { message: /^JSON5: invalid identifier character/, lineNumber: 1, columnNumber: 3, }, 'throws on invalid identifier continue characters' ) t.throws( () => { JSON5.parse('-a') }, { message: /^JSON5: invalid character 'a'/, lineNumber: 1, columnNumber: 2, }, 'throws on invalid characters following a sign' ) t.throws( () => { JSON5.parse('.a') }, { message: /^JSON5: invalid character 'a'/, lineNumber: 1, columnNumber: 2, }, 'throws on invalid characters following a leading decimal point' ) t.throws( () => { JSON5.parse('1ea') }, { message: /^JSON5: invalid character 'a'/, lineNumber: 1, columnNumber: 3, }, 'throws on invalid characters following an exponent indicator' ) t.throws( () => { JSON5.parse('1e-a') }, { message: /^JSON5: invalid character 'a'/, lineNumber: 1, columnNumber: 4, }, 'throws on invalid characters following an exponent sign' ) t.throws( () => { JSON5.parse('0xg') }, { message: /^JSON5: invalid character 'g'/, lineNumber: 1, columnNumber: 3, }, 'throws on invalid characters following a hexadecimal indicator' ) t.throws( () => { JSON5.parse('"\n"') }, { message: /^JSON5: invalid character '\\n'/, lineNumber: 2, columnNumber: 0, }, 'throws on invalid new lines in strings' ) t.throws( () => { JSON5.parse('"') }, { message: /^JSON5: invalid end of input/, lineNumber: 1, columnNumber: 2, }, 'throws on unterminated strings' ) t.throws( () => { JSON5.parse('{!:1}') }, { message: /^JSON5: invalid character '!'/, lineNumber: 1, columnNumber: 2, }, 'throws on invalid identifier start characters in property names' ) t.throws( () => { JSON5.parse('{a!1}') }, { message: /^JSON5: invalid character '!'/, lineNumber: 1, columnNumber: 3, }, 'throws on invalid characters following a property name' ) t.throws( () => { JSON5.parse('{a:1!}') }, { message: /^JSON5: invalid character '!'/, lineNumber: 1, columnNumber: 5, }, 'throws on invalid characters following a property value' ) t.throws( () => { JSON5.parse('[1!]') }, { message: /^JSON5: invalid character '!'/, lineNumber: 1, columnNumber: 3, }, 'throws on invalid characters following an array value' ) t.throws( () => { JSON5.parse('tru!') }, { message: /^JSON5: invalid character '!'/, lineNumber: 1, columnNumber: 4, }, 'throws on invalid characters in literals' ) t.throws( () => { JSON5.parse('"\\') }, { message: /^JSON5: invalid end of input/, lineNumber: 1, columnNumber: 3, }, 'throws on unterminated escapes' ) t.throws( () => { JSON5.parse('"\\xg"') }, { message: /^JSON5: invalid character 'g'/, lineNumber: 1, columnNumber: 4, }, 'throws on invalid first digits in hexadecimal escapes' ) t.throws( () => { JSON5.parse('"\\x0g"') }, { message: /^JSON5: invalid character 'g'/, lineNumber: 1, columnNumber: 5, }, 'throws on invalid second digits in hexadecimal escapes' ) t.throws( () => { JSON5.parse('"\\u000g"') }, { message: /^JSON5: invalid character 'g'/, lineNumber: 1, columnNumber: 7, }, 'throws on invalid unicode escapes' ) for (let i = 1; i <= 9; i++) { t.throws( () => { JSON5.parse(`'\\${i}'`) }, { message: /^JSON5: invalid character '\d'/, lineNumber: 1, columnNumber: 3, }, `throws on escaped digit ${i}` ) } t.throws( () => { JSON5.parse("'\\01'") }, { message: /^JSON5: invalid character '1'/, lineNumber: 1, columnNumber: 4, }, 'throws on octal escapes' ) t.throws( () => { JSON5.parse('1 2') }, { message: /^JSON5: invalid character '2'/, lineNumber: 1, columnNumber: 3, }, 'throws on multiple values' ) t.throws( () => { JSON5.parse('\x01') }, { message: /^JSON5: invalid character '\\x01'/, lineNumber: 1, columnNumber: 1, }, 'throws with control characters escaped in the message' ) t.throws( () => { JSON5.parse('{') }, { message: /^JSON5: invalid end of input/, lineNumber: 1, columnNumber: 2, }, 'throws on unclosed objects before property names' ) t.throws( () => { JSON5.parse('{a') }, { message: /^JSON5: invalid end of input/, lineNumber: 1, columnNumber: 3, }, 'throws on unclosed objects after property names' ) t.throws( () => { JSON5.parse('{a:') }, { message: /^JSON5: invalid end of input/, lineNumber: 1, columnNumber: 4, }, 'throws on unclosed objects before property values' ) t.throws( () => { JSON5.parse('{a:1') }, { message: /^JSON5: invalid end of input/, lineNumber: 1, columnNumber: 5, }, 'throws on unclosed objects after property values' ) t.throws( () => { JSON5.parse('[') }, { message: /^JSON5: invalid end of input/, lineNumber: 1, columnNumber: 2, }, 'throws on unclosed arrays before values' ) t.throws( () => { JSON5.parse('[1') }, { message: /^JSON5: invalid end of input/, lineNumber: 1, columnNumber: 3, }, 'throws on unclosed arrays after values' ) t.end() }) t.end() }) t.end() }) ================================================ FILE: test/invalid.json5 ================================================ a ================================================ FILE: test/parse.js ================================================ const assert = require('assert') const sinon = require('sinon') const JSON5 = require('../lib') const t = require('tap') t.test('parse(text)', t => { t.test('objects', t => { t.strictSame( JSON5.parse('{}'), {}, 'parses empty objects' ) t.strictSame( JSON5.parse('{"a":1}'), {a: 1}, 'parses double string property names' ) t.strictSame( JSON5.parse("{'a':1}"), {a: 1}, 'parses single string property names' ) t.strictSame( JSON5.parse('{a:1}'), {a: 1}, 'parses unquoted property names' ) t.strictSame( JSON5.parse('{$_:1,_$:2,a\u200C:3}'), {$_: 1, _$: 2, 'a\u200C': 3}, 'parses special character property names' ) t.strictSame( JSON5.parse('{ùńîċõďë:9}'), {'ùńîċõďë': 9}, 'parses unicode property names' ) t.strictSame( JSON5.parse('{\\u0061\\u0062:1,\\u0024\\u005F:2,\\u005F\\u0024:3}'), {ab: 1, $_: 2, _$: 3}, 'parses escaped property names' ) t.strictSame( // eslint-disable-next-line no-proto JSON5.parse('{"__proto__":1}').__proto__, 1, 'preserves __proto__ property names' ) t.strictSame( JSON5.parse('{abc:1,def:2}'), {abc: 1, def: 2}, 'parses multiple properties' ) t.strictSame( JSON5.parse('{a:{b:2}}'), {a: {b: 2}}, 'parses nested objects' ) t.end() }) t.test('arrays', t => { t.strictSame( JSON5.parse('[]'), [], 'parses empty arrays' ) t.strictSame( JSON5.parse('[1]'), [1], 'parses array values' ) t.strictSame( JSON5.parse('[1,2]'), [1, 2], 'parses multiple array values' ) t.strictSame( JSON5.parse('[1,[2,3]]'), [1, [2, 3]], 'parses nested arrays' ) t.end() }) t.test('nulls', t => { t.equal( JSON5.parse('null'), null, 'parses nulls' ) t.end() }) t.test('Booleans', t => { t.equal( JSON5.parse('true'), true, 'parses true' ) t.equal( JSON5.parse('false'), false, 'parses false' ) t.end() }) t.test('numbers', t => { t.strictSame( JSON5.parse('[0,0.,0e0]'), [0, 0, 0], 'parses leading zeroes' ) t.strictSame( JSON5.parse('[1,23,456,7890]'), [1, 23, 456, 7890], 'parses integers' ) t.strictSame( JSON5.parse('[-1,+2,-.1,-0]'), [-1, +2, -0.1, -0], 'parses signed numbers' ) t.strictSame( JSON5.parse('[.1,.23]'), [0.1, 0.23], 'parses leading decimal points' ) t.strictSame( JSON5.parse('[1.0,1.23]'), [1, 1.23], 'parses fractional numbers' ) t.strictSame( JSON5.parse('[1e0,1e1,1e01,1.e0,1.1e0,1e-1,1e+1]'), [1, 10, 10, 1, 1.1, 0.1, 10], 'parses exponents' ) t.strictSame( JSON5.parse('[0x1,0x10,0xff,0xFF]'), [1, 16, 255, 255], 'parses hexadecimal numbers' ) t.strictSame( JSON5.parse('[Infinity,-Infinity]'), [Infinity, -Infinity], 'parses signed and unsigned Infinity' ) t.ok( isNaN(JSON5.parse('NaN')), 'parses NaN' ) t.ok( isNaN(JSON5.parse('-NaN')), 'parses signed NaN' ) t.strictSame( JSON5.parse('1'), 1, 'parses 1' ) t.strictSame( JSON5.parse('+1.23e100'), 1.23e100, 'parses +1.23e100' ) t.strictSame( JSON5.parse('0x1'), 0x1, 'parses bare hexadecimal number' ) t.strictSame( JSON5.parse('-0x0123456789abcdefABCDEF'), -0x0123456789abcdefABCDEF, 'parses bare long hexadecimal number' ) t.end() }) t.test('strings', t => { t.equal( JSON5.parse('"abc"'), 'abc', 'parses double quoted strings' ) t.equal( JSON5.parse("'abc'"), 'abc', 'parses single quoted strings' ) t.strictSame( JSON5.parse(`['"',"'"]`), ['"', "'"], 'parses quotes in strings') t.equal( JSON5.parse(`'\\b\\f\\n\\r\\t\\v\\0\\x0f\\u01fF\\\n\\\r\n\\\r\\\u2028\\\u2029\\a\\'\\"'`), `\b\f\n\r\t\v\0\x0f\u01FF\a'"`, // eslint-disable-line no-useless-escape 'parses escaped characters' ) t.test('parses line and paragraph separators with a warning', t => { const mock = sinon.mock(console) mock .expects('warn') .twice() .calledWithMatch('not valid ECMAScript') assert.deepStrictEqual( JSON5.parse("'\u2028\u2029'"), '\u2028\u2029' ) mock.verify() mock.restore() t.end() }) t.end() }) t.test('comments', t => { t.strictSame( JSON5.parse('{//comment\n}'), {}, 'parses single-line comments' ) t.strictSame( JSON5.parse('{}//comment'), {}, 'parses single-line comments at end of input' ) t.strictSame( JSON5.parse('{/*comment\n** */}'), {}, 'parses multi-line comments' ) t.end() }) t.test('whitespace', t => { t.strictSame( JSON5.parse('{\t\v\f \u00A0\uFEFF\n\r\u2028\u2029\u2003}'), {}, 'parses whitespace' ) t.end() }) t.end() }) t.test('parse(text, reviver)', t => { t.strictSame( JSON5.parse('{a:1,b:2}', (k, v) => (k === 'a') ? 'revived' : v), {a: 'revived', b: 2}, 'modifies property values' ) t.strictSame( JSON5.parse('{a:{b:2}}', (k, v) => (k === 'b') ? 'revived' : v), {a: {b: 'revived'}}, 'modifies nested object property values' ) t.strictSame( JSON5.parse('{a:1,b:2}', (k, v) => (k === 'a') ? undefined : v), {b: 2}, 'deletes property values' ) t.strictSame( JSON5.parse('[0,1,2]', (k, v) => (k === '1') ? 'revived' : v), [0, 'revived', 2], 'modifies array values' ) t.strictSame( JSON5.parse('[0,[1,2,3]]', (k, v) => (k === '2') ? 'revived' : v), [0, [1, 2, 'revived']], 'modifies nested array values' ) t.strictSame( JSON5.parse('[0,1,2]', (k, v) => (k === '1') ? undefined : v), [0, , 2], // eslint-disable-line no-sparse-arrays 'deletes array values' ) t.equal( JSON5.parse('1', (k, v) => (k === '') ? 'revived' : v), 'revived', 'modifies the root value' ) t.strictSame( JSON5.parse('{a:{b:2}}', function (k, v) { return (k === 'b' && this.b) ? 'revived' : v }), {a: {b: 'revived'}}, 'sets `this` to the parent value' ) t.end() }) ================================================ FILE: test/require.js ================================================ const assert = require('assert') const sinon = require('sinon') const t = require('tap') t.test('require(*.json5)', t => { t.test('parses a JSON5 document', t => { require('../lib/register') assert.deepStrictEqual({a: 1, b: 2}, require('./test.json5')) t.end() }) t.test('is backward compatible with v0.5.1, but gives a deprecation warning', t => { const mock = sinon.mock(console) mock.expects('warn').once().withExactArgs("'json5/require' is deprecated. Please use 'json5/register' instead.") require('../lib/require') assert.deepStrictEqual({a: 1, b: 2}, require('./test.json5')) mock.verify() t.end() }) t.test('throws on invalid JSON5', t => { require('../lib/register') assert.throws(() => { require('./invalid.json5') }, SyntaxError) t.end() }) t.end() }) ================================================ FILE: test/stringify.js ================================================ const assert = require('assert') const JSON5 = require('../lib') const t = require('tap') t.test('JSON5', t => { t.test('#stringify', t => { t.test('objects', t => { t.strictSame( JSON5.stringify({}), '{}', 'stringifies empty objects' ) t.strictSame( JSON5.stringify({a: 1}), '{a:1}', 'stringifies unquoted property names' ) t.strictSame( JSON5.stringify({'a-b': 1}), "{'a-b':1}", 'stringifies single quoted string property names' ) t.strictSame( JSON5.stringify({"a'": 1}), `{"a'":1}`, 'stringifies double quoted string property names' ) t.strictSame( JSON5.stringify({'': 1}), "{'':1}", 'stringifies empty string property names' ) t.strictSame( JSON5.stringify({$_: 1, _$: 2, 'a\u200C': 3}), '{$_:1,_$:2,a\u200C:3}', 'stringifies special character property names' ) t.strictSame( JSON5.stringify({'ùńîċõďë': 9}), '{ùńîċõďë:9}', 'stringifies unicode property names' ) t.strictSame( JSON5.stringify({'\\\b\f\n\r\t\v\0\x01': 1}), "{'\\\\\\b\\f\\n\\r\\t\\v\\0\\x01':1}", 'stringifies escaped property names' ) t.strictSame( JSON5.stringify({'\0\x001': 1}), "{'\\0\\x001':1}", 'stringifies escaped null character property names' ) t.strictSame( JSON5.stringify({abc: 1, def: 2}), '{abc:1,def:2}', 'stringifies multiple properties' ) t.strictSame( JSON5.stringify({a: {b: 2}}), '{a:{b:2}}', 'stringifies nested objects' ) t.end() }) t.test('arrays', t => { t.strictSame( JSON5.stringify([]), '[]', 'stringifies empty arrays' ) t.strictSame( JSON5.stringify([1]), '[1]', 'stringifies array values' ) t.strictSame( JSON5.stringify([1, 2]), '[1,2]', 'stringifies multiple array values' ) t.strictSame( JSON5.stringify([1, [2, 3]]), '[1,[2,3]]', 'stringifies nested arrays' ) t.end() }) t.strictSame( JSON5.stringify(null), 'null', 'stringifies nulls' ) t.strictSame( JSON5.stringify(() => {}), undefined, 'returns undefined for functions' ) t.strictSame( JSON5.stringify({a () {}}), '{}', 'ignores function properties' ) t.strictSame( JSON5.stringify([() => {}]), '[null]', 'returns null for functions in arrays' ) t.test('Booleans', t => { t.strictSame( JSON5.stringify(true), 'true', 'stringifies true' ) t.strictSame( JSON5.stringify(false), 'false', 'stringifies false' ) t.strictSame( // eslint-disable-next-line no-new-wrappers JSON5.stringify(new Boolean(true)), 'true', 'stringifies true Boolean objects' ) t.strictSame( // eslint-disable-next-line no-new-wrappers JSON5.stringify(new Boolean(false)), 'false', 'stringifies false Boolean objects' ) t.end() }) t.test('numbers', t => { t.strictSame( JSON5.stringify(-1.2), '-1.2', 'stringifies numbers' ) t.strictSame( JSON5.stringify([Infinity, -Infinity, NaN]), '[Infinity,-Infinity,NaN]', 'stringifies non-finite numbers' ) t.strictSame( // eslint-disable-next-line no-new-wrappers JSON5.stringify(new Number(-1.2)), '-1.2', 'stringifies Number objects' ) t.end() }) t.test('strings', t => { t.strictSame( JSON5.stringify('abc'), "'abc'", 'stringifies single quoted strings' ) t.strictSame( JSON5.stringify("abc'"), `"abc'"`, 'stringifies double quoted strings' ) t.strictSame( JSON5.stringify('\\\b\f\n\r\t\v\0\x0f'), "'\\\\\\b\\f\\n\\r\\t\\v\\0\\x0f'", 'stringifies escaped characters' ) t.strictSame( JSON5.stringify('\0\x001'), "'\\0\\x001'", 'stringifies escaped null characters' ) t.strictSame( JSON5.stringify(`'"`), `'\\'"'`, 'stringifies escaped single quotes' ) t.strictSame( JSON5.stringify(`''"`), `"''\\""`, 'stringifies escaped double quotes' ) t.strictSame( JSON5.stringify('\u2028\u2029'), "'\\u2028\\u2029'", 'stringifies escaped line and paragraph separators' ) t.strictSame( // eslint-disable-next-line no-new-wrappers JSON5.stringify(new String('abc')), "'abc'", 'stringifies String objects' ) t.end() }) t.strictSame( JSON5.stringify(new Date('2016-01-01T00:00:00.000Z')), "'2016-01-01T00:00:00.000Z'", 'stringifies using built-in toJSON methods' ) t.test('stringifies using user defined toJSON methods', t => { function C () {} Object.assign(C.prototype, {toJSON () { return {a: 1, b: 2} }}) assert.strictEqual(JSON5.stringify(new C()), '{a:1,b:2}') t.end() }) t.test('stringifies using user defined toJSON(key) methods', t => { function C () {} Object.assign(C.prototype, {toJSON (key) { return (key === 'a') ? 1 : 2 }}) assert.strictEqual(JSON5.stringify({a: new C(), b: new C()}), '{a:1,b:2}') t.end() }) t.test('stringifies using toJSON5 methods', t => { function C () {} Object.assign(C.prototype, {toJSON5 () { return {a: 1, b: 2} }}) assert.strictEqual(JSON5.stringify(new C()), '{a:1,b:2}') t.end() }) t.test('stringifies using toJSON5(key) methods', t => { function C () {} Object.assign(C.prototype, {toJSON5 (key) { return (key === 'a') ? 1 : 2 }}) assert.strictEqual(JSON5.stringify({a: new C(), b: new C()}), '{a:1,b:2}') t.end() }) t.test('calls toJSON5 instead of toJSON if both are defined', t => { function C () {} Object.assign(C.prototype, { toJSON () { return {a: 1, b: 2} }, toJSON5 () { return {a: 2, b: 2} }, }) assert.strictEqual(JSON5.stringify(new C()), '{a:2,b:2}') t.end() }) t.test('throws on circular objects', t => { let a = {} a.a = a assert.throws(() => { JSON5.stringify(a) }, TypeError, 'Converting circular structure to JSON5') t.end() }) t.test('throws on circular arrays', t => { let a = [] a[0] = a assert.throws(() => { JSON5.stringify(a) }, TypeError, 'Converting circular structure to JSON5') t.end() }) t.end() }) t.test('#stringify(value, null, space)', t => { t.strictSame( JSON5.stringify([1]), '[1]', 'does not indent when no value is provided' ) t.strictSame( JSON5.stringify([1], null, 0), '[1]', 'does not indent when 0 is provided' ) t.strictSame( JSON5.stringify([1], null, ''), '[1]', 'does not indent when an empty string is provided' ) t.strictSame( JSON5.stringify([1], null, 2), '[\n 1,\n]', 'indents n spaces when a number is provided' ) t.strictSame( JSON5.stringify([1], null, 11), '[\n 1,\n]', 'does not indent more than 10 spaces when a number is provided' ) t.strictSame( JSON5.stringify([1], null, '\t'), '[\n\t1,\n]', 'indents with the string provided' ) t.strictSame( JSON5.stringify([1], null, ' '), '[\n 1,\n]', 'does not indent more than 10 characters of the string provided' ) t.strictSame( JSON5.stringify([1], null, 2), '[\n 1,\n]', 'indents in arrays' ) t.strictSame( JSON5.stringify([1, [2], 3], null, 2), '[\n 1,\n [\n 2,\n ],\n 3,\n]', 'indents in nested arrays' ) t.strictSame( JSON5.stringify({a: 1}, null, 2), '{\n a: 1,\n}', 'indents in objects' ) t.strictSame( JSON5.stringify({a: {b: 2}}, null, 2), '{\n a: {\n b: 2,\n },\n}', 'indents in nested objects' ) t.strictSame( // eslint-disable-next-line no-new-wrappers JSON5.stringify([1], null, new Number(2)), '[\n 1,\n]', 'accepts Number objects' ) t.strictSame( // eslint-disable-next-line no-new-wrappers JSON5.stringify([1], null, new String('\t')), '[\n\t1,\n]', 'accepts String objects' ) t.end() }) t.test('#stringify(value, replacer)', t => { t.strictSame( JSON5.stringify({a: 1, b: 2, 3: 3}, ['a', 3]), "{a:1,'3':3}", 'filters keys when an array is provided' ) t.strictSame( JSON5.stringify({a: 1, b: 2, 3: 3, false: 4}, ['a', 3, false]), "{a:1,'3':3}", 'only filters string and number keys when an array is provided' ) t.strictSame( // eslint-disable-next-line no-new-wrappers JSON5.stringify({a: 1, b: 2, 3: 3}, [new String('a'), new Number(3)]), "{a:1,'3':3}", 'accepts String and Number objects when an array is provided' ) t.strictSame( JSON5.stringify({a: 1, b: 2}, (key, value) => (key === 'a') ? 2 : value), '{a:2,b:2}', 'replaces values when a function is provided' ) t.strictSame( JSON5.stringify({a: {b: 1}}, function (k, v) { return (k === 'b' && this.b) ? 2 : v }), '{a:{b:2}}', 'sets `this` to the parent value' ) t.test('is called after toJSON', t => { function C () {} Object.assign(C.prototype, {toJSON () { return {a: 1, b: 2} }}) assert.strictEqual( JSON5.stringify(new C(), (key, value) => (key === 'a') ? 2 : value), '{a:2,b:2}' ) t.end() }) t.test('is called after toJSON5', t => { function C () {} Object.assign(C.prototype, {toJSON5 () { return {a: 1, b: 2} }}) assert.strictEqual( JSON5.stringify(new C(), (key, value) => (key === 'a') ? 2 : value), '{a:2,b:2}' ) t.end() }) t.strictSame( JSON5.stringify( {a: 1}, (key, value) => { JSON5.stringify({}, null, 4) return value }, 2 ), '{\n a: 1,\n}', 'does not affect space when calls are nested' ) t.end() }) t.test('#stringify(value, options)', t => { t.strictSame( JSON5.stringify({a: 1, b: 2, 3: 3}, {replacer: ['a', 3]}), "{a:1,'3':3}", 'accepts replacer as an option' ) t.strictSame( JSON5.stringify([1], {space: 2}), '[\n 1,\n]', 'accepts space as an option' ) t.end() }) t.test('#stringify(value, {quote})', t => { t.strictSame( JSON5.stringify({'a"': '1"'}, {quote: '"'}), '{"a\\"":"1\\""}', 'uses double quotes if provided' ) t.strictSame( JSON5.stringify({"a'": "1'"}, {quote: "'"}), "{'a\\'':'1\\''}", 'uses single quotes if provided' ) t.end() }) t.end() }) ================================================ FILE: test/test.json5 ================================================ {a: 1, b: 2}