Scan & Plan in depth
Exactly how CodeMorph reads your project, resolves every import, builds the dependency graph and turns it into leaf-first batches.
Scan & Plan is the foundation of every migration. It reads your project, builds a dependency graph and turns that graph into an ordered plan. It's fully local, needs no API key and never changes a file.
Start it with Start Migration in the Morph panel or Ctrl Shift M.
1. Finding files
CodeMorph walks your workspace folder and collects source files with these extensions:
.js · .jsx · .mjs · .cjs · .ts · .tsx
It skips:
- Anything ignored by git. Every
.gitignorefrom your repository root down to the workspace folder is applied, including nested ones, sonode_modules,distand other build output never enter the graph. - Files over 1 MB. These are almost always generated or bundled code. They're listed as skipped rather than slowing the scan.
In a multi-root workspace, the first folder is scanned.
2. Parsing
Each file is parsed with tree-sitter, using grammars for JavaScript, JSX, TypeScript and TSX. tree-sitter is fast and error-tolerant: a file with a syntax error still produces a usable tree, and CodeMorph records that the file has errors instead of failing the scan.
From each tree CodeMorph extracts:
- Imports:
importstatements,import()calls andrequire()calls, including destructured requires. - Exports: named and default exports,
module.exportsandexports.x, and re-exports such asexport * fromandexport { x } from. - Declarations: functions, classes, variables, types and interfaces, with their line ranges and whether they're exported.
3. Resolving imports
Every import specifier is resolved to a target, using the same rules your toolchain does. The first match wins:
- Path aliases. If the specifier matches
compilerOptions.pathsintsconfig.jsonorjsconfig.json, it's rewritten againstbaseUrl. - The exact path, relative to the importing file.
- Extensions, tried in this order:
.ts,.tsx,.js,.jsx,.mjs,.cjs. - Index files: the same extensions under
/index. - TypeScript-style specifiers. Under NodeNext rules an import of
./dep.jsmay refer todep.ts, so.jsalso matches.tsand.tsx,.jsxmatches.tsx,.mjsmatches.mtsand.cjsmatches.cts.
How each import is classified
| Classification | Meaning | Example |
|---|---|---|
| Local file | Resolved to a file in your project | ./lib/db → src/lib/db.js |
| Built-in | A Node.js built-in module | fs, node:path |
| Package | A dependency listed in package.json | express, @scope/pkg/sub |
| Asset | A non-code file | ./styles.css, ./data.json |
| Unresolved | Couldn't be resolved, with a reason | a missing file, or a package not in package.json |
Each import edge also records whether it's dynamic (import()), type-only (import type), side-effect only (import "./polyfill") or a re-export, and exactly which names it brings in.
4. The graph
Everything is stored in a local SQLite database:
- Files with language, lines of code, a content hash, and flags for test files (
.test.,.spec.,__tests__/), entry points (frommainandmoduleinpackage.json) and syntax errors. - Symbols with kind, line range and export status.
- Edges between files, packages, built-ins and assets.
- Packages from
package.json, with versions. - Unresolved imports with their reasons.
Morph uses this graph as context when it converts files and answers questions.
5. Planning
The plan is computed from the file-to-file edges:
- Strongly connected components. Tarjan's algorithm groups files that import each other in a cycle into a single component. A cycle can only be typed as a whole, so it's never split.
- Topological order. Tarjan's algorithm emits a component only after every component it depends on, which gives a leaf-first order: files with no local imports first, your entry point last.
- Batches. Components are packed into batches of about ten files. Batch size is for pacing and review; the order underneath never changes.
Only JavaScript files go into batches. Existing TypeScript files are already typed and count toward the typed total.
6. Reading the plan
Plan ready. 38 files in 4 batches. Leaf modules first, so types flow upward through your imports.
| You see | It means |
|---|---|
| JS files | How many files will be converted |
| Batches | How many review sittings the migration takes |
| Import edges | How connected the project is |
| Batch names | The folders each batch covers, such as lib/ · utilities or api/ + middleware/ |
From here you can Start migration or Edit plan.
Re-scanning
Run Scan & Plan again any time your code changes significantly, for example after merging a big branch. Scanning is fast and always reflects the current files on disk.
Something unclear or out of date? Tell us.