Skip to content

Commit 55e65f3

Browse files
mohebifarHerringtonDarkholme
authored andcommitted
feat(napi): Typed SgNode and SgRoot
1 parent 6a557c2 commit 55e65f3

8 files changed

Lines changed: 620 additions & 40 deletions

File tree

crates/napi/index.d.ts

Lines changed: 82 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,52 @@
1+
import type { FieldNames, FieldSgNode, NodeTypesMap } from "./types/node-types";
2+
import JavaScriptNodeTypesMap from "./types/JavaScript-node-types";
3+
import TypeScriptNodeTypesMap from "./types/TypeScript-node-types";
4+
import TsxNodeTypesMap from "./types/Tsx-node-types";
5+
import JavaNodeTypesMap from "./types/Java-node-types";
6+
import PythonNodeTypesMap from "./types/Python-node-types";
7+
import RustNodeTypesMap from "./types/Rust-node-types";
8+
import CNodeTypesMap from "./types/C-node-types";
9+
import CppNodeTypesMap from "./types/Cpp-node-types";
10+
import GoNodeTypesMap from "./types/Go-node-types";
11+
import HtmlNodeTypesMap from "./types/Html-node-types";
12+
import CssNodeTypesMap from "./types/Css-node-types";
13+
import JsonNodeTypesMap from "./types/Json-node-types";
14+
import CSharpNodeTypesMap from "./types/CSharp-node-types";
15+
import RubyNodeTypesMap from "./types/Ruby-node-types";
16+
import PhpNodeTypesMap from "./types/Php-node-types";
17+
import ElixirNodeTypesMap from "./types/Elixir-node-types";
18+
import KotlinNodeTypesMap from "./types/Kotlin-node-types";
19+
import SwiftNodeTypesMap from "./types/Swift-node-types";
20+
import HaskellNodeTypesMap from "./types/Haskell-node-types";
21+
import ScalaNodeTypesMap from "./types/Scala-node-types";
22+
import LuaNodeTypesMap from "./types/Lua-node-types";
23+
import BashNodeTypesMap from "./types/Bash-node-types";
24+
import YamlNodeTypesMap from "./types/Yaml-node-types";
25+
export {
26+
JavaScriptNodeTypesMap,
27+
TypeScriptNodeTypesMap,
28+
TsxNodeTypesMap,
29+
JavaNodeTypesMap,
30+
PythonNodeTypesMap,
31+
RustNodeTypesMap,
32+
CNodeTypesMap,
33+
CppNodeTypesMap,
34+
GoNodeTypesMap,
35+
HtmlNodeTypesMap,
36+
CssNodeTypesMap,
37+
JsonNodeTypesMap,
38+
CSharpNodeTypesMap,
39+
RubyNodeTypesMap,
40+
PhpNodeTypesMap,
41+
ElixirNodeTypesMap,
42+
KotlinNodeTypesMap,
43+
SwiftNodeTypesMap,
44+
HaskellNodeTypesMap,
45+
ScalaNodeTypesMap,
46+
LuaNodeTypesMap,
47+
BashNodeTypesMap,
48+
YamlNodeTypesMap
49+
};
150
/* tslint:disable */
251
/* eslint-disable */
352

