@@ -140,6 +140,99 @@ function normalizeErrorsForESLint10(errors) {
140140 } ) ;
141141}
142142
143+ /**
144+ * Normalize autofix output for ESLint 10 compatibility.
145+ *
146+ * ESLint 10's autofix places new content at position 0 instead of preserving leading whitespace.
147+ * It also preserves the original file's indentation for existing code.
148+ *
149+ * ESLint 8/9 pattern: "\n import NEW;\nfirstOriginalLine;\n restOfCode"
150+ * ESLint 10 pattern: "import NEW;\n\n firstOriginalLine;\n restOfCode"
151+ *
152+ * @param {string } output - The expected output (ESLint 8/9 format)
153+ * @param {string } code - The original code
154+ * @returns {string } - Normalized output for ESLint 10
155+ */
156+ function normalizeOutputForESLint10 ( output , code ) {
157+ if ( ! output || ! code ) {
158+ return output ;
159+ }
160+
161+ // Count import statements in code and output
162+ const codeImports = ( code . match ( / i m p o r t \s + / g) || [ ] ) . length ;
163+ const outputImports = ( output . match ( / i m p o r t \s + / g) || [ ] ) . length ;
164+
165+ // Only apply transformation when fixer adds new imports
166+ if ( outputImports <= codeImports ) {
167+ return output ;
168+ }
169+
170+ // Check if output has leading whitespace before an import statement
171+ const leadingMatch = output . match ( / ^ ( \s + ) ( i m p o r t \s + ) / ) ;
172+ if ( ! leadingMatch ) {
173+ return output ;
174+ }
175+
176+ const leadingWhitespace = leadingMatch [ 1 ] ;
177+
178+ // Only transform if there's significant leading whitespace (contains newline)
179+ if ( ! leadingWhitespace . includes ( '\n' ) ) {
180+ return output ;
181+ }
182+
183+ // Detect the indentation used in the original code
184+ const codeIndentMatch = code . match ( / ^ ( \s * \n ) ? ( \s + ) / ) ;
185+ const originalIndent = codeIndentMatch ? codeIndentMatch [ 2 ] : ' ' ;
186+
187+ // Split output into lines and process
188+ const lines = output . split ( '\n' ) ;
189+ const newImports = [ ] ;
190+ const restLines = [ ] ;
191+ let inNewImports = true ;
192+ let isFirstLineAfterImports = true ;
193+
194+ for ( let i = 0 ; i < lines . length ; i ++ ) {
195+ const line = lines [ i ] ;
196+
197+ // Skip leading empty lines
198+ if ( inNewImports && line === '' && newImports . length === 0 ) {
199+ continue ;
200+ }
201+
202+ if ( inNewImports ) {
203+ // A line with indentation + import is a NEW import (inserted by fixer)
204+ if ( / ^ \s + i m p o r t \s + / . test ( line ) ) {
205+ newImports . push ( line . trim ( ) ) ;
206+ } else {
207+ // End of new imports section
208+ inNewImports = false ;
209+
210+ // The first line after new imports in ESLint 8/9 output often loses its indentation
211+ // If it starts at column 0 and has content, restore the original indentation
212+ if ( isFirstLineAfterImports && line !== '' && ! / ^ \s / . test ( line ) ) {
213+ restLines . push ( originalIndent + line ) ;
214+ isFirstLineAfterImports = false ;
215+ } else {
216+ restLines . push ( line ) ;
217+ if ( line !== '' ) {
218+ isFirstLineAfterImports = false ;
219+ }
220+ }
221+ }
222+ } else {
223+ restLines . push ( line ) ;
224+ }
225+ }
226+
227+ // If we found new imports that should be at position 0
228+ if ( newImports . length > 0 ) {
229+ // ESLint 10 format: new imports at start, blank line, then original content
230+ return newImports . join ( '\n' ) + '\n\n' + restLines . join ( '\n' ) ;
231+ }
232+
233+ return output ;
234+ }
235+
143236/**
144237 * Convert test case config to flat config format
145238 * @param {Object|string } testCase - The test case
@@ -161,6 +254,17 @@ function convertTestCase(testCase, isValid = false) {
161254 delete converted . output ;
162255 }
163256
257+ // ESLint 10: Transform expected output to match ESLint 10's autofix formatting
258+ if (
259+ isESLint10OrLater &&
260+ ! isValid &&
261+ 'output' in converted &&
262+ converted . output !== null &&
263+ typeof converted . output === 'string'
264+ ) {
265+ converted . output = normalizeOutputForESLint10 ( converted . output , converted . code ) ;
266+ }
267+
164268 // Convert parser string paths to parser objects
165269 if ( typeof testCase . parser === 'string' ) {
166270 converted . languageOptions = converted . languageOptions || { } ;
0 commit comments