mirror of
https://github.com/circlecell/jsonlint-mod.git
synced 2026-01-21 05:07:49 +08:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67f22e8ac3 | ||
|
|
fcab8c4415 | ||
|
|
b4cf02bd80 | ||
|
|
d506cf924b | ||
|
|
d9057c2d39 | ||
|
|
ac1eae7734 | ||
|
|
3e7c654694 | ||
|
|
5abb74c63d | ||
|
|
1c92b6312b | ||
|
|
77167762e5 | ||
|
|
094ff0d03d | ||
|
|
a4ff31cbf7 | ||
|
|
091450f3a2 | ||
|
|
1d18f80902 | ||
|
|
39f5c3dc89 | ||
|
|
042f6b9507 | ||
|
|
f5cb6e7e98 | ||
|
|
b9a537a3c1 | ||
|
|
5834ccff24 | ||
|
|
957bf60ff3 | ||
|
|
2b833324ba | ||
|
|
8cd6a4f3d2 | ||
|
|
271d8982d0 | ||
|
|
57edf0b901 | ||
|
|
a6a6ff142d | ||
|
|
09c10ae1ac |
4
Makefile
4
Makefile
@@ -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
|
||||
|
||||
33
README.md
33
README.md
@@ -1,12 +1,18 @@
|
||||
JSON Lint
|
||||
JSON Lint [](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:
|
||||
|
||||
@@ -22,35 +28,34 @@ jsonlint will either report a syntax error with details or pretty print the sour
|
||||
|
||||
$ jsonlint -h
|
||||
|
||||
usage: jsonlint <file> [options]
|
||||
Usage: jsonlint [file] [options]
|
||||
|
||||
file file to parse; otherwise uses stdin
|
||||
|
||||
options:
|
||||
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
|
||||
-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
|
||||
-q, --quiet do not print the parsed json to STDOUT
|
||||
-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
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
@@ -60,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
16
bower.json
Normal 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"
|
||||
]
|
||||
}
|
||||
24
lib/cli.js
24
lib/cli.js
@@ -6,7 +6,7 @@ var parser = require("./jsonlint").parser;
|
||||
var JSV = require("JSV").JSV;
|
||||
var formatter = require("./formatter.js").formatter;
|
||||
|
||||
var options = require("nomnom")
|
||||
var options = require("./nomnom")
|
||||
.script("jsonlint")
|
||||
.options({
|
||||
file: {
|
||||
@@ -67,7 +67,12 @@ var options = require("nomnom")
|
||||
if (options.compact) {
|
||||
var fileName = options.file? options.file + ': ' : '';
|
||||
parser.parseError = parser.lexer.parseError = function(str, hash) {
|
||||
console.error(fileName + 'line '+ hash.loc.first_line +', col '+ hash.loc.last_column +', found: \''+ hash.token +'\' - expected: '+ hash.expected.join(', ') +'.');
|
||||
// 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);
|
||||
};
|
||||
}
|
||||
@@ -90,9 +95,9 @@ function parse (source) {
|
||||
}
|
||||
}
|
||||
|
||||
return JSON.stringify(parsed,null,options.indent);
|
||||
return JSON.stringify(parsed, null, options.indent);
|
||||
} catch (e) {
|
||||
if ( options.forcePrettyPrint ) {
|
||||
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
|
||||
@@ -107,16 +112,15 @@ function parse (source) {
|
||||
if (! options.compact) {
|
||||
console.error(e);
|
||||
}
|
||||
return formatted;
|
||||
process.exit(1);
|
||||
// force the pretty print before exiting
|
||||
console.log(formatted);
|
||||
}
|
||||
} else {
|
||||
if (! options.compact) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +158,9 @@ function main (args) {
|
||||
|
||||
// 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
360
lib/doug-json-parse.js
Normal 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;
|
||||
}
|
||||
@@ -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
611
lib/nomnom.js
Normal 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
240
package-lock.json
generated
Normal 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=="
|
||||
}
|
||||
}
|
||||
}
|
||||
21
package.json
21
package.json
@@ -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.6.0",
|
||||
"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,8 +25,9 @@
|
||||
"node": ">= 0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"nomnom": ">= 1.5.x",
|
||||
"JSV": ">= 4.0.x"
|
||||
"JSV": "^4.0.2",
|
||||
"chalk": "^2.4.2",
|
||||
"underscore": "^1.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"test": "*",
|
||||
@@ -34,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": {}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
72
test/fails/35.json
Normal 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
2
test/fails/36.json
Normal file
@@ -0,0 +1,2 @@
|
||||
{"x":1,
|
||||
"x":2}
|
||||
812
web/jsonlint.js
812
web/jsonlint.js
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user