diff options
author | 2023-09-20 21:31:57 -0400 | |
---|---|---|
committer | 2023-09-20 18:31:57 -0700 | |
commit | 365fc0d39ddfaed8683eb6ee75013a0fe3adcae2 (patch) | |
tree | 1647bf44082454f51d6a3e3ceaeeb7032d6c7930 | |
parent | 34d191be67e821284e6e2a241a17731f2d646e2f (diff) | |
download | bun-365fc0d39ddfaed8683eb6ee75013a0fe3adcae2.tar.gz bun-365fc0d39ddfaed8683eb6ee75013a0fe3adcae2.tar.zst bun-365fc0d39ddfaed8683eb6ee75013a0fe3adcae2.zip |
implement `Module.prototype._compile` (#5840)
-rw-r--r-- | src/bun.js/bindings/CommonJSModuleRecord.cpp | 58 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.h | 1 | ||||
-rw-r--r-- | src/bun.js/module_loader.zig | 4 | ||||
-rw-r--r-- | test/js/node/module/node-module-module.test.js | 17 |
4 files changed, 78 insertions, 2 deletions
diff --git a/src/bun.js/bindings/CommonJSModuleRecord.cpp b/src/bun.js/bindings/CommonJSModuleRecord.cpp index 8fbb780a8..e4fb1939c 100644 --- a/src/bun.js/bindings/CommonJSModuleRecord.cpp +++ b/src/bun.js/bindings/CommonJSModuleRecord.cpp @@ -346,6 +346,63 @@ static JSValue createChildren(VM& vm, JSObject* object) return constructEmptyArray(object->globalObject(), nullptr, 0); } +JSC_DEFINE_HOST_FUNCTION(functionCommonJSModuleRecord_compile, (JSGlobalObject * globalObject, CallFrame* callframe)) +{ + auto* moduleObject = jsDynamicCast<JSCommonJSModule*>(callframe->thisValue()); + if (!moduleObject) { + return JSValue::encode(jsUndefined()); + } + + auto& vm = globalObject->vm(); + auto throwScope = DECLARE_THROW_SCOPE(vm); + + String sourceString = callframe->argument(0).toWTFString(globalObject); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode({})); + + String filenameString = callframe->argument(1).toWTFString(globalObject); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode({})); + + String wrappedString = makeString( + "(function(module,exports,require,__dirname,__filename){"_s, + sourceString, + "\n}).call($_BunCommonJSModule_$.module.exports, $_BunCommonJSModule_$.module, $_BunCommonJSModule_$.module.exports, ($_BunCommonJSModule_$.module.require = $_BunCommonJSModule_$.module.require.bind($_BunCommonJSModule_$.module), $_BunCommonJSModule_$.module.require.path = $_BunCommonJSModule_$.module.id, $_BunCommonJSModule_$.module.require.resolve = $_BunCommonJSModule_$.module.require.resolve.bind($_BunCommonJSModule_$.module.id), $_BunCommonJSModule_$.module.require), $_BunCommonJSModule_$.__dirname, $_BunCommonJSModule_$.__filename);"_s); + + SourceCode sourceCode = makeSource( + WTFMove(wrappedString), + SourceOrigin(URL::fileURLWithFileSystemPath(filenameString)), + JSC::SourceTaintedOrigin::Untainted, + filenameString, + WTF::TextPosition(), + JSC::SourceProviderSourceType::Program); + JSSourceCode* jsSourceCode = JSSourceCode::create(vm, WTFMove(sourceCode)); + moduleObject->sourceCode.set(vm, moduleObject, jsSourceCode); + + auto index = filenameString.reverseFind('/', filenameString.length()); + String dirnameString; + if (index != WTF::notFound) { + dirnameString = filenameString.substring(0, index); + } else { + dirnameString = "/"_s; + } + + WTF::NakedPtr<JSC::Exception> exception; + evaluateCommonJSModuleOnce( + vm, + jsCast<Zig::GlobalObject*>(globalObject), + moduleObject, + jsString(vm, dirnameString), + jsString(vm, filenameString), + exception); + + if (exception) { + throwException(globalObject, throwScope, exception.get()); + exception.clear(); + return JSValue::encode({}); + } + + return JSValue::encode(jsUndefined()); +} + static const struct HashTableValue JSCommonJSModulePrototypeTableValues[] = { { "children"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback | PropertyAttribute::DontEnum | 0), NoIntrinsic, { HashTableValue::LazyPropertyType, createChildren } }, { "filename"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterFilename, setterFilename } }, @@ -354,6 +411,7 @@ static const struct HashTableValue JSCommonJSModulePrototypeTableValues[] = { { "parent"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback | PropertyAttribute::DontEnum | 0), NoIntrinsic, { HashTableValue::LazyPropertyType, createParent } }, { "path"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterPath, setterPath } }, { "paths"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterPaths, setterPaths } }, + { "_compile"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, functionCommonJSModuleRecord_compile, 2 } }, }; class JSCommonJSModulePrototype final : public JSC::JSNonFinalObject { diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index 031dc4a13..e27b3bffa 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -346,6 +346,7 @@ public: mutable WriteBarrier<JSFunction> m_nodeModuleOverriddenResolveFilename; mutable WriteBarrier<Unknown> m_nextTickQueue; + // Value of $_BunCommonJSModule_$ mutable WriteBarrier<Unknown> m_BunCommonJSModuleValue; // mutable WriteBarrier<Unknown> m_JSBunDebuggerValue; diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index 135bd5e94..a54b42825 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -2143,7 +2143,7 @@ pub const ModuleLoader = struct { const path = Fs.Path.init(specifier); const loader = if (loader_ != ._none) - options.Loader.fromString(@tagName(loader_)).? + options.Loader.fromAPI(loader_) else jsc_vm.bundler.options.loaders.get(path.name.ext) orelse brk: { if (strings.eqlLong(specifier, jsc_vm.main, true)) { @@ -2162,7 +2162,7 @@ pub const ModuleLoader = struct { referrer_slice.slice(), specifier_ptr.*, path, - options.Loader.fromString(@tagName(loader)).?, + loader, &log, &virtual_source, ret, diff --git a/test/js/node/module/node-module-module.test.js b/test/js/node/module/node-module-module.test.js index e5e21c981..1363636ac 100644 --- a/test/js/node/module/node-module-module.test.js +++ b/test/js/node/module/node-module-module.test.js @@ -70,3 +70,20 @@ test("Overwriting _resolveFilename", () => { expect(stdout.toString().trim().endsWith("--pass--")).toBe(true); expect(exitCode).toBe(0); }); + +test("Module.prototype._compile", () => { + const module = new Module("module id goes here"); + const starting_exports = module.exports; + const r = module._compile( + "module.exports = { module, exports, require, __filename, __dirname }", + "/file/path/goes/here.js", + ); + expect(r).toBe(undefined); + expect(module.exports).not.toBe(starting_exports); + const { module: m, exports: e, require: req, __filename: fn, __dirname: dn } = module.exports; + expect(m).toBe(module); + expect(e).toBe(starting_exports); + expect(req).toBe(module.require); + expect(fn).toBe("/file/path/goes/here.js"); + expect(dn).toBe("/file/path/goes"); +}); |