Skip to content

Commit 677a015

Browse files
authored
feat: Allow multiple @_spi() imports in code generated Swift (#543)
1 parent a9d7504 commit 677a015

File tree

2 files changed

+59
-23
lines changed

2 files changed

+59
-23
lines changed

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/ImportDeclarations.kt

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,19 @@ class ImportDeclarations {
99
private val imports = mutableSetOf<ImportStatement>()
1010

1111
fun addImport(packageName: String, isTestable: Boolean = false, internalSPIName: String? = null) {
12-
if (internalSPIName != null && internalSPIName != "Internal") {
13-
throw IllegalArgumentException(
14-
"""
15-
We currently only support usage of a single spiName 'Internal'.
16-
If you'd like to use another name then please update the logic below to fully support multiple spiNames.
17-
"""
18-
)
19-
}
20-
2112
val existingImport = imports.find { it.packageName == packageName }
2213
if (existingImport != null) {
23-
// If we have an existing import with the same package name, then replace the existing one
24-
val newImport = ImportStatement(
25-
packageName,
26-
isTestable || existingImport.isTestable,
27-
internalSPIName ?: existingImport.internalSPIName
28-
)
29-
imports.remove(existingImport)
30-
imports.add(newImport)
31-
return
14+
// Update isTestable to true if needed
15+
existingImport.isTestable = existingImport.isTestable || isTestable
16+
// If we have an existing import with the same package name, then add the SPI name to the existing list
17+
if (internalSPIName != null) {
18+
existingImport.internalSPINames.add(internalSPIName)
19+
}
20+
} else {
21+
// Otherwise, we have a new package to import, so add it
22+
val internalSPINames = listOf(internalSPIName).mapNotNull { it }.toMutableSet()
23+
imports.add(ImportStatement(packageName, isTestable, internalSPINames))
3224
}
33-
34-
// Otherwise, we have a new import so add it
35-
imports.add(ImportStatement(packageName, isTestable, internalSPIName))
3625
}
3726

3827
override fun toString(): String {
@@ -47,11 +36,11 @@ class ImportDeclarations {
4736
}
4837
}
4938

50-
private data class ImportStatement(val packageName: String, val isTestable: Boolean, val internalSPIName: String?) {
39+
private data class ImportStatement(val packageName: String, var isTestable: Boolean, val internalSPINames: MutableSet<String>) {
5140
val statement: String
5241
get() {
5342
var import = "import $packageName"
54-
if (internalSPIName != null) {
43+
for (internalSPIName in internalSPINames.sorted().reversed()) {
5544
import = "@_spi($internalSPIName) $import"
5645
}
5746
if (isTestable) {

smithy-swift-codegen/src/test/kotlin/ImportDeclarationsTest.kt

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,51 @@ class ImportDeclarationsTest {
3232
val expected = "import Foundation"
3333
assertEquals(expected, statements)
3434
}
35+
36+
@Test
37+
fun `it renders @testable declarations`() {
38+
val subject = ImportDeclarations()
39+
subject.addImport("MyPackage", true)
40+
assertEquals("@testable import MyPackage", subject.toString())
41+
}
42+
43+
@Test
44+
fun `it preserves @testable declarations`() {
45+
val subject = ImportDeclarations()
46+
subject.addImport("MyPackage", true)
47+
subject.addImport("MyPackage", false)
48+
assertEquals("@testable import MyPackage", subject.toString())
49+
}
50+
51+
@Test
52+
fun `it renders a single @_spi() declaration`() {
53+
val subject = ImportDeclarations()
54+
subject.addImport("MyPackage", false, "MyInternalAPI")
55+
assertEquals("@_spi(MyInternalAPI) import MyPackage", subject.toString())
56+
}
57+
58+
@Test
59+
fun `it renders a single @_spi() and @testable declaration`() {
60+
val subject = ImportDeclarations()
61+
subject.addImport("MyPackage", true, "MyInternalAPI")
62+
assertEquals("@testable @_spi(MyInternalAPI) import MyPackage", subject.toString())
63+
}
64+
65+
@Test
66+
fun `it renders multiple @_spi() declarations`() {
67+
val subject = ImportDeclarations()
68+
subject.addImport("MyPackage", false, "MyInternalAPI1")
69+
subject.addImport("MyPackage", false, "MyInternalAPI2")
70+
assertEquals("@_spi(MyInternalAPI1) @_spi(MyInternalAPI2) import MyPackage", subject.toString())
71+
}
72+
73+
@Test
74+
fun `it deduplicates @_spi() declarations`() {
75+
val subject = ImportDeclarations()
76+
subject.addImport("MyPackage", false, "MyInternalAPI1")
77+
subject.addImport("MyPackage", false, "MyInternalAPI2")
78+
subject.addImport("MyPackage", false, "MyInternalAPI1")
79+
subject.addImport("MyPackage", false, "MyInternalAPI2")
80+
assertEquals("@_spi(MyInternalAPI1) @_spi(MyInternalAPI2) import MyPackage", subject.toString())
81+
}
3582
}

0 commit comments

Comments
 (0)