Skip to content

Commit d0bd7ba

Browse files
petrisorcoderabbitharjotgill
authored andcommitted
Move ast-grep documentation under the prompt-customization page
1 parent d705086 commit d0bd7ba

File tree

3 files changed

+265
-280
lines changed

3 files changed

+265
-280
lines changed

docs/guides/prompt-customization.md

+264
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,267 @@ Descriptive test names are used to clearly convey the intent of each test.
4848
- Test the review feedback on pull requests and tailor as necessary.
4949

5050
:::
51+
52+
## Abstract Syntax Tree (AST) instructions
53+
54+
:::note
55+
**Deep dive into AST patterns and AST-Grep rules**
56+
- AST patterns [wikipedia](https://en.wikipedia.org/wiki/Abstract_syntax_tree)
57+
- AST-grep [official documentation](https://ast-grep.github.io/guide/rule-config.html) for detailed guides.
58+
:::
59+
60+
This section explains how to add custom code review instructions using AST-Grep rules. AST-Grep is a tool used for searching code using abstract syntax trees (AST) patterns.
61+
62+
By default, you can add AST-Grep rules by following these steps:
63+
1. Create a folder that keeps all the ast-grep rules in your project directory.
64+
2. Add individual `.yaml` files for each AST-Grep rule within the newly created folder.
65+
3. Ensure that each `.yaml` file contains the necessary AST-Grep rule configurations.
66+
4. Ensure that all rules contains a `message` property, that will be used in the review process.
67+
5. Add the rules folder to the `.coderabbit.yml` file under `tools.ast-grep` configuration.
68+
69+
```yaml
70+
#...
71+
reviews:
72+
#...
73+
tools:
74+
ast-grep:
75+
rules_folder: "custom-name"
76+
#...
77+
```
78+
79+
### The rule object
80+
81+
Rule object is the core concept of ast-grep's rule system and every other features are built on top of it.
82+
83+
Below is the full list of fields in a rule object. Every rule field is optional and can be omitted but at least one field should be present in a rule. A node will match a rule if and only if it satisfies all fields in the rule object.
84+
```yaml
85+
rule:
86+
# atomic rule
87+
pattern: 'search.pattern'
88+
kind: 'tree_sitter_node_kind'
89+
regex: 'rust|regex'
90+
# relational rule
91+
inside: { pattern: 'sub.rule' }
92+
has: { kind: 'sub_rule' }
93+
follows: { regex: 'can|use|any' }
94+
precedes: { kind: 'multi_keys', pattern: 'in.sub' }
95+
# composite rule
96+
all: [ {pattern: 'match.all'}, {kind: 'match_all'} ]
97+
any: [ {pattern: 'match.any'}, {kind: 'match_any'} ]
98+
not: { pattern: 'not.this' }
99+
matches: 'utility-rule'
100+
```
101+
102+
### Three Rule Categories
103+
To summarize the rule object fields above, we have three categories of rules:
104+
105+
- **Atomic Rule:** the most basic rule that checks if AST nodes matches.
106+
- **Relational Rule:** rules that check if a node is surrounded by another node.
107+
- **Composite Rule:** rules that combine sub-rules together using logical operators.
108+
109+
These three categories of rules can be composed together to create more complex rules.
110+
111+
The rule object is inspired by the CSS selectors but with more composability and expressiveness.
112+
Thinking about how selectors in CSS works can help you understand the rule object!
113+
114+
> Read ast-grep [documentation](https://ast-grep.github.io/guide/rule-config.html) for detailed guides.
115+
116+
#### Atomic rule
117+
Atomic rule defines the most basic matching rule that determines whether one syntax node matches the rule or not. There are three kinds of atomic rule: `pattern`, `kind` and `regex`.
118+
119+
> Official documentation guide on [Atomic Rule](https://ast-grep.github.io/guide/rule-config/atomic-rule.html)
120+
121+
#### Relational rule
122+
Relational rule defines the relationship between two syntax nodes. There are four kinds of relational rule: `inside`, `has`, `follows` and `precedes`.
123+
124+
All four relational rules accept a sub-rule object as their value. The sub-rule will match the surrounding node while the relational rule itself will match the target node.
125+
126+
> Official documentation guide on [Relational Rule](https://ast-grep.github.io/guide/rule-config/relational-rule.html)
127+
128+
```yaml
129+
rule:
130+
pattern: await $PROMISE
131+
inside:
132+
kind: for_in_statement
133+
stopBy: end
134+
```
135+
136+
#### Composite rule
137+
Composite rule defines the logical relationship between multiple sub-rules. There are three kinds of composite rule: `all`, `any` and `not`.
138+
139+
**all**
140+
141+
The `all` rule matches if all sub-rules match.
142+
```yaml
143+
rule:
144+
all:
145+
- pattern: console.log('Hello World');
146+
- kind: expression_statement
147+
```
148+
149+
**any**
150+
151+
`any` rule matches if any sub-rule matches.
152+
```yaml
153+
rule:
154+
any:
155+
- pattern: var a = $A
156+
- pattern: const a = $A
157+
- pattern: let a = $A
158+
```
159+
160+
**not**
161+
162+
`not` applies negation to a sub-rule. It matches if the sub-rule does not match.
163+
164+
```yaml
165+
rule:
166+
pattern: console.log($GREETING)
167+
not:
168+
pattern: console.log('Hello World')
169+
```
170+
171+
> Official documentation guide on [Composite Rule](https://ast-grep.github.io/guide/rule-config/composite-rule.html)
172+
173+
174+
### Reusing rule as utility
175+
ast-grep chooses to use YAML for rule representation. While this decision makes writing rules easier, it does impose some limitations on the rule authoring. One of the limitations is that rule objects cannot be reused.
176+
177+
#### Local utility rule
178+
Local utility rules are defined in the utils field of the config file. utils is a string-keyed dictionary.
179+
180+
For example, the following config file defines a local utility rule `is-literal`:
181+
182+
```yaml
183+
utils:
184+
is-literal:
185+
any:
186+
- kind: string
187+
- kind: number
188+
- kind: boolean
189+
rule:
190+
matches: is-literal
191+
```
192+
193+
#### Global utility rule
194+
Global utility rules are defined in a separate file. But they are available across all rule configurations in the project.
195+
196+
To create global utility rules, you need to have the `rules` folder created on the root of your project and another
197+
`utils` directory inside the root of your project.
198+
199+
```yaml
200+
my-awesome-project # project root
201+
|- rules # rule directory
202+
| |- my-rule.yml
203+
|- utils # utils directory
204+
| |- is-literal.yml
205+
```
206+
207+
>Also, you need to add the `rules` and `utils` folders to the `.coderabbit.yml` file under `tools.ast-grep` configuration.
208+
209+
```yaml
210+
#...
211+
reviews:
212+
#...
213+
tools:
214+
ast-grep:
215+
rules_folder: "rules"
216+
utils_folder: "utils"
217+
#...
218+
```
219+
220+
```yaml
221+
# is-literal.yml
222+
id: is-literal
223+
language: TypeScript
224+
rule:
225+
any:
226+
- kind: 'false'
227+
- kind: undefined
228+
- kind: 'null'
229+
- kind: 'true'
230+
- kind: regex
231+
- kind: number
232+
- kind: string
233+
```
234+
235+
> Official documentation guide on [Utility Rule](https://ast-grep.github.io/guide/rule-config/utility-rule.html)
236+
237+
### Multiple Languages Support
238+
239+
CodeRabbit supports multiple programming languages for defining AST-Grep rules.
240+
241+
- JavaScript
242+
- Typescript
243+
- C#
244+
- Golang
245+
- Java
246+
- Kotlin
247+
- Rust
248+
- Python
249+
- C
250+
251+
Below are examples of AST-Grep rules in different languages:
252+
253+
#### JavaScript
254+
**Importing files without an extension is not allowed**
255+
```yaml
256+
id: find-import-file
257+
language: js
258+
message: "Importing files without an extension is not allowed"
259+
rule:
260+
regex: "/[^.]+[^/]$"
261+
kind: string_fragment
262+
any:
263+
- inside:
264+
stopBy: end
265+
kind: import_statement
266+
- inside:
267+
stopBy: end
268+
kind: call_expression
269+
has:
270+
field: function
271+
regex: "^import$"
272+
```
273+
274+
**No console.log allowed except console.error on the catch block**
275+
```yaml
276+
id: no-console-except-error
277+
language: typescript
278+
message: "No console.log allowed except console.error on the catch block"
279+
rule:
280+
any:
281+
- pattern: console.error($$$)
282+
not:
283+
inside:
284+
kind: catch_clause
285+
stopBy: end
286+
- pattern: console.$METHOD($$$)
287+
constraints:
288+
METHOD:
289+
regex: 'log|debug|warn'
290+
```
291+
292+
#### C
293+
In C, there is no built-in support for object-oriented programming, but some programmers use structs and function pointers to simulate classes and methods.
294+
295+
However, this style can have some drawbacks, such as:
296+
- extra memory allocation and reallocation for the struct and the function pointer.
297+
- indirection overhead when calling the function pointer.
298+
299+
A possible alternative is to use a plain function call with the struct pointer as the first argument.
300+
301+
```yaml
302+
id: method_receiver
303+
language: c
304+
rule:
305+
pattern: $R.$METHOD($$$ARGS)
306+
transform:
307+
MAYBE_COMMA:
308+
replace:
309+
source: $$$ARGS
310+
replace: '^.+'
311+
by: ', '
312+
fix:
313+
$METHOD(&$R$MAYBE_COMMA$$$ARGS)
314+
```

0 commit comments

Comments
 (0)