-
-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add upgrade command #8
base: main
Are you sure you want to change the base?
Changes from 4 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import { readFile } from 'node:fs/promises' | ||
import { join, resolve } from 'node:path' | ||
import type { Options } from 'jscodeshift' | ||
import { run as jscodeshift } from 'jscodeshift/src/Runner' | ||
import prompts from 'prompts' | ||
import { coerce, compare } from 'semver' | ||
import { TRANSFORM_OPTIONS } from '../config' | ||
import { onCancel, promptSource } from '../utils/share' | ||
|
||
const transformerDirectory = join(__dirname, '../', 'transforms') | ||
|
||
export async function upgrade(source?: string) { | ||
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) | ||
} | ||
|
||
try { | ||
const packageJsonPath = resolve(sourceSelected || '', 'package.json') | ||
const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')) | ||
|
||
const codemods = suggestCodemods(packageJson) | ||
|
||
if (codemods.length === 0) { | ||
console.info('> No codemods are suggested for this project. \n') | ||
|
||
return | ||
} | ||
|
||
const { codemodsSelected } = await prompts( | ||
{ | ||
type: 'multiselect', | ||
name: 'codemodsSelected', | ||
message: `The following 'codemods' are recommended for your upgrade. Select the ones to apply.`, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we recommend them only by checking version in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But what if there are codemods for version 6 and we're on version 5? We wouldn't want to recommend codemods from version 4, right? |
||
choices: codemods.map(({ description, value, version }) => { | ||
return { | ||
title: `(v${version}) ${value}`, | ||
description, | ||
value, | ||
selected: true, | ||
} | ||
}), | ||
}, | ||
{ onCancel }, | ||
) | ||
|
||
const args: Options = { | ||
dry: false, | ||
babel: false, | ||
silent: true, | ||
ignorePattern: '**/node_modules/**', | ||
extensions: 'cts,mts,ts,js,mjs,cjs', | ||
} | ||
|
||
const results = { | ||
ok: 0, | ||
skipped: 0, | ||
failed: 0, | ||
unmodified: 0, | ||
} | ||
|
||
for (const codemod of codemodsSelected) { | ||
const transformerPath = require.resolve(`${transformerDirectory}/${codemod}.js`) | ||
|
||
console.log(`> Applying codemod: ${codemod}`) | ||
const { ok, skip, error, nochange } = await jscodeshift(transformerPath, [resolve(sourceSelected)], args) | ||
|
||
results.ok += ok | ||
results.skipped += skip | ||
results.failed += error | ||
results.unmodified += nochange | ||
} | ||
|
||
console.log('\n> Summary of the upgrade') | ||
console.log(`> ${results.ok} codemods were applied successfully`) | ||
console.log(`> ${results.skipped} codemods were skipped`) | ||
console.log(`> ${results.failed} codemods failed`) | ||
console.log(`> ${results.unmodified} codemods were skipped because they didn't change anything`) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep |
||
} catch (err) { | ||
if (err.code === 'ENOENT') { | ||
console.info('> No package.json found in the selected directory. \n') | ||
bjohansebas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
process.exit(1) | ||
} else { | ||
console.error(err.message) | ||
} | ||
} | ||
} | ||
|
||
function suggestCodemods(packageJson) { | ||
const { dependencies } = packageJson | ||
|
||
if (dependencies?.express == null) { | ||
console.info('> No express dependency found in package.json. \n') | ||
|
||
process.exit(0) | ||
} | ||
|
||
const expressVersion = coerce(dependencies.express)?.version ?? '4.0.0' | ||
|
||
const codemodsSuggested = TRANSFORM_OPTIONS.filter((a) => { | ||
return compare(a.version, expressVersion) > 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't we apply our codemods only if the project is on v4? according to docs:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is more thought out so that in the future more codemods can be added as Express evolves, and not limit us to version 4 |
||
}) | ||
|
||
return codemodsSuggested | ||
} |
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 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this
share
filename needs adjustment. It does not tell what can be found inside. From what I can see you collect there utility methods for commandsThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I gave it that name without thinking too much, I just wanted to separate it