570 lines
No EOL
24 KiB
TypeScript
570 lines
No EOL
24 KiB
TypeScript
/// <reference path="..\..\..\src\harness\harness.ts" />
|
|
|
|
namespace ts {
|
|
function notImplemented(): any {
|
|
throw new Error("Not yet implemented");
|
|
}
|
|
|
|
const nullLogger: server.Logger = {
|
|
close: () => void 0,
|
|
isVerbose: () => void 0,
|
|
loggingEnabled: () => false,
|
|
perftrc: () => void 0,
|
|
info: () => void 0,
|
|
startGroup: () => void 0,
|
|
endGroup: () => void 0,
|
|
msg: () => void 0
|
|
};
|
|
|
|
const { content: libFileContent } = Harness.getDefaultLibraryFile(Harness.IO);
|
|
|
|
function getExecutingFilePathFromLibFile(libFile: FileOrFolder): string {
|
|
return combinePaths(getDirectoryPath(libFile.path), "tsc.js");
|
|
}
|
|
|
|
interface FileOrFolder {
|
|
path: string;
|
|
content?: string;
|
|
}
|
|
|
|
interface FSEntry {
|
|
path: Path;
|
|
fullPath: string;
|
|
}
|
|
|
|
interface File extends FSEntry {
|
|
content: string;
|
|
}
|
|
|
|
interface Folder extends FSEntry {
|
|
entries: FSEntry[];
|
|
}
|
|
|
|
function isFolder(s: FSEntry): s is Folder {
|
|
return isArray((<Folder>s).entries);
|
|
}
|
|
|
|
function isFile(s: FSEntry): s is File {
|
|
return typeof (<File>s).content === "string";
|
|
}
|
|
|
|
function addFolder(fullPath: string, toPath: (s: string) => Path, fs: FileMap<FSEntry>): Folder {
|
|
const path = toPath(fullPath);
|
|
if (fs.contains(path)) {
|
|
Debug.assert(isFolder(fs.get(path)));
|
|
return (<Folder>fs.get(path));
|
|
}
|
|
|
|
const entry: Folder = { path, entries: [], fullPath };
|
|
fs.set(path, entry);
|
|
|
|
const baseFullPath = getDirectoryPath(fullPath);
|
|
if (fullPath !== baseFullPath) {
|
|
addFolder(baseFullPath, toPath, fs).entries.push(entry);
|
|
}
|
|
|
|
return entry;
|
|
}
|
|
|
|
function sizeOfMap(map: Map<any>): number {
|
|
let n = 0;
|
|
for (const name in map) {
|
|
if (hasProperty(map, name)) {
|
|
n++;
|
|
}
|
|
}
|
|
return n;
|
|
}
|
|
|
|
function checkMapKeys(caption: string, map: Map<any>, expectedKeys: string[]) {
|
|
assert.equal(sizeOfMap(map), expectedKeys.length, `${caption}: incorrect size of map`);
|
|
for (const name of expectedKeys) {
|
|
assert.isTrue(hasProperty(map, name), `${caption} is expected to contain ${name}, actual keys: ${getKeys(map)}`);
|
|
}
|
|
}
|
|
|
|
function checkFileNames(caption: string, actualFileNames: string[], expectedFileNames: string[]) {
|
|
assert.equal(actualFileNames.length, expectedFileNames.length, `${caption}: incorrect actual number of files, expected ${JSON.stringify(expectedFileNames)}, got ${actualFileNames}`);
|
|
for (const f of expectedFileNames) {
|
|
assert.isTrue(contains(actualFileNames, f), `${caption}: expected to find ${f} in ${JSON.stringify(actualFileNames)}`);
|
|
}
|
|
}
|
|
|
|
function checkNumberOfConfiguredProjects(projectService: server.ProjectService, expected: number) {
|
|
assert.equal(projectService.configuredProjects.length, expected, `expected ${expected} configured project(s)`);
|
|
}
|
|
|
|
function checkNumberOfInferredProjects(projectService: server.ProjectService, expected: number) {
|
|
assert.equal(projectService.inferredProjects.length, expected, `expected ${expected} inferred project(s)`);
|
|
}
|
|
|
|
function checkWatchedFiles(host: TestServerHost, expectedFiles: string[]) {
|
|
checkMapKeys("watchedFiles", host.watchedFiles, expectedFiles);
|
|
}
|
|
|
|
function checkWatchedDirectories(host: TestServerHost, expectedDirectories: string[]) {
|
|
checkMapKeys("watchedDirectories", host.watchedDirectories, expectedDirectories);
|
|
}
|
|
|
|
function checkConfiguredProjectActualFiles(project: server.Project, expectedFiles: string[]) {
|
|
checkFileNames("configuredProjects project, actualFileNames", project.getFileNames(), expectedFiles);
|
|
}
|
|
|
|
function checkConfiguredProjectRootFiles(project: server.Project, expectedFiles: string[]) {
|
|
checkFileNames("configuredProjects project, rootFileNames", project.getRootFiles(), expectedFiles);
|
|
}
|
|
|
|
type TimeOutCallback = () => any;
|
|
|
|
class TestServerHost implements server.ServerHost {
|
|
args: string[] = [];
|
|
newLine: "\n";
|
|
|
|
private fs: ts.FileMap<FSEntry>;
|
|
private getCanonicalFileName: (s: string) => string;
|
|
private toPath: (f: string) => Path;
|
|
private callbackQueue: TimeOutCallback[] = [];
|
|
readonly watchedDirectories: Map<{ cb: DirectoryWatcherCallback, recursive: boolean }[]> = {};
|
|
readonly watchedFiles: Map<FileWatcherCallback[]> = {};
|
|
|
|
constructor(public useCaseSensitiveFileNames: boolean, private executingFilePath: string, private currentDirectory: string, fileOrFolderList: FileOrFolder[]) {
|
|
this.getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
|
this.toPath = s => toPath(s, currentDirectory, this.getCanonicalFileName);
|
|
|
|
this.reloadFS(fileOrFolderList);
|
|
}
|
|
|
|
reloadFS(filesOrFolders: FileOrFolder[]) {
|
|
this.fs = createFileMap<FSEntry>();
|
|
for (const fileOrFolder of filesOrFolders) {
|
|
const path = this.toPath(fileOrFolder.path);
|
|
const fullPath = getNormalizedAbsolutePath(fileOrFolder.path, this.currentDirectory);
|
|
if (typeof fileOrFolder.content === "string") {
|
|
const entry = { path, content: fileOrFolder.content, fullPath };
|
|
this.fs.set(path, entry);
|
|
addFolder(getDirectoryPath(fullPath), this.toPath, this.fs).entries.push(entry);
|
|
}
|
|
else {
|
|
addFolder(fullPath, this.toPath, this.fs);
|
|
}
|
|
}
|
|
}
|
|
|
|
fileExists(s: string) {
|
|
const path = this.toPath(s);
|
|
return this.fs.contains(path) && isFile(this.fs.get(path));
|
|
};
|
|
|
|
directoryExists(s: string) {
|
|
const path = this.toPath(s);
|
|
return this.fs.contains(path) && isFolder(this.fs.get(path));
|
|
}
|
|
|
|
getDirectories(s: string) {
|
|
const path = this.toPath(s);
|
|
if (!this.fs.contains(path)) {
|
|
return [];
|
|
}
|
|
else {
|
|
const entry = this.fs.get(path);
|
|
return isFolder(entry) ? map(entry.entries, x => getBaseFileName(x.fullPath)) : [];
|
|
}
|
|
}
|
|
|
|
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[] {
|
|
const that = this;
|
|
return ts.matchFiles(path, extensions, exclude, include, this.useCaseSensitiveFileNames, this.getCurrentDirectory(), (dir) => {
|
|
const result: FileSystemEntries = {
|
|
directories: [],
|
|
files : []
|
|
};
|
|
const dirEntry = that.fs.get(that.toPath(dir));
|
|
if (isFolder(dirEntry)) {
|
|
dirEntry.entries.forEach((entry) => {
|
|
if (isFolder(entry)) {
|
|
result.directories.push(entry.fullPath);
|
|
}
|
|
else if (isFile(entry)) {
|
|
result.files.push(entry.fullPath);
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
});
|
|
}
|
|
|
|
watchDirectory(directoryName: string, callback: DirectoryWatcherCallback, recursive: boolean): DirectoryWatcher {
|
|
const path = this.toPath(directoryName);
|
|
const callbacks = lookUp(this.watchedDirectories, path) || (this.watchedDirectories[path] = []);
|
|
callbacks.push({ cb: callback, recursive });
|
|
return {
|
|
referenceCount: 0,
|
|
directoryName,
|
|
close: () => {
|
|
for (let i = 0; i < callbacks.length; i++) {
|
|
if (callbacks[i].cb === callback) {
|
|
callbacks.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
if (!callbacks.length) {
|
|
delete this.watchedDirectories[path];
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
triggerDirectoryWatcherCallback(directoryName: string, fileName: string): void {
|
|
const path = this.toPath(directoryName);
|
|
const callbacks = lookUp(this.watchedDirectories, path);
|
|
if (callbacks) {
|
|
for (const callback of callbacks) {
|
|
callback.cb(fileName);
|
|
}
|
|
}
|
|
}
|
|
|
|
triggerFileWatcherCallback(fileName: string, removed?: boolean): void {
|
|
const path = this.toPath(fileName);
|
|
const callbacks = lookUp(this.watchedFiles, path);
|
|
if (callbacks) {
|
|
for (const callback of callbacks) {
|
|
callback(path, removed);
|
|
}
|
|
}
|
|
}
|
|
|
|
watchFile(fileName: string, callback: FileWatcherCallback) {
|
|
const path = this.toPath(fileName);
|
|
const callbacks = lookUp(this.watchedFiles, path) || (this.watchedFiles[path] = []);
|
|
callbacks.push(callback);
|
|
return {
|
|
close: () => {
|
|
const i = callbacks.indexOf(callback);
|
|
callbacks.splice(i, 1);
|
|
if (!callbacks.length) {
|
|
delete this.watchedFiles[path];
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
// TOOD: record and invoke callbacks to simulate timer events
|
|
readonly setTimeout = (callback: TimeOutCallback, time: number) => {
|
|
this.callbackQueue.push(callback);
|
|
return this.callbackQueue.length - 1;
|
|
};
|
|
readonly clearTimeout = (timeoutId: any): void => {
|
|
if (typeof timeoutId === "number") {
|
|
this.callbackQueue.splice(timeoutId, 1);
|
|
}
|
|
};
|
|
|
|
checkTimeoutQueueLength(expected: number) {
|
|
assert.equal(this.callbackQueue.length, expected, `expected ${expected} timeout callbacks queued but found ${this.callbackQueue.length}.`);
|
|
}
|
|
|
|
runQueuedTimeoutCallbacks() {
|
|
for (const callback of this.callbackQueue) {
|
|
callback();
|
|
}
|
|
this.callbackQueue = [];
|
|
}
|
|
|
|
readonly readFile = (s: string) => (<File>this.fs.get(this.toPath(s))).content;
|
|
readonly resolvePath = (s: string) => s;
|
|
readonly getExecutingFilePath = () => this.executingFilePath;
|
|
readonly getCurrentDirectory = () => this.currentDirectory;
|
|
readonly writeFile = (path: string, content: string) => notImplemented();
|
|
readonly write = (s: string) => notImplemented();
|
|
readonly createDirectory = (s: string) => notImplemented();
|
|
readonly exit = () => notImplemented();
|
|
}
|
|
|
|
describe("tsserver-project-system", () => {
|
|
const commonFile1: FileOrFolder = {
|
|
path: "/a/b/commonFile1.ts",
|
|
content: "let x = 1"
|
|
};
|
|
const commonFile2: FileOrFolder = {
|
|
path: "/a/b/commonFile2.ts",
|
|
content: "let y = 1"
|
|
};
|
|
const libFile: FileOrFolder = {
|
|
path: "/a/lib/lib.d.ts",
|
|
content: libFileContent
|
|
};
|
|
|
|
it("create inferred project", () => {
|
|
const appFile: FileOrFolder = {
|
|
path: "/a/b/c/app.ts",
|
|
content: `
|
|
import {f} from "./module"
|
|
console.log(f)
|
|
`
|
|
};
|
|
|
|
const moduleFile: FileOrFolder = {
|
|
path: "/a/b/c/module.d.ts",
|
|
content: `export let x: number`
|
|
};
|
|
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [appFile, moduleFile, libFile]);
|
|
const projectService = new server.ProjectService(host, nullLogger);
|
|
const { configFileName } = projectService.openClientFile(appFile.path);
|
|
|
|
assert(!configFileName, `should not find config, got: '${configFileName}`);
|
|
checkNumberOfConfiguredProjects(projectService, 0);
|
|
checkNumberOfInferredProjects(projectService, 1);
|
|
|
|
const project = projectService.inferredProjects[0];
|
|
|
|
checkFileNames("inferred project", project.getFileNames(), [appFile.path, libFile.path, moduleFile.path]);
|
|
checkWatchedDirectories(host, ["/a/b/c", "/a/b", "/a"]);
|
|
});
|
|
|
|
it("create configured project without file list", () => {
|
|
const configFile: FileOrFolder = {
|
|
path: "/a/b/tsconfig.json",
|
|
content: `
|
|
{
|
|
"compilerOptions": {},
|
|
"exclude": [
|
|
"e"
|
|
]
|
|
}`
|
|
};
|
|
const file1: FileOrFolder = {
|
|
path: "/a/b/c/f1.ts",
|
|
content: "let x = 1"
|
|
};
|
|
const file2: FileOrFolder = {
|
|
path: "/a/b/d/f2.ts",
|
|
content: "let y = 1"
|
|
};
|
|
const file3: FileOrFolder = {
|
|
path: "/a/b/e/f3.ts",
|
|
content: "let z = 1"
|
|
};
|
|
|
|
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [ configFile, libFile, file1, file2, file3 ]);
|
|
const projectService = new server.ProjectService(host, nullLogger);
|
|
const { configFileName, configFileErrors } = projectService.openClientFile(file1.path);
|
|
|
|
assert(configFileName, "should find config file");
|
|
assert.isTrue(!configFileErrors, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`);
|
|
checkNumberOfInferredProjects(projectService, 0);
|
|
checkNumberOfConfiguredProjects(projectService, 1);
|
|
|
|
const project = projectService.configuredProjects[0];
|
|
checkConfiguredProjectActualFiles(project, [file1.path, libFile.path, file2.path]);
|
|
checkConfiguredProjectRootFiles(project, [file1.path, file2.path]);
|
|
// watching all files except one that was open
|
|
checkWatchedFiles(host, [configFile.path, file2.path, libFile.path]);
|
|
checkWatchedDirectories(host, [getDirectoryPath(configFile.path)]);
|
|
});
|
|
|
|
it("add and then remove a config file in a folder with loose files", () => {
|
|
const configFile: FileOrFolder = {
|
|
path: "/a/b/tsconfig.json",
|
|
content: `{
|
|
"files": ["commonFile1.ts"]
|
|
}`
|
|
};
|
|
const filesWithoutConfig = [ libFile, commonFile1, commonFile2 ];
|
|
const filesWithConfig = [ libFile, commonFile1, commonFile2, configFile ];
|
|
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", filesWithoutConfig);
|
|
const projectService = new server.ProjectService(host, nullLogger);
|
|
projectService.openClientFile(commonFile1.path);
|
|
projectService.openClientFile(commonFile2.path);
|
|
|
|
checkNumberOfInferredProjects(projectService, 2);
|
|
checkWatchedDirectories(host, ["/a/b", "/a"]);
|
|
|
|
// Add a tsconfig file
|
|
host.reloadFS(filesWithConfig);
|
|
host.triggerDirectoryWatcherCallback("/a/b", configFile.path);
|
|
|
|
checkNumberOfInferredProjects(projectService, 1);
|
|
checkNumberOfConfiguredProjects(projectService, 1);
|
|
// watching all files except one that was open
|
|
checkWatchedFiles(host, [libFile.path, configFile.path]);
|
|
|
|
// remove the tsconfig file
|
|
host.reloadFS(filesWithoutConfig);
|
|
host.triggerFileWatcherCallback(configFile.path);
|
|
|
|
checkNumberOfInferredProjects(projectService, 2);
|
|
checkNumberOfConfiguredProjects(projectService, 0);
|
|
checkWatchedDirectories(host, ["/a/b", "/a"]);
|
|
});
|
|
|
|
it("add new files to a configured project without file list", () => {
|
|
const configFile: FileOrFolder = {
|
|
path: "/a/b/tsconfig.json",
|
|
content: `{}`
|
|
};
|
|
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [commonFile1, libFile, configFile]);
|
|
const projectService = new server.ProjectService(host, nullLogger);
|
|
projectService.openClientFile(commonFile1.path);
|
|
checkWatchedDirectories(host, ["/a/b"]);
|
|
checkNumberOfConfiguredProjects(projectService, 1);
|
|
|
|
const project = projectService.configuredProjects[0];
|
|
checkConfiguredProjectRootFiles(project, [commonFile1.path]);
|
|
|
|
// add a new ts file
|
|
host.reloadFS([commonFile1, commonFile2, libFile, configFile]);
|
|
host.triggerDirectoryWatcherCallback("/a/b", commonFile2.path);
|
|
host.runQueuedTimeoutCallbacks();
|
|
// project service waits for 250ms to update the project structure, therefore the assertion needs to wait longer.
|
|
checkConfiguredProjectRootFiles(project, [commonFile1.path, commonFile2.path]);
|
|
});
|
|
|
|
it("should ignore non-existing files specified in the config file", () => {
|
|
const configFile: FileOrFolder = {
|
|
path: "/a/b/tsconfig.json",
|
|
content: `{
|
|
"compilerOptions": {},
|
|
"files": [
|
|
"commonFile1.ts",
|
|
"commonFile3.ts"
|
|
]
|
|
}`
|
|
};
|
|
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [commonFile1, commonFile2, configFile]);
|
|
const projectService = new server.ProjectService(host, nullLogger);
|
|
projectService.openClientFile(commonFile1.path);
|
|
projectService.openClientFile(commonFile2.path);
|
|
|
|
checkNumberOfConfiguredProjects(projectService, 1);
|
|
const project = projectService.configuredProjects[0];
|
|
checkConfiguredProjectRootFiles(project, [commonFile1.path]);
|
|
checkNumberOfInferredProjects(projectService, 1);
|
|
});
|
|
|
|
it("handle recreated files correctly", () => {
|
|
const configFile: FileOrFolder = {
|
|
path: "/a/b/tsconfig.json",
|
|
content: `{}`
|
|
};
|
|
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [commonFile1, commonFile2, configFile]);
|
|
const projectService = new server.ProjectService(host, nullLogger);
|
|
projectService.openClientFile(commonFile1.path);
|
|
|
|
checkNumberOfConfiguredProjects(projectService, 1);
|
|
const project = projectService.configuredProjects[0];
|
|
checkConfiguredProjectRootFiles(project, [commonFile1.path, commonFile2.path]);
|
|
|
|
// delete commonFile2
|
|
host.reloadFS([commonFile1, configFile]);
|
|
host.triggerDirectoryWatcherCallback("/a/b", commonFile2.path);
|
|
host.runQueuedTimeoutCallbacks();
|
|
checkConfiguredProjectRootFiles(project, [commonFile1.path]);
|
|
|
|
// re-add commonFile2
|
|
host.reloadFS([commonFile1, commonFile2, configFile]);
|
|
host.triggerDirectoryWatcherCallback("/a/b", commonFile2.path);
|
|
host.runQueuedTimeoutCallbacks();
|
|
checkConfiguredProjectRootFiles(project, [commonFile1.path, commonFile2.path]);
|
|
});
|
|
|
|
it("should create new inferred projects for files excluded from a configured project", () => {
|
|
const configFile: FileOrFolder = {
|
|
path: "/a/b/tsconfig.json",
|
|
content: `{
|
|
"compilerOptions": {},
|
|
"files": ["${commonFile1.path}", "${commonFile2.path}"]
|
|
}`
|
|
};
|
|
const files = [commonFile1, commonFile2, configFile];
|
|
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", files);
|
|
const projectService = new server.ProjectService(host, nullLogger);
|
|
projectService.openClientFile(commonFile1.path);
|
|
|
|
const project = projectService.configuredProjects[0];
|
|
checkConfiguredProjectRootFiles(project, [commonFile1.path, commonFile2.path]);
|
|
configFile.content = `{
|
|
"compilerOptions": {},
|
|
"files": ["${commonFile1.path}"]
|
|
}`;
|
|
host.reloadFS(files);
|
|
host.triggerFileWatcherCallback(configFile.path);
|
|
|
|
checkNumberOfConfiguredProjects(projectService, 1);
|
|
checkConfiguredProjectRootFiles(project, [commonFile1.path]);
|
|
|
|
projectService.openClientFile(commonFile2.path);
|
|
checkNumberOfInferredProjects(projectService, 1);
|
|
});
|
|
|
|
it("files explicitly excluded in config file", () => {
|
|
const configFile: FileOrFolder = {
|
|
path: "/a/b/tsconfig.json",
|
|
content: `{
|
|
"compilerOptions": {},
|
|
"exclude": ["/a/c"]
|
|
}`
|
|
};
|
|
const excludedFile1: FileOrFolder = {
|
|
path: "/a/c/excluedFile1.ts",
|
|
content: `let t = 1;`
|
|
};
|
|
|
|
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [commonFile1, commonFile2, excludedFile1, configFile]);
|
|
const projectService = new server.ProjectService(host, nullLogger);
|
|
|
|
projectService.openClientFile(commonFile1.path);
|
|
checkNumberOfConfiguredProjects(projectService, 1);
|
|
const project = projectService.configuredProjects[0];
|
|
checkConfiguredProjectRootFiles(project, [commonFile1.path, commonFile2.path]);
|
|
projectService.openClientFile(excludedFile1.path);
|
|
checkNumberOfInferredProjects(projectService, 1);
|
|
});
|
|
|
|
it("should properly handle module resolution changes in config file", () => {
|
|
const file1: FileOrFolder = {
|
|
path: "/a/b/file1.ts",
|
|
content: `import { T } from "module1";`
|
|
};
|
|
const nodeModuleFile: FileOrFolder = {
|
|
path: "/a/b/node_modules/module1.ts",
|
|
content: `export interface T {}`
|
|
};
|
|
const classicModuleFile: FileOrFolder = {
|
|
path: "/a/module1.ts",
|
|
content: `export interface T {}`
|
|
};
|
|
const configFile: FileOrFolder = {
|
|
path: "/a/b/tsconfig.json",
|
|
content: `{
|
|
"compilerOptions": {
|
|
"moduleResolution": "node"
|
|
},
|
|
"files": ["${file1.path}"]
|
|
}`
|
|
};
|
|
const files = [file1, nodeModuleFile, classicModuleFile, configFile];
|
|
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", files);
|
|
const projectService = new server.ProjectService(host, nullLogger);
|
|
projectService.openClientFile(file1.path);
|
|
projectService.openClientFile(nodeModuleFile.path);
|
|
projectService.openClientFile(classicModuleFile.path);
|
|
|
|
checkNumberOfConfiguredProjects(projectService, 1);
|
|
const project = projectService.configuredProjects[0];
|
|
checkConfiguredProjectActualFiles(project, [file1.path, nodeModuleFile.path]);
|
|
checkNumberOfInferredProjects(projectService, 1);
|
|
|
|
configFile.content = `{
|
|
"compilerOptions": {
|
|
"moduleResolution": "classic"
|
|
},
|
|
"files": ["${file1.path}"]
|
|
}`;
|
|
host.reloadFS(files);
|
|
host.triggerFileWatcherCallback(configFile.path);
|
|
checkConfiguredProjectActualFiles(project, [file1.path, classicModuleFile.path]);
|
|
checkNumberOfInferredProjects(projectService, 1);
|
|
});
|
|
});
|
|
} |