All files / shared code-parser.ts

100% Statements 18/18
83.33% Branches 5/6
100% Functions 8/8
100% Lines 18/18

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 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107                                        178x 178x             115x 115x             113x 113x                   131x 131x                   118x 118x             112x 112x   112x                   8x 8x                           91x 91x 91x                    
import type { ParserMessage } from "./schema";
import { stripComments } from "@shared/parser-patterns";
import { SerialConfigurationParser } from "./parsers/serial-configuration-parser";
import { StructureParser } from "./parsers/structure-parser";
import { PerformanceParser } from "./parsers/performance-parser";
import { HardwareCompatibilityParser } from "./parsers/hardware-compatibility-parser";
import { PinConflictsParser } from "./parsers/pin-conflicts-parser";
import {
  analyzeStaticIO,
  analyzeStaticIOProject,
  type StaticIOAnalysis,
  type StaticIOProjectAnalysis,
} from "./io-registry-parser";
import type { SourceProject } from "./source-project";
 
type StaticIOAnalyzer = (code: string) => StaticIOAnalysis;
type StaticIOProjectAnalyzer = (project: SourceProject) => StaticIOProjectAnalysis;
 
export class CodeParser {
  constructor(
    private readonly analyzeIO: StaticIOAnalyzer = analyzeStaticIO,
    private readonly analyzeIOProject: StaticIOProjectAnalyzer = analyzeStaticIOProject,
  ) {}
 
  /**
   * Parse Serial configuration issues
   */
  parseSerialConfiguration(code: string): ParserMessage[] {
    const parser = new SerialConfigurationParser(code);
    return parser.parse();
  }
 
  /**
   * Parse structure issues (setup/loop)
   */
  parseStructure(code: string): ParserMessage[] {
    const parser = new StructureParser(code);
    return parser.parse();
  }
 
  /**
   * Parse hardware compatibility issues
   */
  parseHardwareCompatibility(
    code: string,
    analysis: StaticIOAnalysis = this.analyzeIO(code),
  ): ParserMessage[] {
    const parser = new HardwareCompatibilityParser(analysis);
    return parser.parse();
  }
 
  /**
   * Parse pin conflicts (same pin used as digital and analog)
   */
  parsePinConflicts(
    code: string,
    analysis: StaticIOAnalysis = this.analyzeIO(code),
  ): ParserMessage[] {
    const parser = new PinConflictsParser(analysis);
    return parser.parse();
  }
 
  /**
   * Parse performance issues
   */
  parsePerformance(code: string): ParserMessage[] {
    const uncommentedCode = stripComments(code);
    const parser = new PerformanceParser(uncommentedCode, code);
 
    return [
      ...parser.analyzeComplexity(),
      ...parser.analyzeLargeArraysAndRecursion(),
    ];
  }
 
  /**
   * Parse all categories and combine results
   */
  parseAll(code: string): ParserMessage[] {
    const analysis = this.analyzeIO(code);
    return [
      ...this.parseSerialConfiguration(code),
      ...this.parseStructure(code),
      ...this.parseHardwareCompatibility(code, analysis),
      ...this.parsePinConflicts(code, analysis),
      ...this.parsePerformance(code),
    ];
  }
 
  /**
   * Parse a project using one include-resolved static I/O analysis. Structure,
   * serial, and performance checks intentionally remain entry-file scoped.
   */
  parseAllProject(project: SourceProject): ParserMessage[] {
    const entryCode = project.files[project.entryFile] ?? "";
    const analysis = this.analyzeIOProject(project);
    return [
      ...this.parseSerialConfiguration(entryCode),
      ...this.parseStructure(entryCode),
      ...this.parseHardwareCompatibility(entryCode, analysis),
      ...this.parsePinConflicts(entryCode, analysis),
      ...this.parsePerformance(entryCode),
    ];
  }
 
}