You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It guides one to write comprehensive AST code (in case people forget to handle some cases)
8
+
Writing AST manipulation code is hard. Even if we have a lot of helpful interactive tool, it's still hard to handle all edge cases.
9
9
10
-
# What are good TypeScript types?
10
+
AST types are good guiderail to write comprehensive AST manipulation code. It guides one to write comprehensive AST manipulation code (in case people forget to handle some cases). Using exhaustive checking, one can ensure that all cases are handled.
11
+
12
+
While ast-grep napi is a convenient tool to programmatically process AST , but it lacks the type information to guide user to write robust logic to handle all potential code. Thank to Mohebifar from codemod, ast-grep napi now can provide type information via nodejs API.
13
+
14
+
The solution to solve the problem is generating types from the static information provided by AST parser library, and using several TypeScript tricks to provide a good typing API.
15
+
16
+
## What are good TypeScript types?
17
+
18
+
before we talk about how we achieve the goal, let's talk about what are good TypeScript types.
19
+
20
+
Designing a good library in the modern JavaScript world is not only about providing good API naming, documentation and examples, but also about providing good TypeScript types. A good API type should be:
11
21
12
22
* Correct: reject invalid code and accept valid code
13
23
* Concise: easy to read, especially in hover and completion
14
-
* Robust: easy to refactor
15
-
* Performant: fast to compile
24
+
* Robust: easy to spot the compile error when you make a mistake. it should not report a huge error that doesn't fit a screen
25
+
* Performant: fast to compile. complex types can slow down the compiler
26
+
27
+
28
+
It is really hard to provide a type system that is both Sound and Complete. This is similar to provide a good typing API.
TS libs nowaday probably pay too much attention to correctness IMHO.
33
+
Having a type to check your path parameter in your routing is cool, but what's the cost?
34
+
35
+
Designing a good TypeScript type is essentially a trade-off of these four aspects.
16
36
17
37
# TreeSitter's types
18
38
19
-
Tree-Sitter's official API is untyped. However it provides static node types in json
39
+
Let's come back to ast-grep's problem. ast-grep is based on Tree-Sitter.
20
40
21
-
1. json hosted by parser library repo
22
-
needs type generation(layman's type provider)
23
-
2. contains a lot unnamed kinds
41
+
Tree-Sitter's official API is untyped. It provies a uniform API to access the syntax tree across different languages. A node in Tree-Sitter has several methods like `kind`, `field`, `parent`, `children`, `range`, `text`, etc.
42
+
43
+
However, a specific language's syntax tree has a specific structure. For example, a function declaration in JavaScript has a `function` keyword, a name, a list of parameters, and a body. Other AST parser libraries encode this structure in their AST object types. For example, a `function_declaration` has fields like `parameters` and `body`.
44
+
45
+
Fortunately tree-sitter provides static node types in json.
46
+
There are several challenges to generate TypeScript types from tree-sitter's static node types.
47
+
48
+
1. json is hosted by parser library repo
49
+
We needs type generation (it is like layman's type provider)
50
+
2. json contains a lot unnamed kinds
24
51
You are writing a compiler plugin, not elementary school math homework
25
-
3. has alias type
52
+
3.json has alias type
26
53
27
54
28
-
#Big Idea
55
+
## Design Type
29
56
30
57
1. lenient type check if no information
31
58
2. more strict checking if refined
32
59
33
60
34
-
#APIs
61
+
## Define Type
35
62
36
-
## Prune unnamed kinds
63
+
###Prune unnamed kinds
37
64
For example `+`/`-`/`*`/`/` is too noisy for a general AST library
38
65
39
-
## `ResolveType<M, T>`
66
+
###`ResolveType<M, T>`
40
67
41
68
Use type script to resolve type alias
42
69
43
-
## `Kinds<M>`
70
+
###`Kinds<M>`
44
71
45
72
1. string literal completion with `LowPriorityString`
46
73
2. lenient
47
74
48
-
Problem?
75
+
Problem? open-ended union is not well supported in TypeScript
## Distinguish general `string`ly kinds and specific kinds
80
+
81
+
### Distinguish general `string`ly kinds and specific kinds
54
82
55
83
Note `SgNode<'expression' | 'type'>` is different from `SgNode<'expression'> | SgNode<'type'>`
56
84
57
85
ast-grep uses a trick via the type `RefineNode<>` to let you switch between the two
58
86
59
87
60
-
## Refine Node, Manually
88
+
## Refine Type
89
+
90
+
### Refine Node, Manually
61
91
62
92
1.via `sgNode.find<"KIND">`
63
93
2.via `sgNode.is<"KIND">`, One time type narrowing
@@ -71,12 +101,12 @@ interface NodeMethod<K> {
71
101
}
72
102
```
73
103
74
-
## Refine Node, Automatically
104
+
###Refine Node, Automatically
75
105
76
106
`sgNode.field("kind")` will
77
107
78
108
79
-
## Exhaustive Checking via `sgNode.kindToRefine`
109
+
###Exhaustive Checking via `sgNode.kindToRefine`
80
110
81
111
Only available for node with specific kinds
82
112
@@ -95,7 +125,9 @@ switch (func.kindToRefine) {
95
125
}
96
126
```
97
127
98
-
## Typed Rule!
128
+
## Confine Types
129
+
130
+
### Typed Rule!
99
131
100
132
```typescript
101
133
sgNode.find({
@@ -106,9 +138,15 @@ sgNode.find({
106
138
})
107
139
```
108
140
109
-
## Opt-in refinement for better compile time performance
110
141
111
-
# Ending
142
+
### Opt-in refinement for better compile time performance
143
+
144
+
## Ending
145
+
146
+
I'm very thrilled to see the future of AST manipulation in TypeScript.
147
+
This feature enables users to switch freely between untyped AST and typed AST.
148
+
149
+
it is like biome / rowan
112
150
113
151
https://x.com/hd_nvim/status/1868453729940500924
114
152
There are very few devs that understands Rust deeply enough and compiler deeply enough that also care about TypeScript in web dev enough to build something for web devs in Rust
0 commit comments