ModuleNamespaceObject.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * Copyright (c) 2022, David Tuin <davidot@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/QuickSort.h>
  7. #include <LibJS/Runtime/GlobalObject.h>
  8. #include <LibJS/Runtime/ModuleNamespaceObject.h>
  9. namespace JS {
  10. JS_DEFINE_ALLOCATOR(ModuleNamespaceObject);
  11. ModuleNamespaceObject::ModuleNamespaceObject(Realm& realm, Module* module, Vector<DeprecatedFlyString> exports)
  12. : Object(ConstructWithPrototypeTag::Tag, realm.intrinsics().object_prototype(), MayInterfereWithIndexedPropertyAccess::Yes)
  13. , m_module(module)
  14. , m_exports(move(exports))
  15. {
  16. // Note: We just perform step 6 of 10.4.6.12 ModuleNamespaceCreate ( module, exports ), https://tc39.es/ecma262/#sec-modulenamespacecreate
  17. // 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.
  18. quick_sort(m_exports, [&](DeprecatedFlyString const& lhs, DeprecatedFlyString const& rhs) {
  19. return lhs.view() < rhs.view();
  20. });
  21. }
  22. void ModuleNamespaceObject::initialize(Realm& realm)
  23. {
  24. auto& vm = this->vm();
  25. Base::initialize(realm);
  26. // 28.3.1 @@toStringTag, https://tc39.es/ecma262/#sec-@@tostringtag
  27. define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Module"_string), 0);
  28. }
  29. // 10.4.6.1 [[GetPrototypeOf]] ( ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-getprototypeof
  30. ThrowCompletionOr<Object*> ModuleNamespaceObject::internal_get_prototype_of() const
  31. {
  32. // 1. Return null.
  33. return nullptr;
  34. }
  35. // 10.4.6.2 [[SetPrototypeOf]] ( V ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-setprototypeof-v
  36. ThrowCompletionOr<bool> ModuleNamespaceObject::internal_set_prototype_of(Object* prototype)
  37. {
  38. // 1. Return ! SetImmutablePrototype(O, V).
  39. return MUST(set_immutable_prototype(prototype));
  40. }
  41. // 10.4.6.3 [[IsExtensible]] ( ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-isextensible
  42. ThrowCompletionOr<bool> ModuleNamespaceObject::internal_is_extensible() const
  43. {
  44. // 1. Return false.
  45. return false;
  46. }
  47. // 10.4.6.4 [[PreventExtensions]] ( ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-preventextensions
  48. ThrowCompletionOr<bool> ModuleNamespaceObject::internal_prevent_extensions()
  49. {
  50. // 1. Return true.
  51. return true;
  52. }
  53. // 10.4.6.5 [[GetOwnProperty]] ( P ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-getownproperty-p
  54. ThrowCompletionOr<Optional<PropertyDescriptor>> ModuleNamespaceObject::internal_get_own_property(PropertyKey const& property_key) const
  55. {
  56. // 1. If Type(P) is Symbol, return OrdinaryGetOwnProperty(O, P).
  57. if (property_key.is_symbol())
  58. return Object::internal_get_own_property(property_key);
  59. // 2. Let exports be O.[[Exports]].
  60. // 3. If P is not an element of exports, return undefined.
  61. auto export_element = m_exports.find(property_key.to_string());
  62. if (export_element.is_end())
  63. return Optional<PropertyDescriptor> {};
  64. // 4. Let value be ? O.[[Get]](P, O).
  65. auto value = TRY(internal_get(property_key, this));
  66. // 5. Return PropertyDescriptor { [[Value]]: value, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: false }.
  67. return PropertyDescriptor { .value = value, .writable = true, .enumerable = true, .configurable = false };
  68. }
  69. // 10.4.6.6 [[DefineOwnProperty]] ( P, Desc ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-defineownproperty-p-desc
  70. ThrowCompletionOr<bool> ModuleNamespaceObject::internal_define_own_property(PropertyKey const& property_key, PropertyDescriptor const& descriptor, Optional<PropertyDescriptor>* precomputed_get_own_property)
  71. {
  72. // 1. If Type(P) is Symbol, return ! OrdinaryDefineOwnProperty(O, P, Desc).
  73. if (property_key.is_symbol())
  74. return MUST(Object::internal_define_own_property(property_key, descriptor, precomputed_get_own_property));
  75. // 2. Let current be ? O.[[GetOwnProperty]](P).
  76. auto current = TRY(internal_get_own_property(property_key));
  77. // 3. If current is undefined, return false.
  78. if (!current.has_value())
  79. return false;
  80. // 4. If Desc has a [[Configurable]] field and Desc.[[Configurable]] is true, return false.
  81. if (descriptor.configurable.has_value() && descriptor.configurable.value())
  82. return false;
  83. // 5. If Desc has an [[Enumerable]] field and Desc.[[Enumerable]] is false, return false.
  84. if (descriptor.enumerable.has_value() && !descriptor.enumerable.value())
  85. return false;
  86. // 6. If IsAccessorDescriptor(Desc) is true, return false.
  87. if (descriptor.is_accessor_descriptor())
  88. return false;
  89. // 7. If Desc has a [[Writable]] field and Desc.[[Writable]] is false, return false.
  90. if (descriptor.writable.has_value() && !descriptor.writable.value())
  91. return false;
  92. // 8. If Desc has a [[Value]] field, return SameValue(Desc.[[Value]], current.[[Value]]).
  93. if (descriptor.value.has_value())
  94. return same_value(descriptor.value.value(), current->value.value());
  95. // 9. Return true.
  96. return true;
  97. }
  98. // 10.4.6.7 [[HasProperty]] ( P ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-hasproperty-p
  99. ThrowCompletionOr<bool> ModuleNamespaceObject::internal_has_property(PropertyKey const& property_key) const
  100. {
  101. // 1. If Type(P) is Symbol, return ! OrdinaryHasProperty(O, P).
  102. if (property_key.is_symbol())
  103. return MUST(Object::internal_has_property(property_key));
  104. // 2. Let exports be O.[[Exports]].
  105. // 3. If P is an element of exports, return true.
  106. auto export_element = m_exports.find(property_key.to_string());
  107. if (!export_element.is_end())
  108. return true;
  109. // 4. Return false.
  110. return false;
  111. }
  112. // 10.4.6.8 [[Get]] ( P, Receiver ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-get-p-receiver
  113. ThrowCompletionOr<Value> ModuleNamespaceObject::internal_get(PropertyKey const& property_key, Value receiver, CacheablePropertyMetadata* cacheable_metadata, PropertyLookupPhase phase) const
  114. {
  115. auto& vm = this->vm();
  116. // 1. If Type(P) is Symbol, then
  117. if (property_key.is_symbol()) {
  118. // a. Return ! OrdinaryGet(O, P, Receiver).
  119. return MUST(Object::internal_get(property_key, receiver, cacheable_metadata, phase));
  120. }
  121. // 2. Let exports be O.[[Exports]].
  122. // 3. If P is not an element of exports, return undefined.
  123. auto export_element = m_exports.find(property_key.to_string());
  124. if (export_element.is_end())
  125. return js_undefined();
  126. // 4. Let m be O.[[Module]].
  127. // 5. Let binding be ! m.ResolveExport(P).
  128. auto binding = MUST(m_module->resolve_export(vm, property_key.to_string()));
  129. // 6. Assert: binding is a ResolvedBinding Record.
  130. VERIFY(binding.is_valid());
  131. // 7. Let targetModule be binding.[[Module]].
  132. auto target_module = binding.module;
  133. // 8. Assert: targetModule is not undefined.
  134. VERIFY(target_module);
  135. // 9. If binding.[[BindingName]] is namespace, then
  136. if (binding.is_namespace()) {
  137. // a. Return ? GetModuleNamespace(targetModule).
  138. return TRY(target_module->get_module_namespace(vm));
  139. }
  140. // 10. Let targetEnv be targetModule.[[Environment]].
  141. auto* target_environment = target_module->environment();
  142. // 11. If targetEnv is empty, throw a ReferenceError exception.
  143. if (!target_environment)
  144. return vm.throw_completion<ReferenceError>(ErrorType::ModuleNoEnvironment);
  145. // 12. Return ? targetEnv.GetBindingValue(binding.[[BindingName]], true).
  146. return target_environment->get_binding_value(vm, binding.export_name, true);
  147. }
  148. // 10.4.6.9 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-set-p-v-receiver
  149. ThrowCompletionOr<bool> ModuleNamespaceObject::internal_set(PropertyKey const&, Value, Value, CacheablePropertyMetadata*)
  150. {
  151. // 1. Return false.
  152. return false;
  153. }
  154. // 10.4.6.10 [[Delete]] ( P ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-delete-p
  155. ThrowCompletionOr<bool> ModuleNamespaceObject::internal_delete(PropertyKey const& property_key)
  156. {
  157. // 1. If Type(P) is Symbol, then
  158. if (property_key.is_symbol()) {
  159. // a. Return ! OrdinaryDelete(O, P).
  160. return MUST(Object::internal_delete(property_key));
  161. }
  162. // 2. Let exports be O.[[Exports]].
  163. // 3. If P is an element of exports, return false.
  164. auto export_element = m_exports.find(property_key.to_string());
  165. if (!export_element.is_end())
  166. return false;
  167. // 4. Return true.
  168. return true;
  169. }
  170. // 10.4.6.11 [[OwnPropertyKeys]] ( ), https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-ownpropertykeys
  171. ThrowCompletionOr<MarkedVector<Value>> ModuleNamespaceObject::internal_own_property_keys() const
  172. {
  173. // 1. Let exports be O.[[Exports]].
  174. // NOTE: We only add the exports after we know the size of symbolKeys
  175. MarkedVector<Value> exports { vm().heap() };
  176. // 2. Let symbolKeys be OrdinaryOwnPropertyKeys(O).
  177. auto symbol_keys = MUST(Object::internal_own_property_keys());
  178. // 3. Return the list-concatenation of exports and symbolKeys.
  179. exports.ensure_capacity(m_exports.size() + symbol_keys.size());
  180. for (auto const& export_name : m_exports)
  181. exports.unchecked_append(PrimitiveString::create(vm(), export_name));
  182. exports.extend(symbol_keys);
  183. return exports;
  184. }
  185. void ModuleNamespaceObject::visit_edges(JS::Cell::Visitor& visitor)
  186. {
  187. Base::visit_edges(visitor);
  188. visitor.visit(m_module);
  189. }
  190. }