summaryrefslogtreecommitdiff
path: root/std/bundle/utils.ts
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2019-10-09 17:18:08 -0400
committerRyan Dahl <ry@tinyclouds.org>2019-10-09 17:18:08 -0400
commit28293acd9c12a94f5d769706291032e844c7b92b (patch)
tree1fec6a3cd8d7c9e8bc9b1486f5c8438eb906a595 /std/bundle/utils.ts
parent5c6835efd82c298df99ce71c4a36ca23515333a3 (diff)
parent151ce0266eb4de2c8fc600c81c192a5f791b6169 (diff)
Merge branch 'std_modified' into merge_std3
Diffstat (limited to 'std/bundle/utils.ts')
-rw-r--r--std/bundle/utils.ts107
1 files changed, 107 insertions, 0 deletions
diff --git a/std/bundle/utils.ts b/std/bundle/utils.ts
new file mode 100644
index 000000000..91c0820bf
--- /dev/null
+++ b/std/bundle/utils.ts
@@ -0,0 +1,107 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+
+import { 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 {
+ // eslint-disable-next-line no-var
+ 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.
+ assert(args.length >= 2, "Expected at least two arguments.");
+ const [, bundleFileName] = args;
+ assert(
+ await exists(bundleFileName),
+ `Expected "${bundleFileName}" to exist.`
+ );
+ return new TextDecoder().decode(await Deno.readFile(bundleFileName));
+}