@famgia/omnify-laravel 0.0.12 → 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/index.cjs CHANGED
@@ -20,45 +20,25 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- enumToUnionType: () => enumToUnionType,
24
- extractInlineEnums: () => extractInlineEnums,
25
23
  formatColumnMethod: () => formatColumnMethod,
26
- formatEnum: () => formatEnum,
27
24
  formatForeignKey: () => formatForeignKey,
28
25
  formatIndex: () => formatIndex,
29
- formatInterface: () => formatInterface,
30
26
  formatMigrationFile: () => formatMigrationFile,
31
- formatProperty: () => formatProperty,
32
- formatTypeAlias: () => formatTypeAlias,
33
27
  generateAlterMigration: () => generateAlterMigration,
34
28
  generateDropMigrationForTable: () => generateDropMigrationForTable,
35
29
  generateDropTableMigration: () => generateDropTableMigration,
36
- generateEnums: () => generateEnums,
37
30
  generateForeignKey: () => generateForeignKey,
38
- generateInterfaces: () => generateInterfaces,
39
31
  generateMigrationFromSchema: () => generateMigrationFromSchema,
40
32
  generateMigrations: () => generateMigrations,
41
33
  generateMigrationsFromChanges: () => generateMigrationsFromChanges,
42
34
  generatePrimaryKeyColumn: () => generatePrimaryKeyColumn,
43
35
  generateSoftDeleteColumn: () => generateSoftDeleteColumn,
44
36
  generateTimestampColumns: () => generateTimestampColumns,
45
- generateTypeScript: () => generateTypeScript,
46
- generateTypeScriptFile: () => generateTypeScriptFile,
47
- generateTypeScriptFiles: () => generateTypeScriptFiles,
48
37
  getMigrationPath: () => getMigrationPath,
49
- getPropertyType: () => getPropertyType,
50
- getTypeScriptPath: () => getTypeScriptPath,
51
38
  laravelPlugin: () => laravelPlugin,
52
39
  propertyToColumnMethod: () => propertyToColumnMethod,
53
- propertyToTSProperty: () => propertyToTSProperty,
54
40
  schemaToBlueprint: () => schemaToBlueprint,
55
- schemaToEnum: () => schemaToEnum,
56
- schemaToInterface: () => schemaToInterface,
57
41
  toColumnName: () => toColumnName,
58
- toEnumMemberName: () => toEnumMemberName,
59
- toEnumName: () => toEnumName,
60
- toInterfaceName: () => toInterfaceName,
61
- toPropertyName: () => toPropertyName,
62
42
  toTableName: () => toTableName
63
43
  });
64
44
  module.exports = __toCommonJS(index_exports);
@@ -331,11 +311,18 @@ function schemaToBlueprint(schema, allSchemas) {
331
311
  }
332
312
  if (schema.options?.indexes) {
333
313
  for (const index of schema.options.indexes) {
334
- indexes.push({
335
- name: index.name,
336
- columns: index.columns.map(toColumnName),
337
- unique: index.unique ?? false
338
- });
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
+ }
339
326
  }
340
327
  }
341
328
  if (schema.options?.unique) {
@@ -1053,503 +1040,611 @@ function generateMigrationsFromChanges(changes, options = {}) {
1053
1040
  return migrations;
1054
1041
  }
1055
1042
 
1056
- // src/typescript/interface-generator.ts
1057
- var TYPE_MAP = {
1058
- String: "string",
1059
- Int: "number",
1060
- BigInt: "number",
1061
- Float: "number",
1062
- Boolean: "boolean",
1063
- Text: "string",
1064
- LongText: "string",
1065
- Date: "string",
1066
- Time: "string",
1067
- Timestamp: "string",
1068
- Json: "unknown",
1069
- Email: "string",
1070
- Password: "string",
1071
- Enum: "string",
1072
- Select: "string",
1073
- Lookup: "number"
1074
- };
1075
- var FILE_INTERFACE_NAME = "File";
1076
- var PK_TYPE_MAP = {
1077
- Int: "number",
1078
- BigInt: "number",
1079
- Uuid: "string",
1080
- String: "string"
1081
- };
1082
- function toPropertyName(name) {
1083
- return name;
1043
+ // src/utils.ts
1044
+ function toSnakeCase(str) {
1045
+ return str.replace(/([A-Z])/g, "_$1").replace(/^_/, "").toLowerCase();
1084
1046
  }
1085
- function toInterfaceName(schemaName) {
1086
- return schemaName;
1047
+ function toPascalCase(str) {
1048
+ return str.replace(/[-_](.)/g, (_, c) => c.toUpperCase()).replace(/^(.)/, (_, c) => c.toUpperCase());
1087
1049
  }
1088
- function getPropertyType(property, _allSchemas) {
1089
- if (property.type === "File") {
1090
- const fileProp = property;
1091
- if (fileProp.multiple) {
1092
- return `${FILE_INTERFACE_NAME}[]`;
1093
- }
1094
- return `${FILE_INTERFACE_NAME} | null`;
1095
- }
1096
- if (property.type === "Association") {
1097
- const assocProp = property;
1098
- const targetName = assocProp.target ?? "unknown";
1099
- switch (assocProp.relation) {
1100
- // Standard relations
1101
- case "OneToOne":
1102
- case "ManyToOne":
1103
- return targetName;
1104
- case "OneToMany":
1105
- case "ManyToMany":
1106
- return `${targetName}[]`;
1107
- // Polymorphic relations
1108
- case "MorphTo":
1109
- if (assocProp.targets && assocProp.targets.length > 0) {
1110
- return assocProp.targets.join(" | ");
1111
- }
1112
- return "unknown";
1113
- case "MorphOne":
1114
- return targetName;
1115
- case "MorphMany":
1116
- case "MorphToMany":
1117
- case "MorphedByMany":
1118
- return `${targetName}[]`;
1119
- default:
1120
- return "unknown";
1121
- }
1122
- }
1123
- if (property.type === "Enum") {
1124
- const enumProp = property;
1125
- if (typeof enumProp.enum === "string") {
1126
- return enumProp.enum;
1127
- }
1128
- if (Array.isArray(enumProp.enum)) {
1129
- return enumProp.enum.map((v) => `'${v}'`).join(" | ");
1130
- }
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";
1131
1057
  }
1132
- if (property.type === "Select") {
1133
- const selectProp = property;
1134
- if (selectProp.options && selectProp.options.length > 0) {
1135
- return selectProp.options.map((v) => `'${v}'`).join(" | ");
1136
- }
1058
+ if (word.endsWith("s") || word.endsWith("x") || word.endsWith("z") || word.endsWith("ch") || word.endsWith("sh")) {
1059
+ return word + "es";
1137
1060
  }
1138
- return TYPE_MAP[property.type] ?? "unknown";
1061
+ return word + "s";
1139
1062
  }
1140
- function propertyToTSProperties(propertyName, property, allSchemas, options = {}) {
1141
- const baseProp = property;
1142
- const isReadonly = options.readonly ?? true;
1143
- if (property.type === "Association") {
1144
- const assocProp = property;
1145
- if (assocProp.relation === "MorphTo" && assocProp.targets && assocProp.targets.length > 0) {
1146
- const propBaseName = toPropertyName(propertyName);
1147
- const targetUnion = assocProp.targets.map((t) => `'${t}'`).join(" | ");
1148
- const relationUnion = assocProp.targets.join(" | ");
1149
- return [
1150
- {
1151
- name: `${propBaseName}Type`,
1152
- type: targetUnion,
1153
- optional: true,
1154
- // Polymorphic columns are nullable
1155
- readonly: isReadonly,
1156
- comment: `Polymorphic type for ${propertyName}`
1157
- },
1158
- {
1159
- name: `${propBaseName}Id`,
1160
- type: "number",
1161
- optional: true,
1162
- readonly: isReadonly,
1163
- comment: `Polymorphic ID for ${propertyName}`
1164
- },
1165
- {
1166
- name: propBaseName,
1167
- type: `${relationUnion} | null`,
1168
- optional: true,
1169
- readonly: isReadonly,
1170
- comment: baseProp.displayName ?? `Polymorphic relation to ${assocProp.targets.join(", ")}`
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";
1171
1146
  }
1172
- ];
1173
- }
1174
- }
1175
- const type = getPropertyType(property, allSchemas);
1176
- return [{
1177
- name: toPropertyName(propertyName),
1178
- type,
1179
- optional: baseProp.nullable ?? false,
1180
- readonly: isReadonly,
1181
- comment: baseProp.displayName
1182
- }];
1183
- }
1184
- function propertyToTSProperty(propertyName, property, allSchemas, options = {}) {
1185
- return propertyToTSProperties(propertyName, property, allSchemas, options)[0];
1186
- }
1187
- function schemaToInterface(schema, allSchemas, options = {}) {
1188
- const properties = [];
1189
- if (schema.options?.id !== false) {
1190
- const pkType = schema.options?.idType ?? "BigInt";
1191
- properties.push({
1192
- name: "id",
1193
- type: PK_TYPE_MAP[pkType] ?? "number",
1194
- optional: false,
1195
- readonly: options.readonly ?? true,
1196
- comment: "Primary key"
1197
- });
1198
- }
1199
- if (schema.properties) {
1200
- for (const [propName, property] of Object.entries(schema.properties)) {
1201
- properties.push(...propertyToTSProperties(propName, property, allSchemas, options));
1202
- }
1203
- }
1204
- if (schema.options?.timestamps !== false) {
1205
- properties.push(
1206
- {
1207
- name: "createdAt",
1208
- type: "string",
1209
- optional: true,
1210
- readonly: options.readonly ?? true,
1211
- comment: "Creation timestamp"
1212
- },
1213
- {
1214
- name: "updatedAt",
1215
- type: "string",
1216
- optional: true,
1217
- readonly: options.readonly ?? true,
1218
- comment: "Last update timestamp"
1219
1147
  }
1220
- );
1221
- }
1222
- if (schema.options?.softDelete) {
1223
- properties.push({
1224
- name: "deletedAt",
1225
- type: "string",
1226
- optional: true,
1227
- readonly: options.readonly ?? true,
1228
- comment: "Soft delete timestamp"
1229
- });
1148
+ return "mixed";
1149
+ }
1150
+ default:
1151
+ return "mixed";
1230
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);
1231
1160
  return {
1232
- name: toInterfaceName(schema.name),
1233
- properties,
1234
- comment: schema.displayName ?? schema.name
1161
+ path: `${options.baseModelPath}/${options.baseModelClassName}.php`,
1162
+ content,
1163
+ type: "base-model",
1164
+ overwrite: true,
1165
+ schemaName: "__base__"
1235
1166
  };
1236
1167
  }
1237
- function formatProperty(property) {
1238
- const readonly = property.readonly ? "readonly " : "";
1239
- const optional = property.optional ? "?" : "";
1240
- const comment = property.comment ? ` /** ${property.comment} */
1241
- ` : "";
1242
- return `${comment} ${readonly}${property.name}${optional}: ${property.type};`;
1243
- }
1244
- function formatInterface(iface) {
1245
- const comment = iface.comment ? `/**
1246
- * ${iface.comment}
1247
- */
1248
- ` : "";
1249
- const extendsClause = iface.extends && iface.extends.length > 0 ? ` extends ${iface.extends.join(", ")}` : "";
1250
- const properties = iface.properties.map(formatProperty).join("\n");
1251
- return `${comment}export interface ${iface.name}${extendsClause} {
1252
- ${properties}
1253
- }`;
1254
- }
1255
- function generateInterfaces(schemas, options = {}) {
1256
- const interfaces = [];
1257
- for (const schema of Object.values(schemas)) {
1258
- if (schema.kind === "enum") {
1259
- continue;
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
+ }
1260
1222
  }
1261
- interfaces.push(schemaToInterface(schema, schemas, options));
1262
1223
  }
1263
- return interfaces;
1264
- }
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';
1265
1234
 
1266
- // src/typescript/enum-generator.ts
1267
- function toEnumMemberName(value) {
1268
- return value.split(/[-_\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("").replace(/[^a-zA-Z0-9]/g, "");
1269
- }
1270
- function toEnumName(schemaName) {
1271
- return schemaName;
1272
- }
1273
- function schemaToEnum(schema) {
1274
- if (schema.kind !== "enum" || !schema.values) {
1275
- return null;
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;");
1276
1245
  }
1277
- const values = schema.values.map((value) => ({
1278
- name: toEnumMemberName(value),
1279
- value
1280
- }));
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"));
1281
1247
  return {
1282
- name: toEnumName(schema.name),
1283
- values,
1284
- comment: schema.displayName ?? schema.name
1248
+ path: `${options.baseModelPath}/${className}BaseModel.php`,
1249
+ content,
1250
+ type: "entity-base",
1251
+ overwrite: true,
1252
+ schemaName: schema.name
1285
1253
  };
1286
1254
  }
1287
- function generateEnums(schemas) {
1288
- const enums = [];
1289
- for (const schema of Object.values(schemas)) {
1290
- if (schema.kind === "enum") {
1291
- const enumDef = schemaToEnum(schema);
1292
- if (enumDef) {
1293
- enums.push(enumDef);
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
+ }`;
1294
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
+ }`;
1295
1303
  }
1296
- }
1297
- return enums;
1298
- }
1299
- function formatEnum(enumDef) {
1300
- const comment = enumDef.comment ? `/**
1301
- * ${enumDef.comment}
1302
- */
1303
- ` : "";
1304
- const values = enumDef.values.map((v) => ` ${v.name} = '${v.value}',`).join("\n");
1305
- return `${comment}export enum ${enumDef.name} {
1306
- ${values}
1307
- }`;
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
+ }`;
1308
1344
  }
1309
- function enumToUnionType(enumDef) {
1310
- const type = enumDef.values.map((v) => `'${v.value}'`).join(" | ");
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);
1311
1348
  return {
1312
- name: enumDef.name,
1313
- type,
1314
- comment: enumDef.comment
1349
+ path: `${options.modelPath}/${className}.php`,
1350
+ content,
1351
+ type: "entity",
1352
+ overwrite: false,
1353
+ // Never overwrite user models
1354
+ schemaName: schema.name
1315
1355
  };
1316
1356
  }
1317
- function formatTypeAlias(alias) {
1318
- const comment = alias.comment ? `/**
1319
- * ${alias.comment}
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
1320
1371
  */
1321
- ` : "";
1322
- return `${comment}export type ${alias.name} = ${alias.type};`;
1323
- }
1324
- function extractInlineEnums(schemas) {
1325
- const typeAliases = [];
1326
- for (const schema of Object.values(schemas)) {
1327
- if (schema.kind === "enum" || !schema.properties) {
1328
- continue;
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);
1329
1394
  }
1330
- for (const [propName, property] of Object.entries(schema.properties)) {
1331
- if (property.type === "Enum") {
1332
- const enumProp = property;
1333
- if (Array.isArray(enumProp.enum) && enumProp.enum.length > 0) {
1334
- const typeName = `${schema.name}${propName.charAt(0).toUpperCase() + propName.slice(1)}`;
1335
- typeAliases.push({
1336
- name: typeName,
1337
- type: enumProp.enum.map((v) => `'${v}'`).join(" | "),
1338
- comment: enumProp.displayName ?? `${schema.name} ${propName} enum`
1339
- });
1340
- }
1341
- }
1342
- if (property.type === "Select") {
1343
- const selectProp = property;
1344
- if (selectProp.options && selectProp.options.length > 0) {
1345
- const typeName = `${schema.name}${propName.charAt(0).toUpperCase() + propName.slice(1)}`;
1346
- typeAliases.push({
1347
- name: typeName,
1348
- type: selectProp.options.map((v) => `'${v}'`).join(" | "),
1349
- comment: selectProp.displayName ?? `${schema.name} ${propName} options`
1350
- });
1351
- }
1352
- }
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;
1353
1402
  }
1354
- }
1355
- return typeAliases;
1356
1403
  }
1404
+ `,
1405
+ "entity-base": `<?php
1357
1406
 
1358
- // src/typescript/generator.ts
1359
- var DEFAULT_OPTIONS = {
1360
- singleFile: true,
1361
- fileName: "types.ts",
1362
- readonly: true,
1363
- strictNullChecks: true
1364
- };
1365
- function generateHeader() {
1366
- return `/**
1367
- * Auto-generated TypeScript types from Omnify schemas.
1368
- * DO NOT EDIT - This file is automatically generated.
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
1369
1414
  */
1370
1415
 
1371
- `;
1372
- }
1373
- function generateTypeScriptFile(schemas, options = {}) {
1374
- const opts = { ...DEFAULT_OPTIONS, ...options };
1375
- const parts = [generateHeader()];
1376
- const types = [];
1377
- const enums = generateEnums(schemas);
1378
- if (enums.length > 0) {
1379
- parts.push("// Enums\n");
1380
- for (const enumDef of enums) {
1381
- parts.push(formatEnum(enumDef));
1382
- parts.push("\n\n");
1383
- types.push(enumDef.name);
1384
- }
1385
- }
1386
- const inlineEnums = extractInlineEnums(schemas);
1387
- if (inlineEnums.length > 0) {
1388
- parts.push("// Type Aliases\n");
1389
- for (const alias of inlineEnums) {
1390
- parts.push(formatTypeAlias(alias));
1391
- parts.push("\n\n");
1392
- types.push(alias.name);
1393
- }
1394
- }
1395
- const interfaces = generateInterfaces(schemas, opts);
1396
- if (interfaces.length > 0) {
1397
- parts.push("// Interfaces\n");
1398
- for (const iface of interfaces) {
1399
- parts.push(formatInterface(iface));
1400
- parts.push("\n\n");
1401
- types.push(iface.name);
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
+ ];
1402
1477
  }
1403
- }
1404
- return {
1405
- fileName: opts.fileName ?? "types.ts",
1406
- content: parts.join("").trim() + "\n",
1407
- types
1408
- };
1478
+
1479
+ {{RELATIONS}}
1409
1480
  }
1410
- function generateTypeScriptFiles(schemas, options = {}) {
1411
- const opts = { ...DEFAULT_OPTIONS, ...options };
1412
- const files = [];
1413
- const enums = generateEnums(schemas);
1414
- if (enums.length > 0) {
1415
- const content = generateHeader() + enums.map(formatEnum).join("\n\n") + "\n";
1416
- files.push({
1417
- fileName: "enums.ts",
1418
- content,
1419
- types: enums.map((e) => e.name)
1420
- });
1421
- }
1422
- const inlineEnums = extractInlineEnums(schemas);
1423
- if (inlineEnums.length > 0) {
1424
- const content = generateHeader() + inlineEnums.map(formatTypeAlias).join("\n\n") + "\n";
1425
- files.push({
1426
- fileName: "type-aliases.ts",
1427
- content,
1428
- types: inlineEnums.map((a) => a.name)
1429
- });
1430
- }
1431
- const interfaces = generateInterfaces(schemas, opts);
1432
- for (const iface of interfaces) {
1433
- const imports = collectImports(iface, enums, inlineEnums, interfaces);
1434
- const importStatement = formatImports(imports);
1435
- const content = generateHeader() + (importStatement ? importStatement + "\n\n" : "") + formatInterface(iface) + "\n";
1436
- files.push({
1437
- fileName: `${toKebabCase(iface.name)}.ts`,
1438
- content,
1439
- types: [iface.name]
1440
- });
1441
- }
1442
- const indexContent = generateIndexFile(files);
1443
- files.push({
1444
- fileName: "index.ts",
1445
- content: indexContent,
1446
- types: []
1447
- });
1448
- return files;
1449
- }
1450
- function toKebabCase(name) {
1451
- return name.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
1452
- }
1453
- function collectImports(iface, enums, typeAliases, allInterfaces) {
1454
- const imports = /* @__PURE__ */ new Map();
1455
- const enumNames = new Set(enums.map((e) => e.name));
1456
- const aliasNames = new Set(typeAliases.map((a) => a.name));
1457
- const interfaceNames = new Set(allInterfaces.map((i) => i.name));
1458
- for (const prop of iface.properties) {
1459
- if (enumNames.has(prop.type)) {
1460
- const existing = imports.get("./enums.js") ?? [];
1461
- if (!existing.includes(prop.type)) {
1462
- imports.set("./enums.js", [...existing, prop.type]);
1463
- }
1464
- }
1465
- if (aliasNames.has(prop.type)) {
1466
- const existing = imports.get("./type-aliases.js") ?? [];
1467
- if (!existing.includes(prop.type)) {
1468
- imports.set("./type-aliases.js", [...existing, prop.type]);
1469
- }
1470
- }
1471
- const baseType = prop.type.replace("[]", "");
1472
- if (interfaceNames.has(baseType) && baseType !== iface.name) {
1473
- const fileName = `./${toKebabCase(baseType)}.js`;
1474
- const existing = imports.get(fileName) ?? [];
1475
- if (!existing.includes(baseType)) {
1476
- imports.set(fileName, [...existing, baseType]);
1477
- }
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
+ ];
1478
1557
  }
1479
- }
1480
- return imports;
1558
+
1559
+ {{RELATIONS}}
1481
1560
  }
1482
- function formatImports(imports) {
1483
- if (imports.size === 0) return "";
1484
- const lines = [];
1485
- for (const [path, names] of imports) {
1486
- lines.push(`import type { ${names.join(", ")} } from '${path}';`);
1487
- }
1488
- return lines.join("\n");
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
1489
1588
  }
1490
- function generateIndexFile(files) {
1491
- const exports2 = [generateHeader().trim(), ""];
1492
- for (const file of files) {
1493
- if (file.fileName === "index.ts") continue;
1494
- const moduleName = file.fileName.replace(".ts", ".js");
1495
- exports2.push(`export * from './${moduleName}';`);
1496
- }
1497
- return exports2.join("\n") + "\n";
1589
+ `
1590
+ };
1591
+ return stubs[stubName] ?? "";
1498
1592
  }
1499
- function generateTypeScript(schemas, options = {}) {
1500
- const opts = { ...DEFAULT_OPTIONS, ...options };
1501
- if (opts.singleFile) {
1502
- return [generateTypeScriptFile(schemas, opts)];
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")));
1503
1609
  }
1504
- return generateTypeScriptFiles(schemas, opts);
1610
+ return models;
1505
1611
  }
1506
- function getTypeScriptPath(file, outputDir = "src/types") {
1507
- return `${outputDir}/${file.fileName}`;
1612
+ function getModelPath(model) {
1613
+ return model.path;
1508
1614
  }
1509
1615
 
1510
1616
  // src/plugin.ts
1511
1617
  var LARAVEL_CONFIG_SCHEMA = {
1512
1618
  fields: [
1513
- // Paths group
1514
1619
  {
1515
1620
  key: "migrationsPath",
1516
1621
  type: "path",
1517
1622
  label: "Migrations Path",
1518
1623
  description: "Directory for Laravel migration files",
1519
1624
  default: "database/migrations",
1520
- group: "paths"
1625
+ group: "output"
1521
1626
  },
1522
1627
  {
1523
- key: "typesPath",
1628
+ key: "modelsPath",
1524
1629
  type: "path",
1525
- label: "TypeScript Types Path",
1526
- description: "Directory for generated TypeScript type files",
1527
- default: "types",
1528
- group: "paths"
1529
- },
1530
- // Generators group
1531
- {
1532
- key: "generateMigrations",
1533
- type: "boolean",
1534
- label: "Generate Migrations",
1535
- description: "Generate Laravel migration files",
1536
- default: true,
1537
- group: "generators"
1630
+ label: "Models Path",
1631
+ description: "Directory for user-editable model files",
1632
+ default: "app/Models",
1633
+ group: "output"
1538
1634
  },
1539
1635
  {
1540
- key: "generateTypes",
1541
- type: "boolean",
1542
- label: "Generate TypeScript Types",
1543
- description: "Generate TypeScript type definitions",
1544
- default: true,
1545
- group: "generators"
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"
1546
1642
  },
1547
- // Options group
1548
1643
  {
1549
- key: "singleFile",
1644
+ key: "generateModels",
1550
1645
  type: "boolean",
1551
- label: "Single File Output",
1552
- description: "Generate all types in a single file",
1646
+ label: "Generate Models",
1647
+ description: "Generate Eloquent model classes",
1553
1648
  default: true,
1554
1649
  group: "options"
1555
1650
  },
@@ -1563,112 +1658,92 @@ var LARAVEL_CONFIG_SCHEMA = {
1563
1658
  }
1564
1659
  ]
1565
1660
  };
1566
- function resolveOptions(options) {
1661
+ function resolveOptions2(options) {
1567
1662
  return {
1568
1663
  migrationsPath: options?.migrationsPath ?? "database/migrations",
1569
- typesPath: options?.typesPath ?? "types",
1570
- singleFile: options?.singleFile ?? true,
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,
1571
1669
  connection: options?.connection,
1572
- timestamp: options?.timestamp,
1573
- generateTypes: options?.generateTypes ?? true,
1574
- generateMigrations: options?.generateMigrations ?? true
1670
+ timestamp: options?.timestamp
1575
1671
  };
1576
1672
  }
1577
1673
  function laravelPlugin(options) {
1578
- const resolved = resolveOptions(options);
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
+ };
1579
1719
  return {
1580
1720
  name: "@famgia/omnify-laravel",
1581
- version: "0.0.12",
1721
+ version: "0.0.14",
1582
1722
  configSchema: LARAVEL_CONFIG_SCHEMA,
1583
- generators: [
1584
- // Laravel Migrations Generator
1585
- ...resolved.generateMigrations ? [
1586
- {
1587
- name: "laravel-migrations",
1588
- description: "Generate Laravel migration files",
1589
- generate: async (ctx) => {
1590
- const migrationOptions = {
1591
- connection: resolved.connection,
1592
- timestamp: resolved.timestamp
1593
- };
1594
- const migrations = generateMigrations(ctx.schemas, migrationOptions);
1595
- return migrations.map((migration) => ({
1596
- path: getMigrationPath(migration, resolved.migrationsPath),
1597
- content: migration.content,
1598
- type: "migration",
1599
- metadata: {
1600
- tableName: migration.tables[0],
1601
- migrationType: migration.type
1602
- }
1603
- }));
1604
- }
1605
- }
1606
- ] : [],
1607
- // TypeScript Types Generator
1608
- ...resolved.generateTypes ? [
1609
- {
1610
- name: "typescript-types",
1611
- description: "Generate TypeScript type definitions",
1612
- generate: async (ctx) => {
1613
- const tsOptions = {
1614
- singleFile: resolved.singleFile
1615
- };
1616
- const files = generateTypeScript(ctx.schemas, tsOptions);
1617
- return files.map((file) => ({
1618
- path: `${resolved.typesPath}/${file.fileName}`,
1619
- content: file.content,
1620
- type: "type",
1621
- metadata: {
1622
- types: file.types
1623
- }
1624
- }));
1625
- }
1626
- }
1627
- ] : []
1628
- ]
1723
+ generators: resolved.generateModels ? [migrationGenerator, modelGenerator] : [migrationGenerator]
1629
1724
  };
1630
1725
  }
1631
1726
  // Annotate the CommonJS export names for ESM import in node:
1632
1727
  0 && (module.exports = {
1633
- enumToUnionType,
1634
- extractInlineEnums,
1635
1728
  formatColumnMethod,
1636
- formatEnum,
1637
1729
  formatForeignKey,
1638
1730
  formatIndex,
1639
- formatInterface,
1640
1731
  formatMigrationFile,
1641
- formatProperty,
1642
- formatTypeAlias,
1643
1732
  generateAlterMigration,
1644
1733
  generateDropMigrationForTable,
1645
1734
  generateDropTableMigration,
1646
- generateEnums,
1647
1735
  generateForeignKey,
1648
- generateInterfaces,
1649
1736
  generateMigrationFromSchema,
1650
1737
  generateMigrations,
1651
1738
  generateMigrationsFromChanges,
1652
1739
  generatePrimaryKeyColumn,
1653
1740
  generateSoftDeleteColumn,
1654
1741
  generateTimestampColumns,
1655
- generateTypeScript,
1656
- generateTypeScriptFile,
1657
- generateTypeScriptFiles,
1658
1742
  getMigrationPath,
1659
- getPropertyType,
1660
- getTypeScriptPath,
1661
1743
  laravelPlugin,
1662
1744
  propertyToColumnMethod,
1663
- propertyToTSProperty,
1664
1745
  schemaToBlueprint,
1665
- schemaToEnum,
1666
- schemaToInterface,
1667
1746
  toColumnName,
1668
- toEnumMemberName,
1669
- toEnumName,
1670
- toInterfaceName,
1671
- toPropertyName,
1672
1747
  toTableName
1673
1748
  });
1674
1749
  //# sourceMappingURL=index.cjs.map