import { existsSync, readFileSync, statSync } from "node:fs"; import { basename } from "node:path"; import { loadMigrations, parseMigration, type Migration } from "@wrnexus/db"; import type { PackageMigrationDefinition } from "@wrnexus/plugin"; function migrationName(definition: PackageMigrationDefinition, name?: string): string { const prefix = definition.id.trim().replace(/[^a-zA-Z0-9_.-]+/g, "_"); const suffix = name?.trim().replace(/[^a-zA-Z0-9_.-]+/g, "_"); return suffix ? `${prefix}__${suffix}` : prefix; } function databaseMatches(definition: PackageMigrationDefinition, database?: string): boolean { const target = definition.database?.trim() || "default"; return target === (database?.trim() || "default"); } /** Resolve package-owned migrations into the same ordered contract as app migrations. */ export function resolvePackageMigrations( definitions: readonly PackageMigrationDefinition[], database?: string, ): Migration[] { const output: Migration[] = []; for (const definition of definitions) { if (!databaseMatches(definition, database)) continue; if (definition.source !== undefined) { const parsed = parseMigration(migrationName(definition), definition.source); output.push(parsed); continue; } const entry = definition.entry; if (!entry || !existsSync(entry)) { throw new Error( `WRN-PLUGIN-MIGRATION-MISSING: ${definition.id} points to ${entry ?? ""}.`, ); } const stat = statSync(entry); if (stat.isDirectory()) { for (const migration of loadMigrations(entry)) { output.push({ ...migration, name: migrationName(definition, migration.name) }); } continue; } if (!stat.isFile() || !entry.endsWith(".sql")) { throw new Error( `WRN-PLUGIN-MIGRATION-ENTRY: ${definition.id} must be a .sql file or directory.`, ); } output.push( parseMigration( migrationName(definition, basename(entry, ".sql")), readFileSync(entry, "utf8"), ), ); } return output; }