mirror of
https://github.com/denoland/deno.git
synced 2025-01-08 15:19:40 -05:00
Add libdeno.builtinModules (#1463)
This is needed to support builtin modules like import { open } from "deno"
This commit is contained in:
parent
f37d67e809
commit
1b7938e3aa
4 changed files with 100 additions and 3 deletions
|
@ -18,6 +18,8 @@ interface Libdeno {
|
|||
|
||||
shared: ArrayBuffer;
|
||||
|
||||
builtinModules: { [s: string]: object };
|
||||
|
||||
setGlobalErrorHandler: (
|
||||
handler: (
|
||||
message: string,
|
||||
|
|
|
@ -323,6 +323,23 @@ void Send(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> DenoIsolate::GetBuiltinModules() {
|
||||
v8::EscapableHandleScope handle_scope(isolate_);
|
||||
if (builtin_modules_.IsEmpty()) {
|
||||
builtin_modules_.Reset(isolate_, v8::Object::New(isolate_));
|
||||
}
|
||||
return handle_scope.Escape(builtin_modules_.Get(isolate_));
|
||||
}
|
||||
|
||||
void BuiltinModules(v8::Local<v8::Name> property,
|
||||
const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||||
v8::Isolate* isolate = info.GetIsolate();
|
||||
DenoIsolate* d = FromIsolate(isolate);
|
||||
DCHECK_EQ(d->isolate_, isolate);
|
||||
v8::Locker locker(d->isolate_);
|
||||
info.GetReturnValue().Set(d->GetBuiltinModules());
|
||||
}
|
||||
|
||||
void Shared(v8::Local<v8::Name> property,
|
||||
const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||||
v8::Isolate* isolate = info.GetIsolate();
|
||||
|
@ -408,6 +425,44 @@ v8::MaybeLocal<v8::Module> ResolveCallback(v8::Local<v8::Context> context,
|
|||
v8::EscapableHandleScope handle_scope(isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
|
||||
v8::String::Utf8Value specifier_utf8val(isolate, specifier);
|
||||
const char* specifier_cstr = ToCString(specifier_utf8val);
|
||||
|
||||
auto builtin_modules = d->GetBuiltinModules();
|
||||
bool has_builtin = builtin_modules->Has(context, specifier).ToChecked();
|
||||
if (has_builtin) {
|
||||
auto val = builtin_modules->Get(context, specifier).ToLocalChecked();
|
||||
CHECK(val->IsObject());
|
||||
auto obj = val->ToObject(isolate);
|
||||
|
||||
// In order to export obj as a module, we must iterate over its properties
|
||||
// and export them each individually.
|
||||
// TODO Find a better way to do this.
|
||||
std::string src = "let globalEval = eval\nlet g = globalEval('this');\n";
|
||||
auto names = obj->GetOwnPropertyNames(context).ToLocalChecked();
|
||||
for (uint32_t i = 0; i < names->Length(); i++) {
|
||||
auto name = names->Get(context, i).ToLocalChecked();
|
||||
v8::String::Utf8Value name_utf8val(isolate, name);
|
||||
const char* name_cstr = ToCString(name_utf8val);
|
||||
// TODO use format string.
|
||||
src.append("export const ");
|
||||
src.append(name_cstr);
|
||||
src.append(" = g.libdeno.builtinModules.");
|
||||
src.append(specifier_cstr);
|
||||
src.append(".");
|
||||
src.append(name_cstr);
|
||||
src.append(";\n");
|
||||
}
|
||||
auto export_str = v8_str(src.c_str(), true);
|
||||
|
||||
auto module =
|
||||
CompileModule(context, specifier_cstr, export_str).ToLocalChecked();
|
||||
auto maybe_ok = module->InstantiateModule(context, ResolveCallback);
|
||||
CHECK(!maybe_ok.IsNothing());
|
||||
|
||||
return handle_scope.Escape(module);
|
||||
}
|
||||
|
||||
int ref_id = referrer->GetIdentityHash();
|
||||
std::string referrer_filename = d->module_filename_map_[ref_id];
|
||||
|
||||
|
@ -439,7 +494,7 @@ void DenoIsolate::ResolveOk(const char* filename, const char* source) {
|
|||
v8::HandleScope handle_scope(isolate_);
|
||||
auto context = context_.Get(isolate_);
|
||||
v8::TryCatch try_catch(isolate_);
|
||||
auto maybe_module = CompileModule(context, filename, v8_str(source));
|
||||
auto maybe_module = CompileModule(context, filename, v8_str(source, true));
|
||||
if (maybe_module.IsEmpty()) {
|
||||
DCHECK(try_catch.HasCaught());
|
||||
HandleException(context, try_catch.Exception());
|
||||
|
@ -545,6 +600,11 @@ void InitializeContext(v8::Isolate* isolate, v8::Local<v8::Context> context) {
|
|||
|
||||
CHECK(deno_val->SetAccessor(context, deno::v8_str("shared"), Shared)
|
||||
.FromJust());
|
||||
|
||||
CHECK(
|
||||
deno_val
|
||||
->SetAccessor(context, deno::v8_str("builtinModules"), BuiltinModules)
|
||||
.FromJust());
|
||||
}
|
||||
|
||||
void DenoIsolate::AddIsolate(v8::Isolate* isolate) {
|
||||
|
|
|
@ -45,6 +45,8 @@ class DenoIsolate {
|
|||
void ResolveOk(const char* filename, const char* source);
|
||||
void ClearModules();
|
||||
|
||||
v8::Local<v8::Object> GetBuiltinModules();
|
||||
|
||||
v8::Isolate* isolate_;
|
||||
v8::ArrayBuffer::Allocator* array_buffer_allocator_;
|
||||
deno_buf shared_;
|
||||
|
@ -63,6 +65,8 @@ class DenoIsolate {
|
|||
// Set by deno_resolve_ok
|
||||
v8::Persistent<v8::Module> resolve_module_;
|
||||
|
||||
v8::Persistent<v8::Object> builtin_modules_;
|
||||
|
||||
v8::Persistent<v8::Context> context_;
|
||||
std::map<int32_t, v8::Persistent<v8::Value>> async_data_map_;
|
||||
std::map<int, v8::Persistent<v8::Value>> pending_promise_map_;
|
||||
|
@ -108,9 +112,15 @@ void Recv(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|||
void Send(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
void Shared(v8::Local<v8::Name> property,
|
||||
const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
void BuiltinModules(v8::Local<v8::Name> property,
|
||||
const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static intptr_t external_references[] = {
|
||||
reinterpret_cast<intptr_t>(Print), reinterpret_cast<intptr_t>(Recv),
|
||||
reinterpret_cast<intptr_t>(Send), reinterpret_cast<intptr_t>(Shared), 0};
|
||||
reinterpret_cast<intptr_t>(Print),
|
||||
reinterpret_cast<intptr_t>(Recv),
|
||||
reinterpret_cast<intptr_t>(Send),
|
||||
reinterpret_cast<intptr_t>(Shared),
|
||||
reinterpret_cast<intptr_t>(BuiltinModules),
|
||||
0};
|
||||
|
||||
static const deno_buf empty_buf = {nullptr, 0, nullptr, 0};
|
||||
|
||||
|
|
|
@ -306,3 +306,28 @@ TEST(LibDenoTest, ModuleSnapshot) {
|
|||
|
||||
delete[] test_snapshot.data_ptr;
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, BuiltinModules) {
|
||||
static int count = 0;
|
||||
auto resolve_cb = [](void* user_data, const char* specifier,
|
||||
const char* referrer) {
|
||||
EXPECT_STREQ(specifier, "b.js");
|
||||
EXPECT_STREQ(referrer, "c.js");
|
||||
count++;
|
||||
auto d = reinterpret_cast<Deno*>(user_data);
|
||||
deno_resolve_ok(d, "b.js", mod_b);
|
||||
};
|
||||
Deno* d = deno_new(deno_config{0, empty, empty, nullptr, resolve_cb});
|
||||
EXPECT_TRUE(deno_execute(
|
||||
d, d, "setup.js", "libdeno.builtinModules['deno'] = { foo: 'bar' }; \n"));
|
||||
EXPECT_EQ(count, 0);
|
||||
EXPECT_TRUE(
|
||||
deno_execute_mod(d, d, "c.js",
|
||||
"import { retb } from 'b.js'\n"
|
||||
"import * as deno from 'deno'\n"
|
||||
"if (retb() != 'b') throw Error('retb');\n"
|
||||
// " libdeno.print('deno ' + JSON.stringify(deno));\n"
|
||||
"if (deno.foo != 'bar') throw Error('foo');\n"));
|
||||
EXPECT_EQ(count, 1);
|
||||
deno_delete(d);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue