Support Dict

This commit is contained in:
ventywing
2023-07-04 16:48:13 +03:00
parent c305e43cec
commit f62da0cbcf
12 changed files with 746 additions and 84 deletions
@@ -248,7 +248,10 @@ public final class ExpressionResolver {
)
}
private lazy var supportedFunctions: [AnyCalcExpression.Symbol: AnyCalcExpression.SymbolEvaluator] =
private lazy var supportedFunctions: [
AnyCalcExpression.Symbol: AnyCalcExpression
.SymbolEvaluator
] =
_supportedFunctions + ValueFunctions.allCases.map { $0.getDeclaration(resolver: self) }.flat()
}
@@ -259,6 +262,7 @@ private let _supportedFunctions: [AnyCalcExpression.Symbol: AnyCalcExpression.Sy
+ DatetimeFunctions.allCases.map(\.declaration).flat()
+ MathFunctions.allCases.map(\.declaration).flat()
+ IntervalFunctions.allCases.map(\.declaration).flat()
+ DictFunctions.allCases.map(\.declaration).flat()
extension ExpressionResolver: ConstantsProvider {
func getValue(_ name: String) -> Any? {
@@ -7,6 +7,8 @@ enum CastFunctions: String, CaseIterable {
case toString
case toNumber
case toInteger
case toColor
case toUrl
var declaration: [AnyCalcExpression.Symbol: AnyCalcExpression.SymbolEvaluator] {
[.function(rawValue, arity: function.arity): function.symbolEvaluator]
@@ -58,6 +60,10 @@ enum CastFunctions: String, CaseIterable {
AnyCalcExpression.Error.toInteger($0.first)
}
)
case .toColor:
return FunctionUnary(impl: _stringToColor)
case .toUrl:
return FunctionUnary(impl: _stringToUrl)
}
}
}
@@ -136,6 +142,20 @@ private func _doubleToInteger(value: Double) throws -> Int {
return number
}
private func _stringToColor(value: String) throws -> Color {
guard let color = Color.color(withHexString: value) else {
throw AnyCalcExpression.Error.toColor(value)
}
return color
}
private func _stringToUrl(value: String) throws -> URL {
guard let url = URL(string: value) else {
throw AnyCalcExpression.Error.toUrl(value)
}
return url
}
extension Bool {
fileprivate func toInteger() -> Int {
switch self {
@@ -206,6 +226,18 @@ extension AnyCalcExpression.Error {
)
}
fileprivate static func toColor(_ value: String) -> AnyCalcExpression.Error {
.message(
"Failed to evaluate [toColor('\(value)')]. Unable to convert value to Color, expected format #AARRGGBB."
)
}
fileprivate static func toUrl(_ value: String) -> AnyCalcExpression.Error {
.message(
"Failed to evaluate [toUrl('\(value)')]. Unable to convert value to URL."
)
}
private static func formatValue(_ value: Any?) -> String {
switch value {
case let strValue as String:
@@ -0,0 +1,335 @@
import CommonCorePublic
import Foundation
enum DictFunctions: String, CaseIterable {
case getDictString
case getDictNumber
case getDictInteger
case getDictBoolean
case getDictColor
case getDictUrl
case getDictOptString
case getDictOptNumber
case getDictOptInteger
case getDictOptBoolean
case getDictOptColor
case getDictOptUrl
var declaration: [AnyCalcExpression.Symbol: AnyCalcExpression.SymbolEvaluator] {
[.function(rawValue, arity: function.arity): function.symbolEvaluator]
}
var function: Function {
switch self {
case .getDictString:
return FunctionVarBinary(impl: _getDictString)
case .getDictNumber:
return FunctionVarBinary(impl: _getDictNumber)
case .getDictInteger:
return FunctionVarBinary(impl: _getDictInteger)
case .getDictBoolean:
return FunctionVarBinary(impl: _getDictBoolean)
case .getDictColor:
return FunctionVarBinary(impl: _getDictColor)
case .getDictUrl:
return FunctionVarBinary(impl: _getDictUrl)
case .getDictOptString:
return FunctionVarTernary(impl: _getDictOptString)
case .getDictOptNumber:
return FunctionVarTernary(impl: _getDictOptNumber)
case .getDictOptInteger:
return FunctionVarTernary(impl: _getDictOptInteger)
case .getDictOptBoolean:
return FunctionVarTernary(impl: _getDictOptBoolean)
case .getDictOptColor:
return OverloadedFunction(
functions: [
FunctionVarTernary(impl: _getDictOptColorWithColorFallback),
FunctionVarTernary(impl: _getDictOptColorWithStringFallback),
]
)
case .getDictOptUrl:
return OverloadedFunction(
functions: [
FunctionVarTernary(impl: _getDictOptUrlWithURLFallback),
FunctionVarTernary(impl: _getDictOptUrlWithStringFallback),
]
)
}
}
private func _getDictString(dict: [String: AnyHashable], path: [String]) throws -> String {
let expression = makeExpression("getDictString", path)
let result = try getProp(
dict: dict,
path: path,
expression: expression
)
guard let stringValue = result as? String else {
throw Error.incorrectValueType(expression, "string", getActualType(result)).message
}
return stringValue
}
private func _getDictNumber(dict: [String: AnyHashable], path: [String]) throws -> Double {
let expression = makeExpression("getDictNumber", path)
let result = try getProp(
dict: dict,
path: path,
expression: expression
)
if result.isBool {
throw Error.incorrectValueType(expression, "number", getActualType(result)).message
}
if let numberValue = result as? Double {
return numberValue
}
if let intValue = result as? Int {
return Double(intValue)
}
throw Error.incorrectValueType(expression, "number", getActualType(result)).message
}
private func _getDictInteger(dict: [String: AnyHashable], path: [String]) throws -> Int {
let expression = makeExpression("getDictInteger", path)
let result = try getProp(
dict: dict,
path: path,
expression: expression
)
if result.isBool {
throw Error.incorrectValueType(expression, "integer", getActualType(result)).message
}
guard let intValue = result as? Int else {
if let doubleValue = result as? Double {
if doubleValue < Double(Int.min) || doubleValue > Double(Int.max) {
throw Error.integerOverflow(expression).message
}
throw Error.cannotConvertToInteger(expression).message
}
throw Error.incorrectValueType(expression, "integer", getActualType(result)).message
}
return intValue
}
private func _getDictBoolean(dict: [String: AnyHashable], path: [String]) throws -> Bool {
let expression = makeExpression("getDictBoolean", path)
let result = try getProp(
dict: dict,
path: path,
expression: expression
)
guard result.isBool else {
throw Error.incorrectValueType(expression, "boolean", getActualType(result)).message
}
guard let boolValue = result as? Bool else {
throw Error.incorrectValueType(expression, "boolean", getActualType(result)).message
}
return boolValue
}
private func _getDictColor(dict: [String: AnyHashable], path: [String]) throws -> Color {
let expression = makeExpression("getDictColor", path)
let result = try getProp(
dict: dict,
path: path,
expression: expression
)
guard let stringValue = result as? String else {
throw Error.incorrectValueType(expression, "color", getActualType(result)).message
}
guard let color = Color.color(withHexString: stringValue) else {
throw Error.incorrectColorFormat(expression).message
}
return color
}
private func _getDictUrl(dict: [String: AnyHashable], path: [String]) throws -> URL {
let expression = makeExpression("getDictUrl", path)
let result = try getProp(
dict: dict,
path: path,
expression: expression
)
guard let stringValue = result as? String else {
throw Error.incorrectValueType(expression, "url", getActualType(result)).message
}
guard let url = URL(string: stringValue) else {
throw Error.incorrectValueType(expression, "url", getActualType(result)).message
}
return url
}
private func _getDictOptString(
fallback: String,
dict: [String: AnyHashable],
path: [String]
) -> String {
guard let value = try? _getDictString(dict: dict, path: path) else {
return fallback
}
return value
}
private func _getDictOptNumber(
fallback: Double,
dict: [String: AnyHashable],
path: [String]
) -> Double {
guard let value = try? _getDictNumber(dict: dict, path: path) else {
return fallback
}
return value
}
private func _getDictOptInteger(
fallback: Int,
dict: [String: AnyHashable],
path: [String]
) -> Int {
guard let value = try? _getDictInteger(dict: dict, path: path) else {
return fallback
}
return value
}
private func _getDictOptBoolean(
fallback: Bool,
dict: [String: AnyHashable],
path: [String]
) -> Bool {
guard let value = try? _getDictBoolean(dict: dict, path: path) else {
return fallback
}
return value
}
private func _getDictOptColorWithColorFallback(
fallback: Color,
dict: [String: AnyHashable],
path: [String]
) -> Color {
guard let value = try? _getDictColor(dict: dict, path: path) else {
return fallback
}
return value
}
private func _getDictOptColorWithStringFallback(
fallback: String,
dict: [String: AnyHashable],
path: [String]
) -> Color {
guard let value = try? _getDictColor(dict: dict, path: path) else {
return Color.color(withHexString: fallback)!
}
return value
}
private func _getDictOptUrlWithURLFallback(
fallback: URL,
dict: [String: AnyHashable],
path: [String]
) -> URL {
guard let value = try? _getDictUrl(dict: dict, path: path) else {
return fallback
}
return value
}
private func _getDictOptUrlWithStringFallback(
fallback: String,
dict: [String: AnyHashable],
path: [String]
) -> URL {
guard let value = try? _getDictUrl(dict: dict, path: path) else {
return URL(string: fallback)!
}
return value
}
private func getProp(
dict: [String: AnyHashable],
path: [String],
expression: String
) throws -> AnyHashable {
var dictionary: [String: AnyHashable]? = dict
var i = 0
while i < path.count - 1 {
let key = path[i]
if let current = dictionary {
dictionary = current[key] as? [String: AnyHashable]
} else {
throw Error.missingProperty(expression, key).message
}
i += 1
}
guard let key = path.last else {
throw Error.wrongPath(expression).message
}
if let current = dictionary,
let result = current[key] {
return result
} else {
throw Error.missingProperty(expression, key).message
}
}
}
private func getActualType(_ value: AnyHashable) -> String {
if value.isBool {
return "boolean"
}
switch value {
case is [String: AnyHashable]:
return "dict"
case is [Any]:
return "array"
case is String:
return "string"
case is Int, is Double:
return "number"
default:
return "null"
}
}
private func makeExpression(_ function: String, _ path: [String]) -> String {
"\(function)(<dict>, \(path.map { "'\($0)'" }.joined(separator: ", ")))"
}
private enum Error {
case missingProperty(String, String)
case wrongPath(String)
case incorrectValueType(String, String, String)
case cannotConvertToInteger(String)
case integerOverflow(String)
case incorrectColorFormat(String)
private var description: String {
switch self {
case let .missingProperty(expression, missing):
return "Failed to evaluate [\(expression)]. Missing property \"\(missing)\" in the dict."
case let .wrongPath(expression):
return "Failed to evaluate [\(expression)]. Path is wrong."
case let .incorrectValueType(expression, expectedType, actualType):
return "Failed to evaluate [\(expression)]. Incorrect value type: expected \"\(expectedType)\", got \"\(actualType)\"."
case let .cannotConvertToInteger(expression):
return "Failed to evaluate [\(expression)]. Cannot convert value to integer."
case let .integerOverflow(expression):
return "Failed to evaluate [\(expression)]. Integer overflow."
case let .incorrectColorFormat(expression):
return "Failed to evaluate [\(expression)]. Unable to convert value to Color, expected format #AARRGGBB."
}
}
var message: AnyCalcExpression.Error {
AnyCalcExpression.Error.message(description)
}
}
extension AnyHashable {
fileprivate var isBool: Bool {
Bool(description) != nil && !(self is String)
}
}
@@ -180,6 +180,63 @@ struct FunctionVarUnary<T1, R>: SimpleFunction {
}
}
struct FunctionVarBinary<T1, T2, R>: SimpleFunction {
private let impl: (T1, [T2]) throws -> R
var signature: FunctionSignature {
get throws {
.init(
arguments: [
.init(type: try .from(type: T1.self)),
.init(type: try .from(type: T2.self), vararg: true),
],
resultType: try .from(type: R.self)
)
}
}
init(impl: @escaping (T1, [T2]) throws -> R) {
self.impl = impl
}
func invoke(args: [Any]) throws -> Any {
guard let v1 = args[0] as? T1 else {
throw FunctionSignature.Error.arityMismatch.message
}
let v2 = args.dropFirst().map { $0 as! T2 }
return try impl(v1, v2)
}
}
struct FunctionVarTernary<T1, T2, T3, R>: SimpleFunction {
private let impl: (T1, T2, [T3]) throws -> R
var signature: FunctionSignature {
get throws {
.init(
arguments: [
.init(type: try .from(type: T1.self)),
.init(type: try .from(type: T2.self)),
.init(type: try .from(type: T3.self), vararg: true),
],
resultType: try .from(type: R.self)
)
}
}
init(impl: @escaping (T1, T2, [T3]) throws -> R) {
self.impl = impl
}
func invoke(args: [Any]) throws -> Any {
guard let v1 = args[0] as? T1, let v2 = args[1] as? T2 else {
throw FunctionSignature.Error.arityMismatch.message
}
let v3 = args.dropFirst(2).map { $0 as! T3 }
return try impl(v1, v2, v3)
}
}
struct OverloadedFunction: Function {
let functions: [SimpleFunction]
let makeError: ([Any]) -> Error
@@ -257,7 +314,7 @@ struct FunctionSignature: Decodable {
case .url:
return URL.self
case .dict:
return [String: Any].self
return [String: AnyHashable].self
}
}
@@ -13,6 +13,7 @@ public enum DivVariableValue: Equatable {
case bool(Bool)
case color(Color)
case url(URL)
case dict([String: AnyHashable])
@inlinable
public func typedValue<T>() -> T? {
@@ -29,6 +30,8 @@ public enum DivVariableValue: Equatable {
return value as? T
case let .url(value):
return value as? T
case let .dict(value):
return value as? T
}
}
}
@@ -80,7 +83,7 @@ public final class DivVariablesStorage {
let variable = storage.local[cardId]?[name] ?? storage.global[name]
return variable?.typedValue()
}
public func set(
cardId: DivCardID,
variables: DivVariables
@@ -254,6 +257,9 @@ extension Dictionary where Key == DivVariableName, Value == DivVariableValue {
} else {
newValue = nil
}
case .dict:
newValue = nil
DivKitLogger.warning("Unsupported variable type: dict")
}
if newValue == oldValue {
@@ -300,8 +306,15 @@ extension Collection where Element == DivVariable {
let name = DivVariableName(rawValue: urlVariable.name)
if variables.keys.contains(name) { return }
variables[name] = .url(urlVariable.value)
case .dictVariable:
DivKitLogger.warning("Unsupported variable type: dict")
case let .dictVariable(dictVariable):
let name = DivVariableName(rawValue: dictVariable.name)
if variables.keys.contains(name) { return }
if let dictionary = NSDictionary(dictionary: dictVariable.value) as? [String: AnyHashable] {
variables[name] = .dict(dictionary)
} else {
DivKitLogger.error("Incorrect value for dict variable \(name): \(dictVariable.value)")
variables[name] = .dict([:])
}
}
}
return variables
@@ -61,6 +61,18 @@ final class ExpressionResolvingTests: XCTestCase {
perform(on: testCases, type: type)
}
func test_Functions_To_Color() throws {
let testCases = try makeTestCases(for: "functions_to_color")
let type: ExpressionType<String> = .stringBased(initializer: { $0 })
perform(on: testCases, type: type)
}
func test_Functions_To_Url() throws {
let testCases = try makeTestCases(for: "functions_to_url")
let type: ExpressionType<String> = .stringBased(initializer: { $0 })
perform(on: testCases, type: type)
}
func test_Functions_Datetime() throws {
let testCases = try makeTestCases(for: "functions_datetime")
let type: ExpressionType<String> = .singleItem
@@ -73,6 +85,12 @@ final class ExpressionResolvingTests: XCTestCase {
perform(on: testCases, type: type)
}
func test_Functions_Dict() throws {
let testCases = try makeTestCases(for: "functions_dict")
let type: ExpressionType<String> = .stringBased(initializer: { $0 })
perform(on: testCases, type: type)
}
func test_Functions_Interval() throws {
let testCases = try makeTestCases(for: "functions_interval")
let type: ExpressionType<String> = .stringBased(initializer: { $0 })
@@ -514,6 +532,9 @@ extension DivVariable: Decodable {
case UrlVariable.type:
let value = try container.decode(String.self, forKey: .value)
self = .urlVariable(UrlVariable(name: name, value: URL(string: value)!))
case DictVariable.type:
let dict = try container.decode(Dict.self, forKey: .value)
self = .dictVariable(DictVariable(name: name, value: dict.value))
default:
throw DecodingError.valueNotFound(
String.self,
@@ -529,3 +550,79 @@ extension DivVariable: Decodable {
case type, name, value
}
}
fileprivate struct JSONCodingKeys: CodingKey {
var stringValue: String
init(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int?
init?(intValue: Int) {
self.init(stringValue: "\(intValue)")
self.intValue = intValue
}
}
fileprivate struct Dict: Decodable {
var value: [String: Any] = [:]
public init(from decoder: Decoder) throws {
if let container = try? decoder.container(keyedBy: JSONCodingKeys.self) {
self.value = decode(fromObject: container)
}
}
func decode(fromObject container: KeyedDecodingContainer<JSONCodingKeys>) -> [String: Any] {
var result: [String: Any] = [:]
for key in container.allKeys {
if let val = try? container.decode(Int.self, forKey: key) {
result[key.stringValue] = val
} else if let val = try? container.decode(Double.self, forKey: key) {
result[key.stringValue] = val
} else if let val = try? container.decode(String.self, forKey: key) {
result[key.stringValue] = val
} else if let val = try? container.decode(Bool.self, forKey: key) {
result[key.stringValue] = val
} else if let nestedContainer = try? container.nestedContainer(
keyedBy: JSONCodingKeys.self,
forKey: key
) {
result[key.stringValue] = decode(fromObject: nestedContainer)
} else if var nestedArray = try? container.nestedUnkeyedContainer(forKey: key) {
result[key.stringValue] = decode(fromArray: &nestedArray)
} else if (try? container.decodeNil(forKey: key)) == true {
result.updateValue(Any?(nil) as Any, forKey: key.stringValue)
}
}
return result
}
func decode(fromArray container: inout UnkeyedDecodingContainer) -> [Any] {
var result: [Any] = []
while !container.isAtEnd {
if let value = try? container.decode(String.self) {
result.append(value)
} else if let value = try? container.decode(Int.self) {
result.append(value)
} else if let value = try? container.decode(Double.self) {
result.append(value)
} else if let value = try? container.decode(Bool.self) {
result.append(value)
} else if let nestedContainer = try? container.nestedContainer(keyedBy: JSONCodingKeys.self) {
result.append(decode(fromObject: nestedContainer))
} else if var nestedArray = try? container.nestedUnkeyedContainer() {
result.append(decode(fromArray: &nestedArray))
} else if (try? container.decodeNil()) == true {
result.append(Any?(nil) as Any)
}
}
return result
}
}
@@ -26,9 +26,10 @@ private let functions: [String: Function] = {
var result = [String: Function]()
DatetimeFunctions.allCases.forEach { result[$0.rawValue] = $0.function }
ColorFunctions.allCases.forEach { result[$0.rawValue] = $0.function }
StringFunctions.allCases.forEach { result[$0.rawValue] = $0.function}
CastFunctions.allCases.forEach { result[$0.rawValue] = $0.function }
StringFunctions.allCases.forEach { result[$0.rawValue] = $0.function }
CastFunctions.allCases.forEach { result[$0.rawValue] = $0.function }
MathFunctions.allCases.forEach { result[$0.rawValue] = $0.function }
DictFunctions.allCases.forEach { result[$0.rawValue] = $0.function }
IntervalFunctions.allCases.forEach { result[$0.rawValue] = $0.function }
ValueFunctions.allCases.forEach {
result[$0.rawValue] = $0.getFunction(resolver: ExpressionResolver(variables: [:]))
+4 -1
View File
@@ -202,7 +202,10 @@
},
{
"$ref": "#/definitions/dict_variable",
"platforms": []
"platforms": [
"web",
"ios"
]
}
]
}
@@ -215,7 +215,8 @@
],
"result_type": "color",
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -230,7 +231,8 @@
],
"result_type": "url",
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -416,7 +418,8 @@
],
"result_type": "string",
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -436,7 +439,8 @@
],
"result_type": "number",
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -456,7 +460,8 @@
],
"result_type": "integer",
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -476,7 +481,8 @@
],
"result_type": "boolean",
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -496,7 +502,8 @@
],
"result_type": "color",
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -516,7 +523,8 @@
],
"result_type": "url",
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -540,7 +548,8 @@
],
"result_type": "string",
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -564,7 +573,8 @@
],
"result_type": "number",
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -588,7 +598,8 @@
],
"result_type": "integer",
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -612,7 +623,8 @@
],
"result_type": "boolean",
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -636,7 +648,8 @@
],
"result_type": "color",
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -660,7 +673,8 @@
],
"result_type": "color",
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -684,7 +698,8 @@
],
"result_type": "url",
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -708,7 +723,8 @@
],
"result_type": "url",
"platforms": [
"web"
"web",
"ios"
]
}
]
@@ -37,7 +37,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -57,7 +58,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -79,7 +81,33 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
"name": "getDictString(dict, 'prop', 'prop2', 'prop3') => 'val'",
"expression": "@{getDictString(dict, 'prop', 'prop2', 'prop3')}",
"expected": {
"type": "string",
"value": "val"
},
"variables": [
{
"type": "dict",
"name": "dict",
"value": {
"prop": {
"prop2": {
"prop3": "val"
}
}
}
}
],
"platforms": [
"web",
"ios"
]
},
{
@@ -101,7 +129,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -121,7 +150,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -143,7 +173,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -163,7 +194,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -183,7 +215,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -203,7 +236,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -223,7 +257,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -243,7 +278,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -263,7 +299,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -283,7 +320,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -303,7 +341,29 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
"name": "getDictNumber(dict, 'prop') => error (2)",
"expression": "@{getDictNumber(dict, 'prop')}",
"expected": {
"type": "error",
"value": "Failed to evaluate [getDictNumber(<dict>, 'prop')]. Incorrect value type: expected \"number\", got \"string\"."
},
"variables": [
{
"type": "dict",
"name": "dict",
"value": {
"prop": "val"
}
}
],
"platforms": [
"web",
"ios"
]
},
{
@@ -323,7 +383,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -343,7 +404,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -363,7 +425,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -383,7 +446,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -398,12 +462,13 @@
"type": "dict",
"name": "dict",
"value": {
"prop": 9223372036854775808
"prop": 9223372036854775808000000000000000000000
}
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -423,7 +488,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -443,7 +509,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -463,7 +530,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -483,7 +551,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -503,7 +572,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -523,7 +593,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -543,7 +614,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -563,7 +635,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -583,7 +656,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -603,7 +677,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -625,7 +700,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -645,7 +721,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -667,7 +744,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -687,7 +765,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -707,7 +786,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -727,7 +807,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -747,7 +828,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -767,7 +849,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -787,7 +870,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -807,7 +891,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -827,7 +912,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -847,7 +933,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -867,7 +954,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -882,12 +970,13 @@
"type": "dict",
"name": "dict",
"value": {
"prop": 9223372036854775808
"prop": 922337203685477580800
}
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -907,7 +996,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -927,7 +1017,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -947,7 +1038,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -967,7 +1059,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -987,7 +1080,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -1007,7 +1101,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -1027,7 +1122,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -1047,7 +1143,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -1067,7 +1164,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -1087,7 +1185,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -1107,7 +1206,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -1127,7 +1227,8 @@
}
],
"platforms": [
"web"
"web",
"ios"
]
}
]
@@ -9,7 +9,8 @@
},
"variables": [],
"platforms": [
"web"
"web",
"ios"
]
},
{
@@ -21,7 +22,8 @@
},
"variables": [],
"platforms": [
"web"
"web",
"ios"
]
}
]
@@ -9,7 +9,8 @@
},
"variables": [],
"platforms": [
"web"
"web",
"ios"
]
}
]