All files / src/analyzers patterns.ts

87.75% Statements 86/98
78.4% Branches 69/88
90.9% Functions 10/11
85.54% Lines 71/83

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82              5x     6x 11x     6x 5x 6x   11x 11x   11x     6x 36x 36x 36x   36x 35x 30x 5x 60x 35x 61x 11x   30x     36x 10x 32x 36x 6x 2x   30x 35x     22x 5x             6x   2x     2x   30x 30x         7x       5x   11x    
import { readFileSync } from 'fs';
import { Severity } from '@aiready/core';
import type { PatternIssue } from '../types';
 
/**
 * Detect inconsistent code patterns across files
 */
export async function analyzePatterns(
  filePaths: string[]
): Promise<PatternIssue[]> {
  const issues: PatternIssue[] = [];
  const contents = new Map<string, string>();
 
  // 1. Error handling style
  const tryCatchPattern = /try\s*\{/g;
 
  const styleStats = {
    tryCatch: 0,
    thenCatch: 0,
    asyncAwait: 0,
    commonJs: 0,
    esm: 0,
  };
 
  for (const filePath of filePaths) {
    try {
      const content = readFileSync(filePath, 'utf-8');
      contents.set(filePath, content);
 
      if (content.match(tryCatchPattern)) styleStats.tryCatch++;
      if (content.match(/\.catch\s*\(/)) styleStats.thenCatch++;
      if (content.match(/\bawait\b/)) styleStats.asyncAwait++;
 
      if (content.match(/\brequire\s*\(/)) styleStats.commonJs++;
      if (content.match(/\bimport\b.*\bfrom\b/)) styleStats.esm++;
    } catch (err) {
      void err;
    }
  }I

  // Report inconsistencies if there's a significant mix
  if (styleStats.tryCatch > 0 && styleStats.thenCatch > 0) {
    const dominant =
      styleStats.tryCatch >= styleStats.thenCatch ? 'try-catch' : '.catch()';
    const minority = dominant === 'try-catch' ? '.catch()' : 'try-catch';
 
    issues.push({
      files: filePaths.filter((f) => {
        const c = contents.get(f) || '';
        return minority === 'try-catch'
          ? c.match(tryCatchPattern)
          : c.match(/\.catch\s*\(/);
      }),
  I    type: 'pattern-inconsistency',
      description: `Mixed error handling styles: codebase primarily uses ${dominant}, but found ${minority} in some files.`,
      examples: [dominant, minority],
      severity: Severity.Minor,
    });
  }
 
  if (styleStats.commonJs > 0 && styleStats.esm > 0) {
    const minority =
      styleStats.esm >= styleStats.commonJs
        ? 'CommonJS (require)'
        : 'ESM (import)';
    issues.push({
      files: filePaths.filter((f) => {
        const c = contents.get(f) || '';
        return minority === 'CommonJS (require)'
          ? c.match(/\brequire\s*\(/)
          : c.match(/\bimport\b/);
      }),
      type: 'pattern-inconsistency',
      description: `Mixed module systems: found both ESM and CommonJS.`,
      examples: ['import X from "y"', 'const X = require("y")'],
      severity: Severity.Major,
    });
  }
 
  return issues;
}