fragment-ts 1.0.43 → 1.0.44

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 (55) hide show
  1. package/dist/cli/commands/diagnostics.command.d.ts.map +1 -1
  2. package/dist/cli/commands/diagnostics.command.js +17 -73
  3. package/dist/cli/commands/diagnostics.command.js.map +1 -1
  4. package/dist/cli/commands/env.command.d.ts +10 -0
  5. package/dist/cli/commands/env.command.d.ts.map +1 -0
  6. package/dist/cli/commands/env.command.js +222 -0
  7. package/dist/cli/commands/env.command.js.map +1 -0
  8. package/dist/cli/commands/generate.command.js +9 -9
  9. package/dist/cli/commands/init.command.d.ts.map +1 -1
  10. package/dist/cli/commands/init.command.js +65 -35
  11. package/dist/cli/commands/init.command.js.map +1 -1
  12. package/dist/cli/commands/migrate.command.d.ts +14 -41
  13. package/dist/cli/commands/migrate.command.d.ts.map +1 -1
  14. package/dist/cli/commands/migrate.command.js +182 -424
  15. package/dist/cli/commands/migrate.command.js.map +1 -1
  16. package/dist/cli/commands/test.command.d.ts.map +1 -1
  17. package/dist/cli/commands/test.command.js +5 -51
  18. package/dist/cli/commands/test.command.js.map +1 -1
  19. package/dist/cli/index.js +48 -0
  20. package/dist/cli/index.js.map +1 -1
  21. package/dist/core/scanner/component-scanner.d.ts +0 -4
  22. package/dist/core/scanner/component-scanner.d.ts.map +1 -1
  23. package/dist/core/scanner/component-scanner.js +0 -15
  24. package/dist/core/scanner/component-scanner.js.map +1 -1
  25. package/dist/shared/config.utils.d.ts +0 -27
  26. package/dist/shared/config.utils.d.ts.map +1 -1
  27. package/dist/shared/config.utils.js +7 -38
  28. package/dist/shared/config.utils.js.map +1 -1
  29. package/dist/shared/env.utils.d.ts +6 -18
  30. package/dist/shared/env.utils.d.ts.map +1 -1
  31. package/dist/shared/env.utils.js +84 -39
  32. package/dist/shared/env.utils.js.map +1 -1
  33. package/dist/testing/runner.d.ts.map +1 -1
  34. package/dist/testing/runner.js +2 -12
  35. package/dist/testing/runner.js.map +1 -1
  36. package/dist/typeorm/typeorm-module.d.ts.map +1 -1
  37. package/dist/typeorm/typeorm-module.js +4 -16
  38. package/dist/typeorm/typeorm-module.js.map +1 -1
  39. package/dist/web/application.d.ts.map +1 -1
  40. package/dist/web/application.js +1 -20
  41. package/dist/web/application.js.map +1 -1
  42. package/package.json +2 -1
  43. package/src/cli/commands/diagnostics.command.ts +16 -87
  44. package/src/cli/commands/env.command.ts +224 -0
  45. package/src/cli/commands/generate.command.ts +9 -9
  46. package/src/cli/commands/init.command.ts +68 -37
  47. package/src/cli/commands/migrate.command.ts +244 -528
  48. package/src/cli/commands/test.command.ts +5 -61
  49. package/src/cli/index.ts +19 -0
  50. package/src/core/scanner/component-scanner.ts +0 -15
  51. package/src/shared/config.utils.ts +10 -54
  52. package/src/shared/env.utils.ts +50 -44
  53. package/src/testing/runner.ts +2 -11
  54. package/src/typeorm/typeorm-module.ts +5 -14
  55. package/src/web/application.ts +1 -21
@@ -43,12 +43,13 @@ const chalk_1 = __importDefault(require("chalk"));
43
43
  const ora_1 = __importDefault(require("ora"));
44
44
  const typeorm_module_1 = require("../../typeorm/typeorm-module");
45
45
  const config_utils_1 = require("../../shared/config.utils");
46
- const env_utils_1 = require("../../shared/env.utils");
46
+ const tsconfig_utils_1 = require("../../shared/tsconfig.utils");
47
+ const glob_1 = require("glob");
47
48
  class MigrateCommand {
48
49
  static register(program) {
49
50
  program
50
51
  .command("migrate")
51
- .description("Run all pending migrations (auto-detect TypeScript/JavaScript)")
52
+ .description("Run all pending migrations")
52
53
  .action(async () => {
53
54
  await this.runMigrations();
54
55
  });
@@ -114,255 +115,169 @@ class MigrateCommand {
114
115
  await this.createSeed(name);
115
116
  });
116
117
  }
117
- // -----------------------------------------
118
- // DETECTION METHODS
119
- // -----------------------------------------
120
118
  /**
121
- * Check if ts-node is available in the user's project
119
+ * Detect if we should use TypeScript or JavaScript
122
120
  */
