Skip to content

Commit 31e85c2

Browse files
authored
Merge branch 'main' into remove-feature-flag-enableStrictEffects
2 parents ce6a837 + 2872a26 commit 31e85c2

File tree

215 files changed

+1215
-553
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

215 files changed

+1215
-553
lines changed

.circleci/config.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ version: 2.1
22

33
aliases:
44
- &docker
5-
- image: cimg/openjdk:17.0.0-node
5+
- image: cimg/openjdk:18.0-node
66

77
- &environment
88
TZ: /usr/share/zoneinfo/America/Los_Angeles
@@ -121,7 +121,7 @@ jobs:
121121
steps:
122122
- checkout
123123
- run:
124-
name: Nodejs Version
124+
name: NodeJS Version
125125
command: node --version
126126
- *restore_yarn_cache
127127
- *restore_node_modules

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
"eslint-plugin-react-internal": "link:./scripts/eslint-rules",
6464
"fbjs-scripts": "1.2.0",
6565
"filesize": "^6.0.1",
66-
"flow-bin": "^0.142.0",
66+
"flow-bin": "^0.188.0",
6767
"glob": "^7.1.6",
6868
"glob-stream": "^6.1.0",
6969
"google-closure-compiler": "^20200517.0.0",
@@ -100,7 +100,7 @@
100100
"yargs": "^15.3.1"
101101
},
102102
"devEngines": {
103-
"node": "^12.17.0 || 13.x || 14.x || 15.x || 16.x || 17.x"
103+
"node": "^12.17.0 || 13.x || 14.x || 15.x || 16.x || 17.x || 18.x"
104104
},
105105
"jest": {
106106
"testRegex": "/scripts/jest/dont-run-jest-directly\\.js$"

packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,6 @@ const tests = {
257257
code: normalizeIndent`
258258
// Valid because they're not matching use[A-Z].
259259
fooState();
260-
use();
261260
_use();
262261
_useState();
263262
use_hook();
@@ -496,8 +495,6 @@ const tests = {
496495
},
497496
{
498497
code: normalizeIndent`
499-
Hook.use();
500-
Hook._use();
501498
Hook.useState();
502499
Hook._useState();
503500
Hook.use42();
@@ -1146,6 +1143,45 @@ if (__EXPERIMENTAL__) {
11461143
}
11471144
`,
11481145
},
1146+
{
1147+
code: normalizeIndent`
1148+
function App() {
1149+
const text = use(Promise.resolve('A'));
1150+
return <Text text={text} />
1151+
}
1152+
`,
1153+
},
1154+
{
1155+
code: normalizeIndent`
1156+
function App() {
1157+
if (shouldShowText) {
1158+
const text = use(query);
1159+
return <Text text={text} />
1160+
}
1161+
return <Text text={shouldFetchBackupText ? use(backupQuery) : "Nothing to see here"} />
1162+
}
1163+
`,
1164+
},
1165+
{
1166+
code: normalizeIndent`
1167+
function App() {
1168+
let data = [];
1169+
for (const query of queries) {
1170+
const text = use(item);
1171+
data.push(text);
1172+
}
1173+
return <Child data={data} />
1174+
}
1175+
`,
1176+
},
1177+
{
1178+
code: normalizeIndent`
1179+
function App() {
1180+
const data = someCallback((x) => use(x));
1181+
return <Child data={data} />
1182+
}
1183+
`,
1184+
},
11491185
];
11501186
tests.invalid = [
11511187
...tests.invalid,
@@ -1220,6 +1256,50 @@ if (__EXPERIMENTAL__) {
12201256
`,
12211257
errors: [useEventError('onClick')],
12221258
},
1259+
{
1260+
code: normalizeIndent`
1261+
Hook.use();
1262+
Hook._use();
1263+
Hook.useState();
1264+
Hook._useState();
1265+
Hook.use42();
1266+
Hook.useHook();
1267+
Hook.use_hook();
1268+
`,
1269+
errors: [
1270+
topLevelError('Hook.use'),
1271+
topLevelError('Hook.useState'),
1272+
topLevelError('Hook.use42'),
1273+
topLevelError('Hook.useHook'),
1274+
],
1275+
},
1276+
{
1277+
code: normalizeIndent`
1278+
function notAComponent() {
1279+
use(promise);
1280+
}
1281+
`,
1282+
errors: [functionError('use', 'notAComponent')],
1283+
},
1284+
{
1285+
code: normalizeIndent`
1286+
const text = use(promise);
1287+
function App() {
1288+
return <Text text={text} />
1289+
}
1290+
`,
1291+
errors: [topLevelError('use')],
1292+
},
1293+
{
1294+
code: normalizeIndent`
1295+
class C {
1296+
m() {
1297+
use(promise);
1298+
}
1299+
}
1300+
`,
1301+
errors: [classError('use')],
1302+
},
12231303
];
12241304
}
12251305

