Package Exports
- @swaggerexpert/json-pointer
- @swaggerexpert/json-pointer/package.json
Readme
@swaggerexpert/json-pointer
@swaggerexpert/json-pointer is a parser, validator, evaluator, compiler and representer for RFC 6901 JavaScript Object Notation (JSON) Pointer.
|
Get professionally supported @swaggerexpert/json-pointer with Tidelift Subscription. |
Table of Contents
Getting started
Installation
You can install @swaggerexpert/json-pointer using npm:
$ npm install @swaggerexpert/json-pointerUsage
@swaggerexpert/json-pointer currently supports parsing, validation ,evaluation, compilation and representation.
Both parser and validator are based on a superset of ABNF (SABNF)
and use apg-lite parser generator.
Parsing
Parsing a JSON Pointer is as simple as importing the parse function and calling it.
import { parse } from '@swaggerexpert/json-parse';
const parseResult = parse('/foo/bar');parseResult variable has the following shape:
{
result: {
success: true,
state: 101,
stateName: 'MATCH',
length: 8,
matched: 8,
maxMatched: 8,
maxTreeDepth: 8,
nodeHits: 49
},
ast: fnast {
callbacks: [
'json-pointer': [Function: jsonPointer],
'reference-token': [Function: referenceToken]
],
init: [Function (anonymous)],
ruleDefined: [Function (anonymous)],
udtDefined: [Function (anonymous)],
down: [Function (anonymous)],
up: [Function (anonymous)],
translate: [Function (anonymous)],
setLength: [Function (anonymous)],
getLength: [Function (anonymous)],
toXml: [Function (anonymous)]
},
computed: [ 'foo', 'bar' ]
}Evaluating AST as list of unescaped reference tokens
One of the ways to interpret the parsed JSON Pointer is to evaluate it as a list of unescaped reference tokens.
import { parse } from '@swaggerexpert/json-parse';
const { computed } = parse('/foo/bar'); // computed = ['foo', 'bar']Interpreting AST as list of entries
import { parse } from '@swaggerexpert/json-parse';
const parseResult = parse('/foo/bar');
const parts = [];
parseResult.ast.translate(parts);After running the above code, parts variable has the following shape:
[
['json-pointer', '/foo/bar'],
['reference-token', 'foo'],
['reference-token', 'bar'],
]Interpreting AST as XML
import { parse } from '@swaggerexpert/json-pointer';
const parseResult = parse('/foo/bar');
const xml = parseResult.ast.toXml();After running the above code, xml variable has the following content:
<?xml version="1.0" encoding="utf-8"?>
<root nodes="3" characters="8">
<!-- input string -->
/foo/bar
<node name="json-pointer" index="0" length="8">
/foo/bar
<node name="reference-token" index="1" length="3">
foo
</node><!-- name="reference-token" -->
<node name="reference-token" index="5" length="3">
bar
</node><!-- name="reference-token" -->
</node><!-- name="json-pointer" -->
</root>NOTE: AST can also be traversed in classical way using depth first traversal. For more information about this option please refer to apg-js and apg-js-examples.
Validation
Validating a JSON Pointer is as simple as importing one of the validation functions and calling it.
import {
testJSONPointer,
testReferenceToken,
testArrayLocation,
testArrayIndex,
testArrayDash
} from '@swaggerexpert/json-pointer';
testJSONPointer('/foo/bar'); // => true
testReferenceToken('foo'); // => true
testArrayLocation('0'); // => true
testArrayLocation('-'); // => true
testArrayIndex('0'); // => true
testArrayDash('-'); // => trueEscaping
Because the characters '~' (%x7E) and '/' (%x2F) have special
meanings in JSON Pointer, '~' needs to be encoded as '~0' and '/'
needs to be encoded as '~1' when these characters appear in a
reference token.
import { escape } from '@swaggerexpert/json-pointer';
escape('~foo'); // => '~0foo'
escape('/foo'); // => '~1foo'Unescape is performed by first transforming any
occurrence of the sequence '~1' to '/', and then transforming any
occurrence of the sequence '~0' to '~'. By performing the
substitutions in this order, this library avoids the error of
turning '~01' first into '~1' and then into '/', which would be
incorrect (the string '~01' correctly becomes '~1' after transformation).
import { unescape } from '@swaggerexpert/json-pointer';
unescape('~0foo'); // => '~foo'
unescape('~1foo'); // => '/foo'Evaluation
Evaluation of a JSON Pointer begins with a reference to the root value of a JSON document and completes with a reference to some value within the document. Each reference token in the JSON Pointer is evaluated sequentially.
import { evaluate } from '@swaggerexpert/json-pointer';
const value = {
"foo": ["bar", "baz"],
"": 0,
"a/b": 1,
"c%d": 2,
"e^f": 3,
"g|h": 4,
"i\\j": 5,
"k\"l": 6,
" ": 7,
"m~n": 8
};
evaluate(value, ''); // => identical to value
evaluate(value, '/foo'); // => ["bar", "baz"]
evaluate(value, '/foo/0'); // => "bar"
evaluate(value, '/'); // => 0
evaluate(value, '/a~1b'); // => 1
evaluate(value, '/c%d'); // => 2
evaluate(value, '/e^f'); // => 3
evaluate(value, '/g|h'); // => 4
evaluate(value, '/i\\j'); // => 5
evaluate(value, '/k"l'); // => 6
evaluate(value, '/ '); // => 7
evaluate(value, '/m~0n'); // => 8
// neither object nor array
evaluate(null, '/foo'); // => throws JSONPointerTypeError
// arrays
evaluate(value, '/foo/2'); // => throws JSONPointerIndexError
evaluate(value, '/foo/-'); // => throws JSONPointerIndexError
evaluate(value, '/foo/a'); // => throws JSONPointerIndexError
// objects
evaluate(value, '/bar'); // => throws JSONPointerKeyErrorStrict Arrays
By default, the evaluation is strict, meaning error condition will be raised if it fails to resolve a concrete value for any of the JSON pointer's reference tokens. For example, if an array is referenced with a non-numeric token, an error condition will be raised.
Note that the use of the "-" character to index an array will always
result in such an error condition because by definition it refers to
a nonexistent array element.
This spec compliant strict behavior can be disabled by setting the strictArrays option to false.
evaluate(value, '/foo/2', { strictArrays: false }); // => undefined
evaluate(value, '/foo/-', { strictArrays: false }); // => undefined
evaluate(value, '/foo/a', { strictArrays: false }); // => undefinedStrict Objects
By default, the evaluation is strict, meaning error condition will be raised if it fails to resolve a concrete value for any of the JSON pointer's reference tokens. For example, if a token references a key that is not present in an object, an error condition will be raised.
This spec compliant strict behavior can be disabled by setting the strictObjects option to false.
evaluate(value, '/bar', { strictObjects: false }); // => undefinedstrictObjects options has no effect in cases where evaluation of previous
reference token failed to resolve a concrete value.
evaluate(value, '/bar/baz', { strictObjects: false }); // => throw JSONPointerTypeErrorCompilation
Compilation is the process of transforming a list of reference tokens into a JSON Pointer. Reference tokens are escaped before compiled into a JSON Pointer.
import { compile } from '@swaggerexpert/json-pointer';
compile(['~foo', 'bar']); // => '/~0foo/bar'Representation
JSON String
A JSON Pointer can be represented in a JSON string value. Per
RFC4627, Section 2.5, all instances of quotation mark '"' (%x22),
reverse solidus '\' (%x5C), and control (%x00-1F) characters MUST be
escaped.
import { JSONString } from '@swaggerexpert/json-pointer';
JSONString.to('/foo"bar'); // => '"/foo\\"bar"'
JSONString.from('"/foo\\"bar"'); // => '/foo"bar'URI Fragment Identifier
A JSON Pointer can be represented in a URI fragment identifier by encoding it into octets using UTF-8 RFC3629, while percent-encoding those characters not allowed by the fragment rule in RFC3986.
import { URIFragmentIdentifier } from '@swaggerexpert/json-pointer';
URIFragmentIdentifier.to('/foo"bar'); // => '#/foo%22bar'
URIFragmentIdentifier.from('#/foo%22bar'); // => '/foo"bar'Errors
@swaggerexpert/json-pointer provides a structured error class hierarchy,
enabling precise error handling across JSON Pointer operations, including parsing, evaluation ,compilation and validation.
import {
JSONPointerError,
JSONPointerParseError,
JSONPointerCompileError,
JSONPointerEvaluateError,
JSONPointerTypeError,
JSONPointerKeyError,
JSONPointerIndexError
} from '@swaggerexpert/json-pointer';JSONPointerError is the base class for all JSON Pointer errors.
Grammar
New grammar instance can be created in following way:
import { Grammar } from '@swaggerexpert/json-pointer';
const grammar = new Grammar();To obtain original ABNF (SABNF) grammar as a string:
import { Grammar } from '@swaggerexpert/json-pointer';
const grammar = new Grammar();
grammar.toString();
// or
String(grammar);More about JSON Pointer
JSON Pointer is defined by the following ABNF syntax
; JavaScript Object Notation (JSON) Pointer ABNF syntax
; https://datatracker.ietf.org/doc/html/rfc6901
json-pointer = *( "/" reference-token )
reference-token = *( unescaped / escaped )
unescaped = %x00-2E / %x30-7D / %x7F-10FFFF
; %x2F ('/') and %x7E ('~') are excluded from 'unescaped'
escaped = "~" ( "0" / "1" )
; representing '~' and '/', respectively
; https://datatracker.ietf.org/doc/html/rfc6901#section-4
array-location = array-index / array-dash
array-index = %x30 / ( %x31-39 *(%x30-39) )
; "0", or digits without a leading "0"
array-dash = "-"License
@swaggerexpert/json-pointer is licensed under Apache 2.0 license.
@swaggerexpert/json-pointer comes with an explicit NOTICE file
containing additional legal notices and information.