Skip to content

Commit 90ff797

Browse files
committed
feat: allow providing custom runner per transform file thru CodeshiftConfig
depends on: - hypermod-io#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: - hypermod-io#67 Signed-off-by: Kipras Melnikovas <kipras@kipras.org>
1 parent d50c7fd commit 90ff797

File tree

2 files changed

+104
-14
lines changed

2 files changed

+104
-14
lines changed

packages/cli/src/main.ts

Lines changed: 84 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,16 @@ import { PluginManager } from 'live-plugin-manager';
66
import merge from 'lodash/merge';
77
// @ts-ignore Run transform(s) on path https://github.com/facebook/jscodeshift/issues/398
88
import * as jscodeshift from 'jscodeshift/src/Runner';
9+
<<<<<<< HEAD
910
import { isValidConfig } from '@codeshift/validator';
1011
import { CodeshiftConfig } from '@codeshift/types';
12+
||||||| parent of e03ebd1 (feat: allow providing custom runner per transform file thru CodeshiftConfig)
13+
=======
14+
import {
15+
CodeshiftConfig, //
16+
DefaultRunner,
17+
} from '@codeshift/types';
18+
>>>>>>> e03ebd1 (feat: allow providing custom runner per transform file thru CodeshiftConfig)
1119

1220
import { Flags } from './types';
1321
import { InvalidUserInputError } from './errors';
@@ -219,20 +227,82 @@ Make sure the package name ${pkgName} has been spelled correctly and exists befo
219227
const resolvedTransformPath = path.resolve(transform);
220228
console.log(chalk.green('Running transform:'), resolvedTransformPath);
221229

222-
await jscodeshift.run(resolvedTransformPath, paths, {
223-
verbose: 0,
224-
dry: flags.dry,
225-
print: true,
226-
babel: true,
227-
extensions: flags.extensions,
228-
ignorePattern: flags.ignorePattern,
229-
cpus: flags.cpus,
230-
ignoreConfig: [],
231-
runInBand: flags.runInBand,
232-
silent: false,
233-
parser: flags.parser,
234-
stdin: false,
235-
});
230+
const defaultRunner: DefaultRunner = (
231+
/**
232+
* ideally you'd be able to pass in either the path,
233+
* or the actual transform,
234+
* but jscodeshift doesn't allow this (unless we fork?)
235+
*/
236+
jscodeshiftOptionOverrides = {},
237+
pathsToModify = paths,
238+
transformerPath: string = resolvedTransformPath,
239+
): Promise<void> =>
240+
jscodeshift.run(transformerPath, pathsToModify, {
241+
verbose: 0,
242+
dry: flags.dry,
243+
print: true,
244+
babel: true,
245+
extensions: flags.extensions,
246+
ignorePattern: flags.ignorePattern,
247+
cpus: flags.cpus,
248+
ignoreConfig: [],
249+
runInBand: flags.runInBand,
250+
silent: false,
251+
parser: flags.parser,
252+
stdin: false,
253+
...jscodeshiftOptionOverrides,
254+
});
255+
256+
let transformImported: any;
257+
try {
258+
// eslint-disable-next-line @typescript-eslint/no-var-requires
259+
transformImported = require(resolvedTransformPath);
260+
} catch (_e) {}
261+
console.log({ transformImported });
262+
263+
const transformHasCustomRunner = (
264+
ti: any,
265+
): ti is {
266+
/**
267+
* ideally, `default` would be the type of the transformer,
268+
* which would be identical to the type of the argument to
269+
* `CustomTransformerConfig`,
270+
*
271+
* but unless we put the transformer itself into the config,
272+
* we cannot ensure that the type is correct.
273+
*
274+
*/
275+
default: unknown; //
276+
codeshiftConfig: CodeshiftConfig<unknown>;
277+
} => {
278+
if (ti && 'codeshiftConfig' in ti) {
279+
return 'runner' in transformImported['codeshiftConfig'];
280+
}
281+
return false;
282+
};
283+
284+
if (transformHasCustomRunner(transformImported)) {
285+
await transformImported.codeshiftConfig.runner(paths, {
286+
defaultRunner,
287+
/**
288+
* providing the `transform`, `resolvedTransformPath`, etc. here
289+
* is quite useless, because it's file-based,
290+
* so in whichever file the config is in,
291+
* that default export will be the transform,
292+
* and the file's path will be the resolved path.
293+
*
294+
* ...unless you have a custom runner defined in a separate file,
295+
* and want it to be able to access the transform,
296+
* esp. if that runner does not take in a path,
297+
* but rather the transform function.
298+
*/
299+
transformInsideFileThatSpecifiesCodeshiftConfig:
300+
transformImported.default,
301+
// resolvedTransformPath
302+
});
303+
} else {
304+
defaultRunner();
305+
}
236306
}
237307

238308
await packageManager.uninstallAll();

packages/types/src/index.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,23 @@ 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+
transformInsideFileThatSpecifiesCodeshiftConfig: Transform;
17+
defaultRunner: DefaultRunner;
18+
}
19+
20+
export type CustomRunner<Transform = unknown> = (
21+
pathsToModify: string[], //
22+
options: CustomRunnerCtx<Transform>,
23+
) => void | Promise<void>;
24+
25+
export interface CodeshiftConfig<Transform = unknown> {
26+
runner: CustomRunner<Transform>;
27+
}

0 commit comments

Comments
 (0)