skrypt-ai 0.3.4 → 0.4.1
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 +1 -1
- package/dist/auth/index.d.ts +0 -1
- package/dist/auth/index.js +3 -5
- package/dist/autofix/index.js +15 -3
- package/dist/cli.js +19 -4
- package/dist/commands/check-links.js +164 -174
- package/dist/commands/deploy.js +5 -2
- package/dist/commands/generate.js +206 -199
- package/dist/commands/i18n.js +3 -20
- package/dist/commands/init.js +47 -40
- package/dist/commands/lint.js +3 -20
- package/dist/commands/mcp.js +125 -122
- package/dist/commands/monitor.js +125 -108
- package/dist/commands/review-pr.js +1 -1
- package/dist/commands/sdk.js +1 -1
- package/dist/config/loader.js +21 -2
- package/dist/generator/organizer.d.ts +3 -0
- package/dist/generator/organizer.js +4 -9
- package/dist/generator/writer.js +2 -10
- package/dist/github/pr-comments.js +21 -8
- package/dist/plugins/index.js +1 -0
- package/dist/scanner/index.js +8 -2
- package/dist/template/docs.json +2 -1
- package/dist/template/next.config.mjs +2 -1
- package/dist/template/package.json +17 -15
- package/dist/template/public/favicon.svg +4 -0
- package/dist/template/public/search-index.json +1 -1
- package/dist/template/scripts/build-search-index.mjs +120 -25
- package/dist/template/src/app/api/chat/route.ts +11 -3
- package/dist/template/src/app/docs/README.md +28 -0
- package/dist/template/src/app/docs/[...slug]/page.tsx +139 -16
- package/dist/template/src/app/docs/auth/page.mdx +589 -0
- package/dist/template/src/app/docs/autofix/page.mdx +624 -0
- package/dist/template/src/app/docs/cli/page.mdx +217 -0
- package/dist/template/src/app/docs/config/page.mdx +428 -0
- package/dist/template/src/app/docs/configuration/page.mdx +86 -0
- package/dist/template/src/app/docs/deployment/page.mdx +112 -0
- package/dist/template/src/app/docs/error.tsx +20 -0
- package/dist/template/src/app/docs/generator/generator.md +504 -0
- package/dist/template/src/app/docs/generator/organizer.md +779 -0
- package/dist/template/src/app/docs/generator/page.mdx +613 -0
- package/dist/template/src/app/docs/github/page.mdx +502 -0
- package/dist/template/src/app/docs/llm/anthropic-client.md +549 -0
- package/dist/template/src/app/docs/llm/index.md +471 -0
- package/dist/template/src/app/docs/llm/page.mdx +428 -0
- package/dist/template/src/app/docs/llms-full.md +256 -0
- package/dist/template/src/app/docs/llms.txt +2971 -0
- package/dist/template/src/app/docs/not-found.tsx +23 -0
- package/dist/template/src/app/docs/page.mdx +0 -3
- package/dist/template/src/app/docs/plugins/page.mdx +1793 -0
- package/dist/template/src/app/docs/pro/page.mdx +121 -0
- package/dist/template/src/app/docs/quickstart/page.mdx +93 -0
- package/dist/template/src/app/docs/scanner/content-type.md +599 -0
- package/dist/template/src/app/docs/scanner/index.md +212 -0
- package/dist/template/src/app/docs/scanner/page.mdx +307 -0
- package/dist/template/src/app/docs/scanner/python.md +469 -0
- package/dist/template/src/app/docs/scanner/python_parser.md +1056 -0
- package/dist/template/src/app/docs/scanner/rust.md +325 -0
- package/dist/template/src/app/docs/scanner/typescript.md +201 -0
- package/dist/template/src/app/error.tsx +3 -3
- package/dist/template/src/app/icon.tsx +29 -0
- package/dist/template/src/app/layout.tsx +42 -0
- package/dist/template/src/app/not-found.tsx +35 -0
- package/dist/template/src/app/page.tsx +62 -28
- package/dist/template/src/components/ai-chat.tsx +26 -21
- package/dist/template/src/components/breadcrumbs.tsx +46 -2
- package/dist/template/src/components/copy-button.tsx +17 -3
- package/dist/template/src/components/docs-layout.tsx +142 -8
- package/dist/template/src/components/feedback.tsx +4 -2
- package/dist/template/src/components/footer.tsx +42 -0
- package/dist/template/src/components/header.tsx +29 -5
- package/dist/template/src/components/mdx/accordion.tsx +7 -6
- package/dist/template/src/components/mdx/card.tsx +19 -7
- package/dist/template/src/components/mdx/code-block.tsx +17 -3
- package/dist/template/src/components/mdx/code-group.tsx +65 -18
- package/dist/template/src/components/mdx/code-playground.tsx +3 -0
- package/dist/template/src/components/mdx/go-playground.tsx +3 -0
- package/dist/template/src/components/mdx/highlighted-code.tsx +171 -76
- package/dist/template/src/components/mdx/python-playground.tsx +2 -0
- package/dist/template/src/components/mdx/tabs.tsx +74 -6
- package/dist/template/src/components/page-header.tsx +19 -0
- package/dist/template/src/components/scroll-to-top.tsx +33 -0
- package/dist/template/src/components/search-dialog.tsx +206 -52
- package/dist/template/src/components/sidebar.tsx +136 -77
- package/dist/template/src/components/table-of-contents.tsx +23 -7
- package/dist/template/src/lib/highlight.ts +90 -31
- package/dist/template/src/lib/search.ts +14 -4
- package/dist/template/src/lib/theme-utils.ts +140 -0
- package/dist/template/src/styles/globals.css +307 -166
- package/dist/template/src/types/remark-gfm.d.ts +2 -0
- package/dist/utils/files.d.ts +9 -0
- package/dist/utils/files.js +33 -0
- package/dist/utils/validation.d.ts +4 -0
- package/dist/utils/validation.js +38 -0
- package/package.json +1 -4
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# Index.ts
|
|
2
|
+
|
|
3
|
+
## Functions
|
|
4
|
+
|
|
5
|
+
### `scanDirectory`
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
async function scanDirectory(dir: string, options: ScanOptions = {}): Promise<ScanAllResult>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Use this to recursively scan a directory (or single file) and extract all API elements — functions, classes, types, and exports — across multiple languages including Python, TypeScript, JavaScript, Go, and Rust.
|
|
12
|
+
|
|
13
|
+
## Parameters
|
|
14
|
+
|
|
15
|
+
| Name | Type | Required | Description |
|
|
16
|
+
|------|------|----------|-------------|
|
|
17
|
+
| `dir` | `string` | ✅ Yes | Path to the directory or single file to scan |
|
|
18
|
+
| `options` | `ScanOptions` | ❌ No | Configuration options to control which files are included or excluded |
|
|
19
|
+
| `options.include` | `string[]` | ❌ No | Glob patterns for files to scan. Defaults to `['**/*.py', '**/*.ts', '**/*.js', '**/*.go', '**/*.rs']` |
|
|
20
|
+
| `options.exclude` | `string[]` | ❌ No | Glob patterns for files to skip. Defaults to `['**/node_modules/**', '**/__pycache__/**', '**/dist/**']` |
|
|
21
|
+
|
|
22
|
+
## Returns
|
|
23
|
+
|
|
24
|
+
Returns a `Promise<ScanAllResult>` that resolves to an object containing all discovered API elements grouped by file. Rejects if the provided path does not exist or cannot be read.
|
|
25
|
+
|
|
26
|
+
| Field | Type | Description |
|
|
27
|
+
|-------|------|-------------|
|
|
28
|
+
| `files` | `ScanResult[]` | Array of per-file scan results, each containing extracted API elements |
|
|
29
|
+
| `totalFiles` | `number` | Total number of files successfully scanned |
|
|
30
|
+
| `errors` | `string[]` | Any non-fatal errors encountered during scanning |
|
|
31
|
+
|
|
32
|
+
## Notes
|
|
33
|
+
|
|
34
|
+
- Passing a **single file path** instead of a directory is supported — the scanner will detect the file extension and apply the appropriate language parser.
|
|
35
|
+
- Files matching `exclude` patterns are silently skipped and do not appear in `errors`.
|
|
36
|
+
- Use `options.include` to narrow scans to a specific language (e.g., `['**/*.ts']`) for faster results in large monorepos.
|
|
37
|
+
|
|
38
|
+
### `scanFile`
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
async function scanFile(filePath: string): Promise<ScanResult>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Use this to analyze a single source file and extract structured metadata — functions, classes, types, and other code constructs — without scanning an entire directory.
|
|
45
|
+
|
|
46
|
+
`scanFile` automatically detects the file's language, selects the appropriate scanner, and returns a normalized `ScanResult` regardless of whether the file is Python, TypeScript, or another supported language.
|
|
47
|
+
|
|
48
|
+
## Parameters
|
|
49
|
+
|
|
50
|
+
| Name | Type | Required | Description |
|
|
51
|
+
|------|------|----------|-------------|
|
|
52
|
+
| `filePath` | `string` | ✅ | Absolute or relative path to the source file to scan |
|
|
53
|
+
|
|
54
|
+
## Returns
|
|
55
|
+
|
|
56
|
+
Returns `Promise<ScanResult>` — resolves with a structured result containing:
|
|
57
|
+
|
|
58
|
+
| Field | Type | Description |
|
|
59
|
+
|-------|------|-------------|
|
|
60
|
+
| `filePath` | `string` | The original file path passed in |
|
|
61
|
+
| `language` | `string` | Detected language (`"typescript"`, `"python"`, etc.) |
|
|
62
|
+
| `functions` | `FunctionInfo[]` | All top-level and exported functions found |
|
|
63
|
+
| `classes` | `ClassInfo[]` | All class definitions found |
|
|
64
|
+
| `exports` | `string[]` | Named exports from the file |
|
|
65
|
+
| `errors` | `string[]` | Any parse errors encountered (non-fatal) |
|
|
66
|
+
|
|
67
|
+
> **Note:** If no scanner is found for the file extension, `scanFile` returns a default result with an empty `functions` and `classes` array rather than throwing. Always check `errors` for partial failures.
|
|
68
|
+
|
|
69
|
+
**Example:**
|
|
70
|
+
|
|
71
|
+
```typescript example.ts
|
|
72
|
+
// Inline types to simulate the autodocs ScanResult shape
|
|
73
|
+
type FunctionInfo = {
|
|
74
|
+
name: string
|
|
75
|
+
signature: string
|
|
76
|
+
docstring?: string
|
|
77
|
+
lineStart: number
|
|
78
|
+
lineEnd: number
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
type ClassInfo = {
|
|
82
|
+
name: string
|
|
83
|
+
methods: FunctionInfo[]
|
|
84
|
+
lineStart: number
|
|
85
|
+
lineEnd: number
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
type ScanResult = {
|
|
89
|
+
filePath: string
|
|
90
|
+
language: string
|
|
91
|
+
functions: FunctionInfo[]
|
|
92
|
+
classes: ClassInfo[]
|
|
93
|
+
exports: string[]
|
|
94
|
+
errors: string[]
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Simulated scanner implementations (mirrors autodocs internal behavior)
|
|
98
|
+
const LANGUAGE_MAP: Record<string, string> = {
|
|
99
|
+
'.ts': 'typescript',
|
|
100
|
+
'.tsx': 'typescript',
|
|
101
|
+
'.js': 'javascript',
|
|
102
|
+
'.py': 'python',
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function detectLanguage(filePath: string): string {
|
|
106
|
+
const ext = filePath.slice(filePath.lastIndexOf('.'))
|
|
107
|
+
return LANGUAGE_MAP[ext] ?? 'unknown'
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Simulated scanFile — mirrors the real function's behavior
|
|
111
|
+
async function scanFile(filePath: string): Promise<ScanResult> {
|
|
112
|
+
const language = detectLanguage(filePath)
|
|
113
|
+
|
|
114
|
+
if (language === 'unknown') {
|
|
115
|
+
// Unsupported file type: return a safe default (no throw)
|
|
116
|
+
return {
|
|
117
|
+
filePath,
|
|
118
|
+
language: 'unknown',
|
|
119
|
+
functions: [],
|
|
120
|
+
classes: [],
|
|
121
|
+
exports: [],
|
|
122
|
+
errors: [`No scanner available for file: ${filePath}`],
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Simulate parsed output for a TypeScript file
|
|
127
|
+
if (language === 'typescript') {
|
|
128
|
+
return {
|
|
129
|
+
filePath,
|
|
130
|
+
language: 'typescript',
|
|
131
|
+
functions: [
|
|
132
|
+
{
|
|
133
|
+
name: 'getUserById',
|
|
134
|
+
signature: 'async function getUserById(id: string): Promise<User>',
|
|
135
|
+
docstring: 'Fetch a user record by their unique ID.',
|
|
136
|
+
lineStart: 12,
|
|
137
|
+
lineEnd: 24,
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: 'formatUserName',
|
|
141
|
+
signature: 'function formatUserName(user: User): string',
|
|
142
|
+
lineStart: 26,
|
|
143
|
+
lineEnd: 31,
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
classes: [
|
|
147
|
+
{
|
|
148
|
+
name: 'UserService',
|
|
149
|
+
methods: [
|
|
150
|
+
{
|
|
151
|
+
name: 'create',
|
|
152
|
+
signature: 'async create(data: CreateUserDto): Promise<User>',
|
|
153
|
+
lineStart: 45,
|
|
154
|
+
lineEnd: 58,
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
lineStart: 40,
|
|
158
|
+
lineEnd: 80,
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
exports: ['getUserById', 'formatUserName', 'UserService'],
|
|
162
|
+
errors: [],
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Fallback for other supported languages
|
|
167
|
+
return {
|
|
168
|
+
filePath,
|
|
169
|
+
language,
|
|
170
|
+
functions: [],
|
|
171
|
+
classes: [],
|
|
172
|
+
exports: [],
|
|
173
|
+
errors: [],
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// --- Usage ---
|
|
178
|
+
async function main() {
|
|
179
|
+
const targetFile = process.env.SCAN_TARGET || './src/users/userService.ts'
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
console.log(`Scanning: ${targetFile}\n`)
|
|
183
|
+
const result = await scanFile(targetFile)
|
|
184
|
+
|
|
185
|
+
console.log(`Language: ${result.language}`)
|
|
186
|
+
console.log(`Functions: ${result.functions.length}`)
|
|
187
|
+
console.log(`Classes: ${result.classes.length}`)
|
|
188
|
+
console.log(`Exports: ${result.exports.join(', ')}`)
|
|
189
|
+
|
|
190
|
+
if (result.errors.length > 0) {
|
|
191
|
+
console.warn('Scan warnings:', result.errors)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
console.log('\nFull result:')
|
|
195
|
+
console.log(JSON.stringify(result, null, 2))
|
|
196
|
+
|
|
197
|
+
// Expected output:
|
|
198
|
+
// Language: typescript
|
|
199
|
+
// Functions: 2
|
|
200
|
+
// Classes: 1
|
|
201
|
+
// Exports: getUserById, formatUserName, UserService
|
|
202
|
+
} catch (error) {
|
|
203
|
+
// scanFile itself won't throw for unsupported files,
|
|
204
|
+
// but may throw on filesystem errors (file not found, permission denied)
|
|
205
|
+
console.error('Scan failed unexpectedly:', error)
|
|
206
|
+
process.exit(1)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
main()
|
|
211
|
+
```
|
|
212
|
+
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
## Classes
|
|
2
|
+
|
|
3
|
+
### `GoScanner`
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
class GoScanner implements Scanner
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Use this to scan Go source files and extract API elements — functions, methods, structs, and interfaces — for automated documentation generation pipelines.
|
|
10
|
+
|
|
11
|
+
`GoScanner` implements the `Scanner` interface and targets `.go` files, automatically skipping test files (`_test.go`).
|
|
12
|
+
|
|
13
|
+
## Methods
|
|
14
|
+
|
|
15
|
+
### `canHandle(filePath: string): boolean`
|
|
16
|
+
Returns `true` if the file path ends in `.go` and is not a test file. Use this to check compatibility before scanning.
|
|
17
|
+
|
|
18
|
+
### `scanFile(filePath: string): Promise<ScanResult>`
|
|
19
|
+
Reads and parses a Go source file, returning all discovered API elements.
|
|
20
|
+
|
|
21
|
+
| Name | Type | Required | Description |
|
|
22
|
+
|------|------|----------|-------------|
|
|
23
|
+
| `filePath` | `string` | ✅ | Absolute or relative path to the `.go` source file to scan |
|
|
24
|
+
|
|
25
|
+
#### Returns
|
|
26
|
+
|
|
27
|
+
`scanFile` returns a `Promise<ScanResult>` containing:
|
|
28
|
+
|
|
29
|
+
| Field | Type | Description |
|
|
30
|
+
|-------|------|-------------|
|
|
31
|
+
| `elements` | `APIElement[]` | All extracted functions, methods, types, and interfaces |
|
|
32
|
+
| `filePath` | `string` | The path of the scanned file |
|
|
33
|
+
| `language` | `string` | Always `"go"` for this scanner |
|
|
34
|
+
|
|
35
|
+
Each `APIElement` includes:
|
|
36
|
+
|
|
37
|
+
| Field | Type | Description |
|
|
38
|
+
|-------|------|-------------|
|
|
39
|
+
| `name` | `string` | Identifier name (e.g. `"NewServer"`) |
|
|
40
|
+
| `kind` | `string` | One of `"function"`, `"method"`, `"type"`, `"interface"` |
|
|
41
|
+
| `signature` | `string` | Full Go signature string |
|
|
42
|
+
| `parameters` | `Parameter[]` | Parsed parameter list |
|
|
43
|
+
| `docstring` | `string \| undefined` | Leading comment block, if present |
|
|
44
|
+
|
|
45
|
+
## Notes
|
|
46
|
+
- Test files (`*_test.go`) are **automatically excluded** — `canHandle` returns `false` for them
|
|
47
|
+
- `languages` property is `['go']`, used by scanner registries to route files to the correct handler
|
|
48
|
+
- Throws if the file cannot be read (e.g. missing file, permission error)
|
|
49
|
+
|
|
50
|
+
### Methods
|
|
51
|
+
|
|
52
|
+
#### `canHandle`
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
canHandle(filePath: string): boolean
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Use this to check whether a Go source file should be processed by the `GoScanner` — it returns `true` for `.go` files that are **not** test files (`_test.go`).
|
|
59
|
+
|
|
60
|
+
This is useful when routing files through a scanner pipeline, letting you skip unsupported or test files before attempting a full scan.
|
|
61
|
+
|
|
62
|
+
### Parameters
|
|
63
|
+
|
|
64
|
+
| Name | Type | Required | Description |
|
|
65
|
+
|------|------|----------|-------------|
|
|
66
|
+
| `filePath` | `string` | ✅ | Absolute or relative path to the file being evaluated |
|
|
67
|
+
|
|
68
|
+
#### Returns
|
|
69
|
+
|
|
70
|
+
| Value | Condition |
|
|
71
|
+
|-------|-----------|
|
|
72
|
+
| `true` | File ends in `.go` **and** does not contain `_test.go` |
|
|
73
|
+
| `false` | File is not a `.go` file, or is a Go test file (`_test.go`) |
|
|
74
|
+
|
|
75
|
+
### Notes
|
|
76
|
+
- Test files (e.g., `auth_test.go`, `parser_test.go`) are explicitly excluded and return `false`
|
|
77
|
+
- Only the file path string is checked — no filesystem access occurs
|
|
78
|
+
|
|
79
|
+
**Example:**
|
|
80
|
+
|
|
81
|
+
```typescript example.ts
|
|
82
|
+
// Inline implementation of GoScanner.canHandle for a self-contained example
|
|
83
|
+
class GoScanner {
|
|
84
|
+
languages = ['go']
|
|
85
|
+
|
|
86
|
+
canHandle(filePath: string): boolean {
|
|
87
|
+
return /\.go$/.test(filePath) && !filePath.includes('_test.go')
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const scanner = new GoScanner()
|
|
92
|
+
|
|
93
|
+
const testCases: Array<{ path: string; expected: boolean; label: string }> = [
|
|
94
|
+
{ path: 'internal/auth/handler.go', expected: true, label: 'standard Go source file' },
|
|
95
|
+
{ path: 'internal/auth/handler_test.go', expected: false, label: 'Go test file (excluded)' },
|
|
96
|
+
{ path: 'cmd/main.go', expected: true, label: 'main package file' },
|
|
97
|
+
{ path: 'src/utils/parser.ts', expected: false, label: 'TypeScript file (wrong ext)' },
|
|
98
|
+
{ path: 'README.md', expected: false, label: 'markdown file' },
|
|
99
|
+
{ path: 'pkg/models/user_test.go', expected: false, label: 'nested test file (excluded)' },
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
console.log('GoScanner.canHandle() results:\n')
|
|
104
|
+
|
|
105
|
+
for (const { path, expected, label } of testCases) {
|
|
106
|
+
const result = scanner.canHandle(path)
|
|
107
|
+
const status = result === expected ? '✅' : '❌'
|
|
108
|
+
console.log(`${status} ${label}`)
|
|
109
|
+
console.log(` Path: ${path}`)
|
|
110
|
+
console.log(` Returns: ${result}\n`)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Typical use in a file-routing pipeline
|
|
114
|
+
const filesToProcess = [
|
|
115
|
+
'pkg/api/routes.go',
|
|
116
|
+
'pkg/api/routes_test.go',
|
|
117
|
+
'pkg/api/middleware.go',
|
|
118
|
+
'docs/overview.md',
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
const scannable = filesToProcess.filter(f => scanner.canHandle(f))
|
|
122
|
+
console.log('Files queued for scanning:', scannable)
|
|
123
|
+
// Output: [ 'pkg/api/routes.go', 'pkg/api/middleware.go' ]
|
|
124
|
+
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error('Unexpected error during canHandle check:', error)
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### `scanFile`
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
async scanFile(filePath: string): Promise<ScanResult>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Use this to extract API elements from a Go source file, returning all discovered functions, types, and parameters in a structured result.
|
|
137
|
+
|
|
138
|
+
`scanFile` reads and parses a `.go` file (excluding test files), identifying exported API elements and collecting any parse errors encountered during scanning.
|
|
139
|
+
|
|
140
|
+
> **Note:** Only handles non-test Go files (`.go` extension, not `_test.go`). Use `canHandle(filePath)` to verify compatibility before calling.
|
|
141
|
+
|
|
142
|
+
#### Parameters
|
|
143
|
+
|
|
144
|
+
| Name | Type | Required | Description |
|
|
145
|
+
|------|------|----------|-------------|
|
|
146
|
+
| `filePath` | `string` | ✅ | Absolute or relative path to the `.go` source file to scan |
|
|
147
|
+
|
|
148
|
+
#### Returns
|
|
149
|
+
|
|
150
|
+
Returns a `Promise<ScanResult>` that resolves to:
|
|
151
|
+
|
|
152
|
+
| Field | Type | Description |
|
|
153
|
+
|-------|------|-------------|
|
|
154
|
+
| `elements` | `APIElement[]` | All discovered API elements (functions, types, etc.) |
|
|
155
|
+
| `errors` | `string[]` | Non-fatal parse errors encountered during scanning |
|
|
156
|
+
| `filePath` | `string` | The original file path that was scanned |
|
|
157
|
+
|
|
158
|
+
**Throws** if the file cannot be read (e.g., file not found, permission denied).
|
|
159
|
+
|
|
160
|
+
**Example:**
|
|
161
|
+
|
|
162
|
+
```typescript example.ts
|
|
163
|
+
import { readFileSync, writeFileSync, unlinkSync } from 'fs'
|
|
164
|
+
import { tmpdir } from 'os'
|
|
165
|
+
import { join } from 'path'
|
|
166
|
+
|
|
167
|
+
// --- Inline types (mirrors the real library's types) ---
|
|
168
|
+
interface Parameter {
|
|
169
|
+
name: string
|
|
170
|
+
type: string
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
interface APIElement {
|
|
174
|
+
name: string
|
|
175
|
+
kind: 'function' | 'type' | 'method'
|
|
176
|
+
parameters: Parameter[]
|
|
177
|
+
returnType?: string
|
|
178
|
+
doc?: string
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
interface ScanResult {
|
|
182
|
+
filePath: string
|
|
183
|
+
elements: APIElement[]
|
|
184
|
+
errors: string[]
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// --- Self-contained GoScanner implementation ---
|
|
188
|
+
class GoScanner {
|
|
189
|
+
canHandle(filePath: string): boolean {
|
|
190
|
+
return /\.go$/.test(filePath) && !filePath.includes('_test.go')
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async scanFile(filePath: string): Promise<ScanResult> {
|
|
194
|
+
const source = readFileSync(filePath, 'utf-8')
|
|
195
|
+
const elements: APIElement[] = []
|
|
196
|
+
const errors: string[] = []
|
|
197
|
+
const lines = source.split('\n')
|
|
198
|
+
|
|
199
|
+
// Match exported Go functions: func FuncName(params) returnType
|
|
200
|
+
const funcRegex = /^func\s+([A-Z][a-zA-Z0-9]*)\s*\(([^)]*)\)\s*([^\s{]*)/
|
|
201
|
+
// Match exported types: type TypeName struct/interface
|
|
202
|
+
const typeRegex = /^type\s+([A-Z][a-zA-Z0-9]*)\s+(struct|interface)/
|
|
203
|
+
|
|
204
|
+
for (let i = 0; i < lines.length; i++) {
|
|
205
|
+
const line = lines[i].trim()
|
|
206
|
+
|
|
207
|
+
const funcMatch = funcRegex.exec(line)
|
|
208
|
+
if (funcMatch) {
|
|
209
|
+
const [, name, rawParams, returnType] = funcMatch
|
|
210
|
+
const parameters: Parameter[] = rawParams
|
|
211
|
+
.split(',')
|
|
212
|
+
.map(p => p.trim())
|
|
213
|
+
.filter(Boolean)
|
|
214
|
+
.map(p => {
|
|
215
|
+
const parts = p.split(/\s+/)
|
|
216
|
+
return parts.length >= 2
|
|
217
|
+
? { name: parts[0], type: parts[1] }
|
|
218
|
+
: { name: p, type: 'unknown' }
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
elements.push({ name, kind: 'function', parameters, returnType: returnType || 'void' })
|
|
222
|
+
continue
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const typeMatch = typeRegex.exec(line)
|
|
226
|
+
if (typeMatch) {
|
|
227
|
+
const [, name] = typeMatch
|
|
228
|
+
elements.push({ name, kind: 'type', parameters: [] })
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return { filePath, elements, errors }
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// --- Example usage ---
|
|
237
|
+
const sampleGoSource = `
|
|
238
|
+
package api
|
|
239
|
+
|
|
240
|
+
// UserService handles user operations.
|
|
241
|
+
type UserService struct{}
|
|
242
|
+
|
|
243
|
+
// GetUser retrieves a user by ID.
|
|
244
|
+
func GetUser(id string, includeDeleted bool) error {
|
|
245
|
+
return nil
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// CreateUser adds a new user to the system.
|
|
249
|
+
func CreateUser(name string, age int) string {
|
|
250
|
+
return ""
|
|
251
|
+
}
|
|
252
|
+
`
|
|
253
|
+
|
|
254
|
+
async function main() {
|
|
255
|
+
// Write a temporary .go file to scan
|
|
256
|
+
const tmpFile = join(tmpdir(), 'example_service.go')
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
writeFileSync(tmpFile, sampleGoSource, 'utf-8')
|
|
260
|
+
|
|
261
|
+
const scanner = new GoScanner()
|
|
262
|
+
|
|
263
|
+
// Verify the file is compatible before scanning
|
|
264
|
+
if (!scanner.canHandle(tmpFile)) {
|
|
265
|
+
throw new Error(`File is not a scannable Go source: ${tmpFile}`)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const result = await scanner.scanFile(tmpFile)
|
|
269
|
+
|
|
270
|
+
console.log('Scanned file:', result.filePath)
|
|
271
|
+
console.log(`Found ${result.elements.length} API elements:\n`)
|
|
272
|
+
|
|
273
|
+
for (const el of result.elements) {
|
|
274
|
+
if (el.kind === 'function') {
|
|
275
|
+
const params = el.parameters.map(p => `${p.name} ${p.type}`).join(', ')
|
|
276
|
+
console.log(` [${el.kind}] ${el.name}(${params}) → ${el.returnType}`)
|
|
277
|
+
} else {
|
|
278
|
+
console.log(` [${el.kind}] ${el.name}`)
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (result.errors.length > 0) {
|
|
283
|
+
console.warn('\nParse errors:', result.errors)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Expected output:
|
|
287
|
+
// Scanned file: /tmp/example_service.go
|
|
288
|
+
// Found 3 API elements:
|
|
289
|
+
// [type] UserService
|
|
290
|
+
// [function] GetUser(id string, includeDeleted bool) → error
|
|
291
|
+
// [function] CreateUser(name string, age int) → string
|
|
292
|
+
|
|
293
|
+
} catch (error) {
|
|
294
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
295
|
+
console.error('File not found - check the path and try again')
|
|
296
|
+
} else {
|
|
297
|
+
console.error('Scan failed:', error)
|
|
298
|
+
}
|
|
299
|
+
} finally {
|
|
300
|
+
// Clean up temp file
|
|
301
|
+
try { unlinkSync(tmpFile) } catch {}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
main()
|
|
306
|
+
```
|
|
307
|
+
|