facebook / jscodeshift

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

The transformation with ImportDeclaration does not work on a TypeScript file when `--parser=ts` is passed. #489

Closed trivikr closed 2 years ago

trivikr commented 2 years ago

Describe the bug

The transformation doesn't work on a TypeScript file when --parser=ts is passed.

jscodeshift: 0.13.1
 - babel: 7.17.5
 - babylon: 7.17.3
 - flow: 0.173.0
 - recast: 0.20.5

Steps to reproduce

Stackblitz: https://stackblitz.com/edit/node-dykwqt?devtoolsheight=33&file=transform.js Run npx jscodeshift example.ts --parser=ts in console.

To reproduce in your workspace, add the following files:

transform.js ```js // transform.js module.exports = function (fileInfo, api) { const j = api.jscodeshift; const source = j(fileInfo.source); source .find(j.ImportDeclaration, { source: { type: "Literal", value: "react" }, }) .replaceWith((nodePath) => { const { node } = nodePath; node.specifiers = [j.importDefaultSpecifier(j.identifier("Vue"))]; node.source.value = "vue"; return node; }); return source.toSource(); }; ```
example.ts ```ts // example.ts import React from "react"; ```

Observed behavior

On running the command with --parser=ts the transformation doesn't happen:

Processing 1 files... 
Spawning 1 workers...
Sending 1 files to free worker...
All done. 
Results: 
0 errors
1 unmodified
0 skipped
0 ok
Time elapsed: 0.592seconds

Expected behavior

The transformation to complete as follows:

Processing 1 files... 
Spawning 1 workers...
Sending 1 files to free worker...
All done. 
Results: 
0 errors
0 unmodified
0 skipped
1 ok
Time elapsed: 0.959seconds

With contents of example.ts changed to:

// example.ts
import Vue from "vue";

Additional context

trivikr commented 2 years ago

The transformation with ImportDeclaration probably doesn't work with --parser=ts as TypeScript transpiles the code to use require before transformation can process the file.

trivikr commented 2 years ago

This happens because literal is of type StringLiteral when parser=ts and is of type Literal when parser=babel.

This can be fixed by removing type: "Literal" from transformer:

// transform.js
module.exports = function (fileInfo, api) {
  const j = api.jscodeshift;
  const source = j(fileInfo.source);

  source
    .find(j.ImportDeclaration, {
      source: { value: "react" },
    })
    .replaceWith((nodePath) => {
      const { node } = nodePath;
      node.specifiers = [j.importDefaultSpecifier(j.identifier("Vue"))];
      node.source.value = "vue";
      return node;
    });

  return source.toSource();
};

Tested fix in https://stackblitz.com/edit/node-tzzm8u?devtoolsheight=33&file=transform.js