JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 10150
  • Score
    100M100P100Q123686F
  • License MIT

Next JSON format

Package Exports

  • next-json
  • next-json/dist/cjs/index.js
  • next-json/dist/es/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (next-json) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

NJSON - next-json

Next JSON format

Build Status Code Climate Test Coverage

NPM version NPM downloads Stars

Types Dependents Donate

Why this package?

Because JSON is awesome, but...

JSON is awesome mainly for two reasons:

  1. it offers an easy way to serialize and deserialize complex data;
  2. a valid JSON encoded string can be pasted in a JavaScript source file, a really awesome feature while developing / debugging.

... but it has some limitations:

  • doesn't support undefined values,
  • doesn't support BigInt numbers,
  • doesn't support many other features...

This package is intended to offer something as great as JSON... trying to add something more.

NJSON Features

  • ☑ extends JSON
  • ☑ supports C style comments
  • ☑ supports escaped new line in strings
  • ☑ supports trailing commas
  • ☑ supports circular and repeated references
  • ☑ supports undefined
  • ☑ supports -0, NaN and Infinity
  • ☑ supports BigInt
  • ☑ supports Date
  • ☑ supports Error (with exception)
  • ☑ supports Map
  • ☑ supports RegExp
  • ☑ supports Set
  • ☑ supports TypedArrays
  • ☑ supports URL

NJSON extends JSON

This doesn't mean it's 100% compliant: due its higher number of supported features the result string of the serialization through NJSON.stringify may differs from the result of the serialization through JSON.stringify.

On the other hand, the result of the deserialization of a valid JSON encoded string through NJSON.parse will produce a value deep equal to the value produced by JSON.parse and the reviver function will be called the same amount of times, with the same parameters and in the same order.

Taken the result of a JSON.parse call (i.e. a value which contains only valid JSON values), if serialized through JSON.stringify or NJSON.stringify produces two equal strings and the replacer function will be called the same amount of times, with the same parameters and in the same order.

NJSON parser

NJSON offers its own parser which means it doesn't use eval with its related security hole.

Even if the NJSON serialized string is JavaScript compliant, NJSON.parse is not able to parse any JavaScript code, but only the subset produced by NJSON.stringify (otherwise it would have been another eval implementation).

Not supported by design

NJSON do not supports some Objects by design; when one of them is encountered during the serialization process NJSON tries to act as JSON does. Nonetheless they take part in the repeated referrence algorithm anyway. Follow the details.

ArrayBuffer

ArrayBuffers can't be manipulated by JavaScript design: they are serialized as empty objects as JSON does.

Function

NJSON is designed to serialize / deserialize complex data to be shared between different systems, possibly written with other languages than JavaScript (once implementations in other languages will be written). Even if JavaScript can see a function as a piece of data, it is actually code, not data. More than this, for other languages, may be a complex problem execute JavaScript functions.

Last but not least, allowing the deserialization of a function would open once again the security hole implied by the use of eval, and one of the reasons why NJSON was born, is exactly to avoid that security hole.

Symbol

A Symbol is something strictly bound to the JavaScript execution environment which instantiate it: sharing it between distinct systems is something almost meaningless.

TypedArray

Note: except for Int8Array, Uint8Array and Uint8ClampedArray, TypedArrays are platform dependant: they are supported, but trying to transfer one of them between different architectures may be source of unexpected problems.

The Error exception

Error's are special objects. By specifications the properties cause, message, name and stack are not enumerable, NJSON serializes them as any other property. This, plus the nature of the stack property, origantes the Error exception to the rule that an NJSON encoded string produces exactly the same value if parsed or evaluated.

  • cause:

    • through NJSON.parse the result is a not enumerable property;
    • throug eval the result may be an enumerable or a not enumerable property depending on the running JavaScript engine;
  • stack:

    • if absent:

      • through NJSON.parse the result is a not enumerable property with value a pseudo-stack;
      • throug 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;
      • throug eval the result may be an enumerable or a not enumerable property depending on the running JavaScript engine;

The only option in my mind to avoid this exception is the use of Object.defineProperties, but it would increase both the complexity of the parser and the size of the produced serialized string. Maybe in the future... configurable through an option... if this can't be really tolerated.

Installation

With npm:

npm install --save next-json

Usage

JavaScript

import { NJSON } from "next-json";

const serialized = NJSON.stringify({ some: "value" });
const deserialized = NJSON.parse(serialized);

TypeScript

