@svton/cli 1.4.1 → 2.0.1
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-AGPOPMTY.mjs +124 -0
- package/dist/index.js +61 -7
- package/dist/index.mjs +37 -2
- package/package.json +1 -1
|
@@ -0,0 +1,124 @@
|
|
|
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
|
+
const existingImports = /* @__PURE__ */ new Map();
|
|
15
|
+
let lastImportIndex = -1;
|
|
16
|
+
traverse(ast, {
|
|
17
|
+
ImportDeclaration(path) {
|
|
18
|
+
const source = path.node.source.value;
|
|
19
|
+
const start = path.node.start;
|
|
20
|
+
if (start !== null && start !== void 0 && start > lastImportIndex) {
|
|
21
|
+
lastImportIndex = start;
|
|
22
|
+
}
|
|
23
|
+
if (!existingImports.has(source)) {
|
|
24
|
+
existingImports.set(source, /* @__PURE__ */ new Set());
|
|
25
|
+
}
|
|
26
|
+
const importSet = existingImports.get(source);
|
|
27
|
+
path.node.specifiers.forEach((spec) => {
|
|
28
|
+
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
|
|
29
|
+
importSet.add(spec.imported.name);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
const newImports = [];
|
|
35
|
+
for (const { from, imports } of importDeclarations) {
|
|
36
|
+
const existingSet = existingImports.get(from);
|
|
37
|
+
const newImportNames = existingSet ? imports.filter((imp) => !existingSet.has(imp)) : imports;
|
|
38
|
+
if (newImportNames.length > 0) {
|
|
39
|
+
const specifiers = newImportNames.map(
|
|
40
|
+
(imp) => t.importSpecifier(t.identifier(imp), t.identifier(imp))
|
|
41
|
+
);
|
|
42
|
+
newImports.push(t.importDeclaration(specifiers, t.stringLiteral(from)));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (newImports.length === 0) {
|
|
46
|
+
return code;
|
|
47
|
+
}
|
|
48
|
+
if (lastImportIndex >= 0) {
|
|
49
|
+
const program = ast.program;
|
|
50
|
+
const lastImportNode = program.body.find(
|
|
51
|
+
(node) => node.type === "ImportDeclaration" && node.start !== null && node.start === lastImportIndex
|
|
52
|
+
);
|
|
53
|
+
if (lastImportNode) {
|
|
54
|
+
const index = program.body.indexOf(lastImportNode);
|
|
55
|
+
program.body.splice(index + 1, 0, ...newImports);
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
ast.program.body.unshift(...newImports);
|
|
59
|
+
}
|
|
60
|
+
const output = generate(ast, {
|
|
61
|
+
retainLines: false,
|
|
62
|
+
compact: false
|
|
63
|
+
});
|
|
64
|
+
return output.code;
|
|
65
|
+
}
|
|
66
|
+
function addModuleImports(code, moduleExpressions) {
|
|
67
|
+
const ast = parser.parse(code, {
|
|
68
|
+
sourceType: "module",
|
|
69
|
+
plugins: ["typescript", "decorators-legacy"]
|
|
70
|
+
});
|
|
71
|
+
let modified = false;
|
|
72
|
+
traverse(ast, {
|
|
73
|
+
Decorator(path) {
|
|
74
|
+
if (t.isCallExpression(path.node.expression) && t.isIdentifier(path.node.expression.callee) && path.node.expression.callee.name === "Module") {
|
|
75
|
+
const args = path.node.expression.arguments;
|
|
76
|
+
if (args.length > 0 && t.isObjectExpression(args[0])) {
|
|
77
|
+
const moduleConfig = args[0];
|
|
78
|
+
const importsProperty = moduleConfig.properties.find(
|
|
79
|
+
(prop) => t.isObjectProperty(prop) && t.isIdentifier(prop.key) && prop.key.name === "imports"
|
|
80
|
+
);
|
|
81
|
+
if (importsProperty && t.isObjectProperty(importsProperty)) {
|
|
82
|
+
if (t.isArrayExpression(importsProperty.value)) {
|
|
83
|
+
for (const expr of moduleExpressions) {
|
|
84
|
+
try {
|
|
85
|
+
const exprAst = parser.parseExpression(expr, {
|
|
86
|
+
plugins: ["typescript"]
|
|
87
|
+
});
|
|
88
|
+
importsProperty.value.elements.push(exprAst);
|
|
89
|
+
modified = true;
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error(`Failed to parse expression: ${expr}`, error);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
if (!modified) {
|
|
101
|
+
console.warn("Could not find @Module decorator or imports array");
|
|
102
|
+
return code;
|
|
103
|
+
}
|
|
104
|
+
const output = generate(ast, {
|
|
105
|
+
retainLines: false,
|
|
106
|
+
compact: false
|
|
107
|
+
});
|
|
108
|
+
return output.code;
|
|
109
|
+
}
|
|
110
|
+
async function updateAppModuleFile(filePath, imports, moduleExpressions) {
|
|
111
|
+
let code = await fs.readFile(filePath, "utf-8");
|
|
112
|
+
if (imports.length > 0) {
|
|
113
|
+
code = addImportToFile(code, imports);
|
|
114
|
+
}
|
|
115
|
+
if (moduleExpressions.length > 0) {
|
|
116
|
+
code = addModuleImports(code, moduleExpressions);
|
|
117
|
+
}
|
|
118
|
+
await fs.writeFile(filePath, code, "utf-8");
|
|
119
|
+
}
|
|
120
|
+
export {
|
|
121
|
+
addImportToFile,
|
|
122
|
+
addModuleImports,
|
|
123
|
+
updateAppModuleFile
|
|
124
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -43,21 +43,40 @@ function addImportToFile(code, importDeclarations) {
|
|
|
43
43
|
sourceType: "module",
|
|
44
44
|
plugins: ["typescript", "decorators-legacy"]
|
|
45
45
|
});
|
|
46
|
+
const existingImports = /* @__PURE__ */ new Map();
|
|
46
47
|
let lastImportIndex = -1;
|
|
47
48
|
(0, import_traverse.default)(ast, {
|
|
48
49
|
ImportDeclaration(path5) {
|
|
50
|
+
const source = path5.node.source.value;
|
|
49
51
|
const start = path5.node.start;
|
|
50
52
|
if (start !== null && start !== void 0 && start > lastImportIndex) {
|
|
51
53
|
lastImportIndex = start;
|
|
52
54
|
}
|
|
55
|
+
if (!existingImports.has(source)) {
|
|
56
|
+
existingImports.set(source, /* @__PURE__ */ new Set());
|
|
57
|
+
}
|
|
58
|
+
const importSet = existingImports.get(source);
|
|
59
|
+
path5.node.specifiers.forEach((spec) => {
|
|
60
|
+
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported)) {
|
|
61
|
+
importSet.add(spec.imported.name);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
53
64
|
}
|
|
54
65
|
});
|
|
55
|
-
const newImports =
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
|
|
66
|
+
const newImports = [];
|
|
67
|
+
for (const { from, imports } of importDeclarations) {
|
|
68
|
+
const existingSet = existingImports.get(from);
|
|
69
|
+
const newImportNames = existingSet ? imports.filter((imp) => !existingSet.has(imp)) : imports;
|
|
70
|
+
if (newImportNames.length > 0) {
|
|
71
|
+
const specifiers = newImportNames.map(
|
|
72
|
+
(imp) => t.importSpecifier(t.identifier(imp), t.identifier(imp))
|
|
73
|
+
);
|
|
74
|
+
newImports.push(t.importDeclaration(specifiers, t.stringLiteral(from)));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (newImports.length === 0) {
|
|
78
|
+
return code;
|
|
79
|
+
}
|
|
61
80
|
if (lastImportIndex >= 0) {
|
|
62
81
|
const program = ast.program;
|
|
63
82
|
const lastImportNode = program.body.find(
|
|
@@ -992,6 +1011,25 @@ ${featuresList}
|
|
|
992
1011
|
await import_fs_extra5.default.writeFile(indexPath, content);
|
|
993
1012
|
logger.info("Generated capabilities index");
|
|
994
1013
|
}
|
|
1014
|
+
async function copyPrismaTemplates(templateDir, targetPath) {
|
|
1015
|
+
const prismaTemplatesDir = import_path3.default.join(templateDir, "apps/backend/prisma");
|
|
1016
|
+
const prismaDestDir = import_path3.default.join(targetPath, "apps/backend/prisma");
|
|
1017
|
+
if (await import_fs_extra5.default.pathExists(prismaTemplatesDir)) {
|
|
1018
|
+
await import_fs_extra5.default.ensureDir(prismaDestDir);
|
|
1019
|
+
await import_fs_extra5.default.copy(prismaTemplatesDir, prismaDestDir);
|
|
1020
|
+
const files = await import_fs_extra5.default.readdir(prismaDestDir);
|
|
1021
|
+
for (const file of files) {
|
|
1022
|
+
if (file.endsWith(".tpl")) {
|
|
1023
|
+
const filePath = import_path3.default.join(prismaDestDir, file);
|
|
1024
|
+
const newPath = filePath.replace(/\.tpl$/, "");
|
|
1025
|
+
await import_fs_extra5.default.rename(filePath, newPath);
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
logger.info("Copied Prisma templates");
|
|
1029
|
+
} else {
|
|
1030
|
+
logger.warn(`Prisma templates not found: ${prismaTemplatesDir}`);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
995
1033
|
async function updatePackageJson(features, config, targetPath) {
|
|
996
1034
|
const packageJsonPath = import_path3.default.join(targetPath, "apps/backend/package.json");
|
|
997
1035
|
const packageJson = await import_fs_extra5.default.readJSON(packageJsonPath);
|
|
@@ -1335,6 +1373,9 @@ async function createProjectFromTemplate(config) {
|
|
|
1335
1373
|
await copyConfigFiles(config.features, featuresConfig, templateDir, config.projectPath);
|
|
1336
1374
|
await copyExampleFiles(config.features, featuresConfig, templateDir, config.projectPath);
|
|
1337
1375
|
await copySkillFiles(config.features, featuresConfig, templateDir, config.projectPath);
|
|
1376
|
+
if (config.template === "backend-only" || config.template === "full-stack") {
|
|
1377
|
+
await copyPrismaTemplates(templateDir, config.projectPath);
|
|
1378
|
+
}
|
|
1338
1379
|
await generateEnvExample(config.features, featuresConfig, config.projectPath);
|
|
1339
1380
|
if (config.template === "backend-only" || config.template === "full-stack") {
|
|
1340
1381
|
await updateAppModule(config.features, featuresConfig, config.projectPath);
|
|
@@ -1343,6 +1384,19 @@ async function createProjectFromTemplate(config) {
|
|
|
1343
1384
|
if (config.installDeps) {
|
|
1344
1385
|
spinner.text = "Installing dependencies...";
|
|
1345
1386
|
await installDependencies(config.packageManager);
|
|
1387
|
+
if (config.template === "backend-only" || config.template === "full-stack") {
|
|
1388
|
+
spinner.text = "Generating Prisma client...";
|
|
1389
|
+
try {
|
|
1390
|
+
const { execSync: execSync4 } = require("child_process");
|
|
1391
|
+
execSync4(`${config.packageManager} --filter=backend prisma:generate`, {
|
|
1392
|
+
cwd: config.projectPath,
|
|
1393
|
+
stdio: "inherit"
|
|
1394
|
+
});
|
|
1395
|
+
logger.info("Prisma client generated successfully");
|
|
1396
|
+
} catch (error) {
|
|
1397
|
+
logger.warn('Failed to generate Prisma client. Please run "pnpm --filter=backend prisma:generate" manually.');
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1346
1400
|
}
|
|
1347
1401
|
if (config.initGit) {
|
|
1348
1402
|
spinner.text = "Initializing Git repository...";
|
|
@@ -1360,7 +1414,7 @@ async function createProjectFromTemplate(config) {
|
|
|
1360
1414
|
}
|
|
1361
1415
|
|
|
1362
1416
|
// package.json
|
|
1363
|
-
var version = "
|
|
1417
|
+
var version = "2.0.1";
|
|
1364
1418
|
|
|
1365
1419
|
// src/index.ts
|
|
1366
1420
|
async function cli() {
|
package/dist/index.mjs
CHANGED
|
@@ -848,6 +848,25 @@ ${featuresList}
|
|
|
848
848
|
await fs4.writeFile(indexPath, content);
|
|
849
849
|
logger.info("Generated capabilities index");
|
|
850
850
|
}
|
|
851
|
+
async function copyPrismaTemplates(templateDir, targetPath) {
|
|
852
|
+
const prismaTemplatesDir = path3.join(templateDir, "apps/backend/prisma");
|
|
853
|
+
const prismaDestDir = path3.join(targetPath, "apps/backend/prisma");
|
|
854
|
+
if (await fs4.pathExists(prismaTemplatesDir)) {
|
|
855
|
+
await fs4.ensureDir(prismaDestDir);
|
|
856
|
+
await fs4.copy(prismaTemplatesDir, prismaDestDir);
|
|
857
|
+
const files = await fs4.readdir(prismaDestDir);
|
|
858
|
+
for (const file of files) {
|
|
859
|
+
if (file.endsWith(".tpl")) {
|
|
860
|
+
const filePath = path3.join(prismaDestDir, file);
|
|
861
|
+
const newPath = filePath.replace(/\.tpl$/, "");
|
|
862
|
+
await fs4.rename(filePath, newPath);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
logger.info("Copied Prisma templates");
|
|
866
|
+
} else {
|
|
867
|
+
logger.warn(`Prisma templates not found: ${prismaTemplatesDir}`);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
851
870
|
async function updatePackageJson(features, config, targetPath) {
|
|
852
871
|
const packageJsonPath = path3.join(targetPath, "apps/backend/package.json");
|
|
853
872
|
const packageJson = await fs4.readJSON(packageJsonPath);
|
|
@@ -960,7 +979,7 @@ async function updateAppModule(features, config, targetPath) {
|
|
|
960
979
|
moduleExpressions.push(moduleExpression);
|
|
961
980
|
}
|
|
962
981
|
}
|
|
963
|
-
const { updateAppModuleFile } = await import("./ast-helper-
|
|
982
|
+
const { updateAppModuleFile } = await import("./ast-helper-AGPOPMTY.mjs");
|
|
964
983
|
await updateAppModuleFile(appModulePath, imports, moduleExpressions);
|
|
965
984
|
logger.info("Successfully updated app.module.ts with feature modules");
|
|
966
985
|
} catch (error) {
|
|
@@ -1191,6 +1210,9 @@ async function createProjectFromTemplate(config) {
|
|
|
1191
1210
|
await copyConfigFiles(config.features, featuresConfig, templateDir, config.projectPath);
|
|
1192
1211
|
await copyExampleFiles(config.features, featuresConfig, templateDir, config.projectPath);
|
|
1193
1212
|
await copySkillFiles(config.features, featuresConfig, templateDir, config.projectPath);
|
|
1213
|
+
if (config.template === "backend-only" || config.template === "full-stack") {
|
|
1214
|
+
await copyPrismaTemplates(templateDir, config.projectPath);
|
|
1215
|
+
}
|
|
1194
1216
|
await generateEnvExample(config.features, featuresConfig, config.projectPath);
|
|
1195
1217
|
if (config.template === "backend-only" || config.template === "full-stack") {
|
|
1196
1218
|
await updateAppModule(config.features, featuresConfig, config.projectPath);
|
|
@@ -1199,6 +1221,19 @@ async function createProjectFromTemplate(config) {
|
|
|
1199
1221
|
if (config.installDeps) {
|
|
1200
1222
|
spinner.text = "Installing dependencies...";
|
|
1201
1223
|
await installDependencies(config.packageManager);
|
|
1224
|
+
if (config.template === "backend-only" || config.template === "full-stack") {
|
|
1225
|
+
spinner.text = "Generating Prisma client...";
|
|
1226
|
+
try {
|
|
1227
|
+
const { execSync: execSync4 } = __require("child_process");
|
|
1228
|
+
execSync4(`${config.packageManager} --filter=backend prisma:generate`, {
|
|
1229
|
+
cwd: config.projectPath,
|
|
1230
|
+
stdio: "inherit"
|
|
1231
|
+
});
|
|
1232
|
+
logger.info("Prisma client generated successfully");
|
|
1233
|
+
} catch (error) {
|
|
1234
|
+
logger.warn('Failed to generate Prisma client. Please run "pnpm --filter=backend prisma:generate" manually.');
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1202
1237
|
}
|
|
1203
1238
|
if (config.initGit) {
|
|
1204
1239
|
spinner.text = "Initializing Git repository...";
|
|
@@ -1216,7 +1251,7 @@ async function createProjectFromTemplate(config) {
|
|
|
1216
1251
|
}
|
|
1217
1252
|
|
|
1218
1253
|
// package.json
|
|
1219
|
-
var version = "
|
|
1254
|
+
var version = "2.0.1";
|
|
1220
1255
|
|
|
1221
1256
|
// src/index.ts
|
|
1222
1257
|
async function cli() {
|