10 Commits

Author SHA1 Message Date
Zachary Carter
cb82cc205d 1.4.1 2012-05-28 12:30:28 -07:00
Zachary Carter
3899996991 update bundle script 2012-05-28 12:30:05 -07:00
Zachary Carter
14a108f3a4 fix escaping of special characters (issue #22) 2012-05-28 12:27:08 -07:00
Zachary Carter
c07fb3db3b 1.4.0 2012-05-27 14:34:50 -07:00
Zachary Carter
f88c4842ff fix Makefile 2012-05-27 14:34:29 -07:00
Zachary Carter
eca60bb22b update grammar for latest jison 2012-05-27 14:26:14 -07:00
Zachary Carter
4f24c338fa fix escaping bug with backslashes 2012-05-27 14:25:28 -07:00
Zachary Carter
f4d68f8fd1 Merge branch 'master' of github.com:zaach/jsonlint 2012-05-27 12:51:26 -07:00
Zach Carter
9eb4bd8260 add vim plugins 2012-05-27 12:41:24 -07:00
Zachary Carter
11e7192a72 appease jslint 2012-05-15 21:42:25 -07:00
10 changed files with 124 additions and 62 deletions

View File

@@ -1,14 +1,16 @@
all: build test
all: build test site
build:
jison src/jsonlint.y src/jsonlint.l
mv jsonlint.js lib/jsonlint.js
node scripts/bundle.js | uglifyjs > web/jsonlint.js
deploy:
site:
cp web/jsonlint.js ../jsonlint-pages/jsonlint.js
cd ../jsolint-pages && git commit -a -m 'deploy site updates' && git push origin gh-pages
deploy: site
cd ../jsonlint-pages && git commit -a -m 'deploy site updates' && git push origin gh-pages
test: lib/jsonlint.js test/all-tests.js
node test/all-tests.js

View File

@@ -41,6 +41,11 @@ I'm not sure why you wouldn't use the built in `JSON.parse` but you can use json
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)
## MIT License
Copyright (C) 2012 Zachary Carter

View File

@@ -87,8 +87,10 @@ 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 (Object.prototype.toString.call(o) !== '[object Object]') {
return o;
}
var sorted = {},
key, a = [];

View File

