# Migrate a deprecated API across every callsite in JavaScript with Atlas (2026)

> Atlas migrates a deprecated JavaScript API by enumerating every caller with the lsp tool's findReferences, tracking each one in todowrite, and applying one context-anchored apply_patch per callsite.

Migrating a deprecated JavaScript API is the workflow that punishes half-measures, so Atlas front-loads enumeration. The lsp tool's findReferences operation yields the complete caller set from the language server, grep catches the dynamic and string-based usages the language server cannot see, and todowrite turns the list into tracked work so no `require()` site in a Node script or `import` in a browser bundle is silently skipped. Each migration lands as a context-anchored apply_patch, and you run vitest through Atlas's bash tool after every file, marking a todo completed only once it is green.

## Key takeaways

- Atlas front-loads enumeration: the lsp tool's findReferences yields the complete JavaScript caller set from the language server before any edit happens.
- Grep catches the dynamic and string-based JavaScript usages that findReferences cannot see, so the true callsite list is the union of both.
- One todowrite entry per callsite makes partial progress visible, and a JavaScript migration is only correct at 100 percent.
- apply_patch throws Failed to find expected lines rather than guessing, so a drifted file fails the patch instead of corrupting it.
- Run vitest after each file, not once at the end, and mark a todo completed only once the tests pass.
- Grep for the deprecated symbol at the end, confirm zero hits, then delete the old implementation so any missed caller fails loudly.

## How do I find every caller of a deprecated JavaScript function?

Enumerate every caller of the deprecated JavaScript symbol with Atlas's lsp tool findReferences operation, which returns the complete reference set from the language server, then cross-check with grep for dynamic or string-based usages. 2 passes, because JavaScript hides callers the type system never sees.

A JavaScript migration fails on the caller you did not know about. Atlas therefore front-loads enumeration rather than starting to edit. The lsp tool's findReferences operation on the deprecated function returns the callers the language server can prove, which covers ordinary `import { legacyFetch } from './lib/http.js'` sites across `src/` and `scripts/`. Then Atlas greps for the same name to catch what the language server cannot: a `require('./lib/http')` accessed by computed property, a method looked up by string on an options object, a name that only appears in a README or a `package.json` script. Atlas's grep runs through ripgrep and takes a real regex plus include and path filters, so you can scope it to `*.js` and `*.mjs` and keep `node_modules` out. The union of the two passes is the true callsite list.

## How do I track a multi-file JavaScript migration so nothing gets skipped?

Atlas creates one todowrite entry per callsite, so partial progress is visible and nothing is silently skipped. A migration across 23 JavaScript files becomes 23 tracked items rather than one vague task that a model, or a developer, can quietly declare finished at file 14.

todowrite is the accountability layer of an Atlas migration. Every callsite that findReferences and grep produced becomes its own entry with a status, so at any point you can see which JavaScript modules are migrated, which are in progress, and which are untouched. That structure matters because a deprecated-API migration is only correct at 100 percent: a codebase with 22 of 23 callers migrated still crashes at the twenty-third. The todo list also survives across turns, so a long migration through `src/api/`, `src/utils/`, and `scripts/` does not depend on Atlas remembering what it did. Atlas fans out work to subagents that can run in the foreground or in parallel background sessions, so large caller sets can be worked in parallel while the todowrite list remains the single record of what is actually done.

## How does apply_patch migrate a JavaScript callsite without misapplying?

Atlas migrates each JavaScript callsite with apply_patch, which seeks the hunk's context and old_lines and throws Failed to find expected lines rather than guessing. A patch against a drifted src/api/client.js fails loudly instead of landing in the wrong function, which is exactly what you want during a migration that spans 23 files.

apply_patch is context-anchored. Each hunk carries the surrounding JavaScript lines it expects to find, and if the file has changed since Atlas read it, apply_patch throws Failed to find expected lines rather than applying to a best-guess location. During a migration this failure is a feature. A run-of-the-mill replace would happily rewrite the wrong call in a file that another process or another subagent modified underneath it. Atlas computes a unified diff for every file edit and surfaces it for approval before writing, so you review each JavaScript callsite change before it lands, and Atlas snapshots file changes as git patches so any patch can be diffed and rolled back. Every Atlas tool call is permission-gated against allow, ask, and deny rules before it runs, which applies to the apply_patch as much as to the bash call after it.

## When should I run vitest during a JavaScript API migration?

Run the affected tests with Atlas's bash tool after each JavaScript file, not once at the end, and mark the todowrite entry completed only once vitest passes. A migration that runs the suite once at the end tells you that something broke across 23 files, which is the least useful possible signal.

