@samitouri / QOS-React-2 / commits / ab390c65ee

ReactDebugHooks optionally includes fileName, and line/column numbers (#21781)

Brian Vaughn committed Jul 1, 2021 at 13:08 UTC ab390c65eefb7f395468c18ee2b059bf35c7cd03
1 file changed +56 -9
packages/react-debug-tools/src/ReactDebugHooks.js
+56 -9
@@ -332,12 +332,20 @@ const Dispatcher: DispatcherType = {
332
333 // Inspect
334
335 +export type HookSource = {
336 + lineNumber: number | null,
337 + columnNumber: number | null,
338 + fileName: string | null,
339 + functionName: string | null,
340 +};
341 +
342 export type HooksNode = {
343 id: number | null,
344 isStateEditable: boolean,
345 name: string,
346 value: mixed,
347 subHooks: Array<HooksNode>,
348 + hookSource?: HookSource,
349 ...
350 };
351 export type HooksTree = Array<HooksNode>;
@@ -473,7 +481,11 @@ function parseCustomHookName(functionName: void | string): string {
481 return functionName.substr(startIndex);
482 }
483
476 -function buildTree(rootStack, readHookLog): HooksTree {
484 +function buildTree(
485 + rootStack,
486 + readHookLog,
487 + includeHooksSource: boolean,
488 +): HooksTree {
489 const rootChildren = [];
490 let prevStack = null;
491 let levelChildren = rootChildren;
@@ -508,13 +520,25 @@ function buildTree(rootStack, readHookLog): HooksTree {
520 // to the tree.
521 for (let j = stack.length - commonSteps - 1; j >= 1; j--) {
522 const children = [];
511 - levelChildren.push({
523 + const stackFrame = stack[j];
524 + const levelChild: HooksNode = {
525 id: null,
526 isStateEditable: false,
527 name: parseCustomHookName(stack[j - 1].functionName),
528 value: undefined,
529 subHooks: children,
517 - });
530 + };
531 +
532 + if (includeHooksSource) {
533 + levelChild.hookSource = {
534 + lineNumber: stackFrame.lineNumber,
535 + columnNumber: stackFrame.columnNumber,
536 + functionName: stackFrame.functionName,
537 + fileName: stackFrame.fileName,
538 + };
539 + }
540 +
541 + levelChildren.push(levelChild);
542 stackOfChildren.push(levelChildren);
543 levelChildren = children;
544 }
@@ -531,14 +555,33 @@ function buildTree(rootStack, readHookLog): HooksTree {
555
556 // For the time being, only State and Reducer hooks support runtime overrides.
557 const isStateEditable = primitive === 'Reducer' || primitive === 'State';
534 -
535 - levelChildren.push({
558 + const levelChild: HooksNode = {
559 id,
560 isStateEditable,
561 name: primitive,
562 value: hook.value,
563 subHooks: [],
541 - });
564 + };
565 +
566 + if (includeHooksSource) {
567 + const hookSource: HookSource = {
568 + lineNumber: null,
569 + functionName: null,
570 + fileName: null,
571 + columnNumber: null,
572 + };
573 + if (stack && stack.length >= 1) {
574 + const stackFrame = stack[0];
575 + hookSource.lineNumber = stackFrame.lineNumber;
576 + hookSource.functionName = stackFrame.functionName;
577 + hookSource.fileName = stackFrame.fileName;
578 + hookSource.columnNumber = stackFrame.columnNumber;
579 + }
580 +
581 + levelChild.hookSource = hookSource;
582 + }
583 +
584 + levelChildren.push(levelChild);
585 }
586
587 // Associate custom hook values (useDebugValue() hook entries) with the correct hooks.
@@ -585,6 +628,7 @@ export function inspectHooks<Props>(
628 renderFunction: Props => React$Node,
629 props: Props,
630 currentDispatcher: ?CurrentDispatcherRef,
631 + includeHooksSource?: boolean = false,
632 ): HooksTree {
633 // DevTools will pass the current renderer's injected dispatcher.
634 // Other apps might compile debug hooks as part of their app though.
@@ -605,7 +649,7 @@ export function inspectHooks<Props>(
649 currentDispatcher.current = previousDispatcher;
650 }
651 const rootStack = ErrorStackParser.parse(ancestorStackError);
608 - return buildTree(rootStack, readHookLog);
652 + return buildTree(rootStack, readHookLog, includeHooksSource);
653 }
654
655 function setupContexts(contextMap: Map<ReactContext<any>, any>, fiber: Fiber) {
@@ -634,6 +678,7 @@ function inspectHooksOfForwardRef<Props, Ref>(
678 props: Props,
679 ref: Ref,
680 currentDispatcher: CurrentDispatcherRef,
681 + includeHooksSource: boolean,
682 ): HooksTree {
683 const previousDispatcher = currentDispatcher.current;
684 let readHookLog;
@@ -648,7 +693,7 @@ function inspectHooksOfForwardRef<Props, Ref>(
693 currentDispatcher.current = previousDispatcher;
694 }
695 const rootStack = ErrorStackParser.parse(ancestorStackError);
651 - return buildTree(rootStack, readHookLog);
696 + return buildTree(rootStack, readHookLog, includeHooksSource);
697 }
698
699 function resolveDefaultProps(Component, baseProps) {
@@ -669,6 +714,7 @@ function resolveDefaultProps(Component, baseProps) {
714 export function inspectHooksOfFiber(
715 fiber: Fiber,
716 currentDispatcher: ?CurrentDispatcherRef,
717 + includeHooksSource?: boolean = false,
718 ) {
719 // DevTools will pass the current renderer's injected dispatcher.
720 // Other apps might compile debug hooks as part of their app though.
@@ -706,9 +752,10 @@ export function inspectHooksOfFiber(
752 props,
753 fiber.ref,
754 currentDispatcher,
755 + includeHooksSource,
756 );
757 }
711 - return inspectHooks(type, props, currentDispatcher);
758 + return inspectHooks(type, props, currentDispatcher, includeHooksSource);
759 } finally {
760 currentHook = null;
761 restoreContexts(contextMap);