@specmind/core
v0.5.1
Published
Core code analysis and architecture generation for SpecMind using tree-sitter
Maintainers
Readme
@specmind/core
Core code analysis and architecture generation library for SpecMind using tree-sitter.
Overview
@specmind/core provides pure logic for analyzing codebases and extracting architectural information. It uses tree-sitter for robust, language-agnostic code parsing and analysis.
Key Features:
- Multi-language support: TypeScript, JavaScript, Python (Go, Rust planned)
- Tree-sitter powered: Fast, incremental, error-tolerant parsing
- Pure logic: No CLI or UI dependencies - just analysis functions
- Type-safe: Full TypeScript with Zod schemas for runtime validation
- Lightweight: Minimal dependencies, focused on core functionality
Installation
pnpm add @specmind/core
# or
npm install @specmind/coreQuick Start
import { analyzeFileContent } from '@specmind/core'
const code = `
export class UserService {
async getUser(id: string): Promise<User> {
return await this.db.find(id)
}
}
`
const analysis = analyzeFileContent('user-service.ts', code, 'typescript')
console.log(analysis.classes)
// [
// {
// name: 'UserService',
// methods: [{ name: 'getUser', parameters: [...], ...}],
// ...
// }
// ]Architecture
Design Principles
- Tree-sitter first: All code parsing uses tree-sitter (per CONSTITUTION.md Section 2.3)
- Pure logic: No side effects, file I/O, or UI concerns
- Type-safe: Zod schemas + TypeScript for runtime and compile-time safety
- Composable: Small, focused functions that can be combined
Package Structure
@specmind/core/
├── analyzer/ # Code analysis logic
│ ├── parser.ts # Tree-sitter parser wrapper
│ ├── language-config.ts # Language-specific configurations
│ ├── file-analyzer.ts # Main file analysis orchestrator
│ ├── dependency-graph.ts # Dependency graph builder
│ └── extractors/ # Element extractors
│ ├── functions.ts # Extract functions
│ ├── classes.ts # Extract classes/interfaces
│ └── imports.ts # Extract imports/exports
└── types/ # Type definitions and Zod schemas
└── index.tsAPI Reference
Core Functions
analyzeFile(filePath: string): Promise<FileAnalysis | null>
Analyze a file from the filesystem.
import { analyzeFile } from '@specmind/core'
const analysis = await analyzeFile('./src/services/user-service.ts')
if (analysis) {
console.log(`Found ${analysis.functions.length} functions`)
console.log(`Found ${analysis.classes.length} classes`)
}Returns:
FileAnalysisobject containing functions, classes, imports, exportsnullif file type is not supported
analyzeFileContent(filePath: string, content: string, language: SupportedLanguage): FileAnalysis
Analyze code from a string (useful for testing or in-memory analysis).
import { analyzeFileContent } from '@specmind/core'
const code = `export function add(a: number, b: number): number { return a + b }`
const analysis = analyzeFileContent('math.ts', code, 'typescript')
console.log(analysis.functions[0])
// {
// name: 'add',
// parameters: [{ name: 'a', type: 'number' }, { name: 'b', type: 'number' }],
// returnType: 'number',
// isExported: true,
// ...
// }buildDependencyGraph(files: FileAnalysis[]): ModuleDependency[]
Build a module dependency graph from analyzed files.
import { analyzeFile, buildDependencyGraph } from '@specmind/core'
const files = await Promise.all([
analyzeFile('./src/index.ts'),
analyzeFile('./src/utils.ts'),
]).then(results => results.filter(Boolean))
const dependencies = buildDependencyGraph(files)
console.log(dependencies)
// [
// {
// source: './src/index.ts',
// target: './utils',
// importedNames: ['helper', 'format']
// }
// ]findEntryPoints(files: FileAnalysis[], dependencies: ModuleDependency[]): string[]
Find entry point files (files that aren't imported by anyone).
import { findEntryPoints } from '@specmind/core'
const entryPoints = findEntryPoints(files, dependencies)
console.log(entryPoints)
// ['./src/index.ts', './src/cli.ts']Language Utilities
detectLanguage(filePath: string): SupportedLanguage | null
Detect language from file extension.
import { detectLanguage } from '@specmind/core'
console.log(detectLanguage('app.ts')) // 'typescript'
console.log(detectLanguage('utils.js')) // 'javascript'
console.log(detectLanguage('main.py')) // 'python'
console.log(detectLanguage('styles.css')) // nullgetLanguageConfig(language: SupportedLanguage): LanguageConfig
Get configuration for a specific language.
import { getLanguageConfig } from '@specmind/core'
const config = getLanguageConfig('typescript')
console.log(config.functionNodeTypes)
// ['function_declaration', 'arrow_function', 'method_definition', ...]Individual Extractors (Advanced)
For fine-grained control, you can use individual extractors:
import { parseCode, extractFunctions, extractClasses } from '@specmind/core'
const tree = parseCode(code, 'typescript')
const functions = extractFunctions(tree, 'file.ts', 'typescript')
const classes = extractClasses(tree, 'file.ts', 'typescript')Type Definitions
All types are exported with both TypeScript types and Zod schemas for runtime validation.
Core Types
import type {
FileAnalysis,
FunctionDefinition,
ClassDefinition,
ImportStatement,
ExportStatement,
ModuleDependency,
} from '@specmind/core'Zod Schemas
import {
FileAnalysisSchema,
FunctionDefinitionSchema,
ClassDefinitionSchema,
} from '@specmind/core'
// Runtime validation
const result = FileAnalysisSchema.safeParse(data)
if (result.success) {
console.log(result.data)
}What We Extract
Functions
{
name: string
qualifiedName: string // e.g., "MyClass.myMethod"
parameters: Parameter[]
returnType?: string
isExported: boolean
isAsync: boolean
location: SourceLocation
docComment?: string // JSDoc comment if present
}Classes / Interfaces
{
name: string
qualifiedName: string
kind: 'class' | 'interface' | 'type' | 'enum'
isExported: boolean
isAbstract: boolean
extendsFrom: string[] // Base classes
implements: string[] // Implemented interfaces
methods: MethodDefinition[]
properties: PropertyDefinition[]
location: SourceLocation
docComment?: string
}Imports
{
source: string // Module path: './utils', 'react'
imports: Array<{
name: string // Imported name
alias?: string // Alias if renamed
isDefault: boolean
isNamespace: boolean // import * as name
}>
location: SourceLocation
}Exports
{
name: string
isDefault: boolean
source?: string // Re-export source if applicable
location: SourceLocation
}Supported Languages
| Language | Status | File Extensions | Features |
|------------|--------|-----------------|----------|
| TypeScript | ✅ Full | .ts, .tsx | Functions, classes, interfaces, types, enums, imports, exports, generics, decorators |
| JavaScript | ✅ Full | .js, .jsx | Functions, classes, imports, exports, generators, async/await, ES6+ |
| Python | ✅ Full | .py, .pyi | Functions, classes, imports, type hints, async/await, decorators |
| Go | 🚧 Planned | .go | Coming soon |
| Rust | 🚧 Planned | .rs | Coming soon |
Implementation Details
Tree-Sitter Approach
We use tree-sitter queries (pattern matching for ASTs) instead of manual traversal:
// Example query for TypeScript functions
const functionQuery = `
(function_declaration
name: (identifier) @name
parameters: (formal_parameters) @params
return_type: (type_annotation)? @return_type) @function
`This approach:
- Fast: Optimized pattern matching
- Robust: Handles syntax errors gracefully
- Maintainable: Declarative queries instead of imperative code
- Consistent: Same pattern across all languages
What We DON'T Do
Unlike full static analysis tools, we focus on high-level architecture:
- ❌ No deep type inference (we use declared types)
- ❌ No control flow analysis (if/loops/branches)
- ❌ No variable tracking within functions
- ❌ No runtime behavior analysis
We extract just enough for generating clean architecture diagrams and documentation.
Examples
Example 1: Analyze a TypeScript Module
import { analyzeFileContent } from '@specmind/core'
const code = `
import { Database } from './database'
export class UserRepository {
constructor(private db: Database) {}
async findById(id: string): Promise<User | null> {
return await this.db.query('SELECT * FROM users WHERE id = ?', [id])
}
async save(user: User): Promise<void> {
await this.db.insert('users', user)
}
}
`
const analysis = analyzeFileContent('user-repository.ts', code, 'typescript')
console.log('Imports:', analysis.imports)
// [{ source: './database', imports: [{ name: 'Database', isDefault: false }] }]
console.log('Classes:', analysis.classes.map(c => c.name))
// ['UserRepository']
console.log('Methods:', analysis.classes[0].methods.map(m => m.name))
// ['constructor', 'findById', 'save']Example 2: Build Dependency Graph
import { analyzeFileContent, buildDependencyGraph } from '@specmind/core'
const files = [
analyzeFileContent('index.ts', `import { UserService } from './services'`, 'typescript'),
analyzeFileContent('services.ts', `import { Database } from './db'`, 'typescript'),
analyzeFileContent('db.ts', `export class Database {}`, 'typescript'),
]
const deps = buildDependencyGraph(files)
console.log(deps)
// [
// { source: 'index.ts', target: './services', importedNames: ['UserService'] },
// { source: 'services.ts', target: './db', importedNames: ['Database'] }
// ]Example 3: Find All Exported Functions
const analysis = await analyzeFile('./src/utils.ts')
const exportedFunctions = analysis.functions.filter(f => f.isExported)
exportedFunctions.forEach(fn => {
console.log(`${fn.name}(${fn.parameters.map(p => `${p.name}: ${p.type}`).join(', ')}): ${fn.returnType}`)
})Example 4: Analyze Python Code
import { analyzeFileContent } from '@specmind/core'
const pythonCode = `
from typing import List, Optional
class UserService:
def __init__(self, db_connection: str):
self.db = db_connection
async def get_users(self, limit: int = 10) -> List[dict]:
return await self.db.query("SELECT * FROM users LIMIT ?", [limit])
def _validate_user(self, user: dict) -> bool:
return "id" in user and "name" in user
`
const analysis = analyzeFileContent('user_service.py', pythonCode, 'python')
console.log('Classes:', analysis.classes.map(c => c.name))
// ['UserService']
console.log('Methods:', analysis.classes[0].methods.map(m => ({
name: m.name,
visibility: m.visibility,
isAsync: m.isAsync
})))
// [
// { name: '__init__', visibility: 'public', isAsync: false },
// { name: 'get_users', visibility: 'public', isAsync: true },
// { name: '_validate_user', visibility: 'private', isAsync: false }
// ]
console.log('Imports:', analysis.imports)
// [{ source: 'typing', imports: [{ name: 'List' }, { name: 'Optional' }] }]Development
Build
pnpm buildTest
pnpm testLint
pnpm lintIntegration with SpecMind
This package is the foundation for:
@specmind/cli: Uses@specmind/coreto analyze codebases and generate .sm files- Future: Architecture Generator: Convert analysis results to Mermaid diagrams
- Future: Architecture Differ: Compare architectures across versions
Design Philosophy
Per CONSTITUTION.md:
- Tree-sitter for ALL parsing (Section 2.3)
- Pure logic - NO CLI/UI dependencies (Section 3.2)
- Type-safe everything (Section 6.3)
- Multi-language support (Section 6.1)
This package provides clean, typed APIs that can be used by CLI tools, VS Code extensions, or any other interface.
Contributing
See the main CONSTITUTION.md for development guidelines.
Adding a New Language
- Add language to
SupportedLanguagetype intypes/index.ts - Install tree-sitter grammar:
pnpm add tree-sitter-{language} - Create language config in
analyzer/language-config.ts - Add parser support in
analyzer/parser.ts - Test with example files
License
MIT
Related Packages
- @specmind/format: .sm file format parser and validator
- @specmind/cli: CLI tool using this package (coming soon)
- specmind-vscode: VS Code extension for .sm files
