Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interactive Mode #352

Open
NickHeiner opened this issue Nov 9, 2019 · 3 comments
Open

Interactive Mode #352

NickHeiner opened this issue Nov 9, 2019 · 3 comments

Comments

@NickHeiner
Copy link

NickHeiner commented Nov 9, 2019

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 Asynchronous code in transformers #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. 😄
@jedwards1211
Copy link
Contributor

@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.

@NickHeiner
Copy link
Author

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
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants