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

Updating casing of variable names and keys #2996

Merged
merged 2 commits into from
May 8, 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
4 changes: 4 additions & 0 deletions Sources/ApolloCodegenLib/TemplateString.swift
Original file line number Diff line number Diff line change
Expand Up @@ -389,4 +389,8 @@ extension String {
return prefix(through: indexToChangeCase).lowercased() +
suffix(from: index(after: indexToChangeCase))
}

var isAllUppercased: Bool {
return self == self.uppercased()
}
}
10 changes: 5 additions & 5 deletions Sources/ApolloCodegenLib/Templates/InputObjectTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ struct InputObjectTemplate: TemplateRenderer {
) -> TemplateString {
TemplateString("""
\(fields.map({
"\($1.name.asInputParameterName): \($1.renderInputValueType(includeDefault: true, config: config.config))"
"\($1.name.asFieldPropertyName): \($1.renderInputValueType(includeDefault: true, config: config.config))"
}), separator: ",\n")
""")
}
Expand All @@ -100,17 +100,17 @@ struct InputObjectTemplate: TemplateRenderer {
_ fields: GraphQLInputFieldDictionary
) -> TemplateString {
TemplateString("""
\(fields.map({ "\"\($1.name)\": \($1.name.asInputParameterName)" }), separator: ",\n")
\(fields.map({ "\"\($1.name)\": \($1.name.asFieldPropertyName)" }), separator: ",\n")
""")
}