packages/eslint-plugin-react-hooks/src/RulesOfHooks.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
*/
1717

1818
function isHookName(s) {
19+
if (__EXPERIMENTAL__) {
20+
return s === 'use' || /^use[A-Z0-9]/.test(s);
21+
}
1922
return /^use[A-Z0-9]/.test(s);
2023
}
2124

@@ -107,6 +110,13 @@ function isUseEventIdentifier(node) {
107110
return false;
108111
}
109112

113+
function isUseIdentifier(node) {
114+
if (__EXPERIMENTAL__) {
115+
return node.type === 'Identifier' && node.name === 'use';
116+
}
117+
return false;
118+
}
119+
110120
export default {
111121
meta: {
112122
type: 'problem',
@@ -458,7 +468,8 @@ export default {
458468

459469
for (const hook of reactHooks) {
460470
// Report an error if a hook may be called more then once.
461-
if (cycled) {
471+
// `use(...)` can be called in loops.
472+
if (cycled && !isUseIdentifier(hook)) {
462473
context.report({
463474
node: hook,
464475
message:
@@ -479,7 +490,11 @@ export default {
479490
// path segments.
480491
//
481492
// Special case when we think there might be an early return.
482-
if (!cycled && pathsFromStartToEnd !== allPathsFromStartToEnd) {
493+
if (
494+
!cycled &&
495+
pathsFromStartToEnd !== allPathsFromStartToEnd &&
496+
!isUseIdentifier(hook) // `use(...)` can be called conditionally.
497+
) {
483498
const message =
484499
`React Hook "${context.getSource(hook)}" is called ` +
485500
'conditionally. React Hooks must be called in the exact ' +
@@ -525,7 +540,8 @@ export default {
525540
// anonymous function expressions. Hopefully this is clarifying
526541
// enough in the common case that the incorrect message in
527542
// uncommon cases doesn't matter.
528-
if (isSomewhereInsideComponentOrHook) {
543+
// `use(...)` can be called in callbacks.
544+
if (isSomewhereInsideComponentOrHook && !isUseIdentifier(hook)) {
529545
const message =
530546
`React Hook "${context.getSource(hook)}" cannot be called ` +
531547
'inside a callback. React Hooks must be called in a ' +

packages/jest-react/src/internalAct.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export function act<T>(scope: () => Thenable<T> | T): Thenable<T> {
7272
if (
7373
typeof result === 'object' &&
7474
result !== null &&
75+
// $FlowFixMe[method-unbinding]
7576
typeof result.then === 'function'
7677
) {
7778
const thenableResult: Thenable<T> = (result: any);

packages/react-cache/src/LRU.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export function createLRU<T>(limit: number): LRU<T> {
5757
// Delete entries from the cache, starting from the end of the list.
5858
if (first !== null) {
5959
const resolvedFirst: Entry<T> = (first: any);
60-
let last = resolvedFirst.previous;
60+
let last: null | Entry<T> = resolvedFirst.previous;
6161
while (size > targetSize && last !== null) {
6262
const onDelete = last.onDelete;
6363
const previous = last.previous;

packages/react-cache/src/ReactCacheOld.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import * as React from 'react';
1313

1414
import {createLRU} from './LRU';
1515

16-
type Suspender = {then(resolve: () => mixed, reject: () => mixed): mixed, ...};
16+
interface Suspender {
17+
then(resolve: () => mixed, reject: () => mixed): mixed;
18+
}
1719

1820
type PendingResult = {
1921
status: 0,

packages/react-debug-tools/src/ReactDebugHooks.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ function useImperativeHandle<T>(
217217
// and if there is a ref callback it might not store it but if it does we
218218
// have no way of knowing where. So let's only enable introspection of the
219219
// ref itself if it is using the object form.
220-
let instance = undefined;
220+
let instance: ?T = undefined;
221221
if (ref !== null && typeof ref === 'object') {
222222
instance = ref.current;
223223
}
@@ -716,14 +716,15 @@ export function inspectHooks<Props>(
716716
} finally {
717717
readHookLog = hookLog;
718718
hookLog = [];
719+
// $FlowFixMe[incompatible-use] found when upgrading Flow
719720
currentDispatcher.current = previousDispatcher;
720721
}
721722
const rootStack = ErrorStackParser.parse(ancestorStackError);
722723
return buildTree(rootStack, readHookLog, includeHooksSource);
723724
}
724725

725726
function setupContexts(contextMap: Map<ReactContext<any>, any>, fiber: Fiber) {
726-
let current = fiber;
727+
let current: null | Fiber = fiber;
727728
while (current) {
728729
if (current.tag === ContextProvider) {
729730
const providerType: ReactProviderType<any> = current.type;

packages/react-devtools-core/src/backend.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ export function connectToDevTools(options: ?ConnectOptions) {
146146
}
147147
},
148148
);
149+
// $FlowFixMe[incompatible-use] found when upgrading Flow
149150
bridge.addListener(
150151
'updateComponentFilters',
151152
(componentFilters: Array<ComponentFilter>) => {
@@ -165,10 +166,12 @@ export function connectToDevTools(options: ?ConnectOptions) {
165166
// Ideally the backend would save the filters itself, but RN doesn't provide a sync storage solution.
166167
// So for now we just fall back to using the default filters...
167168
if (window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ == null) {
169+
// $FlowFixMe[incompatible-use] found when upgrading Flow
168170
bridge.send('overrideComponentFilters', savedComponentFilters);
169171
}
170172

171173
// TODO (npm-packages) Warn if "isBackendStorageAPISupported"
174+
// $FlowFixMe[incompatible-call] found when upgrading Flow
172175
const agent = new Agent(bridge);
173176
agent.addListener('shutdown', () => {
174177
// If we received 'shutdown' from `agent`, we assume the `bridge` is already shutting down,
@@ -181,6 +184,7 @@ export function connectToDevTools(options: ?ConnectOptions) {
181184
// Setup React Native style editor if the environment supports it.
182185
if (resolveRNStyle != null || hook.resolveRNStyle != null) {
183186
setupNativeStyleEditor(
187+
// $FlowFixMe[incompatible-call] found when upgrading Flow
184188
bridge,
185189
agent,
186190
((resolveRNStyle || hook.resolveRNStyle: any): ResolveNativeStyle),

packages/react-devtools-core/src/editor.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ export function launchEditor(
173173
// There's an existing editor process already and it's attached
174174
// to the terminal, so go kill it. Otherwise two separate editor
175175
// instances attach to the stdin/stdout which gets confusing.
176+
// $FlowFixMe[incompatible-use] found when upgrading Flow
176177
childProcess.kill('SIGKILL');
177178
}
178179

@@ -186,6 +187,7 @@ export function launchEditor(
186187
childProcess = spawn(editor, args, {stdio: 'inherit'});
187188
}
188189
childProcess.on('error', function() {});
190+
// $FlowFixMe[incompatible-use] found when upgrading Flow
189191
childProcess.on('exit', function(errorCode) {
190192
childProcess = null;
191193
});

packages/react-devtools-core/src/standalone.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ function hookNamesModuleLoaderFunction() {
5757
);
5858
}
5959

60-
function setContentDOMNode(value: HTMLElement) {
60+
function setContentDOMNode(value: HTMLElement): typeof DevtoolsUI {
6161
node = value;
6262

6363
// Save so we can restore the exact waiting message between sessions.
@@ -70,12 +70,14 @@ function setProjectRoots(value: Array<string>) {
7070
projectRoots = value;
7171
}
7272

73-
function setStatusListener(value: StatusListener) {
73+
function setStatusListener(value: StatusListener): typeof DevtoolsUI {
7474
statusListener = value;
7575
return DevtoolsUI;
7676
}
7777

78-
function setDisconnectedCallback(value: OnDisconnectedCallback) {
78+
function setDisconnectedCallback(
79+
value: OnDisconnectedCallback,
80+
): typeof DevtoolsUI {
7981
disconnectedCallback = value;
8082
return DevtoolsUI;
8183
}
@@ -254,6 +256,7 @@ function initialize(socket: WebSocket) {
254256
socket.close();
255257
});
256258

259+
// $FlowFixMe[incompatible-call] found when upgrading Flow
257260
store = new Store(bridge, {
258261
checkBridgeProtocolCompatibility: true,
259262
supportsNativeInspection: true,

packages/react-devtools-inline/src/backend.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export function activate(
8080
bridge,
8181
}: {
8282
bridge?: BackendBridge,
83+
// $FlowFixMe[incompatible-exact]
8384
} = {},
8485
): void {
8586
if (bridge == null) {

packages/react-devtools-inline/src/frontend.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export function initialize(
6262
}: {
6363
bridge?: FrontendBridge,
6464
store?: Store,
65+
// $FlowFixMe[incompatible-exact]
6566
} = {},
6667
): React.AbstractComponent<Props, mixed> {
6768
if (bridge == null) {

packages/react-devtools-shared/src/PerformanceLoggingUtils.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@ import {__PERFORMANCE_PROFILE__} from './constants';
1111

1212
const supportsUserTiming =
1313
typeof performance !== 'undefined' &&
14+
// $FlowFixMe[method-unbinding]
1415
typeof performance.mark === 'function' &&
16+
// $FlowFixMe[method-unbinding]
1517
typeof performance.clearMarks === 'function';
1618

1719
const supportsPerformanceNow =
20+
// $FlowFixMe[method-unbinding]
1821
typeof performance !== 'undefined' && typeof performance.now === 'function';
1922

2023
function mark(markName: string): void {

packages/react-devtools-shared/src/backend/DevToolsComponentStackFrame.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ export function describeNativeComponentFrame(
121121
} catch (x) {
122122
control = x;
123123
}
124+
// $FlowFixMe[prop-missing] found when upgrading Flow
124125
fn.call(Fake.prototype);
125126
}
126127
} else {

packages/react-devtools-shared/src/backend/DevToolsFiberComponentStack.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,10 @@ export function getStackByFiberInDevAndProd(
8484
): string {
8585
try {
8686
let info = '';
87-
let node = workInProgress;
87+
let node: Fiber = workInProgress;
8888
do {
8989
info += describeFiber(workTagMap, node, currentDispatcherRef);
90+
// $FlowFixMe[incompatible-type] we bail out when we get a null
9091
node = node.return;
9192
} while (node);
9293
return info;

packages/react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,6 @@ function measureStyle(
129129
return;
130130
}
131131

132-
// $FlowFixMe the parameter types of an unknown function are unknown
133132
instance.measure((x, y, width, height, left, top) => {
134133
// RN Android sometimes returns undefined here. Don't send measurements in this case.
135134
// https://github.com/jhen0409/react-native-debugger/issues/84#issuecomment-304611817

0 commit comments

Comments
 (0)