diff --git a/packages/cli/src/main.ts b/packages/cli/src/main.ts index 2d16cc3a8..21d70d1e7 100644 --- a/packages/cli/src/main.ts +++ b/packages/cli/src/main.ts @@ -5,7 +5,7 @@ import chalk from 'chalk'; import findUp from 'find-up'; import inquirer from 'inquirer'; -import { CodeshiftConfig } from '@codeshift/types'; +import { CodeshiftConfig, DefaultRunner } from '@codeshift/types'; import { fetchConfigAtPath, fetchConfigs } from '@codeshift/fetcher'; import { PluginManager } from 'live-plugin-manager'; // @ts-ignore Run transform(s) on path https://github.com/facebook/jscodeshift/issues/398 @@ -234,20 +234,105 @@ export default async function main(paths: string[], flags: Flags) { const resolvedTransformPath = path.resolve(transform); console.log(chalk.green('Running transform:'), resolvedTransformPath); - await jscodeshift.run(resolvedTransformPath, paths, { - verbose: flags.verbose, - dry: flags.dry, - print: true, - babel: true, - extensions: flags.extensions, - ignorePattern: flags.ignorePattern, - cpus: flags.cpus, - ignoreConfig: [], - runInBand: flags.runInBand, - silent: false, - parser: flags.parser, - stdin: false, - }); + const defaultRunner: DefaultRunner = ( + jscodeshiftOptionOverrides = {}, + pathsToModify = paths, + /** + * ideally you'd be able to pass in either the path, + * or the actual transform, + * but jscodeshift doesn't allow this (unless we fork?) + */ + transformerPath: string = resolvedTransformPath, + /** + * i think the jscodeshift.run is synchronous + * so the promise is not needed, + * but if we want to change it in the future, + * making it's return type a promise will help + * to avoid breaking changes for consumers who + * use the defaultRunner. + */ + ): Promise => + jscodeshift.run(transformerPath, pathsToModify, { + verbose: flags.verbose, + dry: flags.dry, + print: true, + babel: true, + extensions: flags.extensions, + ignorePattern: flags.ignorePattern, + cpus: flags.cpus, + ignoreConfig: [], + runInBand: flags.runInBand, + silent: false, + parser: flags.parser, + stdin: false, + ...jscodeshiftOptionOverrides, + }); + + let transformImported: any; + try { + /** + * TODO MAINTAINER -- i am not confident that this will work + * if the transform was provided thru an npm package. + */ + + // eslint-disable-next-line @typescript-eslint/no-var-requires + transformImported = require(resolvedTransformPath); + } catch (_e) {} + + const transformHasCustomRunner = ( + ti: any, + ): ti is { + /** + * ideally, `default` would be the type of the transformer, + * which would be identical to the type of the argument to + * `CustomTransformerConfig`, + * + * but unless we put the transformer itself into the config, + * we cannot ensure that the type is correct. + * + */ + default: unknown; // + codeshiftConfig: CodeshiftConfig; + } => { + if (ti && 'codeshiftConfig' in ti) { + return 'runner' in transformImported['codeshiftConfig']; + } + return false; + }; + + if (transformHasCustomRunner(transformImported)) { + console.info( + '\nusing CUSTOM runner for transform', + resolvedTransformPath, + ); + + await transformImported.codeshiftConfig.runner({ + pathsToModify: paths, + defaultRunner, + /** + * providing the `transform`, `resolvedTransformPath`, etc. here + * is quite useless, because it's file-based, + * so in whichever file the config is in, + * that default export will be the transform, + * and the file's path will be the resolved path. + * + * ...unless you have a custom runner defined in a separate file, + * and want it to be able to access the transform, + * esp. if that runner does not take in a path, + * but rather the transform function. + */ + transformInsideFileThatSpecifiesCodeshiftConfig: + transformImported.default, + // resolvedTransformPath + }); + } else { + console.info( + '\nusing DEFAULT runner for transform', + resolvedTransformPath, + ); + + defaultRunner(); + } } await packageManager.uninstallAll(); diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index a9be9570e..fc5a48946 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -5,3 +5,27 @@ export interface CodeshiftConfig { transforms?: Record; presets?: Record; } + +export type DefaultRunner = ( + jscodeshiftOptionOverrides?: object, + pathsToModify?: string[], // + transformerPath?: string, +) => Promise; + +export interface CustomRunnerCtx { + pathsToModify: string[]; // + defaultRunner: DefaultRunner; + transformInsideFileThatSpecifiesCodeshiftConfig: Transform; +} + +export type CustomRunner< + Transform = unknown, // + Return = unknown | Promise +> = (ctx: CustomRunnerCtx) => Return; + +export interface CodeshiftConfig< + Transform = unknown, // + RunnerReturn = unknown | Promise +> { + runner: CustomRunner; +}