ModuleNamespaceObject.cpp 8.6 KB

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