Add 'info' diagnostics (#22204)

* Add 'info' diagnostics

* Code review
This commit is contained in:
Andy
2018-02-28 11:16:32 -08:00
committed by GitHub
parent e26d4e4729
commit fa4619c5c1
50 changed files with 400 additions and 383 deletions
+5
View File
@@ -3810,6 +3810,11 @@
"code": 18003
},
"File is a CommonJS module; it may be converted to an ES6 module.": {
"category": "Suggestion",
"code": 80001
},
"Add missing 'super()' call": {
"category": "Message",
"code": 90001
+4 -6
View File
@@ -227,8 +227,7 @@ namespace ts {
}
export function formatDiagnostic(diagnostic: Diagnostic, host: FormatDiagnosticsHost): string {
const category = DiagnosticCategory[diagnostic.category].toLowerCase();
const errorMessage = `${category} TS${diagnostic.code}: ${flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine())}${host.getNewLine()}`;
const errorMessage = `${diagnosticCategoryName(diagnostic)} TS${diagnostic.code}: ${flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine())}${host.getNewLine()}`;
if (diagnostic.file) {
const { line, character } = getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start);
@@ -254,8 +253,9 @@ namespace ts {
const ellipsis = "...";
function getCategoryFormat(category: DiagnosticCategory): string {
switch (category) {
case DiagnosticCategory.Warning: return ForegroundColorEscapeSequences.Yellow;
case DiagnosticCategory.Error: return ForegroundColorEscapeSequences.Red;
case DiagnosticCategory.Warning: return ForegroundColorEscapeSequences.Yellow;
case DiagnosticCategory.Suggestion: return Debug.fail("Should never get an Info diagnostic on the command line.");
case DiagnosticCategory.Message: return ForegroundColorEscapeSequences.Blue;
}
}
@@ -337,9 +337,7 @@ namespace ts {
output += " - ";
}
const categoryColor = getCategoryFormat(diagnostic.category);
const category = DiagnosticCategory[diagnostic.category].toLowerCase();
output += formatColorAndReset(category, categoryColor);
output += formatColorAndReset(diagnosticCategoryName(diagnostic), getCategoryFormat(diagnostic.category));
output += formatColorAndReset(` TS${ diagnostic.code }: `, ForegroundColorEscapeSequences.Grey);
output += flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine());
+6
View File
@@ -4017,8 +4017,14 @@ namespace ts {
export enum DiagnosticCategory {
Warning,
Error,
Suggestion,
Message
}
/* @internal */
export function diagnosticCategoryName(d: { category: DiagnosticCategory }, lowerCase = true): string {
const name = DiagnosticCategory[d.category];
return lowerCase ? name.toLowerCase() : name;
}
export enum ModuleResolutionKind {
Classic = 1,
+14 -3
View File
@@ -506,8 +506,11 @@ namespace FourSlash {
}
private getDiagnostics(fileName: string): ts.Diagnostic[] {
return ts.concatenate(this.languageService.getSyntacticDiagnostics(fileName),
this.languageService.getSemanticDiagnostics(fileName));
return [
...this.languageService.getSyntacticDiagnostics(fileName),
...this.languageService.getSemanticDiagnostics(fileName),
...this.languageService.getSuggestionDiagnostics(fileName),
];
}
private getAllDiagnostics(): ts.Diagnostic[] {
@@ -581,7 +584,7 @@ namespace FourSlash {
public verifyNoErrors() {
ts.forEachKey(this.inputFiles, fileName => {
if (!ts.isAnySupportedFileExtension(fileName)) return;
const errors = this.getDiagnostics(fileName);
const errors = this.getDiagnostics(fileName).filter(e => e.category !== ts.DiagnosticCategory.Suggestion);
if (errors.length) {
this.printErrorLog(/*expectErrors*/ false, errors);
const error = errors[0];
@@ -1246,6 +1249,10 @@ Actual: ${stringify(fullActual)}`);
this.testDiagnostics(expected, diagnostics);
}
public getSuggestionDiagnostics(expected: ReadonlyArray<ts.RealizedDiagnostic>): void {
this.testDiagnostics(expected, this.languageService.getSuggestionDiagnostics(this.activeFile.fileName));
}
private testDiagnostics(expected: ReadonlyArray<ts.RealizedDiagnostic>, diagnostics: ReadonlyArray<ts.Diagnostic>) {
assert.deepEqual(ts.realizeDiagnostics(diagnostics, ts.newLineCharacter), expected);
}
@@ -4327,6 +4334,10 @@ namespace FourSlashInterface {
this.state.getSemanticDiagnostics(expected);
}
public getSuggestionDiagnostics(expected: ReadonlyArray<ts.RealizedDiagnostic>) {
this.state.getSuggestionDiagnostics(expected);
}
public ProjectInfo(expected: string[]) {
this.state.verifyProjectInfo(expected);
}
+2 -2
View File
@@ -242,7 +242,7 @@ namespace Utils {
start: diagnostic.start,
length: diagnostic.length,
messageText: ts.flattenDiagnosticMessageText(diagnostic.messageText, Harness.IO.newLine()),
category: (<any>ts).DiagnosticCategory[diagnostic.category],
category: ts.diagnosticCategoryName(diagnostic, /*lowerCase*/ false),
code: diagnostic.code
};
}
@@ -1376,7 +1376,7 @@ namespace Harness {
.split("\n")
.map(s => s.length > 0 && s.charAt(s.length - 1) === "\r" ? s.substr(0, s.length - 1) : s)
.filter(s => s.length > 0)
.map(s => "!!! " + ts.DiagnosticCategory[error.category].toLowerCase() + " TS" + error.code + ": " + s);
.map(s => "!!! " + ts.diagnosticCategoryName(error) + " TS" + error.code + ": " + s);
errLines.forEach(e => outputLines += (newLine() + e));
errorsReported++;
+3
View File
@@ -402,6 +402,9 @@ namespace Harness.LanguageService {
getSemanticDiagnostics(fileName: string): ts.Diagnostic[] {
return unwrapJSONCallResult(this.shim.getSemanticDiagnostics(fileName));
}
getSuggestionDiagnostics(fileName: string): ts.Diagnostic[] {
return unwrapJSONCallResult(this.shim.getSuggestionDiagnostics(fileName));
}
getCompilerOptionsDiagnostics(): ts.Diagnostic[] {
return unwrapJSONCallResult(this.shim.getCompilerOptionsDiagnostics());
}
+1
View File
@@ -216,6 +216,7 @@ namespace ts.server {
CommandNames.GeterrForProject,
CommandNames.SemanticDiagnosticsSync,
CommandNames.SyntacticDiagnosticsSync,
CommandNames.SuggestionDiagnosticsSync,
CommandNames.NavBar,
CommandNames.NavBarFull,
CommandNames.Navto,
+87 -15
View File
@@ -467,12 +467,12 @@ namespace ts.projectSystem {
verifyDiagnostics(actual, []);
}
function checkErrorMessage(session: TestSession, eventName: "syntaxDiag" | "semanticDiag", diagnostics: protocol.DiagnosticEventBody) {
checkNthEvent(session, ts.server.toEvent(eventName, diagnostics), 0, /*isMostRecent*/ false);
function checkErrorMessage(session: TestSession, eventName: protocol.DiagnosticEventKind, diagnostics: protocol.DiagnosticEventBody, isMostRecent = false): void {
checkNthEvent(session, ts.server.toEvent(eventName, diagnostics), 0, isMostRecent);
}
function checkCompleteEvent(session: TestSession, numberOfCurrentEvents: number, expectedSequenceId: number) {
checkNthEvent(session, ts.server.toEvent("requestCompleted", { request_seq: expectedSequenceId }), numberOfCurrentEvents - 1, /*isMostRecent*/ true);
function checkCompleteEvent(session: TestSession, numberOfCurrentEvents: number, expectedSequenceId: number, isMostRecent = true): void {
checkNthEvent(session, ts.server.toEvent("requestCompleted", { request_seq: expectedSequenceId }), numberOfCurrentEvents - 1, isMostRecent);
}
function checkProjectUpdatedInBackgroundEvent(session: TestSession, openFiles: string[]) {
@@ -3076,8 +3076,13 @@ namespace ts.projectSystem {
host.runQueuedImmediateCallbacks();
assert.isFalse(hasError());
checkErrorMessage(session, "semanticDiag", { file: untitledFile, diagnostics: [] });
session.clearMessages();
host.runQueuedImmediateCallbacks(1);
assert.isFalse(hasError());
checkErrorMessage(session, "suggestionDiag", { file: untitledFile, diagnostics: [] });
checkCompleteEvent(session, 2, expectedSequenceId);
session.clearMessages();
}
it("has projectRoot", () => {
@@ -3136,6 +3141,10 @@ namespace ts.projectSystem {
host.runQueuedImmediateCallbacks();
checkErrorMessage(session, "semanticDiag", { file: app.path, diagnostics: [] });
session.clearMessages();
host.runQueuedImmediateCallbacks(1);
checkErrorMessage(session, "suggestionDiag", { file: app.path, diagnostics: [] });
checkCompleteEvent(session, 2, expectedSequenceId);
session.clearMessages();
}
@@ -3934,18 +3943,17 @@ namespace ts.projectSystem {
session.clearMessages();
host.runQueuedImmediateCallbacks();
const moduleNotFound = Diagnostics.Cannot_find_module_0;
const startOffset = file1.content.indexOf('"') + 1;
checkErrorMessage(session, "semanticDiag", {
file: file1.path, diagnostics: [{
start: { line: 1, offset: startOffset },
end: { line: 1, offset: startOffset + '"pad"'.length },
text: formatStringFromArgs(moduleNotFound.message, ["pad"]),
code: moduleNotFound.code,
category: DiagnosticCategory[moduleNotFound.category].toLowerCase(),
source: undefined
}]
file: file1.path,
diagnostics: [
createDiagnostic({ line: 1, offset: startOffset }, { line: 1, offset: startOffset + '"pad"'.length }, Diagnostics.Cannot_find_module_0, ["pad"])
],
});
session.clearMessages();
host.runQueuedImmediateCallbacks(1);
checkErrorMessage(session, "suggestionDiag", { file: file1.path, diagnostics: [] });
checkCompleteEvent(session, 2, expectedSequenceId);
session.clearMessages();
@@ -3966,6 +3974,63 @@ namespace ts.projectSystem {
host.runQueuedImmediateCallbacks();
checkErrorMessage(session, "semanticDiag", { file: file1.path, diagnostics: [] });
});
it("info diagnostics", () => {
const file: FileOrFolder = {
path: "/a.js",
content: 'require("b")',
};
const host = createServerHost([file]);
const session = createSession(host, { canUseEvents: true });
const service = session.getProjectService();
session.executeCommandSeq<protocol.OpenRequest>({
command: server.CommandNames.Open,
arguments: { file: file.path, fileContent: file.content },
});
checkNumberOfProjects(service, { inferredProjects: 1 });
session.clearMessages();
const expectedSequenceId = session.getNextSeq();
host.checkTimeoutQueueLengthAndRun(2);
checkProjectUpdatedInBackgroundEvent(session, [file.path]);
session.clearMessages();
session.executeCommandSeq<protocol.GeterrRequest>({
command: server.CommandNames.Geterr,
arguments: {
delay: 0,
files: [file.path],
}
});
host.checkTimeoutQueueLengthAndRun(1);
checkErrorMessage(session, "syntaxDiag", { file: file.path, diagnostics: [] }, /*isMostRecent*/ true);
session.clearMessages();
host.runQueuedImmediateCallbacks(1);
checkErrorMessage(session, "semanticDiag", { file: file.path, diagnostics: [] });
session.clearMessages();
host.runQueuedImmediateCallbacks(1);
checkErrorMessage(session, "suggestionDiag", {
file: file.path,
diagnostics: [
createDiagnostic({ line: 1, offset: 1 }, { line: 1, offset: 13 }, Diagnostics.File_is_a_CommonJS_module_it_may_be_converted_to_an_ES6_module)
],
});
checkCompleteEvent(session, 2, expectedSequenceId);
session.clearMessages();
});
function createDiagnostic(start: protocol.Location, end: protocol.Location, message: DiagnosticMessage, args: ReadonlyArray<string> = []): protocol.Diagnostic {
return { start, end, text: formatStringFromArgs(message.message, args), code: message.code, category: diagnosticCategoryName(message), source: undefined };
}
});
describe("tsserverProjectSystem Configure file diagnostics events", () => {
@@ -5154,9 +5219,15 @@ namespace ts.projectSystem {
// the semanticDiag message
host.runQueuedImmediateCallbacks();
assert.equal(host.getOutput().length, 2, "expect 2 messages");
assert.equal(host.getOutput().length, 1);
const e2 = <protocol.Event>getMessage(0);
assert.equal(e2.event, "semanticDiag");
session.clearMessages();
host.runQueuedImmediateCallbacks(1);
assert.equal(host.getOutput().length, 2);
const e3 = <protocol.Event>getMessage(0);
assert.equal(e3.event, "suggestionDiag");
verifyRequestCompleted(getErrId, 1);
cancellationToken.resetToken();
@@ -5194,6 +5265,7 @@ namespace ts.projectSystem {
return JSON.parse(server.extractMessage(host.getOutput()[n]));
}
});
it("Lower priority tasks are cancellable", () => {
const f1 = {
path: "/a/app.ts",
@@ -5495,7 +5567,7 @@ namespace ts.projectSystem {
}
type CalledMaps = CalledMapsWithSingleArg | CalledMapsWithFiveArgs;
function createCallsTrackingHost(host: TestServerHost) {
const calledMaps: Record<CalledMapsWithSingleArg, MultiMap<true>> & Record<CalledMapsWithFiveArgs, MultiMap<[ReadonlyArray<string>, ReadonlyArray<string>, ReadonlyArray<string>, number]>> = {
const calledMaps: Record<CalledMapsWithSingleArg, MultiMap<true>> & Record<CalledMapsWithFiveArgs, MultiMap<[ReadonlyArray<string>, ReadonlyArray<string>, ReadonlyArray<string>, number]>> = {
fileExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.fileExists),
directoryExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.directoryExists),
getDirectories: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.getDirectories),
+4 -1
View File
@@ -708,7 +708,10 @@ interface Array<T> {}`
}
}
runQueuedImmediateCallbacks() {
runQueuedImmediateCallbacks(checkCount?: number) {
if (checkCount !== undefined) {
assert.equal(this.immediateCallbacks.count(), checkCount);
}
this.immediateCallbacks.invoke();
}
+21 -31
View File
@@ -75,7 +75,7 @@ namespace ts.server {
return { span: this.decodeSpan(codeEdit, fileName), newText: codeEdit.newText };
}
private processRequest<T extends protocol.Request>(command: string, args?: any): T {
private processRequest<T extends protocol.Request>(command: string, args?: T["arguments"]): T {
const request: protocol.Request = {
seq: this.sequence,
type: "request",
@@ -343,41 +343,31 @@ namespace ts.server {
}
getSyntacticDiagnostics(file: string): Diagnostic[] {
const args: protocol.SyntacticDiagnosticsSyncRequestArgs = { file, includeLinePosition: true };
const request = this.processRequest<protocol.SyntacticDiagnosticsSyncRequest>(CommandNames.SyntacticDiagnosticsSync, args);
const response = this.processResponse<protocol.SyntacticDiagnosticsSyncResponse>(request);
return (<protocol.DiagnosticWithLinePosition[]>response.body).map(entry => this.convertDiagnostic(entry, file));
return this.getDiagnostics(file, CommandNames.SyntacticDiagnosticsSync);
}
getSemanticDiagnostics(file: string): Diagnostic[] {
const args: protocol.SemanticDiagnosticsSyncRequestArgs = { file, includeLinePosition: true };
const request = this.processRequest<protocol.SemanticDiagnosticsSyncRequest>(CommandNames.SemanticDiagnosticsSync, args);
const response = this.processResponse<protocol.SemanticDiagnosticsSyncResponse>(request);
return (<protocol.DiagnosticWithLinePosition[]>response.body).map(entry => this.convertDiagnostic(entry, file));
return this.getDiagnostics(file, CommandNames.SemanticDiagnosticsSync);
}
getSuggestionDiagnostics(file: string): Diagnostic[] {
return this.getDiagnostics(file, CommandNames.SuggestionDiagnosticsSync);
}
convertDiagnostic(entry: protocol.DiagnosticWithLinePosition, _fileName: string): Diagnostic {
let category: DiagnosticCategory;
for (const id in DiagnosticCategory) {
if (isString(id) && entry.category === id.toLowerCase()) {
category = (<any>DiagnosticCategory)[id];
}
}
private getDiagnostics(file: string, command: CommandNames) {
const request = this.processRequest<protocol.SyntacticDiagnosticsSyncRequest | protocol.SemanticDiagnosticsSyncRequest | protocol.SuggestionDiagnosticsSyncRequest>(command, { file, includeLinePosition: true });
const response = this.processResponse<protocol.SyntacticDiagnosticsSyncResponse | protocol.SemanticDiagnosticsSyncResponse | protocol.SuggestionDiagnosticsSyncResponse>(request);
Debug.assert(category !== undefined, "convertDiagnostic: category should not be undefined");
return {
file: undefined,
start: entry.start,
length: entry.length,
messageText: entry.message,
category,
code: entry.code
};
return (<protocol.DiagnosticWithLinePosition[]>response.body).map(entry => {
const category = firstDefined(Object.keys(DiagnosticCategory), id =>
isString(id) && entry.category === id.toLowerCase() ? (<any>DiagnosticCategory)[id] : undefined);
return {
file: undefined,
start: entry.start,
length: entry.length,
messageText: entry.message,
category: Debug.assertDefined(category, "convertDiagnostic: category should not be undefined"),
code: entry.code
};
});
}
getCompilerOptionsDiagnostics(): Diagnostic[] {
+13 -2
View File
@@ -42,6 +42,7 @@ namespace ts.server.protocol {
GeterrForProject = "geterrForProject",
SemanticDiagnosticsSync = "semanticDiagnosticsSync",
SyntacticDiagnosticsSync = "syntacticDiagnosticsSync",
SuggestionDiagnosticsSync = "suggestionDiagnosticsSync",
NavBar = "navbar",
/* @internal */
NavBarFull = "navbar-full",
@@ -2010,6 +2011,14 @@ namespace ts.server.protocol {
body?: Diagnostic[] | DiagnosticWithLinePosition[];
}
export interface SuggestionDiagnosticsSyncRequest extends FileRequest {
command: CommandTypes.SuggestionDiagnosticsSync;
arguments: SuggestionDiagnosticsSyncRequestArgs;
}
export type SuggestionDiagnosticsSyncRequestArgs = SemanticDiagnosticsSyncRequestArgs;
export type SuggestionDiagnosticsSyncResponse = SemanticDiagnosticsSyncResponse;
/**
* Synchronous request for syntactic diagnostics of one file.
*/
@@ -2121,7 +2130,7 @@ namespace ts.server.protocol {
text: string;
/**
* The category of the diagnostic message, e.g. "error" vs. "warning"
* The category of the diagnostic message, e.g. "error", "warning", or "suggestion".
*/
category: string;
@@ -2155,8 +2164,10 @@ namespace ts.server.protocol {
diagnostics: Diagnostic[];
}
export type DiagnosticEventKind = "semanticDiag" | "syntaxDiag" | "suggestionDiag";
/**
* Event message for "syntaxDiag" and "semanticDiag" event types.
* Event message for DiagnosticEventKind event types.
* These events provide syntactic and semantic errors for a file.
*/
export interface DiagnosticEvent extends Event {
+58 -36
View File
@@ -79,7 +79,7 @@ namespace ts.server {
end: scriptInfo.positionToLineOffset(diag.start + diag.length),
text: flattenDiagnosticMessageText(diag.messageText, "\n"),
code: diag.code,
category: DiagnosticCategory[diag.category].toLowerCase(),
category: diagnosticCategoryName(diag),
source: diag.source
};
}
@@ -95,7 +95,7 @@ namespace ts.server {
const end = diag.file && convertToLocation(getLineAndCharacterOfPosition(diag.file, diag.start + diag.length));
const text = flattenDiagnosticMessageText(diag.messageText, "\n");
const { code, source } = diag;
const category = DiagnosticCategory[diag.category].toLowerCase();
const category = diagnosticCategoryName(diag);
return includeFileName ? { start, end, text, code, category, source, fileName: diag.file && diag.file.fileName } :
{ start, end, text, code, category, source };
}
@@ -466,30 +466,26 @@ namespace ts.server {
}
private semanticCheck(file: NormalizedPath, project: Project) {
try {
let diags: ReadonlyArray<Diagnostic> = emptyArray;
if (!isDeclarationFileInJSOnlyNonConfiguredProject(project, file)) {
diags = project.getLanguageService().getSemanticDiagnostics(file);
}
const bakedDiags = diags.map((diag) => formatDiag(file, project, diag));
this.event<protocol.DiagnosticEventBody>({ file, diagnostics: bakedDiags }, "semanticDiag");
}
catch (err) {
this.logError(err, "semantic check");
}
const diags = isDeclarationFileInJSOnlyNonConfiguredProject(project, file)
? emptyArray
: project.getLanguageService().getSemanticDiagnostics(file);
this.sendDiagnosticsEvent(file, project, diags, "semanticDiag");
}
private syntacticCheck(file: NormalizedPath, project: Project) {
this.sendDiagnosticsEvent(file, project, project.getLanguageService().getSyntacticDiagnostics(file), "syntaxDiag");
}
private infoCheck(file: NormalizedPath, project: Project) {
this.sendDiagnosticsEvent(file, project, project.getLanguageService().getSuggestionDiagnostics(file), "suggestionDiag");
}
private sendDiagnosticsEvent(file: NormalizedPath, project: Project, diagnostics: ReadonlyArray<Diagnostic>, kind: protocol.DiagnosticEventKind): void {
try {
const diags = project.getLanguageService().getSyntacticDiagnostics(file);
if (diags) {
const bakedDiags = diags.map((diag) => formatDiag(file, project, diag));
this.event<protocol.DiagnosticEventBody>({ file, diagnostics: bakedDiags }, "syntaxDiag");
}
this.event<protocol.DiagnosticEventBody>({ file, diagnostics: diagnostics.map(diag => formatDiag(file, project, diag)) }, kind);
}
catch (err) {
this.logError(err, "syntactic check");
this.logError(err, kind);
}
}
@@ -499,21 +495,34 @@ namespace ts.server {
let index = 0;
const checkOne = () => {
if (this.changeSeq === seq) {
const checkSpec = checkList[index];
index++;
if (checkSpec.project.containsFile(checkSpec.fileName, requireOpen)) {
this.syntacticCheck(checkSpec.fileName, checkSpec.project);
if (this.changeSeq === seq) {
next.immediate(() => {
this.semanticCheck(checkSpec.fileName, checkSpec.project);
if (checkList.length > index) {
next.delay(followMs, checkOne);
}
});
}
}
if (this.changeSeq !== seq) {
return;
}
const { fileName, project } = checkList[index];
index++;
if (!project.containsFile(fileName, requireOpen)) {
return;
}
this.syntacticCheck(fileName, project);
if (this.changeSeq !== seq) {
return;
}
next.immediate(() => {
this.semanticCheck(fileName, project);
if (this.changeSeq !== seq) {
return;
}
next.immediate(() => {
this.infoCheck(fileName, project);
if (checkList.length > index) {
next.delay(followMs, checkOne);
}
});
});
};
if (checkList.length > index && this.changeSeq === seq) {
@@ -580,7 +589,7 @@ namespace ts.server {
message: flattenDiagnosticMessageText(d.messageText, this.host.newLine),
start: d.start,
length: d.length,
category: DiagnosticCategory[d.category].toLowerCase(),
category: diagnosticCategoryName(d),
code: d.code,
startLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start)),
endLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start + d.length))
@@ -606,7 +615,7 @@ namespace ts.server {
message: flattenDiagnosticMessageText(d.messageText, this.host.newLine),
start: d.start,
length: d.length,
category: DiagnosticCategory[d.category].toLowerCase(),
category: diagnosticCategoryName(d),
code: d.code,
source: d.source,
startLocation: scriptInfo && scriptInfo.positionToLineOffset(d.start),
@@ -756,6 +765,16 @@ namespace ts.server {
return this.getDiagnosticsWorker(args, /*isSemantic*/ true, (project, file) => project.getLanguageService().getSemanticDiagnostics(file), args.includeLinePosition);
}
private getSuggestionDiagnosticsSync(args: protocol.SuggestionDiagnosticsSyncRequestArgs): ReadonlyArray<protocol.Diagnostic> | ReadonlyArray<protocol.DiagnosticWithLinePosition> {
const { configFile } = this.getConfigFileAndProject(args);
if (configFile) {
// Currently there are no info diagnostics for config files.
return emptyArray;
}
// isSemantic because we don't want to info diagnostics in declaration files for JS-only users
return this.getDiagnosticsWorker(args, /*isSemantic*/ true, (project, file) => project.getLanguageService().getSuggestionDiagnostics(file), args.includeLinePosition);
}
private getDocumentHighlights(args: protocol.DocumentHighlightsRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.DocumentHighlightsItem> | ReadonlyArray<DocumentHighlights> {
const { file, project } = this.getFileAndProject(args);
const position = this.getPositionInFile(args, file);
@@ -1953,6 +1972,9 @@ namespace ts.server {
[CommandNames.SyntacticDiagnosticsSync]: (request: protocol.SyntacticDiagnosticsSyncRequest) => {
return this.requiredResponse(this.getSyntacticDiagnosticsSync(request.arguments));
},
[CommandNames.SuggestionDiagnosticsSync]: (request: protocol.SuggestionDiagnosticsSyncRequest) => {
return this.requiredResponse(this.getSuggestionDiagnosticsSync(request.arguments));
},
[CommandNames.Geterr]: (request: protocol.GeterrRequest) => {
this.errorCheck.startNew(next => this.getDiagnostics(next, request.arguments.delay, request.arguments.files));
return this.notRequired();
@@ -1,85 +1,22 @@
/* @internal */
namespace ts.refactor {
const actionName = "Convert to ES6 module";
const description = getLocaleSpecificMessage(Diagnostics.Convert_to_ES6_module);
registerRefactor(actionName, { getEditsForAction, getAvailableActions });
function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined {
const { file, startPosition } = context;
if (!isSourceFileJavaScript(file) || !file.commonJsModuleIndicator) {
return undefined;
}
const node = getTokenAtPosition(file, startPosition, /*includeJsDocComment*/ false);
return !isAtTriggerLocation(file, node) ? undefined : [
{
name: actionName,
description,
actions: [
{
description,
name: actionName,
},
],
},
];
}
function isAtTriggerLocation(sourceFile: SourceFile, node: Node, onSecondTry = false): boolean {
switch (node.kind) {
case SyntaxKind.CallExpression:
return isAtTopLevelRequire(node as CallExpression);
case SyntaxKind.PropertyAccessExpression:
return isExportsOrModuleExportsOrAlias(sourceFile, node as PropertyAccessExpression)
|| isExportsOrModuleExportsOrAlias(sourceFile, (node as PropertyAccessExpression).expression);
case SyntaxKind.VariableDeclarationList:
return isVariableDeclarationTriggerLocation(firstOrUndefined((node as VariableDeclarationList).declarations));
case SyntaxKind.VariableDeclaration:
return isVariableDeclarationTriggerLocation(node as VariableDeclaration);
default:
return isExpression(node) && isExportsOrModuleExportsOrAlias(sourceFile, node)
|| !onSecondTry && isAtTriggerLocation(sourceFile, node.parent, /*onSecondTry*/ true);
}
function isVariableDeclarationTriggerLocation(decl: VariableDeclaration | undefined) {
return !!decl && !!decl.initializer && isExportsOrModuleExportsOrAlias(sourceFile, decl.initializer);
}
}
function isAtTopLevelRequire(call: CallExpression): boolean {
if (!isRequireCall(call, /*checkArgumentIsStringLiteral*/ true)) {
return false;
}
const { parent: propAccess } = call;
const varDecl = isPropertyAccessExpression(propAccess) ? propAccess.parent : propAccess;
if (isExpressionStatement(varDecl) && isSourceFile(varDecl.parent)) { // `require("x");` as a statement
return true;
}
if (!isVariableDeclaration(varDecl)) {
return false;
}
const { parent: varDeclList } = varDecl;
if (varDeclList.kind !== SyntaxKind.VariableDeclarationList) {
return false;
}
const { parent: varStatement } = varDeclList;
return varStatement.kind === SyntaxKind.VariableStatement && varStatement.parent.kind === SyntaxKind.SourceFile;
}
function getEditsForAction(context: RefactorContext, _actionName: string): RefactorEditInfo | undefined {
Debug.assertEqual(actionName, _actionName);
const { file, program } = context;
Debug.assert(isSourceFileJavaScript(file));
const edits = textChanges.ChangeTracker.with(context, changes => {
const moduleExportsChangedToDefault = convertFileToEs6Module(file, program.getTypeChecker(), changes, program.getCompilerOptions().target);
if (moduleExportsChangedToDefault) {
for (const importingFile of program.getSourceFiles()) {
fixImportOfModuleExports(importingFile, file, changes);
namespace ts.codefix {
registerCodeFix({
errorCodes: [Diagnostics.File_is_a_CommonJS_module_it_may_be_converted_to_an_ES6_module.code],
getCodeActions(context) {
const description = getLocaleSpecificMessage(Diagnostics.Convert_to_ES6_module);
const { sourceFile, program } = context;
const changes = textChanges.ChangeTracker.with(context, changes => {
const moduleExportsChangedToDefault = convertFileToEs6Module(sourceFile, program.getTypeChecker(), changes, program.getCompilerOptions().target);
if (moduleExportsChangedToDefault) {
for (const importingFile of program.getSourceFiles()) {
fixImportOfModuleExports(importingFile, sourceFile, changes);
}
}
}
});
return { edits, renameFilename: undefined, renameLocation: undefined };
}
});
// No support for fix-all since this applies to the whole file at once anyway.
return [{ description, changes, fixId: undefined }];
},
});
function fixImportOfModuleExports(importingFile: ts.SourceFile, exportingFile: ts.SourceFile, changes: textChanges.ChangeTracker) {
for (const moduleSpecifier of importingFile.imports) {
+1
View File
@@ -1,4 +1,5 @@
/// <reference path="addMissingInvocationForDecorator.ts" />
/// <reference path="convertToEs6Module.ts" />
/// <reference path="correctQualifiedNameToIndexedAccessType.ts" />
/// <reference path="fixClassIncorrectlyImplementsInterface.ts" />
/// <reference path="fixAddMissingMember.ts" />
-1
View File
@@ -1,6 +1,5 @@
/// <reference path="annotateWithTypeFromJSDoc.ts" />
/// <reference path="convertFunctionToEs6Class.ts" />
/// <reference path="convertToEs6Module.ts" />
/// <reference path="extractSymbol.ts" />
/// <reference path="installTypesForPackage.ts" />
/// <reference path="useDefaultImport.ts" />
+7
View File
@@ -20,6 +20,7 @@
/// <reference path='preProcess.ts' />
/// <reference path='rename.ts' />
/// <reference path='signatureHelp.ts' />
/// <reference path='suggestionDiagnostics.ts' />
/// <reference path='symbolDisplay.ts' />
/// <reference path='transpile.ts' />
/// <reference path='formatting\formatting.ts' />
@@ -1419,6 +1420,11 @@ namespace ts {
return [...semanticDiagnostics, ...declarationDiagnostics];
}
function getSuggestionDiagnostics(fileName: string): Diagnostic[] {
synchronizeHostData();
return computeSuggestionDiagnostics(getValidSourceFile(fileName));
}
function getCompilerOptionsDiagnostics() {
synchronizeHostData();
return [...program.getOptionsDiagnostics(cancellationToken), ...program.getGlobalDiagnostics(cancellationToken)];
@@ -2101,6 +2107,7 @@ namespace ts {
cleanupSemanticCache,
getSyntacticDiagnostics,
getSemanticDiagnostics,
getSuggestionDiagnostics,
getCompilerOptionsDiagnostics,
getSyntacticClassifications,
getSemanticClassifications,
+6 -2
View File
@@ -144,6 +144,7 @@ namespace ts {
getSyntacticDiagnostics(fileName: string): string;
getSemanticDiagnostics(fileName: string): string;
getSuggestionDiagnostics(fileName: string): string;
getCompilerOptionsDiagnostics(): string;
getSyntacticClassifications(fileName: string, start: number, length: number): string;
@@ -597,8 +598,7 @@ namespace ts {
message: flattenDiagnosticMessageText(diagnostic.messageText, newLine),
start: diagnostic.start,
length: diagnostic.length,
/// TODO: no need for the tolowerCase call
category: DiagnosticCategory[diagnostic.category].toLowerCase(),
category: diagnosticCategoryName(diagnostic),
code: diagnostic.code
};
}
@@ -716,6 +716,10 @@ namespace ts {
});
}
public getSuggestionDiagnostics(fileName: string): string {
return this.forwardJSONCall(`getSuggestionDiagnostics('${fileName}')`, () => this.realizeDiagnostics(this.languageService.getSuggestionDiagnostics(fileName)));
}
public getCompilerOptionsDiagnostics(): string {
return this.forwardJSONCall(
"getCompilerOptionsDiagnostics()",
+8
View File
@@ -0,0 +1,8 @@
/* @internal */
namespace ts {
export function computeSuggestionDiagnostics(sourceFile: SourceFile): Diagnostic[] {
return sourceFile.commonJsModuleIndicator
? [createDiagnosticForNode(sourceFile.commonJsModuleIndicator, Diagnostics.File_is_a_CommonJS_module_it_may_be_converted_to_an_ES6_module)]
: emptyArray;
}
}
+1
View File
@@ -70,6 +70,7 @@
"semver.ts",
"shims.ts",
"signatureHelp.ts",
"suggestionDiagnostics.ts",
"symbolDisplay.ts",
"textChanges.ts",
"refactorProvider.ts",
+1
View File
@@ -223,6 +223,7 @@ namespace ts {
getSyntacticDiagnostics(fileName: string): Diagnostic[];
getSemanticDiagnostics(fileName: string): Diagnostic[];
getSuggestionDiagnostics(fileName: string): Diagnostic[];
// TODO: Rename this to getProgramDiagnostics to better indicate that these are any
// diagnostics present for the program level, and not just 'options' diagnostics.
+16 -3
View File
@@ -2262,7 +2262,8 @@ declare namespace ts {
enum DiagnosticCategory {
Warning = 0,
Error = 1,
Message = 2,
Suggestion = 2,
Message = 3,
}
enum ModuleResolutionKind {
Classic = 1,
@@ -4054,6 +4055,7 @@ declare namespace ts {
cleanupSemanticCache(): void;
getSyntacticDiagnostics(fileName: string): Diagnostic[];
getSemanticDiagnostics(fileName: string): Diagnostic[];
getSuggestionDiagnostics(fileName: string): Diagnostic[];
getCompilerOptionsDiagnostics(): Diagnostic[];
/**
* @deprecated Use getEncodedSyntacticClassifications instead.
@@ -5024,6 +5026,7 @@ declare namespace ts.server.protocol {
GeterrForProject = "geterrForProject",
SemanticDiagnosticsSync = "semanticDiagnosticsSync",
SyntacticDiagnosticsSync = "syntacticDiagnosticsSync",
SuggestionDiagnosticsSync = "suggestionDiagnosticsSync",
NavBar = "navbar",
Navto = "navto",
NavTree = "navtree",
@@ -6546,6 +6549,12 @@ declare namespace ts.server.protocol {
interface SemanticDiagnosticsSyncResponse extends Response {
body?: Diagnostic[] | DiagnosticWithLinePosition[];
}
interface SuggestionDiagnosticsSyncRequest extends FileRequest {
command: CommandTypes.SuggestionDiagnosticsSync;
arguments: SuggestionDiagnosticsSyncRequestArgs;
}
type SuggestionDiagnosticsSyncRequestArgs = SemanticDiagnosticsSyncRequestArgs;
type SuggestionDiagnosticsSyncResponse = SemanticDiagnosticsSyncResponse;
/**
* Synchronous request for syntactic diagnostics of one file.
*/
@@ -6642,7 +6651,7 @@ declare namespace ts.server.protocol {
*/
text: string;
/**
* The category of the diagnostic message, e.g. "error" vs. "warning"
* The category of the diagnostic message, e.g. "error", "warning", or "suggestion".
*/
category: string;
/**
@@ -6670,8 +6679,9 @@ declare namespace ts.server.protocol {
*/
diagnostics: Diagnostic[];
}
type DiagnosticEventKind = "semanticDiag" | "syntaxDiag" | "suggestionDiag";
/**
* Event message for "syntaxDiag" and "semanticDiag" event types.
* Event message for DiagnosticEventKind event types.
* These events provide syntactic and semantic errors for a file.
*/
interface DiagnosticEvent extends Event {
@@ -7206,6 +7216,8 @@ declare namespace ts.server {
private doOutput(info, cmdName, reqSeq, success, message?);
private semanticCheck(file, project);
private syntacticCheck(file, project);
private infoCheck(file, project);
private sendDiagnosticsEvent(file, project, diagnostics, kind);
private updateErrorCheck(next, checkList, ms, requireOpen?);
private cleanProjects(caption, projects);
private cleanup();
@@ -7226,6 +7238,7 @@ declare namespace ts.server {
private getOccurrences(args);
private getSyntacticDiagnosticsSync(args);
private getSemanticDiagnosticsSync(args);
private getSuggestionDiagnosticsSync(args);
private getDocumentHighlights(args, simplifiedResult);
private setCompilerOptionsForInferredProjects(args);
private getProjectInfo(args);
+3 -1
View File
@@ -2262,7 +2262,8 @@ declare namespace ts {
enum DiagnosticCategory {
Warning = 0,
Error = 1,
Message = 2,
Suggestion = 2,
Message = 3,
}
enum ModuleResolutionKind {
Classic = 1,
@@ -4306,6 +4307,7 @@ declare namespace ts {
cleanupSemanticCache(): void;
getSyntacticDiagnostics(fileName: string): Diagnostic[];
getSemanticDiagnostics(fileName: string): Diagnostic[];
getSuggestionDiagnostics(fileName: string): Diagnostic[];
getCompilerOptionsDiagnostics(): Diagnostic[];
/**
* @deprecated Use getEncodedSyntacticClassifications instead.
@@ -14,8 +14,6 @@
// @Filename: /d.ts
//// /// <reference path="[|./a.ts|]" />
verify.noErrors();
const ranges = test.ranges();
const [r0, r1, r2] = ranges;
verify.referenceGroups(ranges, [{ definition: 'module "/a"', ranges: [r0, r2, r1] }]);
+1
View File
@@ -349,6 +349,7 @@ declare namespace FourSlashInterface {
}, displayParts: ts.SymbolDisplayPart[], documentation: ts.SymbolDisplayPart[], tags: ts.JSDocTagInfo[]): void;
getSyntacticDiagnostics(expected: ReadonlyArray<RealizedDiagnostic>): void;
getSemanticDiagnostics(expected: ReadonlyArray<RealizedDiagnostic>): void;
getSuggestionDiagnostics(expected: ReadonlyArray<RealizedDiagnostic>): void;
ProjectInfo(expected: string[]): void;
allRangesAppearInImplementationList(markerName: string): void;
}
@@ -5,14 +5,11 @@
// @Filename: /a.js
////const exportsAlias = exports;
////exportsAlias.f = function() {};
/////*a*/module/*b*/.exports = exportsAlias;
////module.exports = exportsAlias;
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `
verify.codeFix({
description: "Convert to ES6 module",
newFileContent: `
export function f() { }
`,
});
@@ -5,15 +5,13 @@
// @allowJs: true
// @Filename: /a.js
/////*a*/exports/*b*/.default = 0;
////exports.default = 0;
////exports.default;
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `const _default = 0;
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`const _default = 0;
export { _default as default };
_default;`,
});
@@ -5,15 +5,13 @@
// @allowJs: true
// @Filename: /a.js
/////*a*/exports/*b*/.class = 0;
////exports.class = 0;
////exports.async = 1;
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `const _class = 0;
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`const _class = 0;
export { _class as class };
export const async = 1;`,
});
@@ -3,7 +3,7 @@
// @allowJs: true
// @Filename: /a.js
/////*a*/module/*b*/.exports = function() {}
////module.exports = function() {}
////module.exports = function f() {}
////module.exports = class {}
////module.exports = class C {}
@@ -11,16 +11,14 @@
// See also `refactorConvertToEs6Module_export_moduleDotExportsEqualsRequire.ts`
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `export default function() { }
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`export default function() { }
export default function f() { }
export default class {
}
export default class C {
}
export default 0;`
export default 0;`,
});
@@ -18,7 +18,7 @@
// @Filename: /z.js
// Normally -- just `export *`
/////*a*/module/*b*/.exports = require("./a");
////module.exports = require("./a");
// If just a default is exported, just `export { default }`
////module.exports = require("./b");
// May need both
@@ -28,12 +28,10 @@
// In untyped case just go with `export *`
////module.exports = require("./unknown");
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent:
goTo.file("/z.js");
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`export * from "./a";
export { default } from "./b";
export * from "./c";
@@ -3,7 +3,7 @@
// @allowJs: true
// @Filename: /a.js
/////*a*/module/*b*/.exports = 0;
////module.exports = 0;
// @Filename: /b.ts
////import a = require("./a");
@@ -11,12 +11,9 @@
// @Filename: /c.js
////const a = require("./a");
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `export default 0;`,
verify.codeFix({
description: "Convert to ES6 module",
newFileContent: "export default 0;",
});
goTo.file("/b.ts");
@@ -3,16 +3,22 @@
// @allowJs: true
// @Filename: /a.js
/////*a*/exports/*b*/.f = function() {}
////exports.f = function() {}/*diagEnd*/
////exports.C = class {}
////exports.x = 0;
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `export function f() { }
verify.getSuggestionDiagnostics([{
message: "File is a CommonJS module; it may be converted to an ES6 module.",
start: 0,
length: test.marker("diagEnd").position,
category: "suggestion",
code: 80001,
}]);
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`export function f() { }
export class C {
}
export const x = 0;`,
@@ -3,15 +3,12 @@
// @allowJs: true
// @Filename: /a.js
/////*a*/exports/*b*/.f = function g() { g(); }
////exports.f = function g() { g(); }
////exports.h = function h() { h(); }
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent:
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`export const f = function g() { g(); };
export function h() { h(); }`
export function h() { h(); }`,
});
@@ -3,7 +3,7 @@
// @allowJs: true
// @Filename: /a.js
/////*a*/module/*b*/.exports = {
////module.exports = {
//// x: 0,
//// f: function() {},
//// g: () => {},
@@ -11,12 +11,10 @@
//// C: class {},
////};
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `export const x = 0;
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`export const x = 0;
export function f() { }
export function g() { }
export function h() { }
@@ -6,13 +6,11 @@
// @Filename: /a.js
////function f() {}
/////*a*/module/*b*/.exports = { f };
////module.exports = { f };
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `function f() {}
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`function f() {}
export default { f };`,
});
@@ -7,7 +7,7 @@
////exports.x;
////
////const y = 1;
/////*a*/exports/*b*/.y = y;
////exports.y = y;
////exports.y;
////
////exports.z = 2;
@@ -15,12 +15,10 @@
//// exports.z;
////}
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `export const x = 0;
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`export const x = 0;
x;
const y = 1;
@@ -3,15 +3,13 @@
// @allowJs: true
// @Filename: /a.js
/////*a*/exports/*b*/.f = async function* f(p) {}
////exports.f = async function* f(p) {}
////exports.C = class C extends D { m() {} }
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `export async function* f(p) { }
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`export async function* f(p) { }
export class C extends D {
m() { }
}`,
@@ -5,11 +5,8 @@
// @Filename: /a.js
////const [x, y] = /*a*/require/*b*/("x");
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `import _x from "x";
verify.codeFix({
description: "Convert to ES6 module",
newFileContent: `import _x from "x";
const [x, y] = _x;`,
});
@@ -7,12 +7,10 @@
////x();
////x.y;
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `import x, { y } from "x";
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`import x, { y } from "x";
x();
y;`,
});
@@ -4,17 +4,15 @@
// @Filename: /a.js
////const x = require("x");
////const [a, b] = /*a*/require/*b*/("x");
////const [a, b] = require("x");
////const {c, ...d} = require("x");
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `import x from "x";
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`import x from "x";
import _x from "x";
const [a, b] = _x;
import __x from "x";
const { c, ...d } = __x;`
const { c, ...d } = __x;`,
});
@@ -5,14 +5,12 @@
// @allowJs: true
// @Filename: /a.js
////const x = /*a*/require/*b*/("x"), y = 0, { z } = require("z");
////const x = require("x"), y = 0, { z } = require("z");
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `import x from "x";
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`import x from "x";
const y = 0;
import { z } from "z";`,
});
@@ -3,19 +3,17 @@
// @allowJs: true
// @Filename: /a.js
////const [] = /*a0*/require/*b0*/("a-b");
////const [] = /*a1*/require/*b1*/("0a");
////const [] = /*a2*/require/*b2*/("1a");
////const [] = require("a-b");
////const [] = require("0a");
////const [] = require("1a");
goTo.select("a0", "b0");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `import aB from "a-b";
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`import aB from "a-b";
const [] = aB;
import A from "0a";
const [] = A;
import _A from "1a";
const [] = _A;`
const [] = _A;`,
});
@@ -3,13 +3,11 @@
// @allowJs: true
// @Filename: /a.js
////const { x: { a, b } } = /*a*/require/*b*/("x");
////const { x: { a, b } } = require("x");
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `import x from "x";
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`import x from "x";
const { x: { a, b } } = x;`,
});
@@ -3,12 +3,9 @@
// @allowJs: true
// @Filename: /a.js
////const { x, y: z } = /*a*/require/*b*/("x");
////const { x, y: z } = require("x");
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: 'import { x, y as z } from "x";',
verify.codeFix({
description: "Convert to ES6 module",
newFileContent: 'import { x, y as z } from "x";',
});
@@ -3,14 +3,12 @@
// @allowJs: true
// @Filename: /a.js
////const x = /*a*/require/*b*/("x");
////const x = require("x");
////x.y;
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `import { y } from "x";
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`import { y } from "x";
y;`,
});
@@ -3,18 +3,16 @@
// @allowJs: true
// @Filename: /a.js
////const x = /*a*/require/*b*/("x").default;
////const x = require("x").default;
////const a = require("b").c;
////const a = require("a").a;
////const [a, b] = require("c").d;
////const [a, b] = require("c").a; // Test that we avoid shadowing the earlier local variable 'a' from 'const [a,b] = d;'.
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `import x from "x";
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`import x from "x";
import { c as a } from "b";
import { a } from "a";
import { d } from "c";
@@ -3,16 +3,14 @@
// @allowJs: true
// @Filename: /a.js
////const mod = /*a*/require/*b*/("mod");
////const mod = require("mod");
////const x = 0;
////mod.x(x);
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: `import { x as _x } from "mod";
verify.codeFix({
description: "Convert to ES6 module",
newFileContent:
`import { x as _x } from "mod";
const x = 0;
_x(x);`
_x(x);`,
});
@@ -7,10 +7,7 @@
// @Filename: /a.js
/////*a*/require/*b*/("foo");
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert to ES6 module",
actionName: "Convert to ES6 module",
actionDescription: "Convert to ES6 module",
newContent: 'import "foo";',
verify.codeFix({
description: "Convert to ES6 module",
newFileContent: 'import "foo";',
});
@@ -1,13 +0,0 @@
/// <reference path='fourslash.ts' />
// @allowJs: true
// @Filename: /a.js
////c[|o|]nst [|a|]lias [|=|] [|m|]odule[|.|]export[|s|];
////[|a|]lias[|.|][|x|] = 0;
////[|module.exports|];
////[|require("x")|];
////[|require("x").y;|];
goTo.eachRange(() => verify.refactorAvailable("Convert to ES6 module"));
@@ -1,9 +0,0 @@
/// <reference path='fourslash.ts' />
// @allowJs: true
// @Filename: /a.js
////c[|o|]nst;
////require("x");
goTo.eachRange(() => verify.not.refactorAvailable("Convert to ES6 module"));
@@ -1,11 +0,0 @@
/// <reference path='fourslash.ts' />
// @allowJs: true
// @Filename: /a.js
/////*a*/const/*b*/ alias;
////require("x");
goTo.select("a", "b");
verify.not.refactorAvailable("Convert to ES6 module");