@samitouri / QOS-React-2 / commits / 135e33c954

Flow: typing of Scheduler (#25317)

Enables well formed exports for /scheduler. Some of the modules there were missing `@flow` and were therefore completely unchecked (despite some spurious types sprinkled around).

Jan Kassens committed Sep 23, 2022 at 10:28 UTC 135e33c954ebc084e70fa765c07007ebddf18361
9 files changed +120 -46
packages/scheduler/src/SchedulerFeatureFlags.js
+1
@@ -4,6 +4,7 @@
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 + * @flow strict
8 */
9
10 export const enableSchedulerDebugging = false;
packages/scheduler/src/SchedulerMinHeap.js
+8 -7
@@ -7,23 +7,24 @@
7 * @flow strict
8 */
9
10 -type Heap = Array<Node>;
10 +type Heap<T: Node> = Array<T>;
11 type Node = {
12 id: number,
13 sortIndex: number,
14 + ...
15 };
16
16 -export function push(heap: Heap, node: Node): void {
17 +export function push<T: Node>(heap: Heap<T>, node: T): void {
18 const index = heap.length;
19 heap.push(node);
20 siftUp(heap, node, index);
21 }
22
22 -export function peek(heap: Heap): Node | null {
23 +export function peek<T: Node>(heap: Heap<T>): T | null {
24 return heap.length === 0 ? null : heap[0];
25 }
26
26 -export function pop(heap: Heap): Node | null {
27 +export function pop<T: Node>(heap: Heap<T>): T | null {
28 if (heap.length === 0) {
29 return null;
30 }
@@ -36,7 +37,7 @@ export function pop(heap: Heap): Node | null {
37 return first;
38 }
39
39 -function siftUp(heap, node, i) {
40 +function siftUp<T: Node>(heap: Heap<T>, node: T, i: number): void {
41 let index = i;
42 while (index > 0) {
43 const parentIndex = (index - 1) >>> 1;
@@ -53,7 +54,7 @@ function siftUp(heap, node, i) {
54 }
55 }
56
56 -function siftDown(heap, node, i) {
57 +function siftDown<T: Node>(heap: Heap<T>, node: T, i: number): void {
58 let index = i;
59 const length = heap.length;
60 const halfLength = length >>> 1;
@@ -85,7 +86,7 @@ function siftDown(heap, node, i) {
86 }
87 }
88
88 -function compare(a, b) {
89 +function compare(a: Node, b: Node) {
90 // Compare sort index first, then task id.
91 const diff = a.sortIndex - b.sortIndex;
92 return diff !== 0 ? diff : a.id - b.id;
packages/scheduler/src/SchedulerPriorities.js
+1 -1
@@ -4,7 +4,7 @@
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 - * @flow
7 + * @flow strict
8 */
9
10 export type PriorityLevel = 0 | 1 | 2 | 3 | 4 | 5;
packages/scheduler/src/forks/Scheduler.js
+53 -15
@@ -4,10 +4,13 @@
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 + * @flow
8 */
9
10 /* eslint-disable no-var */
11
12 +import type {PriorityLevel} from '../SchedulerPriorities';
13 +
14 import {
15 enableSchedulerDebugging,
16 enableProfiling,
@@ -41,7 +44,19 @@ import {
44 startLoggingProfilingEvents,
45 } from '../SchedulerProfiling';
46
44 -let getCurrentTime;
47 +export type Callback = boolean => ?Callback;
48 +
49 +type Task = {
50 + id: number,
51 + callback: Callback | null,
52 + priorityLevel: PriorityLevel,
53 + startTime: number,
54 + expirationTime: number,
55 + sortIndex: number,
56 + isQueued?: boolean,
57 +};
58 +
59 +let getCurrentTime: () => number | DOMHighResTimeStamp;
60 const hasPerformanceNow =
61 typeof performance === 'object' && typeof performance.now === 'function';
62
@@ -96,7 +111,9 @@ const localSetImmediate =
111
112 const isInputPending =
113 typeof navigator !== 'undefined' &&
114 + // $FlowFixMe[prop-missing]
115 navigator.scheduling !== undefined &&
116 + // $FlowFixMe[incompatible-type]
117 navigator.scheduling.isInputPending !== undefined
118 ? navigator.scheduling.isInputPending.bind(navigator.scheduling)
119 : null;
@@ -247,7 +264,10 @@ function workLoop(hasTimeRemaining, initialTime) {
264 }
265 }
266
250 -function unstable_runWithPriority(priorityLevel, eventHandler) {
267 +function unstable_runWithPriority<T>(
268 + priorityLevel: PriorityLevel,
269 + eventHandler: () => T,
270 +): T {
271 switch (priorityLevel) {
272 case ImmediatePriority:
273 case UserBlockingPriority:
@@ -269,7 +289,7 @@ function unstable_runWithPriority(priorityLevel, eventHandler) {
289 }
290 }
291
272 -function unstable_next(eventHandler) {
292 +function unstable_next<T>(eventHandler: () => T): T {
293 var priorityLevel;
294 switch (currentPriorityLevel) {
295 case ImmediatePriority:
@@ -294,8 +314,9 @@ function unstable_next(eventHandler) {
314 }
315 }
316
297 -function unstable_wrapCallback(callback) {
317 +function unstable_wrapCallback<T: (...Array<mixed>) => mixed>(callback: T): T {
318 var parentPriorityLevel = currentPriorityLevel;
319 + // $FlowFixMe[incompatible-return]
320 return function() {
321 // This is a fork of runWithPriority, inlined for performance.
322 var previousPriorityLevel = currentPriorityLevel;
@@ -309,7 +330,11 @@ function unstable_wrapCallback(callback) {
330 };
331 }
332
312 -function unstable_scheduleCallback(priorityLevel, callback, options) {
333 +function unstable_scheduleCallback(
334 + priorityLevel: PriorityLevel,
335 + callback: Callback,
336 + options?: {delay: number},
337 +): Task {
338 var currentTime = getCurrentTime();
339
340 var startTime;
@@ -346,7 +371,7 @@ function unstable_scheduleCallback(priorityLevel, callback, options) {
371
372 var expirationTime = startTime + timeout;
373
349 - var newTask = {
374 + var newTask: Task = {
375 id: taskIdCounter++,
376 callback,
377 priorityLevel,
@@ -403,11 +428,11 @@ function unstable_continueExecution() {
428 }
429 }
430
406 -function unstable_getFirstCallbackNode() {
431 +function unstable_getFirstCallbackNode(): Task | null {
432 return peek(taskQueue);
433 }
434
410 -function unstable_cancelCallback(task) {
435 +function unstable_cancelCallback(task: Task) {
436 if (enableProfiling) {
437 if (task.isQueued) {
438 const currentTime = getCurrentTime();
@@ -422,13 +447,18 @@ function unstable_cancelCallback(task) {
447 task.callback = null;
448 }
449
425 -function unstable_getCurrentPriorityLevel() {
450 +function unstable_getCurrentPriorityLevel(): PriorityLevel {
451 return currentPriorityLevel;
452 }
453
454 let isMessageLoopRunning = false;
430 -let scheduledHostCallback = null;
431 -let taskTimeoutID = -1;
455 +let scheduledHostCallback:
456 + | null
457 + | ((
458 + hasTimeRemaining: boolean,
459 + initialTime: DOMHighResTimeStamp | number,
460 + ) => boolean) = null;
461 +let taskTimeoutID: TimeoutID = (-1: any);
462
463 // Scheduler periodically yields in case there is other work on the main
464 // thread, like user events. By default, it yields multiple times per frame.
@@ -441,7 +471,7 @@ let startTime = -1;
471
472 let needsPaint = false;
473
444 -function shouldYieldToHost() {
474 +function shouldYieldToHost(): boolean {
475 const timeElapsed = getCurrentTime() - startTime;
476 if (timeElapsed < frameInterval) {
477 // The main thread has only been blocked for a really short amount of time;
@@ -490,7 +520,9 @@ function requestPaint() {
520 if (
521 enableIsInputPending &&
522 navigator !== undefined &&
523 + // $FlowFixMe[prop-missing]
524 navigator.scheduling !== undefined &&
525 + // $FlowFixMe[incompatible-type]
526 navigator.scheduling.isInputPending !== undefined
527 ) {
528 needsPaint = true;
@@ -499,7 +531,7 @@ function requestPaint() {
531 // Since we yield every frame regardless, `requestPaint` has no effect.
532 }
533
502 -function forceFrameRate(fps) {
534 +function forceFrameRate(fps: number) {
535 if (fps < 0 || fps > 125) {
536 // Using console['error'] to evade Babel and ESLint
537 console['error'](
@@ -579,6 +611,7 @@ if (typeof localSetImmediate === 'function') {
611 } else {
612 // We should only fallback here in non-browser environments.
613 schedulePerformWorkUntilDeadline = () => {
614 + // $FlowFixMe[not-a-function] nullable value
615 localSetTimeout(performWorkUntilDeadline, 0);
616 };
617 }
@@ -592,14 +625,16 @@ function requestHostCallback(callback) {
625 }
626
627 function requestHostTimeout(callback, ms) {
628 + // $FlowFixMe[not-a-function] nullable value
629 taskTimeoutID = localSetTimeout(() => {
630 callback(getCurrentTime());
631 }, ms);
632 }
633
634 function cancelHostTimeout() {
635 + // $FlowFixMe[not-a-function] nullable value
636 localClearTimeout(taskTimeoutID);
602 - taskTimeoutID = -1;
637 + taskTimeoutID = ((-1: any): TimeoutID);
638 }
639
640 export {
@@ -623,7 +658,10 @@ export {
658 forceFrameRate as unstable_forceFrameRate,
659 };
660
626 -export const unstable_Profiling = enableProfiling
661 +export const unstable_Profiling: {
662 + startLoggingProfilingEvents(): void,
663 + stopLoggingProfilingEvents(): ArrayBuffer | null,
664 +} | null = enableProfiling
665 ? {
666 startLoggingProfilingEvents,
667 stopLoggingProfilingEvents,
packages/scheduler/src/forks/SchedulerFeatureFlags.www-dynamic.js
-1
@@ -3,7 +3,6 @@
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 - *
6 */
7
8 // In www, these flags are controlled by GKs. Because most GKs have some
packages/scheduler/src/forks/SchedulerFeatureFlags.www.js
+4 -1
@@ -4,8 +4,10 @@
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 + * @flow
8 */
9
10 +// $FlowFixMe[cannot-resolve-module]
11 const dynamicFeatureFlags = require('SchedulerFeatureFlags');
12
13 // Re-export dynamic flags from the www version.
@@ -19,4 +21,5 @@ export const {
21 maxYieldMs,
22 } = dynamicFeatureFlags;
23
22 -export const enableProfiling = __PROFILE__ && enableProfilingFeatureFlag;
24 +export const enableProfiling: boolean =
25 + __PROFILE__ && enableProfilingFeatureFlag;
packages/scheduler/src/forks/SchedulerMock.js
+49 -18
@@ -4,11 +4,14 @@
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 + * @flow
8 */
9
10 /* eslint-disable no-var */
11 /* eslint-disable react-internal/prod-error-codes */
12
13 +import type {PriorityLevel} from '../SchedulerPriorities';
14 +
15 import {
16 enableSchedulerDebugging,
17 enableProfiling,
@@ -36,6 +39,18 @@ import {
39 startLoggingProfilingEvents,
40 } from '../SchedulerProfiling';
41
42 +type Callback = boolean => ?Callback;
43 +
44 +type Task = {
45 + id: number,
46 + callback: Callback | null,
47 + priorityLevel: PriorityLevel,
48 + startTime: number,
49 + expirationTime: number,
50 + sortIndex: number,
51 + isQueued?: boolean,
52 +};
53 +
54 // Max 31 bit integer. The max integer size in V8 for 32-bit systems.
55 // Math.pow(2, 30) - 1
56 // 0b111111111111111111111111111111
@@ -52,7 +67,7 @@ var IDLE_PRIORITY_TIMEOUT = maxSigned31BitInt;
67
68 // Tasks are stored on a min heap
69 var taskQueue = [];
55 -var timerQueue = [];
70 +var timerQueue: Array<Task> = [];
71
72 // Incrementing id counter. Used to maintain insertion order.
73 var taskIdCounter = 1;
@@ -70,7 +85,12 @@ var isHostCallbackScheduled = false;
85 var isHostTimeoutScheduled = false;
86
87 let currentMockTime: number = 0;
73 -let scheduledCallback: ((boolean, number) => void) | null = null;
88 +let scheduledCallback:
89 + | null
90 + | ((
91 + hasTimeRemaining: boolean,
92 + initialTime: DOMHighResTimeStamp | number,
93 + ) => boolean) = null;
94 let scheduledTimeout: (number => void) | null = null;
95 let timeoutTime: number = -1;
96 let yieldedValues: Array<mixed> | null = null;
@@ -82,11 +102,11 @@ let shouldYieldForPaint: boolean = false;
102
103 var disableYieldValue = false;
104
85 -function setDisableYieldValue(newValue) {
105 +function setDisableYieldValue(newValue: boolean) {
106 disableYieldValue = newValue;
107 }
108
89 -function advanceTimers(currentTime) {
109 +function advanceTimers(currentTime: number) {
110 // Check for tasks that are no longer delayed and add them to the queue.
111 let timer = peek(timerQueue);
112 while (timer !== null) {
@@ -110,7 +130,7 @@ function advanceTimers(currentTime) {
130 }
131 }
132
113 -function handleTimeout(currentTime) {
133 +function handleTimeout(currentTime: number) {
134 isHostTimeoutScheduled = false;
135 advanceTimers(currentTime);
136
@@ -127,7 +147,7 @@ function handleTimeout(currentTime) {
147 }
148 }
149
130 -function flushWork(hasTimeRemaining, initialTime) {
150 +function flushWork(hasTimeRemaining: boolean, initialTime: number) {
151 if (enableProfiling) {
152 markSchedulerUnsuspended(initialTime);
153 }
@@ -169,7 +189,7 @@ function flushWork(hasTimeRemaining, initialTime) {
189 }
190 }
191
172 -function workLoop(hasTimeRemaining, initialTime) {
192 +function workLoop(hasTimeRemaining, initialTime: number): boolean {
193 let currentTime = initialTime;
194 advanceTimers(currentTime);
195 currentTask = peek(taskQueue);
@@ -238,7 +258,10 @@ function workLoop(hasTimeRemaining, initialTime) {
258 }
259 }
260
241 -function unstable_runWithPriority(priorityLevel, eventHandler) {
261 +function unstable_runWithPriority<T>(
262 + priorityLevel: PriorityLevel,
263 + eventHandler: () => T,
264 +): T {
265 switch (priorityLevel) {
266 case ImmediatePriority:
267 case UserBlockingPriority:
@@ -260,7 +283,7 @@ function unstable_runWithPriority(priorityLevel, eventHandler) {
283 }
284 }
285
263 -function unstable_next(eventHandler) {
286 +function unstable_next<T>(eventHandler: () => T): T {
287 var priorityLevel;
288 switch (currentPriorityLevel) {
289 case ImmediatePriority:
@@ -285,8 +308,9 @@ function unstable_next(eventHandler) {
308 }
309 }
310
288 -function unstable_wrapCallback(callback) {
311 +function unstable_wrapCallback<T: (...Array<mixed>) => mixed>(callback: T): T {
312 var parentPriorityLevel = currentPriorityLevel;
313 + // $FlowFixMe[incompatible-return]
314 return function() {
315 // This is a fork of runWithPriority, inlined for performance.
316 var previousPriorityLevel = currentPriorityLevel;
@@ -300,7 +324,11 @@ function unstable_wrapCallback(callback) {
324 };
325 }
326
303 -function unstable_scheduleCallback(priorityLevel, callback, options) {
327 +function unstable_scheduleCallback(
328 + priorityLevel: PriorityLevel,
329 + callback: Callback,
330 + options?: {delay: number},
331 +): Task {
332 var currentTime = getCurrentTime();
333
334 var startTime;
@@ -337,7 +365,7 @@ function unstable_scheduleCallback(priorityLevel, callback, options) {
365
366 var expirationTime = startTime + timeout;
367
340 - var newTask = {
368 + var newTask: Task = {
369 id: taskIdCounter++,
370 callback,
371 priorityLevel,
@@ -394,11 +422,11 @@ function unstable_continueExecution() {
422 }
423 }
424
397 -function unstable_getFirstCallbackNode() {
425 +function unstable_getFirstCallbackNode(): Task | null {
426 return peek(taskQueue);
427 }
428
401 -function unstable_cancelCallback(task) {
429 +function unstable_cancelCallback(task: Task) {
430 if (enableProfiling) {
431 if (task.isQueued) {
432 const currentTime = getCurrentTime();
@@ -413,11 +441,11 @@ function unstable_cancelCallback(task) {
441 task.callback = null;
442 }
443
416 -function unstable_getCurrentPriorityLevel() {
444 +function unstable_getCurrentPriorityLevel(): PriorityLevel {
445 return currentPriorityLevel;
446 }
447
420 -function requestHostCallback(callback: boolean => void) {
448 +function requestHostCallback(callback: (boolean, number) => boolean) {
449 scheduledCallback = callback;
450 }
451
@@ -494,7 +522,7 @@ function unstable_flushNumberOfYields(count: number): void {
522 }
523 }
524
497 -function unstable_flushUntilNextPaint(): void {
525 +function unstable_flushUntilNextPaint(): false {
526 if (isFlushing) {
527 throw new Error('Already flushing work.');
528 }
@@ -657,7 +685,10 @@ export {
685 setDisableYieldValue as unstable_setDisableYieldValue,
686 };
687
660 -export const unstable_Profiling = enableProfiling
688 +export const unstable_Profiling: {
689 + startLoggingProfilingEvents(): void,
690 + stopLoggingProfilingEvents(): ArrayBuffer | null,
691 +} | null = enableProfiling
692 ? {
693 startLoggingProfilingEvents,
694 stopLoggingProfilingEvents,
packages/scheduler/src/forks/SchedulerPostTask.js
+3 -3
@@ -44,7 +44,7 @@ const setTimeout = window.setTimeout;
44 // Use experimental Chrome Scheduler postTask API.
45 const scheduler = global.scheduler;
46
47 -const getCurrentTime = perf.now.bind(perf);
47 +const getCurrentTime: () => DOMHighResTimeStamp = perf.now.bind(perf);
48
49 export const unstable_now = getCurrentTime;
50
@@ -193,7 +193,7 @@ export function unstable_runWithPriority<T>(
193 }
194 }
195
196 -export function unstable_getCurrentPriorityLevel() {
196 +export function unstable_getCurrentPriorityLevel(): PriorityLevel {
197 return currentPriorityLevel_DEPRECATED;
198 }
199
@@ -240,7 +240,7 @@ export function unstable_pauseExecution() {}
240
241 export function unstable_continueExecution() {}
242
243 -export function unstable_getFirstCallbackNode() {
243 +export function unstable_getFirstCallbackNode(): null {
244 return null;
245 }
246
scripts/flow/config/flowconfig
+1
@@ -51,6 +51,7 @@ well_formed_exports=true
51 well_formed_exports.includes=<PROJECT_ROOT>/packages/react-devtools-shared
52 well_formed_exports.includes=<PROJECT_ROOT>/packages/react-devtools-shell
53 well_formed_exports.includes=<PROJECT_ROOT>/packages/react-devtools-timeline
54 +well_formed_exports.includes=<PROJECT_ROOT>/packages/scheduler
55
56 # Substituted by createFlowConfig.js:
57 %REACT_RENDERER_FLOW_OPTIONS%