stackkit 0.1.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/README.md +41 -0
- package/bin/stackkit.js +4 -0
- package/dist/cli/add.d.ts +8 -0
- package/dist/cli/add.js +313 -0
- package/dist/cli/create.d.ts +22 -0
- package/dist/cli/create.js +336 -0
- package/dist/cli/doctor.d.ts +7 -0
- package/dist/cli/doctor.js +569 -0
- package/dist/cli/list.d.ts +6 -0
- package/dist/cli/list.js +123 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +91 -0
- package/dist/lib/conversion/js-conversion.d.ts +1 -0
- package/dist/lib/conversion/js-conversion.js +244 -0
- package/dist/lib/database/database-config.d.ts +6 -0
- package/dist/lib/database/database-config.js +9 -0
- package/dist/lib/discovery/module-discovery.d.ts +62 -0
- package/dist/lib/discovery/module-discovery.js +188 -0
- package/dist/lib/env/env-editor.d.ts +9 -0
- package/dist/lib/env/env-editor.js +116 -0
- package/dist/lib/framework/framework-utils.d.ts +22 -0
- package/dist/lib/framework/framework-utils.js +74 -0
- package/dist/lib/fs/files.d.ts +14 -0
- package/dist/lib/fs/files.js +101 -0
- package/dist/lib/generation/code-generator.d.ts +83 -0
- package/dist/lib/generation/code-generator.js +681 -0
- package/dist/lib/git-utils.d.ts +1 -0
- package/dist/lib/git-utils.js +9 -0
- package/dist/lib/pm/package-manager.d.ts +5 -0
- package/dist/lib/pm/package-manager.js +69 -0
- package/dist/lib/project/detect.d.ts +4 -0
- package/dist/lib/project/detect.js +121 -0
- package/dist/lib/ui/logger.d.ts +16 -0
- package/dist/lib/ui/logger.js +59 -0
- package/dist/types/index.d.ts +92 -0
- package/dist/types/index.js +2 -0
- package/modules/auth/authjs/files/api/auth/[...nextauth]/route.ts +6 -0
- package/modules/auth/authjs/files/lib/auth-client.ts +11 -0
- package/modules/auth/authjs/files/lib/auth.ts +36 -0
- package/modules/auth/authjs/files/schemas/prisma-schema.prisma +45 -0
- package/modules/auth/authjs/module.json +22 -0
- package/modules/auth/better-auth/files/api/auth/[...all]/route.ts +4 -0
- package/modules/auth/better-auth/files/lib/auth-client.ts +7 -0
- package/modules/auth/better-auth/files/lib/auth.ts +83 -0
- package/modules/auth/better-auth/files/lib/email-service.ts +34 -0
- package/modules/auth/better-auth/files/lib/email-templates.ts +89 -0
- package/modules/auth/better-auth/files/prisma/schema.prisma +63 -0
- package/modules/auth/better-auth/generator.json +78 -0
- package/modules/auth/better-auth/module.json +37 -0
- package/modules/database/mongoose/files/lib/db.ts +63 -0
- package/modules/database/mongoose/files/models/User.ts +34 -0
- package/modules/database/mongoose/generator.json +24 -0
- package/modules/database/mongoose/module.json +15 -0
- package/modules/database/prisma/files/lib/prisma.ts +45 -0
- package/modules/database/prisma/files/prisma/schema.prisma +8 -0
- package/modules/database/prisma/files/prisma.config.ts +12 -0
- package/modules/database/prisma/generator.json +43 -0
- package/modules/database/prisma/module.json +17 -0
- package/package.json +83 -0
- package/templates/express/.env.example +2 -0
- package/templates/express/eslint.config.cjs +42 -0
- package/templates/express/package.json +33 -0
- package/templates/express/src/app.ts +51 -0
- package/templates/express/src/config/env.ts +12 -0
- package/templates/express/src/features/health/health.controller.ts +18 -0
- package/templates/express/src/features/health/health.route.ts +9 -0
- package/templates/express/src/features/health/health.service.ts +6 -0
- package/templates/express/src/middlewares/error.middleware.ts +18 -0
- package/templates/express/src/server.ts +8 -0
- package/templates/express/template.json +27 -0
- package/templates/express/tsconfig.json +30 -0
- package/templates/nextjs/README.md +52 -0
- package/templates/nextjs/app/favicon.ico +0 -0
- package/templates/nextjs/app/globals.css +26 -0
- package/templates/nextjs/app/layout.tsx +30 -0
- package/templates/nextjs/app/page.tsx +57 -0
- package/templates/nextjs/eslint.config.mjs +18 -0
- package/templates/nextjs/lib/env.ts +8 -0
- package/templates/nextjs/next.config.ts +7 -0
- package/templates/nextjs/package.json +27 -0
- package/templates/nextjs/postcss.config.mjs +7 -0
- package/templates/nextjs/public/file.svg +1 -0
- package/templates/nextjs/public/globe.svg +1 -0
- package/templates/nextjs/public/next.svg +1 -0
- package/templates/nextjs/public/vercel.svg +1 -0
- package/templates/nextjs/public/window.svg +1 -0
- package/templates/nextjs/template.json +34 -0
- package/templates/nextjs/tsconfig.json +34 -0
- package/templates/react/.env.example +1 -0
- package/templates/react/.prettierignore +4 -0
- package/templates/react/.prettierrc +9 -0
- package/templates/react/README.md +56 -0
- package/templates/react/eslint.config.js +23 -0
- package/templates/react/index.html +14 -0
- package/templates/react/package.json +44 -0
- package/templates/react/public/vite.svg +1 -0
- package/templates/react/src/api/client.ts +47 -0
- package/templates/react/src/assets/react.svg +1 -0
- package/templates/react/src/components/ErrorBoundary.tsx +51 -0
- package/templates/react/src/components/Layout.tsx +13 -0
- package/templates/react/src/components/Loading.tsx +8 -0
- package/templates/react/src/components/SEO.tsx +49 -0
- package/templates/react/src/config/constants.ts +5 -0
- package/templates/react/src/hooks/index.ts +64 -0
- package/templates/react/src/index.css +1 -0
- package/templates/react/src/lib/queryClient.ts +12 -0
- package/templates/react/src/main.tsx +22 -0
- package/templates/react/src/pages/About.tsx +78 -0
- package/templates/react/src/pages/Home.tsx +49 -0
- package/templates/react/src/pages/NotFound.tsx +24 -0
- package/templates/react/src/router.tsx +21 -0
- package/templates/react/src/types/api.d.ts +20 -0
- package/templates/react/src/utils/helpers.ts +51 -0
- package/templates/react/src/utils/storage.ts +35 -0
- package/templates/react/src/vite-env.d.ts +11 -0
- package/templates/react/template.json +38 -0
- package/templates/react/tsconfig.app.json +28 -0
- package/templates/react/tsconfig.json +4 -0
- package/templates/react/tsconfig.node.json +26 -0
- package/templates/react/vite.config.ts +7 -0
- package/templates/react-vite/README.md +56 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.discoverModules = discoverModules;
|
|
7
|
+
exports.getValidDatabaseOptions = getValidDatabaseOptions;
|
|
8
|
+
exports.getValidAuthOptions = getValidAuthOptions;
|
|
9
|
+
exports.parseDatabaseOption = parseDatabaseOption;
|
|
10
|
+
exports.getCompatibleAuthOptions = getCompatibleAuthOptions;
|
|
11
|
+
exports.getDatabaseChoices = getDatabaseChoices;
|
|
12
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
/**
|
|
15
|
+
* Discover all available modules from the modules directory
|
|
16
|
+
*/
|
|
17
|
+
async function discoverModules(modulesDir) {
|
|
18
|
+
const discovered = {
|
|
19
|
+
frameworks: [],
|
|
20
|
+
databases: [],
|
|
21
|
+
auth: [],
|
|
22
|
+
};
|
|
23
|
+
if (!(await fs_extra_1.default.pathExists(modulesDir))) {
|
|
24
|
+
return discovered;
|
|
25
|
+
}
|
|
26
|
+
// Discover frameworks from templates directory
|
|
27
|
+
const templatesDir = path_1.default.join(modulesDir, '..', 'templates');
|
|
28
|
+
if (await fs_extra_1.default.pathExists(templatesDir)) {
|
|
29
|
+
const frameworkDirs = await fs_extra_1.default.readdir(templatesDir);
|
|
30
|
+
for (const frameworkName of frameworkDirs) {
|
|
31
|
+
const templateJsonPath = path_1.default.join(templatesDir, frameworkName, 'template.json');
|
|
32
|
+
if (await fs_extra_1.default.pathExists(templateJsonPath)) {
|
|
33
|
+
try {
|
|
34
|
+
const templateConfig = await fs_extra_1.default.readJson(templateJsonPath);
|
|
35
|
+
discovered.frameworks.push({
|
|
36
|
+
...templateConfig,
|
|
37
|
+
name: frameworkName,
|
|
38
|
+
category: 'framework',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Silently skip invalid templates
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Discover database modules
|
|
48
|
+
const databaseDir = path_1.default.join(modulesDir, 'database');
|
|
49
|
+
if (await fs_extra_1.default.pathExists(databaseDir)) {
|
|
50
|
+
const dbModules = await fs_extra_1.default.readdir(databaseDir);
|
|
51
|
+
// Sort to ensure consistent order: prisma first, then others
|
|
52
|
+
dbModules.sort((a, b) => {
|
|
53
|
+
if (a === 'prisma')
|
|
54
|
+
return -1;
|
|
55
|
+
if (b === 'prisma')
|
|
56
|
+
return 1;
|
|
57
|
+
return a.localeCompare(b);
|
|
58
|
+
});
|
|
59
|
+
for (const moduleName of dbModules) {
|
|
60
|
+
const modulePath = path_1.default.join(databaseDir, moduleName);
|
|
61
|
+
const moduleJsonPath = path_1.default.join(modulePath, 'module.json');
|
|
62
|
+
if (await fs_extra_1.default.pathExists(moduleJsonPath)) {
|
|
63
|
+
try {
|
|
64
|
+
const metadata = await fs_extra_1.default.readJson(moduleJsonPath);
|
|
65
|
+
discovered.databases.push(metadata);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// Silently skip invalid modules
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Discover auth modules
|
|
74
|
+
const authDir = path_1.default.join(modulesDir, 'auth');
|
|
75
|
+
if (await fs_extra_1.default.pathExists(authDir)) {
|
|
76
|
+
const authModules = await fs_extra_1.default.readdir(authDir);
|
|
77
|
+
for (const moduleName of authModules) {
|
|
78
|
+
const modulePath = path_1.default.join(authDir, moduleName);
|
|
79
|
+
const moduleJsonPath = path_1.default.join(modulePath, 'module.json');
|
|
80
|
+
if (await fs_extra_1.default.pathExists(moduleJsonPath)) {
|
|
81
|
+
try {
|
|
82
|
+
const metadata = await fs_extra_1.default.readJson(moduleJsonPath);
|
|
83
|
+
discovered.auth.push(metadata);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// Silently skip invalid modules
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return discovered;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get valid database options for CLI
|
|
95
|
+
*/
|
|
96
|
+
function getValidDatabaseOptions(databases) {
|
|
97
|
+
const options = ['none'];
|
|
98
|
+
for (const db of databases) {
|
|
99
|
+
if (db.name === 'prisma') {
|
|
100
|
+
// For Prisma, add provider-specific options
|
|
101
|
+
options.push('prisma-postgresql', 'prisma-mongodb', 'prisma-mysql', 'prisma-sqlite');
|
|
102
|
+
}
|
|
103
|
+
else if (db.name === 'mongoose') {
|
|
104
|
+
options.push('mongoose-mongodb', 'mongoose');
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// For other databases, add the name directly
|
|
108
|
+
options.push(db.name);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return options;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get valid auth options for CLI
|
|
115
|
+
*/
|
|
116
|
+
function getValidAuthOptions(authModules) {
|
|
117
|
+
const options = ['none'];
|
|
118
|
+
for (const auth of authModules) {
|
|
119
|
+
options.push(auth.name);
|
|
120
|
+
}
|
|
121
|
+
return options;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Parse database option into database name and provider
|
|
125
|
+
*/
|
|
126
|
+
function parseDatabaseOption(dbOption) {
|
|
127
|
+
if (dbOption === 'none') {
|
|
128
|
+
return { database: 'none' };
|
|
129
|
+
}
|
|
130
|
+
if (dbOption.startsWith('prisma-')) {
|
|
131
|
+
const provider = dbOption.split('-')[1];
|
|
132
|
+
return { database: 'prisma', provider };
|
|
133
|
+
}
|
|
134
|
+
if (dbOption === 'mongoose-mongodb' || dbOption === 'mongoose') {
|
|
135
|
+
return { database: 'mongoose' };
|
|
136
|
+
}
|
|
137
|
+
return { database: dbOption };
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get compatible auth options for given framework and database
|
|
141
|
+
*/
|
|
142
|
+
function getCompatibleAuthOptions(authModules, framework, database) {
|
|
143
|
+
const compatible = [];
|
|
144
|
+
for (const auth of authModules) {
|
|
145
|
+
// Check if auth supports the framework
|
|
146
|
+
if (auth.supportedFrameworks && !auth.supportedFrameworks.includes(framework)) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
// Special compatibility rules
|
|
150
|
+
if (auth.name === 'authjs' && (database !== 'prisma' || framework !== 'nextjs')) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (auth.name === 'better-auth' && database === 'none' && framework !== 'react') {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
compatible.push({
|
|
157
|
+
name: auth.displayName,
|
|
158
|
+
value: auth.name
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
// Add "None" at the end
|
|
162
|
+
compatible.push({ name: 'None', value: 'none' });
|
|
163
|
+
return compatible;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Get database choices for inquirer prompts
|
|
167
|
+
*/
|
|
168
|
+
function getDatabaseChoices(databases, framework) {
|
|
169
|
+
const choices = [];
|
|
170
|
+
for (const db of databases) {
|
|
171
|
+
// Check framework compatibility
|
|
172
|
+
if (db.supportedFrameworks && !db.supportedFrameworks.includes(framework)) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (db.name === 'prisma') {
|
|
176
|
+
choices.push({ name: 'Prisma (PostgreSQL)', value: 'prisma-postgresql' }, { name: 'Prisma (MongoDB)', value: 'prisma-mongodb' }, { name: 'Prisma (MySQL)', value: 'prisma-mysql' }, { name: 'Prisma (SQLite)', value: 'prisma-sqlite' });
|
|
177
|
+
}
|
|
178
|
+
else if (db.name === 'mongoose') {
|
|
179
|
+
choices.push({ name: 'Mongoose (MongoDB)', value: 'mongoose-mongodb' });
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
choices.push({ name: db.displayName, value: db.name });
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Add "None" at the end
|
|
186
|
+
choices.push({ name: 'None', value: 'none' });
|
|
187
|
+
return choices;
|
|
188
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface EnvVariable {
|
|
2
|
+
key: string;
|
|
3
|
+
value?: string;
|
|
4
|
+
required: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function addEnvVariables(projectRoot: string, variables: EnvVariable[], options?: {
|
|
7
|
+
force?: boolean;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
export declare function removeEnvVariables(projectRoot: string, keys: string[]): Promise<void>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.addEnvVariables = addEnvVariables;
|
|
7
|
+
exports.removeEnvVariables = removeEnvVariables;
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const logger_1 = require("../ui/logger");
|
|
11
|
+
const ENV_MARKER_START = "# StackKit:";
|
|
12
|
+
const ENV_MARKER_END = "# End StackKit";
|
|
13
|
+
async function addEnvVariables(projectRoot, variables, options = {}) {
|
|
14
|
+
const envExamplePath = path_1.default.join(projectRoot, ".env.example");
|
|
15
|
+
const envPath = path_1.default.join(projectRoot, ".env");
|
|
16
|
+
await appendToEnvFile(envExamplePath, variables, "example", options);
|
|
17
|
+
const envExists = await fs_extra_1.default.pathExists(envPath);
|
|
18
|
+
if (envExists || options.force) {
|
|
19
|
+
await appendToEnvFile(envPath, variables, "local", options);
|
|
20
|
+
}
|
|
21
|
+
logger_1.logger.success("Environment variables added");
|
|
22
|
+
}
|
|
23
|
+
async function appendToEnvFile(filePath, variables, fileType, options = {}) {
|
|
24
|
+
// Validate environment variable keys
|
|
25
|
+
for (const variable of variables) {
|
|
26
|
+
if (!/^[A-Z_][A-Z0-9_]*$/.test(variable.key)) {
|
|
27
|
+
throw new Error(`Invalid environment variable key: ${variable.key}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
let content = "";
|
|
31
|
+
if (await fs_extra_1.default.pathExists(filePath)) {
|
|
32
|
+
content = await fs_extra_1.default.readFile(filePath, "utf-8");
|
|
33
|
+
}
|
|
34
|
+
// If force, remove existing keys first to avoid duplicates
|
|
35
|
+
if (options.force) {
|
|
36
|
+
const keysToRemove = variables.map((v) => v.key);
|
|
37
|
+
await removeFromEnvFile(filePath, keysToRemove);
|
|
38
|
+
if (await fs_extra_1.default.pathExists(filePath)) {
|
|
39
|
+
content = await fs_extra_1.default.readFile(filePath, "utf-8");
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
content = "";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Check if variables already exist (after potential removal)
|
|
46
|
+
const existingKeys = new Set();
|
|
47
|
+
const lines = content.split("\n");
|
|
48
|
+
for (const line of lines) {
|
|
49
|
+
const match = line.match(/^([A-Z_][A-Z0-9_]*)=/);
|
|
50
|
+
if (match) {
|
|
51
|
+
existingKeys.add(match[1]);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const newVariables = variables.filter((v) => !existingKeys.has(v.key));
|
|
55
|
+
if (newVariables.length === 0) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// Ensure file ends with newline
|
|
59
|
+
if (content && !content.endsWith("\n")) {
|
|
60
|
+
content += "\n";
|
|
61
|
+
}
|
|
62
|
+
// Add marker and variables
|
|
63
|
+
content += "\n";
|
|
64
|
+
content += `${ENV_MARKER_START} Added by StackKit\n`;
|
|
65
|
+
for (const variable of newVariables) {
|
|
66
|
+
const value = fileType === "example" ? (variable.value || "") : (variable.value || "");
|
|
67
|
+
content += `${variable.key}=${value}\n`;
|
|
68
|
+
}
|
|
69
|
+
content += `${ENV_MARKER_END}\n`;
|
|
70
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(filePath));
|
|
71
|
+
await fs_extra_1.default.writeFile(filePath, content, "utf-8");
|
|
72
|
+
}
|
|
73
|
+
async function removeEnvVariables(projectRoot, keys) {
|
|
74
|
+
const envExamplePath = path_1.default.join(projectRoot, ".env.example");
|
|
75
|
+
const envPath = path_1.default.join(projectRoot, ".env");
|
|
76
|
+
await removeFromEnvFile(envExamplePath, keys);
|
|
77
|
+
if (await fs_extra_1.default.pathExists(envPath)) {
|
|
78
|
+
await removeFromEnvFile(envPath, keys);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async function removeFromEnvFile(filePath, keys) {
|
|
82
|
+
if (!(await fs_extra_1.default.pathExists(filePath))) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
const content = await fs_extra_1.default.readFile(filePath, "utf-8");
|
|
87
|
+
const lines = content.split("\n");
|
|
88
|
+
const newLines = [];
|
|
89
|
+
let inStackKitBlock = false;
|
|
90
|
+
for (const line of lines) {
|
|
91
|
+
if (line.includes(ENV_MARKER_START)) {
|
|
92
|
+
inStackKitBlock = true;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (line.includes(ENV_MARKER_END)) {
|
|
96
|
+
inStackKitBlock = false;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const match = line.match(/^([A-Z_][A-Z0-9_]*)=/);
|
|
100
|
+
if (match && keys.includes(match[1])) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (!inStackKitBlock || !line.startsWith("#")) {
|
|
104
|
+
newLines.push(line);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
while (newLines.length > 0 && newLines[newLines.length - 1].trim() === "") {
|
|
108
|
+
newLines.pop();
|
|
109
|
+
}
|
|
110
|
+
await fs_extra_1.default.writeFile(filePath, newLines.join("\n"), "utf-8");
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
logger_1.logger.error(`Failed to remove env variables from ${filePath}: ${error}`);
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface FrameworkConfig {
|
|
2
|
+
name: string;
|
|
3
|
+
displayName: string;
|
|
4
|
+
compatibility: {
|
|
5
|
+
databases: string[];
|
|
6
|
+
auth: string[];
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export interface ModuleConfig {
|
|
10
|
+
name: string;
|
|
11
|
+
displayName: string;
|
|
12
|
+
type: 'database' | 'auth';
|
|
13
|
+
compatibility?: {
|
|
14
|
+
frameworks?: string[];
|
|
15
|
+
databases?: string[];
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export declare class FrameworkUtils {
|
|
19
|
+
private static frameworkConfigs;
|
|
20
|
+
static loadFrameworkConfig(frameworkName: string, templatesDir: string): Promise<FrameworkConfig>;
|
|
21
|
+
static isCompatible(framework: string, database?: string, auth?: string): boolean;
|
|
22
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.FrameworkUtils = void 0;
|
|
37
|
+
const fs = __importStar(require("fs-extra"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
|
|
40
|
+
class FrameworkUtils {
|
|
41
|
+
static async loadFrameworkConfig(frameworkName, templatesDir) {
|
|
42
|
+
const configPath = path.join(templatesDir, frameworkName, 'template.json');
|
|
43
|
+
if (await fs.pathExists(configPath)) {
|
|
44
|
+
const config = await fs.readJson(configPath);
|
|
45
|
+
this.frameworkConfigs.set(frameworkName, config);
|
|
46
|
+
return config;
|
|
47
|
+
}
|
|
48
|
+
// Default config if no template.json exists
|
|
49
|
+
const defaultConfig = {
|
|
50
|
+
name: frameworkName,
|
|
51
|
+
displayName: frameworkName.charAt(0).toUpperCase() + frameworkName.slice(1),
|
|
52
|
+
compatibility: {
|
|
53
|
+
databases: ['prisma', 'mongoose'],
|
|
54
|
+
auth: ['better-auth', 'authjs'],
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
this.frameworkConfigs.set(frameworkName, defaultConfig);
|
|
58
|
+
return defaultConfig;
|
|
59
|
+
}
|
|
60
|
+
static isCompatible(framework, database, auth) {
|
|
61
|
+
const config = this.frameworkConfigs.get(framework);
|
|
62
|
+
if (!config)
|
|
63
|
+
return true; // Assume compatible if no config
|
|
64
|
+
if (database && !config.compatibility.databases.includes(database)) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
if (auth && !config.compatibility.auth.includes(auth)) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.FrameworkUtils = FrameworkUtils;
|
|
74
|
+
FrameworkUtils.frameworkConfigs = new Map();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface PackageJsonConfig {
|
|
2
|
+
dependencies?: Record<string, string>;
|
|
3
|
+
devDependencies?: Record<string, string>;
|
|
4
|
+
scripts?: Record<string, string>;
|
|
5
|
+
}
|
|
6
|
+
export declare function copyBaseFramework(templatesDir: string, targetDir: string, framework: string): Promise<void>;
|
|
7
|
+
export declare function mergePackageJson(targetDir: string, config: PackageJsonConfig): Promise<void>;
|
|
8
|
+
export declare function mergeEnvFile(targetDir: string, envVars: Record<string, string>): Promise<void>;
|
|
9
|
+
export declare function copyTemplate(templatePath: string, targetPath: string, projectName: string): Promise<void>;
|
|
10
|
+
export declare function createFile(targetPath: string, content: string, options?: {
|
|
11
|
+
force?: boolean;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
export declare function readFile(filePath: string): Promise<string>;
|
|
14
|
+
export declare function fileExists(filePath: string): Promise<boolean>;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.copyBaseFramework = copyBaseFramework;
|
|
7
|
+
exports.mergePackageJson = mergePackageJson;
|
|
8
|
+
exports.mergeEnvFile = mergeEnvFile;
|
|
9
|
+
exports.copyTemplate = copyTemplate;
|
|
10
|
+
exports.createFile = createFile;
|
|
11
|
+
exports.readFile = readFile;
|
|
12
|
+
exports.fileExists = fileExists;
|
|
13
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
14
|
+
const path_1 = __importDefault(require("path"));
|
|
15
|
+
const logger_1 = require("../ui/logger");
|
|
16
|
+
async function copyBaseFramework(templatesDir, targetDir, framework) {
|
|
17
|
+
const baseDir = path_1.default.join(templatesDir, framework);
|
|
18
|
+
if (!(await fs_extra_1.default.pathExists(baseDir))) {
|
|
19
|
+
throw new Error(`Base template not found for framework: ${framework}\n` + `Expected at: ${baseDir}`);
|
|
20
|
+
}
|
|
21
|
+
await fs_extra_1.default.copy(baseDir, targetDir, {
|
|
22
|
+
filter: (src) => {
|
|
23
|
+
const basename = path_1.default.basename(src);
|
|
24
|
+
return !["template.json", "config.json", "node_modules", ".git"].includes(basename);
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
async function mergePackageJson(targetDir, config) {
|
|
29
|
+
const pkgPath = path_1.default.join(targetDir, "package.json");
|
|
30
|
+
if (!(await fs_extra_1.default.pathExists(pkgPath))) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const pkg = await fs_extra_1.default.readJson(pkgPath);
|
|
34
|
+
if (config.dependencies) {
|
|
35
|
+
pkg.dependencies = { ...pkg.dependencies, ...config.dependencies };
|
|
36
|
+
}
|
|
37
|
+
if (config.devDependencies) {
|
|
38
|
+
pkg.devDependencies = { ...pkg.devDependencies, ...config.devDependencies };
|
|
39
|
+
}
|
|
40
|
+
if (config.scripts) {
|
|
41
|
+
pkg.scripts = { ...pkg.scripts, ...config.scripts };
|
|
42
|
+
}
|
|
43
|
+
await fs_extra_1.default.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
44
|
+
}
|
|
45
|
+
async function mergeEnvFile(targetDir, envVars) {
|
|
46
|
+
const envPath = path_1.default.join(targetDir, ".env");
|
|
47
|
+
let existingEnv = "";
|
|
48
|
+
if (await fs_extra_1.default.pathExists(envPath)) {
|
|
49
|
+
existingEnv = await fs_extra_1.default.readFile(envPath, "utf-8");
|
|
50
|
+
}
|
|
51
|
+
const envLines = existingEnv.split("\n").filter((line) => line.trim() !== "");
|
|
52
|
+
// Add new variables
|
|
53
|
+
for (const [key, value] of Object.entries(envVars)) {
|
|
54
|
+
const existingIndex = envLines.findIndex((line) => line.startsWith(`${key}=`));
|
|
55
|
+
if (existingIndex !== -1) {
|
|
56
|
+
envLines[existingIndex] = `${key}=${value}`;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
envLines.push(`${key}=${value}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
await fs_extra_1.default.writeFile(envPath, envLines.join("\n") + "\n", "utf-8");
|
|
63
|
+
}
|
|
64
|
+
async function copyTemplate(templatePath, targetPath, projectName) {
|
|
65
|
+
if (!(await fs_extra_1.default.pathExists(templatePath))) {
|
|
66
|
+
throw new Error(`Template not found: ${templatePath}`);
|
|
67
|
+
}
|
|
68
|
+
// Create target directory
|
|
69
|
+
await fs_extra_1.default.ensureDir(targetPath);
|
|
70
|
+
// Copy all files
|
|
71
|
+
await fs_extra_1.default.copy(templatePath, targetPath, {
|
|
72
|
+
filter: (src) => {
|
|
73
|
+
const basename = path_1.default.basename(src);
|
|
74
|
+
// Skip template.json metadata file and node_modules
|
|
75
|
+
return basename !== "template.json" && basename !== "node_modules";
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
// Update package.json with project name
|
|
79
|
+
const packageJsonPath = path_1.default.join(targetPath, "package.json");
|
|
80
|
+
if (await fs_extra_1.default.pathExists(packageJsonPath)) {
|
|
81
|
+
const packageJson = await fs_extra_1.default.readJSON(packageJsonPath);
|
|
82
|
+
packageJson.name = projectName;
|
|
83
|
+
await fs_extra_1.default.writeJSON(packageJsonPath, packageJson, { spaces: 2 });
|
|
84
|
+
}
|
|
85
|
+
logger_1.logger.success(`Template copied to ${targetPath}`);
|
|
86
|
+
}
|
|
87
|
+
async function createFile(targetPath, content, options = {}) {
|
|
88
|
+
const exists = await fs_extra_1.default.pathExists(targetPath);
|
|
89
|
+
if (exists && !options.force) {
|
|
90
|
+
logger_1.logger.warn(`File already exists: ${targetPath} (use --force to overwrite)`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(targetPath));
|
|
94
|
+
await fs_extra_1.default.writeFile(targetPath, content, "utf-8");
|
|
95
|
+
}
|
|
96
|
+
async function readFile(filePath) {
|
|
97
|
+
return fs_extra_1.default.readFile(filePath, "utf-8");
|
|
98
|
+
}
|
|
99
|
+
async function fileExists(filePath) {
|
|
100
|
+
return fs_extra_1.default.pathExists(filePath);
|
|
101
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { FrameworkConfig } from '../framework/framework-utils';
|
|
2
|
+
export interface GenerationContext {
|
|
3
|
+
framework: string;
|
|
4
|
+
database?: string;
|
|
5
|
+
auth?: string;
|
|
6
|
+
features?: string[];
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface TemplateCondition {
|
|
10
|
+
framework?: string | string[];
|
|
11
|
+
database?: string | string[];
|
|
12
|
+
auth?: string | string[];
|
|
13
|
+
features?: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface Operation {
|
|
16
|
+
type: 'create-file' | 'patch-file' | 'add-dependency' | 'add-script' | 'add-env' | 'run-command';
|
|
17
|
+
description?: string;
|
|
18
|
+
condition?: TemplateCondition;
|
|
19
|
+
priority?: number;
|
|
20
|
+
source?: string;
|
|
21
|
+
destination?: string;
|
|
22
|
+
content?: string;
|
|
23
|
+
operations?: PatchOperation[];
|
|
24
|
+
dependencies?: Record<string, string>;
|
|
25
|
+
devDependencies?: Record<string, string>;
|
|
26
|
+
scripts?: Record<string, string>;
|
|
27
|
+
envVars?: Record<string, string>;
|
|
28
|
+
command?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface PatchOperation {
|
|
31
|
+
type: 'add-import' | 'add-code' | 'replace-code' | 'add-to-top' | 'add-to-bottom';
|
|
32
|
+
condition?: TemplateCondition;
|
|
33
|
+
imports?: string[];
|
|
34
|
+
code?: string;
|
|
35
|
+
after?: string;
|
|
36
|
+
before?: string;
|
|
37
|
+
replace?: string;
|
|
38
|
+
content?: string;
|
|
39
|
+
source?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface GeneratorConfig {
|
|
42
|
+
name: string;
|
|
43
|
+
type: 'framework' | 'database' | 'auth';
|
|
44
|
+
priority: number;
|
|
45
|
+
operations?: Operation[];
|
|
46
|
+
dependencies?: Record<string, string>;
|
|
47
|
+
devDependencies?: Record<string, string>;
|
|
48
|
+
scripts?: Record<string, string>;
|
|
49
|
+
envVars?: Record<string, string>;
|
|
50
|
+
postInstall?: string[];
|
|
51
|
+
}
|
|
52
|
+
export declare class AdvancedCodeGenerator {
|
|
53
|
+
private generators;
|
|
54
|
+
private frameworkConfig;
|
|
55
|
+
private postInstallCommands;
|
|
56
|
+
constructor(frameworkConfig: FrameworkConfig);
|
|
57
|
+
loadGenerators(modulesPath: string): Promise<void>;
|
|
58
|
+
private evaluateCondition;
|
|
59
|
+
private processTemplate;
|
|
60
|
+
private processVariableDefinitions;
|
|
61
|
+
private processTemplateRecursive;
|
|
62
|
+
generate(selectedModules: {
|
|
63
|
+
framework: string;
|
|
64
|
+
database?: string;
|
|
65
|
+
auth?: string;
|
|
66
|
+
prismaProvider?: string;
|
|
67
|
+
}, features: string[], outputPath: string): Promise<string[]>;
|
|
68
|
+
private executeOperation;
|
|
69
|
+
private copyTemplate;
|
|
70
|
+
private processOperationTemplates;
|
|
71
|
+
private executeCreateFile;
|
|
72
|
+
private executePatchFile;
|
|
73
|
+
private executeAddDependency;
|
|
74
|
+
private executeAddScript;
|
|
75
|
+
private executeAddEnv;
|
|
76
|
+
private executeRunCommand;
|
|
77
|
+
private generatePackageJson;
|
|
78
|
+
getAvailableGenerators(): {
|
|
79
|
+
frameworks: string[];
|
|
80
|
+
databases: string[];
|
|
81
|
+
auths: string[];
|
|
82
|
+
};
|
|
83
|
+
}
|