arkormx 0.2.5 → 0.2.7
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/cli.mjs +239 -90
- package/dist/index.cjs +169 -14
- package/dist/index.d.cts +40 -1
- package/dist/index.d.mts +40 -1
- package/dist/index.mjs +240 -92
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import { createRequire } from "module";
|
|
5
|
-
import { existsSync as existsSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, rmSync as rmSync$1, writeFileSync as writeFileSync$1 } from "node:fs";
|
|
6
|
-
import { dirname as dirname$1, extname as extname$1, join as join$1, resolve } from "node:path";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, extname, join, resolve } from "node:path";
|
|
7
4
|
import { spawnSync } from "node:child_process";
|
|
8
5
|
import { str } from "@h3ravel/support";
|
|
6
|
+
import path, { dirname as dirname$1, extname as extname$1, join as join$1, relative } from "path";
|
|
7
|
+
import { copyFileSync, existsSync as existsSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, rmSync as rmSync$1, writeFileSync as writeFileSync$1 } from "fs";
|
|
9
8
|
import { fileURLToPath, pathToFileURL } from "url";
|
|
9
|
+
import { createRequire } from "module";
|
|
10
10
|
import { Logger } from "@h3ravel/shared";
|
|
11
11
|
import { Command, Kernel } from "@h3ravel/musket";
|
|
12
12
|
import { createHash } from "node:crypto";
|
|
@@ -1008,14 +1008,14 @@ const generateMigrationFile = (name, options = {}) => {
|
|
|
1008
1008
|
const fileSlug = toMigrationFileSlug(name);
|
|
1009
1009
|
const className = resolveMigrationClassName(name);
|
|
1010
1010
|
const extension = options.extension ?? "ts";
|
|
1011
|
-
const directory = options.directory ?? join
|
|
1011
|
+
const directory = options.directory ?? join(process.cwd(), "database", "migrations");
|
|
1012
1012
|
const fileName = `${timestamp}_${fileSlug}.${extension}`;
|
|
1013
|
-
const filePath = join
|
|
1013
|
+
const filePath = join(directory, fileName);
|
|
1014
1014
|
const content = buildMigrationSource(className, extension);
|
|
1015
1015
|
if (options.write ?? true) {
|
|
1016
|
-
if (!existsSync
|
|
1017
|
-
if (existsSync
|
|
1018
|
-
writeFileSync
|
|
1016
|
+
if (!existsSync(directory)) mkdirSync(directory, { recursive: true });
|
|
1017
|
+
if (existsSync(filePath)) throw new ArkormException(`Migration file already exists: ${filePath}`);
|
|
1018
|
+
writeFileSync(filePath, content);
|
|
1019
1019
|
}
|
|
1020
1020
|
return {
|
|
1021
1021
|
fileName,
|
|
@@ -1048,12 +1048,32 @@ const getMigrationPlan = async (migration, direction = "up") => {
|
|
|
1048
1048
|
* @returns A promise that resolves to an object containing the updated schema, schema path, and list of operations applied.
|
|
1049
1049
|
*/
|
|
1050
1050
|
const applyMigrationToPrismaSchema = async (migration, options = {}) => {
|
|
1051
|
-
const schemaPath = options.schemaPath ?? join
|
|
1052
|
-
if (!existsSync
|
|
1053
|
-
const source = readFileSync
|
|
1051
|
+
const schemaPath = options.schemaPath ?? join(process.cwd(), "prisma", "schema.prisma");
|
|
1052
|
+
if (!existsSync(schemaPath)) throw new ArkormException(`Prisma schema file not found: ${schemaPath}`);
|
|
1053
|
+
const source = readFileSync(schemaPath, "utf-8");
|
|
1054
1054
|
const operations = await getMigrationPlan(migration, "up");
|
|
1055
1055
|
const schema = applyOperationsToPrismaSchema(source, operations);
|
|
1056
|
-
if (options.write ?? true) writeFileSync
|
|
1056
|
+
if (options.write ?? true) writeFileSync(schemaPath, schema);
|
|
1057
|
+
return {
|
|
1058
|
+
schema,
|
|
1059
|
+
schemaPath,
|
|
1060
|
+
operations
|
|
1061
|
+
};
|
|
1062
|
+
};
|
|
1063
|
+
/**
|
|
1064
|
+
* Apply the rollback (down) operations defined in a migration to a Prisma schema file.
|
|
1065
|
+
*
|
|
1066
|
+
* @param migration The migration class or instance to rollback.
|
|
1067
|
+
* @param options Options for applying the rollback, including schema path and write flag.
|
|
1068
|
+
* @returns A promise that resolves to an object containing the updated schema, schema path, and rollback operations applied.
|
|
1069
|
+
*/
|
|
1070
|
+
const applyMigrationRollbackToPrismaSchema = async (migration, options = {}) => {
|
|
1071
|
+
const schemaPath = options.schemaPath ?? join(process.cwd(), "prisma", "schema.prisma");
|
|
1072
|
+
if (!existsSync(schemaPath)) throw new ArkormException(`Prisma schema file not found: ${schemaPath}`);
|
|
1073
|
+
const source = readFileSync(schemaPath, "utf-8");
|
|
1074
|
+
const operations = await getMigrationPlan(migration, "down");
|
|
1075
|
+
const schema = applyOperationsToPrismaSchema(source, operations);
|
|
1076
|
+
if (options.write ?? true) writeFileSync(schemaPath, schema);
|
|
1057
1077
|
return {
|
|
1058
1078
|
schema,
|
|
1059
1079
|
schemaPath,
|
|
@@ -1068,7 +1088,7 @@ const resolveDefaultStubsPath = () => {
|
|
|
1068
1088
|
while (true) {
|
|
1069
1089
|
const packageJsonPath = path.join(current, "package.json");
|
|
1070
1090
|
const stubsPath = path.join(current, "stubs");
|
|
1071
|
-
if (existsSync(packageJsonPath) && existsSync(stubsPath)) return stubsPath;
|
|
1091
|
+
if (existsSync$1(packageJsonPath) && existsSync$1(stubsPath)) return stubsPath;
|
|
1072
1092
|
const parent = path.dirname(current);
|
|
1073
1093
|
if (parent === current) break;
|
|
1074
1094
|
current = parent;
|
|
@@ -1167,7 +1187,7 @@ const loadRuntimeConfigSync = () => {
|
|
|
1167
1187
|
const require = createRequire(import.meta.url);
|
|
1168
1188
|
const syncConfigPaths = [path.join(process.cwd(), "arkormx.config.cjs")];
|
|
1169
1189
|
for (const configPath of syncConfigPaths) {
|
|
1170
|
-
if (!existsSync(configPath)) continue;
|
|
1190
|
+
if (!existsSync$1(configPath)) continue;
|
|
1171
1191
|
try {
|
|
1172
1192
|
resolveAndApplyConfig(require(configPath));
|
|
1173
1193
|
return true;
|
|
@@ -1189,7 +1209,7 @@ const loadArkormConfig = async () => {
|
|
|
1189
1209
|
runtimeConfigLoadingPromise = (async () => {
|
|
1190
1210
|
const configPaths = [path.join(process.cwd(), "arkormx.config.js"), path.join(process.cwd(), "arkormx.config.ts")];
|
|
1191
1211
|
for (const configPath of configPaths) {
|
|
1192
|
-
if (!existsSync(configPath)) continue;
|
|
1212
|
+
if (!existsSync$1(configPath)) continue;
|
|
1193
1213
|
try {
|
|
1194
1214
|
resolveAndApplyConfig(await importConfigFile(configPath));
|
|
1195
1215
|
return;
|
|
@@ -1233,8 +1253,8 @@ var CliApp = class {
|
|
|
1233
1253
|
* @param filePath
|
|
1234
1254
|
*/
|
|
1235
1255
|
ensureDirectory(filePath) {
|
|
1236
|
-
const dir = dirname(filePath);
|
|
1237
|
-
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
1256
|
+
const dir = dirname$1(filePath);
|
|
1257
|
+
if (!existsSync$1(dir)) mkdirSync$1(dir, { recursive: true });
|
|
1238
1258
|
}
|
|
1239
1259
|
/**
|
|
1240
1260
|
* Convert absolute paths under current working directory into relative display paths.
|
|
@@ -1283,13 +1303,13 @@ var CliApp = class {
|
|
|
1283
1303
|
* @returns
|
|
1284
1304
|
*/
|
|
1285
1305
|
resolveRuntimeDirectoryPath(directoryPath) {
|
|
1286
|
-
if (existsSync(directoryPath)) return directoryPath;
|
|
1306
|
+
if (existsSync$1(directoryPath)) return directoryPath;
|
|
1287
1307
|
const { buildOutput } = this.getConfig("paths") || {};
|
|
1288
1308
|
if (typeof buildOutput !== "string" || buildOutput.trim().length === 0) return directoryPath;
|
|
1289
1309
|
const relativeSource = relative(process.cwd(), directoryPath);
|
|
1290
1310
|
if (!relativeSource || relativeSource.startsWith("..")) return directoryPath;
|
|
1291
|
-
const mappedDirectory = join(buildOutput, relativeSource);
|
|
1292
|
-
return existsSync(mappedDirectory) ? mappedDirectory : directoryPath;
|
|
1311
|
+
const mappedDirectory = join$1(buildOutput, relativeSource);
|
|
1312
|
+
return existsSync$1(mappedDirectory) ? mappedDirectory : directoryPath;
|
|
1293
1313
|
}
|
|
1294
1314
|
/**
|
|
1295
1315
|
* Resolve a script file path for runtime execution.
|
|
@@ -1300,7 +1320,7 @@ var CliApp = class {
|
|
|
1300
1320
|
* @returns
|
|
1301
1321
|
*/
|
|
1302
1322
|
resolveRuntimeScriptPath(filePath) {
|
|
1303
|
-
const extension = extname(filePath).toLowerCase();
|
|
1323
|
+
const extension = extname$1(filePath).toLowerCase();
|
|
1304
1324
|
const isTsFile = extension === ".ts" || extension === ".mts" || extension === ".cts";
|
|
1305
1325
|
const candidates = [];
|
|
1306
1326
|
if (isTsFile) {
|
|
@@ -1311,15 +1331,15 @@ var CliApp = class {
|
|
|
1311
1331
|
if (typeof buildOutput === "string" && buildOutput.trim().length > 0) {
|
|
1312
1332
|
const relativeSource = relative(process.cwd(), filePath);
|
|
1313
1333
|
if (relativeSource && !relativeSource.startsWith("..")) {
|
|
1314
|
-
const mappedFile = join(buildOutput, relativeSource);
|
|
1315
|
-
const mappedExtension = extname(mappedFile).toLowerCase();
|
|
1334
|
+
const mappedFile = join$1(buildOutput, relativeSource);
|
|
1335
|
+
const mappedExtension = extname$1(mappedFile).toLowerCase();
|
|
1316
1336
|
if (mappedExtension === ".ts" || mappedExtension === ".mts" || mappedExtension === ".cts") {
|
|
1317
1337
|
const mappedBase = mappedFile.slice(0, -mappedExtension.length);
|
|
1318
1338
|
candidates.push(`${mappedBase}.js`, `${mappedBase}.cjs`, `${mappedBase}.mjs`);
|
|
1319
1339
|
} else candidates.push(mappedFile);
|
|
1320
1340
|
}
|
|
1321
1341
|
}
|
|
1322
|
-
const runtimeMatch = candidates.find((path) => existsSync(path));
|
|
1342
|
+
const runtimeMatch = candidates.find((path) => existsSync$1(path));
|
|
1323
1343
|
if (runtimeMatch) return runtimeMatch;
|
|
1324
1344
|
return filePath;
|
|
1325
1345
|
}
|
|
@@ -1331,14 +1351,14 @@ var CliApp = class {
|
|
|
1331
1351
|
* @param replacements
|
|
1332
1352
|
*/
|
|
1333
1353
|
generateFile(stubPath, outputPath, replacements, options) {
|
|
1334
|
-
if (existsSync(outputPath) && !options?.force) {
|
|
1354
|
+
if (existsSync$1(outputPath) && !options?.force) {
|
|
1335
1355
|
this.command.error(`Error: ${this.formatPathForLog(outputPath)} already exists.`);
|
|
1336
1356
|
process.exit(1);
|
|
1337
|
-
} else if (existsSync(outputPath) && options?.force) rmSync(outputPath);
|
|
1338
|
-
let content = readFileSync(stubPath, "utf-8");
|
|
1357
|
+
} else if (existsSync$1(outputPath) && options?.force) rmSync$1(outputPath);
|
|
1358
|
+
let content = readFileSync$1(stubPath, "utf-8");
|
|
1339
1359
|
for (const [key, value] of Object.entries(replacements)) content = content.replace(new RegExp(`{{${key}}}`, "g"), value);
|
|
1340
1360
|
this.ensureDirectory(outputPath);
|
|
1341
|
-
writeFileSync(outputPath, content);
|
|
1361
|
+
writeFileSync$1(outputPath, content);
|
|
1342
1362
|
return outputPath;
|
|
1343
1363
|
}
|
|
1344
1364
|
/**
|
|
@@ -1360,7 +1380,7 @@ var CliApp = class {
|
|
|
1360
1380
|
* @returns
|
|
1361
1381
|
*/
|
|
1362
1382
|
resolveStubPath(stubName) {
|
|
1363
|
-
return join(this.resolveConfigPath("stubs", getDefaultStubsPath()), stubName);
|
|
1383
|
+
return join$1(this.resolveConfigPath("stubs", getDefaultStubsPath()), stubName);
|
|
1364
1384
|
}
|
|
1365
1385
|
/**
|
|
1366
1386
|
* Generate a factory file for a given model name.
|
|
@@ -1374,9 +1394,9 @@ var CliApp = class {
|
|
|
1374
1394
|
const factoryName = `${baseName}Factory`;
|
|
1375
1395
|
const modelName = options.modelName ? str(options.modelName).pascal() : baseName;
|
|
1376
1396
|
const outputExt = this.resolveOutputExt();
|
|
1377
|
-
const outputPath = join(this.resolveConfigPath("factories", join(process.cwd(), "database", "factories")), `${factoryName}.${outputExt}`);
|
|
1378
|
-
const modelPath = join(this.resolveConfigPath("models", join(process.cwd(), "src", "models")), `${modelName}.${outputExt}`);
|
|
1379
|
-
const relativeImport = options.modelImportPath ?? `./${this.stripKnownSourceExtension(relative(dirname(outputPath), modelPath).replace(/\\/g, "/"))}${outputExt === "js" ? ".js" : ""}`;
|
|
1397
|
+
const outputPath = join$1(this.resolveConfigPath("factories", join$1(process.cwd(), "database", "factories")), `${factoryName}.${outputExt}`);
|
|
1398
|
+
const modelPath = join$1(this.resolveConfigPath("models", join$1(process.cwd(), "src", "models")), `${modelName}.${outputExt}`);
|
|
1399
|
+
const relativeImport = options.modelImportPath ?? `./${this.stripKnownSourceExtension(relative(dirname$1(outputPath), modelPath).replace(/\\/g, "/"))}${outputExt === "js" ? ".js" : ""}`;
|
|
1380
1400
|
const stubPath = this.resolveStubPath(outputExt === "js" ? "factory.js.stub" : "factory.stub");
|
|
1381
1401
|
return {
|
|
1382
1402
|
name: factoryName,
|
|
@@ -1397,7 +1417,7 @@ var CliApp = class {
|
|
|
1397
1417
|
makeSeeder(name, options = {}) {
|
|
1398
1418
|
const seederName = `${str(name.replace(/Seeder$/, "")).pascal()}Seeder`;
|
|
1399
1419
|
const outputExt = this.resolveOutputExt();
|
|
1400
|
-
const outputPath = join(this.resolveConfigPath("seeders", join(process.cwd(), "database", "seeders")), `${seederName}.${outputExt}`);
|
|
1420
|
+
const outputPath = join$1(this.resolveConfigPath("seeders", join$1(process.cwd(), "database", "seeders")), `${seederName}.${outputExt}`);
|
|
1401
1421
|
const stubPath = this.resolveStubPath(outputExt === "js" ? "seeder.js.stub" : "seeder.stub");
|
|
1402
1422
|
return {
|
|
1403
1423
|
name: seederName,
|
|
@@ -1412,7 +1432,7 @@ var CliApp = class {
|
|
|
1412
1432
|
*/
|
|
1413
1433
|
makeMigration(name) {
|
|
1414
1434
|
const generated = generateMigrationFile(name, {
|
|
1415
|
-
directory: this.resolveConfigPath("migrations", join(process.cwd(), "database", "migrations")),
|
|
1435
|
+
directory: this.resolveConfigPath("migrations", join$1(process.cwd(), "database", "migrations")),
|
|
1416
1436
|
extension: this.resolveOutputExt()
|
|
1417
1437
|
});
|
|
1418
1438
|
return {
|
|
@@ -1432,13 +1452,13 @@ var CliApp = class {
|
|
|
1432
1452
|
const modelName = `${baseName}`;
|
|
1433
1453
|
const delegateName = str(baseName).camel().plural().toString();
|
|
1434
1454
|
const outputExt = this.resolveOutputExt();
|
|
1435
|
-
const outputPath = join(this.resolveConfigPath("models", join(process.cwd(), "src", "models")), `${modelName}.${outputExt}`);
|
|
1455
|
+
const outputPath = join$1(this.resolveConfigPath("models", join$1(process.cwd(), "src", "models")), `${modelName}.${outputExt}`);
|
|
1436
1456
|
const shouldBuildFactory = options.all || options.factory;
|
|
1437
1457
|
const shouldBuildSeeder = options.all || options.seeder;
|
|
1438
1458
|
const shouldBuildMigration = options.all || options.migration;
|
|
1439
1459
|
const factoryName = `${baseName}Factory`;
|
|
1440
|
-
const factoryPath = join(this.resolveConfigPath("factories", join(process.cwd(), "database", "factories")), `${factoryName}.${outputExt}`);
|
|
1441
|
-
const factoryImportPath = `./${relative(dirname(outputPath), factoryPath).replace(/\\/g, "/").replace(/\.(ts|tsx|mts|cts|js|mjs|cjs)$/i, "")}${outputExt === "js" ? ".js" : ""}`;
|
|
1460
|
+
const factoryPath = join$1(this.resolveConfigPath("factories", join$1(process.cwd(), "database", "factories")), `${factoryName}.${outputExt}`);
|
|
1461
|
+
const factoryImportPath = `./${relative(dirname$1(outputPath), factoryPath).replace(/\\/g, "/").replace(/\.(ts|tsx|mts|cts|js|mjs|cjs)$/i, "")}${outputExt === "js" ? ".js" : ""}`;
|
|
1442
1462
|
const stubPath = this.resolveStubPath(outputExt === "js" ? "model.js.stub" : "model.stub");
|
|
1443
1463
|
const modelPath = this.generateFile(stubPath, outputPath, {
|
|
1444
1464
|
ModelName: modelName,
|
|
@@ -1460,7 +1480,7 @@ var CliApp = class {
|
|
|
1460
1480
|
if (shouldBuildFactory) created.factory = this.makeFactory(baseName, {
|
|
1461
1481
|
force: options.force,
|
|
1462
1482
|
modelName,
|
|
1463
|
-
modelImportPath: `./${relative(dirname(factoryPath), outputPath).replace(/\\/g, "/").replace(/\.(ts|tsx|mts|cts|js|mjs|cjs)$/i, "")}${outputExt === "js" ? ".js" : ""}`
|
|
1483
|
+
modelImportPath: `./${relative(dirname$1(factoryPath), outputPath).replace(/\\/g, "/").replace(/\.(ts|tsx|mts|cts|js|mjs|cjs)$/i, "")}${outputExt === "js" ? ".js" : ""}`
|
|
1464
1484
|
});
|
|
1465
1485
|
if (shouldBuildSeeder) created.seeder = this.makeSeeder(baseName, { force: options.force });
|
|
1466
1486
|
if (shouldBuildMigration) created.migration = this.makeMigration(`create ${delegateName} table`);
|
|
@@ -1475,26 +1495,28 @@ var CliApp = class {
|
|
|
1475
1495
|
* @param delegateName The name of the delegate (table) to ensure in the Prisma schema.
|
|
1476
1496
|
*/
|
|
1477
1497
|
ensurePrismaModelEntry(modelName, delegateName) {
|
|
1478
|
-
const schemaPath = join(process.cwd(), "prisma", "schema.prisma");
|
|
1479
|
-
if (!existsSync(schemaPath)) return {
|
|
1498
|
+
const schemaPath = join$1(process.cwd(), "prisma", "schema.prisma");
|
|
1499
|
+
if (!existsSync$1(schemaPath)) return {
|
|
1480
1500
|
path: schemaPath,
|
|
1481
1501
|
updated: false
|
|
1482
1502
|
};
|
|
1483
|
-
const source = readFileSync(schemaPath, "utf-8");
|
|
1503
|
+
const source = readFileSync$1(schemaPath, "utf-8");
|
|
1484
1504
|
const existingByTable = findModelBlock(source, delegateName);
|
|
1485
1505
|
const existingByName = new RegExp(`model\\s+${modelName}\\s*\\{`, "m").test(source);
|
|
1486
1506
|
if (existingByTable || existingByName) return {
|
|
1487
1507
|
path: schemaPath,
|
|
1488
1508
|
updated: false
|
|
1489
1509
|
};
|
|
1490
|
-
writeFileSync(schemaPath, applyCreateTableOperation(source, {
|
|
1510
|
+
writeFileSync$1(schemaPath, applyCreateTableOperation(source, {
|
|
1491
1511
|
type: "createTable",
|
|
1492
1512
|
table: delegateName,
|
|
1493
1513
|
columns: [{
|
|
1494
1514
|
name: "id",
|
|
1495
1515
|
type: "id",
|
|
1496
1516
|
primary: true
|
|
1497
|
-
}]
|
|
1517
|
+
}],
|
|
1518
|
+
indexes: [],
|
|
1519
|
+
foreignKeys: []
|
|
1498
1520
|
}));
|
|
1499
1521
|
return {
|
|
1500
1522
|
path: schemaPath,
|
|
@@ -1546,14 +1568,14 @@ var CliApp = class {
|
|
|
1546
1568
|
body.split("\n").forEach((rawLine) => {
|
|
1547
1569
|
const line = rawLine.trim();
|
|
1548
1570
|
if (!line || line.startsWith("@@") || line.startsWith("//")) return;
|
|
1549
|
-
const fieldMatch = line.match(/^(\w+)\s+([A-Za-z]+)(\?)
|
|
1571
|
+
const fieldMatch = line.match(/^(\w+)\s+([A-Za-z]+)(\?)?(?:\s|$)/);
|
|
1550
1572
|
if (!fieldMatch) return;
|
|
1551
1573
|
const fieldType = fieldMatch[2];
|
|
1552
1574
|
if (!scalarTypes.has(fieldType)) return;
|
|
1553
1575
|
fields.push({
|
|
1554
1576
|
name: fieldMatch[1],
|
|
1555
1577
|
type: this.prismaTypeToTs(fieldType),
|
|
1556
|
-
|
|
1578
|
+
nullable: Boolean(fieldMatch[3])
|
|
1557
1579
|
});
|
|
1558
1580
|
});
|
|
1559
1581
|
models.push({
|
|
@@ -1620,18 +1642,18 @@ var CliApp = class {
|
|
|
1620
1642
|
* @returns An object with details about the synchronization process, including updated and skipped files.
|
|
1621
1643
|
*/
|
|
1622
1644
|
syncModelsFromPrisma(options = {}) {
|
|
1623
|
-
const schemaPath = options.schemaPath ?? join(process.cwd(), "prisma", "schema.prisma");
|
|
1624
|
-
const modelsDir = options.modelsDir ?? this.resolveConfigPath("models", join(process.cwd(), "src", "models"));
|
|
1625
|
-
if (!existsSync(schemaPath)) throw new Error(`Prisma schema file not found: ${schemaPath}`);
|
|
1626
|
-
if (!existsSync(modelsDir)) throw new Error(`Models directory not found: ${modelsDir}`);
|
|
1627
|
-
const schema = readFileSync(schemaPath, "utf-8");
|
|
1645
|
+
const schemaPath = options.schemaPath ?? join$1(process.cwd(), "prisma", "schema.prisma");
|
|
1646
|
+
const modelsDir = options.modelsDir ?? this.resolveConfigPath("models", join$1(process.cwd(), "src", "models"));
|
|
1647
|
+
if (!existsSync$1(schemaPath)) throw new Error(`Prisma schema file not found: ${schemaPath}`);
|
|
1648
|
+
if (!existsSync$1(modelsDir)) throw new Error(`Models directory not found: ${modelsDir}`);
|
|
1649
|
+
const schema = readFileSync$1(schemaPath, "utf-8");
|
|
1628
1650
|
const prismaModels = this.parsePrismaModels(schema);
|
|
1629
|
-
const modelFiles = readdirSync(modelsDir).filter((file) => file.endsWith(".ts"));
|
|
1651
|
+
const modelFiles = readdirSync$1(modelsDir).filter((file) => file.endsWith(".ts"));
|
|
1630
1652
|
const updated = [];
|
|
1631
1653
|
const skipped = [];
|
|
1632
1654
|
modelFiles.forEach((file) => {
|
|
1633
|
-
const filePath = join(modelsDir, file);
|
|
1634
|
-
const source = readFileSync(filePath, "utf-8");
|
|
1655
|
+
const filePath = join$1(modelsDir, file);
|
|
1656
|
+
const source = readFileSync$1(filePath, "utf-8");
|
|
1635
1657
|
const classMatch = source.match(/export\s+class\s+(\w+)\s+extends\s+Model<'([^']+)'>/);
|
|
1636
1658
|
if (!classMatch) {
|
|
1637
1659
|
skipped.push(filePath);
|
|
@@ -1644,13 +1666,13 @@ var CliApp = class {
|
|
|
1644
1666
|
skipped.push(filePath);
|
|
1645
1667
|
return;
|
|
1646
1668
|
}
|
|
1647
|
-
const declarations = prismaModel.fields.map((field) => `declare ${field.name}${field.
|
|
1669
|
+
const declarations = prismaModel.fields.map((field) => `declare ${field.name}: ${field.type}${field.nullable ? " | null" : ""}`);
|
|
1648
1670
|
const synced = this.syncModelDeclarations(source, declarations);
|
|
1649
1671
|
if (!synced.updated) {
|
|
1650
1672
|
skipped.push(filePath);
|
|
1651
1673
|
return;
|
|
1652
1674
|
}
|
|
1653
|
-
writeFileSync(filePath, synced.content);
|
|
1675
|
+
writeFileSync$1(filePath, synced.content);
|
|
1654
1676
|
updated.push(filePath);
|
|
1655
1677
|
});
|
|
1656
1678
|
return {
|
|
@@ -1682,23 +1704,23 @@ var InitCommand = class extends Command {
|
|
|
1682
1704
|
*/
|
|
1683
1705
|
async handle() {
|
|
1684
1706
|
this.app.command = this;
|
|
1685
|
-
const outputDir = join
|
|
1707
|
+
const outputDir = join(process.cwd(), "arkormx.config.js");
|
|
1686
1708
|
const { stubs } = getUserConfig("paths") ?? {};
|
|
1687
1709
|
const stubsDir = typeof stubs === "string" && stubs.trim().length > 0 ? stubs : getDefaultStubsPath();
|
|
1688
|
-
const preferredStubPath = join
|
|
1689
|
-
const legacyStubPath = join
|
|
1690
|
-
const stubPath = existsSync(preferredStubPath) ? preferredStubPath : legacyStubPath;
|
|
1691
|
-
if (existsSync(outputDir) && !this.option("force")) {
|
|
1710
|
+
const preferredStubPath = join(stubsDir, "arkormx.config.stub");
|
|
1711
|
+
const legacyStubPath = join(stubsDir, "arkorm.config.stub");
|
|
1712
|
+
const stubPath = existsSync$1(preferredStubPath) ? preferredStubPath : legacyStubPath;
|
|
1713
|
+
if (existsSync$1(outputDir) && !this.option("force")) {
|
|
1692
1714
|
this.error("Error: Arkormˣ has already been initialized. Use --force to reinitialize.");
|
|
1693
1715
|
process.exit(1);
|
|
1694
1716
|
}
|
|
1695
1717
|
this.app.ensureDirectory(outputDir);
|
|
1696
|
-
if (existsSync(outputDir) && this.option("force")) copyFileSync(outputDir, outputDir.replace(/\.js$/, `.backup.${Date.now()}.js`));
|
|
1697
|
-
if (!existsSync(stubPath)) {
|
|
1718
|
+
if (existsSync$1(outputDir) && this.option("force")) copyFileSync(outputDir, outputDir.replace(/\.js$/, `.backup.${Date.now()}.js`));
|
|
1719
|
+
if (!existsSync$1(stubPath)) {
|
|
1698
1720
|
this.error(`Error: Missing config stub at ${preferredStubPath} (or ${legacyStubPath})`);
|
|
1699
1721
|
process.exit(1);
|
|
1700
1722
|
}
|
|
1701
|
-
writeFileSync(outputDir, readFileSync(stubPath, "utf-8"));
|
|
1723
|
+
writeFileSync$1(outputDir, readFileSync$1(stubPath, "utf-8"));
|
|
1702
1724
|
this.success("Arkormˣ initialized successfully!");
|
|
1703
1725
|
}
|
|
1704
1726
|
};
|
|
@@ -1828,39 +1850,43 @@ var MakeSeederCommand = class extends Command {
|
|
|
1828
1850
|
//#region src/helpers/migration-history.ts
|
|
1829
1851
|
const DEFAULT_STATE = {
|
|
1830
1852
|
version: 1,
|
|
1831
|
-
migrations: []
|
|
1853
|
+
migrations: [],
|
|
1854
|
+
runs: []
|
|
1832
1855
|
};
|
|
1833
1856
|
const resolveMigrationStateFilePath = (cwd, configuredPath) => {
|
|
1834
1857
|
if (configuredPath && configuredPath.trim().length > 0) return resolve(configuredPath);
|
|
1835
|
-
return join
|
|
1858
|
+
return join(cwd, ".arkormx", "migrations.applied.json");
|
|
1836
1859
|
};
|
|
1837
1860
|
const buildMigrationIdentity = (filePath, className) => {
|
|
1838
1861
|
const fileName = filePath.split("/").pop()?.split("\\").pop() ?? filePath;
|
|
1839
|
-
return `${fileName.slice(0, fileName.length - extname
|
|
1862
|
+
return `${fileName.slice(0, fileName.length - extname(fileName).length)}:${className}`;
|
|
1840
1863
|
};
|
|
1841
1864
|
const computeMigrationChecksum = (filePath) => {
|
|
1842
|
-
const source = readFileSync
|
|
1865
|
+
const source = readFileSync(filePath, "utf-8");
|
|
1843
1866
|
return createHash("sha256").update(source).digest("hex");
|
|
1844
1867
|
};
|
|
1845
1868
|
const readAppliedMigrationsState = (stateFilePath) => {
|
|
1846
|
-
if (!existsSync
|
|
1869
|
+
if (!existsSync(stateFilePath)) return { ...DEFAULT_STATE };
|
|
1847
1870
|
try {
|
|
1848
|
-
const parsed = JSON.parse(readFileSync
|
|
1871
|
+
const parsed = JSON.parse(readFileSync(stateFilePath, "utf-8"));
|
|
1849
1872
|
if (!Array.isArray(parsed.migrations)) return { ...DEFAULT_STATE };
|
|
1850
1873
|
return {
|
|
1851
1874
|
version: 1,
|
|
1852
1875
|
migrations: parsed.migrations.filter((migration) => {
|
|
1853
1876
|
return typeof migration?.id === "string" && typeof migration?.file === "string" && typeof migration?.className === "string" && typeof migration?.appliedAt === "string" && (migration?.checksum === void 0 || typeof migration?.checksum === "string");
|
|
1854
|
-
})
|
|
1877
|
+
}),
|
|
1878
|
+
runs: Array.isArray(parsed.runs) ? parsed.runs.filter((run) => {
|
|
1879
|
+
return typeof run?.id === "string" && typeof run?.appliedAt === "string" && Array.isArray(run?.migrationIds) && run.migrationIds.every((item) => typeof item === "string");
|
|
1880
|
+
}) : []
|
|
1855
1881
|
};
|
|
1856
1882
|
} catch {
|
|
1857
1883
|
return { ...DEFAULT_STATE };
|
|
1858
1884
|
}
|
|
1859
1885
|
};
|
|
1860
1886
|
const writeAppliedMigrationsState = (stateFilePath, state) => {
|
|
1861
|
-
const directory = dirname
|
|
1862
|
-
if (!existsSync
|
|
1863
|
-
writeFileSync
|
|
1887
|
+
const directory = dirname(stateFilePath);
|
|
1888
|
+
if (!existsSync(directory)) mkdirSync(directory, { recursive: true });
|
|
1889
|
+
writeFileSync(stateFilePath, JSON.stringify(state, null, 2));
|
|
1864
1890
|
};
|
|
1865
1891
|
const isMigrationApplied = (state, identity, checksum) => {
|
|
1866
1892
|
const matched = state.migrations.find((migration) => migration.id === identity);
|
|
@@ -1877,9 +1903,40 @@ const markMigrationApplied = (state, entry) => {
|
|
|
1877
1903
|
next.push(entry);
|
|
1878
1904
|
return {
|
|
1879
1905
|
version: 1,
|
|
1880
|
-
migrations: next
|
|
1906
|
+
migrations: next,
|
|
1907
|
+
runs: state.runs ?? []
|
|
1881
1908
|
};
|
|
1882
1909
|
};
|
|
1910
|
+
const removeAppliedMigration = (state, identity) => {
|
|
1911
|
+
return {
|
|
1912
|
+
version: 1,
|
|
1913
|
+
migrations: state.migrations.filter((migration) => migration.id !== identity),
|
|
1914
|
+
runs: (state.runs ?? []).map((run) => ({
|
|
1915
|
+
...run,
|
|
1916
|
+
migrationIds: run.migrationIds.filter((id) => id !== identity)
|
|
1917
|
+
})).filter((run) => run.migrationIds.length > 0)
|
|
1918
|
+
};
|
|
1919
|
+
};
|
|
1920
|
+
const buildMigrationRunId = () => {
|
|
1921
|
+
return `run_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
1922
|
+
};
|
|
1923
|
+
const markMigrationRun = (state, run) => {
|
|
1924
|
+
const nextRuns = (state.runs ?? []).filter((existing) => existing.id !== run.id);
|
|
1925
|
+
nextRuns.push(run);
|
|
1926
|
+
return {
|
|
1927
|
+
version: 1,
|
|
1928
|
+
migrations: state.migrations,
|
|
1929
|
+
runs: nextRuns
|
|
1930
|
+
};
|
|
1931
|
+
};
|
|
1932
|
+
const getLastMigrationRun = (state) => {
|
|
1933
|
+
const runs = state.runs ?? [];
|
|
1934
|
+
if (runs.length === 0) return void 0;
|
|
1935
|
+
return [...runs].sort((left, right) => right.appliedAt.localeCompare(left.appliedAt))[0];
|
|
1936
|
+
};
|
|
1937
|
+
const getLatestAppliedMigrations = (state, steps) => {
|
|
1938
|
+
return [...state.migrations].sort((left, right) => right.appliedAt.localeCompare(left.appliedAt)).slice(0, Math.max(0, steps));
|
|
1939
|
+
};
|
|
1883
1940
|
|
|
1884
1941
|
//#endregion
|
|
1885
1942
|
//#region src/database/Migration.ts
|
|
@@ -1928,15 +1985,14 @@ var MigrateCommand = class extends Command {
|
|
|
1928
1985
|
*/
|
|
1929
1986
|
async handle() {
|
|
1930
1987
|
this.app.command = this;
|
|
1931
|
-
const configuredMigrationsDir = this.app.getConfig("paths")?.migrations ?? join
|
|
1988
|
+
const configuredMigrationsDir = this.app.getConfig("paths")?.migrations ?? join(process.cwd(), "database", "migrations");
|
|
1932
1989
|
const migrationsDir = this.app.resolveRuntimeDirectoryPath(configuredMigrationsDir);
|
|
1933
|
-
if (!existsSync
|
|
1934
|
-
const schemaPath = this.option("schema") ? resolve(String(this.option("schema"))) : join
|
|
1990
|
+
if (!existsSync(migrationsDir)) return void this.error(`Error: Migrations directory not found: ${this.app.formatPathForLog(configuredMigrationsDir)}`);
|
|
1991
|
+
const schemaPath = this.option("schema") ? resolve(String(this.option("schema"))) : join(process.cwd(), "prisma", "schema.prisma");
|
|
1935
1992
|
const classes = this.option("all") || !this.argument("name") ? await this.loadAllMigrations(migrationsDir) : (await this.loadNamedMigration(migrationsDir, this.argument("name"))).filter(([cls]) => cls !== void 0);
|
|
1936
1993
|
if (classes.length === 0) return void this.error("Error: No migration classes found to run.");
|
|
1937
|
-
const shouldTrackApplied = Boolean(this.option("all") || !this.argument("name") || this.option("state-file"));
|
|
1938
1994
|
const stateFilePath = resolveMigrationStateFilePath(process.cwd(), this.option("state-file") ? String(this.option("state-file")) : void 0);
|
|
1939
|
-
let appliedState =
|
|
1995
|
+
let appliedState = readAppliedMigrationsState(stateFilePath);
|
|
1940
1996
|
const skipped = [];
|
|
1941
1997
|
const changed = [];
|
|
1942
1998
|
const pending = classes.filter(([migrationClass, file]) => {
|
|
@@ -1963,6 +2019,7 @@ var MigrateCommand = class extends Command {
|
|
|
1963
2019
|
write: true
|
|
1964
2020
|
});
|
|
1965
2021
|
if (appliedState) {
|
|
2022
|
+
const runAppliedIds = [];
|
|
1966
2023
|
for (const [migrationClass, file] of pending) {
|
|
1967
2024
|
const identity = buildMigrationIdentity(file, migrationClass.name);
|
|
1968
2025
|
appliedState = markMigrationApplied(appliedState, {
|
|
@@ -1972,7 +2029,13 @@ var MigrateCommand = class extends Command {
|
|
|
1972
2029
|
appliedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1973
2030
|
checksum: computeMigrationChecksum(file)
|
|
1974
2031
|
});
|
|
2032
|
+
runAppliedIds.push(identity);
|
|
1975
2033
|
}
|
|
2034
|
+
appliedState = markMigrationRun(appliedState, {
|
|
2035
|
+
id: buildMigrationRunId(),
|
|
2036
|
+
appliedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2037
|
+
migrationIds: runAppliedIds
|
|
2038
|
+
});
|
|
1976
2039
|
writeAppliedMigrationsState(stateFilePath, appliedState);
|
|
1977
2040
|
}
|
|
1978
2041
|
if (!this.option("skip-generate")) runPrismaCommand(["generate"], process.cwd());
|
|
@@ -1992,7 +2055,7 @@ var MigrateCommand = class extends Command {
|
|
|
1992
2055
|
* @param migrationsDir The directory to load migration classes from.
|
|
1993
2056
|
*/
|
|
1994
2057
|
async loadAllMigrations(migrationsDir) {
|
|
1995
|
-
const files = readdirSync
|
|
2058
|
+
const files = readdirSync(migrationsDir).filter((file) => /\.(ts|js|mjs|cjs)$/i.test(file)).sort((left, right) => left.localeCompare(right)).map((file) => this.app.resolveRuntimeScriptPath(join(migrationsDir, file)));
|
|
1996
2059
|
return (await Promise.all(files.map(async (file) => (await this.loadMigrationClassesFromFile(file)).map((cls) => [cls, file])))).flat();
|
|
1997
2060
|
}
|
|
1998
2061
|
/**
|
|
@@ -2014,7 +2077,7 @@ var MigrateCommand = class extends Command {
|
|
|
2014
2077
|
`${base}Migration.js`,
|
|
2015
2078
|
`${base}Migration.mjs`,
|
|
2016
2079
|
`${base}Migration.cjs`
|
|
2017
|
-
].map((file) => join
|
|
2080
|
+
].map((file) => join(migrationsDir, file)).find((file) => existsSync(file));
|
|
2018
2081
|
if (!target) return [[void 0, name]];
|
|
2019
2082
|
const runtimeTarget = this.app.resolveRuntimeScriptPath(target);
|
|
2020
2083
|
return (await this.loadMigrationClassesFromFile(runtimeTarget)).map((cls) => [cls, runtimeTarget]);
|
|
@@ -2036,6 +2099,91 @@ var MigrateCommand = class extends Command {
|
|
|
2036
2099
|
}
|
|
2037
2100
|
};
|
|
2038
2101
|
|
|
2102
|
+
//#endregion
|
|
2103
|
+
//#region src/cli/commands/MigrateRollbackCommand.ts
|
|
2104
|
+
/**
|
|
2105
|
+
* Rollback migration classes from the Prisma schema and run Prisma workflow.
|
|
2106
|
+
* By default, rolls back classes applied in the last migrate run.
|
|
2107
|
+
*
|
|
2108
|
+
* @author Legacy (3m1n3nc3)
|
|
2109
|
+
* @since 0.2.4
|
|
2110
|
+
*/
|
|
2111
|
+
var MigrateRollbackCommand = class extends Command {
|
|
2112
|
+
signature = `migrate:rollback
|
|
2113
|
+
{--step= : Number of latest applied migration classes to rollback}
|
|
2114
|
+
{--dry-run : Preview rollback targets without applying changes}
|
|
2115
|
+
{--deploy : Use prisma migrate deploy instead of migrate dev}
|
|
2116
|
+
{--skip-generate : Skip prisma generate}
|
|
2117
|
+
{--skip-migrate : Skip prisma migrate command}
|
|
2118
|
+
{--state-file= : Path to applied migration state file}
|
|
2119
|
+
{--schema= : Explicit prisma schema path}
|
|
2120
|
+
{--migration-name= : Name for prisma migrate dev}
|
|
2121
|
+
`;
|
|
2122
|
+
description = "Rollback migration classes from schema.prisma and run Prisma workflow";
|
|
2123
|
+
async handle() {
|
|
2124
|
+
this.app.command = this;
|
|
2125
|
+
const configuredMigrationsDir = this.app.getConfig("paths")?.migrations ?? join(process.cwd(), "database", "migrations");
|
|
2126
|
+
const migrationsDir = this.app.resolveRuntimeDirectoryPath(configuredMigrationsDir);
|
|
2127
|
+
if (!existsSync(migrationsDir)) return void this.error(`Error: Migrations directory not found: ${this.app.formatPathForLog(configuredMigrationsDir)}`);
|
|
2128
|
+
const schemaPath = this.option("schema") ? resolve(String(this.option("schema"))) : join(process.cwd(), "prisma", "schema.prisma");
|
|
2129
|
+
const stateFilePath = resolveMigrationStateFilePath(process.cwd(), this.option("state-file") ? String(this.option("state-file")) : void 0);
|
|
2130
|
+
let appliedState = readAppliedMigrationsState(stateFilePath);
|
|
2131
|
+
const stepOption = this.option("step");
|
|
2132
|
+
const stepCount = stepOption == null ? void 0 : Number(stepOption);
|
|
2133
|
+
if (stepCount != null && (!Number.isFinite(stepCount) || stepCount <= 0 || !Number.isInteger(stepCount))) return void this.error("Error: --step must be a positive integer.");
|
|
2134
|
+
const targets = stepCount ? getLatestAppliedMigrations(appliedState, stepCount) : (() => {
|
|
2135
|
+
const lastRun = getLastMigrationRun(appliedState);
|
|
2136
|
+
if (!lastRun) return [];
|
|
2137
|
+
return lastRun.migrationIds.map((id) => appliedState.migrations.find((migration) => migration.id === id)).filter((migration) => Boolean(migration));
|
|
2138
|
+
})();
|
|
2139
|
+
if (targets.length === 0) return void this.error("Error: No tracked migrations available to rollback.");
|
|
2140
|
+
const available = await this.loadAllMigrations(migrationsDir);
|
|
2141
|
+
const rollbackClasses = targets.map((target) => {
|
|
2142
|
+
return available.find(([migrationClass, file]) => {
|
|
2143
|
+
return buildMigrationIdentity(file, migrationClass.name) === target.id || migrationClass.name === target.className;
|
|
2144
|
+
});
|
|
2145
|
+
}).filter((entry) => Boolean(entry));
|
|
2146
|
+
if (rollbackClasses.length === 0) return void this.error("Error: Unable to resolve rollback migration classes from tracked history.");
|
|
2147
|
+
if (this.option("dry-run")) {
|
|
2148
|
+
this.success(`Dry run: ${rollbackClasses.length} migration(s) would be rolled back.`);
|
|
2149
|
+
rollbackClasses.forEach(([_, file]) => this.success(this.app.splitLogger("WouldRollback", file)));
|
|
2150
|
+
return;
|
|
2151
|
+
}
|
|
2152
|
+
for (const [MigrationClassItem] of rollbackClasses) await applyMigrationRollbackToPrismaSchema(MigrationClassItem, {
|
|
2153
|
+
schemaPath,
|
|
2154
|
+
write: true
|
|
2155
|
+
});
|
|
2156
|
+
for (const [migrationClass, file] of rollbackClasses) {
|
|
2157
|
+
const identity = buildMigrationIdentity(file, migrationClass.name);
|
|
2158
|
+
appliedState = removeAppliedMigration(appliedState, identity);
|
|
2159
|
+
}
|
|
2160
|
+
writeAppliedMigrationsState(stateFilePath, appliedState);
|
|
2161
|
+
if (!this.option("skip-generate")) runPrismaCommand(["generate"], process.cwd());
|
|
2162
|
+
if (!this.option("skip-migrate")) if (this.option("deploy")) runPrismaCommand(["migrate", "deploy"], process.cwd());
|
|
2163
|
+
else runPrismaCommand([
|
|
2164
|
+
"migrate",
|
|
2165
|
+
"dev",
|
|
2166
|
+
"--name",
|
|
2167
|
+
this.option("migration-name") ? String(this.option("migration-name")) : `arkorm_cli_rollback_${Date.now()}`
|
|
2168
|
+
], process.cwd());
|
|
2169
|
+
this.success(`Rolled back ${rollbackClasses.length} migration(s).`);
|
|
2170
|
+
rollbackClasses.forEach(([_, file]) => this.success(this.app.splitLogger("RolledBack", file)));
|
|
2171
|
+
}
|
|
2172
|
+
async loadAllMigrations(migrationsDir) {
|
|
2173
|
+
const files = readdirSync(migrationsDir).filter((file) => /\.(ts|js|mjs|cjs)$/i.test(file)).sort((left, right) => left.localeCompare(right)).map((file) => this.app.resolveRuntimeScriptPath(join(migrationsDir, file)));
|
|
2174
|
+
return (await Promise.all(files.map(async (file) => (await this.loadMigrationClassesFromFile(file)).map((cls) => [cls, file])))).flat();
|
|
2175
|
+
}
|
|
2176
|
+
async loadMigrationClassesFromFile(filePath) {
|
|
2177
|
+
const imported = await import(`${pathToFileURL$1(resolve(filePath)).href}?arkorm_rollback=${Date.now()}`);
|
|
2178
|
+
return Object.values(imported).filter((value) => {
|
|
2179
|
+
if (typeof value !== "function") return false;
|
|
2180
|
+
const candidate = value;
|
|
2181
|
+
const prototype = candidate.prototype;
|
|
2182
|
+
return candidate[MIGRATION_BRAND] === true || typeof prototype?.up === "function" && typeof prototype?.down === "function";
|
|
2183
|
+
});
|
|
2184
|
+
}
|
|
2185
|
+
};
|
|
2186
|
+
|
|
2039
2187
|
//#endregion
|
|
2040
2188
|
//#region src/cli/commands/MigrationHistoryCommand.ts
|
|
2041
2189
|
/**
|
|
@@ -2056,11 +2204,11 @@ var MigrationHistoryCommand = class extends Command {
|
|
|
2056
2204
|
this.app.command = this;
|
|
2057
2205
|
const stateFilePath = resolveMigrationStateFilePath(process.cwd(), this.option("state-file") ? String(this.option("state-file")) : void 0);
|
|
2058
2206
|
if (this.option("delete")) {
|
|
2059
|
-
if (!existsSync
|
|
2207
|
+
if (!existsSync(stateFilePath)) {
|
|
2060
2208
|
this.success(`No migration state file found at ${this.app.formatPathForLog(stateFilePath)}`);
|
|
2061
2209
|
return;
|
|
2062
2210
|
}
|
|
2063
|
-
rmSync
|
|
2211
|
+
rmSync(stateFilePath);
|
|
2064
2212
|
this.success(`Deleted migration state file: ${this.app.formatPathForLog(stateFilePath)}`);
|
|
2065
2213
|
return;
|
|
2066
2214
|
}
|
|
@@ -2087,7 +2235,7 @@ var MigrationHistoryCommand = class extends Command {
|
|
|
2087
2235
|
return;
|
|
2088
2236
|
}
|
|
2089
2237
|
state.migrations.sort((left, right) => left.appliedAt.localeCompare(right.appliedAt)).forEach((migration) => {
|
|
2090
|
-
this.success(this.app.splitLogger("Applied", `${migration.id} @ ${migration.appliedAt}`));
|
|
2238
|
+
this.success(this.app.splitLogger("Applied:", `${migration.id} @ ${migration.appliedAt}`));
|
|
2091
2239
|
});
|
|
2092
2240
|
}
|
|
2093
2241
|
};
|
|
@@ -2187,9 +2335,9 @@ var SeedCommand = class extends Command {
|
|
|
2187
2335
|
*/
|
|
2188
2336
|
async handle() {
|
|
2189
2337
|
this.app.command = this;
|
|
2190
|
-
const configuredSeedersDir = this.app.getConfig("paths")?.seeders ?? join
|
|
2338
|
+
const configuredSeedersDir = this.app.getConfig("paths")?.seeders ?? join(process.cwd(), "database", "seeders");
|
|
2191
2339
|
const seedersDir = this.app.resolveRuntimeDirectoryPath(configuredSeedersDir);
|
|
2192
|
-
if (!existsSync
|
|
2340
|
+
if (!existsSync(seedersDir)) return void this.error(`ERROR: Seeders directory not found: ${this.app.formatPathForLog(configuredSeedersDir)}`);
|
|
2193
2341
|
const classes = this.option("all") ? await this.loadAllSeeders(seedersDir) : await this.loadNamedSeeder(seedersDir, this.argument("name") ?? "DatabaseSeeder");
|
|
2194
2342
|
if (classes.length === 0) return void this.error("ERROR: No seeder classes found to run.");
|
|
2195
2343
|
for (const SeederClassItem of classes) await new SeederClassItem().run();
|
|
@@ -2203,7 +2351,7 @@ var SeedCommand = class extends Command {
|
|
|
2203
2351
|
* @returns
|
|
2204
2352
|
*/
|
|
2205
2353
|
async loadAllSeeders(seedersDir) {
|
|
2206
|
-
const files = readdirSync
|
|
2354
|
+
const files = readdirSync(seedersDir).filter((file) => /\.(ts|js|mjs|cjs)$/i.test(file)).map((file) => this.app.resolveRuntimeScriptPath(join(seedersDir, file)));
|
|
2207
2355
|
return (await Promise.all(files.map(async (file) => await this.loadSeederClassesFromFile(file)))).flat();
|
|
2208
2356
|
}
|
|
2209
2357
|
/**
|
|
@@ -2224,7 +2372,7 @@ var SeedCommand = class extends Command {
|
|
|
2224
2372
|
`${base}Seeder.js`,
|
|
2225
2373
|
`${base}Seeder.mjs`,
|
|
2226
2374
|
`${base}Seeder.cjs`
|
|
2227
|
-
].map((file) => join
|
|
2375
|
+
].map((file) => join(seedersDir, file)).find((file) => existsSync(file));
|
|
2228
2376
|
if (!target) return [];
|
|
2229
2377
|
const runtimeTarget = this.app.resolveRuntimeScriptPath(target);
|
|
2230
2378
|
return await this.loadSeederClassesFromFile(runtimeTarget);
|
|
@@ -2272,6 +2420,7 @@ await Kernel.init(app, {
|
|
|
2272
2420
|
ModelsSyncCommand,
|
|
2273
2421
|
SeedCommand,
|
|
2274
2422
|
MigrateCommand,
|
|
2423
|
+
MigrateRollbackCommand,
|
|
2275
2424
|
MigrationHistoryCommand
|
|
2276
2425
|
],
|
|
2277
2426
|
exceptionHandler(exception) {
|