🚀 Big News:Socket Has Acquired Secure Annex.Learn More
Socket
Book a DemoSign in
Socket

next-json

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

next-json - npm Package Compare versions

Comparing version
0.4.0
to
0.5.0
+39
-23
dist/cjs/index.js

@@ -6,6 +6,7 @@ "use strict";

exports.fetchNJSON = fetchNJSON;
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
const parser_1 = require("./parser");
function parse(text, options) {
try {
const result = (0, parser_1.parse)(text, { grammarSource: "", offset: 0, ...options });
const result = (0, parser_1.parse)(text, { grammarSource: "", offset: 0, ...(typeof options === "function" ? undefined : options) });
if (typeof options === "function")

@@ -20,3 +21,3 @@ options = { reviver: options };

function revive(context, key, value, skip, skipNext) {
if (value && typeof value === "object" && !(value instanceof Date) && !(value instanceof RegExp) && !(value instanceof URL) && !ArrayBuffer.isView(value) && references.indexOf(value) === -1) {
if (value && typeof value === "object" && !(value instanceof Date) && !(value instanceof RegExp) && !(value instanceof URL) && !ArrayBuffer.isView(value) && !references.includes(value)) {
references.push(value);

@@ -182,3 +183,2 @@ if (value instanceof Array)

const indent = space;
const twoIndent = indent + indent;
function getIdentifier() {

@@ -231,21 +231,30 @@ const { length } = letters;

if (value instanceof Array) {
let args = [];
const elements = [];
let elems = elements;
let push = -1;
for (const [i, _] of value.entries())
elements.push(replace(value, numberKey ? i : i.toString(), _, skipNext));
function stringify(currIndent, body, first) {
if (this.identifier && body)
if (this.already && this.identifier && body)
return this.identifier;
if (first) {
const push = elements.findIndex(_ => !_.argument());
push = elements.findIndex(_ => !_.argument());
if (push !== -1) {
elems = elements.slice(0, push);
const args = elements.slice(push, elements.length);
this.statement = function () {
return `${indent}${this.identifier}.push(${newLine}${args.map(_ => twoIndent + _.stringify(twoIndent, true)).join("," + newLine)}${newLine}${indent})`;
};
args = elements.slice(push, elements.length);
}
}
const nextIndent = currIndent + indent;
return elems.length ? `[${newLine}${elems.map(_ => nextIndent + _.stringify(nextIndent, body)).join("," + newLine)}${newLine}${currIndent}]` : "[]";
if (!this.already && this.identifier && body) {
this.already = true;
if (args.length) {
const nextNextIndent = nextIndent + indent;
return `Object.assign(${newLine}${nextIndent}${this.identifier},${newLine}${nextIndent}{${newLine}${args
.map((_, i) => `${nextNextIndent}"${i + push}":${separator}${_.stringify(nextNextIndent, true)}`)
.join(`,${newLine}`)}${newLine}${nextIndent}}${newLine}${currIndent})`;
}
return this.identifier;
}
return elems.length ? `[${newLine}${elems.map(_ => nextIndent + _.stringify(nextIndent, body)).join(`,${newLine}`)}${newLine}${currIndent}]` : "[]";
}

@@ -290,3 +299,3 @@ rest = { argument, elements, stringify };

}
return elems.length ? `new Map([${newLine}${elems.map(_ => nextIndent + _.stringify(nextIndent, body)).join("," + newLine)}${newLine}${currIndent}])` : "new Map()";
return elems.length ? `new Map([${newLine}${elems.map(_ => nextIndent + _.stringify(nextIndent, body)).join(`,${newLine}`)}${newLine}${currIndent}])` : "new Map()";
}

@@ -322,3 +331,3 @@ rest = { argument, elements, stringify };

}
return elems.length ? `new Set([${newLine}${elems.map(_ => nextIndent + _.stringify(nextIndent, body)).join("," + newLine)}${newLine}${currIndent}])` : "new Set()";
return elems.length ? `new Set([${newLine}${elems.map(_ => nextIndent + _.stringify(nextIndent, body)).join(`,${newLine}`)}${newLine}${currIndent}])` : "new Set()";
}

@@ -332,8 +341,11 @@ rest = { argument, elements, stringify };

}
// eslint-disable-next-line no-case-declarations
const id = typedArrays.findIndex(_ => value instanceof _);
if (id !== -1) {
const { name, prototype: { toString } } = typedArrays[id];
const { name,
// eslint-disable-next-line @typescript-eslint/unbound-method
prototype: { toString } } = typedArrays[id];
const bigint = value instanceof BigInt64Array || value instanceof BigUint64Array;
const stringified = toString.call(value);
rest = nativeRef(stringified.length ? `new ${name}([${bigint ? stringified.replace(/,/g, "n,") + "n" : stringified}])` : `new ${name}()`);
rest = nativeRef(stringified.length ? `new ${name}([${bigint ? `${stringified.replace(/,/g, "n,")}n` : stringified}])` : `new ${name}()`);
}

@@ -369,3 +381,3 @@ else {

for (const [key, val] of entries) {
if (["cause", "message", "name", "stack"].indexOf(key) === -1) {
if (!["cause", "message", "name", "stack"].includes(key)) {
const replaced = replace(value, key, val);

@@ -394,3 +406,3 @@ if (!replaced.exclude)

.map(_ => `${nextNextIndent}${JSON.stringify(_[0])}:${separator}${_[1].stringify(nextNextIndent, body)}`)
.join("," + newLine)}${newLine}${nextIndent}}${newLine}${currIndent})`;
.join(`,${newLine}`)}${newLine}${nextIndent}}${newLine}${currIndent})`;
if (!this.already && this.identifier && body) {

@@ -425,8 +437,11 @@ this.already = true;

.map(_ => `${nextNextIndent}${JSON.stringify(_[0])}:${separator}${_[1].stringify(nextNextIndent, true)}`)
.join("," + newLine)}${newLine}${nextIndent}}${newLine}${currIndent})`;
.join(`,${newLine}`)}${newLine}${nextIndent}}${newLine}${currIndent})`;
}
return this.identifier;
}
const wrapped = this.main && body;
const open = wrapped ? "(" : "";
const close = wrapped ? ")" : "";
return elems.length
? `{${newLine}${elems.map(_ => `${nextIndent}${JSON.stringify(_[0])}:${separator}${_[1].stringify(nextIndent, body)}`).join("," + newLine)}${newLine}${currIndent}}`
? `${open}{${newLine}${elems.map(_ => `${nextIndent}${JSON.stringify(_[0])}:${separator}${_[1].stringify(nextIndent, body)}`).join(`,${newLine}`)}${newLine}${currIndent}}${close}`
: "{}";

