mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-03-16 06:28:12 -05:00
Change build system to hereby
This eliminates a significant number of dependencies, eliminating all npm audit issues, speeding up `npm ci` by 20%, and overall making the build faster (faster startup, direct code is faster than streams, etc) and clearer to understand. I'm finding it much easier to make build changes for the module transform with this; I can more clearly indicate task dependencies and prevent running tasks that don't need to be run. Given we're changing our build process entirely (new deps, new steps), it seems like this is a good time to change things up.
This commit is contained in:
@@ -1,17 +1,11 @@
|
||||
/* eslint-disable no-restricted-globals */
|
||||
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
||||
/// <reference path="../types/ambient.d.ts" />
|
||||
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import log from "fancy-log";
|
||||
import del from "del";
|
||||
import File from "vinyl";
|
||||
import ts from "../../lib/typescript.js";
|
||||
import chalk from "chalk";
|
||||
import which from "which";
|
||||
import { spawn } from "child_process";
|
||||
import { Duplex } from "stream";
|
||||
import assert from "assert";
|
||||
|
||||
/**
|
||||
@@ -29,7 +23,7 @@ export async function exec(cmd, args, options = {}) {
|
||||
return /**@type {Promise<{exitCode?: number}>}*/(new Promise((resolve, reject) => {
|
||||
const { ignoreExitCode, waitForExit = true } = options;
|
||||
|
||||
if (!options.hidePrompt) log(`> ${chalk.green(cmd)} ${args.join(" ")}`);
|
||||
if (!options.hidePrompt) console.log(`> ${chalk.green(cmd)} ${args.join(" ")}`);
|
||||
const proc = spawn(which.sync(cmd), args, { stdio: waitForExit ? "inherit" : "ignore" });
|
||||
if (waitForExit) {
|
||||
proc.on("exit", exitCode => {
|
||||
@@ -67,7 +61,7 @@ function formatDiagnostics(diagnostics, options) {
|
||||
* @param {{ cwd?: string }} [options]
|
||||
*/
|
||||
function reportDiagnostics(diagnostics, options) {
|
||||
log(formatDiagnostics(diagnostics, { cwd: options && options.cwd, pretty: process.stdout.isTTY }));
|
||||
console.log(formatDiagnostics(diagnostics, { cwd: options && options.cwd, pretty: process.stdout.isTTY }));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,7 +161,7 @@ export function needsUpdate(source, dest) {
|
||||
export 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.");
|
||||
console.warn("Add the 'DIFF' environment variable to the path of the program you want to use.");
|
||||
process.exit(1);
|
||||
}
|
||||
return program;
|
||||
@@ -191,82 +185,6 @@ export function getDirSize(root) {
|
||||
.reduce((acc, num) => acc + num, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | ((file: File) => string) | { cwd?: string }} [dest]
|
||||
* @param {{ cwd?: string }} [opts]
|
||||
*/
|
||||
export 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 fileAndCallback = pending.shift();
|
||||
assert(fileAndCallback);
|
||||
const { file, cb } = fileAndCallback;
|
||||
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) {
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const endThenCb = () => (duplex.push(null), cb()); // signal end of read queue
|
||||
processDeleted();
|
||||
if (pending.length) {
|
||||
Promise
|
||||
.all(pending.map(entry => entry.promise))
|
||||
.then(() => processDeleted())
|
||||
.then(() => endThenCb(), endThenCb);
|
||||
return;
|
||||
}
|
||||
endThenCb();
|
||||
},
|
||||
read() {
|
||||
}
|
||||
});
|
||||
return duplex;
|
||||
}
|
||||
|
||||
class Deferred {
|
||||
constructor() {
|
||||
this.promise = new Promise((resolve, reject) => {
|
||||
@@ -317,3 +235,20 @@ export class Debouncer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const unset = Symbol();
|
||||
/**
|
||||
* @template T
|
||||
* @param {() => T} fn
|
||||
* @returns {() => T}
|
||||
*/
|
||||
export function memoize(fn) {
|
||||
/** @type {T | unset} */
|
||||
let value = unset;
|
||||
return () => {
|
||||
if (value === unset) {
|
||||
value = fn();
|
||||
}
|
||||
return value;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user