40 Commits

Author SHA1 Message Date
Andrey Gubanov
1810184186 add updated web version 2020-09-16 15:53:58 +03:00
Andrey Gubanov
67f22e8ac3 1.7.6 2020-09-16 14:20:49 +03:00
Andrey Gubanov
fcab8c4415 Merge pull request #3 from jpalardy/master
Report dougJSONParse errors in same format as other parse errors
2020-09-16 14:14:23 +03:00
Jonathan Palardy
b4cf02bd80 Report dougJSONParse errors in same format as other parse errors 2020-09-10 20:44:35 -07:00
Andrey Gubanov
d506cf924b Store deprecated package nomnom locally 2019-07-26 17:48:41 +03:00
Andrey Gubanov
d9057c2d39 Minor enhancements 2019-02-10 13:47:10 +02:00
Andrey Gubanov
ac1eae7734 Merge pull request #2 from kdzwinel/patch-1
Remove console.error call
2018-05-27 00:26:25 +03:00
Konrad Dzwinel
3e7c654694 Remove console.error call
Get rid of unwanted console output.
2018-04-30 11:41:48 +02:00
Andrey Gubanov
5abb74c63d 1.7.2 2017-06-05 19:59:02 +03:00
Andrey Gubanov
1c92b6312b Prepublish bundle 2017-06-05 19:58:51 +03:00
Andrey Gubanov
77167762e5 1.7.1 2017-06-05 19:55:51 +03:00
Andrey Gubanov
094ff0d03d Throw error when Doug parser throws 'Unexpected' 2017-06-05 19:55:27 +03:00
Andrey Gubanov (his digital copy)
a4ff31cbf7 modify readme and publish 1.7.0 2016-09-25 16:22:26 +03:00
Andrey Gubanov (his digital copy)
091450f3a2 bug fixes 2016-09-25 16:07:40 +03:00
Andrey Gubanov (his digital copy)
1d18f80902 bundle 2016-09-25 15:55:43 +03:00
Andrey Gubanov (his digital copy)
39f5c3dc89 add Doug's json parse and check for bad empty symbols and duplicates 2016-09-25 15:29:03 +03:00
Andrey Gubanov (his digital copy)
042f6b9507 add Doug's json parse and check for bad empty symbols and duplicates 2016-09-25 15:27:04 +03:00
Zachary Carter
f5cb6e7e98 1.6.2 2014-08-12 12:34:37 -07:00
Zachary Carter
b9a537a3c1 pretty print should exit with error code when invalid
Fixes issue #38.
2014-08-12 12:33:53 -07:00
Zachary Carter
5834ccff24 1.6.1 2014-08-12 12:03:37 -07:00
Zach Carter
957bf60ff3 Merge pull request #49 from diurnalist/feature/sort-arrays
Fix issue where objects nested in arrays would not have sorted keys
2014-08-12 12:01:22 -07:00
Jason Anderson
2b833324ba Fix issue where objects nested in arrays would not have sorted keys 2014-07-17 14:49:26 +02:00
Zach Carter
8cd6a4f3d2 Merge pull request #33 from louismrose/master
Add bower.json.
2013-08-08 23:26:30 -07:00
Louis Rose
271d8982d0 Add bower.json. 2013-08-06 14:07:52 +01:00
Zach Carter
57edf0b901 Merge pull request #31 from tmcw/master
Makefile should use local binaries, not global
2013-07-24 08:43:24 -07:00
Tom MacWright
a6a6ff142d Makefile should use local binaries, not global 2013-07-24 10:13:42 -04:00
Zachary Carter
09c10ae1ac Update readme with latest command-line arguments 2013-04-02 10:47:25 -07:00
Zachary Carter
fca1f5f846 1.6.0 2013-04-02 10:44:25 -07:00
Zach Carter
f019341e15 Merge pull request #30 from teknogeek0/85bf286c795eeef6d17f1c89b646a94b5623e385
Add in the -q/--quiet option to the README.md so folks know its there.
2013-04-01 21:43:59 -07:00
Christopher Munns
85bf286c79 Adding in the -q/--quiet option to the Readme.md 2013-04-01 21:39:15 -04:00
Zach Carter
79b553fb65 Merge pull request #27 from lroggendorff/add-forceformat-option
Add forceformat option
2012-12-16 11:04:07 -08:00
Lance Roggendorff
59c36ad370 Merge branch 'fix-inplace-overwriting' into add-forceformat-option
* fix-inplace-overwriting:
  Fixing variable name when overwriting input file.
2012-09-12 23:12:25 -05:00
Lance Roggendorff
92ac817d17 Adding forceformat option: format invalid output just like jsonlint.com
When using jsonlint.com, even invalid JSON is pretty printed. It seemed
like a good option to have in the cli version as well. This is simply
inserting the char-by-char formatter from
https://github.com/umbrae/jsonlintdotcom and adding an option to cli.js.
2012-09-12 23:11:11 -05:00
Lance Roggendorff
0f3202370f Fixing variable name when overwriting input file.
It looks like at one time the variable referencing the input file was
'path', and later on it was changed to 'json', but the if
(options.inplace) block was never updated.
2012-09-12 22:55:26 -05:00
Zachary Carter
1d7ed8ab13 1.5.1 2012-08-22 10:37:25 -07:00
Zach Carter
5e02f8b8e0 Merge pull request #26 from gregglind/quiet25
added quiet mode #25
2012-08-22 10:34:16 -07:00
Gregg Lind
f2e1de3039 added quiet mode 2012-08-22 09:10:54 -05:00
Zach Carter
cdb7737033 Update master 2012-06-19 20:44:54 -07:00
Zachary Carter
5c5ad5acf0 1.5.0 2012-05-28 15:14:43 -07:00
Zachary Carter
6af4143235 add schema validation 2012-05-28 15:14:09 -07:00
15 changed files with 2381 additions and 54 deletions

View File

@@ -2,9 +2,9 @@
all: build test site
build:
jison src/jsonlint.y src/jsonlint.l
./node_modules/jison/lib/cli.js src/jsonlint.y src/jsonlint.l
mv jsonlint.js lib/jsonlint.js
node scripts/bundle.js | uglifyjs > web/jsonlint.js
node scripts/bundle.js | ./node_modules/uglify-js/bin/uglifyjs > web/jsonlint.js
site:
cp web/jsonlint.js ../jsonlint-pages/jsonlint.js

View File

@@ -1,12 +1,18 @@
JSON Lint
JSON Lint [![npm version](https://badge.fury.io/js/jsonlint-mod.svg)](https://badge.fury.io/js/jsonlint-mod)
=========
A pure [JavaScript version](http://zaach.github.com/jsonlint/) of the service provided at [jsonlint.com](http://jsonlint.com).
The fork is a modified version of [jsonlint](http://zaach.github.com/jsonlint/) enhanced by the original Douglas Crockford's JSON parser which brought the following features:
- Handle hidden chars
- Handle key duplicates
- Web version exported as CJS module to use with Webpack and other bundlers
A modified description below.
## Command line interface
Install jsonlint with npm to use the command line interface:
npm install jsonlint -g
npm install jsonlint-mod -g
Validate a file like so:
@@ -21,30 +27,35 @@ jsonlint will either report a syntax error with details or pretty print the sour
### Options
$ jsonlint -h
Usage: jsonlint <file> [options]
<file> file to parse; otherwise uses stdin
Usage: jsonlint [file] [options]
file file to parse; otherwise uses stdin
Options:
-v, --version print version and exit
-s, --sort-keys sort object keys
-i, --in-place overwrite the file
-t CHAR, --indent CHAR character(s) to use for indentation [ ]
-c, --compact compact error display
-V, --validate a JSON schema to use for validation
-e, --environment which specification of JSON Schema the validation file uses [json-schema-draft-03]
-q, --quiet do not print the parsed json to STDOUT [false]
-p, --pretty-print force pretty printing even if invalid
options:
-v, --version print version and exit
-s, --sort-keys sort object keys
-i, --in-place overwrite the file
-t CHAR, --indent CHAR character(s) to use for indentation
## Module interface
I'm not sure why you wouldn't use the built in `JSON.parse` but you can use jsonlint from a CommonJS module:
var jsonlint = require("jsonlint-mod");
var jsonlint = require("jsonlint");
jsonlint.parse('{"creative?": false}');
jsonlint.parse('{"creative?": false}');
It returns the parsed object or throws an `Error`.
## Vim Plugins
* [Syntastic](http://www.vim.org/scripts/script.php?script_id=2736)
* [sourcebeautify](http://www.vim.org/scripts/script.php?script_id=4079)
* [sourcebeautify](http://www.vim.org/scripts/script.php?script_id=4079)
## MIT License
@@ -54,4 +65,4 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
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.
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.

16
bower.json Normal file
View File

@@ -0,0 +1,16 @@
{
"name": "jsonlint",
"version": "1.6.0",
"main": "lib/jsonlint.js",
"ignore": [
"**/.*",
"node_modules",
"scripts",
"src",
"test",
"web",
"package.json",
"Makefile",
"README.md"
]
}

View File

@@ -1,10 +1,14 @@
#!/usr/bin/env node
var fs = require("fs");
var path = require("path");
var parser = require("./jsonlint").parser;
var options = require("nomnom")
.scriptName("jsonlint")
.opts({
var JSV = require("JSV").JSV;
var formatter = require("./formatter.js").formatter;
var options = require("./nomnom")
.script("jsonlint")
.options({
file: {
position: 0,
help: "file to parse; otherwise uses stdin"
@@ -14,7 +18,7 @@ var options = require("nomnom")
string: '-v, --version',
help: 'print version and exit',
callback: function() {
return JSON.parse(fs.readFileSync(__dirname + "/../package.json", "utf8")).version;
return require("../package").version;
}
},
sort : {
@@ -36,41 +40,108 @@ var options = require("nomnom")
flag : true,
string: '-c, --compact',
help : 'compact error display'
},
validate : {
string: '-V, --validate',
help : 'a JSON schema to use for validation'
},
env : {
string: '-e, --environment',
"default": "json-schema-draft-03",
help: 'which specification of JSON Schema the validation file uses'
},
quiet: {
flag: true,
key: "value",
string: '-q, --quiet',
"default": false,
help: 'do not print the parsed json to STDOUT'
},
forcePrettyPrint: {
flag: true,
string: '-p, --pretty-print',
help: 'force pretty printing even if invalid'
}
})
.parseArgs();
}).parse();
if (options.compact) {
var fileName = options.file? options.file + ': ' : '';
parser.parseError = parser.lexer.parseError = function(str, hash) {
var fileName = options.file? options.file + ': ' : '';
parser.parseError = parser.lexer.parseError = function(str, hash) {
// error from dougJSONParse
if (hash.message) {
console.error(fileName + 'line '+ hash.line +', col '+ hash.col +',', hash.message + '.');
} else {
console.error(fileName + 'line '+ hash.loc.first_line +', col '+ hash.loc.last_column +', found: \''+ hash.token +'\' - expected: '+ hash.expected.join(', ') +'.');
throw new Error(str);
};
}
throw new Error(str);
};
}
function parse (source) {
var parsed,
formatted;
try {
var parsed = options.sort ?
sortObject(parser.parse(source)) :
parser.parse(source);
return JSON.stringify(parsed,null,options.indent);
parsed = options.sort ?
sortObject(parser.parse(source)) :
parser.parse(source);
if (options.validate) {
var env = JSV.createEnvironment(options.env);
var schema = JSON.parse(fs.readFileSync(path.normalize(options.validate), "utf8"));
var report = env.validate(parsed, schema);
if (report.errors.length) {
throw report.errors.reduce(schemaError, 'Validation Errors:');
}
}
return JSON.stringify(parsed, null, options.indent);
} catch (e) {
if (! options.compact) {
console.log(e);
if (options.forcePrettyPrint) {
/* From https://github.com/umbrae/jsonlintdotcom:
* If we failed to validate, run our manual formatter and then re-validate so that we
* can get a better line number. On a successful validate, we don't want to run our
* manual formatter because the automatic one is faster and probably more reliable.
*/
try {
formatted = formatter.formatJson(source, options.indent);
// Re-parse so exception output gets better line numbers
parsed = parser.parse(formatted);
} catch (e) {
if (! options.compact) {
console.error(e);
}
// force the pretty print before exiting
console.log(formatted);
}
} else {
if (! options.compact) {
console.error(e);
}
}
process.exit(1);
}
}
function schemaError (str, err) {
return str +
"\n\n"+err.message +
"\nuri: " + err.uri +
"\nschemaUri: " + err.schemaUri +
"\nattribute: " + err.attribute +
"\ndetails: " + JSON.stringify(err.details);
}
function main (args) {
var source = '';
if (options.file) {
var path = require('path').normalize(options.file);
source = parse(fs.readFileSync(path, "utf8"));
var json = path.normalize(options.file);
source = parse(fs.readFileSync(json, "utf8"));
if (options.inplace) {
fs.writeSync(fs.openSync(path,'w+'), source, 0, "utf8");
fs.writeSync(fs.openSync(json,'w+'), source, 0, "utf8");
} else {
console.log(source);
if (! options.quiet) { console.log(source)};
}
} else {
var stdin = process.openStdin();
@@ -80,14 +151,16 @@ function main (args) {
source += chunk.toString('utf8');
});
stdin.on('end', function () {
console.log(parse(source));
if (! options.quiet) {console.log(parse(source))};
});
}
}
// from http://stackoverflow.com/questions/1359761/sorting-a-json-object-in-javascript
function sortObject(o) {
if (Object.prototype.toString.call(o) !== '[object Object]') {
if (Array.isArray(o)) {
return o.map(sortObject);
} else if (Object.prototype.toString.call(o) !== '[object Object]') {
return o;
}

360
lib/doug-json-parse.js Normal file
View File

@@ -0,0 +1,360 @@
/*
json_parse.js
2016-05-02
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
This file creates a json_parse function.
json_parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = json_parse(text, function (key, value) {
var a;
if (typeof value === "string") {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
*/
/*jslint for */
/*property
at, b, call, charAt, f, fromCharCode, hasOwnProperty, message, n, name,
prototype, push, r, t, text
*/
var ___dougJSONParse = (function () {
"use strict";
// This is a function that can parse a JSON text, producing a JavaScript
// data structure. It is a simple, recursive descent parser. It does not use
// eval or regular expressions, so it can be used as a model for implementing
// a JSON parser in other languages.
// We are defining the function inside of another function to avoid creating
// global variables.
var at; // The index of the current character
var ch; // The current character
var escapee = {
"\"": "\"",
"\\": "\\",
"/": "/",
b: "\b",
f: "\f",
n: "\n",
r: "\r",
t: "\t"
};
var text;
var error = function (m) {
// Call error when something is wrong.
throw {
name: "SyntaxError",
message: m,
at: at,
text: text
};
};
var next = function (c) {
// If a c parameter is provided, verify that it matches the current character.
if (c && c !== ch) {
error("Expected '" + c + "' instead of '" + ch + "'");
}
// Get the next character. When there are no more characters,
// return the empty string.
ch = text.charAt(at);
at += 1;
return ch;
};
var number = function () {
// Parse a number value.
var value;
var string = "";
if (ch === "-") {
string = "-";
next("-");
}
while (ch >= "0" && ch <= "9") {
string += ch;
next();
}
if (ch === ".") {
string += ".";
while (next() && ch >= "0" && ch <= "9") {
string += ch;
}
}
if (ch === "e" || ch === "E") {
string += ch;
next();
if (ch === "-" || ch === "+") {
string += ch;
next();
}
while (ch >= "0" && ch <= "9") {
string += ch;
next();
}
}
value = +string;
if (!isFinite(value)) {
error("Bad number");
} else {
return value;
}
};
var string = function () {
// Parse a string value.
var hex;
var i;
var value = "";
var uffff;
// When parsing for string values, we must look for " and \ characters.
if (ch === "\"") {
while (next()) {
if (ch === "\"") {
next();
return value;
}
if (ch === "\\") {
next();
if (ch === "u") {
uffff = 0;
for (i = 0; i < 4; i += 1) {
hex = parseInt(next(), 16);
if (!isFinite(hex)) {
break;
}
uffff = uffff * 16 + hex;
}
value += String.fromCharCode(uffff);
} else if (typeof escapee[ch] === "string") {
value += escapee[ch];
} else {
break;
}
} else {
value += ch;
}
}
}
error("Bad string");
};
var white = function () {
// Skip whitespace.
while (ch && ch <= " ") {
next();
}
};
var word = function () {
// true, false, or null.
switch (ch) {
case "t":
next("t");
next("r");
next("u");
next("e");
return true;
case "f":
next("f");
next("a");
next("l");
next("s");
next("e");
return false;
case "n":
next("n");
next("u");
next("l");
next("l");
return null;
}
error("Unexpected '" + ch + "'");
};
var value; // Place holder for the value function.
var array = function () {
// Parse an array value.
var arr = [];
if (ch === "[") {
next("[");
white();
if (ch === "]") {
next("]");
return arr; // empty array
}
while (ch) {
arr.push(value());
white();
if (ch === "]") {
next("]");
return arr;
}
next(",");
white();
}
}
error("Bad array");
};
var object = function () {
// Parse an object value.
var key;
var obj = {};
if (ch === "{") {
next("{");
white();
if (ch === "}") {
next("}");
return obj; // empty object
}
while (ch) {
key = string();
white();
next(":");
if (Object.hasOwnProperty.call(obj, key)) {
error("Duplicate key '" + key + "'");
}
obj[key] = value();
white();
if (ch === "}") {
next("}");
return obj;
}
next(",");
white();
}
}
error("Bad object");
};
value = function () {
// Parse a JSON value. It could be an object, an array, a string, a number,
// or a word.
white();
switch (ch) {
case "{":
return object();
case "[":
return array();
case "\"":
return string();
case "-":
return number();
default:
return (ch >= "0" && ch <= "9")
? number()
: word();
}
};
// Return the json_parse function. It will have access to all of the above
// functions and variables.
return function (source, reviver) {
var result;
text = source;
at = 0;
ch = " ";
result = value();
white();
if (ch) {
error("Syntax error");
}
// If there is a reviver function, we recursively walk the new structure,
// passing each name/value pair to the reviver function for possible
// transformation, starting with a temporary root object that holds the result
// in an empty key. If there is not a reviver function, we simply return the
// result.
return (typeof reviver === "function")
? (function walk(holder, key) {
var k;
var v;
var val = holder[key];
if (val && typeof val === "object") {
for (k in val) {
if (Object.prototype.hasOwnProperty.call(val, k)) {
v = walk(val, k);
if (v !== undefined) {
val[k] = v;
} else {
delete val[k];
}
}
}
}
return reviver.call(holder, key, val);
}({"": result}, ""))
: result;
};
}());
if(typeof module === 'object' && module.exports) {
module.exports = ___dougJSONParse;
}

92
lib/formatter.js Normal file
View File

@@ -0,0 +1,92 @@
#!/usr/bin/env node
/**
* Manual formatter taken straight from https://github.com/umbrae/jsonlintdotcom
**/
/*jslint white: true, devel: true, onevar: true, browser: true, undef: true, nomen: true, regexp: true, plusplus: false, bitwise: true, newcap: true, maxerr: 50, indent: 4 */
/**
* jsl.format - Provide json reformatting in a character-by-character approach, so that even invalid JSON may be reformatted (to the best of its ability).
*
**/
var formatter = (function () {
function repeat(s, count) {
return new Array(count + 1).join(s);
}
function formatJson(json, indentChars) {
var i = 0,
il = 0,
tab = (typeof indentChars !== "undefined") ? indentChars : " ",
newJson = "",
indentLevel = 0,
inString = false,
currentChar = null;
for (i = 0, il = json.length; i < il; i += 1) {
currentChar = json.charAt(i);
switch (currentChar) {
case '{':
case '[':
if (!inString) {
newJson += currentChar + "\n" + repeat(tab, indentLevel + 1);
indentLevel += 1;
} else {
newJson += currentChar;
}
break;
case '}':
case ']':
if (!inString) {
indentLevel -= 1;
newJson += "\n" + repeat(tab, indentLevel) + currentChar;
} else {
newJson += currentChar;
}
break;
case ',':
if (!inString) {
newJson += ",\n" + repeat(tab, indentLevel);
} else {
newJson += currentChar;
}
break;
case ':':
if (!inString) {
newJson += ": ";
} else {
newJson += currentChar;
}
break;
case ' ':
case "\n":
case "\t":
if (inString) {
newJson += currentChar;
}
break;
case '"':
if (i > 0 && json.charAt(i - 1) !== '\\') {
inString = !inString;
}
newJson += currentChar;
break;
default:
newJson += currentChar;
break;
}
}
return newJson;
}
return { "formatJson": formatJson };
}());
if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
exports.formatter = formatter;
}

View File

@@ -17,7 +17,7 @@ case 1: // replace escaped characters with actual character
.replace(/\\v/g,'\v')
.replace(/\\f/g,'\f')
.replace(/\\b/g,'\b');
break;
case 2:this.$ = Number(yytext);
break;
@@ -341,7 +341,7 @@ next:function () {
if (this._input === "") {
return this.EOF;
} else {
this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
{text: "", token: null, line: this.yylineno});
}
},
@@ -412,6 +412,28 @@ return lexer;})()
parser.lexer = lexer;
return parser;
})();
var origParse = jsonlint.parse;
jsonlint.parse = function(input) {
var result = origParse.call(jsonlint, input);
var dougJSONParse = typeof ___dougJSONParse === 'undefined' ? require('./doug-json-parse') : ___dougJSONParse;
try {
dougJSONParse(input);
} catch(e) {
if(/Duplicate key|Bad string|Unexpected/.test(e.message)) {
var linesUntilError = input.substring(0, e.at).split('\n');
var line = linesUntilError.length;
var col = linesUntilError[line - 1].length - 1;
this.parseError(e.message, {line: line, col: col, message: e.message.replace(/./, function(l) { return l.toLowerCase(); })});
throw SyntaxError(e.message + ' on line ' + line);
}
}
return result;
}
if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
exports.parser = jsonlint;
exports.parse = function () { return jsonlint.parse.apply(jsonlint, arguments); }
@@ -429,4 +451,4 @@ exports.main = function commonjsMain(args) {
if (typeof module !== 'undefined' && require.main === module) {
exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args);
}
}
}

611
lib/nomnom.js Normal file
View File

@@ -0,0 +1,611 @@
/*
nomnom is an option parser for node. It noms your args and gives them back to you in a hash.
https://github.com/harthur/nomnom
Copyright (c) 2010 Heather Arthur
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.
*/
var _ = require("underscore"), chalk = require('chalk');
function ArgParser() {
this.commands = {}; // expected commands
this.specs = {}; // option specifications
}
ArgParser.prototype = {
/* Add a command to the expected commands */
command : function(name) {
var command;
if (name) {
command = this.commands[name] = {
name: name,
specs: {}
};
}
else {
command = this.fallback = {
specs: {}
};
}
// facilitates command('name').options().cb().help()
var chain = {
options : function(specs) {
command.specs = specs;
return chain;
},
opts : function(specs) {
// old API
return this.options(specs);
},
option : function(name, spec) {
command.specs[name] = spec;
return chain;
},
callback : function(cb) {
command.cb = cb;
return chain;
},
help : function(help) {
command.help = help;
return chain;
},
usage : function(usage) {
command._usage = usage;
return chain;
}
};
return chain;
},
nocommand : function() {
return this.command();
},
options : function(specs) {
this.specs = specs;
return this;
},
opts : function(specs) {
// old API
return this.options(specs);
},
globalOpts : function(specs) {
// old API
return this.options(specs);
},
option : function(name, spec) {
this.specs[name] = spec;
return this;
},
usage : function(usage) {
this._usage = usage;
return this;
},
printer : function(print) {
this.print = print;
return this;
},
script : function(script) {
this._script = script;
return this;
},
scriptName : function(script) {
// old API
return this.script(script);
},
help : function(help) {
this._help = help;
return this;
},
colors: function() {
// deprecated - colors are on by default now
return this;
},
nocolors : function() {
this._nocolors = true;
return this;
},
parseArgs : function(argv) {
// old API
return this.parse(argv);
},
nom : function(argv) {
return this.parse(argv);
},
parse : function(argv) {
this.print = this.print || function(str, code) {
console.log(str);
process.exit(code || 0);
};
this._help = this._help || "";
this._script = this._script || process.argv[0] + " "
+ require('path').basename(process.argv[1]);
this.specs = this.specs || {};
var argv = argv || process.argv.slice(2);
var arg = Arg(argv[0]).isValue && argv[0],
command = arg && this.commands[arg],
commandExpected = !_(this.commands).isEmpty();
if (commandExpected) {
if (command) {
_(this.specs).extend(command.specs);
this._script += " " + command.name;
if (command.help) {
this._help = command.help;
}
this.command = command;
}
else if (arg) {
return this.print(this._script + ": no such command '" + arg + "'", 1);
}
else {
// no command but command expected e.g. 'git -v'
var helpStringBuilder = {
list : function() {
return 'one of: ' + _(this.commands).keys().join(", ");
},
twoColumn : function() {
// find the longest command name to ensure horizontal alignment
var maxLength = _(this.commands).max(function (cmd) {
return cmd.name.length;
}).name.length;
// create the two column text strings
var cmdHelp = _.map(this.commands, function(cmd, name) {
var diff = maxLength - name.length;
var pad = new Array(diff + 4).join(" ");
return " " + [ name, pad, cmd.help ].join(" ");
});
return "\n" + cmdHelp.join("\n");
}
};
// if there are a small number of commands and all have help strings,
// display them in a two column table; otherwise use the brief version.
// The arbitrary choice of "20" comes from the number commands git
// displays as "common commands"
var helpType = 'list';
if (_(this.commands).size() <= 20) {
if (_(this.commands).every(function (cmd) { return cmd.help; })) {
helpType = 'twoColumn';
}
}
this.specs.command = {
position: 0,
help: helpStringBuilder[helpType].call(this)
}
if (this.fallback) {
_(this.specs).extend(this.fallback.specs);
this._help = this.fallback.help;
} else {
this.specs.command.required = true;
}
}
}
if (this.specs.length === undefined) {
// specs is a hash not an array
this.specs = _(this.specs).map(function(opt, name) {
opt.name = name;
return opt;
});
}
this.specs = this.specs.map(function(opt) {
return Opt(opt);
});
if (argv.indexOf("--help") >= 0 || argv.indexOf("-h") >= 0) {
return this.print(this.getUsage());
}
var options = {};
var args = argv.map(function(arg) {
return Arg(arg);
})
.concat(Arg());
var positionals = [];
/* parse the args */
var that = this;
args.reduce(function(arg, val) {
/* positional */
if (arg.isValue) {
positionals.push(arg.value);
}
else if (arg.chars) {
var last = arg.chars.pop();
/* -cfv */
(arg.chars).forEach(function(ch) {
that.setOption(options, ch, true);
});
/* -v key */
if (!that.opt(last).flag) {
if (val.isValue) {
that.setOption(options, last, val.value);
return Arg(); // skip next turn - swallow arg
}
else {
that.print("'-" + (that.opt(last).name || last) + "'"
+ " expects a value\n\n" + that.getUsage(), 1);
}
}
else {
/* -v */
that.setOption(options, last, true);
}
}
else if (arg.full) {
var value = arg.value;
/* --key */
if (value === undefined) {
/* --key value */
if (!that.opt(arg.full).flag) {
if (val.isValue) {
that.setOption(options, arg.full, val.value);
return Arg();
}
else {
that.print("'--" + (that.opt(arg.full).name || arg.full) + "'"
+ " expects a value\n\n" + that.getUsage(), 1);
}
}
else {
/* --flag */
value = true;
}
}
that.setOption(options, arg.full, value);
}
return val;
});
positionals.forEach(function(pos, index) {
this.setOption(options, index, pos);
}, this);
options._ = positionals;
this.specs.forEach(function(opt) {
if (opt.default !== undefined && options[opt.name] === undefined) {
options[opt.name] = opt.default;
}
}, this);
// exit if required arg isn't present
this.specs.forEach(function(opt) {
if (opt.required && options[opt.name] === undefined) {
var msg = opt.name + " argument is required";
msg = this._nocolors ? msg : chalk.red(msg);
this.print("\n" + msg + "\n" + this.getUsage(), 1);
}
}, this);
if (command && command.cb) {
command.cb(options);
}
else if (this.fallback && this.fallback.cb) {
this.fallback.cb(options);
}
return options;
},
getUsage : function() {
if (this.command && this.command._usage) {
return this.command._usage;
}
else if (this.fallback && this.fallback._usage) {
return this.fallback._usage;
}
if (this._usage) {
return this._usage;
}
// todo: use a template
var str = "\n"
if (!this._nocolors) {
str += chalk.bold("Usage:");
}
else {
str += "Usage:";
}
str += " " + this._script;
var positionals = _(this.specs).select(function(opt) {
return opt.position != undefined;
})
positionals = _(positionals).sortBy(function(opt) {
return opt.position;
});
var options = _(this.specs).select(function(opt) {
return opt.position === undefined;
});
// assume there are no gaps in the specified pos. args
positionals.forEach(function(pos) {
str += " ";
var posStr = pos.string;
if (!posStr) {
posStr = pos.name || "arg" + pos.position;
if (pos.required) {
posStr = "<" + posStr + ">";
} else {
posStr = "[" + posStr + "]";
}
if (pos.list) {
posStr += "...";
}
}
str += posStr;
});
if (options.length) {
if (!this._nocolors) {
// must be a better way to do this
str += chalk.blue(" [options]");
}
else {
str += " [options]";
}
}
if (options.length || positionals.length) {
str += "\n\n";
}
function spaces(length) {
var spaces = "";
for (var i = 0; i < length; i++) {
spaces += " ";
}
return spaces;
}
var longest = positionals.reduce(function(max, pos) {
return pos.name.length > max ? pos.name.length : max;
}, 0);
positionals.forEach(function(pos) {
var posStr = pos.string || pos.name;
str += posStr + spaces(longest - posStr.length) + " ";
if (!this._nocolors) {
str += chalk.grey(pos.help || "")
}
else {
str += (pos.help || "")
}
str += "\n";
}, this);
if (positionals.length && options.length) {
str += "\n";
}
if (options.length) {
if (!this._nocolors) {
str += chalk.blue("Options:");
}
else {
str += "Options:";
}
str += "\n"
var longest = options.reduce(function(max, opt) {
return opt.string.length > max && !opt.hidden ? opt.string.length : max;
}, 0);
options.forEach(function(opt) {
if (!opt.hidden) {
str += " " + opt.string + spaces(longest - opt.string.length) + " ";
var defaults = (opt.default != null ? " [" + opt.default + "]" : "");
var help = opt.help ? opt.help + defaults : "";
str += this._nocolors ? help: chalk.grey(help);
str += "\n";
}
}, this);
}
if (this._help) {
str += "\n" + this._help;
}
return str;
}
};
ArgParser.prototype.opt = function(arg) {
// get the specified opt for this parsed arg
var match = Opt({});
this.specs.forEach(function(opt) {
if (opt.matches(arg)) {
match = opt;
}
});
return match;
};
ArgParser.prototype.setOption = function(options, arg, value) {
var option = this.opt(arg);
if (option.callback) {
var message = option.callback(value);
if (typeof message == "string") {
this.print(message, 1);
}
}
if (option.type != "string") {
try {
// infer type by JSON parsing the string
value = JSON.parse(value)
}
catch(e) {}
}
if (option.transform) {
value = option.transform(value);
}
var name = option.name || arg;
if (option.choices && option.choices.indexOf(value) == -1) {
this.print(name + " must be one of: " + option.choices.join(", "), 1);
}
if (option.list) {
if (!options[name]) {
options[name] = [value];
}
else {
options[name].push(value);
}
}
else {
options[name] = value;
}
};
/* an arg is an item that's actually parsed from the command line
e.g. "-l", "log.txt", or "--logfile=log.txt" */
var Arg = function(str) {
var abbrRegex = /^\-(\w+?)$/,
fullRegex = /^\-\-(no\-)?(.+?)(?:=(.+))?$/,
valRegex = /^[^\-].*/;
var charMatch = abbrRegex.exec(str),
chars = charMatch && charMatch[1].split("");
var fullMatch = fullRegex.exec(str),
full = fullMatch && fullMatch[2];
var isValue = str !== undefined && (str === "" || valRegex.test(str));
var value;
if (isValue) {
value = str;
}
else if (full) {
value = fullMatch[1] ? false : fullMatch[3];
}
return {
str: str,
chars: chars,
full: full,
value: value,
isValue: isValue
}
}
/* an opt is what's specified by the user in opts hash */
var Opt = function(opt) {
var strings = (opt.string || "").split(","),
abbr, full, metavar;
for (var i = 0; i < strings.length; i++) {
var string = strings[i].trim(),
matches;
if (matches = string.match(/^\-([^-])(?:\s+(.*))?$/)) {
abbr = matches[1];
metavar = matches[2];
}
else if (matches = string.match(/^\-\-(.+?)(?:[=\s]+(.+))?$/)) {
full = matches[1];
metavar = metavar || matches[2];
}
}
matches = matches || [];
var abbr = opt.abbr || abbr, // e.g. v from -v
full = opt.full || full, // e.g. verbose from --verbose
metavar = opt.metavar || metavar; // e.g. PATH from '--config=PATH'
var string;
if (opt.string) {
string = opt.string;
}
else if (opt.position === undefined) {
string = "";
if (abbr) {
string += "-" + abbr;
if (metavar)
string += " " + metavar
string += ", ";
}
string += "--" + (full || opt.name);
if (metavar) {
string += " " + metavar;
}
}
opt = _(opt).extend({
name: opt.name || full || abbr,
string: string,
abbr: abbr,
full: full,
metavar: metavar,
matches: function(arg) {
return opt.full == arg || opt.abbr == arg || opt.position == arg
|| opt.name == arg || (opt.list && arg >= opt.position);
}
});
return opt;
}
var createParser = function() {
return new ArgParser();
}
var nomnom = createParser();
for (var i in nomnom) {
if (typeof nomnom[i] == "function") {
createParser[i] = _(nomnom[i]).bind(nomnom);
}
}
module.exports = createParser;

240
package-lock.json generated Normal file
View File

@@ -0,0 +1,240 @@
{
"name": "jsonlint-mod",
"version": "1.7.6",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"JSONSelect": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/JSONSelect/-/JSONSelect-0.4.0.tgz",
"integrity": "sha1-oI7cxn6z/L6Z7WMIVTRKDPKCu40=",
"dev": true
},
"JSV": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz",
"integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c="
},
"amdefine": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
"dev": true,
"optional": true
},
"ansi-font": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/ansi-font/-/ansi-font-0.0.2.tgz",
"integrity": "sha1-iQMBvVhBRi/TnAt3Ca/R9SUUMzE=",
"dev": true
},
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"requires": {
"color-convert": "^1.9.0"
}
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"cjson": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/cjson/-/cjson-0.3.0.tgz",
"integrity": "sha1-5kObkHA9MS/24iJAl76pLOPQKhQ=",
"dev": true,
"requires": {
"jsonlint": "1.6.0"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"colors": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz",
"integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=",
"dev": true
},
"commander": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
"dev": true
},
"ebnf-parser": {
"version": "0.1.10",
"resolved": "https://registry.npmjs.org/ebnf-parser/-/ebnf-parser-0.1.10.tgz",
"integrity": "sha1-zR9rpHfFY4xAyX7ZtXLbW6tdgzE=",
"dev": true
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"escodegen": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.3.3.tgz",
"integrity": "sha1-8CQBb1qI4Eb9EgBQVek5gC5sXyM=",
"dev": true,
"requires": {
"esprima": "~1.1.1",
"estraverse": "~1.5.0",
"esutils": "~1.0.0",
"source-map": "~0.1.33"
}
},
"esprima": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-1.1.1.tgz",
"integrity": "sha1-W28VR/TRAuZw4UDFCb5ncdautUk=",
"dev": true
},
"estraverse": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz",
"integrity": "sha1-hno+jlip+EYYr7bC3bzZFrfLr3E=",
"dev": true
},
"esutils": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz",
"integrity": "sha1-gVHTWOIMisx/t0XnRywAJf5JZXA=",
"dev": true
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
},
"jison": {
"version": "0.4.18",
"resolved": "https://registry.npmjs.org/jison/-/jison-0.4.18.tgz",
"integrity": "sha512-FKkCiJvozgC7VTHhMJ00a0/IApSxhlGsFIshLW6trWJ8ONX2TQJBBz6DlcO1Gffy4w9LT+uL+PA+CVnUSJMF7w==",
"dev": true,
"requires": {
"JSONSelect": "0.4.0",
"cjson": "0.3.0",
"ebnf-parser": "0.1.10",
"escodegen": "1.3.x",
"esprima": "1.1.x",
"jison-lex": "0.3.x",
"lex-parser": "~0.1.3",
"nomnom": "1.5.2"
}
},
"jison-lex": {
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/jison-lex/-/jison-lex-0.3.4.tgz",
"integrity": "sha1-gcoo2E+ESZ36jFlNzePYo/Jux6U=",
"dev": true,
"requires": {
"lex-parser": "0.1.x",
"nomnom": "1.5.2"
}
},
"jsonlint": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.0.tgz",
"integrity": "sha1-iKpGvCiaesk7tGyuLVihh6m7SUo=",
"dev": true,
"requires": {
"JSV": ">= 4.0.x",
"nomnom": ">= 1.5.x"
}
},
"lex-parser": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/lex-parser/-/lex-parser-0.1.4.tgz",
"integrity": "sha1-ZMTwJfF/1Tv7RXY/rrFvAVp0dVA=",
"dev": true
},
"nomnom": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.5.2.tgz",
"integrity": "sha1-9DRUSKhTz71cDSYyDyR3qwUm/i8=",
"dev": true,
"requires": {
"colors": "0.5.x",
"underscore": "1.1.x"
},
"dependencies": {
"underscore": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.1.7.tgz",
"integrity": "sha1-QLq4S60Z0jAJbo1u9ii/8FXYPbA=",
"dev": true
}
}
},
"source-map": {
"version": "0.1.43",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
"integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=",
"dev": true,
"optional": true,
"requires": {
"amdefine": ">=0.0.4"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"requires": {
"has-flag": "^3.0.0"
}
},
"test": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/test/-/test-0.6.0.tgz",
"integrity": "sha1-WYasRF7Bd1QyJRLRBLoyyKY+k44=",
"dev": true,
"requires": {
"ansi-font": "0.0.2"
}
},
"uglify-js": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz",
"integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==",
"dev": true,
"requires": {
"commander": "~2.20.0",
"source-map": "~0.6.1"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"underscore": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz",
"integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg=="
}
}
}

