mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
@@ -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
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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++;
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -216,6 +216,7 @@ namespace ts.server {
|
||||
CommandNames.GeterrForProject,
|
||||
CommandNames.SemanticDiagnosticsSync,
|
||||
CommandNames.SyntacticDiagnosticsSync,
|
||||
CommandNames.SuggestionDiagnosticsSync,
|
||||
CommandNames.NavBar,
|
||||
CommandNames.NavBarFull,
|
||||
CommandNames.Navto,
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
+17
-80
@@ -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,4 +1,5 @@
|
||||
/// <reference path="addMissingInvocationForDecorator.ts" />
|
||||
/// <reference path="convertToEs6Module.ts" />
|
||||
/// <reference path="correctQualifiedNameToIndexedAccessType.ts" />
|
||||
/// <reference path="fixClassIncorrectlyImplementsInterface.ts" />
|
||||
/// <reference path="fixAddMissingMember.ts" />
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,7 @@
|
||||
"semver.ts",
|
||||
"shims.ts",
|
||||
"signatureHelp.ts",
|
||||
"suggestionDiagnostics.ts",
|
||||
"symbolDisplay.ts",
|
||||
"textChanges.ts",
|
||||
"refactorProvider.ts",
|
||||
|
||||
@@ -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
@@ -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
@@ -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] }]);
|
||||
|
||||
@@ -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;`,
|
||||
});
|
||||
|
||||
+5
-7
@@ -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";
|
||||
|
||||
+4
-7
@@ -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;`,
|
||||
});
|
||||
|
||||
+6
-8
@@ -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
-7
@@ -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;`,
|
||||
});
|
||||
|
||||
+5
-7
@@ -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;`,
|
||||
});
|
||||
|
||||
+4
-7
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user