@@ -9,59 +9,89 @@ import (
9
9
"github.com/smacker/go-tree-sitter/javascript"
10
10
)
11
11
12
+ // ExpressionPlaceholder is the string used to replace any
13
+ // expressions when string concatenations are collapsed. E.g:
14
+ // "prefix" + someVar + "suffix"
15
+ // Would become:
16
+ // prefixEXPRsuffix
12
17
var ExpressionPlaceholder = "EXPR"
13
18
19
+ // Node is a wrapper around a tree-sitter node. It serves as
20
+ // an attachment point for convenience methods, and also to
21
+ // store the raw JavaScript source that is a required argument
22
+ // for many tree-sitter functions.
14
23
type Node struct {
15
24
node * sitter.Node
16
25
source []byte
17
26
}
18
27
28
+ // NewNode creates a new Node for the provided tree-sitter
29
+ // node and a byte-slice containing the JavaScript source.
30
+ // The source provided should be the complete source code
31
+ // and not just the source for the node in question.
19
32
func NewNode (n * sitter.Node , source []byte ) * Node {
20
33
return & Node {
21
34
node : n ,
22
35
source : source ,
23
36
}
24
37
}
25
38
39
+ // AsObject returns a Node as jsluice's internal object type,
40
+ // to allow the fetching of keys etc
26
41
func (n * Node ) AsObject () object {
27
42
return newObject (n , n .source )
28
43
}
29
44
45
+ // Content returns the source code for a particular node.
30
46
func (n * Node ) Content () string {
31
47
if n .node == nil {
32
48
return ""
33
49
}
34
50
return n .node .Content (n .source )
35
51
}
36
52
53
+ // Type returns the tree-sitter type string for a Node.
54
+ // E.g. string, object, call_expression. If the node is
55
+ // nil then an empty string is returned.
37
56
func (n * Node ) Type () string {
38
57
if n .node == nil {
39
58
return ""
40
59
}
41
60
return n .node .Type ()
42
61
}
43
62
63
+ // Fetches a child Node from a named field. For example,
64
+ // the 'pair' node has two fields: key, and value.
44
65
func (n * Node ) ChildByFieldName (name string ) * Node {
45
66
if ! n .IsValid () {
46
67
return nil
47
68
}
48
69
return NewNode (n .node .ChildByFieldName (name ), n .source )
49
70
}
50
71
72
+ // NamedChild returns the 'named' child Node at the provided
73
+ // index. Tree-sitter considers a child to be named if it has
74
+ // a name in the syntax tree. Things like brackets are not named,
75
+ // but things like variables and function calls are named.
76
+ // See https://tree-sitter.github.io/tree-sitter/using-parsers#named-vs-anonymous-nodes
77
+ // for more details.
51
78
func (n * Node ) NamedChild (index int ) * Node {
52
79
if ! n .IsValid () {
53
80
return nil
54
81
}
55
82
return NewNode (n .node .NamedChild (index ), n .source )
56
83
}
57
84
85
+ // NamedChildCount returns the number of named children a Node has.
58
86
func (n * Node ) NamedChildCount () int {
59
87
if ! n .IsValid () {
60
88
return 0
61
89
}
62
90
return int (n .node .NamedChildCount ())
63
91
}
64
92
93
+ // NamedChildren returns a slice of *Node containg all
94
+ // named children for a node.
65
95
func (n * Node ) NamedChildren () []* Node {
66
96
count := n .NamedChildCount ()
67
97
out := make ([]* Node , 0 , count )
@@ -83,6 +113,7 @@ func (n *Node) NamedChildren() []*Node {
83
113
//
84
114
// ./upload.php?profile=EXPR&show=EXPR
85
115
//
116
+ // The value of ExpressionPlaceholder is used as a placeholder, defaulting to 'EXPR'
86
117
func (n * Node ) CollapsedString () string {
87
118
if ! n .IsValid () {
88
119
return ""
@@ -101,18 +132,39 @@ func (n *Node) CollapsedString() string {
101
132
}
102
133
}
103
134
135
+ // IsValid returns true if the *Node and the underlying
136
+ // tree-sitter node are both not nil.
104
137
func (n * Node ) IsValid () bool {
105
138
return n != nil && n .node != nil
106
139
}
107
140
141
+ // RawString returns the raw JavaScript representation
142
+ // of a string (i.e. escape sequences are left undecoded)
143
+ // but with the surrounding quotes removed.
108
144
func (n * Node ) RawString () string {
109
145
return dequote (n .Content ())
110
146
}
111
147
148
+ // DecodedString returns a fully decoded version of a
149
+ // JavaScript string. It is just a convenience wrapper
150
+ // around the DecodeString function.
112
151
func (n * Node ) DecodedString () string {
113
152
return DecodeString (n .Content ())
114
153
}
115
154
155
+ // AsGoType returns a representation of a Node as a native
156
+ // Go type, defaulting to a string containing the JavaScript
157
+ // source for the Node. Return types are:
158
+ //
159
+ // string => string
160
+ // number => int, float64
161
+ // object => map[string]any
162
+ // array => []any
163
+ // false => false
164
+ // true => true
165
+ // null => nil
166
+ // other => string
167
+ //
116
168
func (n * Node ) AsGoType () any {
117
169
if n == nil {
118
170
return nil
@@ -138,6 +190,7 @@ func (n *Node) AsGoType() any {
138
190
}
139
191
}
140
192
193
+ // AsMap returns a representation of the Node as a map[string]any
141
194
func (n * Node ) AsMap () map [string ]any {
142
195
if n .Type () != "object" {
143
196
return map [string ]any {}
@@ -160,6 +213,7 @@ func (n *Node) AsMap() map[string]any {
160
213
return out
161
214
}
162
215
216
+ // AsArray returns a representation of the Node as a []any
163
217
func (n * Node ) AsArray () []any {
164
218
if n .Type () != "array" {
165
219
return []any {}
@@ -176,6 +230,9 @@ func (n *Node) AsArray() []any {
176
230
return out
177
231
}
178
232
233
+ // AsNumber returns a representation of the Node as an int or float64.
234
+ //
235
+ // Note: hex, octal etc number formats are currently unsupported
179
236
func (n * Node ) AsNumber () any {
180
237
if n .Type () != "number" {
181
238
return 0
@@ -201,13 +258,20 @@ func (n *Node) AsNumber() any {
201
258
return i
202
259
}
203
260
261
+ // Parent returns the Parent Node for a Node
204
262
func (n * Node ) Parent () * Node {
205
263
if ! n .IsValid () {
206
264
return nil
207
265
}
208
266
return NewNode (n .node .Parent (), n .source )
209
267
}
210
268
269
+ // Query executes a tree-sitter query on a specific Node.
270
+ // Nodes matching the query are passed one at a time to the
271
+ // provided callback function.
272
+ //
273
+ // See https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries
274
+ // for query syntax documentation.
211
275
func (n * Node ) Query (query string , fn func (* Node )) {
212
276
if ! n .IsValid () {
213
277
return
@@ -237,6 +301,9 @@ func (n *Node) Query(query string, fn func(*Node)) {
237
301
}
238
302
}
239
303
304
+ // IsStringy returns true if a Node is a string
305
+ // or is an expression starting with a string
306
+ // (e.g. a string concatenation expression).
240
307
func (n * Node ) IsStringy () bool {
241
308
if n .Type () == "string" {
242
309
return true
@@ -255,17 +322,22 @@ func (n *Node) IsStringy() bool {
255
322
}
256
323
}
257
324
325
+ // dequote removes surround quotes from the provided string
258
326
func dequote (in string ) string {
259
327
return strings .Trim (in , "'\" `" )
260
328
}
261
329
330
+ // content returns the source for the provided tree-sitter
331
+ // node, checking if the node is nil first.
262
332
func content (n * sitter.Node , source []byte ) string {
263
333
if n == nil {
264
334
return ""
265
335
}
266
336
return n .Content (source )
267
337
}
268
338
339
+ // PrintTree returns a string representation of the syntax tree
340
+ // for the provided JavaScript source
269
341
func PrintTree (source []byte ) string {
270
342
parser := sitter .NewParser ()
271
343
parser .SetLanguage (javascript .GetLanguage ())
@@ -276,6 +348,7 @@ func PrintTree(source []byte) string {
276
348
return getTree (root , source )
277
349
}
278
350
351
+ // getTree does the actual heavy lifting and recursion for PrintTree
279
352
// TODO: provide a way to print the tree as a JSON object?
280
353
func getTree (n * sitter.Node , source []byte ) string {
281
354
0 commit comments