An open API service indexing awesome lists of open source software.

https://github.com/retirejs/astronomical


https://github.com/retirejs/astronomical

Last synced: 28 days ago
JSON representation

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);
```