@openmcptools/jref
v1.0.2
Published
Parse and stringify for JSON Reference (JRef).
Maintainers
Readme
jref-lib js
A lightweight JavaScript utility for efficiently stringifying and parsing JSON with support for complex structures (e.g. trees and some graphs) using the JSON Pointers specification (RFC 6901) and the local-only JSON Reference (JREF) specification.
Overview
Standard JSON.stringify inefficiently duplicates object data when the same instance is referenced in multiple locations within the source object graph. jref-lib js solves this by:
- Efficiently serializing duplicate references: For complex data structures (e.g. trees and other graphs) replacing memory references with JSON pointers will frequently result in less data and more efficient network transmission.
- Handling circularity: Safely serializing and parsing objects that point back to themselves.
- Restoring object identity on deserialization: Ensuring that after parsing, multiple references to the same original object point to the same memory instance.
Installation
npm install @openmcptools/jrefAPI Reference
The JRef stringify/parse API exactly duplicates the JSON.stringify and JSON.parse API as given
in ECMAScript 2027 JSON documentation
stringify(value[, replacer[, space]])
value: The object to serialize.replacer: A function or array to transform the output.space: Adds indentation/whitespace to the output string.- ECMAScript 2027 arguments documentation
parse(text[, reviver])
text: The JRef-encoded JSON string.reviver: A function to transform the resulting object.- ECMAScript 2027 arguments documentation.
Usage Examples
1. Circular References
Standard JSON.stringify throws a TypeError on circular structures. JRef handles them seamlessly.
import * as JRef from '@openmcptools/jref';
const user = { name: "Alice" };
user.self = user; // Circular reference
const json = JRef.stringify(user);
console.log(json);
// Output: {"name":"Alice","self":{"$ref":"#"}}
const parsed = JRef.parse(json);
console.log(parsed === parsed.self); // true2. Preserving Object Identity (Deduplication)
When the same object is referenced multiple times, JRef ensures they point to the same instance after parsing.
const sharedMetadata = { version: "1.0.0" };
const data = {
config: sharedMetadata,
settings: sharedMetadata
};
const json = JRef.stringify(data);
console.log(json);
// Output: {"config":{"version":"1.0.0"},"settings":{"$ref":"#/config"}}
const parsed = JRef.parse(json);
console.log(parsed.config === parsed.settings); // true3. Efficient Tree Serialization/Deserialization
// JREF stringify and parse
import * as JRef from '@openmcptools/jref';
const user1 = { name: "Alice", data: "Alice is a caring, kind, and thoughtful person. She is also an excellent, conscientious engineer" };
const user2 = { name: "Bob" };
const user3 = { name: "Mallory" };
user1.self = user1; // Circular reference
user2.friend = user1; // reference to Alice
user3.friend = user1; // reference to Alice
const input = [ user1, user2, user3 ];
// call stringify
const output = JRef.stringify(input);
console.log(output);
console.log("output length=" + output.length);
// call parse
const parsed = JRef.parse(output);
console.log("parsed[0] === parsed[0].self=" + (parsed[0] === parsed[0].self));
console.log("parsed[1].friend === parsed[0]=" + (parsed[1].friend === parsed[0]));
console.log("parsed[2].friend === parsed[0]=" + (parsed[2].friend === parsed[0]));This example can also be found in examples/ex1.js.
Here is the output from running the above
[{"name":"Alice","data":"Alice is a caring, kind, and thoughtful person. She is also an excellent, conscientious engineer","self":{"$ref":"#/0"}},{"name":"Bob","friend":{"$ref":"#/0"}},{"name":"Mallory","friend":{"$ref":"#/0"}}]
output length=229
parsed[0] === parsed[0].self=true
parsed[1].friend === parsed[0]=true
parsed[2].friend === parsed[0]=trueHere is the output using only JSON.stringify and JSON.parse
[{"name":"Alice","data":"Alice is a caring, kind, and thoughtful person. She is also an excellent, conscientious engineer"},{"name":"Bob","friend":{"name":"Alice","data":"Alice is a caring, kind, and thoughtful person. She is also an excellent, conscientious engineer"}},{"name":"Mallory","friend":{"name":"Alice","data":"Alice is a caring, kind, and thoughtful person. She is also an excellent, conscientious engineer"}}]
output length=425
parsed[0] === parsed[0].self=false
parsed[1].friend === parsed[0]=false
parsed[2].friend === parsed[0]=falseThis example can also be found in examples/ex2.js.
4. Using Replacers and Revivers
You can still use standard JSON features, such as replacer functions, with JRef.
const input = { id: 1, secret: "hidden", link: null };
input.link = input;
const json = JRef.stringify(input, (key, value) => {
if (key === 'secret') return; // Filter out sensitive data
return value;
});
const parsed = JRef.parse(json);
console.log(parsed.secret); // undefined
console.log(parsed.link === parsed); // true