import type { AnyFunction, BuildConfig, BunPlugin, OnLoadCallback, 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); }, ); } } ld-subpaths'>fix/build-subpaths Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
AgeCommit message (Expand)AuthorFilesLines
2023-08-21[docs] deprecate build.split and build.excludeMiddleware in config ref (#8158)Gravatar Sarah Rainsberger 1-25/+7
2023-08-21chore: lock fileGravatar Emanuele Stoppa 1-0/+4
2023-08-21[ci] formatGravatar natemoo-re 4-9/+15
2023-08-21Stringify shouldn't throw on user object during rendering (#8127)Gravatar Nate Moore 9-46/+115
2023-08-21[ci] formatGravatar natemoo-re 1-1/+4
2023-08-21fix(dev): open to base path (#8123)Gravatar Nate Moore 2-1/+8
2023-08-21chore(gitpod): resolve potential globbing and word splitting issue (#8124)Gravatar Ben Elan 1-1/+1
2023-08-21fix(#6965): fix build stats (#8122)Gravatar Nate Moore 2-1/+8
2023-08-21only update our own history entires during back navigation through view trans...Gravatar Martin Trapp 2-3/+11
2023-08-21fix: reinsert attribute to specify direction of ViewTransition (forward / bac...Gravatar Martin Trapp 2-7/+12
2023-08-21Remove deprecated APIs (#8170)Gravatar Bjorn Lu 4-107/+5
2023-08-21Remove pre-shiki v0.14 theme names (#8169)Gravatar Bjorn Lu 6-80/+14
2023-08-21[docs] JSX framework integration READMEs (#8151)Gravatar Sarah Rainsberger 3-0/+104
2023-08-21fix(assets): Add missing type for imageConfig export (#8171)Gravatar Erika 2-1/+7
2023-08-21Deprecate simple objects from endpoints (#8132)Gravatar Bjorn Lu 20-201/+243
2023-08-18[docs] update scopedStyleStragegy default and description (#8148)Gravatar Sarah Rainsberger 1-2/+2
2023-08-18[ci] release (#8145)astro@2.10.12@astrojs/react@2.3.2@astrojs/node@5.3.5Gravatar Houston (Bot) 46-92/+98
2023-08-18Fix missing package file regression (#8149)Gravatar Matthew Phillips 2-1/+7
2023-08-18fix(node): delegate preview's not found and error handling to core/app (#8141)Gravatar Arsh 2-9/+6
2023-08-18Replace `class:list` implementation with `clsx` (#8142)Gravatar Nate Moore 12-68/+133
2023-08-18[ci] formatGravatar matthewp 1-1/+4
2023-08-18fix(data collections): normalize file paths for DataEntry.id (#8144)Gravatar Arsh 2-1/+6
2023-08-18[ci] release (beta) (#8140)astro@3.0.0-beta.4Gravatar Houston (Bot) 41-65/+72
2023-08-18[error messages] Update image errors-data.ts (#8126)Gravatar Sarah Rainsberger 1-12/+12
2023-08-18fix(polyfills): Use object shape for Stackblitz polyfill listGravatar Princesseuh 1-2/+2
2023-08-18fix: polyfill File using undici instead of node:buffer (#8139)Gravatar Erika 2-8/+9
2023-08-18[ci] release (beta) (#8073)create-astro@4.0.0-beta.1astro@3.0.0-beta.3@astrojs/vercel@4.0.0-beta.3@astrojs/telemetry@3.0.0-beta.2@astrojs/svelte@4.0.0-beta.1@astrojs/solid-js@3.0.0-beta.2@astrojs/react@3.0.0-beta.3@astrojs/mdx@1.0.0-beta.1@astrojs/cloudflare@7.0.0-beta.2Gravatar Houston (Bot) 63-117/+389
2023-08-18[ci] release (#8138)astro@2.10.11@astrojs/react@2.3.1Gravatar Houston (Bot) 44-80/+82
2023-08-18[ci] formatGravatar natemoo-re 1-1/+1
2023-08-18Fix 404 response leading to an infinite loop when there is no 404 page (#8136)Gravatar André Alves 2-1/+10
2023-08-18fix(react): add missing export (#8137)Gravatar Nate Moore 2-1/+7
2023-08-18[ci] release (#8096)create-astro@3.2.2astro@2.10.10@astrojs/vercel@3.8.2@astrojs/svelte@3.1.1@astrojs/solid-js@2.2.1@astrojs/react@2.3.0Gravatar Houston (Bot) 63-197/+186
2023-08-18changeset(next): inlineStylesheets default switch is major (#8133)Gravatar Arsh 1-1/+1
2023-08-18feat: add polyfills for stackblitz (#8130)Gravatar Erika 7-6/+86