-
Notifications
You must be signed in to change notification settings - Fork 35
feat: Read JSON AST models into memory #1010
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||
| // | ||
|
|
||
|
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 error just get thrown with an appropriate message if there is an error while reading an AST. |
||
| public struct ASTError: Error { | ||
| public let localizedDescription: String | ||
|
|
||
| init(_ localizedDescription: String) { | ||
| self.localizedDescription = localizedDescription | ||
| } | ||
| } | ||
| 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 | ||
| // | ||
|
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 and the below |
||
|
|
||
| // See https://smithy.io/2.0/spec/json-ast.html#ast-member | ||
| struct ASTMember: Decodable { | ||
| let target: String | ||
| let traits: [String: ASTNode]? | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| // | ||
| // Copyright Amazon.com Inc. or its affiliates. | ||
| // All Rights Reserved. | ||
| // | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
|
|
||
| // See https://smithy.io/2.0/spec/json-ast.html#top-level-properties | ||
| struct ASTModel: Decodable { | ||
| let smithy: String | ||
| let metadata: ASTNode? | ||
| let shapes: [String: ASTShape] | ||
| } |
| 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 { | ||
| case object([String: ASTNode]) | ||
| case list([ASTNode]) | ||
| case string(String) | ||
| case number(Double) | ||
| case boolean(Bool) | ||
| case null | ||
| } | ||
|
|
||
|
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. Because a node in AST can be of multiple JSON types, the hand-written |
||
| 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") | ||
| } | ||
| } | ||
| } | ||
| 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 | ||
| // | ||
|
|
||
| // See https://smithy.io/2.0/spec/json-ast.html#ast-shape-reference | ||
| struct ASTReference: Decodable { | ||
| let target: String | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| // | ||
| // 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. Rather than have multiple AST shape types, for simplicity all AST shapes are read with this one ASTShape type that has all the fields of every AST shape. When constructing the actual model from AST later, the ASTShape's |
||
|
|
||
| // 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 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? | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| // | ||
| // Copyright Amazon.com Inc. or its affiliates. | ||
| // All Rights Reserved. | ||
| // | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
|
|
||
| // See https://smithy.io/2.0/spec/model.html#shape-types | ||
| enum ASTType: String, Decodable { | ||
| // These cases are all the standard 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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| // | ||
| // 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 | ||
|
|
||
|
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 is created & called by the CLI to actually perform the codegen. Its responsibilities
For now, it just creates an empty file at the schemas path, which is required for the build plugin to succeed. |
||
| 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 AST from the model file | ||
| let modelData = try Data(contentsOf: modelFileURL) | ||
| let astModel = try JSONDecoder().decode(ASTModel.self, from: modelData) | ||
|
Check warning on line 28 in Sources/SmithyCodegenCore/CodeGenerator.swift
|
||
|
Contributor
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. It does look like astModel is never used as mentioned by the automated warning. What is it for?
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. See the comments immediately below. In a follow-up PR, |
||
|
|
||
| // In the future, AST will be used to create a Model. | ||
| // Model will be used to generate code. | ||
|
|
||
| // This code simply writes an empty schemas file, since it is expected to exist after the | ||
| // code generator plugin runs. | ||
| // | ||
| // Actual code generation will be implemented here later. | ||
| if let schemasFileURL { | ||
| FileManager.default.createFile(atPath: schemasFileURL.path, contents: Data()) | ||
| } | ||
| } | ||
| } | ||
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.
Created this target for codegen components.
Eventually this may be exposed as a library, but for now it's solely a
smithy-swiftinternal target.