Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
3e4f833
Disable input/output serializers
jbelkins Nov 4, 2025
12155d2
add ShapeID, doc comments
jbelkins Nov 5, 2025
6e2519b
Re-enable serde code
jbelkins Nov 5, 2025
c32b39b
Cleanup
jbelkins Nov 5, 2025
21ed6f7
feat: Create code generator plugin
jbelkins Nov 15, 2025
4ddfc98
Fix swiftlint
jbelkins Nov 15, 2025
c57b182
Remove code generator reference
jbelkins Nov 15, 2025
9bd4df2
Remove import
jbelkins Nov 15, 2025
f1ef4e8
Create empty Schemas swift file
jbelkins Nov 15, 2025
a64b53b
feat: Create code generator build tool plugin (#999)
aws-sdk-swift-automation Nov 19, 2025
a49d811
Merge branch 'main' into epic/sbs
jbelkins Nov 19, 2025
38868fa
Merge branch 'main' into epic/sbs
jbelkins Nov 22, 2025
a8beafe
Merge branch 'main' into epic/sbs
jbelkins Nov 26, 2025
8ad618c
Merge branch 'main' into epic/sbs
jbelkins Dec 9, 2025
3b08352
Merge branch 'main' into epic/sbs
jbelkins Dec 12, 2025
e2ded31
feat: Read JSON AST models into memory
jbelkins Dec 12, 2025
f979613
Fix trailing comma
jbelkins Dec 12, 2025
d5a2766
re-add blank schemas file
jbelkins Dec 12, 2025
514b911
feat: Read JSON AST models into memory (#1010)
jbelkins Dec 15, 2025
e59b27e
feat: Add generation context
jbelkins Dec 17, 2025
f9f6d0d
revert schema
jbelkins Dec 17, 2025
268c952
Fix lint
jbelkins Dec 17, 2025
d89742a
Mode ShapeID
jbelkins Dec 17, 2025
b60eebc
feat: Add generation context (#1011)
jbelkins Dec 22, 2025
2089201
Merge branch 'main' into epic/sbs
jbelkins Jan 1, 2026
f8aca97
Merge branch 'main' into epic/sbs
jbelkins Jan 19, 2026
ed8cc78
Add full-featured code generator
jbelkins Jan 19, 2026
52adbb5
Fix tests, remove unneeded code
jbelkins Jan 20, 2026
1483b46
Fix Swift 6 build
jbelkins Jan 20, 2026
e796292
Restore SmithyCBOR dependencies
jbelkins Jan 20, 2026
676d306
Comments and code cleanup
jbelkins Jan 23, 2026
a8e69ec
Fix swiftlint
jbelkins Jan 26, 2026
e38779a
chore: Rename codegen plugin (#1019)
jbelkins Feb 2, 2026
34e8709
Merge branch 'epic/sbs' into jbe/codegen_core
jbelkins Feb 2, 2026
a38fa1f
feat: Add full-featured code generator (#1016)
aws-sdk-swift-automation Feb 2, 2026
2c9fc39
Merge branch 'main' into epic/sbs
jbelkins Feb 3, 2026
c97fe75
feat: Serialization & deserialization interfaces & codegen
jbelkins Feb 3, 2026
ba5e6a8
Merge branch 'main' into jbe/serde_interfaces_and_codegen
jbelkins Feb 3, 2026
f46e7cb
Bring in more codegen files
jbelkins Feb 3, 2026
4de9d57
Merge branch 'main' into epic/sbs
jbelkins Feb 3, 2026
44cf4d2
Merge branch 'epic/sbs' into jbe/serde_interfaces_and_codegen
jbelkins Feb 3, 2026
9f04f59
fix SmithyCodegenCore tests
jbelkins Feb 3, 2026
7def323
Fix generated code
jbelkins Feb 4, 2026
2877e41
Merge branch 'main' into epic/sbs
jbelkins Feb 9, 2026
4c19901
Merge branch 'main' into epic/sbs
jbelkins Feb 11, 2026
beccc43
Merge branch 'main' into epic/sbs
jbelkins Feb 12, 2026
6e19919
Merge branch 'main' into epic/sbs
jbelkins Feb 16, 2026
4e3ea80
Fix ktlint
jbelkins Feb 16, 2026
8dd4d8c
Merge branch 'main' into epic/sbs
jbelkins Feb 20, 2026
58db8db
Merge branch 'epic/sbs' into jbe/serde_interfaces_and_codegen
jbelkins Feb 20, 2026
b51a546
Pin swift-argument-parser
jbelkins Feb 20, 2026
6e8ee22
feat: Serialization interfaces and codegen (#1021)
jbelkins Feb 20, 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
36 changes: 36 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,12 @@ let package = Package(
.library(name: "SmithySwiftNIO", targets: ["SmithySwiftNIO"]),
.library(name: "SmithyTelemetryAPI", targets: ["SmithyTelemetryAPI"]),
.library(name: "SmithyHTTPClientAPI", targets: ["SmithyHTTPClientAPI"]),
.plugin(name: "SmithyCodeGeneratorPlugin", targets: ["SmithyCodeGeneratorPlugin"]),
],
dependencies: {
var dependencies: [Package.Dependency] = [
.package(url: "https://github.com/awslabs/aws-crt-swift.git", exact: "0.58.0"),
.package(url: "https://github.com/apple/swift-argument-parser.git", exact: "1.6.2"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.0.0"),
.package(url: "https://github.com/open-telemetry/opentelemetry-swift", from: "1.13.0"),
.package(url: "https://github.com/swift-server/async-http-client.git", from: "1.22.0"),
Expand Down Expand Up @@ -119,6 +121,7 @@ let package = Package(
"SmithyChecksumsAPI",
"SmithyChecksums",
"SmithyCBOR",
"SmithySerialization",
.product(name: "AwsCommonRuntimeKit", package: "aws-crt-swift"),
// Only include these on macOS, iOS, tvOS, watchOS, and macCatalyst (visionOS and Linux are excluded)
.product(
Expand Down Expand Up @@ -285,12 +288,36 @@ let package = Package(
dependencies: [
"SmithyReadWrite",
"SmithyTimestamps",
"Smithy",
"SmithySerialization",
.product(name: "AwsCommonRuntimeKit", package: "aws-crt-swift")
]
),
.target(
name: "SmithyWaitersAPI"
),
.plugin(
name: "SmithyCodeGeneratorPlugin",
capability: .buildTool(),
dependencies: [
"SmithyCodegenCLI",
]
),
.executableTarget(
name: "SmithyCodegenCLI",
dependencies: [
"SmithyCodegenCore",
.product(name: "ArgumentParser", package: "swift-argument-parser"),
]
),
.target(
name: "SmithyCodegenCore",
dependencies: [
"Smithy",
"SmithySerialization",
],
resources: [ .process("Resources") ]
),
.testTarget(
name: "ClientRuntimeTests",
dependencies: [
Expand All @@ -301,6 +328,10 @@ let package = Package(
],
resources: [ .process("Resources") ]
),
.testTarget(
name: "SmithyTests",
dependencies: ["Smithy"]
),
.testTarget(
name: "SmithySwiftNIOTests",
dependencies: [
Expand Down Expand Up @@ -374,5 +405,10 @@ let package = Package(
name: "SmithyStreamsTests",
dependencies: ["SmithyStreams", "Smithy"]
),
.testTarget(
name: "SmithyCodegenCoreTests",
dependencies: ["SmithyCodegenCore"],
resources: [ .process("Resources") ]
),
].compactMap { $0 }
)
92 changes: 92 additions & 0 deletions Plugins/SmithyCodeGeneratorPlugin/SmithyCodeGeneratorPlugin.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

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

@main
struct SmithyCodeGeneratorPlugin: BuildToolPlugin {

func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] {
// This plugin only runs for package targets that can have source files.
guard let sourceFiles = target.sourceModule?.sourceFiles else { return [] }

// Retrieve the `SmithyCodegenCLI` tool from the plugin's tools.
let smithyCodegenCLITool = try context.tool(named: "SmithyCodegenCLI")

// Construct a build command for each source file with a particular suffix.
return try sourceFiles.map(\.path).compactMap {
try createBuildCommand(
name: target.name,
for: $0,
in: context.pluginWorkDirectory,
with: smithyCodegenCLITool.path
)
}
}

private func createBuildCommand(
name: String,
for inputPath: Path,
in outputDirectoryPath: Path,
with generatorToolPath: Path
) throws -> Command? {
// Skip any file that isn't the smithy-model-info.json for this service.
guard inputPath.lastComponent == "smithy-model-info.json" else { return nil }

let currentWorkingDirectoryFileURL = URL(fileURLWithPath: FileManager.default.currentDirectoryPath)

// Get the smithy-model-info.json file contents.
let modelInfoData = try Data(contentsOf: URL(fileURLWithPath: inputPath.string))
let smithyModelInfo = try JSONDecoder().decode(SmithyModelInfo.self, from: modelInfoData)

// Get the service ID & model path & settings sdkId from smithy-model-info.
let service = smithyModelInfo.service
let modelPathURL = currentWorkingDirectoryFileURL.appendingPathComponent(smithyModelInfo.path)
let modelPath = Path(modelPathURL.path)

// Construct the Schemas.swift path.
let schemasSwiftPath = outputDirectoryPath.appending("\(name)Schemas.swift")

// Construct the Serialize.swift path.
let serializeSwiftPath = outputDirectoryPath.appending("\(name)Serialize.swift")

// Construct the Deserialize.swift path.
let deserializeSwiftPath = outputDirectoryPath.appending("\(name)Deserialize.swift")

// Construct the build command that invokes SmithyCodegenCLI.
return .buildCommand(
displayName: "Generating Swift source files from model file \(smithyModelInfo.path)",
executable: generatorToolPath,
arguments: [
service,
modelPath,
"--schemas-path", schemasSwiftPath,
"--serialize-path", serializeSwiftPath,
"--deserialize-path", deserializeSwiftPath
],
inputFiles: [inputPath, modelPath],
outputFiles: [
schemasSwiftPath,
serializeSwiftPath,
deserializeSwiftPath,
]
)
}
}

/// Codable structure for reading the contents of `smithy-model-info.json`
private struct SmithyModelInfo: Decodable {
/// The shape ID of the service being generated. Must exist in the model.
let service: String

/// The path to the model, from the root of the target's project. Required.
let path: String
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
@_spi(SmithyDocumentImpl)
public struct BigIntegerDocument: SmithyDocument {
public var type: ShapeType { .bigInteger }
let value: Int
let value: Int64

public init(value: Int) {
public init(value: Int64) {
self.value = value
}

Expand All @@ -29,7 +29,7 @@ public struct BigIntegerDocument: SmithyDocument {
}

public func asInteger() throws -> Int {
value
Int(value)
}

public func asLong() throws -> Int64 {
Expand All @@ -45,7 +45,7 @@ public struct BigIntegerDocument: SmithyDocument {
}

public func asBigInteger() throws -> Int64 {
Int64(value)
value
}

public func asBigDecimal() throws -> Double {
Expand Down
109 changes: 109 additions & 0 deletions Sources/Smithy/Node.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

/// Contains the value of a Smithy Node.
///
/// 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
public enum Node: Sendable, Hashable {
case object([String: Node])
case list([Node])
case string(String)
case number(Double)
case boolean(Bool)
case null
}

public extension Node {

/// Returns the object dictionary if this Node is `.object`, else returns `nil`.
var object: [String: Node]? {
guard case .object(let value) = self else { return nil }
return value
}

/// Returns the array of `Node` if this node is `.list`, else returns `nil`.
var list: [Node]? {
guard case .list(let value) = self else { return nil }
return value
}

/// Returns the string if this node is `.string`, else returns `nil`.
var string: String? {
guard case .string(let value) = self else { return nil }
return value
}

/// Returns the Double if this node is `.number`, else returns `nil`.
var number: Double? {
guard case .number(let value) = self else { return nil }
return value
}

/// Returns the `Bool` value if this node is `.boolean`, else returns `nil`.
var boolean: Bool? {
guard case .boolean(let value) = self else { return nil }
return value
}

/// Returns `true` if this node is `.null`, else returns `false`.
var null: Bool {
guard case .null = self else { return false }
return true
}
}

extension Node: ExpressibleByDictionaryLiteral {

public init(dictionaryLiteral elements: (String, Node)...) {
self = .object(Dictionary(uniqueKeysWithValues: elements))
}
}

extension Node: ExpressibleByArrayLiteral {

public init(arrayLiteral elements: Node...) {
self = .list(elements)
}
}

extension Node: ExpressibleByStringLiteral {

public init(stringLiteral value: String) {
self = .string(value)
}
}

extension Node: ExpressibleByIntegerLiteral {

public init(integerLiteral value: IntegerLiteralType) {
self = .number(Double(value))
}
}

extension Node: ExpressibleByFloatLiteral {

public init(floatLiteral value: FloatLiteralType) {
self = .number(Double(value))
}
}

extension Node: ExpressibleByBooleanLiteral {

public init(booleanLiteral value: BooleanLiteralType) {
self = .boolean(value)
}
}

extension Node: ExpressibleByNilLiteral {

public init(nilLiteral: ()) {
self = .null
}
}
Loading
Loading