@office-iss/react-native-win32 0.0.0-canary.299 → 0.0.0-canary.300

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.
Files changed (99) hide show
  1. package/.flowconfig +3 -6
  2. package/CHANGELOG.json +46 -1
  3. package/CHANGELOG.md +19 -6
  4. package/IntegrationTests/IntegrationTestsApp.js +1 -1
  5. package/Libraries/Alert/RCTAlertManager.android.js +2 -0
  6. package/Libraries/Animated/Animated.d.ts +2 -0
  7. package/Libraries/Animated/AnimatedImplementation.js +2 -0
  8. package/Libraries/Animated/Easing.js +2 -0
  9. package/Libraries/Animated/animations/Animation.js +14 -14
  10. package/Libraries/Animated/animations/TimingAnimation.js +2 -0
  11. package/Libraries/Animated/nodes/AnimatedNode.js +7 -7
  12. package/Libraries/Animated/nodes/AnimatedObject.js +7 -7
  13. package/Libraries/Animated/nodes/AnimatedProps.js +30 -30
  14. package/Libraries/Animated/nodes/AnimatedStyle.js +17 -17
  15. package/Libraries/Animated/nodes/AnimatedTransform.js +5 -5
  16. package/Libraries/Animated/nodes/AnimatedValue.js +18 -18
  17. package/Libraries/AppState/AppState.js +3 -3
  18. package/Libraries/BatchedBridge/MessageQueue.js +4 -0
  19. package/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js +1 -1
  20. package/Libraries/Components/AccessibilityInfo/AccessibilityInfo.win32.js +1 -1
  21. package/Libraries/Components/Pressable/Pressable.js +10 -1
  22. package/Libraries/Components/Pressable/Pressable.win32.js +9 -0
  23. package/Libraries/Components/StatusBar/StatusBar.js +2 -2
  24. package/Libraries/Components/Switch/Switch.js +1 -1
  25. package/Libraries/Components/TextInput/TextInput.js +2 -2
  26. package/Libraries/Components/TextInput/TextInput.win32.js +2 -1
  27. package/Libraries/Components/Touchable/TouchableBounce.js +1 -1
  28. package/Libraries/Components/Touchable/TouchableHighlight.js +1 -1
  29. package/Libraries/Components/Touchable/TouchableNativeFeedback.js +1 -1
  30. package/Libraries/Components/Touchable/TouchableOpacity.js +1 -1
  31. package/Libraries/Components/Touchable/TouchableWithoutFeedback.js +2 -2
  32. package/Libraries/Components/View/View.js +86 -168
  33. package/Libraries/Core/ReactNativeVersion.js +37 -10
  34. package/Libraries/Core/Timers/queueMicrotask.js +1 -0
  35. package/Libraries/Core/setUpPerformance.js +2 -1
  36. package/Libraries/Interaction/InteractionManager.js +118 -171
  37. package/Libraries/LayoutAnimation/LayoutAnimation.js +2 -0
  38. package/Libraries/LogBox/Data/LogBoxData.js +4 -1
  39. package/Libraries/Modal/Modal.js +1 -1
  40. package/Libraries/NativeComponent/ViewConfig.js +1 -1
  41. package/Libraries/Network/XMLHttpRequest.js +18 -5
  42. package/Libraries/Pressability/Pressability.js +1 -1
  43. package/Libraries/Pressability/Pressability.win32.js +1 -1
  44. package/Libraries/ReactNative/AppRegistryImpl.js +4 -2
  45. package/Libraries/Renderer/implementations/ReactFabric-dev.js +38 -35
  46. package/Libraries/Renderer/implementations/ReactFabric-prod.js +51 -22
  47. package/Libraries/Renderer/implementations/ReactFabric-profiling.js +54 -24
  48. package/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js +36 -33
  49. package/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js +5 -5
  50. package/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js +5 -5
  51. package/Libraries/Renderer/shims/ReactFabric.js +3 -1
  52. package/Libraries/Renderer/shims/ReactFeatureFlags.js +3 -1
  53. package/Libraries/Renderer/shims/ReactNative.js +3 -1
  54. package/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js +3 -1
  55. package/Libraries/Renderer/shims/createReactNativeComponentClass.js +3 -1
  56. package/Libraries/Utilities/useMergeRefs.js +1 -1
  57. package/Libraries/promiseRejectionTrackingOptions.js +17 -31
  58. package/flow/HermesInternalType.js +114 -0
  59. package/flow/Stringish.js +14 -0
  60. package/flow/bom.js.flow +554 -0
  61. package/flow/console.js +49 -0
  62. package/flow/cssom.js.flow +575 -0
  63. package/flow/dom.js.flow +6289 -0
  64. package/flow/global.js +88 -0
  65. package/flow/prettier.js.flow +14 -0
  66. package/flow/streams.js.flow +140 -0
  67. package/index.js +5 -2
  68. package/index.win32.js +6 -2
  69. package/jest/mockComponent.js +1 -1
  70. package/jest/setup.js +11 -0
  71. package/overrides.json +11 -11
  72. package/package.json +19 -19
  73. package/src/private/animated/NativeAnimatedHelper.js +8 -1
  74. package/src/private/animated/NativeAnimatedHelper.win32.js +8 -1
  75. package/src/private/animated/createAnimatedPropsHook.js +2 -49
  76. package/src/private/animated/createAnimatedPropsMemoHook.js +2 -48
  77. package/src/private/components/virtualview/VirtualView.js +22 -6
  78. package/src/private/components/virtualview/VirtualViewExperimentalNativeComponent.js +93 -0
  79. package/src/private/devsupport/devmenu/elementinspector/ReactDevToolsOverlay.js +2 -2
  80. package/src/private/featureflags/ReactNativeFeatureFlags.js +71 -51
  81. package/src/private/featureflags/ReactNativeFeatureFlagsBase.js +19 -0
  82. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +15 -5
  83. package/src/private/webapis/dom/nodes/ReadOnlyElement.js +1 -1
  84. package/src/private/webapis/dom/oldstylecollections/HTMLCollection.js +2 -2
  85. package/src/private/webapis/dom/oldstylecollections/NodeList.js +2 -2
  86. package/src/private/webapis/geometry/DOMRectList.js +2 -2
  87. package/src/private/webapis/intersectionobserver/internals/IntersectionObserverManager.js +19 -74
  88. package/src/private/webapis/intersectionobserver/specs/NativeIntersectionObserver.js +0 -4
  89. package/src/private/webapis/performance/EventTiming.js +5 -9
  90. package/src/private/webapis/performance/Performance.js +251 -191
  91. package/src/private/webapis/performance/PerformanceObserver.js +8 -29
  92. package/src/private/webapis/performance/UserTiming.js +24 -23
  93. package/src/private/webapis/performance/UserTimingExtensibility.js.flow +38 -0
  94. package/src/private/webapis/performance/internals/Utilities.js +9 -0
  95. package/src/private/webapis/performance/specs/NativePerformance.js +19 -33
  96. package/src/private/webapis/structuredClone/structuredClone.js +1 -1
  97. package/Libraries/Interaction/InteractionManagerStub.js +0 -184
  98. package/Libraries/Interaction/TaskQueue.js +0 -197
  99. package/Libraries/ReactNative/ReactNativeFeatureFlags.js +0 -31
@@ -15,7 +15,11 @@ import type {
15
15
  PerformanceEntryList,
16
16
  PerformanceEntryType,
17
17
  } from './PerformanceEntry';
18
- import type {DetailType, PerformanceMarkOptions} from './UserTiming';
18
+ import type {
19
+ DetailType,
20
+ PerformanceMarkOptions,
21
+ PerformanceMeasureInit,
22
+ } from './UserTiming';
19
23
 
20
24
  import DOMException from '../errors/DOMException';
21
25
  import structuredClone from '../structuredClone/structuredClone';
@@ -25,35 +29,68 @@ import {
25
29
  performanceEntryTypeToRaw,
26
30
  rawToPerformanceEntry,
27
31
  } from './internals/RawPerformanceEntry';
28
- import {warnNoNativePerformance} from './internals/Utilities';
32
+ import {
33
+ getCurrentTimeStamp,
34
+ warnNoNativePerformance,
35
+ } from './internals/Utilities';
29
36
  import MemoryInfo from './MemoryInfo';
30
37
  import ReactNativeStartupTiming from './ReactNativeStartupTiming';
31
- import NativePerformance from './specs/NativePerformance';
38
+ import MaybeNativePerformance from './specs/NativePerformance';
32
39
  import {PerformanceMark, PerformanceMeasure} from './UserTiming';
