fragment-ts 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +0 -0
- package/base.ts +1810 -0
- package/base2.ts +968 -0
- package/bin/frg.ts +5 -0
- package/config/fragment.lock.yaml +0 -0
- package/config/fragment.yaml +0 -0
- package/dist/app.d.ts +15 -0
- package/dist/app.js +90 -0
- package/dist/auth/auth.controller.d.ts +10 -0
- package/dist/auth/auth.controller.js +87 -0
- package/dist/auth/auth.middleware.d.ts +2 -0
- package/dist/auth/auth.middleware.js +24 -0
- package/dist/auth/auth.service.d.ts +20 -0
- package/dist/auth/auth.service.js +143 -0
- package/dist/auth/dto/login.dto.d.ts +9 -0
- package/dist/auth/dto/login.dto.js +2 -0
- package/dist/cli/cli.d.ts +12 -0
- package/dist/cli/cli.js +186 -0
- package/dist/cli/commands/build.command.d.ts +3 -0
- package/dist/cli/commands/build.command.js +23 -0
- package/dist/cli/commands/config.command.d.ts +6 -0
- package/dist/cli/commands/config.command.js +284 -0
- package/dist/cli/commands/generate.command.d.ts +8 -0
- package/dist/cli/commands/generate.command.js +180 -0
- package/dist/cli/commands/init.command.d.ts +7 -0
- package/dist/cli/commands/init.command.js +380 -0
- package/dist/cli/commands/migrate.command.d.ts +7 -0
- package/dist/cli/commands/migrate.command.js +116 -0
- package/dist/cli/commands/serve.command.d.ts +6 -0
- package/dist/cli/commands/serve.command.js +31 -0
- package/dist/cli/templates/controller.template.d.ts +1 -0
- package/dist/cli/templates/controller.template.js +52 -0
- package/dist/cli/templates/entity.template.d.ts +1 -0
- package/dist/cli/templates/entity.template.js +23 -0
- package/dist/cli/templates/repository.template.d.ts +1 -0
- package/dist/cli/templates/repository.template.js +43 -0
- package/dist/cli/templates/service.template.d.ts +1 -0
- package/dist/cli/templates/service.template.js +43 -0
- package/dist/cli/utils/file-generator.d.ts +9 -0
- package/dist/cli/utils/file-generator.js +67 -0
- package/dist/cli/utils/logger.d.ts +14 -0
- package/dist/cli/utils/logger.js +49 -0
- package/dist/controllers/health.controller.d.ts +13 -0
- package/dist/controllers/health.controller.js +50 -0
- package/dist/core/config/config-loader.d.ts +31 -0
- package/dist/core/config/config-loader.js +98 -0
- package/dist/core/container/di-container.d.ts +9 -0
- package/dist/core/container/di-container.js +37 -0
- package/dist/core/decorators/auth-guard.decorator.d.ts +3 -0
- package/dist/core/decorators/auth-guard.decorator.js +18 -0
- package/dist/core/decorators/autowire.decorator.d.ts +3 -0
- package/dist/core/decorators/autowire.decorator.js +17 -0
- package/dist/core/decorators/controller.decorator.d.ts +4 -0
- package/dist/core/decorators/controller.decorator.js +16 -0
- package/dist/core/decorators/injectable.decorator.d.ts +3 -0
- package/dist/core/decorators/injectable.decorator.js +14 -0
- package/dist/core/decorators/middleware.decorator.d.ts +3 -0
- package/dist/core/decorators/middleware.decorator.js +20 -0
- package/dist/core/decorators/repository.decorator.d.ts +1 -0
- package/dist/core/decorators/repository.decorator.js +7 -0
- package/dist/core/decorators/route.decorator.d.ts +14 -0
- package/dist/core/decorators/route.decorator.js +32 -0
- package/dist/core/decorators/service.decorator.d.ts +1 -0
- package/dist/core/decorators/service.decorator.js +7 -0
- package/dist/core/openai/openai-client.d.ts +12 -0
- package/dist/core/openai/openai-client.js +93 -0
- package/dist/database/data-source.d.ts +4 -0
- package/dist/database/data-source.js +26 -0
- package/dist/entities/session.entity.d.ts +9 -0
- package/dist/entities/session.entity.js +45 -0
- package/dist/entities/user.entity.d.ts +10 -0
- package/dist/entities/user.entity.js +48 -0
- package/dist/middlewares/logging.middleware.d.ts +2 -0
- package/dist/middlewares/logging.middleware.js +28 -0
- package/dist/repositories/session.repository.d.ts +9 -0
- package/dist/repositories/session.repository.js +50 -0
- package/dist/repositories/user.repository.d.ts +10 -0
- package/dist/repositories/user.repository.js +43 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +30 -0
- package/dist/services/health.service.d.ts +13 -0
- package/dist/services/health.service.js +44 -0
- package/package.json +46 -0
- package/readme.md +120 -0
- package/src/app.ts +121 -0
- package/src/auth/auth.controller.ts +52 -0
- package/src/auth/auth.middleware.ts +27 -0
- package/src/auth/auth.service.ts +110 -0
- package/src/auth/dto/login.dto.ts +11 -0
- package/src/cli/cli.ts +212 -0
- package/src/cli/commands/build.command.ts +24 -0
- package/src/cli/commands/config.command.ts +280 -0
- package/src/cli/commands/generate.command.ts +170 -0
- package/src/cli/commands/init.command.ts +395 -0
- package/src/cli/commands/migrate.command.ts +118 -0
- package/src/cli/commands/serve.command.ts +37 -0
- package/src/cli/templates/controller.template.ts +51 -0
- package/src/cli/templates/entity.template.ts +22 -0
- package/src/cli/templates/repository.template.ts +42 -0
- package/src/cli/templates/service.template.ts +42 -0
- package/src/cli/utils/file-generator.ts +37 -0
- package/src/cli/utils/logger.ts +52 -0
- package/src/controllers/health.controller.ts +24 -0
- package/src/core/config/config-loader.ts +98 -0
- package/src/core/container/di-container.ts +43 -0
- package/src/core/decorators/auth-guard.decorator.ts +15 -0
- package/src/core/decorators/autowire.decorator.ts +18 -0
- package/src/core/decorators/controller.decorator.ts +15 -0
- package/src/core/decorators/injectable.decorator.ts +13 -0
- package/src/core/decorators/middleware.decorator.ts +18 -0
- package/src/core/decorators/repository.decorator.ts +6 -0
- package/src/core/decorators/route.decorator.ts +33 -0
- package/src/core/decorators/service.decorator.ts +6 -0
- package/src/core/openai/openai-client.ts +99 -0
- package/src/database/data-source.ts +29 -0
- package/src/entities/session.entity.ts +25 -0
- package/src/entities/user.entity.ts +27 -0
- package/src/middlewares/logging.middleware.ts +28 -0
- package/src/repositories/session.repository.ts +42 -0
- package/src/repositories/user.repository.ts +37 -0
- package/src/server.ts +32 -0
- package/src/services/health.service.ts +29 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,380 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.InitCommand = void 0;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const child_process_1 = require("child_process");
|
|
43
|
+
const logger_1 = require("../utils/logger");
|
|
44
|
+
const file_generator_1 = require("../utils/file-generator");
|
|
45
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
46
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
47
|
+
class InitCommand {
|
|
48
|
+
async execute(projectName) {
|
|
49
|
+
logger_1.CLILogger.title('🔷 Fragment Framework Initializer');
|
|
50
|
+
const answers = await inquirer_1.default.prompt([
|
|
51
|
+
{
|
|
52
|
+
type: 'input',
|
|
53
|
+
name: 'projectName',
|
|
54
|
+
message: 'Project name:',
|
|
55
|
+
default: projectName || 'my-fragment-app',
|
|
56
|
+
validate: (input) => {
|
|
57
|
+
if (!/^[a-z0-9-]+$/.test(input)) {
|
|
58
|
+
return 'Project name must contain only lowercase letters, numbers, and hyphens';
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
type: 'list',
|
|
65
|
+
name: 'database',
|
|
66
|
+
message: 'Select database:',
|
|
67
|
+
choices: ['PostgreSQL', 'MySQL', 'SQLite', 'MongoDB'],
|
|
68
|
+
default: 'PostgreSQL'
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
type: 'confirm',
|
|
72
|
+
name: 'useOpenAI',
|
|
73
|
+
message: 'Enable OpenAI integration?',
|
|
74
|
+
default: true
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
type: 'confirm',
|
|
78
|
+
name: 'useAuth',
|
|
79
|
+
message: 'Include authentication system?',
|
|
80
|
+
default: true
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
type: 'list',
|
|
84
|
+
name: 'packageManager',
|
|
85
|
+
message: 'Package manager:',
|
|
86
|
+
choices: ['npm', 'yarn', 'pnpm'],
|
|
87
|
+
default: 'npm'
|
|
88
|
+
}
|
|
89
|
+
]);
|
|
90
|
+
const projectPath = path.join(process.cwd(), answers.projectName);
|
|
91
|
+
if (fs.existsSync(projectPath)) {
|
|
92
|
+
logger_1.CLILogger.error(`Directory ${answers.projectName} already exists`);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const spinner = logger_1.CLILogger.spinner('Creating project structure...');
|
|
96
|
+
try {
|
|
97
|
+
// Create project directory
|
|
98
|
+
file_generator_1.FileGenerator.createDirectory(projectPath);
|
|
99
|
+
// Create directory structure
|
|
100
|
+
const dirs = [
|
|
101
|
+
'src/controllers',
|
|
102
|
+
'src/services',
|
|
103
|
+
'src/repositories',
|
|
104
|
+
'src/entities',
|
|
105
|
+
'src/middlewares',
|
|
106
|
+
'src/core/decorators',
|
|
107
|
+
'src/core/container',
|
|
108
|
+
'src/core/config',
|
|
109
|
+
'src/database',
|
|
110
|
+
'config'
|
|
111
|
+
];
|
|
112
|
+
if (answers.useOpenAI) {
|
|
113
|
+
dirs.push('src/core/openai');
|
|
114
|
+
}
|
|
115
|
+
if (answers.useAuth) {
|
|
116
|
+
dirs.push('src/auth', 'src/auth/dto');
|
|
117
|
+
}
|
|
118
|
+
dirs.forEach(dir => {
|
|
119
|
+
file_generator_1.FileGenerator.createDirectory(path.join(projectPath, dir));
|
|
120
|
+
});
|
|
121
|
+
spinner.text = 'Generating configuration files...';
|
|
122
|
+
// Generate package.json
|
|
123
|
+
const packageJson = {
|
|
124
|
+
name: answers.projectName,
|
|
125
|
+
version: '1.0.0',
|
|
126
|
+
description: 'Fragment Framework Application',
|
|
127
|
+
main: 'dist/server.js',
|
|
128
|
+
scripts: {
|
|
129
|
+
dev: 'ts-node-dev --respawn --transpile-only src/server.ts',
|
|
130
|
+
build: 'tsc',
|
|
131
|
+
start: 'node dist/server.js',
|
|
132
|
+
'frg:generate': 'frg generate',
|
|
133
|
+
'frg:migrate': 'frg migrate'
|
|
134
|
+
},
|
|
135
|
+
dependencies: {
|
|
136
|
+
express: '^4.18.2',
|
|
137
|
+
typeorm: '^0.3.17',
|
|
138
|
+
'reflect-metadata': '^0.1.13',
|
|
139
|
+
bcrypt: '^5.1.1',
|
|
140
|
+
'js-yaml': '^4.1.0',
|
|
141
|
+
pino: '^8.16.0',
|
|
142
|
+
'pino-pretty': '^10.2.3'
|
|
143
|
+
},
|
|
144
|
+
devDependencies: {
|
|
145
|
+
'@types/express': '^4.17.20',
|
|
146
|
+
'@types/node': '^20.9.0',
|
|
147
|
+
'@types/bcrypt': '^5.0.2',
|
|
148
|
+
'@types/js-yaml': '^4.0.9',
|
|
149
|
+
typescript: '^5.2.2',
|
|
150
|
+
'ts-node': '^10.9.1',
|
|
151
|
+
'ts-node-dev': '^2.0.0'
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
// Add database driver
|
|
155
|
+
const dbDrivers = {
|
|
156
|
+
'PostgreSQL': 'pg@^8.11.3',
|
|
157
|
+
'MySQL': 'mysql2@^3.6.5',
|
|
158
|
+
'SQLite': 'sqlite3@^5.1.6',
|
|
159
|
+
'MongoDB': 'mongodb@^6.3.0'
|
|
160
|
+
};
|
|
161
|
+
packageJson.dependencies = {
|
|
162
|
+
...packageJson.dependencies,
|
|
163
|
+
[dbDrivers[answers.database].split('@')[0]]: dbDrivers[answers.database].split('@')[1]
|
|
164
|
+
};
|
|
165
|
+
file_generator_1.FileGenerator.writeFile(path.join(projectPath, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
166
|
+
// Generate tsconfig.json
|
|
167
|
+
const tsConfig = {
|
|
168
|
+
compilerOptions: {
|
|
169
|
+
target: 'ES2020',
|
|
170
|
+
module: 'commonjs',
|
|
171
|
+
lib: ['ES2020'],
|
|
172
|
+
outDir: './dist',
|
|
173
|
+
rootDir: './src',
|
|
174
|
+
strict: true,
|
|
175
|
+
esModuleInterop: true,
|
|
176
|
+
skipLibCheck: true,
|
|
177
|
+
forceConsistentCasingInFileNames: true,
|
|
178
|
+
resolveJsonModule: true,
|
|
179
|
+
experimentalDecorators: true,
|
|
180
|
+
emitDecoratorMetadata: true,
|
|
181
|
+
moduleResolution: 'node',
|
|
182
|
+
allowSyntheticDefaultImports: true
|
|
183
|
+
},
|
|
184
|
+
include: ['src/**/*'],
|
|
185
|
+
exclude: ['node_modules', 'dist']
|
|
186
|
+
};
|
|
187
|
+
file_generator_1.FileGenerator.writeFile(path.join(projectPath, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2));
|
|
188
|
+
// Generate fragment.yaml
|
|
189
|
+
const dbConfig = this.getDatabaseConfig(answers.database);
|
|
190
|
+
const fragmentConfig = `app:
|
|
191
|
+
name: ${answers.projectName}
|
|
192
|
+
port: 3000
|
|
193
|
+
env: development
|
|
194
|
+
|
|
195
|
+
database:
|
|
196
|
+
${dbConfig}
|
|
197
|
+
|
|
198
|
+
${answers.useOpenAI ? `openai:
|
|
199
|
+
apiKey: \${OPENAI_API_KEY}
|
|
200
|
+
model: gpt-4
|
|
201
|
+
` : ''}
|
|
202
|
+
${answers.useAuth ? `auth:
|
|
203
|
+
tokenExpiry: 7d
|
|
204
|
+
sessionExpiry: 30d
|
|
205
|
+
` : ''}`;
|
|
206
|
+
file_generator_1.FileGenerator.writeFile(path.join(projectPath, 'config/fragment.yaml'), fragmentConfig);
|
|
207
|
+
// Generate .env.example
|
|
208
|
+
let envExample = `NODE_ENV=development
|
|
209
|
+
PORT=3000
|
|
210
|
+
|
|
211
|
+
${this.getEnvTemplate(answers.database)}`;
|
|
212
|
+
if (answers.useOpenAI) {
|
|
213
|
+
envExample += '\nOPENAI_API_KEY=sk-your-openai-api-key';
|
|
214
|
+
}
|
|
215
|
+
file_generator_1.FileGenerator.writeFile(path.join(projectPath, '.env.example'), envExample);
|
|
216
|
+
// Generate .gitignore
|
|
217
|
+
const gitignore = `node_modules/
|
|
218
|
+
dist/
|
|
219
|
+
.env
|
|
220
|
+
*.log
|
|
221
|
+
.DS_Store
|
|
222
|
+
config/fragment.lock.yaml`;
|
|
223
|
+
file_generator_1.FileGenerator.writeFile(path.join(projectPath, '.gitignore'), gitignore);
|
|
224
|
+
// Generate README.md
|
|
225
|
+
const readme = this.generateReadme(answers.projectName, answers);
|
|
226
|
+
file_generator_1.FileGenerator.writeFile(path.join(projectPath, 'README.md'), readme);
|
|
227
|
+
spinner.text = 'Copying core framework files...';
|
|
228
|
+
// Copy all core files (decorators, container, config, etc.)
|
|
229
|
+
await this.copyFrameworkCore(projectPath, answers);
|
|
230
|
+
spinner.succeed('Project structure created');
|
|
231
|
+
// Install dependencies
|
|
232
|
+
const installSpinner = logger_1.CLILogger.spinner(`Installing dependencies with ${answers.packageManager}...`);
|
|
233
|
+
try {
|
|
234
|
+
(0, child_process_1.execSync)(`cd ${projectPath} && ${answers.packageManager} install`, {
|
|
235
|
+
stdio: 'pipe'
|
|
236
|
+
});
|
|
237
|
+
installSpinner.succeed('Dependencies installed');
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
installSpinner.fail('Failed to install dependencies');
|
|
241
|
+
logger_1.CLILogger.warning('You can install them manually by running:');
|
|
242
|
+
console.log(` cd ${answers.projectName} && ${answers.packageManager} install`);
|
|
243
|
+
}
|
|
244
|
+
// Success message
|
|
245
|
+
logger_1.CLILogger.box('🎉 Project Created Successfully!', [
|
|
246
|
+
`Project: ${answers.projectName}`,
|
|
247
|
+
`Location: ${projectPath}`,
|
|
248
|
+
`Database: ${answers.database}`,
|
|
249
|
+
`OpenAI: ${answers.useOpenAI ? 'Enabled' : 'Disabled'}`,
|
|
250
|
+
`Auth: ${answers.useAuth ? 'Enabled' : 'Disabled'}`
|
|
251
|
+
]);
|
|
252
|
+
console.log(chalk_1.default.bold('\nNext steps:'));
|
|
253
|
+
console.log(` 1. cd ${answers.projectName}`);
|
|
254
|
+
console.log(` 2. cp .env.example .env`);
|
|
255
|
+
console.log(` 3. Configure your database in .env`);
|
|
256
|
+
if (answers.useOpenAI) {
|
|
257
|
+
console.log(` 4. Add your OpenAI API key to .env`);
|
|
258
|
+
}
|
|
259
|
+
console.log(` ${answers.useOpenAI ? '5' : '4'}. ${answers.packageManager} run dev`);
|
|
260
|
+
logger_1.CLILogger.section('Available Commands:');
|
|
261
|
+
logger_1.CLILogger.table({
|
|
262
|
+
'frg generate controller <name>': 'Generate a new controller',
|
|
263
|
+
'frg generate service <name>': 'Generate a new service',
|
|
264
|
+
'frg generate resource <name>': 'Generate controller, service, repository & entity',
|
|
265
|
+
'frg config ai': 'Configure OpenAI settings',
|
|
266
|
+
'frg migrate': 'Run database migrations',
|
|
267
|
+
'frg serve': 'Start development server'
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
spinner.fail('Failed to create project');
|
|
272
|
+
logger_1.CLILogger.error(error.message);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
getDatabaseConfig(database) {
|
|
276
|
+
const configs = {
|
|
277
|
+
'PostgreSQL': ` type: postgres
|
|
278
|
+
host: \${DB_HOST:localhost}
|
|
279
|
+
port: \${DB_PORT:5432}
|
|
280
|
+
username: \${DB_USERNAME:postgres}
|
|
281
|
+
password: \${DB_PASSWORD:postgres}
|
|
282
|
+
database: \${DB_DATABASE:fragment_db}
|
|
283
|
+
synchronize: true
|
|
284
|
+
logging: false`,
|
|
285
|
+
'MySQL': ` type: mysql
|
|
286
|
+
host: \${DB_HOST:localhost}
|
|
287
|
+
port: \${DB_PORT:3306}
|
|
288
|
+
username: \${DB_USERNAME:root}
|
|
289
|
+
password: \${DB_PASSWORD:root}
|
|
290
|
+
database: \${DB_DATABASE:fragment_db}
|
|
291
|
+
synchronize: true
|
|
292
|
+
logging: false`,
|
|
293
|
+
'SQLite': ` type: sqlite
|
|
294
|
+
database: \${DB_DATABASE:database.sqlite}
|
|
295
|
+
synchronize: true
|
|
296
|
+
logging: false`,
|
|
297
|
+
'MongoDB': ` type: mongodb
|
|
298
|
+
host: \${DB_HOST:localhost}
|
|
299
|
+
port: \${DB_PORT:27017}
|
|
300
|
+
database: \${DB_DATABASE:fragment_db}
|
|
301
|
+
synchronize: true
|
|
302
|
+
logging: false`
|
|
303
|
+
};
|
|
304
|
+
return configs[database];
|
|
305
|
+
}
|
|
306
|
+
getEnvTemplate(database) {
|
|
307
|
+
if (database === 'SQLite') {
|
|
308
|
+
return 'DB_DATABASE=database.sqlite';
|
|
309
|
+
}
|
|
310
|
+
return `DB_HOST=localhost
|
|
311
|
+
DB_PORT=${database === 'PostgreSQL' ? '5432' : database === 'MySQL' ? '3306' : '27017'}
|
|
312
|
+
DB_USERNAME=${database === 'PostgreSQL' ? 'postgres' : 'root'}
|
|
313
|
+
DB_PASSWORD=${database === 'PostgreSQL' ? 'postgres' : 'root'}
|
|
314
|
+
DB_DATABASE=fragment_db`;
|
|
315
|
+
}
|
|
316
|
+
generateReadme(projectName, answers) {
|
|
317
|
+
return `# ${projectName}
|
|
318
|
+
|
|
319
|
+
A Fragment Framework application.
|
|
320
|
+
|
|
321
|
+
## Getting Started
|
|
322
|
+
|
|
323
|
+
\`\`\`bash
|
|
324
|
+
# Install dependencies
|
|
325
|
+
${answers.packageManager} install
|
|
326
|
+
|
|
327
|
+
# Configure environment
|
|
328
|
+
cp .env.example .env
|
|
329
|
+
|
|
330
|
+
# Start development server
|
|
331
|
+
${answers.packageManager} run dev
|
|
332
|
+
\`\`\`
|
|
333
|
+
|
|
334
|
+
## Fragment CLI Commands
|
|
335
|
+
|
|
336
|
+
\`\`\`bash
|
|
337
|
+
# Generate resources
|
|
338
|
+
frg generate controller <name> # Generate controller
|
|
339
|
+
frg generate service <name> # Generate service
|
|
340
|
+
frg generate repository <name> # Generate repository
|
|
341
|
+
frg generate entity <name> # Generate entity
|
|
342
|
+
frg generate resource <name> # Generate all of the above
|
|
343
|
+
|
|
344
|
+
# Configuration
|
|
345
|
+
frg config ai # Configure OpenAI settings
|
|
346
|
+
frg config db # Configure database settings
|
|
347
|
+
|
|
348
|
+
# Database
|
|
349
|
+
frg migrate # Run migrations
|
|
350
|
+
|
|
351
|
+
# Development
|
|
352
|
+
frg serve # Start development server
|
|
353
|
+
frg build # Build for production
|
|
354
|
+
\`\`\`
|
|
355
|
+
|
|
356
|
+
## Project Structure
|
|
357
|
+
|
|
358
|
+
\`\`\`
|
|
359
|
+
src/
|
|
360
|
+
├── controllers/ # HTTP request handlers
|
|
361
|
+
├── services/ # Business logic
|
|
362
|
+
├── repositories/ # Data access layer
|
|
363
|
+
├── entities/ # Database models
|
|
364
|
+
├── middlewares/ # Express middlewares
|
|
365
|
+
└── core/ # Framework core
|
|
366
|
+
\`\`\`
|
|
367
|
+
|
|
368
|
+
## Documentation
|
|
369
|
+
|
|
370
|
+
Visit [Fragment Framework Documentation](https://fragment-framework.dev) for more information.
|
|
371
|
+
`;
|
|
372
|
+
}
|
|
373
|
+
async copyFrameworkCore(projectPath, answers) {
|
|
374
|
+
// This would copy all the core framework files
|
|
375
|
+
// For brevity, I'll show the structure
|
|
376
|
+
// In a real implementation, these would be actual file copies
|
|
377
|
+
logger_1.CLILogger.info('Core framework files copied');
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
exports.InitCommand = InitCommand;
|
|
@@ -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.MigrateCommand = void 0;
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const logger_1 = require("../utils/logger");
|
|
9
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
10
|
+
class MigrateCommand {
|
|
11
|
+
async execute(action) {
|
|
12
|
+
if (!action) {
|
|
13
|
+
const answer = await inquirer_1.default.prompt([
|
|
14
|
+
{
|
|
15
|
+
type: 'list',
|
|
16
|
+
name: 'action',
|
|
17
|
+
message: 'Select migration action:',
|
|
18
|
+
choices: [
|
|
19
|
+
{ name: 'Run pending migrations', value: 'run' },
|
|
20
|
+
{ name: 'Generate new migration', value: 'generate' },
|
|
21
|
+
{ name: 'Revert last migration', value: 'revert' },
|
|
22
|
+
{ name: 'Show migration status', value: 'show' }
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
]);
|
|
26
|
+
action = answer.action;
|
|
27
|
+
}
|
|
28
|
+
switch (action) {
|
|
29
|
+
case 'run':
|
|
30
|
+
await this.runMigrations();
|
|
31
|
+
break;
|
|
32
|
+
case 'generate':
|
|
33
|
+
await this.generateMigration();
|
|
34
|
+
break;
|
|
35
|
+
case 'revert':
|
|
36
|
+
await this.revertMigration();
|
|
37
|
+
break;
|
|
38
|
+
case 'show':
|
|
39
|
+
await this.showMigrations();
|
|
40
|
+
break;
|
|
41
|
+
default:
|
|
42
|
+
logger_1.CLILogger.error(`Unknown action: ${action}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async runMigrations() {
|
|
46
|
+
logger_1.CLILogger.title('📦 Running Migrations');
|
|
47
|
+
const spinner = logger_1.CLILogger.spinner('Executing migrations...');
|
|
48
|
+
try {
|
|
49
|
+
(0, child_process_1.execSync)('npm run typeorm migration:run', { stdio: 'pipe' });
|
|
50
|
+
spinner.succeed('Migrations executed successfully');
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
spinner.fail('Migration failed');
|
|
54
|
+
logger_1.CLILogger.error(error.message);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async generateMigration() {
|
|
58
|
+
const answer = await inquirer_1.default.prompt([
|
|
59
|
+
{
|
|
60
|
+
type: 'input',
|
|
61
|
+
name: 'name',
|
|
62
|
+
message: 'Migration name:',
|
|
63
|
+
validate: (input) => {
|
|
64
|
+
if (!input)
|
|
65
|
+
return 'Name is required';
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
]);
|
|
70
|
+
logger_1.CLILogger.title(`📝 Generating Migration: ${answer.name}`);
|
|
71
|
+
const spinner = logger_1.CLILogger.spinner('Creating migration file...');
|
|
72
|
+
try {
|
|
73
|
+
(0, child_process_1.execSync)(`npm run typeorm migration:generate -- -n ${answer.name}`, { stdio: 'pipe' });
|
|
74
|
+
spinner.succeed('Migration generated successfully');
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
spinner.fail('Failed to generate migration');
|
|
78
|
+
logger_1.CLILogger.error(error.message);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async revertMigration() {
|
|
82
|
+
const confirm = await inquirer_1.default.prompt([
|
|
83
|
+
{
|
|
84
|
+
type: 'confirm',
|
|
85
|
+
name: 'confirmed',
|
|
86
|
+
message: 'Are you sure you want to revert the last migration?',
|
|
87
|
+
default: false
|
|
88
|
+
}
|
|
89
|
+
]);
|
|
90
|
+
if (!confirm.confirmed) {
|
|
91
|
+
logger_1.CLILogger.info('Migration revert cancelled');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
logger_1.CLILogger.title('⏪ Reverting Migration');
|
|
95
|
+
const spinner = logger_1.CLILogger.spinner('Reverting last migration...');
|
|
96
|
+
try {
|
|
97
|
+
(0, child_process_1.execSync)('npm run typeorm migration:revert', { stdio: 'pipe' });
|
|
98
|
+
spinner.succeed('Migration reverted successfully');
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
spinner.fail('Failed to revert migration');
|
|
102
|
+
logger_1.CLILogger.error(error.message);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async showMigrations() {
|
|
106
|
+
logger_1.CLILogger.title('📋 Migration Status');
|
|
107
|
+
try {
|
|
108
|
+
const output = (0, child_process_1.execSync)('npm run typeorm migration:show', { encoding: 'utf-8' });
|
|
109
|
+
console.log(output);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
logger_1.CLILogger.error('Failed to show migrations');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
exports.MigrateCommand = MigrateCommand;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ServeCommand = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const logger_1 = require("../utils/logger");
|
|
6
|
+
class ServeCommand {
|
|
7
|
+
async execute(options) {
|
|
8
|
+
logger_1.CLILogger.title('🚀 Starting Fragment Application');
|
|
9
|
+
const port = options.port || process.env.PORT || 3000;
|
|
10
|
+
const args = ['--respawn', '--transpile-only'];
|
|
11
|
+
if (options.watch !== false) {
|
|
12
|
+
args.push('--watch');
|
|
13
|
+
}
|
|
14
|
+
args.push('src/server.ts');
|
|
15
|
+
const env = { ...process.env, PORT: port.toString() };
|
|
16
|
+
logger_1.CLILogger.info(`Starting server on port ${port}...`);
|
|
17
|
+
const child = (0, child_process_1.spawn)('ts-node-dev', args, {
|
|
18
|
+
env,
|
|
19
|
+
stdio: 'inherit'
|
|
20
|
+
});
|
|
21
|
+
child.on('error', (error) => {
|
|
22
|
+
logger_1.CLILogger.error(`Failed to start server: ${error.message}`);
|
|
23
|
+
});
|
|
24
|
+
child.on('close', (code) => {
|
|
25
|
+
if (code !== 0) {
|
|
26
|
+
logger_1.CLILogger.error(`Server exited with code ${code}`);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.ServeCommand = ServeCommand;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function controllerTemplate(name: string, route: string): string;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.controllerTemplate = controllerTemplate;
|
|
4
|
+
function controllerTemplate(name, route) {
|
|
5
|
+
const className = name.endsWith('Controller') ? name : `${name}Controller`;
|
|
6
|
+
const serviceName = name.replace('Controller', '') + 'Service';
|
|
7
|
+
return `import { Controller } from '../core/decorators/controller.decorator';
|
|
8
|
+
import { Get, Post, Put, Delete } from '../core/decorators/route.decorator';
|
|
9
|
+
import { Injectable } from '../core/decorators/injectable.decorator';
|
|
10
|
+
import { Autowire } from '../core/decorators/autowire.decorator';
|
|
11
|
+
import { ${serviceName} } from '../services/${name.toLowerCase()}.service';
|
|
12
|
+
import { Request, Response } from 'express';
|
|
13
|
+
|
|
14
|
+
@Controller('${route}')
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class ${className} {
|
|
17
|
+
constructor(
|
|
18
|
+
@Autowire() private ${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}: ${serviceName}
|
|
19
|
+
) {}
|
|
20
|
+
|
|
21
|
+
@Get('/')
|
|
22
|
+
async findAll(req: Request, res: Response) {
|
|
23
|
+
const items = await this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}.findAll();
|
|
24
|
+
return res.json(items);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@Get('/:id')
|
|
28
|
+
async findOne(req: Request, res: Response) {
|
|
29
|
+
const item = await this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}.findById(parseInt(req.params.id));
|
|
30
|
+
return res.json(item);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@Post('/')
|
|
34
|
+
async create(req: Request, res: Response) {
|
|
35
|
+
const item = await this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}.create(req.body);
|
|
36
|
+
return res.status(201).json(item);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@Put('/:id')
|
|
40
|
+
async update(req: Request, res: Response) {
|
|
41
|
+
const item = await this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}.update(parseInt(req.params.id), req.body);
|
|
42
|
+
return res.json(item);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@Delete('/:id')
|
|
46
|
+
async delete(req: Request, res: Response) {
|
|
47
|
+
await this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}.delete(parseInt(req.params.id));
|
|
48
|
+
return res.status(204).send();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
`;
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function entityTemplate(name: string): string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.entityTemplate = entityTemplate;
|
|
4
|
+
function entityTemplate(name) {
|
|
5
|
+
const className = name.endsWith('Entity') ? name.replace('Entity', '') : name;
|
|
6
|
+
return `import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
|
|
7
|
+
|
|
8
|
+
@Entity('${className.toLowerCase()}s')
|
|
9
|
+
export class ${className} {
|
|
10
|
+
@PrimaryGeneratedColumn()
|
|
11
|
+
id!: number;
|
|
12
|
+
|
|
13
|
+
@Column({ length: 255 })
|
|
14
|
+
name!: string;
|
|
15
|
+
|
|
16
|
+
@CreateDateColumn()
|
|
17
|
+
createdAt!: Date;
|
|
18
|
+
|
|
19
|
+
@UpdateDateColumn()
|
|
20
|
+
updatedAt!: Date;
|
|
21
|
+
}
|
|
22
|
+
`;
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function repositoryTemplate(name: string, entityName: string): string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.repositoryTemplate = repositoryTemplate;
|
|
4
|
+
function repositoryTemplate(name, entityName) {
|
|
5
|
+
const className = name.endsWith('Repository') ? name : `${name}Repository`;
|
|
6
|
+
return `import { Repository as TypeORMRepository } from 'typeorm';
|
|
7
|
+
import { Repository } from '../core/decorators/repository.decorator';
|
|
8
|
+
import { ${entityName} } from '../entities/${entityName.toLowerCase()}.entity';
|
|
9
|
+
import { AppDataSource } from '../database/data-source';
|
|
10
|
+
|
|
11
|
+
@Repository()
|
|
12
|
+
export class ${className} {
|
|
13
|
+
private repository: TypeORMRepository<${entityName}>;
|
|
14
|
+
|
|
15
|
+
constructor() {
|
|
16
|
+
this.repository = AppDataSource.getRepository(${entityName});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async findAll(): Promise<${entityName}[]> {
|
|
20
|
+
return await this.repository.find();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async findById(id: number): Promise<${entityName} | null> {
|
|
24
|
+
return await this.repository.findOne({ where: { id } });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async create(data: Partial<${entityName}>): Promise<${entityName}> {
|
|
28
|
+
const entity = this.repository.create(data);
|
|
29
|
+
return await this.repository.save(entity);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async update(id: number, data: Partial<${entityName}>): Promise<${entityName} | null> {
|
|
33
|
+
await this.repository.update(id, data);
|
|
34
|
+
return await this.findById(id);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async delete(id: number): Promise<boolean> {
|
|
38
|
+
const result = await this.repository.delete(id);
|
|
39
|
+
return result.affected ? result.affected > 0 : false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
`;
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function serviceTemplate(name: string): string;
|