-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: Adds IntEnum support - Generate IntEnum shapes - Moves shared enum casing logic to Utils so it can be easily shared - Updates test generator to sort members by lower camel case * Adds IntEnumGenerator * ktlintformat * Addresses swiftlint violations * Adds proper import and removes wildcard import
- Loading branch information
Showing
12 changed files
with
274 additions
and
23 deletions.
There are no files selected for viewing
This file contains 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 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 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 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
128 changes: 128 additions & 0 deletions
128
...hy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/IntEnumGenerator.kt
This file contains 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,128 @@ | ||
package software.amazon.smithy.swift.codegen | ||
|
||
import software.amazon.smithy.codegen.core.SymbolProvider | ||
import software.amazon.smithy.model.Model | ||
import software.amazon.smithy.model.shapes.IntEnumShape | ||
import software.amazon.smithy.model.shapes.MemberShape | ||
import software.amazon.smithy.model.shapes.ServiceShape | ||
import software.amazon.smithy.model.traits.EnumValueTrait | ||
import software.amazon.smithy.swift.codegen.customtraits.NestedTrait | ||
import software.amazon.smithy.swift.codegen.model.expectShape | ||
import software.amazon.smithy.swift.codegen.model.hasTrait | ||
import software.amazon.smithy.swift.codegen.model.nestedNamespaceType | ||
import java.util.Optional | ||
|
||
class IntEnumGenerator( | ||
private val model: Model, | ||
private val symbolProvider: SymbolProvider, | ||
private val writer: SwiftWriter, | ||
private val shape: IntEnumShape, | ||
private val settings: SwiftSettings | ||
) { | ||
private var allCasesBuilder: MutableList<String> = mutableListOf() | ||
private var rawValuesBuilder: MutableList<String> = mutableListOf() | ||
|
||
fun render() { | ||
val symbol = symbolProvider.toSymbol(shape) | ||
writer.putContext("enum.name", symbol.name) | ||
val isNestedType = shape.hasTrait<NestedTrait>() | ||
if (isNestedType) { | ||
val service = model.expectShape<ServiceShape>(settings.service) | ||
writer.openBlock("extension ${service.nestedNamespaceType(symbolProvider)} {", "}") { | ||
renderEnum() | ||
} | ||
} else { | ||
renderEnum() | ||
} | ||
writer.removeContext("enum.name") | ||
} | ||
|
||
private fun renderEnum() { | ||
writer.writeShapeDocs(shape) | ||
writer.writeAvailableAttribute(null, shape) | ||
writer.openBlock("public enum \$enum.name:L: \$N, \$N, \$N, \$N, \$N {", "}", SwiftTypes.Protocols.Equatable, SwiftTypes.Protocols.RawRepresentable, SwiftTypes.Protocols.CaseIterable, SwiftTypes.Protocols.Codable, SwiftTypes.Protocols.Hashable) { | ||
createEnumWriterContexts() | ||
// add the sdkUnknown case which will always be last | ||
writer.write("case sdkUnknown(\$N)", SwiftTypes.Int) | ||
|
||
writer.write("") | ||
|
||
// Generate allCases static array | ||
generateAllCasesBlock() | ||
|
||
// Generate initializer from rawValue | ||
generateInitFromRawValueBlock() | ||
|
||
// Generate rawValue internal enum | ||
generateRawValueEnumBlock() | ||
} | ||
} | ||
|
||
fun addEnumCaseToEnum(caseShape: MemberShape) { | ||
writer.writeMemberDocs(model, caseShape) | ||
writer.write("case ${caseShape.swiftEnumCaseName()}") | ||
} | ||
|
||
fun addEnumCaseToAllCases(caseShape: MemberShape) { | ||
allCasesBuilder.add(".${caseShape.swiftEnumCaseName(false)}") | ||
} | ||
|
||
fun addEnumCaseToRawValuesEnum(caseShape: MemberShape) { | ||
rawValuesBuilder.add("case .${caseShape.swiftEnumCaseName(false)}: return ${caseShape.swiftEnumCaseValue()}") | ||
} | ||
|
||
fun createEnumWriterContexts() { | ||
shape | ||
.getCaseMembers() | ||
.sortedBy { it.memberName } | ||
.forEach { | ||
// Add all given enum cases to generated enum definition | ||
addEnumCaseToEnum(it) | ||
addEnumCaseToAllCases(it) | ||
addEnumCaseToRawValuesEnum(it) | ||
} | ||
} | ||
|
||
fun generateAllCasesBlock() { | ||
allCasesBuilder.add(".sdkUnknown(0)") | ||
writer.openBlock("public static var allCases: [\$enum.name:L] {", "}") { | ||
writer.openBlock("return [", "]") { | ||
writer.write(allCasesBuilder.joinToString(",\n")) | ||
} | ||
} | ||
} | ||
|
||
fun generateInitFromRawValueBlock() { | ||
writer.openBlock("public init(rawValue: \$N) {", "}", SwiftTypes.Int) { | ||
writer.write("let value = Self.allCases.first(where: { \$\$0.rawValue == rawValue })") | ||
writer.write("self = value ?? Self.sdkUnknown(rawValue)") | ||
} | ||
} | ||
|
||
fun generateRawValueEnumBlock() { | ||
rawValuesBuilder.add("case let .sdkUnknown(s): return s") | ||
writer.openBlock("public var rawValue: \$N {", "}", SwiftTypes.Int) { | ||
writer.write("switch self {") | ||
writer.write(rawValuesBuilder.joinToString("\n")) | ||
writer.write("}") | ||
} | ||
} | ||
|
||
fun IntEnumShape.getCaseMembers(): List<MemberShape> { | ||
return members().filter { | ||
it.hasTrait<EnumValueTrait>() | ||
} | ||
} | ||
|
||
fun MemberShape.swiftEnumCaseName(shouldBeEscaped: Boolean = true): String { | ||
return swiftEnumCaseName( | ||
Optional.of(memberName), | ||
"${swiftEnumCaseValue()}", | ||
shouldBeEscaped | ||
) | ||
} | ||
|
||
fun MemberShape.swiftEnumCaseValue(): Int { | ||
return expectTrait<EnumValueTrait>(EnumValueTrait::class.java).expectIntValue() | ||
} | ||
} |
This file contains 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 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 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 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 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
52 changes: 52 additions & 0 deletions
52
smithy-swift-codegen/src/test/kotlin/IntEnumGeneratorTests.kt
This file contains 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,52 @@ | ||
import io.kotest.matchers.string.shouldContain | ||
import org.junit.jupiter.api.Assertions | ||
import org.junit.jupiter.api.Test | ||
import software.amazon.smithy.build.MockManifest | ||
import software.amazon.smithy.swift.codegen.SwiftCodegenPlugin | ||
|
||
class IntEnumGeneratorTests { | ||
|
||
@Test | ||
fun `generates int enum`() { | ||
val model = javaClass.getResource("int-enum-shape-test.smithy").asSmithy() | ||
val manifest = MockManifest() | ||
val context = buildMockPluginContext(model, manifest, "smithy.example#Example") | ||
SwiftCodegenPlugin().execute(context) | ||
val enumShape = manifest | ||
.getFileString("example/models/Abcs.swift").get() | ||
Assertions.assertNotNull(enumShape) | ||
|
||
var expectedGeneratedEnum = | ||
""" | ||
public enum Abcs: Swift.Equatable, Swift.RawRepresentable, Swift.CaseIterable, Swift.Codable, Swift.Hashable { | ||
case a | ||
case b | ||
case c | ||
case sdkUnknown(Swift.Int) | ||
public static var allCases: [Abcs] { | ||
return [ | ||
.a, | ||
.b, | ||
.c, | ||
.sdkUnknown(0) | ||
] | ||
} | ||
public init(rawValue: Swift.Int) { | ||
let value = Self.allCases.first(where: { ${'$'}0.rawValue == rawValue }) | ||
self = value ?? Self.sdkUnknown(rawValue) | ||
} | ||
public var rawValue: Swift.Int { | ||
switch self { | ||
case .a: return 1 | ||
case .b: return 2 | ||
case .c: return 3 | ||
case let .sdkUnknown(s): return s | ||
} | ||
} | ||
} | ||
""".trimIndent() | ||
|
||
enumShape.shouldContain(expectedGeneratedEnum) | ||
} | ||
} |
Oops, something went wrong.