mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 06:04:57 +00:00
LibJS+LibWeb: Another round of bringing module loading closer to spec
In particular, this patch focuses on: - Updating the old "import assertions" to the new "import attributes" - Allowing realms as module import referrer
This commit is contained in:
parent
82977ab44b
commit
07f567cd9f
14 changed files with 244 additions and 178 deletions
|
@ -1536,9 +1536,9 @@ DeprecatedFlyString ExportStatement::local_name_for_default = "*default*";
|
|||
|
||||
static void dump_assert_clauses(ModuleRequest const& request)
|
||||
{
|
||||
if (!request.assertions.is_empty()) {
|
||||
if (!request.attributes.is_empty()) {
|
||||
out("[ ");
|
||||
for (auto& assertion : request.assertions)
|
||||
for (auto& assertion : request.attributes)
|
||||
out("{}: {}, ", assertion.key, assertion.value);
|
||||
out(" ]");
|
||||
}
|
||||
|
@ -1882,15 +1882,15 @@ ThrowCompletionOr<void> Program::global_declaration_instantiation(VM& vm, Global
|
|||
return {};
|
||||
}
|
||||
|
||||
ModuleRequest::ModuleRequest(DeprecatedFlyString module_specifier_, Vector<Assertion> assertions_)
|
||||
ModuleRequest::ModuleRequest(DeprecatedFlyString module_specifier_, Vector<ImportAttribute> attributes)
|
||||
: module_specifier(move(module_specifier_))
|
||||
, assertions(move(assertions_))
|
||||
, attributes(move(attributes))
|
||||
{
|
||||
// Perform step 10.e. from EvaluateImportCall, https://tc39.es/proposal-import-assertions/#sec-evaluate-import-call
|
||||
// or step 2. from 2.7 Static Semantics: AssertClauseToAssertions, https://tc39.es/proposal-import-assertions/#sec-assert-clause-to-assertions
|
||||
// Perform step 10.e. from EvaluateImportCall, https://tc39.es/proposal-import-attributes/#sec-evaluate-import-call
|
||||
// or step 2. from WithClauseToAttributes, https://tc39.es/proposal-import-attributes/#sec-with-clause-to-attributes
|
||||
// e. / 2. Sort assertions by the code point order of the [[Key]] of each element.
|
||||
// NOTE: This sorting is observable only in that hosts are prohibited from distinguishing among assertions by the order they occur in.
|
||||
quick_sort(assertions, [](Assertion const& lhs, Assertion const& rhs) {
|
||||
quick_sort(this->attributes, [](ImportAttribute const& lhs, ImportAttribute const& rhs) {
|
||||
return lhs.key < rhs.key;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -162,6 +162,7 @@ class ClassExpression;
|
|||
struct ClassFieldDefinition;
|
||||
class Completion;
|
||||
class Console;
|
||||
class CyclicModule;
|
||||
class DeclarativeEnvironment;
|
||||
class DeferGC;
|
||||
class ECMAScriptFunctionObject;
|
||||
|
@ -178,6 +179,7 @@ class FunctionNode;
|
|||
struct FunctionParameter;
|
||||
class GlobalEnvironment;
|
||||
class GlobalObject;
|
||||
struct GraphLoadingState;
|
||||
class HandleImpl;
|
||||
class Heap;
|
||||
class HeapBlock;
|
||||
|
|
18
Userland/Libraries/LibJS/ModuleLoading.h
Normal file
18
Userland/Libraries/LibJS/ModuleLoading.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (c) 2023, networkException <networkexception@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Variant.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/GCPtr.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
using ImportedModuleReferrer = Variant<NonnullGCPtr<Script>, NonnullGCPtr<CyclicModule>, NonnullGCPtr<Realm>>;
|
||||
using ImportedModulePayload = Variant<NonnullGCPtr<GraphLoadingState>, NonnullGCPtr<PromiseCapability>>;
|
||||
|
||||
}
|
|
@ -1230,7 +1230,7 @@ NonnullRefPtr<ImportCall const> Parser::parse_import_call()
|
|||
// ImportCall[Yield, Await]:
|
||||
// import(AssignmentExpression[+In, ?Yield, ?Await] ,opt)
|
||||
// import(AssignmentExpression[+In, ?Yield, ?Await] ,AssignmentExpression[+In, ?Yield, ?Await] ,opt)
|
||||
// From https://tc39.es/proposal-import-assertions/#sec-evaluate-import-call
|
||||
// From https://tc39.es/proposal-import-attributes/#sec-evaluate-import-call
|
||||
|
||||
consume(TokenType::Import);
|
||||
consume(TokenType::ParenOpen);
|
||||
|
@ -4468,8 +4468,10 @@ void Parser::check_identifier_name_for_assignment_validity(DeprecatedFlyString c
|
|||
}
|
||||
}
|
||||
|
||||
bool Parser::match_assert_clause() const
|
||||
bool Parser::match_with_clause() const
|
||||
{
|
||||
if (m_state.current_token.original_value() == "with"sv)
|
||||
return true;
|
||||
return !m_state.current_token.trivia_contains_line_terminator() && m_state.current_token.original_value() == "assert"sv;
|
||||
}
|
||||
|
||||
|
@ -4495,7 +4497,7 @@ DeprecatedFlyString Parser::consume_string_value()
|
|||
return value;
|
||||
}
|
||||
|
||||
// AssertClause, https://tc39.es/proposal-import-assertions/#prod-AssertClause
|
||||
// WithClause, https://tc39.es/proposal-import-attributes/#prod-WithClause
|
||||
ModuleRequest Parser::parse_module_request()
|
||||
{
|
||||
// Does not include the 'from' since that is not always required.
|
||||
|
@ -4507,10 +4509,10 @@ ModuleRequest Parser::parse_module_request()
|
|||
|
||||
ModuleRequest request { consume_string_value() };
|
||||
|
||||
if (!match_assert_clause())
|
||||
if (!match_with_clause())
|
||||
return request;
|
||||
|
||||
VERIFY(m_state.current_token.original_value() == "assert"sv);
|
||||
VERIFY(m_state.current_token.original_value().is_one_of("with"sv, "assert"sv));
|
||||
consume(TokenType::Identifier);
|
||||
consume(TokenType::CurlyOpen);
|
||||
|
||||
|
@ -4522,18 +4524,18 @@ ModuleRequest Parser::parse_module_request()
|
|||
} else if (match_identifier_name()) {
|
||||
key = consume().value();
|
||||
} else {
|
||||
expected("IdentifierName or StringValue as AssertionKey");
|
||||
expected("IdentifierName or StringValue as WithKey");
|
||||
consume();
|
||||
}
|
||||
|
||||
consume(TokenType::Colon);
|
||||
|
||||
if (match(TokenType::StringLiteral)) {
|
||||
for (auto& entries : request.assertions) {
|
||||
for (auto& entries : request.attributes) {
|
||||
if (entries.key == key)
|
||||
syntax_error(DeprecatedString::formatted("Duplicate assertion clauses with name: {}", key));
|
||||
syntax_error(DeprecatedString::formatted("Duplicate attribute clauses with name: {}", key));
|
||||
}
|
||||
request.add_assertion(move(key), parse_string_literal(m_state.current_token)->value().to_deprecated_string());
|
||||
request.add_attribute(move(key), parse_string_literal(m_state.current_token)->value().to_deprecated_string());
|
||||
}
|
||||
consume(TokenType::StringLiteral);
|
||||
|
||||
|
@ -4554,9 +4556,9 @@ NonnullRefPtr<ImportStatement const> Parser::parse_import_statement(Program& pro
|
|||
{
|
||||
// We use the extended syntax which adds:
|
||||
// ImportDeclaration:
|
||||
// import ImportClause FromClause [no LineTerminator here] AssertClause;
|
||||
// import ModuleSpecifier [no LineTerminator here] AssertClause;
|
||||
// From: https://tc39.es/proposal-import-assertions/#prod-ImportDeclaration
|
||||
// import ImportClause FromClause [no LineTerminator here] WithClause;
|
||||
// import ModuleSpecifier [no LineTerminator here] WithClause;
|
||||
// From: https://tc39.es/proposal-import-attributes/#prod-ImportDeclaration
|
||||
|
||||
auto rule_start = push_start();
|
||||
if (program.type() != Program::Type::Module)
|
||||
|
@ -4714,8 +4716,8 @@ NonnullRefPtr<ExportStatement const> Parser::parse_export_statement(Program& pro
|
|||
{
|
||||
// We use the extended syntax which adds:
|
||||
// ExportDeclaration:
|
||||
// export ExportFromClause FromClause [no LineTerminator here] AssertClause ;
|
||||
// From: https://tc39.es/proposal-import-assertions/#prod-ExportDeclaration
|
||||
// export ExportFromClause FromClause [no LineTerminator here] WithClause ;
|
||||
// From: https://tc39.es/proposal-import-attributes/#sec-exports
|
||||
|
||||
auto rule_start = push_start();
|
||||
if (program.type() != Program::Type::Module)
|
||||
|
|
|
@ -225,7 +225,7 @@ private:
|
|||
bool match_secondary_expression(ForbiddenTokens forbidden = {}) const;
|
||||
bool match_statement() const;
|
||||
bool match_export_or_import() const;
|
||||
bool match_assert_clause() const;
|
||||
bool match_with_clause() const;
|
||||
|
||||
enum class AllowUsingDeclaration {
|
||||
No,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <AK/Optional.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <LibJS/Bytecode/Interpreter.h>
|
||||
#include <LibJS/ModuleLoading.h>
|
||||
#include <LibJS/Parser.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Accessor.h>
|
||||
|
@ -1459,25 +1460,53 @@ Completion dispose_resources(VM& vm, GCPtr<DeclarativeEnvironment> disposable, C
|
|||
return completion;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-import-attributes/#sec-AllImportAttributesSupported
|
||||
static bool all_import_attributes_supported(VM& vm, Vector<ImportAttribute> const& attributes)
|
||||
{
|
||||
// 1. Let supported be HostGetSupportedImportAttributes().
|
||||
auto supported = vm.host_get_supported_import_attributes();
|
||||
|
||||
// 2. For each ImportAttribute Record attribute of attributes, do
|
||||
for (auto const& attribute : attributes) {
|
||||
// a. If supported does not contain attribute.[[Key]], return false.
|
||||
if (!supported.contains_slow(attribute.key))
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. Return true.
|
||||
return true;
|
||||
}
|
||||
|
||||
ThrowCompletionOr<Value> perform_import_call(VM& vm, Value specifier, Value options_value)
|
||||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
// 2.1.1.1 EvaluateImportCall ( specifierExpression [ , optionsExpression ] ), https://tc39.es/proposal-import-assertions/#sec-evaluate-import-call
|
||||
// 1. Let referencingScriptOrModule be GetActiveScriptOrModule().
|
||||
auto referencing_script_or_module = vm.get_active_script_or_module();
|
||||
// 13.3.10.2 EvaluateImportCall ( specifierExpression [ , optionsExpression ] ), https://tc39.es/proposal-import-attributes/#sec-evaluate-import-call
|
||||
// 1. Let referrer be GetActiveScriptOrModule().
|
||||
auto referrer = [&]() -> ImportedModuleReferrer {
|
||||
auto active_script_or_module = vm.get_active_script_or_module();
|
||||
|
||||
// 6. Let promiseCapability be ! NewPromiseCapability(%Promise%).
|
||||
// 2. If referrer is null, set referrer to the current Realm Record.
|
||||
if (active_script_or_module.has<Empty>())
|
||||
return NonnullGCPtr<Realm> { realm };
|
||||
|
||||
if (active_script_or_module.has<NonnullGCPtr<Script>>())
|
||||
return active_script_or_module.get<NonnullGCPtr<Script>>();
|
||||
|
||||
return NonnullGCPtr<CyclicModule> { verify_cast<CyclicModule>(*active_script_or_module.get<NonnullGCPtr<Module>>()) };
|
||||
}();
|
||||
|
||||
// 7. Let promiseCapability be ! NewPromiseCapability(%Promise%).
|
||||
auto promise_capability = MUST(new_promise_capability(vm, realm.intrinsics().promise_constructor()));
|
||||
|
||||
// 7. Let specifierString be Completion(ToString(specifier)).
|
||||
// 8. IfAbruptRejectPromise(specifierString, promiseCapability).
|
||||
// 8. Let specifierString be Completion(ToString(specifier)).
|
||||
// 9. IfAbruptRejectPromise(specifierString, promiseCapability).
|
||||
auto specifier_string = TRY_OR_REJECT_WITH_VALUE(vm, promise_capability, specifier.to_deprecated_string(vm));
|
||||
|
||||
// 9. Let assertions be a new empty List.
|
||||
Vector<ModuleRequest::Assertion> assertions;
|
||||
// 10. Let attributes be a new empty List.
|
||||
Vector<ImportAttribute> attributes;
|
||||
|
||||
// 10. If options is not undefined, then
|
||||
// 11. If options is not undefined, then
|
||||
if (!options_value.is_undefined()) {
|
||||
// a. If Type(options) is not Object,
|
||||
if (!options_value.is_object()) {
|
||||
|
@ -1489,14 +1518,22 @@ ThrowCompletionOr<Value> perform_import_call(VM& vm, Value specifier, Value opti
|
|||
return Value { promise_capability->promise() };
|
||||
}
|
||||
|
||||
// b. Let assertionsObj be Get(options, "assert").
|
||||
// c. IfAbruptRejectPromise(assertionsObj, promiseCapability).
|
||||
auto assertion_object = TRY_OR_REJECT_WITH_VALUE(vm, promise_capability, options_value.get(vm, vm.names.assert));
|
||||
// b. Let attributesObj be Completion(Get(options, "with")).
|
||||
// c. IfAbruptRejectPromise(attributesObj, promiseCapability).
|
||||
auto attributes_obj = TRY_OR_REJECT_WITH_VALUE(vm, promise_capability, options_value.get(vm, vm.names.with));
|
||||
|
||||
// d. If assertionsObj is not undefined,
|
||||
if (!assertion_object.is_undefined()) {
|
||||
// i. If Type(assertionsObj) is not Object,
|
||||
if (!assertion_object.is_object()) {
|
||||
// d. Normative Optional, Deprecated
|
||||
// 11. If the host supports the deprecated assert keyword for import attributes and attributesObj is undefined, then
|
||||
if (attributes_obj.is_undefined()) {
|
||||
// i. Set attributesObj to Completion(Get(options, "assert")).
|
||||
// ii. IfAbruptRejectPromise(attributesObj, promiseCapability).
|
||||
attributes_obj = TRY_OR_REJECT_WITH_VALUE(vm, promise_capability, options_value.get(vm, vm.names.assert));
|
||||
}
|
||||
|
||||
// e. If attributesObj is not undefined,
|
||||
if (!attributes_obj.is_undefined()) {
|
||||
// i. If Type(attributesObj) is not Object,
|
||||
if (!attributes_obj.is_object()) {
|
||||
auto error = TypeError::create(realm, TRY_OR_THROW_OOM(vm, String::formatted(ErrorType::NotAnObject.message(), "ImportOptionsAssertions")));
|
||||
// 1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
|
||||
MUST(call(vm, *promise_capability->reject(), js_undefined(), error));
|
||||
|
@ -1505,20 +1542,17 @@ ThrowCompletionOr<Value> perform_import_call(VM& vm, Value specifier, Value opti
|
|||
return Value { promise_capability->promise() };
|
||||
}
|
||||
|
||||
// ii. Let keys be EnumerableOwnPropertyNames(assertionsObj, key).
|
||||
// iii. IfAbruptRejectPromise(keys, promiseCapability).
|
||||
auto keys = TRY_OR_REJECT_WITH_VALUE(vm, promise_capability, assertion_object.as_object().enumerable_own_property_names(Object::PropertyKind::Key));
|
||||
// ii. Let entries be Completion(EnumerableOwnProperties(attributesObj, key+value)).
|
||||
// iii. IfAbruptRejectPromise(entries, promiseCapability).
|
||||
auto entries = TRY_OR_REJECT_WITH_VALUE(vm, promise_capability, attributes_obj.as_object().enumerable_own_property_names(Object::PropertyKind::KeyAndValue));
|
||||
|
||||
// iv. Let supportedAssertions be ! HostGetSupportedImportAssertions().
|
||||
auto supported_assertions = vm.host_get_supported_import_assertions();
|
||||
// iv. For each entry of entries, do
|
||||
for (auto const& entry : entries) {
|
||||
// 1. Let key be ! Get(entry, "0").
|
||||
auto key = MUST(entry.get(vm, PropertyKey(0)));
|
||||
|
||||
// v. For each String key of keys,
|
||||
for (auto const& key : keys) {
|
||||
auto property_key = MUST(key.to_property_key(vm));
|
||||
|
||||
// 1. Let value be Get(assertionsObj, key).
|
||||
// 2. IfAbruptRejectPromise(value, promiseCapability).
|
||||
auto value = TRY_OR_REJECT_WITH_VALUE(vm, promise_capability, assertion_object.get(vm, property_key));
|
||||
// 2. Let value be ! Get(entry, "1").
|
||||
auto value = MUST(entry.get(vm, PropertyKey(1)));
|
||||
|
||||
// 3. If Type(value) is not String, then
|
||||
if (!value.is_string()) {
|
||||
|
@ -1530,22 +1564,33 @@ ThrowCompletionOr<Value> perform_import_call(VM& vm, Value specifier, Value opti
|
|||
return Value { promise_capability->promise() };
|
||||
}
|
||||
|
||||
// 4. If supportedAssertions contains key, then
|
||||
if (supported_assertions.contains_slow(property_key.to_string())) {
|
||||
// a. Append { [[Key]]: key, [[Value]]: value } to assertions.
|
||||
assertions.empend(property_key.to_string(), value.as_string().deprecated_string());
|
||||
}
|
||||
// 4. Append the ImportAttribute Record { [[Key]]: key, [[Value]]: value } to attributes.
|
||||
attributes.empend(key.as_string().deprecated_string(), value.as_string().deprecated_string());
|
||||
}
|
||||
}
|
||||
// e. Sort assertions by the code point order of the [[Key]] of each element. NOTE: This sorting is observable only in that hosts are prohibited from distinguishing among assertions by the order they occur in.
|
||||
// Note: This is done when constructing the ModuleRequest.
|
||||
|
||||
// f. If AllImportAttributesSupported(attributes) is false, then
|
||||
if (!all_import_attributes_supported(vm, attributes)) {
|
||||
auto error = TypeError::create(realm, TRY_OR_THROW_OOM(vm, String::formatted(ErrorType::NotAnObject.message(), "ImportOptionsAssertions")));
|
||||
// i. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
|
||||
MUST(call(vm, *promise_capability->reject(), js_undefined(), error));
|
||||
|
||||
// ii. Return promiseCapability.[[Promise]].
|
||||
return Value { promise_capability->promise() };
|
||||
}
|
||||
|
||||
// g. Sort attributes according to the lexicographic order of their [[Key]] fields,
|
||||
// treating the value of each such field as a sequence of UTF-16 code unit values.
|
||||
// NOTE: This sorting is observable only in that hosts are prohibited from
|
||||
// distinguishing among attributes by the order they occur in.
|
||||
// NOTE: This is done when constructing the ModuleRequest.
|
||||
}
|
||||
|
||||
// 11. Let moduleRequest be a new ModuleRequest Record { [[Specifier]]: specifierString, [[Assertions]]: assertions }.
|
||||
ModuleRequest request { specifier_string, assertions };
|
||||
// 12. Let moduleRequest be a new ModuleRequest Record { [[Specifier]]: specifierString, [[Attributes]]: attributes }.
|
||||
ModuleRequest request { specifier_string, attributes };
|
||||
|
||||
// 12. Perform HostImportModuleDynamically(referencingScriptOrModule, moduleRequest, promiseCapability).
|
||||
MUST_OR_THROW_OOM(vm.host_import_module_dynamically(referencing_script_or_module, move(request), promise_capability));
|
||||
// 13. Perform HostLoadImportedModule(referrer, moduleRequest, empty, promiseCapability).
|
||||
MUST_OR_THROW_OOM(vm.host_import_module_dynamically(referrer, move(request), promise_capability));
|
||||
|
||||
// 13. Return promiseCapability.[[Promise]].
|
||||
return Value { promise_capability->promise() };
|
||||
|
|
|
@ -18,13 +18,14 @@ struct ModuleWithSpecifier {
|
|||
NonnullGCPtr<Module> module; // [[Module]]
|
||||
};
|
||||
|
||||
// 2.9 ModuleRequest Records, https://tc39.es/proposal-import-assertions/#sec-modulerequest-record
|
||||
struct ModuleRequest {
|
||||
struct Assertion {
|
||||
DeprecatedString key;
|
||||
DeprecatedString value;
|
||||
};
|
||||
// https://tc39.es/proposal-import-attributes/#importattribute-record
|
||||
struct ImportAttribute {
|
||||
DeprecatedString key;
|
||||
DeprecatedString value;
|
||||
};
|
||||
|
||||
// https://tc39.es/proposal-import-attributes/#modulerequest-record
|
||||
struct ModuleRequest {
|
||||
ModuleRequest() = default;
|
||||
|
||||
explicit ModuleRequest(DeprecatedFlyString specifier)
|
||||
|
@ -32,15 +33,15 @@ struct ModuleRequest {
|
|||
{
|
||||
}
|
||||
|
||||
ModuleRequest(DeprecatedFlyString module_specifier, Vector<Assertion> assertions);
|
||||
ModuleRequest(DeprecatedFlyString specifier, Vector<ImportAttribute> attributes);
|
||||
|
||||
void add_assertion(DeprecatedString key, DeprecatedString value)
|
||||
void add_attribute(DeprecatedString key, DeprecatedString value)
|
||||
{
|
||||
assertions.empend(move(key), move(value));
|
||||
attributes.empend(move(key), move(value));
|
||||
}
|
||||
|
||||
DeprecatedFlyString module_specifier; // [[Specifier]]
|
||||
Vector<Assertion> assertions; // [[Assertions]]
|
||||
Vector<ImportAttribute> attributes; // [[Attributes]]
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -233,8 +233,9 @@ ThrowCompletionOr<Value> shadow_realm_import_value(VM& vm, DeprecatedString spec
|
|||
// 5. Push evalContext onto the execution context stack; evalContext is now the running execution context.
|
||||
TRY(vm.push_execution_context(eval_context, {}));
|
||||
|
||||
// 6. Perform HostImportModuleDynamically(null, specifierString, innerCapability).
|
||||
MUST_OR_THROW_OOM(vm.host_import_module_dynamically(Empty {}, ModuleRequest { move(specifier_string) }, inner_capability));
|
||||
// 6. Let referrer be the Realm component of evalContext.
|
||||
// 7. Perform HostImportModuleDynamically(referrer, specifierString, innerCapability).
|
||||
MUST_OR_THROW_OOM(vm.host_import_module_dynamically(NonnullGCPtr { *eval_context.realm }, ModuleRequest { move(specifier_string) }, inner_capability));
|
||||
|
||||
// 7. Suspend evalContext and remove it from the execution context stack.
|
||||
// NOTE: We don't support this concept yet.
|
||||
|
|
|
@ -94,11 +94,11 @@ VM::VM(OwnPtr<CustomData> custom_data, ErrorMessages error_messages)
|
|||
return make_job_callback(function_object);
|
||||
};
|
||||
|
||||
host_resolve_imported_module = [&](ScriptOrModule referencing_script_or_module, ModuleRequest const& specifier) {
|
||||
return resolve_imported_module(move(referencing_script_or_module), specifier);
|
||||
host_resolve_imported_module = [&](ImportedModuleReferrer referrer, ModuleRequest const& specifier) {
|
||||
return resolve_imported_module(referrer, specifier);
|
||||
};
|
||||
|
||||
host_import_module_dynamically = [&](ScriptOrModule, ModuleRequest const&, PromiseCapability const& promise_capability) -> ThrowCompletionOr<void> {
|
||||
host_import_module_dynamically = [&](ImportedModuleReferrer, ModuleRequest const&, PromiseCapability const& promise_capability) -> ThrowCompletionOr<void> {
|
||||
// By default, we throw on dynamic imports this is to prevent arbitrary file access by scripts.
|
||||
VERIFY(current_realm());
|
||||
auto& realm = *current_realm();
|
||||
|
@ -127,8 +127,8 @@ VM::VM(OwnPtr<CustomData> custom_data, ErrorMessages error_messages)
|
|||
return {};
|
||||
};
|
||||
|
||||
host_finish_dynamic_import = [&](ScriptOrModule referencing_script_or_module, ModuleRequest const& specifier, PromiseCapability const& promise_capability, Promise* promise) {
|
||||
return finish_dynamic_import(move(referencing_script_or_module), specifier, promise_capability, promise);
|
||||
host_finish_dynamic_import = [&](ImportedModuleReferrer referrer, ModuleRequest const& specifier, PromiseCapability const& promise_capability, Promise* promise) {
|
||||
return finish_dynamic_import(referrer, specifier, promise_capability, promise);
|
||||
};
|
||||
|
||||
host_get_import_meta_properties = [&](SourceTextModule const&) -> HashMap<PropertyKey, Value> {
|
||||
|
@ -138,7 +138,7 @@ VM::VM(OwnPtr<CustomData> custom_data, ErrorMessages error_messages)
|
|||
host_finalize_import_meta = [&](Object*, SourceTextModule const&) {
|
||||
};
|
||||
|
||||
host_get_supported_import_assertions = [&] {
|
||||
host_get_supported_import_attributes = [&] {
|
||||
return Vector<DeprecatedString> { "type" };
|
||||
};
|
||||
|
||||
|
@ -183,8 +183,8 @@ String const& VM::error_message(ErrorMessage type) const
|
|||
|
||||
void VM::enable_default_host_import_module_dynamically_hook()
|
||||
{
|
||||
host_import_module_dynamically = [&](ScriptOrModule referencing_script_or_module, ModuleRequest const& specifier, PromiseCapability const& promise_capability) {
|
||||
return import_module_dynamically(move(referencing_script_or_module), specifier, promise_capability);
|
||||
host_import_module_dynamically = [&](ImportedModuleReferrer referrer, ModuleRequest const& specifier, PromiseCapability const& promise_capability) {
|
||||
return import_module_dynamically(referrer, specifier, promise_capability);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -760,7 +760,7 @@ ScriptOrModule VM::get_active_script_or_module() const
|
|||
return m_execution_context_stack[0]->script_or_module;
|
||||
}
|
||||
|
||||
VM::StoredModule* VM::get_stored_module(ScriptOrModule const&, DeprecatedString const& filename, DeprecatedString const&)
|
||||
VM::StoredModule* VM::get_stored_module(ImportedModuleReferrer const&, DeprecatedString const& filename, DeprecatedString const&)
|
||||
{
|
||||
// Note the spec says:
|
||||
// Each time this operation is called with a specific referencingScriptOrModule, specifier pair as arguments
|
||||
|
@ -801,7 +801,7 @@ ThrowCompletionOr<void> VM::link_and_eval_module(Module& module)
|
|||
dbgln("Warning: Using multiple modules as entry point can lead to unexpected results");
|
||||
|
||||
m_loaded_modules.empend(
|
||||
NonnullGCPtr(module),
|
||||
ImportedModuleReferrer { NonnullGCPtr { verify_cast<CyclicModule>(module) } },
|
||||
module.filename(),
|
||||
DeprecatedString {}, // Null type
|
||||
module,
|
||||
|
@ -866,7 +866,7 @@ static DeprecatedString resolve_module_filename(StringView filename, StringView
|
|||
}
|
||||
|
||||
// 16.2.1.7 HostResolveImportedModule ( referencingScriptOrModule, specifier ), https://tc39.es/ecma262/#sec-hostresolveimportedmodule
|
||||
ThrowCompletionOr<NonnullGCPtr<Module>> VM::resolve_imported_module(ScriptOrModule referencing_script_or_module, ModuleRequest const& module_request)
|
||||
ThrowCompletionOr<NonnullGCPtr<Module>> VM::resolve_imported_module(ImportedModuleReferrer referrer, ModuleRequest const& module_request)
|
||||
{
|
||||
// An implementation of HostResolveImportedModule must conform to the following requirements:
|
||||
// - If it completes normally, the [[Value]] slot of the completion must contain an instance of a concrete subclass of Module Record.
|
||||
|
@ -882,18 +882,25 @@ ThrowCompletionOr<NonnullGCPtr<Module>> VM::resolve_imported_module(ScriptOrModu
|
|||
// The actual mapping semantic is host-defined but typically a normalization process is applied to specifier as part of the mapping process.
|
||||
// A typical normalization process would include actions such as alphabetic case folding and expansion of relative and abbreviated path specifiers.
|
||||
|
||||
// We only allow "type" as a supported assertion so it is the only valid key that should ever arrive here.
|
||||
VERIFY(module_request.assertions.is_empty() || (module_request.assertions.size() == 1 && module_request.assertions.first().key == "type"));
|
||||
auto module_type = module_request.assertions.is_empty() ? DeprecatedString {} : module_request.assertions.first().value;
|
||||
DeprecatedString module_type;
|
||||
for (auto& attribute : module_request.attributes) {
|
||||
if (attribute.key == "type"sv) {
|
||||
module_type = attribute.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] module at {} has type {}", module_request.module_specifier, module_type);
|
||||
|
||||
StringView base_filename = referencing_script_or_module.visit(
|
||||
[&](Empty) {
|
||||
StringView const base_filename = referrer.visit(
|
||||
[&](NonnullGCPtr<Realm> const&) {
|
||||
return "."sv;
|
||||
},
|
||||
[&](auto& script_or_module) {
|
||||
return script_or_module->filename();
|
||||
[&](NonnullGCPtr<Script> const& script) {
|
||||
return script->filename();
|
||||
},
|
||||
[&](NonnullGCPtr<Module> const& module) {
|
||||
return module->filename();
|
||||
});
|
||||
|
||||
LexicalPath base_path { base_filename };
|
||||
|
@ -907,7 +914,7 @@ ThrowCompletionOr<NonnullGCPtr<Module>> VM::resolve_imported_module(ScriptOrModu
|
|||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] resolved filename: '{}'", filename);
|
||||
|
||||
#if JS_MODULE_DEBUG
|
||||
DeprecatedString referencing_module_string = referencing_script_or_module.visit(
|
||||
DeprecatedString referencing_module_string = referrer.visit(
|
||||
[&](Empty) -> DeprecatedString {
|
||||
return ".";
|
||||
},
|
||||
|
@ -922,7 +929,7 @@ ThrowCompletionOr<NonnullGCPtr<Module>> VM::resolve_imported_module(ScriptOrModu
|
|||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] resolved {} + {} -> {}", base_path, module_request.module_specifier, filename);
|
||||
#endif
|
||||
|
||||
auto* loaded_module_or_end = get_stored_module(referencing_script_or_module, filename, module_type);
|
||||
auto* loaded_module_or_end = get_stored_module(referrer, filename, module_type);
|
||||
if (loaded_module_or_end != nullptr) {
|
||||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] resolve_imported_module({}) already loaded at {}", filename, loaded_module_or_end->module.ptr());
|
||||
return NonnullGCPtr(*loaded_module_or_end->module);
|
||||
|
@ -970,7 +977,7 @@ ThrowCompletionOr<NonnullGCPtr<Module>> VM::resolve_imported_module(ScriptOrModu
|
|||
|
||||
// We have to set it here already in case it references itself.
|
||||
m_loaded_modules.empend(
|
||||
referencing_script_or_module,
|
||||
referrer,
|
||||
filename,
|
||||
module_type,
|
||||
*module,
|
||||
|
@ -980,7 +987,7 @@ ThrowCompletionOr<NonnullGCPtr<Module>> VM::resolve_imported_module(ScriptOrModu
|
|||
}
|
||||
|
||||
// 16.2.1.8 HostImportModuleDynamically ( referencingScriptOrModule, specifier, promiseCapability ), https://tc39.es/ecma262/#sec-hostimportmoduledynamically
|
||||
ThrowCompletionOr<void> VM::import_module_dynamically(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability const& promise_capability)
|
||||
ThrowCompletionOr<void> VM::import_module_dynamically(ImportedModuleReferrer referrer, ModuleRequest module_request, PromiseCapability const& promise_capability)
|
||||
{
|
||||
auto& realm = *current_realm();
|
||||
|
||||
|
@ -999,24 +1006,11 @@ ThrowCompletionOr<void> VM::import_module_dynamically(ScriptOrModule referencing
|
|||
auto promise = Promise::create(realm);
|
||||
|
||||
ScopeGuard finish_dynamic_import = [&] {
|
||||
host_finish_dynamic_import(referencing_script_or_module, module_request, promise_capability, promise);
|
||||
host_finish_dynamic_import(referrer, module_request, promise_capability, promise);
|
||||
};
|
||||
|
||||
// Generally within ECMA262 we always get a referencing_script_or_module. However, ShadowRealm gives an explicit null.
|
||||
// To get around this is we attempt to get the active script_or_module otherwise we might start loading "random" files from the working directory.
|
||||
if (referencing_script_or_module.has<Empty>()) {
|
||||
referencing_script_or_module = get_active_script_or_module();
|
||||
|
||||
// If there is no ScriptOrModule in any of the execution contexts
|
||||
if (referencing_script_or_module.has<Empty>()) {
|
||||
// Throw an error for now
|
||||
promise->reject(InternalError::create(realm, TRY_OR_THROW_OOM(*this, String::formatted(ErrorType::ModuleNotFoundNoReferencingScript.message(), module_request.module_specifier))));
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// Note: If host_resolve_imported_module returns a module it has been loaded successfully and the next call in finish_dynamic_import will retrieve it again.
|
||||
auto module_or_error = host_resolve_imported_module(referencing_script_or_module, module_request);
|
||||
auto module_or_error = host_resolve_imported_module(referrer, module_request);
|
||||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] HostImportModuleDynamically(..., {}) -> {}", module_request.module_specifier, module_or_error.is_error() ? "failed" : "passed");
|
||||
if (module_or_error.is_throw_completion()) {
|
||||
promise->reject(*module_or_error.throw_completion().value());
|
||||
|
@ -1039,19 +1033,19 @@ ThrowCompletionOr<void> VM::import_module_dynamically(ScriptOrModule referencing
|
|||
}
|
||||
|
||||
// 16.2.1.9 FinishDynamicImport ( referencingScriptOrModule, specifier, promiseCapability, innerPromise ), https://tc39.es/ecma262/#sec-finishdynamicimport
|
||||
void VM::finish_dynamic_import(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability const& promise_capability, Promise* inner_promise)
|
||||
void VM::finish_dynamic_import(ImportedModuleReferrer referrer, ModuleRequest module_request, PromiseCapability const& promise_capability, Promise* inner_promise)
|
||||
{
|
||||
dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] finish_dynamic_import on {}", module_request.module_specifier);
|
||||
|
||||
auto& realm = *current_realm();
|
||||
|
||||
// 1. Let fulfilledClosure be a new Abstract Closure with parameters (result) that captures referencingScriptOrModule, specifier, and promiseCapability and performs the following steps when called:
|
||||
auto fulfilled_closure = [referencing_script_or_module = move(referencing_script_or_module), module_request = move(module_request), &promise_capability](VM& vm) -> ThrowCompletionOr<Value> {
|
||||
auto fulfilled_closure = [referrer = move(referrer), module_request = move(module_request), &promise_capability](VM& vm) -> ThrowCompletionOr<Value> {
|
||||
auto result = vm.argument(0);
|
||||
// a. Assert: result is undefined.
|
||||
VERIFY(result.is_undefined());
|
||||
// b. Let moduleRecord be ! HostResolveImportedModule(referencingScriptOrModule, specifier).
|
||||
auto module_record = MUST(vm.host_resolve_imported_module(referencing_script_or_module, module_request));
|
||||
auto module_record = MUST(vm.host_resolve_imported_module(referrer, module_request));
|
||||
|
||||
// c. Assert: Evaluate has already been invoked on moduleRecord and successfully completed.
|
||||
// Note: If HostResolveImportedModule returns a module evaluate will have been called on it.
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <LibJS/CyclicModule.h>
|
||||
#include <LibJS/Heap/Heap.h>
|
||||
#include <LibJS/Heap/MarkedVector.h>
|
||||
#include <LibJS/ModuleLoading.h>
|
||||
#include <LibJS/Runtime/CommonPropertyNames.h>
|
||||
#include <LibJS/Runtime/Completion.h>
|
||||
#include <LibJS/Runtime/Error.h>
|
||||
|
@ -230,14 +231,14 @@ public:
|
|||
// 16.2.1.8 HostLoadImportedModule ( referrer, moduleRequest, hostDefined, payload ), https://tc39.es/proposal-import-attributes/#sec-HostLoadImportedModule
|
||||
Function<void(Realm&, Variant<NonnullGCPtr<Script>, NonnullGCPtr<CyclicModule>>, ModuleRequest const&, GCPtr<GraphLoadingState::HostDefined>, GraphLoadingState&)> host_load_imported_module;
|
||||
|
||||
Function<ThrowCompletionOr<NonnullGCPtr<Module>>(ScriptOrModule, ModuleRequest const&)> host_resolve_imported_module;
|
||||
Function<ThrowCompletionOr<void>(ScriptOrModule, ModuleRequest, PromiseCapability const&)> host_import_module_dynamically;
|
||||
Function<void(ScriptOrModule, ModuleRequest const&, PromiseCapability const&, Promise*)> host_finish_dynamic_import;
|
||||
Function<ThrowCompletionOr<NonnullGCPtr<Module>>(ImportedModuleReferrer, ModuleRequest const&)> host_resolve_imported_module;
|
||||
Function<ThrowCompletionOr<void>(ImportedModuleReferrer, ModuleRequest, PromiseCapability const&)> host_import_module_dynamically;
|
||||
Function<void(ImportedModuleReferrer, ModuleRequest const&, PromiseCapability const&, Promise*)> host_finish_dynamic_import;
|
||||
|
||||
Function<HashMap<PropertyKey, Value>(SourceTextModule&)> host_get_import_meta_properties;
|
||||
Function<void(Object*, SourceTextModule const&)> host_finalize_import_meta;
|
||||
|
||||
Function<Vector<DeprecatedString>()> host_get_supported_import_assertions;
|
||||
Function<Vector<DeprecatedString>()> host_get_supported_import_attributes;
|
||||
|
||||
void enable_default_host_import_module_dynamically_hook();
|
||||
|
||||
|
@ -270,11 +271,11 @@ private:
|
|||
ThrowCompletionOr<void> property_binding_initialization(BindingPattern const& binding, Value value, Environment* environment);
|
||||
ThrowCompletionOr<void> iterator_binding_initialization(BindingPattern const& binding, IteratorRecord& iterator_record, Environment* environment);
|
||||
|
||||
ThrowCompletionOr<NonnullGCPtr<Module>> resolve_imported_module(ScriptOrModule referencing_script_or_module, ModuleRequest const& module_request);
|
||||
ThrowCompletionOr<NonnullGCPtr<Module>> resolve_imported_module(ImportedModuleReferrer, ModuleRequest const& module_request);
|
||||
ThrowCompletionOr<void> link_and_eval_module(Module& module);
|
||||
|
||||
ThrowCompletionOr<void> import_module_dynamically(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability const& promise_capability);
|
||||
void finish_dynamic_import(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability const& promise_capability, Promise* inner_promise);
|
||||
ThrowCompletionOr<void> import_module_dynamically(ImportedModuleReferrer, ModuleRequest module_request, PromiseCapability const& promise_capability);
|
||||
void finish_dynamic_import(ImportedModuleReferrer, ModuleRequest module_request, PromiseCapability const& promise_capability, Promise* inner_promise);
|
||||
|
||||
void set_well_known_symbols(WellKnownSymbols well_known_symbols) { m_well_known_symbols = move(well_known_symbols); }
|
||||
|
||||
|
@ -303,14 +304,14 @@ private:
|
|||
ErrorMessages m_error_messages;
|
||||
|
||||
struct StoredModule {
|
||||
ScriptOrModule referencing_script_or_module;
|
||||
ImportedModuleReferrer referrer;
|
||||
DeprecatedString filename;
|
||||
DeprecatedString type;
|
||||
Handle<Module> module;
|
||||
bool has_once_started_linking { false };
|
||||
};
|
||||
|
||||
StoredModule* get_stored_module(ScriptOrModule const& script_or_module, DeprecatedString const& filename, DeprecatedString const& type);
|
||||
StoredModule* get_stored_module(ImportedModuleReferrer const& script_or_module, DeprecatedString const& filename, DeprecatedString const& type);
|
||||
|
||||
Vector<StoredModule> m_loaded_modules;
|
||||
|
||||
|
|
|
@ -18,35 +18,32 @@ namespace JS {
|
|||
|
||||
JS_DEFINE_ALLOCATOR(SourceTextModule);
|
||||
|
||||
// 2.7 Static Semantics: AssertClauseToAssertions, https://tc39.es/proposal-import-assertions/#sec-assert-clause-to-assertions
|
||||
static Vector<ModuleRequest::Assertion> assert_clause_to_assertions(Vector<ModuleRequest::Assertion> const& source_assertions, Vector<DeprecatedString> const& supported_import_assertions)
|
||||
// 16.2.2.2 Static Semantics: WithClauseToAttributes, https://tc39.es/proposal-import-attributes/#sec-with-clause-to-attributes
|
||||
static Vector<ImportAttribute> with_clause_to_assertions(Vector<ImportAttribute> const& source_attributes)
|
||||
{
|
||||
// AssertClause : assert { AssertEntries ,opt }
|
||||
// 1. Let assertions be AssertClauseToAssertions of AssertEntries.
|
||||
Vector<ModuleRequest::Assertion> assertions;
|
||||
// WithClause : AttributesKeyword { WithEntries , opt }
|
||||
// 1. Let attributes be WithClauseToAttributes of WithEntries.
|
||||
Vector<ImportAttribute> attributes;
|
||||
|
||||
// AssertEntries : AssertionKey : StringLiteral
|
||||
// AssertEntries : AssertionKey : StringLiteral , AssertEntries
|
||||
// 1. Let supportedAssertions be !HostGetSupportedImportAssertions().
|
||||
// AssertEntries : AssertionKey : StringLiteral , WithEntries
|
||||
|
||||
for (auto& assertion : source_assertions) {
|
||||
// 2. Let key be StringValue of AssertionKey.
|
||||
// 3. If supportedAssertions contains key,
|
||||
if (supported_import_assertions.contains_slow(assertion.key)) {
|
||||
// a. Let entry be a Record { [[Key]]: key, [[Value]]: StringValue of StringLiteral }.
|
||||
assertions.empend(assertion);
|
||||
}
|
||||
for (auto const& attribute : source_attributes) {
|
||||
// 1. Let key be the PropName of AttributeKey.
|
||||
// 2. Let entry be the ImportAttribute Record { [[Key]]: key, [[Value]]: SV of StringLiteral }.
|
||||
// 3. Return « entry ».
|
||||
attributes.empend(attribute);
|
||||
}
|
||||
|
||||
// 2. Sort assertions by the code point order of the [[Key]] of each element. NOTE: This sorting is observable only in that hosts are prohibited from distinguishing among assertions by the order they occur in.
|
||||
// 2. Sort attributes according to the lexicographic order of their [[Key]] fields, treating the value of each such field as a sequence of UTF-16 code unit values. NOTE: This sorting is observable only in that hosts are prohibited from distinguishing among attributes by the order they occur in.
|
||||
// Note: The sorting is done in construction of the ModuleRequest object.
|
||||
|
||||
// 3. Return assertions.
|
||||
return assertions;
|
||||
// 3. Return attributes.
|
||||
return attributes;
|
||||
}
|
||||
|
||||
// 16.2.1.3 Static Semantics: ModuleRequests, https://tc39.es/ecma262/#sec-static-semantics-modulerequests
|
||||
static Vector<ModuleRequest> module_requests(Program& program, Vector<DeprecatedString> const& supported_import_assertions)
|
||||
static Vector<ModuleRequest> module_requests(Program& program)
|
||||
{
|
||||
// A List of all the ModuleSpecifier strings used by the module represented by this record to request the importation of a module.
|
||||
// Note: The List is source text occurrence ordered!
|
||||
|
@ -68,7 +65,7 @@ static Vector<ModuleRequest> module_requests(Program& program, Vector<Deprecated
|
|||
}
|
||||
}
|
||||
|
||||
// Note: The List is source code occurrence ordered. https://tc39.es/proposal-import-assertions/#table-cyclic-module-fields
|
||||
// Note: The List is source code occurrence ordered. https://tc39.es/proposal-import-attributes/#table-cyclic-module-fields
|
||||
quick_sort(requested_modules_with_indices, [&](RequestedModuleAndSourceIndex const& lhs, RequestedModuleAndSourceIndex const& rhs) {
|
||||
return lhs.source_offset < rhs.source_offset;
|
||||
});
|
||||
|
@ -76,26 +73,26 @@ static Vector<ModuleRequest> module_requests(Program& program, Vector<Deprecated
|
|||
Vector<ModuleRequest> requested_modules_in_source_order;
|
||||
requested_modules_in_source_order.ensure_capacity(requested_modules_with_indices.size());
|
||||
for (auto& module : requested_modules_with_indices) {
|
||||
// 2.10 Static Semantics: ModuleRequests https://tc39.es/proposal-import-assertions/#sec-static-semantics-modulerequests
|
||||
if (module.module_request->assertions.is_empty()) {
|
||||
// 16.2.1.3 Static Semantics: ModuleRequests, https://tc39.es/proposal-import-attributes/#sec-static-semantics-modulerequests
|
||||
if (module.module_request->attributes.is_empty()) {
|
||||
// ExportDeclaration : export ExportFromClause FromClause ;
|
||||
// ImportDeclaration : import ImportClause FromClause ;
|
||||
|
||||
// 1. Let specifier be StringValue of the StringLiteral contained in FromClause.
|
||||
// 2. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: an empty List }.
|
||||
// 2. Let specifier be SV of FromClause.
|
||||
// 3. Return a List whose sole element is the ModuleRequest Record { [[Specifer]]: specifier, [[Attributes]]: « » }.
|
||||
requested_modules_in_source_order.empend(module.module_request->module_specifier);
|
||||
} else {
|
||||
// ExportDeclaration : export ExportFromClause FromClause AssertClause ;
|
||||
// ImportDeclaration : import ImportClause FromClause AssertClause ;
|
||||
// ExportDeclaration : export ExportFromClause FromClause WithClause ;
|
||||
// ImportDeclaration : import ImportClause FromClause WithClause ;
|
||||
|
||||
// 1. Let specifier be StringValue of the StringLiteral contained in FromClause.
|
||||
// 2. Let assertions be AssertClauseToAssertions of AssertClause.
|
||||
auto assertions = assert_clause_to_assertions(module.module_request->assertions, supported_import_assertions);
|
||||
// Note: We have to modify the assertions in place because else it might keep non supported ones
|
||||
const_cast<ModuleRequest*>(module.module_request)->assertions = move(assertions);
|
||||
// 1. Let specifier be the SV of FromClause.
|
||||
// 2. Let attributes be WithClauseToAttributes of WithClause.
|
||||
auto attributes = with_clause_to_assertions(module.module_request->attributes);
|
||||
// NOTE: We have to modify the attributes in place because else it might keep unsupported ones.
|
||||
const_cast<ModuleRequest*>(module.module_request)->attributes = move(attributes);
|
||||
|
||||
// 3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: assertions }.
|
||||
requested_modules_in_source_order.empend(module.module_request->module_specifier, module.module_request->assertions);
|
||||
// 3. Return a List whose sole element is the ModuleRequest Record { [[Specifer]]: specifier, [[Attributes]]: attributes }.
|
||||
requested_modules_in_source_order.empend(module.module_request->module_specifier, module.module_request->attributes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,12 +131,8 @@ Result<NonnullGCPtr<SourceTextModule>, Vector<ParserError>> SourceTextModule::pa
|
|||
if (parser.has_errors())
|
||||
return parser.errors();
|
||||
|
||||
// Needed for 2.7 Static Semantics: AssertClauseToAssertions, https://tc39.es/proposal-import-assertions/#sec-assert-clause-to-assertions
|
||||
// 1. Let supportedAssertions be !HostGetSupportedImportAssertions().
|
||||
auto supported_assertions = realm.vm().host_get_supported_import_assertions();
|
||||
|
||||
// 3. Let requestedModules be the ModuleRequests of body.
|
||||
auto requested_modules = module_requests(*body, supported_assertions);
|
||||
auto requested_modules = module_requests(*body);
|
||||
|
||||
// 4. Let importEntries be ImportEntries of body.
|
||||
Vector<ImportEntry> import_entries;
|
||||
|
|
|
@ -397,8 +397,8 @@ ErrorOr<void> initialize_main_thread_vm()
|
|||
// FIXME: Implement 8.1.5.5.2 HostImportModuleDynamically(referencingScriptOrModule, moduleRequest, promiseCapability), https://html.spec.whatwg.org/multipage/webappapis.html#hostimportmoduledynamically(referencingscriptormodule,-modulerequest,-promisecapability)
|
||||
// FIXME: Implement 8.1.5.5.3 HostResolveImportedModule(referencingScriptOrModule, moduleRequest), https://html.spec.whatwg.org/multipage/webappapis.html#hostresolveimportedmodule(referencingscriptormodule,-modulerequest)
|
||||
|
||||
// 8.1.5.5.4 HostGetSupportedImportAssertions(), https://html.spec.whatwg.org/multipage/webappapis.html#hostgetsupportedimportassertions
|
||||
s_main_thread_vm->host_get_supported_import_assertions = []() -> Vector<DeprecatedString> {
|
||||
// 8.1.6.5.2 HostGetSupportedImportAttributes(), https://html.spec.whatwg.org/multipage/webappapis.html#hostgetsupportedimportassertions
|
||||
s_main_thread_vm->host_get_supported_import_attributes = []() -> Vector<DeprecatedString> {
|
||||
// 1. Return « "type" ».
|
||||
return { "type"sv };
|
||||
};
|
||||
|
@ -515,15 +515,14 @@ ErrorOr<void> initialize_main_thread_vm()
|
|||
};
|
||||
|
||||
// 8.1.6.5.3 HostResolveImportedModule(referencingScriptOrModule, moduleRequest), https://html.spec.whatwg.org/multipage/webappapis.html#hostresolveimportedmodule(referencingscriptormodule,-modulerequest)
|
||||
s_main_thread_vm->host_resolve_imported_module = [](JS::ScriptOrModule const& referencing_string_or_module, JS::ModuleRequest const& module_request) -> JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Module>> {
|
||||
s_main_thread_vm->host_resolve_imported_module = [](JS::ImportedModuleReferrer referrer, JS::ModuleRequest const& module_request) -> JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Module>> {
|
||||
// 1. Let moduleMap and referencingScript be null.
|
||||
Optional<HTML::ModuleMap&> module_map;
|
||||
Optional<HTML::Script&> referencing_script;
|
||||
|
||||
// 2. If referencingScriptOrModule is not null, then:
|
||||
if (!referencing_string_or_module.has<Empty>()) {
|
||||
if (referrer.has<JS::NonnullGCPtr<JS::Script>>() || referrer.has<JS::NonnullGCPtr<JS::CyclicModule>>()) {
|
||||
// 1. Set referencingScript to referencingScriptOrModule.[[HostDefined]].
|
||||
referencing_script = verify_cast<HTML::Script>(referencing_string_or_module.has<JS::NonnullGCPtr<JS::Script>>() ? *referencing_string_or_module.get<JS::NonnullGCPtr<JS::Script>>()->host_defined() : *referencing_string_or_module.get<JS::NonnullGCPtr<JS::Module>>()->host_defined());
|
||||
referencing_script = verify_cast<HTML::Script>(referrer.has<JS::NonnullGCPtr<JS::Script>>() ? *referrer.get<JS::NonnullGCPtr<JS::Script>>()->host_defined() : *referrer.get<JS::NonnullGCPtr<JS::CyclicModule>>()->host_defined());
|
||||
|
||||
// 2. Set moduleMap to referencingScript's settings object's module map.
|
||||
module_map = referencing_script->settings_object().module_map();
|
||||
|
|
|
@ -59,8 +59,8 @@ DeprecatedString module_type_from_module_request(JS::ModuleRequest const& module
|
|||
// 1. Let moduleType be "javascript".
|
||||
DeprecatedString module_type = "javascript"sv;
|
||||
|
||||
// 2. If moduleRequest.[[Assertions]] has a Record entry such that entry.[[Key]] is "type", then:
|
||||
for (auto const& entry : module_request.assertions) {
|
||||
// 2. If moduleRequest.[[Attributes]] has a Record entry such that entry.[[Key]] is "type", then:
|
||||
for (auto const& entry : module_request.attributes) {
|
||||
if (entry.key != "type"sv)
|
||||
continue;
|
||||
|
||||
|
@ -719,7 +719,7 @@ void fetch_single_imported_module_script(JS::Realm& realm,
|
|||
{
|
||||
// 1. Assert: moduleRequest.[[Attributes]] does not contain any Record entry such that entry.[[Key]] is not "type",
|
||||
// because we only asked for "type" attributes in HostGetSupportedImportAttributes.
|
||||
for (auto const& entry : module_request.assertions)
|
||||
for (auto const& entry : module_request.attributes)
|
||||
VERIFY(entry.key == "type"sv);
|
||||
|
||||
// 2. Let moduleType be the result of running the module type from module request steps given moduleRequest.
|
||||
|
|
|
@ -68,17 +68,27 @@ WebIDL::ExceptionOr<JS::GCPtr<JavaScriptModuleScript>> JavaScriptModuleScript::c
|
|||
return script;
|
||||
}
|
||||
|
||||
// 10. For each ModuleRequest record requested of result.[[RequestedModules]]:
|
||||
// 9. For each ModuleRequest record requested of result.[[RequestedModules]]:
|
||||
for (auto const& requested : result.value()->requested_modules()) {
|
||||
// FIXME: Clarify if this should be checked for all requested before running the steps below.
|
||||
// 9. Assert: requested.[[Assertions]] does not contain any Record entry such that entry.[[Key]] is not "type",
|
||||
// because we only asked for "type" assertions in HostGetSupportedImportAssertions.
|
||||
VERIFY(all_of(requested.assertions, [](auto const& assertion) { return assertion.key == "type"sv; }));
|
||||
// 1. If requested.[[Attributes]] contains a Record entry such that entry.[[Key]] is not "type", then:
|
||||
for (auto const& attribute : requested.attributes) {
|
||||
if (attribute.key != "type"sv) {
|
||||
// 1. Let error be a new SyntaxError exception.
|
||||
auto error = JS::SyntaxError::create(settings_object.realm(), "Module request attributes must only contain a type attribute"_fly_string);
|
||||
|
||||
// 1. Let url be the result of resolving a module specifier given script and requested.[[Specifier]], catching any exceptions.
|
||||
// 2. Set script's parse error to error.
|
||||
script->set_parse_error(error);
|
||||
|
||||
// 3. Return script.
|
||||
return script;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Let url be the result of resolving a module specifier given script and requested.[[Specifier]], catching any exceptions.
|
||||
auto url = resolve_module_specifier(*script, requested.module_specifier);
|
||||
|
||||
// 2. If the previous step threw an exception, then:
|
||||
// 3. If the previous step threw an exception, then:
|
||||
if (url.is_exception()) {
|
||||
// FIXME: 1. Set script's parse error to that exception.
|
||||
|
||||
|
@ -86,10 +96,10 @@ WebIDL::ExceptionOr<JS::GCPtr<JavaScriptModuleScript>> JavaScriptModuleScript::c
|
|||
return script;
|
||||
}
|
||||
|
||||
// 3. Let moduleType be the result of running the module type from module request steps given requested.
|
||||
// 4. Let moduleType be the result of running the module type from module request steps given requested.
|
||||
auto module_type = module_type_from_module_request(requested);
|
||||
|
||||
// 4. If the result of running the module type allowed steps given moduleType and settings is false, then:
|
||||
// 5. If the result of running the module type allowed steps given moduleType and settings is false, then:
|
||||
if (!settings_object.module_type_allowed(module_type)) {
|
||||
// FIXME: 1. Let error be a new TypeError exception.
|
||||
|
||||
|
@ -100,10 +110,10 @@ WebIDL::ExceptionOr<JS::GCPtr<JavaScriptModuleScript>> JavaScriptModuleScript::c
|
|||
}
|
||||
}
|
||||
|
||||
// 11. Set script's record to result.
|
||||
// 10. Set script's record to result.
|
||||
script->m_record = result.value();
|
||||
|
||||
// 12. Return script.
|
||||
// 11. Return script.
|
||||
return script;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue