mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-16 05:58:32 -06:00
Merge remote-tracking branch 'origin/master' into tsserverVS-WIP
This commit is contained in:
commit
82715e22a2
@ -2613,11 +2613,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
return isSourceFileLevelDeclarationInSystemJsModule(targetDeclaration, /*isExported*/ true);
|
||||
}
|
||||
|
||||
function isNameOfExportedDeclarationInNonES6Module(node: Node): boolean {
|
||||
if (modulekind === ModuleKind.System || node.kind !== SyntaxKind.Identifier || nodeIsSynthesized(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, (<Identifier>node).text);
|
||||
}
|
||||
|
||||
function emitPrefixUnaryExpression(node: PrefixUnaryExpression) {
|
||||
const exportChanged = (node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) &&
|
||||
const isPlusPlusOrMinusMinus = (node.operator === SyntaxKind.PlusPlusToken
|
||||
|| node.operator === SyntaxKind.MinusMinusToken);
|
||||
const externalExportChanged = isPlusPlusOrMinusMinus &&
|
||||
isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
|
||||
|
||||
if (exportChanged) {
|
||||
if (externalExportChanged) {
|
||||
// emit
|
||||
// ++x
|
||||
// as
|
||||
@ -2626,6 +2636,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
emitNodeWithoutSourceMap(node.operand);
|
||||
write(`", `);
|
||||
}
|
||||
const internalExportChanged = isPlusPlusOrMinusMinus &&
|
||||
isNameOfExportedDeclarationInNonES6Module(node.operand);
|
||||
|
||||
if (internalExportChanged) {
|
||||
emitAliasEqual(<Identifier> node.operand);
|
||||
}
|
||||
|
||||
write(tokenToString(node.operator));
|
||||
// In some cases, we need to emit a space between the operator and the operand. One obvious case
|
||||
@ -2651,14 +2667,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
}
|
||||
emit(node.operand);
|
||||
|
||||
if (exportChanged) {
|
||||
if (externalExportChanged) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
|
||||
function emitPostfixUnaryExpression(node: PostfixUnaryExpression) {
|
||||
const exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
|
||||
if (exportChanged) {
|
||||
const externalExportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
|
||||
const internalExportChanged = isNameOfExportedDeclarationInNonES6Module(node.operand);
|
||||
|
||||
if (externalExportChanged) {
|
||||
// export function returns the value that was passes as the second argument
|
||||
// however for postfix unary expressions result value should be the value before modification.
|
||||
// emit 'x++' as '(export('x', ++x) - 1)' and 'x--' as '(export('x', --x) + 1)'
|
||||
@ -2676,6 +2694,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
write(") + 1)");
|
||||
}
|
||||
}
|
||||
else if (internalExportChanged) {
|
||||
emitAliasEqual(<Identifier> node.operand);
|
||||
emit(node.operand);
|
||||
if (node.operator === SyntaxKind.PlusPlusToken) {
|
||||
write(" += 1");
|
||||
}
|
||||
else {
|
||||
write(" -= 1");
|
||||
}
|
||||
}
|
||||
else {
|
||||
emit(node.operand);
|
||||
write(tokenToString(node.operator));
|
||||
@ -2777,24 +2805,50 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
}
|
||||
}
|
||||
|
||||
function emitAliasEqual(name: Identifier): boolean {
|
||||
for (const specifier of exportSpecifiers[name.text]) {
|
||||
emitStart(specifier.name);
|
||||
emitContainingModuleName(specifier);
|
||||
if (languageVersion === ScriptTarget.ES3 && name.text === "default") {
|
||||
write('["default"]');
|
||||
}
|
||||
else {
|
||||
write(".");
|
||||
emitNodeWithCommentsAndWithoutSourcemap(specifier.name);
|
||||
}
|
||||
emitEnd(specifier.name);
|
||||
write(" = ");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function emitBinaryExpression(node: BinaryExpression) {
|
||||
if (languageVersion < ScriptTarget.ES6 && node.operatorToken.kind === SyntaxKind.EqualsToken &&
|
||||
(node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) {
|
||||
emitDestructuring(node, node.parent.kind === SyntaxKind.ExpressionStatement);
|
||||
}
|
||||
else {
|
||||
const exportChanged =
|
||||
node.operatorToken.kind >= SyntaxKind.FirstAssignment &&
|
||||
node.operatorToken.kind <= SyntaxKind.LastAssignment &&
|
||||
const isAssignment = isAssignmentOperator(node.operatorToken.kind);
|
||||
|
||||
const externalExportChanged = isAssignment &&
|
||||
isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.left);
|
||||
|
||||
if (exportChanged) {
|
||||
if (externalExportChanged) {
|
||||
// emit assignment 'x <op> y' as 'exports("x", x <op> y)'
|
||||
write(`${exportFunctionForFile}("`);
|
||||
emitNodeWithoutSourceMap(node.left);
|
||||
write(`", `);
|
||||
}
|
||||
|
||||
const internalExportChanged = isAssignment &&
|
||||
isNameOfExportedDeclarationInNonES6Module(node.left);
|
||||
|
||||
if (internalExportChanged) {
|
||||
// export { foo }
|
||||
// emit foo = 2 as exports.foo = foo = 2
|
||||
emitAliasEqual(<Identifier>node.left);
|
||||
}
|
||||
|
||||
if (node.operatorToken.kind === SyntaxKind.AsteriskAsteriskToken || node.operatorToken.kind === SyntaxKind.AsteriskAsteriskEqualsToken) {
|
||||
// Downleveled emit exponentiation operator using Math.pow
|
||||
emitExponentiationOperator(node);
|
||||
@ -2815,7 +2869,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
decreaseIndentIf(indentedBeforeOperator, indentedAfterOperator);
|
||||
}
|
||||
|
||||
if (exportChanged) {
|
||||
if (externalExportChanged) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1143,6 +1143,7 @@ namespace ts {
|
||||
// if any of these properties has changed - structure cannot be reused
|
||||
const oldOptions = oldProgram.getCompilerOptions();
|
||||
if ((oldOptions.module !== options.module) ||
|
||||
(oldOptions.moduleResolution !== options.moduleResolution) ||
|
||||
(oldOptions.noResolve !== options.noResolve) ||
|
||||
(oldOptions.target !== options.target) ||
|
||||
(oldOptions.noLib !== options.noLib) ||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
namespace ts {
|
||||
export type FileWatcherCallback = (fileName: string, removed?: boolean) => void;
|
||||
export type DirectoryWatcherCallback = (directoryName: string) => void;
|
||||
export type DirectoryWatcherCallback = (fileName: string) => void;
|
||||
export interface WatchedFile {
|
||||
fileName: string;
|
||||
callback: FileWatcherCallback;
|
||||
|
||||
@ -2919,6 +2919,7 @@ namespace ts {
|
||||
const changesInCompilationSettingsAffectSyntax = oldSettings &&
|
||||
(oldSettings.target !== newSettings.target ||
|
||||
oldSettings.module !== newSettings.module ||
|
||||
oldSettings.moduleResolution !== newSettings.moduleResolution ||
|
||||
oldSettings.noResolve !== newSettings.noResolve ||
|
||||
oldSettings.jsx !== newSettings.jsx ||
|
||||
oldSettings.allowJs !== newSettings.allowJs);
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
//// [server.ts]
|
||||
|
||||
var foo = 2;
|
||||
foo = 3;
|
||||
|
||||
var baz = 3;
|
||||
baz = 4;
|
||||
|
||||
var buzz = 10;
|
||||
buzz += 3;
|
||||
|
||||
var bizz = 8;
|
||||
bizz++; // compiles to exports.bizz = bizz += 1
|
||||
bizz--; // similarly
|
||||
++bizz; // compiles to exports.bizz = ++bizz
|
||||
|
||||
export { foo, baz, baz as quux, buzz, bizz };
|
||||
|
||||
|
||||
//// [server.js]
|
||||
"use strict";
|
||||
var foo = 2;
|
||||
exports.foo = foo;
|
||||
exports.foo = foo = 3;
|
||||
var baz = 3;
|
||||
exports.baz = baz;
|
||||
exports.quux = baz;
|
||||
exports.baz = exports.quux = baz = 4;
|
||||
var buzz = 10;
|
||||
exports.buzz = buzz;
|
||||
exports.buzz = buzz += 3;
|
||||
var bizz = 8;
|
||||
exports.bizz = bizz;
|
||||
exports.bizz = bizz += 1; // compiles to exports.bizz = bizz += 1
|
||||
exports.bizz = bizz -= 1; // similarly
|
||||
exports.bizz = ++bizz; // compiles to exports.bizz = ++bizz
|
||||
@ -0,0 +1,40 @@
|
||||
=== tests/cases/compiler/server.ts ===
|
||||
|
||||
var foo = 2;
|
||||
>foo : Symbol(foo, Decl(server.ts, 1, 3))
|
||||
|
||||
foo = 3;
|
||||
>foo : Symbol(foo, Decl(server.ts, 1, 3))
|
||||
|
||||
var baz = 3;
|
||||
>baz : Symbol(baz, Decl(server.ts, 4, 3))
|
||||
|
||||
baz = 4;
|
||||
>baz : Symbol(baz, Decl(server.ts, 4, 3))
|
||||
|
||||
var buzz = 10;
|
||||
>buzz : Symbol(buzz, Decl(server.ts, 7, 3))
|
||||
|
||||
buzz += 3;
|
||||
>buzz : Symbol(buzz, Decl(server.ts, 7, 3))
|
||||
|
||||
var bizz = 8;
|
||||
>bizz : Symbol(bizz, Decl(server.ts, 10, 3))
|
||||
|
||||
bizz++; // compiles to exports.bizz = bizz += 1
|
||||
>bizz : Symbol(bizz, Decl(server.ts, 10, 3))
|
||||
|
||||
bizz--; // similarly
|
||||
>bizz : Symbol(bizz, Decl(server.ts, 10, 3))
|
||||
|
||||
++bizz; // compiles to exports.bizz = ++bizz
|
||||
>bizz : Symbol(bizz, Decl(server.ts, 10, 3))
|
||||
|
||||
export { foo, baz, baz as quux, buzz, bizz };
|
||||
>foo : Symbol(foo, Decl(server.ts, 15, 8))
|
||||
>baz : Symbol(baz, Decl(server.ts, 15, 13))
|
||||
>baz : Symbol(quux, Decl(server.ts, 15, 18))
|
||||
>quux : Symbol(quux, Decl(server.ts, 15, 18))
|
||||
>buzz : Symbol(buzz, Decl(server.ts, 15, 31))
|
||||
>bizz : Symbol(bizz, Decl(server.ts, 15, 37))
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
=== tests/cases/compiler/server.ts ===
|
||||
|
||||
var foo = 2;
|
||||
>foo : number
|
||||
>2 : number
|
||||
|
||||
foo = 3;
|
||||
>foo = 3 : number
|
||||
>foo : number
|
||||
>3 : number
|
||||
|
||||
var baz = 3;
|
||||
>baz : number
|
||||
>3 : number
|
||||
|
||||
baz = 4;
|
||||
>baz = 4 : number
|
||||
>baz : number
|
||||
>4 : number
|
||||
|
||||
var buzz = 10;
|
||||
>buzz : number
|
||||
>10 : number
|
||||
|
||||
buzz += 3;
|
||||
>buzz += 3 : number
|
||||
>buzz : number
|
||||
>3 : number
|
||||
|
||||
var bizz = 8;
|
||||
>bizz : number
|
||||
>8 : number
|
||||
|
||||
bizz++; // compiles to exports.bizz = bizz += 1
|
||||
>bizz++ : number
|
||||
>bizz : number
|
||||
|
||||
bizz--; // similarly
|
||||
>bizz-- : number
|
||||
>bizz : number
|
||||
|
||||
++bizz; // compiles to exports.bizz = ++bizz
|
||||
>++bizz : number
|
||||
>bizz : number
|
||||
|
||||
export { foo, baz, baz as quux, buzz, bizz };
|
||||
>foo : number
|
||||
>baz : number
|
||||
>baz : number
|
||||
>quux : number
|
||||
>buzz : number
|
||||
>bizz : number
|
||||
|
||||
19
tests/cases/compiler/es6ExportClauseWithAssignmentInEs5.ts
Normal file
19
tests/cases/compiler/es6ExportClauseWithAssignmentInEs5.ts
Normal file
@ -0,0 +1,19 @@
|
||||
// @target: es5
|
||||
// @module: commonjs
|
||||
|
||||
// @filename: server.ts
|
||||
var foo = 2;
|
||||
foo = 3;
|
||||
|
||||
var baz = 3;
|
||||
baz = 4;
|
||||
|
||||
var buzz = 10;
|
||||
buzz += 3;
|
||||
|
||||
var bizz = 8;
|
||||
bizz++; // compiles to exports.bizz = bizz += 1
|
||||
bizz--; // similarly
|
||||
++bizz; // compiles to exports.bizz = ++bizz
|
||||
|
||||
export { foo, baz, baz as quux, buzz, bizz };
|
||||
@ -107,6 +107,32 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
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";
|
||||
@ -114,6 +140,7 @@ namespace ts {
|
||||
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[]> = {};
|
||||
|
||||
@ -188,6 +215,26 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
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] = []);
|
||||
@ -204,8 +251,27 @@ namespace ts {
|
||||
}
|
||||
|
||||
// TOOD: record and invoke callbacks to simulate timer events
|
||||
readonly setTimeout = (callback: (...args: any[]) => void, ms: number, ...args: any[]): any => void 0;
|
||||
readonly clearTimeout = (timeoutId: any): void => void 0;
|
||||
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;
|
||||
@ -216,7 +282,20 @@ namespace ts {
|
||||
readonly exit = () => notImplemented();
|
||||
}
|
||||
|
||||
describe("tsserver project system:", () => {
|
||||
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",
|
||||
@ -225,10 +304,7 @@ namespace ts {
|
||||
console.log(f)
|
||||
`
|
||||
};
|
||||
const libFile: FileOrFolder = {
|
||||
path: "/a/lib/lib.d.ts",
|
||||
content: libFileContent
|
||||
};
|
||||
|
||||
const moduleFile: FileOrFolder = {
|
||||
path: "/a/b/c/module.d.ts",
|
||||
content: `export let x: number`
|
||||
@ -238,13 +314,13 @@ namespace ts {
|
||||
const { configFileName } = projectService.openClientFile(appFile.path);
|
||||
|
||||
assert(!configFileName, `should not find config, got: '${configFileName}`);
|
||||
assert.equal(projectService.inferredProjects.length, 1, "expected one inferred project");
|
||||
assert.equal(projectService.configuredProjects.length, 0, "expected no configured project");
|
||||
checkNumberOfConfiguredProjects(projectService, 0);
|
||||
checkNumberOfInferredProjects(projectService, 1);
|
||||
|
||||
const project = projectService.inferredProjects[0];
|
||||
|
||||
checkFileNames("inferred project", project.getFileNames(), [appFile.path, libFile.path, moduleFile.path]);
|
||||
checkMapKeys("watchedDirectories", host.watchedDirectories, ["/a/b/c", "/a/b", "/a"]);
|
||||
checkWatchedDirectories(host, ["/a/b/c", "/a/b", "/a"]);
|
||||
});
|
||||
|
||||
it("create configured project without file list", () => {
|
||||
@ -258,10 +334,6 @@ namespace ts {
|
||||
]
|
||||
}`
|
||||
};
|
||||
const libFile: FileOrFolder = {
|
||||
path: "/a/lib/lib.d.ts",
|
||||
content: libFileContent
|
||||
};
|
||||
const file1: FileOrFolder = {
|
||||
path: "/a/b/c/f1.ts",
|
||||
content: "let x = 1"
|
||||
@ -274,21 +346,226 @@ namespace ts {
|
||||
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)}`);
|
||||
assert.equal(projectService.inferredProjects.length, 0, "expected no inferred project");
|
||||
assert.equal(projectService.configuredProjects.length, 1, "expected one configured project");
|
||||
checkNumberOfInferredProjects(projectService, 0);
|
||||
checkNumberOfConfiguredProjects(projectService, 1);
|
||||
|
||||
const project = projectService.configuredProjects[0];
|
||||
checkFileNames("configuredProjects project, actualFileNames", project.getFileNames(), [file1.path, libFile.path, file2.path]);
|
||||
checkFileNames("configuredProjects project, rootFileNames", project.getRootFiles(), [file1.path, file2.path]);
|
||||
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)]);
|
||||
});
|
||||
|
||||
checkMapKeys("watchedFiles", host.watchedFiles, [configFile.path, file2.path, libFile.path]); // watching all files except one that was open
|
||||
checkMapKeys("watchedDirectories", host.watchedDirectories, [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);
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user