@shys/crud 1.0.1-beta.7 → 1.0.1-beta.8

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 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
  }
@@ -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 Pascal = toPascalCase(tableName);
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`;
@@ -245,13 +276,30 @@ export function buildFiles(params) {
245
276
  const sortableBase = [...entityFields, ...pkFields]
246
277
  .filter(f => !isSensitive(f))
247
278
  .map(f => f.camel);
248
- const sortable = [...new Set([...pkCamels, ...sortableBase])];
279
+ let sortable = [...new Set([...pkCamels, ...sortableBase])];
249
280
  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
281
+ let filterableArr = [...new Map([...pkFields, ...filterableBase].map(f => [f.camel, f])).values()];
282
+ let filterable = filterableArr.map(f => f.camel);
283
+ let searchable = filterableArr
253
284
  .filter(f => /char|varchar|text/i.test(f.type))
254
285
  .map(f => f.camel);
286
+ if (hooks?.queryFields) {
287
+ const hookResult = hooks.queryFields(tableName, fields, Pascal, {
288
+ sortable,
289
+ filterable,
290
+ searchable,
291
+ });
292
+ if (hookResult) {
293
+ if (hookResult.sortable !== undefined)
294
+ sortable = hookResult.sortable;
295
+ if (hookResult.filterable !== undefined) {
296
+ filterable = hookResult.filterable;
297
+ filterableArr = fields.filter(f => filterable.includes(f.camel));
298
+ }
299
+ if (hookResult.searchable !== undefined)
300
+ searchable = hookResult.searchable;
301
+ }
302
+ }
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shys/crud",
3
- "version": "1.0.1-beta.7",
3
+ "version": "1.0.1-beta.8",
4
4
  "description": "MidwayJS v4 模块化 CRUD CLI 生成器",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -1,65 +1,65 @@
1
- import { Inject } from '@midwayjs/core';
2
- import { YSController, CrudPiped } from '@shys/core';
3
- import { {{ Pascal }} } from '../entity/{{ Camel }}.entity';
4
- import { {{ ServiceName }} } from '../service/{{ Camel }}.service';
5
- import {
6
- {{ CreateName }},
7
- {{ UpdateName }},
8
- {{ ReplaceName }},
9
- {{ QueryName }},
10
- } from '../dto/{{ Camel }}';
11
- import { {{ VOName }}, {{ ListVOName }} } from '../vo/{{ Camel }}';
12
-
13
- @YSController({
14
- tagName: {{ tagName | json }},
15
- description: {{ desc | json }},
16
- })
17
- @CrudPiped({
18
- model: {{ Pascal }},
19
- service: {{ ServiceName }},
20
- id: {{ idField | json }},
21
- dto: {
22
- create: {{ CreateName }},
23
- update: {{ UpdateName }},
24
- replace: {{ ReplaceName }},
25
- query: {{ QueryName }},
26
- },
27
- serialize: {
28
- get: {{ VOName }},
29
- list: {{ ListVOName }},
30
- create: {{ VOName }},
31
- update: {{ VOName }},
32
- },
33
- routes: {
34
- only: ['list', 'detail', 'create', 'update', 'replace', 'delete'],
35
- },
36
- query: {
37
- maxLimit: 100,
38
- defaultLimit: 10,
39
- sortable: [{{ sortable }}],
40
- filterable: [{{ filterable }}],
41
- searchable: [{{ searchable }}],
42
- defaultSort: {{ defaultSort }},
43
- },
44
- piped: {
45
- create: {
46
- enabled: true,
47
- stages: ['deserialize', 'sanitize', 'mapFields', 'transform', 'validate'],
48
- validate: { enabled: true, errorStatus: 422 },
49
- },
50
- update: {
51
- enabled: true,
52
- stages: ['deserialize', 'sanitize', 'mapFields', 'transform', 'validate'],
53
- validate: { enabled: true, errorStatus: 422 },
54
- },
55
- replace: {
56
- enabled: true,
57
- stages: ['deserialize', 'sanitize', 'mapFields', 'transform', 'validate'],
58
- validate: { enabled: true, errorStatus: 422 },
59
- },
60
- },
61
- })
62
- export class {{ CtrlName }} {
63
- @Inject()
64
- crudService: {{ ServiceName }};
65
- }
1
+ import { Inject } from '@midwayjs/core';
2
+ import { YSController, CrudPiped } from '@shys/core';
3
+ import { {{ Pascal }} } from '../entity/{{ Camel }}.entity';
4
+ import { {{ ServiceName }} } from '../service/{{ Camel }}.service';
5
+ import {
6
+ {{ CreateName }},
7
+ {{ UpdateName }},
8
+ {{ ReplaceName }},
9
+ {{ QueryName }},
10
+ } from '../dto/{{ Camel }}';
11
+ import { {{ VOName }}, {{ ListVOName }} } from '../vo/{{ Camel }}';
12
+
13
+ @YSController({
14
+ tagName: {{ tagName | json }},
15
+ description: {{ desc | json }},
16
+ })
17
+ @CrudPiped({
18
+ model: {{ Pascal }},
19
+ service: {{ ServiceName }},
20
+ id: {{ idField | json }},
21
+ dto: {
22
+ create: {{ CreateName }},
23
+ update: {{ UpdateName }},
24
+ replace: {{ ReplaceName }},
25
+ query: {{ QueryName }},
26
+ },
27
+ serialize: {
28
+ get: {{ VOName }},
29
+ list: {{ ListVOName }},
30
+ create: {{ VOName }},
31
+ update: {{ VOName }},
32
+ },
33
+ routes: {
34
+ only: ['list', 'detail', 'create', 'update', 'replace', 'delete'],
35
+ },
36
+ query: {
37
+ maxLimit: 100,
38
+ defaultLimit: 10,
39
+ sortable: [{{ sortable }}],
40
+ filterable: [{{ filterable }}],
41
+ searchable: [{{ searchable }}],
42
+ defaultSort: {{ defaultSort }},
43
+ },
44
+ piped: {
45
+ create: {
46
+ enabled: true,
47
+ stages: ['deserialize', 'sanitize', 'mapFields', 'transform', 'validate'],
48
+ validate: { enabled: true, errorStatus: 422 },
49
+ },
50
+ update: {
51
+ enabled: true,
52
+ stages: ['deserialize', 'sanitize', 'mapFields', 'transform', 'validate'],
53
+ validate: { enabled: true, errorStatus: 422 },
54
+ },
55
+ replace: {
56
+ enabled: true,
57
+ stages: ['deserialize', 'sanitize', 'mapFields', 'transform', 'validate'],
58
+ validate: { enabled: true, errorStatus: 422 },
59
+ },
60
+ },
61
+ })
62
+ export class {{ CtrlName }} {
63
+ @Inject()
64
+ crudService: {{ ServiceName }};
65
+ }
@@ -1,4 +1,4 @@
1
- export * from './create.dto';
2
- export * from './update.dto';
3
- export * from './replace.dto';
4
- export * from './query.dto';
1
+ export * from './create.dto';
2
+ export * from './update.dto';
3
+ export * from './replace.dto';
4
+ export * from './query.dto';
@@ -1,17 +1,17 @@
1
- import { ApiPropertyOptional } from '@midwayjs/swagger';
2
- import { Rule } from '@midwayjs/validation';
3
- import * as Joi from 'joi';
4
- import { CrudBaseQueryDto } from '../../../../framework/dto/base.query.dto';
5
-
6
- export class {{ QueryName }} extends CrudBaseQueryDto {
7
- {% for f in filterable -%}
8
- @ApiPropertyOptional({
9
- type: {{ f.swagType | json }},
10
- {% if f.len %} maxLength: {{ f.len }},
11
- {% endif %} description: {{ (f.comment or f.camel) | json }},
12
- })
13
- @Rule({{ f.joiRule }}.optional())
14
- {{ f.camel }}?: {{ f.jsType }};
15
-
16
- {% endfor -%}
17
- }
1
+ import { ApiPropertyOptional } from '@midwayjs/swagger';
2
+ import { Rule } from '@midwayjs/validation';
3
+ import * as Joi from 'joi';
4
+ import { CrudBaseQueryDto } from '../../../../framework/dto/base.query.dto';
5
+
6
+ export class {{ QueryName }} extends CrudBaseQueryDto {
7
+ {% for f in filterable -%}
8
+ @ApiPropertyOptional({
9
+ type: {{ f.swagType | json }},
10
+ {% if f.len %} maxLength: {{ f.len }},
11
+ {% endif %} description: {{ (f.comment or f.camel) | json }},
12
+ })
13
+ @Rule({{ f.joiRule }}.optional())
14
+ {{ f.camel }}?: {{ f.jsType }};
15
+
16
+ {% endfor -%}
17
+ }
@@ -1,20 +1,20 @@
1
- {% if ormInfo.orm === 'typeorm' -%}
2
- import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
3
- import { InjectEntityModel } from '@midwayjs/typeorm';
4
- import { Repository } from 'typeorm';
5
- import { BaseTypeOrmCrudService } from '@shys/core';
6
- import { {{ Pascal }} } from '../entity/{{ Camel }}.entity';
7
-
8
- @Provide()
9
- @Scope(ScopeEnum.Request, { allowDowngrade: true })
10
- export class {{ ServiceName }} extends BaseTypeOrmCrudService<{{ Pascal }}> {
11
- @InjectEntityModel({{ Pascal }})
12
- repo: Repository<{{ Pascal }}>;
13
- }
14
- {%- else -%}
15
- // {{ ormInfo.orm }} Service 模板(请按项目注入方式调整)
16
- import { Provide } from '@midwayjs/core';
17
-
18
- @Provide()
19
- export class {{ ServiceName }} {}
20
- {%- endif %}
1
+ {% if ormInfo.orm === 'typeorm' -%}
2
+ import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
3
+ import { InjectEntityModel } from '@midwayjs/typeorm';
4
+ import { Repository } from 'typeorm';
5
+ import { BaseTypeOrmCrudService } from '@shys/core';
6
+ import { {{ Pascal }} } from '../entity/{{ Camel }}.entity';
7
+
8
+ @Provide()
9
+ @Scope(ScopeEnum.Request, { allowDowngrade: true })
10
+ export class {{ ServiceName }} extends BaseTypeOrmCrudService<{{ Pascal }}> {
11
+ @InjectEntityModel({{ Pascal }})
12
+ repo: Repository<{{ Pascal }}>;
13
+ }
14
+ {%- else -%}
15
+ // {{ ormInfo.orm }} Service 模板(请按项目注入方式调整)
16
+ import { Provide } from '@midwayjs/core';
17
+
18
+ @Provide()
19
+ export class {{ ServiceName }} {}
20
+ {%- endif %}