Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'release/0.1.0'

  • Loading branch information...
commit 296eac57522978ccf32dc55708427accbefed988 2 parents 51a4922 + b14c528
@aseemk authored
Showing with 548 additions and 131 deletions.
  1. +2 −0  .gitignore
  2. +56 −0 CHANGELOG.md
  3. +27 −0 Makefile
  4. +70 −22 README.md
  5. +41 −0 lib/cli.js
  6. +66 −43 { → lib}/json5.js
  7. +18 −0 lib/require.js
  8. +0 −19 package.json
  9. +24 −0 package.json5
  10. 0  test/{cases/empty-array.json5 → parse-cases/arrays/empty-array.json}
  11. 0  test/{cases/leading-comma-array.json5 → parse-cases/arrays/leading-comma-array.js}
  12. 0  test/{cases/lone-trailing-comma-array.json5 → parse-cases/arrays/lone-trailing-comma-array.js}
  13. 0  test/{cases/no-comma-array.json5 → parse-cases/arrays/no-comma-array.txt}
  14. 0  test/{cases/regular-array.json5 → parse-cases/arrays/regular-array.json}
  15. 0  test/{cases → parse-cases/arrays}/trailing-comma-array.json5
  16. 0  test/{cases → parse-cases/comments}/block-comment-following-array-element.json5
  17. 0  test/{cases → parse-cases/comments}/block-comment-following-top-level-value.json5
  18. 0  test/{cases/block-comment-in-string.json5 → parse-cases/comments/block-comment-in-string.json}
  19. 0  test/{cases → parse-cases/comments}/block-comment-preceding-top-level-value.json5
  20. 0  test/{cases → parse-cases/comments}/block-comment-with-asterisks.json5
  21. 0  test/{cases → parse-cases/comments}/inline-comment-following-array-element.json5
  22. 0  test/{cases → parse-cases/comments}/inline-comment-following-top-level-value.json5
  23. 0  test/{cases/inline-comment-in-string.json5 → parse-cases/comments/inline-comment-in-string.json}
  24. 0  test/{cases → parse-cases/comments}/inline-comment-preceding-top-level-value.json5
  25. 0  test/{cases/top-level-block-comment.json5 → parse-cases/comments/top-level-block-comment.txt}
  26. 0  test/{cases/top-level-inline-comment.json5 → parse-cases/comments/top-level-inline-comment.txt}
  27. 0  test/{cases/unterminated-block-comment.json5 → parse-cases/comments/unterminated-block-comment.txt}
  28. 0  test/{cases/empty.json5 → parse-cases/misc/empty.txt}
  29. 0  test/{cases → parse-cases/misc}/npm-package.json
  30. +106 −0 test/parse-cases/misc/npm-package.json5
  31. +3 −0  test/{cases/all-features.json5 → parse-cases/misc/readme-example.json5}
  32. +1 −0  test/parse-cases/numbers/decimal-literal-with-exponent.json
  33. +1 −0  test/parse-cases/numbers/decimal-literal-with-negative-exponent.json
  34. +1 −0  test/parse-cases/numbers/decimal-literal.json
  35. +1 −0  test/parse-cases/numbers/hexadecimal-literal-with-lowercase-letter.json5
  36. +1 −0  test/parse-cases/numbers/hexadecimal-literal-with-no-digits.txt
  37. +1 −0  test/parse-cases/numbers/hexadecimal-literal-with-uppercase-x.json5
  38. +1 −0  test/parse-cases/numbers/hexadecimal-literal.json5
  39. +1 −0  test/parse-cases/numbers/leading-decimal-point.json5
  40. +1 −0  test/parse-cases/numbers/negative-decimal-literal.json
  41. +1 −0  test/parse-cases/numbers/negative-hexadecimal-literal.json5
  42. +1 −0  test/parse-cases/numbers/negative-leading-decimal-point.json5
  43. +1 −0  test/parse-cases/numbers/noctal-literal-with-octal-digit-after-leading-zero.js
  44. +1 −0  test/parse-cases/numbers/noctal-literal.js
  45. +1 −0  test/parse-cases/numbers/octal-literal.txt
  46. +1 −0  test/parse-cases/numbers/trailing-decimal-point-with-exponent.js
  47. +1 −0  test/parse-cases/numbers/trailing-decimal-point.js
  48. +1 −0  test/parse-cases/numbers/zero-literal.json
  49. 0  test/{cases/empty-object.json5 → parse-cases/objects/empty-object.json}
  50. 0  test/{cases/illegal-unquoted-key-number.json5 → parse-cases/objects/illegal-unquoted-key-number.txt}
  51. 0  test/{cases/illegal-unquoted-key-symbol.json5 → parse-cases/objects/illegal-unquoted-key-symbol.txt}
  52. 0  test/{cases/leading-comma-object.json5 → parse-cases/objects/leading-comma-object.txt}
  53. 0  test/{cases/lone-trailing-comma-object.json5 → parse-cases/objects/lone-trailing-comma-object.txt}
  54. 0  test/{cases/no-comma-object.json5 → parse-cases/objects/no-comma-object.txt}
  55. 0  test/{cases → parse-cases/objects}/reserved-unquoted-key.json5
  56. 0  test/{cases → parse-cases/objects}/single-quoted-key.json5
  57. 0  test/{cases → parse-cases/objects}/trailing-comma-object.json5
  58. 0  test/{cases → parse-cases/objects}/unquoted-keys.json5
  59. 0  test/{cases/escape-single-quoted-string.json5 → parse-cases/strings/escaped-single-quoted-string.json5}
  60. 0  test/{cases → parse-cases/strings}/multi-line-string.json5
  61. 0  test/{cases → parse-cases/strings}/single-quoted-string.json5
  62. +3 −0  test/parse-cases/todo/unicode-escaped-unquoted-key.json5
  63. 0  test/{cases-todo → parse-cases/todo}/unicode-unquoted-key.json5
  64. +74 −0 test/parse.js
  65. +23 −0 test/readme.md
  66. +18 −0 test/require.js
  67. +0 −47 test/via-eval.js