33
-
34
- declare var global: {
35
- // This value is defined directly via JSI, if available.
36
- +nativePerformanceNow?: ?() => number,
37
- };
38
-
39
- const getCurrentTimeStamp: () => DOMHighResTimeStamp =
40
- NativePerformance?.now ?? global.nativePerformanceNow ?? (() => Date.now());
40
+ import nullthrows from 'nullthrows';
41
41
 
42
42
  export type PerformanceMeasureOptions =
43
- | {
43
+ | $ReadOnly<{
44
44
  detail?: DetailType,
45
45
  start?: DOMHighResTimeStamp | string,
46
46
  duration?: DOMHighResTimeStamp,
47
- }
48
- | {
47
+ }>
48
+ | $ReadOnly<{
49
49
  detail?: DetailType,
50
50
  start?: DOMHighResTimeStamp | string,
51
51
  end?: DOMHighResTimeStamp | string,
52
- };
52
+ }>
53
+ | $ReadOnly<{
54
+ detail?: DetailType,
55
+ duration?: DOMHighResTimeStamp | string,
56
+ end?: DOMHighResTimeStamp | string,
57
+ }>;
53
58
 
54
59
  const ENTRY_TYPES_AVAILABLE_FROM_TIMELINE: $ReadOnlyArray<PerformanceEntryType> =
55
60
  ['mark', 'measure'];
56
61
 
