@hed-hog/cli 0.0.12

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.
Files changed (116) hide show
  1. package/README.md +98 -0
  2. package/dist/scripts/deploy.d.ts +1 -0
  3. package/dist/scripts/deploy.js +84 -0
  4. package/dist/scripts/deploy.js.map +1 -0
  5. package/dist/src/app.module.d.ts +2 -0
  6. package/dist/src/app.module.js +58 -0
  7. package/dist/src/app.module.js.map +1 -0
  8. package/dist/src/commands/add.command.d.ts +14 -0
  9. package/dist/src/commands/add.command.js +58 -0
  10. package/dist/src/commands/add.command.js.map +1 -0
  11. package/dist/src/commands/dev.command/backupdb.subcommand.d.ts +10 -0
  12. package/dist/src/commands/dev.command/backupdb.subcommand.js +47 -0
  13. package/dist/src/commands/dev.command/backupdb.subcommand.js.map +1 -0
  14. package/dist/src/commands/dev.command/create-library.subcommand.d.ts +15 -0
  15. package/dist/src/commands/dev.command/create-library.subcommand.js +88 -0
  16. package/dist/src/commands/dev.command/create-library.subcommand.js.map +1 -0
  17. package/dist/src/commands/dev.command/hash-directory.subcommand.d.ts +12 -0
  18. package/dist/src/commands/dev.command/hash-directory.subcommand.js +70 -0
  19. package/dist/src/commands/dev.command/hash-directory.subcommand.js.map +1 -0
  20. package/dist/src/commands/dev.command/initdb.subcommand.d.ts +10 -0
  21. package/dist/src/commands/dev.command/initdb.subcommand.js +47 -0
  22. package/dist/src/commands/dev.command/initdb.subcommand.js.map +1 -0
  23. package/dist/src/commands/dev.command/reset.subcommand.d.ts +10 -0
  24. package/dist/src/commands/dev.command/reset.subcommand.js +47 -0
  25. package/dist/src/commands/dev.command/reset.subcommand.js.map +1 -0
  26. package/dist/src/commands/dev.command/restoredb.subcommand.d.ts +10 -0
  27. package/dist/src/commands/dev.command/restoredb.subcommand.js +47 -0
  28. package/dist/src/commands/dev.command/restoredb.subcommand.js.map +1 -0
  29. package/dist/src/commands/dev.command/route.subcommand.d.ts +10 -0
  30. package/dist/src/commands/dev.command/route.subcommand.js +47 -0
  31. package/dist/src/commands/dev.command/route.subcommand.js.map +1 -0
  32. package/dist/src/commands/dev.command/tsconfig.subcommand.d.ts +10 -0
  33. package/dist/src/commands/dev.command/tsconfig.subcommand.js +47 -0
  34. package/dist/src/commands/dev.command/tsconfig.subcommand.js.map +1 -0
  35. package/dist/src/commands/dev.command.d.ts +4 -0
  36. package/dist/src/commands/dev.command.js +40 -0
  37. package/dist/src/commands/dev.command.js.map +1 -0
  38. package/dist/src/commands/new.command.d.ts +43 -0
  39. package/dist/src/commands/new.command.js +436 -0
  40. package/dist/src/commands/new.command.js.map +1 -0
  41. package/dist/src/functions/to-pascal-case.d.ts +1 -0
  42. package/dist/src/functions/to-pascal-case.js +10 -0
  43. package/dist/src/functions/to-pascal-case.js.map +1 -0
  44. package/dist/src/main.d.ts +2 -0
  45. package/dist/src/main.js +10 -0
  46. package/dist/src/main.js.map +1 -0
  47. package/dist/src/modules/database/database.module.d.ts +2 -0
  48. package/dist/src/modules/database/database.module.js +22 -0
  49. package/dist/src/modules/database/database.module.js.map +1 -0
  50. package/dist/src/modules/database/database.service.d.ts +14 -0
  51. package/dist/src/modules/database/database.service.js +186 -0
  52. package/dist/src/modules/database/database.service.js.map +1 -0
  53. package/dist/src/modules/developer/developer.module.d.ts +2 -0
  54. package/dist/src/modules/developer/developer.module.js +22 -0
  55. package/dist/src/modules/developer/developer.module.js.map +1 -0
  56. package/dist/src/modules/developer/developer.service.d.ts +37 -0
  57. package/dist/src/modules/developer/developer.service.js +900 -0
  58. package/dist/src/modules/developer/developer.service.js.map +1 -0
  59. package/dist/src/modules/git/git.module.d.ts +2 -0
  60. package/dist/src/modules/git/git.module.js +23 -0
  61. package/dist/src/modules/git/git.module.js.map +1 -0
  62. package/dist/src/modules/git/git.service.d.ts +8 -0
  63. package/dist/src/modules/git/git.service.js +67 -0
  64. package/dist/src/modules/git/git.service.js.map +1 -0
  65. package/dist/src/modules/hedhog/hedhog.module.d.ts +2 -0
  66. package/dist/src/modules/hedhog/hedhog.module.js +41 -0
  67. package/dist/src/modules/hedhog/hedhog.module.js.map +1 -0
  68. package/dist/src/modules/hedhog/hedhog.service.d.ts +44 -0
  69. package/dist/src/modules/hedhog/hedhog.service.js +350 -0
  70. package/dist/src/modules/hedhog/hedhog.service.js.map +1 -0
  71. package/dist/src/modules/hedhog/services/file-system.service.d.ts +22 -0
  72. package/dist/src/modules/hedhog/services/file-system.service.js +230 -0
  73. package/dist/src/modules/hedhog/services/file-system.service.js.map +1 -0
  74. package/dist/src/modules/hedhog/services/migration.service.d.ts +39 -0
  75. package/dist/src/modules/hedhog/services/migration.service.js +767 -0
  76. package/dist/src/modules/hedhog/services/migration.service.js.map +1 -0
  77. package/dist/src/modules/hedhog/services/module.service.d.ts +10 -0
  78. package/dist/src/modules/hedhog/services/module.service.js +135 -0
  79. package/dist/src/modules/hedhog/services/module.service.js.map +1 -0
  80. package/dist/src/modules/hedhog/services/table.service.d.ts +49 -0
  81. package/dist/src/modules/hedhog/services/table.service.js +432 -0
  82. package/dist/src/modules/hedhog/services/table.service.js.map +1 -0
  83. package/dist/src/modules/hedhog/services/template.service.d.ts +13 -0
  84. package/dist/src/modules/hedhog/services/template.service.js +88 -0
  85. package/dist/src/modules/hedhog/services/template.service.js.map +1 -0
  86. package/dist/src/modules/package/package.module.d.ts +2 -0
  87. package/dist/src/modules/package/package.module.js +23 -0
  88. package/dist/src/modules/package/package.module.js.map +1 -0
  89. package/dist/src/modules/package/package.service.d.ts +9 -0
  90. package/dist/src/modules/package/package.service.js +94 -0
  91. package/dist/src/modules/package/package.service.js.map +1 -0
  92. package/dist/src/modules/runner/runner.module.d.ts +2 -0
  93. package/dist/src/modules/runner/runner.module.js +23 -0
  94. package/dist/src/modules/runner/runner.module.js.map +1 -0
  95. package/dist/src/modules/runner/runner.service.d.ts +14 -0
  96. package/dist/src/modules/runner/runner.service.js +69 -0
  97. package/dist/src/modules/runner/runner.service.js.map +1 -0
  98. package/dist/src/questions/database.question.d.ts +12 -0
  99. package/dist/src/questions/database.question.js +61 -0
  100. package/dist/src/questions/database.question.js.map +1 -0
  101. package/dist/src/questions/project-name.question.d.ts +3 -0
  102. package/dist/src/questions/project-name.question.js +34 -0
  103. package/dist/src/questions/project-name.question.js.map +1 -0
  104. package/dist/templates/database/touch_updated_at.sql.ejs +9 -0
  105. package/dist/templates/database/trg_touch_updated_at.sql.ejs +2 -0
  106. package/dist/templates/library/.eslintrc.js.ejs +9 -0
  107. package/dist/templates/library/.prettierrc.js.ejs +4 -0
  108. package/dist/templates/library/index.ts.ejs +1 -0
  109. package/dist/templates/library/init.app.module.ts.ejs +25 -0
  110. package/dist/templates/library/init.package.json.ejs +61 -0
  111. package/dist/templates/library/module.ts.ejs +15 -0
  112. package/dist/templates/library/package.json.ejs +36 -0
  113. package/dist/templates/library/tsconfig.json.ejs +11 -0
  114. package/dist/templates/library/tsconfig.production.json.ejs +46 -0
  115. package/dist/tsconfig.build.tsbuildinfo +1 -0
  116. package/package.json +104 -0
@@ -0,0 +1,900 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.DeveloperService = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const chalk = require("chalk");
15
+ const crypto_1 = require("crypto");
16
+ const ejs_1 = require("ejs");
17
+ const fs_1 = require("fs");
18
+ const promises_1 = require("fs/promises");
19
+ const inquirer_1 = require("inquirer");
20
+ const ora = require("ora");
21
+ const pathModule = require("path");
22
+ const to_pascal_case_1 = require("../../functions/to-pascal-case");
23
+ const database_service_1 = require("../database/database.service");
24
+ const file_system_service_1 = require("../hedhog/services/file-system.service");
25
+ const runner_service_1 = require("../runner/runner.service");
26
+ let DeveloperService = class DeveloperService {
27
+ runner;
28
+ fileSystem;
29
+ database;
30
+ verbose = false;
31
+ constructor(runner, fileSystem, database) {
32
+ this.runner = runner;
33
+ this.fileSystem = fileSystem;
34
+ this.database = database;
35
+ }
36
+ log(...args) {
37
+ if (this.verbose) {
38
+ console.log('\n', ...args);
39
+ }
40
+ }
41
+ async route(path, verbose = false) {
42
+ this.verbose = verbose;
43
+ const spinner = ora('Analyzing NestJS routes...').start();
44
+ try {
45
+ path = await this.getRootPath(path);
46
+ const apiPath = pathModule.join(path, 'apps', 'api');
47
+ if (!(0, fs_1.existsSync)(apiPath)) {
48
+ spinner.fail('API directory not found. Make sure you are in a NestJS project.');
49
+ return;
50
+ }
51
+ // Find main.ts
52
+ const mainPath = pathModule.join(apiPath, 'src', 'main.ts');
53
+ if (!(0, fs_1.existsSync)(mainPath)) {
54
+ spinner.fail('main.ts not found.');
55
+ return;
56
+ }
57
+ spinner.text = 'Reading main.ts...';
58
+ const mainContent = await (0, promises_1.readFile)(mainPath, 'utf8');
59
+ const mainModuleName = this.extractMainModule(mainContent);
60
+ if (!mainModuleName) {
61
+ spinner.fail('Could not determine main module from main.ts');
62
+ return;
63
+ }
64
+ this.log(chalk.blue(`Main module: ${mainModuleName}`));
65
+ // Find app.module.ts
66
+ const appModulePath = pathModule.join(apiPath, 'src', 'app.module.ts');
67
+ if (!(0, fs_1.existsSync)(appModulePath)) {
68
+ spinner.fail('app.module.ts not found.');
69
+ return;
70
+ }
71
+ spinner.text = 'Scanning controllers...';
72
+ const routes = await this.extractRoutes(apiPath);
73
+ spinner.succeed('Routes extracted successfully.');
74
+ if (routes.length === 0) {
75
+ console.log(chalk.yellow('\nNo routes found.'));
76
+ return;
77
+ }
78
+ // Display routes
79
+ console.log(chalk.green.bold('\n📋 Routes found:\n'));
80
+ const groupedRoutes = this.groupRoutesByController(routes);
81
+ for (const [controller, controllerRoutes] of Object.entries(groupedRoutes)) {
82
+ console.log(chalk.cyan.bold(`\n${controller}:`));
83
+ controllerRoutes.forEach((route) => {
84
+ const methodColor = this.getMethodColor(route.method);
85
+ const method = route.method.padEnd(7);
86
+ console.log(` ${methodColor(method)} ${chalk.white(route.path)}`);
87
+ });
88
+ }
89
+ console.log(chalk.gray(`\nTotal routes: ${routes.length}\n`));
90
+ }
91
+ catch (error) {
92
+ spinner.fail('Failed to analyze routes.');
93
+ console.error(chalk.red('Error analyzing routes:'), error);
94
+ throw error;
95
+ }
96
+ finally {
97
+ spinner.stop();
98
+ }
99
+ }
100
+ extractMainModule(content) {
101
+ // Look for patterns like: bootstrap(AppModule) or .create(AppModule)
102
+ const patterns = [
103
+ /NestFactory\.create\((\w+)\)/,
104
+ /bootstrap\((\w+)\)/,
105
+ /\.create\((\w+)\)/,
106
+ ];
107
+ for (const pattern of patterns) {
108
+ const match = content.match(pattern);
109
+ if (match) {
110
+ return match[1];
111
+ }
112
+ }
113
+ return null;
114
+ }
115
+ async extractRoutes(apiPath) {
116
+ const routes = [];
117
+ const srcPath = pathModule.join(apiPath, 'src');
118
+ const findControllers = async (dir) => {
119
+ const entries = await (0, promises_1.readdir)(dir, { withFileTypes: true });
120
+ for (const entry of entries) {
121
+ const fullPath = pathModule.join(dir, entry.name);
122
+ if (entry.isDirectory() && entry.name !== 'node_modules') {
123
+ await findControllers(fullPath);
124
+ }
125
+ else if (entry.isFile() && entry.name.endsWith('.controller.ts')) {
126
+ const controllerRoutes = await this.parseController(fullPath);
127
+ routes.push(...controllerRoutes);
128
+ }
129
+ }
130
+ };
131
+ await findControllers(srcPath);
132
+ return routes;
133
+ }
134
+ async parseController(filePath) {
135
+ const content = await (0, promises_1.readFile)(filePath, 'utf8');
136
+ const routes = [];
137
+ // Extract controller name and base path
138
+ const controllerMatch = content.match(/@Controller\(['"](.*?)['"]\)/);
139
+ const basePath = controllerMatch ? controllerMatch[1] : '';
140
+ // Extract class name
141
+ const classMatch = content.match(/export\s+class\s+(\w+Controller)/);
142
+ const controllerName = classMatch
143
+ ? classMatch[1]
144
+ : pathModule.basename(filePath, '.ts');
145
+ // HTTP methods to look for
146
+ const httpMethods = [
147
+ 'Get',
148
+ 'Post',
149
+ 'Put',
150
+ 'Delete',
151
+ 'Patch',
152
+ 'Options',
153
+ 'Head',
154
+ ];
155
+ for (const method of httpMethods) {
156
+ // Match patterns like @Get(), @Get('path'), @Get(':id')
157
+ const methodRegex = new RegExp(`@${method}\\((?:['"](.*?)['"])?\\)`, 'g');
158
+ let match;
159
+ while ((match = methodRegex.exec(content)) !== null) {
160
+ const routePath = match[1] || '';
161
+ const fullPath = this.buildFullPath(basePath, routePath);
162
+ routes.push({
163
+ controller: controllerName,
164
+ method: method.toUpperCase(),
165
+ path: fullPath,
166
+ filePath,
167
+ });
168
+ }
169
+ }
170
+ return routes;
171
+ }
172
+ buildFullPath(basePath, routePath) {
173
+ const base = basePath.startsWith('/') ? basePath : `/${basePath}`;
174
+ const route = routePath.startsWith('/') ? routePath : `/${routePath}`;
175
+ if (!routePath) {
176
+ return base || '/';
177
+ }
178
+ if (!basePath) {
179
+ return route;
180
+ }
181
+ return `${base}${route}`.replace(/\/+/g, '/');
182
+ }
183
+ groupRoutesByController(routes) {
184
+ const grouped = {};
185
+ for (const route of routes) {
186
+ if (!grouped[route.controller]) {
187
+ grouped[route.controller] = [];
188
+ }
189
+ grouped[route.controller].push({
190
+ method: route.method,
191
+ path: route.path,
192
+ });
193
+ }
194
+ // Sort routes within each controller
195
+ for (const controller in grouped) {
196
+ grouped[controller].sort((a, b) => {
197
+ if (a.path !== b.path) {
198
+ return a.path.localeCompare(b.path);
199
+ }
200
+ return a.method.localeCompare(b.method);
201
+ });
202
+ }
203
+ return grouped;
204
+ }
205
+ getMethodColor(method) {
206
+ const colors = {
207
+ GET: chalk.green,
208
+ POST: chalk.blue,
209
+ PUT: chalk.yellow,
210
+ DELETE: chalk.red,
211
+ PATCH: chalk.magenta,
212
+ OPTIONS: chalk.gray,
213
+ HEAD: chalk.cyan,
214
+ };
215
+ return colors[method] || chalk.white;
216
+ }
217
+ async createLibrary(path, libraryName, force = false, verbose = false, skipInstall = false) {
218
+ this.verbose = verbose;
219
+ this.log(chalk.blue('Starting library creation...'));
220
+ if (!libraryName) {
221
+ console.error(chalk.red('Library name is required.'));
222
+ return;
223
+ }
224
+ const libraryPath = pathModule.join(path, 'libraries', libraryName);
225
+ if ((0, fs_1.existsSync)(libraryPath)) {
226
+ if (force) {
227
+ this.log(chalk.yellow(`Library ${libraryName} already exists. Overwriting...`));
228
+ }
229
+ else {
230
+ console.error(chalk.red(`Library ${libraryName} already exists.`));
231
+ return;
232
+ }
233
+ }
234
+ await (0, promises_1.mkdir)(pathModule.join(libraryPath, 'src'), { recursive: true });
235
+ this.log(chalk.green(`Created directory: ${libraryPath}/src`));
236
+ const vars = {
237
+ path,
238
+ libraryPath,
239
+ libraryNamePascalCase: this.toPascalCase(libraryName),
240
+ libraryNameSnackCase: this.toSnackCase(libraryName),
241
+ libraryNameCamelCase: this.toCamelCase(libraryName),
242
+ libraryNameKebabCase: this.toKebabCase(libraryName),
243
+ libraryName: libraryName,
244
+ };
245
+ const files = [
246
+ {
247
+ template: '.eslintrc.js.ejs',
248
+ destination: `/.eslintrc.js`,
249
+ },
250
+ {
251
+ template: '.prettierrc.js.ejs',
252
+ destination: `/.prettierrc.js`,
253
+ },
254
+ {
255
+ template: 'package.json.ejs',
256
+ destination: `/package.json`,
257
+ },
258
+ {
259
+ template: 'tsconfig.json.ejs',
260
+ destination: `/tsconfig.json`,
261
+ },
262
+ {
263
+ template: 'tsconfig.production.json.ejs',
264
+ destination: `/tsconfig.production.json`,
265
+ },
266
+ {
267
+ template: 'module.ts.ejs',
268
+ destination: `/src/${vars.libraryNameKebabCase}.module.ts`,
269
+ },
270
+ {
271
+ template: 'index.ts.ejs',
272
+ destination: `/src/index.ts`,
273
+ },
274
+ ];
275
+ for (const file of files) {
276
+ const templatePath = pathModule.join(__dirname, '..', '..', 'templates', 'library', file.template);
277
+ const destinationPath = pathModule.join(path, 'libraries', libraryName, file.destination);
278
+ this.log(chalk.blue(`Rendering template: ${file.template}`));
279
+ const content = await (0, promises_1.readFile)(templatePath, 'utf8');
280
+ const renderedContent = await (0, ejs_1.render)(content, vars);
281
+ await (0, promises_1.writeFile)(destinationPath, renderedContent, 'utf8');
282
+ this.log(chalk.blue(`Created file: ${destinationPath}`));
283
+ }
284
+ this.log(chalk.green('Library files created successfully.'));
285
+ await this.updateTsconfigFiles(path, verbose);
286
+ if (!skipInstall) {
287
+ this.log(chalk.blue(`Installing dependencies for ${libraryName}...`));
288
+ await this.runner.executeCommand(runner_service_1.ProgramName.PNPM, ['install'], {
289
+ cwd: libraryPath,
290
+ }, true);
291
+ this.log(chalk.green(`Dependencies installed for ${libraryName}.`));
292
+ }
293
+ this.log(chalk.green(`Library ${libraryName} created successfully at ${libraryPath}.`));
294
+ }
295
+ async hashDirectory(path) {
296
+ const sum = (0, crypto_1.createHash)('sha256');
297
+ const paths = [];
298
+ async function scanDirectory(dir) {
299
+ const entries = await (0, promises_1.readdir)(dir, { withFileTypes: true });
300
+ for (const entry of entries) {
301
+ if (entry.name === 'node_modules')
302
+ continue;
303
+ const path = `${dir}/${entry.name}`;
304
+ if (entry.isDirectory()) {
305
+ await scanDirectory(path);
306
+ }
307
+ else {
308
+ const fileContent = await (0, promises_1.readFile)(path, 'utf8');
309
+ paths.push({ path, content: fileContent });
310
+ }
311
+ }
312
+ }
313
+ await scanDirectory(path);
314
+ const hash = sum.update(JSON.stringify(paths)).digest('hex');
315
+ return hash;
316
+ }
317
+ async updateTsconfigFiles(path, verbose = false) {
318
+ this.verbose = verbose;
319
+ this.log(chalk.blue('Updating tsconfig files...'));
320
+ const directories = [];
321
+ const scanDirs = ['libraries', 'packages'];
322
+ try {
323
+ for (const dir of scanDirs) {
324
+ const baseDir = pathModule.join(path, dir);
325
+ if (!(0, fs_1.existsSync)(baseDir) || !(0, fs_1.statSync)(baseDir).isDirectory())
326
+ continue;
327
+ const subDirs = (0, fs_1.readdirSync)(baseDir, { withFileTypes: true })
328
+ .filter((entry) => entry.isDirectory())
329
+ .map((entry) => pathModule.join(baseDir, entry.name));
330
+ for (const subDir of subDirs) {
331
+ const tsconfigPath = pathModule.join(subDir, 'tsconfig.json');
332
+ const tsconfigProdPath = pathModule.join(subDir, 'tsconfig.production.json');
333
+ if ((0, fs_1.existsSync)(tsconfigPath) || (0, fs_1.existsSync)(tsconfigProdPath)) {
334
+ directories.push(subDir);
335
+ this.log(chalk.blue(`Found tsconfig in: ${subDir}`));
336
+ }
337
+ }
338
+ }
339
+ const destinationPath = '/packages/typescript-config';
340
+ this.log(chalk.blue('Loading base tsconfig...'));
341
+ const baseData = require(pathModule.join(path, destinationPath, 'base.json'));
342
+ baseData.compilerOptions.paths = {
343
+ '@prisma/client': [
344
+ '../../packages/api-prisma/node_modules/.prisma/client',
345
+ ],
346
+ '@prisma/client/*': [
347
+ '../../packages/api-prisma/node_modules/.prisma/client/*',
348
+ ],
349
+ };
350
+ for (const subDir of directories) {
351
+ const packageName = require(pathModule.join(subDir, 'package.json')).name;
352
+ const relativePath = subDir.split(pathModule.sep).slice(-2);
353
+ baseData.compilerOptions.paths[packageName] = [
354
+ `../../${relativePath.join('/')}/src`,
355
+ ];
356
+ baseData.compilerOptions.paths[`${packageName}/*`] = [
357
+ `../../${relativePath.join('/')}/src/*`,
358
+ ];
359
+ this.log(chalk.blue(`Added path mapping for: ${packageName}`));
360
+ }
361
+ await (0, promises_1.writeFile)(pathModule.join(path, destinationPath, 'base.json'), JSON.stringify(baseData, null, 2), 'utf-8');
362
+ this.log(chalk.green('Updated base tsconfig.json successfully.'));
363
+ }
364
+ catch (error) {
365
+ console.error(error);
366
+ this.log(chalk.red('Failed to update tsconfig files.'));
367
+ }
368
+ }
369
+ toCamelCase(str) {
370
+ return str
371
+ .replace(/[-_](\w)/g, (_, c) => (c ? c.toUpperCase() : ''))
372
+ .replace(/^\w/, (c) => c.toLowerCase());
373
+ }
374
+ toKebabCase(str) {
375
+ return str
376
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
377
+ .replace(/[_\s]+/g, '-')
378
+ .toLowerCase();
379
+ }
380
+ toPascalCase(str) {
381
+ return (0, to_pascal_case_1.toPascalCase)(str);
382
+ }
383
+ toSnackCase(str) {
384
+ return str
385
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
386
+ .replace(/[_\s]+/g, '-')
387
+ .toLowerCase()
388
+ .replace(/-/g, '_');
389
+ }
390
+ async resetDevelopmentEnvironment(cwd, verbose = false) {
391
+ this.verbose = verbose;
392
+ const spinner = ora('Resetting development environment...').start();
393
+ try {
394
+ await this.removeLibrariesDirectory(cwd, spinner);
395
+ await this.removeMigrationFiles(cwd, spinner);
396
+ await this.resetAppModuleFile(cwd, spinner);
397
+ await this.resetPackageJsonFile(cwd, spinner);
398
+ await this.resetDatabase(cwd, spinner);
399
+ await this.resetHedhogFile(cwd, spinner);
400
+ }
401
+ catch (error) {
402
+ spinner.fail('Failed to reset development environment.');
403
+ console.error(chalk.red('Error resetting development environment:'), error);
404
+ throw error;
405
+ }
406
+ finally {
407
+ spinner.stop();
408
+ }
409
+ }
410
+ async resetHedhogFile(cwd, spinner) {
411
+ this.log('Resetting .hedhog file...');
412
+ spinner.start('Resetting .hedhog file...');
413
+ const hedHogFilePath = pathModule.join(cwd, 'hedhog.json');
414
+ if ((0, fs_1.existsSync)(hedHogFilePath)) {
415
+ try {
416
+ const currentFileParsed = JSON.parse(await this.fileSystem.readFileAsString(hedHogFilePath));
417
+ spinner.text =
418
+ 'Loaded existing hedhog.json file. Resetting contents...';
419
+ currentFileParsed.libraries = [];
420
+ currentFileParsed.installed = false;
421
+ currentFileParsed.developerMode = false;
422
+ currentFileParsed.buildCache = {};
423
+ await this.fileSystem.writeJsonFile(hedHogFilePath, currentFileParsed);
424
+ spinner.text = 'hedhog.json file reset.';
425
+ this.log('hedhog.json file reset.');
426
+ spinner.succeed('HedHog file reset successfully.');
427
+ }
428
+ catch (error) {
429
+ spinner.fail('Failed to reset hedhog.json file. Proceeding to reset.');
430
+ this.log(chalk.red('Error parsing existing hedhog.json file. Proceeding to reset.'));
431
+ }
432
+ }
433
+ }
434
+ async getRootPath(cwd) {
435
+ let currentPath = cwd;
436
+ while (true) {
437
+ if ((0, fs_1.existsSync)(pathModule.join(currentPath, 'hedhog.json'))) {
438
+ return currentPath;
439
+ }
440
+ const parentPath = pathModule.dirname(currentPath);
441
+ if (parentPath === currentPath) {
442
+ throw new Error('Could not find root path with hedhog.json');
443
+ }
444
+ currentPath = parentPath;
445
+ }
446
+ }
447
+ async resetDatabase(cwd, spinner) {
448
+ cwd = await this.getRootPath(cwd);
449
+ this.log('Resetting database...');
450
+ spinner.start('Resetting database...');
451
+ await this.database.executeQuery(pathModule.join(cwd, 'apps', 'api'), 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;');
452
+ spinner.succeed('Database reset successfully.');
453
+ this.log('Database reset successfully.');
454
+ }
455
+ async removeLibrariesDirectory(cwd, spinner) {
456
+ this.log('Removing libraries directory...');
457
+ spinner.start('Removing libraries directory...');
458
+ const librariesPath = pathModule.join(cwd, 'libraries');
459
+ if ((0, fs_1.existsSync)(librariesPath)) {
460
+ // Give Windows time to release file handles
461
+ await new Promise((resolve) => setTimeout(resolve, 1000));
462
+ await this.fileSystem.remove(librariesPath);
463
+ this.log('Libraries directory removed.');
464
+ }
465
+ spinner.succeed('Libraries directory removed successfully.');
466
+ }
467
+ async removeMigrationFiles(cwd, spinner) {
468
+ this.log('Removing migration files...');
469
+ spinner.start('Removing migration files...');
470
+ const migrationsPath = pathModule.join(cwd, 'apps', 'api', 'prisma', 'migrations');
471
+ if ((0, fs_1.existsSync)(migrationsPath)) {
472
+ await this.fileSystem.remove(migrationsPath);
473
+ this.log('Migration files removed.');
474
+ }
475
+ spinner.succeed('Migration files removed successfully.');
476
+ }
477
+ async resetAppModuleFile(cwd, spinner) {
478
+ this.log('Reset AppModule.ts file...');
479
+ spinner.start('Resetting AppModule.ts file...');
480
+ const appModulePath = pathModule.join(cwd, 'apps', 'api', 'src', 'app.module.ts');
481
+ if ((0, fs_1.existsSync)(appModulePath)) {
482
+ let templateContent;
483
+ this.log(chalk.yellow('Failed to fetch app.module.ts from remote. Using local template.'));
484
+ const localTemplatePath = pathModule.join(__dirname, '..', '..', 'templates', 'library', 'init.app.module.ts.ejs');
485
+ templateContent = await (0, promises_1.readFile)(localTemplatePath, 'utf8');
486
+ await this.fileSystem.writeFileContent(appModulePath, templateContent);
487
+ this.log('AppModule.ts file reset.');
488
+ }
489
+ spinner.succeed('AppModule.ts file reset successfully.');
490
+ }
491
+ async resetPackageJsonFile(cwd, spinner) {
492
+ this.log('Resetting package.json file...');
493
+ spinner.start('Resetting package.json file...');
494
+ const packageJsonPath = pathModule.join(cwd, 'apps', 'api', 'package.json');
495
+ if ((0, fs_1.existsSync)(packageJsonPath)) {
496
+ let templateContent;
497
+ this.log(chalk.yellow('Failed to fetch package.json from remote. Using local template.'));
498
+ const localTemplatePath = pathModule.join(__dirname, '..', '..', 'templates', 'library', 'init.package.json.ejs');
499
+ templateContent = await (0, promises_1.readFile)(localTemplatePath, 'utf8');
500
+ await this.fileSystem.writeFileContent(packageJsonPath, templateContent);
501
+ this.log('package.json file reset.');
502
+ }
503
+ spinner.succeed('package.json file reset successfully.');
504
+ }
505
+ async getRunningDatabaseService(cwd) {
506
+ try {
507
+ // Get list of running services
508
+ const result = await this.runner.executeCommand(runner_service_1.ProgramName.DOCKER_COMPOSE, ['ps', '--services', '--filter', 'status=running'], { cwd }, true);
509
+ const services = result.stdout
510
+ .trim()
511
+ .split('\n')
512
+ .filter((s) => s.length > 0);
513
+ this.log(`Running services: ${services.join(', ')}`);
514
+ if (services.length === 0) {
515
+ return null;
516
+ }
517
+ // Common database service names
518
+ const dbServiceNames = [
519
+ 'db',
520
+ 'postgres',
521
+ 'postgresql',
522
+ 'database',
523
+ 'mysql',
524
+ 'mariadb',
525
+ ];
526
+ // Try to find a database service
527
+ for (const dbName of dbServiceNames) {
528
+ if (services.includes(dbName)) {
529
+ this.log(`Found database service: ${dbName}`);
530
+ return dbName;
531
+ }
532
+ }
533
+ // If multiple services and no standard name found, ask user to choose
534
+ if (services.length > 1) {
535
+ console.log(chalk.yellow('\nMultiple services found. Please select the database service:'));
536
+ const answer = await inquirer_1.default.prompt([
537
+ {
538
+ type: 'list',
539
+ name: 'service',
540
+ message: 'Which service is your database?',
541
+ choices: services,
542
+ },
543
+ ]);
544
+ return answer.service;
545
+ }
546
+ // Only one service, use it
547
+ this.log(`Using the only available service: ${services[0]}`);
548
+ return services[0];
549
+ }
550
+ catch (error) {
551
+ this.log(chalk.red('Error getting running services:'), error);
552
+ return null;
553
+ }
554
+ }
555
+ async backupDatabase(cwd, verbose = false) {
556
+ this.verbose = verbose;
557
+ this.log('Backing up database...');
558
+ const spinner = ora('Backing up database...').start();
559
+ try {
560
+ cwd = await this.getRootPath(cwd);
561
+ // Get database configuration
562
+ const dbConfig = await this.database.getDatabaseConfig(pathModule.join(cwd, 'apps', 'api'));
563
+ if (!dbConfig) {
564
+ throw new Error('Failed to get database configuration');
565
+ }
566
+ // Detect running database service
567
+ spinner.text = 'Detecting database service...';
568
+ const dbService = await this.getRunningDatabaseService(cwd);
569
+ if (!dbService) {
570
+ throw new Error('No running database service found. Please start your database with "docker-compose up -d"');
571
+ }
572
+ this.log(`Using database service: ${dbService}`);
573
+ spinner.text = `Using database service: ${dbService}`;
574
+ // Create backup directory if it doesn't exist
575
+ const backupDir = pathModule.join(cwd, 'backup');
576
+ if (!(0, fs_1.existsSync)(backupDir)) {
577
+ await (0, promises_1.mkdir)(backupDir, { recursive: true });
578
+ this.log(`Created backup directory: ${backupDir}`);
579
+ }
580
+ // Generate backup filename with timestamp
581
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
582
+ const backupFileName = `backup-${timestamp}.dump`;
583
+ const backupFile = pathModule.join(backupDir, backupFileName);
584
+ const containerBackupPath = `/tmp/${backupFileName}`;
585
+ spinner.text = 'Creating database dump inside container...';
586
+ this.log(`Creating database dump at: ${backupFile}`);
587
+ // Execute pg_dump inside the Docker container
588
+ const dockerExecArgs = [
589
+ 'exec',
590
+ '-T',
591
+ dbService,
592
+ 'pg_dump',
593
+ '-h',
594
+ 'localhost',
595
+ '-p',
596
+ '5432',
597
+ '-U',
598
+ dbConfig.user,
599
+ '-d',
600
+ dbConfig.database,
601
+ '-F',
602
+ 'c', // custom format
603
+ '-f',
604
+ containerBackupPath,
605
+ ];
606
+ // Set PGPASSWORD environment variable
607
+ const env = { ...process.env, PGPASSWORD: dbConfig.password };
608
+ await this.runner.executeCommand(runner_service_1.ProgramName.DOCKER_COMPOSE, dockerExecArgs, { cwd, env }, true);
609
+ spinner.text = 'Copying backup from Docker container to host machine...';
610
+ this.log('Copying backup from container to host...');
611
+ // Copy backup file from container to host machine
612
+ const dockerCpArgs = [
613
+ 'cp',
614
+ `${dbService}:${containerBackupPath}`,
615
+ backupFile,
616
+ ];
617
+ await this.runner.executeCommand(runner_service_1.ProgramName.DOCKER_COMPOSE, dockerCpArgs, { cwd }, true);
618
+ spinner.succeed(`Database backup created successfully at: ${backupFile}`);
619
+ this.log(chalk.green(`Database backup created successfully at: ${backupFile}`));
620
+ }
621
+ catch (error) {
622
+ spinner.fail('Failed to backup database.');
623
+ console.error(chalk.red('Error backing up database:'), error);
624
+ throw error;
625
+ }
626
+ finally {
627
+ spinner.stop();
628
+ }
629
+ }
630
+ async initDatabase(cwd, verbose = false) {
631
+ this.verbose = verbose;
632
+ this.log('Initializing database...');
633
+ const spinner = ora('Initializing database...').start();
634
+ try {
635
+ cwd = await this.getRootPath(cwd);
636
+ const dockerComposeYmlPath = pathModule.join(cwd, 'docker-compose.yml');
637
+ const dockerComposeYamlPath = pathModule.join(cwd, 'docker-compose.yaml');
638
+ const dockerComposeYmlPathExists = (0, fs_1.existsSync)(dockerComposeYmlPath);
639
+ const dockerComposeYamlPathExists = (0, fs_1.existsSync)(dockerComposeYamlPath);
640
+ const dockerComposePath = dockerComposeYmlPathExists
641
+ ? dockerComposeYmlPath
642
+ : dockerComposeYamlPath;
643
+ if (!dockerComposeYmlPathExists && !dockerComposeYamlPathExists) {
644
+ spinner.fail('docker-compose.yml or docker-compose.yaml not found in project root.');
645
+ throw new Error('docker-compose.yml or docker-compose.yaml not found in project root.');
646
+ }
647
+ spinner.text = 'Starting database container using Docker Compose...';
648
+ await this.runner.executeCommand(runner_service_1.ProgramName.DOCKER_COMPOSE, ['up', '-d'], { cwd }, true);
649
+ spinner.succeed('Database container started successfully.');
650
+ this.log(chalk.green('Database container started successfully.'));
651
+ spinner.start('Checking database connection...');
652
+ // Check if .env file exists in the api and admin app directory. If not exists then create it from .env.example and replace variables comparing with env vars in docker-compose
653
+ await this.database.generateEnvFileIfNotExists(pathModule.join(cwd, 'apps', 'api'), dockerComposePath);
654
+ spinner.succeed('Environment file checked/created successfully.');
655
+ this.log(chalk.green('Environment file checked/created successfully.'));
656
+ spinner.start('Running database migrations...');
657
+ await this.runner.executeCommand(runner_service_1.ProgramName.PNPM, ['prisma:deploy'], { cwd: pathModule.join(cwd, 'apps', 'api') }, true);
658
+ spinner.succeed('Database initialized and migrations applied successfully.');
659
+ this.log(chalk.green('Database initialized and migrations applied successfully.'));
660
+ spinner.start('Updating Prisma client...');
661
+ await this.runner.executeCommand(runner_service_1.ProgramName.PNPM, ['prisma:update'], { cwd: pathModule.join(cwd, 'apps', 'api') }, true);
662
+ spinner.succeed('Prisma client updated successfully.');
663
+ this.log(chalk.green('Prisma client updated successfully.'));
664
+ spinner.start('Creating .env files for applications...');
665
+ const appsDir = pathModule.join(cwd, 'apps');
666
+ if ((0, fs_1.existsSync)(appsDir)) {
667
+ const appDirs = (0, fs_1.readdirSync)(appsDir, { withFileTypes: true })
668
+ .filter((entry) => entry.isDirectory())
669
+ .map((entry) => pathModule.join(appsDir, entry.name));
670
+ for (const appDir of appDirs) {
671
+ spinner.text = `Checking .env file for ${appDir}...`;
672
+ const envPath = pathModule.join(appDir, '.env');
673
+ const envExamplePath = pathModule.join(appDir, '.env.example');
674
+ if (!(0, fs_1.existsSync)(envPath) && (0, fs_1.existsSync)(envExamplePath)) {
675
+ const envExampleContent = await (0, promises_1.readFile)(envExamplePath, 'utf8');
676
+ await (0, promises_1.writeFile)(envPath, envExampleContent, 'utf8');
677
+ this.log(chalk.green(`Created .env file for ${appDir}`));
678
+ }
679
+ }
680
+ }
681
+ spinner.succeed('.env files created/checked successfully.');
682
+ this.log(chalk.green('.env files created/checked successfully.'));
683
+ }
684
+ catch (error) {
685
+ spinner.fail('Failed to initialize database.');
686
+ console.error(chalk.red('Error initializing database:'), error);
687
+ throw error;
688
+ }
689
+ finally {
690
+ spinner.stop();
691
+ }
692
+ }
693
+ async restoreDatabase(cwd, verbose = false) {
694
+ this.verbose = verbose;
695
+ this.log('Restoring database from backup...');
696
+ const spinner = ora('Restoring database from backup...').start();
697
+ try {
698
+ cwd = await this.getRootPath(cwd);
699
+ // Get database configuration
700
+ const dbConfig = await this.database.getDatabaseConfig(pathModule.join(cwd, 'apps', 'api'));
701
+ if (!dbConfig) {
702
+ throw new Error('Failed to get database configuration');
703
+ }
704
+ // Detect running database service
705
+ spinner.text = 'Detecting database service...';
706
+ const dbService = await this.getRunningDatabaseService(cwd);
707
+ if (!dbService) {
708
+ throw new Error('No running database service found. Please start your database with "docker-compose up -d"');
709
+ }
710
+ this.log(`Using database service: ${dbService}`);
711
+ // Check backup directory
712
+ const backupDir = pathModule.join(cwd, 'backup');
713
+ if (!(0, fs_1.existsSync)(backupDir)) {
714
+ spinner.fail('Backup directory not found.');
715
+ throw new Error(`Backup directory not found at: ${backupDir}. Please create a backup first.`);
716
+ }
717
+ // List all .dump files in backup directory
718
+ spinner.text = 'Searching for backup files...';
719
+ const files = (0, fs_1.readdirSync)(backupDir)
720
+ .filter((file) => file.endsWith('.dump'))
721
+ .map((file) => {
722
+ const filePath = pathModule.join(backupDir, file);
723
+ const stats = (0, fs_1.statSync)(filePath);
724
+ return {
725
+ name: file,
726
+ path: filePath,
727
+ mtime: stats.mtime,
728
+ };
729
+ })
730
+ .sort((a, b) => b.mtime.getTime() - a.mtime.getTime()); // Most recent first
731
+ if (files.length === 0) {
732
+ spinner.fail('No backup files found.');
733
+ throw new Error(`No backup files found in: ${backupDir}. Please create a backup first.`);
734
+ }
735
+ spinner.stop();
736
+ // Let user select a backup file
737
+ console.log(chalk.blue(`\nFound ${files.length} backup file(s):`));
738
+ const { selectedBackup } = await inquirer_1.default.prompt([
739
+ {
740
+ type: 'list',
741
+ name: 'selectedBackup',
742
+ message: 'Select a backup file to restore:',
743
+ choices: files.map((file) => ({
744
+ name: `${file.name} (${file.mtime.toLocaleString()})`,
745
+ value: file.path,
746
+ })),
747
+ },
748
+ ]);
749
+ // Check if database has data
750
+ spinner.start('Checking database for existing data...');
751
+ let hasData = false;
752
+ try {
753
+ const checkResult = await this.database.executeQuery(pathModule.join(cwd, 'apps', 'api'), "SELECT COUNT(*) as table_count FROM information_schema.tables WHERE table_schema = 'public' AND table_type = 'BASE TABLE';");
754
+ hasData =
755
+ checkResult && parseInt(checkResult[0]?.table_count || '0') > 0;
756
+ this.log(`Database has data: ${hasData}`);
757
+ }
758
+ catch (error) {
759
+ this.log(chalk.yellow('Could not check for existing data. Proceeding...'));
760
+ }
761
+ spinner.stop();
762
+ // Confirm if database has data
763
+ if (hasData) {
764
+ console.log(chalk.yellow('\n⚠️ Warning: The database contains existing data.'));
765
+ const { confirmRestore } = await inquirer_1.default.prompt([
766
+ {
767
+ type: 'confirm',
768
+ name: 'confirmRestore',
769
+ message: 'Are you sure you want to replace all existing data with the backup?',
770
+ default: false,
771
+ },
772
+ ]);
773
+ if (!confirmRestore) {
774
+ console.log(chalk.blue('Restore operation cancelled.'));
775
+ return;
776
+ }
777
+ }
778
+ spinner.start('Copying backup file to container...');
779
+ this.log(`Restoring from: ${selectedBackup}`);
780
+ const backupFileName = pathModule.basename(selectedBackup);
781
+ const containerBackupPath = `/tmp/${backupFileName}`;
782
+ // Copy backup file from host to container
783
+ const dockerCpArgs = [
784
+ 'cp',
785
+ selectedBackup,
786
+ `${dbService}:${containerBackupPath}`,
787
+ ];
788
+ await this.runner.executeCommand(runner_service_1.ProgramName.DOCKER_COMPOSE, dockerCpArgs, { cwd }, true);
789
+ spinner.text = 'Dropping and recreating database...';
790
+ this.log('Dropping and recreating database...');
791
+ // Drop the database
792
+ const dropDbArgs = [
793
+ 'exec',
794
+ '-T',
795
+ dbService,
796
+ 'dropdb',
797
+ '-h',
798
+ 'localhost',
799
+ '-p',
800
+ '5432',
801
+ '-U',
802
+ dbConfig.user,
803
+ '--if-exists',
804
+ dbConfig.database,
805
+ ];
806
+ const env = { ...process.env, PGPASSWORD: dbConfig.password };
807
+ try {
808
+ await this.runner.executeCommand(runner_service_1.ProgramName.DOCKER_COMPOSE, dropDbArgs, { cwd, env }, true);
809
+ }
810
+ catch (error) {
811
+ // Check if error is due to active connections
812
+ if (error.message &&
813
+ error.message.includes('is being accessed by other users')) {
814
+ spinner.fail('Cannot drop database - active connections detected.');
815
+ console.log('');
816
+ console.log(chalk.yellow('⚠️ Database Connection Error'));
817
+ console.log('');
818
+ console.log(chalk.white('The database cannot be restored because there are active connections.'));
819
+ console.log('');
820
+ console.log(chalk.cyan('📋 Please follow these steps:'));
821
+ console.log('');
822
+ console.log(chalk.white(' 1. Close all applications connected to the database:'));
823
+ console.log(chalk.gray(' • API servers or backend applications'));
824
+ console.log(chalk.gray(' • Database management tools (DBeaver, pgAdmin, etc.)'));
825
+ console.log(chalk.gray(' • Any running database queries or scripts'));
826
+ console.log('');
827
+ console.log(chalk.white(' 2. After closing all connections, run this command again'));
828
+ console.log('');
829
+ console.log(chalk.blue('💡 Tip: You can also restart the database container to force close all connections:'));
830
+ console.log(chalk.gray(' docker-compose restart db'));
831
+ console.log('');
832
+ throw new Error('Database restore cancelled due to active connections');
833
+ }
834
+ throw error;
835
+ }
836
+ // Create the database
837
+ const createDbArgs = [
838
+ 'exec',
839
+ '-T',
840
+ dbService,
841
+ 'createdb',
842
+ '-h',
843
+ 'localhost',
844
+ '-p',
845
+ '5432',
846
+ '-U',
847
+ dbConfig.user,
848
+ dbConfig.database,
849
+ ];
850
+ await this.runner.executeCommand(runner_service_1.ProgramName.DOCKER_COMPOSE, createDbArgs, { cwd, env }, true);
851
+ spinner.text = 'Restoring database from backup file...';
852
+ this.log('Restoring database from backup file...');
853
+ // Restore database using pg_restore
854
+ const restoreArgs = [
855
+ 'exec',
856
+ '-T',
857
+ dbService,
858
+ 'pg_restore',
859
+ '-h',
860
+ 'localhost',
861
+ '-p',
862
+ '5432',
863
+ '-U',
864
+ dbConfig.user,
865
+ '-d',
866
+ dbConfig.database,
867
+ '-v',
868
+ containerBackupPath,
869
+ ];
870
+ await this.runner.executeCommand(runner_service_1.ProgramName.DOCKER_COMPOSE, restoreArgs, { cwd, env }, true);
871
+ spinner.text = 'Cleaning up temporary files...';
872
+ this.log('Cleaning up temporary files...');
873
+ // Remove temporary backup file from container
874
+ const cleanupArgs = ['exec', '-T', dbService, 'rm', containerBackupPath];
875
+ await this.runner.executeCommand(runner_service_1.ProgramName.DOCKER_COMPOSE, cleanupArgs, { cwd }, true);
876
+ spinner.succeed(chalk.green('Database restored successfully from backup!'));
877
+ this.log(chalk.green('Database restored successfully from backup!'));
878
+ }
879
+ catch (error) {
880
+ spinner.fail('Failed to restore database.');
881
+ // Only show detailed error if it's not the active connections error
882
+ if (!error.message ||
883
+ !error.message.includes('Database restore cancelled due to active connections')) {
884
+ console.error(chalk.red('Error restoring database:'), error);
885
+ }
886
+ throw error;
887
+ }
888
+ finally {
889
+ spinner.stop();
890
+ }
891
+ }
892
+ };
893
+ exports.DeveloperService = DeveloperService;
894
+ exports.DeveloperService = DeveloperService = __decorate([
895
+ (0, common_1.Injectable)(),
896
+ __metadata("design:paramtypes", [runner_service_1.RunnerService,
897
+ file_system_service_1.FileSystemService,
898
+ database_service_1.DatabaseService])
899
+ ], DeveloperService);
900
+ //# sourceMappingURL=developer.service.js.map