import { CompilerOptions, transpile, TranspileOptions } from "jsr:@deno/emit"; import denoJson from "./deno.json" with { type: "json" }; const contentTypes = { "js": "application/javascript; charset=utf-8", // https://github.com/denoland/deno_ast/blob/ea1ccec37e1aa8e5e1e70f983a7ed1472d0e132a/src/media_type.rs#L117 "ts": "text/typescript; charset=utf-8", "jsx": "text/jsx; charset=utf-8", "tsx": "text/tsx; charset=utf-8", } as const; const transpileOptions = ( extension: keyof typeof contentTypes, tsCode: string, targetUrlStr: string, ): TranspileOptions => ({ importMap: { imports: denoJson.imports, }, compilerOptions: denoJson.compilerOptions as CompilerOptions, load(specifier) { const correctContent = specifier === targetUrlStr; return Promise.resolve({ kind: "module", specifier, content: correctContent ? tsCode : "", headers: { "content-type": contentTypes[correctContent ? extension : "js"] }, }); }, }); export default async function transpileResponse( response: Response, requestUrl: string, filepath?: string, ): Promise { const url = new URL(`ts-serve:///${requestUrl}`); const pathname = filepath !== undefined ? filepath : url.pathname; const extension = pathname.split(".").at(-1) ?? ""; if (response.status === 200 && (extension === "ts" || extension === "tsx" || extension === "jsx")) { const tsCode = await response.text(); const targetUrlStr = url.toString(); try { const result = await transpile(url, transpileOptions(extension, tsCode, targetUrlStr)); const jsCode = result.get(targetUrlStr); response.headers.delete("content-length"); response.headers.set("content-type", contentTypes.js); return new Response(jsCode, { status: response.status, statusText: response.statusText, headers: response.headers, }); } catch (e) { console.error("[transpileResponse]: Error transpiling!\n", e); if (typeof e === "string") { return new Response("Internal Server Error", { status: 500, headers: response.headers, }); } } } return response; }