gorig-cli 1.0.24 → 1.0.26

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.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +129 -40
  3. package/commands/create.js +267 -112
  4. package/commands/doc.js +21 -8
  5. package/commands/init.js +316 -255
  6. package/commands/skill.js +55 -17
  7. package/package.json +1 -1
  8. package/templates/config.go.ejs +6 -5
  9. package/templates/config.yaml.ejs +3 -38
  10. package/templates/controller.go.ejs +11 -42
  11. package/templates/crud.controller.go.ejs +71 -0
  12. package/templates/crud.doc.md.ejs +60 -0
  13. package/templates/crud.dto.go.ejs +103 -0
  14. package/templates/crud.integration.init_test.go.ejs +17 -0
  15. package/templates/crud.integration_test.go.ejs +66 -0
  16. package/templates/crud.model.go.ejs +25 -0
  17. package/templates/crud.module.README.md.ejs +70 -0
  18. package/templates/crud.mongo.config.yaml.ejs +19 -0
  19. package/templates/crud.mysql.config.yaml.ejs +14 -0
  20. package/templates/crud.router.go.ejs +18 -0
  21. package/templates/crud.service.go.ejs +179 -0
  22. package/templates/crud.test.go.ejs +52 -0
  23. package/templates/dto.go.ejs +16 -0
  24. package/templates/gitignore.ejs +18 -49
  25. package/templates/hello.controller.go.ejs +19 -0
  26. package/templates/hello.router.go.ejs +12 -0
  27. package/templates/hello.service.go.ejs +31 -0
  28. package/templates/hello.test.go.ejs +34 -0
  29. package/templates/init.go.ejs +1 -27
  30. package/templates/main.go.ejs +2 -5
  31. package/templates/model.go.ejs +3 -4
  32. package/templates/project.README.md.ejs +35 -0
  33. package/templates/router.go.ejs +4 -8
  34. package/templates/service.go.ejs +25 -77
  35. package/templates/skills/gorig-backend/SKILL.md +89 -0
  36. package/templates/skills/gorig-backend/agents/openai.yaml +4 -0
  37. package/templates/skills/gorig-backend/assets/api-doc-template.md +59 -0
  38. package/templates/skills/gorig-backend/assets/gorig.gitignore +65 -0
  39. package/templates/skills/gorig-backend/assets/module-readme-template.md +58 -0
  40. package/templates/skills/gorig-backend/references/advanced-data-access.md +275 -0
  41. package/templates/skills/gorig-backend/references/auth-security.md +194 -0
  42. package/templates/skills/gorig-backend/references/business-scenarios.md +155 -0
  43. package/templates/skills/gorig-backend/references/cache.md +301 -0
  44. package/templates/skills/gorig-backend/references/capability-matrix.md +37 -0
  45. package/templates/skills/gorig-backend/references/configuration.md +48 -0
  46. package/templates/skills/gorig-backend/references/framework-api.md +190 -0
  47. package/templates/skills/gorig-backend/references/messaging.md +143 -0
  48. package/templates/skills/gorig-backend/references/onboarding-files.md +46 -0
  49. package/templates/skills/gorig-backend/references/outbound-http.md +162 -0
  50. package/templates/skills/gorig-backend/references/persistent-crud.md +332 -0
  51. package/templates/skills/gorig-backend/references/project-bootstrap.md +128 -0
  52. package/templates/skills/gorig-backend/references/scheduled-tasks.md +231 -0
  53. package/templates/skills/gorig-backend/references/service-lifecycle.md +51 -0
  54. package/templates/skills/gorig-backend/references/source-map.md +43 -0
  55. package/templates/skills/gorig-backend/references/source-policy.md +58 -0
  56. package/templates/skills/gorig-backend/references/sse.md +121 -0
  57. package/templates/skills/gorig-backend/references/testing.md +171 -0
  58. package/templates/skills/gorig-backend/scripts/check-source-links.sh +48 -0
  59. package/templates/skills/gorig-backend/scripts/detect-gorig-context.sh +67 -0
  60. package/templates/skills/gorig-backend/scripts/verify-basic-project.sh +108 -0
  61. package/npm_publish copy.sh +0 -65
  62. package/templates/internal.go.ejs +0 -49
  63. package/templates/req.go.ejs +0 -8
  64. package/templates/resp.go.ejs +0 -8
  65. package/templates/service.pub.go.ejs +0 -22
  66. package/templates/skills/claude/gorig-backend/SKILL.md +0 -766
  67. package/templates/skills/claude/gorig-backend/assets/api-doc-template.md +0 -50
  68. package/templates/skills/claude/gorig-backend/assets/module-readme-template.md +0 -46
  69. package/templates/skills/claude/gorig-backend/references/onboarding-files.md +0 -44
  70. package/templates/skills/codex/gorig-backend/SKILL.md +0 -766
  71. package/templates/skills/codex/gorig-backend/agents/openai.yaml +0 -4
  72. package/templates/skills/codex/gorig-backend/assets/api-doc-template.md +0 -50
  73. package/templates/skills/codex/gorig-backend/assets/module-readme-template.md +0 -46
  74. package/templates/skills/codex/gorig-backend/references/onboarding-files.md +0 -44
