From 0d08c01f7874da2f932e4d4e4d42b1c43be88111 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 14 May 2026 18:27:46 +0100 Subject: [PATCH] Auto-generate shared bundle --- build.mjs | 54 ++++++++++++++++++++++++++++++++++++--- lib/entry-points.js | 50 ++++++++++++++++++------------------ src/entry-points.ts | 55 ---------------------------------------- src/entry-wrapper.js.tpl | 3 +++ 4 files changed, 79 insertions(+), 83 deletions(-) delete mode 100644 src/entry-points.ts create mode 100644 src/entry-wrapper.js.tpl diff --git a/build.mjs b/build.mjs index 8bf1e356c..7dea367fc 100644 --- a/build.mjs +++ b/build.mjs @@ -1,5 +1,5 @@ import { copyFile, readFile, rm, writeFile } from "node:fs/promises"; -import { dirname, join } from "node:path"; +import { basename, dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; import * as esbuild from "esbuild"; @@ -62,8 +62,14 @@ const onEndPlugin = { }, }; +/** The name of the virtual `entry-points` module. */ +const SHARED_ENTRYPOINT = "entry-points"; + /** - * Emit a tiny stub file for each Action entrypoint. Each stub imports the shared bundle + * This plugin finds all source files that contain action entry points. + * It then generates the virtual `entry-points` module which imports all identifies files, + * and re-exports their `runWrapper` functions with suitable aliases. + * A tiny stub file is emitted for each Action entrypoint. Each stub imports the shared bundle * and calls the respective entry point. * * @type {esbuild.Plugin} @@ -71,6 +77,7 @@ const onEndPlugin = { const entryPointsPlugin = { name: "entry-points", setup(build) { + const namespace = "actions"; const actions = []; const toPascal = (s) => @@ -93,6 +100,44 @@ const entryPointsPlugin = { } }); + // Resolve the virtual `entry-points` file and set the corresponding namespace. + // Ideally, we'd `RegExp.escape` the entrypoint here, but that API isn't supported in Node 20. + // Since we're dealing with a hardcoded string, this isn't too much of a problem. + build.onResolve({ filter: new RegExp(`^${SHARED_ENTRYPOINT}$`) }, () => { + return { path: SHARED_ENTRYPOINT, namespace }; + }); + + // Generate the virtual `entry-points` file based on the actions we discovered. + // Restrict using the namespace. The path filter does not need to discriminate any further. + build.onLoad({ filter: /.*/, namespace }, async () => { + const wrapperTemplatePath = "entry-wrapper.js.tpl"; + const wrapperTemplate = await readFile( + join(SRC_DIR, wrapperTemplatePath), + "utf-8", + ); + + const actionsSorted = actions.sort((a, b) => + a.name.localeCompare(b.name), + ); + const imports = actionsSorted + .map( + (action) => + `import * as ${action.pascalCaseName} from "./src/${basename(action.path)}"`, + ) + .join("\n"); + const wrappers = actionsSorted + .map((action) => + wrapperTemplate.replaceAll("__ACTION__", action.pascalCaseName), + ) + .join("\n\n"); + + return { + contents: `"use strict";\n${imports}\n\n${wrappers}\n`, + resolveDir: ".", + loader: "ts", + }; + }); + // Emit entry point stubs for each action using the entry template. build.onEnd(async (result) => { // Read the entry point template. @@ -119,7 +164,10 @@ const entryPointsPlugin = { const context = await esbuild.context({ // Include upload-lib.ts as an entry point for use in testing environments. - entryPoints: globSync(["src/entry-points.ts", "src/upload-lib.ts"]), + entryPoints: [ + { in: SHARED_ENTRYPOINT, out: SHARED_ENTRYPOINT }, + join(SRC_DIR, "upload-lib.ts"), + ], bundle: true, format: "cjs", outdir: OUT_DIR, diff --git a/lib/entry-points.js b/lib/entry-points.js index cf8b7964b..ee4eaaae1 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -144935,7 +144935,7 @@ var require_lib6 = __commonJS({ } }); -// src/entry-points.ts +// actions:entry-points var entry_points_exports = {}; __export(entry_points_exports, { runAnalyzeAction: () => runAnalyzeAction, @@ -161198,39 +161198,39 @@ async function runWrapper11() { } } -// src/entry-points.ts +// actions:entry-points async function runAnalyzeAction() { - void runWrapper(); -} -async function runAutobuildAction() { - void runWrapper3(); -} -async function runInitAction() { - void runWrapper4(); -} -async function runResolveEnvironmentAction() { - void runWrapper6(); -} -async function runSetupCodeqlAction() { - void runWrapper7(); -} -async function runStartProxyAction() { - void runWrapper8(); -} -async function runUploadSarifAction() { - void runWrapper10(); + return await runWrapper(); } async function runAnalyzePostAction() { - void runWrapper2(); + return await runWrapper2(); +} +async function runAutobuildAction() { + return await runWrapper3(); +} +async function runInitAction() { + return await runWrapper4(); } async function runInitPostAction() { - void runWrapper5(); + return await runWrapper5(); +} +async function runResolveEnvironmentAction() { + return await runWrapper6(); +} +async function runSetupCodeqlAction() { + return await runWrapper7(); +} +async function runStartProxyAction() { + return await runWrapper8(); } async function runStartProxyPostAction() { - void runWrapper9(); + return await runWrapper9(); +} +async function runUploadSarifAction() { + return await runWrapper10(); } async function runUploadSarifPostAction() { - void runWrapper11(); + return await runWrapper11(); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { diff --git a/src/entry-points.ts b/src/entry-points.ts deleted file mode 100644 index 7d9e55678..000000000 --- a/src/entry-points.ts +++ /dev/null @@ -1,55 +0,0 @@ -import * as analyzeAction from "./analyze-action"; -import * as analyzePostAction from "./analyze-action-post"; -import * as autobuildAction from "./autobuild-action"; -import * as initAction from "./init-action"; -import * as initPostAction from "./init-action-post"; -import * as resolveEnvironmentAction from "./resolve-environment-action"; -import * as setupCodeqlAction from "./setup-codeql-action"; -import * as startProxyAction from "./start-proxy-action"; -import * as startProxyPostAction from "./start-proxy-action-post"; -import * as uploadSarifAction from "./upload-sarif-action"; -import * as uploadSarifPostAction from "./upload-sarif-action-post"; - -export async function runAnalyzeAction() { - void analyzeAction.runWrapper(); -} - -export async function runAutobuildAction() { - void autobuildAction.runWrapper(); -} - -export async function runInitAction() { - void initAction.runWrapper(); -} - -export async function runResolveEnvironmentAction() { - void resolveEnvironmentAction.runWrapper(); -} - -export async function runSetupCodeqlAction() { - void setupCodeqlAction.runWrapper(); -} - -export async function runStartProxyAction() { - void startProxyAction.runWrapper(); -} - -export async function runUploadSarifAction() { - void uploadSarifAction.runWrapper(); -} - -export async function runAnalyzePostAction() { - void analyzePostAction.runWrapper(); -} - -export async function runInitPostAction() { - void initPostAction.runWrapper(); -} - -export async function runStartProxyPostAction() { - void startProxyPostAction.runWrapper(); -} - -export async function runUploadSarifPostAction() { - void uploadSarifPostAction.runWrapper(); -} diff --git a/src/entry-wrapper.js.tpl b/src/entry-wrapper.js.tpl new file mode 100644 index 000000000..f84e7758c --- /dev/null +++ b/src/entry-wrapper.js.tpl @@ -0,0 +1,3 @@ +export async function run__ACTION__() { + return await __ACTION__.runWrapper(); +}