Skip to content

Commit

Permalink
feat(json-path): use error hierarchy and metadata when throwing errors (
Browse files Browse the repository at this point in the history
#3107)

Refs #3039
  • Loading branch information
char0n authored Sep 1, 2023
1 parent a17f250 commit d55a846
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 28 deletions.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/apidom-json-path/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"dependencies": {
"@babel/runtime-corejs3": "^7.20.7",
"@swagger-api/apidom-core": "^0.75.0",
"@swagger-api/apidom-error": "^0.75.0",
"@swagger-api/apidom-json-pointer": "^0.75.0",
"jsonpath-plus": "^7.2.0"
},
Expand Down
31 changes: 31 additions & 0 deletions packages/apidom-json-path/src/errors/EvaluationJsonPathError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Element, hasElementSourceMap, toValue } from '@swagger-api/apidom-core';
import { ApiDOMErrorOptions } from '@swagger-api/apidom-error';

import JsonPathError from './JsonPathError';

export interface EvaluationJsonPathErrorOptions<T extends Element> extends ApiDOMErrorOptions {
path: string | string[];
element: T;
}

class EvaluationJsonPathError<T extends Element> extends JsonPathError {
public readonly path!: string | string[];

public readonly element!: string;

public readonly elementSourceMap?: [[number, number, number], [number, number, number]];

constructor(message?: string, structuredOptions?: EvaluationJsonPathErrorOptions<T>) {
super(message, structuredOptions);

if (typeof structuredOptions !== 'undefined') {
this.path = structuredOptions.path;
this.element = structuredOptions.element.element;
if (hasElementSourceMap(structuredOptions.element)) {
this.elementSourceMap = toValue(structuredOptions.element.getMetaProperty('sourceMap'));
}
}
}
}

export default EvaluationJsonPathError;
5 changes: 5 additions & 0 deletions packages/apidom-json-path/src/errors/JsonPathError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ApiDOMStructuredError } from '@swagger-api/apidom-error';

class JsonPathError extends ApiDOMStructuredError {}

export default JsonPathError;
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Element, hasElementSourceMap, toValue } from '@swagger-api/apidom-core';
import { ApiDOMErrorOptions } from '@swagger-api/apidom-error';

import JsonPathError from './JsonPathError';

export interface MultiEvaluationJsonPathErrorOptions<T extends Element> extends ApiDOMErrorOptions {
paths: string[] | string[][];
element: T;
}

class MultiEvaluationJsonPathError<T extends Element> extends JsonPathError {
public readonly paths!: string[] | string[][];

public readonly element!: string;

public readonly elementSourceMap?: [[number, number, number], [number, number, number]];

constructor(message?: string, structuredOptions?: MultiEvaluationJsonPathErrorOptions<T>) {
super(message, structuredOptions);

if (typeof structuredOptions !== 'undefined') {
this.paths = structuredOptions.paths;
this.element = structuredOptions.element.element;
if (hasElementSourceMap(structuredOptions.element)) {
this.elementSourceMap = toValue(structuredOptions.element.getMetaProperty('sourceMap'));
}
}
}
}

export default MultiEvaluationJsonPathError;
55 changes: 34 additions & 21 deletions packages/apidom-json-path/src/evaluate-multi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { JSONPath } from 'jsonpath-plus';
import { Element, toValue } from '@swagger-api/apidom-core';
import { evaluate as jsonPointerEvaluate } from '@swagger-api/apidom-json-pointer';

import MultiEvaluationJsonPathError from './errors/MultiEvaluationJsonPathError';

type JSONPathEvalTuple = [string, Element[]];

