|
|
|
|
@@ -80,6 +80,92 @@ namespace ts.tscWatch {
|
|
|
|
|
checkOutputDoesNotContain(host, expectedNonAffectedFiles);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkOutputErrors(host: WatchedSystem, errors?: ReadonlyArray<Diagnostic>, isInitial?: true, skipWaiting?: true) {
|
|
|
|
|
const outputs = host.getOutput();
|
|
|
|
|
const expectedOutputCount = (isInitial ? 0 : 1) + (errors ? errors.length : 0) + (skipWaiting ? 0 : 1);
|
|
|
|
|
assert.equal(outputs.length, expectedOutputCount, "Outputs = " + outputs.toString());
|
|
|
|
|
let index = 0;
|
|
|
|
|
if (!isInitial) {
|
|
|
|
|
assertWatchDiagnosticAt(host, index, Diagnostics.File_change_detected_Starting_incremental_compilation);
|
|
|
|
|
index++;
|
|
|
|
|
}
|
|
|
|
|
forEach(errors, error => {
|
|
|
|
|
assertDiagnosticAt(host, index, error);
|
|
|
|
|
index++;
|
|
|
|
|
});
|
|
|
|
|
if (!skipWaiting) {
|
|
|
|
|
assertWatchDiagnosticAt(host, index, Diagnostics.Compilation_complete_Watching_for_file_changes);
|
|
|
|
|
}
|
|
|
|
|
host.clearOutput();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function assertDiagnosticAt(host: WatchedSystem, outputAt: number, diagnostic: Diagnostic) {
|
|
|
|
|
const output = host.getOutput()[outputAt];
|
|
|
|
|
assert.equal(output, formatDiagnostic(diagnostic, host), "outputs[" + outputAt + "] is " + output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function assertWatchDiagnosticAt(host: WatchedSystem, outputAt: number, diagnosticMessage: DiagnosticMessage) {
|
|
|
|
|
const output = host.getOutput()[outputAt];
|
|
|
|
|
assert.isTrue(endsWith(output, getWatchDiagnosticWithoutDate(host, diagnosticMessage)), "outputs[" + outputAt + "] is " + output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getWatchDiagnosticWithoutDate(host: WatchedSystem, diagnosticMessage: DiagnosticMessage) {
|
|
|
|
|
return ` - ${flattenDiagnosticMessageText(getLocaleSpecificMessage(diagnosticMessage), host.newLine)}${host.newLine + host.newLine + host.newLine}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getDiagnosticOfFileFrom(file: SourceFile, text: string, start: number, length: number, message: DiagnosticMessage): Diagnostic {
|
|
|
|
|
return {
|
|
|
|
|
file,
|
|
|
|
|
start,
|
|
|
|
|
length,
|
|
|
|
|
|
|
|
|
|
messageText: text,
|
|
|
|
|
category: message.category,
|
|
|
|
|
code: message.code,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getDiagnosticWithoutFile(message: DiagnosticMessage, ..._args: (string | number)[]): Diagnostic {
|
|
|
|
|
let text = getLocaleSpecificMessage(message);
|
|
|
|
|
|
|
|
|
|
if (arguments.length > 1) {
|
|
|
|
|
text = formatStringFromArgs(text, arguments, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return getDiagnosticOfFileFrom(/*file*/ undefined, text, /*start*/ undefined, /*length*/ undefined, message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getDiagnosticOfFile(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ..._args: (string | number)[]): Diagnostic {
|
|
|
|
|
let text = getLocaleSpecificMessage(message);
|
|
|
|
|
|
|
|
|
|
if (arguments.length > 4) {
|
|
|
|
|
text = formatStringFromArgs(text, arguments, 4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return getDiagnosticOfFileFrom(file, text, start, length, message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getUnknownCompilerOption(program: Program, configFile: FileOrFolder, option: string) {
|
|
|
|
|
const quotedOption = `"${option}"`;
|
|
|
|
|
return getDiagnosticOfFile(program.getCompilerOptions().configFile, configFile.content.indexOf(quotedOption), quotedOption.length, Diagnostics.Unknown_compiler_option_0, option);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getDiagnosticOfFileFromProgram(program: Program, filePath: string, start: number, length: number, message: DiagnosticMessage, ..._args: (string | number)[]): Diagnostic {
|
|
|
|
|
let text = getLocaleSpecificMessage(message);
|
|
|
|
|
|
|
|
|
|
if (arguments.length > 5) {
|
|
|
|
|
text = formatStringFromArgs(text, arguments, 5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return getDiagnosticOfFileFrom(program.getSourceFileByPath(toPath(filePath, program.getCurrentDirectory(), s => s.toLowerCase())),
|
|
|
|
|
text, start, length, message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getDiagnosticModuleNotFoundOfFile(program: Program, file: FileOrFolder, moduleName: string) {
|
|
|
|
|
const quotedModuleName = `"${moduleName}"`;
|
|
|
|
|
return getDiagnosticOfFileFromProgram(program, file.path, file.content.indexOf(quotedModuleName), quotedModuleName.length, Diagnostics.Cannot_find_module_0, moduleName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
describe("tsc-watch program updates", () => {
|
|
|
|
|
const commonFile1: FileOrFolder = {
|
|
|
|
|
path: "/a/b/commonFile1.ts",
|
|
|
|
|
@@ -233,9 +319,10 @@ namespace ts.tscWatch {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("handles the missing files - that were added to program because they were added with ///<ref", () => {
|
|
|
|
|
const commonFile2Name = "commonFile2.ts";
|
|
|
|
|
const file1: FileOrFolder = {
|
|
|
|
|
path: "/a/b/commonFile1.ts",
|
|
|
|
|
content: `/// <reference path="commonFile2.ts"/>
|
|
|
|
|
content: `/// <reference path="${commonFile2Name}"/>
|
|
|
|
|
let x = y`
|
|
|
|
|
};
|
|
|
|
|
const host = createWatchedSystem([file1, libFile]);
|
|
|
|
|
@@ -243,18 +330,16 @@ namespace ts.tscWatch {
|
|
|
|
|
|
|
|
|
|
checkProgramRootFiles(watch(), [file1.path]);
|
|
|
|
|
checkProgramActualFiles(watch(), [file1.path, libFile.path]);
|
|
|
|
|
const errors = [
|
|
|
|
|
`a/b/commonFile1.ts(1,22): error TS6053: File '${commonFile2.path}' not found.${host.newLine}`,
|
|
|
|
|
`a/b/commonFile1.ts(2,29): error TS2304: Cannot find name 'y'.${host.newLine}`
|
|
|
|
|
];
|
|
|
|
|
checkOutputContains(host, errors);
|
|
|
|
|
host.clearOutput();
|
|
|
|
|
checkOutputErrors(host, [
|
|
|
|
|
getDiagnosticOfFileFromProgram(watch(), file1.path, file1.content.indexOf(commonFile2Name), commonFile2Name.length, Diagnostics.File_0_not_found, commonFile2.path),
|
|
|
|
|
getDiagnosticOfFileFromProgram(watch(), file1.path, file1.content.indexOf("y"), 1, Diagnostics.Cannot_find_name_0, "y")
|
|
|
|
|
], /*isInitial*/ true);
|
|
|
|
|
|
|
|
|
|
host.reloadFS([file1, commonFile2, libFile]);
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
checkProgramRootFiles(watch(), [file1.path]);
|
|
|
|
|
checkProgramActualFiles(watch(), [file1.path, libFile.path, commonFile2.path]);
|
|
|
|
|
checkOutputDoesNotContain(host, errors);
|
|
|
|
|
checkOutputErrors(host);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should reflect change in config file", () => {
|
|
|
|
|
@@ -578,17 +663,19 @@ namespace ts.tscWatch {
|
|
|
|
|
path: "/a/b/tsconfig.json",
|
|
|
|
|
content: JSON.stringify({ compilerOptions: {} })
|
|
|
|
|
};
|
|
|
|
|
const host = createWatchedSystem([file1, file2, config]);
|
|
|
|
|
const host = createWatchedSystem([file1, file2, libFile, config]);
|
|
|
|
|
const watch = createWatchModeWithConfigFile(config.path, host);
|
|
|
|
|
|
|
|
|
|
checkProgramActualFiles(watch(), [file1.path, file2.path]);
|
|
|
|
|
checkProgramActualFiles(watch(), [file1.path, file2.path, libFile.path]);
|
|
|
|
|
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
|
|
|
|
|
|
|
|
|
|
host.clearOutput();
|
|
|
|
|
host.reloadFS([file1, file2]);
|
|
|
|
|
host.reloadFS([file1, file2, libFile]);
|
|
|
|
|
host.checkTimeoutQueueLengthAndRun(1);
|
|
|
|
|
|
|
|
|
|
assert.equal(host.exitCode, ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
|
|
|
|
checkOutputContains(host, [`error TS6053: File '${config.path}' not found.${host.newLine}`]);
|
|
|
|
|
checkOutputErrors(host, [
|
|
|
|
|
getDiagnosticWithoutFile(Diagnostics.File_0_not_found, config.path)
|
|
|
|
|
], /*isInitial*/ undefined, /*skipWaiting*/ true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("Proper errors: document is not contained in project", () => {
|
|
|
|
|
@@ -687,25 +774,25 @@ namespace ts.tscWatch {
|
|
|
|
|
};
|
|
|
|
|
const file1 = {
|
|
|
|
|
path: "/a/b/file1.ts",
|
|
|
|
|
content: "import * as T from './moduleFile'; T.bar();"
|
|
|
|
|
content: 'import * as T from "./moduleFile"; T.bar();'
|
|
|
|
|
};
|
|
|
|
|
const host = createWatchedSystem([moduleFile, file1, libFile]);
|
|
|
|
|
createWatchModeWithoutConfigFile([file1.path], host);
|
|
|
|
|
const error = "a/b/file1.ts(1,20): error TS2307: Cannot find module \'./moduleFile\'.\n";
|
|
|
|
|
checkOutputDoesNotContain(host, [error]);
|
|
|
|
|
const watch = createWatchModeWithoutConfigFile([file1.path], host);
|
|
|
|
|
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
|
|
|
|
|
|
|
|
|
|
const moduleFileOldPath = moduleFile.path;
|
|
|
|
|
const moduleFileNewPath = "/a/b/moduleFile1.ts";
|
|
|
|
|
moduleFile.path = moduleFileNewPath;
|
|
|
|
|
host.reloadFS([moduleFile, file1, libFile]);
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
checkOutputContains(host, [error]);
|
|
|
|
|
checkOutputErrors(host, [
|
|
|
|
|
getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile")
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
host.clearOutput();
|
|
|
|
|
moduleFile.path = moduleFileOldPath;
|
|
|
|
|
host.reloadFS([moduleFile, file1, libFile]);
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
checkOutputDoesNotContain(host, [error]);
|
|
|
|
|
checkOutputErrors(host);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("rename a module file and rename back should restore the states for configured projects", () => {
|
|
|
|
|
@@ -715,31 +802,29 @@ namespace ts.tscWatch {
|
|
|
|
|
};
|
|
|
|
|
const file1 = {
|
|
|
|
|
path: "/a/b/file1.ts",
|
|
|
|
|
content: "import * as T from './moduleFile'; T.bar();"
|
|
|
|
|
content: 'import * as T from "./moduleFile"; T.bar();'
|
|
|
|
|
};
|
|
|
|
|
const configFile = {
|
|
|
|
|
path: "/a/b/tsconfig.json",
|
|
|
|
|
content: `{}`
|
|
|
|
|
};
|
|
|
|
|
const host = createWatchedSystem([moduleFile, file1, configFile, libFile]);
|
|
|
|
|
createWatchModeWithConfigFile(configFile.path, host);
|
|
|
|
|
|
|
|
|
|
const error = "a/b/file1.ts(1,20): error TS2307: Cannot find module \'./moduleFile\'.\n";
|
|
|
|
|
checkOutputDoesNotContain(host, [error]);
|
|
|
|
|
const watch = createWatchModeWithConfigFile(configFile.path, host);
|
|
|
|
|
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
|
|
|
|
|
|
|
|
|
|
const moduleFileOldPath = moduleFile.path;
|
|
|
|
|
const moduleFileNewPath = "/a/b/moduleFile1.ts";
|
|
|
|
|
moduleFile.path = moduleFileNewPath;
|
|
|
|
|
host.clearOutput();
|
|
|
|
|
host.reloadFS([moduleFile, file1, configFile, libFile]);
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
checkOutputContains(host, [error]);
|
|
|
|
|
checkOutputErrors(host, [
|
|
|
|
|
getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile")
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
host.clearOutput();
|
|
|
|
|
moduleFile.path = moduleFileOldPath;
|
|
|
|
|
host.reloadFS([moduleFile, file1, configFile, libFile]);
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
checkOutputDoesNotContain(host, [error]);
|
|
|
|
|
checkOutputErrors(host);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("types should load from config file path if config exists", () => {
|
|
|
|
|
@@ -771,18 +856,18 @@ namespace ts.tscWatch {
|
|
|
|
|
};
|
|
|
|
|
const file1 = {
|
|
|
|
|
path: "/a/b/file1.ts",
|
|
|
|
|
content: "import * as T from './moduleFile'; T.bar();"
|
|
|
|
|
content: 'import * as T from "./moduleFile"; T.bar();'
|
|
|
|
|
};
|
|
|
|
|
const host = createWatchedSystem([file1, libFile]);
|
|
|
|
|
createWatchModeWithoutConfigFile([file1.path], host);
|
|
|
|
|
const watch = createWatchModeWithoutConfigFile([file1.path], host);
|
|
|
|
|
|
|
|
|
|
const error = `a/b/file1.ts(1,20): error TS2307: Cannot find module \'./moduleFile\'.${host.newLine}`;
|
|
|
|
|
checkOutputContains(host, [error]);
|
|
|
|
|
host.clearOutput();
|
|
|
|
|
checkOutputErrors(host, [
|
|
|
|
|
getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile")
|
|
|
|
|
], /*isInitial*/ true);
|
|
|
|
|
|
|
|
|
|
host.reloadFS([file1, moduleFile, libFile]);
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
checkOutputDoesNotContain(host, [error]);
|
|
|
|
|
checkOutputErrors(host);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("Configure file diagnostics events are generated when the config file has errors", () => {
|
|
|
|
|
@@ -801,14 +886,14 @@ namespace ts.tscWatch {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const host = createWatchedSystem([file, configFile, libFile]);
|
|
|
|
|
createWatchModeWithConfigFile(configFile.path, host);
|
|
|
|
|
checkOutputContains(host, [
|
|
|
|
|
`a/b/tsconfig.json(3,29): error TS5023: Unknown compiler option \'foo\'.${host.newLine}`,
|
|
|
|
|
`a/b/tsconfig.json(4,29): error TS5023: Unknown compiler option \'allowJS\'.${host.newLine}`
|
|
|
|
|
]);
|
|
|
|
|
const watch = createWatchModeWithConfigFile(configFile.path, host);
|
|
|
|
|
checkOutputErrors(host, [
|
|
|
|
|
getUnknownCompilerOption(watch(), configFile, "foo"),
|
|
|
|
|
getUnknownCompilerOption(watch(), configFile, "allowJS")
|
|
|
|
|
], /*isInitial*/ true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("Configure file diagnostics events are generated when the config file doesn't have errors", () => {
|
|
|
|
|
it("If config file doesnt have errors, they are not reported", () => {
|
|
|
|
|
const file = {
|
|
|
|
|
path: "/a/b/app.ts",
|
|
|
|
|
content: "let x = 10"
|
|
|
|
|
@@ -822,13 +907,10 @@ namespace ts.tscWatch {
|
|
|
|
|
|
|
|
|
|
const host = createWatchedSystem([file, configFile, libFile]);
|
|
|
|
|
createWatchModeWithConfigFile(configFile.path, host);
|
|
|
|
|
checkOutputDoesNotContain(host, [
|
|
|
|
|
`a/b/tsconfig.json(3,29): error TS5023: Unknown compiler option \'foo\'.${host.newLine}`,
|
|
|
|
|
`a/b/tsconfig.json(4,29): error TS5023: Unknown compiler option \'allowJS\'.${host.newLine}`
|
|
|
|
|
]);
|
|
|
|
|
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("Configure file diagnostics events are generated when the config file changes", () => {
|
|
|
|
|
it("Reports errors when the config file changes", () => {
|
|
|
|
|
const file = {
|
|
|
|
|
path: "/a/b/app.ts",
|
|
|
|
|
content: "let x = 10"
|
|
|
|
|
@@ -841,9 +923,8 @@ namespace ts.tscWatch {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const host = createWatchedSystem([file, configFile, libFile]);
|
|
|
|
|
createWatchModeWithConfigFile(configFile.path, host);
|
|
|
|
|
const error = `a/b/tsconfig.json(3,25): error TS5023: Unknown compiler option 'haha'.${host.newLine}`;
|
|
|
|
|
checkOutputDoesNotContain(host, [error]);
|
|
|
|
|
const watch = createWatchModeWithConfigFile(configFile.path, host);
|
|
|
|
|
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
|
|
|
|
|
|
|
|
|
|
configFile.content = `{
|
|
|
|
|
"compilerOptions": {
|
|
|
|
|
@@ -852,15 +933,16 @@ namespace ts.tscWatch {
|
|
|
|
|
}`;
|
|
|
|
|
host.reloadFS([file, configFile, libFile]);
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
checkOutputContains(host, [error]);
|
|
|
|
|
checkOutputErrors(host, [
|
|
|
|
|
getUnknownCompilerOption(watch(), configFile, "haha")
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
host.clearOutput();
|
|
|
|
|
configFile.content = `{
|
|
|
|
|
"compilerOptions": {}
|
|
|
|
|
}`;
|
|
|
|
|
host.reloadFS([file, configFile, libFile]);
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
checkOutputDoesNotContain(host, [error]);
|
|
|
|
|
checkOutputErrors(host);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("non-existing directories listed in config file input array should be tolerated without crashing the server", () => {
|
|
|
|
|
@@ -935,29 +1017,28 @@ namespace ts.tscWatch {
|
|
|
|
|
}`;
|
|
|
|
|
const configFileContentWithComment = configFileContentBeforeComment + configFileContentComment + configFileContentAfterComment;
|
|
|
|
|
const configFileContentWithoutCommentLine = configFileContentBeforeComment + configFileContentAfterComment;
|
|
|
|
|
|
|
|
|
|
const line = 5;
|
|
|
|
|
const errors = (line: number) => [
|
|
|
|
|
`a/b/tsconfig.json(${line},25): error TS5053: Option \'allowJs\' cannot be specified with option \'declaration\'.\n`,
|
|
|
|
|
`a/b/tsconfig.json(${line + 1},25): error TS5053: Option \'allowJs\' cannot be specified with option \'declaration\'.\n`
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const configFile = {
|
|
|
|
|
path: "/a/b/tsconfig.json",
|
|
|
|
|
content: configFileContentWithComment
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const host = createWatchedSystem([file, libFile, configFile]);
|
|
|
|
|
createWatchModeWithConfigFile(configFile.path, host);
|
|
|
|
|
checkOutputContains(host, errors(line));
|
|
|
|
|
checkOutputDoesNotContain(host, errors(line - 2));
|
|
|
|
|
host.clearOutput();
|
|
|
|
|
const files = [file, libFile, configFile];
|
|
|
|
|
const host = createWatchedSystem(files);
|
|
|
|
|
const watch = createWatchModeWithConfigFile(configFile.path, host);
|
|
|
|
|
const errors = () => [
|
|
|
|
|
getDiagnosticOfFile(watch().getCompilerOptions().configFile, configFile.content.indexOf('"allowJs"'), '"allowJs"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration"),
|
|
|
|
|
getDiagnosticOfFile(watch().getCompilerOptions().configFile, configFile.content.indexOf('"declaration"'), '"declaration"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration")
|
|
|
|
|
];
|
|
|
|
|
const intialErrors = errors();
|
|
|
|
|
checkOutputErrors(host, intialErrors, /*isInitial*/ true);
|
|
|
|
|
|
|
|
|
|
configFile.content = configFileContentWithoutCommentLine;
|
|
|
|
|
host.reloadFS([file, configFile]);
|
|
|
|
|
host.reloadFS(files);
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
checkOutputContains(host, errors(line - 2));
|
|
|
|
|
checkOutputDoesNotContain(host, errors(line));
|
|
|
|
|
const nowErrors = errors();
|
|
|
|
|
checkOutputErrors(host, nowErrors);
|
|
|
|
|
assert.equal(nowErrors[0].start, intialErrors[0].start - configFileContentComment.length);
|
|
|
|
|
assert.equal(nowErrors[1].start, intialErrors[1].start - configFileContentComment.length);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
@@ -1485,23 +1566,20 @@ namespace ts.tscWatch {
|
|
|
|
|
path: "/a/d/f0.ts",
|
|
|
|
|
content: `import {x} from "f1"`
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const imported = {
|
|
|
|
|
path: "/a/f1.ts",
|
|
|
|
|
content: `foo()`
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const f1IsNotModule = `a/d/f0.ts(1,17): error TS2306: File '${imported.path}' is not a module.\n`;
|
|
|
|
|
const cannotFindFoo = `a/f1.ts(1,1): error TS2304: Cannot find name 'foo'.\n`;
|
|
|
|
|
const cannotAssignValue = "a/d/f0.ts(2,21): error TS2322: Type '1' is not assignable to type 'string'.\n";
|
|
|
|
|
|
|
|
|
|
const files = [root, imported, libFile];
|
|
|
|
|
const host = createWatchedSystem(files);
|
|
|
|
|
createWatchModeWithoutConfigFile([root.path], host, { module: ModuleKind.AMD });
|
|
|
|
|
const watch = createWatchModeWithoutConfigFile([root.path], host, { module: ModuleKind.AMD });
|
|
|
|
|
|
|
|
|
|
const f1IsNotModule = getDiagnosticOfFileFromProgram(watch(), root.path, root.content.indexOf('"f1"'), '"f1"'.length, Diagnostics.File_0_is_not_a_module, imported.path);
|
|
|
|
|
const cannotFindFoo = getDiagnosticOfFileFromProgram(watch(), imported.path, imported.content.indexOf("foo"), "foo".length, Diagnostics.Cannot_find_name_0, "foo");
|
|
|
|
|
|
|
|
|
|
// ensure that imported file was found
|
|
|
|
|
checkOutputContains(host, [f1IsNotModule, cannotFindFoo]);
|
|
|
|
|
host.clearOutput();
|
|
|
|
|
checkOutputErrors(host, [f1IsNotModule, cannotFindFoo], /*isInitial*/ true);
|
|
|
|
|
|
|
|
|
|
const originalFileExists = host.fileExists;
|
|
|
|
|
{
|
|
|
|
|
@@ -1517,8 +1595,11 @@ namespace ts.tscWatch {
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
|
|
|
|
|
// ensure file has correct number of errors after edit
|
|
|
|
|
checkOutputContains(host, [f1IsNotModule, cannotAssignValue]);
|
|
|
|
|
host.clearOutput();
|
|
|
|
|
checkOutputErrors(host, [
|
|
|
|
|
f1IsNotModule,
|
|
|
|
|
getDiagnosticOfFileFromProgram(watch(), root.path, newContent.indexOf("var x") + "var ".length, "x".length, Diagnostics.Type_0_is_not_assignable_to_type_1, 1, "string"),
|
|
|
|
|
cannotFindFoo
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
let fileExistsIsCalled = false;
|
|
|
|
|
@@ -1534,13 +1615,13 @@ namespace ts.tscWatch {
|
|
|
|
|
root.content = `import {x} from "f2"`;
|
|
|
|
|
host.reloadFS(files);
|
|
|
|
|
|
|
|
|
|
// trigger synchronization to make sure that LSHost will try to find 'f2' module on disk
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
// trigger synchronization to make sure that LSHost will try to find 'f2' module on disk
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
|
|
|
|
|
// ensure file has correct number of errors after edit
|
|
|
|
|
const cannotFindModuleF2 = `a/d/f0.ts(1,17): error TS2307: Cannot find module 'f2'.\n`;
|
|
|
|
|
checkOutputContains(host, [cannotFindModuleF2]);
|
|
|
|
|
host.clearOutput();
|
|
|
|
|
// ensure file has correct number of errors after edit
|
|
|
|
|
checkOutputErrors(host, [
|
|
|
|
|
getDiagnosticModuleNotFoundOfFile(watch(), root, "f2")
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
assert.isTrue(fileExistsIsCalled);
|
|
|
|
|
}
|
|
|
|
|
@@ -1561,7 +1642,7 @@ namespace ts.tscWatch {
|
|
|
|
|
host.reloadFS(files);
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
|
|
|
|
|
checkOutputContains(host, [f1IsNotModule, cannotFindFoo]);
|
|
|
|
|
checkOutputErrors(host, [f1IsNotModule, cannotFindFoo]);
|
|
|
|
|
assert.isTrue(fileExistsCalled);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
@@ -1593,12 +1674,12 @@ namespace ts.tscWatch {
|
|
|
|
|
return originalFileExists.call(host, fileName);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
createWatchModeWithoutConfigFile([root.path], host, { module: ModuleKind.AMD });
|
|
|
|
|
const watch = createWatchModeWithoutConfigFile([root.path], host, { module: ModuleKind.AMD });
|
|
|
|
|
|
|
|
|
|
const barNotFound = `a/foo.ts(1,17): error TS2307: Cannot find module 'bar'.\n`;
|
|
|
|
|
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called");
|
|
|
|
|
checkOutputContains(host, [barNotFound]);
|
|
|
|
|
host.clearOutput();
|
|
|
|
|
checkOutputErrors(host, [
|
|
|
|
|
getDiagnosticModuleNotFoundOfFile(watch(), root, "bar")
|
|
|
|
|
], /*isInitial*/ true);
|
|
|
|
|
|
|
|
|
|
fileExistsCalledForBar = false;
|
|
|
|
|
root.content = `import {y} from "bar"`;
|
|
|
|
|
@@ -1606,7 +1687,7 @@ namespace ts.tscWatch {
|
|
|
|
|
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called.");
|
|
|
|
|
checkOutputDoesNotContain(host, [barNotFound]);
|
|
|
|
|
checkOutputErrors(host);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("should compile correctly when resolved module goes missing and then comes back (module is not part of the root)", () => {
|
|
|
|
|
@@ -1617,7 +1698,7 @@ namespace ts.tscWatch {
|
|
|
|
|
|
|
|
|
|
const imported = {
|
|
|
|
|
path: `/a/bar.d.ts`,
|
|
|
|
|
content: `export const y = 1;`
|
|
|
|
|
content: `export const y = 1;export const x = 10;`
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const files = [root, libFile];
|
|
|
|
|
@@ -1635,25 +1716,107 @@ namespace ts.tscWatch {
|
|
|
|
|
return originalFileExists.call(host, fileName);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
createWatchModeWithoutConfigFile([root.path], host, { module: ModuleKind.AMD });
|
|
|
|
|
const watch = createWatchModeWithoutConfigFile([root.path], host, { module: ModuleKind.AMD });
|
|
|
|
|
|
|
|
|
|
const barNotFound = `a/foo.ts(1,17): error TS2307: Cannot find module 'bar'.\n`;
|
|
|
|
|
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called");
|
|
|
|
|
checkOutputDoesNotContain(host, [barNotFound]);
|
|
|
|
|
host.clearOutput();
|
|
|
|
|
checkOutputErrors(host, emptyArray, /*isInitial*/ true);
|
|
|
|
|
|
|
|
|
|
fileExistsCalledForBar = false;
|
|
|
|
|
host.reloadFS(files);
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called.");
|
|
|
|
|
checkOutputContains(host, [barNotFound]);
|
|
|
|
|
host.clearOutput();
|
|
|
|
|
checkOutputErrors(host, [
|
|
|
|
|
getDiagnosticModuleNotFoundOfFile(watch(), root, "bar")
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
fileExistsCalledForBar = false;
|
|
|
|
|
host.reloadFS(filesWithImported);
|
|
|
|
|
host.checkTimeoutQueueLengthAndRun(1);
|
|
|
|
|
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called.");
|
|
|
|
|
checkOutputDoesNotContain(host, [barNotFound]);
|
|
|
|
|
checkOutputErrors(host);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("works when module resolution changes to ambient module", () => {
|
|
|
|
|
const root = {
|
|
|
|
|
path: "/a/b/foo.ts",
|
|
|
|
|
content: `import * as fs from "fs";`
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const packageJson = {
|
|
|
|
|
path: "/a/b/node_modules/@types/node/package.json",
|
|
|
|
|
content: `
|
|
|
|
|
{
|
|
|
|
|
"main": ""
|
|
|
|
|
}
|
|
|
|
|
`
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const nodeType = {
|
|
|
|
|
path: "/a/b/node_modules/@types/node/index.d.ts",
|
|
|
|
|
content: `
|
|
|
|
|
declare module "fs" {
|
|
|
|
|
export interface Stats {
|
|
|
|
|
isFile(): boolean;
|
|
|
|
|
}
|
|
|
|
|
}`
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const files = [root, libFile];
|
|
|
|
|
const filesWithNodeType = files.concat(packageJson, nodeType);
|
|
|
|
|
const host = createWatchedSystem(files, { currentDirectory: "/a/b" });
|
|
|
|
|
|
|
|
|
|
const watch = createWatchModeWithoutConfigFile([root.path], host, { });
|
|
|
|
|
|
|
|
|
|
checkOutputErrors(host, [
|
|
|
|
|
getDiagnosticModuleNotFoundOfFile(watch(), root, "fs")
|
|
|
|
|
], /*isInitial*/ true);
|
|
|
|
|
|
|
|
|
|
host.reloadFS(filesWithNodeType);
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
checkOutputErrors(host);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("works when included file with ambient module changes", () => {
|
|
|
|
|
const root = {
|
|
|
|
|
path: "/a/b/foo.ts",
|
|
|
|
|
content: `
|
|
|
|
|
import * as fs from "fs";
|
|
|
|
|
import * as u from "url";
|
|
|
|
|
`
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const file = {
|
|
|
|
|
path: "/a/b/bar.d.ts",
|
|
|
|
|
content: `
|
|
|
|
|
declare module "url" {
|
|
|
|
|
export interface Url {
|
|
|
|
|
href?: string;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
`
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const fileContentWithFS = `
|
|
|
|
|
declare module "fs" {
|
|
|
|
|
export interface Stats {
|
|
|
|
|
isFile(): boolean;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const files = [root, file, libFile];
|
|
|
|
|
const host = createWatchedSystem(files, { currentDirectory: "/a/b" });
|
|
|
|
|
|
|
|
|
|
const watch = createWatchModeWithoutConfigFile([root.path, file.path], host, {});
|
|
|
|
|
|
|
|
|
|
checkOutputErrors(host, [
|
|
|
|
|
getDiagnosticModuleNotFoundOfFile(watch(), root, "fs")
|
|
|
|
|
], /*isInitial*/ true);
|
|
|
|
|
|
|
|
|
|
file.content += fileContentWithFS;
|
|
|
|
|
host.reloadFS(files);
|
|
|
|
|
host.runQueuedTimeoutCallbacks();
|
|
|
|
|
checkOutputErrors(host);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|