Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,10 @@ let package = Package(
]
),
.target(
name: "SmithyCodegenCore"
name: "SmithyCodegenCore",
dependencies: [
"Smithy",
]
),
.testTarget(
name: "ClientRuntimeTests",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import protocol SmithyHTTPAuthAPI.AuthSchemeResolver
import protocol SmithyHTTPAuthAPI.AuthSchemeResolverParameters
import struct SmithyRetries.DefaultRetryStrategy
import struct SmithyRetries.ExponentialBackoffStrategy
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swiftlint rearranged imports in a few files here & below.

import SmithyTelemetryAPI
import protocol SmithyRetriesAPI.RetryErrorInfoProvider
import protocol SmithyRetriesAPI.RetryStrategy
import struct SmithyRetriesAPI.RetryStrategyOptions
import SmithyTelemetryAPI

public struct DefaultSDKRuntimeConfiguration<DefaultSDKRuntimeRetryStrategy: RetryStrategy,
DefaultSDKRuntimeRetryErrorInfoProvider: RetryErrorInfoProvider> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import protocol SmithyHTTPAPI.HTTPClient
import class SmithyHTTPAPI.HTTPRequest
import class SmithyHTTPAPI.HTTPResponse
import enum SmithyHTTPAPI.HTTPStatusCode
import class SmithyHTTPClientAPI.HttpTelemetry
import enum SmithyHTTPClientAPI.HttpMetricsAttributesKeys
import class SmithyHTTPClientAPI.HttpTelemetry
import class SmithyStreams.BufferedStream
import SmithyTelemetryAPI
#if os(Linux)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import AwsCommonRuntimeKit
import struct Smithy.Attributes
import enum Smithy.ByteStream
import class SmithyHTTPClientAPI.HttpTelemetry
import enum SmithyHTTPClientAPI.HttpMetricsAttributesKeys
import class SmithyHTTPClientAPI.HttpTelemetry

extension HTTP2Stream {
/// Returns the recommended size, in bytes, for the data to write
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import class Foundation.DispatchQueue
import class Foundation.InputStream
import class Foundation.NSObject
import class Foundation.OutputStream
import class SmithyHTTPClientAPI.HttpTelemetry
import enum SmithyHTTPClientAPI.HttpMetricsAttributesKeys
import class Foundation.RunLoop
import class Foundation.Stream
import protocol Foundation.StreamDelegate
Expand All @@ -24,6 +22,8 @@ import class Foundation.Timer
import struct Smithy.Attributes
import protocol Smithy.LogAgent
import protocol Smithy.ReadableStream
import enum SmithyHTTPClientAPI.HttpMetricsAttributesKeys
import class SmithyHTTPClientAPI.HttpTelemetry

/// Reads data from a smithy-swift native `ReadableStream` and streams the data through to a Foundation `InputStream`.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import class Foundation.NSRecursiveLock
import var Foundation.NSURLAuthenticationMethodClientCertificate
import var Foundation.NSURLAuthenticationMethodServerTrust
import struct Foundation.TimeInterval
import class SmithyHTTPClientAPI.HttpTelemetry
import enum SmithyHTTPClientAPI.HttpMetricsAttributesKeys
import class Foundation.URLAuthenticationChallenge
import struct Foundation.URLComponents
import class Foundation.URLCredential
Expand All @@ -29,7 +27,6 @@ import class Foundation.URLResponse
import class Foundation.URLSession
import class Foundation.URLSessionConfiguration
import protocol Foundation.URLSessionDataDelegate
import SmithyTelemetryAPI
import class Foundation.URLSessionDataTask
import class Foundation.URLSessionTask
import class Foundation.URLSessionTaskMetrics
Expand All @@ -44,7 +41,10 @@ import protocol SmithyHTTPAPI.HTTPClient
import class SmithyHTTPAPI.HTTPRequest
import class SmithyHTTPAPI.HTTPResponse
import enum SmithyHTTPAPI.HTTPStatusCode
import enum SmithyHTTPClientAPI.HttpMetricsAttributesKeys
import class SmithyHTTPClientAPI.HttpTelemetry
import class SmithyStreams.BufferedStream
import SmithyTelemetryAPI

/// A client that can be used to make requests to AWS services using `Foundation`'s `URLSession` HTTP client.
///
Expand Down
62 changes: 55 additions & 7 deletions Sources/Smithy/Schema/ShapeID.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
// SPDX-License-Identifier: Apache-2.0
//

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ShapeID has added methods for creating IDs from the string identifiers in AST, and for allowing sort-by-ShapeID.

/// Represents a single Smithy shape ID.
/// Represents a Smithy shape ID.
///
/// The id that ShapeID is created from is presumed to be properly formed, since this type will usually
/// be constructed from previously validated models.
///
/// Shape ID is described in the Smithy 2.0 spec [here](https://smithy.io/2.0/spec/model.html#shape-id).
public struct ShapeID: Sendable, Hashable {
public struct ShapeID: Hashable, Sendable {
public let namespace: String
public let name: String
public let member: String?
Expand All @@ -27,16 +30,61 @@ public struct ShapeID: Sendable, Hashable {
self.name = name
self.member = member
}
}

extension ShapeID: CustomStringConvertible {
public init(_ id: String) throws {
let splitOnPound = id.split(separator: "#")
guard splitOnPound.count == 2 else {
throw ShapeIDError("id \"\(id)\" does not have a #")
}
guard let namespace = splitOnPound.first, !namespace.isEmpty else {
throw ShapeIDError("id \"\(id)\" does not have a nonempty namespace")
}
self.namespace = String(namespace)
let splitOnDollar = splitOnPound.last!.split(separator: "$")
switch splitOnDollar.count {
case 2:
self.name = String(splitOnDollar.first!)
self.member = String(splitOnDollar.last!)
case 1:
self.name = String(splitOnDollar.first!)
self.member = nil
default:
throw ShapeIDError("id \"\(id)\" has more than one $")
}
}

/// Returns the absolute Shape ID in a single, printable string.
public var description: String {
if let member = self.member {
public init(id: ShapeID, member: String) {
self.namespace = id.namespace
self.name = id.name
self.member = member
}

public var id: String {
if let member {
return "\(namespace)#\(name)$\(member)"
} else {
return "\(namespace)#\(name)"
}
}
}

extension ShapeID: Comparable {

public static func < (lhs: ShapeID, rhs: ShapeID) -> Bool {
return lhs.id.lowercased() < rhs.id.lowercased()
}
}

extension ShapeID: CustomStringConvertible {

/// Returns the absolute Shape ID in a single, printable string.
public var description: String { id }
}

public struct ShapeIDError: Error {
public let localizedDescription: String

init(_ localizedDescription: String) {
self.localizedDescription = localizedDescription
}
}
File renamed without changes.
4 changes: 3 additions & 1 deletion Sources/SmithyCodegenCore/AST/ASTMember.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
// SPDX-License-Identifier: Apache-2.0
//

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ASTNode has been replaced by Smithy.Node since the two types were identical.
The change is made here & in several other AST types below.

import enum Smithy.Node

// See https://smithy.io/2.0/spec/json-ast.html#ast-member
struct ASTMember: Decodable {
let target: String
let traits: [String: ASTNode]?
let traits: [String: Node]?
}
4 changes: 3 additions & 1 deletion Sources/SmithyCodegenCore/AST/ASTModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
// SPDX-License-Identifier: Apache-2.0
//

import enum Smithy.Node

// See https://smithy.io/2.0/spec/json-ast.html#top-level-properties
struct ASTModel: Decodable {
let smithy: String
let metadata: ASTNode?
let metadata: Node?
let shapes: [String: ASTShape]
}
4 changes: 3 additions & 1 deletion Sources/SmithyCodegenCore/AST/ASTShape.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
// SPDX-License-Identifier: Apache-2.0
//

import enum Smithy.Node

// See https://smithy.io/2.0/spec/json-ast.html#json-ast
// This Swift type captures fields for all AST shape types
struct ASTShape: Decodable {
let type: ASTType
let traits: [String: ASTNode]?
let traits: [String: Node]?
let member: ASTMember?
let key: ASTMember?
let value: ASTMember?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,11 @@
// 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 {
case object([String: ASTNode])
case list([ASTNode])
case string(String)
case number(Double)
case boolean(Bool)
case null
}
import enum Smithy.Node
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ASTNode is deleted & Smithy.Node is used instead.

The Decodable extension below is applied to Smithy.Node instead of to ASTNode.


extension ASTNode: Decodable {
extension Node: Decodable {

init(from decoder: any Decoder) throws {
public init(from decoder: any Decoder) throws {
let container = try decoder.singleValueContainer()
if container.decodeNil() {
self = .null
Expand All @@ -34,9 +21,9 @@ extension ASTNode: Decodable {
self = .number(double)
} else if let string = try? container.decode(String.self) {
self = .string(string)
} else if let array = try? container.decode([ASTNode].self) {
} else if let array = try? container.decode([Node].self) {
self = .list(array)
} else if let dictionary = try? container.decode([String: ASTNode].self) {
} else if let dictionary = try? container.decode([String: Node].self) {
self = .object(dictionary)
} else {
throw ASTError("Undecodable value in AST node")
Expand Down
10 changes: 8 additions & 2 deletions Sources/SmithyCodegenCore/CodeGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,14 @@ public struct CodeGenerator {
let modelData = try Data(contentsOf: modelFileURL)
let astModel = try JSONDecoder().decode(ASTModel.self, from: modelData)

// In the future, AST will be used to create a Model.
// Model will be used to generate code.
// Create the model from the AST
let model = try Model(astModel: astModel)

// Create a generation context from the model
_ = try GenerationContext(model: model)

// Generation context will be used here in the future
// to generate needed files.

// This code simply writes an empty schemas file, since it is expected to exist after the
// code generator plugin runs.
Expand Down
27 changes: 27 additions & 0 deletions Sources/SmithyCodegenCore/GenerationContext.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

public struct GenerationContext {
public let service: ServiceShape
public let model: Model
public let symbolProvider: SymbolProvider

/// Creates a ``GenerationContext`` from a model.
///
/// The model must contain exactly one service.
/// - Parameter model: The ``Model`` to create the generation context from.
/// - Throws: ``ModelError`` if the model does not contain exactly one service.
init(model: Model) throws {
let services = model.shapes.values.filter { $0.type == .service }
guard services.count == 1, let service = services.first as? ServiceShape else {
throw ModelError("Model contains \(services.count) services")
}
self.service = service
self.model = model
self.symbolProvider = SymbolProvider(service: service, model: model)
}
}
Loading