JSON toolkit for JavaScript
npm install json8JSON8 is a JavaScript library that makes working with JSON/data/structures safer and easier.
Features
- Strong JSON and type validation
- Full support for Map and Set
- Support Node.js/
and browsers; es5-shim for < IE 9, JSON polyfill for < IE 8
- Smarter and safer JSON serializer/stringify
- See Methods and Motivations
- Tested
- Small, no dependencies
- Modular, save bandwith/memory by requiring needed methods using require('json8/lib/METHOD_NAME')
See also
- JSON8 Patch for JSON diffing and patching
- JSON8 Pointer for JSON Pointer (URL for JSON) implementation
- JSON8 Merge Patch for simpler but less capable JSON object diffing/patching alternative to JSON Patch and Pointer
---
- Introduction
- Getting started
- Methods
- oo
- oo.clone
- oo.equal
- oo.type
- oo.is
- structure
- primitive
- object
- array
- number
- string
- boolean
- null
- JSON
- oo.hasKey
- oo.hasValue
- oo.has
- oo.valid
- oo.serialize
- oo.parse
- oo.Document
- Motivations
npm install json8
---
``javascript`
const oo = require("json8");
Returns an oo.Document.
`javascript`
var doc = oo(false);
doc instanceof oo.Document; // true
doc.isBoolean(); // true
doc.isPrimitive(); // true
// ...
Deep clone any value.
`javascript
var doc = { foo: "bar" };
var clone = oo.clone(doc); // {"foo":"bar"}
doc === copy; // false
oo.equal(doc, copy); // true
oo.clone(true); // true
oo.clone(42); // 42
oo.clone(-0); // -0
`
Test for JSON equality between two documents.
`javascript
oo.equal(true, true) // true
oo.equal([], []) // true
oo.equal({}, {}) // true
oo.equal(
{foo: 'bar', bar: 'foo'}
{bar: 'foo', foo: 'bar'}
) // true
oo.equal(new Set([1, 2]), new Set([1, 2])) // true
oo.equal(new Set([2, 1]), new Set([1, 2])) // false
oo.equal(new Set(), []) // true
oo.equal(new Map(), {}) // true
oo.equal([1, 2], [2, 1]) // false
oo.equal(-0, +0) // false
`
Returns the JSON type for a value, undefined if the value is not of any JSON type.
`javascript
oo.type({}); // 'object'
oo.type(new Map()); // 'object'
oo.type([]); // 'array'
oo.type(new Set()); // 'array'
oo.type(42); // 'number'
oo.type("foo"); // 'string'
oo.type(null); // 'null'
oo.type(true); // 'boolean'
oo.type(undefined); // undefined
oo.type(Infinity); // undefined
oo.type(-Infinity); // undefined
oo.type(NaN); // undefined
oo.type(Symbol()); // undefined
oo.type(function () {}); // undefined
`
For each type you can use the syntax
`javascript`
oo.is("foo", type);
or
`javascript`
oo.isType("foo");
Where type is any of:
- structure
- primitive
- object
- array
- number
- string
- boolean
- null
- JSON
oo.is(value, type) throws an error if type is not one of those.
#### structure
Returns true for arrays and objects, false otherwise.
`javascript
oo.is({}, "structure"); // true
oo.isStructure([]); // true
oo.isStructure(new Set()); // true
oo.isStructure(new Map()); // true
oo.isStructure(null); // false
`
#### primitive
Returns true for primitives, false otherwise.
Primitives are: number, boolean, null, string.
`javascript
oo.is(null, 'primitive') // true
oo.isPrimitive(true) // true
oo.isPrimitive('foo') // true
oo.isPrimitive(42) // true
oo.isPrimitive([]]) // false
oo.isPrimitive({}) // false
oo.isPrimitive(undefined)// false
oo.isPrimitive(Infinity) // false
oo.isPrimitive(NaN) // false
`
#### object
Returns true for object, false otherwise.
`javascript
oo.is({}, "object"); // true
oo.isObject({}); // true
oo.isObject(new Map()); // true
oo.isObject(null); // false
oo.isObject([]); // false
oo.isObject(null); // false
oo.isObject(function () {}); // false
oo.isObject(new Set()); // false
`
#### array
Returns true for array, false otherwise.
`javascript
oo.is([], "array"); // true
oo.isArray([]); // true
oo.isArray(new Set()); // true
oo.isArray({}); // false
oo.isArray(new Map()); // false
`
#### number
Returns true for number, false otherwise.
`javascript
oo.is(42, "number"); // true
oo.isNumber(4.2); // true
oo.isNumber(-42); // true
oo.isNumber(Infinity); // false; Infinity is not valid JSON
oo.isNumber(-Infinity); // false; -Infinity is not valid JSON
oo.isNumber(NaN); // false; NaN is not valid JSON
`
#### string
Returns true for string, false otherwise.
`javascript
oo.is('foo', 'string') // true
oo.isString('☕'️) // true
oo.isString('') // true
oo.isString(42) // false
oo.isString(undefined) // false
oo.isString(null) // false
`
#### boolean
Returns true for boolean, false otherwise.
`javascript
oo.is(true, "boolean"); // true
oo.isBoolean(false); // true
oo.isBoolean(0); // false
oo.isBoolean("foo"); // false
`
#### null
Returns true for null, false otherwise.
`javascript
oo.is(null, "null"); // true
oo.isNull(null); // true
oo.isNull(undefined); // false
`
#### JSON
Returns true for any JSON valid value.
JSON valid values are: number, boolean, null, string, array, object.
This method is not recursive, if you need to deep check for validity use the oo.valid method.
`javascript
oo.is(true, "JSON"); //true
oo.isJSON("foo"); //true
oo.isJSON(null); //true
oo.isJSON({}); //true
oo.isJSON([]); //true
oo.isJSON(42); //true
oo.isJSON(new Map()); //true
oo.isJSON(new Set()); //true
oo.isJSON(undefined); //false
oo.isJSON(NaN); //false
oo.isJSON(Infinity); //false
oo.isJSON(-Infinity); //false
oo.isJSON(function () {}); //false
`
Iterates over a JSON object (Map or Object) until an equal JSON key is found.
Returns true if the JSON object (Map or Object) contains an equal key.
Returns false if the key is not a string.
Returns false if the value at the key is undefined.
`javascript
oo.hasKey({ foo: "bar" }, "foo"); // true
oo.hasKey({ undefined: "bar" }, undefined); // false
oo.hasKey({ foo: undefined }, "foo"); // false
var obj = {};
obj[{}] = "foo";
oo.hasKey(obj, {}); // false
var map = new Map();
map.set("foo", "bar");
oo.hasKey(map, "foo"); // true
map.set(undefined, "bar");
oo.hasKey(map, undefined); // false
map.set("foo", undefined);
oo.hasKey(map, "foo"); // false
map.set({}, "foo");
oo.hasKey(map, {}); // true
`
Iterates over a JSON structure (Array or Object) until an equal JSON value is found.
Returns true if the JSON structure contains an equal value.
Returns false if the value or the key for the value is undefined.
`javascript
oo.hasValue({ foo: "bar" }, "bar"); // true
oo.hasValue({ foo: {} }, {}); // true
oo.hasValue({ undefined: "bar" }, bar); // false
oo.hasValue({ foo: undefined }, undefined); // false
var map = new Map();
map.set("foo", "bar");
oo.hasKey(map, "bar"); // true
map.set(undefined, "bar");
oo.hasKey(map, "bar"); // false
map.set("foo", undefined);
oo.hasKey(map, undefined); // false
`
If the provided structure is a JSON array (Set or Array) returns the result of hasValue with the given arguments.
If the provided structure is a JSON object (Map or Object) returns the result of hasKey with the given arguments.
Otherwise returns false.
Recursive version of is JSON, works on primitive values as well.
`javascript
oo.valid(true); //true
oo.valid({ foo: "bar" }); //true
oo.valid({ foo: undefined }); //false
oo.valid({ foo: NaN }); //false
oo.valid(["bar", function () {}]); //false
`
Takes a JSON document and returns a parseable JSON string. Uses JSON.stringify underneath so it's still fast.
Always use try/catch with oo.serialize.
Differences with JSON.stringify
- Throws a TypeError for any invalid JSON value encountered such as
- undefinedInfinity
- -Infinity
- NaN
- symbols
- functions
- -0
- Works with Map (serialized as JSON object)
- Works with Set (serialized as JSON array)
- Serializes signed zeros as "-0" while JSON.stringify returns "0"
- Options are provided as an object instead of arguments
Options
- toJSON set to false disable toJSON behavior_behavior>) (defaults to true)space
- same as JSON.stringify space argumentreplacer
- same as JSON.stringify replacer argument but remove the value from the array if undefined is returnedmaxIndentLevel
- set a maximum level (depth) of indentation
`javascript
oo.serialize(doc[, options]);
oo.serialize({"foo": "bar"})
// {"foo":"bar"}
/*
* Set serialization
*/
var set = new Set()
set.add('hello')
oo.serialize(set)
// ["hello"]
/*
* Map serialization
*/
var map = new Map()
map.set('foo', 'bar')
oo.serialize(map)
// {"foo":"bar"}
/*
* toJSON option
*/
oo.serialize(new Date())
// "2015-10-21T16:29:00.000Z"
oo.serialize(new Date(), {toJSON: false})
// {}
/*
* space option
*/
var obj = {foo: 'bar'}
oo.serialize(obj)
// {"foo":"bar"}
oo.serialize(obj, {space: 2})
// {
// "foo": "bar"
// }
/*
* maxIndentLevel
*/
var obj = {foo: ['0', '1', '2']}
oo.serialize(obj, {space: 2, maxIndentLevel: 1})
// {
// "foo": ['0', '1', '2'] // without maxIndentLevel, each value would be on a newline
// }
`
Takes a JSON string and returns a JavaScript value.
Always use try/catch with oo.parse.
`javascript`
var doc = oo.parse(string[, options]);
options.set to parse JSON arrays as Set (default false).options.map to parse JSON objects as Map (default false).
An oo.Document is a constructor that wraps a value and expose oo methods.
You can use either oo(value) or new oo.Document(value).
`javascript`
var doc = oo("hello");
doc instanceof oo.Document; // true
doc.isString(); // true
var clone = doc.clone(); // oo.Document
doc.equal(clone); // true
Getting/asserting the JSON type of a value in JavaScript is troublesome.
- oo.type returns the JSON type of any value
- oo.is checks if a value is of the provided type
- oo.isStructure checks if a value is a JSON structure (an array or an object)
- oo.isPrimitive checks if a value is a JSON primitive (null, boolean, string, number)
- oo.isJSON checks if the value is a JSON valid value
oo.serialize will throw an exception for any non JSON valid value (undefined, NaN, Infinity, -Infinity, ...) instead of ignoring it or replacing it with null like JSON.striginfy does. It also accept an optional argument to disable toJSON behavior_behavior>) which is a common pitfall. Additionally it encodes invalid JavaScript characters.
JSON8 types helps avoiding many common errors as well.
oo.equal performs deep JSON equality comparaison
oo.valid performs recursive JSON validation on any value
Map and Set are new structures available in ES6. Both are serializable and parseable as JSON, Map as object and Set as array. JSON8 was designed with that in mind and every single method supports Map and Set, a few examples:
- isArray returns true for Settrue
- isObject returns for Maptrue
- valid, isStructure, isJSON return for Map and Set'array'
- type returns for Set and 'object' for Map
- serialize stringifies Set as array and Map as object
- parse optionally parses arrays as Set and objects as Map
`javascript
// undefined is not JSON valid
JSON.stringify(undefined); // undefined
oo.serialize(undefined); // TypeError
JSON.stringify({ foo: undefined }); // '{}'
oo.serialize({ foo: undefined }); // TypeError
JSON.stringify([undefined]); // '[null]'
oo.serialize([undefined]); // TypeError
// same applies for NaN, Infinity and -Infinity
typeof NaN; // 'number'
oo.type(NaN); // undefined
JSON.stringify(NaN); // 'null'
JSON.stringify({ foo: NaN }); // '{"foo":null}'
JSON.stringify([NaN]); // '[null]'
oo.serialize(NaN); // TypeError
// typeof null returns 'object'
typeof null; // 'object'
oo.type(null); // 'null'
// arrays
var array = [];
typeof []; // 'object'
oo.type(array); // 'array'
array[2] = "foo";
array[1]; // undefined
array[0]; // undefined
JSON.stringify(array); // '[null,null,"foo"]'
oo.serialize(array); // TypeError
// functions
JSON.stringify(function () {}); // undefined
JSON.stringify({ foo: function () {} }); // '{}'
JSON.stringify([function () {}]); // '[null]'
oo.serialize(function () {}); // TypeError
// Set
var set = new Set();
typeof set; // 'object'
oo.type(set); // 'array'
set.add("foo");
JSON.stringify(set); // '{}'
oo.serialize(set); // '["foo"]'
// Map
var map = new Map();
typeof map; // 'object'
oo.type(map); // 'object'
map.set("foo", "bar");
JSON.stringify(map); // '{}'
oo.serialize(map); // '{"foo": "bar"}'
// typeof Date returns 'object' but JSON.stringify returns a string
typeof new Date(); // 'object'
JSON.stringify(new Date()); // '2015-10-21T16:29:00.000Z'
oo.type(new Date()); // 'object'
oo.serialize(new Date(), { toJSON: false }); // '{}'
oo.serialize(new Date()) - // '2015-10-21T16:29:00.000Z'
// -0
0 ===
0; // true
oo.equal(-0, 0); // false
JSON.parse("-0"); // -0
JSON.stringify(-0); // "0"
oo.parse("-0"); // -0
oo.serialize(-0); // "-0"
``