@famgia/omnify-cli 0.0.4 → 0.0.6

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/dist/index.js CHANGED
@@ -1,12 +1,160 @@
1
- #!/usr/bin/env node
2
-
3
- // src/index.ts
4
- import { Command } from "commander";
5
- import { OmnifyError as OmnifyError5 } from "@famgia/omnify-core";
1
+ // src/config/loader.ts
2
+ import { existsSync } from "fs";
3
+ import { resolve, dirname } from "path";
4
+ import { createJiti } from "jiti";
5
+ import { configError, configNotFoundError } from "@famgia/omnify-core";
6
+ var CONFIG_FILES = [
7
+ "omnify.config.ts",
8
+ "omnify.config.js",
9
+ "omnify.config.mjs",
10
+ "omnify.config.cjs"
11
+ ];
12
+ function findConfigFile(startDir) {
13
+ const cwd = resolve(startDir);
14
+ for (const filename of CONFIG_FILES) {
15
+ const configPath = resolve(cwd, filename);
16
+ if (existsSync(configPath)) {
17
+ return configPath;
18
+ }
19
+ }
20
+ return null;
21
+ }
22
+ async function loadConfigFile(configPath) {
23
+ const jiti = createJiti(configPath, {
24
+ interopDefault: true,
25
+ moduleCache: false
26
+ });
27
+ try {
28
+ const module = await jiti.import(configPath);
29
+ const config = module;
30
+ if ("default" in config) {
31
+ return config.default;
32
+ }
33
+ return config;
34
+ } catch (error) {
35
+ const message = error instanceof Error ? error.message : String(error);
36
+ throw configError(
37
+ `Failed to load config file: ${message}. Check your omnify.config.ts for syntax errors.`,
38
+ "E002"
39
+ );
40
+ }
41
+ }
42
+ async function resolvePlugins(plugins, configPath) {
43
+ if (!plugins || plugins.length === 0) {
44
+ return [];
45
+ }
46
+ const resolved = [];
47
+ const configDir = configPath ? dirname(configPath) : process.cwd();
48
+ for (const plugin of plugins) {
49
+ if (typeof plugin === "string") {
50
+ const jiti = createJiti(configDir, {
51
+ interopDefault: true,
52
+ moduleCache: false
53
+ });
54
+ try {
55
+ const module = await jiti.import(plugin);
56
+ const loadedPlugin = module.default ?? module;
57
+ resolved.push(loadedPlugin);
58
+ } catch (error) {
59
+ const message = error instanceof Error ? error.message : String(error);
60
+ throw configError(
61
+ `Failed to load plugin '${plugin}': ${message}. Ensure the plugin is installed: npm install ${plugin}`,
62
+ "E301"
63
+ );
64
+ }
65
+ } else {
66
+ resolved.push(plugin);
67
+ }
68
+ }
69
+ return resolved;
70
+ }
71
+ async function resolveConfig(userConfig, configPath) {
72
+ const plugins = await resolvePlugins(userConfig.plugins, configPath);
73
+ const databaseConfig = {
74
+ driver: userConfig.database.driver,
75
+ enableFieldComments: userConfig.database.enableFieldComments ?? false
76
+ };
77
+ const database = userConfig.database.devUrl !== void 0 ? { ...databaseConfig, devUrl: userConfig.database.devUrl } : databaseConfig;
78
+ const laravelConfig = {
79
+ migrationsPath: userConfig.output?.laravel?.migrationsPath ?? "database/migrations"
80
+ };
81
+ const laravel = buildLaravelConfig(laravelConfig, userConfig.output?.laravel);
82
+ const typescript = {
83
+ path: userConfig.output?.typescript?.path ?? "types",
84
+ singleFile: userConfig.output?.typescript?.singleFile ?? true,
85
+ generateEnums: userConfig.output?.typescript?.generateEnums ?? true,
86
+ generateRelationships: userConfig.output?.typescript?.generateRelationships ?? true
87
+ };
88
+ const result = {
89
+ schemasDir: userConfig.schemasDir ?? "./schemas",
90
+ database,
91
+ output: {
92
+ laravel,
93
+ typescript
94
+ },
95
+ plugins,
96
+ verbose: userConfig.verbose ?? false,
97
+ lockFilePath: userConfig.lockFilePath ?? ".omnify.lock"
98
+ };
99
+ return result;
100
+ }
101
+ function buildLaravelConfig(base, userLaravel) {
102
+ const config = { ...base };
103
+ if (userLaravel?.modelsPath !== void 0) {
104
+ config.modelsPath = userLaravel.modelsPath;
105
+ }
106
+ if (userLaravel?.modelsNamespace !== void 0) {
107
+ config.modelsNamespace = userLaravel.modelsNamespace;
108
+ }
109
+ if (userLaravel?.factoriesPath !== void 0) {
110
+ config.factoriesPath = userLaravel.factoriesPath;
111
+ }
112
+ if (userLaravel?.enumsPath !== void 0) {
113
+ config.enumsPath = userLaravel.enumsPath;
114
+ }
115
+ if (userLaravel?.enumsNamespace !== void 0) {
116
+ config.enumsNamespace = userLaravel.enumsNamespace;
117
+ }
118
+ return config;
119
+ }
120
+ function validateConfig(config, rootDir) {
121
+ const schemaPath = resolve(rootDir, config.schemasDir);
122
+ if (!existsSync(schemaPath)) {
123
+ throw configError(
124
+ `Schema directory not found: ${schemaPath}. Create the '${config.schemasDir}' directory or update schemasDir in config.`,
125
+ "E002"
126
+ );
127
+ }
128
+ }
129
+ function requireDevUrl(config) {
130
+ if (!config.database.devUrl) {
131
+ throw configError(
132
+ `database.devUrl is required for diff and generate operations. Add devUrl to your database config, e.g., "mysql://root@localhost:3306/omnify_dev"`,
133
+ "E003"
134
+ );
135
+ }
136
+ }
137
+ async function loadConfig(startDir = process.cwd()) {
138
+ const cwd = resolve(startDir);
139
+ const configPath = findConfigFile(cwd);
140
+ if (configPath) {
141
+ const userConfig = await loadConfigFile(configPath);
142
+ const config = await resolveConfig(userConfig, configPath);
143
+ return {
144
+ config,
145
+ configPath
146
+ };
147
+ }
148
+ throw configNotFoundError(resolve(cwd, "omnify.config.ts"));
149
+ }
150
+ function defineConfig(config) {
151
+ return config;
152
+ }
6
153
 
