ModuleNamespace.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. #nullable disable
  2. using Jint.Collections;
  3. using Jint.Native;
  4. using Jint.Native.Array;
  5. using Jint.Native.Object;
  6. using Jint.Native.Symbol;
  7. using Jint.Runtime.Descriptors;
  8. namespace Jint.Runtime.Modules;
  9. /// <summary>
  10. /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects
  11. /// </summary>
  12. internal sealed class ModuleNamespace : ObjectInstance
  13. {
  14. private readonly ModuleRecord _module;
  15. private readonly HashSet<string> _exports;
  16. public ModuleNamespace(Engine engine, ModuleRecord module, List<string> exports) : base(engine)
  17. {
  18. _module = module;
  19. _exports = new HashSet<string>(exports, StringComparer.Ordinal);
  20. }
  21. protected override void Initialize()
  22. {
  23. var symbols = new SymbolDictionary(1)
  24. {
  25. [GlobalSymbolRegistry.ToStringTag] = new("Module", false, false, false)
  26. };
  27. SetSymbols(symbols);
  28. }
  29. /// <summary>
  30. /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-getprototypeof
  31. /// </summary>
  32. protected internal override ObjectInstance GetPrototypeOf() => null;
  33. /// <summary>
  34. /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-setprototypeof-v
  35. /// </summary>
  36. public override bool SetPrototypeOf(JsValue value) => SetImmutablePrototype(value);
  37. /// <summary>
  38. /// https://tc39.es/ecma262/#sec-set-immutable-prototype
  39. /// </summary>
  40. private bool SetImmutablePrototype(JsValue value)
  41. {
  42. var current = GetPrototypeOf();
  43. return SameValue(value, current ?? Null);
  44. }
  45. /// <summary>
  46. /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-isextensible
  47. /// </summary>
  48. public override bool Extensible => false;
  49. /// <summary>
  50. /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-preventextensions
  51. /// </summary>
  52. public override bool PreventExtensions() => true;
  53. /// <summary>
  54. /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-getownproperty-p
  55. /// </summary>
  56. public override PropertyDescriptor GetOwnProperty(JsValue property)
  57. {
  58. if (property.IsSymbol())
  59. {
  60. return base.GetOwnProperty(property);
  61. }
  62. var p = TypeConverter.ToString(property);
  63. if (!_exports.Contains(p))
  64. {
  65. return PropertyDescriptor.Undefined;
  66. }
  67. var value = Get(property);
  68. return new PropertyDescriptor(value, true, true, false);
  69. }
  70. /// <summary>
  71. /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-defineownproperty-p-desc
  72. /// </summary>
  73. public override bool DefineOwnProperty(JsValue property, PropertyDescriptor desc)
  74. {
  75. if (property.IsSymbol())
  76. {
  77. return base.DefineOwnProperty(property, desc);
  78. }
  79. var current = GetOwnProperty(property);
  80. if (current == PropertyDescriptor.Undefined)
  81. {
  82. return false;
  83. }
  84. if (desc.Configurable)
  85. {
  86. return false;
  87. }
  88. if (desc.EnumerableSet && !desc.Enumerable)
  89. {
  90. return false;
  91. }
  92. if (desc.IsAccessorDescriptor())
  93. {
  94. return false;
  95. }
  96. if (desc.WritableSet && !desc.Writable)
  97. {
  98. return false;
  99. }
  100. if (desc.Value is not null)
  101. {
  102. return SameValue(desc.Value, current.Value);
  103. }
  104. return true;
  105. }
  106. /// <summary>
  107. /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-hasproperty-p
  108. /// </summary>
  109. public override bool HasProperty(JsValue property)
  110. {
  111. if (property.IsSymbol())
  112. {
  113. return base.HasProperty(property);
  114. }
  115. var p = TypeConverter.ToString(property);
  116. return _exports.Contains(p);
  117. }
  118. /// <summary>
  119. /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-get-p-receiver
  120. /// </summary>
  121. public override JsValue Get(JsValue property, JsValue receiver)
  122. {
  123. if (property.IsSymbol())
  124. {
  125. return base.Get(property, receiver);
  126. }
  127. var p = TypeConverter.ToString(property);
  128. if (!_exports.Contains(p))
  129. {
  130. return Undefined;
  131. }
  132. var m = _module;
  133. var binding = m.ResolveExport(p);
  134. var targetModule = binding.Module;
  135. if (string.Equals(binding.BindingName, "*namespace*", StringComparison.Ordinal))
  136. {
  137. return ModuleRecord.GetModuleNamespace(targetModule);
  138. }
  139. var targetEnv = targetModule._environment;
  140. if (targetEnv is null)
  141. {
  142. ExceptionHelper.ThrowReferenceError(_engine.Realm, "Module's environment hasn't been initialized");
  143. }
  144. return targetEnv.GetBindingValue(binding.BindingName, true);
  145. }
  146. /// <summary>
  147. /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-set-p-v-receiver
  148. /// </summary>
  149. public override bool Set(JsValue property, JsValue value, JsValue receiver)
  150. {
  151. return false;
  152. }
  153. /// <summary>
  154. /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-delete-p
  155. /// </summary>
  156. public override bool Delete(JsValue property)
  157. {
  158. if (property.IsSymbol())
  159. {
  160. return base.Delete(property);
  161. }
  162. var p = TypeConverter.ToString(property);
  163. return !_exports.Contains(p);
  164. }
  165. /// <summary>
  166. /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-ownpropertykeys
  167. /// </summary>
  168. public override List<JsValue> GetOwnPropertyKeys(Types types = Types.String | Types.Symbol)
  169. {
  170. var result = new List<JsValue>();
  171. if ((types & Types.String) != Types.None)
  172. {
  173. result.Capacity = _exports.Count;
  174. foreach (var export in _exports)
  175. {
  176. result.Add(export);
  177. }
  178. result.Sort(ArrayPrototype.ArrayComparer.Default);
  179. }
  180. result.AddRange(base.GetOwnPropertyKeys(types));
  181. return result;
  182. }
  183. }