@@ -108,13 +157,18 @@ export declare function pattern(lang: Lang, pattern: string): NapiConfig
108157
* `callback` will receive matching nodes found in a file.
109158
*/
110159
export declare function findInFiles(lang: Lang, config: FindConfig, callback: (err: null | Error, result: SgNode[]) => void): Promise<number>
111-
export declare class SgNode {
160+
export declare class SgNode<
161+
M extends NodeTypesMap = NodeTypesMap,
162+
T extends keyof M = keyof M
163+
> {
112164
range(): Range
113165
isLeaf(): boolean
114166
isNamed(): boolean
115167
isNamedLeaf(): boolean
116168
/** Returns the string name of the node kind */
117-
kind(): string
169+
kind(): T
170+
/** Check if the node is the same kind as the given `kind` string */
171+
is<K extends T>(kind: K): this is SgNode<M, K> & this
118172
text(): string
119173
matches(m: string): boolean
120174
inside(m: string): boolean
@@ -126,17 +180,17 @@ export declare class SgNode {
126180
getTransformed(m: string): string | null
127181
/** Returns the node's SgRoot */
128182
getRoot(): SgRoot
129-
children(): Array<SgNode>
183+
children(): Array<SgNode<M>>
130184
/** Returns the node's id */
131185
id(): number
132-
find(matcher: string | number | NapiConfig): SgNode | null
133-
findAll(matcher: string | number | NapiConfig): Array<SgNode>
186+
find(matcher: string | number | NapiConfig): SgNode<M> | null
187+
findAll(matcher: string | number | NapiConfig): Array<SgNode<M>>
134188
/** Finds the first child node in the `field` */
135-
field(name: string): SgNode | null
189+
field<F extends FieldNames<M[T]>>(name: F): FieldSgNode<M, T, F>
136190
/** Finds all the children nodes in the `field` */
137-
fieldChildren(name: string): Array<SgNode>
191+
fieldChildren<F extends FieldNames<M[T]>>(name: F): Exclude<FieldSgNode<M, T, F>, null>[]
138192
parent(): SgNode | null
139-
child(nth: number): SgNode | null
193+
child(nth: number): SgNode<M> | null
140194
ancestors(): Array<SgNode>
141195
next(): SgNode | null
142196
nextAll(): Array<SgNode>
@@ -146,9 +200,9 @@ export declare class SgNode {
146200
commitEdits(edits: Array<Edit>): string
147201
}
148202
/** Represents the parsed tree of code. */
149-
export declare class SgRoot {
203+
export declare class SgRoot<M extends NodeTypesMap = NodeTypesMap> {
150204
/** Returns the root SgNode of the ast-grep instance. */
151-
root(): SgNode
205+
root(): SgNode<M>
152206
/**
153207
* Returns the path of the file if it is discovered by ast-grep's `findInFiles`.
154208
* Returns `"anonymous"` if the instance is created by `lang.parse(source)`.
@@ -157,15 +211,15 @@ export declare class SgRoot {
157211
}
158212
export declare namespace html {
159213
/** Parse a string to an ast-grep instance */
160-
export function parse(src: string): SgRoot
214+
export function parse(src: string): SgRoot<HtmlNodeTypesMap>
161215
/**
162216
* Parse a string to an ast-grep instance asynchronously in threads.
163217
* It utilize multiple CPU cores when **concurrent processing sources**.
164218
* However, spawning excessive many threads may backfire.
165219
* Please refer to libuv doc, nodejs' underlying runtime
166220
* for its default behavior and performance tuning tricks.
167221
*/
168-
export function parseAsync(src: string): Promise<SgRoot>
222+
export function parseAsync(src: string): Promise<SgRoot<HtmlNodeTypesMap>>
169223
/** Get the `kind` number from its string name. */
170224
export function kind(kindName: string): number
171225
/** Compile a string to ast-grep Pattern. */
@@ -175,19 +229,19 @@ export declare namespace html {
175229
* `config` specifies the file path and matcher.
176230
* `callback` will receive matching nodes found in a file.
177231
*/
178-
export function findInFiles(config: FindConfig, callback: (err: null | Error, result: SgNode[]) => void): Promise<number>
232+
export function findInFiles(config: FindConfig, callback: (err: null | Error, result: SgNode<HtmlNodeTypesMap>[]) => void): Promise<number>
179233
}
180234
export declare namespace js {
181235
/** Parse a string to an ast-grep instance */
182-
export function parse(src: string): SgRoot
236+
export function parse(src: string): SgRoot<JavaScriptNodeTypesMap>
183237
/**
184238
* Parse a string to an ast-grep instance asynchronously in threads.
185239
* It utilize multiple CPU cores when **concurrent processing sources**.
186240
* However, spawning excessive many threads may backfire.
187241
* Please refer to libuv doc, nodejs' underlying runtime
188242
* for its default behavior and performance tuning tricks.
189243
*/
190-
export function parseAsync(src: string): Promise<SgRoot>
244+
export function parseAsync(src: string): Promise<SgRoot<JavaScriptNodeTypesMap>>
191245
/** Get the `kind` number from its string name. */
192246
export function kind(kindName: string): number
193247
/** Compile a string to ast-grep Pattern. */
@@ -197,19 +251,19 @@ export declare namespace js {
197251
* `config` specifies the file path and matcher.
198252
* `callback` will receive matching nodes found in a file.
199253
*/
200-
export function findInFiles(config: FindConfig, callback: (err: null | Error, result: SgNode[]) => void): Promise<number>
254+
export function findInFiles(config: FindConfig, callback: (err: null | Error, result: SgNode<JavaScriptNodeTypesMap>[]) => void): Promise<number>
201255
}
202256
export declare namespace jsx {
203257
/** Parse a string to an ast-grep instance */
204-
export function parse(src: string): SgRoot
258+
export function parse(src: string): SgRoot<JavaScriptNodeTypesMap>
205259
/**
206260
* Parse a string to an ast-grep instance asynchronously in threads.
207261
* It utilize multiple CPU cores when **concurrent processing sources**.
208262
* However, spawning excessive many threads may backfire.
209263
* Please refer to libuv doc, nodejs' underlying runtime
210264
* for its default behavior and performance tuning tricks.
211265
*/
212-
export function parseAsync(src: string): Promise<SgRoot>
266+
export function parseAsync(src: string): Promise<SgRoot<JavaScriptNodeTypesMap>>
213267
/** Get the `kind` number from its string name. */
214268
export function kind(kindName: string): number
215269
/** Compile a string to ast-grep Pattern. */
@@ -219,19 +273,19 @@ export declare namespace jsx {
219273
* `config` specifies the file path and matcher.
220274
* `callback` will receive matching nodes found in a file.
221275
*/
222-
export function findInFiles(config: FindConfig, callback: (err: null | Error, result: SgNode[]) => void): Promise<number>
276+
export function findInFiles(config: FindConfig, callback: (err: null | Error, result: SgNode<JavaScriptNodeTypesMap>[]) => void): Promise<number>
223277
}
224278
export declare namespace ts {
225279
/** Parse a string to an ast-grep instance */
226-
export function parse(src: string): SgRoot
280+
export function parse(src: string): SgRoot<TypeScriptNodeTypesMap>
227281
/**
228282
* Parse a string to an ast-grep instance asynchronously in threads.
229283
* It utilize multiple CPU cores when **concurrent processing sources**.
230284
* However, spawning excessive many threads may backfire.
231285
* Please refer to libuv doc, nodejs' underlying runtime
232286
* for its default behavior and performance tuning tricks.
233287
*/
234-
export function parseAsync(src: string): Promise<SgRoot>
288+
export function parseAsync(src: string): Promise<SgRoot<TypeScriptNodeTypesMap>>
235289
/** Get the `kind` number from its string name. */
236290
export function kind(kindName: string): number
237291
/** Compile a string to ast-grep Pattern. */
@@ -241,19 +295,19 @@ export declare namespace ts {
241295
* `config` specifies the file path and matcher.
242296
* `callback` will receive matching nodes found in a file.
243297
*/
244-
export function findInFiles(config: FindConfig, callback: (err: null | Error, result: SgNode[]) => void): Promise<number>
298+
export function findInFiles(config: FindConfig, callback: (err: null | Error, result: SgNode<TypeScriptNodeTypesMap>[]) => void): Promise<number>
245299
}
246300
export declare namespace tsx {
247301
/** Parse a string to an ast-grep instance */
248-
export function parse(src: string): SgRoot
302+
export function parse(src: string): SgRoot<TsxNodeTypesMap>
249303
/**
250304
* Parse a string to an ast-grep instance asynchronously in threads.
251305
* It utilize multiple CPU cores when **concurrent processing sources**.
252306
* However, spawning excessive many threads may backfire.
253307
* Please refer to libuv doc, nodejs' underlying runtime
254308
* for its default behavior and performance tuning tricks.
255309
*/
256-
export function parseAsync(src: string): Promise<SgRoot>
310+
export function parseAsync(src: string): Promise<SgRoot<TsxNodeTypesMap>>
257311
/** Get the `kind` number from its string name. */
258312
export function kind(kindName: string): number
259313
/** Compile a string to ast-grep Pattern. */
@@ -263,19 +317,19 @@ export declare namespace tsx {
263317
* `config` specifies the file path and matcher.
264318
* `callback` will receive matching nodes found in a file.
265319
*/
266-
export function findInFiles(config: FindConfig, callback: (err: null | Error, result: SgNode[]) => void): Promise<number>
320+
export function findInFiles(config: FindConfig, callback: (err: null | Error, result: SgNode<TsxNodeTypesMap>[]) => void): Promise<number>
267321
}
268322
export declare namespace css {
269323
/** Parse a string to an ast-grep instance */
270-
export function parse(src: string): SgRoot
324+
export function parse(src: string): SgRoot<CssNodeTypesMap>
271325
/**
272326
* Parse a string to an ast-grep instance asynchronously in threads.
273327
* It utilize multiple CPU cores when **concurrent processing sources**.
274328
* However, spawning excessive many threads may backfire.
275329
* Please refer to libuv doc, nodejs' underlying runtime
276330
* for its default behavior and performance tuning tricks.
277331
*/
278-
export function parseAsync(src: string): Promise<SgRoot>
332+
export function parseAsync(src: string): Promise<SgRoot<CssNodeTypesMap>>
279333
/** Get the `kind` number from its string name. */
280334
export function kind(kindName: string): number
281335
/** Compile a string to ast-grep Pattern. */
@@ -285,5 +339,5 @@ export declare namespace css {
285339
* `config` specifies the file path and matcher.
286340
* `callback` will receive matching nodes found in a file.
287341
*/
288-
export function findInFiles(config: FindConfig, callback: (err: null | Error, result: SgNode[]) => void): Promise<number>
342+
export function findInFiles(config: FindConfig, callback: (err: null | Error, result: SgNode<CssNodeTypesMap>[]) => void): Promise<number>
289343
}

crates/napi/package.json

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"files": [
1717
"manual.d.ts",
1818
"index.d.ts",
19-
"index.js"
19+
"index.js",
20+
"types/*.ts"
2021
],
2122
"napi": {
2223
"name": "ast-grep-napi",
@@ -41,17 +42,20 @@
4142
},
4243
"scripts": {
4344
"artifacts": "napi artifacts",
44-
"build": "napi build --no-const-enum --platform --release",
45+
"build": "napi build --no-const-enum --platform --release && yarn run typegen",
4546
"build:debug": "napi build --no-const-enum --platform",
4647
"prepublishOnly": "napi prepublish -t npm --skip-gh-release",
4748
"test": "ava",
48-
"version": "napi version"
49+
"version": "napi version",
50+
"typegen": "tsx scripts/generate-types.ts"
4951
},
5052
"devDependencies": {
5153
"@napi-rs/cli": "2.18.4",
54+
"@types/node": "^22.10.2",
5255
"ava": "6.2.0",
5356
"chalk": "5.3.0",
5457
"ts-node": "10.9.2",
58+
"tsx": "^4.19.2",
5559
"typescript": "5.7.2"
5660
},
5761
"ava": {
@@ -67,4 +71,4 @@
6771
"TS_NODE_PROJECT": "./tsconfig.json"
6872
}
6973
}
70-
}
74+
}

0 commit comments

Comments
 (0)