7
154
  // src/commands/init.ts
8
- import { existsSync, mkdirSync, writeFileSync } from "fs";
9
- import { resolve } from "path";
155
+ import { existsSync as existsSync2, mkdirSync, writeFileSync } from "fs";
156
+ import { resolve as resolve2 } from "path";
157
+ import { select, confirm, input } from "@inquirer/prompts";
10
158
 
11
159
  // src/output/logger.ts
12
160
  import pc from "picocolors";
@@ -133,7 +281,7 @@ var logger = new Logger();
133
281
 
134
282
  // src/commands/init.ts
135
283
  var EXAMPLE_SCHEMA = `# Example User schema
136
- # See https://omnify.dev/docs/schemas for documentation
284
+ # See https://github.com/famgia/omnify for documentation
137
285
 
138
286
  name: User
139
287
  displayName: User Account
@@ -158,78 +306,193 @@ options:
158
306
  timestamps: true
159
307
  softDelete: true
160
308
  `;
161
- var EXAMPLE_CONFIG = `import { defineConfig } from '@famgia/omnify-cli';
309
+ function generateConfig(config) {
310
+ const imports = [`import { defineConfig } from '@famgia/omnify';`];
311
+ const plugins = [];
312
+ if (config.migrationTool === "laravel") {
313
+ imports.push(`import laravel from '@famgia/omnify-laravel/plugin';`);
314
+ plugins.push(` laravel({
315
+ migrationsPath: '${config.migrationsPath}',
316
+ typesPath: '${config.typesPath}',
317
+ singleFile: true,
318
+ generateMigrations: true,
319
+ generateTypes: ${config.generateTypes},
320
+ }),`);
321
+ }
322
+ if (config.migrationTool === "prisma") {
323
+ plugins.push(` // Prisma plugin coming soon!
324
+ // prisma({ schemaPath: 'prisma/schema.prisma' }),`);
325
+ }
326
+ if (config.migrationTool === "drizzle") {
327
+ plugins.push(` // Drizzle plugin coming soon!
328
+ // drizzle({ schemaPath: 'src/db/schema.ts' }),`);
329
+ }
330
+ if (config.migrationTool === "none" && config.generateTypes) {
331
+ imports.push(`import laravel from '@famgia/omnify-laravel/plugin';`);
332
+ plugins.push(` laravel({
333
+ typesPath: '${config.typesPath}',
334
+ generateMigrations: false,
335
+ generateTypes: true,
336
+ }),`);
337
+ }
338
+ const dbUrlExamples = {
339
+ mysql: "mysql://root:password@localhost:3306/omnify_dev",
340
+ postgres: "postgres://postgres:password@localhost:5432/omnify_dev",
341
+ sqlite: "sqlite://./omnify_dev.db"
342
+ };
343
+ return `${imports.join("\n")}
162
344
 
163
345
  export default defineConfig({
164
346
  // Schema files location
165
- schemasDir: './schemas',
347
+ schemasDir: '${config.schemasDir}',
348
+
349
+ // Lock file for tracking schema changes
350
+ lockFilePath: './omnify.lock',
166
351
 
167
352
  // Database configuration
168
353
  database: {
169
- driver: 'mysql',
170
- // Development database URL for Atlas diff operations
171
- // devUrl: 'mysql://root@localhost:3306/omnify_dev',
354
+ driver: '${config.database}',
355
+ // REQUIRED: Set your development database URL
356
+ // devUrl: '${dbUrlExamples[config.database]}',
172
357
  },
173
358
 
174
- // Output configuration
175
- output: {
176
- laravel: {
177
- migrationsPath: 'database/migrations',
178
- },
179
- typescript: {
180
- path: 'types',
181
- singleFile: true,
182
- },
183
- },
184
-
185
- // Plugins for custom types
359
+ // Generator plugins
186
360
  plugins: [
187
- // '@famgia/omnify-japan',
361
+ ${plugins.join("\n\n")}
188
362
  ],
189
363
  });
190
364
  `;
365
+ }
191
366
  async function runInit(options) {
192
367
  const cwd = process.cwd();
193
- logger.header("Initializing Omnify Project");
194
- const configPath = resolve(cwd, "omnify.config.ts");
195
- if (existsSync(configPath) && !options.force) {
368
+ logger.header("Omnify Project Setup");
369
+ logger.newline();
370
+ const configPath = resolve2(cwd, "omnify.config.ts");
371
+ if (existsSync2(configPath) && !options.force) {
196
372
  logger.warn("omnify.config.ts already exists. Use --force to overwrite.");
197
373
  return;
198
374
  }
199
- const schemasDir = resolve(cwd, "schemas");
200
- if (!existsSync(schemasDir)) {
201
- mkdirSync(schemasDir, { recursive: true });
202
- logger.step("Created schemas/ directory");
375
+ let config;
376
+ if (options.yes) {
377
+ config = {
378
+ database: "mysql",
379
+ migrationTool: "laravel",
380
+ generateTypes: true,
381
+ migrationsPath: "database/migrations",
382
+ typesPath: "resources/js/types",
383
+ schemasDir: "./schemas"
384
+ };
385
+ logger.info("Using default configuration...");
203
386
  } else {
204
- logger.debug("schemas/ directory already exists");
387
+ logger.info("Answer a few questions to configure your project:\n");
388
+ const database = await select({
389
+ message: "Which database?",
390
+ choices: [
391
+ { name: "MySQL / MariaDB", value: "mysql" },
392
+ { name: "PostgreSQL", value: "postgres" },
393
+ { name: "SQLite", value: "sqlite" }
394
+ ],
395
+ default: "mysql"
396
+ });
397
+ const migrationTool = await select({
398
+ message: "Which migration tool?",
399
+ choices: [
400
+ { name: "Laravel (PHP)", value: "laravel" },
401
+ { name: "Prisma (coming soon)", value: "prisma", disabled: true },
402
+ { name: "Drizzle (coming soon)", value: "drizzle", disabled: true },
403
+ { name: "None (types only)", value: "none" }
404
+ ],
405
+ default: "laravel"
406
+ });
407
+ const generateTypes = await confirm({
408
+ message: "Generate TypeScript types?",
409
+ default: true
410
+ });
411
+ const defaultPaths = {
412
+ laravel: { migrations: "database/migrations", types: "resources/js/types" },
413
+ prisma: { migrations: "prisma/migrations", types: "src/types" },
414
+ drizzle: { migrations: "drizzle", types: "src/types" },
415
+ none: { migrations: "", types: "types" }
416
+ };
417
+ const defaults = defaultPaths[migrationTool];
418
+ let migrationsPath = defaults.migrations;
419
+ let typesPath = defaults.types;
420
+ if (migrationTool !== "none") {
421
+ migrationsPath = await input({
422
+ message: "Migrations output path:",
423
+ default: defaults.migrations
424
+ });
425
+ }
426
+ if (generateTypes) {
427
+ typesPath = await input({
428
+ message: "TypeScript types path:",
429
+ default: defaults.types
430
+ });
431
+ }
432
+ const schemasDir2 = await input({
433
+ message: "Schemas directory:",
434
+ default: "./schemas"
435
+ });
436
+ config = {
437
+ database,
438
+ migrationTool,
439
+ generateTypes,
440
+ migrationsPath,
441
+ typesPath,
442
+ schemasDir: schemasDir2
443
+ };
444
+ }
445
+ logger.newline();
446
+ logger.step("Creating project files...");
447
+ const schemasDir = resolve2(cwd, config.schemasDir);
448
+ if (!existsSync2(schemasDir)) {
449
+ mkdirSync(schemasDir, { recursive: true });
450
+ logger.debug(`Created ${config.schemasDir}/ directory`);
205
451
  }
206
- const examplePath = resolve(schemasDir, "User.yaml");
207
- if (!existsSync(examplePath) || options.force) {
452
+ const examplePath = resolve2(schemasDir, "User.yaml");
453
+ if (!existsSync2(examplePath) || options.force) {
208
454
  writeFileSync(examplePath, EXAMPLE_SCHEMA);
209
- logger.step("Created example schema: schemas/User.yaml");
210
- } else {
211
- logger.debug("Example schema already exists");
455
+ logger.debug("Created example schema: User.yaml");
212
456
  }
213
- writeFileSync(configPath, EXAMPLE_CONFIG);
214
- logger.step("Created omnify.config.ts");
457
+ const configContent = generateConfig(config);
458
+ writeFileSync(configPath, configContent);
459
+ logger.debug("Created omnify.config.ts");
215
460
  logger.newline();
216
- logger.success("Project initialized successfully!");
461
+ logger.success("Project initialized!");
217
462
  logger.newline();
218
- logger.info("Next steps:");
463
+ const toolName = config.migrationTool === "laravel" ? "Laravel" : config.migrationTool === "prisma" ? "Prisma" : config.migrationTool === "drizzle" ? "Drizzle" : "None";
464
+ logger.info("Configuration:");
219
465
  logger.list([
220
- "Edit omnify.config.ts to configure your database",
221
- "Add your schema files to the schemas/ directory",
222
- 'Run "omnify validate" to check your schemas',
223
- 'Run "omnify diff" to preview changes',
224
- 'Run "omnify generate" to create migrations and types'
466
+ `Database: ${config.database}`,
467
+ `Migration tool: ${toolName}`,
468
+ `TypeScript types: ${config.generateTypes ? "Yes" : "No"}`
225
469
  ]);
470
+ logger.newline();
471
+ logger.info("Files created:");
472
+ logger.list(["omnify.config.ts", `${config.schemasDir}/User.yaml`]);
473
+ logger.newline();
474
+ logger.info("Next steps:");
475
+ logger.newline();
476
+ logger.step("1. Set database URL in omnify.config.ts");
477
+ logger.newline();
478
+ logger.step("2. Define schemas in " + config.schemasDir + "/");
479
+ logger.newline();
480
+ logger.step("3. Generate:");
481
+ logger.info(" npx omnify validate");
482
+ logger.info(" npx omnify generate");
483
+ logger.newline();
226
484
  }
227
- function registerInitCommand(program2) {
228
- program2.command("init").description("Initialize a new omnify project").option("-f, --force", "Overwrite existing files").action(async (options) => {
485
+ function registerInitCommand(program) {
486
+ program.command("init").description("Initialize a new omnify project").option("-f, --force", "Overwrite existing files").option("-y, --yes", "Use default configuration (skip prompts)").action(async (options) => {
229
487
  try {
230
488
  await runInit(options);
231
489
  } catch (error) {
232
490
  if (error instanceof Error) {
491
+ if (error.message.includes("User force closed")) {
492
+ logger.newline();
493
+ logger.info("Setup cancelled.");
494
+ process.exit(0);
495
+ }
233
496
  logger.error(error.message);
234
497
  }
235
498
  process.exit(1);
@@ -240,161 +503,6 @@ function registerInitCommand(program2) {
240
503
  // src/commands/validate.ts
241
504
  import { resolve as resolve3, dirname as dirname2 } from "path";
242
505
  import { loadSchemas, validateSchemas, OmnifyError as OmnifyError2 } from "@famgia/omnify-core";
243
-
244
- // src/config/loader.ts
245
- import { existsSync as existsSync2 } from "fs";
246
- import { resolve as resolve2, dirname } from "path";
247
- import { createJiti } from "jiti";
248
- import { configError, configNotFoundError } from "@famgia/omnify-core";
249
- var CONFIG_FILES = [
250
- "omnify.config.ts",
251
- "omnify.config.js",
252
- "omnify.config.mjs",
253
- "omnify.config.cjs"
254
- ];
255
- function findConfigFile(startDir) {
256
- const cwd = resolve2(startDir);
257
- for (const filename of CONFIG_FILES) {
258
- const configPath = resolve2(cwd, filename);
259
- if (existsSync2(configPath)) {
260
- return configPath;
261
- }
262
- }
263
- return null;
264
- }
265
- async function loadConfigFile(configPath) {
266
- const jiti = createJiti(configPath, {
267
- interopDefault: true,
268
- moduleCache: false
269
- });
270
- try {
271
- const module = await jiti.import(configPath);
272
- const config = module;
273
- if ("default" in config) {
274
- return config.default;
275
- }
276
- return config;
277
- } catch (error) {
278
- const message = error instanceof Error ? error.message : String(error);
279
- throw configError(
280
- `Failed to load config file: ${message}. Check your omnify.config.ts for syntax errors.`,
281
- "E002"
282
- );
283
- }
284
- }
285
- async function resolvePlugins(plugins, configPath) {
286
- if (!plugins || plugins.length === 0) {
287
- return [];
288
- }
289
- const resolved = [];
290
- const configDir = configPath ? dirname(configPath) : process.cwd();
291
- for (const plugin of plugins) {
292
- if (typeof plugin === "string") {
293
- const jiti = createJiti(configDir, {
294
- interopDefault: true,
295
- moduleCache: false
296
- });
297
- try {
298
- const module = await jiti.import(plugin);
299
- const loadedPlugin = module.default ?? module;
300
- resolved.push(loadedPlugin);
301
- } catch (error) {
302
- const message = error instanceof Error ? error.message : String(error);
303
- throw configError(
304
- `Failed to load plugin '${plugin}': ${message}. Ensure the plugin is installed: npm install ${plugin}`,
305
- "E301"
306
- );
307
- }
308
- } else {
309
- resolved.push(plugin);
310
- }
311
- }
312
- return resolved;
313
- }
314
- async function resolveConfig(userConfig, configPath) {
315
- const plugins = await resolvePlugins(userConfig.plugins, configPath);
316
- const databaseConfig = {
317
- driver: userConfig.database.driver,
318
- enableFieldComments: userConfig.database.enableFieldComments ?? false
319
- };
320
- const database = userConfig.database.devUrl !== void 0 ? { ...databaseConfig, devUrl: userConfig.database.devUrl } : databaseConfig;
321
- const laravelConfig = {
322
- migrationsPath: userConfig.output?.laravel?.migrationsPath ?? "database/migrations"
323
- };
324
- const laravel = buildLaravelConfig(laravelConfig, userConfig.output?.laravel);
325
- const typescript = {
326
- path: userConfig.output?.typescript?.path ?? "types",
327
- singleFile: userConfig.output?.typescript?.singleFile ?? true,
328
- generateEnums: userConfig.output?.typescript?.generateEnums ?? true,
329
- generateRelationships: userConfig.output?.typescript?.generateRelationships ?? true
330
- };
331
- const result = {
332
- schemasDir: userConfig.schemasDir ?? "./schemas",
333
- database,
334
- output: {
335
- laravel,
336
- typescript
337
- },
338
- plugins,
339
- verbose: userConfig.verbose ?? false,
340
- lockFilePath: userConfig.lockFilePath ?? ".omnify.lock"
341
- };
342
- return result;
343
- }
344
- function buildLaravelConfig(base, userLaravel) {
345
- const config = { ...base };
346
- if (userLaravel?.modelsPath !== void 0) {
347
- config.modelsPath = userLaravel.modelsPath;
348
- }
349
- if (userLaravel?.modelsNamespace !== void 0) {
350
- config.modelsNamespace = userLaravel.modelsNamespace;
351
- }
352
- if (userLaravel?.factoriesPath !== void 0) {
353
- config.factoriesPath = userLaravel.factoriesPath;
354
- }
355
- if (userLaravel?.enumsPath !== void 0) {
356
- config.enumsPath = userLaravel.enumsPath;
357
- }
358
- if (userLaravel?.enumsNamespace !== void 0) {
359
- config.enumsNamespace = userLaravel.enumsNamespace;
360
- }
361
- return config;
362
- }
363
- function validateConfig(config, rootDir) {
364
- const schemaPath = resolve2(rootDir, config.schemasDir);
365
- if (!existsSync2(schemaPath)) {
366
- throw configError(
367
- `Schema directory not found: ${schemaPath}. Create the '${config.schemasDir}' directory or update schemasDir in config.`,
368
- "E002"
369
- );
370
- }
371
- }
372
- function requireDevUrl(config) {
373
- if (!config.database.devUrl) {
374
- throw configError(
375
- `database.devUrl is required for diff and generate operations. Add devUrl to your database config, e.g., "mysql://root@localhost:3306/omnify_dev"`,
376
- "E003"
377
- );
378
- }
379
- }
380
- async function loadConfig(startDir = process.cwd()) {
381
- const cwd = resolve2(startDir);
382
- const configPath = findConfigFile(cwd);
383
- if (configPath) {
384
- const userConfig = await loadConfigFile(configPath);
385
- const config = await resolveConfig(userConfig, configPath);
386
- return {
387
- config,
388
- configPath
389
- };
390
- }
391
- throw configNotFoundError(resolve2(cwd, "omnify.config.ts"));
392
- }
393
- function defineConfig(config) {
394
- return config;
395
- }
396
-
397
- // src/commands/validate.ts
398
506
  async function runValidate(options) {
399
507
  logger.setVerbose(options.verbose ?? false);
400
508
  logger.header("Validating Schemas");
@@ -432,8 +540,8 @@ async function runValidate(options) {
432
540
  process.exit(2);
433
541
  }
434
542
  }
435
- function registerValidateCommand(program2) {
436
- program2.command("validate").description("Validate schema files").option("-v, --verbose", "Show detailed output").action(async (options) => {
543
+ function registerValidateCommand(program) {
544
+ program.command("validate").description("Validate schema files").option("-v, --verbose", "Show detailed output").action(async (options) => {
437
545
  try {
438
546
  await runValidate(options);
439
547
  } catch (error) {
@@ -536,8 +644,8 @@ async function runDiff(options) {
536
644
  logger.newline();
537
645
  logger.info('Run "omnify generate" to create migrations');
538
646
  }
539
- function registerDiffCommand(program2) {
540
- program2.command("diff").description("Show pending schema changes").option("-v, --verbose", "Show detailed output").option("--check", "Exit with code 1 if changes exist (for CI)").action(async (options) => {
647
+ function registerDiffCommand(program) {
648
+ program.command("diff").description("Show pending schema changes").option("-v, --verbose", "Show detailed output").option("--check", "Exit with code 1 if changes exist (for CI)").action(async (options) => {
541
649
  try {
542
650
  await runDiff(options);
543
651
  } catch (error) {
@@ -556,9 +664,101 @@ function registerDiffCommand(program2) {
556
664
  // src/commands/generate.ts
557
665
  import { existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
558
666
  import { resolve as resolve5, dirname as dirname4 } from "path";
559
- import { loadSchemas as loadSchemas3, validateSchemas as validateSchemas3, OmnifyError as OmnifyError4 } from "@famgia/omnify-core";
560
- import { updateLockFile } from "@famgia/omnify-atlas";
667
+ import {
668
+ loadSchemas as loadSchemas3,
669
+ validateSchemas as validateSchemas3,
670
+ OmnifyError as OmnifyError4,
671
+ PluginManager
672
+ } from "@famgia/omnify-core";
673
+ import {
674
+ writeLockFile,
675
+ readLockFile,
676
+ updateLockFile,
677
+ buildSchemaHashes
678
+ } from "@famgia/omnify-atlas";
561
679
  import { generateMigrations, generateTypeScript } from "@famgia/omnify-laravel";
680
+ function hasPluginGenerators(plugins) {
681
+ return plugins.some((p) => p.generators && p.generators.length > 0);
682
+ }
683
+ function writeGeneratorOutputs(outputs, rootDir) {
684
+ const counts = { migrations: 0, types: 0, other: 0 };
685
+ for (const output of outputs) {
686
+ const filePath = resolve5(rootDir, output.path);
687
+ const dir = dirname4(filePath);
688
+ if (!existsSync3(dir)) {
689
+ mkdirSync2(dir, { recursive: true });
690
+ logger.debug(`Created directory: ${dir}`);
691
+ }
692
+ writeFileSync2(filePath, output.content);
693
+ logger.debug(`Created: ${output.path}`);
694
+ if (output.type === "migration") counts.migrations++;
695
+ else if (output.type === "type") counts.types++;
696
+ else counts.other++;
697
+ }
698
+ return counts;
699
+ }
700
+ async function runPluginGeneration(plugins, schemas, rootDir, verbose) {
701
+ const pluginManager = new PluginManager({
702
+ cwd: rootDir,
703
+ verbose,
704
+ logger: {
705
+ debug: (msg) => logger.debug(msg),
706
+ info: (msg) => logger.info(msg),
707
+ warn: (msg) => logger.warn(msg),
708
+ error: (msg) => logger.error(msg)
709
+ }
710
+ });
711
+ for (const plugin of plugins) {
712
+ await pluginManager.register(plugin);
713
+ }
714
+ const result = await pluginManager.runGenerators(schemas);
715
+ if (!result.success) {
716
+ for (const error of result.errors) {
717
+ logger.error(`Generator ${error.generatorName} failed: ${error.message}`);
718
+ }
719
+ throw new Error("Generator execution failed");
720
+ }
721
+ return writeGeneratorOutputs(result.outputs, rootDir);
722
+ }
723
+ function runDirectGeneration(schemas, config, rootDir, options) {
724
+ let migrationsGenerated = 0;
725
+ let typesGenerated = 0;
726
+ if (!options.typesOnly && config.output.laravel) {
727
+ logger.step("Generating Laravel migrations...");
728
+ const migrationsDir = resolve5(rootDir, config.output.laravel.migrationsPath);
729
+ if (!existsSync3(migrationsDir)) {
730
+ mkdirSync2(migrationsDir, { recursive: true });
731
+ logger.debug(`Created directory: ${migrationsDir}`);
732
+ }
733
+ const migrations = generateMigrations(schemas);
734
+ for (const migration of migrations) {
735
+ const filePath = resolve5(migrationsDir, migration.fileName);
736
+ writeFileSync2(filePath, migration.content);
737
+ logger.debug(`Created: ${migration.fileName}`);
738
+ migrationsGenerated++;
739
+ }
740
+ logger.success(`Generated ${migrationsGenerated} migration(s)`);
741
+ }
742
+ if (!options.migrationsOnly && config.output.typescript) {
743
+ logger.step("Generating TypeScript types...");
744
+ const typesDir = resolve5(rootDir, config.output.typescript.path);
745
+ if (!existsSync3(typesDir)) {
746
+ mkdirSync2(typesDir, { recursive: true });
747
+ logger.debug(`Created directory: ${typesDir}`);
748
+ }
749
+ const typeFiles = generateTypeScript(schemas, {
750
+ singleFile: config.output.typescript.singleFile
751
+ });
752
+ for (const file of typeFiles) {
753
+ const filePath = resolve5(typesDir, file.fileName);
754
+ writeFileSync2(filePath, file.content);
755
+ logger.debug(`Created: ${file.fileName}`);
756
+ typesGenerated++;
757
+ }
758
+ logger.success(`Generated ${typesGenerated} TypeScript file(s)`);
759
+ }
760
+ return { migrations: migrationsGenerated, types: typesGenerated };
761
+ }
562
762
  async function runGenerate(options) {
563
763
  logger.setVerbose(options.verbose ?? false);
564
764
  logger.header("Generating Outputs");
@@ -601,54 +801,48 @@ async function runGenerate(options) {
601
801
  }
602
802
  let migrationsGenerated = 0;
603
803
  let typesGenerated = 0;
604
- if (!options.typesOnly) {
605
- logger.step("Generating Laravel migrations...");
606
- const migrationsDir = resolve5(rootDir, config.output.laravel.migrationsPath);
607
- if (!existsSync3(migrationsDir)) {
608
- mkdirSync2(migrationsDir, { recursive: true });
609
- logger.debug(`Created directory: ${migrationsDir}`);
804
+ const usePlugins = hasPluginGenerators(config.plugins);
805
+ if (usePlugins) {
806
+ logger.step("Running plugin generators...");
807
+ const counts = await runPluginGeneration(
808
+ config.plugins,
809
+ schemas,
810
+ rootDir,
811
+ options.verbose ?? false
812
+ );
813
+ migrationsGenerated = counts.migrations;
814
+ typesGenerated = counts.types;
815
+ if (counts.migrations > 0) {
816
+ logger.success(`Generated ${counts.migrations} migration(s)`);
610
817
  }
611
- const migrations = generateMigrations(schemas);
612
- for (const migration of migrations) {
613
- const filePath = resolve5(migrationsDir, migration.fileName);
614
- writeFileSync2(filePath, migration.content);
615
- logger.debug(`Created: ${migration.fileName}`);
616
- migrationsGenerated++;
818
+ if (counts.types > 0) {
819
+ logger.success(`Generated ${counts.types} TypeScript file(s)`);
617
820
  }
618
- logger.success(`Generated ${migrationsGenerated} migration(s)`);
619
- }
620
- if (!options.migrationsOnly) {
621
- logger.step("Generating TypeScript types...");
622
- const typesDir = resolve5(rootDir, config.output.typescript.path);
623
- if (!existsSync3(typesDir)) {
624
- mkdirSync2(typesDir, { recursive: true });
625
- logger.debug(`Created directory: ${typesDir}`);
821
+ if (counts.other > 0) {
822
+ logger.success(`Generated ${counts.other} other file(s)`);
626
823
  }
627
- const typeFiles = generateTypeScript(schemas, {
628
- singleFile: config.output.typescript.singleFile
629
- });
630
- for (const file of typeFiles) {
631
- const filePath = resolve5(typesDir, file.fileName);
632
- writeFileSync2(filePath, file.content);
633
- logger.debug(`Created: ${file.fileName}`);
634
- typesGenerated++;
635
- }
636
- logger.success(`Generated ${typesGenerated} TypeScript file(s)`);
824
+ } else {
825
+ const counts = runDirectGeneration(schemas, config, rootDir, options);
826
+ migrationsGenerated = counts.migrations;
827
+ typesGenerated = counts.types;
637
828
  }
638
829
  logger.step("Updating lock file...");
639
- await updateLockFile(lockPath, schemas);
830
+ const existingLock = await readLockFile(lockPath);
831
+ const schemaHashes = await buildSchemaHashes(schemas);
832
+ const newLockFile = updateLockFile(existingLock, schemaHashes, config.database.driver);
833
+ await writeLockFile(lockPath, newLockFile);
640
834
  logger.debug(`Updated: ${config.lockFilePath}`);
641
835
  logger.newline();
642
836
  logger.success("Generation complete!");
643
- if (migrationsGenerated > 0) {
837
+ if (migrationsGenerated > 0 && config.output.laravel) {
644
838
  logger.info(` Migrations: ${config.output.laravel.migrationsPath}/`);
645
839
  }
646
- if (typesGenerated > 0) {
840
+ if (typesGenerated > 0 && config.output.typescript) {
647
841
  logger.info(` Types: ${config.output.typescript.path}/`);
648
842
  }
649
843
  }
650
- function registerGenerateCommand(program2) {
651
- program2.command("generate").description("Generate Laravel migrations and TypeScript types").option("-v, --verbose", "Show detailed output").option("--migrations-only", "Only generate migrations").option("--types-only", "Only generate TypeScript types").option("-f, --force", "Generate even if no changes detected").action(async (options) => {
844
+ function registerGenerateCommand(program) {
845
+ program.command("generate").description("Generate Laravel migrations and TypeScript types").option("-v, --verbose", "Show detailed output").option("--migrations-only", "Only generate migrations").option("--types-only", "Only generate TypeScript types").option("-f, --force", "Generate even if no changes detected").action(async (options) => {
652
846
  try {
653
847
  await runGenerate(options);
654
848
  } catch (error) {
@@ -663,38 +857,14 @@ function registerGenerateCommand(program2) {
663
857
  }
664
858
  });
665
859
  }
666
-
667
- // src/index.ts
668
- var VERSION = "0.0.1";
669
- var program = new Command();
670
- program.name("omnify").description("Schema-first database migrations for Laravel and TypeScript").version(VERSION);
671
- registerInitCommand(program);
672
- registerValidateCommand(program);
673
- registerDiffCommand(program);
674
- registerGenerateCommand(program);
675
- process.on("uncaughtException", (error) => {
676
- if (error instanceof OmnifyError5) {
677
- logger.formatError(error);
678
- process.exit(logger.getExitCode(error));
679
- } else {
680
- logger.error(error.message);
681
- process.exit(1);
682
- }
683
- });
684
- process.on("unhandledRejection", (reason) => {
685
- if (reason instanceof OmnifyError5) {
686
- logger.formatError(reason);
687
- process.exit(logger.getExitCode(reason));
688
- } else if (reason instanceof Error) {
689
- logger.error(reason.message);
690
- } else {
691
- logger.error(String(reason));
692
- }
693
- process.exit(1);
694
- });
695
- program.parse();
696
860
  export {
697
861
  defineConfig,
698
- loadConfig
862
+ loadConfig,
863
+ logger,
864
+ registerDiffCommand,
865
+ registerGenerateCommand,
866
+ registerInitCommand,
867
+ registerValidateCommand,
868
+ runInit
699
869
  };
700
870
  //# sourceMappingURL=index.js.map