summaryrefslogtreecommitdiff
path: root/std/bundle
diff options
context:
space:
mode:
Diffstat (limited to 'std/bundle')
m---------std0
-rw-r--r--std/bundle/README.md16
-rw-r--r--std/bundle/run.ts11
-rw-r--r--std/bundle/test.ts116
-rw-r--r--std/bundle/testdata/bundle.js67
-rw-r--r--std/bundle/utils.ts109
6 files changed, 319 insertions, 0 deletions
diff --git a/std b/std
deleted file mode 160000
-Subproject 43aafbf33285753e7b42230f0eb7969b300f71c
diff --git a/std/bundle/README.md b/std/bundle/README.md
new file mode 100644
index 000000000..ecf105d15
--- /dev/null
+++ b/std/bundle/README.md
@@ -0,0 +1,16 @@
+# bundle
+
+These are modules that help support bundling with Deno.
+
+## Usage
+
+The main usage is to load and run bundles. For example, to run a bundle named
+`bundle.js` in your current working directory:
+
+```sh
+deno run https://deno.land/std/bundle/run.ts bundle.js
+```
+
+---
+
+Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
diff --git a/std/bundle/run.ts b/std/bundle/run.ts
new file mode 100644
index 000000000..fb848a671
--- /dev/null
+++ b/std/bundle/run.ts
@@ -0,0 +1,11 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+
+import { evaluate, instantiate, load } from "./utils.ts";
+
+async function main(args: string[]): Promise<void> {
+ const text = await load(args);
+ const result = evaluate(text);
+ instantiate(...result);
+}
+
+main(Deno.args);
diff --git a/std/bundle/test.ts b/std/bundle/test.ts
new file mode 100644
index 000000000..504e449a6
--- /dev/null
+++ b/std/bundle/test.ts
@@ -0,0 +1,116 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+
+import { test } from "../testing/mod.ts";
+import {
+ assert,
+ AssertionError,
+ assertEquals,
+ assertThrowsAsync
+} from "../testing/asserts.ts";
+import { instantiate, load, ModuleMetaData } from "./utils.ts";
+
+/* eslint-disable @typescript-eslint/no-namespace */
+declare global {
+ namespace globalThis {
+ // eslint-disable-next-line no-var
+ var __results: [string, string] | undefined;
+ }
+}
+/* eslint-disable max-len */
+/* eslint-enable @typescript-eslint/no-namespace */
+/*
+const fixture = `
+define("data", [], { "baz": "qat" });
+define("modB", ["require", "exports", "data"], function(require, exports, data) {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ exports.foo = "bar";
+ exports.baz = data.baz;
+});
+define("modA", ["require", "exports", "modB"], function(require, exports, modB) {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ globalThis.__results = [modB.foo, modB.baz];
+});
+`;
+*/
+/* eslint-enable max-len */
+
+const fixtureQueue = ["data", "modB", "modA"];
+const fixtureModules = new Map<string, ModuleMetaData>();
+fixtureModules.set("data", {
+ dependencies: [],
+ factory: {
+ baz: "qat"
+ },
+ exports: {}
+});
+fixtureModules.set("modB", {
+ dependencies: ["require", "exports", "data"],
+ factory(_require, exports, data): void {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ exports.foo = "bar";
+ exports.baz = data.baz;
+ },
+ exports: {}
+});
+fixtureModules.set("modA", {
+ dependencies: ["require", "exports", "modB"],
+ factory(_require, exports, modB): void {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ globalThis.__results = [modB.foo, modB.baz];
+ },
+ exports: {}
+});
+
+test(async function loadBundle(): Promise<void> {
+ const result = await load(["", "./bundle/testdata/bundle.js", "--foo"]);
+ assert(result != null);
+ assert(
+ result.includes(
+ `define("subdir/print_hello", ["require", "exports"], function(`
+ )
+ );
+});
+
+test(async function loadBadArgs(): Promise<void> {
+ await assertThrowsAsync(
+ async (): Promise<void> => {
+ await load(["bundle/test.ts"]);
+ },
+ AssertionError,
+ "Expected at least two arguments."
+ );
+});
+
+test(async function loadMissingBundle(): Promise<void> {
+ await assertThrowsAsync(
+ async (): Promise<void> => {
+ await load([".", "bad_bundle.js"]);
+ },
+ AssertionError,
+ `Expected "bad_bundle.js" to exist.`
+ );
+});
+
+/* TODO re-enable test
+test(async function evaluateBundle(): Promise<void> {
+ assert(globalThis.define == null, "Expected 'define' to be undefined");
+ const [queue, modules] = evaluate(fixture);
+ assert(globalThis.define == null, "Expected 'define' to be undefined");
+ assertEquals(queue, ["data", "modB", "modA"]);
+ assert(modules.has("modA"));
+ assert(modules.has("modB"));
+ assert(modules.has("data"));
+ assertStrictEq(modules.size, 3);
+});
+*/
+
+test(async function instantiateBundle(): Promise<void> {
+ assert(globalThis.__results == null);
+ instantiate(fixtureQueue, fixtureModules);
+ assertEquals(globalThis.__results, ["bar", "qat"]);
+ delete globalThis.__results;
+});
diff --git a/std/bundle/testdata/bundle.js b/std/bundle/testdata/bundle.js
new file mode 100644
index 000000000..6758fd278
--- /dev/null
+++ b/std/bundle/testdata/bundle.js
@@ -0,0 +1,67 @@
+define("subdir/print_hello", ["require", "exports"], function(
+ require,
+ exports
+) {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ function printHello() {
+ console.log("Hello");
+ }
+ exports.printHello = printHello;
+});
+define("subdir/subdir2/mod2", [
+ "require",
+ "exports",
+ "subdir/print_hello"
+], function(require, exports, print_hello_ts_1) {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ function returnsFoo() {
+ return "Foo";
+ }
+ exports.returnsFoo = returnsFoo;
+ function printHello2() {
+ print_hello_ts_1.printHello();
+ }
+ exports.printHello2 = printHello2;
+});
+define("subdir/mod1", ["require", "exports", "subdir/subdir2/mod2"], function(
+ require,
+ exports,
+ mod2_ts_1
+) {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ function returnsHi() {
+ return "Hi";
+ }
+ exports.returnsHi = returnsHi;
+ function returnsFoo2() {
+ return mod2_ts_1.returnsFoo();
+ }
+ exports.returnsFoo2 = returnsFoo2;
+ function printHello3() {
+ mod2_ts_1.printHello2();
+ }
+ exports.printHello3 = printHello3;
+ function throwsError() {
+ throw Error("exception from mod1");
+ }
+ exports.throwsError = throwsError;
+});
+define("005_more_imports", ["require", "exports", "subdir/mod1"], function(
+ require,
+ exports,
+ mod1_ts_1
+) {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ mod1_ts_1.printHello3();
+ if (mod1_ts_1.returnsHi() !== "Hi") {
+ throw Error("Unexpected");
+ }
+ if (mod1_ts_1.returnsFoo2() !== "Foo") {
+ throw Error("Unexpected");
+ }
+});
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVuZGxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZmlsZTovLy9Vc2Vycy9ra2VsbHkvZ2l0aHViL2Rlbm8vdGVzdHMvc3ViZGlyL3ByaW50X2hlbGxvLnRzIiwiZmlsZTovLy9Vc2Vycy9ra2VsbHkvZ2l0aHViL2Rlbm8vdGVzdHMvc3ViZGlyL3N1YmRpcjIvbW9kMi50cyIsImZpbGU6Ly8vVXNlcnMva2tlbGx5L2dpdGh1Yi9kZW5vL3Rlc3RzL3N1YmRpci9tb2QxLnRzIiwiZmlsZTovLy9Vc2Vycy9ra2VsbHkvZ2l0aHViL2Rlbm8vdGVzdHMvMDA1X21vcmVfaW1wb3J0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7SUFBQSxTQUFnQixVQUFVO1FBQ3hCLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDdkIsQ0FBQztJQUZELGdDQUVDOzs7OztJQ0FELFNBQWdCLFVBQVU7UUFDeEIsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRkQsZ0NBRUM7SUFFRCxTQUFnQixXQUFXO1FBQ3pCLDJCQUFVLEVBQUUsQ0FBQztJQUNmLENBQUM7SUFGRCxrQ0FFQzs7Ozs7SUNORCxTQUFnQixTQUFTO1FBQ3ZCLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUZELDhCQUVDO0lBRUQsU0FBZ0IsV0FBVztRQUN6QixPQUFPLG9CQUFVLEVBQUUsQ0FBQztJQUN0QixDQUFDO0lBRkQsa0NBRUM7SUFFRCxTQUFnQixXQUFXO1FBQ3pCLHFCQUFXLEVBQUUsQ0FBQztJQUNoQixDQUFDO0lBRkQsa0NBRUM7SUFFRCxTQUFnQixXQUFXO1FBQ3pCLE1BQU0sS0FBSyxDQUFDLHFCQUFxQixDQUFDLENBQUM7SUFDckMsQ0FBQztJQUZELGtDQUVDOzs7OztJQ2RELHFCQUFXLEVBQUUsQ0FBQztJQUVkLElBQUksbUJBQVMsRUFBRSxLQUFLLElBQUksRUFBRTtRQUN4QixNQUFNLEtBQUssQ0FBQyxZQUFZLENBQUMsQ0FBQztLQUMzQjtJQUVELElBQUkscUJBQVcsRUFBRSxLQUFLLEtBQUssRUFBRTtRQUMzQixNQUFNLEtBQUssQ0FBQyxZQUFZLENBQUMsQ0FBQztLQUMzQiIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBmdW5jdGlvbiBwcmludEhlbGxvKCk6IHZvaWQge1xuICBjb25zb2xlLmxvZyhcIkhlbGxvXCIpO1xufVxuIiwiaW1wb3J0IHsgcHJpbnRIZWxsbyB9IGZyb20gXCIuLi9wcmludF9oZWxsby50c1wiO1xuXG5leHBvcnQgZnVuY3Rpb24gcmV0dXJuc0ZvbygpOiBzdHJpbmcge1xuICByZXR1cm4gXCJGb29cIjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHByaW50SGVsbG8yKCk6IHZvaWQge1xuICBwcmludEhlbGxvKCk7XG59XG4iLCJpbXBvcnQgeyByZXR1cm5zRm9vLCBwcmludEhlbGxvMiB9IGZyb20gXCIuL3N1YmRpcjIvbW9kMi50c1wiO1xuXG5leHBvcnQgZnVuY3Rpb24gcmV0dXJuc0hpKCk6IHN0cmluZyB7XG4gIHJldHVybiBcIkhpXCI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZXR1cm5zRm9vMigpOiBzdHJpbmcge1xuICByZXR1cm4gcmV0dXJuc0ZvbygpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRIZWxsbzMoKTogdm9pZCB7XG4gIHByaW50SGVsbG8yKCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB0aHJvd3NFcnJvcigpOiB2b2lkIHtcbiAgdGhyb3cgRXJyb3IoXCJleGNlcHRpb24gZnJvbSBtb2QxXCIpO1xufVxuIiwiaW1wb3J0IHsgcmV0dXJuc0hpLCByZXR1cm5zRm9vMiwgcHJpbnRIZWxsbzMgfSBmcm9tIFwiLi9zdWJkaXIvbW9kMS50c1wiO1xuXG5wcmludEhlbGxvMygpO1xuXG5pZiAocmV0dXJuc0hpKCkgIT09IFwiSGlcIikge1xuICB0aHJvdyBFcnJvcihcIlVuZXhwZWN0ZWRcIik7XG59XG5cbmlmIChyZXR1cm5zRm9vMigpICE9PSBcIkZvb1wiKSB7XG4gIHRocm93IEVycm9yKFwiVW5leHBlY3RlZFwiKTtcbn1cbiJdfQ==
diff --git a/std/bundle/utils.ts b/std/bundle/utils.ts
new file mode 100644
index 000000000..062c62231
--- /dev/null
+++ b/std/bundle/utils.ts
@@ -0,0 +1,109 @@
+// 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));
+}