private func FieldPropertyTemplate(_ field: GraphQLInputField) -> TemplateString {
"""
\(documentation: field.documentation, config: config)
\(deprecationReason: field.deprecationReason, config: config)
public var \(field.name.asInputParameterName): \(field.renderInputValueType(config: config.config)) {
get { __data["\(field.name.firstLowercased)"] }
set { __data["\(field.name.firstLowercased)"] = newValue }
public var \(field.name.asFieldPropertyName): \(field.renderInputValueType(config: config.config)) {
get { __data["\(field.name)"] }
set { __data["\(field.name)"] = newValue }
}
"""
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ extension OperationTemplateRenderer {
return """
\(`init`)(\(list: variables.map(VariableParameter))) {
\(variables.map {
let name = $0.name.asInputParameterName
let name = $0.name.asFieldPropertyName
return "self.\(name) = \(name)"
}, separator: "\n")
}
Expand All @@ -24,15 +24,15 @@ extension OperationTemplateRenderer {
_ variables: [CompilationResult.VariableDefinition]
) -> TemplateString {
"""
\(variables.map { "public var \($0.name.asInputParameterName): \($0.type.rendered(as: .inputValue, config: config.config))"}, separator: "\n")
\(variables.map { "public var \($0.name.asFieldPropertyName): \($0.type.rendered(as: .inputValue, config: config.config))"}, separator: "\n")
"""
}

func VariableParameter(
_ variable: CompilationResult.VariableDefinition
) -> TemplateString {
"""
\(variable.name.asInputParameterName): \(variable.type.rendered(as: .inputValue, config: config.config))\
\(variable.name.asFieldPropertyName): \(variable.type.rendered(as: .inputValue, config: config.config))\
\(if: variable.defaultValue != nil, " = " + variable.renderVariableDefaultValue(config: config.config))
"""
}
Expand All @@ -46,7 +46,7 @@ extension OperationTemplateRenderer {
}

return """
public var __variables: \(if: !graphQLOperation, "GraphQLOperation.")Variables? { [\(list: variables.map { "\"\($0.name)\": \($0.name.asInputParameterName)"})] }
public var __variables: \(if: !graphQLOperation, "GraphQLOperation.")Variables? { [\(list: variables.map { "\"\($0.name)\": \($0.name.asFieldPropertyName)"})] }
"""
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import Foundation
extension String {
/// Renders the string as the property name for a field accessor on a generated `SelectionSet`.
/// This escapes the names of properties that would conflict with Swift reserved keywords.
var asFieldAccessorPropertyName: String {
escapeIf(in: SwiftKeywords.FieldAccessorNamesToEscape)
var asFieldPropertyName: String {
let str = self.isAllUppercased ? self.lowercased() : self.firstLowercased
return str.escapeIf(in: SwiftKeywords.FieldAccessorNamesToEscape)
}

var asEnumCaseName: String {
Expand All @@ -16,11 +17,7 @@ extension String {
SwiftKeywords.SelectionSetTypeNamesToSuffix.contains(self) ?
"\(self)_SelectionSet" : self
}

var asInputParameterName: String {
escapeIf(in: SwiftKeywords.InputParameterNamesToEscape).firstLowercased
}


var asTestMockFieldPropertyName: String {
escapeIf(in: SwiftKeywords.TestMockFieldNamesToEscape)
}
Expand Down
6 changes: 3 additions & 3 deletions Sources/ApolloCodegenLib/Templates/SelectionSetTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ struct SelectionSetTemplate {
return """
\(documentation: field.underlyingField.documentation, config: config)
\(deprecationReason: field.underlyingField.deprecationReason, config: config)
public var \(field.responseKey.firstLowercased.asFieldAccessorPropertyName): \
public var \(field.responseKey.asFieldPropertyName): \
\(typeName(for: field, forceOptional: field.isConditionallyIncluded(in: scope))) {\
\(if: isMutable,
"""
Expand Down Expand Up @@ -426,7 +426,7 @@ struct SelectionSetTemplate {
) -> TemplateString {
let isOptional: Bool = field.type.isNullable || field.isConditionallyIncluded(in: scope)
return """
\(field.responseKey.asInputParameterName): \(typeName(for: field, forceOptional: isOptional))\
\(field.responseKey.asFieldPropertyName): \(typeName(for: field, forceOptional: isOptional))\
\(if: isOptional, " = nil")
"""
}
Expand Down Expand Up @@ -459,7 +459,7 @@ struct SelectionSetTemplate {
}()

return """
"\(field.responseKey)": \(field.responseKey.asInputParameterName)\
"\(field.responseKey)": \(field.responseKey.asFieldPropertyName)\
\(if: isEntityField, "._fieldData")
"""
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,66 @@ class InputObjectTemplateTests: XCTestCase {
// then
expect(actual).to(equalLineByLine(expected, atLine: 8, ignoringExtraLines: false))
}

func test__render__givenSingleFieldTypeInMixedCase__generatesParameterAndInitializerWithCorrectCasing() throws {
// given
buildSubject(fields: [
GraphQLInputField.mock("Field", type: .scalar(.string()), defaultValue: nil)
])

let expected = """
public init(
field: GraphQLNullable<String> = nil
) {
__data = InputDict([
"Field": field
])
}

public var field: GraphQLNullable<String> {
get { __data["Field"] }
set { __data["Field"] = newValue }
}
}

"""

// when
let actual = renderSubject()

// then
expect(actual).to(equalLineByLine(expected, atLine: 8, ignoringExtraLines: false))
}

func test__render__givenSingleFieldTypeInAllUppercase__generatesParameterAndInitializerWithCorrectCasing() throws {
// given
buildSubject(fields: [
GraphQLInputField.mock("FIELDNAME", type: .scalar(.string()), defaultValue: nil)
])

let expected = """
public init(
fieldname: GraphQLNullable<String> = nil
) {
__data = InputDict([
"FIELDNAME": fieldname
])
}

public var fieldname: GraphQLNullable<String> {
get { __data["FIELDNAME"] }
set { __data["FIELDNAME"] = newValue }
}
}

"""

// when
let actual = renderSubject()

// then
expect(actual).to(equalLineByLine(expected, atLine: 8, ignoringExtraLines: false))
}

func test__render__givenAllPossibleSchemaInputFieldTypes__generatesCorrectParametersAndInitializer() throws {
// given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,90 @@ class OperationDefinition_VariableDefinition_Tests: XCTestCase {
// then
expect(actual).to(equal(expected))
}

func test__renderOperationVariableProperty_givenAllUppercaseVariableName_generatesCorrectlyCasedVariable() throws {
// given
subject = .mock("VARIABLE", type: .string(), defaultValue: nil)

let expected = "public var variable: GraphQLNullable<String>"

// when
buildTemplate()
let actual = template.VariableProperties([subject]).description

// then
expect(actual).to(equal(expected))
}

func test__renderOperationVariableProperty_givenMixedCaseVariableName_generatesCorrectlyCasedVariable() throws {
// given
subject = .mock("VariableName", type: .string(), defaultValue: nil)

let expected = "public var variableName: GraphQLNullable<String>"

// when
buildTemplate()
let actual = template.VariableProperties([subject]).description

// then
expect(actual).to(equal(expected))
}

func test__renderOperationVariableParameter_givenAllUppercaseVariableName_generatesCorrectlyCasedVariable() throws {
// given
subject = .mock("VARIABLE", type: .string(), defaultValue: nil)

let expected = "variable: GraphQLNullable<String>"

// when
buildTemplate()
let actual = template.VariableParameter(subject).description

// then
expect(actual).to(equal(expected))
}

func test__renderOperationVariableParameter_givenMixedCaseVariableName_generatesCorrectlyCasedVariable() throws {
// given
subject = .mock("VariableName", type: .string(), defaultValue: nil)

let expected = "variableName: GraphQLNullable<String>"

// when
buildTemplate()
let actual = template.VariableParameter(subject).description

// then
expect(actual).to(equal(expected))
}

func test__renderOperationVariableAccessor_givenAllUppercaseVariableName_generatesCorrectlyCasedVariable() throws {
// given
subject = .mock("VARIABLE", type: .string(), defaultValue: nil)

let expected = "public var __variables: Variables? { [\"VARIABLE\": variable] }"

// when
buildTemplate()
let actual = template.VariableAccessors([subject]).description

// then
expect(actual).to(equal(expected))
}

func test__renderOperationVariableAccessor_givenMixedCaseVariableName_generatesCorrectlyCasedVariable() throws {
// given
subject = .mock("VariableName", type: .string(), defaultValue: nil)

let expected = "public var __variables: Variables? { [\"VariableName\": variableName] }"

// when
buildTemplate()
let actual = template.VariableAccessors([subject]).description

// then
expect(actual).to(equal(expected))
}

func test__renderOperationVariableParameter_includeDefaultTrue__givenAllInputFieldTypes_nilDefaultValues__generatesCorrectParametersWithoutInitializer() throws {
// given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,45 @@ class SelectionSetTemplateTests: XCTestCase {
// then
expect(actual).to(equalLineByLine(expected, atLine: 7, ignoringExtraLines: true))
}

func test__render_selections__givenAllUppercase_generatesCorrectCasing() throws {
// given
schemaSDL = """
type Query {
allAnimals: [Animal!]
}

type Animal {
FIELDNAME: String
}
"""

document = """
query TestOperation {
allAnimals {
FIELDNAME
}
}
"""

let expected = """
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("FIELDNAME", String?.self),
] }
"""

// when
try buildSubjectAndOperation()
let allAnimals = try XCTUnwrap(
operation[field: "query"]?[field: "allAnimals"] as? IR.EntityField
)

let actual = subject.render(field: allAnimals)

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

func test__render_selections__givenCustomScalar_rendersFieldSelectionsWithNamespaceInAllConfigurations() throws {
// given
Expand Down Expand Up @@ -2405,6 +2444,42 @@ class SelectionSetTemplateTests: XCTestCase {
// then
expect(actual).to(equalLineByLine(expected, atLine: 12, ignoringExtraLines: true))
}

func test__render_fieldAccessors__givenFieldWithAllUpperCaseName_rendersFieldAccessorWithLowercaseName() throws {
// given
schemaSDL = """
type Query {
AllAnimals: [Animal!]
}

type Animal {
FIELDNAME: String!
}
"""

document = """
query TestOperation {
AllAnimals {
FIELDNAME
}
}
"""

let expected = """
public var fieldname: String { __data["FIELDNAME"] }
"""

// when
try buildSubjectAndOperation()
let allAnimals = try XCTUnwrap(
operation[field: "query"]?[field: "AllAnimals"] as? IR.EntityField
)

let actual = subject.render(field: allAnimals)

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

func test__render_fieldAccessors__givenFieldWithAlias_rendersAllFieldAccessors() throws {
// given
Expand Down Expand Up @@ -4068,6 +4143,8 @@ class SelectionSetTemplateTests: XCTestCase {
// then
expect(actual).to(equalLineByLine(expected, atLine: 8, ignoringExtraLines: true))
}



// MARK: - Inline Fragment Accessors

Expand Down
Loading