Skip to content

Commit b38c2d0

Browse files
committed
feat(linter/plugins): add SourceCode#lineStartIndices getter (#16510)
Add a getter `lineStartIndices` to `SourceCode`. ESLint has this property, but it's undocumented. Possible that some ESLint plugins rely on it (if it's there, people will use it!).
1 parent 4fdbacf commit b38c2d0

File tree

4 files changed

+26
-4
lines changed

4 files changed

+26
-4
lines changed

apps/oxlint/src-js/plugins/location.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const LINE_BREAK_PATTERN = /\r\n|[\r\n\u2028\u2029]/gu;
5757
// Lazily populated when `SOURCE_CODE.lines` is accessed.
5858
// `lineStartIndices` starts as `[0]`, and `resetLines` doesn't remove that initial element, so it's never empty.
5959
export const lines: string[] = [];
60-
const lineStartIndices: number[] = [0];
60+
export const lineStartIndices: number[] = [0];
6161

6262
/**
6363
* Split source text into lines.

apps/oxlint/src-js/plugins/source_code.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
getOffsetFromLineColumn,
1515
initLines,
1616
lines,
17+
lineStartIndices,
1718
resetLines,
1819
} from "./location.ts";
1920
import { resetScopeManager, SCOPE_MANAGER } from "./scope.ts";
@@ -180,6 +181,15 @@ export const SOURCE_CODE = Object.freeze({
180181
return lines;
181182
},
182183

184+
/**
185+
* Character offset of the first character of each line in source text,
186+
* split according to specification's definition of line breaks.
187+
*/
188+
get lineStartIndices(): number[] {
189+
if (lines.length === 0) initLines();
190+
return lineStartIndices;
191+
},
192+
183193
/**
184194
* Array of all tokens and comments in the file, in source order.
185195
*/

apps/oxlint/test/fixtures/sourceCode/output.snap.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
| text: "let foo, bar;\n\n// x\n// y\n"
88
| getText(): "let foo, bar;\n\n// x\n// y\n"
99
| lines: ["let foo, bar;","","// x","// y",""]
10+
| lineStartIndices: [0,14,15,20,25]
1011
| locs:
1112
| 0 => { line: 1, column: 0 }("l")
1213
| 1 => { line: 1, column: 1 }("e")
@@ -55,6 +56,7 @@
5556
| text: "let foo, bar;\n\n// x\n// y\n"
5657
| getText(): "let foo, bar;\n\n// x\n// y\n"
5758
| lines: ["let foo, bar;","","// x","// y",""]
59+
| lineStartIndices: [0,14,15,20,25]
5860
| locs:
5961
| 0 => { line: 1, column: 0 }("l")
6062
| 1 => { line: 1, column: 1 }("e")
@@ -163,6 +165,7 @@
163165
| text: "let qux;\n"
164166
| getText(): "let qux;\n"
165167
| lines: ["let qux;",""]
168+
| lineStartIndices: [0,9]
166169
| locs:
167170
| 0 => { line: 1, column: 0 }("l")
168171
| 1 => { line: 1, column: 1 }("e")
@@ -193,6 +196,7 @@
193196
| text: "let qux;\n"
194197
| getText(): "let qux;\n"
195198
| lines: ["let qux;",""]
199+
| lineStartIndices: [0,9]
196200
| locs:
197201
| 0 => { line: 1, column: 0 }("l")
198202
| 1 => { line: 1, column: 1 }("e")

apps/oxlint/test/fixtures/sourceCode/plugin.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ const SPAN: Node = {
1616

1717
const createRule: Rule = {
1818
create(context) {
19-
const { sourceCode } = context,
20-
{ ast, lines, text } = sourceCode;
19+
const { sourceCode } = context;
20+
21+
// Get these first to check they work before `sourceText` or `ast` are accessed
22+
const { lineStartIndices, lines } = sourceCode;
23+
const { ast, text } = sourceCode;
2124

2225
assert(context.getSourceCode() === sourceCode);
2326

@@ -36,6 +39,7 @@ const createRule: Rule = {
3639
`text: ${JSON.stringify(text)}\n` +
3740
`getText(): ${JSON.stringify(sourceCode.getText())}\n` +
3841
`lines: ${JSON.stringify(lines)}\n` +
42+
`lineStartIndices: ${JSON.stringify(lineStartIndices)}\n` +
3943
`locs:${locs}\n` +
4044
// @ts-ignore
4145
`ast: "${ast.body[0].declarations[0].id.name}"\n` +
@@ -83,8 +87,11 @@ const createOnceRule: Rule = {
8387
return {
8488
before() {
8589
const { sourceCode } = context;
90+
91+
// Get these first to check they work before `sourceText` or `ast` are accessed
92+
const { lineStartIndices, lines } = sourceCode;
8693
ast = sourceCode.ast;
87-
const { lines, text } = sourceCode;
94+
const { text } = sourceCode;
8895

8996
let locs = "";
9097
for (let offset = 0; offset <= text.length; offset++) {
@@ -101,6 +108,7 @@ const createOnceRule: Rule = {
101108
`text: ${JSON.stringify(text)}\n` +
102109
`getText(): ${JSON.stringify(sourceCode.getText())}\n` +
103110
`lines: ${JSON.stringify(lines)}\n` +
111+
`lineStartIndices: ${JSON.stringify(lineStartIndices)}\n` +
104112
`locs:${locs}\n` +
105113
// @ts-ignore
106114
`ast: "${ast.body[0].declarations[0].id.name}"\n` +

0 commit comments

Comments
 (0)