JavaScript source analysis and visualizer that generates detailed complexity reports
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Specialized analysis modules for different code quality metrics and linting integration. Reporters provide the core analysis functionality for complexity calculation, JSHint integration, and ESLint integration.
Analyzes JavaScript source code to calculate complexity metrics including cyclomatic complexity, Halstead metrics, and maintainability indices.
/**
* Analyze JavaScript source code complexity metrics
* @param {String} source - JavaScript source code to analyze
* @param {Object} options - Analysis options and configuration
* @param {Object} reportInfo - File information object for context
* @returns {Object} Complexity analysis report with detailed metrics
*/
function process(source, options, reportInfo);Parameters:
source (String): JavaScript source code to analyzeoptions (Object): Analysis options and configurationreportInfo (Object): File information object containing file metadataReturns: Object - Comprehensive complexity analysis report
Report Structure:
interface ComplexityReport {
/** Cyclomatic complexity score */
cyclomatic: number;
/** Source lines of code metrics */
sloc: {
/** Physical lines of code (including comments and whitespace) */
physical: number;
/** Logical lines of code (executable statements) */
logical: number;
};
/** Halstead complexity metrics */
halstead: {
/** Operator analysis */
operators: {
distinct: number; // Number of unique operators
total: number; // Total operator count
identifiers: string[]; // List of operators found
};
/** Operand analysis */
operands: {
distinct: number; // Number of unique operands
total: number; // Total operand count
identifiers: string[]; // List of operands found
};
length: number; // Program length (N = N1 + N2)
vocabulary: number; // Program vocabulary (n = n1 + n2)
difficulty: number; // Programming difficulty
volume: number; // Program volume
effort: number; // Programming effort
bugs: number; // Estimated bugs
time: number; // Estimated programming time (seconds)
};
/** Maintainability index (0-100, higher is better) */
maintainability: number;
/** Function parameter count analysis */
params: number;
/** Additional complexity metrics */
// ... other complexity measurements
}Usage Examples:
const complexityReporter = require('plato/lib/reporters/complexity');
// Analyze source code
const sourceCode = `
function calculateSum(a, b, c) {
if (a > 0) {
return a + b + c;
} else {
return b + c;
}
}
`;
const reportInfo = {
file: 'calculator.js',
fileShort: 'calculator.js'
};
const complexityReport = complexityReporter.process(sourceCode, {}, reportInfo);
console.log('Cyclomatic Complexity:', complexityReport.cyclomatic);
console.log('Maintainability Index:', complexityReport.maintainability);
console.log('Physical SLOC:', complexityReport.sloc.physical);
console.log('Logical SLOC:', complexityReport.sloc.logical);
console.log('Halstead Volume:', complexityReport.halstead.volume);Integrates JSHint linting analysis to identify potential issues and coding standard violations in JavaScript code.
/**
* Run JSHint analysis on JavaScript source code
* @param {String} source - JavaScript source code to analyze
* @param {Object} options - JSHint configuration options
* @returns {Object} JSHint analysis report with messages and metadata
*/
function process(source, options);Parameters:
source (String): JavaScript source code to analyzeoptions (Object): JSHint configuration options and rulesReturns: Object - JSHint analysis report
Report Structure:
interface JSHintReport {
/** Array of JSHint messages */
messages: Array<{
/** Message severity level */
severity: 'error' | 'warning' | 'info';
/** Line number where issue occurs */
line: number;
/** Column number where issue occurs */
column: number;
/** Human-readable message describing the issue */
message: string;
/** Source code evidence showing the problematic line */
evidence: string;
/** JSHint rule identifier */
reason?: string;
/** Character position in source */
character?: number;
}>;
}Usage Examples:
const jshintReporter = require('plato/lib/reporters/jshint');
// Analyze with JSHint
const sourceCode = `
function badCode() {
var unused = 1;
undeclaredVar = 2;
return "missing semicolon"
}
`;
const jshintOptions = {
undef: true, // Require variable declarations
unused: true, // Warn about unused variables
asi: false // Require semicolons
};
const jshintReport = jshintReporter.process(sourceCode, jshintOptions);
jshintReport.messages.forEach(msg => {
console.log(`${msg.severity} at line ${msg.line}: ${msg.message}`);
console.log(`Evidence: ${msg.evidence}`);
});
// Example output:
// error at line 3: 'unused' is defined but never used.
// error at line 4: 'undeclaredVar' is not defined.
// error at line 5: Missing semicolon.Integrates ESLint analysis for modern JavaScript linting with configurable rules and comprehensive error reporting.
/**
* Run ESLint analysis on JavaScript source code
* @param {String} source - JavaScript source code to analyze
* @param {Object} options - ESLint configuration options and rules
* @returns {Object} ESLint analysis report with messages and metadata
*/
function process(source, options);Parameters:
source (String): JavaScript source code to analyzeoptions (Object): ESLint configuration options, rules, and environment settingsReturns: Object - ESLint analysis report
Report Structure:
interface ESLintReport {
/** Array of ESLint messages */
messages: Array<{
/** Message severity level */
severity: 'error' | 'warning';
/** Line number where issue occurs */
line: number;
/** Column number where issue occurs */
column: number;
/** Human-readable message describing the issue */
message: string;
/** ESLint rule identifier that triggered the message */
ruleId: string;
/** End line number for multi-line issues */
endLine?: number;
/** End column number for multi-line issues */
endColumn?: number;
/** Node type that triggered the rule */
nodeType?: string;
/** Source code excerpt */
source?: string;
}>;
}Usage Examples:
const eslintReporter = require('plato/lib/reporters/eslint');
// Analyze with ESLint
const sourceCode = `
const unusedVar = 1;
function inconsistentQuotes() {
console.log("double quotes");
console.log('single quotes');
return `template literal`;
}
if(true){
console.log("no spacing");
}
`;
const eslintOptions = {
env: {
es6: true,
node: true
},
rules: {
'no-unused-vars': 'error',
'quotes': ['error', 'single'],
'space-before-blocks': 'error',
'keyword-spacing': 'error'
}
};
const eslintReport = eslintReporter.process(sourceCode, eslintOptions);
eslintReport.messages.forEach(msg => {
console.log(`${msg.severity}: ${msg.message} (${msg.ruleId})`);
console.log(` at line ${msg.line}, column ${msg.column}`);
});
// Example output:
// error: 'unusedVar' is defined but never used. (no-unused-vars)
// at line 2, column 7
// error: Strings must use single quote. (quotes)
// at line 5, column 15The reporters integrate seamlessly with Plato's main analysis workflow:
const plato = require('plato');
// Configure analysis with multiple reporters
plato.inspect(['src/**/*.js'], 'reports', {
// JSHint configuration
jshint: {
node: true,
browser: true,
camelcase: true,
curly: true,
immed: true,
indent: 2,
latedef: true,
newcap: true,
nonew: true,
quotmark: 'single',
undef: true,
unused: true,
strict: true,
maxparams: 4,
maxdepth: 3,
maxcomplexity: 10
},
// ESLint configuration
eslint: {
env: {
node: true,
es6: true
},
extends: ['eslint:recommended'],
rules: {
'no-console': 'warn',
'no-unused-vars': 'error',
'quotes': ['error', 'single'],
'semi': ['error', 'always']
}
}
}, function(reports) {
reports.forEach(report => {
console.log(`\n--- ${report.info.file} ---`);
// Complexity metrics
console.log(`Complexity: ${report.complexity.cyclomatic}`);
console.log(`Maintainability: ${report.complexity.maintainability}`);
// JSHint results
if (report.jshint && report.jshint.messages.length > 0) {
console.log(`JSHint issues: ${report.jshint.messages.length}`);
}
// ESLint results
if (report.eslint && report.eslint.messages.length > 0) {
console.log(`ESLint issues: ${report.eslint.messages.length}`);
}
});
});// Example of using reporters independently
const complexityReporter = require('plato/lib/reporters/complexity');
const jshintReporter = require('plato/lib/reporters/jshint');
const eslintReporter = require('plato/lib/reporters/eslint');
const fs = require('fs');
function analyzeFile(filePath) {
const source = fs.readFileSync(filePath, 'utf8');
const reportInfo = { file: filePath };
// Run all analyses
const complexity = complexityReporter.process(source, {}, reportInfo);
const jshint = jshintReporter.process(source, { undef: true, unused: true });
const eslint = eslintReporter.process(source, {
rules: { 'no-unused-vars': 'error' }
});
return {
file: filePath,
complexity,
jshint,
eslint
};
}
// Analyze specific file
const analysis = analyzeFile('src/app.js');
console.log('Analysis complete:', analysis);Reporter outputs are combined into the final analysis reports:
// Final report structure combining all reporters
const combinedReport = {
info: {
file: 'src/app.js',
fileShort: 'app.js',
// ... other file info
},
// From complexity reporter
complexity: {
cyclomatic: 8,
maintainability: 75.2,
sloc: { physical: 120, logical: 95 },
halstead: { /* ... */ }
},
// From JSHint reporter (if enabled)
jshint: {
messages: [
{ severity: 'error', line: 15, message: 'Undefined variable' }
]
},
// From ESLint reporter (if enabled)
eslint: {
messages: [
{ severity: 'warning', line: 20, ruleId: 'no-console', message: 'Unexpected console statement.' }
]
}
};Reporters handle various error scenarios gracefully:
// Reporters handle malformed JavaScript
const malformedCode = `
function broken() {
if (condition { // Missing closing parenthesis
return true;
}
`;
try {
const report = complexityReporter.process(malformedCode, {}, { file: 'broken.js' });
// Report may contain partial analysis or error information
} catch (error) {
console.error('Analysis failed:', error.message);
}// Reporters validate configuration options
const invalidConfig = {
rules: {
'nonexistent-rule': 'error'
}
};
const report = eslintReporter.process(sourceCode, invalidConfig);
// Report will include configuration error messagesEach reporter is designed to provide useful information even when encountering errors, ensuring that the overall analysis process can continue and provide valuable insights about code quality.
Install with Tessl CLI
npx tessl i tessl/npm-plato