Skip to content

Conversation

@brkalow
Copy link
Member

@brkalow brkalow commented Dec 5, 2025

Description

The Upgrade CLI has been restructured to better handle current and upcoming releases. The internals have been simplified and release-specific logic has been consolidated out of the core logic.

  • Remove ink usage
  • Remove core-2 upgrade support. If folks need to upgrade, they can use a previous major of @clerk/upgrade
  • Adds a test suite for the upgrade CLI
  • Introduces a release manifest for core 3
  • Introduces codemods for deprecations and breaking changes

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Core 3 upgrade support via an interactive CLI with prompts, spinners, dry‑run and skip‑upgrade modes, clear summaries, and guided upgrade messages.
    • Automated codemods for package renames, theme/import updates, and appearance prop migrations.
    • Improved SDK and package manager detection and upgrade command execution.
  • Tests

    • Extensive new unit/integration tests and fixtures covering CLI flows, detection, codemods, and scans.
  • Chores

    • Added changeset documenting the major release.

✏️ Tip: You can customize this high-level summary in your review settings.

@changeset-bot
Copy link

changeset-bot bot commented Dec 5, 2025

🦋 Changeset detected

Latest commit: 3c2e9bd

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@clerk/upgrade Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 5, 2025

Walkthrough

Replace the Ink/React interactive upgrade UI with an imperative CLI flow; add SDK detection, package-manager utilities, codemod runner and scan tooling; add Core 3 upgrade metadata, codemods, fixtures, helpers, and integration tests; remove prior UI components and legacy utilities.

Changes

Cohort / File(s) Summary
Changeset & Config
\.changeset/busy-tires-admire.md, eslint.config.mjs, packages/upgrade/package.json
Add a changeset declaring a major @clerk/upgrade release; update ESLint ignores and package-specific rule overrides; remove multiple Ink-related deps from packages/upgrade/package.json and add chalk.
Test Fixtures
packages/upgrade/src/__tests__/fixtures/*
Add multiple fixture projects: expo-old-package, nextjs-v6, nextjs-v7, react-v6, and no-clerk with package.json and sample source files demonstrating various SDK states.
Fixture Helpers
packages/upgrade/src/__tests__/helpers/create-fixture.js
New test helper utilities to locate fixtures, create temp copies with cleanup, read/write fixture files, and check file existence.
Integration Tests
packages/upgrade/src/__tests__/integration/*.test.js
Add integration test suites for CLI behavior, config loading/releases, SDK detection/normalization, package manager detection, and runner/scan behavior.
Codemod Fixtures & Tests
packages/upgrade/src/codemods/__tests__/__fixtures__/*, packages/upgrade/src/codemods/__tests__/transform-*.test.js
Add fixtures and parameterized tests for codemods: align-experimental-unstable-prefixes, appearance-layout-to-options, remove-deprecated-appearance-props, themes-to-ui-themes.
Codemod Implementations
packages/upgrade/src/codemods/*.cjs, packages/upgrade/src/codemods/index.js
Implement four jscodeshift TSX codemods and enhance codemod runner: dry-run/skip, new glob ignore patterns, getCodemodConfig, and renderDeprecatedPropsSummary.
CLI Core & Rendering
packages/upgrade/src/cli.js, packages/upgrade/src/render.js, packages/upgrade/src/config.js, packages/upgrade/src/runner.js
Replace Ink app with imperative main() CLI flow; add render utilities (prompts, spinners, messages), loadConfig, and runner functions runCodemods/runScans; add orchestration for dry-run, skip-upgrade, and release handling.
SDK & Package Tools
packages/upgrade/src/util/detect-sdk.js, packages/upgrade/src/util/package-manager.js
Add SDK detection/version utilities and package-manager helpers (detect, install/uninstall/upgrade commands, run commands, display names).
Added Version Metadata
packages/upgrade/src/versions/core-3/*
Add Core 3 upgrade entry and changelog markdowns documenting package renames (@clerk/clerk-react@clerk/react, @clerk/clerk-expo@clerk/expo) and codemod list.
Removed UI Components
packages/upgrade/src/app.js, packages/upgrade/src/components/*.js
Remove Ink-based components and orchestrator: app.js and components Header, Scan, SDKWorkflow, Codemod, Command, UpgradeSDK, plus related utilities.
Removed Legacy Utils
packages/upgrade/src/util/get-clerk-version.js, packages/upgrade/src/util/guess-framework.js, packages/upgrade/src/util/expandable-list.js
Remove older utilities for Clerk version detection, framework guessing, and the expandable-list UI (replaced by new CLI/runner utilities).

Sequence Diagram

sequenceDiagram
    actor User
    participant CLI as CLI Main
    participant Detect as SDK Detector
    participant Config as Config Loader
    participant Codemods as Codemod Runner
    participant Scanner as Scan Runner
    participant PkgMgr as Package Manager

    User->>CLI: run upgrade command
    CLI->>Detect: detectSdk(dir)
    Detect-->>CLI: sdk type & version

    CLI->>Config: loadConfig(sdk, version | release)
    Config-->>CLI: config (codemods, changes, versions)

    CLI->>CLI: promptConfirm(...)
    alt user confirms
        CLI->>Codemods: runCodemods(config, sdk, options)
        Codemods-->>CLI: codemod results

        CLI->>Scanner: runScans(config, sdk, options)
        Scanner-->>CLI: scan results

        CLI->>PkgMgr: detectPackageManager(dir)
        PkgMgr-->>CLI: manager

        CLI->>PkgMgr: perform upgrade (remove/upgrade packages)
        PkgMgr-->>CLI: success/error
    end

    CLI-->>User: renderComplete / summary
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Review focus:
    • packages/upgrade/src/cli.js — orchestration, interactive vs non-interactive flows, and error handling.
    • packages/upgrade/src/config.js — release selection, change parsing, and version status logic.
    • packages/upgrade/src/codemods/*.cjs & packages/upgrade/src/codemods/index.js — AST transforms, edge cases, and renderSummary hooks.
    • packages/upgrade/src/runner.js — globbing, matcher loading, match deduplication, and position calculation.
    • packages/upgrade/src/render.js — prompt/spinner correctness and terminal IO behavior.
    • Integration tests and fixture helpers — temp fixture creation, cleanup, and deterministic test behavior.

Poem

🐰 I hopped from Ink to terminal light,

Codemods nibble through the quiet night.
Core 3 renamed and fixtures align,
Spinners spin, tests pass in a line.
Chalk marks the path — upgrade done, delight.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: restructuring the upgrade CLI to support multiple releases, which aligns with the PR's primary objective of consolidating release-specific logic.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch brk.feat/upgrade-cli-core-3

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 243fc07 and 3c2e9bd.

📒 Files selected for processing (3)
  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx (1 hunks)
  • packages/upgrade/src/__tests__/integration/runner.test.js (1 hunks)
  • packages/upgrade/src/versions/core-3/changes/clerk-react-package-rename.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/upgrade/src/tests/integration/runner.test.js
  • packages/upgrade/src/versions/core-3/changes/clerk-react-package-rename.md
  • packages/upgrade/src/tests/fixtures/nextjs-v6/src/app.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (28)
  • GitHub Check: Integration Tests (nextjs, chrome, 16, RQ)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (quickstart, chrome, 16)
  • GitHub Check: Integration Tests (quickstart, chrome, 15)
  • GitHub Check: Integration Tests (nextjs, chrome, 16)
  • GitHub Check: Integration Tests (machine, chrome, RQ)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (billing, chrome, RQ)
  • GitHub Check: Integration Tests (machine, chrome)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (vue, chrome)
  • GitHub Check: Integration Tests (sessions:staging, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (handshake, chrome)
  • GitHub Check: Integration Tests (custom, chrome)
  • GitHub Check: Integration Tests (handshake:staging, chrome)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan

Comment @coderabbitai help to get the list of available commands and usage tips.

@vercel
Copy link

vercel bot commented Dec 5, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
clerk-js-sandbox Skipped Skipped Dec 8, 2025 10:45pm

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 5, 2025

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7385

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7385

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7385

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7385

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7385

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7385

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@7385

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7385

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7385

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7385

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7385

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7385

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7385

@clerk/react

npm i https://pkg.pr.new/@clerk/react@7385

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7385

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7385

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7385

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7385

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@7385

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7385

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7385

commit: 3c2e9bd

@brkalow
Copy link
Member Author

brkalow commented Dec 5, 2025

!allow-major

Comment on lines +1 to +23
export default {
id: 'core-3',
name: 'Core 3',
docsUrl: 'https://clerk.com/docs/upgrade-guides/core-3',
sdkVersions: {
nextjs: { from: 6, to: 7 },
react: { from: 5, to: 7 },
expo: { from: 2, to: 3 },
'react-router': { from: 2, to: 3 },
'tanstack-react-start': { from: 0, to: 1 },
astro: { from: 2, to: 3 },
nuxt: { from: 2, to: 3 },
vue: { from: 2, to: 3 },
},
codemods: [
'transform-clerk-react-v6',
'transform-remove-deprecated-props',
'transform-remove-deprecated-appearance-props',
'transform-appearance-layout-to-options',
'transform-themes-to-ui-themes',
'transform-align-experimental-unstable-prefixes',
],
};
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New version/release manifest that outlines a version's impacted SDKs and changes. We can use this for only specific SDKs if necessary as well.

@nikosdouvlis nikosdouvlis deleted the branch main December 8, 2025 19:21
@brkalow brkalow reopened this Dec 8, 2025
@brkalow brkalow changed the base branch from vincent-and-the-doctor to main December 8, 2025 19:34
@jacekradko
Copy link
Member

!snapshot

@clerk-cookie
Copy link
Collaborator

Hey @jacekradko - the snapshot version command generated the following package versions:

Package Version
@clerk/agent-toolkit 0.2.7-snapshot.v20251208202852
@clerk/astro 3.0.0-snapshot.v20251208202852
@clerk/backend 3.0.0-snapshot.v20251208202852
@clerk/chrome-extension 3.0.0-snapshot.v20251208202852
@clerk/clerk-js 6.0.0-snapshot.v20251208202852
@clerk/dev-cli 1.0.0-snapshot.v20251208202852
@clerk/expo 3.0.0-snapshot.v20251208202852
@clerk/expo-passkeys 1.0.0-snapshot.v20251208202852
@clerk/express 2.0.0-snapshot.v20251208202852
@clerk/fastify 2.6.7-snapshot.v20251208202852
@clerk/localizations 4.0.0-snapshot.v20251208202852
@clerk/nextjs 7.0.0-snapshot.v20251208202852
@clerk/nuxt 2.0.0-snapshot.v20251208202852
@clerk/react 6.0.0-snapshot.v20251208202852
@clerk/react-router 3.0.0-snapshot.v20251208202852
@clerk/shared 4.0.0-snapshot.v20251208202852
@clerk/tanstack-react-start 1.0.0-snapshot.v20251208202852
@clerk/testing 2.0.0-snapshot.v20251208202852
@clerk/ui 1.0.0-snapshot.v20251208202852
@clerk/upgrade 2.0.0-snapshot.v20251208202852
@clerk/vue 2.0.0-snapshot.v20251208202852

Tip: Use the snippet copy button below to quickly install the required packages.
@clerk/agent-toolkit

npm i @clerk/agent-toolkit@0.2.7-snapshot.v20251208202852 --save-exact

@clerk/astro

npm i @clerk/astro@3.0.0-snapshot.v20251208202852 --save-exact

@clerk/backend

npm i @clerk/backend@3.0.0-snapshot.v20251208202852 --save-exact

@clerk/chrome-extension

npm i @clerk/chrome-extension@3.0.0-snapshot.v20251208202852 --save-exact

@clerk/clerk-js

npm i @clerk/clerk-js@6.0.0-snapshot.v20251208202852 --save-exact

@clerk/dev-cli

npm i @clerk/dev-cli@1.0.0-snapshot.v20251208202852 --save-exact

@clerk/expo

npm i @clerk/expo@3.0.0-snapshot.v20251208202852 --save-exact

@clerk/expo-passkeys

npm i @clerk/expo-passkeys@1.0.0-snapshot.v20251208202852 --save-exact

@clerk/express

npm i @clerk/express@2.0.0-snapshot.v20251208202852 --save-exact

@clerk/fastify

npm i @clerk/fastify@2.6.7-snapshot.v20251208202852 --save-exact

@clerk/localizations

npm i @clerk/localizations@4.0.0-snapshot.v20251208202852 --save-exact

@clerk/nextjs

npm i @clerk/nextjs@7.0.0-snapshot.v20251208202852 --save-exact

@clerk/nuxt

npm i @clerk/nuxt@2.0.0-snapshot.v20251208202852 --save-exact

@clerk/react

npm i @clerk/react@6.0.0-snapshot.v20251208202852 --save-exact

@clerk/react-router

npm i @clerk/react-router@3.0.0-snapshot.v20251208202852 --save-exact

@clerk/shared

npm i @clerk/shared@4.0.0-snapshot.v20251208202852 --save-exact

@clerk/tanstack-react-start

npm i @clerk/tanstack-react-start@1.0.0-snapshot.v20251208202852 --save-exact

@clerk/testing

npm i @clerk/testing@2.0.0-snapshot.v20251208202852 --save-exact

@clerk/ui

npm i @clerk/ui@1.0.0-snapshot.v20251208202852 --save-exact

@clerk/upgrade

npm i @clerk/upgrade@2.0.0-snapshot.v20251208202852 --save-exact

@clerk/vue

npm i @clerk/vue@2.0.0-snapshot.v20251208202852 --save-exact

@jacekradko
Copy link
Member

Does this support upgrading to canary or snapshot versions?

@brkalow
Copy link
Member Author

brkalow commented Dec 8, 2025

@jacekradko not currently, open to suggestions on how to accomplish that! Maybe a --tag flag?

@jacekradko
Copy link
Member

@brkalow --tag sounds good to me

@jacekradko
Copy link
Member

Another DX improvement, when we fail to upgrade for whatever reason, we should not just bail out like this, but allow the user to continue to codemods

Ready to upgrade? (y/n): y

✗ Failed to upgrade @clerk/nextjs
⛔ Command failed with code 1: Progress: resolved 0, reused 1, downloaded 0, added 0
 ERR_PNPM_NO_MATCHING_VERSION  No matching version found for @clerk/nextjs@7 while fetching it from https://registry.npmjs.org/

This error happened while installing a direct dependency of /Users/jacekradko/Development/my-fancy-app

The latest release of @clerk/nextjs is "6.36.1".

Other releases are:
  * staging: 4.27.0-staging.v4f9214a
  * alpha-v5: 5.0.0-alpha-v5.19
  * beta-v5: 5.0.0-beta-v5.21
  * beta: 5.0.0-beta.46
  * billing: 5.1.0-snapshot.vb5b714e
  * keyless: 6.10.0-snapshot.v20250115175323
  * latest-v4: 4.31.8
  * snapshot: 7.0.0-snapshot.v20251208202852
  * canary: 6.36.1-canary.v20251208170916
  * canary-core3: 7.0.0-canary-core3.v20251208193449

If you need the full list of all 4728 published versions run "$ pnpm view @clerk/nextjs versions".

Copy link
Member

@jacekradko jacekradko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it will be good for us to merge this and then iterate. I have some outstanding codemod/upgrade work that is kind of blocked by this refactor

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (22)
packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx (1)

1-19: Fixture implementation looks correct and aligned with other examples

The ClerkProvider + useUser usage and conditional rendering are straightforward and appropriate for a fixture. No functional issues spotted. If these fixtures are type-checked with the same strict rules as source, you could optionally add explicit return types to App and UserInfo, but that’s not critical here.

packages/upgrade/src/codemods/__tests__/transform-themes-to-ui-themes.test.js (1)

7-13: Consider adding explicit test cases for no-change scenarios.

The test suite currently covers positive transformations well, but would benefit from explicit negative test cases to ensure the codemod doesn't incorrectly transform unrelated code. For example:

  • Imports from other packages (e.g., import x from '@other/themes')
  • String literals that contain the package name but aren't imports
  • Comments or documentation mentioning the old package name

This would improve test coverage and catch false-positive transformations.

You can add these cases to the fixtures array:

{
  name: 'Does not transform unrelated imports',
  source: `import theme from '@other/themes';`,
  output: undefined, // or the same as source to indicate no change
},
{
  name: 'Does not transform string literals',
  source: `const pkg = '@clerk/themes';`,
  output: undefined,
}
packages/upgrade/src/codemods/__tests__/__fixtures__/transform-themes-to-ui-themes.fixtures.js (2)

1-47: Consider normalizing whitespace in fixtures for consistency.

The source fields have inconsistent leading/trailing whitespace across fixtures, while the test relies on output.trim() to match. This works but could be clearer if both source and output followed consistent whitespace patterns.

For maintainability, consider either:

  • Trimming both source and output in the fixtures themselves
  • Removing the .trim() call in the test and ensuring exact whitespace matches

Example normalized fixture:

{
  name: 'Renames root import',
  source: `import { dark, light } from '@clerk/themes';`,
  output: `import { dark, light } from "@clerk/ui/themes";`,
},

1-47: Add test case for named export with source.

The codemod implementation handles ExportNamedDeclaration with a source (lines 33-37 in transform-themes-to-ui-themes.cjs), but there's no corresponding test fixture for this case.

Add a fixture for named exports:

{
  name: 'Renames named export source',
  source: `export { dark, light } from '@clerk/themes';`,
  output: `export { dark, light } from "@clerk/ui/themes";`,
},
packages/upgrade/src/codemods/transform-themes-to-ui-themes.cjs (1)

14-14: Consider adding JSDoc documentation.

Per coding guidelines, public APIs should have JSDoc comments. Adding documentation would help other developers understand the codemod's purpose and usage.

Example JSDoc:

/**
 * Transforms imports from the legacy @clerk/themes package to @clerk/ui/themes.
 * Handles various import forms including ES modules, CommonJS, and dynamic imports.
 * 
 * @param {Object} file - The file object containing source code
 * @param {string} file.source - The source code to transform
 * @param {Object} api - The jscodeshift API object
 * @param {Function} api.jscodeshift - The jscodeshift function (j)
 * @returns {string|undefined} The transformed source code, or undefined if no changes
 */