Per-file verification is what makes a large JavaScript migration recoverable. After apply_patch lands on `src/api/client.js`, run vitest through Atlas's bash tool scoped to the tests that cover that module, and only then mark the corresponding todowrite entry completed. If the tests fail, exactly one file changed since the last green state, so the blast radius of the investigation is one patch. Use pnpm to install anything the replacement API needs, and run prettier over each migrated file so the diff a reviewer sees contains behavior changes rather than formatting noise. Atlas reads git branches, status, and diffs, and can stage and create commits on your behalf, so a clean per-file rhythm of patch, vitest, commit is easy to hold across a long migration.

## How do I prove a deprecated JavaScript API has zero remaining callers?

Finish a JavaScript migration by grepping for the deprecated symbol and confirming 0 remaining hits, then delete the old implementation. Deleting the old function is the real proof: if a caller survived anywhere in src/ or scripts/, vitest and the bundler will say so immediately.

A migration is not done when the last todowrite entry is checked. Atlas's documented final step is to grep for the deprecated symbol across the JavaScript codebase and confirm zero remaining hits, which catches the string-based and dynamic usages the language server never reported. Only then delete the old implementation from `src/lib/http.js` or wherever it lived. Removing it converts every missed caller from a silent deprecation warning into a hard failure at the next vitest run, which is the outcome you want. Atlas computes a unified diff for the deletion and surfaces it for approval before writing, and because Atlas snapshots file changes as git patches, the deletion can be rolled back if the grep missed something exotic. Run prettier once more, run vitest across the whole suite, then let Atlas stage and create the commit.

## Steps

1. Enumerate every caller of the deprecated JavaScript symbol with the lsp tool's findReferences operation, which returns the complete reference set from the language server.
2. Cross-check with Atlas's grep for dynamic or string-based usages the language server cannot see, scoping the ripgrep search to *.js and *.mjs so node_modules stays out.
3. Create one todowrite entry per callsite so partial progress is visible and nothing is silently skipped across src/, scripts/, and any bundler config.
4. Migrate each callsite with apply_patch, which seeks the hunk's context and old_lines and throws Failed to find expected lines rather than guessing on a drifted file.
5. Review the unified diff Atlas surfaces for each JavaScript file before it writes, since every file edit is presented for approval.
6. Run the affected tests with vitest through Atlas's bash tool after each file, and install any new dependency with pnpm.
7. Mark the todowrite entry completed only once vitest passes for that file, so the todo list is a record of verified work rather than attempted work.
8. Run prettier over every migrated file so the reviewer sees behavior changes rather than formatting noise.
9. Grep for the deprecated symbol one final time, confirm zero remaining hits, then delete the old implementation and run the full vitest suite.

## FAQ

### how to find every callsite of a deprecated function in javascript

Run the lsp tool's findReferences operation on the deprecated symbol to get the language server's complete reference set, then grep for the same name to catch dynamic and string-based usages the language server cannot see.

### how do I migrate a deprecated api across many javascript files without missing one

Enumerate callers with findReferences plus grep, create one todowrite entry per callsite, migrate each with apply_patch, run vitest after every file, then grep at the end and confirm zero remaining hits before deleting the old implementation.

### what does Failed to find expected lines mean in atlas

apply_patch is context-anchored: it seeks the hunk's context and old_lines. Failed to find expected lines means the JavaScript file drifted since Atlas read it, so the patch refused to guess. Re-read the file and reissue the patch.

### why does grep find javascript callers that findReferences misses

The language server only sees usages the type system can resolve. A function accessed by computed property, referenced by string in a config, or named in a package.json script is invisible to findReferences but visible to grep, which is why Atlas runs both.

### should I run vitest after every file during a migration

Yes. Run vitest through Atlas's bash tool after each migrated JavaScript file and mark the todowrite entry completed only once it passes. Running the suite once at the end tells you something broke, not which patch broke it.

### when should I delete the old javascript implementation

Delete it only after grepping for the deprecated symbol and confirming zero remaining hits. Deleting it turns any surviving caller into a hard vitest or bundler failure instead of a silent deprecation warning, which is the outcome you want.

### does atlas apply javascript patches without my approval

No. Atlas computes a unified diff for every file edit and surfaces it for approval before writing, and every tool call is permission-gated against allow, ask, and deny rules before it runs.

### can I roll back one bad callsite patch in javascript

Yes. Atlas snapshots file changes as git patches so edits can be diffed and rolled back. Because apply_patch works per file, one bad JavaScript callsite migration can be reverted without disturbing the ones that already pass vitest.

---

Canonical HTML: https://runatlas.sh/resources/stacks/migrate-a-deprecated-api-across-callsites-in-javascript
Source of truth: aeo_pages row `/resources/stacks/migrate-a-deprecated-api-across-callsites-in-javascript` (segment: Stacks) (this file is generated from it, never hand-edited).
Licence: Atlas is proprietary with a free core. It is not open source and there is no public source repository.
