relaxed-json
Advanced tools
Comparing version 0.1.0 to 0.1.1
@@ -17,2 +17,9 @@ "use strict"; | ||
}, | ||
webcli: { | ||
src: "web/cli.js", | ||
options: { | ||
browser: true, | ||
node: false, | ||
}, | ||
}, | ||
}, | ||
@@ -19,0 +26,0 @@ }); |
{ | ||
"name": "relaxed-json", | ||
"description": "relaxed JSON is strict superset JSON, relaxing strictness of JSON format", | ||
"version": "0.1.0", | ||
"version": "0.1.1", | ||
"homepage": "https://github.com/phadej/relaxed-json", | ||
@@ -6,0 +6,0 @@ "author": { |
@@ -11,6 +11,16 @@ # Relaxed JSON | ||
* Comments are stripped : `// foo` and `/* bar */` → ` `. Comments are converted into whitespace, so your formatting is preserved. | ||
* Comments are stripped : `// foo` and `/* bar */` → ` `. | ||
Comments are converted into whitespace, so your formatting is preserved. | ||
* Trailing comma is allowed : `[1, 2, 3, ]` → `[1, 2, 3]`. Works also in objects `{ "foo": "bar", }` → `{ "foo": "bar" }`. | ||
* Identifiers are transformed into strings : `{ foo: bar }` → `{ "foo": "bar" }`. | ||
* Single quoted strings are allowed : `'say "Hello"'` → `"say \"Hello\""`. | ||
* More different characters is supported for identifiers: `foo-bar` → `"foo-bar"`. | ||
## API | ||
- `RJSON.transform(text : string) : string`. | ||
Transforms Relaxed JSON text into JSON text. Doesn't verify (parse) the JSON, i.e result JSON might be invalid as well | ||
- `RJSON.parse(text : string, reviver : function) : obj`. | ||
Parse the RJSON text, virtually `JSON.parse(JSON.transform(text), reviver)`. | ||
- `RJSON.parse2(text : string, reviver : function) : obj`. | ||
This is self-made parser function, which should act as `RJSON.parse`, but provides better error messages. |
@@ -62,3 +62,3 @@ /* | ||
raw: raw, | ||
matched: tokenSpec.f(m), | ||
matched: tokenSpec.f(m, line), | ||
}; | ||
@@ -73,8 +73,13 @@ } | ||
if (!matched) { | ||
throw new Error("Cannot tokenize on line " + line); | ||
} else { | ||
// count lines | ||
line += matched.raw.replace(/[^\n]/g, "").length; | ||
var err = new SyntaxError("Unexpected character: " + contents[0]); | ||
err.line = line; | ||
throw err; | ||
} | ||
// add line to token | ||
matched.matched.line = line; | ||
// count lines | ||
line += matched.raw.replace(/[^\n]/g, "").length; | ||
tokens.push(matched.matched); | ||
@@ -96,3 +101,3 @@ } | ||
// String in single quotes | ||
var content = m[1].replace(/([^'\\]|\\['bnrt\/]|\\u[0-9a-fA-F]{4})/g, function (m) { | ||
var content = m[1].replace(/([^'\\]|\\['bnrt\\]|\\u[0-9a-fA-F]{4})/g, function (m) { | ||
if (m === "\"") { | ||
@@ -106,8 +111,24 @@ return "\\\""; | ||
}); | ||
return { type: "string", match: "\"" + content + "\"" }; | ||
return { | ||
type: "string", | ||
match: "\"" + content + "\"", | ||
value: JSON.parse("\"" + content + "\""), // abusing real JSON.parse to unquote string | ||
}; | ||
} | ||
function fStringDouble(m) { | ||
return { | ||
type: "string", | ||
match: m[0], | ||
value: JSON.parse(m[0]), | ||
}; | ||
} | ||
function fIdentifier(m) { | ||
// identifiers are transformed into strings | ||
return { type: "string", match: "\"" + m[0].replace(/./g, function (c) { | ||
return { | ||
type: "string", | ||
value: m[0], | ||
match: "\"" + m[0].replace(/./g, function (c) { | ||
return c === "\\" ? "\\\\" : c; | ||
@@ -124,2 +145,10 @@ }) + "\"" }; | ||
function fNumber(m) { | ||
return { | ||
type : "number", | ||
match: m[0], | ||
value: parseFloat(m[0]), | ||
}; | ||
} | ||
return [ | ||
@@ -134,9 +163,9 @@ { re: /^\s+/, f: f(" ") }, | ||
{ re: /^(true|false|null)/, f: f("keyword") }, | ||
{ re: /^\-?\d+(\.\d+)?([eE][+-]?\d+)?/, f: f("number") }, | ||
{ re: /^"([^"\\]|\\["bnrt\/]|\\u[0-9a-fA-F]{4})*"/, f: f("string") }, | ||
{ re: /^\-?\d+(\.\d+)?([eE][+-]?\d+)?/, f: fNumber }, | ||
{ re: /^"([^"\\]|\\["bnrt\\]|\\u[0-9a-fA-F]{4})*"/, f: fStringDouble }, | ||
// additional stuff | ||
{ re: /^'(([^'\\]|\\['bnrt\/]|\\u[0-9a-fA-F]{4})*)'/, f: fStringSingle }, | ||
{ re: /^'(([^'\\]|\\['bnrt\\]|\\u[0-9a-fA-F]{4})*)'/, f: fStringSingle }, | ||
{ re: /^\/\/.*?\n/, f: fComment }, | ||
{ re: /^\/\*[\s\S]*?\*\//, f: fComment }, | ||
{ re: /^[a-zA-Z0-9_\-+\.\*\?!\|&%\^\\\/]+/, f: fIdentifier }, | ||
{ re: /^[a-zA-Z0-9_\-+\.\*\?!\|&%\^\/#\\]+/, f: fIdentifier }, | ||
]; | ||
@@ -147,8 +176,4 @@ }()); | ||
function transform(contents) { | ||
// Tokenize contents | ||
var tokens = lexer(contents); | ||
// remove trailing commas | ||
tokens = tokens.reduce(function (tokens, token) { | ||
function transformTokens(tokens) { | ||
return tokens.reduce(function (tokens, token) { | ||
// not so functional, js list aren't | ||
@@ -178,3 +203,11 @@ | ||
}, []); | ||
} | ||
function transform(text) { | ||
// Tokenize contents | ||
var tokens = lexer(text); | ||
// remove trailing commas | ||
tokens = transformTokens(tokens); | ||
// concat stuff | ||
@@ -186,6 +219,185 @@ return tokens.reduce(function (str, token) { | ||
function parse(text, reviver) { | ||
return JSON.parse(transform(text), reviver); | ||
} | ||
function popToken(tokens) { | ||
var token = tokens.shift(); | ||
if (!token) { | ||
var err = new SyntaxError("Unexpected end-of-file"); | ||
throw err; | ||
} | ||
return token; | ||
} | ||
function parseObject(tokens, reviver) { | ||
var token = popToken(tokens); | ||
var obj = {}; | ||
var key, colon, value; | ||
var err; | ||
switch (token.type) { | ||
case "}": | ||
return {}; | ||
case "string": | ||
key = token.value; | ||
colon = popToken(tokens); | ||
if (colon.type !== ":") { | ||
err = new SyntaxError("Unexpected token: " + colon.type + ", expected colon"); | ||
err.line = token.line; | ||
throw err; | ||
} | ||
value = parseAny(tokens, reviver); | ||
value = reviver ? reviver(key, value) : value; | ||
if (value !== undefined) { | ||
obj[key] = value; | ||
} | ||
break; | ||
default: | ||
err = new SyntaxError("Unexpected token: " + token.type + ", expected string or }"); | ||
err.line = token.line; | ||
throw err; | ||
} | ||
// Rest | ||
while (true) { | ||
token = popToken(tokens); | ||
switch (token.type) { | ||
case "}": | ||
return obj; | ||
case ",": | ||
token = popToken(tokens); | ||
if (token.type !== "string") { | ||
err = new SyntaxError("Unexpected token: " + token.type + ", expected string"); | ||
err.line = token.line; | ||
throw err; | ||
} | ||
key = token.value; | ||
colon = popToken(tokens); | ||
if (colon.type !== ":") { | ||
err = new SyntaxError("Unexpected token: " + colon.type + ", expected colon"); | ||
err.line = token.line; | ||
throw err; | ||
} | ||
value = parseAny(tokens, reviver); | ||
value = reviver ? reviver(key, value) : value; | ||
if (value !== undefined) { | ||
obj[key] = value; | ||
} | ||
break; | ||
default: | ||
err = new SyntaxError("Unexpected token: " + token.type + ", expected , or }"); | ||
err.line = token.line; | ||
throw err; | ||
} | ||
} | ||
} | ||
function parseArray(tokens, reviver) { | ||
var token = popToken(tokens); | ||
var arr = []; | ||
var key = 0, value; | ||
var err; | ||
switch (token.type) { | ||
case "]": | ||
return []; | ||
default: | ||
tokens.unshift(token); | ||
value = parseAny(tokens, reviver); | ||
arr[key] = reviver ? reviver(key, value) : value; | ||
break; | ||
} | ||
// Rest | ||
while (true) { | ||
token = popToken(tokens); | ||
switch (token.type) { | ||
case "]": | ||
return arr; | ||
case ",": | ||
key += 1; | ||
value = parseAny(tokens, reviver); | ||
arr[key] = reviver ? reviver(key, value) : value; | ||
break; | ||
default: | ||
err = new SyntaxError("Unexpected token: " + token.type + ", expected , or }"); | ||
err.line = token.line; | ||
throw err; | ||
} | ||
} | ||
} | ||
function parseAny(tokens, reviver, end) { | ||
var token = popToken(tokens); | ||
var ret; | ||
var err; | ||
switch (token.type) { | ||
case "{": | ||
ret = parseObject(tokens, reviver); | ||
ret = reviver ? reviver("", ret) : ret; | ||
break; | ||
case "[": | ||
ret = parseArray(tokens, reviver); | ||
ret = reviver ? reviver("", ret) : ret; | ||
break; | ||
case "string": | ||
case "number": | ||
ret = token.value; | ||
break; | ||
case "keyword": | ||
switch (token.match) { | ||
case "null": ret = null; break; | ||
case "true": ret = true; break; | ||
case "false": ret = false; break; | ||
} | ||
break; | ||
default: | ||
err = new SyntaxError("Unexpected token: " + token.type); | ||
err.line = token.line; | ||
throw err; | ||
} | ||
if (end && tokens.length !== 0) { | ||
err = new SyntaxError("Unexpected token: " + tokens[0].type + ", expected end-of-input"); | ||
err.line = tokens[0].line; | ||
throw err; | ||
} | ||
return ret; | ||
} | ||
function parse2(text, reviver) { | ||
// Tokenize contents | ||
var tokens = lexer(text); | ||
// remove trailing commas | ||
tokens = transformTokens(tokens); | ||
tokens = tokens.filter(function (token) { | ||
return token.type !== " "; | ||
}); | ||
// concat stuff | ||
return parseAny(tokens, reviver, true); | ||
} | ||
// Export stuff | ||
var module = { | ||
transform: transform, | ||
makeLexer: makeLexer, | ||
parse: parse, | ||
parse2: parse2, | ||
}; | ||
@@ -192,0 +404,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
2322028
23
13935
25
1