diff --git a/src/processor.ts b/src/processor.ts index ebe77ad..0460d2b 100644 --- a/src/processor.ts +++ b/src/processor.ts @@ -274,6 +274,52 @@ parse("", {}); ]; } +function sourceMapMessages( + messages: ESlint.Linter.LintMessage[], + map: SourceChain +): ESlint.Linter.LintMessage[] { + const res: ESlint.Linter.LintMessage[] = []; + for (const msg of messages) { + debug("Before: %o", msg); + const start = map.originalLocation({ + line: msg.line, + column: msg.column - 1, // Map is 0-based cols + }, Bias.ERROR); + debug("Start: %o", start); + if (start) { + msg.line = start.line; + msg.column = start.column + 1; // Message is 1-based cols + } else { + debug("Cound't find start location column: %d line %d", msg.line, msg.column); + continue; + } + + const end + = (typeof msg.endLine === "number") && (typeof msg.endColumn === "number") + ? map.originalLocation({ + line: msg.endLine, + column: msg.endColumn - 1, // Map is 0-based cols + }, Bias.GREATEST_LOWER_BOUND) + : null; + if (end) { + msg.endLine = end.line; + msg.endColumn = end.column + 1; // Message is 1-based cols + } else { + debug("Cound't find end location column: %d line %d", msg.endLine, msg.endColumn); + continue; + } + if (msg.fix) { + msg.fix.range = [ + map.originalOffset(msg.fix.range[0], Bias.LEAST_UPPER_BOUND), + map.originalOffset(msg.fix.range[1], Bias.GREATEST_LOWER_BOUND), + ]; + } + debug("After: %o", msg); + res.push(msg); + } + return res; +} + /** * Put all of the line/column numbers back into the original file. * @@ -292,45 +338,7 @@ export function postprocess( return [ ...messages[0], - ...messages[1].map(msg => { - debug("Before: %o", msg); - const start = map.originalLocation({ - line: msg.line, - column: msg.column - 1, // Map is 0-based cols - }, Bias.LEAST_UPPER_BOUND); - if (start) { - msg.line = start.line; - msg.column = start.column + 1; // Message is 1-based cols - } else { - msg.line = 1; - msg.column = 1; - debug("Cound't find start location column: %d line %d", msg.line, msg.column); - } - - const end - = (typeof msg.endLine === "number") && (typeof msg.endColumn === "number") - ? map.originalLocation({ - line: msg.endLine, - column: msg.endColumn - 1, // Map is 0-based cols - }, Bias.GREATEST_LOWER_BOUND) - : null; - if (end) { - msg.endLine = end.line; - msg.endColumn = end.column + 1; // Message is 1-based cols - } else { - debug("Cound't find end location column: %d line %d", msg.endLine, msg.endColumn); - msg.endLine = undefined; - msg.endColumn = undefined; - } - if (msg.fix) { - msg.fix.range = [ - map.originalOffset(msg.fix.range[0], Bias.LEAST_UPPER_BOUND), - map.originalOffset(msg.fix.range[1], Bias.GREATEST_LOWER_BOUND), - ]; - } - debug("After: %o", msg); - return msg; - }), + ...sourceMapMessages(messages[1], map), ]; } diff --git a/src/sourcechain.ts b/src/sourcechain.ts index 6d433c7..e844fdb 100644 --- a/src/sourcechain.ts +++ b/src/sourcechain.ts @@ -33,6 +33,10 @@ export enum Bias { * *next* non-boilerplate block. */ GREATEST_LOWER_BOUND = 1, + /** + * If the position specified is in the boilerplate text, return null. + */ + ERROR = 2, } /** @@ -170,6 +174,9 @@ export class SourceChain { // Now we're sure we've got the right block if (!block.loc) { // But it's in the generated section. + if (bias === Bias.ERROR) { + return null; + } // Do we want the end of the previous block? if ((bias === Bias.LEAST_UPPER_BOUND) && prev?.loc) { if (prev.tail) { diff --git a/test/processor.test.js b/test/processor.test.js index 05ab0a1..85b4b65 100644 --- a/test/processor.test.js +++ b/test/processor.test.js @@ -20,45 +20,58 @@ foo }); it("post-processes", () => { - const messages = [[], [{ - ruleId: "semi", - severity: 2, - message: "Semicolon required", - line: 300, - column: 26, - endLine: 4, - endColumn: 1, - }, { - ruleId: "no-unused-vars", - severity: 2, - message: "'o' is defined but never used.", - line: 31, - column: 19, - nodeType: "Identifier", - messageId: "unusedVar", - endLine: 31, - endColumn: 20, - }, { - ruleId: "no-unused-vars", - severity: 2, - message: "'t' is defined but never used.", - line: 31, - column: 22, - nodeType: "Identifier", - messageId: "unusedVar", - endLine: 31, - endColumn: 23, - }, { - ruleId: "example", - severity: 2, - message: "No end in sight", - line: 31, - column: 22, - nodeType: "none", - }]]; + const messages = [[], [ + { + ruleId: "semi", + severity: 2, + message: "Semicolon required", + line: 3, + column: 24, + endLine: 4, + endColumn: 1, + }, + { + ruleId: "no-unused-vars", + severity: 2, + message: "'o' is defined but never used.", + line: 31, + column: 5, + nodeType: "Identifier", + messageId: "unusedVar", + endLine: 31, + endColumn: 6, + }, + { + ruleId: "no-unused-vars", + severity: 2, + message: "'t' is defined but never used.", + line: 32, + column: 5, + nodeType: "Identifier", + messageId: "unusedVar", + endLine: 32, + endColumn: 6, + }, + { + ruleId: "example", + severity: 2, + message: "No end in sight", + line: 32, + column: 5, + nodeType: "none", + }, + { + ruleId: "example2", + severity: 2, + message: "Invalid start", + line: 1, + column: 1, + nodeType: "none", + }, + ]]; const mapped = processor.postprocess(messages, "processor.peggy"); - assert.equal(mapped.length, messages[1].length); + assert.equal(mapped.length, messages[1].length - 2); assert.throws(() => processor.postprocess(messages, "NOT_VALID"), /Map not found/); }); @@ -87,8 +100,8 @@ num = n:$[0-9]+ { return parseInt(n, BASE); } ruleId: "semi", severity: 2, message: "Missing semicolon.", - line: 24, - column: 34, + line: 3, + column: 32, nodeType: "VariableDeclaration", messageId: "missingSemi", endLine: 25,