Simplify gulp to just use 'tsc -b' to build, update to gulp@4
This commit is contained in:
parent
fa74cef81e
commit
47c2708a9c
1145
Gulpfile.js
1145
Gulpfile.js
File diff suppressed because it is too large
Load diff
|
@ -8,10 +8,8 @@ const path = require("path");
|
|||
const fold = require("travis-fold");
|
||||
const ts = require("./lib/typescript");
|
||||
const del = require("del");
|
||||
const getDirSize = require("./scripts/build/getDirSize");
|
||||
const { getDirSize, needsUpdate, flatten } = require("./scripts/build/utils");
|
||||
const { base64VLQFormatEncode } = require("./scripts/build/sourcemaps");
|
||||
const needsUpdate = require("./scripts/build/needsUpdate");
|
||||
const { flatten } = require("./scripts/build/project");
|
||||
|
||||
// add node_modules to path so we don't need global modules, prefer the modules by adding them first
|
||||
var nodeModulesPathPrefix = path.resolve("./node_modules/.bin/") + path.delimiter;
|
||||
|
|
12
package.json
12
package.json
|
@ -35,10 +35,8 @@
|
|||
"@types/convert-source-map": "latest",
|
||||
"@types/del": "latest",
|
||||
"@types/glob": "latest",
|
||||
"@types/gulp": "3.X",
|
||||
"@types/gulp": "^4.0.5",
|
||||
"@types/gulp-concat": "latest",
|
||||
"@types/gulp-help": "latest",
|
||||
"@types/gulp-if": "0.0.33",
|
||||
"@types/gulp-newer": "latest",
|
||||
"@types/gulp-rename": "0.0.33",
|
||||
"@types/gulp-sourcemaps": "0.0.32",
|
||||
|
@ -50,7 +48,6 @@
|
|||
"@types/mocha": "latest",
|
||||
"@types/node": "8.5.5",
|
||||
"@types/q": "latest",
|
||||
"@types/run-sequence": "latest",
|
||||
"@types/source-map-support": "latest",
|
||||
"@types/through2": "latest",
|
||||
"@types/travis-fold": "latest",
|
||||
|
@ -63,16 +60,12 @@
|
|||
"del": "latest",
|
||||
"fancy-log": "latest",
|
||||
"fs-extra": "^6.0.1",
|
||||
"gulp": "3.X",
|
||||
"gulp-clone": "latest",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-concat": "latest",
|
||||
"gulp-help": "latest",
|
||||
"gulp-if": "latest",
|
||||
"gulp-insert": "latest",
|
||||
"gulp-newer": "latest",
|
||||
"gulp-rename": "latest",
|
||||
"gulp-sourcemaps": "latest",
|
||||
"gulp-typescript": "latest",
|
||||
"istanbul": "latest",
|
||||
"jake": "latest",
|
||||
"lodash": "4.17.10",
|
||||
|
@ -86,7 +79,6 @@
|
|||
"prex": "^0.4.3",
|
||||
"q": "latest",
|
||||
"remove-internal": "^2.9.2",
|
||||
"run-sequence": "latest",
|
||||
"source-map-support": "latest",
|
||||
"through2": "latest",
|
||||
"travis-fold": "latest",
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
// @ts-check
|
||||
const merge2 = require("merge2");
|
||||
const gulp = require("./gulp");
|
||||
const rename = require("gulp-rename");
|
||||
const rm = require("./rm");
|
||||
const { localBaseline, refBaseline } = require("./tests");
|
||||
|
||||
module.exports = baselineAccept;
|
||||
|
||||
function baselineAccept(subfolder = "") {
|
||||
return merge2(baselineCopy(subfolder), baselineDelete(subfolder));
|
||||
}
|
||||
|
||||
function baselineCopy(subfolder = "") {
|
||||
return gulp.src([`${localBaseline}${subfolder ? `${subfolder}/` : ``}**`, `!${localBaseline}${subfolder}/**/*.delete`], { base: localBaseline })
|
||||
.pipe(gulp.dest(refBaseline));
|
||||
}
|
||||
|
||||
function baselineDelete(subfolder = "") {
|
||||
return gulp.src([`${localBaseline}${subfolder ? `${subfolder}/` : ``}**/*.delete`], { base: localBaseline, read: false })
|
||||
.pipe(rm())
|
||||
.pipe(rename({ extname: "" }))
|
||||
.pipe(rm(refBaseline));
|
||||
}
|
|
@ -1,12 +1,10 @@
|
|||
// @ts-check
|
||||
const browserify = require("browserify");
|
||||
const Vinyl = require("./vinyl");
|
||||
const Vinyl = require("vinyl");
|
||||
const { Transform } = require("stream");
|
||||
const { streamFromFile } = require("./utils");
|
||||
const { replaceContents } = require("./sourcemaps");
|
||||
|
||||
module.exports = browserifyFile;
|
||||
|
||||
/**
|
||||
* @param {import("browserify").Options} [opts]
|
||||
*/
|
||||
|
@ -31,4 +29,5 @@ function browserifyFile(opts) {
|
|||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.browserify = browserifyFile;
|
|
@ -1,5 +0,0 @@
|
|||
// @ts-check
|
||||
|
||||
// this just fixes the incorrect types for chalk :/
|
||||
const chalk = /**@type {import("chalk").Chalk}*/(require("chalk").default || require("chalk"));
|
||||
module.exports = chalk;
|
|
@ -1,19 +0,0 @@
|
|||
// @ts-check
|
||||
const replace = require("./replace");
|
||||
|
||||
module.exports = exports = convertConstEnum;
|
||||
|
||||
/**
|
||||
* This regexp exists to capture our const enums and replace them with normal enums in our public API
|
||||
* - this is fine since we compile with preserveConstEnums, and ensures our consumers are not locked
|
||||
* to the TS version they compile with.
|
||||
*/
|
||||
const constEnumCaptureRegexp = /^(\s*)(export )?const enum (\S+) {(\s*)$/gm;
|
||||
const constEnumReplacement = "$1$2enum $3 {$4";
|
||||
|
||||
/**
|
||||
* Converts `const enum` declarations in a .d.ts file into non-const `enum` declarations.
|
||||
*/
|
||||
function convertConstEnum() {
|
||||
return replace(constEnumCaptureRegexp, constEnumReplacement);
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
// @ts-check
|
||||
module.exports = debounce;
|
||||
|
||||
/**
|
||||
* @param {() => void} cb
|
||||
* @param {number} timeout
|
||||
* @param {DebounceOptions} [opts]
|
||||
*
|
||||
* @typedef DebounceOptions
|
||||
* @property {number} [max]
|
||||
*/
|
||||
function debounce(cb, timeout, opts = {}) {
|
||||
if (timeout < 10) timeout = 10;
|
||||
let max = opts.max || 10;
|
||||
if (max < timeout) max = timeout;
|
||||
let minTimer;
|
||||
let maxTimer;
|
||||
return trigger;
|
||||
|
||||
function trigger() {
|
||||
if (max > timeout && !maxTimer) maxTimer = setTimeout(done, max);
|
||||
if (minTimer) clearTimeout(minTimer);
|
||||
minTimer = setTimeout(done, timeout);
|
||||
}
|
||||
|
||||
function done() {
|
||||
if (maxTimer) maxTimer = void clearTimeout(maxTimer);
|
||||
if (minTimer) minTimer = void clearTimeout(minTimer);
|
||||
cb();
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
// @ts-check
|
||||
const ts = require("../../lib/typescript");
|
||||
const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util)
|
||||
|
||||
/** @type {FormatDiagnosticsHost} */
|
||||
const formatDiagnosticsHost = exports.formatDiagnosticsHost = {
|
||||
getCanonicalFileName: fileName => fileName,
|
||||
getCurrentDirectory: () => process.cwd(),
|
||||
getNewLine: () => ts.sys.newLine
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Diagnostic[]} diagnostics
|
||||
* @param {{ cwd?: string, pretty?: boolean }} [options]
|
||||
*/
|
||||
function formatDiagnostics(diagnostics, options) {
|
||||
return options && options.pretty
|
||||
? ts.formatDiagnosticsWithColorAndContext(diagnostics, getFormatDiagnosticsHost(options && options.cwd))
|
||||
: ts.formatDiagnostics(diagnostics, getFormatDiagnosticsHost(options && options.cwd));
|
||||
}
|
||||
exports.formatDiagnostics = formatDiagnostics;
|
||||
|
||||
/**
|
||||
* @param {Diagnostic[]} diagnostics
|
||||
* @param {{ cwd?: string }} [options]
|
||||
*/
|
||||
function reportDiagnostics(diagnostics, options) {
|
||||
log(formatDiagnostics(diagnostics, { cwd: options && options.cwd, pretty: process.stdout.isTTY }));
|
||||
}
|
||||
exports.reportDiagnostics = reportDiagnostics;
|
||||
|
||||
/**
|
||||
* @param {string | undefined} cwd
|
||||
* @returns {FormatDiagnosticsHost}
|
||||
*/
|
||||
function getFormatDiagnosticsHost(cwd) {
|
||||
if (!cwd || cwd === process.cwd()) return formatDiagnosticsHost;
|
||||
return {
|
||||
getCanonicalFileName: formatDiagnosticsHost.getCanonicalFileName,
|
||||
getCurrentDirectory: () => cwd,
|
||||
getNewLine: formatDiagnosticsHost.getNewLine
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {import("../../lib/typescript").FormatDiagnosticsHost} FormatDiagnosticsHost
|
||||
* @typedef {import("../../lib/typescript").Diagnostic} Diagnostic
|
||||
*/
|
||||
void 0;
|
|
@ -1,58 +0,0 @@
|
|||
// @ts-check
|
||||
const cp = require("child_process");
|
||||
const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util)
|
||||
const isWin = /^win/.test(process.platform);
|
||||
const chalk = require("./chalk");
|
||||
const { CancellationToken, CancelError } = require("prex");
|
||||
|
||||
module.exports = exec;
|
||||
|
||||
/**
|
||||
* Executes the provided command once with the supplied arguments.
|
||||
* @param {string} cmd
|
||||
* @param {string[]} args
|
||||
* @param {ExecOptions} [options]
|
||||
*
|
||||
* @typedef ExecOptions
|
||||
* @property {boolean} [ignoreExitCode]
|
||||
* @property {import("prex").CancellationToken} [cancelToken]
|
||||
*/
|
||||
function exec(cmd, args, options = {}) {
|
||||
return /**@type {Promise<{exitCode: number}>}*/(new Promise((resolve, reject) => {
|
||||
const { ignoreExitCode, cancelToken = CancellationToken.none } = options;
|
||||
cancelToken.throwIfCancellationRequested();
|
||||
|
||||
// TODO (weswig): Update child_process types to add windowsVerbatimArguments to the type definition
|
||||
const subshellFlag = isWin ? "/c" : "-c";
|
||||
const command = isWin ? [possiblyQuote(cmd), ...args] : [`${cmd} ${args.join(" ")}`];
|
||||
|
||||
log(`> ${chalk.green(cmd)} ${args.join(" ")}`);
|
||||
const proc = cp.spawn(isWin ? "cmd" : "/bin/sh", [subshellFlag, ...command], { stdio: "inherit", windowsVerbatimArguments: true });
|
||||
const registration = cancelToken.register(() => {
|
||||
log(`${chalk.red("killing")} '${chalk.green(cmd)} ${args.join(" ")}'...`);
|
||||
proc.kill("SIGINT");
|
||||
proc.kill("SIGTERM");
|
||||
reject(new CancelError());
|
||||
});
|
||||
proc.on("exit", exitCode => {
|
||||
registration.unregister();
|
||||
if (exitCode === 0 || ignoreExitCode) {
|
||||
resolve({ exitCode });
|
||||
}
|
||||
else {
|
||||
reject(new Error(`Process exited with code: ${exitCode}`));
|
||||
}
|
||||
});
|
||||
proc.on("error", error => {
|
||||
registration.unregister();
|
||||
reject(error);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} cmd
|
||||
*/
|
||||
function possiblyQuote(cmd) {
|
||||
return cmd.indexOf(" ") >= 0 ? `"${cmd}"` : cmd;
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
// @ts-check
|
||||
module.exports = finished;
|
||||
|
||||
/**
|
||||
* @param {NodeJS.ReadableStream | NodeJS.WritableStream} stream
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
function finished(stream) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const readable = "readable" in stream && stream.readable;
|
||||
const writable = "writable" in stream && stream.writable;
|
||||
|
||||
let countdown = 0;
|
||||
const cleanup = () => {
|
||||
if (readable) stream.removeListener("end", signal);
|
||||
if (writable) stream.removeListener("finish", signal);
|
||||
stream.removeListener("error", onerror);
|
||||
};
|
||||
const signal = () => {
|
||||
if (countdown > 0) {
|
||||
countdown--;
|
||||
if (countdown === 0) {
|
||||
cleanup();
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
const onerror = (error) => {
|
||||
if (countdown > 0) {
|
||||
countdown = 0;
|
||||
cleanup();
|
||||
reject(error);
|
||||
}
|
||||
};
|
||||
stream.once("error", onerror);
|
||||
if (readable) {
|
||||
countdown++;
|
||||
stream.once("end", signal);
|
||||
}
|
||||
if (writable) {
|
||||
countdown++;
|
||||
stream.once("finish", signal);
|
||||
}
|
||||
if (countdown === 0) signal();
|
||||
});
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
// @ts-check
|
||||
const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util)
|
||||
module.exports = getDiffTool;
|
||||
|
||||
function getDiffTool() {
|
||||
const program = process.env.DIFF;
|
||||
if (!program) {
|
||||
log.warn("Add the 'DIFF' environment variable to the path of the program you want to use.");
|
||||
process.exit(1);
|
||||
}
|
||||
return program;
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
// @ts-check
|
||||
const { lstatSync, readdirSync } = require("fs");
|
||||
const { join } = require("path");
|
||||
|
||||
/**
|
||||
* Find the size of a directory recursively.
|
||||
* Symbolic links can cause a loop.
|
||||
* @param {string} root
|
||||
* @returns {number} bytes
|
||||
*/
|
||||
function getDirSize(root) {
|
||||
const stats = lstatSync(root);
|
||||
|
||||
if (!stats.isDirectory()) {
|
||||
return stats.size;
|
||||
}
|
||||
|
||||
return readdirSync(root)
|
||||
.map(file => getDirSize(join(root, file)))
|
||||
.reduce((acc, num) => acc + num, 0);
|
||||
}
|
||||
|
||||
module.exports = getDirSize;
|
|
@ -1,149 +0,0 @@
|
|||
// @ts-check
|
||||
const path = require("path");
|
||||
const child_process = require("child_process");
|
||||
const fs = require("fs");
|
||||
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) {
|
||||
text = fs.readFileSync(fileName, "utf8");
|
||||
}
|
||||
|
||||
/** @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;
|
|
@ -1,281 +0,0 @@
|
|||
// @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(json => diagnosticRelatedInformationFromJson(json, 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,
|
||||
category: json.category,
|
||||
code: json.code
|
||||
};
|
||||
}
|
||||
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;
|
|
@ -1,79 +0,0 @@
|
|||
// @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));
|
||||
}
|
||||
});
|
|
@ -1,8 +0,0 @@
|
|||
// @ts-check
|
||||
/**
|
||||
* @typedef {import("gulp").Gulp} Gulp
|
||||
* @typedef {import("gulp-help").GulpHelp} GulpHelp
|
||||
* @typedef {GulpHelp & { Gulp: new () => Gulp }} DotGulpModule
|
||||
* @type {DotGulpModule}
|
||||
*/
|
||||
module.exports = require("gulp-help")(require("gulp"));
|
|
@ -1,30 +0,0 @@
|
|||
// @ts-check
|
||||
const readJson = require("./readJson");
|
||||
const path = require("path");
|
||||
const gulp = require("./gulp");
|
||||
const newer = require("gulp-newer");
|
||||
const concat = require("gulp-concat");
|
||||
const merge2 = require("merge2");
|
||||
|
||||
/** @type {{ libs: string[], paths?: Record<string, string>, sources?: Record<string, string[]> }} */
|
||||
const libraries = readJson("./src/lib/libs.json");
|
||||
const libs = libraries.libs.map(lib => {
|
||||
const relativeSources = ["header.d.ts"].concat(libraries.sources && libraries.sources[lib] || [lib + ".d.ts"]);
|
||||
const relativeTarget = libraries.paths && libraries.paths[lib] || ("lib." + lib + ".d.ts");
|
||||
const sources = relativeSources.map(s => path.posix.join("src/lib", s));
|
||||
const target = `built/local/${relativeTarget}`;
|
||||
return { target, relativeTarget, sources };
|
||||
});
|
||||
exports.libraryTargets = libs.map(lib => lib.target);
|
||||
|
||||
/**
|
||||
* @param {string[]} prepends
|
||||
*/
|
||||
function generateLibs(prepends) {
|
||||
return merge2(libs.map(({ sources, target, relativeTarget }) =>
|
||||
gulp.src(prepends.concat(sources))
|
||||
.pipe(newer(target))
|
||||
.pipe(concat(relativeTarget, { newLine: "\n\n" }))
|
||||
.pipe(gulp.dest("built/local"))));
|
||||
}
|
||||
exports.generateLibs = generateLibs;
|
|
@ -1,14 +0,0 @@
|
|||
// @ts-check
|
||||
const mkdirp = require("mkdirp");
|
||||
|
||||
module.exports = exports = mkdirpAsync;
|
||||
|
||||
/**
|
||||
* @param {string} dir
|
||||
* @param {mkdirp.Mode | mkdirp.Options} [opts]
|
||||
*/
|
||||
function mkdirpAsync(dir, opts) {
|
||||
return new Promise((resolve, reject) => mkdirp(dir, opts, (err, made) => err ? reject(err) : resolve(made)));
|
||||
}
|
||||
|
||||
exports.sync = mkdirp.sync;
|
|
@ -1,72 +0,0 @@
|
|||
// @ts-check
|
||||
const fs = require("fs");
|
||||
|
||||
module.exports = needsUpdate;
|
||||
|
||||
/**
|
||||
* @param {string | string[]} source
|
||||
* @param {string | string[]} dest
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function needsUpdate(source, dest) {
|
||||
if (typeof source === "string" && typeof dest === "string") {
|
||||
if (fs.existsSync(dest)) {
|
||||
const {mtime: outTime} = fs.statSync(dest);
|
||||
const {mtime: inTime} = fs.statSync(source);
|
||||
if (+inTime <= +outTime) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (typeof source === "string" && typeof dest !== "string") {
|
||||
const {mtime: inTime} = fs.statSync(source);
|
||||
for (const filepath of dest) {
|
||||
if (fs.existsSync(filepath)) {
|
||||
const {mtime: outTime} = fs.statSync(filepath);
|
||||
if (+inTime > +outTime) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (typeof source !== "string" && typeof dest === "string") {
|
||||
if (fs.existsSync(dest)) {
|
||||
const {mtime: outTime} = fs.statSync(dest);
|
||||
for (const filepath of source) {
|
||||
if (fs.existsSync(filepath)) {
|
||||
const {mtime: inTime} = fs.statSync(filepath);
|
||||
if (+inTime > +outTime) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (typeof source !== "string" && typeof dest !== "string") {
|
||||
for (let i = 0; i < source.length; i++) {
|
||||
if (!dest[i]) {
|
||||
continue;
|
||||
}
|
||||
if (fs.existsSync(dest[i])) {
|
||||
const {mtime: outTime} = fs.statSync(dest[i]);
|
||||
const {mtime: inTime} = fs.statSync(source[i]);
|
||||
if (+inTime > +outTime) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -4,7 +4,7 @@ const os = require("os");
|
|||
|
||||
/** @type {CommandLineOptions} */
|
||||
module.exports = minimist(process.argv.slice(2), {
|
||||
boolean: ["debug", "dirty", "inspect", "light", "colors", "lint", "lkg", "soft", "fix", "failed", "keepFailed"],
|
||||
boolean: ["debug", "dirty", "inspect", "light", "colors", "lint", "lkg", "soft", "fix", "failed", "keepFailed", "force", "built"],
|
||||
string: ["browser", "tests", "host", "reporter", "stackTraceLimit", "timeout"],
|
||||
alias: {
|
||||
"b": "browser",
|
||||
|
@ -15,7 +15,7 @@ module.exports = minimist(process.argv.slice(2), {
|
|||
"r": "reporter",
|
||||
"c": "colors", "color": "colors",
|
||||
"w": "workers",
|
||||
"f": "fix",
|
||||
"f": "fix"
|
||||
},
|
||||
default: {
|
||||
soft: false,
|
||||
|
@ -35,10 +35,15 @@ module.exports = minimist(process.argv.slice(2), {
|
|||
failed: false,
|
||||
keepFailed: false,
|
||||
lkg: true,
|
||||
dirty: false
|
||||
dirty: false,
|
||||
built: false
|
||||
}
|
||||
});
|
||||
|
||||
if (module.exports.built) {
|
||||
module.exports.lkg = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef TypedOptions
|
||||
* @property {boolean} debug
|
||||
|
@ -48,6 +53,7 @@ module.exports = minimist(process.argv.slice(2), {
|
|||
* @property {boolean} colors
|
||||
* @property {boolean} lint
|
||||
* @property {boolean} lkg
|
||||
* @property {boolean} built
|
||||
* @property {boolean} soft
|
||||
* @property {boolean} fix
|
||||
* @property {string} browser
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
// @ts-check
|
||||
const stream = require("stream");
|
||||
const Vinyl = require("./vinyl");
|
||||
const Vinyl = require("vinyl");
|
||||
const ts = require("../../lib/typescript");
|
||||
const fs = require("fs");
|
||||
const { base64VLQFormatEncode } = require("./sourcemaps");
|
||||
|
||||
module.exports = exports = prepend;
|
||||
|
||||
/**
|
||||
* @param {string | ((file: Vinyl) => string)} data
|
||||
* @param {string | ((file: import("vinyl")) => string)} data
|
||||
*/
|
||||
function prepend(data) {
|
||||
return new stream.Transform({
|
||||
objectMode: true,
|
||||
/**
|
||||
* @param {string | Buffer | Vinyl} input
|
||||
* @param {string | Buffer | import("vinyl")} input
|
||||
* @param {(error: Error, data?: any) => void} cb
|
||||
*/
|
||||
transform(input, _, cb) {
|
||||
|
@ -56,11 +54,11 @@ function prepend(data) {
|
|||
exports.prepend = prepend;
|
||||
|
||||
/**
|
||||
* @param {string | ((file: Vinyl) => string)} file
|
||||
* @param {string | ((file: import("vinyl")) => string)} file
|
||||
*/
|
||||
function prependFile(file) {
|
||||
const data = typeof file === "string" ? fs.readFileSync(file, "utf8") :
|
||||
vinyl => fs.readFileSync(file(vinyl), "utf8");
|
||||
return prepend(data)
|
||||
}
|
||||
exports.file = prependFile;
|
||||
exports.prependFile = prependFile;
|
File diff suppressed because it is too large
Load diff
60
scripts/build/projects.js
Normal file
60
scripts/build/projects.js
Normal file
|
@ -0,0 +1,60 @@
|
|||
// @ts-check
|
||||
const { exec, Debouncer } = require("./utils");
|
||||
|
||||
class ProjectQueue {
|
||||
/**
|
||||
* @param {(projects: string[], lkg: boolean, force: boolean) => Promise<any>} action
|
||||
*/
|
||||
constructor(action) {
|
||||
/** @type {{ lkg: boolean, force: boolean, projects?: string[], debouncer: Debouncer }[]} */
|
||||
this._debouncers = [];
|
||||
this._action = action;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} project
|
||||
* @param {object} options
|
||||
*/
|
||||
enqueue(project, { lkg = true, force = false } = {}) {
|
||||
let entry = this._debouncers.find(entry => entry.lkg === lkg && entry.force === force);
|
||||
if (!entry) {
|
||||
const debouncer = new Debouncer(100, async () => {
|
||||
const projects = entry.projects;
|
||||
if (projects) {
|
||||
entry.projects = undefined;
|
||||
await this._action(projects, lkg, force);
|
||||
}
|
||||
});
|
||||
this._debouncers.push(entry = { lkg, force, debouncer });
|
||||
}
|
||||
if (!entry.projects) entry.projects = [];
|
||||
entry.projects.push(project);
|
||||
return entry.debouncer.enqueue();
|
||||
}
|
||||
}
|
||||
|
||||
const projectBuilder = new ProjectQueue((projects, lkg, force) => exec(process.execPath, [lkg ? "./lib/tsc" : "./built/local/tsc", "-b", ...(force ? ["--force"] : []), ...projects], { hidePrompt: true }));
|
||||
|
||||
/**
|
||||
* @param {string} project
|
||||
* @param {object} [options]
|
||||
* @param {boolean} [options.lkg=true]
|
||||
* @param {boolean} [options.force=false]
|
||||
*/
|
||||
exports.buildProject = (project, { lkg, force } = {}) => projectBuilder.enqueue(project, { lkg, force });
|
||||
|
||||
const projectCleaner = new ProjectQueue((projects, lkg) => exec(process.execPath, [lkg ? "./lib/tsc" : "./built/local/tsc", "-b", "--clean", ...projects], { hidePrompt: true }));
|
||||
|
||||
/**
|
||||
* @param {string} project
|
||||
*/
|
||||
exports.cleanProject = (project) => projectCleaner.enqueue(project);
|
||||
|
||||
const projectWatcher = new ProjectQueue((projects) => exec(process.execPath, ["./lib/tsc", "-b", "--watch", ...projects], { hidePrompt: true }));
|
||||
|
||||
/**
|
||||
* @param {string} project
|
||||
* @param {object} [options]
|
||||
* @param {boolean} [options.lkg=true]
|
||||
*/
|
||||
exports.watchProject = (project, { lkg } = {}) => projectWatcher.enqueue(project, { lkg });
|
|
@ -1,17 +0,0 @@
|
|||
// @ts-check
|
||||
const ts = require("../../lib/typescript");
|
||||
const fs = require("fs");
|
||||
const { reportDiagnostics } = require("./diagnostics");
|
||||
|
||||
module.exports = exports = readJson;
|
||||
|
||||
/** @param {string} jsonPath */
|
||||
function readJson(jsonPath) {
|
||||
const jsonText = fs.readFileSync(jsonPath, "utf8");
|
||||
const result = ts.parseConfigFileTextToJson(jsonPath, jsonText);
|
||||
if (result.error) {
|
||||
reportDiagnostics([result.error]);
|
||||
throw new Error("An error occurred during parse.");
|
||||
}
|
||||
return result.config;
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
// @ts-check
|
||||
const insert = require("gulp-insert");
|
||||
|
||||
/**
|
||||
* @param {string | RegExp} searchValue
|
||||
* @param {string | ((...args: string[]) => string)} replacer
|
||||
*/
|
||||
function replace(searchValue, replacer) {
|
||||
return insert.transform(content => content.replace(searchValue, /**@type {string}*/(replacer)));
|
||||
}
|
||||
|
||||
module.exports = replace;
|
|
@ -1,84 +0,0 @@
|
|||
// @ts-check
|
||||
const { Duplex } = require("stream");
|
||||
const path = require("path");
|
||||
const Vinyl = require("vinyl");
|
||||
const del = require("del");
|
||||
|
||||
module.exports = rm;
|
||||
|
||||
/**
|
||||
* @param {string | ((file: File) => string) | Options} [dest]
|
||||
* @param {Options} [opts]
|
||||
*/
|
||||
function rm(dest, opts) {
|
||||
if (dest && typeof dest === "object") opts = dest, dest = undefined;
|
||||
let failed = false;
|
||||
|
||||
const cwd = path.resolve(opts && opts.cwd || process.cwd());
|
||||
|
||||
/** @type {{ file: File, deleted: boolean, promise: Promise<any>, cb: Function }[]} */
|
||||
const pending = [];
|
||||
|
||||
const processDeleted = () => {
|
||||
if (failed) return;
|
||||
while (pending.length && pending[0].deleted) {
|
||||
const { file, cb } = pending.shift();
|
||||
duplex.push(file);
|
||||
cb();
|
||||
}
|
||||
};
|
||||
|
||||
const duplex = new Duplex({
|
||||
objectMode: true,
|
||||
/**
|
||||
* @param {string|Buffer|File} file
|
||||
*/
|
||||
write(file, _, cb) {
|
||||
if (failed) return;
|
||||
if (typeof file === "string" || Buffer.isBuffer(file)) return cb(new Error("Only Vinyl files are supported."));
|
||||
const basePath = typeof dest === "string" ? path.resolve(cwd, dest) :
|
||||
typeof dest === "function" ? path.resolve(cwd, dest(file)) :
|
||||
file.base;
|
||||
const filePath = path.resolve(basePath, file.relative);
|
||||
file.cwd = cwd;
|
||||
file.base = basePath;
|
||||
file.path = filePath;
|
||||
const entry = {
|
||||
file,
|
||||
deleted: false,
|
||||
cb,
|
||||
promise: del(file.path).then(() => {
|
||||
entry.deleted = true;
|
||||
processDeleted();
|
||||
}, err => {
|
||||
failed = true;
|
||||
pending.length = 0;
|
||||
cb(err);
|
||||
})
|
||||
};
|
||||
pending.push(entry);
|
||||
},
|
||||
final(cb) {
|
||||
processDeleted();
|
||||
if (pending.length) {
|
||||
Promise
|
||||
.all(pending.map(entry => entry.promise))
|
||||
.then(() => processDeleted())
|
||||
.then(() => cb(), cb);
|
||||
return;
|
||||
}
|
||||
cb();
|
||||
},
|
||||
read() {
|
||||
}
|
||||
});
|
||||
return duplex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {import("vinyl")} File
|
||||
*
|
||||
* @typedef Options
|
||||
* @property {string} [cwd]
|
||||
*/
|
||||
void 0;
|
|
@ -1,12 +1,13 @@
|
|||
// @ts-check
|
||||
/// <reference path="../types/ambient.d.ts" />
|
||||
|
||||
const path = require("path");
|
||||
const Vinyl = require("./vinyl");
|
||||
const convertMap = require("convert-source-map");
|
||||
const applySourceMap = require("vinyl-sourcemaps-apply");
|
||||
const through2 = require("through2");
|
||||
|
||||
/**
|
||||
* @param {Vinyl} input
|
||||
* @param {import("vinyl")} input
|
||||
* @param {string | Buffer} contents
|
||||
* @param {string | RawSourceMap} [sourceMap]
|
||||
*/
|
||||
|
@ -16,13 +17,13 @@ function replaceContents(input, contents, sourceMap) {
|
|||
if (input.sourceMap) {
|
||||
output.sourceMap = typeof input.sourceMap === "string" ? /**@type {RawSourceMap}*/(JSON.parse(input.sourceMap)) : input.sourceMap;
|
||||
if (typeof sourceMap === "string") {
|
||||
sourceMap = /**@type {RawSourceMap}*/(JSON.parse(sourceMap));
|
||||
sourceMap = /** @type {RawSourceMap} */(JSON.parse(sourceMap));
|
||||
}
|
||||
else if (sourceMap === undefined) {
|
||||
const stringContents = typeof contents === "string" ? contents : contents.toString("utf8");
|
||||
const newSourceMapConverter = convertMap.fromSource(stringContents);
|
||||
if (newSourceMapConverter) {
|
||||
sourceMap = /**@type {RawSourceMap}*/(newSourceMapConverter.toObject());
|
||||
sourceMap = /** @type {RawSourceMap} */(newSourceMapConverter.toObject());
|
||||
output.contents = new Buffer(convertMap.removeMapFileComments(stringContents), "utf8");
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +32,7 @@ function replaceContents(input, contents, sourceMap) {
|
|||
const base = input.base || cwd;
|
||||
const sourceRoot = output.sourceMap.sourceRoot;
|
||||
makeAbsoluteSourceMap(cwd, base, output.sourceMap);
|
||||
makeAbsoluteSourceMap(cwd, base, sourceMap);
|
||||
makeAbsoluteSourceMap(cwd, base, /** @type {RawSourceMap} */(sourceMap));
|
||||
applySourceMap(output, sourceMap);
|
||||
makeRelativeSourceMap(cwd, base, sourceRoot, output.sourceMap);
|
||||
}
|
||||
|
@ -44,10 +45,12 @@ function replaceContents(input, contents, sourceMap) {
|
|||
exports.replaceContents = replaceContents;
|
||||
|
||||
function removeSourceMaps() {
|
||||
return through2.obj((/**@type {Vinyl}*/file, _, cb) => {
|
||||
if (file.sourceMap && file.isBuffer()) {
|
||||
return through2.obj((/**@type {import("vinyl")}*/file, _, cb) => {
|
||||
if (file.isBuffer()) {
|
||||
file.contents = Buffer.from(convertMap.removeMapFileComments(file.contents.toString("utf8")), "utf8");
|
||||
file.sourceMap = undefined;
|
||||
if (file.sourceMap) {
|
||||
file.sourceMap = undefined;
|
||||
}
|
||||
}
|
||||
cb(null, file);
|
||||
});
|
||||
|
@ -59,7 +62,7 @@ exports.removeSourceMaps = removeSourceMaps;
|
|||
* @param {string | undefined} base
|
||||
* @param {RawSourceMap} sourceMap
|
||||
*
|
||||
* @typedef RawSourceMap
|
||||
* @typedef {object} RawSourceMap
|
||||
* @property {string} version
|
||||
* @property {string} file
|
||||
* @property {string} [sourceRoot]
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
// @ts-check
|
||||
const gulp = require("./gulp");
|
||||
const gulp = require("gulp");
|
||||
const del = require("del");
|
||||
const fs = require("fs");
|
||||
const os = require("os");
|
||||
const path = require("path");
|
||||
const mkdirP = require("./mkdirp");
|
||||
const mkdirP = require("mkdirp");
|
||||
const log = require("fancy-log");
|
||||
const cmdLineOptions = require("./options");
|
||||
const exec = require("./exec");
|
||||
const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util)
|
||||
const { CancellationToken } = require("prex");
|
||||
const mochaJs = require.resolve("mocha/bin/_mocha");
|
||||
const { exec } = require("./utils");
|
||||
|
||||
const mochaJs = require.resolve("mocha/bin/_mocha");
|
||||
exports.localBaseline = "tests/baselines/local/";
|
||||
exports.refBaseline = "tests/baselines/reference/";
|
||||
exports.localRwcBaseline = "internal/baselines/rwc/local";
|
||||
|
@ -27,7 +27,6 @@ exports.localTest262Baseline = "internal/baselines/test262/local";
|
|||
async function runConsoleTests(runJs, defaultReporter, runInParallel, watchMode, cancelToken = CancellationToken.none) {
|
||||
let testTimeout = cmdLineOptions.timeout;
|
||||
let tests = cmdLineOptions.tests;
|
||||
const lintFlag = cmdLineOptions.lint;
|
||||
const debug = cmdLineOptions.debug;
|
||||
const inspect = cmdLineOptions.inspect;
|
||||
const runners = cmdLineOptions.runners;
|
||||
|
@ -117,9 +116,6 @@ async function runConsoleTests(runJs, defaultReporter, runInParallel, watchMode,
|
|||
errorStatus = exitCode;
|
||||
error = new Error(`Process exited with status code ${errorStatus}.`);
|
||||
}
|
||||
else if (lintFlag) {
|
||||
await new Promise((resolve, reject) => gulp.start(["lint"], error => error ? reject(error) : resolve()));
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
errorStatus = undefined;
|
||||
|
@ -144,10 +140,10 @@ async function runConsoleTests(runJs, defaultReporter, runInParallel, watchMode,
|
|||
}
|
||||
exports.runConsoleTests = runConsoleTests;
|
||||
|
||||
function cleanTestDirs() {
|
||||
return del([exports.localBaseline, exports.localRwcBaseline])
|
||||
.then(() => mkdirP(exports.localRwcBaseline))
|
||||
.then(() => mkdirP(exports.localBaseline));
|
||||
async function cleanTestDirs() {
|
||||
await del([exports.localBaseline, exports.localRwcBaseline])
|
||||
mkdirP.sync(exports.localRwcBaseline);
|
||||
mkdirP.sync(exports.localBaseline);
|
||||
}
|
||||
exports.cleanTestDirs = cleanTestDirs;
|
||||
|
||||
|
|
|
@ -1,435 +0,0 @@
|
|||
// @ts-check
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util)
|
||||
const ts = require("../../lib/typescript");
|
||||
const { Duplex } = require("stream");
|
||||
const chalk = /**@type {*} */(require("chalk"));
|
||||
const Vinyl = require("vinyl");
|
||||
|
||||
/**
|
||||
* Creates a stream that passes through its inputs only if the project outputs are not up to date
|
||||
* with respect to the inputs.
|
||||
* @param {ParsedCommandLine} parsedProject
|
||||
* @param {UpToDateOptions} [options]
|
||||
*
|
||||
* @typedef UpToDateOptions
|
||||
* @property {boolean | "minimal"} [verbose]
|
||||
* @property {(configFilePath: string) => ParsedCommandLine | undefined} [parseProject]
|
||||
*/
|
||||
function upToDate(parsedProject, options) {
|
||||
/** @type {File[]} */
|
||||
const inputs = [];
|
||||
/** @type {Map<string, File>} */
|
||||
const inputMap = new Map();
|
||||
/** @type {Map<string, fs.Stats>} */
|
||||
const statCache = new Map();
|
||||
/** @type {UpToDateHost} */
|
||||
const upToDateHost = {
|
||||
fileExists(fileName) {
|
||||
const stats = getStat(fileName);
|
||||
return stats ? stats.isFile() : false;
|
||||
},
|
||||
getModifiedTime(fileName) {
|
||||
return getStat(fileName).mtime;
|
||||
},
|
||||
parseConfigFile: options && options.parseProject
|
||||
};
|
||||
const duplex = new Duplex({
|
||||
objectMode: true,
|
||||
/**
|
||||
* @param {string|Buffer|File} file
|
||||
*/
|
||||
write(file, _, cb) {
|
||||
if (typeof file === "string" || Buffer.isBuffer(file)) return cb(new Error("Only Vinyl files are supported."));
|
||||
inputs.push(file);
|
||||
inputMap.set(path.resolve(file.path), file);
|
||||
cb();
|
||||
},
|
||||
final(cb) {
|
||||
const status = getUpToDateStatus(upToDateHost, parsedProject);
|
||||
reportStatus(parsedProject, status, options);
|
||||
if (status.type !== UpToDateStatusType.UpToDate) {
|
||||
for (const input of inputs) duplex.push(input);
|
||||
}
|
||||
duplex.push(null);
|
||||
inputMap.clear();
|
||||
statCache.clear();
|
||||
cb();
|
||||
},
|
||||
read() {
|
||||
}
|
||||
});
|
||||
return duplex;
|
||||
|
||||
function getStat(fileName) {
|
||||
fileName = path.resolve(fileName);
|
||||
const inputFile = inputMap.get(fileName);
|
||||
if (inputFile && inputFile.stat) return inputFile.stat;
|
||||
|
||||
let stats = statCache.get(fileName);
|
||||
if (!stats && fs.existsSync(fileName)) {
|
||||
stats = fs.statSync(fileName);
|
||||
statCache.set(fileName, stats);
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
}
|
||||
module.exports = exports = upToDate;
|
||||
|
||||
/**
|
||||
* @param {DiagnosticMessage} message
|
||||
* @param {...string} args
|
||||
*/
|
||||
function formatMessage(message, ...args) {
|
||||
log.info(formatStringFromArgs(message.message, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ParsedCommandLine} project
|
||||
* @param {UpToDateStatus} status
|
||||
* @param {{verbose?: boolean | "minimal"}} options
|
||||
*/
|
||||
function reportStatus(project, status, options) {
|
||||
switch (options.verbose) {
|
||||
case "minimal":
|
||||
switch (status.type) {
|
||||
case UpToDateStatusType.UpToDate:
|
||||
log.info(`Project '${fileName(project.options.configFilePath)}' is up to date.`);
|
||||
break;
|
||||
default:
|
||||
log.info(`Project '${fileName(project.options.configFilePath)}' is out of date, rebuilding...`);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case true:
|
||||
/**@type {*}*/(ts).formatUpToDateStatus(project.options.configFilePath, status, fileName, formatMessage);
|
||||
break;
|
||||
}
|
||||
if (!options.verbose) return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} file
|
||||
* @private
|
||||
*/
|
||||
function normalizeSlashes(file) {
|
||||
return file.replace(/\\/g, "/");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} file
|
||||
* @private
|
||||
*/
|
||||
function fileName(file) {
|
||||
return chalk.cyan(normalizeSlashes(path.relative(process.cwd(), path.resolve(file))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {string[]} args
|
||||
* @param {number} [baseIndex]
|
||||
*/
|
||||
function formatStringFromArgs(text, args, baseIndex = 0) {
|
||||
return text.replace(/{(\d+)}/g, (_match, index) => args[+index + baseIndex]);
|
||||
}
|
||||
|
||||
const minimumDate = new Date(-8640000000000000);
|
||||
const maximumDate = new Date(8640000000000000);
|
||||
const missingFileModifiedTime = new Date(0);
|
||||
|
||||
/**
|
||||
* @typedef {0} UpToDateStatusType.Unbuildable
|
||||
* @typedef {1} UpToDateStatusType.UpToDate
|
||||
* @typedef {2} UpToDateStatusType.UpToDateWithUpstreamTypes
|
||||
* @typedef {3} UpToDateStatusType.OutputMissing
|
||||
* @typedef {4} UpToDateStatusType.OutOfDateWithSelf
|
||||
* @typedef {5} UpToDateStatusType.OutOfDateWithUpstream
|
||||
* @typedef {6} UpToDateStatusType.UpstreamOutOfDate
|
||||
* @typedef {7} UpToDateStatusType.UpstreamBlocked
|
||||
* @typedef {8} UpToDateStatusType.ComputingUpstream
|
||||
* @typedef {9} UpToDateStatusType.ContainerOnly
|
||||
* @enum {UpToDateStatusType.Unbuildable | UpToDateStatusType.UpToDate | UpToDateStatusType.UpToDateWithUpstreamTypes | UpToDateStatusType.OutputMissing | UpToDateStatusType.OutOfDateWithSelf | UpToDateStatusType.OutOfDateWithUpstream | UpToDateStatusType.UpstreamOutOfDate | UpToDateStatusType.UpstreamBlocked | UpToDateStatusType.ComputingUpstream | UpToDateStatusType.ContainerOnly}
|
||||
*/
|
||||
const UpToDateStatusType = {
|
||||
Unbuildable: /** @type {0} */(0),
|
||||
UpToDate: /** @type {1} */(1),
|
||||
UpToDateWithUpstreamTypes: /** @type {2} */(2),
|
||||
OutputMissing: /** @type {3} */(3),
|
||||
OutOfDateWithSelf: /** @type {4} */(4),
|
||||
OutOfDateWithUpstream: /** @type {5} */(5),
|
||||
UpstreamOutOfDate: /** @type {6} */(6),
|
||||
UpstreamBlocked: /** @type {7} */(7),
|
||||
ComputingUpstream: /** @type {8} */(8),
|
||||
ContainerOnly: /** @type {9} */(9),
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Date} date1
|
||||
* @param {Date} date2
|
||||
* @returns {Date}
|
||||
*/
|
||||
function newer(date1, date2) {
|
||||
return date2 > date1 ? date2 : date1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {UpToDateHost} host
|
||||
* @param {ParsedCommandLine | undefined} project
|
||||
* @returns {UpToDateStatus}
|
||||
*/
|
||||
function getUpToDateStatus(host, project) {
|
||||
if (project === undefined) return { type: UpToDateStatusType.Unbuildable, reason: "File deleted mid-build" };
|
||||
const prior = host.getLastStatus ? host.getLastStatus(project.options.configFilePath) : undefined;
|
||||
if (prior !== undefined) {
|
||||
return prior;
|
||||
}
|
||||
const actual = getUpToDateStatusWorker(host, project);
|
||||
if (host.setLastStatus) {
|
||||
host.setLastStatus(project.options.configFilePath, actual);
|
||||
}
|
||||
return actual;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {UpToDateHost} host
|
||||
* @param {ParsedCommandLine | undefined} project
|
||||
* @returns {UpToDateStatus}
|
||||
*/
|
||||
function getUpToDateStatusWorker(host, project) {
|
||||
/** @type {string} */
|
||||
let newestInputFileName = undefined;
|
||||
let newestInputFileTime = minimumDate;
|
||||
// Get timestamps of input files
|
||||
for (const inputFile of project.fileNames) {
|
||||
if (!host.fileExists(inputFile)) {
|
||||
return {
|
||||
type: UpToDateStatusType.Unbuildable,
|
||||
reason: `${inputFile} does not exist`
|
||||
};
|
||||
}
|
||||
|
||||
const inputTime = host.getModifiedTime(inputFile) || missingFileModifiedTime;
|
||||
if (inputTime > newestInputFileTime) {
|
||||
newestInputFileName = inputFile;
|
||||
newestInputFileTime = inputTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect the expected outputs of this project
|
||||
const outputs = /**@type {string[]}*/(/**@type {*}*/(ts).getAllProjectOutputs(project));
|
||||
|
||||
if (outputs.length === 0) {
|
||||
return {
|
||||
type: UpToDateStatusType.ContainerOnly
|
||||
};
|
||||
}
|
||||
|
||||
// Now see if all outputs are newer than the newest input
|
||||
let oldestOutputFileName = "(none)";
|
||||
let oldestOutputFileTime = maximumDate;
|
||||
let newestOutputFileName = "(none)";
|
||||
let newestOutputFileTime = minimumDate;
|
||||
/** @type {string | undefined} */
|
||||
let missingOutputFileName;
|
||||
let newestDeclarationFileContentChangedTime = minimumDate;
|
||||
let isOutOfDateWithInputs = false;
|
||||
for (const output of outputs) {
|
||||
// Output is missing; can stop checking
|
||||
// Don't immediately return because we can still be upstream-blocked, which is a higher-priority status
|
||||
if (!host.fileExists(output)) {
|
||||
missingOutputFileName = output;
|
||||
break;
|
||||
}
|
||||
|
||||
const outputTime = host.getModifiedTime(output) || missingFileModifiedTime;
|
||||
if (outputTime < oldestOutputFileTime) {
|
||||
oldestOutputFileTime = outputTime;
|
||||
oldestOutputFileName = output;
|
||||
}
|
||||
|
||||
// If an output is older than the newest input, we can stop checking
|
||||
// Don't immediately return because we can still be upstream-blocked, which is a higher-priority status
|
||||
if (outputTime < newestInputFileTime) {
|
||||
isOutOfDateWithInputs = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (outputTime > newestOutputFileTime) {
|
||||
newestOutputFileTime = outputTime;
|
||||
newestOutputFileName = output;
|
||||
}
|
||||
|
||||
// Keep track of when the most recent time a .d.ts file was changed.
|
||||
// In addition to file timestamps, we also keep track of when a .d.ts file
|
||||
// had its file touched but not had its contents changed - this allows us
|
||||
// to skip a downstream typecheck
|
||||
if (path.extname(output) === ".d.ts") {
|
||||
const unchangedTime = host.getUnchangedTime ? host.getUnchangedTime(output) : undefined;
|
||||
if (unchangedTime !== undefined) {
|
||||
newestDeclarationFileContentChangedTime = newer(unchangedTime, newestDeclarationFileContentChangedTime);
|
||||
}
|
||||
else {
|
||||
const outputModifiedTime = host.getModifiedTime(output) || missingFileModifiedTime;
|
||||
newestDeclarationFileContentChangedTime = newer(newestDeclarationFileContentChangedTime, outputModifiedTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let pseudoUpToDate = false;
|
||||
let usesPrepend = false;
|
||||
/** @type {string | undefined} */
|
||||
let upstreamChangedProject;
|
||||
if (project.projectReferences) {
|
||||
if (host.setLastStatus) host.setLastStatus(project.options.configFilePath, { type: UpToDateStatusType.ComputingUpstream });
|
||||
for (const ref of project.projectReferences) {
|
||||
usesPrepend = usesPrepend || !!(ref.prepend);
|
||||
const resolvedRef = ts.resolveProjectReferencePath(host, ref);
|
||||
const parsedRef = host.parseConfigFile ? host.parseConfigFile(resolvedRef) : ts.getParsedCommandLineOfConfigFile(resolvedRef, {}, parseConfigHost);
|
||||
const refStatus = getUpToDateStatus(host, parsedRef);
|
||||
|
||||
// Its a circular reference ignore the status of this project
|
||||
if (refStatus.type === UpToDateStatusType.ComputingUpstream) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// An upstream project is blocked
|
||||
if (refStatus.type === UpToDateStatusType.Unbuildable) {
|
||||
return {
|
||||
type: UpToDateStatusType.UpstreamBlocked,
|
||||
upstreamProjectName: ref.path
|
||||
};
|
||||
}
|
||||
|
||||
// If the upstream project is out of date, then so are we (someone shouldn't have asked, though?)
|
||||
if (refStatus.type !== UpToDateStatusType.UpToDate) {
|
||||
return {
|
||||
type: UpToDateStatusType.UpstreamOutOfDate,
|
||||
upstreamProjectName: ref.path
|
||||
};
|
||||
}
|
||||
|
||||
// If the upstream project's newest file is older than our oldest output, we
|
||||
// can't be out of date because of it
|
||||
if (refStatus.newestInputFileTime && refStatus.newestInputFileTime <= oldestOutputFileTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the upstream project has only change .d.ts files, and we've built
|
||||
// *after* those files, then we're "psuedo up to date" and eligible for a fast rebuild
|
||||
if (refStatus.newestDeclarationFileContentChangedTime && refStatus.newestDeclarationFileContentChangedTime <= oldestOutputFileTime) {
|
||||
pseudoUpToDate = true;
|
||||
upstreamChangedProject = ref.path;
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have an output older than an upstream output - we are out of date
|
||||
return {
|
||||
type: UpToDateStatusType.OutOfDateWithUpstream,
|
||||
outOfDateOutputFileName: oldestOutputFileName,
|
||||
newerProjectName: ref.path
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (missingOutputFileName !== undefined) {
|
||||
return {
|
||||
type: UpToDateStatusType.OutputMissing,
|
||||
missingOutputFileName
|
||||
};
|
||||
}
|
||||
|
||||
if (isOutOfDateWithInputs) {
|
||||
return {
|
||||
type: UpToDateStatusType.OutOfDateWithSelf,
|
||||
outOfDateOutputFileName: oldestOutputFileName,
|
||||
newerInputFileName: newestInputFileName
|
||||
};
|
||||
}
|
||||
|
||||
if (usesPrepend && pseudoUpToDate) {
|
||||
return {
|
||||
type: UpToDateStatusType.OutOfDateWithUpstream,
|
||||
outOfDateOutputFileName: oldestOutputFileName,
|
||||
newerProjectName: upstreamChangedProject
|
||||
};
|
||||
}
|
||||
|
||||
// Up to date
|
||||
return {
|
||||
type: pseudoUpToDate ? UpToDateStatusType.UpToDateWithUpstreamTypes : UpToDateStatusType.UpToDate,
|
||||
newestDeclarationFileContentChangedTime,
|
||||
newestInputFileTime,
|
||||
newestOutputFileTime,
|
||||
newestInputFileName,
|
||||
newestOutputFileName,
|
||||
oldestOutputFileName
|
||||
};
|
||||
}
|
||||
|
||||
const parseConfigHost = {
|
||||
useCaseSensitiveFileNames: true,
|
||||
getCurrentDirectory: () => process.cwd(),
|
||||
readDirectory: (file) => fs.readdirSync(file),
|
||||
fileExists: file => fs.existsSync(file) && fs.statSync(file).isFile(),
|
||||
readFile: file => fs.readFileSync(file, "utf8"),
|
||||
onUnRecoverableConfigFileDiagnostic: () => undefined
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {import("vinyl")} File
|
||||
* @typedef {import("../../lib/typescript").ParsedCommandLine & { options: CompilerOptions }} ParsedCommandLine
|
||||
* @typedef {import("../../lib/typescript").CompilerOptions & { configFilePath?: string }} CompilerOptions
|
||||
* @typedef {import("../../lib/typescript").DiagnosticMessage} DiagnosticMessage
|
||||
* @typedef UpToDateHost
|
||||
* @property {(fileName: string) => boolean} fileExists
|
||||
* @property {(fileName: string) => Date} getModifiedTime
|
||||
* @property {(fileName: string) => Date} [getUnchangedTime]
|
||||
* @property {(configFilePath: string) => ParsedCommandLine | undefined} parseConfigFile
|
||||
* @property {(configFilePath: string) => UpToDateStatus} [getLastStatus]
|
||||
* @property {(configFilePath: string, status: UpToDateStatus) => void} [setLastStatus]
|
||||
*
|
||||
* @typedef Status.Unbuildable
|
||||
* @property {UpToDateStatusType.Unbuildable} type
|
||||
* @property {string} reason
|
||||
*
|
||||
* @typedef Status.ContainerOnly
|
||||
* @property {UpToDateStatusType.ContainerOnly} type
|
||||
*
|
||||
* @typedef Status.UpToDate
|
||||
* @property {UpToDateStatusType.UpToDate | UpToDateStatusType.UpToDateWithUpstreamTypes} type
|
||||
* @property {Date} [newestInputFileTime]
|
||||
* @property {string} [newestInputFileName]
|
||||
* @property {Date} [newestDeclarationFileContentChangedTime]
|
||||
* @property {Date} [newestOutputFileTime]
|
||||
* @property {string} [newestOutputFileName]
|
||||
* @property {string} [oldestOutputFileName]
|
||||
*
|
||||
* @typedef Status.OutputMissing
|
||||
* @property {UpToDateStatusType.OutputMissing} type
|
||||
* @property {string} missingOutputFileName
|
||||
*
|
||||
* @typedef Status.OutOfDateWithSelf
|
||||
* @property {UpToDateStatusType.OutOfDateWithSelf} type
|
||||
* @property {string} outOfDateOutputFileName
|
||||
* @property {string} newerInputFileName
|
||||
*
|
||||
* @typedef Status.UpstreamOutOfDate
|
||||
* @property {UpToDateStatusType.UpstreamOutOfDate} type
|
||||
* @property {string} upstreamProjectName
|
||||
*
|
||||
* @typedef Status.UpstreamBlocked
|
||||
* @property {UpToDateStatusType.UpstreamBlocked} type
|
||||
* @property {string} upstreamProjectName
|
||||
*
|
||||
* @typedef Status.ComputingUpstream
|
||||
* @property {UpToDateStatusType.ComputingUpstream} type
|
||||
*
|
||||
* @typedef Status.OutOfDateWithUpstream
|
||||
* @property {UpToDateStatusType.OutOfDateWithUpstream} type
|
||||
* @property {string} outOfDateOutputFileName
|
||||
* @property {string} newerProjectName
|
||||
|
||||
* @typedef {Status.Unbuildable | Status.ContainerOnly | Status.UpToDate | Status.OutputMissing | Status.OutOfDateWithSelf | Status.UpstreamOutOfDate | Status.UpstreamBlocked | Status.ComputingUpstream | Status.OutOfDateWithUpstream} UpToDateStatus
|
||||
*/
|
||||
void 0;
|
|
@ -1,7 +1,119 @@
|
|||
// @ts-check
|
||||
/// <reference path="../types/ambient.d.ts" />
|
||||
|
||||
const fs = require("fs");
|
||||
const File = require("./vinyl");
|
||||
const { Readable } = require("stream");
|
||||
const path = require("path");
|
||||
const log = require("fancy-log");
|
||||
const mkdirp = require("mkdirp");
|
||||
const del = require("del");
|
||||
const File = require("vinyl");
|
||||
const ts = require("../../lib/typescript");
|
||||
const { default: chalk } = require("chalk");
|
||||
const { spawn } = require("child_process");
|
||||
const { CancellationToken, CancelError, Deferred } = require("prex");
|
||||
const { Readable, Duplex } = require("stream");
|
||||
|
||||
const isWindows = /^win/.test(process.platform);
|
||||
|
||||
/**
|
||||
* Executes the provided command once with the supplied arguments.
|
||||
* @param {string} cmd
|
||||
* @param {string[]} args
|
||||
* @param {ExecOptions} [options]
|
||||
*
|
||||
* @typedef ExecOptions
|
||||
* @property {boolean} [ignoreExitCode]
|
||||
* @property {import("prex").CancellationToken} [cancelToken]
|
||||
* @property {boolean} [hidePrompt]
|
||||
*/
|
||||
function exec(cmd, args, options = {}) {
|
||||
return /**@type {Promise<{exitCode: number}>}*/(new Promise((resolve, reject) => {
|
||||
const { ignoreExitCode, cancelToken = CancellationToken.none } = options;
|
||||
cancelToken.throwIfCancellationRequested();
|
||||
|
||||
// TODO (weswig): Update child_process types to add windowsVerbatimArguments to the type definition
|
||||
const subshellFlag = isWindows ? "/c" : "-c";
|
||||
const command = isWindows ? [possiblyQuote(cmd), ...args] : [`${cmd} ${args.join(" ")}`];
|
||||
|
||||
if (!options.hidePrompt) log(`> ${chalk.green(cmd)} ${args.join(" ")}`);
|
||||
const proc = spawn(isWindows ? "cmd" : "/bin/sh", [subshellFlag, ...command], { stdio: "inherit", windowsVerbatimArguments: true });
|
||||
const registration = cancelToken.register(() => {
|
||||
log(`${chalk.red("killing")} '${chalk.green(cmd)} ${args.join(" ")}'...`);
|
||||
proc.kill("SIGINT");
|
||||
proc.kill("SIGTERM");
|
||||
reject(new CancelError());
|
||||
});
|
||||
proc.on("exit", exitCode => {
|
||||
registration.unregister();
|
||||
if (exitCode === 0 || ignoreExitCode) {
|
||||
resolve({ exitCode });
|
||||
}
|
||||
else {
|
||||
reject(new Error(`Process exited with code: ${exitCode}`));
|
||||
}
|
||||
});
|
||||
proc.on("error", error => {
|
||||
registration.unregister();
|
||||
reject(error);
|
||||
});
|
||||
}));
|
||||
}
|
||||
exports.exec = exec;
|
||||
|
||||
/**
|
||||
* @param {string} cmd
|
||||
*/
|
||||
function possiblyQuote(cmd) {
|
||||
return cmd.indexOf(" ") >= 0 ? `"${cmd}"` : cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ts.Diagnostic[]} diagnostics
|
||||
* @param {{ cwd?: string, pretty?: boolean }} [options]
|
||||
*/
|
||||
function formatDiagnostics(diagnostics, options) {
|
||||
return options && options.pretty
|
||||
? ts.formatDiagnosticsWithColorAndContext(diagnostics, getFormatDiagnosticsHost(options && options.cwd))
|
||||
: ts.formatDiagnostics(diagnostics, getFormatDiagnosticsHost(options && options.cwd));
|
||||
}
|
||||
exports.formatDiagnostics = formatDiagnostics;
|
||||
|
||||
/**
|
||||
* @param {ts.Diagnostic[]} diagnostics
|
||||
* @param {{ cwd?: string }} [options]
|
||||
*/
|
||||
function reportDiagnostics(diagnostics, options) {
|
||||
log(formatDiagnostics(diagnostics, { cwd: options && options.cwd, pretty: process.stdout.isTTY }));
|
||||
}
|
||||
exports.reportDiagnostics = reportDiagnostics;
|
||||
|
||||
/**
|
||||
* @param {string | undefined} cwd
|
||||
* @returns {ts.FormatDiagnosticsHost}
|
||||
*/
|
||||
function getFormatDiagnosticsHost(cwd) {
|
||||
return {
|
||||
getCanonicalFileName: fileName => fileName,
|
||||
getCurrentDirectory: () => cwd,
|
||||
getNewLine: () => ts.sys.newLine,
|
||||
};
|
||||
}
|
||||
exports.getFormatDiagnosticsHost = getFormatDiagnosticsHost;
|
||||
|
||||
/**
|
||||
* Reads JSON data with optional comments using the LKG TypeScript compiler
|
||||
* @param {string} jsonPath
|
||||
*/
|
||||
function readJson(jsonPath) {
|
||||
const jsonText = fs.readFileSync(jsonPath, "utf8");
|
||||
const result = ts.parseConfigFileTextToJson(jsonPath, jsonText);
|
||||
if (result.error) {
|
||||
reportDiagnostics([result.error]);
|
||||
throw new Error("An error occurred during parse.");
|
||||
}
|
||||
return result.config;
|
||||
}
|
||||
exports.readJson = readJson;
|
||||
|
||||
/**
|
||||
* @param {File} file
|
||||
|
@ -24,4 +136,299 @@ function streamFromBuffer(buffer) {
|
|||
}
|
||||
});
|
||||
}
|
||||
exports.streamFromBuffer = streamFromBuffer;
|
||||
exports.streamFromBuffer = streamFromBuffer;
|
||||
|
||||
/**
|
||||
* @param {string | string[]} source
|
||||
* @param {string | string[]} dest
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function needsUpdate(source, dest) {
|
||||
if (typeof source === "string" && typeof dest === "string") {
|
||||
if (fs.existsSync(dest)) {
|
||||
const {mtime: outTime} = fs.statSync(dest);
|
||||
const {mtime: inTime} = fs.statSync(source);
|
||||
if (+inTime <= +outTime) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (typeof source === "string" && typeof dest !== "string") {
|
||||
const {mtime: inTime} = fs.statSync(source);
|
||||
for (const filepath of dest) {
|
||||
if (fs.existsSync(filepath)) {
|
||||
const {mtime: outTime} = fs.statSync(filepath);
|
||||
if (+inTime > +outTime) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (typeof source !== "string" && typeof dest === "string") {
|
||||
if (fs.existsSync(dest)) {
|
||||
const {mtime: outTime} = fs.statSync(dest);
|
||||
for (const filepath of source) {
|
||||
if (fs.existsSync(filepath)) {
|
||||
const {mtime: inTime} = fs.statSync(filepath);
|
||||
if (+inTime > +outTime) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (typeof source !== "string" && typeof dest !== "string") {
|
||||
for (let i = 0; i < source.length; i++) {
|
||||
if (!dest[i]) {
|
||||
continue;
|
||||
}
|
||||
if (fs.existsSync(dest[i])) {
|
||||
const {mtime: outTime} = fs.statSync(dest[i]);
|
||||
const {mtime: inTime} = fs.statSync(source[i]);
|
||||
if (+inTime > +outTime) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
exports.needsUpdate = needsUpdate;
|
||||
|
||||
function getDiffTool() {
|
||||
const program = process.env.DIFF;
|
||||
if (!program) {
|
||||
log.warn("Add the 'DIFF' environment variable to the path of the program you want to use.");
|
||||
process.exit(1);
|
||||
}
|
||||
return program;
|
||||
}
|
||||
exports.getDiffTool = getDiffTool;
|
||||
|
||||
/**
|
||||
* Find the size of a directory recursively.
|
||||
* Symbolic links can cause a loop.
|
||||
* @param {string} root
|
||||
* @returns {number} bytes
|
||||
*/
|
||||
function getDirSize(root) {
|
||||
const stats = fs.lstatSync(root);
|
||||
|
||||
if (!stats.isDirectory()) {
|
||||
return stats.size;
|
||||
}
|
||||
|
||||
return fs.readdirSync(root)
|
||||
.map(file => getDirSize(path.join(root, file)))
|
||||
.reduce((acc, num) => acc + num, 0);
|
||||
}
|
||||
exports.getDirSize = getDirSize;
|
||||
|
||||
/**
|
||||
* Flattens a project with project references into a single project.
|
||||
* @param {string} projectSpec The path to a tsconfig.json file or its containing directory.
|
||||
* @param {string} flattenedProjectSpec The output path for the flattened tsconfig.json file.
|
||||
* @param {FlattenOptions} [options] Options used to flatten a project hierarchy.
|
||||
*
|
||||
* @typedef FlattenOptions
|
||||
* @property {string} [cwd] The path to use for the current working directory. Defaults to `process.cwd()`.
|
||||
* @property {import("../../lib/typescript").CompilerOptions} [compilerOptions] Compiler option overrides.
|
||||
* @property {boolean} [force] Forces creation of the output project.
|
||||
* @property {string[]} [exclude] Files to exclude (relative to `cwd`)
|
||||
*/
|
||||
function flatten(projectSpec, flattenedProjectSpec, options = {}) {
|
||||
const cwd = normalizeSlashes(options.cwd ? path.resolve(options.cwd) : process.cwd());
|
||||
const files = [];
|
||||
const resolvedOutputSpec = path.resolve(cwd, flattenedProjectSpec);
|
||||
const resolvedOutputDirectory = path.dirname(resolvedOutputSpec);
|
||||
const resolvedProjectSpec = resolveProjectSpec(projectSpec, cwd, undefined);
|
||||
const project = readJson(resolvedProjectSpec);
|
||||
const skipProjects = /**@type {Set<string>}*/(new Set());
|
||||
const skipFiles = new Set(options && options.exclude && options.exclude.map(file => normalizeSlashes(path.resolve(cwd, file))));
|
||||
recur(resolvedProjectSpec, project);
|
||||
|
||||
if (options.force || needsUpdate(files, resolvedOutputSpec)) {
|
||||
const config = {
|
||||
extends: normalizeSlashes(path.relative(resolvedOutputDirectory, resolvedProjectSpec)),
|
||||
compilerOptions: options.compilerOptions || {},
|
||||
files: files.map(file => normalizeSlashes(path.relative(resolvedOutputDirectory, file)))
|
||||
};
|
||||
mkdirp.sync(resolvedOutputDirectory);
|
||||
fs.writeFileSync(resolvedOutputSpec, JSON.stringify(config, undefined, 2), "utf8");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} projectSpec
|
||||
* @param {object} project
|
||||
*/
|
||||
function recur(projectSpec, project) {
|
||||
if (skipProjects.has(projectSpec)) return;
|
||||
skipProjects.add(project);
|
||||
if (project.references) {
|
||||
for (const ref of project.references) {
|
||||
const referencedSpec = resolveProjectSpec(ref.path, cwd, projectSpec);
|
||||
const referencedProject = readJson(referencedSpec);
|
||||
recur(referencedSpec, referencedProject);
|
||||
}
|
||||
}
|
||||
if (project.include) {
|
||||
throw new Error("Flattened project may not have an 'include' list.");
|
||||
}
|
||||
if (!project.files) {
|
||||
throw new Error("Flattened project must have an explicit 'files' list.");
|
||||
}
|
||||
const projectDirectory = path.dirname(projectSpec);
|
||||
for (let file of project.files) {
|
||||
file = normalizeSlashes(path.resolve(projectDirectory, file));
|
||||
if (skipFiles.has(file)) continue;
|
||||
skipFiles.add(file);
|
||||
files.push(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.flatten = flatten;
|
||||
|
||||
/**
|
||||
* @param {string} file
|
||||
*/
|
||||
function normalizeSlashes(file) {
|
||||
return file.replace(/\\/g, "/");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} projectSpec
|
||||
* @param {string} cwd
|
||||
* @param {string | undefined} referrer
|
||||
* @returns {string}
|
||||
*/
|
||||
function resolveProjectSpec(projectSpec, cwd, referrer) {
|
||||
let projectPath = normalizeSlashes(path.resolve(cwd, referrer ? path.dirname(referrer) : "", projectSpec));
|
||||
const stats = fs.statSync(projectPath);
|
||||
if (stats.isFile()) return normalizeSlashes(projectPath);
|
||||
return normalizeSlashes(path.resolve(cwd, projectPath, "tsconfig.json"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | ((file: File) => string) | { cwd?: string }} [dest]
|
||||
* @param {{ cwd?: string }} [opts]
|
||||
*/
|
||||
function rm(dest, opts) {
|
||||
if (dest && typeof dest === "object") opts = dest, dest = undefined;
|
||||
let failed = false;
|
||||
|
||||
const cwd = path.resolve(opts && opts.cwd || process.cwd());
|
||||
|
||||
/** @type {{ file: File, deleted: boolean, promise: Promise<any>, cb: Function }[]} */
|
||||
const pending = [];
|
||||
|
||||
const processDeleted = () => {
|
||||
if (failed) return;
|
||||
while (pending.length && pending[0].deleted) {
|
||||
const { file, cb } = pending.shift();
|
||||
duplex.push(file);
|
||||
cb();
|
||||
}
|
||||
};
|
||||
|
||||
const duplex = new Duplex({
|
||||
objectMode: true,
|
||||
/**
|
||||
* @param {string|Buffer|File} file
|
||||
*/
|
||||
write(file, _, cb) {
|
||||
if (failed) return;
|
||||
if (typeof file === "string" || Buffer.isBuffer(file)) return cb(new Error("Only Vinyl files are supported."));
|
||||
const basePath = typeof dest === "string" ? path.resolve(cwd, dest) :
|
||||
typeof dest === "function" ? path.resolve(cwd, dest(file)) :
|
||||
file.base;
|
||||
const filePath = path.resolve(basePath, file.relative);
|
||||
file.cwd = cwd;
|
||||
file.base = basePath;
|
||||
file.path = filePath;
|
||||
const entry = {
|
||||
file,
|
||||
deleted: false,
|
||||
cb,
|
||||
promise: del(file.path).then(() => {
|
||||
entry.deleted = true;
|
||||
processDeleted();
|
||||
}, err => {
|
||||
failed = true;
|
||||
pending.length = 0;
|
||||
cb(err);
|
||||
})
|
||||
};
|
||||
pending.push(entry);
|
||||
},
|
||||
final(cb) {
|
||||
processDeleted();
|
||||
if (pending.length) {
|
||||
Promise
|
||||
.all(pending.map(entry => entry.promise))
|
||||
.then(() => processDeleted())
|
||||
.then(() => cb(), cb);
|
||||
return;
|
||||
}
|
||||
cb();
|
||||
},
|
||||
read() {
|
||||
}
|
||||
});
|
||||
return duplex;
|
||||
}
|
||||
exports.rm = rm;
|
||||
|
||||
class Debouncer {
|
||||
/**
|
||||
* @param {number} timeout
|
||||
* @param {() => Promise<any>} action
|
||||
*/
|
||||
constructor(timeout, action) {
|
||||
this._timeout = timeout;
|
||||
this._action = action;
|
||||
}
|
||||
|
||||
enqueue() {
|
||||
if (this._timer) {
|
||||
clearTimeout(this._timer);
|
||||
this._timer = undefined;
|
||||
}
|
||||
|
||||
if (!this._deferred) {
|
||||
this._deferred = new Deferred();
|
||||
}
|
||||
|
||||
this._timer = setTimeout(() => this.run(), 100);
|
||||
return this._deferred.promise;
|
||||
}
|
||||
|
||||
run() {
|
||||
if (this._timer) {
|
||||
clearTimeout(this._timer);
|
||||
this._timer = undefined;
|
||||
}
|
||||
|
||||
const deferred = this._deferred;
|
||||
this._deferred = undefined;
|
||||
this._projects = undefined;
|
||||
try {
|
||||
deferred.resolve(this._action());
|
||||
}
|
||||
catch (e) {
|
||||
deferred.reject(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.Debouncer = Debouncer;
|
60
scripts/build/vinyl.d.ts
vendored
60
scripts/build/vinyl.d.ts
vendored
|
@ -1,60 +0,0 @@
|
|||
// NOTE: This makes it possible to correctly type vinyl Files under @ts-check.
|
||||
export = File;
|
||||
|
||||
declare class File<T extends File.Contents = File.Contents> {
|
||||
constructor(options?: File.VinylOptions<T>);
|
||||
|
||||
cwd: string;
|
||||
base: string;
|
||||
path: string;
|
||||
readonly history: ReadonlyArray<string>;
|
||||
contents: T;
|
||||
relative: string;
|
||||
dirname: string;
|
||||
basename: string;
|
||||
stem: string;
|
||||
extname: string;
|
||||
symlink: string | null;
|
||||
stat: import("fs").Stats | null;
|
||||
sourceMap?: import("./sourcemaps").RawSourceMap | string;
|
||||
|
||||
[custom: string]: any;
|
||||
|
||||
isBuffer(): this is T extends Buffer ? File<Buffer> : never;
|
||||
isStream(): this is T extends NodeJS.ReadableStream ? File<NodeJS.ReadableStream> : never;
|
||||
isNull(): this is T extends null ? File<null> : never;
|
||||
isDirectory(): this is T extends null ? File.Directory : never;
|
||||
isSymbolic(): this is T extends null ? File.Symbolic : never;
|
||||
clone(opts?: { contents?: boolean, deep?: boolean }): this;
|
||||
}
|
||||
|
||||
namespace File {
|
||||
export interface VinylOptions<T extends Contents = Contents> {
|
||||
cwd?: string;
|
||||
base?: string;
|
||||
path?: string;
|
||||
history?: ReadonlyArray<string>;
|
||||
stat?: import("fs").Stats;
|
||||
contents?: T;
|
||||
sourceMap?: import("./sourcemaps").RawSourceMap | string;
|
||||
[custom: string]: any;
|
||||
}
|
||||
|
||||
export type Contents = Buffer | NodeJS.ReadableStream | null;
|
||||
export type File = import("./vinyl");
|
||||
export type NullFile = File<null>;
|
||||
export type BufferFile = File<Buffer>;
|
||||
export type StreamFile = File<NodeJS.ReadableStream>;
|
||||
|
||||
export interface Directory extends NullFile {
|
||||
isNull(): true;
|
||||
isDirectory(): true;
|
||||
isSymbolic(): this is never;
|
||||
}
|
||||
|
||||
export interface Symbolic extends NullFile {
|
||||
isNull(): true;
|
||||
isDirectory(): this is never;
|
||||
isSymbolic(): true;
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
module.exports = require("vinyl");
|
77
scripts/types/ambient.d.ts
vendored
77
scripts/types/ambient.d.ts
vendored
|
@ -1,3 +1,5 @@
|
|||
import { TaskFunction } from "gulp";
|
||||
|
||||
declare module "gulp-clone" {
|
||||
function Clone(): NodeJS.ReadWriteStream;
|
||||
namespace Clone {
|
||||
|
@ -14,3 +16,78 @@ declare module "gulp-insert" {
|
|||
}
|
||||
|
||||
declare module "sorcery";
|
||||
|
||||
declare module "vinyl" {
|
||||
// NOTE: This makes it possible to correctly type vinyl Files under @ts-check.
|
||||
export = File;
|
||||
|
||||
declare class File<T extends File.Contents = File.Contents> {
|
||||
constructor(options?: File.VinylOptions<T>);
|
||||
|
||||
cwd: string;
|
||||
base: string;
|
||||
path: string;
|
||||
readonly history: ReadonlyArray<string>;
|
||||
contents: T;
|
||||
relative: string;
|
||||
dirname: string;
|
||||
basename: string;
|
||||
stem: string;
|
||||
extname: string;
|
||||
symlink: string | null;
|
||||
stat: import("fs").Stats | null;
|
||||
sourceMap?: import("./sourcemaps").RawSourceMap | string;
|
||||
|
||||
[custom: string]: any;
|
||||
|
||||
isBuffer(): this is T extends Buffer ? File<Buffer> : never;
|
||||
isStream(): this is T extends NodeJS.ReadableStream ? File<NodeJS.ReadableStream> : never;
|
||||
isNull(): this is T extends null ? File<null> : never;
|
||||
isDirectory(): this is T extends null ? File.Directory : never;
|
||||
isSymbolic(): this is T extends null ? File.Symbolic : never;
|
||||
clone(opts?: { contents?: boolean, deep?: boolean }): this;
|
||||
}
|
||||
|
||||
namespace File {
|
||||
export interface VinylOptions<T extends Contents = Contents> {
|
||||
cwd?: string;
|
||||
base?: string;
|
||||
path?: string;
|
||||
history?: ReadonlyArray<string>;
|
||||
stat?: import("fs").Stats;
|
||||
contents?: T;
|
||||
sourceMap?: import("./sourcemaps").RawSourceMap | string;
|
||||
[custom: string]: any;
|
||||
}
|
||||
|
||||
export type Contents = Buffer | NodeJS.ReadableStream | null;
|
||||
export type File = import("./vinyl");
|
||||
export type NullFile = File<null>;
|
||||
export type BufferFile = File<Buffer>;
|
||||
export type StreamFile = File<NodeJS.ReadableStream>;
|
||||
|
||||
export interface Directory extends NullFile {
|
||||
isNull(): true;
|
||||
isDirectory(): true;
|
||||
isSymbolic(): this is never;
|
||||
}
|
||||
|
||||
export interface Symbolic extends NullFile {
|
||||
isNull(): true;
|
||||
isDirectory(): this is never;
|
||||
isSymbolic(): true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare module "undertaker" {
|
||||
interface TaskFunctionParams {
|
||||
flags?: Record<string, string>;
|
||||
}
|
||||
}
|
||||
|
||||
declare module "gulp-sourcemaps" {
|
||||
interface WriteOptions {
|
||||
destPath?: string;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue