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

Deprecating queryStringLiteralFormat #3129

Merged
merged 10 commits into from
Jul 20, 2023
89 changes: 64 additions & 25 deletions Sources/ApolloCodegenLib/ApolloCodegenConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -509,9 +509,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
public struct OutputOptions: Codable, Equatable {
/// Any non-default rules for pluralization or singularization you wish to include.
public let additionalInflectionRules: [InflectionRule]
/// Formatting of the GraphQL query string literal that is included in each
/// generated operation object.
public let queryStringLiteralFormat: QueryStringLiteralFormat
/// How deprecated enum cases from the schema should be handled.
public let deprecatedEnumCases: Composition
/// Whether schema documentation is added to the generated files.
Expand Down Expand Up @@ -560,7 +557,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
/// Default property values
public struct Default {
public static let additionalInflectionRules: [InflectionRule] = []
public static let queryStringLiteralFormat: QueryStringLiteralFormat = .multiline
public static let deprecatedEnumCases: Composition = .include
public static let schemaDocumentation: Composition = .include
public static let selectionSetInitializers: SelectionSetInitializers = [.localCacheMutations]
Expand All @@ -576,8 +572,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
/// - Parameters:
/// - additionalInflectionRules: Any non-default rules for pluralization or singularization
/// you wish to include.
/// - queryStringLiteralFormat: Formatting of the GraphQL query string literal that is
/// included in each generated operation object.
/// - deprecatedEnumCases: How deprecated enum cases from the schema should be handled.
/// - schemaDocumentation: Whether schema documentation is added to the generated files.
/// - selectionSetInitializers: Which generated selection sets should include
Expand All @@ -593,7 +587,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
/// - pruneGeneratedFiles: Whether unused generated files will be automatically deleted.
public init(
additionalInflectionRules: [InflectionRule] = Default.additionalInflectionRules,
queryStringLiteralFormat: QueryStringLiteralFormat = Default.queryStringLiteralFormat,
deprecatedEnumCases: Composition = Default.deprecatedEnumCases,
schemaDocumentation: Composition = Default.schemaDocumentation,
selectionSetInitializers: SelectionSetInitializers = Default.selectionSetInitializers,
Expand All @@ -604,7 +597,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
pruneGeneratedFiles: Bool = Default.pruneGeneratedFiles
) {
self.additionalInflectionRules = additionalInflectionRules
self.queryStringLiteralFormat = queryStringLiteralFormat
self.deprecatedEnumCases = deprecatedEnumCases
self.schemaDocumentation = schemaDocumentation
self.selectionSetInitializers = selectionSetInitializers
Expand All @@ -619,7 +611,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {

enum CodingKeys: CodingKey {
case additionalInflectionRules
case queryStringLiteralFormat
case deprecatedEnumCases
case schemaDocumentation
case selectionSetInitializers
Expand All @@ -639,11 +630,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
forKey: .additionalInflectionRules
) ?? Default.additionalInflectionRules

queryStringLiteralFormat = try values.decodeIfPresent(
QueryStringLiteralFormat.self,
forKey: .queryStringLiteralFormat
) ?? Default.queryStringLiteralFormat

deprecatedEnumCases = try values.decodeIfPresent(
Composition.self,
forKey: .deprecatedEnumCases
Expand Down Expand Up @@ -694,7 +680,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
var container = encoder.container(keyedBy: CodingKeys.self)

try container.encode(self.additionalInflectionRules, forKey: .additionalInflectionRules)
try container.encode(self.queryStringLiteralFormat, forKey: .queryStringLiteralFormat)
try container.encode(self.deprecatedEnumCases, forKey: .deprecatedEnumCases)
try container.encode(self.schemaDocumentation, forKey: .schemaDocumentation)
try container.encode(self.selectionSetInitializers, forKey: .selectionSetInitializers)
Expand All @@ -706,14 +691,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
}
}

/// Specify the formatting of the GraphQL query string literal.
public enum QueryStringLiteralFormat: String, Codable, Equatable {
/// The query string will be copied into the operation object with all line break formatting removed.
case singleLine
/// The query string will be copied with original formatting into the operation object.
case multiline
}

/// Composition is used as a substitute for a boolean where context is better placed in the value
/// instead of the parameter name, e.g.: `includeDeprecatedEnumCases = true` vs.
/// `deprecatedEnumCases = .include`.
Expand Down Expand Up @@ -1331,7 +1308,7 @@ extension ApolloCodegenConfiguration.OutputOptions {
)
public init(
additionalInflectionRules: [InflectionRule] = Default.additionalInflectionRules,
queryStringLiteralFormat: ApolloCodegenConfiguration.QueryStringLiteralFormat = Default.queryStringLiteralFormat,
queryStringLiteralFormat: QueryStringLiteralFormat = .singleLine,
deprecatedEnumCases: ApolloCodegenConfiguration.Composition = Default.deprecatedEnumCases,
schemaDocumentation: ApolloCodegenConfiguration.Composition = Default.schemaDocumentation,
selectionSetInitializers: ApolloCodegenConfiguration.SelectionSetInitializers = Default.selectionSetInitializers,
Expand All @@ -1342,7 +1319,6 @@ extension ApolloCodegenConfiguration.OutputOptions {
pruneGeneratedFiles: Bool = Default.pruneGeneratedFiles
) {
self.additionalInflectionRules = additionalInflectionRules
self.queryStringLiteralFormat = queryStringLiteralFormat
self.deprecatedEnumCases = deprecatedEnumCases
self.schemaDocumentation = schemaDocumentation
self.selectionSetInitializers = selectionSetInitializers
Expand All @@ -1352,6 +1328,52 @@ extension ApolloCodegenConfiguration.OutputOptions {
self.conversionStrategies = conversionStrategies
self.pruneGeneratedFiles = pruneGeneratedFiles
}

/// Deprecated initializer.
///
/// - Parameters:
/// - additionalInflectionRules: Any non-default rules for pluralization or singularization
/// you wish to include.
/// - queryStringLiteralFormat: Formatting of the GraphQL query string literal that is
/// included in each generated operation object.
/// - deprecatedEnumCases: How deprecated enum cases from the schema should be handled.
/// - schemaDocumentation: Whether schema documentation is added to the generated files.
/// - selectionSetInitializers: Which generated selection sets should include
/// generated initializers.
/// - operationDocumentFormat: How to generate the operation documents for your generated operations.
/// - cocoapodsCompatibleImportStatements: Generate import statements that are compatible with
/// including `Apollo` via Cocoapods.
/// - warningsOnDeprecatedUsage: Annotate generated Swift code with the Swift `available`
/// attribute and `deprecated` argument for parts of the GraphQL schema annotated with the
/// built-in `@deprecated` directive.
/// - 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.
@available(*, deprecated,
renamed: "init(additionalInflectionRules:deprecatedEnumCases:schemaDocumentation:selectionSetInitializers:operationDocumentFormat:cocoapodsCompatibleImportStatements:warningsOnDeprecatedUsage:conversionStrategies:pruneGeneratedFiles:)"
)
public init(
additionalInflectionRules: [InflectionRule] = Default.additionalInflectionRules,
queryStringLiteralFormat: QueryStringLiteralFormat,
deprecatedEnumCases: ApolloCodegenConfiguration.Composition = Default.deprecatedEnumCases,
schemaDocumentation: ApolloCodegenConfiguration.Composition = Default.schemaDocumentation,
selectionSetInitializers: ApolloCodegenConfiguration.SelectionSetInitializers = Default.selectionSetInitializers,
operationDocumentFormat: ApolloCodegenConfiguration.OperationDocumentFormat = Default.operationDocumentFormat,
cocoapodsCompatibleImportStatements: Bool = Default.cocoapodsCompatibleImportStatements,
warningsOnDeprecatedUsage: ApolloCodegenConfiguration.Composition = Default.warningsOnDeprecatedUsage,
conversionStrategies: ApolloCodegenConfiguration.ConversionStrategies = Default.conversionStrategies,
pruneGeneratedFiles: Bool = Default.pruneGeneratedFiles
) {
self.additionalInflectionRules = additionalInflectionRules
self.deprecatedEnumCases = deprecatedEnumCases
self.schemaDocumentation = schemaDocumentation
self.selectionSetInitializers = selectionSetInitializers
self.operationDocumentFormat = operationDocumentFormat
self.cocoapodsCompatibleImportStatements = cocoapodsCompatibleImportStatements
self.warningsOnDeprecatedUsage = warningsOnDeprecatedUsage
self.conversionStrategies = conversionStrategies
self.pruneGeneratedFiles = pruneGeneratedFiles
}

/// Whether the generated operations should use Automatic Persisted Queries.
///
Expand All @@ -1369,4 +1391,21 @@ extension ApolloCodegenConfiguration.OutputOptions {
return .disabled
}
}

/// Formatting of the GraphQL query string literal that is included in each
/// generated operation object.
@available(*, deprecated, message: "Query strings are now always in single line format.")
public var queryStringLiteralFormat: QueryStringLiteralFormat {
return .singleLine
}

/// Specify the formatting of the GraphQL query string literal.
public enum QueryStringLiteralFormat: String, Codable, Equatable {
/// The query string will be copied into the operation object with all line break formatting removed.
@available(*, deprecated, message: "Query strings are now always in single line format.")
case singleLine
/// The query string will be copied with original formatting into the operation object.
@available(*, deprecated, message: "Query strings are now always in single line format.")
case multiline
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ struct OperationManifestItem {
self.identifier = operation.operationIdentifier
self.type = operation.definition.operationType

var source = operation.definition.source
var source = operation.definition.source.convertedToSingleLine()
for fragment in operation.referencedFragments {
source += "\n\(fragment.definition.source)"
source += #"\n\#(fragment.definition.source.convertedToSingleLine())"#
}
self.source = source
}
Expand Down Expand Up @@ -57,8 +57,23 @@ struct OperationManifestFileGenerator {
func generate(fileManager: ApolloFileManager = .default) throws {
let rendered: String = try template.render(operations: operationManifest)

var manifestPath = config.output.operationManifest.unsafelyUnwrapped.path
let relativePrefix = "./"

// if path begins with './' the path should be relative to the config.rootURL
if manifestPath.hasPrefix(relativePrefix) {
let fileURL = URL(fileURLWithPath: String(manifestPath.dropFirst(relativePrefix.count)), relativeTo: config.rootURL)
manifestPath = fileURL
.resolvingSymlinksInPath()
.path
}

if !manifestPath.hasSuffix(".json") {
manifestPath.append(".json")
}

try fileManager.createFile(
atPath: config.output.operationManifest.unsafelyUnwrapped.path,
atPath: manifestPath,
data: rendered.data(using: .utf8),
overwrite: true
)
Expand Down
8 changes: 5 additions & 3 deletions Sources/ApolloCodegenLib/IR/IR.swift
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,15 @@ class IR {
hasher.update(bufferPointer: UnsafeRawBufferPointer(buffer))
})
}
updateHash(with: &definition.source)
var definitionSource = definition.source.convertedToSingleLine()
updateHash(with: &definitionSource)

var newline: String
for fragment in referencedFragments {
newline = "\n"
newline = #"\n"#
updateHash(with: &newline)
updateHash(with: &fragment.definition.source)
var fragmentSource = fragment.definition.source.convertedToSingleLine()
updateHash(with: &fragmentSource)
}

let digest = hasher.finalize()
Expand Down
6 changes: 3 additions & 3 deletions Sources/ApolloCodegenLib/Templates/FragmentTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ struct FragmentTemplate: TemplateRenderer {
struct \(fragment.generatedDefinitionName.asFragmentName): \
\(definition.renderedSelectionSetType(config)), Fragment {
\(accessControlModifier(for: .member))\
static var fragmentDefinition: StaticString { ""\"
\(fragment.definition.source)
""\" }
static var fragmentDefinition: StaticString {
"\(fragment.definition.source.convertedToSingleLine())"
}

\(SelectionSetTemplate(
definition: definition,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,22 @@ import Foundation
/// Provides the format to output an operation manifest file used for APQ registration.
struct LegacyAPQOperationManifestTemplate: OperationManifestTemplate {

struct OperationJSONValue: Codable {
let name: String
let source: String
func render(operations: [OperationManifestItem]) -> String {
template(operations).description
}

func render(operations: [OperationManifestItem]) throws -> String {
try template(operations).description
}

private func template(_ operations: [OperationManifestItem]) throws -> TemplateString {
let encoder = JSONEncoder()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you confident we should be removing this json encoding stuff? If I remember correctly, @calvincestari added this because something in the JSON wasn't formatting correctly otherwise, but I can't remember the details.

I guess if the tests are passing we might be alright, but we should check with Calvin.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the JSON encoding was causing issues with us now trying to actually have a \n in our strings before a fragment, so the persisted query manifest would would fine because it manually creates it's JSON but this would fail tests because the encoding was removing our newline characters.

encoder.outputFormatting = .prettyPrinted

private func template(_ operations: [OperationManifestItem]) -> TemplateString {
return TemplateString(
"""
{
\(try operations.map({ operation in
let value = OperationJSONValue(name: operation.name, source: operation.source)
\(forEachIn: operations, { operation in
return """
"\(operation.identifier)" : \(json: try encoder.encode(value))
"\(operation.identifier)" : {
"name": "\(operation.name)",
"source": "\(operation.source)"
}
"""
}), separator: ",\n")
})
}
"""
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ struct OperationDefinitionTemplate: OperationTemplateRenderer {
""")
\(if: includeDefinition, """
definition: .init(
\(operation.source.formatted(for: config.options.queryStringLiteralFormat))\(if: includeFragments, ",")
\(operation.source.formattedSource())\(if: includeFragments, ",")
\(if: includeFragments,
"fragments: [\(fragments.map { "\($0.name.asFragmentName).self" }, separator: ", ")]")
))
Expand All @@ -98,17 +98,7 @@ fileprivate extension CompilationResult.OperationType {
}

fileprivate extension String {
func formatted(for format: ApolloCodegenConfiguration.QueryStringLiteralFormat) -> Self {
switch format {
case .multiline:
return """
#""\"
\(self)
""\"#
"""

case .singleLine:
return "#\"\(convertedToSingleLine())\"#"
}
func formattedSource() -> Self {
return "#\"\(convertedToSingleLine())\"#"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ struct PersistedQueriesOperationManifestTemplate: OperationManifestTemplate {
let config: ApolloCodegen.ConfigurationContext
let encoder = JSONEncoder()

func render(operations: [OperationManifestItem]) throws -> String {
try template(operations).description
func render(operations: [OperationManifestItem]) -> String {
template(operations).description
}

private func template(_ operations: [OperationManifestItem]) throws -> TemplateString {
return try TemplateString(
private func template(_ operations: [OperationManifestItem]) -> TemplateString {
return TemplateString(
"""
{
"format": "apollo-persisted-query-manifest",
"version": 1,
"operations": [
\(forEachIn: operations, terminator: ",", { operation in
\(forEachIn: operations, { operation in
return """
{
"id": "\(operation.identifier)",
"body": \(try operationSource(for: operation)),
"body": "\(operation.source)",
"name": "\(operation.name)",
"type": "\(operation.type.rawValue)"
}
Expand All @@ -33,13 +33,4 @@ struct PersistedQueriesOperationManifestTemplate: OperationManifestTemplate {
)
}

private func operationSource(for operation: OperationManifestItem) throws -> String {
switch config.options.queryStringLiteralFormat {
case .multiline:
return TemplateString("\(json: try encoder.encode(operation.source))").description
case .singleLine:
return "\"\(operation.source.convertedToSingleLine())\""
}
}

}
Loading