diff --git a/extensions/ext-bundler-esbuild/src/plugin-adapter.ts b/extensions/ext-bundler-esbuild/src/plugin-adapter.ts index 2d909ef0b2..4544481feb 100644 --- a/extensions/ext-bundler-esbuild/src/plugin-adapter.ts +++ b/extensions/ext-bundler-esbuild/src/plugin-adapter.ts @@ -63,6 +63,7 @@ export function toEsbuildPlugin( namespace: args.namespace, suffix: args.suffix, pluginData: args.pluginData, + with: args.with, }; const result = await callback(loadArgs); if (result == null) return result ?? null; diff --git a/scripts/lint/check-sanitizer-baseline.ts b/scripts/lint/check-sanitizer-baseline.ts index 6545507214..ac39c14d10 100644 --- a/scripts/lint/check-sanitizer-baseline.ts +++ b/scripts/lint/check-sanitizer-baseline.ts @@ -28,7 +28,7 @@ import { // audits removed opt-outs. Platform/compat process and opaque-deps suites now // restore the globals and child processes they touch instead of suppressing // leak reports. -export const SANITIZER_OPT_OUT_BASELINE = 340; +export const SANITIZER_OPT_OUT_BASELINE = 338; const OPT_OUT_PATTERN = /sanitize(?:Resources|Ops|Exit)\s*:\s*false/g; diff --git a/src/extensions/bundler/bundler.ts b/src/extensions/bundler/bundler.ts index 2567aed188..5a4f5ac715 100644 --- a/src/extensions/bundler/bundler.ts +++ b/src/extensions/bundler/bundler.ts @@ -234,6 +234,8 @@ export interface OnLoadArgs { namespace: string; suffix?: string; pluginData?: unknown; + /** Import attributes of the import that loads the file. */ + with?: Record; } /** Result returned from an `onLoad` callback. */ diff --git a/src/routing/api/module-loader/compiled-cjs-bundling.test.ts b/src/routing/api/module-loader/compiled-cjs-bundling.test.ts new file mode 100644 index 0000000000..20eb7b5f81 --- /dev/null +++ b/src/routing/api/module-loader/compiled-cjs-bundling.test.ts @@ -0,0 +1,1969 @@ +import "#veryfront/schemas/_test-setup.ts"; +import { assert, assertEquals, assertRejects, assertThrows } from "#veryfront/testing/assert.ts"; +import { afterEach, describe, it } from "#veryfront/testing/bdd.ts"; +import { type PluginBuild, stop as stopBundler, transform } from "veryfront/extensions/bundler"; +import { + bindDynamicImports, + builtinModuleName, + codeString, + createCompiledBuiltinPlugin, + createDependencyFilePredicate, + createDependencyResolvePlugin, + createImportExternalsPlugin, + createImportMetaResolve, + createNativeAddonPlugin, + createRuntimeRequire, + dependencyJsonLoad, + nodePreferredFile, + nodeRelativeFile, + PackageTypeLookup, + prepareCommonJSFile, + prepareDependencyFile, + prepareDependencyJson, + prepareModuleFile, + prependRuntimeRequire, + resolveLiteralCalls, + rewriteImportSpecifiers, + type RuntimeRequireHost, +} from "./compiled-cjs-bundling.ts"; + +type ResolveHandler = (args: Record) => unknown; +type Plugin = { setup(build: PluginBuild): void | Promise }; + +/** The onResolve or onLoad handlers a plugin registers, in order. */ +async function handlers(plugin: Plugin, hook: "onResolve" | "onLoad"): Promise { + const registered: ResolveHandler[] = []; + const register = (_options: unknown, handler: ResolveHandler) => registered.push(handler); + const build = { + onResolve: hook === "onResolve" ? register : () => {}, + onLoad: hook === "onLoad" ? register : () => {}, + onDispose: () => {}, + }; + await plugin.setup(build as unknown as PluginBuild); + return registered; +} + +const resolveHandlers = (plugin: Plugin) => handlers(plugin, "onResolve"); + +/** Throws the code of the error `fn` throws, or undefined. */ +function errorCode(fn: () => unknown): unknown { + try { + fn(); + } catch (error) { + return (error as { code?: unknown }).code; + } + return undefined; +} + +describe("routing/api/module-loader/compiled-cjs-bundling (inbox#4177)", () => { + describe("codeString()", () => { + it("writes a string literal that cannot end a script or a line", () => { + const value = "