@saltify/milky-generator 0.1.0 → 0.1.1
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/cli.mjs +461 -507
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -32,58 +32,120 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
32
32
|
var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
33
33
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
34
34
|
//#endregion
|
|
35
|
-
//#region ../common/src/generator/
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
function toUpperCamelCase$2(s) {
|
|
40
|
-
const lower = toLowerCamelCase$2(s);
|
|
41
|
-
return lower.charAt(0).toUpperCase() + lower.slice(1);
|
|
35
|
+
//#region ../common/src/generator/shared/naming.ts
|
|
36
|
+
const preserveFullCapitalizedWords = new Set(["csrf"]);
|
|
37
|
+
function snakeCaseToLowerCamelCase(value) {
|
|
38
|
+
return value.replace(/_([a-z])/g, (_, char) => char.toUpperCase());
|
|
42
39
|
}
|
|
43
|
-
function
|
|
44
|
-
|
|
40
|
+
function snakeCaseToUpperCamelCase(value) {
|
|
41
|
+
const lowerCamelCase = snakeCaseToLowerCamelCase(value);
|
|
42
|
+
return lowerCamelCase.charAt(0).toUpperCase() + lowerCamelCase.slice(1);
|
|
45
43
|
}
|
|
46
|
-
function
|
|
47
|
-
return
|
|
44
|
+
function snakeCaseToPascalCase(value) {
|
|
45
|
+
return value.split("_").map((part) => preserveFullCapitalizedWords.has(part) ? part.toUpperCase() : part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
48
46
|
}
|
|
49
|
-
function
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
function normalizeDerivedStructName(structName, tagValue) {
|
|
48
|
+
const tagValuePascalCase = snakeCaseToPascalCase(tagValue);
|
|
49
|
+
const lastCapitalIndex = structName.split("").reverse().findIndex((char) => char >= "A" && char <= "Z");
|
|
50
|
+
if (lastCapitalIndex === -1) return structName + tagValuePascalCase;
|
|
51
|
+
const insertPosition = structName.length - lastCapitalIndex - 1;
|
|
52
|
+
return structName.slice(0, insertPosition) + tagValuePascalCase + structName.slice(insertPosition);
|
|
52
53
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region ../common/src/generator/shared/ir.ts
|
|
56
|
+
function getApiTypeNames(endpoint) {
|
|
57
|
+
const pascalEndpoint = snakeCaseToPascalCase(endpoint);
|
|
58
|
+
return {
|
|
59
|
+
pascalEndpoint,
|
|
60
|
+
inputName: `${pascalEndpoint}Input`,
|
|
61
|
+
outputName: `${pascalEndpoint}Output`,
|
|
62
|
+
requestName: `${pascalEndpoint}Request`,
|
|
63
|
+
responseName: `${pascalEndpoint}Response`
|
|
60
64
|
};
|
|
65
|
+
}
|
|
66
|
+
function isSameField(first, second) {
|
|
67
|
+
if (first.name !== second.name) return false;
|
|
68
|
+
if (first.fieldType !== second.fieldType) return false;
|
|
69
|
+
if (first.isArray !== second.isArray) return false;
|
|
70
|
+
if (first.isOptional !== second.isOptional) return false;
|
|
71
|
+
if (first.fieldType === "scalar" && second.fieldType === "scalar") return first.scalarType === second.scalarType;
|
|
72
|
+
if (first.fieldType === "ref" && second.fieldType === "ref") return first.refStructName === second.refStructName;
|
|
73
|
+
if (first.fieldType === "enum" && second.fieldType === "enum") return first.values.join("\0") === second.values.join("\0");
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
function collectUnionStructNames(ir) {
|
|
77
|
+
return new Set(ir.commonStructs.filter((struct) => struct.structType === "union").map((struct) => struct.name));
|
|
78
|
+
}
|
|
79
|
+
function visitAllFieldCollections(ir, visit) {
|
|
61
80
|
ir.commonStructs.forEach((struct) => {
|
|
62
81
|
if (struct.structType === "simple") {
|
|
63
|
-
|
|
82
|
+
visit(struct.fields);
|
|
64
83
|
return;
|
|
65
84
|
}
|
|
66
85
|
if (struct.unionType === "withData") {
|
|
67
|
-
|
|
86
|
+
visit(struct.baseFields);
|
|
68
87
|
struct.derivedTypes.forEach((derivedType) => {
|
|
69
|
-
if (derivedType.derivingType === "struct")
|
|
88
|
+
if (derivedType.derivingType === "struct") visit(derivedType.fields);
|
|
70
89
|
});
|
|
71
90
|
return;
|
|
72
91
|
}
|
|
73
92
|
struct.derivedStructs.forEach((derivedStruct) => {
|
|
74
|
-
|
|
93
|
+
visit(derivedStruct.fields);
|
|
75
94
|
});
|
|
76
95
|
});
|
|
77
96
|
ir.apiCategories.forEach((category) => {
|
|
78
97
|
category.apis.forEach((api) => {
|
|
79
|
-
if (api.requestFields)
|
|
80
|
-
if (api.responseFields)
|
|
98
|
+
if (api.requestFields) visit(api.requestFields);
|
|
99
|
+
if (api.responseFields) visit(api.responseFields);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function collectArrayUnionRefs(ir, unionStructNames = collectUnionStructNames(ir)) {
|
|
104
|
+
const arrayUnionRefs = /* @__PURE__ */ new Set();
|
|
105
|
+
visitAllFieldCollections(ir, (fields) => {
|
|
106
|
+
fields.forEach((field) => {
|
|
107
|
+
if (field.fieldType === "ref" && field.isArray && unionStructNames.has(field.refStructName)) arrayUnionRefs.add(field.refStructName);
|
|
81
108
|
});
|
|
82
109
|
});
|
|
83
110
|
return arrayUnionRefs;
|
|
84
111
|
}
|
|
112
|
+
function getPlainUnionCommonFields(struct) {
|
|
113
|
+
if (struct.derivedStructs.length === 0) return [];
|
|
114
|
+
let commonFields = [...struct.derivedStructs[0].fields];
|
|
115
|
+
for (let index = 1; index < struct.derivedStructs.length; index++) commonFields = commonFields.filter((field) => struct.derivedStructs[index].fields.some((candidate) => isSameField(field, candidate)));
|
|
116
|
+
return commonFields;
|
|
117
|
+
}
|
|
118
|
+
//#endregion
|
|
119
|
+
//#region ../common/src/generator/shared/text.ts
|
|
120
|
+
function createLineWriter() {
|
|
121
|
+
const lines = [];
|
|
122
|
+
return {
|
|
123
|
+
lines,
|
|
124
|
+
line(value = "") {
|
|
125
|
+
lines.push(value);
|
|
126
|
+
},
|
|
127
|
+
toString() {
|
|
128
|
+
return lines.join("\n");
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function indentLines(text, indent = " ") {
|
|
133
|
+
return text.split("\n").map((line) => line.trim() ? indent + line : line).join("\n");
|
|
134
|
+
}
|
|
135
|
+
function formatDocComment(text, prefix = "/// ") {
|
|
136
|
+
return text.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => `${prefix}${line}`);
|
|
137
|
+
}
|
|
138
|
+
//#endregion
|
|
139
|
+
//#region ../common/src/generator/dart/json_serializable.ts
|
|
140
|
+
function formatDartLiteral(value) {
|
|
141
|
+
return JSON.stringify(value);
|
|
142
|
+
}
|
|
143
|
+
function resolveDefaultValue$1(value) {
|
|
144
|
+
if (typeof value === "function") return value();
|
|
145
|
+
return value;
|
|
146
|
+
}
|
|
85
147
|
function renderDropBadElementListHelper(typeName) {
|
|
86
|
-
const className =
|
|
148
|
+
const className = snakeCaseToUpperCamelCase(typeName);
|
|
87
149
|
return [
|
|
88
150
|
`List<${className}> _dropBad${className}ListFromJson(Object? json) {`,
|
|
89
151
|
` if (json == null) {`,
|
|
@@ -154,12 +216,12 @@ function getDartTypeSpec(field) {
|
|
|
154
216
|
else if (field.scalarType === "string") baseType = "String";
|
|
155
217
|
else baseType = "int";
|
|
156
218
|
else if (field.fieldType === "enum") baseType = "String";
|
|
157
|
-
else baseType =
|
|
219
|
+
else baseType = snakeCaseToUpperCamelCase(field.refStructName);
|
|
158
220
|
return field.isArray ? `List<${baseType}>` : baseType;
|
|
159
221
|
}
|
|
160
222
|
function renderFieldLines$1(key, field, unionStructNames, typeOverride) {
|
|
161
223
|
const lines = [];
|
|
162
|
-
const fieldName =
|
|
224
|
+
const fieldName = snakeCaseToLowerCamelCase(key);
|
|
163
225
|
const description = field.description;
|
|
164
226
|
const baseType = typeOverride ?? getDartTypeSpec(field);
|
|
165
227
|
const hasDefault = field.defaultValue !== void 0;
|
|
@@ -169,19 +231,19 @@ function renderFieldLines$1(key, field, unionStructNames, typeOverride) {
|
|
|
169
231
|
const jsonKeyParts = [`name: "${key}"`];
|
|
170
232
|
if (field.fieldType === "ref" && field.isArray) {
|
|
171
233
|
if (field.refStructName === "IncomingSegment") jsonKeyParts.push("fromJson: _incomingSegmentListFromJson");
|
|
172
|
-
else if (unionStructNames.has(field.refStructName)) jsonKeyParts.push(`fromJson: _dropBad${
|
|
234
|
+
else if (unionStructNames.has(field.refStructName)) jsonKeyParts.push(`fromJson: _dropBad${snakeCaseToUpperCamelCase(field.refStructName)}ListFromJson`);
|
|
173
235
|
}
|
|
174
|
-
if (description) formatDocComment
|
|
236
|
+
if (description) formatDocComment(description).forEach((line) => lines.push(line));
|
|
175
237
|
if (hasDefault) lines.push(`@Default(${formatDartLiteral(resolveDefaultValue$1(field.defaultValue))})`);
|
|
176
238
|
lines.push(`@JsonKey(${jsonKeyParts.join(", ")})`);
|
|
177
239
|
lines.push(`${isRequired ? "required " : ""}${dartType} ${fieldName},`);
|
|
178
240
|
return lines;
|
|
179
241
|
}
|
|
180
242
|
function renderIRSimpleStruct$1(name, fields, description, unionStructNames) {
|
|
181
|
-
const className =
|
|
243
|
+
const className = snakeCaseToUpperCamelCase(name);
|
|
182
244
|
const entries = fields;
|
|
183
245
|
const lines = [];
|
|
184
|
-
if (description) lines.push(...formatDocComment
|
|
246
|
+
if (description) lines.push(...formatDocComment(description));
|
|
185
247
|
lines.push("@freezed");
|
|
186
248
|
lines.push(`abstract class ${className} with _$${className} {`);
|
|
187
249
|
if (entries.length === 0) lines.push(` const factory ${className}() = _${className};`);
|
|
@@ -201,21 +263,21 @@ function renderIRSimpleStruct$1(name, fields, description, unionStructNames) {
|
|
|
201
263
|
}
|
|
202
264
|
function renderIRUnionStruct$2(struct, unionStructNames) {
|
|
203
265
|
const name = struct.name;
|
|
204
|
-
const className =
|
|
266
|
+
const className = snakeCaseToUpperCamelCase(name);
|
|
205
267
|
const lines = [];
|
|
206
268
|
const extraDefs = [];
|
|
207
269
|
const discriminator = struct.tagFieldName;
|
|
208
|
-
if (struct.description) lines.push(...formatDocComment
|
|
270
|
+
if (struct.description) lines.push(...formatDocComment(struct.description));
|
|
209
271
|
lines.push(`@Freezed(unionKey: "${discriminator}")`);
|
|
210
272
|
lines.push(`abstract class ${className} with _$${className} {`);
|
|
211
273
|
if (struct.unionType === "withData") struct.derivedTypes.forEach((derivedType, index) => {
|
|
212
274
|
const variantValue = derivedType.tagValue;
|
|
213
|
-
const variantConstructor =
|
|
214
|
-
const variantClassName = `${className}${
|
|
275
|
+
const variantConstructor = snakeCaseToLowerCamelCase(variantValue);
|
|
276
|
+
const variantClassName = `${className}${snakeCaseToUpperCamelCase(variantValue)}`;
|
|
215
277
|
let dataTypeName;
|
|
216
|
-
if (derivedType.derivingType === "ref") dataTypeName =
|
|
278
|
+
if (derivedType.derivingType === "ref") dataTypeName = snakeCaseToUpperCamelCase(derivedType.refStructName);
|
|
217
279
|
else {
|
|
218
|
-
dataTypeName = `${className}${
|
|
280
|
+
dataTypeName = `${className}${snakeCaseToUpperCamelCase(variantValue)}Data`;
|
|
219
281
|
extraDefs.push(renderIRSimpleStruct$1(dataTypeName, derivedType.fields, "", unionStructNames));
|
|
220
282
|
}
|
|
221
283
|
lines.push(` @FreezedUnionValue("${variantValue}")`);
|
|
@@ -240,8 +302,8 @@ function renderIRUnionStruct$2(struct, unionStructNames) {
|
|
|
240
302
|
});
|
|
241
303
|
else struct.derivedStructs.forEach((derivedStruct, index) => {
|
|
242
304
|
const variantValue = derivedStruct.tagValue;
|
|
243
|
-
const variantConstructor =
|
|
244
|
-
const variantClassName = `${className}${
|
|
305
|
+
const variantConstructor = snakeCaseToLowerCamelCase(variantValue);
|
|
306
|
+
const variantClassName = `${className}${snakeCaseToUpperCamelCase(variantValue)}`;
|
|
245
307
|
lines.push(` @FreezedUnionValue("${variantValue}")`);
|
|
246
308
|
lines.push(` const factory ${className}.${variantConstructor}({`);
|
|
247
309
|
derivedStruct.fields.forEach((field) => {
|
|
@@ -262,8 +324,8 @@ function renderIRUnionStruct$2(struct, unionStructNames) {
|
|
|
262
324
|
}
|
|
263
325
|
function generateDartJsonSerializableSpec(ir) {
|
|
264
326
|
const lines = [];
|
|
265
|
-
const unionStructNames =
|
|
266
|
-
const arrayUnionRefs = collectArrayUnionRefs
|
|
327
|
+
const unionStructNames = collectUnionStructNames(ir);
|
|
328
|
+
const arrayUnionRefs = collectArrayUnionRefs(ir);
|
|
267
329
|
function l(line = "") {
|
|
268
330
|
lines.push(line);
|
|
269
331
|
}
|
|
@@ -332,11 +394,11 @@ function generateDartJsonSerializableSpec(ir) {
|
|
|
332
394
|
l(`// ---- ${category.name} ----`);
|
|
333
395
|
l();
|
|
334
396
|
category.apis.forEach((api) => {
|
|
335
|
-
const inputName = `${
|
|
397
|
+
const inputName = `${snakeCaseToUpperCamelCase(api.endpoint)}Input`;
|
|
336
398
|
if (api.requestFields && api.requestFields.length > 0) l(renderIRSimpleStruct$1(inputName, api.requestFields, "", unionStructNames));
|
|
337
399
|
else l(`typedef ${inputName} = ApiEmptyStruct;`);
|
|
338
400
|
l();
|
|
339
|
-
const outputName = `${
|
|
401
|
+
const outputName = `${snakeCaseToUpperCamelCase(api.endpoint)}Output`;
|
|
340
402
|
if (api.responseFields && api.responseFields.length > 0) l(renderIRSimpleStruct$1(outputName, api.responseFields, "", unionStructNames));
|
|
341
403
|
else if (api.responseFields) l(`typedef ${outputName} = ApiEmptyStruct;`);
|
|
342
404
|
else l(`typedef ${outputName} = ApiEmptyStruct;`);
|
|
@@ -357,10 +419,10 @@ function generateDartJsonSerializableSpec(ir) {
|
|
|
357
419
|
ir.apiCategories.forEach((category) => {
|
|
358
420
|
category.apis.forEach((api) => {
|
|
359
421
|
l(` /// ${api.description}`);
|
|
360
|
-
l(` static final ${
|
|
422
|
+
l(` static final ${snakeCaseToLowerCamelCase(api.endpoint)} = ApiEndpoint(`);
|
|
361
423
|
l(` "/${api.endpoint}",`);
|
|
362
|
-
l(` ${
|
|
363
|
-
l(` (${
|
|
424
|
+
l(` ${snakeCaseToUpperCamelCase(api.endpoint)}Input.fromJson,`);
|
|
425
|
+
l(` (${snakeCaseToUpperCamelCase(api.endpoint)}Output output) => output.toJson(),`);
|
|
364
426
|
l(" );");
|
|
365
427
|
});
|
|
366
428
|
});
|
|
@@ -2334,7 +2396,7 @@ const ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
|
|
|
2334
2396
|
inst.array = () => array(inst);
|
|
2335
2397
|
inst.or = (arg) => union([inst, arg]);
|
|
2336
2398
|
inst.and = (arg) => intersection(inst, arg);
|
|
2337
|
-
inst.transform = (tx) => pipe(inst, transform$
|
|
2399
|
+
inst.transform = (tx) => pipe(inst, transform$1(tx));
|
|
2338
2400
|
inst.default = (def) => _default(inst, def);
|
|
2339
2401
|
inst.prefault = (def) => prefault(inst, def);
|
|
2340
2402
|
inst.catch = (params) => _catch(inst, params);
|
|
@@ -2431,7 +2493,7 @@ const ZodTransform = /* @__PURE__ */ $constructor("ZodTransform", (inst, def) =>
|
|
|
2431
2493
|
return payload;
|
|
2432
2494
|
};
|
|
2433
2495
|
});
|
|
2434
|
-
function transform$
|
|
2496
|
+
function transform$1(fn) {
|
|
2435
2497
|
return new ZodTransform({
|
|
2436
2498
|
type: "transform",
|
|
2437
2499
|
transform: fn
|
|
@@ -2569,246 +2631,6 @@ function superRefine(fn) {
|
|
|
2569
2631
|
return /* @__PURE__ */ _superRefine(fn);
|
|
2570
2632
|
}
|
|
2571
2633
|
//#endregion
|
|
2572
|
-
//#region ../common/src/generator/typescript/common.ts
|
|
2573
|
-
const preserveFullCapitalizedWords$2 = ["csrf"];
|
|
2574
|
-
function snakeCaseToPascalCase$2(snakeCase) {
|
|
2575
|
-
return snakeCase.split("_").map((part) => preserveFullCapitalizedWords$2.includes(part) ? part.toUpperCase() : part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
2576
|
-
}
|
|
2577
|
-
function normalizeDerivedStructName(structName, tagValue) {
|
|
2578
|
-
const tagValuePascalCase = snakeCaseToPascalCase$2(tagValue);
|
|
2579
|
-
const lastCapitalIndex = structName.split("").reverse().findIndex((char) => char >= "A" && char <= "Z");
|
|
2580
|
-
if (lastCapitalIndex === -1) return structName + tagValuePascalCase;
|
|
2581
|
-
const insertPosition = structName.length - lastCapitalIndex - 1;
|
|
2582
|
-
return structName.slice(0, insertPosition) + tagValuePascalCase + structName.slice(insertPosition);
|
|
2583
|
-
}
|
|
2584
|
-
function getTypeScriptTypeProjection(field) {
|
|
2585
|
-
if (field.fieldType === "scalar") if (field.scalarType === "string") return "string";
|
|
2586
|
-
else if (field.scalarType === "bool") return "boolean";
|
|
2587
|
-
else return "number";
|
|
2588
|
-
else if (field.fieldType === "enum") return field.values.map((v) => `'${v}'`).join(" | ");
|
|
2589
|
-
else return field.refStructName;
|
|
2590
|
-
}
|
|
2591
|
-
//#endregion
|
|
2592
|
-
//#region ../common/src/generator/typescript/zod.ts
|
|
2593
|
-
const applyDropBadElementArrayStructs = ["GroupNotification"];
|
|
2594
|
-
const specialReplacements = new Map([["IncomingReplySegmentData.segments", " " + `get segments() {
|
|
2595
|
-
return z.array(z.lazy(() => IncomingSegment)).describe('回复消息内容');
|
|
2596
|
-
},`.trim()], ["OutgoingForwardSegmentData.messages", " " + `get messages() {
|
|
2597
|
-
return z.array(z.lazy(() => OutgoingForwardedMessage)).describe('合并转发消息内容');
|
|
2598
|
-
},`.trim()]]);
|
|
2599
|
-
function useLines$1() {
|
|
2600
|
-
const lines = [];
|
|
2601
|
-
function l(line = "") {
|
|
2602
|
-
lines.push(line);
|
|
2603
|
-
}
|
|
2604
|
-
return [lines, l];
|
|
2605
|
-
}
|
|
2606
|
-
function getZodTypeSpec(ir, field) {
|
|
2607
|
-
let typeSpec = "z.unknown()";
|
|
2608
|
-
if (field.fieldType === "scalar") if (field.dataType !== void 0) typeSpec = `z${snakeCaseToPascalCase$2(field.dataType)}`;
|
|
2609
|
-
else if (field.scalarType === "string") typeSpec = "z.string()";
|
|
2610
|
-
else if (field.scalarType === "bool") typeSpec = "z.boolean()";
|
|
2611
|
-
else typeSpec = "z.number().int().nonnegative()";
|
|
2612
|
-
else if (field.fieldType === "enum") typeSpec = `z.enum([${field.values.map((v) => `'${v}'`).join(", ")}])`;
|
|
2613
|
-
else typeSpec = `z.lazy(() => ${field.refStructName})`;
|
|
2614
|
-
if (field.isArray) if (field.fieldType === "ref") {
|
|
2615
|
-
const referredStruct = ir.commonStructs.find((s) => s.name === field.refStructName);
|
|
2616
|
-
if (applyDropBadElementArrayStructs.includes(referredStruct.name)) typeSpec = `zDropBadElementArray(${field.refStructName})`;
|
|
2617
|
-
else typeSpec = `z.array(${typeSpec})`;
|
|
2618
|
-
} else typeSpec = `z.array(${typeSpec})`;
|
|
2619
|
-
if (field.isOptional) typeSpec += ".nullish()";
|
|
2620
|
-
else if (field.defaultValue !== void 0) typeSpec += `.nullish().default(${JSON.stringify(field.defaultValue).replace(/"/g, "'")}).transform<${getTypeScriptTypeProjection(field)}>((val) => val ?? ${JSON.stringify(field.defaultValue).replace(/"/g, "'")})`;
|
|
2621
|
-
return typeSpec;
|
|
2622
|
-
}
|
|
2623
|
-
function renderIRObject$1(ir, name, fields, description, withDescription = true, unionTagFieldName, unionTagValue) {
|
|
2624
|
-
const [lines, l] = useLines$1();
|
|
2625
|
-
l("z.object({");
|
|
2626
|
-
if (unionTagFieldName && unionTagValue) l(` ${unionTagFieldName}: z.literal('${unionTagValue}'),`);
|
|
2627
|
-
fields.forEach((field) => {
|
|
2628
|
-
const specialKey = `${name}.${field.name}`;
|
|
2629
|
-
if (specialReplacements.has(specialKey)) l(specialReplacements.get(specialKey));
|
|
2630
|
-
else l(` ${field.name}: ${getZodTypeSpec(ir, field)}.describe('${field.description}'),`);
|
|
2631
|
-
});
|
|
2632
|
-
if (withDescription) l(`}).describe('${description}')`);
|
|
2633
|
-
else l("})");
|
|
2634
|
-
return lines.join("\n");
|
|
2635
|
-
}
|
|
2636
|
-
function generateTypeScriptZodSpec(ir) {
|
|
2637
|
-
const [lines, l] = useLines$1();
|
|
2638
|
-
l(`// Generated from Milky ${ir.milkyVersion} (${ir.milkyPackageVersion})`);
|
|
2639
|
-
l(`
|
|
2640
|
-
import { z } from 'zod';
|
|
2641
|
-
|
|
2642
|
-
export const milkyVersion = '${ir.milkyVersion}';
|
|
2643
|
-
export const milkyPackageVersion = '${ir.milkyPackageVersion}';
|
|
2644
|
-
|
|
2645
|
-
export const zUin = z.number().int().min(10001).max(4294967295);
|
|
2646
|
-
|
|
2647
|
-
export function zDropBadElementArray<const T extends z.ZodDiscriminatedUnion>(element: T) {
|
|
2648
|
-
const schema = z.array(element.catch(null as never)).transform((val) => val.filter((item) => item !== null));
|
|
2649
|
-
return schema as unknown as z.ZodPipe<z.ZodArray<z.ZodCatch<z.ZodLazy<T>>>, z.ZodArray<z.ZodLazy<T>>>;
|
|
2650
|
-
}
|
|
2651
|
-
`.trim());
|
|
2652
|
-
l();
|
|
2653
|
-
l("// ####################################");
|
|
2654
|
-
l("// Common Structs");
|
|
2655
|
-
l("// ####################################");
|
|
2656
|
-
l();
|
|
2657
|
-
ir.commonStructs.forEach((struct) => {
|
|
2658
|
-
if (struct.structType === "simple") {
|
|
2659
|
-
l(`export const ${struct.name} = ${renderIRObject$1(ir, struct.name, struct.fields, struct.description, true)};`);
|
|
2660
|
-
l(`export type ${struct.name} = z.infer<typeof ${struct.name}>;`);
|
|
2661
|
-
} else {
|
|
2662
|
-
if (struct.unionType === "plain") {
|
|
2663
|
-
struct.derivedStructs.forEach((derived) => {
|
|
2664
|
-
l(`export const ${normalizeDerivedStructName(struct.name, derived.tagValue)} = ${renderIRObject$1(ir, struct.name, derived.fields, derived.description, true, struct.tagFieldName, derived.tagValue)};`);
|
|
2665
|
-
l(`export type ${normalizeDerivedStructName(struct.name, derived.tagValue)} = z.infer<typeof ${normalizeDerivedStructName(struct.name, derived.tagValue)}>;`);
|
|
2666
|
-
l();
|
|
2667
|
-
});
|
|
2668
|
-
l(`export const ${struct.name} = z.discriminatedUnion('${struct.tagFieldName}', [`);
|
|
2669
|
-
struct.derivedStructs.forEach((derived) => {
|
|
2670
|
-
l(` ${normalizeDerivedStructName(struct.name, derived.tagValue)},`);
|
|
2671
|
-
});
|
|
2672
|
-
} else {
|
|
2673
|
-
struct.derivedTypes.forEach((derived) => {
|
|
2674
|
-
const structName = normalizeDerivedStructName(struct.name, derived.tagValue) + "Data";
|
|
2675
|
-
if (derived.derivingType === "struct") {
|
|
2676
|
-
l(`export const ${structName} = ${renderIRObject$1(ir, structName, derived.fields, derived.description, true)};`);
|
|
2677
|
-
l(`export type ${structName} = z.infer<typeof ${structName}>;`);
|
|
2678
|
-
l();
|
|
2679
|
-
if (struct.name === "Event") {
|
|
2680
|
-
l(`export const ${normalizeDerivedStructName(struct.name, derived.tagValue)} = ${structName};`);
|
|
2681
|
-
l(`export type ${normalizeDerivedStructName(struct.name, derived.tagValue)} = z.infer<typeof ${structName}>;`);
|
|
2682
|
-
l();
|
|
2683
|
-
}
|
|
2684
|
-
}
|
|
2685
|
-
});
|
|
2686
|
-
l(`export const ${struct.name} = z.discriminatedUnion('${struct.tagFieldName}', [`);
|
|
2687
|
-
struct.derivedTypes.forEach((derived, index) => {
|
|
2688
|
-
l(" z.object({");
|
|
2689
|
-
l(` ${struct.tagFieldName}: z.literal('${derived.tagValue}'),`);
|
|
2690
|
-
struct.baseFields.forEach((field) => {
|
|
2691
|
-
l(` ${field.name}: ${getZodTypeSpec(ir, field)}.describe('${field.description}'),`);
|
|
2692
|
-
});
|
|
2693
|
-
if (derived.derivingType === "struct") {
|
|
2694
|
-
l(` data: ${normalizeDerivedStructName(struct.name, derived.tagValue)}Data.describe('${derived.description}'),`);
|
|
2695
|
-
l(` }).describe('${derived.description}'),`);
|
|
2696
|
-
} else {
|
|
2697
|
-
l(` data: z.lazy(() => ${derived.refStructName}).describe('${derived.description}'),`);
|
|
2698
|
-
l(` }).describe('${derived.description}'),`);
|
|
2699
|
-
}
|
|
2700
|
-
if (index !== struct.derivedTypes.length - 1) l();
|
|
2701
|
-
});
|
|
2702
|
-
}
|
|
2703
|
-
if (struct.name === "IncomingSegment") {
|
|
2704
|
-
l("]).catch({");
|
|
2705
|
-
l(" type: 'text',");
|
|
2706
|
-
l(" data: { text: '[unknown]' },");
|
|
2707
|
-
l(`}).describe('${struct.description}');`);
|
|
2708
|
-
} else l(`]).describe('${struct.description}');`);
|
|
2709
|
-
l(`export type ${struct.name} = z.infer<typeof ${struct.name}>;`);
|
|
2710
|
-
}
|
|
2711
|
-
l();
|
|
2712
|
-
});
|
|
2713
|
-
l("// ####################################");
|
|
2714
|
-
l("// API Structs");
|
|
2715
|
-
l("// ####################################");
|
|
2716
|
-
l();
|
|
2717
|
-
ir.apiCategories.forEach((category) => {
|
|
2718
|
-
category.apis.forEach((spec) => {
|
|
2719
|
-
const pascalEndpoint = snakeCaseToPascalCase$2(spec.endpoint);
|
|
2720
|
-
if (spec.requestFields) {
|
|
2721
|
-
l(`export const ${pascalEndpoint}Input = ` + renderIRObject$1(ir, `${pascalEndpoint}Input`, spec.requestFields, spec.endpoint + " 请求参数", true) + ";");
|
|
2722
|
-
l(`export type ${pascalEndpoint}Input = z.infer<typeof ${pascalEndpoint}Input>;`);
|
|
2723
|
-
l();
|
|
2724
|
-
}
|
|
2725
|
-
if (spec.responseFields) {
|
|
2726
|
-
l(`export const ${pascalEndpoint}Output = ` + renderIRObject$1(ir, `${pascalEndpoint}Output`, spec.responseFields, spec.endpoint + " 响应数据", true) + ";");
|
|
2727
|
-
l(`export type ${pascalEndpoint}Output = z.infer<typeof ${pascalEndpoint}Output>;`);
|
|
2728
|
-
l();
|
|
2729
|
-
}
|
|
2730
|
-
});
|
|
2731
|
-
});
|
|
2732
|
-
l("// ####################################");
|
|
2733
|
-
l("// Meta Information");
|
|
2734
|
-
l("// ####################################");
|
|
2735
|
-
l();
|
|
2736
|
-
l("export const zodCommonStructs = {");
|
|
2737
|
-
ir.commonStructs.forEach((struct) => {
|
|
2738
|
-
l(` ${struct.name},`);
|
|
2739
|
-
});
|
|
2740
|
-
l("};");
|
|
2741
|
-
l();
|
|
2742
|
-
l("export const zodApiCategories = {");
|
|
2743
|
-
ir.apiCategories.forEach((category) => {
|
|
2744
|
-
l(` ${category.key}: {`);
|
|
2745
|
-
l(` name: '${category.name}',`);
|
|
2746
|
-
l(" apis: {");
|
|
2747
|
-
category.apis.forEach((spec) => {
|
|
2748
|
-
l(` ${spec.endpoint}: {`);
|
|
2749
|
-
l(` description: '${spec.description}',`);
|
|
2750
|
-
l(` requestSchema: ${spec.requestFields ? `${snakeCaseToPascalCase$2(spec.endpoint)}Input` : "null"},`);
|
|
2751
|
-
l(` responseSchema: ${spec.responseFields ? `${snakeCaseToPascalCase$2(spec.endpoint)}Output` : "null"},`);
|
|
2752
|
-
l(" },");
|
|
2753
|
-
});
|
|
2754
|
-
l(" },");
|
|
2755
|
-
l(" },");
|
|
2756
|
-
});
|
|
2757
|
-
l("};");
|
|
2758
|
-
l();
|
|
2759
|
-
return lines.join("\n");
|
|
2760
|
-
}
|
|
2761
|
-
//#endregion
|
|
2762
|
-
//#region ../common/src/generator/common.ts
|
|
2763
|
-
const preserveFullCapitalizedWords$1 = ["csrf"];
|
|
2764
|
-
function snakeCaseToPascalCase$1(snakeCase) {
|
|
2765
|
-
return snakeCase.split("_").map((part) => preserveFullCapitalizedWords$1.includes(part) ? part.toUpperCase() : part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
2766
|
-
}
|
|
2767
|
-
async function importCodeAsModule(code) {
|
|
2768
|
-
return await import("data:text/javascript," + encodeURIComponent(code));
|
|
2769
|
-
}
|
|
2770
|
-
function initRegistry(ir, t) {
|
|
2771
|
-
globalRegistry._idmap.clear();
|
|
2772
|
-
ir.commonStructs.forEach((struct) => {
|
|
2773
|
-
let schema = t[struct.name];
|
|
2774
|
-
globalRegistry.add(schema, {
|
|
2775
|
-
id: struct.name,
|
|
2776
|
-
title: schema.description,
|
|
2777
|
-
description: schema.description
|
|
2778
|
-
});
|
|
2779
|
-
if (schema instanceof ZodCatch) schema = schema.def.innerType;
|
|
2780
|
-
if (schema instanceof ZodDiscriminatedUnion) schema.options.forEach((option) => {
|
|
2781
|
-
const optionAsZodObject = option;
|
|
2782
|
-
globalRegistry.add(optionAsZodObject, {
|
|
2783
|
-
title: optionAsZodObject.description,
|
|
2784
|
-
description: optionAsZodObject.description
|
|
2785
|
-
});
|
|
2786
|
-
});
|
|
2787
|
-
});
|
|
2788
|
-
ir.apiCategories.forEach((category) => {
|
|
2789
|
-
category.apis.forEach((spec) => {
|
|
2790
|
-
if (spec.requestFields !== void 0) {
|
|
2791
|
-
const requestId = `${snakeCaseToPascalCase$1(spec.endpoint)}Input`;
|
|
2792
|
-
const inputSchema = t[requestId];
|
|
2793
|
-
globalRegistry.add(inputSchema, {
|
|
2794
|
-
id: requestId,
|
|
2795
|
-
title: `${spec.endpoint} 请求参数`,
|
|
2796
|
-
description: `${spec.description} API 请求参数`
|
|
2797
|
-
});
|
|
2798
|
-
}
|
|
2799
|
-
if (spec.responseFields !== void 0) {
|
|
2800
|
-
const outputId = `${snakeCaseToPascalCase$1(spec.endpoint)}Output`;
|
|
2801
|
-
const outputSchema = t[outputId];
|
|
2802
|
-
globalRegistry.add(outputSchema, {
|
|
2803
|
-
id: outputId,
|
|
2804
|
-
title: `${spec.endpoint} 响应数据`,
|
|
2805
|
-
description: `${spec.description} API 响应数据`
|
|
2806
|
-
});
|
|
2807
|
-
}
|
|
2808
|
-
});
|
|
2809
|
-
});
|
|
2810
|
-
}
|
|
2811
|
-
//#endregion
|
|
2812
2634
|
//#region ../node_modules/.pnpm/sucrase@3.35.1/node_modules/sucrase/dist/parser/tokenizer/keywords.js
|
|
2813
2635
|
var require_keywords = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
2814
2636
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -23786,7 +23608,7 @@ var require_getTSImportedNames = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
23786
23608
|
}
|
|
23787
23609
|
}));
|
|
23788
23610
|
//#endregion
|
|
23789
|
-
//#region ../common/src/generator/
|
|
23611
|
+
//#region ../common/src/generator/typescript/shared.ts
|
|
23790
23612
|
var import_dist = (/* @__PURE__ */ __commonJSMin(((exports) => {
|
|
23791
23613
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23792
23614
|
function _interopRequireDefault(obj) {
|
|
@@ -23860,12 +23682,243 @@ var import_dist = (/* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
23860
23682
|
};
|
|
23861
23683
|
}
|
|
23862
23684
|
})))();
|
|
23863
|
-
|
|
23685
|
+
function getTypeScriptTypeProjection(field) {
|
|
23686
|
+
if (field.fieldType === "scalar") {
|
|
23687
|
+
if (field.scalarType === "string") return "string";
|
|
23688
|
+
if (field.scalarType === "bool") return "boolean";
|
|
23689
|
+
return "number";
|
|
23690
|
+
}
|
|
23691
|
+
if (field.fieldType === "enum") return field.values.map((value) => `'${value}'`).join(" | ");
|
|
23692
|
+
return field.refStructName;
|
|
23693
|
+
}
|
|
23694
|
+
//#endregion
|
|
23695
|
+
//#region ../common/src/generator/typescript/zod.ts
|
|
23696
|
+
const applyDropBadElementArrayStructNames = new Set(["GroupNotification"]);
|
|
23697
|
+
const specialReplacements = new Map([["IncomingReplySegmentData.segments", " " + `get segments() {
|
|
23698
|
+
return z.array(z.lazy(() => IncomingSegment)).describe('回复消息内容');
|
|
23699
|
+
},`.trim()], ["OutgoingForwardSegmentData.messages", " " + `get messages() {
|
|
23700
|
+
return z.array(z.lazy(() => OutgoingForwardedMessage)).describe('合并转发消息内容');
|
|
23701
|
+
},`.trim()]]);
|
|
23702
|
+
function formatTypeScriptLiteral(value) {
|
|
23703
|
+
return JSON.stringify(value).replace(/"/g, "'");
|
|
23704
|
+
}
|
|
23705
|
+
function getZodTypeSpec(ir, field, options = {}) {
|
|
23706
|
+
let typeSpec = "z.unknown()";
|
|
23707
|
+
if (field.fieldType === "scalar") if (field.dataType !== void 0) typeSpec = `z${snakeCaseToPascalCase(field.dataType)}`;
|
|
23708
|
+
else if (field.scalarType === "string") typeSpec = "z.string()";
|
|
23709
|
+
else if (field.scalarType === "bool") typeSpec = "z.boolean()";
|
|
23710
|
+
else typeSpec = "z.number().int().nonnegative()";
|
|
23711
|
+
else if (field.fieldType === "enum") typeSpec = `z.enum([${field.values.map((value) => `'${value}'`).join(", ")}])`;
|
|
23712
|
+
else typeSpec = `z.lazy(() => ${field.refStructName})`;
|
|
23713
|
+
if (field.isArray) if (field.fieldType === "ref") {
|
|
23714
|
+
const referredStruct = ir.commonStructs.find((struct) => struct.name === field.refStructName);
|
|
23715
|
+
if (options.dropBadElementArrayStructNames?.has(referredStruct.name)) typeSpec = `zDropBadElementArray(${field.refStructName})`;
|
|
23716
|
+
else typeSpec = `z.array(${typeSpec})`;
|
|
23717
|
+
} else typeSpec = `z.array(${typeSpec})`;
|
|
23718
|
+
if (field.isOptional) typeSpec += ".nullish()";
|
|
23719
|
+
else if (field.defaultValue !== void 0) {
|
|
23720
|
+
const defaultValueLiteral = formatTypeScriptLiteral(field.defaultValue);
|
|
23721
|
+
typeSpec += `.nullish().default(${defaultValueLiteral}).transform<${getTypeScriptTypeProjection(field)}>((val) => val ?? ${defaultValueLiteral})`;
|
|
23722
|
+
}
|
|
23723
|
+
return typeSpec;
|
|
23724
|
+
}
|
|
23725
|
+
function renderIRObject$1(ir, name, fields, description, withDescription = true, unionTagFieldName, unionTagValue) {
|
|
23726
|
+
const writer = createLineWriter();
|
|
23727
|
+
const l = writer.line;
|
|
23728
|
+
l("z.object({");
|
|
23729
|
+
if (unionTagFieldName && unionTagValue) l(` ${unionTagFieldName}: z.literal('${unionTagValue}'),`);
|
|
23730
|
+
fields.forEach((field) => {
|
|
23731
|
+
const specialKey = `${name}.${field.name}`;
|
|
23732
|
+
if (specialReplacements.has(specialKey)) l(specialReplacements.get(specialKey));
|
|
23733
|
+
else l(` ${field.name}: ${getZodTypeSpec(ir, field, { dropBadElementArrayStructNames: applyDropBadElementArrayStructNames })}.describe('${field.description}'),`);
|
|
23734
|
+
});
|
|
23735
|
+
if (withDescription) l(`}).describe('${description}')`);
|
|
23736
|
+
else l("})");
|
|
23737
|
+
return writer.toString();
|
|
23738
|
+
}
|
|
23739
|
+
function generateTypeScriptZodSpec(ir) {
|
|
23740
|
+
const writer = createLineWriter();
|
|
23741
|
+
const l = writer.line;
|
|
23742
|
+
l(`// Generated from Milky ${ir.milkyVersion} (${ir.milkyPackageVersion})`);
|
|
23743
|
+
l("import { z } from 'zod';");
|
|
23744
|
+
l();
|
|
23745
|
+
l(`export const milkyVersion = '${ir.milkyVersion}';`);
|
|
23746
|
+
l(`export const milkyPackageVersion = '${ir.milkyPackageVersion}';`);
|
|
23747
|
+
l();
|
|
23748
|
+
l("export const zUin = z.number().int().min(10001).max(4294967295);");
|
|
23749
|
+
l();
|
|
23750
|
+
l("export function zDropBadElementArray<const T extends z.ZodDiscriminatedUnion>(element: T) {");
|
|
23751
|
+
l(" const schema = z.array(element.catch(null as never)).transform((val) => val.filter((item) => item !== null));");
|
|
23752
|
+
l(" return schema as unknown as z.ZodPipe<z.ZodArray<z.ZodCatch<z.ZodLazy<T>>>, z.ZodArray<z.ZodLazy<T>>>;");
|
|
23753
|
+
l("}");
|
|
23754
|
+
l();
|
|
23755
|
+
l("// ####################################");
|
|
23756
|
+
l("// Common Structs");
|
|
23757
|
+
l("// ####################################");
|
|
23758
|
+
l();
|
|
23759
|
+
ir.commonStructs.forEach((struct) => {
|
|
23760
|
+
if (struct.structType === "simple") {
|
|
23761
|
+
l(`export const ${struct.name} = ${renderIRObject$1(ir, struct.name, struct.fields, struct.description, true)};`);
|
|
23762
|
+
l(`export type ${struct.name} = z.infer<typeof ${struct.name}>;`);
|
|
23763
|
+
} else {
|
|
23764
|
+
if (struct.unionType === "plain") {
|
|
23765
|
+
struct.derivedStructs.forEach((derived) => {
|
|
23766
|
+
l(`export const ${normalizeDerivedStructName(struct.name, derived.tagValue)} = ${renderIRObject$1(ir, struct.name, derived.fields, derived.description, true, struct.tagFieldName, derived.tagValue)};`);
|
|
23767
|
+
l(`export type ${normalizeDerivedStructName(struct.name, derived.tagValue)} = z.infer<typeof ${normalizeDerivedStructName(struct.name, derived.tagValue)}>;`);
|
|
23768
|
+
l();
|
|
23769
|
+
});
|
|
23770
|
+
l(`export const ${struct.name} = z.discriminatedUnion('${struct.tagFieldName}', [`);
|
|
23771
|
+
struct.derivedStructs.forEach((derived) => {
|
|
23772
|
+
l(` ${normalizeDerivedStructName(struct.name, derived.tagValue)},`);
|
|
23773
|
+
});
|
|
23774
|
+
} else {
|
|
23775
|
+
struct.derivedTypes.forEach((derived) => {
|
|
23776
|
+
const structName = normalizeDerivedStructName(struct.name, derived.tagValue) + "Data";
|
|
23777
|
+
if (derived.derivingType === "struct") {
|
|
23778
|
+
l(`export const ${structName} = ${renderIRObject$1(ir, structName, derived.fields, derived.description, true)};`);
|
|
23779
|
+
l(`export type ${structName} = z.infer<typeof ${structName}>;`);
|
|
23780
|
+
l();
|
|
23781
|
+
if (struct.name === "Event") {
|
|
23782
|
+
l(`export const ${normalizeDerivedStructName(struct.name, derived.tagValue)} = ${structName};`);
|
|
23783
|
+
l(`export type ${normalizeDerivedStructName(struct.name, derived.tagValue)} = z.infer<typeof ${structName}>;`);
|
|
23784
|
+
l();
|
|
23785
|
+
}
|
|
23786
|
+
}
|
|
23787
|
+
});
|
|
23788
|
+
l(`export const ${struct.name} = z.discriminatedUnion('${struct.tagFieldName}', [`);
|
|
23789
|
+
struct.derivedTypes.forEach((derived, index) => {
|
|
23790
|
+
l(" z.object({");
|
|
23791
|
+
l(` ${struct.tagFieldName}: z.literal('${derived.tagValue}'),`);
|
|
23792
|
+
struct.baseFields.forEach((field) => {
|
|
23793
|
+
l(` ${field.name}: ${getZodTypeSpec(ir, field, { dropBadElementArrayStructNames: applyDropBadElementArrayStructNames })}.describe('${field.description}'),`);
|
|
23794
|
+
});
|
|
23795
|
+
if (derived.derivingType === "struct") {
|
|
23796
|
+
l(` data: ${normalizeDerivedStructName(struct.name, derived.tagValue)}Data.describe('${derived.description}'),`);
|
|
23797
|
+
l(` }).describe('${derived.description}'),`);
|
|
23798
|
+
} else {
|
|
23799
|
+
l(` data: z.lazy(() => ${derived.refStructName}).describe('${derived.description}'),`);
|
|
23800
|
+
l(` }).describe('${derived.description}'),`);
|
|
23801
|
+
}
|
|
23802
|
+
if (index !== struct.derivedTypes.length - 1) l();
|
|
23803
|
+
});
|
|
23804
|
+
}
|
|
23805
|
+
if (struct.name === "IncomingSegment") {
|
|
23806
|
+
l("]).catch({");
|
|
23807
|
+
l(" type: 'text',");
|
|
23808
|
+
l(" data: { text: '[unknown]' },");
|
|
23809
|
+
l(`}).describe('${struct.description}');`);
|
|
23810
|
+
} else l(`]).describe('${struct.description}');`);
|
|
23811
|
+
l(`export type ${struct.name} = z.infer<typeof ${struct.name}>;`);
|
|
23812
|
+
}
|
|
23813
|
+
l();
|
|
23814
|
+
});
|
|
23815
|
+
l("// ####################################");
|
|
23816
|
+
l("// API Structs");
|
|
23817
|
+
l("// ####################################");
|
|
23818
|
+
l();
|
|
23819
|
+
ir.apiCategories.forEach((category) => {
|
|
23820
|
+
category.apis.forEach((spec) => {
|
|
23821
|
+
const typeNames = getApiTypeNames(spec.endpoint);
|
|
23822
|
+
if (spec.requestFields) {
|
|
23823
|
+
l(`export const ${typeNames.inputName} = ` + renderIRObject$1(ir, typeNames.inputName, spec.requestFields, spec.endpoint + " 请求参数", true) + ";");
|
|
23824
|
+
l(`export type ${typeNames.inputName} = z.infer<typeof ${typeNames.inputName}>;`);
|
|
23825
|
+
l();
|
|
23826
|
+
}
|
|
23827
|
+
if (spec.responseFields) {
|
|
23828
|
+
l(`export const ${typeNames.outputName} = ` + renderIRObject$1(ir, typeNames.outputName, spec.responseFields, spec.endpoint + " 响应数据", true) + ";");
|
|
23829
|
+
l(`export type ${typeNames.outputName} = z.infer<typeof ${typeNames.outputName}>;`);
|
|
23830
|
+
l();
|
|
23831
|
+
}
|
|
23832
|
+
});
|
|
23833
|
+
});
|
|
23834
|
+
l("// ####################################");
|
|
23835
|
+
l("// Meta Information");
|
|
23836
|
+
l("// ####################################");
|
|
23837
|
+
l();
|
|
23838
|
+
l("export const zodCommonStructs = {");
|
|
23839
|
+
ir.commonStructs.forEach((struct) => {
|
|
23840
|
+
l(` ${struct.name},`);
|
|
23841
|
+
});
|
|
23842
|
+
l("};");
|
|
23843
|
+
l();
|
|
23844
|
+
l("export const zodApiCategories = {");
|
|
23845
|
+
ir.apiCategories.forEach((category) => {
|
|
23846
|
+
l(` ${category.key}: {`);
|
|
23847
|
+
l(` name: '${category.name}',`);
|
|
23848
|
+
l(" apis: {");
|
|
23849
|
+
category.apis.forEach((spec) => {
|
|
23850
|
+
const typeNames = getApiTypeNames(spec.endpoint);
|
|
23851
|
+
l(` ${spec.endpoint}: {`);
|
|
23852
|
+
l(` description: '${spec.description}',`);
|
|
23853
|
+
l(` requestSchema: ${spec.requestFields ? typeNames.inputName : "null"},`);
|
|
23854
|
+
l(` responseSchema: ${spec.responseFields ? typeNames.outputName : "null"},`);
|
|
23855
|
+
l(" },");
|
|
23856
|
+
});
|
|
23857
|
+
l(" },");
|
|
23858
|
+
l(" },");
|
|
23859
|
+
});
|
|
23860
|
+
l("};");
|
|
23861
|
+
l();
|
|
23862
|
+
return writer.toString();
|
|
23863
|
+
}
|
|
23864
|
+
//#endregion
|
|
23865
|
+
//#region ../common/src/generator/shared/zod-runtime.ts
|
|
23866
|
+
const dynamicImport = new Function("specifier", "return import(specifier);");
|
|
23867
|
+
async function importCodeAsModule(code) {
|
|
23868
|
+
return await dynamicImport("data:text/javascript," + encodeURIComponent(code));
|
|
23869
|
+
}
|
|
23870
|
+
async function loadGeneratedZodTypesModule(ir) {
|
|
23864
23871
|
const { code } = (0, import_dist.transform)(generateTypeScriptZodSpec(ir), { transforms: ["typescript"] });
|
|
23865
23872
|
return await importCodeAsModule(code.replace("'zod'", `'${import.meta.resolve("zod")}'`));
|
|
23866
23873
|
}
|
|
23874
|
+
function initializeZodRegistry(ir, typesModule) {
|
|
23875
|
+
globalRegistry._idmap.clear();
|
|
23876
|
+
ir.commonStructs.forEach((struct) => {
|
|
23877
|
+
let schema = typesModule[struct.name];
|
|
23878
|
+
globalRegistry.add(schema, {
|
|
23879
|
+
id: struct.name,
|
|
23880
|
+
title: schema.description,
|
|
23881
|
+
description: schema.description
|
|
23882
|
+
});
|
|
23883
|
+
if (schema instanceof ZodCatch) schema = schema.def.innerType;
|
|
23884
|
+
if (schema instanceof ZodDiscriminatedUnion) schema.options.forEach((option) => {
|
|
23885
|
+
const optionAsZodObject = option;
|
|
23886
|
+
globalRegistry.add(optionAsZodObject, {
|
|
23887
|
+
title: optionAsZodObject.description,
|
|
23888
|
+
description: optionAsZodObject.description
|
|
23889
|
+
});
|
|
23890
|
+
});
|
|
23891
|
+
});
|
|
23892
|
+
ir.apiCategories.forEach((category) => {
|
|
23893
|
+
category.apis.forEach((api) => {
|
|
23894
|
+
const typeNames = getApiTypeNames(api.endpoint);
|
|
23895
|
+
if (api.requestFields !== void 0) {
|
|
23896
|
+
const inputSchema = typesModule[typeNames.inputName];
|
|
23897
|
+
globalRegistry.add(inputSchema, {
|
|
23898
|
+
id: typeNames.inputName,
|
|
23899
|
+
title: `${api.endpoint} 请求参数`,
|
|
23900
|
+
description: `${api.description} API 请求参数`
|
|
23901
|
+
});
|
|
23902
|
+
}
|
|
23903
|
+
if (api.responseFields !== void 0) {
|
|
23904
|
+
const outputSchema = typesModule[typeNames.outputName];
|
|
23905
|
+
globalRegistry.add(outputSchema, {
|
|
23906
|
+
id: typeNames.outputName,
|
|
23907
|
+
title: `${api.endpoint} 响应数据`,
|
|
23908
|
+
description: `${api.description} API 响应数据`
|
|
23909
|
+
});
|
|
23910
|
+
}
|
|
23911
|
+
});
|
|
23912
|
+
});
|
|
23913
|
+
}
|
|
23914
|
+
function sanitizeGeneratedSchema(schema) {
|
|
23915
|
+
const { $schema, ...rest } = schema;
|
|
23916
|
+
return rest;
|
|
23917
|
+
}
|
|
23918
|
+
//#endregion
|
|
23919
|
+
//#region ../common/src/generator/json-schema/index.ts
|
|
23867
23920
|
async function generateJsonSchema(ir, typesModule) {
|
|
23868
|
-
|
|
23921
|
+
initializeZodRegistry(ir, typesModule ?? await loadGeneratedZodTypesModule(ir));
|
|
23869
23922
|
return {
|
|
23870
23923
|
milkyVersion: ir.milkyVersion,
|
|
23871
23924
|
packageVersion: ir.milkyPackageVersion,
|
|
@@ -23877,16 +23930,6 @@ async function generateJsonSchema(ir, typesModule) {
|
|
|
23877
23930
|
}
|
|
23878
23931
|
//#endregion
|
|
23879
23932
|
//#region ../common/src/generator/kotlin/kotlinx-serialization.ts
|
|
23880
|
-
function toLowerCamelCase$1(s) {
|
|
23881
|
-
return s.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
23882
|
-
}
|
|
23883
|
-
function toUpperCamelCase$1(s) {
|
|
23884
|
-
const lower = toLowerCamelCase$1(s);
|
|
23885
|
-
return lower.charAt(0).toUpperCase() + lower.slice(1);
|
|
23886
|
-
}
|
|
23887
|
-
function indentLines(text, indent = " ") {
|
|
23888
|
-
return text.split("\n").map((line) => line.trim() ? indent + line : line).join("\n");
|
|
23889
|
-
}
|
|
23890
23933
|
function escapeString(str) {
|
|
23891
23934
|
return str.replace(/"/g, "\\\"");
|
|
23892
23935
|
}
|
|
@@ -23897,22 +23940,13 @@ function getKotlinTypeSpec(field, skipDefaultValue = false) {
|
|
|
23897
23940
|
else if (field.scalarType === "int64") baseType = "Long";
|
|
23898
23941
|
else baseType = "Int";
|
|
23899
23942
|
else if (field.fieldType === "enum") baseType = "String";
|
|
23900
|
-
else baseType =
|
|
23943
|
+
else baseType = snakeCaseToUpperCamelCase(field.refStructName);
|
|
23901
23944
|
const typeSpec = field.isArray ? `List<${baseType}>` : baseType;
|
|
23902
23945
|
if (skipDefaultValue) return field.isOptional ? `${typeSpec}?` : typeSpec;
|
|
23903
23946
|
if (field.defaultValue !== void 0) return `${typeSpec} = ${JSON.stringify(field.defaultValue)}`;
|
|
23904
23947
|
if (field.isOptional) return `${typeSpec}? = null`;
|
|
23905
23948
|
return typeSpec;
|
|
23906
23949
|
}
|
|
23907
|
-
function isSameField(f1, f2) {
|
|
23908
|
-
if (f1.name !== f2.name) return false;
|
|
23909
|
-
if (f1.fieldType !== f2.fieldType) return false;
|
|
23910
|
-
if (f1.isArray !== f2.isArray) return false;
|
|
23911
|
-
if (f1.isOptional !== f2.isOptional) return false;
|
|
23912
|
-
if (f1.fieldType === "scalar" && f2.fieldType === "scalar") return f1.scalarType === f2.scalarType;
|
|
23913
|
-
if (f1.fieldType === "ref" && f2.fieldType === "ref") return f1.refStructName === f2.refStructName;
|
|
23914
|
-
return true;
|
|
23915
|
-
}
|
|
23916
23950
|
function renderFieldAnnotations(ir, field, l) {
|
|
23917
23951
|
if (field.fieldType === "ref" && field.isArray) {
|
|
23918
23952
|
if (field.refStructName === "IncomingSegment") l(" @Serializable(with = TransformUnknownSegmentListSerializer::class)");
|
|
@@ -23928,17 +23962,17 @@ function renderIRObject(ir, name, fields, description, includeDesc = true, addit
|
|
|
23928
23962
|
l("@Serializable");
|
|
23929
23963
|
additionalAnnotations.forEach((annotation) => l(annotation));
|
|
23930
23964
|
if (fields.length > 0) {
|
|
23931
|
-
l(`data class ${
|
|
23965
|
+
l(`data class ${snakeCaseToUpperCamelCase(name)}(`);
|
|
23932
23966
|
fields.forEach((field) => {
|
|
23933
23967
|
const needsOverride = overrideFields.has(field.name);
|
|
23934
23968
|
const defaultValue = field.defaultValue !== void 0 ? JSON.stringify(field.defaultValue) : null;
|
|
23935
23969
|
const overridePrefix = needsOverride ? "override " : "";
|
|
23936
23970
|
l(` /** ${field.description ?? ""} */`);
|
|
23937
23971
|
renderFieldAnnotations(ir, field, l);
|
|
23938
|
-
l(` @SerialName("${field.name}")${defaultValue ? ` @LiteralDefault("${escapeString(defaultValue)}")` : ""} ${overridePrefix}val ${
|
|
23972
|
+
l(` @SerialName("${field.name}")${defaultValue ? ` @LiteralDefault("${escapeString(defaultValue)}")` : ""} ${overridePrefix}val ${snakeCaseToLowerCamelCase(field.name)}: ${getKotlinTypeSpec(field, needsOverride)},`);
|
|
23939
23973
|
});
|
|
23940
23974
|
l(")");
|
|
23941
|
-
} else l(`class ${
|
|
23975
|
+
} else l(`class ${snakeCaseToUpperCamelCase(name)}`);
|
|
23942
23976
|
return lines.join("\n");
|
|
23943
23977
|
}
|
|
23944
23978
|
function renderIRUnionStruct$1(ir, struct) {
|
|
@@ -23953,28 +23987,22 @@ function renderIRUnionStruct$1(ir, struct) {
|
|
|
23953
23987
|
if (struct.description) l(`/** ${struct.description} */`);
|
|
23954
23988
|
l("@Serializable");
|
|
23955
23989
|
l(`@JsonClassDiscriminator("${struct.tagFieldName}")`);
|
|
23956
|
-
l(`sealed class ${
|
|
23990
|
+
l(`sealed class ${snakeCaseToUpperCamelCase(name)} {`);
|
|
23957
23991
|
let commonFields = [];
|
|
23958
23992
|
if (struct.unionType === "withData") commonFields = struct.baseFields || [];
|
|
23959
|
-
else
|
|
23960
|
-
commonFields = [...struct.derivedStructs[0].fields];
|
|
23961
|
-
for (let i = 1; i < struct.derivedStructs.length; i++) {
|
|
23962
|
-
const currentStructFields = struct.derivedStructs[i].fields;
|
|
23963
|
-
commonFields = commonFields.filter((f1) => currentStructFields.some((f2) => isSameField(f1, f2)));
|
|
23964
|
-
}
|
|
23965
|
-
}
|
|
23993
|
+
else commonFields = getPlainUnionCommonFields(struct);
|
|
23966
23994
|
const commonFieldNames = /* @__PURE__ */ new Set();
|
|
23967
23995
|
if (commonFields.length > 0) {
|
|
23968
23996
|
commonFields.forEach((field) => {
|
|
23969
23997
|
commonFieldNames.add(field.name);
|
|
23970
23998
|
l(` /** ${field.description ?? ""} */`);
|
|
23971
|
-
l(` abstract val ${
|
|
23999
|
+
l(` abstract val ${snakeCaseToLowerCamelCase(field.name)}: ${getKotlinTypeSpec(field, true)}`);
|
|
23972
24000
|
});
|
|
23973
24001
|
l();
|
|
23974
24002
|
}
|
|
23975
24003
|
if (struct.unionType === "withData") struct.derivedTypes.forEach((derivedType, index) => {
|
|
23976
|
-
const variantName =
|
|
23977
|
-
const dataTypeName = derivedType.derivingType === "ref" ?
|
|
24004
|
+
const variantName = snakeCaseToUpperCamelCase(derivedType.tagValue);
|
|
24005
|
+
const dataTypeName = derivedType.derivingType === "ref" ? snakeCaseToUpperCamelCase(derivedType.refStructName) : "Data";
|
|
23978
24006
|
if (derivedType.description) l(` /** ${derivedType.description} */`);
|
|
23979
24007
|
l(" @Serializable");
|
|
23980
24008
|
l(` @SerialName("${derivedType.tagValue}")`);
|
|
@@ -23982,31 +24010,23 @@ function renderIRUnionStruct$1(ir, struct) {
|
|
|
23982
24010
|
struct.baseFields.forEach((field) => {
|
|
23983
24011
|
l(` /** ${field.description ?? ""} */`);
|
|
23984
24012
|
renderFieldAnnotations(ir, field, l);
|
|
23985
|
-
l(` @SerialName("${field.name}") override val ${
|
|
24013
|
+
l(` @SerialName("${field.name}") override val ${snakeCaseToLowerCamelCase(field.name)}: ${getKotlinTypeSpec(field, true)},`);
|
|
23986
24014
|
});
|
|
23987
24015
|
l(` /** 数据字段 */`);
|
|
23988
24016
|
l(` @SerialName("data") val data: ${dataTypeName}`);
|
|
23989
|
-
l(` ) : ${
|
|
24017
|
+
l(` ) : ${snakeCaseToUpperCamelCase(name)}()`);
|
|
23990
24018
|
const isStruct = derivedType.derivingType === "struct";
|
|
23991
24019
|
const isRef = derivedType.derivingType === "ref";
|
|
23992
24020
|
let targetFields = [];
|
|
23993
24021
|
let targetName = "Data";
|
|
23994
24022
|
if (isStruct) targetFields = derivedType.fields;
|
|
23995
24023
|
else if (isRef) {
|
|
23996
|
-
targetName =
|
|
24024
|
+
targetName = snakeCaseToUpperCamelCase(derivedType.refStructName);
|
|
23997
24025
|
const refStruct = ir.commonStructs.find((s) => s.name === derivedType.refStructName);
|
|
23998
24026
|
if (refStruct) {
|
|
23999
24027
|
if (refStruct.structType === "simple") targetFields = refStruct.fields;
|
|
24000
|
-
else if (refStruct.structType === "union")
|
|
24001
|
-
|
|
24002
|
-
else if (refStruct.derivedStructs && refStruct.derivedStructs.length > 0) {
|
|
24003
|
-
targetFields = [...refStruct.derivedStructs[0].fields];
|
|
24004
|
-
for (let i = 1; i < refStruct.derivedStructs.length; i++) {
|
|
24005
|
-
const currentStructFields = refStruct.derivedStructs[i].fields;
|
|
24006
|
-
targetFields = targetFields.filter((f1) => currentStructFields.some((f2) => isSameField(f1, f2)));
|
|
24007
|
-
}
|
|
24008
|
-
}
|
|
24009
|
-
}
|
|
24028
|
+
else if (refStruct.structType === "union") if (refStruct.unionType === "withData") targetFields = refStruct.baseFields || [];
|
|
24029
|
+
else targetFields = getPlainUnionCommonFields(refStruct);
|
|
24010
24030
|
}
|
|
24011
24031
|
}
|
|
24012
24032
|
if (isStruct || targetFields.length > 0) {
|
|
@@ -24016,7 +24036,7 @@ function renderIRUnionStruct$1(ir, struct) {
|
|
|
24016
24036
|
l();
|
|
24017
24037
|
}
|
|
24018
24038
|
targetFields.forEach((field) => {
|
|
24019
|
-
const realFieldName =
|
|
24039
|
+
const realFieldName = snakeCaseToLowerCamelCase(field.name);
|
|
24020
24040
|
let fieldName = realFieldName;
|
|
24021
24041
|
const fieldType = getKotlinTypeSpec(field, true);
|
|
24022
24042
|
if (commonFieldNames.has(field.name)) fieldName = `data${fieldName.charAt(0).toUpperCase() + fieldName.slice(1)}`;
|
|
@@ -24032,7 +24052,7 @@ function renderIRUnionStruct$1(ir, struct) {
|
|
|
24032
24052
|
});
|
|
24033
24053
|
else struct.derivedStructs.forEach((derivedStruct, index) => {
|
|
24034
24054
|
if (derivedStruct.description) l(` /** ${derivedStruct.description} */`);
|
|
24035
|
-
l(indentLines(renderIRObject(ir, derivedStruct.tagValue, derivedStruct.fields, "", false, [`@SerialName("${derivedStruct.tagValue}")`], commonFieldNames), " ") + ` : ${
|
|
24055
|
+
l(indentLines(renderIRObject(ir, derivedStruct.tagValue, derivedStruct.fields, "", false, [`@SerialName("${derivedStruct.tagValue}")`], commonFieldNames), " ") + ` : ${snakeCaseToUpperCamelCase(name)}()`);
|
|
24036
24056
|
if (index !== struct.derivedStructs.length - 1) l();
|
|
24037
24057
|
});
|
|
24038
24058
|
l("}");
|
|
@@ -24065,75 +24085,71 @@ function generateKotlinxSerializationSpec(ir) {
|
|
|
24065
24085
|
l(" explicitNulls = false");
|
|
24066
24086
|
l("}");
|
|
24067
24087
|
l();
|
|
24068
|
-
l(
|
|
24069
|
-
|
|
24070
|
-
val listSerializer = ListSerializer(elementSerializer)
|
|
24071
|
-
|
|
24072
|
-
override val descriptor: SerialDescriptor =
|
|
24073
|
-
listSerializer.descriptor
|
|
24074
|
-
|
|
24075
|
-
override fun serialize(encoder: Encoder, value: List<T>) {
|
|
24076
|
-
encoder.encodeSerializableValue(listSerializer, value)
|
|
24077
|
-
}
|
|
24078
|
-
|
|
24079
|
-
override fun deserialize(decoder: Decoder): List<T> {
|
|
24080
|
-
if (decoder !is JsonDecoder) {
|
|
24081
|
-
throw SerializationException("This serializer can be used only with Json format")
|
|
24082
|
-
}
|
|
24083
|
-
|
|
24084
|
-
val element = decoder.decodeJsonElement() as? JsonArray
|
|
24085
|
-
?: throw SerializationException("Expected JsonArray for List deserialization")
|
|
24086
|
-
|
|
24087
|
-
val out = ArrayList<T>(element.size)
|
|
24088
|
-
for (e in element) {
|
|
24089
|
-
try {
|
|
24090
|
-
out += decoder.json.decodeFromJsonElement(elementSerializer, e)
|
|
24091
|
-
} catch (_: SerializationException) {
|
|
24092
|
-
// discard bad element quietly
|
|
24093
|
-
}
|
|
24094
|
-
}
|
|
24095
|
-
return out
|
|
24096
|
-
}
|
|
24097
|
-
}
|
|
24098
|
-
`.trim());
|
|
24088
|
+
l("internal class DropBadElementListSerializer<T>(private val elementSerializer: KSerializer<T>) : KSerializer<List<T>> {");
|
|
24089
|
+
l(" val listSerializer = ListSerializer(elementSerializer)");
|
|
24099
24090
|
l();
|
|
24100
|
-
l(
|
|
24101
|
-
|
|
24102
|
-
|
|
24103
|
-
|
|
24104
|
-
|
|
24105
|
-
|
|
24106
|
-
|
|
24107
|
-
|
|
24108
|
-
|
|
24109
|
-
|
|
24110
|
-
|
|
24111
|
-
|
|
24112
|
-
|
|
24113
|
-
|
|
24114
|
-
|
|
24115
|
-
|
|
24116
|
-
|
|
24117
|
-
|
|
24118
|
-
|
|
24119
|
-
|
|
24120
|
-
|
|
24121
|
-
|
|
24122
|
-
|
|
24123
|
-
|
|
24124
|
-
|
|
24125
|
-
|
|
24126
|
-
|
|
24127
|
-
|
|
24128
|
-
|
|
24129
|
-
|
|
24130
|
-
|
|
24131
|
-
|
|
24132
|
-
|
|
24133
|
-
|
|
24134
|
-
|
|
24135
|
-
|
|
24136
|
-
|
|
24091
|
+
l(" override val descriptor: SerialDescriptor =");
|
|
24092
|
+
l(" listSerializer.descriptor");
|
|
24093
|
+
l();
|
|
24094
|
+
l(" override fun serialize(encoder: Encoder, value: List<T>) {");
|
|
24095
|
+
l(" encoder.encodeSerializableValue(listSerializer, value)");
|
|
24096
|
+
l(" }");
|
|
24097
|
+
l();
|
|
24098
|
+
l(" override fun deserialize(decoder: Decoder): List<T> {");
|
|
24099
|
+
l(" if (decoder !is JsonDecoder) {");
|
|
24100
|
+
l(" throw SerializationException(\"This serializer can be used only with Json format\")");
|
|
24101
|
+
l(" }");
|
|
24102
|
+
l();
|
|
24103
|
+
l(" val element = decoder.decodeJsonElement() as? JsonArray");
|
|
24104
|
+
l(" ?: throw SerializationException(\"Expected JsonArray for List deserialization\")");
|
|
24105
|
+
l();
|
|
24106
|
+
l(" val out = ArrayList<T>(element.size)");
|
|
24107
|
+
l(" for (e in element) {");
|
|
24108
|
+
l(" try {");
|
|
24109
|
+
l(" out += decoder.json.decodeFromJsonElement(elementSerializer, e)");
|
|
24110
|
+
l(" } catch (_: SerializationException) {");
|
|
24111
|
+
l(" // discard bad element quietly");
|
|
24112
|
+
l(" }");
|
|
24113
|
+
l(" }");
|
|
24114
|
+
l(" return out");
|
|
24115
|
+
l(" }");
|
|
24116
|
+
l("}");
|
|
24117
|
+
l();
|
|
24118
|
+
l("internal class TransformUnknownSegmentListSerializer(private val elementSerializer: KSerializer<IncomingSegment>) :");
|
|
24119
|
+
l(" KSerializer<List<IncomingSegment>> {");
|
|
24120
|
+
l();
|
|
24121
|
+
l(" val listSerializer = ListSerializer(elementSerializer)");
|
|
24122
|
+
l();
|
|
24123
|
+
l(" override val descriptor: SerialDescriptor =");
|
|
24124
|
+
l(" listSerializer.descriptor");
|
|
24125
|
+
l();
|
|
24126
|
+
l(" override fun serialize(encoder: Encoder, value: List<IncomingSegment>) {");
|
|
24127
|
+
l(" encoder.encodeSerializableValue(listSerializer, value)");
|
|
24128
|
+
l(" }");
|
|
24129
|
+
l();
|
|
24130
|
+
l(" override fun deserialize(decoder: Decoder): List<IncomingSegment> {");
|
|
24131
|
+
l(" if (decoder !is JsonDecoder) {");
|
|
24132
|
+
l(" throw SerializationException(\"This serializer can be used only with Json format\")");
|
|
24133
|
+
l(" }");
|
|
24134
|
+
l();
|
|
24135
|
+
l(" val element = decoder.decodeJsonElement() as? JsonArray");
|
|
24136
|
+
l(" ?: throw SerializationException(\"Expected JsonArray for List deserialization\")");
|
|
24137
|
+
l();
|
|
24138
|
+
l(" val out = ArrayList<IncomingSegment>(element.size)");
|
|
24139
|
+
l(" for (e in element) {");
|
|
24140
|
+
l(" out += try {");
|
|
24141
|
+
l(" decoder.json.decodeFromJsonElement(elementSerializer, e)");
|
|
24142
|
+
l(" } catch (_: SerializationException) {");
|
|
24143
|
+
l(" IncomingSegment.Text(");
|
|
24144
|
+
l(" data = IncomingSegment.Text.Data(");
|
|
24145
|
+
l(" text = \"[${e.jsonObject[\"type\"]!!.jsonPrimitive.content}]\"");
|
|
24146
|
+
l(" )");
|
|
24147
|
+
l(" )");
|
|
24148
|
+
l(" }");
|
|
24149
|
+
l(" }");
|
|
24150
|
+
l(" return out");
|
|
24151
|
+
l(" }");
|
|
24152
|
+
l("}");
|
|
24137
24153
|
l();
|
|
24138
24154
|
l("// ####################################");
|
|
24139
24155
|
l("// Common Structs");
|
|
@@ -24163,11 +24179,11 @@ internal class TransformUnknownSegmentListSerializer(private val elementSerializ
|
|
|
24163
24179
|
l(`// ---- ${category.name} ----`);
|
|
24164
24180
|
l();
|
|
24165
24181
|
category.apis.forEach((api) => {
|
|
24166
|
-
if (api.requestFields && api.requestFields.length > 0) l(renderIRObject(ir, `${
|
|
24167
|
-
else l(`typealias ${
|
|
24182
|
+
if (api.requestFields && api.requestFields.length > 0) l(renderIRObject(ir, `${snakeCaseToUpperCamelCase(api.endpoint)}Input`, api.requestFields, "", false));
|
|
24183
|
+
else l(`typealias ${snakeCaseToUpperCamelCase(api.endpoint)}Input = ApiEmptyStruct`);
|
|
24168
24184
|
l();
|
|
24169
|
-
if (api.responseFields) l(renderIRObject(ir, `${
|
|
24170
|
-
else l(`typealias ${
|
|
24185
|
+
if (api.responseFields) l(renderIRObject(ir, `${snakeCaseToUpperCamelCase(api.endpoint)}Output`, api.responseFields, "", false));
|
|
24186
|
+
else l(`typealias ${snakeCaseToUpperCamelCase(api.endpoint)}Output = ApiEmptyStruct`);
|
|
24171
24187
|
l();
|
|
24172
24188
|
});
|
|
24173
24189
|
});
|
|
@@ -24179,7 +24195,7 @@ internal class TransformUnknownSegmentListSerializer(private val elementSerializ
|
|
|
24179
24195
|
ir.apiCategories.forEach((category) => {
|
|
24180
24196
|
category.apis.forEach((api) => {
|
|
24181
24197
|
l(` /** ${api.description} */`);
|
|
24182
|
-
l(` object ${
|
|
24198
|
+
l(` object ${snakeCaseToUpperCamelCase(api.endpoint)} : ApiEndpoint<${snakeCaseToUpperCamelCase(api.endpoint)}Input, ${snakeCaseToUpperCamelCase(api.endpoint)}Output>("/${api.endpoint}")`);
|
|
24183
24199
|
});
|
|
24184
24200
|
});
|
|
24185
24201
|
l("}");
|
|
@@ -24244,14 +24260,6 @@ function generateMarkdownRoadmap(ir) {
|
|
|
24244
24260
|
}
|
|
24245
24261
|
//#endregion
|
|
24246
24262
|
//#region ../common/src/generator/openapi/index.ts
|
|
24247
|
-
const preserveFullCapitalizedWords = ["csrf"];
|
|
24248
|
-
function snakeCaseToPascalCase(snakeCase) {
|
|
24249
|
-
return snakeCase.split("_").map((part) => preserveFullCapitalizedWords.includes(part) ? part.toUpperCase() : part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
24250
|
-
}
|
|
24251
|
-
function sanitizeSchema(schema) {
|
|
24252
|
-
const { $schema, ...rest } = schema;
|
|
24253
|
-
return rest;
|
|
24254
|
-
}
|
|
24255
24263
|
function buildComponents() {
|
|
24256
24264
|
const jsonSchemas = toJSONSchema(globalRegistry, {
|
|
24257
24265
|
metadata: globalRegistry,
|
|
@@ -24259,7 +24267,7 @@ function buildComponents() {
|
|
|
24259
24267
|
target: "openapi-3.0",
|
|
24260
24268
|
uri: (id) => `#/components/schemas/${id}`
|
|
24261
24269
|
}).schemas;
|
|
24262
|
-
const schemas = Object.fromEntries(Object.entries(jsonSchemas ?? {}).map(([name, schema]) => [name,
|
|
24270
|
+
const schemas = Object.fromEntries(Object.entries(jsonSchemas ?? {}).map(([name, schema]) => [name, sanitizeGeneratedSchema(schema)]));
|
|
24263
24271
|
schemas.ApiResponse = {
|
|
24264
24272
|
type: "object",
|
|
24265
24273
|
required: ["status", "retcode"],
|
|
@@ -24291,8 +24299,9 @@ function buildPaths(ir) {
|
|
|
24291
24299
|
const paths = {};
|
|
24292
24300
|
ir.apiCategories.forEach((category) => {
|
|
24293
24301
|
category.apis.forEach((spec) => {
|
|
24294
|
-
const
|
|
24295
|
-
const
|
|
24302
|
+
const typeNames = getApiTypeNames(spec.endpoint);
|
|
24303
|
+
const requestIdOrNull = spec.requestFields && typeNames.inputName;
|
|
24304
|
+
const responseIdOrNull = spec.responseFields && typeNames.outputName;
|
|
24296
24305
|
paths[`/api/${spec.endpoint}`] = { post: {
|
|
24297
24306
|
tags: [category.name],
|
|
24298
24307
|
summary: spec.description,
|
|
@@ -24324,12 +24333,8 @@ function buildWebhooks() {
|
|
|
24324
24333
|
responses: { "200": { description: "已成功接收事件" } }
|
|
24325
24334
|
} } };
|
|
24326
24335
|
}
|
|
24327
|
-
async function initTypesModule(ir) {
|
|
24328
|
-
const { code } = (0, import_dist.transform)(generateTypeScriptZodSpec(ir), { transforms: ["typescript"] });
|
|
24329
|
-
return await importCodeAsModule(code.replace("'zod'", `'${import.meta.resolve("zod")}'`));
|
|
24330
|
-
}
|
|
24331
24336
|
async function generateOpenApiSpec(ir, typesModule) {
|
|
24332
|
-
|
|
24337
|
+
initializeZodRegistry(ir, typesModule ?? await loadGeneratedZodTypesModule(ir));
|
|
24333
24338
|
return {
|
|
24334
24339
|
openapi: "3.1.0",
|
|
24335
24340
|
info: {
|
|
@@ -24357,19 +24362,9 @@ async function generateOpenApiSpec(ir, typesModule) {
|
|
|
24357
24362
|
}
|
|
24358
24363
|
//#endregion
|
|
24359
24364
|
//#region ../common/src/generator/rust/serde.ts
|
|
24360
|
-
function toLowerCamelCase(s) {
|
|
24361
|
-
return s.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
24362
|
-
}
|
|
24363
|
-
function toUpperCamelCase(s) {
|
|
24364
|
-
const lower = toLowerCamelCase(s);
|
|
24365
|
-
return lower.charAt(0).toUpperCase() + lower.slice(1);
|
|
24366
|
-
}
|
|
24367
24365
|
function toSnakeCase(s) {
|
|
24368
24366
|
return s.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/-/g, "_").toLowerCase();
|
|
24369
24367
|
}
|
|
24370
|
-
function formatDocComment(text, indent = "") {
|
|
24371
|
-
return text.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => `${indent}/// ${line}`);
|
|
24372
|
-
}
|
|
24373
24368
|
function escapeRustString(str) {
|
|
24374
24369
|
let out = "\"";
|
|
24375
24370
|
for (const ch of str) switch (ch) {
|
|
@@ -24416,7 +24411,7 @@ function getRustBaseType(field) {
|
|
|
24416
24411
|
return "i32";
|
|
24417
24412
|
}
|
|
24418
24413
|
if (field.fieldType === "enum") return "String";
|
|
24419
|
-
return
|
|
24414
|
+
return snakeCaseToUpperCamelCase(field.refStructName);
|
|
24420
24415
|
}
|
|
24421
24416
|
function getRustTypeSpec(field) {
|
|
24422
24417
|
const baseType = getRustBaseType(field);
|
|
@@ -24480,40 +24475,6 @@ const rustKeywords = new Set([
|
|
|
24480
24475
|
function toRustFieldName(name) {
|
|
24481
24476
|
return rustKeywords.has(name) ? `r#${name}` : name;
|
|
24482
24477
|
}
|
|
24483
|
-
function collectUnionStructNames(ir) {
|
|
24484
|
-
return new Set(ir.commonStructs.filter((struct) => struct.structType === "union").map((struct) => struct.name));
|
|
24485
|
-
}
|
|
24486
|
-
function collectArrayUnionRefs(ir, unionStructNames) {
|
|
24487
|
-
const arrayUnionRefs = /* @__PURE__ */ new Set();
|
|
24488
|
-
const handleFields = (fields) => {
|
|
24489
|
-
fields.forEach((field) => {
|
|
24490
|
-
if (field.fieldType === "ref" && field.isArray && unionStructNames.has(field.refStructName)) arrayUnionRefs.add(field.refStructName);
|
|
24491
|
-
});
|
|
24492
|
-
};
|
|
24493
|
-
ir.commonStructs.forEach((struct) => {
|
|
24494
|
-
if (struct.structType === "simple") {
|
|
24495
|
-
handleFields(struct.fields);
|
|
24496
|
-
return;
|
|
24497
|
-
}
|
|
24498
|
-
if (struct.unionType === "withData") {
|
|
24499
|
-
handleFields(struct.baseFields);
|
|
24500
|
-
struct.derivedTypes.forEach((derivedType) => {
|
|
24501
|
-
if (derivedType.derivingType === "struct") handleFields(derivedType.fields);
|
|
24502
|
-
});
|
|
24503
|
-
return;
|
|
24504
|
-
}
|
|
24505
|
-
struct.derivedStructs.forEach((derivedStruct) => {
|
|
24506
|
-
handleFields(derivedStruct.fields);
|
|
24507
|
-
});
|
|
24508
|
-
});
|
|
24509
|
-
ir.apiCategories.forEach((category) => {
|
|
24510
|
-
category.apis.forEach((api) => {
|
|
24511
|
-
if (api.requestFields) handleFields(api.requestFields);
|
|
24512
|
-
if (api.responseFields) handleFields(api.responseFields);
|
|
24513
|
-
});
|
|
24514
|
-
});
|
|
24515
|
-
return arrayUnionRefs;
|
|
24516
|
-
}
|
|
24517
24478
|
function getArrayUnionDeserializeFn(field, unionStructNames) {
|
|
24518
24479
|
if (field.fieldType !== "ref" || !field.isArray || field.defaultValue !== void 0) return null;
|
|
24519
24480
|
const fnPrefix = field.isOptional ? "deserialize_optional_" : "deserialize_";
|
|
@@ -24522,7 +24483,7 @@ function getArrayUnionDeserializeFn(field, unionStructNames) {
|
|
|
24522
24483
|
return null;
|
|
24523
24484
|
}
|
|
24524
24485
|
function renderDropBadElementListHelpers(typeName) {
|
|
24525
|
-
const rustTypeName =
|
|
24486
|
+
const rustTypeName = snakeCaseToUpperCamelCase(typeName);
|
|
24526
24487
|
const snakeTypeName = toSnakeCase(typeName);
|
|
24527
24488
|
return [
|
|
24528
24489
|
`fn deserialize_drop_bad_${snakeTypeName}_list<'de, D>(deserializer: D) -> Result<Vec<${rustTypeName}>, D::Error>`,
|
|
@@ -24616,7 +24577,7 @@ function ensureDefaultHelpers(ctx, helperParts, fieldType, defaultValue) {
|
|
|
24616
24577
|
function renderFieldLines(field, ctx, helperParts, indent = " ", typeOverride, isPublic = true) {
|
|
24617
24578
|
const lines = [];
|
|
24618
24579
|
const rustFieldType = typeOverride ?? getRustTypeSpec(field);
|
|
24619
|
-
if (field.description) lines.push(...formatDocComment(field.description, indent));
|
|
24580
|
+
if (field.description) lines.push(...formatDocComment(field.description, `${indent}/// `));
|
|
24620
24581
|
const serdeArgs = [`rename = ${escapeRustString(field.name)}`];
|
|
24621
24582
|
const arrayUnionDeserializeFn = getArrayUnionDeserializeFn(field, ctx.unionStructNames);
|
|
24622
24583
|
if (field.defaultValue !== void 0) {
|
|
@@ -24632,7 +24593,7 @@ function renderFieldLines(field, ctx, helperParts, indent = " ", typeOverride
|
|
|
24632
24593
|
return lines;
|
|
24633
24594
|
}
|
|
24634
24595
|
function renderIRSimpleStruct(name, fields, description, ctx) {
|
|
24635
|
-
const structName =
|
|
24596
|
+
const structName = snakeCaseToUpperCamelCase(name);
|
|
24636
24597
|
const lines = [];
|
|
24637
24598
|
if (description) lines.push(...formatDocComment(description));
|
|
24638
24599
|
lines.push("#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]");
|
|
@@ -24654,7 +24615,7 @@ function renderTypeAlias(name, target, description) {
|
|
|
24654
24615
|
return lines.join("\n");
|
|
24655
24616
|
}
|
|
24656
24617
|
function renderIRUnionStruct(struct, ctx) {
|
|
24657
|
-
const enumName =
|
|
24618
|
+
const enumName = snakeCaseToUpperCamelCase(struct.name);
|
|
24658
24619
|
const lines = [];
|
|
24659
24620
|
const extraDefs = [];
|
|
24660
24621
|
if (struct.description) lines.push(...formatDocComment(struct.description));
|
|
@@ -24662,10 +24623,10 @@ function renderIRUnionStruct(struct, ctx) {
|
|
|
24662
24623
|
lines.push(`#[serde(tag = ${escapeRustString(struct.tagFieldName)})]`);
|
|
24663
24624
|
lines.push(`pub enum ${enumName} {`);
|
|
24664
24625
|
if (struct.unionType === "withData") struct.derivedTypes.forEach((derivedType, index) => {
|
|
24665
|
-
const variantName =
|
|
24666
|
-
const dataTypeName = derivedType.derivingType === "ref" ?
|
|
24626
|
+
const variantName = snakeCaseToUpperCamelCase(derivedType.tagValue);
|
|
24627
|
+
const dataTypeName = derivedType.derivingType === "ref" ? snakeCaseToUpperCamelCase(derivedType.refStructName) : `${enumName}${snakeCaseToUpperCamelCase(derivedType.tagValue)}Data`;
|
|
24667
24628
|
const dataFieldDescription = derivedType.description ? `${derivedType.description}数据` : "数据字段";
|
|
24668
|
-
if (derivedType.description) lines.push(...formatDocComment(derivedType.description, " "));
|
|
24629
|
+
if (derivedType.description) lines.push(...formatDocComment(derivedType.description, " /// "));
|
|
24669
24630
|
lines.push(` #[serde(rename = ${escapeRustString(derivedType.tagValue)})]`);
|
|
24670
24631
|
lines.push(` ${variantName} {`);
|
|
24671
24632
|
struct.baseFields.forEach((field) => {
|
|
@@ -24692,8 +24653,8 @@ function renderIRUnionStruct(struct, ctx) {
|
|
|
24692
24653
|
if (index !== struct.derivedTypes.length - 1) lines.push("");
|
|
24693
24654
|
});
|
|
24694
24655
|
else struct.derivedStructs.forEach((derivedStruct, index) => {
|
|
24695
|
-
const variantName =
|
|
24696
|
-
if (derivedStruct.description) lines.push(...formatDocComment(derivedStruct.description, " "));
|
|
24656
|
+
const variantName = snakeCaseToUpperCamelCase(derivedStruct.tagValue);
|
|
24657
|
+
if (derivedStruct.description) lines.push(...formatDocComment(derivedStruct.description, " /// "));
|
|
24697
24658
|
lines.push(` #[serde(rename = ${escapeRustString(derivedStruct.tagValue)})]`);
|
|
24698
24659
|
if (derivedStruct.fields.length === 0) lines.push(` ${variantName},`);
|
|
24699
24660
|
else {
|
|
@@ -24777,12 +24738,12 @@ function generateRustSerdeSpec(ir) {
|
|
|
24777
24738
|
l(`// ---- ${category.name} ----`);
|
|
24778
24739
|
l();
|
|
24779
24740
|
category.apis.forEach((api) => {
|
|
24780
|
-
const inputName = `${
|
|
24741
|
+
const inputName = `${snakeCaseToUpperCamelCase(api.endpoint)}Input`;
|
|
24781
24742
|
const inputDescription = `${api.description} API 请求参数`;
|
|
24782
24743
|
if (api.requestFields && api.requestFields.length > 0) l(renderIRSimpleStruct(inputName, api.requestFields, inputDescription, ctx));
|
|
24783
24744
|
else l(renderTypeAlias(inputName, "ApiEmptyStruct", inputDescription));
|
|
24784
24745
|
l();
|
|
24785
|
-
const outputName = `${
|
|
24746
|
+
const outputName = `${snakeCaseToUpperCamelCase(api.endpoint)}Output`;
|
|
24786
24747
|
const outputDescription = `${api.description} API 响应数据`;
|
|
24787
24748
|
if (api.responseFields && api.responseFields.length > 0) l(renderIRSimpleStruct(outputName, api.responseFields, outputDescription, ctx));
|
|
24788
24749
|
else l(renderTypeAlias(outputName, "ApiEmptyStruct", outputDescription));
|
|
@@ -24865,7 +24826,7 @@ function generateRustSerdeSpec(ir) {
|
|
|
24865
24826
|
l();
|
|
24866
24827
|
ir.apiCategories.forEach((category) => {
|
|
24867
24828
|
category.apis.forEach((api) => {
|
|
24868
|
-
const endpointName =
|
|
24829
|
+
const endpointName = snakeCaseToUpperCamelCase(api.endpoint);
|
|
24869
24830
|
l(`/// ${api.description}`);
|
|
24870
24831
|
l("#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]");
|
|
24871
24832
|
l(`pub struct ${endpointName};`);
|
|
@@ -24882,21 +24843,13 @@ function generateRustSerdeSpec(ir) {
|
|
|
24882
24843
|
}
|
|
24883
24844
|
//#endregion
|
|
24884
24845
|
//#region ../common/src/generator/typescript/static.ts
|
|
24885
|
-
function useLines() {
|
|
24886
|
-
const lines = [];
|
|
24887
|
-
function l(line = "") {
|
|
24888
|
-
lines.push(line);
|
|
24889
|
-
}
|
|
24890
|
-
return [lines, l];
|
|
24891
|
-
}
|
|
24892
24846
|
function generateTypeScriptStaticSpec(ir) {
|
|
24893
|
-
const
|
|
24847
|
+
const writer = createLineWriter();
|
|
24848
|
+
const l = writer.line;
|
|
24894
24849
|
l(`// Generated from Milky ${ir.milkyVersion} (${ir.milkyPackageVersion})`);
|
|
24895
24850
|
l();
|
|
24896
|
-
l(`
|
|
24897
|
-
export const
|
|
24898
|
-
export const milkyPackageVersion = '${ir.milkyPackageVersion}';
|
|
24899
|
-
`.trim());
|
|
24851
|
+
l(`export const milkyVersion = '${ir.milkyVersion}';`);
|
|
24852
|
+
l(`export const milkyPackageVersion = '${ir.milkyPackageVersion}';`);
|
|
24900
24853
|
l();
|
|
24901
24854
|
l("// ####################################");
|
|
24902
24855
|
l("// Common Structs");
|
|
@@ -24950,7 +24903,7 @@ export const milkyPackageVersion = '${ir.milkyPackageVersion}';
|
|
|
24950
24903
|
l(`export type ${struct.name} =`);
|
|
24951
24904
|
struct.derivedTypes.forEach((derivedType, index) => {
|
|
24952
24905
|
l(" | {");
|
|
24953
|
-
l(`
|
|
24906
|
+
l(` ${struct.tagFieldName}: '${derivedType.tagValue}';`);
|
|
24954
24907
|
l(` data: ${normalizeDerivedStructName(struct.name, derivedType.tagValue)}Data;`);
|
|
24955
24908
|
l(` }${index === struct.derivedTypes.length - 1 ? ";" : ""}`);
|
|
24956
24909
|
});
|
|
@@ -24963,29 +24916,30 @@ export const milkyPackageVersion = '${ir.milkyPackageVersion}';
|
|
|
24963
24916
|
l();
|
|
24964
24917
|
ir.apiCategories.forEach((category) => {
|
|
24965
24918
|
category.apis.forEach((api) => {
|
|
24919
|
+
const typeNames = getApiTypeNames(api.endpoint);
|
|
24966
24920
|
l(`/** ${api.description} API 请求参数 */`);
|
|
24967
24921
|
if (api.requestFields !== void 0) {
|
|
24968
|
-
l(`export interface ${
|
|
24922
|
+
l(`export interface ${typeNames.requestName} {`);
|
|
24969
24923
|
api.requestFields.forEach((field) => {
|
|
24970
24924
|
l(` /** ${field.description} */`);
|
|
24971
24925
|
l(` ${field.name}${field.isOptional ? "?" : ""}: ${getTypeScriptTypeProjection(field)};`);
|
|
24972
24926
|
});
|
|
24973
24927
|
l("}");
|
|
24974
|
-
} else l(`export type ${
|
|
24928
|
+
} else l(`export type ${typeNames.requestName} = {};`);
|
|
24975
24929
|
l();
|
|
24976
24930
|
l(`/** ${api.description} API 响应数据 */`);
|
|
24977
24931
|
if (api.responseFields !== void 0) {
|
|
24978
|
-
l(`export interface ${
|
|
24932
|
+
l(`export interface ${typeNames.responseName} {`);
|
|
24979
24933
|
api.responseFields.forEach((field) => {
|
|
24980
24934
|
l(` /** ${field.description} */`);
|
|
24981
24935
|
l(` ${field.name}${field.isOptional ? "?" : ""}: ${getTypeScriptTypeProjection(field)};`);
|
|
24982
24936
|
});
|
|
24983
24937
|
l("}");
|
|
24984
|
-
} else l(`export type ${
|
|
24938
|
+
} else l(`export type ${typeNames.responseName} = {};`);
|
|
24985
24939
|
l();
|
|
24986
24940
|
});
|
|
24987
24941
|
});
|
|
24988
|
-
return
|
|
24942
|
+
return writer.toString();
|
|
24989
24943
|
}
|
|
24990
24944
|
//#endregion
|
|
24991
24945
|
//#region ../protocol/src/builder.ts
|