/src/serenity/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> |
3 | | * Copyright (c) 2020-2023, Linus Groh <linusg@serenityos.org> |
4 | | * |
5 | | * SPDX-License-Identifier: BSD-2-Clause |
6 | | */ |
7 | | |
8 | | #include <AK/Function.h> |
9 | | #include <LibJS/Runtime/AbstractOperations.h> |
10 | | #include <LibJS/Runtime/Array.h> |
11 | | #include <LibJS/Runtime/Error.h> |
12 | | #include <LibJS/Runtime/GlobalObject.h> |
13 | | #include <LibJS/Runtime/Iterator.h> |
14 | | #include <LibJS/Runtime/ObjectConstructor.h> |
15 | | #include <LibJS/Runtime/ProxyObject.h> |
16 | | #include <LibJS/Runtime/Shape.h> |
17 | | |
18 | | namespace JS { |
19 | | |
20 | | JS_DEFINE_ALLOCATOR(ObjectConstructor); |
21 | | |
22 | | ObjectConstructor::ObjectConstructor(Realm& realm) |
23 | 0 | : NativeFunction(realm.vm().names.Object.as_string(), realm.intrinsics().function_prototype()) |
24 | 0 | { |
25 | 0 | } |
26 | | |
27 | | void ObjectConstructor::initialize(Realm& realm) |
28 | 0 | { |
29 | 0 | auto& vm = this->vm(); |
30 | 0 | Base::initialize(realm); |
31 | | |
32 | | // 20.1.2.21 Object.prototype, https://tc39.es/ecma262/#sec-object.prototype |
33 | 0 | define_direct_property(vm.names.prototype, realm.intrinsics().object_prototype(), 0); |
34 | |
|
35 | 0 | u8 attr = Attribute::Writable | Attribute::Configurable; |
36 | 0 | define_native_function(realm, vm.names.defineProperty, define_property, 3, attr); |
37 | 0 | define_native_function(realm, vm.names.defineProperties, define_properties, 2, attr); |
38 | 0 | define_native_function(realm, vm.names.is, is, 2, attr); |
39 | 0 | define_native_function(realm, vm.names.getOwnPropertyDescriptor, get_own_property_descriptor, 2, attr); |
40 | 0 | define_native_function(realm, vm.names.getOwnPropertyDescriptors, get_own_property_descriptors, 1, attr); |
41 | 0 | define_native_function(realm, vm.names.getOwnPropertyNames, get_own_property_names, 1, attr); |
42 | 0 | define_native_function(realm, vm.names.getOwnPropertySymbols, get_own_property_symbols, 1, attr); |
43 | 0 | define_native_function(realm, vm.names.getPrototypeOf, get_prototype_of, 1, attr); |
44 | 0 | define_native_function(realm, vm.names.groupBy, group_by, 2, attr); |
45 | 0 | define_native_function(realm, vm.names.setPrototypeOf, set_prototype_of, 2, attr); |
46 | 0 | define_native_function(realm, vm.names.isExtensible, is_extensible, 1, attr); |
47 | 0 | define_native_function(realm, vm.names.isFrozen, is_frozen, 1, attr); |
48 | 0 | define_native_function(realm, vm.names.isSealed, is_sealed, 1, attr); |
49 | 0 | define_native_function(realm, vm.names.preventExtensions, prevent_extensions, 1, attr); |
50 | 0 | define_native_function(realm, vm.names.freeze, freeze, 1, attr); |
51 | 0 | define_native_function(realm, vm.names.fromEntries, from_entries, 1, attr); |
52 | 0 | define_native_function(realm, vm.names.seal, seal, 1, attr); |
53 | 0 | define_native_function(realm, vm.names.keys, keys, 1, attr); |
54 | 0 | define_native_function(realm, vm.names.values, values, 1, attr); |
55 | 0 | define_native_function(realm, vm.names.entries, entries, 1, attr); |
56 | 0 | define_native_function(realm, vm.names.create, create, 2, attr); |
57 | 0 | define_native_function(realm, vm.names.hasOwn, has_own, 2, attr); |
58 | 0 | define_native_function(realm, vm.names.assign, assign, 2, attr); |
59 | |
|
60 | 0 | define_direct_property(vm.names.length, Value(1), Attribute::Configurable); |
61 | 0 | } |
62 | | |
63 | | // 20.1.1.1 Object ( [ value ] ), https://tc39.es/ecma262/#sec-object-value |
64 | | ThrowCompletionOr<Value> ObjectConstructor::call() |
65 | 0 | { |
66 | 0 | return TRY(construct(*this)); |
67 | 0 | } |
68 | | |
69 | | // 20.1.1.1 Object ( [ value ] ), https://tc39.es/ecma262/#sec-object-value |
70 | | ThrowCompletionOr<NonnullGCPtr<Object>> ObjectConstructor::construct(FunctionObject& new_target) |
71 | 0 | { |
72 | 0 | auto& vm = this->vm(); |
73 | 0 | auto& realm = *vm.current_realm(); |
74 | 0 | auto value = vm.argument(0); |
75 | | |
76 | | // 1. If NewTarget is neither undefined nor the active function object, then |
77 | 0 | if (&new_target != this) { |
78 | | // a. Return ? OrdinaryCreateFromConstructor(NewTarget, "%Object.prototype%"). |
79 | 0 | return TRY(ordinary_create_from_constructor<Object>(vm, new_target, &Intrinsics::object_prototype, ConstructWithPrototypeTag::Tag)); |
80 | 0 | } |
81 | | |
82 | | // 2. If value is either undefined or null, return OrdinaryObjectCreate(%Object.prototype%). |
83 | 0 | if (value.is_nullish()) |
84 | 0 | return Object::create(realm, realm.intrinsics().object_prototype()); |
85 | | |
86 | | // 3. Return ! ToObject(value). |
87 | 0 | return MUST(value.to_object(vm)); |
88 | 0 | } |
89 | | |
90 | | enum class GetOwnPropertyKeysType { |
91 | | String, |
92 | | Symbol, |
93 | | }; |
94 | | |
95 | | // 20.1.2.11.1 GetOwnPropertyKeys ( O, type ), https://tc39.es/ecma262/#sec-getownpropertykeys |
96 | | static ThrowCompletionOr<MarkedVector<Value>> get_own_property_keys(VM& vm, Value value, GetOwnPropertyKeysType type) |
97 | 0 | { |
98 | | // 1. Let obj be ? ToObject(O). |
99 | 0 | auto object = TRY(value.to_object(vm)); |
100 | | |
101 | | // 2. Let keys be ? obj.[[OwnPropertyKeys]](). |
102 | 0 | auto keys = TRY(object->internal_own_property_keys()); |
103 | | |
104 | | // 3. Let nameList be a new empty List. |
105 | 0 | auto name_list = MarkedVector<Value> { vm.heap() }; |
106 | | |
107 | | // 4. For each element nextKey of keys, do |
108 | 0 | for (auto& next_key : keys) { |
109 | | // a. If Type(nextKey) is Symbol and type is symbol or Type(nextKey) is String and type is string, then |
110 | 0 | if ((next_key.is_symbol() && type == GetOwnPropertyKeysType::Symbol) || (next_key.is_string() && type == GetOwnPropertyKeysType::String)) { |
111 | | // i. Append nextKey as the last element of nameList. |
112 | 0 | name_list.append(next_key); |
113 | 0 | } |
114 | 0 | } |
115 | | |
116 | | // 5. Return nameList. |
117 | 0 | return { move(name_list) }; |
118 | 0 | } |
119 | | |
120 | | // 20.1.2.1 Object.assign ( target, ...sources ), https://tc39.es/ecma262/#sec-object.assign |
121 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::assign) |
122 | 0 | { |
123 | | // 1. Let to be ? ToObject(target). |
124 | 0 | auto to = TRY(vm.argument(0).to_object(vm)); |
125 | | |
126 | | // 2. If only one argument was passed, return to. |
127 | 0 | if (vm.argument_count() == 1) |
128 | 0 | return to; |
129 | | |
130 | | // 3. For each element nextSource of sources, do |
131 | 0 | for (size_t i = 1; i < vm.argument_count(); ++i) { |
132 | 0 | auto next_source = vm.argument(i); |
133 | | |
134 | | // a. If nextSource is neither undefined nor null, then |
135 | 0 | if (next_source.is_nullish()) |
136 | 0 | continue; |
137 | | |
138 | | // i. Let from be ! ToObject(nextSource). |
139 | 0 | auto from = MUST(next_source.to_object(vm)); |
140 | | |
141 | | // ii. Let keys be ? from.[[OwnPropertyKeys]](). |
142 | 0 | auto keys = TRY(from->internal_own_property_keys()); |
143 | | |
144 | | // iii. For each element nextKey of keys, do |
145 | 0 | for (auto& next_key : keys) { |
146 | 0 | auto property_key = MUST(PropertyKey::from_value(vm, next_key)); |
147 | | |
148 | | // 1. Let desc be ? from.[[GetOwnProperty]](nextKey). |
149 | 0 | auto desc = TRY(from->internal_get_own_property(property_key)); |
150 | | |
151 | | // 2. If desc is not undefined and desc.[[Enumerable]] is true, then |
152 | 0 | if (!desc.has_value() || !*desc->enumerable) |
153 | 0 | continue; |
154 | | |
155 | | // a. Let propValue be ? Get(from, nextKey). |
156 | 0 | auto prop_value = TRY(from->get(property_key)); |
157 | | |
158 | | // b. Perform ? Set(to, nextKey, propValue, true). |
159 | 0 | TRY(to->set(property_key, prop_value, Object::ShouldThrowExceptions::Yes)); |
160 | 0 | } |
161 | 0 | } |
162 | | |
163 | | // 4. Return to. |
164 | 0 | return to; |
165 | 0 | } |
166 | | |
167 | | // 20.1.2.2 Object.create ( O, Properties ), https://tc39.es/ecma262/#sec-object.create |
168 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::create) |
169 | 0 | { |
170 | 0 | auto& realm = *vm.current_realm(); |
171 | |
|
172 | 0 | auto proto = vm.argument(0); |
173 | 0 | auto properties = vm.argument(1); |
174 | | |
175 | | // 1. If Type(O) is neither Object nor Null, throw a TypeError exception. |
176 | 0 | if (!proto.is_object() && !proto.is_null()) |
177 | 0 | return vm.throw_completion<TypeError>(ErrorType::ObjectPrototypeWrongType); |
178 | | |
179 | | // 2. Let obj be OrdinaryObjectCreate(O). |
180 | 0 | auto object = Object::create(realm, proto.is_null() ? nullptr : &proto.as_object()); |
181 | | |
182 | | // 3. If Properties is not undefined, then |
183 | 0 | if (!properties.is_undefined()) { |
184 | | // a. Return ? ObjectDefineProperties(obj, Properties). |
185 | 0 | return TRY(object->define_properties(properties)); |
186 | 0 | } |
187 | | |
188 | | // 4. Return obj. |
189 | 0 | return object; |
190 | 0 | } |
191 | | |
192 | | // 20.1.2.3 Object.defineProperties ( O, Properties ), https://tc39.es/ecma262/#sec-object.defineproperties |
193 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::define_properties) |
194 | 0 | { |
195 | 0 | auto object = vm.argument(0); |
196 | 0 | auto properties = vm.argument(1); |
197 | | |
198 | | // 1. If Type(O) is not Object, throw a TypeError exception. |
199 | 0 | if (!object.is_object()) |
200 | 0 | return vm.throw_completion<TypeError>(ErrorType::NotAnObject, "Object argument"); |
201 | | |
202 | | // 2. Return ? ObjectDefineProperties(O, Properties). |
203 | 0 | return TRY(object.as_object().define_properties(properties)); |
204 | 0 | } |
205 | | |
206 | | // 20.1.2.4 Object.defineProperty ( O, P, Attributes ), https://tc39.es/ecma262/#sec-object.defineproperty |
207 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::define_property) |
208 | 0 | { |
209 | | // 1. If O is not an Object, throw a TypeError exception. |
210 | 0 | if (!vm.argument(0).is_object()) |
211 | 0 | return vm.throw_completion<TypeError>(ErrorType::NotAnObject, vm.argument(0).to_string_without_side_effects()); |
212 | | |
213 | 0 | auto object = MUST(vm.argument(0).to_object(vm)); |
214 | | |
215 | | // 2. Let key be ? ToPropertyKey(P). |
216 | 0 | auto key = TRY(vm.argument(1).to_property_key(vm)); |
217 | | |
218 | | // 3. Let desc be ? ToPropertyDescriptor(Attributes). |
219 | 0 | auto descriptor = TRY(to_property_descriptor(vm, vm.argument(2))); |
220 | | |
221 | | // 4. Perform ? DefinePropertyOrThrow(O, key, desc). |
222 | 0 | TRY(object->define_property_or_throw(key, descriptor)); |
223 | | |
224 | | // 5. Return O. |
225 | 0 | return object; |
226 | 0 | } |
227 | | |
228 | | // 20.1.2.5 Object.entries ( O ), https://tc39.es/ecma262/#sec-object.entries |
229 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::entries) |
230 | 0 | { |
231 | 0 | auto& realm = *vm.current_realm(); |
232 | | |
233 | | // 1. Let obj be ? ToObject(O). |
234 | 0 | auto object = TRY(vm.argument(0).to_object(vm)); |
235 | | |
236 | | // 2. Let entryList be ? EnumerableOwnProperties(obj, key+value). |
237 | 0 | auto name_list = TRY(object->enumerable_own_property_names(PropertyKind::KeyAndValue)); |
238 | | |
239 | | // 3. Return CreateArrayFromList(entryList). |
240 | 0 | return Array::create_from(realm, name_list); |
241 | 0 | } |
242 | | |
243 | | // 20.1.2.6 Object.freeze ( O ), https://tc39.es/ecma262/#sec-object.freeze |
244 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::freeze) |
245 | 0 | { |
246 | 0 | auto argument = vm.argument(0); |
247 | | |
248 | | // 1. If O is not an Object, return O. |
249 | 0 | if (!argument.is_object()) |
250 | 0 | return argument; |
251 | | |
252 | | // 2. Let status be ? SetIntegrityLevel(O, frozen). |
253 | 0 | auto status = TRY(argument.as_object().set_integrity_level(Object::IntegrityLevel::Frozen)); |
254 | | |
255 | | // 3. If status is false, throw a TypeError exception. |
256 | 0 | if (!status) |
257 | 0 | return vm.throw_completion<TypeError>(ErrorType::ObjectFreezeFailed); |
258 | | |
259 | | // 4. Return O. |
260 | 0 | return argument; |
261 | 0 | } |
262 | | |
263 | | // 20.1.2.7 Object.fromEntries ( iterable ), https://tc39.es/ecma262/#sec-object.fromentries |
264 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::from_entries) |
265 | 0 | { |
266 | 0 | auto& realm = *vm.current_realm(); |
267 | | |
268 | | // 1. Perform ? RequireObjectCoercible(iterable). |
269 | 0 | auto iterable = TRY(require_object_coercible(vm, vm.argument(0))); |
270 | | |
271 | | // 2. Let obj be OrdinaryObjectCreate(%Object.prototype%). |
272 | 0 | auto object = Object::create(realm, realm.intrinsics().object_prototype()); |
273 | | |
274 | | // 3. Assert: obj is an extensible ordinary object with no own properties. |
275 | | |
276 | | // 4. Let closure be a new Abstract Closure with parameters (key, value) that captures obj and performs the following steps when called: |
277 | | // 5. Let adder be CreateBuiltinFunction(closure, 2, "", « »). |
278 | | // 6. Return ? AddEntriesFromIterable(obj, iterable, adder). |
279 | 0 | (void)TRY(get_iterator_values(vm, iterable, [&](Value iterator_value) -> Optional<Completion> { |
280 | 0 | if (!iterator_value.is_object()) |
281 | 0 | return vm.throw_completion<TypeError>(ErrorType::NotAnObject, ByteString::formatted("Iterator value {}", iterator_value.to_string_without_side_effects())); |
282 | |
|
283 | 0 | auto key = TRY(iterator_value.as_object().get(0)); |
284 | 0 | auto value = TRY(iterator_value.as_object().get(1)); |
285 | | |
286 | | // a. Let propertyKey be ? ToPropertyKey(key). |
287 | 0 | auto property_key = TRY(key.to_property_key(vm)); |
288 | | |
289 | | // b. Perform ! CreateDataPropertyOrThrow(obj, propertyKey, value). |
290 | 0 | MUST(object->create_data_property_or_throw(property_key, value)); |
291 | | |
292 | | // c. Return undefined. |
293 | 0 | return {}; |
294 | 0 | })); |
295 | |
|
296 | 0 | return object; |
297 | 0 | } |
298 | | |
299 | | // 20.1.2.8 Object.getOwnPropertyDescriptor ( O, P ), https://tc39.es/ecma262/#sec-object.getownpropertydescriptor |
300 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_own_property_descriptor) |
301 | 0 | { |
302 | | // 1. Let obj be ? ToObject(O). |
303 | 0 | auto object = TRY(vm.argument(0).to_object(vm)); |
304 | | |
305 | | // 2. Let key be ? ToPropertyKey(P). |
306 | 0 | auto key = TRY(vm.argument(1).to_property_key(vm)); |
307 | | |
308 | | // 3. Let desc be ? obj.[[GetOwnProperty]](key). |
309 | 0 | auto descriptor = TRY(object->internal_get_own_property(key)); |
310 | | |
311 | | // 4. Return FromPropertyDescriptor(desc). |
312 | 0 | return from_property_descriptor(vm, descriptor); |
313 | 0 | } |
314 | | |
315 | | // 20.1.2.9 Object.getOwnPropertyDescriptors ( O ), https://tc39.es/ecma262/#sec-object.getownpropertydescriptors |
316 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_own_property_descriptors) |
317 | 0 | { |
318 | 0 | auto& realm = *vm.current_realm(); |
319 | | |
320 | | // 1. Let obj be ? ToObject(O). |
321 | 0 | auto object = TRY(vm.argument(0).to_object(vm)); |
322 | | |
323 | | // 2. Let ownKeys be ? obj.[[OwnPropertyKeys]](). |
324 | 0 | auto own_keys = TRY(object->internal_own_property_keys()); |
325 | | |
326 | | // 3. Let descriptors be OrdinaryObjectCreate(%Object.prototype%). |
327 | 0 | auto descriptors = Object::create(realm, realm.intrinsics().object_prototype()); |
328 | | |
329 | | // 4. For each element key of ownKeys, do |
330 | 0 | for (auto& key : own_keys) { |
331 | 0 | auto property_key = MUST(PropertyKey::from_value(vm, key)); |
332 | | |
333 | | // a. Let desc be ? obj.[[GetOwnProperty]](key). |
334 | 0 | auto desc = TRY(object->internal_get_own_property(property_key)); |
335 | | |
336 | | // b. Let descriptor be FromPropertyDescriptor(desc). |
337 | 0 | auto descriptor = from_property_descriptor(vm, desc); |
338 | | |
339 | | // c. If descriptor is not undefined, perform ! CreateDataPropertyOrThrow(descriptors, key, descriptor). |
340 | 0 | if (!descriptor.is_undefined()) |
341 | 0 | MUST(descriptors->create_data_property_or_throw(property_key, descriptor)); |
342 | 0 | } |
343 | | |
344 | | // 5. Return descriptors. |
345 | 0 | return descriptors; |
346 | 0 | } |
347 | | |
348 | | // 20.1.2.10 Object.getOwnPropertyNames ( O ), https://tc39.es/ecma262/#sec-object.getownpropertynames |
349 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_own_property_names) |
350 | 0 | { |
351 | 0 | auto& realm = *vm.current_realm(); |
352 | | |
353 | | // 1. Return CreateArrayFromList(? GetOwnPropertyKeys(O, string)). |
354 | 0 | return Array::create_from(realm, TRY(get_own_property_keys(vm, vm.argument(0), GetOwnPropertyKeysType::String))); |
355 | 0 | } |
356 | | |
357 | | // 20.1.2.11 Object.getOwnPropertySymbols ( O ), https://tc39.es/ecma262/#sec-object.getownpropertysymbols |
358 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_own_property_symbols) |
359 | 0 | { |
360 | 0 | auto& realm = *vm.current_realm(); |
361 | | |
362 | | // 1. Return CreateArrayFromList(? GetOwnPropertyKeys(O, symbol)). |
363 | 0 | return Array::create_from(realm, TRY(get_own_property_keys(vm, vm.argument(0), GetOwnPropertyKeysType::Symbol))); |
364 | 0 | } |
365 | | |
366 | | // 20.1.2.12 Object.getPrototypeOf ( O ), https://tc39.es/ecma262/#sec-object.getprototypeof |
367 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_prototype_of) |
368 | 0 | { |
369 | | // 1. Let obj be ? ToObject(O). |
370 | 0 | auto object = TRY(vm.argument(0).to_object(vm)); |
371 | | |
372 | | // 2. Return ? obj.[[GetPrototypeOf]](). |
373 | 0 | return TRY(object->internal_get_prototype_of()); |
374 | 0 | } |
375 | | |
376 | | // 20.1.2.13 Object.groupBy ( items, callbackfn ), https://tc39.es/ecma262/#sec-object.groupby |
377 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::group_by) |
378 | 0 | { |
379 | 0 | auto& realm = *vm.current_realm(); |
380 | |
|
381 | 0 | auto items = vm.argument(0); |
382 | 0 | auto callback_function = vm.argument(1); |
383 | | |
384 | | // 1. Let groups be ? GroupBy(items, callbackfn, property). |
385 | 0 | auto groups = TRY((JS::group_by<OrderedHashMap<PropertyKey, MarkedVector<Value>>, PropertyKey>(vm, items, callback_function))); |
386 | | |
387 | | // 2. Let obj be OrdinaryObjectCreate(null). |
388 | 0 | auto object = Object::create(realm, nullptr); |
389 | | |
390 | | // 3. For each Record { [[Key]], [[Elements]] } g of groups, do |
391 | 0 | for (auto& group : groups) { |
392 | | // a. Let elements be CreateArrayFromList(g.[[Elements]]). |
393 | 0 | auto elements = Array::create_from(realm, group.value); |
394 | | |
395 | | // b. Perform ! CreateDataPropertyOrThrow(obj, g.[[Key]], elements). |
396 | 0 | MUST(object->create_data_property_or_throw(group.key, elements)); |
397 | 0 | } |
398 | | |
399 | | // 4. Return obj. |
400 | 0 | return object; |
401 | 0 | } |
402 | | |
403 | | // 20.1.2.14 Object.hasOwn ( O, P ), https://tc39.es/ecma262/#sec-object.hasown |
404 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::has_own) |
405 | 0 | { |
406 | | // 1. Let obj be ? ToObject(O). |
407 | 0 | auto object = TRY(vm.argument(0).to_object(vm)); |
408 | | |
409 | | // 2. Let key be ? ToPropertyKey(P). |
410 | 0 | auto key = TRY(vm.argument(1).to_property_key(vm)); |
411 | | |
412 | | // 3. Return ? HasOwnProperty(obj, key). |
413 | 0 | return Value(TRY(object->has_own_property(key))); |
414 | 0 | } |
415 | | |
416 | | // 20.1.2.15 Object.is ( value1, value2 ), https://tc39.es/ecma262/#sec-object.is |
417 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::is) |
418 | 0 | { |
419 | | // 1. Return SameValue(value1, value2). |
420 | 0 | return Value(same_value(vm.argument(0), vm.argument(1))); |
421 | 0 | } |
422 | | |
423 | | // 20.1.2.16 Object.isExtensible ( O ), https://tc39.es/ecma262/#sec-object.isextensible |
424 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::is_extensible) |
425 | 0 | { |
426 | 0 | auto argument = vm.argument(0); |
427 | | |
428 | | // 1. If O is not an Object, return false. |
429 | 0 | if (!argument.is_object()) |
430 | 0 | return Value(false); |
431 | | |
432 | | // 2. Return ? IsExtensible(O). |
433 | 0 | return Value(TRY(argument.as_object().is_extensible())); |
434 | 0 | } |
435 | | |
436 | | // 20.1.2.17 Object.isFrozen ( O ), https://tc39.es/ecma262/#sec-object.isfrozen |
437 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::is_frozen) |
438 | 0 | { |
439 | 0 | auto argument = vm.argument(0); |
440 | | |
441 | | // 1. If O is not an Object, return true. |
442 | 0 | if (!argument.is_object()) |
443 | 0 | return Value(true); |
444 | | |
445 | | // 2. Return ? TestIntegrityLevel(O, frozen). |
446 | 0 | return Value(TRY(argument.as_object().test_integrity_level(Object::IntegrityLevel::Frozen))); |
447 | 0 | } |
448 | | |
449 | | // 20.1.2.18 Object.isSealed ( O ), https://tc39.es/ecma262/#sec-object.issealed |
450 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::is_sealed) |
451 | 0 | { |
452 | 0 | auto argument = vm.argument(0); |
453 | | |
454 | | // 1. If O is not an Object, return true. |
455 | 0 | if (!argument.is_object()) |
456 | 0 | return Value(true); |
457 | | |
458 | | // 2. Return ? TestIntegrityLevel(O, sealed). |
459 | 0 | return Value(TRY(argument.as_object().test_integrity_level(Object::IntegrityLevel::Sealed))); |
460 | 0 | } |
461 | | |
462 | | // 20.1.2.19 Object.keys ( O ), https://tc39.es/ecma262/#sec-object.keys |
463 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::keys) |
464 | 0 | { |
465 | 0 | auto& realm = *vm.current_realm(); |
466 | | |
467 | | // 1. Let obj be ? ToObject(O). |
468 | 0 | auto object = TRY(vm.argument(0).to_object(vm)); |
469 | | |
470 | | // 2. Let keyList be ? EnumerableOwnProperties(obj, key). |
471 | 0 | auto name_list = TRY(object->enumerable_own_property_names(PropertyKind::Key)); |
472 | | |
473 | | // 3. Return CreateArrayFromList(keyList). |
474 | 0 | return Array::create_from(realm, name_list); |
475 | 0 | } |
476 | | |
477 | | // 20.1.2.20 Object.preventExtensions ( O ), https://tc39.es/ecma262/#sec-object.preventextensions |
478 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::prevent_extensions) |
479 | 0 | { |
480 | 0 | auto argument = vm.argument(0); |
481 | | |
482 | | // 1. If O is not an Object, return O. |
483 | 0 | if (!argument.is_object()) |
484 | 0 | return argument; |
485 | | |
486 | | // 2. Let status be ? O.[[PreventExtensions]](). |
487 | 0 | auto status = TRY(argument.as_object().internal_prevent_extensions()); |
488 | | |
489 | | // 3. If status is false, throw a TypeError exception. |
490 | 0 | if (!status) { |
491 | | // FIXME: Improve/contextualize error message |
492 | 0 | return vm.throw_completion<TypeError>(ErrorType::ObjectPreventExtensionsReturnedFalse); |
493 | 0 | } |
494 | | |
495 | | // 4. Return O. |
496 | 0 | return argument; |
497 | 0 | } |
498 | | |
499 | | // 20.1.2.22 Object.seal ( O ), https://tc39.es/ecma262/#sec-object.seal |
500 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::seal) |
501 | 0 | { |
502 | 0 | auto argument = vm.argument(0); |
503 | | |
504 | | // 1. If O is not an Object, return O. |
505 | 0 | if (!argument.is_object()) |
506 | 0 | return argument; |
507 | | |
508 | | // 2. Let status be ? SetIntegrityLevel(O, sealed). |
509 | 0 | auto status = TRY(argument.as_object().set_integrity_level(Object::IntegrityLevel::Sealed)); |
510 | | |
511 | | // 3. If status is false, throw a TypeError exception. |
512 | 0 | if (!status) |
513 | 0 | return vm.throw_completion<TypeError>(ErrorType::ObjectSealFailed); |
514 | | |
515 | | // 4. Return O. |
516 | 0 | return argument; |
517 | 0 | } |
518 | | |
519 | | // 20.1.2.23 Object.setPrototypeOf ( O, proto ), https://tc39.es/ecma262/#sec-object.setprototypeof |
520 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::set_prototype_of) |
521 | 0 | { |
522 | 0 | auto proto = vm.argument(1); |
523 | | |
524 | | // 1. Set O to ? RequireObjectCoercible(O). |
525 | 0 | auto object = TRY(require_object_coercible(vm, vm.argument(0))); |
526 | | |
527 | | // 2. If Type(proto) is neither Object nor Null, throw a TypeError exception. |
528 | 0 | if (!proto.is_object() && !proto.is_null()) |
529 | 0 | return vm.throw_completion<TypeError>(ErrorType::ObjectPrototypeWrongType); |
530 | | |
531 | | // 3. If Type(O) is not Object, return O. |
532 | 0 | if (!object.is_object()) |
533 | 0 | return object; |
534 | | |
535 | | // 4. Let status be ? O.[[SetPrototypeOf]](proto). |
536 | 0 | auto status = TRY(object.as_object().internal_set_prototype_of(proto.is_null() ? nullptr : &proto.as_object())); |
537 | | |
538 | | // 5. If status is false, throw a TypeError exception. |
539 | 0 | if (!status) { |
540 | | // FIXME: Improve/contextualize error message |
541 | 0 | return vm.throw_completion<TypeError>(ErrorType::ObjectSetPrototypeOfReturnedFalse); |
542 | 0 | } |
543 | | |
544 | | // 6. Return O. |
545 | 0 | return object; |
546 | 0 | } |
547 | | |
548 | | // 20.1.2.24 Object.values ( O ), https://tc39.es/ecma262/#sec-object.values |
549 | | JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::values) |
550 | 0 | { |
551 | 0 | auto& realm = *vm.current_realm(); |
552 | | |
553 | | // 1. Let obj be ? ToObject(O). |
554 | 0 | auto object = TRY(vm.argument(0).to_object(vm)); |
555 | | |
556 | | // 2. Let valueList be ? EnumerableOwnProperties(obj, value). |
557 | 0 | auto name_list = TRY(object->enumerable_own_property_names(PropertyKind::Value)); |
558 | | |
559 | | // 3. Return CreateArrayFromList(valueList). |
560 | 0 | return Array::create_from(realm, name_list); |
561 | 0 | } |
562 | | |
563 | | } |