ast-grep
ast-grep is a fast and polyglot tool for code structural search, lint, rewriting at large scale.
GenAIScript provides a wrapper around ast-grep to search for patterns in the AST of a script,
and transform the AST! This is a very efficient way to create scripts that modify source code as one is able
to surgically target specific parts of the code.
Installation
Section titled “Installation”The ast-grep functionality is packaged in a plugin so you need to install it first:
npm i @genaiscript/plugin-ast-greppnpm add @genaiscript/plugin-ast-grepyarn add @genaiscript/plugin-ast-grep- load the
ast-grepmodule
import { astGrep } from "@genaiscript/plugin-ast-grep";const sg = await astGrep();Search for patterns
Section titled “Search for patterns”The search method allows you to search for patterns in the AST of a script.
The first argument is the language, the second argument is the file globs, and the third argument is the pattern to search for.
- find all TypeScript
console.logstatements. This example uses the ‘pattern’ syntax.
// matches is an array of AST (immutable) nodesconst { matches } = await sg.search( "ts", "src/*.ts", "console.log($META)",);- find all TypeScript functions without comments. This example uses the rule syntax.
const { matches } = await sg.search("ts", "src/fib.ts", { rule: { kind: "function_declaration", not: { precedes: { kind: "comment", stopBy: "neighbor", }, }, },});or if you copy the rules from the ast-grep playground using YAML,
const { matches } = await sg.search( "ts", "src/fib.ts", YAML`rule: kind: function_declaration not: precedes: kind: comment stopBy: neighbor`,);Filter by diff
Section titled “Filter by diff”A common use case is to restrict the pattern to code impacted by a code diff.
You can pass a diff string to the search method and it will filter out matches
that do not intersect with the to files of the diff.
const diff = await git.diff({ base: "main" })const { matches } = await sg.search("ts", "src/fib.ts", {...}, { diff })Changesets
Section titled “Changesets”A common use case is to search for a pattern and replace it with another pattern. The transformation phase can leverage
inline prompts to perform LLM transformations.
This can be done with the replace method.
const edits = sg.changeset();The replace method creates an edit that replaces the content of a node with new text.
The edit is stored internally but not applied until commit is called.
edits.replace(matches[0], "console.log('replaced')");Of course, things get more interesting when you use inline prompts to generate the replacement text.
for (const match of matches) { const updated = await prompt`... ${match.text()} ...`; edits.replace( match.node, `console.log ('${updated.text}')`, );}Next, you can commit the edits to create a set of in-memory files. The changes are not applied to the file system yet.
const newFiles = edits.commit();If you wish to apply the changes to the file system, you can use the writeFiles function.
await workspace.writeFiles(newFiles);Supported languages
Section titled “Supported languages”This version of ast-grep supports the following built-in languages:
- Html
- JavaScript
- TypeScript
- Tsx
- Css
- C
- C++
- Python
- C#
The following languages require installing an additional package (full list):
- SQL,
@ast-grep/lang-sql - Angular,
@ast-grep/lang-angular
npm install -D @ast-grep/lang-sqlFilename extension mapping
Section titled “Filename extension mapping”The following file extensions are mapped to the corresponding languages:
- HTML:
html,htm - JavaScript:
cjs,mjs,js - TypeScript:
cts,mts,ts - TSX:
tsx - CSS:
css - c:
c - cpp:
cpp,cxx,h,hpp,hxx - python:
py - C#:
cs - sql:
sql
Overriding the language selection
Section titled “Overriding the language selection”GenAIScript has default mappings from well-known file extensions to languages.
However, you can override this by passing the lang option to the search method.
const { matches } = await sg.search("ts", "src/fib.ts", {...}, { lang: "ts" })Learning ast-grep
Section titled “Learning ast-grep”There is a learning curve to grasp the query language of ast-grep.
- the official documentation is a good place to start.
- the online playground allows you to experiment with the tool without installing it.
- the JavaScript API which helps you understand how to work with nodes
- download llms.txt into to your Copilot context for best results.
Logging
Section titled “Logging”You can enable the genaiscript:astgrep namespace to see the queries and results in the logs.
DEBUG=genaiscript:astgrep ...