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);