Skip to content
Merged
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
8 changes: 4 additions & 4 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ let package = Package(
)
],
dependencies: [
.package(url: "https://github.com/omochi/SwiftTypeReader", from: "2.10.0"),
.package(url: "https://github.com/omochi/SwiftTypeReader", from: "2.10.1"),
// .package(path: "../SwiftTypeReader"),
.package(url: "https://github.com/omochi/TypeScriptAST", from: "1.8.6"),
.package(url: "https://github.com/omochi/TypeScriptAST", from: "1.8.8"),
],
targets: [
.target(
Expand Down
7 changes: 7 additions & 0 deletions Sources/CodableToTypeScript/Extensions/STypeEx.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ extension SType {
return (array: array, element: element)
}

internal func asSet() -> (set: StructType, element: any SType)? {
guard isStandardLibraryType("Set"),
let `set` = self.asStruct,
let element = `set`.genericArgs[safe: 0] else { return nil }
return (set: `set`, element: element)
}

internal func asDictionary() -> (dictionary: StructType, value: any SType)? {
guard isStandardLibraryType("Dictionary"),
let dict = self.asStruct,
Expand Down
58 changes: 58 additions & 0 deletions Sources/CodableToTypeScript/Generator/HelperLibraryGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ struct HelperLibraryGenerator {
case optionalEncode
case arrayDecode
case arrayEncode
case setDecode
case setEncode
case dictionaryDecode
case dictionaryEncode
case tagOf
Expand Down Expand Up @@ -36,6 +38,8 @@ struct HelperLibraryGenerator {
case .optionalEncode: return "Optional_encode"
case .arrayDecode: return "Array_decode"
case .arrayEncode: return "Array_encode"
case .setDecode: return "Set_decode"
case .setEncode: return "Set_encode"
case .dictionaryDecode: return "Dictionary_decode"
case .dictionaryEncode: return "Dictionary_encode"
case .tagOf: return "TagOf"
Expand All @@ -56,6 +60,8 @@ struct HelperLibraryGenerator {
case .optionalEncode: return optionalEncodeDecl()
case .arrayDecode: return arrayDecodeDecl()
case .arrayEncode: return arrayEncodeDecl()
case .setDecode: return setDecodeDecl()
case .setEncode: return setEncodeDecl()
case .dictionaryDecode: return dictionaryDecodeDecl()
case .dictionaryEncode: return dictionaryEncodeDecl()
case .tagOf: return tagOfDecl()
Expand Down Expand Up @@ -210,6 +216,58 @@ struct HelperLibraryGenerator {
)
}

func setDecodeDecl() -> TSFunctionDecl {
return TSFunctionDecl(
modifiers: [.export],
name: name(.setDecode),
genericParams: [.init("T"), .init("T_JSON")],
params: [
.init(name: "json", type: TSArrayType(TSIdentType("T_JSON"))),
tDecodeParameter()
],
result: TSIdentType("Set", genericArgs: [TSIdentType("T")]),
body: TSBlockStmt([
TSReturnStmt(
TSNewExpr(
callee: TSIdentType("Set"),
args: [TSCallExpr(
callee: TSMemberExpr(
base: TSIdentExpr.json, name: "map"
),
args: [tDecode()]
)]
)
)
])
)
}

func setEncodeDecl() -> TSFunctionDecl {
return TSFunctionDecl(
modifiers: [.export],
name: name(.setEncode),
genericParams: [.init("T"), .init("T_JSON")],
params: [
.init(name: "entity", type: TSIdentType("Set", genericArgs: [TSIdentType("T")])),
tEncodeParameter()
],
result: TSArrayType(TSIdentType("T_JSON")),
body: TSBlockStmt([
TSReturnStmt(
TSCallExpr(
callee: TSMemberExpr(
base: TSArrayExpr([
TSPrefixOperatorExpr("...", TSIdentExpr.entity),
]),
name: "map"
),
args: [tEncode()]
)
)
])
)
}

func dictionaryDecodeDecl() -> TSFunctionDecl {
return TSFunctionDecl(
modifiers: [.export],
Expand Down
54 changes: 54 additions & 0 deletions Sources/CodableToTypeScript/TypeConverter/SetConverter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import SwiftTypeReader
import TypeScriptAST

public struct SetConverter: TypeConverter {
public init(generator: CodeGenerator, swiftType: any SType) {
self.generator = generator
self.swiftType = swiftType
}

public var generator: CodeGenerator
public var swiftType: any SType

private func element() throws -> any TypeConverter {
let (_, element) = swiftType.asSet()!
return try generator.converter(for: element)
}

public func type(for target: GenerationTarget) throws -> any TSType {
switch target {
case .entity:
return try `default`.type(for: target)
case .json:
return TSArrayType(try element().type(for: target))
}
}

public func typeDecl(for target: GenerationTarget) throws -> TSTypeDecl? {
throw MessageError("Unsupported type: \(swiftType)")
}

public func decodePresence() throws -> CodecPresence {
return .required
}

public func decodeName() throws -> String? {
return generator.helperLibrary().name(.setDecode)
}

public func decodeDecl() throws -> TSFunctionDecl? {
throw MessageError("Unsupported type: \(swiftType)")
}

public func encodePresence() throws -> CodecPresence {
return .required
}

public func encodeName() throws -> String {
return generator.helperLibrary().name(.setEncode)
}

public func encodeDecl() throws -> TSFunctionDecl? {
throw MessageError("Unsupported type: \(swiftType)")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public struct TypeConverterProvider {
return OptionalConverter(generator: generator, swiftType: type)
} else if type.isStandardLibraryType("Array") {
return ArrayConverter(generator: generator, swiftType: type)
} else if type.isStandardLibraryType("Set") {
return SetConverter(generator: generator, swiftType: type)
} else if type.isStandardLibraryType("Dictionary") {
return DictionaryConverter(generator: generator, swiftType: type)
} else if let type = type.asEnum {
Expand Down
36 changes: 36 additions & 0 deletions Tests/CodableToTypeScriptTests/Generate/GenerateStructTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,42 @@ export function S_decode(json: S_JSON): S {
)
}

func testSet() throws {
try assertGenerate(
source: """
enum E { case a }

struct S {
var e1: Set<E>
}
""",
typeSelector: .name("S"),
expecteds: ["""
export type S = {
e1: Set<E>;
} & TagRecord<"S">;

export type S_JSON = {
e1: E_JSON[];
};

export function S_decode(json: S_JSON): S {
const e1 = Set_decode<E, E_JSON>(json.e1, E_decode);
return {
e1: e1
};
}

export function S_encode(entity: S): S_JSON {
const e1 = Set_encode<E, E_JSON>(entity.e1, identity);
return {
e1: e1
};
}
"""]
)
}

func testDecodeDictionary() throws {
try assertGenerate(
source: """
Expand Down
8 changes: 8 additions & 0 deletions Tests/CodableToTypeScriptTests/HelperLibraryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ export function Array_encode<T, T_JSON>(entity: T[], T_encode: (entity: T) => T_
return entity.map(T_encode);
}
""", """
export function Set_decode<T, T_JSON>(json: T_JSON[], T_decode: (json: T_JSON) => T): Set<T> {
return new Set(json.map(T_decode));
}
""", """
export function Set_encode<T, T_JSON>(entity: Set<T>, T_encode: (entity: T) => T_JSON): T_JSON[] {
return [... entity].map(T_encode);
}
""", """
export function Dictionary_decode<T, T_JSON>(json: {
[key: string]: T_JSON;
}, T_decode: (json: T_JSON) => T): Map<string, T> {
Expand Down