type EvaluateMulti = {
Expand All @@ -13,30 +15,41 @@ type EvaluateMulti = {
* Evaluates multiple JSONPaths on ApiDOM element.
*/
const evaluateMulti: EvaluateMulti = (paths, element) => {
const json = toValue(element);
const results: JSONPathEvalTuple[] = [];

for (const path of paths) {
const pointers = JSONPath({
path,
json,
resultType: 'pointer',
}) as string[];

const endPointValues: Element[] = [];
for (const pointer of pointers) {
const endPointValue = jsonPointerEvaluate(pointer, element);
endPointValues.push(endPointValue);
try {
const json = toValue(element);
const results: JSONPathEvalTuple[] = [];

for (const path of paths) {
const pointers = JSONPath({
path,
json,
resultType: 'pointer',
}) as string[];

const endPointValues: Element[] = [];
for (const pointer of pointers) {
const endPointValue = jsonPointerEvaluate(pointer, element);
endPointValues.push(endPointValue);
}

if (Array.isArray(path)) {
results.push([JSONPath.toPathString(path), endPointValues]);
} else {
results.push([path, endPointValues]);
}
}

if (Array.isArray(path)) {
results.push([JSONPath.toPathString(path), endPointValues]);
} else {
results.push([path, endPointValues]);
}
return results;
} catch (error: unknown) {
throw new MultiEvaluationJsonPathError(
`JSON Path evaluation failed while multi-evaluating "${String(paths)}".`,
{
paths,
element,
cause: error,
},
);
}

return results;
};

export default evaluateMulti;
23 changes: 16 additions & 7 deletions packages/apidom-json-path/src/evaluate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { JSONPath } from 'jsonpath-plus';
import { Element, toValue } from '@swagger-api/apidom-core';
import { evaluate as jsonPointerEvaluate } from '@swagger-api/apidom-json-pointer';

import EvaluationJsonPathError from './errors/EvaluationJsonPathError';

type Evaluate = {
<T extends Element>(path: string, element: T): Element[];
<T extends Element>(path: string[], element: T): Element[];
Expand All @@ -11,14 +13,21 @@ type Evaluate = {
* Evaluates single JSONPath on ApiDOM element.
*/
const evaluate: Evaluate = (path, element) => {
const json = toValue(element);
const pointers = JSONPath({
path,
json,
resultType: 'pointer',
}) as string[];
try {
const json = toValue(element);
const pointers = JSONPath({
path,
json,
resultType: 'pointer',
}) as string[];

return pointers.map((pointer) => jsonPointerEvaluate(pointer, element));
return pointers.map((pointer) => jsonPointerEvaluate(pointer, element));
} catch (error: unknown) {
throw new EvaluationJsonPathError(
`JSON Path evaluation failed while evaluating "${String(path)}".`,
{ path, element, cause: error },
);
}
};

export default evaluate;
4 changes: 4 additions & 0 deletions packages/apidom-json-path/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
export { default as EvaluationJsonPathError } from './errors/EvaluationJsonPathError';
export type { EvaluationJsonPathErrorOptions } from './errors/EvaluationJsonPathError';
export { default as MultiEvaluationJsonPathError } from './errors/MultiEvaluationJsonPathError';
export type { MultiEvaluationJsonPathErrorOptions } from './errors/MultiEvaluationJsonPathError';
export { default as evaluate } from './evaluate';
export { default as evaluateMulti } from './evaluate-multi';
1 change: 1 addition & 0 deletions packages/apidom-json-pointer/src/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const compile = (tokens: string[]): string => {
'JSON Pointer compilation of tokens encountered an error.',
{
tokens,
cause: error,
},
);
}
Expand Down
1 change: 1 addition & 0 deletions packages/apidom-json-pointer/src/evaluate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const evaluate = <T extends Element>(pointer: string, element: T): Element => {
{
pointer,
element,
cause: error,
},
);
}
Expand Down
1 change: 1 addition & 0 deletions packages/apidom-json-pointer/src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const parse = (pointer: string): string[] => {
`JSON Pointer parsing of "${pointer}" encountered an error.`,
{
pointer,
cause: error,
},
);
}
Expand Down

0 comments on commit d55a846

Please sign in to comment.