62
+ const NativePerformance = nullthrows(MaybeNativePerformance);
63
+
64
+ const cachedReportMark = NativePerformance.reportMark;
65
+ const cachedReportMeasure = NativePerformance.reportMeasure;
66
+ const cachedGetMarkTime = NativePerformance.getMarkTime;
67
+ const cachedNativeClearMarks = NativePerformance.clearMarks;
68
+ const cachedNativeClearMeasures = NativePerformance.clearMeasures;
69
+
70
+ const MARK_OPTIONS_REUSABLE_OBJECT: {...PerformanceMarkOptions} = {
71
+ startTime: 0,
72
+ detail: undefined,
73
+ };
74
+
75
+ const MEASURE_OPTIONS_REUSABLE_OBJECT: {...PerformanceMeasureInit} = {
76
+ startTime: 0,
77
+ duration: 0,
78
+ detail: undefined,
79
+ };
80
+
81
+ const getMarkTimeForMeasure = cachedGetMarkTime
82
+ ? (markName: string): number => {
83
+ const markTime = cachedGetMarkTime(markName);
84
+ if (markTime == null) {
85
+ throw new DOMException(
86
+ `Failed to execute 'measure' on 'Performance': The mark '${markName}' does not exist.`,
87
+ 'SyntaxError',
88
+ );
89
+ }
90
+ return markTime;
91
+ }
92
+ : undefined;
93
+
57
94
  /**
58
95
  * Partial implementation of the Performance interface for RN,
59
96
  * corresponding to the standard in
@@ -64,111 +101,119 @@ export default class Performance {
64
101
 
65
102
  // Get the current JS memory information.
66
103
  get memory(): MemoryInfo {
67
- if (NativePerformance?.getSimpleMemoryInfo) {
68
- // JSI API implementations may have different variants of names for the JS
69
- // heap information we need here. We will parse the result based on our
70
- // guess of the implementation for now.
71
- const memoryInfo = NativePerformance.getSimpleMemoryInfo();
72
- if (memoryInfo.hasOwnProperty('hermes_heapSize')) {
73
- // We got memory information from Hermes
74
- const {
75
- hermes_heapSize: totalJSHeapSize,
76
- hermes_allocatedBytes: usedJSHeapSize,
77
- } = memoryInfo;
78
-
79
- return new MemoryInfo({
80
- jsHeapSizeLimit: null, // We don't know the heap size limit from Hermes.
81
- totalJSHeapSize,
82
- usedJSHeapSize,
83
- });
84
- } else {
85
- // JSC and V8 has no native implementations for memory information in JSI::Instrumentation
86
- return new MemoryInfo();
87
- }
104
+ // JSI API implementations may have different variants of names for the JS
105
+ // heap information we need here. We will parse the result based on our
106
+ // guess of the implementation for now.
107
+ const memoryInfo = NativePerformance.getSimpleMemoryInfo();
108
+ if (memoryInfo.hasOwnProperty('hermes_heapSize')) {
109
+ // We got memory information from Hermes
110
+ const {
111
+ hermes_heapSize: totalJSHeapSize,
112
+ hermes_allocatedBytes: usedJSHeapSize,
113
+ } = memoryInfo;
114
+
115
+ return new MemoryInfo({
116
+ jsHeapSizeLimit: null, // We don't know the heap size limit from Hermes.
117
+ totalJSHeapSize,
118
+ usedJSHeapSize,
119
+ });
120
+ } else {
121
+ // JSC and V8 has no native implementations for memory information in JSI::Instrumentation
122
+ return new MemoryInfo();
88
123
  }
89
-
90
- return new MemoryInfo();
91
124
  }
92
125
 
93
126
  // Startup metrics is not used in web, but only in React Native.
94
127
  get rnStartupTiming(): ReactNativeStartupTiming {
95
- if (NativePerformance?.getReactNativeStartupTiming) {
96
- const {
97
- startTime,
98
- endTime,
99
- initializeRuntimeStart,
100
- initializeRuntimeEnd,
101
- executeJavaScriptBundleEntryPointStart,
102
- executeJavaScriptBundleEntryPointEnd,
103
- } = NativePerformance.getReactNativeStartupTiming();
104
- return new ReactNativeStartupTiming({
105
- startTime,
106
- endTime,
107
- initializeRuntimeStart,
108
- initializeRuntimeEnd,
109
- executeJavaScriptBundleEntryPointStart,
110
- executeJavaScriptBundleEntryPointEnd,
111
- });
112
- }
113
- return new ReactNativeStartupTiming();
128
+ const {
129
+ startTime,
130
+ endTime,
131
+ initializeRuntimeStart,
132
+ initializeRuntimeEnd,
133
+ executeJavaScriptBundleEntryPointStart,
134
+ executeJavaScriptBundleEntryPointEnd,
135
+ } = NativePerformance.getReactNativeStartupTiming();
136
+ return new ReactNativeStartupTiming({
137
+ startTime,
138
+ endTime,
139
+ initializeRuntimeStart,
140
+ initializeRuntimeEnd,
141
+ executeJavaScriptBundleEntryPointStart,
142
+ executeJavaScriptBundleEntryPointEnd,
143
+ });
114
144
  }
115
145
 
116
146
  mark(
117
147
  markName: string,
118
148
  markOptions?: PerformanceMarkOptions,
119
149
  ): PerformanceMark {
120
- if (markName == null) {
150
+ // IMPORTANT: this method has been micro-optimized.
151
+ // Please run the benchmarks in `Performance-benchmarks-itest` to ensure
152
+ // changes do not regress performance.
153
+
154
+ if (cachedReportMark === undefined) {
155
+ warnNoNativePerformance();
156
+ return new PerformanceMark(markName, {startTime: 0});
157
+ }
158
+
159
+ if (markName === undefined) {
121
160
  throw new TypeError(
122
161
  `Failed to execute 'mark' on 'Performance': 1 argument required, but only 0 present.`,
123
162
  );
124
163
  }
125
164
 
165
+ const resolvedMarkName =
166
+ typeof markName === 'string' ? markName : String(markName);
167
+
168
+ let resolvedStartTime;
126
169
  let resolvedDetail;
127
- if (markOptions?.detail != null) {
128
- resolvedDetail = structuredClone(markOptions.detail);
170
+
171
+ let startTime;
172
+ let detail;
173
+ if (markOptions != null) {
174
+ ({startTime, detail} = markOptions);
129
175
  }
130
176
 
131
- let computedStartTime;
132
- if (NativePerformance?.markWithResult) {
133
- let resolvedStartTime;
134
-
135
- const startTime = markOptions?.startTime;
136
- if (startTime !== undefined) {
137
- resolvedStartTime = Number(startTime);
138
- if (resolvedStartTime < 0) {
139
- throw new TypeError(
140
- `Failed to execute 'mark' on 'Performance': '${markName}' cannot have a negative start time.`,
141
- );
142
- } else if (!Number.isFinite(resolvedStartTime)) {
143
- throw new TypeError(
144
- `Failed to execute 'mark' on 'Performance': Failed to read the 'startTime' property from 'PerformanceMarkOptions': The provided double value is non-finite.`,
145
- );
146
- }
177
+ if (startTime !== undefined) {
178
+ resolvedStartTime =
179
+ typeof startTime === 'number' ? startTime : Number(startTime);
180
+ if (resolvedStartTime < 0) {
181
+ throw new TypeError(
182
+ `Failed to execute 'mark' on 'Performance': '${resolvedMarkName}' cannot have a negative start time.`,
183
+ );
184
+ } else if (
185
+ // This is faster than calling Number.isFinite()
186
+ // eslint-disable-next-line no-self-compare
187
+ resolvedStartTime !== resolvedStartTime ||
188
+ resolvedStartTime === Infinity
189
+ ) {
190
+ throw new TypeError(
191
+ `Failed to execute 'mark' on 'Performance': Failed to read the 'startTime' property from 'PerformanceMarkOptions': The provided double value is non-finite.`,
192
+ );
147
193
  }
148
-
149
- // $FlowExpectedError[not-a-function]
150
- computedStartTime = NativePerformance.markWithResult(
151
- markName,
152
- resolvedStartTime,
153
- );
154
194
  } else {
155
- warnNoNativePerformance();
156
- computedStartTime = performance.now();
195
+ resolvedStartTime = getCurrentTimeStamp();
157
196
  }
158
197
 
159
- return new PerformanceMark(markName, {
160
- startTime: computedStartTime,
161
- detail: resolvedDetail,
162
- });
198
+ if (detail !== undefined) {
199
+ resolvedDetail = structuredClone(detail);
200
+ }
201
+
202
+ MARK_OPTIONS_REUSABLE_OBJECT.startTime = resolvedStartTime;
203
+ MARK_OPTIONS_REUSABLE_OBJECT.detail = resolvedDetail;
204
+
205
+ const entry = new PerformanceMark(
206
+ resolvedMarkName,
207
+ MARK_OPTIONS_REUSABLE_OBJECT,
208
+ );
209
+
210
+ cachedReportMark(resolvedMarkName, resolvedStartTime, entry);
211
+
212
+ return entry;
163
213
  }
164
214
 
165
215
  clearMarks(markName?: string): void {
166
- if (!NativePerformance?.clearMarks) {
167
- warnNoNativePerformance();
168
- return;
169
- }
170
-
171
- NativePerformance.clearMarks(markName);
216
+ cachedNativeClearMarks(markName);
172
217
  }
173
218
 
174
219
  measure(
@@ -176,66 +221,100 @@ export default class Performance {
176
221
  startMarkOrOptions?: string | PerformanceMeasureOptions,
177
222
  endMark?: string,
178
223
  ): PerformanceMeasure {
179
- let resolvedStartTime: number | void;
180
- let resolvedStartMark: string | void;
181
- let resolvedEndTime: number | void;
182
- let resolvedEndMark: string | void;
183
- let resolvedDuration: number | void;
224
+ // IMPORTANT: this method has been micro-optimized.
225
+ // Please run the benchmarks in `Performance-benchmarks-itest` to ensure
226
+ // changes do not regress performance.
227
+
228
+ if (
229
+ getMarkTimeForMeasure === undefined ||
230
+ cachedReportMeasure === undefined
231
+ ) {
232
+ warnNoNativePerformance();
233
+ return new PerformanceMeasure(measureName, {startTime: 0, duration: 0});
234
+ }
235
+
236
+ let resolvedMeasureName: string;
237
+ let resolvedStartTime: number;
238
+ let resolvedDuration: number;
184
239
  let resolvedDetail: mixed;
185
240
 
241
+ if (measureName === undefined) {
242
+ throw new TypeError(
243
+ `Failed to execute 'measure' on 'Performance': 1 argument required, but only 0 present.`,
244
+ );
245
+ }
246
+
247
+ resolvedMeasureName =
248
+ measureName === 'string' ? measureName : String(measureName);
249
+
186
250
  if (startMarkOrOptions != null) {
187
251
  switch (typeof startMarkOrOptions) {
188
252
  case 'object': {
189
- if (endMark != null) {
253
+ if (endMark !== undefined) {
190
254
  throw new TypeError(
191
255
  `Failed to execute 'measure' on 'Performance': If a non-empty PerformanceMeasureOptions object was passed, |end_mark| must not be passed.`,
192
256
  );
193
257
  }
194
258
 
195
- const start = startMarkOrOptions.start;
259
+ const {start, end, duration, detail} = startMarkOrOptions;
260
+
261
+ let resolvedEndTime;
262
+
263
+ if (
264
+ start !== undefined &&
265
+ end !== undefined &&
266
+ duration !== undefined
267
+ ) {
268
+ throw new TypeError(
269
+ `Failed to execute 'measure' on 'Performance': If a non-empty PerformanceMeasureOptions object was passed, it must not have all of its 'start', 'duration', and 'end' properties defined`,
270
+ );
271
+ }
272
+
196
273
  switch (typeof start) {
274
+ case 'undefined': {
275
+ // This will be handled after all options have been processed.
276
+ break;
277
+ }
197
278
  case 'number': {
198
279
  resolvedStartTime = start;
199
280
  break;
200
281
  }
201
282
  case 'string': {
202
- resolvedStartMark = start;
203
- break;
204
- }
205
- case 'undefined': {
283
+ resolvedStartTime = getMarkTimeForMeasure(start);
206
284
  break;
207
285
  }
208
286
  default: {
209
- resolvedStartMark = String(start);
287
+ resolvedStartTime = getMarkTimeForMeasure(String(start));
210
288
  }
211
289
  }
212
290
 
213
- const end = startMarkOrOptions.end;
214
291
  switch (typeof end) {
292
+ case 'undefined': {
293
+ // This will be handled after all options have been processed.
294
+ break;
295
+ }
215
296
  case 'number': {
216
297
  resolvedEndTime = end;
217
298
  break;
218
299
  }
219
300
  case 'string': {
220
- resolvedEndMark = end;
221
- break;
222
- }
223
- case 'undefined': {
301
+ resolvedEndTime = getMarkTimeForMeasure(end);
224
302
  break;
225
303
  }
226
304
  default: {
227
- resolvedEndMark = String(end);
305
+ resolvedEndTime = getMarkTimeForMeasure(String(end));
228
306
  }
229
307
  }
230
308
 
231
- const duration = startMarkOrOptions.duration;
232
309
  switch (typeof duration) {
310
+ case 'undefined': {
311
+ // This will be handled after all options have been processed.
312
+ break;
313
+ }
233
314
  case 'number': {
234
315
  resolvedDuration = duration;
235
316
  break;
236
317
  }
237
- case 'undefined':
238
- break;
239
318
  default: {
240
319
  resolvedDuration = Number(duration);
241
320
  if (!Number.isFinite(resolvedDuration)) {
@@ -246,92 +325,87 @@ export default class Performance {
246
325
  }
247
326
  }
248
327
 
249
- if (
250
- resolvedDuration != null &&
251
- (resolvedEndMark != null || resolvedEndTime != null)
252
- ) {
253
- throw new TypeError(
254
- `Failed to execute 'measure' on 'Performance': If a non-empty PerformanceMeasureOptions object was passed, it must not have all of its 'start', 'duration', and 'end' properties defined`,
255
- );
328
+ if (resolvedStartTime === undefined) {
329
+ if (
330
+ resolvedEndTime !== undefined &&
331
+ resolvedDuration !== undefined
332
+ ) {
333
+ resolvedStartTime = resolvedEndTime - resolvedDuration;
334
+ } else {
335
+ resolvedStartTime = 0;
336
+ }
256
337
  }
257
338
 
258
- const detail = startMarkOrOptions.detail;
259
- if (detail != null) {
339
+ if (resolvedDuration === undefined) {
340
+ if (
341
+ resolvedStartTime !== undefined &&
342
+ resolvedEndTime !== undefined
343
+ ) {
344
+ resolvedDuration = resolvedEndTime - resolvedStartTime;
345
+ } else {
346
+ resolvedDuration = getCurrentTimeStamp() - resolvedStartTime;
347
+ }
348
+ }
349
+
350
+ if (detail !== undefined) {
260
351
  resolvedDetail = structuredClone(detail);
261
352
  }
262
353
 
263
354
  break;
264
355
  }
265
356
  case 'string': {
266
- resolvedStartMark = startMarkOrOptions;
357
+ resolvedStartTime = getMarkTimeForMeasure(startMarkOrOptions);
267
358
 
268
359
  if (endMark !== undefined) {
269
- resolvedEndMark = String(endMark);
360
+ resolvedDuration =
361
+ getMarkTimeForMeasure(endMark) - resolvedStartTime;
362
+ } else {
363
+ resolvedDuration = getCurrentTimeStamp() - resolvedStartTime;
270
364
  }
271
365
  break;
272
366
  }
273
367
  default: {
274
- resolvedStartMark = String(startMarkOrOptions);
368
+ resolvedStartTime = getMarkTimeForMeasure(String(startMarkOrOptions));
369
+
370
+ if (endMark !== undefined) {
371
+ resolvedDuration =
372
+ getMarkTimeForMeasure(endMark) - resolvedStartTime;
373
+ } else {
374
+ resolvedDuration = getCurrentTimeStamp() - resolvedStartTime;
375
+ }
275
376
  }
276
377
  }
277
- }
378
+ } else {
379
+ resolvedStartTime = 0;
278
380
 
279
- let computedStartTime = 0;
280
- let computedDuration = 0;
281
-
282
- if (NativePerformance?.measure) {
283
- try {
284
- [computedStartTime, computedDuration] = NativePerformance.measure(
285
- measureName,
286
- resolvedStartTime,
287
- resolvedEndTime,
288
- resolvedDuration,
289
- resolvedStartMark,
290
- resolvedEndMark,
291
- );
292
- } catch (error) {
293
- throw new DOMException(
294
- "Failed to execute 'measure' on 'Performance': " + error.message,
295
- 'SyntaxError',
296
- );
297
- }
298
- } else if (NativePerformance?.measureWithResult) {
299
- try {
300
- [computedStartTime, computedDuration] =
301
- NativePerformance.measureWithResult(
302
- measureName,
303
- resolvedStartTime ?? 0,
304
- resolvedEndTime ?? 0,
305
- resolvedDuration,
306
- resolvedStartMark,
307
- resolvedEndMark,
308
- );
309
- } catch (error) {
310
- throw new DOMException(
311
- "Failed to execute 'measure' on 'Performance': " + error.message,
312
- 'SyntaxError',
313
- );
381
+ if (endMark !== undefined) {
382
+ resolvedDuration = getMarkTimeForMeasure(endMark) - resolvedStartTime;
383
+ } else {
384
+ resolvedDuration = getCurrentTimeStamp() - resolvedStartTime;
314
385
  }
315
- } else {
316
- warnNoNativePerformance();
317
386
  }
318
387
 
319
- const measure = new PerformanceMeasure(measureName, {
320
- startTime: computedStartTime,
321
- duration: computedDuration ?? 0,
322
- detail: resolvedDetail,
323
- });
388
+ MEASURE_OPTIONS_REUSABLE_OBJECT.startTime = resolvedStartTime;
389
+ MEASURE_OPTIONS_REUSABLE_OBJECT.duration = resolvedDuration;
390
+ MEASURE_OPTIONS_REUSABLE_OBJECT.detail = resolvedDetail;
324
391
 
325
- return measure;
392
+ const entry = new PerformanceMeasure(
393
+ resolvedMeasureName,
394
+ MEASURE_OPTIONS_REUSABLE_OBJECT,
395
+ );
396
+
397
+ cachedReportMeasure(
398
+ resolvedMeasureName,
399
+ resolvedStartTime,
400
+ resolvedDuration,
401
+ entry,
402
+ );
403
+
404
+ return entry;
326
405
  }
327
406
 
328
407
  clearMeasures(measureName?: string): void {
329
- if (!NativePerformance?.clearMeasures) {
330
- warnNoNativePerformance();
331
- return;
332
- }
333
-
334
- NativePerformance?.clearMeasures(measureName);
408
+ cachedNativeClearMeasures(measureName);
335
409
  }
336
410
 
337
411
  /**
@@ -346,10 +420,6 @@ export default class Performance {
346
420
  * https://www.w3.org/TR/performance-timeline/#extensions-to-the-performance-interface
347
421
  */
348
422
  getEntries(): PerformanceEntryList {
349
- if (!NativePerformance?.getEntries) {
350
- warnNoNativePerformance();
351
- return [];
352
- }
353
423
  return NativePerformance.getEntries().map(rawToPerformanceEntry);
354
424
  }
355
425
 
@@ -362,11 +432,6 @@ export default class Performance {
362
432
  return [];
363
433
  }
364
434
 
365
- if (!NativePerformance?.getEntriesByType) {
366
- warnNoNativePerformance();
367
- return [];
368
- }
369
-
370
435
  return NativePerformance.getEntriesByType(
371
436
  performanceEntryTypeToRaw(entryType),
372
437
  ).map(rawToPerformanceEntry);
@@ -384,11 +449,6 @@ export default class Performance {
384
449
  return [];
385
450
  }
386
451
 
387
- if (!NativePerformance?.getEntriesByName) {
388
- warnNoNativePerformance();
389
- return [];
390
- }
391
-
392
452
  return NativePerformance.getEntriesByName(
393
453
  entryName,
394
454
  entryType != null ? performanceEntryTypeToRaw(entryType) : undefined,