quicktype 17.0.4 → 17.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/CompressedJSONFromStream.js +38 -26
- package/dist/cli/GraphQLIntrospection.js +41 -33
- package/dist/cli/TypeSource.d.ts +1 -1
- package/dist/cli/URLGrammar.js +3 -4
- package/dist/cli/index.js +364 -363
- package/dist/quicktype-core/Annotation.js +0 -2
- package/dist/quicktype-core/ConvenienceRenderer.d.ts +17 -17
- package/dist/quicktype-core/ConvenienceRenderer.js +81 -104
- package/dist/quicktype-core/DateTime.js +0 -1
- package/dist/quicktype-core/DeclarationIR.d.ts +1 -1
- package/dist/quicktype-core/DeclarationIR.js +10 -13
- package/dist/quicktype-core/EncodedMarkovChain.js +0 -1
- package/dist/quicktype-core/GatherNames.js +25 -47
- package/dist/quicktype-core/Graph.d.ts +2 -2
- package/dist/quicktype-core/Graph.js +19 -23
- package/dist/quicktype-core/GraphRewriting.d.ts +2 -2
- package/dist/quicktype-core/GraphRewriting.js +54 -65
- package/dist/quicktype-core/MakeTransformations.js +22 -23
- package/dist/quicktype-core/MarkovChain.d.ts +3 -3
- package/dist/quicktype-core/MarkovChain.js +8 -9
- package/dist/quicktype-core/Messages.d.ts +3 -3
- package/dist/quicktype-core/Messages.js +3 -8
- package/dist/quicktype-core/Naming.d.ts +11 -11
- package/dist/quicktype-core/Naming.js +61 -76
- package/dist/quicktype-core/Renderer.d.ts +6 -6
- package/dist/quicktype-core/Renderer.js +17 -34
- package/dist/quicktype-core/RendererOptions.d.ts +5 -5
- package/dist/quicktype-core/RendererOptions.js +3 -6
- package/dist/quicktype-core/Run.d.ts +9 -9
- package/dist/quicktype-core/Run.js +67 -72
- package/dist/quicktype-core/Source.d.ts +3 -3
- package/dist/quicktype-core/Source.js +18 -19
- package/dist/quicktype-core/TargetLanguage.d.ts +10 -10
- package/dist/quicktype-core/TargetLanguage.js +2 -6
- package/dist/quicktype-core/Transformers.d.ts +25 -25
- package/dist/quicktype-core/Transformers.js +66 -94
- package/dist/quicktype-core/Type.d.ts +43 -41
- package/dist/quicktype-core/Type.js +71 -96
- package/dist/quicktype-core/TypeBuilder.d.ts +2 -2
- package/dist/quicktype-core/TypeBuilder.js +47 -53
- package/dist/quicktype-core/TypeGraph.d.ts +4 -4
- package/dist/quicktype-core/TypeGraph.js +40 -49
- package/dist/quicktype-core/TypeUtils.d.ts +2 -2
- package/dist/quicktype-core/TypeUtils.js +22 -23
- package/dist/quicktype-core/UnifyClasses.js +12 -16
- package/dist/quicktype-core/UnionBuilder.d.ts +3 -3
- package/dist/quicktype-core/UnionBuilder.js +30 -33
- package/dist/quicktype-core/attributes/AccessorNames.d.ts +2 -2
- package/dist/quicktype-core/attributes/AccessorNames.js +17 -18
- package/dist/quicktype-core/attributes/Constraints.d.ts +3 -3
- package/dist/quicktype-core/attributes/Constraints.js +4 -8
- package/dist/quicktype-core/attributes/Description.js +5 -6
- package/dist/quicktype-core/attributes/EnumValues.js +3 -4
- package/dist/quicktype-core/attributes/StringTypes.d.ts +1 -1
- package/dist/quicktype-core/attributes/StringTypes.js +21 -24
- package/dist/quicktype-core/attributes/TypeAttributes.d.ts +3 -3
- package/dist/quicktype-core/attributes/TypeAttributes.js +10 -12
- package/dist/quicktype-core/attributes/TypeNames.d.ts +9 -9
- package/dist/quicktype-core/attributes/TypeNames.js +21 -49
- package/dist/quicktype-core/attributes/URIAttributes.d.ts +1 -1
- package/dist/quicktype-core/attributes/URIAttributes.js +6 -10
- package/dist/quicktype-core/index.js +125 -128
- package/dist/quicktype-core/input/CompressedJSON.d.ts +7 -7
- package/dist/quicktype-core/input/CompressedJSON.js +54 -49
- package/dist/quicktype-core/input/FetchingJSONSchemaStore.js +13 -5
- package/dist/quicktype-core/input/Inference.d.ts +2 -2
- package/dist/quicktype-core/input/Inference.js +17 -25
- package/dist/quicktype-core/input/Inputs.d.ts +2 -2
- package/dist/quicktype-core/input/Inputs.js +54 -38
- package/dist/quicktype-core/input/JSONSchemaInput.d.ts +11 -11
- package/dist/quicktype-core/input/JSONSchemaInput.js +523 -503
- package/dist/quicktype-core/input/JSONSchemaStore.d.ts +1 -1
- package/dist/quicktype-core/input/JSONSchemaStore.js +35 -24
- package/dist/quicktype-core/input/PostmanCollection.js +1 -2
- package/dist/quicktype-core/input/io/NodeIO.js +44 -55
- package/dist/quicktype-core/input/io/get-stream/index.js +2 -6
- package/dist/quicktype-core/language/All.js +2 -3
- package/dist/quicktype-core/language/CPlusPlus.d.ts +12 -9
- package/dist/quicktype-core/language/CPlusPlus.js +249 -251
- package/dist/quicktype-core/language/CSharp.d.ts +7 -7
- package/dist/quicktype-core/language/CSharp.js +72 -82
- package/dist/quicktype-core/language/Crystal.d.ts +2 -2
- package/dist/quicktype-core/language/Crystal.js +17 -18
- package/dist/quicktype-core/language/Dart.d.ts +4 -4
- package/dist/quicktype-core/language/Dart.js +34 -36
- package/dist/quicktype-core/language/Elm.d.ts +6 -6
- package/dist/quicktype-core/language/Elm.js +45 -47
- package/dist/quicktype-core/language/Golang.d.ts +4 -4
- package/dist/quicktype-core/language/Golang.js +20 -23
- package/dist/quicktype-core/language/Haskell.d.ts +5 -5
- package/dist/quicktype-core/language/Haskell.js +23 -25
- package/dist/quicktype-core/language/JSONSchema.d.ts +3 -3
- package/dist/quicktype-core/language/JSONSchema.js +16 -17
- package/dist/quicktype-core/language/Java.d.ts +2 -2
- package/dist/quicktype-core/language/Java.js +97 -97
- package/dist/quicktype-core/language/JavaScript.d.ts +7 -7
- package/dist/quicktype-core/language/JavaScript.js +17 -19
- package/dist/quicktype-core/language/JavaScriptPropTypes.js +13 -15
- package/dist/quicktype-core/language/JavaScriptUnicodeMaps.js +11 -12
- package/dist/quicktype-core/language/Kotlin.d.ts +2 -2
- package/dist/quicktype-core/language/Kotlin.js +37 -39
- package/dist/quicktype-core/language/Objective-C.d.ts +3 -3
- package/dist/quicktype-core/language/Objective-C.js +41 -45
- package/dist/quicktype-core/language/Php.d.ts +2 -2
- package/dist/quicktype-core/language/Php.js +41 -66
- package/dist/quicktype-core/language/Pike.d.ts +1 -1
- package/dist/quicktype-core/language/Pike.js +17 -18
- package/dist/quicktype-core/language/Python.d.ts +8 -8
- package/dist/quicktype-core/language/Python.js +64 -63
- package/dist/quicktype-core/language/Rust.d.ts +2 -2
- package/dist/quicktype-core/language/Rust.js +19 -21
- package/dist/quicktype-core/language/Swift.d.ts +7 -7
- package/dist/quicktype-core/language/Swift.js +804 -807
- package/dist/quicktype-core/language/TypeScriptFlow.d.ts +7 -7
- package/dist/quicktype-core/language/TypeScriptFlow.js +26 -28
- package/dist/quicktype-core/language/ruby/index.d.ts +4 -4
- package/dist/quicktype-core/language/ruby/index.js +24 -49
- package/dist/quicktype-core/language/ruby/keywords.js +0 -1
- package/dist/quicktype-core/rewrites/CombineClasses.js +8 -9
- package/dist/quicktype-core/rewrites/ExpandStrings.d.ts +1 -1
- package/dist/quicktype-core/rewrites/ExpandStrings.js +17 -18
- package/dist/quicktype-core/rewrites/FlattenStrings.js +6 -7
- package/dist/quicktype-core/rewrites/FlattenUnions.js +8 -9
- package/dist/quicktype-core/rewrites/InferMaps.js +10 -11
- package/dist/quicktype-core/rewrites/ReplaceObjectType.js +7 -8
- package/dist/quicktype-core/rewrites/ResolveIntersections.js +67 -68
- package/dist/quicktype-core/support/Acronyms.js +1 -3
- package/dist/quicktype-core/support/Chance.js +0 -10
- package/dist/quicktype-core/support/Converters.js +0 -1
- package/dist/quicktype-core/support/Strings.d.ts +4 -4
- package/dist/quicktype-core/support/Strings.js +16 -17
- package/dist/quicktype-core/support/Support.d.ts +1 -1
- package/dist/quicktype-core/support/Support.js +6 -30
- package/dist/quicktype-graphql-input/GraphQLSchema.d.ts +4 -4
- package/dist/quicktype-graphql-input/GraphQLSchema.js +0 -1
- package/dist/quicktype-graphql-input/index.d.ts +1 -1
- package/dist/quicktype-graphql-input/index.js +212 -229
- package/dist/quicktype-typescript-input/index.js +4 -28
- package/package.json +19 -25
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SwiftRenderer = exports.SwiftTargetLanguage = exports.swiftOptions = void 0;
|
|
4
3
|
const collection_utils_1 = require("collection-utils");
|
|
5
4
|
const Support_1 = require("../support/Support");
|
|
6
5
|
const TargetLanguage_1 = require("../TargetLanguage");
|
|
@@ -27,7 +26,7 @@ exports.swiftOptions = {
|
|
|
27
26
|
["class", true]
|
|
28
27
|
]),
|
|
29
28
|
mutableProperties: new RendererOptions_1.BooleanOption("mutable-properties", "Use var instead of let for object properties", false),
|
|
30
|
-
acronymStyle:
|
|
29
|
+
acronymStyle: Acronyms_1.acronymOption(Acronyms_1.AcronymStyleOptions.Pascal),
|
|
31
30
|
dense: new RendererOptions_1.EnumOption("density", "Code density", [
|
|
32
31
|
["dense", true],
|
|
33
32
|
["normal", false]
|
|
@@ -99,7 +98,7 @@ class SwiftTargetLanguage extends TargetLanguage_1.TargetLanguage {
|
|
|
99
98
|
return true;
|
|
100
99
|
}
|
|
101
100
|
makeRenderer(renderContext, untypedOptionValues) {
|
|
102
|
-
return new SwiftRenderer(this, renderContext,
|
|
101
|
+
return new SwiftRenderer(this, renderContext, RendererOptions_1.getOptionValues(exports.swiftOptions, untypedOptionValues));
|
|
103
102
|
}
|
|
104
103
|
get dateTimeRecognizer() {
|
|
105
104
|
return new SwiftDateTimeRecognizer();
|
|
@@ -208,504 +207,476 @@ const keywords = [
|
|
|
208
207
|
"jsonData"
|
|
209
208
|
];
|
|
210
209
|
function isPartCharacter(codePoint) {
|
|
211
|
-
return
|
|
210
|
+
return Strings_1.isLetterOrUnderscore(codePoint) || Strings_1.isNumeric(codePoint);
|
|
212
211
|
}
|
|
213
212
|
function isStartCharacter(codePoint) {
|
|
214
|
-
return isPartCharacter(codePoint) && !
|
|
213
|
+
return isPartCharacter(codePoint) && !Strings_1.isDigit(codePoint);
|
|
215
214
|
}
|
|
216
|
-
const legalizeName =
|
|
215
|
+
const legalizeName = Strings_1.legalizeCharacters(isPartCharacter);
|
|
217
216
|
function swiftNameStyle(prefix, isUpper, original, acronymsStyle = Strings_1.allUpperWordStyle) {
|
|
218
|
-
const words =
|
|
219
|
-
const combined =
|
|
220
|
-
return
|
|
217
|
+
const words = Strings_1.splitIntoWords(original);
|
|
218
|
+
const combined = Strings_1.combineWords(words, legalizeName, isUpper ? Strings_1.firstUpperWordStyle : Strings_1.allLowerWordStyle, Strings_1.firstUpperWordStyle, isUpper ? Strings_1.allUpperWordStyle : Strings_1.allLowerWordStyle, acronymsStyle, "", isStartCharacter);
|
|
219
|
+
return Strings_1.addPrefixIfNecessary(prefix, combined);
|
|
221
220
|
}
|
|
222
221
|
function unicodeEscape(codePoint) {
|
|
223
|
-
return "\\u{" +
|
|
222
|
+
return "\\u{" + Strings_1.intToHex(codePoint, 0) + "}";
|
|
224
223
|
}
|
|
225
|
-
const stringEscape =
|
|
224
|
+
const stringEscape = Strings_1.utf32ConcatMap(Strings_1.escapeNonPrintableMapper(Strings_1.isPrintable, unicodeEscape));
|
|
226
225
|
class SwiftRenderer extends ConvenienceRenderer_1.ConvenienceRenderer {
|
|
227
|
-
_options;
|
|
228
|
-
_currentFilename;
|
|
229
|
-
_needAny = false;
|
|
230
|
-
_needNull = false;
|
|
231
226
|
constructor(targetLanguage, renderContext, _options) {
|
|
232
227
|
super(targetLanguage, renderContext);
|
|
233
228
|
this._options = _options;
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
229
|
+
this._needAny = false;
|
|
230
|
+
this._needNull = false;
|
|
231
|
+
this.emitSupportFunctions4 = () => {
|
|
232
|
+
this.startFile("JSONSchemaSupport");
|
|
233
|
+
this.emitLineOnce("import Foundation");
|
|
234
|
+
this.forEachTopLevel("leading", (t, name) => this.renderTopLevelAlias(t, name), t => this.namedTypeToNameForTopLevel(t) === undefined);
|
|
235
|
+
if (this._options.convenienceInitializers) {
|
|
236
|
+
this.ensureBlankLine();
|
|
237
|
+
this.forEachTopLevel("leading-and-interposing", (t, name) => this.emitTopLevelMapAndArrayConvenienceInitializerExtensions(t, name));
|
|
238
|
+
}
|
|
239
|
+
if ((!this._options.justTypes && this._options.convenienceInitializers) || this._options.alamofire) {
|
|
240
|
+
this.ensureBlankLine();
|
|
241
|
+
this.emitMark("Helper functions for creating encoders and decoders", true);
|
|
242
|
+
this.ensureBlankLine();
|
|
243
|
+
this.emitNewEncoderDecoder();
|
|
244
|
+
}
|
|
245
|
+
if (this._options.alamofire) {
|
|
246
|
+
this.ensureBlankLine();
|
|
247
|
+
this.emitMark("Alamofire response handlers", true);
|
|
248
|
+
this.ensureBlankLine();
|
|
249
|
+
this.emitAlamofireExtension();
|
|
250
|
+
}
|
|
251
|
+
// This assumes that this method is called after declarations
|
|
252
|
+
// are emitted.
|
|
253
|
+
if (this._needAny || this._needNull) {
|
|
254
|
+
this.ensureBlankLine();
|
|
255
|
+
this.emitMark("Encode/decode helpers", true);
|
|
256
|
+
this.ensureBlankLine();
|
|
257
|
+
if (this._options.objcSupport) {
|
|
258
|
+
this.emitLine(this.objcMembersDeclaration, this.accessLevel, "class JSONNull: NSObject, Codable {");
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
this.emitLine(this.accessLevel, "class JSONNull: Codable, Hashable {");
|
|
262
|
+
}
|
|
263
|
+
this.ensureBlankLine();
|
|
264
|
+
this.emitMultiline(` public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool {
|
|
265
|
+
return true
|
|
266
|
+
}`);
|
|
267
|
+
if (this._options.objcSupport === false) {
|
|
268
|
+
this.ensureBlankLine();
|
|
269
|
+
this.emitMultiline(` public var hashValue: Int {
|
|
270
|
+
return 0
|
|
271
|
+
}`);
|
|
272
|
+
if (this._options.swift5Support) {
|
|
273
|
+
this.ensureBlankLine();
|
|
274
|
+
this.emitMultiline(` public func hash(into hasher: inout Hasher) {
|
|
275
|
+
// No-op
|
|
276
|
+
}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
this.ensureBlankLine();
|
|
280
|
+
if (this._options.objcSupport) {
|
|
281
|
+
this.emitItem(" override ");
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
this.emitItem(" ");
|
|
285
|
+
}
|
|
286
|
+
this.emitMultiline(`public init() {}
|
|
287
|
+
|
|
288
|
+
public required init(from decoder: Decoder) throws {
|
|
289
|
+
let container = try decoder.singleValueContainer()
|
|
290
|
+
if !container.decodeNil() {
|
|
291
|
+
throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull"))
|
|
238
292
|
}
|
|
239
|
-
return keywords;
|
|
240
|
-
}
|
|
241
|
-
forbiddenForObjectProperties(_c, _classNamed) {
|
|
242
|
-
return { names: ["fromURL", "json"], includeGlobalForbidden: true };
|
|
243
|
-
}
|
|
244
|
-
forbiddenForEnumCases(_e, _enumName) {
|
|
245
|
-
return { names: [], includeGlobalForbidden: true };
|
|
246
|
-
}
|
|
247
|
-
forbiddenForUnionMembers(_u, _unionName) {
|
|
248
|
-
return { names: [], includeGlobalForbidden: true };
|
|
249
293
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
return this.lowerNamingFunction;
|
|
255
|
-
}
|
|
256
|
-
makeUnionMemberNamer() {
|
|
257
|
-
return this.lowerNamingFunction;
|
|
258
|
-
}
|
|
259
|
-
makeEnumCaseNamer() {
|
|
260
|
-
return this.lowerNamingFunction;
|
|
294
|
+
|
|
295
|
+
public func encode(to encoder: Encoder) throws {
|
|
296
|
+
var container = encoder.singleValueContainer()
|
|
297
|
+
try container.encodeNil()
|
|
261
298
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
299
|
+
}`);
|
|
300
|
+
}
|
|
301
|
+
if (this._needAny) {
|
|
302
|
+
this.ensureBlankLine();
|
|
303
|
+
this.emitMultiline(`class JSONCodingKey: CodingKey {
|
|
304
|
+
let key: String
|
|
305
|
+
|
|
306
|
+
required init?(intValue: Int) {
|
|
307
|
+
return nil
|
|
265
308
|
}
|
|
266
|
-
|
|
267
|
-
|
|
309
|
+
|
|
310
|
+
required init?(stringValue: String) {
|
|
311
|
+
key = stringValue
|
|
268
312
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
this.emitLine("}");
|
|
313
|
+
|
|
314
|
+
var intValue: Int? {
|
|
315
|
+
return nil
|
|
273
316
|
}
|
|
274
|
-
|
|
275
|
-
|
|
317
|
+
|
|
318
|
+
var stringValue: String {
|
|
319
|
+
return key
|
|
276
320
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
321
|
+
}`);
|
|
322
|
+
this.ensureBlankLine();
|
|
323
|
+
if (this._options.objcSupport) {
|
|
324
|
+
this.emitLine(this.objcMembersDeclaration, this.accessLevel, "class JSONAny: NSObject, Codable {");
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
this.emitLine(this.accessLevel, "class JSONAny: Codable {");
|
|
328
|
+
}
|
|
329
|
+
this.ensureBlankLine();
|
|
330
|
+
this.emitMultiline(` ${this.accessLevel}let value: Any
|
|
331
|
+
|
|
332
|
+
static func decodingError(forCodingPath codingPath: [CodingKey]) -> DecodingError {
|
|
333
|
+
let context = DecodingError.Context(codingPath: codingPath, debugDescription: "Cannot decode JSONAny")
|
|
334
|
+
return DecodingError.typeMismatch(JSONAny.self, context)
|
|
282
335
|
}
|
|
283
|
-
|
|
284
|
-
|
|
336
|
+
|
|
337
|
+
static func encodingError(forValue value: Any, codingPath: [CodingKey]) -> EncodingError {
|
|
338
|
+
let context = EncodingError.Context(codingPath: codingPath, debugDescription: "Cannot encode JSONAny")
|
|
339
|
+
return EncodingError.invalidValue(value, context)
|
|
285
340
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
341
|
+
|
|
342
|
+
static func decode(from container: SingleValueDecodingContainer) throws -> Any {
|
|
343
|
+
if let value = try? container.decode(Bool.self) {
|
|
344
|
+
return value
|
|
289
345
|
}
|
|
290
|
-
|
|
291
|
-
return
|
|
346
|
+
if let value = try? container.decode(Int64.self) {
|
|
347
|
+
return value
|
|
292
348
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
const optional = noOptional ? "" : "?";
|
|
296
|
-
return (0, TypeUtils_1.matchType)(t, _anyType => {
|
|
297
|
-
this._needAny = true;
|
|
298
|
-
return (0, Source_1.maybeAnnotated)(withIssues, Annotation_1.anyTypeIssueAnnotation, this.justTypesCase(["Any", optional], "JSONAny"));
|
|
299
|
-
}, _nullType => {
|
|
300
|
-
this._needNull = true;
|
|
301
|
-
return (0, Source_1.maybeAnnotated)(withIssues, Annotation_1.nullTypeIssueAnnotation, this.justTypesCase("NSNull", ["JSONNull", optional]));
|
|
302
|
-
}, _boolType => "Bool", _integerType => "Int", _doubleType => "Double", _stringType => "String", arrayType => ["[", this.swiftType(arrayType.items, withIssues), "]"], classType => this.nameForNamedType(classType), mapType => ["[String: ", this.swiftType(mapType.values, withIssues), "]"], enumType => this.nameForNamedType(enumType), unionType => {
|
|
303
|
-
const nullable = (0, TypeUtils_1.nullableFromUnion)(unionType);
|
|
304
|
-
if (nullable !== null)
|
|
305
|
-
return [this.swiftType(nullable, withIssues), optional];
|
|
306
|
-
return this.nameForNamedType(unionType);
|
|
307
|
-
}, transformedStringType => {
|
|
308
|
-
if (transformedStringType.kind === "date-time") {
|
|
309
|
-
return "Date";
|
|
310
|
-
}
|
|
311
|
-
else {
|
|
312
|
-
return (0, Support_2.panic)(`Transformed string type ${transformedStringType.kind} not supported`);
|
|
313
|
-
}
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
proposedUnionMemberNameForTypeKind(kind) {
|
|
317
|
-
if (kind === "enum") {
|
|
318
|
-
return "enumeration";
|
|
349
|
+
if let value = try? container.decode(Double.self) {
|
|
350
|
+
return value
|
|
319
351
|
}
|
|
320
|
-
if
|
|
321
|
-
return
|
|
352
|
+
if let value = try? container.decode(String.self) {
|
|
353
|
+
return value
|
|
322
354
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
this.emitLineOnce("// To parse the JSON, add this file to your project and do:");
|
|
328
|
-
this.emitLineOnce("//");
|
|
329
|
-
this.forEachTopLevel("none", (t, topLevelName) => {
|
|
330
|
-
if (this._options.convenienceInitializers && !(t instanceof Type_1.EnumType)) {
|
|
331
|
-
this.emitLineOnce("// let ", (0, Source_1.modifySource)(Strings_1.camelCase, topLevelName), " = try ", topLevelName, "(json)");
|
|
332
|
-
}
|
|
333
|
-
else {
|
|
334
|
-
this.emitLineOnce("// let ", (0, Source_1.modifySource)(Strings_1.camelCase, topLevelName), " = ", "try? JSONDecoder().decode(", topLevelName, ".self, from: jsonData)");
|
|
335
|
-
}
|
|
336
|
-
});
|
|
355
|
+
if container.decodeNil() {
|
|
356
|
+
return JSONNull()
|
|
357
|
+
}
|
|
358
|
+
throw decodingError(forCodingPath: container.codingPath)
|
|
337
359
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
360
|
+
|
|
361
|
+
static func decode(from container: inout UnkeyedDecodingContainer) throws -> Any {
|
|
362
|
+
if let value = try? container.decode(Bool.self) {
|
|
363
|
+
return value
|
|
341
364
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
if (this._options.alamofire) {
|
|
355
|
-
this.emitLine("//");
|
|
356
|
-
this.emitLine("// To parse values from Alamofire responses:");
|
|
357
|
-
this.emitLine("//");
|
|
358
|
-
this.emitLine("// Alamofire.request(url).response", name, " { response in");
|
|
359
|
-
this.emitLine("// if let ", (0, Source_1.modifySource)(Strings_1.camelCase, name), " = response.result.value {");
|
|
360
|
-
this.emitLine("// ...");
|
|
361
|
-
this.emitLine("// }");
|
|
362
|
-
this.emitLine("// }");
|
|
363
|
-
}
|
|
364
|
-
if (this._options.protocol.hashable || this._options.protocol.equatable) {
|
|
365
|
-
this.emitLine("//");
|
|
366
|
-
this.emitLine("// Hashable or Equatable:");
|
|
367
|
-
this.emitLine("// The compiler will not be able to synthesize the implementation of Hashable or Equatable");
|
|
368
|
-
this.emitLine("// for types that require the use of JSONAny, nor will the implementation of Hashable be");
|
|
369
|
-
this.emitLine("// synthesized for types that have collections (such as arrays or dictionaries).");
|
|
365
|
+
if let value = try? container.decode(Int64.self) {
|
|
366
|
+
return value
|
|
367
|
+
}
|
|
368
|
+
if let value = try? container.decode(Double.self) {
|
|
369
|
+
return value
|
|
370
|
+
}
|
|
371
|
+
if let value = try? container.decode(String.self) {
|
|
372
|
+
return value
|
|
373
|
+
}
|
|
374
|
+
if let value = try? container.decodeNil() {
|
|
375
|
+
if value {
|
|
376
|
+
return JSONNull()
|
|
370
377
|
}
|
|
371
378
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
if (!this._options.justTypes && this._options.alamofire) {
|
|
375
|
-
this.emitLineOnce("import Alamofire");
|
|
379
|
+
if var container = try? container.nestedUnkeyedContainer() {
|
|
380
|
+
return try decodeArray(from: &container)
|
|
376
381
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
382
|
+
if var container = try? container.nestedContainer(keyedBy: JSONCodingKey.self) {
|
|
383
|
+
return try decodeDictionary(from: &container)
|
|
384
|
+
}
|
|
385
|
+
throw decodingError(forCodingPath: container.codingPath)
|
|
381
386
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
protocols.push("NSObject");
|
|
387
|
+
|
|
388
|
+
static func decode(from container: inout KeyedDecodingContainer<JSONCodingKey>, forKey key: JSONCodingKey) throws -> Any {
|
|
389
|
+
if let value = try? container.decode(Bool.self, forKey: key) {
|
|
390
|
+
return value
|
|
387
391
|
}
|
|
388
|
-
if (
|
|
389
|
-
|
|
392
|
+
if let value = try? container.decode(Int64.self, forKey: key) {
|
|
393
|
+
return value
|
|
390
394
|
}
|
|
391
|
-
if (
|
|
392
|
-
|
|
395
|
+
if let value = try? container.decode(Double.self, forKey: key) {
|
|
396
|
+
return value
|
|
393
397
|
}
|
|
394
|
-
if (
|
|
395
|
-
|
|
398
|
+
if let value = try? container.decode(String.self, forKey: key) {
|
|
399
|
+
return value
|
|
396
400
|
}
|
|
397
|
-
|
|
401
|
+
if let value = try? container.decodeNil(forKey: key) {
|
|
402
|
+
if value {
|
|
403
|
+
return JSONNull()
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
if var container = try? container.nestedUnkeyedContainer(forKey: key) {
|
|
407
|
+
return try decodeArray(from: &container)
|
|
408
|
+
}
|
|
409
|
+
if var container = try? container.nestedContainer(keyedBy: JSONCodingKey.self, forKey: key) {
|
|
410
|
+
return try decodeDictionary(from: &container)
|
|
411
|
+
}
|
|
412
|
+
throw decodingError(forCodingPath: container.codingPath)
|
|
398
413
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
let group = [];
|
|
406
|
-
this.forEachClassProperty(c, "none", (name, jsonName) => {
|
|
407
|
-
const label = stringEscape(jsonName);
|
|
408
|
-
const redundant = this.sourcelikeToString(name) === label;
|
|
409
|
-
if (this._options.dense && redundant) {
|
|
410
|
-
group.push({ name });
|
|
411
|
-
}
|
|
412
|
-
else {
|
|
413
|
-
if (group.length > 0) {
|
|
414
|
-
groups.push(group);
|
|
415
|
-
group = [];
|
|
416
|
-
}
|
|
417
|
-
groups.push([{ name, label }]);
|
|
418
|
-
}
|
|
419
|
-
});
|
|
420
|
-
if (group.length > 0) {
|
|
421
|
-
groups.push(group);
|
|
414
|
+
|
|
415
|
+
static func decodeArray(from container: inout UnkeyedDecodingContainer) throws -> [Any] {
|
|
416
|
+
var arr: [Any] = []
|
|
417
|
+
while !container.isAtEnd {
|
|
418
|
+
let value = try decode(from: &container)
|
|
419
|
+
arr.append(value)
|
|
422
420
|
}
|
|
423
|
-
return
|
|
421
|
+
return arr
|
|
424
422
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
:
|
|
423
|
+
|
|
424
|
+
static func decodeDictionary(from container: inout KeyedDecodingContainer<JSONCodingKey>) throws -> [String: Any] {
|
|
425
|
+
var dict = [String: Any]()
|
|
426
|
+
for key in container.allKeys {
|
|
427
|
+
let value = try decode(from: &container, forKey: key)
|
|
428
|
+
dict[key.stringValue] = value
|
|
429
|
+
}
|
|
430
|
+
return dict
|
|
430
431
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
432
|
+
|
|
433
|
+
static func encode(to container: inout UnkeyedEncodingContainer, array: [Any]) throws {
|
|
434
|
+
for value in array {
|
|
435
|
+
if let value = value as? Bool {
|
|
436
|
+
try container.encode(value)
|
|
437
|
+
} else if let value = value as? Int64 {
|
|
438
|
+
try container.encode(value)
|
|
439
|
+
} else if let value = value as? Double {
|
|
440
|
+
try container.encode(value)
|
|
441
|
+
} else if let value = value as? String {
|
|
442
|
+
try container.encode(value)
|
|
443
|
+
} else if value is JSONNull {
|
|
444
|
+
try container.encodeNil()
|
|
445
|
+
} else if let value = value as? [Any] {
|
|
446
|
+
var container = container.nestedUnkeyedContainer()
|
|
447
|
+
try encode(to: &container, array: value)
|
|
448
|
+
} else if let value = value as? [String: Any] {
|
|
449
|
+
var container = container.nestedContainer(keyedBy: JSONCodingKey.self)
|
|
450
|
+
try encode(to: &container, dictionary: value)
|
|
451
|
+
} else {
|
|
452
|
+
throw encodingError(forValue: value, codingPath: container.codingPath)
|
|
453
|
+
}
|
|
434
454
|
}
|
|
435
|
-
return "";
|
|
436
455
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
456
|
+
|
|
457
|
+
static func encode(to container: inout KeyedEncodingContainer<JSONCodingKey>, dictionary: [String: Any]) throws {
|
|
458
|
+
for (key, value) in dictionary {
|
|
459
|
+
let key = JSONCodingKey(stringValue: key)!
|
|
460
|
+
if let value = value as? Bool {
|
|
461
|
+
try container.encode(value, forKey: key)
|
|
462
|
+
} else if let value = value as? Int64 {
|
|
463
|
+
try container.encode(value, forKey: key)
|
|
464
|
+
} else if let value = value as? Double {
|
|
465
|
+
try container.encode(value, forKey: key)
|
|
466
|
+
} else if let value = value as? String {
|
|
467
|
+
try container.encode(value, forKey: key)
|
|
468
|
+
} else if value is JSONNull {
|
|
469
|
+
try container.encodeNil(forKey: key)
|
|
470
|
+
} else if let value = value as? [Any] {
|
|
471
|
+
var container = container.nestedUnkeyedContainer(forKey: key)
|
|
472
|
+
try encode(to: &container, array: value)
|
|
473
|
+
} else if let value = value as? [String: Any] {
|
|
474
|
+
var container = container.nestedContainer(keyedBy: JSONCodingKey.self, forKey: key)
|
|
475
|
+
try encode(to: &container, dictionary: value)
|
|
476
|
+
} else {
|
|
477
|
+
throw encodingError(forValue: value, codingPath: container.codingPath)
|
|
478
|
+
}
|
|
441
479
|
}
|
|
442
|
-
(0, Support_1.assert)(this._currentFilename === undefined, "Previous file wasn't finished: " + this._currentFilename);
|
|
443
|
-
// FIXME: The filenames should actually be Sourcelikes, too
|
|
444
|
-
this._currentFilename = `${this.sourcelikeToString(basename)}.swift`;
|
|
445
|
-
this.initializeEmitContextForFilename(this._currentFilename);
|
|
446
480
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
if
|
|
450
|
-
|
|
481
|
+
|
|
482
|
+
static func encode(to container: inout SingleValueEncodingContainer, value: Any) throws {
|
|
483
|
+
if let value = value as? Bool {
|
|
484
|
+
try container.encode(value)
|
|
485
|
+
} else if let value = value as? Int64 {
|
|
486
|
+
try container.encode(value)
|
|
487
|
+
} else if let value = value as? Double {
|
|
488
|
+
try container.encode(value)
|
|
489
|
+
} else if let value = value as? String {
|
|
490
|
+
try container.encode(value)
|
|
491
|
+
} else if value is JSONNull {
|
|
492
|
+
try container.encodeNil()
|
|
493
|
+
} else {
|
|
494
|
+
throw encodingError(forValue: value, codingPath: container.codingPath)
|
|
451
495
|
}
|
|
452
|
-
this.finishFile((0, Support_1.defined)(this._currentFilename));
|
|
453
|
-
this._currentFilename = undefined;
|
|
454
496
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
497
|
+
|
|
498
|
+
public required init(from decoder: Decoder) throws {
|
|
499
|
+
if var arrayContainer = try? decoder.unkeyedContainer() {
|
|
500
|
+
self.value = try JSONAny.decodeArray(from: &arrayContainer)
|
|
501
|
+
} else if var container = try? decoder.container(keyedBy: JSONCodingKey.self) {
|
|
502
|
+
self.value = try JSONAny.decodeDictionary(from: &container)
|
|
503
|
+
} else {
|
|
504
|
+
let container = try decoder.singleValueContainer()
|
|
505
|
+
self.value = try JSONAny.decode(from: container)
|
|
506
|
+
}
|
|
464
507
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
508
|
+
|
|
509
|
+
public func encode(to encoder: Encoder) throws {
|
|
510
|
+
if let arr = self.value as? [Any] {
|
|
511
|
+
var container = encoder.unkeyedContainer()
|
|
512
|
+
try JSONAny.encode(to: &container, array: arr)
|
|
513
|
+
} else if let dict = self.value as? [String: Any] {
|
|
514
|
+
var container = encoder.container(keyedBy: JSONCodingKey.self)
|
|
515
|
+
try JSONAny.encode(to: &container, dictionary: dict)
|
|
516
|
+
} else {
|
|
517
|
+
var container = encoder.singleValueContainer()
|
|
518
|
+
try JSONAny.encode(to: &container, value: self.value)
|
|
475
519
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
let lastProperty = undefined;
|
|
479
|
-
let lastNames = [];
|
|
480
|
-
const emitLastProperty = () => {
|
|
481
|
-
if (lastProperty === undefined)
|
|
482
|
-
return;
|
|
483
|
-
const useMutableProperties = this._options.mutableProperties;
|
|
484
|
-
let sources = [
|
|
485
|
-
[
|
|
486
|
-
this._options.optionalEnums && lastProperty.type.kind === "enum"
|
|
487
|
-
? `@NilOnFail${this._options.namedTypePrefix} `
|
|
488
|
-
: "",
|
|
489
|
-
this.accessLevel,
|
|
490
|
-
useMutableProperties || (this._options.optionalEnums && lastProperty.type.kind === "enum")
|
|
491
|
-
? "var "
|
|
492
|
-
: "let "
|
|
493
|
-
]
|
|
494
|
-
];
|
|
495
|
-
lastNames.forEach((n, i) => {
|
|
496
|
-
if (i > 0)
|
|
497
|
-
sources.push(", ");
|
|
498
|
-
sources.push(n);
|
|
499
|
-
});
|
|
500
|
-
sources.push(": ");
|
|
501
|
-
sources.push(this.swiftPropertyType(lastProperty));
|
|
502
|
-
this.emitLine(sources);
|
|
503
|
-
lastProperty = undefined;
|
|
504
|
-
lastNames = [];
|
|
505
|
-
};
|
|
506
|
-
this.forEachClassProperty(c, "none", (name, jsonName, p) => {
|
|
507
|
-
const description = this.descriptionForClassProperty(c, jsonName);
|
|
508
|
-
if (!p.equals(lastProperty) ||
|
|
509
|
-
lastNames.length >= MAX_SAMELINE_PROPERTIES ||
|
|
510
|
-
description !== undefined) {
|
|
511
|
-
emitLastProperty();
|
|
512
|
-
}
|
|
513
|
-
if (lastProperty === undefined) {
|
|
514
|
-
lastProperty = p;
|
|
515
|
-
}
|
|
516
|
-
lastNames.push(name);
|
|
517
|
-
if (description !== undefined) {
|
|
518
|
-
this.emitDescription(description);
|
|
519
|
-
emitLastProperty();
|
|
520
|
-
}
|
|
521
|
-
});
|
|
522
|
-
emitLastProperty();
|
|
523
|
-
}
|
|
524
|
-
else {
|
|
525
|
-
this.forEachClassProperty(c, "none", (name, jsonName, p) => {
|
|
526
|
-
const description = this.descriptionForClassProperty(c, jsonName);
|
|
527
|
-
const propertyLines = this.propertyLinesDefinition(name, p);
|
|
528
|
-
this.emitDescription(description);
|
|
529
|
-
this.emitLine(propertyLines);
|
|
530
|
-
});
|
|
531
|
-
}
|
|
532
|
-
if (!this._options.justTypes) {
|
|
533
|
-
const groups = this.getEnumPropertyGroups(c);
|
|
534
|
-
const allPropertiesRedundant = groups.every(group => {
|
|
535
|
-
return group.every(p => p.label === undefined);
|
|
536
|
-
});
|
|
537
|
-
if (!allPropertiesRedundant && c.getProperties().size > 0) {
|
|
538
|
-
this.ensureBlankLine();
|
|
539
|
-
this.emitBlock("enum CodingKeys: String, CodingKey", () => {
|
|
540
|
-
for (const group of groups) {
|
|
541
|
-
const { name, label } = group[0];
|
|
542
|
-
if (this._options.explicitCodingKeys && label !== undefined) {
|
|
543
|
-
this.emitLine("case ", name, ' = "', label, '"');
|
|
544
|
-
}
|
|
545
|
-
else {
|
|
546
|
-
const names = (0, collection_utils_1.arrayIntercalate)(", ", group.map(p => p.name));
|
|
547
|
-
this.emitLine("case ", names);
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
});
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
// this main initializer must be defined within the class
|
|
554
|
-
// declaration since it assigns let constants
|
|
555
|
-
if (isClass ||
|
|
556
|
-
// Public structs need explicit initializers
|
|
557
|
-
// https://github.com/quicktype/quicktype/issues/899
|
|
558
|
-
this._options.accessLevel === "public") {
|
|
559
|
-
// Make an initializer that initalizes all fields
|
|
560
|
-
this.ensureBlankLine();
|
|
561
|
-
let initProperties = this.initializableProperties(c);
|
|
562
|
-
let propertiesLines = [];
|
|
563
|
-
for (let property of initProperties) {
|
|
564
|
-
if (propertiesLines.length > 0)
|
|
565
|
-
propertiesLines.push(", ");
|
|
566
|
-
propertiesLines.push(property.name, ": ", this.swiftPropertyType(property.parameter));
|
|
567
|
-
}
|
|
568
|
-
if (this.propertyCount(c) === 0 && this._options.objcSupport) {
|
|
569
|
-
this.emitBlockWithAccess(["override init()"], () => {
|
|
570
|
-
return "";
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
else {
|
|
574
|
-
this.emitBlockWithAccess(["init(", ...propertiesLines, ")"], () => {
|
|
575
|
-
for (let property of initProperties) {
|
|
576
|
-
this.emitLine("self.", property.name, " = ", property.name);
|
|
577
|
-
}
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
});
|
|
582
|
-
if (!this._options.justTypes) {
|
|
583
|
-
// FIXME: We emit only the MARK line for top-level-enum.schema
|
|
584
|
-
if (this._options.convenienceInitializers) {
|
|
585
|
-
this.ensureBlankLine();
|
|
586
|
-
this.emitMark(this.sourcelikeToString(className) + " convenience initializers and mutators");
|
|
587
|
-
this.ensureBlankLine();
|
|
588
|
-
this.emitConvenienceInitializersExtension(c, className);
|
|
589
|
-
this.ensureBlankLine();
|
|
520
|
+
}
|
|
521
|
+
}`);
|
|
590
522
|
}
|
|
523
|
+
this.endFile();
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
forbiddenNamesForGlobalNamespace() {
|
|
527
|
+
if (this._options.alamofire) {
|
|
528
|
+
return ["DataRequest", ...keywords];
|
|
591
529
|
}
|
|
592
|
-
|
|
530
|
+
return keywords;
|
|
593
531
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
this.forEachClassProperty(c, "none", (name, jsonName, parameter, position) => {
|
|
597
|
-
const property = { name, jsonName, parameter, position };
|
|
598
|
-
properties.push(property);
|
|
599
|
-
});
|
|
600
|
-
return properties;
|
|
532
|
+
forbiddenForObjectProperties(_c, _classNamed) {
|
|
533
|
+
return { names: ["fromURL", "json"], includeGlobalForbidden: true };
|
|
601
534
|
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
this.emitLine("let decoder = JSONDecoder()");
|
|
605
|
-
if (!this._options.linux) {
|
|
606
|
-
this.emitBlock("if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)", () => {
|
|
607
|
-
this.emitLine("decoder.dateDecodingStrategy = .iso8601");
|
|
608
|
-
});
|
|
609
|
-
}
|
|
610
|
-
else {
|
|
611
|
-
this.emitMultiline(`decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in
|
|
612
|
-
let container = try decoder.singleValueContainer()
|
|
613
|
-
let dateStr = try container.decode(String.self)
|
|
614
|
-
|
|
615
|
-
let formatter = DateFormatter()
|
|
616
|
-
formatter.calendar = Calendar(identifier: .iso8601)
|
|
617
|
-
formatter.locale = Locale(identifier: "en_US_POSIX")
|
|
618
|
-
formatter.timeZone = TimeZone(secondsFromGMT: 0)
|
|
619
|
-
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
|
|
620
|
-
if let date = formatter.date(from: dateStr) {
|
|
621
|
-
return date
|
|
535
|
+
forbiddenForEnumCases(_e, _enumName) {
|
|
536
|
+
return { names: [], includeGlobalForbidden: true };
|
|
622
537
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
return date
|
|
538
|
+
forbiddenForUnionMembers(_u, _unionName) {
|
|
539
|
+
return { names: [], includeGlobalForbidden: true };
|
|
626
540
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
541
|
+
makeNamedTypeNamer() {
|
|
542
|
+
return Naming_1.funPrefixNamer("upper", s => swiftNameStyle(this._options.namedTypePrefix, true, s, Acronyms_1.acronymStyle(this._options.acronymStyle)));
|
|
543
|
+
}
|
|
544
|
+
namerForObjectProperty() {
|
|
545
|
+
return this.lowerNamingFunction;
|
|
546
|
+
}
|
|
547
|
+
makeUnionMemberNamer() {
|
|
548
|
+
return this.lowerNamingFunction;
|
|
549
|
+
}
|
|
550
|
+
makeEnumCaseNamer() {
|
|
551
|
+
return this.lowerNamingFunction;
|
|
552
|
+
}
|
|
553
|
+
isImplicitCycleBreaker(t) {
|
|
554
|
+
const kind = t.kind;
|
|
555
|
+
return kind === "array" || kind === "map";
|
|
556
|
+
}
|
|
557
|
+
emitDescriptionBlock(lines) {
|
|
558
|
+
this.emitCommentLines(lines, "/// ");
|
|
559
|
+
}
|
|
560
|
+
emitBlock(line, f) {
|
|
561
|
+
this.emitLine(line, " {");
|
|
562
|
+
this.indent(f);
|
|
563
|
+
this.emitLine("}");
|
|
564
|
+
}
|
|
565
|
+
emitBlockWithAccess(line, f) {
|
|
566
|
+
this.emitBlock([this.accessLevel, line], f);
|
|
567
|
+
}
|
|
568
|
+
justTypesCase(justTypes, notJustTypes) {
|
|
569
|
+
if (this._options.justTypes)
|
|
570
|
+
return justTypes;
|
|
571
|
+
else
|
|
572
|
+
return notJustTypes;
|
|
573
|
+
}
|
|
574
|
+
get lowerNamingFunction() {
|
|
575
|
+
return Naming_1.funPrefixNamer("lower", s => swiftNameStyle("", false, s, Acronyms_1.acronymStyle(this._options.acronymStyle)));
|
|
576
|
+
}
|
|
577
|
+
swiftPropertyType(p) {
|
|
578
|
+
if (p.isOptional || (this._options.optionalEnums && p.type.kind === "enum")) {
|
|
579
|
+
return [this.swiftType(p.type, true, true), "?"];
|
|
580
|
+
}
|
|
581
|
+
else {
|
|
582
|
+
return this.swiftType(p.type, true);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
swiftType(t, withIssues = false, noOptional = false) {
|
|
586
|
+
const optional = noOptional ? "" : "?";
|
|
587
|
+
return TypeUtils_1.matchType(t, _anyType => {
|
|
588
|
+
this._needAny = true;
|
|
589
|
+
return Source_1.maybeAnnotated(withIssues, Annotation_1.anyTypeIssueAnnotation, this.justTypesCase(["Any", optional], "JSONAny"));
|
|
590
|
+
}, _nullType => {
|
|
591
|
+
this._needNull = true;
|
|
592
|
+
return Source_1.maybeAnnotated(withIssues, Annotation_1.nullTypeIssueAnnotation, this.justTypesCase("NSNull", ["JSONNull", optional]));
|
|
593
|
+
}, _boolType => "Bool", _integerType => "Int", _doubleType => "Double", _stringType => "String", arrayType => ["[", this.swiftType(arrayType.items, withIssues), "]"], classType => this.nameForNamedType(classType), mapType => ["[String: ", this.swiftType(mapType.values, withIssues), "]"], enumType => this.nameForNamedType(enumType), unionType => {
|
|
594
|
+
const nullable = TypeUtils_1.nullableFromUnion(unionType);
|
|
595
|
+
if (nullable !== null)
|
|
596
|
+
return [this.swiftType(nullable, withIssues), optional];
|
|
597
|
+
return this.nameForNamedType(unionType);
|
|
598
|
+
}, transformedStringType => {
|
|
599
|
+
if (transformedStringType.kind === "date-time") {
|
|
600
|
+
return "Date";
|
|
639
601
|
}
|
|
640
602
|
else {
|
|
641
|
-
|
|
642
|
-
formatter.calendar = Calendar(identifier: .iso8601)
|
|
643
|
-
formatter.locale = Locale(identifier: "en_US_POSIX")
|
|
644
|
-
formatter.timeZone = TimeZone(secondsFromGMT: 0)
|
|
645
|
-
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssXXXXX"
|
|
646
|
-
encoder.dateEncodingStrategy = .formatted(formatter)`);
|
|
603
|
+
return Support_2.panic(`Transformed string type ${transformedStringType.kind} not supported`);
|
|
647
604
|
}
|
|
648
|
-
this.emitLine("return encoder");
|
|
649
605
|
});
|
|
650
606
|
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
args.push(name, ": ", "me.", name);
|
|
668
|
-
});
|
|
669
|
-
this.emitLine("self.init(", ...args, ")");
|
|
670
|
-
});
|
|
607
|
+
proposedUnionMemberNameForTypeKind(kind) {
|
|
608
|
+
if (kind === "enum") {
|
|
609
|
+
return "enumeration";
|
|
610
|
+
}
|
|
611
|
+
if (kind === "union") {
|
|
612
|
+
return "one_of";
|
|
613
|
+
}
|
|
614
|
+
return null;
|
|
615
|
+
}
|
|
616
|
+
renderSingleFileHeaderComments() {
|
|
617
|
+
this.emitLineOnce("// This file was generated from JSON Schema using quicktype, do not modify it directly.");
|
|
618
|
+
this.emitLineOnce("// To parse the JSON, add this file to your project and do:");
|
|
619
|
+
this.emitLineOnce("//");
|
|
620
|
+
this.forEachTopLevel("none", (t, topLevelName) => {
|
|
621
|
+
if (this._options.convenienceInitializers && !(t instanceof Type_1.EnumType)) {
|
|
622
|
+
this.emitLineOnce("// let ", Source_1.modifySource(Strings_1.camelCase, topLevelName), " = try ", topLevelName, "(json)");
|
|
671
623
|
}
|
|
672
624
|
else {
|
|
673
|
-
this.
|
|
674
|
-
this.emitLine("self = try newJSONDecoder().decode(", this.swiftType(c), ".self, from: data)");
|
|
675
|
-
});
|
|
625
|
+
this.emitLineOnce("// let ", Source_1.modifySource(Strings_1.camelCase, topLevelName), " = ", "try? JSONDecoder().decode(", topLevelName, ".self, from: jsonData)");
|
|
676
626
|
}
|
|
677
|
-
this.ensureBlankLine();
|
|
678
|
-
this.emitBlock([convenience, "init(_ json: String, using encoding: String.Encoding = .utf8) throws"], () => {
|
|
679
|
-
this.emitBlock("guard let data = json.data(using: encoding) else", () => {
|
|
680
|
-
this.emitLine(`throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)`);
|
|
681
|
-
});
|
|
682
|
-
this.emitLine("try self.init(data: data)");
|
|
683
|
-
});
|
|
684
|
-
this.ensureBlankLine();
|
|
685
|
-
this.emitBlock([convenience, `init(fromURL url: URL) throws`], () => {
|
|
686
|
-
this.emitLine("try self.init(data: try Data(contentsOf: url))");
|
|
687
|
-
});
|
|
688
|
-
this.ensureBlankLine();
|
|
689
|
-
this.emitConvenienceMutator(c, className);
|
|
690
|
-
// Convenience serializers
|
|
691
|
-
this.ensureBlankLine();
|
|
692
|
-
this.emitBlock(`func jsonData() throws -> Data`, () => {
|
|
693
|
-
this.emitLine("return try newJSONEncoder().encode(self)");
|
|
694
|
-
});
|
|
695
|
-
this.ensureBlankLine();
|
|
696
|
-
this.emitBlock(`func jsonString(encoding: String.Encoding = .utf8) throws -> String?`, () => {
|
|
697
|
-
this.emitLine("return String(data: try self.jsonData(), encoding: encoding)");
|
|
698
|
-
});
|
|
699
627
|
});
|
|
700
628
|
}
|
|
701
|
-
|
|
702
|
-
this.
|
|
629
|
+
renderHeader(type, name) {
|
|
630
|
+
if (this.leadingComments !== undefined) {
|
|
631
|
+
this.emitCommentLines(this.leadingComments);
|
|
632
|
+
}
|
|
633
|
+
else if (!this._options.justTypes) {
|
|
634
|
+
if (this._options.multiFileOutput) {
|
|
635
|
+
this.emitLineOnce("// This file was generated from JSON Schema using quicktype, do not modify it directly.");
|
|
636
|
+
this.emitLineOnce("// To parse the JSON, add this file to your project and do:");
|
|
637
|
+
this.emitLineOnce("//");
|
|
638
|
+
if (this._options.convenienceInitializers && !(type instanceof Type_1.EnumType)) {
|
|
639
|
+
this.emitLine("// let ", Source_1.modifySource(Strings_1.camelCase, name), " = try ", name, "(json)");
|
|
640
|
+
}
|
|
641
|
+
else {
|
|
642
|
+
this.emitLine("// let ", Source_1.modifySource(Strings_1.camelCase, name), " = ", "try? newJSONDecoder().decode(", name, ".self, from: jsonData)");
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
if (this._options.alamofire) {
|
|
646
|
+
this.emitLine("//");
|
|
647
|
+
this.emitLine("// To parse values from Alamofire responses:");
|
|
648
|
+
this.emitLine("//");
|
|
649
|
+
this.emitLine("// Alamofire.request(url).response", name, " { response in");
|
|
650
|
+
this.emitLine("// if let ", Source_1.modifySource(Strings_1.camelCase, name), " = response.result.value {");
|
|
651
|
+
this.emitLine("// ...");
|
|
652
|
+
this.emitLine("// }");
|
|
653
|
+
this.emitLine("// }");
|
|
654
|
+
}
|
|
655
|
+
if (this._options.protocol.hashable || this._options.protocol.equatable) {
|
|
656
|
+
this.emitLine("//");
|
|
657
|
+
this.emitLine("// Hashable or Equatable:");
|
|
658
|
+
this.emitLine("// The compiler will not be able to synthesize the implementation of Hashable or Equatable");
|
|
659
|
+
this.emitLine("// for types that require the use of JSONAny, nor will the implementation of Hashable be");
|
|
660
|
+
this.emitLine("// synthesized for types that have collections (such as arrays or dictionaries).");
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
this.ensureBlankLine();
|
|
703
664
|
this.emitLineOnce("import Foundation");
|
|
665
|
+
if (!this._options.justTypes && this._options.alamofire) {
|
|
666
|
+
this.emitLineOnce("import Alamofire");
|
|
667
|
+
}
|
|
704
668
|
this.ensureBlankLine();
|
|
705
|
-
|
|
669
|
+
}
|
|
670
|
+
renderTopLevelAlias(t, name) {
|
|
671
|
+
this.emitLine(this.accessLevel, "typealias ", name, " = ", this.swiftType(t, true));
|
|
672
|
+
}
|
|
673
|
+
getProtocolsArray(_t, isClass) {
|
|
706
674
|
const protocols = [];
|
|
675
|
+
// [Michael Fey (@MrRooni), 2019-4-24] Technically NSObject isn't a "protocol" in this instance, but this felt like the best place to slot in this superclass declaration.
|
|
676
|
+
if (isClass && this._options.objcSupport) {
|
|
677
|
+
protocols.push("NSObject");
|
|
678
|
+
}
|
|
707
679
|
if (!this._options.justTypes) {
|
|
708
|
-
protocols.push("String"); // Not a protocol
|
|
709
680
|
protocols.push("Codable");
|
|
710
681
|
}
|
|
711
682
|
if (this._options.protocol.hashable) {
|
|
@@ -714,423 +685,449 @@ encoder.dateEncodingStrategy = .formatted(formatter)`);
|
|
|
714
685
|
if (this._options.protocol.equatable) {
|
|
715
686
|
protocols.push("Equatable");
|
|
716
687
|
}
|
|
717
|
-
|
|
718
|
-
if (this._options.justTypes) {
|
|
719
|
-
this.emitBlockWithAccess(["enum ", enumName, protocolString], () => {
|
|
720
|
-
this.forEachEnumCase(e, "none", name => {
|
|
721
|
-
this.emitLine("case ", name);
|
|
722
|
-
});
|
|
723
|
-
});
|
|
724
|
-
}
|
|
725
|
-
else {
|
|
726
|
-
this.emitBlockWithAccess(["enum ", enumName, protocolString], () => {
|
|
727
|
-
this.forEachEnumCase(e, "none", (name, jsonName) => {
|
|
728
|
-
this.emitLine("case ", name, ' = "', stringEscape(jsonName), '"');
|
|
729
|
-
});
|
|
730
|
-
});
|
|
731
|
-
}
|
|
732
|
-
this.endFile();
|
|
688
|
+
return protocols;
|
|
733
689
|
}
|
|
734
|
-
|
|
735
|
-
this.
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
this.emitLine("self = .", this.nameForUnionMember(u, t), "(x)");
|
|
747
|
-
this.emitLine("return");
|
|
748
|
-
});
|
|
749
|
-
};
|
|
750
|
-
this.emitDescription(this.descriptionForType(u));
|
|
751
|
-
const indirect = this.isCycleBreakerType(u) ? "indirect " : "";
|
|
752
|
-
const [maybeNull, nonNulls] = (0, TypeUtils_1.removeNullFromUnion)(u, sortBy);
|
|
753
|
-
this.emitBlockWithAccess([indirect, "enum ", unionName, this.getProtocolString(u, false)], () => {
|
|
754
|
-
this.forEachUnionMember(u, nonNulls, "none", null, (name, t) => {
|
|
755
|
-
this.emitLine("case ", name, "(", this.swiftType(t), ")");
|
|
756
|
-
});
|
|
757
|
-
if (maybeNull !== null) {
|
|
758
|
-
this.emitLine("case ", this.nameForUnionMember(u, maybeNull));
|
|
690
|
+
getProtocolString(_t, isClass) {
|
|
691
|
+
const protocols = this.getProtocolsArray(_t, isClass);
|
|
692
|
+
return protocols.length > 0 ? ": " + protocols.join(", ") : "";
|
|
693
|
+
}
|
|
694
|
+
getEnumPropertyGroups(c) {
|
|
695
|
+
let groups = [];
|
|
696
|
+
let group = [];
|
|
697
|
+
this.forEachClassProperty(c, "none", (name, jsonName) => {
|
|
698
|
+
const label = stringEscape(jsonName);
|
|
699
|
+
const redundant = this.sourcelikeToString(name) === label;
|
|
700
|
+
if (this._options.dense && redundant) {
|
|
701
|
+
group.push({ name });
|
|
759
702
|
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
renderUnionCase(boolMember);
|
|
767
|
-
const integerMember = u.findMember("integer");
|
|
768
|
-
if (integerMember !== undefined)
|
|
769
|
-
renderUnionCase(integerMember);
|
|
770
|
-
for (const t of nonNulls) {
|
|
771
|
-
if (t.kind === "bool" || t.kind === "integer")
|
|
772
|
-
continue;
|
|
773
|
-
renderUnionCase(t);
|
|
774
|
-
}
|
|
775
|
-
if (maybeNull !== null) {
|
|
776
|
-
this.emitBlock("if container.decodeNil()", () => {
|
|
777
|
-
this.emitLine("self = .", this.nameForUnionMember(u, maybeNull));
|
|
778
|
-
this.emitLine("return");
|
|
779
|
-
});
|
|
780
|
-
}
|
|
781
|
-
this.emitDecodingError(unionName);
|
|
782
|
-
});
|
|
783
|
-
this.ensureBlankLine();
|
|
784
|
-
this.emitBlockWithAccess("func encode(to encoder: Encoder) throws", () => {
|
|
785
|
-
this.emitLine("var container = encoder.singleValueContainer()");
|
|
786
|
-
this.emitLine("switch self {");
|
|
787
|
-
this.forEachUnionMember(u, nonNulls, "none", null, (name, _) => {
|
|
788
|
-
this.emitLine("case .", name, "(let x):");
|
|
789
|
-
this.indent(() => this.emitLine("try container.encode(x)"));
|
|
790
|
-
});
|
|
791
|
-
if (maybeNull !== null) {
|
|
792
|
-
this.emitLine("case .", this.nameForUnionMember(u, maybeNull), ":");
|
|
793
|
-
this.indent(() => this.emitLine("try container.encodeNil()"));
|
|
794
|
-
}
|
|
795
|
-
this.emitLine("}");
|
|
796
|
-
});
|
|
703
|
+
else {
|
|
704
|
+
if (group.length > 0) {
|
|
705
|
+
groups.push(group);
|
|
706
|
+
group = [];
|
|
707
|
+
}
|
|
708
|
+
groups.push([{ name, label }]);
|
|
797
709
|
}
|
|
798
710
|
});
|
|
799
|
-
|
|
711
|
+
if (group.length > 0) {
|
|
712
|
+
groups.push(group);
|
|
713
|
+
}
|
|
714
|
+
return groups;
|
|
800
715
|
}
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
716
|
+
/// Access level with trailing space (e.g. "public "), or empty string
|
|
717
|
+
get accessLevel() {
|
|
718
|
+
return this._options.accessLevel === "internal"
|
|
719
|
+
? "" // internal is default, so we don't have to emit it
|
|
720
|
+
: this._options.accessLevel + " ";
|
|
721
|
+
}
|
|
722
|
+
get objcMembersDeclaration() {
|
|
723
|
+
if (this._options.objcSupport) {
|
|
724
|
+
return "@objcMembers ";
|
|
805
725
|
}
|
|
806
|
-
|
|
807
|
-
|
|
726
|
+
return "";
|
|
727
|
+
}
|
|
728
|
+
/// startFile takes a file name, appends ".swift" to it and sets it as the current filename.
|
|
729
|
+
startFile(basename) {
|
|
730
|
+
if (this._options.multiFileOutput === false) {
|
|
731
|
+
return;
|
|
808
732
|
}
|
|
809
|
-
|
|
733
|
+
Support_1.assert(this._currentFilename === undefined, "Previous file wasn't finished: " + this._currentFilename);
|
|
734
|
+
// FIXME: The filenames should actually be Sourcelikes, too
|
|
735
|
+
this._currentFilename = `${this.sourcelikeToString(basename)}.swift`;
|
|
736
|
+
this.initializeEmitContextForFilename(this._currentFilename);
|
|
737
|
+
}
|
|
738
|
+
/// endFile pushes the current file name onto the collection of finished files and then resets the current file name. These finished files are used in index.ts to write the output.
|
|
739
|
+
endFile() {
|
|
740
|
+
if (this._options.multiFileOutput === false) {
|
|
810
741
|
return;
|
|
811
742
|
}
|
|
812
|
-
this.
|
|
813
|
-
|
|
814
|
-
this.emitLine("self = try newJSONDecoder().decode(", name, ".self, from: data)");
|
|
815
|
-
});
|
|
816
|
-
this.ensureBlankLine();
|
|
817
|
-
this.emitBlock("init(_ json: String, using encoding: String.Encoding = .utf8) throws", () => {
|
|
818
|
-
this.emitBlock("guard let data = json.data(using: encoding) else", () => {
|
|
819
|
-
this.emitLine(`throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)`);
|
|
820
|
-
});
|
|
821
|
-
this.emitLine("try self.init(data: data)");
|
|
822
|
-
});
|
|
823
|
-
this.ensureBlankLine();
|
|
824
|
-
this.emitBlock(`init(fromURL url: URL) throws`, () => {
|
|
825
|
-
this.emitLine("try self.init(data: try Data(contentsOf: url))");
|
|
826
|
-
});
|
|
827
|
-
this.ensureBlankLine();
|
|
828
|
-
this.emitBlock("func jsonData() throws -> Data", () => {
|
|
829
|
-
this.emitLine("return try newJSONEncoder().encode(self)");
|
|
830
|
-
});
|
|
831
|
-
this.ensureBlankLine();
|
|
832
|
-
this.emitBlock("func jsonString(encoding: String.Encoding = .utf8) throws -> String?", () => {
|
|
833
|
-
this.emitLine("return String(data: try self.jsonData(), encoding: encoding)");
|
|
834
|
-
});
|
|
835
|
-
});
|
|
743
|
+
this.finishFile(Support_1.defined(this._currentFilename));
|
|
744
|
+
this._currentFilename = undefined;
|
|
836
745
|
}
|
|
837
|
-
|
|
838
|
-
|
|
746
|
+
propertyLinesDefinition(name, parameter) {
|
|
747
|
+
const useMutableProperties = this._options.mutableProperties;
|
|
748
|
+
return [
|
|
749
|
+
this.accessLevel,
|
|
750
|
+
useMutableProperties ? "var " : "let ",
|
|
751
|
+
name,
|
|
752
|
+
": ",
|
|
753
|
+
this.swiftPropertyType(parameter)
|
|
754
|
+
];
|
|
839
755
|
}
|
|
840
|
-
|
|
841
|
-
this.startFile(
|
|
842
|
-
this.
|
|
843
|
-
this.
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
this.
|
|
850
|
-
this.emitMark("Helper functions for creating encoders and decoders", true);
|
|
851
|
-
this.ensureBlankLine();
|
|
852
|
-
this.emitNewEncoderDecoder();
|
|
853
|
-
}
|
|
854
|
-
if (this._options.alamofire) {
|
|
855
|
-
this.ensureBlankLine();
|
|
856
|
-
this.emitMark("Alamofire response handlers", true);
|
|
857
|
-
this.ensureBlankLine();
|
|
858
|
-
this.emitAlamofireExtension();
|
|
756
|
+
renderClassDefinition(c, className) {
|
|
757
|
+
this.startFile(className);
|
|
758
|
+
this.renderHeader(c, className);
|
|
759
|
+
this.emitDescription(this.descriptionForType(c));
|
|
760
|
+
this.emitMark(this.sourcelikeToString(className), true);
|
|
761
|
+
const isClass = this._options.useClasses || this.isCycleBreakerType(c);
|
|
762
|
+
const structOrClass = isClass ? "class" : "struct";
|
|
763
|
+
if (isClass && this._options.objcSupport) {
|
|
764
|
+
// [Michael Fey (@MrRooni), 2019-4-24] Swift 5 or greater, must come before the access declaration for the class.
|
|
765
|
+
this.emitItem(this.objcMembersDeclaration);
|
|
859
766
|
}
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
767
|
+
this.emitBlockWithAccess([structOrClass, " ", className, this.getProtocolString(c, isClass)], () => {
|
|
768
|
+
if (this._options.dense) {
|
|
769
|
+
let lastProperty = undefined;
|
|
770
|
+
let lastNames = [];
|
|
771
|
+
const emitLastProperty = () => {
|
|
772
|
+
if (lastProperty === undefined)
|
|
773
|
+
return;
|
|
774
|
+
const useMutableProperties = this._options.mutableProperties;
|
|
775
|
+
let sources = [
|
|
776
|
+
[
|
|
777
|
+
this._options.optionalEnums && lastProperty.type.kind === "enum"
|
|
778
|
+
? `@NilOnFail${this._options.namedTypePrefix} `
|
|
779
|
+
: "",
|
|
780
|
+
this.accessLevel,
|
|
781
|
+
useMutableProperties || (this._options.optionalEnums && lastProperty.type.kind === "enum")
|
|
782
|
+
? "var "
|
|
783
|
+
: "let "
|
|
784
|
+
]
|
|
785
|
+
];
|
|
786
|
+
lastNames.forEach((n, i) => {
|
|
787
|
+
if (i > 0)
|
|
788
|
+
sources.push(", ");
|
|
789
|
+
sources.push(n);
|
|
790
|
+
});
|
|
791
|
+
sources.push(": ");
|
|
792
|
+
sources.push(this.swiftPropertyType(lastProperty));
|
|
793
|
+
this.emitLine(sources);
|
|
794
|
+
lastProperty = undefined;
|
|
795
|
+
lastNames = [];
|
|
796
|
+
};
|
|
797
|
+
this.forEachClassProperty(c, "none", (name, jsonName, p) => {
|
|
798
|
+
const description = this.descriptionForClassProperty(c, jsonName);
|
|
799
|
+
if (!p.equals(lastProperty) ||
|
|
800
|
+
lastNames.length >= MAX_SAMELINE_PROPERTIES ||
|
|
801
|
+
description !== undefined) {
|
|
802
|
+
emitLastProperty();
|
|
803
|
+
}
|
|
804
|
+
if (lastProperty === undefined) {
|
|
805
|
+
lastProperty = p;
|
|
806
|
+
}
|
|
807
|
+
lastNames.push(name);
|
|
808
|
+
if (description !== undefined) {
|
|
809
|
+
this.emitDescription(description);
|
|
810
|
+
emitLastProperty();
|
|
811
|
+
}
|
|
812
|
+
});
|
|
813
|
+
emitLastProperty();
|
|
868
814
|
}
|
|
869
815
|
else {
|
|
870
|
-
this.
|
|
816
|
+
this.forEachClassProperty(c, "none", (name, jsonName, p) => {
|
|
817
|
+
const description = this.descriptionForClassProperty(c, jsonName);
|
|
818
|
+
const propertyLines = this.propertyLinesDefinition(name, p);
|
|
819
|
+
this.emitDescription(description);
|
|
820
|
+
this.emitLine(propertyLines);
|
|
821
|
+
});
|
|
871
822
|
}
|
|
872
|
-
this.
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
this.emitMultiline(` public var hashValue: Int {
|
|
879
|
-
return 0
|
|
880
|
-
}`);
|
|
881
|
-
if (this._options.swift5Support) {
|
|
823
|
+
if (!this._options.justTypes) {
|
|
824
|
+
const groups = this.getEnumPropertyGroups(c);
|
|
825
|
+
const allPropertiesRedundant = groups.every(group => {
|
|
826
|
+
return group.every(p => p.label === undefined);
|
|
827
|
+
});
|
|
828
|
+
if (!allPropertiesRedundant && c.getProperties().size > 0) {
|
|
882
829
|
this.ensureBlankLine();
|
|
883
|
-
this.
|
|
884
|
-
|
|
885
|
-
|
|
830
|
+
this.emitBlock("enum CodingKeys: String, CodingKey", () => {
|
|
831
|
+
for (const group of groups) {
|
|
832
|
+
const { name, label } = group[0];
|
|
833
|
+
if (this._options.explicitCodingKeys && label !== undefined) {
|
|
834
|
+
this.emitLine("case ", name, ' = "', label, '"');
|
|
835
|
+
}
|
|
836
|
+
else {
|
|
837
|
+
const names = collection_utils_1.arrayIntercalate(", ", group.map(p => p.name));
|
|
838
|
+
this.emitLine("case ", names);
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
});
|
|
886
842
|
}
|
|
887
843
|
}
|
|
888
|
-
this
|
|
889
|
-
|
|
890
|
-
|
|
844
|
+
// this main initializer must be defined within the class
|
|
845
|
+
// declaration since it assigns let constants
|
|
846
|
+
if (isClass ||
|
|
847
|
+
// Public structs need explicit initializers
|
|
848
|
+
// https://github.com/quicktype/quicktype/issues/899
|
|
849
|
+
this._options.accessLevel === "public") {
|
|
850
|
+
// Make an initializer that initalizes all fields
|
|
851
|
+
this.ensureBlankLine();
|
|
852
|
+
let initProperties = this.initializableProperties(c);
|
|
853
|
+
let propertiesLines = [];
|
|
854
|
+
for (let property of initProperties) {
|
|
855
|
+
if (propertiesLines.length > 0)
|
|
856
|
+
propertiesLines.push(", ");
|
|
857
|
+
propertiesLines.push(property.name, ": ", this.swiftPropertyType(property.parameter));
|
|
858
|
+
}
|
|
859
|
+
if (this.propertyCount(c) === 0 && this._options.objcSupport) {
|
|
860
|
+
this.emitBlockWithAccess(["override init()"], () => {
|
|
861
|
+
return "";
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
else {
|
|
865
|
+
this.emitBlockWithAccess(["init(", ...propertiesLines, ")"], () => {
|
|
866
|
+
for (let property of initProperties) {
|
|
867
|
+
this.emitLine("self.", property.name, " = ", property.name);
|
|
868
|
+
}
|
|
869
|
+
});
|
|
870
|
+
}
|
|
891
871
|
}
|
|
892
|
-
|
|
893
|
-
|
|
872
|
+
});
|
|
873
|
+
if (!this._options.justTypes) {
|
|
874
|
+
// FIXME: We emit only the MARK line for top-level-enum.schema
|
|
875
|
+
if (this._options.convenienceInitializers) {
|
|
876
|
+
this.ensureBlankLine();
|
|
877
|
+
this.emitMark(this.sourcelikeToString(className) + " convenience initializers and mutators");
|
|
878
|
+
this.ensureBlankLine();
|
|
879
|
+
this.emitConvenienceInitializersExtension(c, className);
|
|
880
|
+
this.ensureBlankLine();
|
|
894
881
|
}
|
|
895
|
-
this.emitMultiline(`public init() {}
|
|
896
|
-
|
|
897
|
-
public required init(from decoder: Decoder) throws {
|
|
898
|
-
let container = try decoder.singleValueContainer()
|
|
899
|
-
if !container.decodeNil() {
|
|
900
|
-
throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull"))
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
public func encode(to encoder: Encoder) throws {
|
|
905
|
-
var container = encoder.singleValueContainer()
|
|
906
|
-
try container.encodeNil()
|
|
907
|
-
}
|
|
908
|
-
}`);
|
|
909
882
|
}
|
|
910
|
-
|
|
911
|
-
this.ensureBlankLine();
|
|
912
|
-
this.emitMultiline(`class JSONCodingKey: CodingKey {
|
|
913
|
-
let key: String
|
|
914
|
-
|
|
915
|
-
required init?(intValue: Int) {
|
|
916
|
-
return nil
|
|
883
|
+
this.endFile();
|
|
917
884
|
}
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
885
|
+
initializableProperties(c) {
|
|
886
|
+
const properties = [];
|
|
887
|
+
this.forEachClassProperty(c, "none", (name, jsonName, parameter, position) => {
|
|
888
|
+
const property = { name, jsonName, parameter, position };
|
|
889
|
+
properties.push(property);
|
|
890
|
+
});
|
|
891
|
+
return properties;
|
|
921
892
|
}
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
893
|
+
emitNewEncoderDecoder() {
|
|
894
|
+
this.emitBlock("func newJSONDecoder() -> JSONDecoder", () => {
|
|
895
|
+
this.emitLine("let decoder = JSONDecoder()");
|
|
896
|
+
if (!this._options.linux) {
|
|
897
|
+
this.emitBlock("if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)", () => {
|
|
898
|
+
this.emitLine("decoder.dateDecodingStrategy = .iso8601");
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
else {
|
|
902
|
+
this.emitMultiline(`decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in
|
|
903
|
+
let container = try decoder.singleValueContainer()
|
|
904
|
+
let dateStr = try container.decode(String.self)
|
|
905
|
+
|
|
906
|
+
let formatter = DateFormatter()
|
|
907
|
+
formatter.calendar = Calendar(identifier: .iso8601)
|
|
908
|
+
formatter.locale = Locale(identifier: "en_US_POSIX")
|
|
909
|
+
formatter.timeZone = TimeZone(secondsFromGMT: 0)
|
|
910
|
+
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
|
|
911
|
+
if let date = formatter.date(from: dateStr) {
|
|
912
|
+
return date
|
|
925
913
|
}
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
return
|
|
914
|
+
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssXXXXX"
|
|
915
|
+
if let date = formatter.date(from: dateStr) {
|
|
916
|
+
return date
|
|
929
917
|
}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
918
|
+
throw DecodingError.typeMismatch(Date.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not decode date"))
|
|
919
|
+
})`);
|
|
920
|
+
}
|
|
921
|
+
this.emitLine("return decoder");
|
|
922
|
+
});
|
|
923
|
+
this.ensureBlankLine();
|
|
924
|
+
this.emitBlock("func newJSONEncoder() -> JSONEncoder", () => {
|
|
925
|
+
this.emitLine("let encoder = JSONEncoder()");
|
|
926
|
+
if (!this._options.linux) {
|
|
927
|
+
this.emitBlock("if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)", () => {
|
|
928
|
+
this.emitLine("encoder.dateEncodingStrategy = .iso8601");
|
|
929
|
+
});
|
|
934
930
|
}
|
|
935
931
|
else {
|
|
936
|
-
this.
|
|
932
|
+
this.emitMultiline(`let formatter = DateFormatter()
|
|
933
|
+
formatter.calendar = Calendar(identifier: .iso8601)
|
|
934
|
+
formatter.locale = Locale(identifier: "en_US_POSIX")
|
|
935
|
+
formatter.timeZone = TimeZone(secondsFromGMT: 0)
|
|
936
|
+
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssXXXXX"
|
|
937
|
+
encoder.dateEncodingStrategy = .formatted(formatter)`);
|
|
937
938
|
}
|
|
938
|
-
this.
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
static func decodingError(forCodingPath codingPath: [CodingKey]) -> DecodingError {
|
|
942
|
-
let context = DecodingError.Context(codingPath: codingPath, debugDescription: "Cannot decode JSONAny")
|
|
943
|
-
return DecodingError.typeMismatch(JSONAny.self, context)
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
static func encodingError(forValue value: Any, codingPath: [CodingKey]) -> EncodingError {
|
|
947
|
-
let context = EncodingError.Context(codingPath: codingPath, debugDescription: "Cannot encode JSONAny")
|
|
948
|
-
return EncodingError.invalidValue(value, context)
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
static func decode(from container: SingleValueDecodingContainer) throws -> Any {
|
|
952
|
-
if let value = try? container.decode(Bool.self) {
|
|
953
|
-
return value
|
|
954
|
-
}
|
|
955
|
-
if let value = try? container.decode(Int64.self) {
|
|
956
|
-
return value
|
|
957
|
-
}
|
|
958
|
-
if let value = try? container.decode(Double.self) {
|
|
959
|
-
return value
|
|
960
|
-
}
|
|
961
|
-
if let value = try? container.decode(String.self) {
|
|
962
|
-
return value
|
|
963
|
-
}
|
|
964
|
-
if container.decodeNil() {
|
|
965
|
-
return JSONNull()
|
|
966
|
-
}
|
|
967
|
-
throw decodingError(forCodingPath: container.codingPath)
|
|
939
|
+
this.emitLine("return encoder");
|
|
940
|
+
});
|
|
968
941
|
}
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
942
|
+
emitConvenienceInitializersExtension(c, className) {
|
|
943
|
+
const isClass = this._options.useClasses || this.isCycleBreakerType(c);
|
|
944
|
+
const convenience = isClass ? "convenience " : "";
|
|
945
|
+
this.emitBlockWithAccess(["extension ", className], () => {
|
|
946
|
+
if (isClass) {
|
|
947
|
+
this.emitBlock("convenience init(data: Data) throws", () => {
|
|
948
|
+
if (this.propertyCount(c) > 0) {
|
|
949
|
+
this.emitLine("let me = try newJSONDecoder().decode(", this.swiftType(c), ".self, from: data)");
|
|
950
|
+
}
|
|
951
|
+
else {
|
|
952
|
+
this.emitLine("let _ = try newJSONDecoder().decode(", this.swiftType(c), ".self, from: data)");
|
|
953
|
+
}
|
|
954
|
+
let args = [];
|
|
955
|
+
this.forEachClassProperty(c, "none", name => {
|
|
956
|
+
if (args.length > 0)
|
|
957
|
+
args.push(", ");
|
|
958
|
+
args.push(name, ": ", "me.", name);
|
|
959
|
+
});
|
|
960
|
+
this.emitLine("self.init(", ...args, ")");
|
|
961
|
+
});
|
|
986
962
|
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
963
|
+
else {
|
|
964
|
+
this.emitBlock("init(data: Data) throws", () => {
|
|
965
|
+
this.emitLine("self = try newJSONDecoder().decode(", this.swiftType(c), ".self, from: data)");
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
this.ensureBlankLine();
|
|
969
|
+
this.emitBlock([convenience, "init(_ json: String, using encoding: String.Encoding = .utf8) throws"], () => {
|
|
970
|
+
this.emitBlock("guard let data = json.data(using: encoding) else", () => {
|
|
971
|
+
this.emitLine(`throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)`);
|
|
972
|
+
});
|
|
973
|
+
this.emitLine("try self.init(data: data)");
|
|
974
|
+
});
|
|
975
|
+
this.ensureBlankLine();
|
|
976
|
+
this.emitBlock([convenience, `init(fromURL url: URL) throws`], () => {
|
|
977
|
+
this.emitLine("try self.init(data: try Data(contentsOf: url))");
|
|
978
|
+
});
|
|
979
|
+
this.ensureBlankLine();
|
|
980
|
+
this.emitConvenienceMutator(c, className);
|
|
981
|
+
// Convenience serializers
|
|
982
|
+
this.ensureBlankLine();
|
|
983
|
+
this.emitBlock(`func jsonData() throws -> Data`, () => {
|
|
984
|
+
this.emitLine("return try newJSONEncoder().encode(self)");
|
|
985
|
+
});
|
|
986
|
+
this.ensureBlankLine();
|
|
987
|
+
this.emitBlock(`func jsonString(encoding: String.Encoding = .utf8) throws -> String?`, () => {
|
|
988
|
+
this.emitLine("return String(data: try self.jsonData(), encoding: encoding)");
|
|
989
|
+
});
|
|
990
|
+
});
|
|
995
991
|
}
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
return value
|
|
1006
|
-
}
|
|
1007
|
-
if let value = try? container.decode(String.self, forKey: key) {
|
|
1008
|
-
return value
|
|
992
|
+
renderEnumDefinition(e, enumName) {
|
|
993
|
+
this.startFile(enumName);
|
|
994
|
+
this.emitLineOnce("import Foundation");
|
|
995
|
+
this.ensureBlankLine();
|
|
996
|
+
this.emitDescription(this.descriptionForType(e));
|
|
997
|
+
const protocols = [];
|
|
998
|
+
if (!this._options.justTypes) {
|
|
999
|
+
protocols.push("String"); // Not a protocol
|
|
1000
|
+
protocols.push("Codable");
|
|
1009
1001
|
}
|
|
1010
|
-
if
|
|
1011
|
-
|
|
1012
|
-
return JSONNull()
|
|
1013
|
-
}
|
|
1002
|
+
if (this._options.protocol.hashable) {
|
|
1003
|
+
protocols.push("Hashable");
|
|
1014
1004
|
}
|
|
1015
|
-
if
|
|
1016
|
-
|
|
1005
|
+
if (this._options.protocol.equatable) {
|
|
1006
|
+
protocols.push("Equatable");
|
|
1017
1007
|
}
|
|
1018
|
-
|
|
1019
|
-
|
|
1008
|
+
const protocolString = protocols.length > 0 ? ": " + protocols.join(", ") : "";
|
|
1009
|
+
if (this._options.justTypes) {
|
|
1010
|
+
this.emitBlockWithAccess(["enum ", enumName, protocolString], () => {
|
|
1011
|
+
this.forEachEnumCase(e, "none", name => {
|
|
1012
|
+
this.emitLine("case ", name);
|
|
1013
|
+
});
|
|
1014
|
+
});
|
|
1020
1015
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
let value = try decode(from: &container)
|
|
1028
|
-
arr.append(value)
|
|
1016
|
+
else {
|
|
1017
|
+
this.emitBlockWithAccess(["enum ", enumName, protocolString], () => {
|
|
1018
|
+
this.forEachEnumCase(e, "none", (name, jsonName) => {
|
|
1019
|
+
this.emitLine("case ", name, ' = "', stringEscape(jsonName), '"');
|
|
1020
|
+
});
|
|
1021
|
+
});
|
|
1029
1022
|
}
|
|
1030
|
-
|
|
1023
|
+
this.endFile();
|
|
1031
1024
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1025
|
+
renderUnionDefinition(u, unionName) {
|
|
1026
|
+
this.startFile(unionName);
|
|
1027
|
+
this.emitLineOnce("import Foundation");
|
|
1028
|
+
this.ensureBlankLine();
|
|
1029
|
+
function sortBy(t) {
|
|
1030
|
+
const kind = t.kind;
|
|
1031
|
+
if (kind === "class")
|
|
1032
|
+
return kind;
|
|
1033
|
+
return "_" + kind;
|
|
1038
1034
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
} else if let value = value as? [Any] {
|
|
1055
|
-
var container = container.nestedUnkeyedContainer()
|
|
1056
|
-
try encode(to: &container, array: value)
|
|
1057
|
-
} else if let value = value as? [String: Any] {
|
|
1058
|
-
var container = container.nestedContainer(keyedBy: JSONCodingKey.self)
|
|
1059
|
-
try encode(to: &container, dictionary: value)
|
|
1060
|
-
} else {
|
|
1061
|
-
throw encodingError(forValue: value, codingPath: container.codingPath)
|
|
1035
|
+
const renderUnionCase = (t) => {
|
|
1036
|
+
this.emitBlock(["if let x = try? container.decode(", this.swiftType(t), ".self)"], () => {
|
|
1037
|
+
this.emitLine("self = .", this.nameForUnionMember(u, t), "(x)");
|
|
1038
|
+
this.emitLine("return");
|
|
1039
|
+
});
|
|
1040
|
+
};
|
|
1041
|
+
this.emitDescription(this.descriptionForType(u));
|
|
1042
|
+
const indirect = this.isCycleBreakerType(u) ? "indirect " : "";
|
|
1043
|
+
const [maybeNull, nonNulls] = TypeUtils_1.removeNullFromUnion(u, sortBy);
|
|
1044
|
+
this.emitBlockWithAccess([indirect, "enum ", unionName, this.getProtocolString(u, false)], () => {
|
|
1045
|
+
this.forEachUnionMember(u, nonNulls, "none", null, (name, t) => {
|
|
1046
|
+
this.emitLine("case ", name, "(", this.swiftType(t), ")");
|
|
1047
|
+
});
|
|
1048
|
+
if (maybeNull !== null) {
|
|
1049
|
+
this.emitLine("case ", this.nameForUnionMember(u, maybeNull));
|
|
1062
1050
|
}
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1051
|
+
if (!this._options.justTypes) {
|
|
1052
|
+
this.ensureBlankLine();
|
|
1053
|
+
this.emitBlockWithAccess("init(from decoder: Decoder) throws", () => {
|
|
1054
|
+
this.emitLine("let container = try decoder.singleValueContainer()");
|
|
1055
|
+
const boolMember = u.findMember("bool");
|
|
1056
|
+
if (boolMember !== undefined)
|
|
1057
|
+
renderUnionCase(boolMember);
|
|
1058
|
+
const integerMember = u.findMember("integer");
|
|
1059
|
+
if (integerMember !== undefined)
|
|
1060
|
+
renderUnionCase(integerMember);
|
|
1061
|
+
for (const t of nonNulls) {
|
|
1062
|
+
if (t.kind === "bool" || t.kind === "integer")
|
|
1063
|
+
continue;
|
|
1064
|
+
renderUnionCase(t);
|
|
1065
|
+
}
|
|
1066
|
+
if (maybeNull !== null) {
|
|
1067
|
+
this.emitBlock("if container.decodeNil()", () => {
|
|
1068
|
+
this.emitLine("self = .", this.nameForUnionMember(u, maybeNull));
|
|
1069
|
+
this.emitLine("return");
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
this.emitDecodingError(unionName);
|
|
1073
|
+
});
|
|
1074
|
+
this.ensureBlankLine();
|
|
1075
|
+
this.emitBlockWithAccess("func encode(to encoder: Encoder) throws", () => {
|
|
1076
|
+
this.emitLine("var container = encoder.singleValueContainer()");
|
|
1077
|
+
this.emitLine("switch self {");
|
|
1078
|
+
this.forEachUnionMember(u, nonNulls, "none", null, (name, _) => {
|
|
1079
|
+
this.emitLine("case .", name, "(let x):");
|
|
1080
|
+
this.indent(() => this.emitLine("try container.encode(x)"));
|
|
1081
|
+
});
|
|
1082
|
+
if (maybeNull !== null) {
|
|
1083
|
+
this.emitLine("case .", this.nameForUnionMember(u, maybeNull), ":");
|
|
1084
|
+
this.indent(() => this.emitLine("try container.encodeNil()"));
|
|
1085
|
+
}
|
|
1086
|
+
this.emitLine("}");
|
|
1087
|
+
});
|
|
1087
1088
|
}
|
|
1088
|
-
}
|
|
1089
|
+
});
|
|
1090
|
+
this.endFile();
|
|
1089
1091
|
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
if
|
|
1093
|
-
|
|
1094
|
-
} else if let value = value as? Int64 {
|
|
1095
|
-
try container.encode(value)
|
|
1096
|
-
} else if let value = value as? Double {
|
|
1097
|
-
try container.encode(value)
|
|
1098
|
-
} else if let value = value as? String {
|
|
1099
|
-
try container.encode(value)
|
|
1100
|
-
} else if value is JSONNull {
|
|
1101
|
-
try container.encodeNil()
|
|
1102
|
-
} else {
|
|
1103
|
-
throw encodingError(forValue: value, codingPath: container.codingPath)
|
|
1092
|
+
emitTopLevelMapAndArrayConvenienceInitializerExtensions(t, name) {
|
|
1093
|
+
let extensionSource;
|
|
1094
|
+
if (t instanceof Type_1.ArrayType) {
|
|
1095
|
+
extensionSource = ["Array where Element == ", name, ".Element"];
|
|
1104
1096
|
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
public required init(from decoder: Decoder) throws {
|
|
1108
|
-
if var arrayContainer = try? decoder.unkeyedContainer() {
|
|
1109
|
-
self.value = try JSONAny.decodeArray(from: &arrayContainer)
|
|
1110
|
-
} else if var container = try? decoder.container(keyedBy: JSONCodingKey.self) {
|
|
1111
|
-
self.value = try JSONAny.decodeDictionary(from: &container)
|
|
1112
|
-
} else {
|
|
1113
|
-
let container = try decoder.singleValueContainer()
|
|
1114
|
-
self.value = try JSONAny.decode(from: container)
|
|
1097
|
+
else if (t instanceof Type_1.MapType) {
|
|
1098
|
+
extensionSource = ["Dictionary where Key == String, Value == ", this.swiftType(t.values)];
|
|
1115
1099
|
}
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
public func encode(to encoder: Encoder) throws {
|
|
1119
|
-
if let arr = self.value as? [Any] {
|
|
1120
|
-
var container = encoder.unkeyedContainer()
|
|
1121
|
-
try JSONAny.encode(to: &container, array: arr)
|
|
1122
|
-
} else if let dict = self.value as? [String: Any] {
|
|
1123
|
-
var container = encoder.container(keyedBy: JSONCodingKey.self)
|
|
1124
|
-
try JSONAny.encode(to: &container, dictionary: dict)
|
|
1125
|
-
} else {
|
|
1126
|
-
var container = encoder.singleValueContainer()
|
|
1127
|
-
try JSONAny.encode(to: &container, value: self.value)
|
|
1100
|
+
else {
|
|
1101
|
+
return;
|
|
1128
1102
|
}
|
|
1103
|
+
this.emitBlockWithAccess(["extension ", extensionSource], () => {
|
|
1104
|
+
this.emitBlock(["init(data: Data) throws"], () => {
|
|
1105
|
+
this.emitLine("self = try newJSONDecoder().decode(", name, ".self, from: data)");
|
|
1106
|
+
});
|
|
1107
|
+
this.ensureBlankLine();
|
|
1108
|
+
this.emitBlock("init(_ json: String, using encoding: String.Encoding = .utf8) throws", () => {
|
|
1109
|
+
this.emitBlock("guard let data = json.data(using: encoding) else", () => {
|
|
1110
|
+
this.emitLine(`throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)`);
|
|
1111
|
+
});
|
|
1112
|
+
this.emitLine("try self.init(data: data)");
|
|
1113
|
+
});
|
|
1114
|
+
this.ensureBlankLine();
|
|
1115
|
+
this.emitBlock(`init(fromURL url: URL) throws`, () => {
|
|
1116
|
+
this.emitLine("try self.init(data: try Data(contentsOf: url))");
|
|
1117
|
+
});
|
|
1118
|
+
this.ensureBlankLine();
|
|
1119
|
+
this.emitBlock("func jsonData() throws -> Data", () => {
|
|
1120
|
+
this.emitLine("return try newJSONEncoder().encode(self)");
|
|
1121
|
+
});
|
|
1122
|
+
this.ensureBlankLine();
|
|
1123
|
+
this.emitBlock("func jsonString(encoding: String.Encoding = .utf8) throws -> String?", () => {
|
|
1124
|
+
this.emitLine("return String(data: try self.jsonData(), encoding: encoding)");
|
|
1125
|
+
});
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1128
|
+
emitDecodingError(name) {
|
|
1129
|
+
this.emitLine("throw DecodingError.typeMismatch(", name, '.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for ', name, '"))');
|
|
1129
1130
|
}
|
|
1130
|
-
}`);
|
|
1131
|
-
}
|
|
1132
|
-
this.endFile();
|
|
1133
|
-
};
|
|
1134
1131
|
emitConvenienceMutator(c, className) {
|
|
1135
1132
|
this.emitLine("func with(");
|
|
1136
1133
|
this.indent(() => {
|