diff --git a/package-lock.json b/package-lock.json index f21c6c7a4..66281f547 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34635,6 +34635,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" } diff --git a/packages/apidom-json-path/package.json b/packages/apidom-json-path/package.json index 9fac646fb..367ec996e 100644 --- a/packages/apidom-json-path/package.json +++ b/packages/apidom-json-path/package.json @@ -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" }, diff --git a/packages/apidom-json-path/src/errors/EvaluationJsonPathError.ts b/packages/apidom-json-path/src/errors/EvaluationJsonPathError.ts new file mode 100644 index 000000000..e398611c5 --- /dev/null +++ b/packages/apidom-json-path/src/errors/EvaluationJsonPathError.ts @@ -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 extends ApiDOMErrorOptions { + path: string | string[]; + element: T; +} + +class EvaluationJsonPathError 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) { + 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; diff --git a/packages/apidom-json-path/src/errors/JsonPathError.ts b/packages/apidom-json-path/src/errors/JsonPathError.ts new file mode 100644 index 000000000..e2e03a6ba --- /dev/null +++ b/packages/apidom-json-path/src/errors/JsonPathError.ts @@ -0,0 +1,5 @@ +import { ApiDOMStructuredError } from '@swagger-api/apidom-error'; + +class JsonPathError extends ApiDOMStructuredError {} + +export default JsonPathError; diff --git a/packages/apidom-json-path/src/errors/MultiEvaluationJsonPathError.ts b/packages/apidom-json-path/src/errors/MultiEvaluationJsonPathError.ts new file mode 100644 index 000000000..849f2c5f4 --- /dev/null +++ b/packages/apidom-json-path/src/errors/MultiEvaluationJsonPathError.ts @@ -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 extends ApiDOMErrorOptions { + paths: string[] | string[][]; + element: T; +} + +class MultiEvaluationJsonPathError 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) { + 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; diff --git a/packages/apidom-json-path/src/evaluate-multi.ts b/packages/apidom-json-path/src/evaluate-multi.ts index abe6e5188..b8e2733f4 100644 --- a/packages/apidom-json-path/src/evaluate-multi.ts +++ b/packages/apidom-json-path/src/evaluate-multi.ts @@ -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 = { @@ -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; diff --git a/packages/apidom-json-path/src/evaluate.ts b/packages/apidom-json-path/src/evaluate.ts index 6adb43faa..bfd327644 100644 --- a/packages/apidom-json-path/src/evaluate.ts +++ b/packages/apidom-json-path/src/evaluate.ts @@ -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 = { (path: string, element: T): Element[]; (path: string[], element: T): Element[]; @@ -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; diff --git a/packages/apidom-json-path/src/index.ts b/packages/apidom-json-path/src/index.ts index ec2a73298..12649c845 100644 --- a/packages/apidom-json-path/src/index.ts +++ b/packages/apidom-json-path/src/index.ts @@ -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'; diff --git a/packages/apidom-json-pointer/src/compile.ts b/packages/apidom-json-pointer/src/compile.ts index 7a07d1443..393dfec49 100644 --- a/packages/apidom-json-pointer/src/compile.ts +++ b/packages/apidom-json-pointer/src/compile.ts @@ -14,6 +14,7 @@ const compile = (tokens: string[]): string => { 'JSON Pointer compilation of tokens encountered an error.', { tokens, + cause: error, }, ); } diff --git a/packages/apidom-json-pointer/src/evaluate.ts b/packages/apidom-json-pointer/src/evaluate.ts index e6425f02a..964a48a8d 100644 --- a/packages/apidom-json-pointer/src/evaluate.ts +++ b/packages/apidom-json-pointer/src/evaluate.ts @@ -16,6 +16,7 @@ const evaluate = (pointer: string, element: T): Element => { { pointer, element, + cause: error, }, ); } diff --git a/packages/apidom-json-pointer/src/parse.ts b/packages/apidom-json-pointer/src/parse.ts index 3cdf4de59..0df7d699f 100644 --- a/packages/apidom-json-pointer/src/parse.ts +++ b/packages/apidom-json-pointer/src/parse.ts @@ -27,6 +27,7 @@ const parse = (pointer: string): string[] => { `JSON Pointer parsing of "${pointer}" encountered an error.`, { pointer, + cause: error, }, ); }