test-renderer 0.14.0 → 0.15.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 +69 -31
- package/dist/index.cjs +254 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -17
- package/dist/index.d.ts +28 -17
- package/dist/index.js +254 -75
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -74,64 +74,95 @@ var Tag = {
|
|
|
74
74
|
};
|
|
75
75
|
var CONTAINER_TYPE = "";
|
|
76
76
|
|
|
77
|
+
// src/performance.ts
|
|
78
|
+
function mark(name, details) {
|
|
79
|
+
if (!globalThis.TEST_RENDERER_ENABLE_PROFILING) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
performance.mark(`test-renderer/${name}`, { detail: details });
|
|
83
|
+
}
|
|
84
|
+
function measureStart(name) {
|
|
85
|
+
if (!globalThis.TEST_RENDERER_ENABLE_PROFILING) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
performance.mark(`test-renderer/${name}:start`);
|
|
89
|
+
}
|
|
90
|
+
function measureEnd(name, details) {
|
|
91
|
+
if (!globalThis.TEST_RENDERER_ENABLE_PROFILING) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
performance.mark(`test-renderer/${name}:end`);
|
|
95
|
+
performance.measure(`test-renderer/${name}`, {
|
|
96
|
+
start: `test-renderer/${name}:start`,
|
|
97
|
+
end: `test-renderer/${name}:end`,
|
|
98
|
+
detail: details
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/reconciler.ts
|
|
103
|
+
var import_react_reconciler = __toESM(require("react-reconciler"), 1);
|
|
104
|
+
var import_constants3 = require("react-reconciler/constants");
|
|
105
|
+
|
|
77
106
|
// src/query-all.ts
|
|
78
|
-
function queryAll(
|
|
107
|
+
function queryAll(instance, predicate, options) {
|
|
79
108
|
var _a, _b;
|
|
80
109
|
const includeSelf = (_a = options == null ? void 0 : options.includeSelf) != null ? _a : false;
|
|
81
110
|
const matchDeepestOnly = (_b = options == null ? void 0 : options.matchDeepestOnly) != null ? _b : false;
|
|
82
111
|
const results = [];
|
|
83
112
|
const matchingDescendants = [];
|
|
84
|
-
|
|
113
|
+
instance.children.forEach((child) => {
|
|
85
114
|
if (typeof child === "string") {
|
|
86
115
|
return;
|
|
87
116
|
}
|
|
88
117
|
matchingDescendants.push(...queryAll(child, predicate, __spreadProps(__spreadValues({}, options), { includeSelf: true })));
|
|
89
118
|
});
|
|
90
119
|
if (includeSelf && // When matchDeepestOnly = true: add current element only if no descendants match
|
|
91
|
-
(matchingDescendants.length === 0 || !matchDeepestOnly) && predicate(
|
|
92
|
-
results.push(
|
|
120
|
+
(matchingDescendants.length === 0 || !matchDeepestOnly) && predicate(instance)) {
|
|
121
|
+
results.push(instance);
|
|
93
122
|
}
|
|
94
123
|
results.push(...matchingDescendants);
|
|
95
124
|
return results;
|
|
96
125
|
}
|
|
97
126
|
|
|
98
|
-
// src/
|
|
99
|
-
function
|
|
127
|
+
// src/to-json.ts
|
|
128
|
+
function containerToJson(container) {
|
|
100
129
|
return {
|
|
101
130
|
type: CONTAINER_TYPE,
|
|
102
131
|
props: {},
|
|
103
|
-
children:
|
|
132
|
+
children: childrenToJson(container.children),
|
|
104
133
|
$$typeof: /* @__PURE__ */ Symbol.for("react.test.json")
|
|
105
134
|
};
|
|
106
135
|
}
|
|
107
|
-
function
|
|
108
|
-
|
|
136
|
+
function instanceToJson(instance) {
|
|
137
|
+
const shouldExcludeHidden = instance.rootContainer.config.transformHiddenInstanceProps == null;
|
|
138
|
+
if (instance.isHidden && shouldExcludeHidden) {
|
|
109
139
|
return null;
|
|
110
140
|
}
|
|
111
141
|
const _a = instance.props, { children: _children } = _a, restProps = __objRest(_a, ["children"]);
|
|
112
142
|
return {
|
|
113
143
|
type: instance.type,
|
|
114
144
|
props: restProps,
|
|
115
|
-
children:
|
|
145
|
+
children: childrenToJson(instance.children),
|
|
116
146
|
$$typeof: /* @__PURE__ */ Symbol.for("react.test.json")
|
|
117
147
|
};
|
|
118
148
|
}
|
|
119
|
-
function
|
|
120
|
-
|
|
149
|
+
function textInstanceToJson(instance) {
|
|
150
|
+
const shouldExcludeHidden = instance.rootContainer.config.transformHiddenInstanceProps == null;
|
|
151
|
+
if (instance.isHidden && shouldExcludeHidden) {
|
|
121
152
|
return null;
|
|
122
153
|
}
|
|
123
154
|
return instance.text;
|
|
124
155
|
}
|
|
125
|
-
function
|
|
156
|
+
function childrenToJson(children) {
|
|
126
157
|
const result = [];
|
|
127
158
|
for (const child of children) {
|
|
128
159
|
if (child.tag === Tag.Instance) {
|
|
129
|
-
const renderedChild =
|
|
160
|
+
const renderedChild = instanceToJson(child);
|
|
130
161
|
if (renderedChild != null) {
|
|
131
162
|
result.push(renderedChild);
|
|
132
163
|
}
|
|
133
164
|
} else {
|
|
134
|
-
const renderedChild =
|
|
165
|
+
const renderedChild = textInstanceToJson(child);
|
|
135
166
|
if (renderedChild != null) {
|
|
136
167
|
result.push(renderedChild);
|
|
137
168
|
}
|
|
@@ -140,9 +171,9 @@ function renderChildrenToJson(children) {
|
|
|
140
171
|
return result;
|
|
141
172
|
}
|
|
142
173
|
|
|
143
|
-
// src/
|
|
174
|
+
// src/test-instance.ts
|
|
144
175
|
var instanceMap = /* @__PURE__ */ new WeakMap();
|
|
145
|
-
var
|
|
176
|
+
var TestInstance = class _TestInstance {
|
|
146
177
|
constructor(instance) {
|
|
147
178
|
this.instance = instance;
|
|
148
179
|
}
|
|
@@ -151,6 +182,7 @@ var HostElement = class _HostElement {
|
|
|
151
182
|
return this.instance.tag === Tag.Instance ? this.instance.type : CONTAINER_TYPE;
|
|
152
183
|
}
|
|
153
184
|
/** The element's props object. */
|
|
185
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
154
186
|
get props() {
|
|
155
187
|
return this.instance.tag === Tag.Instance ? this.instance.props : {};
|
|
156
188
|
}
|
|
@@ -160,11 +192,13 @@ var HostElement = class _HostElement {
|
|
|
160
192
|
if (parentInstance == null) {
|
|
161
193
|
return null;
|
|
162
194
|
}
|
|
163
|
-
return
|
|
195
|
+
return _TestInstance.fromInstance(parentInstance);
|
|
164
196
|
}
|
|
165
|
-
/** Array of child nodes (elements and text strings). Hidden children are excluded. */
|
|
197
|
+
/** Array of child nodes (elements and text strings). Hidden children are excluded by default. */
|
|
166
198
|
get children() {
|
|
167
|
-
const
|
|
199
|
+
const container = this.instance.tag === Tag.Container ? this.instance : this.instance.rootContainer;
|
|
200
|
+
const shouldExcludeHiddenChildren = container.config.transformHiddenInstanceProps == null;
|
|
201
|
+
const result = this.instance.children.filter((child) => !child.isHidden || !shouldExcludeHiddenChildren).map((child) => getTestNodeForInstance(child));
|
|
168
202
|
return result;
|
|
169
203
|
}
|
|
170
204
|
/**
|
|
@@ -180,10 +214,10 @@ var HostElement = class _HostElement {
|
|
|
180
214
|
/**
|
|
181
215
|
* Convert this element to a JSON representation suitable for snapshots.
|
|
182
216
|
*
|
|
183
|
-
* @returns JSON element or null if the element is hidden.
|
|
217
|
+
* @returns JSON element or null if the element is hidden and hidden nodes are excluded.
|
|
184
218
|
*/
|
|
185
219
|
toJSON() {
|
|
186
|
-
return this.instance.tag === Tag.Container ?
|
|
220
|
+
return this.instance.tag === Tag.Container ? containerToJson(this.instance) : instanceToJson(this.instance);
|
|
187
221
|
}
|
|
188
222
|
/**
|
|
189
223
|
* Find all descendant elements matching the predicate.
|
|
@@ -197,28 +231,24 @@ var HostElement = class _HostElement {
|
|
|
197
231
|
}
|
|
198
232
|
/** @internal */
|
|
199
233
|
static fromInstance(instance) {
|
|
200
|
-
const
|
|
201
|
-
if (
|
|
202
|
-
return
|
|
234
|
+
const testInstance = instanceMap.get(instance);
|
|
235
|
+
if (testInstance) {
|
|
236
|
+
return testInstance;
|
|
203
237
|
}
|
|
204
|
-
const result = new
|
|
238
|
+
const result = new _TestInstance(instance);
|
|
205
239
|
instanceMap.set(instance, result);
|
|
206
240
|
return result;
|
|
207
241
|
}
|
|
208
242
|
};
|
|
209
|
-
function
|
|
243
|
+
function getTestNodeForInstance(instance) {
|
|
210
244
|
switch (instance.tag) {
|
|
211
245
|
case Tag.Text:
|
|
212
246
|
return instance.text;
|
|
213
247
|
case Tag.Instance:
|
|
214
|
-
return
|
|
248
|
+
return TestInstance.fromInstance(instance);
|
|
215
249
|
}
|
|
216
250
|
}
|
|
217
251
|
|
|
218
|
-
// src/reconciler.ts
|
|
219
|
-
var import_react_reconciler = __toESM(require("react-reconciler"), 1);
|
|
220
|
-
var import_constants3 = require("react-reconciler/constants");
|
|
221
|
-
|
|
222
252
|
// src/utils.ts
|
|
223
253
|
function formatComponentList(names) {
|
|
224
254
|
if (names.length === 0) {
|
|
@@ -300,10 +330,12 @@ var hostConfig = {
|
|
|
300
330
|
* something when an instance is definitely in the tree, look at `commitMount` instead.
|
|
301
331
|
*/
|
|
302
332
|
createInstance(type, props, rootContainer, _hostContext, internalHandle) {
|
|
333
|
+
mark("reconciler/createInstance", { type });
|
|
303
334
|
return {
|
|
304
335
|
tag: Tag.Instance,
|
|
305
336
|
type,
|
|
306
337
|
props,
|
|
338
|
+
propsBeforeHiding: null,
|
|
307
339
|
isHidden: false,
|
|
308
340
|
children: [],
|
|
309
341
|
parent: null,
|
|
@@ -319,6 +351,7 @@ var hostConfig = {
|
|
|
319
351
|
*/
|
|
320
352
|
createTextInstance(text, rootContainer, hostContext, _internalHandle) {
|
|
321
353
|
var _a;
|
|
354
|
+
mark("reconciler/createTextInstance", { text });
|
|
322
355
|
if (rootContainer.config.textComponentTypes && !hostContext.isInsideText) {
|
|
323
356
|
const componentTypes = (_a = rootContainer.config.publicTextComponentTypes) != null ? _a : rootContainer.config.textComponentTypes;
|
|
324
357
|
throw new Error(
|
|
@@ -331,6 +364,7 @@ var hostConfig = {
|
|
|
331
364
|
tag: Tag.Text,
|
|
332
365
|
text,
|
|
333
366
|
parent: null,
|
|
367
|
+
rootContainer,
|
|
334
368
|
isHidden: false
|
|
335
369
|
};
|
|
336
370
|
},
|
|
@@ -344,7 +378,15 @@ var hostConfig = {
|
|
|
344
378
|
* must not modify any other nodes. It's called while the tree is still being built up and not connected
|
|
345
379
|
* to the actual tree on the screen.
|
|
346
380
|
*/
|
|
347
|
-
appendInitialChild
|
|
381
|
+
appendInitialChild(parentInstance, child) {
|
|
382
|
+
if (globalThis.TEST_RENDERER_ENABLE_PROFILING) {
|
|
383
|
+
mark("reconciler/appendInitialChild", {
|
|
384
|
+
parentType: parentInstance.type,
|
|
385
|
+
childType: formatInstanceType(child)
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
appendChild(parentInstance, child);
|
|
389
|
+
},
|
|
348
390
|
/**
|
|
349
391
|
* #### `finalizeInitialChildren(instance, type, props, rootContainer, hostContext)`
|
|
350
392
|
*
|
|
@@ -361,7 +403,8 @@ var hostConfig = {
|
|
|
361
403
|
*
|
|
362
404
|
* If you don't want to do anything here, you should return `false`.
|
|
363
405
|
*/
|
|
364
|
-
finalizeInitialChildren(
|
|
406
|
+
finalizeInitialChildren(instance, _type, _props, _rootContainer, _hostContext) {
|
|
407
|
+
mark("reconciler/finalizeInitialChildren", { type: instance.type });
|
|
365
408
|
return false;
|
|
366
409
|
},
|
|
367
410
|
/**
|
|
@@ -379,19 +422,24 @@ var hostConfig = {
|
|
|
379
422
|
* If you don't want to do anything here, you should return `false`.
|
|
380
423
|
* This method happens **in the render phase**. Do not mutate the tree from it.
|
|
381
424
|
*/
|
|
382
|
-
shouldSetTextContent(
|
|
425
|
+
shouldSetTextContent(type, _props) {
|
|
426
|
+
mark("reconciler/shouldSetTextContent", { type, result: false });
|
|
383
427
|
return false;
|
|
384
428
|
},
|
|
385
|
-
setCurrentUpdatePriority(
|
|
386
|
-
|
|
429
|
+
setCurrentUpdatePriority(priority) {
|
|
430
|
+
mark("reconciler/setCurrentUpdatePriority", { priority });
|
|
431
|
+
currentUpdatePriority = priority;
|
|
387
432
|
},
|
|
388
433
|
getCurrentUpdatePriority() {
|
|
389
434
|
return currentUpdatePriority;
|
|
390
435
|
},
|
|
391
436
|
resolveUpdatePriority() {
|
|
392
|
-
|
|
437
|
+
const priority = currentUpdatePriority || import_constants3.DefaultEventPriority;
|
|
438
|
+
mark("reconciler/resolveUpdatePriority", { priority });
|
|
439
|
+
return priority;
|
|
393
440
|
},
|
|
394
441
|
shouldAttemptEagerTransition() {
|
|
442
|
+
mark("reconciler/shouldAttemptEagerTransition", { result: false });
|
|
395
443
|
return false;
|
|
396
444
|
},
|
|
397
445
|
/**
|
|
@@ -404,6 +452,7 @@ var hostConfig = {
|
|
|
404
452
|
* This method happens **in the render phase**. Do not mutate the tree from it.
|
|
405
453
|
*/
|
|
406
454
|
getRootHostContext(rootContainer) {
|
|
455
|
+
mark("reconciler/getRootHostContext");
|
|
407
456
|
return {
|
|
408
457
|
type: "ROOT",
|
|
409
458
|
config: rootContainer.config,
|
|
@@ -428,6 +477,7 @@ var hostConfig = {
|
|
|
428
477
|
*/
|
|
429
478
|
getChildHostContext(parentHostContext, type) {
|
|
430
479
|
var _a;
|
|
480
|
+
mark("reconciler/getChildHostContext", { type });
|
|
431
481
|
const isInsideText = Boolean((_a = parentHostContext.config.textComponentTypes) == null ? void 0 : _a.includes(type));
|
|
432
482
|
return __spreadProps(__spreadValues({}, parentHostContext), { type, isInsideText });
|
|
433
483
|
},
|
|
@@ -440,19 +490,19 @@ var hostConfig = {
|
|
|
440
490
|
* If you don't want to do anything here, return `instance`.
|
|
441
491
|
*/
|
|
442
492
|
getPublicInstance(instance) {
|
|
493
|
+
if (globalThis.TEST_RENDERER_ENABLE_PROFILING) {
|
|
494
|
+
mark("reconciler/getPublicInstance", {
|
|
495
|
+
type: formatInstanceType(instance)
|
|
496
|
+
});
|
|
497
|
+
}
|
|
443
498
|
switch (instance.tag) {
|
|
444
499
|
case Tag.Instance: {
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
props: instance.props,
|
|
449
|
-
key: null
|
|
450
|
-
});
|
|
451
|
-
nodeToInstanceMap.set(mockNode, instance);
|
|
452
|
-
return mockNode;
|
|
500
|
+
const testInstance = TestInstance.fromInstance(instance);
|
|
501
|
+
nodeToInstanceMap.set(testInstance, instance);
|
|
502
|
+
return testInstance;
|
|
453
503
|
}
|
|
454
504
|
default:
|
|
455
|
-
return
|
|
505
|
+
return null;
|
|
456
506
|
}
|
|
457
507
|
},
|
|
458
508
|
/**
|
|
@@ -465,6 +515,8 @@ var hostConfig = {
|
|
|
465
515
|
* Even if you don't want to do anything here, you need to return `null` from it.
|
|
466
516
|
*/
|
|
467
517
|
prepareForCommit(_containerInfo) {
|
|
518
|
+
mark("reconciler/prepareForCommit");
|
|
519
|
+
measureStart("react/commit");
|
|
468
520
|
return null;
|
|
469
521
|
},
|
|
470
522
|
/**
|
|
@@ -476,6 +528,8 @@ var hostConfig = {
|
|
|
476
528
|
* You can leave it empty.
|
|
477
529
|
*/
|
|
478
530
|
resetAfterCommit(_containerInfo) {
|
|
531
|
+
measureEnd("react/commit");
|
|
532
|
+
mark("reconciler/resetAfterCommit");
|
|
479
533
|
},
|
|
480
534
|
/**
|
|
481
535
|
* #### `preparePortalMount(containerInfo)`
|
|
@@ -483,19 +537,31 @@ var hostConfig = {
|
|
|
483
537
|
* This method is called for a container that's used as a portal target. Usually you can leave it empty.
|
|
484
538
|
*/
|
|
485
539
|
preparePortalMount(_containerInfo) {
|
|
540
|
+
mark("reconciler/preparePortalMount");
|
|
486
541
|
},
|
|
487
542
|
/**
|
|
488
543
|
* #### `scheduleTimeout(fn, delay)`
|
|
489
544
|
*
|
|
490
545
|
* You can proxy this to `setTimeout` or its equivalent in your environment.
|
|
491
546
|
*/
|
|
492
|
-
scheduleTimeout
|
|
547
|
+
scheduleTimeout(fn, delay) {
|
|
548
|
+
const id = setTimeout(() => {
|
|
549
|
+
mark("reconciler/scheduled timeout:start");
|
|
550
|
+
fn();
|
|
551
|
+
mark("reconciler/scheduled timeout:end");
|
|
552
|
+
}, delay);
|
|
553
|
+
mark("reconciler/scheduleTimeout", { id });
|
|
554
|
+
return id;
|
|
555
|
+
},
|
|
493
556
|
/**
|
|
494
557
|
* #### `cancelTimeout(id)`
|
|
495
558
|
*
|
|
496
559
|
* You can proxy this to `clearTimeout` or its equivalent in your environment.
|
|
497
560
|
*/
|
|
498
|
-
cancelTimeout
|
|
561
|
+
cancelTimeout(id) {
|
|
562
|
+
mark("reconciler/cancelTimeout", { id });
|
|
563
|
+
clearTimeout(id);
|
|
564
|
+
},
|
|
499
565
|
/**
|
|
500
566
|
* #### `noTimeout`
|
|
501
567
|
*
|
|
@@ -517,7 +583,14 @@ var hostConfig = {
|
|
|
517
583
|
*
|
|
518
584
|
* Optional. You can proxy this to `queueMicrotask` or its equivalent in your environment.
|
|
519
585
|
*/
|
|
520
|
-
scheduleMicrotask
|
|
586
|
+
scheduleMicrotask(fn) {
|
|
587
|
+
mark("reconciler/scheduleMicrotask");
|
|
588
|
+
queueMicrotask(() => {
|
|
589
|
+
mark("reconciler/scheduled microtask:start");
|
|
590
|
+
fn();
|
|
591
|
+
mark("reconciler/scheduled microtask:end");
|
|
592
|
+
});
|
|
593
|
+
},
|
|
521
594
|
/**
|
|
522
595
|
* #### `isPrimaryRenderer`
|
|
523
596
|
*
|
|
@@ -531,6 +604,7 @@ var hostConfig = {
|
|
|
531
604
|
*/
|
|
532
605
|
warnsIfNotActing: true,
|
|
533
606
|
getInstanceFromNode(node) {
|
|
607
|
+
mark("reconciler/getInstanceFromNode");
|
|
534
608
|
const instance = nodeToInstanceMap.get(node);
|
|
535
609
|
if (instance !== void 0) {
|
|
536
610
|
return instance.unstable_fiber;
|
|
@@ -538,17 +612,22 @@ var hostConfig = {
|
|
|
538
612
|
return null;
|
|
539
613
|
},
|
|
540
614
|
beforeActiveInstanceBlur() {
|
|
615
|
+
mark("reconciler/beforeActiveInstanceBlur");
|
|
541
616
|
},
|
|
542
617
|
afterActiveInstanceBlur() {
|
|
618
|
+
mark("reconciler/afterActiveInstanceBlur");
|
|
543
619
|
},
|
|
544
620
|
prepareScopeUpdate(scopeInstance, instance) {
|
|
621
|
+
mark("reconciler/prepareScopeUpdate");
|
|
545
622
|
nodeToInstanceMap.set(scopeInstance, instance);
|
|
546
623
|
},
|
|
547
624
|
getInstanceFromScope(scopeInstance) {
|
|
548
625
|
var _a;
|
|
626
|
+
mark("reconciler/getInstanceFromScope");
|
|
549
627
|
return (_a = nodeToInstanceMap.get(scopeInstance)) != null ? _a : null;
|
|
550
628
|
},
|
|
551
629
|
detachDeletedInstance(_node) {
|
|
630
|
+
mark("reconciler/detachDeletedInstance");
|
|
552
631
|
},
|
|
553
632
|
/**
|
|
554
633
|
* #### `appendChild(parentInstance, child)`
|
|
@@ -559,7 +638,15 @@ var hostConfig = {
|
|
|
559
638
|
* Although this method currently runs in the commit phase, you still should not mutate any other nodes
|
|
560
639
|
* in it. If you need to do some additional work when a node is definitely connected to the visible tree, look at `commitMount`.
|
|
561
640
|
*/
|
|
562
|
-
appendChild,
|
|
641
|
+
appendChild(parentInstance, child) {
|
|
642
|
+
if (globalThis.TEST_RENDERER_ENABLE_PROFILING) {
|
|
643
|
+
mark("reconciler/appendChild", {
|
|
644
|
+
parentType: parentInstance.type,
|
|
645
|
+
childType: formatInstanceType(child)
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
appendChild(parentInstance, child);
|
|
649
|
+
},
|
|
563
650
|
/**
|
|
564
651
|
* #### `appendChildToContainer(container, child)`
|
|
565
652
|
*
|
|
@@ -567,7 +654,14 @@ var hostConfig = {
|
|
|
567
654
|
* to the root has a slightly different implementation, or if the root container nodes are of a different
|
|
568
655
|
* type than the rest of the tree.
|
|
569
656
|
*/
|
|
570
|
-
appendChildToContainer
|
|
657
|
+
appendChildToContainer(container, child) {
|
|
658
|
+
if (globalThis.TEST_RENDERER_ENABLE_PROFILING) {
|
|
659
|
+
mark("reconciler/appendChildToContainer", {
|
|
660
|
+
childType: formatInstanceType(child)
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
appendChild(container, child);
|
|
664
|
+
},
|
|
571
665
|
/**
|
|
572
666
|
* #### `insertBefore(parentInstance, child, beforeChild)`
|
|
573
667
|
*
|
|
@@ -577,7 +671,16 @@ var hostConfig = {
|
|
|
577
671
|
* Note that React uses this method both for insertions and for reordering nodes. Similar to DOM, it is expected
|
|
578
672
|
* that you can call `insertBefore` to reposition an existing child. Do not mutate any other parts of the tree from it.
|
|
579
673
|
*/
|
|
580
|
-
insertBefore,
|
|
674
|
+
insertBefore(parentInstance, child, beforeChild) {
|
|
675
|
+
if (globalThis.TEST_RENDERER_ENABLE_PROFILING) {
|
|
676
|
+
mark("reconciler/insertBefore", {
|
|
677
|
+
parentType: parentInstance.type,
|
|
678
|
+
childType: formatInstanceType(child),
|
|
679
|
+
beforeChildType: formatInstanceType(beforeChild)
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
insertBefore(parentInstance, child, beforeChild);
|
|
683
|
+
},
|
|
581
684
|
/**
|
|
582
685
|
* #### `insertInContainerBefore(container, child, beforeChild)
|
|
583
686
|
*
|
|
@@ -585,7 +688,15 @@ var hostConfig = {
|
|
|
585
688
|
* to the root has a slightly different implementation, or if the root container nodes are of a different type
|
|
586
689
|
* than the rest of the tree.
|
|
587
690
|
*/
|
|
588
|
-
insertInContainerBefore
|
|
691
|
+
insertInContainerBefore(container, child, beforeChild) {
|
|
692
|
+
if (globalThis.TEST_RENDERER_ENABLE_PROFILING) {
|
|
693
|
+
mark("reconciler/insertInContainerBefore", {
|
|
694
|
+
childType: formatInstanceType(child),
|
|
695
|
+
beforeChildType: formatInstanceType(beforeChild)
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
insertBefore(container, child, beforeChild);
|
|
699
|
+
},
|
|
589
700
|
/**
|
|
590
701
|
* #### `removeChild(parentInstance, child)`
|
|
591
702
|
*
|
|
@@ -594,7 +705,15 @@ var hostConfig = {
|
|
|
594
705
|
* React will only call it for the top-level node that is being removed. It is expected that garbage collection
|
|
595
706
|
* would take care of the whole subtree. You are not expected to traverse the child tree in it.
|
|
596
707
|
*/
|
|
597
|
-
removeChild,
|
|
708
|
+
removeChild(parentInstance, child) {
|
|
709
|
+
if (globalThis.TEST_RENDERER_ENABLE_PROFILING) {
|
|
710
|
+
mark("reconciler/removeChild", {
|
|
711
|
+
parentType: parentInstance.type,
|
|
712
|
+
childType: formatInstanceType(child)
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
removeChild(parentInstance, child);
|
|
716
|
+
},
|
|
598
717
|
/**
|
|
599
718
|
* #### `removeChildFromContainer(container, child)`
|
|
600
719
|
*
|
|
@@ -602,7 +721,14 @@ var hostConfig = {
|
|
|
602
721
|
* to the root has a slightly different implementation, or if the root container nodes are of a different type
|
|
603
722
|
* than the rest of the tree.
|
|
604
723
|
*/
|
|
605
|
-
removeChildFromContainer
|
|
724
|
+
removeChildFromContainer(container, child) {
|
|
725
|
+
if (globalThis.TEST_RENDERER_ENABLE_PROFILING) {
|
|
726
|
+
mark("reconciler/removeChildFromContainer", {
|
|
727
|
+
childType: formatInstanceType(child)
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
removeChild(container, child);
|
|
731
|
+
},
|
|
606
732
|
/**
|
|
607
733
|
* #### `resetTextContent(instance)`
|
|
608
734
|
*
|
|
@@ -612,7 +738,8 @@ var hostConfig = {
|
|
|
612
738
|
*
|
|
613
739
|
* If you never return `true` from `shouldSetTextContent`, you can leave it empty.
|
|
614
740
|
*/
|
|
615
|
-
resetTextContent(
|
|
741
|
+
resetTextContent(instance) {
|
|
742
|
+
mark("reconciler/resetTextContent", { type: instance.type });
|
|
616
743
|
},
|
|
617
744
|
/**
|
|
618
745
|
* #### `commitTextUpdate(textInstance, prevText, nextText)`
|
|
@@ -621,7 +748,8 @@ var hostConfig = {
|
|
|
621
748
|
*
|
|
622
749
|
* Here, `textInstance` is a node created by `createTextInstance`.
|
|
623
750
|
*/
|
|
624
|
-
commitTextUpdate(textInstance,
|
|
751
|
+
commitTextUpdate(textInstance, oldText, newText) {
|
|
752
|
+
mark("reconciler/commitTextUpdate", { oldText, newText });
|
|
625
753
|
textInstance.text = newText;
|
|
626
754
|
},
|
|
627
755
|
/**
|
|
@@ -643,7 +771,8 @@ var hostConfig = {
|
|
|
643
771
|
*
|
|
644
772
|
* If you never return `true` from `finalizeInitialChildren`, you can leave it empty.
|
|
645
773
|
*/
|
|
646
|
-
commitMount(_instance,
|
|
774
|
+
commitMount(_instance, type, _props, _internalHandle) {
|
|
775
|
+
mark("reconciler/commitMount", { type });
|
|
647
776
|
},
|
|
648
777
|
/**
|
|
649
778
|
* #### `commitUpdate(instance, type, prevProps, nextProps, internalHandle)`
|
|
@@ -661,8 +790,18 @@ var hostConfig = {
|
|
|
661
790
|
// @ts-expect-error @types/react-reconciler types don't fully match react-reconciler's actual Flow types.
|
|
662
791
|
// Correctness is verified through tests.
|
|
663
792
|
commitUpdate(instance, type, _prevProps, nextProps, internalHandle) {
|
|
793
|
+
mark("reconciler/commitUpdate", { type });
|
|
664
794
|
instance.type = type;
|
|
665
|
-
instance.
|
|
795
|
+
if (instance.isHidden && instance.rootContainer.config.transformHiddenInstanceProps != null) {
|
|
796
|
+
instance.propsBeforeHiding = nextProps;
|
|
797
|
+
instance.props = instance.rootContainer.config.transformHiddenInstanceProps({
|
|
798
|
+
props: nextProps,
|
|
799
|
+
type: instance.type
|
|
800
|
+
});
|
|
801
|
+
} else {
|
|
802
|
+
instance.props = nextProps;
|
|
803
|
+
instance.propsBeforeHiding = null;
|
|
804
|
+
}
|
|
666
805
|
instance.unstable_fiber = internalHandle;
|
|
667
806
|
},
|
|
668
807
|
/**
|
|
@@ -672,7 +811,17 @@ var hostConfig = {
|
|
|
672
811
|
* visual styling to hide it. It is used by Suspense to hide the tree while the fallback is visible.
|
|
673
812
|
*/
|
|
674
813
|
hideInstance(instance) {
|
|
814
|
+
mark("reconciler/hideInstance", { type: instance.type });
|
|
815
|
+
if (instance.isHidden) {
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
675
818
|
instance.isHidden = true;
|
|
819
|
+
instance.propsBeforeHiding = instance.props;
|
|
820
|
+
const transformHiddenInstanceProps = instance.rootContainer.config.transformHiddenInstanceProps;
|
|
821
|
+
if (transformHiddenInstanceProps) {
|
|
822
|
+
const { props, type } = instance;
|
|
823
|
+
instance.props = transformHiddenInstanceProps({ props, type });
|
|
824
|
+
}
|
|
676
825
|
},
|
|
677
826
|
/**
|
|
678
827
|
* #### `hideTextInstance(textInstance)`
|
|
@@ -680,6 +829,7 @@ var hostConfig = {
|
|
|
680
829
|
* Same as `hideInstance`, but for nodes created by `createTextInstance`.
|
|
681
830
|
*/
|
|
682
831
|
hideTextInstance(textInstance) {
|
|
832
|
+
mark("reconciler/hideTextInstance", { text: textInstance.text });
|
|
683
833
|
textInstance.isHidden = true;
|
|
684
834
|
},
|
|
685
835
|
/**
|
|
@@ -688,7 +838,13 @@ var hostConfig = {
|
|
|
688
838
|
* This method should make the `instance` visible, undoing what `hideInstance` did.
|
|
689
839
|
*/
|
|
690
840
|
unhideInstance(instance, _props) {
|
|
841
|
+
mark("reconciler/unhideInstance", { type: instance.type });
|
|
691
842
|
instance.isHidden = false;
|
|
843
|
+
const transformHiddenInstanceProps = instance.rootContainer.config.transformHiddenInstanceProps;
|
|
844
|
+
if (transformHiddenInstanceProps && instance.propsBeforeHiding) {
|
|
845
|
+
instance.props = instance.propsBeforeHiding;
|
|
846
|
+
instance.propsBeforeHiding = null;
|
|
847
|
+
}
|
|
692
848
|
},
|
|
693
849
|
/**
|
|
694
850
|
* #### `unhideTextInstance(textInstance, text)`
|
|
@@ -696,6 +852,7 @@ var hostConfig = {
|
|
|
696
852
|
* Same as `unhideInstance`, but for nodes created by `createTextInstance`.
|
|
697
853
|
*/
|
|
698
854
|
unhideTextInstance(textInstance, _text) {
|
|
855
|
+
mark("reconciler/unhideTextInstance", { text: textInstance.text });
|
|
699
856
|
textInstance.isHidden = false;
|
|
700
857
|
},
|
|
701
858
|
/**
|
|
@@ -704,6 +861,7 @@ var hostConfig = {
|
|
|
704
861
|
* This method should mutate the `container` root node and remove all children from it.
|
|
705
862
|
*/
|
|
706
863
|
clearContainer(container) {
|
|
864
|
+
mark("reconciler/clearContainer");
|
|
707
865
|
container.children.forEach((child) => {
|
|
708
866
|
child.parent = null;
|
|
709
867
|
});
|
|
@@ -715,7 +873,8 @@ var hostConfig = {
|
|
|
715
873
|
* This method is called during render to determine if the Host Component type and props require
|
|
716
874
|
* some kind of loading process to complete before committing an update.
|
|
717
875
|
*/
|
|
718
|
-
maySuspendCommit(
|
|
876
|
+
maySuspendCommit(type, _props) {
|
|
877
|
+
mark("reconciler/maySuspendCommit", { type });
|
|
719
878
|
return false;
|
|
720
879
|
},
|
|
721
880
|
/**
|
|
@@ -724,7 +883,8 @@ var hostConfig = {
|
|
|
724
883
|
* This method may be called during render if the Host Component type and props might suspend a commit.
|
|
725
884
|
* It can be used to initiate any work that might shorten the duration of a suspended commit.
|
|
726
885
|
*/
|
|
727
|
-
preloadInstance(
|
|
886
|
+
preloadInstance(type, _props) {
|
|
887
|
+
mark("reconciler/preloadInstance", { type });
|
|
728
888
|
return true;
|
|
729
889
|
},
|
|
730
890
|
/**
|
|
@@ -734,6 +894,7 @@ var hostConfig = {
|
|
|
734
894
|
* Components that might suspend this commit are evaluated to determine if the commit must be suspended.
|
|
735
895
|
*/
|
|
736
896
|
startSuspendingCommit() {
|
|
897
|
+
mark("reconciler/startSuspendingCommit");
|
|
737
898
|
},
|
|
738
899
|
/**
|
|
739
900
|
* #### `suspendInstance(type, props)`
|
|
@@ -741,7 +902,8 @@ var hostConfig = {
|
|
|
741
902
|
* This method is called after `startSuspendingCommit` for each Host Component that indicated it might
|
|
742
903
|
* suspend a commit.
|
|
743
904
|
*/
|
|
744
|
-
suspendInstance() {
|
|
905
|
+
suspendInstance(type, _props) {
|
|
906
|
+
mark("reconciler/suspendInstance", { type });
|
|
745
907
|
},
|
|
746
908
|
/**
|
|
747
909
|
* #### `waitForCommitToBeReady()`
|
|
@@ -753,7 +915,8 @@ var hostConfig = {
|
|
|
753
915
|
* callback will initiate the commit when called. The return value is a cancellation function that the
|
|
754
916
|
* Reconciler can use to abort the commit.
|
|
755
917
|
*/
|
|
756
|
-
waitForCommitToBeReady() {
|
|
918
|
+
waitForCommitToBeReady(type, _props) {
|
|
919
|
+
mark("reconciler/waitForCommitToBeReady", { type });
|
|
757
920
|
return null;
|
|
758
921
|
},
|
|
759
922
|
// -------------------
|
|
@@ -769,8 +932,10 @@ var hostConfig = {
|
|
|
769
932
|
supportsHydration: false,
|
|
770
933
|
NotPendingTransition: null,
|
|
771
934
|
resetFormInstance(_form) {
|
|
935
|
+
mark("reconciler/resetFormInstance");
|
|
772
936
|
},
|
|
773
937
|
requestPostPaintCallback(_callback) {
|
|
938
|
+
mark("reconciler/requestPostPaintCallback");
|
|
774
939
|
}
|
|
775
940
|
};
|
|
776
941
|
var TestReconciler = (0, import_react_reconciler.default)(hostConfig);
|
|
@@ -796,9 +961,11 @@ function removeChild(parentInstance, child) {
|
|
|
796
961
|
parentInstance.children.splice(index, 1);
|
|
797
962
|
child.parent = null;
|
|
798
963
|
}
|
|
964
|
+
function formatInstanceType(instance) {
|
|
965
|
+
return instance.tag === Tag.Text ? `text: "${instance.text}"` : instance.type;
|
|
966
|
+
}
|
|
799
967
|
|
|
800
968
|
// src/renderer.ts
|
|
801
|
-
var defaultCreateMockNode = () => ({});
|
|
802
969
|
var defaultOnUncaughtError = (error, errorInfo) => {
|
|
803
970
|
console.error("Uncaught error:", error, errorInfo);
|
|
804
971
|
};
|
|
@@ -809,7 +976,8 @@ var defaultOnRecoverableError = (error, errorInfo) => {
|
|
|
809
976
|
console.error("Recoverable error:", error, errorInfo);
|
|
810
977
|
};
|
|
811
978
|
function createRoot(options) {
|
|
812
|
-
var _a, _b, _c, _d, _e
|
|
979
|
+
var _a, _b, _c, _d, _e;
|
|
980
|
+
measureStart("createRoot");
|
|
813
981
|
let container = {
|
|
814
982
|
tag: Tag.Container,
|
|
815
983
|
parent: null,
|
|
@@ -818,7 +986,7 @@ function createRoot(options) {
|
|
|
818
986
|
config: {
|
|
819
987
|
textComponentTypes: options == null ? void 0 : options.textComponentTypes,
|
|
820
988
|
publicTextComponentTypes: options == null ? void 0 : options.publicTextComponentTypes,
|
|
821
|
-
|
|
989
|
+
transformHiddenInstanceProps: options == null ? void 0 : options.transformHiddenInstanceProps
|
|
822
990
|
}
|
|
823
991
|
};
|
|
824
992
|
let containerFiber = TestReconciler.createContainer(
|
|
@@ -826,30 +994,41 @@ function createRoot(options) {
|
|
|
826
994
|
import_constants5.ConcurrentRoot,
|
|
827
995
|
null,
|
|
828
996
|
// hydrationCallbacks
|
|
829
|
-
(
|
|
997
|
+
(_a = options == null ? void 0 : options.isStrictMode) != null ? _a : false,
|
|
830
998
|
false,
|
|
831
999
|
// concurrentUpdatesByDefaultOverride
|
|
832
|
-
(
|
|
833
|
-
(
|
|
834
|
-
(
|
|
1000
|
+
(_b = options == null ? void 0 : options.identifierPrefix) != null ? _b : "",
|
|
1001
|
+
(_c = options == null ? void 0 : options.onUncaughtError) != null ? _c : defaultOnUncaughtError,
|
|
1002
|
+
(_d = options == null ? void 0 : options.onCaughtError) != null ? _d : defaultOnCaughtError,
|
|
835
1003
|
// @ts-expect-error @types/react-reconciler types don't include onRecoverableError parameter
|
|
836
1004
|
// in the createContainer signature, but react-reconciler's actual Flow types do.
|
|
837
1005
|
// Correctness is verified through tests.
|
|
838
|
-
(
|
|
1006
|
+
(_e = options == null ? void 0 : options.onRecoverableError) != null ? _e : defaultOnRecoverableError,
|
|
839
1007
|
null
|
|
840
1008
|
// transitionCallbacks
|
|
841
1009
|
);
|
|
1010
|
+
measureEnd("createRoot");
|
|
842
1011
|
const render = (element) => {
|
|
843
1012
|
if (containerFiber == null) {
|
|
844
1013
|
throw new Error("Cannot render after unmount");
|
|
845
1014
|
}
|
|
846
|
-
|
|
1015
|
+
measureStart("render");
|
|
1016
|
+
try {
|
|
1017
|
+
TestReconciler.updateContainer(element, containerFiber, null, null);
|
|
1018
|
+
} finally {
|
|
1019
|
+
measureEnd("render", { elementType: String(element.type) });
|
|
1020
|
+
}
|
|
847
1021
|
};
|
|
848
1022
|
const unmount = () => {
|
|
849
1023
|
if (container == null) {
|
|
850
1024
|
return;
|
|
851
1025
|
}
|
|
852
|
-
|
|
1026
|
+
measureStart("unmount");
|
|
1027
|
+
try {
|
|
1028
|
+
TestReconciler.updateContainer(null, containerFiber, null, null);
|
|
1029
|
+
} finally {
|
|
1030
|
+
measureEnd("unmount");
|
|
1031
|
+
}
|
|
853
1032
|
containerFiber = null;
|
|
854
1033
|
container = null;
|
|
855
1034
|
};
|
|
@@ -860,7 +1039,7 @@ function createRoot(options) {
|
|
|
860
1039
|
if (container == null) {
|
|
861
1040
|
throw new Error("Cannot access .container on unmounted test renderer");
|
|
862
1041
|
}
|
|
863
|
-
return
|
|
1042
|
+
return TestInstance.fromInstance(container);
|
|
864
1043
|
}
|
|
865
1044
|
};
|
|
866
1045
|
}
|