diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..4de517a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,7 @@ +language: node_js +node_js: + - "0.12" + - "0.11" + - "0.10" + - "iojs" + - "iojs-v1.0.4" diff --git a/README.md b/README.md index 983ff3e..1206b3c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # μson μson (uson) is a compact human-readable data serialization format especially designed for shell. -This is initial implementation in node.js. Grammar is written in [PEG](http://en.wikipedia.org/wiki/Parsing_expression_grammar) and parser is generated by [peg.js](http://pegjs.org/). +This is initial implementation written in Javascript and node.js. Grammar is written in [PEG](http://en.wikipedia.org/wiki/Parsing_expression_grammar) and parser is generated by [peg.js](http://pegjs.org/). -Inspiration by python CLI utility [jarg](https://github.com/jdp/jarg) by Justin Poliey (@jdp). +Inspired by python CLI utility [jarg](https://github.com/jdp/jarg) by Justin Poliey (@jdp). ## Example ``` @@ -45,7 +45,7 @@ or in YAML: key1:value1 key2:value2 .. ``` -Supported is all JSON types: +Supported types (JSON): * string * number * object diff --git a/bin/cli.js b/bin/cli.js index 22b4d35..c4c0589 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -8,8 +8,9 @@ var version = require('../package.json').version; program .version(version) .usage('[options] ') - .option('-p, --pretty', 'Pretty print output (only JSON)') + .option('-p, --pretty', 'Pretty print output (only JSONN)') .option('-y, --yaml', 'Use YAML dialect instead of JSON') + .option('-o, --object', 'Object mode') .parse(process.argv); if(program.args.length < 1) { @@ -19,7 +20,8 @@ if(program.args.length < 1) { }; var input = program.args.join(' '); -var output = USON.parse(input); +var options = { mode: program.object ? 'object' : null}; +var output = USON.parse(input, options); var str = null; if(program.yaml) { diff --git a/dist/parser.js b/dist/parser.js index cfcad1c..b678a10 100644 --- a/dist/parser.js +++ b/dist/parser.js @@ -33,62 +33,64 @@ module.exports = (function() { peg$startRuleFunction = peg$parsestart, peg$c0 = peg$FAILED, - peg$c1 = [], - peg$c2 = function(c) {return c}, - peg$c3 = function(head, tail) {return [head].concat(tail)}, - peg$c4 = ":", - peg$c5 = { type: "literal", value: ":", description: "\":\"" }, - peg$c6 = function(v) {return v}, - peg$c7 = function(k, tail) {return ['objectAdd', k, tail]}, - peg$c8 = "[", - peg$c9 = { type: "literal", value: "[", description: "\"[\"" }, - peg$c10 = null, - peg$c11 = "]", - peg$c12 = { type: "literal", value: "]", description: "\"]\"" }, - peg$c13 = function(k) {return k || true}, - peg$c14 = function(k, tail) {return [k, tail]}, - peg$c15 = ".", - peg$c16 = { type: "literal", value: ".", description: "\".\"" }, - peg$c17 = function(k) {return k}, - peg$c18 = /^[\-_a-zA-Z0-9]/, - peg$c19 = { type: "class", value: "[\\-_a-zA-Z0-9]", description: "[\\-_a-zA-Z0-9]" }, - peg$c20 = function(k) {return k.join('')}, - peg$c21 = "{", - peg$c22 = { type: "literal", value: "{", description: "\"{\"" }, - peg$c23 = "}", - peg$c24 = { type: "literal", value: "}", description: "\"}\"" }, - peg$c25 = /^[, ]/, - peg$c26 = { type: "class", value: "[, ]", description: "[, ]" }, - peg$c27 = function(arr) {return arr}, - peg$c28 = "true", - peg$c29 = { type: "literal", value: "true", description: "\"true\"" }, - peg$c30 = "false", - peg$c31 = { type: "literal", value: "false", description: "\"false\"" }, - peg$c32 = function(v) {return v=='true'}, - peg$c33 = "undefined", - peg$c34 = { type: "literal", value: "undefined", description: "\"undefined\"" }, - peg$c35 = function() {return undefined}, - peg$c36 = "null", - peg$c37 = { type: "literal", value: "null", description: "\"null\"" }, - peg$c38 = function() {return null}, - peg$c39 = "/", - peg$c40 = { type: "literal", value: "/", description: "\"/\"" }, - peg$c41 = /^[^\/]/, - peg$c42 = { type: "class", value: "[^\\/]", description: "[^\\/]" }, - peg$c43 = /^[i]/, - peg$c44 = { type: "class", value: "[i]", description: "[i]" }, - peg$c45 = function(pattern, flags) {return new RegExp(pattern.join(''), flags)}, - peg$c46 = /^[0-9.]/, - peg$c47 = { type: "class", value: "[0-9.]", description: "[0-9.]" }, - peg$c48 = function(v) {return parseFloat(v.join(''))}, - peg$c49 = "\"", - peg$c50 = { type: "literal", value: "\"", description: "\"\\\"\"" }, - peg$c51 = /^[^"]/, - peg$c52 = { type: "class", value: "[^\"]", description: "[^\"]" }, - peg$c53 = function(s) {return s.join('')}, - peg$c54 = function(v) {return v.join('')}, - peg$c55 = /^[\r\t\n ]/, - peg$c56 = { type: "class", value: "[\\r\\t\\n ]", description: "[\\r\\t\\n ]" }, + peg$c1 = function(head, tail) {return {type:'expr',value:head,tail:tail}}, + peg$c2 = [], + peg$c3 = /^[, ]/, + peg$c4 = { type: "class", value: "[, ]", description: "[, ]" }, + peg$c5 = function(v) {return v}, + peg$c6 = function(out) {return out}, + peg$c7 = ":", + peg$c8 = { type: "literal", value: ":", description: "\":\"" }, + peg$c9 = function(k, tail) {return {type:'objectAdd',value:[k].concat(tail)}}, + peg$c10 = "[", + peg$c11 = { type: "literal", value: "[", description: "\"[\"" }, + peg$c12 = null, + peg$c13 = "]", + peg$c14 = { type: "literal", value: "]", description: "\"]\"" }, + peg$c15 = function(k) {return k || true}, + peg$c16 = function(k, tail) {return {type:'keyExpr',value:[k].concat(tail)}}, + peg$c17 = ".", + peg$c18 = { type: "literal", value: ".", description: "\".\"" }, + peg$c19 = function(k) {return k}, + peg$c20 = function(head, tail) {return [head].concat(tail)}, + peg$c21 = /^[\-_a-zA-Z0-9]/, + peg$c22 = { type: "class", value: "[\\-_a-zA-Z0-9]", description: "[\\-_a-zA-Z0-9]" }, + peg$c23 = function(k) {return k.join('')}, + peg$c24 = "{", + peg$c25 = { type: "literal", value: "{", description: "\"{\"" }, + peg$c26 = "}", + peg$c27 = { type: "literal", value: "}", description: "\"}\"" }, + peg$c28 = function(v) {return {type:'objectAddNormal',value:v}}, + peg$c29 = function(v) {return {type:'arrayAdd',value:v}}, + peg$c30 = "true", + peg$c31 = { type: "literal", value: "true", description: "\"true\"" }, + peg$c32 = "false", + peg$c33 = { type: "literal", value: "false", description: "\"false\"" }, + peg$c34 = function(v) {return v=='true'}, + peg$c35 = "undefined", + peg$c36 = { type: "literal", value: "undefined", description: "\"undefined\"" }, + peg$c37 = function() {return undefined}, + peg$c38 = "null", + peg$c39 = { type: "literal", value: "null", description: "\"null\"" }, + peg$c40 = function() {return null}, + peg$c41 = "/", + peg$c42 = { type: "literal", value: "/", description: "\"/\"" }, + peg$c43 = /^[^\/]/, + peg$c44 = { type: "class", value: "[^\\/]", description: "[^\\/]" }, + peg$c45 = /^[i]/, + peg$c46 = { type: "class", value: "[i]", description: "[i]" }, + peg$c47 = function(pattern, flags) {return new RegExp(pattern.join(''), flags)}, + peg$c48 = /^[0-9.]/, + peg$c49 = { type: "class", value: "[0-9.]", description: "[0-9.]" }, + peg$c50 = function(v) {return parseFloat(v.join(''))}, + peg$c51 = "\"", + peg$c52 = { type: "literal", value: "\"", description: "\"\\\"\"" }, + peg$c53 = /^[^"]/, + peg$c54 = { type: "class", value: "[^\"]", description: "[^\"]" }, + peg$c55 = function(s) {return s.join('')}, + peg$c56 = function(v) {return v.join('')}, + peg$c57 = /^[\r\t\n ]/, + peg$c58 = { type: "class", value: "[\\r\\t\\n ]", description: "[\\r\\t\\n ]" }, peg$currPos = 0, peg$reportedPos = 0, @@ -257,59 +259,116 @@ module.exports = (function() { } function peg$parsestart() { - var s0, s1, s2, s3, s4, s5, s6; + var s0, s1, s2, s3; s0 = peg$currPos; s1 = peg$parsews(); if (s1 !== peg$FAILED) { s2 = peg$parsecontrol(); if (s2 !== peg$FAILED) { - s3 = []; - s4 = peg$currPos; - s5 = peg$parsews(); - if (s5 !== peg$FAILED) { - s6 = peg$parsecontrol(); - if (s6 !== peg$FAILED) { - peg$reportedPos = s4; - s5 = peg$c2(s6); - s4 = s5; + s3 = peg$parseexpr(); + if (s3 !== peg$FAILED) { + peg$reportedPos = s0; + s1 = peg$c1(s2, s3); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$c0; + } + } else { + peg$currPos = s0; + s0 = peg$c0; + } + } else { + peg$currPos = s0; + s0 = peg$c0; + } + + return s0; + } + + function peg$parseexpr() { + var s0, s1, s2, s3, s4, s5, s6; + + s0 = peg$currPos; + s1 = peg$parsews(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + s4 = peg$parsecontrol(); + if (s4 !== peg$FAILED) { + s5 = []; + if (peg$c3.test(input.charAt(peg$currPos))) { + s6 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c4); } + } + while (s6 !== peg$FAILED) { + s5.push(s6); + if (peg$c3.test(input.charAt(peg$currPos))) { + s6 = input.charAt(peg$currPos); + peg$currPos++; } else { - peg$currPos = s4; - s4 = peg$c0; + s6 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c4); } } + } + if (s5 !== peg$FAILED) { + peg$reportedPos = s3; + s4 = peg$c5(s4); + s3 = s4; } else { - peg$currPos = s4; - s4 = peg$c0; + peg$currPos = s3; + s3 = peg$c0; } - while (s4 !== peg$FAILED) { - s3.push(s4); - s4 = peg$currPos; - s5 = peg$parsews(); - if (s5 !== peg$FAILED) { - s6 = peg$parsecontrol(); - if (s6 !== peg$FAILED) { - peg$reportedPos = s4; - s5 = peg$c2(s6); - s4 = s5; + } else { + peg$currPos = s3; + s3 = peg$c0; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = peg$parsecontrol(); + if (s4 !== peg$FAILED) { + s5 = []; + if (peg$c3.test(input.charAt(peg$currPos))) { + s6 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c4); } + } + while (s6 !== peg$FAILED) { + s5.push(s6); + if (peg$c3.test(input.charAt(peg$currPos))) { + s6 = input.charAt(peg$currPos); + peg$currPos++; } else { - peg$currPos = s4; - s4 = peg$c0; + s6 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c4); } } + } + if (s5 !== peg$FAILED) { + peg$reportedPos = s3; + s4 = peg$c5(s4); + s3 = s4; } else { - peg$currPos = s4; - s4 = peg$c0; + peg$currPos = s3; + s3 = peg$c0; } + } else { + peg$currPos = s3; + s3 = peg$c0; } + } + if (s2 !== peg$FAILED) { + s3 = peg$parsews(); if (s3 !== peg$FAILED) { - s4 = peg$parsews(); - if (s4 !== peg$FAILED) { - peg$reportedPos = s0; - s1 = peg$c3(s2, s3); - s0 = s1; - } else { - peg$currPos = s0; - s0 = peg$c0; - } + peg$reportedPos = s0; + s1 = peg$c6(s2); + s0 = s1; } else { peg$currPos = s0; s0 = peg$c0; @@ -336,19 +395,19 @@ module.exports = (function() { s3 = peg$parsews(); if (s3 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 58) { - s4 = peg$c4; + s4 = peg$c7; peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c5); } + if (peg$silentFails === 0) { peg$fail(peg$c8); } } if (s4 !== peg$FAILED) { s5 = peg$parsews(); if (s5 !== peg$FAILED) { - s6 = peg$parsevalue(); + s6 = peg$parsecontrol(); if (s6 !== peg$FAILED) { peg$reportedPos = s2; - s3 = peg$c6(s6); + s3 = peg$c5(s6); s2 = s3; } else { peg$currPos = s2; @@ -368,7 +427,7 @@ module.exports = (function() { } if (s2 !== peg$FAILED) { peg$reportedPos = s0; - s1 = peg$c7(s1, s2); + s1 = peg$c9(s1, s2); s0 = s1; } else { peg$currPos = s0; @@ -394,28 +453,28 @@ module.exports = (function() { s2 = []; s3 = peg$currPos; if (input.charCodeAt(peg$currPos) === 91) { - s4 = peg$c8; + s4 = peg$c10; peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c9); } + if (peg$silentFails === 0) { peg$fail(peg$c11); } } if (s4 !== peg$FAILED) { s5 = peg$parsenestedKey(); if (s5 === peg$FAILED) { - s5 = peg$c10; + s5 = peg$c12; } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 93) { - s6 = peg$c11; + s6 = peg$c13; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c12); } + if (peg$silentFails === 0) { peg$fail(peg$c14); } } if (s6 !== peg$FAILED) { peg$reportedPos = s3; - s4 = peg$c13(s5); + s4 = peg$c15(s5); s3 = s4; } else { peg$currPos = s3; @@ -433,28 +492,28 @@ module.exports = (function() { s2.push(s3); s3 = peg$currPos; if (input.charCodeAt(peg$currPos) === 91) { - s4 = peg$c8; + s4 = peg$c10; peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c9); } + if (peg$silentFails === 0) { peg$fail(peg$c11); } } if (s4 !== peg$FAILED) { s5 = peg$parsenestedKey(); if (s5 === peg$FAILED) { - s5 = peg$c10; + s5 = peg$c12; } if (s5 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 93) { - s6 = peg$c11; + s6 = peg$c13; peg$currPos++; } else { s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c12); } + if (peg$silentFails === 0) { peg$fail(peg$c14); } } if (s6 !== peg$FAILED) { peg$reportedPos = s3; - s4 = peg$c13(s5); + s4 = peg$c15(s5); s3 = s4; } else { peg$currPos = s3; @@ -471,7 +530,7 @@ module.exports = (function() { } if (s2 !== peg$FAILED) { peg$reportedPos = s0; - s1 = peg$c14(s1, s2); + s1 = peg$c16(s1, s2); s0 = s1; } else { peg$currPos = s0; @@ -494,17 +553,17 @@ module.exports = (function() { s2 = []; s3 = peg$currPos; if (input.charCodeAt(peg$currPos) === 46) { - s4 = peg$c15; + s4 = peg$c17; peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c16); } + if (peg$silentFails === 0) { peg$fail(peg$c18); } } if (s4 !== peg$FAILED) { s5 = peg$parsekey(); if (s5 !== peg$FAILED) { peg$reportedPos = s3; - s4 = peg$c17(s5); + s4 = peg$c19(s5); s3 = s4; } else { peg$currPos = s3; @@ -518,17 +577,17 @@ module.exports = (function() { s2.push(s3); s3 = peg$currPos; if (input.charCodeAt(peg$currPos) === 46) { - s4 = peg$c15; + s4 = peg$c17; peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c16); } + if (peg$silentFails === 0) { peg$fail(peg$c18); } } if (s4 !== peg$FAILED) { s5 = peg$parsekey(); if (s5 !== peg$FAILED) { peg$reportedPos = s3; - s4 = peg$c17(s5); + s4 = peg$c19(s5); s3 = s4; } else { peg$currPos = s3; @@ -541,7 +600,7 @@ module.exports = (function() { } if (s2 !== peg$FAILED) { peg$reportedPos = s0; - s1 = peg$c3(s1, s2); + s1 = peg$c20(s1, s2); s0 = s1; } else { peg$currPos = s0; @@ -560,22 +619,22 @@ module.exports = (function() { s0 = peg$currPos; s1 = []; - if (peg$c18.test(input.charAt(peg$currPos))) { + if (peg$c21.test(input.charAt(peg$currPos))) { s2 = input.charAt(peg$currPos); peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c19); } + if (peg$silentFails === 0) { peg$fail(peg$c22); } } if (s2 !== peg$FAILED) { while (s2 !== peg$FAILED) { s1.push(s2); - if (peg$c18.test(input.charAt(peg$currPos))) { + if (peg$c21.test(input.charAt(peg$currPos))) { s2 = input.charAt(peg$currPos); peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c19); } + if (peg$silentFails === 0) { peg$fail(peg$c22); } } } } else { @@ -583,7 +642,7 @@ module.exports = (function() { } if (s1 !== peg$FAILED) { peg$reportedPos = s0; - s1 = peg$c20(s1); + s1 = peg$c23(s1); } s0 = s1; @@ -627,25 +686,25 @@ module.exports = (function() { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 123) { - s1 = peg$c21; + s1 = peg$c24; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c22); } + if (peg$silentFails === 0) { peg$fail(peg$c25); } } if (s1 !== peg$FAILED) { - s2 = peg$parsecontrol(); + s2 = peg$parseexpr(); if (s2 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 125) { - s3 = peg$c23; + s3 = peg$c26; peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c24); } + if (peg$silentFails === 0) { peg$fail(peg$c27); } } if (s3 !== peg$FAILED) { peg$reportedPos = s0; - s1 = peg$c2(s2); + s1 = peg$c28(s2); s0 = s1; } else { peg$currPos = s0; @@ -664,98 +723,29 @@ module.exports = (function() { } function peg$parsearray() { - var s0, s1, s2, s3, s4, s5, s6; + var s0, s1, s2, s3; s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 91) { - s1 = peg$c8; + s1 = peg$c10; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c9); } + if (peg$silentFails === 0) { peg$fail(peg$c11); } } if (s1 !== peg$FAILED) { - s2 = []; - s3 = peg$currPos; - s4 = peg$parsecontrol(); - if (s4 !== peg$FAILED) { - s5 = []; - if (peg$c25.test(input.charAt(peg$currPos))) { - s6 = input.charAt(peg$currPos); - peg$currPos++; - } else { - s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c26); } - } - while (s6 !== peg$FAILED) { - s5.push(s6); - if (peg$c25.test(input.charAt(peg$currPos))) { - s6 = input.charAt(peg$currPos); - peg$currPos++; - } else { - s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c26); } - } - } - if (s5 !== peg$FAILED) { - peg$reportedPos = s3; - s4 = peg$c6(s4); - s3 = s4; - } else { - peg$currPos = s3; - s3 = peg$c0; - } - } else { - peg$currPos = s3; - s3 = peg$c0; - } - while (s3 !== peg$FAILED) { - s2.push(s3); - s3 = peg$currPos; - s4 = peg$parsecontrol(); - if (s4 !== peg$FAILED) { - s5 = []; - if (peg$c25.test(input.charAt(peg$currPos))) { - s6 = input.charAt(peg$currPos); - peg$currPos++; - } else { - s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c26); } - } - while (s6 !== peg$FAILED) { - s5.push(s6); - if (peg$c25.test(input.charAt(peg$currPos))) { - s6 = input.charAt(peg$currPos); - peg$currPos++; - } else { - s6 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c26); } - } - } - if (s5 !== peg$FAILED) { - peg$reportedPos = s3; - s4 = peg$c6(s4); - s3 = s4; - } else { - peg$currPos = s3; - s3 = peg$c0; - } - } else { - peg$currPos = s3; - s3 = peg$c0; - } - } + s2 = peg$parseexpr(); if (s2 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 93) { - s3 = peg$c11; + s3 = peg$c13; peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c12); } + if (peg$silentFails === 0) { peg$fail(peg$c14); } } if (s3 !== peg$FAILED) { peg$reportedPos = s0; - s1 = peg$c27(s2); + s1 = peg$c29(s2); s0 = s1; } else { peg$currPos = s0; @@ -777,25 +767,25 @@ module.exports = (function() { var s0, s1; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c28) { - s1 = peg$c28; + if (input.substr(peg$currPos, 4) === peg$c30) { + s1 = peg$c30; peg$currPos += 4; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c29); } + if (peg$silentFails === 0) { peg$fail(peg$c31); } } if (s1 === peg$FAILED) { - if (input.substr(peg$currPos, 5) === peg$c30) { - s1 = peg$c30; + if (input.substr(peg$currPos, 5) === peg$c32) { + s1 = peg$c32; peg$currPos += 5; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c31); } + if (peg$silentFails === 0) { peg$fail(peg$c33); } } } if (s1 !== peg$FAILED) { peg$reportedPos = s0; - s1 = peg$c32(s1); + s1 = peg$c34(s1); } s0 = s1; @@ -806,16 +796,16 @@ module.exports = (function() { var s0, s1; s0 = peg$currPos; - if (input.substr(peg$currPos, 9) === peg$c33) { - s1 = peg$c33; + if (input.substr(peg$currPos, 9) === peg$c35) { + s1 = peg$c35; peg$currPos += 9; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c34); } + if (peg$silentFails === 0) { peg$fail(peg$c36); } } if (s1 !== peg$FAILED) { peg$reportedPos = s0; - s1 = peg$c35(); + s1 = peg$c37(); } s0 = s1; @@ -826,16 +816,16 @@ module.exports = (function() { var s0, s1; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c36) { - s1 = peg$c36; + if (input.substr(peg$currPos, 4) === peg$c38) { + s1 = peg$c38; peg$currPos += 4; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c37); } + if (peg$silentFails === 0) { peg$fail(peg$c39); } } if (s1 !== peg$FAILED) { peg$reportedPos = s0; - s1 = peg$c38(); + s1 = peg$c40(); } s0 = s1; @@ -847,61 +837,61 @@ module.exports = (function() { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 47) { - s1 = peg$c39; + s1 = peg$c41; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c40); } + if (peg$silentFails === 0) { peg$fail(peg$c42); } } if (s1 !== peg$FAILED) { s2 = []; - if (peg$c41.test(input.charAt(peg$currPos))) { + if (peg$c43.test(input.charAt(peg$currPos))) { s3 = input.charAt(peg$currPos); peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c42); } + if (peg$silentFails === 0) { peg$fail(peg$c44); } } while (s3 !== peg$FAILED) { s2.push(s3); - if (peg$c41.test(input.charAt(peg$currPos))) { + if (peg$c43.test(input.charAt(peg$currPos))) { s3 = input.charAt(peg$currPos); peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c42); } + if (peg$silentFails === 0) { peg$fail(peg$c44); } } } if (s2 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 47) { - s3 = peg$c39; + s3 = peg$c41; peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c40); } + if (peg$silentFails === 0) { peg$fail(peg$c42); } } if (s3 !== peg$FAILED) { s4 = []; - if (peg$c43.test(input.charAt(peg$currPos))) { + if (peg$c45.test(input.charAt(peg$currPos))) { s5 = input.charAt(peg$currPos); peg$currPos++; } else { s5 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c44); } + if (peg$silentFails === 0) { peg$fail(peg$c46); } } while (s5 !== peg$FAILED) { s4.push(s5); - if (peg$c43.test(input.charAt(peg$currPos))) { + if (peg$c45.test(input.charAt(peg$currPos))) { s5 = input.charAt(peg$currPos); peg$currPos++; } else { s5 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c44); } + if (peg$silentFails === 0) { peg$fail(peg$c46); } } } if (s4 !== peg$FAILED) { peg$reportedPos = s0; - s1 = peg$c45(s2, s4); + s1 = peg$c47(s2, s4); s0 = s1; } else { peg$currPos = s0; @@ -928,22 +918,22 @@ module.exports = (function() { s0 = peg$currPos; s1 = []; - if (peg$c46.test(input.charAt(peg$currPos))) { + if (peg$c48.test(input.charAt(peg$currPos))) { s2 = input.charAt(peg$currPos); peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c47); } + if (peg$silentFails === 0) { peg$fail(peg$c49); } } if (s2 !== peg$FAILED) { while (s2 !== peg$FAILED) { s1.push(s2); - if (peg$c46.test(input.charAt(peg$currPos))) { + if (peg$c48.test(input.charAt(peg$currPos))) { s2 = input.charAt(peg$currPos); peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c47); } + if (peg$silentFails === 0) { peg$fail(peg$c49); } } } } else { @@ -951,7 +941,7 @@ module.exports = (function() { } if (s1 !== peg$FAILED) { peg$reportedPos = s0; - s1 = peg$c48(s1); + s1 = peg$c50(s1); } s0 = s1; @@ -963,30 +953,30 @@ module.exports = (function() { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 34) { - s1 = peg$c49; + s1 = peg$c51; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c50); } + if (peg$silentFails === 0) { peg$fail(peg$c52); } } if (s1 !== peg$FAILED) { s2 = []; - if (peg$c51.test(input.charAt(peg$currPos))) { + if (peg$c53.test(input.charAt(peg$currPos))) { s3 = input.charAt(peg$currPos); peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c52); } + if (peg$silentFails === 0) { peg$fail(peg$c54); } } if (s3 !== peg$FAILED) { while (s3 !== peg$FAILED) { s2.push(s3); - if (peg$c51.test(input.charAt(peg$currPos))) { + if (peg$c53.test(input.charAt(peg$currPos))) { s3 = input.charAt(peg$currPos); peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c52); } + if (peg$silentFails === 0) { peg$fail(peg$c54); } } } } else { @@ -994,15 +984,15 @@ module.exports = (function() { } if (s2 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 34) { - s3 = peg$c49; + s3 = peg$c51; peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c50); } + if (peg$silentFails === 0) { peg$fail(peg$c52); } } if (s3 !== peg$FAILED) { peg$reportedPos = s0; - s1 = peg$c53(s2); + s1 = peg$c55(s2); s0 = s1; } else { peg$currPos = s0; @@ -1025,22 +1015,22 @@ module.exports = (function() { s0 = peg$currPos; s1 = []; - if (peg$c18.test(input.charAt(peg$currPos))) { + if (peg$c21.test(input.charAt(peg$currPos))) { s2 = input.charAt(peg$currPos); peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c19); } + if (peg$silentFails === 0) { peg$fail(peg$c22); } } if (s2 !== peg$FAILED) { while (s2 !== peg$FAILED) { s1.push(s2); - if (peg$c18.test(input.charAt(peg$currPos))) { + if (peg$c21.test(input.charAt(peg$currPos))) { s2 = input.charAt(peg$currPos); peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c19); } + if (peg$silentFails === 0) { peg$fail(peg$c22); } } } } else { @@ -1048,7 +1038,7 @@ module.exports = (function() { } if (s1 !== peg$FAILED) { peg$reportedPos = s0; - s1 = peg$c54(s1); + s1 = peg$c56(s1); } s0 = s1; @@ -1059,21 +1049,21 @@ module.exports = (function() { var s0, s1; s0 = []; - if (peg$c55.test(input.charAt(peg$currPos))) { + if (peg$c57.test(input.charAt(peg$currPos))) { s1 = input.charAt(peg$currPos); peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c56); } + if (peg$silentFails === 0) { peg$fail(peg$c58); } } while (s1 !== peg$FAILED) { s0.push(s1); - if (peg$c55.test(input.charAt(peg$currPos))) { + if (peg$c57.test(input.charAt(peg$currPos))) { s1 = input.charAt(peg$currPos); peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c56); } + if (peg$silentFails === 0) { peg$fail(peg$c58); } } } diff --git a/index.js b/index.js index d48923b..7dbed9e 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,4 @@ +var _ = require('lodash'); var parser = require('./dist/parser'); var toString = Object.prototype.toString; @@ -6,7 +7,18 @@ function nestObject(key, value) { return output; } -function TreeInterpreter() { +function TreeInterpreter(options) { + var options = options || {}; + this.expandQueue = []; + this.mode = options.mode || 'array'; +} + +TreeInterpreter.prototype.process = function(node) { + if(this.mode == 'object') { + var output = this.visit(node); + return this.visitobjectAddNormal({}, output); + } + return this.visit(node); } TreeInterpreter.prototype.visitObject = function(node) { @@ -22,34 +34,78 @@ TreeInterpreter.prototype.visitObject = function(node) { return node; } -TreeInterpreter.prototype.visit = function(node) { +TreeInterpreter.prototype.visitArray = function(node) { + var output = []; var self = this; - if(toString.call(node) === "[object Array]") { - if(node[0] == 'objectAdd') { - var output = {}; - output[node[1][0].join('.')] = self.visit(node[2]); - return self.visitObject(output); - } else if(node[0] == 'arrayAdd') { - return self.visit(node[1]); + node.forEach(function(item) { + output.push(self.visit(item)); + }); + return output; +} + +TreeInterpreter.prototype.visitobjectAdd = function(node) { + var out = {}; + var key = this.visit(node.value[0]); + out[key[0].join('.')] = this.visit(node.value[1]); + return this.visitObject(out); +} + +TreeInterpreter.prototype.visitobjectAddNormal = function(node, values) { + var values = values || this.visitArray(node.value); + var arrcount = 0; + var obj = {}; + values.forEach(function(item) { + var type = toString.call(item); + if(type == '[object Array]') { + obj[arrcount] = item; + arrcount = arrcount+1; + } else if(type == '[object Object]') { + obj = _.assign(obj, item); } else { - var output = []; - node.forEach(function(n){ - output.push(self.visit(n)); - }); - return output; + obj[arrcount] = item; + arrcount = arrcount+1; + } + }); + return obj; +} + + +TreeInterpreter.prototype.visitkeyExpr = function(node) { + return this.visit(node.value); +} + +TreeInterpreter.prototype.visitarrayAdd = function(node) { + return this.visit(node.value); +} + +TreeInterpreter.prototype.visitexpr = function(node) { + var array = [this.visit(node.value)].concat(this.visit(node.tail)); + return array; +} + +TreeInterpreter.prototype.visit = function(node) { + + var type = toString.call(node); + if(type == '[object Array]') { + return this.visitArray(node); + } else if (type == '[object Object]') { + if(!node.type) return node; + var visitMethod = this["visit"+node.type]; + if(visitMethod === undefined) { + throw new Error('No visit method: '+node.type); } - } else if (toString.call(node) === "[object]") { - return self.visitObject(node); + var out = visitMethod.call(this, node); + return out; } else { return node; } } module.exports = { - parse: function(str) { - var interpreter = new TreeInterpreter; + parse: function(str, options) { + var interpreter = new TreeInterpreter(options); var tree = parser.parse(str); - return interpreter.visit(tree); + return interpreter.process(tree); }, stringify: function() {} } diff --git a/package.json b/package.json index ab086fb..0271cca 100644 --- a/package.json +++ b/package.json @@ -27,5 +27,9 @@ "dependencies": { "commander": "^2.7.1", "js-yaml": "^3.2.7" + }, + "devDependencies": { + "assert": "^1.3.0", + "mocha": "^2.2.1" } } diff --git a/test/compliance/basic.json b/test/compliance/basic.json new file mode 100644 index 0000000..7a0b075 --- /dev/null +++ b/test/compliance/basic.json @@ -0,0 +1,69 @@ +[{ + "cases": [ + { + "expression": "a b c", + "result": { + "array": [ "a", "b", "c" ], + "object": { "0": "a", "1": "b", "2": "c" } + } + } + ] +},{ + "cases": [ + { + "expression": "[a]", + "result": { + "array": [[ "a" ]], + "object": { "0": ["a"] } + } + }, + { + "expression": "[a b c]", + "result": { + "array": [[ "a", "b", "c" ]], + "object": { "0": ["a", "b", "c"] } + } + }, + { + "expression": "[a [[b]] c]", + "result": { + "array": [[ "a",[[ "b" ]], "c" ]], + "object": { "0": ["a", [["b"]], "c"] } + } + } + ] +},{ + "cases": [ + { + "expression": "a:1 b:2 c:3", + "result": { + "array": [ {"a":1}, {"b":2}, {"c":3} ], + "object": { "a": 1, "b": 2, "c": 3 } + } + }, + { + "expression": "[a:1 b:2 c:3]", + "result": { + "array": [[ {"a":1}, {"b":2}, {"c":3} ]], + "object": { "0": [ {"a":1}, {"b":2}, {"c":3} ] } + } + } + ] +},{ + "cases": [ + { + "expression": "a:b:c:d:1", + "result": { + "array": [{"a":{"b":{"c":{"d":1}}}}], + "object": {"a":{"b":{"c":{"d":1}}}} + } + }, + { + "expression": "a:b:{c:d:1}", + "result": { + "array": [{"a":{"b":{"c":{"d":1}}}}], + "object": {"a":{"b":{"c":{"d":1}}}} + } + } + ] +}] diff --git a/test/compliance/values.json b/test/compliance/values.json new file mode 100644 index 0000000..f8b5114 --- /dev/null +++ b/test/compliance/values.json @@ -0,0 +1,48 @@ +[{ + "cases": [ + { + "expression": "1", + "result": { + "array": [ 1 ] , + "object": { "0": 1 } + } + } + ] +},{ + "cases": [ + { + "expression": "abc", + "result": { + "array": [ "abc" ] , + "object": { "0": "abc" } + } + } + ] +},{ + "cases": [ + { + "expression": "true", + "result": { + "array": [ true ] , + "object": { "0": true } + } + }, + { + "expression": "false", + "result": { + "array": [ false ] , + "object": { "0": false } + } + } + ] +},{ + "cases": [ + { + "expression": "{a:1 b:2 c:3}", + "result": { + "array": [ { "a":1, "b":2, "c":3 } ], + "object": { "0": { "a":1, "b":2, "c":3 } } + } + } + ] +}] diff --git a/test/index.js b/test/index.js new file mode 100644 index 0000000..842d32b --- /dev/null +++ b/test/index.js @@ -0,0 +1,60 @@ +var fs = require('fs'); +var path = require('path'); +var assert = require('assert'); +var USON = require('../'); + +// Compliance tests that aren't supported yet. +var notImplementedYet = []; + +function endsWith(str, suffix) { + return str.indexOf(suffix, str.length - suffix.length) !== -1; +} + +var listing = fs.readdirSync('test/compliance'); +for (var i = 0; i < listing.length; i++) { + var filename = 'test/compliance/' + listing[i]; + if (fs.statSync(filename).isFile() && endsWith(filename, '.json') && + notImplementedYet.indexOf(path.basename(filename)) === -1) { + addTestSuitesFromFile(filename); + } +} + +function addTestSuitesFromFile(filename) { + describe(filename, function() { + var spec = JSON.parse(fs.readFileSync(filename, 'utf-8')); + var modes = [ 'array', 'object' ]; + var errorMsg; + for (var i = 0; i < spec.length; i++) { + var msg = "suite " + i + " for filename " + filename; + describe(msg, function() { + var given = spec[i].given; + var cases = spec[i].cases; + for (var j = 0; j < cases.length; j++) { + var testcase = cases[j]; + for (var k = 0; k < modes.length; k++) { + var mode = modes[k]; + if (testcase.error !== undefined) { + // For now just verify that an error is thrown + // for error tests. + (function(testcase, given) { + it('should throw error for test ' + j, function() { + assert.throws( + function() { + search(given, testcase.expression); + }, Error, testcase.expression); + }); + })(testcase, given); + } else { + (function(mode, testcase, given) { + it('should pass test ' + j + " in mode '"+mode+"' expression: " + testcase.expression, function() { + assert.deepEqual(USON.parse(testcase.expression,{mode:mode}), + testcase.result[mode]); + }); + })(mode, testcase, given); + } + } + } + }); + } + }); +} diff --git a/uson.pegjs b/uson.pegjs index 778cd39..c696ae8 100644 --- a/uson.pegjs +++ b/uson.pegjs @@ -1,10 +1,12 @@ -start = ws head:control tail:(ws c:control {return c})* ws {return [head].concat(tail)} +start = ws head:control tail:expr {return {type:'expr',value:head,tail:tail}} + +expr = ws out:(v:control [, ]* {return v})* ws {return out} control - = k:keyExpr tail:(ws ':' ws v:value {return v}) {return ['objectAdd', k, tail]} + = k:keyExpr tail:(ws ':' ws v:control {return v}) {return {type:'objectAdd',value:[k].concat(tail)}} / value -keyExpr = k:nestedKey tail:('[' k:nestedKey? ']' {return k || true})* {return [k, tail]} +keyExpr = k:nestedKey tail:('[' k:nestedKey? ']' {return k || true})* {return {type:'keyExpr',value:[k].concat(tail)}} nestedKey = head:key tail:('.' k:key {return k})* {return [head].concat(tail)} @@ -21,9 +23,9 @@ value / quotedString / string -object = '{' c:control '}' {return c} +object = '{' v:expr '}' {return {type:'objectAddNormal',value:v}} -array = '[' arr:(v:control [, ]* {return v})* ']' {return arr} +array = '[' v:expr ']' {return {type:'arrayAdd',value:v}} boolean = v:('true' / 'false') {return v=='true'}