Skip to content

Commit

Permalink
Merge pull request #64 from amzn/custom_target_names_v2
Browse files Browse the repository at this point in the history
Support custom target names V2
  • Loading branch information
tachyonics authored Sep 28, 2022
2 parents cf4aa31 + 56a8581 commit a1adc01
Show file tree
Hide file tree
Showing 27 changed files with 457 additions and 221 deletions.
18 changes: 2 additions & 16 deletions .github/workflows/swift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,12 @@ jobs:
strategy:
matrix:
os: [ubuntu-20.04]
swift: ["5.6", "5.5.3"]
swift: ["5.7", "5.6.3", "5.5.3"]
runs-on: ${{ matrix.os }}
steps:
- uses: fwal/setup-swift@v1.14.0
- uses: swift-actions/setup-swift@v1.18.0
with:
swift-version: ${{ matrix.swift }}
- uses: actions/checkout@v2
- name: Build
run: swift build -c release
BuildOpenAPIWorkaround:
name: Swift ${{ matrix.swift }} on ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04]
swift: ["5.4.3"]
runs-on: ${{ matrix.os }}
steps:
- uses: fwal/setup-swift@v1.14.0
with:
swift-version: ${{ matrix.swift }}
- uses: actions/checkout@v2
- name: Build
run: swift build -Xswiftc -Xfrontend -Xswiftc -sil-verify-none -c release
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:5.4
// swift-tools-version:5.5
//
// Copyright 2019-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
Expand Down
126 changes: 111 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<img src="https://github.com/amzn/service-model-swift-code-generate/actions/workflows/swift.yml/badge.svg?branch=main" alt="Build - main Branch">
</a>
<a href="http://swift.org">
<img src="https://img.shields.io/badge/swift-5.4|5.5|5.6-orange.svg?style=flat" alt="Swift 5.4, 5.5 and 5.6 Tested">
<img src="https://img.shields.io/badge/swift-5.5|5.6|5.7-orange.svg?style=flat" alt="Swift 5.5, 5.6 and 5.7 Tested">
</a>
<a href="https://gitter.im/SmokeServerSide">
<img src="https://img.shields.io/badge/chat-on%20gitter-ee115e.svg?style=flat" alt="Join the Smoke Server Side community on gitter">
Expand Down Expand Up @@ -39,7 +39,7 @@ will attempt to parse that file into the required service model type and will th
to the provided function which can call any required generation functions.

```swift
extension ServiceModelCodeGenerator {
extension ServiceModelCodeGenerator where TargetSupportType: ModelTargetSupport & ClientTargetSupport {

func generateFromModel<ModelType: ServiceModel>(serviceModel: ModelType,
...) throws {
Expand All @@ -62,28 +62,124 @@ extension ServiceModelCodeGenerator {
}
}

public struct MyCodeGeneration {
public static func generateFromModel<ModelType: ServiceModel>(
modelFilePath: String,
modelType: ModelType.Type,
customizations: CodeGenerationCustomizations,
applicationDescription: ApplicationDescription,
modelOverride: ModelOverride?,
...) throws
-> ModelType {
return try ServiceModelGenerate.generateFromModel(
modelFilePath: modelFilePath,
customizations: customizations,
applicationDescription: applicationDescription,
modelOverride: modelOverride) { (codeGenerator, serviceModel) in
try codeGenerator.generateFromModel(serviceModel: serviceModel, ...)
}
}
}
```

By default, the code generator will use `\(applicationDescription.baseName)Model` for the name of the model target and
`\(applicationDescription.baseName)Client` for the name of the client target. You can override these defaults by using
the `ModelAndClientTargetSupport` type.

```
public struct MyCodeGeneration {
static let asyncResultType = AsyncResultType(typeName: "HTTPResult",
libraryImport: "SmokeHTTPClient")
public static func generateFromModel<ModelType: ServiceModel>(
modelFilePath: String,
modelType: ModelType.Type,
modelTargetName: String, clientTargetName: String,
customizations: CodeGenerationCustomizations,
applicationDescription: ApplicationDescription,
modelOverride: ModelOverride?,
...) throws
-> ModelType {
let targetSupport = ModelAndClientTargetSupport(modelTargetName: modelTargetName,
clientTargetName: clientTargetName)
return try ServiceModelGenerate.generateFromModel(
modelFilePath: modelFilePath,
customizations: customizations,
applicationDescription: applicationDescription,
targetSupport: targetSupport,
modelOverride: modelOverride) { (codeGenerator, serviceModel) in
try codeGenerator.generateFromModel(serviceModel: serviceModel, ...)
}
}
}
```

Further, if you are generating additional targets, you can use a custom type that provides the name of
additional targets. This type will have to conform to the `ModelTargetSupport` and `ClientTargetSupport` protocols.

```swift
extension ServiceModelCodeGenerator where TargetSupportType: ModelTargetSupport & ClientTargetSupport & MyCustomTargetSupport {

func generateFromModel<ModelType: ServiceModel>(serviceModel: ModelType,
...) throws {
let myClientDelegate = ...
let myModelErrorsDelegate = ...

generateClient(delegate: myClientDelegate)
generateModelOperationsEnum()
generateOperationsReporting()
generateModelOperationClientInput()
generateModelOperationClientOutput()
generateModelOperationHTTPInput()
generateModelOperationHTTPOutput()
generateModelStructures()
generateModelTypes()
generateModelErrors(delegate: myModelErrorsDelegate)
generateDefaultInstances(generationType: .internalTypes)

// Call any custom generation functions as required
// The `targetSupport` attribute will conform to the `MyCustomTargetSupport` protocol.
}
}

public protocol MyCustomTargetSupport {
var myCustomTargetName: String { get }
}

public struct MyTargetSupport: ModelTargetSupport, ClientTargetSupport, MyCustomTargetSupport {
public let modelTargetName: String
public let clientTargetName: String
public let myCustomTargetName: String

public init(modelTargetName: String, clientTargetName: String,
myCustomTargetName: String) {
self.modelTargetName = modelTargetName
self.clientTargetName = clientTargetName
self.myCustomTargetName = myCustomTargetName
}
}

public struct MyCodeGeneration {
public static func generateFromModel<ModelType: ServiceModel>(
modelFilePath: String,
modelType: ModelType.Type,
modelTargetName: String, clientTargetName: String,
myCustomTargetName: String,
customizations: CodeGenerationCustomizations,
applicationDescription: ApplicationDescription,
modelOverride: ModelOverride?,
...) throws {
func generatorFunction(codeGenerator: ServiceModelCodeGenerator,
serviceModel: ModelType) throws {
...) throws
-> ModelType {
let targetSupport = MyTargetSupport(modelTargetName: modelTargetName,
clientTargetName: clientTargetName,
myCustomTargetName: myCustomTargetName)

return try ServiceModelGenerate.generateFromModel(
modelFilePath: modelFilePath,
customizations: customizations,
applicationDescription: applicationDescription,
targetSupport: targetSupport,
modelOverride: modelOverride) { (codeGenerator, serviceModel) in
try codeGenerator.generateFromModel(serviceModel: serviceModel, ...)
}

try ServiceModelGenerate.generateFromModel(
modelFilePath: modelFilePath,
customizations: customizations,
applicationDescription: applicationDescription,
modelOverride: modelOverride,
generatorFunction: generatorFunction)
}
}
}
```
Expand Down
18 changes: 10 additions & 8 deletions Sources/ServiceModelCodeGeneration/ModelClientDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ public enum ClientEntityType {
from the Service Model.
*/
public protocol ModelClientDelegate {
associatedtype TargetSupportType

/// The type of client being generated.
var clientType: ClientType { get }

Expand All @@ -91,8 +93,8 @@ public protocol ModelClientDelegate {
- delegate: the delegate being used.
- fileBuilder: The FileBuilder to output to.
*/
func addCustomFileHeader(codeGenerator: ServiceModelCodeGenerator,
delegate: ModelClientDelegate,
func addCustomFileHeader(codeGenerator: ServiceModelCodeGenerator<TargetSupportType>,
delegate: Self,
fileBuilder: FileBuilder,
fileType: ClientFileType)

Expand All @@ -104,8 +106,8 @@ public protocol ModelClientDelegate {
- delegate: the delegate being used.
- fileBuilder: The FileBuilder to output to.
*/
func addTypeDescription(codeGenerator: ServiceModelCodeGenerator,
delegate: ModelClientDelegate,
func addTypeDescription(codeGenerator: ServiceModelCodeGenerator<TargetSupportType>,
delegate: Self,
fileBuilder: FileBuilder,
entityType: ClientEntityType)

Expand All @@ -118,8 +120,8 @@ public protocol ModelClientDelegate {
- fileBuilder: The FileBuilder to output to.
- sortedOperations: A list of sorted operations from the current model.
*/
func addCommonFunctions(codeGenerator: ServiceModelCodeGenerator,
delegate: ModelClientDelegate,
func addCommonFunctions(codeGenerator: ServiceModelCodeGenerator<TargetSupportType>,
delegate: Self,
fileBuilder: FileBuilder,
sortedOperations: [(String, OperationDescription)],
entityType: ClientEntityType)
Expand All @@ -137,8 +139,8 @@ public protocol ModelClientDelegate {
- functionInputType: the input type to the operation.
- functionOutputType: the output type for the operation.
*/
func addOperationBody(codeGenerator: ServiceModelCodeGenerator,
delegate: ModelClientDelegate,
func addOperationBody(codeGenerator: ServiceModelCodeGenerator<TargetSupportType>,
delegate: Self,
fileBuilder: FileBuilder,
invokeType: InvokeType,
operationName: String,
Expand Down
25 changes: 23 additions & 2 deletions Sources/ServiceModelCodeGeneration/ServiceModelCodeGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,31 @@
import Foundation
import ServiceModelEntities

public protocol ModelTargetSupport {
var modelTargetName: String { get }
}

public protocol ClientTargetSupport {
var clientTargetName: String { get }
}

public struct ModelAndClientTargetSupport: ModelTargetSupport, ClientTargetSupport {
public let modelTargetName: String
public let clientTargetName: String

public init(modelTargetName: String, clientTargetName: String) {
self.modelTargetName = modelTargetName
self.clientTargetName = clientTargetName
}
}

/// A code generator that uses a Service Model
public struct ServiceModelCodeGenerator {
public struct ServiceModelCodeGenerator<TargetSupportType> {
public let model: ServiceModel
public let applicationDescription: ApplicationDescription
public let customizations: CodeGenerationCustomizations
public let modelOverride: ModelOverride?
public let targetSupport: TargetSupportType

/**
Constructs the description with an application base name and suffix.
Expand All @@ -40,11 +59,13 @@ public struct ServiceModelCodeGenerator {
public init(model: ServiceModel,
applicationDescription: ApplicationDescription,
customizations: CodeGenerationCustomizations,
modelOverride: ModelOverride?) {
modelOverride: ModelOverride?,
targetSupport: TargetSupportType) {
self.model = model
self.applicationDescription = applicationDescription
self.customizations = customizations
self.modelOverride = modelOverride
self.targetSupport = targetSupport
}
}

Expand Down
19 changes: 10 additions & 9 deletions Sources/ServiceModelGenerate/ClientProtocolDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import ServiceModelEntities
A ModelClientDelegate that can be used to generate a
Client protocol from a Service Model.
*/
public struct ClientProtocolDelegate: ModelClientDelegate {
public struct ClientProtocolDelegate<TargetSupportType>: ModelClientDelegate
where TargetSupportType: ModelTargetSupport & ClientTargetSupport {
public let clientType: ClientType
public let baseName: String
public let typeDescription: String
Expand All @@ -49,22 +50,22 @@ public struct ClientProtocolDelegate: ModelClientDelegate {
self.minimumCompilerSupport = minimumCompilerSupport
}

public func addTypeDescription(codeGenerator: ServiceModelCodeGenerator,
delegate: ModelClientDelegate,
public func addTypeDescription(codeGenerator: ServiceModelCodeGenerator<TargetSupportType>,
delegate: Self,
fileBuilder: FileBuilder,
entityType: ClientEntityType) {
fileBuilder.appendLine(self.typeDescription)
}

public func addCustomFileHeader(codeGenerator: ServiceModelCodeGenerator,
delegate: ModelClientDelegate,
public func addCustomFileHeader(codeGenerator: ServiceModelCodeGenerator<TargetSupportType>,
delegate: Self,
fileBuilder: FileBuilder,
fileType: ClientFileType) {
// no custom file header
}

public func addCommonFunctions(codeGenerator: ServiceModelCodeGenerator,
delegate: ModelClientDelegate,
public func addCommonFunctions(codeGenerator: ServiceModelCodeGenerator<TargetSupportType>,
delegate: Self,
fileBuilder: FileBuilder,
sortedOperations: [(String, OperationDescription)],
entityType: ClientEntityType) {
Expand Down Expand Up @@ -124,8 +125,8 @@ public struct ClientProtocolDelegate: ModelClientDelegate {
}
}

public func addOperationBody(codeGenerator: ServiceModelCodeGenerator,
delegate: ModelClientDelegate,
public func addOperationBody(codeGenerator: ServiceModelCodeGenerator<TargetSupportType>,
delegate: Self,
fileBuilder: FileBuilder, invokeType: InvokeType,
operationName: String,
operationDescription: OperationDescription,
Expand Down
Loading

0 comments on commit a1adc01

Please sign in to comment.