@svton/cli 1.2.5 → 1.4.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/ast-helper-5I5LPFKU.mjs +105 -0
- package/dist/ast-helper-RVSIO37P.mjs +105 -0
- package/dist/chunk-Y6FXYEAI.mjs +10 -0
- package/dist/index.js +289 -59
- package/dist/index.mjs +150 -37
- package/package.json +10 -4
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import "./chunk-Y6FXYEAI.mjs";
|
|
2
|
+
|
|
3
|
+
// src/utils/ast-helper.ts
|
|
4
|
+
import * as parser from "@babel/parser";
|
|
5
|
+
import traverse from "@babel/traverse";
|
|
6
|
+
import generate from "@babel/generator";
|
|
7
|
+
import * as t from "@babel/types";
|
|
8
|
+
import fs from "fs-extra";
|
|
9
|
+
function addImportToFile(code, importDeclarations) {
|
|
10
|
+
const ast = parser.parse(code, {
|
|
11
|
+
sourceType: "module",
|
|
12
|
+
plugins: ["typescript", "decorators-legacy"]
|
|
13
|
+
});
|
|
14
|
+
let lastImportIndex = -1;
|
|
15
|
+
traverse(ast, {
|
|
16
|
+
ImportDeclaration(path) {
|
|
17
|
+
const start = path.node.start;
|
|
18
|
+
if (start !== null && start !== void 0 && start > lastImportIndex) {
|
|
19
|
+
lastImportIndex = start;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
const newImports = importDeclarations.map(({ from, imports }) => {
|
|
24
|
+
const specifiers = imports.map(
|
|
25
|
+
(imp) => t.importSpecifier(t.identifier(imp), t.identifier(imp))
|
|
26
|
+
);
|
|
27
|
+
return t.importDeclaration(specifiers, t.stringLiteral(from));
|
|
28
|
+
});
|
|
29
|
+
if (lastImportIndex >= 0) {
|
|
30
|
+
const program = ast.program;
|
|
31
|
+
const lastImportNode = program.body.find(
|
|
32
|
+
(node) => node.type === "ImportDeclaration" && node.start !== null && node.start === lastImportIndex
|
|
33
|
+
);
|
|
34
|
+
if (lastImportNode) {
|
|
35
|
+
const index = program.body.indexOf(lastImportNode);
|
|
36
|
+
program.body.splice(index + 1, 0, ...newImports);
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
ast.program.body.unshift(...newImports);
|
|
40
|
+
}
|
|
41
|
+
const output = generate(ast, {
|
|
42
|
+
retainLines: false,
|
|
43
|
+
compact: false
|
|
44
|
+
});
|
|
45
|
+
return output.code;
|
|
46
|
+
}
|
|
47
|
+
function addModuleImports(code, moduleExpressions) {
|
|
48
|
+
const ast = parser.parse(code, {
|
|
49
|
+
sourceType: "module",
|
|
50
|
+
plugins: ["typescript", "decorators-legacy"]
|
|
51
|
+
});
|
|
52
|
+
let modified = false;
|
|
53
|
+
traverse(ast, {
|
|
54
|
+
Decorator(path) {
|
|
55
|
+
if (t.isCallExpression(path.node.expression) && t.isIdentifier(path.node.expression.callee) && path.node.expression.callee.name === "Module") {
|
|
56
|
+
const args = path.node.expression.arguments;
|
|
57
|
+
if (args.length > 0 && t.isObjectExpression(args[0])) {
|
|
58
|
+
const moduleConfig = args[0];
|
|
59
|
+
const importsProperty = moduleConfig.properties.find(
|
|
60
|
+
(prop) => t.isObjectProperty(prop) && t.isIdentifier(prop.key) && prop.key.name === "imports"
|
|
61
|
+
);
|
|
62
|
+
if (importsProperty && t.isObjectProperty(importsProperty)) {
|
|
63
|
+
if (t.isArrayExpression(importsProperty.value)) {
|
|
64
|
+
for (const expr of moduleExpressions) {
|
|
65
|
+
try {
|
|
66
|
+
const exprAst = parser.parseExpression(expr, {
|
|
67
|
+
plugins: ["typescript"]
|
|
68
|
+
});
|
|
69
|
+
importsProperty.value.elements.push(exprAst);
|
|
70
|
+
modified = true;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error(`Failed to parse expression: ${expr}`, error);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
if (!modified) {
|
|
82
|
+
console.warn("Could not find @Module decorator or imports array");
|
|
83
|
+
return code;
|
|
84
|
+
}
|
|
85
|
+
const output = generate(ast, {
|
|
86
|
+
retainLines: false,
|
|
87
|
+
compact: false
|
|
88
|
+
});
|
|
89
|
+
return output.code;
|
|
90
|
+
}
|
|
91
|
+
async function updateAppModuleFile(filePath, imports, moduleExpressions) {
|
|
92
|
+
let code = await fs.readFile(filePath, "utf-8");
|
|
93
|
+
if (imports.length > 0) {
|
|
94
|
+
code = addImportToFile(code, imports);
|
|
95
|
+
}
|
|
96
|
+
if (moduleExpressions.length > 0) {
|
|
97
|
+
code = addModuleImports(code, moduleExpressions);
|
|
98
|
+
}
|
|
99
|
+
await fs.writeFile(filePath, code, "utf-8");
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
addImportToFile,
|
|
103
|
+
addModuleImports,
|
|
104
|
+
updateAppModuleFile
|
|
105
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import "./chunk-Y6FXYEAI.mjs";
|
|
2
|
+
|
|
3
|
+
// src/utils/ast-helper.ts
|
|
4
|
+
import * as parser from "@babel/parser";
|
|
5
|
+
import traverse from "@babel/traverse";
|
|
6
|
+
import generate from "@babel/generator";
|
|
7
|
+
import * as t from "@babel/types";
|
|
8
|
+
import fs from "fs-extra";
|
|
9
|
+
function addImportToFile(code, importDeclarations) {
|
|
10
|
+
const ast = parser.parse(code, {
|
|
11
|
+
sourceType: "module",
|
|
12
|
+
plugins: ["typescript", "decorators-legacy"]
|
|
13
|
+
});
|
|
14
|
+
let lastImportIndex = -1;
|
|
15
|
+
traverse(ast, {
|
|
16
|
+
ImportDeclaration(path) {
|
|
17
|
+
const start = path.node.start;
|
|
18
|
+
if (start !== null && start > lastImportIndex) {
|
|
19
|
+
lastImportIndex = start;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
const newImports = importDeclarations.map(({ from, imports }) => {
|
|
24
|
+
const specifiers = imports.map(
|
|
25
|
+
(imp) => t.importSpecifier(t.identifier(imp), t.identifier(imp))
|
|
26
|
+
);
|
|
27
|
+
return t.importDeclaration(specifiers, t.stringLiteral(from));
|
|
28
|
+
});
|
|
29
|
+
if (lastImportIndex >= 0) {
|
|
30
|
+
const program = ast.program;
|
|
31
|
+
const lastImportNode = program.body.find(
|
|
32
|
+
(node) => node.type === "ImportDeclaration" && node.start === lastImportIndex
|
|
33
|
+
);
|
|
34
|
+
if (lastImportNode) {
|
|
35
|
+
const index = program.body.indexOf(lastImportNode);
|
|
36
|
+
program.body.splice(index + 1, 0, ...newImports);
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
ast.program.body.unshift(...newImports);
|
|
40
|
+
}
|
|
41
|
+
const output = generate(ast, {
|
|
42
|
+
retainLines: false,
|
|
43
|
+
compact: false
|
|
44
|
+
});
|
|
45
|
+
return output.code;
|
|
46
|
+
}
|
|
47
|
+
function addModuleImports(code, moduleExpressions) {
|
|
48
|
+
const ast = parser.parse(code, {
|
|
49
|
+
sourceType: "module",
|
|
50
|
+
plugins: ["typescript", "decorators-legacy"]
|
|
51
|
+
});
|
|
52
|
+
let modified = false;
|
|
53
|
+
traverse(ast, {
|
|
54
|
+
Decorator(path) {
|
|
55
|
+
if (t.isCallExpression(path.node.expression) && t.isIdentifier(path.node.expression.callee) && path.node.expression.callee.name === "Module") {
|
|
56
|
+
const args = path.node.expression.arguments;
|
|
57
|
+
if (args.length > 0 && t.isObjectExpression(args[0])) {
|
|
58
|
+
const moduleConfig = args[0];
|
|
59
|
+
const importsProperty = moduleConfig.properties.find(
|
|
60
|
+
(prop) => t.isObjectProperty(prop) && t.isIdentifier(prop.key) && prop.key.name === "imports"
|
|
61
|
+
);
|
|
62
|
+
if (importsProperty && t.isObjectProperty(importsProperty)) {
|
|
63
|
+
if (t.isArrayExpression(importsProperty.value)) {
|
|
64
|
+
for (const expr of moduleExpressions) {
|
|
65
|
+
try {
|
|
66
|
+
const exprAst = parser.parseExpression(expr, {
|
|
67
|
+
plugins: ["typescript"]
|
|
68
|
+
});
|
|
69
|
+
importsProperty.value.elements.push(exprAst);
|
|
70
|
+
modified = true;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error(`Failed to parse expression: ${expr}`, error);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
if (!modified) {
|
|
82
|
+
console.warn("Could not find @Module decorator or imports array");
|
|
83
|
+
return code;
|
|
84
|
+
}
|
|
85
|
+
const output = generate(ast, {
|
|
86
|
+
retainLines: false,
|
|
87
|
+
compact: false
|
|
88
|
+
});
|
|
89
|
+
return output.code;
|
|
90
|
+
}
|
|
91
|
+
async function updateAppModuleFile(filePath, imports, moduleExpressions) {
|
|
92
|
+
let code = await fs.readFile(filePath, "utf-8");
|
|
93
|
+
if (imports.length > 0) {
|
|
94
|
+
code = addImportToFile(code, imports);
|
|
95
|
+
}
|
|
96
|
+
if (moduleExpressions.length > 0) {
|
|
97
|
+
code = addModuleImports(code, moduleExpressions);
|
|
98
|
+
}
|
|
99
|
+
await fs.writeFile(filePath, code, "utf-8");
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
addImportToFile,
|
|
103
|
+
addModuleImports,
|
|
104
|
+
updateAppModuleFile
|
|
105
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
__require
|
|
10
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
9
12
|
var __export = (target, all) => {
|
|
10
13
|
for (var name in all)
|
|
11
14
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -28,6 +31,117 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
31
|
));
|
|
29
32
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
33
|
|
|
34
|
+
// src/utils/ast-helper.ts
|
|
35
|
+
var ast_helper_exports = {};
|
|
36
|
+
__export(ast_helper_exports, {
|
|
37
|
+
addImportToFile: () => addImportToFile,
|
|
38
|
+
addModuleImports: () => addModuleImports,
|
|
39
|
+
updateAppModuleFile: () => updateAppModuleFile
|
|
40
|
+
});
|
|
41
|
+
function addImportToFile(code, importDeclarations) {
|
|
42
|
+
const ast = parser.parse(code, {
|
|
43
|
+
sourceType: "module",
|
|
44
|
+
plugins: ["typescript", "decorators-legacy"]
|
|
45
|
+
});
|
|
46
|
+
let lastImportIndex = -1;
|
|
47
|
+
(0, import_traverse.default)(ast, {
|
|
48
|
+
ImportDeclaration(path5) {
|
|
49
|
+
const start = path5.node.start;
|
|
50
|
+
if (start !== null && start !== void 0 && start > lastImportIndex) {
|
|
51
|
+
lastImportIndex = start;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
const newImports = importDeclarations.map(({ from, imports }) => {
|
|
56
|
+
const specifiers = imports.map(
|
|
57
|
+
(imp) => t.importSpecifier(t.identifier(imp), t.identifier(imp))
|
|
58
|
+
);
|
|
59
|
+
return t.importDeclaration(specifiers, t.stringLiteral(from));
|
|
60
|
+
});
|
|
61
|
+
if (lastImportIndex >= 0) {
|
|
62
|
+
const program = ast.program;
|
|
63
|
+
const lastImportNode = program.body.find(
|
|
64
|
+
(node) => node.type === "ImportDeclaration" && node.start !== null && node.start === lastImportIndex
|
|
65
|
+
);
|
|
66
|
+
if (lastImportNode) {
|
|
67
|
+
const index = program.body.indexOf(lastImportNode);
|
|
68
|
+
program.body.splice(index + 1, 0, ...newImports);
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
ast.program.body.unshift(...newImports);
|
|
72
|
+
}
|
|
73
|
+
const output = (0, import_generator.default)(ast, {
|
|
74
|
+
retainLines: false,
|
|
75
|
+
compact: false
|
|
76
|
+
});
|
|
77
|
+
return output.code;
|
|
78
|
+
}
|
|
79
|
+
function addModuleImports(code, moduleExpressions) {
|
|
80
|
+
const ast = parser.parse(code, {
|
|
81
|
+
sourceType: "module",
|
|
82
|
+
plugins: ["typescript", "decorators-legacy"]
|
|
83
|
+
});
|
|
84
|
+
let modified = false;
|
|
85
|
+
(0, import_traverse.default)(ast, {
|
|
86
|
+
Decorator(path5) {
|
|
87
|
+
if (t.isCallExpression(path5.node.expression) && t.isIdentifier(path5.node.expression.callee) && path5.node.expression.callee.name === "Module") {
|
|
88
|
+
const args = path5.node.expression.arguments;
|
|
89
|
+
if (args.length > 0 && t.isObjectExpression(args[0])) {
|
|
90
|
+
const moduleConfig = args[0];
|
|
91
|
+
const importsProperty = moduleConfig.properties.find(
|
|
92
|
+
(prop) => t.isObjectProperty(prop) && t.isIdentifier(prop.key) && prop.key.name === "imports"
|
|
93
|
+
);
|
|
94
|
+
if (importsProperty && t.isObjectProperty(importsProperty)) {
|
|
95
|
+
if (t.isArrayExpression(importsProperty.value)) {
|
|
96
|
+
for (const expr of moduleExpressions) {
|
|
97
|
+
try {
|
|
98
|
+
const exprAst = parser.parseExpression(expr, {
|
|
99
|
+
plugins: ["typescript"]
|
|
100
|
+
});
|
|
101
|
+
importsProperty.value.elements.push(exprAst);
|
|
102
|
+
modified = true;
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error(`Failed to parse expression: ${expr}`, error);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
if (!modified) {
|
|
114
|
+
console.warn("Could not find @Module decorator or imports array");
|
|
115
|
+
return code;
|
|
116
|
+
}
|
|
117
|
+
const output = (0, import_generator.default)(ast, {
|
|
118
|
+
retainLines: false,
|
|
119
|
+
compact: false
|
|
120
|
+
});
|
|
121
|
+
return output.code;
|
|
122
|
+
}
|
|
123
|
+
async function updateAppModuleFile(filePath, imports, moduleExpressions) {
|
|
124
|
+
let code = await import_fs_extra4.default.readFile(filePath, "utf-8");
|
|
125
|
+
if (imports.length > 0) {
|
|
126
|
+
code = addImportToFile(code, imports);
|
|
127
|
+
}
|
|
128
|
+
if (moduleExpressions.length > 0) {
|
|
129
|
+
code = addModuleImports(code, moduleExpressions);
|
|
130
|
+
}
|
|
131
|
+
await import_fs_extra4.default.writeFile(filePath, code, "utf-8");
|
|
132
|
+
}
|
|
133
|
+
var parser, import_traverse, import_generator, t, import_fs_extra4;
|
|
134
|
+
var init_ast_helper = __esm({
|
|
135
|
+
"src/utils/ast-helper.ts"() {
|
|
136
|
+
"use strict";
|
|
137
|
+
parser = __toESM(require("@babel/parser"));
|
|
138
|
+
import_traverse = __toESM(require("@babel/traverse"));
|
|
139
|
+
import_generator = __toESM(require("@babel/generator"));
|
|
140
|
+
t = __toESM(require("@babel/types"));
|
|
141
|
+
import_fs_extra4 = __toESM(require("fs-extra"));
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
31
145
|
// src/index.ts
|
|
32
146
|
var index_exports = {};
|
|
33
147
|
__export(index_exports, {
|
|
@@ -40,7 +154,7 @@ var import_commander = require("commander");
|
|
|
40
154
|
var import_inquirer = __toESM(require("inquirer"));
|
|
41
155
|
var import_chalk2 = __toESM(require("chalk"));
|
|
42
156
|
var import_ora = __toESM(require("ora"));
|
|
43
|
-
var
|
|
157
|
+
var import_fs_extra6 = __toESM(require("fs-extra"));
|
|
44
158
|
var import_path4 = __toESM(require("path"));
|
|
45
159
|
var import_validate_npm_package_name = __toESM(require("validate-npm-package-name"));
|
|
46
160
|
|
|
@@ -263,12 +377,12 @@ async function replacePackageNames(directory, config) {
|
|
|
263
377
|
}
|
|
264
378
|
async function findFilesToUpdate(directory) {
|
|
265
379
|
const files = [];
|
|
266
|
-
const
|
|
380
|
+
const traverse2 = async (dir) => {
|
|
267
381
|
const entries = await import_fs_extra2.default.readdir(dir, { withFileTypes: true });
|
|
268
382
|
for (const entry of entries) {
|
|
269
383
|
const fullPath = import_path2.default.join(dir, entry.name);
|
|
270
384
|
if (entry.isDirectory()) {
|
|
271
|
-
await
|
|
385
|
+
await traverse2(fullPath);
|
|
272
386
|
} else if (entry.isFile()) {
|
|
273
387
|
const ext = import_path2.default.extname(entry.name);
|
|
274
388
|
const shouldUpdate = [".json", ".ts", ".tsx", ".js", ".jsx", ".md", ".yaml", ".yml", ".env.example", ".tpl"].includes(ext) || entry.name.endsWith(".tpl");
|
|
@@ -278,7 +392,7 @@ async function findFilesToUpdate(directory) {
|
|
|
278
392
|
}
|
|
279
393
|
}
|
|
280
394
|
};
|
|
281
|
-
await
|
|
395
|
+
await traverse2(directory);
|
|
282
396
|
return files;
|
|
283
397
|
}
|
|
284
398
|
async function copyBuiltInTemplates(config) {
|
|
@@ -682,17 +796,17 @@ async function initGit(projectName) {
|
|
|
682
796
|
}
|
|
683
797
|
|
|
684
798
|
// src/utils/features.ts
|
|
685
|
-
var
|
|
799
|
+
var import_fs_extra5 = __toESM(require("fs-extra"));
|
|
686
800
|
var import_path3 = __toESM(require("path"));
|
|
687
801
|
async function loadFeaturesConfig() {
|
|
688
802
|
const configPath = import_path3.default.join(__dirname, "../features.json");
|
|
689
|
-
if (!
|
|
803
|
+
if (!import_fs_extra5.default.existsSync(configPath)) {
|
|
690
804
|
const devPath = import_path3.default.join(__dirname, "../../features.json");
|
|
691
|
-
if (
|
|
692
|
-
return await
|
|
805
|
+
if (import_fs_extra5.default.existsSync(devPath)) {
|
|
806
|
+
return await import_fs_extra5.default.readJSON(devPath);
|
|
693
807
|
}
|
|
694
808
|
}
|
|
695
|
-
return await
|
|
809
|
+
return await import_fs_extra5.default.readJSON(configPath);
|
|
696
810
|
}
|
|
697
811
|
function getFeatureChoices(config) {
|
|
698
812
|
return Object.entries(config.features).map(([key, feature]) => ({
|
|
@@ -729,21 +843,53 @@ function collectEnvVars(features, config) {
|
|
|
729
843
|
}
|
|
730
844
|
async function generateEnvExample(features, config, targetPath) {
|
|
731
845
|
const envVars = collectEnvVars(features, config);
|
|
846
|
+
if (envVars.length === 0) {
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
732
849
|
const content = [
|
|
850
|
+
"# ========================================",
|
|
733
851
|
"# Environment Variables",
|
|
852
|
+
"# ========================================",
|
|
734
853
|
"# Copy this file to .env and fill in the values",
|
|
854
|
+
"#",
|
|
855
|
+
"# IMPORTANT: Never commit .env file to version control!",
|
|
856
|
+
"# Add .env to your .gitignore file",
|
|
857
|
+
"#",
|
|
735
858
|
"",
|
|
736
|
-
|
|
737
|
-
|
|
859
|
+
"# ========================================",
|
|
860
|
+
"# Application Configuration",
|
|
861
|
+
"# ========================================",
|
|
862
|
+
"NODE_ENV=development",
|
|
863
|
+
"PORT=3000",
|
|
864
|
+
"",
|
|
865
|
+
"# ========================================",
|
|
866
|
+
"# Database Configuration",
|
|
867
|
+
"# ========================================",
|
|
868
|
+
"DATABASE_URL=mysql://root:root123456@localhost:3306/{{PROJECT_NAME}}",
|
|
869
|
+
""
|
|
870
|
+
];
|
|
871
|
+
const featureGroups = {};
|
|
872
|
+
for (const featureKey of features) {
|
|
873
|
+
const feature = config.features[featureKey];
|
|
874
|
+
if (feature && feature.envVars.length > 0) {
|
|
875
|
+
featureGroups[feature.name] = feature.envVars;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
for (const [featureName, vars] of Object.entries(featureGroups)) {
|
|
879
|
+
content.push("# ========================================");
|
|
880
|
+
content.push(`# ${featureName} Configuration`);
|
|
881
|
+
content.push("# ========================================");
|
|
882
|
+
for (const envVar of vars) {
|
|
738
883
|
if (envVar.description) {
|
|
739
|
-
|
|
884
|
+
content.push(`# ${envVar.description}`);
|
|
740
885
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
await
|
|
886
|
+
content.push(`${envVar.key}=${envVar.default}`);
|
|
887
|
+
content.push("");
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
const envPath = import_path3.default.join(targetPath, "apps/backend/.env.example");
|
|
891
|
+
await import_fs_extra5.default.ensureDir(import_path3.default.dirname(envPath));
|
|
892
|
+
await import_fs_extra5.default.writeFile(envPath, content.join("\n"));
|
|
747
893
|
logger.info("Generated .env.example");
|
|
748
894
|
}
|
|
749
895
|
async function copyConfigFiles(features, config, templateDir, targetPath) {
|
|
@@ -753,9 +899,9 @@ async function copyConfigFiles(features, config, templateDir, targetPath) {
|
|
|
753
899
|
for (const configFile of feature.configFiles) {
|
|
754
900
|
const sourcePath = import_path3.default.join(templateDir, configFile.template);
|
|
755
901
|
const destPath = import_path3.default.join(targetPath, configFile.path);
|
|
756
|
-
if (await
|
|
757
|
-
await
|
|
758
|
-
await
|
|
902
|
+
if (await import_fs_extra5.default.pathExists(sourcePath)) {
|
|
903
|
+
await import_fs_extra5.default.ensureDir(import_path3.default.dirname(destPath));
|
|
904
|
+
await import_fs_extra5.default.copy(sourcePath, destPath);
|
|
759
905
|
logger.info(`Copied config: ${configFile.path}`);
|
|
760
906
|
} else {
|
|
761
907
|
logger.warn(`Config template not found: ${sourcePath}`);
|
|
@@ -770,9 +916,9 @@ async function copyExampleFiles(features, config, templateDir, targetPath) {
|
|
|
770
916
|
if (feature && feature.exampleFiles) {
|
|
771
917
|
const sourcePath = import_path3.default.join(templateDir, feature.exampleFiles.source);
|
|
772
918
|
const destPath = import_path3.default.join(targetPath, feature.exampleFiles.target);
|
|
773
|
-
if (await
|
|
774
|
-
await
|
|
775
|
-
await
|
|
919
|
+
if (await import_fs_extra5.default.pathExists(sourcePath)) {
|
|
920
|
+
await import_fs_extra5.default.ensureDir(import_path3.default.dirname(destPath));
|
|
921
|
+
await import_fs_extra5.default.copy(sourcePath, destPath);
|
|
776
922
|
logger.info(`Copied examples: ${feature.exampleFiles.target}`);
|
|
777
923
|
} else {
|
|
778
924
|
logger.warn(`Example template not found: ${sourcePath}`);
|
|
@@ -782,11 +928,11 @@ async function copyExampleFiles(features, config, templateDir, targetPath) {
|
|
|
782
928
|
}
|
|
783
929
|
async function copySkillFiles(features, config, templateDir, targetPath) {
|
|
784
930
|
const skillsDir = import_path3.default.join(targetPath, ".kiro/skills");
|
|
785
|
-
await
|
|
931
|
+
await import_fs_extra5.default.ensureDir(skillsDir);
|
|
786
932
|
const baseSkillSource = import_path3.default.join(templateDir, "skills/base.skill.md");
|
|
787
933
|
const baseSkillDest = import_path3.default.join(skillsDir, "project-capabilities.md");
|
|
788
|
-
if (await
|
|
789
|
-
await
|
|
934
|
+
if (await import_fs_extra5.default.pathExists(baseSkillSource)) {
|
|
935
|
+
await import_fs_extra5.default.copy(baseSkillSource, baseSkillDest);
|
|
790
936
|
logger.info("Copied base skill file");
|
|
791
937
|
} else {
|
|
792
938
|
logger.warn(`Base skill template not found: ${baseSkillSource}`);
|
|
@@ -796,9 +942,9 @@ async function copySkillFiles(features, config, templateDir, targetPath) {
|
|
|
796
942
|
if (feature && feature.skillFile) {
|
|
797
943
|
const sourcePath = import_path3.default.join(templateDir, feature.skillFile.template);
|
|
798
944
|
const destPath = import_path3.default.join(targetPath, feature.skillFile.target);
|
|
799
|
-
if (await
|
|
800
|
-
await
|
|
801
|
-
await
|
|
945
|
+
if (await import_fs_extra5.default.pathExists(sourcePath)) {
|
|
946
|
+
await import_fs_extra5.default.ensureDir(import_path3.default.dirname(destPath));
|
|
947
|
+
await import_fs_extra5.default.copy(sourcePath, destPath);
|
|
802
948
|
logger.info(`Copied skill: ${feature.skillFile.target}`);
|
|
803
949
|
} else {
|
|
804
950
|
logger.warn(`Skill template not found: ${sourcePath}`);
|
|
@@ -843,29 +989,39 @@ ${featuresList}
|
|
|
843
989
|
- GitHub\uFF1Ahttps://github.com/751848178/svton
|
|
844
990
|
`;
|
|
845
991
|
const indexPath = import_path3.default.join(targetPath, ".kiro/skills/project-capabilities.md");
|
|
846
|
-
await
|
|
992
|
+
await import_fs_extra5.default.writeFile(indexPath, content);
|
|
847
993
|
logger.info("Generated capabilities index");
|
|
848
994
|
}
|
|
849
995
|
async function updatePackageJson(features, config, targetPath) {
|
|
850
996
|
const packageJsonPath = import_path3.default.join(targetPath, "apps/backend/package.json");
|
|
851
|
-
const packageJson = await
|
|
997
|
+
const packageJson = await import_fs_extra5.default.readJSON(packageJsonPath);
|
|
852
998
|
const dependencies = collectDependencies(features, config);
|
|
853
999
|
packageJson.dependencies = {
|
|
854
1000
|
...packageJson.dependencies,
|
|
855
1001
|
...dependencies
|
|
856
1002
|
};
|
|
857
|
-
await
|
|
1003
|
+
await import_fs_extra5.default.writeJSON(packageJsonPath, packageJson, { spaces: 2 });
|
|
858
1004
|
logger.info("Updated package.json with feature dependencies");
|
|
859
1005
|
}
|
|
860
1006
|
function generateModuleImports(features, config) {
|
|
861
1007
|
const imports = [];
|
|
1008
|
+
const seen = /* @__PURE__ */ new Set();
|
|
862
1009
|
for (const featureKey of features) {
|
|
863
1010
|
const feature = config.features[featureKey];
|
|
864
1011
|
if (feature && feature.moduleImports) {
|
|
865
1012
|
for (const moduleImport of feature.moduleImports) {
|
|
866
|
-
|
|
1013
|
+
const importKey = `${moduleImport.from}:${moduleImport.import}`;
|
|
1014
|
+
if (!seen.has(importKey)) {
|
|
1015
|
+
imports.push(`import { ${moduleImport.import} } from '${moduleImport.from}';`);
|
|
1016
|
+
seen.add(importKey);
|
|
1017
|
+
}
|
|
867
1018
|
}
|
|
868
1019
|
}
|
|
1020
|
+
if (feature && feature.configFiles && feature.configFiles.length > 0) {
|
|
1021
|
+
const configFileName = import_path3.default.basename(feature.configFiles[0].path, ".ts");
|
|
1022
|
+
const configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
|
|
1023
|
+
imports.push(`import { ${configFunctionName} } from './config/${configFileName}';`);
|
|
1024
|
+
}
|
|
869
1025
|
}
|
|
870
1026
|
return imports.join("\n");
|
|
871
1027
|
}
|
|
@@ -874,40 +1030,114 @@ function generateModuleRegistrations(features, config) {
|
|
|
874
1030
|
for (const featureKey of features) {
|
|
875
1031
|
const feature = config.features[featureKey];
|
|
876
1032
|
if (feature && feature.moduleRegistration) {
|
|
877
|
-
const { module: moduleName,
|
|
878
|
-
|
|
879
|
-
|
|
1033
|
+
const { module: moduleName, type: registrationType } = feature.moduleRegistration;
|
|
1034
|
+
const configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
|
|
1035
|
+
registrations.push(` ${moduleName}.${registrationType}({
|
|
1036
|
+
imports: [ConfigModule],
|
|
880
1037
|
inject: [ConfigService],
|
|
1038
|
+
useFactory: (configService: ConfigService) => ${configFunctionName}(configService),
|
|
881
1039
|
}),`);
|
|
882
1040
|
}
|
|
883
1041
|
}
|
|
884
1042
|
return registrations.join("\n");
|
|
885
1043
|
}
|
|
886
1044
|
async function updateAppModule(features, config, targetPath) {
|
|
1045
|
+
if (features.length === 0) {
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
887
1048
|
const appModulePath = import_path3.default.join(targetPath, "apps/backend/src/app.module.ts");
|
|
888
|
-
if (!await
|
|
1049
|
+
if (!await import_fs_extra5.default.pathExists(appModulePath)) {
|
|
889
1050
|
logger.warn("app.module.ts not found, skipping module injection");
|
|
890
1051
|
return;
|
|
891
1052
|
}
|
|
892
|
-
|
|
1053
|
+
try {
|
|
1054
|
+
const imports = [];
|
|
1055
|
+
const moduleExpressions = [];
|
|
1056
|
+
const needsConfigService = features.some((key) => {
|
|
1057
|
+
const feature = config.features[key];
|
|
1058
|
+
return feature && feature.moduleRegistration;
|
|
1059
|
+
});
|
|
1060
|
+
if (needsConfigService) {
|
|
1061
|
+
}
|
|
1062
|
+
for (const featureKey of features) {
|
|
1063
|
+
const feature = config.features[featureKey];
|
|
1064
|
+
if (!feature) continue;
|
|
1065
|
+
if (feature.moduleImports) {
|
|
1066
|
+
for (const moduleImport of feature.moduleImports) {
|
|
1067
|
+
imports.push({
|
|
1068
|
+
from: moduleImport.from,
|
|
1069
|
+
imports: [moduleImport.import]
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
if (feature.configFiles && feature.configFiles.length > 0) {
|
|
1074
|
+
const configFileName = import_path3.default.basename(feature.configFiles[0].path, ".ts");
|
|
1075
|
+
const configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
|
|
1076
|
+
imports.push({
|
|
1077
|
+
from: `./config/${configFileName}`,
|
|
1078
|
+
imports: [configFunctionName]
|
|
1079
|
+
});
|
|
1080
|
+
}
|
|
1081
|
+
if (feature.moduleRegistration) {
|
|
1082
|
+
const { module: moduleName, type: registrationType } = feature.moduleRegistration;
|
|
1083
|
+
const configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
|
|
1084
|
+
const moduleExpression = `${moduleName}.${registrationType}({
|
|
1085
|
+
imports: [ConfigModule],
|
|
1086
|
+
inject: [ConfigService],
|
|
1087
|
+
useFactory: (configService: ConfigService) => ${configFunctionName}(configService),
|
|
1088
|
+
})`;
|
|
1089
|
+
moduleExpressions.push(moduleExpression);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
const { updateAppModuleFile: updateAppModuleFile2 } = await Promise.resolve().then(() => (init_ast_helper(), ast_helper_exports));
|
|
1093
|
+
await updateAppModuleFile2(appModulePath, imports, moduleExpressions);
|
|
1094
|
+
logger.info("Successfully updated app.module.ts with feature modules");
|
|
1095
|
+
} catch (error) {
|
|
1096
|
+
logger.error(`Failed to update app.module.ts: ${error instanceof Error ? error.message : String(error)}`);
|
|
1097
|
+
await generateManualIntegrationGuide(features, config, targetPath);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
async function generateManualIntegrationGuide(features, config, targetPath) {
|
|
893
1101
|
const imports = generateModuleImports(features, config);
|
|
894
1102
|
const registrations = generateModuleRegistrations(features, config);
|
|
895
|
-
const
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
1103
|
+
const content = `# \u529F\u80FD\u6A21\u5757\u96C6\u6210\u8BF4\u660E
|
|
1104
|
+
|
|
1105
|
+
\u26A0\uFE0F \u81EA\u52A8\u96C6\u6210\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A
|
|
1106
|
+
|
|
1107
|
+
## 1. \u6DFB\u52A0\u5BFC\u5165\u8BED\u53E5
|
|
1108
|
+
|
|
1109
|
+
\u5728 \`apps/backend/src/app.module.ts\` \u6587\u4EF6\u9876\u90E8\u6DFB\u52A0\u4EE5\u4E0B\u5BFC\u5165\uFF1A
|
|
1110
|
+
|
|
1111
|
+
\`\`\`typescript
|
|
1112
|
+
${imports}
|
|
1113
|
+
\`\`\`
|
|
1114
|
+
|
|
1115
|
+
## 2. \u6CE8\u518C\u6A21\u5757
|
|
1116
|
+
|
|
1117
|
+
\u5728 \`@Module\` \u88C5\u9970\u5668\u7684 \`imports\` \u6570\u7EC4\u4E2D\u6DFB\u52A0\u4EE5\u4E0B\u6A21\u5757\uFF1A
|
|
1118
|
+
|
|
1119
|
+
\`\`\`typescript
|
|
1120
|
+
@Module({
|
|
1121
|
+
imports: [
|
|
1122
|
+
// ... \u5176\u4ED6\u6A21\u5757
|
|
1123
|
+
${registrations}
|
|
1124
|
+
],
|
|
1125
|
+
// ...
|
|
1126
|
+
})
|
|
1127
|
+
export class AppModule {}
|
|
1128
|
+
\`\`\`
|
|
1129
|
+
|
|
1130
|
+
## 3. \u914D\u7F6E\u6587\u4EF6
|
|
1131
|
+
|
|
1132
|
+
\u6BCF\u4E2A\u529F\u80FD\u7684\u914D\u7F6E\u6587\u4EF6\u5DF2\u751F\u6210\u5728 \`apps/backend/src/config/\` \u76EE\u5F55\u4E0B\u3002
|
|
1133
|
+
|
|
1134
|
+
## 4. \u73AF\u5883\u53D8\u91CF
|
|
1135
|
+
|
|
1136
|
+
\u8BF7\u590D\u5236 \`.env.example\` \u4E3A \`.env\` \u5E76\u586B\u5199\u76F8\u5E94\u7684\u914D\u7F6E\u503C\u3002
|
|
1137
|
+
`;
|
|
1138
|
+
const docPath = import_path3.default.join(targetPath, "apps/backend/FEATURE_INTEGRATION.md");
|
|
1139
|
+
await import_fs_extra5.default.writeFile(docPath, content);
|
|
1140
|
+
logger.warn("Generated manual integration guide: apps/backend/FEATURE_INTEGRATION.md");
|
|
911
1141
|
}
|
|
912
1142
|
|
|
913
1143
|
// src/commands/create.ts
|
|
@@ -922,7 +1152,7 @@ async function createProject(projectName, options = {}) {
|
|
|
922
1152
|
process.exit(1);
|
|
923
1153
|
}
|
|
924
1154
|
const projectPath = import_path4.default.resolve(process.cwd(), projectName);
|
|
925
|
-
if (await
|
|
1155
|
+
if (await import_fs_extra6.default.pathExists(projectPath)) {
|
|
926
1156
|
logger.error(`Directory ${projectName} already exists!`);
|
|
927
1157
|
process.exit(1);
|
|
928
1158
|
}
|
|
@@ -1055,7 +1285,7 @@ async function getTemplateDirectory() {
|
|
|
1055
1285
|
const cliPackageRoot = import_path4.default.dirname(__dirname);
|
|
1056
1286
|
const frameworkRoot = import_path4.default.dirname(import_path4.default.dirname(cliPackageRoot));
|
|
1057
1287
|
const localTemplateDir = import_path4.default.join(frameworkRoot, "templates");
|
|
1058
|
-
if (await
|
|
1288
|
+
if (await import_fs_extra6.default.pathExists(localTemplateDir)) {
|
|
1059
1289
|
logger.debug(`Using local template directory: ${localTemplateDir}`);
|
|
1060
1290
|
return localTemplateDir;
|
|
1061
1291
|
}
|
|
@@ -1072,7 +1302,7 @@ async function createProjectFromTemplate(config) {
|
|
|
1072
1302
|
const spinner = (0, import_ora.default)("Creating project...").start();
|
|
1073
1303
|
let templateDirToCleanup = null;
|
|
1074
1304
|
try {
|
|
1075
|
-
await
|
|
1305
|
+
await import_fs_extra6.default.ensureDir(config.projectPath);
|
|
1076
1306
|
process.chdir(config.projectPath);
|
|
1077
1307
|
spinner.text = "Generating project files...";
|
|
1078
1308
|
await generateFromTemplate(config);
|
|
@@ -1115,7 +1345,7 @@ async function createProjectFromTemplate(config) {
|
|
|
1115
1345
|
}
|
|
1116
1346
|
|
|
1117
1347
|
// package.json
|
|
1118
|
-
var version = "1.
|
|
1348
|
+
var version = "1.4.0";
|
|
1119
1349
|
|
|
1120
1350
|
// src/index.ts
|
|
1121
1351
|
async function cli() {
|
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
5
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
-
});
|
|
2
|
+
import {
|
|
3
|
+
__require
|
|
4
|
+
} from "./chunk-Y6FXYEAI.mjs";
|
|
8
5
|
|
|
9
6
|
// src/index.ts
|
|
10
7
|
import { Command } from "commander";
|
|
@@ -702,21 +699,53 @@ function collectEnvVars(features, config) {
|
|
|
702
699
|
}
|
|
703
700
|
async function generateEnvExample(features, config, targetPath) {
|
|
704
701
|
const envVars = collectEnvVars(features, config);
|
|
702
|
+
if (envVars.length === 0) {
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
705
|
const content = [
|
|
706
|
+
"# ========================================",
|
|
706
707
|
"# Environment Variables",
|
|
708
|
+
"# ========================================",
|
|
707
709
|
"# Copy this file to .env and fill in the values",
|
|
710
|
+
"#",
|
|
711
|
+
"# IMPORTANT: Never commit .env file to version control!",
|
|
712
|
+
"# Add .env to your .gitignore file",
|
|
713
|
+
"#",
|
|
714
|
+
"",
|
|
715
|
+
"# ========================================",
|
|
716
|
+
"# Application Configuration",
|
|
717
|
+
"# ========================================",
|
|
718
|
+
"NODE_ENV=development",
|
|
719
|
+
"PORT=3000",
|
|
708
720
|
"",
|
|
709
|
-
|
|
710
|
-
|
|
721
|
+
"# ========================================",
|
|
722
|
+
"# Database Configuration",
|
|
723
|
+
"# ========================================",
|
|
724
|
+
"DATABASE_URL=mysql://root:root123456@localhost:3306/{{PROJECT_NAME}}",
|
|
725
|
+
""
|
|
726
|
+
];
|
|
727
|
+
const featureGroups = {};
|
|
728
|
+
for (const featureKey of features) {
|
|
729
|
+
const feature = config.features[featureKey];
|
|
730
|
+
if (feature && feature.envVars.length > 0) {
|
|
731
|
+
featureGroups[feature.name] = feature.envVars;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
for (const [featureName, vars] of Object.entries(featureGroups)) {
|
|
735
|
+
content.push("# ========================================");
|
|
736
|
+
content.push(`# ${featureName} Configuration`);
|
|
737
|
+
content.push("# ========================================");
|
|
738
|
+
for (const envVar of vars) {
|
|
711
739
|
if (envVar.description) {
|
|
712
|
-
|
|
740
|
+
content.push(`# ${envVar.description}`);
|
|
713
741
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
await fs4.
|
|
742
|
+
content.push(`${envVar.key}=${envVar.default}`);
|
|
743
|
+
content.push("");
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
const envPath = path3.join(targetPath, "apps/backend/.env.example");
|
|
747
|
+
await fs4.ensureDir(path3.dirname(envPath));
|
|
748
|
+
await fs4.writeFile(envPath, content.join("\n"));
|
|
720
749
|
logger.info("Generated .env.example");
|
|
721
750
|
}
|
|
722
751
|
async function copyConfigFiles(features, config, templateDir, targetPath) {
|
|
@@ -832,13 +861,23 @@ async function updatePackageJson(features, config, targetPath) {
|
|
|
832
861
|
}
|
|
833
862
|
function generateModuleImports(features, config) {
|
|
834
863
|
const imports = [];
|
|
864
|
+
const seen = /* @__PURE__ */ new Set();
|
|
835
865
|
for (const featureKey of features) {
|
|
836
866
|
const feature = config.features[featureKey];
|
|
837
867
|
if (feature && feature.moduleImports) {
|
|
838
868
|
for (const moduleImport of feature.moduleImports) {
|
|
839
|
-
|
|
869
|
+
const importKey = `${moduleImport.from}:${moduleImport.import}`;
|
|
870
|
+
if (!seen.has(importKey)) {
|
|
871
|
+
imports.push(`import { ${moduleImport.import} } from '${moduleImport.from}';`);
|
|
872
|
+
seen.add(importKey);
|
|
873
|
+
}
|
|
840
874
|
}
|
|
841
875
|
}
|
|
876
|
+
if (feature && feature.configFiles && feature.configFiles.length > 0) {
|
|
877
|
+
const configFileName = path3.basename(feature.configFiles[0].path, ".ts");
|
|
878
|
+
const configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
|
|
879
|
+
imports.push(`import { ${configFunctionName} } from './config/${configFileName}';`);
|
|
880
|
+
}
|
|
842
881
|
}
|
|
843
882
|
return imports.join("\n");
|
|
844
883
|
}
|
|
@@ -847,40 +886,114 @@ function generateModuleRegistrations(features, config) {
|
|
|
847
886
|
for (const featureKey of features) {
|
|
848
887
|
const feature = config.features[featureKey];
|
|
849
888
|
if (feature && feature.moduleRegistration) {
|
|
850
|
-
const { module: moduleName,
|
|
851
|
-
|
|
852
|
-
|
|
889
|
+
const { module: moduleName, type: registrationType } = feature.moduleRegistration;
|
|
890
|
+
const configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
|
|
891
|
+
registrations.push(` ${moduleName}.${registrationType}({
|
|
892
|
+
imports: [ConfigModule],
|
|
853
893
|
inject: [ConfigService],
|
|
894
|
+
useFactory: (configService: ConfigService) => ${configFunctionName}(configService),
|
|
854
895
|
}),`);
|
|
855
896
|
}
|
|
856
897
|
}
|
|
857
898
|
return registrations.join("\n");
|
|
858
899
|
}
|
|
859
900
|
async function updateAppModule(features, config, targetPath) {
|
|
901
|
+
if (features.length === 0) {
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
860
904
|
const appModulePath = path3.join(targetPath, "apps/backend/src/app.module.ts");
|
|
861
905
|
if (!await fs4.pathExists(appModulePath)) {
|
|
862
906
|
logger.warn("app.module.ts not found, skipping module injection");
|
|
863
907
|
return;
|
|
864
908
|
}
|
|
865
|
-
|
|
909
|
+
try {
|
|
910
|
+
const imports = [];
|
|
911
|
+
const moduleExpressions = [];
|
|
912
|
+
const needsConfigService = features.some((key) => {
|
|
913
|
+
const feature = config.features[key];
|
|
914
|
+
return feature && feature.moduleRegistration;
|
|
915
|
+
});
|
|
916
|
+
if (needsConfigService) {
|
|
917
|
+
}
|
|
918
|
+
for (const featureKey of features) {
|
|
919
|
+
const feature = config.features[featureKey];
|
|
920
|
+
if (!feature) continue;
|
|
921
|
+
if (feature.moduleImports) {
|
|
922
|
+
for (const moduleImport of feature.moduleImports) {
|
|
923
|
+
imports.push({
|
|
924
|
+
from: moduleImport.from,
|
|
925
|
+
imports: [moduleImport.import]
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
if (feature.configFiles && feature.configFiles.length > 0) {
|
|
930
|
+
const configFileName = path3.basename(feature.configFiles[0].path, ".ts");
|
|
931
|
+
const configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
|
|
932
|
+
imports.push({
|
|
933
|
+
from: `./config/${configFileName}`,
|
|
934
|
+
imports: [configFunctionName]
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
if (feature.moduleRegistration) {
|
|
938
|
+
const { module: moduleName, type: registrationType } = feature.moduleRegistration;
|
|
939
|
+
const configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
|
|
940
|
+
const moduleExpression = `${moduleName}.${registrationType}({
|
|
941
|
+
imports: [ConfigModule],
|
|
942
|
+
inject: [ConfigService],
|
|
943
|
+
useFactory: (configService: ConfigService) => ${configFunctionName}(configService),
|
|
944
|
+
})`;
|
|
945
|
+
moduleExpressions.push(moduleExpression);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
const { updateAppModuleFile } = await import("./ast-helper-5I5LPFKU.mjs");
|
|
949
|
+
await updateAppModuleFile(appModulePath, imports, moduleExpressions);
|
|
950
|
+
logger.info("Successfully updated app.module.ts with feature modules");
|
|
951
|
+
} catch (error) {
|
|
952
|
+
logger.error(`Failed to update app.module.ts: ${error instanceof Error ? error.message : String(error)}`);
|
|
953
|
+
await generateManualIntegrationGuide(features, config, targetPath);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
async function generateManualIntegrationGuide(features, config, targetPath) {
|
|
866
957
|
const imports = generateModuleImports(features, config);
|
|
867
958
|
const registrations = generateModuleRegistrations(features, config);
|
|
868
|
-
const
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
959
|
+
const content = `# \u529F\u80FD\u6A21\u5757\u96C6\u6210\u8BF4\u660E
|
|
960
|
+
|
|
961
|
+
\u26A0\uFE0F \u81EA\u52A8\u96C6\u6210\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A
|
|
962
|
+
|
|
963
|
+
## 1. \u6DFB\u52A0\u5BFC\u5165\u8BED\u53E5
|
|
964
|
+
|
|
965
|
+
\u5728 \`apps/backend/src/app.module.ts\` \u6587\u4EF6\u9876\u90E8\u6DFB\u52A0\u4EE5\u4E0B\u5BFC\u5165\uFF1A
|
|
966
|
+
|
|
967
|
+
\`\`\`typescript
|
|
968
|
+
${imports}
|
|
969
|
+
\`\`\`
|
|
970
|
+
|
|
971
|
+
## 2. \u6CE8\u518C\u6A21\u5757
|
|
972
|
+
|
|
973
|
+
\u5728 \`@Module\` \u88C5\u9970\u5668\u7684 \`imports\` \u6570\u7EC4\u4E2D\u6DFB\u52A0\u4EE5\u4E0B\u6A21\u5757\uFF1A
|
|
974
|
+
|
|
975
|
+
\`\`\`typescript
|
|
976
|
+
@Module({
|
|
977
|
+
imports: [
|
|
978
|
+
// ... \u5176\u4ED6\u6A21\u5757
|
|
979
|
+
${registrations}
|
|
980
|
+
],
|
|
981
|
+
// ...
|
|
982
|
+
})
|
|
983
|
+
export class AppModule {}
|
|
984
|
+
\`\`\`
|
|
985
|
+
|
|
986
|
+
## 3. \u914D\u7F6E\u6587\u4EF6
|
|
987
|
+
|
|
988
|
+
\u6BCF\u4E2A\u529F\u80FD\u7684\u914D\u7F6E\u6587\u4EF6\u5DF2\u751F\u6210\u5728 \`apps/backend/src/config/\` \u76EE\u5F55\u4E0B\u3002
|
|
989
|
+
|
|
990
|
+
## 4. \u73AF\u5883\u53D8\u91CF
|
|
991
|
+
|
|
992
|
+
\u8BF7\u590D\u5236 \`.env.example\` \u4E3A \`.env\` \u5E76\u586B\u5199\u76F8\u5E94\u7684\u914D\u7F6E\u503C\u3002
|
|
993
|
+
`;
|
|
994
|
+
const docPath = path3.join(targetPath, "apps/backend/FEATURE_INTEGRATION.md");
|
|
995
|
+
await fs4.writeFile(docPath, content);
|
|
996
|
+
logger.warn("Generated manual integration guide: apps/backend/FEATURE_INTEGRATION.md");
|
|
884
997
|
}
|
|
885
998
|
|
|
886
999
|
// src/commands/create.ts
|
|
@@ -1088,7 +1201,7 @@ async function createProjectFromTemplate(config) {
|
|
|
1088
1201
|
}
|
|
1089
1202
|
|
|
1090
1203
|
// package.json
|
|
1091
|
-
var version = "1.
|
|
1204
|
+
var version = "1.4.0";
|
|
1092
1205
|
|
|
1093
1206
|
// src/index.ts
|
|
1094
1207
|
async function cli() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@svton/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Svton CLI - Create full-stack applications with NestJS, Next.js, and Taro",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -47,16 +47,22 @@
|
|
|
47
47
|
"node": ">=18.0.0"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"
|
|
51
|
-
"
|
|
50
|
+
"@babel/generator": "^7.29.0",
|
|
51
|
+
"@babel/parser": "^7.29.0",
|
|
52
|
+
"@babel/traverse": "^7.29.0",
|
|
53
|
+
"@babel/types": "^7.29.0",
|
|
52
54
|
"chalk": "^5.3.0",
|
|
53
|
-
"
|
|
55
|
+
"commander": "^11.1.0",
|
|
54
56
|
"fs-extra": "^11.2.0",
|
|
57
|
+
"inquirer": "^9.2.12",
|
|
55
58
|
"mustache": "^4.2.0",
|
|
59
|
+
"ora": "^8.0.1",
|
|
56
60
|
"validate-npm-package-name": "^5.0.0"
|
|
57
61
|
},
|
|
58
62
|
"devDependencies": {
|
|
59
63
|
"@changesets/cli": "^2.29.8",
|
|
64
|
+
"@types/babel__generator": "^7.27.0",
|
|
65
|
+
"@types/babel__traverse": "^7.28.0",
|
|
60
66
|
"@types/fs-extra": "^11.0.4",
|
|
61
67
|
"@types/inquirer": "^9.0.7",
|
|
62
68
|
"@types/mustache": "^4.2.5",
|