import * as has from 'lodash.has';
import { isPointer } from './isPointer';
import { GetPointer } from './types';
The get
function dereferences json
pointers according to the IETF RFC6901
specification. It takes a schema
and a json pointer
as its arguments and
then returns the value in schema
described by pointer
throwing an error
if the path described by the pointer
was not found in the schema
.
import { get } from '@jdw/jst';
const schema = { definitions: { foo: 123 }};
get(schema, '#/definitions/foo'); // resolves value 123
Arguments
schema
{Object}: The object to query.pointer
{string}: The JSON pointer path of the property to get.Returns
Throws
pointer
cannot be resolved in schema
.
import * as has from 'lodash.has';
import { isPointer } from './isPointer';
import { GetPointer } from './types';
The get
function implements the Jst.Getter
signature as described in
typings.d.ts.
export const get: GetPointer = (schema, pointer) => {
A JSON pointer
must begin with the symbols ‘#’, ‘/‘ or be an empty
string ‘’. So as a first step, we check that this assumption is true and
bail if not.
if (!isPointer(pointer)) {
throw new Error(`invalid JSON pointer specified: '${pointer}'`);
}
If this check passes we have a valid pointer
. In order to dereference
its value, we will split the pointer into its orthogonal pieces and then
iterate schema
checking from left to right that each piece of pointer
references a valid path in schema
.
const fragments = pointer.split('/');
return fragments.reduce((object, fragment) => {
If fragment
points to the root path of object
we can just return
the object
itself.
if (fragment === '#' || fragment === '/' || fragment === '') {
return object;
}
Here we decode fragment
according to the JSON pointer
specification, replacing the character codes ‘~1’ and ‘~0’ with the
symbols ‘/‘ and ‘~’ respectively.
const token = fragment.replace('~1', '/').replace('~0', '~');
let reference = null;
If the ‘object’ is array assume that token
indicates an index in
this array and try to resolve it appropriately.
if (Array.isArray(object)) {
const index = parseInt(token, 10);
if (!object.indexOf(index)) {
throw new Error(
`could not dereference JSON pointer: ${pointer}. Array does not have`
+ ` index: ${index}::${JSON.stringify(object)}`);
}
reference = object[index];
Otherwise if object
is not an Array we expect object
to be of
type Object and that token
references a valid path in object
.
} else {
if (!has(object, token)) {
throw new Error(
`could not dereference pointer '${pointer}'. The fragment ${token}`
+ ` is not a valid property of object: ${JSON.stringify(object, null, 2)}`);
}
reference = object[token];
}
Now return reference
return reference;
}, schema);
};