Skip to content

Commit 78a1a91

Browse files
committed
Something to just demonstrate
1 parent 57d2b4f commit 78a1a91

File tree

7 files changed

+110
-41
lines changed

7 files changed

+110
-41
lines changed

Sources/ApolloCodegenLib/ApolloCodegen.swift

Lines changed: 85 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class ApolloCodegen {
2222
case invalidSchemaName(_ name: String, message: String)
2323
case targetNameConflict(name: String)
2424
case typeNameConflict(name: String, conflictingName: String, containingObject: String)
25+
case failedToComputeOperationIdentifier(type: String, name: String, error: Swift.Error)
2526

2627
public var errorDescription: String? {
2728
switch self {
@@ -64,6 +65,8 @@ public class ApolloCodegen {
6465
Recommend using a field alias for one of these fields to resolve this conflict. \
6566
For more info see: https://www.apollographql.com/docs/ios/troubleshooting/codegen-troubleshooting#typenameconflict
6667
"""
68+
case let .failedToComputeOperationIdentifier(type, name, error):
69+
return "Received failure while computing operation identifier for \(type) named '\(name)', Error: \(error.localizedDescription)"
6770
}
6871
}
6972
}
@@ -91,6 +94,9 @@ public class ApolloCodegen {
9194

9295
}
9396

97+
/// A `nil` result is treated as a cancellation, and the default operationIdentifier is used
98+
public typealias ComputeOperationIdentifier = (any IROperation, @escaping (Result<String, Swift.Error>?) -> Void) -> Void
99+
94100
/// Executes the code generation engine with a specified configuration.
95101
///
96102
/// - Parameters:
@@ -103,16 +109,18 @@ public class ApolloCodegen {
103109
public static func build(
104110
with configuration: ApolloCodegenConfiguration,
105111
withRootURL rootURL: URL? = nil,
106-
itemsToGenerate: ItemsToGenerate = [.code]
112+
itemsToGenerate: ItemsToGenerate = [.code],
113+
computeOperationIdentifier: ComputeOperationIdentifier? = nil
107114
) throws {
108-
try build(with: configuration, rootURL: rootURL, itemsToGenerate: itemsToGenerate)
115+
try build(with: configuration, rootURL: rootURL, itemsToGenerate: itemsToGenerate, computeOperationIdentifier: computeOperationIdentifier)
109116
}
110117

111118
internal static func build(
112119
with configuration: ApolloCodegenConfiguration,
113120
rootURL: URL? = nil,
114121
fileManager: ApolloFileManager = .default,
115-
itemsToGenerate: ItemsToGenerate
122+
itemsToGenerate: ItemsToGenerate,
123+
computeOperationIdentifier: ComputeOperationIdentifier? = nil
116124
) throws {
117125

118126
let configContext = ConfigurationContext(
@@ -131,29 +139,34 @@ public class ApolloCodegen {
131139

132140
let ir = IR(compilationResult: compilationResult)
133141

134-
var existingGeneratedFilePaths: Set<String>?
135-
136-
if itemsToGenerate.contains(.code) && configuration.options.pruneGeneratedFiles {
137-
existingGeneratedFilePaths = try findExistingGeneratedFilePaths(
142+
let generate: () throws -> Void = {
143+
try generateFiles(
144+
compilationResult: compilationResult,
145+
ir: ir,
138146
config: configContext,
139-
fileManager: fileManager
147+
fileManager: fileManager,
148+
itemsToGenerate: itemsToGenerate,
149+
computeOperationIdentifier: computeOperationIdentifier
140150
)
141151
}
142152

143-
try generateFiles(
144-
compilationResult: compilationResult,
145-
ir: ir,
146-
config: configContext,
147-
fileManager: fileManager,
148-
itemsToGenerate: itemsToGenerate
149-
)
150-
151-
if var existingGeneratedFilePaths {
153+
let generateWithPruning: () throws -> Void = {
154+
var existingGeneratedFilePaths = try findExistingGeneratedFilePaths(
155+
config: configContext,
156+
fileManager: fileManager
157+
)
158+
try generate()
152159
try deleteExtraneousGeneratedFiles(
153160
from: &existingGeneratedFilePaths,
154161
afterCodeGenerationUsing: fileManager
155162
)
156163
}
164+
165+
if itemsToGenerate.contains(.code) && configuration.options.pruneGeneratedFiles {
166+
try generateWithPruning()
167+
} else {
168+
try generate()
169+
}
157170
}
158171

159172
// MARK: Internal
@@ -412,7 +425,8 @@ public class ApolloCodegen {
412425
ir: IR,
413426
config: ConfigurationContext,
414427
fileManager: ApolloFileManager = .default,
415-
itemsToGenerate: ItemsToGenerate
428+
itemsToGenerate: ItemsToGenerate,
429+
computeOperationIdentifier: ComputeOperationIdentifier? = nil
416430
) throws {
417431

418432
if itemsToGenerate.contains(.code) {
@@ -431,9 +445,40 @@ public class ApolloCodegen {
431445
operationIDsFileGenerator = OperationManifestFileGenerator(config: config)
432446
}
433447

434-
for operation in compilationResult.operations {
448+
let irOperations = compilationResult.operations.map { ir.build(operation: $0) }
449+
var results = [Result<String, Swift.Error>?](repeating: nil, count: irOperations.count)
450+
451+
if let computeOperationIdentifier {
452+
let dispatchGroup = DispatchGroup()
453+
DispatchQueue.concurrentPerform(iterations: irOperations.count) { index in
454+
let irOperation = irOperations[index]
455+
var sources: [String] = [irOperation.definition.source.convertedToSingleLine()]
456+
for fragment in irOperation.referencedFragments {
457+
sources.append(fragment.definition.source.convertedToSingleLine())
458+
}
459+
dispatchGroup.enter()
460+
computeOperationIdentifier(irOperation) { result in
461+
results[index] = result
462+
dispatchGroup.leave()
463+
}
464+
}
465+
dispatchGroup.wait()
466+
}
467+
468+
for (index, irOperation) in irOperations.enumerated() {
435469
try autoreleasepool {
436-
let irOperation = ir.build(operation: operation)
470+
if let result = results[index] {
471+
switch result {
472+
case .success(let operationIdentifier):
473+
irOperation.operationIdentifier = operationIdentifier
474+
case .failure(let error):
475+
throw Error.failedToComputeOperationIdentifier(
476+
type: irOperation.definition.operationType.rawValue,
477+
name: irOperation.definition.name,
478+
error: error
479+
)
480+
}
481+
}
437482

438483
if itemsToGenerate.contains(.code) {
439484
try validateTypeConflicts(for: irOperation.rootField.selectionSet, with: config, in: irOperation.definition.name)
@@ -611,4 +656,24 @@ public class ApolloCodegen {
611656

612657
}
613658

659+
public protocol IROperation: AnyObject {
660+
var filePath: String { get }
661+
var name: String { get }
662+
var source: String { get }
663+
var type: CompilationResult.OperationType { get }
664+
}
665+
666+
extension IR.Operation: IROperation {
667+
public var filePath: String { definition.filePath }
668+
public var name: String { definition.name }
669+
public var source: String {
670+
var sources: [String] = [definition.source.convertedToSingleLine()]
671+
for fragment in referencedFragments {
672+
sources.append(fragment.definition.source.convertedToSingleLine())
673+
}
674+
return sources.joined(separator: "\n")
675+
}
676+
public var type: CompilationResult.OperationType { definition.operationType }
677+
}
678+
614679
#endif

Sources/ApolloCodegenLib/Frontend/CompilationResult.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import JavaScriptCore
22

33
/// The output of the frontend compiler.
4-
public class CompilationResult: JavaScriptObject {
4+
public final class CompilationResult: JavaScriptObject {
55
private enum Constants {
66
static let LocalCacheMutationDirectiveName = "apollo_client_ios_localCacheMutation"
77
}
@@ -15,15 +15,15 @@ public class CompilationResult: JavaScriptObject {
1515

1616
lazy var schemaDocumentation: String? = self["schemaDocumentation"]
1717

18-
public class RootTypeDefinition: JavaScriptObject {
18+
public final class RootTypeDefinition: JavaScriptObject {
1919
lazy var queryType: GraphQLNamedType = self["queryType"]
2020

2121
lazy var mutationType: GraphQLNamedType? = self["mutationType"]
2222

2323
lazy var subscriptionType: GraphQLNamedType? = self["subscriptionType"]
2424
}
2525

26-
public class OperationDefinition: JavaScriptObject, Hashable {
26+
public final class OperationDefinition: JavaScriptObject, Hashable {
2727
lazy var name: String = self["name"]
2828

2929
lazy var operationType: OperationType = self["operationType"]
@@ -94,15 +94,15 @@ public class CompilationResult: JavaScriptObject {
9494
}
9595
}
9696

97-
public class VariableDefinition: JavaScriptObject {
97+
public final class VariableDefinition: JavaScriptObject {
9898
lazy var name: String = self["name"]
9999

100100
lazy var type: GraphQLType = self["type"]
101101

102102
lazy var defaultValue: GraphQLValue? = self["defaultValue"]
103103
}
104104

105-
public class FragmentDefinition: JavaScriptObject, Hashable {
105+
public final class FragmentDefinition: JavaScriptObject, Hashable {
106106
lazy var name: String = self["name"]
107107

108108
lazy var type: GraphQLCompositeType = self["typeCondition"]
@@ -132,7 +132,7 @@ public class CompilationResult: JavaScriptObject {
132132
}
133133
}
134134

135-
public class SelectionSet: JavaScriptWrapper, Hashable, CustomDebugStringConvertible {
135+
public final class SelectionSet: JavaScriptWrapper, Hashable, CustomDebugStringConvertible {
136136
lazy var parentType: GraphQLCompositeType = self["parentType"]
137137

138138
lazy var selections: [Selection] = self["selections"]
@@ -165,7 +165,7 @@ public class CompilationResult: JavaScriptObject {
165165
}
166166
}
167167

168-
public class InlineFragment: JavaScriptObject, Hashable {
168+
public final class InlineFragment: JavaScriptObject, Hashable {
169169
lazy var selectionSet: SelectionSet = self["selectionSet"]
170170

171171
lazy var inclusionConditions: [InclusionCondition]? = self["inclusionConditions"]
@@ -187,7 +187,7 @@ public class CompilationResult: JavaScriptObject {
187187

188188
/// Represents an individual selection that includes a named fragment in a selection set.
189189
/// (ie. `...FragmentName`)
190-
public class FragmentSpread: JavaScriptObject, Hashable {
190+
public final class FragmentSpread: JavaScriptObject, Hashable {
191191
lazy var fragment: FragmentDefinition = self["fragment"]
192192

193193
lazy var inclusionConditions: [InclusionCondition]? = self["inclusionConditions"]
@@ -253,7 +253,7 @@ public class CompilationResult: JavaScriptObject {
253253
}
254254
}
255255

256-
public class Field: JavaScriptWrapper, Hashable, CustomDebugStringConvertible {
256+
public final class Field: JavaScriptWrapper, Hashable, CustomDebugStringConvertible {
257257
lazy var name: String = self["name"]!
258258

259259
lazy var alias: String? = self["alias"]
@@ -330,7 +330,7 @@ public class CompilationResult: JavaScriptObject {
330330
}
331331
}
332332

333-
public class Argument: JavaScriptObject, Hashable {
333+
public final class Argument: JavaScriptObject, Hashable {
334334
lazy var name: String = self["name"]
335335

336336
lazy var type: GraphQLType = self["type"]
@@ -352,7 +352,7 @@ public class CompilationResult: JavaScriptObject {
352352
}
353353
}
354354

355-
public class Directive: JavaScriptObject, Hashable {
355+
public final class Directive: JavaScriptObject, Hashable {
356356
lazy var name: String = self["name"]
357357

358358
lazy var arguments: [Argument]? = self["arguments"]

Sources/ApolloCodegenLib/IR/IR.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import OrderedCollections
22
import CryptoKit
33

4-
class IR {
4+
final class IR {
55

66
let compilationResult: CompilationResult
77

@@ -85,7 +85,7 @@ class IR {
8585
///
8686
/// Multiple `SelectionSet`s may select fields on the same `Entity`. All `SelectionSet`s that will
8787
/// be selected on the same object share the same `Entity`.
88-
class Entity {
88+
final class Entity {
8989

9090
/// Represents the location within a GraphQL definition (operation or fragment) of an `Entity`.
9191
struct Location: Hashable {
@@ -170,7 +170,7 @@ class IR {
170170
}
171171
}
172172

173-
class Operation {
173+
final class Operation {
174174
let definition: CompilationResult.OperationDefinition
175175

176176
/// The root field of the operation. This field must be the root query, mutation, or
@@ -218,7 +218,7 @@ class IR {
218218
}
219219
}
220220

221-
class NamedFragment: Hashable, CustomDebugStringConvertible {
221+
final class NamedFragment: Hashable, CustomDebugStringConvertible {
222222
let definition: CompilationResult.FragmentDefinition
223223
let rootField: EntityField
224224

@@ -264,7 +264,7 @@ class IR {
264264

265265
/// Represents an Inline Fragment that has been "spread into" another SelectionSet using the
266266
/// spread operator (`...`).
267-
class InlineFragmentSpread: Hashable, CustomDebugStringConvertible {
267+
final class InlineFragmentSpread: Hashable, CustomDebugStringConvertible {
268268
/// The `SelectionSet` representing the inline fragment that has been "spread into" its
269269
/// enclosing operation/fragment.
270270
let selectionSet: SelectionSet
@@ -310,7 +310,7 @@ class IR {
310310
///
311311
/// While a `NamedFragment` can be shared between operations, a `NamedFragmentSpread` represents a
312312
/// `NamedFragment` included in a specific operation.
313-
class NamedFragmentSpread: Hashable, CustomDebugStringConvertible {
313+
final class NamedFragmentSpread: Hashable, CustomDebugStringConvertible {
314314

315315
/// The `NamedFragment` that this fragment refers to.
316316
///

Sources/CodegenCLI/Commands/Generate.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ public struct Generate: ParsableCommand {
7777
try codegenProvider.build(
7878
with: configuration,
7979
withRootURL: rootOutputURL(for: inputs),
80-
itemsToGenerate: itemsToGenerate
80+
itemsToGenerate: itemsToGenerate,
81+
computeOperationIdentifier: nil
8182
)
8283
}
8384

Sources/CodegenCLI/Commands/GenerateOperationManifest.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ public struct GenerateOperationManifest: ParsableCommand {
4444
try codegenProvider.build(
4545
with: configuration,
4646
withRootURL: rootOutputURL(for: inputs),
47-
itemsToGenerate: [.operationManifest]
47+
itemsToGenerate: [.operationManifest],
48+
computeOperationIdentifier: nil
4849
)
4950
}
5051

Sources/CodegenCLI/Protocols/CodegenProvider.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ public protocol CodegenProvider {
66
static func build(
77
with configuration: ApolloCodegenConfiguration,
88
withRootURL rootURL: URL?,
9-
itemsToGenerate: ApolloCodegen.ItemsToGenerate
9+
itemsToGenerate: ApolloCodegen.ItemsToGenerate,
10+
computeOperationIdentifier: ApolloCodegen.ComputeOperationIdentifier?
1011
) throws
1112
}
1213

Tests/CodegenCLITests/Support/MockApolloCodegen.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ class MockApolloCodegen: CodegenProvider {
88
static func build(
99
with configuration: ApolloCodegenConfiguration,
1010
withRootURL rootURL: URL?,
11-
itemsToGenerate: ApolloCodegen.ItemsToGenerate
11+
itemsToGenerate: ApolloCodegen.ItemsToGenerate,
12+
computeOperationIdentifier: ApolloCodegen.ComputeOperationIdentifier? = nil
1213
) throws {
1314
guard let handler = buildHandler else {
1415
fatalError("You must set buildHandler before calling \(#function)!")

0 commit comments

Comments
 (0)