Skip to content

Commit 388fc25

Browse files
authored
feat: add support for new waiter expressions, upgrade Smithy to 1.22 (#672)
1 parent 7da7822 commit 388fc25

File tree

22 files changed

+338
-128
lines changed

22 files changed

+338
-128
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"id": "5bdddd68-7b25-4785-9a20-03790e330f27",
3+
"type": "feature",
4+
"description": "Add support for NOT, OR, and AND JMESPath expressions in waiters"
5+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"id": "ba998d36-ef93-4b63-8830-18e0f38c3b9a",
3+
"type": "misc",
4+
"description": "Upgrade Smithy version to 1.22",
5+
"issues": [
6+
"awslabs/smithy-kotlin#599"
7+
]
8+
}

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jsoupVersion=1.14.3
2424
okHttpVersion=5.0.0-alpha.9
2525

2626
# codegen
27-
smithyVersion=1.17.0
27+
smithyVersion=1.22.0
2828
smithyGradleVersion=0.5.3
2929

3030
# testing/utility

runtime/utils/common/src/aws/smithy/kotlin/runtime/util/Convenience.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,16 @@ inline fun <reified T> Collection<T>.flattenIfPossible(): Collection<T> = this
1818

1919
@JvmName("flattenNestedCollection")
2020
inline fun <reified T> Collection<Collection<T>>.flattenIfPossible(): Collection<T> = flatten()
21+
22+
/**
23+
* Evaluates the "truthiness" of a value based on
24+
* [JMESPath definitions](https://jmespath.org/specification.html#or-expressions).
25+
*/
26+
fun truthiness(value: Any?): Boolean = when (value) {
27+
is Boolean -> value
28+
is Collection<*> -> value.isNotEmpty()
29+
is Map<*, *> -> value.isNotEmpty()
30+
is String -> value.isNotEmpty()
31+
null -> false
32+
else -> true
33+
}
Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
package software.amazon.smithy.kotlin.codegen.core
66

77
import software.amazon.smithy.kotlin.codegen.integration.SectionId
8-
import software.amazon.smithy.utils.CodeWriter
8+
import software.amazon.smithy.utils.AbstractCodeWriter
9+
import software.amazon.smithy.utils.SimpleCodeWriter
910
import java.util.function.BiFunction
1011