@@ -449,3 +464,3 @@ }

case "bigint":
return nativeRef(value.toString() + "n");
return nativeRef(`${value.toString()}n`);
case "boolean":

@@ -467,2 +482,3 @@ case "number":

return undefined;
replaced.main = true;
const identifiers = Array.from(references.values())

@@ -474,5 +490,3 @@ .filter(_ => _.identifier)

const args = identifiers.map(_ => _.stringify(indent, false, true));
const statements = identifiers.filter(_ => _.statement).map(_ => _.statement());
statements.push(`${indent}return ${replaced.stringify(indent, true)}`);
return (`((${identifiers.map(_ => _.identifier).join("," + separator)})${separator}=>${separator}{${newLine}${statements.join(";" + newLine)}${newLine}})` +
return (`((${identifiers.map(_ => _.identifier).join(`,${separator}`)})${separator}=>${newLine}${indent}${replaced.stringify(indent, true)}${newLine})` +
`(${newLine}${indent}${args.join(`,${newLine}${indent}`)}${newLine})`);

@@ -496,2 +510,3 @@ }

};
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
if (req._body || req.headers["content-type"] !== "application/njson")

@@ -503,2 +518,3 @@ return next();

try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
req.body = exports.NJSON.parse(Buffer.concat(chunks).toString(req.headers["content-encoding"] || "utf8"), parse);

@@ -521,3 +537,3 @@ req._body = true;

