Advanced Features
Deep dive into fast-brake's advanced capabilities, tokenizer internals, performance tuning, and extensibility
fast-brake provides advanced features for power users who need fine-grained control over ES feature detection, performance optimization, and custom integrations.
Tokenizer Deep Dive
The tokenizer is the heart of fast-brake’s accuracy. Understanding its internals helps you optimize performance and troubleshoot edge cases.
Token Types and Structure
interface Token {
type: string; // 'keyword', 'identifier', 'operator', 'string', etc.
value: string; // The actual token text
start: number; // Start position in source
end: number; // End position in source
line: number; // Line number (1-based)
column: number; // Column number (1-based)
}
State Management
The tokenizer tracks context for accurate detection:
enum TokenState {
NORMAL = 0, // Regular code
STRING_SINGLE = 1, // Inside 'single quotes'
STRING_DOUBLE = 2, // Inside "double quotes"
TEMPLATE = 3, // Inside `template literals`
COMMENT_LINE = 4, // Inside // line comments
COMMENT_BLOCK = 5, // Inside /* block comments */
REGEX = 6 // Inside /regex/ patterns
}
Advanced Tokenization Examples
import { Tokenizer } from 'fast-brake/tokenizer';
const code = `
const arrow = () => {};
const str = "This => is not an arrow function";
// This => is also not an arrow function
const regex = /=>/; // Neither is this
`;
const tokenizer = new Tokenizer(code);
const allTokens = tokenizer.tokenize();
const codeTokens = tokenizer.getCodeTokens(); // Excludes strings/comments
console.log('All tokens:', allTokens.length); // ~20 tokens
console.log('Code tokens:', codeTokens.length); // ~12 tokens (no strings/comments)
// Find actual arrow functions (not in strings/comments)
const arrowTokens = codeTokens.filter(t => t.value === '=>');
console.log('Real arrow functions:', arrowTokens.length); // 1
Performance Tuning
Choosing the Right Mode
Quick Mode - When Speed Matters Most:
import { detect } from 'fast-brake';
// Development builds with hot reloading
const features = detect(code, { quick: true });
// Build tools where speed is critical
const isCompatible = check(code, { target: 'es5', quick: true });
// Batch processing thousands of files
const results = files.map(file =>
getMinimumESVersion(file.content, { quick: true })
);
Full Mode - When Accuracy is Critical:
// Production builds
const features = detect(code, { quick: false }); // default
// CI/CD pipelines
fastBrake(code, { target: 'es2018' }); // always uses full mode
// Code analysis and reporting
const analysis = detect(codebase, { quick: false });
Batch Processing Optimization
import { getDetector } from 'fast-brake';
// Reuse detector instance for better performance
const detector = getDetector();
// Process multiple files efficiently
const results = files.map(file => ({
path: file.path,
features: detector.detect(file.content, { quick: true }),
minVersion: detector.getMinimumVersion(file.content, { quick: true })
}));
// Memory-efficient streaming for large codebases
async function* processLargeCodebase(files) {
const detector = getDetector();
for (const file of files) {
yield {
path: file.path,
result: detector.detect(file.content, { quick: true })
};
}
}
Memory Management
// Efficient processing with minimal memory allocation
function analyzeCodebase(files, options = {}) {
const detector = getDetector(); // Singleton - reuses compiled patterns
const results = [];
for (const file of files) {
// Process one file at a time to minimize memory usage
const features = detector.detect(file.content, options);
// Store only essential data
results.push({
file: file.path,
featureCount: features.length,
minVersion: features.reduce((max, f) =>
getVersionIndex(f.version) > getVersionIndex(max) ? f.version : max, 'es5'
)
});
}
return results;
}
Custom Feature Detection
Extending Pattern Matching
import { QUICK_PATTERNS, FEATURE_VERSIONS } from 'fast-brake/constants';
// Add custom patterns (for internal use)
const customPatterns = {
...QUICK_PATTERNS,
// Custom company-specific patterns
company_api: /CompanyAPI\./,
legacy_jquery: /\$\(/,
custom_decorator: /@CustomDecorator/
};
const customVersions = {
...FEATURE_VERSIONS,
company_api: 'es2020',
legacy_jquery: 'es5',
custom_decorator: 'es2015'
};
Building Custom Detectors
import { Detector } from 'fast-brake/detector';
class CustomDetector extends Detector {
detect(code, options) {
// Get standard features
const standardFeatures = super.detect(code, options);
// Add custom detection logic
const customFeatures = this.detectCustomFeatures(code);
return [...standardFeatures, ...customFeatures];
}
detectCustomFeatures(code) {
const features = [];
// Detect company-specific patterns
if (/CompanyAPI\./.test(code)) {
features.push({
name: 'company_api',
version: 'es2020',
line: this.getLineNumber(code, code.indexOf('CompanyAPI.')),
column: code.indexOf('CompanyAPI.') + 1
});
}
// Detect legacy jQuery usage
if (/\$\(/.test(code)) {
features.push({
name: 'legacy_jquery',
version: 'es5',
line: this.getLineNumber(code, code.indexOf('$(')),
column: code.indexOf('$(') + 1
});
}
return features;
}
}
// Use custom detector
const customDetector = new CustomDetector();
const features = customDetector.detect(code, { target: 'es2018' });
Advanced Integration Patterns
Webpack Plugin
class FastBrakeWebpackPlugin {
constructor(options = {}) {
this.target = options.target || 'es5';
this.mode = options.mode || 'full';
this.failOnIncompatible = options.failOnIncompatible || false;
}
apply(compiler) {
compiler.hooks.compilation.tap('FastBrakePlugin', (compilation) => {
compilation.hooks.optimizeChunkAssets.tap('FastBrakePlugin', (chunks) => {
const { detect, check } = require('fast-brake');
chunks.forEach(chunk => {
chunk.files.forEach(filename => {
if (!filename.endsWith('.js')) return;
const asset = compilation.assets[filename];
const source = asset.source();
// Check compatibility
const isCompatible = check(source, {
target: this.target,
quick: this.mode === 'quick'
});
if (!isCompatible) {
const features = detect(source, {
target: this.target,
quick: this.mode === 'quick'
});
const incompatible = features.filter(f =>
this.getVersionIndex(f.version) > this.getVersionIndex(this.target)
);
const message = `${filename} contains incompatible features: ${
incompatible.map(f => f.name).join(', ')
}`;
if (this.failOnIncompatible) {
compilation.errors.push(new Error(message));
} else {
compilation.warnings.push(new Error(message));
}
}
});
});
});
});
}
getVersionIndex(version) {
const versions = ['es5', 'es2015', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'es2021', 'es2022'];
return versions.indexOf(version);
}
}
// Usage
module.exports = {
plugins: [
new FastBrakeWebpackPlugin({
target: 'es2018',
mode: 'full',
failOnIncompatible: true
})
]
};
Rollup Plugin
import { detect, check } from 'fast-brake';
function fastBrakePlugin(options = {}) {
const target = options.target || 'es5';
const mode = options.mode || 'full';
return {
name: 'fast-brake',
generateBundle(outputOptions, bundle) {
Object.entries(bundle).forEach(([fileName, chunk]) => {
if (chunk.type === 'chunk' && chunk.code) {
const isCompatible = check(chunk.code, {
target,
quick: mode === 'quick'
});
if (!isCompatible) {
const features = detect(chunk.code, { target, quick: mode === 'quick' });
const incompatible = features.filter(f =>
getVersionIndex(f.version) > getVersionIndex(target)
);
this.warn(`${fileName} contains incompatible features: ${
incompatible.map(f => f.name).join(', ')
}`);
}
}
});
}
};
}
// Usage
export default {
plugins: [
fastBrakePlugin({
target: 'es2018',
mode: 'full'
})
]
};
ESLint Integration
// eslint-plugin-fast-brake
const { detect } = require('fast-brake');
module.exports = {
rules: {
'es-version-compatibility': {
meta: {
type: 'problem',
docs: {
description: 'Enforce ES version compatibility'
},
schema: [
{
type: 'object',
properties: {
target: { type: 'string' },
mode: { type: 'string', enum: ['quick', 'full'] }
},
additionalProperties: false
}
]
},
create(context) {
const options = context.options[0] || {};
const target = options.target || 'es5';
const mode = options.mode || 'full';
return {
Program(node) {
const sourceCode = context.getSourceCode();
const text = sourceCode.getText();
try {
const features = detect(text, {
target,
quick: mode === 'quick'
});
const incompatible = features.filter(f =>
getVersionIndex(f.version) > getVersionIndex(target)
);
incompatible.forEach(feature => {
context.report({
node,
message: `ES feature "${feature.name}" requires ${feature.version} but target is ${target}`,
loc: feature.line ? {
line: feature.line,
column: feature.column || 0
} : undefined
});
});
} catch (error) {
// Fallback to quick mode on tokenizer errors
if (mode === 'full') {
const quickFeatures = detect(text, { target, quick: true });
// Process quick features...
}
}
}
};
}
}
}
};
Error Handling and Debugging
Advanced Error Information
import { fastBrake } from 'fast-brake';
try {
fastBrake(code, { target: 'es5' });
} catch (error) {
if (error.feature) {
console.log('Compatibility Error Details:');
console.log(` Feature: ${error.feature.name}`);
console.log(` Requires: ${error.feature.version}`);
console.log(` Target: ${error.target}`);
console.log(` Location: line ${error.feature.line}, column ${error.feature.column}`);
if (error.feature.snippet) {
console.log(` Code: ${error.feature.snippet}`);
}
// Get suggestions for fixing
const suggestions = getSuggestions(error.feature, error.target);
console.log(` Suggestions: ${suggestions.join(', ')}`);
}
}
function getSuggestions(feature, target) {
const suggestions = [];
switch (feature.name) {
case 'arrow_functions':
suggestions.push('Use function expressions', 'Add Babel transform');
break;
case 'optional_chaining':
suggestions.push('Use logical AND (&&)', 'Add optional-chaining polyfill');
break;
case 'nullish_coalescing':
suggestions.push('Use logical OR (||)', 'Add nullish-coalescing polyfill');
break;
default:
suggestions.push(`Transpile to ${target}`, 'Add appropriate polyfill');
}
return suggestions;
}
Debugging Tokenizer Issues
import { Tokenizer } from 'fast-brake/tokenizer';
function debugTokenization(code) {
const tokenizer = new Tokenizer(code);
const allTokens = tokenizer.tokenize();
const codeTokens = tokenizer.getCodeTokens();
console.log('=== Tokenization Debug ===');
console.log(`Total tokens: ${allTokens.length}`);
console.log(`Code tokens: ${codeTokens.length}`);
console.log(`Filtered out: ${allTokens.length - codeTokens.length}`);
// Show filtered tokens (strings, comments)
const filteredTokens = allTokens.filter(t =>
!codeTokens.some(ct => ct.start === t.start)
);
console.log('\nFiltered tokens (strings/comments):');
filteredTokens.forEach(token => {
console.log(` ${token.type}: "${token.value}" at line ${token.line}`);
});
// Show potential ES features in filtered tokens
console.log('\nPotential false positives:');
filteredTokens.forEach(token => {
if (token.value.includes('=>')) {
console.log(` Arrow function syntax in ${token.type}: "${token.value}"`);
}
if (token.value.includes('?.')) {
console.log(` Optional chaining in ${token.type}: "${token.value}"`);
}
});
}
// Usage
const problematicCode = `
const arrow = () => {};
const str = "This => looks like an arrow function";
// This => comment also looks suspicious
const regex = /=>/g;
`;
debugTokenization(problematicCode);
Performance Monitoring
Benchmarking Custom Code
import { detect, getMinimumESVersion } from 'fast-brake';
function benchmarkDetection(code, iterations = 1000) {
console.log('=== Performance Benchmark ===');
// Warm up
for (let i = 0; i < 10; i++) {
detect(code, { quick: true });
detect(code, { quick: false });
}
// Benchmark quick mode
const quickStart = performance.now();
for (let i = 0; i < iterations; i++) {
detect(code, { quick: true });
}
const quickTime = performance.now() - quickStart;
// Benchmark full mode
const fullStart = performance.now();
for (let i = 0; i < iterations; i++) {
detect(code, { quick: false });
}
const fullTime = performance.now() - fullStart;
console.log(`Quick mode: ${(quickTime / iterations).toFixed(3)}ms per call`);
console.log(`Full mode: ${(fullTime / iterations).toFixed(3)}ms per call`);
console.log(`Speed difference: ${(fullTime / quickTime).toFixed(1)}x`);
return {
quickAvg: quickTime / iterations,
fullAvg: fullTime / iterations,
speedup: fullTime / quickTime
};
}
// Usage
const testCode = `
const arrow = () => {};
class MyClass {
#private = 'secret';
async method() {
return await fetch('/api');
}
}
`;
benchmarkDetection(testCode);
Memory Usage Monitoring
function monitorMemoryUsage(files) {
const initialMemory = process.memoryUsage();
console.log('Initial memory:', formatMemory(initialMemory));
const detector = getDetector();
const results = [];
files.forEach((file, index) => {
const features = detector.detect(file.content, { quick: false });
results.push({ file: file.path, features });
// Check memory every 100 files
if (index % 100 === 0) {
const currentMemory = process.memoryUsage();
console.log(`After ${index + 1} files:`, formatMemory(currentMemory));
}
});
const finalMemory = process.memoryUsage();
console.log('Final memory:', formatMemory(finalMemory));
return results;
}
function formatMemory(memUsage) {
return {
rss: `${Math.round(memUsage.rss / 1024 / 1024)}MB`,
heapUsed: `${Math.round(memUsage.heapUsed / 1024 / 1024)}MB`,
heapTotal: `${Math.round(memUsage.heapTotal / 1024 / 1024)}MB`
};
}
Best Practices for Advanced Usage
1. Mode Selection Strategy
// Development: Quick mode for speed
const devConfig = {
mode: 'quick',
target: 'es2015'
};
// CI/CD: Full mode for accuracy
const ciConfig = {
mode: 'full',
target: 'es2018',
throwOnFirst: true
};
// Production analysis: Full mode with detailed reporting
const prodConfig = {
mode: 'full',
target: 'es5',
generateReport: true
};
2. Error Recovery Patterns
function robustDetection(code, options) {
try {
// Try full mode first
return detect(code, { ...options, quick: false });
} catch (error) {
console.warn('Full mode failed, falling back to quick mode:', error.message);
try {
// Fallback to quick mode
return detect(code, { ...options, quick: true });
} catch (quickError) {
console.error('Both modes failed:', quickError.message);
return []; // Return empty array as last resort
}
}
}
3. Caching for Large Codebases
const detectionCache = new Map();
function cachedDetection(code, options) {
const cacheKey = `${code.length}-${JSON.stringify(options)}`;
if (detectionCache.has(cacheKey)) {
return detectionCache.get(cacheKey);
}
const result = detect(code, options);
detectionCache.set(cacheKey, result);
// Limit cache size
if (detectionCache.size > 1000) {
const firstKey = detectionCache.keys().next().value;
detectionCache.delete(firstKey);
}
return result;
}
4. Progressive Enhancement
function progressiveDetection(code, target) {
// Start with quick mode for immediate feedback
const quickResult = detect(code, { target, quick: true });
// If quick mode finds issues, run full mode for accuracy
if (quickResult.length > 0) {
const fullResult = detect(code, { target, quick: false });
return {
mode: 'full',
features: fullResult,
quickFeatures: quickResult
};
}
return {
mode: 'quick',
features: quickResult
};
}
These features support complex use cases while keeping detection fast.