View File

@@ -1,6 +1,6 @@
{
"author": "Zach Carter <zach@carter.name> (http://zaa.ch)",
"name": "jsonlint",
"name": "jsonlint-mod",
"description": "Validate JSON",
"keywords": [
"json",
@@ -8,16 +8,16 @@
"lint",
"jsonlint"
],
"version": "1.4.1",
"version": "1.7.6",
"preferGlobal": true,
"repository": {
"type": "git",
"url": "git://github.com/zaach/jsonlint.git"
"url": "git://github.com/circlecell/jsonlint.git"
},
"bugs": {
"url": "http://github.com/zaach/jsonlint/issues"
"url": "http://github.com/circlecell/jsonlint/issues"
},
"main": "lib/jsonlint.js",
"main": "web/jsonlint.js",
"bin": {
"jsonlint": "lib/cli.js"
},
@@ -25,7 +25,9 @@
"node": ">= 0.6"
},
"dependencies": {
"nomnom": ">= 1.x.x"
"JSV": "^4.0.2",
"chalk": "^2.4.2",
"underscore": "^1.9.1"
},
"devDependencies": {
"test": "*",
@@ -33,8 +35,10 @@
"uglify-js": "*"
},
"scripts": {
"test": "node test/all-tests.js"
"test": "node test/all-tests.js",
"bundle": "node scripts/bundle > web/jsonlint.js",
"prepublish": "npm run bundle"
},
"homepage": "http://zaach.github.com/jsonlint/",
"homepage": "http://jsonlint.com",
"optionalDependencies": {}
}

