77
88/**
99 * @import {AST, ESLint, Linter, Rule, SourceCode} from 'eslint'
10+ * @import {Position} from 'estree'
1011 * @import {FileInfoOptions, Options as PrettierOptions} from 'prettier'
1112 * @import {Difference} from 'prettier-linter-helpers'
1213 */
1314
1415/**
15- * @typedef {{ line: number; column: number; offset: number } } Location
16- *
1716 * @typedef {PrettierOptions & {
1817 * onDiskFilepath: string;
1918 * parserMeta?: ESLint.ObjectMetaProperties['meta'];
2726 * options: Options,
2827 * fileInfoOptions: FileInfoOptions,
2928 * ) => string} PrettierFormat
30- *
31- *
32- * @typedef {Parameters<
33- * Exclude<ESLint.Plugin['rules'], undefined>[string]['create']
34- * >[0]} RuleContext
3529 */
3630
3731'use strict' ;
@@ -64,29 +58,46 @@ let prettierFormat;
6458// Rule Definition
6559// ------------------------------------------------------------------------------
6660
61+ /** @type {WeakMap<SourceCode, number[]> } */
62+ const lineIndexesCache = new WeakMap ( ) ;
63+
6764/**
68- * Converts a byte offset to a Location .
65+ * Ponyfill `sourceCode.getLocFromIndex` when it's unavailable .
6966 *
7067 * See also `getLocFromIndex` in `@eslint/js`.
7168 *
72- * @param {number[] } lineIndexes
73- * @param {number } offset
74- * @returns {Location }
69+ * @param {SourceCode } sourceCode
70+ * @param {number } index
71+ * @returns {Position }
7572 */
76- function getLocFromOffset ( lineIndexes , offset ) {
73+ function getLocFromIndex ( sourceCode , index ) {
74+ if ( typeof sourceCode . getLocFromIndex === 'function' ) {
75+ return sourceCode . getLocFromIndex ( index ) ;
76+ }
77+
78+ let lineIndexes = lineIndexesCache . get ( sourceCode ) ;
79+ if ( ! lineIndexes ) {
80+ lineIndexes = [ ...sourceCode . text . matchAll ( / \r ? \n / g) ] . map (
81+ match => match . index ,
82+ ) ;
83+ // first line in the file starts at byte offset 0
84+ lineIndexes . unshift ( 0 ) ;
85+ lineIndexesCache . set ( sourceCode , lineIndexes ) ;
86+ }
87+
7788 let line = 0 ;
78- while ( line + 1 < lineIndexes . length && lineIndexes [ line + 1 ] < offset ) {
89+ while ( line + 1 < lineIndexes . length && lineIndexes [ line + 1 ] < index ) {
7990 line += 1 ;
8091 }
92+ const column = index - lineIndexes [ line ] ;
8193
82- const column = offset - lineIndexes [ line ] ;
83- return { line : line + 1 , column, offset } ;
94+ return { line : line + 1 , column } ;
8495}
8596
8697/**
8798 * Reports a difference.
8899 *
89- * @param {RuleContext } context - The ESLint rule context.
100+ * @param {Rule. RuleContext } context - The ESLint rule context.
90101 * @param {Difference } difference - The difference object.
91102 * @returns {void }
92103 */
@@ -99,38 +110,7 @@ function reportDifference(context, difference) {
99110 // TODO: Only use property when our eslint peerDependency is >=8.40.0.
100111 const sourceCode = context . sourceCode ?? context . getSourceCode ( ) ;
101112
102- const lazy = {
103- /**
104- * Lazily computes the line indices for `sourceCode`.
105- *
106- * @returns {number[] }
107- */
108- get lineIndexes ( ) {
109- // @ts -ignore
110- delete this . lineIndexes ;
111-
112- if ( ! ( 'text' in sourceCode ) ) {
113- throw new Error (
114- 'prettier/prettier: non-textual source code is unsupported' ,
115- ) ;
116- }
117-
118- // @ts -ignore
119- this . lineIndexes = [ ...sourceCode . text . matchAll ( / \n / g) ] . map (
120- match => match . index ,
121- ) ;
122- // first line in the file starts at byte offset 0
123- this . lineIndexes . unshift ( 0 ) ;
124- return this . lineIndexes ;
125- } ,
126- } ;
127-
128- const [ start , end ] = range . map (
129- index =>
130- // @ts -ignore
131- sourceCode . getLocFromIndex ?. ( index ) ??
132- getLocFromOffset ( lazy . lineIndexes , index ) ,
133- ) ;
113+ const [ start , end ] = range . map ( index => getLocFromIndex ( sourceCode , index ) ) ;
134114
135115 context . report ( {
136116 messageId : operation ,
@@ -147,7 +127,7 @@ function reportDifference(context, difference) {
147127// Module Definition
148128// ------------------------------------------------------------------------------
149129
150- /** @satisfies {ESLint.Plugin } */
130+ /** @type {ESLint.Plugin } */
151131const eslintPluginPrettier = {
152132 meta : { name, version } ,
153133 configs : {
@@ -225,6 +205,7 @@ const eslintPluginPrettier = {
225205 const source = sourceCode . text ;
226206
227207 return {
208+ /** @param {unknown } node */
228209 [ sourceCode . ast . type ] ( node ) {
229210 if ( ! prettierFormat ) {
230211 // Prettier is expensive to load, so only load it if needed.
0 commit comments