rbtr-lang-go 2026.7.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rbtr_lang_go/__init__.py +1 -0
- rbtr_lang_go/go.scm +53 -0
- rbtr_lang_go/plugin.py +38 -0
- rbtr_lang_go/py.typed +0 -0
- rbtr_lang_go/tests/__init__.py +0 -0
- rbtr_lang_go/tests/__snapshots__/test_samples/test_edges_match_snapshot.json +3 -0
- rbtr_lang_go/tests/__snapshots__/test_samples/test_extraction_matches_snapshot.json +308 -0
- rbtr_lang_go/tests/cases_docstrings.py +140 -0
- rbtr_lang_go/tests/cases_extraction.py +294 -0
- rbtr_lang_go/tests/samples/go/go.go +43 -0
- rbtr_lang_go/tests/samples/go/greeter/util.go +9 -0
- rbtr_lang_go/tests/test_docstrings.py +45 -0
- rbtr_lang_go/tests/test_extraction.py +57 -0
- rbtr_lang_go/tests/test_samples.py +74 -0
- rbtr_lang_go-2026.7.0.dev0.dist-info/METADATA +8 -0
- rbtr_lang_go-2026.7.0.dev0.dist-info/RECORD +18 -0
- rbtr_lang_go-2026.7.0.dev0.dist-info/WHEEL +4 -0
- rbtr_lang_go-2026.7.0.dev0.dist-info/entry_points.txt +3 -0
rbtr_lang_go/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Go language plugin package."""
|
rbtr_lang_go/go.scm
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
; Top-level comments (Go uses one `comment` type for `//` and `/* */`).
|
|
2
|
+
; The engine groups these and folds a block flush before a symbol into it.
|
|
3
|
+
(comment) @comment
|
|
4
|
+
|
|
5
|
+
(function_declaration
|
|
6
|
+
name: (identifier) @_fn_name) @function
|
|
7
|
+
|
|
8
|
+
(method_declaration
|
|
9
|
+
receiver: (parameter_list
|
|
10
|
+
(parameter_declaration
|
|
11
|
+
type: [
|
|
12
|
+
(type_identifier) @_scope
|
|
13
|
+
(pointer_type (type_identifier) @_scope)
|
|
14
|
+
]))
|
|
15
|
+
name: (field_identifier) @_method_name) @method
|
|
16
|
+
|
|
17
|
+
(type_declaration
|
|
18
|
+
(type_spec
|
|
19
|
+
name: (type_identifier) @_cls_name)) @class
|
|
20
|
+
|
|
21
|
+
(type_spec
|
|
22
|
+
(interface_type
|
|
23
|
+
(method_elem
|
|
24
|
+
name: (field_identifier) @_method_name) @method))
|
|
25
|
+
|
|
26
|
+
(type_declaration
|
|
27
|
+
(type_alias
|
|
28
|
+
name: (type_identifier) @_cls_name)) @class
|
|
29
|
+
|
|
30
|
+
(import_declaration
|
|
31
|
+
(import_spec
|
|
32
|
+
path: (interpreted_string_literal) @_import_module) @import)
|
|
33
|
+
|
|
34
|
+
(import_declaration
|
|
35
|
+
(import_spec_list
|
|
36
|
+
(import_spec
|
|
37
|
+
path: (interpreted_string_literal) @_import_module) @import))
|
|
38
|
+
|
|
39
|
+
(source_file
|
|
40
|
+
(var_declaration
|
|
41
|
+
(var_spec
|
|
42
|
+
name: (identifier) @_var_name) @variable))
|
|
43
|
+
|
|
44
|
+
(source_file
|
|
45
|
+
(const_declaration
|
|
46
|
+
(const_spec
|
|
47
|
+
name: (identifier) @_var_name) @variable))
|
|
48
|
+
|
|
49
|
+
(source_file
|
|
50
|
+
(var_declaration
|
|
51
|
+
(var_spec_list
|
|
52
|
+
(var_spec
|
|
53
|
+
name: (identifier) @_var_name) @variable)))
|
rbtr_lang_go/plugin.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Go language plugin.
|
|
2
|
+
|
|
3
|
+
Provides full support: functions, methods, type declarations,
|
|
4
|
+
and import extraction.
|
|
5
|
+
|
|
6
|
+
Extracted chunks::
|
|
7
|
+
|
|
8
|
+
func hello() {} → function "hello", scope ""
|
|
9
|
+
func (u User) Name() string {} → method "Name", scope ""
|
|
10
|
+
type User struct { ... } → class "User", scope ""
|
|
11
|
+
type Reader interface { ... } → class "Reader", scope ""
|
|
12
|
+
|
|
13
|
+
import "fmt"
|
|
14
|
+
→ import, metadata {module: "fmt"}
|
|
15
|
+
import ("fmt" "os/exec")
|
|
16
|
+
→ 2 import chunks: {module: "fmt"}, {module: "os/exec"}
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from rbtr.languages.registration import LanguageRegistration, QueryExtraction, load_query
|
|
22
|
+
|
|
23
|
+
# ── Query ────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# ── Plugin ───────────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
go = LanguageRegistration(
|
|
30
|
+
id="go",
|
|
31
|
+
extensions=frozenset({".go"}),
|
|
32
|
+
grammar_module="tree_sitter_go",
|
|
33
|
+
extraction=QueryExtraction(
|
|
34
|
+
query=load_query(__package__, "go"),
|
|
35
|
+
scope_types=frozenset({"type_spec"}),
|
|
36
|
+
),
|
|
37
|
+
extraction_serial=4,
|
|
38
|
+
)
|
rbtr_lang_go/py.typed
ADDED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "d1f4278c0ca4e638",
|
|
4
|
+
"blob_sha": "sha1",
|
|
5
|
+
"file_path": "go.go",
|
|
6
|
+
"kind": "comment",
|
|
7
|
+
"name": "<anonymous>",
|
|
8
|
+
"scope": "",
|
|
9
|
+
"language": "go",
|
|
10
|
+
"content": "// Package greet formats greetings for named recipients.\n//\n// The Go plugin extracts functions, methods (functions with a\n// receiver), type declarations (struct, interface, and alias, as\n// classes), const/var declarations (as variables), and imports.",
|
|
11
|
+
"line_start": 1,
|
|
12
|
+
"line_end": 5,
|
|
13
|
+
"metadata": {
|
|
14
|
+
"module": "",
|
|
15
|
+
"names": "",
|
|
16
|
+
"dots": "",
|
|
17
|
+
"language_hint": ""
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "617a74fefdf94501",
|
|
22
|
+
"blob_sha": "sha1",
|
|
23
|
+
"file_path": "go.go",
|
|
24
|
+
"kind": "import",
|
|
25
|
+
"name": "\"fmt\"",
|
|
26
|
+
"scope": "",
|
|
27
|
+
"language": "go",
|
|
28
|
+
"content": "\"fmt\"",
|
|
29
|
+
"line_start": 9,
|
|
30
|
+
"line_end": 9,
|
|
31
|
+
"metadata": {
|
|
32
|
+
"module": "fmt",
|
|
33
|
+
"names": "",
|
|
34
|
+
"dots": "",
|
|
35
|
+
"language_hint": ""
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "22c93a3cd18d6a4e",
|
|
40
|
+
"blob_sha": "sha1",
|
|
41
|
+
"file_path": "go.go",
|
|
42
|
+
"kind": "import",
|
|
43
|
+
"name": "\"greeter/util\"",
|
|
44
|
+
"scope": "",
|
|
45
|
+
"language": "go",
|
|
46
|
+
"content": "\"greeter/util\"",
|
|
47
|
+
"line_start": 11,
|
|
48
|
+
"line_end": 11,
|
|
49
|
+
"metadata": {
|
|
50
|
+
"module": "greeter/util",
|
|
51
|
+
"names": "",
|
|
52
|
+
"dots": "",
|
|
53
|
+
"language_hint": ""
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"id": "1bc7a9beaa5abc1f",
|
|
58
|
+
"blob_sha": "sha1",
|
|
59
|
+
"file_path": "go.go",
|
|
60
|
+
"kind": "comment",
|
|
61
|
+
"name": "<anonymous>",
|
|
62
|
+
"scope": "",
|
|
63
|
+
"language": "go",
|
|
64
|
+
"content": "// DefaultGreeting is the fallback prefix.",
|
|
65
|
+
"line_start": 14,
|
|
66
|
+
"line_end": 14,
|
|
67
|
+
"metadata": {
|
|
68
|
+
"module": "",
|
|
69
|
+
"names": "",
|
|
70
|
+
"dots": "",
|
|
71
|
+
"language_hint": ""
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"id": "6088984e54e72e54",
|
|
76
|
+
"blob_sha": "sha1",
|
|
77
|
+
"file_path": "go.go",
|
|
78
|
+
"kind": "variable",
|
|
79
|
+
"name": "DefaultGreeting",
|
|
80
|
+
"scope": "",
|
|
81
|
+
"language": "go",
|
|
82
|
+
"content": "DefaultGreeting = \"Hello\"",
|
|
83
|
+
"line_start": 15,
|
|
84
|
+
"line_end": 15,
|
|
85
|
+
"metadata": {
|
|
86
|
+
"module": "",
|
|
87
|
+
"names": "",
|
|
88
|
+
"dots": "",
|
|
89
|
+
"language_hint": ""
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"id": "8682e0e6778060e5",
|
|
94
|
+
"blob_sha": "sha1",
|
|
95
|
+
"file_path": "go.go",
|
|
96
|
+
"kind": "variable",
|
|
97
|
+
"name": "fallbackLocale",
|
|
98
|
+
"scope": "",
|
|
99
|
+
"language": "go",
|
|
100
|
+
"content": "fallbackLocale = \"en\"",
|
|
101
|
+
"line_start": 17,
|
|
102
|
+
"line_end": 17,
|
|
103
|
+
"metadata": {
|
|
104
|
+
"module": "",
|
|
105
|
+
"names": "",
|
|
106
|
+
"dots": "",
|
|
107
|
+
"language_hint": ""
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"id": "6cf50d84e9893957",
|
|
112
|
+
"blob_sha": "sha1",
|
|
113
|
+
"file_path": "go.go",
|
|
114
|
+
"kind": "comment",
|
|
115
|
+
"name": "<anonymous>",
|
|
116
|
+
"scope": "",
|
|
117
|
+
"language": "go",
|
|
118
|
+
"content": "// trailing comment: its own chunk, not folded",
|
|
119
|
+
"line_start": 17,
|
|
120
|
+
"line_end": 17,
|
|
121
|
+
"metadata": {
|
|
122
|
+
"module": "",
|
|
123
|
+
"names": "",
|
|
124
|
+
"dots": "",
|
|
125
|
+
"language_hint": ""
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"id": "6d998cbd76a60714",
|
|
130
|
+
"blob_sha": "sha1",
|
|
131
|
+
"file_path": "go.go",
|
|
132
|
+
"kind": "class",
|
|
133
|
+
"name": "Temperature",
|
|
134
|
+
"scope": "",
|
|
135
|
+
"language": "go",
|
|
136
|
+
"content": "// Temperature is an alias for the underlying float type.\ntype Temperature = float64",
|
|
137
|
+
"line_start": 19,
|
|
138
|
+
"line_end": 20,
|
|
139
|
+
"metadata": {
|
|
140
|
+
"module": "",
|
|
141
|
+
"names": "",
|
|
142
|
+
"dots": "",
|
|
143
|
+
"language_hint": ""
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"id": "3f6b670c5127f21d",
|
|
148
|
+
"blob_sha": "sha1",
|
|
149
|
+
"file_path": "go.go",
|
|
150
|
+
"kind": "class",
|
|
151
|
+
"name": "Greeter",
|
|
152
|
+
"scope": "",
|
|
153
|
+
"language": "go",
|
|
154
|
+
"content": "// Greeter holds a greeting prefix.\ntype Greeter struct {\n\tPrefix string\n}",
|
|
155
|
+
"line_start": 22,
|
|
156
|
+
"line_end": 25,
|
|
157
|
+
"metadata": {
|
|
158
|
+
"module": "",
|
|
159
|
+
"names": "",
|
|
160
|
+
"dots": "",
|
|
161
|
+
"language_hint": ""
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"id": "373545cefb441d30",
|
|
166
|
+
"blob_sha": "sha1",
|
|
167
|
+
"file_path": "go.go",
|
|
168
|
+
"kind": "class",
|
|
169
|
+
"name": "Formatter",
|
|
170
|
+
"scope": "",
|
|
171
|
+
"language": "go",
|
|
172
|
+
"content": "// Formatter renders a greeting for a name.\ntype Formatter interface {\n\tFormat(name string) string\n}",
|
|
173
|
+
"line_start": 27,
|
|
174
|
+
"line_end": 30,
|
|
175
|
+
"metadata": {
|
|
176
|
+
"module": "",
|
|
177
|
+
"names": "",
|
|
178
|
+
"dots": "",
|
|
179
|
+
"language_hint": ""
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"id": "7c2d2b8469f4c6b9",
|
|
184
|
+
"blob_sha": "sha1",
|
|
185
|
+
"file_path": "go.go",
|
|
186
|
+
"kind": "method",
|
|
187
|
+
"name": "Format",
|
|
188
|
+
"scope": "Formatter",
|
|
189
|
+
"language": "go",
|
|
190
|
+
"content": "Format(name string) string",
|
|
191
|
+
"line_start": 29,
|
|
192
|
+
"line_end": 29,
|
|
193
|
+
"metadata": {
|
|
194
|
+
"module": "",
|
|
195
|
+
"names": "",
|
|
196
|
+
"dots": "",
|
|
197
|
+
"language_hint": ""
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"id": "77923e25be8f065d",
|
|
202
|
+
"blob_sha": "sha1",
|
|
203
|
+
"file_path": "go.go",
|
|
204
|
+
"kind": "comment",
|
|
205
|
+
"name": "<anonymous>",
|
|
206
|
+
"scope": "",
|
|
207
|
+
"language": "go",
|
|
208
|
+
"content": "// Standalone note, separated by blank lines from any definition.\n// Second line of the same block.",
|
|
209
|
+
"line_start": 32,
|
|
210
|
+
"line_end": 33,
|
|
211
|
+
"metadata": {
|
|
212
|
+
"module": "",
|
|
213
|
+
"names": "",
|
|
214
|
+
"dots": "",
|
|
215
|
+
"language_hint": ""
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"id": "d49eb7eef5c71c0f",
|
|
220
|
+
"blob_sha": "sha1",
|
|
221
|
+
"file_path": "go.go",
|
|
222
|
+
"kind": "method",
|
|
223
|
+
"name": "Greet",
|
|
224
|
+
"scope": "Greeter",
|
|
225
|
+
"language": "go",
|
|
226
|
+
"content": "// Greet greets a single recipient.\nfunc (g Greeter) Greet(name string) string {\n\treturn fmt.Sprintf(\"%s, %s\", g.Prefix, util.Trim(name))\n}",
|
|
227
|
+
"line_start": 35,
|
|
228
|
+
"line_end": 38,
|
|
229
|
+
"metadata": {
|
|
230
|
+
"module": "",
|
|
231
|
+
"names": "",
|
|
232
|
+
"dots": "",
|
|
233
|
+
"language_hint": ""
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"id": "8355f60b7f62d374",
|
|
238
|
+
"blob_sha": "sha1",
|
|
239
|
+
"file_path": "go.go",
|
|
240
|
+
"kind": "function",
|
|
241
|
+
"name": "FormatGreeting",
|
|
242
|
+
"scope": "",
|
|
243
|
+
"language": "go",
|
|
244
|
+
"content": "// FormatGreeting formats a greeting via a Greeter.\nfunc FormatGreeting(g Greeter, name string) string {\n\treturn g.Greet(name)\n}",
|
|
245
|
+
"line_start": 40,
|
|
246
|
+
"line_end": 43,
|
|
247
|
+
"metadata": {
|
|
248
|
+
"module": "",
|
|
249
|
+
"names": "",
|
|
250
|
+
"dots": "",
|
|
251
|
+
"language_hint": ""
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"id": "19cd38988ba480c4",
|
|
256
|
+
"blob_sha": "sha1",
|
|
257
|
+
"file_path": "greeter/util.go",
|
|
258
|
+
"kind": "comment",
|
|
259
|
+
"name": "<anonymous>",
|
|
260
|
+
"scope": "",
|
|
261
|
+
"language": "go",
|
|
262
|
+
"content": "// Package util holds greeting helpers.",
|
|
263
|
+
"line_start": 1,
|
|
264
|
+
"line_end": 1,
|
|
265
|
+
"metadata": {
|
|
266
|
+
"module": "",
|
|
267
|
+
"names": "",
|
|
268
|
+
"dots": "",
|
|
269
|
+
"language_hint": ""
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
"id": "d2279d95b96822bc",
|
|
274
|
+
"blob_sha": "sha1",
|
|
275
|
+
"file_path": "greeter/util.go",
|
|
276
|
+
"kind": "import",
|
|
277
|
+
"name": "\"strings\"",
|
|
278
|
+
"scope": "",
|
|
279
|
+
"language": "go",
|
|
280
|
+
"content": "\"strings\"",
|
|
281
|
+
"line_start": 4,
|
|
282
|
+
"line_end": 4,
|
|
283
|
+
"metadata": {
|
|
284
|
+
"module": "strings",
|
|
285
|
+
"names": "",
|
|
286
|
+
"dots": "",
|
|
287
|
+
"language_hint": ""
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"id": "5d95fbaf4ba5f22b",
|
|
292
|
+
"blob_sha": "sha1",
|
|
293
|
+
"file_path": "greeter/util.go",
|
|
294
|
+
"kind": "function",
|
|
295
|
+
"name": "Trim",
|
|
296
|
+
"scope": "",
|
|
297
|
+
"language": "go",
|
|
298
|
+
"content": "// Trim removes surrounding whitespace from a name.\nfunc Trim(name string) string {\n\treturn strings.TrimSpace(name)\n}",
|
|
299
|
+
"line_start": 6,
|
|
300
|
+
"line_end": 9,
|
|
301
|
+
"metadata": {
|
|
302
|
+
"module": "",
|
|
303
|
+
"names": "",
|
|
304
|
+
"dots": "",
|
|
305
|
+
"language_hint": ""
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
]
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""Go docstring-extraction test cases.
|
|
2
|
+
|
|
3
|
+
Each `@case` returns `(lang, source, symbol_name, snippet)` consumed by `test_docstrings.py`.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from pytest_cases import case
|
|
9
|
+
|
|
10
|
+
type DocstringCase = tuple[str, str, str, str]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@case(tags=["documented", "canonical", "exterior_doc"])
|
|
14
|
+
def case_go_doc_comment_on_function() -> DocstringCase:
|
|
15
|
+
"""Canonical Go doc comment above `func`."""
|
|
16
|
+
src = """\
|
|
17
|
+
package main
|
|
18
|
+
|
|
19
|
+
// Greet says hello.
|
|
20
|
+
func Greet() {}
|
|
21
|
+
"""
|
|
22
|
+
return "go", src, "Greet", "Greet says hello"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@case(tags=["documented", "canonical", "exterior_doc"])
|
|
26
|
+
def case_go_doc_comment_on_type() -> DocstringCase:
|
|
27
|
+
"""Doc comment above a `type` declaration."""
|
|
28
|
+
src = """\
|
|
29
|
+
package main
|
|
30
|
+
|
|
31
|
+
// Widget is a UI element.
|
|
32
|
+
type Widget struct {
|
|
33
|
+
name string
|
|
34
|
+
}
|
|
35
|
+
"""
|
|
36
|
+
return "go", src, "Widget", "Widget is a UI element"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@case(tags=["documented", "canonical", "exterior_doc"])
|
|
40
|
+
def case_go_doc_comment_on_method() -> DocstringCase:
|
|
41
|
+
"""Doc comment above a method receiver."""
|
|
42
|
+
src = """\
|
|
43
|
+
package main
|
|
44
|
+
|
|
45
|
+
type T struct{}
|
|
46
|
+
|
|
47
|
+
// Do performs the action.
|
|
48
|
+
func (t *T) Do() {}
|
|
49
|
+
"""
|
|
50
|
+
return "go", src, "Do", "Do performs the action"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@case(tags=["documented", "canonical", "exterior_doc"])
|
|
54
|
+
def case_go_multi_line_doc_comment() -> DocstringCase:
|
|
55
|
+
"""Multi-line `//` doc-comment run."""
|
|
56
|
+
src = """\
|
|
57
|
+
package main
|
|
58
|
+
|
|
59
|
+
// Compute executes the pipeline.
|
|
60
|
+
//
|
|
61
|
+
// It returns an error if the inputs do not validate.
|
|
62
|
+
func Compute() error { return nil }
|
|
63
|
+
"""
|
|
64
|
+
return "go", src, "Compute", "It returns an error if the inputs"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@case(tags=["documented", "edge_case", "exterior_doc"])
|
|
68
|
+
def case_go_block_comment() -> DocstringCase:
|
|
69
|
+
"""`/* ... */` block comment as Go-doc. Supported by
|
|
70
|
+
`go doc` but rare.
|
|
71
|
+
"""
|
|
72
|
+
src = """\
|
|
73
|
+
package main
|
|
74
|
+
|
|
75
|
+
/* Block doc above foo.
|
|
76
|
+
Continues here. */
|
|
77
|
+
func Foo() {}
|
|
78
|
+
"""
|
|
79
|
+
return "go", src, "Foo", "Block doc above foo"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@case(tags=["documented", "unconventional", "exterior_doc"])
|
|
83
|
+
def case_go_non_godoc_style_comment() -> DocstringCase:
|
|
84
|
+
"""Comment that does *not* begin with the symbol's name.
|
|
85
|
+
`go doc` would warn, but rbtr leans toward flexibility and
|
|
86
|
+
attaches it.
|
|
87
|
+
"""
|
|
88
|
+
src = """\
|
|
89
|
+
package main
|
|
90
|
+
|
|
91
|
+
// Deliberately unconventional opening.
|
|
92
|
+
func Work() {}
|
|
93
|
+
"""
|
|
94
|
+
return "go", src, "Work", "Deliberately unconventional opening"
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@case(tags=["undocumented", "no_docs"])
|
|
98
|
+
def case_go_fn_without_doc() -> DocstringCase:
|
|
99
|
+
"""Undocumented function."""
|
|
100
|
+
src = """\
|
|
101
|
+
package main
|
|
102
|
+
|
|
103
|
+
func bare() {}
|
|
104
|
+
"""
|
|
105
|
+
return "go", src, "bare", "PHANTOM_DOC_TEXT_SHOULD_NEVER_APPEAR"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@case(tags=["undocumented", "boundary_not_attached"])
|
|
109
|
+
def case_go_doc_detached_by_blank_line() -> DocstringCase:
|
|
110
|
+
"""Blank line breaks attachment — the Go style guide
|
|
111
|
+
explicitly forbids a blank line between a doc comment and
|
|
112
|
+
its symbol.
|
|
113
|
+
"""
|
|
114
|
+
src = """\
|
|
115
|
+
package main
|
|
116
|
+
|
|
117
|
+
// Orphan.
|
|
118
|
+
|
|
119
|
+
func Later() {}
|
|
120
|
+
"""
|
|
121
|
+
return "go", src, "Later", "Orphan"
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@case(tags=["undocumented", "invalid"])
|
|
125
|
+
def case_go_doc_comment_above_previous_function_not_attached() -> DocstringCase:
|
|
126
|
+
"""Comment between two `func`s belongs to the second one,
|
|
127
|
+
not the first. The walk starts from the symbol and goes
|
|
128
|
+
*backwards*, so the comment correctly attaches to `Second`.
|
|
129
|
+
We probe the chunk for the *first* function to confirm it
|
|
130
|
+
does not steal the comment.
|
|
131
|
+
"""
|
|
132
|
+
src = """\
|
|
133
|
+
package main
|
|
134
|
+
|
|
135
|
+
func First() {}
|
|
136
|
+
|
|
137
|
+
// Doc for Second.
|
|
138
|
+
func Second() {}
|
|
139
|
+
"""
|
|
140
|
+
return "go", src, "First", "Doc for Second"
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"""Go extraction test cases."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from pytest_cases import case
|
|
7
|
+
|
|
8
|
+
type SymbolCase = tuple[str, str, list[tuple[str, str, str]]]
|
|
9
|
+
type ImportCase = tuple[str, str, dict[str, str]]
|
|
10
|
+
type MultiImportCase = tuple[str, str, int, list[dict[str, str]]]
|
|
11
|
+
type MixedCase = tuple[str, str, set[str], list[tuple[str, str]]]
|
|
12
|
+
|
|
13
|
+
_xfail_nested = pytest.mark.xfail(
|
|
14
|
+
reason="nested/chained destructuring unsupported — no query-only recursion",
|
|
15
|
+
strict=True,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@case(tags=["symbol"])
|
|
20
|
+
def case_go_function() -> SymbolCase:
|
|
21
|
+
"""func hello() {}."""
|
|
22
|
+
src = """\
|
|
23
|
+
package main
|
|
24
|
+
|
|
25
|
+
func hello() {}
|
|
26
|
+
"""
|
|
27
|
+
return "go", src, [("function", "hello", "")]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@case(tags=["symbol"])
|
|
31
|
+
def case_go_function_params() -> SymbolCase:
|
|
32
|
+
"""func add(a int, b int) int."""
|
|
33
|
+
src = """\
|
|
34
|
+
package main
|
|
35
|
+
|
|
36
|
+
func add(a int, b int) int { return a + b }
|
|
37
|
+
"""
|
|
38
|
+
return "go", src, [("function", "add", "")]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@case(tags=["symbol"])
|
|
42
|
+
def case_go_multiple_functions() -> SymbolCase:
|
|
43
|
+
"""Multiple functions."""
|
|
44
|
+
src = """\
|
|
45
|
+
package main
|
|
46
|
+
|
|
47
|
+
func foo() {}
|
|
48
|
+
func bar() {}
|
|
49
|
+
func baz() {}
|
|
50
|
+
"""
|
|
51
|
+
return (
|
|
52
|
+
"go",
|
|
53
|
+
src,
|
|
54
|
+
[
|
|
55
|
+
("function", "foo", ""),
|
|
56
|
+
("function", "bar", ""),
|
|
57
|
+
("function", "baz", ""),
|
|
58
|
+
],
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@case(tags=["symbol"])
|
|
63
|
+
def case_go_method() -> SymbolCase:
|
|
64
|
+
"""Value receiver method."""
|
|
65
|
+
src = """\
|
|
66
|
+
package main
|
|
67
|
+
|
|
68
|
+
type User struct{}
|
|
69
|
+
|
|
70
|
+
func (u User) Name() string { return u.name }
|
|
71
|
+
"""
|
|
72
|
+
return "go", src, [("method", "Name", "User")]
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@case(tags=["symbol"])
|
|
76
|
+
def case_go_pointer_method() -> SymbolCase:
|
|
77
|
+
"""Pointer receiver method."""
|
|
78
|
+
src = """\
|
|
79
|
+
package main
|
|
80
|
+
|
|
81
|
+
type Svc struct{}
|
|
82
|
+
|
|
83
|
+
func (s *Svc) Start() {}
|
|
84
|
+
"""
|
|
85
|
+
return "go", src, [("method", "Start", "Svc")]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@case(tags=["symbol"])
|
|
89
|
+
def case_go_struct() -> SymbolCase:
|
|
90
|
+
"""type User struct."""
|
|
91
|
+
src = """\
|
|
92
|
+
package main
|
|
93
|
+
|
|
94
|
+
type User struct {
|
|
95
|
+
Name string
|
|
96
|
+
}
|
|
97
|
+
"""
|
|
98
|
+
return "go", src, [("class", "User", "")]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@case(tags=["symbol"])
|
|
102
|
+
def case_go_interface() -> SymbolCase:
|
|
103
|
+
"""type Reader interface."""
|
|
104
|
+
src = """\
|
|
105
|
+
package main
|
|
106
|
+
|
|
107
|
+
type Reader interface {
|
|
108
|
+
Read(p []byte) (int, error)
|
|
109
|
+
}
|
|
110
|
+
"""
|
|
111
|
+
return "go", src, [("class", "Reader", "")]
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@case(tags=["symbol"])
|
|
115
|
+
def case_go_type_alias() -> SymbolCase:
|
|
116
|
+
"""type ID string."""
|
|
117
|
+
src = """\
|
|
118
|
+
package main
|
|
119
|
+
|
|
120
|
+
type ID string
|
|
121
|
+
"""
|
|
122
|
+
return "go", src, [("class", "ID", "")]
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@case(tags=["symbol"])
|
|
126
|
+
def case_go_multiple_types() -> SymbolCase:
|
|
127
|
+
"""Multiple type declarations."""
|
|
128
|
+
src = """\
|
|
129
|
+
package main
|
|
130
|
+
|
|
131
|
+
type Foo struct{}
|
|
132
|
+
type Bar struct{}
|
|
133
|
+
"""
|
|
134
|
+
return "go", src, [("class", "Foo", ""), ("class", "Bar", "")]
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@case(tags=["import"])
|
|
138
|
+
def case_go_import_single() -> ImportCase:
|
|
139
|
+
"""import "fmt"."""
|
|
140
|
+
src = """\
|
|
141
|
+
package main
|
|
142
|
+
import "fmt"
|
|
143
|
+
"""
|
|
144
|
+
return "go", src, {"module": "fmt"}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@case(tags=["import"])
|
|
148
|
+
def case_go_import_nested() -> ImportCase:
|
|
149
|
+
"""import "os/exec"."""
|
|
150
|
+
src = """\
|
|
151
|
+
package main
|
|
152
|
+
import "os/exec"
|
|
153
|
+
"""
|
|
154
|
+
return "go", src, {"module": "os/exec"}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@case(tags=["import"])
|
|
158
|
+
def case_go_import_url() -> ImportCase:
|
|
159
|
+
"""import "github.com/user/repo"."""
|
|
160
|
+
src = """\
|
|
161
|
+
package main
|
|
162
|
+
import "github.com/user/repo"
|
|
163
|
+
"""
|
|
164
|
+
return "go", src, {"module": "github.com/user/repo"}
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@case(tags=["import"])
|
|
168
|
+
def case_go_import_aliased() -> ImportCase:
|
|
169
|
+
"""import f "fmt" — alias ignored, module captured."""
|
|
170
|
+
src = """\
|
|
171
|
+
package main
|
|
172
|
+
import f "fmt"
|
|
173
|
+
"""
|
|
174
|
+
return "go", src, {"module": "fmt"}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@case(tags=["multi_import"])
|
|
178
|
+
def case_go_import_grouped() -> MultiImportCase:
|
|
179
|
+
"""import ("fmt" "os") — separate chunks per spec."""
|
|
180
|
+
src = """\
|
|
181
|
+
package main
|
|
182
|
+
import (
|
|
183
|
+
"fmt"
|
|
184
|
+
"os"
|
|
185
|
+
)
|
|
186
|
+
"""
|
|
187
|
+
return (
|
|
188
|
+
"go",
|
|
189
|
+
src,
|
|
190
|
+
2,
|
|
191
|
+
[{"module": "fmt"}, {"module": "os"}],
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
@case(tags=["multi_import"])
|
|
196
|
+
def case_go_import_grouped_paths() -> MultiImportCase:
|
|
197
|
+
"""Grouped import with nested paths — separate chunks."""
|
|
198
|
+
src = """\
|
|
199
|
+
package main
|
|
200
|
+
import (
|
|
201
|
+
"fmt"
|
|
202
|
+
"os/exec"
|
|
203
|
+
"net/http"
|
|
204
|
+
)
|
|
205
|
+
"""
|
|
206
|
+
return (
|
|
207
|
+
"go",
|
|
208
|
+
src,
|
|
209
|
+
3,
|
|
210
|
+
[{"module": "fmt"}, {"module": "os/exec"}, {"module": "net/http"}],
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@case(tags=["import"])
|
|
215
|
+
def case_go_import_grouped_single() -> ImportCase:
|
|
216
|
+
"""Grouped import with one item."""
|
|
217
|
+
src = """\
|
|
218
|
+
package main
|
|
219
|
+
import (
|
|
220
|
+
"fmt"
|
|
221
|
+
)
|
|
222
|
+
"""
|
|
223
|
+
return "go", src, {"module": "fmt"}
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
@case(tags=["mixed"])
|
|
227
|
+
def case_go_full_module() -> MixedCase:
|
|
228
|
+
"""Realistic Go module with godoc-style comments.
|
|
229
|
+
|
|
230
|
+
Expected-kinds tuple unchanged; content assertions are in
|
|
231
|
+
`test_docstrings.py`.
|
|
232
|
+
"""
|
|
233
|
+
src = """\
|
|
234
|
+
package main
|
|
235
|
+
|
|
236
|
+
import (
|
|
237
|
+
"fmt"
|
|
238
|
+
"os"
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
// Config is the runtime configuration for the service.
|
|
242
|
+
type Config struct {
|
|
243
|
+
Name string
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// String returns a human-readable summary of the Config.
|
|
247
|
+
func (c Config) String() string { return c.Name }
|
|
248
|
+
|
|
249
|
+
// main is the entry point for the service.
|
|
250
|
+
func main() {
|
|
251
|
+
fmt.Println("hello")
|
|
252
|
+
}
|
|
253
|
+
"""
|
|
254
|
+
return "go", src, {"import", "class", "method", "function"}, [("String", "Config")]
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
@case(tags=["symbol"])
|
|
258
|
+
def case_go_package_var() -> SymbolCase:
|
|
259
|
+
"""Package-level var."""
|
|
260
|
+
return "go", "package main\nvar MaxSize = 100\n", [("variable", "MaxSize", "")]
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
@case(tags=["symbol"])
|
|
264
|
+
def case_go_package_const() -> SymbolCase:
|
|
265
|
+
"""Package-level const."""
|
|
266
|
+
return "go", "package main\nconst Timeout = 30\n", [("variable", "Timeout", "")]
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
@case(tags=["symbol"])
|
|
270
|
+
def case_go_grouped_var() -> SymbolCase:
|
|
271
|
+
"""Go grouped var block."""
|
|
272
|
+
src = """\
|
|
273
|
+
package m
|
|
274
|
+
|
|
275
|
+
var (
|
|
276
|
+
X = 1
|
|
277
|
+
Y = 2
|
|
278
|
+
)
|
|
279
|
+
"""
|
|
280
|
+
return "go", src, [("variable", "X", ""), ("variable", "Y", "")]
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
@case(tags=["symbol"])
|
|
284
|
+
def case_go_grouped_const() -> SymbolCase:
|
|
285
|
+
"""Go grouped const block (already supported — regression guard)."""
|
|
286
|
+
src = """\
|
|
287
|
+
package m
|
|
288
|
+
|
|
289
|
+
const (
|
|
290
|
+
A = 1
|
|
291
|
+
B = 2
|
|
292
|
+
)
|
|
293
|
+
"""
|
|
294
|
+
return "go", src, [("variable", "A", ""), ("variable", "B", "")]
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Package greet formats greetings for named recipients.
|
|
2
|
+
//
|
|
3
|
+
// The Go plugin extracts functions, methods (functions with a
|
|
4
|
+
// receiver), type declarations (struct, interface, and alias, as
|
|
5
|
+
// classes), const/var declarations (as variables), and imports.
|
|
6
|
+
package greet
|
|
7
|
+
|
|
8
|
+
import (
|
|
9
|
+
"fmt"
|
|
10
|
+
|
|
11
|
+
"greeter/util"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
// DefaultGreeting is the fallback prefix.
|
|
15
|
+
const DefaultGreeting = "Hello"
|
|
16
|
+
|
|
17
|
+
var fallbackLocale = "en" // trailing comment: its own chunk, not folded
|
|
18
|
+
|
|
19
|
+
// Temperature is an alias for the underlying float type.
|
|
20
|
+
type Temperature = float64
|
|
21
|
+
|
|
22
|
+
// Greeter holds a greeting prefix.
|
|
23
|
+
type Greeter struct {
|
|
24
|
+
Prefix string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Formatter renders a greeting for a name.
|
|
28
|
+
type Formatter interface {
|
|
29
|
+
Format(name string) string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Standalone note, separated by blank lines from any definition.
|
|
33
|
+
// Second line of the same block.
|
|
34
|
+
|
|
35
|
+
// Greet greets a single recipient.
|
|
36
|
+
func (g Greeter) Greet(name string) string {
|
|
37
|
+
return fmt.Sprintf("%s, %s", g.Prefix, util.Trim(name))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// FormatGreeting formats a greeting via a Greeter.
|
|
41
|
+
func FormatGreeting(g Greeter, name string) string {
|
|
42
|
+
return g.Greet(name)
|
|
43
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Go doc-comment extraction (Go is exterior-doc: leading comments attach via the sibling walk)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pytest_cases import parametrize_with_cases
|
|
6
|
+
|
|
7
|
+
from rbtr.git import FileEntry
|
|
8
|
+
from rbtr.languages.extract import extract_file
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@parametrize_with_cases(
|
|
12
|
+
"lang, source, name, snippet", cases=".cases_docstrings", has_tag="documented"
|
|
13
|
+
)
|
|
14
|
+
def test_documented_chunk_includes_doc_text(
|
|
15
|
+
lang: str, source: str, name: str, snippet: str
|
|
16
|
+
) -> None:
|
|
17
|
+
"""By default the chunk content carries the symbol's docs."""
|
|
18
|
+
chunks = extract_file(FileEntry("input", "sha1", source.encode()), lang)
|
|
19
|
+
chunk = next(c for c in chunks if c.name == name)
|
|
20
|
+
assert snippet in chunk.content, f"expected {snippet!r} in {lang}.{name}: {chunk.content!r}"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@parametrize_with_cases(
|
|
24
|
+
"lang, source, name, snippet", cases=".cases_docstrings", has_tag="undocumented"
|
|
25
|
+
)
|
|
26
|
+
def test_no_phantom_documentation(lang: str, source: str, name: str, snippet: str) -> None:
|
|
27
|
+
"""Symbols without documentation do not gain any in content."""
|
|
28
|
+
chunks = extract_file(FileEntry("input", "sha1", source.encode()), lang)
|
|
29
|
+
chunk = next(c for c in chunks if c.name == name)
|
|
30
|
+
assert snippet not in chunk.content, (
|
|
31
|
+
f"unexpected {snippet!r} in {lang}.{name}: {chunk.content!r}"
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@parametrize_with_cases(
|
|
36
|
+
"lang, source, name, snippet", cases=".cases_docstrings", has_tag="exterior_doc"
|
|
37
|
+
)
|
|
38
|
+
def test_leading_doc_folds_into_symbol(lang: str, source: str, name: str, snippet: str) -> None:
|
|
39
|
+
"""A leading doc comment folds into its symbol: it appears in the chunk
|
|
40
|
+
content and the chunk starts on the comment's line, above the definition."""
|
|
41
|
+
chunk = next(
|
|
42
|
+
c for c in extract_file(FileEntry("input", "sha1", source.encode()), lang) if c.name == name
|
|
43
|
+
)
|
|
44
|
+
assert snippet in chunk.content
|
|
45
|
+
assert chunk.content.lstrip().startswith(("//", "/*"))
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Go extraction tests (cases in `cases_extraction.py`)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pytest_cases import parametrize_with_cases
|
|
6
|
+
|
|
7
|
+
from rbtr.git import FileEntry
|
|
8
|
+
from rbtr.index.models import ChunkKind, ImportMeta
|
|
9
|
+
from rbtr.languages.extract import extract_file
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@parametrize_with_cases("lang, source, expected", cases=".cases_extraction", has_tag="symbol")
|
|
13
|
+
def test_extracts_expected_symbols(lang: str, source: str, expected: list) -> None:
|
|
14
|
+
"""Each expected (kind, name, scope) tuple appears in the output."""
|
|
15
|
+
chunks = extract_file(FileEntry("input", "sha1", source.encode()), lang)
|
|
16
|
+
symbols = [(c.kind, c.name, c.scope) for c in chunks]
|
|
17
|
+
for exp in expected:
|
|
18
|
+
assert exp in symbols, f"expected {exp} not found in {symbols}"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@parametrize_with_cases(
|
|
22
|
+
"lang, source, expected_kinds, expected_methods", cases=".cases_extraction", has_tag="mixed"
|
|
23
|
+
)
|
|
24
|
+
def test_extracts_all_expected_kinds(
|
|
25
|
+
lang: str, source: str, expected_kinds: set[str], expected_methods: list[tuple[str, str]]
|
|
26
|
+
) -> None:
|
|
27
|
+
"""Realistic source produces all expected chunk kinds and method scoping."""
|
|
28
|
+
chunks = extract_file(FileEntry("input", "sha1", source.encode()), lang)
|
|
29
|
+
kinds = {c.kind for c in chunks}
|
|
30
|
+
for kind in expected_kinds:
|
|
31
|
+
assert kind in kinds, f"expected kind {kind!r} not in {kinds}"
|
|
32
|
+
methods = [(c.name, c.scope) for c in chunks if c.kind == ChunkKind.METHOD]
|
|
33
|
+
for name, scope in expected_methods:
|
|
34
|
+
assert (name, scope) in methods, f"expected method ({name}, {scope}) not in {methods}"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@parametrize_with_cases("lang, source, expected", cases=".cases_extraction", has_tag="import")
|
|
38
|
+
def test_extracts_import_metadata(lang: str, source: str, expected: dict) -> None:
|
|
39
|
+
"""First import chunk has the expected metadata."""
|
|
40
|
+
chunks = extract_file(FileEntry("input", "sha1", source.encode()), lang)
|
|
41
|
+
imports = [c for c in chunks if c.kind == ChunkKind.IMPORT]
|
|
42
|
+
assert len(imports) >= 1, f"no import chunks extracted from {source!r}"
|
|
43
|
+
assert imports[0].metadata == ImportMeta(**expected)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@parametrize_with_cases(
|
|
47
|
+
"lang, source, count, metadata_list", cases=".cases_extraction", has_tag="multi_import"
|
|
48
|
+
)
|
|
49
|
+
def test_extracts_multi_import(
|
|
50
|
+
lang: str, source: str, count: int, metadata_list: list[dict]
|
|
51
|
+
) -> None:
|
|
52
|
+
"""Multiple imports have correct count and per-import metadata."""
|
|
53
|
+
chunks = extract_file(FileEntry("input", "sha1", source.encode()), lang)
|
|
54
|
+
imports = [c for c in chunks if c.kind == ChunkKind.IMPORT]
|
|
55
|
+
assert len(imports) == count
|
|
56
|
+
for imp, expected in zip(imports, metadata_list, strict=True):
|
|
57
|
+
assert imp.metadata == ImportMeta(**expected)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""go sample extraction: the `samples/go/` project through the real pipeline."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
from tree_sitter import Parser
|
|
10
|
+
|
|
11
|
+
from rbtr.git import FileEntry
|
|
12
|
+
from rbtr.index.models import Chunk, ChunkKind, Edge
|
|
13
|
+
from rbtr.languages.edges import build_resolution_map, infer_import_edges
|
|
14
|
+
from rbtr.languages.extract import extract_file
|
|
15
|
+
from rbtr.languages.manager import get_manager
|
|
16
|
+
from rbtr.testing import render_edges
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from syrupy.assertion import SnapshotAssertion
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture
|
|
23
|
+
def project() -> list[tuple[str, str]]:
|
|
24
|
+
root = Path(__file__).parent / "samples" / "go"
|
|
25
|
+
return [
|
|
26
|
+
(str(p.relative_to(root)), p.read_text()) for p in sorted(root.rglob("*")) if p.is_file()
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@pytest.fixture
|
|
31
|
+
def chunks(project: list[tuple[str, str]]) -> list[Chunk]:
|
|
32
|
+
manager = get_manager()
|
|
33
|
+
out: list[Chunk] = []
|
|
34
|
+
for path, text in project:
|
|
35
|
+
lang = manager.detect_language(path) or "go"
|
|
36
|
+
out.extend(extract_file(FileEntry(path, "sha1", text.encode()), lang))
|
|
37
|
+
return out
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@pytest.fixture
|
|
41
|
+
def edges(project: list[tuple[str, str]], chunks: list[Chunk]) -> list[Edge]:
|
|
42
|
+
manager = get_manager()
|
|
43
|
+
repo_files = {path for path, _ in project}
|
|
44
|
+
return infer_import_edges(chunks, repo_files, build_resolution_map(manager))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_emits_expected_kinds(chunks: list[Chunk]) -> None:
|
|
48
|
+
kinds = {c.kind for c in chunks}
|
|
49
|
+
assert {
|
|
50
|
+
ChunkKind.FUNCTION,
|
|
51
|
+
ChunkKind.METHOD,
|
|
52
|
+
ChunkKind.CLASS,
|
|
53
|
+
ChunkKind.VARIABLE,
|
|
54
|
+
ChunkKind.IMPORT,
|
|
55
|
+
ChunkKind.COMMENT,
|
|
56
|
+
} <= kinds
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_parses_cleanly(project: list[tuple[str, str]]) -> None:
|
|
60
|
+
manager = get_manager()
|
|
61
|
+
for path, text in project:
|
|
62
|
+
grammar = manager.grammar(manager.detect_language(path) or "go")
|
|
63
|
+
assert grammar is not None
|
|
64
|
+
assert not Parser(grammar).parse(text.encode()).root_node.has_error, path
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_extraction_matches_snapshot(chunks: list[Chunk], snapshot_json: SnapshotAssertion) -> None:
|
|
68
|
+
assert chunks == snapshot_json
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_edges_match_snapshot(
|
|
72
|
+
chunks: list[Chunk], edges: list[Edge], snapshot_json: SnapshotAssertion
|
|
73
|
+
) -> None:
|
|
74
|
+
assert render_edges(edges, chunks) == snapshot_json
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
rbtr_lang_go/__init__.py,sha256=ESnwM06MFOjJEdiK8MbCsQGStwLJ-2n0AIgzYpsuZkg,34
|
|
2
|
+
rbtr_lang_go/go.scm,sha256=t2T5WwXqMNkGa0TT9PIT9ue_2nTO-TubZdKobz90v5w,1271
|
|
3
|
+
rbtr_lang_go/plugin.py,sha256=zKsesdh0CLCRdr68dKbbb_5xjtzu5zQjzBvTS-yQpIw,1342
|
|
4
|
+
rbtr_lang_go/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
rbtr_lang_go/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
rbtr_lang_go/tests/__snapshots__/test_samples/test_edges_match_snapshot.json,sha256=nBRO23R3ddiNmQUm5ndA5lSDAdOJH0iAQWPErqpe4As,67
|
|
7
|
+
rbtr_lang_go/tests/__snapshots__/test_samples/test_extraction_matches_snapshot.json,sha256=6Iy2ie47Ety7dICpKLXhh5bOA3DBXuSTU0rMCngRZyg,7182
|
|
8
|
+
rbtr_lang_go/tests/cases_docstrings.py,sha256=9cV3w9AxmMm9ZDaO3u1Bv-AHeXHAgnHL7IHe-U9fq9A,3453
|
|
9
|
+
rbtr_lang_go/tests/cases_extraction.py,sha256=hprGkPynyITK8U2VY_bdk6E6nA6HBEcF8UWK_9J_o7o,5810
|
|
10
|
+
rbtr_lang_go/tests/samples/go/go.go,sha256=_PhwkrAMIaFZfXO-4WkEr0b7thT_GQ1s1HAP2T70vtE,1090
|
|
11
|
+
rbtr_lang_go/tests/samples/go/greeter/util.go,sha256=6JsGe7imJr6rcCj4jfTJf9uDpbTGD7l0sYtI4BGvYlU,190
|
|
12
|
+
rbtr_lang_go/tests/test_docstrings.py,sha256=HLh5Rv-LRO_Fjt04yJ1jijwjDpnSJxJ2KqrJHWWr8VY,1891
|
|
13
|
+
rbtr_lang_go/tests/test_extraction.py,sha256=5CmjbgGegt-UWCvtTO_6cIJx39BuWawhJHj-SAmTn9s,2652
|
|
14
|
+
rbtr_lang_go/tests/test_samples.py,sha256=JdFj3Zyq6NnbPukt76KOI7fiWr-WmMQbCIy9BqGO94o,2290
|
|
15
|
+
rbtr_lang_go-2026.7.0.dev0.dist-info/WHEEL,sha256=CoDSoyhtC_eO_tlxRYzsTraPv1fPJRXFx91k6ISeAvA,81
|
|
16
|
+
rbtr_lang_go-2026.7.0.dev0.dist-info/entry_points.txt,sha256=7KT_1_hCbZVpXXkfDXPjHoop0XPZK3GUCGqczFOrWGw,46
|
|
17
|
+
rbtr_lang_go-2026.7.0.dev0.dist-info/METADATA,sha256=c_RgDm3iQeqSO9C6BOo6ABB7N-BkZ4ul3oFElZkegL4,214
|
|
18
|
+
rbtr_lang_go-2026.7.0.dev0.dist-info/RECORD,,
|