const _options = options;
if (Response && Response.prototype) {
if (Response === null || Response === void 0 ? void 0 : Response.prototype) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any

@@ -524,0 +540,0 @@ Response.prototype.njson = async function njson(options) {

@@ -0,5 +1,6 @@

/* eslint-disable @typescript-eslint/no-unnecessary-condition */
import { NJSONError, parse as parser } from "./parser.js";
function parse(text, options) {
try {
const result = parser(text, { grammarSource: "", offset: 0, ...options });
const result = parser(text, { grammarSource: "", offset: 0, ...(typeof options === "function" ? undefined : options) });
if (typeof options === "function")

@@ -14,3 +15,3 @@ options = { reviver: options };

function revive(context, key, value, skip, skipNext) {
if (value && typeof value === "object" && !(value instanceof Date) && !(value instanceof RegExp) && !(value instanceof URL) && !ArrayBuffer.isView(value) && references.indexOf(value) === -1) {
if (value && typeof value === "object" && !(value instanceof Date) && !(value instanceof RegExp) && !(value instanceof URL) && !ArrayBuffer.isView(value) && !references.includes(value)) {
references.push(value);

@@ -176,3 +177,2 @@ if (value instanceof Array)

const indent = space;
const twoIndent = indent + indent;
function getIdentifier() {

@@ -225,21 +225,30 @@ const { length } = letters;

if (value instanceof Array) {
let args = [];
const elements = [];
let elems = elements;
let push = -1;
for (const [i, _] of value.entries())
elements.push(replace(value, numberKey ? i : i.toString(), _, skipNext));
function stringify(currIndent, body, first) {
if (this.identifier && body)
if (this.already && this.identifier && body)
return this.identifier;
if (first) {
const push = elements.findIndex(_ => !_.argument());
push = elements.findIndex(_ => !_.argument());
if (push !== -1) {
elems = elements.slice(0, push);
const args = elements.slice(push, elements.length);
this.statement = function () {
return `${indent}${this.identifier}.push(${newLine}${args.map(_ => twoIndent + _.stringify(twoIndent, true)).join("," + newLine)}${newLine}${indent})`;
};
args = elements.slice(push, elements.length);
}
}
const nextIndent = currIndent + indent;
return elems.length ? `[${newLine}${elems.map(_ => nextIndent + _.stringify(nextIndent, body)).join("," + newLine)}${newLine}${currIndent}]` : "[]";
if (!this.already && this.identifier && body) {
this.already = true;
if (args.length) {
const nextNextIndent = nextIndent + indent;
return `Object.assign(${newLine}${nextIndent}${this.identifier},${newLine}${nextIndent}{${newLine}${args
.map((_, i) => `${nextNextIndent}"${i + push}":${separator}${_.stringify(nextNextIndent, true)}`)
.join(`,${newLine}`)}${newLine}${nextIndent}}${newLine}${currIndent})`;
}
return this.identifier;
}
return elems.length ? `[${newLine}${elems.map(_ => nextIndent + _.stringify(nextIndent, body)).join(`,${newLine}`)}${newLine}${currIndent}]` : "[]";
}

@@ -284,3 +293,3 @@ rest = { argument, elements, stringify };

}
return elems.length ? `new Map([${newLine}${elems.map(_ => nextIndent + _.stringify(nextIndent, body)).join("," + newLine)}${newLine}${currIndent}])` : "new Map()";
return elems.length ? `new Map([${newLine}${elems.map(_ => nextIndent + _.stringify(nextIndent, body)).join(`,${newLine}`)}${newLine}${currIndent}])` : "new Map()";
}

@@ -316,3 +325,3 @@ rest = { argument, elements, stringify };

}
return elems.length ? `new Set([${newLine}${elems.map(_ => nextIndent + _.stringify(nextIndent, body)).join("," + newLine)}${newLine}${currIndent}])` : "new Set()";
return elems.length ? `new Set([${newLine}${elems.map(_ => nextIndent + _.stringify(nextIndent, body)).join(`,${newLine}`)}${newLine}${currIndent}])` : "new Set()";
}

@@ -326,8 +335,11 @@ rest = { argument, elements, stringify };

}
// eslint-disable-next-line no-case-declarations
const id = typedArrays.findIndex(_ => value instanceof _);
if (id !== -1) {
const { name, prototype: { toString } } = typedArrays[id];
const { name,
// eslint-disable-next-line @typescript-eslint/unbound-method
prototype: { toString } } = typedArrays[id];
const bigint = value instanceof BigInt64Array || value instanceof BigUint64Array;
const stringified = toString.call(value);
rest = nativeRef(stringified.length ? `new ${name}([${bigint ? stringified.replace(/,/g, "n,") + "n" : stringified}])` : `new ${name}()`);
rest = nativeRef(stringified.length ? `new ${name}([${bigint ? `${stringified.replace(/,/g, "n,")}n` : stringified}])` : `new ${name}()`);
}

@@ -363,3 +375,3 @@ else {

for (const [key, val] of entries) {
if (["cause", "message", "name", "stack"].indexOf(key) === -1) {
if (!["cause", "message", "name", "stack"].includes(key)) {
const replaced = replace(value, key, val);

@@ -388,3 +400,3 @@ if (!replaced.exclude)

.map(_ => `${nextNextIndent}${JSON.stringify(_[0])}:${separator}${_[1].stringify(nextNextIndent, body)}`)
.join("," + newLine)}${newLine}${nextIndent}}${newLine}${currIndent})`;
.join(`,${newLine}`)}${newLine}${nextIndent}}${newLine}${currIndent})`;
if (!this.already && this.identifier && body) {

@@ -419,8 +431,11 @@ this.already = true;

.map(_ => `${nextNextIndent}${JSON.stringify(_[0])}:${separator}${_[1].stringify(nextNextIndent, true)}`)
.join("," + newLine)}${newLine}${nextIndent}}${newLine}${currIndent})`;
.join(`,${newLine}`)}${newLine}${nextIndent}}${newLine}${currIndent})`;
}
return this.identifier;
}
const wrapped = this.main && body;
const open = wrapped ? "(" : "";
const close = wrapped ? ")" : "";
return elems.length
? `{${newLine}${elems.map(_ => `${nextIndent}${JSON.stringify(_[0])}:${separator}${_[1].stringify(nextIndent, body)}`).join("," + newLine)}${newLine}${currIndent}}`
? `${open}{${newLine}${elems.map(_ => `${nextIndent}${JSON.stringify(_[0])}:${separator}${_[1].stringify(nextIndent, body)}`).join(`,${newLine}`)}${newLine}${currIndent}}${close}`
: "{}";

@@ -443,3 +458,3 @@ }

