From 9be475bdaa9e40787e610ffe0a27ecfe9ae323a8 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 3 Jul 2019 15:47:32 -0700 Subject: [PATCH] Refactoring --- .../unittests/tsserver/projectReferences.ts | 532 ++++++++---------- 1 file changed, 222 insertions(+), 310 deletions(-) diff --git a/src/testRunner/unittests/tsserver/projectReferences.ts b/src/testRunner/unittests/tsserver/projectReferences.ts index f39ec72e03e..f9445dc6d19 100644 --- a/src/testRunner/unittests/tsserver/projectReferences.ts +++ b/src/testRunner/unittests/tsserver/projectReferences.ts @@ -105,6 +105,7 @@ export function fn4() { } export function fn5() { } ` }; + const dependencyTsPath = dependencyTs.path.toLowerCase(); const dependencyConfig: File = { path: `${dependecyLocation}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, declarationMap: true, declarationDir: "../decls" } }) @@ -362,6 +363,13 @@ fn5(); }; } + function removePath(array: readonly string[], ...delPaths: string[]) { + return array.filter(a => { + const aLower = a.toLowerCase(); + return delPaths.every(dPath => dPath !== aLower); + }); + } + interface Action { reqName: string; request: Partial; @@ -369,8 +377,8 @@ fn5(); } interface ActionInfo { action: (fn: number) => Action; - closedInfos: () => readonly string[]; - otherWatchedFiles: () => readonly string[]; + closedInfos: readonly string[]; + otherWatchedFiles: readonly string[]; expectsDts: boolean; expectsMap: boolean; freshMapInfo?: boolean; @@ -379,7 +387,11 @@ fn5(); } type ActionKey = keyof ActionInfoVerifier; type ActionInfoGetterFn = () => ActionInfo; - type ActionInfoGetter = ActionInfoGetterFn | ActionKey; + type ActionInfoSpreader = [ + ActionKey, // Key to get initial value and pass this value to spread function + (actionInfo: ActionInfo) => Partial> + ]; + type ActionInfoGetter = ActionInfoGetterFn | ActionKey | ActionInfoSpreader; interface ProjectInfoVerifier { openFile: File; openFileLastLine: number; @@ -486,14 +498,25 @@ fn5(); } } + function getActionInfoOfVerfier(verifier: DocumentPositionMapperVerifier, actionKey: ActionKey): ActionInfo { + const actionInfoGetter = verifier[actionKey]; + if (isString(actionInfoGetter)) { + return getActionInfoOfVerfier(verifier, actionInfoGetter); + } + + if (isArray(actionInfoGetter)) { + const initialValue = getActionInfoOfVerfier(verifier, actionInfoGetter[0]); + return { + ...initialValue, + ...actionInfoGetter[1](initialValue) + }; + } + + return actionInfoGetter(); + } + function getActionInfo(verifiers: readonly DocumentPositionMapperVerifier[], actionKey: ActionKey): ActionInfo[] { - return verifiers.map(v => { - let actionInfoGetter = v[actionKey]; - while (isString(actionInfoGetter)) { - actionInfoGetter = v[actionInfoGetter]; - } - return actionInfoGetter(); - }); + return verifiers.map(v => getActionInfoOfVerfier(v, actionKey)); } interface VerifyAllFnAction { @@ -543,8 +566,8 @@ fn5(); session, host, openFiles(verifiers).map(f => f.path), - closedInfos(), - otherWatchedFiles(), + closedInfos, + otherWatchedFiles, debugInfo ); @@ -601,8 +624,8 @@ fn5(); session, host, openFiles(verifiers).map(f => f.path), - closedInfos(), - otherWatchedFiles(), + closedInfos, + otherWatchedFiles, debugInfo ); verifyDocumentPositionMapper({ @@ -887,360 +910,249 @@ ${dependencyTs.content}`); } describe("from project that uses dependency", () => { - function goToDefActionInfo(withRefs: boolean): ActionInfo { - return { - action: goToDefFromMainTs, - closedInfos: () => withRefs ? - [dependencyTs.path, dependencyConfig.path, libFile.path] : - [dependencyTs.path, libFile.path, dtsPath, dtsMapLocation], - otherWatchedFiles: () => [mainConfig.path], - expectsDts: !withRefs, // Dts script info present only if no project reference - expectsMap: !withRefs // Map script info present only if no project reference - }; - } - - function goToDefNoMapActionInfo(withRefs: boolean): ActionInfo { - return { - ...goToDefActionInfo(withRefs), - action: withRefs ? - goToDefFromMainTs : - goToDefFromMainTsWithNoMap, - closedInfos: () => withRefs ? - [dependencyTs.path, dependencyConfig.path, libFile.path] : - [libFile.path, dtsPath], // Because map is deleted, dts and dependency are released - otherWatchedFiles: () => withRefs ? - [mainConfig.path] : - [mainConfig.path, dtsMapPath], // Watches deleted file - expectsMap: false - }; - } - - function goToDefNoDtsActionInfo(withRefs: boolean): ActionInfo { - return { - ...goToDefActionInfo(withRefs), - action: withRefs ? - goToDefFromMainTs : - goToDefFromMainTsWithNoDts, - closedInfos: () => withRefs ? - [dependencyTs.path, dependencyConfig.path, libFile.path] : - [libFile.path], // No dts means no map, no dependency - expectsDts: false, - expectsMap: false - }; - } - verifyScenario({ mainScenario: "can go to definition correctly", verifier: withRefs => [ { ...goToDefFromMainTsProjectInfoVerifier(withRefs), - main: () => goToDefActionInfo(withRefs), + main: () => ({ + action: goToDefFromMainTs, + closedInfos: withRefs ? + [dependencyTs.path, dependencyConfig.path, libFile.path] : + [dependencyTs.path, libFile.path, dtsPath, dtsMapLocation], + otherWatchedFiles: [mainConfig.path], + expectsDts: !withRefs, // Dts script info present only if no project reference + expectsMap: !withRefs // Map script info present only if no project reference + }), change: "main", dtsChange: "main", - mapChange: () => ({ - ...goToDefActionInfo(withRefs), + mapChange: ["main", () => ({ freshDocumentMapper: true - }), - noMap: () => goToDefNoMapActionInfo(withRefs), + })], + noMap: withRefs ? + "main" : + ["main", main => ({ + action: goToDefFromMainTsWithNoMap, + // Because map is deleted, dts and dependency are released + closedInfos: removePath(main.closedInfos, dtsMapPath, dependencyTsPath), + // Watches deleted file + otherWatchedFiles: main.otherWatchedFiles.concat(dtsMapLocation), + expectsMap: false + })], mapFileCreated: "main", - mapFileDeleted: () => ({ - ...goToDefNoMapActionInfo(withRefs), - closedInfos: () => withRefs ? - [dependencyTs.path, dependencyConfig.path, libFile.path] : + mapFileDeleted: withRefs ? + "main" : + ["noMap", noMap => ({ // The script info for depedency is collected only after file open - [dependencyTs.path, libFile.path, dtsPath] - }), - noDts: () => goToDefNoDtsActionInfo(withRefs), + closedInfos: noMap.closedInfos.concat(dependencyTs.path) + })], + noDts: withRefs ? + "main" : + ["main", main => ({ + action: goToDefFromMainTsWithNoDts, + // No dts, no map, no dependency + closedInfos: removePath(main.closedInfos, dtsPath, dtsMapPath, dependencyTsPath), + expectsDts: false, + expectsMap: false + })], dtsFileCreated: "main", - dtsFileDeleted: () => ({ - ...goToDefNoDtsActionInfo(withRefs), - // The script info for map is collected only after file open - closedInfos: () => withRefs ? - [dependencyTs.path, dependencyConfig.path, libFile.path] : - [dependencyTs.path, libFile.path, dtsMapLocation], - expectsMap: !withRefs - }), - dependencyChange: () => ({ - ...goToDefActionInfo(withRefs), + dtsFileDeleted: withRefs ? + "main" : + ["noDts", noDts => ({ + // The script info for map is collected only after file open + closedInfos: noDts.closedInfos.concat(dependencyTs.path, dtsMapLocation), + expectsMap: true + })], + dependencyChange: ["main", () => ({ action: goToDefFromMainTsWithDependencyChange, - expectsDts: false, - expectsMap: false - }), - noBuild: "main" + })], + noBuild: "noDts" } ] }); }); describe("from defining project", () => { - function renameActionInfo(): ActionInfo { - return { - action: renameFromDependencyTs, - closedInfos: () => [libFile.path, dtsLocation, dtsMapLocation], - otherWatchedFiles: () => [dependencyConfig.path], - expectsDts: true, - expectsMap: true - }; - } - - function renameNoDtsActionInfo(): ActionInfo { - return { - action: renameFromDependencyTs, - closedInfos: () => [libFile.path], // no dts or map since dts itself doesnt exist - otherWatchedFiles: () => [dependencyConfig.path, dtsPath], // watch deleted file - expectsDts: false, - expectsMap: false - }; - } - verifyScenario({ mainScenario: "rename locations from dependency", verifier: () => [ { ...renameFromDependencyTsProjectInfoVerifier(), - main: renameActionInfo, - change: "main", - dtsChange: "main", - mapChange: () => ({ - ...renameActionInfo(), - freshDocumentMapper: true - }), - noMap: () => ({ - ...renameActionInfo(), - closedInfos: () => [libFile.path, dtsLocation], // No map - otherWatchedFiles: () => [dependencyConfig.path, dtsMapLocation], // watch map - expectsMap: false - }), - mapFileCreated: "main", - mapFileDeleted: "noMap", - noDts: renameNoDtsActionInfo, - dtsFileCreated: "main", - dtsFileDeleted: () => ({ - ...renameNoDtsActionInfo(), - // Map is collected after file open - closedInfos: () => [libFile.path, dtsMapLocation], + main: () => ({ + action: renameFromDependencyTs, + closedInfos: [libFile.path, dtsLocation, dtsMapLocation], + otherWatchedFiles: [dependencyConfig.path], + expectsDts: true, expectsMap: true }), - dependencyChange: () => ({ - ...renameActionInfo(), - action: renameFromDependencyTsWithDependencyChange - }), - noBuild: () => ({ - action: renameFromDependencyTs, - closedInfos: () => [libFile.path], // No dts or map since its not built/present - // Watching for creation of dts so that it can give correct results across projects - otherWatchedFiles: () => [dependencyConfig.path, dtsPath], + change: "main", + dtsChange: "main", + mapChange: ["main", () => ({ + freshDocumentMapper: true + })], + noMap: ["main", main => ({ + // No map + closedInfos: removePath(main.closedInfos, dtsMapPath), + // watch map + otherWatchedFiles: [...main.otherWatchedFiles, dtsMapLocation], + expectsMap: false + })], + mapFileCreated: "main", + mapFileDeleted: "noMap", + noDts: ["main", main => ({ + // no dts or map since dts itself doesnt exist + closedInfos: removePath(main.closedInfos, dtsMapPath, dtsPath), + // watch deleted file + otherWatchedFiles: [...main.otherWatchedFiles, dtsLocation], expectsDts: false, expectsMap: false - }) + })], + dtsFileCreated: "main", + dtsFileDeleted: ["noDts", noDts => ({ + // Map is collected after file open + closedInfos: noDts.closedInfos.concat(dtsMapLocation), + expectsMap: true + })], + dependencyChange: ["main", () => ({ + action: renameFromDependencyTsWithDependencyChange + })], + noBuild: "noDts" } ] }); }); describe("when opening depedency and usage project", () => { - function goToDefActionInfo(withRefs: boolean): ActionInfo { - return { - action: goToDefFromMainTs, - // DependencyTs is open, so omit it from closed infos - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path] : - [libFile.path, dtsPath, dtsMapLocation], - otherWatchedFiles: () => withRefs ? - [mainConfig.path] : // Its in closed info - [mainConfig.path, dependencyConfig.path], - expectsDts: !withRefs, // Dts script info present only if no project reference - expectsMap: !withRefs // Map script info present only if no project reference - }; - } - - function renameActionInfo(withRefs: boolean): ActionInfo { - return { - action: renameFromDependencyTsWithBothProjectsOpen, - // DependencyTs is open, so omit it from closed infos - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path, dtsLocation, dtsMapLocation] : - [libFile.path, dtsPath, dtsMapLocation], - otherWatchedFiles: () => withRefs ? - [mainConfig.path] : // Its in closed info - [mainConfig.path, dependencyConfig.path], - expectsDts: true, - expectsMap: true - }; - } - - function goToDefNoMapActionInfo(withRefs: boolean): ActionInfo { - return { - action: withRefs ? - goToDefFromMainTs : - goToDefFromMainTsWithNoMap, - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path] : - [libFile.path, dtsPath], // No map - otherWatchedFiles: () => withRefs ? - [mainConfig.path] : // Its in closed info - [mainConfig.path, dependencyConfig.path, dtsMapLocation], // Watch map file - expectsDts: !withRefs, // Dts script info present only if no project reference - expectsMap: false - }; - } - - function renameNoMapActionInfo(withRefs: boolean): ActionInfo { - return { - ...renameActionInfo(withRefs), - action: withRefs ? - renameFromDependencyTsWithBothProjectsOpen : - renameFromDependencyTs, - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path, dtsLocation] : - [libFile.path, dtsPath], // No map - otherWatchedFiles: () => withRefs ? - [mainConfig.path, dtsMapLocation] : // Its in closed info - [mainConfig.path, dependencyConfig.path, dtsMapLocation], // Watch map file - expectsMap: false - }; - } - - function goToDefNoDtsActionInfo(withRefs: boolean): ActionInfo { - return { - ...goToDefActionInfo(withRefs), - action: withRefs ? - goToDefFromMainTs : - goToDefFromMainTsWithNoDts, - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path] : - [libFile.path], // No dts or map, - expectsDts: false, - expectsMap: false - }; - } - - function renameNoDtsActionInfo(withRefs: boolean): ActionInfo { - return { - action: withRefs ? - renameFromDependencyTsWithBothProjectsOpen : - renameFromDependencyTs, - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path] : - [libFile.path], // No dts or map, - otherWatchedFiles: () => withRefs ? - [mainConfig.path, dtsLocation] : - [mainConfig.path, dependencyConfig.path, dtsPath], // Watch dts, - expectsDts: false, - expectsMap: false - }; - } - verifyScenario({ mainScenario: "goto Definition in usage and rename locations from defining project", verifier: withRefs => [ { ...goToDefFromMainTsProjectInfoVerifier(withRefs), - main: () => goToDefActionInfo(withRefs), - change: () => ({ - // Because before this rename is done the closed info remains same as rename's main operation - ...goToDefActionInfo(withRefs), - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path, dtsLocation, dtsMapLocation] : + main: () => ({ + action: goToDefFromMainTs, + // DependencyTs is open, so omit it from closed infos + closedInfos: withRefs ? + [dependencyConfig.path, libFile.path] : [libFile.path, dtsPath, dtsMapLocation], - expectsDts: true, - expectsMap: true + otherWatchedFiles: withRefs ? + [mainConfig.path] : // Its in closed info + [mainConfig.path, dependencyConfig.path], + expectsDts: !withRefs, // Dts script info present only if no project reference + expectsMap: !withRefs // Map script info present only if no project reference }), + change: withRefs ? + ["main", main => ({ + // Because before this rename is done the closed info remains same as rename's main operation + closedInfos: main.closedInfos.concat(dtsLocation, dtsMapLocation), + expectsDts: true, + expectsMap: true + })] : + "main", dtsChange: "change", mapChange: "change", - noMap: () => goToDefNoMapActionInfo(withRefs), - mapFileCreated: () => ({ - // Because before this rename is done the closed info remains same as rename's main - ...goToDefActionInfo(withRefs), - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path, dtsLocation] : - [libFile.path, dtsPath, dtsMapLocation], - expectsDts: true, - // This operation doesnt need map so the map info path in dts is not refreshed - skipDtsMapCheck: withRefs - }), - mapFileDeleted: () => ({ - // Because before this rename is done the closed info remains same as rename's noMap operation - ...goToDefNoMapActionInfo(withRefs), - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path, dtsLocation] : - [libFile.path, dtsPath], // No map, - expectsDts: true, - // This operation doesnt need map so the map info path in dts is not refreshed - skipDtsMapCheck: withRefs - }), - noDts: () => goToDefNoDtsActionInfo(withRefs), - dtsFileCreated: () => ({ - ...goToDefActionInfo(withRefs), - // Since the project for dependency is not updated, the watcher from rename for dts still there - otherWatchedFiles: () => withRefs ? - [mainConfig.path, dtsLocation] : - [mainConfig.path, dependencyConfig.path], - }), - dtsFileDeleted: () => ({ - ...goToDefNoDtsActionInfo(withRefs), + noMap: withRefs ? + "main" : + ["main", main => ({ + action: goToDefFromMainTsWithNoMap, + closedInfos: removePath(main.closedInfos, dtsMapPath), + otherWatchedFiles: main.otherWatchedFiles.concat(dtsMapLocation), + expectsMap: false + })], + mapFileCreated: withRefs ? + ["main", main => ({ + // Because before this rename is done the closed info remains same as rename's main + closedInfos: main.closedInfos.concat(dtsLocation), + expectsDts: true, + // This operation doesnt need map so the map info path in dts is not refreshed + skipDtsMapCheck: withRefs + })] : + "main", + mapFileDeleted: withRefs ? + ["noMap", noMap => ({ + // Because before this rename is done the closed info remains same as rename's noMap operation + closedInfos: noMap.closedInfos.concat(dtsLocation), + expectsDts: true, + // This operation doesnt need map so the map info path in dts is not refreshed + skipDtsMapCheck: true + })] : + "noMap", + noDts: withRefs ? + "main" : + ["main", main => ({ + action: goToDefFromMainTsWithNoDts, + closedInfos: removePath(main.closedInfos, dtsMapPath, dtsPath), + expectsDts: false, + expectsMap: false + })], + dtsFileCreated: withRefs ? + ["main", main => ({ + // Since the project for dependency is not updated, the watcher from rename for dts still there + otherWatchedFiles: main.otherWatchedFiles.concat(dtsLocation) + })] : + "main", + dtsFileDeleted: ["noDts", noDts => ({ // Map collection after file open - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path, dtsMapLocation] : - [libFile.path, dtsMapLocation], + closedInfos: noDts.closedInfos.concat(dtsMapLocation), expectsMap: true - }), - dependencyChange: () => ({ - ...goToDefActionInfo(withRefs), + })], + dependencyChange: ["change", () => ({ action: goToDefFromMainTsWithDependencyChange, - // From rename main action - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path, dtsLocation, dtsMapLocation] : - [libFile.path, dtsPath, dtsMapLocation], - expectsDts: withRefs, - expectsMap: withRefs - }), - noBuild: "main" + })], + noBuild: "noDts" }, { ...renameFromDependencyTsProjectInfoVerifier(), main: () => ({ - ...renameActionInfo(withRefs), + action: renameFromDependencyTsWithBothProjectsOpen, + // DependencyTs is open, so omit it from closed infos + closedInfos: withRefs ? + [dependencyConfig.path, libFile.path, dtsLocation, dtsMapLocation] : + [libFile.path, dtsPath, dtsMapLocation], + otherWatchedFiles: withRefs ? + [mainConfig.path] : // Its in closed info + [mainConfig.path, dependencyConfig.path], + expectsDts: true, + expectsMap: true, freshMapInfo: withRefs }), - change: () => renameActionInfo(withRefs), + change: ["main", () => ({ + freshMapInfo: false + })], dtsChange: "change", - mapChange: () => ({ - ...renameActionInfo(withRefs), + mapChange: ["main", () => ({ + freshMapInfo: false, freshDocumentMapper: withRefs - }), - noMap: () => ({ - ...renameNoMapActionInfo(withRefs), - freshMapInfo: withRefs, + })], + noMap: ["main", main => ({ + action: withRefs ? + renameFromDependencyTsWithBothProjectsOpen : + renameFromDependencyTs, + closedInfos: removePath(main.closedInfos, dtsMapPath), + otherWatchedFiles: main.otherWatchedFiles.concat(dtsMapLocation), + expectsMap: false, freshDocumentMapper: withRefs - }), + })], mapFileCreated: "main", mapFileDeleted: "noMap", - noDts: () => renameNoDtsActionInfo(withRefs), - dtsFileCreated: "main", - dtsFileDeleted: () => ({ - ...renameNoDtsActionInfo(withRefs), - // Map collection after file open - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path, dtsMapLocation] : - [libFile.path, dtsMapLocation], - expectsMap: true - }), - dependencyChange: () => ({ - ...renameActionInfo(withRefs), - action: renameFromDependencyTsWithBothProjectsOpenWithDependencyChange - }), - noBuild: () => ({ - action: renameFromDependencyTsWithBothProjectsOpen, - closedInfos: () => withRefs ? - [dependencyConfig.path, libFile.path] : - [libFile.path], - otherWatchedFiles: () => withRefs ? - [mainConfig.path, dtsLocation] : // Its in closed info - [mainConfig.path, dependencyConfig.path], + noDts: ["change", change => ({ + action: withRefs ? + renameFromDependencyTsWithBothProjectsOpen : + renameFromDependencyTs, + closedInfos: removePath(change.closedInfos, dtsPath, dtsMapPath), + otherWatchedFiles: change.otherWatchedFiles.concat(dtsLocation), expectsDts: false, expectsMap: false - }) + })], + dtsFileCreated: "main", + dtsFileDeleted: ["noDts", noDts => ({ + // Map collection after file open + closedInfos: noDts.closedInfos.concat(dtsMapLocation) , + expectsMap: true + })], + dependencyChange: ["change", () => ({ + action: renameFromDependencyTsWithBothProjectsOpenWithDependencyChange + })], + noBuild: "noDts" } ] });