@samitouri / QOS-React-2 / commits / 9db209ee64

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 +}