@svton/cli 1.4.0 → 2.0.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-AGPOPMTY.mjs +124 -0
- package/dist/index.js +66 -10
- package/dist/index.mjs +42 -5
- 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);
|
|
@@ -1031,7 +1069,12 @@ function generateModuleRegistrations(features, config) {
|
|
|
1031
1069
|
const feature = config.features[featureKey];
|
|
1032
1070
|
if (feature && feature.moduleRegistration) {
|
|
1033
1071
|
const { module: moduleName, type: registrationType } = feature.moduleRegistration;
|
|
1034
|
-
|
|
1072
|
+
let configFunctionName;
|
|
1073
|
+
if (featureKey === "oauth") {
|
|
1074
|
+
configFunctionName = "useOAuthConfig";
|
|
1075
|
+
} else {
|
|
1076
|
+
configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
|
|
1077
|
+
}
|
|
1035
1078
|
registrations.push(` ${moduleName}.${registrationType}({
|
|
1036
1079
|
imports: [ConfigModule],
|
|
1037
1080
|
inject: [ConfigService],
|
|
@@ -1072,7 +1115,12 @@ async function updateAppModule(features, config, targetPath) {
|
|
|
1072
1115
|
}
|
|
1073
1116
|
if (feature.configFiles && feature.configFiles.length > 0) {
|
|
1074
1117
|
const configFileName = import_path3.default.basename(feature.configFiles[0].path, ".ts");
|
|
1075
|
-
|
|
1118
|
+
let configFunctionName;
|
|
1119
|
+
if (featureKey === "oauth") {
|
|
1120
|
+
configFunctionName = "useOAuthConfig";
|
|
1121
|
+
} else {
|
|
1122
|
+
configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
|
|
1123
|
+
}
|
|
1076
1124
|
imports.push({
|
|
1077
1125
|
from: `./config/${configFileName}`,
|
|
1078
1126
|
imports: [configFunctionName]
|
|
@@ -1080,7 +1128,12 @@ async function updateAppModule(features, config, targetPath) {
|
|
|
1080
1128
|
}
|
|
1081
1129
|
if (feature.moduleRegistration) {
|
|
1082
1130
|
const { module: moduleName, type: registrationType } = feature.moduleRegistration;
|
|
1083
|
-
|
|
1131
|
+
let configFunctionName;
|
|
1132
|
+
if (featureKey === "oauth") {
|
|
1133
|
+
configFunctionName = "useOAuthConfig";
|
|
1134
|
+
} else {
|
|
1135
|
+
configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
|
|
1136
|
+
}
|
|
1084
1137
|
const moduleExpression = `${moduleName}.${registrationType}({
|
|
1085
1138
|
imports: [ConfigModule],
|
|
1086
1139
|
inject: [ConfigService],
|
|
@@ -1320,6 +1373,9 @@ async function createProjectFromTemplate(config) {
|
|
|
1320
1373
|
await copyConfigFiles(config.features, featuresConfig, templateDir, config.projectPath);
|
|
1321
1374
|
await copyExampleFiles(config.features, featuresConfig, templateDir, config.projectPath);
|
|
1322
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
|
+
}
|
|
1323
1379
|
await generateEnvExample(config.features, featuresConfig, config.projectPath);
|
|
1324
1380
|
if (config.template === "backend-only" || config.template === "full-stack") {
|
|
1325
1381
|
await updateAppModule(config.features, featuresConfig, config.projectPath);
|
|
@@ -1345,7 +1401,7 @@ async function createProjectFromTemplate(config) {
|
|
|
1345
1401
|
}
|
|
1346
1402
|
|
|
1347
1403
|
// package.json
|
|
1348
|
-
var version = "
|
|
1404
|
+
var version = "2.0.0";
|
|
1349
1405
|
|
|
1350
1406
|
// src/index.ts
|
|
1351
1407
|
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);
|
|
@@ -887,7 +906,12 @@ function generateModuleRegistrations(features, config) {
|
|
|
887
906
|
const feature = config.features[featureKey];
|
|
888
907
|
if (feature && feature.moduleRegistration) {
|
|
889
908
|
const { module: moduleName, type: registrationType } = feature.moduleRegistration;
|
|
890
|
-
|
|
909
|
+
let configFunctionName;
|
|
910
|
+
if (featureKey === "oauth") {
|
|
911
|
+
configFunctionName = "useOAuthConfig";
|
|
912
|
+
} else {
|
|
913
|
+
configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
|
|
914
|
+
}
|
|
891
915
|
registrations.push(` ${moduleName}.${registrationType}({
|
|
892
916
|
imports: [ConfigModule],
|
|
893
917
|
inject: [ConfigService],
|
|
@@ -928,7 +952,12 @@ async function updateAppModule(features, config, targetPath) {
|
|
|
928
952
|
}
|
|
929
953
|
if (feature.configFiles && feature.configFiles.length > 0) {
|
|
930
954
|
const configFileName = path3.basename(feature.configFiles[0].path, ".ts");
|
|
931
|
-
|
|
955
|
+
let configFunctionName;
|
|
956
|
+
if (featureKey === "oauth") {
|
|
957
|
+
configFunctionName = "useOAuthConfig";
|
|
958
|
+
} else {
|
|
959
|
+
configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
|
|
960
|
+
}
|
|
932
961
|
imports.push({
|
|
933
962
|
from: `./config/${configFileName}`,
|
|
934
963
|
imports: [configFunctionName]
|
|
@@ -936,7 +965,12 @@ async function updateAppModule(features, config, targetPath) {
|
|
|
936
965
|
}
|
|
937
966
|
if (feature.moduleRegistration) {
|
|
938
967
|
const { module: moduleName, type: registrationType } = feature.moduleRegistration;
|
|
939
|
-
|
|
968
|
+
let configFunctionName;
|
|
969
|
+
if (featureKey === "oauth") {
|
|
970
|
+
configFunctionName = "useOAuthConfig";
|
|
971
|
+
} else {
|
|
972
|
+
configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
|
|
973
|
+
}
|
|
940
974
|
const moduleExpression = `${moduleName}.${registrationType}({
|
|
941
975
|
imports: [ConfigModule],
|
|
942
976
|
inject: [ConfigService],
|
|
@@ -945,7 +979,7 @@ async function updateAppModule(features, config, targetPath) {
|
|
|
945
979
|
moduleExpressions.push(moduleExpression);
|
|
946
980
|
}
|
|
947
981
|
}
|
|
948
|
-
const { updateAppModuleFile } = await import("./ast-helper-
|
|
982
|
+
const { updateAppModuleFile } = await import("./ast-helper-AGPOPMTY.mjs");
|
|
949
983
|
await updateAppModuleFile(appModulePath, imports, moduleExpressions);
|
|
950
984
|
logger.info("Successfully updated app.module.ts with feature modules");
|
|
951
985
|
} catch (error) {
|
|
@@ -1176,6 +1210,9 @@ async function createProjectFromTemplate(config) {
|
|
|
1176
1210
|
await copyConfigFiles(config.features, featuresConfig, templateDir, config.projectPath);
|
|
1177
1211
|
await copyExampleFiles(config.features, featuresConfig, templateDir, config.projectPath);
|
|
1178
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
|
+
}
|
|
1179
1216
|
await generateEnvExample(config.features, featuresConfig, config.projectPath);
|
|
1180
1217
|
if (config.template === "backend-only" || config.template === "full-stack") {
|
|
1181
1218
|
await updateAppModule(config.features, featuresConfig, config.projectPath);
|
|
@@ -1201,7 +1238,7 @@ async function createProjectFromTemplate(config) {
|
|
|
1201
1238
|
}
|
|
1202
1239
|
|
|
1203
1240
|
// package.json
|
|
1204
|
-
var version = "
|
|
1241
|
+
var version = "2.0.0";
|
|
1205
1242
|
|
|
1206
1243
|
// src/index.ts
|
|
1207
1244
|
async function cli() {
|