@@ -6,8 +6,11 @@ import { applyStackTrace, captureStackTrace } from "./traces.js";
6
6
import type { ProfilerContextValue } from "./context.js" ;
7
7
import { ProfilerContextProvider , useProfilerContext } from "./context.js" ;
8
8
import { disableActWarnings } from "./disableActWarnings.js" ;
9
+ import { render } from "@testing-library/react" ;
9
10
10
- type ValidSnapshot = void | ( object & { /* not a function */ call ?: never } ) ;
11
+ export type ValidSnapshot =
12
+ | void
13
+ | ( object & { /* not a function */ call ?: never } ) ;
11
14
12
15
/** only used for passing around data internally */
13
16
const _stackTrace = Symbol ( ) ;
@@ -17,17 +20,6 @@ export interface NextRenderOptions {
17
20
[ _stackTrace ] ?: string ;
18
21
}
19
22
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
-
31
23
interface ReplaceSnapshot < Snapshot > {
32
24
( newSnapshot : Snapshot ) : void ;
33
25
( updateSnapshot : ( lastSnapshot : Readonly < Snapshot > ) => Snapshot ) : void ;
@@ -42,13 +34,13 @@ interface MergeSnapshot<Snapshot> {
42
34
) : void ;
43
35
}
44
36
45
- interface ProfiledComponentOnlyFields < Snapshot > {
37
+ export interface ProfiledComponentOnlyFields < Snapshot > {
46
38
// Allows for partial updating of the snapshot by shallow merging the results
47
39
mergeSnapshot : MergeSnapshot < Snapshot > ;
48
40
// Performs a full replacement of the snapshot
49
41
replaceSnapshot : ReplaceSnapshot < Snapshot > ;
50
42
}
51
- interface ProfiledComponentFields < Snapshot > {
43
+ export interface ProfiledComponentFields < Snapshot > {
52
44
/**
53
45
* An array of all renders that have happened so far.
54
46
* Errors thrown during component render will be captured here, too.
@@ -84,50 +76,16 @@ interface ProfiledComponentFields<Snapshot> {
84
76
waitForNextRender ( options ?: NextRenderOptions ) : Promise < Render < Snapshot > > ;
85
77
}
86
78
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 > ,
90
81
ProfiledComponentOnlyFields < Snapshot > { }
91
82
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 } > ;
122
86
}
123
87
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 > = {
131
89
onRender ?: (
132
90
info : BaseRender & {
133
91
snapshot : Snapshot ;
@@ -142,7 +100,15 @@ export function createProfiler<Snapshot extends ValidSnapshot = void>({
142
100
* `useTrackRenders` occured.
143
101
*/
144
102
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 > {
146
112
let nextRender : Promise < Render < Snapshot > > | undefined ;
147
113
let resolveNextRender : ( ( render : Render < Snapshot > ) => void ) | undefined ;
148
114
let rejectNextRender : ( ( error : unknown ) => void ) | undefined ;
@@ -245,16 +211,17 @@ export function createProfiler<Snapshot extends ValidSnapshot = void>({
245
211
} ;
246
212
247
213
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 (
258
225
{
259
226
replaceSnapshot,
260
227
mergeSnapshot,
@@ -350,7 +317,8 @@ export function createProfiler<Snapshot extends ValidSnapshot = void>({
350
317
}
351
318
return nextRender ;
352
319
} ,
353
- } satisfies ProfiledComponentFields < Snapshot >
320
+ } satisfies ProfiledComponentFields < Snapshot > ,
321
+ { Wrapper }
354
322
) ;
355
323
return Profiler ;
356
324
}
@@ -363,74 +331,6 @@ export class WaitForRenderTimeoutError extends Error {
363
331
}
364
332
}
365
333
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
-
434
334
function resolveR18HookOwner ( ) : React . ComponentType | undefined {
435
335
return ( React as any ) . __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
436
336
?. ReactCurrentOwner ?. current ?. elementType ;
0 commit comments