View File

@@ -1,8 +1,8 @@
var fs = require('fs');
var source = "var jsonlint = (function(){var require=true,module=false;var exports={};" +
fs.readFileSync(__dirname+'/../lib/doug-json-parse.js', 'utf8') +
fs.readFileSync(__dirname+'/../lib/jsonlint.js', 'utf8') +
"return exports;})()";
"return exports;})();if(typeof module === 'object' && module.exports) module.exports = jsonlint;";
console.log(source);

View File

@@ -213,6 +213,16 @@ exports["test extra brace"] = function () {
assert["throws"](function () {parser.parse(json)}, "should throw error");
}
exports["test hidden characters"] = function () {
var json = fs.readFileSync(__dirname + "/fails/35.json").toString();
assert["throws"](function () {parser.parse(json)}, "should throw error");
}
exports["test key duplicates"] = function () {
var json = fs.readFileSync(__dirname + "/fails/36.json").toString();
assert["throws"](function () {parser.parse(json)}, "should throw error");
}
exports["test pass-1"] = function () {
var json = fs.readFileSync(__dirname + "/passes/1.json").toString();
assert.doesNotThrow(function () {parser.parse(json)}, "should pass");

72
test/fails/35.json Normal file
View File

@@ -0,0 +1,72 @@
{
   "chapters":[
        {
            "title":"Unit Opener",
            "file":"index1.html"
        },
        {
            "title":"Reading",
            "file":"index2.html"
        },
        {
            "title":"Reading Comprehension",
            "file":"index3.html"
        },
        {
            "title":"Vocabulary List",
            "file":"index4.html"
        },
        {
            "title":"Mind Map",
            "file":"index5.html"
        },
        {
            "title":"Vocabulary and Spelling",
            "file":"index6.html"
        },
        {
            "title":"Language Arts",
            "file":"index7.html"
        },
        {
            "title":"Grammar",
            "file":"index8.html"
        },
{
            "title":"Reading 2",
            "file":"index9.html"
        },
        {
            "title":"Reading Comprehension and Vocabulary",
            "file":"index10.html"
        },
        {
            "title":"Let's Play",
            "file":"index11.html"
        },
        {
            "title":"Investigate and Report",
            "file":"index12.html"
        },
        {
            "title":"Grammar Review",
            "file":"index13.html"
        },
        {
            "title":"Everyday English",
            "file":"index14.html"
        },
        {
            "title":"Test Yourself: Reading",
            "file":"index15.html"
        },
        {
            "title":"Test Yourself: Writing",
            "file":"index16.html"
        },
{
            "title":"Logic: Allegory",
            "file":"index16.html"
        }
    ]
}

2
test/fails/36.json Normal file
View File

@@ -0,0 +1,2 @@
{"x":1,
"x":2}

File diff suppressed because one or more lines are too long