Skip to content

Commit

Permalink
fix: Schema/Target/Module name with spaces breaks generated code (#2760)
Browse files Browse the repository at this point in the history
  • Loading branch information
calvincestari authored Jan 9, 2023
1 parent 923d4cc commit daf1250
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 93 deletions.
2 changes: 1 addition & 1 deletion Plugins/InstallCLI/InstallCLIPluginCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ struct InstallCLIPluginCommand: CommandPlugin {
let task = Process()
task.standardInput = nil
task.environment = ProcessInfo.processInfo.environment
task.arguments = ["-c", "ln -f -s \(from.string) \(to.string)"]
task.arguments = ["-c", "ln -f -s '\(from.string)' '\(to.string)'"]
task.executableURL = URL(fileURLWithPath: "/bin/zsh")
try task.run()
task.waitUntilExit()
Expand Down
58 changes: 43 additions & 15 deletions Sources/ApolloCodegenLib/ApolloCodegen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class ApolloCodegen {
case cannotLoadSchema
case cannotLoadOperations
case invalidConfiguration(message: String)
case invalidSchemaName(_ name: String, message: String)

public var errorDescription: String? {
switch self {
Expand Down Expand Up @@ -47,6 +48,8 @@ public class ApolloCodegen {
return "No GraphQL operations could be found. Please verify the operation search paths."
case let .invalidConfiguration(message):
return "The codegen configuration has conflicting values: \(message)"
case let .invalidSchemaName(name, message):
return "The schema name `\(name)` is invalid: \(message)"
}
}
}
Expand Down Expand Up @@ -76,14 +79,14 @@ public class ApolloCodegen {
rootURL: rootURL
)

try validate(config: configContext)
try validate(configContext)

let compilationResult = try compileGraphQLResult(
configContext,
experimentalFeatures: configuration.experimentalFeatures
)

try validate(schemaName: configContext.schemaName, compilationResult: compilationResult)
try validate(configContext, with: compilationResult)

let ir = IR(compilationResult: compilationResult)

Expand Down Expand Up @@ -130,26 +133,50 @@ public class ApolloCodegen {
}
}

/// Performs validation against deterministic errors that will cause code generation to fail.
static func validate(config: ConfigurationContext) throws {
if case .swiftPackage = config.output.testMocks,
config.output.schemaTypes.moduleType != .swiftPackageManager {
/// Validates the configuration against deterministic errors that will cause code generation to
/// fail. This validation step does not take into account schema and operation specific types, it
/// is only a static analysis of the configuration.
///
/// - Parameter config: Code generation configuration settings.
public static func _validate(config: ApolloCodegenConfiguration) throws {
try validate(ConfigurationContext(config: config))
}

static private func validate(_ context: ConfigurationContext) throws {
guard
!context.schemaName.isEmpty,
!context.schemaName.contains(where: { $0.isWhitespace })
else {
throw Error.invalidSchemaName(context.schemaName, message: """
Cannot be empty nor contain spaces. If your schema name has spaces consider replacing them \
with the underscore character.
""")
}

guard
!SwiftKeywords.DisallowedSchemaNamespaceNames.contains(context.schemaName.lowercased())
else {
throw Error.schemaNameConflict(name: context.schemaName)
}

if case .swiftPackage = context.output.testMocks,
context.output.schemaTypes.moduleType != .swiftPackageManager {
throw Error.testMocksInvalidSwiftPackageConfiguration
}

if case .swiftPackageManager = config.output.schemaTypes.moduleType,
config.options.cocoapodsCompatibleImportStatements == true {
if case .swiftPackageManager = context.output.schemaTypes.moduleType,
context.options.cocoapodsCompatibleImportStatements == true {
throw Error.invalidConfiguration(message: """
cocoapodsCompatibleImportStatements cannot be set to 'true' when the output schema types \
module type is Swift Package Manager. Change the cocoapodsCompatibleImportStatements \
value to 'false', or choose a different module type, to resolve the conflict.
""")
}

for searchPath in config.input.schemaSearchPaths {
for searchPath in context.input.schemaSearchPaths {
try validate(inputSearchPath: searchPath)
}
for searchPath in config.input.operationSearchPaths {
for searchPath in context.input.operationSearchPaths {
try validate(inputSearchPath: searchPath)
}
}
Expand All @@ -160,17 +187,18 @@ public class ApolloCodegen {
}
}

static func validate(schemaName: String, compilationResult: CompilationResult) throws {
/// Validates the configuration context against the GraphQL compilation result, checking for
/// configuration errors that are dependent on the schema and operations.
static func validate(_ context: ConfigurationContext, with compilationResult: CompilationResult) throws {
guard
!SwiftKeywords.DisallowedSchemaNamespaceNames.contains(schemaName.lowercased()),
!compilationResult.referencedTypes.contains(where: { namedType in
namedType.swiftName == schemaName.firstUppercased
namedType.swiftName == context.schemaName.firstUppercased
}),
!compilationResult.fragments.contains(where: { fragmentDefinition in
fragmentDefinition.name == schemaName.firstUppercased
fragmentDefinition.name == context.schemaName.firstUppercased
})
else {
throw Error.schemaNameConflict(name: schemaName)
throw Error.schemaNameConflict(name: context.schemaName)
}
}

Expand Down
14 changes: 5 additions & 9 deletions Sources/CodegenCLI/Commands/Initialize.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,6 @@ public struct Initialize: ParsableCommand {
public init() { }

public func validate() throws {
guard !schemaName.trimmingCharacters(in: .whitespaces).isEmpty else {
throw ValidationError("--schema-name value cannot be empty.")
}

switch (moduleType, targetName?.isEmpty) {
case (.embeddedInTarget, nil), (.embeddedInTarget, true):
throw ValidationError("""
Expand All @@ -86,11 +82,11 @@ public struct Initialize: ParsableCommand {

func _run(fileManager: ApolloFileManager = .default, output: OutputClosure? = nil) throws {
let encoded = try ApolloCodegenConfiguration
.minimalJSON(
schemaName: schemaName,
moduleType: moduleType,
targetName: targetName
).asData()
.minimalJSON(schemaName: schemaName, moduleType: moduleType, targetName: targetName)
.asData()

let decoded = try JSONDecoder().decode(ApolloCodegenConfiguration.self, from: encoded)
try ApolloCodegen._validate(config: decoded)

if print {
try print(data: encoded, output: output)
Expand Down
Loading

0 comments on commit daf1250

Please sign in to comment.