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 warning in generated server code #209

Merged
merged 5 commits into from
Aug 17, 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
Original file line number Diff line number Diff line change
Expand Up @@ -39,31 +39,86 @@ struct ServerFileTranslator: FileTranslator {
+ config.additionalImports
.map { ImportDescription(moduleName: $0) }

let serverMethodDeclPairs =
let allOperations =
try OperationDescription
.all(
from: doc.paths,
in: components,
asSwiftSafeName: swiftSafeName
)

let (registerHandlersDecl, serverMethodDecls) = try translateRegisterHandlers(allOperations)

let protocolExtensionDecl: Declaration = .extension(
accessModifier: nil,
onType: Constants.APIProtocol.typeName,
declarations: [
registerHandlersDecl
]
)

let serverExtensionDecl: Declaration = .extension(
accessModifier: .fileprivate,
onType: Constants.Server.Universal.typeName,
whereClause: .init(requirements: [
.conformance(
Constants.Server.Universal.apiHandlerName,
Constants.APIProtocol.typeName
)
]),
declarations: serverMethodDecls
)

return StructuredSwiftRepresentation(
file: .init(
name: GeneratorMode.server.outputFileName,
contents: .init(
topComment: topComment,
imports: imports,
codeBlocks: [
.declaration(protocolExtensionDecl),
.declaration(serverExtensionDecl),
]
)
)
)
}

/// Returns a declaration of the registerHandlers method and
/// the declarations of the individual operation methods.
/// - Parameter operations: The operations found in the OpenAPI document.
func translateRegisterHandlers(
_ operations: [OperationDescription]
) throws -> (Declaration, [Declaration]) {
var registerHandlersDeclBody: [CodeBlock] = []
let serverMethodDeclPairs =
try operations
.map { operation in
try translateServerMethod(operation, serverUrlVariableName: "server")
}
let serverMethodDecls = serverMethodDeclPairs.map(\.functionDecl)

let serverMethodRegisterCalls = serverMethodDeclPairs.map(\.registerCall)
// To avoid an unused variable warning, we add the server variable declaration
// and server method register calls to the body of the register handler declaration
// only when there is at least one registration call.
if !serverMethodDeclPairs.isEmpty {
let serverMethodRegisterCalls = serverMethodDeclPairs.map(\.registerCall)
let registerHandlerServerVarDecl: Declaration = .variable(
kind: .let,
left: "server",
right: .identifier(Constants.Server.Universal.typeName)
.call([
.init(label: "serverURL", expression: .identifier("serverURL")),
.init(label: "handler", expression: .identifier("self")),
.init(label: "configuration", expression: .identifier("configuration")),
.init(label: "middlewares", expression: .identifier("middlewares")),
])
)

registerHandlersDeclBody.append(.declaration(registerHandlerServerVarDecl))
registerHandlersDeclBody.append(contentsOf: serverMethodRegisterCalls.map { .expression($0) })
}

let registerHandlerServerVarDecl: Declaration = .variable(
kind: .let,
left: "server",
right: .identifier(Constants.Server.Universal.typeName)
.call([
.init(label: "serverURL", expression: .identifier("serverURL")),
.init(label: "handler", expression: .identifier("self")),
.init(label: "configuration", expression: .identifier("configuration")),
.init(label: "middlewares", expression: .identifier("middlewares")),
])
)
let registerHandlersDecl: Declaration = .commentable(
.doc(
#"""
Expand Down Expand Up @@ -104,44 +159,9 @@ struct ServerFileTranslator: FileTranslator {
keywords: [
.throws
],
body: [
.declaration(registerHandlerServerVarDecl)
] + serverMethodRegisterCalls.map { .expression($0) }
)
)

let protocolExtensionDecl: Declaration = .extension(
accessModifier: nil,
onType: Constants.APIProtocol.typeName,
declarations: [
registerHandlersDecl
]
)

let serverExtensionDecl: Declaration = .extension(
accessModifier: .fileprivate,
onType: Constants.Server.Universal.typeName,
whereClause: .init(requirements: [
.conformance(
Constants.Server.Universal.apiHandlerName,
Constants.APIProtocol.typeName
)
]),
declarations: serverMethodDecls
)

return StructuredSwiftRepresentation(
file: .init(
name: GeneratorMode.server.outputFileName,
contents: .init(
topComment: topComment,
imports: imports,
codeBlocks: [
.declaration(protocolExtensionDecl),
.declaration(serverExtensionDecl),
]
)
body: registerHandlersDeclBody
)
)
return (registerHandlersDecl, serverMethodDecls)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,61 @@ final class SnippetBasedReferenceTests: XCTestCase {
)
}

func testServerRegisterHandlers_oneOperation() throws {
try self.assertServerRegisterHandlers(
"""
/health:
get:
operationId: getHealth
responses:
'200':
description: A success response with a greeting.
content:
text/plain:
schema:
type: string
""",
"""
public func registerHandlers(
on transport: any ServerTransport,
serverURL: URL = .defaultOpenAPIServerURL,
configuration: Configuration = .init(),
middlewares: [any ServerMiddleware] = []
) throws {
let server = UniversalServer(
serverURL: serverURL,
handler: self,
configuration: configuration,
middlewares: middlewares
)
try transport.register(
{ try await server.getHealth(request: $0, metadata: $1) },
method: .get,
path: server.apiPathComponentsWithServerPrefix(["health"]),
queryItemNames: []
)
}
"""
)
}

func testServerRegisterHandlers_noOperation() throws {
try self.assertServerRegisterHandlers(
"""
{}
""",
"""
public func registerHandlers(
on transport: any ServerTransport,
serverURL: URL = .defaultOpenAPIServerURL,
configuration: Configuration = .init(),
middlewares: [any ServerMiddleware] = []
) throws {
}
"""
)
}

func testPathWithPathItemReference() throws {
XCTAssertThrowsError(
try self.assertPathsTranslation(
Expand Down Expand Up @@ -1595,6 +1650,23 @@ extension SnippetBasedReferenceTests {
let translation = try translator.translateAPIProtocol(paths)
try XCTAssertSwiftEquivalent(translation, expectedSwift, file: file, line: line)
}

func assertServerRegisterHandlers(
_ pathsYAML: String,
_ expectedSwift: String,
file: StaticString = #filePath,
line: UInt = #line
) throws {
let (_, _, translator) = try makeTranslators()
let paths = try YAMLDecoder().decode(OpenAPI.PathItem.Map.self, from: pathsYAML)
let operations = try OperationDescription.all(
from: paths,
in: .noComponents,
asSwiftSafeName: translator.swiftSafeName
)
let (registerHandlersDecl, _) = try translator.translateRegisterHandlers(operations)
try XCTAssertSwiftEquivalent(registerHandlersDecl, expectedSwift, file: file, line: line)
}
}

private func XCTAssertEqualWithDiff(
Expand Down