#pragma warning disable CA1859 // Use concrete types when possible for improved performance -- most of constructor methods return JsValue
using Jint.Native.Function;
using Jint.Native.Iterator;
using Jint.Native.Object;
using Jint.Native.Symbol;
using Jint.Runtime;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Interop;
namespace Jint.Native.Map;
public sealed class MapConstructor : Constructor
{
private static readonly JsString _functionName = new("Map");
internal MapConstructor(
Engine engine,
Realm realm,
FunctionPrototype functionPrototype,
ObjectPrototype objectPrototype)
: base(engine, realm, _functionName)
{
_prototype = functionPrototype;
PrototypeObject = new MapPrototype(engine, realm, this, objectPrototype);
_length = new PropertyDescriptor(0, PropertyFlag.Configurable);
_prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
}
private MapPrototype PrototypeObject { get; }
protected override void Initialize()
{
const PropertyFlag PropertyFlags = PropertyFlag.Writable | PropertyFlag.Configurable;
var properties = new PropertyDictionary(1, checkExistingKeys: false) { ["groupBy"] = new(new ClrFunction(Engine, "groupBy", GroupBy, 2, PropertyFlag.Configurable), PropertyFlags), };
SetProperties(properties);
var symbols = new SymbolDictionary(1) { [GlobalSymbolRegistry.Species] = new GetSetPropertyDescriptor(get: new ClrFunction(_engine, "get [Symbol.species]", Species, 0, PropertyFlag.Configurable), set: Undefined, PropertyFlag.Configurable) };
SetSymbols(symbols);
}
public JsMap Construct() => ConstructMap(this);
///
/// https://tc39.es/ecma262/#sec-map-iterable
///
public override ObjectInstance Construct(JsCallArguments arguments, JsValue newTarget)
{
var map = ConstructMap(newTarget);
if (arguments.Length > 0 && !arguments[0].IsNullOrUndefined())
{
var adder = ((ObjectInstance) map).Get("set");
var iterator = arguments.At(0).GetIterator(_realm);
IteratorProtocol.AddEntriesFromIterable(map, iterator, adder);
}
return map;
}
private JsMap ConstructMap(JsValue newTarget)
{
if (newTarget.IsUndefined())
{
Throw.TypeError(_realm);
}
var map = OrdinaryCreateFromConstructor(
newTarget,
static intrinsics => intrinsics.Map.PrototypeObject,
static (Engine engine, Realm realm, object? _) => new JsMap(engine, realm));
return map;
}
///
/// https://tc39.es/proposal-array-grouping/#sec-map.groupby
///
private JsValue GroupBy(JsValue thisObject, JsCallArguments arguments)
{
var items = arguments.At(0);
var callbackfn = arguments.At(1);
var grouping = GroupByHelper.GroupBy(_engine, _realm, items, callbackfn, mapMode: true);
var map = (JsMap) Construct(_realm.Intrinsics.Map);
foreach (var pair in grouping)
{
map.Set(pair.Key, pair.Value);
}
return map;
}
private static JsValue Species(JsValue thisObject, JsCallArguments arguments)
{
return thisObject;
}
}