@nocobase/plugin-workflow-json-query 1.9.0-beta.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +172 -0
- package/README.md +1 -0
- package/client.d.ts +2 -0
- package/client.js +1 -0
- package/dist/client/index.d.ts +23 -0
- package/dist/client/index.js +10 -0
- package/dist/client/instruction.d.ts +167 -0
- package/dist/externalVersion.js +19 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +42 -0
- package/dist/locale/en-US.json +13 -0
- package/dist/locale/index.d.ts +10 -0
- package/dist/locale/index.js +42 -0
- package/dist/locale/zh-CN.json +14 -0
- package/dist/node_modules/jmespath/LICENSE +13 -0
- package/dist/node_modules/jmespath/artifacts/jmespath.min.js +2 -0
- package/dist/node_modules/jmespath/bower.json +24 -0
- package/dist/node_modules/jmespath/jmespath.js +1 -0
- package/dist/node_modules/jmespath/jp.js +23 -0
- package/dist/node_modules/jmespath/package.json +1 -0
- package/dist/node_modules/jsonata/LICENSE +19 -0
- package/dist/node_modules/jsonata/jsonata-es5.js +9875 -0
- package/dist/node_modules/jsonata/jsonata-es5.min.js +1 -0
- package/dist/node_modules/jsonata/jsonata.d.ts +72 -0
- package/dist/node_modules/jsonata/jsonata.js +1 -0
- package/dist/node_modules/jsonata/jsonata.min.js +1 -0
- package/dist/node_modules/jsonata/package.json +1 -0
- package/dist/node_modules/jsonpath-plus/LICENSE +22 -0
- package/dist/node_modules/jsonpath-plus/bin/jsonpath-cli.js +36 -0
- package/dist/node_modules/jsonpath-plus/dist/index-browser-esm.js +2158 -0
- package/dist/node_modules/jsonpath-plus/dist/index-browser-esm.min.js +2 -0
- package/dist/node_modules/jsonpath-plus/dist/index-browser-umd.cjs +2166 -0
- package/dist/node_modules/jsonpath-plus/dist/index-browser-umd.min.cjs +2 -0
- package/dist/node_modules/jsonpath-plus/dist/index-node-cjs.cjs +1 -0
- package/dist/node_modules/jsonpath-plus/dist/index-node-esm.js +2068 -0
- package/dist/node_modules/jsonpath-plus/package.json +1 -0
- package/dist/node_modules/jsonpath-plus/src/Safe-Script.js +200 -0
- package/dist/node_modules/jsonpath-plus/src/jsonpath-browser.js +102 -0
- package/dist/node_modules/jsonpath-plus/src/jsonpath-node.js +8 -0
- package/dist/node_modules/jsonpath-plus/src/jsonpath.d.ts +226 -0
- package/dist/node_modules/jsonpath-plus/src/jsonpath.js +784 -0
- package/dist/server/JSONQueryInstruction.d.ts +42 -0
- package/dist/server/JSONQueryInstruction.js +99 -0
- package/dist/server/Plugin.d.ts +24 -0
- package/dist/server/Plugin.js +62 -0
- package/dist/server/index.d.ts +17 -0
- package/dist/server/index.js +42 -0
- package/package.json +31 -0
- package/server.d.ts +2 -0
- package/server.js +1 -0
|
@@ -0,0 +1,784 @@
|
|
|
1
|
+
/* eslint-disable camelcase -- Convenient for escaping */
|
|
2
|
+
|
|
3
|
+
import {SafeScript} from './Safe-Script.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {null|boolean|number|string|object|GenericArray} JSONObject
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {any} AnyItem
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {any} AnyResult
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Copies array and then pushes item into it.
|
|
19
|
+
* @param {GenericArray} arr Array to copy and into which to push
|
|
20
|
+
* @param {AnyItem} item Array item to add (to end)
|
|
21
|
+
* @returns {GenericArray} Copy of the original array
|
|
22
|
+
*/
|
|
23
|
+
function push (arr, item) {
|
|
24
|
+
arr = arr.slice();
|
|
25
|
+
arr.push(item);
|
|
26
|
+
return arr;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Copies array and then unshifts item into it.
|
|
30
|
+
* @param {AnyItem} item Array item to add (to beginning)
|
|
31
|
+
* @param {GenericArray} arr Array to copy and into which to unshift
|
|
32
|
+
* @returns {GenericArray} Copy of the original array
|
|
33
|
+
*/
|
|
34
|
+
function unshift (item, arr) {
|
|
35
|
+
arr = arr.slice();
|
|
36
|
+
arr.unshift(item);
|
|
37
|
+
return arr;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Caught when JSONPath is used without `new` but rethrown if with `new`
|
|
42
|
+
* @extends Error
|
|
43
|
+
*/
|
|
44
|
+
class NewError extends Error {
|
|
45
|
+
/**
|
|
46
|
+
* @param {AnyResult} value The evaluated scalar value
|
|
47
|
+
*/
|
|
48
|
+
constructor (value) {
|
|
49
|
+
super(
|
|
50
|
+
'JSONPath should not be called with "new" (it prevents return ' +
|
|
51
|
+
'of (unwrapped) scalar values)'
|
|
52
|
+
);
|
|
53
|
+
this.avoidNew = true;
|
|
54
|
+
this.value = value;
|
|
55
|
+
this.name = 'NewError';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @typedef {object} ReturnObject
|
|
61
|
+
* @property {string} path
|
|
62
|
+
* @property {JSONObject} value
|
|
63
|
+
* @property {object|GenericArray} parent
|
|
64
|
+
* @property {string} parentProperty
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @callback JSONPathCallback
|
|
69
|
+
* @param {string|object} preferredOutput
|
|
70
|
+
* @param {"value"|"property"} type
|
|
71
|
+
* @param {ReturnObject} fullRetObj
|
|
72
|
+
* @returns {void}
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @callback OtherTypeCallback
|
|
77
|
+
* @param {JSONObject} val
|
|
78
|
+
* @param {string} path
|
|
79
|
+
* @param {object|GenericArray} parent
|
|
80
|
+
* @param {string} parentPropName
|
|
81
|
+
* @returns {boolean}
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @typedef {any} ContextItem
|
|
86
|
+
*/
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @typedef {any} EvaluatedResult
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @callback EvalCallback
|
|
94
|
+
* @param {string} code
|
|
95
|
+
* @param {ContextItem} context
|
|
96
|
+
* @returns {EvaluatedResult}
|
|
97
|
+
*/
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @typedef {typeof SafeScript} EvalClass
|
|
101
|
+
*/
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @typedef {object} JSONPathOptions
|
|
105
|
+
* @property {JSON} json
|
|
106
|
+
* @property {string|string[]} path
|
|
107
|
+
* @property {"value"|"path"|"pointer"|"parent"|"parentProperty"|
|
|
108
|
+
* "all"} [resultType="value"]
|
|
109
|
+
* @property {boolean} [flatten=false]
|
|
110
|
+
* @property {boolean} [wrap=true]
|
|
111
|
+
* @property {object} [sandbox={}]
|
|
112
|
+
* @property {EvalCallback|EvalClass|'safe'|'native'|
|
|
113
|
+
* boolean} [eval = 'safe']
|
|
114
|
+
* @property {object|GenericArray|null} [parent=null]
|
|
115
|
+
* @property {string|null} [parentProperty=null]
|
|
116
|
+
* @property {JSONPathCallback} [callback]
|
|
117
|
+
* @property {OtherTypeCallback} [otherTypeCallback] Defaults to
|
|
118
|
+
* function which throws on encountering `@other`
|
|
119
|
+
* @property {boolean} [autostart=true]
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @param {string|JSONPathOptions} opts If a string, will be treated as `expr`
|
|
124
|
+
* @param {string} [expr] JSON path to evaluate
|
|
125
|
+
* @param {JSON} [obj] JSON object to evaluate against
|
|
126
|
+
* @param {JSONPathCallback} [callback] Passed 3 arguments: 1) desired payload
|
|
127
|
+
* per `resultType`, 2) `"value"|"property"`, 3) Full returned object with
|
|
128
|
+
* all payloads
|
|
129
|
+
* @param {OtherTypeCallback} [otherTypeCallback] If `@other()` is at the end
|
|
130
|
+
* of one's query, this will be invoked with the value of the item, its
|
|
131
|
+
* path, its parent, and its parent's property name, and it should return
|
|
132
|
+
* a boolean indicating whether the supplied value belongs to the "other"
|
|
133
|
+
* type or not (or it may handle transformations and return `false`).
|
|
134
|
+
* @returns {JSONPath}
|
|
135
|
+
* @class
|
|
136
|
+
*/
|
|
137
|
+
function JSONPath (opts, expr, obj, callback, otherTypeCallback) {
|
|
138
|
+
// eslint-disable-next-line no-restricted-syntax -- Allow for pseudo-class
|
|
139
|
+
if (!(this instanceof JSONPath)) {
|
|
140
|
+
try {
|
|
141
|
+
return new JSONPath(opts, expr, obj, callback, otherTypeCallback);
|
|
142
|
+
} catch (e) {
|
|
143
|
+
if (!e.avoidNew) {
|
|
144
|
+
throw e;
|
|
145
|
+
}
|
|
146
|
+
return e.value;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (typeof opts === 'string') {
|
|
151
|
+
otherTypeCallback = callback;
|
|
152
|
+
callback = obj;
|
|
153
|
+
obj = expr;
|
|
154
|
+
expr = opts;
|
|
155
|
+
opts = null;
|
|
156
|
+
}
|
|
157
|
+
const optObj = opts && typeof opts === 'object';
|
|
158
|
+
opts = opts || {};
|
|
159
|
+
this.json = opts.json || obj;
|
|
160
|
+
this.path = opts.path || expr;
|
|
161
|
+
this.resultType = opts.resultType || 'value';
|
|
162
|
+
this.flatten = opts.flatten || false;
|
|
163
|
+
this.wrap = Object.hasOwn(opts, 'wrap') ? opts.wrap : true;
|
|
164
|
+
this.sandbox = opts.sandbox || {};
|
|
165
|
+
this.eval = opts.eval === undefined ? 'safe' : opts.eval;
|
|
166
|
+
this.ignoreEvalErrors = (typeof opts.ignoreEvalErrors === 'undefined')
|
|
167
|
+
? false
|
|
168
|
+
: opts.ignoreEvalErrors;
|
|
169
|
+
this.parent = opts.parent || null;
|
|
170
|
+
this.parentProperty = opts.parentProperty || null;
|
|
171
|
+
this.callback = opts.callback || callback || null;
|
|
172
|
+
this.otherTypeCallback = opts.otherTypeCallback ||
|
|
173
|
+
otherTypeCallback ||
|
|
174
|
+
function () {
|
|
175
|
+
throw new TypeError(
|
|
176
|
+
'You must supply an otherTypeCallback callback option ' +
|
|
177
|
+
'with the @other() operator.'
|
|
178
|
+
);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
if (opts.autostart !== false) {
|
|
182
|
+
const args = {
|
|
183
|
+
path: (optObj ? opts.path : expr)
|
|
184
|
+
};
|
|
185
|
+
if (!optObj) {
|
|
186
|
+
args.json = obj;
|
|
187
|
+
} else if ('json' in opts) {
|
|
188
|
+
args.json = opts.json;
|
|
189
|
+
}
|
|
190
|
+
const ret = this.evaluate(args);
|
|
191
|
+
if (!ret || typeof ret !== 'object') {
|
|
192
|
+
throw new NewError(ret);
|
|
193
|
+
}
|
|
194
|
+
return ret;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// PUBLIC METHODS
|
|
199
|
+
JSONPath.prototype.evaluate = function (
|
|
200
|
+
expr, json, callback, otherTypeCallback
|
|
201
|
+
) {
|
|
202
|
+
let currParent = this.parent,
|
|
203
|
+
currParentProperty = this.parentProperty;
|
|
204
|
+
let {flatten, wrap} = this;
|
|
205
|
+
|
|
206
|
+
this.currResultType = this.resultType;
|
|
207
|
+
this.currEval = this.eval;
|
|
208
|
+
this.currSandbox = this.sandbox;
|
|
209
|
+
callback = callback || this.callback;
|
|
210
|
+
this.currOtherTypeCallback = otherTypeCallback || this.otherTypeCallback;
|
|
211
|
+
|
|
212
|
+
json = json || this.json;
|
|
213
|
+
expr = expr || this.path;
|
|
214
|
+
if (expr && typeof expr === 'object' && !Array.isArray(expr)) {
|
|
215
|
+
if (!expr.path && expr.path !== '') {
|
|
216
|
+
throw new TypeError(
|
|
217
|
+
'You must supply a "path" property when providing an object ' +
|
|
218
|
+
'argument to JSONPath.evaluate().'
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
if (!(Object.hasOwn(expr, 'json'))) {
|
|
222
|
+
throw new TypeError(
|
|
223
|
+
'You must supply a "json" property when providing an object ' +
|
|
224
|
+
'argument to JSONPath.evaluate().'
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
({json} = expr);
|
|
228
|
+
flatten = Object.hasOwn(expr, 'flatten') ? expr.flatten : flatten;
|
|
229
|
+
this.currResultType = Object.hasOwn(expr, 'resultType')
|
|
230
|
+
? expr.resultType
|
|
231
|
+
: this.currResultType;
|
|
232
|
+
this.currSandbox = Object.hasOwn(expr, 'sandbox')
|
|
233
|
+
? expr.sandbox
|
|
234
|
+
: this.currSandbox;
|
|
235
|
+
wrap = Object.hasOwn(expr, 'wrap') ? expr.wrap : wrap;
|
|
236
|
+
this.currEval = Object.hasOwn(expr, 'eval')
|
|
237
|
+
? expr.eval
|
|
238
|
+
: this.currEval;
|
|
239
|
+
callback = Object.hasOwn(expr, 'callback') ? expr.callback : callback;
|
|
240
|
+
this.currOtherTypeCallback = Object.hasOwn(expr, 'otherTypeCallback')
|
|
241
|
+
? expr.otherTypeCallback
|
|
242
|
+
: this.currOtherTypeCallback;
|
|
243
|
+
currParent = Object.hasOwn(expr, 'parent') ? expr.parent : currParent;
|
|
244
|
+
currParentProperty = Object.hasOwn(expr, 'parentProperty')
|
|
245
|
+
? expr.parentProperty
|
|
246
|
+
: currParentProperty;
|
|
247
|
+
expr = expr.path;
|
|
248
|
+
}
|
|
249
|
+
currParent = currParent || null;
|
|
250
|
+
currParentProperty = currParentProperty || null;
|
|
251
|
+
|
|
252
|
+
if (Array.isArray(expr)) {
|
|
253
|
+
expr = JSONPath.toPathString(expr);
|
|
254
|
+
}
|
|
255
|
+
if ((!expr && expr !== '') || !json) {
|
|
256
|
+
return undefined;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const exprList = JSONPath.toPathArray(expr);
|
|
260
|
+
if (exprList[0] === '$' && exprList.length > 1) {
|
|
261
|
+
exprList.shift();
|
|
262
|
+
}
|
|
263
|
+
this._hasParentSelector = null;
|
|
264
|
+
const result = this
|
|
265
|
+
._trace(
|
|
266
|
+
exprList, json, ['$'], currParent, currParentProperty, callback
|
|
267
|
+
)
|
|
268
|
+
.filter(function (ea) {
|
|
269
|
+
return ea && !ea.isParentSelector;
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
if (!result.length) {
|
|
273
|
+
return wrap ? [] : undefined;
|
|
274
|
+
}
|
|
275
|
+
if (!wrap && result.length === 1 && !result[0].hasArrExpr) {
|
|
276
|
+
return this._getPreferredOutput(result[0]);
|
|
277
|
+
}
|
|
278
|
+
return result.reduce((rslt, ea) => {
|
|
279
|
+
const valOrPath = this._getPreferredOutput(ea);
|
|
280
|
+
if (flatten && Array.isArray(valOrPath)) {
|
|
281
|
+
rslt = rslt.concat(valOrPath);
|
|
282
|
+
} else {
|
|
283
|
+
rslt.push(valOrPath);
|
|
284
|
+
}
|
|
285
|
+
return rslt;
|
|
286
|
+
}, []);
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
// PRIVATE METHODS
|
|
290
|
+
|
|
291
|
+
JSONPath.prototype._getPreferredOutput = function (ea) {
|
|
292
|
+
const resultType = this.currResultType;
|
|
293
|
+
switch (resultType) {
|
|
294
|
+
case 'all': {
|
|
295
|
+
const path = Array.isArray(ea.path)
|
|
296
|
+
? ea.path
|
|
297
|
+
: JSONPath.toPathArray(ea.path);
|
|
298
|
+
ea.pointer = JSONPath.toPointer(path);
|
|
299
|
+
ea.path = typeof ea.path === 'string'
|
|
300
|
+
? ea.path
|
|
301
|
+
: JSONPath.toPathString(ea.path);
|
|
302
|
+
return ea;
|
|
303
|
+
} case 'value': case 'parent': case 'parentProperty':
|
|
304
|
+
return ea[resultType];
|
|
305
|
+
case 'path':
|
|
306
|
+
return JSONPath.toPathString(ea[resultType]);
|
|
307
|
+
case 'pointer':
|
|
308
|
+
return JSONPath.toPointer(ea.path);
|
|
309
|
+
default:
|
|
310
|
+
throw new TypeError('Unknown result type');
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
JSONPath.prototype._handleCallback = function (fullRetObj, callback, type) {
|
|
315
|
+
if (callback) {
|
|
316
|
+
const preferredOutput = this._getPreferredOutput(fullRetObj);
|
|
317
|
+
fullRetObj.path = typeof fullRetObj.path === 'string'
|
|
318
|
+
? fullRetObj.path
|
|
319
|
+
: JSONPath.toPathString(fullRetObj.path);
|
|
320
|
+
// eslint-disable-next-line n/callback-return -- No need to return
|
|
321
|
+
callback(preferredOutput, type, fullRetObj);
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
*
|
|
327
|
+
* @param {string} expr
|
|
328
|
+
* @param {JSONObject} val
|
|
329
|
+
* @param {string} path
|
|
330
|
+
* @param {object|GenericArray} parent
|
|
331
|
+
* @param {string} parentPropName
|
|
332
|
+
* @param {JSONPathCallback} callback
|
|
333
|
+
* @param {boolean} hasArrExpr
|
|
334
|
+
* @param {boolean} literalPriority
|
|
335
|
+
* @returns {ReturnObject|ReturnObject[]}
|
|
336
|
+
*/
|
|
337
|
+
JSONPath.prototype._trace = function (
|
|
338
|
+
expr, val, path, parent, parentPropName, callback, hasArrExpr,
|
|
339
|
+
literalPriority
|
|
340
|
+
) {
|
|
341
|
+
// No expr to follow? return path and value as the result of
|
|
342
|
+
// this trace branch
|
|
343
|
+
let retObj;
|
|
344
|
+
if (!expr.length) {
|
|
345
|
+
retObj = {
|
|
346
|
+
path,
|
|
347
|
+
value: val,
|
|
348
|
+
parent,
|
|
349
|
+
parentProperty: parentPropName,
|
|
350
|
+
hasArrExpr
|
|
351
|
+
};
|
|
352
|
+
this._handleCallback(retObj, callback, 'value');
|
|
353
|
+
return retObj;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const loc = expr[0], x = expr.slice(1);
|
|
357
|
+
|
|
358
|
+
// We need to gather the return value of recursive trace calls in order to
|
|
359
|
+
// do the parent sel computation.
|
|
360
|
+
const ret = [];
|
|
361
|
+
/**
|
|
362
|
+
*
|
|
363
|
+
* @param {ReturnObject|ReturnObject[]} elems
|
|
364
|
+
* @returns {void}
|
|
365
|
+
*/
|
|
366
|
+
function addRet (elems) {
|
|
367
|
+
if (Array.isArray(elems)) {
|
|
368
|
+
// This was causing excessive stack size in Node (with or
|
|
369
|
+
// without Babel) against our performance test:
|
|
370
|
+
// `ret.push(...elems);`
|
|
371
|
+
elems.forEach((t) => {
|
|
372
|
+
ret.push(t);
|
|
373
|
+
});
|
|
374
|
+
} else {
|
|
375
|
+
ret.push(elems);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
if ((typeof loc !== 'string' || literalPriority) && val &&
|
|
379
|
+
Object.hasOwn(val, loc)
|
|
380
|
+
) { // simple case--directly follow property
|
|
381
|
+
addRet(this._trace(x, val[loc], push(path, loc), val, loc, callback,
|
|
382
|
+
hasArrExpr));
|
|
383
|
+
// eslint-disable-next-line unicorn/prefer-switch -- Part of larger `if`
|
|
384
|
+
} else if (loc === '*') { // all child properties
|
|
385
|
+
this._walk(val, (m) => {
|
|
386
|
+
addRet(this._trace(
|
|
387
|
+
x, val[m], push(path, m), val, m, callback, true, true
|
|
388
|
+
));
|
|
389
|
+
});
|
|
390
|
+
} else if (loc === '..') { // all descendent parent properties
|
|
391
|
+
// Check remaining expression with val's immediate children
|
|
392
|
+
addRet(
|
|
393
|
+
this._trace(x, val, path, parent, parentPropName, callback,
|
|
394
|
+
hasArrExpr)
|
|
395
|
+
);
|
|
396
|
+
this._walk(val, (m) => {
|
|
397
|
+
// We don't join m and x here because we only want parents,
|
|
398
|
+
// not scalar values
|
|
399
|
+
if (typeof val[m] === 'object') {
|
|
400
|
+
// Keep going with recursive descent on val's
|
|
401
|
+
// object children
|
|
402
|
+
addRet(this._trace(
|
|
403
|
+
expr.slice(), val[m], push(path, m), val, m, callback, true
|
|
404
|
+
));
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
// The parent sel computation is handled in the frame above using the
|
|
408
|
+
// ancestor object of val
|
|
409
|
+
} else if (loc === '^') {
|
|
410
|
+
// This is not a final endpoint, so we do not invoke the callback here
|
|
411
|
+
this._hasParentSelector = true;
|
|
412
|
+
return {
|
|
413
|
+
path: path.slice(0, -1),
|
|
414
|
+
expr: x,
|
|
415
|
+
isParentSelector: true
|
|
416
|
+
};
|
|
417
|
+
} else if (loc === '~') { // property name
|
|
418
|
+
retObj = {
|
|
419
|
+
path: push(path, loc),
|
|
420
|
+
value: parentPropName,
|
|
421
|
+
parent,
|
|
422
|
+
parentProperty: null
|
|
423
|
+
};
|
|
424
|
+
this._handleCallback(retObj, callback, 'property');
|
|
425
|
+
return retObj;
|
|
426
|
+
} else if (loc === '$') { // root only
|
|
427
|
+
addRet(this._trace(x, val, path, null, null, callback, hasArrExpr));
|
|
428
|
+
} else if ((/^(-?\d*):(-?\d*):?(\d*)$/u).test(loc)) { // [start:end:step] Python slice syntax
|
|
429
|
+
addRet(
|
|
430
|
+
this._slice(loc, x, val, path, parent, parentPropName, callback)
|
|
431
|
+
);
|
|
432
|
+
} else if (loc.indexOf('?(') === 0) { // [?(expr)] (filtering)
|
|
433
|
+
if (this.currEval === false) {
|
|
434
|
+
throw new Error('Eval [?(expr)] prevented in JSONPath expression.');
|
|
435
|
+
}
|
|
436
|
+
const safeLoc = loc.replace(/^\?\((.*?)\)$/u, '$1');
|
|
437
|
+
// check for a nested filter expression
|
|
438
|
+
const nested = (/@.?([^?]*)[['](\??\(.*?\))(?!.\)\])[\]']/gu).exec(safeLoc);
|
|
439
|
+
if (nested) {
|
|
440
|
+
// find if there are matches in the nested expression
|
|
441
|
+
// add them to the result set if there is at least one match
|
|
442
|
+
this._walk(val, (m) => {
|
|
443
|
+
const npath = [nested[2]];
|
|
444
|
+
const nvalue = nested[1]
|
|
445
|
+
? val[m][nested[1]]
|
|
446
|
+
: val[m];
|
|
447
|
+
const filterResults = this._trace(npath, nvalue, path,
|
|
448
|
+
parent, parentPropName, callback, true);
|
|
449
|
+
if (filterResults.length > 0) {
|
|
450
|
+
addRet(this._trace(x, val[m], push(path, m), val,
|
|
451
|
+
m, callback, true));
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
} else {
|
|
455
|
+
this._walk(val, (m) => {
|
|
456
|
+
if (this._eval(safeLoc, val[m], m, path, parent,
|
|
457
|
+
parentPropName)) {
|
|
458
|
+
addRet(this._trace(x, val[m], push(path, m), val, m,
|
|
459
|
+
callback, true));
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
} else if (loc[0] === '(') { // [(expr)] (dynamic property/index)
|
|
464
|
+
if (this.currEval === false) {
|
|
465
|
+
throw new Error('Eval [(expr)] prevented in JSONPath expression.');
|
|
466
|
+
}
|
|
467
|
+
// As this will resolve to a property name (but we don't know it
|
|
468
|
+
// yet), property and parent information is relative to the
|
|
469
|
+
// parent of the property to which this expression will resolve
|
|
470
|
+
addRet(this._trace(unshift(
|
|
471
|
+
this._eval(
|
|
472
|
+
loc, val, path.at(-1),
|
|
473
|
+
path.slice(0, -1), parent, parentPropName
|
|
474
|
+
),
|
|
475
|
+
x
|
|
476
|
+
), val, path, parent, parentPropName, callback, hasArrExpr));
|
|
477
|
+
} else if (loc[0] === '@') { // value type: @boolean(), etc.
|
|
478
|
+
let addType = false;
|
|
479
|
+
const valueType = loc.slice(1, -2);
|
|
480
|
+
switch (valueType) {
|
|
481
|
+
case 'scalar':
|
|
482
|
+
if (!val || !(['object', 'function'].includes(typeof val))) {
|
|
483
|
+
addType = true;
|
|
484
|
+
}
|
|
485
|
+
break;
|
|
486
|
+
case 'boolean': case 'string': case 'undefined': case 'function':
|
|
487
|
+
if (typeof val === valueType) {
|
|
488
|
+
addType = true;
|
|
489
|
+
}
|
|
490
|
+
break;
|
|
491
|
+
case 'integer':
|
|
492
|
+
if (Number.isFinite(val) && !(val % 1)) {
|
|
493
|
+
addType = true;
|
|
494
|
+
}
|
|
495
|
+
break;
|
|
496
|
+
case 'number':
|
|
497
|
+
if (Number.isFinite(val)) {
|
|
498
|
+
addType = true;
|
|
499
|
+
}
|
|
500
|
+
break;
|
|
501
|
+
case 'nonFinite':
|
|
502
|
+
if (typeof val === 'number' && !Number.isFinite(val)) {
|
|
503
|
+
addType = true;
|
|
504
|
+
}
|
|
505
|
+
break;
|
|
506
|
+
case 'object':
|
|
507
|
+
if (val && typeof val === valueType) {
|
|
508
|
+
addType = true;
|
|
509
|
+
}
|
|
510
|
+
break;
|
|
511
|
+
case 'array':
|
|
512
|
+
if (Array.isArray(val)) {
|
|
513
|
+
addType = true;
|
|
514
|
+
}
|
|
515
|
+
break;
|
|
516
|
+
case 'other':
|
|
517
|
+
addType = this.currOtherTypeCallback(
|
|
518
|
+
val, path, parent, parentPropName
|
|
519
|
+
);
|
|
520
|
+
break;
|
|
521
|
+
case 'null':
|
|
522
|
+
if (val === null) {
|
|
523
|
+
addType = true;
|
|
524
|
+
}
|
|
525
|
+
break;
|
|
526
|
+
/* c8 ignore next 2 */
|
|
527
|
+
default:
|
|
528
|
+
throw new TypeError('Unknown value type ' + valueType);
|
|
529
|
+
}
|
|
530
|
+
if (addType) {
|
|
531
|
+
retObj = {path, value: val, parent, parentProperty: parentPropName};
|
|
532
|
+
this._handleCallback(retObj, callback, 'value');
|
|
533
|
+
return retObj;
|
|
534
|
+
}
|
|
535
|
+
// `-escaped property
|
|
536
|
+
} else if (loc[0] === '`' && val && Object.hasOwn(val, loc.slice(1))) {
|
|
537
|
+
const locProp = loc.slice(1);
|
|
538
|
+
addRet(this._trace(
|
|
539
|
+
x, val[locProp], push(path, locProp), val, locProp, callback,
|
|
540
|
+
hasArrExpr, true
|
|
541
|
+
));
|
|
542
|
+
} else if (loc.includes(',')) { // [name1,name2,...]
|
|
543
|
+
const parts = loc.split(',');
|
|
544
|
+
for (const part of parts) {
|
|
545
|
+
addRet(this._trace(
|
|
546
|
+
unshift(part, x), val, path, parent, parentPropName, callback,
|
|
547
|
+
true
|
|
548
|
+
));
|
|
549
|
+
}
|
|
550
|
+
// simple case--directly follow property
|
|
551
|
+
} else if (
|
|
552
|
+
!literalPriority && val && Object.hasOwn(val, loc)
|
|
553
|
+
) {
|
|
554
|
+
addRet(
|
|
555
|
+
this._trace(x, val[loc], push(path, loc), val, loc, callback,
|
|
556
|
+
hasArrExpr, true)
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// We check the resulting values for parent selections. For parent
|
|
561
|
+
// selections we discard the value object and continue the trace with the
|
|
562
|
+
// current val object
|
|
563
|
+
if (this._hasParentSelector) {
|
|
564
|
+
for (let t = 0; t < ret.length; t++) {
|
|
565
|
+
const rett = ret[t];
|
|
566
|
+
if (rett && rett.isParentSelector) {
|
|
567
|
+
const tmp = this._trace(
|
|
568
|
+
rett.expr, val, rett.path, parent, parentPropName, callback,
|
|
569
|
+
hasArrExpr
|
|
570
|
+
);
|
|
571
|
+
if (Array.isArray(tmp)) {
|
|
572
|
+
ret[t] = tmp[0];
|
|
573
|
+
const tl = tmp.length;
|
|
574
|
+
for (let tt = 1; tt < tl; tt++) {
|
|
575
|
+
// eslint-disable-next-line @stylistic/max-len -- Long
|
|
576
|
+
// eslint-disable-next-line sonarjs/updated-loop-counter -- Convenient
|
|
577
|
+
t++;
|
|
578
|
+
ret.splice(t, 0, tmp[tt]);
|
|
579
|
+
}
|
|
580
|
+
} else {
|
|
581
|
+
ret[t] = tmp;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return ret;
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
JSONPath.prototype._walk = function (val, f) {
|
|
590
|
+
if (Array.isArray(val)) {
|
|
591
|
+
const n = val.length;
|
|
592
|
+
for (let i = 0; i < n; i++) {
|
|
593
|
+
f(i);
|
|
594
|
+
}
|
|
595
|
+
} else if (val && typeof val === 'object') {
|
|
596
|
+
Object.keys(val).forEach((m) => {
|
|
597
|
+
f(m);
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
JSONPath.prototype._slice = function (
|
|
603
|
+
loc, expr, val, path, parent, parentPropName, callback
|
|
604
|
+
) {
|
|
605
|
+
if (!Array.isArray(val)) {
|
|
606
|
+
return undefined;
|
|
607
|
+
}
|
|
608
|
+
const len = val.length, parts = loc.split(':'),
|
|
609
|
+
step = (parts[2] && Number.parseInt(parts[2])) || 1;
|
|
610
|
+
let start = (parts[0] && Number.parseInt(parts[0])) || 0,
|
|
611
|
+
end = (parts[1] && Number.parseInt(parts[1])) || len;
|
|
612
|
+
start = (start < 0) ? Math.max(0, start + len) : Math.min(len, start);
|
|
613
|
+
end = (end < 0) ? Math.max(0, end + len) : Math.min(len, end);
|
|
614
|
+
const ret = [];
|
|
615
|
+
for (let i = start; i < end; i += step) {
|
|
616
|
+
const tmp = this._trace(
|
|
617
|
+
unshift(i, expr), val, path, parent, parentPropName, callback, true
|
|
618
|
+
);
|
|
619
|
+
// Should only be possible to be an array here since first part of
|
|
620
|
+
// ``unshift(i, expr)` passed in above would not be empty, nor `~`,
|
|
621
|
+
// nor begin with `@` (as could return objects)
|
|
622
|
+
// This was causing excessive stack size in Node (with or
|
|
623
|
+
// without Babel) against our performance test: `ret.push(...tmp);`
|
|
624
|
+
tmp.forEach((t) => {
|
|
625
|
+
ret.push(t);
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
return ret;
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
JSONPath.prototype._eval = function (
|
|
632
|
+
code, _v, _vname, path, parent, parentPropName
|
|
633
|
+
) {
|
|
634
|
+
this.currSandbox._$_parentProperty = parentPropName;
|
|
635
|
+
this.currSandbox._$_parent = parent;
|
|
636
|
+
this.currSandbox._$_property = _vname;
|
|
637
|
+
this.currSandbox._$_root = this.json;
|
|
638
|
+
this.currSandbox._$_v = _v;
|
|
639
|
+
|
|
640
|
+
const containsPath = code.includes('@path');
|
|
641
|
+
if (containsPath) {
|
|
642
|
+
this.currSandbox._$_path = JSONPath.toPathString(path.concat([_vname]));
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
const scriptCacheKey = this.currEval + 'Script:' + code;
|
|
646
|
+
if (!JSONPath.cache[scriptCacheKey]) {
|
|
647
|
+
let script = code
|
|
648
|
+
.replaceAll('@parentProperty', '_$_parentProperty')
|
|
649
|
+
.replaceAll('@parent', '_$_parent')
|
|
650
|
+
.replaceAll('@property', '_$_property')
|
|
651
|
+
.replaceAll('@root', '_$_root')
|
|
652
|
+
.replaceAll(/@([.\s)[])/gu, '_$_v$1');
|
|
653
|
+
if (containsPath) {
|
|
654
|
+
script = script.replaceAll('@path', '_$_path');
|
|
655
|
+
}
|
|
656
|
+
if (
|
|
657
|
+
this.currEval === 'safe' ||
|
|
658
|
+
this.currEval === true ||
|
|
659
|
+
this.currEval === undefined
|
|
660
|
+
) {
|
|
661
|
+
JSONPath.cache[scriptCacheKey] = new this.safeVm.Script(script);
|
|
662
|
+
} else if (this.currEval === 'native') {
|
|
663
|
+
JSONPath.cache[scriptCacheKey] = new this.vm.Script(script);
|
|
664
|
+
} else if (
|
|
665
|
+
typeof this.currEval === 'function' &&
|
|
666
|
+
this.currEval.prototype &&
|
|
667
|
+
Object.hasOwn(this.currEval.prototype, 'runInNewContext')
|
|
668
|
+
) {
|
|
669
|
+
const CurrEval = this.currEval;
|
|
670
|
+
JSONPath.cache[scriptCacheKey] = new CurrEval(script);
|
|
671
|
+
} else if (typeof this.currEval === 'function') {
|
|
672
|
+
JSONPath.cache[scriptCacheKey] = {
|
|
673
|
+
runInNewContext: (context) => this.currEval(script, context)
|
|
674
|
+
};
|
|
675
|
+
} else {
|
|
676
|
+
throw new TypeError(`Unknown "eval" property "${this.currEval}"`);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
try {
|
|
681
|
+
return JSONPath.cache[scriptCacheKey].runInNewContext(this.currSandbox);
|
|
682
|
+
} catch (e) {
|
|
683
|
+
if (this.ignoreEvalErrors) {
|
|
684
|
+
return false;
|
|
685
|
+
}
|
|
686
|
+
throw new Error('jsonPath: ' + e.message + ': ' + code);
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
// PUBLIC CLASS PROPERTIES AND METHODS
|
|
691
|
+
|
|
692
|
+
// Could store the cache object itself
|
|
693
|
+
JSONPath.cache = {};
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* @param {string[]} pathArr Array to convert
|
|
697
|
+
* @returns {string} The path string
|
|
698
|
+
*/
|
|
699
|
+
JSONPath.toPathString = function (pathArr) {
|
|
700
|
+
const x = pathArr, n = x.length;
|
|
701
|
+
let p = '$';
|
|
702
|
+
for (let i = 1; i < n; i++) {
|
|
703
|
+
if (!(/^(~|\^|@.*?\(\))$/u).test(x[i])) {
|
|
704
|
+
p += (/^[0-9*]+$/u).test(x[i]) ? ('[' + x[i] + ']') : ("['" + x[i] + "']");
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
return p;
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* @param {string} pointer JSON Path
|
|
712
|
+
* @returns {string} JSON Pointer
|
|
713
|
+
*/
|
|
714
|
+
JSONPath.toPointer = function (pointer) {
|
|
715
|
+
const x = pointer, n = x.length;
|
|
716
|
+
let p = '';
|
|
717
|
+
for (let i = 1; i < n; i++) {
|
|
718
|
+
if (!(/^(~|\^|@.*?\(\))$/u).test(x[i])) {
|
|
719
|
+
p += '/' + x[i].toString()
|
|
720
|
+
.replaceAll('~', '~0')
|
|
721
|
+
.replaceAll('/', '~1');
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
return p;
|
|
725
|
+
};
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* @param {string} expr Expression to convert
|
|
729
|
+
* @returns {string[]}
|
|
730
|
+
*/
|
|
731
|
+
JSONPath.toPathArray = function (expr) {
|
|
732
|
+
const {cache} = JSONPath;
|
|
733
|
+
if (cache[expr]) {
|
|
734
|
+
return cache[expr].concat();
|
|
735
|
+
}
|
|
736
|
+
const subx = [];
|
|
737
|
+
const normalized = expr
|
|
738
|
+
// Properties
|
|
739
|
+
.replaceAll(
|
|
740
|
+
/@(?:null|boolean|number|string|integer|undefined|nonFinite|scalar|array|object|function|other)\(\)/gu,
|
|
741
|
+
';$&;'
|
|
742
|
+
)
|
|
743
|
+
// Parenthetical evaluations (filtering and otherwise), directly
|
|
744
|
+
// within brackets or single quotes
|
|
745
|
+
.replaceAll(/[['](\??\(.*?\))[\]'](?!.\])/gu, function ($0, $1) {
|
|
746
|
+
return '[#' + (subx.push($1) - 1) + ']';
|
|
747
|
+
})
|
|
748
|
+
// Escape periods and tildes within properties
|
|
749
|
+
.replaceAll(/\[['"]([^'\]]*)['"]\]/gu, function ($0, prop) {
|
|
750
|
+
return "['" + prop
|
|
751
|
+
.replaceAll('.', '%@%')
|
|
752
|
+
.replaceAll('~', '%%@@%%') +
|
|
753
|
+
"']";
|
|
754
|
+
})
|
|
755
|
+
// Properties operator
|
|
756
|
+
.replaceAll('~', ';~;')
|
|
757
|
+
// Split by property boundaries
|
|
758
|
+
.replaceAll(/['"]?\.['"]?(?![^[]*\])|\[['"]?/gu, ';')
|
|
759
|
+
// Reinsert periods within properties
|
|
760
|
+
.replaceAll('%@%', '.')
|
|
761
|
+
// Reinsert tildes within properties
|
|
762
|
+
.replaceAll('%%@@%%', '~')
|
|
763
|
+
// Parent
|
|
764
|
+
.replaceAll(/(?:;)?(\^+)(?:;)?/gu, function ($0, ups) {
|
|
765
|
+
return ';' + ups.split('').join(';') + ';';
|
|
766
|
+
})
|
|
767
|
+
// Descendents
|
|
768
|
+
.replaceAll(/;;;|;;/gu, ';..;')
|
|
769
|
+
// Remove trailing
|
|
770
|
+
.replaceAll(/;$|'?\]|'$/gu, '');
|
|
771
|
+
|
|
772
|
+
const exprList = normalized.split(';').map(function (exp) {
|
|
773
|
+
const match = exp.match(/#(\d+)/u);
|
|
774
|
+
return !match || !match[1] ? exp : subx[match[1]];
|
|
775
|
+
});
|
|
776
|
+
cache[expr] = exprList;
|
|
777
|
+
return cache[expr].concat();
|
|
778
|
+
};
|
|
779
|
+
|
|
780
|
+
JSONPath.prototype.safeVm = {
|
|
781
|
+
Script: SafeScript
|
|
782
|
+
};
|
|
783
|
+
|
|
784
|
+
export {JSONPath};
|