trendmicro-frontend / tonic-ui

Tonic UI is a UI component library for React, built with Emotion and Styled System. It is designed to be easy to use and easy to customize.
https://trendmicro-frontend.github.io/tonic-ui
MIT License
125 stars 28 forks source link

Address issues caused by Codemod during migration from v1 to v2 #875

Closed UMNIYAH closed 2 months ago

UMNIYAH commented 2 months ago

Here are some issues I faced when following the migration guide v1 to v2; running Codemod on Typescript files

Here is a simplified example of what caused the transformation error:

function Component({icon}){
  return <>{ icon || <Icon icon="info-o"/> }
  }


cheton commented 2 months ago

An unnecessary set of parenthesis gets added around everything between return statements. This is not an issue when the return statement comes after a conditional (i.e. if statement).

I also encountered this issue while developing the import-react-icons codemod. Unfortunately, I'm unable to find a solution to remove these parentheses. If you discover any solutions, please feel free to contribute.

cheton commented 2 months ago

One of my icons was not transformed and caused an error. There was a variable called icon in that file, and I think the parser expected it to be the icon component. Maybe, you can mention a warning if this issue cannot be fixed. Here is a simplified example of what caused the transformation error:

function Component({icon}){ return <>{ icon || } }

The error was resolved by adding a closing fragment </> element in your example. Did it solve your issue?

image

Here is the transformed result:

function Component({icon}){
  return <>{ icon || <Icon as={InfoOIcon}/> }</>;
  }
derekhawker commented 2 months ago

The error was resolved by adding a closing fragment </> element in your example. Did it solve your issue

I think we could mention this in the migration docs as a known limitation that needs manual inspection. Devs using the codemod tool will want to search their code for strings like '&& <Icon ' or '|| <Icon ' to verify those icons were updated or need to be manually changed.

It's an easy thing to miss on large codebases when someone will be busy trying to verify large code diffs triggered by the codemod tool.

cheton commented 2 months ago

One more thing to mention, I was not able to exclude JSON files even though I ran the following: npx @tonic-ui/codemod@latest react/v2.0.0/import-react-icons src --parser=tsx --extensions=ts,tsx Is there another way for them to be filtered out?

It turns out the --extensions option was hard-coded with js,ts,jsx,tsx,json in the code:

  const args = [
    // can't directly spawn `jscodeshiftExecutable` due to https://github.com/facebook/jscodeshift/issues/424
    jscodeshiftExecutable,
    '--transform',
    transformPath,
    ...codemodFlags,
    '--extensions',
    'js,ts,jsx,tsx,json',
    '--parser',
    flags.parser || 'babel',
    '--ignore-pattern',
    '**/node_modules/**',
  ];

I need to make minor changes to the codemod to provide configurable options.

derekhawker commented 2 months ago

@cheton Thanks for the explanation about the hardcoded json extension. Once that was removed it was easier to see that the codemod tool was throwing an error. This code throws an error during transformation:

import { Icon } from '@tonic-ui/react';
import React from 'react';

export default () => {
  return <Icon icon="alert" {...restProps} />;
};

image

When we iterate over the attributes, restProp causes an error because it's a Node of type 'JSXSpreadAttribute' and it doesn't have a name property.

Seems there are a couple fixes, but maybe the easiest is to check if attribute.type === 'JSXSpreadAttribute' and return early

  path.node.openingElement.attributes = path.node.openingElement.attributes.reduce((acc, attribute) => {
     if (attribute.type === "JSXSpreadAttribute") {
        return [...acc, attribute];
      }
      if (attribute.name.name === 'icon') {
        ...
cheton commented 2 months ago

This optional chaining operator (?.) could also work correctly in this context:

if (attribute.name?.name === 'icon') {

This will be fixed in the commit https://github.com/trendmicro-frontend/tonic-ui/pull/877/commits/d0fa7d8ef21fc4d58b89b615e03d23f5574d5bfb of PR #877

cheton commented 2 months ago

Hi @UMNIYAH and @derekhawker

If you have come across any patterns that could cause the codemod process to fail, please inform me or submit a PR (recommended) to update test fixtures and import-react-icons codemod accordingly.

cheton commented 2 months ago

@tonic-ui/codemod 2.1.0 has been released. The default extensions now changed to .js only.

$ npx @tonic-ui/codemod@latest react/v2.0.0/import-react-icons --help
npx @tonic-ui/codemod <codemod> <paths...>

Applies a `@tonic-ui/codemod` to the specified paths

Positionals:
  codemod  The name of the codemod to apply                             [string]
  paths    The paths to the codebase that will be forwarded to `jscodeshift`
                                                                        [string]

Options:
  --version         Show version number                                [boolean]
  --help            Show help                                          [boolean]
  --dry             dry run (no changes are made to files)
                                                      [boolean] [default: false]
  --extensions      transform files with these file extensions (comma separated
                    list)                               [string] [default: "js"]
  --ignore-pattern  ignore files that match a provided glob expression
                                        [string] [default: "**/node_modules/**"]
  --parser          the parser to use for parsing the source files
                    (--parser=babel|babylon|flow|ts|tsx)
                                                     [string] [default: "babel"]
  --print           print transformed files to stdout, useful for development
                                                      [boolean] [default: false]
  --verbose         show more information about the transform process
                    (--verbose=0|1|2)                      [number] [default: 0]
  --jscodeshift     pass options directly to jscodeshift
                                                       [string] [default: false]

Examples:
  npx @tonic-ui/codemod react/v2.0.0/import-react-icons src

For JavaScript files:

npx @tonic-ui/codemod@latest react/v2.0.0/import-react-icons . --extensions=js,jsx --verbose=2

For TypeScript files:

npx @tonic-ui/codemod@latest react/v2.0.0/import-react-icons . --extensions=ts,tsx --parser=tsx --verbose=2