2022-01-16 23:32:41 +01:00
/*
* Copyright ( c ) 2022 , David Tuin < davidot @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include <AK/QuickSort.h>
# include <LibJS/Runtime/GlobalObject.h>
# include <LibJS/Runtime/ModuleNamespaceObject.h>
namespace JS {
2023-01-08 19:23:00 -05:00
ModuleNamespaceObject : : ModuleNamespaceObject ( Realm & realm , Module * module , Vector < DeprecatedFlyString > exports )
2022-12-14 12:17:58 +01:00
: Object ( ConstructWithPrototypeTag : : Tag , * realm . intrinsics ( ) . object_prototype ( ) )
2022-01-16 23:32:41 +01:00
, m_module ( module )
, m_exports ( move ( exports ) )
{
// Note: We just perform step 6 of 10.4.6.12 ModuleNamespaceCreate ( module, exports ), https://tc39.es/ecma262/#sec-modulenamespacecreate
// 6. Let sortedExports be a List whose elements are the elements of exports ordered as if an Array of the same values had been sorted using %Array.prototype.sort% using undefined as comparefn.
2023-01-08 19:23:00 -05:00
quick_sort ( m_exports , [ & ] ( DeprecatedFlyString const & lhs , DeprecatedFlyString const & rhs ) {
2022-01-16 23:32:41 +01:00
return lhs . view ( ) < rhs . view ( ) ;
} ) ;
}
2023-01-28 12:33:35 -05:00
ThrowCompletionOr < void > ModuleNamespaceObject : : initialize ( Realm & realm )
2022-01-16 23:32:41 +01:00
{
2023-01-28 12:33:35 -05:00
MUST_OR_THROW_OOM ( Base : : initialize ( realm ) ) ;
2022-01-16 23:32:41 +01:00
// 28.3.1 @@toStringTag, https://tc39.es/ecma262/#sec-@@tostringtag
2023-02-09 09:00:14 -05:00
define_direct_property ( * vm ( ) . well_known_symbol_to_string_tag ( ) , MUST_OR_THROW_OOM ( PrimitiveString : : create ( vm ( ) , " Module " sv ) ) , 0 ) ;
2023-01-28 12:33:35 -05:00
return { } ;
2022-01-16 23:32:41 +01:00
}
// 10.4.6.1 [[GetPrototypeOf]] ( ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-getprototypeof
ThrowCompletionOr < Object * > ModuleNamespaceObject : : internal_get_prototype_of ( ) const
{
// 1. Return null.
return nullptr ;
}
// 10.4.6.2 [[SetPrototypeOf]] ( V ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-setprototypeof-v
ThrowCompletionOr < bool > ModuleNamespaceObject : : internal_set_prototype_of ( Object * prototype )
{
2022-05-02 20:54:39 +02:00
// 1. Return ! SetImmutablePrototype(O, V).
return MUST ( set_immutable_prototype ( prototype ) ) ;
2022-01-16 23:32:41 +01:00
}
// 10.4.6.3 [[IsExtensible]] ( ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-isextensible
ThrowCompletionOr < bool > ModuleNamespaceObject : : internal_is_extensible ( ) const
{
// 1. Return false.
return false ;
}
// 10.4.6.4 [[PreventExtensions]] ( ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-preventextensions
ThrowCompletionOr < bool > ModuleNamespaceObject : : internal_prevent_extensions ( )
{
// 1. Return true.
return true ;
}
// 10.4.6.5 [[GetOwnProperty]] ( P ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-getownproperty-p
ThrowCompletionOr < Optional < PropertyDescriptor > > ModuleNamespaceObject : : internal_get_own_property ( PropertyKey const & property_key ) const
{
// 1. If Type(P) is Symbol, return OrdinaryGetOwnProperty(O, P).
if ( property_key . is_symbol ( ) )
return Object : : internal_get_own_property ( property_key ) ;
// 2. Let exports be O.[[Exports]].
// 3. If P is not an element of exports, return undefined.
auto export_element = m_exports . find ( property_key . to_string ( ) ) ;
if ( export_element . is_end ( ) )
return Optional < PropertyDescriptor > { } ;
// 4. Let value be ? O.[[Get]](P, O).
auto value = TRY ( internal_get ( property_key , this ) ) ;
// 5. Return PropertyDescriptor { [[Value]]: value, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: false }.
return PropertyDescriptor { . value = value , . writable = true , . enumerable = true , . configurable = false } ;
}
// 10.4.6.6 [[DefineOwnProperty]] ( P, Desc ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-defineownproperty-p-desc
ThrowCompletionOr < bool > ModuleNamespaceObject : : internal_define_own_property ( PropertyKey const & property_key , PropertyDescriptor const & descriptor )
{
2022-05-02 20:54:39 +02:00
// 1. If Type(P) is Symbol, return ! OrdinaryDefineOwnProperty(O, P, Desc).
2022-01-16 23:32:41 +01:00
if ( property_key . is_symbol ( ) )
2022-05-02 20:54:39 +02:00
return MUST ( Object : : internal_define_own_property ( property_key , descriptor ) ) ;
2022-01-16 23:32:41 +01:00
// 2. Let current be ? O.[[GetOwnProperty]](P).
auto current = TRY ( internal_get_own_property ( property_key ) ) ;
// 3. If current is undefined, return false.
if ( ! current . has_value ( ) )
return false ;
// 4. If Desc has a [[Configurable]] field and Desc.[[Configurable]] is true, return false.
if ( descriptor . configurable . has_value ( ) & & descriptor . configurable . value ( ) )
return false ;
// 5. If Desc has an [[Enumerable]] field and Desc.[[Enumerable]] is false, return false.
if ( descriptor . enumerable . has_value ( ) & & ! descriptor . enumerable . value ( ) )
return false ;
2022-05-02 20:54:39 +02:00
// 6. If IsAccessorDescriptor(Desc) is true, return false.
2022-01-16 23:32:41 +01:00
if ( descriptor . is_accessor_descriptor ( ) )
return false ;
// 7. If Desc has a [[Writable]] field and Desc.[[Writable]] is false, return false.
if ( descriptor . writable . has_value ( ) & & ! descriptor . writable . value ( ) )
return false ;
// 8. If Desc has a [[Value]] field, return SameValue(Desc.[[Value]], current.[[Value]]).
if ( descriptor . value . has_value ( ) )
return same_value ( descriptor . value . value ( ) , current - > value . value ( ) ) ;
// 9. Return true.
return true ;
}
// 10.4.6.7 [[HasProperty]] ( P ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-hasproperty-p
ThrowCompletionOr < bool > ModuleNamespaceObject : : internal_has_property ( PropertyKey const & property_key ) const
{
2022-05-02 20:54:39 +02:00
// 1. If Type(P) is Symbol, return ! OrdinaryHasProperty(O, P).
2022-01-16 23:32:41 +01:00
if ( property_key . is_symbol ( ) )
2022-05-02 20:54:39 +02:00
return MUST ( Object : : internal_has_property ( property_key ) ) ;
2022-01-16 23:32:41 +01:00
// 2. Let exports be O.[[Exports]].
// 3. If P is an element of exports, return true.
auto export_element = m_exports . find ( property_key . to_string ( ) ) ;
if ( ! export_element . is_end ( ) )
return true ;
// 4. Return false.
return false ;
}
// 10.4.6.8 [[Get]] ( P, Receiver ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-get-p-receiver
ThrowCompletionOr < Value > ModuleNamespaceObject : : internal_get ( PropertyKey const & property_key , Value receiver ) const
{
2022-08-21 15:12:43 +01:00
auto & vm = this - > vm ( ) ;
2022-01-16 23:32:41 +01:00
// 1. If Type(P) is Symbol, then
if ( property_key . is_symbol ( ) ) {
2022-05-02 20:54:39 +02:00
// a. Return ! OrdinaryGet(O, P, Receiver).
return MUST ( Object : : internal_get ( property_key , receiver ) ) ;
2022-01-16 23:32:41 +01:00
}
// 2. Let exports be O.[[Exports]].
// 3. If P is not an element of exports, return undefined.
auto export_element = m_exports . find ( property_key . to_string ( ) ) ;
if ( export_element . is_end ( ) )
return js_undefined ( ) ;
// 4. Let m be O.[[Module]].
// 5. Let binding be ! m.ResolveExport(P).
2022-08-21 15:12:43 +01:00
auto binding = MUST ( m_module - > resolve_export ( vm , property_key . to_string ( ) ) ) ;
2022-01-18 19:29:17 +01:00
// 6. Assert: binding is a ResolvedBinding Record.
VERIFY ( binding . is_valid ( ) ) ;
// 7. Let targetModule be binding.[[Module]].
2023-02-26 16:09:02 -07:00
auto target_module = binding . module ;
2022-01-18 19:29:17 +01:00
// 8. Assert: targetModule is not undefined.
VERIFY ( target_module ) ;
// 9. If binding.[[BindingName]] is namespace, then
if ( binding . is_namespace ( ) ) {
// a. Return ? GetModuleNamespace(targetModule).
2022-08-21 15:12:43 +01:00
return TRY ( target_module - > get_module_namespace ( vm ) ) ;
2022-01-18 19:29:17 +01:00
}
// 10. Let targetEnv be targetModule.[[Environment]].
auto * target_environment = target_module - > environment ( ) ;
// 11. If targetEnv is empty, throw a ReferenceError exception.
if ( ! target_environment )
2022-08-21 15:12:43 +01:00
return vm . throw_completion < ReferenceError > ( ErrorType : : ModuleNoEnvironment ) ;
2022-01-18 19:29:17 +01:00
// 12. Return ? targetEnv.GetBindingValue(binding.[[BindingName]], true).
2022-08-21 15:12:43 +01:00
return target_environment - > get_binding_value ( vm , binding . export_name , true ) ;
2022-01-16 23:32:41 +01:00
}
// 10.4.6.9 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-set-p-v-receiver
ThrowCompletionOr < bool > ModuleNamespaceObject : : internal_set ( PropertyKey const & , Value , Value )
{
// 1. Return false.
return false ;
}
// 10.4.6.10 [[Delete]] ( P ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-delete-p
ThrowCompletionOr < bool > ModuleNamespaceObject : : internal_delete ( PropertyKey const & property_key )
{
// 1. If Type(P) is Symbol, then
if ( property_key . is_symbol ( ) ) {
2022-05-02 20:54:39 +02:00
// a. Return ! OrdinaryDelete(O, P).
return MUST ( Object : : internal_delete ( property_key ) ) ;
2022-01-16 23:32:41 +01:00
}
// 2. Let exports be O.[[Exports]].
// 3. If P is an element of exports, return false.
auto export_element = m_exports . find ( property_key . to_string ( ) ) ;
if ( ! export_element . is_end ( ) )
return false ;
// 4. Return true.
return true ;
}
// 10.4.6.11 [[OwnPropertyKeys]] ( ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-ownpropertykeys
2022-02-09 10:06:40 +00:00
ThrowCompletionOr < MarkedVector < Value > > ModuleNamespaceObject : : internal_own_property_keys ( ) const
2022-01-16 23:32:41 +01:00
{
// 1. Let exports be O.[[Exports]].
2022-08-31 20:31:02 +02:00
// NOTE: We only add the exports after we know the size of symbolKeys
MarkedVector < Value > exports { vm ( ) . heap ( ) } ;
2022-01-16 23:32:41 +01:00
2022-05-02 20:54:39 +02:00
// 2. Let symbolKeys be OrdinaryOwnPropertyKeys(O).
2022-01-16 23:32:41 +01:00
auto symbol_keys = MUST ( Object : : internal_own_property_keys ( ) ) ;
// 3. Return the list-concatenation of exports and symbolKeys.
2022-08-31 20:31:02 +02:00
exports . ensure_capacity ( m_exports . size ( ) + symbol_keys . size ( ) ) ;
for ( auto const & export_name : m_exports )
2022-12-06 22:17:27 +00:00
exports . unchecked_append ( PrimitiveString : : create ( vm ( ) , export_name ) ) ;
2022-08-31 20:31:02 +02:00
exports . extend ( symbol_keys ) ;
2022-01-16 23:32:41 +01:00
2022-08-31 20:31:02 +02:00
return exports ;
2022-01-16 23:32:41 +01:00
}
}