Skip to content

Commit f545114

Browse files
committed
✨ Implement Argument Encoding
- Fix Date encoding in unkeyed/keyed containers - Add tests for keyed encoding
1 parent 1a7297d commit f545114

File tree

9 files changed

+818
-168
lines changed

9 files changed

+818
-168
lines changed

JavaScriptKit.xcodeproj/project.pbxproj

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
/* Begin PBXBuildFile section */
1010
551B2F6D1F5A9466009AE800 /* JSResultDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 551B2F6C1F5A9466009AE800 /* JSResultDecoder.swift */; };
1111
551B2F6E1F5A9466009AE800 /* JSResultDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 551B2F6C1F5A9466009AE800 /* JSResultDecoder.swift */; };
12+
5530C2FD1F5D8429005A97C9 /* JSSingleValueDecoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5530C2FC1F5D8429005A97C9 /* JSSingleValueDecoderTests.swift */; };
13+
5530C2FE1F5D8429005A97C9 /* JSSingleValueDecoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5530C2FC1F5D8429005A97C9 /* JSSingleValueDecoderTests.swift */; };
14+
5530C3001F5DAC73005A97C9 /* JSKeyedEncodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5530C2FF1F5DAC73005A97C9 /* JSKeyedEncodingTests.swift */; };
15+
5530C3011F5DAC73005A97C9 /* JSKeyedEncodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5530C2FF1F5DAC73005A97C9 /* JSKeyedEncodingTests.swift */; };
1216
5543E4931F5736D80057E28B /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5543E4911F5736BF0057E28B /* Result.framework */; };
1317
5543E4951F5736E50057E28B /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5543E4941F5736E50057E28B /* Result.framework */; };
1418
5543E4961F5737370057E28B /* JavaScriptKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 556E88E71F556EF70031476D /* JavaScriptKit.framework */; };
@@ -35,8 +39,8 @@
3539
55BFFFD51F57EF6400F13633 /* JSArgumentEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55BFFFD31F57EF6400F13633 /* JSArgumentEncoder.swift */; };
3640
55C410B51F5AB39F008B0B0E /* JSSingleValueEncoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C410B41F5AB39F008B0B0E /* JSSingleValueEncoderTests.swift */; };
3741
55C410B61F5AB39F008B0B0E /* JSSingleValueEncoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C410B41F5AB39F008B0B0E /* JSSingleValueEncoderTests.swift */; };
38-
55C410B81F5AEF6C008B0B0E /* JSMockData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C410B71F5AEF6C008B0B0E /* JSMockData.swift */; };
39-
55C410B91F5AEF6C008B0B0E /* JSMockData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C410B71F5AEF6C008B0B0E /* JSMockData.swift */; };
42+
55C410B81F5AEF6C008B0B0E /* CodableModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C410B71F5AEF6C008B0B0E /* CodableModels.swift */; };
43+
55C410B91F5AEF6C008B0B0E /* CodableModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C410B71F5AEF6C008B0B0E /* CodableModels.swift */; };
4044
55DAE6AD1F546C22009593AF /* JavaScriptKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55DAE6A31F546C21009593AF /* JavaScriptKit.framework */; };
4145
55DAE6C91F546C9F009593AF /* JSVariable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DAE6C31F546C9F009593AF /* JSVariable.swift */; };
4246
55DAE6CA1F546C9F009593AF /* JSErrorDomain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55DAE6C41F546C9F009593AF /* JSErrorDomain.swift */; };
@@ -93,6 +97,8 @@
9397

9498
/* Begin PBXFileReference section */
9599
551B2F6C1F5A9466009AE800 /* JSResultDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSResultDecoder.swift; sourceTree = "<group>"; };
100+
5530C2FC1F5D8429005A97C9 /* JSSingleValueDecoderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSSingleValueDecoderTests.swift; sourceTree = "<group>"; };
101+
5530C2FF1F5DAC73005A97C9 /* JSKeyedEncodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSKeyedEncodingTests.swift; sourceTree = "<group>"; };
96102
5543E48A1F57336D0057E28B /* JavaScriptKit.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = JavaScriptKit.podspec; sourceTree = "<group>"; };
97103
5543E48B1F57336D0057E28B /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
98104
5543E48C1F57336D0057E28B /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
@@ -107,7 +113,7 @@
107113
556E88FB1F556FDA0031476D /* JavaScriptKitTests-macOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "JavaScriptKitTests-macOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
108114
55BFFFD31F57EF6400F13633 /* JSArgumentEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSArgumentEncoder.swift; sourceTree = "<group>"; };
109115
55C410B41F5AB39F008B0B0E /* JSSingleValueEncoderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSSingleValueEncoderTests.swift; sourceTree = "<group>"; };
110-
55C410B71F5AEF6C008B0B0E /* JSMockData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSMockData.swift; sourceTree = "<group>"; };
116+
55C410B71F5AEF6C008B0B0E /* CodableModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableModels.swift; sourceTree = "<group>"; };
111117
55DAE6A31F546C21009593AF /* JavaScriptKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JavaScriptKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
112118
55DAE6AC1F546C22009593AF /* JavaScriptKitTests-iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "JavaScriptKitTests-iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
113119
55DAE6BE1F546C8B009593AF /* JavaScriptKitTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = JavaScriptKitTests.plist; sourceTree = "<group>"; };
@@ -172,6 +178,14 @@
172178
path = Codable;
173179
sourceTree = "<group>";
174180
};
181+
5530C2FB1F5D8415005A97C9 /* Decoder */ = {
182+
isa = PBXGroup;
183+
children = (
184+
5530C2FC1F5D8429005A97C9 /* JSSingleValueDecoderTests.swift */,
185+
);
186+
path = Decoder;
187+
sourceTree = "<group>";
188+
};
175189
5543E48D1F5733730057E28B /* Library Metadata */ = {
176190
isa = PBXGroup;
177191
children = (
@@ -188,6 +202,7 @@
188202
children = (
189203
55C410B41F5AB39F008B0B0E /* JSSingleValueEncoderTests.swift */,
190204
556987D31F5BF31700FC4E07 /* JSUnkeyedEncoderTests.swift */,
205+
5530C2FF1F5DAC73005A97C9 /* JSKeyedEncodingTests.swift */,
191206
);
192207
path = Encoder;
193208
sourceTree = "<group>";
@@ -267,8 +282,9 @@
267282
55DAE6D21F546CB5009593AF /* JavaScriptKit */ = {
268283
isa = PBXGroup;
269284
children = (
270-
55C410B71F5AEF6C008B0B0E /* JSMockData.swift */,
285+
55C410B71F5AEF6C008B0B0E /* CodableModels.swift */,
271286
556987D61F5C0B4700FC4E07 /* Encoder */,
287+
5530C2FB1F5D8415005A97C9 /* Decoder */,
272288
55DAE6D31F546CB5009593AF /* JSExecutionTests.swift */,
273289
55DAE6D41F546CB5009593AF /* JSGenericExpressionTests.swift */,
274290
55DAE6D51F546CB5009593AF /* JSConcreteExpressionTests.swift */,
@@ -490,7 +506,9 @@
490506
isa = PBXSourcesBuildPhase;
491507
buildActionMask = 2147483647;
492508
files = (
493-
55C410B91F5AEF6C008B0B0E /* JSMockData.swift in Sources */,
509+
5530C3011F5DAC73005A97C9 /* JSKeyedEncodingTests.swift in Sources */,
510+
55C410B91F5AEF6C008B0B0E /* CodableModels.swift in Sources */,
511+
5530C2FE1F5D8429005A97C9 /* JSSingleValueDecoderTests.swift in Sources */,
494512
55C410B61F5AB39F008B0B0E /* JSSingleValueEncoderTests.swift in Sources */,
495513
556987D51F5BF31700FC4E07 /* JSUnkeyedEncoderTests.swift in Sources */,
496514
);
@@ -516,7 +534,9 @@
516534
isa = PBXSourcesBuildPhase;
517535
buildActionMask = 2147483647;
518536
files = (
519-
55C410B81F5AEF6C008B0B0E /* JSMockData.swift in Sources */,
537+
5530C3001F5DAC73005A97C9 /* JSKeyedEncodingTests.swift in Sources */,
538+
55C410B81F5AEF6C008B0B0E /* CodableModels.swift in Sources */,
539+
5530C2FD1F5D8429005A97C9 /* JSSingleValueDecoderTests.swift in Sources */,
520540
55C410B51F5AB39F008B0B0E /* JSSingleValueEncoderTests.swift in Sources */,
521541
556987D41F5BF31700FC4E07 /* JSUnkeyedEncoderTests.swift in Sources */,
522542
);

Sources/Codable/CodableSupport.swift

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ enum SingleValueStorage {
6363
/// An empty object.
6464
case emptyObject
6565

66-
var underlyingValue: Any {
66+
/// The stored value.
67+
var storedValue: Any {
6768

6869
switch self {
6970
case .null:
@@ -84,7 +85,11 @@ enum SingleValueStorage {
8485
return [String: Any]()
8586
}
8687

88+
}
8789

90+
/// The type of the stored value.
91+
var storedType: Any.Type {
92+
return type(of: storedValue)
8893
}
8994

9095
}
@@ -130,26 +135,6 @@ class ArrayStorage {
130135
array.insert(value, at: index)
131136
}
132137

133-
/// Appends the contents of a single value storage to the array.
134-
func appendSingleValue(_ storage: SingleValueStorage) {
135-
136-
switch storage {
137-
case .boolean(let bool):
138-
array.append(bool)
139-
case .double(let double):
140-
array.append(double)
141-
case .float(let float):
142-
array.append(float)
143-
case .integer(let integer):
144-
array.append(integer.intValue)
145-
case .string(let string):
146-
array.append(string)
147-
default:
148-
break
149-
}
150-
151-
}
152-
153138
}
154139

155140
// MARK: - Dictionary Storage
@@ -162,18 +147,18 @@ class ArrayStorage {
162147
class DictionaryStorage {
163148

164149
/// The underlying dictionary.
165-
var dictionary: [String: Any]
150+
var dictionary: [AnyHashable: Any]
166151

167152
// MARK: Initialization
168153

169154
/// Creates an empty dictionary storage.
170155
init() {
171-
dictionary = [String: Any]()
156+
dictionary = [AnyHashable: Any]()
172157
}
173158

174159
/// Creates a dictionary storage from an existing copy.
175160
init(_ dictionary: NSDictionary) {
176-
self.dictionary = dictionary as! [String: Any]
161+
self.dictionary = dictionary as! [AnyHashable: Any]
177162
}
178163

179164
// MARK: Dictionary Interaction
@@ -224,6 +209,24 @@ class AnyInteger {
224209
return intGenerator()
225210
}
226211

212+
/// Converts the integer to another integer type or returns `nil` if the target type is too
213+
/// small to contain the `intValue`.
214+
func convertingType<T: BinaryInteger & FixedWidthInteger>() -> T? {
215+
216+
let intValue = self.intValue
217+
218+
guard T.bitWidth <= Int.bitWidth else {
219+
return nil
220+
}
221+
222+
guard intValue >= T.min && intValue <= T.max else {
223+
return nil
224+
}
225+
226+
return T(intValue)
227+
228+
}
229+
227230
}
228231

229232
// MARK: - Escaping
@@ -240,26 +243,16 @@ extension String {
240243
escapableCharacters.insert(charactersIn: escapablePuntuation)
241244

242245
return unicodeScalars.reduce("") {
243-
current, next in
244-
let needsEscaping = escapableCharacters.contains(next)
245-
let nextString = needsEscaping ? next.escapingForJS : String(next)
246-
return current + nextString
246+
current, scalar in
247+
let needsEscaping = escapableCharacters.contains(scalar)
248+
let nextSequence = needsEscaping ? "\\u{\(String(scalar.value, radix: 16))}" : String(scalar)
249+
return current + nextSequence
247250
}
248251

249252
}
250253

251254
}
252255

253-
extension UnicodeScalar {
254-
255-
/// Escapes the Unicode code point for use in JavaScript.
256-
var escapingForJS: String {
257-
let hexString = String(value, radix: 16)
258-
return "\\u" + "{\(hexString)}"
259-
}
260-
261-
}
262-
263256
// MARK: - JSON Key
264257

265258
/// A key for JavaScript objects.

0 commit comments

Comments
 (0)