import type { AnyFunction, BuildConfig, BunPlugin, OnLoadCallback, OnLoadResult, OnLoadResultObject, OnLoadResultSourceCode, OnResolveCallback, PluginBuilder, PluginConstraints, } from "bun"; // This API expects 4 functions: // It should be generic enough to reuse for Bun.plugin() eventually, too. interface BundlerPlugin { onLoad: Map; onResolve: Map; onLoadAsync( internalID, sourceCode: string | Uint8Array | ArrayBuffer | DataView | null, loaderKey: number | null, ): void; onResolveAsync(internalID, a, b, c): void; addError(internalID, error, number): void; addFilter(filter, namespace, number): void; } // Extra types type Setup = BunPlugin["setup"]; type MinifyObj = Exclude; interface BuildConfigExt extends BuildConfig { // we support esbuild-style entryPoints entryPoints?: string[]; // plugins is guaranteed to not be null plugins: BunPlugin[]; } interface PluginBuilderExt extends PluginBuilder { // these functions aren't implemented yet, so we dont publicly expose them resolve: AnyFunction; onStart: AnyFunction; onEnd: AnyFunction; onDispose: AnyFunction; // we partially support initialOptions. it's read-only and a subset of // all options mapped to their esbuild names initialOptions: any; // we set this to an empty object esbuild: any; } export function runSetupFunction(this: BundlerPlugin, setup: Setup, config: BuildConfigExt) { var onLoadPlugins = new Map(); var onResolvePlugins = new Map(); function validate(filterObject: PluginConstraints, callback, map) { if (!filterObject || !$isObject(filterObject)) { throw new TypeError('Expected an object with "filter" RegExp'); } if (!callback || !$isCallable(callback)) { throw new TypeError("callback must be a function"); } var { filter, namespace = "file" } = filterObject; if (!filter) { throw new TypeError('Expected an object with "filter" RegExp'); } if (!$isRegExpObject(filter)) { throw new TypeError("filter must be a RegExp"); } if (namespace && !(typeof namespace === "string")) { throw new TypeError("namespace must be a string"); } if ((namespace?.length ?? 0) === 0) { namespace = "file"; } if (!/^([/$a-zA-Z0-9_\\-]+)$/.test(namespace)) { throw new TypeError("namespace can only contain $a-zA-Z0-9_\\-"); } var callbacks = map.$get(namespace); if (!callbacks) { map.$set(namespace, [[filter, callback]]); } else { $arrayPush(callbacks, [filter, callback]); } } function onLoad(filterObject, callback) { validate(filterObject, callback, onLoadPlugins); } function onResolve(filterObject, callback) { validate(filterObject, callback, onResolvePlugins); } const processSetupResult = () => { var anyOnLoad = false, anyOnResolve = false; for (var [namespace, callbacks] of onLoadPlugins.entries()) { for (var [filter] of callbacks) { this.addFilter(filter, namespace, 1); anyOnLoad = true; } } for (var [namespace, callbacks] of onResolvePlugins.entries()) { for (var [filter] of callbacks) { this.addFilter(filter, namespace, 0); anyOnResolve = true; } } if (anyOnResolve) { var onResolveObject = this.onResolve; if (!onResolveObject) { this.onResolve = onResolvePlugins; } else { for (var [namespace, callbacks] of onResolvePlugins.entries()) { var existing = onResolveObject.$get(namespace) as [RegExp, AnyFunction][]; if (!existing) { onResolveObject.$set(namespace, callbacks); } else { onResolveObject.$set(namespace, existing.concat(callbacks)); } } } } if (anyOnLoad) { var onLoadObject = this.onLoad; if (!onLoadObject) { this.onLoad = onLoadPlugins; } else { for (var [namespace, callbacks] of onLoadPlugins.entries()) { var existing = onLoadObject.$get(namespace) as [RegExp, AnyFunction][]; if (!existing) { onLoadObject.$set(namespace, callbacks); } else { onLoadObject.$set(namespace, existing.concat(callbacks)); } } } } return anyOnLoad || anyOnResolve; }; var setupResult = setup({ config: config, onDispose: notImplementedIssueFn(2771, "On-dispose callbacks"), onEnd: notImplementedIssueFn(2771, "On-end callbacks"), onLoad, onResolve, onStart: notImplementedIssueFn(2771, "On-start callbacks"), resolve: notImplementedIssueFn(2771, "build.resolve()"), // esbuild's options argument is different, we provide some interop initialOptions: { ...config, bundle: true, entryPoints: config.entrypoints ?? config.entryPoints ?? [], minify: typeof config.minify === "boolean" ? config.minify : false, minifyIdentifiers: config.minify === true || (config.minify as MinifyObj)?.identifiers, minifyWhitespace: config.minify === true || (config.minify as MinifyObj)?.whitespace, minifySyntax: config.minify === true || (config.minify as MinifyObj)?.syntax, outbase: config.root, platform: config.target === "bun" ? "node" : config.target, }, esbuild: {}, } satisfies PluginBuilderExt as PluginBuilder); if (setupResult && $isPromise(setupResult)) { if ($getPromiseInternalField(setupResult, $promiseFieldFlags) & $promiseStateFulfilled) { setupResult = $getPromiseInternalField(setupResult, $promiseFieldReactionsOrResult); } else { return setupResult.$then(processSetupResult); } } return processSetupResult(); } export function runOnResolvePlugins(this: BundlerPlugin, specifier, inputNamespace, importer, internalID, kindId) { // Must be kept in sync with ImportRecord.label const kind = $ImportKindIdToLabel[kindId]; var promiseResult: any = (async (inputPath, inputNamespace, importer, kind) => { var { onResolve, onLoad } = this; var results = onResolve.$get(inputNamespace); if (!results) { this.onResolveAsync(internalID, null, null, null); return null; } for (let [filter, callback] of results) { if (filter.test(inputPath)) { var result = callback({ path: inputPath, importer, namespace: inputNamespace, // resolveDir kind, // pluginData }); while ( result && $isPromise(result) && ($getPromiseInternalField(result, $promiseFieldFlags) & $promiseStateMask) === $promiseStateFulfilled ) { result = $getPromiseInternalField(result, $promiseFieldReactionsOrResult); } if (result && $isPromise(result)) { result = await result; } if (!result || !$isObject(result)) { continue; } var { path, namespace: userNamespace = inputNamespace, external } = result; if (!(typeof path === "string") || !(typeof userNamespace === "string")) { throw new TypeError("onResolve plugins must return an object with a string 'path' and string 'loader' field"); } if (!path) { continue; } if (!userNamespace) { userNamespace = inputNamespace; } if (typeof external !== "boolean" && !$isUndefinedOrNull(external)) { throw new TypeError('onResolve plugins "external" field must be boolean or unspecified'); } if (!external) { if (userNamespace === "file") { if (process.platform !== "win32") { if (path[0] !== "/" || path.includes("..")) { throw new TypeError('onResolve plugin "path" must be absolute when the namespace is "file"'); } } else { // TODO: Windows } } if (userNamespace === "dataurl") { if (!path.startsWith("data:")) { throw new TypeError('onResolve plugin "path" must start with "data:" when the namespace is "dataurl"'); } } if (userNamespace && userNamespace !== "file" && (!onLoad || !onLoad.$has(userNamespace))) { throw new TypeError(`Expected onLoad plugin for namespace ${userNamespace} to exist`); } } this.onResolveAsync(internalID, path, userNamespace, external); return null; } } this.onResolveAsync(internalID, null, null, null); return null; })(specifier, inputNamespace, importer, kind); while ( promiseResult && $isPromise(promiseResult) && ($getPromiseInternalField(promiseResult, $promiseFieldFlags) & $promiseStateMask) === $promiseStateFulfilled ) { promiseResult = $getPromiseInternalField(promiseResult, $promiseFieldReactionsOrResult); } if (promiseResult && $isPromise(promiseResult)) { promiseResult.then( () => {}, e => { this.addError(internalID, e, 0); }, ); } } export function runOnLoadPlugins(this: BundlerPlugin, internalID, path, namespace, defaultLoaderId) { const LOADERS_MAP = $LoaderLabelToId; const loaderName = $LoaderIdToLabel[defaultLoaderId]; var promiseResult = (async (internalID, path, namespace, defaultLoader) => { var results = this.onLoad.$get(namespace); if (!results) { this.onLoadAsync(internalID, null, null); return null; } for (let [filter, callback] of results) { if (filter.test(path)) { var result = callback({ path, namespace, // suffix // pluginData loader: defaultLoader, }); while ( result && $isPromise(result) && ($getPromiseInternalField(result, $promiseFieldFlags) & $promiseStateMask) === $promiseStateFulfilled ) { result = $getPromiseInternalField(result, $promiseFieldReactionsOrResult); } if (result && $isPromise(result)) { result = await result; } if (!result || !$isObject(result)) { continue; } var { contents, loader = defaultLoader } = result as OnLoadResultSourceCode & OnLoadResultObject; if (!(typeof contents === "string") && !$isTypedArrayView(contents)) { throw new TypeError('onLoad plugins must return an object with "contents" as a string or Uint8Array'); } if (!(typeof loader === "string")) { throw new TypeError('onLoad plugins must return an object with "loader" as a string'); } const chosenLoader = LOADERS_MAP[loader]; if (chosenLoader === undefined) { throw new TypeError(`Loader ${loader} is not supported.`); } this.onLoadAsync(internalID, contents, chosenLoader); return null; } } this.onLoadAsync(internalID, null, null); return null; })(internalID, path, namespace, loaderName); while ( promiseResult && $isPromise(promiseResult) && ($getPromiseInternalField(promiseResult, $promiseFieldFlags) & $promiseStateMask) === $promiseStateFulfilled ) { promiseResult = $getPromiseInternalField(promiseResult, $promiseFieldReactionsOrResult); } if (promiseResult && $isPromise(promiseResult)) { promiseResult.then( () => {}, e => { this.addError(internalID, e, 1); }, ); } } origin/main'>origin/main Unnamed repository; edit this file 'description' to name the repository.
aboutsummaryrefslogtreecommitdiff
AgeCommit message (Expand)AuthorFilesLines
2023-10-17Remove ancient changelogGravatar Ashcon Partovi 1-11/+0
2023-10-17docs: fix ws.publish (#6558)Gravatar Aral Roca Gomez 1-1/+1
2023-10-17perf(bun-types): remove needless some call (#6550)Gravatar Mikhail 1-1/+1
2023-10-16fix(runtime): make some things more stable (partial jsc debug build) (#5881)Gravatar dave caruso 116-1446/+1830
2023-10-16fix(runtime): improve IPC reliability + organization pass on that code (#6475)Gravatar dave caruso 15-98/+266
2023-10-16Simplify getting Set of extentions (#4975)Gravatar Mikhail 1-3/+3
2023-10-16Fix formattingGravatar Ashcon Partovi 1-3/+1
2023-10-16fix(test): when tests run with --only the nested describe blocks `.on… (#5616)Gravatar Igor Shapiro 2-13/+45
2023-10-16perf(node:events): optimize `emit(...)` function (#5485)Gravatar Yannik Schröder 3-11/+132
2023-10-16fix: don't remove content-encoding header from header table (#5743)Gravatar Liz 2-2/+25
2023-10-16fix(sqlite) Insert .all() does not return an array #5872 (#5946)Gravatar Hugo Galan 2-7/+11
2023-10-16Fix formattingGravatar Ashcon Partovi 2-5/+4
2023-10-16Fix `Response.statusText` (#6151)Gravatar Chris Toshok 10-238/+269
2023-10-16fix-subprocess-argument-missing (#6407)Gravatar Nicolae-Rares Ailincai 4-2/+40
2023-10-16Add type parameter to `expect` (#6128)Gravatar Voldemat 1-3/+3
2023-10-16fix(node:worker_threads): ensure threadId property is exposed on worker_threa...Gravatar Jérôme Benoit 6-15/+75
2023-10-16Fix use before define bug in sqliteGravatar Ashcon Partovi 2-5/+5
2023-10-16fix(jest): fix toStrictEqual on same URLs (#6528)Gravatar João Alisson 2-13/+16
2023-10-16Fix `toHaveBeenCalled` having wrong error signatureGravatar Ashcon Partovi 1-2/+2
2023-10-16Fix formattingGravatar Ashcon Partovi 1-2/+1
2023-10-16Add `reusePort` to `Bun.serve` typesGravatar Ashcon Partovi 1-0/+9
2023-10-16Fix `request.url` having incorrect portGravatar Ashcon Partovi 4-1/+92
2023-10-16Remove uWebSockets header from Bun.serve responsesGravatar Ashcon Partovi 1-6/+6
2023-10-16Rename some testsGravatar Ashcon Partovi 3-0/+0
2023-10-16Fix #6467Gravatar Ashcon Partovi 2-3/+10
2023-10-16Update InternalModuleRegistryConstants.hGravatar Dylan Conway 1-3/+3
2023-10-16Development -> Contributing (#6538)Gravatar Colin McDonnell 2-1/+1
2023-10-14fix(net/tls) fix pg hang on end + hanging on query (#6487)Gravatar Ciro Spaciari 3-8/+36
2023-10-13fix installing dependencies that match workspace versions (#6494)Gravatar Dylan Conway 4-2/+64
2023-10-13fix lockfile struct padding (#6495)Gravatar Dylan Conway 3-3/+18