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 | 4x 4x 4x 4x 4x 4x 4x 4x 21x 118x 118x 47x 95x 95x 47x 21x 21x | import type { ParserMessage } from "../schema";
import { randomUUID } from "node:crypto";
import {
type StaticIOAnalysis,
type StaticIOCall,
} from "@shared/io-registry-parser";
function compareDigitalCallOrder(
a: { digitalCalls: StaticIOCall[] },
b: { digitalCalls: StaticIOCall[] },
): number {
const aPinModes = a.digitalCalls.filter(({ op }) => op === "pinMode");
const bPinModes = b.digitalCalls.filter(({ op }) => op === "pinMode");
Iif (aPinModes.length > 0 && bPinModes.length === 0) return -1;
Iif (aPinModes.length === 0 && bPinModes.length > 0) return 1;
const aCalls = aPinModes.length > 0 ? aPinModes : a.digitalCalls;
const bCalls = bPinModes.length > 0 ? bPinModes : b.digitalCalls;
return Math.min(...aCalls.map(({ line }) => line)) -
Math.min(...bCalls.map(({ line }) => line));
}
function pinLabel(pinId: number): string {
return pinId >= 14 ? `A${pinId - 14}` : String(pinId);
}
/**
* Parser for pin conflicts (same pin used as digital and analog)
*
* Rules:
* 1. Digital + analog on same pin
* 2. Multiple conflicts
* 3. Numeric pin notation
*/
export class PinConflictsParser {
constructor(private readonly analysis: StaticIOAnalysis) {}
parse(): ParserMessage[] {
return this.analysis.pins
.map(({ pinId, calls }) => ({
pinId,
digitalCalls: calls.filter(({ op }) =>
op === "pinMode" || op === "digitalRead" || op === "digitalWrite"
),
analogCalls: calls.filter(({ op }) =>
op === "analogRead" || op === "analogWrite"
),
}))
.filter(({ digitalCalls, analogCalls }) =>
digitalCalls.length > 0 && analogCalls.length > 0
)
.sort(compareDigitalCallOrder)
.map(({ pinId, digitalCalls, analogCalls }) => {
// Project-aware calls carry their original file and line. Legacy
// string analysis omits these additive fields for compatibility.
const location = digitalCalls[0] ?? analogCalls[0];
return {
...(location
? { line: location.line, ...(location.file ? { file: location.file } : {}) }
: {}),
id: randomUUID(),
type: "warning" as const,
category: "hardware" as const,
severity: 2 as const,
message: `Pin ${pinLabel(pinId)} used as both digital and analog. This may be unintended.`,
suggestion: "// Use separate pins for digital and analog",
};
});
}
}
|