Merge pull request #25250 from Microsoft/gulpTypeScriptReporter

Report errors in corrrect process for gulp-typescript-oop
This commit is contained in:
Ron Buckton 2018-06-26 16:04:28 -07:00 committed by GitHub
commit f4a2ee456d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 586 additions and 222 deletions

View file

@ -46,7 +46,7 @@ const produceLKGJs = "scripts/produceLKG.js";
const word2mdJs = "scripts/word2md.js";
gulp.task("scripts", /*help*/ false, () => project.compile(scriptsProject), {
aliases: [
configurePrereleaseJs,
configurePrereleaseJs,
processDiagnosticMessagesJs,
generateLocalizedDiagnosticMessagesJs,
produceLKGJs,
@ -134,10 +134,11 @@ gulp.task(generatedLCGFile, /*help*/ false, [generateLocalizedDiagnosticMessages
gulp.task("localize", /*help*/ false, [generatedLCGFile]);
const servicesProject = "src/services/tsconfig.json";
const typescriptServicesProject = "built/local/typescriptServices.tsconfig.json";
gulp.task(typescriptServicesProject, /*help*/ false, () => {
// NOTE: flatten services so that we can properly strip @internal
project.flatten("src/services/tsconfig.json", typescriptServicesProject, {
project.flatten(servicesProject, typescriptServicesProject, {
compilerOptions: {
"removeComments": true,
"stripInternal": true,
@ -148,7 +149,7 @@ gulp.task(typescriptServicesProject, /*help*/ false, () => {
const typescriptServicesJs = "built/local/typescriptServices.js";
const typescriptServicesDts = "built/local/typescriptServices.d.ts";
gulp.task(typescriptServicesJs, /*help*/ false, ["lib", "generate-diagnostics", typescriptServicesProject], () =>
gulp.task(typescriptServicesJs, /*help*/ false, ["lib", "generate-diagnostics", typescriptServicesProject], () =>
project.compile(typescriptServicesProject, { dts: files => files.pipe(convertConstEnums()) }),
{ aliases: [typescriptServicesDts] });
@ -225,7 +226,7 @@ gulp.task(tsserverlibraryProject, /*help*/ false, () => {
const tsserverlibraryJs = "built/local/tsserverlibrary.js";
const tsserverlibraryDts = "built/local/tsserverlibrary.d.ts";
gulp.task(tsserverlibraryJs, /*help*/ false, [typescriptServicesJs, tsserverlibraryProject], () =>
project.compile(tsserverlibraryProject, {
project.compile(tsserverlibraryProject, {
dts: files => files
.pipe(convertConstEnums())
.pipe(append("\nexport = ts;\nexport as namespace ts;")),
@ -253,21 +254,21 @@ gulp.task(specMd, /*help*/ false, [word2mdJs], () =>
exec("cscript", ["//nologo", word2mdJs, path.resolve(specMd), path.resolve("doc/TypeScript Language Specification.docx")]));
gulp.task(
"generate-spec",
"Generates a Markdown version of the Language Specification",
"generate-spec",
"Generates a Markdown version of the Language Specification",
[specMd]);
gulp.task("produce-LKG", /*help*/ false, ["scripts", "local", cancellationTokenJs, typingsInstallerJs, watchGuardJs, tscReleaseJs], () => {
const expectedFiles = [
tscReleaseJs,
typescriptServicesJs,
tsserverJs,
typescriptJs,
typescriptDts,
typescriptServicesDts,
tsserverlibraryDts,
tsserverlibraryDts,
typingsInstallerJs,
tscReleaseJs,
typescriptServicesJs,
tsserverJs,
typescriptJs,
typescriptDts,
typescriptServicesDts,
tsserverlibraryDts,
tsserverlibraryDts,
typingsInstallerJs,
cancellationTokenJs
].concat(libraryTargets);
const missingFiles = expectedFiles
@ -286,8 +287,8 @@ gulp.task("produce-LKG", /*help*/ false, ["scripts", "local", cancellationTokenJ
});
gulp.task(
"LKG",
"Makes a new LKG out of the built js files",
"LKG",
"Makes a new LKG out of the built js files",
() => runSequence("clean-built", "produce-LKG"));
// Task to build the tests infrastructure using the built compiler
@ -464,12 +465,40 @@ gulp.task(
"Runs 'local'",
["local"]);
gulp.task(
"watch-diagnostics",
/*help*/ false,
[processDiagnosticMessagesJs],
() => gulp.watch([diagnosticMessagesJson], [diagnosticInformationMapTs, builtGeneratedDiagnosticMessagesJson]));
gulp.task(
"watch-lib",
/*help*/ false,
() => gulp.watch(["src/lib/**/*"], ["lib"]));
gulp.task(
"watch-tsc",
"Watches for changes to the build inputs for built/local/tsc.js",
[typescriptServicesJs],
/*help*/ false,
["watch-diagnostics", "watch-lib", typescriptServicesJs],
() => project.watch(tscProject, { typescript: "built" }));
gulp.task(
"watch-services",
/*help*/ false,
["watch-diagnostics", "watch-lib", typescriptServicesJs],
() => project.watch(servicesProject, { typescript: "built" }));
gulp.task(
"watch-server",
/*help*/ false,
["watch-diagnostics", "watch-lib", typescriptServicesJs],
() => project.watch(tsserverProject, { typescript: "built" }));
gulp.task(
"watch-local",
/*help*/ false,
["watch-lib", "watch-tsc", "watch-services", "watch-server"]);
gulp.task(
"watch",
"Watches for changes to the build inputs for built/local/run.js executes runtests-parallel.",

6
package-lock.json generated
View file

@ -5801,9 +5801,9 @@
"dev": true
},
"typescript": {
"version": "3.0.0-dev.20180609",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.0.0-dev.20180609.tgz",
"integrity": "sha512-bqO5mSGbxZoiY/9Y1bnnU36dC5CfnrA9I9WKf3QB0qMuJakoofO2DNTDRwsypyhCThlNtF2Ls/OMj3Txglu4Xg==",
"version": "3.0.0-dev.20180626",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.0.0-dev.20180626.tgz",
"integrity": "sha512-OQH9osIC4CdsVzVvsb2RenRTVPRKwSIMIpRy2J42XNOEUP+vhX56BX1Z47K3l//LEGY0xG7zF7qVKCDlUhhrlg==",
"dev": true
},
"uglify-js": {

View file

@ -1,91 +0,0 @@
// @ts-check
const path = require("path");
const child_process = require("child_process");
const tsc = require("gulp-typescript");
const Vinyl = require("vinyl");
const { Duplex, Readable } = require("stream");
/**
* @param {string | undefined} tsConfigFileName
* @param {tsc.Settings} settings
* @param {Object} options
* @param {string} [options.typescript]
*/
function createProject(tsConfigFileName, settings, options) {
settings = Object.assign({}, settings);
options = Object.assign({}, options);
if (settings.typescript) throw new Error();
const localSettings = Object.assign({}, settings);
if (options.typescript) {
options.typescript = path.resolve(options.typescript);
localSettings.typescript = require(options.typescript);
}
const project = tsConfigFileName === undefined ? tsc.createProject(localSettings) : tsc.createProject(tsConfigFileName, localSettings);
const wrappedProject = /** @type {tsc.Project} */(() => {
const proc = child_process.fork(require.resolve("./main.js"), [], {
// Prevent errors when debugging gulpfile due to the same debug port being passed to forked children.
execArgv: []
});
/** @type {Duplex & { js?: Readable, dts?: Readable }} */
const compileStream = new Duplex({
objectMode: true,
read() {},
/** @param {*} file */
write(file, _encoding, callback) {
proc.send({ method: "write", params: { path: file.path, cwd: file.cwd, base: file.base, sourceMap: file.sourceMap }});
callback();
},
final(callback) {
proc.send({ method: "final" });
callback();
}
});
const jsStream = compileStream.js = new Readable({
objectMode: true,
read() {}
});
const dtsStream = compileStream.dts = new Readable({
objectMode: true,
read() {}
});
proc.send({ method: "createProject", params: { tsConfigFileName, settings, options } });
proc.on("message", ({ method, params }) => {
if (method === "write") {
const file = new Vinyl({
path: params.path,
cwd: params.cwd,
base: params.base,
contents: Buffer.from(params.contents, "utf8")
});
if (params.sourceMap) file.sourceMap = params.sourceMap
compileStream.push(file);;
if (file.path.endsWith(".d.ts")) {
dtsStream.push(file);
}
else {
jsStream.push(file);
}
}
else if (method === "final") {
compileStream.push(null);
jsStream.push(null);
dtsStream.push(null);
proc.kill();
}
else if (method === "error") {
const error = new Error();
error.name = params.name;
error.message = params.message;
error.stack = params.stack;
compileStream.emit("error", error);
proc.kill();
}
});
return /** @type {*} */(compileStream);
});
return Object.assign(wrappedProject, project);
}
exports.createProject = createProject;

View file

@ -0,0 +1,145 @@
// @ts-check
const path = require("path");
const child_process = require("child_process");
const tsc = require("gulp-typescript");
const Vinyl = require("vinyl");
const { Duplex, Readable } = require("stream");
const protocol = require("./protocol");
/**
* @param {string | undefined} tsConfigFileName
* @param {tsc.Settings} settings
* @param {CreateProjectOptions} options
*
* @typedef CreateProjectOptions
* @property {string} [typescript]
* @property {boolean} [parse]
*/
function createProject(tsConfigFileName, settings, options) {
settings = Object.assign({}, settings);
options = Object.assign({}, options);
if (settings.typescript) throw new Error();
const localSettings = Object.assign({}, settings);
if (options.typescript) {
options.typescript = path.resolve(options.typescript);
localSettings.typescript = require(options.typescript);
}
const project = tsConfigFileName === undefined ? tsc.createProject(localSettings) : tsc.createProject(tsConfigFileName, localSettings);
const wrappedProject = /** @type {tsc.Project} */((reporter = tsc.reporter.defaultReporter()) => {
const ts = project.typescript;
const proc = child_process.fork(require.resolve("./worker.js"), [], {
// Prevent errors when debugging gulpfile due to the same debug port being passed to forked children.
execArgv: []
});
/** @type {Map<string, import("vinyl")>} */
const inputs = new Map();
/** @type {Map<string, *>} */
const sourceFiles = new Map();
/** @type {protocol.SourceFileHost & protocol.VinylHost} */
const host = {
getVinyl(path) { return inputs.get(path); },
getSourceFile(fileName) { return sourceFiles.get(fileName); },
createSourceFile(fileName, text, languageVersion) {
if (text === undefined) throw new Error("File not cached.");
/** @type {protocol.SourceFile} */
let file;
if (options.parse) {
file = ts.createSourceFile(fileName, text, languageVersion, /*setParentNodes*/ true);
}
else {
// NOTE: the built-in reporters in gulp-typescript don't actually need a full
// source file, so save time by faking one unless requested.
file = /**@type {protocol.SourceFile}*/({
pos: 0,
end: text.length,
kind: ts.SyntaxKind.SourceFile,
fileName,
text,
languageVersion,
statements: /**@type {*} */([]),
endOfFileToken: { pos: text.length, end: text.length, kind: ts.SyntaxKind.EndOfFileToken },
amdDependencies: /**@type {*} */([]),
referencedFiles: /**@type {*} */([]),
typeReferenceDirectives: /**@type {*} */([]),
libReferenceDirectives: /**@type {*} */([]),
languageVariant: ts.LanguageVariant.Standard,
isDeclarationFile: /\.d\.ts$/.test(fileName),
hasNoDefaultLib: /[\\/]lib\.[^\\/]+\.d\.ts$/.test(fileName)
});
}
sourceFiles.set(fileName, file);
return file;
}
};
/** @type {Duplex & { js?: Readable, dts?: Readable }} */
const compileStream = new Duplex({
objectMode: true,
read() {},
/** @param {*} file */
write(file, _encoding, callback) {
inputs.set(file.path, file);
proc.send(protocol.message.write(file));
callback();
},
final(callback) {
proc.send(protocol.message.final());
callback();
}
});
const jsStream = compileStream.js = new Readable({
objectMode: true,
read() {}
});
const dtsStream = compileStream.dts = new Readable({
objectMode: true,
read() {}
});
proc.send(protocol.message.createProject(tsConfigFileName, settings, options));
proc.on("message", (/**@type {protocol.WorkerMessage}*/ message) => {
switch (message.method) {
case "write": {
const file = protocol.vinylFromJson(message.params);
compileStream.push(file);
if (file.path.endsWith(".d.ts")) {
dtsStream.push(file);
}
else {
jsStream.push(file);
}
break;
}
case "final": {
compileStream.push(null);
jsStream.push(null);
dtsStream.push(null);
proc.kill(); // TODO(rbuckton): pool workers? may not be feasible due to gulp-typescript holding onto memory
break;
}
case "error": {
const error = protocol.errorFromJson(message.params);
compileStream.emit("error", error);
proc.kill(); // TODO(rbuckton): pool workers? may not be feasible due to gulp-typescript holding onto memory
break;
}
case "reporter.error": {
if (reporter.error) {
const error = protocol.typeScriptErrorFromJson(message.params, host);
reporter.error(error, project.typescript);
}
break;
}
case "reporter.finish": {
if (reporter.finish) {
reporter.finish(message.params);
}
}
}
});
return /** @type {*} */(compileStream);
});
return Object.assign(wrappedProject, project);
}
exports.createProject = createProject;

View file

@ -0,0 +1,279 @@
// @ts-check
const Vinyl = require("vinyl");
/**
* @param {File} file
* @returns {*}
*/
function vinylToJson(file) {
if (file.isStream()) throw new TypeError("Streams not supported.");
return {
path: file.path,
cwd: file.cwd,
base: file.base,
contents: file.isBuffer() ? file.contents.toString("utf8") : undefined,
sourceMap: file.sourceMap
};
}
exports.vinylToJson = vinylToJson;
/**
* @param {*} json
* @returns {File}
*/
function vinylFromJson(json) {
return new Vinyl({
path: json.path,
cwd: json.cwd,
base: json.base,
contents: typeof json.contents === "string" ? Buffer.from(json.contents, "utf8") : undefined,
sourceMap: json.sourceMap
});
}
exports.vinylFromJson = vinylFromJson;
/**
* @param {Error} error
* @returns {*}
*/
function errorToJson(error) {
return {
name: error.name,
message: error.message,
stack: error.stack
};
}
exports.errorToJson = errorToJson;
/**
* @param {*} json
* @returns {Error}
*/
function errorFromJson(json) {
const error = new Error();
error.name = json.name;
error.message = json.message;
error.stack = json.stack;
return error;
}
exports.errorFromJson = errorFromJson;
/**
* @param {TypeScriptError} error
* @returns {*}
*/
function typeScriptErrorToJson(error) {
return Object.assign({}, errorToJson(error), {
fullFilename: error.fullFilename,
relativeFilename: error.relativeFilename,
file: error.file && { path: error.file.path },
tsFile: error.tsFile && sourceFileToJson(error.tsFile),
diagnostic: diagnosticToJson(error.diagnostic),
startPosition: error.startPosition,
endPosition: error.endPosition
});
}
exports.typeScriptErrorToJson = typeScriptErrorToJson;
/**
* @param {*} json
* @param {SourceFileHost & VinylHost} host
* @returns {TypeScriptError}
*/
function typeScriptErrorFromJson(json, host) {
const error = /**@type {TypeScriptError}*/(errorFromJson(json));
error.fullFilename = json.fullFilename;
error.relativeFilename = json.relativeFilename;
error.file = json.file && host.getVinyl(json.file.path);
error.tsFile = json.tsFile && sourceFileFromJson(json.tsFile, host);
error.diagnostic = diagnosticFromJson(json.diagnostic, host);
error.startPosition = json.startPosition;
error.endPosition = json.endPosition;
return error;
}
exports.typeScriptErrorFromJson = typeScriptErrorFromJson;
/**
* @param {SourceFile} file
* @returns {*}
*/
function sourceFileToJson(file) {
return {
fileName: file.fileName,
text: file.text,
languageVersion: file.languageVersion
};
}
exports.sourceFileToJson = sourceFileToJson;
/**
* @param {*} json
* @param {SourceFileHost} host
*/
function sourceFileFromJson(json, host) {
return host.getSourceFile(json.fileName)
|| host.createSourceFile(json.fileName, json.text, json.languageVersion);
}
exports.sourceFileFromJson = sourceFileFromJson;
/**
* @param {Diagnostic} diagnostic
* @returns {*}
*/
function diagnosticToJson(diagnostic) {
return Object.assign({}, diagnosticRelatedInformationToJson(diagnostic), {
category: diagnostic.category,
code: diagnostic.code,
source: diagnostic.source,
relatedInformation: diagnostic.relatedInformation && diagnostic.relatedInformation.map(diagnosticRelatedInformationToJson)
});
}
exports.diagnosticToJson = diagnosticToJson;
/**
* @param {*} json
* @param {SourceFileHost} host
* @returns {Diagnostic}
*/
function diagnosticFromJson(json, host) {
return Object.assign({}, diagnosticRelatedInformationFromJson(json, host), {
category: json.category,
code: json.code,
source: json.source,
relatedInformation: json.relatedInformation && json.relatedInformation.map(diagnosticRelatedInformationFromJson, host)
});
}
exports.diagnosticFromJson = diagnosticFromJson;
/**
* @param {DiagnosticRelatedInformation} diagnostic
* @returns {*}
*/
function diagnosticRelatedInformationToJson(diagnostic) {
return {
file: diagnostic.file && { fileName: diagnostic.file.fileName },
start: diagnostic.start,
length: diagnostic.length,
messageText: diagnostic.messageText
};
}
exports.diagnosticRelatedInformationToJson = diagnosticRelatedInformationToJson;
/**
* @param {*} json
* @param {SourceFileHost} host
* @returns {DiagnosticRelatedInformation}
*/
function diagnosticRelatedInformationFromJson(json, host) {
return {
file: json.file && sourceFileFromJson(json.file, host),
start: json.start,
length: json.length,
messageText: json.messageText
};
}
exports.diagnosticRelatedInformationFromJson = diagnosticRelatedInformationFromJson;
exports.message = {};
/**
* @param {string | undefined} tsConfigFileName
* @param {import("gulp-typescript").Settings} settings
* @param {Object} options
* @param {string} [options.typescript]
* @returns {CreateProjectMessage}
*
* @typedef CreateProjectMessage
* @property {"createProject"} method
* @property {CreateProjectParams} params
*
* @typedef CreateProjectParams
* @property {string | undefined} tsConfigFileName
* @property {import("gulp-typescript").Settings} settings
* @property {CreateProjectOptions} options
*
* @typedef CreateProjectOptions
* @property {string} [typescript]
*/
exports.message.createProject = function(tsConfigFileName, settings, options) {
return { method: "createProject", params: { tsConfigFileName, settings, options } };
};
/**
* @param {File} file
* @returns {WriteMessage}
*
* @typedef WriteMessage
* @property {"write"} method
* @property {*} params
*/
exports.message.write = function(file) {
return { method: "write", params: vinylToJson(file) };
};
/**
* @returns {FinalMessage}
*
* @typedef FinalMessage
* @property {"final"} method
*/
exports.message.final = function() {
return { method: "final" };
};
/**
* @param {Error} error
* @returns {ErrorMessage}
*
* @typedef ErrorMessage
* @property {"error"} method
* @property {*} params
*/
exports.message.error = function(error) {
return { method: "error", params: errorToJson(error) };
};
exports.message.reporter = {};
/**
* @param {TypeScriptError} error
* @returns {reporter.ErrorMessage}
*
* @typedef reporter.ErrorMessage
* @property {"reporter.error"} method
* @property {*} params
*/
exports.message.reporter.error = function(error) {
return { method: "reporter.error", params: typeScriptErrorToJson(error) };
};
/**
* @param {*} results
* @returns {reporter.FinishMessage}
*
* @typedef reporter.FinishMessage
* @property {"reporter.finish"} method
* @property {*} params
*/
exports.message.reporter.finish = function(results) {
return { method: "reporter.finish", params: results };
};
/**
* @typedef {import("vinyl")} File
* @typedef {typeof import("typescript")} TypeScriptModule
* @typedef {import("typescript").SourceFile} SourceFile
* @typedef {import("typescript").Diagnostic} Diagnostic
* @typedef {import("typescript").DiagnosticRelatedInformation} DiagnosticRelatedInformation
* @typedef {import("gulp-typescript").reporter.TypeScriptError} TypeScriptError
* @typedef {WriteMessage | FinalMessage | CreateProjectMessage} HostMessage
* @typedef {WriteMessage | FinalMessage | ErrorMessage | reporter.ErrorMessage | reporter.FinishMessage} WorkerMessage
*
* @typedef SourceFileHost
* @property {(fileName: string) => SourceFile | undefined} getSourceFile
* @property {(fileName: string, text: string, languageVersion: number) => SourceFile} createSourceFile
*
* @typedef VinylHost
* @property {(path: string) => File | undefined} getVinyl
*/
void 0;

View file

@ -0,0 +1,79 @@
// @ts-check
const fs = require("fs");
const tsc = require("gulp-typescript");
const { Readable, Writable } = require("stream");
const protocol = require("./protocol");
/** @type {tsc.Project} */
let project;
/** @type {Readable} */
let inputStream;
/** @type {Writable} */
let outputStream;
/** @type {tsc.CompileStream} */
let compileStream;
process.on("message", (/**@type {protocol.HostMessage}*/ message) => {
try {
switch (message.method) {
case "createProject": {
const { tsConfigFileName, settings, options } = message.params;
if (options.typescript) {
settings.typescript = require(options.typescript);
}
project = tsConfigFileName === undefined
? tsc.createProject(settings)
: tsc.createProject(tsConfigFileName, settings);
inputStream = new Readable({
objectMode: true,
read() {}
});
outputStream = new Writable({
objectMode: true,
/**
* @param {*} file
*/
write(file, _, callback) {
process.send(protocol.message.write(file));
callback();
},
final(callback) {
process.send(protocol.message.final());
callback();
}
});
compileStream = project({
error(error) { process.send(protocol.message.reporter.error(error)); },
finish(results) { process.send(protocol.message.reporter.finish(results)); }
});
compileStream.on("error", error => {
process.send(protocol.message.error(error));
});
outputStream.on("error", () => {
/* do nothing */
});
inputStream.pipe(compileStream).pipe(outputStream);
break;
}
case "write": {
const file = protocol.vinylFromJson(message.params);
if (!file.isBuffer()) file.contents = fs.readFileSync(file.path);
inputStream.push(file);
break;
}
case "final": {
inputStream.push(null);
break;
}
}
}
catch (e) {
process.send(protocol.message.error(e));
}
});

View file

@ -1,91 +0,0 @@
// @ts-check
const fs = require("fs");
const tsc = require("gulp-typescript");
const Vinyl = require("vinyl");
const { Readable, Writable } = require("stream");
/** @type {tsc.Project} */
let project;
/** @type {Readable} */
let inputStream;
/** @type {Writable} */
let outputStream;
/** @type {tsc.CompileStream} */
let compileStream;
process.on("message", ({ method, params }) => {
try {
if (method === "createProject") {
const { tsConfigFileName, settings, options } = params;
if (options.typescript) {
settings.typescript = require(options.typescript);
}
project = tsConfigFileName === undefined ? tsc.createProject(settings) : tsc.createProject(tsConfigFileName, settings);
inputStream = new Readable({
objectMode: true,
read() {}
});
outputStream = new Writable({
objectMode: true,
/**
* @param {*} file
*/
write(file, _, callback) {
process.send({
method: "write",
params: {
path: file.path,
cwd: file.cwd,
base: file.base,
contents: file.contents.toString(),
sourceMap: file.sourceMap
}
});
callback();
},
final(callback) {
process.send({ method: "final" });
callback();
}
});
outputStream.on("error", error => {
process.send({
method: "error",
params: {
name: error.name,
message: error.message,
stack: error.stack
}
});
});
compileStream = project();
inputStream.pipe(compileStream).pipe(outputStream);
}
else if (method === "write") {
const file = new Vinyl({
path: params.path,
cwd: params.cwd,
base: params.base
});
file.contents = fs.readFileSync(file.path);
if (params.sourceMap) file.sourceMap = params.sourceMap;
inputStream.push(/** @type {*} */(file));
}
else if (method === "final") {
inputStream.push(null);
}
}
catch (e) {
process.send({
method: "error",
params: {
name: e.name,
message: e.message,
stack: e.stack
}
});
}
});

View file

@ -137,6 +137,7 @@ function watch(projectSpec, options, tasks, callback) {
if (typeof options === "function") callback = options, tasks = /**@type {string[] | undefined}*/(undefined), options = /**@type {CompileOptions | undefined}*/(undefined);
if (Array.isArray(options)) tasks = options, options = /**@type {CompileOptions | undefined}*/(undefined);
const resolvedOptions = resolveCompileOptions(options);
resolvedOptions.watch = true;
const resolvedProjectSpec = resolveProjectSpec(projectSpec, resolvedOptions.paths, /*referrer*/ undefined);
const projectGraph = getOrCreateProjectGraph(resolvedProjectSpec, resolvedOptions.paths);
projectGraph.isRoot = true;
@ -284,6 +285,7 @@ function resolvePathOptions(options) {
* @property {boolean} [verbose] Indicates whether verbose logging is enabled.
* @property {boolean} [force] Force recompilation (no up-to-date check).
* @property {boolean} [inProcess] Indicates whether to run gulp-typescript in-process or out-of-process (default).
* @property {boolean} [watch] Indicates the project was created in watch mode
*/
function resolveCompileOptions(options = {}) {
const paths = resolvePathOptions(options);
@ -305,7 +307,7 @@ function resolveCompileOptions(options = {}) {
* @returns {ResolvedCompileOptions}
*/
function mergeCompileOptions(left, right) {
if (left.typescript !== right.typescript) throw new Error("Cannot merge project options targeting different TypeScript packages");
if (left.typescript.typescript !== right.typescript.typescript) throw new Error("Cannot merge project options targeting different TypeScript packages");
if (tryReuseCompileOptions(left, right)) return left;
return {
paths: left.paths,
@ -314,7 +316,8 @@ function mergeCompileOptions(left, right) {
dts: right.dts || left.dts,
verbose: right.verbose || left.verbose,
force: right.force || left.force,
inProcess: right.inProcess || left.inProcess
inProcess: right.inProcess || left.inProcess,
watch: right.watch || left.watch
};
}
@ -599,30 +602,40 @@ function resolveDestPath(projectGraph, paths) {
*/
function ensureCompileTask(projectGraph, options) {
const projectGraphConfig = getOrCreateProjectGraphConfiguration(projectGraph, options);
projectGraphConfig.resolvedOptions = options = mergeCompileOptions(options, options);
if (!projectGraphConfig.compileTaskCreated) {
const deps = makeProjectReferenceCompileTasks(projectGraph, options.typescript, options.paths);
compilationGulp.task(compileTaskName(projectGraph, options.typescript), deps, () => {
const destPath = resolveDestPath(projectGraph, options.paths);
projectGraphConfig.resolvedOptions = mergeCompileOptions(projectGraphConfig.resolvedOptions, options);
const hasCompileTask = projectGraphConfig.compileTaskCreated;
projectGraphConfig.compileTaskCreated = true;
const deps = makeProjectReferenceCompileTasks(projectGraph, projectGraphConfig.resolvedOptions.typescript, projectGraphConfig.resolvedOptions.paths, projectGraphConfig.resolvedOptions.watch);
if (!hasCompileTask) {
compilationGulp.task(compileTaskName(projectGraph, projectGraphConfig.resolvedOptions.typescript), deps, () => {
const destPath = resolveDestPath(projectGraph, projectGraphConfig.resolvedOptions.paths);
const { sourceMap, inlineSourceMap, inlineSources = false, sourceRoot, declarationMap } = projectGraph.project.options;
const configFilePath = projectGraph.project.options.configFilePath;
const sourceMapPath = inlineSourceMap ? undefined : ".";
const sourceMapOptions = { includeContent: inlineSources, sourceRoot, destPath };
const project = options.inProcess
? tsc.createProject(configFilePath, { typescript: require(options.typescript.typescript) })
: tsc_oop.createProject(configFilePath, {}, { typescript: options.typescript.typescript });
const project = projectGraphConfig.resolvedOptions.inProcess
? tsc.createProject(configFilePath, { typescript: require(projectGraphConfig.resolvedOptions.typescript.typescript) })
: tsc_oop.createProject(configFilePath, {}, { typescript: projectGraphConfig.resolvedOptions.typescript.typescript });
const stream = project.src()
.pipe(gulpif(!options.force, upToDate(projectGraph.project, { verbose: options.verbose, parseProject: createParseProject(options.paths) })))
.pipe(gulpif(!projectGraphConfig.resolvedOptions.force, upToDate(projectGraph.project, { verbose: projectGraphConfig.resolvedOptions.verbose, parseProject: createParseProject(projectGraphConfig.resolvedOptions.paths) })))
.pipe(gulpif(sourceMap || inlineSourceMap, sourcemaps.init()))
.pipe(project());
const js = (options.js ? options.js(stream.js) : stream.js)
if (projectGraphConfig.resolvedOptions.watch) {
stream.on("error", error => {
if (error.message === "TypeScript: Compilation failed") {
stream.emit("end");
stream.js.emit("end");
stream.dts.emit("end");
}
});
}
const js = (projectGraphConfig.resolvedOptions.js ? projectGraphConfig.resolvedOptions.js(stream.js) : stream.js)
.pipe(gulpif(sourceMap || inlineSourceMap, sourcemaps.write(sourceMapPath, sourceMapOptions)));
const dts = (options.dts ? options.dts(stream.dts) : stream.dts)
const dts = (projectGraphConfig.resolvedOptions.dts ? projectGraphConfig.resolvedOptions.dts(stream.dts) : stream.dts)
.pipe(gulpif(declarationMap, sourcemaps.write(sourceMapPath, sourceMapOptions)));
return merge2([js, dts])
.pipe(gulp.dest(destPath));
});
projectGraphConfig.compileTaskCreated = true;
}
return projectGraph;
}
@ -631,9 +644,10 @@ function ensureCompileTask(projectGraph, options) {
* @param {ProjectGraph} projectGraph
* @param {ResolvedTypeScript} typescript
* @param {ResolvedPathOptions} paths
* @param {boolean} watch
*/
function makeProjectReferenceCompileTasks(projectGraph, typescript, paths) {
return projectGraph.references.map(({target}) => compileTaskName(ensureCompileTask(target, { paths, typescript }), typescript));
function makeProjectReferenceCompileTasks(projectGraph, typescript, paths, watch) {
return projectGraph.references.map(({target}) => compileTaskName(ensureCompileTask(target, { paths, typescript, watch }), typescript));
}
/**
@ -715,7 +729,7 @@ function ensureWatcher(projectGraph, options, tasks, callback) {
}
/**
* @param {ProjectGraphConfiguration} config
* @param {ProjectGraphConfiguration} config
* @param {import("orchestrator").Task} task
*/
function possiblyTriggerRecompilation(config, task) {
@ -732,7 +746,7 @@ function possiblyTriggerRecompilation(config, task) {
/**
* @param {import("orchestrator").Task} task
* @param {ProjectGraphConfiguration} config
* @param {ProjectGraphConfiguration} config
*/
function triggerRecompilation(task, config) {
compilationGulp._resetTask(task);