@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/plugin.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugin.ts","../src/migration/schema-builder.ts","../src/migration/generator.ts"],"sourcesContent":["/**\n * @famgia/omnify-laravel - Plugin\n *\n * Plugin for generating Laravel migration files from Omnify schemas.\n *\n * @example\n * ```typescript\n * import { defineConfig } from '@famgia/omnify';\n * import laravel from '@famgia/omnify-laravel/plugin';\n *\n * export default defineConfig({\n * plugins: [\n * laravel({\n * migrationsPath: 'database/migrations',\n * connection: 'mysql',\n * }),\n * ],\n * });\n * ```\n */\n\nimport type { OmnifyPlugin, GeneratorOutput, GeneratorContext, PluginConfigSchema } from '@famgia/omnify-types';\nimport { generateMigrations, getMigrationPath, type MigrationOptions } from './migration/index.js';\n\n/**\n * Configuration schema for Laravel plugin UI settings\n */\nconst LARAVEL_CONFIG_SCHEMA: PluginConfigSchema = {\n fields: [\n {\n key: 'migrationsPath',\n type: 'path',\n label: 'Migrations Path',\n description: 'Directory for Laravel migration files',\n default: 'database/migrations',\n group: 'output',\n },\n {\n key: 'connection',\n type: 'string',\n label: 'Database Connection',\n description: 'Laravel database connection name (optional)',\n placeholder: 'mysql',\n group: 'options',\n },\n ],\n};\n\n/**\n * Options for the Laravel plugin.\n */\nexport interface LaravelPluginOptions {\n /**\n * Path for Laravel migration files.\n * @default 'database/migrations'\n */\n migrationsPath?: string;\n\n /**\n * Database connection name for migrations.\n */\n connection?: string;\n\n /**\n * Custom timestamp for migration file names (mainly for testing).\n */\n timestamp?: string;\n}\n\n/**\n * Resolved options with defaults applied.\n */\ninterface ResolvedOptions {\n migrationsPath: string;\n connection: string | undefined;\n timestamp: string | undefined;\n}\n\n/**\n * Resolves options with defaults.\n */\nfunction resolveOptions(options?: LaravelPluginOptions): ResolvedOptions {\n return {\n migrationsPath: options?.migrationsPath ?? 'database/migrations',\n connection: options?.connection,\n timestamp: options?.timestamp,\n };\n}\n\n/**\n * Creates the Laravel plugin with the specified options.\n *\n * @param options - Plugin configuration options\n * @returns OmnifyPlugin configured for Laravel migrations\n */\nexport default function laravelPlugin(options?: LaravelPluginOptions): OmnifyPlugin {\n const resolved = resolveOptions(options);\n\n return {\n name: '@famgia/omnify-laravel',\n version: '0.0.13',\n configSchema: LARAVEL_CONFIG_SCHEMA,\n\n generators: [\n {\n name: 'laravel-migrations',\n description: 'Generate Laravel migration files',\n\n generate: async (ctx: GeneratorContext): Promise<GeneratorOutput[]> => {\n const migrationOptions: MigrationOptions = {\n connection: resolved.connection,\n timestamp: resolved.timestamp,\n };\n\n const migrations = generateMigrations(ctx.schemas, migrationOptions);\n\n return migrations.map((migration) => ({\n path: getMigrationPath(migration, resolved.migrationsPath),\n content: migration.content,\n type: 'migration' as const,\n metadata: {\n tableName: migration.tables[0],\n migrationType: migration.type,\n },\n }));\n },\n },\n ],\n };\n}\n\n// Named export for flexibility\nexport { laravelPlugin };\n","/**\n * @famgia/omnify-laravel - Schema Builder Converter\n *\n * Converts SQL types and operations to Laravel Schema Builder methods.\n */\n\nimport type { PropertyDefinition, LoadedSchema, SchemaCollection } from '@famgia/omnify-types';\nimport type {\n ColumnMethod,\n ColumnModifier,\n ForeignKeyDefinition,\n IndexDefinition,\n TableBlueprint,\n} from './types.js';\n\n/**\n * Maps Omnify property types to Laravel column methods.\n */\nconst TYPE_METHOD_MAP: Record<string, string> = {\n String: 'string',\n Int: 'integer',\n BigInt: 'bigInteger',\n Float: 'double',\n Decimal: 'decimal',\n Boolean: 'boolean',\n Text: 'text',\n LongText: 'longText',\n Date: 'date',\n Time: 'time',\n Timestamp: 'timestamp',\n Json: 'json',\n Email: 'string',\n Password: 'string',\n Enum: 'enum',\n // Note: File type is now polymorphic - no column generated, uses files table\n};\n\n/**\n * Maps primary key types to Laravel methods.\n */\nconst PK_METHOD_MAP: Record<string, string> = {\n Int: 'increments',\n BigInt: 'bigIncrements',\n Uuid: 'uuid',\n String: 'string',\n};\n\n/**\n * Gets the ID type from schema options.\n */\nfunction getIdType(schema: LoadedSchema): 'Int' | 'BigInt' | 'Uuid' | 'String' {\n return (schema.options?.idType ?? 'BigInt') as 'Int' | 'BigInt' | 'Uuid' | 'String';\n}\n\n/**\n * Checks if the schema should have an auto-generated ID column.\n * Returns false if options.id is explicitly set to false.\n */\nfunction hasAutoId(schema: LoadedSchema): boolean {\n return schema.options?.id !== false;\n}\n\n/**\n * Converts a property name to snake_case column name.\n */\nexport function toColumnName(propertyName: string): string {\n return propertyName.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\n}\n\n/**\n * Converts schema name to snake_case plural table name.\n */\nexport function toTableName(schemaName: string): string {\n const snakeCase = schemaName\n .replace(/([A-Z])/g, '_$1')\n .toLowerCase()\n .replace(/^_/, '');\n\n // Simple pluralization\n if (snakeCase.endsWith('y')) {\n return snakeCase.slice(0, -1) + 'ies';\n } else if (\n snakeCase.endsWith('s') ||\n snakeCase.endsWith('x') ||\n snakeCase.endsWith('ch') ||\n snakeCase.endsWith('sh')\n ) {\n return snakeCase + 'es';\n } else {\n return snakeCase + 's';\n }\n}\n\n/**\n * Converts a property to Laravel column method.\n */\nexport function propertyToColumnMethod(\n propertyName: string,\n property: PropertyDefinition\n): ColumnMethod | null {\n // Skip associations - they're handled separately\n if (property.type === 'Association') {\n return null;\n }\n\n // Skip File type - uses polymorphic relation to files table\n if (property.type === 'File') {\n return null;\n }\n\n const columnName = toColumnName(propertyName);\n const method = TYPE_METHOD_MAP[property.type] ?? 'string';\n const args: (string | number | boolean)[] = [columnName];\n const modifiers: ColumnModifier[] = [];\n\n // Handle length for string types\n const propWithLength = property as { length?: number };\n if (method === 'string' && propWithLength.length) {\n args.push(propWithLength.length);\n }\n\n // Handle precision and scale for decimal types\n if (property.type === 'Decimal') {\n const decimalProp = property as { precision?: number; scale?: number };\n const precision = decimalProp.precision ?? 8;\n const scale = decimalProp.scale ?? 2;\n args.push(precision, scale);\n }\n\n // Handle enum values\n if (property.type === 'Enum') {\n const enumProp = property as { enum?: readonly string[] };\n if (enumProp.enum && enumProp.enum.length > 0) {\n args.push(enumProp.enum as unknown as string);\n }\n }\n\n // Add modifiers\n const baseProp = property as {\n nullable?: boolean;\n unique?: boolean;\n default?: unknown;\n unsigned?: boolean;\n };\n\n if (baseProp.nullable) {\n modifiers.push({ method: 'nullable' });\n }\n\n if (baseProp.unique) {\n modifiers.push({ method: 'unique' });\n }\n\n if (baseProp.default !== undefined) {\n const defaultValue = typeof baseProp.default === 'string'\n ? baseProp.default\n : JSON.stringify(baseProp.default);\n modifiers.push({ method: 'default', args: [defaultValue] });\n }\n\n if (baseProp.unsigned && (method === 'integer' || method === 'bigInteger')) {\n modifiers.push({ method: 'unsigned' });\n }\n\n return {\n name: columnName,\n method,\n args,\n modifiers,\n };\n}\n\n/**\n * Generates primary key column method.\n */\nexport function generatePrimaryKeyColumn(\n pkType: 'Int' | 'BigInt' | 'Uuid' | 'String' = 'BigInt'\n): ColumnMethod {\n const method = PK_METHOD_MAP[pkType] ?? 'bigIncrements';\n\n if (pkType === 'Uuid') {\n return {\n name: 'id',\n method: 'uuid',\n args: ['id'],\n modifiers: [{ method: 'primary' }],\n };\n }\n\n if (pkType === 'String') {\n return {\n name: 'id',\n method: 'string',\n args: ['id', 255],\n modifiers: [{ method: 'primary' }],\n };\n }\n\n // For Int/BigInt, use increments which auto-creates primary key\n return {\n name: 'id',\n method,\n args: ['id'],\n modifiers: [],\n };\n}\n\n/**\n * Generates timestamp columns.\n */\nexport function generateTimestampColumns(): ColumnMethod[] {\n return [\n {\n name: 'created_at',\n method: 'timestamp',\n args: ['created_at'],\n modifiers: [{ method: 'nullable' }],\n },\n {\n name: 'updated_at',\n method: 'timestamp',\n args: ['updated_at'],\n modifiers: [{ method: 'nullable' }],\n },\n ];\n}\n\n/**\n * Generates soft delete column.\n */\nexport function generateSoftDeleteColumn(): ColumnMethod {\n return {\n name: 'deleted_at',\n method: 'timestamp',\n args: ['deleted_at'],\n modifiers: [{ method: 'nullable' }],\n };\n}\n\n/**\n * Polymorphic column result with type enum and id column.\n */\nexport interface PolymorphicColumnsResult {\n typeColumn: ColumnMethod;\n idColumn: ColumnMethod;\n indexes: IndexDefinition[];\n}\n\n/**\n * Generates polymorphic columns for MorphTo relations.\n * Creates {name}_type (ENUM) and {name}_id columns.\n */\nexport function generatePolymorphicColumns(\n propertyName: string,\n property: PropertyDefinition,\n allSchemas: SchemaCollection\n): PolymorphicColumnsResult | null {\n if (property.type !== 'Association') {\n return null;\n }\n\n const assocProp = property as {\n relation?: string;\n targets?: readonly string[];\n };\n\n // Only handle MorphTo - it creates the type and id columns\n if (assocProp.relation !== 'MorphTo') {\n return null;\n }\n\n const targets = assocProp.targets;\n if (!targets || targets.length === 0) {\n return null;\n }\n\n const columnBaseName = toColumnName(propertyName);\n const typeColumnName = `${columnBaseName}_type`;\n const idColumnName = `${columnBaseName}_id`;\n\n // Generate ENUM type column with target schema names as values\n const typeColumn: ColumnMethod = {\n name: typeColumnName,\n method: 'enum',\n args: [typeColumnName, targets as unknown as string],\n modifiers: [{ method: 'nullable' }],\n };\n\n // For polymorphic id, we need to determine the largest ID type among targets\n // Default to unsignedBigInteger for maximum compatibility\n let idMethod = 'unsignedBigInteger';\n\n // Check if any target uses UUID or String - those take precedence\n for (const targetName of targets) {\n const targetSchema = allSchemas[targetName];\n if (targetSchema) {\n const targetIdType = (targetSchema.options?.idType ?? 'BigInt') as string;\n if (targetIdType === 'Uuid') {\n idMethod = 'uuid';\n break; // UUID takes highest precedence\n } else if (targetIdType === 'String') {\n idMethod = 'string';\n // Don't break - UUID still takes precedence\n }\n }\n }\n\n const idColumn: ColumnMethod = {\n name: idColumnName,\n method: idMethod,\n args: idMethod === 'string' ? [idColumnName, 255] : [idColumnName],\n modifiers: [{ method: 'nullable' }],\n };\n\n // Create composite index for faster polymorphic lookups\n const indexes: IndexDefinition[] = [\n {\n columns: [typeColumnName, idColumnName],\n unique: false,\n },\n ];\n\n return { typeColumn, idColumn, indexes };\n}\n\n/**\n * Generates foreign key column and constraint from association.\n */\nexport function generateForeignKey(\n propertyName: string,\n property: PropertyDefinition,\n allSchemas: SchemaCollection\n): { column: ColumnMethod; foreignKey: ForeignKeyDefinition; index: IndexDefinition } | null {\n if (property.type !== 'Association') {\n return null;\n }\n\n const assocProp = property as {\n relation?: string;\n target?: string;\n onDelete?: string;\n onUpdate?: string;\n mappedBy?: string;\n owningSide?: boolean;\n };\n\n // Only create FK column for ManyToOne and OneToOne (owning side)\n if (assocProp.relation !== 'ManyToOne' && assocProp.relation !== 'OneToOne') {\n return null;\n }\n\n // Skip inverse side (mappedBy means this is the inverse side)\n if (assocProp.mappedBy) {\n return null;\n }\n\n const columnName = toColumnName(propertyName) + '_id';\n const targetSchema = assocProp.target ? allSchemas[assocProp.target] : undefined;\n const targetTable = assocProp.target ? toTableName(assocProp.target) : 'unknown';\n const targetPkType = targetSchema ? getIdType(targetSchema) : 'BigInt';\n\n // Determine column method based on target PK type\n let method = 'unsignedBigInteger';\n if (targetPkType === 'Int') {\n method = 'unsignedInteger';\n } else if (targetPkType === 'Uuid') {\n method = 'uuid';\n } else if (targetPkType === 'String') {\n method = 'string';\n }\n\n const column: ColumnMethod = {\n name: columnName,\n method,\n args: [columnName],\n modifiers: assocProp.relation === 'ManyToOne' ? [{ method: 'nullable' }] : [],\n };\n\n const foreignKey: ForeignKeyDefinition = {\n columns: [columnName],\n references: 'id',\n on: [targetTable],\n onDelete: assocProp.onDelete ?? 'restrict',\n onUpdate: assocProp.onUpdate ?? 'cascade',\n };\n\n // Don't specify index name - let Laravel auto-generate unique names\n const index: IndexDefinition = {\n columns: [columnName],\n unique: false,\n };\n\n return { column, foreignKey, index };\n}\n\n/**\n * Generates table blueprint from schema.\n */\nexport function schemaToBlueprint(\n schema: LoadedSchema,\n allSchemas: SchemaCollection\n): TableBlueprint {\n const tableName = toTableName(schema.name);\n const columns: ColumnMethod[] = [];\n const foreignKeys: ForeignKeyDefinition[] = [];\n const indexes: IndexDefinition[] = [];\n\n // Primary key (only if id is not disabled)\n if (hasAutoId(schema)) {\n const pkType = getIdType(schema);\n columns.push(generatePrimaryKeyColumn(pkType));\n }\n\n // Process properties\n if (schema.properties) {\n for (const [propName, property] of Object.entries(schema.properties)) {\n // Handle regular columns\n const columnMethod = propertyToColumnMethod(propName, property);\n if (columnMethod) {\n columns.push(columnMethod);\n }\n\n // Handle foreign keys (standard associations)\n const fkResult = generateForeignKey(propName, property, allSchemas);\n if (fkResult) {\n columns.push(fkResult.column);\n foreignKeys.push(fkResult.foreignKey);\n indexes.push(fkResult.index);\n }\n\n // Handle polymorphic columns (MorphTo)\n const polyResult = generatePolymorphicColumns(propName, property, allSchemas);\n if (polyResult) {\n columns.push(polyResult.typeColumn);\n columns.push(polyResult.idColumn);\n indexes.push(...polyResult.indexes);\n }\n }\n }\n\n // Timestamps\n if (schema.options?.timestamps !== false) {\n columns.push(...generateTimestampColumns());\n }\n\n // Soft delete\n if (schema.options?.softDelete) {\n columns.push(generateSoftDeleteColumn());\n }\n\n // Custom indexes\n if (schema.options?.indexes) {\n for (const index of schema.options.indexes) {\n indexes.push({\n name: index.name,\n columns: index.columns.map(toColumnName),\n unique: index.unique ?? false,\n });\n }\n }\n\n // Unique constraints\n if (schema.options?.unique) {\n const uniqueConstraints = Array.isArray(schema.options.unique[0])\n ? (schema.options.unique as readonly (readonly string[])[])\n : [schema.options.unique as readonly string[]];\n\n for (const constraint of uniqueConstraints) {\n indexes.push({\n columns: constraint.map(toColumnName),\n unique: true,\n });\n }\n }\n\n return {\n tableName,\n columns,\n primaryKey: ['id'],\n foreignKeys,\n indexes,\n };\n}\n\n/**\n * Formats a column method to PHP code.\n */\nexport function formatColumnMethod(column: ColumnMethod): string {\n const args = column.args.map(arg => {\n if (typeof arg === 'string') {\n return `'${arg}'`;\n }\n if (Array.isArray(arg)) {\n return `[${(arg as string[]).map(v => `'${v}'`).join(', ')}]`;\n }\n return String(arg);\n }).join(', ');\n\n let code = `$table->${column.method}(${args})`;\n\n for (const modifier of column.modifiers) {\n if (modifier.args && modifier.args.length > 0) {\n const modArgs = modifier.args.map(arg => {\n if (typeof arg === 'string') {\n return `'${arg}'`;\n }\n return String(arg);\n }).join(', ');\n code += `->${modifier.method}(${modArgs})`;\n } else {\n code += `->${modifier.method}()`;\n }\n }\n\n return code + ';';\n}\n\n/**\n * Formats a foreign key to PHP code.\n */\nexport function formatForeignKey(fk: ForeignKeyDefinition): string {\n const column = fk.columns[0];\n const table = fk.on[0];\n let code = `$table->foreign('${column}')->references('${fk.references}')->on('${table}')`;\n\n if (fk.onDelete) {\n code += `->onDelete('${fk.onDelete}')`;\n }\n if (fk.onUpdate) {\n code += `->onUpdate('${fk.onUpdate}')`;\n }\n\n return code + ';';\n}\n\n/**\n * Formats an index to PHP code.\n */\nexport function formatIndex(index: IndexDefinition): string {\n const columns = index.columns.length === 1\n ? `'${index.columns[0]}'`\n : `[${index.columns.map(c => `'${c}'`).join(', ')}]`;\n\n const method = index.unique ? 'unique' : 'index';\n const name = index.name ? `, '${index.name}'` : '';\n\n return `$table->${method}(${columns}${name});`;\n}\n\n/**\n * Pivot table information for ManyToMany relationships.\n */\nexport interface PivotTableInfo {\n tableName: string;\n sourceTable: string;\n targetTable: string;\n sourceColumn: string;\n targetColumn: string;\n sourcePkType: 'Int' | 'BigInt' | 'Uuid' | 'String';\n targetPkType: 'Int' | 'BigInt' | 'Uuid' | 'String';\n onDelete: string | undefined;\n onUpdate: string | undefined;\n}\n\n/**\n * Polymorphic pivot table information for MorphToMany relationships.\n */\nexport interface MorphToManyPivotInfo {\n tableName: string;\n /** The fixed target schema that uses MorphToMany */\n targetTable: string;\n targetColumn: string;\n targetPkType: 'Int' | 'BigInt' | 'Uuid' | 'String';\n /** Base name for polymorphic columns (creates {name}_type and {name}_id) */\n morphName: string;\n /** Schema names that can be morphed to */\n morphTargets: readonly string[];\n onDelete: string | undefined;\n onUpdate: string | undefined;\n}\n\n/**\n * Generates pivot table name for ManyToMany relationship.\n * Uses alphabetical ordering for consistency.\n */\nexport function generatePivotTableName(\n sourceTable: string,\n targetTable: string,\n customName?: string\n): string {\n if (customName) {\n return customName;\n }\n\n // Sort alphabetically for consistent naming\n const tables = [sourceTable, targetTable].sort();\n // Remove trailing 's' and join with underscore\n const singular1 = tables[0]!.replace(/ies$/, 'y').replace(/s$/, '');\n const singular2 = tables[1]!.replace(/ies$/, 'y').replace(/s$/, '');\n return `${singular1}_${singular2}`;\n}\n\n/**\n * Extracts ManyToMany relationships from a schema.\n */\nexport function extractManyToManyRelations(\n schema: LoadedSchema,\n allSchemas: SchemaCollection\n): PivotTableInfo[] {\n const pivotTables: PivotTableInfo[] = [];\n\n if (!schema.properties) {\n return pivotTables;\n }\n\n const sourceTable = toTableName(schema.name);\n const sourcePkType = getIdType(schema);\n\n for (const [, property] of Object.entries(schema.properties)) {\n if (property.type !== 'Association') {\n continue;\n }\n\n const assocProp = property as {\n relation?: string;\n target?: string;\n joinTable?: string;\n onDelete?: string;\n onUpdate?: string;\n owning?: boolean;\n };\n\n // Only handle ManyToMany on the owning side (or if not specified, use alphabetical order)\n if (assocProp.relation !== 'ManyToMany') {\n continue;\n }\n\n const targetName = assocProp.target;\n if (!targetName) {\n continue;\n }\n\n const targetSchema = allSchemas[targetName];\n const targetTable = toTableName(targetName);\n const targetPkType = targetSchema ? getIdType(targetSchema) : 'BigInt';\n\n // Determine if this side owns the relationship\n // Default: alphabetically first schema owns it\n const isOwningSide = assocProp.owning ?? (schema.name < targetName);\n\n if (!isOwningSide) {\n continue; // Skip non-owning side to avoid duplicate pivot tables\n }\n\n const pivotTableName = generatePivotTableName(sourceTable, targetTable, assocProp.joinTable);\n\n // Column names: singular form of table name + _id\n const sourceColumn = sourceTable.replace(/ies$/, 'y').replace(/s$/, '') + '_id';\n const targetColumn = targetTable.replace(/ies$/, 'y').replace(/s$/, '') + '_id';\n\n pivotTables.push({\n tableName: pivotTableName,\n sourceTable,\n targetTable,\n sourceColumn,\n targetColumn,\n sourcePkType,\n targetPkType,\n onDelete: assocProp.onDelete,\n onUpdate: assocProp.onUpdate,\n });\n }\n\n return pivotTables;\n}\n\n/**\n * Generates blueprint for a pivot table.\n */\nexport function generatePivotTableBlueprint(pivot: PivotTableInfo): TableBlueprint {\n const columns: ColumnMethod[] = [];\n const foreignKeys: ForeignKeyDefinition[] = [];\n const indexes: IndexDefinition[] = [];\n\n // Determine column methods based on PK types\n const getMethodForPkType = (pkType: string): string => {\n switch (pkType) {\n case 'Int': return 'unsignedInteger';\n case 'Uuid': return 'uuid';\n case 'String': return 'string';\n default: return 'unsignedBigInteger';\n }\n };\n\n // Source column\n columns.push({\n name: pivot.sourceColumn,\n method: getMethodForPkType(pivot.sourcePkType),\n args: [pivot.sourceColumn],\n modifiers: [],\n });\n\n // Target column\n columns.push({\n name: pivot.targetColumn,\n method: getMethodForPkType(pivot.targetPkType),\n args: [pivot.targetColumn],\n modifiers: [],\n });\n\n // Foreign keys\n foreignKeys.push({\n columns: [pivot.sourceColumn],\n references: 'id',\n on: [pivot.sourceTable],\n onDelete: pivot.onDelete ?? 'cascade',\n onUpdate: pivot.onUpdate ?? 'cascade',\n });\n\n foreignKeys.push({\n columns: [pivot.targetColumn],\n references: 'id',\n on: [pivot.targetTable],\n onDelete: pivot.onDelete ?? 'cascade',\n onUpdate: pivot.onUpdate ?? 'cascade',\n });\n\n // Composite primary key / unique constraint\n indexes.push({\n columns: [pivot.sourceColumn, pivot.targetColumn],\n unique: true,\n });\n\n // Individual indexes for faster lookups (no name - let Laravel auto-generate)\n indexes.push({\n columns: [pivot.sourceColumn],\n unique: false,\n });\n\n indexes.push({\n columns: [pivot.targetColumn],\n unique: false,\n });\n\n return {\n tableName: pivot.tableName,\n columns,\n primaryKey: [pivot.sourceColumn, pivot.targetColumn],\n foreignKeys,\n indexes,\n };\n}\n\n/**\n * Extracts MorphToMany relationships from a schema.\n * MorphToMany creates a pivot table with polymorphic type/id columns.\n */\nexport function extractMorphToManyRelations(\n schema: LoadedSchema,\n allSchemas: SchemaCollection\n): MorphToManyPivotInfo[] {\n const morphPivotTables: MorphToManyPivotInfo[] = [];\n\n if (!schema.properties) {\n return morphPivotTables;\n }\n\n for (const [propName, property] of Object.entries(schema.properties)) {\n if (property.type !== 'Association') {\n continue;\n }\n\n const assocProp = property as {\n relation?: string;\n target?: string;\n joinTable?: string;\n onDelete?: string;\n onUpdate?: string;\n owning?: boolean;\n };\n\n if (assocProp.relation !== 'MorphToMany') {\n continue;\n }\n\n const targetName = assocProp.target;\n if (!targetName) {\n continue;\n }\n\n const targetSchema = allSchemas[targetName];\n const targetTable = toTableName(targetName);\n const targetPkType = targetSchema ? getIdType(targetSchema) : 'BigInt';\n\n // Determine if this side owns the relationship\n const isOwningSide = assocProp.owning ?? (schema.name < targetName);\n\n if (!isOwningSide) {\n continue;\n }\n\n // Find all schemas that have MorphedByMany pointing to this target\n // to determine the morphTargets for the ENUM\n const morphTargets: string[] = [];\n\n // The source schema itself is a morph target\n morphTargets.push(schema.name);\n\n // Look for other schemas with MorphToMany to the same target\n for (const [otherName, otherSchema] of Object.entries(allSchemas)) {\n if (otherName === schema.name) continue;\n if (!otherSchema.properties) continue;\n\n for (const otherProp of Object.values(otherSchema.properties)) {\n if (otherProp.type !== 'Association') continue;\n const otherAssoc = otherProp as { relation?: string; target?: string };\n if (otherAssoc.relation === 'MorphToMany' && otherAssoc.target === targetName) {\n if (!morphTargets.includes(otherName)) {\n morphTargets.push(otherName);\n }\n }\n }\n }\n\n // Default table name: taggables (for Tag target), commentables, etc.\n const defaultTableName = targetTable.replace(/s$/, '') + 'ables';\n const tableName = assocProp.joinTable ?? defaultTableName;\n\n // Column name for the target side (e.g., tag_id for Tag)\n const targetColumn = targetTable.replace(/ies$/, 'y').replace(/s$/, '') + '_id';\n\n // MorphName is typically the property name or a convention like 'taggable'\n const morphName = propName.replace(/s$/, '') + 'able';\n\n morphPivotTables.push({\n tableName,\n targetTable,\n targetColumn,\n targetPkType,\n morphName,\n morphTargets,\n onDelete: assocProp.onDelete,\n onUpdate: assocProp.onUpdate,\n });\n }\n\n return morphPivotTables;\n}\n\n/**\n * Generates blueprint for a polymorphic pivot table (MorphToMany).\n */\nexport function generateMorphToManyPivotBlueprint(pivot: MorphToManyPivotInfo): TableBlueprint {\n const columns: ColumnMethod[] = [];\n const foreignKeys: ForeignKeyDefinition[] = [];\n const indexes: IndexDefinition[] = [];\n\n const getMethodForPkType = (pkType: string): string => {\n switch (pkType) {\n case 'Int': return 'unsignedInteger';\n case 'Uuid': return 'uuid';\n case 'String': return 'string';\n default: return 'unsignedBigInteger';\n }\n };\n\n // Target column (e.g., tag_id)\n columns.push({\n name: pivot.targetColumn,\n method: getMethodForPkType(pivot.targetPkType),\n args: [pivot.targetColumn],\n modifiers: [],\n });\n\n // Polymorphic type column as ENUM\n const typeColumnName = `${pivot.morphName}_type`;\n columns.push({\n name: typeColumnName,\n method: 'enum',\n args: [typeColumnName, pivot.morphTargets as unknown as string],\n modifiers: [],\n });\n\n // Polymorphic ID column\n const idColumnName = `${pivot.morphName}_id`;\n columns.push({\n name: idColumnName,\n method: 'unsignedBigInteger', // Default to BigInt for polymorphic IDs\n args: [idColumnName],\n modifiers: [],\n });\n\n // Foreign key for target\n foreignKeys.push({\n columns: [pivot.targetColumn],\n references: 'id',\n on: [pivot.targetTable],\n onDelete: pivot.onDelete ?? 'cascade',\n onUpdate: pivot.onUpdate ?? 'cascade',\n });\n\n // Unique constraint for polymorphic pivot (target + morphable)\n indexes.push({\n columns: [pivot.targetColumn, typeColumnName, idColumnName],\n unique: true,\n });\n\n // Index for faster polymorphic lookups\n indexes.push({\n columns: [typeColumnName, idColumnName],\n unique: false,\n });\n\n // Index for target lookups\n indexes.push({\n columns: [pivot.targetColumn],\n unique: false,\n });\n\n return {\n tableName: pivot.tableName,\n columns,\n primaryKey: [pivot.targetColumn, typeColumnName, idColumnName],\n foreignKeys,\n indexes,\n };\n}\n\n// Note: File schema functions (hasFileProperties, schemasHaveFileProperties, generateFilesTableBlueprint)\n// have been moved to @famgia/omnify-core's schema/loader.ts\n// The File table is now managed as a proper schema (File.yaml) instead of being auto-generated in code.\n","/**\n * @famgia/omnify-laravel - Migration Generator\n *\n * Generates Laravel migration files from schemas.\n */\n\nimport type { LoadedSchema, SchemaCollection } from '@famgia/omnify-types';\nimport type {\n MigrationFile,\n MigrationOptions,\n TableBlueprint,\n} from './types.js';\nimport {\n schemaToBlueprint,\n formatColumnMethod,\n formatForeignKey,\n formatIndex,\n extractManyToManyRelations,\n generatePivotTableBlueprint,\n} from './schema-builder.js';\n\n/**\n * Generates timestamp prefix for migration file name.\n */\nfunction generateTimestamp(): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const day = String(now.getDate()).padStart(2, '0');\n const hours = String(now.getHours()).padStart(2, '0');\n const minutes = String(now.getMinutes()).padStart(2, '0');\n const seconds = String(now.getSeconds()).padStart(2, '0');\n return `${year}_${month}_${day}_${hours}${minutes}${seconds}`;\n}\n\n/**\n * Converts table name to Laravel migration class name.\n */\nfunction toClassName(tableName: string, type: 'create' | 'alter' | 'drop'): string {\n const pascalCase = tableName\n .split('_')\n .map(word => word.charAt(0).toUpperCase() + word.slice(1))\n .join('');\n\n switch (type) {\n case 'create':\n return `Create${pascalCase}Table`;\n case 'alter':\n return `Alter${pascalCase}Table`;\n case 'drop':\n return `Drop${pascalCase}Table`;\n }\n}\n\n/**\n * Generates file name for migration.\n */\nfunction generateFileName(\n tableName: string,\n type: 'create' | 'alter' | 'drop',\n timestamp?: string\n): string {\n const ts = timestamp ?? generateTimestamp();\n const action = type === 'create' ? 'create' : type === 'drop' ? 'drop' : 'update';\n return `${ts}_${action}_${tableName}_table.php`;\n}\n\n/**\n * Renders the up method body for a create table operation.\n */\nfunction renderCreateTableUp(blueprint: TableBlueprint): string {\n const lines: string[] = [];\n\n // Column definitions\n for (const column of blueprint.columns) {\n lines.push(` ${formatColumnMethod(column)}`);\n }\n\n // Foreign keys (separate for Laravel best practices)\n // Note: Foreign keys should be in a separate migration or at the end\n // We'll include them in the same migration for simplicity\n\n return lines.join('\\n');\n}\n\n/**\n * Renders foreign key constraints (usually added after all columns).\n */\nfunction renderForeignKeys(blueprint: TableBlueprint): string {\n if (blueprint.foreignKeys.length === 0) {\n return '';\n }\n\n const lines = blueprint.foreignKeys.map(fk => ` ${formatForeignKey(fk)}`);\n return '\\n' + lines.join('\\n');\n}\n\n/**\n * Renders indexes.\n */\nfunction renderIndexes(blueprint: TableBlueprint): string {\n // Filter out indexes that are already handled (primary key, unique columns)\n const customIndexes = blueprint.indexes.filter(idx => {\n // Skip single-column unique indexes (handled by column modifier)\n if (idx.unique && idx.columns.length === 1) {\n return false;\n }\n return true;\n });\n\n if (customIndexes.length === 0) {\n return '';\n }\n\n const lines = customIndexes.map(idx => ` ${formatIndex(idx)}`);\n return '\\n' + lines.join('\\n');\n}\n\n/**\n * Generates a create table migration.\n */\nfunction generateCreateMigration(\n blueprint: TableBlueprint,\n options: MigrationOptions = {}\n): MigrationFile {\n const className = toClassName(blueprint.tableName, 'create');\n const fileName = generateFileName(blueprint.tableName, 'create', options.timestamp);\n\n const connection = options.connection\n ? `\\n protected $connection = '${options.connection}';\\n`\n : '';\n\n const upContent = renderCreateTableUp(blueprint);\n const foreignKeyContent = renderForeignKeys(blueprint);\n const indexContent = renderIndexes(blueprint);\n\n const content = `<?php\n\nuse Illuminate\\\\Database\\\\Migrations\\\\Migration;\nuse Illuminate\\\\Database\\\\Schema\\\\Blueprint;\nuse Illuminate\\\\Support\\\\Facades\\\\Schema;\n\nreturn new class extends Migration\n{${connection}\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::create('${blueprint.tableName}', function (Blueprint $table) {\n${upContent}${foreignKeyContent}${indexContent}\n });\n }\n\n /**\n * Reverse the migrations.\n */\n public function down(): void\n {\n Schema::dropIfExists('${blueprint.tableName}');\n }\n};\n`;\n\n return {\n fileName,\n className,\n content,\n tables: [blueprint.tableName],\n type: 'create',\n };\n}\n\n/**\n * Generates a drop table migration.\n */\nfunction generateDropMigration(\n tableName: string,\n options: MigrationOptions = {}\n): MigrationFile {\n const className = toClassName(tableName, 'drop');\n const fileName = generateFileName(tableName, 'drop', options.timestamp);\n\n const connection = options.connection\n ? `\\n protected $connection = '${options.connection}';\\n`\n : '';\n\n const content = `<?php\n\nuse Illuminate\\\\Database\\\\Migrations\\\\Migration;\nuse Illuminate\\\\Database\\\\Schema\\\\Blueprint;\nuse Illuminate\\\\Support\\\\Facades\\\\Schema;\n\nreturn new class extends Migration\n{${connection}\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::dropIfExists('${tableName}');\n }\n\n /**\n * Reverse the migrations.\n */\n public function down(): void\n {\n // Cannot recreate table without schema information\n // This is a one-way migration\n }\n};\n`;\n\n return {\n fileName,\n className,\n content,\n tables: [tableName],\n type: 'drop',\n };\n}\n\n/**\n * Extracts FK dependencies from a schema.\n * Returns array of schema names that this schema depends on.\n */\nfunction extractDependencies(schema: LoadedSchema): string[] {\n const deps: string[] = [];\n\n if (!schema.properties) {\n return deps;\n }\n\n for (const property of Object.values(schema.properties)) {\n if (property.type !== 'Association') {\n continue;\n }\n\n const assocProp = property as {\n relation?: string;\n target?: string;\n mappedBy?: string;\n };\n\n // ManyToOne and OneToOne (owning side) create FK columns\n if (\n (assocProp.relation === 'ManyToOne' || assocProp.relation === 'OneToOne') &&\n !assocProp.mappedBy &&\n assocProp.target\n ) {\n deps.push(assocProp.target);\n }\n }\n\n return deps;\n}\n\n/**\n * Topological sort of schemas based on FK dependencies.\n * Returns schemas in order where dependencies come before dependents.\n */\nfunction topologicalSort(schemas: SchemaCollection): LoadedSchema[] {\n const schemaList = Object.values(schemas).filter(s => s.kind !== 'enum');\n const sorted: LoadedSchema[] = [];\n const visited = new Set<string>();\n const visiting = new Set<string>(); // For cycle detection\n\n function visit(schema: LoadedSchema): void {\n if (visited.has(schema.name)) {\n return;\n }\n\n if (visiting.has(schema.name)) {\n // Circular dependency - just continue (FK can be nullable)\n return;\n }\n\n visiting.add(schema.name);\n\n // Visit dependencies first\n const deps = extractDependencies(schema);\n for (const depName of deps) {\n const depSchema = schemas[depName];\n if (depSchema && depSchema.kind !== 'enum') {\n visit(depSchema);\n }\n }\n\n visiting.delete(schema.name);\n visited.add(schema.name);\n sorted.push(schema);\n }\n\n // Visit all schemas\n for (const schema of schemaList) {\n visit(schema);\n }\n\n return sorted;\n}\n\n/**\n * Generates migrations for all schemas.\n */\nexport function generateMigrations(\n schemas: SchemaCollection,\n options: MigrationOptions = {}\n): MigrationFile[] {\n const migrations: MigrationFile[] = [];\n const pivotTablesGenerated = new Set<string>();\n let timestampOffset = 0;\n\n // Note: File table (for polymorphic file storage) is now managed as a proper schema (File.yaml)\n // It will be processed like any other schema in the topological sort below.\n // Use ensureFileSchema() from @famgia/omnify-core to auto-generate File.yaml when needed.\n\n // Sort schemas by FK dependencies (topological sort)\n const sortedSchemas = topologicalSort(schemas);\n\n // Generate main table migrations in dependency order\n for (const schema of sortedSchemas) {\n // Generate timestamp with offset to ensure unique filenames\n const timestamp = options.timestamp ?? generateTimestamp();\n const offsetTimestamp = incrementTimestamp(timestamp, timestampOffset);\n timestampOffset++;\n\n const blueprint = schemaToBlueprint(schema, schemas);\n const migration = generateCreateMigration(blueprint, {\n ...options,\n timestamp: offsetTimestamp,\n });\n migrations.push(migration);\n }\n\n // Third pass: generate pivot table migrations for ManyToMany (always last)\n for (const schema of sortedSchemas) {\n const pivotTables = extractManyToManyRelations(schema, schemas);\n\n for (const pivot of pivotTables) {\n // Skip if already generated\n if (pivotTablesGenerated.has(pivot.tableName)) {\n continue;\n }\n pivotTablesGenerated.add(pivot.tableName);\n\n const timestamp = options.timestamp ?? generateTimestamp();\n const offsetTimestamp = incrementTimestamp(timestamp, timestampOffset);\n timestampOffset++;\n\n const blueprint = generatePivotTableBlueprint(pivot);\n const migration = generateCreateMigration(blueprint, {\n ...options,\n timestamp: offsetTimestamp,\n });\n migrations.push(migration);\n }\n }\n\n return migrations;\n}\n\n/**\n * Increments a timestamp by seconds.\n */\nfunction incrementTimestamp(timestamp: string, seconds: number): string {\n if (seconds === 0) return timestamp;\n\n // Parse timestamp: YYYY_MM_DD_HHMMSS\n const parts = timestamp.split('_');\n if (parts.length < 4) {\n // Invalid format, return original\n return timestamp;\n }\n\n const yearPart = parts[0] ?? '2024';\n const monthPart = parts[1] ?? '01';\n const dayPart = parts[2] ?? '01';\n const timePart = parts[3] ?? '000000';\n\n const year = parseInt(yearPart, 10);\n const month = parseInt(monthPart, 10) - 1;\n const day = parseInt(dayPart, 10);\n const hours = parseInt(timePart.substring(0, 2), 10);\n const minutes = parseInt(timePart.substring(2, 4), 10);\n const secs = parseInt(timePart.substring(4, 6), 10);\n\n const date = new Date(year, month, day, hours, minutes, secs + seconds);\n\n const newYear = date.getFullYear();\n const newMonth = String(date.getMonth() + 1).padStart(2, '0');\n const newDay = String(date.getDate()).padStart(2, '0');\n const newHours = String(date.getHours()).padStart(2, '0');\n const newMinutes = String(date.getMinutes()).padStart(2, '0');\n const newSecs = String(date.getSeconds()).padStart(2, '0');\n\n return `${newYear}_${newMonth}_${newDay}_${newHours}${newMinutes}${newSecs}`;\n}\n\n/**\n * Generates migration from a single schema.\n */\nexport function generateMigrationFromSchema(\n schema: LoadedSchema,\n allSchemas: SchemaCollection,\n options: MigrationOptions = {}\n): MigrationFile {\n const blueprint = schemaToBlueprint(schema, allSchemas);\n return generateCreateMigration(blueprint, options);\n}\n\n/**\n * Generates drop migration for a table.\n */\nexport function generateDropMigrationForTable(\n tableName: string,\n options: MigrationOptions = {}\n): MigrationFile {\n return generateDropMigration(tableName, options);\n}\n\n/**\n * Formats migration content for writing to file.\n */\nexport function formatMigrationFile(migration: MigrationFile): string {\n return migration.content;\n}\n\n/**\n * Gets the output path for a migration file.\n */\nexport function getMigrationPath(\n migration: MigrationFile,\n outputDir: string = 'database/migrations'\n): string {\n return `${outputDir}/${migration.fileName}`;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts","../src/migration/schema-builder.ts","../src/migration/generator.ts","../src/utils.ts","../src/model/generator.ts"],"sourcesContent":["/**\n * @famgia/omnify-laravel - Plugin\n *\n * Plugin for generating Laravel migration files and Eloquent models from Omnify schemas.\n *\n * @example\n * ```typescript\n * import { defineConfig } from '@famgia/omnify';\n * import laravel from '@famgia/omnify-laravel/plugin';\n *\n * export default defineConfig({\n * plugins: [\n * laravel({\n * migrationsPath: 'database/migrations',\n * modelsPath: 'app/Models',\n * connection: 'mysql',\n * }),\n * ],\n * });\n * ```\n */\n\nimport type { OmnifyPlugin, GeneratorOutput, GeneratorContext, PluginConfigSchema } from '@famgia/omnify-types';\nimport { generateMigrations, getMigrationPath, type MigrationOptions } from './migration/index.js';\nimport { generateModels, getModelPath, type ModelGeneratorOptions } from './model/index.js';\n\n/**\n * Configuration schema for Laravel plugin UI settings\n */\nconst LARAVEL_CONFIG_SCHEMA: PluginConfigSchema = {\n fields: [\n {\n key: 'migrationsPath',\n type: 'path',\n label: 'Migrations Path',\n description: 'Directory for Laravel migration files',\n default: 'database/migrations',\n group: 'output',\n },\n {\n key: 'modelsPath',\n type: 'path',\n label: 'Models Path',\n description: 'Directory for user-editable model files',\n default: 'app/Models',\n group: 'output',\n },\n {\n key: 'baseModelsPath',\n type: 'path',\n label: 'Base Models Path',\n description: 'Directory for auto-generated base model files',\n default: 'app/Models/OmnifyBase',\n group: 'output',\n },\n {\n key: 'generateModels',\n type: 'boolean',\n label: 'Generate Models',\n description: 'Generate Eloquent model classes',\n default: true,\n group: 'options',\n },\n {\n key: 'connection',\n type: 'string',\n label: 'Database Connection',\n description: 'Laravel database connection name (optional)',\n placeholder: 'mysql',\n group: 'options',\n },\n ],\n};\n\n/**\n * Options for the Laravel plugin.\n */\nexport interface LaravelPluginOptions {\n /**\n * Path for Laravel migration files.\n * @default 'database/migrations'\n */\n migrationsPath?: string;\n\n /**\n * Path for user-editable model files.\n * @default 'app/Models'\n */\n modelsPath?: string;\n\n /**\n * Path for auto-generated base model files.\n * @default 'app/Models/OmnifyBase'\n */\n baseModelsPath?: string;\n\n /**\n * Model namespace.\n * @default 'App\\\\Models'\n */\n modelNamespace?: string;\n\n /**\n * Base model namespace.\n * @default 'App\\\\Models\\\\OmnifyBase'\n */\n baseModelNamespace?: string;\n\n /**\n * Whether to generate Eloquent models.\n * @default true\n */\n generateModels?: boolean;\n\n /**\n * Database connection name for migrations.\n */\n connection?: string;\n\n /**\n * Custom timestamp for migration file names (mainly for testing).\n */\n timestamp?: string;\n}\n\n/**\n * Resolved options with defaults applied.\n */\ninterface ResolvedOptions {\n migrationsPath: string;\n modelsPath: string;\n baseModelsPath: string;\n modelNamespace: string;\n baseModelNamespace: string;\n generateModels: boolean;\n connection: string | undefined;\n timestamp: string | undefined;\n}\n\n/**\n * Resolves options with defaults.\n */\nfunction resolveOptions(options?: LaravelPluginOptions): ResolvedOptions {\n return {\n migrationsPath: options?.migrationsPath ?? 'database/migrations',\n modelsPath: options?.modelsPath ?? 'app/Models',\n baseModelsPath: options?.baseModelsPath ?? 'app/Models/OmnifyBase',\n modelNamespace: options?.modelNamespace ?? 'App\\\\Models',\n baseModelNamespace: options?.baseModelNamespace ?? 'App\\\\Models\\\\OmnifyBase',\n generateModels: options?.generateModels ?? true,\n connection: options?.connection,\n timestamp: options?.timestamp,\n };\n}\n\n/**\n * Creates the Laravel plugin with the specified options.\n *\n * @param options - Plugin configuration options\n * @returns OmnifyPlugin configured for Laravel migrations and models\n */\nexport default function laravelPlugin(options?: LaravelPluginOptions): OmnifyPlugin {\n const resolved = resolveOptions(options);\n\n // Build generators array\n const migrationGenerator = {\n name: 'laravel-migrations',\n description: 'Generate Laravel migration files',\n\n generate: async (ctx: GeneratorContext): Promise<GeneratorOutput[]> => {\n const migrationOptions: MigrationOptions = {\n connection: resolved.connection,\n timestamp: resolved.timestamp,\n };\n\n const migrations = generateMigrations(ctx.schemas, migrationOptions);\n\n return migrations.map((migration) => ({\n path: getMigrationPath(migration, resolved.migrationsPath),\n content: migration.content,\n type: 'migration' as const,\n metadata: {\n tableName: migration.tables[0],\n migrationType: migration.type,\n },\n }));\n },\n };\n\n const modelGenerator = {\n name: 'laravel-models',\n description: 'Generate Eloquent model classes',\n\n generate: async (ctx: GeneratorContext): Promise<GeneratorOutput[]> => {\n const modelOptions: ModelGeneratorOptions = {\n modelNamespace: resolved.modelNamespace,\n baseModelNamespace: resolved.baseModelNamespace,\n modelPath: resolved.modelsPath,\n baseModelPath: resolved.baseModelsPath,\n };\n\n const models = generateModels(ctx.schemas, modelOptions);\n\n return models.map((model) => ({\n path: getModelPath(model),\n content: model.content,\n type: 'model' as const,\n // Skip writing user models if they already exist\n skipIfExists: !model.overwrite,\n metadata: {\n modelType: model.type,\n schemaName: model.schemaName,\n },\n }));\n },\n };\n\n return {\n name: '@famgia/omnify-laravel',\n version: '0.0.14',\n configSchema: LARAVEL_CONFIG_SCHEMA,\n generators: resolved.generateModels\n ? [migrationGenerator, modelGenerator]\n : [migrationGenerator],\n };\n}\n\n// Named export for flexibility\nexport { laravelPlugin };\n","/**\n * @famgia/omnify-laravel - Schema Builder Converter\n *\n * Converts SQL types and operations to Laravel Schema Builder methods.\n */\n\nimport type { PropertyDefinition, LoadedSchema, SchemaCollection } from '@famgia/omnify-types';\nimport type {\n ColumnMethod,\n ColumnModifier,\n ForeignKeyDefinition,\n IndexDefinition,\n TableBlueprint,\n} from './types.js';\n\n/**\n * Maps Omnify property types to Laravel column methods.\n */\nconst TYPE_METHOD_MAP: Record<string, string> = {\n String: 'string',\n Int: 'integer',\n BigInt: 'bigInteger',\n Float: 'double',\n Decimal: 'decimal',\n Boolean: 'boolean',\n Text: 'text',\n LongText: 'longText',\n Date: 'date',\n Time: 'time',\n Timestamp: 'timestamp',\n Json: 'json',\n Email: 'string',\n Password: 'string',\n Enum: 'enum',\n // Note: File type is now polymorphic - no column generated, uses files table\n};\n\n/**\n * Maps primary key types to Laravel methods.\n */\nconst PK_METHOD_MAP: Record<string, string> = {\n Int: 'increments',\n BigInt: 'bigIncrements',\n Uuid: 'uuid',\n String: 'string',\n};\n\n/**\n * Gets the ID type from schema options.\n */\nfunction getIdType(schema: LoadedSchema): 'Int' | 'BigInt' | 'Uuid' | 'String' {\n return (schema.options?.idType ?? 'BigInt') as 'Int' | 'BigInt' | 'Uuid' | 'String';\n}\n\n/**\n * Checks if the schema should have an auto-generated ID column.\n * Returns false if options.id is explicitly set to false.\n */\nfunction hasAutoId(schema: LoadedSchema): boolean {\n return schema.options?.id !== false;\n}\n\n/**\n * Converts a property name to snake_case column name.\n */\nexport function toColumnName(propertyName: string): string {\n return propertyName.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\n}\n\n/**\n * Converts schema name to snake_case plural table name.\n */\nexport function toTableName(schemaName: string): string {\n const snakeCase = schemaName\n .replace(/([A-Z])/g, '_$1')\n .toLowerCase()\n .replace(/^_/, '');\n\n // Simple pluralization\n if (snakeCase.endsWith('y')) {\n return snakeCase.slice(0, -1) + 'ies';\n } else if (\n snakeCase.endsWith('s') ||\n snakeCase.endsWith('x') ||\n snakeCase.endsWith('ch') ||\n snakeCase.endsWith('sh')\n ) {\n return snakeCase + 'es';\n } else {\n return snakeCase + 's';\n }\n}\n\n/**\n * Converts a property to Laravel column method.\n */\nexport function propertyToColumnMethod(\n propertyName: string,\n property: PropertyDefinition\n): ColumnMethod | null {\n // Skip associations - they're handled separately\n if (property.type === 'Association') {\n return null;\n }\n\n // Skip File type - uses polymorphic relation to files table\n if (property.type === 'File') {\n return null;\n }\n\n const columnName = toColumnName(propertyName);\n const method = TYPE_METHOD_MAP[property.type] ?? 'string';\n const args: (string | number | boolean)[] = [columnName];\n const modifiers: ColumnModifier[] = [];\n\n // Handle length for string types\n const propWithLength = property as { length?: number };\n if (method === 'string' && propWithLength.length) {\n args.push(propWithLength.length);\n }\n\n // Handle precision and scale for decimal types\n if (property.type === 'Decimal') {\n const decimalProp = property as { precision?: number; scale?: number };\n const precision = decimalProp.precision ?? 8;\n const scale = decimalProp.scale ?? 2;\n args.push(precision, scale);\n }\n\n // Handle enum values\n if (property.type === 'Enum') {\n const enumProp = property as { enum?: readonly string[] };\n if (enumProp.enum && enumProp.enum.length > 0) {\n args.push(enumProp.enum as unknown as string);\n }\n }\n\n // Add modifiers\n const baseProp = property as {\n nullable?: boolean;\n unique?: boolean;\n default?: unknown;\n unsigned?: boolean;\n };\n\n if (baseProp.nullable) {\n modifiers.push({ method: 'nullable' });\n }\n\n if (baseProp.unique) {\n modifiers.push({ method: 'unique' });\n }\n\n if (baseProp.default !== undefined) {\n const defaultValue = typeof baseProp.default === 'string'\n ? baseProp.default\n : JSON.stringify(baseProp.default);\n modifiers.push({ method: 'default', args: [defaultValue] });\n }\n\n if (baseProp.unsigned && (method === 'integer' || method === 'bigInteger')) {\n modifiers.push({ method: 'unsigned' });\n }\n\n return {\n name: columnName,\n method,\n args,\n modifiers,\n };\n}\n\n/**\n * Generates primary key column method.\n */\nexport function generatePrimaryKeyColumn(\n pkType: 'Int' | 'BigInt' | 'Uuid' | 'String' = 'BigInt'\n): ColumnMethod {\n const method = PK_METHOD_MAP[pkType] ?? 'bigIncrements';\n\n if (pkType === 'Uuid') {\n return {\n name: 'id',\n method: 'uuid',\n args: ['id'],\n modifiers: [{ method: 'primary' }],\n };\n }\n\n if (pkType === 'String') {\n return {\n name: 'id',\n method: 'string',\n args: ['id', 255],\n modifiers: [{ method: 'primary' }],\n };\n }\n\n // For Int/BigInt, use increments which auto-creates primary key\n return {\n name: 'id',\n method,\n args: ['id'],\n modifiers: [],\n };\n}\n\n/**\n * Generates timestamp columns.\n */\nexport function generateTimestampColumns(): ColumnMethod[] {\n return [\n {\n name: 'created_at',\n method: 'timestamp',\n args: ['created_at'],\n modifiers: [{ method: 'nullable' }],\n },\n {\n name: 'updated_at',\n method: 'timestamp',\n args: ['updated_at'],\n modifiers: [{ method: 'nullable' }],\n },\n ];\n}\n\n/**\n * Generates soft delete column.\n */\nexport function generateSoftDeleteColumn(): ColumnMethod {\n return {\n name: 'deleted_at',\n method: 'timestamp',\n args: ['deleted_at'],\n modifiers: [{ method: 'nullable' }],\n };\n}\n\n/**\n * Polymorphic column result with type enum and id column.\n */\nexport interface PolymorphicColumnsResult {\n typeColumn: ColumnMethod;\n idColumn: ColumnMethod;\n indexes: IndexDefinition[];\n}\n\n/**\n * Generates polymorphic columns for MorphTo relations.\n * Creates {name}_type (ENUM) and {name}_id columns.\n */\nexport function generatePolymorphicColumns(\n propertyName: string,\n property: PropertyDefinition,\n allSchemas: SchemaCollection\n): PolymorphicColumnsResult | null {\n if (property.type !== 'Association') {\n return null;\n }\n\n const assocProp = property as {\n relation?: string;\n targets?: readonly string[];\n };\n\n // Only handle MorphTo - it creates the type and id columns\n if (assocProp.relation !== 'MorphTo') {\n return null;\n }\n\n const targets = assocProp.targets;\n if (!targets || targets.length === 0) {\n return null;\n }\n\n const columnBaseName = toColumnName(propertyName);\n const typeColumnName = `${columnBaseName}_type`;\n const idColumnName = `${columnBaseName}_id`;\n\n // Generate ENUM type column with target schema names as values\n const typeColumn: ColumnMethod = {\n name: typeColumnName,\n method: 'enum',\n args: [typeColumnName, targets as unknown as string],\n modifiers: [{ method: 'nullable' }],\n };\n\n // For polymorphic id, we need to determine the largest ID type among targets\n // Default to unsignedBigInteger for maximum compatibility\n let idMethod = 'unsignedBigInteger';\n\n // Check if any target uses UUID or String - those take precedence\n for (const targetName of targets) {\n const targetSchema = allSchemas[targetName];\n if (targetSchema) {\n const targetIdType = (targetSchema.options?.idType ?? 'BigInt') as string;\n if (targetIdType === 'Uuid') {\n idMethod = 'uuid';\n break; // UUID takes highest precedence\n } else if (targetIdType === 'String') {\n idMethod = 'string';\n // Don't break - UUID still takes precedence\n }\n }\n }\n\n const idColumn: ColumnMethod = {\n name: idColumnName,\n method: idMethod,\n args: idMethod === 'string' ? [idColumnName, 255] : [idColumnName],\n modifiers: [{ method: 'nullable' }],\n };\n\n // Create composite index for faster polymorphic lookups\n const indexes: IndexDefinition[] = [\n {\n columns: [typeColumnName, idColumnName],\n unique: false,\n },\n ];\n\n return { typeColumn, idColumn, indexes };\n}\n\n/**\n * Generates foreign key column and constraint from association.\n */\nexport function generateForeignKey(\n propertyName: string,\n property: PropertyDefinition,\n allSchemas: SchemaCollection\n): { column: ColumnMethod; foreignKey: ForeignKeyDefinition; index: IndexDefinition } | null {\n if (property.type !== 'Association') {\n return null;\n }\n\n const assocProp = property as {\n relation?: string;\n target?: string;\n onDelete?: string;\n onUpdate?: string;\n mappedBy?: string;\n owningSide?: boolean;\n };\n\n // Only create FK column for ManyToOne and OneToOne (owning side)\n if (assocProp.relation !== 'ManyToOne' && assocProp.relation !== 'OneToOne') {\n return null;\n }\n\n // Skip inverse side (mappedBy means this is the inverse side)\n if (assocProp.mappedBy) {\n return null;\n }\n\n const columnName = toColumnName(propertyName) + '_id';\n const targetSchema = assocProp.target ? allSchemas[assocProp.target] : undefined;\n const targetTable = assocProp.target ? toTableName(assocProp.target) : 'unknown';\n const targetPkType = targetSchema ? getIdType(targetSchema) : 'BigInt';\n\n // Determine column method based on target PK type\n let method = 'unsignedBigInteger';\n if (targetPkType === 'Int') {\n method = 'unsignedInteger';\n } else if (targetPkType === 'Uuid') {\n method = 'uuid';\n } else if (targetPkType === 'String') {\n method = 'string';\n }\n\n const column: ColumnMethod = {\n name: columnName,\n method,\n args: [columnName],\n modifiers: assocProp.relation === 'ManyToOne' ? [{ method: 'nullable' }] : [],\n };\n\n const foreignKey: ForeignKeyDefinition = {\n columns: [columnName],\n references: 'id',\n on: [targetTable],\n onDelete: assocProp.onDelete ?? 'restrict',\n onUpdate: assocProp.onUpdate ?? 'cascade',\n };\n\n // Don't specify index name - let Laravel auto-generate unique names\n const index: IndexDefinition = {\n columns: [columnName],\n unique: false,\n };\n\n return { column, foreignKey, index };\n}\n\n/**\n * Generates table blueprint from schema.\n */\nexport function schemaToBlueprint(\n schema: LoadedSchema,\n allSchemas: SchemaCollection\n): TableBlueprint {\n const tableName = toTableName(schema.name);\n const columns: ColumnMethod[] = [];\n const foreignKeys: ForeignKeyDefinition[] = [];\n const indexes: IndexDefinition[] = [];\n\n // Primary key (only if id is not disabled)\n if (hasAutoId(schema)) {\n const pkType = getIdType(schema);\n columns.push(generatePrimaryKeyColumn(pkType));\n }\n\n // Process properties\n if (schema.properties) {\n for (const [propName, property] of Object.entries(schema.properties)) {\n // Handle regular columns\n const columnMethod = propertyToColumnMethod(propName, property);\n if (columnMethod) {\n columns.push(columnMethod);\n }\n\n // Handle foreign keys (standard associations)\n const fkResult = generateForeignKey(propName, property, allSchemas);\n if (fkResult) {\n columns.push(fkResult.column);\n foreignKeys.push(fkResult.foreignKey);\n indexes.push(fkResult.index);\n }\n\n // Handle polymorphic columns (MorphTo)\n const polyResult = generatePolymorphicColumns(propName, property, allSchemas);\n if (polyResult) {\n columns.push(polyResult.typeColumn);\n columns.push(polyResult.idColumn);\n indexes.push(...polyResult.indexes);\n }\n }\n }\n\n // Timestamps\n if (schema.options?.timestamps !== false) {\n columns.push(...generateTimestampColumns());\n }\n\n // Soft delete\n if (schema.options?.softDelete) {\n columns.push(generateSoftDeleteColumn());\n }\n\n // Custom indexes\n if (schema.options?.indexes) {\n for (const index of schema.options.indexes) {\n // Handle both shorthand (string) and full object format\n if (typeof index === 'string') {\n // Shorthand: just column name\n indexes.push({\n columns: [toColumnName(index)],\n unique: false,\n });\n } else {\n // Full object format\n indexes.push({\n name: index.name,\n columns: index.columns.map(toColumnName),\n unique: index.unique ?? false,\n });\n }\n }\n }\n\n // Unique constraints\n if (schema.options?.unique) {\n const uniqueConstraints = Array.isArray(schema.options.unique[0])\n ? (schema.options.unique as readonly (readonly string[])[])\n : [schema.options.unique as readonly string[]];\n\n for (const constraint of uniqueConstraints) {\n indexes.push({\n columns: constraint.map(toColumnName),\n unique: true,\n });\n }\n }\n\n return {\n tableName,\n columns,\n primaryKey: ['id'],\n foreignKeys,\n indexes,\n };\n}\n\n/**\n * Formats a column method to PHP code.\n */\nexport function formatColumnMethod(column: ColumnMethod): string {\n const args = column.args.map(arg => {\n if (typeof arg === 'string') {\n return `'${arg}'`;\n }\n if (Array.isArray(arg)) {\n return `[${(arg as string[]).map(v => `'${v}'`).join(', ')}]`;\n }\n return String(arg);\n }).join(', ');\n\n let code = `$table->${column.method}(${args})`;\n\n for (const modifier of column.modifiers) {\n if (modifier.args && modifier.args.length > 0) {\n const modArgs = modifier.args.map(arg => {\n if (typeof arg === 'string') {\n return `'${arg}'`;\n }\n return String(arg);\n }).join(', ');\n code += `->${modifier.method}(${modArgs})`;\n } else {\n code += `->${modifier.method}()`;\n }\n }\n\n return code + ';';\n}\n\n/**\n * Formats a foreign key to PHP code.\n */\nexport function formatForeignKey(fk: ForeignKeyDefinition): string {\n const column = fk.columns[0];\n const table = fk.on[0];\n let code = `$table->foreign('${column}')->references('${fk.references}')->on('${table}')`;\n\n if (fk.onDelete) {\n code += `->onDelete('${fk.onDelete}')`;\n }\n if (fk.onUpdate) {\n code += `->onUpdate('${fk.onUpdate}')`;\n }\n\n return code + ';';\n}\n\n/**\n * Formats an index to PHP code.\n */\nexport function formatIndex(index: IndexDefinition): string {\n const columns = index.columns.length === 1\n ? `'${index.columns[0]}'`\n : `[${index.columns.map(c => `'${c}'`).join(', ')}]`;\n\n const method = index.unique ? 'unique' : 'index';\n const name = index.name ? `, '${index.name}'` : '';\n\n return `$table->${method}(${columns}${name});`;\n}\n\n/**\n * Pivot table information for ManyToMany relationships.\n */\nexport interface PivotTableInfo {\n tableName: string;\n sourceTable: string;\n targetTable: string;\n sourceColumn: string;\n targetColumn: string;\n sourcePkType: 'Int' | 'BigInt' | 'Uuid' | 'String';\n targetPkType: 'Int' | 'BigInt' | 'Uuid' | 'String';\n onDelete: string | undefined;\n onUpdate: string | undefined;\n}\n\n/**\n * Polymorphic pivot table information for MorphToMany relationships.\n */\nexport interface MorphToManyPivotInfo {\n tableName: string;\n /** The fixed target schema that uses MorphToMany */\n targetTable: string;\n targetColumn: string;\n targetPkType: 'Int' | 'BigInt' | 'Uuid' | 'String';\n /** Base name for polymorphic columns (creates {name}_type and {name}_id) */\n morphName: string;\n /** Schema names that can be morphed to */\n morphTargets: readonly string[];\n onDelete: string | undefined;\n onUpdate: string | undefined;\n}\n\n/**\n * Generates pivot table name for ManyToMany relationship.\n * Uses alphabetical ordering for consistency.\n */\nexport function generatePivotTableName(\n sourceTable: string,\n targetTable: string,\n customName?: string\n): string {\n if (customName) {\n return customName;\n }\n\n // Sort alphabetically for consistent naming\n const tables = [sourceTable, targetTable].sort();\n // Remove trailing 's' and join with underscore\n const singular1 = tables[0]!.replace(/ies$/, 'y').replace(/s$/, '');\n const singular2 = tables[1]!.replace(/ies$/, 'y').replace(/s$/, '');\n return `${singular1}_${singular2}`;\n}\n\n/**\n * Extracts ManyToMany relationships from a schema.\n */\nexport function extractManyToManyRelations(\n schema: LoadedSchema,\n allSchemas: SchemaCollection\n): PivotTableInfo[] {\n const pivotTables: PivotTableInfo[] = [];\n\n if (!schema.properties) {\n return pivotTables;\n }\n\n const sourceTable = toTableName(schema.name);\n const sourcePkType = getIdType(schema);\n\n for (const [, property] of Object.entries(schema.properties)) {\n if (property.type !== 'Association') {\n continue;\n }\n\n const assocProp = property as {\n relation?: string;\n target?: string;\n joinTable?: string;\n onDelete?: string;\n onUpdate?: string;\n owning?: boolean;\n };\n\n // Only handle ManyToMany on the owning side (or if not specified, use alphabetical order)\n if (assocProp.relation !== 'ManyToMany') {\n continue;\n }\n\n const targetName = assocProp.target;\n if (!targetName) {\n continue;\n }\n\n const targetSchema = allSchemas[targetName];\n const targetTable = toTableName(targetName);\n const targetPkType = targetSchema ? getIdType(targetSchema) : 'BigInt';\n\n // Determine if this side owns the relationship\n // Default: alphabetically first schema owns it\n const isOwningSide = assocProp.owning ?? (schema.name < targetName);\n\n if (!isOwningSide) {\n continue; // Skip non-owning side to avoid duplicate pivot tables\n }\n\n const pivotTableName = generatePivotTableName(sourceTable, targetTable, assocProp.joinTable);\n\n // Column names: singular form of table name + _id\n const sourceColumn = sourceTable.replace(/ies$/, 'y').replace(/s$/, '') + '_id';\n const targetColumn = targetTable.replace(/ies$/, 'y').replace(/s$/, '') + '_id';\n\n pivotTables.push({\n tableName: pivotTableName,\n sourceTable,\n targetTable,\n sourceColumn,\n targetColumn,\n sourcePkType,\n targetPkType,\n onDelete: assocProp.onDelete,\n onUpdate: assocProp.onUpdate,\n });\n }\n\n return pivotTables;\n}\n\n/**\n * Generates blueprint for a pivot table.\n */\nexport function generatePivotTableBlueprint(pivot: PivotTableInfo): TableBlueprint {\n const columns: ColumnMethod[] = [];\n const foreignKeys: ForeignKeyDefinition[] = [];\n const indexes: IndexDefinition[] = [];\n\n // Determine column methods based on PK types\n const getMethodForPkType = (pkType: string): string => {\n switch (pkType) {\n case 'Int': return 'unsignedInteger';\n case 'Uuid': return 'uuid';\n case 'String': return 'string';\n default: return 'unsignedBigInteger';\n }\n };\n\n // Source column\n columns.push({\n name: pivot.sourceColumn,\n method: getMethodForPkType(pivot.sourcePkType),\n args: [pivot.sourceColumn],\n modifiers: [],\n });\n\n // Target column\n columns.push({\n name: pivot.targetColumn,\n method: getMethodForPkType(pivot.targetPkType),\n args: [pivot.targetColumn],\n modifiers: [],\n });\n\n // Foreign keys\n foreignKeys.push({\n columns: [pivot.sourceColumn],\n references: 'id',\n on: [pivot.sourceTable],\n onDelete: pivot.onDelete ?? 'cascade',\n onUpdate: pivot.onUpdate ?? 'cascade',\n });\n\n foreignKeys.push({\n columns: [pivot.targetColumn],\n references: 'id',\n on: [pivot.targetTable],\n onDelete: pivot.onDelete ?? 'cascade',\n onUpdate: pivot.onUpdate ?? 'cascade',\n });\n\n // Composite primary key / unique constraint\n indexes.push({\n columns: [pivot.sourceColumn, pivot.targetColumn],\n unique: true,\n });\n\n // Individual indexes for faster lookups (no name - let Laravel auto-generate)\n indexes.push({\n columns: [pivot.sourceColumn],\n unique: false,\n });\n\n indexes.push({\n columns: [pivot.targetColumn],\n unique: false,\n });\n\n return {\n tableName: pivot.tableName,\n columns,\n primaryKey: [pivot.sourceColumn, pivot.targetColumn],\n foreignKeys,\n indexes,\n };\n}\n\n/**\n * Extracts MorphToMany relationships from a schema.\n * MorphToMany creates a pivot table with polymorphic type/id columns.\n */\nexport function extractMorphToManyRelations(\n schema: LoadedSchema,\n allSchemas: SchemaCollection\n): MorphToManyPivotInfo[] {\n const morphPivotTables: MorphToManyPivotInfo[] = [];\n\n if (!schema.properties) {\n return morphPivotTables;\n }\n\n for (const [propName, property] of Object.entries(schema.properties)) {\n if (property.type !== 'Association') {\n continue;\n }\n\n const assocProp = property as {\n relation?: string;\n target?: string;\n joinTable?: string;\n onDelete?: string;\n onUpdate?: string;\n owning?: boolean;\n };\n\n if (assocProp.relation !== 'MorphToMany') {\n continue;\n }\n\n const targetName = assocProp.target;\n if (!targetName) {\n continue;\n }\n\n const targetSchema = allSchemas[targetName];\n const targetTable = toTableName(targetName);\n const targetPkType = targetSchema ? getIdType(targetSchema) : 'BigInt';\n\n // Determine if this side owns the relationship\n const isOwningSide = assocProp.owning ?? (schema.name < targetName);\n\n if (!isOwningSide) {\n continue;\n }\n\n // Find all schemas that have MorphedByMany pointing to this target\n // to determine the morphTargets for the ENUM\n const morphTargets: string[] = [];\n\n // The source schema itself is a morph target\n morphTargets.push(schema.name);\n\n // Look for other schemas with MorphToMany to the same target\n for (const [otherName, otherSchema] of Object.entries(allSchemas)) {\n if (otherName === schema.name) continue;\n if (!otherSchema.properties) continue;\n\n for (const otherProp of Object.values(otherSchema.properties)) {\n if (otherProp.type !== 'Association') continue;\n const otherAssoc = otherProp as { relation?: string; target?: string };\n if (otherAssoc.relation === 'MorphToMany' && otherAssoc.target === targetName) {\n if (!morphTargets.includes(otherName)) {\n morphTargets.push(otherName);\n }\n }\n }\n }\n\n // Default table name: taggables (for Tag target), commentables, etc.\n const defaultTableName = targetTable.replace(/s$/, '') + 'ables';\n const tableName = assocProp.joinTable ?? defaultTableName;\n\n // Column name for the target side (e.g., tag_id for Tag)\n const targetColumn = targetTable.replace(/ies$/, 'y').replace(/s$/, '') + '_id';\n\n // MorphName is typically the property name or a convention like 'taggable'\n const morphName = propName.replace(/s$/, '') + 'able';\n\n morphPivotTables.push({\n tableName,\n targetTable,\n targetColumn,\n targetPkType,\n morphName,\n morphTargets,\n onDelete: assocProp.onDelete,\n onUpdate: assocProp.onUpdate,\n });\n }\n\n return morphPivotTables;\n}\n\n/**\n * Generates blueprint for a polymorphic pivot table (MorphToMany).\n */\nexport function generateMorphToManyPivotBlueprint(pivot: MorphToManyPivotInfo): TableBlueprint {\n const columns: ColumnMethod[] = [];\n const foreignKeys: ForeignKeyDefinition[] = [];\n const indexes: IndexDefinition[] = [];\n\n const getMethodForPkType = (pkType: string): string => {\n switch (pkType) {\n case 'Int': return 'unsignedInteger';\n case 'Uuid': return 'uuid';\n case 'String': return 'string';\n default: return 'unsignedBigInteger';\n }\n };\n\n // Target column (e.g., tag_id)\n columns.push({\n name: pivot.targetColumn,\n method: getMethodForPkType(pivot.targetPkType),\n args: [pivot.targetColumn],\n modifiers: [],\n });\n\n // Polymorphic type column as ENUM\n const typeColumnName = `${pivot.morphName}_type`;\n columns.push({\n name: typeColumnName,\n method: 'enum',\n args: [typeColumnName, pivot.morphTargets as unknown as string],\n modifiers: [],\n });\n\n // Polymorphic ID column\n const idColumnName = `${pivot.morphName}_id`;\n columns.push({\n name: idColumnName,\n method: 'unsignedBigInteger', // Default to BigInt for polymorphic IDs\n args: [idColumnName],\n modifiers: [],\n });\n\n // Foreign key for target\n foreignKeys.push({\n columns: [pivot.targetColumn],\n references: 'id',\n on: [pivot.targetTable],\n onDelete: pivot.onDelete ?? 'cascade',\n onUpdate: pivot.onUpdate ?? 'cascade',\n });\n\n // Unique constraint for polymorphic pivot (target + morphable)\n indexes.push({\n columns: [pivot.targetColumn, typeColumnName, idColumnName],\n unique: true,\n });\n\n // Index for faster polymorphic lookups\n indexes.push({\n columns: [typeColumnName, idColumnName],\n unique: false,\n });\n\n // Index for target lookups\n indexes.push({\n columns: [pivot.targetColumn],\n unique: false,\n });\n\n return {\n tableName: pivot.tableName,\n columns,\n primaryKey: [pivot.targetColumn, typeColumnName, idColumnName],\n foreignKeys,\n indexes,\n };\n}\n\n// Note: File schema functions (hasFileProperties, schemasHaveFileProperties, generateFilesTableBlueprint)\n// have been moved to @famgia/omnify-core's schema/loader.ts\n// The File table is now managed as a proper schema (File.yaml) instead of being auto-generated in code.\n","/**\n * @famgia/omnify-laravel - Migration Generator\n *\n * Generates Laravel migration files from schemas.\n */\n\nimport type { LoadedSchema, SchemaCollection } from '@famgia/omnify-types';\nimport type {\n MigrationFile,\n MigrationOptions,\n TableBlueprint,\n} from './types.js';\nimport {\n schemaToBlueprint,\n formatColumnMethod,\n formatForeignKey,\n formatIndex,\n extractManyToManyRelations,\n generatePivotTableBlueprint,\n} from './schema-builder.js';\n\n/**\n * Generates timestamp prefix for migration file name.\n */\nfunction generateTimestamp(): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const day = String(now.getDate()).padStart(2, '0');\n const hours = String(now.getHours()).padStart(2, '0');\n const minutes = String(now.getMinutes()).padStart(2, '0');\n const seconds = String(now.getSeconds()).padStart(2, '0');\n return `${year}_${month}_${day}_${hours}${minutes}${seconds}`;\n}\n\n/**\n * Converts table name to Laravel migration class name.\n */\nfunction toClassName(tableName: string, type: 'create' | 'alter' | 'drop'): string {\n const pascalCase = tableName\n .split('_')\n .map(word => word.charAt(0).toUpperCase() + word.slice(1))\n .join('');\n\n switch (type) {\n case 'create':\n return `Create${pascalCase}Table`;\n case 'alter':\n return `Alter${pascalCase}Table`;\n case 'drop':\n return `Drop${pascalCase}Table`;\n }\n}\n\n/**\n * Generates file name for migration.\n */\nfunction generateFileName(\n tableName: string,\n type: 'create' | 'alter' | 'drop',\n timestamp?: string\n): string {\n const ts = timestamp ?? generateTimestamp();\n const action = type === 'create' ? 'create' : type === 'drop' ? 'drop' : 'update';\n return `${ts}_${action}_${tableName}_table.php`;\n}\n\n/**\n * Renders the up method body for a create table operation.\n */\nfunction renderCreateTableUp(blueprint: TableBlueprint): string {\n const lines: string[] = [];\n\n // Column definitions\n for (const column of blueprint.columns) {\n lines.push(` ${formatColumnMethod(column)}`);\n }\n\n // Foreign keys (separate for Laravel best practices)\n // Note: Foreign keys should be in a separate migration or at the end\n // We'll include them in the same migration for simplicity\n\n return lines.join('\\n');\n}\n\n/**\n * Renders foreign key constraints (usually added after all columns).\n */\nfunction renderForeignKeys(blueprint: TableBlueprint): string {\n if (blueprint.foreignKeys.length === 0) {\n return '';\n }\n\n const lines = blueprint.foreignKeys.map(fk => ` ${formatForeignKey(fk)}`);\n return '\\n' + lines.join('\\n');\n}\n\n/**\n * Renders indexes.\n */\nfunction renderIndexes(blueprint: TableBlueprint): string {\n // Filter out indexes that are already handled (primary key, unique columns)\n const customIndexes = blueprint.indexes.filter(idx => {\n // Skip single-column unique indexes (handled by column modifier)\n if (idx.unique && idx.columns.length === 1) {\n return false;\n }\n return true;\n });\n\n if (customIndexes.length === 0) {\n return '';\n }\n\n const lines = customIndexes.map(idx => ` ${formatIndex(idx)}`);\n return '\\n' + lines.join('\\n');\n}\n\n/**\n * Generates a create table migration.\n */\nfunction generateCreateMigration(\n blueprint: TableBlueprint,\n options: MigrationOptions = {}\n): MigrationFile {\n const className = toClassName(blueprint.tableName, 'create');\n const fileName = generateFileName(blueprint.tableName, 'create', options.timestamp);\n\n const connection = options.connection\n ? `\\n protected $connection = '${options.connection}';\\n`\n : '';\n\n const upContent = renderCreateTableUp(blueprint);\n const foreignKeyContent = renderForeignKeys(blueprint);\n const indexContent = renderIndexes(blueprint);\n\n const content = `<?php\n\nuse Illuminate\\\\Database\\\\Migrations\\\\Migration;\nuse Illuminate\\\\Database\\\\Schema\\\\Blueprint;\nuse Illuminate\\\\Support\\\\Facades\\\\Schema;\n\nreturn new class extends Migration\n{${connection}\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::create('${blueprint.tableName}', function (Blueprint $table) {\n${upContent}${foreignKeyContent}${indexContent}\n });\n }\n\n /**\n * Reverse the migrations.\n */\n public function down(): void\n {\n Schema::dropIfExists('${blueprint.tableName}');\n }\n};\n`;\n\n return {\n fileName,\n className,\n content,\n tables: [blueprint.tableName],\n type: 'create',\n };\n}\n\n/**\n * Generates a drop table migration.\n */\nfunction generateDropMigration(\n tableName: string,\n options: MigrationOptions = {}\n): MigrationFile {\n const className = toClassName(tableName, 'drop');\n const fileName = generateFileName(tableName, 'drop', options.timestamp);\n\n const connection = options.connection\n ? `\\n protected $connection = '${options.connection}';\\n`\n : '';\n\n const content = `<?php\n\nuse Illuminate\\\\Database\\\\Migrations\\\\Migration;\nuse Illuminate\\\\Database\\\\Schema\\\\Blueprint;\nuse Illuminate\\\\Support\\\\Facades\\\\Schema;\n\nreturn new class extends Migration\n{${connection}\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::dropIfExists('${tableName}');\n }\n\n /**\n * Reverse the migrations.\n */\n public function down(): void\n {\n // Cannot recreate table without schema information\n // This is a one-way migration\n }\n};\n`;\n\n return {\n fileName,\n className,\n content,\n tables: [tableName],\n type: 'drop',\n };\n}\n\n/**\n * Extracts FK dependencies from a schema.\n * Returns array of schema names that this schema depends on.\n */\nfunction extractDependencies(schema: LoadedSchema): string[] {\n const deps: string[] = [];\n\n if (!schema.properties) {\n return deps;\n }\n\n for (const property of Object.values(schema.properties)) {\n if (property.type !== 'Association') {\n continue;\n }\n\n const assocProp = property as {\n relation?: string;\n target?: string;\n mappedBy?: string;\n };\n\n // ManyToOne and OneToOne (owning side) create FK columns\n if (\n (assocProp.relation === 'ManyToOne' || assocProp.relation === 'OneToOne') &&\n !assocProp.mappedBy &&\n assocProp.target\n ) {\n deps.push(assocProp.target);\n }\n }\n\n return deps;\n}\n\n/**\n * Topological sort of schemas based on FK dependencies.\n * Returns schemas in order where dependencies come before dependents.\n */\nfunction topologicalSort(schemas: SchemaCollection): LoadedSchema[] {\n const schemaList = Object.values(schemas).filter(s => s.kind !== 'enum');\n const sorted: LoadedSchema[] = [];\n const visited = new Set<string>();\n const visiting = new Set<string>(); // For cycle detection\n\n function visit(schema: LoadedSchema): void {\n if (visited.has(schema.name)) {\n return;\n }\n\n if (visiting.has(schema.name)) {\n // Circular dependency - just continue (FK can be nullable)\n return;\n }\n\n visiting.add(schema.name);\n\n // Visit dependencies first\n const deps = extractDependencies(schema);\n for (const depName of deps) {\n const depSchema = schemas[depName];\n if (depSchema && depSchema.kind !== 'enum') {\n visit(depSchema);\n }\n }\n\n visiting.delete(schema.name);\n visited.add(schema.name);\n sorted.push(schema);\n }\n\n // Visit all schemas\n for (const schema of schemaList) {\n visit(schema);\n }\n\n return sorted;\n}\n\n/**\n * Generates migrations for all schemas.\n */\nexport function generateMigrations(\n schemas: SchemaCollection,\n options: MigrationOptions = {}\n): MigrationFile[] {\n const migrations: MigrationFile[] = [];\n const pivotTablesGenerated = new Set<string>();\n let timestampOffset = 0;\n\n // Note: File table (for polymorphic file storage) is now managed as a proper schema (File.yaml)\n // It will be processed like any other schema in the topological sort below.\n // Use ensureFileSchema() from @famgia/omnify-core to auto-generate File.yaml when needed.\n\n // Sort schemas by FK dependencies (topological sort)\n const sortedSchemas = topologicalSort(schemas);\n\n // Generate main table migrations in dependency order\n for (const schema of sortedSchemas) {\n // Generate timestamp with offset to ensure unique filenames\n const timestamp = options.timestamp ?? generateTimestamp();\n const offsetTimestamp = incrementTimestamp(timestamp, timestampOffset);\n timestampOffset++;\n\n const blueprint = schemaToBlueprint(schema, schemas);\n const migration = generateCreateMigration(blueprint, {\n ...options,\n timestamp: offsetTimestamp,\n });\n migrations.push(migration);\n }\n\n // Third pass: generate pivot table migrations for ManyToMany (always last)\n for (const schema of sortedSchemas) {\n const pivotTables = extractManyToManyRelations(schema, schemas);\n\n for (const pivot of pivotTables) {\n // Skip if already generated\n if (pivotTablesGenerated.has(pivot.tableName)) {\n continue;\n }\n pivotTablesGenerated.add(pivot.tableName);\n\n const timestamp = options.timestamp ?? generateTimestamp();\n const offsetTimestamp = incrementTimestamp(timestamp, timestampOffset);\n timestampOffset++;\n\n const blueprint = generatePivotTableBlueprint(pivot);\n const migration = generateCreateMigration(blueprint, {\n ...options,\n timestamp: offsetTimestamp,\n });\n migrations.push(migration);\n }\n }\n\n return migrations;\n}\n\n/**\n * Increments a timestamp by seconds.\n */\nfunction incrementTimestamp(timestamp: string, seconds: number): string {\n if (seconds === 0) return timestamp;\n\n // Parse timestamp: YYYY_MM_DD_HHMMSS\n const parts = timestamp.split('_');\n if (parts.length < 4) {\n // Invalid format, return original\n return timestamp;\n }\n\n const yearPart = parts[0] ?? '2024';\n const monthPart = parts[1] ?? '01';\n const dayPart = parts[2] ?? '01';\n const timePart = parts[3] ?? '000000';\n\n const year = parseInt(yearPart, 10);\n const month = parseInt(monthPart, 10) - 1;\n const day = parseInt(dayPart, 10);\n const hours = parseInt(timePart.substring(0, 2), 10);\n const minutes = parseInt(timePart.substring(2, 4), 10);\n const secs = parseInt(timePart.substring(4, 6), 10);\n\n const date = new Date(year, month, day, hours, minutes, secs + seconds);\n\n const newYear = date.getFullYear();\n const newMonth = String(date.getMonth() + 1).padStart(2, '0');\n const newDay = String(date.getDate()).padStart(2, '0');\n const newHours = String(date.getHours()).padStart(2, '0');\n const newMinutes = String(date.getMinutes()).padStart(2, '0');\n const newSecs = String(date.getSeconds()).padStart(2, '0');\n\n return `${newYear}_${newMonth}_${newDay}_${newHours}${newMinutes}${newSecs}`;\n}\n\n/**\n * Generates migration from a single schema.\n */\nexport function generateMigrationFromSchema(\n schema: LoadedSchema,\n allSchemas: SchemaCollection,\n options: MigrationOptions = {}\n): MigrationFile {\n const blueprint = schemaToBlueprint(schema, allSchemas);\n return generateCreateMigration(blueprint, options);\n}\n\n/**\n * Generates drop migration for a table.\n */\nexport function generateDropMigrationForTable(\n tableName: string,\n options: MigrationOptions = {}\n): MigrationFile {\n return generateDropMigration(tableName, options);\n}\n\n/**\n * Formats migration content for writing to file.\n */\nexport function formatMigrationFile(migration: MigrationFile): string {\n return migration.content;\n}\n\n/**\n * Gets the output path for a migration file.\n */\nexport function getMigrationPath(\n migration: MigrationFile,\n outputDir: string = 'database/migrations'\n): string {\n return `${outputDir}/${migration.fileName}`;\n}\n","/**\n * Utility functions for Laravel generator.\n */\n\n/**\n * Convert a string to snake_case.\n */\nexport function toSnakeCase(str: string): string {\n return str\n .replace(/([A-Z])/g, '_$1')\n .replace(/^_/, '')\n .toLowerCase();\n}\n\n/**\n * Convert a string to PascalCase.\n */\nexport function toPascalCase(str: string): string {\n return str\n .replace(/[-_](.)/g, (_, c) => c.toUpperCase())\n .replace(/^(.)/, (_, c) => c.toUpperCase());\n}\n\n/**\n * Convert a string to camelCase.\n */\nexport function toCamelCase(str: string): string {\n const pascal = toPascalCase(str);\n return pascal.charAt(0).toLowerCase() + pascal.slice(1);\n}\n\n/**\n * Simple pluralization (English).\n */\nexport function pluralize(word: string): string {\n if (word.endsWith('y') && !['ay', 'ey', 'iy', 'oy', 'uy'].some(v => word.endsWith(v))) {\n return word.slice(0, -1) + 'ies';\n }\n if (word.endsWith('s') || word.endsWith('x') || word.endsWith('z') ||\n word.endsWith('ch') || word.endsWith('sh')) {\n return word + 'es';\n }\n return word + 's';\n}\n","/**\n * Laravel Model Generator\n *\n * Generates Eloquent model classes from Omnify schemas.\n * Creates base models (auto-generated) and user models (created once).\n */\n\nimport type { LoadedSchema, PropertyDefinition, AssociationDefinition, SchemaCollection } from '@famgia/omnify-types';\nimport { pluralize, toSnakeCase, toPascalCase, toCamelCase } from '../utils.js';\n\n/**\n * Options for model generation.\n */\nexport interface ModelGeneratorOptions {\n /**\n * Base model namespace.\n * @default 'App\\\\Models\\\\OmnifyBase'\n */\n baseModelNamespace?: string;\n\n /**\n * User model namespace.\n * @default 'App\\\\Models'\n */\n modelNamespace?: string;\n\n /**\n * Base model class name.\n * @default 'BaseModel'\n */\n baseModelClassName?: string;\n\n /**\n * Output path for base models.\n * @default 'app/Models/OmnifyBase'\n */\n baseModelPath?: string;\n\n /**\n * Output path for user models.\n * @default 'app/Models'\n */\n modelPath?: string;\n}\n\n/**\n * Generated model output.\n */\nexport interface GeneratedModel {\n /** File path relative to project root */\n path: string;\n /** PHP content */\n content: string;\n /** Model type */\n type: 'base-model' | 'entity-base' | 'entity';\n /** Whether to overwrite existing file */\n overwrite: boolean;\n /** Schema name */\n schemaName: string;\n}\n\n/**\n * Resolved options with defaults.\n */\ninterface ResolvedOptions {\n baseModelNamespace: string;\n modelNamespace: string;\n baseModelClassName: string;\n baseModelPath: string;\n modelPath: string;\n}\n\n/**\n * Default options.\n */\nconst DEFAULT_OPTIONS: ResolvedOptions = {\n baseModelNamespace: 'App\\\\Models\\\\OmnifyBase',\n modelNamespace: 'App\\\\Models',\n baseModelClassName: 'BaseModel',\n baseModelPath: 'app/Models/OmnifyBase',\n modelPath: 'app/Models',\n};\n\n/**\n * Resolve options with defaults.\n */\nfunction resolveOptions(options?: ModelGeneratorOptions): ResolvedOptions {\n return {\n baseModelNamespace: options?.baseModelNamespace ?? DEFAULT_OPTIONS.baseModelNamespace,\n modelNamespace: options?.modelNamespace ?? DEFAULT_OPTIONS.modelNamespace,\n baseModelClassName: options?.baseModelClassName ?? DEFAULT_OPTIONS.baseModelClassName,\n baseModelPath: options?.baseModelPath ?? DEFAULT_OPTIONS.baseModelPath,\n modelPath: options?.modelPath ?? DEFAULT_OPTIONS.modelPath,\n };\n}\n\n/**\n * Get PHP type for casting.\n */\nfunction getCastType(propDef: PropertyDefinition): string | null {\n switch (propDef.type) {\n case 'Boolean':\n return 'boolean';\n case 'Int':\n case 'BigInt':\n return 'integer';\n case 'Float':\n return 'float';\n case 'Decimal':\n return 'decimal:' + ((propDef as any).scale ?? 2);\n case 'Json':\n return 'array';\n case 'Date':\n return 'date';\n case 'Timestamp':\n return 'datetime';\n case 'Password':\n return 'hashed';\n default:\n return null;\n }\n}\n\n/**\n * Check if a property definition is nullable.\n * For associations, check the 'nullable' field if it exists as an extension.\n */\nfunction isNullable(propDef: PropertyDefinition): boolean {\n // BasePropertyDefinition has nullable, AssociationDefinition does not\n // But some schemas may define nullable on associations as an extension\n return 'nullable' in propDef && propDef.nullable === true;\n}\n\n/**\n * Get PHP doc type for a property.\n */\nfunction getPhpDocType(propDef: PropertyDefinition, schemas: SchemaCollection): string {\n const nullable = isNullable(propDef);\n\n switch (propDef.type) {\n case 'String':\n case 'Text':\n case 'LongText':\n case 'Email':\n case 'Password':\n return 'string' + (nullable ? '|null' : '');\n case 'Int':\n case 'BigInt':\n return 'int' + (nullable ? '|null' : '');\n case 'Float':\n case 'Decimal':\n return 'float' + (nullable ? '|null' : '');\n case 'Boolean':\n return 'bool' + (nullable ? '|null' : '');\n case 'Date':\n case 'Time':\n case 'Timestamp':\n return '\\\\Carbon\\\\Carbon' + (nullable ? '|null' : '');\n case 'Json':\n return 'array' + (nullable ? '|null' : '');\n case 'Enum':\n case 'EnumRef':\n return 'string' + (nullable ? '|null' : '');\n case 'Association': {\n const assoc = propDef as AssociationDefinition;\n if (assoc.target) {\n const className = toPascalCase(assoc.target);\n switch (assoc.relation) {\n case 'OneToMany':\n case 'ManyToMany':\n case 'MorphMany':\n case 'MorphToMany':\n case 'MorphedByMany':\n return `\\\\Illuminate\\\\Database\\\\Eloquent\\\\Collection<${className}>`;\n default:\n // ManyToOne, OneToOne - typically nullable unless owning\n return className + '|null';\n }\n }\n return 'mixed';\n }\n default:\n return 'mixed';\n }\n}\n\n/**\n * Generate the shared BaseModel class.\n */\nfunction generateBaseModel(\n schemas: SchemaCollection,\n options: ResolvedOptions,\n stubContent: string\n): GeneratedModel {\n // Build model map\n const modelMap = Object.values(schemas)\n .filter(s => s.kind !== 'enum')\n .map(s => {\n const className = toPascalCase(s.name);\n return ` '${s.name}' => \\\\${options.modelNamespace}\\\\${className}::class,`;\n })\n .join('\\n');\n\n const content = stubContent\n .replace(/\\{\\{BASE_MODEL_NAMESPACE\\}\\}/g, options.baseModelNamespace)\n .replace(/\\{\\{BASE_MODEL_CLASS\\}\\}/g, options.baseModelClassName)\n .replace(/\\{\\{MODEL_MAP\\}\\}/g, modelMap);\n\n return {\n path: `${options.baseModelPath}/${options.baseModelClassName}.php`,\n content,\n type: 'base-model',\n overwrite: true,\n schemaName: '__base__',\n };\n}\n\n/**\n * Generate entity base model (auto-generated).\n */\nfunction generateEntityBaseModel(\n schema: LoadedSchema,\n schemas: SchemaCollection,\n options: ResolvedOptions,\n stubContent: string,\n authStubContent: string\n): GeneratedModel {\n const className = toPascalCase(schema.name);\n const tableName = schema.options?.tableName ?? pluralize(toSnakeCase(schema.name));\n const isAuth = schema.options?.authenticatable ?? false;\n\n // Determine primary key\n const primaryKey = 'id';\n const idType = schema.options?.idType ?? 'BigInt';\n const isUuid = idType === 'Uuid';\n const isStringKey = idType === 'Uuid' || idType === 'String';\n\n // Build imports, traits, fillable, hidden, casts, relations\n const imports: string[] = [];\n const traits: string[] = [];\n const fillable: string[] = [];\n const hidden: string[] = [];\n const appends: string[] = [];\n const casts: string[] = [];\n const relations: string[] = [];\n const docProperties: string[] = [];\n\n // Add soft delete\n if (schema.options?.softDelete) {\n imports.push('use Illuminate\\\\Database\\\\Eloquent\\\\SoftDeletes;');\n traits.push(' use SoftDeletes;');\n }\n\n // Process properties\n const properties = schema.properties ?? {};\n for (const [propName, propDef] of Object.entries(properties)) {\n const snakeName = toSnakeCase(propName);\n\n // Add to doc comments\n const phpType = getPhpDocType(propDef, schemas);\n docProperties.push(` * @property ${phpType} $${snakeName}`);\n\n if (propDef.type === 'Association') {\n const assoc = propDef as AssociationDefinition;\n if (assoc.target) {\n imports.push(`use ${options.modelNamespace}\\\\${toPascalCase(assoc.target)};`);\n }\n relations.push(generateRelation(propName, assoc, options));\n\n // Add foreign key to fillable for belongsTo relations\n if (assoc.relation === 'ManyToOne' || assoc.relation === 'OneToOne') {\n if (!assoc.mappedBy) {\n const fkName = toSnakeCase(propName) + '_id';\n fillable.push(` '${fkName}',`);\n docProperties.push(` * @property int|null $${fkName}`);\n }\n }\n } else if (propDef.type === 'Password') {\n fillable.push(` '${snakeName}',`);\n hidden.push(` '${snakeName}',`);\n const cast = getCastType(propDef);\n if (cast) {\n casts.push(` '${snakeName}' => '${cast}',`);\n }\n } else if (propDef.type === 'File') {\n // File properties don't add to fillable (polymorphic)\n const relMethod = generateFileRelation(propName, propDef as any);\n relations.push(relMethod);\n } else {\n // Regular property\n fillable.push(` '${snakeName}',`);\n\n const cast = getCastType(propDef);\n if (cast) {\n casts.push(` '${snakeName}' => '${cast}',`);\n }\n }\n }\n\n // Build doc comment\n const docComment = `/**\n * ${className}BaseModel\n *\n${docProperties.join('\\n')}\n */`;\n\n // Choose stub based on authenticatable\n const stub = isAuth ? authStubContent : stubContent;\n\n // Build key type and incrementing\n const keyType = isStringKey ? ` /**\n * The \"type\" of the primary key ID.\n */\n protected $keyType = 'string';\n\n` : '';\n\n const incrementing = isUuid ? ` /**\n * Indicates if the IDs are auto-incrementing.\n */\n public $incrementing = false;\n\n` : '';\n\n // Add UUID trait if needed\n if (isUuid) {\n imports.push('use Illuminate\\\\Database\\\\Eloquent\\\\Concerns\\\\HasUuids;');\n traits.push(' use HasUuids;');\n }\n\n const content = stub\n .replace(/\\{\\{BASE_MODEL_NAMESPACE\\}\\}/g, options.baseModelNamespace)\n .replace(/\\{\\{BASE_MODEL_CLASS\\}\\}/g, options.baseModelClassName)\n .replace(/\\{\\{CLASS_NAME\\}\\}/g, className)\n .replace(/\\{\\{TABLE_NAME\\}\\}/g, tableName)\n .replace(/\\{\\{PRIMARY_KEY\\}\\}/g, primaryKey)\n .replace(/\\{\\{KEY_TYPE\\}\\}/g, keyType)\n .replace(/\\{\\{INCREMENTING\\}\\}/g, incrementing)\n .replace(/\\{\\{TIMESTAMPS\\}\\}/g, schema.options?.timestamps !== false ? 'true' : 'false')\n .replace(/\\{\\{IMPORTS\\}\\}/g, [...new Set(imports)].sort().join('\\n'))\n .replace(/\\{\\{TRAITS\\}\\}/g, traits.join('\\n'))\n .replace(/\\{\\{DOC_COMMENT\\}\\}/g, docComment)\n .replace(/\\{\\{FILLABLE\\}\\}/g, fillable.join('\\n'))\n .replace(/\\{\\{HIDDEN\\}\\}/g, hidden.join('\\n'))\n .replace(/\\{\\{APPENDS\\}\\}/g, appends.join('\\n'))\n .replace(/\\{\\{CASTS\\}\\}/g, casts.join('\\n'))\n .replace(/\\{\\{RELATIONS\\}\\}/g, relations.join('\\n\\n'));\n\n return {\n path: `${options.baseModelPath}/${className}BaseModel.php`,\n content,\n type: 'entity-base',\n overwrite: true,\n schemaName: schema.name,\n };\n}\n\n/**\n * Generate relation method.\n */\nfunction generateRelation(propName: string, assoc: AssociationDefinition, options: ResolvedOptions): string {\n const methodName = toCamelCase(propName);\n const targetClass = assoc.target ? toPascalCase(assoc.target) : '';\n const fkName = toSnakeCase(propName) + '_id';\n\n switch (assoc.relation) {\n case 'ManyToOne':\n return ` /**\n * Get the ${propName} that owns this model.\n */\n public function ${methodName}(): BelongsTo\n {\n return $this->belongsTo(${targetClass}::class, '${fkName}');\n }`;\n\n case 'OneToOne':\n if (assoc.mappedBy) {\n return ` /**\n * Get the ${propName} for this model.\n */\n public function ${methodName}(): HasOne\n {\n return $this->hasOne(${targetClass}::class, '${toSnakeCase(assoc.mappedBy)}_id');\n }`;\n }\n return ` /**\n * Get the ${propName} that owns this model.\n */\n public function ${methodName}(): BelongsTo\n {\n return $this->belongsTo(${targetClass}::class, '${fkName}');\n }`;\n\n case 'OneToMany':\n return ` /**\n * Get the ${propName} for this model.\n */\n public function ${methodName}(): HasMany\n {\n return $this->hasMany(${targetClass}::class, '${toSnakeCase(assoc.inversedBy ?? propName)}_id');\n }`;\n\n case 'ManyToMany': {\n const pivotTable = assoc.joinTable ?? `${toSnakeCase(propName)}_pivot`;\n return ` /**\n * The ${propName} that belong to this model.\n */\n public function ${methodName}(): BelongsToMany\n {\n return $this->belongsToMany(${targetClass}::class, '${pivotTable}')\n ->withTimestamps();\n }`;\n }\n\n case 'MorphTo':\n return ` /**\n * Get the parent ${propName} model.\n */\n public function ${methodName}(): MorphTo\n {\n return $this->morphTo('${methodName}');\n }`;\n\n case 'MorphOne':\n return ` /**\n * Get the ${propName} for this model.\n */\n public function ${methodName}(): MorphOne\n {\n return $this->morphOne(${targetClass}::class, '${assoc.morphName ?? propName}');\n }`;\n\n case 'MorphMany':\n return ` /**\n * Get the ${propName} for this model.\n */\n public function ${methodName}(): MorphMany\n {\n return $this->morphMany(${targetClass}::class, '${assoc.morphName ?? propName}');\n }`;\n\n default:\n return ` // TODO: Implement ${assoc.relation} relation for ${propName}`;\n }\n}\n\n/**\n * Generate file relation method.\n */\nfunction generateFileRelation(propName: string, propDef: { multiple?: boolean }): string {\n const methodName = toCamelCase(propName);\n const relationType = propDef.multiple ? 'MorphMany' : 'MorphOne';\n const relationMethod = propDef.multiple ? 'morphMany' : 'morphOne';\n\n return ` /**\n * Get the ${propName} file(s) for this model.\n */\n public function ${methodName}(): ${relationType}\n {\n return $this->${relationMethod}(FileUpload::class, 'uploadable')\n ->where('attribute_name', '${propName}');\n }`;\n}\n\n/**\n * Generate user model (created once, not overwritten).\n */\nfunction generateEntityModel(\n schema: LoadedSchema,\n options: ResolvedOptions,\n stubContent: string\n): GeneratedModel {\n const className = toPascalCase(schema.name);\n\n const content = stubContent\n .replace(/\\{\\{BASE_MODEL_NAMESPACE\\}\\}/g, options.baseModelNamespace)\n .replace(/\\{\\{MODEL_NAMESPACE\\}\\}/g, options.modelNamespace)\n .replace(/\\{\\{CLASS_NAME\\}\\}/g, className);\n\n return {\n path: `${options.modelPath}/${className}.php`,\n content,\n type: 'entity',\n overwrite: false, // Never overwrite user models\n schemaName: schema.name,\n };\n}\n\n/**\n * Read stub file content.\n */\nfunction getStubContent(stubName: string): string {\n // Stubs are embedded as strings since this runs in Node.js\n const stubs: Record<string, string> = {\n 'base-model': `<?php\n\nnamespace {{BASE_MODEL_NAMESPACE}};\n\n/**\n * Base model class for all Omnify-generated models.\n * Contains model mapping for polymorphic relations.\n *\n * DO NOT EDIT - This file is auto-generated by Omnify.\n * Any changes will be overwritten on next generation.\n *\n * @generated by @famgia/omnify-laravel\n */\n\nuse Illuminate\\\\Database\\\\Eloquent\\\\Model;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\Relation;\n\nabstract class {{BASE_MODEL_CLASS}} extends Model\n{\n /**\n * Model class map for polymorphic relations.\n */\n protected static array $modelMap = [\n{{MODEL_MAP}}\n ];\n\n /**\n * Boot the model and register morph map.\n */\n protected static function boot(): void\n {\n parent::boot();\n\n // Register morph map for polymorphic relations\n Relation::enforceMorphMap(static::$modelMap);\n }\n\n /**\n * Get the model class for a given morph type.\n */\n public static function getModelClass(string $morphType): ?string\n {\n return static::$modelMap[$morphType] ?? null;\n }\n}\n`,\n\n 'entity-base': `<?php\n\nnamespace {{BASE_MODEL_NAMESPACE}};\n\n/**\n * DO NOT EDIT - This file is auto-generated by Omnify.\n * Any changes will be overwritten on next generation.\n *\n * @generated by @famgia/omnify-laravel\n */\n\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\BelongsTo;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\HasMany;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\HasOne;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\BelongsToMany;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\MorphTo;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\MorphOne;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\MorphMany;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\MorphToMany;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Collection as EloquentCollection;\n{{IMPORTS}}\n\n{{DOC_COMMENT}}\nclass {{CLASS_NAME}}BaseModel extends {{BASE_MODEL_CLASS}}\n{\n{{TRAITS}}\n /**\n * The table associated with the model.\n */\n protected $table = '{{TABLE_NAME}}';\n\n /**\n * The primary key for the model.\n */\n protected $primaryKey = '{{PRIMARY_KEY}}';\n\n{{KEY_TYPE}}\n{{INCREMENTING}}\n /**\n * Indicates if the model should be timestamped.\n */\n public $timestamps = {{TIMESTAMPS}};\n\n /**\n * The attributes that are mass assignable.\n */\n protected $fillable = [\n{{FILLABLE}}\n ];\n\n /**\n * The attributes that should be hidden for serialization.\n */\n protected $hidden = [\n{{HIDDEN}}\n ];\n\n /**\n * The accessors to append to the model's array form.\n */\n protected $appends = [\n{{APPENDS}}\n ];\n\n /**\n * Get the attributes that should be cast.\n */\n protected function casts(): array\n {\n return [\n{{CASTS}}\n ];\n }\n\n{{RELATIONS}}\n}\n`,\n\n 'entity-base-auth': `<?php\n\nnamespace {{BASE_MODEL_NAMESPACE}};\n\n/**\n * DO NOT EDIT - This file is auto-generated by Omnify.\n * Any changes will be overwritten on next generation.\n *\n * @generated by @famgia/omnify-laravel\n */\n\nuse Illuminate\\\\Foundation\\\\Auth\\\\User as Authenticatable;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\BelongsTo;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\HasMany;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\HasOne;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\BelongsToMany;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\MorphTo;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\MorphOne;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\MorphMany;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\MorphToMany;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Collection as EloquentCollection;\nuse Illuminate\\\\Notifications\\\\Notifiable;\n{{IMPORTS}}\n\n{{DOC_COMMENT}}\nclass {{CLASS_NAME}}BaseModel extends Authenticatable\n{\n use Notifiable;\n{{TRAITS}}\n /**\n * The table associated with the model.\n */\n protected $table = '{{TABLE_NAME}}';\n\n /**\n * The primary key for the model.\n */\n protected $primaryKey = '{{PRIMARY_KEY}}';\n\n{{KEY_TYPE}}\n{{INCREMENTING}}\n /**\n * Indicates if the model should be timestamped.\n */\n public $timestamps = {{TIMESTAMPS}};\n\n /**\n * The attributes that are mass assignable.\n */\n protected $fillable = [\n{{FILLABLE}}\n ];\n\n /**\n * The attributes that should be hidden for serialization.\n */\n protected $hidden = [\n{{HIDDEN}}\n ];\n\n /**\n * The accessors to append to the model's array form.\n */\n protected $appends = [\n{{APPENDS}}\n ];\n\n /**\n * Get the attributes that should be cast.\n */\n protected function casts(): array\n {\n return [\n{{CASTS}}\n ];\n }\n\n{{RELATIONS}}\n}\n`,\n\n 'entity': `<?php\n\nnamespace {{MODEL_NAMESPACE}};\n\nuse {{BASE_MODEL_NAMESPACE}}\\\\{{CLASS_NAME}}BaseModel;\nuse Illuminate\\\\Database\\\\Eloquent\\\\Factories\\\\HasFactory;\n\n/**\n * {{CLASS_NAME}} Model\n *\n * This file is generated once and can be customized.\n * Add your custom methods and logic here.\n */\nclass {{CLASS_NAME}} extends {{CLASS_NAME}}BaseModel\n{\n use HasFactory;\n\n /**\n * Create a new model instance.\n */\n public function __construct(array $attributes = [])\n {\n parent::__construct($attributes);\n }\n\n // Add your custom methods here\n}\n`,\n };\n\n return stubs[stubName] ?? '';\n}\n\n/**\n * Generate all models for the given schemas.\n */\nexport function generateModels(\n schemas: SchemaCollection,\n options?: ModelGeneratorOptions\n): GeneratedModel[] {\n const resolved = resolveOptions(options);\n const models: GeneratedModel[] = [];\n\n // Generate shared base model\n models.push(generateBaseModel(schemas, resolved, getStubContent('base-model')));\n\n // Generate models for each schema (excluding enums)\n for (const schema of Object.values(schemas)) {\n if (schema.kind === 'enum') {\n continue;\n }\n\n // Generate entity base model (always overwritten)\n models.push(generateEntityBaseModel(\n schema,\n schemas,\n resolved,\n getStubContent('entity-base'),\n getStubContent('entity-base-auth')\n ));\n\n // Generate user model (created once)\n models.push(generateEntityModel(schema, resolved, getStubContent('entity')));\n }\n\n return models;\n}\n\n/**\n * Get the output path for a model.\n */\nexport function getModelPath(model: GeneratedModel): string {\n return model.path;\n}\n"],"mappings":"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","names":["resolveOptions"]}
|
package/dist/plugin.d.cts
CHANGED
|
@@ -3,7 +3,7 @@ import { OmnifyPlugin } from '@famgia/omnify-types';
|
|
|
3
3
|
/**
|
|
4
4
|
* @famgia/omnify-laravel - Plugin
|
|
5
5
|
*
|
|
6
|
-
* Plugin for generating Laravel migration files from Omnify schemas.
|
|
6
|
+
* Plugin for generating Laravel migration files and Eloquent models from Omnify schemas.
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
9
|
* ```typescript
|
|
@@ -14,6 +14,7 @@ import { OmnifyPlugin } from '@famgia/omnify-types';
|
|
|
14
14
|
* plugins: [
|
|
15
15
|
* laravel({
|
|
16
16
|
* migrationsPath: 'database/migrations',
|
|
17
|
+
* modelsPath: 'app/Models',
|
|
17
18
|
* connection: 'mysql',
|
|
18
19
|
* }),
|
|
19
20
|
* ],
|
|
@@ -30,6 +31,31 @@ interface LaravelPluginOptions {
|
|
|
30
31
|
* @default 'database/migrations'
|
|
31
32
|
*/
|
|
32
33
|
migrationsPath?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Path for user-editable model files.
|
|
36
|
+
* @default 'app/Models'
|
|
37
|
+
*/
|
|
38
|
+
modelsPath?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Path for auto-generated base model files.
|
|
41
|
+
* @default 'app/Models/OmnifyBase'
|
|
42
|
+
*/
|
|
43
|
+
baseModelsPath?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Model namespace.
|
|
46
|
+
* @default 'App\\Models'
|
|
47
|
+
*/
|
|
48
|
+
modelNamespace?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Base model namespace.
|
|
51
|
+
* @default 'App\\Models\\OmnifyBase'
|
|
52
|
+
*/
|
|
53
|
+
baseModelNamespace?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Whether to generate Eloquent models.
|
|
56
|
+
* @default true
|
|
57
|
+
*/
|
|
58
|
+
generateModels?: boolean;
|
|
33
59
|
/**
|
|
34
60
|
* Database connection name for migrations.
|
|
35
61
|
*/
|
|
@@ -43,7 +69,7 @@ interface LaravelPluginOptions {
|
|
|
43
69
|
* Creates the Laravel plugin with the specified options.
|
|
44
70
|
*
|
|
45
71
|
* @param options - Plugin configuration options
|
|
46
|
-
* @returns OmnifyPlugin configured for Laravel migrations
|
|
72
|
+
* @returns OmnifyPlugin configured for Laravel migrations and models
|
|
47
73
|
*/
|
|
48
74
|
declare function laravelPlugin(options?: LaravelPluginOptions): OmnifyPlugin;
|
|
49
75
|
|
package/dist/plugin.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { OmnifyPlugin } from '@famgia/omnify-types';
|
|
|
3
3
|
/**
|
|
4
4
|
* @famgia/omnify-laravel - Plugin
|
|
5
5
|
*
|
|
6
|
-
* Plugin for generating Laravel migration files from Omnify schemas.
|
|
6
|
+
* Plugin for generating Laravel migration files and Eloquent models from Omnify schemas.
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
9
|
* ```typescript
|
|
@@ -14,6 +14,7 @@ import { OmnifyPlugin } from '@famgia/omnify-types';
|
|
|
14
14
|
* plugins: [
|
|
15
15
|
* laravel({
|
|
16
16
|
* migrationsPath: 'database/migrations',
|
|
17
|
+
* modelsPath: 'app/Models',
|
|
17
18
|
* connection: 'mysql',
|
|
18
19
|
* }),
|
|
19
20
|
* ],
|
|
@@ -30,6 +31,31 @@ interface LaravelPluginOptions {
|
|
|
30
31
|
* @default 'database/migrations'
|
|
31
32
|
*/
|
|
32
33
|
migrationsPath?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Path for user-editable model files.
|
|
36
|
+
* @default 'app/Models'
|
|
37
|
+
*/
|
|
38
|
+
modelsPath?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Path for auto-generated base model files.
|
|
41
|
+
* @default 'app/Models/OmnifyBase'
|
|
42
|
+
*/
|
|
43
|
+
baseModelsPath?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Model namespace.
|
|
46
|
+
* @default 'App\\Models'
|
|
47
|
+
*/
|
|
48
|
+
modelNamespace?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Base model namespace.
|
|
51
|
+
* @default 'App\\Models\\OmnifyBase'
|
|
52
|
+
*/
|
|
53
|
+
baseModelNamespace?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Whether to generate Eloquent models.
|
|
56
|
+
* @default true
|
|
57
|
+
*/
|
|
58
|
+
generateModels?: boolean;
|
|
33
59
|
/**
|
|
34
60
|
* Database connection name for migrations.
|
|
35
61
|
*/
|
|
@@ -43,7 +69,7 @@ interface LaravelPluginOptions {
|
|
|
43
69
|
* Creates the Laravel plugin with the specified options.
|
|
44
70
|
*
|
|
45
71
|
* @param options - Plugin configuration options
|
|
46
|
-
* @returns OmnifyPlugin configured for Laravel migrations
|
|
72
|
+
* @returns OmnifyPlugin configured for Laravel migrations and models
|
|
47
73
|
*/
|
|
48
74
|
declare function laravelPlugin(options?: LaravelPluginOptions): OmnifyPlugin;
|
|
49
75
|
|
package/dist/plugin.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@famgia/omnify-laravel",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "Laravel migration and TypeScript type generator for omnify-schema",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@famgia/omnify-types": "0.0.9",
|
|
27
|
-
"@famgia/omnify-core": "0.0.
|
|
27
|
+
"@famgia/omnify-core": "0.0.11",
|
|
28
28
|
"@famgia/omnify-atlas": "0.0.9"
|
|
29
29
|
},
|
|
30
30
|
"scripts": {
|