jscodeshift icon indicating copy to clipboard operation
jscodeshift copied to clipboard

Interactive Mode

Open NickHeiner opened this issue 6 years ago • 3 comments

image

I'd like to add a way for a human to have input on a codemod. This expands the range of what codemods can do.

For instance, consider the shift from CJS to ESM:

function A() {}
function B() {}
function C() {}
module.exports = { A, B, C};

// Option 1: The three values are standalone
export function A() {}
export function B() {}
export function C() {}

// Option 2: The three values are a single unit
const _export = {A, B, C}
export default _export;

Determining which of the two options are preferable would be programmatically prohibitively difficult, if not impossible. But I don't want to fall back to having to handle these cases entirely by hand. If the codemod knows which of the two cases it is, it can still do the rest of the work for me.

My dream is that this is a low-friction task where the user can quickly crank through a bunch of files, when questions are easy for humans to answer but hard for machines.

My suggested API is:

async function transformer(file, api) {
  // ...
  await api.prompt(node, {
    type: 'multiselect',
    name: 'namedExports',
    message: 'Choose the exports that should be converted to named exports.',
    choices: exportNames
  });
}

api.prompt is a wrapper around prompts. It applies some codemod-specific logic, like a syntax highlighted snippet of the relevant node.

Longer demo:

interactive codemod

I have a branch that produces a demo for this. I created it in a single day, so it's very proof-of-concept. If this fits with your vision of jscodeshift, I'll work to get it into a mergeable state, including exhaustive tests and docs.

Implementation Notes

  1. This requires #254. I could do that as a separate PR.
  2. This could become very complicated. I'd like to keep it as simple as possible and start small. Perhaps it would be labeled as an experimental API at first.
  3. I have a separate PR to prompts that would make this better.
  4. prompts relies on nothing else being written to the terminal. My branch has some work to ensure that only one part of the code writes to the terminal at once, but it only works with --run-in-band.
  5. Features I'd like to add that are not in the demo:
    • Undo: choose a different answer for a question you've already answered
    • Support multiple questions per file
    • Support for more than Node v13
    • The demo codemod I have is both too simplistic and also produces incorrect code. :smile:

NickHeiner avatar Nov 09 '19 00:11 NickHeiner

@NickHeiner I would hope something like this doesn't need to live in core. Esp because

  • I use inquirer a lot and never heard of prompts, it would be nice if people can use whatever they want
  • Some transforms might need to display more than one node of context for a given prompt
  • What if someone wants to use a full-blown Electron UI for user input?

This is a very good argument for async transform functions though.

jedwards1211 avatar Jan 29 '20 08:01 jedwards1211

I would happily start with implementing async transforms (#254). If I felt that there still needed to be a core change, that could be discussed later.

NickHeiner avatar Jan 29 '20 17:01 NickHeiner

Looks like there are already two PRs implementing async transforms: #325, #237. And another issue: #210.

NickHeiner avatar Sep 14 '20 21:09 NickHeiner