81 lines
2.8 KiB
TypeScript
81 lines
2.8 KiB
TypeScript
import { contentType } from "jsr:@std/media-types";
|
|
import { transpile } from "jsr:@deno/emit";
|
|
import config from "./deno.json" with { type: "json" };
|
|
|
|
const jsContentType = contentType(".js");
|
|
|
|
export enum MediaType {
|
|
TypeScript,
|
|
JSX,
|
|
TSX,
|
|
};
|
|
|
|
// https://github.com/denoland/deno_ast/blob/ea1ccec37e1aa8e5e1e70f983a7ed1472d0e132a/src/media_type.rs#L117
|
|
const customContentType = {
|
|
[MediaType.TypeScript]: "text/typescript; charset=utf-8",
|
|
[MediaType.JSX]: "text/jsx; charset=utf-8",
|
|
[MediaType.TSX]: "text/tsx; charset=utf-8",
|
|
};
|
|
|
|
async function rewriteTsResponse(response: Response, url: URL, mediaType: MediaType) {
|
|
const tsCode = await response.text();
|
|
const targetUrlStr = url.toString();
|
|
try {
|
|
const result = await transpile(url, {
|
|
importMap: config,
|
|
compilerOptions: config.compilerOptions,
|
|
load(specifier) {
|
|
if (specifier !== targetUrlStr) {
|
|
return Promise.resolve({
|
|
kind: "module",
|
|
specifier,
|
|
content: "",
|
|
headers: { "content-type": "application/javascript; charset=utf-8" },
|
|
});
|
|
} else {
|
|
return Promise.resolve({
|
|
kind: "module",
|
|
specifier,
|
|
content: tsCode,
|
|
headers: {
|
|
"content-type": customContentType[mediaType],
|
|
},
|
|
});
|
|
}
|
|
},
|
|
});
|
|
const jsCode = result.get(targetUrlStr);
|
|
const { headers } = response;
|
|
headers.set("content-type", jsContentType);
|
|
headers.delete("content-length");
|
|
|
|
return new Response(jsCode, {
|
|
status: response.status,
|
|
statusText: response.statusText,
|
|
headers,
|
|
});
|
|
} catch (e) {
|
|
console.error(e);
|
|
return new Response(`${e}`, {
|
|
status: 500,
|
|
statusText: `${e}`,
|
|
headers: response.headers,
|
|
});
|
|
}
|
|
}
|
|
|
|
export default async function transpileResponse(response: Response, requestUrl: string, filepath?: string): Promise<Response> {
|
|
const url = new URL(`ts-serve:///${ requestUrl }`);
|
|
if (response.status !== 200) {
|
|
return response;
|
|
}
|
|
const pathname = filepath !== undefined ? filepath : url.pathname;
|
|
const extension = pathname.split('.').at(-1) ?? null;
|
|
switch (extension) {
|
|
case 'ts': return await rewriteTsResponse(response, url, MediaType.TypeScript);
|
|
case 'tsx': return await rewriteTsResponse(response, url, MediaType.TSX);
|
|
case 'jsx': return await rewriteTsResponse(response, url, MediaType.JSX);
|
|
default: return response;
|
|
}
|
|
}
|