@shys/crud 1.0.1-beta.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/dist/cli.d.ts +2 -0
- package/dist/cli.js +305 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.js +115 -0
- package/dist/db.d.ts +5 -0
- package/dist/db.js +132 -0
- package/dist/generator.d.ts +27 -0
- package/dist/generator.js +322 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +7 -0
- package/dist/orm.d.ts +2 -0
- package/dist/orm.js +57 -0
- package/dist/renderer.d.ts +14 -0
- package/dist/renderer.js +62 -0
- package/dist/templates.d.ts +70 -0
- package/dist/templates.js +528 -0
- package/dist/types.d.ts +43 -0
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +33 -0
- package/package.json +51 -0
- package/templates/controller.njk +65 -0
- package/templates/crud-page-vo.njk +59 -0
- package/templates/dto-create.njk +18 -0
- package/templates/dto-index.njk +4 -0
- package/templates/dto-query.njk +71 -0
- package/templates/dto-replace.njk +21 -0
- package/templates/dto-update.njk +22 -0
- package/templates/entity.njk +60 -0
- package/templates/service.njk +20 -0
- package/templates/vo-index.njk +2 -0
- package/templates/vo-list.njk +15 -0
- package/templates/vo-single.njk +24 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { toCamelCase, toPascalCase, toPluralKebab } from './utils.js';
|
|
3
|
+
import { createRenderer } from './renderer.js';
|
|
4
|
+
const BASE_FIELD_NAMES = ['createTime', 'updateTime', 'deleteTime'];
|
|
5
|
+
const JSTypeMap = {
|
|
6
|
+
int: 'number', integer: 'number', bigint: 'number', smallint: 'number', tinyint: 'number', mediumint: 'number',
|
|
7
|
+
decimal: 'number', numeric: 'number', float: 'number', double: 'number', real: 'number',
|
|
8
|
+
char: 'string', varchar: 'string', text: 'string', tinytext: 'string', mediumtext: 'string', longtext: 'string',
|
|
9
|
+
enum: 'string', set: 'string', json: 'any',
|
|
10
|
+
date: 'Date', datetime: 'Date', timestamp: 'Date', time: 'Date', year: 'number',
|
|
11
|
+
binary: 'Buffer', varbinary: 'Buffer', blob: 'Buffer',
|
|
12
|
+
bool: 'boolean', boolean: 'boolean', bit: 'boolean',
|
|
13
|
+
};
|
|
14
|
+
const NO_LENGTH_ORM_TYPES = /^(text|tinytext|mediumtext|longtext|blob|tinyblob|mediumblob|longblob|json)$/i;
|
|
15
|
+
function normalizeOrmType(type) {
|
|
16
|
+
return String(type).toLowerCase().replace(/\(\d+.*?\)/, '').trim() || 'varchar';
|
|
17
|
+
}
|
|
18
|
+
function fieldSupportsLength(f) {
|
|
19
|
+
return !NO_LENGTH_ORM_TYPES.test(normalizeOrmType(f.type));
|
|
20
|
+
}
|
|
21
|
+
function jsTypeOf(field) {
|
|
22
|
+
const base = JSTypeMap[field.type] || 'string';
|
|
23
|
+
if (field.nullable)
|
|
24
|
+
return `${base} | null`;
|
|
25
|
+
return base;
|
|
26
|
+
}
|
|
27
|
+
function createDtoTypeOf(field) {
|
|
28
|
+
const base = JSTypeMap[field.type] || 'string';
|
|
29
|
+
return `${base}${field.nullable ? ' | null' : ''}`;
|
|
30
|
+
}
|
|
31
|
+
function joiSwagType(f) {
|
|
32
|
+
const t = f.type;
|
|
33
|
+
if (t === 'int' || t === 'bigint' || t === 'smallint' || t === 'tinyint' || t === 'mediumint' || t === 'integer')
|
|
34
|
+
return `'integer'`;
|
|
35
|
+
if (t === 'decimal' || t === 'numeric' || t === 'float' || t === 'double' || t === 'real' || t === 'number')
|
|
36
|
+
return `'number'`;
|
|
37
|
+
if (t === 'datetime' || t === 'timestamp' || t === 'date')
|
|
38
|
+
return `'string'`;
|
|
39
|
+
if (t === 'bool' || t === 'boolean')
|
|
40
|
+
return `'boolean'`;
|
|
41
|
+
return `'string'`;
|
|
42
|
+
}
|
|
43
|
+
function joiRuleOf(field, opts = {}) {
|
|
44
|
+
const { required = false, allowNull = false } = opts;
|
|
45
|
+
const t = field.type;
|
|
46
|
+
let j;
|
|
47
|
+
switch (t) {
|
|
48
|
+
case 'int':
|
|
49
|
+
case 'integer':
|
|
50
|
+
case 'bigint':
|
|
51
|
+
case 'smallint':
|
|
52
|
+
case 'tinyint':
|
|
53
|
+
case 'mediumint':
|
|
54
|
+
j = 'Joi.number().integer()';
|
|
55
|
+
break;
|
|
56
|
+
case 'decimal':
|
|
57
|
+
case 'numeric':
|
|
58
|
+
case 'float':
|
|
59
|
+
case 'double':
|
|
60
|
+
case 'real':
|
|
61
|
+
j = 'Joi.number()';
|
|
62
|
+
break;
|
|
63
|
+
case 'date':
|
|
64
|
+
case 'datetime':
|
|
65
|
+
case 'timestamp':
|
|
66
|
+
j = 'Joi.date()';
|
|
67
|
+
break;
|
|
68
|
+
case 'bool':
|
|
69
|
+
case 'boolean':
|
|
70
|
+
j = 'Joi.boolean()';
|
|
71
|
+
break;
|
|
72
|
+
default:
|
|
73
|
+
j = 'Joi.string()' + (field.len ? `.max(${field.len})` : '');
|
|
74
|
+
}
|
|
75
|
+
if (allowNull)
|
|
76
|
+
j += '.allow(null)';
|
|
77
|
+
if (required)
|
|
78
|
+
j += '.required()';
|
|
79
|
+
return j;
|
|
80
|
+
}
|
|
81
|
+
function zodRuleOf(field) {
|
|
82
|
+
const t = field.type;
|
|
83
|
+
let zodBase;
|
|
84
|
+
if (/int|bigint|smallint|tinyint|mediumint|integer/.test(t)) {
|
|
85
|
+
zodBase = 'z.number().int()';
|
|
86
|
+
}
|
|
87
|
+
else if (/decimal|numeric|float|double|real/.test(t)) {
|
|
88
|
+
zodBase = 'z.number()';
|
|
89
|
+
}
|
|
90
|
+
else if (/date|datetime|timestamp/.test(t)) {
|
|
91
|
+
zodBase = 'z.date()';
|
|
92
|
+
}
|
|
93
|
+
else if (/bool|boolean/.test(t)) {
|
|
94
|
+
zodBase = 'z.boolean()';
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
zodBase = `z.string()${field.len ? `.max(${field.len})` : ''}`;
|
|
98
|
+
}
|
|
99
|
+
return `${zodBase}.describe(${JSON.stringify(field.comment || field.camel)})`;
|
|
100
|
+
}
|
|
101
|
+
function enhanceField(f, extra = {}) {
|
|
102
|
+
return {
|
|
103
|
+
...f,
|
|
104
|
+
swagType: joiSwagType(f),
|
|
105
|
+
jsType: jsTypeOf(f),
|
|
106
|
+
createDtoType: createDtoTypeOf(f),
|
|
107
|
+
joiRule: joiRuleOf(f, { required: false, allowNull: f.nullable }),
|
|
108
|
+
joiRuleRequired: joiRuleOf(f, { required: true, allowNull: f.nullable }),
|
|
109
|
+
zodRule: zodRuleOf(f),
|
|
110
|
+
ormType: normalizeOrmType(f.type),
|
|
111
|
+
supportsLength: fieldSupportsLength(f),
|
|
112
|
+
isDate: /datetime|date|timestamp/i.test(f.type),
|
|
113
|
+
isSensitive: /password|passwd|salt|token|secret|private_key/i.test(f.name + f.camel),
|
|
114
|
+
voType: /datetime|date|timestamp/i.test(f.type) ? 'string' : (JSTypeMap[f.type] || 'string'),
|
|
115
|
+
idx: !!extra.idx,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
export function buildFiles(params) {
|
|
119
|
+
const { moduleName, tableName, baseSrcPath, ormInfo, fields, outputPath, templatesPath, renderer: customRenderer, onlyEntity } = params;
|
|
120
|
+
const renderer = customRenderer || createRenderer({ customTemplatesPath: templatesPath });
|
|
121
|
+
const Camel = toCamelCase(tableName);
|
|
122
|
+
const Pascal = toPascalCase(tableName);
|
|
123
|
+
const CreateName = `Create${Pascal}Dto`;
|
|
124
|
+
const UpdateName = `Update${Pascal}Dto`;
|
|
125
|
+
const ReplaceName = `Replace${Pascal}Dto`;
|
|
126
|
+
const QueryName = `Query${Pascal}Dto`;
|
|
127
|
+
const VOName = `${Pascal}VO`;
|
|
128
|
+
const ListVOName = `${Pascal}ListVO`;
|
|
129
|
+
const ServiceName = `${Pascal}Service`;
|
|
130
|
+
const CtrlName = `${Pascal}Controller`;
|
|
131
|
+
const pluralKebab = toPluralKebab(tableName);
|
|
132
|
+
const tagName = `${Pascal}管理`;
|
|
133
|
+
const desc = `${tableName} 表增删改查接口`;
|
|
134
|
+
const modRoot = resolve(outputPath || baseSrcPath, 'modules', moduleName);
|
|
135
|
+
const resultFiles = [];
|
|
136
|
+
const originalPkInfo = fields.find((f) => f.pk);
|
|
137
|
+
const hasPk = !!originalPkInfo;
|
|
138
|
+
const entityFields = fields.filter((f) => {
|
|
139
|
+
if (BASE_FIELD_NAMES.includes(f.camel))
|
|
140
|
+
return false;
|
|
141
|
+
if (f.pk)
|
|
142
|
+
return false;
|
|
143
|
+
return true;
|
|
144
|
+
});
|
|
145
|
+
const idxFields = entityFields.filter((f) => !f.pk && (String(f.name).toUpperCase() === 'COUNTRYCODE' || /_id$/.test(f.name)));
|
|
146
|
+
const hasDateField = entityFields.some((f) => /datetime|date|timestamp/i.test(f.type));
|
|
147
|
+
const enhancedEntityFields = entityFields.map((f) => enhanceField(f, { idx: idxFields.some((i) => i.name === f.name) }));
|
|
148
|
+
const enhancedPkInfo = originalPkInfo ? enhanceField(originalPkInfo) : null;
|
|
149
|
+
// Entity
|
|
150
|
+
resultFiles.push({
|
|
151
|
+
path: resolve(modRoot, `entity/${Camel}.entity.ts`),
|
|
152
|
+
content: renderer.render('entity', {
|
|
153
|
+
orm: ormInfo.orm,
|
|
154
|
+
ormSuffix: ormInfo.ormSuffix,
|
|
155
|
+
fields: enhancedEntityFields,
|
|
156
|
+
tableName,
|
|
157
|
+
Pascal,
|
|
158
|
+
Camel,
|
|
159
|
+
pkInfo: enhancedPkInfo,
|
|
160
|
+
hasPk,
|
|
161
|
+
hasDateField,
|
|
162
|
+
idxCount: idxFields.length,
|
|
163
|
+
}),
|
|
164
|
+
});
|
|
165
|
+
if (onlyEntity) {
|
|
166
|
+
return {
|
|
167
|
+
files: resultFiles,
|
|
168
|
+
Pascal,
|
|
169
|
+
pluralKebab,
|
|
170
|
+
Camel,
|
|
171
|
+
sortable: [],
|
|
172
|
+
filterable: [],
|
|
173
|
+
searchable: [],
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
const createFields = entityFields.filter((f) => !(f.pk && f.auto));
|
|
177
|
+
const writable = createFields.filter((f) => !/ctime|mtime|created_at|updated_at|create_time|update_time/i.test(f.name));
|
|
178
|
+
const isSensitive = (f) => /password|passwd|salt|token|secret|private_key/i.test(f.name + f.camel);
|
|
179
|
+
const pkCamel = originalPkInfo?.camel || '';
|
|
180
|
+
const sortableBase = entityFields.filter((f) => !isSensitive(f)).map((f) => f.camel);
|
|
181
|
+
const sortable = pkCamel && !sortableBase.includes(pkCamel)
|
|
182
|
+
? [pkCamel, ...sortableBase]
|
|
183
|
+
: sortableBase;
|
|
184
|
+
const filterableBase = entityFields.filter((f) => !isSensitive(f));
|
|
185
|
+
const filterableArr = pkCamel && !filterableBase.some((f) => f.camel === pkCamel)
|
|
186
|
+
? [originalPkInfo, ...filterableBase]
|
|
187
|
+
: filterableBase;
|
|
188
|
+
const filterable = filterableArr.map((f) => f.camel);
|
|
189
|
+
const searchable = filterableArr
|
|
190
|
+
.filter((f) => /char|varchar|text/i.test(f.type))
|
|
191
|
+
.map((f) => f.camel);
|
|
192
|
+
const enhancedCreateFields = createFields.map((f) => enhanceField(f));
|
|
193
|
+
const enhancedWritable = writable.map((f) => enhanceField(f));
|
|
194
|
+
const enhancedFilterable = filterableArr.map((f) => enhanceField(f));
|
|
195
|
+
// Create DTO
|
|
196
|
+
resultFiles.push({
|
|
197
|
+
path: resolve(modRoot, `dto/${Camel}/create.dto.ts`),
|
|
198
|
+
content: renderer.render('dto-create', {
|
|
199
|
+
CreateName,
|
|
200
|
+
Pascal,
|
|
201
|
+
createFields: enhancedCreateFields,
|
|
202
|
+
}),
|
|
203
|
+
});
|
|
204
|
+
// Update DTO
|
|
205
|
+
const updatePicks = enhancedWritable.map((f) => JSON.stringify(f.camel)).join(',\n ');
|
|
206
|
+
const updateTypeArgs = enhancedWritable.map((f) => `'${f.camel}'`).join(' | ');
|
|
207
|
+
resultFiles.push({
|
|
208
|
+
path: resolve(modRoot, `dto/${Camel}/update.dto.ts`),
|
|
209
|
+
content: renderer.render('dto-update', {
|
|
210
|
+
UpdateName,
|
|
211
|
+
CreateName,
|
|
212
|
+
writable: enhancedWritable,
|
|
213
|
+
picks: updatePicks,
|
|
214
|
+
typeArgs: updateTypeArgs || 'never',
|
|
215
|
+
}),
|
|
216
|
+
});
|
|
217
|
+
// Replace DTO
|
|
218
|
+
const replacePicks = enhancedWritable.map((f) => JSON.stringify(f.camel)).join(',\n ');
|
|
219
|
+
resultFiles.push({
|
|
220
|
+
path: resolve(modRoot, `dto/${Camel}/replace.dto.ts`),
|
|
221
|
+
content: renderer.render('dto-replace', {
|
|
222
|
+
ReplaceName,
|
|
223
|
+
CreateName,
|
|
224
|
+
writable: enhancedWritable,
|
|
225
|
+
picks: replacePicks,
|
|
226
|
+
}),
|
|
227
|
+
});
|
|
228
|
+
// Query DTO
|
|
229
|
+
const queryPicks = enhancedFilterable.map((f) => JSON.stringify(f.camel)).join(',\n ');
|
|
230
|
+
const queryTypeArgs = enhancedFilterable.map((f) => `'${f.camel}'`).join(' | ');
|
|
231
|
+
const sortEx = filterable[0] ? `${filterable[0]}:ASC,id:DESC` : 'id:DESC';
|
|
232
|
+
const filterEx = filterableArr
|
|
233
|
+
.slice(0, 2)
|
|
234
|
+
.map((f) => {
|
|
235
|
+
const isStr = /char|varchar|text/i.test(f.type);
|
|
236
|
+
return isStr ? `${f.camel}:like:a` : `${f.camel}:gte:10`;
|
|
237
|
+
})
|
|
238
|
+
.join(',');
|
|
239
|
+
const searchFields = searchable.join('/') || '无';
|
|
240
|
+
resultFiles.push({
|
|
241
|
+
path: resolve(modRoot, `dto/${Camel}/query.dto.ts`),
|
|
242
|
+
content: renderer.render('dto-query', {
|
|
243
|
+
QueryName,
|
|
244
|
+
CreateName,
|
|
245
|
+
filterable: enhancedFilterable,
|
|
246
|
+
picks: queryPicks,
|
|
247
|
+
typeArgs: queryTypeArgs || 'never',
|
|
248
|
+
sortDescription: '排序字段。标准格式:field:ASC 或 field:DESC;多字段用英文逗号分隔,或多次传 sort。示例:id:DESC、' + sortEx,
|
|
249
|
+
filterExample: filterEx || 'id:gte:1',
|
|
250
|
+
searchDescription: '搜索关键字,对可搜索字段(' + searchFields + ')模糊匹配',
|
|
251
|
+
}),
|
|
252
|
+
});
|
|
253
|
+
// DTO index
|
|
254
|
+
resultFiles.push({
|
|
255
|
+
path: resolve(modRoot, `dto/${Camel}/index.ts`),
|
|
256
|
+
content: renderer.render('dto-index', {}),
|
|
257
|
+
});
|
|
258
|
+
// Single VO
|
|
259
|
+
const allVoFields = [...(originalPkInfo ? [originalPkInfo] : []), ...entityFields].map((f) => enhanceField(f));
|
|
260
|
+
const voHasTransform = allVoFields.some((f) => f.isDate || f.isSensitive);
|
|
261
|
+
resultFiles.push({
|
|
262
|
+
path: resolve(modRoot, `vo/${Camel}/${Camel}.vo.ts`),
|
|
263
|
+
content: renderer.render('vo-single', {
|
|
264
|
+
VOName,
|
|
265
|
+
fields: allVoFields,
|
|
266
|
+
hasTransform: voHasTransform,
|
|
267
|
+
}),
|
|
268
|
+
});
|
|
269
|
+
// List VO
|
|
270
|
+
resultFiles.push({
|
|
271
|
+
path: resolve(modRoot, `vo/${Camel}/${Camel}List.vo.ts`),
|
|
272
|
+
content: renderer.render('vo-list', {
|
|
273
|
+
ListVOName,
|
|
274
|
+
VOName,
|
|
275
|
+
Camel,
|
|
276
|
+
}),
|
|
277
|
+
});
|
|
278
|
+
// VO index
|
|
279
|
+
resultFiles.push({
|
|
280
|
+
path: resolve(modRoot, `vo/${Camel}/index.ts`),
|
|
281
|
+
content: renderer.render('vo-index', { Camel }),
|
|
282
|
+
});
|
|
283
|
+
// Service
|
|
284
|
+
resultFiles.push({
|
|
285
|
+
path: resolve(modRoot, `service/${Camel}.service.ts`),
|
|
286
|
+
content: renderer.render('service', {
|
|
287
|
+
ServiceName,
|
|
288
|
+
Pascal,
|
|
289
|
+
Camel,
|
|
290
|
+
ormInfo,
|
|
291
|
+
}),
|
|
292
|
+
});
|
|
293
|
+
// Controller
|
|
294
|
+
const sArr = (arr) => arr.map((x) => JSON.stringify(x)).join(', ');
|
|
295
|
+
const idField = pkCamel || 'id';
|
|
296
|
+
const defaultSort = searchable && searchable.length
|
|
297
|
+
? `[{ field: ${JSON.stringify(sortable[0] || idField)}, order: 'DESC' }]`
|
|
298
|
+
: `[{ field: 'id', order: 'DESC' }]`;
|
|
299
|
+
resultFiles.push({
|
|
300
|
+
path: resolve(modRoot, `controller/${Camel}.controller.ts`),
|
|
301
|
+
content: renderer.render('controller', {
|
|
302
|
+
CtrlName, Pascal, ServiceName,
|
|
303
|
+
CreateName, UpdateName, ReplaceName, QueryName,
|
|
304
|
+
VOName, ListVOName,
|
|
305
|
+
Camel, pluralKebab, tagName, desc,
|
|
306
|
+
sortable: sArr(sortable),
|
|
307
|
+
filterable: sArr(filterable),
|
|
308
|
+
searchable: sArr(searchable),
|
|
309
|
+
pkCamel,
|
|
310
|
+
idField,
|
|
311
|
+
defaultSort,
|
|
312
|
+
}),
|
|
313
|
+
});
|
|
314
|
+
// Common VO
|
|
315
|
+
const commonVO = resolve(outputPath || baseSrcPath, 'framework/vo/crudPage.vo.ts');
|
|
316
|
+
resultFiles.push({
|
|
317
|
+
path: commonVO,
|
|
318
|
+
content: renderer.render('crud-page-vo', {}),
|
|
319
|
+
createOnly: true,
|
|
320
|
+
});
|
|
321
|
+
return { files: resultFiles, Pascal, pluralKebab, Camel, sortable, filterable, searchable };
|
|
322
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { loadConfig, mergeConfigs } from './config.js';
|
|
2
|
+
export { detectOrm } from './orm.js';
|
|
3
|
+
export { getDbConfigFromProject, resolveDefaultDbName, getTableFieldsFromDb, templateFieldsFor, } from './db.js';
|
|
4
|
+
export { buildFiles } from './generator.js';
|
|
5
|
+
export { TemplateRenderer, createRenderer } from './renderer.js';
|
|
6
|
+
export type { TemplateName, TemplateRendererOptions } from './renderer.js';
|
|
7
|
+
export { runCli } from './cli.js';
|
|
8
|
+
export * from './types.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { loadConfig, mergeConfigs } from './config.js';
|
|
2
|
+
export { detectOrm } from './orm.js';
|
|
3
|
+
export { getDbConfigFromProject, resolveDefaultDbName, getTableFieldsFromDb, templateFieldsFor, } from './db.js';
|
|
4
|
+
export { buildFiles } from './generator.js';
|
|
5
|
+
export { TemplateRenderer, createRenderer } from './renderer.js';
|
|
6
|
+
export { runCli } from './cli.js';
|
|
7
|
+
export * from './types.js';
|
package/dist/orm.d.ts
ADDED
package/dist/orm.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
export function detectOrm(baseSrcPath) {
|
|
4
|
+
const pkgFile = resolve(baseSrcPath, '../package.json');
|
|
5
|
+
const deps = {};
|
|
6
|
+
if (existsSync(pkgFile)) {
|
|
7
|
+
const raw = readFileSync(pkgFile, 'utf-8').replace(/^\uFEFF/, '');
|
|
8
|
+
const p = JSON.parse(raw);
|
|
9
|
+
for (const k of Object.keys(p.dependencies || {}))
|
|
10
|
+
deps[k] = p.dependencies[k];
|
|
11
|
+
for (const k of Object.keys(p.devDependencies || {}))
|
|
12
|
+
deps[k] = p.devDependencies[k];
|
|
13
|
+
}
|
|
14
|
+
if (deps['@midwayjs/typeorm'] || deps.typeorm) {
|
|
15
|
+
return {
|
|
16
|
+
orm: 'typeorm',
|
|
17
|
+
ormSuffix: 'entity',
|
|
18
|
+
serviceParent: 'TypeOrmCrudService',
|
|
19
|
+
importCrudOrm: `from '@midwayjs/crud/typeorm'`,
|
|
20
|
+
injectEntity: '@InjectEntityModel',
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (deps['@midwayjs/sequelize'] || deps.sequelize) {
|
|
24
|
+
return {
|
|
25
|
+
orm: 'sequelize',
|
|
26
|
+
ormSuffix: 'model',
|
|
27
|
+
serviceParent: 'SequelizeCrudService',
|
|
28
|
+
importCrudOrm: `from '@midwayjs/crud/sequelize'`,
|
|
29
|
+
injectEntity: '@InjectModel',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (deps['@midwayjs/mikro'] || deps['@mikro-orm/core']) {
|
|
33
|
+
return {
|
|
34
|
+
orm: 'mikro',
|
|
35
|
+
ormSuffix: 'entity',
|
|
36
|
+
serviceParent: 'MikroCrudService',
|
|
37
|
+
importCrudOrm: `from '@midwayjs/crud/mikro'`,
|
|
38
|
+
injectEntity: '@InjectRepository',
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (deps['@midwayjs/mongoose'] || deps.mongoose) {
|
|
42
|
+
return {
|
|
43
|
+
orm: 'mongoose',
|
|
44
|
+
ormSuffix: 'schema',
|
|
45
|
+
serviceParent: 'MongooseCrudService',
|
|
46
|
+
importCrudOrm: `from '@midwayjs/crud/mongoose'`,
|
|
47
|
+
injectEntity: '@InjectModel',
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
orm: 'typeorm',
|
|
52
|
+
ormSuffix: 'entity',
|
|
53
|
+
serviceParent: 'TypeOrmCrudService',
|
|
54
|
+
importCrudOrm: `from '@midwayjs/crud/typeorm'`,
|
|
55
|
+
injectEntity: '@InjectEntityModel',
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type TemplateName = 'entity' | 'dto-create' | 'dto-update' | 'dto-replace' | 'dto-query' | 'dto-index' | 'vo-single' | 'vo-list' | 'vo-index' | 'service' | 'controller' | 'crud-page-vo';
|
|
2
|
+
export interface TemplateRendererOptions {
|
|
3
|
+
customTemplatesPath?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare class TemplateRenderer {
|
|
6
|
+
private env;
|
|
7
|
+
private customTemplatesPath?;
|
|
8
|
+
constructor(options?: TemplateRendererOptions);
|
|
9
|
+
render(templateName: TemplateName, context: Record<string, any>): string;
|
|
10
|
+
hasCustomTemplate(templateName: TemplateName): boolean;
|
|
11
|
+
getDefaultTemplatesDir(): string;
|
|
12
|
+
getCustomTemplatesDir(): string | undefined;
|
|
13
|
+
}
|
|
14
|
+
export declare function createRenderer(options?: TemplateRendererOptions): TemplateRenderer;
|
package/dist/renderer.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { resolve, dirname } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import nunjucks from 'nunjucks';
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = dirname(__filename);
|
|
7
|
+
const DEFAULT_TEMPLATES_DIR = resolve(__dirname, '..', 'templates');
|
|
8
|
+
const TEMPLATE_FILES = {
|
|
9
|
+
entity: 'entity.njk',
|
|
10
|
+
'dto-create': 'dto-create.njk',
|
|
11
|
+
'dto-update': 'dto-update.njk',
|
|
12
|
+
'dto-replace': 'dto-replace.njk',
|
|
13
|
+
'dto-query': 'dto-query.njk',
|
|
14
|
+
'dto-index': 'dto-index.njk',
|
|
15
|
+
'vo-single': 'vo-single.njk',
|
|
16
|
+
'vo-list': 'vo-list.njk',
|
|
17
|
+
'vo-index': 'vo-index.njk',
|
|
18
|
+
service: 'service.njk',
|
|
19
|
+
controller: 'controller.njk',
|
|
20
|
+
'crud-page-vo': 'crud-page-vo.njk',
|
|
21
|
+
};
|
|
22
|
+
export class TemplateRenderer {
|
|
23
|
+
env;
|
|
24
|
+
customTemplatesPath;
|
|
25
|
+
constructor(options = {}) {
|
|
26
|
+
this.customTemplatesPath = options.customTemplatesPath;
|
|
27
|
+
const searchPaths = [];
|
|
28
|
+
if (this.customTemplatesPath && existsSync(this.customTemplatesPath)) {
|
|
29
|
+
searchPaths.push(this.customTemplatesPath);
|
|
30
|
+
}
|
|
31
|
+
searchPaths.push(DEFAULT_TEMPLATES_DIR);
|
|
32
|
+
this.env = new nunjucks.Environment(searchPaths.map((p) => new nunjucks.FileSystemLoader(p)), {
|
|
33
|
+
autoescape: false,
|
|
34
|
+
throwOnUndefined: false,
|
|
35
|
+
trimBlocks: false,
|
|
36
|
+
lstripBlocks: false,
|
|
37
|
+
});
|
|
38
|
+
this.env.addFilter('json', (value) => JSON.stringify(value));
|
|
39
|
+
}
|
|
40
|
+
render(templateName, context) {
|
|
41
|
+
const templateFile = TEMPLATE_FILES[templateName];
|
|
42
|
+
if (!templateFile) {
|
|
43
|
+
throw new Error(`Unknown template: ${templateName}`);
|
|
44
|
+
}
|
|
45
|
+
return this.env.render(templateFile, context);
|
|
46
|
+
}
|
|
47
|
+
hasCustomTemplate(templateName) {
|
|
48
|
+
if (!this.customTemplatesPath)
|
|
49
|
+
return false;
|
|
50
|
+
const templateFile = TEMPLATE_FILES[templateName];
|
|
51
|
+
return existsSync(resolve(this.customTemplatesPath, templateFile));
|
|
52
|
+
}
|
|
53
|
+
getDefaultTemplatesDir() {
|
|
54
|
+
return DEFAULT_TEMPLATES_DIR;
|
|
55
|
+
}
|
|
56
|
+
getCustomTemplatesDir() {
|
|
57
|
+
return this.customTemplatesPath;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function createRenderer(options = {}) {
|
|
61
|
+
return new TemplateRenderer(options);
|
|
62
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { FieldInfo, OrmInfo } from './types.js';
|
|
2
|
+
export declare function entityTemplate(params: {
|
|
3
|
+
orm: string;
|
|
4
|
+
ormSuffix: string;
|
|
5
|
+
fields: FieldInfo[];
|
|
6
|
+
tableName: string;
|
|
7
|
+
Pascal: string;
|
|
8
|
+
Camel: string;
|
|
9
|
+
originalPkInfo?: FieldInfo | null;
|
|
10
|
+
hasPk: boolean;
|
|
11
|
+
}): string;
|
|
12
|
+
export declare function createDtoTemplate(params: {
|
|
13
|
+
CreateName: string;
|
|
14
|
+
Pascal: string;
|
|
15
|
+
createFields: FieldInfo[];
|
|
16
|
+
}): string;
|
|
17
|
+
export declare function updateDtoTemplate(params: {
|
|
18
|
+
UpdateName: string;
|
|
19
|
+
CreateName: string;
|
|
20
|
+
writable: FieldInfo[];
|
|
21
|
+
Camel: string;
|
|
22
|
+
Pascal: string;
|
|
23
|
+
}): string;
|
|
24
|
+
export declare function replaceDtoTemplate(params: {
|
|
25
|
+
ReplaceName: string;
|
|
26
|
+
CreateName: string;
|
|
27
|
+
writable: FieldInfo[];
|
|
28
|
+
}): string;
|
|
29
|
+
export declare function queryDtoTemplate(params: {
|
|
30
|
+
QueryName: string;
|
|
31
|
+
CreateName: string;
|
|
32
|
+
filterable: FieldInfo[];
|
|
33
|
+
}): string;
|
|
34
|
+
export declare function singleVOTemplate(params: {
|
|
35
|
+
VOName: string;
|
|
36
|
+
Pascal: string;
|
|
37
|
+
Camel: string;
|
|
38
|
+
fields: FieldInfo[];
|
|
39
|
+
}): string;
|
|
40
|
+
export declare function listVOTemplate(params: {
|
|
41
|
+
ListVOName: string;
|
|
42
|
+
VOName: string;
|
|
43
|
+
Camel: string;
|
|
44
|
+
}): string;
|
|
45
|
+
export declare function crudPageCommonTemplate(): string;
|
|
46
|
+
export declare function serviceTemplate(params: {
|
|
47
|
+
ServiceName: string;
|
|
48
|
+
Pascal: string;
|
|
49
|
+
Camel: string;
|
|
50
|
+
ormInfo: OrmInfo;
|
|
51
|
+
}): string;
|
|
52
|
+
export declare function controllerTemplate(params: {
|
|
53
|
+
CtrlName: string;
|
|
54
|
+
Pascal: string;
|
|
55
|
+
ServiceName: string;
|
|
56
|
+
CreateName: string;
|
|
57
|
+
UpdateName: string;
|
|
58
|
+
ReplaceName: string;
|
|
59
|
+
QueryName: string;
|
|
60
|
+
VOName: string;
|
|
61
|
+
ListVOName: string;
|
|
62
|
+
Camel: string;
|
|
63
|
+
pluralKebab: string;
|
|
64
|
+
tagName: string;
|
|
65
|
+
desc: string;
|
|
66
|
+
sortable: string[];
|
|
67
|
+
filterable: string[];
|
|
68
|
+
searchable: string[];
|
|
69
|
+
pkCamel: string;
|
|
70
|
+
}): string;
|