Socket
Socket
Sign inDemoInstall

relaxed-json

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

relaxed-json - npm Package Compare versions

Comparing version 0.1.1 to 0.2.0

.travis.yml

82

Gruntfile.js

@@ -7,14 +7,21 @@ "use strict";

grunt.initConfig({
pkg: grunt.file.readJSON("package.json"),
jshint: {
options: {
jshintrc: ".jshintrc"
jshintrc: ".jshintrc",
},
gruntfile: {
src: "Gruntfile.js"
src: "Gruntfile.js",
},
src: {
src: "relaxed-json.js"
src: "relaxed-json.js",
options: {
node: false,
},
},
test: {
src: "test/**/*.js",
},
webcli: {
src: "web/cli.js",
src: "web.js",
options: {

@@ -26,2 +33,63 @@ browser: true,

},
simplemocha: {
options: {
timeout: 3000,
ui: "bdd",
reporter: "spec"
},
all: { src: "test/**/*.js" }
},
uglify: {
core: {
src: "relaxed-json.js",
dest: "relaxed-json.min.js",
options: {
sourceMap: "relaxed-json.min.js.map",
report: "min",
},
},
web: {
src: [
"components/codemirror.js",
"components/cm-mode-javascript.js",
"components/jquery-2.0.3.js",
"relaxed-json.js",
"web.js",
],
dest: "web.min.js",
options: {
sourceMap: "web.min.js.map",
report: "min",
},
}
},
less: {
web: {
src: [
"web.less",
],
dest: "web.min.css",
options: {
report: "min",
compress: true,
strictMath: true,
strictImports: true,
strictUnits: true,
syncImport: true,
sourceMap: true,
sourceMapFilename: "web.min.css.map",
}
},
},
watch: {
less: {
files: "<%= less.web.src %>",
tasks: ["less"],
},
uglify: {
files: "<%= uglify.web.src %>",
tasks: ["uglify:web"],
},
},
});

@@ -31,5 +99,9 @@

grunt.loadNpmTasks("grunt-contrib-jshint");
grunt.loadNpmTasks("grunt-contrib-uglify");
grunt.loadNpmTasks("grunt-contrib-less");
grunt.loadNpmTasks("grunt-contrib-watch");
grunt.loadNpmTasks("grunt-simple-mocha");
// Default task.
grunt.registerTask("default", ["jshint"]);
grunt.registerTask("default", ["jshint", "simplemocha"]);
};

12

package.json
{
"name": "relaxed-json",
"description": "relaxed JSON is strict superset JSON, relaxing strictness of JSON format",
"version": "0.1.1",
"description": "Relaxed JSON is strict superset JSON, relaxing strictness of valilla JSON",
"version": "0.2.0",
"homepage": "https://github.com/phadej/relaxed-json",

@@ -33,3 +33,9 @@ "author": {

"grunt-contrib-jshint": "~0.6.4",
"grunt": "~0.4.1"
"grunt": "~0.4.1",
"grunt-contrib-watch": "~0.5.3",
"grunt-contrib-uglify": "~0.2.5",
"grunt-contrib-less": "~0.8.1",
"grunt-simple-mocha": "~0.4.0",
"jsverify": "~0.1.2",
"underscore": "~1.5.2"
},

@@ -36,0 +42,0 @@ "keywords": [

# Relaxed JSON
Are you frustrated that you cannot add comments into your example JSON
structure or easily strip them? Relaxed JSON is a simple solution. Small
JavaScript library with only one exposed function `EJSON.transform /* string → string */`.
[![Build Status](https://secure.travis-ci.org/phadej/jsverify.png?branch=master)](http://travis-ci.org/phadej/jsverify)
[![NPM version](https://badge.fury.io/js/relaxed-json.png)](http://badge.fury.io/js/relaxed-json)
[Relaxed JSON](http://oleg.fi/relaxed-json) (modified BSD license) is a strict superset of JSON. Valid JSON
will not be changed by `RJSON.transform`. But in addition there are few
extensions helping writing JSON by hand.
Are you frustrated that you cannot add comments into your configuration JSON
Relaxed JSON is a simple solution.
Small JavaScript library with only one exposed function `RJSON.transform(text : string) : string`
(and few convenient helpers).
[Relaxed JSON](http://oleg.fi/relaxed-json) (modified BSD license) is a strict superset of JSON,
relaxing strictness of valilla JSON.
Valid, vanilla JSON will not be changed by `RJSON.transform`. But there are few additional
features helping writing JSON by hand.
* Comments are stripped : `// foo` and `/* bar */` → ` `.

@@ -16,3 +21,3 @@ Comments are converted into whitespace, so your formatting is preserved.

* Single quoted strings are allowed : `'say "Hello"'` → `"say \"Hello\""`.
* More different characters is supported for identifiers: `foo-bar` → `"foo-bar"`.
* More different characters is supported in identifiers: `foo-bar` → `"foo-bar"`.

@@ -23,5 +28,8 @@ ## API

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`.
- `RJSON.parse(text : string, reviver : function | opts : obj) : 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.
You could pass a reviver function or an options object as the second argument. Supported options:
- `reviver`: you could still pass a reviver
- `relaxed`: use relaxed version of JSON (default: true)
- `warnings`: use relaxed JSON own parser, supports better error messages (default: false).
- `duplicate`: fail if there are duplicate keys in objects

@@ -35,7 +35,3 @@ /*

function some(array, f) {
if (array.length === 0) {
return false;
}
var acc;
var acc = false;
for (var i = 0; i < array.length; i++) {

@@ -91,3 +87,3 @@ acc = f(array[i], i, array);

var tokenSpecs = (function (){
function tokenSpecs(relaxed) {
function f(type) {

@@ -101,3 +97,3 @@ return function(m) {

// String in single quotes
var content = m[1].replace(/([^'\\]|\\['bnrt\\]|\\u[0-9a-fA-F]{4})/g, function (m) {
var content = m[1].replace(/([^'\\]|\\['bnrtf\\]|\\u[0-9a-fA-F]{4})/g, function (m) {
if (m === "\"") {

@@ -152,3 +148,17 @@ return "\\\"";

return [
function fKeyword(m) {
var value;
switch (m[1]) {
case "null": value = null; break;
case "true": value = true; break;
case "false": value = false; break;
}
return {
type: "atom",
match: m[0],
value: value,
};
}
var ret = [
{ re: /^\s+/, f: f(" ") },

@@ -161,15 +171,23 @@ { re: /^\{/, f: f("{") },

{ re: /^:/, f: f(":") },
{ re: /^(true|false|null)/, f: f("keyword") },
{ re: /^(true|false|null)/, f: fKeyword },
{ 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: /^\/\/.*?\n/, f: fComment },
{ re: /^\/\*[\s\S]*?\*\//, f: fComment },
{ re: /^[a-zA-Z0-9_\-+\.\*\?!\|&%\^\/#\\]+/, f: fIdentifier },
{ re: /^"([^"\\]|\\["bnrtf\\]|\\u[0-9a-fA-F]{4})*"/, f: fStringDouble },
];
}());
var lexer = makeLexer(tokenSpecs);
// additional stuff
if (relaxed) {
ret = ret.concat([
{ re: /^'(([^'\\]|\\['bnrtf\\]|\\u[0-9a-fA-F]{4})*)'/, f: fStringSingle },
{ re: /^\/\/.*?\n/, f: fComment },
{ re: /^\/\*[\s\S]*?\*\//, f: fComment },
{ re: /^[a-zA-Z0-9_\-+\.\*\?!\|&%\^\/#\\]+/, f: fIdentifier },
]);
}
return ret;
}
var lexer = makeLexer(tokenSpecs(true));
var strictLexer = makeLexer(tokenSpecs(false));
function transformTokens(tokens) {

@@ -216,21 +234,92 @@ return tokens.reduce(function (tokens, token) {

function parse(text, reviver) {
return JSON.parse(transform(text), reviver);
}
function popToken(tokens, state) {
var token = tokens[state.pos];
state.pos += 1;
function popToken(tokens) {
var token = tokens.shift();
if (!token) {
var err = new SyntaxError("Unexpected end-of-file");
throw err;
var line = tokens.length !== 0 ? tokens[tokens.length - 1].line : 1;
return { type: "eof", line: line };
}
return token;
}
function parseObject(tokens, reviver) {
var token = popToken(tokens);
function strToken(token) {
switch (token.type) {
case "atom":
case "string":
case "number":
return token.type + " " + token.match;
case "eof":
return "end-of-file";
default:
return token.type;
}
}
function skipColon(tokens, state) {
var colon = popToken(tokens, state);
if (colon.type !== ":") {
var message = "Unexpected token: " + strToken(colon) + ", expected ':'";
if (state.tolerant) {
state.warnings.push({
message: message,
line: colon.line,
});
state.pos -= 1;
} else {
var err = new SyntaxError(message);
err.line = colon.line;
throw err;
}
}
}
function parseObject(tokens, state) {
var token = popToken(tokens, state);
var obj = {};
var key, colon, value;
var key, value;
var err;
var message;
if (token.type !== "}" && token.type !== "string") {
message = "Unexpected token: " + strToken(token) + ", expected '}' or string";
if (state.tolerant) {
state.warnings.push({
message: message,
line: token.line,
});
if (token.type !== "eof" && token.type !== "number" && token.type !== "atom") {
state.pos -= 1;
}
if (token.type === "number" || token.type === "atom") {
token = {
type: "string",
value: ""+token.value,
line: token.line,
};
} else if (token.type === "eof") {
token = {
type: "}",
line: token.line,
};
} else {
token = {
type: "string",
value: "null",
line: token.line,
};
}
} else {
err = new SyntaxError(message);
err.line = token.line;
throw err;
}
}
switch (token.type) {

@@ -242,11 +331,6 @@ case "}":

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);
skipColon(tokens, state);
value = parseAny(tokens, state);
value = reviver ? reviver(key, value) : value;
value = state.reviver ? state.reviver(key, value) : value;
if (value !== undefined) {

@@ -256,7 +340,2 @@ obj[key] = value;

break;
default:
err = new SyntaxError("Unexpected token: " + token.type + ", expected string or }");
err.line = token.line;
throw err;
}

@@ -266,4 +345,26 @@

while (true) {
token = popToken(tokens);
token = popToken(tokens, state);
if (token.type !== "}" && token.type !== ",") {
message = "Unexpected token: " + strToken(token) + ", expected ',' or ']'";
var newtype = token.type === "eof" ? "}" : ",";
if (state.tolerant) {
state.warnings.push({
message: message + "; assuming '" + newtype + "'",
line: token.line,
});
token = {
type: newtype,
line: token.line,
};
state.pos -= 1;
} else {
err = new SyntaxError(message);
err.line = token.line;
throw err;
}
}
switch (token.type) {

@@ -274,18 +375,53 @@ case "}":

case ",":
token = popToken(tokens);
token = popToken(tokens, state);
if (token.type !== "string") {
err = new SyntaxError("Unexpected token: " + token.type + ", expected string");
err.line = token.line;
throw err;
message = "Unexpected token: " + strToken(token) + ", expected string";
if (state.tolerant) {
state.warnings.push({
message: message,
line: token.line,
});
if (token.type === "number" || token.type === "atom") {
token = {
type: "string",
value: "" + token.value,
line: token.line,
};
} else {
token = {
type: "string",
value: "null",
line: token.line,
};
state.pos -= 1;
}
} else {
err = new SyntaxError(message);
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;
if (state.duplicate && Object.prototype.hasOwnProperty.call(obj, key)) {
message = "Duplicate key: " + key;
if (state.tolerant) {
state.warnings.push({
message: message,
line: token.line,
});
} else {
err = new SyntaxError(message);
err.line = token.line;
throw err;
}
}
value = parseAny(tokens, reviver);
value = reviver ? reviver(key, value) : value;
skipColon(tokens, state);
value = parseAny(tokens, state);
value = state.reviver ? state.reviver(key, value) : value;
if (value !== undefined) {

@@ -295,7 +431,2 @@ obj[key] = value;

break;
default:
err = new SyntaxError("Unexpected token: " + token.type + ", expected , or }");
err.line = token.line;
throw err;
}

@@ -305,8 +436,17 @@ }

function parseArray(tokens, reviver) {
var token = popToken(tokens);
function parseArray(tokens, state) {
var token = popToken(tokens, state);
var arr = [];
var key = 0, value;
var err;
var message;
if (state.tolerant && token.type === "eof") {
state.warnings.push({
message: "Unexpected token: " + strToken(token) + ", expected ']' or json object",
line: token.line,
});
token.type = "]";
}
switch (token.type) {

@@ -317,6 +457,6 @@ case "]":

default:
tokens.unshift(token);
value = parseAny(tokens, reviver);
state.pos -= 1; // push the token back
value = parseAny(tokens, state);
arr[key] = reviver ? reviver(key, value) : value;
arr[key] = state.reviver ? state.reviver("" + key, value) : value;
break;

@@ -327,4 +467,26 @@ }

while (true) {
token = popToken(tokens);
token = popToken(tokens, state);
if (token.type !== "]" && token.type !== ",") {
message = "Unexpected token: " + strToken(token) + ", expected ',' or ']'";
var newtype = token.type === "eof" ? "]" : ",";
if (state.tolerant) {
state.warnings.push({
message: message + "; assuming '" + newtype + "'",
line: token.line,
});
token = {
type: newtype,
line: token.line,
};
state.pos -= 1;
} else {
err = new SyntaxError(message);
err.line = token.line;
throw err;
}
}
switch (token.type) {

@@ -336,10 +498,5 @@ case "]":

key += 1;
value = parseAny(tokens, reviver);
arr[key] = reviver ? reviver(key, value) : value;
value = parseAny(tokens, state);
arr[key] = state.reviver ? state.reviver("" + key, value) : value;
break;
default:
err = new SyntaxError("Unexpected token: " + token.type + ", expected , or }");
err.line = token.line;
throw err;
}

@@ -349,36 +506,60 @@ }

function parseAny(tokens, reviver, end) {
var token = popToken(tokens);
function parseAny(tokens, state, end) {
var token = popToken(tokens, state);
var ret;
var err;
var message;
switch (token.type) {
case "{":
ret = parseObject(tokens, reviver);
ret = reviver ? reviver("", ret) : ret;
ret = parseObject(tokens, state);
break;
case "[":
ret = parseArray(tokens, reviver);
ret = reviver ? reviver("", ret) : ret;
ret = parseArray(tokens, state);
break;
case "string":
case "number":
case "atom":
ret = token.value;
break;
case "keyword":
switch (token.match) {
case "null": ret = null; break;
case "true": ret = true; break;
case "false": ret = false; break;
default:
message = "Unexpected token: " + strToken(token) + ", expected '[', '{', number, string or atom";
if (state.tolerant) {
state.warnings.push({
message: message + "; assuming null",
line: token.line,
});
ret = null;
} else {
err = new SyntaxError();
err.line = token.line;
throw err;
}
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;
if (end) {
ret = state.reviver ? state.reviver("", ret) : ret;
}
if (end && state.pos < tokens.length) {
message = "Unexpected token: " + strToken(tokens[state.pos]) + ", expected end-of-input";
if (state.tolerant) {
state.warnings.push({
message: message,
line: tokens[state.pos].line,
});
} else {
err = new SyntaxError(message);
err.line = tokens[state.pos].line;
throw err;
}
}
// Throw error at the end
if (end && state.tolerant && state.warnings.length !== 0) {
message = state.warnings.length === 1 ? state.warnings[0].message : state.warnings.length + " parse warnings";
err = new SyntaxError(message);
err.line = state.warnings[0].line;
err.warnings = state.warnings;
err.obj = ret;
throw err;

@@ -390,35 +571,54 @@ }

function parse2(text, reviver) {
// Tokenize contents
var tokens = lexer(text);
function parse(text, opts) {
if (typeof opts === "function" || opts === undefined) {
return JSON.parse(transform(text), opts);
} else if (new Object(opts) !== opts) {
throw new TypeError("opts/reviver should be undefined, a function or an object");
}
// remove trailing commas
tokens = transformTokens(tokens);
opts.relaxed = opts.relaxed !== undefined ? opts.relaxed : true;
opts.warnings = opts.warnings || opts.tolerant || false;
opts.tolerant = opts.tolerant || false;
opts.duplicate = opts.duplicate || false;
tokens = tokens.filter(function (token) {
return token.type !== " ";
});
if (!opts.warnings && !opts.relaxed) {
return JSON.parse(text, opts.reviver);
}
// concat stuff
return parseAny(tokens, reviver, true);
var tokens = opts.relaxed ? lexer(text) : strictLexer(text);
if (opts.relaxed) {
// Strip commas
tokens = transformTokens(tokens);
}
if (opts.warnings) {
// Strip whitespace
tokens = tokens.filter(function (token) {
return token.type !== " ";
});
var state = { pos: 0, reviver: opts.reviver, tolerant: opts.tolerant, duplicate: opts.duplicate, warnings: [] };
return parseAny(tokens, state, true);
} else {
var newtext = tokens.reduce(function (str, token) {
return str + token.match;
}, "");
return JSON.parse(newtext, opts.reviver);
}
}
// Export stuff
var module = {
var RJSON = {
transform: transform,
parse: parse,
parse2: parse2,
};
/* global window, exports */
/* global window, module */
if (typeof window !== "undefined") {
window.RJSON = module;
} else if (typeof exports !== "undefined") {
for (var k in module) {
// Check to make jshint happy
if (Object.prototype.hasOwnProperty.call(module, k)) {
exports[k] = module[k];
}
}
window.RJSON = RJSON;
} else if (typeof module !== "undefined") {
module.exports = RJSON;
}
}());

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc