astronomical 1.0.0-beta.12
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 +201 -0
- package/README.md +79 -0
- package/lib/cjs/index.js +453 -0
- package/lib/cjs/nodeutils.js +241 -0
- package/lib/cjs/parseQuery.js +298 -0
- package/lib/cjs/traverse.js +197 -0
- package/lib/cjs/types/index.d.ts +23 -0
- package/lib/cjs/types/index.d.ts.map +1 -0
- package/lib/cjs/types/nodeutils.d.ts +17 -0
- package/lib/cjs/types/nodeutils.d.ts.map +1 -0
- package/lib/cjs/types/parseQuery.d.ts +42 -0
- package/lib/cjs/types/parseQuery.d.ts.map +1 -0
- package/lib/cjs/types/traverse.d.ts +29 -0
- package/lib/cjs/types/traverse.d.ts.map +1 -0
- package/lib/esm/index.mjs +453 -0
- package/lib/esm/nodeutils.js +241 -0
- package/lib/esm/parseQuery.js +298 -0
- package/lib/esm/traverse.js +197 -0
- package/lib/esm/types/index.d.ts +23 -0
- package/lib/esm/types/index.d.ts.map +1 -0
- package/lib/esm/types/nodeutils.d.ts +17 -0
- package/lib/esm/types/nodeutils.d.ts.map +1 -0
- package/lib/esm/types/parseQuery.d.ts +42 -0
- package/lib/esm/types/parseQuery.d.ts.map +1 -0
- package/lib/esm/types/traverse.d.ts +29 -0
- package/lib/esm/types/traverse.d.ts.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parse = exports.tokenize = void 0;
|
|
4
|
+
const _1 = require(".");
|
|
5
|
+
const nodeutils_1 = require("./nodeutils");
|
|
6
|
+
const debugLogEnabled = false;
|
|
7
|
+
const log = {
|
|
8
|
+
debug: (...args) => {
|
|
9
|
+
if (debugLogEnabled)
|
|
10
|
+
console.debug(...args);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
const supportedIdentifiers = Object.fromEntries(Object.keys(nodeutils_1.VISITOR_KEYS).map(k => [k, k]));
|
|
14
|
+
function isIdentifierToken(token) {
|
|
15
|
+
if (token == undefined)
|
|
16
|
+
return false;
|
|
17
|
+
if (token.type != "identifier" && token.type != "wildcard")
|
|
18
|
+
return false;
|
|
19
|
+
if (!token.value)
|
|
20
|
+
return false;
|
|
21
|
+
if (!(token.value in supportedIdentifiers) && token.value != "*") {
|
|
22
|
+
throw new Error("Unsupported identifier: " + token.value);
|
|
23
|
+
}
|
|
24
|
+
;
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
const whitespace = " \n\r\t";
|
|
28
|
+
function isCharacter(c) {
|
|
29
|
+
const charcode = c.charCodeAt(0);
|
|
30
|
+
return (charcode >= 65 && charcode <= 90) || (charcode >= 97 && charcode <= 122);
|
|
31
|
+
}
|
|
32
|
+
function isInteger(c) {
|
|
33
|
+
const charcode = c.charCodeAt(0);
|
|
34
|
+
return (charcode >= 48 && charcode <= 57);
|
|
35
|
+
}
|
|
36
|
+
function tokenize(input) {
|
|
37
|
+
let s = 0;
|
|
38
|
+
const result = [];
|
|
39
|
+
while (s < input.length) {
|
|
40
|
+
while (whitespace.includes(input[s]))
|
|
41
|
+
s++;
|
|
42
|
+
if (s >= input.length)
|
|
43
|
+
break;
|
|
44
|
+
if (input[s] == "/") {
|
|
45
|
+
if (input[s + 1] == "/") {
|
|
46
|
+
result.push({ type: "descendant" });
|
|
47
|
+
s += 2;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
result.push({ type: "child" });
|
|
51
|
+
s++;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (input[s] == ":") {
|
|
55
|
+
result.push({ type: "attributeSelector" });
|
|
56
|
+
s++;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (input[s] == "$" && input[s + 1] == "$") {
|
|
60
|
+
result.push({ type: "resolveSelector" });
|
|
61
|
+
s += 2;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (input[s] == "$") {
|
|
65
|
+
result.push({ type: "bindingSelector" });
|
|
66
|
+
s++;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (input[s] == "[") {
|
|
70
|
+
result.push({ type: "filterBegin" });
|
|
71
|
+
s++;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (input[s] == "]") {
|
|
75
|
+
result.push({ type: "filterEnd" });
|
|
76
|
+
s++;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (input[s] == ",") {
|
|
80
|
+
result.push({ type: "separator" });
|
|
81
|
+
s++;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (input[s] == "(") {
|
|
85
|
+
result.push({ type: "parametersBegin" });
|
|
86
|
+
s++;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (input[s] == "f" && input[s + 1] == "n" && input[s + 2] == ":") {
|
|
90
|
+
result.push({ type: "function" });
|
|
91
|
+
s += 3;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (input[s] == ")") {
|
|
95
|
+
result.push({ type: "parametersEnd" });
|
|
96
|
+
s++;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (input[s] == "&" && input[s + 1] == "&") {
|
|
100
|
+
result.push({ type: "and" });
|
|
101
|
+
s += 2;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (input[s] == "|" && input[s + 1] == "|") {
|
|
105
|
+
result.push({ type: "or" });
|
|
106
|
+
s += 2;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (input[s] == "=" && input[s + 1] == "=") {
|
|
110
|
+
result.push({ type: "eq" });
|
|
111
|
+
s += 2;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (input[s] == "'" || input[s] == '"') {
|
|
115
|
+
const begin = input[s];
|
|
116
|
+
const start = s;
|
|
117
|
+
s++;
|
|
118
|
+
while (s < input.length && input[s] != begin)
|
|
119
|
+
s++;
|
|
120
|
+
result.push({ type: "literal", value: input.slice(start + 1, s) });
|
|
121
|
+
s++;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (input[s] == "." && input[s + 1] == ".") {
|
|
125
|
+
result.push({ type: "parent" });
|
|
126
|
+
s += 2;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (input[s] == "*") {
|
|
130
|
+
result.push({ type: "wildcard", value: "*" });
|
|
131
|
+
s++;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (isCharacter(input[s])) {
|
|
135
|
+
const start = s;
|
|
136
|
+
while (s < input.length && isCharacter(input[s]))
|
|
137
|
+
s++;
|
|
138
|
+
result.push({ type: "identifier", value: input.slice(start, s) });
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (isInteger(input[s])) {
|
|
142
|
+
const start = s;
|
|
143
|
+
while (s < input.length && isInteger(input[s]))
|
|
144
|
+
s++;
|
|
145
|
+
result.push({ type: "literal", value: input.slice(start, s) });
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
throw new Error("Unexpected token: " + input[s]);
|
|
149
|
+
}
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
exports.tokenize = tokenize;
|
|
153
|
+
function buildFilter(tokens) {
|
|
154
|
+
log.debug("BUILD FILTER", tokens);
|
|
155
|
+
tokens.shift();
|
|
156
|
+
const p = buildTree(tokens);
|
|
157
|
+
const next = tokens[0];
|
|
158
|
+
if (next.type == "and") {
|
|
159
|
+
return {
|
|
160
|
+
type: "and",
|
|
161
|
+
left: p,
|
|
162
|
+
right: buildFilter(tokens)
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
if (next.type == "or") {
|
|
166
|
+
return {
|
|
167
|
+
type: "or",
|
|
168
|
+
left: p,
|
|
169
|
+
right: buildFilter(tokens)
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
if (next.type == "eq") {
|
|
173
|
+
const right = buildFilter(tokens);
|
|
174
|
+
if (right.type == "or" || right.type == "and") {
|
|
175
|
+
return {
|
|
176
|
+
type: right.type,
|
|
177
|
+
left: {
|
|
178
|
+
type: "equals",
|
|
179
|
+
left: p,
|
|
180
|
+
right: right.left
|
|
181
|
+
},
|
|
182
|
+
right: right.right
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
if (right.type == "equals")
|
|
186
|
+
throw new Error("Unexpected equals in equals");
|
|
187
|
+
return {
|
|
188
|
+
type: "equals",
|
|
189
|
+
left: p,
|
|
190
|
+
right: right
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
if (next.type == "filterEnd") {
|
|
194
|
+
tokens.shift();
|
|
195
|
+
return p;
|
|
196
|
+
}
|
|
197
|
+
throw new Error("Unexpected token in filter: " + next?.type);
|
|
198
|
+
}
|
|
199
|
+
const subNodes = ["child", "descendant"];
|
|
200
|
+
function buildTree(tokens) {
|
|
201
|
+
log.debug("BUILD TREE", tokens);
|
|
202
|
+
if (tokens.length == 0)
|
|
203
|
+
throw new Error("Unexpected end of input");
|
|
204
|
+
const token = tokens.shift();
|
|
205
|
+
if (token == undefined)
|
|
206
|
+
throw new Error("Unexpected end of input");
|
|
207
|
+
if (token.type == "parent") {
|
|
208
|
+
return {
|
|
209
|
+
type: "parent",
|
|
210
|
+
child: buildTree(tokens)
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
if (subNodes.includes(token.type)) {
|
|
214
|
+
let next = tokens.shift();
|
|
215
|
+
if (next?.type == "function") {
|
|
216
|
+
const name = tokens.shift();
|
|
217
|
+
if (name == undefined || name.type != "identifier" || name.value == undefined || typeof (name.value) != "string")
|
|
218
|
+
throw new Error("Unexpected token: " + name?.type + ". Expecting function name");
|
|
219
|
+
const value = name.value;
|
|
220
|
+
if (!(0, _1.isAvailableFunction)(value)) {
|
|
221
|
+
throw new Error("Unsupported function: " + name.value);
|
|
222
|
+
}
|
|
223
|
+
return buildFunctionCall(value, tokens);
|
|
224
|
+
}
|
|
225
|
+
if (next?.type == "parent") {
|
|
226
|
+
return { type: "parent", child: buildTree(tokens) };
|
|
227
|
+
}
|
|
228
|
+
const modifiers = [];
|
|
229
|
+
while (next && (next?.type == "attributeSelector" || next?.type == "bindingSelector" || next?.type == "resolveSelector")) {
|
|
230
|
+
modifiers.push(next);
|
|
231
|
+
next = tokens.shift();
|
|
232
|
+
}
|
|
233
|
+
const isAttribute = modifiers.some(m => m.type == "attributeSelector");
|
|
234
|
+
const isBinding = modifiers.some(m => m.type == "bindingSelector");
|
|
235
|
+
const isResolve = modifiers.some(m => m.type == "resolveSelector");
|
|
236
|
+
if (isResolve && isBinding)
|
|
237
|
+
throw new Error("Cannot have both resolve and binding");
|
|
238
|
+
if (!next || !next.value || (!isAttribute && !isIdentifierToken(next)))
|
|
239
|
+
throw new Error("Unexpected or missing token: " + next?.type);
|
|
240
|
+
const identifer = next.value;
|
|
241
|
+
let filter = undefined;
|
|
242
|
+
if (tokens.length > 0 && tokens[0].type == "filterBegin") {
|
|
243
|
+
filter = buildFilter(tokens);
|
|
244
|
+
log.debug("FILTER", filter, tokens);
|
|
245
|
+
}
|
|
246
|
+
let child = undefined;
|
|
247
|
+
if (tokens.length > 0 && subNodes.includes(tokens[0].type)) {
|
|
248
|
+
child = buildTree(tokens);
|
|
249
|
+
}
|
|
250
|
+
if (typeof (identifer) != "string")
|
|
251
|
+
throw new Error("Identifier must be a string");
|
|
252
|
+
return {
|
|
253
|
+
type: token.type,
|
|
254
|
+
value: identifer,
|
|
255
|
+
attribute: isAttribute,
|
|
256
|
+
binding: isBinding,
|
|
257
|
+
resolve: isResolve,
|
|
258
|
+
filter: filter,
|
|
259
|
+
child: child
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
if (token.type == "literal") {
|
|
263
|
+
return {
|
|
264
|
+
type: "literal",
|
|
265
|
+
value: token.value
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
throw new Error("Unexpected token: " + token.type);
|
|
269
|
+
}
|
|
270
|
+
function buildFunctionCall(name, tokens) {
|
|
271
|
+
log.debug("BUILD FUNCTION", name, tokens);
|
|
272
|
+
const parameters = [];
|
|
273
|
+
const next = tokens.shift();
|
|
274
|
+
if (next?.type != "parametersBegin")
|
|
275
|
+
throw new Error("Unexpected token: " + next?.type);
|
|
276
|
+
while (tokens.length > 0 && tokens[0].type != "parametersEnd") {
|
|
277
|
+
parameters.push(buildTree(tokens));
|
|
278
|
+
if (tokens[0].type == "separator")
|
|
279
|
+
tokens.shift();
|
|
280
|
+
}
|
|
281
|
+
if (tokens.length == 0)
|
|
282
|
+
throw new Error("Unexpected end of input");
|
|
283
|
+
tokens.shift();
|
|
284
|
+
return {
|
|
285
|
+
type: "function",
|
|
286
|
+
function: name,
|
|
287
|
+
parameters: parameters
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function parse(input) {
|
|
291
|
+
const tokens = tokenize(input);
|
|
292
|
+
const result = buildTree(tokens);
|
|
293
|
+
log.debug("RESULT", result);
|
|
294
|
+
if (!result)
|
|
295
|
+
throw new Error("No root element found");
|
|
296
|
+
return result;
|
|
297
|
+
}
|
|
298
|
+
exports.parse = parse;
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createNodePath = exports.getBinding = void 0;
|
|
4
|
+
const nodeutils_1 = require("./nodeutils");
|
|
5
|
+
const debugLogEnabled = false;
|
|
6
|
+
const log = {
|
|
7
|
+
debug: (...args) => {
|
|
8
|
+
if (debugLogEnabled)
|
|
9
|
+
console.debug(...args);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const scopes = new Array(100000);
|
|
13
|
+
const voidFn = () => { };
|
|
14
|
+
let scopeIdCounter = 0;
|
|
15
|
+
let removedScopes = 0;
|
|
16
|
+
function createScope(parentScopeId) {
|
|
17
|
+
const id = scopeIdCounter++;
|
|
18
|
+
/*const bindings: Record<string, Binding> = {};
|
|
19
|
+
const s: Scope = {
|
|
20
|
+
bindings,
|
|
21
|
+
id,
|
|
22
|
+
parentScopeId,
|
|
23
|
+
hasEntries: false
|
|
24
|
+
}*/
|
|
25
|
+
scopes[id] = parentScopeId ?? -1;
|
|
26
|
+
return id;
|
|
27
|
+
}
|
|
28
|
+
function getBinding(scopeId, name) {
|
|
29
|
+
const scope = scopes[scopeId];
|
|
30
|
+
if (typeof scope == "number") {
|
|
31
|
+
if (scope == -1)
|
|
32
|
+
return undefined;
|
|
33
|
+
return getBinding(scope, name);
|
|
34
|
+
}
|
|
35
|
+
const s = scope.bindings[name];
|
|
36
|
+
if (s)
|
|
37
|
+
return s;
|
|
38
|
+
if (scope.parentScopeId != undefined && scope.parentScopeId >= 0) {
|
|
39
|
+
return getBinding(scope.parentScopeId, name);
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
exports.getBinding = getBinding;
|
|
44
|
+
function setBinding(scopeId, name, binding) {
|
|
45
|
+
let scope;
|
|
46
|
+
const s = scopes[scopeId];
|
|
47
|
+
if (typeof s == "number") {
|
|
48
|
+
scope = {
|
|
49
|
+
bindings: {},
|
|
50
|
+
id: scopeId,
|
|
51
|
+
parentScopeId: s == -1 ? undefined : s,
|
|
52
|
+
hasEntries: false
|
|
53
|
+
};
|
|
54
|
+
scopes[scopeId] = scope;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
scope = s;
|
|
58
|
+
}
|
|
59
|
+
scope.bindings[name] = binding;
|
|
60
|
+
scope.hasEntries = true;
|
|
61
|
+
}
|
|
62
|
+
let pathsCreated = 0;
|
|
63
|
+
const nodeKey = "ASTronomical-path";
|
|
64
|
+
function createNodePath(node, key, parentKey, scopeId, nodePath) {
|
|
65
|
+
if (node.extra && node.extra[nodeKey]) {
|
|
66
|
+
const path = node.extra[nodeKey];
|
|
67
|
+
path.key = key;
|
|
68
|
+
path.parentKey = parentKey;
|
|
69
|
+
path.parentPath = nodePath;
|
|
70
|
+
return path;
|
|
71
|
+
}
|
|
72
|
+
const finalScope = ((node.extra && node.extra["scopeId"]) ? node.extra["scopeId"] : scopeId) ?? createScope();
|
|
73
|
+
const path = {
|
|
74
|
+
node,
|
|
75
|
+
scopeId: finalScope,
|
|
76
|
+
shouldStop: false,
|
|
77
|
+
stop: voidFn,
|
|
78
|
+
get: (key) => {
|
|
79
|
+
if (key in node) {
|
|
80
|
+
const r = node[key];
|
|
81
|
+
if (Array.isArray(r)) {
|
|
82
|
+
return r.map((n, i) => createNodePath(n, i.toString(), key, scopeId, nodePath));
|
|
83
|
+
}
|
|
84
|
+
else if (r != undefined) {
|
|
85
|
+
return [createNodePath(r, key, key, scopeId, nodePath)];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return [];
|
|
89
|
+
},
|
|
90
|
+
parentPath: nodePath,
|
|
91
|
+
key,
|
|
92
|
+
parentKey
|
|
93
|
+
};
|
|
94
|
+
path.stop = () => { path.shouldStop = true; };
|
|
95
|
+
if ((0, nodeutils_1.isNode)(node)) {
|
|
96
|
+
node.extra = node.extra ?? {};
|
|
97
|
+
node.extra[nodeKey] = path;
|
|
98
|
+
Object.defineProperty(node.extra, nodeKey, { enumerable: false });
|
|
99
|
+
}
|
|
100
|
+
pathsCreated++;
|
|
101
|
+
return path;
|
|
102
|
+
}
|
|
103
|
+
exports.createNodePath = createNodePath;
|
|
104
|
+
function registerBinding(node, parentNode, grandParentNode, scopeId) {
|
|
105
|
+
//console.log("x registerBinding?", isIdentifier(node) ? node.name : node.type, parentNode.type, grandParentNode?.type, scopeId, isBinding(node, parentNode, grandParentNode));
|
|
106
|
+
if ((0, nodeutils_1.isBinding)(node, parentNode, grandParentNode)) {
|
|
107
|
+
if ((0, nodeutils_1.isIdentifier)(node) && !(0, nodeutils_1.isAssignmentExpression)(parentNode) && !(0, nodeutils_1.isMemberExpression)(parentNode)) {
|
|
108
|
+
//console.log("x registerBinding!", node.name, parentNode.type, grandParentNode?.type, scopeId);
|
|
109
|
+
//A bit of a hack here as well. Needs some further investigation
|
|
110
|
+
if ((0, nodeutils_1.isScope)(node, parentNode)) {
|
|
111
|
+
setBinding(scopeId, node.name, { path: createNodePath(node, undefined, undefined, scopeId) });
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
setBinding(scopeId, node.name, { path: createNodePath(parentNode, undefined, undefined, scopeId) });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function registerBindings(node, parentNode, grandParentNode, scopeId) {
|
|
120
|
+
if (typeof node == "object" && node != null) {
|
|
121
|
+
node.extra = node.extra ?? {};
|
|
122
|
+
if (node.extra["scopeId"])
|
|
123
|
+
return;
|
|
124
|
+
node.extra["scopeId"] = scopeId;
|
|
125
|
+
}
|
|
126
|
+
const keys = nodeutils_1.VISITOR_KEYS[node.type];
|
|
127
|
+
//console.log(keys, node);
|
|
128
|
+
if (!keys) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
let childScopeId = scopeId;
|
|
132
|
+
// This is also buggy. Need to investigate what creates a new scope
|
|
133
|
+
if ((0, nodeutils_1.isScopable)(node)) {
|
|
134
|
+
childScopeId = createScope(scopeId);
|
|
135
|
+
}
|
|
136
|
+
for (const key of keys) {
|
|
137
|
+
const childNodes = node[key];
|
|
138
|
+
const children = Array.isArray(childNodes) ? childNodes : childNodes ? [childNodes] : [];
|
|
139
|
+
children.forEach((child) => {
|
|
140
|
+
if ((0, nodeutils_1.isNode)(child)) {
|
|
141
|
+
// This feels like a hack. Need to figure out how to make this work
|
|
142
|
+
// for other types of scopes as well (classes, etc.)
|
|
143
|
+
const s = key == "id" ? scopeId : childScopeId;
|
|
144
|
+
registerBinding(child, node, parentNode, s);
|
|
145
|
+
registerBindings(child, node, parentNode, s);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
if (childScopeId != scopeId && typeof scopes[childScopeId] == "number") { // Scope has not been populated
|
|
150
|
+
scopes[childScopeId] = scopes[scopeId];
|
|
151
|
+
removedScopes++;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function traverseInner(node, visitor, scopeId, state, path) {
|
|
155
|
+
const nodePath = path ?? createNodePath(node, undefined, undefined, scopeId);
|
|
156
|
+
const keys = nodeutils_1.VISITOR_KEYS[node.type];
|
|
157
|
+
if (nodePath.parentPath)
|
|
158
|
+
registerBindings(nodePath.node, nodePath.parentPath.node, nodePath.parentPath.parentPath?.node, nodePath.scopeId);
|
|
159
|
+
if (!keys) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
for (const key of keys) {
|
|
163
|
+
const childNodes = node[key];
|
|
164
|
+
const children = Array.isArray(childNodes) ? childNodes : childNodes ? [childNodes] : [];
|
|
165
|
+
const nodePaths = children.map((child, i) => {
|
|
166
|
+
if ((0, nodeutils_1.isNode)(child)) {
|
|
167
|
+
return createNodePath(child, key, Array.isArray(childNodes) ? i.toString() : key, nodePath.scopeId, nodePath);
|
|
168
|
+
}
|
|
169
|
+
return undefined;
|
|
170
|
+
}).filter(x => x != undefined);
|
|
171
|
+
nodePaths.forEach((childPath) => {
|
|
172
|
+
visitor.enter(childPath, state);
|
|
173
|
+
if (childPath.shouldStop) {
|
|
174
|
+
childPath.shouldStop = false;
|
|
175
|
+
nodePath.shouldStop = true;
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
traverseInner(childPath.node, visitor, nodePath.scopeId, state, childPath);
|
|
179
|
+
if (visitor.exit)
|
|
180
|
+
visitor.exit(childPath, state);
|
|
181
|
+
if (childPath.shouldStop) {
|
|
182
|
+
childPath.shouldStop = false;
|
|
183
|
+
nodePath.shouldStop = true;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const sOut = [];
|
|
190
|
+
function traverse(node, visitor, scopeId, state, path) {
|
|
191
|
+
traverseInner(node, visitor, scopeId, state, path);
|
|
192
|
+
if (!sOut.includes(scopeIdCounter)) {
|
|
193
|
+
log.debug("Scopes created", scopeIdCounter, " Scopes removed", removedScopes, "Paths created", pathsCreated);
|
|
194
|
+
sOut.push(scopeIdCounter);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
exports.default = traverse;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ASTNode } from "./nodeutils";
|
|
2
|
+
export declare const functions: {
|
|
3
|
+
join: {
|
|
4
|
+
fn: (result: Result[][]) => Result[];
|
|
5
|
+
};
|
|
6
|
+
concat: {
|
|
7
|
+
fn: (result: Result[][]) => Result[];
|
|
8
|
+
};
|
|
9
|
+
first: {
|
|
10
|
+
fn: (result: Result[][]) => Result[];
|
|
11
|
+
};
|
|
12
|
+
nthchild: {
|
|
13
|
+
fn: (result: Result[][]) => Result[];
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export type AvailableFunction = keyof typeof functions;
|
|
17
|
+
export declare function isAvailableFunction(name: string): name is AvailableFunction;
|
|
18
|
+
type Result = ASTNode | string | number | boolean;
|
|
19
|
+
export declare function query(code: ASTNode | string, query: string): Result[];
|
|
20
|
+
export declare function multiQuery<T extends Record<string, string>>(code: ASTNode | string, namedQueries: T): Record<keyof T, Result[]>;
|
|
21
|
+
export declare function parseSource(source: string): ASTNode;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAUtC,eAAO,MAAM,SAAS;;qBAEL,MAAM,EAAE,EAAE,KAAG,MAAM,EAAE;;;qBAWrB,MAAM,EAAE,EAAE,KAAG,MAAM,EAAE;;;qBAMrB,MAAM,EAAE,EAAE,KAAG,MAAM,EAAE;;;qBAOrB,MAAM,EAAE,EAAE,KAAG,MAAM,EAAE;;CASrC,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,SAAS,CAAC;AACvD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAI,IAAI,IAAI,iBAAiB,CAE5E;AAOD,KAAK,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAiXlD,wBAAgB,KAAK,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,GAAI,MAAM,EAAE,CAEtE;AAED,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE,YAAY,EAAE,CAAC,GAAI,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAQhI;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAI,OAAO,CAMpD"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ESTree } from "meriyah";
|
|
2
|
+
export declare function isNode(candidate: unknown): candidate is ASTNode;
|
|
3
|
+
export declare function isAssignmentExpression(node: ESTree.Node): node is ESTree.AssignmentExpression;
|
|
4
|
+
export declare function isMemberExpression(node: ESTree.Node): node is ESTree.MemberExpression;
|
|
5
|
+
export declare function isIdentifier(node: ESTree.Node): node is ESTree.Identifier;
|
|
6
|
+
export declare function isFunctionDeclaration(node: ESTree.Node): node is ESTree.FunctionDeclaration;
|
|
7
|
+
export declare function isFunctionExpression(node: ESTree.Node): node is ESTree.FunctionExpression;
|
|
8
|
+
export declare function isVariableDeclarator(node: ESTree.Node): node is ESTree.VariableDeclarator;
|
|
9
|
+
export declare function isBinding(node: ESTree.Node, parentNode: ESTree.Node, grandParentNode: ESTree.Node | undefined): boolean;
|
|
10
|
+
export declare const VISITOR_KEYS: Record<ESTree.Node["type"], string[]>;
|
|
11
|
+
export declare function isScope(node: ESTree.Node, parentNode: ESTree.Node): boolean;
|
|
12
|
+
export declare function isScopable(node: ESTree.Node): boolean;
|
|
13
|
+
export declare function isExportSpecifier(node: ESTree.Node): node is ESTree.ExportSpecifier;
|
|
14
|
+
export type ASTNode = ESTree.Node & {
|
|
15
|
+
extra?: Record<string, unknown>;
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=nodeutils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nodeutils.d.ts","sourceRoot":"","sources":["../../../src/nodeutils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,wBAAgB,MAAM,CAAC,SAAS,EAAE,OAAO,GAAI,SAAS,IAAI,OAAO,CAEhE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,IAAI,IAAI,MAAM,CAAC,oBAAoB,CAE7F;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,IAAI,IAAI,MAAM,CAAC,gBAAgB,CAErF;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,IAAI,IAAI,MAAM,CAAC,UAAU,CAEzE;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,IAAI,IAAI,MAAM,CAAC,mBAAmB,CAE3F;AACD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,IAAI,IAAI,MAAM,CAAC,kBAAkB,CAEzF;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,IAAI,IAAI,MAAM,CAAC,kBAAkB,CAEzF;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,CAAC,IAAI,GAAG,SAAS,GAAG,OAAO,CA0BvH;AAuDD,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CA0F9D,CAAC;AAqBF,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,GAAG,OAAO,CAS3E;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,OAAO,CAqBrD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,IAAI,IAAI,MAAM,CAAC,eAAe,CAEnF;AAGD,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { AvailableFunction } from ".";
|
|
2
|
+
type Token = {
|
|
3
|
+
type: string;
|
|
4
|
+
value?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function tokenize(input: string): Token[];
|
|
7
|
+
type BaseNode = {
|
|
8
|
+
type: string;
|
|
9
|
+
attribute?: boolean;
|
|
10
|
+
binding?: boolean;
|
|
11
|
+
resolve?: boolean;
|
|
12
|
+
filter?: QNode;
|
|
13
|
+
value?: string;
|
|
14
|
+
child?: QNode;
|
|
15
|
+
};
|
|
16
|
+
export type Selector = BaseNode & ({
|
|
17
|
+
type: "child" | "descendant";
|
|
18
|
+
attribute: boolean;
|
|
19
|
+
binding: boolean;
|
|
20
|
+
value: string;
|
|
21
|
+
resolve: boolean;
|
|
22
|
+
} | {
|
|
23
|
+
type: "parent";
|
|
24
|
+
});
|
|
25
|
+
export type Condition = BaseNode & {
|
|
26
|
+
type: "and" | "or" | "equals";
|
|
27
|
+
left: QNode;
|
|
28
|
+
right: QNode;
|
|
29
|
+
};
|
|
30
|
+
export type Literal = BaseNode & {
|
|
31
|
+
type: "literal";
|
|
32
|
+
value: string;
|
|
33
|
+
};
|
|
34
|
+
export type FunctionCall = BaseNode & {
|
|
35
|
+
type: "function";
|
|
36
|
+
function: AvailableFunction;
|
|
37
|
+
parameters: QNode[];
|
|
38
|
+
};
|
|
39
|
+
export type QNode = Selector | Condition | Literal | FunctionCall;
|
|
40
|
+
export declare function parse(input: string): QNode;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=parseQuery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseQuery.d.ts","sourceRoot":"","sources":["../../../src/parseQuery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAuB,MAAM,GAAG,CAAC;AAa3D,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAA;AA2BD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAI,KAAK,EAAE,CA8GhD;AACD,KAAK,QAAQ,GAAG;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,CAAC;IACjC,IAAI,EAAE,OAAO,GAAG,YAAY,CAAC;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB,GAAG;IACF,IAAI,EAAE,QAAQ,CAAA;CACf,CAAC,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG;IACjC,IAAI,EAAE,KAAK,GAAG,IAAI,GAAG,QAAQ,CAAC;IAC9B,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE,KAAK,CAAC;CACd,CAAA;AACD,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG;IACpC,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,UAAU,EAAE,KAAK,EAAE,CAAC;CACrB,CAAA;AAED,MAAM,MAAM,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,YAAY,CAAE;AAyInE,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAM1C"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ASTNode } from "./nodeutils";
|
|
2
|
+
export type Binding = {
|
|
3
|
+
path: NodePath<ASTNode>;
|
|
4
|
+
};
|
|
5
|
+
export type Scope = {
|
|
6
|
+
bindings: Record<string, Binding>;
|
|
7
|
+
parentScopeId?: number;
|
|
8
|
+
id: number;
|
|
9
|
+
hasEntries: boolean;
|
|
10
|
+
};
|
|
11
|
+
export type NodePath<T> = {
|
|
12
|
+
node: T;
|
|
13
|
+
key?: string;
|
|
14
|
+
parentPath?: NodePath<T>;
|
|
15
|
+
parentKey?: string;
|
|
16
|
+
stop: () => void;
|
|
17
|
+
get(key: string): NodePath<ASTNode>[];
|
|
18
|
+
scopeId: number;
|
|
19
|
+
shouldStop: boolean;
|
|
20
|
+
};
|
|
21
|
+
type Visitor<T> = {
|
|
22
|
+
enter: (path: NodePath<ASTNode>, state: T) => void;
|
|
23
|
+
exit?: (path: NodePath<ASTNode>, state: T) => void;
|
|
24
|
+
};
|
|
25
|
+
export declare function getBinding(scopeId: number, name: string): Binding | undefined;
|
|
26
|
+
export declare function createNodePath(node: ASTNode, key: string | undefined, parentKey: string | undefined, scopeId: number | undefined, nodePath?: NodePath<ASTNode>): NodePath<ASTNode>;
|
|
27
|
+
export default function traverse<T>(node: ASTNode, visitor: Visitor<T>, scopeId: number | undefined, state: T, path?: NodePath<ASTNode>): void;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=traverse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traverse.d.ts","sourceRoot":"","sources":["../../../src/traverse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAkH,MAAM,aAAa,CAAC;AAStJ,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;CACzB,CAAA;AAED,MAAM,MAAM,KAAK,GAAG;IAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAMF,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;IACxB,IAAI,EAAE,CAAC,CAAC;IACR,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,KAAK,OAAO,CAAC,CAAC,IAAI;IAChB,KAAK,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IACnD,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;CACpD,CAAA;AAmBD,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,uBAYvD;AAwBD,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAI,QAAQ,CAAC,OAAO,CAAC,CAsCnL;AAuGD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,CAAC,EAAI,IAAI,EAAE,OAAO,EACjD,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,KAAK,EAAE,CAAC,EACR,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,QAMzB"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "astronomical",
|
|
3
|
+
"version": "1.0.0-beta.12",
|
|
4
|
+
"description": "offers a way to query a Javascript AST to find specific patterns using a syntax somewhat similar to XPath.",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"lint": "eslint . --ext .ts --fix --ignore-path .gitignore",
|
|
7
|
+
"typecheck": "tsc --noEmit",
|
|
8
|
+
"clean": "rm -rf lib && mkdir lib",
|
|
9
|
+
"build": "npm run clean && npm run build:esm && npm run build:cjs",
|
|
10
|
+
"build:esm": "tsc && mv lib/esm/index.js lib/esm/index.mjs",
|
|
11
|
+
"build:cjs": "tsc -p ./tsconfig.cjs.json",
|
|
12
|
+
"watch": "tsc --watch",
|
|
13
|
+
"check": "npm run lint && npm run typecheck",
|
|
14
|
+
"dev": "tsc --watch",
|
|
15
|
+
"testWatch": "jest --watchAll",
|
|
16
|
+
"test": "jest --ci",
|
|
17
|
+
"prepack": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/RetireJS/babel-q.git"
|
|
22
|
+
},
|
|
23
|
+
"author": "Erlend Oftedal <erlend@oftedal.no>",
|
|
24
|
+
"license": "Apache-2.0",
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/jest": "^29.5.11",
|
|
27
|
+
"@types/node": "^20.11.5",
|
|
28
|
+
"@typescript-eslint/eslint-plugin": "^6.20.0",
|
|
29
|
+
"eslint": "^8.56.0",
|
|
30
|
+
"eslint-config-prettier": "^9.1.0",
|
|
31
|
+
"prettier": "^3.2.4",
|
|
32
|
+
"ts-jest": "^29.1.2",
|
|
33
|
+
"typescript": "^5.3.3"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"meriyah": "^4.3.9"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"lib/**/*"
|
|
40
|
+
],
|
|
41
|
+
"exports": {
|
|
42
|
+
".": {
|
|
43
|
+
"import": {
|
|
44
|
+
"types": "./lib/esm/types/index.d.ts",
|
|
45
|
+
"default": "./lib/esm/index.mjs"
|
|
46
|
+
},
|
|
47
|
+
"require": {
|
|
48
|
+
"types": "./lib/cjs/types/index.d.ts",
|
|
49
|
+
"default": "./lib/cjs/index.js"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"types": "./lib/cjs/types/index.d.ts",
|
|
54
|
+
"main": "./lib/cjs/index.js"
|
|
55
|
+
}
|