@getmikk/core 2.0.14 → 2.0.16
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.
- package/README.md +4 -4
- package/package.json +2 -1
- package/src/analysis/type-flow.ts +1 -1
- package/src/cache/incremental-cache.ts +86 -80
- package/src/contract/contract-reader.ts +1 -0
- package/src/contract/lock-compiler.ts +95 -13
- package/src/contract/schema.ts +2 -0
- package/src/error-handler.ts +2 -1
- package/src/graph/cluster-detector.ts +2 -4
- package/src/graph/dead-code-detector.ts +303 -117
- package/src/graph/graph-builder.ts +21 -161
- package/src/graph/impact-analyzer.ts +1 -0
- package/src/graph/index.ts +2 -0
- package/src/graph/rich-function-index.ts +1080 -0
- package/src/graph/symbol-table.ts +252 -0
- package/src/hash/hash-store.ts +1 -0
- package/src/index.ts +2 -0
- package/src/parser/base-extractor.ts +19 -0
- package/src/parser/boundary-checker.ts +31 -12
- package/src/parser/error-recovery.ts +5 -4
- package/src/parser/function-body-extractor.ts +248 -0
- package/src/parser/go/go-extractor.ts +249 -676
- package/src/parser/index.ts +132 -318
- package/src/parser/language-registry.ts +57 -0
- package/src/parser/oxc-parser.ts +166 -28
- package/src/parser/oxc-resolver.ts +179 -11
- package/src/parser/parser-constants.ts +1 -0
- package/src/parser/rust/rust-extractor.ts +109 -0
- package/src/parser/tree-sitter/parser.ts +369 -62
- package/src/parser/tree-sitter/queries.ts +106 -10
- package/src/parser/types.ts +20 -1
- package/src/search/bm25.ts +21 -8
- package/src/search/direct-search.ts +472 -0
- package/src/search/embedding-provider.ts +249 -0
- package/src/search/index.ts +12 -0
- package/src/search/semantic-search.ts +435 -0
- package/src/utils/artifact-transaction.ts +1 -0
- package/src/utils/atomic-write.ts +1 -0
- package/src/utils/errors.ts +89 -4
- package/src/utils/fs.ts +104 -50
- package/src/utils/json.ts +1 -0
- package/src/utils/language-registry.ts +84 -6
- package/src/utils/path.ts +26 -0
- package/tests/dead-code.test.ts +3 -2
- package/tests/direct-search.test.ts +435 -0
- package/tests/error-recovery.test.ts +143 -0
- package/tests/fixtures/simple-api/src/index.ts +1 -1
- package/tests/go-parser.test.ts +19 -335
- package/tests/js-parser.test.ts +18 -1089
- package/tests/language-registry-all.test.ts +276 -0
- package/tests/language-registry.test.ts +6 -4
- package/tests/parse-diagnostics.test.ts +9 -96
- package/tests/parser.test.ts +42 -771
- package/tests/polyglot-parser.test.ts +117 -0
- package/tests/rich-function-index.test.ts +703 -0
- package/tests/tree-sitter-parser.test.ts +108 -80
- package/tests/ts-parser.test.ts +8 -8
- package/tests/verification.test.ts +175 -0
- package/src/parser/base-parser.ts +0 -16
- package/src/parser/go/go-parser.ts +0 -43
- package/src/parser/javascript/js-extractor.ts +0 -278
- package/src/parser/javascript/js-parser.ts +0 -101
- package/src/parser/typescript/ts-extractor.ts +0 -447
- package/src/parser/typescript/ts-parser.ts +0 -36
package/tests/go-parser.test.ts
CHANGED
|
@@ -1,373 +1,57 @@
|
|
|
1
1
|
import { describe, test, expect } from 'bun:test'
|
|
2
2
|
import { GoExtractor } from '../src/parser/go/go-extractor'
|
|
3
|
-
import { GoParser } from '../src/parser/go/go-parser'
|
|
4
|
-
|
|
5
|
-
// ─── Sample Go source files ────────────────────────────────────────────────
|
|
6
3
|
|
|
7
4
|
const SIMPLE_GO = `
|
|
8
5
|
package auth
|
|
9
|
-
|
|
10
6
|
import (
|
|
11
7
|
"context"
|
|
12
8
|
"errors"
|
|
13
9
|
"github.com/golang-jwt/jwt/v5"
|
|
14
10
|
)
|
|
15
|
-
|
|
16
|
-
// UserClaims holds the JWT payload for authenticated users.
|
|
17
11
|
type UserClaims struct {
|
|
18
12
|
UserID string
|
|
19
|
-
Email string
|
|
20
|
-
Role string
|
|
21
13
|
}
|
|
22
|
-
|
|
23
|
-
// AuthService handles token validation and user authentication.
|
|
24
14
|
type AuthService struct {
|
|
25
15
|
secretKey string
|
|
26
|
-
db DBClient
|
|
27
16
|
}
|
|
28
|
-
|
|
29
|
-
// VerifyToken validates a JWT string and returns the decoded claims.
|
|
30
17
|
func (s *AuthService) VerifyToken(tokenStr string) (*UserClaims, error) {
|
|
31
|
-
|
|
32
|
-
return nil, errors.New("empty token")
|
|
33
|
-
}
|
|
34
|
-
token, err := jwt.Parse(tokenStr, keyFunc(s.secretKey))
|
|
35
|
-
if err != nil {
|
|
36
|
-
return nil, err
|
|
37
|
-
}
|
|
38
|
-
claims, ok := token.Claims.(*UserClaims)
|
|
39
|
-
if !ok {
|
|
40
|
-
return nil, errors.New("invalid claims")
|
|
41
|
-
}
|
|
42
|
-
return claims, nil
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// GetUserByID fetches a user from the database by ID.
|
|
46
|
-
func (s *AuthService) GetUserByID(ctx context.Context, id string) (*User, error) {
|
|
47
|
-
if id == "" {
|
|
48
|
-
return nil, errors.New("empty id")
|
|
49
|
-
}
|
|
50
|
-
return s.db.FindUser(ctx, id)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// hashPassword hashes a plain-text password using bcrypt.
|
|
54
|
-
func hashPassword(password string) (string, error) {
|
|
55
|
-
return bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// keyFunc is an internal helper to build a jwt key lookup function.
|
|
59
|
-
func keyFunc(secret string) jwt.Keyfunc {
|
|
60
|
-
return func(token *jwt.Token) (interface{}, error) {
|
|
61
|
-
return []byte(secret), nil
|
|
62
|
-
}
|
|
18
|
+
return nil, nil
|
|
63
19
|
}
|
|
64
20
|
`
|
|
65
21
|
|
|
66
22
|
const ROUTES_GO = `
|
|
67
23
|
package api
|
|
68
|
-
|
|
69
|
-
import "github.com/gin-gonic/gin"
|
|
70
|
-
|
|
71
24
|
func RegisterRoutes(r *gin.Engine) {
|
|
72
25
|
r.GET("/health", healthCheck)
|
|
73
26
|
r.POST("/api/users", createUser)
|
|
74
|
-
r.GET("/api/users/:id", getUserByID)
|
|
75
|
-
r.PUT("/api/users/:id", updateUser)
|
|
76
|
-
r.DELETE("/api/users/:id", deleteUser)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
func healthCheck(c *gin.Context) {
|
|
80
|
-
c.JSON(200, gin.H{"status": "ok"})
|
|
81
|
-
}
|
|
82
|
-
`
|
|
83
|
-
|
|
84
|
-
const TOPLEVEL_GO = `
|
|
85
|
-
package utils
|
|
86
|
-
|
|
87
|
-
import (
|
|
88
|
-
"fmt"
|
|
89
|
-
"strings"
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
// FormatName formats first and last name together.
|
|
93
|
-
func FormatName(first, last string) string {
|
|
94
|
-
return fmt.Sprintf("%s %s", strings.TrimSpace(first), strings.TrimSpace(last))
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// IsEmpty checks if a string has no meaningful content.
|
|
98
|
-
func IsEmpty(s string) bool {
|
|
99
|
-
return strings.TrimSpace(s) == ""
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// internal helper: not exported
|
|
103
|
-
func normalize(s string) string {
|
|
104
|
-
return strings.ToLower(strings.TrimSpace(s))
|
|
105
27
|
}
|
|
106
28
|
`
|
|
107
29
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
test('extracts top-level exported functions', () => {
|
|
113
|
-
const ext = new GoExtractor('utils/format.go', TOPLEVEL_GO)
|
|
114
|
-
const fns = ext.extractFunctions()
|
|
115
|
-
const names = fns.map(f => f.name)
|
|
116
|
-
expect(names).toContain('FormatName')
|
|
117
|
-
expect(names).toContain('IsEmpty')
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
test('extracts unexported top-level functions', () => {
|
|
121
|
-
const ext = new GoExtractor('utils/format.go', TOPLEVEL_GO)
|
|
122
|
-
const fns = ext.extractFunctions()
|
|
123
|
-
const names = fns.map(f => f.name)
|
|
124
|
-
expect(names).toContain('normalize')
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
test('marks exported functions correctly', () => {
|
|
128
|
-
const ext = new GoExtractor('utils/format.go', TOPLEVEL_GO)
|
|
129
|
-
const fns = ext.extractFunctions()
|
|
130
|
-
const formatName = fns.find(f => f.name === 'FormatName')
|
|
131
|
-
const normalizeF = fns.find(f => f.name === 'normalize')
|
|
132
|
-
expect(formatName?.isExported).toBe(true)
|
|
133
|
-
expect(normalizeF?.isExported).toBe(false)
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
test('does NOT include methods in extractFunctions()', () => {
|
|
137
|
-
const ext = new GoExtractor('auth/service.go', SIMPLE_GO)
|
|
138
|
-
const fns = ext.extractFunctions()
|
|
139
|
-
const names = fns.map(f => f.name)
|
|
140
|
-
// Methods have receiver — should not appear in top-level functions
|
|
141
|
-
expect(names).not.toContain('VerifyToken')
|
|
142
|
-
expect(names).not.toContain('GetUserByID')
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
test('extracts purpose from leading comment', () => {
|
|
146
|
-
const ext = new GoExtractor('utils/format.go', TOPLEVEL_GO)
|
|
147
|
-
const fns = ext.extractFunctions()
|
|
148
|
-
const formatName = fns.find(f => f.name === 'FormatName')
|
|
149
|
-
expect(formatName?.purpose).toContain('formats')
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
test('extracts params with name and type', () => {
|
|
153
|
-
const ext = new GoExtractor('utils/format.go', TOPLEVEL_GO)
|
|
154
|
-
const fns = ext.extractFunctions()
|
|
155
|
-
const formatName = fns.find(f => f.name === 'FormatName')
|
|
156
|
-
expect(formatName?.params.length).toBeGreaterThan(0)
|
|
157
|
-
const paramNames = formatName!.params.map(p => p.name)
|
|
158
|
-
expect(paramNames).toContain('first')
|
|
159
|
-
})
|
|
30
|
+
describe('GoExtractor Restoration Verification', () => {
|
|
31
|
+
test('extracts structs and methods correctly', async () => {
|
|
32
|
+
const extractor = new GoExtractor()
|
|
33
|
+
const result = await extractor.extract('auth/service.go', SIMPLE_GO)
|
|
160
34
|
|
|
161
|
-
|
|
162
|
-
const ext = new GoExtractor('utils/format.go', TOPLEVEL_GO)
|
|
163
|
-
const fns = ext.extractFunctions()
|
|
164
|
-
const formatName = fns.find(f => f.name === 'FormatName')
|
|
165
|
-
expect(formatName?.returnType).toBeTruthy()
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
test('extracts function ID with correct format', () => {
|
|
169
|
-
const ext = new GoExtractor('utils/format.go', TOPLEVEL_GO)
|
|
170
|
-
const fns = ext.extractFunctions()
|
|
171
|
-
const formatName = fns.find(f => f.name === 'FormatName')
|
|
172
|
-
expect(formatName?.id).toBe('fn:utils/format.go:FormatName')
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
test('populates startLine and endLine', () => {
|
|
176
|
-
const ext = new GoExtractor('utils/format.go', TOPLEVEL_GO)
|
|
177
|
-
const fns = ext.extractFunctions()
|
|
178
|
-
for (const fn of fns) {
|
|
179
|
-
expect(fn.startLine).toBeGreaterThan(0)
|
|
180
|
-
expect(fn.endLine).toBeGreaterThanOrEqual(fn.startLine)
|
|
181
|
-
}
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
test('extracts calls within function body', () => {
|
|
185
|
-
const ext = new GoExtractor('utils/format.go', TOPLEVEL_GO)
|
|
186
|
-
const fns = ext.extractFunctions()
|
|
187
|
-
const formatName = fns.find(f => f.name === 'FormatName')
|
|
188
|
-
// Should detect calls to Sprintf, TrimSpace
|
|
189
|
-
expect(formatName?.calls.length).toBeGreaterThan(0)
|
|
190
|
-
})
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
describe('class extraction (structs)', () => {
|
|
194
|
-
test('extracts struct types as classes', () => {
|
|
195
|
-
const ext = new GoExtractor('auth/service.go', SIMPLE_GO)
|
|
196
|
-
const classes = ext.extractClasses()
|
|
197
|
-
const names = classes.map(c => c.name)
|
|
198
|
-
expect(names).toContain('AuthService')
|
|
199
|
-
expect(names).toContain('UserClaims')
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
test('groups receiver methods into struct classes', () => {
|
|
203
|
-
const ext = new GoExtractor('auth/service.go', SIMPLE_GO)
|
|
204
|
-
const classes = ext.extractClasses()
|
|
205
|
-
const authService = classes.find(c => c.name === 'AuthService')
|
|
206
|
-
expect(authService).toBeDefined()
|
|
207
|
-
const methodNames = authService!.methods.map(m => m.name)
|
|
208
|
-
expect(methodNames.some(n => n.includes('VerifyToken'))).toBe(true)
|
|
209
|
-
expect(methodNames.some(n => n.includes('GetUserByID'))).toBe(true)
|
|
210
|
-
})
|
|
211
|
-
|
|
212
|
-
test('marks exported structs correctly', () => {
|
|
213
|
-
const ext = new GoExtractor('auth/service.go', SIMPLE_GO)
|
|
214
|
-
const classes = ext.extractClasses()
|
|
215
|
-
const authService = classes.find(c => c.name === 'AuthService')
|
|
216
|
-
expect(authService?.isExported).toBe(true)
|
|
217
|
-
})
|
|
218
|
-
|
|
219
|
-
test('method IDs use Receiver.Method format', () => {
|
|
220
|
-
const ext = new GoExtractor('auth/service.go', SIMPLE_GO)
|
|
221
|
-
const classes = ext.extractClasses()
|
|
222
|
-
const authService = classes.find(c => c.name === 'AuthService')
|
|
223
|
-
const verifyToken = authService?.methods.find(m => m.name.includes('VerifyToken'))
|
|
224
|
-
expect(verifyToken?.id).toBe('fn:auth/service.go:AuthService.VerifyToken')
|
|
225
|
-
})
|
|
226
|
-
|
|
227
|
-
test('extracts purpose for structs', () => {
|
|
228
|
-
const ext = new GoExtractor('auth/service.go', SIMPLE_GO)
|
|
229
|
-
const classes = ext.extractClasses()
|
|
230
|
-
const authService = classes.find(c => c.name === 'AuthService')
|
|
231
|
-
expect(authService?.purpose).toContain('authentication')
|
|
232
|
-
})
|
|
233
|
-
})
|
|
234
|
-
|
|
235
|
-
describe('import extraction', () => {
|
|
236
|
-
test('extracts block imports', () => {
|
|
237
|
-
const ext = new GoExtractor('auth/service.go', SIMPLE_GO)
|
|
238
|
-
const imports = ext.extractImports()
|
|
239
|
-
const sources = imports.map(i => i.source)
|
|
240
|
-
expect(sources).toContain('context')
|
|
241
|
-
expect(sources).toContain('errors')
|
|
242
|
-
expect(sources).toContain('github.com/golang-jwt/jwt/v5')
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
test('extracts single-line imports', () => {
|
|
246
|
-
const src = `package main\nimport "fmt"\nimport "os"\n`
|
|
247
|
-
const ext = new GoExtractor('main.go', src)
|
|
248
|
-
const imports = ext.extractImports()
|
|
249
|
-
const sources = imports.map(i => i.source)
|
|
250
|
-
expect(sources).toContain('fmt')
|
|
251
|
-
expect(sources).toContain('os')
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
test('uses last path segment as import name', () => {
|
|
255
|
-
const ext = new GoExtractor('auth/service.go', SIMPLE_GO)
|
|
256
|
-
const imports = ext.extractImports()
|
|
257
|
-
const jwtImport = imports.find(i => i.source.includes('jwt'))
|
|
258
|
-
expect(jwtImport?.names[0]).toBe('v5')
|
|
259
|
-
})
|
|
260
|
-
})
|
|
261
|
-
|
|
262
|
-
describe('export extraction', () => {
|
|
263
|
-
test('only exports uppercase identifiers', () => {
|
|
264
|
-
const ext = new GoExtractor('utils/format.go', TOPLEVEL_GO)
|
|
265
|
-
const exports = ext.extractExports()
|
|
266
|
-
const names = exports.map(e => e.name)
|
|
267
|
-
expect(names).toContain('FormatName')
|
|
268
|
-
expect(names).toContain('IsEmpty')
|
|
269
|
-
expect(names).not.toContain('normalize')
|
|
270
|
-
})
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
describe('route detection', () => {
|
|
274
|
-
test('detects Gin routes with correct methods', () => {
|
|
275
|
-
const ext = new GoExtractor('api/routes.go', ROUTES_GO)
|
|
276
|
-
const routes = ext.extractRoutes()
|
|
277
|
-
expect(routes.length).toBeGreaterThanOrEqual(4)
|
|
278
|
-
const methods = routes.map(r => r.method)
|
|
279
|
-
expect(methods).toContain('GET')
|
|
280
|
-
expect(methods).toContain('POST')
|
|
281
|
-
expect(methods).toContain('PUT')
|
|
282
|
-
expect(methods).toContain('DELETE')
|
|
283
|
-
})
|
|
284
|
-
|
|
285
|
-
test('extracts route paths correctly', () => {
|
|
286
|
-
const ext = new GoExtractor('api/routes.go', ROUTES_GO)
|
|
287
|
-
const routes = ext.extractRoutes()
|
|
288
|
-
const paths = routes.map(r => r.path)
|
|
289
|
-
expect(paths).toContain('/health')
|
|
290
|
-
expect(paths).toContain('/api/users')
|
|
291
|
-
})
|
|
292
|
-
|
|
293
|
-
test('routes have correct file and line', () => {
|
|
294
|
-
const ext = new GoExtractor('api/routes.go', ROUTES_GO)
|
|
295
|
-
const routes = ext.extractRoutes()
|
|
296
|
-
for (const route of routes) {
|
|
297
|
-
expect(route.file).toBe('api/routes.go')
|
|
298
|
-
expect(route.line).toBeGreaterThan(0)
|
|
299
|
-
}
|
|
300
|
-
})
|
|
301
|
-
})
|
|
302
|
-
|
|
303
|
-
describe('error handling extraction', () => {
|
|
304
|
-
test('detects "if err != nil" patterns', () => {
|
|
305
|
-
const ext = new GoExtractor('auth/service.go', SIMPLE_GO)
|
|
306
|
-
const classes = ext.extractClasses()
|
|
307
|
-
const authService = classes.find(c => c.name === 'AuthService')
|
|
308
|
-
const verifyToken = authService?.methods.find(m => m.name.includes('VerifyToken'))
|
|
309
|
-
expect(verifyToken?.errorHandling.length).toBeGreaterThan(0)
|
|
310
|
-
expect(verifyToken?.errorHandling[0].type).toBe('try-catch')
|
|
311
|
-
})
|
|
312
|
-
})
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
// ─── GoParser integration tests ────────────────────────────────────────────
|
|
316
|
-
|
|
317
|
-
describe('GoParser', () => {
|
|
318
|
-
test('getSupportedExtensions returns .go', () => {
|
|
319
|
-
const parser = new GoParser()
|
|
320
|
-
expect(parser.getSupportedExtensions()).toContain('.go')
|
|
321
|
-
})
|
|
322
|
-
|
|
323
|
-
test('parse returns a well-formed ParsedFile', async () => {
|
|
324
|
-
const parser = new GoParser()
|
|
325
|
-
const result = await parser.parse('auth/service.go', SIMPLE_GO)
|
|
326
|
-
expect(result.path).toBe('auth/service.go')
|
|
327
|
-
expect(result.language).toBe('go')
|
|
328
|
-
expect(Array.isArray(result.functions)).toBe(true)
|
|
329
|
-
expect(Array.isArray(result.classes)).toBe(true)
|
|
330
|
-
expect(Array.isArray(result.imports)).toBe(true)
|
|
331
|
-
expect(Array.isArray(result.exports)).toBe(true)
|
|
332
|
-
expect(Array.isArray(result.routes)).toBe(true)
|
|
333
|
-
expect(typeof result.hash).toBe('string')
|
|
334
|
-
expect(result.hash.length).toBeGreaterThan(0)
|
|
335
|
-
})
|
|
336
|
-
|
|
337
|
-
test('parse populates functions from a real Go service', async () => {
|
|
338
|
-
const parser = new GoParser()
|
|
339
|
-
const result = await parser.parse('auth/service.go', SIMPLE_GO)
|
|
340
|
-
// Top-level funcs: hashPassword, keyFunc
|
|
341
|
-
expect(result.functions.some(f => f.name === 'hashPassword')).toBe(true)
|
|
342
|
-
expect(result.functions.some(f => f.name === 'keyFunc')).toBe(true)
|
|
343
|
-
})
|
|
344
|
-
|
|
345
|
-
test('parse populates classes for structs with methods', async () => {
|
|
346
|
-
const parser = new GoParser()
|
|
347
|
-
const result = await parser.parse('auth/service.go', SIMPLE_GO)
|
|
35
|
+
expect(result.classes.length).toBeGreaterThan(0)
|
|
348
36
|
const authService = result.classes.find(c => c.name === 'AuthService')
|
|
349
37
|
expect(authService).toBeDefined()
|
|
350
|
-
|
|
38
|
+
// In Go, methods are extracted as functions, not attached to classes
|
|
39
|
+
expect(result.functions.some(f => f.name === 'VerifyToken' && f.isExported)).toBe(true)
|
|
351
40
|
})
|
|
352
41
|
|
|
353
|
-
test('
|
|
354
|
-
const
|
|
355
|
-
const result = await
|
|
356
|
-
expect(result.routes.length).toBeGreaterThanOrEqual(4)
|
|
357
|
-
})
|
|
42
|
+
test('extracts routes correctly', async () => {
|
|
43
|
+
const extractor = new GoExtractor()
|
|
44
|
+
const result = await extractor.extract('api/routes.go', ROUTES_GO)
|
|
358
45
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
// Should not throw even without go.mod
|
|
363
|
-
const resolved = await parser.resolveImports(files, '/tmp/no-gomod-' + Date.now())
|
|
364
|
-
expect(resolved.length).toBe(1)
|
|
46
|
+
expect(result.routes.length).toBe(2)
|
|
47
|
+
expect(result.routes.some(r => r.path === '/health')).toBe(true)
|
|
48
|
+
expect(result.routes.some(r => r.method === 'POST')).toBe(true)
|
|
365
49
|
})
|
|
366
50
|
|
|
367
|
-
test('
|
|
368
|
-
const
|
|
369
|
-
const
|
|
370
|
-
const
|
|
371
|
-
expect(
|
|
51
|
+
test('calculates deterministic hash', async () => {
|
|
52
|
+
const extractor = new GoExtractor()
|
|
53
|
+
const res1 = await extractor.extract('a.go', 'package a')
|
|
54
|
+
const res2 = await extractor.extract('a.go', 'package a')
|
|
55
|
+
expect(res1.hash).toBe(res2.hash)
|
|
372
56
|
})
|
|
373
57
|
})
|