UNPKG

4.74 kBJavaScriptView Raw
1"use strict";
2// deno-lint-ignore-file no-explicit-any no-prototype-builtins
3Object.defineProperty(exports, "__esModule", { value: true });
4exports.match = exports.normalize = exports.trace = void 0;
5// Modernized version of Stefan Goessner's original JSON Path implementation.
6// Copyright (c) 2007 Stefan Goessner (goessner.net)
7// Licensed under the MIT license.
8// TODO: refactor to avoid string splitting/joining
9function* trace(expr, val, path) {
10 if (expr) {
11 const [loc, ...rest] = expr.split(";");
12 const x = rest.join(";");
13 if (val !== null && typeof val === 'object' && loc in val) {
14 yield* trace(x, val[loc], path + ";" + loc);
15 }
16 else if (loc === "*") {
17 for (const [m, _l, v, p] of walk(loc, val, path)) {
18 yield* trace(m + ";" + x, v, p);
19 }
20 }
21 else if (loc === "..") {
22 yield* trace(x, val, path);
23 for (const [m, _l, v, p] of walk(loc, val, path)) {
24 if (typeof v[m] === "object")
25 yield* trace("..;" + x, v[m], p + ";" + m);
26 }
27 }
28 else if (/,/.test(loc)) { // [name1,name2,...]
29 for (let s = loc.split(/'?,'?/), i = 0, n = s.length; i < n; i++)
30 yield* trace(s[i] + ";" + x, val, path);
31 }
32 else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)) { // [start:end:step] slice syntax
33 yield* slice(loc, x, val, path);
34 }
35 }
36 else
37 yield [path, val];
38}
39exports.trace = trace;
40function* slice(loc, expr, val, path) {
41 if (val instanceof Array) {
42 const len = val.length;
43 let start = 0, end = len, step = 1;
44 loc.replace(/^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/g, (_$0, $1, $2, $3) => {
45 start = parseInt($1 || start);
46 end = parseInt($2 || end);
47 step = parseInt($3 || step);
48 return '';
49 });
50 start = (start < 0) ? Math.max(0, start + len) : Math.min(len, start);
51 end = (end < 0) ? Math.max(0, end + len) : Math.min(len, end);
52 for (let i = start; i < end; i += step)
53 yield* trace(i + ";" + expr, val, path);
54 }
55}
56function* walk(loc, val, path) {
57 if (val instanceof Array) {
58 for (let i = 0, n = val.length; i < n; i++)
59 if (i in val)
60 yield [i, loc, val, path];
61 }
62 else if (typeof val === "object") {
63 for (const m in val)
64 if (val.hasOwnProperty(m))
65 yield [m, loc, val, path];
66 }
67}
68function normalize(expr) {
69 const subX = [];
70 if (!expr.startsWith('$'))
71 expr = '$' + expr;
72 return expr
73 .replace(/[\['](\??\(.*?\))[\]']/g, (_$0, $1) => { return "[#" + (subX.push($1) - 1) + "]"; })
74 .replace(/'?\.'?|\['?/g, ";")
75 .replace(/;;;|;;/g, ";..;")
76 .replace(/;$|'?\]|'$/g, "")
77 .replace(/#([0-9]+)/g, (_$0, $1) => { return subX[$1]; });
78}
79exports.normalize = normalize;
80// FIXME: avoid repeated split/join/regex.test
81function match(expr, path) {
82 if (expr && path) {
83 const [loc, ...restLoc] = expr.split(";");
84 const [val, ...restVal] = path.split(";");
85 const exprRest = restLoc.join(";");
86 const pathRest = restVal.join(';');
87 if (loc === val) {
88 return match(exprRest, pathRest);
89 }
90 else if (loc === "*") {
91 return match(exprRest, pathRest);
92 }
93 else if (loc === "..") {
94 return match(exprRest, path) || match("..;" + exprRest, pathRest);
95 }
96 else if (/,/.test(loc)) { // [name1,name2,...]
97 if (loc.split(/'?,'?/).some(v => v === val))
98 return match(exprRest, pathRest);
99 else
100 return false;
101 }
102 else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)) { // [start:end:step] slice syntax
103 let start = 0, end = Number.MAX_SAFE_INTEGER, step = 1;
104 loc.replace(/^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/g, (_$0, $1, $2, $3) => {
105 start = parseInt($1 || start);
106 end = parseInt($2 || end);
107 step = parseInt($3 || step);
108 return '';
109 });
110 const idx = Number(val);
111 if (start < 0 || end < 0 || step < 0)
112 throw TypeError('Negative numbers not supported. Can\'t know length ahead of time when stream parsing');
113 if (idx >= start && idx < end && start + idx % step === 0)
114 return match(exprRest, pathRest);
115 else
116 return false;
117 }
118 }
119 else if (!expr && !path)
120 return true;
121 return false;
122}
123exports.match = match;
124//# sourceMappingURL=json-path.js.map
\No newline at end of file