@tutao/licc 3.106.4 → 3.106.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Accumulator.js +2 -4
- package/dist/KotlinGenerator.js +6 -6
- package/dist/Parser.js +137 -10
- package/dist/SwiftGenerator.js +13 -18
- package/dist/TypescriptGenerator.js +5 -7
- package/dist/common.js +3 -3
- package/dist/tsbuildinfo +1 -1
- package/lib/Accumulator.ts +5 -10
- package/lib/KotlinGenerator.ts +21 -20
- package/lib/Parser.ts +141 -14
- package/lib/SwiftGenerator.ts +52 -54
- package/lib/TypescriptGenerator.ts +20 -27
- package/lib/cli.ts +24 -22
- package/lib/common.ts +9 -9
- package/lib/index.ts +7 -7
- package/package.json +2 -2
- package/preinstall.js +2 -4
- package/test/ParserTest.ts +62 -45
- package/test/Suite.ts +2 -2
- package/test/tsconfig.json +14 -18
- package/tsconfig.json +101 -101
package/lib/Parser.ts
CHANGED
|
@@ -1,19 +1,146 @@
|
|
|
1
1
|
export const PRIMITIVES = ["string", "boolean", "number", "bytes", "void"]
|
|
2
2
|
const KOTLIN_KEYWORDS = [
|
|
3
|
-
"as",
|
|
4
|
-
"
|
|
3
|
+
"as",
|
|
4
|
+
"break",
|
|
5
|
+
"class",
|
|
6
|
+
"continue",
|
|
7
|
+
"do",
|
|
8
|
+
"else",
|
|
9
|
+
"false",
|
|
10
|
+
"for",
|
|
11
|
+
"fun",
|
|
12
|
+
"if",
|
|
13
|
+
"in",
|
|
14
|
+
"interface",
|
|
15
|
+
"is",
|
|
16
|
+
"null",
|
|
17
|
+
"object",
|
|
18
|
+
"package",
|
|
19
|
+
"return",
|
|
20
|
+
"super",
|
|
21
|
+
"this",
|
|
22
|
+
"throw",
|
|
23
|
+
"true",
|
|
24
|
+
"try",
|
|
25
|
+
"typealias",
|
|
26
|
+
"typeof",
|
|
27
|
+
"val",
|
|
28
|
+
"var",
|
|
29
|
+
"when",
|
|
30
|
+
"while",
|
|
5
31
|
]
|
|
6
32
|
const TYPESCRIPT_KEYWORDS = [
|
|
7
|
-
"var",
|
|
8
|
-
"
|
|
9
|
-
"
|
|
33
|
+
"var",
|
|
34
|
+
"const",
|
|
35
|
+
"let",
|
|
36
|
+
"break",
|
|
37
|
+
"return",
|
|
38
|
+
"case",
|
|
39
|
+
"catch",
|
|
40
|
+
"class",
|
|
41
|
+
"continue",
|
|
42
|
+
"debugger",
|
|
43
|
+
"default",
|
|
44
|
+
"delete",
|
|
45
|
+
"do",
|
|
46
|
+
"else",
|
|
47
|
+
"enum",
|
|
48
|
+
"export",
|
|
49
|
+
"extends",
|
|
50
|
+
"false",
|
|
51
|
+
"finally",
|
|
52
|
+
"for",
|
|
53
|
+
"function",
|
|
54
|
+
"if",
|
|
55
|
+
"import",
|
|
56
|
+
"in",
|
|
57
|
+
"instanceOf",
|
|
58
|
+
"new",
|
|
59
|
+
"null",
|
|
60
|
+
"return",
|
|
61
|
+
"super",
|
|
62
|
+
"switch",
|
|
63
|
+
"this",
|
|
64
|
+
"throw",
|
|
65
|
+
"true",
|
|
66
|
+
"try",
|
|
67
|
+
"typeOf",
|
|
68
|
+
"void",
|
|
69
|
+
"while",
|
|
70
|
+
"with",
|
|
10
71
|
]
|
|
11
72
|
const SWIFT_KEYWORDS = [
|
|
12
|
-
"Class",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
73
|
+
"Class",
|
|
74
|
+
"deinit",
|
|
75
|
+
"Enum",
|
|
76
|
+
"extension",
|
|
77
|
+
"Func",
|
|
78
|
+
"import",
|
|
79
|
+
"Init",
|
|
80
|
+
"internal",
|
|
81
|
+
"Let",
|
|
82
|
+
"operator",
|
|
83
|
+
"private",
|
|
84
|
+
"protocol",
|
|
85
|
+
"public",
|
|
86
|
+
"static",
|
|
87
|
+
"struct",
|
|
88
|
+
"subscript",
|
|
89
|
+
"typealias",
|
|
90
|
+
"var",
|
|
91
|
+
"break",
|
|
92
|
+
"case",
|
|
93
|
+
"continue",
|
|
94
|
+
"default",
|
|
95
|
+
"do",
|
|
96
|
+
"else",
|
|
97
|
+
"fallthrough",
|
|
98
|
+
"for",
|
|
99
|
+
"if",
|
|
100
|
+
"in",
|
|
101
|
+
"return",
|
|
102
|
+
"switch",
|
|
103
|
+
"where",
|
|
104
|
+
"while",
|
|
105
|
+
"as",
|
|
106
|
+
"dynamicType",
|
|
107
|
+
"false",
|
|
108
|
+
"is",
|
|
109
|
+
"nil",
|
|
110
|
+
"self",
|
|
111
|
+
"Self",
|
|
112
|
+
"super",
|
|
113
|
+
"true",
|
|
114
|
+
"_COLUMN_",
|
|
115
|
+
"_FILE_",
|
|
116
|
+
"_FUNCTION_",
|
|
117
|
+
"_LINE_",
|
|
118
|
+
"associativity",
|
|
119
|
+
"convenience",
|
|
120
|
+
"dynamic",
|
|
121
|
+
"didSet",
|
|
122
|
+
"final",
|
|
123
|
+
"get",
|
|
124
|
+
"infix",
|
|
125
|
+
"inout",
|
|
126
|
+
"lazy",
|
|
127
|
+
"left",
|
|
128
|
+
"mutating",
|
|
129
|
+
"none",
|
|
130
|
+
"nonmutating",
|
|
131
|
+
"optional",
|
|
132
|
+
"override",
|
|
133
|
+
"postfix",
|
|
134
|
+
"precedence",
|
|
135
|
+
"prefix",
|
|
136
|
+
"Protocol",
|
|
137
|
+
"required",
|
|
138
|
+
"right",
|
|
139
|
+
"set",
|
|
140
|
+
"Type",
|
|
141
|
+
"unowned",
|
|
142
|
+
"weak",
|
|
143
|
+
"willSet",
|
|
17
144
|
]
|
|
18
145
|
|
|
19
146
|
const FORBIDDEN_IDENTIFIERS = new Set([...KOTLIN_KEYWORDS, ...TYPESCRIPT_KEYWORDS, ...SWIFT_KEYWORDS])
|
|
@@ -33,14 +160,14 @@ export function parseType(typeString: string): ParsedType {
|
|
|
33
160
|
const listMatch = typeString.match(/^\s*List<\s*(.*)\s*>\s*$/)
|
|
34
161
|
if (listMatch) {
|
|
35
162
|
const nested = parseType(listMatch[1])
|
|
36
|
-
return {baseName: "List", generics: [nested], nullable, external: false}
|
|
163
|
+
return { baseName: "List", generics: [nested], nullable, external: false }
|
|
37
164
|
}
|
|
38
165
|
|
|
39
166
|
const mapMatch = typeString.match(/^\s*Map<\s*(.*?),\s*(.*?)\s*>\s*$/)
|
|
40
167
|
if (mapMatch) {
|
|
41
168
|
const nestedKey = parseType(mapMatch[1])
|
|
42
169
|
const nestedValue = parseType(mapMatch[2])
|
|
43
|
-
return {baseName: "Map", generics: [nestedKey, nestedValue], nullable, external: false}
|
|
170
|
+
return { baseName: "Map", generics: [nestedKey, nestedValue], nullable, external: false }
|
|
44
171
|
}
|
|
45
172
|
|
|
46
173
|
// this is a basic type without generic params
|
|
@@ -51,7 +178,7 @@ export function parseType(typeString: string): ParsedType {
|
|
|
51
178
|
throw new Error(`illegal identifier: "${typeString}"`)
|
|
52
179
|
}
|
|
53
180
|
|
|
54
|
-
return {baseName: typeString, generics: [], external, nullable}
|
|
181
|
+
return { baseName: typeString, generics: [], external, nullable }
|
|
55
182
|
} // frontend type
|
|
56
183
|
|
|
57
184
|
/**
|
|
@@ -79,4 +206,4 @@ export interface ParsedType {
|
|
|
79
206
|
baseName: string
|
|
80
207
|
// contained generic types, if any
|
|
81
208
|
generics: ParsedType[]
|
|
82
|
-
}
|
|
209
|
+
}
|
package/lib/SwiftGenerator.ts
CHANGED
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
minusculize,
|
|
8
8
|
RenderedType,
|
|
9
9
|
StructDefinition,
|
|
10
|
-
TypeRefDefinition
|
|
10
|
+
TypeRefDefinition,
|
|
11
11
|
} from "./common.js"
|
|
12
|
-
import {Accumulator} from "./Accumulator.js"
|
|
13
|
-
import {ParsedType, parseType} from "./Parser.js"
|
|
12
|
+
import { Accumulator } from "./Accumulator.js"
|
|
13
|
+
import { ParsedType, parseType } from "./Parser.js"
|
|
14
14
|
|
|
15
15
|
export class SwiftGenerator implements LangGenerator {
|
|
16
16
|
handleStructDefinition(definition: StructDefinition): string {
|
|
@@ -55,9 +55,7 @@ export class SwiftGenerator implements LangGenerator {
|
|
|
55
55
|
const lastArg = args[args.length - 1]
|
|
56
56
|
for (const argument of args) {
|
|
57
57
|
const renderedArgument = typeNameSwift(argument.type)
|
|
58
|
-
const argLine =
|
|
59
|
-
`_ ${argument.name}: ${renderedArgument.name}` +
|
|
60
|
-
((argument === lastArg) ? "" : ",")
|
|
58
|
+
const argLine = `_ ${argument.name}: ${renderedArgument.name}` + (argument === lastArg ? "" : ",")
|
|
61
59
|
argGenerator.line(argLine)
|
|
62
60
|
}
|
|
63
61
|
const renderedReturn = typeNameSwift(methodDefinition.ret)
|
|
@@ -83,7 +81,7 @@ export class SwiftGenerator implements LangGenerator {
|
|
|
83
81
|
const arg = getArgs(methodName, method)
|
|
84
82
|
const decodedArgs = []
|
|
85
83
|
for (let i = 0; i < arg.length; i++) {
|
|
86
|
-
const {name: argName, type} = arg[i]
|
|
84
|
+
const { name: argName, type } = arg[i]
|
|
87
85
|
const renderedArgType = typeNameSwift(type)
|
|
88
86
|
decodedArgs.push([argName, renderedArgType] as const)
|
|
89
87
|
}
|
|
@@ -120,40 +118,38 @@ export class SwiftGenerator implements LangGenerator {
|
|
|
120
118
|
generateGlobalDispatcher(name: string, facadeNames: Array<string>): string {
|
|
121
119
|
return new Accumulator()
|
|
122
120
|
.line(`public class ${name} {`)
|
|
123
|
-
.indented(acc =>
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
.
|
|
129
|
-
|
|
130
|
-
|
|
121
|
+
.indented((acc) =>
|
|
122
|
+
acc
|
|
123
|
+
.lines(facadeNames.map((facadeName) => `private let ${minusculize(facadeName)}: ${facadeName}ReceiveDispatcher`))
|
|
124
|
+
.line()
|
|
125
|
+
.line(`init(`)
|
|
126
|
+
.indented((acc) =>
|
|
127
|
+
acc.lines(
|
|
128
|
+
facadeNames.map((name) => `${minusculize(name)} : ${name}`),
|
|
129
|
+
{ suffix: ",", trailing: false },
|
|
130
|
+
),
|
|
131
|
+
)
|
|
132
|
+
.line(`) {`)
|
|
133
|
+
.indented((acc) =>
|
|
134
|
+
acc.lines(facadeNames.map((name) => `self.${minusculize(name)} = ${name}ReceiveDispatcher(facade: ${minusculize(name)})`)),
|
|
131
135
|
)
|
|
132
|
-
)
|
|
133
|
-
.line(`) {`)
|
|
134
|
-
.indented(acc => acc
|
|
135
|
-
.lines(facadeNames.map(name =>
|
|
136
|
-
`self.${minusculize(name)} = ${name}ReceiveDispatcher(facade: ${minusculize(name)})`
|
|
137
|
-
))
|
|
138
|
-
)
|
|
139
|
-
.line(`}`)
|
|
140
|
-
.line()
|
|
141
|
-
.line(`func dispatch(facadeName: String, methodName: String, args: Array<String>) async throws -> String {`)
|
|
142
|
-
.indented(acc => acc
|
|
143
|
-
.line(`switch facadeName {`)
|
|
144
|
-
.indented(acc => {
|
|
145
|
-
for (let facadeName of facadeNames) {
|
|
146
|
-
acc.line(`case "${facadeName}":`)
|
|
147
|
-
.indent()
|
|
148
|
-
.line(`return try await self.${minusculize(facadeName)}.dispatch(method: methodName, arg: args)`)
|
|
149
|
-
}
|
|
150
|
-
acc.line(`default:`)
|
|
151
|
-
.indent()
|
|
152
|
-
.line(`fatalError("licc messed up! " + facadeName)`)
|
|
153
|
-
})
|
|
154
136
|
.line(`}`)
|
|
155
|
-
|
|
156
|
-
|
|
137
|
+
.line()
|
|
138
|
+
.line(`func dispatch(facadeName: String, methodName: String, args: Array<String>) async throws -> String {`)
|
|
139
|
+
.indented((acc) =>
|
|
140
|
+
acc
|
|
141
|
+
.line(`switch facadeName {`)
|
|
142
|
+
.indented((acc) => {
|
|
143
|
+
for (let facadeName of facadeNames) {
|
|
144
|
+
acc.line(`case "${facadeName}":`)
|
|
145
|
+
.indent()
|
|
146
|
+
.line(`return try await self.${minusculize(facadeName)}.dispatch(method: methodName, arg: args)`)
|
|
147
|
+
}
|
|
148
|
+
acc.line(`default:`).indent().line(`fatalError("licc messed up! " + facadeName)`)
|
|
149
|
+
})
|
|
150
|
+
.line(`}`),
|
|
151
|
+
)
|
|
152
|
+
.line(`}`),
|
|
157
153
|
)
|
|
158
154
|
.line(`}`)
|
|
159
155
|
.finish()
|
|
@@ -185,7 +181,9 @@ export class SwiftGenerator implements LangGenerator {
|
|
|
185
181
|
methodBodyAcc.line(`let encodedFacadeName = toJson("${definition.name}")`)
|
|
186
182
|
methodBodyAcc.line(`let encodedMethodName = toJson("${methodName}")`)
|
|
187
183
|
if (methodDefinition.ret !== "void") {
|
|
188
|
-
methodBodyAcc.line(
|
|
184
|
+
methodBodyAcc.line(
|
|
185
|
+
`let returnValue = try await self.transport.sendRequest(requestType: "ipc", args: [encodedFacadeName, encodedMethodName] + args)`,
|
|
186
|
+
)
|
|
189
187
|
methodBodyAcc.line(`return try! JSONDecoder().decode(${typeNameSwift(methodDefinition.ret).name}.self, from: returnValue.data(using: .utf8)!)`)
|
|
190
188
|
} else {
|
|
191
189
|
methodBodyAcc.line(`let _ = try await self.transport.sendRequest(requestType: "ipc", args: [encodedFacadeName, encodedMethodName] + args)`)
|
|
@@ -201,7 +199,7 @@ export class SwiftGenerator implements LangGenerator {
|
|
|
201
199
|
|
|
202
200
|
generateExtraFiles(): Record<string, string> {
|
|
203
201
|
return {
|
|
204
|
-
|
|
202
|
+
NativeInterface: SwiftGenerator.generateNativeInterface(),
|
|
205
203
|
}
|
|
206
204
|
}
|
|
207
205
|
|
|
@@ -222,11 +220,11 @@ export class SwiftGenerator implements LangGenerator {
|
|
|
222
220
|
return null
|
|
223
221
|
}
|
|
224
222
|
|
|
225
|
-
generateEnum({name, values, doc}: EnumDefinition): string {
|
|
223
|
+
generateEnum({ name, values, doc }: EnumDefinition): string {
|
|
226
224
|
return new Accumulator()
|
|
227
|
-
.do(acc => this.generateDocComment(acc, doc))
|
|
225
|
+
.do((acc) => this.generateDocComment(acc, doc))
|
|
228
226
|
.line(`public enum ${name}: Int {`)
|
|
229
|
-
.indented(acc => acc.lines(values.map((value, index) => `case ${value} = ${index}`)))
|
|
227
|
+
.indented((acc) => acc.lines(values.map((value, index) => `case ${value} = ${index}`)))
|
|
230
228
|
.line("}")
|
|
231
229
|
.finish()
|
|
232
230
|
}
|
|
@@ -238,33 +236,33 @@ function typeNameSwift(name: string): RenderedType {
|
|
|
238
236
|
}
|
|
239
237
|
|
|
240
238
|
function renderSwiftType(parsed: ParsedType): RenderedType {
|
|
241
|
-
const {baseName, nullable} = parsed
|
|
239
|
+
const { baseName, nullable } = parsed
|
|
242
240
|
switch (baseName) {
|
|
243
241
|
case "List":
|
|
244
242
|
const renderedListInner = renderSwiftType(parsed.generics[0])
|
|
245
|
-
return {externals: renderedListInner.externals, name: maybeNullable(`[${renderedListInner.name}]`, nullable)}
|
|
243
|
+
return { externals: renderedListInner.externals, name: maybeNullable(`[${renderedListInner.name}]`, nullable) }
|
|
246
244
|
case "Map":
|
|
247
245
|
const renderedKey = renderSwiftType(parsed.generics[0])
|
|
248
246
|
const renderedValue = renderSwiftType(parsed.generics[1])
|
|
249
247
|
return {
|
|
250
248
|
externals: [...renderedKey.externals, ...renderedValue.externals],
|
|
251
|
-
name: maybeNullable(`[${renderedKey.name} : ${renderedValue.name}]`, nullable)
|
|
249
|
+
name: maybeNullable(`[${renderedKey.name} : ${renderedValue.name}]`, nullable),
|
|
252
250
|
}
|
|
253
251
|
case "string":
|
|
254
|
-
return {externals: [], name: maybeNullable("String", nullable)}
|
|
252
|
+
return { externals: [], name: maybeNullable("String", nullable) }
|
|
255
253
|
case "boolean":
|
|
256
|
-
return {externals: [], name: maybeNullable("Bool", nullable)}
|
|
254
|
+
return { externals: [], name: maybeNullable("Bool", nullable) }
|
|
257
255
|
case "number":
|
|
258
|
-
return {externals: [], name: maybeNullable("Int", nullable)}
|
|
256
|
+
return { externals: [], name: maybeNullable("Int", nullable) }
|
|
259
257
|
case "bytes":
|
|
260
|
-
return {externals: [], name: maybeNullable("DataWrapper", nullable)}
|
|
258
|
+
return { externals: [], name: maybeNullable("DataWrapper", nullable) }
|
|
261
259
|
case "void":
|
|
262
|
-
return {externals: [], name: maybeNullable("Void", nullable)}
|
|
260
|
+
return { externals: [], name: maybeNullable("Void", nullable) }
|
|
263
261
|
default:
|
|
264
|
-
return {externals: [baseName], name: maybeNullable(baseName, nullable)}
|
|
262
|
+
return { externals: [baseName], name: maybeNullable(baseName, nullable) }
|
|
265
263
|
}
|
|
266
264
|
}
|
|
267
265
|
|
|
268
266
|
function maybeNullable(name: string, nullable: boolean) {
|
|
269
267
|
return nullable ? `${name}?` : name
|
|
270
|
-
}
|
|
268
|
+
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import {Accumulator} from "./Accumulator.js"
|
|
2
|
-
import {EnumDefinition, FacadeDefinition, getArgs, LangGenerator, minusculize, RenderedType, StructDefinition, TypeRefDefinition} from "./common.js"
|
|
3
|
-
import {ParsedType, parseType} from "./Parser.js"
|
|
1
|
+
import { Accumulator } from "./Accumulator.js"
|
|
2
|
+
import { EnumDefinition, FacadeDefinition, getArgs, LangGenerator, minusculize, RenderedType, StructDefinition, TypeRefDefinition } from "./common.js"
|
|
3
|
+
import { ParsedType, parseType } from "./Parser.js"
|
|
4
4
|
import path from "path"
|
|
5
5
|
|
|
6
6
|
export class TypescriptGenerator implements LangGenerator {
|
|
7
|
-
|
|
8
7
|
generateGlobalDispatcher(name: string, facadeNames: Array<string>): string {
|
|
9
8
|
const acc = new Accumulator()
|
|
10
9
|
for (let facadeName of facadeNames) {
|
|
@@ -50,7 +49,7 @@ export class TypescriptGenerator implements LangGenerator {
|
|
|
50
49
|
acc.line(`export interface ${definition.name} {`)
|
|
51
50
|
let bodyGenerator = acc.indent()
|
|
52
51
|
for (const [fieldName, fieldType] of Object.entries(definition.fields)) {
|
|
53
|
-
const {name, externals} = typeNameTypescript(fieldType)
|
|
52
|
+
const { name, externals } = typeNameTypescript(fieldType)
|
|
54
53
|
for (const external of externals) {
|
|
55
54
|
acc.addImport(`import {${external}} from "./${external}.js"`)
|
|
56
55
|
}
|
|
@@ -59,7 +58,6 @@ export class TypescriptGenerator implements LangGenerator {
|
|
|
59
58
|
acc.line("}")
|
|
60
59
|
|
|
61
60
|
return acc.finish()
|
|
62
|
-
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
private generateDocComment(acc: Accumulator, comment: string | null | undefined) {
|
|
@@ -112,7 +110,7 @@ export class TypescriptGenerator implements LangGenerator {
|
|
|
112
110
|
const arg = getArgs(methodName, methodDef)
|
|
113
111
|
const decodedArgs = []
|
|
114
112
|
for (let i = 0; i < arg.length; i++) {
|
|
115
|
-
const {name: argName, type} = arg[i]
|
|
113
|
+
const { name: argName, type } = arg[i]
|
|
116
114
|
const renderedArgType = renderTypeAndAddImports(type, acc)
|
|
117
115
|
decodedArgs.push([argName, renderedArgType] as const)
|
|
118
116
|
}
|
|
@@ -154,62 +152,57 @@ export class TypescriptGenerator implements LangGenerator {
|
|
|
154
152
|
}
|
|
155
153
|
|
|
156
154
|
generateExtraFiles(): Record<string, string> {
|
|
157
|
-
return {}
|
|
155
|
+
return {}
|
|
158
156
|
}
|
|
159
157
|
|
|
160
158
|
generateTypeRef(outDir: string, definitionPath: string, definition: TypeRefDefinition): string {
|
|
161
159
|
const acc = new Accumulator()
|
|
162
160
|
let tsPath = definition.location.typescript
|
|
163
161
|
const isRelative = tsPath.startsWith(".")
|
|
164
|
-
const actualPath = (
|
|
165
|
-
? path.relative(
|
|
166
|
-
path.resolve(outDir),
|
|
167
|
-
path.resolve(definitionPath, tsPath)
|
|
168
|
-
)
|
|
169
|
-
: tsPath
|
|
162
|
+
const actualPath = isRelative ? path.relative(path.resolve(outDir), path.resolve(definitionPath, tsPath)) : tsPath
|
|
170
163
|
acc.line(`export {${definition.name}} from "${actualPath}"`)
|
|
171
164
|
|
|
172
165
|
return acc.finish()
|
|
173
166
|
}
|
|
174
167
|
|
|
175
|
-
generateEnum({name, values, doc}: EnumDefinition): string {
|
|
168
|
+
generateEnum({ name, values, doc }: EnumDefinition): string {
|
|
176
169
|
return new Accumulator()
|
|
177
|
-
.do(acc => this.generateDocComment(acc, doc))
|
|
170
|
+
.do((acc) => this.generateDocComment(acc, doc))
|
|
178
171
|
.line(`export const enum ${name} {`)
|
|
179
|
-
.indented(acc => acc.lines(values.map((value, index) => `${value} = ${index},`)))
|
|
172
|
+
.indented((acc) => acc.lines(values.map((value, index) => `${value} = ${index},`)))
|
|
180
173
|
.line("}")
|
|
181
174
|
.finish()
|
|
182
175
|
}
|
|
183
176
|
}
|
|
184
177
|
|
|
185
178
|
function renderTypescriptType(parsed: ParsedType): RenderedType {
|
|
186
|
-
const {baseName, nullable, external} = parsed
|
|
179
|
+
const { baseName, nullable, external } = parsed
|
|
187
180
|
switch (baseName) {
|
|
188
181
|
case "List":
|
|
189
182
|
const renderedListInner = renderTypescriptType(parsed.generics[0])
|
|
190
183
|
return {
|
|
191
184
|
externals: renderedListInner.externals,
|
|
192
|
-
name: maybeNullable(`ReadonlyArray<${renderedListInner.name}>`, nullable)
|
|
185
|
+
name: maybeNullable(`ReadonlyArray<${renderedListInner.name}>`, nullable),
|
|
193
186
|
}
|
|
194
187
|
case "Map":
|
|
195
188
|
const renderedKey = renderTypescriptType(parsed.generics[0])
|
|
196
189
|
const renderedValue = renderTypescriptType(parsed.generics[1])
|
|
197
190
|
return {
|
|
198
191
|
externals: [...renderedKey.externals, ...renderedValue.externals],
|
|
199
|
-
name: maybeNullable(`Record<${renderedKey.name}, ${renderedValue.name}>`, nullable)
|
|
192
|
+
name: maybeNullable(`Record<${renderedKey.name}, ${renderedValue.name}>`, nullable),
|
|
200
193
|
}
|
|
201
194
|
case "string":
|
|
202
|
-
return {externals: [], name: maybeNullable("string", nullable)}
|
|
195
|
+
return { externals: [], name: maybeNullable("string", nullable) }
|
|
203
196
|
case "boolean":
|
|
204
|
-
return {externals: [], name: maybeNullable("boolean", nullable)}
|
|
197
|
+
return { externals: [], name: maybeNullable("boolean", nullable) }
|
|
205
198
|
case "number":
|
|
206
|
-
return {externals: [], name: maybeNullable("number", nullable)}
|
|
199
|
+
return { externals: [], name: maybeNullable("number", nullable) }
|
|
207
200
|
case "bytes":
|
|
208
|
-
return {externals: [], name: maybeNullable("Uint8Array", nullable)}
|
|
201
|
+
return { externals: [], name: maybeNullable("Uint8Array", nullable) }
|
|
209
202
|
case "void":
|
|
210
|
-
return {externals: [], name: maybeNullable("void", nullable)}
|
|
203
|
+
return { externals: [], name: maybeNullable("void", nullable) }
|
|
211
204
|
default:
|
|
212
|
-
return {externals: [baseName], name: maybeNullable(baseName, nullable)}
|
|
205
|
+
return { externals: [baseName], name: maybeNullable(baseName, nullable) }
|
|
213
206
|
}
|
|
214
207
|
}
|
|
215
208
|
|
|
@@ -228,4 +221,4 @@ function renderTypeAndAddImports(name: string, acc: Accumulator) {
|
|
|
228
221
|
acc.addImport(`import {${external}} from "./${external}.js"`)
|
|
229
222
|
}
|
|
230
223
|
return rendered.name
|
|
231
|
-
}
|
|
224
|
+
}
|
package/lib/cli.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {generate} from "./index.js"
|
|
2
|
+
import { generate } from "./index.js"
|
|
3
3
|
import * as fs from "fs"
|
|
4
4
|
import * as path from "path"
|
|
5
|
-
import {globby} from "zx"
|
|
6
|
-
import {Platform} from "./common"
|
|
7
|
-
import {Argument, Option, program} from "commander"
|
|
5
|
+
import { globby } from "zx"
|
|
6
|
+
import { Platform } from "./common"
|
|
7
|
+
import { Argument, Option, program } from "commander"
|
|
8
8
|
import JSON5 from "json5"
|
|
9
9
|
|
|
10
10
|
const PLATFORMS: Array<Platform> = ["ios", "web", "android", "desktop"]
|
|
@@ -18,17 +18,23 @@ await program
|
|
|
18
18
|
.usage(USAGE)
|
|
19
19
|
.addArgument(new Argument("from_dir").argRequired())
|
|
20
20
|
.addArgument(new Argument("to_dir").argOptional())
|
|
21
|
-
.addOption(
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
.addOption(
|
|
22
|
+
new Option(
|
|
23
|
+
"-p, --platform <platform>",
|
|
24
|
+
"platform to generate code for. if not specified, from_dir must be omitted as well. In this case, licc will read <from_dir>/.liccc as a json map from platform to output dir. if -p is set, from_dir must be set as well.",
|
|
25
|
+
)
|
|
26
|
+
.makeOptionMandatory(false)
|
|
27
|
+
.choices(PLATFORMS),
|
|
24
28
|
)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
assert(
|
|
31
|
-
|
|
29
|
+
.action(async (from_dir, to_dir, { platform }) => {
|
|
30
|
+
assert(
|
|
31
|
+
!(platform == null && to_dir != null),
|
|
32
|
+
"can't omit platform and use an explicit output dir. specify both -p <platform> and to_dir or none of them.",
|
|
33
|
+
)
|
|
34
|
+
assert(
|
|
35
|
+
!(platform != null && to_dir == null),
|
|
36
|
+
"can't use an explicit platform but no output dir. specify both -p <platform> and to_dir or none of them.",
|
|
37
|
+
)
|
|
32
38
|
|
|
33
39
|
let conf: Record<string, string> = {}
|
|
34
40
|
if (platform != null) {
|
|
@@ -37,7 +43,7 @@ await program
|
|
|
37
43
|
// check if there's a .liccc file that states the desired platforms and output dirs
|
|
38
44
|
const confPath = path.join(from_dir, ".liccc")
|
|
39
45
|
try {
|
|
40
|
-
const relConf: Record<Platform, string> = JSON5.parse(await fs.promises.readFile(confPath, {encoding: "utf-8"}))
|
|
46
|
+
const relConf: Record<Platform, string> = JSON5.parse(await fs.promises.readFile(confPath, { encoding: "utf-8" }))
|
|
41
47
|
for (let [relPlatform, relPath] of Object.entries(relConf) as [Platform | "__comment", string][]) {
|
|
42
48
|
if (relPlatform === "__comment") continue
|
|
43
49
|
assert(PLATFORMS.includes(relPlatform), `invalid platform in .liccc: ${relPlatform}`)
|
|
@@ -53,12 +59,8 @@ await program
|
|
|
53
59
|
.parseAsync(process.argv)
|
|
54
60
|
|
|
55
61
|
async function run(from_dir: string, conf: Record<Platform, string>): Promise<void> {
|
|
56
|
-
const inputFiles = await globby(["*/**/*.json", "*/**/*.json5"].map(glob => path.join(process.cwd(), from_dir, glob)))
|
|
57
|
-
const inputMap = new Map(
|
|
58
|
-
inputFiles.map((n: string) => (
|
|
59
|
-
[path.basename(n, n.endsWith("5") ? ".json5" : ".json"), fs.readFileSync(n, "utf8")]
|
|
60
|
-
))
|
|
61
|
-
)
|
|
62
|
+
const inputFiles = await globby(["*/**/*.json", "*/**/*.json5"].map((glob) => path.join(process.cwd(), from_dir, glob)))
|
|
63
|
+
const inputMap = new Map(inputFiles.map((n: string) => [path.basename(n, n.endsWith("5") ? ".json5" : ".json"), fs.readFileSync(n, "utf8")]))
|
|
62
64
|
|
|
63
65
|
// doing it here because some platforms generate into the same dir.
|
|
64
66
|
for (let outDir of Object.values(conf)) {
|
|
@@ -68,7 +70,7 @@ async function run(from_dir: string, conf: Record<Platform, string>): Promise<vo
|
|
|
68
70
|
for (let [confPlatform, confOutDir] of Object.entries(conf)) {
|
|
69
71
|
console.log("generating for", confPlatform, "into", confOutDir)
|
|
70
72
|
try {
|
|
71
|
-
await generate(confPlatform as Platform, inputMap, confOutDir
|
|
73
|
+
await generate(confPlatform as Platform, inputMap, confOutDir)
|
|
72
74
|
} catch (e) {
|
|
73
75
|
assert(false, `compilation failed with ${e}`)
|
|
74
76
|
}
|
package/lib/common.ts
CHANGED
|
@@ -50,7 +50,7 @@ export interface FacadeDefinition {
|
|
|
50
50
|
senders: Array<Platform>
|
|
51
51
|
receivers: Array<Platform>
|
|
52
52
|
methods: Record<string, MethodDefinition>
|
|
53
|
-
doc?: string
|
|
53
|
+
doc?: string
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
export interface TypeRefDefinition {
|
|
@@ -66,8 +66,8 @@ export interface MethodDefinition {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
export interface EnumDefinition {
|
|
69
|
-
type: "enum"
|
|
70
|
-
name: string
|
|
69
|
+
type: "enum"
|
|
70
|
+
name: string
|
|
71
71
|
values: Array<string>
|
|
72
72
|
doc?: string
|
|
73
73
|
}
|
|
@@ -75,11 +75,11 @@ export interface EnumDefinition {
|
|
|
75
75
|
export type ArgumentDefinition = Record<string, string>
|
|
76
76
|
|
|
77
77
|
export interface RenderedType {
|
|
78
|
-
externals: string[]
|
|
78
|
+
externals: string[]
|
|
79
79
|
name: string
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
export function getArgs(methName: string, methodDef: MethodDefinition): {name: string
|
|
82
|
+
export function getArgs(methName: string, methodDef: MethodDefinition): { name: string; type: string }[] {
|
|
83
83
|
return methodDef.arg.map((a, i) => {
|
|
84
84
|
const entries = Object.entries(a)
|
|
85
85
|
if (entries.length === 0) {
|
|
@@ -87,14 +87,14 @@ export function getArgs(methName: string, methodDef: MethodDefinition): {name: s
|
|
|
87
87
|
} else if (entries.length > 1) {
|
|
88
88
|
throw new Error(`Syntax Error: method ${methName} argument ${i} has too many entries`)
|
|
89
89
|
}
|
|
90
|
-
return {
|
|
90
|
+
return { name: entries[0][0], type: entries[0][1] }
|
|
91
91
|
})
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
export function capitalize(input: string): string {
|
|
95
|
-
return input.replace(/^\w/, c => c.toUpperCase())
|
|
95
|
+
return input.replace(/^\w/, (c) => c.toUpperCase())
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
export function minusculize(input: string): string {
|
|
99
|
-
return input.replace(/^\w/, c => c.toLowerCase())
|
|
100
|
-
}
|
|
99
|
+
return input.replace(/^\w/, (c) => c.toLowerCase())
|
|
100
|
+
}
|
package/lib/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {TypescriptGenerator} from "./TypescriptGenerator.js"
|
|
2
|
-
import {capitalize, EnumDefinition, FacadeDefinition, LangGenerator, Language, Platform, StructDefinition, TypeRefDefinition} from "./common.js"
|
|
3
|
-
import {SwiftGenerator} from "./SwiftGenerator.js"
|
|
4
|
-
import {KotlinGenerator} from "./KotlinGenerator.js"
|
|
1
|
+
import { TypescriptGenerator } from "./TypescriptGenerator.js"
|
|
2
|
+
import { capitalize, EnumDefinition, FacadeDefinition, LangGenerator, Language, Platform, StructDefinition, TypeRefDefinition } from "./common.js"
|
|
3
|
+
import { SwiftGenerator } from "./SwiftGenerator.js"
|
|
4
|
+
import { KotlinGenerator } from "./KotlinGenerator.js"
|
|
5
5
|
import * as path from "path"
|
|
6
6
|
import * as fs from "fs"
|
|
7
7
|
import JSON5 from "json5"
|
|
@@ -117,15 +117,15 @@ function getFileExtensionForLang(lang: string): string {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
function write(code: string, outDir: string, target: string) {
|
|
120
|
-
fs.mkdirSync(outDir, {recursive: true})
|
|
120
|
+
fs.mkdirSync(outDir, { recursive: true })
|
|
121
121
|
const filePath = path.join(outDir, target)
|
|
122
122
|
fs.writeFileSync(filePath, code)
|
|
123
123
|
console.log("written:", filePath)
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
function assertReturnTypesPresent(definition: FacadeDefinition): void {
|
|
127
|
-
const methNoRet = Object.entries(definition.methods).find(([_, {ret}]) => ret == null)
|
|
127
|
+
const methNoRet = Object.entries(definition.methods).find(([_, { ret }]) => ret == null)
|
|
128
128
|
if (methNoRet) {
|
|
129
129
|
throw new Error(`missing return type on method ${methNoRet[0]} in ${definition.name}`)
|
|
130
130
|
}
|
|
131
|
-
}
|
|
131
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tutao/licc",
|
|
3
|
-
"version": "3.106.
|
|
3
|
+
"version": "3.106.5",
|
|
4
4
|
"bin": {
|
|
5
5
|
"licc": "dist/cli.js"
|
|
6
6
|
},
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"zx": "6.1.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@tutao/tutanota-test-utils": "3.106.
|
|
23
|
+
"@tutao/tutanota-test-utils": "3.106.5",
|
|
24
24
|
"ospec": "https://github.com/tutao/ospec.git#0472107629ede33be4c4d19e89f237a6d7b0cb11"
|
|
25
25
|
}
|
|
26
26
|
}
|