diff --git a/packages/core/src/annotations.test.ts b/packages/core/src/annotations.test.ts index b034af8f12..e1c6a1759e 100644 --- a/packages/core/src/annotations.test.ts +++ b/packages/core/src/annotations.test.ts @@ -3,7 +3,7 @@ import { parseAnnotations } from "./annotations" import assert from "assert/strict" describe("annotations", () => { - test("error", () => { + test("github", () => { const output = ` ::error file=packages/core/src/github.ts,line=71,endLine=71,code=concatenation_override::The change on line 71 may lead to the original \`text\` content being overridden instead of appending the footer. Consider using \`text = appendGeneratedComment(script, info, text)\` to ensure the original text is preserved and the footer is appended. 😇 @@ -25,4 +25,21 @@ describe("annotations", () => { "The change on line 71 may lead to the original `text` content being overridden instead of appending the footer. Consider using `text = appendGeneratedComment(script, info, text)` to ensure the original text is preserved and the footer is appended. 😇" ) }) + + test("tsc", () => { + const output = ` + +src/annotations.ts:11:28 - error TS1005: ',' expected. + ` + + const diags = parseAnnotations(output) + // console.log(diags) + assert.strictEqual(diags.length, 1) + assert.strictEqual(diags[0].severity, "error") + assert.strictEqual(diags[0].filename, "src/annotations.ts") + assert.strictEqual(diags[0].range[0][0], 10) + assert.strictEqual(diags[0].range[1][0], 27) + assert.strictEqual(diags[0].code, "TS1005") + assert.strictEqual(diags[0].message, "',' expected.") + }) }) diff --git a/packages/core/src/annotations.ts b/packages/core/src/annotations.ts index 1ac67d1171..38b2b39226 100644 --- a/packages/core/src/annotations.ts +++ b/packages/core/src/annotations.ts @@ -1,3 +1,4 @@ +// https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-error-message const GITHUB_ANNOTATIONS_RX = /^\s*::(?notice|warning|error)\s*file=(?[^,]+),\s*line=(?\d+),\s*endLine=(?\d+)\s*(,\s*code=(?[^,:]+)?\s*)?::(?.*)$/gim // ##vso[task.logissue type=warning;sourcepath=consoleap @@ -6,18 +7,38 @@ const GITHUB_ANNOTATIONS_RX = const AZURE_DEVOPS_ANNOTATIONS_RX = /^\s*##vso\[task.logissue\s+type=(?error|warning);sourcepath=(?);linenumber=(?\d+)(;code=(?\d+);)?[^\]]*\](?.*)$/gim +// https://code.visualstudio.com/docs/editor/tasks#_background-watching-tasks +const TYPESCRIPT_ANNOTATIONS_RX = + /^(?[^:\s].*?):(?\d+)(?::(?\d+))?(?::\d+)?\s+-\s+(?error|warning)\s+(?[^:]+)\s*:\s*(?.*)$/gim + /** - * Matches ::(notice|warning|error) file=,line=:: + * Matches TypeScript, GitHub Actions and Azure DevOps annotations * @param line + * @link https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-error-message */ export function parseAnnotations(text: string): Diagnostic[] { if (!text) return [] const sevMap: Record = { + ["info"]: "info", ["notice"]: "info", ["warning"]: "warning", ["error"]: "error", } - const annotations: Record = {} + const annotations = new Set() + for (const m of text.matchAll(TYPESCRIPT_ANNOTATIONS_RX)) { + const { file, line, endLine, severity, code, message } = m.groups + const annotation: Diagnostic = { + severity: sevMap[severity], + filename: file, + range: [ + [parseInt(line) - 1, 0], + [parseInt(endLine) - 1, Number.MAX_VALUE], + ], + message, + code, + } + annotations.add(annotation) + } text.replace( GITHUB_ANNOTATIONS_RX, (_, severity, file, line, endLine, __, code, message) => { @@ -31,12 +52,11 @@ export function parseAnnotations(text: string): Diagnostic[] { message, code, } - const key = JSON.stringify(annotation) - annotations[key] = annotation + annotations.add(annotation) return "" } ) - text?.replace( + text.replace( AZURE_DEVOPS_ANNOTATIONS_RX, (_, severity, file, line, __, code, message) => { const annotation: Diagnostic = { @@ -49,12 +69,11 @@ export function parseAnnotations(text: string): Diagnostic[] { message, code, } - const key = JSON.stringify(annotation) - annotations[key] = annotation + annotations.add(annotation) return "" } ) - return Object.values(annotations) + return Array.from(annotations.values()) } export function convertDiagnosticToGitHubActionCommand(d: Diagnostic) {