Skip to content

Commit 9de98bd

Browse files
[feat] implement more napi interface
1 parent cc6d363 commit 9de98bd

File tree

3 files changed

+154
-20
lines changed

3 files changed

+154
-20
lines changed

.editorconfig

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ indent_size = 2
99
end_of_line = lf
1010
charset = utf-8
1111
trim_trailing_whitespace = true
12-
insert_final_newline = true
12+
insert_final_newline = false
1313

1414
[*.md]
1515
trim_trailing_whitespace = false

crates/napi/__test__/index.spec.ts

+6
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,9 @@ test('findAll from native code', t => {
2929
end: { row: 0, col: 37 },
3030
})
3131
})
32+
33+
test('findByString not match', t => {
34+
const sg = AstGrep.js('console.log(123)')
35+
const match = sg.root().findByString('notExist')
36+
t.is(match, null)
37+
})

crates/napi/src/lib.rs

+147-19
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ pub struct Range {
4848
}
4949

5050
#[napi]
51-
pub struct SGNode {
52-
inner: SharedReference<SGRoot, Node<'static, FrontEndLanguage>>,
51+
pub struct SgNode {
52+
inner: SharedReference<SgRoot, Node<'static, FrontEndLanguage>>,
5353
}
5454

5555
#[napi]
56-
impl SGNode {
56+
impl SgNode {
5757
#[napi]
5858
pub fn range(&self) -> Range {
5959
let start_pos = self.inner.start_pos();
@@ -64,49 +64,177 @@ impl SGNode {
6464
}
6565
}
6666

67+
#[napi]
68+
pub fn is_leaf(&self) -> bool {
69+
self.inner.is_leaf()
70+
}
71+
#[napi]
72+
pub fn kind(&self) -> String {
73+
self.inner.kind().to_string()
74+
}
75+
#[napi]
76+
pub fn text(&self) -> String {
77+
self.inner.text().to_string()
78+
}
79+
}
80+
81+
#[napi]
82+
impl SgNode {
83+
#[napi]
84+
pub fn matches(&self, m: String) -> bool {
85+
self.inner.matches(&*m)
86+
}
87+
88+
#[napi]
89+
pub fn inside(&self, m: String) -> bool {
90+
self.inner.inside(&*m)
91+
}
92+
93+
#[napi]
94+
pub fn has(&self, m: String) -> bool {
95+
self.inner.has(&*m)
96+
}
97+
98+
#[napi]
99+
pub fn precedes(&self, m: String) -> bool {
100+
self.inner.precedes(&*m)
101+
}
102+
103+
#[napi]
104+
pub fn follows(&self, m: String) -> bool {
105+
self.inner.follows(&*m)
106+
}
107+
}
108+
109+
/// tree traversal API
110+
#[napi]
111+
impl SgNode {
112+
#[napi]
113+
pub fn children(&self, reference: Reference<SgNode>, env: Env) -> Result<Vec<SgNode>> {
114+
let children = reference.inner.children();
115+
Self::from_iter_to_vec(&reference, env, children)
116+
}
117+
67118
#[napi]
68119
pub fn find_by_string(
69120
&self,
70-
reference: Reference<SGNode>,
121+
reference: Reference<SgNode>,
71122
env: Env,
72123
pattern: String,
73-
) -> Result<Option<SGNode>> {
124+
) -> Result<Option<SgNode>> {
74125
let pattern = Pattern::new(&pattern, reference.inner.lang().clone());
75-
let node = if let Some(node) = self.inner.find(pattern) {
76-
node.get_node().clone()
126+
let node = reference.inner.find(pattern).map(|n| n.get_node().clone());
127+
Self::transpose_option(reference, env, node)
128+
}
129+
130+
fn transpose_option(
131+
reference: Reference<SgNode>,
132+
env: Env,
133+
node: Option<Node<'static, FrontEndLanguage>>,
134+
) -> Result<Option<SgNode>> {
135+
if let Some(node) = node {
136+
let root_ref = reference.inner.clone_owner(env)?;
137+
let inner = root_ref.share_with(env, move |_| Ok(node))?;
138+
Ok(Some(SgNode { inner }))
77139
} else {
78-
return Ok(None);
79-
};
80-
let root_ref = reference.inner.clone_owner(env)?;
81-
let inner = root_ref.share_with(env, move |_| Ok(node))?;
82-
Ok(Some(SGNode { inner }))
140+
Ok(None)
141+
}
83142
}
84143

85144
#[napi]
86145
pub fn find_all(
87146
&self,
88-
reference: Reference<SGNode>,
147+
reference: Reference<SgNode>,
89148
env: Env,
90149
pattern: String,
91-
) -> Result<Vec<SGNode>> {
150+
) -> Result<Vec<SgNode>> {
92151
let mut ret = vec![];
93152
for node_match in self.inner.find_all(&*pattern) {
94153
let node = node_match.get_node().clone();
95154
let root_ref = reference.inner.clone_owner(env)?;
96-
let sg_node = SGNode {
155+
let sg_node = SgNode {
156+
inner: root_ref.share_with(env, move |_| Ok(node))?,
157+
};
158+
ret.push(sg_node);
159+
}
160+
Ok(ret)
161+
}
162+
163+
fn from_iter_to_vec(
164+
reference: &Reference<SgNode>,
165+
env: Env,
166+
iter: impl Iterator<Item = Node<'static, FrontEndLanguage>>,
167+
) -> Result<Vec<SgNode>> {
168+
let mut ret = vec![];
169+
for node in iter {
170+
let root_ref = reference.inner.clone_owner(env)?;
171+
let sg_node = SgNode {
97172
inner: root_ref.share_with(env, move |_| Ok(node))?,
98173
};
99174
ret.push(sg_node);
100175
}
101176
Ok(ret)
102177
}
178+
179+
#[napi]
180+
pub fn field(
181+
&self,
182+
reference: Reference<SgNode>,
183+
env: Env,
184+
name: String,
185+
) -> Result<Option<SgNode>> {
186+
let node = reference.inner.field(&name);
187+
Self::transpose_option(reference, env, node)
188+
}
189+
190+
#[napi]
191+
pub fn parent(&self, reference: Reference<SgNode>, env: Env) -> Result<Option<SgNode>> {
192+
let node = reference.inner.parent();
193+
Self::transpose_option(reference, env, node)
194+
}
195+
196+
#[napi]
197+
pub fn child(&self, reference: Reference<SgNode>, env: Env, nth: u32) -> Result<Option<SgNode>> {
198+
let inner = reference.inner.child(nth as usize);
199+
Self::transpose_option(reference, env, inner)
200+
}
201+
202+
#[napi]
203+
pub fn ancestors(&self, reference: Reference<SgNode>, env: Env) -> Result<Vec<SgNode>> {
204+
let ancestors = reference.inner.ancestors();
205+
Self::from_iter_to_vec(&reference, env, ancestors)
206+
}
207+
208+
#[napi]
209+
pub fn next(&self, reference: Reference<SgNode>, env: Env) -> Result<Option<SgNode>> {
210+
let inner = reference.inner.next();
211+
Self::transpose_option(reference, env, inner)
212+
}
213+
214+
#[napi]
215+
pub fn next_all(&self, reference: Reference<SgNode>, env: Env) -> Result<Vec<SgNode>> {
216+
let inner = reference.inner.next_all();
217+
Self::from_iter_to_vec(&reference, env, inner)
218+
}
219+
220+
#[napi]
221+
pub fn prev(&self, reference: Reference<SgNode>, env: Env) -> Result<Option<SgNode>> {
222+
let inner = reference.inner.prev();
223+
Self::transpose_option(reference, env, inner)
224+
}
225+
226+
#[napi]
227+
pub fn prev_all(&self, reference: Reference<SgNode>, env: Env) -> Result<Vec<SgNode>> {
228+
let inner = reference.inner.prev_all();
229+
Self::from_iter_to_vec(&reference, env, inner)
230+
}
103231
}
104232

105233
#[napi(js_name = "AstGrep")]
106-
pub struct SGRoot(AstGrep<FrontEndLanguage>);
234+
pub struct SgRoot(AstGrep<FrontEndLanguage>);
107235

108236
#[napi]
109-
impl SGRoot {
237+
impl SgRoot {
110238
fn from_lang(src: String, fe_lang: FrontEndLanguage) -> Self {
111239
Self(AstGrep::new(src, fe_lang))
112240
}
@@ -132,8 +260,8 @@ impl SGRoot {
132260
}
133261

134262
#[napi]
135-
pub fn root(&self, root_ref: Reference<SGRoot>, env: Env) -> Result<SGNode> {
263+
pub fn root(&self, root_ref: Reference<SgRoot>, env: Env) -> Result<SgNode> {
136264
let inner = root_ref.share_with(env, |root| Ok(root.0.root()))?;
137-
Ok(SGNode { inner })
265+
Ok(SgNode { inner })
138266
}
139267
}

0 commit comments

Comments
 (0)