1112
/**
@@ -26,7 +27,7 @@ import java.util.function.BiFunction
2627
* writer.closeBlock("}")
2728
* ```
2829
*/
29-
fun <T : CodeWriter> T.withBlock(
30+
fun <T : AbstractCodeWriter<T>> T.withBlock(
3031
textBeforeNewLine: String,
3132
textAfterNewLine: String,
3233
vararg args: Any,
@@ -36,7 +37,7 @@ fun <T : CodeWriter> T.withBlock(
3637
/**
3738
* Like [withBlock], except the closing write of [textAfterNewLine] does NOT include a line break.
3839
*/
39-
fun <T : CodeWriter> T.withInlineBlock(
40+
fun <T : AbstractCodeWriter<T>> T.withInlineBlock(
4041
textBeforeNewLine: String,
4142
textAfterNewLine: String,
4243
vararg args: Any,
@@ -66,7 +67,7 @@ fun <T : CodeWriter> T.withInlineBlock(
6667
* if (foo == bar) writer.closeBlock("}")
6768
* ```
6869
*/
69-
fun <T : CodeWriter> T.wrapBlockIf(
70+
fun <T : AbstractCodeWriter<T>> T.wrapBlockIf(
7071
condition: Boolean,
7172
textBeforeNewLine: String,
7273
textAfterNewLine: String,
@@ -80,9 +81,9 @@ fun <T : CodeWriter> T.wrapBlockIf(
8081
}
8182

8283
/**
83-
* Like [CodeWriter.closeBlock], except the closing write of [textAfterNewLine] does NOT include a line break.
84+
* Like [AbstractCodeWriter.closeBlock], except the closing write of [textAfterNewLine] does NOT include a line break.
8485
*/
85-
fun <T : CodeWriter> T.closeInlineBlock(textAfterNewLine: String): T {
86+
fun <T : AbstractCodeWriter<T>> T.closeInlineBlock(textAfterNewLine: String): T {
8687
writeInline("\n")
8788
dedent()
8889
writeInline(textAfterNewLine)
@@ -103,7 +104,7 @@ fun <T : CodeWriter> T.closeInlineBlock(textAfterNewLine: String): T {
103104
* .closeBlock("}")
104105
* ```
105106
*/
106-
fun <T : CodeWriter> T.closeAndOpenBlock(
107+
fun <T : AbstractCodeWriter<T>> T.closeAndOpenBlock(
107108
textBeforeNewLine: String,
108109
vararg args: Any,
109110
): T = apply {
@@ -116,7 +117,11 @@ fun <T : CodeWriter> T.closeAndOpenBlock(
116117
* of the type housing the codegen associated with the section. This keeps [SectionId]s closely
117118
* associated with their targets.
118119
*/
119-
fun <T : CodeWriter> T.declareSection(id: SectionId, context: Map<String, Any?> = emptyMap(), block: T.() -> Unit = {}): T {
120+
fun <T : AbstractCodeWriter<T>> T.declareSection(
121+
id: SectionId,
122+
context: Map<String, Any?> = emptyMap(),
123+
block: T.() -> Unit = { },
124+
): T {
120125
putContext(context)
121126
pushState(id.javaClass.canonicalName)
122127
block(this)
@@ -125,25 +130,27 @@ fun <T : CodeWriter> T.declareSection(id: SectionId, context: Map<String, Any?>
125130
return this
126131
}
127132

128-
private fun <T : CodeWriter> T.removeContext(context: Map<String, Any?>): Unit =
133+
private fun <T : AbstractCodeWriter<T>> T.removeContext(context: Map<String, Any?>): Unit =
129134
context.keys.forEach { key -> removeContext(key) }
130135

131136
/**
132137
* Convenience function to get a typed value out of the context or throw if the key doesn't exist
133138
* or the type is wrong
134139
*/
135-
inline fun <reified T> CodeWriter.getContextValue(key: String): T = checkNotNull(getContext(key) as? T) {
136-
"Expected `$key` in CodeWriter context"
137-
}
140+
inline fun <W : AbstractCodeWriter<W>, reified V> AbstractCodeWriter<W>.getContextValue(key: String): V =
141+
checkNotNull(getContext(key) as? V) {
142+
"Expected `$key` in CodeWriter context"
143+
}
144+
145+
typealias InlineCodeWriter = AbstractCodeWriter<*>.() -> Unit
138146

139-
// Specifies a function that receives a [CodeWriter]
140-
typealias InlineCodeWriter = CodeWriter.() -> Unit
141147
/**
142148
* Formatter to enable passing a writing function
143-
* @param codeWriterCreator function that creates a new [CodeWriter] instance used to generate output of inline content
149+
* @param codeWriterCreator function that creates a new [AbstractCodeWriter] instance used to generate output of inline
150+
* content
144151
*/
145152
class InlineCodeWriterFormatter(
146-
private val codeWriterCreator: () -> CodeWriter = { CodeWriter() }
153+
private val codeWriterCreator: () -> AbstractCodeWriter<*> = ::SimpleCodeWriter
147154
) : BiFunction<Any, String, String> {
148155
@Suppress("UNCHECKED_CAST")
149156
override fun apply(t: Any, u: String): String {
@@ -158,7 +165,7 @@ class InlineCodeWriterFormatter(
158165
* Optionally call the [Runnable] if [test] is true, otherwise do nothing and return the instance without
159166
* running the block
160167
*/
161-
fun CodeWriter.callIf(test: Boolean, runnable: Runnable): CodeWriter {
168+
fun <T : AbstractCodeWriter<T>> T.callIf(test: Boolean, runnable: Runnable): T {
162169
if (test) {
163170
runnable.run()
164171
}

smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/KotlinSymbolProvider.kt

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import software.amazon.smithy.model.shapes.*
1313
import software.amazon.smithy.model.traits.BoxTrait
1414
import software.amazon.smithy.model.traits.SparseTrait
1515
import software.amazon.smithy.model.traits.StreamingTrait
16+
import software.amazon.smithy.model.traits.UniqueItemsTrait
1617
import java.util.logging.Logger
1718

1819
/**
@@ -94,7 +95,7 @@ class KotlinSymbolProvider(private val model: Model, private val settings: Kotli
9495
createSymbolBuilder(shape, "String", boxed = true, namespace = "kotlin").build()
9596
}
9697

97-
fun createEnumSymbol(shape: StringShape): Symbol {
98+
private fun createEnumSymbol(shape: StringShape): Symbol {
9899
val namespace = "$rootNamespace.model"
99100
return createSymbolBuilder(shape, shape.defaultName(service), namespace, boxed = true)
100101
.definitionFile("${shape.defaultName(service)}.kt")
@@ -146,12 +147,19 @@ class KotlinSymbolProvider(private val model: Model, private val settings: Kotli
146147
override fun listShape(shape: ListShape): Symbol {
147148
val reference = toSymbol(shape.member)
148149
val valueType = if (shape.hasTrait<SparseTrait>()) "${reference.name}?" else reference.name
149-
150-
return createSymbolBuilder(shape, "List<$valueType>", boxed = true)
151-
.addReferences(reference)
152-
.putProperty(SymbolProperty.MUTABLE_COLLECTION_FUNCTION, "mutableListOf<$valueType>")
153-
.putProperty(SymbolProperty.IMMUTABLE_COLLECTION_FUNCTION, "listOf<$valueType>")
154-
.build()
150+
return if (shape.hasTrait<UniqueItemsTrait>()) {
151+
createSymbolBuilder(shape, "Set<$valueType>", boxed = true)
152+
.addReference(reference)
153+
.putProperty(SymbolProperty.MUTABLE_COLLECTION_FUNCTION, "mutableSetOf<$valueType>")
154+
.putProperty(SymbolProperty.IMMUTABLE_COLLECTION_FUNCTION, "setOf<$valueType>")
155+
.build()
156+
} else {
157+
createSymbolBuilder(shape, "List<$valueType>", boxed = true)
158+
.addReferences(reference)
159+
.putProperty(SymbolProperty.MUTABLE_COLLECTION_FUNCTION, "mutableListOf<$valueType>")
160+
.putProperty(SymbolProperty.IMMUTABLE_COLLECTION_FUNCTION, "listOf<$valueType>")
161+
.build()
162+
}
155163
}
156164

157165
override fun mapShape(shape: MapShape): Symbol {
@@ -166,15 +174,6 @@ class KotlinSymbolProvider(private val model: Model, private val settings: Kotli
166174
.build()
167175
}
168176

169-
override fun setShape(shape: SetShape): Symbol {
170-
val reference = toSymbol(shape.member)
171-
return createSymbolBuilder(shape, "Set<${reference.name}>", boxed = true)
172-
.addReference(reference)
173-
.putProperty(SymbolProperty.MUTABLE_COLLECTION_FUNCTION, "mutableSetOf<${reference.name}>")
174-
.putProperty(SymbolProperty.IMMUTABLE_COLLECTION_FUNCTION, "setOf<${reference.name}>")
175-
.build()
176-
}
177-
178177
override fun memberShape(shape: MemberShape): Symbol {
179178
val targetShape =
180179
model.getShape(shape.target).orElseThrow { CodegenException("Shape not found: ${shape.target}") }

smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/KotlinWriter.kt

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import software.amazon.smithy.model.shapes.MemberShape
2222
import software.amazon.smithy.model.shapes.Shape
2323
import software.amazon.smithy.model.traits.DocumentationTrait
2424
import software.amazon.smithy.model.traits.EnumDefinition
25-
import software.amazon.smithy.utils.CodeWriter
25+
import software.amazon.smithy.utils.AbstractCodeWriter
2626
import java.util.function.BiFunction
2727

2828
/**
@@ -42,16 +42,18 @@ class KotlinWriter(
4242
val fullyQualifiedSymbols: MutableSet<FullyQualifiedSymbolName> = mutableSetOf(),
4343
val dependencies: MutableSet<SymbolDependency> = mutableSetOf(),
4444
val imports: ImportDeclarations = ImportDeclarations()
45-
) : CodeWriter() {
45+
) : AbstractCodeWriter<KotlinWriter>() {
4646

4747
init {
4848
trimBlankLines()
4949
trimTrailingSpaces()
50-
setIndentText(" ")
50+
51+
indentText = " "
5152
expressionStart = '#'
5253

5354
// type name: `Foo`
5455
putFormatter('T', KotlinSymbolFormatter(this) { symbol -> fullyQualifiedSymbols.contains(symbol.toFullyQualifiedSymbolName()) })
56+
5557
// fully qualified type: `aws.sdk.kotlin.model.Foo`
5658
putFormatter('Q', KotlinSymbolFormatter(this) { true })
5759

@@ -173,7 +175,7 @@ class KotlinWriter(
173175
fun dokka(block: KotlinWriter.() -> Unit): KotlinWriter {
174176
pushState()
175177
write("/**")
176-
setNewlinePrefix(" * ")
178+
newlinePrefix = " * "
177179
block(this)
178180
popState()
179181
write(" */")
@@ -234,7 +236,7 @@ class KotlinWriter(
234236
/**
235237
* Registers a [SectionWriter] given a [SectionId] to a specific writer. This will cause the
236238
* [SectionWriter.write] to be called at the point in which the section is declared via
237-
* the [CodeWriter.declareSection] function.
239+
* the [declareSection] function.
238240
*/
239241
fun KotlinWriter.registerSectionWriter(id: SectionId, writer: SectionWriter): KotlinWriter {
240242
onSection(id.javaClass.canonicalName) { default ->
@@ -334,7 +336,7 @@ class KotlinPropertyFormatter(
334336
typealias InlineKotlinWriter = KotlinWriter.() -> Unit
335337
/**
336338
* Formatter to enable passing a writing function
337-
* @param codeWriterCreator function that creates a new [CodeWriter] instance used to generate output of inline content
339+
* @param parent a [KotlinWriter] which provides inherited state for this inner writer.
338340
*/
339341
class InlineKotlinWriterFormatter(private val parent: KotlinWriter) : BiFunction<Any, String, String> {
340342
@Suppress("UNCHECKED_CAST")
@@ -351,14 +353,6 @@ class InlineKotlinWriterFormatter(private val parent: KotlinWriter) : BiFunction
351353
}
352354
}
353355

354-
// Remove all strings from source string and return the result
355-
private fun String.stripAll(stripList: List<String>): String {
356-
var newStr = this
357-
for (item in stripList) newStr = newStr.replace(item, "")
358-
359-
return newStr
360-
}
361-
362356
// Remove leading, trailing, and consecutive blank lines
363357
private fun formatDocumentation(doc: String, lineSeparator: String = "\n") =
364358
doc

smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/RuntimeTypes.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ object RuntimeTypes {
137137
val AttributeKey = runtimeSymbol("AttributeKey", KotlinDependency.UTILS)
138138
val flattenIfPossible = runtimeSymbol("flattenIfPossible", KotlinDependency.UTILS)
139139
val length = runtimeSymbol("length", KotlinDependency.UTILS)
140+
val truthiness = runtimeSymbol("truthiness", KotlinDependency.UTILS)
140141
val urlEncodeComponent = runtimeSymbol("urlEncodeComponent", KotlinDependency.UTILS, "text")
141142
}
142143

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
package software.amazon.smithy.kotlin.codegen.model
6+
7+
import software.amazon.smithy.kotlin.codegen.KotlinSettings
8+
import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration
9+
import software.amazon.smithy.model.Model
10+
import software.amazon.smithy.model.shapes.CollectionShape
11+
import software.amazon.smithy.model.shapes.ListShape
12+
import software.amazon.smithy.model.shapes.Shape
13+
import software.amazon.smithy.model.traits.UniqueItemsTrait
14+
import software.amazon.smithy.model.transform.ModelTransformer
15+
16+
/**
17+
* Replaces deprecated Smithy `set` shapes with `list` shapes annotated with the `@uniqueItems` trait. This transformer
18+
* should only be necessary until all models have migrated away from `set` shapes.
19+
*/
20+
class SetRefactorPreprocessor : KotlinIntegration {
21+
override fun preprocessModel(model: Model, settings: KotlinSettings): Model {
22+
val replaced = model
23+
.shapeIds
24+
.map(model::expectShape)
25+
.mapNotNull(::toSetShapeOrNull)
26+
.map(::toUniqueValuedList)
27+
28+
return ModelTransformer.create().replaceShapes(model, replaced)
29+
}
30+
}
31+
32+
// Necessary to suppress deprecation because we're detecting deprecated shapes!
33+
@Suppress("DEPRECATION")
34+
private fun toSetShapeOrNull(shape: Shape) = shape as? software.amazon.smithy.model.shapes.SetShape
35+
36+
private fun toUniqueValuedList(shape: CollectionShape): ListShape = ListShape
37+
.builder()
38+
.id(shape.id)
39+
.member(shape.member)
40+
.traits(shape.allTraits.values + UniqueItemsTrait())
41+
.build()

smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/model/knowledge/SerdeIndex.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,6 @@ private fun walkNestedShapesRequiringSerde(model: Model, shapes: Set<Shape>): Se
129129
RelationshipType.MEMBER_TARGET,
130130
RelationshipType.STRUCTURE_MEMBER,
131131
RelationshipType.LIST_MEMBER,
132-
RelationshipType.SET_MEMBER,
133132
RelationshipType.MAP_VALUE,
134133
RelationshipType.UNION_MEMBER -> true
135134
else -> false

0 commit comments

Comments
 (0)