mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 14:42:44 +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) | static void dump_assert_clauses(ModuleRequest const& request) | ||||||
| { | { | ||||||
|     if (!request.assertions.is_empty()) { |     if (!request.attributes.is_empty()) { | ||||||
|         out("[ "); |         out("[ "); | ||||||
|         for (auto& assertion : request.assertions) |         for (auto& assertion : request.attributes) | ||||||
|             out("{}: {}, ", assertion.key, assertion.value); |             out("{}: {}, ", assertion.key, assertion.value); | ||||||
|         out(" ]"); |         out(" ]"); | ||||||
|     } |     } | ||||||
|  | @ -1882,15 +1882,15 @@ ThrowCompletionOr<void> Program::global_declaration_instantiation(VM& vm, Global | ||||||
|     return {}; |     return {}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ModuleRequest::ModuleRequest(DeprecatedFlyString module_specifier_, Vector<Assertion> assertions_) | ModuleRequest::ModuleRequest(DeprecatedFlyString module_specifier_, Vector<ImportAttribute> attributes) | ||||||
|     : module_specifier(move(module_specifier_)) |     : 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
 |     // Perform step 10.e. from EvaluateImportCall, https://tc39.es/proposal-import-attributes/#sec-evaluate-import-call
 | ||||||
|     // or step 2. from 2.7 Static Semantics: AssertClauseToAssertions, https://tc39.es/proposal-import-assertions/#sec-assert-clause-to-assertions
 |     // 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.
 |     // 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.
 |     // 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; |         return lhs.key < rhs.key; | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -162,6 +162,7 @@ class ClassExpression; | ||||||
| struct ClassFieldDefinition; | struct ClassFieldDefinition; | ||||||
| class Completion; | class Completion; | ||||||
| class Console; | class Console; | ||||||
|  | class CyclicModule; | ||||||
| class DeclarativeEnvironment; | class DeclarativeEnvironment; | ||||||
| class DeferGC; | class DeferGC; | ||||||
| class ECMAScriptFunctionObject; | class ECMAScriptFunctionObject; | ||||||
|  | @ -178,6 +179,7 @@ class FunctionNode; | ||||||
| struct FunctionParameter; | struct FunctionParameter; | ||||||
| class GlobalEnvironment; | class GlobalEnvironment; | ||||||
| class GlobalObject; | class GlobalObject; | ||||||
|  | struct GraphLoadingState; | ||||||
| class HandleImpl; | class HandleImpl; | ||||||
| class Heap; | class Heap; | ||||||
| class HeapBlock; | 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]:
 |     //  ImportCall[Yield, Await]:
 | ||||||
|     //      import(AssignmentExpression[+In, ?Yield, ?Await] ,opt)
 |     //      import(AssignmentExpression[+In, ?Yield, ?Await] ,opt)
 | ||||||
|     //      import(AssignmentExpression[+In, ?Yield, ?Await] ,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::Import); | ||||||
|     consume(TokenType::ParenOpen); |     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; |     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; |     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() | ModuleRequest Parser::parse_module_request() | ||||||
| { | { | ||||||
|     // Does not include the 'from' since that is not always required.
 |     // 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() }; |     ModuleRequest request { consume_string_value() }; | ||||||
| 
 | 
 | ||||||
|     if (!match_assert_clause()) |     if (!match_with_clause()) | ||||||
|         return request; |         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::Identifier); | ||||||
|     consume(TokenType::CurlyOpen); |     consume(TokenType::CurlyOpen); | ||||||
| 
 | 
 | ||||||
|  | @ -4522,18 +4524,18 @@ ModuleRequest Parser::parse_module_request() | ||||||
|         } else if (match_identifier_name()) { |         } else if (match_identifier_name()) { | ||||||
|             key = consume().value(); |             key = consume().value(); | ||||||
|         } else { |         } else { | ||||||
|             expected("IdentifierName or StringValue as AssertionKey"); |             expected("IdentifierName or StringValue as WithKey"); | ||||||
|             consume(); |             consume(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         consume(TokenType::Colon); |         consume(TokenType::Colon); | ||||||
| 
 | 
 | ||||||
|         if (match(TokenType::StringLiteral)) { |         if (match(TokenType::StringLiteral)) { | ||||||
|             for (auto& entries : request.assertions) { |             for (auto& entries : request.attributes) { | ||||||
|                 if (entries.key == key) |                 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); |         consume(TokenType::StringLiteral); | ||||||
| 
 | 
 | ||||||
|  | @ -4554,9 +4556,9 @@ NonnullRefPtr<ImportStatement const> Parser::parse_import_statement(Program& pro | ||||||
| { | { | ||||||
|     // We use the extended syntax which adds:
 |     // We use the extended syntax which adds:
 | ||||||
|     //  ImportDeclaration:
 |     //  ImportDeclaration:
 | ||||||
|     //      import ImportClause FromClause [no LineTerminator here] AssertClause;
 |     //      import ImportClause FromClause [no LineTerminator here] WithClause;
 | ||||||
|     //      import ModuleSpecifier [no LineTerminator here] AssertClause;
 |     //      import ModuleSpecifier [no LineTerminator here] WithClause;
 | ||||||
|     // From:  https://tc39.es/proposal-import-assertions/#prod-ImportDeclaration
 |     // From:  https://tc39.es/proposal-import-attributes/#prod-ImportDeclaration
 | ||||||
| 
 | 
 | ||||||
|     auto rule_start = push_start(); |     auto rule_start = push_start(); | ||||||
|     if (program.type() != Program::Type::Module) |     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:
 |     // We use the extended syntax which adds:
 | ||||||
|     //  ExportDeclaration:
 |     //  ExportDeclaration:
 | ||||||
|     //      export ExportFromClause FromClause [no LineTerminator here] AssertClause ;
 |     //      export ExportFromClause FromClause [no LineTerminator here] WithClause ;
 | ||||||
|     // From:  https://tc39.es/proposal-import-assertions/#prod-ExportDeclaration
 |     // From:  https://tc39.es/proposal-import-attributes/#sec-exports
 | ||||||
| 
 | 
 | ||||||
|     auto rule_start = push_start(); |     auto rule_start = push_start(); | ||||||
|     if (program.type() != Program::Type::Module) |     if (program.type() != Program::Type::Module) | ||||||
|  |  | ||||||
|  | @ -225,7 +225,7 @@ private: | ||||||
|     bool match_secondary_expression(ForbiddenTokens forbidden = {}) const; |     bool match_secondary_expression(ForbiddenTokens forbidden = {}) const; | ||||||
|     bool match_statement() const; |     bool match_statement() const; | ||||||
|     bool match_export_or_import() const; |     bool match_export_or_import() const; | ||||||
|     bool match_assert_clause() const; |     bool match_with_clause() const; | ||||||
| 
 | 
 | ||||||
|     enum class AllowUsingDeclaration { |     enum class AllowUsingDeclaration { | ||||||
|         No, |         No, | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ | ||||||
| #include <AK/Optional.h> | #include <AK/Optional.h> | ||||||
| #include <AK/Utf16View.h> | #include <AK/Utf16View.h> | ||||||
| #include <LibJS/Bytecode/Interpreter.h> | #include <LibJS/Bytecode/Interpreter.h> | ||||||
|  | #include <LibJS/ModuleLoading.h> | ||||||
| #include <LibJS/Parser.h> | #include <LibJS/Parser.h> | ||||||
| #include <LibJS/Runtime/AbstractOperations.h> | #include <LibJS/Runtime/AbstractOperations.h> | ||||||
| #include <LibJS/Runtime/Accessor.h> | #include <LibJS/Runtime/Accessor.h> | ||||||
|  | @ -1459,25 +1460,53 @@ Completion dispose_resources(VM& vm, GCPtr<DeclarativeEnvironment> disposable, C | ||||||
|     return completion; |     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) | ThrowCompletionOr<Value> perform_import_call(VM& vm, Value specifier, Value options_value) | ||||||
| { | { | ||||||
|     auto& realm = *vm.current_realm(); |     auto& realm = *vm.current_realm(); | ||||||
| 
 | 
 | ||||||
|     // 2.1.1.1 EvaluateImportCall ( specifierExpression [ , optionsExpression ] ), https://tc39.es/proposal-import-assertions/#sec-evaluate-import-call
 |     // 13.3.10.2 EvaluateImportCall ( specifierExpression [ , optionsExpression ] ), https://tc39.es/proposal-import-attributes/#sec-evaluate-import-call
 | ||||||
|     //  1. Let referencingScriptOrModule be GetActiveScriptOrModule().
 |     // 1. Let referrer be GetActiveScriptOrModule().
 | ||||||
|     auto referencing_script_or_module = vm.get_active_script_or_module(); |     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())); |     auto promise_capability = MUST(new_promise_capability(vm, realm.intrinsics().promise_constructor())); | ||||||
| 
 | 
 | ||||||
|     // 7. Let specifierString be Completion(ToString(specifier)).
 |     // 8. Let specifierString be Completion(ToString(specifier)).
 | ||||||
|     // 8. IfAbruptRejectPromise(specifierString, promiseCapability).
 |     // 9. IfAbruptRejectPromise(specifierString, promiseCapability).
 | ||||||
|     auto specifier_string = TRY_OR_REJECT_WITH_VALUE(vm, promise_capability, specifier.to_deprecated_string(vm)); |     auto specifier_string = TRY_OR_REJECT_WITH_VALUE(vm, promise_capability, specifier.to_deprecated_string(vm)); | ||||||
| 
 | 
 | ||||||
|     // 9. Let assertions be a new empty List.
 |     // 10. Let attributes be a new empty List.
 | ||||||
|     Vector<ModuleRequest::Assertion> assertions; |     Vector<ImportAttribute> attributes; | ||||||
| 
 | 
 | ||||||
|     // 10. If options is not undefined, then
 |     // 11. If options is not undefined, then
 | ||||||
|     if (!options_value.is_undefined()) { |     if (!options_value.is_undefined()) { | ||||||
|         // a. If Type(options) is not Object,
 |         // a. If Type(options) is not Object,
 | ||||||
|         if (!options_value.is_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() }; |             return Value { promise_capability->promise() }; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // b. Let assertionsObj be Get(options, "assert").
 |         // b. Let attributesObj be Completion(Get(options, "with")).
 | ||||||
|         // c. IfAbruptRejectPromise(assertionsObj, promiseCapability).
 |         // c. IfAbruptRejectPromise(attributesObj, promiseCapability).
 | ||||||
|         auto assertion_object = TRY_OR_REJECT_WITH_VALUE(vm, promise_capability, options_value.get(vm, vm.names.assert)); |         auto attributes_obj = TRY_OR_REJECT_WITH_VALUE(vm, promise_capability, options_value.get(vm, vm.names.with)); | ||||||
| 
 | 
 | ||||||
|         // d. If assertionsObj is not undefined,
 |         // d. Normative Optional, Deprecated
 | ||||||
|         if (!assertion_object.is_undefined()) { |         // 11. If the host supports the deprecated assert keyword for import attributes and attributesObj is undefined, then
 | ||||||
|             // i. If Type(assertionsObj) is not Object,
 |         if (attributes_obj.is_undefined()) { | ||||||
|             if (!assertion_object.is_object()) { |             // 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"))); |                 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 »).
 |                 // 1. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
 | ||||||
|                 MUST(call(vm, *promise_capability->reject(), js_undefined(), error)); |                 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() }; |                 return Value { promise_capability->promise() }; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // ii. Let keys be EnumerableOwnPropertyNames(assertionsObj, key).
 |             // ii. Let entries be Completion(EnumerableOwnProperties(attributesObj, key+value)).
 | ||||||
|             // iii. IfAbruptRejectPromise(keys, promiseCapability).
 |             // iii. IfAbruptRejectPromise(entries, promiseCapability).
 | ||||||
|             auto keys = TRY_OR_REJECT_WITH_VALUE(vm, promise_capability, assertion_object.as_object().enumerable_own_property_names(Object::PropertyKind::Key)); |             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().
 |             // iv. For each entry of entries, do
 | ||||||
|             auto supported_assertions = vm.host_get_supported_import_assertions(); |             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,
 |                 // 2. Let value be ! Get(entry, "1").
 | ||||||
|             for (auto const& key : keys) { |                 auto value = MUST(entry.get(vm, PropertyKey(1))); | ||||||
|                 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)); |  | ||||||
| 
 | 
 | ||||||
|                 // 3. If Type(value) is not String, then
 |                 // 3. If Type(value) is not String, then
 | ||||||
|                 if (!value.is_string()) { |                 if (!value.is_string()) { | ||||||
|  | @ -1530,22 +1564,33 @@ ThrowCompletionOr<Value> perform_import_call(VM& vm, Value specifier, Value opti | ||||||
|                     return Value { promise_capability->promise() }; |                     return Value { promise_capability->promise() }; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 // 4. If supportedAssertions contains key, then
 |                 // 4. Append the ImportAttribute Record { [[Key]]: key, [[Value]]: value } to attributes.
 | ||||||
|                 if (supported_assertions.contains_slow(property_key.to_string())) { |                 attributes.empend(key.as_string().deprecated_string(), value.as_string().deprecated_string()); | ||||||
|                     // a. Append { [[Key]]: key, [[Value]]: value } to assertions.
 |  | ||||||
|                     assertions.empend(property_key.to_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 }.
 |     // 12. Let moduleRequest be a new ModuleRequest Record { [[Specifier]]: specifierString, [[Attributes]]: attributes }.
 | ||||||
|     ModuleRequest request { specifier_string, assertions }; |     ModuleRequest request { specifier_string, attributes }; | ||||||
| 
 | 
 | ||||||
|     // 12. Perform HostImportModuleDynamically(referencingScriptOrModule, moduleRequest, promiseCapability).
 |     // 13. Perform HostLoadImportedModule(referrer, moduleRequest, empty, promiseCapability).
 | ||||||
|     MUST_OR_THROW_OOM(vm.host_import_module_dynamically(referencing_script_or_module, move(request), promise_capability)); |     MUST_OR_THROW_OOM(vm.host_import_module_dynamically(referrer, move(request), promise_capability)); | ||||||
| 
 | 
 | ||||||
|     // 13. Return promiseCapability.[[Promise]].
 |     // 13. Return promiseCapability.[[Promise]].
 | ||||||
|     return Value { promise_capability->promise() }; |     return Value { promise_capability->promise() }; | ||||||
|  |  | ||||||
|  | @ -18,13 +18,14 @@ struct ModuleWithSpecifier { | ||||||
|     NonnullGCPtr<Module> module; // [[Module]]
 |     NonnullGCPtr<Module> module; // [[Module]]
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // 2.9 ModuleRequest Records, https://tc39.es/proposal-import-assertions/#sec-modulerequest-record
 | // https://tc39.es/proposal-import-attributes/#importattribute-record
 | ||||||
| struct ModuleRequest { | struct ImportAttribute { | ||||||
|     struct Assertion { |     DeprecatedString key; | ||||||
|         DeprecatedString key; |     DeprecatedString value; | ||||||
|         DeprecatedString value; | }; | ||||||
|     }; |  | ||||||
| 
 | 
 | ||||||
|  | // https://tc39.es/proposal-import-attributes/#modulerequest-record
 | ||||||
|  | struct ModuleRequest { | ||||||
|     ModuleRequest() = default; |     ModuleRequest() = default; | ||||||
| 
 | 
 | ||||||
|     explicit ModuleRequest(DeprecatedFlyString specifier) |     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]]
 |     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.
 |     // 5. Push evalContext onto the execution context stack; evalContext is now the running execution context.
 | ||||||
|     TRY(vm.push_execution_context(eval_context, {})); |     TRY(vm.push_execution_context(eval_context, {})); | ||||||
| 
 | 
 | ||||||
|     // 6. Perform HostImportModuleDynamically(null, specifierString, innerCapability).
 |     // 6. Let referrer be the Realm component of evalContext.
 | ||||||
|     MUST_OR_THROW_OOM(vm.host_import_module_dynamically(Empty {}, ModuleRequest { move(specifier_string) }, inner_capability)); |     // 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.
 |     // 7. Suspend evalContext and remove it from the execution context stack.
 | ||||||
|     // NOTE: We don't support this concept yet.
 |     // 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); |         return make_job_callback(function_object); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     host_resolve_imported_module = [&](ScriptOrModule referencing_script_or_module, ModuleRequest const& specifier) { |     host_resolve_imported_module = [&](ImportedModuleReferrer referrer, ModuleRequest const& specifier) { | ||||||
|         return resolve_imported_module(move(referencing_script_or_module), 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.
 |         // By default, we throw on dynamic imports this is to prevent arbitrary file access by scripts.
 | ||||||
|         VERIFY(current_realm()); |         VERIFY(current_realm()); | ||||||
|         auto& realm = *current_realm(); |         auto& realm = *current_realm(); | ||||||
|  | @ -127,8 +127,8 @@ VM::VM(OwnPtr<CustomData> custom_data, ErrorMessages error_messages) | ||||||
|         return {}; |         return {}; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     host_finish_dynamic_import = [&](ScriptOrModule referencing_script_or_module, ModuleRequest const& specifier, PromiseCapability const& promise_capability, Promise* promise) { |     host_finish_dynamic_import = [&](ImportedModuleReferrer referrer, ModuleRequest const& specifier, PromiseCapability const& promise_capability, Promise* promise) { | ||||||
|         return finish_dynamic_import(move(referencing_script_or_module), specifier, promise_capability, promise); |         return finish_dynamic_import(referrer, specifier, promise_capability, promise); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     host_get_import_meta_properties = [&](SourceTextModule const&) -> HashMap<PropertyKey, Value> { |     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_finalize_import_meta = [&](Object*, SourceTextModule const&) { | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     host_get_supported_import_assertions = [&] { |     host_get_supported_import_attributes = [&] { | ||||||
|         return Vector<DeprecatedString> { "type" }; |         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() | 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) { |     host_import_module_dynamically = [&](ImportedModuleReferrer referrer, ModuleRequest const& specifier, PromiseCapability const& promise_capability) { | ||||||
|         return import_module_dynamically(move(referencing_script_or_module), specifier, 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; |     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:
 |     // Note the spec says:
 | ||||||
|     // Each time this operation is called with a specific referencingScriptOrModule, specifier pair as arguments
 |     // 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"); |             dbgln("Warning: Using multiple modules as entry point can lead to unexpected results"); | ||||||
| 
 | 
 | ||||||
|         m_loaded_modules.empend( |         m_loaded_modules.empend( | ||||||
|             NonnullGCPtr(module), |             ImportedModuleReferrer { NonnullGCPtr { verify_cast<CyclicModule>(module) } }, | ||||||
|             module.filename(), |             module.filename(), | ||||||
|             DeprecatedString {}, // Null type
 |             DeprecatedString {}, // Null type
 | ||||||
|             module, |             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
 | // 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:
 |     // 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.
 |     //  - 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.
 |     // 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.
 |     // 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.
 |     DeprecatedString module_type; | ||||||
|     VERIFY(module_request.assertions.is_empty() || (module_request.assertions.size() == 1 && module_request.assertions.first().key == "type")); |     for (auto& attribute : module_request.attributes) { | ||||||
|     auto module_type = module_request.assertions.is_empty() ? DeprecatedString {} : module_request.assertions.first().value; |         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); |     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( |     StringView const base_filename = referrer.visit( | ||||||
|         [&](Empty) { |         [&](NonnullGCPtr<Realm> const&) { | ||||||
|             return "."sv; |             return "."sv; | ||||||
|         }, |         }, | ||||||
|         [&](auto& script_or_module) { |         [&](NonnullGCPtr<Script> const& script) { | ||||||
|             return script_or_module->filename(); |             return script->filename(); | ||||||
|  |         }, | ||||||
|  |         [&](NonnullGCPtr<Module> const& module) { | ||||||
|  |             return module->filename(); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|     LexicalPath base_path { base_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); |     dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] resolved filename: '{}'", filename); | ||||||
| 
 | 
 | ||||||
| #if JS_MODULE_DEBUG | #if JS_MODULE_DEBUG | ||||||
|     DeprecatedString referencing_module_string = referencing_script_or_module.visit( |     DeprecatedString referencing_module_string = referrer.visit( | ||||||
|         [&](Empty) -> DeprecatedString { |         [&](Empty) -> DeprecatedString { | ||||||
|             return "."; |             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); |     dbgln_if(JS_MODULE_DEBUG, "[JS MODULE]     resolved {} + {} -> {}", base_path, module_request.module_specifier, filename); | ||||||
| #endif | #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) { |     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()); |         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); |         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.
 |     // We have to set it here already in case it references itself.
 | ||||||
|     m_loaded_modules.empend( |     m_loaded_modules.empend( | ||||||
|         referencing_script_or_module, |         referrer, | ||||||
|         filename, |         filename, | ||||||
|         module_type, |         module_type, | ||||||
|         *module, |         *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
 | // 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(); |     auto& realm = *current_realm(); | ||||||
| 
 | 
 | ||||||
|  | @ -999,24 +1006,11 @@ ThrowCompletionOr<void> VM::import_module_dynamically(ScriptOrModule referencing | ||||||
|     auto promise = Promise::create(realm); |     auto promise = Promise::create(realm); | ||||||
| 
 | 
 | ||||||
|     ScopeGuard finish_dynamic_import = [&] { |     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.
 |     // 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"); |     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()) { |     if (module_or_error.is_throw_completion()) { | ||||||
|         promise->reject(*module_or_error.throw_completion().value()); |         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
 | // 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); |     dbgln_if(JS_MODULE_DEBUG, "[JS MODULE] finish_dynamic_import on {}", module_request.module_specifier); | ||||||
| 
 | 
 | ||||||
|     auto& realm = *current_realm(); |     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:
 |     // 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); |         auto result = vm.argument(0); | ||||||
|         // a. Assert: result is undefined.
 |         // a. Assert: result is undefined.
 | ||||||
|         VERIFY(result.is_undefined()); |         VERIFY(result.is_undefined()); | ||||||
|         // b. Let moduleRecord be ! HostResolveImportedModule(referencingScriptOrModule, specifier).
 |         // 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.
 |         // 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.
 |         // Note: If HostResolveImportedModule returns a module evaluate will have been called on it.
 | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ | ||||||
| #include <LibJS/CyclicModule.h> | #include <LibJS/CyclicModule.h> | ||||||
| #include <LibJS/Heap/Heap.h> | #include <LibJS/Heap/Heap.h> | ||||||
| #include <LibJS/Heap/MarkedVector.h> | #include <LibJS/Heap/MarkedVector.h> | ||||||
|  | #include <LibJS/ModuleLoading.h> | ||||||
| #include <LibJS/Runtime/CommonPropertyNames.h> | #include <LibJS/Runtime/CommonPropertyNames.h> | ||||||
| #include <LibJS/Runtime/Completion.h> | #include <LibJS/Runtime/Completion.h> | ||||||
| #include <LibJS/Runtime/Error.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
 |     // 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<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<NonnullGCPtr<Module>>(ImportedModuleReferrer, ModuleRequest const&)> host_resolve_imported_module; | ||||||
|     Function<ThrowCompletionOr<void>(ScriptOrModule, ModuleRequest, PromiseCapability const&)> host_import_module_dynamically; |     Function<ThrowCompletionOr<void>(ImportedModuleReferrer, ModuleRequest, PromiseCapability const&)> host_import_module_dynamically; | ||||||
|     Function<void(ScriptOrModule, ModuleRequest const&, PromiseCapability const&, Promise*)> host_finish_dynamic_import; |     Function<void(ImportedModuleReferrer, ModuleRequest const&, PromiseCapability const&, Promise*)> host_finish_dynamic_import; | ||||||
| 
 | 
 | ||||||
|     Function<HashMap<PropertyKey, Value>(SourceTextModule&)> host_get_import_meta_properties; |     Function<HashMap<PropertyKey, Value>(SourceTextModule&)> host_get_import_meta_properties; | ||||||
|     Function<void(Object*, SourceTextModule const&)> host_finalize_import_meta; |     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(); |     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> property_binding_initialization(BindingPattern const& binding, Value value, Environment* environment); | ||||||
|     ThrowCompletionOr<void> iterator_binding_initialization(BindingPattern const& binding, IteratorRecord& iterator_record, 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> link_and_eval_module(Module& module); | ||||||
| 
 | 
 | ||||||
|     ThrowCompletionOr<void> import_module_dynamically(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability const& promise_capability); |     ThrowCompletionOr<void> import_module_dynamically(ImportedModuleReferrer, 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); |     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); } |     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; |     ErrorMessages m_error_messages; | ||||||
| 
 | 
 | ||||||
|     struct StoredModule { |     struct StoredModule { | ||||||
|         ScriptOrModule referencing_script_or_module; |         ImportedModuleReferrer referrer; | ||||||
|         DeprecatedString filename; |         DeprecatedString filename; | ||||||
|         DeprecatedString type; |         DeprecatedString type; | ||||||
|         Handle<Module> module; |         Handle<Module> module; | ||||||
|         bool has_once_started_linking { false }; |         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; |     Vector<StoredModule> m_loaded_modules; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -18,35 +18,32 @@ namespace JS { | ||||||
| 
 | 
 | ||||||
| JS_DEFINE_ALLOCATOR(SourceTextModule); | JS_DEFINE_ALLOCATOR(SourceTextModule); | ||||||
| 
 | 
 | ||||||
| // 2.7 Static Semantics: AssertClauseToAssertions, https://tc39.es/proposal-import-assertions/#sec-assert-clause-to-assertions
 | // 16.2.2.2 Static Semantics: WithClauseToAttributes, https://tc39.es/proposal-import-attributes/#sec-with-clause-to-attributes
 | ||||||
| static Vector<ModuleRequest::Assertion> assert_clause_to_assertions(Vector<ModuleRequest::Assertion> const& source_assertions, Vector<DeprecatedString> const& supported_import_assertions) | static Vector<ImportAttribute> with_clause_to_assertions(Vector<ImportAttribute> const& source_attributes) | ||||||
| { | { | ||||||
|     // AssertClause : assert { AssertEntries ,opt }
 |     // WithClause : AttributesKeyword { WithEntries , opt }
 | ||||||
|     // 1. Let assertions be AssertClauseToAssertions of AssertEntries.
 |     // 1. Let attributes be WithClauseToAttributes of WithEntries.
 | ||||||
|     Vector<ModuleRequest::Assertion> assertions; |     Vector<ImportAttribute> attributes; | ||||||
| 
 | 
 | ||||||
|     // AssertEntries : AssertionKey : StringLiteral
 |     // AssertEntries : AssertionKey : StringLiteral
 | ||||||
|     // AssertEntries : AssertionKey : StringLiteral , AssertEntries
 |     // AssertEntries : AssertionKey : StringLiteral , WithEntries
 | ||||||
|     // 1. Let supportedAssertions be !HostGetSupportedImportAssertions().
 |  | ||||||
| 
 | 
 | ||||||
|     for (auto& assertion : source_assertions) { |     for (auto const& attribute : source_attributes) { | ||||||
|         // 2. Let key be StringValue of AssertionKey.
 |         // 1. Let key be the PropName of AttributeKey.
 | ||||||
|         // 3. If supportedAssertions contains key,
 |         // 2. Let entry be the ImportAttribute Record { [[Key]]: key, [[Value]]: SV of StringLiteral }.
 | ||||||
|         if (supported_import_assertions.contains_slow(assertion.key)) { |         // 3. Return « entry ».
 | ||||||
|             // a. Let entry be a Record { [[Key]]: key, [[Value]]: StringValue of StringLiteral }.
 |         attributes.empend(attribute); | ||||||
|             assertions.empend(assertion); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // 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.
 |     // Note: The sorting is done in construction of the ModuleRequest object.
 | ||||||
| 
 | 
 | ||||||
|     // 3. Return assertions.
 |     // 3. Return attributes.
 | ||||||
|     return assertions; |     return attributes; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // 16.2.1.3 Static Semantics: ModuleRequests, https://tc39.es/ecma262/#sec-static-semantics-modulerequests
 | // 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.
 |     // 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!
 |     // 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) { |     quick_sort(requested_modules_with_indices, [&](RequestedModuleAndSourceIndex const& lhs, RequestedModuleAndSourceIndex const& rhs) { | ||||||
|         return lhs.source_offset < rhs.source_offset; |         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; |     Vector<ModuleRequest> requested_modules_in_source_order; | ||||||
|     requested_modules_in_source_order.ensure_capacity(requested_modules_with_indices.size()); |     requested_modules_in_source_order.ensure_capacity(requested_modules_with_indices.size()); | ||||||
|     for (auto& module : requested_modules_with_indices) { |     for (auto& module : requested_modules_with_indices) { | ||||||
|         // 2.10 Static Semantics: ModuleRequests https://tc39.es/proposal-import-assertions/#sec-static-semantics-modulerequests
 |         // 16.2.1.3 Static Semantics: ModuleRequests, https://tc39.es/proposal-import-attributes/#sec-static-semantics-modulerequests
 | ||||||
|         if (module.module_request->assertions.is_empty()) { |         if (module.module_request->attributes.is_empty()) { | ||||||
|             //  ExportDeclaration : export ExportFromClause FromClause ;
 |             //  ExportDeclaration : export ExportFromClause FromClause ;
 | ||||||
|             //  ImportDeclaration : import ImportClause FromClause ;
 |             //  ImportDeclaration : import ImportClause FromClause ;
 | ||||||
| 
 | 
 | ||||||
|             // 1. Let specifier be StringValue of the StringLiteral contained in FromClause.
 |             // 2. Let specifier be SV of FromClause.
 | ||||||
|             // 2. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: an empty List }.
 |             // 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); |             requested_modules_in_source_order.empend(module.module_request->module_specifier); | ||||||
|         } else { |         } else { | ||||||
|             //  ExportDeclaration : export ExportFromClause FromClause AssertClause ;
 |             //  ExportDeclaration : export ExportFromClause FromClause WithClause ;
 | ||||||
|             //  ImportDeclaration : import ImportClause FromClause AssertClause ;
 |             //  ImportDeclaration : import ImportClause FromClause WithClause ;
 | ||||||
| 
 | 
 | ||||||
|             // 1. Let specifier be StringValue of the StringLiteral contained in FromClause.
 |             // 1. Let specifier be the SV of FromClause.
 | ||||||
|             // 2. Let assertions be AssertClauseToAssertions of AssertClause.
 |             // 2. Let attributes be WithClauseToAttributes of WithClause.
 | ||||||
|             auto assertions = assert_clause_to_assertions(module.module_request->assertions, supported_import_assertions); |             auto attributes = with_clause_to_assertions(module.module_request->attributes); | ||||||
|             // Note: We have to modify the assertions in place because else it might keep non supported ones
 |             // NOTE: We have to modify the attributes in place because else it might keep unsupported ones.
 | ||||||
|             const_cast<ModuleRequest*>(module.module_request)->assertions = move(assertions); |             const_cast<ModuleRequest*>(module.module_request)->attributes = move(attributes); | ||||||
| 
 | 
 | ||||||
|             // 3. Return a ModuleRequest Record { [[Specifer]]: specifier, [[Assertions]]: 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->assertions); |             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()) |     if (parser.has_errors()) | ||||||
|         return parser.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.
 |     // 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.
 |     // 4. Let importEntries be ImportEntries of body.
 | ||||||
|     Vector<ImportEntry> import_entries; |     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.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)
 |     // 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
 |     // 8.1.6.5.2 HostGetSupportedImportAttributes(), https://html.spec.whatwg.org/multipage/webappapis.html#hostgetsupportedimportassertions
 | ||||||
|     s_main_thread_vm->host_get_supported_import_assertions = []() -> Vector<DeprecatedString> { |     s_main_thread_vm->host_get_supported_import_attributes = []() -> Vector<DeprecatedString> { | ||||||
|         // 1. Return « "type" ».
 |         // 1. Return « "type" ».
 | ||||||
|         return { "type"sv }; |         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)
 |     // 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.
 |         // 1. Let moduleMap and referencingScript be null.
 | ||||||
|         Optional<HTML::ModuleMap&> module_map; |         Optional<HTML::ModuleMap&> module_map; | ||||||
|         Optional<HTML::Script&> referencing_script; |         Optional<HTML::Script&> referencing_script; | ||||||
| 
 | 
 | ||||||
|         // 2. If referencingScriptOrModule is not null, then:
 |         if (referrer.has<JS::NonnullGCPtr<JS::Script>>() || referrer.has<JS::NonnullGCPtr<JS::CyclicModule>>()) { | ||||||
|         if (!referencing_string_or_module.has<Empty>()) { |  | ||||||
|             // 1. Set referencingScript to referencingScriptOrModule.[[HostDefined]].
 |             // 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.
 |             // 2. Set moduleMap to referencingScript's settings object's module map.
 | ||||||
|             module_map = referencing_script->settings_object().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".
 |     // 1. Let moduleType be "javascript".
 | ||||||
|     DeprecatedString module_type = "javascript"sv; |     DeprecatedString module_type = "javascript"sv; | ||||||
| 
 | 
 | ||||||
|     // 2. If moduleRequest.[[Assertions]] has a Record entry such that entry.[[Key]] is "type", then:
 |     // 2. If moduleRequest.[[Attributes]] has a Record entry such that entry.[[Key]] is "type", then:
 | ||||||
|     for (auto const& entry : module_request.assertions) { |     for (auto const& entry : module_request.attributes) { | ||||||
|         if (entry.key != "type"sv) |         if (entry.key != "type"sv) | ||||||
|             continue; |             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",
 |     // 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.
 |     //    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); |         VERIFY(entry.key == "type"sv); | ||||||
| 
 | 
 | ||||||
|     // 2. Let moduleType be the result of running the module type from module request steps given moduleRequest.
 |     // 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; |         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()) { |     for (auto const& requested : result.value()->requested_modules()) { | ||||||
|         // FIXME: Clarify if this should be checked for all requested before running the steps below.
 |         // 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",
 |         // 1. If requested.[[Attributes]] contains a Record entry such that entry.[[Key]] is not "type", then:
 | ||||||
|         //            because we only asked for "type" assertions in HostGetSupportedImportAssertions.
 |         for (auto const& attribute : requested.attributes) { | ||||||
|         VERIFY(all_of(requested.assertions, [](auto const& assertion) { return assertion.key == "type"sv; })); |             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); |         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()) { |         if (url.is_exception()) { | ||||||
|             // FIXME: 1. Set script's parse error to that exception.
 |             // FIXME: 1. Set script's parse error to that exception.
 | ||||||
| 
 | 
 | ||||||
|  | @ -86,10 +96,10 @@ WebIDL::ExceptionOr<JS::GCPtr<JavaScriptModuleScript>> JavaScriptModuleScript::c | ||||||
|             return script; |             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); |         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)) { |         if (!settings_object.module_type_allowed(module_type)) { | ||||||
|             // FIXME: 1. Let error be a new TypeError exception.
 |             // 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(); |     script->m_record = result.value(); | ||||||
| 
 | 
 | ||||||
|     // 12. Return script.
 |     // 11. Return script.
 | ||||||
|     return script; |     return script; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling