1 // Copyright 2022-present 650 Industries. All rights reserved.
2 
3 /**
4  Enum with available kinds of values. It's almost the same as a result of "typeof"
5  in JavaScript, however `null` has its own kind (typeof null == "object").
6  */
7 public enum JavaScriptValueKind: String {
8   case undefined
9   case null
10   case bool
11   case number
12   case symbol
13   case string
14   case function
15   case object
16 }
17 
18 public extension JavaScriptValue {
19   var kind: JavaScriptValueKind {
20     switch true {
21     case isUndefined():
22       return .undefined
23     case isNull():
24       return .null
25     case isBool():
26       return .bool
27     case isNumber():
28       return .number
29     case isSymbol():
30       return .symbol
31     case isString():
32       return .string
33     case isFunction():
34       return .function
35     default:
36       return .object
37     }
38   }
39 
40   func asBool() throws -> Bool {
41     if isBool() {
42       return getBool()
43     }
44     throw JavaScriptValueConversionException((kind: kind, target: "Bool"))
45   }
46 
47   func asInt() throws -> Int {
48     if isNumber() {
49       return getInt()
50     }
51     throw JavaScriptValueConversionException((kind: kind, target: "Int"))
52   }
53 
54   func asDouble() throws -> Double {
55     if isNumber() {
56       return getDouble()
57     }
58     throw JavaScriptValueConversionException((kind: kind, target: "Double"))
59   }
60 
61   func asString() throws -> String {
62     if isString() {
63       return getString()
64     }
65     throw JavaScriptValueConversionException((kind: kind, target: "String"))
66   }
67 
68   func asArray() throws -> [JavaScriptValue?] {
69     if isObject() {
70       return getArray()
71     }
72     throw JavaScriptValueConversionException((kind: kind, target: "Array"))
73   }
74 
75   func asDict() throws -> [String: Any] {
76     if isObject() {
77       return getDictionary()
78     }
79     throw JavaScriptValueConversionException((kind: kind, target: "Dict"))
80   }
81 
82   func asObject() throws -> JavaScriptObject {
83     if isObject() {
84       return getObject()
85     }
86     throw JavaScriptValueConversionException((kind: kind, target: "Object"))
87   }
88 
89   func asTypedArray() throws -> JavaScriptTypedArray {
90     if let typedArray = getTypedArray() {
91       return typedArray
92     }
93     throw JavaScriptValueConversionException((kind: kind, target: "TypedArray"))
94   }
95 }
96 
97 internal final class JavaScriptValueConversionException: GenericException<(kind: JavaScriptValueKind, target: String)> {
98   override var reason: String {
99     "Cannot represent a value of kind '\(param.kind)' as \(param.target)"
100   }
101 }
102