This repository has been archived by the owner on Oct 10, 2018. It is now read-only.
/
MissingImportCreator.ts
104 lines (96 loc) · 3.72 KB
/
MissingImportCreator.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
99
100
101
102
103
104
import { Logger } from '../utilities/winstonLogger';
import { inject, injectable } from 'inversify';
import { Command, Diagnostic, TextDocument } from 'vscode';
import { iocSymbols } from '../IoCSymbols';
import { DeclarationIndexMapper } from '../utilities/DeclarationIndexMapper';
import { AddImportCodeAction, AddMissingImportsCodeAction, NoopCodeAction } from './CodeAction';
import { CodeActionCreator } from './CodeActionCreator';
const REGEX_CANNOT_FIND_IMPORT = /cannot find name (['"])(.*)\1/i;
/**
* Action creator that handles missing imports in files.
*
* @export
* @class MissingImportCreator
* @extends {CodeActionCreator}
*/
@injectable()
export class MissingImportCreator extends CodeActionCreator {
constructor(
@inject(iocSymbols.declarationIndexMapper) private indices: DeclarationIndexMapper,
@inject(iocSymbols.logger) private logger: Logger,
) {
super();
}
/**
* Determines if the given diagnostic can be handled by this creator.
*
* @param {Diagnostic} diagnostic
* @returns {boolean}
*
* @memberof MissingImportCreator
*/
public canHandleDiagnostic(diagnostic: Diagnostic): boolean {
return REGEX_CANNOT_FIND_IMPORT.test(diagnostic.message);
}
/**
* Handles the given diagnostic. Must return an array of commands that are given to the light bulb.
*
* @param {TextDocument} document The commands that are created until now
* @param {Command[]} commands The commands that are created until now
* @param {Diagnostic} diagnostic The diagnostic to handle
* @returns {Promise<Command[]>}
*
* @memberof MissingImportCreator
*/
public async handleDiagnostic(document: TextDocument, commands: Command[], diagnostic: Diagnostic): Promise<Command[]> {
const match = REGEX_CANNOT_FIND_IMPORT.exec(diagnostic.message);
const index = this.indices.getIndexForFile(document.uri);
if (!match || !index) {
this.logger.debug(
'[%s] cannot handle the diagnostic',
MissingImportCreator.name,
);
return commands;
}
const infos = index.declarationInfos.filter(o => o.declaration.name === match[2]);
if (infos.length > 0) {
for (const info of infos) {
commands.push(this.createCommand(
`Import "${info.declaration.name}" from "${info.from}".`,
new AddImportCodeAction(document, info),
));
this.logger.debug(
'[%s] add command to import missing specifier',
MissingImportCreator.name,
{ symbol: info.declaration.name, library: info.from },
);
}
if (
!commands.some(o =>
o.arguments !== undefined &&
o.arguments.some(a => a instanceof AddMissingImportsCodeAction),
)
) {
commands.push(this.createCommand(
'Add all missing imports if possible.',
new AddMissingImportsCodeAction(document, index),
));
this.logger.debug(
'[%s] add "import all missing imports" command',
MissingImportCreator.name,
);
}
} else {
commands.push(this.createCommand(
`Cannot find "${match[2]}" in the index.`,
new NoopCodeAction(),
));
this.logger.debug(
'[%s] class not found in index',
MissingImportCreator.name,
{ specifier: match[2] },
);
}
return commands;
}
}