Testing WIP
This commit is contained in:
parent
7e0825a3e7
commit
6d04378e90
|
@ -1073,6 +1073,7 @@ namespace ts {
|
|||
_fs.utimesSync(path, time, time);
|
||||
}
|
||||
catch (e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1081,6 +1082,7 @@ namespace ts {
|
|||
return _fs.unlinkSync(path);
|
||||
}
|
||||
catch (e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace ts {
|
|||
* The primary thing we track here is which files were written to,
|
||||
* but unchanged, because this enables fast downstream updates
|
||||
*/
|
||||
interface BuildContext {
|
||||
export interface BuildContext {
|
||||
options: BuildOptions;
|
||||
/**
|
||||
* Map from output file name to its pre-build timestamp
|
||||
|
@ -299,6 +299,9 @@ namespace ts {
|
|||
|
||||
function parseConfigFile(configFilePath: string) {
|
||||
const sourceFile = host.getSourceFile(configFilePath, ScriptTarget.JSON) as JsonSourceFile;
|
||||
if (sourceFile === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const parsed = parseJsonSourceFileConfigFileContent(sourceFile, configParseHost, getDirectoryPath(configFilePath));
|
||||
parsed.options.configFilePath = configFilePath;
|
||||
cache.setValue(configFilePath, parsed);
|
||||
|
@ -322,7 +325,7 @@ namespace ts {
|
|||
return fileExtensionIs(fileName, ".d.ts");
|
||||
}
|
||||
|
||||
function createBuildContext(options: BuildOptions): BuildContext {
|
||||
export function createBuildContext(options: BuildOptions): BuildContext {
|
||||
const verboseDiag = options.verbose && createDiagnosticReporter(sys, /*pretty*/ false);
|
||||
return {
|
||||
options,
|
||||
|
@ -334,18 +337,15 @@ namespace ts {
|
|||
};
|
||||
}
|
||||
|
||||
export function performBuild(args: string[]) {
|
||||
const diagReporter = createDiagnosticReporter(sys, /*pretty*/true);
|
||||
const host = createCompilerHost({});
|
||||
|
||||
export function performBuild(host: CompilerHost, reportDiagnostic: DiagnosticReporter, args: string[]) {
|
||||
let verbose = false;
|
||||
let dry = false;
|
||||
let force = false;
|
||||
let clean = false;
|
||||
|
||||
const projects: string[] = [];
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
switch (args[i].toLowerCase()) {
|
||||
for (const arg of args) {
|
||||
switch (arg.toLowerCase()) {
|
||||
case "-v":
|
||||
case "--verbose":
|
||||
verbose = true;
|
||||
|
@ -363,7 +363,7 @@ namespace ts {
|
|||
continue;
|
||||
}
|
||||
// Not a flag, parse as filename
|
||||
addProject(args[i]);
|
||||
addProject(arg);
|
||||
}
|
||||
|
||||
if (projects.length === 0) {
|
||||
|
@ -372,7 +372,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
const context = createBuildContext({ verbose, dry, force });
|
||||
const builder = createSolutionBuilder(host, context);
|
||||
const builder = createSolutionBuilder(host, reportDiagnostic, context);
|
||||
if (clean) {
|
||||
builder.cleanProjects(projects);
|
||||
}
|
||||
|
@ -384,15 +384,14 @@ namespace ts {
|
|||
const fileName = resolvePath(host.getCurrentDirectory(), projectSpecification);
|
||||
const refPath = resolveProjectReferencePath(host, { path: fileName });
|
||||
if (!host.fileExists(refPath)) {
|
||||
diagReporter(createCompilerDiagnostic(Diagnostics.File_0_does_not_exist, fileName));
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.File_0_does_not_exist, fileName));
|
||||
}
|
||||
projects.push(refPath);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export function createSolutionBuilder(host: CompilerHost, context: BuildContext) {
|
||||
const diagReporter = createDiagnosticReporter(sys, /*pretty*/true);
|
||||
export function createSolutionBuilder(host: CompilerHost, reportDiagnostic: DiagnosticReporter, context: BuildContext) {
|
||||
const configFileCache = createConfigFileCache(host);
|
||||
|
||||
return {
|
||||
|
@ -418,7 +417,7 @@ namespace ts {
|
|||
else {
|
||||
const outputs: string[] = [];
|
||||
for (const inputFile of project.fileNames) {
|
||||
(outputs as string[]).push(...getOutputFileNames(inputFile, project));
|
||||
outputs.push(...getOutputFileNames(inputFile, project));
|
||||
}
|
||||
return outputs;
|
||||
}
|
||||
|
@ -553,7 +552,8 @@ namespace ts {
|
|||
for (const root of roots) {
|
||||
const config = configFileCache.parseConfigFile(root);
|
||||
if (config === undefined) {
|
||||
throw new Error(`Could not parse ${root}`);
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.File_0_does_not_exist, root));
|
||||
continue;
|
||||
}
|
||||
enumerateReferences(normalizePath(root), config);
|
||||
}
|
||||
|
@ -564,7 +564,7 @@ namespace ts {
|
|||
dependencyMap
|
||||
};
|
||||
|
||||
function enumerateReferences(fileName: string, root: ts.ParsedCommandLine): void {
|
||||
function enumerateReferences(fileName: string, root: ParsedCommandLine): void {
|
||||
const myBuildLevel = buildQueue[buildQueuePosition] = buildQueue[buildQueuePosition] || [];
|
||||
if (myBuildLevel.indexOf(fileName) < 0) {
|
||||
myBuildLevel.push(fileName);
|
||||
|
@ -605,7 +605,7 @@ namespace ts {
|
|||
// TODO Accept parsedCommandLine
|
||||
function buildSingleProject(proj: string) {
|
||||
if (context.options.dry) {
|
||||
diagReporter(createCompilerDiagnostic(Diagnostics.Would_build_project_0, proj));
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Would_build_project_0, proj));
|
||||
}
|
||||
|
||||
context.verbose(Diagnostics.Building_project_0, proj);
|
||||
|
@ -627,18 +627,18 @@ namespace ts {
|
|||
|
||||
const programOptions: CreateProgramOptions = {
|
||||
projectReferences: configFile.projectReferences,
|
||||
host: host,
|
||||
host,
|
||||
rootNames: configFile.fileNames,
|
||||
options: configFile.options
|
||||
};
|
||||
const program = ts.createProgram(programOptions);
|
||||
const program = createProgram(programOptions);
|
||||
|
||||
// Don't emit anything in the presence of syntactic errors or options diagnostics
|
||||
const syntaxDiagnostics = [...program.getOptionsDiagnostics(), ...program.getSyntacticDiagnostics()];
|
||||
if (syntaxDiagnostics.length) {
|
||||
resultFlags |= BuildResultFlags.SyntaxErrors;
|
||||
for (const diag of syntaxDiagnostics) {
|
||||
diagReporter(diag);
|
||||
reportDiagnostic(diag);
|
||||
}
|
||||
return resultFlags;
|
||||
}
|
||||
|
@ -649,7 +649,7 @@ namespace ts {
|
|||
if (declDiagnostics.length) {
|
||||
resultFlags |= BuildResultFlags.DeclarationEmitErrors;
|
||||
for (const diag of declDiagnostics) {
|
||||
diagReporter(diag);
|
||||
reportDiagnostic(diag);
|
||||
}
|
||||
return resultFlags;
|
||||
}
|
||||
|
@ -659,13 +659,13 @@ namespace ts {
|
|||
if (semanticDiagnostics.length) {
|
||||
resultFlags |= BuildResultFlags.TypeErrors;
|
||||
for (const diag of semanticDiagnostics) {
|
||||
diagReporter(diag);
|
||||
reportDiagnostic(diag);
|
||||
}
|
||||
return resultFlags;
|
||||
}
|
||||
|
||||
let newestDeclarationFileContentChangedTime = minimumDate;
|
||||
program.emit(undefined, (fileName, content, writeBom, onError) => {
|
||||
program.emit(/*targetSourceFile*/ undefined, (fileName, content, writeBom, onError) => {
|
||||
let priorChangeTime: Date | undefined;
|
||||
|
||||
if (isDeclarationFile(fileName) && host.fileExists(fileName)) {
|
||||
|
@ -690,7 +690,7 @@ namespace ts {
|
|||
|
||||
function updateOutputTimestamps(proj: ParsedCommandLine) {
|
||||
if (context.options.dry) {
|
||||
diagReporter(createCompilerDiagnostic(Diagnostics.Would_build_project_0, proj.options.configFilePath));
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Would_build_project_0, proj.options.configFilePath));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -731,13 +731,29 @@ namespace ts {
|
|||
}
|
||||
|
||||
if (context.options.dry) {
|
||||
diagReporter(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, fileReport.map(f => `\r\n * ${f}`).join("")));
|
||||
}
|
||||
}
|
||||
|
||||
function buildProjects(configFileNames: string[]) {
|
||||
const resolvedNames: string[] = [];
|
||||
for (const name of configFileNames) {
|
||||
let fullPath = resolvePath(host.getCurrentDirectory(), name);
|
||||
if (host.fileExists(fullPath)) {
|
||||
resolvedNames.push(fullPath);
|
||||
continue;
|
||||
}
|
||||
fullPath = combinePaths(fullPath, "tsconfig.json");
|
||||
if (host.fileExists(fullPath)) {
|
||||
resolvedNames.push(fullPath);
|
||||
continue;
|
||||
}
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.File_0_not_found, fullPath));
|
||||
return;
|
||||
}
|
||||
|
||||
// Establish what needs to be built
|
||||
const graph = createDependencyGraph(configFileNames);
|
||||
const graph = createDependencyGraph(resolvedNames);
|
||||
|
||||
const queue = graph.buildQueue;
|
||||
reportBuildQueue(graph);
|
||||
|
|
|
@ -48,9 +48,9 @@ namespace ts {
|
|||
|
||||
export function executeCommandLine(args: string[]): void {
|
||||
if ((args[0].toLowerCase() === "--build") || (args[0].toLowerCase() === "-b")) {
|
||||
return performBuild(args.slice(1));
|
||||
return performBuild(createCompilerHost({}), createDiagnosticReporter(sys), args.slice(1));
|
||||
}
|
||||
|
||||
|
||||
const commandLine = parseCommandLine(args);
|
||||
|
||||
// Configuration file name (if any)
|
||||
|
|
|
@ -131,6 +131,10 @@ namespace fakes {
|
|||
return stats ? stats.mtime : undefined;
|
||||
}
|
||||
|
||||
public setModifiedTime(path: string, time: Date) {
|
||||
this.vfs.utimesSync(path, time, time);
|
||||
}
|
||||
|
||||
public createHash(data: string): string {
|
||||
return data;
|
||||
}
|
||||
|
@ -252,6 +256,14 @@ namespace fakes {
|
|||
return this.sys.directoryExists(directoryName);
|
||||
}
|
||||
|
||||
public getModifiedTime(fileName: string) {
|
||||
return this.sys.getModifiedTime(fileName);
|
||||
}
|
||||
|
||||
public setModifiedTime(fileName: string, time: Date) {
|
||||
return this.sys.setModifiedTime(fileName, time);
|
||||
}
|
||||
|
||||
public getDirectories(path: string): string[] {
|
||||
return this.sys.getDirectories(path);
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
"../compiler/builder.ts",
|
||||
"../compiler/resolutionCache.ts",
|
||||
"../compiler/watch.ts",
|
||||
"../compiler/tsbuild.ts",
|
||||
"../compiler/commandLineParser.ts",
|
||||
|
||||
"../services/types.ts",
|
||||
|
|
71
src/harness/unittests/tsbuild.ts
Normal file
71
src/harness/unittests/tsbuild.ts
Normal file
|
@ -0,0 +1,71 @@
|
|||
/// <reference path="../vfs.ts" />
|
||||
|
||||
namespace ts {
|
||||
let currentTime = 100;
|
||||
const bfs = new vfs.FileSystem(/*ignoreCase*/ false, { time });
|
||||
const lastDiagnostics: Diagnostic[] = [];
|
||||
const reportDiagnostic: DiagnosticReporter = diagnostic => lastDiagnostics.push(diagnostic);
|
||||
|
||||
const sampleRoot = resolvePath(__dirname, "../../tests/projects/sample1");
|
||||
loadFsMirror(bfs, sampleRoot, "/src");
|
||||
bfs.mkdirpSync("/lib");
|
||||
bfs.writeFileSync("/lib/lib.d.ts", Harness.IO.readFile(combinePaths(Harness.libFolder, "lib.d.ts")));
|
||||
bfs.meta.set("defaultLibLocation", "/lib");
|
||||
bfs.makeReadonly();
|
||||
|
||||
describe("tsbuild tests", () => {
|
||||
it("builds the referenced project", () => {
|
||||
const fs = bfs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, reportDiagnostic, createBuildContext({ dry: false, force: false, verbose: false }));
|
||||
|
||||
fs.chdir("/src/tests");
|
||||
fs.debugPrint();
|
||||
builder.buildProjects(["."]);
|
||||
printDiagnostics();
|
||||
fs.debugPrint();
|
||||
assertDiagnosticMessages(Diagnostics.File_0_does_not_exist);
|
||||
|
||||
tick();
|
||||
});
|
||||
});
|
||||
|
||||
function assertDiagnosticMessages(...expected: DiagnosticMessage[]) {
|
||||
const actual = lastDiagnostics.slice();
|
||||
actual.sort((a, b) => b.code - a.code);
|
||||
expected.sort((a, b) => b.code - a.code);
|
||||
if (actual.length !== expected.length) {
|
||||
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - expected ${actual.join(",")}, got ${expected.join(",")}`);
|
||||
}
|
||||
for (let i = 0; i < actual.length; i++) {
|
||||
if (actual[i].code !== expected[i].code) {
|
||||
assert.fail(actual[i].messageText, expected[i].message, "Mismatched error code");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function printDiagnostics() {
|
||||
const out = createDiagnosticReporter(sys);
|
||||
for (const d of lastDiagnostics) {
|
||||
out(d);
|
||||
}
|
||||
}
|
||||
|
||||
function tick() {
|
||||
currentTime += 10;
|
||||
}
|
||||
function time() {
|
||||
return currentTime;
|
||||
}
|
||||
|
||||
function loadFsMirror(vfs: vfs.FileSystem, localRoot: string, virtualRoot: string) {
|
||||
vfs.mkdirpSync(virtualRoot);
|
||||
for (const path of Harness.IO.readDirectory(localRoot)) {
|
||||
const file = getBaseFileName(path);
|
||||
vfs.writeFileSync(virtualRoot + "/" + file, Harness.IO.readFile(localRoot + "/" + file));
|
||||
}
|
||||
for (const dir of Harness.IO.getDirectories(localRoot)){
|
||||
loadFsMirror(vfs, localRoot + "/" + dir, virtualRoot + "/" + dir);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,11 @@ namespace vfs {
|
|||
*/
|
||||
export const builtFolder = "/.ts";
|
||||
|
||||
/**
|
||||
* Posix-style path to additional mountable folders (./tests/projects in this repo)
|
||||
*/
|
||||
export const projectsFolder = "/.projects";
|
||||
|
||||
/**
|
||||
* Posix-style path to additional test libraries
|
||||
*/
|
||||
|
@ -404,7 +409,18 @@ namespace vfs {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get file status.
|
||||
* Change file access times
|
||||
*
|
||||
* NOTE: do not rename this method as it is intended to align with the same named export of the "fs" module.
|
||||
*/
|
||||
public utimesSync(path: string, atime: Date, mtime: Date) {
|
||||
const entry = this._walk(this._resolve(path));
|
||||
entry.node.atimeMs = +atime;
|
||||
entry.node.mtimeMs = +mtime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file status. If `path` is a symbolic link, it is dereferenced.
|
||||
*
|
||||
* @link http://pubs.opengroup.org/onlinepubs/9699919799/functions/lstat.html
|
||||
*
|
||||
|
@ -414,6 +430,7 @@ namespace vfs {
|
|||
return this._stat(this._walk(this._resolve(path), /*noFollow*/ true));
|
||||
}
|
||||
|
||||
|
||||
private _stat(entry: WalkResult) {
|
||||
const node = entry.node;
|
||||
if (!node) throw createIOError("ENOENT");
|
||||
|
@ -1282,6 +1299,7 @@ namespace vfs {
|
|||
files: {
|
||||
[builtFolder]: new Mount(vpath.resolve(host.getWorkspaceRoot(), "built/local"), resolver),
|
||||
[testLibFolder]: new Mount(vpath.resolve(host.getWorkspaceRoot(), "tests/lib"), resolver),
|
||||
[projectsFolder]: new Mount(vpath.resolve(host.getWorkspaceRoot(), "tests/projects"), resolver),
|
||||
[srcFolder]: {}
|
||||
},
|
||||
cwd: srcFolder,
|
||||
|
|
2
tests/projects/sample1/core/index.ts
Normal file
2
tests/projects/sample1/core/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export function leftPad(s: string, n: number) { return s + n; }
|
||||
export function multiply(a: number, b: number) { return a * b; }
|
3
tests/projects/sample1/core/tsconfig.json
Normal file
3
tests/projects/sample1/core/tsconfig.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
|
||||
}
|
4
tests/projects/sample1/logic/index.ts
Normal file
4
tests/projects/sample1/logic/index.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
import * as c from '../core';
|
||||
export function getSecondsInDay() {
|
||||
return c.multiply(10, 15);
|
||||
}
|
5
tests/projects/sample1/logic/tsconfig.json
Normal file
5
tests/projects/sample1/logic/tsconfig.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"references": [
|
||||
{ "path": "../core" }
|
||||
]
|
||||
}
|
5
tests/projects/sample1/tests/index.ts
Normal file
5
tests/projects/sample1/tests/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import * as c from '../core';
|
||||
import * as logic from '../logic';
|
||||
|
||||
c.leftPad("", 10);
|
||||
logic.getSecondsInDay();
|
6
tests/projects/sample1/tests/tsconfig.json
Normal file
6
tests/projects/sample1/tests/tsconfig.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"references": [
|
||||
{ "path": "../core" },
|
||||
{ "path": "../logic" }
|
||||
]
|
||||
}
|
5
tests/projects/sample1/ui/index.ts
Normal file
5
tests/projects/sample1/ui/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import * as logic from '../logic';
|
||||
|
||||
export function run() {
|
||||
console.log(logic.getSecondsInDay());
|
||||
}
|
5
tests/projects/sample1/ui/tsconfig.json
Normal file
5
tests/projects/sample1/ui/tsconfig.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"references": [
|
||||
{ "path": "../logic" }
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue