Skip to content

Commit

Permalink
feature: final class definitions for graphql codegen (#3189)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mordil authored Sep 5, 2023
1 parent 0773964 commit 5f93599
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 93 deletions.
29 changes: 24 additions & 5 deletions Sources/ApolloCodegenLib/ApolloCodegenConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,8 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
///
/// Defaults to `true`.
public let pruneGeneratedFiles: Bool
/// Whether generated GraphQL operation and local cache mutation class types will be marked as `final`.
public let markOperationDefinitionsAsFinal: Bool

/// Default property values
public struct Default {
Expand All @@ -515,6 +517,7 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
public static let warningsOnDeprecatedUsage: Composition = .include
public static let conversionStrategies: ConversionStrategies = .init()
public static let pruneGeneratedFiles: Bool = true
public static let markOperationDefinitionsAsFinal: Bool = false
}

/// Designated initializer.
Expand All @@ -535,6 +538,7 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
/// - conversionStrategies: Rules for how to convert the names of values from the schema in
/// generated code.
/// - pruneGeneratedFiles: Whether unused generated files will be automatically deleted.
/// - markOperationDefinitionsAsFinal: Whether generated GraphQL operation and local cache mutation class types will be marked as `final`.
public init(
additionalInflectionRules: [InflectionRule] = Default.additionalInflectionRules,
deprecatedEnumCases: Composition = Default.deprecatedEnumCases,
Expand All @@ -544,7 +548,8 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
cocoapodsCompatibleImportStatements: Bool = Default.cocoapodsCompatibleImportStatements,
warningsOnDeprecatedUsage: Composition = Default.warningsOnDeprecatedUsage,
conversionStrategies: ConversionStrategies = Default.conversionStrategies,
pruneGeneratedFiles: Bool = Default.pruneGeneratedFiles
pruneGeneratedFiles: Bool = Default.pruneGeneratedFiles,
markOperationDefinitionsAsFinal: Bool = Default.markOperationDefinitionsAsFinal
) {
self.additionalInflectionRules = additionalInflectionRules
self.deprecatedEnumCases = deprecatedEnumCases
Expand All @@ -555,6 +560,7 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
self.warningsOnDeprecatedUsage = warningsOnDeprecatedUsage
self.conversionStrategies = conversionStrategies
self.pruneGeneratedFiles = pruneGeneratedFiles
self.markOperationDefinitionsAsFinal = markOperationDefinitionsAsFinal
}

// MARK: Codable
Expand All @@ -571,6 +577,7 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
case warningsOnDeprecatedUsage
case conversionStrategies
case pruneGeneratedFiles
case markOperationDefinitionsAsFinal
}

public init(from decoder: Decoder) throws {
Expand Down Expand Up @@ -626,6 +633,11 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
Bool.self,
forKey: .pruneGeneratedFiles
) ?? Default.pruneGeneratedFiles

markOperationDefinitionsAsFinal = try values.decodeIfPresent(
Bool.self,
forKey: .markOperationDefinitionsAsFinal
) ?? Default.markOperationDefinitionsAsFinal
}

public func encode(to encoder: Encoder) throws {
Expand All @@ -640,6 +652,7 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
try container.encode(self.warningsOnDeprecatedUsage, forKey: .warningsOnDeprecatedUsage)
try container.encode(self.conversionStrategies, forKey: .conversionStrategies)
try container.encode(self.pruneGeneratedFiles, forKey: .pruneGeneratedFiles)
try container.encode(self.markOperationDefinitionsAsFinal, forKey: .markOperationDefinitionsAsFinal)
}
}

Expand Down Expand Up @@ -1332,8 +1345,9 @@ extension ApolloCodegenConfiguration.OutputOptions {
/// - conversionStrategies: Rules for how to convert the names of values from the schema in
/// generated code.
/// - pruneGeneratedFiles: Whether unused generated files will be automatically deleted.
/// - markOperationDefinitionsAsFinal: Whether generated GraphQL operation and local cache mutation class types will be marked as `final`.
@available(*, deprecated,
renamed: "init(additionalInflectionRules:queryStringLiteralFormat:deprecatedEnumCases:schemaDocumentation:selectionSetInitializers:operationDocumentFormat:cocoapodsCompatibleImportStatements:warningsOnDeprecatedUsage:conversionStrategies:pruneGeneratedFiles:)"
renamed: "init(additionalInflectionRules:queryStringLiteralFormat:deprecatedEnumCases:schemaDocumentation:selectionSetInitializers:operationDocumentFormat:cocoapodsCompatibleImportStatements:warningsOnDeprecatedUsage:conversionStrategies:pruneGeneratedFiles:markOperationDefinitionsAsFinal:)"
)
public init(
additionalInflectionRules: [InflectionRule] = Default.additionalInflectionRules,
Expand All @@ -1345,7 +1359,8 @@ extension ApolloCodegenConfiguration.OutputOptions {
cocoapodsCompatibleImportStatements: Bool = Default.cocoapodsCompatibleImportStatements,
warningsOnDeprecatedUsage: ApolloCodegenConfiguration.Composition = Default.warningsOnDeprecatedUsage,
conversionStrategies: ApolloCodegenConfiguration.ConversionStrategies = Default.conversionStrategies,
pruneGeneratedFiles: Bool = Default.pruneGeneratedFiles
pruneGeneratedFiles: Bool = Default.pruneGeneratedFiles,
markOperationDefinitionsAsFinal: Bool = Default.markOperationDefinitionsAsFinal
) {
self.additionalInflectionRules = additionalInflectionRules
self.deprecatedEnumCases = deprecatedEnumCases
Expand All @@ -1356,6 +1371,7 @@ extension ApolloCodegenConfiguration.OutputOptions {
self.warningsOnDeprecatedUsage = warningsOnDeprecatedUsage
self.conversionStrategies = conversionStrategies
self.pruneGeneratedFiles = pruneGeneratedFiles
self.markOperationDefinitionsAsFinal = markOperationDefinitionsAsFinal
}

/// Deprecated initializer.
Expand All @@ -1378,8 +1394,9 @@ extension ApolloCodegenConfiguration.OutputOptions {
/// - conversionStrategies: Rules for how to convert the names of values from the schema in
/// generated code.
/// - pruneGeneratedFiles: Whether unused generated files will be automatically deleted.
/// - markOperationDefinitionsAsFinal: Whether generated GraphQL operation and local cache mutation class types will be marked as `final`.
@available(*, deprecated,
renamed: "init(additionalInflectionRules:deprecatedEnumCases:schemaDocumentation:selectionSetInitializers:operationDocumentFormat:cocoapodsCompatibleImportStatements:warningsOnDeprecatedUsage:conversionStrategies:pruneGeneratedFiles:)"
renamed: "init(additionalInflectionRules:deprecatedEnumCases:schemaDocumentation:selectionSetInitializers:operationDocumentFormat:cocoapodsCompatibleImportStatements:warningsOnDeprecatedUsage:conversionStrategies:pruneGeneratedFiles:markOperationDefinitionsAsFinal:)"
)
public init(
additionalInflectionRules: [InflectionRule] = Default.additionalInflectionRules,
Expand All @@ -1391,7 +1408,8 @@ extension ApolloCodegenConfiguration.OutputOptions {
cocoapodsCompatibleImportStatements: Bool = Default.cocoapodsCompatibleImportStatements,
warningsOnDeprecatedUsage: ApolloCodegenConfiguration.Composition = Default.warningsOnDeprecatedUsage,
conversionStrategies: ApolloCodegenConfiguration.ConversionStrategies = Default.conversionStrategies,
pruneGeneratedFiles: Bool = Default.pruneGeneratedFiles
pruneGeneratedFiles: Bool = Default.pruneGeneratedFiles,
markOperationDefinitionsAsFinal: Bool = Default.markOperationDefinitionsAsFinal
) {
self.additionalInflectionRules = additionalInflectionRules
self.deprecatedEnumCases = deprecatedEnumCases
Expand All @@ -1402,6 +1420,7 @@ extension ApolloCodegenConfiguration.OutputOptions {
self.warningsOnDeprecatedUsage = warningsOnDeprecatedUsage
self.conversionStrategies = conversionStrategies
self.pruneGeneratedFiles = pruneGeneratedFiles
self.markOperationDefinitionsAsFinal = markOperationDefinitionsAsFinal
}

/// Whether the generated operations should use Automatic Persisted Queries.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct LocalCacheMutationDefinitionTemplate: OperationTemplateRenderer {
return TemplateString(
"""
\(accessControlModifier(for: .parent))\
class \(operation.generatedDefinitionName): LocalCacheMutation {
\(classDefinitionKeywords) \(operation.generatedDefinitionName): LocalCacheMutation {
\(memberAccessControl)static let operationType: GraphQLOperationType = .\(operation.definition.operationType.rawValue)
\(section: VariableProperties(operation.definition.variables))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ struct OperationDefinitionTemplate: OperationTemplateRenderer {
private func OperationDeclaration() -> TemplateString {
return """
\(accessControlModifier(for: .parent))\
class \(operation.generatedDefinitionName): \
\(classDefinitionKeywords) \(operation.generatedDefinitionName): \
\(operation.definition.operationType.renderedProtocolName) {
\(accessControlModifier(for: .member))\
static let operationName: String = "\(operation.definition.name)"
Expand Down
2 changes: 2 additions & 0 deletions Sources/ApolloCodegenLib/Templates/TemplateRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ enum AccessControlScope {
}

extension TemplateRenderer {
var classDefinitionKeywords: String { config.options.markOperationDefinitionsAsFinal ? "final class" : "class" }

func accessControlModifier(for scope: AccessControlScope) -> String {
switch target {
case .moduleFile, .schemaFile: return schemaAccessControlModifier(scope: scope)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ class ApolloCodegenConfigurationCodableTests: XCTestCase {
enumCases: .none,
fieldAccessors: .camelCase
),
pruneGeneratedFiles: false
pruneGeneratedFiles: false,
markOperationDefinitionsAsFinal: true
),
experimentalFeatures: .init(
clientControlledNullability: true,
Expand Down Expand Up @@ -98,6 +99,7 @@ class ApolloCodegenConfigurationCodableTests: XCTestCase {
"fieldAccessors" : "camelCase"
},
"deprecatedEnumCases" : "exclude",
"markOperationDefinitionsAsFinal" : true,
"operationDocumentFormat" : [
"definition"
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,26 @@ class LocalCacheMutationDefinitionTemplateTests: XCTestCase {
expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true))
}

func test__generate_givenQuery_configIncludesMarkOperationDefinitionsAsFinal_generatesFinalLocalCacheMutation() throws {
// given
let expected =
"""
final class TestOperationLocalCacheMutation: LocalCacheMutation {
static let operationType: GraphQLOperationType = .query
"""

config = .mock(options: .init(markOperationDefinitionsAsFinal: true))

// when
try buildSubjectAndOperation()

let actual = renderSubject()

// then
expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true))
}


func test__generate__givenQueryWithLowercasing_generatesCorrectlyCasedLocalCacheMutation() throws {
// given
schemaSDL = """
Expand Down
Loading

0 comments on commit 5f93599

Please sign in to comment.