@@ -9,7 +9,15 @@ performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
var $0 = $$.length - 1;
switch (yystate) {
case 1:this.$ = yytext;
case 1: // replace escaped characters with actual character
this.$ = yytext.replace(/\\(\\|")/g, "$"+"1")
.replace(/\\n/g,'\n')
.replace(/\\r/g,'\r')
.replace(/\\t/g,'\t')
.replace(/\\v/g,'\v')
.replace(/\\f/g,'\f')
.replace(/\\b/g,'\b');
break;
case 2:this.$ = Number(yytext);
break;
@@ -86,7 +94,7 @@ parse: function parse(input) {
token = self.symbols_[token] || token;
}
return token;
};
}
var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected;
while (true) {
@@ -104,6 +112,7 @@ parse: function parse(input) {
}
// handle parse error
_handle_error:
if (typeof action === 'undefined' || !action.length || !action[0]) {
if (!recovering) {
@@ -114,7 +123,7 @@ parse: function parse(input) {
}
var errStr = '';
if (this.lexer.showPosition) {
errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+'\nExpecting '+expected.join(', ');
errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + this.terminals_[symbol]+ "'";
} else {
errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +
(symbol == 1 /*EOF*/ ? "end of input" :
@@ -228,8 +237,10 @@ parse: function parse(input) {
}
return true;
}};/* Jison generated lexer */
var lexer = (function(){var lexer = ({EOF:1,
}};
/* Jison generated lexer */
var lexer = (function(){
var lexer = ({EOF:1,
parseError:function parseError(str, hash) {
if (this.yy.parseError) {
this.yy.parseError(str, hash);
@@ -265,6 +276,9 @@ more:function () {
this._more = true;
return this;
},
less:function (n) {
this._input = this.match.slice(n) + this._input;
},
pastInput:function () {
var past = this.matched.substr(0, this.matched.length - this.match.length);
return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
@@ -289,6 +303,8 @@ next:function () {
var token,
match,
tempMatch,
index,
col,
lines;
if (!this._more) {
@@ -297,26 +313,31 @@ next:function () {
}
var rules = this._currentRules();
for (var i=0;i < rules.length; i++) {
match = this._input.match(this.rules[rules[i]]);
if (match) {
lines = match[0].match(/\n.*/g);
if (lines) this.yylineno += lines.length;
this.yylloc = {first_line: this.yylloc.last_line,
last_line: this.yylineno+1,
first_column: this.yylloc.last_column,
last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length}
this.yytext += match[0];
this.match += match[0];
this.matches = match;
this.yyleng = this.yytext.length;
this._more = false;
this._input = this._input.slice(match[0].length);
this.matched += match[0];
token = this.performAction.call(this, this.yy, this, rules[i],this.conditionStack[this.conditionStack.length-1]);
if (token) return token;
else return;
tempMatch = this._input.match(this.rules[rules[i]]);
if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
match = tempMatch;
index = i;
if (!this.options.flex) break;
}
}
if (match) {
lines = match[0].match(/\n.*/g);
if (lines) this.yylineno += lines.length;
this.yylloc = {first_line: this.yylloc.last_line,
last_line: this.yylineno+1,
first_column: this.yylloc.last_column,
last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length}
this.yytext += match[0];
this.match += match[0];
this.yyleng = this.yytext.length;
this._more = false;
this._input = this._input.slice(match[0].length);
this.matched += match[0];
token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]);
if (this.done && this._input) this.done = false;
if (token) return token;
else return;
}
if (this._input === "") {
return this.EOF;
} else {
@@ -340,20 +361,27 @@ popState:function popState() {
},
_currentRules:function _currentRules() {
return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;
},
topState:function () {
return this.conditionStack[this.conditionStack.length-2];
},
pushState:function begin(condition) {
this.begin(condition);
}});
lexer.options = {};
lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
var YYSTATE=YY_START
switch($avoiding_name_collisions) {
case 0:/* skip whitespace */
break;
case 1:return 6;
case 1:return 6
break;
case 2:yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2); return 4;
case 2:yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2); return 4
break;
case 3: return 17
case 3:return 17
break;
case 4: return 18
case 4:return 18
break;
case 5:return 23
break;
@@ -375,8 +403,12 @@ case 13:return 'INVALID'
break;
}
};
lexer.rules = [/^\s+/,/^-?([0-9]|[1-9][0-9]+)(\.[0-9]+)?([eE][-+]?[0-9]+)?\b/,/^"(\\["bfnrt/\\]|\\u[a-fA-F0-9]{4}|[^\0-\x09\x0a-\x1f"\\])*"/,/^\{/,/^\}/,/^\[/,/^\]/,/^,/,/^:/,/^true\b/,/^false\b/,/^null\b/,/^$/,/^./];
lexer.conditions = {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13],"inclusive":true}};return lexer;})()
lexer.rules = [/^(?:\s+)/,/^(?:(-?([0-9]|[1-9][0-9]+))(\.[0-9]+)?([eE][-+]?[0-9]+)?\b)/,/^(?:"(?:\\[\\"bfnrt/]|\\u[a-fA-F0-9]{4}|[^\\\0-\x09\x0a-\x1f"])*")/,/^(?:\{)/,/^(?:\})/,/^(?:\[)/,/^(?:\])/,/^(?:,)/,/^(?::)/,/^(?:true\b)/,/^(?:false\b)/,/^(?:null\b)/,/^(?:$)/,/^(?:.)/];
lexer.conditions = {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13],"inclusive":true}};
;
return lexer;})()
parser.lexer = lexer;
return parser;
})();

View File

