- index/tsconfig: JSONC sanitize (comments, trailing commas), baseUrl +
star/exact path keys, first candidate only, longest-prefix wins; invalid
or missing tsconfig silently means no aliases
- resolution pass: '.'-prefixed specifiers resolve relatively as before,
bare ones go through the alias table and join the importer graph
- planner: remap keeps the alias shape while the moved file stays inside
the mapped tree (morphological, since destinations do not exist yet),
exact keys keep meaning only while still resolving to the target;
otherwise the previous relative rewrite applies unchanged
- resolve_base extracted from resolve_module (shared extension/index
guessing); MODULE_EXTS is the exact inverse for remapping
- e2e: @utils/str.ts -> @utils/text.ts inside alias, -> ./core/text.ts
when leaving it, @cfg falls back to ./settings; check passes on aliases
- binds names via tree-sitter (default, namespace, named + alias, type-only),
keeps a statement when ANY bound name occurs outside it (word scan over
comments/strings included): under-delete is the safe direction, mirroring
the Java rule's asymmetry
- ESM caveat encoded in the policy: mixed live/dead statements are not
touched — removing a specifier would still drop the module's side effects
- side-effect imports and 'export .. from' re-exports are never candidates
- parser/ts became a folder (mod/extract/unused_imports) to keep the
4-entries-per-module rule; word_occurs shared via crate::parser
- java/rules/unused_imports now reuses the shared word scanner (DRY)