mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-30 11:24:49 -05:00
Handle seenEmittedFiles which was not being set when emit of a file was complete (#33145)
* Add test that fails because file is written multiple times Reported from #33061 * Handle seenEmittedFiles which was not being set when emit of a file was complete. It was issue only when errors are reported before emitting (which puts the files into pendingEmit that needs to check only in seenEmittedFiles) If emit happens before semantic diagnostics query this issue is not repro, because the affected files come into play and those are being set correctly Fixes #31398 * make baselining source map optional * Handle emitDeclarationOnly in --build scenario * Ensure we are using d.ts emit as signature even when --declarationMap is on (map files are emitted before d.ts) * Move module specifiers to verifyTsBuildOutput * implement create Hash to be default hashing plus data so we can verify it easily in baseline * Remove failing baseline * Accept correct baseline name
This commit is contained in:
@@ -94,6 +94,7 @@
|
||||
"unittests/tsbuild/amdModulesWithOut.ts",
|
||||
"unittests/tsbuild/containerOnlyReferenced.ts",
|
||||
"unittests/tsbuild/demo.ts",
|
||||
"unittests/tsbuild/emitDeclarationOnly.ts",
|
||||
"unittests/tsbuild/emptyFiles.ts",
|
||||
"unittests/tsbuild/graphOrdering.ts",
|
||||
"unittests/tsbuild/inferredTypeFromTransitiveModule.ts",
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace ts {
|
||||
[outputFiles[project.lib][ext.buildinfo], outputFiles[project.lib][ext.js], outputFiles[project.lib][ext.dts]],
|
||||
[outputFiles[project.app][ext.buildinfo], outputFiles[project.app][ext.js], outputFiles[project.app][ext.dts]]
|
||||
],
|
||||
lastProjectOutputJs: outputFiles[project.app][ext.js],
|
||||
lastProjectOutput: outputFiles[project.app][ext.js],
|
||||
initialBuild: {
|
||||
modifyFs
|
||||
},
|
||||
@@ -231,7 +231,7 @@ ${internal} export enum internalEnum { a, b, c }`);
|
||||
[libOutputFile[ext.buildinfo], libOutputFile[ext.js], libOutputFile[ext.dts]],
|
||||
[outputFiles[project.app][ext.buildinfo], outputFiles[project.app][ext.js], outputFiles[project.app][ext.dts]]
|
||||
],
|
||||
lastProjectOutputJs: outputFiles[project.app][ext.js],
|
||||
lastProjectOutput: outputFiles[project.app][ext.js],
|
||||
initialBuild: {
|
||||
modifyFs,
|
||||
expectedDiagnostics: [
|
||||
|
||||
109
src/testRunner/unittests/tsbuild/emitDeclarationOnly.ts
Normal file
109
src/testRunner/unittests/tsbuild/emitDeclarationOnly.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
namespace ts {
|
||||
describe("unittests:: tsbuild:: on project with emitDeclarationOnly set to true", () => {
|
||||
let projFs: vfs.FileSystem;
|
||||
const { time, tick } = getTime();
|
||||
before(() => {
|
||||
projFs = loadProjectFromDisk("tests/projects/emitDeclarationOnly", time);
|
||||
});
|
||||
after(() => {
|
||||
projFs = undefined!;
|
||||
});
|
||||
|
||||
function verifyEmitDeclarationOnly(disableMap?: true) {
|
||||
verifyTsbuildOutput({
|
||||
scenario: `only dts output in circular import project with emitDeclarationOnly${disableMap ? "" : " and declarationMap"}`,
|
||||
projFs: () => projFs,
|
||||
time,
|
||||
tick,
|
||||
proj: "emitDeclarationOnly",
|
||||
rootNames: ["/src"],
|
||||
lastProjectOutput: `/src/lib/index.d.ts`,
|
||||
outputFiles: [
|
||||
"/src/lib/a.d.ts",
|
||||
"/src/lib/b.d.ts",
|
||||
"/src/lib/c.d.ts",
|
||||
"/src/lib/index.d.ts",
|
||||
"/src/tsconfig.tsbuildinfo",
|
||||
...(disableMap ? emptyArray : [
|
||||
"/src/lib/a.d.ts.map",
|
||||
"/src/lib/b.d.ts.map",
|
||||
"/src/lib/c.d.ts.map",
|
||||
"/src/lib/index.d.ts.map"
|
||||
])
|
||||
],
|
||||
initialBuild: {
|
||||
modifyFs: disableMap ?
|
||||
(fs => replaceText(fs, "/src/tsconfig.json", `"declarationMap": true,`, "")) :
|
||||
noop,
|
||||
expectedDiagnostics: [
|
||||
getExpectedDiagnosticForProjectsInBuild("src/tsconfig.json"),
|
||||
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/tsconfig.json", "src/lib/a.d.ts"],
|
||||
[Diagnostics.Building_project_0, "/src/tsconfig.json"]
|
||||
]
|
||||
},
|
||||
incrementalDtsChangedBuild: {
|
||||
modifyFs: fs => replaceText(fs, "/src/src/a.ts", "b: B;", "b: B; foo: any;"),
|
||||
expectedDiagnostics: [
|
||||
getExpectedDiagnosticForProjectsInBuild("src/tsconfig.json"),
|
||||
[Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, "src/tsconfig.json", "src/lib/a.d.ts", "src/src/a.ts"],
|
||||
[Diagnostics.Building_project_0, "/src/tsconfig.json"]
|
||||
]
|
||||
},
|
||||
baselineOnly: true,
|
||||
verifyDiagnostics: true
|
||||
});
|
||||
}
|
||||
verifyEmitDeclarationOnly();
|
||||
verifyEmitDeclarationOnly(/*disableMap*/ true);
|
||||
|
||||
verifyTsbuildOutput({
|
||||
scenario: `only dts output in non circular imports project with emitDeclarationOnly`,
|
||||
projFs: () => projFs,
|
||||
time,
|
||||
tick,
|
||||
proj: "emitDeclarationOnly",
|
||||
rootNames: ["/src"],
|
||||
lastProjectOutput: `/src/lib/a.d.ts`,
|
||||
outputFiles: [
|
||||
"/src/lib/a.d.ts",
|
||||
"/src/lib/b.d.ts",
|
||||
"/src/lib/c.d.ts",
|
||||
"/src/tsconfig.tsbuildinfo",
|
||||
"/src/lib/a.d.ts.map",
|
||||
"/src/lib/b.d.ts.map",
|
||||
"/src/lib/c.d.ts.map",
|
||||
],
|
||||
initialBuild: {
|
||||
modifyFs: fs => {
|
||||
fs.rimrafSync("/src/src/index.ts");
|
||||
replaceText(fs, "/src/src/a.ts", `import { B } from "./b";`, `export class B { prop = "hello"; }`);
|
||||
},
|
||||
expectedDiagnostics: [
|
||||
getExpectedDiagnosticForProjectsInBuild("src/tsconfig.json"),
|
||||
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/tsconfig.json", "src/lib/a.d.ts"],
|
||||
[Diagnostics.Building_project_0, "/src/tsconfig.json"]
|
||||
]
|
||||
},
|
||||
incrementalDtsChangedBuild: {
|
||||
modifyFs: fs => replaceText(fs, "/src/src/a.ts", "b: B;", "b: B; foo: any;"),
|
||||
expectedDiagnostics: [
|
||||
getExpectedDiagnosticForProjectsInBuild("src/tsconfig.json"),
|
||||
[Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, "src/tsconfig.json", "src/lib/a.d.ts", "src/src/a.ts"],
|
||||
[Diagnostics.Building_project_0, "/src/tsconfig.json"]
|
||||
]
|
||||
},
|
||||
incrementalDtsUnchangedBuild: {
|
||||
modifyFs: fs => replaceText(fs, "/src/src/a.ts", "export interface A {", `class C { }
|
||||
export interface A {`),
|
||||
expectedDiagnostics: [
|
||||
getExpectedDiagnosticForProjectsInBuild("src/tsconfig.json"),
|
||||
[Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, "src/tsconfig.json", "src/lib/a.d.ts", "src/src/a.ts"],
|
||||
[Diagnostics.Building_project_0, "/src/tsconfig.json"],
|
||||
[Diagnostics.Updating_unchanged_output_timestamps_of_project_0, "/src/tsconfig.json"]
|
||||
]
|
||||
},
|
||||
baselineOnly: true,
|
||||
verifyDiagnostics: true
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -102,7 +102,22 @@ namespace ts {
|
||||
interface ReadonlyArray<T> {}
|
||||
declare const console: { log(msg: any): void; };`;
|
||||
|
||||
export function loadProjectFromDisk(root: string, time?: vfs.FileSystemOptions["time"]): vfs.FileSystem {
|
||||
export const symbolLibContent = `
|
||||
interface SymbolConstructor {
|
||||
readonly species: symbol;
|
||||
readonly toStringTag: symbol;
|
||||
}
|
||||
declare var Symbol: SymbolConstructor;
|
||||
interface Symbol {
|
||||
readonly [Symbol.toStringTag]: string;
|
||||
}
|
||||
`;
|
||||
|
||||
export function loadProjectFromDisk(
|
||||
root: string,
|
||||
time?: vfs.FileSystemOptions["time"],
|
||||
libContentToAppend?: string
|
||||
): vfs.FileSystem {
|
||||
const resolver = vfs.createResolver(Harness.IO);
|
||||
const fs = new vfs.FileSystem(/*ignoreCase*/ true, {
|
||||
files: {
|
||||
@@ -112,12 +127,31 @@ declare const console: { log(msg: any): void; };`;
|
||||
meta: { defaultLibLocation: "/lib" },
|
||||
time
|
||||
});
|
||||
fs.mkdirSync("/lib");
|
||||
fs.writeFileSync("/lib/lib.d.ts", libContent);
|
||||
fs.makeReadonly();
|
||||
addLibAndMakeReadonly(fs, libContentToAppend);
|
||||
return fs;
|
||||
}
|
||||
|
||||
export function loadProjectFromFiles(
|
||||
files: vfs.FileSet,
|
||||
time?: vfs.FileSystemOptions["time"],
|
||||
libContentToAppend?: string
|
||||
): vfs.FileSystem {
|
||||
const fs = new vfs.FileSystem(/*ignoreCase*/ true, {
|
||||
files,
|
||||
cwd: "/",
|
||||
meta: { defaultLibLocation: "/lib" },
|
||||
time
|
||||
});
|
||||
addLibAndMakeReadonly(fs, libContentToAppend);
|
||||
return fs;
|
||||
}
|
||||
|
||||
function addLibAndMakeReadonly(fs: vfs.FileSystem, libContentToAppend?: string) {
|
||||
fs.mkdirSync("/lib");
|
||||
fs.writeFileSync("/lib/lib.d.ts", libContentToAppend ? `${libContent}${libContentToAppend}` : libContent);
|
||||
fs.makeReadonly();
|
||||
}
|
||||
|
||||
export function verifyOutputsPresent(fs: vfs.FileSystem, outputs: readonly string[]) {
|
||||
for (const output of outputs) {
|
||||
assert(fs.existsSync(output), `Expect file ${output} to exist`);
|
||||
@@ -199,7 +233,7 @@ declare const console: { log(msg: any): void; };`;
|
||||
fs: vfs.FileSystem;
|
||||
tick: () => void;
|
||||
rootNames: ReadonlyArray<string>;
|
||||
expectedMapFileNames: ReadonlyArray<string>;
|
||||
expectedMapFileNames?: ReadonlyArray<string>;
|
||||
expectedBuildInfoFilesForSectionBaselines?: ReadonlyArray<BuildInfoSectionBaselineFiles>;
|
||||
modifyFs: (fs: vfs.FileSystem) => void;
|
||||
}
|
||||
@@ -221,7 +255,7 @@ declare const console: { log(msg: any): void; };`;
|
||||
return originalReadFile.call(host, path);
|
||||
};
|
||||
builder.build();
|
||||
generateSourceMapBaselineFiles(fs, expectedMapFileNames);
|
||||
if (expectedMapFileNames) generateSourceMapBaselineFiles(fs, expectedMapFileNames);
|
||||
generateBuildInfoSectionBaselineFiles(fs, expectedBuildInfoFilesForSectionBaselines || emptyArray);
|
||||
fs.makeReadonly();
|
||||
return { fs, actualReadFileMap, host, builder };
|
||||
@@ -268,9 +302,10 @@ Mismatch Actual(path, actual, expected): ${JSON.stringify(arrayFrom(mapDefinedIt
|
||||
tick: () => void;
|
||||
proj: string;
|
||||
rootNames: ReadonlyArray<string>;
|
||||
expectedMapFileNames: ReadonlyArray<string>;
|
||||
/** map file names to generate baseline of */
|
||||
expectedMapFileNames?: ReadonlyArray<string>;
|
||||
expectedBuildInfoFilesForSectionBaselines?: ReadonlyArray<BuildInfoSectionBaselineFiles>;
|
||||
lastProjectOutputJs: string;
|
||||
lastProjectOutput: string;
|
||||
initialBuild: BuildState;
|
||||
outputFiles?: ReadonlyArray<string>;
|
||||
incrementalDtsChangedBuild?: BuildState;
|
||||
@@ -282,7 +317,7 @@ Mismatch Actual(path, actual, expected): ${JSON.stringify(arrayFrom(mapDefinedIt
|
||||
|
||||
export function verifyTsbuildOutput({
|
||||
scenario, projFs, time, tick, proj, rootNames, outputFiles, baselineOnly, verifyDiagnostics,
|
||||
expectedMapFileNames, expectedBuildInfoFilesForSectionBaselines, lastProjectOutputJs,
|
||||
expectedMapFileNames, expectedBuildInfoFilesForSectionBaselines, lastProjectOutput,
|
||||
initialBuild, incrementalDtsChangedBuild, incrementalDtsUnchangedBuild, incrementalHeaderChangedBuild
|
||||
}: VerifyTsBuildInput) {
|
||||
describe(`tsc --b ${proj}:: ${scenario}`, () => {
|
||||
@@ -331,7 +366,7 @@ Mismatch Actual(path, actual, expected): ${JSON.stringify(arrayFrom(mapDefinedIt
|
||||
let beforeBuildTime: number;
|
||||
let afterBuildTime: number;
|
||||
before(() => {
|
||||
beforeBuildTime = fs.statSync(lastProjectOutputJs).mtimeMs;
|
||||
beforeBuildTime = fs.statSync(lastProjectOutput).mtimeMs;
|
||||
tick();
|
||||
newFs = fs.shadow();
|
||||
tick();
|
||||
@@ -343,7 +378,7 @@ Mismatch Actual(path, actual, expected): ${JSON.stringify(arrayFrom(mapDefinedIt
|
||||
expectedBuildInfoFilesForSectionBaselines,
|
||||
modifyFs: incrementalModifyFs,
|
||||
}));
|
||||
afterBuildTime = newFs.statSync(lastProjectOutputJs).mtimeMs;
|
||||
afterBuildTime = newFs.statSync(lastProjectOutput).mtimeMs;
|
||||
});
|
||||
after(() => {
|
||||
newFs = undefined!;
|
||||
@@ -359,6 +394,12 @@ Mismatch Actual(path, actual, expected): ${JSON.stringify(arrayFrom(mapDefinedIt
|
||||
host.assertDiagnosticMessages(...(incrementalExpectedDiagnostics || emptyArray));
|
||||
});
|
||||
}
|
||||
else {
|
||||
// Build should pass without errors if not verifying diagnostics
|
||||
it(`verify no errors`, () => {
|
||||
host.assertErrors(/*empty*/);
|
||||
});
|
||||
}
|
||||
it(`Generates files matching the baseline`, () => {
|
||||
generateBaseline(newFs, proj, scenario, subScenario, fs);
|
||||
});
|
||||
@@ -373,7 +414,6 @@ Mismatch Actual(path, actual, expected): ${JSON.stringify(arrayFrom(mapDefinedIt
|
||||
fs: newFs.shadow(),
|
||||
tick,
|
||||
rootNames,
|
||||
expectedMapFileNames: emptyArray,
|
||||
modifyFs: fs => {
|
||||
// Delete output files
|
||||
for (const outputFile of expectedOutputFiles) {
|
||||
|
||||
@@ -16,8 +16,7 @@ namespace ts {
|
||||
tick,
|
||||
proj: "inferredTypeFromTransitiveModule",
|
||||
rootNames: ["/src"],
|
||||
expectedMapFileNames: emptyArray,
|
||||
lastProjectOutputJs: `/src/obj/index.js`,
|
||||
lastProjectOutput: `/src/obj/index.js`,
|
||||
outputFiles: [
|
||||
"/src/obj/bar.js", "/src/obj/bar.d.ts",
|
||||
"/src/obj/bundling.js", "/src/obj/bundling.d.ts",
|
||||
|
||||
@@ -16,8 +16,7 @@ namespace ts {
|
||||
tick,
|
||||
proj: "lateBoundSymbol",
|
||||
rootNames: ["/src/tsconfig.json"],
|
||||
expectedMapFileNames: emptyArray,
|
||||
lastProjectOutputJs: "/src/src/main.js",
|
||||
lastProjectOutput: "/src/src/main.js",
|
||||
outputFiles: [
|
||||
"/src/src/hkt.js",
|
||||
"/src/src/main.js",
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
namespace ts {
|
||||
// https://github.com/microsoft/TypeScript/issues/31696
|
||||
it("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers to referenced projects resolve correctly", () => {
|
||||
const baseFs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, {
|
||||
files: {
|
||||
describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers to referenced projects resolve correctly", () => {
|
||||
let projFs: vfs.FileSystem;
|
||||
const { time, tick } = getTime();
|
||||
before(() => {
|
||||
projFs = loadProjectFromFiles({
|
||||
"/src/common/nominal.ts": utils.dedent`
|
||||
export declare type Nominal<T, Name extends string> = T & {
|
||||
[Symbol.species]: Name;
|
||||
@@ -71,7 +73,6 @@ namespace ts {
|
||||
"skipLibCheck": true,
|
||||
"rootDir": "./",
|
||||
"outDir": "lib",
|
||||
"lib": ["dom", "es2015", "es2015.symbol.wellknown"]
|
||||
}
|
||||
}`,
|
||||
"/tsconfig.json": utils.dedent`{
|
||||
@@ -83,16 +84,23 @@ namespace ts {
|
||||
],
|
||||
"include": []
|
||||
}`
|
||||
},
|
||||
cwd: "/"
|
||||
}, time, symbolLibContent);
|
||||
});
|
||||
after(() => {
|
||||
projFs = undefined!;
|
||||
});
|
||||
verifyTsbuildOutput({
|
||||
scenario: `synthesized module specifiers resolve correctly`,
|
||||
projFs: () => projFs,
|
||||
time,
|
||||
tick,
|
||||
proj: "moduleSpecifiers",
|
||||
rootNames: ["/"],
|
||||
lastProjectOutput: `/src/lib/index.d.ts`,
|
||||
initialBuild: {
|
||||
modifyFs: noop,
|
||||
},
|
||||
baselineOnly: true
|
||||
});
|
||||
const fs = baseFs.makeReadonly().shadow();
|
||||
const sys = new fakes.System(fs, { executingFilePath: "/", newLine: "\n" });
|
||||
const host = new fakes.SolutionBuilderHost(sys);
|
||||
const builder = createSolutionBuilder(host, ["/tsconfig.json"], { dry: false, force: false, verbose: false });
|
||||
builder.build();
|
||||
|
||||
// Prior to fixing GH31696 the import in `/lib/src/sub-project-2/index.d.ts` was `import("../../lib/src/common/nonterminal")`, which was invalid.
|
||||
Harness.Baseline.runBaseline("tsbuild/moduleSpecifiers/initial-build/resolves-correctly.js", vfs.formatPatch(fs.diff(baseFs)));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ namespace ts {
|
||||
rootNames: ["/src/third"],
|
||||
expectedMapFileNames,
|
||||
expectedBuildInfoFilesForSectionBaselines: expectedBuildInfoFilesForSectionBaselines || expectedTsbuildInfoFileNames,
|
||||
lastProjectOutputJs: outputFiles[project.third][ext.js],
|
||||
lastProjectOutput: outputFiles[project.third][ext.js],
|
||||
initialBuild: {
|
||||
modifyFs,
|
||||
expectedDiagnostics: initialExpectedDiagnostics,
|
||||
|
||||
@@ -617,7 +617,7 @@ export class cNew {}`);
|
||||
"/src/core/index.d.ts.map",
|
||||
"/src/logic/index.js.map"
|
||||
],
|
||||
lastProjectOutputJs: "/src/tests/index.js",
|
||||
lastProjectOutput: "/src/tests/index.js",
|
||||
initialBuild,
|
||||
incrementalDtsChangedBuild: {
|
||||
modifyFs: fs => appendText(fs, "/src/core/index.ts", `
|
||||
@@ -727,7 +727,7 @@ class someClass { }`),
|
||||
"/src/core/index.d.ts.map",
|
||||
"/src/logic/index.js.map"
|
||||
],
|
||||
lastProjectOutputJs: "/src/tests/index.js",
|
||||
lastProjectOutput: "/src/tests/index.js",
|
||||
initialBuild,
|
||||
incrementalDtsChangedBuild: {
|
||||
modifyFs: fs => replaceText(fs, "/src/logic/tsconfig.json", `"declaration": true,`, `"declaration": true,
|
||||
@@ -795,7 +795,7 @@ class someClass { }`),
|
||||
"/src/core/index.d.ts.map",
|
||||
"/src/logic/index.js.map"
|
||||
],
|
||||
lastProjectOutputJs: "/src/tests/index.js",
|
||||
lastProjectOutput: "/src/tests/index.js",
|
||||
initialBuild: {
|
||||
modifyFs: fs => replaceText(fs, "/src/logic/tsconfig.json", `"composite": true,`, `"composite": true,
|
||||
"tsBuildInfoFile": "ownFile.tsbuildinfo",`),
|
||||
@@ -851,8 +851,7 @@ class someClass { }`),
|
||||
tick,
|
||||
proj: "sample1",
|
||||
rootNames: ["/src/core"],
|
||||
expectedMapFileNames: emptyArray,
|
||||
lastProjectOutputJs: "/src/core/index.js",
|
||||
lastProjectOutput: "/src/core/index.js",
|
||||
initialBuild: {
|
||||
modifyFs: fs => fs.writeFileSync("/src/core/tsconfig.json", `{
|
||||
"compilerOptions": {
|
||||
@@ -892,8 +891,7 @@ class someClass { }`),
|
||||
tick,
|
||||
proj: "sample1",
|
||||
rootNames: ["/src/core"],
|
||||
expectedMapFileNames: emptyArray,
|
||||
lastProjectOutputJs: "/src/core/index.js",
|
||||
lastProjectOutput: "/src/core/index.js",
|
||||
initialBuild: {
|
||||
modifyFs: fs => {
|
||||
fs.writeFileSync("/lib/lib.esnext.full.d.ts", `/// <reference no-default-lib="true"/>
|
||||
@@ -942,8 +940,7 @@ class someClass { }`),
|
||||
tick,
|
||||
proj: "sample1",
|
||||
rootNames: ["/src/core"],
|
||||
expectedMapFileNames: emptyArray,
|
||||
lastProjectOutputJs: "/src/core/index.js",
|
||||
lastProjectOutput: "/src/core/index.js",
|
||||
initialBuild: {
|
||||
modifyFs: fs => fs.writeFileSync("/src/core/tsconfig.json", `{
|
||||
"compilerOptions": {
|
||||
@@ -981,8 +978,7 @@ class someClass { }`),
|
||||
tick,
|
||||
proj: "sample1",
|
||||
rootNames: ["/src/tests"],
|
||||
expectedMapFileNames: emptyArray,
|
||||
lastProjectOutputJs: "/src/tests/index.js",
|
||||
lastProjectOutput: "/src/tests/index.js",
|
||||
initialBuild: {
|
||||
modifyFs: fs => fs.writeFileSync("/src/tests/tsconfig.json", `{
|
||||
"references": [
|
||||
|
||||
@@ -16,17 +16,17 @@ namespace ts.tscWatch {
|
||||
expectedIncrementalEmit?: ReadonlyArray<File>;
|
||||
expectedIncrementalErrors?: ReadonlyArray<string>;
|
||||
}
|
||||
function verifyIncrementalWatchEmit(input: VerifyIncrementalWatchEmitInput) {
|
||||
function verifyIncrementalWatchEmit(input: () => VerifyIncrementalWatchEmitInput) {
|
||||
it("with tsc --w", () => {
|
||||
verifyIncrementalWatchEmitWorker({
|
||||
input,
|
||||
input: input(),
|
||||
emitAndReportErrors: createWatchOfConfigFile,
|
||||
verifyErrors: checkOutputErrorsInitial
|
||||
});
|
||||
});
|
||||
it("with tsc", () => {
|
||||
verifyIncrementalWatchEmitWorker({
|
||||
input,
|
||||
input: input(),
|
||||
emitAndReportErrors: incrementalBuild,
|
||||
verifyErrors: checkNormalBuildErrors
|
||||
});
|
||||
@@ -122,7 +122,7 @@ namespace ts.tscWatch {
|
||||
|
||||
function checkFileEmit(actual: Map<string>, expected: ReadonlyArray<File>) {
|
||||
assert.equal(actual.size, expected.length, `Actual: ${JSON.stringify(arrayFrom(actual.entries()), /*replacer*/ undefined, " ")}\nExpected: ${JSON.stringify(expected, /*replacer*/ undefined, " ")}`);
|
||||
expected.forEach(file => {
|
||||
for (const file of expected) {
|
||||
let expectedContent = file.content;
|
||||
let actualContent = actual.get(file.path);
|
||||
if (isBuildInfoFile(file.path)) {
|
||||
@@ -130,7 +130,7 @@ namespace ts.tscWatch {
|
||||
expectedContent = sanitizeBuildInfo(expectedContent);
|
||||
}
|
||||
assert.equal(actualContent, expectedContent, `Emit for ${file.path}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const libFileInfo: BuilderState.FileInfo = {
|
||||
@@ -170,7 +170,7 @@ namespace ts.tscWatch {
|
||||
describe("own file emit without errors", () => {
|
||||
function verify(optionsToExtend?: CompilerOptions, expectedBuildinfoOptions?: CompilerOptions) {
|
||||
const modifiedFile2Content = file2.content.replace("y", "z").replace("20", "10");
|
||||
verifyIncrementalWatchEmit({
|
||||
verifyIncrementalWatchEmit(() => ({
|
||||
files: [libFile, file1, file2, configFile],
|
||||
optionsToExtend,
|
||||
expectedInitialEmit: [
|
||||
@@ -226,7 +226,7 @@ namespace ts.tscWatch {
|
||||
}
|
||||
],
|
||||
expectedIncrementalErrors: emptyArray,
|
||||
});
|
||||
}));
|
||||
}
|
||||
verify();
|
||||
describe("with commandline parameters that are not relative", () => {
|
||||
@@ -259,7 +259,7 @@ namespace ts.tscWatch {
|
||||
"file2.ts(1,7): error TS2322: Type '20' is not assignable to type 'string'.\n"
|
||||
];
|
||||
const modifiedFile1Content = file1.content.replace("x", "z");
|
||||
verifyIncrementalWatchEmit({
|
||||
verifyIncrementalWatchEmit(() => ({
|
||||
files: [libFile, file1, fileModified, configFile],
|
||||
expectedInitialEmit: [
|
||||
file1Js,
|
||||
@@ -320,7 +320,7 @@ namespace ts.tscWatch {
|
||||
}
|
||||
],
|
||||
expectedIncrementalErrors: file2Errors,
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe("with --out", () => {
|
||||
@@ -332,7 +332,7 @@ namespace ts.tscWatch {
|
||||
path: `${project}/out.js`,
|
||||
content: "var x = 10;\nvar y = 20;\n"
|
||||
};
|
||||
verifyIncrementalWatchEmit({
|
||||
verifyIncrementalWatchEmit(() => ({
|
||||
files: [libFile, file1, file2, config],
|
||||
expectedInitialEmit: [
|
||||
outFile,
|
||||
@@ -353,7 +353,7 @@ namespace ts.tscWatch {
|
||||
}
|
||||
],
|
||||
expectedInitialErrors: emptyArray
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
});
|
||||
@@ -397,7 +397,7 @@ namespace ts.tscWatch {
|
||||
|
||||
describe("own file emit without errors", () => {
|
||||
const modifiedFile2Content = file2.content.replace("y", "z").replace("20", "10");
|
||||
verifyIncrementalWatchEmit({
|
||||
verifyIncrementalWatchEmit(() => ({
|
||||
files: [libFile, file1, file2, config],
|
||||
expectedInitialEmit: [
|
||||
file1Js,
|
||||
@@ -451,7 +451,7 @@ namespace ts.tscWatch {
|
||||
}
|
||||
],
|
||||
expectedIncrementalErrors: emptyArray,
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe("own file emit with errors", () => {
|
||||
@@ -479,7 +479,7 @@ namespace ts.tscWatch {
|
||||
"file2.ts(1,14): error TS2322: Type '20' is not assignable to type 'string'.\n"
|
||||
];
|
||||
const modifiedFile1Content = file1.content.replace("x = 10", "z = 10");
|
||||
verifyIncrementalWatchEmit({
|
||||
verifyIncrementalWatchEmit(() => ({
|
||||
files: [libFile, file1, fileModified, config],
|
||||
expectedInitialEmit: [
|
||||
file1Js,
|
||||
@@ -541,7 +541,7 @@ namespace ts.tscWatch {
|
||||
}
|
||||
],
|
||||
expectedIncrementalErrors: file2Errors,
|
||||
});
|
||||
}));
|
||||
|
||||
it("verify that state is read correctly", () => {
|
||||
const system = createWatchedSystem([libFile, file1, fileModified, config], { currentDirectory: project });
|
||||
@@ -604,7 +604,7 @@ namespace ts.tscWatch {
|
||||
});
|
||||
`;
|
||||
}
|
||||
verifyIncrementalWatchEmit({
|
||||
verifyIncrementalWatchEmit(() => ({
|
||||
files: [libFile, file1, file2, config],
|
||||
expectedInitialEmit: [
|
||||
outFile,
|
||||
@@ -625,7 +625,140 @@ namespace ts.tscWatch {
|
||||
}
|
||||
],
|
||||
expectedInitialErrors: emptyArray
|
||||
});
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("incremental with circular references", () => {
|
||||
function getFileInfo(content: string): BuilderState.FileInfo {
|
||||
const signature = Harness.mockHash(content);
|
||||
return { version: signature, signature };
|
||||
}
|
||||
const config: File = {
|
||||
path: configFile.path,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
incremental: true,
|
||||
target: "es5",
|
||||
module: "commonjs",
|
||||
declaration: true,
|
||||
emitDeclarationOnly: true
|
||||
}
|
||||
})
|
||||
};
|
||||
const aTs: File = {
|
||||
path: `${project}/a.ts`,
|
||||
content: `import { B } from "./b";
|
||||
export interface A {
|
||||
b: B;
|
||||
}
|
||||
`
|
||||
};
|
||||
const bTs: File = {
|
||||
path: `${project}/b.ts`,
|
||||
content: `import { C } from "./c";
|
||||
export interface B {
|
||||
b: C;
|
||||
}
|
||||
`
|
||||
};
|
||||
const cTs: File = {
|
||||
path: `${project}/c.ts`,
|
||||
content: `import { A } from "./a";
|
||||
export interface C {
|
||||
a: A;
|
||||
}
|
||||
`
|
||||
};
|
||||
const indexTs: File = {
|
||||
path: `${project}/index.ts`,
|
||||
content: `export { A } from "./a";
|
||||
export { B } from "./b";
|
||||
export { C } from "./c";
|
||||
`
|
||||
};
|
||||
|
||||
verifyIncrementalWatchEmit(() => {
|
||||
const referencedMap: MapLike<string[]> = {
|
||||
"./a.ts": ["./b.ts"],
|
||||
"./b.ts": ["./c.ts"],
|
||||
"./c.ts": ["./a.ts"],
|
||||
"./index.ts": ["./a.ts", "./b.ts", "./c.ts"],
|
||||
};
|
||||
const initialProgram: ProgramBuildInfo = {
|
||||
fileInfos: {
|
||||
[libFilePath]: libFileInfo,
|
||||
"./c.ts": getFileInfo(cTs.content),
|
||||
"./b.ts": getFileInfo(bTs.content),
|
||||
"./a.ts": getFileInfo(aTs.content),
|
||||
"./index.ts": getFileInfo(indexTs.content)
|
||||
},
|
||||
options: {
|
||||
incremental: true,
|
||||
target: ScriptTarget.ES5,
|
||||
module: ModuleKind.CommonJS,
|
||||
declaration: true,
|
||||
emitDeclarationOnly: true,
|
||||
configFilePath: "./tsconfig.json"
|
||||
},
|
||||
referencedMap,
|
||||
exportedModulesMap: referencedMap,
|
||||
semanticDiagnosticsPerFile: [
|
||||
libFilePath,
|
||||
"./a.ts",
|
||||
"./b.ts",
|
||||
"./c.ts",
|
||||
"./index.ts",
|
||||
]
|
||||
};
|
||||
const { fileInfos, ...rest } = initialProgram;
|
||||
const expectedADts: File = { path: `${project}/a.d.ts`, content: aTs.content };
|
||||
const expectedBDts: File = { path: `${project}/b.d.ts`, content: bTs.content };
|
||||
const expectedCDts: File = { path: `${project}/c.d.ts`, content: cTs.content };
|
||||
const expectedIndexDts: File = { path: `${project}/index.d.ts`, content: indexTs.content };
|
||||
const modifiedATsContent = aTs.content.replace("b: B;", `b: B;
|
||||
foo: any;`);
|
||||
return {
|
||||
files: [libFile, aTs, bTs, cTs, indexTs, config],
|
||||
expectedInitialEmit: [
|
||||
expectedADts,
|
||||
expectedBDts,
|
||||
expectedCDts,
|
||||
expectedIndexDts,
|
||||
{
|
||||
path: `${project}/tsconfig.tsbuildinfo`,
|
||||
content: getBuildInfoText({
|
||||
program: initialProgram,
|
||||
version
|
||||
})
|
||||
}
|
||||
],
|
||||
expectedInitialErrors: emptyArray,
|
||||
modifyFs: host => host.writeFile(aTs.path, modifiedATsContent),
|
||||
expectedIncrementalEmit: [
|
||||
{ path: expectedADts.path, content: modifiedATsContent },
|
||||
expectedBDts,
|
||||
expectedCDts,
|
||||
expectedIndexDts,
|
||||
{
|
||||
path: `${project}/tsconfig.tsbuildinfo`,
|
||||
content: getBuildInfoText({
|
||||
program: {
|
||||
fileInfos: {
|
||||
[libFilePath]: libFileInfo,
|
||||
"./c.ts": getFileInfo(cTs.content),
|
||||
"./b.ts": getFileInfo(bTs.content),
|
||||
"./a.ts": getFileInfo(modifiedATsContent),
|
||||
"./index.ts": getFileInfo(indexTs.content)
|
||||
},
|
||||
...rest
|
||||
},
|
||||
version
|
||||
})
|
||||
}
|
||||
],
|
||||
expectedIncrementalErrors: emptyArray
|
||||
};
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user