@shys/crud 1.0.1-beta.7 → 1.0.1-beta.9
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.js +60 -50
- package/dist/config.js +2 -0
- package/dist/generator.d.ts +2 -1
- package/dist/generator.js +66 -18
- package/dist/types.d.ts +18 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -16,56 +16,56 @@ const warn = (t) => console.log(`${chalk.yellow('!')} ${t}`);
|
|
|
16
16
|
const err = (t) => console.log(`${chalk.red('✘')} ${t}`);
|
|
17
17
|
const info = (t) => console.log(`${chalk.cyan('ℹ')} ${t}`);
|
|
18
18
|
function printHelp() {
|
|
19
|
-
console.log(`shys-crud CLI — MidwayJS v4 模块化 CRUD 代码生成器
|
|
20
|
-
|
|
21
|
-
用法:
|
|
22
|
-
shys-crud --module <moduleName> --table <tableName> [选项]
|
|
23
|
-
npx @shys/crud --module <moduleName> --table <tableName> [选项]
|
|
24
|
-
|
|
25
|
-
参数:
|
|
26
|
-
-m, --module 模块名(如 home/order/goods)
|
|
27
|
-
-t, --table 表名(如 sys_dept/city/order_info)
|
|
28
|
-
-s, --src src 根路径(默认 ./src 或从配置文件读取)
|
|
29
|
-
-o, --output 生成文件输出路径(默认与 --src 相同)
|
|
30
|
-
--templates-path 自定义模板目录路径
|
|
31
|
-
|
|
32
|
-
选项:
|
|
33
|
-
-f, --force 强制覆盖已存在的文件
|
|
34
|
-
-n, --dry-run 模拟运行,不实际写入文件
|
|
35
|
-
-c, --compile 生成完后自动执行 mwtsc --cleanOutDir
|
|
36
|
-
--only-entity 仅生成 entity 文件,不生成 DTO/VO/Service/Controller
|
|
37
|
-
--no-db 不尝试连库,使用模板字段模式
|
|
38
|
-
--db-host 数据库 host
|
|
39
|
-
--db-port 数据库端口(默认 3306)
|
|
40
|
-
--db-user 数据库用户名
|
|
41
|
-
--db-pass 数据库密码
|
|
42
|
-
--db-name 数据库名
|
|
43
|
-
-h, --help 显示帮助信息
|
|
44
|
-
|
|
45
|
-
配置文件支持(按优先级从高到低):
|
|
46
|
-
--src 指向的目录或 cwd 下查找:
|
|
47
|
-
- crud.config.ts / crud.config.js / crud.config.mjs / crud.config.cjs
|
|
48
|
-
- .crudrc / .crudrc.json / .crudrc.yaml / .crudrc.yml / .crudrc.js
|
|
49
|
-
- .config/crudrc / .config/crudrc.json
|
|
50
|
-
- package.json 中的 "crud" 字段
|
|
51
|
-
|
|
52
|
-
配置文件示例(crud.config.ts):
|
|
53
|
-
export default {
|
|
54
|
-
baseSrcPath: './src',
|
|
55
|
-
outputPath: './src',
|
|
56
|
-
db: {
|
|
57
|
-
host: '127.0.0.1',
|
|
58
|
-
port: 3306,
|
|
59
|
-
user: 'root',
|
|
60
|
-
password: '',
|
|
61
|
-
database: 'mydb',
|
|
62
|
-
},
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
示例:
|
|
66
|
-
shys-crud --module home --table sys_dept
|
|
67
|
-
shys-crud --module order --table order_info --force
|
|
68
|
-
shys-crud -m home -t city -s ./packages/webtest/src --db-name world
|
|
19
|
+
console.log(`shys-crud CLI — MidwayJS v4 模块化 CRUD 代码生成器
|
|
20
|
+
|
|
21
|
+
用法:
|
|
22
|
+
shys-crud --module <moduleName> --table <tableName> [选项]
|
|
23
|
+
npx @shys/crud --module <moduleName> --table <tableName> [选项]
|
|
24
|
+
|
|
25
|
+
参数:
|
|
26
|
+
-m, --module 模块名(如 home/order/goods)
|
|
27
|
+
-t, --table 表名(如 sys_dept/city/order_info)
|
|
28
|
+
-s, --src src 根路径(默认 ./src 或从配置文件读取)
|
|
29
|
+
-o, --output 生成文件输出路径(默认与 --src 相同)
|
|
30
|
+
--templates-path 自定义模板目录路径
|
|
31
|
+
|
|
32
|
+
选项:
|
|
33
|
+
-f, --force 强制覆盖已存在的文件
|
|
34
|
+
-n, --dry-run 模拟运行,不实际写入文件
|
|
35
|
+
-c, --compile 生成完后自动执行 mwtsc --cleanOutDir
|
|
36
|
+
--only-entity 仅生成 entity 文件,不生成 DTO/VO/Service/Controller
|
|
37
|
+
--no-db 不尝试连库,使用模板字段模式
|
|
38
|
+
--db-host 数据库 host
|
|
39
|
+
--db-port 数据库端口(默认 3306)
|
|
40
|
+
--db-user 数据库用户名
|
|
41
|
+
--db-pass 数据库密码
|
|
42
|
+
--db-name 数据库名
|
|
43
|
+
-h, --help 显示帮助信息
|
|
44
|
+
|
|
45
|
+
配置文件支持(按优先级从高到低):
|
|
46
|
+
--src 指向的目录或 cwd 下查找:
|
|
47
|
+
- crud.config.ts / crud.config.js / crud.config.mjs / crud.config.cjs
|
|
48
|
+
- .crudrc / .crudrc.json / .crudrc.yaml / .crudrc.yml / .crudrc.js
|
|
49
|
+
- .config/crudrc / .config/crudrc.json
|
|
50
|
+
- package.json 中的 "crud" 字段
|
|
51
|
+
|
|
52
|
+
配置文件示例(crud.config.ts):
|
|
53
|
+
export default {
|
|
54
|
+
baseSrcPath: './src',
|
|
55
|
+
outputPath: './src',
|
|
56
|
+
db: {
|
|
57
|
+
host: '127.0.0.1',
|
|
58
|
+
port: 3306,
|
|
59
|
+
user: 'root',
|
|
60
|
+
password: '',
|
|
61
|
+
database: 'mydb',
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
示例:
|
|
66
|
+
shys-crud --module home --table sys_dept
|
|
67
|
+
shys-crud --module order --table order_info --force
|
|
68
|
+
shys-crud -m home -t city -s ./packages/webtest/src --db-name world
|
|
69
69
|
`);
|
|
70
70
|
}
|
|
71
71
|
function parseArgs(argv) {
|
|
@@ -153,6 +153,15 @@ async function askIfMissing(cli, config) {
|
|
|
153
153
|
if (!cli.onlyEntity && config.onlyEntity) {
|
|
154
154
|
cli.onlyEntity = true;
|
|
155
155
|
}
|
|
156
|
+
if (!cli.hooks && config.hooks) {
|
|
157
|
+
cli.hooks = config.hooks;
|
|
158
|
+
}
|
|
159
|
+
if (!cli.baseFieldNames && config.baseFieldNames) {
|
|
160
|
+
cli.baseFieldNames = config.baseFieldNames;
|
|
161
|
+
}
|
|
162
|
+
if (!cli.excludeWritableFields && config.excludeWritableFields) {
|
|
163
|
+
cli.excludeWritableFields = config.excludeWritableFields;
|
|
164
|
+
}
|
|
156
165
|
}
|
|
157
166
|
finally {
|
|
158
167
|
rl.close();
|
|
@@ -279,6 +288,7 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
279
288
|
onlyEntity: cli.onlyEntity,
|
|
280
289
|
baseFieldNames: cli.baseFieldNames,
|
|
281
290
|
excludeWritableFields: cli.excludeWritableFields,
|
|
291
|
+
hooks: cli.hooks,
|
|
282
292
|
});
|
|
283
293
|
console.log(`\n${chalk.cyan(`生成清单(${built.files.length})`)}`);
|
|
284
294
|
const stats = writeAll(built.files, { force: !!cli.force, dryRun: !!cli.dryRun });
|
package/dist/config.js
CHANGED
|
@@ -111,6 +111,8 @@ export function mergeConfigs(...configs) {
|
|
|
111
111
|
result.baseFieldNames = config.baseFieldNames;
|
|
112
112
|
if (config.excludeWritableFields !== undefined)
|
|
113
113
|
result.excludeWritableFields = config.excludeWritableFields;
|
|
114
|
+
if (config.hooks !== undefined)
|
|
115
|
+
result.hooks = { ...(result.hooks || {}), ...config.hooks };
|
|
114
116
|
if (config.db) {
|
|
115
117
|
result.db = { ...(result.db || {}), ...config.db };
|
|
116
118
|
}
|
package/dist/generator.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FieldInfo, OrmInfo } from './types.js';
|
|
1
|
+
import type { CrudHooks, FieldInfo, OrmInfo } from './types.js';
|
|
2
2
|
import { TemplateRenderer } from './renderer.js';
|
|
3
3
|
export interface BuildResult {
|
|
4
4
|
files: Array<{
|
|
@@ -25,5 +25,6 @@ export interface BuildFilesParams {
|
|
|
25
25
|
onlyEntity?: boolean;
|
|
26
26
|
baseFieldNames?: string[];
|
|
27
27
|
excludeWritableFields?: string[];
|
|
28
|
+
hooks?: CrudHooks;
|
|
28
29
|
}
|
|
29
30
|
export declare function buildFiles(params: BuildFilesParams): BuildResult;
|
package/dist/generator.js
CHANGED
|
@@ -166,13 +166,44 @@ function enhanceField(f, extra = {}) {
|
|
|
166
166
|
};
|
|
167
167
|
}
|
|
168
168
|
export function buildFiles(params) {
|
|
169
|
-
const { moduleName, tableName, baseSrcPath, ormInfo, fields, outputPath, templatesPath, renderer: customRenderer, onlyEntity, baseFieldNames, excludeWritableFields, } = params;
|
|
169
|
+
const { moduleName, tableName: rawTableName, baseSrcPath, ormInfo, fields: rawFields, outputPath, templatesPath, renderer: customRenderer, onlyEntity, baseFieldNames, excludeWritableFields, hooks, } = params;
|
|
170
|
+
const tableName = hooks?.customTableName
|
|
171
|
+
? hooks.customTableName(rawTableName)
|
|
172
|
+
: rawTableName;
|
|
173
|
+
let fields = rawFields;
|
|
174
|
+
if (hooks?.customFields) {
|
|
175
|
+
fields = hooks.customFields(fields);
|
|
176
|
+
}
|
|
177
|
+
if (hooks?.customField || hooks?.customFieldName) {
|
|
178
|
+
fields = fields
|
|
179
|
+
.map((f) => {
|
|
180
|
+
let field = { ...f };
|
|
181
|
+
if (hooks?.customFieldName) {
|
|
182
|
+
const newName = hooks.customFieldName(field.name);
|
|
183
|
+
if (newName !== field.name) {
|
|
184
|
+
field.name = newName;
|
|
185
|
+
field.camel = toCamelCase(newName);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (hooks?.customField) {
|
|
189
|
+
const result = hooks.customField(field);
|
|
190
|
+
if (result === null)
|
|
191
|
+
return null;
|
|
192
|
+
field = { ...field, ...result };
|
|
193
|
+
}
|
|
194
|
+
return field;
|
|
195
|
+
})
|
|
196
|
+
.filter(Boolean);
|
|
197
|
+
}
|
|
170
198
|
const renderer = customRenderer || createRenderer({ customTemplatesPath: templatesPath });
|
|
171
199
|
const finalBaseFieldNames = baseFieldNames ?? DEFAULT_BASE_FIELD_NAMES;
|
|
172
200
|
const finalExcludeWritable = excludeWritableFields ?? DEFAULT_EXCLUDE_WRITABLE_FIELDS;
|
|
173
201
|
const excludeWritableRegex = new RegExp(finalExcludeWritable.map(s => `^${s}$`).join('|'), 'i');
|
|
174
202
|
const Camel = toCamelCase(tableName);
|
|
175
|
-
const
|
|
203
|
+
const rawPascal = toPascalCase(tableName);
|
|
204
|
+
const Pascal = hooks?.customEntityName
|
|
205
|
+
? hooks.customEntityName(rawPascal)
|
|
206
|
+
: rawPascal;
|
|
176
207
|
const CreateName = `Create${Pascal}Dto`;
|
|
177
208
|
const UpdateName = `Update${Pascal}Dto`;
|
|
178
209
|
const ReplaceName = `Replace${Pascal}Dto`;
|
|
@@ -220,15 +251,45 @@ export function buildFiles(params) {
|
|
|
220
251
|
idxCount: idxFields.length,
|
|
221
252
|
}),
|
|
222
253
|
});
|
|
254
|
+
const isSensitive = (f) => /password|passwd|salt|token|secret|private_key/i.test(f.name + f.camel);
|
|
255
|
+
const pkCamel = originalPkInfo?.camel || '';
|
|
256
|
+
const pkCamels = pkFields.map(f => f.camel);
|
|
257
|
+
const sortableBase = [...entityFields, ...pkFields]
|
|
258
|
+
.filter(f => !isSensitive(f))
|
|
259
|
+
.map(f => f.camel);
|
|
260
|
+
let sortable = [...new Set([...pkCamels, ...sortableBase])];
|
|
261
|
+
const filterableBase = [...entityFields, ...pkFields].filter(f => !isSensitive(f));
|
|
262
|
+
let filterableArr = [...new Map([...pkFields, ...filterableBase].map(f => [f.camel, f])).values()];
|
|
263
|
+
let filterable = filterableArr.map(f => f.camel);
|
|
264
|
+
let searchable = filterableArr
|
|
265
|
+
.filter(f => /char|varchar|text/i.test(f.type))
|
|
266
|
+
.map(f => f.camel);
|
|
267
|
+
if (hooks?.queryFields) {
|
|
268
|
+
const hookResult = hooks.queryFields(tableName, fields, Pascal, {
|
|
269
|
+
sortable,
|
|
270
|
+
filterable,
|
|
271
|
+
searchable,
|
|
272
|
+
});
|
|
273
|
+
if (hookResult) {
|
|
274
|
+
if (hookResult.sortable !== undefined)
|
|
275
|
+
sortable = hookResult.sortable;
|
|
276
|
+
if (hookResult.filterable !== undefined) {
|
|
277
|
+
filterable = hookResult.filterable;
|
|
278
|
+
filterableArr = fields.filter(f => filterable.includes(f.camel));
|
|
279
|
+
}
|
|
280
|
+
if (hookResult.searchable !== undefined)
|
|
281
|
+
searchable = hookResult.searchable;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
223
284
|
if (onlyEntity) {
|
|
224
285
|
return {
|
|
225
286
|
files: resultFiles,
|
|
226
287
|
Pascal,
|
|
227
288
|
pluralKebab,
|
|
228
289
|
Camel,
|
|
229
|
-
sortable
|
|
230
|
-
filterable
|
|
231
|
-
searchable
|
|
290
|
+
sortable,
|
|
291
|
+
filterable,
|
|
292
|
+
searchable,
|
|
232
293
|
};
|
|
233
294
|
}
|
|
234
295
|
const createFields = fields.filter(f => {
|
|
@@ -239,19 +300,6 @@ export function buildFiles(params) {
|
|
|
239
300
|
return true;
|
|
240
301
|
});
|
|
241
302
|
const writable = createFields.filter(f => !excludeWritableRegex.test(f.name));
|
|
242
|
-
const isSensitive = (f) => /password|passwd|salt|token|secret|private_key/i.test(f.name + f.camel);
|
|
243
|
-
const pkCamel = originalPkInfo?.camel || '';
|
|
244
|
-
const pkCamels = pkFields.map(f => f.camel);
|
|
245
|
-
const sortableBase = [...entityFields, ...pkFields]
|
|
246
|
-
.filter(f => !isSensitive(f))
|
|
247
|
-
.map(f => f.camel);
|
|
248
|
-
const sortable = [...new Set([...pkCamels, ...sortableBase])];
|
|
249
|
-
const filterableBase = [...entityFields, ...pkFields].filter(f => !isSensitive(f));
|
|
250
|
-
const filterableArr = [...new Map([...pkFields, ...filterableBase].map(f => [f.camel, f])).values()];
|
|
251
|
-
const filterable = filterableArr.map(f => f.camel);
|
|
252
|
-
const searchable = filterableArr
|
|
253
|
-
.filter(f => /char|varchar|text/i.test(f.type))
|
|
254
|
-
.map(f => f.camel);
|
|
255
303
|
const enhancedCreateFields = createFields.map(f => enhanceField(f));
|
|
256
304
|
const enhancedWritable = writable.map(f => enhanceField(f));
|
|
257
305
|
const enhancedFilterable = filterableArr.map(f => enhanceField(f));
|
package/dist/types.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export interface CrudConfig {
|
|
|
20
20
|
onlyEntity?: boolean;
|
|
21
21
|
baseFieldNames?: string[];
|
|
22
22
|
excludeWritableFields?: string[];
|
|
23
|
+
hooks?: CrudHooks;
|
|
23
24
|
}
|
|
24
25
|
export interface CliOptions extends CrudConfig {
|
|
25
26
|
help?: boolean;
|
|
@@ -36,6 +37,23 @@ export interface FieldInfo {
|
|
|
36
37
|
defaultVal: any;
|
|
37
38
|
comment: string;
|
|
38
39
|
}
|
|
40
|
+
export interface QueryFieldsResult {
|
|
41
|
+
sortable?: string[];
|
|
42
|
+
filterable?: string[];
|
|
43
|
+
searchable?: string[];
|
|
44
|
+
}
|
|
45
|
+
export interface CrudHooks {
|
|
46
|
+
customEntityName?: (tableName: string) => string;
|
|
47
|
+
customFieldName?: (fieldName: string) => string;
|
|
48
|
+
customField?: (field: FieldInfo) => FieldInfo | null;
|
|
49
|
+
customFields?: (fields: FieldInfo[]) => FieldInfo[];
|
|
50
|
+
customTableName?: (tableName: string) => string;
|
|
51
|
+
queryFields?: (tableName: string, fields: FieldInfo[], pascal: string, defaultQuery: {
|
|
52
|
+
sortable: string[];
|
|
53
|
+
filterable: string[];
|
|
54
|
+
searchable: string[];
|
|
55
|
+
}) => QueryFieldsResult | void;
|
|
56
|
+
}
|
|
39
57
|
export interface OrmInfo {
|
|
40
58
|
orm: string;
|
|
41
59
|
ormSuffix: string;
|