• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts.tscWatch {
2    import getFileFromProject = TestFSWithWatch.getTsBuildProjectFile;
3    describe("unittests:: tsc-watch:: watchAPI:: with sourceOfProjectReferenceRedirect", () => {
4        interface VerifyWatchInput {
5            files: readonly TestFSWithWatch.FileOrFolderOrSymLink[];
6            config: string;
7            expectedProgramFiles: readonly string[];
8        }
9        function verifyWatch(
10            { files, config, expectedProgramFiles }: VerifyWatchInput,
11            alreadyBuilt: boolean
12        ) {
13            const sys = createWatchedSystem(files);
14            if (alreadyBuilt) {
15                const solutionBuilder = createSolutionBuilder(sys, [config], {});
16                solutionBuilder.build();
17                solutionBuilder.close();
18                sys.clearOutput();
19            }
20            const host = createWatchCompilerHostOfConfigFile({
21                configFileName: config,
22                system: sys
23            });
24            host.useSourceOfProjectReferenceRedirect = returnTrue;
25            const watch = createWatchProgram(host);
26            checkProgramActualFiles(watch.getCurrentProgram().getProgram(), expectedProgramFiles);
27        }
28
29        function verifyScenario(input: () => VerifyWatchInput) {
30            it("when solution is not built", () => {
31                verifyWatch(input(), /*alreadyBuilt*/ false);
32            });
33
34            it("when solution is already built", () => {
35                verifyWatch(input(), /*alreadyBuilt*/ true);
36            });
37        }
38
39        describe("with simple project", () => {
40            verifyScenario(() => {
41                const baseConfig = getFileFromProject("demo", "tsconfig-base.json");
42                const coreTs = getFileFromProject("demo", "core/utilities.ts");
43                const coreConfig = getFileFromProject("demo", "core/tsconfig.json");
44                const animalTs = getFileFromProject("demo", "animals/animal.ts");
45                const dogTs = getFileFromProject("demo", "animals/dog.ts");
46                const indexTs = getFileFromProject("demo", "animals/index.ts");
47                const animalsConfig = getFileFromProject("demo", "animals/tsconfig.json");
48                return {
49                    files: [{ path: libFile.path, content: libContent }, baseConfig, coreTs, coreConfig, animalTs, dogTs, indexTs, animalsConfig],
50                    config: animalsConfig.path,
51                    expectedProgramFiles: [libFile.path, indexTs.path, dogTs.path, animalTs.path, coreTs.path]
52                };
53            });
54        });
55
56        describe("when references are monorepo like with symlinks", () => {
57            interface Packages {
58                bPackageJson: File;
59                aTest: File;
60                bFoo: File;
61                bBar: File;
62                bSymlink: SymLink;
63            }
64            function verifySymlinkScenario(packages: () => Packages) {
65                describe("when preserveSymlinks is turned off", () => {
66                    verifySymlinkScenarioWorker(packages, {});
67                });
68                describe("when preserveSymlinks is turned on", () => {
69                    verifySymlinkScenarioWorker(packages, { preserveSymlinks: true });
70                });
71            }
72
73            function verifySymlinkScenarioWorker(packages: () => Packages, extraOptions: CompilerOptions) {
74                verifyScenario(() => {
75                    const { bPackageJson, aTest, bFoo, bBar, bSymlink } = packages();
76                    const aConfig = config("A", extraOptions, ["../B"]);
77                    const bConfig = config("B", extraOptions);
78                    return {
79                        files: [libFile, bPackageJson, aConfig, bConfig, aTest, bFoo, bBar, bSymlink],
80                        config: aConfig.path,
81                        expectedProgramFiles: [libFile.path, aTest.path, bFoo.path, bBar.path]
82                    };
83                });
84            }
85
86            function config(packageName: string, extraOptions: CompilerOptions, references?: string[]): File {
87                return {
88                    path: `${projectRoot}/packages/${packageName}/tsconfig.json`,
89                    content: JSON.stringify({
90                        compilerOptions: {
91                            outDir: "lib",
92                            rootDir: "src",
93                            composite: true,
94                            ...extraOptions
95                        },
96                        include: ["src"],
97                        ...(references ? { references: references.map(path => ({ path })) } : {})
98                    })
99                };
100            }
101
102            function file(packageName: string, fileName: string, content: string): File {
103                return {
104                    path: `${projectRoot}/packages/${packageName}/src/${fileName}`,
105                    content
106                };
107            }
108
109            function verifyMonoRepoLike(scope = "") {
110                describe("when packageJson has types field", () => {
111                    verifySymlinkScenario(() => ({
112                        bPackageJson: {
113                            path: `${projectRoot}/packages/B/package.json`,
114                            content: JSON.stringify({
115                                main: "lib/index.js",
116                                types: "lib/index.d.ts"
117                            })
118                        },
119                        aTest: file("A", "index.ts", `import { foo } from '${scope}b';
120import { bar } from '${scope}b/lib/bar';
121foo();
122bar();
123`),
124                        bFoo: file("B", "index.ts", `export function foo() { }`),
125                        bBar: file("B", "bar.ts", `export function bar() { }`),
126                        bSymlink: {
127                            path: `${projectRoot}/node_modules/${scope}b`,
128                            symLink: `${projectRoot}/packages/B`
129                        }
130                    }));
131                });
132
133                describe("when referencing file from subFolder", () => {
134                    verifySymlinkScenario(() => ({
135                        bPackageJson: {
136                            path: `${projectRoot}/packages/B/package.json`,
137                            content: "{}"
138                        },
139                        aTest: file("A", "test.ts", `import { foo } from '${scope}b/lib/foo';
140import { bar } from '${scope}b/lib/bar/foo';
141foo();
142bar();
143`),
144                        bFoo: file("B", "foo.ts", `export function foo() { }`),
145                        bBar: file("B", "bar/foo.ts", `export function bar() { }`),
146                        bSymlink: {
147                            path: `${projectRoot}/node_modules/${scope}b`,
148                            symLink: `${projectRoot}/packages/B`
149                        }
150                    }));
151                });
152            }
153            describe("when package is not scoped", () => {
154                verifyMonoRepoLike();
155            });
156            describe("when package is scoped", () => {
157                verifyMonoRepoLike("@issue/");
158            });
159        });
160    });
161}
162