@@ -6,8 +6,11 @@ import { applyStackTrace, captureStackTrace } from "./traces.js";
66import type { ProfilerContextValue } from "./context.js" ;
77import { ProfilerContextProvider , useProfilerContext } from "./context.js" ;
88import { disableActWarnings } from "./disableActWarnings.js" ;
9+ import { render } from "@testing-library/react" ;
910
10- type ValidSnapshot = void | ( object & { /* not a function */ call ?: never } ) ;
11+ export type ValidSnapshot =
12+ | void
13+ | ( object & { /* not a function */ call ?: never } ) ;
1114
1215/** only used for passing around data internally */
1316const _stackTrace = Symbol ( ) ;
@@ -17,17 +20,6 @@ export interface NextRenderOptions {
1720 [ _stackTrace ] ?: string ;
1821}
1922
20- /** @internal */
21- interface ProfilerProps {
22- children : React . ReactNode ;
23- }
24-
25- /** @internal */
26- export interface Profiler < Snapshot >
27- extends React . FC < ProfilerProps > ,
28- ProfiledComponentFields < Snapshot > ,
29- ProfiledComponentOnlyFields < Snapshot > { }
30-
3123interface ReplaceSnapshot < Snapshot > {
3224 ( newSnapshot : Snapshot ) : void ;
3325 ( updateSnapshot : ( lastSnapshot : Readonly < Snapshot > ) => Snapshot ) : void ;
@@ -42,13 +34,13 @@ interface MergeSnapshot<Snapshot> {
4234 ) : void ;
4335}
4436
45- interface ProfiledComponentOnlyFields < Snapshot > {
37+ export interface ProfiledComponentOnlyFields < Snapshot > {
4638 // Allows for partial updating of the snapshot by shallow merging the results
4739 mergeSnapshot : MergeSnapshot < Snapshot > ;
4840 // Performs a full replacement of the snapshot
4941 replaceSnapshot : ReplaceSnapshot < Snapshot > ;
5042}
51- interface ProfiledComponentFields < Snapshot > {
43+ export interface ProfiledComponentFields < Snapshot > {
5244 /**
5345 * An array of all renders that have happened so far.
5446 * Errors thrown during component render will be captured here, too.
@@ -84,50 +76,16 @@ interface ProfiledComponentFields<Snapshot> {
8476 waitForNextRender ( options ?: NextRenderOptions ) : Promise < Render < Snapshot > > ;
8577}
8678
87- export interface ProfiledComponent < Snapshot extends ValidSnapshot , Props = { } >
88- extends React . FC < Props > ,
89- ProfiledComponentFields < Snapshot > ,
79+ export interface RenderStream < Snapshot extends ValidSnapshot >
80+ extends ProfiledComponentFields < Snapshot > ,
9081 ProfiledComponentOnlyFields < Snapshot > { }
9182
92- /** @internal */
93- export function profile < Snapshot extends ValidSnapshot = void , Props = { } > ( {
94- Component,
95- ...options
96- } : Parameters < typeof createProfiler < Snapshot > > [ 0 ] & {
97- Component : React . ComponentType < Props > ;
98- } ) : ProfiledComponent < Snapshot , Props > {
99- const Profiler = createProfiler ( options ) ;
100-
101- return Object . assign (
102- function ProfiledComponent ( props : Props ) {
103- return (
104- < Profiler >
105- < Component { ...( props as any ) } />
106- </ Profiler >
107- ) ;
108- } ,
109- {
110- mergeSnapshot : Profiler . mergeSnapshot ,
111- replaceSnapshot : Profiler . replaceSnapshot ,
112- getCurrentRender : Profiler . getCurrentRender ,
113- peekRender : Profiler . peekRender ,
114- takeRender : Profiler . takeRender ,
115- totalRenderCount : Profiler . totalRenderCount ,
116- waitForNextRender : Profiler . waitForNextRender ,
117- get renders ( ) {
118- return Profiler . renders ;
119- } ,
120- }
121- ) ;
83+ export interface RenderStreamWithWrapper < Snapshot extends ValidSnapshot >
84+ extends RenderStream < Snapshot > {
85+ Wrapper : React . FC < { children : React . ReactNode } > ;
12286}
12387
124- /** @internal */
125- export function createProfiler < Snapshot extends ValidSnapshot = void > ( {
126- onRender,
127- snapshotDOM = false ,
128- initialSnapshot,
129- skipNonTrackingRenders,
130- } : {
88+ export type ProfilerOptions < Snapshot extends ValidSnapshot > = {
13189 onRender ?: (
13290 info : BaseRender & {
13391 snapshot : Snapshot ;
@@ -142,7 +100,15 @@ export function createProfiler<Snapshot extends ValidSnapshot = void>({
142100 * `useTrackRenders` occured.
143101 */
144102 skipNonTrackingRenders ?: boolean ;
145- } = { } ) {
103+ } ;
104+
105+ /** @internal */
106+ export function createProfiler < Snapshot extends ValidSnapshot = void > ( {
107+ onRender,
108+ snapshotDOM = false ,
109+ initialSnapshot,
110+ skipNonTrackingRenders,
111+ } : ProfilerOptions < Snapshot > = { } ) : RenderStreamWithWrapper < Snapshot > {
146112 let nextRender : Promise < Render < Snapshot > > | undefined ;
147113 let resolveNextRender : ( ( render : Render < Snapshot > ) => void ) | undefined ;
148114 let rejectNextRender : ( ( error : unknown ) => void ) | undefined ;
@@ -245,16 +211,17 @@ export function createProfiler<Snapshot extends ValidSnapshot = void>({
245211 } ;
246212
247213 let iteratorPosition = 0 ;
248- const Profiler : Profiler < Snapshot > = Object . assign (
249- ( { children } : ProfilerProps ) => {
250- return (
251- < ProfilerContextProvider value = { profilerContext } >
252- < React . Profiler id = "test" onRender = { profilerOnRender } >
253- { children }
254- </ React . Profiler >
255- </ ProfilerContextProvider >
256- ) ;
257- } ,
214+ function Wrapper ( { children } : { children : React . ReactNode } ) {
215+ return (
216+ < ProfilerContextProvider value = { profilerContext } >
217+ < React . Profiler id = "test" onRender = { profilerOnRender } >
218+ { children }
219+ </ React . Profiler >
220+ </ ProfilerContextProvider >
221+ ) ;
222+ }
223+
224+ const Profiler : RenderStreamWithWrapper < Snapshot > = Object . assign (
258225 {
259226 replaceSnapshot,
260227 mergeSnapshot,
@@ -350,7 +317,8 @@ export function createProfiler<Snapshot extends ValidSnapshot = void>({
350317 }
351318 return nextRender ;
352319 } ,
353- } satisfies ProfiledComponentFields < Snapshot >
320+ } satisfies ProfiledComponentFields < Snapshot > ,
321+ { Wrapper }
354322 ) ;
355323 return Profiler ;
356324}
@@ -363,74 +331,6 @@ export class WaitForRenderTimeoutError extends Error {
363331 }
364332}
365333
366- type StringReplaceRenderWithSnapshot < T extends string > =
367- T extends `${infer Pre } Render${infer Post } ` ? `${Pre } Snapshot${Post } ` : T ;
368-
369- type ResultReplaceRenderWithSnapshot < T > = T extends (
370- ...args : infer Args
371- ) => Render < infer Snapshot >
372- ? ( ...args : Args ) => Snapshot
373- : T extends ( ...args : infer Args ) => Promise < Render < infer Snapshot > >
374- ? ( ...args : Args ) => Promise < Snapshot >
375- : T ;
376-
377- type ProfiledHookFields < ReturnValue > =
378- ProfiledComponentFields < ReturnValue > extends infer PC
379- ? {
380- [ K in keyof PC as StringReplaceRenderWithSnapshot <
381- K & string
382- > ] : ResultReplaceRenderWithSnapshot < PC [ K ] > ;
383- }
384- : never ;
385-
386- /** @internal */
387- export interface ProfiledHook < Props , ReturnValue >
388- extends React . FC < Props > ,
389- ProfiledHookFields < ReturnValue > {
390- Profiler : Profiler < ReturnValue > ;
391- }
392-
393- /** @internal */
394- export function profileHook < ReturnValue extends ValidSnapshot , Props > (
395- renderCallback : ( props : Props ) => ReturnValue
396- ) : ProfiledHook < Props , ReturnValue > {
397- const Profiler = createProfiler < ReturnValue > ( ) ;
398-
399- const ProfiledHook = ( props : Props ) => {
400- Profiler . replaceSnapshot ( renderCallback ( props ) ) ;
401- return null ;
402- } ;
403-
404- return Object . assign (
405- function App ( props : Props ) {
406- return (
407- < Profiler >
408- < ProfiledHook { ...( props as any ) } />
409- </ Profiler >
410- ) ;
411- } ,
412- {
413- Profiler,
414- } ,
415- {
416- renders : Profiler . renders ,
417- totalSnapshotCount : Profiler . totalRenderCount ,
418- async peekSnapshot ( options ) {
419- return ( await Profiler . peekRender ( options ) ) . snapshot ;
420- } ,
421- async takeSnapshot ( options ) {
422- return ( await Profiler . takeRender ( options ) ) . snapshot ;
423- } ,
424- getCurrentSnapshot ( ) {
425- return Profiler . getCurrentRender ( ) . snapshot ;
426- } ,
427- async waitForNextSnapshot ( options ) {
428- return ( await Profiler . waitForNextRender ( options ) ) . snapshot ;
429- } ,
430- } satisfies ProfiledHookFields < ReturnValue >
431- ) ;
432- }
433-
434334function resolveR18HookOwner ( ) : React . ComponentType | undefined {
435335 return ( React as any ) . __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
436336 ?. ReactCurrentOwner ?. current ?. elementType ;
0 commit comments