diff --git a/.yarnrc.yml b/.yarnrc.yml index 00a2d6a..a325345 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -1 +1,2 @@ yarnPath: .yarn/releases/yarn-3.5.0.cjs +nodeLinker: node-modules diff --git a/codemod.yaml b/codemod.yaml new file mode 100644 index 0000000..1d06c56 --- /dev/null +++ b/codemod.yaml @@ -0,0 +1,7 @@ +schema_version: "1.0.0" +name: react-declassify-workflow +version: 1.0.0 +description: "React Class to Hook Codemod with AI review" +author: "istan" +engine: workflow +arguments: [] diff --git a/justfile b/justfile new file mode 100644 index 0000000..f222d6a --- /dev/null +++ b/justfile @@ -0,0 +1,36 @@ +default: + just -l + +# Build the project +build: + yarn install + yarn build + +# Install the packaged tarball globally on your machine +# Example of how to use afterwords: +# yarn dlx @codemod/cli --plugin react-declassify +install-global: pack + npm install -g ./package.tgz + +# Run tests +test: build + yarn test + +# Create a yarn tarball (equivalent to a Python wheel) +pack: build + yarn pack --filename package.tgz + +# Run the codemod locally using the built plugin against a target directory +# Usage: just run-local ../my-project/src +run-local target_dir: build + yarn dlx @codemod/cli --plugin ./dist/index.js '{{ target_dir }}/**/*.tsx' '{{ target_dir }}/**/*.ts' '{{ target_dir }}/**/*.jsx' '{{ target_dir }}/**/*.js' + +# Run the Codemod AI Workflow WITHOUT the AI step +# Usage: just run-workflow ../my-project/src +run-workflow target_dir: build + yarn dlx codemod@latest run . --target {{ target_dir }} + +# Run the Codemod AI Workflow WITH the AI step turned on +# Usage: just run-workflow-ai ../my-project/src +run-workflow-ai target_dir: build + yarn dlx codemod@latest run . --target {{ target_dir }} --autoAiReview=true diff --git a/workflow.yaml b/workflow.yaml new file mode 100644 index 0000000..971243f --- /dev/null +++ b/workflow.yaml @@ -0,0 +1,40 @@ +version: "1" + +params: + autoAiReview: + name: "Auto AI Review" + description: "Whether to use AI to review the transformed React components (requires LLM_API_KEY environment variable)" + type: boolean + default: false + +nodes: + - id: apply-transforms + name: Apply AST Transformations + type: automatic + steps: + - name: "Transform React class components to function components" + run: "npx -y @codemod/cli@3.3.0 --plugin ../../../react-declassify/cjs/dist/index.js ${TARGET:-src/} || true" + - id: ai-review + name: "AI Review" + type: automatic + if: "params.autoAiReview == true" + depends_on: + - apply-transforms + steps: + - name: "AI Code Review" + glob: "src/**/*.js" + ai: + max_tokens: 8000 + prompt: | + You are an expert React migration codemod agent. + Your job is to fix the remaining issues in the React codebase after an automatic class-to-function component transform. + Please search for all .js files in the src/ directory (especially src/components/ and src/reducers/ and src/control/) that contain the string `TODO_this` or `react-declassify-disable`. + For each file you find, you must edit it to fix the issues: + 1. If `TODO_this.shouldComponentUpdate` is used, remove it completely and rewrite the component export to use `React.memo(ComponentName, (prevProps, nextProps) => { ... })`. Make sure to convert any `props` variables and maintain identical behavior. WARNING: `shouldComponentUpdate` returns `true` to update. `React.memo` returns `true` to SKIP update. Invert the boolean logic! + 2. For component refs (like dom_rotate, dom_down, etc.), if they are accessed dynamically via `TODO_this[\`dom_${key}\`].dom`, replace that access with `eval(\`dom_${key}\`).current` or create a local object mapping keys to refs and use that. Make sure `TODO_this` is completely removed. + 3. Fix any eslint errors you might create: + - Ensure spaces before function parentheses (e.g., `function () {}` not `function(){}`). + - Ensure there are no missing trailing commas. + - If there are camelcase errors for variables like `dom_rotate`, either fix them to `domRotate` (and update all usages including string interpolation like `` \`dom_${key}\` ``) or add `/* eslint-disable camelcase */` at the top of the file to ignore them. + + Edit the files directly using your available tools. Do not stop until all instances of `TODO_this` are removed from the src/ directory.