Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix graph delta bugs when a dependency is added+modified+removed / re…
…moved+modified+added within a traversal Summary: I came across this edge case while working on module diffing. Typically: 1. DeltaCalculator aggregates relevant file changes between requests for a delta (e.g., via HMR). (If no client is connected, these changes may accrue over a period of time) 2. When `getDelta` is called, this list of paths is provided to `Graph.traverseDependencies`, which determines the actual graph delta, performing any necessary transformation and dependency traversal. 3. `traverseDependencies` works through these paths sequentially, marking modules as modified and deeply adding/removing dependencies as it goes. It ignores any path that doesn't correspond to a module in the graph. Previously, a path was added to `delta.modified` if only if it was given in `paths` *and* existed in the graph at the time we came to traverse it as part of the `traverseDependencies` sequence. ## Error cases This led to issues in a couple of cases: ## Module modified while temporarily NOT part of the graph For an existing graph with edges `A->B` and `A->C`. 1. The dependency `A->C` is removed, freeing `C` from the graph and adding it to `delta.deleted`. `A` is marked modified. 2. `C` is modified, but traversal skips it because it's not in the graph. 3. The dependency `B->C` is added. `C` is removed from `delta.deleted` and processed. `B` is marked modified. Result: `{ added: [], modified: [A, B], deleted: [] }` - `C`'s modification is missed. ### Module modified while temporarily part of the graph For an existing graph with edges `A->B`. 1. The dependency `B->C` is added, processing `C` as a new dependency and adding it to `delta.added` 2. `C` is modified, traversal marks it as modified because it's now part of the graph. 3. The dependency `A->B` is removed. `C` is removed from `delta.added` but remains in `delta.modified`. `A` is marked modified, `B` marked deleted. Result: `C`'s path remains in `delta.modified` but not `added` or `deleted`, but it's not present in the graph at the end of the traversal. `traverseDependencies` throws, client sees a redbox from `nullthrows` on: ``` modified.set(pathOfC, nullthrows(this.dependencies.get(pathOfC))) ``` ## This diff - Mark modules as potentially modified when they are **processed**, *either directly or transitively*. - Filter modifications to only those from the given `paths` that were present in the graph *before traversal started*. [Building this list feeds nicely into subsequent work on diffing modules.] Changelog: ``` **[Fix]**: Fix crash on a module added+modified+removed between updates. **[Fix]**: Fix missed modification on module removed+modified+added between updates. ``` Reviewed By: motiz88 Differential Revision: D45691691 fbshipit-source-id: 4f246582311063650f26678006b6089c778014f4
- Loading branch information