/** * migration-name.ts — Pure naming formatter. * * Convention ported from the global /efcore agents (without MCP): * {contextPrefix}_v{version_underscore}_{seq3}_{PascalCaseDescription} * * Examples: * core_v0_4_0_007_AddEmployeeAvatar * ext_v1_0_0_003_CreateOrders * studio_v1_0_0_005_AddBugWorkflow * * - `contextPrefix` is lowercased and collapsed (ExtensionsDbContext → ext, * CoreDbContext → core, StudioDbContext → studio). * - Description is PascalCase with only [A-Za-z0-9] characters. Empty input * throws — the caller must validate. */ import { normalizeVersionForName } from './parse-csproj-version.js'; export interface MigrationNameInput { contextName: string; version: string; sequence: number; description: string; } export function contextPrefix(contextName: string): string { const stripped = contextName.replace(/DbContext$/i, '').replace(/Context$/i, ''); const lower = stripped.toLowerCase(); if (lower === 'extensions') return 'ext'; if (lower === 'extension') return 'ext'; return lower || 'db'; } export function toPascalCase(input: string): string { const parts = input .replace(/[^A-Za-z0-9\s_-]/g, ' ') .split(/[\s_-]+/) .filter(Boolean); if (parts.length === 0) return ''; return parts.map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(''); } export function padSequence(n: number): string { return String(Math.max(0, Math.floor(n))).padStart(3, '0'); } export function buildMigrationName(input: MigrationNameInput): string { const desc = toPascalCase(input.description); if (!desc) { throw new Error('description must contain at least one alphanumeric character'); } const prefix = contextPrefix(input.contextName); const vPart = normalizeVersionForName(input.version); const seq = padSequence(input.sequence); return `${prefix}_v${vPart}_${seq}_${desc}`; }