// https://tc39.github.io/ecma262/#sec-reflect.construct EncodedJSValue JSC_HOST_CALL reflectObjectConstruct(ExecState* exec) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSValue target = exec->argument(0); if (!target.isObject()) return JSValue::encode(throwTypeError(exec, scope, ASCIILiteral("Reflect.construct requires the first argument be a constructor"))); ConstructData constructData; ConstructType constructType; if (!target.isConstructor(constructType, constructData)) return JSValue::encode(throwTypeError(exec, scope, ASCIILiteral("Reflect.construct requires the first argument be a constructor"))); JSValue newTarget = target; if (exec->argumentCount() >= 3) { newTarget = exec->argument(2); if (!newTarget.isConstructor()) return JSValue::encode(throwTypeError(exec, scope, ASCIILiteral("Reflect.construct requires the third argument be a constructor if present"))); } MarkedArgumentBuffer arguments; JSObject* argumentsObject = jsDynamicCast<JSObject*>(exec->argument(1)); if (!argumentsObject) return JSValue::encode(throwTypeError(exec, scope, ASCIILiteral("Reflect.construct requires the second argument be an object"))); createListFromArrayLike(exec, argumentsObject, RuntimeTypeMaskAllTypes, ASCIILiteral("This error must not be raised"), [&] (JSValue value, RuntimeType) -> bool { arguments.append(value); return false; }); RETURN_IF_EXCEPTION(scope, encodedJSValue()); scope.release(); return JSValue::encode(construct(exec, target, constructType, constructData, arguments, newTarget)); }
// https://tc39.github.io/ecma262/#sec-reflect.construct EncodedJSValue JSC_HOST_CALL reflectObjectConstruct(ExecState* exec) { JSValue target = exec->argument(0); if (!target.isObject()) return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.construct requires the first argument be a constructor"))); ConstructData constructData; ConstructType constructType; if (!target.isConstructor(constructType, constructData)) return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.construct requires the first argument be a constructor"))); JSValue newTarget = target; if (exec->argumentCount() >= 3) { newTarget = exec->argument(2); if (!newTarget.isConstructor()) return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.construct requires the third argument be a constructor if present"))); } MarkedArgumentBuffer arguments; JSObject* argumentsObject = jsDynamicCast<JSObject*>(exec->argument(1)); if (!argumentsObject) return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.construct requires the second argument be an object"))); createListFromArrayLike(exec, argumentsObject, RuntimeTypeMaskAllTypes, ASCIILiteral("This error must not be raised"), [&] (JSValue value, RuntimeType) -> bool { arguments.append(value); return false; }); if (exec->hadException()) return JSValue::encode(jsUndefined()); return JSValue::encode(construct(exec, target, constructType, constructData, arguments, newTarget)); }
// https://html.spec.whatwg.org/#dom-customelementsregistry-define JSValue JSCustomElementsRegistry::define(ExecState& state) { if (UNLIKELY(state.argumentCount() < 2)) return state.vm().throwException(&state, createNotEnoughArgumentsError(&state)); AtomicString localName(state.uncheckedArgument(0).toString(&state)->toAtomicString(&state)); if (UNLIKELY(state.hadException())) return jsUndefined(); JSValue constructorValue = state.uncheckedArgument(1); if (!constructorValue.isConstructor()) return throwTypeError(&state, ASCIILiteral("The second argument must be a constructor")); JSObject* constructor = constructorValue.getObject(); // FIXME: Throw a TypeError if constructor doesn't inherit from HTMLElement. // https://github.com/w3c/webcomponents/issues/541 switch (Document::validateCustomElementName(localName)) { case CustomElementNameValidationStatus::Valid: break; case CustomElementNameValidationStatus::ConflictsWithBuiltinNames: return throwSyntaxError(&state, ASCIILiteral("Custom element name cannot be same as one of the builtin elements")); case CustomElementNameValidationStatus::NoHyphen: return throwSyntaxError(&state, ASCIILiteral("Custom element name must contain a hyphen")); case CustomElementNameValidationStatus::ContainsUpperCase: return throwSyntaxError(&state, ASCIILiteral("Custom element name cannot contain an upper case letter")); } // FIXME: Check re-entrancy here. // https://github.com/w3c/webcomponents/issues/545 CustomElementsRegistry& registry = wrapped(); if (registry.findInterface(localName)) { throwNotSupportedError(state, ASCIILiteral("Cannot define multiple custom elements with the same tag name")); return jsUndefined(); } if (registry.containsConstructor(constructor)) { throwNotSupportedError(state, ASCIILiteral("Cannot define multiple custom elements with the same class")); return jsUndefined(); } auto& vm = globalObject()->vm(); JSValue prototypeValue = constructor->get(&state, vm.propertyNames->prototype); if (state.hadException()) return jsUndefined(); if (!prototypeValue.isObject()) return throwTypeError(&state, ASCIILiteral("Custom element constructor's prototype must be an object")); JSObject& prototypeObject = *asObject(prototypeValue); QualifiedName name(nullAtom, localName, HTMLNames::xhtmlNamespaceURI); auto elementInterface = JSCustomElementInterface::create(name, constructor, globalObject()); auto* connectedCallback = getCustomElementCallback(state, prototypeObject, Identifier::fromString(&vm, "connectedCallback")); if (state.hadException()) return jsUndefined(); if (connectedCallback) elementInterface->setConnectedCallback(connectedCallback); auto* disconnectedCallback = getCustomElementCallback(state, prototypeObject, Identifier::fromString(&vm, "disconnectedCallback")); if (state.hadException()) return jsUndefined(); if (disconnectedCallback) elementInterface->setDisconnectedCallback(disconnectedCallback); // FIXME: Add the support for adoptedCallback. getCustomElementCallback(state, prototypeObject, Identifier::fromString(&vm, "adoptedCallback")); if (state.hadException()) return jsUndefined(); auto* attributeChangedCallback = getCustomElementCallback(state, prototypeObject, Identifier::fromString(&vm, "attributeChangedCallback")); if (state.hadException()) return jsUndefined(); if (attributeChangedCallback) { auto value = convertOptional<Vector<String>>(state, constructor->get(&state, Identifier::fromString(&state, "observedAttributes"))); if (state.hadException()) return jsUndefined(); if (value) elementInterface->setAttributeChangedCallback(attributeChangedCallback, *value); } PrivateName uniquePrivateName; globalObject()->putDirect(vm, uniquePrivateName, constructor); registry.addElementDefinition(WTFMove(elementInterface)); // FIXME: 17. Let map be registry's upgrade candidates map. // FIXME: 18. Upgrade a newly-defined element given map and definition. // FIXME: 19. Resolve whenDefined promise. return jsUndefined(); }