CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-plato

JavaScript source analysis and visualizer that generates detailed complexity reports

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

models.mddocs/

History and Models

Data models for tracking code quality metrics over time and maintaining historical analysis data. These models provide the foundation for trend analysis and longitudinal code quality reporting.

Capabilities

Base History Model

Foundation class for tracking analysis data over time with basic operations for adding and retrieving historical entries.

/**
 * Base history tracking model for analysis data over time
 * @param {Array} data - Initial history data (optional)
 */
class History {
  constructor(data);
  
  /** Number of history entries */
  length: number;
  
  /**
   * Add entry to history
   * @param {Object} obj - Object to add to history
   */
  push(obj): void;
  
  /**
   * Convert history to JSON array
   * @returns {Array} JSON representation of history
   */
  toJSON(): Array;
}

Constructor Parameters:

  • data (Array, optional): Initial history data to populate the instance

Properties:

  • length (Number): Number of entries currently stored in history

Methods:

  • push(obj): Add a new entry to the history
  • toJSON(): Convert the entire history to a JSON-serializable array

Usage Examples:

const History = require('plato/lib/models/History');

// Create new history
const history = new History();

// Add entries
history.push({ date: '2024-01-01', complexity: 5.2 });
history.push({ date: '2024-01-02', complexity: 4.8 });

console.log(history.length); // 2

// Convert to JSON
const jsonHistory = history.toJSON();
console.log(jsonHistory); // [{ date: '2024-01-01', complexity: 5.2 }, ...]

// Initialize with existing data
const existingData = [
  { date: '2024-01-01', value: 100 },
  { date: '2024-01-02', value: 95 }
];
const populatedHistory = new History(existingData);
console.log(populatedHistory.length); // 2

Overview History Model

Specialized history tracking for project-wide overview reports with aggregated metrics across all analyzed files.

/**
 * History tracking for overview reports (extends History)
 * @param {Array} data - Initial history data (optional)
 */
class OverviewHistory extends History {
  constructor(data);
  
  /**
   * Add overview report to history with timestamp
   * @param {Object} report - Overview report object
   * @param {String} date - Report date (optional, defaults to current date)
   */
  addReport(report, date): void;
}

Constructor Parameters:

  • data (Array, optional): Initial overview history data

Methods:

  • addReport(report, date): Add an overview report with automatic timestamping

Usage Examples:

const OverviewHistory = require('plato/lib/models/OverviewHistory');

// Create overview history
const overviewHistory = new OverviewHistory();

// Add overview reports
const overviewReport = {
  summary: {
    total: { sloc: 1000, maintainability: 85.5 },
    average: { sloc: 50, maintainability: 85.5 }
  },
  reports: []
};

overviewHistory.addReport(overviewReport, '2024-01-01');
overviewHistory.addReport(overviewReport, '2024-01-02');

// Track trends over time
const history = overviewHistory.toJSON();
history.forEach(entry => {
  console.log(`${entry.date}: ${entry.summary.average.maintainability} maintainability`);
});

// Initialize with existing overview data
const existingOverviews = [
  { date: '2024-01-01', summary: { average: { maintainability: 85 } } }
];
const preloadedHistory = new OverviewHistory(existingOverviews);

File History Model

Specialized history tracking for individual file analysis reports with file-specific metrics over time.

/**
 * History tracking for individual file reports (extends History)
 * @param {Array} data - Initial history data (optional)
 */
class FileHistory extends History {
  constructor(data);
  
  /**
   * Add file analysis report to history with timestamp
   * @param {Object} report - File analysis report object
   * @param {String} date - Report date (optional, defaults to current date)
   */
  addReport(report, date): void;
}

Constructor Parameters:

  • data (Array, optional): Initial file history data

Methods:

  • addReport(report, date): Add a file analysis report with automatic timestamping

Usage Examples:

const FileHistory = require('plato/lib/models/FileHistory');

// Create file history
const fileHistory = new FileHistory();

// Add file reports
const fileReport = {
  info: { file: 'src/app.js' },
  complexity: {
    cyclomatic: 8,
    maintainability: 82.5,
    sloc: { physical: 150, logical: 120 }
  }
};

fileHistory.addReport(fileReport, '2024-01-01');
fileHistory.addReport(fileReport, '2024-01-02');

// Analyze file trends
const fileHistoryData = fileHistory.toJSON();
fileHistoryData.forEach(entry => {
  console.log(`${entry.date}: Complexity ${entry.complexity.cyclomatic}`);
});

// Load existing file history
const existingFileData = [
  { date: '2024-01-01', complexity: { cyclomatic: 5 } }
];
const existingFileHistory = new FileHistory(existingFileData);

Integration with Analysis Workflow

These models integrate with Plato's analysis workflow to provide historical tracking:

Overview Tracking

const plato = require('plato');
const OverviewHistory = require('plato/lib/models/OverviewHistory');

// Load existing overview history
const overviewHistory = new OverviewHistory();

// Perform analysis
plato.inspect(['src/**/*.js'], 'reports', {}, function(reports) {
  // Generate overview
  const overview = plato.getOverviewReport(reports);
  
  // Add to history
  const today = new Date().toISOString().split('T')[0];
  overviewHistory.addReport(overview, today);
  
  // Save history for future runs
  const historyData = overviewHistory.toJSON();
  require('fs').writeFileSync('overview-history.json', JSON.stringify(historyData));
});

File-Level Tracking

const plato = require('plato');
const FileHistory = require('plato/lib/models/FileHistory');

// Track individual files over time
const fileHistories = new Map();

plato.inspect(['src/**/*.js'], 'reports', {}, function(reports) {
  const today = new Date().toISOString().split('T')[0];
  
  reports.forEach(report => {
    const fileName = report.info.file;
    
    // Get or create history for this file
    if (!fileHistories.has(fileName)) {
      fileHistories.set(fileName, new FileHistory());
    }
    
    const fileHistory = fileHistories.get(fileName);
    fileHistory.addReport(report, today);
  });
  
  // Identify files with increasing complexity
  fileHistories.forEach((history, fileName) => {
    const entries = history.toJSON();
    if (entries.length >= 2) {
      const latest = entries[entries.length - 1];
      const previous = entries[entries.length - 2];
      
      if (latest.complexity.cyclomatic > previous.complexity.cyclomatic) {
        console.log(`${fileName}: Complexity increased from ${previous.complexity.cyclomatic} to ${latest.complexity.cyclomatic}`);
      }
    }
  });
});

Data Persistence

The models are designed to work with persistent storage for long-term trend analysis:

JSON Serialization

const OverviewHistory = require('plato/lib/models/OverviewHistory');
const fs = require('fs');

// Save history
function saveHistory(history, filename) {
  const data = history.toJSON();
  fs.writeFileSync(filename, JSON.stringify(data, null, 2));
}

// Load history
function loadHistory(filename, HistoryClass) {
  if (fs.existsSync(filename)) {
    const data = JSON.parse(fs.readFileSync(filename, 'utf8'));
    return new HistoryClass(data);
  }
  return new HistoryClass();
}

// Usage
const overviewHistory = loadHistory('overview.json', OverviewHistory);
// ... perform analysis and add reports ...
saveHistory(overviewHistory, 'overview.json');

Database Integration

// Example database integration
class DatabaseHistory extends History {
  constructor(tableName) {
    super();
    this.tableName = tableName;
    this.loadFromDatabase();
  }
  
  async loadFromDatabase() {
    // Load history from database
    const rows = await db.query(`SELECT * FROM ${this.tableName} ORDER BY date`);
    rows.forEach(row => this.push(row));
  }
  
  async push(obj) {
    super.push(obj);
    // Also save to database
    await db.query(`INSERT INTO ${this.tableName} VALUES (?, ?)`, [obj.date, JSON.stringify(obj)]);
  }
}

Historical Analysis Patterns

Common patterns for analyzing historical data:

Trend Analysis

function analyzeTrends(history) {
  const data = history.toJSON();
  
  if (data.length < 2) return null;
  
  const latest = data[data.length - 1];
  const previous = data[data.length - 2];
  
  return {
    maintainabilityTrend: latest.complexity.maintainability - previous.complexity.maintainability,
    complexityTrend: latest.complexity.cyclomatic - previous.complexity.cyclomatic,
    slocTrend: latest.complexity.sloc.logical - previous.complexity.sloc.logical
  };
}

Quality Gates

function checkQualityGates(overviewHistory) {
  const data = overviewHistory.toJSON();
  const latest = data[data.length - 1];
  
  const alerts = [];
  
  if (latest.summary.average.maintainability < 70) {
    alerts.push('Low maintainability detected');
  }
  
  if (data.length >= 2) {
    const previous = data[data.length - 2];
    const maintainabilityChange = latest.summary.average.maintainability - previous.summary.average.maintainability;
    
    if (maintainabilityChange < -5) {
      alerts.push('Significant maintainability decrease');
    }
  }
  
  return alerts;
}

Install with Tessl CLI

npx tessl i tessl/npm-plato

docs

cli-api.md

index.md

models.md

programmatic-api.md

reporters.md

utilities.md

tile.json