using Jint.Collections;
using Jint.Native.Object;
using Jint.Native.Symbol;
using Jint.Runtime;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Interop;
namespace Jint.Native.ShadowRealm;
///
/// https://tc39.es/proposal-shadowrealm/#sec-properties-of-the-shadowrealm-prototype-object
///
internal sealed class ShadowRealmPrototype : Prototype
{
private readonly ShadowRealmConstructor _constructor;
internal ShadowRealmPrototype(
Engine engine,
Realm realm,
ShadowRealmConstructor constructor,
ObjectPrototype prototype) : base(engine, realm)
{
_prototype = prototype;
_constructor = constructor;
}
protected override void Initialize()
{
const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
var properties = new PropertyDictionary(5, checkExistingKeys: false)
{
["length"] = new PropertyDescriptor(0, PropertyFlag.Configurable),
["constructor"] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
["evaluate"] = new PropertyDescriptor(new ClrFunction(Engine, "evaluate", Evaluate, 1, PropertyFlag.Configurable), propertyFlags),
["importValue"] = new PropertyDescriptor(new ClrFunction(Engine, "importValue", ImportValue, 2, PropertyFlag.Configurable), propertyFlags),
};
SetProperties(properties);
var symbols = new SymbolDictionary(1) { [GlobalSymbolRegistry.ToStringTag] = new PropertyDescriptor("ShadowRealm", false, false, true) };
SetSymbols(symbols);
}
///
/// https://tc39.es/proposal-shadowrealm/#sec-shadowrealm.prototype.evaluate
///
private JsValue Evaluate(JsValue thisObject, JsValue[] arguments)
{
var shadowRealm = ValidateShadowRealmObject(thisObject);
var sourceText = arguments.At(0);
if (!sourceText.IsString())
{
ExceptionHelper.ThrowTypeError(_realm, "Invalid source text " + sourceText);
}
var parserOptions = _engine.GetActiveParserOptions();
// Just like in the case of eval, we don't allow top level returns.
var adjustedParserOptions = parserOptions.AllowReturnOutsideFunction
? parserOptions with { AllowReturnOutsideFunction = false }
: parserOptions;
var parser = _engine.GetParserFor(adjustedParserOptions);
return shadowRealm.PerformShadowRealmEval(sourceText.AsString(), parserOptions, parser, _realm);
}
///
/// https://tc39.es/proposal-shadowrealm/#sec-shadowrealm.prototype.importvalue
///
private JsValue ImportValue(JsValue thisObject, JsValue[] arguments)
{
var specifier = arguments.At(0);
var exportName = arguments.At(1);
var O = ValidateShadowRealmObject(thisObject);
var specifierString = TypeConverter.ToJsString(specifier);
if (!specifier.IsString())
{
ExceptionHelper.ThrowTypeError(_realm, "Invalid specifier");
}
if (!exportName.IsString())
{
ExceptionHelper.ThrowTypeError(_realm, "Invalid exportName");
}
var callerRealm = _realm;
return O.ShadowRealmImportValue(specifierString.ToString(), exportName.ToString(), callerRealm);
}
private ShadowRealm ValidateShadowRealmObject(JsValue thisObject)
{
if (thisObject is ShadowRealm shadowRealm)
{
return shadowRealm;
}
ExceptionHelper.ThrowTypeError(_realm, "object must be a ShadowRealm");
return default;
}
}