@neurolint/cli
Version:
Professional React/Next.js modernization platform with CLI, VS Code, and Web App integrations
461 lines (398 loc) • 12 kB
JavaScript
/**
* NeuroLint Shared Core
*
* Unified interface for CLI, VS Code, and Web App platforms.
* Provides rule engine, configuration management, and analytics.
*/
const ruleEngine = require('./rule-engine');
const configManager = require('./config-manager');
const analytics = require('./analytics');
const path = require('path');
/**
* Smart Layer Selector for analyzing and recommending layers
* This provides the intelligent analysis that rule analysis expects
*/
class SmartLayerSelector {
static analyzeAndRecommend(code, filePath) {
const issues = [];
const ext = path.extname(filePath || '');
try {
// Use AST-based analysis for more accurate detection
const ASTTransformer = require('../ast-transformer');
const transformer = new ASTTransformer();
const astIssues = transformer.analyzeCode(code, { filename: filePath });
// Convert AST issues to layer recommendations
astIssues.forEach(issue => {
issues.push({
layer: issue.layer,
reason: issue.message,
confidence: 0.9,
location: issue.location
});
});
} catch (error) {
// Fallback to regex-based detection if AST parsing fails
issues.push(...this.fallbackAnalysis(code, filePath));
}
return {
detectedIssues: issues,
recommendedLayers: [...new Set(issues.map(i => i.layer))].sort(),
reasons: issues.map(i => i.reason),
confidence: issues.reduce((acc, i) => acc + i.confidence, 0) / issues.length || 0
};
}
static fallbackAnalysis(code, filePath) {
const issues = [];
const ext = path.extname(filePath || '');
// Layer 1: Configuration issues
if (code.includes('tsconfig.json') || code.includes('next.config.js')) {
issues.push({
layer: 1,
reason: 'Configuration file detected',
confidence: 0.8,
location: { line: 1, column: 1 }
});
}
// Layer 2: HTML entities
if (code.includes('"') || code.includes('&') || code.includes('<') || code.includes('>')) {
issues.push({
layer: 2,
reason: 'HTML entities detected',
confidence: 0.9,
location: { line: 1, column: 1 }
});
}
// Layer 3: React component issues
if (ext === '.tsx' || ext === '.jsx' || code.includes('React') || code.includes('useState')) {
if (code.includes('.map(') && !code.includes('key=')) {
issues.push({
layer: 3,
reason: 'Missing key props in React lists',
confidence: 0.9,
location: { line: 1, column: 1 }
});
}
}
// Layer 4: SSR safety
if (code.includes('window.') || code.includes('document.') || code.includes('localStorage')) {
issues.push({
layer: 4,
reason: 'Client-side APIs detected',
confidence: 0.8,
location: { line: 1, column: 1 }
});
}
// Layer 5: Next.js App Router
if (code.includes('use client') || code.includes('use server')) {
issues.push({
layer: 5,
reason: 'App Router directives detected',
confidence: 0.7,
location: { line: 1, column: 1 }
});
}
// Layer 6: Testing and accessibility
if (code.includes('test') || code.includes('spec') || code.includes('aria-')) {
issues.push({
layer: 6,
reason: 'Testing or accessibility patterns detected',
confidence: 0.6,
location: { line: 1, column: 1 }
});
}
return issues;
}
}
/**
* Main NeuroLint Core class
*/
class NeuroLintCore {
constructor() {
this.ruleEngine = ruleEngine;
this.configManager = configManager;
this.analytics = analytics;
this.initialized = false;
}
/**
* Initialize the core with configuration
*/
async initialize(options = {}) {
try {
// Load configuration
await this.configManager.loadConfig(options.configPath);
// Initialize analytics
await this.analytics.loadAnalytics();
this.initialized = true;
// Track initialization
this.analytics.trackCommand('initialize', {
platform: options.platform || 'cli',
success: true
});
return true;
} catch (error) {
// Track error without console.log
this.analytics.trackCommand('initialize', {
platform: options.platform || 'cli',
success: false,
error: error.message
});
return false;
}
}
/**
* Analyze code and return issues
*/
async analyze(code, options = {}) {
if (!this.initialized) {
await this.initialize(options);
}
const startTime = Date.now();
try {
// Get platform-specific configuration
const platformConfig = this.configManager.getPlatformConfig(options.platform || 'cli');
// Merge options with configuration
const analysisOptions = {
...platformConfig,
...options,
layers: options.layers || this.configManager.getEnabledLayers()
};
// Use SmartLayerSelector for intelligent analysis
const smartAnalysis = SmartLayerSelector.analyzeAndRecommend(code, options.filename);
// Perform rule engine analysis
const ruleResult = await this.ruleEngine.analyze(code, analysisOptions);
// Combine results with SmartLayerSelector recommendations
const result = {
...ruleResult,
summary: {
...ruleResult.summary,
recommendedLayers: smartAnalysis.recommendedLayers,
confidence: smartAnalysis.confidence,
reasoning: smartAnalysis.reasons
},
detectedIssues: smartAnalysis.detectedIssues,
// Add properties that SmartLayerSelector provides
hasModernConfig: smartAnalysis.detectedIssues.some(issue => issue.layer === 1),
hasHtmlEntities: smartAnalysis.detectedIssues.some(issue => issue.layer === 2),
hasAppRouter: smartAnalysis.detectedIssues.some(issue => issue.layer === 5)
};
// Track analytics
this.analytics.trackAnalysis({
files: [options.filename || 'unknown'],
issues: result.issues,
executionTime: Date.now() - startTime,
layers: analysisOptions.layers,
platform: options.platform || 'cli'
});
// Calculate quality metrics
if (result.issues.length > 0) {
this.analytics.calculateQualityScore(result.issues, 1);
this.analytics.calculateModernizationProgress(result.summary.issuesByLayer);
this.analytics.calculateTechnicalDebt(result.summary.issuesByLayer);
}
return result;
} catch (error) {
// Track error
this.analytics.trackAnalysis({
files: [options.filename || 'unknown'],
issues: [],
executionTime: Date.now() - startTime,
layers: options.layers || [],
platform: options.platform || 'cli'
});
throw error;
}
}
/**
* Get configuration
*/
getConfig(key = null) {
if (key) {
return this.configManager.get(key);
}
return this.configManager.config;
}
/**
* Set configuration
*/
setConfig(key, value) {
this.configManager.set(key, value);
}
/**
* Save configuration
*/
async saveConfig(config = null, configPath = null) {
return await this.configManager.saveConfig(config, configPath);
}
/**
* Get analytics report
*/
getAnalyticsReport(options = {}) {
return this.analytics.generateReport(options);
}
/**
* Save analytics data
*/
async saveAnalytics() {
return await this.analytics.saveAnalytics();
}
/**
* Export analytics
*/
exportAnalytics(format = 'json') {
return this.analytics.exportAnalytics(format);
}
/**
* Get rule engine
*/
getRuleEngine() {
return this.ruleEngine;
}
/**
* Get configuration manager
*/
getConfigManager() {
return this.configManager;
}
/**
* Get analytics
*/
getAnalytics() {
return this.analytics;
}
/**
* Validate configuration
*/
validateConfig(config = null) {
return this.configManager.validateConfig(config);
}
/**
* Get platform-specific configuration
*/
getPlatformConfig(platform) {
return this.configManager.getPlatformConfig(platform);
}
/**
* Create default configuration
*/
createDefaultConfig() {
return this.configManager.createDefaultConfig();
}
/**
* Export configuration
*/
exportConfig() {
return this.configManager.exportConfig();
}
/**
* Import configuration
*/
async importConfig(configData) {
return await this.configManager.importConfig(configData);
}
/**
* Add custom rule
*/
addRule(name, rule) {
this.ruleEngine.addRule(name, rule);
}
/**
* Get all rules
*/
getRules() {
return Array.from(this.ruleEngine.rules.entries()).map(([name, rule]) => ({
name,
description: rule.description,
layer: rule.layer
}));
}
/**
* Check if layer is enabled
*/
isLayerEnabled(layerId) {
return this.configManager.isLayerEnabled(layerId);
}
/**
* Get enabled layers
*/
getEnabledLayers() {
return this.configManager.getEnabledLayers();
}
/**
* Get include patterns
*/
getIncludePatterns() {
return this.configManager.getIncludePatterns();
}
/**
* Get exclude patterns
*/
getExcludePatterns() {
return this.configManager.getExcludePatterns();
}
/**
* Get team preferences
*/
getTeamPrefs() {
return this.configManager.getTeamPrefs();
}
/**
* Track user activity
*/
trackUser(userId, action) {
this.analytics.trackUser(userId, action);
}
/**
* Track command usage
*/
trackCommand(command, options = {}) {
this.analytics.trackCommand(command, options);
}
/**
* Shutdown and cleanup
*/
async shutdown() {
try {
// Save analytics data
await this.analytics.saveAnalytics();
// Track shutdown
this.analytics.trackCommand('shutdown', {
platform: 'cli',
success: true
});
this.initialized = false;
return true;
} catch (error) {
// Track error without console.log
this.analytics.trackCommand('shutdown', {
platform: 'cli',
success: false,
error: error.message
});
return false;
}
}
}
// Create and export singleton instance
const neurolintCore = new NeuroLintCore();
// Export individual modules for direct access
module.exports = {
// Main core instance
core: neurolintCore,
// Individual modules
ruleEngine,
configManager,
analytics,
// Smart Layer Selector
SmartLayerSelector,
// Convenience methods
analyze: (code, options) => neurolintCore.analyze(code, options),
analyzeAndRecommend: (code, filePath) => SmartLayerSelector.analyzeAndRecommend(code, filePath),
getConfig: (key) => neurolintCore.getConfig(key),
setConfig: (key, value) => neurolintCore.setConfig(key, value),
getAnalyticsReport: (options) => neurolintCore.getAnalyticsReport(options),
trackCommand: (command, options) => neurolintCore.trackCommand(command, options),
trackUser: (userId, action) => neurolintCore.trackUser(userId, action),
// Version info
version: '1.2.1',
description: 'NeuroLint Shared Core - Unified code modernization engine'
};