11import type { DependencyInfo , ValidNode } from '#types/extractor'
22import type { PackageInfo } from '#utils/api/package'
3+ import type { ParsedVersion } from '#utils/version'
34import type { Awaitable } from 'reactive-vscode'
45import type { Diagnostic , TextDocument } from 'vscode'
56import { useActiveExtractor } from '#composables/active-extractor'
67import { config , logger } from '#state'
78import { getPackageInfo } from '#utils/api/package'
9+ import { resolveExactVersion } from '#utils/package'
10+ import { isSupportedProtocol , parseVersion } from '#utils/version'
811import { debounce } from 'perfect-debounce'
912import { computed , useActiveTextEditor , useDisposable , useDocumentText , watch } from 'reactive-vscode'
1013import { languages } from 'vscode'
@@ -15,10 +18,17 @@ import { checkReplacement } from './rules/replacement'
1518import { checkUpgrade } from './rules/upgrade'
1619import { checkVulnerability } from './rules/vulnerability'
1720
21+ export interface DiagnosticContext {
22+ dep : DependencyInfo
23+ pkg : PackageInfo
24+ parsed : ParsedVersion | null
25+ exactVersion : string | null
26+ }
27+
1828export interface NodeDiagnosticInfo extends Omit < Diagnostic , 'range' | 'source' > {
1929 node : ValidNode
2030}
21- export type DiagnosticRule = ( dep : DependencyInfo , pkg : PackageInfo ) => Awaitable < NodeDiagnosticInfo | undefined >
31+ export type DiagnosticRule = ( ctx : DiagnosticContext ) => Awaitable < NodeDiagnosticInfo | undefined >
2232
2333export function useDiagnostics ( ) {
2434 const diagnosticCollection = useDisposable ( languages . createDiagnosticCollection ( displayName ) )
@@ -86,20 +96,28 @@ export function useDiagnostics() {
8696 if ( ! pkg )
8797 continue
8898
99+ const parsed = parseVersion ( dep . version )
100+ const exactVersion = parsed && isSupportedProtocol ( parsed . protocol )
101+ ? resolveExactVersion ( pkg , parsed . version )
102+ : null
103+
89104 for ( const rule of rules ) {
90- const diagnostic = await rule ( dep , pkg )
91- if ( isDocumentChanged ( document , targetUri , targetVersion ) )
92- return
93- if ( ! diagnostic )
94- continue
95-
96- diagnostics . push ( {
97- source : displayName ,
98- range : extractor . getNodeRange ( document , diagnostic . node ) ,
99- ...diagnostic ,
100- } )
101-
102- flush ( document , targetUri , targetVersion , diagnostics )
105+ try {
106+ const diagnostic = await rule ( { dep, pkg, parsed, exactVersion } )
107+ if ( isDocumentChanged ( document , targetUri , targetVersion ) )
108+ return
109+ if ( ! diagnostic )
110+ continue
111+
112+ diagnostics . push ( {
113+ source : displayName ,
114+ range : extractor . getNodeRange ( document , diagnostic . node ) ,
115+ ...diagnostic ,
116+ } )
117+ flush ( document , targetUri , targetVersion , diagnostics )
118+ } catch ( err ) {
119+ logger . warn ( `Fail to check ${ dep . name } (${ rule . name } ): ${ err } ` )
120+ }
103121 }
104122 } catch ( err ) {
105123 logger . warn ( `Failed to check ${ dep . name } : ${ err } ` )
0 commit comments