add esbuild loader
parent
bc82791626
commit
4f122bbb9c
|
@ -1 +0,0 @@
|
||||||
Subproject commit 70c34bb6d77b2dd05255f0e4a813bb62239d62d1
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Luca Casonato
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,21 @@
|
||||||
|
# esbuild_deno_loader
|
||||||
|
|
||||||
|
Deno module resolution for `esbuild`.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
This example bundles an entrypoint into a single ESM output.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import * as esbuild from "https://deno.land/x/esbuild@v0.14.51/mod.js";
|
||||||
|
import { denoPlugin } from "https://deno.land/x/esbuild_deno_loader@0.5.2/mod.ts";
|
||||||
|
|
||||||
|
await esbuild.build({
|
||||||
|
plugins: [denoPlugin()],
|
||||||
|
entryPoints: ["https://deno.land/std@0.150.0/hash/sha1.ts"],
|
||||||
|
outfile: "./dist/sha1.esm.js",
|
||||||
|
bundle: true,
|
||||||
|
format: "esm",
|
||||||
|
});
|
||||||
|
esbuild.stop();
|
||||||
|
```
|
|
@ -0,0 +1,13 @@
|
||||||
|
import type * as esbuild from "https://deno.land/x/esbuild@v0.14.54/mod.d.ts";
|
||||||
|
export type { esbuild };
|
||||||
|
export {
|
||||||
|
fromFileUrl,
|
||||||
|
resolve,
|
||||||
|
toFileUrl,
|
||||||
|
} from "https://deno.land/std@0.150.0/path/mod.ts";
|
||||||
|
export { basename, extname } from "https://deno.land/std@0.150.0/path/mod.ts";
|
||||||
|
export {
|
||||||
|
resolveImportMap,
|
||||||
|
resolveModuleSpecifier,
|
||||||
|
} from "https://deno.land/x/importmap@0.2.1/mod.ts";
|
||||||
|
export type { ImportMap } from "https://deno.land/x/importmap@0.2.1/mod.ts";
|
|
@ -0,0 +1,11 @@
|
||||||
|
import * as esbuild from "https://deno.land/x/esbuild@v0.14.51/mod.js";
|
||||||
|
import { denoPlugin } from "https://deno.land/x/esbuild_deno_loader@0.5.2/mod.ts";
|
||||||
|
|
||||||
|
await esbuild.build({
|
||||||
|
plugins: [denoPlugin()],
|
||||||
|
entryPoints: ["https://deno.land/std@0.150.0/hash/sha1.ts"],
|
||||||
|
outfile: "./dist/sha1.esm.js",
|
||||||
|
bundle: true,
|
||||||
|
format: "esm",
|
||||||
|
});
|
||||||
|
esbuild.stop();
|
|
@ -0,0 +1,11 @@
|
||||||
|
test:
|
||||||
|
deno test -A
|
||||||
|
|
||||||
|
lint:
|
||||||
|
deno lint
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
deno fmt
|
||||||
|
|
||||||
|
fmt/check:
|
||||||
|
deno fmt --check
|
|
@ -0,0 +1,110 @@
|
||||||
|
import {
|
||||||
|
esbuild,
|
||||||
|
ImportMap,
|
||||||
|
resolveImportMap,
|
||||||
|
resolveModuleSpecifier,
|
||||||
|
toFileUrl,
|
||||||
|
} from "./deps.ts";
|
||||||
|
import { load as nativeLoad } from "./src/native_loader.ts";
|
||||||
|
import { load as portableLoad } from "./src/portable_loader.ts";
|
||||||
|
import { ModuleEntry } from "./src/deno.ts";
|
||||||
|
|
||||||
|
export interface DenoPluginOptions {
|
||||||
|
/**
|
||||||
|
* Specify the URL to an import map to use when resolving import specifiers.
|
||||||
|
* The URL must be fetchable with `fetch`.
|
||||||
|
*/
|
||||||
|
importMapURL?: URL;
|
||||||
|
/**
|
||||||
|
* Specify which loader to use. By default this will use the `native` loader,
|
||||||
|
* unless `Deno.run` is not available.
|
||||||
|
*
|
||||||
|
* - `native`: Shells out to the Deno execuatble under the hood to load
|
||||||
|
* files. Requires --allow-read and --allow-run.
|
||||||
|
* - `portable`: Do module downloading and caching with only Web APIs.
|
||||||
|
* Requires --allow-net.
|
||||||
|
*/
|
||||||
|
loader?: "native" | "portable";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The default loader to use. */
|
||||||
|
export const DEFAULT_LOADER: "native" | "portable" =
|
||||||
|
typeof Deno.run === "function" ? "native" : "portable";
|
||||||
|
|
||||||
|
export function denoPlugin(options: DenoPluginOptions = {}): esbuild.Plugin {
|
||||||
|
const loader = options.loader ?? DEFAULT_LOADER;
|
||||||
|
return {
|
||||||
|
name: "deno",
|
||||||
|
setup(build) {
|
||||||
|
const infoCache = new Map<string, ModuleEntry>();
|
||||||
|
let importMap: ImportMap | null = null;
|
||||||
|
|
||||||
|
build.onStart(async function onStart() {
|
||||||
|
if (options.importMapURL !== undefined) {
|
||||||
|
const resp = await fetch(options.importMapURL.href);
|
||||||
|
const txt = await resp.text();
|
||||||
|
importMap = resolveImportMap(JSON.parse(txt), options.importMapURL);
|
||||||
|
} else {
|
||||||
|
importMap = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
build.onResolve(
|
||||||
|
{ filter: /.*/ },
|
||||||
|
function onResolve(
|
||||||
|
args: esbuild.OnResolveArgs,
|
||||||
|
): esbuild.OnResolveResult | null | undefined {
|
||||||
|
// console.log("To resolve", args.path);
|
||||||
|
const resolveDir = args.resolveDir
|
||||||
|
? `${toFileUrl(args.resolveDir).href}/`
|
||||||
|
: "";
|
||||||
|
const referrer = args.importer || resolveDir;
|
||||||
|
let resolved: URL;
|
||||||
|
if (importMap !== null) {
|
||||||
|
const res = resolveModuleSpecifier(
|
||||||
|
args.path,
|
||||||
|
importMap,
|
||||||
|
new URL(referrer) || undefined,
|
||||||
|
);
|
||||||
|
resolved = new URL(res);
|
||||||
|
} else {
|
||||||
|
resolved = new URL(args.path, referrer);
|
||||||
|
}
|
||||||
|
// console.log("Resolved", resolved.href);
|
||||||
|
if (build.initialOptions.external) {
|
||||||
|
for (const external of build.initialOptions.external) {
|
||||||
|
if (resolved.href.startsWith(external)) {
|
||||||
|
// console.log("Got external", args.path, resolved.href);
|
||||||
|
return { path: resolved.href, external: true };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resolved.href.endsWith(".css")) {
|
||||||
|
return {
|
||||||
|
path: resolved.href.substring("file://".length),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return { path: resolved.href, namespace: "deno" };
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
build.onLoad(
|
||||||
|
{ filter: /.*/ },
|
||||||
|
function onLoad(
|
||||||
|
args: esbuild.OnLoadArgs,
|
||||||
|
): Promise<esbuild.OnLoadResult | null> {
|
||||||
|
if (args.path.endsWith(".css")) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
const url = new URL(args.path);
|
||||||
|
switch (loader) {
|
||||||
|
case "native":
|
||||||
|
return nativeLoad(infoCache, url, options);
|
||||||
|
case "portable":
|
||||||
|
return portableLoad(url, options);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
// Lifted from https://raw.githubusercontent.com/denoland/deno_graph/89affe43c9d3d5c9165c8089687c107d53ed8fe1/lib/media_type.ts
|
||||||
|
export type MediaType =
|
||||||
|
| "JavaScript"
|
||||||
|
| "Mjs"
|
||||||
|
| "Cjs"
|
||||||
|
| "JSX"
|
||||||
|
| "TypeScript"
|
||||||
|
| "Mts"
|
||||||
|
| "Cts"
|
||||||
|
| "Dts"
|
||||||
|
| "Dmts"
|
||||||
|
| "Dcts"
|
||||||
|
| "TSX"
|
||||||
|
| "Json"
|
||||||
|
| "Wasm"
|
||||||
|
| "TsBuildInfo"
|
||||||
|
| "SourceMap"
|
||||||
|
| "Unknown";
|
||||||
|
|
||||||
|
export interface InfoOutput {
|
||||||
|
roots: string[];
|
||||||
|
modules: ModuleEntry[];
|
||||||
|
redirects: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ModuleEntry {
|
||||||
|
specifier: string;
|
||||||
|
size: number;
|
||||||
|
mediaType?: MediaType;
|
||||||
|
local?: string;
|
||||||
|
checksum?: string;
|
||||||
|
emit?: string;
|
||||||
|
map?: string;
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DenoInfoOptions {
|
||||||
|
importMap?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tempDir: null | string;
|
||||||
|
|
||||||
|
export async function info(
|
||||||
|
specifier: URL,
|
||||||
|
options: DenoInfoOptions,
|
||||||
|
): Promise<InfoOutput> {
|
||||||
|
const cmd = [
|
||||||
|
Deno.execPath(),
|
||||||
|
"info",
|
||||||
|
"--json",
|
||||||
|
];
|
||||||
|
if (options.importMap !== undefined) {
|
||||||
|
cmd.push("--import-map", options.importMap);
|
||||||
|
}
|
||||||
|
cmd.push(specifier.href);
|
||||||
|
|
||||||
|
if (!tempDir) {
|
||||||
|
tempDir = Deno.makeTempDirSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
let proc;
|
||||||
|
|
||||||
|
try {
|
||||||
|
proc = Deno.run({
|
||||||
|
cmd,
|
||||||
|
stdout: "piped",
|
||||||
|
cwd: tempDir,
|
||||||
|
});
|
||||||
|
const raw = await proc.output();
|
||||||
|
const status = await proc.status();
|
||||||
|
if (!status.success) {
|
||||||
|
throw new Error(`Failed to call 'deno info' on '${specifier.href}'`);
|
||||||
|
}
|
||||||
|
const txt = new TextDecoder().decode(raw);
|
||||||
|
return JSON.parse(txt);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
proc?.stdout.close();
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof Deno.errors.BadResource) {
|
||||||
|
// ignore the error
|
||||||
|
} else {
|
||||||
|
// deno-lint-ignore no-unsafe-finally
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
proc?.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
import { esbuild, fromFileUrl } from "../deps.ts";
|
||||||
|
import * as deno from "./deno.ts";
|
||||||
|
import { mediaTypeToLoader, transformRawIntoContent } from "./shared.ts";
|
||||||
|
|
||||||
|
export interface LoadOptions {
|
||||||
|
importMapURL?: URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function load(
|
||||||
|
infoCache: Map<string, deno.ModuleEntry>,
|
||||||
|
url: URL,
|
||||||
|
options: LoadOptions
|
||||||
|
): Promise<esbuild.OnLoadResult | null> {
|
||||||
|
switch (url.protocol) {
|
||||||
|
case "http:":
|
||||||
|
case "https:":
|
||||||
|
case "data:":
|
||||||
|
return await loadFromCLI(infoCache, url, options);
|
||||||
|
case "file:": {
|
||||||
|
const res = await loadFromCLI(infoCache, url, options);
|
||||||
|
res.watchFiles = [fromFileUrl(url.href)];
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadFromCLI(
|
||||||
|
infoCache: Map<string, deno.ModuleEntry>,
|
||||||
|
specifier: URL,
|
||||||
|
options: LoadOptions
|
||||||
|
): Promise<esbuild.OnLoadResult> {
|
||||||
|
const specifierRaw = specifier.href;
|
||||||
|
if (!infoCache.has(specifierRaw)) {
|
||||||
|
const { modules, redirects } = await deno.info(specifier, {
|
||||||
|
importMap: options.importMapURL?.href,
|
||||||
|
});
|
||||||
|
for (const module of modules) {
|
||||||
|
infoCache.set(module.specifier, module);
|
||||||
|
}
|
||||||
|
for (const [specifier, redirect] of Object.entries(redirects)) {
|
||||||
|
const redirected = infoCache.get(redirect);
|
||||||
|
if (!redirected) {
|
||||||
|
throw new TypeError("Unreachable.");
|
||||||
|
}
|
||||||
|
infoCache.set(specifier, redirected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const module = infoCache.get(specifierRaw);
|
||||||
|
if (!module) {
|
||||||
|
throw new TypeError("Unreachable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (module.error) throw new Error(module.error);
|
||||||
|
if (!module.local) throw new Error("Module not downloaded yet.");
|
||||||
|
const mediaType = module.mediaType ?? "Unknown";
|
||||||
|
|
||||||
|
const loader = mediaTypeToLoader(mediaType);
|
||||||
|
|
||||||
|
const raw = await Deno.readFile(module.local);
|
||||||
|
const contents = transformRawIntoContent(raw, mediaType);
|
||||||
|
|
||||||
|
return { contents, loader };
|
||||||
|
}
|
|
@ -0,0 +1,194 @@
|
||||||
|
import { esbuild, extname, fromFileUrl } from "../deps.ts";
|
||||||
|
import * as deno from "./deno.ts";
|
||||||
|
import { mediaTypeToLoader, transformRawIntoContent } from "./shared.ts";
|
||||||
|
|
||||||
|
export interface LoadOptions {
|
||||||
|
importMapURL?: URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function load(
|
||||||
|
url: URL,
|
||||||
|
_options: LoadOptions,
|
||||||
|
): Promise<esbuild.OnLoadResult | null> {
|
||||||
|
switch (url.protocol) {
|
||||||
|
case "http:":
|
||||||
|
case "https:":
|
||||||
|
case "data:":
|
||||||
|
return await loadWithFetch(url);
|
||||||
|
case "file:": {
|
||||||
|
const res = await loadWithReadFile(url);
|
||||||
|
res.watchFiles = [fromFileUrl(url.href)];
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadWithFetch(
|
||||||
|
specifier: URL,
|
||||||
|
): Promise<esbuild.OnLoadResult> {
|
||||||
|
const specifierRaw = specifier.href;
|
||||||
|
|
||||||
|
// TODO(lucacasonato): redirects!
|
||||||
|
const resp = await fetch(specifierRaw);
|
||||||
|
if (!resp.ok) {
|
||||||
|
throw new Error(
|
||||||
|
`Encountered status code ${resp.status} while fetching ${specifierRaw}.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentType = resp.headers.get("content-type");
|
||||||
|
const mediaType = mapContentType(
|
||||||
|
new URL(resp.url || specifierRaw),
|
||||||
|
contentType,
|
||||||
|
);
|
||||||
|
|
||||||
|
const loader = mediaTypeToLoader(mediaType);
|
||||||
|
|
||||||
|
const raw = new Uint8Array(await resp.arrayBuffer());
|
||||||
|
const contents = transformRawIntoContent(raw, mediaType);
|
||||||
|
|
||||||
|
return { contents, loader };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadWithReadFile(specifier: URL): Promise<esbuild.OnLoadResult> {
|
||||||
|
const path = fromFileUrl(specifier);
|
||||||
|
|
||||||
|
const mediaType = mapContentType(specifier, null);
|
||||||
|
const loader = mediaTypeToLoader(mediaType);
|
||||||
|
|
||||||
|
const raw = await Deno.readFile(path);
|
||||||
|
const contents = transformRawIntoContent(raw, mediaType);
|
||||||
|
|
||||||
|
return { contents, loader };
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapContentType(
|
||||||
|
specifier: URL,
|
||||||
|
contentType: string | null,
|
||||||
|
): deno.MediaType {
|
||||||
|
if (contentType !== null) {
|
||||||
|
const contentTypes = contentType.split(";");
|
||||||
|
const mediaType = contentTypes[0].toLowerCase();
|
||||||
|
switch (mediaType) {
|
||||||
|
case "application/typescript":
|
||||||
|
case "text/typescript":
|
||||||
|
case "video/vnd.dlna.mpeg-tts":
|
||||||
|
case "video/mp2t":
|
||||||
|
case "application/x-typescript":
|
||||||
|
return mapJsLikeExtension(specifier, "TypeScript");
|
||||||
|
case "application/javascript":
|
||||||
|
case "text/javascript":
|
||||||
|
case "application/ecmascript":
|
||||||
|
case "text/ecmascript":
|
||||||
|
case "application/x-javascript":
|
||||||
|
case "application/node":
|
||||||
|
return mapJsLikeExtension(specifier, "JavaScript");
|
||||||
|
case "text/jsx":
|
||||||
|
return "JSX";
|
||||||
|
case "text/tsx":
|
||||||
|
return "TSX";
|
||||||
|
case "application/json":
|
||||||
|
case "text/json":
|
||||||
|
return "Json";
|
||||||
|
case "application/wasm":
|
||||||
|
return "Wasm";
|
||||||
|
case "text/plain":
|
||||||
|
case "application/octet-stream":
|
||||||
|
return mediaTypeFromSpecifier(specifier);
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return mediaTypeFromSpecifier(specifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapJsLikeExtension(
|
||||||
|
specifier: URL,
|
||||||
|
defaultType: deno.MediaType,
|
||||||
|
): deno.MediaType {
|
||||||
|
const path = specifier.pathname;
|
||||||
|
switch (extname(path)) {
|
||||||
|
case ".jsx":
|
||||||
|
return "JSX";
|
||||||
|
case ".mjs":
|
||||||
|
return "Mjs";
|
||||||
|
case ".cjs":
|
||||||
|
return "Cjs";
|
||||||
|
case ".tsx":
|
||||||
|
return "TSX";
|
||||||
|
case ".ts":
|
||||||
|
if (path.endsWith(".d.ts")) {
|
||||||
|
return "Dts";
|
||||||
|
} else {
|
||||||
|
return defaultType;
|
||||||
|
}
|
||||||
|
case ".mts": {
|
||||||
|
if (path.endsWith(".d.mts")) {
|
||||||
|
return "Dmts";
|
||||||
|
} else {
|
||||||
|
return defaultType == "JavaScript" ? "Mjs" : "Mts";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ".cts": {
|
||||||
|
if (path.endsWith(".d.cts")) {
|
||||||
|
return "Dcts";
|
||||||
|
} else {
|
||||||
|
return defaultType == "JavaScript" ? "Cjs" : "Cts";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return defaultType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mediaTypeFromSpecifier(specifier: URL): deno.MediaType {
|
||||||
|
const path = specifier.pathname;
|
||||||
|
switch (extname(path)) {
|
||||||
|
case "":
|
||||||
|
if (path.endsWith("/.tsbuildinfo")) {
|
||||||
|
return "TsBuildInfo";
|
||||||
|
} else {
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
case ".ts":
|
||||||
|
if (path.endsWith(".d.ts")) {
|
||||||
|
return "Dts";
|
||||||
|
} else {
|
||||||
|
return "TypeScript";
|
||||||
|
}
|
||||||
|
case ".mts":
|
||||||
|
if (path.endsWith(".d.mts")) {
|
||||||
|
return "Dmts";
|
||||||
|
} else {
|
||||||
|
return "Mts";
|
||||||
|
}
|
||||||
|
case ".cts":
|
||||||
|
if (path.endsWith(".d.cts")) {
|
||||||
|
return "Dcts";
|
||||||
|
} else {
|
||||||
|
return "Cts";
|
||||||
|
}
|
||||||
|
case ".tsx":
|
||||||
|
return "TSX";
|
||||||
|
case ".js":
|
||||||
|
return "JavaScript";
|
||||||
|
case ".jsx":
|
||||||
|
return "JSX";
|
||||||
|
case ".mjs":
|
||||||
|
return "Mjs";
|
||||||
|
case ".cjs":
|
||||||
|
return "Cjs";
|
||||||
|
case ".json":
|
||||||
|
return "Json";
|
||||||
|
case ".wasm":
|
||||||
|
return "Wasm";
|
||||||
|
case ".tsbuildinfo":
|
||||||
|
return "TsBuildInfo";
|
||||||
|
case ".map":
|
||||||
|
return "SourceMap";
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { esbuild } from "../deps.ts";
|
||||||
|
import { MediaType } from "./deno.ts";
|
||||||
|
|
||||||
|
export function mediaTypeToLoader(mediaType: MediaType): esbuild.Loader {
|
||||||
|
switch (mediaType) {
|
||||||
|
case "JavaScript":
|
||||||
|
case "Mjs":
|
||||||
|
return "js";
|
||||||
|
case "JSX":
|
||||||
|
return "jsx";
|
||||||
|
case "TypeScript":
|
||||||
|
case "Mts":
|
||||||
|
return "ts";
|
||||||
|
case "TSX":
|
||||||
|
return "tsx";
|
||||||
|
case "Json":
|
||||||
|
return "js";
|
||||||
|
default:
|
||||||
|
throw new Error(`Unhandled media type ${mediaType}.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transformRawIntoContent(
|
||||||
|
raw: Uint8Array,
|
||||||
|
mediaType: MediaType
|
||||||
|
): string | Uint8Array {
|
||||||
|
switch (mediaType) {
|
||||||
|
case "Json":
|
||||||
|
return jsonToESM(raw);
|
||||||
|
default:
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function jsonToESM(source: Uint8Array): string {
|
||||||
|
const sourceString = new TextDecoder().decode(source);
|
||||||
|
let json = JSON.stringify(JSON.parse(sourceString), null, 2);
|
||||||
|
json = json.replaceAll(`"__proto__":`, `["__proto__"]:`);
|
||||||
|
return `export default ${json};`;
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
import * as esbuild from "https://deno.land/x/esbuild@v0.14.51/mod.js";
|
||||||
|
export { esbuild };
|
||||||
|
export {
|
||||||
|
assert,
|
||||||
|
assertEquals,
|
||||||
|
} from "https://deno.land/std@0.150.0/testing/asserts.ts";
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"hello": "world",
|
||||||
|
"__proto__": {
|
||||||
|
"sky": "universe"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "mod";
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"mod": "./mod.ts"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
const bool = "asd";
|
||||||
|
export { bool };
|
|
@ -0,0 +1,11 @@
|
||||||
|
function createElement(fn) {
|
||||||
|
return fn();
|
||||||
|
}
|
||||||
|
|
||||||
|
const React = { createElement };
|
||||||
|
|
||||||
|
function Asd() {
|
||||||
|
return "foo";
|
||||||
|
}
|
||||||
|
|
||||||
|
export default <Asd />;
|
|
@ -0,0 +1,2 @@
|
||||||
|
const bool = "asd";
|
||||||
|
export { bool };
|
|
@ -0,0 +1,4 @@
|
||||||
|
let bool: string;
|
||||||
|
bool = "asd";
|
||||||
|
bool = "asd2";
|
||||||
|
export { bool };
|
|
@ -0,0 +1,4 @@
|
||||||
|
let bool: string;
|
||||||
|
bool = "asd";
|
||||||
|
bool = "asd2";
|
||||||
|
export { bool };
|
|
@ -0,0 +1,11 @@
|
||||||
|
function createElement(fn: () => string) {
|
||||||
|
return fn();
|
||||||
|
}
|
||||||
|
|
||||||
|
const React = { createElement };
|
||||||
|
|
||||||
|
function Asd() {
|
||||||
|
return "foo";
|
||||||
|
}
|
||||||
|
|
||||||
|
export default <Asd />;
|
Loading…
Reference in New Issue