-
Notifications
You must be signed in to change notification settings - Fork 35
feat: Add schema + code generation #989
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 2 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
495f2e1
Disable input/output serializers
jbelkins ca5b331
add ShapeID, doc comments
jbelkins 212120e
Re-enable serde code
jbelkins fcdf1bf
Cleanup
jbelkins b2152c2
Merge branch 'main' into jbe/add_schema
jbelkins 88f7be9
Merge branch 'main' into jbe/add_schema
jbelkins File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | ||
| // | ||
|
|
||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This type holds the actual content of a trait. |
||
| /// 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 { | ||
| 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 | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| // | ||
| // Copyright Amazon.com Inc. or its affiliates. | ||
| // All Rights Reserved. | ||
| // | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
|
|
||
| // Below are schemas for all model shapes defined in the Smithy 2.0 prelude. | ||
| // Schemas for custom Smithy types may use these schemas in their definitions. | ||
|
|
||
| public enum Prelude { | ||
|
|
||
| public static var unitSchema: Schema { | ||
| Schema(id: .init("smithy.api", "Unit"), type: .structure) | ||
| } | ||
|
|
||
| public static var booleanSchema: Schema { | ||
| Schema(id: .init("smithy.api", "Boolean"), type: .boolean) | ||
| } | ||
|
|
||
| public static var stringSchema: Schema { | ||
| Schema(id: .init("smithy.api", "String"), type: .string) | ||
| } | ||
|
|
||
| public static var integerSchema: Schema { | ||
| Schema(id: .init("smithy.api", "Integer"), type: .integer) | ||
| } | ||
|
|
||
| public static var blobSchema: Schema { | ||
| Schema(id: .init("smithy.api", "Blob"), type: .blob) | ||
| } | ||
|
|
||
| public static var timestampSchema: Schema { | ||
| Schema(id: .init("smithy.api", "Timestamp"), type: .timestamp) | ||
| } | ||
|
|
||
| public static var byteSchema: Schema { | ||
| Schema(id: .init("smithy.api", "Byte"), type: .byte) | ||
| } | ||
|
|
||
| public static var shortSchema: Schema { | ||
| Schema(id: .init("smithy.api", "Short"), type: .short) | ||
| } | ||
|
|
||
| public static var longSchema: Schema { | ||
| Schema(id: .init("smithy.api", "Long"), type: .long) | ||
| } | ||
|
|
||
| public static var floatSchema: Schema { | ||
| Schema(id: .init("smithy.api", "Float"), type: .float) | ||
| } | ||
|
|
||
| public static var doubleSchema: Schema { | ||
| Schema(id: .init("smithy.api", "Double"), type: .double) | ||
| } | ||
|
|
||
| public static var documentSchema: Schema { | ||
| Schema(id: .init("smithy.api", "PrimitiveDocument"), type: .document) | ||
| } | ||
|
|
||
| public static var primitiveBooleanSchema: Schema { | ||
| Schema(id: .init("smithy.api", "PrimitiveBoolean"), type: .boolean, traits: [defaultTraitID: false]) | ||
| } | ||
|
|
||
| public static var primitiveIntegerSchema: Schema { | ||
| Schema(id: .init("smithy.api", "PrimitiveInteger"), type: .integer, traits: [defaultTraitID: 0]) | ||
| } | ||
|
|
||
| public static var primitiveByteSchema: Schema { | ||
| Schema(id: .init("smithy.api", "PrimitiveByte"), type: .byte, traits: [defaultTraitID: 0]) | ||
| } | ||
|
|
||
| public static var primitiveShortSchema: Schema { | ||
| Schema(id: .init("smithy.api", "PrimitiveShort"), type: .short, traits: [defaultTraitID: 0]) | ||
| } | ||
|
|
||
| public static var primitiveLongSchema: Schema { | ||
| Schema(id: .init("smithy.api", "PrimitiveLong"), type: .long, traits: [defaultTraitID: 0]) | ||
| } | ||
|
|
||
| public static var primitiveFloatSchema: Schema { | ||
| Schema(id: .init("smithy.api", "PrimitiveFloat"), type: .float, traits: [defaultTraitID: 0]) | ||
| } | ||
|
|
||
| public static var primitiveDoubleSchema: Schema { | ||
| Schema(id: .init("smithy.api", "PrimitiveDouble"), type: .double, traits: [defaultTraitID: 0]) | ||
| } | ||
| } | ||
|
|
||
| private let defaultTraitID = ShapeID("smithy.api", "default") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| // | ||
| // Copyright Amazon.com Inc. or its affiliates. | ||
| // All Rights Reserved. | ||
| // | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
|
|
||
| /// A structure which describes selected Smithy model information for a Smithy model shape. | ||
| /// | ||
| /// Typically, the Schema contains only modeled info & properties that are relevant to | ||
| /// serialization, transport bindings, and other functions performed by the SDK. | ||
| public class Schema { | ||
|
|
||
| /// The Smithy shape ID for the shape described by this schema. | ||
| public let id: ShapeID | ||
|
|
||
| /// The type of the shape being described. | ||
| public let type: ShapeType | ||
|
|
||
| /// A dictionary of the described shape's trait shape IDs to Nodes with trait data. | ||
| /// | ||
| /// Not all traits for a shape will be represented in the schema; | ||
| /// typically the Schema contains only the traits relevant to the client-side SDK. | ||
| public let traits: [ShapeID: Node] | ||
|
|
||
| /// The member schemas for this schema, if any. | ||
| /// | ||
| /// Typically only a schema of type Structure, Union, Enum, IntEnum, List or Map will have members. | ||
| public let members: [Schema] | ||
|
|
||
| /// The target schema for this schema. Will only be used when this is a member schema. | ||
| public let target: Schema? | ||
|
|
||
| /// The index of this schema, if it represents a Smithy member. | ||
| /// | ||
| /// For a member schema, index will be set to its index in the members array. | ||
| /// For other types of schema, index will be `-1`. | ||
| /// | ||
| /// This index is intended for use as a performance enhancement when looking up member schemas | ||
| /// during deserialization. | ||
| public let index: Int | ||
|
|
||
| /// Creates a new Schema using the passed parameters. | ||
| /// | ||
| /// No validation is performed on the parameters since calls to this initializer | ||
| /// are almost always code-generated from a previously validated Smithy model. | ||
| public init( | ||
| id: ShapeID, | ||
| type: ShapeType, | ||
| traits: [ShapeID: Node] = [:], | ||
| members: [Schema] = [], | ||
| target: Schema? = nil, | ||
| index: Int = -1 | ||
| ) { | ||
| self.id = id | ||
| self.type = type | ||
| self.traits = traits | ||
| self.members = members | ||
| self.target = target | ||
| self.index = index | ||
| } | ||
| } | ||
|
|
||
| public extension Schema { | ||
|
|
||
| /// The member name for this schema, if any. | ||
| /// | ||
| /// Member name is computed from the schema's ID. | ||
| var memberName: String? { | ||
| id.member | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| // | ||
| // Copyright Amazon.com Inc. or its affiliates. | ||
| // All Rights Reserved. | ||
| // | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
|
|
||
| /// Represents a single Smithy shape ID. | ||
| /// | ||
| /// Shape ID is described in the Smithy 2.0 spec [here](https://smithy.io/2.0/spec/model.html#shape-id). | ||
| public struct ShapeID: Hashable { | ||
| public let namespace: String | ||
| public let name: String | ||
| public let member: String? | ||
|
|
||
| /// Creates a Shape ID for a Smithy shape. | ||
| /// | ||
| /// This initializer does no validation of length or of allowed characters in the Shape ID; | ||
| /// that is to be ensured by the caller (typically calls to this initializer will be code-generated | ||
| /// from previously validated Smithy models.) | ||
| /// - Parameters: | ||
| /// - namespace: The namespace for this shape, i.e. `smithy.api`. | ||
| /// - name: The name for this shape, i.e. `Integer`. | ||
| /// - member: The optional member name for this shape. | ||
| public init(_ namespace: String, _ name: String, _ member: String? = nil) { | ||
| self.namespace = namespace | ||
| self.name = name | ||
| self.member = member | ||
| } | ||
| } | ||
|
|
||
| extension ShapeID: CustomStringConvertible { | ||
|
|
||
| /// Returns the absolute Shape ID in a single, printable string. | ||
| public var description: String { | ||
| if let member = self.member { | ||
| return "\(namespace)#\(name)$\(member)" | ||
| } else { | ||
| return "\(namespace)#\(name)" | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| // | ||
| // Copyright Amazon.com Inc. or its affiliates. | ||
| // All Rights Reserved. | ||
| // | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
|
|
||
| import XCTest | ||
| import Smithy | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Simple test on ShapeID to ensure it renders to String properly. |
||
|
|
||
| class ShapeIDTests: XCTestCase { | ||
|
|
||
| func test_description_noMember() { | ||
| let subject = ShapeID("smithy.test", "TestShape") | ||
| XCTAssertEqual(subject.description, "smithy.test#TestShape") | ||
| } | ||
|
|
||
| func test_description_withMember() { | ||
| let subject = ShapeID("smithy.test", "TestShape", "TestMember") | ||
| XCTAssertEqual(subject.description, "smithy.test#TestShape$TestMember") | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a test target to the
Smithytarget since none previously existed.