case "bigint":
return nativeRef(value.toString() + "n");
return nativeRef(`${value.toString()}n`);
case "boolean":

@@ -461,2 +476,3 @@ case "number":

return undefined;
replaced.main = true;
const identifiers = Array.from(references.values())

@@ -468,5 +484,3 @@ .filter(_ => _.identifier)

const args = identifiers.map(_ => _.stringify(indent, false, true));
const statements = identifiers.filter(_ => _.statement).map(_ => _.statement());
statements.push(`${indent}return ${replaced.stringify(indent, true)}`);
return (`((${identifiers.map(_ => _.identifier).join("," + separator)})${separator}=>${separator}{${newLine}${statements.join(";" + newLine)}${newLine}})` +
return (`((${identifiers.map(_ => _.identifier).join(`,${separator}`)})${separator}=>${newLine}${indent}${replaced.stringify(indent, true)}${newLine})` +
`(${newLine}${indent}${args.join(`,${newLine}${indent}`)}${newLine})`);

@@ -490,2 +504,3 @@ }

};
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
if (req._body || req.headers["content-type"] !== "application/njson")

@@ -497,2 +512,3 @@ return next();

try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
req.body = NJSON.parse(Buffer.concat(chunks).toString(req.headers["content-encoding"] || "utf8"), parse);

@@ -515,3 +531,3 @@ req._body = true;

