mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-19 00:42:28 -05:00
WIP
This commit is contained in:
@@ -3634,6 +3634,10 @@
|
||||
"category": "Message",
|
||||
"code": 6359
|
||||
},
|
||||
"Project '{0}' is up to date": {
|
||||
"category": "Message",
|
||||
"code": 6360
|
||||
},
|
||||
|
||||
"Variable '{0}' implicitly has an '{1}' type.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -608,10 +608,11 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Accept parsedCommandLine
|
||||
// TODO Accept parsedCommandLine instead?
|
||||
function buildSingleProject(proj: string) {
|
||||
if (context.options.dry) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Would_build_project_0, proj));
|
||||
return;
|
||||
}
|
||||
|
||||
context.verbose(Diagnostics.Building_project_0, proj);
|
||||
@@ -714,34 +715,47 @@ namespace ts {
|
||||
context.projectStatus.setValue(proj.options.configFilePath, { type: UpToDateStatusType.UpToDate, newestDeclarationFileContentChangedTime: priorNewestUpdateTime } as UpToDateStatus);
|
||||
}
|
||||
|
||||
function cleanProjects(configFileNames: string[]) {
|
||||
// Get the same graph for cleaning we'd use for building
|
||||
const graph = createDependencyGraph(configFileNames);
|
||||
function getFilesToClean(configFileNames: string[]): string[] | undefined {
|
||||
const resolvedNames: string[] | undefined = resolveProjectNames(configFileNames);
|
||||
if (resolvedNames === undefined) return;
|
||||
|
||||
const fileReport: string[] = [];
|
||||
// Get the same graph for cleaning we'd use for building
|
||||
const graph = createDependencyGraph(resolvedNames);
|
||||
|
||||
const filesToDelete: string[] = [];
|
||||
for (const level of graph.buildQueue) {
|
||||
for (const proj of level) {
|
||||
const parsed = configFileCache.parseConfigFile(proj);
|
||||
const outputs = getAllProjectOutputs(parsed);
|
||||
for (const output of outputs) {
|
||||
if (host.fileExists(output)) {
|
||||
if (context.options.dry) {
|
||||
fileReport.push(output);
|
||||
}
|
||||
else {
|
||||
host.deleteFile(output);
|
||||
}
|
||||
filesToDelete.push(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return filesToDelete;
|
||||
}
|
||||
|
||||
function cleanProjects(configFileNames: string[]) {
|
||||
const filesToDelete = getFilesToClean(configFileNames);
|
||||
|
||||
if (context.options.dry) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Would_delete_the_following_files_Colon_0, fileReport.map(f => `\r\n * ${f}`).join("")));
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Would_delete_the_following_files_Colon_0, filesToDelete.map(f => `\r\n * ${f}`).join("")));
|
||||
}
|
||||
else {
|
||||
if (!host.deleteFile) {
|
||||
throw new Error("Host does not support deleting files");
|
||||
}
|
||||
|
||||
for (const output of filesToDelete) {
|
||||
host.deleteFile(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildProjects(configFileNames: string[]) {
|
||||
// TODO add branding to resolved filenames
|
||||
function resolveProjectNames(configFileNames: string[]): string[] | undefined {
|
||||
const resolvedNames: string[] = [];
|
||||
for (const name of configFileNames) {
|
||||
let fullPath = resolvePath(host.getCurrentDirectory(), name);
|
||||
@@ -755,8 +769,14 @@ namespace ts {
|
||||
continue;
|
||||
}
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.File_0_not_found, fullPath));
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
return resolvedNames;
|
||||
}
|
||||
|
||||
function buildProjects(configFileNames: string[]) {
|
||||
const resolvedNames: string[] | undefined = resolveProjectNames(configFileNames);
|
||||
if (resolvedNames === undefined) return;
|
||||
|
||||
// Establish what needs to be built
|
||||
const graph = createDependencyGraph(resolvedNames);
|
||||
@@ -772,6 +792,10 @@ namespace ts {
|
||||
|
||||
if (status.type === UpToDateStatusType.UpToDate && !context.options.force) {
|
||||
// Up to date, skip
|
||||
if (options.dry) {
|
||||
// In a dry build, inform the user of this fact
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Project_0_is_up_to_date));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,10 @@ namespace fakes {
|
||||
this.vfs.writeFileSync(path, writeByteOrderMark ? utils.addUTF8ByteOrderMark(data) : data);
|
||||
}
|
||||
|
||||
public deleteFile(path: string) {
|
||||
this.vfs.unlinkSync(path);
|
||||
}
|
||||
|
||||
public fileExists(path: string) {
|
||||
const stats = this._getStats(path);
|
||||
return stats ? stats.isFile() : false;
|
||||
@@ -248,6 +252,10 @@ namespace fakes {
|
||||
return this.sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
}
|
||||
|
||||
public deleteFile(fileName: string) {
|
||||
this.sys.deleteFile(fileName);
|
||||
}
|
||||
|
||||
public fileExists(fileName: string): boolean {
|
||||
return this.sys.fileExists(fileName);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ namespace ts {
|
||||
bfs.meta.set("defaultLibLocation", "/lib");
|
||||
bfs.makeReadonly();
|
||||
tick();
|
||||
const allExpectedOutputs = ["/src/tests/index.js",
|
||||
"/src/core/index.js", "/src/core/index.d.ts",
|
||||
"/src/logic/index.js", "/src/logic/index.d.ts"];
|
||||
|
||||
describe("tsbuild - sanity check of clean build of 'sample1' project", () => {
|
||||
it("can build the sample project 'sample1' without error", () => {
|
||||
@@ -23,13 +26,95 @@ namespace ts {
|
||||
assertDiagnosticMessages(/*empty*/);
|
||||
|
||||
// Check for outputs. Not an exhaustive list
|
||||
const expectedOutputs = ["/src/tests/index.js", "/src/core/index.js", "/src/core/index.d.ts"];
|
||||
for (const output of expectedOutputs) {
|
||||
for (const output of allExpectedOutputs) {
|
||||
assert(fs.existsSync(output), `Expect file ${output} to exist`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsbuild - dry builds", () => {
|
||||
it("doesn't write any files in a dry build", () => {
|
||||
clearDiagnostics();
|
||||
const fs = bfs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, reportDiagnostic, { dry: true, force: false, verbose: false });
|
||||
fs.chdir("/src/tests");
|
||||
builder.buildProjects(["."]);
|
||||
assertDiagnosticMessages(Diagnostics.Would_build_project_0, Diagnostics.Would_build_project_0, Diagnostics.Would_build_project_0);
|
||||
|
||||
// Check for outputs to not be written. Not an exhaustive list
|
||||
for (const output of allExpectedOutputs) {
|
||||
assert(!fs.existsSync(output), `Expect file ${output} to not exist`);
|
||||
}
|
||||
});
|
||||
|
||||
it("indicates that it would skip builds during a dry build", () => {
|
||||
clearDiagnostics();
|
||||
const fs = bfs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
|
||||
let builder = createSolutionBuilder(host, reportDiagnostic, { dry: false, force: false, verbose: false });
|
||||
fs.chdir("/src/tests");
|
||||
builder.buildProjects(["."]);
|
||||
tick();
|
||||
|
||||
clearDiagnostics();
|
||||
builder = createSolutionBuilder(host, reportDiagnostic, { dry: true, force: false, verbose: false });
|
||||
builder.buildProjects(["."]);
|
||||
assertDiagnosticMessages(Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date);
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsbuild - clean builds", () => {
|
||||
it("removes all files it built", () => {
|
||||
clearDiagnostics();
|
||||
const fs = bfs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
|
||||
const builder = createSolutionBuilder(host, reportDiagnostic, { dry: false, force: false, verbose: false });
|
||||
fs.chdir("/src/tests");
|
||||
builder.buildProjects(["."]);
|
||||
// Verify they exist
|
||||
for (const output of allExpectedOutputs) {
|
||||
assert(fs.existsSync(output), `Expect file ${output} to exist`);
|
||||
}
|
||||
builder.cleanProjects(["."]);
|
||||
// Verify they are gone
|
||||
for (const output of allExpectedOutputs) {
|
||||
assert(!fs.existsSync(output), `Expect file ${output} to not exist`);
|
||||
}
|
||||
// Subsequent clean shouldn't throw / etc
|
||||
builder.cleanProjects(["."]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsbuild - force builds", () => {
|
||||
it("always builds under --force", () => {
|
||||
const fs = bfs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
|
||||
const builder = createSolutionBuilder(host, reportDiagnostic, { dry: false, force: true, verbose: false });
|
||||
fs.chdir("/src/tests");
|
||||
builder.buildProjects(["."]);
|
||||
let currentTime = time();
|
||||
checkOutputTimestamps(currentTime);
|
||||
|
||||
tick();
|
||||
Debug.assert(time() !== currentTime, "Time moves on");
|
||||
currentTime = time();
|
||||
builder.buildProjects(["."]);
|
||||
checkOutputTimestamps(currentTime);
|
||||
|
||||
function checkOutputTimestamps(expected: number) {
|
||||
// Check timestamps
|
||||
for (const output of allExpectedOutputs) {
|
||||
const actual = fs.statSync(output).mtimeMs;
|
||||
assert(actual === expected, `File ${output} has timestamp ${actual}, expected ${expected}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsbuild - can detect when and what to rebuild", () => {
|
||||
const fs = bfs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
@@ -38,6 +123,7 @@ namespace ts {
|
||||
fs.chdir("/src/tests");
|
||||
|
||||
it("Builds the project", () => {
|
||||
clearDiagnostics();
|
||||
builder.resetBuildContext();
|
||||
builder.buildProjects(["."]);
|
||||
assertDiagnosticMessages(Diagnostics.Sorted_list_of_input_projects_Colon_0,
|
||||
|
||||
Reference in New Issue
Block a user