facebook / jscodeshift

A JavaScript codemod toolkit.
https://jscodeshift.com
MIT License
9.14k stars 471 forks source link

Multiple transform support #148

Open tivac opened 7 years ago

tivac commented 7 years ago

I've got a collection of transforms that don't really make sense to be run individually. I'd like to provide a straightforward way to run them all against a group of files. I don't see a way to do this with jscodeshift currently, but it seems useful.

ava-codemods does this by running jscodeshift once per transform. It's a bit brute-force, but it'll work for now until (if?) jscodeshift adds support.

fkling commented 7 years ago

That seems very reasonable to me. As a first step, we can pass multiple transforms to the workers and have them apply each one in series (will have to check how custom parser selections impacts this, but I think it should work without problem).

Later we could avoid code generation from the AST and provide a way to "chain" transforms and reuse the existing AST. That would require some thought around custom parsers though.

nickserv commented 7 years ago

We could use package based collections of transforms and modify the jscodeshift CLI to support running all of a package's transforms in sequence.

Cross post: https://github.com/facebook/jscodeshift/issues/126#issuecomment-265649259

benjamn commented 7 years ago

Recast doesn't care what you do to the AST between parsing and printing, so there shouldn't be any trouble chaining transforms there. You might want to reuse the same NodePath tree, though, so you don't have to recreate those objects for each transform.

stevecooperorg commented 7 years ago

A cheap and cheerful approach is to create a 'master' transform which uses the output of one transform as the input to the next. This is working fairly well for me; wouldn't call it production code but for the hacking I've been doing it suffices. Might be useful to someone else;

import fix1 from './fix1'
import fix2 from './fix2'
import fix3 from './fix3'

module.exports = function(file, api, options) {
    const fixes = [fix1,fix2,fix3];
    let src = file.source;
    fixes.forEach(fix => {
        if (typeof(src) === "undefined") { return; }
        src = fix({ ...file, source:src }, api, options);
    });
    return src;
};
stkao05 commented 6 years ago

@stevecooperorg Thanks for sharing the script 👍 Here is a slightly modified version which fixes the scenarios where some transform function could return nothing.

import fix1 from './fix1'
import fix2 from './fix2'
import fix3 from './fix3'

module.exports = function(file, api, options) {
    const fixes = [fix1,fix2,fix3];
    let src = file.source;
    fixes.forEach(fix => {
        if (typeof(src) === "undefined") { return; }
        const nextSrc = fix({ ...file, source:src }, api, options);

        if (nextSrc) {
            src = nextSrc;
        }
    });
    return src;
};
brysgo commented 6 years ago

I wrote jscodemigrate to do this a while back