const _options = options;
if (Response && Response.prototype) {
if (Response?.prototype) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any

@@ -518,0 +534,0 @@ Response.prototype.njson = async function njson(options) {

@@ -9,3 +9,6 @@ /** A function which can be used as `replacer` or `reviver`. */

numberKey?: boolean;
/** A function that transforms the results. This function is called for each member of the object. If a member contains nested objects, the nested objects are transformed before the parent object is. */
/**
* A function that transforms the results. This function is called for each member of the object.
* If a member contains nested objects, the nested objects are transformed before the parent object is.
*/
reviver?: NjsonFunction;

@@ -43,3 +46,4 @@ }

* @param text A valid NJSON string.
* @param reviver A function that transforms the results. This function is called for each member of the object. If a member contains nested objects, the nested objects are transformed before the parent object is.
* @param reviver A function that transforms the results. This function is called for each member of the object.
* If a member contains nested objects, the nested objects are transformed before the parent object is.
*/

@@ -46,0 +50,0 @@ declare function parse<T = unknown>(text: string, reviver?: NjsonFunction): T;

@@ -1,8 +0,3 @@

import path from "node:path";
import { fileURLToPath } from "node:url";
import { fixupPluginRules } from "@eslint/compat";
import { FlatCompat } from "@eslint/eslintrc";
import js from "@eslint/js";
import tsParser from "@typescript-eslint/parser";
import stylistic from "@stylistic/eslint-plugin";
import _import from "eslint-plugin-import";

@@ -12,42 +7,63 @@ import simpleImportSort from "eslint-plugin-simple-import-sort";

import globals from "globals";
import tsEslint from "typescript-eslint";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({ allConfig: js.configs.all, baseDirectory: __dirname, recommendedConfig: js.configs.recommended });
const overrides = { for: { after: false }, if: { after: false }, switch: { after: false }, while: { after: false } };
const unusedVarsOptions = { argsIgnorePattern: "^_", caughtErrors: "none", ignoreRestSiblings: true };
export default [
...compat.extends("plugin:@typescript-eslint/recommended"),
export default tsEslint.config(
{ ignores: ["coverage", "dist", "parser.ts"] },
{
languageOptions: { ecmaVersion: 9, globals: { ...globals.amd, ...globals.browser, ...globals.jquery, ...globals.node }, parser: tsParser, sourceType: "module" },
plugins: { import: fixupPluginRules(_import), "simple-import-sort": simpleImportSort, "sort-keys": sortKeys },
rules: {
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"arrow-body-style": ["error", "as-needed"],
"arrow-parens": ["error", "as-needed"],
"arrow-spacing": "error",
"brace-style": ["error", "1tbs", { allowSingleLine: true }],
curly: ["error", "multi-or-nest"],
eqeqeq: ["error"],
"import/first": "error",
"import/newline-after-import": "error",
"import/no-duplicates": "error",
indent: ["error", 2],
"key-spacing": ["error", { align: { afterColon: true, beforeColon: false, on: "value" } }],
"keyword-spacing": ["error", { before: true, overrides: { catch: { after: false }, for: { after: false }, if: { after: false }, switch: { after: false }, while: { after: false } } }],
"linebreak-style": ["error", "unix"],
"no-console": "warn",
"no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
"nonblock-statement-body-position": ["error", "beside"],
"prefer-const": ["error", { destructuring: "all" }],
semi: ["error", "always"],
"simple-import-sort/exports": "error",
"simple-import-sort/imports": "error",
"sort-keys": "off",
"sort-keys/sort-keys-fix": "error",
"space-before-function-paren": ["error", { anonymous: "never", asyncArrow: "always", named: "never" }],
"space-unary-ops": ["error", { nonwords: false, overrides: { "!": true }, words: true }]
extends: [js.configs.recommended, ...tsEslint.configs.strictTypeChecked, ...tsEslint.configs.recommendedTypeChecked, ...tsEslint.configs.stylisticTypeChecked],
files: ["**/*.{cjs,js,mjs,ts}"],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
projectService: { allowDefaultProject: ["eslint.config.mjs", "jest.config.cjs"], defaultProject: "tsconfig.json" },
tsconfigRootDir: import.meta.dirname
}
},
plugins: { "@stylistic": stylistic, import: _import, "simple-import-sort": simpleImportSort, "sort-keys": sortKeys },
rules: {
"@stylistic/keyword-spacing": ["error", { after: true, before: true, overrides }],
"@stylistic/space-before-function-paren": ["error", { anonymous: "never", asyncArrow: "always", catch: "never", named: "never" }],
"@typescript-eslint/consistent-type-definitions": "off",
"@typescript-eslint/no-confusing-void-expression": "off",
"@typescript-eslint/no-dynamic-delete": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-extraneous-class": "off",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unused-vars": ["error", unusedVarsOptions],
"@typescript-eslint/prefer-nullish-coalescing": "off",
"@typescript-eslint/prefer-regexp-exec": "off",
"@typescript-eslint/restrict-template-expressions": ["error", { allowNumber: true }],
"@typescript-eslint/use-unknown-in-catch-callback-variable": "off",
"arrow-body-style": ["error", "as-needed"],
"arrow-parens": ["error", "as-needed"],
"arrow-spacing": "error",
"brace-style": ["error", "1tbs", { allowSingleLine: true }],
curly: ["error", "multi-or-nest"],
eqeqeq: ["error"],
"import/first": "error",
"import/newline-after-import": "error",
"import/no-duplicates": "error",
indent: ["error", 2],
"key-spacing": ["error", { align: { afterColon: true, beforeColon: false, on: "value" } }],
"linebreak-style": ["error", "unix"],
"max-len": ["error", { code: 200, ignoreStrings: true }],
"no-console": "warn",
"no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
"prefer-const": ["error", { destructuring: "all" }],
"prefer-template": "error",
quotes: ["error", "double", { avoidEscape: true }],
semi: ["error", "always"],
"simple-import-sort/exports": "error",
"simple-import-sort/imports": "error",
"sort-keys": "off",
"sort-keys/sort-keys-fix": "error",
"space-unary-ops": ["error", { nonwords: false, overrides: { "!": true }, words: true }]
}
}
];
);

