diff --git a/packages/metro/src/DeltaBundler/__tests__/traverseDependencies-test.js b/packages/metro/src/DeltaBundler/__tests__/traverseDependencies-test.js index cb648562..4c843059 100644 --- a/packages/metro/src/DeltaBundler/__tests__/traverseDependencies-test.js +++ b/packages/metro/src/DeltaBundler/__tests__/traverseDependencies-test.js @@ -178,6 +178,30 @@ describe('edge cases', () => { }); }); + it('should not try to remove wrong dependencies when renaming files', async () => { + const edges = new Map(); + await initialTraverseDependencies('/bundle', dependencyGraph, {}, edges); + + // Rename /foo to /foo-renamed, but keeping all its dependencies. + const moduleFooRenamed = createModule({ + path: '/foo-renamed', + name: 'foo-renamed', + }); + mockedDependencyTree.set(entryModule.path, [moduleFooRenamed]); + mockedDependencyTree.set(moduleFooRenamed.path, [moduleBar, moduleBaz]); + mockedDependencies.add(moduleFooRenamed); + mockedDependencies.delete(moduleFoo); + + // Call traverseDependencies with /foo, /qux and /baz, simulating that the + // user has modified the 3 files. + expect( + await traverseDependencies(['/bundle'], dependencyGraph, {}, edges), + ).toEqual({ + added: new Set(['/foo-renamed']), + deleted: new Set(['/foo']), + }); + }); + it('modify a file and delete it afterwards', async () => { const edges = new Map(); await initialTraverseDependencies('/bundle', dependencyGraph, {}, edges); diff --git a/packages/metro/src/DeltaBundler/traverseDependencies.js b/packages/metro/src/DeltaBundler/traverseDependencies.js index 2a973a3e..f134ab3e 100644 --- a/packages/metro/src/DeltaBundler/traverseDependencies.js +++ b/packages/metro/src/DeltaBundler/traverseDependencies.js @@ -68,7 +68,15 @@ async function traverseDependencies( added.add(path); } for (const path of change.deleted) { - deleted.add(path); + // If a path has been marked both as added and deleted, it means that this + // path is a dependency of a renamed file (or that dependency has been + // removed from one path but added back in a different path). In this case + // the addition and deletion "get cancelled". + if (added.has(path)) { + added.delete(path); + } else { + deleted.add(path); + } } }