mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-17 11:24:29 -05:00
Add way to exclude files and directories to watch (#39243)
* Parse excludeDirectories and excludeFiles * Use watch factory in typings installer * Some refactoring for watchFactory * Create Noop watcher if file or directory being watched is excluded * Baselines without using exclude watch options * Baselines including exclude option * Handle exclude options in the system watches * Add test without exclude option for recursive directory watching * Test baselines with exclude option * Always set sysLog * Test for exclude option in server * Add exclude options in the config file and fix the test * Fix host configuration for server * Handle host configuration for watch options * Fix sysLog time log so baselines can be clean * Handle reloadProjects to reload the project from scratch * Ensure that file updates are reflected * Feedback * Feedback
This commit is contained in:
@@ -187,6 +187,7 @@
|
||||
"unittests/tsserver/projects.ts",
|
||||
"unittests/tsserver/refactors.ts",
|
||||
"unittests/tsserver/reload.ts",
|
||||
"unittests/tsserver/reloadProjects.ts",
|
||||
"unittests/tsserver/rename.ts",
|
||||
"unittests/tsserver/resolutionCache.ts",
|
||||
"unittests/tsserver/session.ts",
|
||||
|
||||
@@ -663,6 +663,64 @@ namespace ts {
|
||||
watchOptions: { fallbackPolling: undefined }
|
||||
});
|
||||
});
|
||||
|
||||
it("parse --excludeDirectories", () => {
|
||||
assertParseResult(["--excludeDirectories", "**/temp", "0.ts"],
|
||||
{
|
||||
errors: [],
|
||||
fileNames: ["0.ts"],
|
||||
options: {},
|
||||
watchOptions: { excludeDirectories: ["**/temp"] }
|
||||
});
|
||||
});
|
||||
|
||||
it("errors on invalid excludeDirectories", () => {
|
||||
assertParseResult(["--excludeDirectories", "**/../*", "0.ts"],
|
||||
{
|
||||
errors: [
|
||||
{
|
||||
messageText: `File specification cannot contain a parent directory ('..') that appears after a recursive directory wildcard ('**'): '**/../*'.`,
|
||||
category: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.category,
|
||||
code: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.code,
|
||||
file: undefined,
|
||||
start: undefined,
|
||||
length: undefined
|
||||
}
|
||||
],
|
||||
fileNames: ["0.ts"],
|
||||
options: {},
|
||||
watchOptions: { excludeDirectories: [] }
|
||||
});
|
||||
});
|
||||
|
||||
it("parse --excludeFiles", () => {
|
||||
assertParseResult(["--excludeFiles", "**/temp/*.ts", "0.ts"],
|
||||
{
|
||||
errors: [],
|
||||
fileNames: ["0.ts"],
|
||||
options: {},
|
||||
watchOptions: { excludeFiles: ["**/temp/*.ts"] }
|
||||
});
|
||||
});
|
||||
|
||||
it("errors on invalid excludeFiles", () => {
|
||||
assertParseResult(["--excludeFiles", "**/../*", "0.ts"],
|
||||
{
|
||||
errors: [
|
||||
{
|
||||
messageText: `File specification cannot contain a parent directory ('..') that appears after a recursive directory wildcard ('**'): '**/../*'.`,
|
||||
category: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.category,
|
||||
code: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.code,
|
||||
file: undefined,
|
||||
start: undefined,
|
||||
length: undefined
|
||||
}
|
||||
],
|
||||
fileNames: ["0.ts"],
|
||||
options: {},
|
||||
watchOptions: { excludeFiles: [] }
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -912,6 +970,54 @@ namespace ts {
|
||||
watchOptions: { fallbackPolling: undefined }
|
||||
});
|
||||
});
|
||||
|
||||
it("errors on invalid excludeDirectories", () => {
|
||||
assertParseResult(["--excludeDirectories", "**/../*"],
|
||||
{
|
||||
errors: [
|
||||
{
|
||||
messageText: `File specification cannot contain a parent directory ('..') that appears after a recursive directory wildcard ('**'): '**/../*'.`,
|
||||
category: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.category,
|
||||
code: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.code,
|
||||
file: undefined,
|
||||
start: undefined,
|
||||
length: undefined
|
||||
}
|
||||
],
|
||||
projects: ["."],
|
||||
buildOptions: {},
|
||||
watchOptions: { excludeDirectories: [] }
|
||||
});
|
||||
});
|
||||
|
||||
it("parse --excludeFiles", () => {
|
||||
assertParseResult(["--excludeFiles", "**/temp/*.ts"],
|
||||
{
|
||||
errors: [],
|
||||
projects: ["."],
|
||||
buildOptions: {},
|
||||
watchOptions: { excludeFiles: ["**/temp/*.ts"] }
|
||||
});
|
||||
});
|
||||
|
||||
it("errors on invalid excludeFiles", () => {
|
||||
assertParseResult(["--excludeFiles", "**/../*"],
|
||||
{
|
||||
errors: [
|
||||
{
|
||||
messageText: `File specification cannot contain a parent directory ('..') that appears after a recursive directory wildcard ('**'): '**/../*'.`,
|
||||
category: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.category,
|
||||
code: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.code,
|
||||
file: undefined,
|
||||
start: undefined,
|
||||
length: undefined
|
||||
}
|
||||
],
|
||||
projects: ["."],
|
||||
buildOptions: {},
|
||||
watchOptions: { excludeFiles: [] }
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -45,20 +45,33 @@ namespace ts {
|
||||
expectedOptions: WatchOptions | undefined;
|
||||
additionalFiles?: vfs.FileSet;
|
||||
existingWatchOptions?: WatchOptions | undefined;
|
||||
expectedErrors?: (sourceFile?: SourceFile) => Diagnostic[];
|
||||
}
|
||||
|
||||
function verifyWatchOptions(scenario: () => VerifyWatchOptions[]) {
|
||||
it("with json api", () => {
|
||||
for (const { json, expectedOptions, additionalFiles, existingWatchOptions } of scenario()) {
|
||||
for (const { json, expectedOptions, additionalFiles, existingWatchOptions, expectedErrors } of scenario()) {
|
||||
const parsed = getParsedCommandJson(json, additionalFiles, existingWatchOptions);
|
||||
assert.deepEqual(parsed.watchOptions, expectedOptions);
|
||||
assert.deepEqual(parsed.watchOptions, expectedOptions, `With ${JSON.stringify(json)}`);
|
||||
if (length(parsed.errors)) {
|
||||
assert.deepEqual(parsed.errors, expectedErrors?.());
|
||||
}
|
||||
else {
|
||||
assert.equal(0, length(expectedErrors?.()), `Expected no errors`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("with json source file api", () => {
|
||||
for (const { json, expectedOptions, additionalFiles, existingWatchOptions } of scenario()) {
|
||||
for (const { json, expectedOptions, additionalFiles, existingWatchOptions, expectedErrors } of scenario()) {
|
||||
const parsed = getParsedCommandJsonNode(json, additionalFiles, existingWatchOptions);
|
||||
assert.deepEqual(parsed.watchOptions, expectedOptions);
|
||||
if (length(parsed.errors)) {
|
||||
assert.deepEqual(parsed.errors, expectedErrors?.(parsed.options.configFile));
|
||||
}
|
||||
else {
|
||||
assert.equal(0, length(expectedErrors?.(parsed.options.configFile)), `Expected no errors`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -156,7 +169,47 @@ namespace ts {
|
||||
{
|
||||
json: { watchOptions: { synchronousWatchDirectory: true } },
|
||||
expectedOptions: { synchronousWatchDirectory: true }
|
||||
}
|
||||
},
|
||||
{
|
||||
json: { watchOptions: { excludeDirectories: ["**/temp"] } },
|
||||
expectedOptions: { excludeDirectories: ["/**/temp"] }
|
||||
},
|
||||
{
|
||||
json: { watchOptions: { excludeFiles: ["**/temp/*.ts"] } },
|
||||
expectedOptions: { excludeFiles: ["/**/temp/*.ts"] }
|
||||
},
|
||||
{
|
||||
json: { watchOptions: { excludeDirectories: ["**/../*"] } },
|
||||
expectedOptions: { excludeDirectories: [] },
|
||||
expectedErrors: sourceFile => [
|
||||
{
|
||||
messageText: `File specification cannot contain a parent directory ('..') that appears after a recursive directory wildcard ('**'): '**/../*'.`,
|
||||
category: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.category,
|
||||
code: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.code,
|
||||
file: sourceFile,
|
||||
start: sourceFile && sourceFile.text.indexOf(`"**/../*"`),
|
||||
length: sourceFile && `"**/../*"`.length,
|
||||
reportsDeprecated: undefined,
|
||||
reportsUnnecessary: undefined
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
json: { watchOptions: { excludeFiles: ["**/../*"] } },
|
||||
expectedOptions: { excludeFiles: [] },
|
||||
expectedErrors: sourceFile => [
|
||||
{
|
||||
messageText: `File specification cannot contain a parent directory ('..') that appears after a recursive directory wildcard ('**'): '**/../*'.`,
|
||||
category: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.category,
|
||||
code: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.code,
|
||||
file: sourceFile,
|
||||
start: sourceFile && sourceFile.text.indexOf(`"**/../*"`),
|
||||
length: sourceFile && `"**/../*"`.length,
|
||||
reportsDeprecated: undefined,
|
||||
reportsUnnecessary: undefined
|
||||
}
|
||||
]
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
@@ -411,6 +411,91 @@ namespace ts.tscWatch {
|
||||
},
|
||||
changes: emptyArray
|
||||
});
|
||||
|
||||
describe("exclude options", () => {
|
||||
function sys(watchOptions: WatchOptions, runWithoutRecursiveWatches?: boolean): WatchedSystem {
|
||||
const configFile: File = {
|
||||
path: `${projectRoot}/tsconfig.json`,
|
||||
content: JSON.stringify({ exclude: ["node_modules"], watchOptions })
|
||||
};
|
||||
const main: File = {
|
||||
path: `${projectRoot}/src/main.ts`,
|
||||
content: `import { foo } from "bar"; foo();`
|
||||
};
|
||||
const bar: File = {
|
||||
path: `${projectRoot}/node_modules/bar/index.d.ts`,
|
||||
content: `export { foo } from "./foo";`
|
||||
};
|
||||
const foo: File = {
|
||||
path: `${projectRoot}/node_modules/bar/foo.d.ts`,
|
||||
content: `export function foo(): string;`
|
||||
};
|
||||
const fooBar: File = {
|
||||
path: `${projectRoot}/node_modules/bar/fooBar.d.ts`,
|
||||
content: `export function fooBar(): string;`
|
||||
};
|
||||
const temp: File = {
|
||||
path: `${projectRoot}/node_modules/bar/temp/index.d.ts`,
|
||||
content: "export function temp(): string;"
|
||||
};
|
||||
const files = [libFile, main, bar, foo, fooBar, temp, configFile];
|
||||
return createWatchedSystem(files, { currentDirectory: projectRoot, runWithoutRecursiveWatches });
|
||||
}
|
||||
|
||||
function verifyWorker(...additionalFlags: string[]) {
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `watchOptions/with excludeFiles option${additionalFlags.join("")}`,
|
||||
commandLineArgs: ["-w", ...additionalFlags],
|
||||
sys: () => sys({ excludeFiles: ["node_modules/*"] }),
|
||||
changes: [
|
||||
{
|
||||
caption: "Change foo",
|
||||
change: sys => replaceFileText(sys, `${projectRoot}/node_modules/bar/foo.d.ts`, "foo", "fooBar"),
|
||||
timeouts: sys => sys.checkTimeoutQueueLength(0),
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `watchOptions/with excludeDirectories option${additionalFlags.join("")}`,
|
||||
commandLineArgs: ["-w", ...additionalFlags],
|
||||
sys: () => sys({ excludeDirectories: ["node_modules"] }),
|
||||
changes: [
|
||||
{
|
||||
caption: "delete fooBar",
|
||||
change: sys => sys.deleteFile(`${projectRoot}/node_modules/bar/fooBar.d.ts`),
|
||||
timeouts: sys => sys.checkTimeoutQueueLength(0), }
|
||||
]
|
||||
});
|
||||
|
||||
verifyTscWatch({
|
||||
scenario,
|
||||
subScenario: `watchOptions/with excludeDirectories option with recursive directory watching${additionalFlags.join("")}`,
|
||||
commandLineArgs: ["-w", ...additionalFlags],
|
||||
sys: () => sys({ excludeDirectories: ["**/temp"] }, /*runWithoutRecursiveWatches*/ true),
|
||||
changes: [
|
||||
{
|
||||
caption: "Directory watch updates because of main.js creation",
|
||||
change: noop,
|
||||
timeouts: sys => {
|
||||
sys.checkTimeoutQueueLengthAndRun(1); // To update directory callbacks for main.js output
|
||||
sys.checkTimeoutQueueLength(0);
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "add new folder to temp",
|
||||
change: sys => sys.ensureFileOrFolder({ path: `${projectRoot}/node_modules/bar/temp/fooBar/index.d.ts`, content: "export function temp(): string;" }),
|
||||
timeouts: sys => sys.checkTimeoutQueueLength(0),
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
verifyWorker();
|
||||
verifyWorker("-extendedDiagnostics");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
139
src/testRunner/unittests/tsserver/reloadProjects.ts
Normal file
139
src/testRunner/unittests/tsserver/reloadProjects.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
namespace ts.projectSystem {
|
||||
describe("unittests:: tsserver:: reloadProjects", () => {
|
||||
const configFile: File = {
|
||||
path: `${tscWatch.projectRoot}/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
watchOptions: { excludeDirectories: ["node_modules"] }
|
||||
})
|
||||
};
|
||||
const file1: File = {
|
||||
path: `${tscWatch.projectRoot}/file1.ts`,
|
||||
content: `import { foo } from "module1";
|
||||
foo();
|
||||
import { bar } from "./file2";
|
||||
bar();`
|
||||
};
|
||||
const file2: File = {
|
||||
path: `${tscWatch.projectRoot}/file2.ts`,
|
||||
content: `export function bar(){}`
|
||||
};
|
||||
const moduleFile: File = {
|
||||
path: `${tscWatch.projectRoot}/node_modules/module1/index.d.ts`,
|
||||
content: `export function foo(): string;`
|
||||
};
|
||||
|
||||
function verifyFileUpdates(host: TestServerHost, service: TestProjectService, project: server.Project) {
|
||||
// update file
|
||||
const updatedText = `${file2.content}
|
||||
bar();`;
|
||||
host.writeFile(file2.path, updatedText);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
service.reloadProjects();
|
||||
assert.equal(project.getCurrentProgram()?.getSourceFile(file2.path)?.text, updatedText);
|
||||
|
||||
// delete file
|
||||
host.deleteFile(file2.path);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
service.reloadProjects();
|
||||
assert.isUndefined(project.getCurrentProgram()?.getSourceFile(file2.path)?.text);
|
||||
assert.isUndefined(service.getScriptInfo(file2.path));
|
||||
}
|
||||
|
||||
it("configured project", () => {
|
||||
const host = createServerHost([configFile, libFile, file1, file2]);
|
||||
const service = createProjectService(host);
|
||||
service.setHostConfiguration({ watchOptions: { excludeFiles: [file2.path] } });
|
||||
service.openClientFile(file1.path);
|
||||
checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
const project = service.configuredProjects.get(configFile.path)!;
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, configFile.path]);
|
||||
|
||||
// Install module1
|
||||
host.ensureFileOrFolder(moduleFile);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
|
||||
service.reloadProjects();
|
||||
checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
assert.strictEqual(service.configuredProjects.get(configFile.path), project);
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, configFile.path, moduleFile.path]);
|
||||
|
||||
verifyFileUpdates(host, service, project);
|
||||
});
|
||||
|
||||
it("inferred project", () => {
|
||||
const host = createServerHost([libFile, file1, file2]);
|
||||
const service = createProjectService(host, /*parameters*/ undefined, { useInferredProjectPerProjectRoot: true, });
|
||||
service.setHostConfiguration({ watchOptions: { excludeFiles: [file2.path] } });
|
||||
const timeoutId = host.getNextTimeoutId();
|
||||
service.setCompilerOptionsForInferredProjects({ excludeDirectories: ["node_modules"] }, tscWatch.projectRoot);
|
||||
host.clearTimeout(timeoutId);
|
||||
service.openClientFile(file1.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, tscWatch.projectRoot);
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
const project = service.inferredProjects[0];
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path]);
|
||||
|
||||
// Install module1
|
||||
host.ensureFileOrFolder(moduleFile);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
|
||||
service.reloadProjects();
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
assert.strictEqual(service.inferredProjects[0], project);
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, moduleFile.path]);
|
||||
|
||||
verifyFileUpdates(host, service, project);
|
||||
});
|
||||
|
||||
it("external project", () => {
|
||||
const host = createServerHost([libFile, file1, file2]);
|
||||
const service = createProjectService(host);
|
||||
service.setHostConfiguration({ watchOptions: { excludeFiles: [file2.path] } });
|
||||
service.openExternalProject({
|
||||
projectFileName: `${tscWatch.projectRoot}/project.sln`,
|
||||
options: { excludeDirectories: ["node_modules"] },
|
||||
rootFiles: [{ fileName: file1.path }, { fileName: file2.path }]
|
||||
});
|
||||
service.openClientFile(file1.path);
|
||||
checkNumberOfProjects(service, { externalProjects: 1 });
|
||||
const project = service.externalProjects[0];
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path]);
|
||||
|
||||
// Install module1
|
||||
host.ensureFileOrFolder(moduleFile);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
|
||||
service.reloadProjects();
|
||||
checkNumberOfProjects(service, { externalProjects: 1 });
|
||||
assert.strictEqual(service.externalProjects[0], project);
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, moduleFile.path]);
|
||||
|
||||
verifyFileUpdates(host, service, project);
|
||||
});
|
||||
|
||||
it("external project with config file", () => {
|
||||
const host = createServerHost([libFile, file1, file2, configFile]);
|
||||
const service = createProjectService(host);
|
||||
service.setHostConfiguration({ watchOptions: { excludeFiles: [file2.path] } });
|
||||
service.openExternalProject({
|
||||
projectFileName: `${tscWatch.projectRoot}/project.sln`,
|
||||
options: { excludeDirectories: ["node_modules"] },
|
||||
rootFiles: [{ fileName: file1.path }, { fileName: file2.path }, { fileName: configFile.path }]
|
||||
});
|
||||
service.openClientFile(file1.path);
|
||||
checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
const project = service.configuredProjects.get(configFile.path)!;
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, configFile.path]);
|
||||
|
||||
// Install module1
|
||||
host.ensureFileOrFolder(moduleFile);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
|
||||
service.reloadProjects();
|
||||
checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
assert.strictEqual(service.configuredProjects.get(configFile.path), project);
|
||||
checkProjectActualFiles(project, [libFile.path, file1.path, file2.path, configFile.path, moduleFile.path]);
|
||||
|
||||
verifyFileUpdates(host, service, project);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -565,6 +565,202 @@ namespace ts.projectSystem {
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ true);
|
||||
});
|
||||
|
||||
describe("excludeDirectories", () => {
|
||||
function setupFiles() {
|
||||
const main: File = {
|
||||
path: `${tscWatch.projectRoot}/src/main.ts`,
|
||||
content: `import { foo } from "bar"; foo();`
|
||||
};
|
||||
const bar: File = {
|
||||
path: `${tscWatch.projectRoot}/node_modules/bar/index.d.ts`,
|
||||
content: `export { foo } from "./foo";`
|
||||
};
|
||||
const foo: File = {
|
||||
path: `${tscWatch.projectRoot}/node_modules/bar/foo.d.ts`,
|
||||
content: `export function foo(): string;`
|
||||
};
|
||||
return { main, bar, foo };
|
||||
}
|
||||
|
||||
function setupConfigureHost(service: TestProjectService, configureHost: boolean | undefined) {
|
||||
if (configureHost) {
|
||||
service.setHostConfiguration({
|
||||
watchOptions: { excludeDirectories: ["node_modules"] }
|
||||
});
|
||||
}
|
||||
}
|
||||
function setup(configureHost?: boolean) {
|
||||
const configFile: File = {
|
||||
path: `${tscWatch.projectRoot}/tsconfig.json`,
|
||||
content: JSON.stringify({ include: ["src"], watchOptions: { excludeDirectories: ["node_modules"] } })
|
||||
};
|
||||
const { main, bar, foo } = setupFiles();
|
||||
const files = [libFile, main, bar, foo, configFile];
|
||||
const host = createServerHost(files, { currentDirectory: tscWatch.projectRoot });
|
||||
const service = createProjectService(host);
|
||||
setupConfigureHost(service, configureHost);
|
||||
service.openClientFile(main.path);
|
||||
return { host, configFile };
|
||||
}
|
||||
|
||||
it("with excludeDirectories option in configFile", () => {
|
||||
const { host, configFile } = setup();
|
||||
checkWatchedFilesDetailed(host, [configFile.path, libFile.path], 1);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectoriesDetailed(
|
||||
host,
|
||||
arrayToMap(
|
||||
[`${tscWatch.projectRoot}/src`, `${tscWatch.projectRoot}/node_modules`],
|
||||
identity,
|
||||
f => f === `${tscWatch.projectRoot}/node_modules` ? 1 : 2,
|
||||
),
|
||||
/*recursive*/ true,
|
||||
);
|
||||
});
|
||||
|
||||
it("with excludeDirectories option in configuration", () => {
|
||||
const { host, configFile } = setup(/*configureHost*/ true);
|
||||
checkWatchedFilesDetailed(host, [configFile.path, libFile.path], 1);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectoriesDetailed(
|
||||
host,
|
||||
[`${tscWatch.projectRoot}/src`],
|
||||
2,
|
||||
/*recursive*/ true,
|
||||
);
|
||||
});
|
||||
|
||||
function setupExternalProject(configureHost?: boolean) {
|
||||
const { main, bar, foo } = setupFiles();
|
||||
const files = [libFile, main, bar, foo];
|
||||
const host = createServerHost(files, { currentDirectory: tscWatch.projectRoot });
|
||||
const service = createProjectService(host);
|
||||
setupConfigureHost(service, configureHost);
|
||||
service.openExternalProject(<protocol.ExternalProject>{
|
||||
projectFileName: `${tscWatch.projectRoot}/project.csproj`,
|
||||
rootFiles: toExternalFiles([main.path, bar.path, foo.path]),
|
||||
options: { excludeDirectories: ["node_modules"] }
|
||||
});
|
||||
service.openClientFile(main.path);
|
||||
return host;
|
||||
}
|
||||
|
||||
it("external project watch options", () => {
|
||||
const host = setupExternalProject();
|
||||
checkWatchedFilesDetailed(host, [libFile.path], 1);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectoriesDetailed(
|
||||
host,
|
||||
[`${tscWatch.projectRoot}/src`, `${tscWatch.projectRoot}/node_modules`],
|
||||
1,
|
||||
/*recursive*/ true,
|
||||
);
|
||||
});
|
||||
|
||||
it("external project watch options in host configuration", () => {
|
||||
const host = setupExternalProject(/*configureHost*/ true);
|
||||
checkWatchedFilesDetailed(host, [libFile.path], 1);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectoriesDetailed(
|
||||
host,
|
||||
[`${tscWatch.projectRoot}/src`],
|
||||
1,
|
||||
/*recursive*/ true,
|
||||
);
|
||||
});
|
||||
|
||||
it("external project watch options errors", () => {
|
||||
const { main, bar, foo } = setupFiles();
|
||||
const files = [libFile, main, bar, foo];
|
||||
const host = createServerHost(files, { currentDirectory: tscWatch.projectRoot });
|
||||
const service = createProjectService(host);
|
||||
service.openExternalProject(<protocol.ExternalProject>{
|
||||
projectFileName: `${tscWatch.projectRoot}/project.csproj`,
|
||||
rootFiles: toExternalFiles([main.path, bar.path, foo.path]),
|
||||
options: { excludeDirectories: ["**/../*"] }
|
||||
});
|
||||
service.openClientFile(main.path);
|
||||
const project = service.externalProjects[0];
|
||||
assert.deepEqual(project.getAllProjectErrors(), [
|
||||
{
|
||||
messageText: `File specification cannot contain a parent directory ('..') that appears after a recursive directory wildcard ('**'): '**/../*'.`,
|
||||
category: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.category,
|
||||
code: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.code,
|
||||
file: undefined,
|
||||
start: undefined,
|
||||
length: undefined,
|
||||
reportsDeprecated: undefined,
|
||||
reportsUnnecessary: undefined,
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
function setupInferredProject(configureHost?: boolean) {
|
||||
const { main, bar, foo } = setupFiles();
|
||||
const files = [libFile, main, bar, foo];
|
||||
const host = createServerHost(files, { currentDirectory: tscWatch.projectRoot });
|
||||
const service = createProjectService(host, {}, { useInferredProjectPerProjectRoot: true });
|
||||
setupConfigureHost(service, configureHost);
|
||||
service.setCompilerOptionsForInferredProjects({ excludeDirectories: ["node_modules"] }, tscWatch.projectRoot);
|
||||
service.openClientFile(main.path, main.content, ScriptKind.TS, tscWatch.projectRoot);
|
||||
return host;
|
||||
}
|
||||
|
||||
it("inferred project watch options", () => {
|
||||
const host = setupInferredProject();
|
||||
checkWatchedFilesDetailed(
|
||||
host,
|
||||
[libFile.path, `${tscWatch.projectRoot}/tsconfig.json`, `${tscWatch.projectRoot}/jsconfig.json`, `${tscWatch.projectRoot}/src/tsconfig.json`, `${tscWatch.projectRoot}/src/jsconfig.json`],
|
||||
1
|
||||
);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectoriesDetailed(
|
||||
host,
|
||||
[`${tscWatch.projectRoot}/src`, `${tscWatch.projectRoot}/node_modules`],
|
||||
1,
|
||||
/*recursive*/ true,
|
||||
);
|
||||
});
|
||||
|
||||
it("inferred project watch options in host configuration", () => {
|
||||
const host = setupInferredProject(/*configureHost*/ true);
|
||||
checkWatchedFilesDetailed(
|
||||
host,
|
||||
[libFile.path, `${tscWatch.projectRoot}/tsconfig.json`, `${tscWatch.projectRoot}/jsconfig.json`, `${tscWatch.projectRoot}/src/tsconfig.json`, `${tscWatch.projectRoot}/src/jsconfig.json`],
|
||||
1
|
||||
);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectoriesDetailed(
|
||||
host,
|
||||
[`${tscWatch.projectRoot}/src`],
|
||||
1,
|
||||
/*recursive*/ true,
|
||||
);
|
||||
});
|
||||
|
||||
it("inferred project watch options errors", () => {
|
||||
const { main, bar, foo } = setupFiles();
|
||||
const files = [libFile, main, bar, foo];
|
||||
const host = createServerHost(files, { currentDirectory: tscWatch.projectRoot });
|
||||
const service = createProjectService(host, {}, { useInferredProjectPerProjectRoot: true });
|
||||
service.setCompilerOptionsForInferredProjects({ excludeDirectories: ["**/../*"] }, tscWatch.projectRoot);
|
||||
service.openClientFile(main.path, main.content, ScriptKind.TS, tscWatch.projectRoot);
|
||||
const project = service.inferredProjects[0];
|
||||
assert.deepEqual(project.getAllProjectErrors(), [
|
||||
{
|
||||
messageText: `File specification cannot contain a parent directory ('..') that appears after a recursive directory wildcard ('**'): '**/../*'.`,
|
||||
category: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.category,
|
||||
code: Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0.code,
|
||||
file: undefined,
|
||||
start: undefined,
|
||||
length: undefined,
|
||||
reportsDeprecated: undefined,
|
||||
reportsUnnecessary: undefined,
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("unittests:: tsserver:: watchEnvironment:: file names on case insensitive file system", () => {
|
||||
|
||||
Reference in New Issue
Block a user