first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

57
node_modules/expo-modules-core/ios/JS/EXJSIInstaller.h generated vendored Normal file
View File

@@ -0,0 +1,57 @@
// Copyright 2018-present 650 Industries. All rights reserved.
#import <React/RCTBridge.h>
// Swift classes need forward-declaration in the headers.
@class EXAppContext;
@class EXRuntime;
@class EXJavaScriptRuntime;
#if __has_include(<ReactCommon/RCTRuntimeExecutor.h>)
@class RCTRuntimeExecutor;
#endif // React Native >=0.74
/**
Property name of the core object in the global scope of the Expo JS runtime.
*/
extern NSString *_Nonnull const EXGlobalCoreObjectPropertyName;
@interface EXJavaScriptRuntimeManager : NSObject
/**
Gets the JS runtime from the given bridge. May return `nil` when
the runtime is not available yet or the remote debugging is enabled.
*/
+ (nullable EXRuntime *)runtimeFromBridge:(nonnull RCTBridge *)bridge NS_SWIFT_NAME(runtime(fromBridge:));
#if __has_include(<ReactCommon/RCTRuntimeExecutor.h>)
+ (nullable EXRuntime *)runtimeFromBridge:(nonnull RCTBridge *)bridge withExecutor:(nonnull RCTRuntimeExecutor *)executor;
#endif // React Native >=0.74
/**
Installs ExpoModules host object in the runtime of the given app context.
Returns a bool value whether the installation succeeded.
*/
+ (BOOL)installExpoModulesHostObject:(nonnull EXAppContext *)appContext;
/**
Installs the base class for shared objects, i.e. `global.expo.SharedObject`.
*/
+ (void)installSharedObjectClass:(nonnull EXJavaScriptRuntime *)runtime releaser:(void (^)(long))releaser;
/**
Installs the base class for shared refs, i.e. `global.expo.SharedRef`.
*/
+ (void)installSharedRefClass:(nonnull EXJavaScriptRuntime *)runtime;
/**
Installs the EventEmitter class in the given runtime as `global.expo.EventEmitter`.
*/
+ (void)installEventEmitterClass:(nonnull EXJavaScriptRuntime *)runtime;
/**
Installs the NativeModule class in the given runtime as `global.expo.NativeModule`.
*/
+ (void)installNativeModuleClass:(nonnull EXJavaScriptRuntime *)runtime;
@end

103
node_modules/expo-modules-core/ios/JS/EXJSIInstaller.mm generated vendored Normal file
View File

@@ -0,0 +1,103 @@
// Copyright 2018-present 650 Industries. All rights reserved.
#import <ExpoModulesJSI/BridgelessJSCallInvoker.h>
#import <ExpoModulesCore/EXJSIInstaller.h>
#import <ExpoModulesCore/ExpoModulesHostObject.h>
#import <ExpoModulesCore/LazyObject.h>
#import <ExpoModulesCore/SharedObject.h>
#import <ExpoModulesCore/SharedRef.h>
#import <ExpoModulesCore/EventEmitter.h>
#import <ExpoModulesCore/NativeModule.h>
#import <ExpoModulesCore/Swift.h>
#import <ExpoModulesCore/EXRuntime.h>
#import <ExpoModulesJSI/EXJSIUtils.h>
#import <react/renderer/runtimescheduler/RuntimeScheduler.h>
#import <react/renderer/runtimescheduler/RuntimeSchedulerBinding.h>
namespace jsi = facebook::jsi;
/**
Property name of the core object in the global scope of the Expo JS runtime.
*/
NSString *const EXGlobalCoreObjectPropertyName = @"expo";
/**
Property name used to define the modules host object in the main object of the Expo JS runtime.
*/
static NSString *modulesHostObjectPropertyName = @"modules";
@interface RCTBridge (ExpoBridgeWithRuntime)
- (void *)runtime;
- (std::shared_ptr<facebook::react::CallInvoker>)jsCallInvoker;
@end
@implementation EXJavaScriptRuntimeManager
+ (nullable EXRuntime *)runtimeFromBridge:(nonnull RCTBridge *)bridge
{
jsi::Runtime *jsiRuntime = reinterpret_cast<jsi::Runtime *>(bridge.runtime);
if (!jsiRuntime) {
return nil;
}
return [[EXRuntime alloc] initWithRuntime:*jsiRuntime];
}
#pragma mark - Installing JSI bindings
+ (BOOL)installExpoModulesHostObject:(nonnull EXAppContext *)appContext
{
EXRuntime *runtime = [appContext _runtime];
// The runtime may be unavailable, e.g. remote debugger is enabled or it hasn't been set yet.
if (!runtime) {
return false;
}
EXJavaScriptObject *global = [runtime global];
EXJavaScriptValue *coreProperty = [global getProperty:EXGlobalCoreObjectPropertyName];
NSAssert([coreProperty isObject], @"The global core property should be an object");
EXJavaScriptObject *coreObject = [coreProperty getObject];
if ([coreObject hasProperty:modulesHostObjectPropertyName]) {
return false;
}
std::shared_ptr<expo::ExpoModulesHostObject> modulesHostObjectPtr = std::make_shared<expo::ExpoModulesHostObject>(appContext);
EXJavaScriptObject *modulesHostObject = [runtime createHostObject:modulesHostObjectPtr];
// Define the `global.expo.modules` object as a non-configurable, read-only and enumerable property.
[coreObject defineProperty:modulesHostObjectPropertyName
value:modulesHostObject
options:EXJavaScriptObjectPropertyDescriptorEnumerable];
return true;
}
+ (void)installSharedObjectClass:(nonnull EXRuntime *)runtime releaser:(void(^)(long))releaser
{
expo::SharedObject::installBaseClass(*[runtime get], [releaser](expo::SharedObject::ObjectId objectId) {
releaser(objectId);
});
}
+ (void)installSharedRefClass:(nonnull EXJavaScriptRuntime *)runtime
{
expo::SharedRef::installBaseClass(*[runtime get]);
}
+ (void)installEventEmitterClass:(nonnull EXJavaScriptRuntime *)runtime
{
expo::EventEmitter::installClass(*[runtime get]);
}
+ (void)installNativeModuleClass:(nonnull EXJavaScriptRuntime *)runtime
{
expo::NativeModule::installClass(*[runtime get]);
}
@end

16
node_modules/expo-modules-core/ios/JS/EXJSUtils.h generated vendored Normal file
View File

@@ -0,0 +1,16 @@
// Copyright 2025-present 650 Industries. All rights reserved.
#import <ExpoModulesJSI/EXJavaScriptObject.h>
#import <ExpoModulesJSI/EXJavaScriptRuntime.h>
NS_SWIFT_NAME(JSUtils)
@interface EXJSUtils : NSObject
+ (nonnull EXJavaScriptObject *)createNativeModuleObject:(nonnull EXJavaScriptRuntime *)runtime;
+ (void)emitEvent:(nonnull NSString *)eventName
toObject:(nonnull EXJavaScriptObject *)object
withArguments:(nonnull NSArray<id> *)arguments
inRuntime:(nonnull EXJavaScriptRuntime *)runtime;
@end

26
node_modules/expo-modules-core/ios/JS/EXJSUtils.mm generated vendored Normal file
View File

@@ -0,0 +1,26 @@
#import <ExpoModulesJSI/EXJavaScriptRuntime.h>
#import <ExpoModulesJSI/EXJavaScriptObject.h>
#import <ExpoModulesJSI/EXJSIConversions.h>
#import <ExpoModulesCore/EXJSUtils.h>
#import <ExpoModulesCore/NativeModule.h>
#import <ExpoModulesCore/EventEmitter.h>
@implementation EXJSUtils
+ (nonnull EXJavaScriptObject *)createNativeModuleObject:(nonnull EXJavaScriptRuntime *)runtime
{
std::shared_ptr<jsi::Object> nativeModule = std::make_shared<jsi::Object>(expo::NativeModule::createInstance(*[runtime get]));
return [[EXJavaScriptObject alloc] initWith:nativeModule runtime:runtime];
}
+ (void)emitEvent:(nonnull NSString *)eventName
toObject:(nonnull EXJavaScriptObject *)object
withArguments:(nonnull NSArray<id> *)arguments
inRuntime:(nonnull EXJavaScriptRuntime *)runtime
{
const std::vector<jsi::Value> argumentsVector(expo::convertNSArrayToStdVector(*[runtime get], arguments));
expo::EventEmitter::emitEvent(*[runtime get], *[object get], [eventName UTF8String], std::move(argumentsVector));
}
@end

21
node_modules/expo-modules-core/ios/JS/EXRuntime.h generated vendored Normal file
View File

@@ -0,0 +1,21 @@
// Copyright 2025-present 650 Industries. All rights reserved.
#import <ExpoModulesJSI/EXJavaScriptRuntime.h>
#import <ExpoModulesJSI/EXJavaScriptObject.h>
NS_SWIFT_NAME(ExpoRuntime)
@interface EXRuntime : EXJavaScriptRuntime
typedef void (^ClassConstructorBlock)(EXJavaScriptObject *_Nonnull thisValue, NSArray<EXJavaScriptValue *> *_Nonnull arguments);
#pragma mark - Shared objects
- (nonnull EXJavaScriptObject *)createSharedObjectClass:(nonnull NSString *)name
constructor:(nonnull ClassConstructorBlock)constructor;
#pragma mark - Shared refs
- (nonnull EXJavaScriptObject *)createSharedRefClass:(nonnull NSString *)name
constructor:(nonnull ClassConstructorBlock)constructor;
@end

75
node_modules/expo-modules-core/ios/JS/EXRuntime.mm generated vendored Normal file
View File

@@ -0,0 +1,75 @@
// Copyright 2025-present 650 Industries. All rights reserved.
#import <ExpoModulesJSI/EXJSIConversions.h>
#import <ExpoModulesCore/EXRuntime.h>
#import <ExpoModulesCore/EXJSUtils.h>
#import <ExpoModulesCore/SharedObject.h>
#import <ExpoModulesCore/SharedRef.h>
@implementation EXRuntime
typedef jsi::Function (^InstanceFactory)(jsi::Runtime &runtime, NSString *_Nonnull name, expo::common::ClassConstructor constructor);
- (nonnull EXJavaScriptObject *)createInstance:(nonnull NSString *)name
instanceFactory:(nonnull InstanceFactory)instanceFactory
constructor:(nonnull ClassConstructorBlock)constructor
{
expo::common::ClassConstructor jsConstructor = [self, constructor](jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value {
std::shared_ptr<jsi::Object> thisPtr = std::make_shared<jsi::Object>(thisValue.asObject(runtime));
EXJavaScriptObject *caller = [[EXJavaScriptObject alloc] initWith:thisPtr runtime:self];
NSArray<EXJavaScriptValue *> *arguments = expo::convertJSIValuesToNSArray(self, args, count);
// Returning something else than `this` is not supported in native constructors.
@try {
constructor(caller, arguments);
} @catch (NSException *exception) {
jsi::String jsMessage = expo::convertNSStringToJSIString(runtime, exception.reason ?: @"Constructor failed");
jsi::Value error = runtime
.global()
.getProperty(runtime, "Error")
.asObject(runtime)
.asFunction(runtime)
.callAsConstructor(runtime, {
jsi::Value(runtime, jsMessage)
});
if (exception.userInfo[@"code"]) {
jsi::String jsCode = expo::convertNSStringToJSIString(runtime, exception.userInfo[@"code"]);
error.asObject(runtime).setProperty(runtime, "code", jsi::Value(runtime, jsCode));
}
throw jsi::JSError(runtime, jsi::Value(runtime, error));
}
return jsi::Value(runtime, thisValue);
};
std::shared_ptr<jsi::Function> klass = std::make_shared<jsi::Function>(instanceFactory(*[self get], name, jsConstructor));
return [[EXJavaScriptObject alloc] initWith:klass runtime:self];
}
#pragma mark - Shared objects
- (nonnull EXJavaScriptObject *)createSharedObjectClass:(nonnull NSString *)name
constructor:(nonnull ClassConstructorBlock)constructor
{
InstanceFactory instanceFactory = ^(jsi::Runtime& runtime, NSString * name, expo::common::ClassConstructor constructor){
return expo::SharedObject::createClass(*[self get], [name UTF8String], constructor);
};
return [self createInstance:name instanceFactory:instanceFactory constructor:constructor];
}
#pragma mark - Shared refs
- (nonnull EXJavaScriptObject *)createSharedRefClass:(nonnull NSString *)name
constructor:(nonnull ClassConstructorBlock)constructor
{
InstanceFactory instanceFactory = ^(jsi::Runtime& runtime, NSString * name, expo::common::ClassConstructor constructor){
return expo::SharedRef::createClass(*[self get], [name UTF8String], constructor);
};
return [self createInstance:name instanceFactory:instanceFactory constructor:constructor];
}
@end

View File

@@ -0,0 +1,15 @@
// Copyright 2024-present 650 Industries. All rights reserved.
#import <ExpoModulesJSI/EXJavaScriptObject.h>
typedef void (^ObjectReleaser)(long objectId);
NS_SWIFT_NAME(SharedObjectUtils)
@interface EXSharedObjectUtils : NSObject
+ (void)setNativeState:(nonnull EXJavaScriptObject *)object
runtime:(nonnull EXJavaScriptRuntime *)runtime
objectId:(long)objectId
releaser:(nonnull ObjectReleaser)releaser;
@end

View File

@@ -0,0 +1,19 @@
// Copyright 2024-present 650 Industries. All rights reserved.
#import <ExpoModulesCore/EXSharedObjectUtils.h>
#import <ExpoModulesCore/SharedObject.h>
#import <ExpoModulesJSI/EXJavaScriptRuntime.h>
@implementation EXSharedObjectUtils
+ (void)setNativeState:(nonnull EXJavaScriptObject *)object
runtime:(nonnull EXJavaScriptRuntime *)runtime
objectId:(long)objectId
releaser:(nonnull ObjectReleaser)releaser
{
auto nativeState = std::make_shared<expo::SharedObject::NativeState>(objectId, releaser);
[object get]->setNativeState(*[runtime get], nativeState);
}
@end

View File

@@ -0,0 +1,38 @@
// Copyright 2022-present 650 Industries. All rights reserved.
#ifdef __cplusplus
#import <vector>
#import <unordered_map>
#import <jsi/jsi.h>
namespace jsi = facebook::jsi;
@class EXAppContext;
namespace expo {
using SharedJSIObject = std::shared_ptr<jsi::Object>;
using UniqueJSIObject = std::unique_ptr<jsi::Object>;
class JSI_EXPORT ExpoModulesHostObject : public jsi::HostObject {
public:
ExpoModulesHostObject(EXAppContext *appContext);
virtual ~ExpoModulesHostObject();
jsi::Value get(jsi::Runtime &, const jsi::PropNameID &name) override;
void set(jsi::Runtime &, const jsi::PropNameID &name, const jsi::Value &value) override;
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime &rt) override;
private:
EXAppContext *appContext;
std::unordered_map<std::string, UniqueJSIObject> modulesCache;
}; // class ExpoModulesHostObject
} // namespace expo
#endif

View File

@@ -0,0 +1,61 @@
// Copyright 2022-present 650 Industries. All rights reserved.
#import <ExpoModulesJSI/EXJavaScriptObject.h>
#import <ExpoModulesCore/ExpoModulesHostObject.h>
#import <ExpoModulesCore/LazyObject.h>
#import <ExpoModulesCore/Swift.h>
namespace expo {
ExpoModulesHostObject::ExpoModulesHostObject(EXAppContext *appContext) : appContext(appContext) {}
ExpoModulesHostObject::~ExpoModulesHostObject() {
modulesCache.clear();
appContext._runtime = nil;
}
jsi::Value ExpoModulesHostObject::get(jsi::Runtime &runtime, const jsi::PropNameID &name) {
std::string moduleName = name.utf8(runtime);
NSString *nsModuleName = [NSString stringWithUTF8String:moduleName.c_str()];
if (![appContext hasModule:nsModuleName]) {
// The module object can already be cached but no longer registered — we remove it from the cache in that case.
modulesCache.erase(moduleName);
return jsi::Value::undefined();
}
if (UniqueJSIObject &cachedObject = modulesCache[moduleName]) {
return jsi::Value(runtime, *cachedObject);
}
// Create a lazy object for the specific module. It defers initialization of the final module object.
LazyObject::Shared moduleLazyObject = std::make_shared<LazyObject>(^SharedJSIObject(jsi::Runtime &runtime) {
return [[appContext getNativeModuleObject:nsModuleName] getShared];
});
// Save the module's lazy host object for later use.
modulesCache[moduleName] = std::make_unique<jsi::Object>(jsi::Object::createFromHostObject(runtime, moduleLazyObject));
return jsi::Value(runtime, *modulesCache[moduleName]);
}
void ExpoModulesHostObject::set(jsi::Runtime &runtime, const jsi::PropNameID &name, const jsi::Value &value) {
std::string message("RuntimeError: Cannot override the host object for expo module '");
message += name.utf8(runtime);
message += "'.";
throw jsi::JSError(runtime, message);
}
std::vector<jsi::PropNameID> ExpoModulesHostObject::getPropertyNames(jsi::Runtime &runtime) {
NSArray<NSString *> *moduleNames = [appContext getModuleNames];
std::vector<jsi::PropNameID> propertyNames;
propertyNames.reserve([moduleNames count]);
for (NSString *moduleName in moduleNames) {
propertyNames.push_back(jsi::PropNameID::forAscii(runtime, [moduleName UTF8String]));
}
return propertyNames;
}
} // namespace expo

View File

@@ -0,0 +1,78 @@
/**
Global actor that is used to isolate the code that should only be executed from the JavaScript thread.
Theoretically it does not act as a real actor; it uses a serial executor that executes jobs **synchronously**
without hopping to the proper thread. Meaning that running these jobs on the JavaScript thread must be ensured
externally before switching to the isolated context, e.g. using `schedule` function on `JavaScriptRuntime`
or enforcing the isolation with `JavaScriptActor.assumeIsolated`.
*/
@globalActor
public actor JavaScriptActor: GlobalActor {
public static let shared = JavaScriptActor()
private init() {}
nonisolated private let executor = JavaScriptSerialExecutor()
nonisolated public var unownedExecutor: UnownedSerialExecutor {
return executor.asUnownedSerialExecutor()
}
/**
An equivalent of `MainActor.assumeIsolated`, but for the `JavaScriptActor`. Assumes that the currently executing
synchronous function is actually executing on the JavaScript thread and invokes an isolated version of the operation,
allowing synchronous access to JavaScript runtime state without hopping through asynchronous boundaries.
See https://stackoverflow.com/a/79346971 for more information about the implementation.
*/
public static func assumeIsolated<T>(_ operation: @JavaScriptActor () throws -> T) rethrows -> T {
typealias YesActor = @JavaScriptActor () throws -> T
typealias NoActor = () throws -> T
// This will crash if the current context cannot be isolated.
shared.executor.checkIsolated()
// To do the unsafe cast, we have to pretend it's @escaping.
return try withoutActuallyEscaping(operation) { (_ fn: @escaping YesActor) throws -> T in
let rawFn = unsafeBitCast(fn, to: NoActor.self)
return try rawFn()
}
}
}
/**
Name of the JavaScript thread created by React Native. Copied from `RCTJSThreadManager.mm`.
*/
private let jsThreadName = "com.facebook.react.runtime.JavaScript"
/**
Executor for the `JavaScriptActor` that executes given jobs synchronously and immediately.
- Note: It does not ensure that given jobs are executed on the JavaScript thread; it must be done externally.
*/
private final class JavaScriptSerialExecutor: SerialExecutor {
func enqueue(_ job: UnownedJob) {
job.runSynchronously(on: self.asUnownedSerialExecutor())
}
/**
Converts the executor to the optimized form of borrowed executor reference.
*/
func asUnownedSerialExecutor() -> UnownedSerialExecutor {
return UnownedSerialExecutor(ordinary: self)
}
/**
Stops program execution if the executor is not isolating the current context.
*/
func checkIsolated() {
precondition(isIsolatingCurrentContext() == true, "JavaScriptActor operations must be run on the JavaScript thread")
}
/**
Checks whether the executor isolates the current context, i.e. the current thread is a JavaScript thread.
The condition is also met when running tests and in single threaded environments.
*/
func isIsolatingCurrentContext() -> Bool? {
// We must be careful as it relies on the thread name given by React Native.
return Thread.current.name == jsThreadName || !Thread.isMultiThreaded() || ProcessInfo.processInfo.processName == "xctest"
}
}

View File

@@ -0,0 +1,85 @@
// Copyright 2022-present 650 Industries. All rights reserved.
public extension JavaScriptRuntime {
/**
A type of the closure that you pass to the `createSyncFunction` function.
*/
typealias SyncFunctionClosure = (_ this: JavaScriptValue, _ arguments: [JavaScriptValue]) throws -> JavaScriptValue
/**
Evaluates JavaScript code represented as a string.
- Parameter source: A string representing a JavaScript expression, statement, or sequence of statements.
The expression can include variables and properties of existing objects.
- Returns: The completion value of evaluating the given code represented as `JavaScriptValue`.
If the completion value is empty, `undefined` is returned.
- Throws: `JavaScriptEvalException` when evaluated code has invalid syntax or throws an error.
- Note: It wraps the original `evaluateScript` to better handle and rethrow exceptions.
*/
@discardableResult
func eval(_ source: String) throws -> JavaScriptValue {
do {
var result: JavaScriptValue?
try EXUtilities.catchException {
result = self.__evaluateScript(source)
}
// There is no risk to force unwrapping as long as the `evaluateScript` returns nonnull value.
return result!
} catch {
throw JavaScriptEvalException(error as NSError)
}
}
/**
Evaluates the JavaScript code made by joining an array of strings with a newline separator.
See the other ``eval(_:)`` for more details.
*/
@discardableResult
func eval(_ source: [String]) throws -> JavaScriptValue {
try eval(source.joined(separator: "\n"))
}
/**
Creates a synchronous host function that runs the given closure when it's called.
The value returned by the closure is synchronously returned to JS.
- Returns: A JavaScript function represented as a `JavaScriptObject`.
- Note: It refines the ObjC implementation from `EXJavaScriptRuntime` to properly catch Swift errors and rethrow them as ObjC `NSError`.
*/
func createSyncFunction(_ name: String, argsCount: Int = 0, closure: @escaping SyncFunctionClosure) -> JavaScriptObject {
return __createSyncFunction(name, argsCount: argsCount) { this, args, errorPointer in
do {
return try runWithErrorPointer(errorPointer) {
return try closure(this, args)
}
} catch {
// Nicely log all errors to the console.
log.error(error)
// Can return anything as the error will be caught through the error pointer already.
return nil
}
}
}
/**
Schedules a block to be executed with granted synchronized access to the JS runtime.
*/
func schedule(priority: SchedulerPriority = .normal, @_implicitSelfCapture _ closure: @JavaScriptActor @escaping () -> Void) {
__schedule({ JavaScriptActor.assumeIsolated(closure) }, priority: priority.rawValue)
}
}
// Keep it in sync with the equivalent C++ enum from React Native (see SchedulerPriority.h from React-callinvoker).
public enum SchedulerPriority: Int32 {
case immediate = 1
case userBlocking = 2
case normal = 3
case low = 4
case idle = 5
}
internal final class JavaScriptEvalException: GenericException<NSError> {
override var reason: String {
return param.userInfo["message"] as? String ?? "unknown reason"
}
}

