• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts.projectSystem {
2    describe("unittests:: tsserver:: symLinks", () => {
3        it("rename in common file renames all project", () => {
4            const projects = "/users/username/projects";
5            const folderA = `${projects}/a`;
6            const aFile: File = {
7                path: `${folderA}/a.ts`,
8                content: `import {C} from "./c/fc"; console.log(C)`
9            };
10            const aTsconfig: File = {
11                path: `${folderA}/tsconfig.json`,
12                content: JSON.stringify({ compilerOptions: { module: "commonjs" } })
13            };
14            const aC: SymLink = {
15                path: `${folderA}/c`,
16                symLink: "../c"
17            };
18            const aFc = `${folderA}/c/fc.ts`;
19
20            const folderB = `${projects}/b`;
21            const bFile: File = {
22                path: `${folderB}/b.ts`,
23                content: `import {C} from "./c/fc"; console.log(C)`
24            };
25            const bTsconfig: File = {
26                path: `${folderB}/tsconfig.json`,
27                content: JSON.stringify({ compilerOptions: { module: "commonjs" } })
28            };
29            const bC: SymLink = {
30                path: `${folderB}/c`,
31                symLink: "../c"
32            };
33            const bFc = `${folderB}/c/fc.ts`;
34
35            const folderC = `${projects}/c`;
36            const cFile: File = {
37                path: `${folderC}/fc.ts`,
38                content: `export const C = 8`
39            };
40
41            const files = [cFile, libFile, aFile, aTsconfig, aC, bFile, bTsconfig, bC];
42            const host = createServerHost(files);
43            const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) });
44            openFilesForSession(
45                [
46                    { file: aFile, projectRootPath: folderA },
47                    { file: bFile, projectRootPath: folderB },
48                    { file: aFc, projectRootPath: folderA },
49                    { file: bFc, projectRootPath: folderB },
50                ],
51                session);
52            executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, { file: aFc, ...protocolLocationFromSubstring(cFile.content, "C") });
53            baselineTsserverLogs("symLinks", "rename in common file renames all project", session);
54        });
55
56        describe("module resolution when symlinked folder contents change and resolve modules", () => {
57            const projectRootPath = "/users/username/projects/myproject";
58            const packages = `${projectRootPath}/javascript/packages`;
59            const recognizersDateTime = `${packages}/recognizers-date-time`;
60            const recognizersText = `${packages}/recognizers-text`;
61            const recognizersTextDist = `${recognizersText}/dist`;
62            const moduleName = "@microsoft/recognizers-text";
63            const moduleNameInFile = `"${moduleName}"`;
64            const recognizersDateTimeSrcFile: File = {
65                path: `${recognizersDateTime}/src/datetime/baseDate.ts`,
66                content: `import {C} from ${moduleNameInFile};
67new C();`
68            };
69            const recognizerDateTimeTsconfigPath = `${recognizersDateTime}/tsconfig.json`;
70            const recognizerDateTimeTsconfigWithoutPathMapping: File = {
71                path: recognizerDateTimeTsconfigPath,
72                content: JSON.stringify({
73                    include: ["src"]
74                })
75            };
76            const recognizerDateTimeTsconfigWithPathMapping: File = {
77                path: recognizerDateTimeTsconfigPath,
78                content: JSON.stringify({
79                    compilerOptions: {
80                        rootDir: "src",
81                        baseUrl: "./",
82                        paths: {
83                            "@microsoft/*": ["../*"]
84                        }
85                    },
86                    include: ["src"]
87                })
88            };
89            const nodeModulesRecorgnizersText: SymLink = {
90                path: `${recognizersDateTime}/node_modules/@microsoft/recognizers-text`,
91                symLink: recognizersText
92            };
93            const recognizerTextSrcFile: File = {
94                path: `${recognizersText}/src/recognizers-text.ts`,
95                content: `export class C { method () { return 10; } }`
96            };
97            const recongnizerTextDistTypingFile: File = {
98                path: `${recognizersTextDist}/types/recognizers-text.d.ts`,
99                content: `export class C { method(): number; }`
100            };
101            const recongnizerTextPackageJson: File = {
102                path: `${recognizersText}/package.json`,
103                content: JSON.stringify({
104                    typings: "dist/types/recognizers-text.d.ts"
105                })
106            };
107
108            function createSessionAndOpenFile(host: TestServerHost) {
109                const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) });
110                session.executeCommandSeq<protocol.OpenRequest>({
111                    command: protocol.CommandTypes.Open,
112                    arguments: {
113                        file: recognizersDateTimeSrcFile.path,
114                        projectRootPath
115                    }
116                });
117                return session;
118            }
119
120            function verifyModuleResolution(withPathMapping: boolean) {
121                describe(withPathMapping ? "when tsconfig file contains path mapping" : "when tsconfig does not contain path mapping", () => {
122                    const filesWithSources = [libFile, recognizersDateTimeSrcFile, withPathMapping ? recognizerDateTimeTsconfigWithPathMapping : recognizerDateTimeTsconfigWithoutPathMapping, recognizerTextSrcFile, recongnizerTextPackageJson];
123                    it("when project compiles from sources", () => {
124                        const host = createServerHost(filesWithSources);
125                        const session = createSessionAndOpenFile(host);
126                        verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] });
127
128                        host.ensureFileOrFolder(nodeModulesRecorgnizersText);
129                        host.writeFile(recongnizerTextDistTypingFile.path, recongnizerTextDistTypingFile.content);
130                        host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions
131                        host.runQueuedTimeoutCallbacks(); // Actual update
132
133                        verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] });
134
135                        // Change config file's module resolution affecting option
136                        const config = JSON.parse(host.readFile(recognizerDateTimeTsconfigPath)!);
137                        host.writeFile(recognizerDateTimeTsconfigPath, JSON.stringify({
138                            ...config,
139                            compilerOptions: { ...config.compilerOptions, resolveJsonModule: true }
140                        }));
141                        host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions
142                        host.runQueuedTimeoutCallbacks(); // Actual update
143
144                        baselineTsserverLogs("symLinks", `module resolution${withPathMapping ? " with path mapping" : ""} when project compiles from sources`, session);
145                    });
146
147                    it("when project has node_modules setup but doesnt have modules in typings folder and then recompiles", () => {
148                        const host = createServerHost([...filesWithSources, nodeModulesRecorgnizersText]);
149                        const session = createSessionAndOpenFile(host);
150                        verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] });
151
152                        host.writeFile(recongnizerTextDistTypingFile.path, recongnizerTextDistTypingFile.content);
153                        host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions
154                        host.runQueuedTimeoutCallbacks(); // Actual update
155
156                        verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] });
157                        baselineTsserverLogs("symLinks", `module resolution${withPathMapping ? " with path mapping" : ""} when project has node_modules setup but doesnt have modules in typings folder and then recompiles`, session);
158                    });
159
160                    it("when project recompiles after deleting generated folders", () => {
161                        const host = createServerHost([...filesWithSources, nodeModulesRecorgnizersText, recongnizerTextDistTypingFile]);
162                        const session = createSessionAndOpenFile(host);
163
164                        verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] });
165
166                        host.deleteFolder(recognizersTextDist, /*recursive*/ true);
167                        host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions
168                        host.runQueuedTimeoutCallbacks(); // Actual update
169
170                        verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] });
171
172                        host.ensureFileOrFolder(recongnizerTextDistTypingFile);
173                        host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions
174                        host.runQueuedTimeoutCallbacks(); // Actual update
175
176                        verifyGetErrRequest({ session, host, files: [recognizersDateTimeSrcFile] });
177                        baselineTsserverLogs("symLinks", `module resolution${withPathMapping ? " with path mapping" : ""} when project recompiles after deleting generated folders`, session);
178                    });
179                });
180            }
181
182            verifyModuleResolution(/*withPathMapping*/ false);
183            verifyModuleResolution(/*withPathMapping*/ true);
184        });
185    });
186}
187