@@ -8,7 +8,7 @@
"lint",
"jsonlint"
],
"version": "1.3.2",
"version": "1.4.1",
"preferGlobal": true,
"repository": {
"type": "git",

View File

@@ -1,9 +1,8 @@
var fs = require('fs');
var sys = require('sys');
var source = "var jsonlint = (function(){var require=true,module=false;var exports={};" +
var source = "var jsonlint = (function(){var require=true,module=false;var exports={};" +
fs.readFileSync(__dirname+'/../lib/jsonlint.js', 'utf8') +
"return exports;})()";
sys.puts(source);
console.log(source);

View File

@@ -1,23 +1,24 @@
esc "\\"
int "-"?([0-9]|[1-9][0-9]+)
exp ([eE][-+]?[0-9]+)
frac ("."[0-9]+)
exp [eE][-+]?[0-9]+
frac "."[0-9]+
%%
\s+ {/* skip whitespace */}
{int}{frac}?{exp}?\b {return 'NUMBER';}
'"'("\\"["bfnrt/{esc}]|"\\u"[a-fA-F0-9]{4}|[^\0-\x09\x0a-\x1f"{esc}])*'"' {yytext = yytext.substr(1,yyleng-2); return 'STRING';}
"{" %{ return '{' %}
"}" %{ return '}' %}
"[" {return '['}
"]" {return ']'}
"," {return ','}
":" {return ':'}
"true" {return 'TRUE'}
"false" {return 'FALSE'}
"null" {return 'NULL'}
<<EOF>> {return 'EOF'}
. {return 'INVALID'}
\s+ /* skip whitespace */
{int}{frac}?{exp}?\b return 'NUMBER'
\"(?:'\\'[\\"bfnrt/]|'\\u'[a-fA-F0-9]{4}|[^\\\0-\x09\x0a-\x1f"])*\" yytext = yytext.substr(1,yyleng-2); return 'STRING'
"{" return '{'
"}" return '}'
"[" return '['
"]" return ']'
"," return ','
":" return ':'
"true" return 'TRUE'
"false" return 'FALSE'
"null" return 'NULL'
<<EOF>> return 'EOF'
. return 'INVALID'
%%

View File

@@ -1,18 +1,23 @@
%start JSONText
/*
ECMA-262 5th Edition, 15.12.1 The JSON Grammar.
*/
/* author: Zach Carter */
%start JSONText
%%
JSONString
: STRING
{$$ = yytext;}
{ // replace escaped characters with actual character
$$ = yytext.replace(/\\(\\|")/g, "$"+"1")
.replace(/\\n/g,'\n')
.replace(/\\r/g,'\r')
.replace(/\\t/g,'\t')
.replace(/\\v/g,'\v')
.replace(/\\f/g,'\f')
.replace(/\\b/g,'\b');
}
;
JSONNumber

View File

@@ -7,9 +7,25 @@ exports["test object"] = function () {
assert.deepEqual(parser.parse(json), {"foo": "bar"});
};
exports["test escaped backslash"] = function () {
var json = '{"foo": "\\\\"}';
assert.deepEqual(parser.parse(json), {"foo": "\\"});
};
exports["test escaped chars"] = function () {
var json = '{"foo": "\\\\\\\""}';
assert.deepEqual(parser.parse(json), {"foo": '\\\"'});
};
exports["test escaped \\n"] = function () {
var json = '{"foo": "\\\\\\n"}';
assert.deepEqual(parser.parse(json), {"foo": '\\\n'});
};
exports["test string with escaped line break"] = function () {
var json = '{"foo": "bar\\nbar"}';
assert.deepEqual(parser.parse(json), {"foo": "bar\\nbar"});
assert.deepEqual(parser.parse(json), {"foo": "bar\nbar"});
assert.equal(JSON.stringify(parser.parse(json)).length, 18);
};
exports["test string with line break"] = function () {

File diff suppressed because one or more lines are too long