To rename a symbol across a JavaScript repo, Atlas combines three passes: the lsp tool's findReferences gives the authoritative callsite list from the language server, grep catches the occurrences the language server never sees (string keys, JSDoc comments, README examples, npm script names in package.json), and edit with replaceAll does the mechanical rewriting. A rename is where naive find-and-replace does the most damage, and JavaScript makes that worse than most languages because there is no compiler to catch a missed reference. edit refuses ambiguous single replacements, so an unintended match is an error rather than a silent corruption.
Why is renaming a JavaScript symbol riskier than renaming one in a typed language?
JavaScript has no compile step to catch a missed reference. A rename that leaves one stale call to createUserSession in src/auth/session.js ships fine and fails at runtime in the browser bundle. Atlas therefore runs 2 discovery passes, lsp findReferences and grep, before a single edit.
The JavaScript idioms that break a naive rename are the ones a language server cannot follow: a dynamic require, a handler looked up by string key in an object map, an export named in the exports field of package.json, a function referenced by name inside an npm script, or a JSDoc @param tag. None of those are references in the language server's sense, and all of them break at runtime. Atlas's answer is not to trust one source. findReferences through the lsp tool gives the real reference graph the JavaScript language service can resolve. grep, which runs through ripgrep with a real regex plus include and path filters, sweeps everything else in the repo, including .md docs and the bundler config.
How do I get the true callsite list for a JavaScript function before renaming it?
Run the lsp tool's findReferences operation on the symbol. Atlas asks the language server, not a text matcher, so a rename of a function used in 30 files under src/ starts from the authoritative list rather than a regex that also matched a similarly named variable in a test fixture.
findReferences is the first pass because it is the only pass that distinguishes a real reference from a coincidental string. In a JavaScript repo where getConfig appears both as an exported function in src/config/index.js and as a property name in an unrelated options object, a regex sees two hits and the language server sees one. Atlas also indexes code by AST declarations using tree-sitter, not blind line windows, so when you use codebase_search to find where the symbol is declared in the first place, the hit is the function declaration itself. Run atlas where your package.json lives and it maps your modules, npm scripts, and bundler config, which is the context that makes findReferences meaningful.
What does grep catch during a JavaScript rename that findReferences misses?
grep catches everything outside the JavaScript type system: string literals, JSDoc comments, markdown docs, and config. Atlas runs grep for the old name as a second pass, through ripgrep with include and path filters, because a rename that updates 30 imports and leaves the name in package.json scripts is not finished.
Concretely, in a JavaScript repo the second grep pass finds the old name in places like a route table that maps 'createUserSession' to a handler, a JSDoc @returns tag in src/auth/session.js, an example in README.md, an entry in the exports map of package.json, a mock name inside a Jest test, and a chunk name in the bundler config. None of those are references. All of them are breakage or rot. Atlas grep takes a real regex plus include and path filters, so you can scope the sweep to '*.js' or to docs and handle each class of hit deliberately instead of blanket-replacing across the repo.
How does Atlas edit with replaceAll avoid corrupting a JavaScript file?
Atlas applies the mechanical renames with edit using replaceAll where the match is unambiguous per file. Where a single occurrence must change, edit enforces uniqueness: 1 name appearing 4 times in src/auth/session.js throws Found multiple matches for oldString unless you add context or opt into replaceAll.
That uniqueness rule is the safety property that a shell one-liner over src/**/*.js does not have. If Atlas is asked to change one occurrence of a name that appears four times in src/auth/session.js, edit does not pick one, it throws Found multiple matches for oldString and demands either surrounding context or an explicit replaceAll. So the failure mode of a JavaScript rename becomes a loud error at the moment of the edit rather than a wrong callsite discovered a week later in production. Atlas also computes a unified diff for every file edit and surfaces it for approval before writing, so every replaceAll you accept was shown to you first.
How do I prove a JavaScript rename is complete?
Atlas proves a JavaScript rename is complete with 2 checks: run the suite through the bash tool with pnpm vitest run, then grep once more for the old name and prove zero remaining hits. In a repo where the runtime is the only type checker, a clean grep is the closest thing to a compile error.
The order matters. Run pnpm vitest run through bash first, because a rename that broke a mock or a dynamic import shows up as a failing spec. Then run the final grep for the old name across the whole repo, not just src/: docs, package.json, and the bundler config all count. Zero hits is the completion criterion. Finish by running prettier so the diff contains renames and nothing else, and let Atlas stage the change: Atlas reads git branches, status, and diffs, and can stage and create commits on your behalf, and it snapshots file changes as git patches so edits can be diffed and rolled back if one replaceAll went too wide.
How do I set Atlas up in a JavaScript repo before a rename?
Run atlas where your package.json lives. Atlas maps your modules, npm scripts, and bundler config, which is the context the 3 rename passes rely on: lsp findReferences for callsites, grep for strings and docs, and edit for the mechanical rewrite.
Setup is deliberately thin for JavaScript. package.json is the anchor: it tells Atlas the entry points, the npm scripts, and the dependency graph. From there the same install you already use, pnpm, brings the language server's dependencies into place so findReferences resolves. Once running, you can have Atlas modernize callbacks to async/await or add Jest tests, reviewing each diff, and the rename workflow uses the same review path: every edit call surfaces a unified diff before writing, and every Atlas tool call is permission-gated against allow, ask, and deny rules before it runs, so no bash invocation and no write happens without your say.
Step by step
- 01Run atlas where your package.json lives so Atlas maps your modules, npm scripts, and bundler config, then install with pnpm.
- 02Run the lsp tool's findReferences operation on the symbol to get the authoritative callsite list from the JavaScript language server.
- 03Run grep for the old name to catch occurrences outside the type system: string keys, JSDoc comments, README.md examples, package.json scripts, and bundler config.
- 04Apply the mechanical renames with edit using replaceAll where the match is unambiguous per file, reviewing the unified diff Atlas surfaces before each write.
- 05Where a single occurrence must change, let edit enforce uniqueness: it throws Found multiple matches for oldString unless you add context or opt into replaceAll.
- 06Run the suite through the bash tool with pnpm vitest run, since JavaScript has no compiler to catch a missed reference.
- 07Grep once more for the old name across src/, docs, and package.json to prove zero remaining hits.
- 08Run prettier so the final diff shows only renames, then let Atlas stage and commit the change.
Frequently asked questions
- how to safely rename a function across a whole JavaScript codebase
- Use Atlas's three pass approach: lsp findReferences for the authoritative callsite list, grep for the occurrences outside the type system such as string keys and JSDoc comments, then edit with replaceAll for the mechanical rewrite. Finish with pnpm vitest run and a final grep proving zero hits for the old name.
- why is find and replace dangerous for renaming JavaScript symbols
- Find and replace matches text, not references. In JavaScript a name can appear as a property key, a mock name, a docs example, or an unrelated local variable. Atlas's edit tool refuses ambiguous single replacements and throws Found multiple matches for oldString, so an unintended match becomes an error instead of a silent corruption.
- what does Found multiple matches for oldString mean in Atlas
- It means the edit tool found more than one occurrence of the string you asked it to replace once, so it refused rather than guessing. Add surrounding context to make the match unique, or opt into replaceAll if every occurrence in that file should change.
- does renaming a JavaScript symbol require running the tests
- Yes. JavaScript has no compiler to catch a stale reference, so the suite is your check. Run pnpm vitest run through Atlas's bash tool after the renames land, and grep once more for the old name to prove there are zero remaining hits in src/, docs, and package.json.
- can Atlas find where a JavaScript function is declared if I only know what it does
- Yes. Atlas indexes code by AST declarations using tree-sitter, not blind line windows, and searches with hybrid semantic and keyword retrieval fused by reciprocal rank fusion, so codebase_search returns the actual function declaration rather than an arbitrary window of a file.
- how do I undo a JavaScript rename that replaced too much
- Atlas snapshots file changes as git patches so edits can be diffed and rolled back. Every edit also surfaces a unified diff for approval before writing, so an over-wide replaceAll should be visible before it lands rather than after.
- does Atlas work with npm scripts and bundler config
- Yes. Run atlas where your package.json lives and it maps your modules, npm scripts, and bundler config. That matters in a rename because a symbol name can live in an npm script or a bundler chunk name, which grep finds and the language server does not.
Try Atlas in your terminal
The terminal-native AI coding agent. Free core, single binary.
Install AtlasRelated guides
Rename a Symbol Across the Repo with Atlas in 2026
How to rename a symbol across a repo with Atlas in 2026: findReferences gets the true reference set, grep catches strings and docs, and edit refuses ambiguous matches.
Atlas for JavaScript in 2026
In 2026, Atlas empowers JavaScript developers with a terminal-native AI coding agent. It indexes code by AST, uses local embeddings, and offers permission-gated tools for safe, efficient development.
Locate Where a Behavior Is Implemented in JavaScript with Atlas in 2026
Find the exact JavaScript file and symbol behind a behavior in 2026. Atlas pairs codebase_search with grep over ripgrep and the lsp tool's findReferences.
Add a Regression Test for a Bug Fix in JavaScript with Atlas (2026)
Atlas writes a failing vitest spec, proves it fails via the bash tool exit code, applies the JavaScript fix with edit, and re-runs the same command to prove it passes.
Audit a JavaScript Repo with Parallel Subagents in 2026
In 2026, JavaScript developers use Atlas to sweep entire repositories for code issues. Leverage parallel subagents to audit pnpm projects, vitest configurations, and prettier formatting without blowing your main context
Refactor a Legacy Module in JavaScript with Atlas (2026)
Refactor a legacy JavaScript module with Atlas in 2026: enumerate callsites with the lsp tool, restructure with apply_patch, and prove behavior with vitest.
Research a Third-Party API Before Integrating It in JavaScript with Atlas (2026)
Atlas uses websearch and webfetch to pull live API docs into context before you write JavaScript, so your Node or browser integration matches the real endpoints in 2026.
Upgrade a Dependency and Fix the Breakage in JavaScript with Atlas (2026)
Atlas upgrades a JavaScript dependency through pnpm, fetches the release notes with webfetch, and fixes every callsite the build and vitest report, one diff at a time.