Skip to content

Comments

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

User description

PR_040


PR Type

Enhancement, Tests


Description

  • Add CLI command typo detection using Levenshtein distance algorithm

  • Detect and suggest corrections for mistyped Next.js commands

  • Export commands object for typo detection module access

  • Add comprehensive integration tests for typo detection


Diagram Walkthrough

flowchart LR
  A["User enters typo<br/>e.g., 'buidl'"] --> B["getProjectDir detects<br/>invalid input"]
  B --> C["detectTypo calculates<br/>Levenshtein distance"]
  C --> D["Match found<br/>distance ≤ 2"]
  D --> E["Suggest correction<br/>Did you mean 'build'?"]
  E --> F["Exit with error"]
Loading

File Walkthrough

Relevant files
Enhancement
detect-typo.ts
Implement typo detection with Levenshtein distance             

packages/next/lib/detect-typo.ts

  • Implement minDistance function using dynamic programming to calculate
    Levenshtein distance
  • Implement detectTypo function to find closest matching command within
    threshold
  • Filter and sort potential typos by distance, returning best match or
    null
+44/-0   
get-project-dir.ts
Integrate typo detection into directory validation             

packages/next/lib/get-project-dir.ts

  • Import commands object and detectTypo function
  • Add typo detection logic when directory is not found
  • Display helpful error message suggesting correct command
  • Exit process when typo is detected
+13/-0   
next.ts
Export commands object for module access                                 

packages/next/bin/next.ts

  • Export commands object to make it accessible to other modules
  • Enable typo detection module to access available CLI commands
+1/-1     
Tests
index.test.js
Add integration tests for typo detection                                 

test/integration/cli/test/index.test.js

  • Add new test case detects command typos with multiple typo scenarios
  • Test typos for common commands: build, export, start, dev
  • Verify error messages suggest correct commands
  • Validate typo detection works across various misspellings
+20/-0   

* 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>
@qodo-code-review
Copy link

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Algorithmic complexity

Description: The Levenshtein implementation in minDistance() runs in O(m*n) time with no
early-exit/short-circuit despite accepting a threshold parameter, so a very long
user-controlled input (propagated from CLI args via getProjectDir()) can cause excessive
CPU/memory usage (algorithmic complexity DoS).
detect-typo.ts [1-28]

Referred Code
// the minimum number of operations required to convert string a to string b.
function minDistance(a: string, b: string, threshold: number): number {
  const m = a.length
  const n = b.length

  if (m < n) {
    return minDistance(b, a, threshold)
  }

  if (n === 0) {
    return m
  }

  let previousRow = Array.from({ length: n + 1 }, (_, i) => i)

  for (let i = 0; i < m; i++) {
    const s1 = a[i]
    let currentRow = [i + 1]
    for (let j = 0; j < n; j++) {
      const s2 = b[j]
      const insertions = previousRow[j + 1] + 1


 ... (clipped 7 lines)
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Hard process exit: The new typo-detection path terminates via process.exit(1) inside getProjectDir, which may
prevent callers from handling the error and can be non-graceful depending on runtime
context.

Referred Code
if (typeof dir === 'string') {
  const detectedTypo = detectTypo(dir, Object.keys(commands))

  if (detectedTypo) {
    Log.error(
      `"next ${dir}" does not exist. Did you mean "next ${detectedTypo}"?`
    )
    process.exit(1)
  }

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Relocate command typo detection logic

Move the command typo detection logic from the getProjectDir function to the
main command dispatcher in packages/next/bin/next.ts. This separates command
parsing from directory handling.

Examples:

packages/next/lib/get-project-dir.ts [23-41]
    if (err.code === 'ENOENT') {
      if (typeof dir === 'string') {
        const detectedTypo = detectTypo(dir, Object.keys(commands))

        if (detectedTypo) {
          Log.error(
            `"next ${dir}" does not exist. Did you mean "next ${detectedTypo}"?`
          )
          process.exit(1)
        }

 ... (clipped 9 lines)

Solution Walkthrough:

Before:

// in 'packages/next/lib/get-project-dir.ts'
export function getProjectDir(dir?: string) {
  try {
    // ... try to resolve directory
  } catch (err: any) {
    if (err.code === 'ENOENT') {
      // If directory not found, check if it was a command typo
      const detectedTypo = detectTypo(dir, Object.keys(commands))
      if (detectedTypo) {
        Log.error(`Did you mean "next ${detectedTypo}"?`)
        process.exit(1)
      }
      // ... otherwise, it's a real missing directory
      Log.error(`Invalid project directory provided...`)
      process.exit(1)
    }
    throw err
  }
}

After:

// in 'packages/next/bin/next.ts'
const command = argv._[0]

if (commands[command]) {
  // ... execute valid command
} else {
  // Handle unknown command before treating it as a directory
  const detectedTypo = detectTypo(command, Object.keys(commands));
  if (detectedTypo) {
    log.error(`Did you mean "next ${detectedTypo}"?`);
    process.exit(1);
  }

  // ... then proceed with original unknown command/directory logic
  log.error('Unknown command:', command);
  process.exit(1);
}
Suggestion importance[1-10]: 9

__

Why: This suggestion correctly identifies a significant design flaw, where command typo detection is improperly coupled with file system error handling, and proposes a much cleaner, more robust architectural solution.

High
General
Make typo detection case-insensitive

Make typo detection case-insensitive by converting both the user input and the
command options to lowercase before calculating the distance.

packages/next/lib/detect-typo.ts [31-44]

 export function detectTypo(input: string, options: string[], threshold = 2) {
+  const normalizedInput = input.toLowerCase()
   const potentialTypos = options
     .map((o) => ({
       option: o,
-      distance: minDistance(o, input, threshold),
+      distance: minDistance(o.toLowerCase(), normalizedInput, threshold),
     }))
     .filter(({ distance }) => distance <= threshold && distance > 0)
     .sort((a, b) => a.distance - b.distance)
 
   if (potentialTypos.length) {
     return potentialTypos[0].option
   }
   return null
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: This is a valuable improvement that makes the typo detection case-insensitive, which is the expected behavior for CLI commands, thus enhancing the feature's robustness.

Medium
Remove unused function parameter

Remove the unused threshold parameter from the minDistance function signature
and its recursive call, as it is not used in the function's logic.

packages/next/lib/detect-typo.ts [2-8]

 // the minimum number of operations required to convert string a to string b.
-function minDistance(a: string, b: string, threshold: number): number {
+function minDistance(a: string, b: string): number {
   const m = a.length
   const n = b.length
 
   if (m < n) {
-    return minDistance(b, a, threshold)
+    return minDistance(b, a)
   }
 ...

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 5

__

Why: The suggestion correctly identifies that the threshold parameter in minDistance is unused, and removing it is a valid way to clean up the code.

Low
  • More

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants