-
Notifications
You must be signed in to change notification settings - Fork 149
Generate enums for server variables #618
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
Merged
czechboy0
merged 17 commits into
apple:main
from
theoriginalbit:refactor/generate-server-variable-enums
Oct 11, 2024
Merged
Changes from 8 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
a84d1e7
Generate enums for server variables
theoriginalbit 1e73c29
Generated enums for server variables are now feature flagged
theoriginalbit 78ed2de
Update Sources/_OpenAPIGeneratorCore/FeatureFlags.swift
theoriginalbit d866ab6
Revert addition of file-based reference test
theoriginalbit ad29a41
Introduce snippet-based reference tests for server variable translation
theoriginalbit 924362c
Adopt approach that does not require feature flags
theoriginalbit 8d56c51
Merge remote-tracking branch 'upstream/main' into refactor/generate-s…
theoriginalbit 4d30ace
Address review feedback
theoriginalbit ef855f6
Merge branch 'main' into refactor/generate-server-variable-enums
czechboy0 d875fe4
Add missing comments to the new implementations
theoriginalbit 7156e50
Generate the server variable enums as Sendable
theoriginalbit c62d6bd
Update tutorials and tests to reference new type-safe variables API
theoriginalbit 4d8a719
Remove no longer required test
theoriginalbit b559ea1
Resolve code that was failing format check workflow
theoriginalbit ca06171
Merge branch 'main' into refactor/generate-server-variable-enums
theoriginalbit ecd0000
Run linter and fix Swift 5.9 compile issue
theoriginalbit f7fcfe2
Merge branch 'main' into refactor/generate-server-variable-enums
czechboy0 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
214 changes: 214 additions & 0 deletions
214
Sources/_OpenAPIGeneratorCore/Translator/TypesTranslator/translateServersVariables.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,214 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This source file is part of the SwiftOpenAPIGenerator open source project | ||
| // | ||
| // Copyright (c) 2023 Apple Inc. and the SwiftOpenAPIGenerator project authors | ||
| // Licensed under Apache License v2.0 | ||
| // | ||
| // See LICENSE.txt for license information | ||
| // See CONTRIBUTORS.txt for the list of SwiftOpenAPIGenerator project authors | ||
| // | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| import OpenAPIKit | ||
|
|
||
| extension TypesFileTranslator { | ||
| /// Returns a declaration of a namespace (enum) for a specific server and will define | ||
| /// one enum member for each of the server's variables in the OpenAPI Document. | ||
| /// If the server does not define variables, no declaration will be generated. | ||
| /// - Parameters: | ||
| /// - index: The index of the server in the list of servers defined | ||
| /// in the OpenAPI document. | ||
| /// - server: The server variables information. | ||
| /// - Returns: A declaration of the server variables namespace, or `nil` if no | ||
| /// variables are declared. | ||
| func translateServerVariables(index: Int, server: OpenAPI.Server, generateAsEnum: Bool) -> [any ServerVariableGenerator] { | ||
| return server.variables.map { (key, variable) in | ||
| guard generateAsEnum, let enumValues = variable.enum else { | ||
| return RawStringTranslatedServerVariable( | ||
| key: key, | ||
| variable: variable, | ||
| context: context | ||
| ) | ||
| } | ||
|
|
||
| return GeneratedEnumTranslatedServerVariable( | ||
| key: key, | ||
| variable: variable, | ||
| enumValues: enumValues, | ||
| accessModifier: config.access, | ||
| context: context | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| // MARK: Generators | ||
|
|
||
| /// Represents a server variable and the function of generation that should be applied. | ||
| protocol ServerVariableGenerator { | ||
| /// Returns the declaration (enum) that should be added to the `Variables.Server#` | ||
theoriginalbit marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// namespace. If the server variable does not require any codegen then it should | ||
| /// return `nil`. | ||
| var declaration: Declaration? { get } | ||
|
|
||
| /// Returns the description of the parameter that will be used to define the variable | ||
| /// in the static method for a given server. | ||
| var parameter: ParameterDescription { get } | ||
|
|
||
| /// Returns an expression for the variable initializer that is used in the body of a server's | ||
| /// static method by passing it along to the URL resolver. | ||
| var initializer: Expression { get } | ||
|
|
||
| /// Returns the description of this variables documentation for the function comment of | ||
| /// the server's static method. | ||
| var functionComment: (name: String, comment: String?) { get } | ||
| } | ||
|
|
||
| /// Represents a variable that is required to be represented as a `Swift.String`. | ||
| private struct RawStringTranslatedServerVariable: ServerVariableGenerator { | ||
| let key: String | ||
| let swiftSafeKey: String | ||
| let variable: OpenAPI.Server.Variable | ||
theoriginalbit marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| init(key: String, variable: OpenAPI.Server.Variable, context: TranslatorContext) { | ||
theoriginalbit marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| self.key = key | ||
| swiftSafeKey = context.asSwiftSafeName(key) | ||
| self.variable = variable | ||
| } | ||
|
|
||
| /// A variable being represented by a `Swift.String` does not have a declaration that needs to | ||
| /// be added to the `Variables.Server#` namespace. | ||
| var declaration: Declaration? { nil } | ||
|
|
||
| /// Returns the description of the parameter that will be used to define the variable | ||
| /// in the static method for a given server. | ||
| var parameter: ParameterDescription { | ||
| return .init( | ||
| label: swiftSafeKey, | ||
| type: .init(TypeName.string), | ||
| defaultValue: .literal(variable.default) | ||
| ) | ||
| } | ||
|
|
||
| /// Returns an expression for the variable initializer that is used in the body of a server's | ||
| /// static method by passing it along to the URL resolver. | ||
| var initializer: Expression { | ||
| var arguments: [FunctionArgumentDescription] = [ | ||
| .init(label: "name", expression: .literal(key)), | ||
| .init(label: "value", expression: .identifierPattern(swiftSafeKey)), | ||
| ] | ||
| if let allowedValues = variable.enum { | ||
| arguments.append(.init( | ||
| label: "allowedValues", | ||
| expression: .literal(.array(allowedValues.map { .literal($0) })) | ||
| )) | ||
| } | ||
| return .dot("init").call(arguments) | ||
| } | ||
|
|
||
| /// Returns the description of this variables documentation for the function comment of | ||
| /// the server's static method. | ||
| var functionComment: (name: String, comment: String?) { | ||
| (name: swiftSafeKey, comment: variable.description) | ||
| } | ||
| } | ||
|
|
||
| /// Represents a variable that will be generated as an enum and added to the `Variables.Server#` | ||
| /// namespace. The enum will contain a `default` static case which returns the default defined in | ||
| /// the OpenAPI Document. | ||
| private struct GeneratedEnumTranslatedServerVariable: ServerVariableGenerator { | ||
| let key: String | ||
| let swiftSafeKey: String | ||
| let enumName: String | ||
| let variable: OpenAPI.Server.Variable | ||
| let enumValues: [String] | ||
|
|
||
| let accessModifier: AccessModifier | ||
| let context: TranslatorContext | ||
|
|
||
| init(key: String, variable: OpenAPI.Server.Variable, enumValues: [String], accessModifier: AccessModifier, context: TranslatorContext) { | ||
| self.key = key | ||
| swiftSafeKey = context.asSwiftSafeName(key) | ||
| enumName = context.asSwiftSafeName(key.localizedCapitalized) | ||
| self.variable = variable | ||
| self.enumValues = enumValues | ||
|
|
||
| self.context = context | ||
| self.accessModifier = accessModifier | ||
| } | ||
|
|
||
| /// Returns the declaration (enum) that should be added to the `Variables.Server#` | ||
| /// namespace. | ||
| var declaration: Declaration? { | ||
| let description: String = if let description = variable.description { | ||
| description + "\n\n" | ||
| } else { | ||
| "" | ||
| } | ||
|
|
||
| return .commentable( | ||
| .doc(""" | ||
| \(description)The "\(key)" variable defined in the OpenAPI document. The default value is "\(variable.default)". | ||
| """), | ||
| .enum( | ||
| isFrozen: true, | ||
| accessModifier: accessModifier, | ||
| name: enumName, | ||
| conformances: [ | ||
| TypeName.string.fullyQualifiedSwiftName, | ||
| ], | ||
| members: enumValues.map(translateVariableCase) | ||
| ) | ||
| ) | ||
| } | ||
|
|
||
| /// Returns the description of the parameter that will be used to define the variable | ||
| /// in the static method for a given server. | ||
| var parameter: ParameterDescription { | ||
| return .init( | ||
| label: swiftSafeKey, | ||
| type: .member([enumName]), | ||
| defaultValue: .memberAccess(.dot(context.asSwiftSafeName(variable.default))) | ||
| ) | ||
| } | ||
|
|
||
| /// Returns an expression for the variable initializer that is used in the body of a server's | ||
| /// static method by passing it along to the URL resolver. | ||
| var initializer: Expression { | ||
| .dot("init").call( | ||
| [ | ||
| .init(label: "name", expression: .literal(key)), | ||
| .init(label: "value", expression: .memberAccess(.init( | ||
| left: .identifierPattern(swiftSafeKey), | ||
| right: "rawValue" | ||
| ))), | ||
| ] | ||
| ) | ||
| } | ||
|
|
||
| /// Returns the description of this variables documentation for the function comment of | ||
| /// the server's static method. | ||
| var functionComment: (name: String, comment: String?) { | ||
| (name: swiftSafeKey, comment: variable.description) | ||
| } | ||
|
|
||
| /// Returns an enum case declaration for a raw string enum. | ||
| /// | ||
| /// If the name does not need to be converted to a Swift safe identifier then the | ||
| /// enum case will not define a raw value and rely on the implicit generation from | ||
| /// Swift. Otherwise the enum case name will be the Swift safe name and a string | ||
| /// raw value will be set to the original name. | ||
| /// | ||
| /// - Parameter name: The original name. | ||
| /// - Returns: A declaration of an enum case. | ||
| private func translateVariableCase(_ name: String) -> Declaration { | ||
| let caseName = context.asSwiftSafeName(name) | ||
| if caseName == name { | ||
| return .enumCase(name: caseName, kind: .nameOnly) | ||
| } else { | ||
| return .enumCase(name: caseName, kind: .nameWithRawValue(.string(name))) | ||
| } | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.