Files
WRNexusJS/packages/dev-server/src/plugin-migrations.ts
T
2026-07-27 12:42:18 +05:30

57 lines
2.0 KiB
TypeScript

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 ?? "<empty>"}.`,
);
}
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;
}