bippy
Version:
hack into react internals
94 lines (73 loc) • 2.72 kB
text/typescript
import { Fiber } from "../types.js";
import { getDisplayName } from "../core.js";
import { getOwnerStack } from "./owner-stack.js";
import { getSourceFromSourceMap, getSourceMap } from "./symbolication.js";
import { StackFrame } from "./parse-stack.js";
const extractComponentNameFromSource = (
sourceContent: string,
lineNumber: number,
): string | null => {
const lines = sourceContent.split("\n");
const targetLineIndex = lineNumber - 1;
if (targetLineIndex < 0 || targetLineIndex >= lines.length) {
return null;
}
const startLine = Math.max(0, targetLineIndex - 5);
const endLine = Math.min(lines.length, targetLineIndex + 5);
const contextLines = lines.slice(startLine, endLine).join("\n");
const arrowFunctionPattern = /(?:^|export\s+)(?:const|let|var)\s+(\w+)\s*=/m;
const functionPattern = /(?:^|export\s+)function\s+(\w+)/m;
const classPattern = /(?:^|export\s+)class\s+(\w+)/m;
const arrowMatch = contextLines.match(arrowFunctionPattern);
if (arrowMatch?.[1]) {
return arrowMatch[1];
}
const functionMatch = contextLines.match(functionPattern);
if (functionMatch?.[1]) {
return functionMatch[1];
}
const classMatch = contextLines.match(classPattern);
if (classMatch?.[1]) {
return classMatch[1];
}
return null;
};
export const getDisplayNameFromSource = async (
fiber: Fiber,
cache = true,
fetchFn?: (url: string) => Promise<Response>,
): Promise<string | null> => {
const ownerStack = await getOwnerStack(fiber, cache, fetchFn);
const stackFrame = ownerStack.filter((stackFrame) => stackFrame.fileName)[0];
if (!stackFrame?.fileName) {
return getDisplayName(fiber.type);
}
const bundleSourceMap = await getSourceMap(stackFrame.fileName, cache, fetchFn);
if (!bundleSourceMap) {
return getDisplayName(fiber.type);
}
let source: StackFrame | null = null;
if (typeof stackFrame.lineNumber === "number" && typeof stackFrame.columnNumber === "number") {
source = getSourceFromSourceMap(
bundleSourceMap,
stackFrame.lineNumber,
stackFrame.columnNumber,
);
}
if (!source?.fileName || !source.lineNumber) {
return getDisplayName(fiber.type);
}
if (!bundleSourceMap.sourcesContent) {
return getDisplayName(fiber.type);
}
const sourceIndex = bundleSourceMap.sources.indexOf(source.fileName);
if (sourceIndex === -1 || !bundleSourceMap.sourcesContent[sourceIndex]) {
return getDisplayName(fiber.type);
}
const sourceContent = bundleSourceMap.sourcesContent[sourceIndex];
const extractedName = extractComponentNameFromSource(sourceContent, source.lineNumber);
if (extractedName) {
return extractedName;
}
return getDisplayName(fiber.type);
};