RefTools
RefTools is a JavaScript utility library providing a comprehensive set of functions for working with JavaScript objects, particularly focusing on JSON References, JSON Pointers, and various cloning strategies. It offers deep, shallow, and circular-aware cloning, object flattening, and powerful recursion and visitation mechanisms for complex object structures. Currently at version 1.1.9, the library is actively maintained, as evidenced by its integration into the `oas-kit` monorepo, which includes projects like `swagger2openapi`. While `reftools` itself does not have a rapid, independent release cadence, its core features are crucial for OpenAPI/Swagger tooling, ensuring ongoing relevance and updates. Its key differentiators lie in its robust handling of JSON Pointers/References and advanced object traversal features with configurable callbacks, making it suitable for intricate data manipulation and schema processing tasks.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'someProp')
cause Attempting to access a property via `jptr` or `dereference` with a JSON Pointer that resolves to a non-existent path or an `undefined` intermediate object.fixVerify that the JSON Pointer path is valid and all intermediate objects exist. Add defensive checks or ensure your data structure matches the expected path before calling `jptr` or `dereference`. -
RangeError: Maximum call stack size exceeded
cause Using recursive functions like `dereference` or custom `recurse` callbacks on deeply nested or circularly referenced objects without proper handling for recursion depth or explicit circularity detection.fixFor circular references, ensure you use `circularClone` or the `dereference` function as intended. When writing custom `recurse` or `visit` callbacks, implement a visited-set mechanism to prevent re-processing already seen objects.
Warnings
- gotcha RefTools offers several cloning functions (`clone`, `shallowClone`, `deepClone`, `fastClone`, `circularClone`). Each has distinct behavior regarding prototype properties, deep vs. shallow copies, and handling of circular references. Using the wrong cloning method can lead to unexpected data loss (e.g., `clone` via `JSON.parse/stringify` drops circular references and certain data types) or performance issues.
- gotcha When working with JSON Pointers (`jptr`, `jpescape`, `jpunescape`), strict adherence to RFC 6901 syntax is required. Incorrectly formatted pointers (e.g., forgetting to escape `~` or `/` with `~0` and `~1` respectively) will result in incorrect paths being resolved or errors, particularly when dealing with property names containing these special characters.
- gotcha The `recurse` and `visit` functions provide powerful object traversal but require careful implementation of callbacks. Improperly written callbacks, especially those that mutate the object structure without caution or fail to handle termination conditions, can lead to infinite loops or unexpected side effects during traversal, particularly with highly interconnected or circular data.
Install
-
npm install reftools -
yarn add reftools -
pnpm add reftools
Imports
- clone
const { clone } = require('reftools')import { clone } from 'reftools' - dereference
import dereference from 'reftools'
import { dereference } from 'reftools' - jptr
const jptr = require('reftools').jptrimport { jptr } from 'reftools' - recurse
import { recurse } from 'reftools' - visit
import { visit } from 'reftools'
Quickstart
import { clone, dereference, jptr, circularClone } from 'reftools';
const originalObject = {
a: 1,
b: { c: 2 },
d: { $ref: '#/b' }, // JSON Reference
e: [],
};
originalObject.e.push(originalObject.b); // Introduce a circular reference
console.log('Original Object:', JSON.stringify(originalObject, null, 2));
// 1. Basic cloning
const clonedObject = clone(originalObject);
console.log('\nCloned Object (JSON.parse/stringify):', JSON.stringify(clonedObject, null, 2));
// Note: JSON.parse/stringify cloning loses circular refs and some types
// 2. Dereferencing JSON Pointers
const dereferencedObject = dereference(originalObject);
console.log('\nDereferenced Object (JSON Pointers resolved):', JSON.stringify(dereferencedObject, null, 2));
// 3. Using JSON Pointer (jptr) to get and set values
const valueA = jptr(originalObject, '/a');
console.log(`\nValue at '/a': ${valueA}`);
jptr(originalObject, '/b/c', 99);
console.log('Object after jptr set /b/c to 99:', JSON.stringify(originalObject, null, 2));
// 4. Cloning with circular reference handling
const circularHandledClone = circularClone(originalObject);
console.log('\nCircular-aware cloned object (inspect for circularity - will be simplified):', circularHandledClone);