View
2  .gitignore
@@ -1,2 +1,4 @@
node_modules
npm-debug.log
+
+package.json
View
56 CHANGELOG.md
@@ -0,0 +1,56 @@
+### v0.1.0 [[code][c0.1.0], [diff][d0.1.0]]
+
+[c0.1.0]: https://github.com/aseemk/json5/tree/v0.1.0
+[d0.1.0]: https://github.com/aseemk/json5/compare/v0.0.1...v0.1.0
+
+This release tightens JSON5 support and adds helpful utility features:
+
+- Support hexadecimal numbers. (Thanks [@MaxNanasy][].)
+
+- 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][].)
+
+- 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.
+
+- Throw proper `SyntaxError` instances on errors now.
+
+- Add Node.js `require()` hook. Require `json5/lib/require` to register it.
+
+- Add Node.js executable to compile JSON5 files to JSON. Run with `json5`.
+
+### v0.0.1 [[code][c0.0.1], [diff][d0.0.1]]
+
+[c0.0.1]: https://github.com/aseemk/json5/tree/v0.0.1
+[d0.0.1]: https://github.com/aseemk/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 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/aseemk/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
+
+[@MaxNanasy]: https://github.com/MaxNanasy
View
27 Makefile
@@ -0,0 +1,27 @@
+all: install
+
+clean:
+ $(call clean)
+
+install: package
+ @npm install
+ $(call clean)
+
+link: package
+ @npm link
+ $(call clean)
+
+package:
+ @./lib/cli.js -c package.json5
+
+publish: package
+ @npm publish
+ $(call clean)
+
+test: package
+ @npm test || : # don't fail on test errors; TODO still fail after clean?
+ $(call clean)
+
+# Helpers:
+
+clean = @rm -f package.json
View
92 README.md
@@ -1,37 +1,50 @@
# JSON5 – Modern JSON
-JSON is strict. Keys need to be quoted; strings can only be double-quoted;
-objects and arrays can't have trailing commas; and comments aren't allowed.
+JSON isn't the friendliest to write and maintain by hand. Keys need to be
+quoted; objects and arrays can't have trailing commas; comments aren't
+supported — even though none of these is the case with regular JavaScript
+today.
-Using such a strict subset of "JavaScript object notation" was likely for the
-best at the time, but with modern ECMAScript 5 engines like V8 in Chrome and
-Node, these limitations are cumbersome.
+Restricting JSON to such a strict subset of "JavaScript object notation" made
+sense for making it a great data-exchange format, but JSON's usage has
+expanded [beyond][ex1] [machine-to-machine][ex2] [communication][ex3].
-JSON5 does for JSON what ES5 did for ES3. It also is to regular ES5 what JSON
-was to ES3 — a pure subset.
+[ex1]: http://plovr.com/docs.html
+[ex2]: http://npmjs.org/doc/json.html
+[ex3]: http://code.google.com/p/fuzztester/wiki/JSONFileFormat
-This module provides a replacement for ES5's native `JSON.parse()` method that
-understands these additions. The parser is based directly off of Douglas
-Crockford's [json_parse.js][], which avoids `eval()` and validates input as it
-parses it, making it secure and safe to use today.
+**JSON5 is a proposed extension to JSON** that brings ES5 enhancements to its
+syntax. It remains a **strict subset of JavaScript**, adds **no new data
+types**, and is a **strict superset of existing JSON**.
+
+JSON5 is not an official successor to JSON, and existing JSON parsers may not
+understand these new features. It's thus recommended that files use a new
+extension like `.json5` to be explicit. *[TODO: New MIME type too?]*
+
+This module provides a JavaScript implementation that works on all modern JS
+engines (even IE6). Its parser is based directly off of Douglas Crockford's
+eval-free [json_parse.js][], making it both secure and robust. Give it a try!
## Features
-- Object keys don't need to be quoted if they contain no special characters.
- Yes, even reserved keywords are valid unquoted keys in ES5.
+These are the new features of JSON5's syntax. All of these are optional, and
+all of these are part of ES5 JavaScript.
- *[TODO: Unicode characters and escape sequences aren't yet supported in
- unquoted keys.]*
+- Object keys don't need to be quoted if they're valid [identifiers](
+ https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Core_Language_Features#Variables). Yes, even reserved keywords are valid unquoted keys in ES5 [[§11.1.5](http://es5.github.com/#x11.1.5), [§7.6](http://es5.github.com/#x7.6)].
+ *[TODO: Unicode characters and escape sequences aren't yet supported in this implementation.]*
- Strings can be single-quoted.
-- Strings can be multi-line; just prefix the newline with a backslash.
+- Strings can be split across multiple lines; just prefix each newline with a
+ backslash. [ES5 [§7.8.4](http://es5.github.com/#x7.8.4)]
- Objects and arrays can have trailing commas.
- Both inline (single-line) and block (multi-line) comments are allowed.
-- *[IDEA: Allow octal and hexadecimal numbers.]*
+- Numbers can be hexadecimal (base 16), and they can also begin with a leading
+ decimal (e.g. `.5`).
## Example
@@ -47,11 +60,14 @@ parses it, making it secure and safe to use today.
here: 'is another', // inline comment
/* this is a block comment
- it continues on another line */
+ that continues on another line */
+
+ hex: 0xDEADbeef,
+ half: .5,
finally: 'a trailing comma',
oh: [
- 'we shouldn\'t forget',
+ "we shouldn't forget",
'arrays can have',
'trailing commas too',
],
@@ -88,25 +104,54 @@ console.log(str);
`JSON5.stringify()` is currently aliased to the native `JSON.stringify()` in
order for the output to be fully compatible with all JSON parsers today.
+If you're running Node, you can also register a JSON5 `require()` hook to let
+you `require()` `.json5` files just like you can `.json` files:
+
+```js
+require('json5/lib/require');
+require('./path/to/foo'); // tries foo.json5 after foo.js, foo.json, etc.
+require('./path/to/bar.json5');
+```
+
+This module also provides a `json5` executable (requires Node) for converting
+JSON5 files to sibling JSON files:
+
+```
+$ json5 -c path/to/foo.json5 # generates path/to/foo.json
+```
+
## Development
```
git clone git://github.com/aseemk/json5.git
cd json5
-npm link
+make
+make test
+```
+
+If your system doesn't have Make, this should work in place of `make [test]`:
+
+```
+./lib/cli.js -c package.json5
+npm install
npm test
```
+Make is used to auto-generate the package.json file that npm requires from our
+package.json5 file. Just re-run `make` (or `./lib/cli.js -c package.json5`) on
+changes to package.json5.
+
Feel free to [file issues](https://github.com/aseemk/json5/issues) and submit
[pull requests](https://github.com/aseemk/json5/pulls) — contributions are
welcome.
If you submit a pull request, please be sure to add or update corresponding
-test cases, and ensure that `npm test` continues to pass.
+test cases, and ensure that `make test` (or `npm test`) continues to pass.
## License
-MIT License. © 2012 Aseem Kishore.
+MIT License. © 2012 Aseem Kishore, and [others](
+https://github.com/aseemk/json5/contributors).
## Credits
@@ -123,3 +168,6 @@ This code is also modeled directly off of Doug's open-source [json_parse.js][]
parser. I'm super grateful for that clean and well-documented code.
[json_parse.js]: https://github.com/douglascrockford/JSON-js/blob/master/json_parse.js
+
+[Max Nanasy](https://github.com/MaxNanasy) has been an early and prolific
+supporter, contributing multiple patches and ideas. Thanks Max!
View
41 lib/cli.js
@@ -0,0 +1,41 @@
+#!/usr/bin/env node
+
+// cli.js
+// JSON5 command-line interface.
+//
+// This is pretty minimal for now; just supports compiling files via `-c`.
+// TODO More useful functionality, like output path, watch, etc.?
+
+var FS = require('fs');
+var JSON5 = require('./json5');
+var Path = require('path');
+
+var USAGE = [
+ 'Usage: json5 -c path/to/file.json5 ...',
+ 'Compiles JSON5 files into sibling JSON files with the same basenames.',
+].join('\n');
+
+// if valid, args look like [node, json5, -c, file1, file2, ...]
+var args = process.argv;
+
+if (args.length < 4 || args[2] !== '-c') {
+ console.error(USAGE);
+ process.exit(1);
+}
+
+var cwd = process.cwd();
+var files = args.slice(3);
+
+// iterate over each file and convert JSON5 files to JSON:
+files.forEach(function (file) {
+ var path = Path.resolve(cwd, file);
+ var basename = Path.basename(path, '.json5');
+ var dirname = Path.dirname(path);
+
+ var json5 = FS.readFileSync(path, 'utf8');
+ var obj = JSON5.parse(json5);
+ var json = JSON.stringify(obj, null, 4); // 4 spaces; TODO configurable?
+
+ path = Path.join(dirname, basename + '.json');
+ FS.writeFileSync(path, json, 'utf8');
+});
View
109 json5.js → lib/json5.js
@@ -1,7 +1,7 @@
// json5.js
// Modern JSON. See README.md for details.
//
-// This file is modeled directly off of Douglas Crockford's json_parse.js:
+// This file is based directly off of Douglas Crockford's json_parse.js:
// https://github.com/douglascrockford/JSON-js/blob/master/json_parse.js
var JSON5 = (typeof exports === 'object' ? exports : {});
@@ -24,7 +24,7 @@ JSON5.parse = (function () {
'"': '"',
'\\': '\\',
'/': '/',
- '\n': '', // Replace newlines in strings w/ empty string
+ '\n': '', // Replace escaped newlines in strings w/ empty string
b: '\b',
f: '\f',
n: '\n',
@@ -37,12 +37,11 @@ JSON5.parse = (function () {
// Call error when something is wrong.
- throw {
- name: 'SyntaxError',
- message: m,
- at: at,
- text: text
- };
+ var error = new SyntaxError();
+ error.message = m;
+ error.at = at;
+ error.text = text;
+ throw error;
},
next = function (c) {
@@ -74,12 +73,18 @@ JSON5.parse = (function () {
var key = ch;
// Identifiers must start with a letter, _ or $.
- if (!ch.match(/^[a-zA-Z_$]$/)) {
+ if ((ch !== '_' && ch !== '$') &&
+ (ch < 'a' || ch > 'z') &&
+ (ch < 'A' || ch > 'Z')) {
error("Bad identifier");
}
// Subsequent characters can contain digits.
- while (next() && ch.match(/^[\w$]$/)) {
+ while (next() && (
+ ch === '_' || ch === '$' ||
+ (ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z') ||
+ (ch >= '0' && ch <= '9'))) {
key += ch;
}
@@ -91,33 +96,60 @@ JSON5.parse = (function () {
// Parse a number value.
var number,
- string = '';
+ string = '',
+ base = 10;
if (ch === '-') {
string = '-';
next('-');
}
- while (ch >= '0' && ch <= '9') {
+ if (ch === '0') {
string += ch;
next();
- }
- if (ch === '.') {
- string += '.';
- while (next() && ch >= '0' && ch <= '9') {
+ if (ch === 'x' || ch === 'X') {
string += ch;
+ next();
+ base = 16;
+ } else if (ch >= '0' && ch <= '9') {
+ error('Octal literal');
}
}
- if (ch === 'e' || ch === 'E') {
- string += ch;
- next();
- if (ch === '-' || ch === '+') {
+ switch (base) {
+ case 10:
+ while (ch >= '0' && ch <= '9' ) {
+ string += ch;
+ next();
+ }
+ if (ch === '.') {
+ string += '.';
+ next('.');
+ if (ch < '0' || ch > '9') {
+ error('Trailing decimal point');
+ }
+ do {
+ string += ch;
+ next();
+ } while (ch && ch >= '0' && ch <= '9');
+ }
+ if (ch === 'e' || ch === 'E') {
string += ch;
next();
+ if (ch === '-' || ch === '+') {
+ string += ch;
+ next();
+ }
+ while (ch >= '0' && ch <= '9') {
+ string += ch;
+ next();
+ }
}
- while (ch >= '0' && ch <= '9') {
+ break;
+ case 16:
+ while (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'F' || ch >= 'a' && ch <= 'f') {
string += ch;
next();
}
+ break;
}
number = +string;
if (!isFinite(number)) {
@@ -137,7 +169,7 @@ JSON5.parse = (function () {
delim, // double quote or single quote
uffff;
-// When parsing for string values, we must look for " and \ characters.
+// When parsing for string values, we must look for ' or " and \ characters.
if (ch === '"' || ch === "'") {
delim = ch;
@@ -172,9 +204,9 @@ JSON5.parse = (function () {
inlineComment = function () {
-// Skip inline comments, assuming this is one. The current character should be
-// the second / character in the // pair that begins this inline comment.
-// When parsing inline comments, we look for a newline or the end of the text.
+// Skip an inline comment, assuming this is one. The current character should
+// be the second / character in the // pair that begins this inline comment.
+// To finish the inline comment, we look for a newline or the end of the text.
if (ch !== '/') {
error("Not an inline comment");
@@ -191,9 +223,9 @@ JSON5.parse = (function () {
blockComment = function () {
-// Skip block comments, assuming this is one. The current character should be
+// Skip a block comment, assuming this is one. The current character should be
// the * character in the /* pair that begins this block comment.
-// When parsing block comments, we look for an ending */ pair of characters,
+// To finish the block comment, we look for an ending */ pair of characters,
// but we also watch for the end of text before the comment is terminated.
if (ch !== '*') {
@@ -216,8 +248,8 @@ JSON5.parse = (function () {
comment = function () {
-// Skip comments, both inline and block-level, assuming this is one. Comments
-// always begin with a / character.
+// Skip a comment, whether inline or block-level, assuming this is one.
+// Comments always begin with a / character.
if (ch !== '/') {
error("Not a comment");
@@ -296,21 +328,12 @@ JSON5.parse = (function () {
next(']');
return array; // Potentially empty array
}
- // Omitted values are allowed and detected by the presence
- // of a trailing comma. Whether the value was omitted or
- // not, the current character after this block should be
- // the character after the value.
+ // ES5 allows omitting elements in arrays, e.g. [,] and
+ // [,null]. We don't allow this in JSON5.
if (ch === ',') {
- // Pushing an undefined value isn't quite equivalent
- // to what ES5 does in practice, but we can emulate it
- // by incrementing the array's length.
- array.length += 1;
- // Don't go next; the comma is the character after the
- // omitted (undefined) value.
+ error("Missing array element");
} else {
array.push(value());
- // The various value methods call next(); the current
- // character here is now the one after the value.
}
white();
// If there's no comma after this value, this needs to
@@ -329,7 +352,6 @@ JSON5.parse = (function () {
object = function () {
// Parse an object value.
-// TODO Update to support unquoted keys.
var key,
object = {};
@@ -386,6 +408,7 @@ JSON5.parse = (function () {
case "'":
return string();
case '-':
+ case '.':
return number();
default:
return ch >= '0' && ch <= '9' ? number() : word();
@@ -433,7 +456,7 @@ JSON5.parse = (function () {
}());
JSON5.stringify = function (obj, replacer, space) {
- // Since regular JSON is a strict subset of JSON5, we'll always output as
+ // Since regular JSON is a strict subset of JSON5, we'll always output
// regular JSON to foster better interoperability. TODO Should we not?
return JSON.stringify.apply(JSON, arguments);
};
View
18 lib/require.js
@@ -0,0 +1,18 @@
+// require.js
+// Node.js only: adds a require() hook for .json5 files, just like the native
+// hook for .json files.
+//
+// Usage:
+// require('json5/require');
+// require('./foo'); // will check foo.json5 after foo.js, foo.json, etc.
+// require('./bar.json5');
+
+var FS = require('fs');
+var JSON5 = require('./json5');
+
+// Modeled off of (v0.6.18 link; check latest too):
+// https://github.com/joyent/node/blob/v0.6.18/lib/module.js#L468-L472
+require.extensions['.json5'] = function (module, filename) {
+ var content = FS.readFileSync(filename, 'utf8');
+ module.exports = JSON5.parse(content);
+};
View
19 package.json
@@ -1,19 +0,0 @@
-{ "name": "json5"
-, "version": "0.0.1"
-, "description": "Modern JSON."
-, "keywords": ["json", "json5"]
-, "author": "Aseem Kishore <aseem.kishore@gmail.com>"
-, "main": "json5"
-, "dependencies": {}
-, "devDependencies":
- { "mocha": "~1.0.3"
- }
-, "scripts":
- { "test": "mocha --ui exports --reporter list"
- }
-, "homepage": "https://github.com/aseemk/json5"
-,"repository":
- { "type" : "git"
- , "url" : "https://github.com/aseemk/json5.git"
- }
-}
View
24 package.json5
@@ -0,0 +1,24 @@
+{
+ name: 'json5',
+ version: '0.1.0',
+ description: 'JSON for the ES5 era.',
+ keywords: ['json', 'es5'],
+ author: 'Aseem Kishore <aseem.kishore@gmail.com>',
+ contributors: [
+ 'Max Nanasy <max.nanasy@gmail.com>',
+ ],
+ main: 'lib/json5.js',
+ bin: 'lib/cli.js',
+ dependencies: {},
+ devDependencies: {
+ mocha: '~1.0.3',
+ },
+ scripts: {
+ test: 'mocha --ui exports --reporter spec',
+ },
+ homepage: 'http://json5.org/',
+ repository: {
+ type: 'git',
+ url: 'https://github.com/aseemk/json5.git',
+ },
+}
View
0  test/cases/empty-array.json5 → test/parse-cases/arrays/empty-array.json
File renamed without changes
View
0  test/cases/leading-comma-array.json5 → ...parse-cases/arrays/leading-comma-array.js
File renamed without changes
View
0  test/cases/lone-trailing-comma-array.json5 → ...cases/arrays/lone-trailing-comma-array.js
File renamed without changes
View
0  test/cases/no-comma-array.json5 → test/parse-cases/arrays/no-comma-array.txt
File renamed without changes
View
0  test/cases/regular-array.json5 → test/parse-cases/arrays/regular-array.json
File renamed without changes
View
0  test/cases/trailing-comma-array.json5 → ...e-cases/arrays/trailing-comma-array.json5
File renamed without changes
View
0  ...ock-comment-following-array-element.json5 → ...ock-comment-following-array-element.json5
File renamed without changes
View
0  ...k-comment-following-top-level-value.json5 → ...k-comment-following-top-level-value.json5
File renamed without changes
View
0  test/cases/block-comment-in-string.json5 → ...ses/comments/block-comment-in-string.json
File renamed without changes
View
0  ...k-comment-preceding-top-level-value.json5 → ...k-comment-preceding-top-level-value.json5
File renamed without changes
View
0  .../cases/block-comment-with-asterisks.json5 → ...mments/block-comment-with-asterisks.json5
File renamed without changes
View
0  ...ine-comment-following-array-element.json5 → ...ine-comment-following-array-element.json5
File renamed without changes
View
0  ...e-comment-following-top-level-value.json5 → ...e-comment-following-top-level-value.json5
File renamed without changes
View
0  test/cases/inline-comment-in-string.json5 → ...es/comments/inline-comment-in-string.json
File renamed without changes
View
0  ...e-comment-preceding-top-level-value.json5 → ...e-comment-preceding-top-level-value.json5
File renamed without changes
View
0  test/cases/top-level-block-comment.json5 → ...ases/comments/top-level-block-comment.txt
File renamed without changes
View
0  test/cases/top-level-inline-comment.json5 → ...ses/comments/top-level-inline-comment.txt
File renamed without changes
View
0  test/cases/unterminated-block-comment.json5 → ...s/comments/unterminated-block-comment.txt
File renamed without changes
View
0  test/cases/empty.json5 → test/parse-cases/misc/empty.txt
File renamed without changes
View
0  test/cases/npm-package.json → test/parse-cases/misc/npm-package.json
File renamed without changes
View
106 test/parse-cases/misc/npm-package.json5
@@ -0,0 +1,106 @@
+{
+ name: 'npm',
+ publishConfig: {
+ 'proprietary-attribs': false,
+ },
+ description: 'A package manager for node',
+ keywords: [
+ 'package manager',
+ 'modules',
+ 'install',
+ 'package.json',
+ ],
+ version: '1.1.22',
+ preferGlobal: true,
+ config: {
+ publishtest: false,
+ },
+ homepage: 'http://npmjs.org/',
+ author: 'Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)',
+ repository: {
+ type: 'git',
+ url: 'https://github.com/isaacs/npm',
+ },
+ bugs: {
+ email: 'npm-@googlegroups.com',
+ url: 'http://github.com/isaacs/npm/issues',
+ },
+ directories: {
+ doc: './doc',
+ man: './man',
+ lib: './lib',
+ bin: './bin',
+ },
+ main: './lib/npm.js',
+ bin: './bin/npm-cli.js',
+ dependencies: {
+ semver: '~1.0.14',
+ ini: '1',
+ slide: '1',
+ abbrev: '1',
+ 'graceful-fs': '~1.1.1',
+ minimatch: '~0.2',
+ nopt: '1',
+ 'node-uuid': '~1.3',
+ 'proto-list': '1',
+ rimraf: '2',
+ request: '~2.9',
+ which: '1',
+ tar: '~0.1.12',
+ fstream: '~0.1.17',
+ 'block-stream': '*',
+ inherits: '1',
+ mkdirp: '0.3',
+ read: '0',
+ 'lru-cache': '1',
+ 'node-gyp': '~0.4.1',
+ 'fstream-npm': '0 >=0.0.5',
+ 'uid-number': '0',
+ archy: '0',
+ chownr: '0',
+ },
+ bundleDependencies: [
+ 'slide',
+ 'ini',
+ 'semver',
+ 'abbrev',
+ 'graceful-fs',
+ 'minimatch',
+ 'nopt',
+ 'node-uuid',
+ 'rimraf',
+ 'request',
+ 'proto-list',
+ 'which',
+ 'tar',
+ 'fstream',
+ 'block-stream',
+ 'inherits',
+ 'mkdirp',
+ 'read',
+ 'lru-cache',
+ 'node-gyp',
+ 'fstream-npm',
+ 'uid-number',
+ 'archy',
+ 'chownr',
+ ],
+ devDependencies: {
+ ronn: 'https://github.com/isaacs/ronnjs/tarball/master',
+ },
+ engines: {
+ node: '0.6 || 0.7 || 0.8',
+ npm: '1',
+ },
+ scripts: {
+ test: 'node ./test/run.js',
+ prepublish: 'npm prune; rm -rf node_modules/*/{test,example,bench}*; make -j4 doc',
+ dumpconf: 'env | grep npm | sort | uniq',
+ },
+ licenses: [
+ {
+ type: 'MIT +no-false-attribs',
+ url: 'http://github.com/isaacs/npm/raw/master/LICENSE',
+ },
+ ],
+}
View
3  test/cases/all-features.json5 → test/parse-cases/misc/readme-example.json5
@@ -11,6 +11,9 @@
/* this is a block comment
it continues on another line */
+ hex: 0xDEADbeef,
+ half: .5,
+
finally: 'a trailing comma',
oh: [
'we shouldn\'t forget',
View
1  test/parse-cases/numbers/decimal-literal-with-exponent.json
@@ -0,0 +1 @@
+2e23
View
1  test/parse-cases/numbers/decimal-literal-with-negative-exponent.json
@@ -0,0 +1 @@
+2e-23
View
1  test/parse-cases/numbers/decimal-literal.json
@@ -0,0 +1 @@
+15
View
1  test/parse-cases/numbers/hexadecimal-literal-with-lowercase-letter.json5
@@ -0,0 +1 @@
+0xc8
View
1  test/parse-cases/numbers/hexadecimal-literal-with-no-digits.txt
@@ -0,0 +1 @@
+0x
View
1  test/parse-cases/numbers/hexadecimal-literal-with-uppercase-x.json5
@@ -0,0 +1 @@
+0XC8
View
1  test/parse-cases/numbers/hexadecimal-literal.json5
@@ -0,0 +1 @@
+0xC8
View
1  test/parse-cases/numbers/leading-decimal-point.json5
@@ -0,0 +1 @@
+.5
View
1  test/parse-cases/numbers/negative-decimal-literal.json
@@ -0,0 +1 @@
+-15
View
1  test/parse-cases/numbers/negative-hexadecimal-literal.json5
@@ -0,0 +1 @@
+-0xC8
View
1  test/parse-cases/numbers/negative-leading-decimal-point.json5
@@ -0,0 +1 @@
+-.5
View
1  test/parse-cases/numbers/noctal-literal-with-octal-digit-after-leading-zero.js
@@ -0,0 +1 @@
+0780
View
1  test/parse-cases/numbers/noctal-literal.js
@@ -0,0 +1 @@
+080
View
1  test/parse-cases/numbers/octal-literal.txt
@@ -0,0 +1 @@
+010
View
1  test/parse-cases/numbers/trailing-decimal-point-with-exponent.js
@@ -0,0 +1 @@
+5.e4
View
1  test/parse-cases/numbers/trailing-decimal-point.js
@@ -0,0 +1 @@
+5.
View
1  test/parse-cases/numbers/zero-literal.json
@@ -0,0 +1 @@
+0
View
0  test/cases/empty-object.json5 → test/parse-cases/objects/empty-object.json
File renamed without changes
View
0  test/cases/illegal-unquoted-key-number.json5 → ...s/objects/illegal-unquoted-key-number.txt
File renamed without changes
View
0  test/cases/illegal-unquoted-key-symbol.json5 → ...s/objects/illegal-unquoted-key-symbol.txt
File renamed without changes
View
0  test/cases/leading-comma-object.json5 → ...se-cases/objects/leading-comma-object.txt
File renamed without changes
View
0  test/cases/lone-trailing-comma-object.json5 → ...es/objects/lone-trailing-comma-object.txt
File renamed without changes
View
0  test/cases/no-comma-object.json5 → test/parse-cases/objects/no-comma-object.txt
File renamed without changes
View
0  test/cases/reserved-unquoted-key.json5 → ...cases/objects/reserved-unquoted-key.json5
File renamed without changes
View
0  test/cases/single-quoted-key.json5 → ...rse-cases/objects/single-quoted-key.json5
File renamed without changes
View
0  test/cases/trailing-comma-object.json5 → ...cases/objects/trailing-comma-object.json5
File renamed without changes
View
0  test/cases/unquoted-keys.json5 → test/parse-cases/objects/unquoted-keys.json5
File renamed without changes
View
0  test/cases/escape-single-quoted-string.json5 → ...trings/escaped-single-quoted-string.json5
File renamed without changes
View
0  test/cases/multi-line-string.json5 → ...rse-cases/strings/multi-line-string.json5
File renamed without changes
View
0  test/cases/single-quoted-string.json5 → ...-cases/strings/single-quoted-string.json5
File renamed without changes
View
3  test/parse-cases/todo/unicode-escaped-unquoted-key.json5
@@ -0,0 +1,3 @@
+{
+ sig\u03A3ma: "the sum of all things"
+}
View
0  test/cases-todo/unicode-unquoted-key.json5 → ...rse-cases/todo/unicode-unquoted-key.json5
File renamed without changes
View
74 test/parse.js
@@ -0,0 +1,74 @@
+// parse.js
+// Tests parse(). See readme.txt for details.
+
+var assert = require('assert');
+var FS = require('fs');
+var JSON5 = require('..');
+var Path = require('path');
+
+// Test JSON5.parse() by comparing its output for each case with either the
+// native JSON.parse() or ES5 strict-mode eval(). See readme.txt for details.
+// For eval(), remember to wrap the input in parentheses before eval()'ing,
+// since {...} is ambiguous in JavaScript. Also ensure the parentheses are on
+// lines of their own, to support inline comments.
+
+// TODO More test cases, and ones that test specific features and edge cases.
+// Mozilla's test cases are a great inspiration and reference here:
+// http://mxr.mozilla.org/mozilla-central/source/js/src/tests/ecma_5/JSON/
+
+var dirsPath = Path.resolve(__dirname, 'parse-cases');
+var dirs = FS.readdirSync(dirsPath);
+
+function createTest(fileName, dir) {
+ var ext = Path.extname(fileName);
+ var filePath = Path.join(dirsPath, dir, fileName);
+ var str = FS.readFileSync(filePath, 'utf8');
+
+ function parseJSON5() {
+ return JSON5.parse(str);
+ }
+
+ function parseJSON() {
+ return JSON.parse(str);
+ }
+
+ function parseES5() {
+ return eval('"use strict"; (\n' + str + '\n)');
+ }
+
+ exports[dir][fileName] = function test() {
+ switch (ext) {
+ case '.json':
+ assert.deepEqual(parseJSON5(), parseJSON());
+ break;
+ case '.json5':
+ assert.throws(parseJSON); // test validation
+ assert.deepEqual(parseJSON5(), parseES5());
+ break;
+ case '.js':
+ assert.throws(parseJSON); // test validation
+ assert.doesNotThrow(parseES5); // test validation
+ assert.throws(parseJSON5);
+ break;
+ case '.txt':
+ assert.throws(parseES5); // test validation
+ assert.throws(parseJSON5);
+ break;
+ }
+ };
+}
+
+dirs.forEach(function (dir) {
+ // create a test suite for this group of tests:
+ exports[dir] = {};
+
+ // skip the TODO directory -- these tests are expected to fail:
+ if (dir === 'todo') {
+ return;
+ }
+
+ // otherwise create a test for each file in this group:
+ FS.readdirSync(Path.join(dirsPath, dir)).forEach(function (file) {
+ createTest(file, dir);
+ });
+});
View
23 test/readme.md
@@ -0,0 +1,23 @@
+These tests are written for [Mocha][] using the [exports][] interface.
+
+[Mocha]: http://visionmedia.github.com/mocha/
+[exports]: http://visionmedia.github.com/mocha/#exports-interface
+
+The `parse()` tests are run by comparing the output of `JSON5.parse()` with
+that of the native `JSON.parse()` and ES5's `eval()` in strict mode. The test
+cases' file extension signals the expected behavior:
+
+- Valid JSON should remain valid JSON5. These cases have a `.json` extension
+ and are tested via `JSON.parse()`.
+
+- JSON5's new features should remain valid ES5. These cases have a `.json5`
+ extension are tested via `eval()`.
+
+- Valid ES5 that's explicitly disallowed by JSON5 is also invalid JSON. These
+ cases have a `.js` extension and are expected to fail.
+
+- Invalid ES5 should remain invalid JSON5. These cases have a `.txt` extension
+ and are expected to fail.
+
+This should cover all our bases. Most of the cases are unit tests for each
+supported data type, but aggregate test cases are welcome, too.
View
18 test/require.js
@@ -0,0 +1,18 @@
+// require.js
+// Tests JSON5's require() hook.
+//
+// Important: expects the following test cases to be present:
+// - /parse-cases/misc/npm-package.json
+// - /parse-cases/misc/npm-package.json5
+
+var assert = require('assert');
+
+exports['misc'] = {};
+exports['misc']['require hook'] = function () {
+ require('../lib/require');
+
+ var json = require('./parse-cases/misc/npm-package.json');
+ var json5 = require('./parse-cases/misc/npm-package.json5');
+
+ assert.deepEqual(json5, json);
+};
View
47 test/via-eval.js
@@ -1,47 +0,0 @@
-var assert = require('assert');
-var FS = require('fs');
-var JSON5 = require('..');
-var Path = require('path');
-
-// Test JSON5.parse() with each test case under /cases by comparing its output
-// with eval(). If the input is valid, it should eval() fine since JSON5 is a
-// pure subset of ES5, and the JSON5.parse() output should match eval()'s. If
-// the input *isn't* valid, eval() will throw an error, and JSON5.parse()
-// should too. Remember to wrap the input in parentheses before eval()'ing,
-// since {...} is ambiguous in JavaScript. Also ensure the parentheses are on
-// lines of their own, to support inline comments.
-
-// TODO More test cases, and ones that test specific features and edge cases.
-// Mozilla's test cases are a great inspiration and reference here:
-// http://mxr.mozilla.org/mozilla-central/source/js/src/tests/ecma_5/JSON/
-
-var dirPath = Path.resolve(__dirname, 'cases');
-var files = FS.readdirSync(dirPath);
-
-function createTest(fileName) {
- var filePath = Path.join(dirPath, fileName);
- var str = FS.readFileSync(filePath, 'utf8');
-
- function parse() {
- return JSON5.parse(str);
- }
-
- exports[fileName] = function test() {
- var objExp, valid = false;
-
- try {
- objExp = eval('(\n' + str + '\n)');
- valid = true;
- } catch (err) {}
-
- if (valid) {
- assert.deepEqual(parse(), objExp);
- } else {
- assert.throws(parse);
- }
- };
-}
-
-for (var i = 0; i < files.length; i++) {
- createTest(files[i]);
-}

0 comments on commit 296eac5

Please sign in to comment.
Something went wrong with that request. Please try again.