@cloudbase/cals 1.2.17 → 1.2.18-alpha.0
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/lib/cjs/utils/mermaid-datasource/build.d.ts +2 -0
- package/lib/cjs/utils/mermaid-datasource/build.d.ts.map +1 -0
- package/lib/cjs/utils/mermaid-datasource/build.js +82 -0
- package/lib/cjs/utils/mermaid-datasource/classDb.d.ts +116 -0
- package/lib/cjs/utils/mermaid-datasource/classDb.d.ts.map +1 -0
- package/lib/cjs/utils/mermaid-datasource/classDb.js +333 -0
- package/lib/cjs/utils/mermaid-datasource/classDiagram.d.ts +4 -0
- package/lib/cjs/utils/mermaid-datasource/classDiagram.d.ts.map +1 -0
- package/lib/cjs/utils/mermaid-datasource/classDiagram.js +1115 -0
- package/lib/cjs/utils/mermaid-datasource/jison-builder.d.ts +2 -0
- package/lib/cjs/utils/mermaid-datasource/jison-builder.d.ts.map +1 -0
- package/lib/cjs/utils/mermaid-datasource/jison-builder.js +22 -0
- package/lib/cjs/utils/mermaid-datasource/mermaid-json-transform.d.ts +70 -0
- package/lib/cjs/utils/mermaid-datasource/mermaid-json-transform.d.ts.map +1 -0
- package/lib/cjs/utils/mermaid-datasource/mermaid-json-transform.js +624 -0
- package/lib/cjs/utils/mermaid-datasource/prompts/cases/activity_reservation.d.ts +11 -0
- package/lib/cjs/utils/mermaid-datasource/prompts/cases/activity_reservation.d.ts.map +1 -0
- package/lib/cjs/utils/mermaid-datasource/prompts/cases/activity_reservation.js +9 -0
- package/lib/cjs/utils/mermaid-datasource/prompts/cases/index.d.ts +6 -0
- package/lib/cjs/utils/mermaid-datasource/prompts/cases/index.d.ts.map +1 -0
- package/lib/cjs/utils/mermaid-datasource/prompts/cases/index.js +18 -0
- package/lib/cjs/utils/mermaid-datasource/prompts/cases/students_course_selection.d.ts +11 -0
- package/lib/cjs/utils/mermaid-datasource/prompts/cases/students_course_selection.d.ts.map +1 -0
- package/lib/cjs/utils/mermaid-datasource/prompts/cases/students_course_selection.js +9 -0
- package/lib/cjs/utils/mermaid-datasource/prompts/system.d.ts +7 -0
- package/lib/cjs/utils/mermaid-datasource/prompts/system.d.ts.map +1 -0
- package/lib/cjs/utils/mermaid-datasource/prompts/system.js +9 -0
- package/lib/esm/utils/mermaid-datasource/build.d.ts +2 -0
- package/lib/esm/utils/mermaid-datasource/build.d.ts.map +1 -0
- package/lib/esm/utils/mermaid-datasource/build.js +77 -0
- package/lib/esm/utils/mermaid-datasource/classDb.d.ts +116 -0
- package/lib/esm/utils/mermaid-datasource/classDb.d.ts.map +1 -0
- package/lib/esm/utils/mermaid-datasource/classDb.js +331 -0
- package/lib/esm/utils/mermaid-datasource/classDiagram.d.ts +4 -0
- package/lib/esm/utils/mermaid-datasource/classDiagram.d.ts.map +1 -0
- package/lib/esm/utils/mermaid-datasource/classDiagram.js +1112 -0
- package/lib/esm/utils/mermaid-datasource/jison-builder.d.ts +2 -0
- package/lib/esm/utils/mermaid-datasource/jison-builder.d.ts.map +1 -0
- package/lib/esm/utils/mermaid-datasource/jison-builder.js +15 -0
- package/lib/esm/utils/mermaid-datasource/mermaid-json-transform.d.ts +70 -0
- package/lib/esm/utils/mermaid-datasource/mermaid-json-transform.d.ts.map +1 -0
- package/lib/esm/utils/mermaid-datasource/mermaid-json-transform.js +615 -0
- package/lib/esm/utils/mermaid-datasource/prompts/cases/activity_reservation.d.ts +11 -0
- package/lib/esm/utils/mermaid-datasource/prompts/cases/activity_reservation.d.ts.map +1 -0
- package/lib/esm/utils/mermaid-datasource/prompts/cases/activity_reservation.js +7 -0
- package/lib/esm/utils/mermaid-datasource/prompts/cases/index.d.ts +6 -0
- package/lib/esm/utils/mermaid-datasource/prompts/cases/index.d.ts.map +1 -0
- package/lib/esm/utils/mermaid-datasource/prompts/cases/index.js +12 -0
- package/lib/esm/utils/mermaid-datasource/prompts/cases/students_course_selection.d.ts +11 -0
- package/lib/esm/utils/mermaid-datasource/prompts/cases/students_course_selection.d.ts.map +1 -0
- package/lib/esm/utils/mermaid-datasource/prompts/cases/students_course_selection.js +7 -0
- package/lib/esm/utils/mermaid-datasource/prompts/system.d.ts +7 -0
- package/lib/esm/utils/mermaid-datasource/prompts/system.d.ts.map +1 -0
- package/lib/esm/utils/mermaid-datasource/prompts/system.js +7 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.jsonSchemaToMermaid = exports.mermaidToJsonSchema = exports.parseMermaid = void 0;
|
|
7
|
+
const classDiagram_js_1 = require("./classDiagram.js");
|
|
8
|
+
const parserInstance = classDiagram_js_1.parser;
|
|
9
|
+
const classDb_js_1 = __importDefault(require("./classDb.js"));
|
|
10
|
+
// const code = 'classDiagram\n class User {\n id: string <<用户ID>>\n name: string <<姓名>>\n phone: phone <<手机号>>\n email: email <<邮箱>>\n avatar: x-image <<头像>>\n required() ["name", "phone"]\n unique() ["phone", "email"]\n }\n \n class Activity {\n id: string <<活动ID>>\n title: string <<活动标题>>\n description: x-rtf <<活动详情>>\n coverImage: x-image <<封面图>>\n startTime: datetime <<开始时间>>\n endTime: datetime <<结束时间>>\n address: string <<活动地址>>\n location: x-location <<地理位置>>\n maxParticipants: number = 100 <<最大参与人数>>\n status: x-enum = ["未开始", "进行中", "已结束", "已取消"] <<状态>>\n required() ["title", "startTime", "endTime"]\n }\n \n class Reservation {\n id: string <<预约ID>>\n userId: string <<用户ID>>\n activityId: string <<活动ID>>\n reservationTime: datetime <<预约时间>>\n status: x-enum = ["待确认", "已预约", "已取消", "已签到"] <<状态>>\n notes: string <<备注>>\n required() ["userId", "activityId", "reservationTime"]\n }\n \n class ActivityCategory {\n id: string <<分类ID>>\n name: string <<分类名称>>\n icon: x-image <<图标>>\n required() ["name"]\n }\n \n class Review {\n id: string <<评价ID>>\n userId: string <<用户ID>>\n activityId: string <<活动ID>>\n rating: number = 5 <<评分>>\n comment: string <<评价内容>>\n reviewTime: datetime <<评价时间>>\n required() ["userId", "activityId", "rating"]\n }\n User "1" --> "n" Reservation : userId\n Activity "1" --> "n" Reservation : activityId\n Activity "n" --> "1" ActivityCategory : categoryId\n User "1" --> "n" Review : userId\n Activity "1" --> "n" Review : activityId\n note for User "用户模型"\n note for Activity "活动模型"\n note for Reservation "预约模型"\n note for ActivityCategory "活动分类模型"\n note for Review "评价模型"\n\n';
|
|
11
|
+
// 检查类型是否为关联关系类型(其他类名或其他类名的数组)
|
|
12
|
+
function isRelationshipType(type, classNames) {
|
|
13
|
+
// 移除数组标记
|
|
14
|
+
const baseType = type.endsWith('[]') ? type.slice(0, -2) : type;
|
|
15
|
+
// 检查是否为已知的类名
|
|
16
|
+
return classNames.includes(baseType);
|
|
17
|
+
}
|
|
18
|
+
function convertToJSONSchema(data) {
|
|
19
|
+
const schemas = {};
|
|
20
|
+
// 解析关联关系,建立关系映射 - 用于查找关联信息
|
|
21
|
+
const relationMap = {};
|
|
22
|
+
// 处理关联关系
|
|
23
|
+
if (data.relations) {
|
|
24
|
+
data.relations.forEach((relation) => {
|
|
25
|
+
const { id1, id2, relation: rel, relationTitle1, relationTitle2, title } = relation;
|
|
26
|
+
// 判断关系方向和类型
|
|
27
|
+
const hasType1 = rel.type1 !== undefined && rel.type1 !== 'none';
|
|
28
|
+
const hasType2 = rel.type2 !== undefined && rel.type2 !== 'none';
|
|
29
|
+
if (!relationMap[id1])
|
|
30
|
+
relationMap[id1] = {};
|
|
31
|
+
if (!relationMap[id2])
|
|
32
|
+
relationMap[id2] = {};
|
|
33
|
+
if (hasType2) {
|
|
34
|
+
// id1 -> id2 的关系
|
|
35
|
+
relationMap[id1][title || ''] = {
|
|
36
|
+
targetClass: id2,
|
|
37
|
+
cardinality1: relationTitle1 || '',
|
|
38
|
+
cardinality2: relationTitle2 || '',
|
|
39
|
+
isReverse: false,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (hasType1) {
|
|
43
|
+
// id2 -> id1 的关系(反向)
|
|
44
|
+
relationMap[id2][title || ''] = {
|
|
45
|
+
targetClass: id1,
|
|
46
|
+
cardinality1: relationTitle2 || '',
|
|
47
|
+
cardinality2: relationTitle1 || '',
|
|
48
|
+
isReverse: true,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
// TODO: 拼反向关联关系
|
|
54
|
+
// Object.entries(relationMap).forEach(([className, relations]) => {
|
|
55
|
+
// Object.entries(relations).forEach(([fieldName, relation]) => {
|
|
56
|
+
// const { targetClass, cardinality1, cardinality2 } = relation;
|
|
57
|
+
// if ((cardinality1 === '1' && cardinality2 === 'n') || (cardinality1 === 'n' && cardinality2 === '1')) {
|
|
58
|
+
// const targetReleation = relationMap[relationMap[className][fieldName].targetClass];
|
|
59
|
+
// const reverseRelation = Object.entries(targetReleation ?? {}).find(([_, relation]) => relation.targetClass === className);
|
|
60
|
+
// if (!reverseRelation) {
|
|
61
|
+
// let reverseFieldName;
|
|
62
|
+
// const match = fieldName.match(/(\w+)2(\w+)/);
|
|
63
|
+
// if (match) {
|
|
64
|
+
// const [_, field1, field2] = match;
|
|
65
|
+
// reverseFieldName = `${field2}2${field1}`;
|
|
66
|
+
// } else {
|
|
67
|
+
// if (cardinality1 === 'n') {
|
|
68
|
+
// reverseFieldName = pluralize.plural(className.toLowerCase());
|
|
69
|
+
// } else {
|
|
70
|
+
// reverseFieldName = className.toLowerCase();
|
|
71
|
+
// }
|
|
72
|
+
// }
|
|
73
|
+
// relationMap[targetClass][reverseFieldName] = {
|
|
74
|
+
// targetClass: className,
|
|
75
|
+
// cardinality1: cardinality2,
|
|
76
|
+
// cardinality2: cardinality1,
|
|
77
|
+
// isReverse: true
|
|
78
|
+
// };
|
|
79
|
+
// }
|
|
80
|
+
// }
|
|
81
|
+
// });
|
|
82
|
+
// })
|
|
83
|
+
// 为每个类生成JSON Schema
|
|
84
|
+
Object.entries(data.classes).forEach(([className, classInfo]) => {
|
|
85
|
+
var _a, _b;
|
|
86
|
+
// 查找该类的注释作为标题
|
|
87
|
+
const noteText = ((_b = (_a = data.notes) === null || _a === void 0 ? void 0 : _a.find((note) => note.class === className)) === null || _b === void 0 ? void 0 : _b.text) || '';
|
|
88
|
+
const schema = {
|
|
89
|
+
type: 'object',
|
|
90
|
+
title: noteText || classInfo.label || className,
|
|
91
|
+
description: noteText || classInfo.label || className,
|
|
92
|
+
properties: {},
|
|
93
|
+
required: [],
|
|
94
|
+
};
|
|
95
|
+
// 处理成员属性(包括关联字段)
|
|
96
|
+
if (classInfo.members) {
|
|
97
|
+
classInfo.members.forEach((member) => {
|
|
98
|
+
var _a;
|
|
99
|
+
const memberName = member.name;
|
|
100
|
+
const parsed = parseMemberDefinition(memberName);
|
|
101
|
+
if (parsed) {
|
|
102
|
+
// 检查是否为关联关系字段
|
|
103
|
+
const isRelationField = isRelationshipType(parsed.type, Object.keys(data.classes));
|
|
104
|
+
if (isRelationField) {
|
|
105
|
+
// 处理关联字段
|
|
106
|
+
const baseType = parsed.type.endsWith('[]') ? parsed.type.slice(0, -2) : parsed.type;
|
|
107
|
+
const isArray = parsed.type.endsWith('[]');
|
|
108
|
+
// 查找关联关系信息
|
|
109
|
+
const relationInfo = (_a = relationMap[className]) === null || _a === void 0 ? void 0 : _a[parsed.name];
|
|
110
|
+
let format = 'one-one'; // 默认格式
|
|
111
|
+
if (relationInfo) {
|
|
112
|
+
format = determineRelationType(relationInfo.cardinality1, relationInfo.cardinality2, relationInfo.isReverse).format;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// 根据类型推断格式
|
|
116
|
+
format = isArray ? 'one-many' : 'one-one';
|
|
117
|
+
}
|
|
118
|
+
const parentFieldKey = `_${className.toLowerCase()}`;
|
|
119
|
+
schema.properties[parsed.name] = {
|
|
120
|
+
type: isArray ? 'array' : 'object',
|
|
121
|
+
format: format,
|
|
122
|
+
title: parsed.title,
|
|
123
|
+
description: parsed.title,
|
|
124
|
+
'x-parent': {
|
|
125
|
+
parentDataSourceName: baseType,
|
|
126
|
+
parentFieldKey,
|
|
127
|
+
parentFieldTitle: `关联到${baseType} ${format}`,
|
|
128
|
+
},
|
|
129
|
+
'x-deleteWay': 'doNothing',
|
|
130
|
+
};
|
|
131
|
+
if (isArray) {
|
|
132
|
+
schema.properties[parsed.name].items = {
|
|
133
|
+
type: 'object',
|
|
134
|
+
properties: {
|
|
135
|
+
_id: { name: '_id', title: '数据标识', type: 'string' },
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
schema.properties[parsed.name].properties = {
|
|
141
|
+
_id: { name: '_id', title: '数据标识', type: 'string' },
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// 处理普通字段
|
|
147
|
+
schema.properties[parsed.name] = {
|
|
148
|
+
type: mapType(parsed.type),
|
|
149
|
+
title: parsed.title,
|
|
150
|
+
description: parsed.title,
|
|
151
|
+
};
|
|
152
|
+
// 处理默认值
|
|
153
|
+
if (parsed.defaultValue !== undefined) {
|
|
154
|
+
schema.properties[parsed.name].default = parsed.defaultValue;
|
|
155
|
+
}
|
|
156
|
+
// 处理枚举类型
|
|
157
|
+
if (parsed.type.startsWith('x-enum')) {
|
|
158
|
+
schema.properties[parsed.name].type = 'string';
|
|
159
|
+
schema.properties[parsed.name].format = 'enum';
|
|
160
|
+
if (parsed.enumValues) {
|
|
161
|
+
schema.properties[parsed.name].enum = parsed.enumValues;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// 处理数组类型
|
|
165
|
+
if (parsed.type.endsWith('[]')) {
|
|
166
|
+
const baseType = parsed.type.slice(0, -2);
|
|
167
|
+
schema.properties[parsed.name] = {
|
|
168
|
+
type: 'array',
|
|
169
|
+
title: parsed.title,
|
|
170
|
+
description: parsed.title,
|
|
171
|
+
items: {
|
|
172
|
+
type: mapType(baseType),
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
// 处理特殊格式
|
|
177
|
+
const format = getSpecialFormat(parsed.type);
|
|
178
|
+
if (format) {
|
|
179
|
+
schema.properties[parsed.name].format = format;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
// 处理方法中的约束
|
|
186
|
+
if (classInfo.methods) {
|
|
187
|
+
classInfo.methods.forEach((method) => {
|
|
188
|
+
const methodName = method.name;
|
|
189
|
+
if (methodName.startsWith('required()')) {
|
|
190
|
+
const fields = extractArrayFromMethod(methodName);
|
|
191
|
+
if (fields.length > 0) {
|
|
192
|
+
schema.required = fields;
|
|
193
|
+
for (const field of fields) {
|
|
194
|
+
safeSet(schema.properties[field], ['x-required'], true);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
else if (methodName.startsWith('unique()')) {
|
|
199
|
+
const fields = extractArrayFromMethod(methodName);
|
|
200
|
+
for (const field of fields) {
|
|
201
|
+
safeSet(schema.properties[field], ['x-unique'], true);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
else if (methodName.startsWith('display_field()')) {
|
|
205
|
+
const fieldName = extractDisplayField(methodName);
|
|
206
|
+
if (fieldName) {
|
|
207
|
+
schema['x-primary-column'] = fieldName;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
else if (methodName.startsWith('enum_')) {
|
|
211
|
+
const fieldName = methodName.split('(')[0].replace('enum_', '');
|
|
212
|
+
const enumValues = extractArrayFromMethod(methodName);
|
|
213
|
+
if (schema.properties[fieldName]) {
|
|
214
|
+
schema.properties[fieldName].enum = enumValues;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
// 根据关联关系图添加缺失的关联字段
|
|
220
|
+
const classRelations = relationMap[className] || {};
|
|
221
|
+
Object.entries(classRelations).forEach(([relationName, relationInfo]) => {
|
|
222
|
+
const { targetClass, cardinality1, cardinality2, isReverse } = relationInfo;
|
|
223
|
+
const relationType = determineRelationType(cardinality1, cardinality2, isReverse);
|
|
224
|
+
// 如果该字段已存在但不是关联字段,则转换为关联字段
|
|
225
|
+
if (schema.properties[relationName] && !schema.properties[relationName].format) {
|
|
226
|
+
// 保留原有的标题
|
|
227
|
+
const originalTitle = schema.properties[relationName].title;
|
|
228
|
+
const parentFieldKey = `_${className.toLowerCase()}`;
|
|
229
|
+
schema.properties[relationName] = {
|
|
230
|
+
type: relationType.type,
|
|
231
|
+
format: relationType.format,
|
|
232
|
+
title: originalTitle,
|
|
233
|
+
description: originalTitle,
|
|
234
|
+
'x-parent': {
|
|
235
|
+
parentDataSourceName: targetClass,
|
|
236
|
+
parentFieldKey,
|
|
237
|
+
parentFieldTitle: `关联到${targetClass} ${relationType.format}`,
|
|
238
|
+
},
|
|
239
|
+
'x-deleteWay': 'doNothing',
|
|
240
|
+
};
|
|
241
|
+
if (relationType.type === 'array') {
|
|
242
|
+
schema.properties[relationName].items = {
|
|
243
|
+
type: 'object',
|
|
244
|
+
properties: {
|
|
245
|
+
_id: { name: '_id', title: '数据标识', type: 'string' },
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
schema.properties[relationName].properties = {
|
|
251
|
+
_id: { name: '_id', title: '数据标识', type: 'string' },
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// 如果该字段不存在,则添加
|
|
256
|
+
else if (!schema.properties[relationName]) {
|
|
257
|
+
const targetRelations = relationMap[relationMap[className][relationName].targetClass];
|
|
258
|
+
// const reverseField = Object.keys(targetRelations).find((k) => {
|
|
259
|
+
// return targetRelations[k].targetClass === className;
|
|
260
|
+
// });
|
|
261
|
+
const reverseField = `_${className.toLowerCase()}`;
|
|
262
|
+
schema.properties[relationName] = {
|
|
263
|
+
type: relationType.type,
|
|
264
|
+
format: relationType.format,
|
|
265
|
+
title: `关联到${targetClass}`,
|
|
266
|
+
description: `与${targetClass}的关联关系`,
|
|
267
|
+
'x-parent': {
|
|
268
|
+
parentDataSourceName: targetClass,
|
|
269
|
+
parentFieldKey: reverseField,
|
|
270
|
+
parentFieldTitle: `关联到${targetClass} ${relationType.format}`,
|
|
271
|
+
},
|
|
272
|
+
'x-deleteWay': 'doNothing',
|
|
273
|
+
};
|
|
274
|
+
if (relationType.type === 'array') {
|
|
275
|
+
schema.properties[relationName].items = {
|
|
276
|
+
type: 'object',
|
|
277
|
+
properties: {
|
|
278
|
+
_id: { name: '_id', title: '数据标识', type: 'string' },
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
schema.properties[relationName].properties = {
|
|
284
|
+
_id: { name: '_id', title: '数据标识', type: 'string' },
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
schemas[className] = schema;
|
|
290
|
+
});
|
|
291
|
+
return schemas;
|
|
292
|
+
}
|
|
293
|
+
// 解析成员定义
|
|
294
|
+
function parseMemberDefinition(memberDef) {
|
|
295
|
+
// 解析格式:name: type = defaultValue <<title>>
|
|
296
|
+
const regex = /^(\w+):\s*([^=<]+?)(?:\s*=\s*([^<]+?))?(?:\s*<<(.+?)>>)?$/;
|
|
297
|
+
const match = memberDef.match(regex);
|
|
298
|
+
if (!match)
|
|
299
|
+
return null;
|
|
300
|
+
const [, name, type, defaultValue, title] = match;
|
|
301
|
+
let enumValues = null;
|
|
302
|
+
let cleanType = type.trim();
|
|
303
|
+
// 处理枚举类型
|
|
304
|
+
if (cleanType.includes('=')) {
|
|
305
|
+
const enumMatch = cleanType.match(/x-enum\s*=\s*\[(.*?)\]/);
|
|
306
|
+
if (enumMatch) {
|
|
307
|
+
enumValues = enumMatch[1].split(',').map((v) => v.trim().replace(/"/g, ''));
|
|
308
|
+
cleanType = 'x-enum';
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return {
|
|
312
|
+
name: name.trim(),
|
|
313
|
+
type: cleanType,
|
|
314
|
+
defaultValue: defaultValue ? parseDefaultValue(defaultValue.trim()) : undefined,
|
|
315
|
+
title: (title === null || title === void 0 ? void 0 : title.trim()) || name.trim(),
|
|
316
|
+
enumValues,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
// 映射类型
|
|
320
|
+
function mapType(type) {
|
|
321
|
+
const typeMap = {
|
|
322
|
+
string: 'string',
|
|
323
|
+
number: 'number',
|
|
324
|
+
boolean: 'boolean',
|
|
325
|
+
datetime: 'number',
|
|
326
|
+
email: 'string',
|
|
327
|
+
phone: 'string',
|
|
328
|
+
'x-enum': 'string',
|
|
329
|
+
'x-image': 'string',
|
|
330
|
+
'x-rtf': 'string',
|
|
331
|
+
'x-location': 'object',
|
|
332
|
+
};
|
|
333
|
+
return typeMap[type] || 'string';
|
|
334
|
+
}
|
|
335
|
+
// 获取特殊格式
|
|
336
|
+
function getSpecialFormat(type) {
|
|
337
|
+
const formatMap = {
|
|
338
|
+
datetime: 'datetime',
|
|
339
|
+
email: 'email',
|
|
340
|
+
phone: 'phone',
|
|
341
|
+
'x-image': 'x-image',
|
|
342
|
+
'x-rtf': 'x-rtf',
|
|
343
|
+
'x-location': 'x-location',
|
|
344
|
+
'x-area-code': 'x-area-code',
|
|
345
|
+
'x-file': 'x-file',
|
|
346
|
+
};
|
|
347
|
+
// 只保留这些
|
|
348
|
+
return formatMap[type] || null;
|
|
349
|
+
}
|
|
350
|
+
// 解析默认值
|
|
351
|
+
function parseDefaultValue(value) {
|
|
352
|
+
if (value === 'true')
|
|
353
|
+
return true;
|
|
354
|
+
if (value === 'false')
|
|
355
|
+
return false;
|
|
356
|
+
if (/^\d+$/.test(value))
|
|
357
|
+
return parseInt(value);
|
|
358
|
+
if (/^\d+\.\d+$/.test(value))
|
|
359
|
+
return parseFloat(value);
|
|
360
|
+
if (value.startsWith('[') && value.endsWith(']')) {
|
|
361
|
+
try {
|
|
362
|
+
return JSON.parse(value);
|
|
363
|
+
}
|
|
364
|
+
catch (_a) {
|
|
365
|
+
return value;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return value.replace(/"/g, '');
|
|
369
|
+
}
|
|
370
|
+
// 从方法字符串中提取数组
|
|
371
|
+
function extractArrayFromMethod(methodStr) {
|
|
372
|
+
const match = methodStr.match(/\[(.*?)\]/);
|
|
373
|
+
if (!match)
|
|
374
|
+
return [];
|
|
375
|
+
return match[1].split(',').map((item) => item.trim().replace(/"/g, ''));
|
|
376
|
+
}
|
|
377
|
+
// 从方法字符串中提取显示字段
|
|
378
|
+
function extractDisplayField(methodStr) {
|
|
379
|
+
const match = methodStr.match(/display_field\(\)\s*"([^"]+)"/);
|
|
380
|
+
if (!match)
|
|
381
|
+
return null;
|
|
382
|
+
return match[1].trim();
|
|
383
|
+
}
|
|
384
|
+
// 确定关系类型
|
|
385
|
+
function determineRelationType(cardinality1, cardinality2, isReverse) {
|
|
386
|
+
const is1ToMany = cardinality1 === '1' && (cardinality2 === 'n' || cardinality2 === 'm');
|
|
387
|
+
const isManyTo1 = (cardinality1 === 'n' || cardinality1 === 'm') && cardinality2 === '1';
|
|
388
|
+
const is1To1 = cardinality1 === '1' && cardinality2 === '1';
|
|
389
|
+
const isManyToMany = (cardinality1 === 'n' || cardinality1 === 'm') && (cardinality2 === 'n' || cardinality2 === 'm');
|
|
390
|
+
if (isManyToMany) {
|
|
391
|
+
return { type: 'array', format: 'many-many' };
|
|
392
|
+
}
|
|
393
|
+
else if (is1ToMany) {
|
|
394
|
+
return { type: 'array', format: 'one-many' };
|
|
395
|
+
}
|
|
396
|
+
else if (isManyTo1) {
|
|
397
|
+
return { type: 'object', format: 'many-one' };
|
|
398
|
+
}
|
|
399
|
+
else if (is1To1) {
|
|
400
|
+
return { type: 'object', format: isReverse ? 'one-one-r' : 'one-one' };
|
|
401
|
+
}
|
|
402
|
+
return { type: 'object', format: 'one-one' };
|
|
403
|
+
}
|
|
404
|
+
function safeSet(obj, path, value) {
|
|
405
|
+
let current = obj;
|
|
406
|
+
if (typeof current !== 'object' || current === null) {
|
|
407
|
+
throw new TypeError(`Expected object, got ${typeof current}`);
|
|
408
|
+
}
|
|
409
|
+
for (let i = 0; i < path.length; i++) {
|
|
410
|
+
const key = path[i];
|
|
411
|
+
if (typeof current[key] !== 'object' || current[key] === null) {
|
|
412
|
+
if (i === path.length - 1) {
|
|
413
|
+
current[key] = value;
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
current[key] = {};
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
current = current[key];
|
|
420
|
+
}
|
|
421
|
+
return obj;
|
|
422
|
+
}
|
|
423
|
+
function parseMermaid(code) {
|
|
424
|
+
const classDb = new classDb_js_1.default();
|
|
425
|
+
parserInstance.yy = classDb;
|
|
426
|
+
parserInstance.parse(code);
|
|
427
|
+
return classDb.exportData();
|
|
428
|
+
}
|
|
429
|
+
exports.parseMermaid = parseMermaid;
|
|
430
|
+
function mermaidToJsonSchema(code) {
|
|
431
|
+
const classDb = new classDb_js_1.default();
|
|
432
|
+
parserInstance.yy = classDb;
|
|
433
|
+
parserInstance.parse(code);
|
|
434
|
+
const exportedData = classDb.exportData();
|
|
435
|
+
const schemas = convertToJSONSchema(exportedData);
|
|
436
|
+
return schemas;
|
|
437
|
+
}
|
|
438
|
+
exports.mermaidToJsonSchema = mermaidToJsonSchema;
|
|
439
|
+
// 反向转换:将JSON Schema转换为Mermaid类图
|
|
440
|
+
function jsonSchemaToMermaid(schemas) {
|
|
441
|
+
const lines = [];
|
|
442
|
+
lines.push('classDiagram');
|
|
443
|
+
// 存储关联关系,稍后处理
|
|
444
|
+
const relationSet = new Set();
|
|
445
|
+
const notes = [];
|
|
446
|
+
// 为每个类生成定义
|
|
447
|
+
Object.entries(schemas).forEach(([className, schema]) => {
|
|
448
|
+
lines.push(` class ${className} {`);
|
|
449
|
+
const properties = schema.properties || {};
|
|
450
|
+
const required = schema.required || [];
|
|
451
|
+
const uniqueFields = [];
|
|
452
|
+
const enumFields = {};
|
|
453
|
+
// 处理普通属性和关联关系
|
|
454
|
+
Object.entries(properties).forEach(([propName, prop]) => {
|
|
455
|
+
var _a;
|
|
456
|
+
// 检查是否为关联关系字段(基于format属性)
|
|
457
|
+
const isRelationField = prop.format && ['one-one', 'one-one-r', 'one-many', 'many-one', 'many-many'].includes(prop.format);
|
|
458
|
+
if (isRelationField) {
|
|
459
|
+
// 只收集关联关系用于后续生成,不添加到类定义中
|
|
460
|
+
const targetClass = ((_a = prop['x-parent']) === null || _a === void 0 ? void 0 : _a.parentDataSourceName) || '';
|
|
461
|
+
if (targetClass && prop.format) {
|
|
462
|
+
const relation = generateRelation(className, targetClass, propName, prop.format);
|
|
463
|
+
if (relation) {
|
|
464
|
+
relationSet.add(relation);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
// 生成普通属性定义
|
|
470
|
+
let propLine = ` ${propName}: `;
|
|
471
|
+
// 确定类型
|
|
472
|
+
let propType = prop.type;
|
|
473
|
+
if (prop.format) {
|
|
474
|
+
switch (prop.format) {
|
|
475
|
+
case 'email':
|
|
476
|
+
propType = 'email';
|
|
477
|
+
break;
|
|
478
|
+
case 'phone':
|
|
479
|
+
propType = 'phone';
|
|
480
|
+
break;
|
|
481
|
+
case 'datetime':
|
|
482
|
+
propType = 'datetime';
|
|
483
|
+
break;
|
|
484
|
+
case 'enum':
|
|
485
|
+
propType = 'x-enum';
|
|
486
|
+
if (prop.enum) {
|
|
487
|
+
enumFields[propName] = prop.enum;
|
|
488
|
+
}
|
|
489
|
+
break;
|
|
490
|
+
case 'x-image':
|
|
491
|
+
propType = 'x-image';
|
|
492
|
+
break;
|
|
493
|
+
case 'x-rtf':
|
|
494
|
+
propType = 'x-rtf';
|
|
495
|
+
break;
|
|
496
|
+
case 'x-location':
|
|
497
|
+
propType = 'x-location';
|
|
498
|
+
break;
|
|
499
|
+
case 'x-area-code':
|
|
500
|
+
propType = 'x-area-code';
|
|
501
|
+
break;
|
|
502
|
+
case 'x-file':
|
|
503
|
+
propType = 'x-file';
|
|
504
|
+
break;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
else {
|
|
508
|
+
// 如果没有format,根据type来决定
|
|
509
|
+
switch (prop.type) {
|
|
510
|
+
case 'number':
|
|
511
|
+
propType = 'number';
|
|
512
|
+
break;
|
|
513
|
+
case 'boolean':
|
|
514
|
+
propType = 'boolean';
|
|
515
|
+
break;
|
|
516
|
+
case 'string':
|
|
517
|
+
default:
|
|
518
|
+
propType = 'string';
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
// 处理数组类型
|
|
523
|
+
if (prop.type === 'array' && prop.items) {
|
|
524
|
+
const itemType = prop.items.type;
|
|
525
|
+
propType = `${itemType}[]`;
|
|
526
|
+
}
|
|
527
|
+
propLine += propType;
|
|
528
|
+
// 添加默认值
|
|
529
|
+
if (prop.default !== undefined) {
|
|
530
|
+
if (typeof prop.default === 'string') {
|
|
531
|
+
propLine += ` = "${prop.default}"`;
|
|
532
|
+
}
|
|
533
|
+
else {
|
|
534
|
+
propLine += ` = ${prop.default}`;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
// 添加标题
|
|
538
|
+
if (prop.title) {
|
|
539
|
+
propLine += ` <<${prop.title}>>`;
|
|
540
|
+
}
|
|
541
|
+
lines.push(propLine);
|
|
542
|
+
// 收集唯一性约束
|
|
543
|
+
if (prop['x-unique']) {
|
|
544
|
+
uniqueFields.push(propName);
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
// 添加约束方法
|
|
548
|
+
if (required.length > 0) {
|
|
549
|
+
const requiredStr = required.map((f) => `"${f}"`).join(', ');
|
|
550
|
+
lines.push(` required() [${requiredStr}]`);
|
|
551
|
+
}
|
|
552
|
+
if (uniqueFields.length > 0) {
|
|
553
|
+
const uniqueStr = uniqueFields.map((f) => `"${f}"`).join(', ');
|
|
554
|
+
lines.push(` unique() [${uniqueStr}]`);
|
|
555
|
+
}
|
|
556
|
+
// 添加显示字段方法
|
|
557
|
+
if (schema['x-primary-column']) {
|
|
558
|
+
lines.push(` display_field() "${schema['x-primary-column']}"`);
|
|
559
|
+
}
|
|
560
|
+
// 添加枚举方法
|
|
561
|
+
Object.entries(enumFields).forEach(([fieldName, values]) => {
|
|
562
|
+
const enumStr = values.map((v) => `"${v}"`).join(', ');
|
|
563
|
+
lines.push(` enum_${fieldName}() [${enumStr}]`);
|
|
564
|
+
});
|
|
565
|
+
lines.push(' }');
|
|
566
|
+
lines.push('');
|
|
567
|
+
// 收集注释
|
|
568
|
+
if (schema.title && schema.title !== className) {
|
|
569
|
+
notes.push(` note for ${className} "${schema.title}"`);
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
// 添加关联关系(去重后)
|
|
573
|
+
if (relationSet.size > 0) {
|
|
574
|
+
lines.push(' %% 关联关系');
|
|
575
|
+
// 去重逻辑:只保留原始方向的关系,避免重复
|
|
576
|
+
const uniqueRelations = new Set();
|
|
577
|
+
const processedPairs = new Set();
|
|
578
|
+
Array.from(relationSet).forEach((relationStr) => {
|
|
579
|
+
const match = relationStr.match(/(\w+)\s+"([^"]+)"\s+(.*?)\s+"([^"]+)"\s+(\w+)\s*:\s*(.+)/);
|
|
580
|
+
if (match) {
|
|
581
|
+
const [, class1, card1, arrow, card2, class2, relationName] = match;
|
|
582
|
+
// 创建关系对的标识符 - 考虑箭头方向
|
|
583
|
+
const directionKey = arrow.includes('<--') ? `${class2}-${class1}` : `${class1}-${class2}`;
|
|
584
|
+
const pairKey = directionKey + '-' + relationName;
|
|
585
|
+
// 如果这个关系对还没有被处理过,就添加它
|
|
586
|
+
if (!processedPairs.has(pairKey)) {
|
|
587
|
+
uniqueRelations.add(relationStr);
|
|
588
|
+
processedPairs.add(pairKey);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
Array.from(uniqueRelations).forEach((relation) => {
|
|
593
|
+
lines.push(` ${relation}`);
|
|
594
|
+
});
|
|
595
|
+
lines.push('');
|
|
596
|
+
}
|
|
597
|
+
// 添加注释
|
|
598
|
+
if (notes.length > 0) {
|
|
599
|
+
lines.push(' %% 类的命名');
|
|
600
|
+
notes.forEach((note) => {
|
|
601
|
+
lines.push(note);
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
return lines.join('\n');
|
|
605
|
+
}
|
|
606
|
+
exports.jsonSchemaToMermaid = jsonSchemaToMermaid;
|
|
607
|
+
// 生成关联关系字符串
|
|
608
|
+
function generateRelation(fromClass, toClass, relationName, format) {
|
|
609
|
+
const relationMap = {
|
|
610
|
+
'one-one': { cardinality1: '1', cardinality2: '1', arrow: '-->' },
|
|
611
|
+
'one-one-r': { cardinality1: '1', cardinality2: '1', arrow: '<--' },
|
|
612
|
+
'one-many': { cardinality1: '1', cardinality2: 'n', arrow: '-->' },
|
|
613
|
+
'many-one': { cardinality1: 'n', cardinality2: '1', arrow: '-->' },
|
|
614
|
+
'many-many': { cardinality1: 'n', cardinality2: 'm', arrow: '-->' },
|
|
615
|
+
};
|
|
616
|
+
const relation = relationMap[format];
|
|
617
|
+
if (!relation)
|
|
618
|
+
return null;
|
|
619
|
+
// 对于反向关系,需要交换类的位置
|
|
620
|
+
if (format === 'one-one-r') {
|
|
621
|
+
return `${toClass} "${relation.cardinality2}" ${relation.arrow} "${relation.cardinality1}" ${fromClass} : ${relationName}`;
|
|
622
|
+
}
|
|
623
|
+
return `${fromClass} "${relation.cardinality1}" ${relation.arrow} "${relation.cardinality2}" ${toClass} : ${relationName}`;
|
|
624
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity_reservation.d.ts","sourceRoot":"","sources":["../../../../../../src/utils/mermaid-datasource/prompts/cases/activity_reservation.ts"],"names":[],"mappings":"AAGA;;;GAGG;;;;;;AAGH,wBAAurF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
//
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
/**
|
|
6
|
+
* 本文件由 build.ts 自动生成,请勿手动修改
|
|
7
|
+
* }
|
|
8
|
+
*/
|
|
9
|
+
exports.default = { "user": "创建一个活动预约管理应用", "assistant": "以下是基于活动预约管理应用的Mermaid类图设计:\n```mermaid\nclassDiagram\n class Activity {\n title: string <<活动标题>>\n description: x-rtf <<活动描述>>\n coverImage: x-image <<封面图片>>\n startTime: datetime <<开始时间>>\n endTime: datetime <<结束时间>>\n registrationDeadline: datetime <<报名截止时间>>\n maxParticipants: number <<最大参与人数>>\n currentParticipants: number = 0 <<当前参与人数>>\n location: string <<活动地点>>\n areaCode: x-area-code <<活动区域>>\n status: x-enum = \"未开始\" <<活动状态>>\n required() [\"title\", \"startTime\", \"endTime\", \"maxParticipants\"]\n enum_status() [\"未开始\", \"进行中\", \"已结束\", \"已取消\"] \n unique() [\"title\"]\n }\n \n class ReservationSystemUser {\n username: string <<用户名>>\n email: email <<邮箱>>\n phone: phone <<手机号>>\n avatar: x-image <<头像>>\n registrationTime: datetime <<注册时间>>\n lastLoginTime: datetime <<最后登录时间>>\n required() [\"username\", \"email\"]\n unique() [\"username\", \"email\", \"phone\"]\n }\n \n class ActivityReservation {\n reservationTime: datetime <<预约时间>>\n status: x-enum = \"待确认\" <<预约状态>>\n notes: string <<备注>>\n enum_status() [\"待确认\", \"已确认\", \"已取消\", \"已签到\"]\n required() [\"reservationTime\"]\n }\n \n class ActivityCategory {\n name: string <<分类名称>>\n icon: string <<图标>>\n required() [\"name\"]\n unique() [\"name\"]\n }\n \n class ActivityReview {\n rating: number <<评分>>\n content: string <<评价内容>>\n reviewTime: datetime <<评价时间>>\n required() [\"rating\", \"reviewTime\"]\n }\n\n %% 关联关系\n Activity \"1\" --> \"n\" ActivityReservation : activity2reservation\n ReservationSystemUser \"1\" --> \"n\" ActivityReservation : user2reservation\n Activity \"n\" --> \"m\" ActivityCategory : categories\n Activity \"n\" <-- \"m\" ActivityCategory : activities\n Activity \"1\" --> \"n\" ActivityReview : activity2review\n ReservationSystemUser \"1\" --> \"n\" ActivityReview : user2review\n \n %% 类的命名\n note for Activity \"活动模型\"\n note for ReservationSystemUser \"用户模型\"\n note for ActivityReservation \"预约模型\"\n note for ActivityCategory \"分类模型\"\n note for ActivityReview \"评价模型\"\n```\n\n这个设计包含以下核心功能:\n1. 用户管理(ReservationSystemUser):包含用户基本信息和联系方式\n2. 活动管理(Activity):包含活动详情、时间、地点等信息\n3. 预约管理(ActivityReservation):记录用户预约活动的情况\n4. 活动分类(ActivityCategory):对活动进行分类管理\n5. 评价系统(ActivityReview):用户对活动的评价和评分\n\n关键特性:\n• 使用\n\n• 地理位置使用x-location类型\n\n• 设置了必填字段和唯一约束\n\n• 包含默认值设置(如最大参与人数默认为100)\n\n• 使用标准类型映射(如phone、email等)", "name": "activity_reservation" };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/utils/mermaid-datasource/prompts/cases/index.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,KAAK;;;;GAGjB,CAAC"}
|