-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
diagnostics.ts
98 lines (92 loc) · 4.53 KB
/
diagnostics.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import * as sourcegraph from 'sourcegraph'
import { DependencySpecificationWithType } from './combinedProvider'
import { DependencyManagementCampaignContextCommon, LOADING } from './common'
import { DependencyQuery, DependencyManagementProvider } from '.'
import { Observable, from, of } from 'rxjs'
import { startWith, map, switchMap } from 'rxjs/operators'
import { isDefined } from '../../../../../shared/src/util/types'
import { toLocation } from '../../../../../shared/src/api/extension/api/types'
export interface DependencyManagementDiagnosticData<Q extends DependencyQuery>
extends DependencySpecificationWithType<Q>,
Pick<DependencyManagementCampaignContextCommon, 'action' | 'createChangesets'> {}
export interface DependencyManagementDiagnostic<Q extends DependencyQuery> extends sourcegraph.Diagnostic {
parsedData: DependencyManagementDiagnosticData<Q>
}
export const parseDependencyManagementDiagnostic = <Q extends DependencyQuery>(
diagnostic: sourcegraph.Diagnostic,
tag: string
): DependencyManagementDiagnostic<Q> | null => {
if (!diagnostic.data) {
return null
}
if (!diagnostic.tags || !diagnostic.tags.includes(tag)) {
return null
}
const parsed: DependencyManagementDiagnosticData<Q> = JSON.parse(diagnostic.data) // URL objects are stringified
const converted: DependencyManagementDiagnosticData<Q> = {
...parsed,
declarations: parsed.declarations.map(d => ({ ...d, location: toLocation(d.location as any) })),
resolutions: parsed.resolutions.map(r => ({
...r,
location: r.location ? toLocation(r.location as any) : undefined,
})),
}
return { ...diagnostic, parsedData: converted }
}
export const provideDependencyManagementDiagnostics = <
Q extends DependencyQuery,
S extends DependencySpecificationWithType<Q> = DependencySpecificationWithType<Q>
>(
{ provideDependencySpecifications }: Pick<DependencyManagementProvider<Q, S>, 'provideDependencySpecifications'>,
dependencyTag: string,
query: Q,
{
action,
createChangesets,
filters,
}: Pick<DependencyManagementCampaignContextCommon, 'action' | 'createChangesets' | 'filters'>
): Observable<sourcegraph.Diagnostic[] | typeof LOADING> =>
from(sourcegraph.workspace.rootChanges).pipe(
startWith(undefined),
map(() => sourcegraph.workspace.roots),
switchMap(roots => {
if (roots.length > 0) {
return of<sourcegraph.Diagnostic[]>([]) // TODO!(sqs): dont run in comparison mode
}
const specs = provideDependencySpecifications(query, filters)
return specs.pipe(
map(specs =>
specs
.flatMap(spec => {
const diags: sourcegraph.Diagnostic[] = [...(spec.diagnostics || [])]
const specMain = spec.declarations[0]
? spec.declarations[0]
: { ...spec.resolutions[0], direct: false }
if (specMain.location) {
const data: DependencyManagementDiagnosticData<Q> = {
...spec,
action,
createChangesets,
}
diags.push({
resource: specMain.location.uri,
message: `${specMain.direct ? 'Dependency' : 'Indirect dependency'} ${
specMain.name
}${query.versionRange === '*' ? '' : `@${query.versionRange}`} ${
action === 'ban' ? 'is banned' : `must be upgraded to ${action.requireVersion}`
}`,
range: specMain.location.range || new sourcegraph.Range(0, 0, 0, 0),
severity: sourcegraph.DiagnosticSeverity.Warning,
// eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion
data: JSON.stringify(data),
tags: [dependencyTag],
})
}
return diags
})
.filter(isDefined)
)
)
}),
startWith(LOADING)
)