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; }