@@ -9,21 +9,20 @@ {

"devDependencies": {
"@eslint/compat": "1.2.2",
"@types/express": "5.0.0",
"@stylistic/eslint-plugin": "5.2.3",
"@types/express": "5.0.3",
"@types/jest": "29.5.14",
"@types/node": "22.9.0",
"@typescript-eslint/eslint-plugin": "8.14.0",
"@typescript-eslint/parser": "8.14.0",
"eslint": "9.14.0",
"eslint-plugin-import": "2.31.0",
"@types/node": "24.3.0",
"eslint": "9.34.0",
"eslint-plugin-import": "2.32.0",
"eslint-plugin-simple-import-sort": "12.1.1",
"eslint-plugin-sort-keys": "2.3.5",
"express": "4.21.1",
"express": "5.1.0",
"jest": "29.7.0",
"jest-environment-node-single-context": "29.4.0",
"peggy": "4.1.1",
"prettier": "3.3.3",
"ts-jest": "29.2.5",
"peggy": "5.0.6",
"prettier": "3.6.2",
"ts-jest": "29.4.1",
"ts-pegjs": "4.2.1",
"tsx": "4.19.2",
"typescript": "5.6.3"
"tsx": "4.20.5",
"typescript": "5.9.2",
"typescript-eslint": "8.41.0"
},

@@ -47,4 +46,9 @@ "engines": {

"buffer",
"circular",
"circular-reference",
"custom-json",
"date",
"deserialize",
"eval",
"extended-json",
"infinity",

@@ -57,2 +61,5 @@ "javascript",

"regexp",
"repeated",
"repeated-reference",
"serialize",
"set",

@@ -80,2 +87,3 @@ "stringify",

"deploy": "make deploy",
"lint": "eslint . --report-unused-disable-directives --max-warnings 0",
"parser": "typescript",

@@ -89,3 +97,3 @@ "precoverage": "make",

"types": "./dist/types/index.d.ts",
"version": "0.4.0"
"version": "0.5.0"
}
+91
-39

@@ -51,5 +51,6 @@ # NJSON - next-json

- doesn't support `undefined` values,
- doesn't support `BigInt` numbers,
- doesn't support many other features...
- &#10060; loses `undefined`, `NaN`, `Infinity`, `-0`
- &#10060; throws `TypeError` serializing circular references
- &#10060; cannot handle `BigInt`, `Date`, `Error`, `Map`, `RegExp`, `Set`, `URL`
- &#10060; doesn't support many other features...

@@ -60,18 +61,67 @@ This package is intended to offer something as great as JSON... trying to add something more.

- &#9745; extends JSON
- &#9745; supports C style comments
- &#9745; supports escaped new line in strings
- &#9745; supports trailing commas
- &#9745; supports circular and repeated references
- &#9745; supports `undefined`
- &#9745; supports `-0`, `NaN` and `Infinity`
- &#9745; supports `BigInt`
- &#9745; supports `Date`
- &#9745; supports `Error` (with [exception](#the-error-exception))
- &#9745; supports `Map`
- &#9745; supports `RegExp`
- &#9745; supports `Set`
- &#9745; supports `TypedArray`s (but `Float16Array`)
- &#9745; supports `URL`
- &#10004; extends JSON
- &#10004; safe parser: doesn't use `eval`
- &#10004; JavaScript compatible: same result from `parse` and `eval`
- &#10004; includes TypeScript types
- &#10004; supports C style comments
- &#10004; supports escaped new line in strings
- &#10004; supports trailing commas
- &#10004; supports circular and repeated references
- &#10004; supports `undefined`
- &#10004; supports `-0`, `NaN` and `Infinity`
- &#10004; supports `BigInt`
- &#10004; supports `Date`
- &#10004; supports `Error` (with [exception](#the-error-exception))
- &#10004; supports `Map`
- &#10004; supports `RegExp`
- &#10004; supports `Set`
- &#10004; supports `TypedArray`s (but `Float16Array`)
- &#10004; supports `URL`
# Example
<!-- prettier-ignore-start -->
```javascript
const set = new Set();
const arr = [set];
const obj = { arr, nan: NaN, set };
arr.push(arr, obj);
obj.obj = obj;
set.add(arr).add(obj);
const serialized = NJSON.stringify(obj);
const parsed = NJSON.parse(serialized);
console.log(parsed === parsed.obj); // true
console.log(parsed.arr === parsed.arr[1]); // true
console.log(isNaN(parsed.nan)); // true
console.log(parsed.set instanceof Set); // true
console.log(parsed === [...parsed.set][1]); // true
console.log(serialized);
// ((A,B,C)=>Object.assign(B,{"arr":Object.assign(A,{"0":C.add(A).add(B),"1":A,"2":B}),"set":C,"obj":B}))([],{"nan":NaN},new Set())
```
<!-- prettier-ignore-end -->
## Comparison with alternatives
| Feature | JSON | flatted | devalue | superjson | **NJSON** |
| ------------------------ | -------- | -------- | -------- | --------- | --------- |
| Safe: no `eval` use | &#10004; | &#10004; | &#10004; | &#10004; | &#10004; |
| `eval` compliant \* | &#10004; | &#10060; | &#10060; | &#10060; | &#10004; |
| Circular / repeated refs | &#10060; | &#10004; | &#10004; | &#10004; | &#10004; |
| `Map` / `Set` | &#10060; | &#10060; | &#10004; | &#10004; | &#10004; |
| `BigInt` | &#10060; | &#10060; | &#10004; | &#10004; | &#10004; |
| `Date` | &#10060; | &#10060; | &#10004; | &#10004; | &#10004; |
| `RegExp` | &#10060; | &#10060; | &#10004; | &#10004; | &#10004; |
| `TypedArray`s | &#10060; | &#10060; | &#10004; | &#10060; | &#10004; |
| Preserves `undefined` | &#10060; | &#10060; | &#10004; | &#10004; | &#10004; |
> \* This is the main reason why `NJSON` was born. The string produced by any other option strictly requires its own
> parser to be converted back to the original value. As with `JSON`, the string produced by `NJSON` can be cut / pasted
> in any JavaScript environment - without the need of any additional library - to reproduce the original value; a very
> powerful feature while debugging / developing.
## NJSON extends JSON

@@ -138,3 +188,2 @@

- `cause`:
- through `NJSON.parse` the result is **a not enumerable** property;

@@ -145,5 +194,3 @@ - through `eval` the result may be **an enumerable** or **a not enumerable** property depending on the running

- `stack`:
- if absent:
- through `NJSON.parse` the result is **a not enumerable** property with value a _pseudo-stack_;

@@ -153,3 +200,2 @@ - through `eval` the result is the standard `stack` property for the running JavaScript engine;

- if present:
- through `NJSON.parse` the result is **a not enumerable** property;

@@ -191,19 +237,2 @@ - through `eval` the result may be **an enumerable** or **a not enumerable** property depending on the running

# Example
```javascript
const obj = { test: Infinity };
const set = new Set();
const arr = [NaN, obj, set];
arr.push(arr);
arr.push(obj);
obj.arr = arr;
set.add(obj);
set.add(arr);
console.log(NJSON.stringify(arr));
// ((A,B)=>{B.push(Object.assign(A,{"arr":B}),new Set([A,B]),B,A);return B})({"test":Infinity},[NaN])
```
# Polyfill

@@ -473,2 +502,25 @@

# Version 0.5.0
`v0.5.0` changes the stringification of `Array`s from the use of `push` to the use `Object.assign` with some
advantages:
- enables the support of _sparse arrays_, next item in the TODO list;
- enables the use of _body-less functions_ rather than _functions_ which makes the parser thinner;
and one disadvantage:
- breaks the compatibility with previous versions stringification.
To make the change as smooth as possible, `v0.5.0` still supports the deserialization of previous versions
stringification: support for parsing `push` will be removed in some later version TBD.
> If `NJSON` is used to produce volatile values through `stringify` that are immediately parsed and discarded, no
> actions are required.
>
> If some values stringified using `NJSON.version` < `v0.5.0` are stored (in some DBs or in some files), it is
> recommended to convert them serialization to the newer format (just parse and re-stringify them using `v0.5.0` <=
> `NJSON.version` < `TBD`).
# Compatibility

@@ -475,0 +527,0 @@

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display