Skip to content

Commit e0eed72

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 <kipras@kipras.org>
1 parent 73ed5b4 commit e0eed72

File tree

2 files changed

+127
-15
lines changed

2 files changed

+127
-15
lines changed

packages/cli/src/main.ts

Lines changed: 103 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ import * as jscodeshift from 'jscodeshift/src/Runner';
88

99
import { fetchPackage, fetchRemotePackage } from '@codeshift/fetcher';
1010
import { isValidConfig } from '@codeshift/validator';
11-
import { CodeshiftConfig } from '@codeshift/types';
11+
import {
12+
CodeshiftConfig, //
13+
DefaultRunner,
14+
} from '@codeshift/types';
1215

1316
import { Flags } from './types';
1417
import { InvalidUserInputError } from './errors';
@@ -184,20 +187,105 @@ Make sure the package name "${pkgName}" is correct and try again.`,
184187
const resolvedTransformPath = path.resolve(transform);
185188
console.log(chalk.green('Running transform:'), resolvedTransformPath);
186189

187-
await jscodeshift.run(resolvedTransformPath, paths, {
188-
verbose: flags.verbose,
189-
dry: flags.dry,
190-
print: true,
191-
babel: true,
192-
extensions: flags.extensions,
193-
ignorePattern: flags.ignorePattern,
194-
cpus: flags.cpus,
195-
ignoreConfig: [],
196-
runInBand: flags.runInBand,
197-
silent: false,
198-
parser: flags.parser,
199-
stdin: false,
200-
});
190+
const defaultRunner: DefaultRunner = (
191+
jscodeshiftOptionOverrides = {},
192+
pathsToModify = paths,
193+
/**
194+
* ideally you'd be able to pass in either the path,
195+
* or the actual transform,
196+
* but jscodeshift doesn't allow this (unless we fork?)
197+
*/
198+
transformerPath: string = resolvedTransformPath,
199+
/**
200+
* i think the jscodeshift.run is synchronous
201+
* so the promise is not needed,
202+
* but if we want to change it in the future,
203+
* making it's return type a promise will help
204+
* to avoid breaking changes for consumers who
205+
* use the defaultRunner.
206+
*/
207+
): Promise<void> =>
208+
jscodeshift.run(transformerPath, pathsToModify, {
209+
verbose: flags.verbose,
210+
dry: flags.dry,
211+
print: true,
212+
babel: true,
213+
extensions: flags.extensions,
214+
ignorePattern: flags.ignorePattern,
215+
cpus: flags.cpus,
216+
ignoreConfig: [],
217+
runInBand: flags.runInBand,
218+
silent: false,
219+
parser: flags.parser,
220+
stdin: false,
221+
...jscodeshiftOptionOverrides,
222+
});
223+
224+
let transformImported: any;
225+
try {
226+
/**
227+
* TODO MAINTAINER -- i am not confident that this will work
228+
* if the transform was provided thru an npm package.
229+
*/
230+
231+
// eslint-disable-next-line @typescript-eslint/no-var-requires
232+
transformImported = require(resolvedTransformPath);
233+
} catch (_e) {}
234+
235+
const transformHasCustomRunner = (
236+
ti: any,
237+
): ti is {
238+
/**
239+
* ideally, `default` would be the type of the transformer,
240+
* which would be identical to the type of the argument to
241+
* `CustomTransformerConfig`,
242+
*
243+
* but unless we put the transformer itself into the config,
244+
* we cannot ensure that the type is correct.
245+
*
246+
*/
247+
default: unknown; //
248+
codeshiftConfig: CodeshiftConfig<unknown>;
249+
} => {
250+
if (ti && 'codeshiftConfig' in ti) {
251+
return 'runner' in transformImported['codeshiftConfig'];
252+
}
253+
return false;
254+
};
255+
256+
if (transformHasCustomRunner(transformImported)) {
257+
console.info(
258+
'\nusing CUSTOM runner for transform',
259+
resolvedTransformPath,
260+
);
261+
262+
await transformImported.codeshiftConfig.runner({
263+
pathsToModify: paths,
264+
defaultRunner,
265+
/**
266+
* providing the `transform`, `resolvedTransformPath`, etc. here
267+
* is quite useless, because it's file-based,
268+
* so in whichever file the config is in,
269+
* that default export will be the transform,
270+
* and the file's path will be the resolved path.
271+
*
272+
* ...unless you have a custom runner defined in a separate file,
273+
* and want it to be able to access the transform,
274+
* esp. if that runner does not take in a path,
275+
* but rather the transform function.
276+
*/
277+
transformInsideFileThatSpecifiesCodeshiftConfig:
278+
transformImported.default,
279+
// resolvedTransformPath
280+
});
281+
} else {
282+
console.info(
283+
'\nusing DEFAULT runner for transform',
284+
resolvedTransformPath,
285+
);
286+
287+
defaultRunner();
288+
}
201289
}
202290

203291
await packageManager.uninstallAll();

packages/types/src/index.ts

Lines changed: 24 additions & 0 deletions
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)