template JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSWorkerDOMConstructor::construct()

in src/bun.js/bindings/webcore/JSWorker.cpp [114:278]


template<> JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSWorkerDOMConstructor::construct(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame)
{
    VM& vm = lexicalGlobalObject->vm();
    auto throwScope = DECLARE_THROW_SCOPE(vm);
    auto* castedThis = jsCast<JSWorkerDOMConstructor*>(callFrame->jsCallee());
    ASSERT(castedThis);
    if (UNLIKELY(callFrame->argumentCount() < 1))
        return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
    auto* context = castedThis->scriptExecutionContext();
    if (UNLIKELY(!context))
        return throwConstructorScriptExecutionContextUnavailableError(*lexicalGlobalObject, throwScope, "Worker"_s);
    EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0);
    auto scriptUrl = convert<IDLUSVString>(*lexicalGlobalObject, argument0.value());
    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
    EnsureStillAliveScope argument1 = callFrame->argument(1);

    auto options = WorkerOptions {};
    options.bun.unref = false;

    if (JSObject* optionsObject = JSC::jsDynamicCast<JSC::JSObject*>(argument1.value())) {
        if (auto nameValue = optionsObject->getIfPropertyExists(lexicalGlobalObject, vm.propertyNames->name)) {
            if (nameValue.isString()) {
                options.name = nameValue.toWTFString(lexicalGlobalObject);
                RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
            }
        }

        if (auto miniModeValue = optionsObject->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "smol"_s))) {
            options.bun.mini = miniModeValue.toBoolean(lexicalGlobalObject);
            RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
        }

        if (auto ref = optionsObject->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "ref"_s))) {
            options.bun.unref = !ref.toBoolean(lexicalGlobalObject);
            RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
        }

        auto workerData = optionsObject->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "workerData"_s));
        if (!workerData) {
            workerData = optionsObject->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "data"_s));
        }

        if (workerData) {
            Vector<RefPtr<MessagePort>> ports;
            Vector<JSC::Strong<JSC::JSObject>> transferList;

            if (JSValue transferListValue = optionsObject->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "transferList"_s))) {
                if (transferListValue.isObject()) {
                    JSC::JSObject* transferListObject = transferListValue.getObject();
                    if (auto* transferListArray = jsDynamicCast<JSC::JSArray*>(transferListObject)) {
                        for (unsigned i = 0; i < transferListArray->length(); i++) {
                            JSC::JSValue transferListValue = transferListArray->get(lexicalGlobalObject, i);
                            if (transferListValue.isObject()) {
                                JSC::JSObject* transferListObject = transferListValue.getObject();
                                transferList.append(JSC::Strong<JSC::JSObject>(vm, transferListObject));
                            }
                        }
                    }
                }
            }

            ExceptionOr<Ref<SerializedScriptValue>> serialized = SerializedScriptValue::create(*lexicalGlobalObject, workerData, WTFMove(transferList), ports, SerializationForStorage::No, SerializationContext::WorkerPostMessage);
            if (serialized.hasException()) {
                WebCore::propagateException(*lexicalGlobalObject, throwScope, serialized.releaseException());
                return encodedJSValue();
            }

            Vector<TransferredMessagePort> transferredPorts;

            if (!ports.isEmpty()) {
                auto disentangleResult = MessagePort::disentanglePorts(WTFMove(ports));
                if (disentangleResult.hasException()) {
                    WebCore::propagateException(*lexicalGlobalObject, throwScope, disentangleResult.releaseException());
                    return encodedJSValue();
                }
                transferredPorts = disentangleResult.releaseReturnValue();
            }

            options.bun.data = serialized.releaseReturnValue();
            options.bun.dataMessagePorts = WTFMove(transferredPorts);
        }

        auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
        auto envValue = optionsObject->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "env"_s));
        RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
        JSObject* envObject = nullptr;

        if (envValue && envValue.isCell()) {
            envObject = jsDynamicCast<JSC::JSObject*>(envValue);
        } else if (globalObject->m_processEnvObject.isInitialized()) {
            envObject = globalObject->processEnvObject();
        }

        if (envObject) {
            if (!envObject->staticPropertiesReified()) {
                envObject->reifyAllStaticProperties(globalObject);
                RETURN_IF_EXCEPTION(throwScope, {});
            }

            JSC::PropertyNameArray keys(vm, JSC::PropertyNameMode::Strings, JSC::PrivateSymbolMode::Exclude);
            envObject->methodTable()->getOwnPropertyNames(envObject, lexicalGlobalObject, keys, JSC::DontEnumPropertiesMode::Exclude);
            RETURN_IF_EXCEPTION(throwScope, {});

            HashMap<String, String> env;

            for (const auto& key : keys) {
                JSValue value = envObject->get(lexicalGlobalObject, key);
                RETURN_IF_EXCEPTION(throwScope, {});
                String str = value.toWTFString(lexicalGlobalObject).isolatedCopy();
                RETURN_IF_EXCEPTION(throwScope, {});
                env.add(key.impl()->isolatedCopy(), str);
            }

            options.bun.env = std::make_unique<HashMap<String, String>>(WTFMove(env));
        }

        JSValue argvValue = optionsObject->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "argv"_s));
        RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
        if (argvValue && argvValue.isCell() && argvValue.asCell()->type() == JSC::JSType::ArrayType) {
            Vector<String> argv;
            forEachInIterable(lexicalGlobalObject, argvValue, [&argv](JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSValue nextValue) {
                auto scope = DECLARE_THROW_SCOPE(vm);
                String str = nextValue.toWTFString(lexicalGlobalObject).isolatedCopy();
                if (UNLIKELY(scope.exception()))
                    return;
                argv.append(str);
            });
            options.bun.argv = std::make_unique<Vector<String>>(WTFMove(argv));
        }

        JSValue execArgvValue = optionsObject->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "execArgv"_s));
        RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
        if (execArgvValue && execArgvValue.isCell() && execArgvValue.asCell()->type() == JSC::JSType::ArrayType) {
            Vector<String> execArgv;
            forEachInIterable(lexicalGlobalObject, execArgvValue, [&execArgv](JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSValue nextValue) {
                auto scope = DECLARE_THROW_SCOPE(vm);
                String str = nextValue.toWTFString(lexicalGlobalObject).isolatedCopy();
                if (UNLIKELY(scope.exception()))
                    return;
                execArgv.append(str);
            });
            options.bun.execArgv = std::make_unique<Vector<String>>(WTFMove(execArgv));
        }
    }

    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
    auto object = Worker::create(*context, WTFMove(scriptUrl), WTFMove(options));
    if constexpr (IsExceptionOr<decltype(object)>)
        RETURN_IF_EXCEPTION(throwScope, {});
    static_assert(TypeOrExceptionOrUnderlyingType<decltype(object)>::isRef);
    auto jsValue = toJSNewlyCreated<IDLInterface<Worker>>(*lexicalGlobalObject, *castedThis->globalObject(), throwScope, WTFMove(object));
    if constexpr (IsExceptionOr<decltype(object)>)
        RETURN_IF_EXCEPTION(throwScope, {});

    auto& impl = jsCast<JSWorker*>(jsValue)->wrapped();
    if (!impl.updatePtr()) {
        throwVMError(lexicalGlobalObject, throwScope, "Failed to start Worker thread"_s);
        return encodedJSValue();
    }

    setSubclassStructureIfNeeded<Worker>(lexicalGlobalObject, callFrame, asObject(jsValue));
    RETURN_IF_EXCEPTION(throwScope, {});

    return JSValue::encode(jsValue);
}