@@ -8,6 +8,88 @@ import { fileURLToPath } from 'url';
8
8
  const __filename = fileURLToPath(import.meta.url);
9
9
  const __dirname = path.dirname(__filename);
10
10
 
11
+ const readOptionValue = (args, index, name) => {
12
+ const arg = args[index];
13
+ const prefix = `${name}=`;
14
+ if (arg.startsWith(prefix)) {
15
+ return { value: arg.slice(prefix.length), nextIndex: index };
16
+ }
17
+ if (index + 1 >= args.length || args[index + 1].startsWith('--')) {
18
+ throw new Error(`Missing value for ${name}`);
19
+ }
20
+ return { value: args[index + 1], nextIndex: index + 1 };
21
+ };
22
+
23
+ const toModuleName = (moduleName) => moduleName
24
+ .split('_')
25
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
26
+ .join('');
27
+
28
+ export const parseCreateArgs = (args) => {
29
+ if (args.length < 1) {
30
+ throw new Error('Please use the correct command format: gorig-cli create <module name>');
31
+ }
32
+
33
+ const moduleName = args[0];
34
+ if (!/^[a-z][a-z0-9_]*$/.test(moduleName)) {
35
+ throw new Error('Module name must use lower snake_case, for example: user or supply_order');
36
+ }
37
+
38
+ const options = {
39
+ moduleName,
40
+ ModuleName: toModuleName(moduleName),
41
+ crud: false,
42
+ db: '',
43
+ dbName: '',
44
+ http: true,
45
+ };
46
+
47
+ for (let i = 1; i < args.length; i += 1) {
48
+ const arg = args[i];
49
+ if (arg === '--crud') {
50
+ options.crud = true;
51
+ continue;
52
+ }
53
+ if (arg === '--no-http') {
54
+ options.http = false;
55
+ continue;
56
+ }
57
+
58
+ const valueOptions = ['--db', '--database', '--store', '--db-name'];
59
+ const optionName = valueOptions.find((name) => arg === name || arg.startsWith(`${name}=`));
60
+ if (!optionName) {
61
+ throw new Error(`Unknown create option: ${arg}`);
62
+ }
63
+
64
+ const { value, nextIndex } = readOptionValue(args, i, optionName);
65
+ i = nextIndex;
66
+
67
+ if (['--db', '--database', '--store'].includes(optionName)) {
68
+ options.crud = true;
69
+ options.db = value.toLowerCase();
70
+ } else if (optionName === '--db-name') {
71
+ options.dbName = value;
72
+ }
73
+ }
74
+
75
+ if (options.crud) {
76
+ if (!['mysql', 'mongo', 'mongodb'].includes(options.db)) {
77
+ throw new Error('Persistent CRUD modules require --db mysql or --db mongo');
78
+ }
79
+ if (options.db === 'mongodb') {
80
+ options.db = 'mongo';
81
+ }
82
+ if (!options.dbName) {
83
+ options.dbName = options.db === 'mysql' ? 'Main' : 'main';
84
+ }
85
+ if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(options.dbName)) {
86
+ throw new Error('Database connection name must start with a letter and contain only letters, numbers, or underscores');
87
+ }
88
+ }
89
+
90
+ return options;
91
+ };
92
+
11
93
  // Get the module name from the go.mod file
12
94
  const getGoModModuleName = async () => {
13
95
  try {
@@ -25,135 +107,208 @@ const getGoModModuleName = async () => {
25
107
  }
26
108
  };
27
109
 
28
- // Create module main function
29
- const createModule = async (args) => {
30
- if (args.length < 1) {
31
- console.error(chalk.yellow('Please use the correct command format: npx <your package name> create <module name>'));
32
- process.exit(1);
110
+ const renderTemplate = async (templateName, destination, data) => {
111
+ const templatePath = path.join(__dirname, '../templates', templateName);
112
+ const content = await ejs.renderFile(templatePath, data);
113
+ await fs.ensureDir(path.dirname(destination));
114
+ await fs.writeFile(destination, content);
115
+ };
116
+
117
+ const renderTemplateContent = async (templateName, data) => {
118
+ const templatePath = path.join(__dirname, '../templates', templateName);
119
+ return ejs.renderFile(templatePath, data);
120
+ };
121
+
122
+ const insertYamlConnection = (content, topKey, connectionName, connectionBlock) => {
123
+ const normalized = content.endsWith('\n') ? content : `${content}\n`;
124
+ const lines = normalized.split('\n');
125
+ const topIndex = lines.findIndex((line) => line === `${topKey}:`);
126
+
127
+ if (topIndex < 0) {
128
+ return `${normalized.trimEnd()}\n\n${topKey}:\n${connectionBlock.trimEnd()}\n`;
33
129
  }
34
130
 
35
- const moduleName = args[0];
36
- const ModuleName = moduleName.charAt(0).toUpperCase() + moduleName.slice(1);
131
+ let endIndex = lines.length - 1;
132
+ for (let i = topIndex + 1; i < lines.length; i += 1) {
133
+ if (/^[A-Za-z0-9_.-]+\s*:/.test(lines[i])) {
134
+ endIndex = i;
135
+ break;
136
+ }
137
+ }
37
138
 
38
- // Get the current working directory, which is the directory where the command is executed
39
- const currentDir = process.cwd();
139
+ const connectionPattern = new RegExp(`^ ${connectionName}:\\s*$`);
140
+ if (lines.slice(topIndex + 1, endIndex).some((line) => connectionPattern.test(line))) {
141
+ return content;
142
+ }
40
143
 
41
- // Build the paths for the domain directory and module directory
42
- const domainDir = path.join(currentDir, 'domain');
43
- const moduleDir = path.join(domainDir, moduleName);
144
+ lines.splice(endIndex, 0, ...connectionBlock.trimEnd().split('\n'));
145
+ return `${lines.join('\n').trimEnd()}\n`;
146
+ };
44
147
 
45
- // Define the subdirectories to be created
46
- const subDirs = ['api', 'model', 'internal', 'api/req'];
148
+ const ensureCrudConfig = async (projectDir, data) => {
149
+ const topKey = data.db === 'mysql' ? 'Mysql' : 'mongo';
150
+ const templateName = data.db === 'mysql'
151
+ ? 'crud.mysql.config.yaml.ejs'
152
+ : 'crud.mongo.config.yaml.ejs';
153
+ const connectionBlock = await renderTemplateContent(templateName, data);
154
+ const configPaths = [
155
+ '_bin/local.yaml',
156
+ '_bin/dev.yaml',
157
+ '_bin/prod.yaml',
158
+ 'test/_bin/local.yaml',
159
+ ];
47
160
 
48
- console.log(chalk.blue(`\nStarting to create module: ${chalk.bold(moduleName)}`));
161
+ for (const relativePath of configPaths) {
162
+ const configPath = path.join(projectDir, relativePath);
163
+ if (!await fs.pathExists(configPath)) {
164
+ console.log(chalk.yellow(`Could not find ${relativePath}, skipping database configuration`));
165
+ continue;
166
+ }
49
167
 
50
- try {
51
- const projectName = await getGoModModuleName();
168
+ const original = await fs.readFile(configPath, 'utf8');
169
+ const updated = insertYamlConnection(original, topKey, data.dbName, connectionBlock);
170
+ if (updated !== original) {
171
+ await fs.writeFile(configPath, updated);
172
+ console.log(chalk.green(`Successfully updated ${chalk.bold(relativePath)} database configuration`));
173
+ }
174
+ }
175
+ };
52
176
 
53
- await fs.ensureDir(domainDir);
54
- await fs.ensureDir(moduleDir);
55
-
56
- // Create subdirectories
57
- const createSubDirs = subDirs.map((subDir) => {
58
- const subDirPath = path.join(moduleDir, subDir);
59
- return fs.ensureDir(subDirPath);
60
- });
61
- await Promise.all(createSubDirs);
62
-
63
- // Create and write model.go file
64
- const modelDir = path.join(moduleDir, 'model');
65
- const modelFilePath = path.join(modelDir, `${moduleName}.go`);
66
- const modelTemplatePath = path.join(__dirname, '../templates/model.go.ejs');
67
- const modelContent = await ejs.renderFile(modelTemplatePath, { moduleName, ModuleName, projectName });
68
- await fs.writeFile(modelFilePath, modelContent);
69
- console.log(chalk.green(`Successfully created ${chalk.bold('model.go')} file`));
70
-
71
- // Create and write req.go file
72
- const apiDir = path.join(moduleDir, 'api');
73
- const reqDir = path.join(apiDir, 'req');
74
- const reqFilePath = path.join(reqDir, `req.go`);
75
- const reqTemplatePath = path.join(__dirname, '../templates/req.go.ejs');
76
- const reqContent = await ejs.renderFile(reqTemplatePath, { moduleName, ModuleName, projectName });
77
- await fs.writeFile(reqFilePath, reqContent);
78
- console.log(chalk.green(`Successfully created ${chalk.bold('req.go')} file`));
79
-
80
- // Create and write resp.go file
81
- const respFilePath = path.join(reqDir, `resp.go`);
82
- const respTemplatePath = path.join(__dirname, '../templates/resp.go.ejs');
83
- const respContent = await ejs.renderFile(respTemplatePath, { moduleName, ModuleName, projectName });
84
- await fs.writeFile(respFilePath, respContent);
85
- console.log(chalk.green(`Successfully created ${chalk.bold('resp.go')} file`));
86
-
87
- // Create and write internal.go file
88
- const internalDir = path.join(moduleDir, 'internal');
89
- const internalFilePath = path.join(internalDir, `${moduleName}.go`);
90
- const internalTemplatePath = path.join(__dirname, '../templates/internal.go.ejs');
91
- const internalContent = await ejs.renderFile(internalTemplatePath, { moduleName, ModuleName, projectName });
92
- await fs.writeFile(internalFilePath, internalContent);
93
- console.log(chalk.green(`Successfully created ${chalk.bold('internal.go')} file`));
94
-
95
- // Create and write service.pub.go file
96
- const serviceFilePath = path.join(apiDir, `service.pub.go`);
97
- const serviceTemplatePath = path.join(__dirname, '../templates/service.pub.go.ejs');
98
- const serviceContent = await ejs.renderFile(serviceTemplatePath, { moduleName, ModuleName, projectName });
99
- await fs.writeFile(serviceFilePath, serviceContent);
100
- console.log(chalk.green(`Successfully created ${chalk.bold('service.pub.go')} file`));
101
-
102
- // Create and write service.go file
103
- const serviceGoFilePath = path.join(apiDir, `service.go`);
104
- const serviceGoTemplatePath = path.join(__dirname, '../templates/service.go.ejs');
105
- const serviceGoContent = await ejs.renderFile(serviceGoTemplatePath, { moduleName, ModuleName, projectName });
106
- await fs.writeFile(serviceGoFilePath, serviceGoContent);
107
- console.log(chalk.green(`Successfully created ${chalk.bold('service.go')} file`));
108
-
109
- // Create and write controller.go file
110
- const controllerGoFilePath = path.join(apiDir, `controller.go`);
111
- const controllerGoTemplatePath = path.join(__dirname, '../templates/controller.go.ejs');
112
- const controllerGoContent = await ejs.renderFile(controllerGoTemplatePath, { moduleName, ModuleName, projectName });
113
- await fs.writeFile(controllerGoFilePath, controllerGoContent);
177
+ const updateDomainInit = async (domainDir, projectName, moduleName) => {
178
+ const initFilePath = path.join(domainDir, 'init.go');
179
+ if (!await fs.pathExists(initFilePath)) {
180
+ console.log(chalk.yellow(`Could not find ${chalk.bold('init.go')} file, skipping import statement addition`));
181
+ return;
182
+ }
183
+
184
+ let initFileContent = await fs.readFile(initFilePath, 'utf-8');
185
+ const importStatement = `import _ "${projectName}/domain/${moduleName}"`;
186
+
187
+ if (initFileContent.includes(importStatement)) {
188
+ console.log(chalk.yellow('The corresponding import statement already exists in init.go, no need to add it again'));
189
+ return;
190
+ }
191
+
192
+ const packageMatch = initFileContent.match(/^package\s+\w+\s*$/m);
193
+ if (!packageMatch) {
194
+ console.log(chalk.yellow('package declaration not found, skipping import statement addition'));
195
+ return;
196
+ }
197
+
198
+ const insertPosition = packageMatch.index + packageMatch[0].length;
199
+ const rest = initFileContent.slice(insertPosition).trimStart();
200
+ initFileContent =
201
+ `${initFileContent.slice(0, insertPosition).trimEnd()}\n\n` +
202
+ `${importStatement}\n` +
203
+ (rest ? `\n${rest}` : '');
204
+
205
+ await fs.writeFile(initFilePath, initFileContent);
206
+ console.log(chalk.green(`Successfully updated ${chalk.bold('init.go')} file, added import statement`));
207
+ };
208
+
209
+ const createSimpleModule = async (moduleDir, data) => {
210
+ const { moduleName } = data;
211
+
212
+ await renderTemplate('model.go.ejs', path.join(moduleDir, 'model', `${moduleName}.go`), data);
213
+ console.log(chalk.green(`Successfully created ${chalk.bold('model.go')} file`));
214
+
215
+ await renderTemplate('dto.go.ejs', path.join(moduleDir, 'dto.go'), data);
216
+ console.log(chalk.green(`Successfully created ${chalk.bold('dto.go')} file`));
217
+
218
+ await renderTemplate('service.go.ejs', path.join(moduleDir, 'service.go'), data);
219
+ console.log(chalk.green(`Successfully created ${chalk.bold('service.go')} file`));
220
+
221
+ await renderTemplate('controller.go.ejs', path.join(moduleDir, 'controller.go'), data);
222
+ console.log(chalk.green(`Successfully created ${chalk.bold('controller.go')} file`));
223
+
224
+ await renderTemplate('router.go.ejs', path.join(moduleDir, 'router.go'), data);
225
+ console.log(chalk.green(`Successfully created ${chalk.bold('router.go')} file`));
226
+ };
227
+
228
+ const createCrudModule = async (moduleDir, projectDir, data, options) => {
229
+ const { moduleName } = data;
230
+ const crudData = {
231
+ ...data,
232
+ ...options,
233
+ dbTitle: options.db === 'mysql' ? 'MySQL' : 'MongoDB',
234
+ dbEnvName: options.dbName.replace(/[^A-Za-z0-9]/g, '_').toUpperCase(),
235
+ dbSchema: path.basename(projectDir).replace(/[^a-z0-9]/gi, '_').toLowerCase(),
236
+ };
237
+
238
+ await ensureCrudConfig(projectDir, crudData);
239
+
240
+ await renderTemplate('crud.model.go.ejs', path.join(moduleDir, 'model', `${moduleName}.go`), crudData);
241
+ console.log(chalk.green(`Successfully created ${chalk.bold('model.go')} file`));
242
+
243
+ await renderTemplate('crud.dto.go.ejs', path.join(moduleDir, 'dto.go'), crudData);
244
+ console.log(chalk.green(`Successfully created ${chalk.bold('dto.go')} file`));
245
+
246
+ await renderTemplate('crud.service.go.ejs', path.join(moduleDir, 'service.go'), crudData);
247
+ console.log(chalk.green(`Successfully created ${chalk.bold('service.go')} file`));
248
+
249
+ await renderTemplate('crud.module.README.md.ejs', path.join(moduleDir, 'README.md'), crudData);
250
+ console.log(chalk.green(`Successfully created ${chalk.bold('README.md')} file`));
251
+
252
+ await renderTemplate('crud.test.go.ejs', path.join(projectDir, 'test', `${moduleName}_test.go`), crudData);
253
+ console.log(chalk.green(`Successfully created ${chalk.bold('test file')} file`));
254
+
255
+ const integrationInitPath = path.join(projectDir, 'test', `init_${options.db}_integration_test.go`);
256
+ if (!await fs.pathExists(integrationInitPath)) {
257
+ await renderTemplate('crud.integration.init_test.go.ejs', integrationInitPath, crudData);
258
+ console.log(chalk.green(`Successfully created ${chalk.bold('database integration init file')} file`));
259
+ }
260
+
261
+ await renderTemplate(
262
+ 'crud.integration_test.go.ejs',
263
+ path.join(projectDir, 'test', `${moduleName}_integration_test.go`),
264
+ crudData,
265
+ );
266
+ console.log(chalk.green(`Successfully created ${chalk.bold('database integration test file')} file`));
267
+
268
+ if (options.http) {
269
+ await renderTemplate('crud.controller.go.ejs', path.join(moduleDir, 'controller.go'), crudData);
114
270
  console.log(chalk.green(`Successfully created ${chalk.bold('controller.go')} file`));
115
271
 
116
- // Create and write router.go file
117
- const routerGoFilePath = path.join(apiDir, `router.go`);
118
- const routerGoTemplatePath = path.join(__dirname, '../templates/router.go.ejs');
119
- const routerGoContent = await ejs.renderFile(routerGoTemplatePath, { moduleName, ModuleName, projectName });
120
- await fs.writeFile(routerGoFilePath, routerGoContent);
272
+ await renderTemplate('crud.router.go.ejs', path.join(moduleDir, 'router.go'), crudData);
121
273
  console.log(chalk.green(`Successfully created ${chalk.bold('router.go')} file`));
122
274
 
123
- // Check and update domain/init.go file
124
- const initFilePath = path.join(domainDir, 'init.go');
125
- if (await fs.pathExists(initFilePath)) {
126
- let initFileContent = await fs.readFile(initFilePath, 'utf-8');
127
-
128
- const importStatement = `import _ "${projectName}/domain/${moduleName}/api"`;
129
-
130
- if (!initFileContent.includes(importStatement)) {
131
- const initFuncIndex = initFileContent.indexOf('func init()');
132
-
133
- if (initFuncIndex !== -1) {
134
- // Find init function, ensure import statement is added above init function
135
- const insertPosition = initFuncIndex;
136
- const headCode = initFileContent.slice(0, insertPosition).trimEnd();
137
- initFileContent =
138
- `${headCode}\n` +
139
- `${importStatement}\n\n` +
140
- initFileContent.slice(insertPosition);
141
-
142
- await fs.writeFile(initFilePath, initFileContent);
143
- console.log(chalk.green(`Successfully updated ${chalk.bold('init.go')} file, added import statement`));
144
- } else {
145
- console.log(chalk.yellow(`init() function not found, skipping import statement addition`));
146
- }
147
- } else {
148
- console.log(chalk.yellow(`The corresponding import statement already exists in init.go, no need to add it again`));
149
- }
275
+ await renderTemplate('crud.doc.md.ejs', path.join(projectDir, 'doc', `${moduleName}.md`), crudData);
276
+ console.log(chalk.green(`Successfully created ${chalk.bold('doc file')} file`));
277
+ }
278
+ };
279
+
280
+ // Create module main function
281
+ const createModule = async (args) => {
282
+ try {
283
+ const options = parseCreateArgs(args);
284
+ const { moduleName, ModuleName } = options;
285
+ const currentDir = process.cwd();
286
+ const domainDir = path.join(currentDir, 'domain');
287
+ const moduleDir = path.join(domainDir, moduleName);
288
+
289
+ console.log(chalk.blue(`\nStarting to create module: ${chalk.bold(moduleName)}`));
290
+
291
+ const projectName = await getGoModModuleName();
292
+ const data = { moduleName, ModuleName, projectName };
293
+
294
+ await fs.ensureDir(domainDir);
295
+ await fs.ensureDir(path.join(moduleDir, 'model'));
296
+
297
+ if (options.crud) {
298
+ await createCrudModule(moduleDir, currentDir, data, options);
150
299
  } else {
151
- console.log(chalk.yellow(`Could not find ${chalk.bold('init.go')} file, skipping import statement addition`));
300
+ await createSimpleModule(moduleDir, data);
301
+ }
302
+
303
+ if (!options.crud || options.http) {
304
+ await updateDomainInit(domainDir, projectName, moduleName);
152
305
  }
153
306
 
154
- console.log(chalk.blue(`\nModule ${chalk.bold(moduleName)} has been successfully created in ${chalk.bold(`domain/${moduleName}`)} directory`));
307
+ const profile = options.crud ? `persistent CRUD (${options.db})` : 'basic';
308
+ console.log(chalk.blue(`\nModule ${chalk.bold(moduleName)} has been successfully created in ${chalk.bold(`domain/${moduleName}`)} directory [${profile}]`));
155
309
  } catch (error) {
156
310
  console.error(chalk.red('Error creating module:'), chalk.redBright(error.message));
311
+ process.exitCode = 1;
157
312
  }
158
313
  };
159
314
 
package/commands/doc.js CHANGED
@@ -422,16 +422,27 @@ const generateOpenAPIDocs = async (moduleName = null) => {
422
422
 
423
423
  for (const module of modulesToProcess) {
424
424
  const modulePath = path.join(domainDir, module);
425
- const routerFilePath = path.join(modulePath, 'api/router.go');
426
- const controllerFilePath = path.join(modulePath, 'api/controller.go');
425
+ const flatRouterFilePath = path.join(modulePath, 'router.go');
426
+ const flatControllerFilePath = path.join(modulePath, 'controller.go');
427
+ const legacyRouterFilePath = path.join(modulePath, 'api/router.go');
428
+ const legacyControllerFilePath = path.join(modulePath, 'api/controller.go');
429
+ const routerFilePath = await fs.pathExists(flatRouterFilePath) ? flatRouterFilePath : legacyRouterFilePath;
430
+ const controllerFilePath = await fs.pathExists(flatControllerFilePath) ? flatControllerFilePath : legacyControllerFilePath;
427
431
  const modelFilePath = path.join(modulePath, 'model', `${module}.go`);
432
+ const dtoFilePath = path.join(modulePath, 'dto.go');
428
433
  const reqFilePath = path.join(modulePath, 'api', 'req', 'req.go');
429
434
 
430
435
  // 检查文件是否存在
431
- if (!(await fs.pathExists(routerFilePath)) || !(await fs.pathExists(controllerFilePath)) || !(await fs.pathExists(modelFilePath)) || !(await fs.pathExists(reqFilePath))) {
436
+ if (!(await fs.pathExists(routerFilePath)) || !(await fs.pathExists(controllerFilePath)) || !(await fs.pathExists(modelFilePath))) {
432
437
  console.warn(chalk.yellow(`Module "${module}" is missing required files, skipping...`));
433
438
  continue;
434
439
  }
440
+ const schemaFilePaths = [modelFilePath];
441
+ if (await fs.pathExists(dtoFilePath)) {
442
+ schemaFilePaths.push(dtoFilePath);
443
+ } else if (await fs.pathExists(reqFilePath)) {
444
+ schemaFilePaths.push(reqFilePath);
445
+ }
435
446
 
436
447
  // 扫描 router.go 获取路由信息
437
448
  const routes = await scanRouterFile(routerFilePath);
@@ -439,13 +450,15 @@ const generateOpenAPIDocs = async (moduleName = null) => {
439
450
 
440
451
  // 扫描 controller.go 获取方法参数
441
452
  const controllerContent = await fs.readFile(controllerFilePath, 'utf-8');
442
- const controllerParams = await extractParamsFromController(controllerContent, path.dirname(reqFilePath), path.dirname(modelFilePath));
453
+ const reqDir = await fs.pathExists(reqFilePath) ? path.dirname(reqFilePath) : modulePath;
454
+ const controllerParams = await extractParamsFromController(controllerContent, reqDir, path.dirname(modelFilePath));
443
455
  // console.log(`Extracted controller parameters for module "${module}":`, controllerParams);
444
456
 
445
- // 扫描 model.go 和 req.go 获取字段
446
- const modelFields = await extractModelFields(modelFilePath);
447
- const reqFields = await extractModelFields(reqFilePath);
448
- const allFields = [...modelFields, ...reqFields];
457
+ // 扫描 model.go 和 dto.go/req.go 获取字段
458
+ const allFields = [];
459
+ for (const schemaFilePath of schemaFilePaths) {
460
+ allFields.push(...await extractModelFields(schemaFilePath));
461
+ }
449
462
 
450
463
  // 生成 OpenAPI 格式文档
451
464
  const openAPIDoc = {