11import type { RawSourceMap } from '@ampproject/remapping'
22import type { File , Task , TaskResultPack , TaskState } from '@vitest/runner'
33import type { ParsedStack } from '@vitest/utils'
4+ import type { EachMapping } from '@vitest/utils/source-map'
45import type { ChildProcess } from 'node:child_process'
56import type { Vitest } from '../node/core'
67import type { TestProject } from '../node/project'
@@ -10,7 +11,7 @@ import type { TscErrorInfo } from './types'
1011import { rm } from 'node:fs/promises'
1112import { performance } from 'node:perf_hooks'
1213import { getTasks } from '@vitest/runner/utils'
13- import { generatedPositionFor , TraceMap } from '@vitest/utils/source-map'
14+ import { eachMapping , generatedPositionFor , TraceMap } from '@vitest/utils/source-map'
1415import { basename , extname , resolve } from 'pathe'
1516import { x } from 'tinyexec'
1617import { collectTests } from './collect'
@@ -161,7 +162,7 @@ export class Typechecker {
161162 }
162163 errors . forEach ( ( { error, originalError } ) => {
163164 const processedPos = traceMap
164- ? generatedPositionFor ( traceMap , {
165+ ? findGeneratedPosition ( traceMap , {
165166 line : originalError . line ,
166167 column : originalError . column ,
167168 source : basename ( path ) ,
@@ -364,3 +365,40 @@ export class Typechecker {
364365 . map < TaskResultPack > ( i => [ i . id , i . result , { typecheck : true } ] )
365366 }
366367}
368+
369+ function findGeneratedPosition ( traceMap : TraceMap , { line, column, source } : { line : number ; column : number ; source : string } ) {
370+ const found = generatedPositionFor ( traceMap , {
371+ line,
372+ column,
373+ source,
374+ } )
375+ if ( found . line !== null ) {
376+ return found
377+ }
378+ // find the next source token position when the exact error position doesn't exist in source map.
379+ // this can happen, for example, when the type error is in the comment "// @ts-expect-error"
380+ // and comments are stripped away in the generated code.
381+ const mappings : ( EachMapping & { originalLine : number } ) [ ] = [ ]
382+ eachMapping ( traceMap , ( m ) => {
383+ if (
384+ m . source === source
385+ && m . originalLine !== null
386+ && m . originalColumn !== null
387+ && ( line === m . originalLine ? column < m . originalColumn : line < m . originalLine )
388+ ) {
389+ mappings . push ( m )
390+ }
391+ } )
392+ const next = mappings
393+ . sort ( ( a , b ) =>
394+ a . originalLine === b . originalLine ? a . originalColumn - b . originalColumn : a . originalLine - b . originalLine ,
395+ )
396+ . at ( 0 )
397+ if ( next ) {
398+ return {
399+ line : next . generatedLine ,
400+ column : next . generatedColumn ,
401+ }
402+ }
403+ return { line : null , column : null }
404+ }
0 commit comments