55 * @typedef {import("@eslint/core").TraversalStep } TraversalStep
66 * @typedef {import("@html-eslint/types").CommentContent } CommentContent
77 * @typedef {import("@html-eslint/types").AnyHTMLNode } AnyHTMLNode
8+ * @typedef {import("@eslint/core").Position } Position
89 * @typedef {import("../types").BaseNode } BaseNode
910 */
1011const {
1112 TextSourceCodeBase,
1213 ConfigCommentParser,
1314 Directive,
1415} = require ( "@eslint/plugin-kit" ) ;
15- const { SourceCode } = require ( "eslint" ) ;
1616const { HTMLTraversalStep, STEP_PHASE } = require ( "./html-traversal-step" ) ;
1717const { visitorKeys } = require ( "@html-eslint/parser" ) ;
1818
19+ const lineBreakPattern = / \r \n | [ \r \n \u2028 \u2029 ] / u;
20+
21+ function createGlobalLinebreakMatcher ( ) {
22+ return new RegExp ( lineBreakPattern . source , "gu" ) ;
23+ }
24+
1925const INLINE_CONFIG =
2026 / ^ \s * (?: e s l i n t (?: - e n a b l e | - d i s a b l e (?: (?: - n e x t ) ? - l i n e ) ? ) ? ) (?: \s | $ ) / u;
2127
@@ -27,10 +33,7 @@ class HTMLSourceCode extends TextSourceCodeBase {
2733 */
2834 constructor ( { ast, text, comments } ) {
2935 super ( { ast, text } ) ;
30- /**
31- * @property
32- */
33- this . eslintSourceCode = new SourceCode ( text , ast ) ;
36+
3437 /**
3538 * @property
3639 */
@@ -40,6 +43,14 @@ class HTMLSourceCode extends TextSourceCodeBase {
4043 */
4144 this . comments = comments ;
4245 this . parentsMap = new Map ( ) ;
46+
47+ this . lineStartIndices = [ 0 ] ;
48+
49+ const lineEndingPattern = createGlobalLinebreakMatcher ( ) ;
50+ let match ;
51+ while ( ( match = lineEndingPattern . exec ( this . text ) ) ) {
52+ this . lineStartIndices . push ( match . index + match [ 0 ] . length ) ;
53+ }
4354 }
4455
4556 /**
@@ -62,20 +73,88 @@ class HTMLSourceCode extends TextSourceCodeBase {
6273 return this . lines ;
6374 }
6475
76+ // Copied from eslint source code
6577 /**
66- * @param {import("@eslint/core").Position } loc
67- * @returns
78+ * @see https://github.com/eslint/eslint/blob/f60f2764971a33e252be13e560dccf21f554dbf1/lib/languages/js/source-code/source-code.js#L745
79+ * @param {Position } loc
80+ * @returns {number }
6881 */
6982 getIndexFromLoc ( loc ) {
70- return this . eslintSourceCode . getIndexFromLoc ( loc ) ;
83+ if (
84+ typeof loc !== "object" ||
85+ typeof loc . line !== "number" ||
86+ typeof loc . column !== "number"
87+ ) {
88+ throw new TypeError (
89+ "Expected `loc` to be an object with numeric `line` and `column` properties."
90+ ) ;
91+ }
92+
93+ if ( loc . line <= 0 ) {
94+ throw new RangeError (
95+ `Line number out of range (line ${ loc . line } requested). Line numbers should be 1-based.`
96+ ) ;
97+ }
98+
99+ if ( loc . line > this . lineStartIndices . length ) {
100+ throw new RangeError (
101+ `Line number out of range (line ${ loc . line } requested, but only ${ this . lineStartIndices . length } lines present).`
102+ ) ;
103+ }
104+
105+ const lineStartIndex = this . lineStartIndices [ loc . line - 1 ] ;
106+ const lineEndIndex =
107+ loc . line === this . lineStartIndices . length
108+ ? this . text . length
109+ : this . lineStartIndices [ loc . line ] ;
110+ const positionIndex = lineStartIndex + loc . column ;
111+ if (
112+ ( loc . line === this . lineStartIndices . length &&
113+ positionIndex > lineEndIndex ) ||
114+ ( loc . line < this . lineStartIndices . length && positionIndex >= lineEndIndex )
115+ ) {
116+ throw new RangeError (
117+ `Column number out of range (column ${ loc . column } requested, but the length of line ${ loc . line } is ${ lineEndIndex - lineStartIndex } ).`
118+ ) ;
119+ }
120+
121+ return positionIndex ;
71122 }
72123
124+ // Copied from eslint source code
73125 /**
126+ * @see https://github.com/eslint/eslint/blob/f60f2764971a33e252be13e560dccf21f554dbf1/lib/languages/js/source-code/source-code.js#L694
74127 * @param {number } index
75- * @returns {import("@eslint/core"). Position }
128+ * @returns {Position }
76129 */
77130 getLocFromIndex ( index ) {
78- return this . eslintSourceCode . getLocFromIndex ( index ) ;
131+ if ( typeof index !== "number" ) {
132+ throw new TypeError ( "Expected `index` to be a number." ) ;
133+ }
134+
135+ if ( index < 0 || index > this . text . length ) {
136+ throw new RangeError (
137+ `Index out of range (requested index ${ index } , but source text has length ${ this . text . length } ).`
138+ ) ;
139+ }
140+ if ( index === this . text . length ) {
141+ return {
142+ line : this . lines . length ,
143+ // @ts -ignore
144+ column : this . lines . at ( - 1 ) . length ,
145+ } ;
146+ }
147+
148+ const lineNumber =
149+ // @ts -ignore
150+ index >= this . lineStartIndices . at ( - 1 )
151+ ? this . lineStartIndices . length
152+ : this . lineStartIndices . findIndex ( ( el ) => index < el ) ;
153+
154+ return {
155+ line : lineNumber ,
156+ column : index - this . lineStartIndices [ lineNumber - 1 ] ,
157+ } ;
79158 }
80159
81160 getInlineConfigNodes ( ) {
0 commit comments