diff options
63 files changed, 920 insertions, 1586 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json index 38242e143..5c42d297a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -98,7 +98,7 @@ // "args": ["--serve", "--origin=http://localhost:3000"], "args": ["dev", "--origin=http://localhost:3000"], "cwd": "${workspaceFolder}/examples/hello-next", - "console": "internalConsole" + "console": "internalConsole" }, { "type": "lldb", @@ -154,7 +154,7 @@ "request": "launch", "name": "Demo .bun", "program": "${workspaceFolder}/build/debug/macos-x86_64/bun", - "args": ["bun", "--use=./bun-framework-next"], + "args": ["bun", "--use=bun-framework-next"], "cwd": "${workspaceFolder}/examples/hello-next", "console": "internalConsole" }, diff --git a/examples/hello-next/bun-framework-next/.npmignore b/examples/hello-next/bun-framework-next/.npmignore deleted file mode 100644 index dc0954477..000000000 --- a/examples/hello-next/bun-framework-next/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -*.bun -node_modules
\ No newline at end of file diff --git a/examples/hello-next/bun-framework-next/client.development.tsx b/examples/hello-next/bun-framework-next/client.development.tsx index 0d019e175..f8fd054c3 100644 --- a/examples/hello-next/bun-framework-next/client.development.tsx +++ b/examples/hello-next/bun-framework-next/client.development.tsx @@ -1,7 +1,8 @@ -import "./bun-error"; globalThis.global = globalThis; globalThis.Bun_disableCSSImports = true; +import "./bun-error"; + import * as React from "react"; var onlyChildPolyfill = React.Children.only; React.Children.only = function (children) { diff --git a/examples/hello-next/bun-framework-next/fallback.development.tsx b/examples/hello-next/bun-framework-next/fallback.development.tsx deleted file mode 100644 index 1cd5f847e..000000000 --- a/examples/hello-next/bun-framework-next/fallback.development.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { insertStyleSheet } from "./page-loader"; -import type { - FallbackMessageContainer, - FallbackStep, -} from "../../../src/api/schema"; - -var once = false; -function insertGlobalStyleSheet(detail) { - if (!once) { - document.head.insertAdjacentHTML( - "beforeend", - `<meta name="next-head-count" content="${document.head.childElementCount}">` - ); - once = true; - } - pageLoader.cssQueue.push(insertStyleSheet(detail).then(() => {})); -} - -[...globalThis["__BUN"].allImportedStyles].map((detail) => - insertGlobalStyleSheet(detail) -); - -document.addEventListener("onimportcss", insertGlobalStyleSheet, { - passive: true, -}); - -import { renderError, _boot, pageLoader } from "./client.development"; -import { renderFallbackError } from "bun-error"; - -function renderFallback({ - router, - reason, - problems, -}: FallbackMessageContainer) { - const route = router.routes[router.route]; - - if (!document.getElementById("__next")) { - const next = document.createElement("div"); - next.id = "__next"; - document.body.prepend(next); - } - - document.removeEventListener("onimportcss", insertGlobalStyleSheet); - document.addEventListener("onimportcss", pageLoader.onImportCSS, { - passive: true, - }); - - globalThis.__NEXT_DATA__.pages["/_app"] = [ - ...globalThis.__NEXT_DATA__.pages["/_app"], - ...globalThis["__BUN"].allImportedStyles, - ]; - - return import(route) - .then((Namespace) => { - return _boot(Namespace, true); - }) - .then(() => { - const cssQueue = pageLoader.cssQueue.slice(); - pageLoader.cssQueue = []; - return Promise.all([...cssQueue]); - }) - .finally(() => { - document.body.style.visibility = "visible"; - document.removeEventListener("onimportcss", pageLoader.onImportCSS); - }); -} - -export default function render(props: FallbackMessageContainer) { - renderFallback(props).then( - () => { - Promise.all(pageLoader.cssQueue).finally(() => { - renderFallbackError(props); - document.body.style.visibility = "visible"; - }); - }, - (err) => { - Promise.all(pageLoader.cssQueue).finally(() => { - renderFallbackError(props); - }); - } - ); -} diff --git a/examples/hello-next/bun-framework-next/index.js b/examples/hello-next/bun-framework-next/index.js deleted file mode 100644 index e69de29bb..000000000 --- a/examples/hello-next/bun-framework-next/index.js +++ /dev/null diff --git a/examples/hello-next/bun-framework-next/next-server.tsx b/examples/hello-next/bun-framework-next/next-server.tsx deleted file mode 100644 index e69de29bb..000000000 --- a/examples/hello-next/bun-framework-next/next-server.tsx +++ /dev/null diff --git a/examples/hello-next/bun-framework-next/package.json b/examples/hello-next/bun-framework-next/package.json deleted file mode 100644 index af6286343..000000000 --- a/examples/hello-next/bun-framework-next/package.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "name": "bun-framework-next", - "version": "0.0.0-18", - "description": "", - "framework": { - "displayName": "Next.js", - "static": "public", - "assetPrefix": "_next/", - "router": { - "dir": [ - "pages", - "src/pages" - ], - "extensions": [ - ".js", - ".ts", - ".tsx", - ".jsx" - ] - }, - "css": "onimportcss", - "development": { - "client": "client.development.tsx", - "fallback": "fallback.development.tsx", - "server": "server.development.tsx", - "css": "onimportcss", - "define": { - "client": { - ".env": "NEXT_PUBLIC_", - "defaults": { - "process.env.__NEXT_TRAILING_SLASH": "false", - "process.env.NODE_ENV": "\"development\"", - "process.env.__NEXT_ROUTER_BASEPATH": "''", - "process.env.__NEXT_SCROLL_RESTORATION": "false", - "process.env.__NEXT_I18N_SUPPORT": "false", - "process.env.__NEXT_HAS_REWRITES": "false", - "process.env.__NEXT_ANALYTICS_ID": "null", - "process.env.__NEXT_OPTIMIZE_CSS": "false", - "process.env.__NEXT_CROSS_ORIGIN": "''", - "process.env.__NEXT_STRICT_MODE": "false", - "process.env.__NEXT_IMAGE_OPTS": "null" - } - }, - "server": { - ".env": "NEXT_", - "defaults": { - "process.env.__NEXT_TRAILING_SLASH": "false", - "process.env.__NEXT_OPTIMIZE_FONTS": "false", - "process.env.NODE_ENV": "\"development\"", - "process.env.__NEXT_OPTIMIZE_IMAGES": "false", - "process.env.__NEXT_OPTIMIZE_CSS": "false", - "process.env.__NEXT_ROUTER_BASEPATH": "''", - "process.env.__NEXT_SCROLL_RESTORATION": "false", - "process.env.__NEXT_I18N_SUPPORT": "false", - "process.env.__NEXT_HAS_REWRITES": "false", - "process.env.__NEXT_ANALYTICS_ID": "null", - "process.env.__NEXT_CROSS_ORIGIN": "''", - "process.env.__NEXT_STRICT_MODE": "false", - "process.env.__NEXT_IMAGE_OPTS": "null", - "global": "globalThis", - "window": "undefined" - } - } - } - }, - "production": { - "client": "client.production.tsx", - "server": "server.production.tsx", - "fallback": "fallback.production.tsx", - "css": "onimportcss" - } - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "ISC", - "dependencies": { - "react-is": "^17.0.2" - } -} diff --git a/examples/hello-next/bun-framework-next/page-loader.ts b/examples/hello-next/bun-framework-next/page-loader.ts deleted file mode 100644 index fc07578db..000000000 --- a/examples/hello-next/bun-framework-next/page-loader.ts +++ /dev/null @@ -1,147 +0,0 @@ -import NextPageLoader from "next/dist/client/page-loader"; -import getAssetPathFromRoute from "next/dist/shared/lib/router/utils/get-asset-path-from-route"; -// import createRouteLoader from "./route-loader"; - -export function insertStyleSheet(url: string) { - if (document.querySelector(`link[href="${url}"]`)) { - return Promise.resolve(); - } - - return new Promise((resolve, reject) => { - const link = document.createElement("link"); - link.rel = "stylesheet"; - - link.onload = () => resolve(); - link.onerror = () => reject(); - - link.href = url; - - // if (headCount) { - // document.head.insertBefore(headCount, link); - // } else { - document.head.appendChild(link); - // } - }); -} - -export default class PageLoader extends NextPageLoader { - public routeLoader: RouteLoader; - - constructor(_, __, pages) { - super(_, __); - - // TODO: assetPrefix? - // this.routeLoader = {}; //createRouteLoader(""); - - // Rewrite the pages object to omit the entry script - // At this point, the entry point has been loaded so we don't want to do that again. - for (let name in pages) { - for (let i = 0; i < pages[name].length; i += 1) { - const lastDot = pages[name][i].lastIndexOf("."); - if (lastDot == -1) continue; - if ( - pages[name][i].substring(lastDot - ".entry".length, lastDot) !== - ".entry" - ) - continue; - - pages[name][i] = - pages[name][i].substring(0, lastDot - ".entry".length) + - pages[name][i].substring(lastDot); - } - } - - this.pages = pages; - this.pageList = Object.keys(this.pages); - } - - pageList: string[]; - pages: Record<string, string[]>; - - getPageList() { - return this.pageList; - } - - cssQueue = []; - - onImportCSS = (event) => { - this.cssQueue.push( - insertStyleSheet(event.detail).then( - () => {}, - () => {} - ) - ); - }; - - prefetch(route) { - return Promise.resolve({}); - } - - async loadPage(route: string): Promise<GoodPageCache> { - const assets = - this.pages[route] || this.pages[getAssetPathFromRoute(route)]; - - var src; - console.log(getAssetPathFromRoute(route), assets); - for (let asset of assets) { - if (!asset.endsWith(".css")) { - src = asset; - break; - } - } - console.assert(src, "Invalid or unknown route passed to loadPage"); - - document.removeEventListener("onimportcss", this.onImportCSS); - this.cssQueue.length = 0; - document.addEventListener("onimportcss", this.onImportCSS, { - passive: true, - }); - - try { - const res = await import(src); - - if (this.cssQueue.length > 0) { - await Promise.all(this.cssQueue); - this.cssQueue.length = 0; - } - - document.removeEventListener("onimportcss", this.onImportCSS); - - if (this.cssQueue.length > 0) { - await Promise.all(this.cssQueue); - - this.cssQueue.length = 0; - } - - return { - page: res.default, - mod: res, - styleSheets: [], - __N_SSG: false, - __N_SSP: false, - }; - } catch (exception) { - console.error({ exception }); - } - - // return this.routeLoader.loadRoute(route).then((res) => { - // debugger; - // if ("component" in res) { - // return { - // page: res.component, - // mod: res.exports, - // styleSheets: res.styles.map((o) => ({ - // href: o.href, - // text: o.content, - // })), - // }; - // } - // throw res.error; - // }); - } - - // not used in development! - // prefetch(route: string): Promise<void> { - // return this.routeLoader.prefetch(route); - // } -} diff --git a/examples/hello-next/bun-framework-next/render.tsx b/examples/hello-next/bun-framework-next/render.tsx deleted file mode 100644 index e69de29bb..000000000 --- a/examples/hello-next/bun-framework-next/render.tsx +++ /dev/null diff --git a/examples/hello-next/bun-framework-next/renderDocument.tsx b/examples/hello-next/bun-framework-next/renderDocument.tsx deleted file mode 100644 index 356ff788b..000000000 --- a/examples/hello-next/bun-framework-next/renderDocument.tsx +++ /dev/null @@ -1,722 +0,0 @@ -import * as App from "next/app"; -import { AmpStateContext } from "next/dist/shared/lib/amp-context"; -import { HeadManagerContext } from "next/dist/shared/lib/head-manager-context"; -import Loadable from "next/dist/shared/lib/loadable"; -import { LoadableContext } from "next/dist/shared/lib/loadable-context"; -import { RouterContext } from "next/dist/shared/lib/router-context"; -import { NextRouter } from "next/dist/shared/lib/router/router"; -import { - AppType, - ComponentsEnhancer, - DocumentInitialProps, - DocumentProps, - DocumentType, - getDisplayName, - loadGetInitialProps, - NextComponentType, - RenderPage, - RenderPageResult, - HtmlContext, -} from "next/dist/shared/lib/utils"; -import * as NextDocument from "next/document"; -import * as ReactDOMServer from "react-dom/server.browser"; -import * as url from "url"; -import * as React from "react"; -import * as ReactIs from "react-is"; -import { BODY_RENDER_TARGET } from "next/constants"; - -const dev = process.env.NODE_ENV === "development"; - -type ParsedUrlQuery = Record<string, string | string[]>; - -const isJSFile = (file: string) => - file.endsWith(".js") || - file.endsWith(".jsx") || - file.endsWith(".mjs") || - file.endsWith(".ts") || - file.endsWith(".tsx"); - -const notImplementedProxy = (base) => - new Proxy( - {}, - { - deleteProperty: function (target, prop) { - return undefined; - }, - enumerate: function (oTarget, sKey) { - return [].entries(); - }, - ownKeys: function (oTarget, sKey) { - return [].values(); - }, - has: function (oTarget, sKey) { - return false; - }, - defineProperty: function (oTarget, sKey, oDesc) { - return undefined; - }, - getOwnPropertyDescriptor: function (oTarget, sKey) { - return undefined; - }, - get(this, prop) { - throw new ReferenceError( - `${base} is not available for this environment.` - ); - }, - set(this, prop, value) { - throw new ReferenceError( - `${base} is not available for this environment.` - ); - }, - } - ); - -globalThis.fetch = (url, options) => { - return Promise.reject(new Error(`fetch is not implemented yet. sorry!!`)); -}; - -function getScripts(files: DocumentFiles) { - const { context, props } = this; - const { - assetPrefix, - buildManifest, - isDevelopment, - devOnlyCacheBusterQueryString, - disableOptimizedLoading, - } = context; - const normalScripts = files.allFiles.filter(isJSFile); - const lowPriorityScripts = buildManifest.lowPriorityFiles?.filter(isJSFile); - - return [...normalScripts, ...lowPriorityScripts].map((file) => { - return ( - <script - key={file} - src={`${encodeURI(file)}${devOnlyCacheBusterQueryString}`} - nonce={props.nonce} - async - crossOrigin={props.crossOrigin || process.env.__NEXT_CROSS_ORIGIN} - type="module" - /> - ); - }); -} - -// function fixLink(from: string) { -// if (from.startsWith("/_next/http://") || from.startsWith("/_next/https://")) -// return from.substring("/_next".length); -// return from; -// } - -// function cloneWithOverwrittenLink(element: React.ReactElement<any>) { -// const props = { ...element.props }; -// if ("href" in element.props) { -// props.href = fixLink(props.href); -// } - -// if ("n-href" in element.props) { -// props["n-href"] = fixLink(props["n-href"]); -// } - -// if ("n-src" in element.props) { -// props["n-src"] = fixLink(props["n-src"]); -// } - -// if ("src" in element.props) { -// props["src"] = fixLink(props.src); -// } - -// return React.cloneElement(element, props); -// } - -interface DomainLocale { - defaultLocale: string; - domain: string; - http?: true; - locales?: string[]; -} - -function renderDocument( - Document: DocumentType, - { - buildManifest, - docComponentsRendered, - props, - docProps, - pathname, - query, - buildId, - canonicalBase, - assetPrefix, - runtimeConfig, - nextExport, - autoExport, - isFallback, - dynamicImportsIds, - dangerousAsPath, - err, - dev, - ampPath, - ampState, - inAmpMode, - hybridAmp, - dynamicImports, - headTags, - gsp, - gssp, - customServer, - gip, - appGip, - unstable_runtimeJS, - unstable_JsPreload, - devOnlyCacheBusterQueryString, - scriptLoader, - locale, - locales, - defaultLocale, - domainLocales, - isPreview, - disableOptimizedLoading, - }: RenderOpts & { - props: any; - docComponentsRendered: DocumentProps["docComponentsRendered"]; - docProps: DocumentInitialProps; - pathname: string; - query: ParsedUrlQuery; - dangerousAsPath: string; - ampState: any; - ampPath: string; - inAmpMode: boolean; - hybridAmp: boolean; - dynamicImportsIds: (string | number)[]; - dynamicImports: string[]; - headTags: any; - isFallback?: boolean; - gsp?: boolean; - gssp?: boolean; - customServer?: boolean; - gip?: boolean; - appGip?: boolean; - devOnlyCacheBusterQueryString: string; - scriptLoader: any; - isPreview?: boolean; - autoExport?: boolean; - } -): string { - const htmlProps = { - __NEXT_DATA__: { - props, // The result of getInitialProps - page: pathname, // The rendered page - query, // querystring parsed / passed by the user - buildId, // buildId is used to facilitate caching of page bundles, we send it to the client so that pageloader knows where to load bundles - assetPrefix: assetPrefix === "" ? undefined : assetPrefix, // send assetPrefix to the client side when configured, otherwise don't sent in the resulting HTML - runtimeConfig, // runtimeConfig if provided, otherwise don't sent in the resulting HTML - nextExport, // If this is a page exported by `next export` - autoExport, // If this is an auto exported page - isFallback, - dynamicIds: - dynamicImportsIds.length === 0 ? undefined : dynamicImportsIds, - err: err || undefined, // err: err ? serializeError(dev, err) : undefined, // Error if one happened, otherwise don't sent in the resulting HTML - gsp, // whether the page is getStaticProps - gssp, // whether the page is getServerSideProps - customServer, // whether the user is using a custom server - gip, // whether the page has getInitialProps - appGip, // whether the _app has getInitialProps - locale, - locales, - defaultLocale, - domainLocales, - isPreview, - - pages: buildManifest.pages, - }, - buildManifest, - docComponentsRendered, - dangerousAsPath, - canonicalBase, - ampPath, - inAmpMode, - isDevelopment: !!dev, - hybridAmp, - dynamicImports, - assetPrefix, - headTags, - unstable_runtimeJS, - unstable_JsPreload, - devOnlyCacheBusterQueryString, - scriptLoader, - locale, - disableOptimizedLoading, - ...docProps, - }; - return ( - "<!DOCTYPE html>" + - ReactDOMServer.renderToStaticMarkup( - <AmpStateContext.Provider value={ampState}> - <HtmlContext.Provider value={htmlProps}> - <Document {...htmlProps} {...docProps}></Document> - </HtmlContext.Provider> - </AmpStateContext.Provider> - ) - ); -} - -class ServerRouter implements NextRouter { - route: string; - pathname: string; - query: ParsedUrlQuery; - asPath: string; - basePath: string; - events: any; - isFallback: boolean; - locale?: string; - isReady: boolean; - locales?: string[]; - defaultLocale?: string; - domainLocales?: DomainLocale[]; - isPreview: boolean; - isLocaleDomain: boolean; - - constructor( - pathname: string, - query: ParsedUrlQuery, - as: string, - { isFallback }: { isFallback: boolean }, - isReady: boolean, - basePath: string, - locale?: string, - locales?: string[], - defaultLocale?: string, - domainLocales?: DomainLocale[], - isPreview?: boolean, - isLocaleDomain?: boolean - ) { - this.route = pathname.replace(/\/$/, "") || "/"; - this.pathname = pathname; - this.query = query; - this.asPath = as; - this.isFallback = isFallback; - this.basePath = basePath; - this.locale = locale; - this.locales = locales; - this.defaultLocale = defaultLocale; - this.isReady = isReady; - this.domainLocales = domainLocales; - this.isPreview = !!isPreview; - this.isLocaleDomain = !!isLocaleDomain; - } - - push(): any { - noRouter(); - } - replace(): any { - noRouter(); - } - reload() { - noRouter(); - } - back() { - noRouter(); - } - prefetch(): any { - noRouter(); - } - beforePopState() { - noRouter(); - } -} - -function noRouter() { - const message = - 'No router instance found. you should only use "next/router" inside the client side of your app. https://nextjs.org/docs/messages/no-router-instance'; - throw new Error(message); -} - -function enhanceComponents( - options: ComponentsEnhancer, - App: AppType, - Component: NextComponentType -): { - App: AppType; - Component: NextComponentType; -} { - // For backwards compatibility - if (typeof options === "function") { - return { - App, - Component: options(Component), - }; - } - - return { - App: options.enhanceApp ? options.enhanceApp(App) : App, - Component: options.enhanceComponent - ? options.enhanceComponent(Component) - : Component, - }; -} - -Object.defineProperty(NextDocument.Head.prototype, "getScripts", { - get() { - return getScripts; - }, -}); -Object.defineProperty(NextDocument.NextScript.prototype, "getScripts", { - get() { - return getScripts; - }, -}); - -export async function render({ - route, - PageNamespace, - AppNamespace, - appStylesheets = [], - pageStylesheets = [], - DocumentNamespace = null, - buildId, - routePaths = [], -}: { - buildId: number; - route: any; - PageNamespace: { default: NextComponentType<any> }; - AppNamespace: { default: NextComponentType<any> } | null; - DocumentNamespace: Object | null; - appStylesheets: string[]; - pageStylesheets: string[]; - routePaths: string[]; -}): Promise<Response> { - const { default: Component, getStaticProps = null } = PageNamespace || {}; - const { default: AppComponent_ } = AppNamespace || {}; - var query = Object.assign({}, route.query); - - // These are reversed in our Router versus Next.js...mostly due to personal preference. - const pathname = "/" + route.name; - var asPath = route.pathname; - const pages = {}; - - for (let path of routePaths) { - const filePath = path.substring( - path.indexOf("_next/pages/") + "_next/pages".length - ); - const name = filePath.substring(0, filePath.indexOf(".")); - pages[name] = [path]; - } - - pages[pathname] = [route.scriptSrc, ...pageStylesheets]; - - if (appStylesheets.length > 0) { - if (pages["/_app"]) { - pages["/_app"].push(...appStylesheets); - } else { - pages["/_app"] = appStylesheets; - } - } - - const AppComponent = AppComponent_ || App.default; - const Document = - (DocumentNamespace && DocumentNamespace.default) || NextDocument.default; - // Document.Html.prototype.getScripts = getScripts; - // } - - const callMiddleware = async (method: string, args: any[], props = false) => { - let results: any = props ? {} : []; - - if ((Document as any)[`${method}Middleware`]) { - let middlewareFunc = await (Document as any)[`${method}Middleware`]; - middlewareFunc = middlewareFunc.default || middlewareFunc; - - const curResults = await middlewareFunc(...args); - if (props) { - for (const result of curResults) { - results = { - ...results, - ...result, - }; - } - } else { - results = curResults; - } - } - return results; - }; - - const headTags = (...args: any) => callMiddleware("headTags", args); - - if (!ReactIs.isValidElementType(Component)) { - const exportNames = Object.keys(PageNamespace || {}); - - const reactComponents = exportNames.filter(ReactIs.isValidElementType); - if (reactComponents.length > 2) { - throw new Error( - `\"export default\" missing in ${ - route.filePath - }.\nTry exporting one of ${reactComponents.join(", ")}\n` - ); - } else if (reactComponents.length === 2) { - throw new Error( - `\"export default\" missing in ${route.filePath}.\n\nTry exporting <${reactComponents[0]} /> or <${reactComponents[1]} />\n` - ); - } else if (reactComponents.length == 1) { - throw new Error( - `\"export default\" missing in ${route.filePath}. Try adding this to the bottom of the file:\n\n export default ${reactComponents[0]};\n` - ); - } else if (reactComponents.length == 0) { - throw new Error( - `\"export default\" missing in ${route.filePath}. Try exporting a React component.\n` - ); - } - } - - const isFallback = !!query.__nextFallback; - delete query.__nextFallback; - delete query.__nextLocale; - delete query.__nextDefaultLocale; - - const isSSG = !!getStaticProps; - const isBuildTimeSSG = isSSG && false; - const defaultAppGetInitialProps = - App.getInitialProps === (App as any).origGetInitialProps; - - const hasPageGetInitialProps = !!(Component as any).getInitialProps; - const pageIsDynamic = route.kind === "dynamic"; - const isAutoExport = false; - - if (isAutoExport || isFallback) { - // // remove query values except ones that will be set during export - // query = { - // ...(query.amp - // ? { - // amp: query.amp, - // } - // : {}), - // }; - asPath = `${asPath}${ - // ensure trailing slash is present for non-dynamic auto-export pages - asPath.endsWith("/") && asPath !== "/" && !pageIsDynamic ? "/" : "" - }`; - } - - let head: JSX.Element[] = [ - <meta charSet="utf-8" />, - <meta name="viewport" content="width=device-width" />, - ]; - - const nextExport = isAutoExport || isFallback; - const reactLoadableModules: string[] = []; - var scriptLoader = {}; - const AppContainer = ({ children }: any) => ( - <RouterContext.Provider value={router}> - {/* <AmpStateContext.Provider value={ampState}> */} - <HeadManagerContext.Provider - value={{ - updateHead: (state) => { - head = state; - }, - updateScripts: (scripts) => { - scriptLoader = scripts; - }, - scripts: {}, - mountedInstances: new Set(), - }} - > - <LoadableContext.Provider - value={(moduleName) => reactLoadableModules.push(moduleName)} - > - {children} - </LoadableContext.Provider> - </HeadManagerContext.Provider> - {/* </AmpStateContext.Provider> */} - </RouterContext.Provider> - ); - - await Loadable.preloadAll(); // Make sure all dynamic imports are loaded - - const router = new ServerRouter( - pathname, - query, - asPath, - { - isFallback: isFallback, - }, - true, - Bun.origin, - null, - [], // renderOpts.locales, - null, //renderOpts.defaultLocale, - [], // renderOpts.domainLocales, - false, - false - ); - - const ctx = { - err: null, - req: undefined, - res: undefined, - pathname, - query, - asPath, - locale: null, - locales: [], - defaultLocale: null, - AppTree: (props: any) => { - return ( - <AppContainer> - <App {...props} Component={Component} router={router} /> - </AppContainer> - ); - }, - }; - - var props = await loadGetInitialProps(AppComponent, { - AppTree: ctx.AppTree, - Component, - router, - ctx, - }); - - // This isn't correct. - // We don't call getServerSideProps on clients. - const getServerSideProps = PageNamespace.getServerSideProps; - if (typeof getServerSideProps === "function") { - const result = await getServerSideProps({ - params: route.params, - query: route.query, - req: notImplementedProxy("req"), - res: notImplementedProxy("res"), - resolvedUrl: route.pathname, - preview: false, - previewData: null, - locale: null, - locales: [], - defaultLocale: null, - }); - - if (result) { - if ("props" in result) { - if (typeof result.props === "object") { - Object.assign(props, result.props); - } - } - } - } - - const renderToString = ReactDOMServer.renderToString; - const ErrorDebug = null; - - const renderPage: RenderPage = ( - options: ComponentsEnhancer = {} - ): RenderPageResult | Promise<RenderPageResult> => { - if (ctx.err && ErrorDebug) { - const htmlOrPromise = renderToString(<ErrorDebug error={ctx.err} />); - return typeof htmlOrPromise === "string" - ? { html: htmlOrPromise, head } - : htmlOrPromise.then((html) => ({ - html, - head, - })); - } - - if (dev && (props.router || props.Component)) { - throw new Error( - `'router' and 'Component' can not be returned in getInitialProps from _app.js https://nextjs.org/docs/messages/cant-override-next-props` - ); - } - - const { App: EnhancedApp, Component: EnhancedComponent } = - enhanceComponents(options, AppComponent, Component); - - const htmlOrPromise = renderToString( - <AppContainer> - <EnhancedApp Component={EnhancedComponent} router={router} {...props} /> - </AppContainer> - ); - return typeof htmlOrPromise === "string" - ? { html: htmlOrPromise, head } - : htmlOrPromise.then((html) => ({ - html, - head, - })); - }; - - const documentCtx = { ...ctx, renderPage }; - const docProps: DocumentInitialProps = await loadGetInitialProps( - Document, - documentCtx - ); - - if (!docProps || typeof docProps.html !== "string") { - const message = `"${getDisplayName( - Document - )}.getInitialProps()" should resolve to an object with a "html" prop set with a valid html string`; - throw new Error(message); - } - - const renderOpts = { - params: route.params, - }; - // renderOpts.params = _params || params; - - // parsedUrl.pathname = denormalizePagePath(parsedUrl.pathname!); - // renderOpts.resolvedUrl = formatUrl({ - // ...parsedUrl, - // query: origQuery, - // }); - const docComponentsRendered: DocumentProps["docComponentsRendered"] = {}; - - const isPreview = false; - - let html = renderDocument(Document, { - docComponentsRendered, - ...renderOpts, - disableOptimizedLoading: false, - canonicalBase: Bun.origin, - buildManifest: { - devFiles: [], - allFiles: [], - polyfillFiles: [], - lowPriorityFiles: [], - pages: pages, - }, - // Only enabled in production as development mode has features relying on HMR (style injection for example) - unstable_runtimeJS: true, - // process.env.NODE_ENV === "production" - // ? pageConfig.unstable_runtimeJS - // : undefined, - // unstable_JsPreload: pageConfig.unstable_JsPreload, - unstable_JsPreload: true, - dangerousAsPath: router.asPath, - ampState: undefined, - props, - assetPrefix: "", - headTags: await headTags(documentCtx), - isFallback, - docProps, - pathname, - ampPath: undefined, - query, - inAmpMode: false, - hybridAmp: undefined, - dynamicImportsIds: [], // Array.from(dynamicImportsIds), - dynamicImports: [], //Array.from(dynamicImports), - gsp: !!getStaticProps ? true : undefined, - gssp: !!getServerSideProps ? true : undefined, - gip: hasPageGetInitialProps ? true : undefined, - appGip: !defaultAppGetInitialProps ? true : undefined, - devOnlyCacheBusterQueryString: "", - scriptLoader, - isPreview: isPreview === true ? true : undefined, - autoExport: isAutoExport === true ? true : undefined, - nextExport: nextExport === true ? true : undefined, - }); - const bodyRenderIdx = html.indexOf(BODY_RENDER_TARGET); - html = - html.substring(0, bodyRenderIdx) + - (false ? "<!-- __NEXT_DATA__ -->" : "") + - docProps.html + - html.substring(bodyRenderIdx + BODY_RENDER_TARGET.length); - return new Response( - html - .replaceAll("/_next/http://", "http://") - .replaceAll("/_next/https://", "https://") - ); -} diff --git a/examples/hello-next/bun-framework-next/route-loader.ts b/examples/hello-next/bun-framework-next/route-loader.ts deleted file mode 100644 index e69de29bb..000000000 --- a/examples/hello-next/bun-framework-next/route-loader.ts +++ /dev/null diff --git a/examples/hello-next/bun-framework-next/server.development.tsx b/examples/hello-next/bun-framework-next/server.development.tsx deleted file mode 100644 index e3cd24e01..000000000 --- a/examples/hello-next/bun-framework-next/server.development.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import * as React from "react"; -import { Buffer } from "buffer"; -globalThis.Buffer = Buffer; - -class URL { - constructor(base, source) { - this.pathname = source; - this.href = base + source; - } -} -var onlyChildPolyfill = React.Children.only; -React.Children.only = function (children) { - if (children && typeof children === "object" && children.length == 1) { - return onlyChildPolyfill(children[0]); - } - - return onlyChildPolyfill(children); -}; -globalThis.URL = URL; -globalThis.global = globalThis; -import { render } from "./renderDocument"; - -let buildId = 0; - -var DocumentLoaded = false; -var DocumentNamespace; - -import(Bun.routesDir + "_document").then( - (doc) => { - DocumentNamespace = doc; - DocumentLoaded = true; - }, - (err) => { - if (err instanceof ResolveError) { - DocumentLoaded = true; - } else { - console.error(err); - } - } -); - -addEventListener("fetch", async (event: FetchEvent) => { - var route = Bun.match(event); - - // This imports the currently matched route. - const PageNamespace = await import(route.filePath); - - // This returns all .css files that were imported in the line above. - // It's recursive, so any file that imports a CSS file will be included. - const pageStylesheets = (Bun.getImportedStyles() as string[]).slice(); - - var appRoute; - - try { - appRoute = await import(Bun.routesDir + "_app"); - } catch (exception) { - appRoute = null; - } - const appStylesheets = (Bun.getImportedStyles() as string[]).slice(); - - event.respondWith( - render({ - route, - PageNamespace, - appStylesheets, - pageStylesheets, - DocumentNamespace, - AppNamespace: appRoute, - buildId, - routePaths: Bun.getRouteFiles(), - }) - ); - buildId++; -}); - -// typescript isolated modules -export {}; - -declare var Bun: any; diff --git a/examples/hello-next/bun-framework-next/server.production.tsx b/examples/hello-next/bun-framework-next/server.production.tsx deleted file mode 100644 index e69de29bb..000000000 --- a/examples/hello-next/bun-framework-next/server.production.tsx +++ /dev/null diff --git a/examples/hello-next/bun-framework-next/tsconfig.json b/examples/hello-next/bun-framework-next/tsconfig.json deleted file mode 100644 index d14767c9f..000000000 --- a/examples/hello-next/bun-framework-next/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "target": "esnext", - "lib": ["dom", "dom.iterable", "esnext", "WebWorker"], - "allowJs": true, - "skipLibCheck": true, - "strict": false, - "forceConsistentCasingInFileNames": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "Node", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "baseUrl": ".", - "paths": {} - }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], - "exclude": ["node_modules"] -} diff --git a/examples/hello-next/package.json b/examples/hello-next/package.json index 1ce5e4982..e49602501 100644 --- a/examples/hello-next/package.json +++ b/examples/hello-next/package.json @@ -4,6 +4,9 @@ "main": "index.js", "license": "MIT", "dependencies": { + "@jarred/react-static-tweets": "0.5.8", + "@jarred/static-tweets": "^0.5.8", + "date-fns": "^2.23.0", "isomorphic-fetch": "^3.0.0", "next": "^11.1.0", "parcel": "2.0.0-rc.0", @@ -11,8 +14,6 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "react-is": "^17.0.2", - "react-static-tweets": "^0.5.4", - "static-tweets": "^0.5.5", "whatwg-url": "^9.1.0" }, "devDependencies": { diff --git a/examples/hello-next/pages/errortest.tsx b/examples/hello-next/pages/errortest.tsx deleted file mode 100644 index 49a293df7..000000000 --- a/examples/hello-next/pages/errortest.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import IndexPage from "pages/index"; - -export default function ErrorTestPage() { - class Wow {} - - const ladee = "", - foo = { bar: { boom: new Wow() } }; - - if (typeof window === "undefined") { - const Doge = import("wow/such-esm/very-import"); - } - - return <IndexPage />; -} diff --git a/examples/hello-next/pages/index.tsx b/examples/hello-next/pages/index.tsx index 7a2eb9f64..52b8f1f1f 100644 --- a/examples/hello-next/pages/index.tsx +++ b/examples/hello-next/pages/index.tsx @@ -1,80 +1,105 @@ import Head from "next/head"; -import Image from "next/image"; -import styles from "../styles/Home.module.css"; import Link from "next/link"; import { useRouter } from "next/router"; -import Title, { TitleEnum } from "../components/Title"; import React from "react"; +import { + Tweet, + TwitterContextProvider, +} from "@jarred/react-static-tweets/src/index"; +import "@jarred/react-static-tweets/styles.css"; +import { fetchTweetAst } from "@jarred/static-tweets/src/fetchTweetAst"; +import { SWRConfig } from "swr"; +import styles from "../styles/Home.module.css"; -export default function Home({}) { - const router = useRouter(); +export async function getStaticProps(ctx) { + return { + props: { + tweetAst: await fetchTweetAst("1390084458724741121"), + }, + }; +} +export default function Home({ tweetAst }) { return ( - <div className={styles.container}> - <Head> - <title>Fo</title> - <meta name="description" content="Generated by create next app" /> - <link rel="icon" href="/favicon.ico" /> - </Head> + <SWRConfig value={{ fallback: { [tweetAst[0].data.id]: tweetAst } }}> + <TwitterContextProvider + value={{ + tweetAstMap: { [tweetAst[0].data.id]: tweetAst }, + }} + > + <div className={styles.container}> + <Head> + <title>Fo</title> + <meta name="description" content="Generated by create next app" /> + <link rel="icon" href="/favicon.ico" /> + </Head> - <main className={styles.main}> - <h1 className={styles.title}> - Welcome to <a href="https://nextjs.org">Next.js!</a> - </h1> + <main className={styles.main}> + + {/* <h1 className={styles.title}> + Welcome to <a href="https://nextjs.org">Next.js!</a> + </h1> - <p className={styles.description}> - Get started by editing{" "} - <code className={styles.code}>pages/index.js</code> - </p> + <p className={styles.description}> + Get started by editing{" "} + <code className={styles.code}>pages/index.js</code> + </p> - <div className={styles.grid}> - <Link href="/second"> - <div className={styles.card}> - <h2>Second Page →</h2> - <p>Link</p> - </div> - </Link> + <div className={styles.grid}> + <Link href="/second"> + <div className={styles.card}> + <h2>Second Page →</h2> + <p>Link</p> + </div> + </Link> - <a - onClick={() => router.push("/foo/bar/third")} - className={styles.card} - > - <h2>Third Page →</h2> - <p>button, router.push()</p> - </a> + <a + onClick={() => router.push("/foo/bar/third")} + className={styles.card} + > + <h2>Third Page →</h2> + <p>button, router.push()</p> + </a> - <a - href="https://github.com/vercel/next.js/tree/master/examples" - className={styles.card} - > - <h2>Examples →</h2> - <p>Discover and deploy boilerplate example Next.js projects.</p> - </a> + <a + href="https://github.com/vercel/next.js/tree/master/examples" + className={styles.card} + > + <h2>Examples →</h2> + <p>Discover and deploy boilerplate example Next.js projects.</p> + </a> - <a - href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app" - className={styles.card} - > - <h2>Deploy →</h2> - <p> - Instantly deploy your Next.js site to a public URL with Vercel. - </p> - </a> + <a + href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app" + className={styles.card} + > + <h2>Deploy →</h2> + <p> + Instantly deploy your Next.js site to a public URL with + Vercel. + </p> + </a> + </div> */} + </main> + + {/* <footer className={styles.footer}> + <a + href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app" + target="_blank" + rel="noopener noreferrer" + > + Powered by{" "} + <span className={styles.logo}> + <img + src="/vercel.svg" + alt="Vercel Logo" + width={72} + height={16} + /> + </span> + </a> + </footer> */} </div> - </main> - <footer className={styles.footer}> - <a - href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app" - target="_blank" - rel="noopener noreferrer" - > - Powered by{" "} - <span className={styles.logo}> - <img src="/vercel.svg" alt="Vercel Logo" width={72} height={16} /> - </span> - </a> - </footer> - </div> ); } diff --git a/examples/hello-next/bun-framework-next/bun-error.css b/packages/bun-framework-next/bun-error.css index c5ed9881b..c5ed9881b 100644 --- a/examples/hello-next/bun-framework-next/bun-error.css +++ b/packages/bun-framework-next/bun-error.css diff --git a/examples/hello-next/bun-framework-next/bun-error.tsx b/packages/bun-framework-next/bun-error.tsx index 5d57dd0ea..5d57dd0ea 100644 --- a/examples/hello-next/bun-framework-next/bun-error.tsx +++ b/packages/bun-framework-next/bun-error.tsx diff --git a/examples/hello-next/bun-framework-next/bun-error/close.png b/packages/bun-framework-next/bun-error/close.png Binary files differindex 11e513a1b..11e513a1b 100644 --- a/examples/hello-next/bun-framework-next/bun-error/close.png +++ b/packages/bun-framework-next/bun-error/close.png diff --git a/examples/hello-next/bun-framework-next/bun-error/error.png b/packages/bun-framework-next/bun-error/error.png Binary files differindex c35e01a2b..c35e01a2b 100644 --- a/examples/hello-next/bun-framework-next/bun-error/error.png +++ b/packages/bun-framework-next/bun-error/error.png diff --git a/examples/hello-next/bun-framework-next/bun-error/powered-by.png b/packages/bun-framework-next/bun-error/powered-by.png Binary files differindex 7e71f1357..7e71f1357 100644 --- a/examples/hello-next/bun-framework-next/bun-error/powered-by.png +++ b/packages/bun-framework-next/bun-error/powered-by.png diff --git a/examples/hello-next/bun-framework-next/bun-error/powered-by.webp b/packages/bun-framework-next/bun-error/powered-by.webp Binary files differindex 0f48488ea..0f48488ea 100644 --- a/examples/hello-next/bun-framework-next/bun-error/powered-by.webp +++ b/packages/bun-framework-next/bun-error/powered-by.webp diff --git a/examples/hello-next/bun-framework-next/bun-runtime-error.ts b/packages/bun-framework-next/bun-runtime-error.ts index 331040b36..331040b36 100644 --- a/examples/hello-next/bun-framework-next/bun-runtime-error.ts +++ b/packages/bun-framework-next/bun-runtime-error.ts diff --git a/packages/bun-framework-next/client.development.tsx b/packages/bun-framework-next/client.development.tsx index b93b1fcce..c08eb513e 100644 --- a/packages/bun-framework-next/client.development.tsx +++ b/packages/bun-framework-next/client.development.tsx @@ -1,5 +1,6 @@ globalThis.global = globalThis; globalThis.Bun_disableCSSImports = true; +import "./bun-error"; import * as React from "react"; var onlyChildPolyfill = React.Children.only; @@ -367,7 +368,7 @@ export async function _boot(EntryPointNamespace, isError) { <TopLevelRender App={CachedApp} Component={PageComponent} - props={{ pageProps: hydrateProps }} + props={hydrateProps} />, document.querySelector("#__next") ); @@ -376,7 +377,7 @@ export async function _boot(EntryPointNamespace, isError) { <TopLevelRender App={CachedApp} Component={PageComponent} - props={{ pageProps: hydrateProps }} + props={hydrateProps} />, document.querySelector("#__next") ); diff --git a/packages/bun-framework-next/fallback.development.tsx b/packages/bun-framework-next/fallback.development.tsx index 34e6cb349..b42835d36 100644 --- a/packages/bun-framework-next/fallback.development.tsx +++ b/packages/bun-framework-next/fallback.development.tsx @@ -1,43 +1,83 @@ import { insertStyleSheet } from "./page-loader"; +import type { + FallbackMessageContainer, + FallbackStep, +} from "../../../src/api/schema"; -const globalCSSQueue = []; -function insertGlobalStyleSheet({ detail }) { - globalCSSQueue.push(insertStyleSheet(detail)); +var once = false; +function insertGlobalStyleSheet(detail) { + if (!once) { + document.head.insertAdjacentHTML( + "beforeend", + `<meta name="next-head-count" content="${document.head.childElementCount}">` + ); + once = true; + } + pageLoader.cssQueue.push(insertStyleSheet(detail).then(() => {})); } +[...globalThis["__BUN"].allImportedStyles].map((detail) => + insertGlobalStyleSheet(detail) +); + document.addEventListener("onimportcss", insertGlobalStyleSheet, { passive: true, }); import { renderError, _boot, pageLoader } from "./client.development"; +import { renderFallbackError } from "bun-error"; -export default function render({ router, reason, problems }) { +function renderFallback({ + router, + reason, + problems, +}: FallbackMessageContainer) { const route = router.routes[router.route]; + if (!document.getElementById("__next")) { const next = document.createElement("div"); next.id = "__next"; document.body.prepend(next); - document.head.insertAdjacentHTML( - "beforeend", - `<meta name="next-head-count" content="2">` - ); } document.removeEventListener("onimportcss", insertGlobalStyleSheet); document.addEventListener("onimportcss", pageLoader.onImportCSS, { passive: true, }); - import(route) + + globalThis.__NEXT_DATA__.pages["/_app"] = [ + ...globalThis.__NEXT_DATA__.pages["/_app"], + ...globalThis["__BUN"].allImportedStyles, + ]; + + return import(route) .then((Namespace) => { return _boot(Namespace, true); }) .then(() => { - const cssQueue = pageLoader.cssQueue; + const cssQueue = pageLoader.cssQueue.slice(); pageLoader.cssQueue = []; - return Promise.all([...cssQueue, ...globalCSSQueue]); + return Promise.all([...cssQueue]); }) .finally(() => { document.body.style.visibility = "visible"; document.removeEventListener("onimportcss", pageLoader.onImportCSS); }); } + +export default function render(props: FallbackMessageContainer) { + renderFallback(props).then( + () => { + Promise.all(pageLoader.cssQueue).finally(() => { + renderFallbackError(props); + document.body.style.visibility = "visible"; + }); + }, + (err) => { + console.error(err); + Promise.all(pageLoader.cssQueue).finally(() => { + renderFallbackError(props); + }); + } + ); +} diff --git a/packages/bun-framework-next/next-image-polyfill.tsx b/packages/bun-framework-next/next-image-polyfill.tsx new file mode 100644 index 000000000..edc3775d7 --- /dev/null +++ b/packages/bun-framework-next/next-image-polyfill.tsx @@ -0,0 +1,36 @@ +function NextImagePolyfill({ + src, + width, + height, + objectFit, + style, + layout, + ...otherProps +}) { + var _style = style; + if (layout === "fit") { + objectFit = "contain"; + } else if (layout === "fill") { + objectFit = "cover"; + } + + if (objectFit) { + if (!_style) { + _style = { objectFit: objectFit }; + } else { + _style.objectFit = objectFit; + } + } + + return ( + <img + src={src} + width={width} + height={height} + style={_style} + {...otherProps} + /> + ); +} + +export default NextImagePolyfill; diff --git a/packages/bun-framework-next/package.json b/packages/bun-framework-next/package.json index af6286343..1f937589a 100644 --- a/packages/bun-framework-next/package.json +++ b/packages/bun-framework-next/package.json @@ -24,6 +24,9 @@ "fallback": "fallback.development.tsx", "server": "server.development.tsx", "css": "onimportcss", + "override": { + "next/dist/client/image.js": "next-image-polyfill.tsx" + }, "define": { "client": { ".env": "NEXT_PUBLIC_", diff --git a/packages/bun-framework-next/page-loader.ts b/packages/bun-framework-next/page-loader.ts index 98e132a5f..fc07578db 100644 --- a/packages/bun-framework-next/page-loader.ts +++ b/packages/bun-framework-next/page-loader.ts @@ -15,7 +15,12 @@ export function insertStyleSheet(url: string) { link.onerror = () => reject(); link.href = url; + + // if (headCount) { + // document.head.insertBefore(headCount, link); + // } else { document.head.appendChild(link); + // } }); } diff --git a/packages/bun-framework-next/polyfills.tsx b/packages/bun-framework-next/polyfills.tsx new file mode 100644 index 000000000..b000c1f54 --- /dev/null +++ b/packages/bun-framework-next/polyfills.tsx @@ -0,0 +1,23 @@ +globalThis.global = globalThis; + +import { Buffer } from "buffer"; + +globalThis.Buffer = Buffer; + +import * as React from "react"; + +class URL { + constructor(base, source) { + this.pathname = source; + this.href = base + source; + } +} +var onlyChildPolyfill = React.Children.only; +React.Children.only = function (children) { + if (children && typeof children === "object" && children.length == 1) { + return onlyChildPolyfill(children[0]); + } + + return onlyChildPolyfill(children); +}; +globalThis.URL = URL; diff --git a/packages/bun-framework-next/renderDocument.tsx b/packages/bun-framework-next/renderDocument.tsx index 97a65fff8..957615047 100644 --- a/packages/bun-framework-next/renderDocument.tsx +++ b/packages/bun-framework-next/renderDocument.tsx @@ -71,10 +71,6 @@ const notImplementedProxy = (base) => } ); -globalThis.fetch = (url, options) => { - return Promise.reject(new Error(`fetch is not implemented yet. sorry!!`)); -}; - function getScripts(files: DocumentFiles) { const { context, props } = this; const { @@ -574,6 +570,9 @@ export async function render({ ctx, }); + const pageProps = Object.assign({}, props.pageProps || {}); + // This isn't correct. + // We don't call getServerSideProps on clients. // This isn't correct. // We don't call getServerSideProps on clients. const getServerSideProps = PageNamespace.getServerSideProps; @@ -594,7 +593,7 @@ export async function render({ if (result) { if ("props" in result) { if (typeof result.props === "object") { - Object.assign(props, result.props); + Object.assign(pageProps, result.props); } } } @@ -615,7 +614,7 @@ export async function render({ if (result) { if ("props" in result) { if (typeof result.props === "object") { - Object.assign(props, result.props); + Object.assign(pageProps, result.props); } } } @@ -623,6 +622,7 @@ export async function render({ const renderToString = ReactDOMServer.renderToString; const ErrorDebug = null; + props.pageProps = pageProps; const renderPage: RenderPage = ( options: ComponentsEnhancer = {} @@ -648,7 +648,12 @@ export async function render({ const htmlOrPromise = renderToString( <AppContainer> - <EnhancedApp Component={EnhancedComponent} router={router} {...props} /> + <EnhancedApp + Component={EnhancedComponent} + router={router} + {...props} + pageProps={pageProps} + /> </AppContainer> ); return typeof htmlOrPromise === "string" diff --git a/packages/bun-framework-next/server.development.tsx b/packages/bun-framework-next/server.development.tsx index c6a7beebf..7391d9f32 100644 --- a/packages/bun-framework-next/server.development.tsx +++ b/packages/bun-framework-next/server.development.tsx @@ -1,23 +1,4 @@ -import * as React from "react"; -import { Buffer } from "buffer"; -globalThis.Buffer = Buffer; - -class URL { - constructor(base, source) { - this.pathname = source; - this.href = base + source; - } -} -var onlyChildPolyfill = React.Children.only; -React.Children.only = function (children) { - if (children && typeof children === "object" && children.length == 1) { - return onlyChildPolyfill(children[0]); - } - - return onlyChildPolyfill(children); -}; -globalThis.URL = URL; -globalThis.global = globalThis; +import "./polyfills"; import { render } from "./renderDocument"; let buildId = 0; @@ -40,14 +21,6 @@ import(Bun.routesDir + "_document").then( ); addEventListener("fetch", async (event: FetchEvent) => { - var appRoute; - - try { - appRoute = await import(Bun.routesDir + "_app"); - } catch (exception) { - appRoute = null; - } - const appStylesheets = (Bun.getImportedStyles() as string[]).slice(); var route = Bun.match(event); // This imports the currently matched route. @@ -57,6 +30,15 @@ addEventListener("fetch", async (event: FetchEvent) => { // It's recursive, so any file that imports a CSS file will be included. const pageStylesheets = (Bun.getImportedStyles() as string[]).slice(); + var appRoute; + + try { + appRoute = await import(Bun.routesDir + "_app"); + } catch (exception) { + appRoute = null; + } + const appStylesheets = (Bun.getImportedStyles() as string[]).slice(); + event.respondWith( render({ route, diff --git a/src/api/schema.d.ts b/src/api/schema.d.ts index 159cf4061..46429c9d0 100644 --- a/src/api/schema.d.ts +++ b/src/api/schema.d.ts @@ -401,6 +401,7 @@ type uint32 = number; development?: boolean; client_css_in_js?: CSSInJSBehavior; display_name?: string; + overrideModules?: StringMap; } export interface FrameworkEntryPoint { @@ -426,6 +427,7 @@ type uint32 = number; development: boolean; entry_points: FrameworkEntryPointMap; client_css_in_js: CSSInJSBehavior; + overrideModules: StringMap; } export interface LoadedRouteConfig { diff --git a/src/api/schema.js b/src/api/schema.js index 1b928aa20..c69b09834 100644 --- a/src/api/schema.js +++ b/src/api/schema.js @@ -1226,6 +1226,10 @@ function decodeFrameworkConfig(bb) { result["display_name"] = bb.readString(); break; + case 8: + result["overrideModules"] = decodeStringMap(bb); + break; + default: throw new Error("Attempted to parse invalid message"); } @@ -1277,6 +1281,12 @@ bb.writeByte(encoded); bb.writeByte(7); bb.writeString(value); } + + var value = message["overrideModules"]; + if (value != null) { + bb.writeByte(8); + encodeStringMap(value, bb); + } bb.writeByte(0); } @@ -1413,6 +1423,7 @@ function decodeLoadedFramework(bb) { result["development"] = !!bb.readByte(); result["entry_points"] = decodeFrameworkEntryPointMap(bb); result["client_css_in_js"] = CSSInJSBehavior[bb.readByte()]; + result["overrideModules"] = decodeStringMap(bb); return result; } @@ -1455,6 +1466,13 @@ bb.writeByte(encoded); throw new Error("Missing required field \"client_css_in_js\""); } + var value = message["overrideModules"]; + if (value != null) { + encodeStringMap(value, bb); + } else { + throw new Error("Missing required field \"overrideModules\""); + } + } function decodeLoadedRouteConfig(bb) { diff --git a/src/api/schema.peechy b/src/api/schema.peechy index a74059dca..fd887db3b 100644 --- a/src/api/schema.peechy +++ b/src/api/schema.peechy @@ -256,6 +256,8 @@ message FrameworkConfig { CSSInJSBehavior client_css_in_js = 6; string display_name = 7; + + StringMap overrideModules = 8; } struct FrameworkEntryPoint { @@ -281,6 +283,7 @@ struct LoadedFramework { bool development; FrameworkEntryPointMap entry_points; CSSInJSBehavior client_css_in_js; + StringMap overrideModules; } struct LoadedRouteConfig { diff --git a/src/api/schema.zig b/src/api/schema.zig index 980346698..13598e487 100644 --- a/src/api/schema.zig +++ b/src/api/schema.zig @@ -1340,6 +1340,9 @@ client_css_in_js: ?CssInJsBehavior = null, /// display_name display_name: ?[]const u8 = null, +/// overrideModules +override_modules: ?StringMap = null, + pub fn decode(reader: anytype) anyerror!FrameworkConfig { var this = std.mem.zeroes(FrameworkConfig); @@ -1369,6 +1372,9 @@ pub fn decode(reader: anytype) anyerror!FrameworkConfig { 7 => { this.display_name = try reader.readValue([]const u8); }, + 8 => { + this.override_modules = try reader.readValue(StringMap); +}, else => { return error.InvalidMessage; }, @@ -1406,6 +1412,10 @@ if (this.display_name) |display_name| { try writer.writeFieldID(7); try writer.writeValue(display_name); } +if (this.override_modules) |override_modules| { + try writer.writeFieldID(8); + try writer.writeValue(override_modules); +} try writer.endMessage(); } @@ -1551,6 +1561,9 @@ entry_points: FrameworkEntryPointMap, /// client_css_in_js client_css_in_js: CssInJsBehavior, +/// overrideModules +override_modules: StringMap, + pub fn decode(reader: anytype) anyerror!LoadedFramework { var this = std.mem.zeroes(LoadedFramework); @@ -1560,6 +1573,7 @@ pub fn decode(reader: anytype) anyerror!LoadedFramework { this.development = try reader.readValue(bool); this.entry_points = try reader.readValue(FrameworkEntryPointMap); this.client_css_in_js = try reader.readValue(CssInJsBehavior); + this.override_modules = try reader.readValue(StringMap); return this; } @@ -1569,6 +1583,7 @@ pub fn encode(this: *const @This(), writer: anytype) anyerror!void { try writer.writeInt(@intCast(u8, @boolToInt(this.development))); try writer.writeValue(this.entry_points); try writer.writeEnum(this.client_css_in_js); + try writer.writeValue(this.override_modules); } }; diff --git a/src/bundler.zig b/src/bundler.zig index 49ece989f..9b5371014 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -486,6 +486,7 @@ pub fn NewBundler(cache_files: bool) type { pub fn init(worker: *Worker, generator: *GenerateNodeModuleBundle) !void { worker.generator = generator; + worker.allocator = generator.allocator; worker.thread = try std.Thread.spawn(.{}, Worker.run, .{worker}); } @@ -754,6 +755,12 @@ pub fn NewBundler(cache_files: bool) type { try this.bundler.configureFramework(true); if (bundler.options.framework) |framework| { + if (framework.override_modules.keys.len > 0) { + bundler.options.framework.?.override_modules_hashes = allocator.alloc(u64, framework.override_modules.keys.len) catch unreachable; + for (framework.override_modules.keys) |key, i| { + bundler.options.framework.?.override_modules_hashes[i] = std.hash.Wyhash.hash(0, key); + } + } if (bundler.options.platform == .bun) { if (framework.server.isEnabled()) { const resolved = try bundler.linker.resolver.resolve( @@ -1074,7 +1081,14 @@ pub fn NewBundler(cache_files: bool) type { }; fn processImportRecord(this: *GenerateNodeModuleBundle, import_record: ImportRecord) !void {} - + var json_ast_symbols = [_]js_ast.Symbol{ + js_ast.Symbol{ .original_name = "$$m" }, + js_ast.Symbol{ .original_name = "exports" }, + js_ast.Symbol{ .original_name = "module" }, + js_ast.Symbol{ .original_name = "CONGRATS_YOU_FOUND_A_BUG" }, + }; + var json_ast_symbols_list = std.mem.span(&json_ast_symbols); + threadlocal var override_file_path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; pub fn processFile(this: *GenerateNodeModuleBundle, worker: *ThreadPool.Worker, _resolve: _resolver.Result) !void { const resolve = _resolve; if (resolve.is_external) return; @@ -1094,90 +1108,121 @@ pub fn NewBundler(cache_files: bool) type { // If we're in a node_module, build that almost normally if (is_from_node_modules) { - switch (loader) { - .jsx, - .tsx, - .js, - .ts, - => { - var written: usize = undefined; - var code_offset: u32 = 0; - - const entry: CacheEntry = brk: { - if (!strings.eqlComptime(file_path.namespace, "node")) - break :brk try bundler.resolver.caches.fs.readFileShared( - bundler.fs, - file_path.textZ(), - resolve.dirname_fd, - if (resolve.file_fd != 0) resolve.file_fd else null, - shared_buffer, - ); - - var module_name = file_path.text["/bun-vfs/node_modules/".len..]; - - if (module_name[0] == '@') { - var end = strings.indexOfChar(module_name, '/').? + 1; - end += strings.indexOfChar(module_name[end..], '/').?; - - module_name = module_name[0..end]; - } else { - module_name = module_name[0..strings.indexOfChar(module_name, '/').?]; - } - - if (NodeFallbackModules.Map.get(module_name)) |mod| { - break :brk CacheEntry{ .contents = mod.code.* }; - } + var written: usize = undefined; + var code_offset: u32 = 0; + + const module_data = BundledModuleData.get(this, &resolve) orelse { + const fake_path = logger.Source.initPathString(file_path.text, ""); + log.addResolveError( + &fake_path, + logger.Range.None, + this.allocator, + "Bug while resolving: \"{s}\"", + .{file_path.text}, + resolve.import_kind, + ) catch {}; + return error.ResolveError; + }; - break :brk CacheEntry{ - .contents = "", + const module_id = module_data.module_id; + const package = module_data.package; + const package_relative_path = module_data.import_path; + + file_path.pretty = module_data.package_path; + + const entry: CacheEntry = brk: { + if (this.bundler.options.framework.?.override_modules_hashes.len > 0) { + const package_relative_path_hash = std.hash.Wyhash.hash(0, module_data.package_path); + if (std.mem.indexOfScalar( + u64, + this.bundler.options.framework.?.override_modules_hashes, + package_relative_path_hash, + )) |index| { + const relative_path = [_]string{ + this.bundler.options.framework.?.resolved_dir, + this.bundler.options.framework.?.override_modules.values[index], }; - }; + var override_path = this.bundler.fs.absBuf( + &relative_path, + &override_file_path_buf, + ); + override_file_path_buf[override_path.len] = 0; + var override_pathZ = override_file_path_buf[0..override_path.len :0]; + break :brk try bundler.resolver.caches.fs.readFileShared( + bundler.fs, + override_pathZ, + 0, + null, + shared_buffer, + ); + } + } - const module_data = BundledModuleData.get(this, &resolve) orelse { - const source = logger.Source.initPathString(file_path.text, entry.contents); - log.addResolveError( - &source, - logger.Range.None, - this.allocator, - "Bug while resolving: \"{s}\"", - .{file_path.text}, - resolve.import_kind, - ) catch {}; - return error.ResolveError; - }; - const module_id = module_data.module_id; - const package = module_data.package; - const package_relative_path = module_data.import_path; - file_path.pretty = module_data.package_path; - - // Handle empty files - // We can't just ignore them. Sometimes code will try to import it. Often because of TypeScript types. - // So we just say it's an empty object. Empty object mimicks what "browser": false does as well. - // TODO: optimize this so that all the exports for these are done in one line instead of writing repeatedly - if (entry.contents.len == 0 or (entry.contents.len < 33 and strings.trim(entry.contents, " \n\r").len == 0)) { - this.write_lock.lock(); - defer this.write_lock.unlock(); - code_offset = @truncate(u32, try this.tmpfile.getPos()); - var writer = this.tmpfile.writer(); - var buffered = std.io.bufferedWriter(writer); - - var bufwriter = buffered.writer(); - try bufwriter.writeAll("// "); - try bufwriter.writeAll(package_relative_path); - try bufwriter.writeAll("\nexport var $"); - std.fmt.formatInt(module_id, 16, .lower, .{}, bufwriter) catch unreachable; - try bufwriter.writeAll(" = () => ({});\n"); - try buffered.flush(); - this.tmpfile_byte_offset = @truncate(u32, try this.tmpfile.getPos()); - } else { - const source = logger.Source.initRecycledFile( - Fs.File{ - .path = file_path, - .contents = entry.contents, - }, - bundler.allocator, - ) catch return null; + if (!strings.eqlComptime(file_path.namespace, "node")) + break :brk try bundler.resolver.caches.fs.readFileShared( + bundler.fs, + file_path.textZ(), + resolve.dirname_fd, + if (resolve.file_fd != 0) resolve.file_fd else null, + shared_buffer, + ); + + var module_name = file_path.text["/bun-vfs/node_modules/".len..]; + + if (module_name[0] == '@') { + var end = strings.indexOfChar(module_name, '/').? + 1; + end += strings.indexOfChar(module_name[end..], '/').?; + + module_name = module_name[0..end]; + } else { + module_name = module_name[0..strings.indexOfChar(module_name, '/').?]; + } + if (NodeFallbackModules.Map.get(module_name)) |mod| { + break :brk CacheEntry{ .contents = mod.code.* }; + } + + break :brk CacheEntry{ + .contents = "", + }; + }; + + // Handle empty files + // We can't just ignore them. Sometimes code will try to import it. Often because of TypeScript types. + // So we just say it's an empty object. Empty object mimicks what "browser": false does as well. + // TODO: optimize this so that all the exports for these are done in one line instead of writing repeatedly + if (entry.contents.len == 0 or (entry.contents.len < 33 and strings.trim(entry.contents, " \n\r").len == 0)) { + this.write_lock.lock(); + defer this.write_lock.unlock(); + code_offset = @truncate(u32, try this.tmpfile.getPos()); + var writer = this.tmpfile.writer(); + var buffered = std.io.bufferedWriter(writer); + + var bufwriter = buffered.writer(); + try bufwriter.writeAll("// "); + try bufwriter.writeAll(package_relative_path); + try bufwriter.writeAll("(disabled or empty file) \nexport var $"); + std.fmt.formatInt(module_id, 16, .lower, .{}, bufwriter) catch unreachable; + try bufwriter.writeAll(" = () => (var obj = {}, Object.defineProperty(obj, 'default', { value: obj, enumerable: false, configurable: true }, obj);\n"); + try buffered.flush(); + this.tmpfile_byte_offset = @truncate(u32, try this.tmpfile.getPos()); + } else { + var ast: js_ast.Ast = undefined; + + const source = logger.Source.initRecycledFile( + Fs.File{ + .path = file_path, + .contents = entry.contents, + }, + bundler.allocator, + ) catch return null; + + switch (loader) { + .jsx, + .tsx, + .js, + .ts, + => { var jsx = bundler.options.jsx; jsx.parse = loader.isJSX(); @@ -1186,7 +1231,7 @@ pub fn NewBundler(cache_files: bool) type { opts.enable_bundling = true; opts.warn_about_unbundled_modules = false; - var ast: js_ast.Ast = (try bundler.resolver.caches.js.parse( + ast = (try bundler.resolver.caches.js.parse( bundler.allocator, opts, bundler.options.define, @@ -1291,193 +1336,215 @@ pub fn NewBundler(cache_files: bool) type { } } } + }, + .json => { + var expr = json_parser.ParseJSON(&source, worker.data.log, worker.allocator) catch return; + var stmt = js_ast.Stmt.alloc(worker.allocator, js_ast.S.ExportDefault{ + .value = js_ast.StmtOrExpr{ .expr = expr }, + .default_name = js_ast.LocRef{ .loc = logger.Loc{}, .ref = Ref{} }, + }, logger.Loc{ .start = 0 }); + var stmts = worker.allocator.alloc(js_ast.Stmt, 1) catch unreachable; + stmts[0] = stmt; + var parts = worker.allocator.alloc(js_ast.Part, 1) catch unreachable; + parts[0] = js_ast.Part{ .stmts = stmts }; + ast = js_ast.Ast.initTest(parts); + + ast.runtime_imports = runtime.Runtime.Imports{}; + ast.runtime_imports.register = Ref{ .source_index = 0, .inner_index = 0 }; + ast.runtime_imports.__export = Ref{ .source_index = 0, .inner_index = 1 }; + ast.symbols = json_ast_symbols_list; + ast.module_ref = Ref{ .source_index = 0, .inner_index = 2 }; + ast.exports_ref = ast.runtime_imports.__export; + ast.bundle_export_ref = Ref{ .source_index = 0, .inner_index = 3 }; + }, + else => { + return; + }, + } - // const load_from_symbol_ref = ast.runtime_imports.$$r.?; - // const reexport_ref = ast.runtime_imports.__reExport.?; - const register_ref = ast.runtime_imports.register.?; - const E = js_ast.E; - const Expr = js_ast.Expr; - const Stmt = js_ast.Stmt; - - var prepend_part: js_ast.Part = undefined; - var needs_prepend_part = false; - if (ast.parts.len > 1) { - for (ast.parts) |part| { - if (part.tag != .none and part.stmts.len > 0) { - prepend_part = part; - needs_prepend_part = true; - break; - } - } - } - - if (ast.parts.len == 0) { - if (comptime isDebug) { - Output.prettyErrorln("Missing AST for file: {s}", .{file_path.text}); - Output.flush(); - } + // const load_from_symbol_ref = ast.runtime_imports.$$r.?; + // const reexport_ref = ast.runtime_imports.__reExport.?; + const register_ref = ast.runtime_imports.register.?; + const E = js_ast.E; + const Expr = js_ast.Expr; + const Stmt = js_ast.Stmt; + + var prepend_part: js_ast.Part = undefined; + var needs_prepend_part = false; + if (ast.parts.len > 1) { + for (ast.parts) |part| { + if (part.tag != .none and part.stmts.len > 0) { + prepend_part = part; + needs_prepend_part = true; + break; } + } + } - var part = &ast.parts[ast.parts.len - 1]; - var new_stmts: [1]Stmt = undefined; - var register_args: [3]Expr = undefined; - - var package_json_string = E.String{ .utf8 = package.name }; - var module_path_string = E.String{ .utf8 = module_data.import_path }; - var target_identifier = E.Identifier{ .ref = register_ref }; - var cjs_args: [2]js_ast.G.Arg = undefined; - var module_binding = js_ast.B.Identifier{ .ref = ast.module_ref.? }; - var exports_binding = js_ast.B.Identifier{ .ref = ast.exports_ref.? }; - - // if (!ast.uses_module_ref) { - // var symbol = &ast.symbols[ast.module_ref.?.inner_index]; - // symbol.original_name = "_$$"; - // } - - cjs_args[0] = js_ast.G.Arg{ - .binding = js_ast.Binding{ - .loc = logger.Loc.Empty, - .data = .{ .b_identifier = &module_binding }, - }, - }; - cjs_args[1] = js_ast.G.Arg{ - .binding = js_ast.Binding{ - .loc = logger.Loc.Empty, - .data = .{ .b_identifier = &exports_binding }, - }, - }; + if (ast.parts.len == 0) { + if (comptime isDebug) { + Output.prettyErrorln("Missing AST for file: {s}", .{file_path.text}); + Output.flush(); + } + } - var closure = E.Arrow{ - .args = &cjs_args, - .body = .{ - .loc = logger.Loc.Empty, - .stmts = part.stmts, - }, - }; + var part = &ast.parts[ast.parts.len - 1]; + var new_stmts: [1]Stmt = undefined; + var register_args: [3]Expr = undefined; + + var package_json_string = E.String{ .utf8 = package.name }; + var module_path_string = E.String{ .utf8 = module_data.import_path }; + var target_identifier = E.Identifier{ .ref = register_ref }; + var cjs_args: [2]js_ast.G.Arg = undefined; + var module_binding = js_ast.B.Identifier{ .ref = ast.module_ref.? }; + var exports_binding = js_ast.B.Identifier{ .ref = ast.exports_ref.? }; + + // if (!ast.uses_module_ref) { + // var symbol = &ast.symbols[ast.module_ref.?.inner_index]; + // symbol.original_name = "_$$"; + // } + + cjs_args[0] = js_ast.G.Arg{ + .binding = js_ast.Binding{ + .loc = logger.Loc.Empty, + .data = .{ .b_identifier = &module_binding }, + }, + }; + cjs_args[1] = js_ast.G.Arg{ + .binding = js_ast.Binding{ + .loc = logger.Loc.Empty, + .data = .{ .b_identifier = &exports_binding }, + }, + }; - // $$m(12345, "react", "index.js", function(module, exports) { + var closure = E.Arrow{ + .args = &cjs_args, + .body = .{ + .loc = logger.Loc.Empty, + .stmts = part.stmts, + }, + }; - // }) - register_args[0] = Expr{ .loc = .{ .start = 0 }, .data = .{ .e_string = &package_json_string } }; - register_args[1] = Expr{ .loc = .{ .start = 0 }, .data = .{ .e_string = &module_path_string } }; - register_args[2] = Expr{ .loc = .{ .start = 0 }, .data = .{ .e_arrow = &closure } }; + // $$m(12345, "react", "index.js", function(module, exports) { - var call_register = E.Call{ - .target = Expr{ - .data = .{ .e_identifier = &target_identifier }, - .loc = logger.Loc{ .start = 0 }, - }, - .args = ®ister_args, - }; - var register_expr = Expr{ .loc = call_register.target.loc, .data = .{ .e_call = &call_register } }; - var decls: [1]js_ast.G.Decl = undefined; - var bundle_export_binding = js_ast.B.Identifier{ .ref = ast.bundle_export_ref.? }; - var binding = js_ast.Binding{ - .loc = register_expr.loc, - .data = .{ .b_identifier = &bundle_export_binding }, - }; - decls[0] = js_ast.G.Decl{ - .value = register_expr, - .binding = binding, - }; - var export_var = js_ast.S.Local{ - .decls = &decls, - .is_export = true, - }; - new_stmts[0] = Stmt{ .loc = register_expr.loc, .data = .{ .s_local = &export_var } }; - part.stmts = &new_stmts; + // }) + register_args[0] = Expr{ .loc = .{ .start = 0 }, .data = .{ .e_string = &package_json_string } }; + register_args[1] = Expr{ .loc = .{ .start = 0 }, .data = .{ .e_string = &module_path_string } }; + register_args[2] = Expr{ .loc = .{ .start = 0 }, .data = .{ .e_arrow = &closure } }; - var writer = js_printer.NewFileWriter(this.tmpfile); - var symbols: [][]js_ast.Symbol = &([_][]js_ast.Symbol{ast.symbols}); + var call_register = E.Call{ + .target = Expr{ + .data = .{ .e_identifier = &target_identifier }, + .loc = logger.Loc{ .start = 0 }, + }, + .args = ®ister_args, + }; + var register_expr = Expr{ .loc = call_register.target.loc, .data = .{ .e_call = &call_register } }; + var decls: [1]js_ast.G.Decl = undefined; + var bundle_export_binding = js_ast.B.Identifier{ .ref = ast.bundle_export_ref.? }; + var binding = js_ast.Binding{ + .loc = register_expr.loc, + .data = .{ .b_identifier = &bundle_export_binding }, + }; + decls[0] = js_ast.G.Decl{ + .value = register_expr, + .binding = binding, + }; + var export_var = js_ast.S.Local{ + .decls = &decls, + .is_export = true, + }; + new_stmts[0] = Stmt{ .loc = register_expr.loc, .data = .{ .s_local = &export_var } }; + part.stmts = &new_stmts; - // It should only have one part. - ast.parts = ast.parts[ast.parts.len - 1 ..]; + var writer = js_printer.NewFileWriter(this.tmpfile); + var symbols: [][]js_ast.Symbol = &([_][]js_ast.Symbol{ast.symbols}); - const write_result = - try js_printer.printCommonJSThreaded( - @TypeOf(writer), - writer, - ast, - js_ast.Symbol.Map.initList(symbols), - &source, - false, - js_printer.Options{ - .to_module_ref = Ref.RuntimeRef, - .bundle_export_ref = ast.bundle_export_ref.?, - .source_path = file_path, - .externals = ast.externals, - .indent = 0, - .module_hash = module_id, - .runtime_imports = ast.runtime_imports, - .prepend_part_value = &prepend_part, - .prepend_part_key = if (needs_prepend_part) closure.body.stmts.ptr else null, - }, - Linker, - &bundler.linker, - &this.write_lock, - std.fs.File, - this.tmpfile, - std.fs.File.getPos, - ); + // It should only have one part. + ast.parts = ast.parts[ast.parts.len - 1 ..]; - code_offset = write_result.off; - written = write_result.len; + const write_result = + try js_printer.printCommonJSThreaded( + @TypeOf(writer), + writer, + ast, + js_ast.Symbol.Map.initList(symbols), + &source, + false, + js_printer.Options{ + .to_module_ref = Ref.RuntimeRef, + .bundle_export_ref = ast.bundle_export_ref.?, + .source_path = file_path, + .externals = ast.externals, + .indent = 0, + .module_hash = module_id, + .runtime_imports = ast.runtime_imports, + .prepend_part_value = &prepend_part, + .prepend_part_key = if (needs_prepend_part) closure.body.stmts.ptr else null, + }, + Linker, + &bundler.linker, + &this.write_lock, + std.fs.File, + this.tmpfile, + std.fs.File.getPos, + ); - // Faster to _not_ do the syscall - // But there's some off-by-one error somewhere and more reliable to just do the lseek - this.tmpfile_byte_offset = write_result.end_off; - } + code_offset = write_result.off; + written = write_result.len; - if (comptime isDebug) { - Output.prettyln("{s}@{s}/{s} - {d}:{d} \n", .{ package.name, package.version, package_relative_path, package.hash, module_id }); - Output.flush(); - std.debug.assert(package_relative_path.len > 0); - } + // Faster to _not_ do the syscall + // But there's some off-by-one error somewhere and more reliable to just do the lseek + this.tmpfile_byte_offset = write_result.end_off; - this.list_lock.lock(); - defer this.list_lock.unlock(); + if (comptime isDebug) { + Output.prettyln("{s}@{s}/{s} - {d}:{d} \n", .{ package.name, package.version, package_relative_path, package.hash, module_id }); + Output.flush(); + std.debug.assert(package_relative_path.len > 0); + } - const code_length = this.tmpfile_byte_offset - code_offset; + this.list_lock.lock(); + defer this.list_lock.unlock(); - if (comptime isDebug) { - std.debug.assert(code_length > 0); - std.debug.assert(package.hash != 0); - std.debug.assert(package.version.len > 0); - std.debug.assert(package.name.len > 0); - std.debug.assert(module_id > 0); - } + const code_length = this.tmpfile_byte_offset - code_offset; - var package_get_or_put_entry = try this.package_list_map.getOrPut(package.hash); + if (comptime isDebug) { + std.debug.assert(code_length > 0); + std.debug.assert(package.hash != 0); + std.debug.assert(package.version.len > 0); + std.debug.assert(package.name.len > 0); + std.debug.assert(module_id > 0); + } - if (!package_get_or_put_entry.found_existing) { - package_get_or_put_entry.value_ptr.* = @truncate(u32, this.package_list.items.len); - try this.package_list.append( - Api.JavascriptBundledPackage{ - .name = try this.appendHeaderString(package.name), - .version = try this.appendHeaderString(package.version), - .hash = package.hash, - }, - ); - this.has_jsx = this.has_jsx or strings.eql(package.name, this.bundler.options.jsx.package_name); - } + var package_get_or_put_entry = try this.package_list_map.getOrPut(package.hash); - var path_extname_length = @truncate(u8, std.fs.path.extension(package_relative_path).len); - try this.module_list.append( - Api.JavascriptBundledModule{ - .path = try this.appendHeaderString( - package_relative_path, - ), - .path_extname_length = path_extname_length, - .package_id = package_get_or_put_entry.value_ptr.*, - .id = module_id, - .code = Api.StringPointer{ - .length = @truncate(u32, code_length), - .offset = @truncate(u32, code_offset), - }, + if (!package_get_or_put_entry.found_existing) { + package_get_or_put_entry.value_ptr.* = @truncate(u32, this.package_list.items.len); + try this.package_list.append( + Api.JavascriptBundledPackage{ + .name = try this.appendHeaderString(package.name), + .version = try this.appendHeaderString(package.version), + .hash = package.hash, }, ); - }, - else => {}, + this.has_jsx = this.has_jsx or strings.eql(package.name, this.bundler.options.jsx.package_name); + } + + var path_extname_length = @truncate(u8, std.fs.path.extension(package_relative_path).len); + try this.module_list.append( + Api.JavascriptBundledModule{ + .path = try this.appendHeaderString( + package_relative_path, + ), + .path_extname_length = path_extname_length, + .package_id = package_get_or_put_entry.value_ptr.*, + .id = module_id, + .code = Api.StringPointer{ + .length = @truncate(u32, code_length), + .offset = @truncate(u32, code_offset), + }, + }, + ); } } else { // If it's app code, scan but do not fully parse. @@ -1586,10 +1653,7 @@ pub fn NewBundler(cache_files: bool) type { } } }, - // TODO: - else => { - return; - }, + else => {}, } } } diff --git a/src/deps/iguanaTLS/test/DSTRootCAX3.crt.pem b/src/deps/iguanaTLS/test/DSTRootCAX3.crt.pem new file mode 100644 index 000000000..ea08d57a2 --- /dev/null +++ b/src/deps/iguanaTLS/test/DSTRootCAX3.crt.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE-----
+MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
+MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
+DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
+PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
+Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
+rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
+OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
+xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
+7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
+aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
+SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
+ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
+AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
+R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
+JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
+Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
+-----END CERTIFICATE-----
diff --git a/src/deps/iguanaTLS/test/DigiCertGlobalRootCA.crt.pem b/src/deps/iguanaTLS/test/DigiCertGlobalRootCA.crt.pem new file mode 100644 index 000000000..fd4341df2 --- /dev/null +++ b/src/deps/iguanaTLS/test/DigiCertGlobalRootCA.crt.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- diff --git a/src/deps/iguanaTLS/test/DigiCertHighAssuranceEVRootCA.crt.pem b/src/deps/iguanaTLS/test/DigiCertHighAssuranceEVRootCA.crt.pem new file mode 100644 index 000000000..9e6810ab7 --- /dev/null +++ b/src/deps/iguanaTLS/test/DigiCertHighAssuranceEVRootCA.crt.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- diff --git a/src/deps/iguanaTLS/test/badssl.com-client.pem b/src/deps/iguanaTLS/test/badssl.com-client.pem new file mode 100644 index 000000000..16a2d1ad9 --- /dev/null +++ b/src/deps/iguanaTLS/test/badssl.com-client.pem @@ -0,0 +1,61 @@ +Bag Attributes + localKeyID: 41 C3 6C 33 C7 E3 36 DD EA 4A 1F C0 B7 23 B8 E6 9C DC D8 0F +subject=C = US, ST = California, L = San Francisco, O = BadSSL, CN = BadSSL Client Certificate + +issuer=C = US, ST = California, L = San Francisco, O = BadSSL, CN = BadSSL Client Root Certificate Authority + +-----BEGIN CERTIFICATE----- +MIIEqDCCApCgAwIBAgIUK5Ns4y2CzosB/ZoFlaxjZqoBTIIwDQYJKoZIhvcNAQEL +BQAwfjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM +DVNhbiBGcmFuY2lzY28xDzANBgNVBAoMBkJhZFNTTDExMC8GA1UEAwwoQmFkU1NM +IENsaWVudCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xOTExMjcwMDE5 +NTdaFw0yMTExMjYwMDE5NTdaMG8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp +Zm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ8wDQYDVQQKDAZCYWRTU0wx +IjAgBgNVBAMMGUJhZFNTTCBDbGllbnQgQ2VydGlmaWNhdGUwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDHN18R6x5Oz+u6SOXLoxIscz5GHR6cDcCLgyPa +x2XfXHdJs+h6fTy61WGM+aXEhR2SIwbj5997s34m0MsbvkJrFmn0LHK1fuTLCihE +EmxGdCGZA9xrwxFYAkEjP7D8v7cAWRMipYF/JP7VU7xNUo+QSkZ0sOi9k6bNkABK +L3+yP6PqAzsBoKIN5lN/YRLrppsDmk6nrRDo4R3CD+8JQl9quEoOmL22Pc/qpOjL +1jgOIFSE5y3gwbzDlfCYoAL5V+by1vu0yJShTTK8oo5wvphcFfEHaQ9w5jFg2htd +q99UER3BKuNDuL+zejqGQZCWb0Xsk8S5WBuX8l3Brrg5giqNAgMBAAGjLTArMAkG +A1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgeAMAsGA1UdDwQEAwIF4DANBgkqhkiG +9w0BAQsFAAOCAgEAZBauLzFSOijkDadcippr9C6laHebb0oRS54xAV70E9k5GxfR +/E2EMuQ8X+miRUMXxKquffcDsSxzo2ac0flw94hDx3B6vJIYvsQx9Lzo95Im0DdT +DkHFXhTlv2kjQwFVnEsWYwyGpHMTjanvNkO7sBP9p1bN1qTE3QAeyMZNKWJk5xPl +U298ERar6tl3Z2Cl8mO6yLhrq4ba6iPGw08SENxzuAJW+n8r0rq7EU+bMg5spgT1 +CxExzG8Bb0f98ZXMklpYFogkcuH4OUOFyRodotrotm3iRbuvZNk0Zz7N5n1oLTPl +bGPMwBcqaGXvK62NlaRkwjnbkPM4MYvREM0bbAgZD2GHyANBTso8bdWvhLvmoSjs +FSqJUJp17AZ0x/ELWZd69v2zKW9UdPmw0evyVR19elh/7dmtF6wbewc4N4jxQnTq +IItuhIWKWB9edgJz65uZ9ubQWjXoa+9CuWcV/1KxuKCbLHdZXiboLrKm4S1WmMYW +d0sJm95H9mJzcLyhLF7iX2kK6K9ug1y02YCVXBC9WGZc2x6GMS7lDkXSkJFy3EWh +CmfxkmFGwOgwKt3Jd1pF9ftcSEMhu4WcMgxi9vZr9OdkJLxmk033sVKI/hnkPaHw +g0Y2YBH5v0xmi8sYU7weOcwynkjZARpUltBUQ0pWCF5uJsEB8uE8PPDD3c4= +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAxzdfEeseTs/rukjly6MSLHM+Rh0enA3Ai4Mj2sdl31x3SbPo +en08utVhjPmlxIUdkiMG4+ffe7N+JtDLG75CaxZp9CxytX7kywooRBJsRnQhmQPc +a8MRWAJBIz+w/L+3AFkTIqWBfyT+1VO8TVKPkEpGdLDovZOmzZAASi9/sj+j6gM7 +AaCiDeZTf2ES66abA5pOp60Q6OEdwg/vCUJfarhKDpi9tj3P6qToy9Y4DiBUhOct +4MG8w5XwmKAC+Vfm8tb7tMiUoU0yvKKOcL6YXBXxB2kPcOYxYNobXavfVBEdwSrj +Q7i/s3o6hkGQlm9F7JPEuVgbl/Jdwa64OYIqjQIDAQABAoIBAFUQf7fW/YoJnk5c +8kKRzyDL1Lt7k6Zu+NiZlqXEnutRQF5oQ8yJzXS5yH25296eOJI+AqMuT28ypZtN +bGzcQOAZIgTxNcnp9Sf9nlPyyekLjY0Y6PXaxX0e+VFj0N8bvbiYUGNq6HCyC15r +8uvRZRvnm04YfEj20zLTWkxTG+OwJ6ZNha1vfq8z7MG5JTsZbP0g7e/LrEb3wI7J +Zu9yHQUzq23HhfhpmLN/0l89YLtOaS8WNq4QvKYgZapw/0G1wWoWW4Y2/UpAxZ9r +cqTBWSpCSCCgyWjiNhPbSJWfe/9J2bcanITLcvCLlPWGAHy1wpo9iBH57y7S+7YS +3yi7lgECgYEA8lwaRIChc38tmtQCNPtai/7uVDdeJe0uv8Jsg04FTF8KMYcD0V1g ++T7rUPA+rTHwv8uAGLdzl4NW5Qryw18rDY+UivnaZkEdEsnlo3fc8MSQF78dDHCX +nwmHfOmBnBoSbLl+W5ByHkJRHOnX+8qKq9ePNFUMf/hZNYuma9BCFBUCgYEA0m2p +VDn12YdhFUUBIH91aD5cQIsBhkHFU4vqW4zBt6TsJpFciWbrBrTeRzeDou59aIsn +zGBrLMykOY+EwwRku9KTVM4U791Z/NFbH89GqyUaicb4or+BXw5rGF8DmzSsDo0f +ixJ9TVD5DmDi3c9ZQ7ljrtdSxPdA8kOoYPFsApkCgYEA08uZSPQAI6aoe/16UEK4 +Rk9qhz47kHlNuVZ27ehoyOzlQ5Lxyy0HacmKaxkILOLPuUxljTQEWAv3DAIdVI7+ +WMN41Fq0eVe9yIWXoNtGwUGFirsA77YVSm5RcN++3GQMZedUfUAl+juKFvJkRS4j +MTkXdGw+mDa3/wsjTGSa2mECgYABO6NCWxSVsbVf6oeXKSgG9FaWCjp4DuqZErjM +0IZSDSVVFIT2SSQXZffncuvSiJMziZ0yFV6LZKeRrsWYXu44K4Oxe4Oj5Cgi0xc1 +mIFRf2YoaIIMchLP+8Wk3ummfyiC7VDB/9m8Gj1bWDX8FrrvKqbq31gcz1YSFVNn +PgLkAQKBgFzG8NdL8os55YcjBcOZMUs5QTKiQSyZM0Abab17k9JaqsU0jQtzeFsY +FTiwh2uh6l4gdO/dGC/P0Vrp7F05NnO7oE4T+ojDzVQMnFpCBeL7x08GfUQkphEG +m0Wqhhi8/24Sy934t5Txgkfoltg8ahkx934WjP6WWRnSAu+cf+vW +-----END RSA PRIVATE KEY----- diff --git a/src/deps/iguanaTLS/test/github.der b/src/deps/iguanaTLS/test/github.der Binary files differnew file mode 100644 index 000000000..dae019650 --- /dev/null +++ b/src/deps/iguanaTLS/test/github.der diff --git a/src/deps/iguanaTLS/test/github.pem b/src/deps/iguanaTLS/test/github.pem new file mode 100644 index 000000000..4b1bc66be --- /dev/null +++ b/src/deps/iguanaTLS/test/github.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
+ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
+LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
+RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
+PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
+xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
+Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
+hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
+EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
+FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
+nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
+eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
+hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
+Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
++OkuE6N36B9K
+-----END CERTIFICATE-----
diff --git a/src/deps/picohttp.zig b/src/deps/picohttp.zig index 3340793ca..7c081afc4 100644 --- a/src/deps/picohttp.zig +++ b/src/deps/picohttp.zig @@ -35,6 +35,14 @@ pub const Request = struct { minor_version: usize, headers: []const Header, + pub fn format(self: Request, comptime layout: []const u8, opts: fmt.FormatOptions, writer: anytype) !void { + try fmt.format(writer, "{s} {s}\n", .{ self.method, self.path }); + for (self.headers) |header| { + _ = try writer.write("\t"); + try fmt.format(writer, "{s}\n", .{header}); + } + } + pub fn parse(buf: []const u8, src: []Header) !Request { var method: []const u8 = undefined; var path: []const u8 = undefined; diff --git a/src/http_client.zig b/src/http_client.zig index e01d6aa92..cbc2ddedb 100644 --- a/src/http_client.zig +++ b/src/http_client.zig @@ -35,6 +35,7 @@ header_entries: Headers.Entries, header_buf: string, url: URL, allocator: *std.mem.Allocator, +verbose: bool = true, pub fn init(allocator: *std.mem.Allocator, method: Method, url: URL, header_entries: Headers.Entries, header_buf: string) HTTPClient { return HTTPClient{ @@ -155,7 +156,7 @@ pub fn buildRequest(this: *const HTTPClient, body_len: usize) picohttp.Request { return picohttp.Request{ .method = @tagName(this.method), - .path = this.url.path, + .path = this.url.pathname, .minor_version = 1, .headers = request_headers_buf[0..header_count], }; @@ -203,7 +204,9 @@ pub fn sendHTTP(this: *HTTPClient, body: []const u8, body_out_str: *MutableStrin std.os.closeSocket(client.socket.fd); } var request = buildRequest(this, body.len); - + if (this.verbose) { + Output.prettyErrorln("{s}", .{request}); + } var client_writer = client.writer(SOCKET_FLAGS); { var client_writer_buffered = std.io.bufferedWriter(client_writer); @@ -246,8 +249,10 @@ pub fn sendHTTP(this: *HTTPClient, body: []const u8, body_out_str: *MutableStrin switch (hashHeaderName(header.name)) { content_length_header_hash => { content_length = std.fmt.parseInt(u32, header.value, 10) catch 0; - try body_out_str.inflate(content_length); + // Always write a sentinel + try body_out_str.inflate(content_length + 1); body_out_str.list.expandToCapacity(); + body_out_str.list.items[content_length] = 0; }, content_encoding_hash => { return error.UnsupportedEncoding; @@ -311,6 +316,9 @@ pub fn sendHTTPS(this: *HTTPClient, body_str: []const u8, body_out_str: *Mutable } var request = buildRequest(this, body_str.len); + if (this.verbose) { + Output.prettyErrorln("{s}", .{request}); + } const body = body_str; var client_writer = client.writer(); diff --git a/src/javascript/jsc/webcore/response.zig b/src/javascript/jsc/webcore/response.zig index 680e8aa06..8b698bdea 100644 --- a/src/javascript/jsc/webcore/response.zig +++ b/src/javascript/jsc/webcore/response.zig @@ -105,16 +105,30 @@ pub const Response = struct { arguments: []const js.JSValueRef, exception: js.ExceptionRef, ) js.JSValueRef { - defer this.body.value = .Empty; var zig_string = ZigString.init(""); + var deallocate = false; + defer { + if (deallocate) { + if (this.body.value == .Unconsumed) { + this.body.ptr_allocator.?.free(this.body.ptr.?[0..this.body.len]); + this.body.ptr_allocator = null; + this.body.ptr = null; + this.body.len = 0; + } + } + + this.body.value = .Empty; + } - var js_string = (js.JSValueCreateJSONString( + var json_value = (js.JSValueMakeFromJSONString( ctx, brk: { switch (this.body.value) { .Unconsumed => { if (this.body.ptr) |_ptr| { zig_string = ZigString.init(_ptr[0..this.body.len]); + deallocate = true; + break :brk zig_string.toJSStringRef(); } @@ -133,8 +147,6 @@ pub const Response = struct { }, } }, - 0, - exception, ) orelse { var out = std.fmt.bufPrint(&temp_error_buffer, "Invalid JSON\n\n \"{s}\"", .{zig_string.slice()[0..std.math.min(zig_string.len, 4000)]}) catch unreachable; error_arg_list[0] = ZigString.init(out).toValueGC(VirtualMachine.vm.global).asRef(); @@ -150,16 +162,10 @@ pub const Response = struct { ), ).asRef(); }); - defer js.JSStringRelease(js_string); return JSPromise.resolvedPromiseValue( VirtualMachine.vm.global, - JSValue.fromRef( - js.JSValueMakeString( - ctx, - js_string, - ), - ), + JSValue.fromRef(json_value), ).asRef(); } pub fn getArrayBuffer( diff --git a/src/js_ast.zig b/src/js_ast.zig index 750100750..3b40a0127 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -1128,6 +1128,18 @@ pub const E = struct { } } + pub fn hash(s: *const String) u64 { + if (s.isBlank()) return 0; + + if (s.isUTF8()) { + // hash utf-8 + return std.hash.Wyhash.hash(0, s.utf8); + } else { + // hash utf-16 + return std.hash.Wyhash.hash(0, @ptrCast([*]u8, s.value.ptr)[0 .. s.value.len * 2]); + } + } + pub fn jsonStringify(s: *const String, options: anytype, writer: anytype) !void { var buf = [_]u8{0} ** 4096; var i: usize = 0; diff --git a/src/js_lexer.zig b/src/js_lexer.zig index 0cbe88ae9..265ccef18 100644 --- a/src/js_lexer.zig +++ b/src/js_lexer.zig @@ -2682,6 +2682,7 @@ pub const CodepointIterator = struct { // TODO: implement this to actually work right // this fn is a stub! pub fn rangeOfIdentifier(source: *const Source, loc: logger.Loc) logger.Range { + if (loc.start == -1) return logger.Range.None; const text = source.contents[loc.toUsize()..]; var r = logger.Range{ .loc = loc, .len = 0 }; if (text.len == 0) { diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index 274b79c20..a0ce4252f 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -10643,23 +10643,39 @@ pub fn NewParser( .classic => { // Arguments to createElement() const args = p.allocator.alloc(Expr, 2 + children_count) catch unreachable; + // There are at least two args: + // - name of the tag + // - props var i: usize = 1; args[0] = tag; if (e_.properties.len > 0) { + for (e_.properties) |prop, prop_i| { + if (prop.key) |key| { + e_.properties[prop_i].key = p.visitExpr(key); + } + + if (prop.value) |val| { + e_.properties[prop_i].value = p.visitExpr(val); + } + } + if (e_.key) |key| { - var props = List(G.Property).fromOwnedSlice(p.allocator, e_.properties); - props.append(G.Property{ .key = Expr{ .loc = key.loc, .data = keyExprData }, .value = key }) catch unreachable; - args[1] = p.e(E.Object{ .properties = props.toOwnedSlice() }, expr.loc); + var props = p.allocator.alloc(G.Property, e_.properties.len + 1) catch unreachable; + std.mem.copy(G.Property, props, e_.properties); + props[props.len - 1] = G.Property{ .key = Expr{ .loc = key.loc, .data = keyExprData }, .value = key }; + args[1] = p.e(E.Object{ .properties = props }, expr.loc); } else { args[1] = p.e(E.Object{ .properties = e_.properties }, expr.loc); } + i = 2; } else { args[1] = p.e(E.Null{}, expr.loc); + i = 2; } for (e_.children[0..children_count]) |child| { args[i] = p.visitExpr(child); - i += 1; + i += @intCast(usize, @boolToInt(args[i].data != .e_missing)); } // Call createElement() @@ -11227,9 +11243,9 @@ pub fn NewParser( } // maybe won't do this idk - if (Expr.maybeSimplifyNot(&e_.value, p.allocator)) |exp| { - return exp; - } + // if (Expr.maybeSimplifyNot(&e_.value, p.allocator)) |exp| { + // return exp; + // } }, .un_void => { if (p.exprCanBeRemovedIfUnused(&e_.value)) { diff --git a/src/js_printer.zig b/src/js_printer.zig index bf9286a9d..153a29850 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -3243,7 +3243,7 @@ pub fn NewPrinter( } } - pub fn printModuleExportSymbol(p: *Printer) void { + pub inline fn printModuleExportSymbol(p: *Printer) void { p.print("module.exports"); } @@ -3446,7 +3446,7 @@ pub fn NewPrinter( pub fn printBundledRexport(p: *Printer, name: string, import_record_index: u32) void { p.print("Object.defineProperty("); - p.print("module.exports"); + p.printModuleExportSymbol(); p.print(","); p.printQuotedUTF8(name, true); @@ -3456,13 +3456,11 @@ pub fn NewPrinter( } pub fn printBundledExport(p: *Printer, name: string, identifier: string) void { - p.print("Object.defineProperty("); - p.print("module.exports"); - p.print(","); - p.printQuotedUTF8(name, true); - p.print(",{get: () => ("); + p.printModuleExportSymbol(); + p.print("."); + p.printIdentifier(name); + p.print(" = "); p.printIdentifier(identifier); - p.print("), enumerable: true, configurable: true})"); } pub fn printForLoopInit(p: *Printer, initSt: Stmt) void { @@ -3603,7 +3601,10 @@ pub fn NewPrinter( pub fn printDeclStmt(p: *Printer, is_export: bool, comptime keyword: string, decls: []G.Decl) void { if (rewrite_esm_to_cjs and keyword[0] == 'v' and is_export) { // this is a top-level export - if (decls.len == 1 and std.meta.activeTag(decls[0].binding.data) == .b_identifier and decls[0].binding.data.b_identifier.ref.eql(p.options.bundle_export_ref.?)) { + if (decls.len == 1 and + std.meta.activeTag(decls[0].binding.data) == .b_identifier and + decls[0].binding.data.b_identifier.ref.eql(p.options.bundle_export_ref.?)) + { p.print("// "); p.print(p.options.source_path.?.pretty); p.print("\nexport var $"); diff --git a/src/json_parser.zig b/src/json_parser.zig index 8f8f415f3..4bb20f1cc 100644 --- a/src/json_parser.zig +++ b/src/json_parser.zig @@ -142,7 +142,7 @@ fn JSONLikeParser(opts: js_lexer.JSONOptions) type { try p.lexer.next(); var is_single_line = !p.lexer.has_newline_before; var properties = std.ArrayList(G.Property).init(p.allocator); - var duplicates = std.BufSet.init(p.allocator); + var duplicates = std.AutoHashMap(u64, void).init(p.allocator); defer duplicates.deinit(); while (p.lexer.token != .t_close_brace) { @@ -159,13 +159,13 @@ fn JSONLikeParser(opts: js_lexer.JSONOptions) type { } var str = p.lexer.toEString(); - const is_duplicate = duplicates.contains(p.lexer.string_literal_slice); - if (!is_duplicate) { - duplicates.insert(p.lexer.string_literal_slice) catch unreachable; - } + const hash_key = str.hash(); + const duplicate_get_or_put = duplicates.getOrPut(hash_key) catch unreachable; + duplicate_get_or_put.key_ptr.* = hash_key; + var key_range = p.lexer.range(); // Warn about duplicate keys - if (is_duplicate) { + if (duplicate_get_or_put.found_existing) { p.log.addRangeWarningFmt(p.source, key_range, p.allocator, "Duplicate key \"{s}\" in object literal", .{p.lexer.string_literal_slice}) catch unreachable; } diff --git a/src/node-fallbacks/@vercel_fetch.js b/src/node-fallbacks/@vercel_fetch.js index 5ab626670..95314ba9e 100644 --- a/src/node-fallbacks/@vercel_fetch.js +++ b/src/node-fallbacks/@vercel_fetch.js @@ -1,6 +1,8 @@ // This is just a no-op. Intent is to prevent importing a bunch of stuff that isn't relevant. -module.exports = (wrapper = Bun.fetch) => { - return async function vercelFetch(url, opts = {}) { +module.exports = ( + wrapper = "Bun" in globalThis ? Bun.fetch : globalThis.fetch +) => { + async function vercelFetch(url, opts = {}) { // Convert Object bodies to JSON if they are JS objects if ( opts.body && @@ -27,5 +29,8 @@ module.exports = (wrapper = Bun.fetch) => { err.opts = opts; throw err; } - }; + } + + vercelFetch.default = vercelFetch; + return vercelFetch; }; diff --git a/src/node-fallbacks/isomorphic-fetch.js b/src/node-fallbacks/isomorphic-fetch.js index 0bbe50ebf..96cbd72fb 100644 --- a/src/node-fallbacks/isomorphic-fetch.js +++ b/src/node-fallbacks/isomorphic-fetch.js @@ -1 +1 @@ -export default Bun.fetch; +export default "Bun" in globalThis ? Bun.fetch : globalThis.fetch; diff --git a/src/node-fallbacks/node-fetch.js b/src/node-fallbacks/node-fetch.js index 0bbe50ebf..96cbd72fb 100644 --- a/src/node-fallbacks/node-fetch.js +++ b/src/node-fallbacks/node-fetch.js @@ -1 +1 @@ -export default Bun.fetch; +export default "Bun" in globalThis ? Bun.fetch : globalThis.fetch; diff --git a/src/options.zig b/src/options.zig index 30f8dc018..a1c96dc1e 100644 --- a/src/options.zig +++ b/src/options.zig @@ -1611,6 +1611,10 @@ pub const Framework = struct { resolved: bool = false, from_bundle: bool = false, + resolved_dir: string = "", + override_modules: Api.StringMap = Api.StringMap{}, + override_modules_hashes: []u64 = &[_]u64{}, + client_css_in_js: Api.CssInJsBehavior = .auto_onimportcss, pub const fallback_html: string = @embedFile("./fallback.html"); @@ -1633,6 +1637,7 @@ pub const Framework = struct { .from_bundle = true, .client_css_in_js = loaded.client_css_in_js, .display_name = loaded.display_name, + .override_modules = loaded.override_modules, }; if (loaded.entry_points.fallback) |fallback| { @@ -1667,6 +1672,7 @@ pub const Framework = struct { .server = try this.server.toAPI(allocator, toplevel_path, .server), }, .client_css_in_js = this.client_css_in_js, + .override_modules = this.override_modules, }; } @@ -1701,6 +1707,7 @@ pub const Framework = struct { .package = transform.package orelse "", .display_name = transform.display_name orelse "", .development = transform.development orelse true, + .override_modules = transform.override_modules orelse .{ .keys = &.{}, .values = &.{} }, .resolved = false, .client_css_in_js = switch (transform.client_css_in_js orelse .auto_onimportcss) { .facade_onimportcss => .facade_onimportcss, diff --git a/src/query_string_map.zig b/src/query_string_map.zig index ddf90750f..4c451806d 100644 --- a/src/query_string_map.zig +++ b/src/query_string_map.zig @@ -226,7 +226,12 @@ pub const URL = struct { } if (base.len > path_offset and base[path_offset] == '/' and offset > 0) { - url.pathname = base[path_offset..std.math.min(offset, base.len)]; + if (url.search.len > 0) { + url.pathname = base[path_offset..std.math.min(offset + url.search.len, base.len)]; + } else { + url.pathname = base[path_offset..std.math.min(offset, base.len)]; + } + url.origin = base[0..path_offset]; } diff --git a/src/resolver/package_json.zig b/src/resolver/package_json.zig index 4547be9db..972feb06c 100644 --- a/src/resolver/package_json.zig +++ b/src/resolver/package_json.zig @@ -108,6 +108,29 @@ pub const PackageJSON = struct { } } + fn loadOverrides( + framework: *options.Framework, + json: *const js_ast.E.Object, + allocator: *std.mem.Allocator, + ) void { + var valid_count: usize = 0; + for (json.properties) |prop| { + if (prop.value.?.data != .e_string) continue; + valid_count += 1; + } + + var buffer = allocator.alloc([]const u8, valid_count * 2) catch unreachable; + var keys = buffer[0 .. buffer.len / 2]; + var values = buffer[keys.len..]; + var i: usize = 0; + for (json.properties) |prop| { + if (prop.value.?.data != .e_string) continue; + keys[i] = prop.key.?.data.e_string.string(allocator) catch unreachable; + values[i] = prop.value.?.data.e_string.string(allocator) catch unreachable; + } + framework.override_modules = Api.StringMap{ .keys = keys, .values = values }; + } + fn loadDefineExpression( env: *options.Env, json: *const js_ast.E.Object, @@ -178,6 +201,12 @@ pub const PackageJSON = struct { } } + if (json.asProperty("override")) |override| { + if (override.expr.data == .e_object) { + loadOverrides(framework, override.expr.data.e_object, allocator); + } + } + if (comptime read_define) { if (json.asProperty("define")) |defines| { var skip_fallback = false; diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index 4d8f91881..5cf860a88 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -509,6 +509,8 @@ pub fn NewResolver(cache_files: bool) type { var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + pair.framework.resolved_dir = pkg.source.path.sourceDir(); + if (pair.framework.client.isEnabled()) { var parts = [_]string{ dir, pair.framework.client.path }; const abs = r.fs.abs(&parts); diff --git a/src/runtime.js b/src/runtime.js index bcfd4c3fb..98cea8b8a 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -37,6 +37,7 @@ export var __toModule = (module) => { ); }; +var tagSymbol = Symbol("CommonJSTransformed"); export var __commonJS = (cb, name) => { var mod = {}; var has_run = false; @@ -59,21 +60,8 @@ export var __commonJS = (cb, name) => { if ( kind === "object" && "default" in mod.exports && - Object.keys(mod.exports).len === 1 - ) { - mod.exports = mod.exports.default; - Object.defineProperty(mod.exports, "default", { - get() { - return mod.exports; - }, - enumerable: true, - configurable: true, - }); - // If it's a namespace export without .default, pretend .default is the same as mod.exports - } else if ( - kind === "object" && - "default" in mod.exports && - Object.keys(mod.exports).len === 1 + !mod.exports[tagSymbol] && + Object.keys(mod.exports).length === 1 ) { mod.exports = mod.exports.default; Object.defineProperty(mod.exports, "default", { @@ -101,6 +89,14 @@ export var __commonJS = (cb, name) => { }); } + if (kind === "object" && !mod.exports[tagSymbol]) { + Object.defineProperty(mod.exports, tagSymbol, { + value: true, + enumerable: false, + configurable: false, + }); + } + return mod.exports; }, }[`require(${name})`]; diff --git a/src/runtime.version b/src/runtime.version index b309f488e..d4f951e04 100644 --- a/src/runtime.version +++ b/src/runtime.version @@ -1 +1 @@ -a36793f60275e5e9
\ No newline at end of file +c525e78958fc519b
\ No newline at end of file diff --git a/src/runtime.zig b/src/runtime.zig index 32c5f752e..7af295957 100644 --- a/src/runtime.zig +++ b/src/runtime.zig @@ -8,25 +8,23 @@ const Schema = @import("./api/schema.zig"); const Api = Schema.Api; -const ErrorCSSPath = "../examples/hello-next/bun-framework-next/bun-error.css"; +const ErrorCSSPath = "packages/bun-framework-next/bun-error.css"; pub const ErrorCSS = struct { pub const ProdSourceContent = @embedFile(ErrorCSSPath); pub fn sourceContent() string { if (comptime isDebug) { - var dirpath = std.fs.path.dirname(@src().file).?; var env = std.process.getEnvMap(default_allocator) catch unreachable; - - const dir = std.mem.replaceOwned( - u8, - default_allocator, - dirpath, - "jarred", - env.get("USER").?, + var out_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; + var dirname = std.fs.selfExeDirPath(&out_buffer) catch unreachable; + var paths = [_]string{ dirname, "../../../", ErrorCSSPath }; + const file = std.fs.cwd().openFile( + resolve_path.joinAbsString(dirname, std.mem.span(&paths), .auto), + .{ + .read = true, + }, ) catch unreachable; - var runtime_path = std.fs.path.join(default_allocator, &[_]string{ dir, ErrorCSSPath }) catch unreachable; - const file = std.fs.openFileAbsolute(runtime_path, .{}) catch unreachable; defer file.close(); return file.readToEndAlloc(default_allocator, (file.stat() catch unreachable).size) catch unreachable; } else { diff --git a/src/runtime/hmr.ts b/src/runtime/hmr.ts index dc72f469d..5c91683a2 100644 --- a/src/runtime/hmr.ts +++ b/src/runtime/hmr.ts @@ -611,7 +611,6 @@ if (typeof window !== "undefined") { this.client.verbose = verbose; this.client.start(); globalThis["__BUN_HMR"] = this.client; - globalThis["__BUN"] = this; } handleBuildFailure(buffer: ByteBuffer, timestamp: number) { @@ -1341,6 +1340,7 @@ if (typeof window !== "undefined") { window.addEventListener("error", HMRClient.onError, { passive: true }); } + globalThis["__BUN"] = HMRClient; } export { __HMRModule, __FastRefreshModule, __HMRClient }; diff --git a/src/string_immutable.zig b/src/string_immutable.zig index a68059aef..923d860cc 100644 --- a/src/string_immutable.zig +++ b/src/string_immutable.zig @@ -660,6 +660,21 @@ pub const CodepointIterator = struct { return if (!(it.i > it.bytes.len)) it.bytes[it.i - cp_len .. it.i] else ""; } + pub fn needsUTF8Decoding(slice: string) bool { + var it = CodepointIterator{ .bytes = slice, .i = 0 }; + + while (true) { + const part = it.nextCodepointSlice(); + it.width = @intCast(u3, part.len); + @setRuntimeSafety(false); + switch (it.width) { + 0 => return false, + 1 => continue, + else => return true, + } + } + } + pub fn nextCodepoint(it: *CodepointIterator) CodePoint { const slice = it.nextCodepointSlice(); it.width = @intCast(u3, slice.len); |