• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    export type TscCompileSystem = fakes.System & {
3        writtenFiles: Set<string>;
4        baseLine(): { file: string; text: string; };
5    };
6
7    export enum BuildKind {
8        Initial = "initial-build",
9        IncrementalDtsChange = "incremental-declaration-changes",
10        IncrementalDtsUnchanged = "incremental-declaration-doesnt-change",
11        IncrementalHeadersChange = "incremental-headers-change-without-dts-changes",
12        NoChangeRun ="no-change-run"
13    }
14
15    export const noChangeRun: TscIncremental = {
16        buildKind: BuildKind.NoChangeRun,
17        modifyFs: noop
18    };
19    export const noChangeOnlyRuns = [noChangeRun];
20
21    export interface TscCompile {
22        scenario: string;
23        subScenario: string;
24        buildKind?: BuildKind; // Should be defined for tsc --b
25        fs: () => vfs.FileSystem;
26        commandLineArgs: readonly string[];
27
28        modifyFs?: (fs: vfs.FileSystem) => void;
29        baselineSourceMap?: boolean;
30        baselineReadFileCalls?: boolean;
31        baselinePrograms?: boolean;
32    }
33
34    export type CommandLineProgram = [Program, EmitAndSemanticDiagnosticsBuilderProgram?];
35    export interface CommandLineCallbacks {
36        cb: ExecuteCommandLineCallbacks;
37        getPrograms: () => readonly CommandLineProgram[];
38    }
39
40    function isAnyProgram(program: Program | EmitAndSemanticDiagnosticsBuilderProgram | ParsedCommandLine): program is Program | EmitAndSemanticDiagnosticsBuilderProgram {
41        return !!(program as Program | EmitAndSemanticDiagnosticsBuilderProgram).getCompilerOptions;
42    }
43    export function commandLineCallbacks(
44        sys: System & { writtenFiles: ReadonlyCollection<string>; },
45        originalReadCall?: System["readFile"]
46    ): CommandLineCallbacks {
47        let programs: CommandLineProgram[] | undefined;
48
49        return {
50            cb: program => {
51                if (isAnyProgram(program)) {
52                    baselineBuildInfo(program.getCompilerOptions(), sys, originalReadCall);
53                    (programs || (programs = [])).push(isBuilderProgram(program) ?
54                        [program.getProgram(), program] :
55                        [program]
56                    );
57                }
58                else {
59                    baselineBuildInfo(program.options, sys, originalReadCall);
60                }
61            },
62            getPrograms: () => {
63                const result = programs || emptyArray;
64                programs = undefined;
65                return result;
66            }
67        };
68    }
69
70    export function tscCompile(input: TscCompile) {
71        const initialFs = input.fs();
72        const inputFs = initialFs.shadow();
73        const {
74            scenario, subScenario, buildKind,
75            commandLineArgs, modifyFs,
76            baselineSourceMap, baselineReadFileCalls, baselinePrograms
77        } = input;
78        if (modifyFs) modifyFs(inputFs);
79        inputFs.makeReadonly();
80        const fs = inputFs.shadow();
81
82        // Create system
83        const sys = new fakes.System(fs, { executingFilePath: "/lib/tsc" }) as TscCompileSystem;
84        fakes.patchHostForBuildInfoReadWrite(sys);
85        const writtenFiles = sys.writtenFiles = new Set<string>();
86        const originalWriteFile = sys.writeFile;
87        sys.writeFile = (fileName, content, writeByteOrderMark) => {
88            assert.isFalse(writtenFiles.has(fileName));
89            writtenFiles.add(fileName);
90            return originalWriteFile.call(sys, fileName, content, writeByteOrderMark);
91        };
92        const actualReadFileMap: MapLike<number> = {};
93        const originalReadFile = sys.readFile;
94        sys.readFile = path => {
95            // Dont record libs
96            if (path.startsWith("/src/")) {
97                actualReadFileMap[path] = (getProperty(actualReadFileMap, path) || 0) + 1;
98            }
99            return originalReadFile.call(sys, path);
100        };
101
102        sys.write(`${sys.getExecutingFilePath()} ${commandLineArgs.join(" ")}\n`);
103        sys.exit = exitCode => sys.exitCode = exitCode;
104        const { cb, getPrograms } = commandLineCallbacks(sys, originalReadFile);
105        executeCommandLine(
106            sys,
107            cb,
108            commandLineArgs,
109        );
110        sys.write(`exitCode:: ExitStatus.${ExitStatus[sys.exitCode as ExitStatus]}\n`);
111        if (baselinePrograms) {
112            const baseline: string[] = [];
113            tscWatch.baselinePrograms(baseline, getPrograms);
114            sys.write(baseline.join("\n"));
115        }
116        if (baselineReadFileCalls) {
117            sys.write(`readFiles:: ${JSON.stringify(actualReadFileMap, /*replacer*/ undefined, " ")} `);
118        }
119        if (baselineSourceMap) generateSourceMapBaselineFiles(sys);
120
121        fs.makeReadonly();
122
123        sys.baseLine = () => {
124            const baseFsPatch = !buildKind || buildKind === BuildKind.Initial ?
125                inputFs.diff(/*base*/ undefined, { baseIsNotShadowRoot: true }) :
126                inputFs.diff(initialFs, { includeChangedFileWithSameContent: true });
127            const patch = fs.diff(inputFs, { includeChangedFileWithSameContent: true });
128            return {
129                file: `${isBuild(commandLineArgs) ? "tsbuild" : "tsc"}/${scenario}/${buildKind || BuildKind.Initial}/${subScenario.split(" ").join("-")}.js`,
130                text: `Input::
131${baseFsPatch ? vfs.formatPatch(baseFsPatch) : ""}
132
133Output::
134${sys.output.join("")}
135
136${patch ? vfs.formatPatch(patch) : ""}`
137            };
138        };
139        return sys;
140    }
141
142    export function verifyTscBaseline(sys: () => { baseLine: TscCompileSystem["baseLine"]; }) {
143        it(`Generates files matching the baseline`, () => {
144            const { file, text } = sys().baseLine();
145            Harness.Baseline.runBaseline(file, text);
146        });
147    }
148
149    export function verifyTsc(input: TscCompile) {
150        describe(`tsc ${input.commandLineArgs.join(" ")} ${input.scenario}:: ${input.subScenario}`, () => {
151            describe(input.scenario, () => {
152                describe(input.subScenario, () => {
153                    let sys: TscCompileSystem;
154                    before(() => {
155                        sys = tscCompile({
156                            ...input,
157                            fs: () => getFsWithTime(input.fs()).fs.makeReadonly()
158                        });
159                    });
160                    after(() => {
161                        sys = undefined!;
162                    });
163                    verifyTscBaseline(() => sys);
164                });
165            });
166        });
167    }
168}
169