JavaScript Code Review with LGTM
AI code review for JavaScript: LGTM catches == vs === bugs, missing await on Promises, unhandled rejections, and event-listener cleanup leaks.
How LGTM reviews JavaScript PRs
Tree-sitter parses .js / .jsx / .mjs / .cjs files. JavaScript's dynamic nature means symbol resolution is best-effort: the agents see what's exported and imported, but full type info (which would require TS-style annotation) isn't available.
This is why TypeScript projects get richer reviews — more type info means fewer 'could be anything' false positives. JavaScript projects are still substantially reviewed; the agents just lean on naming conventions, JSDoc comments (when present), and runtime patterns more.
Per-PR: PageRank ranks the symbols related to the diff, agents see context, output structured findings. The same 6-agent pipeline applies — but the Bugs agent has JS-specific heuristics for the failure modes that plain JS produces.
Common JavaScript bugs LGTM catches
Equality bugs. `if (x == null)` is a common idiom (covers both null and undefined); `if (x == 0)` is almost always wrong (also matches '' and false). The agent distinguishes by context.
Missing await on Promise-returning calls. `function save() { db.write() }` — db.write() returns a Promise that nobody awaits. Same pattern as TypeScript; the agent catches it in both.
Unhandled rejections. .then() without .catch() at top level. process.on('unhandledRejection') as a safety net is fine; missing it on Node servers can crash the process silently in modern Node.
Prototype pollution. `Object.assign(target, JSON.parse(userInput))` where userInput could contain __proto__. Flagged by Security agent.
Event listener cleanup. `element.addEventListener('click', handler)` without a corresponding removeEventListener — memory leak in long-lived browser pages and React components without effect cleanup.
for-in on arrays. `for (let i in arr)` instead of `for (let i of arr)` or `arr.forEach` — iterates over inherited properties too. Subtle bug, easy to spot in review.
Tree-sitter coverage for JavaScript
Excellent grammar. ES6 modules, CommonJS, JSX, optional chaining, nullish coalescing, top-level await, dynamic import — all parse cleanly.
Mixed JS+TS monorepos work fine. Each file uses the appropriate tree-sitter grammar based on extension.
Build outputs (dist/, build/, .next/, .nuxt/) are auto-excluded by path heuristics. Source maps (.map) are also excluded — they're not source.
Module resolution follows package.json's exports/main/module fields where present. Workspaces (npm/yarn/pnpm) resolve sub-package imports correctly.
Setup notes for JavaScript projects
Install the LGTM GitHub App. Index time: 20-60 seconds for typical Node apps, longer for monorepos with many packages.
Node + React + Vue + Express + Next + Nuxt + Astro — all supported with the JS grammar. Framework-specific patterns (React hooks, Vue composables) are partly recognised by naming + import heuristics.
JSDoc comments are extracted. Repos that document with JSDoc get richer agent context, similar to TypeScript's type info but lower fidelity.
node_modules is excluded (universal). Build artifacts excluded by common heuristics.
Example bugs LGTM catches
// ❌ Bug: matches 0, '', false, null, undefined
function isEmpty(value) {
return value == false;
}
isEmpty(0); // true <-- probably not what you want
isEmpty(''); // true
isEmpty(false); // true
isEmpty(null); // true
// LGTM finding:
// "Loose equality with false matches many falsy values. If
// the intent is 'no value', use 'value == null' (matches null
// + undefined only). For empty-string check, use 'value === ""'."// ❌ Bug: handler accumulates on every render
function Component() {
const [data, setData] = useState();
useEffect(() => {
window.addEventListener('resize', () => setData(window.innerWidth));
// <-- no cleanup return!
}); // <-- no dep array either
}
// LGTM finding:
// "useEffect adds listener every render with no cleanup.
// Return () => window.removeEventListener(...) from the effect.
// Empty dep array if registration should run once."See LGTM reviewing JavaScript
Node + React + Vue + serverless · npm/yarn/pnpm workspaces
Go to the product pageJavaScript review FAQs
JavaScript vs TypeScript review quality difference?
TypeScript review is richer because the type info helps the agents narrow down 'is this actually a bug or is it fine?' For JS projects with good JSDoc, the gap narrows. For untyped JS with no comments, the agents lean more on naming + structure heuristics.
Node + Express + Fastify all supported?
Yes. The Security agent has light awareness of common patterns — SQL building from req.body, missing helmet, exposed routes without auth middleware. Not a substitute for an AppSec scan but catches common smells.
React Native + Electron + serverless?
All parse the same way. The Bugs agent's heuristics carry across — useEffect cleanup, async without await, etc. work everywhere JS runs.
Mixed JS+TS monorepo?
Fine. Each file picked up by the appropriate grammar. Cross-language imports (TS file imports a JS module) resolve via package.json + tsconfig paths.
Cost per JS review?
$0.04-$0.12 for a 300-line PR on GPT-4o via BYOK. JS code is typically less verbose than Java, more verbose than Python — costs land in the middle.
Related across LGTM
AI code review explained
What LLM review catches in plain JS that ESLint can't articulate.
Tree-sitter explained
Mixed JS/TS monorepos parse cleanly — tree-sitter handles both.
TypeScript code review
Why TS projects get richer review than untyped JS.
Pre-push CLI review
Catch JS bugs locally with `lgtm review` before opening the PR.
Other languages
TypeScript
AI code review for TypeScript: LGTM catches type-narrowing bugs, unsafe assertions, async race conditions, React stale-closure bugs, and unused exports — across the diff and the wider repo context.
Python
AI code review for Python: LGTM catches mutable-default-argument bugs, missing await on coroutines, missing type hints on public APIs, unsafe subprocess, and SQL injection — with full repo context.
Ruby
AI code review for Ruby: LGTM catches N+1 query patterns, dangerous send + eval calls, missing strong-params on Rails controllers, monkey-patch surprises, and unsafe deserialization.
Java
AI code review for Java: LGTM catches potential NPEs, mutable collection leaks from getters, thread-safety smells, missing equals/hashCode pairs, and Spring Boot anti-patterns.