stackkit 0.1.4 → 0.1.5

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/README.md CHANGED
@@ -40,4 +40,4 @@ npx stackkit doctor
40
40
  ## Documentation
41
41
 
42
42
  - [StackKit Docs](https://stackkit.tariqul.dev)
43
- - [GitHub Repository](https://github.com/tariqul420/stackkit)
43
+ - [GitHub Repository](https://github.com/tariqul420/stackkit)
package/dist/cli/add.js CHANGED
@@ -43,12 +43,13 @@ async function addCommand(module, options) {
43
43
  }
44
44
  }
45
45
  async function getAddConfig(module, options, projectInfo) {
46
- const modulesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), 'modules');
46
+ const modulesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), "modules");
47
47
  const argv = process.argv.slice(2);
48
- const addIndex = argv.indexOf('add');
48
+ const addIndex = argv.indexOf("add");
49
49
  const argsAfterAdd = addIndex >= 0 ? argv.slice(addIndex + 1) : [];
50
- const flagsProvided = argsAfterAdd.some(arg => arg.startsWith('-'));
51
- const optionsProvided = flagsProvided || !!(options && (options.yes || options.provider || options.force || options.dryRun));
50
+ const flagsProvided = argsAfterAdd.some((arg) => arg.startsWith("-"));
51
+ const optionsProvided = flagsProvided ||
52
+ !!(options && (options.yes || options.provider || options.force || options.dryRun));
52
53
  if (optionsProvided) {
53
54
  if (!module) {
54
55
  throw new Error("Module name is required when using flags");
@@ -60,8 +61,8 @@ async function getAddConfig(module, options, projectInfo) {
60
61
  }
61
62
  let baseProvider = options.provider;
62
63
  let adapterProvider = options.provider;
63
- if (options.provider.includes('-')) {
64
- const parts = options.provider.split('-');
64
+ if (options.provider.includes("-")) {
65
+ const parts = options.provider.split("-");
65
66
  baseProvider = parts[0]; // e.g., "prisma"
66
67
  adapterProvider = options.provider; // e.g., "prisma-postgresql"
67
68
  }
@@ -72,7 +73,7 @@ async function getAddConfig(module, options, projectInfo) {
72
73
  return {
73
74
  module: "database",
74
75
  provider: adapterProvider,
75
- displayName: `${moduleMetadata.displayName} (${adapterProvider.split('-')[1] || adapterProvider})`,
76
+ displayName: `${moduleMetadata.displayName} (${adapterProvider.split("-")[1] || adapterProvider})`,
76
77
  metadata: moduleMetadata,
77
78
  };
78
79
  }
@@ -99,7 +100,8 @@ async function getAddConfig(module, options, projectInfo) {
99
100
  selectedProvider = module;
100
101
  }
101
102
  if (moduleMetadata.category === "database" && !selectedProvider) {
102
- if (typeof moduleMetadata.dependencies === "object" && "providers" in moduleMetadata.dependencies) {
103
+ if (typeof moduleMetadata.dependencies === "object" &&
104
+ "providers" in moduleMetadata.dependencies) {
103
105
  const providers = Object.keys(moduleMetadata.dependencies.providers || {});
104
106
  if (providers.length > 0) {
105
107
  const { provider } = await inquirer_1.default.prompt([
@@ -167,7 +169,7 @@ async function getAddConfig(module, options, projectInfo) {
167
169
  module: "database",
168
170
  provider: "prisma",
169
171
  displayName: `Prisma (${providerAnswers.provider})`,
170
- metadata: await loadModuleMetadata(modulesDir, "prisma", "prisma"),
172
+ metadata: (await loadModuleMetadata(modulesDir, "prisma", "prisma")),
171
173
  };
172
174
  }
173
175
  else {
@@ -175,7 +177,7 @@ async function getAddConfig(module, options, projectInfo) {
175
177
  module: "database",
176
178
  provider: "mongoose",
177
179
  displayName: "Mongoose",
178
- metadata: await loadModuleMetadata(modulesDir, "mongoose", "mongoose"),
180
+ metadata: (await loadModuleMetadata(modulesDir, "mongoose", "mongoose")),
179
181
  };
180
182
  }
181
183
  }
@@ -230,20 +232,26 @@ async function addModuleToProject(projectRoot, projectInfo, config, options) {
230
232
  logger_1.logger.warn("Dry run mode - no changes will be made");
231
233
  logger_1.logger.newLine();
232
234
  }
233
- const moduleBasePath = await findModulePath(path_1.default.join((0, package_root_1.getPackageRoot)(), 'modules'), config.module, config.provider);
235
+ const moduleBasePath = await findModulePath(path_1.default.join((0, package_root_1.getPackageRoot)(), "modules"), config.module, config.provider);
234
236
  if (moduleBasePath) {
235
- const frameworkConfig = await framework_utils_1.FrameworkUtils.loadFrameworkConfig(projectInfo.framework, path_1.default.join((0, package_root_1.getPackageRoot)(), 'templates'));
237
+ const frameworkConfig = await framework_utils_1.FrameworkUtils.loadFrameworkConfig(projectInfo.framework, path_1.default.join((0, package_root_1.getPackageRoot)(), "templates"));
236
238
  const gen = new code_generator_1.AdvancedCodeGenerator(frameworkConfig);
237
- await gen.loadGenerators(path_1.default.join((0, package_root_1.getPackageRoot)(), 'modules'));
239
+ await gen.loadGenerators(path_1.default.join((0, package_root_1.getPackageRoot)(), "modules"));
238
240
  const moduleName = path_1.default.basename(moduleBasePath);
239
241
  const available = gen.getAvailableGenerators();
240
- const alreadyRegistered = (config.module === 'database' && available.databases.includes(moduleName)) || (config.module === 'auth' && available.auths.includes(moduleName));
242
+ const alreadyRegistered = (config.module === "database" && available.databases.includes(moduleName)) ||
243
+ (config.module === "auth" && available.auths.includes(moduleName));
241
244
  if (!alreadyRegistered) {
242
245
  const ops = [];
243
246
  if (Array.isArray(moduleMetadata.patches)) {
244
247
  for (const p of moduleMetadata.patches) {
245
- if (p.type === 'create-file') {
246
- ops.push({ type: 'create-file', source: p.source, destination: p.destination, condition: p.condition });
248
+ if (p.type === "create-file") {
249
+ ops.push({
250
+ type: "create-file",
251
+ source: p.source,
252
+ destination: p.destination,
253
+ condition: p.condition,
254
+ });
247
255
  }
248
256
  }
249
257
  }
@@ -258,40 +266,40 @@ async function addModuleToProject(projectRoot, projectInfo, config, options) {
258
266
  }
259
267
  }
260
268
  const selectedModules = { framework: projectInfo.framework };
261
- if (config.module === 'database' && config.provider) {
262
- if (config.provider.startsWith('prisma-')) {
263
- selectedModules.database = 'prisma';
264
- selectedModules.prismaProvider = config.provider.split('-')[1];
269
+ if (config.module === "database" && config.provider) {
270
+ if (config.provider.startsWith("prisma-")) {
271
+ selectedModules.database = "prisma";
272
+ selectedModules.prismaProvider = config.provider.split("-")[1];
265
273
  }
266
274
  else {
267
275
  selectedModules.database = config.provider;
268
276
  }
269
277
  }
270
- if (config.module === 'auth' && config.provider) {
278
+ if (config.module === "auth" && config.provider) {
271
279
  selectedModules.auth = config.provider;
272
280
  }
273
281
  const postInstall = await gen.applyToProject(selectedModules, [], projectRoot);
274
282
  if (postInstall && postInstall.length > 0 && !options?.dryRun) {
275
- const postInstallSpinner = logger_1.logger.startSpinner('Running post-install commands...');
283
+ const postInstallSpinner = logger_1.logger.startSpinner("Running post-install commands...");
276
284
  try {
277
285
  for (const command of postInstall) {
278
- (0, child_process_1.execSync)(command, { cwd: projectRoot, stdio: 'pipe' });
286
+ (0, child_process_1.execSync)(command, { cwd: projectRoot, stdio: "pipe" });
279
287
  }
280
- postInstallSpinner.succeed('Post-install commands completed');
288
+ postInstallSpinner.succeed("Post-install commands completed");
281
289
  }
282
290
  catch (error) {
283
- postInstallSpinner.fail('Failed to run post-install commands');
291
+ postInstallSpinner.fail("Failed to run post-install commands");
284
292
  throw error;
285
293
  }
286
294
  }
287
295
  if (!options?.dryRun && options?.install !== false) {
288
- const installSpinner = logger_1.logger.startSpinner('Installing dependencies...');
296
+ const installSpinner = logger_1.logger.startSpinner("Installing dependencies...");
289
297
  try {
290
298
  await (0, package_manager_1.installDependencies)(projectRoot, projectInfo.packageManager);
291
- installSpinner.succeed('Dependencies installed');
299
+ installSpinner.succeed("Dependencies installed");
292
300
  }
293
301
  catch (err) {
294
- installSpinner.fail('Failed to install dependencies');
302
+ installSpinner.fail("Failed to install dependencies");
295
303
  throw err;
296
304
  }
297
305
  }
@@ -314,15 +322,18 @@ async function addModuleToProject(projectRoot, projectInfo, config, options) {
314
322
  if (moduleMetadata.envVars) {
315
323
  const envArray = Array.isArray(moduleMetadata.envVars)
316
324
  ? moduleMetadata.envVars
317
- : Object.entries(moduleMetadata.envVars).map(([k, v]) => ({ key: k, value: String(v) }));
325
+ : Object.entries(moduleMetadata.envVars).map(([k, v]) => ({
326
+ key: k,
327
+ value: String(v),
328
+ }));
318
329
  for (const ev of envArray) {
319
- if (ev.key && typeof ev.value === 'string')
330
+ if (ev.key && typeof ev.value === "string")
320
331
  variables[ev.key] = ev.value;
321
332
  }
322
333
  for (let pass = 0; pass < 5; pass++) {
323
334
  let changed = false;
324
335
  for (const ev of envArray) {
325
- if (!ev.key || typeof ev.value !== 'string')
336
+ if (!ev.key || typeof ev.value !== "string")
326
337
  continue;
327
338
  const resolved = ev.value.replace(/\{\{(\w+)\}\}/g, (_m, k) => variables[k] ?? _m);
328
339
  if (variables[ev.key] !== resolved) {
@@ -10,10 +10,10 @@ interface CliOptions {
10
10
  packageManager?: string;
11
11
  p?: string;
12
12
  install?: boolean;
13
- 'skip-install'?: boolean;
13
+ "skip-install"?: boolean;
14
14
  skipInstall?: boolean;
15
15
  git?: boolean;
16
- 'no-git'?: boolean;
16
+ "no-git"?: boolean;
17
17
  noGit?: boolean;
18
18
  yes?: boolean;
19
19
  y?: boolean;
@@ -18,6 +18,7 @@ const framework_utils_1 = require("../lib/framework/framework-utils");
18
18
  const module_discovery_1 = require("../lib/discovery/module-discovery");
19
19
  const code_generator_1 = require("../lib/generation/code-generator");
20
20
  const package_root_1 = require("../lib/utils/package-root");
21
+ const env_editor_1 = require("../lib/env/env-editor");
21
22
  async function createProject(projectName, options) {
22
23
  logger_1.logger.newLine();
23
24
  logger_1.logger.log(chalk_1.default.bold.cyan("📦 Create StackKit App"));
@@ -30,18 +31,19 @@ async function createProject(projectName, options) {
30
31
  process.exit(1);
31
32
  }
32
33
  await generateProject(config, targetDir, options);
34
+ await processGeneratorEnvVars(config, targetDir);
33
35
  showNextSteps(config);
34
36
  }
35
37
  async function getProjectConfig(projectName, options) {
36
- const modulesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), 'modules');
38
+ const modulesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), "modules");
37
39
  const discoveredModules = await (0, module_discovery_1.discoverModules)(modulesDir);
38
40
  const argv = process.argv.slice(2);
39
- const createIndex = argv.indexOf('create');
41
+ const createIndex = argv.indexOf("create");
40
42
  const argsAfterCreate = createIndex >= 0 ? argv.slice(createIndex + 1) : [];
41
- const flagsProvided = argsAfterCreate.some(arg => arg.startsWith('-'));
43
+ const flagsProvided = argsAfterCreate.some((arg) => arg.startsWith("-"));
42
44
  const optionsProvided = flagsProvided || !!(options && (options.yes || options.y));
43
45
  if (optionsProvided) {
44
- if ((options && (options.yes || options.y))) {
46
+ if (options && (options.yes || options.y) && !flagsProvided) {
45
47
  return {
46
48
  projectName: projectName || "my-app",
47
49
  framework: "nextjs",
@@ -54,37 +56,37 @@ async function getProjectConfig(projectName, options) {
54
56
  }
55
57
  const framework = (options && (options.framework || options.f)) || undefined;
56
58
  if (discoveredModules.frameworks && discoveredModules.frameworks.length > 0) {
57
- const validFrameworks = discoveredModules.frameworks.map(f => f.name);
59
+ const validFrameworks = discoveredModules.frameworks.map((f) => f.name);
58
60
  if (framework && !validFrameworks.includes(framework)) {
59
- throw new Error(`Invalid framework: ${framework}. Valid options: ${validFrameworks.join(', ')}`);
61
+ throw new Error(`Invalid framework: ${framework}. Valid options: ${validFrameworks.join(", ")}`);
60
62
  }
61
63
  }
62
64
  const db = (options && (options.database || options.d)) || undefined;
63
65
  let allValidDatabases = [];
64
66
  if (discoveredModules.databases && discoveredModules.databases.length > 0) {
65
67
  const validDatabases = (0, module_discovery_1.getValidDatabaseOptions)(discoveredModules.databases);
66
- const validBaseDatabases = discoveredModules.databases.map(db => db.name);
68
+ const validBaseDatabases = discoveredModules.databases.map((db) => db.name);
67
69
  allValidDatabases = [...validDatabases, ...validBaseDatabases];
68
70
  if (db && !allValidDatabases.includes(db)) {
69
- throw new Error(`Invalid database: ${db}. Valid options: ${allValidDatabases.filter((v, i, arr) => arr.indexOf(v) === i).join(', ')}`);
71
+ throw new Error(`Invalid database: ${db}. Valid options: ${allValidDatabases.filter((v, i, arr) => arr.indexOf(v) === i).join(", ")}`);
70
72
  }
71
73
  }
72
74
  const authOpt = (options && (options.auth || options.a)) || undefined;
73
75
  if (discoveredModules.auth && discoveredModules.auth.length > 0) {
74
76
  const validAuth = (0, module_discovery_1.getValidAuthOptions)(discoveredModules.auth);
75
77
  if (authOpt && !validAuth.includes(authOpt)) {
76
- throw new Error(`Invalid auth: ${authOpt}. Valid options: ${validAuth.join(', ')}`);
78
+ throw new Error(`Invalid auth: ${authOpt}. Valid options: ${validAuth.join(", ")}`);
77
79
  }
78
80
  }
79
- const validLanguages = ['typescript', 'javascript'];
81
+ const validLanguages = ["typescript", "javascript"];
80
82
  const language = (options && (options.language || options.l)) || undefined;
81
83
  if (language && !validLanguages.includes(language)) {
82
- throw new Error(`Invalid language: ${language}. Valid options: ${validLanguages.join(', ')}`);
84
+ throw new Error(`Invalid language: ${language}. Valid options: ${validLanguages.join(", ")}`);
83
85
  }
84
- const validPackageManagers = ['pnpm', 'npm', 'yarn', 'bun'];
86
+ const validPackageManagers = ["pnpm", "npm", "yarn", "bun"];
85
87
  const pm = (options && (options.packageManager || options.p)) || undefined;
86
88
  if (pm && !validPackageManagers.includes(pm)) {
87
- throw new Error(`Invalid package manager: ${pm}. Valid options: ${validPackageManagers.join(', ')}`);
89
+ throw new Error(`Invalid package manager: ${pm}. Valid options: ${validPackageManagers.join(", ")}`);
88
90
  }
89
91
  let database = "none";
90
92
  let prismaProvider;
@@ -136,12 +138,12 @@ async function getProjectConfig(projectName, options) {
136
138
  type: "list",
137
139
  name: "framework",
138
140
  message: "Select framework:",
139
- choices: (discoveredModules.frameworks && discoveredModules.frameworks.length > 0)
140
- ? discoveredModules.frameworks.map(f => ({ name: f.displayName, value: f.name }))
141
+ choices: discoveredModules.frameworks && discoveredModules.frameworks.length > 0
142
+ ? discoveredModules.frameworks.map((f) => ({ name: f.displayName, value: f.name }))
141
143
  : [
142
- { name: 'Next.js', value: 'nextjs' },
143
- { name: 'Express.js', value: 'express' },
144
- { name: 'React (Vite)', value: 'react' },
144
+ { name: "Next.js", value: "nextjs" },
145
+ { name: "Express.js", value: "express" },
146
+ { name: "React (Vite)", value: "react" },
145
147
  ],
146
148
  },
147
149
  {
@@ -171,7 +173,7 @@ async function getProjectConfig(projectName, options) {
171
173
  type: "list",
172
174
  name: "auth",
173
175
  message: "Select authentication:",
174
- when: (answers) => (answers.database !== "none" || answers.framework === "react"),
176
+ when: (answers) => answers.database !== "none" || answers.framework === "react",
175
177
  choices: (answers) => (0, module_discovery_1.getCompatibleAuthOptions)(discoveredModules.auth, answers.framework, answers.database || "none"),
176
178
  },
177
179
  {
@@ -204,7 +206,7 @@ async function getProjectConfig(projectName, options) {
204
206
  ? "none"
205
207
  : answers.database),
206
208
  prismaProvider: answers.prismaProvider,
207
- auth: (answers.auth || "none"),
209
+ auth: answers.auth || "none",
208
210
  language: answers.language,
209
211
  packageManager: answers.packageManager,
210
212
  };
@@ -220,7 +222,7 @@ async function generateProject(config, targetDir, options) {
220
222
  copySpinner.fail("Failed to create project files");
221
223
  throw error;
222
224
  }
223
- if (options?.install !== false && !(options?.['skip-install'] || options?.skipInstall)) {
225
+ if (options?.install !== false && !(options?.["skip-install"] || options?.skipInstall)) {
224
226
  const installSpinner = logger_1.logger.startSpinner("Installing dependencies...");
225
227
  try {
226
228
  await (0, package_manager_1.installDependencies)(targetDir, config.packageManager);
@@ -231,7 +233,9 @@ async function generateProject(config, targetDir, options) {
231
233
  throw error;
232
234
  }
233
235
  }
234
- if (postInstallCommands.length > 0 && options?.install !== false && !(options?.['skip-install'] || options?.skipInstall)) {
236
+ if (postInstallCommands.length > 0 &&
237
+ options?.install !== false &&
238
+ !(options?.["skip-install"] || options?.skipInstall)) {
235
239
  const postInstallSpinner = logger_1.logger.startSpinner("Running post-install commands...");
236
240
  try {
237
241
  for (const command of postInstallCommands) {
@@ -244,7 +248,7 @@ async function generateProject(config, targetDir, options) {
244
248
  throw error;
245
249
  }
246
250
  }
247
- if (options?.git !== false && !(options?.['no-git'] || options?.noGit)) {
251
+ if (options?.git !== false && !(options?.["no-git"] || options?.noGit)) {
248
252
  const gitSpinner = logger_1.logger.startSpinner("Initializing git repository...");
249
253
  try {
250
254
  await (0, git_utils_1.initGit)(targetDir);
@@ -257,8 +261,8 @@ async function generateProject(config, targetDir, options) {
257
261
  }
258
262
  async function composeTemplate(config, targetDir) {
259
263
  const packageRoot = (0, package_root_1.getPackageRoot)();
260
- const templatesDir = path_1.default.join(packageRoot, 'templates');
261
- const modulesDirForGenerator = path_1.default.join(packageRoot, 'modules');
264
+ const templatesDir = path_1.default.join(packageRoot, "templates");
265
+ const modulesDirForGenerator = path_1.default.join(packageRoot, "modules");
262
266
  await fs_extra_1.default.ensureDir(targetDir);
263
267
  const frameworkConfig = await framework_utils_1.FrameworkUtils.loadFrameworkConfig(config.framework, templatesDir);
264
268
  const generator = new code_generator_1.AdvancedCodeGenerator(frameworkConfig);
@@ -266,8 +270,8 @@ async function composeTemplate(config, targetDir) {
266
270
  const features = [];
267
271
  const postInstallCommands = await generator.generate({
268
272
  framework: config.framework,
269
- database: config.database === 'none' ? undefined : config.database,
270
- auth: config.auth === 'none' ? undefined : config.auth,
273
+ database: config.database === "none" ? undefined : config.database,
274
+ auth: config.auth === "none" ? undefined : config.auth,
271
275
  prismaProvider: config.prismaProvider,
272
276
  }, features, targetDir);
273
277
  const packageJsonPath = path_1.default.join(targetDir, "package.json");
@@ -285,12 +289,75 @@ async function composeTemplate(config, targetDir) {
285
289
  }
286
290
  }
287
291
  catch {
292
+ // env copy failed.
288
293
  }
289
294
  if (config.language === "javascript") {
290
295
  await (0, js_conversion_1.convertToJavaScript)(targetDir, config.framework);
291
296
  }
292
297
  return postInstallCommands;
293
298
  }
299
+ async function processGeneratorEnvVars(config, targetDir) {
300
+ const modulesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), "modules");
301
+ const envVars = [];
302
+ // Process database generator env vars
303
+ if (config.database && config.database !== "none") {
304
+ const dbGeneratorPath = path_1.default.join(modulesDir, "database", config.database, "generator.json");
305
+ if (await fs_extra_1.default.pathExists(dbGeneratorPath)) {
306
+ const generator = await fs_extra_1.default.readJson(dbGeneratorPath);
307
+ if (generator.operations) {
308
+ for (const operation of generator.operations) {
309
+ if (operation.type === "add-env" && (!operation.condition || checkCondition(operation.condition, config))) {
310
+ for (const [key, value] of Object.entries(operation.envVars)) {
311
+ envVars.push({
312
+ key,
313
+ value: value,
314
+ required: true,
315
+ });
316
+ }
317
+ }
318
+ }
319
+ }
320
+ }
321
+ }
322
+ // Process auth generator env vars
323
+ if (config.auth && config.auth !== "none") {
324
+ const authGeneratorPath = path_1.default.join(modulesDir, "auth", config.auth, "generator.json");
325
+ if (await fs_extra_1.default.pathExists(authGeneratorPath)) {
326
+ const generator = await fs_extra_1.default.readJson(authGeneratorPath);
327
+ if (generator.operations) {
328
+ for (const operation of generator.operations) {
329
+ if (operation.type === "add-env" && (!operation.condition || checkCondition(operation.condition, config))) {
330
+ for (const [key, value] of Object.entries(operation.envVars)) {
331
+ envVars.push({
332
+ key,
333
+ value: value,
334
+ required: true,
335
+ });
336
+ }
337
+ }
338
+ }
339
+ }
340
+ }
341
+ }
342
+ if (envVars.length > 0) {
343
+ await (0, env_editor_1.addEnvVariables)(targetDir, envVars, { force: true });
344
+ }
345
+ }
346
+ function checkCondition(condition, config) {
347
+ for (const [key, value] of Object.entries(condition)) {
348
+ if (Array.isArray(value)) {
349
+ if (!value.includes(config[key])) {
350
+ return false;
351
+ }
352
+ }
353
+ else {
354
+ if (config[key] !== value) {
355
+ return false;
356
+ }
357
+ }
358
+ }
359
+ return true;
360
+ }
294
361
  function showNextSteps(config) {
295
362
  logger_1.logger.newLine();
296
363
  logger_1.logger.success(`Created ${config.projectName}`);
@@ -96,7 +96,7 @@ async function runDoctorChecks() {
96
96
  const gitCheck = await checkGitRepo(projectRoot);
97
97
  checks.push(gitCheck);
98
98
  const conflicts = checkConflicts(authModules, databaseModules);
99
- conflicts.forEach(conflict => {
99
+ conflicts.forEach((conflict) => {
100
100
  checks.push({
101
101
  status: "warning",
102
102
  message: conflict,
@@ -118,8 +118,11 @@ async function runDoctorChecks() {
118
118
  },
119
119
  files: {
120
120
  envExample: await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, ".env.example")),
121
- env: await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, ".env")) || await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, ".env.local")),
122
- prismaSchema: databaseModules.includes("prisma") ? await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, "prisma", "schema.prisma")) : undefined,
121
+ env: (await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, ".env"))) ||
122
+ (await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, ".env.local"))),
123
+ prismaSchema: databaseModules.includes("prisma")
124
+ ? await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, "prisma", "schema.prisma"))
125
+ : undefined,
123
126
  authRoutes: authModules.length > 0 ? await checkAuthRoutesExist(projectRoot, projectType) : undefined,
124
127
  tsconfig: await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, "tsconfig.json")),
125
128
  eslintConfig: await checkEslintConfigExists(projectRoot),
@@ -132,8 +135,8 @@ async function runDoctorChecks() {
132
135
  conflicts,
133
136
  checks,
134
137
  summary: {
135
- errors: checks.filter(c => c.status === "error").length,
136
- warnings: checks.filter(c => c.status === "warning").length,
138
+ errors: checks.filter((c) => c.status === "error").length,
139
+ warnings: checks.filter((c) => c.status === "warning").length,
137
140
  suggestions: generateSuggestions(),
138
141
  },
139
142
  };
@@ -232,7 +235,9 @@ async function checkKeyFiles(projectRoot, projectType, authModules, databaseModu
232
235
  const envExampleExists = await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, ".env.example"));
233
236
  checks.push({
234
237
  status: envExampleExists ? "success" : "warning",
235
- message: envExampleExists ? ".env.example file found" : ".env.example file missing (recommended for documentation)",
238
+ message: envExampleExists
239
+ ? ".env.example file found"
240
+ : ".env.example file missing (recommended for documentation)",
236
241
  });
237
242
  if (databaseModules.includes("prisma")) {
238
243
  const schemaExists = await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, "prisma", "schema.prisma"));
@@ -245,7 +250,9 @@ async function checkKeyFiles(projectRoot, projectType, authModules, databaseModu
245
250
  const authRoutesExist = await checkAuthRoutesExist(projectRoot, projectType);
246
251
  checks.push({
247
252
  status: authRoutesExist ? "success" : "warning",
248
- message: authRoutesExist ? "Auth routes configured" : "Auth routes not found (may need configuration)",
253
+ message: authRoutesExist
254
+ ? "Auth routes configured"
255
+ : "Auth routes not found (may need configuration)",
249
256
  });
250
257
  }
251
258
  return checks;
@@ -300,8 +307,11 @@ async function checkEnvFiles(projectRoot, authModules, databaseModules) {
300
307
  });
301
308
  return { checks, envStatus: { missing: requiredKeys, present: [] } };
302
309
  }
303
- const envLines = envContent.split("\n").map(line => line.trim()).filter(line => line && !line.startsWith("#"));
304
- const envVars = new Set(envLines.map(line => line.split("=")[0]));
310
+ const envLines = envContent
311
+ .split("\n")
312
+ .map((line) => line.trim())
313
+ .filter((line) => line && !line.startsWith("#"));
314
+ const envVars = new Set(envLines.map((line) => line.split("=")[0]));
305
315
  for (const key of requiredKeys) {
306
316
  if (envVars.has(key)) {
307
317
  present.push(key);
@@ -346,7 +356,9 @@ async function checkConfigFiles(projectRoot, projectType, packageJson) {
346
356
  status: eslintExists ? "success" : "warning",
347
357
  message: eslintExists ? MESSAGES.ESLINT_CONFIG_FOUND : MESSAGES.ESLINT_CONFIG_MISSING,
348
358
  });
349
- const hasBuildScript = packageJson.scripts && typeof packageJson.scripts === "object" && "build" in packageJson.scripts;
359
+ const hasBuildScript = packageJson.scripts &&
360
+ typeof packageJson.scripts === "object" &&
361
+ "build" in packageJson.scripts;
350
362
  checks.push({
351
363
  status: hasBuildScript ? "success" : "warning",
352
364
  message: hasBuildScript ? MESSAGES.BUILD_SCRIPT_FOUND : MESSAGES.BUILD_SCRIPT_MISSING,
@@ -521,7 +533,7 @@ function printDoctorReport(report, verbose) {
521
533
  // Conflicts
522
534
  if (report.conflicts.length > 0) {
523
535
  logger_1.logger.log(chalk_1.default.bold("Conflicts"));
524
- report.conflicts.forEach(conflict => {
536
+ report.conflicts.forEach((conflict) => {
525
537
  logger_1.logger.warn(conflict);
526
538
  });
527
539
  logger_1.logger.newLine();
@@ -529,7 +541,7 @@ function printDoctorReport(report, verbose) {
529
541
  // Detailed checks if verbose
530
542
  if (verbose) {
531
543
  logger_1.logger.log(chalk_1.default.bold("Detailed Checks"));
532
- report.checks.forEach(check => {
544
+ report.checks.forEach((check) => {
533
545
  if (check.status === "success") {
534
546
  logger_1.logger.success(check.message);
535
547
  }
@@ -552,7 +564,7 @@ function printDoctorReport(report, verbose) {
552
564
  logger_1.logger.newLine();
553
565
  if (report.summary.suggestions.length > 0) {
554
566
  logger_1.logger.log(chalk_1.default.bold("Suggestions"));
555
- report.summary.suggestions.forEach(suggestion => {
567
+ report.summary.suggestions.forEach((suggestion) => {
556
568
  logger_1.logger.log(` • ${suggestion}`);
557
569
  });
558
570
  }
package/dist/cli/list.js CHANGED
@@ -52,10 +52,22 @@ async function listCommand(options) {
52
52
  logger_1.logger.log(` ${chalk_1.default.gray(categoryPrefix)} ${chalk_1.default.yellow(formatCategoryName(category))} ${chalk_1.default.dim(`(${mods.length})`)}`);
53
53
  mods.forEach((mod, modIndex) => {
54
54
  const isLastMod = modIndex === mods.length - 1;
55
- const modPrefix = isLastCategory ? (isLastMod ? " └──" : " ├──") : (isLastMod ? "│ └──" : "│ ├──");
55
+ const modPrefix = isLastCategory
56
+ ? isLastMod
57
+ ? " └──"
58
+ : " ├──"
59
+ : isLastMod
60
+ ? "│ └──"
61
+ : "│ ├──";
56
62
  logger_1.logger.log(` ${chalk_1.default.gray(modPrefix)} ${chalk_1.default.green(mod.displayName)}`);
57
63
  if (mod.category === "database" && mod.name === "prisma") {
58
- const providerPrefix = isLastCategory ? (isLastMod ? " └──" : " ├──") : (isLastMod ? "│ └──" : "│ ├──");
64
+ const providerPrefix = isLastCategory
65
+ ? isLastMod
66
+ ? " └──"
67
+ : " ├──"
68
+ : isLastMod
69
+ ? "│ └──"
70
+ : "│ ├──";
59
71
  logger_1.logger.log(` ${chalk_1.default.gray(providerPrefix)} ${chalk_1.default.dim("Providers: PostgreSQL, MongoDB, MySQL, SQLite")}`);
60
72
  }
61
73
  });
package/dist/index.js CHANGED
@@ -11,28 +11,28 @@ const program = new commander_1.Command();
11
11
  program
12
12
  .name("stackkit")
13
13
  .description("CLI for creating and managing StackKit projects")
14
- .version("0.1.4")
14
+ .version("0.1.5")
15
15
  .configureHelp({
16
16
  subcommandTerm: (cmd) => {
17
17
  const name = cmd.name();
18
- if (name === 'create')
19
- return 'create [project-name] [options]';
20
- if (name === 'add')
21
- return 'add <module> [options]';
22
- if (name === 'doctor')
23
- return 'doctor [options]';
24
- if (name === 'list')
25
- return 'list [options]';
26
- if (name === 'help')
27
- return 'help [command]';
28
- return name + ' [options]';
29
- }
18
+ if (name === "create")
19
+ return "create [project-name] [options]";
20
+ if (name === "add")
21
+ return "add <module> [options]";
22
+ if (name === "doctor")
23
+ return "doctor [options]";
24
+ if (name === "list")
25
+ return "list [options]";
26
+ if (name === "help")
27
+ return "help [command]";
28
+ return name + " [options]";
29
+ },
30
30
  });
31
31
  // Create command
32
32
  program
33
- .command('create [project-name]')
33
+ .command("create [project-name]")
34
34
  .description("Create a new StackKit project")
35
- .usage('[project-name] [options]')
35
+ .usage("[project-name] [options]")
36
36
  .option("-f, --framework <framework>", "Framework: nextjs, express, react")
37
37
  .option("-d, --database <database>", "Database: prisma, mongoose, none")
38
38
  .option("--prisma-provider <provider>", "Prisma provider: postgresql, mongodb, mysql, sqlite")
@@ -55,7 +55,7 @@ program
55
55
  program
56
56
  .command("add [module]")
57
57
  .description("Add a module or category to your existing project")
58
- .usage('[module] [options]')
58
+ .usage("[module] [options]")
59
59
  .option("--provider <provider>", "Specific provider/variant to use")
60
60
  .option("--force", "Overwrite existing files")
61
61
  .option("--dry-run", "Show what would be changed without making changes")
@@ -10,7 +10,7 @@ const path_1 = __importDefault(require("path"));
10
10
  const package_root_1 = require("../utils/package-root");
11
11
  const baseDirs = {
12
12
  express: "./src",
13
- "react": "./src",
13
+ react: "./src",
14
14
  nextjs: ".",
15
15
  };
16
16
  async function convertToJavaScript(targetDir, framework) {