stackkit 0.1.3 → 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 +5 -3
- package/dist/cli/add.d.ts +2 -1
- package/dist/cli/add.js +325 -102
- package/dist/cli/create.d.ts +2 -2
- package/dist/cli/create.js +96 -30
- package/dist/cli/doctor.js +25 -17
- package/dist/cli/list.js +14 -2
- package/dist/index.js +22 -3
- package/dist/lib/conversion/js-conversion.js +2 -2
- package/dist/lib/discovery/module-discovery.d.ts +0 -1
- package/dist/lib/discovery/module-discovery.js +35 -35
- package/dist/lib/env/env-editor.js +1 -1
- package/dist/lib/framework/framework-utils.d.ts +1 -1
- package/dist/lib/framework/framework-utils.js +3 -3
- package/dist/lib/generation/code-generator.d.ts +18 -4
- package/dist/lib/generation/code-generator.js +212 -147
- package/dist/lib/generation/generator-utils.d.ts +11 -0
- package/dist/lib/generation/generator-utils.js +124 -0
- package/dist/lib/git-utils.js +20 -0
- package/dist/lib/project/detect.js +2 -4
- package/dist/lib/utils/package-root.js +2 -2
- package/dist/types/index.d.ts +0 -10
- package/modules/auth/authjs/generator.json +10 -0
- package/modules/auth/authjs/module.json +0 -9
- package/modules/auth/better-auth/files/lib/auth.ts +38 -31
- package/modules/auth/better-auth/files/prisma/schema.prisma +3 -3
- package/modules/auth/better-auth/generator.json +58 -28
- package/modules/auth/better-auth/module.json +0 -24
- package/modules/database/mongoose/files/models/health.ts +34 -0
- package/modules/database/mongoose/generator.json +27 -8
- package/modules/database/mongoose/module.json +1 -2
- package/modules/database/prisma/files/lib/prisma.ts +27 -21
- package/modules/database/prisma/files/prisma.config.ts +17 -0
- package/modules/database/prisma/generator.json +79 -15
- package/modules/database/prisma/module.json +1 -4
- package/package.json +1 -1
- package/templates/express/src/server.ts +9 -3
- package/templates/express/tsconfig.json +2 -23
- package/templates/nextjs/lib/env.ts +1 -1
- package/dist/lib/database/database-config.d.ts +0 -6
- package/dist/lib/database/database-config.js +0 -9
- package/modules/database/mongoose/files/models/User.ts +0 -34
- /package/modules/database/mongoose/files/lib/{db.ts → mongoose.ts} +0 -0
package/dist/cli/create.js
CHANGED
|
@@ -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)(),
|
|
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(
|
|
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 (
|
|
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 = [
|
|
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 = [
|
|
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:
|
|
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:
|
|
143
|
-
{ name:
|
|
144
|
-
{ name:
|
|
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) =>
|
|
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:
|
|
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?.[
|
|
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 &&
|
|
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,21 +248,21 @@ async function generateProject(config, targetDir, options) {
|
|
|
244
248
|
throw error;
|
|
245
249
|
}
|
|
246
250
|
}
|
|
247
|
-
if (options?.git !== false && !(options?.[
|
|
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);
|
|
251
255
|
gitSpinner.succeed("Git repository initialized");
|
|
252
256
|
}
|
|
253
|
-
catch {
|
|
254
|
-
gitSpinner.warn(
|
|
257
|
+
catch (error) {
|
|
258
|
+
gitSpinner.warn(`Failed to initialize git repository: ${error.message}`);
|
|
255
259
|
}
|
|
256
260
|
}
|
|
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,
|
|
261
|
-
const modulesDirForGenerator = path_1.default.join(packageRoot,
|
|
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 ===
|
|
270
|
-
auth: 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,13 +289,75 @@ async function composeTemplate(config, targetDir) {
|
|
|
285
289
|
}
|
|
286
290
|
}
|
|
287
291
|
catch {
|
|
288
|
-
//
|
|
292
|
+
// env copy failed.
|
|
289
293
|
}
|
|
290
294
|
if (config.language === "javascript") {
|
|
291
295
|
await (0, js_conversion_1.convertToJavaScript)(targetDir, config.framework);
|
|
292
296
|
}
|
|
293
297
|
return postInstallCommands;
|
|
294
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
|
+
}
|
|
295
361
|
function showNextSteps(config) {
|
|
296
362
|
logger_1.logger.newLine();
|
|
297
363
|
logger_1.logger.success(`Created ${config.projectName}`);
|
package/dist/cli/doctor.js
CHANGED
|
@@ -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")) ||
|
|
122
|
-
|
|
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
|
|
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
|
|
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
|
|
304
|
-
|
|
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);
|
|
@@ -336,20 +346,19 @@ function checkConflicts(authModules, databaseModules) {
|
|
|
336
346
|
}
|
|
337
347
|
async function checkConfigFiles(projectRoot, projectType, packageJson) {
|
|
338
348
|
const checks = [];
|
|
339
|
-
// Check tsconfig.json
|
|
340
349
|
const tsconfigExists = await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, "tsconfig.json"));
|
|
341
350
|
checks.push({
|
|
342
351
|
status: tsconfigExists ? "success" : "error",
|
|
343
352
|
message: tsconfigExists ? MESSAGES.TSCONFIG_FOUND : MESSAGES.TSCONFIG_MISSING,
|
|
344
353
|
});
|
|
345
|
-
// Check ESLint config
|
|
346
354
|
const eslintExists = await checkEslintConfigExists(projectRoot);
|
|
347
355
|
checks.push({
|
|
348
356
|
status: eslintExists ? "success" : "warning",
|
|
349
357
|
message: eslintExists ? MESSAGES.ESLINT_CONFIG_FOUND : MESSAGES.ESLINT_CONFIG_MISSING,
|
|
350
358
|
});
|
|
351
|
-
|
|
352
|
-
|
|
359
|
+
const hasBuildScript = packageJson.scripts &&
|
|
360
|
+
typeof packageJson.scripts === "object" &&
|
|
361
|
+
"build" in packageJson.scripts;
|
|
353
362
|
checks.push({
|
|
354
363
|
status: hasBuildScript ? "success" : "warning",
|
|
355
364
|
message: hasBuildScript ? MESSAGES.BUILD_SCRIPT_FOUND : MESSAGES.BUILD_SCRIPT_MISSING,
|
|
@@ -363,7 +372,6 @@ async function checkDependencies(packageJson) {
|
|
|
363
372
|
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
364
373
|
for (const [name, version] of Object.entries(deps || {})) {
|
|
365
374
|
if (typeof version === "string" && (version.startsWith("^") || version.startsWith("~"))) {
|
|
366
|
-
// Assume up to date
|
|
367
375
|
}
|
|
368
376
|
else {
|
|
369
377
|
outdated.push(name);
|
|
@@ -525,7 +533,7 @@ function printDoctorReport(report, verbose) {
|
|
|
525
533
|
// Conflicts
|
|
526
534
|
if (report.conflicts.length > 0) {
|
|
527
535
|
logger_1.logger.log(chalk_1.default.bold("Conflicts"));
|
|
528
|
-
report.conflicts.forEach(conflict => {
|
|
536
|
+
report.conflicts.forEach((conflict) => {
|
|
529
537
|
logger_1.logger.warn(conflict);
|
|
530
538
|
});
|
|
531
539
|
logger_1.logger.newLine();
|
|
@@ -533,7 +541,7 @@ function printDoctorReport(report, verbose) {
|
|
|
533
541
|
// Detailed checks if verbose
|
|
534
542
|
if (verbose) {
|
|
535
543
|
logger_1.logger.log(chalk_1.default.bold("Detailed Checks"));
|
|
536
|
-
report.checks.forEach(check => {
|
|
544
|
+
report.checks.forEach((check) => {
|
|
537
545
|
if (check.status === "success") {
|
|
538
546
|
logger_1.logger.success(check.message);
|
|
539
547
|
}
|
|
@@ -556,7 +564,7 @@ function printDoctorReport(report, verbose) {
|
|
|
556
564
|
logger_1.logger.newLine();
|
|
557
565
|
if (report.summary.suggestions.length > 0) {
|
|
558
566
|
logger_1.logger.log(chalk_1.default.bold("Suggestions"));
|
|
559
|
-
report.summary.suggestions.forEach(suggestion => {
|
|
567
|
+
report.summary.suggestions.forEach((suggestion) => {
|
|
560
568
|
logger_1.logger.log(` • ${suggestion}`);
|
|
561
569
|
});
|
|
562
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
|
|
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
|
|
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,11 +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.
|
|
14
|
+
.version("0.1.5")
|
|
15
|
+
.configureHelp({
|
|
16
|
+
subcommandTerm: (cmd) => {
|
|
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
|
+
},
|
|
30
|
+
});
|
|
15
31
|
// Create command
|
|
16
32
|
program
|
|
17
33
|
.command("create [project-name]")
|
|
18
34
|
.description("Create a new StackKit project")
|
|
35
|
+
.usage("[project-name] [options]")
|
|
19
36
|
.option("-f, --framework <framework>", "Framework: nextjs, express, react")
|
|
20
37
|
.option("-d, --database <database>", "Database: prisma, mongoose, none")
|
|
21
38
|
.option("--prisma-provider <provider>", "Prisma provider: postgresql, mongodb, mysql, sqlite")
|
|
@@ -36,12 +53,14 @@ program
|
|
|
36
53
|
});
|
|
37
54
|
// Add command
|
|
38
55
|
program
|
|
39
|
-
.command("add
|
|
40
|
-
.description("Add a module to your existing project")
|
|
56
|
+
.command("add [module]")
|
|
57
|
+
.description("Add a module or category to your existing project")
|
|
58
|
+
.usage("[module] [options]")
|
|
41
59
|
.option("--provider <provider>", "Specific provider/variant to use")
|
|
42
60
|
.option("--force", "Overwrite existing files")
|
|
43
61
|
.option("--dry-run", "Show what would be changed without making changes")
|
|
44
62
|
.option("--no-install", "Skip installing dependencies")
|
|
63
|
+
.option("-y, --yes", "Use default options")
|
|
45
64
|
.action(async (module, options) => {
|
|
46
65
|
try {
|
|
47
66
|
await (0, add_1.addCommand)(module, options);
|
|
@@ -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
|
-
|
|
13
|
+
react: "./src",
|
|
14
14
|
nextjs: ".",
|
|
15
15
|
};
|
|
16
16
|
async function convertToJavaScript(targetDir, framework) {
|
|
@@ -77,7 +77,7 @@ async function convertToJavaScript(targetDir, framework) {
|
|
|
77
77
|
presets.push([
|
|
78
78
|
require.resolve("@babel/preset-react"),
|
|
79
79
|
{
|
|
80
|
-
runtime: "
|
|
80
|
+
runtime: "automatic",
|
|
81
81
|
},
|
|
82
82
|
]);
|
|
83
83
|
}
|
|
@@ -5,7 +5,6 @@ export interface ModuleMetadata {
|
|
|
5
5
|
category: string;
|
|
6
6
|
provider?: string;
|
|
7
7
|
supportedFrameworks?: string[];
|
|
8
|
-
databaseAdapters?: Record<string, unknown>;
|
|
9
8
|
frameworkConfigs?: Record<string, unknown>;
|
|
10
9
|
dependencies?: Record<string, unknown>;
|
|
11
10
|
devDependencies?: Record<string, unknown>;
|