module.exports = function transformThemesToUiThemes({ source }, { jscodeshift: j }) {
packages/upgrade/src/codemods/transform-align-experimental-unstable-prefixes.cjs (1)

105-120: Consider simplifying the key generation logic.

The key generation on line 108 handles multiple cases but is complex. For ImportSpecifier nodes, spec.imported should always exist and be an Identifier, so the additional checks for ?.value and the empty string fallback add complexity without clear benefit.

Consider this simpler approach:

 const mergeImportSpecifiers = (targetImport, specifiers) => {
   const existingKeys = new Set(
     (targetImport.node.specifiers || []).map(
-      spec => `${spec.local ? spec.local.name : (spec.imported?.name ?? spec.imported?.value ?? '')}`,
+      spec => spec.local?.name ?? spec.imported?.name ?? '',
     ),
   );
   specifiers.forEach(spec => {
-    const key = spec.local ? spec.local.name : spec.imported?.name;
+    const key = spec.local?.name ?? spec.imported?.name;
     if (!existingKeys.has(key)) {
packages/upgrade/src/codemods/__tests__/__fixtures__/transform-align-experimental-unstable-prefixes.fixtures.js (1)

1-74: Consider adding test cases for additional edge cases.

The current fixtures provide good coverage of the main scenarios, but consider adding test cases for:

  1. Removed props in object destructuring patterns (relates to the ObjectPattern handling issue):
const { __unstable_manageBillingUrl, validProp } = props;
  1. Aliased imports that need to be moved:
import { __experimental_createTheme as myTheme } from '@clerk/ui';
  1. Object expressions with removed props (non-JSX):
const config = { __unstable_manageBillingUrl: 'url', other: true };
  1. Merging imports when target already exists:
import { Button } from '@clerk/ui/themes/experimental';
import { __experimental_createTheme } from '@clerk/ui';

These would help catch edge cases and ensure consistent behavior across all AST node types.

packages/upgrade/src/codemods/transform-remove-deprecated-appearance-props.cjs (1)

1-116: Codemod logic is solid; identifier resolution limitations are acceptable but worth noting

The transform correctly:

  • Targets only appearance JSX attributes.
  • Handles both inline object literals and identifiers bound to object literals.
  • Safely renames baseThemetheme and the listed variables keys, including string-literal keys and non-computed props.
  • Avoids touching spread elements and non-object appearance values.

Two minor, behavior-defining limitations to be aware of:

  • findObjectForIdentifier only follows identifiers that are directly initialized with an object literal in a VariableDeclarator, so imported configs or indirection like const a = appearance; <X appearance={a} /> won’t be transformed.
  • If the same identifier name is declared multiple times in the file, the first object-literal declarator wins, which could be surprising in unusual code.

If that scope is intentional for core‑3 migrations, this is good to ship as-is; otherwise, a follow‑up could tighten identifier resolution (e.g., by preferring nearest scope/const declarations around the JSX site).

packages/upgrade/src/codemods/__tests__/transform-remove-deprecated-appearance-props.test.js (1)

7-12: Make tests resilient to no-op transforms and formatting differences

Since the transformer returns undefined when it makes no changes, this test will fail if you add a fixture where no migration is expected. Also, strict equality against output.trim() can be fragile if the printer adds a trailing newline or minor whitespace.

You can harden the test like this:

-  it.each(fixtures)('$name', ({ source, output }) => {
-    const result = applyTransform(transformer, {}, { source });
-
-    expect(result).toEqual(output.trim());
-  });
+  it.each(fixtures)('$name', ({ source, output }) => {
+    const result = applyTransform(transformer, {}, { source }) ?? source;
+
+    expect(result.trim()).toEqual(output.trim());
+  });
packages/upgrade/src/codemods/__tests__/__fixtures__/transform-remove-deprecated-appearance-props.fixtures.js (1)

1-67: Good fixture coverage; consider adding a no-op case

Fixtures nicely cover:

  • Inline JSX appearance={{ baseTheme: ... }}.
  • Referenced appearance object with nested variables.
  • String-literal keys.

For extra confidence, you might add a fixture where appearance contains no deprecated keys, to lock in the codemod’s no-op behavior and formatting stability.

packages/upgrade/src/codemods/transform-appearance-layout-to-options.cjs (1)

1-67: Codemod logic for appearanceoptions looks solid; literal-only scope is acceptable

The transform correctly and safely renames layout to options for object-literal appearance props, handling identifiers, string literals, and computed string-literal keys while safely ignoring other property shapes. For now, restricting to inline object literals (and not chasing variables or nested structures) is a reasonable trade-off between safety and coverage.

If you later want broader coverage, you could extend this to handle identifiers pointing at object literals or nested layout keys, but that’d be an incremental enhancement, not a blocker.

packages/upgrade/src/util/detect-sdk.js (1)

9-124: SDK detection and version helpers are cohesive and resilient

The detection helpers handle both new and legacy package names, gracefully deal with missing or non‑semver versions, and centralize normalization (normalizeSdkName and getOldPackageName) in a way that matches how the CLI uses them. Returning null/{} on unreadable package.jsons is a sensible fallback for a CLI utility.

If you ever need to support setups that only use peerDependencies or optionalDependencies for Clerk SDKs, you could extend detectSdk/getInstalledClerkPackages to scan those sections as well.

packages/upgrade/src/config.js (1)

10-93: Version selection and package name helpers are straightforward and match the new upgrade model

loadConfig’s search strategy (explicit release first, otherwise first matching needs-upgrade then already-upgraded) is reasonable for the current single core-3 release and keeps the data-driven sdkVersions logic central. The getTargetPackageName/getOldPackageName helpers align with the SDK normalization logic in detect-sdk.js, which should keep package resolution and docs change entries in sync.

If you later add multiple releases, you may want to sort versionDirs (e.g. semver-aware) to make the upgrade path deterministic across filesystems.

Also applies to: 121-139

packages/upgrade/src/render.js (1)

11-99: Rendering and prompt utilities are solid; a couple of small UX nits

The rendering layer looks cohesive and appropriate for the new imperative CLI—headers, config summary, prompts, spinner, codemod/scan results, and completion messaging all fit together well.

Two minor polish ideas:

  • In promptConfirm/promptSelect/promptText, consider trimming input (answer.trim().toLowerCase()) so trailing spaces don’t cause “no” on y and similar.
  • In renderCodemodResults, rendering 0 errors in red is slightly misleading; you could color only when result.error > 0 and leave the zero case uncolored or green.

These are minor DX tweaks; the current implementation is otherwise good to ship.

Also applies to: 101-143, 145-182

packages/upgrade/src/codemods/__tests__/transform-appearance-layout-to-options.test.js (1)

1-13: Codemod test wiring is correct and follows existing patterns

The test correctly wires applyTransform to the CJS transformer, iterates over fixtures with it.each, and asserts the transformed source matches the expected output. This provides good coverage for the primary behavior of the codemod.

You could add a no-op fixture (where appearance lacks a layout key) to assert that unchanged inputs are passed through untouched, but that’s an optional extra guard.

packages/upgrade/src/codemods/__tests__/__fixtures__/transform-appearance-layout-to-options.fixtures.js (1)

1-11: Consider adding edge case fixtures for more robust codemod testing.

The current fixture covers the basic JSX transformation. Consider adding additional test cases such as:

  • Multiple components with appearance props in the same file
  • Nested layout objects with multiple properties
  • Components where layout should not be renamed (non-Clerk components)
  • Mixed layout and other appearance properties
packages/upgrade/src/__tests__/integration/detect-sdk.test.js (1)

45-48: Test name may be misleading - fixture name vs. actual version.

The test name says "clerk-react fixture" but the fixture is named react-v6 while the expected version is 5. Consider clarifying whether react-v6 refers to the target upgrade version or the fixture's current Clerk version.

-  it('returns major version 5 for clerk-react fixture', () => {
+  it('returns major version 5 for react-v6 fixture with @clerk/clerk-react ^5.0.0', () => {
     const version = getSdkVersion('clerk-react', getFixturePath('react-v6'));
     expect(version).toBe(5);
   });
packages/upgrade/src/cli.js (2)

205-212: Consider allowing codemods to run even after upgrade failure.

Per PR discussion, when the package upgrade fails (e.g., version not found), the CLI currently exits immediately. Users might still benefit from running codemods on their existing code. Consider prompting to continue with codemods despite the installation failure.

   try {
     await upgradePackage(packageManager, targetPackage, targetVersion, options.dir);
     spinner.success(`Upgraded ${targetPackage} to version ${targetVersion}`);
   } catch (error) {
     spinner.error(`Failed to upgrade ${targetPackage}`);
     renderError(error.message);
-    process.exit(1);
+    if (isInteractive) {
+      const continueAnyway = await promptConfirm('Would you like to continue with codemods anyway?');
+      if (!continueAnyway) {
+        process.exit(1);
+      }
+    } else {
+      process.exit(1);
+    }
   }

81-84: Minor: Extra leading space in warning message.

   if (options.dryRun) {
-    renderWarning(' Upgrade running in dry run mode - no changes will be made');
+    renderWarning('Upgrade running in dry run mode - no changes will be made');
     renderNewline();
   }
packages/upgrade/src/__tests__/integration/cli.test.js (2)

15-61: Improve runCli portability and env flexibility

Two small tweaks would make this helper more robust:

  • Use process.execPath instead of hardcoded 'node' so tests work in environments where node isn’t on PATH or has a different binary name.
  • Merge an optional options.env into the child env (on top of the color flags) so tests can explicitly control things like CI, feature flags, etc.

For example:

-  return new Promise((resolve, reject) => {
-    const child = spawn('node', [CLI_PATH, ...args], {
-      cwd: options.cwd || process.cwd(),
-      env: { ...process.env, FORCE_COLOR: '0', NO_COLOR: '1' },
+  return new Promise((resolve, reject) => {
+    const child = spawn(process.execPath, [CLI_PATH, ...args], {
+      cwd: options.cwd || process.cwd(),
+      env: {
+        ...process.env,
+        FORCE_COLOR: '0',
+        NO_COLOR: '1',
+        ...(options.env || {}),
+      },
       stdio: ['pipe', 'pipe', 'pipe'],
     });

223-239: Align codemods dry‑run test with its intent

This test is named/described as listing codemods that would run in dry‑run mode, but it also passes --skip-codemods. That can be a bit confusing when reading the spec.

Consider either:

  • Dropping --skip-codemods here so the test truly reflects “dry‑run with codemods”, or
  • Updating the description to clarify that codemods are skipped but still listed.

Functionally it’s fine either way; this is mostly a readability/DX tweak for future maintainers.

packages/upgrade/src/util/package-manager.js (1)

52-81: Include the invoked command in error messages from package manager runs

runPackageManagerCommand already aggregates stdout/stderr and rejects on non‑zero exit, which is good. For debugging failed upgrades, it would help to surface the exact command that was run:

-    child.on('close', code => {
-      if (code === 0) {
-        resolve({ stdout, stderr });
-      } else {
-        reject(new Error(`Command failed with code ${code}: ${stderr || stdout}`));
-      }
-    });
+    child.on('close', code => {
+      if (code === 0) {
+        resolve({ stdout, stderr });
+      } else {
+        const cmdLine = [command, ...args].join(' ');
+        reject(
+          new Error(
+            `Command "${cmdLine}" failed with code ${code}: ${stderr || stdout}`,
+          ),
+        );
+      }
+    });

This makes it much easier to reproduce and diagnose issues when the underlying package manager rejects.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2b82a6e and 202e28c.

⛔ Files ignored due to path filters (5)
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/package-lock.json is excluded by !**/package-lock.json
  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • packages/upgrade/src/__tests__/fixtures/react-v6/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (49)
  • .changeset/busy-tires-admire.md (1 hunks)
  • eslint.config.mjs (2 hunks)
  • packages/upgrade/package.json (1 hunks)
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/package.json (1 hunks)
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/src/App.tsx (1 hunks)
  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/package.json (1 hunks)
  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx (1 hunks)
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/package.json (1 hunks)
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/src/app.tsx (1 hunks)
  • packages/upgrade/src/__tests__/fixtures/no-clerk/package.json (1 hunks)
  • packages/upgrade/src/__tests__/fixtures/react-v6/package.json (1 hunks)
  • packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx (1 hunks)
  • packages/upgrade/src/__tests__/helpers/create-fixture.js (1 hunks)
  • packages/upgrade/src/__tests__/integration/cli.test.js (1 hunks)
  • packages/upgrade/src/__tests__/integration/config.test.js (1 hunks)
  • packages/upgrade/src/__tests__/integration/detect-sdk.test.js (1 hunks)
  • packages/upgrade/src/__tests__/integration/runner.test.js (1 hunks)
  • packages/upgrade/src/app.js (0 hunks)
  • packages/upgrade/src/cli.js (1 hunks)
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-align-experimental-unstable-prefixes.fixtures.js (1 hunks)
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-appearance-layout-to-options.fixtures.js (1 hunks)
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-remove-deprecated-appearance-props.fixtures.js (1 hunks)
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-themes-to-ui-themes.fixtures.js (1 hunks)
  • packages/upgrade/src/codemods/__tests__/transform-align-experimental-unstable-prefixes.test.js (1 hunks)
  • packages/upgrade/src/codemods/__tests__/transform-appearance-layout-to-options.test.js (1 hunks)
  • packages/upgrade/src/codemods/__tests__/transform-remove-deprecated-appearance-props.test.js (1 hunks)
  • packages/upgrade/src/codemods/__tests__/transform-themes-to-ui-themes.test.js (1 hunks)
  • packages/upgrade/src/codemods/index.js (2 hunks)
  • packages/upgrade/src/codemods/transform-align-experimental-unstable-prefixes.cjs (1 hunks)
  • packages/upgrade/src/codemods/transform-appearance-layout-to-options.cjs (1 hunks)
  • packages/upgrade/src/codemods/transform-remove-deprecated-appearance-props.cjs (1 hunks)
  • packages/upgrade/src/codemods/transform-themes-to-ui-themes.cjs (1 hunks)
  • packages/upgrade/src/components/Codemod.js (0 hunks)
  • packages/upgrade/src/components/Command.js (0 hunks)
  • packages/upgrade/src/components/Header.js (0 hunks)
  • packages/upgrade/src/components/SDKWorkflow.js (0 hunks)
  • packages/upgrade/src/components/Scan.js (0 hunks)
  • packages/upgrade/src/components/UpgradeSDK.js (0 hunks)
  • packages/upgrade/src/config.js (1 hunks)
  • packages/upgrade/src/render.js (1 hunks)
  • packages/upgrade/src/runner.js (1 hunks)
  • packages/upgrade/src/util/detect-sdk.js (1 hunks)
  • packages/upgrade/src/util/expandable-list.js (0 hunks)
  • packages/upgrade/src/util/get-clerk-version.js (0 hunks)
  • packages/upgrade/src/util/guess-framework.js (0 hunks)
  • packages/upgrade/src/util/package-manager.js (1 hunks)
  • packages/upgrade/src/versions/core-3/changes/clerk-expo-package-rename.md (1 hunks)
  • packages/upgrade/src/versions/core-3/changes/clerk-react-package-rename.md (1 hunks)
  • packages/upgrade/src/versions/core-3/index.js (1 hunks)
💤 Files with no reviewable changes (10)
  • packages/upgrade/src/util/get-clerk-version.js
  • packages/upgrade/src/components/Codemod.js
  • packages/upgrade/src/components/UpgradeSDK.js
  • packages/upgrade/src/util/guess-framework.js
  • packages/upgrade/src/components/Scan.js
  • packages/upgrade/src/app.js
  • packages/upgrade/src/components/Header.js
  • packages/upgrade/src/components/SDKWorkflow.js
  • packages/upgrade/src/components/Command.js
  • packages/upgrade/src/util/expandable-list.js
🧰 Additional context used
📓 Path-based instructions (16)
**/*.{js,jsx,ts,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/package.json
  • packages/upgrade/src/__tests__/fixtures/react-v6/package.json
  • packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx
  • packages/upgrade/src/versions/core-3/changes/clerk-expo-package-rename.md
  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx
  • packages/upgrade/src/__tests__/fixtures/no-clerk/package.json
  • packages/upgrade/src/__tests__/integration/cli.test.js
  • packages/upgrade/src/codemods/__tests__/transform-appearance-layout-to-options.test.js
  • packages/upgrade/src/versions/core-3/index.js
  • packages/upgrade/src/__tests__/integration/runner.test.js
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/src/App.tsx
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/package.json
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-themes-to-ui-themes.fixtures.js
  • packages/upgrade/src/__tests__/integration/config.test.js
  • packages/upgrade/src/runner.js
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-align-experimental-unstable-prefixes.fixtures.js
  • packages/upgrade/src/config.js
  • packages/upgrade/src/util/package-manager.js
  • packages/upgrade/src/__tests__/integration/detect-sdk.test.js
  • packages/upgrade/src/__tests__/helpers/create-fixture.js
  • packages/upgrade/src/versions/core-3/changes/clerk-react-package-rename.md
  • packages/upgrade/package.json
  • packages/upgrade/src/codemods/__tests__/transform-remove-deprecated-appearance-props.test.js
  • packages/upgrade/src/codemods/__tests__/transform-themes-to-ui-themes.test.js
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-remove-deprecated-appearance-props.fixtures.js
  • packages/upgrade/src/cli.js
  • packages/upgrade/src/codemods/__tests__/transform-align-experimental-unstable-prefixes.test.js
  • packages/upgrade/src/util/detect-sdk.js
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/package.json
  • packages/upgrade/src/render.js
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/src/app.tsx
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-appearance-layout-to-options.fixtures.js
  • packages/upgrade/src/codemods/index.js
**/package.json

📄 CodeRabbit inference engine (.cursor/rules/global.mdc)

Use pnpm as the package manager for this monorepo

Files:

  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/package.json
  • packages/upgrade/src/__tests__/fixtures/react-v6/package.json
  • packages/upgrade/src/__tests__/fixtures/no-clerk/package.json
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/package.json
  • packages/upgrade/package.json
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/package.json
**/*.{js,ts,jsx,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Use Prettier for code formatting across all packages

Files:

  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/package.json
  • packages/upgrade/src/__tests__/fixtures/react-v6/package.json
  • packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx
  • packages/upgrade/src/versions/core-3/changes/clerk-expo-package-rename.md
  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx
  • packages/upgrade/src/__tests__/fixtures/no-clerk/package.json
  • packages/upgrade/src/__tests__/integration/cli.test.js
  • packages/upgrade/src/codemods/__tests__/transform-appearance-layout-to-options.test.js
  • packages/upgrade/src/versions/core-3/index.js
  • packages/upgrade/src/__tests__/integration/runner.test.js
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/src/App.tsx
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/package.json
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-themes-to-ui-themes.fixtures.js
  • packages/upgrade/src/__tests__/integration/config.test.js
  • packages/upgrade/src/runner.js
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-align-experimental-unstable-prefixes.fixtures.js
  • packages/upgrade/src/config.js
  • packages/upgrade/src/util/package-manager.js
  • packages/upgrade/src/__tests__/integration/detect-sdk.test.js
  • packages/upgrade/src/__tests__/helpers/create-fixture.js
  • packages/upgrade/src/versions/core-3/changes/clerk-react-package-rename.md
  • packages/upgrade/package.json
  • packages/upgrade/src/codemods/__tests__/transform-remove-deprecated-appearance-props.test.js
  • packages/upgrade/src/codemods/__tests__/transform-themes-to-ui-themes.test.js
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-remove-deprecated-appearance-props.fixtures.js
  • packages/upgrade/src/cli.js
  • packages/upgrade/src/codemods/__tests__/transform-align-experimental-unstable-prefixes.test.js
  • packages/upgrade/src/util/detect-sdk.js
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/package.json
  • packages/upgrade/src/render.js
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/src/app.tsx
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-appearance-layout-to-options.fixtures.js
  • packages/upgrade/src/codemods/index.js
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

All code must pass ESLint checks with the project's configuration

Files:

  • packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx
  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx
  • packages/upgrade/src/__tests__/integration/cli.test.js
  • packages/upgrade/src/codemods/__tests__/transform-appearance-layout-to-options.test.js
  • packages/upgrade/src/versions/core-3/index.js
  • packages/upgrade/src/__tests__/integration/runner.test.js
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/src/App.tsx
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-themes-to-ui-themes.fixtures.js
  • packages/upgrade/src/__tests__/integration/config.test.js
  • packages/upgrade/src/runner.js
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-align-experimental-unstable-prefixes.fixtures.js
  • packages/upgrade/src/config.js
  • packages/upgrade/src/util/package-manager.js
  • packages/upgrade/src/__tests__/integration/detect-sdk.test.js
  • packages/upgrade/src/__tests__/helpers/create-fixture.js
  • packages/upgrade/src/codemods/__tests__/transform-remove-deprecated-appearance-props.test.js
  • packages/upgrade/src/codemods/__tests__/transform-themes-to-ui-themes.test.js
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-remove-deprecated-appearance-props.fixtures.js
  • packages/upgrade/src/cli.js
  • packages/upgrade/src/codemods/__tests__/transform-align-experimental-unstable-prefixes.test.js
  • packages/upgrade/src/util/detect-sdk.js
  • packages/upgrade/src/render.js
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/src/app.tsx
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-appearance-layout-to-options.fixtures.js
  • packages/upgrade/src/codemods/index.js
packages/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx
  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/src/App.tsx
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/src/app.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Follow established naming conventions (PascalCase for components, camelCase for variables)

Files:

  • packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx
  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx
  • packages/upgrade/src/__tests__/integration/cli.test.js
  • packages/upgrade/src/codemods/__tests__/transform-appearance-layout-to-options.test.js
  • packages/upgrade/src/versions/core-3/index.js
  • packages/upgrade/src/__tests__/integration/runner.test.js
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/src/App.tsx
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-themes-to-ui-themes.fixtures.js
  • packages/upgrade/src/__tests__/integration/config.test.js
  • packages/upgrade/src/runner.js
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-align-experimental-unstable-prefixes.fixtures.js
  • packages/upgrade/src/config.js
  • packages/upgrade/src/util/package-manager.js
  • packages/upgrade/src/__tests__/integration/detect-sdk.test.js
  • packages/upgrade/src/__tests__/helpers/create-fixture.js
  • packages/upgrade/src/codemods/__tests__/transform-remove-deprecated-appearance-props.test.js
  • packages/upgrade/src/codemods/__tests__/transform-themes-to-ui-themes.test.js
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-remove-deprecated-appearance-props.fixtures.js
  • packages/upgrade/src/cli.js
  • packages/upgrade/src/codemods/__tests__/transform-align-experimental-unstable-prefixes.test.js
  • packages/upgrade/src/util/detect-sdk.js
  • packages/upgrade/src/render.js
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/src/app.tsx
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-appearance-layout-to-options.fixtures.js
  • packages/upgrade/src/codemods/index.js
packages/**/src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

packages/**/src/**/*.{ts,tsx,js,jsx}: Maintain comprehensive JSDoc comments for public APIs
Use tree-shaking friendly exports
Validate all inputs and sanitize outputs
All public APIs must be documented with JSDoc
Use dynamic imports for optional features
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Implement proper logging with different levels

Files:

  • packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx
  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx
  • packages/upgrade/src/__tests__/integration/cli.test.js
  • packages/upgrade/src/codemods/__tests__/transform-appearance-layout-to-options.test.js
  • packages/upgrade/src/versions/core-3/index.js
  • packages/upgrade/src/__tests__/integration/runner.test.js
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/src/App.tsx
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-themes-to-ui-themes.fixtures.js
  • packages/upgrade/src/__tests__/integration/config.test.js
  • packages/upgrade/src/runner.js
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-align-experimental-unstable-prefixes.fixtures.js
  • packages/upgrade/src/config.js
  • packages/upgrade/src/util/package-manager.js
  • packages/upgrade/src/__tests__/integration/detect-sdk.test.js
  • packages/upgrade/src/__tests__/helpers/create-fixture.js
  • packages/upgrade/src/codemods/__tests__/transform-remove-deprecated-appearance-props.test.js
  • packages/upgrade/src/codemods/__tests__/transform-themes-to-ui-themes.test.js
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-remove-deprecated-appearance-props.fixtures.js
  • packages/upgrade/src/cli.js
  • packages/upgrade/src/codemods/__tests__/transform-align-experimental-unstable-prefixes.test.js
  • packages/upgrade/src/util/detect-sdk.js
  • packages/upgrade/src/render.js
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/src/app.tsx
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-appearance-layout-to-options.fixtures.js
  • packages/upgrade/src/codemods/index.js
**/*.ts?(x)

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

Files:

  • packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx
  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/src/App.tsx
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/src/app.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.tsx: Use error boundaries in React components
Minimize re-renders in React components

**/*.tsx: Use proper type definitions for props and state in React components
Leverage TypeScript's type inference where possible in React components
Use proper event types for handlers in React components
Implement proper generic types for reusable React components
Use proper type guards for conditional rendering in React components

Files:

  • packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx
  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/src/App.tsx
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/src/app.tsx
**/*.{md,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Update documentation for API changes

Files:

  • packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx
  • packages/upgrade/src/versions/core-3/changes/clerk-expo-package-rename.md
  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/src/App.tsx
  • packages/upgrade/src/versions/core-3/changes/clerk-react-package-rename.md
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/src/app.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/react.mdc)

**/*.{jsx,tsx}: Always use functional components with hooks instead of class components
Follow PascalCase naming for components (e.g., UserProfile, NavigationMenu)
Keep components focused on a single responsibility - split large components
Limit component size to 150-200 lines; extract logic into custom hooks
Use composition over inheritance - prefer smaller, composable components
Export components as named exports for better tree-shaking
One component per file with matching filename and component name
Separate UI components from business logic components
Use useState for simple state management in React components
Use useReducer for complex state logic in React components
Implement proper state initialization in React components
Use proper state updates with callbacks in React components
Implement proper state cleanup in React components
Use Context API for theme/authentication state management
Implement proper state persistence in React applications
Use React.memo for expensive components
Implement proper useCallback for handlers in React components
Use proper useMemo for expensive computations in React components
Implement proper virtualization for lists in React components
Use proper code splitting with React.lazy in React applications
Implement proper cleanup in useEffect hooks
Use proper refs for DOM access in React components
Implement proper event listener cleanup in React components
Use proper abort controllers for fetch in React components
Implement proper subscription cleanup in React components
Use proper HTML elements for semantic HTML in React components
Implement proper ARIA attributes for accessibility in React components
Use proper heading hierarchy in React components
Implement proper form labels in React components
Use proper button types in React components
Implement proper focus management for keyboard navigation in React components
Use proper keyboard shortcuts in React components
Implement proper tab order in React components
Use proper ...

Files:

  • packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx
  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/src/App.tsx
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/src/app.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Implement type guards for unknown types using the pattern function isType(value: unknown): value is Type
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details in classes
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Use mixins for shared behavior across unrelated classes in TypeScript
Use generic constraints with bounded type parameters like <T extends { id: string }>
Use utility types like Omit, Partial, and Pick for data transformation instead of manual type construction
Use discriminated unions instead of boolean flags for state management and API responses
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation at the type level
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Document functions with JSDoc comments including @param, @returns, @throws, and @example tags
Create custom error classes that extend Error for specific error types
Use the Result pattern for error handling instead of throwing exceptions
Use optional chaining (?.) and nullish coalescing (??) operators for safe property access
Let TypeScript infer obvious types to reduce verbosity
Use const assertions with as const for literal types
Use satisfies operator for type checking without widening types
Declare readonly arrays and objects for immutable data structures
Use spread operator and array spread for immutable updates instead of mutations
Use lazy loading for large types...

Files:

  • packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx
  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/src/App.tsx
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/src/app.tsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Use ESLint with custom configurations tailored for different package types

Files:

  • packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx
  • packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx
  • packages/upgrade/src/__tests__/integration/cli.test.js
  • packages/upgrade/src/codemods/__tests__/transform-appearance-layout-to-options.test.js
  • packages/upgrade/src/versions/core-3/index.js
  • packages/upgrade/src/__tests__/integration/runner.test.js
  • packages/upgrade/src/__tests__/fixtures/expo-old-package/src/App.tsx
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-themes-to-ui-themes.fixtures.js
  • packages/upgrade/src/__tests__/integration/config.test.js
  • packages/upgrade/src/runner.js
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-align-experimental-unstable-prefixes.fixtures.js
  • packages/upgrade/src/config.js
  • packages/upgrade/src/util/package-manager.js
  • packages/upgrade/src/__tests__/integration/detect-sdk.test.js
  • packages/upgrade/src/__tests__/helpers/create-fixture.js
  • packages/upgrade/src/codemods/__tests__/transform-remove-deprecated-appearance-props.test.js
  • packages/upgrade/src/codemods/__tests__/transform-themes-to-ui-themes.test.js
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-remove-deprecated-appearance-props.fixtures.js
  • packages/upgrade/src/cli.js
  • packages/upgrade/src/codemods/__tests__/transform-align-experimental-unstable-prefixes.test.js
  • packages/upgrade/src/util/detect-sdk.js
  • packages/upgrade/src/render.js
  • packages/upgrade/src/__tests__/fixtures/nextjs-v7/src/app.tsx
  • packages/upgrade/src/codemods/__tests__/__fixtures__/transform-appearance-layout-to-options.fixtures.js
  • packages/upgrade/src/codemods/index.js
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{test,spec}.{ts,tsx,js,jsx}: Unit tests are required for all new functionality
Verify proper error handling and edge cases
Include tests for all new features

Files:

  • packages/upgrade/src/__tests__/integration/cli.test.js
  • packages/upgrade/src/codemods/__tests__/transform-appearance-layout-to-options.test.js
  • packages/upgrade/src/__tests__/integration/runner.test.js
  • packages/upgrade/src/__tests__/integration/config.test.js
  • packages/upgrade/src/__tests__/integration/detect-sdk.test.js
  • packages/upgrade/src/codemods/__tests__/transform-remove-deprecated-appearance-props.test.js
  • packages/upgrade/src/codemods/__tests__/transform-themes-to-ui-themes.test.js
  • packages/upgrade/src/codemods/__tests__/transform-align-experimental-unstable-prefixes.test.js
**/*.{test,spec,e2e}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use real Clerk instances for integration tests

Files:

  • packages/upgrade/src/__tests__/integration/cli.test.js
  • packages/upgrade/src/codemods/__tests__/transform-appearance-layout-to-options.test.js
  • packages/upgrade/src/__tests__/integration/runner.test.js
  • packages/upgrade/src/__tests__/integration/config.test.js
  • packages/upgrade/src/__tests__/integration/detect-sdk.test.js
  • packages/upgrade/src/codemods/__tests__/transform-remove-deprecated-appearance-props.test.js
  • packages/upgrade/src/codemods/__tests__/transform-themes-to-ui-themes.test.js
  • packages/upgrade/src/codemods/__tests__/transform-align-experimental-unstable-prefixes.test.js
packages/*/package.json

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

packages/*/package.json: Packages should export TypeScript types alongside runtime code
Follow semantic versioning for all packages

All packages must be published under @clerk namespace

packages/*/package.json: Framework packages should depend on @clerk/clerk-js for core functionality
@clerk/shared should be a common dependency for most packages in the monorepo

Files:

  • packages/upgrade/package.json
🧬 Code graph analysis (16)
packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx (3)
packages/upgrade/src/__tests__/fixtures/expo-old-package/src/App.tsx (1)
  • App (3-9)
packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx (1)
  • App (4-6)
packages/upgrade/src/__tests__/fixtures/nextjs-v7/src/app.tsx (1)
  • App (3-5)
packages/upgrade/src/__tests__/integration/cli.test.js (3)
packages/upgrade/src/__tests__/helpers/create-fixture.js (2)
  • getFixturePath (9-11)
  • createTempFixture (13-25)
packages/upgrade/src/cli.js (1)
  • options (71-79)
packages/upgrade/src/__tests__/integration/runner.test.js (2)
  • fixture (21-21)
  • fixture (71-71)
packages/upgrade/src/codemods/__tests__/transform-appearance-layout-to-options.test.js (1)
packages/upgrade/src/codemods/__tests__/__fixtures__/transform-appearance-layout-to-options.fixtures.js (2)
  • fixtures (1-11)
  • fixtures (1-11)
packages/upgrade/src/__tests__/fixtures/expo-old-package/src/App.tsx (3)
packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx (1)
  • App (4-6)
packages/upgrade/src/__tests__/fixtures/nextjs-v7/src/app.tsx (1)
  • App (3-5)
packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx (1)
  • App (3-9)
packages/upgrade/src/codemods/transform-themes-to-ui-themes.cjs (1)
packages/upgrade/src/codemods/transform-align-experimental-unstable-prefixes.cjs (1)
  • source (238-238)
packages/upgrade/src/runner.js (2)
packages/upgrade/src/codemods/index.js (4)
  • GLOBBY_IGNORE (16-34)
  • result (61-61)
  • runCodemod (36-80)
  • getCodemodConfig (82-84)
packages/upgrade/src/render.js (2)
  • createSpinner (103-143)
  • renderCodemodResults (145-148)
packages/upgrade/src/config.js (3)
packages/upgrade/src/__tests__/integration/cli.test.js (1)
  • __dirname (12-12)
packages/upgrade/src/__tests__/helpers/create-fixture.js (1)
  • __dirname (6-6)
packages/upgrade/src/cli.js (2)
  • sdk (87-87)
  • currentVersion (119-119)
packages/upgrade/src/util/package-manager.js (1)
packages/upgrade/src/cli.js (1)
  • packageManager (120-120)
packages/upgrade/src/__tests__/integration/detect-sdk.test.js (4)
packages/upgrade/src/cli.js (1)
  • sdk (87-87)
packages/upgrade/src/util/detect-sdk.js (5)
  • detectSdk (30-50)
  • version (63-67)
  • getSdkVersion (52-74)
  • getMajorVersion (76-86)
  • normalizeSdkName (107-124)
packages/upgrade/src/__tests__/helpers/create-fixture.js (1)
  • getFixturePath (9-11)
packages/upgrade/src/util/package-manager.js (1)
  • detectPackageManager (5-20)
packages/upgrade/src/__tests__/helpers/create-fixture.js (3)
packages/upgrade/src/__tests__/integration/cli.test.js (1)
  • __dirname (12-12)
packages/upgrade/src/config.js (3)
  • __dirname (7-7)
  • filePath (152-152)
  • content (153-153)
packages/upgrade/src/runner.js (1)
  • content (82-82)
packages/upgrade/src/codemods/__tests__/transform-remove-deprecated-appearance-props.test.js (1)
packages/upgrade/src/codemods/__tests__/__fixtures__/transform-remove-deprecated-appearance-props.fixtures.js (2)
  • fixtures (1-67)
  • fixtures (1-67)
packages/upgrade/src/codemods/__tests__/transform-themes-to-ui-themes.test.js (1)
packages/upgrade/src/codemods/__tests__/__fixtures__/transform-themes-to-ui-themes.fixtures.js (2)
  • fixtures (1-47)
  • fixtures (1-47)
packages/upgrade/src/cli.js (5)
packages/upgrade/src/render.js (12)
  • renderHeader (5-9)
  • renderWarning (24-26)
  • renderNewline (28-30)
  • renderError (20-22)
  • renderText (11-14)
  • promptSelect (61-83)
  • renderConfig (32-45)
  • promptConfirm (47-59)
  • renderSuccess (16-18)
  • renderScanResults (150-175)
  • renderComplete (177-182)
  • createSpinner (103-143)
packages/upgrade/src/util/detect-sdk.js (3)
  • normalizeSdkName (107-124)
  • detectSdk (30-50)
  • getSupportedSdks (26-28)
packages/upgrade/src/util/package-manager.js (4)
  • detectPackageManager (5-20)
  • getPackageManagerDisplayName (93-105)
  • removePackage (88-91)
  • upgradePackage (83-86)
packages/upgrade/src/config.js (5)
  • config (29-29)
  • config (53-53)
  • loadConfig (10-93)
  • getTargetPackageName (121-129)
  • getOldPackageName (131-139)
packages/upgrade/src/runner.js (5)
  • runCodemods (33-59)
  • results (76-76)
  • runScans (61-120)
  • spinner (43-43)
  • spinner (68-68)
packages/upgrade/src/util/detect-sdk.js (3)
packages/upgrade/src/util/package-manager.js (1)
  • pkg (23-23)
packages/upgrade/src/cli.js (1)
  • sdk (87-87)
packages/upgrade/src/config.js (1)
  • getOldPackageName (131-139)
packages/upgrade/src/__tests__/fixtures/nextjs-v7/src/app.tsx (3)
packages/upgrade/src/__tests__/fixtures/expo-old-package/src/App.tsx (1)
  • App (3-9)
packages/upgrade/src/__tests__/fixtures/nextjs-v6/src/app.tsx (2)
  • App (4-6)
  • UserProfile (8-17)
packages/upgrade/src/__tests__/fixtures/react-v6/src/App.tsx (1)
  • App (3-9)
packages/upgrade/src/codemods/index.js (4)
packages/upgrade/src/__tests__/integration/cli.test.js (1)
  • __dirname (12-12)
packages/upgrade/src/cli.js (1)
  • options (71-79)
packages/upgrade/src/runner.js (1)
  • result (46-46)
packages/upgrade/src/codemods/transform-clerk-react-v6.cjs (1)
  • result (148-148)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (28)
  • GitHub Check: Integration Tests (nextjs, chrome, 16, RQ)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (quickstart, chrome, 16)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (machine, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome, 15)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 16)
  • GitHub Check: Integration Tests (vue, chrome)
  • GitHub Check: Integration Tests (billing, chrome, RQ)
  • GitHub Check: Integration Tests (machine, chrome, RQ)
  • GitHub Check: Integration Tests (custom, chrome)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (handshake, chrome)
  • GitHub Check: Integration Tests (handshake:staging, chrome)
  • GitHub Check: Integration Tests (sessions:staging, chrome)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan

Comment on lines 57 to 67
it('respects ignore patterns', async () => {
const config = await loadConfig('nextjs', 6);
const options = {
dir: fixture.path,
ignore: ['**/src/**'],
};

const results = await runScans(config, 'nextjs', options);

expect(Array.isArray(results)).toBe(true);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Test doesn't verify that ignore patterns actually reduce results.

This test should compare results with and without ignore patterns to confirm the ignore functionality works, or at minimum verify that no results come from ignored paths.

     const results = await runScans(config, 'nextjs', options);

-    expect(Array.isArray(results)).toBe(true);
+    expect(Array.isArray(results)).toBe(true);
+    // Verify no results from ignored src directory
+    const srcResults = results.flatMap(r => r.instances).filter(i => i.file.includes('src/'));
+    expect(srcResults).toHaveLength(0);
🤖 Prompt for AI Agents
In packages/upgrade/src/__tests__/integration/runner.test.js around lines 57-67,
the test only asserts results is an array and doesn't verify that the ignore
pattern actually reduces or removes results; update the test to run runScans
twice (once without the ignore option and once with ignore: ['**/src/**']) and
assert that the ignored run returns fewer results (or at minimum that none of
the returned items originate from paths containing '/src/' or match the ignore
glob), e.g., capture both result sets and compare lengths or filter results for
entries with paths including '/src/' and assert zero for the ignored run.

Comment on lines +180 to +196
root.find(j.ObjectPattern).forEach(path => {
path.node.properties.forEach(prop => {
if (!prop) {
return;
}
const keyName = getPropertyName(prop.key);
if (keyName && REMOVED_PROPS.has(keyName) && !prop.computed) {
return;
}
if (prop.key) {
renamePropertyKey(prop.key, prop.computed);
}
if (prop.value && j.Identifier.check(prop.value)) {
renameIdentifier(prop.value);
}
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

ObjectPattern handling doesn't remove deprecated props.

Unlike JSXAttributes (lines 204-219), Properties (lines 169-172), and ObjectExpression (lines 460-473), this code doesn't filter out properties that are in REMOVED_PROPS from object destructuring patterns. The early return on line 187 only skips renaming but leaves the deprecated property in place.

This inconsistency means destructuring like const { __unstable_manageBillingUrl, other } = props; won't have the deprecated property removed, while JSX attributes and object literals will. If this is intentional (e.g., to avoid breaking function signatures), it should be documented. Otherwise, consider filtering the properties array similar to other node types.

If removal is intended, apply this diff:

 root.find(j.ObjectPattern).forEach(path => {
-  path.node.properties.forEach(prop => {
+  const filtered = [];
+  path.node.properties.forEach(prop => {
     if (!prop) {
       return;
     }
     const keyName = getPropertyName(prop.key);
     if (keyName && REMOVED_PROPS.has(keyName) && !prop.computed) {
+      dirty = true;
       return;
     }
     if (prop.key) {
       renamePropertyKey(prop.key, prop.computed);
     }
     if (prop.value && j.Identifier.check(prop.value)) {
       renameIdentifier(prop.value);
     }
+    filtered.push(prop);
   });
+  path.node.properties = filtered;
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
root.find(j.ObjectPattern).forEach(path => {
path.node.properties.forEach(prop => {
if (!prop) {
return;
}
const keyName = getPropertyName(prop.key);
if (keyName && REMOVED_PROPS.has(keyName) && !prop.computed) {
return;
}
if (prop.key) {
renamePropertyKey(prop.key, prop.computed);
}
if (prop.value && j.Identifier.check(prop.value)) {
renameIdentifier(prop.value);
}
});
});
root.find(j.ObjectPattern).forEach(path => {
const filtered = [];
path.node.properties.forEach(prop => {
if (!prop) {
return;
}
const keyName = getPropertyName(prop.key);
if (keyName && REMOVED_PROPS.has(keyName) && !prop.computed) {
dirty = true;
return;
}
if (prop.key) {
renamePropertyKey(prop.key, prop.computed);
}
if (prop.value && j.Identifier.check(prop.value)) {
renameIdentifier(prop.value);
}
filtered.push(prop);
});
path.node.properties = filtered;
});

Comment on lines +141 to +178
function loadChanges(versionDir, sdk) {
const changesDir = path.join(VERSIONS_DIR, versionDir, 'changes');

if (!fs.existsSync(changesDir)) {
return [];
}

const files = fs.readdirSync(changesDir).filter(f => f.endsWith('.md'));
const changes = [];

for (const file of files) {
const filePath = path.join(changesDir, file);
const content = fs.readFileSync(filePath, 'utf8');
const parsed = matter(content);
const fm = parsed.data;

const packages = fm.packages || ['*'];
const appliesToSdk = packages.includes('*') || packages.includes(sdk);

if (!appliesToSdk) {
continue;
}

const matcher = fm.matcher
? Array.isArray(fm.matcher)
? fm.matcher.map(m => new RegExp(m, `g${fm.matcherFlags || ''}`))
: new RegExp(fm.matcher, `g${fm.matcherFlags || ''}`)
: null;

changes.push({
title: fm.title,
matcher,
packages,
category: fm.category || 'breaking',
warning: fm.warning || fm.category === 'warning',
docsAnchor: fm.docsAnchor || file.replace('.md', ''),
content: parsed.content,
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Guard against invalid RegExp flags when combining matcher and matcherFlags

loadChanges always prefixes 'g' to fm.matcherFlags:

new RegExp(fm.matcher, `g${fm.matcherFlags || ''}`)

If a change file ever sets matcherFlags including 'g' (e.g. 'gi'), this becomes 'ggi' and will throw a SyntaxError at runtime, breaking the CLI when loading changes.

You can make this more robust by deduplicating flags and ensuring g is present only once, e.g.:

-    const matcher = fm.matcher
-      ? Array.isArray(fm.matcher)
-        ? fm.matcher.map(m => new RegExp(m, `g${fm.matcherFlags || ''}`))
-        : new RegExp(fm.matcher, `g${fm.matcherFlags || ''}`)
-      : null;
+    const matcher = fm.matcher
+      ? (() => {
+          const baseFlags = fm.matcherFlags || '';
+          const flags = baseFlags.includes('g') ? baseFlags : `g${baseFlags}`;
+          if (Array.isArray(fm.matcher)) {
+            return fm.matcher.map(m => new RegExp(m, flags));
+          }
+          return new RegExp(fm.matcher, flags);
+        })()
+      : null;

This keeps the “always global” behavior while avoiding brittle config expectations.

🤖 Prompt for AI Agents
In packages/upgrade/src/config.js around lines 141 to 178, the code blindly
prefixes 'g' to fm.matcherFlags which can produce invalid duplicate flags (e.g.
'ggi') and throw a SyntaxError; fix by normalizing the flags: treat
fm.matcherFlags as a string, split into individual characters, filter to the
allowed RegExp flag set (e.g. 'g', 'i', 'm', 's', 'u', 'y'), remove duplicates,
ensure 'g' is present exactly once, then rejoin the characters to build the
flags argument passed to new RegExp; apply this normalization for both array and
string matcher branches and handle empty/undefined fm.matcherFlags by falling
back to just 'g'.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…table-prefixes.cjs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/upgrade/src/codemods/transform-align-experimental-unstable-prefixes.cjs (1)

191-207: ObjectPattern doesn't remove deprecated props (inconsistent with other node types).

The early return on line 198 skips processing deprecated props but doesn't remove them from path.node.properties. This leaves deprecated properties in destructuring patterns, which is inconsistent with how deprecated props are removed from Property nodes (line 181 prunes), JSXOpeningElement (lines 215-230 filters), and ObjectExpression (lines 473-483 filters).

For example, const { __unstable_manageBillingUrl, other } = props; would retain the deprecated prop in the pattern.

Apply this diff to filter out deprecated props from ObjectPattern:

 root.find(j.ObjectPattern).forEach(path => {
-  path.node.properties.forEach(prop => {
+  const filtered = [];
+  path.node.properties.forEach(prop => {
     if (!prop) {
       return;
     }
     const keyName = getPropertyName(prop.key);
     if (keyName && REMOVED_PROPS.has(keyName) && !prop.computed) {
+      dirty = true;
       return;
     }
     if (prop.key) {
       renamePropertyKey(prop.key, prop.computed);
     }
     if (prop.value && j.Identifier.check(prop.value)) {
       renameIdentifier(prop.value);
     }
+    filtered.push(prop);
   });
+  path.node.properties = filtered;
 });
🧹 Nitpick comments (1)
packages/upgrade/src/codemods/transform-align-experimental-unstable-prefixes.cjs (1)

339-469: Consider extracting shared logic for require() handling.

The blocks handling UI theme requires (lines 339-405) and Chrome extension requires (lines 407-469) are nearly identical, differing only in the source constants, name sets, and target destinations. Extracting a shared helper function would improve maintainability and reduce duplication.

For example:

const relocateRequireImports = (sourceMatcher, nameSet, targetSource) => {
  root
    .find(j.VariableDeclarator, {
      init: { callee: { name: 'require' } },
    })
    .filter(path => {
      const arg = path.node.init.arguments?.[0];
      return (
        arg &&
        (j.Literal.check(arg) || (j.StringLiteral && j.StringLiteral.check(arg))) &&
        sourceMatcher(arg.value)
      );
    })
    .forEach(path => {
      // ... shared relocation logic ...
    });
};

// Then call:
relocateRequireImports(
  source => UI_LEGACY_SOURCES.has(source),
  UI_THEME_NAMES,
  UI_THEME_SOURCE
);
relocateRequireImports(
  source => source === CHROME_LEGACY_SOURCE,
  CHROME_CLIENT_NAMES,
  CHROME_BACKGROUND_SOURCE
);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 202e28c and 955f685.

📒 Files selected for processing (2)
  • packages/upgrade/src/__tests__/integration/runner.test.js (1 hunks)
  • packages/upgrade/src/codemods/transform-align-experimental-unstable-prefixes.cjs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/upgrade/src/tests/integration/runner.test.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (28)
  • GitHub Check: Publish with pkg-pr-new
  • GitHub Check: Unit Tests (shared, clerk-js, RQ)
  • GitHub Check: Static analysis
  • GitHub Check: Integration Tests (nextjs, chrome, 16, RQ)
  • GitHub Check: Integration Tests (quickstart, chrome, 16)
  • GitHub Check: Integration Tests (quickstart, chrome, 15)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (machine, chrome, RQ)
  • GitHub Check: Integration Tests (machine, chrome)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 16)
  • GitHub Check: Integration Tests (billing, chrome, RQ)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (custom, chrome)
  • GitHub Check: Integration Tests (vue, chrome)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (handshake:staging, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (handshake, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Integration Tests (sessions:staging, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (1)
packages/upgrade/src/codemods/transform-align-experimental-unstable-prefixes.cjs (1)

248-337: Import reorganization logic looks sound.

The complex logic for relocating UI theme imports (lines 254-294) and Chrome extension imports (lines 296-336) appears correct:

  • Properly identifies and normalizes specifiers to move
  • Handles the case where source is already the target (lines 268-275)
  • Creates new imports or merges into existing ones using mergeImportSpecifiers
  • Correctly removes or updates original imports based on remaining specifiers

The mergeImportSpecifiers utility prevents duplicate imports, and the use of insertAfter preserves import ordering.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/upgrade/src/codemods/index.js (1)

44-52: dry vs dryRun still allow real writes when dry is true but dryRun is false

As currently structured:

  • A caller passing { dry: true } but leaving dryRun falsy will:
    • Run the first jscodeshift pass in dry mode (no writes).
    • Still run the second pass with dry: false (real file writes), because only dryRun gates the second pass.
    • Then hit if (options.dry) { return dryResult; }, returning the dry stats while the second pass has already mutated files.

That’s surprising behavior for programmatic callers who might reasonably equate dry: true with “do not write changes,” and it can lead to unintended code modifications that the returned result doesn’t reflect.

You can preserve current CLI semantics while making dry safe by treating it as an alias for “dry run” at this level and skipping the second pass whenever either dry or dryRun is truthy, and by short‑circuiting before the second run. For example:

   const resolvedPath = resolve(__dirname, `${transform}.cjs`);
-
-  const paths = await globby(glob, { ignore: GLOBBY_IGNORE });
-
-  if (options.skipCodemods) {
+  if (options.skipCodemods) {
     return {
       stats: {
         total: 0,
         modified: 0,
         deleted: 0,
       },
     };
   }
+
+  const paths = await globby(glob, { ignore: GLOBBY_IGNORE });
+
+  const isDryRun = Boolean(options.dryRun ?? options.dry);
 
   // First pass: dry run to collect stats (jscodeshift only reports stats in dry mode)
   const dryResult = await run(resolvedPath, paths ?? [], {
     ...options,
     dry: true,
     silent: true,
   });
 
-  let result = {};
-  if (!options.dryRun) {
-    // Second pass: apply the changes
-    result = await run(resolvedPath, paths ?? [], {
-      ...options,
-      dry: false,
-      silent: true,
-    });
-  }
-
-  if (options.dry) {
-    return dryResult;
-  }
+  if (isDryRun) {
+    // Only collect stats; don't apply changes.
+    return dryResult;
+  }
+
+  // Second pass: apply the changes
+  const result = await run(resolvedPath, paths ?? [], {
+    ...options,
+    dry: false,
+    silent: true,
+  });
 
   // Merge stats from dry run into final result
   return {
     ...result,
     stats: dryResult.stats,
   };

This:

  • Keeps existing CLI behavior for dryRun.
  • Ensures that any caller setting dry: true (with or without dryRun) never triggers the write pass.
  • Avoids doing the expensive second run just to throw its result away.

To double‑check how risky this is and who might be using dry, you can scan for runCodemod call sites:

#!/bin/bash
# Inspect call sites and options passed into runCodemod
rg -n "runCodemod\(" -C3

Also applies to: 61-79

🧹 Nitpick comments (1)
packages/upgrade/src/codemods/index.js (1)

4-4: Nice codemod config + human‑friendly summary; consider doc/testability tweaks

The CODEMOD_CONFIG mapping plus the summary renderer give a good hook for per‑transform guidance and clear follow‑up instructions for developers, and the messages themselves are concrete and actionable.

Two small polish ideas you might consider (non‑blocking):

  • If getCodemodConfig and this config object are part of the package’s public surface (used outside this package), adding a brief JSDoc on getCodemodConfig and documenting the expected stats shape would help future callers and align with the “public APIs documented with JSDoc” guideline.
  • For easier unit testing and potential reuse, you could factor the message assembly into a pure helper that returns an array of lines, and have renderDeprecatedPropsSummary just join/console.log them. That would let tests assert on output without needing to stub the console.

Also applies to: 10-14, 82-120

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 955f685 and 243fc07.

📒 Files selected for processing (2)
  • packages/upgrade/src/codemods/index.js (3 hunks)
  • packages/upgrade/src/runner.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/upgrade/src/runner.js
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

All code must pass ESLint checks with the project's configuration

Files:

  • packages/upgrade/src/codemods/index.js
**/*.{js,jsx,ts,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/upgrade/src/codemods/index.js
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Follow established naming conventions (PascalCase for components, camelCase for variables)

Files:

  • packages/upgrade/src/codemods/index.js
packages/**/src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

packages/**/src/**/*.{ts,tsx,js,jsx}: Maintain comprehensive JSDoc comments for public APIs
Use tree-shaking friendly exports
Validate all inputs and sanitize outputs
All public APIs must be documented with JSDoc
Use dynamic imports for optional features
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Implement proper logging with different levels

Files:

  • packages/upgrade/src/codemods/index.js
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Use ESLint with custom configurations tailored for different package types

Files:

  • packages/upgrade/src/codemods/index.js
**/*.{js,ts,jsx,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Use Prettier for code formatting across all packages

Files:

  • packages/upgrade/src/codemods/index.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (28)
  • GitHub Check: Integration Tests (machine, chrome, RQ)
  • GitHub Check: Integration Tests (quickstart, chrome, 16)
  • GitHub Check: Integration Tests (nextjs, chrome, 16, RQ)
  • GitHub Check: Integration Tests (billing, chrome, RQ)
  • GitHub Check: Integration Tests (nextjs, chrome, 16)
  • GitHub Check: Integration Tests (machine, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome, 15)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (handshake, chrome)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (custom, chrome)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (vue, chrome)
  • GitHub Check: Integration Tests (handshake:staging, chrome)
  • GitHub Check: Integration Tests (sessions:staging, chrome)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (1)
packages/upgrade/src/codemods/index.js (1)

31-33: Expanded ignore patterns look appropriate for JS/TS codemods

Excluding common binary assets and stylesheet extensions from the codemod glob should reduce unnecessary file system work and avoid accidentally feeding non‑source files into jscodeshift. This looks aligned with how these codemods are meant to be used.

@brkalow brkalow enabled auto-merge (squash) December 8, 2025 22:46
@brkalow brkalow merged commit ff335a0 into main Dec 8, 2025
43 checks passed
@brkalow brkalow deleted the brk.feat/upgrade-cli-core-3 branch December 8, 2025 22:54
@jacekradko jacekradko mentioned this pull request Dec 9, 2025
9 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants