@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.
@@ -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 = 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
- });
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
- const configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
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
- const configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
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
- const configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
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 = "1.4.0";
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
- const configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
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
- const configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
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
- const configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
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-5I5LPFKU.mjs");
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 = "1.4.0";
1241
+ var version = "2.0.0";
1205
1242
 
1206
1243
  // src/index.ts
1207
1244
  async function cli() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svton/cli",
3
- "version": "1.4.0",
3
+ "version": "2.0.0",
4
4
  "description": "Svton CLI - Create full-stack applications with NestJS, Next.js, and Taro",
5
5
  "keywords": [
6
6
  "cli",