Skip to content

Commit 6886f1c

Browse files
committed
feat: allow providing custom runner per transform file thru CodeshiftConfig
depends on: hypermod-io#63 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 <[email protected]>
1 parent 2821bdb commit 6886f1c

File tree

2 files changed

+107
-14
lines changed

2 files changed

+107
-14
lines changed

packages/cli/src/main.ts

Lines changed: 80 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import chalk from 'chalk';
44
import { PluginManager } from 'live-plugin-manager';
55
// @ts-ignore Run transform(s) on path https://github.com/facebook/jscodeshift/issues/398
66
import * as jscodeshift from 'jscodeshift/src/Runner';
7+
import {
8+
CodeshiftConfig, //
9+
DefaultRunner,
10+
} from '@codeshift/types';
711

812
import { Flags } from './types';
913
import { InvalidUserInputError } from './errors';
@@ -130,20 +134,82 @@ export default async function main(paths: string[], flags: Flags) {
130134
const resolvedTransformPath = path.resolve(transform);
131135
console.log(chalk.green('Running transform:'), resolvedTransformPath);
132136

133-
await jscodeshift.run(resolvedTransformPath, paths, {
134-
verbose: 0,
135-
dry: flags.dry,
136-
print: true,
137-
babel: true,
138-
extensions: flags.extensions,
139-
ignorePattern: flags.ignorePattern,
140-
cpus: flags.cpus,
141-
ignoreConfig: [],
142-
runInBand: flags.runInBand,
143-
silent: false,
144-
parser: flags.parser,
145-
stdin: false,
146-
});
137+
const defaultRunner: DefaultRunner = (
138+
/**
139+
* ideally you'd be able to pass in either the path,
140+
* or the actual transform,
141+
* but jscodeshift doesn't allow this (unless we fork?)
142+
*/
143+
jscodeshiftOptionOverrides = {},
144+
pathsToModify = paths,
145+
transformerPath: string = resolvedTransformPath,
146+
): Promise<void> =>
147+
jscodeshift.run(transformerPath, pathsToModify, {
148+
verbose: 0,
149+
dry: flags.dry,
150+
print: true,
151+
babel: true,
152+
extensions: flags.extensions,
153+
ignorePattern: flags.ignorePattern,
154+
cpus: flags.cpus,
155+
ignoreConfig: [],
156+
runInBand: flags.runInBand,
157+
silent: false,
158+
parser: flags.parser,
159+
stdin: false,
160+
...jscodeshiftOptionOverrides,
161+
});
162+
163+
let transformImported: any;
164+
try {
165+
// eslint-disable-next-line @typescript-eslint/no-var-requires
166+
transformImported = require(resolvedTransformPath);
167+
} catch (_e) {}
168+
console.log({ transformImported });
169+
170+
const transformHasCustomRunner = (
171+
ti: any,
172+
): ti is {
173+
/**
174+
* ideally, `default` would be the type of the transformer,
175+
* which would be identical to the type of the argument to
176+
* `CustomTransformerConfig`,
177+
*
178+
* but unless we put the transformer itself into the config,
179+
* we cannot ensure that the type is correct.
180+
*
181+
*/
182+
default: unknown; //
183+
codeshiftConfig: CodeshiftConfig<unknown>;
184+
} => {
185+
if (ti && 'codeshiftConfig' in ti) {
186+
return 'runner' in transformImported['codeshiftConfig'];
187+
}
188+
return false;
189+
};
190+
191+
if (transformHasCustomRunner(transformImported)) {
192+
await transformImported.codeshiftConfig.runner(paths, {
193+
defaultRunner,
194+
/**
195+
* providing the `transform`, `resolvedTransformPath`, etc. here
196+
* is quite useless, because it's file-based,
197+
* so in whichever file the config is in,
198+
* that default export will be the transform,
199+
* and the file's path will be the resolved path.
200+
*
201+
* ...unless you have a custom runner defined in a separate file,
202+
* and want it to be able to access the transform,
203+
* esp. if that runner does not take in a path,
204+
* but rather the transform function.
205+
*/
206+
transformInsideFileThatSpecifiesCodeshiftConfig:
207+
transformImported.default,
208+
// resolvedTransformPath
209+
});
210+
} else {
211+
defaultRunner();
212+
}
147213
}
148214

149215
await packageManager.uninstallAll();

packages/types/src/index.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
export interface CodeshiftConfig {
2+
target?: string[];
3+
maintainers?: string[];
4+
description?: string;
5+
transforms?: Record<string, string>;
6+
presets?: Record<string, string>;
7+
}
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)