Initial pass at adding filter-by-type Flow types and support to renderer
Brian Vaughn committed
Apr 26, 2019 at 14:40 UTC
9db209ee64b6eb12cbfb9cae8c74027fb2317d1f
5 files changed
+93
-15
OVERVIEW.md
+1
-1
@@ -83,7 +83,7 @@ For example, adding a function component `<Foo>` with an id 2:
83
[
84
1, // add operation
85
2, // fiber id
86
- 2, // ElementTypeFunction
86
+ 1, // ElementTypeClass
87
1, // parent id
88
0, // owner id
89
3, // encoded display name size
src/backend/renderer.js
+61
-12
@@ -3,19 +3,27 @@
3
import { gte } from 'semver';
4
import {
5
ElementTypeClass,
6
- ElementTypeFunction,
6
ElementTypeContext,
7
ElementTypeEventComponent,
8
ElementTypeEventTarget,
9
+ ElementTypeFunction,
10
ElementTypeForwardRef,
11
- ElementTypeHost,
11
+ ElementTypeHostComponent,
12
ElementTypeMemo,
13
ElementTypeOtherOrUnknown,
14
ElementTypeProfiler,
15
ElementTypeRoot,
16
ElementTypeSuspense,
17
+ FilterByElementType,
18
+ FilterByName,
19
+ FilterByPath,
20
} from 'src/types';
18
-import { getDisplayName, utfEncodeString } from '../utils';
21
+import {
22
+ getDisplayName,
23
+ getSavedFilters,
24
+ getUID,
25
+ utfEncodeString,
26
+} from 'src/utils';
27
import { cleanForBridge, copyWithSet, setInObject } from './utils';
28
import {
29
__DEBUG__,
@@ -25,7 +33,6 @@ import {
33
TREE_OPERATION_REORDER_CHILDREN,
34
TREE_OPERATION_UPDATE_TREE_BASE_DURATION,
35
} from '../constants';
28
-import { getUID } from '../utils';
36
import { inspectHooksOfFiber } from './ReactDebugHooks';
37
38
import type {
@@ -43,6 +50,7 @@ import type {
50
ReactRenderer,
51
RendererInterface,
52
} from './types';
53
+import type { ElementType, Filter } from 'src/types';
54
import type { InspectedElement } from 'src/devtools/views/Components/types';
55
56
function getInternalReactConstants(version) {
@@ -260,22 +268,62 @@ export function attach(
268
}
269
};
270
271
+ const filterByElementTypeMap: Map<ElementType, boolean> = new Map();
272
+ const filterByNames: Set<RegExp> = new Set();
273
+ const filterByPaths: Set<RegExp> = new Set();
274
+
275
+ function updateFilters(filters: Array<Filter>): void {
276
+ filterByElementTypeMap.clear();
277
+ filterByNames.clear();
278
+ filterByPaths.clear();
279
+
280
+ filters.forEach(({ type, value }) => {
281
+ switch (type) {
282
+ case FilterByElementType:
283
+ filterByElementTypeMap.set(((value: any): ElementType), true);
284
+ break;
285
+ case FilterByName:
286
+ filterByNames.add(((value: any): RegExp));
287
+ break;
288
+ case FilterByPath:
289
+ filterByPaths.add(((value: any): RegExp));
290
+ break;
291
+ default:
292
+ console.error(`Unsupported filter type "${type}"`);
293
+ break;
294
+ }
295
+ });
296
+ }
297
+
298
+ // Initialize to the persisted values
299
+ updateFilters(getSavedFilters());
300
+
301
// NOTICE Keep in sync with getDataForFiber()
302
function shouldFilterFiber(fiber: Fiber): boolean {
303
const { tag } = fiber;
304
305
+ // TODO (filter) This does not yet support display name or path based filtering.
306
+
307
switch (tag) {
308
case ClassComponent:
269
- case FunctionComponent:
270
- case HostComponent:
309
case IncompleteClassComponent:
310
+ return filterByElementTypeMap.get(ElementTypeClass) === true;
311
+ case FunctionComponent:
312
+ return filterByElementTypeMap.get(ElementTypeFunction) === true;
313
case IndeterminateComponent:
314
+ return (
315
+ filterByElementTypeMap.get(ElementTypeClass) === true ||
316
+ filterByElementTypeMap.get(ElementTypeFunction) === true
317
+ );
318
case ForwardRef:
274
- case HostRoot:
319
+ return filterByElementTypeMap.get(ElementTypeForwardRef) === true;
320
case MemoComponent:
321
case SimpleMemoComponent:
277
- // TODO (filtering) Check custom filters
278
- return false;
322
+ return filterByElementTypeMap.get(ElementTypeMemo) === true;
323
+ case HostComponent:
324
+ return filterByElementTypeMap.get(ElementTypeHostComponent) === true;
325
+ case HostRoot:
326
+ return false; // We never support filtering roots
327
case DehydratedSuspenseComponent:
328
// TODO: ideally we would show dehydrated Suspense immediately.
329
// However, it has some special behavior (like disconnecting
@@ -302,13 +350,14 @@ export function attach(
350
case CONTEXT_PROVIDER_SYMBOL_STRING:
351
case CONTEXT_CONSUMER_NUMBER:
352
case CONTEXT_CONSUMER_SYMBOL_STRING:
353
+ return filterByElementTypeMap.get(ElementTypeContext) === true;
354
case SUSPENSE_NUMBER:
355
case SUSPENSE_SYMBOL_STRING:
356
case DEPRECATED_PLACEHOLDER_SYMBOL_STRING:
357
+ return filterByElementTypeMap.get(ElementTypeSuspense) === true;
358
case PROFILER_NUMBER:
359
case PROFILER_SYMBOL_STRING:
310
- // TODO (filtering) Check custom filters
311
- return false;
360
+ return filterByElementTypeMap.get(ElementTypeProfiler) === true;
361
default:
362
return false;
363
}
@@ -403,7 +452,7 @@ export function attach(
452
return {
453
displayName: type,
454
key,
406
- type: ElementTypeHost,
455
+ type: ElementTypeHostComponent,
456
};
457
case HostPortal:
458
case HostText:
src/constants.js
+2
@@ -5,6 +5,8 @@ export const TREE_OPERATION_REMOVE = 2;
5
export const TREE_OPERATION_REORDER_CHILDREN = 3;
6
export const TREE_OPERATION_UPDATE_TREE_BASE_DURATION = 4;
7
8
+export const LOCAL_STORAGE_FILTERS_KEY = 'React::DevTools::filters';
9
+
10
export const LOCAL_STORAGE_RELOAD_AND_PROFILE_KEY =
11
'React::DevTools::reloadAndProfile';
12
src/types.js
+15
-1
@@ -18,7 +18,7 @@ export const ElementTypeEventComponent = 3;
18
export const ElementTypeEventTarget = 4;
19
export const ElementTypeFunction = 5;
20
export const ElementTypeForwardRef = 6;
21
-export const ElementTypeHost = 7;
21
+export const ElementTypeHostComponent = 7;
22
export const ElementTypeMemo = 8;
23
export const ElementTypeOtherOrUnknown = 9;
24
export const ElementTypeProfiler = 10;
@@ -29,3 +29,17 @@ export const ElementTypeSuspense = 12;
29
// These types may be used to visually distinguish types,
30
// or to enable/disable certain functionality.
31
export type ElementType = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
32
+
33
+export const FilterByElementType = 1;
34
+export const FilterByName = 2;
35
+export const FilterByPath = 3;
36
+
37
+export type Filter =
38
+ | {|
39
+ type: 1,
40
+ value: ElementType,
41
+ |}
42
+ | {|
43
+ type: 2 | 3,
44
+ value: RegExp,
45
+ |};
src/utils.js
+14
-1
@@ -1,6 +1,10 @@
1
// @flow
2
3
-const LRU = require('lru-cache');
3
+import LRU from 'lru-cache';
4
+import { LOCAL_STORAGE_FILTERS_KEY } from './constants';
5
+import { ElementTypeHostComponent } from './types';
6
+
7
+import type { Filter } from './types';
8
9
const FB_MODULE_RE = /^(.*) \[from (.*)\]$/;
10
const cachedDisplayNames: WeakMap<Function, string> = new WeakMap();
@@ -76,3 +80,12 @@ export function utfEncodeString(string: string): Uint32Array {
80
function toCodePoint(string: string) {
81
return string.codePointAt(0);
82
}
83
+
84
+export function getSavedFilters(): Array<Filter> {
85
+ const filters = localStorage.getItem(LOCAL_STORAGE_FILTERS_KEY);
86
+ if (filters != null) {
87
+ return ((JSON.parse(filters): any): Array<Filter>);
88
+ } else {
89
+ return [{ type: 1, value: ElementTypeHostComponent }];
90
+ }
91
+}