https://github.com/retirejs/astronomical
https://github.com/retirejs/astronomical
Last synced: 28 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/retirejs/astronomical
- Owner: RetireJS
- License: apache-2.0
- Created: 2024-02-01T20:57:26.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2024-12-11T14:02:53.000Z (over 1 year ago)
- Last Synced: 2025-04-02T14:50:41.715Z (about 1 year ago)
- Language: TypeScript
- Size: 214 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# ASTronomical
`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](https://github.com/rse/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_
## Example
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.
## Grammar
* `/` - find a child node of the given type
* `//` - find a descendant of the given type
* `/:` - find an attribute of the current node with the given 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
* `/$:` - find the binding of an Identifier
* `/$$:` - 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
* `''`,`""` - 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
## API
* `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 as `sourceType: "unambiguous"`), and returns the result.
* `multiQuery>(code: string, namedQueries: T) : Record` - 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 as `sourceType: "unambiguous"`), and returns a map of named results (one result array per named query).
where `Result` is `Babel.Node | string | number | boolean;`
## Example code
```
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);
```