- 
                Notifications
    You must be signed in to change notification settings 
- Fork 148
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 6 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
    
  
  
    
              
        
          
          
            218 changes: 218 additions & 0 deletions
          
          218 
        
  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,218 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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, | ||
| asSwiftSafeName: swiftSafeName(for:) | ||
| ) | ||
| } | ||
|  | ||
| return GeneratedEnumTranslatedServerVariable( | ||
| key: key, | ||
| variable: variable, | ||
| enumValues: enumValues, | ||
| accessModifier: config.access, | ||
| asSwiftSafeName: swiftSafeName(for:) | ||
| ) | ||
| } | ||
| } | ||
|  | ||
| // 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, asSwiftSafeName: @escaping (String) -> String) { | ||
| self.key = key | ||
| swiftSafeKey = 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 asSwiftSafeName: (String) -> String | ||
|  | ||
| init(key: String, variable: OpenAPI.Server.Variable, enumValues: [String], accessModifier: AccessModifier, asSwiftSafeName: @escaping (String) -> String) { | ||
| self.key = key | ||
| swiftSafeKey = asSwiftSafeName(key) | ||
| enumName = asSwiftSafeName(key.localizedCapitalized) | ||
| self.variable = variable | ||
| self.enumValues = enumValues | ||
|  | ||
| self.asSwiftSafeName = asSwiftSafeName | ||
| 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 { | ||
| let safeDefault = asSwiftSafeName(variable.default) | ||
| let memberPath: [String] = [ | ||
| enumName | ||
| ] | ||
| return .init( | ||
| label: swiftSafeKey, | ||
| type: .member(memberPath), | ||
| defaultValue: .identifierType(.member(memberPath + CollectionOfOne(safeDefault))) | ||
| ) | ||
| } | ||
|  | ||
| /// 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 = 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.