Skip to content

Commit c4d9567

Browse files
authored
Merge pull request #36 from sidepelican/macro_scan
Scan service protocols using macro annotations
2 parents da4460c + e7e9dc8 commit c4d9567

File tree

13 files changed

+177
-147
lines changed

13 files changed

+177
-147
lines changed

Package.resolved

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ let package = Package(
1515
dependencies: [
1616
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.2"),
1717
.package(url: "https://github.com/swiftlang/swift-syntax.git", from: "600.0.1"),
18-
.package(url: "https://github.com/omochi/CodableToTypeScript.git", from: "2.11.0"),
19-
.package(url: "https://github.com/omochi/SwiftTypeReader.git", from: "2.8.0"),
18+
.package(url: "https://github.com/omochi/CodableToTypeScript.git", from: "3.0.1"),
19+
.package(url: "https://github.com/omochi/SwiftTypeReader.git", from: "3.1.0"),
2020
.package(url: "https://github.com/vapor/vapor.git", from: "4.106.7"),
2121
.package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.5.0"),
2222
],

Sources/CallableKitMacros/CallableMacro.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public struct CallableMacro: PeerMacro {
1313
}
1414

1515
let protocolName = `protocol`.name.trimmedDescription
16-
let serviceName = protocolName.replacingOccurrences(of: "ServiceProtocol", with: "")
16+
let serviceName = protocolName.trimmingSuffix("Protocol").trimmingSuffix("Service")
1717

1818
let functions = `protocol`.memberBlock.members.compactMap { item in
1919
return item.decl.as(FunctionDeclSyntax.self)
@@ -42,3 +42,14 @@ public struct CallableMacro: PeerMacro {
4242
return [DeclSyntax(configureFunc)]
4343
}
4444
}
45+
46+
extension String {
47+
fileprivate func trimmingSuffix(_ suffix: String) -> String {
48+
if self.hasSuffix(suffix) {
49+
var copy = self
50+
copy.removeLast(suffix.count)
51+
return copy
52+
}
53+
return self
54+
}
55+
}

Sources/CodegenImpl/GenerateTSClient.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,8 @@ struct FlatRawRepresentableConverter: TypeConverter {
271271
}
272272
}
273273

274-
func decodePresence() throws -> CodecPresence {
275-
return isTransferringRawValueType ? .identity : .required
274+
func hasDecode() -> Bool {
275+
return !isTransferringRawValueType
276276
}
277277

278278
func decodeDecl() throws -> TSFunctionDecl? {
@@ -288,8 +288,8 @@ struct FlatRawRepresentableConverter: TypeConverter {
288288
return decl
289289
}
290290

291-
func encodePresence() throws -> CodecPresence {
292-
return isTransferringRawValueType ? .identity : .required
291+
func hasEncode() -> Bool {
292+
return !isTransferringRawValueType
293293
}
294294

295295
func encodeDecl() throws -> TSFunctionDecl? {

Sources/CodegenImpl/ServiceProtocolScanner.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ enum ServiceProtocolScanner {
3838

3939
static func scan(_ stype: any SType) -> ServiceProtocolType? {
4040
guard let ptype = stype as? ProtocolType,
41-
ptype.name.hasSuffix("ServiceProtocol"),
41+
ptype.decl.attributes.contains(where: { $0.name == "Callable" }),
4242
!ptype.decl.functions.isEmpty
4343
else { return nil }
4444

45-
let serviceName = ptype.name.replacingOccurrences(of: "ServiceProtocol", with: "")
45+
let serviceName = ptype.name.trimmingSuffix("Protocol").trimmingSuffix("Service")
4646

4747
let functions = ptype.decl.functions.compactMap { fdecl -> ServiceProtocolType.Function? in
4848
guard fdecl.parameters.count <= 1 else {
@@ -77,3 +77,14 @@ enum ServiceProtocolScanner {
7777
)
7878
}
7979
}
80+
81+
extension String {
82+
fileprivate func trimmingSuffix(_ suffix: String) -> String {
83+
if self.hasSuffix(suffix) {
84+
var copy = self
85+
copy.removeLast(suffix.count)
86+
return copy
87+
}
88+
return self
89+
}
90+
}

example/Package.resolved

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/TSClient/src/Gen/APIDefinition/Account.gen.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { IStubClient } from "../CallableKit.gen.js";
2-
import { CodableResult, CodableResult_JSON, CodableResult_decode } from "../OtherDependency/CodableResult.gen.js";
2+
import { CodableResult, CodableResult$JSON, CodableResult_decode } from "../OtherDependency/CodableResult.gen.js";
33
import { TagRecord, identity } from "../common.gen.js";
44
import { SubmitError } from "./Entity/SubmitError.gen.js";
55

@@ -10,7 +10,7 @@ export interface IAccountClient {
1010
export const bindAccount = (stub: IStubClient): IAccountClient => {
1111
return {
1212
async signin(request: AccountSignin_Request): Promise<CodableResult<AccountSignin_Response, SubmitError<AccountSignin_Error>>> {
13-
const json = await stub.send(request, "Account/signin") as CodableResult_JSON<AccountSignin_Response, SubmitError<AccountSignin_Error>>;
13+
const json = await stub.send(request, "Account/signin") as CodableResult$JSON<AccountSignin_Response, SubmitError<AccountSignin_Error>>;
1414
return CodableResult_decode<
1515
AccountSignin_Response,
1616
AccountSignin_Response,

example/TSClient/src/Gen/APIDefinition/Echo.gen.ts

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ import {
99
import {
1010
Student,
1111
Student2,
12-
Student2_JSON,
12+
Student2$JSON,
1313
Student2_decode,
1414
Student2_encode,
1515
Student3,
16-
Student3_JSON,
16+
Student3$JSON,
1717
Student3_decode,
1818
Student3_encode,
1919
Student4,
20-
Student4_JSON,
20+
Student4$JSON,
2121
Student4_decode,
2222
Student4_encode,
2323
Student5
@@ -50,7 +50,7 @@ export const bindEcho = (stub: IStubClient): IEchoClient => {
5050
return await stub.send(request, "Echo/testTypicalEntity") as User;
5151
},
5252
async testComplexType(request: TestComplexType_Request): Promise<TestComplexType_Response> {
53-
const json = await stub.send(request, "Echo/testComplexType") as TestComplexType_Response_JSON;
53+
const json = await stub.send(request, "Echo/testComplexType") as TestComplexType_Response$JSON;
5454
return TestComplexType_Response_decode(json);
5555
},
5656
async emptyRequestAndResponse(): Promise<void> {
@@ -60,15 +60,15 @@ export const bindEcho = (stub: IStubClient): IEchoClient => {
6060
return await stub.send(request, "Echo/testTypeAliasToRawRepr") as Student;
6161
},
6262
async testRawRepr(request: Student2): Promise<Student2> {
63-
const json = await stub.send(Student2_encode(request), "Echo/testRawRepr") as Student2_JSON;
63+
const json = await stub.send(Student2_encode(request), "Echo/testRawRepr") as Student2$JSON;
6464
return Student2_decode(json);
6565
},
6666
async testRawRepr2(request: Student3): Promise<Student3> {
67-
const json = await stub.send(Student3_encode(request), "Echo/testRawRepr2") as Student3_JSON;
67+
const json = await stub.send(Student3_encode(request), "Echo/testRawRepr2") as Student3$JSON;
6868
return Student3_decode(json);
6969
},
7070
async testRawRepr3(request: Student4): Promise<Student4> {
71-
const json = await stub.send(Student4_encode(request), "Echo/testRawRepr3") as Student4_JSON;
71+
const json = await stub.send(Student4_encode(request), "Echo/testRawRepr3") as Student4$JSON;
7272
return Student4_decode(json);
7373
},
7474
async testRawRepr4(request: Student5): Promise<Student5> {
@@ -91,18 +91,18 @@ export type TestComplexType_K<T> = {
9191
x: T;
9292
} & TagRecord<"TestComplexType_K", [T]>;
9393

94-
export type TestComplexType_K_JSON<T_JSON> = {
95-
x: T_JSON;
94+
export type TestComplexType_K$JSON<T$JSON> = {
95+
x: T$JSON;
9696
};
9797

98-
export function TestComplexType_K_decode<T, T_JSON>(json: TestComplexType_K_JSON<T_JSON>, T_decode: (json: T_JSON) => T): TestComplexType_K<T> {
98+
export function TestComplexType_K_decode<T, T$JSON>(json: TestComplexType_K$JSON<T$JSON>, T_decode: (json: T$JSON) => T): TestComplexType_K<T> {
9999
const x = T_decode(json.x);
100100
return {
101101
x: x
102102
};
103103
}
104104

105-
export function TestComplexType_K_encode<T, T_JSON>(entity: TestComplexType_K<T>, T_encode: (entity: T) => T_JSON): TestComplexType_K_JSON<T_JSON> {
105+
export function TestComplexType_K_encode<T, T$JSON>(entity: TestComplexType_K<T>, T_encode: (entity: T) => T$JSON): TestComplexType_K$JSON<T$JSON> {
106106
const x = T_encode(entity.x);
107107
return {
108108
x: x
@@ -124,9 +124,9 @@ export type TestComplexType_E<T> = ({
124124
n: {};
125125
}) & TagRecord<"TestComplexType_E", [T]>;
126126

127-
export type TestComplexType_E_JSON<T_JSON> = {
127+
export type TestComplexType_E$JSON<T$JSON> = {
128128
k: {
129-
_0: TestComplexType_K_JSON<T_JSON>;
129+
_0: TestComplexType_K$JSON<T$JSON>;
130130
};
131131
} | {
132132
i: {
@@ -136,10 +136,10 @@ export type TestComplexType_E_JSON<T_JSON> = {
136136
n: {};
137137
};
138138

139-
export function TestComplexType_E_decode<T, T_JSON>(json: TestComplexType_E_JSON<T_JSON>, T_decode: (json: T_JSON) => T): TestComplexType_E<T> {
139+
export function TestComplexType_E_decode<T, T$JSON>(json: TestComplexType_E$JSON<T$JSON>, T_decode: (json: T$JSON) => T): TestComplexType_E<T> {
140140
if ("k" in json) {
141141
const j = json.k;
142-
const _0 = TestComplexType_K_decode<T, T_JSON>(j._0, T_decode);
142+
const _0 = TestComplexType_K_decode<T, T$JSON>(j._0, T_decode);
143143
return {
144144
kind: "k",
145145
k: {
@@ -165,12 +165,12 @@ export function TestComplexType_E_decode<T, T_JSON>(json: TestComplexType_E_JSON
165165
}
166166
}
167167

168-
export function TestComplexType_E_encode<T, T_JSON>(entity: TestComplexType_E<T>, T_encode: (entity: T) => T_JSON): TestComplexType_E_JSON<T_JSON> {
168+
export function TestComplexType_E_encode<T, T$JSON>(entity: TestComplexType_E<T>, T_encode: (entity: T) => T$JSON): TestComplexType_E$JSON<T$JSON> {
169169
switch (entity.kind) {
170170
case "k":
171171
{
172172
const e = entity.k;
173-
const _0 = TestComplexType_K_encode<T, T_JSON>(e._0, T_encode);
173+
const _0 = TestComplexType_K_encode<T, T$JSON>(e._0, T_encode);
174174
return {
175175
k: {
176176
_0: _0
@@ -207,15 +207,15 @@ export type TestComplexType_Request = {
207207
a?: TestComplexType_K<(TestComplexType_E<TestComplexType_L> | null)[]>;
208208
} & TagRecord<"TestComplexType_Request">;
209209

210-
export type TestComplexType_Request_JSON = {
211-
a?: TestComplexType_K_JSON<(TestComplexType_E_JSON<TestComplexType_L> | null)[]>;
210+
export type TestComplexType_Request$JSON = {
211+
a?: TestComplexType_K$JSON<(TestComplexType_E$JSON<TestComplexType_L> | null)[]>;
212212
};
213213

214-
export function TestComplexType_Request_decode(json: TestComplexType_Request_JSON): TestComplexType_Request {
215-
const a = OptionalField_decode<TestComplexType_K<(TestComplexType_E<TestComplexType_L> | null)[]>, TestComplexType_K_JSON<(TestComplexType_E_JSON<TestComplexType_L> | null)[]>>(json.a, (json: TestComplexType_K_JSON<(TestComplexType_E_JSON<TestComplexType_L> | null)[]>): TestComplexType_K<(TestComplexType_E<TestComplexType_L> | null)[]> => {
216-
return TestComplexType_K_decode<(TestComplexType_E<TestComplexType_L> | null)[], (TestComplexType_E_JSON<TestComplexType_L> | null)[]>(json, (json: (TestComplexType_E_JSON<TestComplexType_L> | null)[]): (TestComplexType_E<TestComplexType_L> | null)[] => {
217-
return Array_decode<TestComplexType_E<TestComplexType_L> | null, TestComplexType_E_JSON<TestComplexType_L> | null>(json, (json: TestComplexType_E_JSON<TestComplexType_L> | null): TestComplexType_E<TestComplexType_L> | null => {
218-
return Optional_decode<TestComplexType_E<TestComplexType_L>, TestComplexType_E_JSON<TestComplexType_L>>(json, (json: TestComplexType_E_JSON<TestComplexType_L>): TestComplexType_E<TestComplexType_L> => {
214+
export function TestComplexType_Request_decode(json: TestComplexType_Request$JSON): TestComplexType_Request {
215+
const a = OptionalField_decode<TestComplexType_K<(TestComplexType_E<TestComplexType_L> | null)[]>, TestComplexType_K$JSON<(TestComplexType_E$JSON<TestComplexType_L> | null)[]>>(json.a, (json: TestComplexType_K$JSON<(TestComplexType_E$JSON<TestComplexType_L> | null)[]>): TestComplexType_K<(TestComplexType_E<TestComplexType_L> | null)[]> => {
216+
return TestComplexType_K_decode<(TestComplexType_E<TestComplexType_L> | null)[], (TestComplexType_E$JSON<TestComplexType_L> | null)[]>(json, (json: (TestComplexType_E$JSON<TestComplexType_L> | null)[]): (TestComplexType_E<TestComplexType_L> | null)[] => {
217+
return Array_decode<TestComplexType_E<TestComplexType_L> | null, TestComplexType_E$JSON<TestComplexType_L> | null>(json, (json: TestComplexType_E$JSON<TestComplexType_L> | null): TestComplexType_E<TestComplexType_L> | null => {
218+
return Optional_decode<TestComplexType_E<TestComplexType_L>, TestComplexType_E$JSON<TestComplexType_L>>(json, (json: TestComplexType_E$JSON<TestComplexType_L>): TestComplexType_E<TestComplexType_L> => {
219219
return TestComplexType_E_decode<TestComplexType_L, TestComplexType_L>(json, identity);
220220
});
221221
});
@@ -230,15 +230,15 @@ export type TestComplexType_Response = {
230230
a?: TestComplexType_K<(TestComplexType_E<TestComplexType_L> | null)[]>;
231231
} & TagRecord<"TestComplexType_Response">;
232232

233-
export type TestComplexType_Response_JSON = {
234-
a?: TestComplexType_K_JSON<(TestComplexType_E_JSON<TestComplexType_L> | null)[]>;
233+
export type TestComplexType_Response$JSON = {
234+
a?: TestComplexType_K$JSON<(TestComplexType_E$JSON<TestComplexType_L> | null)[]>;
235235
};
236236

237-
export function TestComplexType_Response_decode(json: TestComplexType_Response_JSON): TestComplexType_Response {
238-
const a = OptionalField_decode<TestComplexType_K<(TestComplexType_E<TestComplexType_L> | null)[]>, TestComplexType_K_JSON<(TestComplexType_E_JSON<TestComplexType_L> | null)[]>>(json.a, (json: TestComplexType_K_JSON<(TestComplexType_E_JSON<TestComplexType_L> | null)[]>): TestComplexType_K<(TestComplexType_E<TestComplexType_L> | null)[]> => {
239-
return TestComplexType_K_decode<(TestComplexType_E<TestComplexType_L> | null)[], (TestComplexType_E_JSON<TestComplexType_L> | null)[]>(json, (json: (TestComplexType_E_JSON<TestComplexType_L> | null)[]): (TestComplexType_E<TestComplexType_L> | null)[] => {
240-
return Array_decode<TestComplexType_E<TestComplexType_L> | null, TestComplexType_E_JSON<TestComplexType_L> | null>(json, (json: TestComplexType_E_JSON<TestComplexType_L> | null): TestComplexType_E<TestComplexType_L> | null => {
241-
return Optional_decode<TestComplexType_E<TestComplexType_L>, TestComplexType_E_JSON<TestComplexType_L>>(json, (json: TestComplexType_E_JSON<TestComplexType_L>): TestComplexType_E<TestComplexType_L> => {
237+
export function TestComplexType_Response_decode(json: TestComplexType_Response$JSON): TestComplexType_Response {
238+
const a = OptionalField_decode<TestComplexType_K<(TestComplexType_E<TestComplexType_L> | null)[]>, TestComplexType_K$JSON<(TestComplexType_E$JSON<TestComplexType_L> | null)[]>>(json.a, (json: TestComplexType_K$JSON<(TestComplexType_E$JSON<TestComplexType_L> | null)[]>): TestComplexType_K<(TestComplexType_E<TestComplexType_L> | null)[]> => {
239+
return TestComplexType_K_decode<(TestComplexType_E<TestComplexType_L> | null)[], (TestComplexType_E$JSON<TestComplexType_L> | null)[]>(json, (json: (TestComplexType_E$JSON<TestComplexType_L> | null)[]): (TestComplexType_E<TestComplexType_L> | null)[] => {
240+
return Array_decode<TestComplexType_E<TestComplexType_L> | null, TestComplexType_E$JSON<TestComplexType_L> | null>(json, (json: TestComplexType_E$JSON<TestComplexType_L> | null): TestComplexType_E<TestComplexType_L> | null => {
241+
return Optional_decode<TestComplexType_E<TestComplexType_L>, TestComplexType_E$JSON<TestComplexType_L>>(json, (json: TestComplexType_E$JSON<TestComplexType_L>): TestComplexType_E<TestComplexType_L> => {
242242
return TestComplexType_E_decode<TestComplexType_L, TestComplexType_L>(json, identity);
243243
});
244244
});

0 commit comments

Comments
 (0)