Go
Classes
GoScanner
class GoScanner implements Scanner
Use GoScanner to extract functions, methods, structs, and interfaces from Go source files so skrypt can generate documentation for your Go codebase.
Reach for GoScanner when you're building a custom documentation pipeline that needs to parse .go files directly — for example, integrating skrypt's scanning step into your own tooling or extending it with post-processing logic. It's the Go-specific implementation of the Scanner interface that skrypt generate uses under the hood.
GoScanner automatically skips test files (anything ending in _test.go) and reads each file's source to extract top-level API elements along with their signatures, parameters, and surrounding source context.
Methods
| Name | Signature | Description |
|---|---|---|
canHandle | (filePath: string) => boolean | Returns true if the file is a .go source file that isn't a test file. Use this to check eligibility before calling scanFile. |
scanFile | (filePath: string) => Promise<ScanResult> | Parses the file at the given path and returns all discovered API elements. |
scanFile Parameters
| Name | Type | Required | Description |
|---|---|---|---|
filePath | string | Yes | Absolute or relative path to the .go file to scan. Must be a file canHandle returns true for, otherwise results are undefined. |
Returns
scanFile returns a Promise<ScanResult> — an object containing an elements array of APIElement objects. Each element includes the name, kind (function, method, type, or interface), signature, parameters, and the surrounding source snippet. Pass the elements array to skrypt's doc generation step or your own AI prompt to produce documentation.
Heads up
GoScannerreads files synchronously under the hood (readFileSync), so scanning very large files will block the event loop. For bulk scanning, process files sequentially rather than withPromise.all.- Only non-test
.gofiles are processed. IfcanHandlereturnsfalse, callingscanFileon that path may throw or return empty results.
Example:
import { readFileSync } from 'fs'
import { tmpdir } from 'os'
import { join } from 'path'
import { writeFileSync } from 'fs'
// Inline the Scanner interface so we don't import from autodocs
interface Parameter {
name: string
type: string
required: boolean
description: string
}
interface APIElement {
name: string
kind: 'function' | 'method' | 'type' | 'interface'
signature: string
parameters: Parameter[]
sourceContext: string
lineNumber: number
}
interface ScanResult {
elements: APIElement[]
}
interface Scanner {
languages: string[]
canHandle(filePath: string): boolean
scanFile(filePath: string): Promise<ScanResult>
}
// Minimal GoScanner implementation matching the real class's behavior
class GoScanner implements Scanner {
languages = ['go']
canHandle(filePath: string): boolean {
return /\.go$/.test(filePath) && !filePath.includes('_test.go')
}
async scanFile(filePath: string): Promise<ScanResult> {
const source = readFileSync(filePath, 'utf-8')
const elements: APIElement[] = []
const lines = source.split('\n')
// Extract top-level functions
lines.forEach((line, i) => {
const fnMatch = line.match(/^func\s+(\w+)\s*\(([^)]*)\)/)
if (fnMatch) {
elements.push({
name: fnMatch[1],
kind: 'function',
signature: line.trim(),
parameters: fnMatch[2]
? fnMatch[2].split(',').map(p => {
const [name, type] = p.trim().split(/\s+/)
return { name: name || '', type: type || '', required: true, description: '' }
})
: [],
sourceContext: lines.slice(Math.max(0, i - 1), i + 5).join('\n'),
lineNumber: i + 1,
})
}
})
return { elements }
}
}
// Write a sample Go file to scan
const sampleGoFile = join(tmpdir(), 'payments.go')
writeFileSync(sampleGoFile, `
package payments
// CreateCharge creates a new charge for the given amount.
func CreateCharge(customerID string, amount int) (string, error) {
// implementation
return "ch_3Nk8Lx2eZvKYlo2C0abc1234", nil
}
// RefundCharge reverses a previously created charge.
func RefundCharge(chargeID string) error {
return nil
}
`.trim())
async function main() {
const scanner = new GoScanner()
// Check the file is eligible before scanning
if (!scanner.canHandle(sampleGoFile)) {
console.error('File is not a scannable Go source file')
process.exit(1)
}
try {
const result = await scanner.scanFile(sampleGoFile)
console.log(`Discovered ${result.elements.length} API elements:\n`)
for (const el of result.elements) {
console.log(`[${el.kind}] ${el.name}`)
console.log(` Signature : ${el.signature}`)
console.log(` Line : ${el.lineNumber}`)
console.log(` Params : ${el.parameters.map(p => `${p.name} ${p.type}`).join(', ') || 'none'}`)
console.log()
}
} catch (err) {
console.error('Scan failed:', err)
}
}
main()
// Expected output:
// Discovered 2 API elements:
//
// [function] CreateCharge
// Signature : func CreateCharge(customerID string, amount int) (string, error) {
// Line : 3
// Params : customerID string, amount int
//
// [function] RefundCharge
// Signature : func RefundCharge(chargeID string) error {
// Line : 8
// Params : chargeID string
Methods
canHandle
canHandle(filePath: string): boolean
Use canHandle to determine whether a GoScanner instance should process a given file before attempting to scan it.
Call this before passing a file path to scanFile — it acts as a gate that confirms the file is a Go source file and not a test file. This is the standard pattern when building a multi-language scanning pipeline where each scanner only processes the files it understands.
Returns true only for files ending in .go that don't include _test.go in their path. Test files are intentionally excluded because skrypt targets public API surfaces, not test helpers.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
filePath | string | Yes | Absolute or relative path to the file being evaluated. Paths containing _test.go will always return false, even if they end in .go. |
Returns
A boolean — true if the file is a non-test Go source file that GoScanner can process. Pass the file to scanFile only when this returns true; otherwise skip it or route it to a different scanner.
Heads up
_test.gofiles are rejected regardless of where_test.goappears in the path (e.g.internal/_test.go_helpers/util.gowould also be excluded). Keep this in mind if your project has unconventional directory naming.
Example:
// Inline types to keep this self-contained
interface Scanner {
languages: string[];
canHandle(filePath: string): boolean;
}
// Minimal GoScanner implementation matching the real behavior
class GoScanner implements Scanner {
languages = ['go'];
canHandle(filePath: string): boolean {
return /\.go$/.test(filePath) && !filePath.includes('_test.go');
}
}
const scanner = new GoScanner();
const filePaths = [
'/workspace/myproject/internal/auth/handler.go',
'/workspace/myproject/internal/auth/handler_test.go',
'/workspace/myproject/cmd/server/main.go',
'/workspace/myproject/README.md',
'/workspace/myproject/src/index.ts',
];
for (const filePath of filePaths) {
const shouldScan = scanner.canHandle(filePath);
console.log(`${shouldScan ? '✓' : '✗'} ${filePath}`);
}
// Expected output:
// ✓ /workspace/myproject/internal/auth/handler.go
// ✗ /workspace/myproject/internal/auth/handler_test.go
// ✓ /workspace/myproject/cmd/server/main.go
// ✗ /workspace/myproject/README.md
// ✗ /workspace/myproject/src/index.ts
scanFile
async scanFile(filePath: string): Promise<ScanResult>
Use scanFile to extract all exported API elements from a Go source file and feed them into skrypt's documentation pipeline.
Reach for this when you're building a custom documentation workflow and need to programmatically scan individual .go files — for example, scanning only files that changed in a pull request rather than an entire directory.
GoScanner reads the file from disk, parses its exported functions, types, and methods, and returns structured APIElement objects that skrypt's generator uses to produce MDX documentation. It skips test files (_test.go) automatically — use canHandle() first to confirm a file is eligible before calling scanFile.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
filePath | string | Yes | Absolute or relative path to the .go source file to scan. Must point to a non-test Go file — test files (_test.go) will produce an empty result. |
Returns
Returns a Promise<ScanResult> containing the extracted APIElement[] array and any parse errors[] encountered. Pass result.elements directly to your doc generator or merge it with results from other scanners before generating output.
Heads up
scanFiledoes not check whether the file is a valid Go file before reading — callcanHandle(filePath)first to guard against accidentally passing test files or non-Go paths.- Errors during parsing are collected into
result.errorsrather than thrown, so always check that array even when the promise resolves successfully.
Example:
import { readFileSync } from 'fs'
import { join } from 'path'
// Inline types matching skrypt's internal shape
interface Parameter {
name: string
type: string
required: boolean
description: string
}
interface APIElement {
name: string
kind: 'function' | 'type' | 'method' | 'constant'
signature: string
parameters: Parameter[]
returns: string
description: string
filePath: string
lineNumber: number
sourceContext: string
}
interface ScanResult {
elements: APIElement[]
errors: string[]
}
// Minimal GoScanner implementation for demonstration
class GoScanner {
canHandle(filePath: string): boolean {
return /\.go$/.test(filePath) && !filePath.includes('_test.go')
}
async scanFile(filePath: string): Promise<ScanResult> {
const elements: APIElement[] = []
const errors: string[] = []
try {
const source = readFileSync(filePath, 'utf-8')
const lines = source.split('\n')
// Detect exported top-level functions (simplified)
const funcRegex = /^func\s+([A-Z][a-zA-Z0-9]*)\s*\(([^)]*)\)\s*(.*)?\s*\{/
lines.forEach((line, index) => {
const match = funcRegex.exec(line)
if (match) {
elements.push({
name: match[1],
kind: 'function',
signature: line.trim(),
parameters: [],
returns: match[3]?.trim() ?? '',
description: '',
filePath,
lineNumber: index + 1,
sourceContext: lines.slice(Math.max(0, index - 1), index + 5).join('\n'),
})
}
})
} catch (err) {
errors.push(`Failed to read ${filePath}: ${(err as Error).message}`)
}
return { elements, errors }
}
}
// --- Usage ---
async function main() {
const scanner = new GoScanner()
// Simulate a .go file on disk for the example
const { writeFileSync, mkdirSync } = await import('fs')
mkdirSync('/tmp/skrypt-demo', { recursive: true })
const demoFile = '/tmp/skrypt-demo/payments.go'
writeFileSync(demoFile, `package payments
// CreateCharge creates a new charge against a customer.
func CreateCharge(customerID string, amount int) (string, error) {
return "", nil
}
// RefundCharge reverses a previously created charge.
func RefundCharge(chargeID string) error {
return nil
}
`)
if (!scanner.canHandle(demoFile)) {
console.error('File is not a scannable Go source file.')
process.exit(1)
}
try {
const result = await scanner.scanFile(demoFile)
if (result.errors.length > 0) {
console.warn('Parse warnings:', result.errors)
}
console.log(`Found ${result.elements.length} exported elements:\n`)
for (const el of result.elements) {
console.log(` [${el.kind}] ${el.name} — line ${el.lineNumber}`)
console.log(` Signature: ${el.signature}\n`)
}
// Expected output:
// Found 2 exported elements:
//
// [function] CreateCharge — line 4
// Signature: func CreateCharge(customerID string, amount int) (string, error) {
//
// [function] RefundCharge — line 9
// Signature: func RefundCharge(chargeID string) error {
} catch (err) {
console.error('Unexpected error during scan:', err)
}
}
main()