@sun-asterisk/sunlint
Version:
☀️ SunLint - Multi-language static analysis tool for code quality and security | Sun* Engineering Standards
693 lines (620 loc) • 40.7 kB
Markdown
# SunLint Architecture Documentation
## Table of Contents
1. [Overview](#overview)
2. [Folder Structure](#folder-structure)
3. [Core Components](#core-components)
4. [Execution Flow](#execution-flow)
5. [Engine Architecture](#engine-architecture)
6. [Rule System](#rule-system)
7. [Data Flow Diagrams](#data-flow-diagrams)
## Overview
SunLint là một static code analyzer đa ngôn ngữ, được thiết kế với kiến trúc plugin-based để dễ dàng mở rộng.
```
┌─────────────────────────────────────────────────────────────────┐
│ SunLint CLI │
│ "sunlint --security --input=src" │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Analysis Orchestrator │
│ - Route files to appropriate engines │
│ - Merge results from multiple engines │
│ - Handle batching and performance │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ ESLint Engine │ │Heuristic Engine│ │ OpenAI Engine │
│ (JS/TS only) │ │ (All languages)│ │ (AI-powered) │
└───────────────┘ └───────────────┘ └───────────────┘
```
## Folder Structure
```
sunlint/
├── cli.js # Entry point
│
├── core/ # Core modules
│ ├── cli-program.js # CLI definition (commander.js)
│ ├── cli-action-handler.js # Main action handler
│ ├── config-manager.js # Configuration management
│ ├── config-merger.js # Merge configs (CLI + file)
│ ├── config-validator.js # Validate config
│ ├── config-preset-resolver.js # Resolve presets
│ ├── config-source-loader.js # Load config files
│ ├── config-override-processor.js# Process overrides
│ │
│ ├── analysis-orchestrator.js # ⭐ Main orchestrator
│ ├── rule-selection-service.js # Select rules to run
│ ├── file-targeting-service.js # Find files to analyze
│ ├── performance-optimizer.js # Optimize analysis
│ ├── auto-performance-manager.js # Auto-tune performance
│ │
│ ├── semantic-engine.js # ts-morph Symbol Table
│ ├── semantic-rule-base.js # Base class for semantic rules
│ │
│ ├── output-service.js # Format & output results
│ ├── report-generator.js # Generate reports
│ ├── scoring-service.js # Calculate scores
│ ├── summary-report-service.js # Summary reports
│ ├── upload-service.js # Upload to API
│ ├── html-report-generator.js # HTML reports
│ ├── github-annotate-service.js # GitHub PR annotations
│ ├── github-step-summary-generator.js
│ │
│ ├── unified-rule-registry.js # Rule registry
│ ├── enhanced-rules-registry.js # Enhanced registry
│ ├── rule-mapping-service.js # Map rules to engines
│ │
│ ├── git-utils.js # Git operations
│ ├── dependency-checker.js # Check dependencies
│ ├── dependency-manager.js # Manage dependencies
│ ├── smart-installer.js # Auto-install deps
│ ├── plugin-manager.js # Plugin management
│ │
│ ├── adapters/
│ │ └── sunlint-rule-adapter.js # Adapt rules to engines
│ │
│ ├── interfaces/
│ │ ├── analysis-engine.interface.js # Engine interface
│ │ └── rule-plugin.interface.js # Rule interface
│ │
│ ├── ast-modules/
│ │ ├── index.js # AST module registry
│ │ ├── base-parser.js # Base parser class
│ │ └── parsers/
│ │ ├── javascript-parser.js
│ │ ├── typescript-parser.js
│ │ ├── eslint-js-parser.js
│ │ └── eslint-ts-parser.js
│ │
│ └── constants/
│ ├── index.js
│ ├── categories.js
│ ├── engines.js
│ ├── rules.js
│ └── defaults.js
│
├── engines/ # Analysis engines
│ ├── eslint-engine.js # ESLint-based analysis
│ ├── heuristic-engine.js # Pattern/regex + ts-morph
│ ├── openai-engine.js # AI-powered analysis
│ └── engine-factory.js # Engine factory
│
├── config/
│ ├── presets/ # Rule presets
│ │ ├── all.json
│ │ ├── quality.json
│ │ └── security.json
│ │
│ ├── engines/
│ │ └── engines.json # Engine configuration
│ │
│ ├── rules/ # Rule definitions
│ │
│ └── integrations/
│ └── eslint/ # ESLint configs
│
├── integrations/
│ └── eslint/
│ ├── plugin/
│ │ ├── index.js # ESLint plugin entry
│ │ └── rules/
│ │ ├── security/ # Security rules
│ │ ├── typescript/ # TS-specific rules
│ │ └── common/ # Common rules
│ └── configs/
│
├── custom-rules/ # Custom rule examples
│
├── test/
│ ├── unit/
│ ├── integration/
│ └── fixtures/
│
├── examples/
│
└── docs/
```
## Core Components
### 1. CLI Entry (`cli.js`)
```javascript
// Entry point - minimal bootstrapping
const program = createCliProgram();
program.action(async (options) => {
const actionHandler = new CliActionHandler(options);
await actionHandler.execute();
});
program.parse();
```
### 2. CLI Action Handler (`core/cli-action-handler.js`)
Orchestrates the entire analysis flow:
```javascript
class CliActionHandler {
async execute() {
// 1. Load configuration
const config = await this.loadConfiguration();
// 2. Validate input
this.validateInput(config);
// 3. Select rules to run
const rulesToRun = await this.ruleSelectionService.selectRules(config, this.options);
// 4. Apply file targeting
const targetingResult = await this.applyFileTargeting(config);
// 5. Run analysis
const results = await this.runModernAnalysis(rulesToRun, targetingResult.files, config);
// 6. Output results
await this.outputService.outputResults(results, this.options, metadata);
}
}
```
### 3. Analysis Orchestrator (`core/analysis-orchestrator.js`)
Routes rules to appropriate engines:
```javascript
class AnalysisOrchestrator {
async analyze(files, rules, options) {
// 1. Group rules by engine preference
const engineGroups = this.groupRulesByEngine(rules, config);
// 2. Run each engine
for (const [engineName, engineRules] of engineGroups) {
const engine = this.engines.get(engineName);
const result = await engine.analyze(files, engineRules, options);
results.push(result);
}
// 3. Merge results
return this.mergeEngineResults(results);
}
}
```
### 4. Semantic Engine (`core/semantic-engine.js`)
Provides ts-morph Symbol Table for advanced analysis:
```javascript
class SemanticEngine {
async initialize(projectPath, targetFiles) {
// Initialize ts-morph project
this.project = new Project({
compilerOptions: { ... },
skipFileDependencyResolution: true,
skipLoadingLibFiles: true,
});
// Load target files into Symbol Table
for (const file of targetFiles) {
this.project.addSourceFileAtPath(file);
}
}
// Provides cross-file analysis capabilities
getSymbolsInFile(filePath) { ... }
findReferences(symbol) { ... }
getTypeInfo(node) { ... }
}
```
## Execution Flow
### Complete Flow Diagram
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ USER INPUT │
│ $ sunlint --security --input=src --format=summary │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 1. CLI PROGRAM (cli-program.js) │
│ - Parse arguments with commander.js │
│ - Extract options: {security: true, input: 'src', format: 'summary'} │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 2. CLI ACTION HANDLER (cli-action-handler.js) │
│ - Main orchestration entry point │
└─────────────────────────────────────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Config │ │ Rule │ │ File │
│ Manager │ │ Selection │ │ Targeting │
│ │ │ Service │ │ Service │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Load config │ │ Load preset │ │ Find files │
│ files │ │ security.json│ │ in src/ │
│ Merge CLI │ │ 57 rules │ │ 500 files │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
└───────────────┼───────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 3. ANALYSIS ORCHESTRATOR (analysis-orchestrator.js) │
│ - Initialize engines │
│ - Group rules by engine │
│ - Batch rules for performance │
└─────────────────────────────────────────────────────────────────────────────┘
│
┌───────────────┴───────────────┐
▼ ▼
┌───────────────────────┐ ┌───────────────────────┐
│ ESLint Engine │ │ Heuristic Engine │
│ (eslint-engine.js) │ │ (heuristic-engine.js)│
│ │ │ │
│ Rules: S001, S002... │ │ Rules: S003, S004... │
│ (7 ESLint rules) │ │ (50 heuristic rules) │
└───────────────────────┘ └───────────────────────┘
│ │
▼ ▼
┌───────────────────────┐ ┌───────────────────────┐
│ ESLint Core │ │ Semantic Engine │
│ - Parse with ESLint │ │ (ts-morph) │
│ - Run custom rules │ │ - Symbol Table │
│ │ │ - AST analysis │
│ │ │ - Pattern matching │
└───────────────────────┘ └───────────────────────┘
│ │
▼ ▼
┌───────────────────────┐ ┌───────────────────────┐
│ Violations: │ │ Violations: │
│ [{file, line, msg}] │ │ [{file, line, msg}] │
└───────────────────────┘ └───────────────────────┘
│ │
└───────────────┬───────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 4. MERGE RESULTS │
│ - Combine violations from all engines │
│ - Calculate statistics │
│ - Generate summary │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 5. OUTPUT SERVICE (output-service.js) │
│ - Format results (eslint/json/summary/table) │
│ - Write to file if --output specified │
│ - Upload to API if --upload-report │
│ - GitHub annotations if --github-annotate │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 6. CONSOLE OUTPUT │
│ │
│ 📊 Sun Lint Summary: │
│ Analysis completed in 10762ms │
│ Files: 237 | Total: 58 │
│ Errors: 55 Warnings: 3 │
└─────────────────────────────────────────────────────────────────────────────┘
```
## Engine Architecture
### Engine Interface
```javascript
// core/interfaces/analysis-engine.interface.js
class AnalysisEngineInterface {
constructor(id, version, supportedLanguages) {
this.id = id; // 'eslint', 'heuristic', 'openai'
this.version = version; // '4.0'
this.supportedLanguages = supportedLanguages; // ['typescript', 'javascript']
}
async initialize(config) { }
async analyze(files, rules, options) { }
isRuleSupported(ruleId) { }
getSupportedRules() { }
cleanup() { }
}
```
### Engine Comparison
| Engine | Languages | Approach | Speed | Accuracy |
|--------|-----------|----------|-------|----------|
| **ESLint** | JS/TS only | AST + ESLint rules | Fast | High |
| **Heuristic** | All | ts-morph + Regex | Medium | Medium-High |
| **OpenAI** | All | AI analysis | Slow | Variable |
### Heuristic Engine Detail
```
┌─────────────────────────────────────────────────────────────────┐
│ HEURISTIC ENGINE │
└─────────────────────────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Semantic │ │ AST │ │ Pattern │
│ Analysis │ │ Analysis │ │ Matching │
│ (ts-morph) │ │ (tree-sitter)│ │ (Regex) │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Symbol Table│ │ Parse tree │ │ Text search │
│ Type info │ │ Node types │ │ Line/column │
│ Cross-file │ │ Visitors │ │ Fast scan │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
└───────────────┼───────────────┘
▼
┌─────────────────┐
│ Violations │
└─────────────────┘
```
## Rule System
### Rule Definition Structure
```json
// config/presets/security.json
{
"name": "@sun/sunlint/security",
"rules": {
"S001": "error",
"S002": "error",
"S003": "warn",
...
}
}
```
### Rule Selection Flow
```
┌─────────────────────────────────────────────────────────────────┐
│ CLI Options │
│ --rule, --rules, --all, --quality, --security, --category │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ RULE SELECTION SERVICE (rule-selection-service.js) │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ --rule C019 │ │ --security │ │ (no option) │
│ │ │ │ │ │
│ Single rule │ │ Load preset │ │ Use config │
│ [C019] │ │ security.json │ │ file rules │
│ │ │ 57 rules │ │ │
└───────────────┘ └───────────────┘ └───────────────┘
│ │ │
└─────────────────────┼─────────────────────┘
│
▼
┌─────────────────┐
│ Rules to Run │
│ [{id, name,...}]│
└─────────────────┘
```
### Rule to Engine Mapping
```
┌─────────────────────────────────────────────────────────────────┐
│ Rules to Analyze: [S001, S003, S005, S017, S022, ...] │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ ORCHESTRATOR: groupRulesByEngine() │
│ │
│ For each rule: │
│ 1. Check rule.analyzer field │
│ 2. Check config.requestedEngine (--engine option) │
│ 3. Check engine.isRuleSupported(ruleId) │
│ 4. Fallback to 'heuristic' │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────────┴─────────────────────┐
▼ ▼
┌───────────────────────┐ ┌───────────────────────┐
│ ESLint Engine │ │ Heuristic Engine │
│ │ │ │
│ Rules: │ │ Rules: │
│ - S001 (custom) │ │ - S003 │
│ - S002 (custom) │ │ - S004 │
│ - S009 (custom) │ │ - S005 │
│ - S017 (custom) │ │ - S006 │
│ ... │ │ - S012 │
│ (7 ESLint rules) │ │ ... │
│ │ │ (50 heuristic rules) │
└───────────────────────┘ └───────────────────────┘
```
## Data Flow Diagrams
### Config Loading Flow
```
┌─────────────────────────────────────────────────────────────────┐
│ CONFIG LOADING ORDER │
│ (Lower → Higher Priority) │
└─────────────────────────────────────────────────────────────────┘
1. Built-in Defaults (config-manager.js defaultConfig)
│
▼
2. Environment Variables (SUNLINT_RULES, SUNLINT_AI_ENABLED)
│
▼
3. Global Config (~/.sunlint.json)
│
▼
4. Project Config (sunlint.config.json, .sunlint.json)
│
▼
5. CLI Options (--rule, --security, --format, etc.)
⚠️ Note: --all/--security/--quality OVERRIDE config rules
│
▼
┌─────────────────────────────┐
│ Final Merged Config │
└─────────────────────────────┘
```
### File Analysis Flow
```
┌─────────────────────────────────────────────────────────────────┐
│ Input: --input=src (directory) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ FILE TARGETING SERVICE │
│ │
│ 1. Resolve path: src → /full/path/to/src │
│ 2. Discover files recursively │
│ 3. Apply include patterns: ['**/*.ts', '**/*.js'] │
│ 4. Apply exclude patterns: ['node_modules/**', 'dist/**'] │
│ 5. Filter by language if specified │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Target Files: [ │
│ '/path/src/index.ts', │
│ '/path/src/utils/helper.ts', │
│ '/path/src/components/Button.tsx', │
│ ... │
│ ] │
│ Total: 500 files │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ SEMANTIC ENGINE (ts-morph) │
│ │
│ 1. Create ts-morph Project │
│ 2. Load files into Symbol Table (max 1000 by default) │
│ 3. Build AST for each file │
│ 4. Cache for reuse across rules │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ FOR EACH FILE: │
│ │
│ 1. Get file content │
│ 2. Get AST from ts-morph (if available) │
│ 3. FOR EACH RULE: │
│ - Run rule analyzer │
│ - Collect violations │
│ 4. Aggregate file violations │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ All Violations: [ │
│ { │
│ ruleId: 'S022', │
│ file: '/path/src/utils/helper.ts', │
│ line: 42, │
│ column: 10, │
│ message: 'XSS vulnerability detected', │
│ severity: 'error' │
│ }, │
│ ... │
│ ] │
└─────────────────────────────────────────────────────────────────┘
```
### Output Generation Flow
```
┌─────────────────────────────────────────────────────────────────┐
│ Analysis Results (violations array) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ OUTPUT SERVICE │
│ │
│ 1. Calculate statistics │
│ 2. Group by file/rule │
│ 3. Format based on --format option │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ --format= │ │ --format= │ │ --format= │
│ eslint │ │ json │ │ summary │
│ │ │ │ │ │
│ ESLint-style │ │ Raw JSON │ │ Summary │
│ output │ │ output │ │ table │
└───────────────┘ └───────────────┘ └───────────────┘
│ │ │
└─────────────────────┼─────────────────────┘
│
▼
┌─────────────────────┴─────────────────────┐
▼ ▼
┌───────────────────────┐ ┌───────────────────────┐
│ Console Output │ │ File Output │
│ (default) │ │ (--output=report.json)│
└───────────────────────┘ └───────────────────────┘
│
▼ (optional)
┌─────────────────────┴─────────────────────┐
▼ ▼
┌───────────────────────┐ ┌───────────────────────┐
│ Upload to API │ │ GitHub Annotations │
│ (--upload-report) │ │ (--github-annotate) │
└───────────────────────┘ └───────────────────────┘
```
## Key Integration Points for Dart Support
Để thêm Dart support, cần tích hợp tại các điểm sau:
### 1. File Targeting Service
```javascript
// core/file-targeting-service.js
this.supportedLanguages = ['typescript', 'javascript', 'dart', ...];
// Đã có sẵn 'dart' trong list
```
### 2. Engine Configuration
```json
// config/engines/engines.json
"heuristic": {
"supportedLanguages": ["typescript", "javascript", "dart", ...],
// Đã có sẵn 'dart' trong list
}
```
### 3. Semantic Engine
```javascript
// core/semantic-engine.js
// Hiện tại chỉ hỗ trợ ts/js
// CẦN THÊM: Dart analyzer subprocess
```
### 4. New Dart Analyzer Adapter
```javascript
// core/adapters/dart-analyzer.ts (MỚI)
class DartAnalyzer implements ILanguageAnalyzer {
// Spawn Dart binary subprocess
// JSON-RPC communication
}
```
## Summary
SunLint sử dụng kiến trúc **Plugin-Based Engine** với:
1. **CLI Layer**: Parse arguments, bootstrap
2. **Orchestrator Layer**: Route rules to engines, merge results
3. **Engine Layer**: Actual analysis (ESLint, Heuristic, OpenAI)
4. **Output Layer**: Format and output results
Để thêm ngôn ngữ mới (như Dart):
- Core đã sẵn sàng (multi-language support)
- Cần thêm analyzer adapter cho ngôn ngữ đó
- Cần định nghĩa rules cho ngôn ngữ đó