react-render-detective 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/babel.cjs +2 -2
- package/dist/babel.js +1 -1
- package/dist/{chunk-6YPJQ7M5.cjs → chunk-DZ3BZ654.cjs} +88 -4
- package/dist/chunk-DZ3BZ654.cjs.map +1 -0
- package/dist/chunk-H5RG2EPP.cjs +75 -0
- package/dist/chunk-H5RG2EPP.cjs.map +1 -0
- package/dist/{chunk-LSIXHWQD.js → chunk-HOTY7J3X.js} +14 -4
- package/dist/chunk-HOTY7J3X.js.map +1 -0
- package/dist/{chunk-QQ4VARSD.cjs → chunk-JD4IJ4MN.cjs} +14 -4
- package/dist/chunk-JD4IJ4MN.cjs.map +1 -0
- package/dist/chunk-LILK23YH.js +71 -0
- package/dist/chunk-LILK23YH.js.map +1 -0
- package/dist/{chunk-PSCFSJ65.js → chunk-MCIQMYNR.js} +12 -5
- package/dist/chunk-MCIQMYNR.js.map +1 -0
- package/dist/{chunk-BPNLNIHU.cjs → chunk-PHYYA67T.cjs} +12 -5
- package/dist/chunk-PHYYA67T.cjs.map +1 -0
- package/dist/{chunk-MSISKPST.js → chunk-QOGTEVBP.js} +88 -4
- package/dist/chunk-QOGTEVBP.js.map +1 -0
- package/dist/core.cjs +18 -18
- package/dist/core.d.cts +38 -2
- package/dist/core.d.ts +38 -2
- package/dist/core.js +1 -1
- package/dist/index.cjs +354 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +172 -4
- package/dist/index.d.ts +172 -4
- package/dist/index.js +316 -6
- package/dist/index.js.map +1 -1
- package/dist/overlay.cjs +6 -6
- package/dist/overlay.cjs.map +1 -1
- package/dist/overlay.js +4 -4
- package/dist/overlay.js.map +1 -1
- package/dist/testing.cjs +20 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +62 -0
- package/dist/testing.d.ts +62 -0
- package/dist/testing.js +3 -0
- package/dist/testing.js.map +1 -0
- package/dist/{types-BWVaQPHb.d.cts → types-gl13xwmN.d.cts} +5 -0
- package/dist/{types-BWVaQPHb.d.ts → types-gl13xwmN.d.ts} +5 -0
- package/dist/vite.cjs +9 -6
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.js +8 -5
- package/dist/vite.js.map +1 -1
- package/package.json +6 -1
- package/dist/chunk-6YPJQ7M5.cjs.map +0 -1
- package/dist/chunk-BPNLNIHU.cjs.map +0 -1
- package/dist/chunk-LSIXHWQD.js.map +0 -1
- package/dist/chunk-MSISKPST.js.map +0 -1
- package/dist/chunk-PSCFSJ65.js.map +0 -1
- package/dist/chunk-QQ4VARSD.cjs.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/console/reporter.ts","../src/react/ancestry.ts","../src/react/instrument.tsx","../src/react/withRenderDetective.tsx","../src/react/RenderDetective.tsx","../src/react/hooks.ts","../src/index.ts"],"names":["jsx","useContext","useState","componentName"],"mappings":"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","file":"index.js","sourcesContent":["import { formatInspected } from \"../core/inspect.js\";\nimport type { Detective } from \"../core/store.js\";\nimport type { PropChange, RenderEvent } from \"../core/types.js\";\n\nconst ICON: Record<string, string> = {\n normal: \"·\",\n monitor: \"•\",\n slow: \"▲\",\n \"very-slow\": \"▲▲\",\n critical: \"■\",\n};\n\n/** Attaches console output. Returns an unsubscribe so init() stays idempotent. */\nexport function attachConsoleReporter(detective: Detective): () => void {\n return detective.subscribe((event) => {\n const mode = detective.config.mode;\n if (mode === \"silent\") return;\n try {\n if (mode === \"verbose\") printVerbose(event);\n else printConcise(event, detective.config.slowRenderThreshold);\n } catch {\n /* ignore */\n }\n });\n}\n\nfunction printConcise(event: RenderEvent, slowThreshold: number): void {\n const { diagnosis, timings, component } = event;\n const changed = event.changedProps.map((c) => c.key).join(\", \");\n const parts = [\n `[RRD] ${component.name} #${event.renderNumber}`,\n `Reason: ${label(event)}`,\n changed ? `Changed: ${changed}` : undefined,\n timings.subtreeDuration > 0 ? `Duration: ${timings.selfDuration.toFixed(1)}ms` : undefined,\n ].filter(Boolean);\n\n const line = `${ICON[diagnosis.severity] ?? \"·\"} ${parts.join(\" \")}`;\n const slow = timings.selfDuration >= slowThreshold;\n if (slow) console.warn(line);\n else console.log(line);\n}\n\nfunction printVerbose(event: RenderEvent): void {\n const { diagnosis, timings } = event;\n const header = `[RRD] ${event.component.name} #${event.renderNumber} — ${diagnosis.summary}`;\n\n const group = diagnosis.severity === \"normal\" ? console.groupCollapsed : console.group;\n group.call(console, header);\n try {\n console.log(`Cause: ${label(event)} (confidence: ${diagnosis.confidence})`);\n if (event.component.source) console.log(`Source: ${event.component.source}`);\n if (event.parent) {\n console.log(\n `Parent: ${event.parent.name}${event.parent.source ? ` (${event.parent.source})` : \"\"}` +\n `${event.parentRendered ? \" — re-rendered in this commit\" : \" — did not re-render\"}`,\n );\n }\n console.log(\n `Cost: self ${timings.selfDuration.toFixed(1)}ms · subtree ${timings.subtreeDuration.toFixed(1)}ms` +\n (timings.accountedDescendantDuration > 0\n ? ` (${timings.accountedDescendantDuration.toFixed(1)}ms in instrumented children)`\n : \"\"),\n );\n\n if (event.changedProps.length > 0) {\n console.groupCollapsed(`Props changed (${event.changedProps.length})`);\n for (const c of event.changedProps) console.log(propLine(c));\n console.groupEnd();\n }\n if (event.unchangedProps.length > 0) {\n console.log(`Props same: ${event.unchangedProps.join(\", \")}`);\n }\n if (event.trackedState.length > 0) {\n console.log(\n `State: ${event.trackedState\n .map((s) => `${s.name}: ${formatInspected(s.previous)} → ${formatInspected(s.current)}`)\n .join(\", \")}`,\n );\n }\n if (event.contextChanges.length > 0) {\n console.log(`Context: ${event.contextChanges.map((c) => c.contextName).join(\", \")} changed in this commit`);\n }\n\n console.groupCollapsed(\"Evidence\");\n for (const line of diagnosis.evidence) console.log(`• ${line}`);\n console.groupEnd();\n\n if (diagnosis.suggestion) console.log(`Next step: ${diagnosis.suggestion}`);\n if (diagnosis.potentiallyAvoidable) console.log(\"Flag: potentially avoidable render\");\n } finally {\n console.groupEnd();\n }\n}\n\nfunction propLine(c: PropChange): string {\n const head = `${c.key} (${c.valueType}) — ${describeKind(c)}`;\n if (c.kind === \"added\") return `${head}: ${formatInspected(c.current)}`;\n if (c.kind === \"removed\") return `${head}: was ${formatInspected(c.previous)}`;\n return `${head}\\n previous: ${formatInspected(c.previous)}\\n current: ${formatInspected(c.current)}`;\n}\n\nfunction describeKind(c: PropChange): string {\n switch (c.kind) {\n case \"added\":\n return \"added\";\n case \"removed\":\n return \"removed\";\n case \"value\":\n return \"value changed\";\n case \"reference\":\n if (c.valueType === \"function\") return c.sourceEqual ? \"new function, identical source\" : \"new function reference\";\n return c.shallowEqual === true ? \"reference changed, contents identical\" : \"reference changed\";\n }\n}\n\nfunction label(event: RenderEvent): string {\n switch (event.diagnosis.reason) {\n case \"mount\":\n return \"mount\";\n case \"props\":\n return event.changedProps.every((c) => c.kind === \"reference\") ? \"prop changed (reference only)\" : \"prop changed\";\n case \"parent\":\n return \"parent rendered\";\n case \"context\":\n return \"context update\";\n case \"state\":\n return \"state changed\";\n case \"state-or-external\":\n return \"state or external store\";\n case \"unknown\":\n return \"undetermined\";\n }\n}\n","import { createContext } from \"react\";\nimport type { NodeRecord } from \"../core/store.js\";\n\n/**\n * Carries the nearest instrumented ancestor down the tree.\n *\n * The value is the node object, created once per mounted instance and **never\n * replaced**. That is deliberate: a context value that changed per render would\n * force every instrumented descendant to re-render, defeating `React.memo` and\n * changing the behaviour of the very app we are measuring.\n */\nexport const AncestryContext = createContext<NodeRecord | undefined>(undefined);\nAncestryContext.displayName = \"RenderDetectiveAncestry\";\n","import { Profiler, useCallback, useContext, useLayoutEffect, useState } from \"react\";\nimport type { ProfilerOnRenderCallback, ReactNode } from \"react\";\nimport { getDetective } from \"../core/store.js\";\nimport type { NodeRecord } from \"../core/store.js\";\nimport type { RenderPhase } from \"../core/types.js\";\nimport { AncestryContext } from \"./ancestry.js\";\n\nexport interface TrackOptions {\n /** Overrides the inferred component name. Required for anonymous components. */\n name?: string;\n /**\n * `path/to/File.tsx:12:2`. Supplied automatically by the build plugin; there\n * is no runtime way to obtain it.\n */\n source?: string;\n}\n\n/**\n * Registers the current component, records this render attempt, and returns the\n * node plus a Profiler callback. All of it is a no-op when disabled.\n */\nexport function useInstrumentedNode(\n name: string,\n props: Record<string, unknown>,\n source?: string,\n): { node: NodeRecord | undefined; onRender: ProfilerOnRenderCallback } {\n const detective = getDetective();\n const parent = useContext(AncestryContext);\n\n // The active/inactive decision is frozen per instance so the element tree\n // shape never changes underneath a mounted component.\n const [node] = useState<NodeRecord | undefined>(() =>\n detective.enabled ? detective.createNode(name, parent, source) : undefined,\n );\n\n useLayoutEffect(() => {\n if (!node) return;\n detective.attach(node);\n return () => detective.detach(node);\n }, [detective, node]);\n\n if (node) {\n try {\n detective.recordAttempt(node, props);\n } catch {\n /* never break the app being debugged (§46) */\n }\n }\n\n const onRender = useCallback<ProfilerOnRenderCallback>(\n (_id, phase, actualDuration, baseDuration, startTime, commitTime) => {\n if (!node) return;\n try {\n detective.recordCommit(node, {\n phase: phase as RenderPhase,\n subtreeDuration: actualDuration,\n baseDuration,\n startTime,\n commitTime,\n });\n } catch {\n /* ignore */\n }\n },\n [detective, node],\n );\n\n return { node, onRender };\n}\n\nexport function renderInstrumented(\n node: NodeRecord | undefined,\n onRender: ProfilerOnRenderCallback,\n children: ReactNode,\n): ReactNode {\n if (!node) return children;\n return (\n <Profiler id={node.id} onRender={onRender}>\n <AncestryContext.Provider value={node}>{children}</AncestryContext.Provider>\n </Profiler>\n );\n}\n\nexport function componentName(component: unknown, fallback = \"Anonymous\"): string {\n const c = component as { displayName?: string; name?: string; type?: unknown } | null;\n if (!c) return fallback;\n if (typeof c.displayName === \"string\" && c.displayName) return c.displayName;\n if (typeof c.name === \"string\" && c.name) return c.name;\n // React.memo / forwardRef wrappers keep the real component on `.type`.\n if (c.type) return componentName(c.type, fallback);\n return fallback;\n}\n","import type { ComponentType } from \"react\";\n\n/** Marks a component as one of ours, so it is never wrapped twice. */\nconst IS_WRAPPER = Symbol.for(\"react-render-detective.wrapper\");\nimport { componentName, renderInstrumented, useInstrumentedNode } from \"./instrument.js\";\nimport type { TrackOptions } from \"./instrument.js\";\n\n/**\n * Wraps a component with full instrumentation: render counting, prop diffing,\n * parent attribution and Profiler timings.\n *\n * This is the most accurate integration mode — the wrapper's render function\n * runs exactly when the wrapped component re-renders, and it receives the same\n * props, so every diagnosis has first-hand evidence.\n *\n * Ref note: on React 19 `ref` is an ordinary prop and passes through the spread.\n * On React 18 and below, wrap with `forwardRef` yourself if the component needs\n * a ref.\n */\nexport function withRenderDetective<P extends object>(\n Component: ComponentType<P>,\n options: TrackOptions = {},\n): ComponentType<P> {\n /*\n * Wrapping a wrapper would make it render itself. That is unreachable through\n * careful hand-wrapping but trivially reachable once a build plugin is\n * wrapping everything, and the failure mode is a stack overflow before first\n * paint — so return the existing wrapper instead.\n */\n if ((Component as { [IS_WRAPPER]?: boolean })[IS_WRAPPER]) return Component;\n\n const name = options.name ?? componentName(Component);\n\n function RenderDetected(props: P) {\n const { node, onRender } = useInstrumentedNode(name, props as Record<string, unknown>, options.source);\n return renderInstrumented(node, onRender, <Component {...props} />);\n }\n\n RenderDetected.displayName = `RenderDetective(${name})`;\n (RenderDetected as { [IS_WRAPPER]?: boolean })[IS_WRAPPER] = true;\n return RenderDetected;\n}\n","import type { ReactNode } from \"react\";\nimport { renderInstrumented, useInstrumentedNode } from \"./instrument.js\";\n\nexport interface RenderDetectiveProps {\n name: string;\n children: ReactNode;\n}\n\n/**\n * Zero-refactor integration: drop it around a subtree.\n *\n * <RenderDetective name=\"UserProfile\"><UserProfile /></RenderDetective>\n *\n * Accuracy note: this boundary only sees the `children` **element**, not the\n * wrapped component's props. It therefore reports timings, parent propagation\n * and children-element churn accurately, but it cannot attribute a render to an\n * individual prop. Use `withRenderDetective` when you want per-prop diagnosis.\n */\nexport function RenderDetective({ name, children }: RenderDetectiveProps): ReactNode {\n const { node, onRender } = useInstrumentedNode(name, { children });\n return renderInstrumented(node, onRender, children);\n}\n","import * as React from \"react\";\nimport { useContext, useEffect, useRef, useState } from \"react\";\nimport type { Dispatch, SetStateAction } from \"react\";\nimport { getDetective } from \"../core/store.js\";\nimport { inspect } from \"../core/inspect.js\";\nimport { diffProps, shallowEqual } from \"../core/compare.js\";\nimport type { RenderEvent } from \"../core/types.js\";\nimport { AncestryContext } from \"./ancestry.js\";\n\n/**\n * In-component diagnostics without wrapping.\n *\n * Limitation, by design: a hook cannot install a `<Profiler>` around its own\n * component, so **no duration is available in this mode** — timings are\n * reported as 0. Everything else (render count, prop diffing, parent\n * attribution) is as accurate as the HOC.\n */\nexport function useRenderDiagnostics(name: string, props?: Record<string, unknown>): RenderEvent | undefined {\n const detective = getDetective();\n const parent = useContext(AncestryContext);\n const [node] = useState(() => {\n if (!detective.enabled) return undefined;\n const created = detective.createNode(name, parent);\n if (created) detective.hookModeNodes.add(created);\n return created;\n });\n const last = useRef<RenderEvent | undefined>(undefined);\n\n useEffect(() => {\n if (!node) return;\n detective.attach(node);\n const unsubscribe = detective.subscribe((event) => {\n if (event.component.id === node.id) last.current = event;\n });\n return () => {\n unsubscribe();\n detective.detach(node);\n };\n }, [detective, node]);\n\n if (node) {\n const isMount = !node.seenCommit;\n detective.recordAttempt(node, props ?? {});\n // No Profiler in hook mode: enqueue with a sentinel commit time, which the\n // flush pass resolves to the next real commit that follows this render.\n detective.recordCommit(node, {\n phase: isMount ? \"mount\" : \"update\",\n subtreeDuration: 0,\n baseDuration: 0,\n startTime: 0,\n commitTime: -1,\n });\n }\n\n return last.current;\n}\n\n/**\n * React 18+. Used only to identify *which* component under an instrumented node\n * owns the tracked state; `useId` is stable across StrictMode's double render,\n * which a `useRef` token would not be. Older React simply loses the guard.\n */\nconst useOwnerId: () => string =\n typeof (React as { useId?: () => string }).useId === \"function\"\n ? (React as unknown as { useId: () => string }).useId\n : () => \"\";\n\n/**\n * `useState` with a label. The only reliable way to attribute a render to a\n * specific piece of local state without React internals.\n *\n * **Call this inside a component that is itself instrumented** (wrapped with\n * `withRenderDetective`, or using `useRenderDiagnostics`). A hook cannot see\n * which component called it, only the nearest instrumented ancestor — so state\n * named in an uninstrumented descendant would be reported as the ancestor's.\n * The first caller under a given node claims it and later callers are ignored,\n * which stops a descendant from stealing the attribution, but it cannot rescue\n * the case where the ancestor never tracks state of its own.\n */\nexport function useTrackedState<S>(name: string, initial: S | (() => S)): [S, Dispatch<SetStateAction<S>>] {\n const detective = getDetective();\n const node = useContext(AncestryContext);\n const ownerId = useOwnerId();\n const [state, setState] = useState<S>(initial);\n const previous = useRef<S>(state);\n\n if (node && node.stateOwner === undefined) node.stateOwner = ownerId;\n const owns = !node || node.stateOwner === ownerId;\n\n if (node && owns && !Object.is(previous.current, state)) {\n detective.recordStateChange(node, {\n name,\n previous: inspect(previous.current, detective.config.inspection),\n current: inspect(state, detective.config.inspection),\n });\n previous.current = state;\n } else if (!owns) {\n previous.current = state;\n }\n\n return [state, setState];\n}\n\n/**\n * `useEffect` that reports which of **its own declared** dependencies changed.\n *\n * This does not analyse whether the dependency list is correct — that needs\n * static analysis, not runtime observation (see docs/FEASIBILITY.md §9).\n */\nexport function useTrackedEffect(\n name: string,\n effect: () => void | (() => void),\n deps: unknown[],\n): void {\n const detective = getDetective();\n const previous = useRef<unknown[] | undefined>(undefined);\n const changed = useRef<number[]>([]);\n\n if (detective.enabled) {\n const prev = previous.current;\n changed.current = prev\n ? deps.map((d, i) => (Object.is(d, prev[i]) ? -1 : i)).filter((i) => i >= 0)\n : [];\n previous.current = deps;\n }\n\n useEffect(() => {\n if (detective.enabled && detective.config.mode !== \"silent\" && changed.current.length > 0) {\n // eslint-disable-next-line no-console\n console.debug(`[RRD] effect ${name} ran — deps changed at index ${changed.current.join(\", \")}`);\n }\n return effect();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, deps);\n}\n\n/**\n * Reports when a context value changes, from inside the provider.\n * Returns the value untouched.\n */\nexport function useTrackedContextValue<T>(contextName: string, value: T): T {\n const detective = getDetective();\n const previous = useRef<T | undefined>(undefined);\n const first = useRef(true);\n\n if (detective.enabled) {\n if (first.current) {\n first.current = false;\n } else if (!Object.is(previous.current, value)) {\n const prev = previous.current;\n const equal = shallowEqual(prev, value, detective.config);\n const changedKeys =\n isRecord(prev) && isRecord(value)\n ? diffProps(prev, value, detective.config).changed.map((c) => c.key)\n : [];\n detective.recordContextChange({\n contextName,\n changedKeys,\n referenceOnly: equal === true,\n commitTime: -1,\n });\n }\n previous.current = value;\n }\n\n return value;\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n","import { attachConsoleReporter } from \"./console/reporter.js\";\nimport { explainEvents, formatExplanation } from \"./core/explain.js\";\nimport { getDetective } from \"./core/store.js\";\nimport type {\n AppStats,\n ComponentStats,\n DetectiveConfig,\n DetectiveOptions,\n RenderEvent,\n} from \"./core/types.js\";\n\nconst REPORTER = Symbol.for(\"react-render-detective.reporter\");\ntype Global = typeof globalThis & { [REPORTER]?: () => void };\n\n/**\n * Enable diagnostics. Safe to call repeatedly — Fast Refresh, duplicate module\n * copies and re-entrant setup all reconfigure the single instance rather than\n * stacking listeners (§47).\n */\nexport function init(options: DetectiveOptions = {}): void {\n const detective = getDetective();\n detective.init(options);\n\n const g = globalThis as Global;\n g[REPORTER]?.();\n g[REPORTER] = undefined;\n\n if (detective.enabled && detective.config.mode !== \"silent\") {\n g[REPORTER] = attachConsoleReporter(detective);\n } else if (!detective.enabled) {\n // Never fail silently: a disabled detective looks identical to a broken one.\n console.info(\n \"[RRD] Diagnostics are disabled\" +\n (detective.config.enabled === false ? \" (enabled: false, or a production build was detected).\" : \".\"),\n );\n }\n}\n\n/** Update configuration without re-initialising. */\nexport function configure(options: DetectiveOptions): void {\n getDetective().configure(options);\n}\n\nexport function getConfig(): Readonly<DetectiveConfig> {\n return getDetective().config;\n}\n\nexport function isEnabled(): boolean {\n return getDetective().enabled;\n}\n\n/** Oldest → newest, bounded by `maxEvents`. */\nexport function getEvents(): RenderEvent[] {\n return getDetective().getEvents();\n}\n\nexport function getStats(): AppStats {\n return getDetective().getStats();\n}\n\nexport function getComponentStats(name?: string): ComponentStats[] {\n return getDetective().getComponentStats(name);\n}\n\n/** Live event stream. Returns an unsubscribe function. */\nexport function subscribe(listener: (event: RenderEvent) => void): () => void {\n return getDetective().subscribe(listener);\n}\n\n/** Clears recorded events and statistics; instrumentation stays attached. */\nexport function clear(): void {\n getDetective().clear();\n}\n\n/** Full teardown, including configuration. Mainly for tests and HMR disposal. */\nexport function reset(): void {\n const g = globalThis as Global;\n g[REPORTER]?.();\n g[REPORTER] = undefined;\n getDetective().reset();\n}\n\n/**\n * The flagship answer: aggregate every recorded render of one component into a\n * single, human explanation. Returns `undefined` if nothing was recorded.\n */\nexport function explain(componentName: string): string | undefined {\n const explanation = explainEvents(componentName, getEvents());\n return explanation ? formatExplanation(explanation) : undefined;\n}\n\n/** Structured form of `explain`, for building UIs on top. */\nexport function explainStructured(componentName: string) {\n return explainEvents(componentName, getEvents());\n}\n\n/** Prints the application-level dashboard (§53). */\nexport function printStats(): void {\n const s = getStats();\n const lines = [\n \"React Render Detective\",\n \"\",\n `Components ${s.components}`,\n `Total renders ${s.totalRenders}`,\n `Total render time ${s.totalRenderTime.toFixed(1)}ms`,\n `Slow renders ${s.slowRenders}`,\n `Potentially avoidable ${s.potentiallyAvoidableRenders}`,\n ];\n if (s.devReplays > 0) {\n lines.push(`Development replays ${s.devReplays} (StrictMode / discarded — not counted above)`);\n }\n if (s.mostExpensive.length > 0) {\n lines.push(\"\", \"Top by cumulative render time\");\n for (const [i, c] of s.mostExpensive.slice(0, 5).entries()) {\n lines.push(\n `${String(i + 1).padStart(2)}. ${c.name.padEnd(22)} ${String(c.renderCount).padStart(6)} renders ${c.totalSelfDuration\n .toFixed(1)\n .padStart(8)}ms (avg ${c.averageSelfDuration.toFixed(1)}ms, p95 ${c.p95SelfDuration.toFixed(1)}ms)`,\n );\n }\n }\n console.log(lines.join(\"\\n\"));\n}\n\n/** Namespaced form, matching the documented `ReactRenderDetective.init()` usage. */\nexport const ReactRenderDetective = {\n init,\n configure,\n getConfig,\n isEnabled,\n getEvents,\n getStats,\n getComponentStats,\n subscribe,\n clear,\n reset,\n explain,\n explainStructured,\n printStats,\n};\n\nexport { withRenderDetective } from \"./react/withRenderDetective.js\";\nexport { RenderDetective } from \"./react/RenderDetective.js\";\nexport type { RenderDetectiveProps } from \"./react/RenderDetective.js\";\nexport {\n useRenderDiagnostics,\n useTrackedState,\n useTrackedEffect,\n useTrackedContextValue,\n} from \"./react/hooks.js\";\nexport type { TrackOptions } from \"./react/instrument.js\";\nexport { explainEvents, formatExplanation } from \"./core/explain.js\";\nexport type { Explanation } from \"./core/explain.js\";\nexport type * from \"./core/types.js\";\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/console/reporter.ts","../src/core/interactions.ts","../src/core/opportunities.ts","../src/react/ancestry.ts","../src/react/instrument.tsx","../src/react/withRenderDetective.tsx","../src/react/RenderDetective.tsx","../src/react/hooks.ts","../src/index.ts"],"names":["label","jsx","useContext","useState","componentName"],"mappings":";;;;;;;;;AAIA,IAAM,IAAA,GAA+B;AAAA,EACnC,MAAA,EAAQ,MAAA;AAAA,EACR,OAAA,EAAS,QAAA;AAAA,EACT,IAAA,EAAM,QAAA;AAAA,EACN,WAAA,EAAa,cAAA;AAAA,EACb,QAAA,EAAU;AACZ,CAAA;AAGO,SAAS,sBAAsB,SAAA,EAAkC;AACtE,EAAA,OAAO,SAAA,CAAU,SAAA,CAAU,CAAC,KAAA,KAAU;AACpC,IAAA,MAAM,IAAA,GAAO,UAAU,MAAA,CAAO,IAAA;AAC9B,IAAA,IAAI,SAAS,QAAA,EAAU;AACvB,IAAA,IAAI;AACF,MAAA,IAAI,IAAA,KAAS,SAAA,EAAW,YAAA,CAAa,KAAK,CAAA;AAAA,WACrC,YAAA,CAAa,KAAA,EAAO,SAAA,CAAU,MAAA,CAAO,mBAAmB,CAAA;AAAA,IAC/D,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF,CAAC,CAAA;AACH;AAEA,SAAS,YAAA,CAAa,OAAoB,aAAA,EAA6B;AACrE,EAAA,MAAM,EAAE,SAAA,EAAW,OAAA,EAAS,SAAA,EAAU,GAAI,KAAA;AAC1C,EAAA,MAAM,OAAA,GAAU,KAAA,CAAM,YAAA,CAAa,GAAA,CAAI,CAAC,MAAM,CAAA,CAAE,GAAG,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AAC9D,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,CAAA,MAAA,EAAS,SAAA,CAAU,IAAI,CAAA,EAAA,EAAK,MAAM,YAAY,CAAA,CAAA;AAAA,IAC9C,CAAA,QAAA,EAAW,KAAA,CAAM,KAAK,CAAC,CAAA,CAAA;AAAA,IACvB,OAAA,GAAU,CAAA,SAAA,EAAY,OAAO,CAAA,CAAA,GAAK,MAAA;AAAA,IAClC,OAAA,CAAQ,kBAAkB,CAAA,GAAI,CAAA,UAAA,EAAa,QAAQ,YAAA,CAAa,OAAA,CAAQ,CAAC,CAAC,CAAA,EAAA,CAAA,GAAO;AAAA,GACnF,CAAE,OAAO,OAAO,CAAA;AAEhB,EAAA,MAAM,IAAA,GAAO,CAAA,EAAG,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAA,IAAK,MAAG,CAAA,CAAA,EAAI,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AACnE,EAAA,MAAM,IAAA,GAAO,QAAQ,YAAA,IAAgB,aAAA;AACrC,EAAA,IAAI,IAAA,EAAM,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAA;AAAA,OACtB,OAAA,CAAQ,IAAI,IAAI,CAAA;AACvB;AAEA,SAAS,aAAa,KAAA,EAA0B;AAC9C,EAAA,MAAM,EAAE,SAAA,EAAW,OAAA,EAAQ,GAAI,KAAA;AAC/B,EAAA,MAAM,MAAA,GAAS,CAAA,MAAA,EAAS,KAAA,CAAM,SAAA,CAAU,IAAI,KAAK,KAAA,CAAM,YAAY,CAAA,QAAA,EAAM,SAAA,CAAU,OAAO,CAAA,CAAA;AAE1F,EAAA,MAAM,QAAQ,SAAA,CAAU,QAAA,KAAa,QAAA,GAAW,OAAA,CAAQ,iBAAiB,OAAA,CAAQ,KAAA;AACjF,EAAA,KAAA,CAAM,IAAA,CAAK,SAAS,MAAM,CAAA;AAC1B,EAAA,IAAI;AACF,IAAA,OAAA,CAAQ,GAAA,CAAI,gBAAgB,KAAA,CAAM,KAAK,CAAC,CAAA,cAAA,EAAiB,SAAA,CAAU,UAAU,CAAA,CAAA,CAAG,CAAA;AAChF,IAAA,IAAI,KAAA,CAAM,UAAU,MAAA,EAAQ,OAAA,CAAQ,IAAI,CAAA,aAAA,EAAgB,KAAA,CAAM,SAAA,CAAU,MAAM,CAAA,CAAE,CAAA;AAChF,IAAA,IAAI,MAAM,MAAA,EAAQ;AAChB,MAAA,OAAA,CAAQ,GAAA;AAAA,QACN,gBAAgB,KAAA,CAAM,MAAA,CAAO,IAAI,CAAA,EAAG,KAAA,CAAM,OAAO,MAAA,GAAS,CAAA,EAAA,EAAK,KAAA,CAAM,MAAA,CAAO,MAAM,CAAA,CAAA,CAAA,GAAM,EAAE,GACrF,KAAA,CAAM,cAAA,GAAiB,uCAAkC,2BAAsB,CAAA;AAAA,OACtF;AAAA,IACF;AACA,IAAA,OAAA,CAAQ,GAAA;AAAA,MACN,CAAA,kBAAA,EAAqB,QAAQ,YAAA,CAAa,OAAA,CAAQ,CAAC,CAAC,CAAA,gBAAA,EAAgB,OAAA,CAAQ,eAAA,CAAgB,OAAA,CAAQ,CAAC,CAAC,CAAA,EAAA,CAAA,IACnG,OAAA,CAAQ,8BAA8B,CAAA,GACnC,CAAA,EAAA,EAAK,QAAQ,2BAAA,CAA4B,OAAA,CAAQ,CAAC,CAAC,CAAA,4BAAA,CAAA,GACnD,EAAA;AAAA,KACR;AAEA,IAAA,IAAI,KAAA,CAAM,YAAA,CAAa,MAAA,GAAS,CAAA,EAAG;AACjC,MAAA,OAAA,CAAQ,cAAA,CAAe,CAAA,eAAA,EAAkB,KAAA,CAAM,YAAA,CAAa,MAAM,CAAA,CAAA,CAAG,CAAA;AACrE,MAAA,KAAA,MAAW,KAAK,KAAA,CAAM,YAAA,UAAsB,GAAA,CAAI,QAAA,CAAS,CAAC,CAAC,CAAA;AAC3D,MAAA,OAAA,CAAQ,QAAA,EAAS;AAAA,IACnB;AACA,IAAA,IAAI,KAAA,CAAM,cAAA,CAAe,MAAA,GAAS,CAAA,EAAG;AACnC,MAAA,OAAA,CAAQ,IAAI,CAAA,aAAA,EAAgB,KAAA,CAAM,eAAe,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,IAC/D;AACA,IAAA,IAAI,KAAA,CAAM,YAAA,CAAa,MAAA,GAAS,CAAA,EAAG;AACjC,MAAA,OAAA,CAAQ,GAAA;AAAA,QACN,CAAA,aAAA,EAAgB,MAAM,YAAA,CACnB,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,EAAG,CAAA,CAAE,IAAI,CAAA,EAAA,EAAK,eAAA,CAAgB,EAAE,QAAQ,CAAC,CAAA,QAAA,EAAM,eAAA,CAAgB,CAAA,CAAE,OAAO,CAAC,CAAA,CAAE,CAAA,CACtF,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,OACf;AAAA,IACF;AACA,IAAA,IAAI,KAAA,CAAM,cAAA,CAAe,MAAA,GAAS,CAAA,EAAG;AACnC,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,aAAA,EAAgB,KAAA,CAAM,cAAA,CAAe,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,uBAAA,CAAyB,CAAA;AAAA,IAChH;AAEA,IAAA,OAAA,CAAQ,eAAe,UAAU,CAAA;AACjC,IAAA,KAAA,MAAW,QAAQ,SAAA,CAAU,QAAA,UAAkB,GAAA,CAAI,CAAA,OAAA,EAAK,IAAI,CAAA,CAAE,CAAA;AAC9D,IAAA,OAAA,CAAQ,QAAA,EAAS;AAEjB,IAAA,IAAI,UAAU,UAAA,EAAY,OAAA,CAAQ,IAAI,CAAA,aAAA,EAAgB,SAAA,CAAU,UAAU,CAAA,CAAE,CAAA;AAC5E,IAAA,IAAI,SAAA,CAAU,oBAAA,EAAsB,OAAA,CAAQ,GAAA,CAAI,2CAA2C,CAAA;AAAA,EAC7F,CAAA,SAAE;AACA,IAAA,OAAA,CAAQ,QAAA,EAAS;AAAA,EACnB;AACF;AAEA,SAAS,SAAS,CAAA,EAAuB;AACvC,EAAA,MAAM,IAAA,GAAO,CAAA,EAAG,CAAA,CAAE,GAAG,CAAA,EAAA,EAAK,EAAE,SAAS,CAAA,SAAA,EAAO,YAAA,CAAa,CAAC,CAAC,CAAA,CAAA;AAC3D,EAAA,IAAI,CAAA,CAAE,IAAA,KAAS,OAAA,EAAS,OAAO,CAAA,EAAG,IAAI,CAAA,EAAA,EAAK,eAAA,CAAgB,CAAA,CAAE,OAAO,CAAC,CAAA,CAAA;AACrE,EAAA,IAAI,CAAA,CAAE,IAAA,KAAS,SAAA,EAAW,OAAO,CAAA,EAAG,IAAI,CAAA,MAAA,EAAS,eAAA,CAAgB,CAAA,CAAE,QAAQ,CAAC,CAAA,CAAA;AAC5E,EAAA,OAAO,GAAG,IAAI;AAAA,cAAA,EAAmB,eAAA,CAAgB,CAAA,CAAE,QAAQ,CAAC;AAAA,cAAA,EAAmB,eAAA,CAAgB,CAAA,CAAE,OAAO,CAAC,CAAA,CAAA;AAC3G;AAEA,SAAS,aAAa,CAAA,EAAuB;AAC3C,EAAA,QAAQ,EAAE,IAAA;AAAM,IACd,KAAK,OAAA;AACH,MAAA,OAAO,OAAA;AAAA,IACT,KAAK,SAAA;AACH,MAAA,OAAO,SAAA;AAAA,IACT,KAAK,OAAA;AACH,MAAA,OAAO,eAAA;AAAA,IACT,KAAK,WAAA;AACH,MAAA,IAAI,EAAE,SAAA,KAAc,UAAA,EAAY,OAAO,CAAA,CAAE,cAAc,gCAAA,GAAmC,wBAAA;AAC1F,MAAA,OAAO,CAAA,CAAE,YAAA,KAAiB,IAAA,GAAO,uCAAA,GAA0C,mBAAA;AAAA;AAEjF;AAEA,SAAS,MAAM,KAAA,EAA4B;AACzC,EAAA,QAAQ,KAAA,CAAM,UAAU,MAAA;AAAQ,IAC9B,KAAK,OAAA;AACH,MAAA,OAAO,OAAA;AAAA,IACT,KAAK,OAAA;AACH,MAAA,OAAO,KAAA,CAAM,aAAa,KAAA,CAAM,CAAC,MAAM,CAAA,CAAE,IAAA,KAAS,WAAW,CAAA,GAAI,+BAAA,GAAkC,cAAA;AAAA,IACrG,KAAK,QAAA;AACH,MAAA,OAAO,iBAAA;AAAA,IACT,KAAK,SAAA;AACH,MAAA,OAAO,gBAAA;AAAA,IACT,KAAK,OAAA;AACH,MAAA,OAAO,eAAA;AAAA,IACT,KAAK,mBAAA;AACH,MAAA,OAAO,yBAAA;AAAA,IACT,KAAK,SAAA;AACH,MAAA,OAAO,cAAA;AAAA;AAEb;;;ACtFA,IAAM,eAAA,GAAkB,GAAA;AAGxB,IAAM,iBAAA,GAAoB,EAAA;AAUnB,IAAM,qBAAN,MAAyB;AAAA,EAK9B,WAAA,CAAoB,WAAW,EAAA,EAAI;AAAf,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAJpB,IAAA,IAAA,CAAQ,UAA+B,EAAC;AAExC,IAAA,IAAA,CAAQ,MAAA,GAAS,CAAA;AAAA,EAEmB;AAAA;AAAA,EAGpC,KAAA,GAAiB;AACf,IAAA,IAAI,IAAA,CAAK,UAAU,OAAO,IAAA;AAC1B,IAAA,MAAM,KAAM,UAAA,CAAoE,mBAAA;AAChF,IAAA,MAAM,SAAA,GAAY,EAAA,EAAI,mBAAA,EAAqB,QAAA,CAAS,OAAO,CAAA;AAC3D,IAAA,IAAI,CAAC,EAAA,IAAM,CAAC,SAAA,EAAW,OAAO,KAAA;AAE9B,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,IAAI,EAAA,CAAG,CAAC,IAAA,KAAS;AAChC,QAAA,KAAA,MAAW,KAAA,IAAS,IAAA,CAAK,UAAA,EAAW,EAAG;AACrC,UAAA,MAAM,MAAA,GAAS,KAAA;AACf,UAAA,IAAA,CAAK,MAAA,CAAO;AAAA,YACV,MAAM,MAAA,CAAO,IAAA;AAAA,YACb,WAAW,MAAA,CAAO,SAAA;AAAA,YAClB,UAAU,MAAA,CAAO,QAAA;AAAA,YACjB,MAAA,EAAQ,cAAA,CAAe,MAAA,CAAO,MAAM;AAAA,WACrC,CAAA;AAAA,QACH;AAAA,MACF,CAAC,CAAA;AAED,MAAA,QAAA,CAAS,OAAA,CAAQ,EAAE,IAAA,EAAM,OAAA,EAAS,UAAU,IAAA,EAAM,iBAAA,EAAmB,IAA+B,CAAA;AACpG,MAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,MAAA,OAAO,IAAA;AAAA,IACT,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAAA,EAEA,IAAA,GAAa;AACX,IAAA,IAAA,CAAK,UAAU,UAAA,EAAW;AAC1B,IAAA,IAAA,CAAK,QAAA,GAAW,MAAA;AAAA,EAClB;AAAA;AAAA,EAGA,IAAI,SAAA,GAAqB;AACvB,IAAA,OAAO,KAAK,QAAA,KAAa,MAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAA,CAAWA,QAAe,MAAA,EAAoB;AAC5C,IAAA,MAAM,YAAY,GAAA,EAAI;AACtB,IAAA,IAAI,SAAA,GAAY,CAAA;AAChB,IAAA,IAAI,QAAA,GAAW,KAAA;AACf,IAAA,MAAM,SAAS,MAAY;AACzB,MAAA,IAAI,QAAA,EAAU;AACd,MAAA,QAAA,GAAW,IAAA;AACX,MAAA,IAAA,CAAK,MAAA,CAAO,EAAE,IAAA,EAAMA,MAAAA,EAAO,SAAA,EAAW,UAAU,GAAA,EAAI,GAAI,SAAA,EAAW,SAAA,EAAW,CAAA;AAAA,IAChF,CAAA;AAEA,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI;AACF,MAAA,MAAA,GAAS,MAAA,EAAO;AAChB,MAAA,SAAA,GAAY,KAAI,GAAI,SAAA;AAAA,IACtB,SAAS,KAAA,EAAO;AACd,MAAA,SAAA,GAAY,KAAI,GAAI,SAAA;AACpB,MAAA,MAAA,EAAO;AACP,MAAA,MAAM,KAAA;AAAA,IACR;AAUA,IAAA,MAAM,MAAO,UAAA,CAAoE,qBAAA;AACjF,IAAA,IAAI,GAAA,EAAK,GAAA,CAAI,MAAM,GAAA,CAAI,MAAM,CAAC,CAAA;AAC9B,IAAA,UAAA,CAAW,QAAQ,iBAAiB,CAAA;AAEpC,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA,EAGA,OAAO,MAAA,EAA2C;AAChD,IAAA,MAAM,MAAA,GAA4B;AAAA,MAChC,EAAA,EAAI,CAAA,YAAA,EAAe,EAAE,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,MAChC,MAAM,MAAA,CAAO,IAAA;AAAA,MACb,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,WAAW,MAAA,CAAO,SAAA;AAAA,MAClB,YAAY,MAAA,CAAO,QAAA;AAAA,MACnB,WAAW,MAAA,CAAO,SAAA;AAAA,MAClB,SAAS,EAAC;AAAA,MACV,YAAA,EAAc,CAAA;AAAA,MACd,qBAAA,EAAuB;AAAA,KACzB;AACA,IAAA,IAAA,CAAK,OAAA,CAAQ,KAAK,MAAM,CAAA;AACxB,IAAA,IAAI,KAAK,OAAA,CAAQ,MAAA,GAAS,KAAK,QAAA,EAAU,IAAA,CAAK,QAAQ,KAAA,EAAM;AAC5D,IAAA,OAAO,MAAA;AAAA,EACT;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,QAAQ,MAAA,GAAS,CAAA;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAU,MAAA,EAA4C;AACpD,IAAA,KAAA,MAAW,MAAA,IAAU,KAAK,OAAA,EAAS;AACjC,MAAA,MAAM,OAAO,MAAA,CAAO,SAAA;AACpB,MAAA,MAAM,EAAA,GAAK,MAAA,CAAO,SAAA,GAAY,MAAA,CAAO,UAAA,GAAa,eAAA;AAClD,MAAA,MAAA,CAAO,OAAA,GAAU,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,CAAQ,UAAA,IAAc,IAAA,IAAQ,CAAA,CAAE,OAAA,CAAQ,UAAA,IAAc,EAAE,CAAA;AAChG,MAAA,MAAA,CAAO,YAAA,GAAe,MAAA,CAAO,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,YAAA,EAAc,CAAC,CAAA;AACnF,MAAA,MAAA,CAAO,wBAAwB,MAAA,CAAO,OAAA,CACnC,OAAO,CAAC,CAAA,KAAM,EAAE,SAAA,CAAU,oBAAoB,CAAA,CAC9C,MAAA,CAAO,CAAC,CAAA,EAAG,CAAA,KAAM,IAAI,CAAA,CAAE,OAAA,CAAQ,cAAc,CAAC,CAAA;AAAA,IACnD;AACA,IAAA,OAAO,CAAC,GAAG,IAAA,CAAK,OAAO,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,UAAA,GAAa,CAAA,CAAE,UAAU,CAAA;AAAA,EACrE;AACF;AAEO,SAAS,UAAU,MAAA,EAA+C;AACvE,EAAA,MAAM,WAAA,uBAAkB,GAAA,EAAkF;AAC1G,EAAA,KAAA,MAAW,KAAA,IAAS,OAAO,OAAA,EAAS;AAClC,IAAA,MAAM,QAAQ,WAAA,CAAY,GAAA,CAAI,KAAA,CAAM,SAAA,CAAU,IAAI,CAAA,IAAK;AAAA,MACrD,OAAA,EAAS,CAAA;AAAA,MACT,OAAA,EAAS,CAAA;AAAA,MACT,MAAA,EAAQ,MAAM,SAAA,CAAU,MAAA;AAAA,MACxB,KAAA,EAAO,MAAM,SAAA,CAAU;AAAA,KACzB;AACA,IAAA,KAAA,CAAM,OAAA,EAAA;AACN,IAAA,KAAA,CAAM,OAAA,IAAW,MAAM,OAAA,CAAQ,YAAA;AAC/B,IAAA,WAAA,CAAY,GAAA,CAAI,KAAA,CAAM,SAAA,CAAU,IAAA,EAAM,KAAK,CAAA;AAAA,EAC7C;AAEA,EAAA,MAAM,eAAe,CAAC,GAAG,WAAA,CAAY,OAAA,EAAS,CAAA,CAC3C,GAAA,CAAI,CAAC,CAAC,WAAW,CAAC,CAAA,MAAO,EAAE,SAAA,EAAW,QAAQ,CAAA,CAAE,MAAA,EAAQ,OAAA,EAAS,CAAA,CAAE,SAAS,OAAA,EAAS,CAAA,CAAE,OAAA,EAAS,KAAA,EAAO,EAAE,KAAA,EAAM,CAAE,CAAA,CACjH,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,OAAA,GAAU,EAAE,OAAO,CAAA;AAEvC,EAAA,MAAM,GAAA,GAAM,aAAa,CAAC,CAAA;AAQ1B,EAAA,MAAM,SAAA,GAAA,CAAa,MAAA,CAAO,SAAA,IAAa,MAAA,CAAO,cAAc,MAAA,CAAO,YAAA;AACnE,EAAA,MAAM,UAAA,GAAa,MAAA,CAAO,SAAA,KAAc,MAAA,IAAa,MAAA,CAAO,aAAa,SAAA,GAAY,CAAA,IAAK,MAAA,CAAO,UAAA,GAAa,SAAA,GAAY,GAAA;AAC1H,EAAA,MAAM,WAAA,GAAc,UAAA,GAAa,SAAA,GAAY,MAAA,CAAO,UAAA;AACpD,EAAA,MAAM,KAAA,GAAQ,WAAA,GAAc,CAAA,GAAI,MAAA,CAAO,eAAe,WAAA,GAAc,CAAA;AAEpE,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI,UAAA,GAAyB,QAAA;AAE7B,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,QAAA,GACE,GAAG,MAAA,CAAO,IAAI,KAAK,GAAA,CAAI,MAAA,CAAO,aAAa,CAAC,CAAC,CAAA,oBAAA,EAAuB,GAAA,CAAI,OAAO,YAAY,CAAC,uCACjE,GAAA,CAAI,MAAA,CAAO,UAAU,CAAC,CAAA,qEAAA,CAAA;AACnD,IAAA,QAAA,GACE,MAAA,CAAO,YAAA,IAAgB,MAAA,CAAO,SAAA,IAAa,CAAA,CAAA,GACvC,CAAA,iCAAA,EAAoC,GAAA,GAAM,CAAA,aAAA,EAAgB,GAAA,CAAI,SAAS,CAAA,CAAA,GAAK,EAAE,CAAA,CAAA,CAAA,GAC9E,+EAAA;AACN,IAAA,OAAO,EAAE,WAAA,EAAa,MAAA,EAAQ,cAAc,QAAA,EAAU,QAAA,EAAU,YAAY,QAAA,EAAS;AAAA,EACvF;AAEA,EAAA,IAAI,MAAA,CAAO,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG;AAC/B,IAAA,QAAA,GAAW,GAAG,MAAA,CAAO,IAAI,SAAS,GAAA,CAAI,MAAA,CAAO,UAAU,CAAC,CAAA,mDAAA,CAAA;AACxD,IAAA,QAAA,GACE,oKAAA;AACF,IAAA,UAAA,GAAa,KAAA;AAAA,EACf,CAAA,MAAA,IAAW,KAAA,IAAS,GAAA,IAAO,MAAA,CAAO,wBAAwB,CAAA,EAAG;AAC3D,IAAA,QAAA,GACE,GAAG,MAAA,CAAO,IAAI,CAAA,MAAA,EAAS,GAAA,CAAI,OAAO,UAAU,CAAC,CAAA,EAAA,EAAK,GAAA,CAAI,OAAO,YAAY,CAAC,6BACnE,GAAA,CAAI,MAAA,CAAO,qBAAqB,CAAC,CAAA,2CAAA,CAAA;AAC1C,IAAA,QAAA,GAAW,GAAA,GACP,CAAA,WAAA,EAAc,GAAA,CAAI,SAAS,CAAA,EAAG,GAAA,CAAI,MAAA,GAAS,CAAA,EAAA,EAAK,GAAA,CAAI,MAAM,CAAA,CAAA,CAAA,GAAM,EAAE,CAAA,QAAA,EAAM,IAAI,GAAA,CAAI,OAAO,CAAC,CAAA,QAAA,EAAW,GAAA,CAAI,OAAO,CAAA,OAAA,EAAU,GAAA,CAAI,OAAA,KAAY,CAAA,GAAI,EAAA,GAAK,GAAG,CAAA,CAAA,CAAA,GACpJ,oCAAA;AACJ,IAAA,UAAA,GAAa,MAAA;AAAA,EACf,CAAA,MAAA,IAAW,SAAS,GAAA,EAAK;AACvB,IAAA,QAAA,GAAW,CAAA,EAAG,MAAA,CAAO,IAAI,CAAA,MAAA,EAAS,GAAA,CAAI,MAAA,CAAO,UAAU,CAAC,CAAA,EAAA,EAAK,GAAA,CAAI,MAAA,CAAO,YAAY,CAAC,CAAA,gEAAA,CAAA;AACrF,IAAA,QAAA,GAAW,2GAAA;AACX,IAAA,UAAA,GAAa,MAAA;AAAA,EACf,CAAA,MAAO;AACL,IAAA,QAAA,GAAW,CAAA,EAAG,MAAA,CAAO,IAAI,CAAA,MAAA,EAAS,GAAA,CAAI,MAAA,CAAO,UAAU,CAAC,CAAA,WAAA,EAAc,GAAA,CAAI,MAAA,CAAO,YAAY,CAAC,CAAA,qBAAA,CAAA;AAC9F,IAAA,QAAA,GAAW,oIAAA;AACX,IAAA,UAAA,GAAa,QAAA;AAAA,EACf;AAEA,EAAA,OAAO,EAAE,WAAA,EAAa,MAAA,EAAQ,YAAA,EAAc,QAAA,EAAU,UAAU,UAAA,EAAW;AAC7E;AAEO,SAAS,kBAAkB,OAAA,EAAqC;AACrE,EAAA,MAAM,EAAE,WAAA,EAAa,CAAA,EAAE,GAAI,OAAA;AAC3B,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,CAAA,EAAG,CAAA,CAAE,IAAI,CAAA,EAAG,EAAE,MAAA,GAAS,CAAA,IAAA,EAAO,CAAA,CAAE,MAAM,KAAK,EAAE,CAAA,GAAA,EAAM,GAAA,CAAI,CAAA,CAAE,UAAU,CAAC,CAAA,CAAA;AAAA,IACpE,EAAA;AAAA,IACA,OAAA,CAAQ;AAAA,GACV;AAEA,EAAA,IAAI,OAAA,CAAQ,YAAA,CAAa,MAAA,GAAS,CAAA,EAAG;AACnC,IAAA,KAAA,CAAM,IAAA,CAAK,IAAI,mCAAmC,CAAA;AAClD,IAAA,KAAA,MAAW,KAAK,OAAA,CAAQ,YAAA,CAAa,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA,EAAG;AAChD,MAAA,KAAA,CAAM,IAAA;AAAA,QACJ,CAAA,EAAA,EAAK,CAAA,CAAE,SAAA,CAAU,MAAA,CAAO,EAAE,CAAC,CAAA,CAAA,EAAI,MAAA,CAAO,CAAA,CAAE,OAAO,CAAA,CAAE,QAAA,CAAS,CAAC,CAAC,CAAA,YAAA,EAAe,GAAA,CAAI,CAAA,CAAE,OAAO,CAAA,CAAE,SAAS,CAAC,CAAC,CAAA,EAAA,EAAK,CAAA,CAAE,KAAK,CAAA;AAAA,OACnH;AAAA,IACF;AAAA,EACF;AAEA,EAAA,KAAA,CAAM,IAAA,CAAK,EAAA,EAAI,CAAA,SAAA,CAAA,EAAa,CAAA,EAAA,EAAK,OAAA,CAAQ,QAAQ,CAAA,CAAA,EAAI,EAAA,EAAI,CAAA,YAAA,EAAe,OAAA,CAAQ,UAAU,CAAA,CAAE,CAAA;AAC5F,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;AAEA,SAAS,eAAe,MAAA,EAAqC;AAC3D,EAAA,IAAI,CAAC,MAAA,IAAU,OAAO,MAAA,KAAW,UAAU,OAAO,MAAA;AAClD,EAAA,MAAM,EAAA,GAAK,MAAA;AACX,EAAA,IAAI,CAAC,EAAA,CAAG,OAAA,EAAS,OAAO,MAAA;AACxB,EAAA,MAAM,GAAA,GAAM,EAAA,CAAG,OAAA,CAAQ,WAAA,EAAY;AACnC,EAAA,IAAI,GAAG,EAAA,EAAI,OAAO,GAAG,GAAG,CAAA,CAAA,EAAI,GAAG,EAAE,CAAA,CAAA;AACjC,EAAA,MAAM,SAAA,GAAY,OAAO,EAAA,CAAG,SAAA,KAAc,QAAA,GAAW,EAAA,CAAG,SAAA,CAAU,IAAA,EAAK,CAAE,KAAA,CAAM,KAAK,CAAA,CAAE,CAAC,CAAA,GAAI,MAAA;AAC3F,EAAA,IAAI,SAAA,EAAW,OAAO,CAAA,EAAG,GAAG,IAAI,SAAS,CAAA,CAAA;AACzC,EAAA,MAAM,OAAO,EAAA,CAAG,WAAA,EAAa,MAAK,CAAE,KAAA,CAAM,GAAG,EAAE,CAAA;AAC/C,EAAA,OAAO,IAAA,GAAO,CAAA,EAAG,GAAG,CAAA,EAAA,EAAK,IAAI,CAAA,CAAA,CAAA,GAAM,GAAA;AACrC;AAEA,IAAM,MAAM,CAAC,EAAA,KAAuB,GAAG,EAAA,CAAG,OAAA,CAAQ,CAAC,CAAC,CAAA,EAAA,CAAA;AAEpD,IAAM,GAAA,GAAM,MACV,OAAO,WAAA,KAAgB,WAAA,IAAe,OAAO,WAAA,CAAY,GAAA,KAAQ,UAAA,GAAa,WAAA,CAAY,GAAA,EAAI,GAAI,KAAK,GAAA,EAAI;;;ACvQ7G,IAAM,qBAAA,GAAwB,CAAA;AAEvB,SAAS,kBAAkB,EAAE,MAAA,EAAQ,UAAA,EAAY,WAAA,GAAc,uBAAsB,EAAoC;AAC9H,EAAA,MAAM,KAAA,GAAQ,IAAI,GAAA,CAAI,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,SAAA,CAAU,IAAI,CAAC,CAAA;AACzD,EAAA,MAAM,MAAqB,EAAC;AAE5B,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,SAAA,GAAY,UAAA,CAAW,GAAA,CAAI,IAAI,CAAA;AACrC,IAAA,MAAM,WAAA,GAAc,aAAA,CAAc,IAAA,EAAM,MAAA,EAAQ,SAAS,CAAA;AACzD,IAAA,IAAI,CAAC,WAAA,EAAa;AAQlB,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAA,CAAU,IAAA,KAAS,IAAA,IAAQ,CAAA,CAAE,KAAA,KAAU,OAAO,CAAA;AACpF,IAAA,MAAM,gBAAA,GAAmB,MAAA,CAAO,MAAA,GAC5B,MAAA,CAAO,OAAO,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,EAAE,OAAA,CAAQ,YAAA,EAAc,CAAC,CAAA,GAAI,OAAO,MAAA,GAChE,CAAA;AACJ,IAAA,MAAM,aAAA,GAAgB,YAAY,QAAA,GAAW,gBAAA;AAC7C,IAAA,MAAM,iBAAA,GAAoB,YAAY,sBAAA,GAAyB,aAAA;AAE/D,IAAA,IAAI,oBAAoB,WAAA,EAAa;AAErC,IAAA,GAAA,CAAI,IAAA,CAAK;AAAA,MACP,SAAA,EAAW,IAAA;AAAA,MACX,QAAQ,WAAA,CAAY,MAAA;AAAA,MACpB,iBAAA;AAAA,MACA,kBAAkB,WAAA,CAAY,2BAAA;AAAA,MAC9B,UAAU,WAAA,CAAY,QAAA;AAAA,MACtB,qBAAqB,WAAA,CAAY,mBAAA;AAAA,MACjC,SAAS,WAAA,CAAY,QAAA;AAAA,MACrB,UAAU,WAAA,CAAY,QAAA;AAAA,MACtB,YAAY,WAAA,CAAY;AAAA,KACzB,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,GAAA,CAAI,KAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,iBAAA,GAAoB,EAAE,iBAAiB,CAAA;AACrE;AAEO,SAAS,oBAAoB,aAAA,EAAsC;AACxE,EAAA,IAAI,aAAA,CAAc,WAAW,CAAA,EAAG;AAC9B,IAAA,OAAO,sGAAA;AAAA,EACT;AAEA,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,6DAAA;AAAA,IACA,EAAA;AAAA,IACA,0EAAA;AAAA,IACA,mBAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,KAAA,MAAW,CAAC,KAAA,EAAO,CAAC,CAAA,IAAK,aAAA,CAAc,SAAQ,EAAG;AAChD,IAAA,KAAA,CAAM,IAAA;AAAA,MACJ,GAAG,MAAA,CAAO,KAAA,GAAQ,CAAC,CAAA,CAAE,QAAA,CAAS,CAAC,CAAC,CAAA,EAAA,EAAK,CAAA,CAAE,SAAS,GAAG,CAAA,CAAE,MAAA,GAAS,MAAM,CAAA,CAAE,MAAM,KAAK,EAAE,CAAA,CAAA;AAAA,MACnF,CAAA,KAAA,EAAQ,CAAA,CAAE,iBAAA,CAAkB,OAAA,CAAQ,CAAC,CAAC,CAAA,iBAAA,EACjC,CAAA,CAAE,gBAAgB,CAAA,iBAAA,EAAoB,CAAA,CAAE,gBAAA,KAAqB,CAAA,GAAI,KAAK,GAAG,CAAA,EACzE,CAAA,CAAE,QAAA,GAAW,CAAA,GAAI,CAAA,EAAA,EAAK,CAAA,CAAE,QAAQ,CAAA,YAAA,CAAA,GAAc,EAAE,CAAA,gBAAA,EAAmB,CAAA,CAAE,UAAU,CAAA,CAAA,CAAA;AAAA,MACpF,CAAA,IAAA,EAAO,EAAE,OAAO,CAAA,CAAA;AAAA,MAChB,CAAA,WAAA,EAAS,EAAE,QAAQ,CAAA,CAAA;AAAA,MACnB;AAAA,KACF;AAAA,EACF;AAEA,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;AC3FO,IAAM,eAAA,GAAkB,cAAsC,MAAS,CAAA;AAC9E,eAAA,CAAgB,WAAA,GAAc,yBAAA;ACevB,SAAS,mBAAA,CACd,IAAA,EACA,KAAA,EACA,MAAA,EACsE;AACtE,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,MAAM,MAAA,GAAS,WAAW,eAAe,CAAA;AAIzC,EAAA,MAAM,CAAC,IAAI,CAAA,GAAI,QAAA;AAAA,IAAiC,MAC9C,UAAU,OAAA,GAAU,SAAA,CAAU,WAAW,IAAA,EAAM,MAAA,EAAQ,MAAM,CAAA,GAAI;AAAA,GACnE;AAEA,EAAA,eAAA,CAAgB,MAAM;AACpB,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,SAAA,CAAU,OAAO,IAAI,CAAA;AACrB,IAAA,OAAO,MAAM,SAAA,CAAU,MAAA,CAAO,IAAI,CAAA;AAAA,EACpC,CAAA,EAAG,CAAC,SAAA,EAAW,IAAI,CAAC,CAAA;AAEpB,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,IAAI;AACF,MAAA,SAAA,CAAU,aAAA,CAAc,MAAM,KAAK,CAAA;AAAA,IACrC,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,MAAM,QAAA,GAAW,WAAA;AAAA,IACf,CAAC,GAAA,EAAK,KAAA,EAAO,cAAA,EAAgB,YAAA,EAAc,WAAW,UAAA,KAAe;AACnE,MAAA,IAAI,CAAC,IAAA,EAAM;AACX,MAAA,IAAI;AACF,QAAA,SAAA,CAAU,aAAa,IAAA,EAAM;AAAA,UAC3B,KAAA;AAAA,UACA,eAAA,EAAiB,cAAA;AAAA,UACjB,YAAA;AAAA,UACA,SAAA;AAAA,UACA;AAAA,SACD,CAAA;AAAA,MACH,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF,CAAA;AAAA,IACA,CAAC,WAAW,IAAI;AAAA,GAClB;AAEA,EAAA,OAAO,EAAE,MAAM,QAAA,EAAS;AAC1B;AAEO,SAAS,kBAAA,CACd,IAAA,EACA,QAAA,EACA,QAAA,EACW;AACX,EAAA,IAAI,CAAC,MAAM,OAAO,QAAA;AAClB,EAAA,uBACE,GAAA,CAAC,QAAA,EAAA,EAAS,EAAA,EAAI,IAAA,CAAK,EAAA,EAAI,QAAA,EACrB,QAAA,kBAAA,GAAA,CAAC,eAAA,CAAgB,QAAA,EAAhB,EAAyB,KAAA,EAAO,IAAA,EAAO,UAAS,CAAA,EACnD,CAAA;AAEJ;AAEO,SAAS,aAAA,CAAc,SAAA,EAAoB,QAAA,GAAW,WAAA,EAAqB;AAChF,EAAA,MAAM,CAAA,GAAI,SAAA;AACV,EAAA,IAAI,CAAC,GAAG,OAAO,QAAA;AACf,EAAA,IAAI,OAAO,CAAA,CAAE,WAAA,KAAgB,YAAY,CAAA,CAAE,WAAA,SAAoB,CAAA,CAAE,WAAA;AACjE,EAAA,IAAI,OAAO,CAAA,CAAE,IAAA,KAAS,YAAY,CAAA,CAAE,IAAA,SAAa,CAAA,CAAE,IAAA;AAEnD,EAAA,IAAI,EAAE,IAAA,EAAM,OAAO,aAAA,CAAc,CAAA,CAAE,MAAM,QAAQ,CAAA;AACjD,EAAA,OAAO,QAAA;AACT;AC7FA,IAAM,UAAA,mBAAa,MAAA,CAAO,GAAA,CAAI,gCAAgC,CAAA;AAgBvD,SAAS,mBAAA,CACd,SAAA,EACA,OAAA,GAAwB,EAAC,EACP;AAOlB,EAAA,IAAK,SAAA,CAAyC,UAAU,CAAA,EAAG,OAAO,SAAA;AAElE,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,IAAA,IAAQ,aAAA,CAAc,SAAS,CAAA;AAQpD,EAAA,YAAA,GAAe,cAAA,CAAe,IAAA,EAAM,QAAQ,MAAA,EAAQ,OAAA,CAAQ,qBAAqB,IAAI,CAAA;AAErF,EAAA,SAAS,eAAe,KAAA,EAAU;AAChC,IAAA,MAAM,EAAE,MAAM,QAAA,EAAS,GAAI,oBAAoB,IAAA,EAAM,KAAA,EAAkC,QAAQ,MAAM,CAAA;AACrG,IAAA,OAAO,kBAAA,CAAmB,MAAM,QAAA,kBAAUC,IAAC,SAAA,EAAA,EAAW,GAAG,OAAO,CAAE,CAAA;AAAA,EACpE;AAEA,EAAA,cAAA,CAAe,WAAA,GAAc,mBAAmB,IAAI,CAAA,CAAA,CAAA;AACpD,EAAC,cAAA,CAA8C,UAAU,CAAA,GAAI,IAAA;AAC7D,EAAA,OAAO,cAAA;AACT;;;AChCO,SAAS,eAAA,CAAgB,EAAE,IAAA,EAAM,QAAA,EAAS,EAAoC;AACnF,EAAA,MAAM,EAAE,MAAM,QAAA,EAAS,GAAI,oBAAoB,IAAA,EAAM,EAAE,UAAU,CAAA;AACjE,EAAA,OAAO,kBAAA,CAAmB,IAAA,EAAM,QAAA,EAAU,QAAQ,CAAA;AACpD;ACJO,SAAS,oBAAA,CAAqB,MAAc,KAAA,EAA0D;AAC3G,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,MAAM,MAAA,GAASC,WAAW,eAAe,CAAA;AACzC,EAAA,MAAM,CAAC,IAAI,CAAA,GAAIC,QAAAA,CAAS,MAAM;AAC5B,IAAA,IAAI,CAAC,SAAA,CAAU,OAAA,EAAS,OAAO,MAAA;AAC/B,IAAA,MAAM,OAAA,GAAU,SAAA,CAAU,UAAA,CAAW,IAAA,EAAM,MAAM,CAAA;AACjD,IAAA,IAAI,OAAA,EAAS,SAAA,CAAU,aAAA,CAAc,GAAA,CAAI,OAAO,CAAA;AAChD,IAAA,OAAO,OAAA;AAAA,EACT,CAAC,CAAA;AACD,EAAA,MAAM,IAAA,GAAO,OAAgC,MAAS,CAAA;AAEtD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,SAAA,CAAU,OAAO,IAAI,CAAA;AACrB,IAAA,MAAM,WAAA,GAAc,SAAA,CAAU,SAAA,CAAU,CAAC,KAAA,KAAU;AACjD,MAAA,IAAI,MAAM,SAAA,CAAU,EAAA,KAAO,IAAA,CAAK,EAAA,OAAS,OAAA,GAAU,KAAA;AAAA,IACrD,CAAC,CAAA;AACD,IAAA,OAAO,MAAM;AACX,MAAA,WAAA,EAAY;AACZ,MAAA,SAAA,CAAU,OAAO,IAAI,CAAA;AAAA,IACvB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,SAAA,EAAW,IAAI,CAAC,CAAA;AAEpB,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,MAAM,OAAA,GAAU,CAAC,IAAA,CAAK,UAAA;AACtB,IAAA,SAAA,CAAU,aAAA,CAAc,IAAA,EAAM,KAAA,IAAS,EAAE,CAAA;AAGzC,IAAA,SAAA,CAAU,aAAa,IAAA,EAAM;AAAA,MAC3B,KAAA,EAAO,UAAU,OAAA,GAAU,QAAA;AAAA,MAC3B,eAAA,EAAiB,CAAA;AAAA,MACjB,YAAA,EAAc,CAAA;AAAA,MACd,SAAA,EAAW,CAAA;AAAA,MACX,UAAA,EAAY;AAAA,KACb,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,IAAA,CAAK,OAAA;AACd;AAOA,IAAM,UAAA,GACJ,OAA2C,KAAA,CAAA,KAAA,KAAU,UAAA,GACH,cAC9C,MAAM,EAAA;AAcL,SAAS,eAAA,CAAmB,MAAc,OAAA,EAA0D;AACzG,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,MAAM,IAAA,GAAOD,WAAW,eAAe,CAAA;AACvC,EAAA,MAAM,UAAU,UAAA,EAAW;AAC3B,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIC,SAAY,OAAO,CAAA;AAC7C,EAAA,MAAM,QAAA,GAAW,OAAU,KAAK,CAAA;AAEhC,EAAA,IAAI,IAAA,IAAQ,IAAA,CAAK,UAAA,KAAe,MAAA,OAAgB,UAAA,GAAa,OAAA;AAC7D,EAAA,MAAM,IAAA,GAAO,CAAC,IAAA,IAAQ,IAAA,CAAK,UAAA,KAAe,OAAA;AAE1C,EAAA,IAAI,IAAA,IAAQ,QAAQ,CAAC,MAAA,CAAO,GAAG,QAAA,CAAS,OAAA,EAAS,KAAK,CAAA,EAAG;AACvD,IAAA,SAAA,CAAU,kBAAkB,IAAA,EAAM;AAAA,MAChC,IAAA;AAAA,MACA,UAAU,OAAA,CAAQ,QAAA,CAAS,OAAA,EAAS,SAAA,CAAU,OAAO,UAAU,CAAA;AAAA,MAC/D,OAAA,EAAS,OAAA,CAAQ,KAAA,EAAO,SAAA,CAAU,OAAO,UAAU;AAAA,KACpD,CAAA;AACD,IAAA,QAAA,CAAS,OAAA,GAAU,KAAA;AAAA,EACrB,CAAA,MAAA,IAAW,CAAC,IAAA,EAAM;AAChB,IAAA,QAAA,CAAS,OAAA,GAAU,KAAA;AAAA,EACrB;AAEA,EAAA,OAAO,CAAC,OAAO,QAAQ,CAAA;AACzB;AAQO,SAAS,gBAAA,CACd,IAAA,EACA,MAAA,EACA,IAAA,EACM;AACN,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,MAAM,QAAA,GAAW,OAA8B,MAAS,CAAA;AACxD,EAAA,MAAM,OAAA,GAAU,MAAA,CAAiB,EAAE,CAAA;AAEnC,EAAA,IAAI,UAAU,OAAA,EAAS;AACrB,IAAA,MAAM,OAAO,QAAA,CAAS,OAAA;AACtB,IAAA,OAAA,CAAQ,OAAA,GAAU,OACd,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,KAAO,MAAA,CAAO,EAAA,CAAG,CAAA,EAAG,IAAA,CAAK,CAAC,CAAC,CAAA,GAAI,EAAA,GAAK,CAAE,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,IAAK,CAAC,CAAA,GACzE,EAAC;AACL,IAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AAAA,EACrB;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,SAAA,CAAU,WAAW,SAAA,CAAU,MAAA,CAAO,SAAS,QAAA,IAAY,OAAA,CAAQ,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AAEzF,MAAA,OAAA,CAAQ,KAAA,CAAM,gBAAgB,IAAI,CAAA,kCAAA,EAAgC,QAAQ,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,IAChG;AACA,IAAA,OAAO,MAAA,EAAO;AAAA,EAEhB,GAAG,IAAI,CAAA;AACT;AAMO,SAAS,sBAAA,CAA0B,aAAqB,KAAA,EAAa;AAC1E,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,MAAM,QAAA,GAAW,OAAsB,MAAS,CAAA;AAChD,EAAA,MAAM,KAAA,GAAQ,OAAO,IAAI,CAAA;AAEzB,EAAA,IAAI,UAAU,OAAA,EAAS;AACrB,IAAA,IAAI,MAAM,OAAA,EAAS;AACjB,MAAA,KAAA,CAAM,OAAA,GAAU,KAAA;AAAA,IAClB,WAAW,CAAC,MAAA,CAAO,GAAG,QAAA,CAAS,OAAA,EAAS,KAAK,CAAA,EAAG;AAC9C,MAAA,MAAM,OAAO,QAAA,CAAS,OAAA;AACtB,MAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,IAAA,EAAM,KAAA,EAAO,UAAU,MAAM,CAAA;AACxD,MAAA,MAAM,WAAA,GACJ,SAAS,IAAI,CAAA,IAAK,SAAS,KAAK,CAAA,GAC5B,UAAU,IAAA,EAAM,KAAA,EAAO,UAAU,MAAM,CAAA,CAAE,QAAQ,GAAA,CAAI,CAAC,MAAM,CAAA,CAAE,GAAG,IACjE,EAAC;AACP,MAAA,SAAA,CAAU,mBAAA,CAAoB;AAAA,QAC5B,WAAA;AAAA,QACA,WAAA;AAAA,QACA,eAAe,KAAA,KAAU,IAAA;AAAA,QACzB,UAAA,EAAY;AAAA,OACb,CAAA;AAAA,IACH;AACA,IAAA,QAAA,CAAS,OAAA,GAAU,KAAA;AAAA,EACrB;AAEA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,SAAS,CAAA,EAA0C;AAC1D,EAAA,OAAO,OAAO,MAAM,QAAA,IAAY,CAAA,KAAM,QAAQ,CAAC,KAAA,CAAM,QAAQ,CAAC,CAAA;AAChE;;;ACzJA,IAAM,QAAA,mBAAW,MAAA,CAAO,GAAA,CAAI,iCAAiC,CAAA;AAC7D,IAAM,YAAA,mBAAe,MAAA,CAAO,GAAA,CAAI,qCAAqC,CAAA;AAGrE,SAAS,OAAA,GAA8B;AACrC,EAAA,MAAM,CAAA,GAAI,UAAA;AACV,EAAA,IAAI,CAAC,EAAE,YAAY,CAAA,IAAK,YAAY,CAAA,GAAI,IAAI,kBAAA,EAAmB;AAC/D,EAAA,OAAO,EAAE,YAAY,CAAA;AACvB;AAOO,SAAS,IAAA,CAAK,OAAA,GAA4B,EAAC,EAAS;AACzD,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,SAAA,CAAU,KAAK,OAAO,CAAA;AAEtB,EAAA,MAAM,CAAA,GAAI,UAAA;AACV,EAAA,CAAA,CAAE,QAAQ,CAAA,IAAI;AACd,EAAA,CAAA,CAAE,QAAQ,CAAA,GAAI,MAAA;AAEd,EAAA,IAAI,UAAU,OAAA,EAAS;AAErB,IAAA,OAAA,GAAU,KAAA,EAAM;AAAA,EAClB;AAEA,EAAA,IAAI,SAAA,CAAU,OAAA,IAAW,SAAA,CAAU,MAAA,CAAO,SAAS,QAAA,EAAU;AAC3D,IAAA,CAAA,CAAE,QAAQ,CAAA,GAAI,qBAAA,CAAsB,SAAS,CAAA;AAAA,EAC/C,CAAA,MAAA,IAAW,CAAC,SAAA,CAAU,OAAA,EAAS;AAE7B,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN,gCAAA,IACG,SAAA,CAAU,MAAA,CAAO,OAAA,KAAY,QAAQ,wDAAA,GAA2D,GAAA;AAAA,KACrG;AAAA,EACF;AACF;AAGO,SAAS,UAAU,OAAA,EAAiC;AACzD,EAAA,YAAA,EAAa,CAAE,UAAU,OAAO,CAAA;AAClC;AAEO,SAAS,SAAA,GAAuC;AACrD,EAAA,OAAO,cAAa,CAAE,MAAA;AACxB;AAEO,SAAS,SAAA,GAAqB;AACnC,EAAA,OAAO,cAAa,CAAE,OAAA;AACxB;AAGO,SAAS,SAAA,GAA2B;AACzC,EAAA,OAAO,YAAA,GAAe,SAAA,EAAU;AAClC;AAEO,SAAS,QAAA,GAAqB;AACnC,EAAA,OAAO,YAAA,GAAe,QAAA,EAAS;AACjC;AAEO,SAAS,kBAAkB,IAAA,EAAiC;AACjE,EAAA,OAAO,YAAA,EAAa,CAAE,iBAAA,CAAkB,IAAI,CAAA;AAC9C;AAGO,SAAS,UAAU,QAAA,EAAoD;AAC5E,EAAA,OAAO,YAAA,EAAa,CAAE,SAAA,CAAU,QAAQ,CAAA;AAC1C;AAGO,SAAS,KAAA,GAAc;AAC5B,EAAA,YAAA,GAAe,KAAA,EAAM;AACrB,EAAA,OAAA,GAAU,KAAA,EAAM;AAClB;AAGO,SAAS,KAAA,GAAc;AAC5B,EAAA,MAAM,CAAA,GAAI,UAAA;AACV,EAAA,CAAA,CAAE,QAAQ,CAAA,IAAI;AACd,EAAA,CAAA,CAAE,QAAQ,CAAA,GAAI,MAAA;AACd,EAAA,CAAA,CAAE,YAAY,GAAG,IAAA,EAAK;AACtB,EAAA,CAAA,CAAE,YAAY,CAAA,GAAI,MAAA;AAClB,EAAA,YAAA,GAAe,KAAA,EAAM;AACvB;AAMO,SAAS,QAAQC,cAAAA,EAA2C;AACjE,EAAA,MAAM,WAAA,GAAc,kBAAkBA,cAAa,CAAA;AACnD,EAAA,OAAO,WAAA,GAAc,iBAAA,CAAkB,WAAW,CAAA,GAAI,MAAA;AACxD;AAGO,SAAS,kBAAkBA,cAAAA,EAAuB;AACvD,EAAA,OAAO,aAAA,CAAcA,gBAAe,SAAA,EAAU,EAAG,cAAa,CAAE,WAAA,CAAYA,cAAa,CAAC,CAAA;AAC5F;AAGO,SAAS,iBAAiB,QAAA,EAAiC;AAChE,EAAA,MAAM,WAAmC,EAAC;AAC1C,EAAA,KAAA,MAAW,KAAA,IAAS,cAAa,CAAE,iBAAA,IAAqB,QAAA,CAAS,KAAA,CAAM,IAAI,CAAA,GAAI,KAAA,CAAM,YAAA;AACrF,EAAA,OAAO,iBAAA,CAAkB,QAAA,EAAU,SAAA,EAAU,EAAG,QAAQ,CAAA;AAC1D;AASO,SAAS,eAAA,GAAuC;AACrD,EAAA,OAAO,OAAA,EAAQ,CAAE,SAAA,CAAU,SAAA,EAAW,CAAA;AACxC;AAGO,SAAS,6BAA6B,EAAA,EAA6C;AACxF,EAAA,MAAM,UAAU,eAAA,EAAgB;AAChC,EAAA,MAAM,MAAA,GAAS,EAAA,GAAK,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,EAAA,KAAO,EAAE,CAAA,GAAI,OAAA,CAAQ,CAAC,CAAA;AAChE,EAAA,OAAO,MAAA,GAAS,SAAA,CAAU,MAAM,CAAA,GAAI,MAAA;AACtC;AAEO,SAAS,mBAAmB,EAAA,EAAiC;AAClE,EAAA,MAAM,OAAA,GAAU,6BAA6B,EAAE,CAAA;AAC/C,EAAA,OAAO,OAAA,GAAU,iBAAA,CAAkB,OAAO,CAAA,GAAI,MAAA;AAChD;AAEO,SAAS,iBAAA,CAAkB,QAAQ,CAAA,EAAS;AACjD,EAAA,MAAM,OAAA,GAAU,eAAA,EAAgB,CAAE,KAAA,CAAM,GAAG,KAAK,CAAA;AAChD,EAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,IAAA,OAAA,CAAQ,GAAA;AAAA,MACN,OAAA,EAAQ,CAAE,SAAA,GACN,qMAAA,GAEA;AAAA,KAEN;AACA,IAAA;AAAA,EACF;AACA,EAAA,OAAA,CAAQ,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,iBAAA,CAAkB,SAAA,CAAU,CAAC,CAAC,CAAC,CAAA,CAAE,IAAA,CAAK,MAAM,CAAC,CAAA;AAC9E;AAQO,SAAS,kBAAA,CAAsBJ,QAAe,MAAA,EAAoB;AACvE,EAAA,OAAO,OAAA,EAAQ,CAAE,OAAA,CAAQA,MAAAA,EAAO,MAAM,CAAA;AACxC;AAMO,SAAS,gBAAA,CAAiB,QAAQ,EAAA,EAAmB;AAC1D,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAkC;AACzD,EAAA,KAAA,MAAW,KAAA,IAAS,SAAA,CAAU,iBAAA,EAAkB,EAAG;AACjD,IAAA,UAAA,CAAW,IAAI,KAAA,CAAM,IAAA,EAAM,EAAE,QAAA,EAAU,KAAA,CAAM,cAAc,CAAA;AAAA,EAC7D;AACA,EAAA,OAAO,iBAAA,CAAkB,EAAE,MAAA,EAAQ,SAAA,CAAU,SAAA,EAAU,EAAG,UAAA,EAAY,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA;AACxF;AAEO,SAAS,kBAAA,CAAmB,QAAQ,EAAA,EAAU;AACnD,EAAA,OAAA,CAAQ,GAAA,CAAI,mBAAA,CAAoB,gBAAA,CAAiB,KAAK,CAAC,CAAC,CAAA;AAC1D;AAGO,SAAS,UAAA,GAAmB;AACjC,EAAA,MAAM,IAAI,QAAA,EAAS;AACnB,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,wBAAA;AAAA,IACA,EAAA;AAAA,IACA,CAAA,yBAAA,EAA4B,EAAE,UAAU,CAAA,CAAA;AAAA,IACxC,CAAA,yBAAA,EAA4B,EAAE,YAAY,CAAA,CAAA;AAAA,IAC1C,CAAA,yBAAA,EAA4B,CAAA,CAAE,eAAA,CAAgB,OAAA,CAAQ,CAAC,CAAC,CAAA,EAAA,CAAA;AAAA,IACxD,CAAA,yBAAA,EAA4B,EAAE,WAAW,CAAA,CAAA;AAAA,IACzC,CAAA,yBAAA,EAA4B,EAAE,2BAA2B,CAAA;AAAA,GAC3D;AACA,EAAA,MAAM,OAAA,GAAU,EAAE,YAAA,CAAa,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,gBAAgB,CAAC,CAAA;AAChE,EAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACtB,IAAA,KAAA,CAAM,IAAA;AAAA,MACJ,EAAA;AAAA,MACA,qEAAA;AAAA,MACA,GAAG,QAAQ,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,EAAA,EAAK,CAAA,CAAE,KAAK,MAAA,CAAO,EAAE,CAAC,CAAA,CAAA,EAAI,MAAA,CAAO,CAAA,CAAE,YAAY,CAAA,CAAE,QAAA,CAAS,CAAC,CAAC,CAAA,cAAA,CAAa;AAAA,KAC7G;AAAA,EACF;AACA,EAAA,IAAI,CAAA,CAAE,aAAa,CAAA,EAAG;AACpB,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,yBAAA,EAA4B,CAAA,CAAE,UAAU,CAAA,kDAAA,CAA+C,CAAA;AAAA,EACpG;AACA,EAAA,IAAI,CAAA,CAAE,aAAA,CAAc,MAAA,GAAS,CAAA,EAAG;AAC9B,IAAA,KAAA,CAAM,IAAA,CAAK,IAAI,+BAA+B,CAAA;AAC9C,IAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,CAAA,IAAK,CAAA,CAAE,aAAA,CAAc,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA,CAAE,OAAA,EAAQ,EAAG;AAC1D,MAAA,KAAA,CAAM,IAAA;AAAA,QACJ,GAAG,MAAA,CAAO,CAAA,GAAI,CAAC,CAAA,CAAE,QAAA,CAAS,CAAC,CAAC,CAAA,EAAA,EAAK,EAAE,IAAA,CAAK,MAAA,CAAO,EAAE,CAAC,CAAA,CAAA,EAAI,OAAO,CAAA,CAAE,WAAW,EAAE,QAAA,CAAS,CAAC,CAAC,CAAA,UAAA,EAAa,EAAE,iBAAA,CACnG,OAAA,CAAQ,CAAC,CAAA,CACT,QAAA,CAAS,CAAC,CAAC,CAAA,SAAA,EAAY,EAAE,mBAAA,CAAoB,OAAA,CAAQ,CAAC,CAAC,CAAA,QAAA,EAAW,EAAE,eAAA,CAAgB,OAAA,CAAQ,CAAC,CAAC,CAAA,GAAA;AAAA,OACnG;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC,CAAA;AAC9B;AAGO,IAAM,oBAAA,GAAuB;AAAA,EAClC,IAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,iBAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,OAAA;AAAA,EACA,iBAAA;AAAA,EACA,gBAAA;AAAA,EACA,kBAAA;AAAA,EACA,eAAA;AAAA,EACA,kBAAA;AAAA,EACA,4BAAA;AAAA,EACA,iBAAA;AAAA,EACA,kBAAA;AAAA,EACA,gBAAA;AAAA,EACA;AACF","file":"index.js","sourcesContent":["import { formatInspected } from \"../core/inspect.js\";\nimport type { Detective } from \"../core/store.js\";\nimport type { PropChange, RenderEvent } from \"../core/types.js\";\n\nconst ICON: Record<string, string> = {\n normal: \"·\",\n monitor: \"•\",\n slow: \"▲\",\n \"very-slow\": \"▲▲\",\n critical: \"■\",\n};\n\n/** Attaches console output. Returns an unsubscribe so init() stays idempotent. */\nexport function attachConsoleReporter(detective: Detective): () => void {\n return detective.subscribe((event) => {\n const mode = detective.config.mode;\n if (mode === \"silent\") return;\n try {\n if (mode === \"verbose\") printVerbose(event);\n else printConcise(event, detective.config.slowRenderThreshold);\n } catch {\n /* ignore */\n }\n });\n}\n\nfunction printConcise(event: RenderEvent, slowThreshold: number): void {\n const { diagnosis, timings, component } = event;\n const changed = event.changedProps.map((c) => c.key).join(\", \");\n const parts = [\n `[RRD] ${component.name} #${event.renderNumber}`,\n `Reason: ${label(event)}`,\n changed ? `Changed: ${changed}` : undefined,\n timings.subtreeDuration > 0 ? `Duration: ${timings.selfDuration.toFixed(1)}ms` : undefined,\n ].filter(Boolean);\n\n const line = `${ICON[diagnosis.severity] ?? \"·\"} ${parts.join(\" \")}`;\n const slow = timings.selfDuration >= slowThreshold;\n if (slow) console.warn(line);\n else console.log(line);\n}\n\nfunction printVerbose(event: RenderEvent): void {\n const { diagnosis, timings } = event;\n const header = `[RRD] ${event.component.name} #${event.renderNumber} — ${diagnosis.summary}`;\n\n const group = diagnosis.severity === \"normal\" ? console.groupCollapsed : console.group;\n group.call(console, header);\n try {\n console.log(`Cause: ${label(event)} (confidence: ${diagnosis.confidence})`);\n if (event.component.source) console.log(`Source: ${event.component.source}`);\n if (event.parent) {\n console.log(\n `Parent: ${event.parent.name}${event.parent.source ? ` (${event.parent.source})` : \"\"}` +\n `${event.parentRendered ? \" — re-rendered in this commit\" : \" — did not re-render\"}`,\n );\n }\n console.log(\n `Cost: self ${timings.selfDuration.toFixed(1)}ms · subtree ${timings.subtreeDuration.toFixed(1)}ms` +\n (timings.accountedDescendantDuration > 0\n ? ` (${timings.accountedDescendantDuration.toFixed(1)}ms in instrumented children)`\n : \"\"),\n );\n\n if (event.changedProps.length > 0) {\n console.groupCollapsed(`Props changed (${event.changedProps.length})`);\n for (const c of event.changedProps) console.log(propLine(c));\n console.groupEnd();\n }\n if (event.unchangedProps.length > 0) {\n console.log(`Props same: ${event.unchangedProps.join(\", \")}`);\n }\n if (event.trackedState.length > 0) {\n console.log(\n `State: ${event.trackedState\n .map((s) => `${s.name}: ${formatInspected(s.previous)} → ${formatInspected(s.current)}`)\n .join(\", \")}`,\n );\n }\n if (event.contextChanges.length > 0) {\n console.log(`Context: ${event.contextChanges.map((c) => c.contextName).join(\", \")} changed in this commit`);\n }\n\n console.groupCollapsed(\"Evidence\");\n for (const line of diagnosis.evidence) console.log(`• ${line}`);\n console.groupEnd();\n\n if (diagnosis.suggestion) console.log(`Next step: ${diagnosis.suggestion}`);\n if (diagnosis.potentiallyAvoidable) console.log(\"Flag: potentially avoidable render\");\n } finally {\n console.groupEnd();\n }\n}\n\nfunction propLine(c: PropChange): string {\n const head = `${c.key} (${c.valueType}) — ${describeKind(c)}`;\n if (c.kind === \"added\") return `${head}: ${formatInspected(c.current)}`;\n if (c.kind === \"removed\") return `${head}: was ${formatInspected(c.previous)}`;\n return `${head}\\n previous: ${formatInspected(c.previous)}\\n current: ${formatInspected(c.current)}`;\n}\n\nfunction describeKind(c: PropChange): string {\n switch (c.kind) {\n case \"added\":\n return \"added\";\n case \"removed\":\n return \"removed\";\n case \"value\":\n return \"value changed\";\n case \"reference\":\n if (c.valueType === \"function\") return c.sourceEqual ? \"new function, identical source\" : \"new function reference\";\n return c.shallowEqual === true ? \"reference changed, contents identical\" : \"reference changed\";\n }\n}\n\nfunction label(event: RenderEvent): string {\n switch (event.diagnosis.reason) {\n case \"mount\":\n return \"mount\";\n case \"props\":\n return event.changedProps.every((c) => c.kind === \"reference\") ? \"prop changed (reference only)\" : \"prop changed\";\n case \"parent\":\n return \"parent rendered\";\n case \"context\":\n return \"context update\";\n case \"state\":\n return \"state changed\";\n case \"state-or-external\":\n return \"state or external store\";\n case \"unknown\":\n return \"undetermined\";\n }\n}\n","import type { Confidence, RenderEvent } from \"./types.js\";\n\n/**\n * Interaction-scoped attribution.\n *\n * Performance is felt per interaction, not in aggregate — and INP is the metric\n * teams are actually judged on. This joins the two halves: the browser says a\n * keystroke took 240ms, and the render events say which components spent it and\n * why.\n *\n * Uses `PerformanceObserver` with `event` timing, a public browser API. Where it\n * is unsupported (older Safari, jsdom) interaction tracking simply stays empty\n * rather than guessing.\n */\nexport interface InteractionRecord {\n id: string;\n /** `click`, `keydown`, `pointerup`… */\n type: string;\n /** Best-effort description of what was interacted with. */\n target?: string;\n startTime: number;\n /** Browser-reported event duration — the number INP is computed from. */\n durationMs: number;\n /**\n * For a manually measured interaction: how long the synchronous action took.\n * Immune to throttling, unlike the full window, which waits on a frame.\n */\n handlerMs?: number;\n /** Renders committed inside this interaction's window. */\n renders: RenderEvent[];\n /** Sum of self durations for those renders. */\n renderTimeMs: number;\n /** Render time that no observable input change explains. */\n avoidableRenderTimeMs: number;\n}\n\nexport interface InteractionSummary {\n interaction: InteractionRecord;\n /** Components ordered by cost within this interaction. */\n contributors: Array<{ component: string; source?: string; renders: number; totalMs: number; cause: string }>;\n headline: string;\n nextStep: string;\n confidence: Confidence;\n}\n\n/** Entries React commits slightly after the event finishes; allow for that. */\nconst COMMIT_SLACK_MS = 100;\n\n/** Used when requestAnimationFrame cannot fire — a hidden tab, or jsdom. */\nconst FALLBACK_CLOSE_MS = 50;\n\ninterface RawEventTiming {\n name: string;\n startTime: number;\n duration: number;\n target?: string;\n handlerMs?: number;\n}\n\nexport class InteractionTracker {\n private records: InteractionRecord[] = [];\n private observer: { disconnect: () => void } | undefined;\n private nextId = 0;\n\n constructor(private capacity = 50) {}\n\n /** Returns false when the browser cannot report event timing. */\n start(): boolean {\n if (this.observer) return true;\n const PO = (globalThis as { PerformanceObserver?: typeof PerformanceObserver }).PerformanceObserver;\n const supported = PO?.supportedEntryTypes?.includes(\"event\");\n if (!PO || !supported) return false;\n\n try {\n const observer = new PO((list) => {\n for (const entry of list.getEntries()) {\n const timing = entry as PerformanceEntry & { duration: number; target?: Element };\n this.record({\n name: timing.name,\n startTime: timing.startTime,\n duration: timing.duration,\n target: describeTarget(timing.target),\n });\n }\n });\n // 16ms: anything that misses a frame is worth attributing.\n observer.observe({ type: \"event\", buffered: true, durationThreshold: 16 } as PerformanceObserverInit);\n this.observer = observer;\n return true;\n } catch {\n return false;\n }\n }\n\n stop(): void {\n this.observer?.disconnect();\n this.observer = undefined;\n }\n\n /** Is the automatic path available in this browser? */\n get automatic(): boolean {\n return this.observer !== undefined;\n }\n\n /**\n * Time an interaction by hand.\n *\n * The automatic path depends on the Event Timing API, which Safari only\n * gained in 16.4 and which does not fire for synthetic input at all — so\n * anything driven by a test harness records nothing. This measures a specific\n * action instead, up to the paint that follows it, and needs no browser\n * support beyond `performance.now`.\n */\n measure<T>(label: string, action: () => T): T {\n const startTime = now();\n let handlerMs = 0;\n let finished = false;\n const finish = (): void => {\n if (finished) return;\n finished = true;\n this.record({ name: label, startTime, duration: now() - startTime, handlerMs });\n };\n\n let result: T;\n try {\n result = action();\n handlerMs = now() - startTime;\n } catch (error) {\n handlerMs = now() - startTime;\n finish();\n throw error;\n }\n\n /*\n * Close the window after the frame in which React commits and paints.\n *\n * The timer is not belt-and-braces: `requestAnimationFrame` does not fire\n * in a hidden tab, and does not exist in jsdom, so without it an\n * interaction would simply never be recorded. Whichever fires first wins;\n * the fallback is long enough that rAF normally does.\n */\n const raf = (globalThis as { requestAnimationFrame?: (cb: () => void) => void }).requestAnimationFrame;\n if (raf) raf(() => raf(finish));\n setTimeout(finish, FALLBACK_CLOSE_MS);\n\n return result;\n }\n\n /** Exposed for tests and for `measure`. */\n record(timing: RawEventTiming): InteractionRecord {\n const record: InteractionRecord = {\n id: `interaction_${++this.nextId}`,\n type: timing.name,\n target: timing.target,\n startTime: timing.startTime,\n durationMs: timing.duration,\n handlerMs: timing.handlerMs,\n renders: [],\n renderTimeMs: 0,\n avoidableRenderTimeMs: 0,\n };\n this.records.push(record);\n if (this.records.length > this.capacity) this.records.shift();\n return record;\n }\n\n clear(): void {\n this.records.length = 0;\n }\n\n /**\n * Joins render events to interactions by commit time. A render belongs to an\n * interaction when it committed between the event starting and shortly after\n * it finished — React commits just after the event handler returns.\n */\n attribute(events: RenderEvent[]): InteractionRecord[] {\n for (const record of this.records) {\n const from = record.startTime;\n const to = record.startTime + record.durationMs + COMMIT_SLACK_MS;\n record.renders = events.filter((e) => e.timings.commitTime >= from && e.timings.commitTime <= to);\n record.renderTimeMs = record.renders.reduce((a, e) => a + e.timings.selfDuration, 0);\n record.avoidableRenderTimeMs = record.renders\n .filter((e) => e.diagnosis.potentiallyAvoidable)\n .reduce((a, e) => a + e.timings.selfDuration, 0);\n }\n return [...this.records].sort((a, b) => b.durationMs - a.durationMs);\n }\n}\n\nexport function summarise(record: InteractionRecord): InteractionSummary {\n const byComponent = new Map<string, { renders: number; totalMs: number; source?: string; cause: string }>();\n for (const event of record.renders) {\n const entry = byComponent.get(event.component.name) ?? {\n renders: 0,\n totalMs: 0,\n source: event.component.source,\n cause: event.diagnosis.reason,\n };\n entry.renders++;\n entry.totalMs += event.timings.selfDuration;\n byComponent.set(event.component.name, entry);\n }\n\n const contributors = [...byComponent.entries()]\n .map(([component, v]) => ({ component, source: v.source, renders: v.renders, totalMs: v.totalMs, cause: v.cause }))\n .sort((a, b) => b.totalMs - a.totalMs);\n\n const top = contributors[0];\n\n /*\n * A manually measured window waits for a frame, and a throttled or hidden tab\n * can stretch that to hundreds of milliseconds of pure idling. Attributing\n * that to the app would be inventing a problem, so when the window is far\n * larger than the work inside it, reason about the work instead.\n */\n const accounted = (record.handlerMs ?? record.durationMs) + record.renderTimeMs;\n const idleWindow = record.handlerMs !== undefined && record.durationMs > accounted * 3 && record.durationMs - accounted > 100;\n const effectiveMs = idleWindow ? accounted : record.durationMs;\n const share = effectiveMs > 0 ? record.renderTimeMs / effectiveMs : 0;\n\n let headline: string;\n let nextStep: string;\n let confidence: Confidence = \"medium\";\n\n if (idleWindow) {\n headline =\n `${record.type}: ${fmt(record.handlerMs ?? 0)} in the handler and ${fmt(record.renderTimeMs)} rendering. ` +\n `The measured window was ${fmt(record.durationMs)}, but most of that was the page waiting for a frame — ignore it.`;\n nextStep =\n record.renderTimeMs > (record.handlerMs ?? 0)\n ? `Rendering dominates the real work${top ? `; start with ${top.component}` : \"\"}.`\n : \"The handler itself costs more than rendering. Profile the handler, not React.\";\n return { interaction: record, contributors, headline, nextStep, confidence: \"medium\" };\n }\n\n if (record.renders.length === 0) {\n headline = `${record.type} took ${fmt(record.durationMs)}, and no instrumented component rendered inside it.`;\n nextStep =\n \"The cost is somewhere other than React rendering — an event handler, a layout, or an uninstrumented component. Instrument more of the tree to narrow it down.\";\n confidence = \"low\";\n } else if (share >= 0.4 && record.avoidableRenderTimeMs > 0) {\n headline =\n `${record.type} took ${fmt(record.durationMs)}; ${fmt(record.renderTimeMs)} of it was rendering, ` +\n `and ${fmt(record.avoidableRenderTimeMs)} of that had no input change to explain it.`;\n nextStep = top\n ? `Start with ${top.component}${top.source ? ` (${top.source})` : \"\"} — ${fmt(top.totalMs)} across ${top.renders} render${top.renders === 1 ? \"\" : \"s\"}.`\n : \"Look at the top contributor below.\";\n confidence = \"high\";\n } else if (share >= 0.4) {\n headline = `${record.type} took ${fmt(record.durationMs)}; ${fmt(record.renderTimeMs)} of it was rendering, all of it explained by real input changes.`;\n nextStep = \"This is genuine work. Make the renders cheaper rather than fewer — or do less of it per interaction.\";\n confidence = \"high\";\n } else {\n headline = `${record.type} took ${fmt(record.durationMs)}, but only ${fmt(record.renderTimeMs)} was React rendering.`;\n nextStep = \"Most of the cost is outside rendering — event handlers, layout or paint. A browser profile will show more than this tool can.\";\n confidence = \"medium\";\n }\n\n return { interaction: record, contributors, headline, nextStep, confidence };\n}\n\nexport function formatInteraction(summary: InteractionSummary): string {\n const { interaction: i } = summary;\n const lines = [\n `${i.type}${i.target ? ` on ${i.target}` : \"\"} ${fmt(i.durationMs)}`,\n \"\",\n summary.headline,\n ];\n\n if (summary.contributors.length > 0) {\n lines.push(\"\", \"Rendering inside this interaction\");\n for (const c of summary.contributors.slice(0, 8)) {\n lines.push(\n ` ${c.component.padEnd(22)} ${String(c.renders).padStart(4)} render(s) ${fmt(c.totalMs).padStart(8)} ${c.cause}`,\n );\n }\n }\n\n lines.push(\"\", `Next step`, ` ${summary.nextStep}`, \"\", `Confidence: ${summary.confidence}`);\n return lines.join(\"\\n\");\n}\n\nfunction describeTarget(target: unknown): string | undefined {\n if (!target || typeof target !== \"object\") return undefined;\n const el = target as { tagName?: string; id?: string; className?: unknown; textContent?: string | null };\n if (!el.tagName) return undefined;\n const tag = el.tagName.toLowerCase();\n if (el.id) return `${tag}#${el.id}`;\n const className = typeof el.className === \"string\" ? el.className.trim().split(/\\s+/)[0] : undefined;\n if (className) return `${tag}.${className}`;\n const text = el.textContent?.trim().slice(0, 20);\n return text ? `${tag} \"${text}\"` : tag;\n}\n\nconst fmt = (ms: number): string => `${ms.toFixed(1)}ms`;\n\nconst now = (): number =>\n typeof performance !== \"undefined\" && typeof performance.now === \"function\" ? performance.now() : Date.now();\n","import { explainEvents } from \"./explain.js\";\nimport type { Confidence, RenderEvent } from \"./types.js\";\n\n/**\n * \"Where should I spend my next hour?\"\n *\n * Render counts answer the wrong question — a component rendering 2 000 times\n * for 0.01ms is not the problem, and one rendering 40 times for 12ms might be.\n * This ranks by **estimated recoverable time**, so the top of the list is the\n * biggest win rather than the noisiest component.\n */\nexport interface Opportunity {\n component: string;\n source?: string;\n /** Milliseconds plausibly recovered by fixing this. The ranking key. */\n estimatedSavingMs: number;\n /** Renders where no observable input changed. */\n avoidableRenders: number;\n /** Times the component was rebuilt rather than re-rendered. */\n remounts: number;\n averageSelfDuration: number;\n /** One line: what to look at. Comes from the diagnostic engine, not from here. */\n summary: string;\n nextStep: string;\n confidence: Confidence;\n}\n\nexport interface OpportunityInput {\n events: RenderEvent[];\n lifecycles: Map<string, { remounts: number }>;\n /** Ignore anything below this. Noise is worse than silence in a ranked list. */\n minSavingMs?: number;\n}\n\nconst DEFAULT_MIN_SAVING_MS = 1;\n\nexport function rankOpportunities({ events, lifecycles, minSavingMs = DEFAULT_MIN_SAVING_MS }: OpportunityInput): Opportunity[] {\n const names = new Set(events.map((e) => e.component.name));\n const out: Opportunity[] = [];\n\n for (const name of names) {\n const lifecycle = lifecycles.get(name);\n const explanation = explainEvents(name, events, lifecycle);\n if (!explanation) continue;\n\n /*\n * A remount is charged at the cost of a mount, because that is what it is:\n * React rebuilds the subtree. Avoidable renders are charged at what they\n * actually cost. Both are estimates and are labelled as such — the point is\n * an ordering, not a promise.\n */\n const mounts = events.filter((e) => e.component.name === name && e.phase === \"mount\");\n const averageMountCost = mounts.length\n ? mounts.reduce((a, e) => a + e.timings.selfDuration, 0) / mounts.length\n : 0;\n const remountSaving = explanation.remounts * averageMountCost;\n const estimatedSavingMs = explanation.estimatedAvoidableTime + remountSaving;\n\n if (estimatedSavingMs < minSavingMs) continue;\n\n out.push({\n component: name,\n source: explanation.source,\n estimatedSavingMs,\n avoidableRenders: explanation.potentiallyAvoidableRenders,\n remounts: explanation.remounts,\n averageSelfDuration: explanation.averageSelfDuration,\n summary: explanation.headline,\n nextStep: explanation.nextStep,\n confidence: explanation.confidence,\n });\n }\n\n return out.sort((a, b) => b.estimatedSavingMs - a.estimatedSavingMs);\n}\n\nexport function formatOpportunities(opportunities: Opportunity[]): string {\n if (opportunities.length === 0) {\n return \"React Render Detective\\n\\nNo measurable render waste found yet. Interact with the app and try again.\";\n }\n\n const lines = [\n \"React Render Detective — where to spend your next hour\",\n \"\",\n \"Ranked by estimated recoverable time. These are estimates, not promises:\",\n \"measure each fix.\",\n \"\",\n ];\n\n for (const [index, o] of opportunities.entries()) {\n lines.push(\n `${String(index + 1).padStart(2)}. ${o.component}${o.source ? ` ${o.source}` : \"\"}`,\n ` ~${o.estimatedSavingMs.toFixed(0)}ms recoverable ` +\n `${o.avoidableRenders} avoidable render${o.avoidableRenders === 1 ? \"\" : \"s\"}` +\n `${o.remounts > 0 ? `, ${o.remounts}× rebuilt` : \"\"} (confidence: ${o.confidence})`,\n ` ${o.summary}`,\n ` → ${o.nextStep}`,\n \"\",\n );\n }\n\n return lines.join(\"\\n\");\n}\n","import { createContext } from \"react\";\nimport type { NodeRecord } from \"../core/store.js\";\n\n/**\n * Carries the nearest instrumented ancestor down the tree.\n *\n * The value is the node object, created once per mounted instance and **never\n * replaced**. That is deliberate: a context value that changed per render would\n * force every instrumented descendant to re-render, defeating `React.memo` and\n * changing the behaviour of the very app we are measuring.\n */\nexport const AncestryContext = createContext<NodeRecord | undefined>(undefined);\nAncestryContext.displayName = \"RenderDetectiveAncestry\";\n","import { Profiler, useCallback, useContext, useLayoutEffect, useState } from \"react\";\nimport type { ProfilerOnRenderCallback, ReactNode } from \"react\";\nimport { getDetective } from \"../core/store.js\";\nimport type { NodeRecord } from \"../core/store.js\";\nimport type { RenderPhase } from \"../core/types.js\";\nimport { AncestryContext } from \"./ancestry.js\";\n\nexport interface TrackOptions {\n /** Overrides the inferred component name. Required for anonymous components. */\n name?: string;\n /**\n * `path/to/File.tsx:12:2`. Supplied automatically by the build plugin; there\n * is no runtime way to obtain it.\n */\n source?: string;\n /**\n * Set by the build plugin when the component is declared inside another\n * function. React sees a new component type on every parent render and\n * rebuilds the whole subtree, so this turns a guess into a fact.\n */\n declaredInRender?: boolean;\n}\n\n/**\n * Registers the current component, records this render attempt, and returns the\n * node plus a Profiler callback. All of it is a no-op when disabled.\n */\nexport function useInstrumentedNode(\n name: string,\n props: Record<string, unknown>,\n source?: string,\n): { node: NodeRecord | undefined; onRender: ProfilerOnRenderCallback } {\n const detective = getDetective();\n const parent = useContext(AncestryContext);\n\n // The active/inactive decision is frozen per instance so the element tree\n // shape never changes underneath a mounted component.\n const [node] = useState<NodeRecord | undefined>(() =>\n detective.enabled ? detective.createNode(name, parent, source) : undefined,\n );\n\n useLayoutEffect(() => {\n if (!node) return;\n detective.attach(node);\n return () => detective.detach(node);\n }, [detective, node]);\n\n if (node) {\n try {\n detective.recordAttempt(node, props);\n } catch {\n /* never break the app being debugged (§46) */\n }\n }\n\n const onRender = useCallback<ProfilerOnRenderCallback>(\n (_id, phase, actualDuration, baseDuration, startTime, commitTime) => {\n if (!node) return;\n try {\n detective.recordCommit(node, {\n phase: phase as RenderPhase,\n subtreeDuration: actualDuration,\n baseDuration,\n startTime,\n commitTime,\n });\n } catch {\n /* ignore */\n }\n },\n [detective, node],\n );\n\n return { node, onRender };\n}\n\nexport function renderInstrumented(\n node: NodeRecord | undefined,\n onRender: ProfilerOnRenderCallback,\n children: ReactNode,\n): ReactNode {\n if (!node) return children;\n return (\n <Profiler id={node.id} onRender={onRender}>\n <AncestryContext.Provider value={node}>{children}</AncestryContext.Provider>\n </Profiler>\n );\n}\n\nexport function componentName(component: unknown, fallback = \"Anonymous\"): string {\n const c = component as { displayName?: string; name?: string; type?: unknown } | null;\n if (!c) return fallback;\n if (typeof c.displayName === \"string\" && c.displayName) return c.displayName;\n if (typeof c.name === \"string\" && c.name) return c.name;\n // React.memo / forwardRef wrappers keep the real component on `.type`.\n if (c.type) return componentName(c.type, fallback);\n return fallback;\n}\n","import type { ComponentType } from \"react\";\nimport { getDetective } from \"../core/store.js\";\n\n/** Marks a component as one of ours, so it is never wrapped twice. */\nconst IS_WRAPPER = Symbol.for(\"react-render-detective.wrapper\");\nimport { componentName, renderInstrumented, useInstrumentedNode } from \"./instrument.js\";\nimport type { TrackOptions } from \"./instrument.js\";\n\n/**\n * Wraps a component with full instrumentation: render counting, prop diffing,\n * parent attribution and Profiler timings.\n *\n * This is the most accurate integration mode — the wrapper's render function\n * runs exactly when the wrapped component re-renders, and it receives the same\n * props, so every diagnosis has first-hand evidence.\n *\n * Ref note: on React 19 `ref` is an ordinary prop and passes through the spread.\n * On React 18 and below, wrap with `forwardRef` yourself if the component needs\n * a ref.\n */\nexport function withRenderDetective<P extends object>(\n Component: ComponentType<P>,\n options: TrackOptions = {},\n): ComponentType<P> {\n /*\n * Wrapping a wrapper would make it render itself. That is unreachable through\n * careful hand-wrapping but trivially reachable once a build plugin is\n * wrapping everything, and the failure mode is a stack overflow before first\n * paint — so return the existing wrapper instead.\n */\n if ((Component as { [IS_WRAPPER]?: boolean })[IS_WRAPPER]) return Component;\n\n const name = options.name ?? componentName(Component);\n\n /*\n * Counted at wrap time, not render time. A component declared at module scope\n * is wrapped once; one declared inside a render body is wrapped again on every\n * parent render, which is the tell for the most expensive mistake in this\n * list — React rebuilds the whole subtree each time.\n */\n getDetective().noteDefinition(name, options.source, options.declaredInRender === true);\n\n function RenderDetected(props: P) {\n const { node, onRender } = useInstrumentedNode(name, props as Record<string, unknown>, options.source);\n return renderInstrumented(node, onRender, <Component {...props} />);\n }\n\n RenderDetected.displayName = `RenderDetective(${name})`;\n (RenderDetected as { [IS_WRAPPER]?: boolean })[IS_WRAPPER] = true;\n return RenderDetected;\n}\n","import type { ReactNode } from \"react\";\nimport { renderInstrumented, useInstrumentedNode } from \"./instrument.js\";\n\nexport interface RenderDetectiveProps {\n name: string;\n children: ReactNode;\n}\n\n/**\n * Zero-refactor integration: drop it around a subtree.\n *\n * <RenderDetective name=\"UserProfile\"><UserProfile /></RenderDetective>\n *\n * Accuracy note: this boundary only sees the `children` **element**, not the\n * wrapped component's props. It therefore reports timings, parent propagation\n * and children-element churn accurately, but it cannot attribute a render to an\n * individual prop. Use `withRenderDetective` when you want per-prop diagnosis.\n */\nexport function RenderDetective({ name, children }: RenderDetectiveProps): ReactNode {\n const { node, onRender } = useInstrumentedNode(name, { children });\n return renderInstrumented(node, onRender, children);\n}\n","import * as React from \"react\";\nimport { useContext, useEffect, useRef, useState } from \"react\";\nimport type { Dispatch, SetStateAction } from \"react\";\nimport { getDetective } from \"../core/store.js\";\nimport { inspect } from \"../core/inspect.js\";\nimport { diffProps, shallowEqual } from \"../core/compare.js\";\nimport type { RenderEvent } from \"../core/types.js\";\nimport { AncestryContext } from \"./ancestry.js\";\n\n/**\n * In-component diagnostics without wrapping.\n *\n * Limitation, by design: a hook cannot install a `<Profiler>` around its own\n * component, so **no duration is available in this mode** — timings are\n * reported as 0. Everything else (render count, prop diffing, parent\n * attribution) is as accurate as the HOC.\n */\nexport function useRenderDiagnostics(name: string, props?: Record<string, unknown>): RenderEvent | undefined {\n const detective = getDetective();\n const parent = useContext(AncestryContext);\n const [node] = useState(() => {\n if (!detective.enabled) return undefined;\n const created = detective.createNode(name, parent);\n if (created) detective.hookModeNodes.add(created);\n return created;\n });\n const last = useRef<RenderEvent | undefined>(undefined);\n\n useEffect(() => {\n if (!node) return;\n detective.attach(node);\n const unsubscribe = detective.subscribe((event) => {\n if (event.component.id === node.id) last.current = event;\n });\n return () => {\n unsubscribe();\n detective.detach(node);\n };\n }, [detective, node]);\n\n if (node) {\n const isMount = !node.seenCommit;\n detective.recordAttempt(node, props ?? {});\n // No Profiler in hook mode: enqueue with a sentinel commit time, which the\n // flush pass resolves to the next real commit that follows this render.\n detective.recordCommit(node, {\n phase: isMount ? \"mount\" : \"update\",\n subtreeDuration: 0,\n baseDuration: 0,\n startTime: 0,\n commitTime: -1,\n });\n }\n\n return last.current;\n}\n\n/**\n * React 18+. Used only to identify *which* component under an instrumented node\n * owns the tracked state; `useId` is stable across StrictMode's double render,\n * which a `useRef` token would not be. Older React simply loses the guard.\n */\nconst useOwnerId: () => string =\n typeof (React as { useId?: () => string }).useId === \"function\"\n ? (React as unknown as { useId: () => string }).useId\n : () => \"\";\n\n/**\n * `useState` with a label. The only reliable way to attribute a render to a\n * specific piece of local state without React internals.\n *\n * **Call this inside a component that is itself instrumented** (wrapped with\n * `withRenderDetective`, or using `useRenderDiagnostics`). A hook cannot see\n * which component called it, only the nearest instrumented ancestor — so state\n * named in an uninstrumented descendant would be reported as the ancestor's.\n * The first caller under a given node claims it and later callers are ignored,\n * which stops a descendant from stealing the attribution, but it cannot rescue\n * the case where the ancestor never tracks state of its own.\n */\nexport function useTrackedState<S>(name: string, initial: S | (() => S)): [S, Dispatch<SetStateAction<S>>] {\n const detective = getDetective();\n const node = useContext(AncestryContext);\n const ownerId = useOwnerId();\n const [state, setState] = useState<S>(initial);\n const previous = useRef<S>(state);\n\n if (node && node.stateOwner === undefined) node.stateOwner = ownerId;\n const owns = !node || node.stateOwner === ownerId;\n\n if (node && owns && !Object.is(previous.current, state)) {\n detective.recordStateChange(node, {\n name,\n previous: inspect(previous.current, detective.config.inspection),\n current: inspect(state, detective.config.inspection),\n });\n previous.current = state;\n } else if (!owns) {\n previous.current = state;\n }\n\n return [state, setState];\n}\n\n/**\n * `useEffect` that reports which of **its own declared** dependencies changed.\n *\n * This does not analyse whether the dependency list is correct — that needs\n * static analysis, not runtime observation (see docs/FEASIBILITY.md §9).\n */\nexport function useTrackedEffect(\n name: string,\n effect: () => void | (() => void),\n deps: unknown[],\n): void {\n const detective = getDetective();\n const previous = useRef<unknown[] | undefined>(undefined);\n const changed = useRef<number[]>([]);\n\n if (detective.enabled) {\n const prev = previous.current;\n changed.current = prev\n ? deps.map((d, i) => (Object.is(d, prev[i]) ? -1 : i)).filter((i) => i >= 0)\n : [];\n previous.current = deps;\n }\n\n useEffect(() => {\n if (detective.enabled && detective.config.mode !== \"silent\" && changed.current.length > 0) {\n // eslint-disable-next-line no-console\n console.debug(`[RRD] effect ${name} ran — deps changed at index ${changed.current.join(\", \")}`);\n }\n return effect();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, deps);\n}\n\n/**\n * Reports when a context value changes, from inside the provider.\n * Returns the value untouched.\n */\nexport function useTrackedContextValue<T>(contextName: string, value: T): T {\n const detective = getDetective();\n const previous = useRef<T | undefined>(undefined);\n const first = useRef(true);\n\n if (detective.enabled) {\n if (first.current) {\n first.current = false;\n } else if (!Object.is(previous.current, value)) {\n const prev = previous.current;\n const equal = shallowEqual(prev, value, detective.config);\n const changedKeys =\n isRecord(prev) && isRecord(value)\n ? diffProps(prev, value, detective.config).changed.map((c) => c.key)\n : [];\n detective.recordContextChange({\n contextName,\n changedKeys,\n referenceOnly: equal === true,\n commitTime: -1,\n });\n }\n previous.current = value;\n }\n\n return value;\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n","import { attachConsoleReporter } from \"./console/reporter.js\";\nimport { explainEvents, formatExplanation } from \"./core/explain.js\";\nimport { formatInteraction, InteractionTracker, summarise } from \"./core/interactions.js\";\nimport type { InteractionRecord, InteractionSummary } from \"./core/interactions.js\";\nimport { formatOpportunities, rankOpportunities } from \"./core/opportunities.js\";\nimport type { Opportunity } from \"./core/opportunities.js\";\nimport { getDetective } from \"./core/store.js\";\nimport { profileFromEvents } from \"./testing/index.js\";\nimport type { RenderProfile } from \"./testing/index.js\";\nimport type {\n AppStats,\n ComponentStats,\n DetectiveConfig,\n DetectiveOptions,\n RenderEvent,\n} from \"./core/types.js\";\n\nconst REPORTER = Symbol.for(\"react-render-detective.reporter\");\nconst INTERACTIONS = Symbol.for(\"react-render-detective.interactions\");\ntype Global = typeof globalThis & { [REPORTER]?: () => void; [INTERACTIONS]?: InteractionTracker };\n\nfunction tracker(): InteractionTracker {\n const g = globalThis as Global;\n if (!g[INTERACTIONS]) g[INTERACTIONS] = new InteractionTracker();\n return g[INTERACTIONS] as InteractionTracker;\n}\n\n/**\n * Enable diagnostics. Safe to call repeatedly — Fast Refresh, duplicate module\n * copies and re-entrant setup all reconfigure the single instance rather than\n * stacking listeners (§47).\n */\nexport function init(options: DetectiveOptions = {}): void {\n const detective = getDetective();\n detective.init(options);\n\n const g = globalThis as Global;\n g[REPORTER]?.();\n g[REPORTER] = undefined;\n\n if (detective.enabled) {\n // Browsers without `event` timing simply report no interactions.\n tracker().start();\n }\n\n if (detective.enabled && detective.config.mode !== \"silent\") {\n g[REPORTER] = attachConsoleReporter(detective);\n } else if (!detective.enabled) {\n // Never fail silently: a disabled detective looks identical to a broken one.\n console.info(\n \"[RRD] Diagnostics are disabled\" +\n (detective.config.enabled === false ? \" (enabled: false, or a production build was detected).\" : \".\"),\n );\n }\n}\n\n/** Update configuration without re-initialising. */\nexport function configure(options: DetectiveOptions): void {\n getDetective().configure(options);\n}\n\nexport function getConfig(): Readonly<DetectiveConfig> {\n return getDetective().config;\n}\n\nexport function isEnabled(): boolean {\n return getDetective().enabled;\n}\n\n/** Oldest → newest, bounded by `maxEvents`. */\nexport function getEvents(): RenderEvent[] {\n return getDetective().getEvents();\n}\n\nexport function getStats(): AppStats {\n return getDetective().getStats();\n}\n\nexport function getComponentStats(name?: string): ComponentStats[] {\n return getDetective().getComponentStats(name);\n}\n\n/** Live event stream. Returns an unsubscribe function. */\nexport function subscribe(listener: (event: RenderEvent) => void): () => void {\n return getDetective().subscribe(listener);\n}\n\n/** Clears recorded events and statistics; instrumentation stays attached. */\nexport function clear(): void {\n getDetective().clear();\n tracker().clear();\n}\n\n/** Full teardown, including configuration. Mainly for tests and HMR disposal. */\nexport function reset(): void {\n const g = globalThis as Global;\n g[REPORTER]?.();\n g[REPORTER] = undefined;\n g[INTERACTIONS]?.stop();\n g[INTERACTIONS] = undefined;\n getDetective().reset();\n}\n\n/**\n * The flagship answer: aggregate every recorded render of one component into a\n * single, human explanation. Returns `undefined` if nothing was recorded.\n */\nexport function explain(componentName: string): string | undefined {\n const explanation = explainStructured(componentName);\n return explanation ? formatExplanation(explanation) : undefined;\n}\n\n/** Structured form of `explain`, for building UIs on top. */\nexport function explainStructured(componentName: string) {\n return explainEvents(componentName, getEvents(), getDetective().lifecycleOf(componentName));\n}\n\n/** Snapshot render behaviour for regression testing. See `react-render-detective/testing`. */\nexport function getRenderProfile(scenario: string): RenderProfile {\n const remounts: Record<string, number> = {};\n for (const stats of getDetective().getComponentStats()) remounts[stats.name] = stats.remountCount;\n return profileFromEvents(scenario, getEvents(), remounts);\n}\n\n/**\n * Interactions, slowest first, with the renders that happened inside each.\n *\n * This is the bridge from render causality to what a user actually feels: the\n * browser reports how long the interaction took, and the render events say\n * which components spent that time and why.\n */\nexport function getInteractions(): InteractionRecord[] {\n return tracker().attribute(getEvents());\n}\n\n/** Structured analysis of one interaction. Defaults to the slowest recorded. */\nexport function explainInteractionStructured(id?: string): InteractionSummary | undefined {\n const records = getInteractions();\n const record = id ? records.find((r) => r.id === id) : records[0];\n return record ? summarise(record) : undefined;\n}\n\nexport function explainInteraction(id?: string): string | undefined {\n const summary = explainInteractionStructured(id);\n return summary ? formatInteraction(summary) : undefined;\n}\n\nexport function printInteractions(limit = 5): void {\n const records = getInteractions().slice(0, limit);\n if (records.length === 0) {\n console.log(\n tracker().automatic\n ? \"No interactions recorded yet. Event timing is working — nothing has taken longer than 16ms.\\n\" +\n \"Synthetic clicks from a test harness never produce these entries; use measureInteraction() there.\"\n : \"This browser does not report event timing (Safari before 16.4, jsdom).\\n\" +\n \"Use measureInteraction(label, fn) to time interactions by hand.\",\n );\n return;\n }\n console.log(records.map((r) => formatInteraction(summarise(r))).join(\"\\n\\n\"));\n}\n\n/**\n * Time one interaction explicitly, up to the paint that follows it.\n *\n * Needed wherever the automatic path cannot see: Safari before 16.4, and any\n * synthetic input, which never produces Event Timing entries.\n */\nexport function measureInteraction<T>(label: string, action: () => T): T {\n return tracker().measure(label, action);\n}\n\n/**\n * Components ranked by estimated recoverable time — the triage view. Render\n * counts answer the wrong question; this answers \"what should I fix first?\".\n */\nexport function getOpportunities(limit = 10): Opportunity[] {\n const detective = getDetective();\n const lifecycles = new Map<string, { remounts: number }>();\n for (const stats of detective.getComponentStats()) {\n lifecycles.set(stats.name, { remounts: stats.remountCount });\n }\n return rankOpportunities({ events: detective.getEvents(), lifecycles }).slice(0, limit);\n}\n\nexport function printOpportunities(limit = 10): void {\n console.log(formatOpportunities(getOpportunities(limit)));\n}\n\n/** Prints the application-level dashboard (§53). */\nexport function printStats(): void {\n const s = getStats();\n const lines = [\n \"React Render Detective\",\n \"\",\n `Components ${s.components}`,\n `Total renders ${s.totalRenders}`,\n `Total render time ${s.totalRenderTime.toFixed(1)}ms`,\n `Slow renders ${s.slowRenders}`,\n `Potentially avoidable ${s.potentiallyAvoidableRenders}`,\n ];\n const rebuilt = s.mostRendered.filter((c) => c.remountCount >= 2);\n if (rebuilt.length > 0) {\n lines.push(\n \"\",\n \"Rebuilt rather than re-rendered (state and DOM discarded each time)\",\n ...rebuilt.slice(0, 5).map((c) => ` ${c.name.padEnd(22)} ${String(c.remountCount).padStart(5)}× remounted`),\n );\n }\n if (s.devReplays > 0) {\n lines.push(`Development replays ${s.devReplays} (StrictMode / discarded — not counted above)`);\n }\n if (s.mostExpensive.length > 0) {\n lines.push(\"\", \"Top by cumulative render time\");\n for (const [i, c] of s.mostExpensive.slice(0, 5).entries()) {\n lines.push(\n `${String(i + 1).padStart(2)}. ${c.name.padEnd(22)} ${String(c.renderCount).padStart(6)} renders ${c.totalSelfDuration\n .toFixed(1)\n .padStart(8)}ms (avg ${c.averageSelfDuration.toFixed(1)}ms, p95 ${c.p95SelfDuration.toFixed(1)}ms)`,\n );\n }\n }\n console.log(lines.join(\"\\n\"));\n}\n\n/** Namespaced form, matching the documented `ReactRenderDetective.init()` usage. */\nexport const ReactRenderDetective = {\n init,\n configure,\n getConfig,\n isEnabled,\n getEvents,\n getStats,\n getComponentStats,\n subscribe,\n clear,\n reset,\n explain,\n explainStructured,\n getOpportunities,\n printOpportunities,\n getInteractions,\n explainInteraction,\n explainInteractionStructured,\n printInteractions,\n measureInteraction,\n getRenderProfile,\n printStats,\n};\n\nexport { withRenderDetective } from \"./react/withRenderDetective.js\";\nexport { RenderDetective } from \"./react/RenderDetective.js\";\nexport type { RenderDetectiveProps } from \"./react/RenderDetective.js\";\nexport {\n useRenderDiagnostics,\n useTrackedState,\n useTrackedEffect,\n useTrackedContextValue,\n} from \"./react/hooks.js\";\nexport type { TrackOptions } from \"./react/instrument.js\";\nexport { explainEvents, formatExplanation } from \"./core/explain.js\";\nexport { rankOpportunities, formatOpportunities } from \"./core/opportunities.js\";\nexport { InteractionTracker, summarise as summariseInteraction, formatInteraction } from \"./core/interactions.js\";\nexport type { InteractionRecord, InteractionSummary } from \"./core/interactions.js\";\nexport type { Opportunity } from \"./core/opportunities.js\";\nexport type { Explanation } from \"./core/explain.js\";\nexport type * from \"./core/types.js\";\n"]}
|
package/dist/overlay.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkJD4IJ4MN_cjs = require('./chunk-JD4IJ4MN.cjs');
|
|
4
|
+
var chunkDZ3BZ654_cjs = require('./chunk-DZ3BZ654.cjs');
|
|
5
5
|
|
|
6
6
|
// src/overlay/overlay.ts
|
|
7
7
|
var MOUNTED = /* @__PURE__ */ Symbol.for("react-render-detective.overlay");
|
|
@@ -15,7 +15,7 @@ function mountOverlay() {
|
|
|
15
15
|
} };
|
|
16
16
|
return noop;
|
|
17
17
|
}
|
|
18
|
-
const detective =
|
|
18
|
+
const detective = chunkDZ3BZ654_cjs.getDetective();
|
|
19
19
|
const root = document.createElement("div");
|
|
20
20
|
root.setAttribute("data-rrd-overlay", "");
|
|
21
21
|
root.attachShadow({ mode: "open" });
|
|
@@ -68,7 +68,7 @@ function mountOverlay() {
|
|
|
68
68
|
const rows = stats.mostExpensive.concat(stats.mostRendered).filter((s, i, arr) => arr.findIndex((o) => o.name === s.name) === i).filter((s) => !filter || s.name.toLowerCase().includes(filter)).sort((a, b) => b.totalSelfDuration - a.totalSelfDuration).slice(0, 40);
|
|
69
69
|
listEl.innerHTML = rows.map((s) => {
|
|
70
70
|
const waste = s.potentiallyAvoidableRenders;
|
|
71
|
-
const flag = waste > 0 ? `<span class="warn">${waste} avoidable</span>` : "";
|
|
71
|
+
const flag = s.remountCount >= 2 ? `<span class="warn">${s.remountCount}\xD7 rebuilt</span>` : waste > 0 ? `<span class="warn">${waste} avoidable</span>` : "";
|
|
72
72
|
return `<div class="row${s.name === selected ? " sel" : ""}" data-name="${escapeHtml(s.name)}" title="${escapeHtml(s.source ?? s.name)}">
|
|
73
73
|
<span class="name">${escapeHtml(s.name)}</span>
|
|
74
74
|
<span class="num">${s.renderCount}</span>
|
|
@@ -77,8 +77,8 @@ function mountOverlay() {
|
|
|
77
77
|
</div>`;
|
|
78
78
|
}).join("");
|
|
79
79
|
if (selected) {
|
|
80
|
-
const explanation =
|
|
81
|
-
detailEl.textContent = explanation ?
|
|
80
|
+
const explanation = chunkJD4IJ4MN_cjs.explainEvents(selected, detective.getEvents(), detective.lifecycleOf(selected));
|
|
81
|
+
detailEl.textContent = explanation ? chunkJD4IJ4MN_cjs.formatExplanation(explanation) : `No recorded renders for ${selected}.`;
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
const handle = {
|
package/dist/overlay.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/overlay/overlay.ts"],"names":["getDetective","explainEvents","formatExplanation"],"mappings":"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","file":"overlay.cjs","sourcesContent":["import { explainEvents, formatExplanation } from \"../core/explain.js\";\nimport { getDetective } from \"../core/store.js\";\nimport type { RenderEvent } from \"../core/types.js\";\n\nexport interface OverlayHandle {\n destroy: () => void;\n show: () => void;\n hide: () => void;\n}\n\nconst MOUNTED = Symbol.for(\"react-render-detective.overlay\");\ntype Global = typeof globalThis & { [MOUNTED]?: OverlayHandle };\n\n/**\n * Development overlay.\n *\n * Deliberately plain DOM: rendering the inspector *inside* the app's React tree\n * would add renders to the tree it is measuring. It consumes the same event\n * model as console mode — no diagnostic logic is duplicated here (§68).\n */\nexport function mountOverlay(): OverlayHandle {\n const g = globalThis as Global;\n if (g[MOUNTED]) return g[MOUNTED] as OverlayHandle;\n if (typeof document === \"undefined\") {\n const noop: OverlayHandle = { destroy: () => {}, show: () => {}, hide: () => {} };\n return noop;\n }\n\n const detective = getDetective();\n const root = document.createElement(\"div\");\n root.setAttribute(\"data-rrd-overlay\", \"\");\n root.attachShadow({ mode: \"open\" });\n const shadow = root.shadowRoot as ShadowRoot;\n shadow.innerHTML = TEMPLATE;\n document.body.appendChild(root);\n\n const $ = <T extends HTMLElement>(sel: string): T => shadow.querySelector(sel) as T;\n const listEl = $<HTMLDivElement>(\"#list\");\n const detailEl = $<HTMLPreElement>(\"#detail\");\n const filterEl = $<HTMLInputElement>(\"#filter\");\n const summaryEl = $<HTMLDivElement>(\"#summary\");\n const panelEl = $<HTMLDivElement>(\"#panel\");\n\n let selected: string | undefined;\n let paused = false;\n let dirty = true;\n let filter = \"\";\n const recent: RenderEvent[] = [];\n\n const unsubscribe = detective.subscribe((event) => {\n if (paused) return;\n recent.push(event);\n if (recent.length > 200) recent.shift();\n dirty = true;\n });\n\n filterEl.addEventListener(\"input\", () => {\n filter = filterEl.value.trim().toLowerCase();\n dirty = true;\n });\n $(\"#pause\").addEventListener(\"click\", () => {\n paused = !paused;\n ($(\"#pause\") as HTMLButtonElement).textContent = paused ? \"Resume\" : \"Pause\";\n });\n $(\"#clear\").addEventListener(\"click\", () => {\n detective.clear();\n recent.length = 0;\n selected = undefined;\n detailEl.textContent = \"\";\n dirty = true;\n });\n $(\"#close\").addEventListener(\"click\", () => handle.hide());\n listEl.addEventListener(\"click\", (e) => {\n const row = (e.target as HTMLElement).closest(\"[data-name]\") as HTMLElement | null;\n if (!row) return;\n selected = row.dataset.name as string;\n dirty = true;\n });\n\n const timer = setInterval(() => {\n if (!dirty || panelEl.hidden) return;\n dirty = false;\n render();\n }, 400);\n\n function render(): void {\n const stats = detective.getStats();\n summaryEl.textContent =\n `${stats.totalRenders} renders · ${stats.totalRenderTime.toFixed(0)}ms · ` +\n `${stats.potentiallyAvoidableRenders} potentially avoidable` +\n (stats.devReplays > 0 ? ` · ${stats.devReplays} dev replays` : \"\");\n\n const rows = stats.mostExpensive\n .concat(stats.mostRendered)\n .filter((s, i, arr) => arr.findIndex((o) => o.name === s.name) === i)\n .filter((s) => !filter || s.name.toLowerCase().includes(filter))\n .sort((a, b) => b.totalSelfDuration - a.totalSelfDuration)\n .slice(0, 40);\n\n listEl.innerHTML = rows\n .map((s) => {\n const waste = s.potentiallyAvoidableRenders;\n const flag = waste > 0 ? `<span class=\"warn\">${waste} avoidable</span>` : \"\";\n return `<div class=\"row${s.name === selected ? \" sel\" : \"\"}\" data-name=\"${escapeHtml(s.name)}\" title=\"${escapeHtml(s.source ?? s.name)}\">\n <span class=\"name\">${escapeHtml(s.name)}</span>\n <span class=\"num\">${s.renderCount}</span>\n <span class=\"num\">${s.totalSelfDuration.toFixed(0)}ms</span>\n ${flag}\n </div>`;\n })\n .join(\"\");\n\n if (selected) {\n const explanation = explainEvents(selected, detective.getEvents());\n detailEl.textContent = explanation ? formatExplanation(explanation) : `No recorded renders for ${selected}.`;\n }\n }\n\n const handle: OverlayHandle = {\n destroy() {\n unsubscribe();\n clearInterval(timer);\n root.remove();\n (globalThis as Global)[MOUNTED] = undefined;\n },\n show() {\n panelEl.hidden = false;\n dirty = true;\n },\n hide() {\n panelEl.hidden = true;\n },\n };\n\n g[MOUNTED] = handle;\n return handle;\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"]/g, (c) => ({ \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\" })[c] as string);\n}\n\nconst TEMPLATE = `\n<style>\n :host { all: initial; }\n #panel {\n position: fixed; right: 16px; bottom: 16px; width: 460px; max-height: 70vh;\n display: flex; flex-direction: column; z-index: 2147483000;\n font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;\n background: #14161a; color: #e6e6e6; border: 1px solid #2b2f36; border-radius: 10px;\n box-shadow: 0 12px 40px rgba(0,0,0,.45); overflow: hidden;\n }\n header { display: flex; gap: 8px; align-items: center; padding: 8px 10px; background: #1b1e24; border-bottom: 1px solid #2b2f36; }\n header b { font-weight: 600; letter-spacing: .02em; }\n header .spacer { flex: 1; }\n button, input { font: inherit; color: inherit; background: #23272e; border: 1px solid #333842; border-radius: 6px; padding: 3px 8px; }\n button { cursor: pointer; }\n #summary { padding: 6px 10px; color: #9aa4b2; border-bottom: 1px solid #2b2f36; }\n #list { overflow: auto; max-height: 30vh; }\n .row { display: flex; gap: 8px; padding: 4px 10px; cursor: pointer; align-items: baseline; }\n .row:hover { background: #1d2128; }\n .row.sel { background: #263041; }\n .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .num { color: #9aa4b2; min-width: 56px; text-align: right; }\n .warn { color: #f2b263; }\n #detail { margin: 0; padding: 10px; overflow: auto; white-space: pre-wrap; border-top: 1px solid #2b2f36; color: #cfd6df; }\n</style>\n<div id=\"panel\">\n <header>\n <b>Render Detective</b>\n <span class=\"spacer\"></span>\n <input id=\"filter\" placeholder=\"filter\" size=\"10\" />\n <button id=\"pause\">Pause</button>\n <button id=\"clear\">Clear</button>\n <button id=\"close\">×</button>\n </header>\n <div id=\"summary\"></div>\n <div id=\"list\"></div>\n <pre id=\"detail\">Select a component to see why it rendered.</pre>\n</div>\n`;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/overlay/overlay.ts"],"names":["getDetective","explainEvents","formatExplanation"],"mappings":"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","file":"overlay.cjs","sourcesContent":["import { explainEvents, formatExplanation } from \"../core/explain.js\";\nimport { getDetective } from \"../core/store.js\";\nimport type { RenderEvent } from \"../core/types.js\";\n\nexport interface OverlayHandle {\n destroy: () => void;\n show: () => void;\n hide: () => void;\n}\n\nconst MOUNTED = Symbol.for(\"react-render-detective.overlay\");\ntype Global = typeof globalThis & { [MOUNTED]?: OverlayHandle };\n\n/**\n * Development overlay.\n *\n * Deliberately plain DOM: rendering the inspector *inside* the app's React tree\n * would add renders to the tree it is measuring. It consumes the same event\n * model as console mode — no diagnostic logic is duplicated here (§68).\n */\nexport function mountOverlay(): OverlayHandle {\n const g = globalThis as Global;\n if (g[MOUNTED]) return g[MOUNTED] as OverlayHandle;\n if (typeof document === \"undefined\") {\n const noop: OverlayHandle = { destroy: () => {}, show: () => {}, hide: () => {} };\n return noop;\n }\n\n const detective = getDetective();\n const root = document.createElement(\"div\");\n root.setAttribute(\"data-rrd-overlay\", \"\");\n root.attachShadow({ mode: \"open\" });\n const shadow = root.shadowRoot as ShadowRoot;\n shadow.innerHTML = TEMPLATE;\n document.body.appendChild(root);\n\n const $ = <T extends HTMLElement>(sel: string): T => shadow.querySelector(sel) as T;\n const listEl = $<HTMLDivElement>(\"#list\");\n const detailEl = $<HTMLPreElement>(\"#detail\");\n const filterEl = $<HTMLInputElement>(\"#filter\");\n const summaryEl = $<HTMLDivElement>(\"#summary\");\n const panelEl = $<HTMLDivElement>(\"#panel\");\n\n let selected: string | undefined;\n let paused = false;\n let dirty = true;\n let filter = \"\";\n const recent: RenderEvent[] = [];\n\n const unsubscribe = detective.subscribe((event) => {\n if (paused) return;\n recent.push(event);\n if (recent.length > 200) recent.shift();\n dirty = true;\n });\n\n filterEl.addEventListener(\"input\", () => {\n filter = filterEl.value.trim().toLowerCase();\n dirty = true;\n });\n $(\"#pause\").addEventListener(\"click\", () => {\n paused = !paused;\n ($(\"#pause\") as HTMLButtonElement).textContent = paused ? \"Resume\" : \"Pause\";\n });\n $(\"#clear\").addEventListener(\"click\", () => {\n detective.clear();\n recent.length = 0;\n selected = undefined;\n detailEl.textContent = \"\";\n dirty = true;\n });\n $(\"#close\").addEventListener(\"click\", () => handle.hide());\n listEl.addEventListener(\"click\", (e) => {\n const row = (e.target as HTMLElement).closest(\"[data-name]\") as HTMLElement | null;\n if (!row) return;\n selected = row.dataset.name as string;\n dirty = true;\n });\n\n const timer = setInterval(() => {\n if (!dirty || panelEl.hidden) return;\n dirty = false;\n render();\n }, 400);\n\n function render(): void {\n const stats = detective.getStats();\n summaryEl.textContent =\n `${stats.totalRenders} renders · ${stats.totalRenderTime.toFixed(0)}ms · ` +\n `${stats.potentiallyAvoidableRenders} potentially avoidable` +\n (stats.devReplays > 0 ? ` · ${stats.devReplays} dev replays` : \"\");\n\n const rows = stats.mostExpensive\n .concat(stats.mostRendered)\n .filter((s, i, arr) => arr.findIndex((o) => o.name === s.name) === i)\n .filter((s) => !filter || s.name.toLowerCase().includes(filter))\n .sort((a, b) => b.totalSelfDuration - a.totalSelfDuration)\n .slice(0, 40);\n\n listEl.innerHTML = rows\n .map((s) => {\n const waste = s.potentiallyAvoidableRenders;\n const flag =\n s.remountCount >= 2\n ? `<span class=\"warn\">${s.remountCount}× rebuilt</span>`\n : waste > 0\n ? `<span class=\"warn\">${waste} avoidable</span>`\n : \"\";\n return `<div class=\"row${s.name === selected ? \" sel\" : \"\"}\" data-name=\"${escapeHtml(s.name)}\" title=\"${escapeHtml(s.source ?? s.name)}\">\n <span class=\"name\">${escapeHtml(s.name)}</span>\n <span class=\"num\">${s.renderCount}</span>\n <span class=\"num\">${s.totalSelfDuration.toFixed(0)}ms</span>\n ${flag}\n </div>`;\n })\n .join(\"\");\n\n if (selected) {\n const explanation = explainEvents(selected, detective.getEvents(), detective.lifecycleOf(selected));\n detailEl.textContent = explanation ? formatExplanation(explanation) : `No recorded renders for ${selected}.`;\n }\n }\n\n const handle: OverlayHandle = {\n destroy() {\n unsubscribe();\n clearInterval(timer);\n root.remove();\n (globalThis as Global)[MOUNTED] = undefined;\n },\n show() {\n panelEl.hidden = false;\n dirty = true;\n },\n hide() {\n panelEl.hidden = true;\n },\n };\n\n g[MOUNTED] = handle;\n return handle;\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"]/g, (c) => ({ \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\" })[c] as string);\n}\n\nconst TEMPLATE = `\n<style>\n :host { all: initial; }\n #panel {\n position: fixed; right: 16px; bottom: 16px; width: 460px; max-height: 70vh;\n display: flex; flex-direction: column; z-index: 2147483000;\n font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;\n background: #14161a; color: #e6e6e6; border: 1px solid #2b2f36; border-radius: 10px;\n box-shadow: 0 12px 40px rgba(0,0,0,.45); overflow: hidden;\n }\n header { display: flex; gap: 8px; align-items: center; padding: 8px 10px; background: #1b1e24; border-bottom: 1px solid #2b2f36; }\n header b { font-weight: 600; letter-spacing: .02em; }\n header .spacer { flex: 1; }\n button, input { font: inherit; color: inherit; background: #23272e; border: 1px solid #333842; border-radius: 6px; padding: 3px 8px; }\n button { cursor: pointer; }\n #summary { padding: 6px 10px; color: #9aa4b2; border-bottom: 1px solid #2b2f36; }\n #list { overflow: auto; max-height: 30vh; }\n .row { display: flex; gap: 8px; padding: 4px 10px; cursor: pointer; align-items: baseline; }\n .row:hover { background: #1d2128; }\n .row.sel { background: #263041; }\n .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .num { color: #9aa4b2; min-width: 56px; text-align: right; }\n .warn { color: #f2b263; }\n #detail { margin: 0; padding: 10px; overflow: auto; white-space: pre-wrap; border-top: 1px solid #2b2f36; color: #cfd6df; }\n</style>\n<div id=\"panel\">\n <header>\n <b>Render Detective</b>\n <span class=\"spacer\"></span>\n <input id=\"filter\" placeholder=\"filter\" size=\"10\" />\n <button id=\"pause\">Pause</button>\n <button id=\"clear\">Clear</button>\n <button id=\"close\">×</button>\n </header>\n <div id=\"summary\"></div>\n <div id=\"list\"></div>\n <pre id=\"detail\">Select a component to see why it rendered.</pre>\n</div>\n`;\n"]}
|
package/dist/overlay.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { explainEvents, formatExplanation } from './chunk-
|
|
2
|
-
import { getDetective } from './chunk-
|
|
1
|
+
import { explainEvents, formatExplanation } from './chunk-HOTY7J3X.js';
|
|
2
|
+
import { getDetective } from './chunk-QOGTEVBP.js';
|
|
3
3
|
|
|
4
4
|
// src/overlay/overlay.ts
|
|
5
5
|
var MOUNTED = /* @__PURE__ */ Symbol.for("react-render-detective.overlay");
|
|
@@ -66,7 +66,7 @@ function mountOverlay() {
|
|
|
66
66
|
const rows = stats.mostExpensive.concat(stats.mostRendered).filter((s, i, arr) => arr.findIndex((o) => o.name === s.name) === i).filter((s) => !filter || s.name.toLowerCase().includes(filter)).sort((a, b) => b.totalSelfDuration - a.totalSelfDuration).slice(0, 40);
|
|
67
67
|
listEl.innerHTML = rows.map((s) => {
|
|
68
68
|
const waste = s.potentiallyAvoidableRenders;
|
|
69
|
-
const flag = waste > 0 ? `<span class="warn">${waste} avoidable</span>` : "";
|
|
69
|
+
const flag = s.remountCount >= 2 ? `<span class="warn">${s.remountCount}\xD7 rebuilt</span>` : waste > 0 ? `<span class="warn">${waste} avoidable</span>` : "";
|
|
70
70
|
return `<div class="row${s.name === selected ? " sel" : ""}" data-name="${escapeHtml(s.name)}" title="${escapeHtml(s.source ?? s.name)}">
|
|
71
71
|
<span class="name">${escapeHtml(s.name)}</span>
|
|
72
72
|
<span class="num">${s.renderCount}</span>
|
|
@@ -75,7 +75,7 @@ function mountOverlay() {
|
|
|
75
75
|
</div>`;
|
|
76
76
|
}).join("");
|
|
77
77
|
if (selected) {
|
|
78
|
-
const explanation = explainEvents(selected, detective.getEvents());
|
|
78
|
+
const explanation = explainEvents(selected, detective.getEvents(), detective.lifecycleOf(selected));
|
|
79
79
|
detailEl.textContent = explanation ? formatExplanation(explanation) : `No recorded renders for ${selected}.`;
|
|
80
80
|
}
|
|
81
81
|
}
|
package/dist/overlay.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/overlay/overlay.ts"],"names":[],"mappings":"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","file":"overlay.js","sourcesContent":["import { explainEvents, formatExplanation } from \"../core/explain.js\";\nimport { getDetective } from \"../core/store.js\";\nimport type { RenderEvent } from \"../core/types.js\";\n\nexport interface OverlayHandle {\n destroy: () => void;\n show: () => void;\n hide: () => void;\n}\n\nconst MOUNTED = Symbol.for(\"react-render-detective.overlay\");\ntype Global = typeof globalThis & { [MOUNTED]?: OverlayHandle };\n\n/**\n * Development overlay.\n *\n * Deliberately plain DOM: rendering the inspector *inside* the app's React tree\n * would add renders to the tree it is measuring. It consumes the same event\n * model as console mode — no diagnostic logic is duplicated here (§68).\n */\nexport function mountOverlay(): OverlayHandle {\n const g = globalThis as Global;\n if (g[MOUNTED]) return g[MOUNTED] as OverlayHandle;\n if (typeof document === \"undefined\") {\n const noop: OverlayHandle = { destroy: () => {}, show: () => {}, hide: () => {} };\n return noop;\n }\n\n const detective = getDetective();\n const root = document.createElement(\"div\");\n root.setAttribute(\"data-rrd-overlay\", \"\");\n root.attachShadow({ mode: \"open\" });\n const shadow = root.shadowRoot as ShadowRoot;\n shadow.innerHTML = TEMPLATE;\n document.body.appendChild(root);\n\n const $ = <T extends HTMLElement>(sel: string): T => shadow.querySelector(sel) as T;\n const listEl = $<HTMLDivElement>(\"#list\");\n const detailEl = $<HTMLPreElement>(\"#detail\");\n const filterEl = $<HTMLInputElement>(\"#filter\");\n const summaryEl = $<HTMLDivElement>(\"#summary\");\n const panelEl = $<HTMLDivElement>(\"#panel\");\n\n let selected: string | undefined;\n let paused = false;\n let dirty = true;\n let filter = \"\";\n const recent: RenderEvent[] = [];\n\n const unsubscribe = detective.subscribe((event) => {\n if (paused) return;\n recent.push(event);\n if (recent.length > 200) recent.shift();\n dirty = true;\n });\n\n filterEl.addEventListener(\"input\", () => {\n filter = filterEl.value.trim().toLowerCase();\n dirty = true;\n });\n $(\"#pause\").addEventListener(\"click\", () => {\n paused = !paused;\n ($(\"#pause\") as HTMLButtonElement).textContent = paused ? \"Resume\" : \"Pause\";\n });\n $(\"#clear\").addEventListener(\"click\", () => {\n detective.clear();\n recent.length = 0;\n selected = undefined;\n detailEl.textContent = \"\";\n dirty = true;\n });\n $(\"#close\").addEventListener(\"click\", () => handle.hide());\n listEl.addEventListener(\"click\", (e) => {\n const row = (e.target as HTMLElement).closest(\"[data-name]\") as HTMLElement | null;\n if (!row) return;\n selected = row.dataset.name as string;\n dirty = true;\n });\n\n const timer = setInterval(() => {\n if (!dirty || panelEl.hidden) return;\n dirty = false;\n render();\n }, 400);\n\n function render(): void {\n const stats = detective.getStats();\n summaryEl.textContent =\n `${stats.totalRenders} renders · ${stats.totalRenderTime.toFixed(0)}ms · ` +\n `${stats.potentiallyAvoidableRenders} potentially avoidable` +\n (stats.devReplays > 0 ? ` · ${stats.devReplays} dev replays` : \"\");\n\n const rows = stats.mostExpensive\n .concat(stats.mostRendered)\n .filter((s, i, arr) => arr.findIndex((o) => o.name === s.name) === i)\n .filter((s) => !filter || s.name.toLowerCase().includes(filter))\n .sort((a, b) => b.totalSelfDuration - a.totalSelfDuration)\n .slice(0, 40);\n\n listEl.innerHTML = rows\n .map((s) => {\n const waste = s.potentiallyAvoidableRenders;\n const flag = waste > 0 ? `<span class=\"warn\">${waste} avoidable</span>` : \"\";\n return `<div class=\"row${s.name === selected ? \" sel\" : \"\"}\" data-name=\"${escapeHtml(s.name)}\" title=\"${escapeHtml(s.source ?? s.name)}\">\n <span class=\"name\">${escapeHtml(s.name)}</span>\n <span class=\"num\">${s.renderCount}</span>\n <span class=\"num\">${s.totalSelfDuration.toFixed(0)}ms</span>\n ${flag}\n </div>`;\n })\n .join(\"\");\n\n if (selected) {\n const explanation = explainEvents(selected, detective.getEvents());\n detailEl.textContent = explanation ? formatExplanation(explanation) : `No recorded renders for ${selected}.`;\n }\n }\n\n const handle: OverlayHandle = {\n destroy() {\n unsubscribe();\n clearInterval(timer);\n root.remove();\n (globalThis as Global)[MOUNTED] = undefined;\n },\n show() {\n panelEl.hidden = false;\n dirty = true;\n },\n hide() {\n panelEl.hidden = true;\n },\n };\n\n g[MOUNTED] = handle;\n return handle;\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"]/g, (c) => ({ \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\" })[c] as string);\n}\n\nconst TEMPLATE = `\n<style>\n :host { all: initial; }\n #panel {\n position: fixed; right: 16px; bottom: 16px; width: 460px; max-height: 70vh;\n display: flex; flex-direction: column; z-index: 2147483000;\n font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;\n background: #14161a; color: #e6e6e6; border: 1px solid #2b2f36; border-radius: 10px;\n box-shadow: 0 12px 40px rgba(0,0,0,.45); overflow: hidden;\n }\n header { display: flex; gap: 8px; align-items: center; padding: 8px 10px; background: #1b1e24; border-bottom: 1px solid #2b2f36; }\n header b { font-weight: 600; letter-spacing: .02em; }\n header .spacer { flex: 1; }\n button, input { font: inherit; color: inherit; background: #23272e; border: 1px solid #333842; border-radius: 6px; padding: 3px 8px; }\n button { cursor: pointer; }\n #summary { padding: 6px 10px; color: #9aa4b2; border-bottom: 1px solid #2b2f36; }\n #list { overflow: auto; max-height: 30vh; }\n .row { display: flex; gap: 8px; padding: 4px 10px; cursor: pointer; align-items: baseline; }\n .row:hover { background: #1d2128; }\n .row.sel { background: #263041; }\n .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .num { color: #9aa4b2; min-width: 56px; text-align: right; }\n .warn { color: #f2b263; }\n #detail { margin: 0; padding: 10px; overflow: auto; white-space: pre-wrap; border-top: 1px solid #2b2f36; color: #cfd6df; }\n</style>\n<div id=\"panel\">\n <header>\n <b>Render Detective</b>\n <span class=\"spacer\"></span>\n <input id=\"filter\" placeholder=\"filter\" size=\"10\" />\n <button id=\"pause\">Pause</button>\n <button id=\"clear\">Clear</button>\n <button id=\"close\">×</button>\n </header>\n <div id=\"summary\"></div>\n <div id=\"list\"></div>\n <pre id=\"detail\">Select a component to see why it rendered.</pre>\n</div>\n`;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/overlay/overlay.ts"],"names":[],"mappings":";;;;AAUA,IAAM,OAAA,mBAAU,MAAA,CAAO,GAAA,CAAI,gCAAgC,CAAA;AAUpD,SAAS,YAAA,GAA8B;AAC5C,EAAA,MAAM,CAAA,GAAI,UAAA;AACV,EAAA,IAAI,CAAA,CAAE,OAAO,CAAA,EAAG,OAAO,EAAE,OAAO,CAAA;AAChC,EAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AACnC,IAAA,MAAM,IAAA,GAAsB,EAAE,OAAA,EAAS,MAAM;AAAA,IAAC,CAAA,EAAG,MAAM,MAAM;AAAA,IAAC,CAAA,EAAG,MAAM,MAAM;AAAA,IAAC,CAAA,EAAE;AAChF,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACzC,EAAA,IAAA,CAAK,YAAA,CAAa,oBAAoB,EAAE,CAAA;AACxC,EAAA,IAAA,CAAK,YAAA,CAAa,EAAE,IAAA,EAAM,MAAA,EAAQ,CAAA;AAClC,EAAA,MAAM,SAAS,IAAA,CAAK,UAAA;AACpB,EAAA,MAAA,CAAO,SAAA,GAAY,QAAA;AACnB,EAAA,QAAA,CAAS,IAAA,CAAK,YAAY,IAAI,CAAA;AAE9B,EAAA,MAAM,CAAA,GAAI,CAAwB,GAAA,KAAmB,MAAA,CAAO,cAAc,GAAG,CAAA;AAC7E,EAAA,MAAM,MAAA,GAAS,EAAkB,OAAO,CAAA;AACxC,EAAA,MAAM,QAAA,GAAW,EAAkB,SAAS,CAAA;AAC5C,EAAA,MAAM,QAAA,GAAW,EAAoB,SAAS,CAAA;AAC9C,EAAA,MAAM,SAAA,GAAY,EAAkB,UAAU,CAAA;AAC9C,EAAA,MAAM,OAAA,GAAU,EAAkB,QAAQ,CAAA;AAE1C,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI,MAAA,GAAS,KAAA;AACb,EAAA,IAAI,KAAA,GAAQ,IAAA;AACZ,EAAA,IAAI,MAAA,GAAS,EAAA;AAGb,EAAA,MAAM,WAAA,GAAc,SAAA,CAAU,SAAA,CAAU,CAAC,KAAA,KAAU;AACjD,IAAA,IAAI,MAAA,EAAQ;AAGZ,IAAA,KAAA,GAAQ,IAAA;AAAA,EACV,CAAC,CAAA;AAED,EAAA,QAAA,CAAS,gBAAA,CAAiB,SAAS,MAAM;AACvC,IAAA,MAAA,GAAS,QAAA,CAAS,KAAA,CAAM,IAAA,EAAK,CAAE,WAAA,EAAY;AAC3C,IAAA,KAAA,GAAQ,IAAA;AAAA,EACV,CAAC,CAAA;AACD,EAAA,CAAA,CAAE,QAAQ,CAAA,CAAE,gBAAA,CAAiB,OAAA,EAAS,MAAM;AAC1C,IAAA,MAAA,GAAS,CAAC,MAAA;AACV,IAAC,CAAA,CAAE,QAAQ,CAAA,CAAwB,WAAA,GAAc,SAAS,QAAA,GAAW,OAAA;AAAA,EACvE,CAAC,CAAA;AACD,EAAA,CAAA,CAAE,QAAQ,CAAA,CAAE,gBAAA,CAAiB,OAAA,EAAS,MAAM;AAC1C,IAAA,SAAA,CAAU,KAAA,EAAM;AAEhB,IAAA,QAAA,GAAW,MAAA;AACX,IAAA,QAAA,CAAS,WAAA,GAAc,EAAA;AACvB,IAAA,KAAA,GAAQ,IAAA;AAAA,EACV,CAAC,CAAA;AACD,EAAA,CAAA,CAAE,QAAQ,CAAA,CAAE,gBAAA,CAAiB,SAAS,MAAM,MAAA,CAAO,MAAM,CAAA;AACzD,EAAA,MAAA,CAAO,gBAAA,CAAiB,OAAA,EAAS,CAAC,CAAA,KAAM;AACtC,IAAA,MAAM,GAAA,GAAO,CAAA,CAAE,MAAA,CAAuB,OAAA,CAAQ,aAAa,CAAA;AAC3D,IAAA,IAAI,CAAC,GAAA,EAAK;AACV,IAAA,QAAA,GAAW,IAAI,OAAA,CAAQ,IAAA;AACvB,IAAA,KAAA,GAAQ,IAAA;AAAA,EACV,CAAC,CAAA;AAED,EAAA,MAAM,KAAA,GAAQ,YAAY,MAAM;AAC9B,IAAA,IAAI,CAAC,KAAA,IAAS,OAAA,CAAQ,MAAA,EAAQ;AAC9B,IAAA,KAAA,GAAQ,KAAA;AACR,IAAA,MAAA,EAAO;AAAA,EACT,GAAG,GAAG,CAAA;AAEN,EAAA,SAAS,MAAA,GAAe;AACtB,IAAA,MAAM,KAAA,GAAQ,UAAU,QAAA,EAAS;AACjC,IAAA,SAAA,CAAU,WAAA,GACR,GAAG,KAAA,CAAM,YAAY,iBAAc,KAAA,CAAM,eAAA,CAAgB,QAAQ,CAAC,CAAC,WAChE,KAAA,CAAM,2BAA2B,4BACnC,KAAA,CAAM,UAAA,GAAa,IAAI,CAAA,MAAA,EAAM,KAAA,CAAM,UAAU,CAAA,YAAA,CAAA,GAAiB,EAAA,CAAA;AAEjE,IAAA,MAAM,IAAA,GAAO,MAAM,aAAA,CAChB,MAAA,CAAO,MAAM,YAAY,CAAA,CACzB,OAAO,CAAC,CAAA,EAAG,GAAG,GAAA,KAAQ,GAAA,CAAI,UAAU,CAAC,CAAA,KAAM,EAAE,IAAA,KAAS,CAAA,CAAE,IAAI,CAAA,KAAM,CAAC,CAAA,CACnE,OAAO,CAAC,CAAA,KAAM,CAAC,MAAA,IAAU,CAAA,CAAE,KAAK,WAAA,EAAY,CAAE,QAAA,CAAS,MAAM,CAAC,CAAA,CAC9D,KAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,iBAAA,GAAoB,EAAE,iBAAiB,CAAA,CACxD,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAEd,IAAA,MAAA,CAAO,SAAA,GAAY,IAAA,CAChB,GAAA,CAAI,CAAC,CAAA,KAAM;AACV,MAAA,MAAM,QAAQ,CAAA,CAAE,2BAAA;AAChB,MAAA,MAAM,IAAA,GACJ,CAAA,CAAE,YAAA,IAAgB,CAAA,GACd,CAAA,mBAAA,EAAsB,CAAA,CAAE,YAAY,CAAA,mBAAA,CAAA,GACpC,KAAA,GAAQ,CAAA,GACN,CAAA,mBAAA,EAAsB,KAAK,CAAA,iBAAA,CAAA,GAC3B,EAAA;AACR,MAAA,OAAO,kBAAkB,CAAA,CAAE,IAAA,KAAS,QAAA,GAAW,MAAA,GAAS,EAAE,CAAA,aAAA,EAAgB,UAAA,CAAW,CAAA,CAAE,IAAI,CAAC,CAAA,SAAA,EAAY,UAAA,CAAW,EAAE,MAAA,IAAU,CAAA,CAAE,IAAI,CAAC,CAAA;AAAA,6BAAA,EAC/G,UAAA,CAAW,CAAA,CAAE,IAAI,CAAC,CAAA;AAAA,4BAAA,EACnB,EAAE,WAAW,CAAA;AAAA,4BAAA,EACb,CAAA,CAAE,iBAAA,CAAkB,OAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,UAAA,EAChD,IAAI;AAAA,cAAA,CAAA;AAAA,IAEV,CAAC,CAAA,CACA,IAAA,CAAK,EAAE,CAAA;AAEV,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,MAAM,WAAA,GAAc,cAAc,QAAA,EAAU,SAAA,CAAU,WAAU,EAAG,SAAA,CAAU,WAAA,CAAY,QAAQ,CAAC,CAAA;AAClG,MAAA,QAAA,CAAS,cAAc,WAAA,GAAc,iBAAA,CAAkB,WAAW,CAAA,GAAI,2BAA2B,QAAQ,CAAA,CAAA,CAAA;AAAA,IAC3G;AAAA,EACF;AAEA,EAAA,MAAM,MAAA,GAAwB;AAAA,IAC5B,OAAA,GAAU;AACR,MAAA,WAAA,EAAY;AACZ,MAAA,aAAA,CAAc,KAAK,CAAA;AACnB,MAAA,IAAA,CAAK,MAAA,EAAO;AACZ,MAAC,UAAA,CAAsB,OAAO,CAAA,GAAI,MAAA;AAAA,IACpC,CAAA;AAAA,IACA,IAAA,GAAO;AACL,MAAA,OAAA,CAAQ,MAAA,GAAS,KAAA;AACjB,MAAA,KAAA,GAAQ,IAAA;AAAA,IACV,CAAA;AAAA,IACA,IAAA,GAAO;AACL,MAAA,OAAA,CAAQ,MAAA,GAAS,IAAA;AAAA,IACnB;AAAA,GACF;AAEA,EAAA,CAAA,CAAE,OAAO,CAAA,GAAI,MAAA;AACb,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,WAAW,CAAA,EAAmB;AACrC,EAAA,OAAO,EAAE,OAAA,CAAQ,SAAA,EAAW,CAAC,CAAA,KAAA,CAAO,EAAE,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,MAAA,EAAQ,KAAK,MAAA,EAAQ,GAAA,EAAK,QAAA,EAAS,EAAG,CAAC,CAAW,CAAA;AAC7G;AAEA,IAAM,QAAA,GAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA","file":"overlay.js","sourcesContent":["import { explainEvents, formatExplanation } from \"../core/explain.js\";\nimport { getDetective } from \"../core/store.js\";\nimport type { RenderEvent } from \"../core/types.js\";\n\nexport interface OverlayHandle {\n destroy: () => void;\n show: () => void;\n hide: () => void;\n}\n\nconst MOUNTED = Symbol.for(\"react-render-detective.overlay\");\ntype Global = typeof globalThis & { [MOUNTED]?: OverlayHandle };\n\n/**\n * Development overlay.\n *\n * Deliberately plain DOM: rendering the inspector *inside* the app's React tree\n * would add renders to the tree it is measuring. It consumes the same event\n * model as console mode — no diagnostic logic is duplicated here (§68).\n */\nexport function mountOverlay(): OverlayHandle {\n const g = globalThis as Global;\n if (g[MOUNTED]) return g[MOUNTED] as OverlayHandle;\n if (typeof document === \"undefined\") {\n const noop: OverlayHandle = { destroy: () => {}, show: () => {}, hide: () => {} };\n return noop;\n }\n\n const detective = getDetective();\n const root = document.createElement(\"div\");\n root.setAttribute(\"data-rrd-overlay\", \"\");\n root.attachShadow({ mode: \"open\" });\n const shadow = root.shadowRoot as ShadowRoot;\n shadow.innerHTML = TEMPLATE;\n document.body.appendChild(root);\n\n const $ = <T extends HTMLElement>(sel: string): T => shadow.querySelector(sel) as T;\n const listEl = $<HTMLDivElement>(\"#list\");\n const detailEl = $<HTMLPreElement>(\"#detail\");\n const filterEl = $<HTMLInputElement>(\"#filter\");\n const summaryEl = $<HTMLDivElement>(\"#summary\");\n const panelEl = $<HTMLDivElement>(\"#panel\");\n\n let selected: string | undefined;\n let paused = false;\n let dirty = true;\n let filter = \"\";\n const recent: RenderEvent[] = [];\n\n const unsubscribe = detective.subscribe((event) => {\n if (paused) return;\n recent.push(event);\n if (recent.length > 200) recent.shift();\n dirty = true;\n });\n\n filterEl.addEventListener(\"input\", () => {\n filter = filterEl.value.trim().toLowerCase();\n dirty = true;\n });\n $(\"#pause\").addEventListener(\"click\", () => {\n paused = !paused;\n ($(\"#pause\") as HTMLButtonElement).textContent = paused ? \"Resume\" : \"Pause\";\n });\n $(\"#clear\").addEventListener(\"click\", () => {\n detective.clear();\n recent.length = 0;\n selected = undefined;\n detailEl.textContent = \"\";\n dirty = true;\n });\n $(\"#close\").addEventListener(\"click\", () => handle.hide());\n listEl.addEventListener(\"click\", (e) => {\n const row = (e.target as HTMLElement).closest(\"[data-name]\") as HTMLElement | null;\n if (!row) return;\n selected = row.dataset.name as string;\n dirty = true;\n });\n\n const timer = setInterval(() => {\n if (!dirty || panelEl.hidden) return;\n dirty = false;\n render();\n }, 400);\n\n function render(): void {\n const stats = detective.getStats();\n summaryEl.textContent =\n `${stats.totalRenders} renders · ${stats.totalRenderTime.toFixed(0)}ms · ` +\n `${stats.potentiallyAvoidableRenders} potentially avoidable` +\n (stats.devReplays > 0 ? ` · ${stats.devReplays} dev replays` : \"\");\n\n const rows = stats.mostExpensive\n .concat(stats.mostRendered)\n .filter((s, i, arr) => arr.findIndex((o) => o.name === s.name) === i)\n .filter((s) => !filter || s.name.toLowerCase().includes(filter))\n .sort((a, b) => b.totalSelfDuration - a.totalSelfDuration)\n .slice(0, 40);\n\n listEl.innerHTML = rows\n .map((s) => {\n const waste = s.potentiallyAvoidableRenders;\n const flag =\n s.remountCount >= 2\n ? `<span class=\"warn\">${s.remountCount}× rebuilt</span>`\n : waste > 0\n ? `<span class=\"warn\">${waste} avoidable</span>`\n : \"\";\n return `<div class=\"row${s.name === selected ? \" sel\" : \"\"}\" data-name=\"${escapeHtml(s.name)}\" title=\"${escapeHtml(s.source ?? s.name)}\">\n <span class=\"name\">${escapeHtml(s.name)}</span>\n <span class=\"num\">${s.renderCount}</span>\n <span class=\"num\">${s.totalSelfDuration.toFixed(0)}ms</span>\n ${flag}\n </div>`;\n })\n .join(\"\");\n\n if (selected) {\n const explanation = explainEvents(selected, detective.getEvents(), detective.lifecycleOf(selected));\n detailEl.textContent = explanation ? formatExplanation(explanation) : `No recorded renders for ${selected}.`;\n }\n }\n\n const handle: OverlayHandle = {\n destroy() {\n unsubscribe();\n clearInterval(timer);\n root.remove();\n (globalThis as Global)[MOUNTED] = undefined;\n },\n show() {\n panelEl.hidden = false;\n dirty = true;\n },\n hide() {\n panelEl.hidden = true;\n },\n };\n\n g[MOUNTED] = handle;\n return handle;\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"]/g, (c) => ({ \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\" })[c] as string);\n}\n\nconst TEMPLATE = `\n<style>\n :host { all: initial; }\n #panel {\n position: fixed; right: 16px; bottom: 16px; width: 460px; max-height: 70vh;\n display: flex; flex-direction: column; z-index: 2147483000;\n font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;\n background: #14161a; color: #e6e6e6; border: 1px solid #2b2f36; border-radius: 10px;\n box-shadow: 0 12px 40px rgba(0,0,0,.45); overflow: hidden;\n }\n header { display: flex; gap: 8px; align-items: center; padding: 8px 10px; background: #1b1e24; border-bottom: 1px solid #2b2f36; }\n header b { font-weight: 600; letter-spacing: .02em; }\n header .spacer { flex: 1; }\n button, input { font: inherit; color: inherit; background: #23272e; border: 1px solid #333842; border-radius: 6px; padding: 3px 8px; }\n button { cursor: pointer; }\n #summary { padding: 6px 10px; color: #9aa4b2; border-bottom: 1px solid #2b2f36; }\n #list { overflow: auto; max-height: 30vh; }\n .row { display: flex; gap: 8px; padding: 4px 10px; cursor: pointer; align-items: baseline; }\n .row:hover { background: #1d2128; }\n .row.sel { background: #263041; }\n .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .num { color: #9aa4b2; min-width: 56px; text-align: right; }\n .warn { color: #f2b263; }\n #detail { margin: 0; padding: 10px; overflow: auto; white-space: pre-wrap; border-top: 1px solid #2b2f36; color: #cfd6df; }\n</style>\n<div id=\"panel\">\n <header>\n <b>Render Detective</b>\n <span class=\"spacer\"></span>\n <input id=\"filter\" placeholder=\"filter\" size=\"10\" />\n <button id=\"pause\">Pause</button>\n <button id=\"clear\">Clear</button>\n <button id=\"close\">×</button>\n </header>\n <div id=\"summary\"></div>\n <div id=\"list\"></div>\n <pre id=\"detail\">Select a component to see why it rendered.</pre>\n</div>\n`;\n"]}
|
package/dist/testing.cjs
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkH5RG2EPP_cjs = require('./chunk-H5RG2EPP.cjs');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Object.defineProperty(exports, "assertNoRenderRegressions", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () { return chunkH5RG2EPP_cjs.assertNoRenderRegressions; }
|
|
10
|
+
});
|
|
11
|
+
Object.defineProperty(exports, "compareProfiles", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function () { return chunkH5RG2EPP_cjs.compareProfiles; }
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(exports, "profileFromEvents", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return chunkH5RG2EPP_cjs.profileFromEvents; }
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=testing.cjs.map
|
|
20
|
+
//# sourceMappingURL=testing.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"testing.cjs"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { b as RenderEvent } from './types-gl13xwmN.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Render-regression testing.
|
|
5
|
+
*
|
|
6
|
+
* Fixing a render problem once is easy; keeping it fixed is the hard part. This
|
|
7
|
+
* turns render behaviour into something a pull request can fail on: record a
|
|
8
|
+
* profile for a scripted interaction, commit it, and compare on every run.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately assertion-library agnostic — it returns data and a message, and
|
|
11
|
+
* your test framework decides what to do with it.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
interface ComponentProfile {
|
|
15
|
+
renders: number;
|
|
16
|
+
remounts: number;
|
|
17
|
+
avoidableRenders: number;
|
|
18
|
+
}
|
|
19
|
+
interface RenderProfile {
|
|
20
|
+
/** Free-form label, e.g. "search: type one character". */
|
|
21
|
+
scenario: string;
|
|
22
|
+
components: Record<string, ComponentProfile>;
|
|
23
|
+
}
|
|
24
|
+
interface RegressionOptions {
|
|
25
|
+
/**
|
|
26
|
+
* Allowed growth before a component counts as regressed, as a fraction.
|
|
27
|
+
* `0.2` tolerates a 20% increase. Defaults to 0 — exact.
|
|
28
|
+
*/
|
|
29
|
+
tolerance?: number;
|
|
30
|
+
/** Ignore components below this render count in the baseline. */
|
|
31
|
+
ignoreBelow?: number;
|
|
32
|
+
/** Component names to skip entirely. */
|
|
33
|
+
ignore?: string[];
|
|
34
|
+
/** Fail when a component is rendering *fewer* times too. Off by default. */
|
|
35
|
+
failOnImprovement?: boolean;
|
|
36
|
+
}
|
|
37
|
+
interface Regression {
|
|
38
|
+
component: string;
|
|
39
|
+
metric: "renders" | "remounts" | "avoidableRenders";
|
|
40
|
+
baseline: number;
|
|
41
|
+
current: number;
|
|
42
|
+
delta: number;
|
|
43
|
+
}
|
|
44
|
+
interface RegressionResult {
|
|
45
|
+
ok: boolean;
|
|
46
|
+
scenario: string;
|
|
47
|
+
regressions: Regression[];
|
|
48
|
+
improvements: Regression[];
|
|
49
|
+
/** Components present now but absent from the baseline. */
|
|
50
|
+
added: string[];
|
|
51
|
+
message: string;
|
|
52
|
+
}
|
|
53
|
+
/** Builds a profile from recorded events. Pass `getEvents()`. */
|
|
54
|
+
declare function profileFromEvents(scenario: string, events: RenderEvent[], remounts?: Record<string, number>): RenderProfile;
|
|
55
|
+
declare function compareProfiles(baseline: RenderProfile, current: RenderProfile, options?: RegressionOptions): RegressionResult;
|
|
56
|
+
/**
|
|
57
|
+
* Throws when the current profile is worse than the baseline. The one-liner for
|
|
58
|
+
* a test file; use `compareProfiles` when you want the data.
|
|
59
|
+
*/
|
|
60
|
+
declare function assertNoRenderRegressions(baseline: RenderProfile, current: RenderProfile, options?: RegressionOptions): void;
|
|
61
|
+
|
|
62
|
+
export { type ComponentProfile, type Regression, type RegressionOptions, type RegressionResult, type RenderProfile, assertNoRenderRegressions, compareProfiles, profileFromEvents };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { b as RenderEvent } from './types-gl13xwmN.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Render-regression testing.
|
|
5
|
+
*
|
|
6
|
+
* Fixing a render problem once is easy; keeping it fixed is the hard part. This
|
|
7
|
+
* turns render behaviour into something a pull request can fail on: record a
|
|
8
|
+
* profile for a scripted interaction, commit it, and compare on every run.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately assertion-library agnostic — it returns data and a message, and
|
|
11
|
+
* your test framework decides what to do with it.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
interface ComponentProfile {
|
|
15
|
+
renders: number;
|
|
16
|
+
remounts: number;
|
|
17
|
+
avoidableRenders: number;
|
|
18
|
+
}
|
|
19
|
+
interface RenderProfile {
|
|
20
|
+
/** Free-form label, e.g. "search: type one character". */
|
|
21
|
+
scenario: string;
|
|
22
|
+
components: Record<string, ComponentProfile>;
|
|
23
|
+
}
|
|
24
|
+
interface RegressionOptions {
|
|
25
|
+
/**
|
|
26
|
+
* Allowed growth before a component counts as regressed, as a fraction.
|
|
27
|
+
* `0.2` tolerates a 20% increase. Defaults to 0 — exact.
|
|
28
|
+
*/
|
|
29
|
+
tolerance?: number;
|
|
30
|
+
/** Ignore components below this render count in the baseline. */
|
|
31
|
+
ignoreBelow?: number;
|
|
32
|
+
/** Component names to skip entirely. */
|
|
33
|
+
ignore?: string[];
|
|
34
|
+
/** Fail when a component is rendering *fewer* times too. Off by default. */
|
|
35
|
+
failOnImprovement?: boolean;
|
|
36
|
+
}
|
|
37
|
+
interface Regression {
|
|
38
|
+
component: string;
|
|
39
|
+
metric: "renders" | "remounts" | "avoidableRenders";
|
|
40
|
+
baseline: number;
|
|
41
|
+
current: number;
|
|
42
|
+
delta: number;
|
|
43
|
+
}
|
|
44
|
+
interface RegressionResult {
|
|
45
|
+
ok: boolean;
|
|
46
|
+
scenario: string;
|
|
47
|
+
regressions: Regression[];
|
|
48
|
+
improvements: Regression[];
|
|
49
|
+
/** Components present now but absent from the baseline. */
|
|
50
|
+
added: string[];
|
|
51
|
+
message: string;
|
|
52
|
+
}
|
|
53
|
+
/** Builds a profile from recorded events. Pass `getEvents()`. */
|
|
54
|
+
declare function profileFromEvents(scenario: string, events: RenderEvent[], remounts?: Record<string, number>): RenderProfile;
|
|
55
|
+
declare function compareProfiles(baseline: RenderProfile, current: RenderProfile, options?: RegressionOptions): RegressionResult;
|
|
56
|
+
/**
|
|
57
|
+
* Throws when the current profile is worse than the baseline. The one-liner for
|
|
58
|
+
* a test file; use `compareProfiles` when you want the data.
|
|
59
|
+
*/
|
|
60
|
+
declare function assertNoRenderRegressions(baseline: RenderProfile, current: RenderProfile, options?: RegressionOptions): void;
|
|
61
|
+
|
|
62
|
+
export { type ComponentProfile, type Regression, type RegressionOptions, type RegressionResult, type RenderProfile, assertNoRenderRegressions, compareProfiles, profileFromEvents };
|
package/dist/testing.js
ADDED