123
- static isTsNodeAvailable() {
124
- if (this.tsNodeAvailable !== null)
125
- return this.tsNodeAvailable;
126
- try {
127
- // Check if ts-node is installed in the user's project
128
- require.resolve("ts-node");
129
- this.tsNodeAvailable = true;
130
- }
131
- catch {
132
- try {
133
- // Check if ts-node is installed globally or in parent modules
134
- require("ts-node");
135
- this.tsNodeAvailable = true;
136
- }
137
- catch {
138
- this.tsNodeAvailable = false;
139
- }
140
- }
141
- return this.tsNodeAvailable;
121
+ static setupEnvironment() {
122
+ return this.shouldUseTypeScript();
142
123
  }
143
124
  /**
144
- * Check if tsconfig.json exists
145
- */
146
- static hasTsConfig() {
147
- if (this.tsConfigExists !== null)
148
- return this.tsConfigExists;
149
- this.tsConfigExists = fs.existsSync(path.join(process.cwd(), "tsconfig.json"));
150
- return this.tsConfigExists;
151
- }
152
- /**
153
- * Detect if TypeScript files exist in the project
154
- */
155
- static detectProjectType() {
156
- const srcDir = path.join(process.cwd(), "src");
157
- const hasSrcDir = fs.existsSync(srcDir);
158
- const hasTsFiles = hasSrcDir && fs.readdirSync(srcDir).some((file) => file.endsWith(".ts"));
159
- const distDir = path.join(process.cwd(), "dist");
160
- const hasDistDir = fs.existsSync(distDir);
161
- const hasJsFiles = hasDistDir &&
162
- fs.readdirSync(distDir).some((file) => file.endsWith(".js"));
163
- if (hasTsFiles && !hasJsFiles)
164
- return "typescript";
165
- if (!hasTsFiles && hasJsFiles)
166
- return "javascript";
167
- if (hasTsFiles && hasJsFiles)
168
- return "mixed";
169
- // Default to checking for tsconfig
170
- return this.hasTsConfig() ? "typescript" : "javascript";
171
- }
172
- /**
173
- * Determine whether to use TypeScript or JavaScript for migrations
125
+ * Detect if we should use TypeScript or JavaScript
126
+ * - Check if tsconfig.json exists AND has decorator support
127
+ * - Check if TypeScript files exist in include patterns
128
+ * - Check if ts-node is available
174
129
  */
175
130
  static shouldUseTypeScript() {
176
- const projectType = this.detectProjectType();
177
- const tsNodeAvailable = this.isTsNodeAvailable();
178
- // Use the same logic as EnvUtils for consistency
179
- const isDevMode = env_utils_1.EnvUtils.isDevelopmentMode();
180
- // In development mode with ts-node available, use TypeScript
181
- if (isDevMode && tsNodeAvailable) {
182
- return true;
183
- }
184
- // In production mode, always use JavaScript
185
- if (!isDevMode) {
131
+ if (!tsconfig_utils_1.TsConfigUtils.exists()) {
186
132
  return false;
187
133
  }
188
- // Fallback to project type detection
189
- return projectType === "typescript" && tsNodeAvailable;
190
- }
191
- /**
192
- * Register ts-node if needed
193
- */
194
- static registerTsNodeIfNeeded(useTypeScript) {
195
- if (!useTypeScript)
196
- return;
197
- try {
198
- // Register ts-node for TypeScript support
199
- require("ts-node/register");
200
- // If tsconfig-paths is available, register it too
134
+ if (!tsconfig_utils_1.TsConfigUtils.hasDecoratorSupport()) {
135
+ return false;
136
+ }
137
+ if (!this.isTsNodeAvailable()) {
138
+ return false;
139
+ }
140
+ const includePatterns = tsconfig_utils_1.TsConfigUtils.getIncludePatterns();
141
+ const cwd = process.cwd();
142
+ for (const pattern of includePatterns) {
201
143
  try {
202
- require("tsconfig-paths/register");
144
+ const files = (0, glob_1.globSync)(pattern, { cwd });
145
+ if (files.some((file) => file.endsWith(".ts") && !file.endsWith(".d.ts"))) {
146
+ return true;
147
+ }
203
148
  }
204
149
  catch {
205
- // tsconfig-paths not available, that's okay
150
+ // Ignore glob errors
206
151
  }
207
- console.log(chalk_1.default.gray("šŸ“ Using ts-node for TypeScript migrations"));
208
152
  }
209
- catch (error) {
210
- console.error(chalk_1.default.yellow("āš ļø Failed to register ts-node. Falling back to JavaScript."));
153
+ return false;
154
+ }
155
+ static isTsNodeAvailable() {
156
+ if (this.tsNodeAvailable !== null) {
157
+ return this.tsNodeAvailable;
158
+ }
159
+ try {
160
+ require.resolve("ts-node");
161
+ this.tsNodeAvailable = true;
211
162
  }
163
+ catch {
164
+ this.tsNodeAvailable = false;
165
+ }
166
+ return this.tsNodeAvailable;
212
167
  }
213
- /**
214
- * Get entity paths from fragment.json config
215
- */
216
- static getEntityPathsFromConfig() {
217
- const dbConfig = config_utils_1.ConfigUtils.getDatabaseConfig();
218
- return dbConfig.entities || [];
168
+ static registerTsNodeIfNeeded(useTypeScript) {
169
+ if (useTypeScript && this.isTsNodeAvailable()) {
170
+ require("ts-node").register({
171
+ transpileOnly: true,
172
+ compilerOptions: {
173
+ module: "commonjs",
174
+ },
175
+ });
176
+ }
219
177
  }
220
178
  /**
221
- * Get migration paths from fragment.json config
179
+ * Get entity and migration paths based on current mode
180
+ * Uses fragment.json config when available, otherwise infers from tsconfig
222
181
  */
223
- static getMigrationPathsFromConfig() {
182
+ static getPaths(useTypeScript) {
224
183
  const dbConfig = config_utils_1.ConfigUtils.getDatabaseConfig();
225
- return dbConfig.migrations || [];
184
+ const resolveExtension = (pattern) => {
185
+ return useTypeScript
186
+ ? pattern.replace(/\.js$/, ".ts")
187
+ : pattern.replace(/\.ts$/, ".js");
188
+ };
189
+ if (dbConfig.entities || dbConfig.migrations) {
190
+ const entities = dbConfig.entities
191
+ ? dbConfig.entities.map(resolveExtension)
192
+ : [useTypeScript ? "src/**/*.entity.ts" : "dist/**/*.entity.js"];
193
+ const migrations = dbConfig.migrations
194
+ ? dbConfig.migrations.map(resolveExtension)
195
+ : [
196
+ useTypeScript
197
+ ? "src/migrations/**/*.ts"
198
+ : "dist/migrations/**/*.js",
199
+ ];
200
+ const migrationDir = this.extractMigrationDirectory(migrations[0], useTypeScript);
201
+ const seedsDir = path.join(migrationDir, "..", "seeds");
202
+ return { entities, migrations, seeds: seedsDir };
203
+ }
204
+ const rootDir = tsconfig_utils_1.TsConfigUtils.getRootDir();
205
+ const outDir = tsconfig_utils_1.TsConfigUtils.getOutDir();
206
+ const entities = [
207
+ useTypeScript ? `${rootDir}/**/*.entity.ts` : `${outDir}/**/*.entity.js`,
208
+ ];
209
+ const migrations = [
210
+ useTypeScript
211
+ ? `${rootDir}/migrations/**/*.ts`
212
+ : `${outDir}/migrations/**/*.js`,
213
+ ];
214
+ const seeds = useTypeScript ? `${rootDir}/seeds` : `${outDir}/seeds`;
215
+ return { entities, migrations, seeds };
226
216
  }
227
217
  /**
228
- * Get resolved entity paths based on current mode
218
+ * Extract the actual directory path from a glob pattern for file creation
229
219
  */
230
- static getResolvedEntityPaths(useTypeScript) {
231
- const configPaths = this.getEntityPathsFromConfig();
232
- if (configPaths.length > 0) {
233
- // Use configured paths but resolve based on current mode
234
- return configPaths.map((pattern) => {
235
- if (useTypeScript) {
236
- return pattern.replace(/\.js$/, ".ts");
237
- }
238
- else {
239
- return pattern.replace(/\.ts$/, ".js");
240
- }
241
- });
220
+ static extractMigrationDirectory(pattern, useTypeScript) {
221
+ if (pattern.includes("/**/*")) {
222
+ return pattern.split("/**/*")[0];
242
223
  }
243
- // Fallback to default paths
244
- return useTypeScript ? ["src/**/*.entity.ts"] : ["dist/**/*.entity.js"];
245
- }
246
- /**
247
- * Get resolved migration paths based on current mode
248
- */
249
- static getResolvedMigrationPaths(useTypeScript) {
250
- const configPaths = this.getMigrationPathsFromConfig();
251
- if (configPaths.length > 0) {
252
- // Use configured paths but resolve based on current mode
253
- return configPaths.map((pattern) => {
254
- if (useTypeScript) {
255
- return pattern.replace(/\.js$/, ".ts");
256
- }
257
- else {
258
- return pattern.replace(/\.ts$/, ".js");
259
- }
260
- });
224
+ if (pattern.includes("/*.")) {
225
+ return pattern.split("/*")[0];
261
226
  }
262
- // Fallback to default paths
263
- return useTypeScript
264
- ? ["src/migrations/**/*.ts"]
265
- : ["dist/migrations/**/*.js"];
227
+ if (pattern.endsWith(".ts") || pattern.endsWith(".js")) {
228
+ return path.dirname(pattern);
229
+ }
230
+ return useTypeScript ? "src/migrations" : "dist/migrations";
266
231
  }
267
- // -----------------------------------------
268
- // MIGRATION GENERATE
269
- // -----------------------------------------
270
232
  static async generateMigration(nameOrPath, options) {
271
- const useTypeScript = this.shouldUseTypeScript();
272
- const spinner = (0, ora_1.default)("Generating migration...").start();
233
+ const useTypeScript = this.setupEnvironment();
234
+ const spinner = (0, ora_1.default)(`Generating ${useTypeScript ? "TypeScript" : "JavaScript"} migration...`).start();
273
235
  let dataSource = null;
274
236
  try {
275
- // Register ts-node if using TypeScript
276
237
  this.registerTsNodeIfNeeded(useTypeScript);
277
- // Initialize DataSource with paths from fragment.json config
278
- const configOverride = {
279
- entities: this.getResolvedEntityPaths(useTypeScript),
280
- migrations: this.getResolvedMigrationPaths(useTypeScript),
281
- };
238
+ const { entities, migrations } = this.getPaths(useTypeScript);
239
+ const configOverride = { entities, migrations };
282
240
  dataSource = await typeorm_module_1.TypeORMModule.initialize(configOverride);
283
241
  if (!dataSource?.isInitialized) {
284
242
  throw new Error("Failed to initialize DataSource");
285
243
  }
286
- // Verify entities are loaded
287
244
  this.verifyEntities(dataSource);
288
- // Setup migrations directory from config
289
- const migrationPaths = this.getResolvedMigrationPaths(useTypeScript);
290
- const migrationsDir = path.dirname(migrationPaths[0].replace("/**/*", ""));
245
+ const migrationsPattern = migrations[0];
246
+ const migrationsDir = this.extractMigrationDirectory(migrationsPattern, useTypeScript);
291
247
  await fs.ensureDir(migrationsDir);
292
248
  const existingMigrations = fs.existsSync(migrationsDir)
293
249
  ? fs
294
250
  .readdirSync(migrationsDir)
295
- .filter((f) => f.endsWith(useTypeScript ? ".ts" : ".js"))
251
+ .filter((f) => f.endsWith(useTypeScript ? ".ts" : ".js") &&
252
+ !f.endsWith(".d.ts"))
296
253
  : [];
297
254
  const isFirstMigration = existingMigrations.length === 0;
298
- // Generate schema SQL by comparing entities with database
299
255
  spinner.text = "Analyzing schema changes...";
300
256
  const sqlInMemory = await dataSource.driver.createSchemaBuilder().log();
301
257
  const upQueries = sqlInMemory.upQueries || [];
302
258
  const downQueries = sqlInMemory.downQueries || [];
303
259
  const hasChanges = upQueries.length > 0;
304
- // Handle no changes scenario
305
260
  if (!hasChanges && !isFirstMigration) {
306
261
  spinner.info("No schema changes detected. Migration not generated.");
307
262
  return;
308
263
  }
309
- if (!hasChanges && isFirstMigration) {
310
- const helpMessage = useTypeScript
311
- ? " - Your entities are in the correct location\n" +
312
- " - Entity paths in fragment.json are correct\n" +
313
- " - Entities are decorated with @Entity()"
314
- : " - Your entities are compiled (run 'npm run build')\n" +
315
- " - Entity paths in fragment.json point to dist/**/*.entity.js\n" +
316
- " - Entities are decorated with @Entity()";
317
- spinner.warn("No schema changes detected on first migration. Check that:\n" +
318
- helpMessage);
319
- return;
320
- }
321
- // Determine migration name
322
264
  const migrationName = options.name ||
323
265
  (nameOrPath ? path.basename(nameOrPath).replace(/\.ts$/, "") : null) ||
324
266
  (isFirstMigration ? "InitialMigration" : "Migration");
325
267
  const timestamp = Date.now();
326
268
  const className = `${migrationName}${timestamp}`;
327
- // Build queries
328
- spinner.text = "Building migration file...";
329
- const upStatements = upQueries.map((query) => {
330
- return this.buildQueryStatement(query);
331
- });
332
- const downStatements = downQueries.map((query) => {
333
- return this.buildQueryStatement(query);
334
- });
335
- // Generate migration file content
269
+ const upStatements = upQueries.map((q) => this.buildQueryStatement(q));
270
+ const downStatements = downQueries.map((q) => this.buildQueryStatement(q));
336
271
  const migrationContent = this.buildMigrationTemplate(className, upStatements, downStatements, isFirstMigration);
337
- // Write migration file using config directory
338
272
  const fileExt = useTypeScript ? ".ts" : ".js";
339
273
  const fileName = `${timestamp}-${migrationName}${fileExt}`;
340
274
  const filePath = path.join(migrationsDir, fileName);
341
275
  await fs.writeFile(filePath, migrationContent, "utf-8");
342
- const fileType = useTypeScript ? "TypeScript" : "JavaScript";
343
- spinner.succeed(`${fileType} migration generated: ${chalk_1.default.cyan(fileName)}\n` +
344
- ` ${chalk_1.default.gray("Location:")} ${filePath}\n` +
345
- ` ${chalk_1.default.gray("Queries:")} ${upQueries.length} up, ${downQueries.length} down\n` +
346
- ` ${chalk_1.default.gray("Mode:")} ${useTypeScript ? "TypeScript (ts-node)" : "JavaScript"}`);
276
+ spinner.succeed(`${useTypeScript ? "TypeScript" : "JavaScript"} migration generated: ${chalk_1.default.cyan(fileName)}`);
347
277
  }
348
278
  catch (error) {
349
279
  spinner.fail("Migration generation failed");
350
- if (error instanceof Error) {
351
- console.error(chalk_1.default.red("\nāŒ Error: " + error.message));
352
- if (error.message.includes("Cannot find module") && useTypeScript) {
353
- console.error(chalk_1.default.yellow("\nšŸ’” Tip: Try one of these solutions:\n" +
354
- " 1. Install ts-node: npm install -D ts-node\n" +
355
- " 2. Compile your project first: npm run build\n" +
356
- " 3. Ensure your entities are in src/**/*.entity.ts"));
357
- }
358
- if (error.stack) {
359
- console.error(chalk_1.default.gray("\nStack trace:"));
360
- console.error(chalk_1.default.gray(error.stack));
361
- }
362
- }
363
- else {
364
- console.error(chalk_1.default.red(String(error)));
365
- }
280
+ console.error(chalk_1.default.red(error instanceof Error ? error.message : String(error)));
366
281
  process.exit(1);
367
282
  }
368
283
  finally {
@@ -370,111 +285,25 @@ class MigrateCommand {
370
285
  try {
371
286
  await dataSource.destroy();
372
287
  }
373
- catch (err) {
374
- // Ignore cleanup errors
375
- }
288
+ catch { }
376
289
  }
377
290
  }
378
291
  }
379
- /**
380
- * Verify entities are loaded and provide helpful debugging
381
- */
382
- static verifyEntities(dataSource) {
383
- const entities = dataSource.entityMetadatas;
384
- if (entities.length === 0) {
385
- throw new Error("No entities found! Make sure:\n" +
386
- " 1. Your entities are decorated with @Entity()\n" +
387
- " 2. Entity paths in fragment.json are correct\n" +
388
- " 3. For JavaScript mode: run 'npm run build' to compile\n" +
389
- " 4. For TypeScript mode: entities should be in src/**/*.entity.ts");
390
- }
391
- console.log(chalk_1.default.gray(`\nšŸ“¦ Loaded ${entities.length} entity/entities:`));
392
- entities.forEach((entity) => {
393
- console.log(chalk_1.default.gray(` - ${entity.name} (${entity.tableName})`));
394
- });
395
- console.log();
396
- }
397
- /**
398
- * Build a single query statement with proper escaping
399
- */
400
- static buildQueryStatement(query) {
401
- // Escape backslashes, backticks, and dollar signs for template literals
402
- let sql = query.query
403
- .replace(/\\/g, "\\\\") // Escape backslashes first
404
- .replace(/`/g, "\\`") // Escape backticks
405
- .replace(/\$/g, "\\$") // Escape dollar signs
406
- .replace(/\r\n/g, " ") // Remove Windows line breaks
407
- .replace(/\n/g, " ") // Remove Unix line breaks
408
- .replace(/\s+/g, " ") // Collapse multiple spaces
409
- .trim();
410
- // Handle parameters if present
411
- if (query.parameters && query.parameters.length > 0) {
412
- const params = JSON.stringify(query.parameters);
413
- return `await queryRunner.query(\`${sql}\`, ${params});`;
414
- }
415
- return `await queryRunner.query(\`${sql}\`);`;
416
- }
417
- // -----------------------------------------
418
- // MIGRATION EXECUTION METHODS
419
- // -----------------------------------------
420
292
  static async runMigrations() {
421
- const useTypeScript = this.shouldUseTypeScript();
422
- const spinner = (0, ora_1.default)("Running migrations...").start();
293
+ const useTypeScript = this.setupEnvironment();
294
+ const spinner = (0, ora_1.default)(`Running ${useTypeScript ? "TypeScript" : "JavaScript"} migrations...`).start();
423
295
  let dataSource = null;
424
296
  try {
425
- // Register ts-node if using TypeScript
426
297
  this.registerTsNodeIfNeeded(useTypeScript);
427
- // Initialize DataSource with paths from fragment.json config
428
- const configOverride = {
429
- entities: this.getResolvedEntityPaths(useTypeScript),
430
- migrations: this.getResolvedMigrationPaths(useTypeScript),
431
- };
298
+ const { entities, migrations } = this.getPaths(useTypeScript);
299
+ const configOverride = { entities, migrations };
432
300
  dataSource = await typeorm_module_1.TypeORMModule.initialize(configOverride);
433
- // Check if migrations exist using config paths
434
- const migrationPaths = this.getResolvedMigrationPaths(useTypeScript);
435
- const migrationsDir = path.dirname(migrationPaths[0].replace("/**/*", ""));
436
- const fileExt = useTypeScript ? ".ts" : ".js";
437
- const hasMigrations = fs.existsSync(migrationsDir) &&
438
- fs.readdirSync(migrationsDir).filter((f) => f.endsWith(fileExt))
439
- .length > 0;
440
- if (!hasMigrations) {
441
- const mode = useTypeScript ? "TypeScript" : "JavaScript";
442
- spinner.info(`No ${mode.toLowerCase()} migrations found in ${migrationsDir}.`);
443
- if (useTypeScript && this.hasJavaScriptMigrations()) {
444
- console.log(chalk_1.default.yellow(`\nšŸ’” JavaScript migrations found. Try:\n` +
445
- ` 1. fragment migrate:run (in JavaScript mode)\n` +
446
- ` 2. Or compile your TypeScript: npm run build`));
447
- }
448
- else if (!useTypeScript && this.hasTypeScriptMigrations()) {
449
- console.log(chalk_1.default.yellow(`\nšŸ’” TypeScript migrations found. Try:\n` +
450
- ` 1. Install ts-node: npm install -D ts-node\n` +
451
- ` 2. Then run: fragment migrate:run\n` +
452
- ` 3. Or compile first: npm run build`));
453
- }
454
- return;
455
- }
456
- const mode = useTypeScript ? "TypeScript" : "JavaScript";
457
- spinner.text = `Running ${mode} migrations...`;
458
301
  await typeorm_module_1.TypeORMModule.runMigrations();
459
- spinner.succeed(`${mode} migrations completed successfully`);
302
+ spinner.succeed(`${useTypeScript ? "TypeScript" : "JavaScript"} migrations completed successfully`);
460
303
  }
461
304
  catch (error) {
462
305
  spinner.fail("Migration failed");
463
- if (error instanceof Error) {
464
- if (error.message.includes("Cannot find module") && useTypeScript) {
465
- console.error(chalk_1.default.red("\nāŒ TypeScript module not found."));
466
- console.error(chalk_1.default.yellow("\nšŸ’” Try one of these solutions:\n" +
467
- " 1. Install ts-node: npm install -D ts-node\n" +
468
- " 2. Compile your TypeScript: npm run build\n" +
469
- " 3. Check that your migration files are in src/migrations/*.ts"));
470
- }
471
- else {
472
- console.error(chalk_1.default.red(error.message));
473
- }
474
- }
475
- else {
476
- console.error(chalk_1.default.red(String(error)));
477
- }
306
+ console.error(chalk_1.default.red(error instanceof Error ? error.message : String(error)));
478
307
  process.exit(1);
479
308
  }
480
309
  finally {
@@ -484,16 +313,13 @@ class MigrateCommand {
484
313
  }
485
314
  }
486
315
  static async createMigration(name) {
487
- // Always create TypeScript migrations
488
- const useTypeScript = true;
316
+ const useTypeScript = this.setupEnvironment();
489
317
  const spinner = (0, ora_1.default)("Creating TypeScript migration...").start();
490
318
  try {
319
+ const { migrations } = this.getPaths(true);
320
+ const migrationsDir = this.extractMigrationDirectory(migrations[0], true);
491
321
  const timestamp = Date.now();
492
- const fileExt = useTypeScript ? ".ts" : ".js";
493
- // Get migration directory from config
494
- const migrationPaths = this.getResolvedMigrationPaths(useTypeScript);
495
- const migrationsDir = path.dirname(migrationPaths[0].replace("/**/*", ""));
496
- const fileName = `${timestamp}-${name}${fileExt}`;
322
+ const fileName = `${timestamp}-${name}.ts`;
497
323
  const filePath = path.join(migrationsDir, fileName);
498
324
  const content = `import { MigrationInterface, QueryRunner } from 'typeorm';
499
325
 
@@ -506,10 +332,6 @@ export class ${name}${timestamp} implements MigrationInterface {
506
332
  await fs.ensureDir(path.dirname(filePath));
507
333
  await fs.writeFile(filePath, content);
508
334
  spinner.succeed(`TypeScript migration created: ${fileName}`);
509
- console.log(chalk_1.default.gray(`\nšŸ’” Note: Migration created as TypeScript file.\n` +
510
- ` To use it, either:\n` +
511
- ` 1. Install ts-node: npm install -D ts-node\n` +
512
- ` 2. Or compile to JavaScript: npm run build`));
513
335
  }
514
336
  catch (error) {
515
337
  spinner.fail("Failed to create migration");
@@ -518,21 +340,16 @@ export class ${name}${timestamp} implements MigrationInterface {
518
340
  }
519
341
  }
520
342
  static async revertMigration() {
521
- const useTypeScript = this.shouldUseTypeScript();
522
- const spinner = (0, ora_1.default)("Reverting migration...").start();
343
+ const useTypeScript = this.setupEnvironment();
344
+ const spinner = (0, ora_1.default)(`Reverting ${useTypeScript ? "TypeScript" : "JavaScript"} migration...`).start();
523
345
  let dataSource = null;
524
346
  try {
525
- // Register ts-node if using TypeScript
526
347
  this.registerTsNodeIfNeeded(useTypeScript);
527
- // Initialize DataSource with paths from fragment.json config
528
- const configOverride = {
529
- entities: this.getResolvedEntityPaths(useTypeScript),
530
- migrations: this.getResolvedMigrationPaths(useTypeScript),
531
- };
348
+ const { entities, migrations } = this.getPaths(useTypeScript);
349
+ const configOverride = { entities, migrations };
532
350
  dataSource = await typeorm_module_1.TypeORMModule.initialize(configOverride);
533
351
  await typeorm_module_1.TypeORMModule.revertMigration();
534
- const mode = useTypeScript ? "TypeScript" : "JavaScript";
535
- spinner.succeed(`${mode} migration reverted successfully`);
352
+ spinner.succeed(`${useTypeScript ? "TypeScript" : "JavaScript"} migration reverted successfully`);
536
353
  }
537
354
  catch (error) {
538
355
  spinner.fail("Revert failed");
@@ -546,22 +363,17 @@ export class ${name}${timestamp} implements MigrationInterface {
546
363
  }
547
364
  }
548
365
  static async refreshMigrations() {
549
- const useTypeScript = this.shouldUseTypeScript();
550
- const spinner = (0, ora_1.default)("Refreshing migrations...").start();
366
+ const useTypeScript = this.setupEnvironment();
367
+ const spinner = (0, ora_1.default)(`Refreshing ${useTypeScript ? "TypeScript" : "JavaScript"} migrations...`).start();
551
368
  let dataSource = null;
552
369
  try {
553
- // Register ts-node if using TypeScript
554
370
  this.registerTsNodeIfNeeded(useTypeScript);
555
- // Initialize DataSource with paths from fragment.json config
556
- const configOverride = {
557
- entities: this.getResolvedEntityPaths(useTypeScript),
558
- migrations: this.getResolvedMigrationPaths(useTypeScript),
559
- };
371
+ const { entities, migrations } = this.getPaths(useTypeScript);
372
+ const configOverride = { entities, migrations };
560
373
  dataSource = await typeorm_module_1.TypeORMModule.initialize(configOverride);
561
374
  await typeorm_module_1.TypeORMModule.dropSchema();
562
375
  await typeorm_module_1.TypeORMModule.runMigrations();
563
- const mode = useTypeScript ? "TypeScript" : "JavaScript";
564
- spinner.succeed(`${mode} migrations refreshed successfully`);
376
+ spinner.succeed(`${useTypeScript ? "TypeScript" : "JavaScript"} migrations refreshed successfully`);
565
377
  }
566
378
  catch (error) {
567
379
  spinner.fail("Refresh failed");
@@ -575,16 +387,12 @@ export class ${name}${timestamp} implements MigrationInterface {
575
387
  }
576
388
  }
577
389
  static async showStatus() {
578
- const useTypeScript = this.shouldUseTypeScript();
390
+ const useTypeScript = this.setupEnvironment();
579
391
  let dataSource = null;
580
392
  try {
581
- // Register ts-node if using TypeScript
582
393
  this.registerTsNodeIfNeeded(useTypeScript);
583
- // Initialize DataSource with paths from fragment.json config
584
- const configOverride = {
585
- entities: this.getResolvedEntityPaths(useTypeScript),
586
- migrations: this.getResolvedMigrationPaths(useTypeScript),
587
- };
394
+ const { entities, migrations } = this.getPaths(useTypeScript);
395
+ const configOverride = { entities, migrations };
588
396
  dataSource = await typeorm_module_1.TypeORMModule.initialize(configOverride);
589
397
  const executedMigrations = await dataSource.query(`SELECT * FROM migrations ORDER BY timestamp DESC`);
590
398
  const mode = useTypeScript ? "TypeScript" : "JavaScript";
@@ -598,9 +406,8 @@ export class ${name}${timestamp} implements MigrationInterface {
598
406
  console.log(` ${chalk_1.default.cyan(m.name)} - ${new Date(m.timestamp).toLocaleString()}`);
599
407
  });
600
408
  }
601
- // Show migration directory from config
602
- const migrationPaths = this.getResolvedMigrationPaths(useTypeScript);
603
- const migrationsDir = path.dirname(migrationPaths[0].replace("/**/*", ""));
409
+ const migrationsPattern = migrations[0];
410
+ const migrationsDir = this.extractMigrationDirectory(migrationsPattern, useTypeScript);
604
411
  const fileExt = useTypeScript ? ".ts" : ".js";
605
412
  if (fs.existsSync(migrationsDir)) {
606
413
  const files = fs
@@ -608,9 +415,7 @@ export class ${name}${timestamp} implements MigrationInterface {
608
415
  .filter((f) => f.endsWith(fileExt));
609
416
  console.log(chalk_1.default.blue(`\n Available ${mode.toLowerCase()} migration files: ${files.length}`));
610
417
  }
611
- // Show detection info
612
- console.log(chalk_1.default.gray(`\n Mode detection:`));
613
- console.log(chalk_1.default.gray(` - Environment mode: ${env_utils_1.EnvUtils.getEnvironmentMode()}`));
418
+ console.log(chalk_1.default.gray(`\n Configuration:`));
614
419
  console.log(chalk_1.default.gray(` - ts-node available: ${this.isTsNodeAvailable()}`));
615
420
  console.log(chalk_1.default.gray(` - Using: ${useTypeScript ? "TypeScript" : "JavaScript"}`));
616
421
  }
@@ -625,16 +430,13 @@ export class ${name}${timestamp} implements MigrationInterface {
625
430
  }
626
431
  }
627
432
  static async syncSchema() {
628
- const useTypeScript = this.shouldUseTypeScript();
629
- const spinner = (0, ora_1.default)("Synchronizing schema...").start();
433
+ const useTypeScript = this.setupEnvironment();
434
+ const spinner = (0, ora_1.default)(`Synchronizing ${useTypeScript ? "TypeScript" : "JavaScript"} schema...`).start();
630
435
  let dataSource = null;
631
436
  try {
632
- // Register ts-node if using TypeScript
633
437
  this.registerTsNodeIfNeeded(useTypeScript);
634
- // Initialize DataSource with entity paths from config
635
- const configOverride = {
636
- entities: this.getResolvedEntityPaths(useTypeScript),
637
- };
438
+ const { entities } = this.getPaths(useTypeScript);
439
+ const configOverride = { entities };
638
440
  dataSource = await typeorm_module_1.TypeORMModule.initialize(configOverride);
639
441
  await typeorm_module_1.TypeORMModule.syncSchema();
640
442
  spinner.succeed("Schema synchronized");
@@ -651,16 +453,13 @@ export class ${name}${timestamp} implements MigrationInterface {
651
453
  }
652
454
  }
653
455
  static async dropSchema() {
654
- const useTypeScript = this.shouldUseTypeScript();
655
- const spinner = (0, ora_1.default)("Dropping schema...").start();
456
+ const useTypeScript = this.setupEnvironment();
457
+ const spinner = (0, ora_1.default)(`Dropping ${useTypeScript ? "TypeScript" : "JavaScript"} schema...`).start();
656
458
  let dataSource = null;
657
459
  try {
658
- // Register ts-node if using TypeScript
659
460
  this.registerTsNodeIfNeeded(useTypeScript);
660
- // Initialize DataSource with entity paths from config
661
- const configOverride = {
662
- entities: this.getResolvedEntityPaths(useTypeScript),
663
- };
461
+ const { entities } = this.getPaths(useTypeScript);
462
+ const configOverride = { entities };
664
463
  dataSource = await typeorm_module_1.TypeORMModule.initialize(configOverride);
665
464
  await typeorm_module_1.TypeORMModule.dropSchema();
666
465
  spinner.succeed("Schema dropped");
@@ -677,40 +476,25 @@ export class ${name}${timestamp} implements MigrationInterface {
677
476
  }
678
477
  }
679
478
  static async runSeeds() {
680
- const spinner = (0, ora_1.default)("Running seeds...").start();
479
+ const useTypeScript = this.setupEnvironment();
480
+ const spinner = (0, ora_1.default)(`Running ${useTypeScript ? "TypeScript" : "JavaScript"} seeds...`).start();
681
481
  try {
682
- // Try TypeScript first if available
683
- const useTypeScript = this.shouldUseTypeScript();
684
- // Get seed directory from config or default
685
- const dbConfig = config_utils_1.ConfigUtils.getDatabaseConfig();
686
- let seedsDir = "";
687
- if (dbConfig.subscribers && dbConfig.subscribers.length > 0) {
688
- // Infer seeds directory from subscribers or migrations
689
- const migrationPaths = this.getResolvedMigrationPaths(useTypeScript);
690
- seedsDir = path.join(path.dirname(migrationPaths[0]), "..", "seeds");
691
- }
692
- else {
693
- // seedsDir = useTypeScript
694
- // ? path.join(process.cwd(), "src", "seeds")
695
- // : path.join(process.cwd(), "dist", "seeds");
696
- throw new Error("No seeds directory found");
482
+ const { seeds: seedsDir } = this.getPaths(useTypeScript);
483
+ if (!fs.existsSync(seedsDir)) {
484
+ spinner.info(`No seeds directory found at ${seedsDir}`);
485
+ return;
697
486
  }
698
- if (fs.existsSync(seedsDir)) {
699
- const files = fs.readdirSync(seedsDir);
700
- for (const file of files) {
701
- if (useTypeScript && file.endsWith(".ts")) {
702
- // For TypeScript, we need to register ts-node
487
+ const files = fs.readdirSync(seedsDir);
488
+ for (const file of files) {
489
+ const isTsFile = file.endsWith(".ts") && !file.endsWith(".d.ts");
490
+ const isJsFile = file.endsWith(".js");
491
+ if ((useTypeScript && isTsFile) || (!useTypeScript && isJsFile)) {
492
+ if (useTypeScript) {
703
493
  this.registerTsNodeIfNeeded(true);
704
- const seedModule = require(path.join(seedsDir, file));
705
- if (seedModule.default?.run) {
706
- await seedModule.default.run();
707
- }
708
494
  }
709
- else if (!useTypeScript && file.endsWith(".js")) {
710
- const seedModule = require(path.join(seedsDir, file));
711
- if (seedModule.default?.run) {
712
- await seedModule.default.run();
713
- }
495
+ const seedModule = require(path.join(seedsDir, file));
496
+ if (seedModule.default?.run) {
497
+ await seedModule.default.run();
714
498
  }
715
499
  }
716
500
  }
@@ -723,27 +507,17 @@ export class ${name}${timestamp} implements MigrationInterface {
723
507
  }
724
508
  }
725
509
  static async createSeed(name) {
726
- // Always create TypeScript seeds
510
+ const useTypeScript = this.setupEnvironment();
727
511
  const spinner = (0, ora_1.default)("Creating TypeScript seed...").start();
728
512
  try {
729
- // Get seed directory from config or default
730
- const dbConfig = config_utils_1.ConfigUtils.getDatabaseConfig();
731
- let seedsDir = "";
732
- if (dbConfig.subscribers && dbConfig.subscribers.length > 0) {
733
- const migrationPaths = this.getResolvedMigrationPaths(true);
734
- seedsDir = path.join(path.dirname(migrationPaths[0]), "..", "seeds");
735
- }
736
- else {
737
- seedsDir = path.join(process.cwd(), "src", "seeds");
738
- }
513
+ const { seeds: seedsDir } = this.getPaths(true);
739
514
  const fileName = `${name}.seed.ts`;
740
515
  const filePath = path.join(seedsDir, fileName);
741
516
  const content = `export default class ${name}Seed {
742
517
  static async run() {
743
518
  console.log('Running ${name} seed...');
744
519
  }
745
- }
746
- `;
520
+ }`;
747
521
  await fs.ensureDir(path.dirname(filePath));
748
522
  await fs.writeFile(filePath, content);
749
523
  spinner.succeed(`TypeScript seed created: ${fileName}`);
@@ -754,42 +528,32 @@ export class ${name}${timestamp} implements MigrationInterface {
754
528
  process.exit(1);
755
529
  }
756
530
  }
757
- // Keep existing helper methods unchanged
758
- static hasTypeScriptMigrations() {
759
- const srcMigrationsDir = path.join(process.cwd(), "src", "migrations");
760
- if (!fs.existsSync(srcMigrationsDir))
761
- return false;
762
- const tsFiles = fs
763
- .readdirSync(srcMigrationsDir)
764
- .filter((file) => file.endsWith(".ts"));
765
- return tsFiles.length > 0;
766
- }
767
- static hasJavaScriptMigrations() {
768
- const distMigrationsDir = path.join(process.cwd(), "dist", "migrations");
769
- if (!fs.existsSync(distMigrationsDir))
770
- return false;
771
- const jsFiles = fs
772
- .readdirSync(distMigrationsDir)
773
- .filter((file) => file.endsWith(".js"));
774
- return jsFiles.length > 0;
531
+ static verifyEntities(dataSource) {
532
+ const entities = dataSource.entityMetadatas;
533
+ if (entities.length === 0) {
534
+ throw new Error("No entities found!");
535
+ }
536
+ console.log(chalk_1.default.gray(`\nšŸ“¦ Loaded ${entities.length} entity/entities:`));
537
+ entities.forEach((entity) => {
538
+ console.log(chalk_1.default.gray(` - ${entity.name} (${entity.tableName})`));
539
+ });
540
+ console.log();
775
541
  }
776
- static findEntityFiles(dir, files = []) {
777
- const items = fs.readdirSync(dir);
778
- for (const item of items) {
779
- const fullPath = path.join(dir, item);
780
- const stat = fs.statSync(fullPath);
781
- if (stat.isDirectory()) {
782
- this.findEntityFiles(fullPath, files);
783
- }
784
- else if (item.endsWith(".entity.js")) {
785
- files.push(fullPath.replace(process.cwd(), "."));
786
- }
542
+ static buildQueryStatement(query) {
543
+ let sql = query.query
544
+ .replace(/\\/g, "\\\\")
545
+ .replace(/`/g, "\\`")
546
+ .replace(/\$/g, "\\$")
547
+ .replace(/\r\n/g, " ")
548
+ .replace(/\n/g, " ")
549
+ .replace(/\s+/g, " ")
550
+ .trim();
551
+ if (query.parameters && query.parameters.length > 0) {
552
+ const params = JSON.stringify(query.parameters);
553
+ return `await queryRunner.query(\`${sql}\`, ${params});`;
787
554
  }
788
- return files;
555
+ return `await queryRunner.query(\`${sql}\`);`;
789
556
  }
790
- /**
791
- * Build the complete migration file template
792
- */
793
557
  static buildMigrationTemplate(className, upStatements, downStatements, isFirstMigration) {
794
558
  const upBody = upStatements.length > 0
795
559
  ? upStatements.map((s) => ` ${s}`).join("\n")
@@ -797,13 +561,9 @@ export class ${name}${timestamp} implements MigrationInterface {
797
561
  const downBody = downStatements.length > 0
798
562
  ? downStatements.map((s) => ` ${s}`).join("\n")
799
563
  : " // No changes";
800
- const comment = isFirstMigration
801
- ? " // Initial migration - creates all tables\n"
802
- : "";
803
- return `import { MigrationInterface, QueryRunner } from "typeorm";
564
+ return `import { MigrationInterface, QueryRunner } from "fragment-ts";
804
565
 
805
566
  export class ${className} implements MigrationInterface {
806
- ${comment}
807
567
  public async up(queryRunner: QueryRunner): Promise<void> {
808
568
  ${upBody}
809
569
  }
@@ -811,11 +571,9 @@ ${upBody}
811
571
  public async down(queryRunner: QueryRunner): Promise<void> {
812
572
  ${downBody}
813
573
  }
814
- }
815
- `;
574
+ }`;
816
575
  }
817
576
  }
818
577
  exports.MigrateCommand = MigrateCommand;
819
578
  MigrateCommand.tsNodeAvailable = null;
820
- MigrateCommand.tsConfigExists = null;
821
579
  //# sourceMappingURL=migrate.command.js.map