Skip to content

Commit

Permalink
feat: add upgrade command
Browse files Browse the repository at this point in the history
  • Loading branch information
bjohansebas committed Jan 27, 2025
1 parent 60f69d6 commit 5950126
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 20 deletions.
29 changes: 29 additions & 0 deletions commands/__test__/upgrade.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { run } from 'jscodeshift/src/Runner'
import { upgrade } from '../upgrade'

jest.mock('jscodeshift/src/Runner', () => ({
run: jest.fn(),
}))

describe('interactive mode', () => {
beforeEach(() => {
jest.clearAllMocks()
})

it.todo('runs without source params provided and select is true')
})

describe('Non-Interactive Mode', () => {
beforeEach(() => {
jest.clearAllMocks()
})

it('Transforms code with source params provided', async () => {
const spyOnConsole = jest.spyOn(console, 'log').mockImplementation()

await upgrade('__testfixtures__')

expect(spyOnConsole).toHaveBeenCalled()
expect(run).toHaveBeenCalledTimes(4)
})
})
22 changes: 2 additions & 20 deletions commands/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ import { run as jscodeshift } from 'jscodeshift/src/Runner'
import { bold } from 'picocolors'
import prompts from 'prompts'
import { TRANSFORM_OPTIONS } from '../config'

export function onCancel() {
console.info('> Cancelled process. Program will stop now without any actions. \n')
process.exit(1)
}
import { onCancel, promptSource } from '../utils/prompts'

const transformerDirectory = join(__dirname, '../', 'transforms')

Expand All @@ -32,20 +28,6 @@ const selectCodemod = async (): Promise<string> => {
return res.transformer
}

const selectSource = async (): Promise<string> => {
const res = await prompts(
{
type: 'text',
name: 'path',
message: 'Which files or directories should the codemods be applied to?',
initial: '.',
},
{ onCancel },
)

return res.path
}

export async function transform(codemodName?: string, source?: string, options?: Record<string, unknown>) {
const existCodemod = TRANSFORM_OPTIONS.find(({ value }) => value === codemodName)
const codemodSelected = !codemodName || (codemodName && !existCodemod) ? await selectCodemod() : codemodName
Expand All @@ -55,7 +37,7 @@ export async function transform(codemodName?: string, source?: string, options?:
process.exit(1)
}

const sourceSelected = source || (await selectSource())
const sourceSelected = source || (await promptSource('Which files or directories should the codemods be applied to?'))

if (!sourceSelected) {
console.info('> Source path for project is not selected. Exits the program. \n')
Expand Down
63 changes: 63 additions & 0 deletions commands/upgrade.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { join, resolve } from 'node:path'
import type { Options } from 'jscodeshift'
import { run as jscodeshift } from 'jscodeshift/src/Runner'
import prompts from 'prompts'
import { TRANSFORM_OPTIONS } from '../config'
import { onCancel, promptSource } from '../utils/prompts'

const transformerDirectory = join(__dirname, '../', 'transforms')

export async function upgrade(source?: string, options?: Record<string, unknown>) {
const sourceSelected = source || (await promptSource('Which directory should the codemods be applied to?'))

if (!sourceSelected) {
console.info('> Source path for project is not selected. Exits the program. \n')
process.exit(1)
}
let codemods: string[] = []

if (options?.select) {
const { codemodsSelected } = await prompts(
{
type: 'multiselect',
name: 'codemodsSelected',
message: `The following 'codemods' are recommended for your upgrade. Select the ones to apply.`,
choices: TRANSFORM_OPTIONS.map(({ description, value, version }) => {
return {
title: `(v${version}) ${value}`,
description,
value,
selected: true,
}
}),
},
{ onCancel },
)
codemods = codemodsSelected
} else {
codemods = TRANSFORM_OPTIONS.map(({ value }) => value)
}

const args: Options = {
dry: false,
babel: false,
silent: true,
ignorePattern: '**/node_modules/**',
extensions: 'cts,mts,ts,js,mjs,cjs',
}

for (const codemod of codemods) {
const transformerPath = join(transformerDirectory, `${codemod}.js`)

console.log(`> Applying codemod: ${codemod}`)

try {
await jscodeshift(transformerPath, [resolve(sourceSelected)], args)
} catch (error) {
console.error(`> Error applying codemod: ${codemod}`)
console.error(error)
}
}

console.log('\n> All codemods have been applied successfully. \n')
}
8 changes: 8 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { Command } from 'commander'
import { transform } from './commands/transform'
import { upgrade } from './commands/upgrade'
import packageJson from './package.json'

const program = new Command(packageJson.name)
Expand All @@ -22,4 +23,11 @@ const program = new Command(packageJson.name)
// Why this option is necessary is explained here: https://github.com/tj/commander.js/pull/1427
.enablePositionalOptions()

program
.command('upgrade')
.description('Upgrade your express server to the latest version.')
.argument('[source]', 'Path to source files or directory to transform.')
.option('--select', 'Select which codemods to apply (Show a list of available codemods)')
.action(upgrade)

program.parse(process.argv)
20 changes: 20 additions & 0 deletions utils/prompts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import prompts from 'prompts'

export function onCancel() {
console.info('> Cancelled process. Program will stop now without any actions. \n')
process.exit(1)
}

export const promptSource = async (message: string): Promise<string> => {
const res = await prompts(
{
type: 'text',
name: 'path',
message,
initial: '.',
},
{ onCancel },
)

return res.path
}

0 comments on commit 5950126

Please sign in to comment.