#nullable disable using Jint.Native; using Jint.Native.Array; using Jint.Native.Object; using Jint.Native.Symbol; using Jint.Runtime.Descriptors; namespace Jint.Runtime.Modules; /// /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects /// internal sealed class ModuleNamespace : ObjectInstance { private readonly Module _module; private readonly HashSet _exports; public ModuleNamespace(Engine engine, Module module, List exports) : base(engine) { _module = module; _exports = new HashSet(exports, StringComparer.Ordinal); } protected override void Initialize() { var symbols = new SymbolDictionary(1) { [GlobalSymbolRegistry.ToStringTag] = new("Module", false, false, false) }; SetSymbols(symbols); } /// /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-getprototypeof /// protected internal override ObjectInstance GetPrototypeOf() => null; /// /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-setprototypeof-v /// internal override bool SetPrototypeOf(JsValue value) => SetImmutablePrototype(value); /// /// https://tc39.es/ecma262/#sec-set-immutable-prototype /// private bool SetImmutablePrototype(JsValue value) { var current = GetPrototypeOf(); return SameValue(value, current ?? Null); } /// /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-isextensible /// public override bool Extensible => false; /// /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-preventextensions /// public override bool PreventExtensions() => true; /// /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-getownproperty-p /// public override PropertyDescriptor GetOwnProperty(JsValue property) { if (property.IsSymbol()) { return base.GetOwnProperty(property); } var p = TypeConverter.ToString(property); if (!_exports.Contains(p)) { return PropertyDescriptor.Undefined; } var value = Get(property); return new PropertyDescriptor(value, true, true, false); } /// /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-defineownproperty-p-desc /// public override bool DefineOwnProperty(JsValue property, PropertyDescriptor desc) { if (property.IsSymbol()) { return base.DefineOwnProperty(property, desc); } var current = GetOwnProperty(property); if (current == PropertyDescriptor.Undefined) { return false; } if (desc.Configurable) { return false; } if (desc.EnumerableSet && !desc.Enumerable) { return false; } if (desc.IsAccessorDescriptor()) { return false; } if (desc.WritableSet && !desc.Writable) { return false; } if (desc.Value is not null) { return SameValue(desc.Value, current.Value); } return true; } /// /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-hasproperty-p /// public override bool HasProperty(JsValue property) { if (property.IsSymbol()) { return base.HasProperty(property); } var p = TypeConverter.ToString(property); return _exports.Contains(p); } /// /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-get-p-receiver /// public override JsValue Get(JsValue property, JsValue receiver) { if (property.IsSymbol()) { return base.Get(property, receiver); } var p = TypeConverter.ToString(property); if (!_exports.Contains(p)) { return Undefined; } var m = _module; var binding = m.ResolveExport(p); var targetModule = binding.Module; if (string.Equals(binding.BindingName, "*namespace*", StringComparison.Ordinal)) { return Module.GetModuleNamespace(targetModule); } var targetEnv = targetModule._environment; if (targetEnv is null) { Throw.ReferenceError(_engine.Realm, "Module's environment hasn't been initialized"); } return targetEnv.GetBindingValue(binding.BindingName, true); } /// /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-set-p-v-receiver /// public override bool Set(JsValue property, JsValue value, JsValue receiver) { return false; } /// /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-delete-p /// public override bool Delete(JsValue property) { if (property.IsSymbol()) { return base.Delete(property); } var p = TypeConverter.ToString(property); return !_exports.Contains(p); } /// /// https://tc39.es/ecma262/#sec-module-namespace-exotic-objects-ownpropertykeys /// public override List GetOwnPropertyKeys(Types types = Types.String | Types.Symbol) { var result = new List(); if ((types & Types.String) != Types.Empty) { result.Capacity = _exports.Count; foreach (var export in _exports) { result.Add(export); } result.Sort(ArrayPrototype.ArrayComparer.Default); } result.AddRange(base.GetOwnPropertyKeys(types)); return result; } }