diff --git a/Sources/_OpenAPIGeneratorCore/Layers/StructuredSwiftRepresentation.swift b/Sources/_OpenAPIGeneratorCore/Layers/StructuredSwiftRepresentation.swift index 4a7cacef..1c7ec440 100644 --- a/Sources/_OpenAPIGeneratorCore/Layers/StructuredSwiftRepresentation.swift +++ b/Sources/_OpenAPIGeneratorCore/Layers/StructuredSwiftRepresentation.swift @@ -105,6 +105,11 @@ enum LiteralDescription: Equatable, Codable { /// For example `42`. case int(Int) + /// A double literal. + /// + /// For example `42.24`. + case double(Double) + /// A Boolean literal. /// /// For example `true`. diff --git a/Sources/_OpenAPIGeneratorCore/Renderer/TextBasedRenderer.swift b/Sources/_OpenAPIGeneratorCore/Renderer/TextBasedRenderer.swift index 6d9f5468..80a78352 100644 --- a/Sources/_OpenAPIGeneratorCore/Renderer/TextBasedRenderer.swift +++ b/Sources/_OpenAPIGeneratorCore/Renderer/TextBasedRenderer.swift @@ -453,6 +453,7 @@ struct TextBasedRenderer: RendererProtocol { write("\"\(string)\"") } case let .int(int): write("\(int)") + case let .double(double): write("\(double)") case let .bool(bool): write(bool ? "true" : "false") case .nil: write("nil") case .array(let items): diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateAllAnyOneOf.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateAllAnyOneOf.swift index 1816cabc..86d6ef16 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateAllAnyOneOf.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateAllAnyOneOf.swift @@ -73,10 +73,19 @@ extension TypesFileTranslator { } else { associatedDeclarations = [] } + + var defaultValue: PropertyBlueprint.DefaultValue? = nil + if let schemaDefaultValue = schema.defaultValue { + if let literalDescription = convertValueToLiteralDescription(schemaDefaultValue.value) { + defaultValue = .expression(.literal(literalDescription)) + } + } + let blueprint = PropertyBlueprint( comment: comment, originalName: key, typeUsage: propertyType, + default: defaultValue, associatedDeclarations: associatedDeclarations, context: context ) diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateArray.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateArray.swift index c9958420..f4ad4045 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateArray.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateArray.swift @@ -26,11 +26,15 @@ extension TypesFileTranslator { /// document. /// - arrayContext: The context for the array, including information such /// as the element schema. + /// - defaultValue: An optional default value for the array. /// - Throws: An error if there is an issue during translation. /// - Returns: A list of declarations representing the translated array. - func translateArray(typeName: TypeName, openAPIDescription: String?, arrayContext: JSONSchema.ArrayContext) throws - -> [Declaration] - { + func translateArray( + typeName: TypeName, + openAPIDescription: String?, + arrayContext: JSONSchema.ArrayContext, + defaultValue: AnyCodable? + ) throws -> [Declaration] { var inline: [Declaration] = [] @@ -61,6 +65,20 @@ extension TypesFileTranslator { existingType: .init(elementType.typeName.asUsage.asArray) ) ) - return inline + [arrayDecl] + inline.append(arrayDecl) + if let defaultValue, let literalDescription = convertValueToLiteralDescription(defaultValue.value) { + + let defaultDecl: Declaration = .variable( + accessModifier: config.access, + isStatic: true, + kind: .let, + left: "`default`", + type: .init(elementType.typeName.asUsage.asArray), + right: .literal(literalDescription) + ) + inline.append(defaultDecl) + } + + return inline } } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift index e2680fe6..81f760ae 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateObjectStruct.swift @@ -94,11 +94,20 @@ extension TypesFileTranslator { } else { associatedDeclarations = [] } + + var defaultValue: PropertyBlueprint.DefaultValue? = nil + if let schemaDefaultValue = value.defaultValue { + if let literalDescription = convertValueToLiteralDescription(schemaDefaultValue.value) { + defaultValue = .expression(.literal(literalDescription)) + } + } + return PropertyBlueprint( comment: comment, isDeprecated: value.deprecated, originalName: key, typeUsage: propertyType, + default: defaultValue, associatedDeclarations: associatedDeclarations, context: context ) diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift index e92b5605..0436b30b 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateSchema.swift @@ -90,14 +90,14 @@ extension TypesFileTranslator { // If this type maps to a referenceable schema, define a typealias if let builtinType = try typeMatcher.tryMatchReferenceableType(for: schema, components: components) { - let typealiasDecl = try translateTypealias( + return try translateTypealias( named: typeName, userDescription: overrides.userDescription ?? schema.description, to: builtinType.withOptional( overrides.isOptional ?? typeMatcher.isOptional(schema, components: components) - ) + ), + defaultValue: schema.defaultValue ) - return [typealiasDecl] } // Not a global schema, we have to actually define a type for it @@ -138,7 +138,8 @@ extension TypesFileTranslator { return try translateArray( typeName: typeName, openAPIDescription: overrides.userDescription ?? coreContext.description, - arrayContext: arrayContext + arrayContext: arrayContext, + defaultValue: coreContext.defaultValue ) case let .all(of: schemas, core: coreContext): let allOfDecl = try translateAllOrAnyOf( diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateTypealias.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateTypealias.swift index f6c2d48a..83c61620 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateTypealias.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateTypealias.swift @@ -20,17 +20,55 @@ extension FileTranslator { /// - typeName: The name of the type to give to the declared typealias. /// - userDescription: A user-specified description from the OpenAPI document. /// - existingTypeUsage: The existing type the alias points to. + /// - defaultValue: An optional default value for the typealias. /// - Throws: An error if there is an issue during translation. /// - Returns: A declaration representing the translated typealias. - func translateTypealias(named typeName: TypeName, userDescription: String?, to existingTypeUsage: TypeUsage) throws - -> Declaration - { + func translateTypealias( + named typeName: TypeName, + userDescription: String?, + to existingTypeUsage: TypeUsage, + defaultValue: AnyCodable? + ) throws -> [Declaration] { let typealiasDescription = TypealiasDescription( accessModifier: config.access, name: typeName.shortSwiftName, existingType: .init(existingTypeUsage.withOptional(false)) ) let typealiasComment: Comment? = typeName.docCommentWithUserDescription(userDescription) - return .commentable(typealiasComment, .typealias(typealiasDescription)) + + var declarations: [Declaration] = [.commentable(typealiasComment, .typealias(typealiasDescription))] + + if let defaultValue, let literalDescription = convertValueToLiteralDescription(defaultValue.value) { + let defaultDecl: Declaration = .variable( + accessModifier: config.access, + isStatic: true, + kind: .let, + left: "`default`", + type: .init(existingTypeUsage.withOptional(false)), + right: .literal(literalDescription) + ) + declarations.append(defaultDecl) + } + + return declarations + } + + /// Converts a given value to a `LiteralDescription`. + /// + /// - Parameter value: The value to be converted. + /// - Returns: A `LiteralDescription` representing the value, or `nil` if the value cannot be converted. + func convertValueToLiteralDescription(_ value: Any) -> LiteralDescription? { + switch value { + case let stringValue as String: return .string(stringValue) + case let intValue as Int: return .int(intValue) + case let boolValue as Bool: return .bool(boolValue) + case let doubleValue as Double: return .double(doubleValue) + case let arrayValue as [Any]: + let arrayExpressions = arrayValue.compactMap { element -> Expression? in + convertValueToLiteralDescription(element).map { .literal($0) } + } + return .array(arrayExpressions) + default: return nil + } } } diff --git a/Tests/OpenAPIGeneratorCoreTests/StructureHelpers.swift b/Tests/OpenAPIGeneratorCoreTests/StructureHelpers.swift index fc40833b..02d72114 100644 --- a/Tests/OpenAPIGeneratorCoreTests/StructureHelpers.swift +++ b/Tests/OpenAPIGeneratorCoreTests/StructureHelpers.swift @@ -126,6 +126,7 @@ extension LiteralDescription { switch self { case .string: return "string" case .int: return "int" + case .double: return "double" case .bool: return "bool" case .nil: return "nil" case .array: return "array"