Skip to content

Commit b25c05e

Browse files
committed
feat: allow providing custom runner per transform file thru CodeshiftConfig
depends on: - #63 example on how it could be used: - https://github.com/pipedrive/CodeshiftCommunity/pull/22 - though note we might refactor into separate PRs, idk, preferably would use directly from upstream (you). fixes a lot of cases for us: 1. we have a postcss codemod that we want to run, while still utilizing the @codeshift/cli. though, i don't know if these changes will work if we're using a remote package, will they? 2. we'll want to do some global pre-processing on files before running our codemod. though, there's still no way to provide the codemod as a __function__ instead of an __import path__ to jscodeshift, which will force us to do dependency injection instead of just passing the pre-processed results as an argument to a function. this is where the considerations to fork jscodeshift come into play again: - #67 Signed-off-by: Kipras Melnikovas <[email protected]>
1 parent 999edd6 commit b25c05e

File tree

2 files changed

+124
-15
lines changed

2 files changed

+124
-15
lines changed

packages/cli/src/main.ts

+100-15
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import chalk from 'chalk';
55
import findUp from 'find-up';
66
import inquirer from 'inquirer';
77

8-
import { CodeshiftConfig } from '@codeshift/types';
8+
import { CodeshiftConfig, DefaultRunner } from '@codeshift/types';
99
import { fetchConfigAtPath, fetchConfigs } from '@codeshift/fetcher';
1010
import { PluginManager } from 'live-plugin-manager';
1111
// @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) {
234234
const resolvedTransformPath = path.resolve(transform);
235235
console.log(chalk.green('Running transform:'), resolvedTransformPath);
236236

237-
await jscodeshift.run(resolvedTransformPath, paths, {
238-
verbose: flags.verbose,
239-
dry: flags.dry,
240-
print: true,
241-
babel: true,
242-
extensions: flags.extensions,
243-
ignorePattern: flags.ignorePattern,
244-
cpus: flags.cpus,
245-
ignoreConfig: [],
246-
runInBand: flags.runInBand,
247-
silent: false,
248-
parser: flags.parser,
249-
stdin: false,
250-
});
237+
const defaultRunner: DefaultRunner = (
238+
jscodeshiftOptionOverrides = {},
239+
pathsToModify = paths,
240+
/**
241+
* ideally you'd be able to pass in either the path,
242+
* or the actual transform,
243+
* but jscodeshift doesn't allow this (unless we fork?)
244+
*/
245+
transformerPath: string = resolvedTransformPath,
246+
/**
247+
* i think the jscodeshift.run is synchronous
248+
* so the promise is not needed,
249+
* but if we want to change it in the future,
250+
* making it's return type a promise will help
251+
* to avoid breaking changes for consumers who
252+
* use the defaultRunner.
253+
*/
254+
): Promise<void> =>
255+
jscodeshift.run(transformerPath, pathsToModify, {
256+
verbose: flags.verbose,
257+
dry: flags.dry,
258+
print: true,
259+
babel: true,
260+
extensions: flags.extensions,
261+
ignorePattern: flags.ignorePattern,
262+
cpus: flags.cpus,
263+
ignoreConfig: [],
264+
runInBand: flags.runInBand,
265+
silent: false,
266+
parser: flags.parser,
267+
stdin: false,
268+
...jscodeshiftOptionOverrides,
269+
});
270+
271+
let transformImported: any;
272+
try {
273+
/**
274+
* TODO MAINTAINER -- i am not confident that this will work
275+
* if the transform was provided thru an npm package.
276+
*/
277+
278+
// eslint-disable-next-line @typescript-eslint/no-var-requires
279+
transformImported = require(resolvedTransformPath);
280+
} catch (_e) {}
281+
282+
const transformHasCustomRunner = (
283+
ti: any,
284+
): ti is {
285+
/**
286+
* ideally, `default` would be the type of the transformer,
287+
* which would be identical to the type of the argument to
288+
* `CustomTransformerConfig`,
289+
*
290+
* but unless we put the transformer itself into the config,
291+
* we cannot ensure that the type is correct.
292+
*
293+
*/
294+
default: unknown; //
295+
codeshiftConfig: CodeshiftConfig<unknown>;
296+
} => {
297+
if (ti && 'codeshiftConfig' in ti) {
298+
return 'runner' in transformImported['codeshiftConfig'];
299+
}
300+
return false;
301+
};
302+
303+
if (transformHasCustomRunner(transformImported)) {
304+
console.info(
305+
'\nusing CUSTOM runner for transform',
306+
resolvedTransformPath,
307+
);
308+
309+
await transformImported.codeshiftConfig.runner({
310+
pathsToModify: paths,
311+
defaultRunner,
312+
/**
313+
* providing the `transform`, `resolvedTransformPath`, etc. here
314+
* is quite useless, because it's file-based,
315+
* so in whichever file the config is in,
316+
* that default export will be the transform,
317+
* and the file's path will be the resolved path.
318+
*
319+
* ...unless you have a custom runner defined in a separate file,
320+
* and want it to be able to access the transform,
321+
* esp. if that runner does not take in a path,
322+
* but rather the transform function.
323+
*/
324+
transformInsideFileThatSpecifiesCodeshiftConfig:
325+
transformImported.default,
326+
// resolvedTransformPath
327+
});
328+
} else {
329+
console.info(
330+
'\nusing DEFAULT runner for transform',
331+
resolvedTransformPath,
332+
);
333+
334+
defaultRunner();
335+
}
251336
}
252337

253338
await packageManager.uninstallAll();

packages/types/src/index.ts

+24
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,27 @@ export interface CodeshiftConfig {
55
transforms?: Record<string, string>;
66
presets?: Record<string, string>;
77
}
8+
9+
export type DefaultRunner = (
10+
jscodeshiftOptionOverrides?: object,
11+
pathsToModify?: string[], //
12+
transformerPath?: string,
13+
) => Promise<void>;
14+
15+
export interface CustomRunnerCtx<Transform = unknown> {
16+
pathsToModify: string[]; //
17+
defaultRunner: DefaultRunner;
18+
transformInsideFileThatSpecifiesCodeshiftConfig: Transform;
19+
}
20+
21+
export type CustomRunner<
22+
Transform = unknown, //
23+
Return = unknown | Promise<unknown>,
24+
> = (ctx: CustomRunnerCtx<Transform>) => Return;
25+
26+
export interface CodeshiftConfig<
27+
Transform = unknown, //
28+
RunnerReturn = unknown | Promise<unknown>,
29+
> {
30+
runner: CustomRunner<Transform, RunnerReturn>;
31+
}

0 commit comments

Comments
 (0)