summaryrefslogtreecommitdiff
path: root/std/node
diff options
context:
space:
mode:
Diffstat (limited to 'std/node')
-rw-r--r--std/node/README.md17
-rw-r--r--std/node/global.ts1
-rw-r--r--std/node/module.ts (renamed from std/node/require.ts)78
-rw-r--r--std/node/module_test.ts44
-rw-r--r--std/node/path.ts1
-rw-r--r--std/node/require_test.ts27
-rw-r--r--std/node/tests/cjs/cjs_builtin.js10
-rw-r--r--std/node/tests/cjs/index.js1
8 files changed, 132 insertions, 47 deletions
diff --git a/std/node/README.md b/std/node/README.md
index 6d363a11d..14c245809 100644
--- a/std/node/README.md
+++ b/std/node/README.md
@@ -5,3 +5,20 @@ This module is meant to have a compatibility layer for the
**Warning** : Any function of this module should not be referred anywhere in the
deno standard library as it's a compatiblity module.
+
+## CommonJS Module Loading
+
+`createRequire(...)` is provided to create a `require` function for loading CJS
+modules.
+
+```ts
+import { createRequire } from "https://deno.land/std/node/module.ts";
+
+const require_ = createRequire(import.meta.url);
+// Loads native module polyfill.
+const path = require_("path");
+// Loads extensionless module.
+const cjsModule = require_("./my_mod");
+// Visits node_modules.
+const leftPad = require_("left-pad");
+```
diff --git a/std/node/global.ts b/std/node/global.ts
new file mode 100644
index 000000000..c21b0b659
--- /dev/null
+++ b/std/node/global.ts
@@ -0,0 +1 @@
+window["global"] = window;
diff --git a/std/node/require.ts b/std/node/module.ts
index 22393a418..3d51bf641 100644
--- a/std/node/require.ts
+++ b/std/node/module.ts
@@ -19,6 +19,12 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
+import "./global.ts";
+
+import * as nodeFS from "./fs.ts";
+import * as nodeUtil from "./util.ts";
+import * as nodePath from "./path.ts";
+
import * as path from "../path/mod.ts";
import { assert } from "../testing/asserts.ts";
@@ -80,8 +86,7 @@ class Module {
this.paths = [];
this.path = path.dirname(id);
}
- // TODO: populate this with polyfills!
- static builtinModules: Module[] = [];
+ static builtinModules: string[] = [];
static _extensions: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: (module: Module, filename: string) => any;
@@ -191,7 +196,11 @@ class Module {
isMain: boolean,
options?: { paths: string[] }
): string {
- // Native module code removed
+ // Polyfills.
+ if (nativeModuleCanBeRequiredByUsers(request)) {
+ return request;
+ }
+
let paths: string[];
if (typeof options === "object" && options !== null) {
@@ -355,7 +364,9 @@ class Module {
return cachedModule.exports;
}
- // Native module NOT supported.
+ // Native module polyfills
+ const mod = loadNativeModule(filename, request);
+ if (mod) return mod.exports;
// Don't call updateChildren(), Module constructor already does.
const module = new Module(filename, parent);
@@ -475,6 +486,20 @@ class Module {
}
}
+ /**
+ * Create a `require` function that can be used to import CJS modules.
+ * Follows CommonJS resolution similar to that of Node.js,
+ * with `node_modules` lookup and `index.js` lookup support.
+ * Also injects available Node.js builtin module polyfills.
+ *
+ * const require_ = createRequire(import.meta.url);
+ * const fs = require_("fs");
+ * const leftPad = require_("left-pad");
+ * const cjsModule = require_("./cjs_mod");
+ *
+ * @param filename path or URL to current module
+ * @return Require function to import CJS modules
+ */
static createRequire(filename: string | URL): RequireFunction {
let filepath: string;
if (
@@ -540,6 +565,32 @@ class Module {
}
}
+// Polyfills.
+const nativeModulePolyfill = new Map<string, Module>();
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+function createNativeModule(id: string, exports: any): Module {
+ const mod = new Module(id);
+ mod.exports = exports;
+ mod.loaded = true;
+ return mod;
+}
+nativeModulePolyfill.set("fs", createNativeModule("fs", nodeFS));
+nativeModulePolyfill.set("util", createNativeModule("util", nodeUtil));
+nativeModulePolyfill.set("path", createNativeModule("path", nodePath));
+function loadNativeModule(
+ _filename: string,
+ request: string
+): Module | undefined {
+ return nativeModulePolyfill.get(request);
+}
+function nativeModuleCanBeRequiredByUsers(request: string): boolean {
+ return nativeModulePolyfill.has(request);
+}
+// Populate with polyfill names
+for (const id of nativeModulePolyfill.keys()) {
+ Module.builtinModules.push(id);
+}
+
let modulePaths = [];
// Given a module name, and a list of paths to test, returns the first
@@ -1171,19 +1222,6 @@ function pathToFileURL(filepath: string): URL {
return outURL;
}
-/**
- * Create a `require` function that can be used to import CJS modules
- * @param path path of this module
- */
-function makeRequire(filePath: string): RequireFunction {
- let mod: Module;
- const fullPath = path.resolve(filePath);
- if (fullPath in Module._cache) {
- mod = Module._cache[fullPath];
- } else {
- mod = new Module(fullPath);
- }
- return makeRequireFunction(mod);
-}
-
-export { makeRequire };
+export const builtinModules = Module.builtinModules;
+export const createRequire = Module.createRequire;
+export default Module;
diff --git a/std/node/module_test.ts b/std/node/module_test.ts
new file mode 100644
index 000000000..91744d94d
--- /dev/null
+++ b/std/node/module_test.ts
@@ -0,0 +1,44 @@
+import { test } from "../testing/mod.ts";
+import { assertEquals, assert } from "../testing/asserts.ts";
+import { createRequire } from "./module.ts";
+
+// TS compiler would try to resolve if function named "require"
+// Thus suffixing it with require_ to fix this...
+const require_ = createRequire(import.meta.url);
+
+test(function requireSuccess() {
+ // Relative to import.meta.url
+ const result = require_("./tests/cjs/cjs_a.js");
+ assert("helloA" in result);
+ assert("helloB" in result);
+ assert("C" in result);
+ assert("leftPad" in result);
+ assertEquals(result.helloA(), "A");
+ assertEquals(result.helloB(), "B");
+ assertEquals(result.C, "C");
+ assertEquals(result.leftPad("pad", 4), " pad");
+});
+
+test(function requireCycle() {
+ const resultA = require_("./tests/cjs/cjs_cycle_a");
+ const resultB = require_("./tests/cjs/cjs_cycle_b");
+ assert(resultA);
+ assert(resultB);
+});
+
+test(function requireBuiltin() {
+ const fs = require_("fs");
+ assert("readFileSync" in fs);
+ const { readFileSync, isNull, extname } = require_("./tests/cjs/cjs_builtin");
+ assertEquals(
+ readFileSync("./node/testdata/hello.txt", { encoding: "utf8" }),
+ "hello world"
+ );
+ assert(isNull(null));
+ assertEquals(extname("index.html"), ".html");
+});
+
+test(function requireIndexJS() {
+ const { isIndex } = require_("./tests/cjs");
+ assert(isIndex);
+});
diff --git a/std/node/path.ts b/std/node/path.ts
new file mode 100644
index 000000000..e8295281a
--- /dev/null
+++ b/std/node/path.ts
@@ -0,0 +1 @@
+export * from "../path/mod.ts";
diff --git a/std/node/require_test.ts b/std/node/require_test.ts
deleted file mode 100644
index 7cac6d6b2..000000000
--- a/std/node/require_test.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { test } from "../testing/mod.ts";
-import { assertEquals, assert } from "../testing/asserts.ts";
-import { makeRequire } from "./require.ts";
-
-const selfPath = window.unescape(import.meta.url.substring(7));
-// TS compiler would try to resolve if function named "require"
-// Thus suffixing it with require_ to fix this...
-const require_ = makeRequire(selfPath);
-
-test(function requireSuccess() {
- const result = require_("./node/tests/cjs/cjs_a.js");
- assert("helloA" in result);
- assert("helloB" in result);
- assert("C" in result);
- assert("leftPad" in result);
- assertEquals(result.helloA(), "A");
- assertEquals(result.helloB(), "B");
- assertEquals(result.C, "C");
- assertEquals(result.leftPad("pad", 4), " pad");
-});
-
-test(function requireCycle() {
- const resultA = require_("./node/tests/cjs/cjs_cycle_a");
- const resultB = require_("./node/tests/cjs/cjs_cycle_b");
- assert(resultA);
- assert(resultB);
-});
diff --git a/std/node/tests/cjs/cjs_builtin.js b/std/node/tests/cjs/cjs_builtin.js
new file mode 100644
index 000000000..3d182981a
--- /dev/null
+++ b/std/node/tests/cjs/cjs_builtin.js
@@ -0,0 +1,10 @@
+/* eslint-disable */
+const fs = require("fs");
+const util = require("util");
+const path = require("path");
+
+module.exports = {
+ readFileSync: fs.readFileSync,
+ isNull: util.isNull,
+ extname: path.extname
+};
diff --git a/std/node/tests/cjs/index.js b/std/node/tests/cjs/index.js
new file mode 100644
index 000000000..5dea52db2
--- /dev/null
+++ b/std/node/tests/cjs/index.js
@@ -0,0 +1 @@
+module.exports = { isIndex: true };