View File

@@ -0,0 +1,141 @@
// Copyright 2022-present 650 Industries. All rights reserved.
/**
Enum with available kinds of values. It's almost the same as a result of "typeof"
in JavaScript, however `null` has its own kind (typeof null == "object").
*/
public enum JavaScriptValueKind: String {
case undefined
case null
case bool
case number
case symbol
case string
case function
case object
}
/**
A protocol that JavaScript values, objects and functions can conform to.
*/
public protocol AnyJavaScriptValue: AnyArgument {
/**
Tries to convert a raw JavaScript value to the conforming type.
*/
static func convert(from value: JavaScriptValue, appContext: AppContext) throws -> Self
}
extension AnyJavaScriptValue {
public static func getDynamicType() -> AnyDynamicType {
return DynamicJavaScriptType(innerType: Self.self)
}
}
extension JavaScriptValue: AnyJavaScriptValue, AnyArgument {
public var kind: JavaScriptValueKind {
switch true {
case isUndefined():
return .undefined
case isNull():
return .null
case isBool():
return .bool
case isNumber():
return .number
case isSymbol():
return .symbol
case isString():
return .string
case isFunction():
return .function
default:
return .object
}
}
func asBool() throws -> Bool {
if isBool() {
return getBool()
}
throw JavaScriptValueConversionException((kind: kind, target: "Bool"))
}
func asInt() throws -> Int {
if isNumber() {
return getInt()
}
throw JavaScriptValueConversionException((kind: kind, target: "Int"))
}
func asDouble() throws -> Double {
if isNumber() {
return getDouble()
}
throw JavaScriptValueConversionException((kind: kind, target: "Double"))
}
func asString() throws -> String {
if isString() {
return getString()
}
throw JavaScriptValueConversionException((kind: kind, target: "String"))
}
func asArray() throws -> [JavaScriptValue?] {
if isObject() {
return getArray()
}
throw JavaScriptValueConversionException((kind: kind, target: "Array"))
}
func asDict() throws -> [String: Any] {
if isObject() {
return getDictionary()
}
throw JavaScriptValueConversionException((kind: kind, target: "Dict"))
}
func asObject() throws -> JavaScriptObject {
if isObject() {
return getObject()
}
throw JavaScriptValueConversionException((kind: kind, target: "Object"))
}
func asFunction() throws -> RawJavaScriptFunction {
if isFunction() {
return getFunction()
}
throw JavaScriptValueConversionException((kind: kind, target: "Function"))
}
func asTypedArray() throws -> JavaScriptTypedArray {
if let typedArray = getTypedArray() {
return typedArray
}
throw JavaScriptValueConversionException((kind: kind, target: "TypedArray"))
}
func asArrayBuffer() throws -> JavaScriptArrayBuffer {
if let backingBuffer = getArrayBuffer() {
return JavaScriptArrayBuffer(backingBuffer)
}
throw JavaScriptValueConversionException((kind: kind, target: "ArrayBuffer"))
}
// MARK: - AnyJavaScriptValue
public static func convert(from value: JavaScriptValue, appContext: AppContext) throws -> Self {
// It's already a `JavaScriptValue` so it should always pass through.
if let value = value as? Self {
return value
}
throw JavaScriptValueConversionException((kind: value.kind, target: String(describing: Self.self)))
}
}
internal final class JavaScriptValueConversionException: GenericException<(kind: JavaScriptValueKind, target: String)> {
override var reason: String {
"Cannot represent a value of kind '\(param.kind)' as \(param.target)"
}
}