astronomical
offers a way to query a JavaScript AST to find specific patterns using a syntax somewhat similar to XPath.
astronomical
was inspired by astq, but offers some features that did not seem possible in astq
and also has some limits compared to astq
.
Goals:
- Should try to traverse the AST only once when resolving the Query
- Should allow filtering of nodes
- Allow running multiple queries at the same time without traversing the AST multiple times
The following pattern:
//AssignmentExpression[
/MemberExpression[
/:property/:name == "migrateVersion" &&
/$:object == ../../../../:params
]
]/:right/:value
tries to find the following code snippet and returns the string value assigned to the migrateVersion
property:
...
function( jQuery, window ) {
...
jQuery.migrateVersion = "3.4.1";
...
}
...
Find an AssignmentExpression at arbitrary depth, which directly contains a MemberExpression where the property name is "migrateVersion" and the object is bound to a parameter of the surrounding function, an return the assigned value.
/<node type>
- find a child node of the given type//<node type>
- find a descendant of the given type/:<name>
- find an attribute of the current node with the given name//:<name>
- find an attribute of the current node with the given name regardless of whether it's on the current node or on a descendant/$:<name>
- find the binding of an Identifier/$$:<name>
- return the binding or the attribute if binding cannot be resolved (helpful if a variable is sometimes directly assigned and sometimes not)[]
- apply a filter to the node&&
,||
- logical conditions of a filter==
- comparison in filter../
- go to parent in filter (use with care, as this causes extra traversal)/*
- wildcard type child//*
- wildcard type descendant'<some value>'
,"<some value>"
- a string literal/fn:first(selector)
- returns the first result from all matches/fn:concat(...selectors...)
- concatenates results. If an argument has more than one value, those will be concatenated first./fn:join(selector, ",")
- concatenates the results of a selector with the given separator
query(code: string, query: string) : Result[]
- Runs the given query on the given code in the form of an already parsed AST or a string (which is parsed assourceType: "unambiguous"
), and returns the result.multiQuery<T extends Record<string, string>>(code: string, namedQueries: T) : Record<keyof T, Result[]>
- Runs the given set of named queries on the given code in the form of an already parsed AST or a string (which is parsed assourceType: "unambiguous"
), and returns a map of named results (one result array per named query).
where Result
is Babel.Node | string | number | boolean;
import { query } from "astronomical";
import * as fs from "fs";
const contents = fs.readFileSync("some-file.js");
const result = query(
contents,
`//FunctionDeclaration/:id/:name`
);
console.log("Function names", result);