Fix Inconsistent Variable Naming in AI Code in 20 Minutes

Standardize variable names across AI-generated codebases using ESLint rules and automated refactoring to improve maintainability.

Problem: AI Tools Use Different Naming Styles

You merged code from ChatGPT, Claude, and Copilot into one codebase. Now you have userData, user_data, and UserData all referring to the same concept, making the code confusing to maintain.

You'll learn:

  • Why AI models produce inconsistent naming
  • How to enforce naming conventions with ESLint
  • Automated refactoring techniques for large codebases

Time: 20 min | Level: Intermediate


Why This Happens

Different AI models were trained on different code repositories with varying conventions. ChatGPT favors camelCase (JavaScript heavy training), Claude sometimes uses snake_case (Python influence), and Copilot matches your file's existing style but inconsistently.

Common symptoms:

  • Same concept named 3+ different ways in one file
  • findUser() but get_order() in the same class
  • PR reviews flagging style inconsistencies
  • Developers unsure which convention to follow

Solution

Step 1: Audit Your Naming Patterns

# Find all variable naming patterns
grep -rE "(let|const|var|function) [a-zA-Z_]+" src/ | \
  sed 's/.*\(let\|const\|var\|function\) \([a-zA-Z_][a-zA-Z0-9_]*\).*/\2/' | \
  sort | uniq -c | sort -rn > naming-audit.txt

Expected: A sorted list showing your most common patterns. Look for duplicates like userData (23 times) and user_data (17 times).


Step 2: Set Up ESLint Naming Rules

npm install --save-dev eslint @typescript-eslint/eslint-plugin

Create .eslintrc.json:

{
  "extends": ["eslint:recommended"],
  "rules": {
    "camelcase": ["error", {
      "properties": "always",
      "ignoreDestructuring": false,
      "ignoreImports": false
    }],
    "@typescript-eslint/naming-convention": [
      "error",
      {
        "selector": "variable",
        "format": ["camelCase", "UPPER_CASE"],
        "leadingUnderscore": "allow"
      },
      {
        "selector": "function",
        "format": ["camelCase"]
      },
      {
        "selector": "typeLike",
        "format": ["PascalCase"]
      }
    ]
  }
}

Why this works: Enforces camelCase for variables/functions (JavaScript standard), PascalCase for types, and allows UPPER_CASE for constants. This catches new violations in PRs.


Step 3: Automated Refactoring for Existing Code

# Install refactoring tools
npm install --save-dev jscodeshift @codemod/cli

Create fix-naming.codemod.js:

// Converts snake_case to camelCase for variables
module.exports = function transformer(file, api) {
  const j = api.jscodeshift;
  const root = j(file.source);

  // Convert variable declarations
  root.find(j.VariableDeclarator)
    .forEach(path => {
      const name = path.value.id.name;
      if (name.includes('_') && name !== name.toUpperCase()) {
        // user_data → userData
        const camelName = name.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
        
        // Rename all references in scope
        j(path)
          .closestScope()
          .find(j.Identifier, { name: name })
          .forEach(identPath => {
            identPath.value.name = camelName;
          });
      }
    });

  return root.toSource();
};

Run the codemod:

npx jscodeshift -t fix-naming.codemod.js src/

Expected: Transforms user_datauserData, api_keyapiKey across all files.

If it fails:

  • Error: "Cannot read property 'name'": Some variables use destructuring. Add destructuring pattern handling.
  • Breaks tests: Constants like API_KEY should stay uppercase. Update codemod to skip UPPER_CASE.

Step 4: Create Pre-Commit Hook

# Install husky for git hooks
npx husky init

Add to .husky/pre-commit:

#!/bin/sh
npx eslint --fix src/
git add -u

Why this works: Automatically fixes naming violations before commits reach your main branch. Prevents new AI-generated code from introducing inconsistencies.


Verification

# Run linter
npx eslint src/

# Check for remaining snake_case
grep -r "[a-z]_[a-z]" src/ --include="*.js" --include="*.ts"

You should see: Zero ESLint errors, no snake_case in grep results (except in strings/comments).


What You Learned

  • AI models inherit naming styles from their training data
  • ESLint enforces conventions for new code, codemods fix existing code
  • Pre-commit hooks prevent regressions

Limitation: This doesn't catch naming logic issues (like handleSubmit() doing validation). Review AI code for semantic correctness separately.


Bonus: Naming Convention Quick Reference

// ✅ JavaScript/TypeScript Standard
const userData = {};           // camelCase for variables
function fetchUser() {}        // camelCase for functions
class UserService {}           // PascalCase for classes
const API_KEY = "secret";      // UPPER_CASE for constants
interface UserData {}          // PascalCase for types

// ⌠Avoid mixing
const user_data = {};          // snake_case (Python style)
function FetchUser() {}        // PascalCase functions (Go style)
const apiKey = "secret";       // Constant not uppercase

When to deviate:

  • External APIs using snake_case (keep as-is, convert at boundary)
  • Database column names (match schema, use ORMs to map)
  • Environment variables (always UPPER_CASE)

Tested with ESLint 9.x, jscodeshift 17.x, Node.js 22.x, TypeScript 5.5+