@famgia/omnify-laravel 0.0.29 → 0.0.31

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.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { CustomTypeDefinition, PropertyDefinition, SchemaCollection, LoadedSchema } from '@famgia/omnify-types';
1
+ import { CustomTypeDefinition, LocaleResolutionOptions, PropertyDefinition, SchemaCollection, LoadedSchema } from '@famgia/omnify-types';
2
2
  import { SchemaChange } from '@famgia/omnify-atlas';
3
3
  export { LaravelPluginOptions, laravelPlugin } from './plugin.cjs';
4
4
 
@@ -37,6 +37,8 @@ interface MigrationOptions {
37
37
  readonly connection?: string | undefined;
38
38
  /** Custom types from plugins (for compound type expansion) */
39
39
  readonly customTypes?: ReadonlyMap<string, CustomTypeDefinition> | undefined;
40
+ /** Locale resolution options for displayName */
41
+ readonly locale?: LocaleResolutionOptions | undefined;
40
42
  }
41
43
  /**
42
44
  * Schema Builder column method.
@@ -140,10 +142,17 @@ declare function toColumnName(propertyName: string): string;
140
142
  * Converts schema name to snake_case plural table name.
141
143
  */
142
144
  declare function toTableName(schemaName: string): string;
145
+ /**
146
+ * Options for property to column conversion.
147
+ */
148
+ interface PropertyToColumnOptions {
149
+ /** Locale resolution options for displayName */
150
+ locale?: LocaleResolutionOptions;
151
+ }
143
152
  /**
144
153
  * Converts a property to Laravel column method.
145
154
  */
146
- declare function propertyToColumnMethod(propertyName: string, property: PropertyDefinition): ColumnMethod | null;
155
+ declare function propertyToColumnMethod(propertyName: string, property: PropertyDefinition, options?: PropertyToColumnOptions): ColumnMethod | null;
147
156
  /**
148
157
  * Generates primary key column method.
149
158
  */
@@ -159,7 +168,7 @@ declare function generateSoftDeleteColumn(): ColumnMethod;
159
168
  /**
160
169
  * Generates foreign key column and constraint from association.
161
170
  */
162
- declare function generateForeignKey(propertyName: string, property: PropertyDefinition, allSchemas: SchemaCollection): {
171
+ declare function generateForeignKey(propertyName: string, property: PropertyDefinition, allSchemas: SchemaCollection, options?: PropertyToColumnOptions): {
163
172
  column: ColumnMethod;
164
173
  foreignKey: ForeignKeyDefinition;
165
174
  index: IndexDefinition;
@@ -170,6 +179,8 @@ declare function generateForeignKey(propertyName: string, property: PropertyDefi
170
179
  interface SchemaToBlueprintOptions {
171
180
  /** Custom types from plugins (for compound type expansion) */
172
181
  customTypes?: ReadonlyMap<string, CustomTypeDefinition>;
182
+ /** Locale resolution options for displayName */
183
+ locale?: LocaleResolutionOptions;
173
184
  }
174
185
  /**
175
186
  * Generates table blueprint from schema.
@@ -270,6 +281,11 @@ interface ModelGeneratorOptions {
270
281
  * @default 'app/Models'
271
282
  */
272
283
  modelPath?: string;
284
+ /**
285
+ * Custom types registered by plugins.
286
+ * Used to expand compound types in fillable array.
287
+ */
288
+ customTypes?: ReadonlyMap<string, CustomTypeDefinition>;
273
289
  }
274
290
  /**
275
291
  * Generated model output.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CustomTypeDefinition, PropertyDefinition, SchemaCollection, LoadedSchema } from '@famgia/omnify-types';
1
+ import { CustomTypeDefinition, LocaleResolutionOptions, PropertyDefinition, SchemaCollection, LoadedSchema } from '@famgia/omnify-types';
2
2
  import { SchemaChange } from '@famgia/omnify-atlas';
3
3
  export { LaravelPluginOptions, laravelPlugin } from './plugin.js';
4
4
 
@@ -37,6 +37,8 @@ interface MigrationOptions {
37
37
  readonly connection?: string | undefined;
38
38
  /** Custom types from plugins (for compound type expansion) */
39
39
  readonly customTypes?: ReadonlyMap<string, CustomTypeDefinition> | undefined;
40
+ /** Locale resolution options for displayName */
41
+ readonly locale?: LocaleResolutionOptions | undefined;
40
42
  }
41
43
  /**
42
44
  * Schema Builder column method.
@@ -140,10 +142,17 @@ declare function toColumnName(propertyName: string): string;
140
142
  * Converts schema name to snake_case plural table name.
141
143
  */
142
144
  declare function toTableName(schemaName: string): string;
145
+ /**
146
+ * Options for property to column conversion.
147
+ */
148
+ interface PropertyToColumnOptions {
149
+ /** Locale resolution options for displayName */
150
+ locale?: LocaleResolutionOptions;
151
+ }
143
152
  /**
144
153
  * Converts a property to Laravel column method.
145
154
  */
146
- declare function propertyToColumnMethod(propertyName: string, property: PropertyDefinition): ColumnMethod | null;
155
+ declare function propertyToColumnMethod(propertyName: string, property: PropertyDefinition, options?: PropertyToColumnOptions): ColumnMethod | null;
147
156
  /**
148
157
  * Generates primary key column method.
149
158
  */
@@ -159,7 +168,7 @@ declare function generateSoftDeleteColumn(): ColumnMethod;
159
168
  /**
160
169
  * Generates foreign key column and constraint from association.
161
170
  */
162
- declare function generateForeignKey(propertyName: string, property: PropertyDefinition, allSchemas: SchemaCollection): {
171
+ declare function generateForeignKey(propertyName: string, property: PropertyDefinition, allSchemas: SchemaCollection, options?: PropertyToColumnOptions): {
163
172
  column: ColumnMethod;
164
173
  foreignKey: ForeignKeyDefinition;
165
174
  index: IndexDefinition;
@@ -170,6 +179,8 @@ declare function generateForeignKey(propertyName: string, property: PropertyDefi
170
179
  interface SchemaToBlueprintOptions {
171
180
  /** Custom types from plugins (for compound type expansion) */
172
181
  customTypes?: ReadonlyMap<string, CustomTypeDefinition>;
182
+ /** Locale resolution options for displayName */
183
+ locale?: LocaleResolutionOptions;
173
184
  }
174
185
  /**
175
186
  * Generates table blueprint from schema.
@@ -270,6 +281,11 @@ interface ModelGeneratorOptions {
270
281
  * @default 'app/Models'
271
282
  */
272
283
  modelPath?: string;
284
+ /**
285
+ * Custom types registered by plugins.
286
+ * Used to expand compound types in fillable array.
287
+ */
288
+ customTypes?: ReadonlyMap<string, CustomTypeDefinition>;
273
289
  }
274
290
  /**
275
291
  * Generated model output.
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ import {
22
22
  schemaToBlueprint,
23
23
  toColumnName,
24
24
  toTableName
25
- } from "./chunk-4LHIH7NX.js";
25
+ } from "./chunk-BYMCYVUK.js";
26
26
  export {
27
27
  formatColumnMethod,
28
28
  formatForeignKey,
package/dist/plugin.cjs CHANGED
@@ -28,8 +28,10 @@ var import_node_fs = require("fs");
28
28
  var import_node_path = require("path");
29
29
 
30
30
  // src/migration/schema-builder.ts
31
+ var import_omnify_types = require("@famgia/omnify-types");
31
32
  var TYPE_METHOD_MAP = {
32
33
  String: "string",
34
+ TinyInt: "tinyInteger",
33
35
  Int: "integer",
34
36
  BigInt: "bigInteger",
35
37
  Float: "double",
@@ -44,7 +46,9 @@ var TYPE_METHOD_MAP = {
44
46
  Json: "json",
45
47
  Email: "string",
46
48
  Password: "string",
47
- Enum: "enum"
49
+ Enum: "enum",
50
+ EnumRef: "string"
51
+ // EnumRef stores the enum value as string (lookup via schema)
48
52
  // Note: File type is now polymorphic - no column generated, uses files table
49
53
  };
50
54
  var PK_METHOD_MAP = {
@@ -72,7 +76,7 @@ function toTableName(schemaName) {
72
76
  return snakeCase + "s";
73
77
  }
74
78
  }
75
- function propertyToColumnMethod(propertyName, property) {
79
+ function propertyToColumnMethod(propertyName, property, options = {}) {
76
80
  if (property.type === "Association") {
77
81
  return null;
78
82
  }
@@ -86,6 +90,8 @@ function propertyToColumnMethod(propertyName, property) {
86
90
  const propWithLength = property;
87
91
  if (method === "string" && propWithLength.length) {
88
92
  args.push(propWithLength.length);
93
+ } else if (property.type === "EnumRef") {
94
+ args.push(50);
89
95
  }
90
96
  if (property.type === "Decimal") {
91
97
  const decimalProp = property;
@@ -109,12 +115,15 @@ function propertyToColumnMethod(propertyName, property) {
109
115
  if (baseProp.default !== void 0 && baseProp.default !== null) {
110
116
  modifiers.push({ method: "default", args: [baseProp.default] });
111
117
  }
112
- if (baseProp.unsigned && (method === "integer" || method === "bigInteger")) {
118
+ if (baseProp.unsigned && (method === "tinyInteger" || method === "integer" || method === "bigInteger")) {
113
119
  modifiers.push({ method: "unsigned" });
114
120
  }
115
- const displayName = property.displayName;
116
- if (displayName) {
117
- modifiers.push({ method: "comment", args: [displayName] });
121
+ const rawDisplayName = property.displayName;
122
+ if (rawDisplayName) {
123
+ const displayName = (0, import_omnify_types.resolveLocalizedString)(rawDisplayName, options.locale);
124
+ if (displayName) {
125
+ modifiers.push({ method: "comment", args: [displayName] });
126
+ }
118
127
  }
119
128
  return {
120
129
  name: columnName,
@@ -220,7 +229,7 @@ function generatePolymorphicColumns(propertyName, property, allSchemas) {
220
229
  ];
221
230
  return { typeColumn, idColumn, indexes };
222
231
  }
223
- function generateForeignKey(propertyName, property, allSchemas) {
232
+ function generateForeignKey(propertyName, property, allSchemas, options = {}) {
224
233
  if (property.type !== "Association") {
225
234
  return null;
226
235
  }
@@ -251,7 +260,10 @@ function generateForeignKey(propertyName, property, allSchemas) {
251
260
  modifiers.push({ method: "default", args: [assocProp.default] });
252
261
  }
253
262
  if (assocProp.displayName) {
254
- modifiers.push({ method: "comment", args: [assocProp.displayName] });
263
+ const displayName = (0, import_omnify_types.resolveLocalizedString)(assocProp.displayName, options.locale);
264
+ if (displayName) {
265
+ modifiers.push({ method: "comment", args: [displayName] });
266
+ }
255
267
  }
256
268
  const column = {
257
269
  name: columnName,
@@ -272,7 +284,7 @@ function generateForeignKey(propertyName, property, allSchemas) {
272
284
  };
273
285
  return { column, foreignKey, index };
274
286
  }
275
- function expandCompoundType(propName, property, customTypes) {
287
+ function expandCompoundType(propName, property, customTypes, options = {}) {
276
288
  const typeDef = customTypes.get(property.type);
277
289
  if (!typeDef || !typeDef.compound || !typeDef.expand) {
278
290
  return null;
@@ -286,13 +298,26 @@ function expandCompoundType(propName, property, customTypes) {
286
298
  type: "String"
287
299
  // Default type, will be overridden by sql definition
288
300
  };
289
- if (field.sql) {
301
+ const fieldOverrides = baseProp.fields;
302
+ const fieldOverride = fieldOverrides?.[field.suffix];
303
+ const fieldWithEnumRef = field;
304
+ if (fieldWithEnumRef.enumRef) {
305
+ expandedProp.type = "EnumRef";
306
+ expandedProp.enum = fieldWithEnumRef.enumRef;
307
+ if (fieldOverride?.nullable !== void 0) {
308
+ expandedProp.nullable = fieldOverride.nullable;
309
+ } else if (baseProp.nullable !== void 0) {
310
+ expandedProp.nullable = baseProp.nullable;
311
+ }
312
+ } else if (field.sql) {
290
313
  const sqlType = field.sql.sqlType.toUpperCase();
291
314
  if (sqlType === "VARCHAR" || sqlType === "CHAR" || sqlType === "STRING") {
292
315
  expandedProp.type = "String";
293
316
  if (field.sql.length) {
294
317
  expandedProp.length = field.sql.length;
295
318
  }
319
+ } else if (sqlType === "TINYINT") {
320
+ expandedProp.type = "TinyInt";
296
321
  } else if (sqlType === "INT" || sqlType === "INTEGER") {
297
322
  expandedProp.type = "Int";
298
323
  } else if (sqlType === "BIGINT") {
@@ -310,17 +335,29 @@ function expandCompoundType(propName, property, customTypes) {
310
335
  } else if (sqlType === "TIMESTAMP" || sqlType === "DATETIME") {
311
336
  expandedProp.type = "Timestamp";
312
337
  }
338
+ if (field.sql.unsigned) {
339
+ expandedProp.unsigned = true;
340
+ }
341
+ if (field.sql.default !== void 0) {
342
+ expandedProp.default = field.sql.default;
343
+ }
313
344
  if (field.sql.nullable !== void 0) {
314
345
  expandedProp.nullable = field.sql.nullable;
315
346
  } else if (baseProp.nullable !== void 0) {
316
347
  expandedProp.nullable = baseProp.nullable;
317
348
  }
318
- if (field.sql.default !== void 0) {
319
- expandedProp.default = field.sql.default;
349
+ if (fieldOverride?.nullable !== void 0) {
350
+ expandedProp.nullable = fieldOverride.nullable;
320
351
  }
321
352
  }
322
353
  if (baseProp.displayName) {
323
- expandedProp.displayName = `${baseProp.displayName} (${field.suffix})`;
354
+ const resolvedDisplayName = (0, import_omnify_types.resolveLocalizedString)(
355
+ baseProp.displayName,
356
+ options.locale
357
+ );
358
+ if (resolvedDisplayName) {
359
+ expandedProp.displayName = `${resolvedDisplayName} (${field.suffix})`;
360
+ }
324
361
  }
325
362
  expanded.push({
326
363
  name: columnName,
@@ -330,7 +367,8 @@ function expandCompoundType(propName, property, customTypes) {
330
367
  return expanded;
331
368
  }
332
369
  function schemaToBlueprint(schema, allSchemas, options = {}) {
333
- const { customTypes = /* @__PURE__ */ new Map() } = options;
370
+ const { customTypes = /* @__PURE__ */ new Map(), locale } = options;
371
+ const columnOptions = { locale };
334
372
  const tableName = toTableName(schema.name);
335
373
  const columns = [];
336
374
  const foreignKeys = [];
@@ -341,21 +379,21 @@ function schemaToBlueprint(schema, allSchemas, options = {}) {
341
379
  }
342
380
  if (schema.properties) {
343
381
  for (const [propName, property] of Object.entries(schema.properties)) {
344
- const expandedProps = expandCompoundType(propName, property, customTypes);
382
+ const expandedProps = expandCompoundType(propName, property, customTypes, columnOptions);
345
383
  if (expandedProps) {
346
384
  for (const { name: expandedName, property: expandedProp } of expandedProps) {
347
- const columnMethod2 = propertyToColumnMethod(expandedName, expandedProp);
385
+ const columnMethod2 = propertyToColumnMethod(expandedName, expandedProp, columnOptions);
348
386
  if (columnMethod2) {
349
387
  columns.push(columnMethod2);
350
388
  }
351
389
  }
352
390
  continue;
353
391
  }
354
- const columnMethod = propertyToColumnMethod(propName, property);
392
+ const columnMethod = propertyToColumnMethod(propName, property, columnOptions);
355
393
  if (columnMethod) {
356
394
  columns.push(columnMethod);
357
395
  }
358
- const fkResult = generateForeignKey(propName, property, allSchemas);
396
+ const fkResult = generateForeignKey(propName, property, allSchemas, columnOptions);
359
397
  if (fkResult) {
360
398
  columns.push(fkResult.column);
361
399
  foreignKeys.push(fkResult.foreignKey);
@@ -758,7 +796,8 @@ function generateMigrations(schemas, options = {}) {
758
796
  const offsetTimestamp = incrementTimestamp(timestamp, timestampOffset);
759
797
  timestampOffset++;
760
798
  const blueprint = schemaToBlueprint(schema, schemas, {
761
- customTypes: options.customTypes
799
+ customTypes: options.customTypes,
800
+ locale: options.locale
762
801
  });
763
802
  const migration = generateCreateMigration(blueprint, {
764
803
  ...options,
@@ -1098,7 +1137,7 @@ function generateMigrationsFromChanges(changes, options = {}) {
1098
1137
  }
1099
1138
 
1100
1139
  // src/model/generator.ts
1101
- var import_omnify_types = require("@famgia/omnify-types");
1140
+ var import_omnify_types2 = require("@famgia/omnify-types");
1102
1141
 
1103
1142
  // src/utils.ts
1104
1143
  function toSnakeCase(str) {
@@ -1127,7 +1166,8 @@ var DEFAULT_OPTIONS = {
1127
1166
  modelNamespace: "App\\Models",
1128
1167
  baseModelClassName: "BaseModel",
1129
1168
  baseModelPath: "app/Models/OmnifyBase",
1130
- modelPath: "app/Models"
1169
+ modelPath: "app/Models",
1170
+ customTypes: /* @__PURE__ */ new Map()
1131
1171
  };
1132
1172
  function generateLocalizedDisplayNames(displayName, indent = " ") {
1133
1173
  if (displayName === void 0) {
@@ -1136,7 +1176,7 @@ function generateLocalizedDisplayNames(displayName, indent = " ") {
1136
1176
  if (typeof displayName === "string") {
1137
1177
  return `${indent}'en' => '${escapePhpString(displayName)}',`;
1138
1178
  }
1139
- if ((0, import_omnify_types.isLocaleMap)(displayName)) {
1179
+ if ((0, import_omnify_types2.isLocaleMap)(displayName)) {
1140
1180
  const entries = Object.entries(displayName).map(([locale, value]) => `${indent}'${locale}' => '${escapePhpString(value)}',`).join("\n");
1141
1181
  return entries;
1142
1182
  }
@@ -1156,7 +1196,7 @@ function generatePropertyLocalizedDisplayNames(schema, indent = " ") {
1156
1196
  entries.push(`${indent}'${snakeName}' => [
1157
1197
  ${innerIndent}'en' => '${escapePhpString(displayName)}',
1158
1198
  ${indent}],`);
1159
- } else if ((0, import_omnify_types.isLocaleMap)(displayName)) {
1199
+ } else if ((0, import_omnify_types2.isLocaleMap)(displayName)) {
1160
1200
  const localeEntries = Object.entries(displayName).map(([locale, value]) => `${innerIndent}'${locale}' => '${escapePhpString(value)}',`).join("\n");
1161
1201
  entries.push(`${indent}'${snakeName}' => [
1162
1202
  ${localeEntries}
@@ -1174,7 +1214,8 @@ function resolveOptions(options) {
1174
1214
  modelNamespace: options?.modelNamespace ?? DEFAULT_OPTIONS.modelNamespace,
1175
1215
  baseModelClassName: options?.baseModelClassName ?? DEFAULT_OPTIONS.baseModelClassName,
1176
1216
  baseModelPath: options?.baseModelPath ?? DEFAULT_OPTIONS.baseModelPath,
1177
- modelPath: options?.modelPath ?? DEFAULT_OPTIONS.modelPath
1217
+ modelPath: options?.modelPath ?? DEFAULT_OPTIONS.modelPath,
1218
+ customTypes: options?.customTypes ?? /* @__PURE__ */ new Map()
1178
1219
  };
1179
1220
  }
1180
1221
  function getCastType(propDef) {
@@ -1305,7 +1346,10 @@ function generateEntityBaseModel(schema, schemas, options, stubContent, authStub
1305
1346
  }
1306
1347
  }
1307
1348
  } else if (propDef.type === "Password") {
1308
- fillable.push(` '${snakeName}',`);
1349
+ const propWithFillable = propDef;
1350
+ if (propWithFillable.fillable !== false) {
1351
+ fillable.push(` '${snakeName}',`);
1352
+ }
1309
1353
  hidden.push(` '${snakeName}',`);
1310
1354
  const cast = getCastType(propDef);
1311
1355
  if (cast) {
@@ -1315,10 +1359,58 @@ function generateEntityBaseModel(schema, schemas, options, stubContent, authStub
1315
1359
  const relMethod = generateFileRelation(propName, propDef);
1316
1360
  relations.push(relMethod);
1317
1361
  } else {
1318
- fillable.push(` '${snakeName}',`);
1319
- const cast = getCastType(propDef);
1320
- if (cast) {
1321
- casts.push(` '${snakeName}' => '${cast}',`);
1362
+ const propWithOptions = propDef;
1363
+ const isFillable = propWithOptions.fillable !== false;
1364
+ const isHidden = propWithOptions.hidden === true;
1365
+ const typeDef = options.customTypes.get(propDef.type);
1366
+ const isCompoundType = typeDef?.compound && typeDef.expand;
1367
+ if (isCompoundType && typeDef.expand) {
1368
+ const fieldOverrides = propWithOptions.fields ?? {};
1369
+ for (const field of typeDef.expand) {
1370
+ const suffixSnake = toSnakeCase(field.suffix);
1371
+ const fieldName = `${snakeName}_${suffixSnake}`;
1372
+ const override = fieldOverrides[field.suffix];
1373
+ const fieldFillable = override?.fillable !== void 0 ? override.fillable : isFillable;
1374
+ if (fieldFillable) {
1375
+ fillable.push(` '${fieldName}',`);
1376
+ }
1377
+ const fieldHidden = override?.hidden !== void 0 ? override.hidden : isHidden;
1378
+ if (fieldHidden) {
1379
+ hidden.push(` '${fieldName}',`);
1380
+ }
1381
+ }
1382
+ } else {
1383
+ if (isFillable) {
1384
+ fillable.push(` '${snakeName}',`);
1385
+ }
1386
+ const cast = getCastType(propDef);
1387
+ if (cast) {
1388
+ casts.push(` '${snakeName}' => '${cast}',`);
1389
+ }
1390
+ if (isHidden) {
1391
+ hidden.push(` '${snakeName}',`);
1392
+ }
1393
+ }
1394
+ if (typeDef?.compound && typeDef.accessors) {
1395
+ for (const accessor of typeDef.accessors) {
1396
+ const accessorName = `${snakeName}_${toSnakeCase(accessor.name)}`;
1397
+ appends.push(` '${accessorName}',`);
1398
+ const methodName = toPascalCase(accessorName);
1399
+ const separator = accessor.separator ?? " ";
1400
+ const fieldRefs = accessor.fields.map((field) => {
1401
+ const fieldName = `${snakeName}_${toSnakeCase(field)}`;
1402
+ return `$this->${fieldName}`;
1403
+ });
1404
+ const accessorMethod = ` /**
1405
+ * Get the ${accessor.name.replace(/_/g, " ")} attribute.
1406
+ */
1407
+ public function get${methodName}Attribute(): ?string
1408
+ {
1409
+ $parts = array_filter([${fieldRefs.join(", ")}], fn($v) => $v !== null && $v !== '');
1410
+ return count($parts) > 0 ? implode('${separator}', $parts) : null;
1411
+ }`;
1412
+ relations.push(accessorMethod);
1413
+ }
1322
1414
  }
1323
1415
  }
1324
1416
  }
@@ -2525,7 +2617,8 @@ function laravelPlugin(options) {
2525
2617
  modelNamespace: resolved.modelNamespace,
2526
2618
  baseModelNamespace: resolved.baseModelNamespace,
2527
2619
  modelPath: resolved.modelsPath,
2528
- baseModelPath: resolved.baseModelsPath
2620
+ baseModelPath: resolved.baseModelsPath,
2621
+ customTypes: ctx.customTypes
2529
2622
  };
2530
2623
  const models = generateModels(ctx.schemas, modelOptions);
2531
2624
  const outputs = models.map((model) => ({