diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/grain.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/grain.xcscheme index ea116bd..9291ddc 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/grain.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/grain.xcscheme @@ -93,6 +93,10 @@ + + diff --git a/Package.resolved b/Package.resolved index cdf10b9..ef8f64a 100644 --- a/Package.resolved +++ b/Package.resolved @@ -35,6 +35,15 @@ "revision" : "0b77e67c484e532444ceeab60119b8536f8cd648", "version" : "0.3.0" } + }, + { + "identity" : "yams", + "kind" : "remoteSourceControl", + "location" : "https://github.com/jpsim/Yams.git", + "state" : { + "revision" : "01835dc202670b5bb90d07f3eae41867e9ed29f6", + "version" : "5.0.1" + } } ], "version" : 2 diff --git a/Package.swift b/Package.swift index 1066ce8..ca416b8 100644 --- a/Package.swift +++ b/Package.swift @@ -19,12 +19,14 @@ let package = Package( dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser", from: "1.1.0"), .package(url: "https://github.com/apple/swift-tools-support-core.git", from: "0.2.7"), - .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.6.2") + .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.6.2"), + .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.1") ], targets: [ .target( name: "GrainDescriptor", dependencies: [ + "Yams", "Alamofire", .product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"), ], diff --git a/Sources/Fixture.swift b/Sources/Fixture.swift index 3055891..207a259 100644 --- a/Sources/Fixture.swift +++ b/Sources/Fixture.swift @@ -2,9 +2,9 @@ import GrainDescriptor import Foundation import Alamofire -let response = try await AF.request("https://httpbin.org/get").serializingString().value +//let response = try await AF.request("https://httpbin.org/get").serializingString().value -serialize { +serialize(.yaml) { GrainObject { GrainMember("data") { @@ -13,9 +13,9 @@ serialize { .init(name: "B", age: 2), ]) } - GrainMember("result") { - response - } +// GrainMember("result") { +// response +// } GrainMember("context") { context.filePath.pathString } diff --git a/Sources/Grain/CLI.swift b/Sources/Grain/CLI.swift index ce9777c..2fa464d 100644 --- a/Sources/Grain/CLI.swift +++ b/Sources/Grain/CLI.swift @@ -42,8 +42,9 @@ struct CLI: AsyncParsableCommand { } - @Argument var targetFilePaths: [String] + @Argument(completion: .directory) var targetFilePaths: [String] @Option(name: .customLong("output")) var outputDirectory: String? + @Option(help: "a parameter to inject json as Context") var userInfo: String? @Flag var verbose = false func run() async throws { @@ -59,7 +60,8 @@ struct CLI: AsyncParsableCommand { let context = GrainDescriptor.Context( filePath: path, - outputDir: outputDirectory.map { AbsolutePath($0, relativeTo: localFileSystem.currentWorkingDirectory!) } + outputDir: outputDirectory.map { AbsolutePath($0, relativeTo: localFileSystem.currentWorkingDirectory!) }, + userInfoString: userInfo ) try await self.render(path, context: context) diff --git a/Sources/GrainDescriptor/Entrypoint.swift b/Sources/GrainDescriptor/Entrypoint.swift index 07facbc..6fa4f78 100644 --- a/Sources/GrainDescriptor/Entrypoint.swift +++ b/Sources/GrainDescriptor/Entrypoint.swift @@ -2,7 +2,11 @@ import Alamofire @_implementationOnly import Darwin.C import Foundation import TSCBasic +import Yams +/** + The strategy to use serialization as `Data` + */ public struct Serialization { private let _encode: (any GrainView) throws -> Data @@ -43,6 +47,45 @@ public struct Serialization { ) } + + public static var plist: Self { + plist(outputFormat: .xml) + } + + public static func plist( + outputFormat: PropertyListSerialization.PropertyListFormat + ) -> Self { + + let encoder = PropertyListEncoder() + + return .init( + fileExtension: "plist", + encode: { + try encoder.encode($0) + } + ) + + } + + public static var yaml: Self { + yaml(options: .init()) + } + + public static func yaml(options: YAMLEncoder.Options) -> Self { + + let encoder = YAMLEncoder() + + encoder.options = options + + return .init( + fileExtension: "yml", + encode: { + let string = try encoder.encode($0) + return string.data(using: .utf8)! + } + ) + + } public func encode(_ view: some GrainView) throws -> Data { return try _encode(view) @@ -51,16 +94,23 @@ public struct Serialization { } public struct Context: Codable { + + public enum DomainError: Int, Error { + case contextNotProvided + } public let filePath: AbsolutePath public let outputDir: AbsolutePath? + public let userInfoString: String? public init( filePath: AbsolutePath, - outputDir: AbsolutePath? + outputDir: AbsolutePath?, + userInfoString: String? ) { self.filePath = filePath self.outputDir = outputDir + self.userInfoString = userInfoString } public func json() -> String { @@ -79,6 +129,15 @@ public struct Context: Codable { let url = URL(fileURLWithPath: path.pathString) try data.write(to: url, options: [.atomic]) } + + public func userInfo(_ decodableType: T.Type) throws -> T { + guard let userInfoString else { + throw DomainError.contextNotProvided + } + let decoder = JSONDecoder() + let decoded = try decoder.decode(decodableType.self, from: userInfoString.data(using: .utf8)!) + return decoded + } } @@ -144,6 +203,14 @@ public struct Output { } +public func serialize( + _ serialization: Serialization = .json, + output: Output = .stdout, + @GrainBuilder _ thunk: () throws -> some GrainView +) { + serialize(serialization: serialization, output: output, thunk) +} + public func serialize( serialization: Serialization = .json, output: Output = .stdout, diff --git a/fixtures/context.swift b/fixtures/context.swift new file mode 100644 index 0000000..480127c --- /dev/null +++ b/fixtures/context.swift @@ -0,0 +1,19 @@ +import GrainDescriptor + +// ./fixtures/context.swift --user-info '{"name" : "muukii"}' + +struct Parameter: Decodable { + var name: String +} + +let parameter = try context.userInfo(Parameter.self) + +serialize(.json) { + + GrainObject { + GrainMember("context") { + parameter.name + } + } + +}