Skip to content
Draft
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
495f2e1
Disable input/output serializers
jbelkins Nov 4, 2025
ca5b331
add ShapeID, doc comments
jbelkins Nov 5, 2025
212120e
Re-enable serde code
jbelkins Nov 5, 2025
fcdf1bf
Cleanup
jbelkins Nov 5, 2025
b2152c2
Merge branch 'main' into jbe/add_schema
jbelkins Nov 7, 2025
88f7be9
Merge branch 'main' into jbe/add_schema
jbelkins Nov 8, 2025
aa823be
feat: Add Swift-native codegen plugin
jbelkins Nov 9, 2025
e817d55
Fix lint
jbelkins Nov 9, 2025
6a9c537
Make service trait optional
jbelkins Nov 9, 2025
33cc093
Fix ktlint again
jbelkins Nov 9, 2025
6b54575
Refactor code generator plugin
jbelkins Nov 9, 2025
ae474f1
Convert smithy model info file to .json
jbelkins Nov 9, 2025
70f7669
Fix Swift 5.9 URL initializer
jbelkins Nov 9, 2025
3d623e6
Code cleanup
jbelkins Nov 9, 2025
d535e66
Revert disabling of schemas
jbelkins Nov 9, 2025
52f9532
Schemas generate for entire SDK
jbelkins Nov 15, 2025
1fa7fbd
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Nov 19, 2025
70e8a15
Fix method name renderSchema
jbelkins Nov 19, 2025
b1548a7
Fix swiftlint
jbelkins Nov 19, 2025
94a901d
Fix ktlint
jbelkins Nov 19, 2025
54a4300
Fix SmithyCodegenCoreTests
jbelkins Nov 19, 2025
6b860df
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Nov 22, 2025
1eb996b
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Nov 26, 2025
3fd9854
Cleanup
jbelkins Dec 5, 2025
64dd13a
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Dec 9, 2025
6a65655
Fixes
jbelkins Dec 9, 2025
db5b76a
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Dec 12, 2025
64eeff9
More codegen added
jbelkins Dec 12, 2025
953e1d9
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Dec 15, 2025
260e5ca
Serializes to string
jbelkins Dec 17, 2025
2e73154
Serializes maps & lists to string
jbelkins Dec 17, 2025
0a3b8c6
Fix rendered string for structure
jbelkins Dec 18, 2025
05d8088
Convert ShapeSerializer methods to throwing
jbelkins Dec 19, 2025
dbfb2af
Add deser code
jbelkins Dec 22, 2025
b19ab8c
Clarify doc comment
jbelkins Dec 22, 2025
d99a7c0
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Dec 22, 2025
811c8cc
Comments, fix swiftlint
jbelkins Dec 22, 2025
1005d47
Refine serializer interfaces
jbelkins Dec 22, 2025
707ab1a
refactor, added codec
jbelkins Dec 26, 2025
46b0808
Separate methods named sdkId, prune model to one service
jbelkins Dec 31, 2025
bf7b1b3
Protocol tests now run
jbelkins Jan 1, 2026
6550aab
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Jan 1, 2026
5ecb766
CBOR serialization passes protocol tests
jbelkins Jan 5, 2026
7a2eb11
All CBOR protocol tests pass, with local CRT changes
jbelkins Jan 7, 2026
82196f9
Fix swiftlint, ktlint, refactor
jbelkins Jan 8, 2026
6a07b2d
Added ClientProtocol
jbelkins Jan 12, 2026
aab0ecc
immediateDescendant refactor
jbelkins Jan 12, 2026
ee07905
Add query compatibility extensions
jbelkins Jan 13, 2026
faba2fc
Enable query mode
jbelkins Jan 14, 2026
9929a5f
Convert schemas to struct
jbelkins Jan 14, 2026
1257136
Add query compatibility, fix tests
jbelkins Jan 15, 2026
9ac9104
Fix Swift unit tests
jbelkins Jan 15, 2026
0abd9bc
No model info file for non-schema based svcs
jbelkins Jan 15, 2026
30c3184
TypeRegistry sendable
jbelkins Jan 15, 2026
36348a3
DeserializableShape: Sendable
jbelkins Jan 15, 2026
8ff310f
Refactor query compatible from TypeRegistry to ClientProtocol impl
jbelkins Jan 15, 2026
5908312
Fix swiftlint, rename
jbelkins Jan 15, 2026
1ba6543
Move query compatibility logic out
jbelkins Jan 15, 2026
8cb08ab
Fixes & model transforms so all but 6 svcs build
jbelkins Jan 17, 2026
87e8112
Whole SDK builds schema-based code now
jbelkins Jan 17, 2026
fe5aa9f
Fix compile warnings
jbelkins Jan 19, 2026
49cf3c6
Code cleanup
jbelkins Jan 19, 2026
7ce66d4
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Jan 19, 2026
4f961f7
Fix lint
jbelkins Jan 19, 2026
797ddd1
Simplify deser interfaces, test StringSerializer
jbelkins Jan 21, 2026
8ee1e87
Add clarifying comments on force unwraps
jbelkins Jan 22, 2026
4b2d01f
Merge branch 'jbe/codegen_core' into jbe/swift_codegen_schema
jbelkins Jan 24, 2026
67a016b
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Feb 2, 2026
3e47875
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Feb 3, 2026
3b423c5
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Feb 4, 2026
367ab7d
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Feb 9, 2026
b2b2351
CBOR uses plugin for path
jbelkins Feb 10, 2026
15d5e8d
Restore deprecations, fix lint
jbelkins Feb 10, 2026
1ab0a7f
Fix build for all services
jbelkins Feb 11, 2026
8256563
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Feb 12, 2026
29c0786
Internal clients generate compiling code
jbelkins Feb 13, 2026
f4f8a81
Fix lint
jbelkins Feb 13, 2026
4971dfc
Fix broken tests
jbelkins Feb 13, 2026
9e8d3cd
AWS JSON svcs build with schema-based
jbelkins Feb 13, 2026
f90b41d
Fix SmithyModelInfo whitespace
jbelkins Feb 13, 2026
61bed21
Fix lint
jbelkins Feb 16, 2026
ff47f1f
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Feb 16, 2026
bcd6dc7
Fix trailing comma in Package.swift
jbelkins Feb 16, 2026
85b016d
AWSJSON protocol tests now pass
jbelkins Feb 20, 2026
1686cdb
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Feb 20, 2026
09818e2
Pin swift-argument-parser while awaiting resolution of Swift 5.x issues
jbelkins Feb 20, 2026
ef21da0
Merge branch 'epic/sbs' into jbe/swift_codegen_schema
jbelkins Feb 20, 2026
1126577
Code cleanup, fix tests
jbelkins Feb 20, 2026
cfbca36
Fix lint
jbelkins Feb 20, 2026
4d43f12
Fix Swift 6 compile issue
jbelkins Feb 20, 2026
eec5714
More Swift 6 fixes
jbelkins Feb 20, 2026
ae04109
More Swift 6 fixes
jbelkins Feb 20, 2026
b2ee536
Even more Swift 6 fixes
jbelkins Feb 21, 2026
ac75b38
Get client name from settings sdkId
jbelkins Feb 23, 2026
242814d
Fix event stream protocol test build
jbelkins Feb 23, 2026
24a1bb9
Disable initial response integration
jbelkins Feb 23, 2026
d4109c1
Fix ktlint
jbelkins Feb 23, 2026
9fe9d83
Only add operations CLI param if operations is non empty
jbelkins Feb 24, 2026
b3c3a03
Remove timeout on smithy-swift CI
jbelkins Feb 24, 2026
a4f284a
feat: Add operation and type registry codegen
jbelkins Feb 26, 2026
52a642c
Fix SmithyCodegenCoreTests
jbelkins Feb 26, 2026
3eb8e82
Add support for service closure renames
jbelkins Feb 26, 2026
b1b4b55
Merge branch 'jbe/operations_and_type_registry' into jbe/swift_codege…
jbelkins Feb 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -303,9 +303,15 @@ let package = Package(
.executableTarget(
name: "SmithyCodegenCLI",
dependencies: [
"SmithyCodegenCore",
.product(name: "ArgumentParser", package: "swift-argument-parser"),
]
),
.target(
name: "SmithyCodegenCore",
dependencies: ["Smithy"],
resources: [ .process("Resources") ]
),
.testTarget(
name: "ClientRuntimeTests",
dependencies: [
Expand Down Expand Up @@ -393,5 +399,9 @@ let package = Package(
name: "SmithyStreamsTests",
dependencies: ["SmithyStreams", "Smithy"]
),
.testTarget(
name: "SmithyCodegenCoreTests",
dependencies: ["SmithyCodegenCore"]
),
].compactMap { $0 }
)
21 changes: 21 additions & 0 deletions Sources/Smithy/Schema/SchemaTraits.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

/// The trait IDs that should be copied into schemas. Other traits are omitted for brevity.
///
/// This list can be expanded as features are added to Smithy/SDK that use them.
public let permittedTraitIDs: Set<String> = [
"smithy.api#sparse",
"smithy.api#input",
"smithy.api#output",
"smithy.api#error",
"smithy.api#enumValue",
"smithy.api#jsonName",
"smithy.api#required",
"smithy.api#default",
"smithy.api#timestampFormat",
]
9 changes: 3 additions & 6 deletions Sources/SmithyCodegenCLI/SmithyCodegenCLI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import ArgumentParser
import Foundation
import struct SmithyCodegenCore.CodeGenerator

@main
struct SmithyCodegenCLI: AsyncParsableCommand {
Expand All @@ -31,12 +32,8 @@ struct SmithyCodegenCLI: AsyncParsableCommand {
// If --schemas-path was supplied, create the schema file URL
let schemasFileURL = resolve(paramName: "--schemas-path", path: schemasPath)

// All file URLs needed for code generation have now been resolved.
// Implement code generation here.
if let schemasFileURL {
print("Schemas file path: \(schemasFileURL)")
FileManager.default.createFile(atPath: schemasFileURL.path, contents: Data())
}
// Use resolved file URLs to run code generator
try CodeGenerator(modelFileURL: modelFileURL, schemasFileURL: schemasFileURL).run()
}

private func currentWorkingDirectoryFileURL() -> URL {
Expand Down
14 changes: 14 additions & 0 deletions Sources/SmithyCodegenCore/AST/ASTError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

public struct ASTError: Error {
public let localizedDescription: String

init(_ localizedDescription: String) {
self.localizedDescription = localizedDescription
}
}
11 changes: 11 additions & 0 deletions Sources/SmithyCodegenCore/AST/ASTMember.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

struct ASTMember: Decodable {
let target: String
let traits: [String: ASTNode]?
}
12 changes: 12 additions & 0 deletions Sources/SmithyCodegenCore/AST/ASTModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

struct ASTModel: Decodable {
let smithy: String
let metadata: ASTNode?
let shapes: [String: ASTShape]
}
45 changes: 45 additions & 0 deletions Sources/SmithyCodegenCore/AST/ASTNode.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

/// Contains the value of a Smithy Node, as used in a JSON AST.
///
/// Smithy node data is basically the same as the data that can be stored in JSON.
/// The root of a Smithy node may be of any type, i.e. unlike JSON, the root element is not limited to object or list.
///
/// See the definition of node value in the Smithy spec: https://smithy.io/2.0/spec/model.html#node-values
enum ASTNode: Sendable {
case object([String: ASTNode])
case list([ASTNode])
case string(String)
case number(Double)
case boolean(Bool)
case null
}

extension ASTNode: Decodable {

init(from decoder: any Decoder) throws {
let container = try decoder.singleValueContainer()
if container.decodeNil() {
self = .null
} else if let bool = try? container.decode(Bool.self) {
self = .boolean(bool)
} else if let int = try? container.decode(Int.self) {
self = .number(Double(int))
} else if let double = try? container.decode(Double.self) {
self = .number(double)
} else if let string = try? container.decode(String.self) {
self = .string(string)
} else if let array = try? container.decode([ASTNode].self) {
self = .list(array)
} else if let dictionary = try? container.decode([String: ASTNode].self) {
self = .object(dictionary)
} else {
throw ASTError("Undecodable value in AST node")
}
}
}
10 changes: 10 additions & 0 deletions Sources/SmithyCodegenCore/AST/ASTReference.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

struct ASTReference: Decodable {
let target: String
}
31 changes: 31 additions & 0 deletions Sources/SmithyCodegenCore/AST/ASTShape.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

struct ASTShape: Decodable {
let type: ASTType
let traits: [String: ASTNode]?
let member: ASTMember?
let key: ASTMember?
let value: ASTMember?
let members: [String: ASTMember]?
let version: String?
let operations: [ASTReference]?
let resources: [ASTReference]?
let errors: [ASTReference]?
let rename: [String: String]?
let identifiers: [String: ASTReference]?
let properties: [String: ASTReference]?
let create: ASTReference?
let put: ASTReference?
let read: ASTReference?
let update: ASTReference?
let delete: ASTReference?
let list: ASTReference?
let collectionOperations: [ASTReference]?
let input: ASTReference?
let output: ASTReference?
}
37 changes: 37 additions & 0 deletions Sources/SmithyCodegenCore/AST/ASTType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

enum ASTType: String, Decodable {
// These cases are all the Smithy shape types
case blob
case boolean
case string
case timestamp
case byte
case short
case integer
case long
case float
case document
case double
case bigDecimal
case bigInteger
case `enum`
case intEnum
case list
case set
case map
case structure
case union
case member
case service
case resource
case operation

// Special for AST, added 'apply' case
case apply
}
30 changes: 30 additions & 0 deletions Sources/SmithyCodegenCore/CodeGenerator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import struct Foundation.Data
import struct Foundation.URL

public struct CodeGenerator {
let modelFileURL: URL
let schemasFileURL: URL?

public init(modelFileURL: URL, schemasFileURL: URL?) {
self.modelFileURL = modelFileURL
self.schemasFileURL = schemasFileURL
}

public func run() throws {
// Load the model from the model file
let model = try Model(modelFileURL: modelFileURL)

// If a schema file URL was provided, generate it
if let schemasFileURL {
let schemaContents = try SmithySchemaCodegen().generate(model: model)
try Data(schemaContents.utf8).write(to: schemasFileURL)
}
}
}
14 changes: 14 additions & 0 deletions Sources/SmithyCodegenCore/CodegenError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

struct CodegenError: Error {
let localizedDescription: String

init(_ localizedDescription: String) {
self.localizedDescription = localizedDescription
}
}
87 changes: 87 additions & 0 deletions Sources/SmithyCodegenCore/Model/Model.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import struct Foundation.Data
import class Foundation.JSONDecoder
import struct Foundation.URL

public class Model {
public let version: String
public let metadata: Node?
public let shapes: [ShapeID: Shape]

public convenience init(modelFileURL: URL) throws {
let modelData = try Data(contentsOf: modelFileURL)
let astModel = try JSONDecoder().decode(ASTModel.self, from: modelData)
try self.init(astModel: astModel)
}

init(astModel: ASTModel) throws {
self.version = astModel.smithy
self.metadata = astModel.metadata?.modelNode
let idToShapePairs = try astModel.shapes.map { try Self.shapePair(id: $0.key, astShape: $0.value) }
let idToMemberShapePairs = try astModel.shapes.flatMap { astShape in
try Self.memberShapePairs(id: astShape.key, astShape: astShape.value)
}
self.shapes = Dictionary(uniqueKeysWithValues: idToShapePairs + idToMemberShapePairs)

// self is now initialized, perform post-initialization wireup

// set the Shapes with references back to this model
self.shapes.values.forEach { $0.model = self }

// set the memberIDs for each Shape
self.shapes.values.filter { $0.type != .member }.forEach { shape in
let namespace = shape.id.namespace
let name = shape.id.name
let memberIDs: [ShapeID] = Array(self.shapes.keys)
let filteredMemberIDs = memberIDs.filter {
$0.namespace == namespace && $0.name == name && $0.member != nil
}
shape.memberIDs = filteredMemberIDs.sorted()
}
}

private static func shapePair(id: String, astShape: ASTShape) throws -> (ShapeID, Shape) {
let shapeID = try ShapeID(id)
let idToTraitPairs = try astShape.traits?.map { (try ShapeID($0.key), $0.value.modelNode) } ?? []
let shape = Shape(
id: shapeID,
type: astShape.type.modelType,
traits: Dictionary(uniqueKeysWithValues: idToTraitPairs),
targetID: nil
)
return (shapeID, shape)
}

private static func memberShapePairs(id: String, astShape: ASTShape) throws -> [(ShapeID, Shape)] {
var baseMembers = (astShape.members ?? [:])
if let member = astShape.member {
baseMembers["member"] = member
}
if let key = astShape.key {
baseMembers["key"] = key
}
if let value = astShape.value {
baseMembers["value"] = value
}
return try baseMembers.map { astMember in
let memberID = ShapeID(id: try ShapeID(id), member: astMember.key)
let traitPairs = try astMember.value.traits?.map { (try ShapeID($0.key), $0.value.modelNode) }
let traits = Dictionary(uniqueKeysWithValues: traitPairs ?? [])
let targetID = try ShapeID(astMember.value.target)
return (memberID, Shape(id: memberID, type: .member, traits: traits, targetID: targetID))
}
}

func expectShape(id: ShapeID) throws -> Shape {
guard let shape = shapes[id] else {
throw ModelError("ShapeID \(id) was expected in model but not found")
}
return shape
}
}
14 changes: 14 additions & 0 deletions Sources/SmithyCodegenCore/Model/ModelError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

public struct ModelError: Error {
public let localizedDescription: String

init(_ localizedDescription: String) {
self.localizedDescription = localizedDescription
}
}
Loading
Loading