mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
194 lines
7.6 KiB
TypeScript
194 lines
7.6 KiB
TypeScript
import assert from "assert";
|
|
import { expect, mock, test } from "bun:test";
|
|
import { tempDirWithFiles } from "harness";
|
|
import path from "path";
|
|
|
|
test("require.extensions shape makes sense", () => {
|
|
const extensions = require.extensions;
|
|
expect(extensions).toBeDefined();
|
|
expect(typeof extensions).toBe("object");
|
|
expect(extensions[".js"]).toBeFunction();
|
|
expect(extensions[".json"]).toBeFunction();
|
|
expect(extensions[".node"]).toBeFunction();
|
|
// When --experimental-strip-types is passed, TypeScript files can be loaded.
|
|
expect(extensions[".cts"]).toBeFunction();
|
|
expect(extensions[".ts"]).toBeFunction();
|
|
expect(extensions[".mjs"]).toBeFunction();
|
|
expect(extensions[".mts"]).toBeFunction();
|
|
expect(require("module")._extensions === require.extensions).toBe(true);
|
|
});
|
|
test("custom require extension 1", () => {
|
|
const custom = (require.extensions[".custom"] = mock(function (module, filename) {
|
|
expect(filename).toBe(path.join(import.meta.dir, "extensions-fixture", "c.custom"));
|
|
(module as any)._compile(`module.exports = 'custom';`, filename);
|
|
}));
|
|
const mod = require("./extensions-fixture/c");
|
|
expect(mod).toBe("custom");
|
|
expect(custom.mock.calls.length).toBe(1);
|
|
delete require.extensions[".custom"];
|
|
expect(() => require("./extensions-fixture/c")).toThrow(/Cannot find module/);
|
|
expect(require("./extensions-fixture/c.custom")).toBe("custom"); // already loaded
|
|
delete require.cache[require.resolve("./extensions-fixture/c.custom")];
|
|
expect(custom.mock.calls.length).toBe(1);
|
|
expect(require("./extensions-fixture/c.custom")).toBe("c dot custom"); // use js loader
|
|
});
|
|
test("custom require extension overwrite default loader", () => {
|
|
const original = require.extensions[".js"];
|
|
try {
|
|
const custom = (require.extensions[".js"] = mock(function (module, filename) {
|
|
expect(filename).toBe(path.join(import.meta.dir, "extensions-fixture", "d.js"));
|
|
(module as any)._compile(`module.exports = 'custom';`, filename);
|
|
}));
|
|
const mod = require("./extensions-fixture/d");
|
|
expect(mod).toBe("custom");
|
|
expect(custom.mock.calls.length).toBe(1);
|
|
require.extensions[".js"] = original;
|
|
expect(require("./extensions-fixture/d")).toBe("custom"); // already loaded
|
|
delete require.cache[require.resolve("./extensions-fixture/d")];
|
|
expect(custom.mock.calls.length).toBe(1);
|
|
expect(require("./extensions-fixture/d")).toBe("d.js"); // use js loader
|
|
} finally {
|
|
require.extensions[".js"] = original;
|
|
}
|
|
});
|
|
test("custom require extension overwrite default loader with other default loader", () => {
|
|
const original = require.extensions[".js"];
|
|
try {
|
|
require.extensions[".js"] = require.extensions[".ts"]!;
|
|
const mod = require("./extensions-fixture/e.js"); // should not enter JS
|
|
expect(mod).toBe("hello world");
|
|
} finally {
|
|
require.extensions[".js"] = original;
|
|
}
|
|
});
|
|
test("test that assigning properties weirdly wont do anything bad", () => {
|
|
const original = require.extensions[".js"];
|
|
try {
|
|
function f1() {}
|
|
function f2() {}
|
|
require.extensions[".js"] = f1;
|
|
require.extensions[".abc"] = f2;
|
|
require.extensions[".js"] = f2;
|
|
require.extensions[".js"] = undefined!;
|
|
require.extensions[".abc"] = undefined!;
|
|
require.extensions[".abc"] = f1;
|
|
require.extensions[".js"] = f2;
|
|
} finally {
|
|
require.extensions[".js"] = original;
|
|
}
|
|
});
|
|
test("wrapping an existing extension with no logic", () => {
|
|
const original = require.extensions[".js"];
|
|
try {
|
|
delete require.cache[require.resolve("./extensions-fixture/d")];
|
|
const mocked = (require.extensions[".js"] = mock(function (module, filename) {
|
|
expect(module).toBeDefined();
|
|
expect(filename).toBe(path.join(import.meta.dir, "extensions-fixture", "d.js"));
|
|
original(module, filename);
|
|
}));
|
|
const mod = require("./extensions-fixture/d");
|
|
expect(mod).toBe("d.js");
|
|
expect(mocked).toBeCalled();
|
|
} finally {
|
|
require.extensions[".js"] = original;
|
|
}
|
|
});
|
|
test("wrapping an existing extension with mutated compile function", () => {
|
|
const original = require.extensions[".js"];
|
|
try {
|
|
delete require.cache[require.resolve("./extensions-fixture/d")];
|
|
const mocked = (require.extensions[".js"] = mock(function (module, filename) {
|
|
expect(module).toBeDefined();
|
|
expect(filename).toBe(path.join(import.meta.dir, "extensions-fixture", "d.js"));
|
|
const originalCompile = module._compile;
|
|
module._compile = function (code, filename) {
|
|
expect(code).toBe('\n module.exports = \"d.js\";\n');
|
|
expect(filename).toBe(path.join(import.meta.dir, "extensions-fixture", "d.js"));
|
|
originalCompile.call(module, 'module.exports = "new";', filename);
|
|
};
|
|
original(module, filename);
|
|
}));
|
|
const mod = require("./extensions-fixture/d");
|
|
expect(mod).toBe("new");
|
|
expect(mocked).toBeCalled();
|
|
} finally {
|
|
require.extensions[".js"] = original;
|
|
}
|
|
});
|
|
test("wrapping an existing extension with mutated compile function ts", () => {
|
|
const original = require.extensions[".ts"];
|
|
assert(original);
|
|
try {
|
|
delete require.cache[require.resolve("./extensions-fixture/e.js")];
|
|
const mocked = (require.extensions[".js"] = mock(function (module, filename) {
|
|
expect(module).toBeDefined();
|
|
expect(filename).toBe(path.join(import.meta.dir, "extensions-fixture", "e.js"));
|
|
const originalCompile = module._compile;
|
|
module._compile = function (code, filename) {
|
|
expect(code).toBe(
|
|
'\n var J;\n ((J) => J.x = \"hello\")(J ||= {});\n const hello = \" world\";\n module.exports = \"hello world\";\n',
|
|
);
|
|
expect(filename).toBe(path.join(import.meta.dir, "extensions-fixture", "e.js"));
|
|
originalCompile.call(module, 'module.exports = "new";', filename);
|
|
};
|
|
original(module, filename);
|
|
}));
|
|
const mod = require("./extensions-fixture/e");
|
|
expect(mod).toBe("new");
|
|
expect(mocked).toBeCalled();
|
|
} finally {
|
|
require.extensions[".js"] = original;
|
|
}
|
|
});
|
|
test("wrapping an existing extension but it's secretly sync esm", () => {
|
|
const original = require.extensions[".ts"];
|
|
assert(original);
|
|
try {
|
|
delete require.cache[require.resolve("./extensions-fixture/secretly_esm.cjs")];
|
|
let called = false;
|
|
const mocked = (require.extensions[".cjs"] = mock(function (module, filename) {
|
|
expect(module).toBeDefined();
|
|
expect(filename).toBe(path.join(import.meta.dir, "extensions-fixture", "secretly_esm.cjs"));
|
|
module._compile = function (code, filename) {
|
|
called = true;
|
|
throw new Error("should not be called");
|
|
};
|
|
original(module, filename);
|
|
}));
|
|
const mod = require("./extensions-fixture/secretly_esm");
|
|
expect(mod).toEqual({ default: 1 });
|
|
expect(mocked).toBeCalled();
|
|
} finally {
|
|
require.extensions[".cjs"] = original;
|
|
}
|
|
});
|
|
test("mutating extensions is banned by some files", () => {
|
|
// vercel is not allowed to mutate require.extensions
|
|
const files = ["node_modules/next/dist/build/next-config-ts/index.js", "node_modules/@meteorjs/babel/index.js"];
|
|
const fixture = tempDirWithFiles(
|
|
"extensions-fixture",
|
|
Object.fromEntries(
|
|
files.map(file => [
|
|
file,
|
|
`
|
|
const assert = require('assert');
|
|
const mock = function (module, filename) {
|
|
throw new Error('should not be called');
|
|
};
|
|
require.extensions['.js'] = mock;
|
|
assert(require.extensions['.js'] !== mock);
|
|
globalThis.pass += 1;
|
|
`,
|
|
]),
|
|
),
|
|
);
|
|
globalThis.pass = 0;
|
|
|
|
let n = 0;
|
|
for (const file of files) {
|
|
require(path.join(fixture, file));
|
|
n++;
|
|
expect(globalThis.pass).toBe(n);
|
|
}
|
|
});
|