Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Adding type name suffixing for reserved keywords #3058

Merged
merged 2 commits into from
Jun 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions Sources/ApolloCodegenLib/Frontend/GraphQLSchema.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ public class GraphQLSchema: JavaScriptObject {

public class GraphQLNamedType: JavaScriptObject, Hashable {
lazy var name: String = self["name"]

var formattedName: String {
swiftName
}

lazy var documentation: String? = self["description"]

Expand Down Expand Up @@ -66,10 +70,26 @@ public class GraphQLScalarType: GraphQLNamedType {
return false
}
}

override var formattedName: String {
if !isCustomScalar {
return swiftName
}

let uppercasedName = swiftName.firstUppercased
return SwiftKeywords.TypeNamesToSuffix.contains(uppercasedName) ?
"\(uppercasedName)_Scalar" : uppercasedName
}
}

public class GraphQLEnumType: GraphQLNamedType {
lazy var values: [GraphQLEnumValue] = try! invokeMethod("getValues")

override var formattedName: String {
let uppercasedName = swiftName.firstUppercased
return SwiftKeywords.TypeNamesToSuffix.contains(uppercasedName) ?
"\(uppercasedName)_Enum" : uppercasedName
}
}

public class GraphQLEnumValue: JavaScriptObject {
Expand All @@ -91,6 +111,12 @@ typealias GraphQLInputFieldDictionary = OrderedDictionary<String, GraphQLInputFi

public class GraphQLInputObjectType: GraphQLNamedType {
lazy var fields: GraphQLInputFieldDictionary = try! invokeMethod("getFields")

override var formattedName: String {
let uppercasedName = swiftName.firstUppercased
return SwiftKeywords.TypeNamesToSuffix.contains(uppercasedName) ?
"\(uppercasedName)_InputObject" : uppercasedName
}
}

public class GraphQLInputField: JavaScriptObject {
Expand Down Expand Up @@ -131,6 +157,12 @@ public class GraphQLObjectType: GraphQLCompositeType, GraphQLInterfaceImplementi
lazy var fields: [String: GraphQLField] = try! invokeMethod("getFields")

lazy var interfaces: [GraphQLInterfaceType] = try! invokeMethod("getInterfaces")

override var formattedName: String {
let uppercasedName = swiftName.firstUppercased
return SwiftKeywords.TypeNamesToSuffix.contains(uppercasedName) ?
"\(uppercasedName)_Object" : uppercasedName
}

public override var debugDescription: String {
"Object - \(name)"
Expand All @@ -146,6 +178,12 @@ public class GraphQLInterfaceType: GraphQLAbstractType, GraphQLInterfaceImplemen
lazy var fields: [String: GraphQLField] = try! invokeMethod("getFields")

lazy var interfaces: [GraphQLInterfaceType] = try! invokeMethod("getInterfaces")

override var formattedName: String {
let uppercasedName = swiftName.firstUppercased
return SwiftKeywords.TypeNamesToSuffix.contains(uppercasedName) ?
"\(uppercasedName)_Interface" : uppercasedName
}

public override var debugDescription: String {
"Interface - \(name)"
Expand All @@ -154,6 +192,12 @@ public class GraphQLInterfaceType: GraphQLAbstractType, GraphQLInterfaceImplemen

public class GraphQLUnionType: GraphQLAbstractType {
lazy var types: [GraphQLObjectType] = try! invokeMethod("getTypes")

override var formattedName: String {
let uppercasedName = swiftName.firstUppercased
return SwiftKeywords.TypeNamesToSuffix.contains(uppercasedName) ?
"\(uppercasedName)_Union" : uppercasedName
}

public override var debugDescription: String {
"Union - \(name)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ struct CustomScalarTemplate: TemplateRenderer {
"""
\(documentation: documentationTemplate, config: config)
\(accessControlModifier(for: .parent))\
typealias \(graphqlScalar.name.firstUppercased) = String
typealias \(graphqlScalar.formattedName) = String

"""
)
Expand Down
2 changes: 1 addition & 1 deletion Sources/ApolloCodegenLib/Templates/EnumTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct EnumTemplate: TemplateRenderer {
"""
\(documentation: graphqlEnum.documentation, config: config)
\(accessControlModifier(for: .parent))\
enum \(graphqlEnum.name.firstUppercased): String, EnumType {
enum \(graphqlEnum.formattedName): String, EnumType {
\(graphqlEnum.values.compactMap({
enumCase(for: $0)
}), separator: "\n")
Expand Down
2 changes: 1 addition & 1 deletion Sources/ApolloCodegenLib/Templates/FragmentTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ struct FragmentTemplate: TemplateRenderer {
return TemplateString(
"""
\(accessControlModifier(for: .parent))\
struct \(fragment.generatedDefinitionName): \
struct \(fragment.generatedDefinitionName.asFragmentName): \
\(definition.renderedSelectionSetType(config)), Fragment {
\(accessControlModifier(for: .member))\
static var fragmentDefinition: StaticString { ""\"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ struct InputObjectTemplate: TemplateRenderer {
"""
\(documentation: graphqlInputObject.documentation, config: config)
\(accessControlModifier(for: .parent))\
struct \(graphqlInputObject.name.firstUppercased): InputObject {
struct \(graphqlInputObject.formattedName): InputObject {
\(memberAccessControl)private(set) var __data: InputDict

\(memberAccessControl)init(_ data: InputDict) {
Expand Down
2 changes: 1 addition & 1 deletion Sources/ApolloCodegenLib/Templates/InterfaceTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ struct InterfaceTemplate: TemplateRenderer {
var template: TemplateString {
"""
\(documentation: graphqlInterface.documentation, config: config)
static let \(graphqlInterface.name.firstUppercased) = Interface(name: "\(graphqlInterface.name)")
static let \(graphqlInterface.formattedName) = Interface(name: "\(graphqlInterface.name)")
"""
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ struct MockInterfacesTemplate: TemplateRenderer {
TemplateString("""
\(accessControlModifier(for: .parent))extension MockObject {
\(graphQLInterfaces.map {
"typealias \($0.name.firstUppercased) = Interface"
"typealias \($0.formattedName) = Interface"
}, separator: "\n")
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/ApolloCodegenLib/Templates/MockObjectTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ struct MockObjectTemplate: TemplateRenderer {
)

var template: TemplateString {
let objectName = graphqlObject.name.firstUppercased
let objectName = graphqlObject.formattedName
let fields: [TemplateField] = ir.fieldCollector
.collectedFields(for: graphqlObject)
.map {
Expand Down Expand Up @@ -94,7 +94,7 @@ struct MockObjectTemplate: TemplateRenderer {
case is GraphQLInterfaceType, is GraphQLUnionType:
mockType = "AnyMock"
default:
mockType = "Mock<\(graphQLCompositeType.name.firstUppercased)>"
mockType = "Mock<\(graphQLCompositeType.formattedName)>"
}
return TemplateString("\(mockType)\(if: !forceNonNull, "?")").description
case .scalar,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ struct MockUnionsTemplate: TemplateRenderer {
TemplateString("""
\(accessControlModifier(for: .parent))extension MockObject {
\(graphQLUnions.map {
"typealias \($0.name.firstUppercased) = Union"
"typealias \($0.formattedName) = Union"
}, separator: "\n")
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/ApolloCodegenLib/Templates/ObjectTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ struct ObjectTemplate: TemplateRenderer {
var template: TemplateString {
"""
\(documentation: graphqlObject.documentation, config: config)
static let \(graphqlObject.name.firstUppercased) = Object(
static let \(graphqlObject.formattedName) = Object(
typename: "\(graphqlObject.name)\",
implementedInterfaces: \(ImplementedInterfacesTemplate())
)
Expand All @@ -25,7 +25,7 @@ struct ObjectTemplate: TemplateRenderer {
[\(list: graphqlObject.interfaces.map({ interface in
TemplateString("""
\(if: !config.output.schemaTypes.isInModule, "\(config.schemaNamespace.firstUppercased).")\
Interfaces.\(interface.name.firstUppercased).self
Interfaces.\(interface.formattedName).self
""")
}))]
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ struct OperationDefinitionTemplate: OperationTemplateRenderer {
definition: .init(
\(operation.source.formatted(for: config.options.queryStringLiteralFormat))\(if: includeFragments, ",")
\(if: includeFragments,
"fragments: [\(fragments.map { "\($0.name.firstUppercased).self" }, separator: ", ")]")
"fragments: [\(fragments.map { "\($0.name.asFragmentName).self" }, separator: ", ")]")
))
""",
else: """
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,10 @@ extension GraphQLNamedType {
var testMockFieldTypeName: String {
if SwiftKeywords.TestMockFieldAbstractTypeNamesToNamespace.contains(name) &&
self is GraphQLAbstractType {
return "MockObject.\(swiftName)"
return "MockObject.\(formattedName)"
}

return swiftName
return formattedName
}

fileprivate func qualifiedRootTypeName(
Expand All @@ -154,7 +154,7 @@ extension GraphQLNamedType {
if case .testMockField = context {
return newTypeName ?? testMockFieldTypeName.firstUppercased
} else {
return newTypeName ?? self.swiftName.firstUppercased
return newTypeName ?? self.formattedName
}
}()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@ extension String {
}

var asSelectionSetName: String {
SwiftKeywords.SelectionSetTypeNamesToSuffix.contains(self) ?
SwiftKeywords.TypeNamesToSuffix.contains(self) ?
"\(self)_SelectionSet" : self
}

var asFragmentName: String {
let uppercasedName = self.firstUppercased
return SwiftKeywords.TypeNamesToSuffix.contains(uppercasedName) ?
"\(uppercasedName)_Fragment" : uppercasedName
}

var asTestMockFieldPropertyName: String {
escapeIf(in: SwiftKeywords.TestMockFieldNamesToEscape)
}
Expand Down Expand Up @@ -54,7 +60,7 @@ enum SwiftKeywords {
"apollo", "apolloapi"
]

static let SelectionSetTypeNamesToSuffix: Set<String> = [
static let TypeNamesToSuffix: Set<String> = [
"Any",
"DataDict",
"DocumentType",
Expand All @@ -72,6 +78,7 @@ enum SwiftKeywords {
"Double",
"ID",
"Type",
"Error",
"_",
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ struct SchemaMetadataTemplate: TemplateRenderer {
static func objectType(forTypename typename: String) -> Object? {
switch typename {
\(schema.referencedTypes.objects.map {
"case \"\($0.name)\": return \(schemaNamespace).Objects.\($0.name.firstUppercased)"
"case \"\($0.name)\": return \(schemaNamespace).Objects.\($0.formattedName)"
}, separator: "\n")
default: return nil
}
Expand Down
12 changes: 6 additions & 6 deletions Sources/ApolloCodegenLib/Templates/SelectionSetTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ struct SelectionSetTemplate {
pluralizer: config.pluralizer))
\(if: config.options.schemaDocumentation == .include, """
///
/// Parent Type: `\(selectionSet.parentType.name.firstUppercased)`
/// Parent Type: `\(selectionSet.parentType.formattedName)`
""")
"""
}
Expand Down Expand Up @@ -162,7 +162,7 @@ struct SelectionSetTemplate {
}

private func GeneratedSchemaTypeReference(_ type: GraphQLCompositeType) -> TemplateString {
"\(config.schemaNamespace.firstUppercased).\(type.schemaTypesNamespace).\(type.name.firstUppercased)"
"\(config.schemaNamespace.firstUppercased).\(type.schemaTypesNamespace).\(type.formattedName)"
}

// MARK: - Selections
Expand Down Expand Up @@ -285,7 +285,7 @@ struct SelectionSetTemplate {

private func FragmentSelectionTemplate(_ fragment: IR.FragmentSpread) -> TemplateString {
"""
.fragment(\(fragment.definition.name.firstUppercased).self)
.fragment(\(fragment.definition.name.asFragmentName).self)
"""
}

Expand Down Expand Up @@ -380,7 +380,7 @@ struct SelectionSetTemplate {
) -> TemplateString {
let name = fragment.definition.name
let propertyName = name.firstLowercased
let typeName = name.firstUppercased
let typeName = name.asFragmentName
let isOptional = fragment.inclusionConditions != nil &&
!scope.matches(fragment.inclusionConditions.unsafelyUnwrapped)

Expand Down Expand Up @@ -505,7 +505,7 @@ struct SelectionSetTemplate {
!selectionSet.typeInfo.scope.matches(conditions) {
continue
}
fulfilledFragments.append(fragment.definition.name.firstUppercased)
fulfilledFragments.append(fragment.definition.name.asFragmentName)
}

return """
Expand Down Expand Up @@ -838,7 +838,7 @@ fileprivate extension IR.ScopeCondition {

var selectionSetNameComponent: String {
return TemplateString("""
\(ifLet: type, { "As\($0.name.firstUppercased)" })\
\(ifLet: type, { "As\($0.formattedName)" })\
\(ifLet: conditions, { "If\($0.typeNameComponents)"})
""").description
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/ApolloCodegenLib/Templates/UnionTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct UnionTemplate: TemplateRenderer {
TemplateString(
"""
\(documentation: graphqlUnion.documentation, config: config)
static let \(graphqlUnion.name.firstUppercased) = Union(
static let \(graphqlUnion.formattedName) = Union(
name: "\(graphqlUnion.name)",
possibleTypes: \(PossibleTypesTemplate())
)
Expand All @@ -31,7 +31,7 @@ struct UnionTemplate: TemplateRenderer {
) -> TemplateString {
"""
\(if: !config.output.schemaTypes.isInModule, "\(config.schemaNamespace.firstUppercased).")\
Objects.\(type.name.firstUppercased).self
Objects.\(type.formattedName).self
"""
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class EnumFileGeneratorTests: XCTestCase {
// given
buildSubject()

let expected = graphqlEnum.name.firstUppercased
let expected = graphqlEnum.formattedName

// then
expect(self.subject.fileName).to(equal(expected))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,4 +214,27 @@ class CustomScalarTemplateTests: XCTestCase {
// then
expect(rendered).to(equalLineByLine(expected))
}

// MARK: - Reserved Keyword Tests

func test__render__givenCustomScalar_usingReservedKeyword_shouldRenderAsEscaped() throws {
let keywords = ["Type", "type"]

keywords.forEach { keyword in
// given
buildSubject(name: keyword)

let expected = """
typealias \(keyword.firstUppercased)_Scalar = String

"""

// when
let rendered = renderSubject()

// then
expect(rendered).to(equalLineByLine(expected))
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -461,4 +461,26 @@ class EnumTemplateTests: XCTestCase {
// then
expect(rendered).to(equalLineByLine(expected))
}

// MARK: - Reserved Keyword Tests

func test_render_givenReservedKeywordType_AsEscapedType() {
let keywords = ["Type", "type"]

keywords.forEach { keyword in
// given
buildSubject(name: keyword)

let expected = """
enum \(keyword.firstUppercased)_Enum: String, EnumType {
"""

// when
let actual = renderSubject()

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

}
Loading