Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions src/commands/migrate.meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,25 @@ export const meta = {
name: 'migrate',
description: 'Migrate from a package to a more performant alternative.',
args: {
'dry-run': {
all: {
type: 'boolean',
default: false,
description: `Don't apply any fixes, only show what would change.`
description: 'Run all available migrations'
},
interactive: {
'dry-run': {
type: 'boolean',
default: false,
description: 'Run in interactive mode.'
description: `Don't apply any fixes, only show what would change.`
},
include: {
type: 'string',
default: '**/*.{ts,js}',
description: 'Files to migrate'
},
interactive: {
type: 'boolean',
default: false,
description: 'Run in interactive mode.'
}
}
} as const;
10 changes: 9 additions & 1 deletion src/commands/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export async function run(ctx: CommandContext<typeof meta.args>) {
const dryRun = ctx.values['dry-run'] === true;
const interactive = ctx.values.interactive === true;
const include = ctx.values.include;
const all = ctx.values.all === true;
const fileSystem = new LocalFileSystem(process.cwd());
const packageJson = await getPackageJson(fileSystem);

Expand All @@ -37,6 +38,13 @@ export async function run(ctx: CommandContext<typeof meta.args>) {
.map((rep) => rep.from)
);

// If --all flag is used, add all available migrations
if (all) {
for (const target of fixableReplacementsTargets) {
targetModules.push(target);
}
}

if (interactive) {
const additionalTargets = await prompts.autocompleteMultiselect({
message: 'Select packages to migrate',
Expand All @@ -62,7 +70,7 @@ export async function run(ctx: CommandContext<typeof meta.args>) {

if (targetModules.length === 0) {
prompts.cancel(
'Error: Please specify a package to migrate. For example, `migrate chalk`'
'Error: Please specify a package to migrate. For example, `migrate chalk` or use `--all` to migrate all available packages'
);
return;
}
Expand Down
171 changes: 171 additions & 0 deletions src/test/__snapshots__/migrate.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`migrate command > should handle custom include pattern 1`] = `
"e18e (cli <version>)

┌ Migrating packages...
│
│ Targets: chalk
│
◇ {cwd}/lib/main.js...
│
│ loading {cwd}/lib/main.js
│ loading {cwd}/lib/main.js
│ migrating chalk to picocolors
│ loading {cwd}/lib/main.js
│ migrating chalk to picocolors
│ writing {cwd}/lib/main.js
│
◆ {cwd}/lib/main.js (1 migrated)
│
└ Migration complete.

"
`;

exports[`migrate command > should handle custom include pattern 2`] = `
"import * as pc from 'picocolors';

console.log(pc.cyan('I am _so_ cyan'));
"
`;

exports[`migrate command > should handle interactive mode 1`] = `
"e18e (cli <version>)

┌ Migrating packages...
[?25l│
◆ Select packages to migrate

│ Search: _
│ ◼ chalk
│ ↑/↓ to navigate • Space: select • Enter: confirm • Type: to search
└"
`;

exports[`migrate command > should handle interactive mode 2`] = `
"import chalk from 'chalk';

console.log(chalk.cyan('I am _so_ cyan'));
"
`;

exports[`migrate command > should migrate specific package 1`] = `
"e18e (cli <version>)

┌ Migrating packages...
│
│ Targets: chalk
│
◇ {cwd}/lib/main.js...
│
│ loading {cwd}/lib/main.js
│ loading {cwd}/lib/main.js
│ migrating chalk to picocolors
│ loading {cwd}/lib/main.js
│ migrating chalk to picocolors
│ writing {cwd}/lib/main.js
│
◆ {cwd}/lib/main.js (1 migrated)
│
└ Migration complete.

"
`;

exports[`migrate command > should migrate specific package 2`] = `
"import * as pc from 'picocolors';

console.log(pc.cyan('I am _so_ cyan'));
"
`;

exports[`migrate command > should migrate with --all flag 1`] = `
"e18e (cli <version>)

┌ Migrating packages...
│
│ Targets: chalk
│
◇ {cwd}/lib/main.js...
│
│ loading {cwd}/lib/main.js
│ loading {cwd}/lib/main.js
│ migrating chalk to picocolors
│ loading {cwd}/lib/main.js
│ migrating chalk to picocolors
│ writing {cwd}/lib/main.js
│
◆ {cwd}/lib/main.js (1 migrated)
│
└ Migration complete.

"
`;

exports[`migrate command > should migrate with --all flag 2`] = `
"import * as pc from 'picocolors';

console.log(pc.cyan('I am _so_ cyan'));
"
`;

exports[`migrate command > should not modify files with --all flag in dry-run mode 1`] = `
"e18e (cli <version>)

┌ Migrating packages...
│
│ Targets: chalk
│
◇ {cwd}/lib/main.js...
│
│ loading {cwd}/lib/main.js
│ loading {cwd}/lib/main.js
│ migrating chalk to picocolors
│ loading {cwd}/lib/main.js
│ migrating chalk to picocolors
│ writing {cwd}/lib/main.js
│
◆ {cwd}/lib/main.js (1 migrated)
│
└ Migration complete.

"
`;

exports[`migrate command > should not modify files with --all flag in dry-run mode 2`] = `
"import chalk from 'chalk';

console.log(chalk.cyan('I am _so_ cyan'));
"
`;

exports[`migrate command > should not modify files with specific package in dry-run mode 1`] = `
"e18e (cli <version>)

┌ Migrating packages...
│
│ Targets: chalk
│
◇ {cwd}/lib/main.js...
│
│ loading {cwd}/lib/main.js
│ loading {cwd}/lib/main.js
│ migrating chalk to picocolors
│ loading {cwd}/lib/main.js
│ migrating chalk to picocolors
│ writing {cwd}/lib/main.js
│
◆ {cwd}/lib/main.js (1 migrated)
│
└ Migration complete.

"
`;

exports[`migrate command > should not modify files with specific package in dry-run mode 2`] = `
"import chalk from 'chalk';

console.log(chalk.cyan('I am _so_ cyan'));
"
`;
40 changes: 9 additions & 31 deletions src/test/cli.test.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import {describe, it, expect, beforeAll, afterAll} from 'vitest';
import {spawn} from 'node:child_process';
import path from 'node:path';
import fs from 'node:fs/promises';
import {createTempDir, cleanupTempDir, createTestPackage} from './utils.js';
import {
createTempDir,
cleanupTempDir,
createTestPackage,
runCliProcess,
stripVersion
} from './utils.js';
import {pack as packAsTarball} from '@publint/pack';

let mockTarballPath: string;
let tempDir: string;
const stripVersion = (str: string): string =>
str.replace(
new RegExp(/\(cli v\d+\.\d+\.\d+(?:-\S+)?\)/, 'g'),
'(cli <version>)'
);

beforeAll(async () => {
// Create a temporary directory for the test package
Expand Down Expand Up @@ -59,28 +59,6 @@ afterAll(async () => {
await cleanupTempDir(tempDir);
});

function runCliProcess(
args: string[],
cwd?: string
): Promise<{stdout: string; stderr: string; code: number | null}> {
return new Promise((resolve) => {
const cliPath = path.resolve(__dirname, '../../lib/cli.js');
const proc = spawn('node', [cliPath, ...args], {
env: process.env,
cwd: cwd || process.cwd()
});
let stdout = '';
let stderr = '';
proc.stdout.on('data', (data) => (stdout += data.toString()));
proc.stderr.on('data', (data) => (stderr += data.toString()));
proc.on('error', (err) => {
stderr += String(err);
resolve({stdout, stderr, code: 1});
});
proc.on('close', (code) => resolve({stdout, stderr, code}));
});
}

describe('CLI', () => {
it('should run successfully with default options', async () => {
const {stdout, stderr, code} = await runCliProcess(
Expand All @@ -91,7 +69,7 @@ describe('CLI', () => {
console.error('CLI Error:', stderr);
}
expect(code).toBe(0);
expect(stripVersion(stdout)).toMatchSnapshot();
expect(await stripVersion(stdout, process.cwd())).toMatchSnapshot();
expect(stderr).toBe('');
});

Expand All @@ -101,7 +79,7 @@ describe('CLI', () => {
tempDir
);
expect(code).toBe(0);
expect(stripVersion(stdout)).toMatchSnapshot();
expect(await stripVersion(stdout, process.cwd())).toMatchSnapshot();
expect(stderr).toMatchSnapshot();
});
});
Loading
Loading