ModuleNamespace.cs 5.9 KB

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