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:
Jake Bailey
2022-10-09 13:15:45 -07:00
parent f45cc4578e
commit 3cd72e76b2
32 changed files with 1330 additions and 9695 deletions

View File

@@ -26,4 +26,4 @@ export function findUpFile(name) {
/** @type {string | undefined} */
let findUpRootCache;
export const findUpRoot = () => findUpRootCache || (findUpRootCache = dirname(findUpFile("Gulpfile.mjs")));
export const findUpRoot = () => findUpRootCache || (findUpRootCache = dirname(findUpFile("Herebyfile.mjs")));

View File

@@ -49,7 +49,7 @@ const projectCleaner = new ProjectQueue((projects) => execTsc("--clean", ...proj
*/
export const cleanProject = (project) => projectCleaner.enqueue(project);
const projectWatcher = new ProjectQueue((projects) => execTsc("--watch", ...projects));
const projectWatcher = new ProjectQueue((projects) => execTsc("--watch", "--preserveWatchOutput", ...projects));
/**
* @param {string} project

View File

@@ -1,48 +0,0 @@
/**
* @param {string} message
* @returns {never}
*/
function fail(message) {
throw new Error(message);
}
/**
* @param {number} value
*/
function base64FormatEncode(value) {
return value < 0 ? fail("Invalid value") :
value < 26 ? 0x41 /*A*/ + value :
value < 52 ? 0x61 /*a*/ + value - 26 :
value < 62 ? 0x30 /*0*/ + value - 52 :
value === 62 ? 0x2B /*+*/ :
value === 63 ? 0x2F /*/*/ :
fail("Invalid value");
}
/**
* @param {number} value
*/
export function base64VLQFormatEncode(value) {
if (value < 0) {
value = ((-value) << 1) + 1;
}
else {
value = value << 1;
}
// Encode 5 bits at a time starting from least significant bits
let result = "";
do {
let currentDigit = value & 31; // 11111
value = value >> 5;
if (value > 0) {
// There are still more digits to decode, set the msb (6th bit)
currentDigit = currentDigit | 32;
}
result += String.fromCharCode(base64FormatEncode(currentDigit));
} while (value > 0);
return result;
}
/** @typedef {object} RawSourceMap */

View File

@@ -3,7 +3,6 @@ import fs from "fs";
import os from "os";
import path from "path";
import mkdirP from "mkdirp";
import log from "fancy-log";
import cmdLineOptions from "./options.mjs";
import { exec } from "./utils.mjs";
import { findUpFile, findUpRoot } from "./findUpDir.mjs";
@@ -19,9 +18,8 @@ export const localTest262Baseline = "internal/baselines/test262/local";
* @param {string} runJs
* @param {string} defaultReporter
* @param {boolean} runInParallel
* @param {boolean} _watchMode
*/
export async function runConsoleTests(runJs, defaultReporter, runInParallel, _watchMode) {
export async function runConsoleTests(runJs, defaultReporter, runInParallel) {
let testTimeout = cmdLineOptions.timeout;
const tests = cmdLineOptions.tests;
const inspect = cmdLineOptions.break || cmdLineOptions.inspect;
@@ -147,7 +145,7 @@ export async function cleanTestDirs() {
}
/**
* used to pass data from gulp command line directly to run.js
* used to pass data from command line directly to run.js
* @param {string} tests
* @param {string} runners
* @param {boolean} light
@@ -173,7 +171,7 @@ export function writeTestConfigFile(tests, runners, light, taskConfigsFolder, wo
shards,
shardId
});
log.info("Running tests with config: " + testConfigContents);
console.info("Running tests with config: " + testConfigContents);
fs.writeFileSync("test.config", testConfigContents);
}

View File

@@ -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;
};
}