Skip to content

Add CLI command typo detection (#34836)#10

Open
MitchLewis930 wants to merge 1 commit intopr_040_beforefrom
pr_040_after
Open

Add CLI command typo detection (#34836)#10
MitchLewis930 wants to merge 1 commit intopr_040_beforefrom
pr_040_after

Conversation

@MitchLewis930
Copy link

@MitchLewis930 MitchLewis930 commented Jan 30, 2026

PR_040

Summary by CodeRabbit

  • New Features
    • CLI now detects and suggests corrections when users enter mistyped commands, displaying helpful error messages with the correct command format.

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

* Add CLI command typo detection

* Apply suggestions from code review

Co-authored-by: Steven <steven@ceriously.com>

* Apply suggestions from code review

* Apply suggestions from code review

Co-authored-by: Steven <steven@ceriously.com>
@coderabbitai
Copy link

coderabbitai bot commented Jan 30, 2026

📝 Walkthrough

Walkthrough

Introduces a typo detection feature for the Next.js CLI that suggests corrections when invalid commands are provided. A new utility implements Levenshtein distance algorithm; the project directory resolver integrates detection into its error handling path. The commands export is made public to support this feature.

Changes

Cohort / File(s) Summary
Typo Detection Feature
packages/next/lib/detect-typo.ts
New utility module implementing Levenshtein distance algorithm with configurable threshold to find closest matching string option. Exports detectTypo() function that returns the best match or null.
Core Integration
packages/next/bin/next.ts, packages/next/lib/get-project-dir.ts
Exports commands object to enable reuse; enhances project directory resolver to invoke typo detection on ENOENT errors and output corrected command suggestions.
Test Coverage
test/integration/cli/test/index.test.js
Adds test case validating typo detection by verifying CLI outputs suggestions in the format: "next " does not exist. Did you mean "next "?

Sequence Diagram

sequenceDiagram
    actor User
    participant CLI as Next.js CLI
    participant Resolver as getProjectDir()
    participant Detector as detectTypo()
    participant Output as Error Output

    User->>CLI: Enter invalid command (typo)
    CLI->>Resolver: Resolve project directory
    Resolver->>Resolver: Check if directory exists
    alt Directory not found (ENOENT)
        Resolver->>Detector: detectTypo(invalid_command, available_commands)
        Detector->>Detector: Calculate Levenshtein distances
        Detector->>Detector: Filter matches by threshold
        Detector->>Resolver: Return closest match or null
        alt Match found
            Resolver->>Output: Log suggestion message
            Output->>User: "Did you mean 'next <correct>'?"
        else No match
            Resolver->>Output: Log original error
            Output->>User: Original error message
        end
    end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

Poem

🐰 A typo here, a typo there—
Next.js now catches them with care!
Levenshtein hops through distance space,
Suggesting fixes at a rabbit's pace.
Mistyped commands? Fear not, dear friend,
Our CLI guides you to the end! 🐇

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is minimal and non-informative, consisting only of 'PR_040' without explaining the change, rationale, or implementation approach. Provide a meaningful description explaining what changes were made, why they were needed, and how the typo detection works (e.g., what it does, affected files, testing approach).
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding CLI command typo detection functionality.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 pr_040_after

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

Copy link

@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: 1

🤖 Fix all issues with AI agents
In `@packages/next/lib/get-project-dir.ts`:
- Around line 3-5: getProjectDir imports ../bin/next which triggers heavy side
effects (dependency checks, CLI parsing/execution, process.exit, env and signal
handlers); extract the simple commands list into a new side-effect-free module
(e.g., packages/next/lib/commands.ts) that exports the command names
array/object and import that module from both bin/next.ts and get-project-dir.ts
instead of importing ../bin/next; in practice remove the import of ../bin/next
from get-project-dir.ts, create and export the same `commands` symbol from the
new commands.ts, and update bin/next.ts to import `commands` from commands.ts so
behavior is preserved without executing the CLI side effects.
🧹 Nitpick comments (1)
packages/next/lib/detect-typo.ts (1)

2-28: Use threshold to short‑circuit the distance computation.

threshold is currently unused in minDistance, so the full O(m·n) matrix is always computed even when the result will exceed the threshold. Consider an early exit to keep this cheap (and make the parameter meaningful).

♻️ Proposed refactor (early exit)
 function minDistance(a: string, b: string, threshold: number): number {
   const m = a.length
   const n = b.length
+  if (Math.abs(m - n) > threshold) {
+    return threshold + 1
+  }

   if (m < n) {
     return minDistance(b, a, threshold)
   }
@@
     for (let j = 0; j < n; j++) {
       const s2 = b[j]
       const insertions = previousRow[j + 1] + 1
       const deletions = currentRow[j] + 1
       const substitutions = previousRow[j] + Number(s1 !== s2)
       currentRow.push(Math.min(insertions, deletions, substitutions))
     }
+    if (Math.min(...currentRow) > threshold) {
+      return threshold + 1
+    }
     previousRow = currentRow
   }
   return previousRow[previousRow.length - 1]
 }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0aba307 and ed43c03.

📒 Files selected for processing (4)
  • packages/next/bin/next.ts
  • packages/next/lib/detect-typo.ts
  • packages/next/lib/get-project-dir.ts
  • test/integration/cli/test/index.test.js
🧰 Additional context used
🧬 Code graph analysis (2)
test/integration/cli/test/index.test.js (1)
test/lib/next-test-utils.js (2)
  • check (452-479)
  • runNextCommand (129-219)
packages/next/lib/get-project-dir.ts (3)
test/integration/cli/test/index.test.js (1)
  • dir (15-15)
packages/next/lib/detect-typo.ts (1)
  • detectTypo (31-44)
packages/next/bin/next.ts (1)
  • commands (18-27)
🔇 Additional comments (4)
packages/next/lib/detect-typo.ts (1)

31-43: Nice, concise selection logic.
The filtering and closest-match selection are clear and easy to reason about.

packages/next/bin/next.ts (1)

17-18: Exporting commands for reuse looks fine.

packages/next/lib/get-project-dir.ts (1)

24-33: Typo suggestion path reads well.
The error message is clear and the early exit is consistent with existing ENOENT handling.

test/integration/cli/test/index.test.js (1)

61-79: Good coverage for typo suggestions.
The test matrix is clear and aligns with the new CLI behavior.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +3 to +5
import { commands } from '../bin/next'
import * as Log from '../build/output/log'
import { detectTypo } from './detect-typo'
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find all call sites of getProjectDir and all imports of it
rg -n "getProjectDir\s*\(" --type=ts --type=tsx | head -30

Repository: Signal65/next.js-CodeRabbit

Length of output: 98


🏁 Script executed:

# Find all imports of get-project-dir module
rg -n "from ['\"].*get-project-dir['\"]" --type=ts --type=tsx

Repository: Signal65/next.js-CodeRabbit

Length of output: 98


🏁 Script executed:

# Check the bin/next file to understand what it does
cat -n packages/next/bin/next

Repository: Signal65/next.js-CodeRabbit

Length of output: 125


🏁 Script executed:

# Also check the actual get-project-dir.ts file to see full context
cat -n packages/next/lib/get-project-dir.ts

Repository: Signal65/next.js-CodeRabbit

Length of output: 1579


🏁 Script executed:

# Find the bin/next file (may be .js or .ts)
find packages/next/bin -type f 2>/dev/null | head -20

Repository: Signal65/next.js-CodeRabbit

Length of output: 96


🏁 Script executed:

# List files in bin directory
ls -la packages/next/bin/ 2>/dev/null || echo "Directory listing failed"

Repository: Signal65/next.js-CodeRabbit

Length of output: 241


🏁 Script executed:

# Use git to find bin files
git ls-files packages/next/bin/ 2>/dev/null | head -20

Repository: Signal65/next.js-CodeRabbit

Length of output: 96


🏁 Script executed:

# Search for getProjectDir usages without type filters
rg -n "getProjectDir" packages/next --max-count=50

Repository: Signal65/next.js-CodeRabbit

Length of output: 974


🏁 Script executed:

cat -n packages/next/bin/next.ts

Repository: Signal65/next.js-CodeRabbit

Length of output: 5679


🏁 Script executed:

# Check if there are any side effects at top level before the 'commands' export
head -100 packages/next/bin/next.ts | cat -n

Repository: Signal65/next.js-CodeRabbit

Length of output: 3804


🏁 Script executed:

# Verify circular dependency by checking if cli/next-build imports get-project-dir
head -20 packages/next/cli/next-build.ts | grep -n "get-project-dir"

Repository: Signal65/next.js-CodeRabbit

Length of output: 127


🏁 Script executed:

# Check the structure of the commands object more carefully
sed -n '18,27p' packages/next/bin/next.ts

Repository: Signal65/next.js-CodeRabbit

Length of output: 659


Extract the commands list to a side-effect-free module.

Importing ../bin/next pulls in significant side effects: dependency checks (lines 5–14), immediate argument parsing (lines 29–43), potential process.exit() calls on --version or --help (lines 46–72), environment mutation (line 106), process signal handlers (lines 125–126), and most critically, immediate CLI command execution (lines 128–150). This causes unpredictable behavior when getProjectDir is called from library code. Create a separate module (e.g., packages/next/lib/commands.ts) exporting only the command names, and import that in both bin/next.ts and get-project-dir.ts to eliminate side effects and the circular dependency.

🤖 Prompt for AI Agents
In `@packages/next/lib/get-project-dir.ts` around lines 3 - 5, getProjectDir
imports ../bin/next which triggers heavy side effects (dependency checks, CLI
parsing/execution, process.exit, env and signal handlers); extract the simple
commands list into a new side-effect-free module (e.g.,
packages/next/lib/commands.ts) that exports the command names array/object and
import that module from both bin/next.ts and get-project-dir.ts instead of
importing ../bin/next; in practice remove the import of ../bin/next from
get-project-dir.ts, create and export the same `commands` symbol from the new
commands.ts, and update bin/next.ts to import `commands` from commands.ts so
behavior is preserved without executing the CLI side effects.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants