@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 ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export declare function runCli(argv?: string[]): Promise<void>;
package/dist/cli.js ADDED
@@ -0,0 +1,305 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
3
+ import { resolve, dirname, relative } from 'node:path';
4
+ import { createInterface } from 'node:readline';
5
+ import { fileURLToPath } from 'node:url';
6
+ import chalk from 'chalk';
7
+ import { loadConfig } from './config.js';
8
+ import { detectOrm } from './orm.js';
9
+ import { getDbConfigFromProject, resolveDefaultDbName, getTableFieldsFromDb, templateFieldsFor, } from './db.js';
10
+ import { buildFiles } from './generator.js';
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = dirname(__filename);
13
+ const WORKSPACE_ROOT = resolve(__dirname, '..', '..');
14
+ const ok = (t) => console.log(`${chalk.green('✔')} ${t}`);
15
+ const warn = (t) => console.log(`${chalk.yellow('!')} ${t}`);
16
+ const err = (t) => console.log(`${chalk.red('✘')} ${t}`);
17
+ const info = (t) => console.log(`${chalk.cyan('ℹ')} ${t}`);
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
69
+ `);
70
+ }
71
+ function parseArgs(argv) {
72
+ const cli = { _: [] };
73
+ for (let i = 0; i < argv.length; i++) {
74
+ const a = argv[i];
75
+ if (a === '--help' || a === '-h')
76
+ cli.help = true;
77
+ else if (a === '--force' || a === '-f')
78
+ cli.force = true;
79
+ else if (a === '--dry-run' || a === '-n')
80
+ cli.dryRun = true;
81
+ else if (a === '--compile' || a === '-c')
82
+ cli.compile = true;
83
+ else if (a === '--only-entity')
84
+ cli.onlyEntity = true;
85
+ else if (a === '--no-db')
86
+ cli.noDb = true;
87
+ else if (a === '--module' || a === '-m')
88
+ cli.moduleName = argv[++i];
89
+ else if (a === '--table' || a === '-t')
90
+ cli.tableName = argv[++i];
91
+ else if (a === '--src' || a === '-s')
92
+ cli.baseSrcPath = argv[++i];
93
+ else if (a === '--output' || a === '-o')
94
+ cli.outputPath = argv[++i];
95
+ else if (a === '--templates-path')
96
+ cli.templatesPath = argv[++i];
97
+ else if (a === '--db-host')
98
+ cli.db = { ...(cli.db || {}), host: argv[++i] };
99
+ else if (a === '--db-port')
100
+ cli.db = { ...(cli.db || {}), port: Number(argv[++i]) };
101
+ else if (a === '--db-user')
102
+ cli.db = { ...(cli.db || {}), user: argv[++i] };
103
+ else if (a === '--db-pass')
104
+ cli.db = { ...(cli.db || {}), password: argv[++i] };
105
+ else if (a === '--db-name')
106
+ cli.db = { ...(cli.db || {}), database: argv[++i] };
107
+ else
108
+ cli._.push(a);
109
+ }
110
+ return cli;
111
+ }
112
+ async function askIfMissing(cli, config) {
113
+ const rl = createInterface({
114
+ input: process.stdin,
115
+ output: process.stdout,
116
+ terminal: !!process.stdin.isTTY,
117
+ });
118
+ const ask = (q, dft) => new Promise((res) => rl.question(q + (dft != null ? ` ${chalk.gray(`[${dft}]`)} ` : ' '), (ans) => res(ans.trim() || dft || '')));
119
+ try {
120
+ const isTTY = !!process.stdin.isTTY;
121
+ if (!cli.moduleName)
122
+ cli.moduleName = isTTY
123
+ ? await ask(`${chalk.cyan('?')} moduleName (home/order/goods):`, config.moduleName || 'home')
124
+ : config.moduleName || 'home';
125
+ if (!cli.tableName)
126
+ cli.tableName = isTTY
127
+ ? await ask(`${chalk.cyan('?')} tableName (city/sys_user/order_info):`, config.tableName || 'city')
128
+ : config.tableName || 'city';
129
+ if (!cli.baseSrcPath) {
130
+ const defaultSrc = config.baseSrcPath || resolve(process.cwd(), 'src');
131
+ cli.baseSrcPath = isTTY
132
+ ? await ask(`${chalk.cyan('?')} baseSrcPath (Midway src 根绝对路径):`, defaultSrc)
133
+ : defaultSrc;
134
+ }
135
+ if (!cli.outputPath && config.outputPath) {
136
+ cli.outputPath = config.outputPath;
137
+ }
138
+ if (!cli.noDb && config.noDb) {
139
+ cli.noDb = true;
140
+ }
141
+ if (!cli.force && config.force) {
142
+ cli.force = true;
143
+ }
144
+ if (!cli.dryRun && config.dryRun) {
145
+ cli.dryRun = true;
146
+ }
147
+ if (!cli.compile && config.compile) {
148
+ cli.compile = true;
149
+ }
150
+ if (!cli.templatesPath && config.templatesPath) {
151
+ cli.templatesPath = config.templatesPath;
152
+ }
153
+ if (!cli.onlyEntity && config.onlyEntity) {
154
+ cli.onlyEntity = true;
155
+ }
156
+ }
157
+ finally {
158
+ rl.close();
159
+ }
160
+ }
161
+ async function askDbConfig(cli, config) {
162
+ if (cli.noDb)
163
+ return;
164
+ const resolvedSrcPath = resolve(process.cwd(), cli.baseSrcPath || '.');
165
+ const autoDbCfg = await getDbConfigFromProject(resolvedSrcPath);
166
+ const mergedDb = { ...(config.db || {}), ...(autoDbCfg || {}), ...(cli.db || {}) };
167
+ const rl = createInterface({
168
+ input: process.stdin,
169
+ output: process.stdout,
170
+ terminal: !!process.stdin.isTTY,
171
+ });
172
+ const ask = (q, dft) => new Promise((res) => rl.question(q + (dft != null ? ` ${chalk.gray(`[${dft}]`)} ` : ' '), (ans) => res(ans.trim() || dft || '')));
173
+ try {
174
+ if (!mergedDb.host)
175
+ mergedDb.host = await ask(`${chalk.cyan('?')} db-host:`, '127.0.0.1');
176
+ if (mergedDb.port == null)
177
+ mergedDb.port = Number(await ask(`${chalk.cyan('?')} db-port:`, '3306'));
178
+ if (!mergedDb.user)
179
+ mergedDb.user = await ask(`${chalk.cyan('?')} db-user:`, 'root');
180
+ if (mergedDb.password == null)
181
+ mergedDb.password = await ask(`${chalk.cyan('?')} db-pass:`, '');
182
+ if (!mergedDb.database)
183
+ mergedDb.database = await ask(`${chalk.cyan('?')} db-name:`, resolveDefaultDbName(resolvedSrcPath) || '');
184
+ }
185
+ finally {
186
+ rl.close();
187
+ }
188
+ cli.db = mergedDb;
189
+ }
190
+ function ensureDir(p) {
191
+ mkdirSync(dirname(p), { recursive: true });
192
+ }
193
+ function writeAll(files, opts) {
194
+ let created = 0, skipped = 0, overwritten = 0;
195
+ for (const f of files) {
196
+ const fileExists = existsSync(f.path);
197
+ const isCreateOnly = !!f.createOnly;
198
+ let action = 'CREATE';
199
+ if (fileExists) {
200
+ if (isCreateOnly) {
201
+ action = 'SKIP(exist)';
202
+ skipped++;
203
+ }
204
+ else if (!opts.force) {
205
+ action = 'SKIP(exist)';
206
+ skipped++;
207
+ }
208
+ else {
209
+ action = 'OVERWRITE';
210
+ overwritten++;
211
+ }
212
+ }
213
+ else {
214
+ created++;
215
+ }
216
+ const rel = relative(process.cwd(), f.path);
217
+ if (opts.dryRun) {
218
+ console.log(` ${chalk.gray('[dry-run]')} ${action} ${rel}`);
219
+ continue;
220
+ }
221
+ if (action === 'SKIP(exist)') {
222
+ warn(`已存在(跳过,加 --force 覆盖):${rel}`);
223
+ continue;
224
+ }
225
+ ensureDir(f.path);
226
+ writeFileSync(f.path, f.content, 'utf-8');
227
+ ok(`${action}: ${rel}`);
228
+ }
229
+ return { created, skipped, overwritten };
230
+ }
231
+ async function describeTableOrTemplate(cli, tableName) {
232
+ if (!cli.noDb && cli.db?.database) {
233
+ try {
234
+ const fields = await getTableFieldsFromDb(cli.db, tableName);
235
+ if (fields.length) {
236
+ ok(`DESCRIBE ${tableName} 成功,${fields.length} 列`);
237
+ return fields;
238
+ }
239
+ }
240
+ catch (e) {
241
+ warn(`DB 连接失败:${e.message},回退到模板字段`);
242
+ }
243
+ }
244
+ warn('使用模板字段模式(可通过 --db-name/--db-host... 启用真实 DESCRIBE)');
245
+ return templateFieldsFor(tableName);
246
+ }
247
+ export async function runCli(argv = process.argv.slice(2)) {
248
+ const cli = parseArgs(argv);
249
+ if (cli.help) {
250
+ printHelp();
251
+ return;
252
+ }
253
+ console.log(`${chalk.cyan('shys-crud CLI')} cwd: ${process.cwd()}`);
254
+ const fileConfig = await loadConfig(process.cwd());
255
+ await askIfMissing(cli, fileConfig);
256
+ const baseSrcPath = resolve(process.cwd(), cli.baseSrcPath || '.');
257
+ if (!existsSync(baseSrcPath) || !existsSync(resolve(baseSrcPath, '../package.json'))) {
258
+ err(`baseSrcPath 不是一个有效的 Midway 业务包 src:${baseSrcPath}`);
259
+ process.exit(2);
260
+ }
261
+ const ormInfo = detectOrm(baseSrcPath);
262
+ info(`ORM: ${ormInfo.orm} suffix: ${ormInfo.ormSuffix}`);
263
+ await askDbConfig(cli, fileConfig);
264
+ const fields = await describeTableOrTemplate(cli, cli.tableName || '');
265
+ if (!fields.length) {
266
+ err('字段为空,无法生成');
267
+ process.exit(3);
268
+ }
269
+ const outputPath = cli.outputPath ? resolve(process.cwd(), cli.outputPath) : baseSrcPath;
270
+ const templatesPath = cli.templatesPath ? resolve(process.cwd(), cli.templatesPath) : undefined;
271
+ const built = buildFiles({
272
+ moduleName: cli.moduleName || 'home',
273
+ tableName: cli.tableName || '',
274
+ baseSrcPath,
275
+ ormInfo,
276
+ fields,
277
+ outputPath,
278
+ templatesPath,
279
+ onlyEntity: cli.onlyEntity,
280
+ });
281
+ console.log(`\n${chalk.cyan(`生成清单(${built.files.length})`)}`);
282
+ const stats = writeAll(built.files, { force: !!cli.force, dryRun: !!cli.dryRun });
283
+ console.log(`\n${chalk.green('完成')}:created=${stats.created} overwritten=${stats.overwritten} skipped=${stats.skipped}`);
284
+ const src = relative(process.cwd(), baseSrcPath);
285
+ console.log(`\n${chalk.cyan('下一步(建议按顺序执行):')}`);
286
+ console.log(` 1) 编译:cd ${src ? src + '/..' : '.'} ; npx mwtsc --cleanOutDir`);
287
+ console.log(` 2) 启动:node ${resolve(baseSrcPath, '../bootstrap.js')}`);
288
+ console.log(` 3) 验证列表:curl http://127.0.0.1:7001/api/${built.pluralKebab}?page=1&limit=2`);
289
+ if (cli.dryRun) {
290
+ info('这是 dry-run,未写任何文件。去掉 -n 即可实际写入。');
291
+ }
292
+ else if (cli.compile) {
293
+ info('执行 mwtsc --cleanOutDir...');
294
+ const { spawnSync } = await import('node:child_process');
295
+ const cwd = resolve(baseSrcPath, '..');
296
+ const res = spawnSync(process.platform === 'win32' ? 'npx.cmd' : 'npx', ['mwtsc', '--cleanOutDir'], { cwd, stdio: 'inherit', shell: false });
297
+ process.exit(res.status || 0);
298
+ }
299
+ }
300
+ if (process.argv[1] && process.argv[1].endsWith('cli.js')) {
301
+ runCli().catch((e) => {
302
+ err(e.stack || String(e));
303
+ process.exit(1);
304
+ });
305
+ }
@@ -0,0 +1,3 @@
1
+ import type { CrudConfig } from './types.js';
2
+ export declare function loadConfig(cwd?: string): Promise<CrudConfig>;
3
+ export declare function mergeConfigs(...configs: Partial<CrudConfig>[]): CrudConfig;
package/dist/config.js ADDED
@@ -0,0 +1,115 @@
1
+ import { cosmiconfig } from 'cosmiconfig';
2
+ const MODULE_NAME = 'crud';
3
+ export async function loadConfig(cwd = process.cwd()) {
4
+ const explorer = cosmiconfig(MODULE_NAME, {
5
+ searchPlaces: [
6
+ 'package.json',
7
+ `.${MODULE_NAME}rc`,
8
+ `.${MODULE_NAME}rc.json`,
9
+ `.${MODULE_NAME}rc.yaml`,
10
+ `.${MODULE_NAME}rc.yml`,
11
+ `.${MODULE_NAME}rc.js`,
12
+ `.${MODULE_NAME}rc.cjs`,
13
+ `.${MODULE_NAME}rc.mjs`,
14
+ `.config/${MODULE_NAME}rc`,
15
+ `.config/${MODULE_NAME}rc.json`,
16
+ `.config/${MODULE_NAME}rc.yaml`,
17
+ `.config/${MODULE_NAME}rc.yml`,
18
+ `.config/${MODULE_NAME}rc.js`,
19
+ `.config/${MODULE_NAME}rc.cjs`,
20
+ `.config/${MODULE_NAME}rc.mjs`,
21
+ `${MODULE_NAME}.config.js`,
22
+ `${MODULE_NAME}.config.cjs`,
23
+ `${MODULE_NAME}.config.mjs`,
24
+ `${MODULE_NAME}.config.ts`,
25
+ `${MODULE_NAME}.config.cts`,
26
+ `${MODULE_NAME}.config.mts`,
27
+ ],
28
+ loaders: {
29
+ '.ts': async (filepath) => {
30
+ try {
31
+ // @ts-ignore - tsx is optional runtime dependency
32
+ const tsxMod = await import('tsx');
33
+ const result = await tsxMod.loadConfig(filepath);
34
+ return result?.default ?? result;
35
+ }
36
+ catch {
37
+ try {
38
+ // @ts-ignore - jiti is optional runtime dependency
39
+ const jitiMod = await import('jiti');
40
+ const jiti = jitiMod.default;
41
+ const load = jiti(filepath, { esmResolve: true, interopDefault: true });
42
+ const result = load(filepath);
43
+ return result?.default ?? result;
44
+ }
45
+ catch {
46
+ return {};
47
+ }
48
+ }
49
+ },
50
+ '.cts': async (filepath) => {
51
+ try {
52
+ // @ts-ignore - tsx is optional runtime dependency
53
+ const tsxMod = await import('tsx');
54
+ const result = await tsxMod.loadConfig(filepath);
55
+ return result?.default ?? result;
56
+ }
57
+ catch {
58
+ return {};
59
+ }
60
+ },
61
+ '.mts': async (filepath) => {
62
+ try {
63
+ // @ts-ignore - tsx is optional runtime dependency
64
+ const tsxMod = await import('tsx');
65
+ const result = await tsxMod.loadConfig(filepath);
66
+ return result?.default ?? result;
67
+ }
68
+ catch {
69
+ return {};
70
+ }
71
+ },
72
+ },
73
+ });
74
+ try {
75
+ const result = await explorer.search(cwd);
76
+ if (result && !result.isEmpty) {
77
+ return result.config;
78
+ }
79
+ }
80
+ catch (e) {
81
+ // 配置文件加载失败时静默返回空配置
82
+ }
83
+ return {};
84
+ }
85
+ export function mergeConfigs(...configs) {
86
+ const result = {};
87
+ for (const config of configs) {
88
+ if (!config)
89
+ continue;
90
+ if (config.baseSrcPath !== undefined)
91
+ result.baseSrcPath = config.baseSrcPath;
92
+ if (config.moduleName !== undefined)
93
+ result.moduleName = config.moduleName;
94
+ if (config.tableName !== undefined)
95
+ result.tableName = config.tableName;
96
+ if (config.noDb !== undefined)
97
+ result.noDb = config.noDb;
98
+ if (config.force !== undefined)
99
+ result.force = config.force;
100
+ if (config.dryRun !== undefined)
101
+ result.dryRun = config.dryRun;
102
+ if (config.compile !== undefined)
103
+ result.compile = config.compile;
104
+ if (config.outputPath !== undefined)
105
+ result.outputPath = config.outputPath;
106
+ if (config.templatesPath !== undefined)
107
+ result.templatesPath = config.templatesPath;
108
+ if (config.onlyEntity !== undefined)
109
+ result.onlyEntity = config.onlyEntity;
110
+ if (config.db) {
111
+ result.db = { ...(result.db || {}), ...config.db };
112
+ }
113
+ }
114
+ return result;
115
+ }
package/dist/db.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import type { CrudDbConfig, FieldInfo } from './types.js';
2
+ export declare function getDbConfigFromProject(baseSrcPath: string): Promise<CrudDbConfig | null>;
3
+ export declare function resolveDefaultDbName(baseSrcPath: string): string;
4
+ export declare function getTableFieldsFromDb(dbConfig: CrudDbConfig, tableName: string): Promise<FieldInfo[]>;
5
+ export declare function templateFieldsFor(tableName: string): FieldInfo[];
package/dist/db.js ADDED
@@ -0,0 +1,132 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import fs from 'fs-extra';
4
+ import { toCamelCase } from './utils.js';
5
+ export async function getDbConfigFromProject(baseSrcPath) {
6
+ const configLocalPath = resolve(baseSrcPath, 'config/config.local.ts');
7
+ const configDefaultPath = resolve(baseSrcPath, 'config/config.default.ts');
8
+ let configContent = '';
9
+ if (await fs.pathExists(configLocalPath)) {
10
+ configContent = await fs.readFile(configLocalPath, 'utf-8');
11
+ }
12
+ else if (await fs.pathExists(configDefaultPath)) {
13
+ configContent = await fs.readFile(configDefaultPath, 'utf-8');
14
+ }
15
+ else {
16
+ return null;
17
+ }
18
+ const typeMatch = configContent.match(/type:\s*['"]([^'"]+)['"]/);
19
+ const hostMatch = configContent.match(/host:\s*['"]([^'"]+)['"]/);
20
+ const portMatch = configContent.match(/port:\s*(\d+)/);
21
+ const usernameMatch = configContent.match(/username:\s*['"]([^'"]+)['"]/);
22
+ const passwordMatch = configContent.match(/password:\s*['"]([^'"]+)['"]/);
23
+ const databaseMatch = configContent.match(/database:\s*['"]([^'"]+)['"]/);
24
+ return {
25
+ type: typeMatch ? typeMatch[1] : 'mysql',
26
+ host: hostMatch ? hostMatch[1] : '127.0.0.1',
27
+ port: portMatch ? parseInt(portMatch[1], 10) : 3306,
28
+ user: usernameMatch ? usernameMatch[1] : 'root',
29
+ password: passwordMatch ? passwordMatch[1] : '',
30
+ database: databaseMatch ? databaseMatch[1] : '',
31
+ };
32
+ }
33
+ export function resolveDefaultDbName(baseSrcPath) {
34
+ try {
35
+ const cfg = readFileSync(resolve(baseSrcPath, 'config/config.default.ts'), 'utf-8');
36
+ const m = cfg.match(/database:\s*['"]([^'"]+)['"]/);
37
+ return m ? m[1] : '';
38
+ }
39
+ catch {
40
+ return '';
41
+ }
42
+ }
43
+ export async function getTableFieldsFromDb(dbConfig, tableName) {
44
+ const { host, port, user, password, database } = dbConfig;
45
+ try {
46
+ const mysql2 = await import('mysql2/promise');
47
+ const connection = await mysql2.createConnection({
48
+ host: host || '127.0.0.1',
49
+ port: parseInt(String(port || '3306'), 10),
50
+ user: user || 'root',
51
+ password: password ?? '',
52
+ database: database || '',
53
+ });
54
+ try {
55
+ const [rows] = await connection.execute(`SELECT column_name, data_type, is_nullable, column_type, column_comment, column_default, character_maximum_length, extra
56
+ FROM information_schema.COLUMNS
57
+ WHERE table_schema = ? AND table_name = ?
58
+ ORDER BY ordinal_position`, [database, tableName]);
59
+ return rows
60
+ .map((row) => {
61
+ const columnName = row.COLUMN_NAME || row.column_name || '';
62
+ if (!columnName)
63
+ return null;
64
+ const camelName = toCamelCase(columnName);
65
+ const dataType = row.DATA_TYPE || row.data_type || 'varchar';
66
+ const nullable = (row.IS_NULLABLE || row.is_nullable || 'NO') === 'YES';
67
+ const comment = row.COLUMN_COMMENT || row.column_comment || '';
68
+ const defaultVal = row.COLUMN_DEFAULT || row.column_default;
69
+ const length = row.CHARACTER_MAXIMUM_LENGTH || row.character_maximum_length;
70
+ const extra = row.EXTRA || row.extra || '';
71
+ const isPk = extra.includes('PRI') || columnName.toLowerCase().includes('id');
72
+ const isAuto = extra.includes('auto_increment');
73
+ return {
74
+ name: columnName,
75
+ camel: camelName,
76
+ type: dataType,
77
+ nullable,
78
+ len: length,
79
+ pk: isPk,
80
+ auto: isAuto,
81
+ comment,
82
+ defaultVal,
83
+ };
84
+ })
85
+ .filter(Boolean);
86
+ }
87
+ finally {
88
+ await connection.end();
89
+ }
90
+ }
91
+ catch (e) {
92
+ return [];
93
+ }
94
+ }
95
+ export function templateFieldsFor(tableName) {
96
+ const t = tableName.toLowerCase();
97
+ if (t === 'city')
98
+ return [
99
+ { name: 'ID', camel: 'id', type: 'int', len: null, nullable: false, pk: true, auto: true, defaultVal: null, comment: '城市ID,自增主键' },
100
+ { name: 'Name', camel: 'name', type: 'char', len: 35, nullable: false, pk: false, auto: false, defaultVal: '', comment: '城市名称,最大35字符' },
101
+ { name: 'CountryCode', camel: 'countryCode', type: 'char', len: 3, nullable: false, pk: false, auto: false, defaultVal: '', comment: '所属国家代码,3位字符' },
102
+ { name: 'District', camel: 'district', type: 'char', len: 20, nullable: false, pk: false, auto: false, defaultVal: '', comment: '所在省/州/行政区' },
103
+ { name: 'Population', camel: 'population', type: 'int', len: null, nullable: false, pk: false, auto: false, defaultVal: 0, comment: '城市人口' },
104
+ ];
105
+ if (t === 'sys_user' || t.endsWith('_user'))
106
+ return [
107
+ { name: 'id', camel: 'id', type: 'bigint', len: null, nullable: false, pk: true, auto: true, defaultVal: null, comment: '主键ID' },
108
+ { name: 'user_name', camel: 'userName', type: 'varchar', len: 64, nullable: false, pk: false, auto: false, defaultVal: '', comment: '用户名' },
109
+ { name: 'password', camel: 'password', type: 'varchar', len: 128, nullable: false, pk: false, auto: false, defaultVal: '', comment: '密码(加密后)' },
110
+ { name: 'mobile', camel: 'mobile', type: 'varchar', len: 20, nullable: true, pk: false, auto: false, defaultVal: null, comment: '手机号' },
111
+ { name: 'email', camel: 'email', type: 'varchar', len: 128, nullable: true, pk: false, auto: false, defaultVal: null, comment: '邮箱' },
112
+ { name: 'status', camel: 'status', type: 'tinyint', len: null, nullable: false, pk: false, auto: false, defaultVal: 1, comment: '状态 1启用 0禁用' },
113
+ { name: 'ctime', camel: 'ctime', type: 'datetime', len: null, nullable: true, pk: false, auto: false, defaultVal: null, comment: '创建时间' },
114
+ { name: 'mtime', camel: 'mtime', type: 'datetime', len: null, nullable: true, pk: false, auto: false, defaultVal: null, comment: '更新时间' },
115
+ ];
116
+ if (t.includes('order'))
117
+ return [
118
+ { name: 'id', camel: 'id', type: 'bigint', len: null, nullable: false, pk: true, auto: true, defaultVal: null, comment: '主键ID' },
119
+ { name: 'order_no', camel: 'orderNo', type: 'varchar', len: 64, nullable: false, pk: false, auto: false, defaultVal: '', comment: '订单号' },
120
+ { name: 'user_id', camel: 'userId', type: 'bigint', len: null, nullable: false, pk: false, auto: false, defaultVal: 0, comment: '下单用户ID' },
121
+ { name: 'total_amount', camel: 'totalAmount', type: 'decimal', len: 12, nullable: false, pk: false, auto: false, defaultVal: '0.00', comment: '订单总金额' },
122
+ { name: 'status', camel: 'status', type: 'tinyint', len: null, nullable: false, pk: false, auto: false, defaultVal: 0, comment: '订单状态' },
123
+ { name: 'pay_status', camel: 'payStatus', type: 'tinyint', len: null, nullable: false, pk: false, auto: false, defaultVal: 0, comment: '支付状态' },
124
+ { name: 'ctime', camel: 'ctime', type: 'datetime', len: null, nullable: true, pk: false, auto: false, defaultVal: null, comment: '创建时间' },
125
+ { name: 'mtime', camel: 'mtime', type: 'datetime', len: null, nullable: true, pk: false, auto: false, defaultVal: null, comment: '更新时间' },
126
+ ];
127
+ return [
128
+ { name: 'id', camel: 'id', type: 'int', len: null, nullable: false, pk: true, auto: true, defaultVal: null, comment: '主键ID' },
129
+ { name: 'name', camel: 'name', type: 'varchar', len: 255, nullable: true, pk: false, auto: false, defaultVal: null, comment: '名称' },
130
+ { name: 'ctime', camel: 'ctime', type: 'datetime', len: null, nullable: true, pk: false, auto: false, defaultVal: null, comment: '创建时间' },
131
+ ];
132
+ }
@@ -0,0 +1,27 @@
1
+ import type { FieldInfo, OrmInfo } from './types.js';
2
+ import { TemplateRenderer } from './renderer.js';
3
+ export interface BuildResult {
4
+ files: Array<{
5
+ path: string;
6
+ content: string;
7
+ createOnly?: boolean;
8
+ }>;
9
+ Pascal: string;
10
+ pluralKebab: string;
11
+ Camel: string;
12
+ sortable: string[];
13
+ filterable: string[];
14
+ searchable: string[];
15
+ }
16
+ export interface BuildFilesParams {
17
+ moduleName: string;
18
+ tableName: string;
19
+ baseSrcPath: string;
20
+ ormInfo: OrmInfo;
21
+ fields: FieldInfo[];
22
+ outputPath?: string;
23
+ templatesPath?: string;
24
+ renderer?: TemplateRenderer;
25
+ onlyEntity?: boolean;
26
+ }
27
+ export declare function buildFiles(params: BuildFilesParams): BuildResult;