@emigrate/cli
Version:
Emigrate is a tool for managing database migrations. It is designed to be simple yet support advanced setups, modular and extensible.
110 lines • 4.92 kB
JavaScript
import { hrtime } from 'node:process';
import fs from 'node:fs/promises';
import path from 'node:path';
import { getTimestampPrefix, sanitizeMigrationName, getOrLoadPlugin, getOrLoadReporter } from '@emigrate/plugin-tools';
import { isFailedMigration } from '@emigrate/types';
import { BadOptionError, EmigrateError, MissingArgumentsError, MissingOptionError, UnexpectedError, toError, } from '../errors.js';
import { withLeadingPeriod } from '../with-leading-period.js';
import { version } from '../get-package-info.js';
import { getDuration } from '../get-duration.js';
import { getStandardReporter } from '../reporters/get.js';
export default async function newCommand({ directory, template, reporter: reporterConfig, plugins = [], cwd, extension, color }, name) {
if (!directory) {
throw MissingOptionError.fromOption('directory');
}
if (!name) {
throw MissingArgumentsError.fromArgument('name');
}
if (!extension && !template && plugins.length === 0) {
throw MissingOptionError.fromOption(['extension', 'template', 'plugin']);
}
const reporter = getStandardReporter(reporterConfig) ?? (await getOrLoadReporter([reporterConfig]));
if (!reporter) {
throw BadOptionError.fromOption('reporter', 'No reporter found, please specify an existing reporter using the reporter option');
}
await reporter.onInit?.({ command: 'new', version, cwd, dry: false, directory, color });
const start = hrtime();
let filename;
let content;
if (template) {
const fs = await import('node:fs/promises');
const templatePath = path.resolve(cwd, template);
const fileExtension = path.extname(templatePath);
try {
content = await fs.readFile(templatePath, 'utf8');
content = content.replaceAll('{{name}}', name);
}
catch (error) {
await reporter.onFinished?.([], new UnexpectedError(`Failed to read template file: ${templatePath}`, { cause: error }));
return;
}
filename = `${getTimestampPrefix()}_${sanitizeMigrationName(name)}${withLeadingPeriod(extension ?? fileExtension)}`;
}
let hasGeneratedFile = Boolean(filename && content !== undefined);
if (plugins.length > 0 && !hasGeneratedFile) {
const generatorPlugin = await getOrLoadPlugin('generator', plugins);
if (generatorPlugin) {
const generated = await generatorPlugin.generateMigration(name);
filename = generated.filename;
content = generated.content;
}
}
hasGeneratedFile = Boolean(filename && content !== undefined);
if (extension && !hasGeneratedFile) {
content = '';
filename = `${getTimestampPrefix()}_${sanitizeMigrationName(name)}${withLeadingPeriod(extension)}`;
}
if (!filename || content === undefined) {
throw BadOptionError.fromOption('plugin', 'No generator plugin found, please specify a generator plugin using the plugin option');
}
const directoryPath = path.resolve(cwd, directory);
const filePath = path.resolve(directoryPath, filename);
const migration = {
name: filename,
filePath,
relativeFilePath: path.relative(cwd, filePath),
extension: withLeadingPeriod(path.extname(filename)),
directory,
cwd,
};
await reporter.onNewMigration?.(migration, content);
const finishedMigrations = [];
try {
await createDirectory(directoryPath);
await saveFile(filePath, content);
const duration = getDuration(start);
finishedMigrations.push({ ...migration, status: 'done', duration });
}
catch (error) {
const duration = getDuration(start);
const errorInstance = toError(error);
finishedMigrations.push({ ...migration, status: 'failed', duration, error: errorInstance });
}
// eslint-disable-next-line unicorn/no-array-callback-reference
const firstFailed = finishedMigrations.find(isFailedMigration);
const firstError = firstFailed?.error instanceof EmigrateError
? firstFailed.error
: firstFailed
? new UnexpectedError(`Failed to create migration file: ${firstFailed.relativeFilePath}`, {
cause: firstFailed?.error,
})
: undefined;
await reporter.onFinished?.(finishedMigrations, firstError);
}
async function createDirectory(directoryPath) {
try {
await fs.mkdir(directoryPath, { recursive: true });
}
catch (error) {
throw new UnexpectedError(`Failed to create migration directory: ${directoryPath}`, { cause: error });
}
}
async function saveFile(filePath, content) {
try {
await fs.writeFile(filePath, content);
}
catch (error) {
throw new UnexpectedError(`Failed to write migration file: ${filePath}`, { cause: error });
}
}
//# sourceMappingURL=new.js.map