feat(cli): improve "up" command output and flow a lot
This commit is contained in:
parent
e5eec7cdf1
commit
59ec16b87b
14 changed files with 533 additions and 62 deletions
5
.changeset/great-spies-obey.md
Normal file
5
.changeset/great-spies-obey.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@emigrate/cli': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Make the dry run mode work for the "up" command using the "--dry" CLI option
|
||||||
5
.changeset/loud-comics-obey.md
Normal file
5
.changeset/loud-comics-obey.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@emigrate/cli': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Improve the default reporter with good looking output that has colors and animations. In non-interactive environments the animations are not used (this includes CI environments).
|
||||||
5
.changeset/many-items-kneel.md
Normal file
5
.changeset/many-items-kneel.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@emigrate/cli': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Improve the "up" command flow and the usage of reporters, handle migration errors and automatic skipping of migrations.
|
||||||
|
|
@ -56,7 +56,8 @@
|
||||||
"space": true,
|
"space": true,
|
||||||
"prettier": true,
|
"prettier": true,
|
||||||
"rules": {
|
"rules": {
|
||||||
"complexity": 0
|
"complexity": 0,
|
||||||
|
"capitalized-comments": 0
|
||||||
},
|
},
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,13 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emigrate/plugin-tools": "workspace:*",
|
"@emigrate/plugin-tools": "workspace:*",
|
||||||
"cosmiconfig": "8.3.6"
|
"ansis": "2.0.2",
|
||||||
|
"cosmiconfig": "8.3.6",
|
||||||
|
"elegant-spinner": "3.0.0",
|
||||||
|
"figures": "6.0.1",
|
||||||
|
"is-interactive": "2.0.0",
|
||||||
|
"log-update": "6.0.0",
|
||||||
|
"pretty-ms": "8.0.0"
|
||||||
},
|
},
|
||||||
"volta": {
|
"volta": {
|
||||||
"extends": "../../package.json"
|
"extends": "../../package.json"
|
||||||
|
|
|
||||||
|
|
@ -213,6 +213,4 @@ try {
|
||||||
} else {
|
} else {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
process.exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
export * from './types.js';
|
export * from './types.js';
|
||||||
|
|
||||||
export const emigrate = () => {
|
export const emigrate = () => {
|
||||||
console.log('Done!');
|
// console.log('Done!');
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import path from 'node:path';
|
||||||
import { getTimestampPrefix, sanitizeMigrationName, getOrLoadPlugin } from '@emigrate/plugin-tools';
|
import { getTimestampPrefix, sanitizeMigrationName, getOrLoadPlugin } from '@emigrate/plugin-tools';
|
||||||
import { BadOptionError, MissingArgumentsError, MissingOptionError, UnexpectedError } from './errors.js';
|
import { BadOptionError, MissingArgumentsError, MissingOptionError, UnexpectedError } from './errors.js';
|
||||||
import { type Config } from './types.js';
|
import { type Config } from './types.js';
|
||||||
import { stripLeadingPeriod } from './strip-leading-period.js';
|
import { withLeadingPeriod } from './with-leading-period.js';
|
||||||
|
|
||||||
export default async function newCommand({ directory, template, plugins = [], extension }: Config, name: string) {
|
export default async function newCommand({ directory, template, plugins = [], extension }: Config, name: string) {
|
||||||
if (!directory) {
|
if (!directory) {
|
||||||
|
|
@ -34,7 +34,7 @@ export default async function newCommand({ directory, template, plugins = [], ex
|
||||||
throw new UnexpectedError(`Failed to read template file: ${templatePath}`, { cause: error });
|
throw new UnexpectedError(`Failed to read template file: ${templatePath}`, { cause: error });
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = `${getTimestampPrefix()}_${sanitizeMigrationName(name)}.${stripLeadingPeriod(
|
filename = `${getTimestampPrefix()}_${sanitizeMigrationName(name)}.${withLeadingPeriod(
|
||||||
extension ?? fileExtension,
|
extension ?? fileExtension,
|
||||||
)}`;
|
)}`;
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +56,7 @@ export default async function newCommand({ directory, template, plugins = [], ex
|
||||||
|
|
||||||
if (extension && !hasGeneratedFile) {
|
if (extension && !hasGeneratedFile) {
|
||||||
content = '';
|
content = '';
|
||||||
filename = `${getTimestampPrefix()}_${sanitizeMigrationName(name)}.${stripLeadingPeriod(extension)}`;
|
filename = `${getTimestampPrefix()}_${sanitizeMigrationName(name)}.${withLeadingPeriod(extension)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!filename || content === undefined) {
|
if (!filename || content === undefined) {
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,344 @@
|
||||||
import { type ReporterPlugin } from '@emigrate/plugin-tools/types';
|
import path from 'node:path';
|
||||||
|
import ansis from 'ansis';
|
||||||
|
import logUpdate from 'log-update';
|
||||||
|
import elegantSpinner from 'elegant-spinner';
|
||||||
|
import figures from 'figures';
|
||||||
|
import isInteractive from 'is-interactive';
|
||||||
|
import prettyMs from 'pretty-ms';
|
||||||
|
import {
|
||||||
|
type MigrationMetadata,
|
||||||
|
type MigrationMetadataFinished,
|
||||||
|
type ReporterPlugin,
|
||||||
|
} from '@emigrate/plugin-tools/types';
|
||||||
|
|
||||||
const reporterDefault: ReporterPlugin = {
|
type Status = ReturnType<typeof getMigrationStatus>;
|
||||||
onInit({ dry, directory }) {
|
|
||||||
console.log(`Running migrations in: ${directory}${dry ? ' (dry run)' : ''}`);
|
|
||||||
},
|
|
||||||
onCollectedMigrations(migrations) {
|
|
||||||
console.log(`Found ${migrations.length} pending migrations`);
|
|
||||||
},
|
|
||||||
onLockedMigrations(migrations) {
|
|
||||||
console.log(`Locked ${migrations.length} migrations`);
|
|
||||||
},
|
|
||||||
onMigrationStart(migration) {
|
|
||||||
console.log(`- ${migration.relativeFilePath} (running)`);
|
|
||||||
},
|
|
||||||
onMigrationSuccess(migration) {
|
|
||||||
console.log(`- ${migration.relativeFilePath} (success) [${migration.duration}ms]`);
|
|
||||||
},
|
|
||||||
onMigrationError(migration, error) {
|
|
||||||
console.error(`- ${migration.relativeFilePath} (failed!) [${migration.duration}ms]`);
|
|
||||||
console.error(error.cause ?? error);
|
|
||||||
},
|
|
||||||
onMigrationSkip(migration) {
|
|
||||||
console.log(`- ${migration.relativeFilePath} (skipped)`);
|
|
||||||
},
|
|
||||||
onFinished(migrations, error) {
|
|
||||||
const totalDuration = migrations.reduce((total, migration) => total + migration.duration, 0);
|
|
||||||
|
|
||||||
if (error) {
|
const interactive = isInteractive();
|
||||||
console.error('Failed to run migrations! [total duration: %dms]', totalDuration);
|
const spinner = interactive ? elegantSpinner() : () => figures.pointerSmall;
|
||||||
console.error(error.cause ?? error);
|
|
||||||
|
const formatDuration = (duration: number): string => {
|
||||||
|
const pretty = prettyMs(duration);
|
||||||
|
|
||||||
|
return ansis.yellow(pretty.replaceAll(/([^\s\d]+)/g, ansis.dim('$1')));
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTitle = ({ directory, dry, cwd }: { directory: string; dry: boolean; cwd: string }) => {
|
||||||
|
return `${ansis.bgBlueBright(ansis.black(' Emigrate '))} ${ansis.gray(cwd + path.sep)}${directory}${
|
||||||
|
dry ? ansis.yellow(' (dry run)') : ''
|
||||||
|
}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMigrationStatus = (
|
||||||
|
migration: MigrationMetadata | MigrationMetadataFinished,
|
||||||
|
activeMigration?: MigrationMetadata,
|
||||||
|
) => {
|
||||||
|
if ('status' in migration) {
|
||||||
|
return migration.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return migration.name === activeMigration?.name ? 'running' : 'pending';
|
||||||
|
};
|
||||||
|
|
||||||
|
const getIcon = (status: Status) => {
|
||||||
|
switch (status) {
|
||||||
|
case 'running': {
|
||||||
|
return ansis.cyan(spinner());
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'pending': {
|
||||||
|
return ansis.gray(figures.pointerSmall);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'done': {
|
||||||
|
return ansis.green(figures.tick);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'failed': {
|
||||||
|
return ansis.red(figures.cross);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'skipped': {
|
||||||
|
return ansis.yellow(figures.circle);
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getName = (name: string, status?: Status) => {
|
||||||
|
switch (status) {
|
||||||
|
case 'failed': {
|
||||||
|
return ansis.red(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'skipped': {
|
||||||
|
return ansis.yellow(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMigrationText = (
|
||||||
|
migration: MigrationMetadata | MigrationMetadataFinished,
|
||||||
|
activeMigration?: MigrationMetadata,
|
||||||
|
) => {
|
||||||
|
const nameWithoutExtension = migration.name.slice(0, -migration.extension.length);
|
||||||
|
const status = getMigrationStatus(migration, activeMigration);
|
||||||
|
const parts = [' ', getIcon(status)];
|
||||||
|
|
||||||
|
parts.push(`${getName(nameWithoutExtension, status)}${ansis.dim(migration.extension)}`);
|
||||||
|
|
||||||
|
if ('status' in migration) {
|
||||||
|
parts.push(ansis.gray(`(${migration.status})`));
|
||||||
|
} else if (migration.name === activeMigration?.name) {
|
||||||
|
parts.push(ansis.gray('(running)'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('duration' in migration && migration.duration) {
|
||||||
|
parts.push(formatDuration(migration.duration));
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.join(' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
const getError = (error?: Error, indent = ' ') => {
|
||||||
|
if (!error) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
let errorTitle: string;
|
||||||
|
let stack: string[] = [];
|
||||||
|
|
||||||
|
if (error.stack) {
|
||||||
|
// @ts-expect-error error won't be undefined here
|
||||||
|
[errorTitle, ...stack] = error.stack.split('\n');
|
||||||
|
} else if (error.name) {
|
||||||
|
errorTitle = `${error.name}: ${error.message}`;
|
||||||
|
} else {
|
||||||
|
errorTitle = error.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts = [`${indent}${ansis.bold.red(errorTitle)}`, ...stack.map((line) => `${indent}${ansis.dim(line)}`)];
|
||||||
|
|
||||||
|
if (error.cause instanceof Error) {
|
||||||
|
const nextIndent = `${indent} `;
|
||||||
|
parts.push(`\n${nextIndent}${ansis.bold('Original error cause:')}\n`, getError(error.cause, nextIndent));
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.join('\n');
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSummary = (migrations: Array<MigrationMetadata | MigrationMetadataFinished> = []) => {
|
||||||
|
const total = migrations.length;
|
||||||
|
let done = 0;
|
||||||
|
let failed = 0;
|
||||||
|
let skipped = 0;
|
||||||
|
|
||||||
|
for (const migration of migrations) {
|
||||||
|
const status = getMigrationStatus(migration);
|
||||||
|
switch (status) {
|
||||||
|
case 'done': {
|
||||||
|
done++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'failed': {
|
||||||
|
failed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'skipped': {
|
||||||
|
skipped++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusLine = [
|
||||||
|
failed ? ansis.bold.red(`${failed} failed`) : '',
|
||||||
|
done ? ansis.bold.green(`${done} done`) : '',
|
||||||
|
skipped ? ansis.bold.yellow(`${skipped} skipped`) : '',
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(ansis.dim(' | '));
|
||||||
|
|
||||||
|
if (!statusLine) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return ` ${statusLine}${ansis.gray(` (${total} total)`)}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getHeaderMessage = (migrations?: MigrationMetadata[], lockedMigrations?: MigrationMetadata[]) => {
|
||||||
|
if (!migrations || !lockedMigrations) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (migrations.length === 0) {
|
||||||
|
return ' No pending migrations found';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (migrations.length === lockedMigrations.length) {
|
||||||
|
return ` ${ansis.bold(migrations.length.toString())} ${ansis.dim('pending migrations to run')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lockedMigrations.length === 0) {
|
||||||
|
return ` ${ansis.bold(`0 of ${migrations.length}`)} ${ansis.dim('pending migrations to run')} ${ansis.redBright(
|
||||||
|
'(all locked)',
|
||||||
|
)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ` ${ansis.bold(`${lockedMigrations.length} of ${migrations.length}`)} ${ansis.dim(
|
||||||
|
'pending migrations to run',
|
||||||
|
)} ${ansis.yellow(`(${migrations.length - lockedMigrations.length} locked)`)}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DefaultFancyReporter implements Required<ReporterPlugin> {
|
||||||
|
#migrations: Array<MigrationMetadata | MigrationMetadataFinished> | undefined;
|
||||||
|
#lockedMigrations: MigrationMetadata[] | undefined;
|
||||||
|
#activeMigration: MigrationMetadata | undefined;
|
||||||
|
#error: Error | undefined;
|
||||||
|
#directory!: string;
|
||||||
|
#cwd!: string;
|
||||||
|
#dry!: boolean;
|
||||||
|
#interval: NodeJS.Timeout | undefined;
|
||||||
|
|
||||||
|
onInit(parameters: { directory: string; cwd: string; dry: boolean }): void | PromiseLike<void> {
|
||||||
|
this.#directory = parameters.directory;
|
||||||
|
this.#dry = parameters.dry;
|
||||||
|
this.#cwd = parameters.cwd;
|
||||||
|
|
||||||
|
this.#start();
|
||||||
|
}
|
||||||
|
|
||||||
|
onCollectedMigrations(migrations: MigrationMetadata[]): void | PromiseLike<void> {
|
||||||
|
this.#migrations = migrations;
|
||||||
|
}
|
||||||
|
|
||||||
|
onLockedMigrations(migrations: MigrationMetadata[]): void | PromiseLike<void> {
|
||||||
|
this.#lockedMigrations = migrations;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMigrationStart(migration: MigrationMetadata): void | PromiseLike<void> {
|
||||||
|
this.#activeMigration = migration;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMigrationSuccess(migration: MigrationMetadataFinished): void | PromiseLike<void> {
|
||||||
|
this.#finishMigration(migration);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMigrationError(migration: MigrationMetadataFinished, _error: Error): void | PromiseLike<void> {
|
||||||
|
this.#finishMigration(migration);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMigrationSkip(migration: MigrationMetadataFinished): void | PromiseLike<void> {
|
||||||
|
this.#finishMigration(migration);
|
||||||
|
}
|
||||||
|
|
||||||
|
onFinished(_migrations: MigrationMetadataFinished[], error?: Error | undefined): void | PromiseLike<void> {
|
||||||
|
this.#error = error;
|
||||||
|
this.#activeMigration = undefined;
|
||||||
|
this.#stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
#finishMigration(migration: MigrationMetadataFinished): void {
|
||||||
|
if (!this.#migrations) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Successfully ran ${migrations.length} migrations! [total duration: ${totalDuration}ms]`);
|
const index = this.#migrations.findIndex((m) => m.name === migration.name);
|
||||||
},
|
|
||||||
};
|
if (index !== -1) {
|
||||||
|
this.#migrations[index] = migration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#render(): void {
|
||||||
|
const parts = [
|
||||||
|
getTitle({ directory: this.#directory, dry: this.#dry, cwd: this.#cwd }),
|
||||||
|
getHeaderMessage(this.#migrations, this.#lockedMigrations),
|
||||||
|
this.#migrations?.map((migration) => getMigrationText(migration, this.#activeMigration)).join('\n') ?? '',
|
||||||
|
getSummary(this.#migrations),
|
||||||
|
getError(this.#error),
|
||||||
|
];
|
||||||
|
logUpdate('\n' + parts.filter(Boolean).join('\n\n') + '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
#start(): void {
|
||||||
|
this.#render();
|
||||||
|
this.#interval = setInterval(() => {
|
||||||
|
this.#render();
|
||||||
|
}, 80).unref();
|
||||||
|
}
|
||||||
|
|
||||||
|
#stop(): void {
|
||||||
|
if (this.#interval) {
|
||||||
|
clearInterval(this.#interval);
|
||||||
|
this.#interval = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DefaultReporter implements Required<ReporterPlugin> {
|
||||||
|
#migrations?: MigrationMetadata[];
|
||||||
|
#lockedMigrations?: MigrationMetadata[];
|
||||||
|
|
||||||
|
onInit(parameters: { directory: string; cwd: string; dry: boolean }): void | PromiseLike<void> {
|
||||||
|
console.log('');
|
||||||
|
console.log(getTitle(parameters));
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
onCollectedMigrations(migrations: MigrationMetadata[]): void | PromiseLike<void> {
|
||||||
|
this.#migrations = migrations;
|
||||||
|
}
|
||||||
|
|
||||||
|
onLockedMigrations(migrations: MigrationMetadata[]): void | PromiseLike<void> {
|
||||||
|
this.#lockedMigrations = migrations;
|
||||||
|
|
||||||
|
console.log(getHeaderMessage(this.#migrations, this.#lockedMigrations));
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
onMigrationStart(migration: MigrationMetadata): void | PromiseLike<void> {
|
||||||
|
console.log(getMigrationText(migration, migration));
|
||||||
|
}
|
||||||
|
|
||||||
|
onMigrationSuccess(migration: MigrationMetadataFinished): void | PromiseLike<void> {
|
||||||
|
console.log(getMigrationText(migration));
|
||||||
|
}
|
||||||
|
|
||||||
|
onMigrationError(migration: MigrationMetadataFinished, _error: Error): void | PromiseLike<void> {
|
||||||
|
console.error(getMigrationText(migration));
|
||||||
|
}
|
||||||
|
|
||||||
|
onMigrationSkip(migration: MigrationMetadataFinished): void | PromiseLike<void> {
|
||||||
|
console.log(getMigrationText(migration));
|
||||||
|
}
|
||||||
|
|
||||||
|
onFinished(migrations: MigrationMetadataFinished[], error?: Error | undefined): void | PromiseLike<void> {
|
||||||
|
console.log('');
|
||||||
|
console.log(getSummary(migrations));
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.error(getError(error));
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const reporterDefault = interactive ? new DefaultFancyReporter() : new DefaultReporter();
|
||||||
|
|
||||||
export default reporterDefault;
|
export default reporterDefault;
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export const stripLeadingPeriod = (string: string) => string.replace(/^\./, '');
|
|
||||||
|
|
@ -18,7 +18,7 @@ import {
|
||||||
MissingOptionError,
|
MissingOptionError,
|
||||||
} from './errors.js';
|
} from './errors.js';
|
||||||
import { type Config } from './types.js';
|
import { type Config } from './types.js';
|
||||||
import { stripLeadingPeriod } from './strip-leading-period.js';
|
import { withLeadingPeriod } from './with-leading-period.js';
|
||||||
import pluginLoaderJs from './plugin-loader-js.js';
|
import pluginLoaderJs from './plugin-loader-js.js';
|
||||||
import pluginReporterDefault from './plugin-reporter-default.js';
|
import pluginReporterDefault from './plugin-reporter-default.js';
|
||||||
|
|
||||||
|
|
@ -76,7 +76,7 @@ export default async function upCommand({ directory, dry = false, plugins = [] }
|
||||||
name,
|
name,
|
||||||
filePath,
|
filePath,
|
||||||
relativeFilePath: path.relative(cwd, filePath),
|
relativeFilePath: path.relative(cwd, filePath),
|
||||||
extension: stripLeadingPeriod(path.extname(name)),
|
extension: withLeadingPeriod(path.extname(name)),
|
||||||
directory,
|
directory,
|
||||||
cwd,
|
cwd,
|
||||||
};
|
};
|
||||||
|
|
@ -108,7 +108,7 @@ export default async function upCommand({ directory, dry = false, plugins = [] }
|
||||||
[
|
[
|
||||||
extension,
|
extension,
|
||||||
loaderPlugins.find((plugin) =>
|
loaderPlugins.find((plugin) =>
|
||||||
plugin.loadableExtensions.some((loadableExtension) => stripLeadingPeriod(loadableExtension) === extension),
|
plugin.loadableExtensions.some((loadableExtension) => withLeadingPeriod(loadableExtension) === extension),
|
||||||
),
|
),
|
||||||
] as const,
|
] as const,
|
||||||
),
|
),
|
||||||
|
|
@ -123,33 +123,56 @@ export default async function upCommand({ directory, dry = false, plugins = [] }
|
||||||
await reporter.onCollectedMigrations?.(migrationFiles);
|
await reporter.onCollectedMigrations?.(migrationFiles);
|
||||||
|
|
||||||
if (migrationFiles.length === 0 || dry || migrationHistoryError) {
|
if (migrationFiles.length === 0 || dry || migrationHistoryError) {
|
||||||
await reporter.onLockedMigrations?.([]);
|
await reporter.onLockedMigrations?.(migrationFiles);
|
||||||
|
|
||||||
for await (const migration of migrationFiles) {
|
const finishedMigrations: MigrationMetadataFinished[] = migrationFiles.map((migration) => ({
|
||||||
|
...migration,
|
||||||
|
duration: 0,
|
||||||
|
status: 'skipped',
|
||||||
|
}));
|
||||||
|
|
||||||
|
for await (const migration of finishedMigrations) {
|
||||||
await reporter.onMigrationSkip?.(migration);
|
await reporter.onMigrationSkip?.(migration);
|
||||||
}
|
}
|
||||||
|
|
||||||
await reporter.onFinished?.(
|
await reporter.onFinished?.(finishedMigrations, migrationHistoryError);
|
||||||
migrationFiles.map((migration) => ({ ...migration, status: 'skipped', duration: 0 })),
|
|
||||||
migrationHistoryError,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lockedMigrationFiles = await storage.lock(migrationFiles);
|
let lockedMigrationFiles: MigrationMetadata[] = [];
|
||||||
|
|
||||||
let cleaningUp = false;
|
try {
|
||||||
|
lockedMigrationFiles = await storage.lock(migrationFiles);
|
||||||
|
|
||||||
|
await reporter.onLockedMigrations?.(lockedMigrationFiles);
|
||||||
|
} catch (error) {
|
||||||
|
for await (const migration of migrationFiles) {
|
||||||
|
await reporter.onMigrationSkip?.({ ...migration, duration: 0, status: 'skipped' });
|
||||||
|
}
|
||||||
|
|
||||||
|
await reporter.onFinished?.([], error instanceof Error ? error : new Error(String(error)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nonLockedMigrations = migrationFiles.filter((migration) => !lockedMigrationFiles.includes(migration));
|
||||||
|
|
||||||
|
for await (const migration of nonLockedMigrations) {
|
||||||
|
await reporter.onMigrationSkip?.({ ...migration, duration: 0, status: 'skipped' });
|
||||||
|
}
|
||||||
|
|
||||||
|
let cleaningUp: Promise<void> | undefined;
|
||||||
|
|
||||||
const cleanup = async () => {
|
const cleanup = async () => {
|
||||||
if (cleaningUp) {
|
if (cleaningUp) {
|
||||||
return;
|
return cleaningUp;
|
||||||
}
|
}
|
||||||
|
|
||||||
process.off('SIGINT', cleanup);
|
process.off('SIGINT', cleanup);
|
||||||
process.off('SIGTERM', cleanup);
|
process.off('SIGTERM', cleanup);
|
||||||
|
|
||||||
cleaningUp = true;
|
cleaningUp = storage.unlock(lockedMigrationFiles);
|
||||||
await storage.unlock(lockedMigrationFiles);
|
|
||||||
|
return cleaningUp;
|
||||||
};
|
};
|
||||||
|
|
||||||
process.on('SIGINT', cleanup);
|
process.on('SIGINT', cleanup);
|
||||||
|
|
@ -162,8 +185,9 @@ export default async function upCommand({ directory, dry = false, plugins = [] }
|
||||||
const lastMigrationStatus = finishedMigrations.at(-1)?.status;
|
const lastMigrationStatus = finishedMigrations.at(-1)?.status;
|
||||||
|
|
||||||
if (lastMigrationStatus === 'failed' || lastMigrationStatus === 'skipped') {
|
if (lastMigrationStatus === 'failed' || lastMigrationStatus === 'skipped') {
|
||||||
await reporter.onMigrationSkip?.(migration);
|
const finishedMigration: MigrationMetadataFinished = { ...migration, status: 'skipped', duration: 0 };
|
||||||
finishedMigrations.push({ ...migration, status: 'skipped', duration: 0 });
|
await reporter.onMigrationSkip?.(finishedMigration);
|
||||||
|
finishedMigrations.push(finishedMigration);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -204,7 +228,7 @@ export default async function upCommand({ directory, dry = false, plugins = [] }
|
||||||
const duration = getDuration(start);
|
const duration = getDuration(start);
|
||||||
const finishedMigration: MigrationMetadataFinished = {
|
const finishedMigration: MigrationMetadataFinished = {
|
||||||
...migration,
|
...migration,
|
||||||
status: 'done',
|
status: 'failed',
|
||||||
duration,
|
duration,
|
||||||
error: errorInstance,
|
error: errorInstance,
|
||||||
};
|
};
|
||||||
|
|
@ -218,7 +242,7 @@ export default async function upCommand({ directory, dry = false, plugins = [] }
|
||||||
} finally {
|
} finally {
|
||||||
const firstError = finishedMigrations.find((migration) => migration.status === 'failed')?.error;
|
const firstError = finishedMigrations.find((migration) => migration.status === 'failed')?.error;
|
||||||
|
|
||||||
await reporter.onFinished?.(finishedMigrations, firstError);
|
|
||||||
await cleanup();
|
await cleanup();
|
||||||
|
await reporter.onFinished?.(finishedMigrations, firstError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
packages/cli/src/with-leading-period.ts
Normal file
1
packages/cli/src/with-leading-period.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export const withLeadingPeriod = (string: string) => (string.startsWith('.') ? string : `.${string}`);
|
||||||
|
|
@ -121,9 +121,9 @@ export type MigrationMetadata = {
|
||||||
*/
|
*/
|
||||||
cwd: string;
|
cwd: string;
|
||||||
/**
|
/**
|
||||||
* The extension of the migration file
|
* The extension of the migration file, with a leading period
|
||||||
*
|
*
|
||||||
* @example js
|
* @example .js
|
||||||
*/
|
*/
|
||||||
extension: string;
|
extension: string;
|
||||||
};
|
};
|
||||||
|
|
@ -207,7 +207,7 @@ export type ReporterPlugin = Partial<{
|
||||||
*
|
*
|
||||||
* @param migration Information about the migration that was skipped.
|
* @param migration Information about the migration that was skipped.
|
||||||
*/
|
*/
|
||||||
onMigrationSkip(migration: MigrationMetadata): Awaitable<void>;
|
onMigrationSkip(migration: MigrationMetadataFinished): Awaitable<void>;
|
||||||
/**
|
/**
|
||||||
* Called when the migration process has finished.
|
* Called when the migration process has finished.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
122
pnpm-lock.yaml
generated
122
pnpm-lock.yaml
generated
|
|
@ -59,9 +59,27 @@ importers:
|
||||||
'@emigrate/plugin-tools':
|
'@emigrate/plugin-tools':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../plugin-tools
|
version: link:../plugin-tools
|
||||||
|
ansis:
|
||||||
|
specifier: 2.0.2
|
||||||
|
version: 2.0.2
|
||||||
cosmiconfig:
|
cosmiconfig:
|
||||||
specifier: 8.3.6
|
specifier: 8.3.6
|
||||||
version: 8.3.6(typescript@5.2.2)
|
version: 8.3.6(typescript@5.2.2)
|
||||||
|
elegant-spinner:
|
||||||
|
specifier: 3.0.0
|
||||||
|
version: 3.0.0
|
||||||
|
figures:
|
||||||
|
specifier: 6.0.1
|
||||||
|
version: 6.0.1
|
||||||
|
is-interactive:
|
||||||
|
specifier: 2.0.0
|
||||||
|
version: 2.0.0
|
||||||
|
log-update:
|
||||||
|
specifier: 6.0.0
|
||||||
|
version: 6.0.0
|
||||||
|
pretty-ms:
|
||||||
|
specifier: 8.0.0
|
||||||
|
version: 8.0.0
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@emigrate/tsconfig':
|
'@emigrate/tsconfig':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
|
|
@ -1370,6 +1388,13 @@ packages:
|
||||||
type-fest: 1.4.0
|
type-fest: 1.4.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/ansi-escapes@6.2.0:
|
||||||
|
resolution: {integrity: sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==}
|
||||||
|
engines: {node: '>=14.16'}
|
||||||
|
dependencies:
|
||||||
|
type-fest: 3.13.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/ansi-regex@5.0.1:
|
/ansi-regex@5.0.1:
|
||||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
@ -1404,6 +1429,11 @@ packages:
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/ansis@2.0.2:
|
||||||
|
resolution: {integrity: sha512-D64onic45SdssSfEKNJOybZhDSE9BFryY6LX1CvRzuChBC7SJGJ+VZzgiWrXTEiOK3f/MA7wyFbu34/PvhVDsQ==}
|
||||||
|
engines: {node: '>=12.13'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/argparse@1.0.10:
|
/argparse@1.0.10:
|
||||||
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
|
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -2070,6 +2100,15 @@ packages:
|
||||||
resolution: {integrity: sha512-V0ZhSu1BQZKfG0yNEL6Dadzik8E1vAzfpVOapdSiT9F6yapEJ3Bk+4tZ4SMPdWiUchCgnM/ByYtBzp5ntzDMIA==}
|
resolution: {integrity: sha512-V0ZhSu1BQZKfG0yNEL6Dadzik8E1vAzfpVOapdSiT9F6yapEJ3Bk+4tZ4SMPdWiUchCgnM/ByYtBzp5ntzDMIA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/elegant-spinner@3.0.0:
|
||||||
|
resolution: {integrity: sha512-nWUuor3FWTGYAch7SY0unb5qLzs7eAc24ic9PBh+eQctFNQ4IDWJqBpBgsL4SrrGHHN0mJoL7CpWZby5t2KjFg==}
|
||||||
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/emoji-regex@10.3.0:
|
||||||
|
resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/emoji-regex@8.0.0:
|
/emoji-regex@8.0.0:
|
||||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
@ -2744,6 +2783,13 @@ packages:
|
||||||
reusify: 1.0.4
|
reusify: 1.0.4
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/figures@6.0.1:
|
||||||
|
resolution: {integrity: sha512-0oY/olScYD4IhQ8u//gCPA4F3mlTn2dacYmiDm/mbDQvpmLjV4uH+zhsQ5IyXRyvqkvtUkXkNdGvg5OFJTCsuQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dependencies:
|
||||||
|
is-unicode-supported: 2.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/file-entry-cache@6.0.1:
|
/file-entry-cache@6.0.1:
|
||||||
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
|
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
|
||||||
engines: {node: ^10.12.0 || >=12.0.0}
|
engines: {node: ^10.12.0 || >=12.0.0}
|
||||||
|
|
@ -2890,6 +2936,11 @@ packages:
|
||||||
engines: {node: 6.* || 8.* || >= 10.*}
|
engines: {node: 6.* || 8.* || >= 10.*}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/get-east-asian-width@1.2.0:
|
||||||
|
resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/get-func-name@2.0.2:
|
/get-func-name@2.0.2:
|
||||||
resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
|
resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
@ -3352,6 +3403,13 @@ packages:
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/is-fullwidth-code-point@5.0.0:
|
||||||
|
resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dependencies:
|
||||||
|
get-east-asian-width: 1.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/is-get-set-prop@1.0.0:
|
/is-get-set-prop@1.0.0:
|
||||||
resolution: {integrity: sha512-DvAYZ1ZgGUz4lzxKMPYlt08qAUqyG9ckSg2pIjfvcQ7+pkVNUHk8yVLXOnCLe5WKXhLop8oorWFBJHpwWQpszQ==}
|
resolution: {integrity: sha512-DvAYZ1ZgGUz4lzxKMPYlt08qAUqyG9ckSg2pIjfvcQ7+pkVNUHk8yVLXOnCLe5WKXhLop8oorWFBJHpwWQpszQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -3374,6 +3432,11 @@ packages:
|
||||||
is-docker: 3.0.0
|
is-docker: 3.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/is-interactive@2.0.0:
|
||||||
|
resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/is-js-type@2.0.0:
|
/is-js-type@2.0.0:
|
||||||
resolution: {integrity: sha512-Aj13l47+uyTjlQNHtXBV8Cji3jb037vxwMWCgopRR8h6xocgBGW3qG8qGlIOEmbXQtkKShKuBM9e8AA1OeQ+xw==}
|
resolution: {integrity: sha512-Aj13l47+uyTjlQNHtXBV8Cji3jb037vxwMWCgopRR8h6xocgBGW3qG8qGlIOEmbXQtkKShKuBM9e8AA1OeQ+xw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -3509,6 +3572,11 @@ packages:
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/is-unicode-supported@2.0.0:
|
||||||
|
resolution: {integrity: sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/is-weakref@1.0.2:
|
/is-weakref@1.0.2:
|
||||||
resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
|
resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -3850,6 +3918,17 @@ packages:
|
||||||
wrap-ansi: 8.1.0
|
wrap-ansi: 8.1.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/log-update@6.0.0:
|
||||||
|
resolution: {integrity: sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dependencies:
|
||||||
|
ansi-escapes: 6.2.0
|
||||||
|
cli-cursor: 4.0.0
|
||||||
|
slice-ansi: 7.1.0
|
||||||
|
strip-ansi: 7.1.0
|
||||||
|
wrap-ansi: 9.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/loupe@2.3.7:
|
/loupe@2.3.7:
|
||||||
resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
|
resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -4341,6 +4420,11 @@ packages:
|
||||||
lines-and-columns: 1.2.4
|
lines-and-columns: 1.2.4
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/parse-ms@3.0.0:
|
||||||
|
resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/path-exists@4.0.0:
|
/path-exists@4.0.0:
|
||||||
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
@ -4532,6 +4616,13 @@ packages:
|
||||||
react-is: 18.2.0
|
react-is: 18.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/pretty-ms@8.0.0:
|
||||||
|
resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==}
|
||||||
|
engines: {node: '>=14.16'}
|
||||||
|
dependencies:
|
||||||
|
parse-ms: 3.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/proto-props@2.0.0:
|
/proto-props@2.0.0:
|
||||||
resolution: {integrity: sha512-2yma2tog9VaRZY2mn3Wq51uiSW4NcPYT1cQdBagwyrznrilKSZwIZ0UG3ZPL/mx+axEns0hE35T5ufOYZXEnBQ==}
|
resolution: {integrity: sha512-2yma2tog9VaRZY2mn3Wq51uiSW4NcPYT1cQdBagwyrznrilKSZwIZ0UG3ZPL/mx+axEns0hE35T5ufOYZXEnBQ==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
@ -4941,6 +5032,14 @@ packages:
|
||||||
is-fullwidth-code-point: 4.0.0
|
is-fullwidth-code-point: 4.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/slice-ansi@7.1.0:
|
||||||
|
resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dependencies:
|
||||||
|
ansi-styles: 6.2.1
|
||||||
|
is-fullwidth-code-point: 5.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/smartwrap@2.0.2:
|
/smartwrap@2.0.2:
|
||||||
resolution: {integrity: sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==}
|
resolution: {integrity: sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
@ -5052,6 +5151,15 @@ packages:
|
||||||
strip-ansi: 7.1.0
|
strip-ansi: 7.1.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/string-width@7.0.0:
|
||||||
|
resolution: {integrity: sha512-GPQHj7row82Hjo9hKZieKcHIhaAIKOJvFSIZXuCU9OASVZrMNUaZuz++SPVrBjnLsnk4k+z9f2EIypgxf2vNFw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dependencies:
|
||||||
|
emoji-regex: 10.3.0
|
||||||
|
get-east-asian-width: 1.2.0
|
||||||
|
strip-ansi: 7.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/string.prototype.padend@3.1.5:
|
/string.prototype.padend@3.1.5:
|
||||||
resolution: {integrity: sha512-DOB27b/2UTTD+4myKUFh+/fXWcu/UDyASIXfg+7VzoCNNGOfWvoyU/x5pvVHr++ztyt/oSYI1BcWBBG/hmlNjA==}
|
resolution: {integrity: sha512-DOB27b/2UTTD+4myKUFh+/fXWcu/UDyASIXfg+7VzoCNNGOfWvoyU/x5pvVHr++ztyt/oSYI1BcWBBG/hmlNjA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
@ -5466,6 +5574,11 @@ packages:
|
||||||
engines: {node: '>=12.20'}
|
engines: {node: '>=12.20'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/type-fest@3.13.1:
|
||||||
|
resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==}
|
||||||
|
engines: {node: '>=14.16'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/typed-array-buffer@1.0.0:
|
/typed-array-buffer@1.0.0:
|
||||||
resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==}
|
resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
@ -5858,6 +5971,15 @@ packages:
|
||||||
strip-ansi: 7.1.0
|
strip-ansi: 7.1.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/wrap-ansi@9.0.0:
|
||||||
|
resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dependencies:
|
||||||
|
ansi-styles: 6.2.1
|
||||||
|
string-width: 7.0.0
|
||||||
|
strip-ansi: 7.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/wrappy@1.0.2:
|
/wrappy@1.0.2:
|
||||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue