mirror of
https://github.com/denoland/deno.git
synced 2024-11-01 09:24:20 -04:00
109 lines
3 KiB
TypeScript
109 lines
3 KiB
TypeScript
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||
|
|
||
|
import { assertStrictEq, assert } from "../testing/asserts.ts";
|
||
|
import { exists } from "../fs/exists.ts";
|
||
|
|
||
|
export interface DefineFactory {
|
||
|
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||
|
(...args: any): object | void;
|
||
|
}
|
||
|
|
||
|
export interface ModuleMetaData {
|
||
|
dependencies: string[];
|
||
|
factory?: DefineFactory | object;
|
||
|
exports: object;
|
||
|
}
|
||
|
|
||
|
type Define = (
|
||
|
id: string,
|
||
|
dependencies: string[],
|
||
|
factory: DefineFactory
|
||
|
) => void;
|
||
|
|
||
|
/* eslint-disable @typescript-eslint/no-namespace */
|
||
|
declare global {
|
||
|
namespace globalThis {
|
||
|
var define: Define | undefined;
|
||
|
}
|
||
|
}
|
||
|
/* eslint-enable @typescript-eslint/no-namespace */
|
||
|
|
||
|
/** Evaluate the bundle, returning a queue of module IDs and their data to
|
||
|
* instantiate.
|
||
|
*/
|
||
|
export function evaluate(
|
||
|
text: string
|
||
|
): [string[], Map<string, ModuleMetaData>] {
|
||
|
const queue: string[] = [];
|
||
|
const modules = new Map<string, ModuleMetaData>();
|
||
|
|
||
|
globalThis.define = function define(
|
||
|
id: string,
|
||
|
dependencies: string[],
|
||
|
factory: DefineFactory
|
||
|
): void {
|
||
|
modules.set(id, {
|
||
|
dependencies,
|
||
|
factory,
|
||
|
exports: {}
|
||
|
});
|
||
|
queue.push(id);
|
||
|
};
|
||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||
|
(Deno as any).core.evalContext(text);
|
||
|
// Deleting `define()` so it isn't accidentally there when the modules
|
||
|
// instantiate.
|
||
|
delete globalThis.define;
|
||
|
|
||
|
return [queue, modules];
|
||
|
}
|
||
|
|
||
|
/** Drain the queue of module IDs while instantiating the modules. */
|
||
|
export function instantiate(
|
||
|
queue: string[],
|
||
|
modules: Map<string, ModuleMetaData>
|
||
|
): void {
|
||
|
let id: string | undefined;
|
||
|
while ((id = queue.shift())) {
|
||
|
const module = modules.get(id)!;
|
||
|
assert(module != null);
|
||
|
assert(module.factory != null);
|
||
|
|
||
|
const dependencies = module.dependencies.map(
|
||
|
(id): object => {
|
||
|
if (id === "require") {
|
||
|
// TODO(kitsonk) support dynamic import by passing a `require()` that
|
||
|
// can return a local module or dynamically import one.
|
||
|
return (): void => {};
|
||
|
} else if (id === "exports") {
|
||
|
return module.exports;
|
||
|
}
|
||
|
const dep = modules.get(id)!;
|
||
|
assert(dep != null);
|
||
|
return dep.exports;
|
||
|
}
|
||
|
);
|
||
|
|
||
|
if (typeof module.factory === "function") {
|
||
|
module.factory!(...dependencies);
|
||
|
} else if (module.factory) {
|
||
|
// when bundling JSON, TypeScript just emits it as an object/array as the
|
||
|
// third argument of the `define()`.
|
||
|
module.exports = module.factory;
|
||
|
}
|
||
|
delete module.factory;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Load the bundle and return the contents asynchronously. */
|
||
|
export async function load(args: string[]): Promise<string> {
|
||
|
// TODO(kitsonk) allow loading of remote bundles via fetch.
|
||
|
assertStrictEq(args.length, 2, "Expected exactly two arguments.");
|
||
|
const [, bundleFileName] = args;
|
||
|
assert(
|
||
|
await exists(bundleFileName),
|
||
|
`Expected "${bundleFileName}" to exist.`
|
||
|
);
|
||
|
return new TextDecoder().decode(await Deno.readFile(bundleFileName));
|
||
|
}
|