@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/README.md +261 -23
- package/dist/cli.js +916 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +447 -278
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +144 -1
- package/dist/index.d.ts +144 -1
- package/dist/index.js +447 -277
- package/dist/index.js.map +1 -1
- package/package.json +10 -6
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
"use strict";
|
|
3
2
|
var __create = Object.create;
|
|
4
3
|
var __defProp = Object.defineProperty;
|
|
@@ -32,19 +31,177 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
32
31
|
var index_exports = {};
|
|
33
32
|
__export(index_exports, {
|
|
34
33
|
defineConfig: () => defineConfig,
|
|
35
|
-
loadConfig: () => loadConfig
|
|
34
|
+
loadConfig: () => loadConfig,
|
|
35
|
+
logger: () => logger,
|
|
36
|
+
registerDiffCommand: () => registerDiffCommand,
|
|
37
|
+
registerGenerateCommand: () => registerGenerateCommand,
|
|
38
|
+
registerInitCommand: () => registerInitCommand,
|
|
39
|
+
registerValidateCommand: () => registerValidateCommand,
|
|
40
|
+
runInit: () => runInit
|
|
36
41
|
});
|
|
37
42
|
module.exports = __toCommonJS(index_exports);
|
|
38
|
-
var import_commander = require("commander");
|
|
39
|
-
var import_omnify_core6 = require("@famgia/omnify-core");
|
|
40
43
|
|
|
41
|
-
// src/
|
|
44
|
+
// src/config/loader.ts
|
|
42
45
|
var import_node_fs = require("fs");
|
|
43
46
|
var import_node_path = require("path");
|
|
47
|
+
var import_jiti = require("jiti");
|
|
48
|
+
var import_omnify_core = require("@famgia/omnify-core");
|
|
49
|
+
var CONFIG_FILES = [
|
|
50
|
+
"omnify.config.ts",
|
|
51
|
+
"omnify.config.js",
|
|
52
|
+
"omnify.config.mjs",
|
|
53
|
+
"omnify.config.cjs"
|
|
54
|
+
];
|
|
55
|
+
function findConfigFile(startDir) {
|
|
56
|
+
const cwd = (0, import_node_path.resolve)(startDir);
|
|
57
|
+
for (const filename of CONFIG_FILES) {
|
|
58
|
+
const configPath = (0, import_node_path.resolve)(cwd, filename);
|
|
59
|
+
if ((0, import_node_fs.existsSync)(configPath)) {
|
|
60
|
+
return configPath;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
async function loadConfigFile(configPath) {
|
|
66
|
+
const jiti = (0, import_jiti.createJiti)(configPath, {
|
|
67
|
+
interopDefault: true,
|
|
68
|
+
moduleCache: false
|
|
69
|
+
});
|
|
70
|
+
try {
|
|
71
|
+
const module2 = await jiti.import(configPath);
|
|
72
|
+
const config = module2;
|
|
73
|
+
if ("default" in config) {
|
|
74
|
+
return config.default;
|
|
75
|
+
}
|
|
76
|
+
return config;
|
|
77
|
+
} catch (error) {
|
|
78
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
79
|
+
throw (0, import_omnify_core.configError)(
|
|
80
|
+
`Failed to load config file: ${message}. Check your omnify.config.ts for syntax errors.`,
|
|
81
|
+
"E002"
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function resolvePlugins(plugins, configPath) {
|
|
86
|
+
if (!plugins || plugins.length === 0) {
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
const resolved = [];
|
|
90
|
+
const configDir = configPath ? (0, import_node_path.dirname)(configPath) : process.cwd();
|
|
91
|
+
for (const plugin of plugins) {
|
|
92
|
+
if (typeof plugin === "string") {
|
|
93
|
+
const jiti = (0, import_jiti.createJiti)(configDir, {
|
|
94
|
+
interopDefault: true,
|
|
95
|
+
moduleCache: false
|
|
96
|
+
});
|
|
97
|
+
try {
|
|
98
|
+
const module2 = await jiti.import(plugin);
|
|
99
|
+
const loadedPlugin = module2.default ?? module2;
|
|
100
|
+
resolved.push(loadedPlugin);
|
|
101
|
+
} catch (error) {
|
|
102
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
103
|
+
throw (0, import_omnify_core.configError)(
|
|
104
|
+
`Failed to load plugin '${plugin}': ${message}. Ensure the plugin is installed: npm install ${plugin}`,
|
|
105
|
+
"E301"
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
resolved.push(plugin);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return resolved;
|
|
113
|
+
}
|
|
114
|
+
async function resolveConfig(userConfig, configPath) {
|
|
115
|
+
const plugins = await resolvePlugins(userConfig.plugins, configPath);
|
|
116
|
+
const databaseConfig = {
|
|
117
|
+
driver: userConfig.database.driver,
|
|
118
|
+
enableFieldComments: userConfig.database.enableFieldComments ?? false
|
|
119
|
+
};
|
|
120
|
+
const database = userConfig.database.devUrl !== void 0 ? { ...databaseConfig, devUrl: userConfig.database.devUrl } : databaseConfig;
|
|
121
|
+
const laravelConfig = {
|
|
122
|
+
migrationsPath: userConfig.output?.laravel?.migrationsPath ?? "database/migrations"
|
|
123
|
+
};
|
|
124
|
+
const laravel = buildLaravelConfig(laravelConfig, userConfig.output?.laravel);
|
|
125
|
+
const typescript = {
|
|
126
|
+
path: userConfig.output?.typescript?.path ?? "types",
|
|
127
|
+
singleFile: userConfig.output?.typescript?.singleFile ?? true,
|
|
128
|
+
generateEnums: userConfig.output?.typescript?.generateEnums ?? true,
|
|
129
|
+
generateRelationships: userConfig.output?.typescript?.generateRelationships ?? true
|
|
130
|
+
};
|
|
131
|
+
const result = {
|
|
132
|
+
schemasDir: userConfig.schemasDir ?? "./schemas",
|
|
133
|
+
database,
|
|
134
|
+
output: {
|
|
135
|
+
laravel,
|
|
136
|
+
typescript
|
|
137
|
+
},
|
|
138
|
+
plugins,
|
|
139
|
+
verbose: userConfig.verbose ?? false,
|
|
140
|
+
lockFilePath: userConfig.lockFilePath ?? ".omnify.lock"
|
|
141
|
+
};
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
function buildLaravelConfig(base, userLaravel) {
|
|
145
|
+
const config = { ...base };
|
|
146
|
+
if (userLaravel?.modelsPath !== void 0) {
|
|
147
|
+
config.modelsPath = userLaravel.modelsPath;
|
|
148
|
+
}
|
|
149
|
+
if (userLaravel?.modelsNamespace !== void 0) {
|
|
150
|
+
config.modelsNamespace = userLaravel.modelsNamespace;
|
|
151
|
+
}
|
|
152
|
+
if (userLaravel?.factoriesPath !== void 0) {
|
|
153
|
+
config.factoriesPath = userLaravel.factoriesPath;
|
|
154
|
+
}
|
|
155
|
+
if (userLaravel?.enumsPath !== void 0) {
|
|
156
|
+
config.enumsPath = userLaravel.enumsPath;
|
|
157
|
+
}
|
|
158
|
+
if (userLaravel?.enumsNamespace !== void 0) {
|
|
159
|
+
config.enumsNamespace = userLaravel.enumsNamespace;
|
|
160
|
+
}
|
|
161
|
+
return config;
|
|
162
|
+
}
|
|
163
|
+
function validateConfig(config, rootDir) {
|
|
164
|
+
const schemaPath = (0, import_node_path.resolve)(rootDir, config.schemasDir);
|
|
165
|
+
if (!(0, import_node_fs.existsSync)(schemaPath)) {
|
|
166
|
+
throw (0, import_omnify_core.configError)(
|
|
167
|
+
`Schema directory not found: ${schemaPath}. Create the '${config.schemasDir}' directory or update schemasDir in config.`,
|
|
168
|
+
"E002"
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function requireDevUrl(config) {
|
|
173
|
+
if (!config.database.devUrl) {
|
|
174
|
+
throw (0, import_omnify_core.configError)(
|
|
175
|
+
`database.devUrl is required for diff and generate operations. Add devUrl to your database config, e.g., "mysql://root@localhost:3306/omnify_dev"`,
|
|
176
|
+
"E003"
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async function loadConfig(startDir = process.cwd()) {
|
|
181
|
+
const cwd = (0, import_node_path.resolve)(startDir);
|
|
182
|
+
const configPath = findConfigFile(cwd);
|
|
183
|
+
if (configPath) {
|
|
184
|
+
const userConfig = await loadConfigFile(configPath);
|
|
185
|
+
const config = await resolveConfig(userConfig, configPath);
|
|
186
|
+
return {
|
|
187
|
+
config,
|
|
188
|
+
configPath
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
throw (0, import_omnify_core.configNotFoundError)((0, import_node_path.resolve)(cwd, "omnify.config.ts"));
|
|
192
|
+
}
|
|
193
|
+
function defineConfig(config) {
|
|
194
|
+
return config;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// src/commands/init.ts
|
|
198
|
+
var import_node_fs2 = require("fs");
|
|
199
|
+
var import_node_path2 = require("path");
|
|
200
|
+
var import_prompts = require("@inquirer/prompts");
|
|
44
201
|
|
|
45
202
|
// src/output/logger.ts
|
|
46
203
|
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
47
|
-
var
|
|
204
|
+
var import_omnify_core2 = require("@famgia/omnify-core");
|
|
48
205
|
var Logger = class {
|
|
49
206
|
_verbose;
|
|
50
207
|
_quiet;
|
|
@@ -153,21 +310,21 @@ var Logger = class {
|
|
|
153
310
|
* Format and log an OmnifyError.
|
|
154
311
|
*/
|
|
155
312
|
formatError(error) {
|
|
156
|
-
const formatted = (0,
|
|
313
|
+
const formatted = (0, import_omnify_core2.formatError)(error, { color: true });
|
|
157
314
|
console.error(formatted);
|
|
158
315
|
}
|
|
159
316
|
/**
|
|
160
317
|
* Get exit code for an error.
|
|
161
318
|
*/
|
|
162
319
|
getExitCode(error) {
|
|
163
|
-
return (0,
|
|
320
|
+
return (0, import_omnify_core2.getExitCode)(error);
|
|
164
321
|
}
|
|
165
322
|
};
|
|
166
323
|
var logger = new Logger();
|
|
167
324
|
|
|
168
325
|
// src/commands/init.ts
|
|
169
326
|
var EXAMPLE_SCHEMA = `# Example User schema
|
|
170
|
-
# See https://
|
|
327
|
+
# See https://github.com/famgia/omnify for documentation
|
|
171
328
|
|
|
172
329
|
name: User
|
|
173
330
|
displayName: User Account
|
|
@@ -192,78 +349,193 @@ options:
|
|
|
192
349
|
timestamps: true
|
|
193
350
|
softDelete: true
|
|
194
351
|
`;
|
|
195
|
-
|
|
352
|
+
function generateConfig(config) {
|
|
353
|
+
const imports = [`import { defineConfig } from '@famgia/omnify';`];
|
|
354
|
+
const plugins = [];
|
|
355
|
+
if (config.migrationTool === "laravel") {
|
|
356
|
+
imports.push(`import laravel from '@famgia/omnify-laravel/plugin';`);
|
|
357
|
+
plugins.push(` laravel({
|
|
358
|
+
migrationsPath: '${config.migrationsPath}',
|
|
359
|
+
typesPath: '${config.typesPath}',
|
|
360
|
+
singleFile: true,
|
|
361
|
+
generateMigrations: true,
|
|
362
|
+
generateTypes: ${config.generateTypes},
|
|
363
|
+
}),`);
|
|
364
|
+
}
|
|
365
|
+
if (config.migrationTool === "prisma") {
|
|
366
|
+
plugins.push(` // Prisma plugin coming soon!
|
|
367
|
+
// prisma({ schemaPath: 'prisma/schema.prisma' }),`);
|
|
368
|
+
}
|
|
369
|
+
if (config.migrationTool === "drizzle") {
|
|
370
|
+
plugins.push(` // Drizzle plugin coming soon!
|
|
371
|
+
// drizzle({ schemaPath: 'src/db/schema.ts' }),`);
|
|
372
|
+
}
|
|
373
|
+
if (config.migrationTool === "none" && config.generateTypes) {
|
|
374
|
+
imports.push(`import laravel from '@famgia/omnify-laravel/plugin';`);
|
|
375
|
+
plugins.push(` laravel({
|
|
376
|
+
typesPath: '${config.typesPath}',
|
|
377
|
+
generateMigrations: false,
|
|
378
|
+
generateTypes: true,
|
|
379
|
+
}),`);
|
|
380
|
+
}
|
|
381
|
+
const dbUrlExamples = {
|
|
382
|
+
mysql: "mysql://root:password@localhost:3306/omnify_dev",
|
|
383
|
+
postgres: "postgres://postgres:password@localhost:5432/omnify_dev",
|
|
384
|
+
sqlite: "sqlite://./omnify_dev.db"
|
|
385
|
+
};
|
|
386
|
+
return `${imports.join("\n")}
|
|
196
387
|
|
|
197
388
|
export default defineConfig({
|
|
198
389
|
// Schema files location
|
|
199
|
-
schemasDir: '
|
|
390
|
+
schemasDir: '${config.schemasDir}',
|
|
391
|
+
|
|
392
|
+
// Lock file for tracking schema changes
|
|
393
|
+
lockFilePath: './omnify.lock',
|
|
200
394
|
|
|
201
395
|
// Database configuration
|
|
202
396
|
database: {
|
|
203
|
-
driver: '
|
|
204
|
-
//
|
|
205
|
-
// devUrl: '
|
|
206
|
-
},
|
|
207
|
-
|
|
208
|
-
// Output configuration
|
|
209
|
-
output: {
|
|
210
|
-
laravel: {
|
|
211
|
-
migrationsPath: 'database/migrations',
|
|
212
|
-
},
|
|
213
|
-
typescript: {
|
|
214
|
-
path: 'types',
|
|
215
|
-
singleFile: true,
|
|
216
|
-
},
|
|
397
|
+
driver: '${config.database}',
|
|
398
|
+
// REQUIRED: Set your development database URL
|
|
399
|
+
// devUrl: '${dbUrlExamples[config.database]}',
|
|
217
400
|
},
|
|
218
401
|
|
|
219
|
-
//
|
|
402
|
+
// Generator plugins
|
|
220
403
|
plugins: [
|
|
221
|
-
|
|
404
|
+
${plugins.join("\n\n")}
|
|
222
405
|
],
|
|
223
406
|
});
|
|
224
407
|
`;
|
|
408
|
+
}
|
|
225
409
|
async function runInit(options) {
|
|
226
410
|
const cwd = process.cwd();
|
|
227
|
-
logger.header("
|
|
228
|
-
|
|
229
|
-
|
|
411
|
+
logger.header("Omnify Project Setup");
|
|
412
|
+
logger.newline();
|
|
413
|
+
const configPath = (0, import_node_path2.resolve)(cwd, "omnify.config.ts");
|
|
414
|
+
if ((0, import_node_fs2.existsSync)(configPath) && !options.force) {
|
|
230
415
|
logger.warn("omnify.config.ts already exists. Use --force to overwrite.");
|
|
231
416
|
return;
|
|
232
417
|
}
|
|
233
|
-
|
|
234
|
-
if (
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
logger.
|
|
418
|
+
let config;
|
|
419
|
+
if (options.yes) {
|
|
420
|
+
config = {
|
|
421
|
+
database: "mysql",
|
|
422
|
+
migrationTool: "laravel",
|
|
423
|
+
generateTypes: true,
|
|
424
|
+
migrationsPath: "database/migrations",
|
|
425
|
+
typesPath: "resources/js/types",
|
|
426
|
+
schemasDir: "./schemas"
|
|
427
|
+
};
|
|
428
|
+
logger.info("Using default configuration...");
|
|
244
429
|
} else {
|
|
245
|
-
logger.
|
|
430
|
+
logger.info("Answer a few questions to configure your project:\n");
|
|
431
|
+
const database = await (0, import_prompts.select)({
|
|
432
|
+
message: "Which database?",
|
|
433
|
+
choices: [
|
|
434
|
+
{ name: "MySQL / MariaDB", value: "mysql" },
|
|
435
|
+
{ name: "PostgreSQL", value: "postgres" },
|
|
436
|
+
{ name: "SQLite", value: "sqlite" }
|
|
437
|
+
],
|
|
438
|
+
default: "mysql"
|
|
439
|
+
});
|
|
440
|
+
const migrationTool = await (0, import_prompts.select)({
|
|
441
|
+
message: "Which migration tool?",
|
|
442
|
+
choices: [
|
|
443
|
+
{ name: "Laravel (PHP)", value: "laravel" },
|
|
444
|
+
{ name: "Prisma (coming soon)", value: "prisma", disabled: true },
|
|
445
|
+
{ name: "Drizzle (coming soon)", value: "drizzle", disabled: true },
|
|
446
|
+
{ name: "None (types only)", value: "none" }
|
|
447
|
+
],
|
|
448
|
+
default: "laravel"
|
|
449
|
+
});
|
|
450
|
+
const generateTypes = await (0, import_prompts.confirm)({
|
|
451
|
+
message: "Generate TypeScript types?",
|
|
452
|
+
default: true
|
|
453
|
+
});
|
|
454
|
+
const defaultPaths = {
|
|
455
|
+
laravel: { migrations: "database/migrations", types: "resources/js/types" },
|
|
456
|
+
prisma: { migrations: "prisma/migrations", types: "src/types" },
|
|
457
|
+
drizzle: { migrations: "drizzle", types: "src/types" },
|
|
458
|
+
none: { migrations: "", types: "types" }
|
|
459
|
+
};
|
|
460
|
+
const defaults = defaultPaths[migrationTool];
|
|
461
|
+
let migrationsPath = defaults.migrations;
|
|
462
|
+
let typesPath = defaults.types;
|
|
463
|
+
if (migrationTool !== "none") {
|
|
464
|
+
migrationsPath = await (0, import_prompts.input)({
|
|
465
|
+
message: "Migrations output path:",
|
|
466
|
+
default: defaults.migrations
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
if (generateTypes) {
|
|
470
|
+
typesPath = await (0, import_prompts.input)({
|
|
471
|
+
message: "TypeScript types path:",
|
|
472
|
+
default: defaults.types
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
const schemasDir2 = await (0, import_prompts.input)({
|
|
476
|
+
message: "Schemas directory:",
|
|
477
|
+
default: "./schemas"
|
|
478
|
+
});
|
|
479
|
+
config = {
|
|
480
|
+
database,
|
|
481
|
+
migrationTool,
|
|
482
|
+
generateTypes,
|
|
483
|
+
migrationsPath,
|
|
484
|
+
typesPath,
|
|
485
|
+
schemasDir: schemasDir2
|
|
486
|
+
};
|
|
246
487
|
}
|
|
247
|
-
(0, import_node_fs.writeFileSync)(configPath, EXAMPLE_CONFIG);
|
|
248
|
-
logger.step("Created omnify.config.ts");
|
|
249
488
|
logger.newline();
|
|
250
|
-
logger.
|
|
489
|
+
logger.step("Creating project files...");
|
|
490
|
+
const schemasDir = (0, import_node_path2.resolve)(cwd, config.schemasDir);
|
|
491
|
+
if (!(0, import_node_fs2.existsSync)(schemasDir)) {
|
|
492
|
+
(0, import_node_fs2.mkdirSync)(schemasDir, { recursive: true });
|
|
493
|
+
logger.debug(`Created ${config.schemasDir}/ directory`);
|
|
494
|
+
}
|
|
495
|
+
const examplePath = (0, import_node_path2.resolve)(schemasDir, "User.yaml");
|
|
496
|
+
if (!(0, import_node_fs2.existsSync)(examplePath) || options.force) {
|
|
497
|
+
(0, import_node_fs2.writeFileSync)(examplePath, EXAMPLE_SCHEMA);
|
|
498
|
+
logger.debug("Created example schema: User.yaml");
|
|
499
|
+
}
|
|
500
|
+
const configContent = generateConfig(config);
|
|
501
|
+
(0, import_node_fs2.writeFileSync)(configPath, configContent);
|
|
502
|
+
logger.debug("Created omnify.config.ts");
|
|
251
503
|
logger.newline();
|
|
252
|
-
logger.
|
|
504
|
+
logger.success("Project initialized!");
|
|
505
|
+
logger.newline();
|
|
506
|
+
const toolName = config.migrationTool === "laravel" ? "Laravel" : config.migrationTool === "prisma" ? "Prisma" : config.migrationTool === "drizzle" ? "Drizzle" : "None";
|
|
507
|
+
logger.info("Configuration:");
|
|
253
508
|
logger.list([
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
'Run "omnify diff" to preview changes',
|
|
258
|
-
'Run "omnify generate" to create migrations and types'
|
|
509
|
+
`Database: ${config.database}`,
|
|
510
|
+
`Migration tool: ${toolName}`,
|
|
511
|
+
`TypeScript types: ${config.generateTypes ? "Yes" : "No"}`
|
|
259
512
|
]);
|
|
513
|
+
logger.newline();
|
|
514
|
+
logger.info("Files created:");
|
|
515
|
+
logger.list(["omnify.config.ts", `${config.schemasDir}/User.yaml`]);
|
|
516
|
+
logger.newline();
|
|
517
|
+
logger.info("Next steps:");
|
|
518
|
+
logger.newline();
|
|
519
|
+
logger.step("1. Set database URL in omnify.config.ts");
|
|
520
|
+
logger.newline();
|
|
521
|
+
logger.step("2. Define schemas in " + config.schemasDir + "/");
|
|
522
|
+
logger.newline();
|
|
523
|
+
logger.step("3. Generate:");
|
|
524
|
+
logger.info(" npx omnify validate");
|
|
525
|
+
logger.info(" npx omnify generate");
|
|
526
|
+
logger.newline();
|
|
260
527
|
}
|
|
261
|
-
function registerInitCommand(
|
|
262
|
-
|
|
528
|
+
function registerInitCommand(program) {
|
|
529
|
+
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) => {
|
|
263
530
|
try {
|
|
264
531
|
await runInit(options);
|
|
265
532
|
} catch (error) {
|
|
266
533
|
if (error instanceof Error) {
|
|
534
|
+
if (error.message.includes("User force closed")) {
|
|
535
|
+
logger.newline();
|
|
536
|
+
logger.info("Setup cancelled.");
|
|
537
|
+
process.exit(0);
|
|
538
|
+
}
|
|
267
539
|
logger.error(error.message);
|
|
268
540
|
}
|
|
269
541
|
process.exit(1);
|
|
@@ -274,161 +546,6 @@ function registerInitCommand(program2) {
|
|
|
274
546
|
// src/commands/validate.ts
|
|
275
547
|
var import_node_path3 = require("path");
|
|
276
548
|
var import_omnify_core3 = require("@famgia/omnify-core");
|
|
277
|
-
|
|
278
|
-
// src/config/loader.ts
|
|
279
|
-
var import_node_fs2 = require("fs");
|
|
280
|
-
var import_node_path2 = require("path");
|
|
281
|
-
var import_jiti = require("jiti");
|
|
282
|
-
var import_omnify_core2 = require("@famgia/omnify-core");
|
|
283
|
-
var CONFIG_FILES = [
|
|
284
|
-
"omnify.config.ts",
|
|
285
|
-
"omnify.config.js",
|
|
286
|
-
"omnify.config.mjs",
|
|
287
|
-
"omnify.config.cjs"
|
|
288
|
-
];
|
|
289
|
-
function findConfigFile(startDir) {
|
|
290
|
-
const cwd = (0, import_node_path2.resolve)(startDir);
|
|
291
|
-
for (const filename of CONFIG_FILES) {
|
|
292
|
-
const configPath = (0, import_node_path2.resolve)(cwd, filename);
|
|
293
|
-
if ((0, import_node_fs2.existsSync)(configPath)) {
|
|
294
|
-
return configPath;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
return null;
|
|
298
|
-
}
|
|
299
|
-
async function loadConfigFile(configPath) {
|
|
300
|
-
const jiti = (0, import_jiti.createJiti)(configPath, {
|
|
301
|
-
interopDefault: true,
|
|
302
|
-
moduleCache: false
|
|
303
|
-
});
|
|
304
|
-
try {
|
|
305
|
-
const module2 = await jiti.import(configPath);
|
|
306
|
-
const config = module2;
|
|
307
|
-
if ("default" in config) {
|
|
308
|
-
return config.default;
|
|
309
|
-
}
|
|
310
|
-
return config;
|
|
311
|
-
} catch (error) {
|
|
312
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
313
|
-
throw (0, import_omnify_core2.configError)(
|
|
314
|
-
`Failed to load config file: ${message}. Check your omnify.config.ts for syntax errors.`,
|
|
315
|
-
"E002"
|
|
316
|
-
);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
async function resolvePlugins(plugins, configPath) {
|
|
320
|
-
if (!plugins || plugins.length === 0) {
|
|
321
|
-
return [];
|
|
322
|
-
}
|
|
323
|
-
const resolved = [];
|
|
324
|
-
const configDir = configPath ? (0, import_node_path2.dirname)(configPath) : process.cwd();
|
|
325
|
-
for (const plugin of plugins) {
|
|
326
|
-
if (typeof plugin === "string") {
|
|
327
|
-
const jiti = (0, import_jiti.createJiti)(configDir, {
|
|
328
|
-
interopDefault: true,
|
|
329
|
-
moduleCache: false
|
|
330
|
-
});
|
|
331
|
-
try {
|
|
332
|
-
const module2 = await jiti.import(plugin);
|
|
333
|
-
const loadedPlugin = module2.default ?? module2;
|
|
334
|
-
resolved.push(loadedPlugin);
|
|
335
|
-
} catch (error) {
|
|
336
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
337
|
-
throw (0, import_omnify_core2.configError)(
|
|
338
|
-
`Failed to load plugin '${plugin}': ${message}. Ensure the plugin is installed: npm install ${plugin}`,
|
|
339
|
-
"E301"
|
|
340
|
-
);
|
|
341
|
-
}
|
|
342
|
-
} else {
|
|
343
|
-
resolved.push(plugin);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
return resolved;
|
|
347
|
-
}
|
|
348
|
-
async function resolveConfig(userConfig, configPath) {
|
|
349
|
-
const plugins = await resolvePlugins(userConfig.plugins, configPath);
|
|
350
|
-
const databaseConfig = {
|
|
351
|
-
driver: userConfig.database.driver,
|
|
352
|
-
enableFieldComments: userConfig.database.enableFieldComments ?? false
|
|
353
|
-
};
|
|
354
|
-
const database = userConfig.database.devUrl !== void 0 ? { ...databaseConfig, devUrl: userConfig.database.devUrl } : databaseConfig;
|
|
355
|
-
const laravelConfig = {
|
|
356
|
-
migrationsPath: userConfig.output?.laravel?.migrationsPath ?? "database/migrations"
|
|
357
|
-
};
|
|
358
|
-
const laravel = buildLaravelConfig(laravelConfig, userConfig.output?.laravel);
|
|
359
|
-
const typescript = {
|
|
360
|
-
path: userConfig.output?.typescript?.path ?? "types",
|
|
361
|
-
singleFile: userConfig.output?.typescript?.singleFile ?? true,
|
|
362
|
-
generateEnums: userConfig.output?.typescript?.generateEnums ?? true,
|
|
363
|
-
generateRelationships: userConfig.output?.typescript?.generateRelationships ?? true
|
|
364
|
-
};
|
|
365
|
-
const result = {
|
|
366
|
-
schemasDir: userConfig.schemasDir ?? "./schemas",
|
|
367
|
-
database,
|
|
368
|
-
output: {
|
|
369
|
-
laravel,
|
|
370
|
-
typescript
|
|
371
|
-
},
|
|
372
|
-
plugins,
|
|
373
|
-
verbose: userConfig.verbose ?? false,
|
|
374
|
-
lockFilePath: userConfig.lockFilePath ?? ".omnify.lock"
|
|
375
|
-
};
|
|
376
|
-
return result;
|
|
377
|
-
}
|
|
378
|
-
function buildLaravelConfig(base, userLaravel) {
|
|
379
|
-
const config = { ...base };
|
|
380
|
-
if (userLaravel?.modelsPath !== void 0) {
|
|
381
|
-
config.modelsPath = userLaravel.modelsPath;
|
|
382
|
-
}
|
|
383
|
-
if (userLaravel?.modelsNamespace !== void 0) {
|
|
384
|
-
config.modelsNamespace = userLaravel.modelsNamespace;
|
|
385
|
-
}
|
|
386
|
-
if (userLaravel?.factoriesPath !== void 0) {
|
|
387
|
-
config.factoriesPath = userLaravel.factoriesPath;
|
|
388
|
-
}
|
|
389
|
-
if (userLaravel?.enumsPath !== void 0) {
|
|
390
|
-
config.enumsPath = userLaravel.enumsPath;
|
|
391
|
-
}
|
|
392
|
-
if (userLaravel?.enumsNamespace !== void 0) {
|
|
393
|
-
config.enumsNamespace = userLaravel.enumsNamespace;
|
|
394
|
-
}
|
|
395
|
-
return config;
|
|
396
|
-
}
|
|
397
|
-
function validateConfig(config, rootDir) {
|
|
398
|
-
const schemaPath = (0, import_node_path2.resolve)(rootDir, config.schemasDir);
|
|
399
|
-
if (!(0, import_node_fs2.existsSync)(schemaPath)) {
|
|
400
|
-
throw (0, import_omnify_core2.configError)(
|
|
401
|
-
`Schema directory not found: ${schemaPath}. Create the '${config.schemasDir}' directory or update schemasDir in config.`,
|
|
402
|
-
"E002"
|
|
403
|
-
);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
function requireDevUrl(config) {
|
|
407
|
-
if (!config.database.devUrl) {
|
|
408
|
-
throw (0, import_omnify_core2.configError)(
|
|
409
|
-
`database.devUrl is required for diff and generate operations. Add devUrl to your database config, e.g., "mysql://root@localhost:3306/omnify_dev"`,
|
|
410
|
-
"E003"
|
|
411
|
-
);
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
async function loadConfig(startDir = process.cwd()) {
|
|
415
|
-
const cwd = (0, import_node_path2.resolve)(startDir);
|
|
416
|
-
const configPath = findConfigFile(cwd);
|
|
417
|
-
if (configPath) {
|
|
418
|
-
const userConfig = await loadConfigFile(configPath);
|
|
419
|
-
const config = await resolveConfig(userConfig, configPath);
|
|
420
|
-
return {
|
|
421
|
-
config,
|
|
422
|
-
configPath
|
|
423
|
-
};
|
|
424
|
-
}
|
|
425
|
-
throw (0, import_omnify_core2.configNotFoundError)((0, import_node_path2.resolve)(cwd, "omnify.config.ts"));
|
|
426
|
-
}
|
|
427
|
-
function defineConfig(config) {
|
|
428
|
-
return config;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
// src/commands/validate.ts
|
|
432
549
|
async function runValidate(options) {
|
|
433
550
|
logger.setVerbose(options.verbose ?? false);
|
|
434
551
|
logger.header("Validating Schemas");
|
|
@@ -466,8 +583,8 @@ async function runValidate(options) {
|
|
|
466
583
|
process.exit(2);
|
|
467
584
|
}
|
|
468
585
|
}
|
|
469
|
-
function registerValidateCommand(
|
|
470
|
-
|
|
586
|
+
function registerValidateCommand(program) {
|
|
587
|
+
program.command("validate").description("Validate schema files").option("-v, --verbose", "Show detailed output").action(async (options) => {
|
|
471
588
|
try {
|
|
472
589
|
await runValidate(options);
|
|
473
590
|
} catch (error) {
|
|
@@ -567,8 +684,8 @@ async function runDiff(options) {
|
|
|
567
684
|
logger.newline();
|
|
568
685
|
logger.info('Run "omnify generate" to create migrations');
|
|
569
686
|
}
|
|
570
|
-
function registerDiffCommand(
|
|
571
|
-
|
|
687
|
+
function registerDiffCommand(program) {
|
|
688
|
+
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) => {
|
|
572
689
|
try {
|
|
573
690
|
await runDiff(options);
|
|
574
691
|
} catch (error) {
|
|
@@ -590,6 +707,88 @@ var import_node_path5 = require("path");
|
|
|
590
707
|
var import_omnify_core5 = require("@famgia/omnify-core");
|
|
591
708
|
var import_omnify_atlas2 = require("@famgia/omnify-atlas");
|
|
592
709
|
var import_omnify_laravel = require("@famgia/omnify-laravel");
|
|
710
|
+
function hasPluginGenerators(plugins) {
|
|
711
|
+
return plugins.some((p) => p.generators && p.generators.length > 0);
|
|
712
|
+
}
|
|
713
|
+
function writeGeneratorOutputs(outputs, rootDir) {
|
|
714
|
+
const counts = { migrations: 0, types: 0, other: 0 };
|
|
715
|
+
for (const output of outputs) {
|
|
716
|
+
const filePath = (0, import_node_path5.resolve)(rootDir, output.path);
|
|
717
|
+
const dir = (0, import_node_path5.dirname)(filePath);
|
|
718
|
+
if (!(0, import_node_fs3.existsSync)(dir)) {
|
|
719
|
+
(0, import_node_fs3.mkdirSync)(dir, { recursive: true });
|
|
720
|
+
logger.debug(`Created directory: ${dir}`);
|
|
721
|
+
}
|
|
722
|
+
(0, import_node_fs3.writeFileSync)(filePath, output.content);
|
|
723
|
+
logger.debug(`Created: ${output.path}`);
|
|
724
|
+
if (output.type === "migration") counts.migrations++;
|
|
725
|
+
else if (output.type === "type") counts.types++;
|
|
726
|
+
else counts.other++;
|
|
727
|
+
}
|
|
728
|
+
return counts;
|
|
729
|
+
}
|
|
730
|
+
async function runPluginGeneration(plugins, schemas, rootDir, verbose) {
|
|
731
|
+
const pluginManager = new import_omnify_core5.PluginManager({
|
|
732
|
+
cwd: rootDir,
|
|
733
|
+
verbose,
|
|
734
|
+
logger: {
|
|
735
|
+
debug: (msg) => logger.debug(msg),
|
|
736
|
+
info: (msg) => logger.info(msg),
|
|
737
|
+
warn: (msg) => logger.warn(msg),
|
|
738
|
+
error: (msg) => logger.error(msg)
|
|
739
|
+
}
|
|
740
|
+
});
|
|
741
|
+
for (const plugin of plugins) {
|
|
742
|
+
await pluginManager.register(plugin);
|
|
743
|
+
}
|
|
744
|
+
const result = await pluginManager.runGenerators(schemas);
|
|
745
|
+
if (!result.success) {
|
|
746
|
+
for (const error of result.errors) {
|
|
747
|
+
logger.error(`Generator ${error.generatorName} failed: ${error.message}`);
|
|
748
|
+
}
|
|
749
|
+
throw new Error("Generator execution failed");
|
|
750
|
+
}
|
|
751
|
+
return writeGeneratorOutputs(result.outputs, rootDir);
|
|
752
|
+
}
|
|
753
|
+
function runDirectGeneration(schemas, config, rootDir, options) {
|
|
754
|
+
let migrationsGenerated = 0;
|
|
755
|
+
let typesGenerated = 0;
|
|
756
|
+
if (!options.typesOnly && config.output.laravel) {
|
|
757
|
+
logger.step("Generating Laravel migrations...");
|
|
758
|
+
const migrationsDir = (0, import_node_path5.resolve)(rootDir, config.output.laravel.migrationsPath);
|
|
759
|
+
if (!(0, import_node_fs3.existsSync)(migrationsDir)) {
|
|
760
|
+
(0, import_node_fs3.mkdirSync)(migrationsDir, { recursive: true });
|
|
761
|
+
logger.debug(`Created directory: ${migrationsDir}`);
|
|
762
|
+
}
|
|
763
|
+
const migrations = (0, import_omnify_laravel.generateMigrations)(schemas);
|
|
764
|
+
for (const migration of migrations) {
|
|
765
|
+
const filePath = (0, import_node_path5.resolve)(migrationsDir, migration.fileName);
|
|
766
|
+
(0, import_node_fs3.writeFileSync)(filePath, migration.content);
|
|
767
|
+
logger.debug(`Created: ${migration.fileName}`);
|
|
768
|
+
migrationsGenerated++;
|
|
769
|
+
}
|
|
770
|
+
logger.success(`Generated ${migrationsGenerated} migration(s)`);
|
|
771
|
+
}
|
|
772
|
+
if (!options.migrationsOnly && config.output.typescript) {
|
|
773
|
+
logger.step("Generating TypeScript types...");
|
|
774
|
+
const typesDir = (0, import_node_path5.resolve)(rootDir, config.output.typescript.path);
|
|
775
|
+
if (!(0, import_node_fs3.existsSync)(typesDir)) {
|
|
776
|
+
(0, import_node_fs3.mkdirSync)(typesDir, { recursive: true });
|
|
777
|
+
logger.debug(`Created directory: ${typesDir}`);
|
|
778
|
+
}
|
|
779
|
+
const typeFiles = (0, import_omnify_laravel.generateTypeScript)(schemas, {
|
|
780
|
+
singleFile: config.output.typescript.singleFile
|
|
781
|
+
});
|
|
782
|
+
for (const file of typeFiles) {
|
|
783
|
+
const filePath = (0, import_node_path5.resolve)(typesDir, file.fileName);
|
|
784
|
+
(0, import_node_fs3.writeFileSync)(filePath, file.content);
|
|
785
|
+
logger.debug(`Created: ${file.fileName}`);
|
|
786
|
+
typesGenerated++;
|
|
787
|
+
}
|
|
788
|
+
logger.success(`Generated ${typesGenerated} TypeScript file(s)`);
|
|
789
|
+
}
|
|
790
|
+
return { migrations: migrationsGenerated, types: typesGenerated };
|
|
791
|
+
}
|
|
593
792
|
async function runGenerate(options) {
|
|
594
793
|
logger.setVerbose(options.verbose ?? false);
|
|
595
794
|
logger.header("Generating Outputs");
|
|
@@ -632,54 +831,48 @@ async function runGenerate(options) {
|
|
|
632
831
|
}
|
|
633
832
|
let migrationsGenerated = 0;
|
|
634
833
|
let typesGenerated = 0;
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
834
|
+
const usePlugins = hasPluginGenerators(config.plugins);
|
|
835
|
+
if (usePlugins) {
|
|
836
|
+
logger.step("Running plugin generators...");
|
|
837
|
+
const counts = await runPluginGeneration(
|
|
838
|
+
config.plugins,
|
|
839
|
+
schemas,
|
|
840
|
+
rootDir,
|
|
841
|
+
options.verbose ?? false
|
|
842
|
+
);
|
|
843
|
+
migrationsGenerated = counts.migrations;
|
|
844
|
+
typesGenerated = counts.types;
|
|
845
|
+
if (counts.migrations > 0) {
|
|
846
|
+
logger.success(`Generated ${counts.migrations} migration(s)`);
|
|
648
847
|
}
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
if (!options.migrationsOnly) {
|
|
652
|
-
logger.step("Generating TypeScript types...");
|
|
653
|
-
const typesDir = (0, import_node_path5.resolve)(rootDir, config.output.typescript.path);
|
|
654
|
-
if (!(0, import_node_fs3.existsSync)(typesDir)) {
|
|
655
|
-
(0, import_node_fs3.mkdirSync)(typesDir, { recursive: true });
|
|
656
|
-
logger.debug(`Created directory: ${typesDir}`);
|
|
848
|
+
if (counts.types > 0) {
|
|
849
|
+
logger.success(`Generated ${counts.types} TypeScript file(s)`);
|
|
657
850
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
});
|
|
661
|
-
for (const file of typeFiles) {
|
|
662
|
-
const filePath = (0, import_node_path5.resolve)(typesDir, file.fileName);
|
|
663
|
-
(0, import_node_fs3.writeFileSync)(filePath, file.content);
|
|
664
|
-
logger.debug(`Created: ${file.fileName}`);
|
|
665
|
-
typesGenerated++;
|
|
851
|
+
if (counts.other > 0) {
|
|
852
|
+
logger.success(`Generated ${counts.other} other file(s)`);
|
|
666
853
|
}
|
|
667
|
-
|
|
854
|
+
} else {
|
|
855
|
+
const counts = runDirectGeneration(schemas, config, rootDir, options);
|
|
856
|
+
migrationsGenerated = counts.migrations;
|
|
857
|
+
typesGenerated = counts.types;
|
|
668
858
|
}
|
|
669
859
|
logger.step("Updating lock file...");
|
|
670
|
-
await (0, import_omnify_atlas2.
|
|
860
|
+
const existingLock = await (0, import_omnify_atlas2.readLockFile)(lockPath);
|
|
861
|
+
const schemaHashes = await (0, import_omnify_atlas2.buildSchemaHashes)(schemas);
|
|
862
|
+
const newLockFile = (0, import_omnify_atlas2.updateLockFile)(existingLock, schemaHashes, config.database.driver);
|
|
863
|
+
await (0, import_omnify_atlas2.writeLockFile)(lockPath, newLockFile);
|
|
671
864
|
logger.debug(`Updated: ${config.lockFilePath}`);
|
|
672
865
|
logger.newline();
|
|
673
866
|
logger.success("Generation complete!");
|
|
674
|
-
if (migrationsGenerated > 0) {
|
|
867
|
+
if (migrationsGenerated > 0 && config.output.laravel) {
|
|
675
868
|
logger.info(` Migrations: ${config.output.laravel.migrationsPath}/`);
|
|
676
869
|
}
|
|
677
|
-
if (typesGenerated > 0) {
|
|
870
|
+
if (typesGenerated > 0 && config.output.typescript) {
|
|
678
871
|
logger.info(` Types: ${config.output.typescript.path}/`);
|
|
679
872
|
}
|
|
680
873
|
}
|
|
681
|
-
function registerGenerateCommand(
|
|
682
|
-
|
|
874
|
+
function registerGenerateCommand(program) {
|
|
875
|
+
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) => {
|
|
683
876
|
try {
|
|
684
877
|
await runGenerate(options);
|
|
685
878
|
} catch (error) {
|
|
@@ -694,39 +887,15 @@ function registerGenerateCommand(program2) {
|
|
|
694
887
|
}
|
|
695
888
|
});
|
|
696
889
|
}
|
|
697
|
-
|
|
698
|
-
// src/index.ts
|
|
699
|
-
var VERSION = "0.0.1";
|
|
700
|
-
var program = new import_commander.Command();
|
|
701
|
-
program.name("omnify").description("Schema-first database migrations for Laravel and TypeScript").version(VERSION);
|
|
702
|
-
registerInitCommand(program);
|
|
703
|
-
registerValidateCommand(program);
|
|
704
|
-
registerDiffCommand(program);
|
|
705
|
-
registerGenerateCommand(program);
|
|
706
|
-
process.on("uncaughtException", (error) => {
|
|
707
|
-
if (error instanceof import_omnify_core6.OmnifyError) {
|
|
708
|
-
logger.formatError(error);
|
|
709
|
-
process.exit(logger.getExitCode(error));
|
|
710
|
-
} else {
|
|
711
|
-
logger.error(error.message);
|
|
712
|
-
process.exit(1);
|
|
713
|
-
}
|
|
714
|
-
});
|
|
715
|
-
process.on("unhandledRejection", (reason) => {
|
|
716
|
-
if (reason instanceof import_omnify_core6.OmnifyError) {
|
|
717
|
-
logger.formatError(reason);
|
|
718
|
-
process.exit(logger.getExitCode(reason));
|
|
719
|
-
} else if (reason instanceof Error) {
|
|
720
|
-
logger.error(reason.message);
|
|
721
|
-
} else {
|
|
722
|
-
logger.error(String(reason));
|
|
723
|
-
}
|
|
724
|
-
process.exit(1);
|
|
725
|
-
});
|
|
726
|
-
program.parse();
|
|
727
890
|
// Annotate the CommonJS export names for ESM import in node:
|
|
728
891
|
0 && (module.exports = {
|
|
729
892
|
defineConfig,
|
|
730
|
-
loadConfig
|
|
893
|
+
loadConfig,
|
|
894
|
+
logger,
|
|
895
|
+
registerDiffCommand,
|
|
896
|
+
registerGenerateCommand,
|
|
897
|
+
registerInitCommand,
|
|
898
|
+
registerValidateCommand,
|
|
899
|
+
runInit
|
|
731
900
|
});
|
|
732
901
|
//# sourceMappingURL=index.cjs.map
|