[validation] More detailed error diagnostics for validatePreserveExistingMemo
--- This should make it easier to grep through error diagnostics to understand state of the codebase: - no matching dependences -> likely that source is ignoring eslint failures - differences in ref.current access -> non-backwards compatible refs - subpath -> should be fixable in the compiler (unless source is ignore eslint failures)
Mofei Zhang committed
Mar 20, 2024 at 16:05 UTC
4daa4eceb7577918fb07eea8b03dcd70cfa84e81
13 files changed
+70
-20
compiler/packages/babel-plugin-react-forget/src/Validation/ValidatePreservedManualMemoization.ts
+56
-6
@@ -102,10 +102,41 @@ function prettyPrintScopeDependency(val: ReactiveScopeDependency): string {
102
return `${rootStr}${val.path.length > 0 ? "." : ""}${val.path.join(".")}`;
103
}
104
105
+enum CompareDependencyResult {
106
+ Ok = 0,
107
+ RootDifference = 1,
108
+ PathDifference = 2,
109
+ Subpath = 3,
110
+ RefAccessDifference = 4,
111
+}
112
+
113
+function merge(
114
+ a: CompareDependencyResult,
115
+ b: CompareDependencyResult
116
+): CompareDependencyResult {
117
+ return Math.max(a, b);
118
+}
119
+
120
+function getCompareDependencyResultDescription(
121
+ result: CompareDependencyResult
122
+): string {
123
+ switch (result) {
124
+ case CompareDependencyResult.Ok:
125
+ return "dependencies equal";
126
+ case CompareDependencyResult.RootDifference:
127
+ case CompareDependencyResult.PathDifference:
128
+ return "inferred different dependency than source";
129
+ case CompareDependencyResult.RefAccessDifference:
130
+ return "differences in ref.current access";
131
+ case CompareDependencyResult.Subpath:
132
+ return "inferred less specific property than source";
133
+ }
134
+}
135
+
136
function compareDeps(
137
inferred: ManualMemoDependency,
138
source: ManualMemoDependency
108
-): boolean {
139
+): CompareDependencyResult {
140
const rootsEqual =
141
(inferred.root.kind === "Global" &&
142
source.root.kind === "Global" &&
@@ -114,7 +145,7 @@ function compareDeps(
145
source.root.kind === "NamedLocal" &&
146
inferred.root.value.identifier.id === source.root.value.identifier.id);
147
if (!rootsEqual) {
117
- return false;
148
+ return CompareDependencyResult.RootDifference;
149
}
150
151
let isSubpath = true;
@@ -131,9 +162,20 @@ function compareDeps(
162
(inferred.path.length >= source.path.length &&
163
!inferred.path.includes("current")))
164
) {
134
- return true;
165
+ return CompareDependencyResult.Ok;
166
} else {
136
- return false;
167
+ if (isSubpath) {
168
+ if (
169
+ source.path.includes("current") ||
170
+ inferred.path.includes("current")
171
+ ) {
172
+ return CompareDependencyResult.RefAccessDifference;
173
+ } else {
174
+ return CompareDependencyResult.Subpath;
175
+ }
176
+ } else {
177
+ return CompareDependencyResult.PathDifference;
178
+ }
179
}
180
}
181
@@ -197,9 +239,13 @@ function validateInferredDep(
239
return;
240
}
241
}
242
+ let errorDiagnostic: CompareDependencyResult | null = null;
243
for (const originalDep of validDepsInMemoBlock) {
201
- if (compareDeps(normalizedDep, originalDep)) {
244
+ const compareResult = compareDeps(normalizedDep, originalDep);
245
+ if (compareResult === CompareDependencyResult.Ok) {
246
return;
247
+ } else {
248
+ errorDiagnostic = merge(errorDiagnostic ?? compareResult, compareResult);
249
}
250
}
251
errorState.push({
@@ -210,7 +256,11 @@ function validateInferredDep(
256
dep
257
)}\`, but the source dependencies were [${validDepsInMemoBlock
258
.map((dep) => printManualMemoDependency(dep, true))
213
- .join(", ")}]`,
259
+ .join(", ")}]. Detail: ${
260
+ errorDiagnostic
261
+ ? getCompareDependencyResultDescription(errorDiagnostic)
262
+ : "none"
263
+ }`,
264
loc: GeneratedSource,
265
suggestions: null,
266
});
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-invalid-useCallback-read-maybeRef.expect.md
+1
-1
@@ -17,7 +17,7 @@ function useHook(maybeRef) {
17
## Error
18
19
```
20
-[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `maybeRef.current`, but the source dependencies were [maybeRef]
20
+[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `maybeRef.current`, but the source dependencies were [maybeRef]. Detail: differences in ref.current access
21
```
22
23
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-invalid-useMemo-read-maybeRef.expect.md
+1
-1
@@ -17,7 +17,7 @@ function useHook(maybeRef, shouldRead) {
17
## Error
18
19
```
20
-[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `maybeRef.current`, but the source dependencies were [shouldRead, maybeRef]
20
+[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `maybeRef.current`, but the source dependencies were [shouldRead, maybeRef]. Detail: differences in ref.current access
21
```
22
23
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-aliased-var.expect.md
+1
-1
@@ -19,7 +19,7 @@ function useHook(x) {
19
## Error
20
21
```
22
-[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `aliasedX`, but the source dependencies were [x, aliasedProp]
22
+[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `aliasedX`, but the source dependencies were [x, aliasedProp]. Detail: inferred different dependency than source
23
```
24
25
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-conditional-access-noAlloc.expect.md
+1
-1
@@ -25,7 +25,7 @@ export const FIXTURE_ENTRYPOINT = {
25
## Error
26
27
```
28
-[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propB`, but the source dependencies were [propA, propB.x.y]
28
+[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propB`, but the source dependencies were [propA, propB.x.y]. Detail: inferred less specific property than source
29
```
30
31
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-infer-less-specific-conditional-access.expect.md
+1
-1
@@ -24,7 +24,7 @@ function Component({ propA, propB }) {
24
## Error
25
26
```
27
-[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.a, propB.x.y]
27
+[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.a, propB.x.y]. Detail: inferred less specific property than source
28
```
29
30
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-property-call-dep.expect.md
+1
-1
@@ -17,7 +17,7 @@ function Component({ propA }) {
17
## Error
18
19
```
20
-[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.x]
20
+[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.x]. Detail: inferred less specific property than source
21
```
22
23
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-aliased-var.expect.md
+1
-1
@@ -19,7 +19,7 @@ function useHook(x) {
19
## Error
20
21
```
22
-[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `x`, but the source dependencies were [aliasedX, aliasedProp]
22
+[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `x`, but the source dependencies were [aliasedX, aliasedProp]. Detail: inferred different dependency than source
23
```
24
25
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-infer-less-specific-conditional-access.expect.md
+2
-2
@@ -24,9 +24,9 @@ function Component({ propA, propB }) {
24
## Error
25
26
```
27
-[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.a, propB.x.y]
27
+[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.a, propB.x.y]. Detail: inferred less specific property than source
28
29
-[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propB`, but the source dependencies were [propA.a, propB.x.y]
29
+[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propB`, but the source dependencies were [propA.a, propB.x.y]. Detail: inferred less specific property than source
30
```
31
32
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-infer-less-specific-conditional-value-block.expect.md
+2
-2
@@ -24,9 +24,9 @@ function Component({ propA, propB }) {
24
## Error
25
26
```
27
-[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.a, propB.x.y]
27
+[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.a, propB.x.y]. Detail: inferred less specific property than source
28
29
-[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propB`, but the source dependencies were [propA.a, propB.x.y]
29
+[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propB`, but the source dependencies were [propA.a, propB.x.y]. Detail: inferred less specific property than source
30
```
31
32
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-property-call-chained-object.expect.md
+1
-1
@@ -19,7 +19,7 @@ function Component({ propA }) {
19
## Error
20
21
```
22
-[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.x]
22
+[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.x]. Detail: inferred less specific property than source
23
```
24
25
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-property-call-dep.expect.md
+1
-1
@@ -17,7 +17,7 @@ function Component({ propA }) {
17
## Error
18
19
```
20
-[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.x]
20
+[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `propA`, but the source dependencies were [propA.x]. Detail: inferred less specific property than source
21
```
22
23
\ No newline at end of file
compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-unrelated-mutation-in-depslist.expect.md
+1
-1
@@ -30,7 +30,7 @@ function useFoo(input1) {
30
## Error
31
32
```
33
-[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `input1`, but the source dependencies were [y]
33
+[ReactForget] Todo: Could not preserve manual memoization because an inferred dependency does not match the dependency list in source. The inferred dependency was `input1`, but the source dependencies were [y]. Detail: inferred different dependency than source
34
```
35
36
\ No newline at end of file