diff --git a/apps/oxlint/src-js/plugins/location.ts b/apps/oxlint/src-js/plugins/location.ts index 824db9983c334..030e5dfa9d68b 100644 --- a/apps/oxlint/src-js/plugins/location.ts +++ b/apps/oxlint/src-js/plugins/location.ts @@ -57,7 +57,7 @@ const LINE_BREAK_PATTERN = /\r\n|[\r\n\u2028\u2029]/gu; // Lazily populated when `SOURCE_CODE.lines` is accessed. // `lineStartIndices` starts as `[0]`, and `resetLines` doesn't remove that initial element, so it's never empty. export const lines: string[] = []; -const lineStartIndices: number[] = [0]; +export const lineStartIndices: number[] = [0]; /** * Split source text into lines. diff --git a/apps/oxlint/src-js/plugins/source_code.ts b/apps/oxlint/src-js/plugins/source_code.ts index 89d006b132f98..abb0efd84f249 100644 --- a/apps/oxlint/src-js/plugins/source_code.ts +++ b/apps/oxlint/src-js/plugins/source_code.ts @@ -14,6 +14,7 @@ import { getOffsetFromLineColumn, initLines, lines, + lineStartIndices, resetLines, } from "./location.ts"; import { resetScopeManager, SCOPE_MANAGER } from "./scope.ts"; @@ -180,6 +181,15 @@ export const SOURCE_CODE = Object.freeze({ return lines; }, + /** + * Character offset of the first character of each line in source text, + * split according to specification's definition of line breaks. + */ + get lineStartIndices(): number[] { + if (lines.length === 0) initLines(); + return lineStartIndices; + }, + /** * Array of all tokens and comments in the file, in source order. */ diff --git a/apps/oxlint/test/fixtures/sourceCode/output.snap.md b/apps/oxlint/test/fixtures/sourceCode/output.snap.md index 78a889d991d89..edbd93ac7217c 100644 --- a/apps/oxlint/test/fixtures/sourceCode/output.snap.md +++ b/apps/oxlint/test/fixtures/sourceCode/output.snap.md @@ -7,6 +7,7 @@ | text: "let foo, bar;\n\n// x\n// y\n" | getText(): "let foo, bar;\n\n// x\n// y\n" | lines: ["let foo, bar;","","// x","// y",""] + | lineStartIndices: [0,14,15,20,25] | locs: | 0 => { line: 1, column: 0 }("l") | 1 => { line: 1, column: 1 }("e") @@ -55,6 +56,7 @@ | text: "let foo, bar;\n\n// x\n// y\n" | getText(): "let foo, bar;\n\n// x\n// y\n" | lines: ["let foo, bar;","","// x","// y",""] + | lineStartIndices: [0,14,15,20,25] | locs: | 0 => { line: 1, column: 0 }("l") | 1 => { line: 1, column: 1 }("e") @@ -163,6 +165,7 @@ | text: "let qux;\n" | getText(): "let qux;\n" | lines: ["let qux;",""] + | lineStartIndices: [0,9] | locs: | 0 => { line: 1, column: 0 }("l") | 1 => { line: 1, column: 1 }("e") @@ -193,6 +196,7 @@ | text: "let qux;\n" | getText(): "let qux;\n" | lines: ["let qux;",""] + | lineStartIndices: [0,9] | locs: | 0 => { line: 1, column: 0 }("l") | 1 => { line: 1, column: 1 }("e") diff --git a/apps/oxlint/test/fixtures/sourceCode/plugin.ts b/apps/oxlint/test/fixtures/sourceCode/plugin.ts index f9150ebec4982..d610a0b9478dd 100644 --- a/apps/oxlint/test/fixtures/sourceCode/plugin.ts +++ b/apps/oxlint/test/fixtures/sourceCode/plugin.ts @@ -16,8 +16,11 @@ const SPAN: Node = { const createRule: Rule = { create(context) { - const { sourceCode } = context, - { ast, lines, text } = sourceCode; + const { sourceCode } = context; + + // Get these first to check they work before `sourceText` or `ast` are accessed + const { lineStartIndices, lines } = sourceCode; + const { ast, text } = sourceCode; assert(context.getSourceCode() === sourceCode); @@ -36,6 +39,7 @@ const createRule: Rule = { `text: ${JSON.stringify(text)}\n` + `getText(): ${JSON.stringify(sourceCode.getText())}\n` + `lines: ${JSON.stringify(lines)}\n` + + `lineStartIndices: ${JSON.stringify(lineStartIndices)}\n` + `locs:${locs}\n` + // @ts-ignore `ast: "${ast.body[0].declarations[0].id.name}"\n` + @@ -83,8 +87,11 @@ const createOnceRule: Rule = { return { before() { const { sourceCode } = context; + + // Get these first to check they work before `sourceText` or `ast` are accessed + const { lineStartIndices, lines } = sourceCode; ast = sourceCode.ast; - const { lines, text } = sourceCode; + const { text } = sourceCode; let locs = ""; for (let offset = 0; offset <= text.length; offset++) { @@ -101,6 +108,7 @@ const createOnceRule: Rule = { `text: ${JSON.stringify(text)}\n` + `getText(): ${JSON.stringify(sourceCode.getText())}\n` + `lines: ${JSON.stringify(lines)}\n` + + `lineStartIndices: ${JSON.stringify(lineStartIndices)}\n` + `locs:${locs}\n` + // @ts-ignore `ast: "${ast.body[0].declarations[0].id.name}"\n` +