Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion badges/tests-badge.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 3 additions & 6 deletions dist/index-browser-esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -2394,15 +2394,12 @@ class JSONPathClass {
}
const scriptCacheKey = this.currEval + 'Script:' + code;
if (!scriptCache.has(scriptCacheKey)) {
let script = code.replaceAll('@parentProperty', '_$_parentProperty').replaceAll('@parent', '_$_parent').replaceAll('@property', '_$_property').replaceAll('@root', '_$_root')
// Replace a bare `@` (not followed by an identifier
// Replace `@parentProperty`, `@parent`, `@property`, `@root`,
// `@path` and a bare `@` (not followed by an identifier
// character) while leaving quoted string literals and
// regex literals (a `/` where an operand is expected,
// as opposed to division) intact
.replaceAll(/('(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"|(?<=(?:^|[\(,=:\[!\|?\{\};+\-*%<>~^]|&)\s*)\/(?:\\.|\[(?:\\.|[^\]\\])*\]|[^\/\\\[])+\/[dgimsuvy]*)|@(?![\w$])/gv, (_, literal) => literal ?? '_$_v');
if (containsPath) {
script = script.replaceAll('@path', '_$_path');
}
const script = code.replaceAll(/('(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"|(?<=(?:^|[\(,=:\[!\|?\{\};+\-*%<>~^]|&)\s*)\/(?:\\.|\[(?:\\.|[^\]\\])*\]|[^\/\\\[])+\/[dgimsuvy]*)|@(?:(parentProperty|parent|property|root|path)|(?![\w$]))/gv, (_, literal, name) => literal ?? '_$_' + (name ?? 'v'));
const evalType = /** @type {string|boolean|undefined} */
this.currEval;
if (['safe', true, undefined].includes(evalType)) {
Expand Down
2 changes: 1 addition & 1 deletion dist/index-browser-esm.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index-browser-esm.min.js.map

Large diffs are not rendered by default.

9 changes: 3 additions & 6 deletions dist/index-browser-umd.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2400,15 +2400,12 @@
}
const scriptCacheKey = this.currEval + 'Script:' + code;
if (!scriptCache.has(scriptCacheKey)) {
let script = code.replaceAll('@parentProperty', '_$_parentProperty').replaceAll('@parent', '_$_parent').replaceAll('@property', '_$_property').replaceAll('@root', '_$_root')
// Replace a bare `@` (not followed by an identifier
// Replace `@parentProperty`, `@parent`, `@property`, `@root`,
// `@path` and a bare `@` (not followed by an identifier
// character) while leaving quoted string literals and
// regex literals (a `/` where an operand is expected,
// as opposed to division) intact
.replaceAll(/('(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"|(?<=(?:^|[\(,=:\[!\|?\{\};+\-*%<>~^]|&)\s*)\/(?:\\.|\[(?:\\.|[^\]\\])*\]|[^\/\\\[])+\/[dgimsuvy]*)|@(?![\w$])/gv, (_, literal) => literal ?? '_$_v');
if (containsPath) {
script = script.replaceAll('@path', '_$_path');
}
const script = code.replaceAll(/('(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"|(?<=(?:^|[\(,=:\[!\|?\{\};+\-*%<>~^]|&)\s*)\/(?:\\.|\[(?:\\.|[^\]\\])*\]|[^\/\\\[])+\/[dgimsuvy]*)|@(?:(parentProperty|parent|property|root|path)|(?![\w$]))/gv, (_, literal, name) => literal ?? '_$_' + (name ?? 'v'));
const evalType = /** @type {string|boolean|undefined} */
this.currEval;
if (['safe', true, undefined].includes(evalType)) {
Expand Down
2 changes: 1 addition & 1 deletion dist/index-browser-umd.min.cjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index-browser-umd.min.cjs.map

Large diffs are not rendered by default.

9 changes: 3 additions & 6 deletions dist/index-node-cjs.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2398,15 +2398,12 @@ class JSONPathClass {
}
const scriptCacheKey = this.currEval + 'Script:' + code;
if (!scriptCache.has(scriptCacheKey)) {
let script = code.replaceAll('@parentProperty', '_$_parentProperty').replaceAll('@parent', '_$_parent').replaceAll('@property', '_$_property').replaceAll('@root', '_$_root')
// Replace a bare `@` (not followed by an identifier
// Replace `@parentProperty`, `@parent`, `@property`, `@root`,
// `@path` and a bare `@` (not followed by an identifier
// character) while leaving quoted string literals and
// regex literals (a `/` where an operand is expected,
// as opposed to division) intact
.replaceAll(/('(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"|(?<=(?:^|[\(,=:\[!\|?\{\};+\-*%<>~^]|&)\s*)\/(?:\\.|\[(?:\\.|[^\]\\])*\]|[^\/\\\[])+\/[dgimsuvy]*)|@(?![\w$])/gv, (_, literal) => literal ?? '_$_v');
if (containsPath) {
script = script.replaceAll('@path', '_$_path');
}
const script = code.replaceAll(/('(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"|(?<=(?:^|[\(,=:\[!\|?\{\};+\-*%<>~^]|&)\s*)\/(?:\\.|\[(?:\\.|[^\]\\])*\]|[^\/\\\[])+\/[dgimsuvy]*)|@(?:(parentProperty|parent|property|root|path)|(?![\w$]))/gv, (_, literal, name) => literal ?? '_$_' + (name ?? 'v'));
const evalType = /** @type {string|boolean|undefined} */
this.currEval;
if (['safe', true, undefined].includes(evalType)) {
Expand Down
9 changes: 3 additions & 6 deletions dist/index-node-esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -2396,15 +2396,12 @@ class JSONPathClass {
}
const scriptCacheKey = this.currEval + 'Script:' + code;
if (!scriptCache.has(scriptCacheKey)) {
let script = code.replaceAll('@parentProperty', '_$_parentProperty').replaceAll('@parent', '_$_parent').replaceAll('@property', '_$_property').replaceAll('@root', '_$_root')
// Replace a bare `@` (not followed by an identifier
// Replace `@parentProperty`, `@parent`, `@property`, `@root`,
// `@path` and a bare `@` (not followed by an identifier
// character) while leaving quoted string literals and
// regex literals (a `/` where an operand is expected,
// as opposed to division) intact
.replaceAll(/('(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"|(?<=(?:^|[\(,=:\[!\|?\{\};+\-*%<>~^]|&)\s*)\/(?:\\.|\[(?:\\.|[^\]\\])*\]|[^\/\\\[])+\/[dgimsuvy]*)|@(?![\w$])/gv, (_, literal) => literal ?? '_$_v');
if (containsPath) {
script = script.replaceAll('@path', '_$_path');
}
const script = code.replaceAll(/('(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"|(?<=(?:^|[\(,=:\[!\|?\{\};+\-*%<>~^]|&)\s*)\/(?:\\.|\[(?:\\.|[^\]\\])*\]|[^\/\\\[])+\/[dgimsuvy]*)|@(?:(parentProperty|parent|property|root|path)|(?![\w$]))/gv, (_, literal, name) => literal ?? '_$_' + (name ?? 'v'));
const evalType = /** @type {string|boolean|undefined} */
this.currEval;
if (['safe', true, undefined].includes(evalType)) {
Expand Down
25 changes: 9 additions & 16 deletions src/jsonpath.js
Original file line number Diff line number Diff line change
Expand Up @@ -1048,22 +1048,15 @@ class JSONPathClass {

const scriptCacheKey = this.currEval + 'Script:' + code;
if (!scriptCache.has(scriptCacheKey)) {
let script = code
.replaceAll('@parentProperty', '_$_parentProperty')
.replaceAll('@parent', '_$_parent')
.replaceAll('@property', '_$_property')
.replaceAll('@root', '_$_root')
// Replace a bare `@` (not followed by an identifier
// character) while leaving quoted string literals and
// regex literals (a `/` where an operand is expected,
// as opposed to division) intact
.replaceAll(
/('(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"|(?<=(?:^|[\(,=:\[!\|?\{\};+\-*%<>~^]|&)\s*)\/(?:\\.|\[(?:\\.|[^\]\\])*\]|[^\/\\\[])+\/[dgimsuvy]*)|@(?![\w$])/gv,
(_, literal) => literal ?? '_$_v'
);
if (containsPath) {
script = script.replaceAll('@path', '_$_path');
}
// Replace `@parentProperty`, `@parent`, `@property`, `@root`,
// `@path` and a bare `@` (not followed by an identifier
// character) while leaving quoted string literals and
// regex literals (a `/` where an operand is expected,
// as opposed to division) intact
const script = code.replaceAll(
/('(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"|(?<=(?:^|[\(,=:\[!\|?\{\};+\-*%<>~^]|&)\s*)\/(?:\\.|\[(?:\\.|[^\]\\])*\]|[^\/\\\[])+\/[dgimsuvy]*)|@(?:(parentProperty|parent|property|root|path)|(?![\w$]))/gv,
(_, literal, name) => literal ?? '_$_' + (name ?? 'v')
);
const evalType = /** @type {string|boolean|undefined} */ (
this.currEval
);
Expand Down
21 changes: 21 additions & 0 deletions test/test.at_and_dollar.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,26 @@ describe('JSONPath - At and Dollar sign', function () {
query(String.raw`$[?(@.a==='it\'s@')]`), [{a: "it's@"}]
);
});

it(`@root, @parent, etc. inside literals are left intact (${evalType})`, () => {
const json = [
{a: 'jo@rootmail.com'}, {a: 'kim@parentco.org'},
{a: 'lee@property.io'}, {a: 'x@parentProperty'},
{a: 'y@path'}
];
/** @param {string} path */
const query = (path) => jsonpathFn({json, path, eval: evalType});
for (const {a} of json) {
assertChai.deepEqual(query(`$[?(@.a==='${a}')]`), [{a}], a);
assertChai.deepEqual(query(`$[?(@.a==="${a}")]`), [{a}], a);
}
assertChai.deepEqual(
query('$[?(/@root/.test(@.a))]'), [{a: 'jo@rootmail.com'}]
);
assertChai.deepEqual(
query(`$[?(@property===4 && @path==="$[4]" && @.a==='y@path')]`),
[{a: 'y@path'}]
);
});
}
});
Loading