@famgia/omnify-laravel 0.0.13 → 0.0.14
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-G4UAJVC2.js → chunk-UVF7W2J2.js} +663 -31
- package/dist/chunk-UVF7W2J2.js.map +1 -0
- package/dist/index.cjs +662 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/plugin.cjs +662 -30
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +28 -2
- package/dist/plugin.d.ts +28 -2
- package/dist/plugin.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-G4UAJVC2.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -311,11 +311,18 @@ function schemaToBlueprint(schema, allSchemas) {
|
|
|
311
311
|
}
|
|
312
312
|
if (schema.options?.indexes) {
|
|
313
313
|
for (const index of schema.options.indexes) {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
314
|
+
if (typeof index === "string") {
|
|
315
|
+
indexes.push({
|
|
316
|
+
columns: [toColumnName(index)],
|
|
317
|
+
unique: false
|
|
318
|
+
});
|
|
319
|
+
} else {
|
|
320
|
+
indexes.push({
|
|
321
|
+
name: index.name,
|
|
322
|
+
columns: index.columns.map(toColumnName),
|
|
323
|
+
unique: index.unique ?? false
|
|
324
|
+
});
|
|
325
|
+
}
|
|
319
326
|
}
|
|
320
327
|
}
|
|
321
328
|
if (schema.options?.unique) {
|
|
@@ -1033,6 +1040,579 @@ function generateMigrationsFromChanges(changes, options = {}) {
|
|
|
1033
1040
|
return migrations;
|
|
1034
1041
|
}
|
|
1035
1042
|
|
|
1043
|
+
// src/utils.ts
|
|
1044
|
+
function toSnakeCase(str) {
|
|
1045
|
+
return str.replace(/([A-Z])/g, "_$1").replace(/^_/, "").toLowerCase();
|
|
1046
|
+
}
|
|
1047
|
+
function toPascalCase(str) {
|
|
1048
|
+
return str.replace(/[-_](.)/g, (_, c) => c.toUpperCase()).replace(/^(.)/, (_, c) => c.toUpperCase());
|
|
1049
|
+
}
|
|
1050
|
+
function toCamelCase(str) {
|
|
1051
|
+
const pascal = toPascalCase(str);
|
|
1052
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
1053
|
+
}
|
|
1054
|
+
function pluralize(word) {
|
|
1055
|
+
if (word.endsWith("y") && !["ay", "ey", "iy", "oy", "uy"].some((v) => word.endsWith(v))) {
|
|
1056
|
+
return word.slice(0, -1) + "ies";
|
|
1057
|
+
}
|
|
1058
|
+
if (word.endsWith("s") || word.endsWith("x") || word.endsWith("z") || word.endsWith("ch") || word.endsWith("sh")) {
|
|
1059
|
+
return word + "es";
|
|
1060
|
+
}
|
|
1061
|
+
return word + "s";
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
// src/model/generator.ts
|
|
1065
|
+
var DEFAULT_OPTIONS = {
|
|
1066
|
+
baseModelNamespace: "App\\Models\\OmnifyBase",
|
|
1067
|
+
modelNamespace: "App\\Models",
|
|
1068
|
+
baseModelClassName: "BaseModel",
|
|
1069
|
+
baseModelPath: "app/Models/OmnifyBase",
|
|
1070
|
+
modelPath: "app/Models"
|
|
1071
|
+
};
|
|
1072
|
+
function resolveOptions(options) {
|
|
1073
|
+
return {
|
|
1074
|
+
baseModelNamespace: options?.baseModelNamespace ?? DEFAULT_OPTIONS.baseModelNamespace,
|
|
1075
|
+
modelNamespace: options?.modelNamespace ?? DEFAULT_OPTIONS.modelNamespace,
|
|
1076
|
+
baseModelClassName: options?.baseModelClassName ?? DEFAULT_OPTIONS.baseModelClassName,
|
|
1077
|
+
baseModelPath: options?.baseModelPath ?? DEFAULT_OPTIONS.baseModelPath,
|
|
1078
|
+
modelPath: options?.modelPath ?? DEFAULT_OPTIONS.modelPath
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
function getCastType(propDef) {
|
|
1082
|
+
switch (propDef.type) {
|
|
1083
|
+
case "Boolean":
|
|
1084
|
+
return "boolean";
|
|
1085
|
+
case "Int":
|
|
1086
|
+
case "BigInt":
|
|
1087
|
+
return "integer";
|
|
1088
|
+
case "Float":
|
|
1089
|
+
return "float";
|
|
1090
|
+
case "Decimal":
|
|
1091
|
+
return "decimal:" + (propDef.scale ?? 2);
|
|
1092
|
+
case "Json":
|
|
1093
|
+
return "array";
|
|
1094
|
+
case "Date":
|
|
1095
|
+
return "date";
|
|
1096
|
+
case "Timestamp":
|
|
1097
|
+
return "datetime";
|
|
1098
|
+
case "Password":
|
|
1099
|
+
return "hashed";
|
|
1100
|
+
default:
|
|
1101
|
+
return null;
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
function isNullable(propDef) {
|
|
1105
|
+
return "nullable" in propDef && propDef.nullable === true;
|
|
1106
|
+
}
|
|
1107
|
+
function getPhpDocType(propDef, schemas) {
|
|
1108
|
+
const nullable = isNullable(propDef);
|
|
1109
|
+
switch (propDef.type) {
|
|
1110
|
+
case "String":
|
|
1111
|
+
case "Text":
|
|
1112
|
+
case "LongText":
|
|
1113
|
+
case "Email":
|
|
1114
|
+
case "Password":
|
|
1115
|
+
return "string" + (nullable ? "|null" : "");
|
|
1116
|
+
case "Int":
|
|
1117
|
+
case "BigInt":
|
|
1118
|
+
return "int" + (nullable ? "|null" : "");
|
|
1119
|
+
case "Float":
|
|
1120
|
+
case "Decimal":
|
|
1121
|
+
return "float" + (nullable ? "|null" : "");
|
|
1122
|
+
case "Boolean":
|
|
1123
|
+
return "bool" + (nullable ? "|null" : "");
|
|
1124
|
+
case "Date":
|
|
1125
|
+
case "Time":
|
|
1126
|
+
case "Timestamp":
|
|
1127
|
+
return "\\Carbon\\Carbon" + (nullable ? "|null" : "");
|
|
1128
|
+
case "Json":
|
|
1129
|
+
return "array" + (nullable ? "|null" : "");
|
|
1130
|
+
case "Enum":
|
|
1131
|
+
case "EnumRef":
|
|
1132
|
+
return "string" + (nullable ? "|null" : "");
|
|
1133
|
+
case "Association": {
|
|
1134
|
+
const assoc = propDef;
|
|
1135
|
+
if (assoc.target) {
|
|
1136
|
+
const className = toPascalCase(assoc.target);
|
|
1137
|
+
switch (assoc.relation) {
|
|
1138
|
+
case "OneToMany":
|
|
1139
|
+
case "ManyToMany":
|
|
1140
|
+
case "MorphMany":
|
|
1141
|
+
case "MorphToMany":
|
|
1142
|
+
case "MorphedByMany":
|
|
1143
|
+
return `\\Illuminate\\Database\\Eloquent\\Collection<${className}>`;
|
|
1144
|
+
default:
|
|
1145
|
+
return className + "|null";
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
return "mixed";
|
|
1149
|
+
}
|
|
1150
|
+
default:
|
|
1151
|
+
return "mixed";
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
function generateBaseModel(schemas, options, stubContent) {
|
|
1155
|
+
const modelMap = Object.values(schemas).filter((s) => s.kind !== "enum").map((s) => {
|
|
1156
|
+
const className = toPascalCase(s.name);
|
|
1157
|
+
return ` '${s.name}' => \\${options.modelNamespace}\\${className}::class,`;
|
|
1158
|
+
}).join("\n");
|
|
1159
|
+
const content = stubContent.replace(/\{\{BASE_MODEL_NAMESPACE\}\}/g, options.baseModelNamespace).replace(/\{\{BASE_MODEL_CLASS\}\}/g, options.baseModelClassName).replace(/\{\{MODEL_MAP\}\}/g, modelMap);
|
|
1160
|
+
return {
|
|
1161
|
+
path: `${options.baseModelPath}/${options.baseModelClassName}.php`,
|
|
1162
|
+
content,
|
|
1163
|
+
type: "base-model",
|
|
1164
|
+
overwrite: true,
|
|
1165
|
+
schemaName: "__base__"
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
function generateEntityBaseModel(schema, schemas, options, stubContent, authStubContent) {
|
|
1169
|
+
const className = toPascalCase(schema.name);
|
|
1170
|
+
const tableName = schema.options?.tableName ?? pluralize(toSnakeCase(schema.name));
|
|
1171
|
+
const isAuth = schema.options?.authenticatable ?? false;
|
|
1172
|
+
const primaryKey = "id";
|
|
1173
|
+
const idType = schema.options?.idType ?? "BigInt";
|
|
1174
|
+
const isUuid = idType === "Uuid";
|
|
1175
|
+
const isStringKey = idType === "Uuid" || idType === "String";
|
|
1176
|
+
const imports = [];
|
|
1177
|
+
const traits = [];
|
|
1178
|
+
const fillable = [];
|
|
1179
|
+
const hidden = [];
|
|
1180
|
+
const appends = [];
|
|
1181
|
+
const casts = [];
|
|
1182
|
+
const relations = [];
|
|
1183
|
+
const docProperties = [];
|
|
1184
|
+
if (schema.options?.softDelete) {
|
|
1185
|
+
imports.push("use Illuminate\\Database\\Eloquent\\SoftDeletes;");
|
|
1186
|
+
traits.push(" use SoftDeletes;");
|
|
1187
|
+
}
|
|
1188
|
+
const properties = schema.properties ?? {};
|
|
1189
|
+
for (const [propName, propDef] of Object.entries(properties)) {
|
|
1190
|
+
const snakeName = toSnakeCase(propName);
|
|
1191
|
+
const phpType = getPhpDocType(propDef, schemas);
|
|
1192
|
+
docProperties.push(` * @property ${phpType} $${snakeName}`);
|
|
1193
|
+
if (propDef.type === "Association") {
|
|
1194
|
+
const assoc = propDef;
|
|
1195
|
+
if (assoc.target) {
|
|
1196
|
+
imports.push(`use ${options.modelNamespace}\\${toPascalCase(assoc.target)};`);
|
|
1197
|
+
}
|
|
1198
|
+
relations.push(generateRelation(propName, assoc, options));
|
|
1199
|
+
if (assoc.relation === "ManyToOne" || assoc.relation === "OneToOne") {
|
|
1200
|
+
if (!assoc.mappedBy) {
|
|
1201
|
+
const fkName = toSnakeCase(propName) + "_id";
|
|
1202
|
+
fillable.push(` '${fkName}',`);
|
|
1203
|
+
docProperties.push(` * @property int|null $${fkName}`);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
} else if (propDef.type === "Password") {
|
|
1207
|
+
fillable.push(` '${snakeName}',`);
|
|
1208
|
+
hidden.push(` '${snakeName}',`);
|
|
1209
|
+
const cast = getCastType(propDef);
|
|
1210
|
+
if (cast) {
|
|
1211
|
+
casts.push(` '${snakeName}' => '${cast}',`);
|
|
1212
|
+
}
|
|
1213
|
+
} else if (propDef.type === "File") {
|
|
1214
|
+
const relMethod = generateFileRelation(propName, propDef);
|
|
1215
|
+
relations.push(relMethod);
|
|
1216
|
+
} else {
|
|
1217
|
+
fillable.push(` '${snakeName}',`);
|
|
1218
|
+
const cast = getCastType(propDef);
|
|
1219
|
+
if (cast) {
|
|
1220
|
+
casts.push(` '${snakeName}' => '${cast}',`);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
const docComment = `/**
|
|
1225
|
+
* ${className}BaseModel
|
|
1226
|
+
*
|
|
1227
|
+
${docProperties.join("\n")}
|
|
1228
|
+
*/`;
|
|
1229
|
+
const stub = isAuth ? authStubContent : stubContent;
|
|
1230
|
+
const keyType = isStringKey ? ` /**
|
|
1231
|
+
* The "type" of the primary key ID.
|
|
1232
|
+
*/
|
|
1233
|
+
protected $keyType = 'string';
|
|
1234
|
+
|
|
1235
|
+
` : "";
|
|
1236
|
+
const incrementing = isUuid ? ` /**
|
|
1237
|
+
* Indicates if the IDs are auto-incrementing.
|
|
1238
|
+
*/
|
|
1239
|
+
public $incrementing = false;
|
|
1240
|
+
|
|
1241
|
+
` : "";
|
|
1242
|
+
if (isUuid) {
|
|
1243
|
+
imports.push("use Illuminate\\Database\\Eloquent\\Concerns\\HasUuids;");
|
|
1244
|
+
traits.push(" use HasUuids;");
|
|
1245
|
+
}
|
|
1246
|
+
const content = stub.replace(/\{\{BASE_MODEL_NAMESPACE\}\}/g, options.baseModelNamespace).replace(/\{\{BASE_MODEL_CLASS\}\}/g, options.baseModelClassName).replace(/\{\{CLASS_NAME\}\}/g, className).replace(/\{\{TABLE_NAME\}\}/g, tableName).replace(/\{\{PRIMARY_KEY\}\}/g, primaryKey).replace(/\{\{KEY_TYPE\}\}/g, keyType).replace(/\{\{INCREMENTING\}\}/g, incrementing).replace(/\{\{TIMESTAMPS\}\}/g, schema.options?.timestamps !== false ? "true" : "false").replace(/\{\{IMPORTS\}\}/g, [...new Set(imports)].sort().join("\n")).replace(/\{\{TRAITS\}\}/g, traits.join("\n")).replace(/\{\{DOC_COMMENT\}\}/g, docComment).replace(/\{\{FILLABLE\}\}/g, fillable.join("\n")).replace(/\{\{HIDDEN\}\}/g, hidden.join("\n")).replace(/\{\{APPENDS\}\}/g, appends.join("\n")).replace(/\{\{CASTS\}\}/g, casts.join("\n")).replace(/\{\{RELATIONS\}\}/g, relations.join("\n\n"));
|
|
1247
|
+
return {
|
|
1248
|
+
path: `${options.baseModelPath}/${className}BaseModel.php`,
|
|
1249
|
+
content,
|
|
1250
|
+
type: "entity-base",
|
|
1251
|
+
overwrite: true,
|
|
1252
|
+
schemaName: schema.name
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
function generateRelation(propName, assoc, options) {
|
|
1256
|
+
const methodName = toCamelCase(propName);
|
|
1257
|
+
const targetClass = assoc.target ? toPascalCase(assoc.target) : "";
|
|
1258
|
+
const fkName = toSnakeCase(propName) + "_id";
|
|
1259
|
+
switch (assoc.relation) {
|
|
1260
|
+
case "ManyToOne":
|
|
1261
|
+
return ` /**
|
|
1262
|
+
* Get the ${propName} that owns this model.
|
|
1263
|
+
*/
|
|
1264
|
+
public function ${methodName}(): BelongsTo
|
|
1265
|
+
{
|
|
1266
|
+
return $this->belongsTo(${targetClass}::class, '${fkName}');
|
|
1267
|
+
}`;
|
|
1268
|
+
case "OneToOne":
|
|
1269
|
+
if (assoc.mappedBy) {
|
|
1270
|
+
return ` /**
|
|
1271
|
+
* Get the ${propName} for this model.
|
|
1272
|
+
*/
|
|
1273
|
+
public function ${methodName}(): HasOne
|
|
1274
|
+
{
|
|
1275
|
+
return $this->hasOne(${targetClass}::class, '${toSnakeCase(assoc.mappedBy)}_id');
|
|
1276
|
+
}`;
|
|
1277
|
+
}
|
|
1278
|
+
return ` /**
|
|
1279
|
+
* Get the ${propName} that owns this model.
|
|
1280
|
+
*/
|
|
1281
|
+
public function ${methodName}(): BelongsTo
|
|
1282
|
+
{
|
|
1283
|
+
return $this->belongsTo(${targetClass}::class, '${fkName}');
|
|
1284
|
+
}`;
|
|
1285
|
+
case "OneToMany":
|
|
1286
|
+
return ` /**
|
|
1287
|
+
* Get the ${propName} for this model.
|
|
1288
|
+
*/
|
|
1289
|
+
public function ${methodName}(): HasMany
|
|
1290
|
+
{
|
|
1291
|
+
return $this->hasMany(${targetClass}::class, '${toSnakeCase(assoc.inversedBy ?? propName)}_id');
|
|
1292
|
+
}`;
|
|
1293
|
+
case "ManyToMany": {
|
|
1294
|
+
const pivotTable = assoc.joinTable ?? `${toSnakeCase(propName)}_pivot`;
|
|
1295
|
+
return ` /**
|
|
1296
|
+
* The ${propName} that belong to this model.
|
|
1297
|
+
*/
|
|
1298
|
+
public function ${methodName}(): BelongsToMany
|
|
1299
|
+
{
|
|
1300
|
+
return $this->belongsToMany(${targetClass}::class, '${pivotTable}')
|
|
1301
|
+
->withTimestamps();
|
|
1302
|
+
}`;
|
|
1303
|
+
}
|
|
1304
|
+
case "MorphTo":
|
|
1305
|
+
return ` /**
|
|
1306
|
+
* Get the parent ${propName} model.
|
|
1307
|
+
*/
|
|
1308
|
+
public function ${methodName}(): MorphTo
|
|
1309
|
+
{
|
|
1310
|
+
return $this->morphTo('${methodName}');
|
|
1311
|
+
}`;
|
|
1312
|
+
case "MorphOne":
|
|
1313
|
+
return ` /**
|
|
1314
|
+
* Get the ${propName} for this model.
|
|
1315
|
+
*/
|
|
1316
|
+
public function ${methodName}(): MorphOne
|
|
1317
|
+
{
|
|
1318
|
+
return $this->morphOne(${targetClass}::class, '${assoc.morphName ?? propName}');
|
|
1319
|
+
}`;
|
|
1320
|
+
case "MorphMany":
|
|
1321
|
+
return ` /**
|
|
1322
|
+
* Get the ${propName} for this model.
|
|
1323
|
+
*/
|
|
1324
|
+
public function ${methodName}(): MorphMany
|
|
1325
|
+
{
|
|
1326
|
+
return $this->morphMany(${targetClass}::class, '${assoc.morphName ?? propName}');
|
|
1327
|
+
}`;
|
|
1328
|
+
default:
|
|
1329
|
+
return ` // TODO: Implement ${assoc.relation} relation for ${propName}`;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
function generateFileRelation(propName, propDef) {
|
|
1333
|
+
const methodName = toCamelCase(propName);
|
|
1334
|
+
const relationType = propDef.multiple ? "MorphMany" : "MorphOne";
|
|
1335
|
+
const relationMethod = propDef.multiple ? "morphMany" : "morphOne";
|
|
1336
|
+
return ` /**
|
|
1337
|
+
* Get the ${propName} file(s) for this model.
|
|
1338
|
+
*/
|
|
1339
|
+
public function ${methodName}(): ${relationType}
|
|
1340
|
+
{
|
|
1341
|
+
return $this->${relationMethod}(FileUpload::class, 'uploadable')
|
|
1342
|
+
->where('attribute_name', '${propName}');
|
|
1343
|
+
}`;
|
|
1344
|
+
}
|
|
1345
|
+
function generateEntityModel(schema, options, stubContent) {
|
|
1346
|
+
const className = toPascalCase(schema.name);
|
|
1347
|
+
const content = stubContent.replace(/\{\{BASE_MODEL_NAMESPACE\}\}/g, options.baseModelNamespace).replace(/\{\{MODEL_NAMESPACE\}\}/g, options.modelNamespace).replace(/\{\{CLASS_NAME\}\}/g, className);
|
|
1348
|
+
return {
|
|
1349
|
+
path: `${options.modelPath}/${className}.php`,
|
|
1350
|
+
content,
|
|
1351
|
+
type: "entity",
|
|
1352
|
+
overwrite: false,
|
|
1353
|
+
// Never overwrite user models
|
|
1354
|
+
schemaName: schema.name
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
function getStubContent(stubName) {
|
|
1358
|
+
const stubs = {
|
|
1359
|
+
"base-model": `<?php
|
|
1360
|
+
|
|
1361
|
+
namespace {{BASE_MODEL_NAMESPACE}};
|
|
1362
|
+
|
|
1363
|
+
/**
|
|
1364
|
+
* Base model class for all Omnify-generated models.
|
|
1365
|
+
* Contains model mapping for polymorphic relations.
|
|
1366
|
+
*
|
|
1367
|
+
* DO NOT EDIT - This file is auto-generated by Omnify.
|
|
1368
|
+
* Any changes will be overwritten on next generation.
|
|
1369
|
+
*
|
|
1370
|
+
* @generated by @famgia/omnify-laravel
|
|
1371
|
+
*/
|
|
1372
|
+
|
|
1373
|
+
use Illuminate\\Database\\Eloquent\\Model;
|
|
1374
|
+
use Illuminate\\Database\\Eloquent\\Relations\\Relation;
|
|
1375
|
+
|
|
1376
|
+
abstract class {{BASE_MODEL_CLASS}} extends Model
|
|
1377
|
+
{
|
|
1378
|
+
/**
|
|
1379
|
+
* Model class map for polymorphic relations.
|
|
1380
|
+
*/
|
|
1381
|
+
protected static array $modelMap = [
|
|
1382
|
+
{{MODEL_MAP}}
|
|
1383
|
+
];
|
|
1384
|
+
|
|
1385
|
+
/**
|
|
1386
|
+
* Boot the model and register morph map.
|
|
1387
|
+
*/
|
|
1388
|
+
protected static function boot(): void
|
|
1389
|
+
{
|
|
1390
|
+
parent::boot();
|
|
1391
|
+
|
|
1392
|
+
// Register morph map for polymorphic relations
|
|
1393
|
+
Relation::enforceMorphMap(static::$modelMap);
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
/**
|
|
1397
|
+
* Get the model class for a given morph type.
|
|
1398
|
+
*/
|
|
1399
|
+
public static function getModelClass(string $morphType): ?string
|
|
1400
|
+
{
|
|
1401
|
+
return static::$modelMap[$morphType] ?? null;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
`,
|
|
1405
|
+
"entity-base": `<?php
|
|
1406
|
+
|
|
1407
|
+
namespace {{BASE_MODEL_NAMESPACE}};
|
|
1408
|
+
|
|
1409
|
+
/**
|
|
1410
|
+
* DO NOT EDIT - This file is auto-generated by Omnify.
|
|
1411
|
+
* Any changes will be overwritten on next generation.
|
|
1412
|
+
*
|
|
1413
|
+
* @generated by @famgia/omnify-laravel
|
|
1414
|
+
*/
|
|
1415
|
+
|
|
1416
|
+
use Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;
|
|
1417
|
+
use Illuminate\\Database\\Eloquent\\Relations\\HasMany;
|
|
1418
|
+
use Illuminate\\Database\\Eloquent\\Relations\\HasOne;
|
|
1419
|
+
use Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany;
|
|
1420
|
+
use Illuminate\\Database\\Eloquent\\Relations\\MorphTo;
|
|
1421
|
+
use Illuminate\\Database\\Eloquent\\Relations\\MorphOne;
|
|
1422
|
+
use Illuminate\\Database\\Eloquent\\Relations\\MorphMany;
|
|
1423
|
+
use Illuminate\\Database\\Eloquent\\Relations\\MorphToMany;
|
|
1424
|
+
use Illuminate\\Database\\Eloquent\\Collection as EloquentCollection;
|
|
1425
|
+
{{IMPORTS}}
|
|
1426
|
+
|
|
1427
|
+
{{DOC_COMMENT}}
|
|
1428
|
+
class {{CLASS_NAME}}BaseModel extends {{BASE_MODEL_CLASS}}
|
|
1429
|
+
{
|
|
1430
|
+
{{TRAITS}}
|
|
1431
|
+
/**
|
|
1432
|
+
* The table associated with the model.
|
|
1433
|
+
*/
|
|
1434
|
+
protected $table = '{{TABLE_NAME}}';
|
|
1435
|
+
|
|
1436
|
+
/**
|
|
1437
|
+
* The primary key for the model.
|
|
1438
|
+
*/
|
|
1439
|
+
protected $primaryKey = '{{PRIMARY_KEY}}';
|
|
1440
|
+
|
|
1441
|
+
{{KEY_TYPE}}
|
|
1442
|
+
{{INCREMENTING}}
|
|
1443
|
+
/**
|
|
1444
|
+
* Indicates if the model should be timestamped.
|
|
1445
|
+
*/
|
|
1446
|
+
public $timestamps = {{TIMESTAMPS}};
|
|
1447
|
+
|
|
1448
|
+
/**
|
|
1449
|
+
* The attributes that are mass assignable.
|
|
1450
|
+
*/
|
|
1451
|
+
protected $fillable = [
|
|
1452
|
+
{{FILLABLE}}
|
|
1453
|
+
];
|
|
1454
|
+
|
|
1455
|
+
/**
|
|
1456
|
+
* The attributes that should be hidden for serialization.
|
|
1457
|
+
*/
|
|
1458
|
+
protected $hidden = [
|
|
1459
|
+
{{HIDDEN}}
|
|
1460
|
+
];
|
|
1461
|
+
|
|
1462
|
+
/**
|
|
1463
|
+
* The accessors to append to the model's array form.
|
|
1464
|
+
*/
|
|
1465
|
+
protected $appends = [
|
|
1466
|
+
{{APPENDS}}
|
|
1467
|
+
];
|
|
1468
|
+
|
|
1469
|
+
/**
|
|
1470
|
+
* Get the attributes that should be cast.
|
|
1471
|
+
*/
|
|
1472
|
+
protected function casts(): array
|
|
1473
|
+
{
|
|
1474
|
+
return [
|
|
1475
|
+
{{CASTS}}
|
|
1476
|
+
];
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
{{RELATIONS}}
|
|
1480
|
+
}
|
|
1481
|
+
`,
|
|
1482
|
+
"entity-base-auth": `<?php
|
|
1483
|
+
|
|
1484
|
+
namespace {{BASE_MODEL_NAMESPACE}};
|
|
1485
|
+
|
|
1486
|
+
/**
|
|
1487
|
+
* DO NOT EDIT - This file is auto-generated by Omnify.
|
|
1488
|
+
* Any changes will be overwritten on next generation.
|
|
1489
|
+
*
|
|
1490
|
+
* @generated by @famgia/omnify-laravel
|
|
1491
|
+
*/
|
|
1492
|
+
|
|
1493
|
+
use Illuminate\\Foundation\\Auth\\User as Authenticatable;
|
|
1494
|
+
use Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;
|
|
1495
|
+
use Illuminate\\Database\\Eloquent\\Relations\\HasMany;
|
|
1496
|
+
use Illuminate\\Database\\Eloquent\\Relations\\HasOne;
|
|
1497
|
+
use Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany;
|
|
1498
|
+
use Illuminate\\Database\\Eloquent\\Relations\\MorphTo;
|
|
1499
|
+
use Illuminate\\Database\\Eloquent\\Relations\\MorphOne;
|
|
1500
|
+
use Illuminate\\Database\\Eloquent\\Relations\\MorphMany;
|
|
1501
|
+
use Illuminate\\Database\\Eloquent\\Relations\\MorphToMany;
|
|
1502
|
+
use Illuminate\\Database\\Eloquent\\Collection as EloquentCollection;
|
|
1503
|
+
use Illuminate\\Notifications\\Notifiable;
|
|
1504
|
+
{{IMPORTS}}
|
|
1505
|
+
|
|
1506
|
+
{{DOC_COMMENT}}
|
|
1507
|
+
class {{CLASS_NAME}}BaseModel extends Authenticatable
|
|
1508
|
+
{
|
|
1509
|
+
use Notifiable;
|
|
1510
|
+
{{TRAITS}}
|
|
1511
|
+
/**
|
|
1512
|
+
* The table associated with the model.
|
|
1513
|
+
*/
|
|
1514
|
+
protected $table = '{{TABLE_NAME}}';
|
|
1515
|
+
|
|
1516
|
+
/**
|
|
1517
|
+
* The primary key for the model.
|
|
1518
|
+
*/
|
|
1519
|
+
protected $primaryKey = '{{PRIMARY_KEY}}';
|
|
1520
|
+
|
|
1521
|
+
{{KEY_TYPE}}
|
|
1522
|
+
{{INCREMENTING}}
|
|
1523
|
+
/**
|
|
1524
|
+
* Indicates if the model should be timestamped.
|
|
1525
|
+
*/
|
|
1526
|
+
public $timestamps = {{TIMESTAMPS}};
|
|
1527
|
+
|
|
1528
|
+
/**
|
|
1529
|
+
* The attributes that are mass assignable.
|
|
1530
|
+
*/
|
|
1531
|
+
protected $fillable = [
|
|
1532
|
+
{{FILLABLE}}
|
|
1533
|
+
];
|
|
1534
|
+
|
|
1535
|
+
/**
|
|
1536
|
+
* The attributes that should be hidden for serialization.
|
|
1537
|
+
*/
|
|
1538
|
+
protected $hidden = [
|
|
1539
|
+
{{HIDDEN}}
|
|
1540
|
+
];
|
|
1541
|
+
|
|
1542
|
+
/**
|
|
1543
|
+
* The accessors to append to the model's array form.
|
|
1544
|
+
*/
|
|
1545
|
+
protected $appends = [
|
|
1546
|
+
{{APPENDS}}
|
|
1547
|
+
];
|
|
1548
|
+
|
|
1549
|
+
/**
|
|
1550
|
+
* Get the attributes that should be cast.
|
|
1551
|
+
*/
|
|
1552
|
+
protected function casts(): array
|
|
1553
|
+
{
|
|
1554
|
+
return [
|
|
1555
|
+
{{CASTS}}
|
|
1556
|
+
];
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
{{RELATIONS}}
|
|
1560
|
+
}
|
|
1561
|
+
`,
|
|
1562
|
+
"entity": `<?php
|
|
1563
|
+
|
|
1564
|
+
namespace {{MODEL_NAMESPACE}};
|
|
1565
|
+
|
|
1566
|
+
use {{BASE_MODEL_NAMESPACE}}\\{{CLASS_NAME}}BaseModel;
|
|
1567
|
+
use Illuminate\\Database\\Eloquent\\Factories\\HasFactory;
|
|
1568
|
+
|
|
1569
|
+
/**
|
|
1570
|
+
* {{CLASS_NAME}} Model
|
|
1571
|
+
*
|
|
1572
|
+
* This file is generated once and can be customized.
|
|
1573
|
+
* Add your custom methods and logic here.
|
|
1574
|
+
*/
|
|
1575
|
+
class {{CLASS_NAME}} extends {{CLASS_NAME}}BaseModel
|
|
1576
|
+
{
|
|
1577
|
+
use HasFactory;
|
|
1578
|
+
|
|
1579
|
+
/**
|
|
1580
|
+
* Create a new model instance.
|
|
1581
|
+
*/
|
|
1582
|
+
public function __construct(array $attributes = [])
|
|
1583
|
+
{
|
|
1584
|
+
parent::__construct($attributes);
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
// Add your custom methods here
|
|
1588
|
+
}
|
|
1589
|
+
`
|
|
1590
|
+
};
|
|
1591
|
+
return stubs[stubName] ?? "";
|
|
1592
|
+
}
|
|
1593
|
+
function generateModels(schemas, options) {
|
|
1594
|
+
const resolved = resolveOptions(options);
|
|
1595
|
+
const models = [];
|
|
1596
|
+
models.push(generateBaseModel(schemas, resolved, getStubContent("base-model")));
|
|
1597
|
+
for (const schema of Object.values(schemas)) {
|
|
1598
|
+
if (schema.kind === "enum") {
|
|
1599
|
+
continue;
|
|
1600
|
+
}
|
|
1601
|
+
models.push(generateEntityBaseModel(
|
|
1602
|
+
schema,
|
|
1603
|
+
schemas,
|
|
1604
|
+
resolved,
|
|
1605
|
+
getStubContent("entity-base"),
|
|
1606
|
+
getStubContent("entity-base-auth")
|
|
1607
|
+
));
|
|
1608
|
+
models.push(generateEntityModel(schema, resolved, getStubContent("entity")));
|
|
1609
|
+
}
|
|
1610
|
+
return models;
|
|
1611
|
+
}
|
|
1612
|
+
function getModelPath(model) {
|
|
1613
|
+
return model.path;
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1036
1616
|
// src/plugin.ts
|
|
1037
1617
|
var LARAVEL_CONFIG_SCHEMA = {
|
|
1038
1618
|
fields: [
|
|
@@ -1044,6 +1624,30 @@ var LARAVEL_CONFIG_SCHEMA = {
|
|
|
1044
1624
|
default: "database/migrations",
|
|
1045
1625
|
group: "output"
|
|
1046
1626
|
},
|
|
1627
|
+
{
|
|
1628
|
+
key: "modelsPath",
|
|
1629
|
+
type: "path",
|
|
1630
|
+
label: "Models Path",
|
|
1631
|
+
description: "Directory for user-editable model files",
|
|
1632
|
+
default: "app/Models",
|
|
1633
|
+
group: "output"
|
|
1634
|
+
},
|
|
1635
|
+
{
|
|
1636
|
+
key: "baseModelsPath",
|
|
1637
|
+
type: "path",
|
|
1638
|
+
label: "Base Models Path",
|
|
1639
|
+
description: "Directory for auto-generated base model files",
|
|
1640
|
+
default: "app/Models/OmnifyBase",
|
|
1641
|
+
group: "output"
|
|
1642
|
+
},
|
|
1643
|
+
{
|
|
1644
|
+
key: "generateModels",
|
|
1645
|
+
type: "boolean",
|
|
1646
|
+
label: "Generate Models",
|
|
1647
|
+
description: "Generate Eloquent model classes",
|
|
1648
|
+
default: true,
|
|
1649
|
+
group: "options"
|
|
1650
|
+
},
|
|
1047
1651
|
{
|
|
1048
1652
|
key: "connection",
|
|
1049
1653
|
type: "string",
|
|
@@ -1054,41 +1658,69 @@ var LARAVEL_CONFIG_SCHEMA = {
|
|
|
1054
1658
|
}
|
|
1055
1659
|
]
|
|
1056
1660
|
};
|
|
1057
|
-
function
|
|
1661
|
+
function resolveOptions2(options) {
|
|
1058
1662
|
return {
|
|
1059
1663
|
migrationsPath: options?.migrationsPath ?? "database/migrations",
|
|
1664
|
+
modelsPath: options?.modelsPath ?? "app/Models",
|
|
1665
|
+
baseModelsPath: options?.baseModelsPath ?? "app/Models/OmnifyBase",
|
|
1666
|
+
modelNamespace: options?.modelNamespace ?? "App\\Models",
|
|
1667
|
+
baseModelNamespace: options?.baseModelNamespace ?? "App\\Models\\OmnifyBase",
|
|
1668
|
+
generateModels: options?.generateModels ?? true,
|
|
1060
1669
|
connection: options?.connection,
|
|
1061
1670
|
timestamp: options?.timestamp
|
|
1062
1671
|
};
|
|
1063
1672
|
}
|
|
1064
1673
|
function laravelPlugin(options) {
|
|
1065
|
-
const resolved =
|
|
1674
|
+
const resolved = resolveOptions2(options);
|
|
1675
|
+
const migrationGenerator = {
|
|
1676
|
+
name: "laravel-migrations",
|
|
1677
|
+
description: "Generate Laravel migration files",
|
|
1678
|
+
generate: async (ctx) => {
|
|
1679
|
+
const migrationOptions = {
|
|
1680
|
+
connection: resolved.connection,
|
|
1681
|
+
timestamp: resolved.timestamp
|
|
1682
|
+
};
|
|
1683
|
+
const migrations = generateMigrations(ctx.schemas, migrationOptions);
|
|
1684
|
+
return migrations.map((migration) => ({
|
|
1685
|
+
path: getMigrationPath(migration, resolved.migrationsPath),
|
|
1686
|
+
content: migration.content,
|
|
1687
|
+
type: "migration",
|
|
1688
|
+
metadata: {
|
|
1689
|
+
tableName: migration.tables[0],
|
|
1690
|
+
migrationType: migration.type
|
|
1691
|
+
}
|
|
1692
|
+
}));
|
|
1693
|
+
}
|
|
1694
|
+
};
|
|
1695
|
+
const modelGenerator = {
|
|
1696
|
+
name: "laravel-models",
|
|
1697
|
+
description: "Generate Eloquent model classes",
|
|
1698
|
+
generate: async (ctx) => {
|
|
1699
|
+
const modelOptions = {
|
|
1700
|
+
modelNamespace: resolved.modelNamespace,
|
|
1701
|
+
baseModelNamespace: resolved.baseModelNamespace,
|
|
1702
|
+
modelPath: resolved.modelsPath,
|
|
1703
|
+
baseModelPath: resolved.baseModelsPath
|
|
1704
|
+
};
|
|
1705
|
+
const models = generateModels(ctx.schemas, modelOptions);
|
|
1706
|
+
return models.map((model) => ({
|
|
1707
|
+
path: getModelPath(model),
|
|
1708
|
+
content: model.content,
|
|
1709
|
+
type: "model",
|
|
1710
|
+
// Skip writing user models if they already exist
|
|
1711
|
+
skipIfExists: !model.overwrite,
|
|
1712
|
+
metadata: {
|
|
1713
|
+
modelType: model.type,
|
|
1714
|
+
schemaName: model.schemaName
|
|
1715
|
+
}
|
|
1716
|
+
}));
|
|
1717
|
+
}
|
|
1718
|
+
};
|
|
1066
1719
|
return {
|
|
1067
1720
|
name: "@famgia/omnify-laravel",
|
|
1068
|
-
version: "0.0.
|
|
1721
|
+
version: "0.0.14",
|
|
1069
1722
|
configSchema: LARAVEL_CONFIG_SCHEMA,
|
|
1070
|
-
generators: [
|
|
1071
|
-
{
|
|
1072
|
-
name: "laravel-migrations",
|
|
1073
|
-
description: "Generate Laravel migration files",
|
|
1074
|
-
generate: async (ctx) => {
|
|
1075
|
-
const migrationOptions = {
|
|
1076
|
-
connection: resolved.connection,
|
|
1077
|
-
timestamp: resolved.timestamp
|
|
1078
|
-
};
|
|
1079
|
-
const migrations = generateMigrations(ctx.schemas, migrationOptions);
|
|
1080
|
-
return migrations.map((migration) => ({
|
|
1081
|
-
path: getMigrationPath(migration, resolved.migrationsPath),
|
|
1082
|
-
content: migration.content,
|
|
1083
|
-
type: "migration",
|
|
1084
|
-
metadata: {
|
|
1085
|
-
tableName: migration.tables[0],
|
|
1086
|
-
migrationType: migration.type
|
|
1087
|
-
}
|
|
1088
|
-
}));
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
]
|
|
1723
|
+
generators: resolved.generateModels ? [migrationGenerator, modelGenerator] : [migrationGenerator]
|
|
1092
1724
|
};
|
|
1093
1725
|
}
|
|
1094
1726
|
// Annotate the CommonJS export names for ESM import in node:
|