import { NJSON, NjsonParseOptions, NjsonStringifyOptions } from "next-json";

const serialized = NJSON.stringify({ some: "value" });
const deserialized = NJSON.parse<{ some: string }>(serialized);

Example

const obj = { test: Infinity };
const set = new Set();
const arr = [NaN, obj, set];

set.add(obj);
set.add(arr);
arr.push(arr);

console.log(NJSON.stringify(arr));
// ((A,B)=>{B.push(A,new Set([A,B]),B);return B})({"test":Infinity},[NaN])

MIME type

The proposed MIME type for NJSON format is: application/njson .

API

NJSON.parse(text[, reviver])

Just for compatibility with JSON.parse. Alias for:

NJSON.parse(text, { reviver });

NJSON.parse(text[, options])

NJSON.stringify(value[, replacer[, space]])

Just for compatibility with JSON.stringify. Alias for:

NJSON.stringify(value, { replacer, space });

NJSON.stringify(value[, options])

interface NjsonParseOptions

NjsonParseOptions.numberKey

If true, the reviver function, for Array elements, will be called with the key argument in a Number form.

NjsonParseOptions.reviver

As the reviver parameter of JSON.parse. See also replacer / reviver for NJSON specific details.

interface NjsonStringifyOptions

NjsonStringifyOptions.date

Specifies the method of Date objects used to serialize them. Follows the list of the allowed values and the relative method used.

  • "iso": Date.toISOString()
  • "string": Date.toString()
  • "time": Date.getTime() - the default
  • "utc": Date.toUTCString()

NjsonStringifyOptions.numberKey

If true, the replacer function, for Array elements, will be called with the key argument in a Number form.

NjsonStringifyOptions.omitStack

For default NJSON.stringify serializes the stack property for Errors. If set to true, the property is omitted from the serialized representation.

NjsonStringifyOptions.replacer

As the replacer parameter of JSON.serialize. See also replacer / reviver for NJSON specific details.

NjsonStringifyOptions.sortKeys

For default NJSON stringifies (and replaces as well) Object keys in the order they appear in the Object itself. If set to true, Object keys are sorted alphabetically before both the processes. This can be useful to compare two references: using this option, the stringified representation of two deep equal references are two equal strings.

NjsonStringifyOptions.space

As the space parameter of JSON.serialize.

NjsonStringifyOptions.stringLength

If specified, Strings which length is greater or equal to the specified value take part in the repeated referrence algorithm.

NjsonStringifyOptions.undef

For default NJSON.stringify serializes undefined values as well. If set to false, undefined values are treated as JSON.stringify does.

replacer / reviver

Even if Date, RegExp, TypedArrays and URL are Objects, they are treated as native values i.e. replacer and reviver will be never called with one of them as this context.

Array

For Arrays the key argument is a positive integer, but in a String form for JSON compatibility. This can be altered (i.e. in a Number form) through the numberKey option.

Map

Map's keys can be Functions and Symbols; for Maps the key argument is a positive integer in a Number form and the value argument is the entry in the form [mapKey, mapValue]. This gives a way to replace/revive keys which can't be serialized. If replacer or reviver do not return a two elements array, the value is omitted.

Set

For Sets the key argument is a positive integer and it is passed in a Number form.

TypedArray

Unlike JSON, NJSON does not call replacer and reviver for each element. Except for Int8Array, Uint8Array and Uint8ClampedArray, TypedArrays are platform dependant: trying to transfer one of them between different architectures may be source of unexpected problems.

circular / repeated references

Regardless of whether they are omitted, serialized as native values or not, every Objects (but null), Functions and Symbols take part in the repeated referrence algorithm; long Strings can take part as well (refer to NjsonStringifyOptions.stringLength for details).
When a repeated reference is encountered, replacer and reviver are called against the reference, but it is not called recursively against its properies. If a property of a repeted reference is changed, the same change has effect in all other occurences of the same reference.
Circular references are simply special cases of repeated references.

Compatibility

Requires Node.js v14.

The package is tested under all Node.js versions currently supported accordingly to Node.js Release.

TypeScript

TypeScript types are distributed with the package itself.

License

MIT License

Bugs

Do not hesitate to report any bug or inconsistency @github.

Donating

If you find useful this package, please consider the opportunity to donate some satoshis to this bitcoin address: 1Md9WFAHrXTb3yPBwQWmUfv2RmzrtbHioB

See also

Other projects which aim to solve similar problems: