Architecture
Deep dive into fast-brake's high-performance pattern matching system and plugin architecture
How fast-brake Works
fast-brake uses pattern matching and a plugin architecture for fast feature detection.
graph TD
A[JavaScript Code] --> B[Pattern Matching Engine]
B --> C[Regex-based Feature Detection]
C --> D[Feature Results]
D --> E{Include Location?}
E -->|Yes| F[Calculate Location Data]
E -->|No| G[Return Results]
F --> G[Return Results]
This approach delivers up to 85x faster performance with targeted plugins compared to traditional AST parsers.
Module Types
Fast Brake has three types of optional, composable modules:
| Module | Purpose | Location | Examples |
|---|---|---|---|
| Preprocessors | Transform code before detection | src/plugins/ (core) | jscomments - strips comments/strings |
| Plugins | Define detection patterns/schemas | src/plugins/ (bundled) | esversion - ES feature patterns |
| Extensions | Enrich detection results | extensions/ (separate packages) | fast-brake-acorn - AST validation |
Preprocessors
Preprocessors prepare code for accurate detection. The jscomments preprocessor is core infrastructure - parsing JavaScript without comment/string awareness produces unreliable results.
Preprocessors with external dependencies (TypeScript, JSX, Flow) are separate packages:
fast-brake-typescript-preprocessorfast-brake-jsx-preprocessorfast-brake-flow-preprocessor
Plugins
Plugins answer: “What are we looking for?”
They provide pattern schemas for detection. Bundled plugins (esversion, telemetry) have no external dependencies and ship with fast-brake.
Extensions
Extensions answer: “What else can we learn about the match?”
They enrich results post-detection (line numbers, AST validation, code frames). Extensions with external dependencies live in extensions/ as separate workspace packages that users install as needed.
Core Architecture Components
1. Detector Engine (src/detector.ts)
The Detector is the main engine that performs pattern-based feature detection.
class Detector {
// High-performance pattern scanning
scan(code: string, options?: DetectionOptions): DetectedFeature[]
// Main detection method
detect(code: string, options: DetectionOptions): DetectedFeature[]
// Check compatibility
check(code: string, options: DetectionOptions): boolean
// Get minimum ES version
getMinimumVersion(code: string): string
}
Key Responsibilities:
- Manages compiled regex patterns for optimal performance
- Performs single-pass pattern matching
- Provides location data when requested
- Singleton instance for performance optimization
2. Plugin System (src/plugins/)
The Plugin System allows targeted detection for specific use cases.
123456789101112131415161718192021222324Available Plugins:
- ES Version Plugins: es5, es2015, es2016, etc.
- All Plugin: Detects all ES features
- Browser Plugin: Browser compatibility checking
- Telemetry Plugin: Analytics detection
- Detect Plugin: Auto-detect minimum version
3. Pattern Engine (src/constants.ts)
The Pattern Engine contains optimized regex patterns and feature mappings.
// Quick detection patterns
export const QUICK_PATTERNS: Record<string, RegExp> = {
arrow_functions: /=>/,
template_literals: /`/,
optional_chaining: /\?\./,
// ... 40+ patterns
};
// Feature version mappings
export const FEATURE_VERSIONS: Record<string, string> = {
arrow_functions: 'es2015',
optional_chaining: 'es2020',
private_fields: 'es2022',
// ... complete mappings
};
Optimization Strategies:
- Pre-compiled patterns: Regex patterns compiled at startup
- Hierarchical organization: Patterns grouped by ES version
- Performance tuning: Optimized for common cases first
Pattern Matching Deep Dive
High-Performance Detection
Objective: Fast feature detection using optimized regex patterns.
// Example: Detecting arrow functions
const arrowPattern = /=>/;
const matches = code.match(arrowPattern);
if (matches) {
features.push({
name: 'arrow_functions',
version: 'es2015',
line: getLineNumber(matches.index),
column: matches.index
});
}
Characteristics:
- Ultra-fast: ~0.001ms with targeted plugins
- High accuracy: Carefully crafted patterns
- Single-pass: Processes code once
Use Cases:
- Development builds with hot reloading
- Build tools where speed is critical
- CI/CD pipelines for compatibility checking
Location Data Support
Provides optional AST-like location information.
// Example: Getting location data
const features = detect(code, { includeLoc: true });
// Returns:
// {
// name: 'arrow_functions',
// version: 'es2015',
// loc: {
// start: { line: 1, column: 15 },
// end: { line: 1, column: 17 },
// offset: 14,
// length: 2
// }
// }
Characteristics:
- Precise locations: Line, column, offset, and length
- Optional feature: No overhead unless requested
- AST compatibility: Similar to parser output
- Minimal overhead: Calculated only when needed
Performance Optimizations
1. Singleton Pattern
let detectorInstance: Detector | null = null;
export function getDetector(): Detector {
if (!detectorInstance) {
detectorInstance = new Detector();
}
return detectorInstance;
}
Benefits:
- Reuses compiled regex patterns
- Reduces memory allocation
- Faster subsequent calls
2. Pattern Compilation
class Detector {
private compiledPatterns: Map<string, RegExp>;
constructor() {
// Compile all patterns once at startup
this.compiledPatterns = new Map();
for (const [name, pattern] of Object.entries(QUICK_PATTERNS)) {
this.compiledPatterns.set(name, pattern);
}
}
}
Benefits:
- Patterns compiled once, used many times
- Eliminates regex compilation overhead
- Consistent performance across calls
3. Early Termination
// Stop on first incompatible feature
if (options.throwOnFirst && featureIndex > targetIndex) {
throw new Error(`Incompatible feature: ${feature.name}`);
}
Benefits:
- Faster failure detection
- Reduced processing for incompatible code
- Better CI/CD performance
4. Memory Efficiency
// Minimal allocations for location data
if (options.includeLoc) {
feature.loc = calculateLocation(match);
}
Benefits:
- Minimal garbage collection
- Consistent memory usage
- Better performance under load
Feature Detection Strategies
Simple Patterns
arrow_functions: /=>/,
template_literals: /`/,
optional_chaining: /\?\./,
nullish_coalescing: /\?\?/,
Complex Patterns
async_await: /\b(?:async\s+function|async\s*(?:\([^)]*\)|[a-zA-Z_$][a-zA-Z0-9_$]*)\s*=>|await\s)/,
destructuring: /(?:const|let|var)\s*[[{]/,
private_fields: /#[a-zA-Z_$][a-zA-Z0-9_$]*/,
top_level_await: /^[^{]*\bawait\s/m
Pattern Categories
ES2015 Features:
- Arrow functions, classes, template literals
- Let/const, destructuring, spread/rest
- For-of loops, generators, imports/exports
ES2020+ Features:
- Optional chaining, nullish coalescing
- Private fields, static blocks
- Top-level await, logical assignment
Plugin Architecture
Plugins enable targeted detection for specific use cases:
ES2015 Plugin Example
123456789101112131415161718192021222324252627282930313233343536373839404142Custom Plugin Example
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556Using Plugins
// Use specific plugins for maximum performance
import { detectWithPlugins } from 'fast-brake';
// Single ES version - 85x faster!
const features = detectWithPlugins(code, ['es2015']);
// All ES versions
const features = detectWithPlugins(code, ['all']);
// Browser compatibility
const features = detectWithPlugins(code, ['browser:defaults']);
Plugin benefits:
- Targeted detection: Load only what you need
- Maximum performance: Single plugin can be 85x faster
- Composable: Combine multiple plugins
- Extensible: Create custom plugins
Plugin Performance Comparison
| Plugin Configuration | Ops/sec | Relative Speed | Use Case |
|---|---|---|---|
| Single ES2015 | 1,063,499 | 85.2x | Known target version |
| All ES Versions | 980,954 | 78.6x | Comprehensive checking |
| Browser Defaults | 947,381 | 75.9x | Browser compatibility |
| Full Detection | 12,488 | 1.0x | All features, all versions |
Error Handling Architecture
Detailed Error Information
const error = new Error(
`ES feature "${feature.name}" requires ${feature.version} but target is ${options.target}` +
(feature.line ? ` at line ${feature.line}:${feature.column}` : '') +
(feature.snippet ? `\n ${feature.snippet}` : '')
);
// Attach structured data
(error as any).feature = feature;
(error as any).target = options.target;
Extensibility Points
Adding New Features
- Add pattern to constants:
export const QUICK_PATTERNS = {
// ... existing patterns
new_feature: /pattern/,
};
export const FEATURE_VERSIONS = {
// ... existing versions
new_feature: 'es2025',
};
- Create your custom plugin:
See the Custom Plugin Example above for a complete implementation of a React Hooks detection plugin.
Custom Detection Logic
// Extend detector for custom features
class CustomDetector extends Detector {
detect(code: string, options: DetectionOptions): DetectedFeature[] {
const features = super.detect(code, options);
// Add custom detection logic
const customFeatures = this.detectCustomFeatures(code);
return [...features, ...customFeatures];
}
}
Performance Benchmarks
Live Benchmark Results
| Parser | Time (ms) | Ops/sec | Speed |
|---|---|---|---|
| fast-brake | 0.002 | 552,385 | 1.0x |
| fast-brake (detect) | 0.007 | 139,003 | 0.3x |
| fast-brake (es5 only) | 0.016 | 64,194 | 0.1x |
| fast-brake (browserlist) | 0.016 | 63,239 | 0.1x |
| cherow | 0.019 | 53,499 | 0.1x |
| fast-brake (es2015 only) | 0.021 | 48,691 | 0.1x |
| meriyah | 0.021 | 47,350 | 0.1x |
| esprima | 0.026 | 37,952 | 0.1x |
| acorn | 0.054 | 18,598 | 0.0x |
| @babel/parser | 0.059 | 16,919 | 0.0x |
| espree | 0.064 | 15,720 | 0.0x |
Detailed Performance Analysis
| Approach | 1000 Files | Single File | Memory |
|---|---|---|---|
| fast-brake (plugin) | 1ms | 0.001ms | 2MB |
| fast-brake (all) | 80ms | 0.080ms | 4MB |
| Babel Parser | ~100ms | ~2ms | ~15MB |
| ESLint Parser | ~120ms | ~2.5ms | ~18MB |
| Acorn Parser | ~80ms | ~1.8ms | ~12MB |
Results show performance with optimized plugins vs full detection.
Scalability Characteristics
graph LR
A[File Size] --> B[Processing Time]
B --> C[Linear Growth]
D[Number of Files] --> E[Batch Processing]
E --> F[Near-Linear Growth]
G[Feature Complexity] --> H[Detection Time]
H --> I[Constant Time]
Key Insights:
- Linear scaling: Processing time scales linearly with code size
- Batch efficiency: Minimal overhead for processing multiple files
- Feature independence: Detection time independent of feature complexity
- Memory stability: Consistent memory usage regardless of input size
Best Practices
Development Builds
// Development builds - use targeted plugins
const features = detectWithPlugins(code, ['es2015']);
// Hot reloading - fast feedback
if (checkWithPlugins(code, ['es2015'])) {
// Continue with hot reload
}
Production Builds
// Production builds - comprehensive detection
const features = detectWithPlugins(code, ['all']);
// CI/CD pipelines - browser compatibility
const features = detectWithPlugins(code, ['all', 'browser:defaults']);
// Code analysis - with location data
const analysis = detect(codebase, { includeLoc: true });
Performance Optimization Tips
- Use targeted plugins:
// Development: targeted plugin
const devFeatures = detectWithPlugins(code, ['es2015']);
// Production: comprehensive detection
const prodFeatures = detectWithPlugins(code, ['all']);
- Reuse detector instances:
const detector = getDetector(); // Singleton
const results = files.map(file => detector.detect(file.content));
- Batch processing:
// Process multiple files efficiently
const results = files.map(file => ({
file: file.path,
features: detect(file.content, options)
}));
The fast-brake architecture demonstrates how optimized pattern matching and plugin architecture can deliver exceptional performance without sacrificing accuracy, making it the ideal choice for modern JavaScript tooling.