@famgia/omnify-laravel 2.0.21 → 2.0.23
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/{chunk-U3NDJ6S6.js → chunk-RSC5ATSV.js} +201 -9
- package/dist/chunk-RSC5ATSV.js.map +1 -0
- package/dist/index.cjs +200 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +1 -1
- package/dist/plugin.cjs +200 -8
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-U3NDJ6S6.js.map +0 -1
|
@@ -420,7 +420,8 @@ function expandCompoundType(propName, property, customTypes, options = {}) {
|
|
|
420
420
|
return expanded;
|
|
421
421
|
}
|
|
422
422
|
function schemaToBlueprint(schema, allSchemas, options = {}) {
|
|
423
|
-
const { customTypes = /* @__PURE__ */ new Map(), pluginEnums = /* @__PURE__ */ new Map(), locale } = options;
|
|
423
|
+
const { customTypes = /* @__PURE__ */ new Map(), pluginEnums = /* @__PURE__ */ new Map(), locale, excludeFKs } = options;
|
|
424
|
+
const schemaName = options.schemaName ?? schema.name;
|
|
424
425
|
const compoundOptions = { locale, pluginEnums };
|
|
425
426
|
const tableName = schema.options?.tableName ?? toTableName(schema.name);
|
|
426
427
|
const columns = [];
|
|
@@ -490,7 +491,10 @@ function schemaToBlueprint(schema, allSchemas, options = {}) {
|
|
|
490
491
|
if (!explicitColumnNames.has(fkResult.column.name)) {
|
|
491
492
|
columns.push(fkResult.column);
|
|
492
493
|
}
|
|
493
|
-
|
|
494
|
+
const fkKey = `${schemaName}.${propName}`;
|
|
495
|
+
if (!excludeFKs?.has(fkKey)) {
|
|
496
|
+
foreignKeys.push(fkResult.foreignKey);
|
|
497
|
+
}
|
|
494
498
|
indexes.push(fkResult.index);
|
|
495
499
|
}
|
|
496
500
|
const polyResult = generatePolymorphicColumns(propName, property, allSchemas);
|
|
@@ -1157,6 +1161,143 @@ function extractDependencies(schema) {
|
|
|
1157
1161
|
}
|
|
1158
1162
|
return deps;
|
|
1159
1163
|
}
|
|
1164
|
+
function detectCircularDependencies(schemas) {
|
|
1165
|
+
const circularFKs = /* @__PURE__ */ new Set();
|
|
1166
|
+
const graph = /* @__PURE__ */ new Map();
|
|
1167
|
+
for (const schema of Object.values(schemas)) {
|
|
1168
|
+
if (schema.kind === "enum" || !schema.properties) continue;
|
|
1169
|
+
const refs = /* @__PURE__ */ new Map();
|
|
1170
|
+
for (const [propName, property] of Object.entries(schema.properties)) {
|
|
1171
|
+
if (property.type !== "Association") continue;
|
|
1172
|
+
const assocProp = property;
|
|
1173
|
+
if ((assocProp.relation === "ManyToOne" || assocProp.relation === "OneToOne") && !assocProp.mappedBy && assocProp.target && assocProp.target !== schema.name) {
|
|
1174
|
+
refs.set(assocProp.target, propName);
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
if (refs.size > 0) {
|
|
1178
|
+
graph.set(schema.name, refs);
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
for (const [schemaA, refsA] of graph) {
|
|
1182
|
+
for (const [targetB, propNameA] of refsA) {
|
|
1183
|
+
if (targetB === schemaA) continue;
|
|
1184
|
+
const refsB = graph.get(targetB);
|
|
1185
|
+
if (refsB && refsB.has(schemaA)) {
|
|
1186
|
+
if (schemaA > targetB) {
|
|
1187
|
+
circularFKs.add(`${schemaA}.${propNameA}`);
|
|
1188
|
+
} else {
|
|
1189
|
+
const propNameB = refsB.get(schemaA);
|
|
1190
|
+
circularFKs.add(`${targetB}.${propNameB}`);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
return circularFKs;
|
|
1196
|
+
}
|
|
1197
|
+
function extractDeferredFKs(schemas, circularFKs) {
|
|
1198
|
+
const deferred = [];
|
|
1199
|
+
for (const schema of Object.values(schemas)) {
|
|
1200
|
+
if (schema.kind === "enum" || !schema.properties) continue;
|
|
1201
|
+
const tableName = schema.options?.tableName ?? toTableName(schema.name);
|
|
1202
|
+
for (const [propName, property] of Object.entries(schema.properties)) {
|
|
1203
|
+
const key = `${schema.name}.${propName}`;
|
|
1204
|
+
if (!circularFKs.has(key)) continue;
|
|
1205
|
+
const assocProp = property;
|
|
1206
|
+
if (!assocProp.target) continue;
|
|
1207
|
+
const targetSchema = schemas[assocProp.target];
|
|
1208
|
+
const targetTable = targetSchema?.options?.tableName ?? toTableName(assocProp.target);
|
|
1209
|
+
const columnName = toColumnName(propName) + "_id";
|
|
1210
|
+
deferred.push({
|
|
1211
|
+
tableName,
|
|
1212
|
+
columnName,
|
|
1213
|
+
targetTable,
|
|
1214
|
+
onDelete: assocProp.onDelete,
|
|
1215
|
+
onUpdate: assocProp.onUpdate
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
return deferred;
|
|
1220
|
+
}
|
|
1221
|
+
function generateDeferredFKMigration(deferredFKs, options = {}) {
|
|
1222
|
+
if (deferredFKs.length === 0) return null;
|
|
1223
|
+
const timestamp = options.timestamp ?? generateTimestamp();
|
|
1224
|
+
const fileName = `${timestamp}_add_circular_foreign_keys.php`;
|
|
1225
|
+
const connection = options.connection ? `
|
|
1226
|
+
protected $connection = '${options.connection}';
|
|
1227
|
+
` : "";
|
|
1228
|
+
const byTable = /* @__PURE__ */ new Map();
|
|
1229
|
+
for (const fk of deferredFKs) {
|
|
1230
|
+
const existing = byTable.get(fk.tableName) ?? [];
|
|
1231
|
+
existing.push(fk);
|
|
1232
|
+
byTable.set(fk.tableName, existing);
|
|
1233
|
+
}
|
|
1234
|
+
const upStatements = [];
|
|
1235
|
+
const downStatements = [];
|
|
1236
|
+
for (const [tableName, fks] of byTable) {
|
|
1237
|
+
const fkLines = fks.map((fk) => {
|
|
1238
|
+
let line = ` $table->foreign('${fk.columnName}')->references('id')->on('${fk.targetTable}')`;
|
|
1239
|
+
if (fk.onDelete) line += `->onDelete('${fk.onDelete}')`;
|
|
1240
|
+
if (fk.onUpdate) line += `->onUpdate('${fk.onUpdate}')`;
|
|
1241
|
+
return line + ";";
|
|
1242
|
+
});
|
|
1243
|
+
upStatements.push(` Schema::table('${tableName}', function (Blueprint $table) {
|
|
1244
|
+
${fkLines.join("\n")}
|
|
1245
|
+
});`);
|
|
1246
|
+
const dropLines = fks.map(
|
|
1247
|
+
(fk) => ` $table->dropForeign(['${fk.columnName}']);`
|
|
1248
|
+
);
|
|
1249
|
+
downStatements.push(` Schema::table('${tableName}', function (Blueprint $table) {
|
|
1250
|
+
${dropLines.join("\n")}
|
|
1251
|
+
});`);
|
|
1252
|
+
}
|
|
1253
|
+
const content = `<?php
|
|
1254
|
+
|
|
1255
|
+
/**
|
|
1256
|
+
* \u26A0\uFE0F DO NOT EDIT THIS FILE! \u26A0\uFE0F
|
|
1257
|
+
* \u3053\u306E\u30D5\u30A1\u30A4\u30EB\u3092\u7DE8\u96C6\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\uFF01
|
|
1258
|
+
* KH\xD4NG \u0110\u01AF\u1EE2C S\u1EECA FILE N\xC0Y!
|
|
1259
|
+
*
|
|
1260
|
+
* This file is AUTO-GENERATED by Omnify.
|
|
1261
|
+
* Any manual changes will be OVERWRITTEN on next generation.
|
|
1262
|
+
*
|
|
1263
|
+
* This migration adds foreign key constraints for circular dependencies.
|
|
1264
|
+
* These constraints are deferred to run after all tables are created.
|
|
1265
|
+
*
|
|
1266
|
+
* @generated by @famgia/omnify-laravel
|
|
1267
|
+
*/
|
|
1268
|
+
|
|
1269
|
+
use Illuminate\\Database\\Migrations\\Migration;
|
|
1270
|
+
use Illuminate\\Database\\Schema\\Blueprint;
|
|
1271
|
+
use Illuminate\\Support\\Facades\\Schema;
|
|
1272
|
+
|
|
1273
|
+
return new class extends Migration
|
|
1274
|
+
{${connection}
|
|
1275
|
+
/**
|
|
1276
|
+
* Run the migrations.
|
|
1277
|
+
*/
|
|
1278
|
+
public function up(): void
|
|
1279
|
+
{
|
|
1280
|
+
${upStatements.join("\n\n")}
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
/**
|
|
1284
|
+
* Reverse the migrations.
|
|
1285
|
+
*/
|
|
1286
|
+
public function down(): void
|
|
1287
|
+
{
|
|
1288
|
+
${downStatements.join("\n\n")}
|
|
1289
|
+
}
|
|
1290
|
+
};
|
|
1291
|
+
`;
|
|
1292
|
+
const tables = [...byTable.keys()];
|
|
1293
|
+
return {
|
|
1294
|
+
fileName,
|
|
1295
|
+
className: "AddCircularForeignKeys",
|
|
1296
|
+
content,
|
|
1297
|
+
tables,
|
|
1298
|
+
type: "alter"
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1160
1301
|
function topologicalSort(schemas) {
|
|
1161
1302
|
const schemaList = Object.values(schemas).filter((s) => s.kind !== "enum");
|
|
1162
1303
|
const sorted = [];
|
|
@@ -1190,6 +1331,7 @@ function generateMigrations(schemas, options = {}) {
|
|
|
1190
1331
|
const migrations = [];
|
|
1191
1332
|
const pivotTablesGenerated = /* @__PURE__ */ new Set();
|
|
1192
1333
|
let timestampOffset = 0;
|
|
1334
|
+
const circularFKs = detectCircularDependencies(schemas);
|
|
1193
1335
|
const sortedSchemas = topologicalSort(schemas);
|
|
1194
1336
|
const baseTimestamp = options.timestamp ?? generateTimestamp();
|
|
1195
1337
|
for (const schema of sortedSchemas) {
|
|
@@ -1198,7 +1340,9 @@ function generateMigrations(schemas, options = {}) {
|
|
|
1198
1340
|
const blueprint = schemaToBlueprint(schema, schemas, {
|
|
1199
1341
|
customTypes: options.customTypes,
|
|
1200
1342
|
pluginEnums: options.pluginEnums,
|
|
1201
|
-
locale: options.locale
|
|
1343
|
+
locale: options.locale,
|
|
1344
|
+
excludeFKs: circularFKs,
|
|
1345
|
+
schemaName: schema.name
|
|
1202
1346
|
});
|
|
1203
1347
|
const migration = generateCreateMigration(blueprint, {
|
|
1204
1348
|
...options,
|
|
@@ -1238,6 +1382,19 @@ function generateMigrations(schemas, options = {}) {
|
|
|
1238
1382
|
});
|
|
1239
1383
|
}
|
|
1240
1384
|
}
|
|
1385
|
+
if (circularFKs.size > 0) {
|
|
1386
|
+
const deferredFKs = extractDeferredFKs(schemas, circularFKs);
|
|
1387
|
+
if (deferredFKs.length > 0) {
|
|
1388
|
+
const offsetTimestamp = incrementTimestamp(baseTimestamp, timestampOffset);
|
|
1389
|
+
const deferredMigration = generateDeferredFKMigration(deferredFKs, {
|
|
1390
|
+
...options,
|
|
1391
|
+
timestamp: offsetTimestamp
|
|
1392
|
+
});
|
|
1393
|
+
if (deferredMigration) {
|
|
1394
|
+
migrations.push(deferredMigration);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1241
1398
|
return migrations;
|
|
1242
1399
|
}
|
|
1243
1400
|
function incrementTimestamp(timestamp, seconds) {
|
|
@@ -1327,8 +1484,16 @@ function generateTimestamp2() {
|
|
|
1327
1484
|
const seconds = String(now.getSeconds()).padStart(2, "0");
|
|
1328
1485
|
return `${year}_${month}_${day}_${hours}${minutes}${seconds}`;
|
|
1329
1486
|
}
|
|
1487
|
+
function shouldSkipAssociationColumn(prop) {
|
|
1488
|
+
if (prop.type !== "Association") return false;
|
|
1489
|
+
if (isAssociationWithFkColumn(prop)) return false;
|
|
1490
|
+
return true;
|
|
1491
|
+
}
|
|
1330
1492
|
function formatAddColumn(columnName, prop) {
|
|
1331
1493
|
const lines = [];
|
|
1494
|
+
if (shouldSkipAssociationColumn(prop)) {
|
|
1495
|
+
return lines;
|
|
1496
|
+
}
|
|
1332
1497
|
if (isAssociationWithFkColumn(prop)) {
|
|
1333
1498
|
const fkColumn = getAssociationFkColumnName(columnName);
|
|
1334
1499
|
let code2 = `$table->unsignedBigInteger('${fkColumn}')`;
|
|
@@ -1368,6 +1533,9 @@ function formatAddColumn(columnName, prop) {
|
|
|
1368
1533
|
}
|
|
1369
1534
|
function formatDropColumn(columnName, prop) {
|
|
1370
1535
|
const lines = [];
|
|
1536
|
+
if (prop && shouldSkipAssociationColumn(prop)) {
|
|
1537
|
+
return lines;
|
|
1538
|
+
}
|
|
1371
1539
|
if (prop && isAssociationWithFkColumn(prop)) {
|
|
1372
1540
|
const fkColumn = getAssociationFkColumnName(columnName);
|
|
1373
1541
|
lines.push(`$table->dropForeign(['${fkColumn}']);`);
|
|
@@ -3017,9 +3185,26 @@ ${providerLine}
|
|
|
3017
3185
|
}
|
|
3018
3186
|
|
|
3019
3187
|
// src/factory/generator.ts
|
|
3188
|
+
function deriveFactoryNamespace(modelNamespace) {
|
|
3189
|
+
if (modelNamespace === "App\\Models") {
|
|
3190
|
+
return "Database\\Factories";
|
|
3191
|
+
}
|
|
3192
|
+
if (modelNamespace.endsWith("\\Models")) {
|
|
3193
|
+
const base = modelNamespace.slice(0, -7);
|
|
3194
|
+
return `${base}\\Database\\Factories`;
|
|
3195
|
+
}
|
|
3196
|
+
const parts = modelNamespace.split("\\");
|
|
3197
|
+
if (parts.length > 1 && parts[parts.length - 1] === "Models") {
|
|
3198
|
+
parts.pop();
|
|
3199
|
+
return [...parts, "Database", "Factories"].join("\\");
|
|
3200
|
+
}
|
|
3201
|
+
return "Database\\Factories";
|
|
3202
|
+
}
|
|
3020
3203
|
function resolveOptions2(options) {
|
|
3204
|
+
const modelNamespace = options?.modelNamespace ?? "App\\Models";
|
|
3021
3205
|
return {
|
|
3022
|
-
modelNamespace
|
|
3206
|
+
modelNamespace,
|
|
3207
|
+
factoryNamespace: options?.factoryNamespace ?? deriveFactoryNamespace(modelNamespace),
|
|
3023
3208
|
factoryPath: options?.factoryPath ?? "database/factories",
|
|
3024
3209
|
fakerLocale: options?.fakerLocale ?? "en_US",
|
|
3025
3210
|
customTypes: options?.customTypes ?? /* @__PURE__ */ new Map(),
|
|
@@ -3032,16 +3217,18 @@ function resolveSchemaOptions2(schema, globalOptions) {
|
|
|
3032
3217
|
return globalOptions;
|
|
3033
3218
|
}
|
|
3034
3219
|
const base = pkgOutput.base;
|
|
3220
|
+
const modelNamespace = pkgOutput.modelsNamespace;
|
|
3035
3221
|
return {
|
|
3036
3222
|
...globalOptions,
|
|
3037
|
-
modelNamespace
|
|
3223
|
+
modelNamespace,
|
|
3224
|
+
factoryNamespace: pkgOutput.factoriesNamespace ?? deriveFactoryNamespace(modelNamespace),
|
|
3038
3225
|
factoryPath: `${base}/${pkgOutput.factoriesPath ?? "database/factories"}`
|
|
3039
3226
|
};
|
|
3040
3227
|
}
|
|
3041
3228
|
function getStubContent2() {
|
|
3042
3229
|
return `<?php
|
|
3043
3230
|
|
|
3044
|
-
namespace
|
|
3231
|
+
namespace {{FACTORY_NAMESPACE}};
|
|
3045
3232
|
|
|
3046
3233
|
use {{MODEL_NAMESPACE}}\\{{MODEL_NAME}};
|
|
3047
3234
|
use Illuminate\\Database\\Eloquent\\Factories\\Factory;
|
|
@@ -3338,6 +3525,7 @@ function generateFactory(schema, schemas, options, stubContent) {
|
|
|
3338
3525
|
}
|
|
3339
3526
|
}
|
|
3340
3527
|
let content = stubContent;
|
|
3528
|
+
content = content.replace(/\{\{FACTORY_NAMESPACE\}\}/g, options.factoryNamespace);
|
|
3341
3529
|
content = content.replace(/\{\{MODEL_NAMESPACE\}\}/g, options.modelNamespace);
|
|
3342
3530
|
content = content.replace(/\{\{MODEL_NAME\}\}/g, modelName);
|
|
3343
3531
|
const uniqueImports = [...new Set(imports)];
|
|
@@ -4958,9 +5146,10 @@ function laravelPlugin(options) {
|
|
|
4958
5146
|
name: "laravel-migrations",
|
|
4959
5147
|
description: "Generate Laravel migration files",
|
|
4960
5148
|
generate: async (ctx) => {
|
|
5149
|
+
const baseTimestamp = resolved.timestamp ?? generateTimestamp();
|
|
4961
5150
|
const migrationOptions = {
|
|
4962
5151
|
connection: resolved.connection,
|
|
4963
|
-
timestamp:
|
|
5152
|
+
timestamp: baseTimestamp,
|
|
4964
5153
|
customTypes: ctx.customTypes,
|
|
4965
5154
|
pluginEnums: ctx.pluginEnums
|
|
4966
5155
|
};
|
|
@@ -4982,6 +5171,7 @@ function laravelPlugin(options) {
|
|
|
4982
5171
|
if (ctx.changes.length === 0) {
|
|
4983
5172
|
return outputs;
|
|
4984
5173
|
}
|
|
5174
|
+
let timestampOffset = 0;
|
|
4985
5175
|
const addedSchemaNames = new Set(
|
|
4986
5176
|
ctx.changes.filter((c) => c.changeType === "added").map((c) => c.schemaName)
|
|
4987
5177
|
);
|
|
@@ -5006,15 +5196,17 @@ function laravelPlugin(options) {
|
|
|
5006
5196
|
schemaName: migration.schemaName
|
|
5007
5197
|
}
|
|
5008
5198
|
});
|
|
5199
|
+
timestampOffset++;
|
|
5009
5200
|
}
|
|
5010
5201
|
}
|
|
5011
5202
|
const alterChanges = ctx.changes.filter(
|
|
5012
5203
|
(c) => c.changeType === "modified" || c.changeType === "removed"
|
|
5013
5204
|
);
|
|
5014
5205
|
if (alterChanges.length > 0) {
|
|
5206
|
+
const alterTimestamp = timestampOffset > 0 ? incrementTimestamp(baseTimestamp, timestampOffset) : baseTimestamp;
|
|
5015
5207
|
const alterMigrations = generateMigrationsFromChanges(
|
|
5016
5208
|
alterChanges,
|
|
5017
|
-
migrationOptions
|
|
5209
|
+
{ ...migrationOptions, timestamp: alterTimestamp }
|
|
5018
5210
|
);
|
|
5019
5211
|
for (const migration of alterMigrations) {
|
|
5020
5212
|
outputs.push({
|
|
@@ -5259,4 +5451,4 @@ export {
|
|
|
5259
5451
|
getFactoryPath,
|
|
5260
5452
|
laravelPlugin
|
|
5261
5453
|
};
|
|
5262
|
-
//# sourceMappingURL=chunk-
|
|
5454
|
+
//# sourceMappingURL=chunk-RSC5ATSV.js.map
|