cf127e8144
This patch gives the ability for the embedder to ask for the module requests of a module, and to pass a ResolveCallback into Module::Instantiate(). In d8, I've implemented a simple module_map that's used along with this API to allow loading, compiling, instantiating, and evaluating a whole tree of modules. No path resolution is yet implemented, meaning that all import paths are relative to whatever directory d8 runs in. And no imports are linked to the exports of the requested module. BUG=v8:1569 Review-Url: https://codereview.chromium.org/2351113004 Cr-Commit-Position: refs/heads/master@{#39569}
92 lines
3.1 KiB
C++
92 lines
3.1 KiB
C++
// Copyright 2016 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "src/flags.h"
|
|
|
|
#include "test/cctest/cctest.h"
|
|
|
|
using v8::Context;
|
|
using v8::HandleScope;
|
|
using v8::Isolate;
|
|
using v8::Local;
|
|
using v8::MaybeLocal;
|
|
using v8::Module;
|
|
using v8::ScriptCompiler;
|
|
using v8::ScriptOrigin;
|
|
using v8::String;
|
|
using v8::Value;
|
|
|
|
static MaybeLocal<Module> AlwaysEmptyResolveCallback(Local<Context> context,
|
|
Local<String> specifier,
|
|
Local<Module> referrer,
|
|
Local<Value> data) {
|
|
return MaybeLocal<Module>();
|
|
}
|
|
|
|
static int g_count = 0;
|
|
static MaybeLocal<Module> FailOnSecondCallResolveCallback(
|
|
Local<Context> context, Local<String> specifier, Local<Module> referrer,
|
|
Local<Value> data) {
|
|
if (g_count++ > 0) return MaybeLocal<Module>();
|
|
Local<String> source_text = v8_str("");
|
|
ScriptOrigin origin(v8_str("module.js"));
|
|
ScriptCompiler::Source source(source_text, origin);
|
|
return ScriptCompiler::CompileModule(CcTest::isolate(), &source)
|
|
.ToLocalChecked();
|
|
}
|
|
|
|
TEST(ModuleInstantiationFailures) {
|
|
Isolate* isolate = CcTest::isolate();
|
|
HandleScope scope(isolate);
|
|
LocalContext env;
|
|
|
|
Local<String> source_text = v8_str(
|
|
"import './foo.js';"
|
|
"export {} from './bar.js';");
|
|
ScriptOrigin origin(v8_str("file.js"));
|
|
ScriptCompiler::Source source(source_text, origin);
|
|
Local<Module> module =
|
|
ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
|
|
CHECK_EQ(2, module->GetModuleRequestsLength());
|
|
CHECK(v8_str("./foo.js")->StrictEquals(module->GetModuleRequest(0)));
|
|
CHECK(v8_str("./bar.js")->StrictEquals(module->GetModuleRequest(1)));
|
|
|
|
// Instantiation should fail.
|
|
CHECK(!module->Instantiate(env.local(), AlwaysEmptyResolveCallback));
|
|
|
|
// Start over again...
|
|
module = ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
|
|
|
|
// Instantiation should fail if a sub-module fails to resolve.
|
|
g_count = 0;
|
|
CHECK(!module->Instantiate(env.local(), FailOnSecondCallResolveCallback));
|
|
}
|
|
|
|
static MaybeLocal<Module> CompileSpecifierAsModuleResolveCallback(
|
|
Local<Context> context, Local<String> specifier, Local<Module> referrer,
|
|
Local<Value> data) {
|
|
ScriptOrigin origin(v8_str("module.js"));
|
|
ScriptCompiler::Source source(specifier, origin);
|
|
return ScriptCompiler::CompileModule(CcTest::isolate(), &source)
|
|
.ToLocalChecked();
|
|
}
|
|
|
|
TEST(ModuleEvaluation) {
|
|
Isolate* isolate = CcTest::isolate();
|
|
HandleScope scope(isolate);
|
|
LocalContext env;
|
|
|
|
Local<String> source_text = v8_str(
|
|
"import 'Object.expando = 5';"
|
|
"import 'Object.expando *= 2';");
|
|
ScriptOrigin origin(v8_str("file.js"));
|
|
ScriptCompiler::Source source(source_text, origin);
|
|
Local<Module> module =
|
|
ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
|
|
CHECK(module->Instantiate(env.local(),
|
|
CompileSpecifierAsModuleResolveCallback));
|
|
CHECK(!module->Evaluate(env.local()).IsEmpty());
|
|
ExpectInt32("Object.expando", 10);
|
|
}
|