Skip to content

Commit dfe0f23

Browse files
committed
test(parse): add tests cases for parsing
1 parent a72d987 commit dfe0f23

File tree

10 files changed

+331
-17
lines changed

10 files changed

+331
-17
lines changed

src/compile.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
import escape from './escape.js';
2+
import JSONPointerCompileError from './errors/JSONPointerCompileError.js';
23

34
const compile = (tokens) => {
4-
if (tokens.length === 0) {
5-
return '';
6-
}
5+
try {
6+
if (tokens.length === 0) {
7+
return '';
8+
}
79

8-
return `/${tokens.map(escape).join('/')}`;
10+
return `/${tokens.map(escape).join('/')}`;
11+
} catch (error) {
12+
throw new JSONPointerCompileError('Unknown error during JSON Pointer compilation', {
13+
cause: error,
14+
});
15+
}
916
};
1017

1118
export default compile;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import JSONPointerError from './JSONPointerError.js';
2+
3+
class JSONPointerCompileError extends JSONPointerError {}
4+
5+
export default JSONPointerCompileError;

src/errors/JSONPointerError.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
class JSONPointerError extends Error {
2+
constructor(message, options = undefined) {
3+
super(message, options);
4+
5+
this.name = this.constructor.name;
6+
if (typeof message === 'string') {
7+
this.message = message;
8+
}
9+
if (typeof Error.captureStackTrace === 'function') {
10+
Error.captureStackTrace(this, this.constructor);
11+
} else {
12+
this.stack = new Error(message).stack;
13+
}
14+
15+
/**
16+
* This needs to stay here until our minimum supported version of Node.js is >= 16.9.0.
17+
* Node.js is >= 16.9.0 supports error causes natively.
18+
*/
19+
if (
20+
options != null &&
21+
typeof options === 'object' &&
22+
Object.prototype.hasOwnProperty.call(options, 'cause') &&
23+
!('cause' in this)
24+
) {
25+
const { cause } = options;
26+
this.cause = cause;
27+
if (cause instanceof Error && 'stack' in cause) {
28+
this.stack = `${this.stack}\nCAUSE: ${cause.stack}`;
29+
}
30+
}
31+
}
32+
}
33+
34+
export default JSONPointerError;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import JSONPointerError from './JSONPointerError.js';
2+
3+
class JSONPointerEvaluateError extends JSONPointerError {}
4+
5+
export default JSONPointerEvaluateError;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import JSONPointerError from './JSONPointerError.js';
2+
3+
class JSONPointerParseError extends JSONPointerError {}
4+
5+
export default JSONPointerParseError;

src/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,8 @@ export { default as escape } from './escape.js';
1818
export { default as unescape } from './unescape.js';
1919

2020
export { default as evaluate } from './evaluate.js';
21+
22+
export { default as JSONPointerError } from './errors/JSONPointerError.js';
23+
export { default as JSONPointerParseError } from './errors/JSONPointerParseError.js';
24+
export { default as JSONPointerCompileError } from './errors/JSONPointerCompileError.js';
25+
export { default as JSONPointerEvaluateError } from './errors/JSONPointerEvaluateError.js';

src/parse/callbacks/json-pointer.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { identifiers, utilities } from 'apg-lite';
22

3+
import JSONPointerParseError from '../../errors/JSONPointerParseError.js';
4+
35
const jsonPointer = (state, chars, phraseIndex, phraseLength, data) => {
46
if (state === identifiers.SEM_PRE) {
57
if (Array.isArray(data) === false) {
6-
throw new Error("parser's user data must be an array");
8+
throw new JSONPointerParseError("parser's user data must be an array");
79
}
810
data.push(['json-pointer', utilities.charsToString(chars, phraseIndex, phraseLength)]);
911
}

src/parse/index.js

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,35 @@ import Grammar from '../grammar.js';
44
import jsonPointerCallback from './callbacks/json-pointer.js';
55
import referenceTokenCallback from './callbacks/reference-token.js';
66
import referenceTokenListEvaluator from './evaluators/reference-token-list.js';
7+
import JSONPointerParseError from '../errors/JSONPointerParseError.js';
78

89
const grammar = new Grammar();
910

1011
const parse = (jsonPointer, { evaluator = referenceTokenListEvaluator } = {}) => {
11-
const parser = new Parser();
12+
if (typeof jsonPointer !== 'string') {
13+
throw new JSONPointerParseError('JSON Pointer must be a string');
14+
}
1215

13-
parser.ast = new AST();
14-
parser.ast.callbacks['json-pointer'] = jsonPointerCallback;
15-
parser.ast.callbacks['reference-token'] = referenceTokenCallback;
16+
try {
17+
const parser = new Parser();
1618

17-
const { ast } = parser;
18-
const result = parser.parse(grammar, 'json-pointer', jsonPointer);
19+
parser.ast = new AST();
20+
parser.ast.callbacks['json-pointer'] = jsonPointerCallback;
21+
parser.ast.callbacks['reference-token'] = referenceTokenCallback;
1922

20-
if (!result.success) {
21-
return { result, ast, computed: null };
22-
}
23+
const { ast } = parser;
24+
const result = parser.parse(grammar, 'json-pointer', jsonPointer);
2325

24-
const computed = evaluator(ast, { result });
26+
if (!result.success) {
27+
return { result, ast, computed: null };
28+
}
2529

26-
return { result, ast, computed };
30+
const computed = evaluator(ast, { result });
31+
32+
return { result, ast, computed };
33+
} catch (error) {
34+
throw new JSONPointerParseError('Unknown error during JSON Pointer parsing', { cause: error });
35+
}
2736
};
2837

2938
export default parse;

test/compile.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { assert } from 'chai';
22

3-
import { compile } from '../src/index.js';
3+
import { compile, JSONPointerCompileError } from '../src/index.js';
44

55
describe('compile', function () {
66
it('should return an empty string for an empty array', function () {
@@ -38,4 +38,8 @@ describe('compile', function () {
3838
it('should retain spaces and special symbols without escaping them', function () {
3939
assert.strictEqual(compile(['foo bar', 'baz@qux']), '/foo bar/baz@qux');
4040
});
41+
42+
it('should throw error on invalid input', function () {
43+
assert.throws(() => compile(null), JSONPointerCompileError);
44+
});
4145
});

0 commit comments

Comments
 (0)