1use crate::{
14 builtins::{self, BuiltIn},
15 object::ObjectInitializer,
16 property::Attribute,
17 symbol::WellKnownSymbols,
18 BoaProfiler, Context, JsResult, JsValue,
19};
20
21use super::{Array, JsArgs};
22
23#[cfg(test)]
24mod tests;
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
28pub(crate) struct Reflect;
29
30impl BuiltIn for Reflect {
31 const NAME: &'static str = "Reflect";
32
33 fn attribute() -> Attribute {
34 Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE
35 }
36
37 fn init(context: &mut Context) -> (&'static str, JsValue, Attribute) {
38 let _timer = BoaProfiler::global().start_event(Self::NAME, "init");
39
40 let to_string_tag = WellKnownSymbols::to_string_tag();
41
42 let object = ObjectInitializer::new(context)
43 .function(Self::apply, "apply", 3)
44 .function(Self::construct, "construct", 2)
45 .function(Self::define_property, "defineProperty", 3)
46 .function(Self::delete_property, "deleteProperty", 2)
47 .function(Self::get, "get", 2)
48 .function(
49 Self::get_own_property_descriptor,
50 "getOwnPropertyDescriptor",
51 2,
52 )
53 .function(Self::get_prototype_of, "getPrototypeOf", 1)
54 .function(Self::has, "has", 2)
55 .function(Self::is_extensible, "isExtensible", 1)
56 .function(Self::own_keys, "ownKeys", 1)
57 .function(Self::prevent_extensions, "preventExtensions", 1)
58 .function(Self::set, "set", 3)
59 .function(Self::set_prototype_of, "setPrototypeOf", 3)
60 .property(
61 to_string_tag,
62 Self::NAME,
63 Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
64 )
65 .build();
66 (Self::NAME, object.into(), Self::attribute())
67 }
68}
69
70impl Reflect {
71 pub(crate) fn apply(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
80 let target = args
81 .get(0)
82 .and_then(|v| v.as_object())
83 .ok_or_else(|| context.construct_type_error("target must be a function"))?;
84 let this_arg = args.get_or_undefined(1);
85 let args_list = args.get_or_undefined(2);
86
87 if !target.is_callable() {
88 return context.throw_type_error("target must be a function");
89 }
90 let args = args_list.create_list_from_array_like(&[], context)?;
91 target.call(this_arg, &args, context)
92 }
93
94 pub(crate) fn construct(
103 _: &JsValue,
104 args: &[JsValue],
105 context: &mut Context,
106 ) -> JsResult<JsValue> {
107 let target = args
108 .get(0)
109 .and_then(|v| v.as_object())
110 .ok_or_else(|| context.construct_type_error("target must be a function"))?;
111 let args_list = args.get_or_undefined(1);
112
113 if !target.is_constructable() {
114 return context.throw_type_error("target must be a constructor");
115 }
116
117 let new_target = if let Some(new_target) = args.get(2) {
118 if new_target.as_object().map(|o| o.is_constructable()) != Some(true) {
119 return context.throw_type_error("newTarget must be constructor");
120 }
121 new_target.clone()
122 } else {
123 target.clone().into()
124 };
125
126 let args = args_list.create_list_from_array_like(&[], context)?;
127 target.construct(&args, &new_target, context)
128 }
129
130 pub(crate) fn define_property(
139 _: &JsValue,
140 args: &[JsValue],
141 context: &mut Context,
142 ) -> JsResult<JsValue> {
143 let target = args
144 .get(0)
145 .and_then(|v| v.as_object())
146 .ok_or_else(|| context.construct_type_error("target must be an object"))?;
147 let key = args.get_or_undefined(1).to_property_key(context)?;
148 let prop_desc: JsValue = args
149 .get(2)
150 .and_then(|v| v.as_object())
151 .ok_or_else(|| context.construct_type_error("property descriptor must be an object"))?
152 .into();
153
154 target
155 .__define_own_property__(key, prop_desc.to_property_descriptor(context)?, context)
156 .map(|b| b.into())
157 }
158
159 pub(crate) fn delete_property(
168 _: &JsValue,
169 args: &[JsValue],
170 context: &mut Context,
171 ) -> JsResult<JsValue> {
172 let target = args
173 .get(0)
174 .and_then(|v| v.as_object())
175 .ok_or_else(|| context.construct_type_error("target must be an object"))?;
176 let key = args.get_or_undefined(1).to_property_key(context)?;
177
178 Ok(target.__delete__(&key, context)?.into())
179 }
180
181 pub(crate) fn get(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
190 let target = args
192 .get(0)
193 .and_then(|v| v.as_object())
194 .ok_or_else(|| context.construct_type_error("target must be an object"))?;
195 let key = args.get_or_undefined(1).to_property_key(context)?;
197 let receiver = if let Some(receiver) = args.get(2).cloned() {
199 receiver
200 } else {
201 target.clone().into()
203 };
204 target.__get__(&key, receiver, context)
206 }
207
208 pub(crate) fn get_own_property_descriptor(
217 _: &JsValue,
218 args: &[JsValue],
219 context: &mut Context,
220 ) -> JsResult<JsValue> {
221 match args.get(0) {
222 Some(v) if v.is_object() => (),
223 _ => return context.throw_type_error("target must be an object"),
224 }
225 builtins::object::Object::get_own_property_descriptor(&JsValue::undefined(), args, context)
228 }
229
230 pub(crate) fn get_prototype_of(
239 _: &JsValue,
240 args: &[JsValue],
241 context: &mut Context,
242 ) -> JsResult<JsValue> {
243 let target = args
244 .get(0)
245 .and_then(|v| v.as_object())
246 .ok_or_else(|| context.construct_type_error("target must be an object"))?;
247 target.__get_prototype_of__(context)
248 }
249
250 pub(crate) fn has(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
259 let target = args
260 .get(0)
261 .and_then(|v| v.as_object())
262 .ok_or_else(|| context.construct_type_error("target must be an object"))?;
263 let key = args
264 .get(1)
265 .unwrap_or(&JsValue::undefined())
266 .to_property_key(context)?;
267 Ok(target.__has_property__(&key, context)?.into())
268 }
269
270 pub(crate) fn is_extensible(
279 _: &JsValue,
280 args: &[JsValue],
281 context: &mut Context,
282 ) -> JsResult<JsValue> {
283 let target = args
284 .get(0)
285 .and_then(|v| v.as_object())
286 .ok_or_else(|| context.construct_type_error("target must be an object"))?;
287 Ok(target.__is_extensible__(context)?.into())
288 }
289
290 pub(crate) fn own_keys(
299 _: &JsValue,
300 args: &[JsValue],
301 context: &mut Context,
302 ) -> JsResult<JsValue> {
303 let target = args
304 .get(0)
305 .and_then(|v| v.as_object())
306 .ok_or_else(|| context.construct_type_error("target must be an object"))?;
307
308 let keys: Vec<JsValue> = target
309 .__own_property_keys__(context)?
310 .into_iter()
311 .map(|key| key.into())
312 .collect();
313
314 Ok(Array::create_array_from_list(keys, context).into())
315 }
316
317 pub(crate) fn prevent_extensions(
326 _: &JsValue,
327 args: &[JsValue],
328 context: &mut Context,
329 ) -> JsResult<JsValue> {
330 let target = args
331 .get(0)
332 .and_then(|v| v.as_object())
333 .ok_or_else(|| context.construct_type_error("target must be an object"))?;
334
335 Ok(target.__prevent_extensions__(context)?.into())
336 }
337
338 pub(crate) fn set(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
347 let target = args
348 .get(0)
349 .and_then(|v| v.as_object())
350 .ok_or_else(|| context.construct_type_error("target must be an object"))?;
351 let key = args.get_or_undefined(1).to_property_key(context)?;
352 let value = args.get_or_undefined(2);
353 let receiver = if let Some(receiver) = args.get(3).cloned() {
354 receiver
355 } else {
356 target.clone().into()
357 };
358 Ok(target
359 .__set__(key, value.clone(), receiver, context)?
360 .into())
361 }
362
363 pub(crate) fn set_prototype_of(
372 _: &JsValue,
373 args: &[JsValue],
374 context: &mut Context,
375 ) -> JsResult<JsValue> {
376 let mut target = args
377 .get(0)
378 .and_then(|v| v.as_object())
379 .ok_or_else(|| context.construct_type_error("target must be an object"))?;
380 let proto = args.get_or_undefined(1);
381 if !proto.is_null() && !proto.is_object() {
382 return context.throw_type_error("proto must be an object or null");
383 }
384 Ok(target.__set_prototype_of__(proto.clone(), context)?.into())
385 }
386}