Skip to content

Commit f2fed1b

Browse files
committed
[DevTools] Give a distinct color to the root (facebook#34690)
Stacked on facebook#34654. The root is special since it represents "Initial Paint" (or a "Transition" when an Activity is selected). This gives it a different color in the timeline as well as gives it an outline that's clickable. Hovering the timeline now shows "Initial Paint" or "Suspense". Also made the cursor a pointer to invite you to try to click things and some rounded corners. <img width="1219" height="420" alt="Screenshot 2025-10-02 at 1 26 38 PM" src="https://github.com/user-attachments/assets/12451f93-8917-4f3b-8f01-930129e5fc13" /> <img width="1217" height="419" alt="Screenshot 2025-10-02 at 1 26 54 PM" src="https://github.com/user-attachments/assets/02b5e94c-3fbe-488d-b0f2-225b73578608" /> <img width="1215" height="419" alt="Screenshot 2025-10-02 at 1 27 24 PM" src="https://github.com/user-attachments/assets/c24e8861-e74a-4ccc-8643-ee9d04bef43c" /> <img width="1216" height="419" alt="Screenshot 2025-10-02 at 1 27 10 PM" src="https://github.com/user-attachments/assets/d5cc2b62-fa64-41bf-b485-116b1cd67467" /> DiffTrain build for [2e68dc7](facebook@2e68dc7)
1 parent dc77cd3 commit f2fed1b

37 files changed

+4550
-3301
lines changed

compiled/eslint-plugin-react-hooks/index.js

Lines changed: 79 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ var PluginProposalPrivateMethods = require('@babel/plugin-proposal-private-metho
2929
var HermesParser = require('hermes-parser');
3030
var util = require('util');
3131

32+
const SETTINGS_KEY = 'react-hooks';
33+
const SETTINGS_ADDITIONAL_EFFECT_HOOKS_KEY = 'additionalEffectHooks';
34+
function getAdditionalEffectHooksFromSettings(settings) {
35+
var _a;
36+
const additionalHooks = (_a = settings[SETTINGS_KEY]) === null || _a === void 0 ? void 0 : _a[SETTINGS_ADDITIONAL_EFFECT_HOOKS_KEY];
37+
if (additionalHooks != null && typeof additionalHooks === 'string') {
38+
return new RegExp(additionalHooks);
39+
}
40+
return undefined;
41+
}
42+
3243
const rule$1 = {
3344
meta: {
3445
type: 'suggestion',
@@ -59,23 +70,24 @@ const rule$1 = {
5970
},
6071
requireExplicitEffectDeps: {
6172
type: 'boolean',
62-
}
73+
},
6374
},
6475
},
6576
],
6677
},
6778
create(context) {
6879
const rawOptions = context.options && context.options[0];
80+
const settings = context.settings || {};
6981
const additionalHooks = rawOptions && rawOptions.additionalHooks
7082
? new RegExp(rawOptions.additionalHooks)
71-
: undefined;
83+
: getAdditionalEffectHooksFromSettings(settings);
7284
const enableDangerousAutofixThisMayCauseInfiniteLoops = (rawOptions &&
7385
rawOptions.enableDangerousAutofixThisMayCauseInfiniteLoops) ||
7486
false;
7587
const experimental_autoDependenciesHooks = rawOptions && Array.isArray(rawOptions.experimental_autoDependenciesHooks)
7688
? rawOptions.experimental_autoDependenciesHooks
7789
: [];
78-
const requireExplicitEffectDeps = rawOptions && rawOptions.requireExplicitEffectDeps || false;
90+
const requireExplicitEffectDeps = (rawOptions && rawOptions.requireExplicitEffectDeps) || false;
7991
const options = {
8092
additionalHooks,
8193
experimental_autoDependenciesHooks,
@@ -944,7 +956,7 @@ const rule$1 = {
944956
reportProblem({
945957
node: reactiveHook,
946958
message: `React Hook ${reactiveHookName} always requires dependencies. ` +
947-
`Please add a dependency array or an explicit \`undefined\``
959+
`Please add a dependency array or an explicit \`undefined\``,
948960
});
949961
}
950962
const isAutoDepsHook = options.experimental_autoDependenciesHooks.includes(reactiveHookName);
@@ -1446,9 +1458,7 @@ function isAncestorNodeOf(a, b) {
14461458
a.range[1] >= b.range[1]);
14471459
}
14481460
function isUseEffectEventIdentifier$1(node) {
1449-
{
1450-
return node.type === 'Identifier' && node.name === 'useEffectEvent';
1451-
}
1461+
return node.type === 'Identifier' && node.name === 'useEffectEvent';
14521462
}
14531463
function getUnknownDependenciesMessage(reactiveHookName) {
14541464
return (`React Hook ${reactiveHookName} received a function whose dependencies ` +
@@ -32113,7 +32123,7 @@ const EnvironmentConfigSchema = zod.z.object({
3211332123
moduleTypeProvider: zod.z.nullable(zod.z.function().args(zod.z.string())).default(null),
3211432124
customMacros: zod.z.nullable(zod.z.array(MacroSchema)).default(null),
3211532125
enableResetCacheOnSourceFileChanges: zod.z.nullable(zod.z.boolean()).default(null),
32116-
enablePreserveExistingMemoizationGuarantees: zod.z.boolean().default(false),
32126+
enablePreserveExistingMemoizationGuarantees: zod.z.boolean().default(true),
3211732127
validatePreserveExistingMemoizationGuarantees: zod.z.boolean().default(true),
3211832128
enablePreserveExistingManualUseMemo: zod.z.boolean().default(false),
3211932129
enableForest: zod.z.boolean().default(false),
@@ -45353,6 +45363,29 @@ function collectNonNullsInBlocks(fn, context) {
4535345363
}
4535445364
}
4535545365
}
45366+
else if (fn.env.config.enablePreserveExistingMemoizationGuarantees &&
45367+
instr.value.kind === 'StartMemoize' &&
45368+
instr.value.deps != null) {
45369+
for (const dep of instr.value.deps) {
45370+
if (dep.root.kind === 'NamedLocal') {
45371+
if (!isImmutableAtInstr(dep.root.value.identifier, instr.id, context)) {
45372+
continue;
45373+
}
45374+
for (let i = 0; i < dep.path.length; i++) {
45375+
const pathEntry = dep.path[i];
45376+
if (pathEntry.optional) {
45377+
break;
45378+
}
45379+
const depNode = context.registry.getOrCreateProperty({
45380+
identifier: dep.root.value.identifier,
45381+
path: dep.path.slice(0, i),
45382+
reactive: dep.root.value.reactive,
45383+
});
45384+
assumedNonNullObjects.add(depNode);
45385+
}
45386+
}
45387+
}
45388+
}
4535645389
}
4535745390
nodes.set(block.id, {
4535845391
block,
@@ -54464,7 +54497,7 @@ const allRules = LintRules.reduce((acc, rule) => {
5446454497
severity: ErrorSeverity.Error,
5446554498
},
5446654499
});
54467-
const recommendedRules = LintRules.filter(rule => rule.recommended).reduce((acc, rule) => {
54500+
LintRules.filter(rule => rule.recommended).reduce((acc, rule) => {
5446854501
acc[rule.name] = { rule: makeRule(rule), severity: rule.severity };
5446954502
return acc;
5447054503
}, {
@@ -54473,23 +54506,6 @@ const recommendedRules = LintRules.filter(rule => rule.recommended).reduce((acc,
5447354506
severity: ErrorSeverity.Error,
5447454507
},
5447554508
});
54476-
function mapErrorSeverityToESlint(severity) {
54477-
switch (severity) {
54478-
case ErrorSeverity.Error: {
54479-
return 'error';
54480-
}
54481-
case ErrorSeverity.Warning: {
54482-
return 'warn';
54483-
}
54484-
case ErrorSeverity.Hint:
54485-
case ErrorSeverity.Off: {
54486-
return 'off';
54487-
}
54488-
default: {
54489-
assertExhaustive(severity, `Unhandled severity: ${severity}`);
54490-
}
54491-
}
54492-
}
5449354509

5449454510
var assert_1;
5449554511
var hasRequiredAssert;
@@ -57375,13 +57391,26 @@ function getNodeWithoutReactNamespace(node) {
5737557391
}
5737657392
return node;
5737757393
}
57378-
function isEffectIdentifier(node) {
57379-
return node.type === 'Identifier' && (node.name === 'useEffect' || node.name === 'useLayoutEffect' || node.name === 'useInsertionEffect');
57394+
function isEffectIdentifier(node, additionalHooks) {
57395+
const isBuiltInEffect = node.type === 'Identifier' &&
57396+
(node.name === 'useEffect' ||
57397+
node.name === 'useLayoutEffect' ||
57398+
node.name === 'useInsertionEffect');
57399+
if (isBuiltInEffect) {
57400+
return true;
57401+
}
57402+
if (additionalHooks && node.type === 'Identifier') {
57403+
return additionalHooks.test(node.name);
57404+
}
57405+
return false;
5738057406
}
5738157407
function isUseEffectEventIdentifier(node) {
57382-
{
57383-
return node.type === 'Identifier' && node.name === 'useEffectEvent';
57384-
}
57408+
return node.type === 'Identifier' && node.name === 'useEffectEvent';
57409+
}
57410+
function useEffectEventError(fn, called) {
57411+
return (`\`${fn}\` is a function created with React Hook "useEffectEvent", and can only be called from ` +
57412+
'Effects and Effect Events in the same component.' +
57413+
(called ? '' : ' It cannot be assigned to a variable or passed down.'));
5738557414
}
5738657415
function isUseIdentifier(node) {
5738757416
return isReactFunction(node, 'use');
@@ -57394,8 +57423,21 @@ const rule = {
5739457423
recommended: true,
5739557424
url: 'https://react.dev/reference/rules/rules-of-hooks',
5739657425
},
57426+
schema: [
57427+
{
57428+
type: 'object',
57429+
additionalProperties: false,
57430+
properties: {
57431+
additionalHooks: {
57432+
type: 'string',
57433+
},
57434+
},
57435+
},
57436+
],
5739757437
},
5739857438
create(context) {
57439+
const settings = context.settings || {};
57440+
const additionalEffectHooks = getAdditionalEffectHooksFromSettings(settings);
5739957441
let lastEffect = null;
5740057442
const codePathReactHooksMapStack = [];
5740157443
const codePathSegmentStack = [];
@@ -57676,19 +57718,15 @@ const rule = {
5767657718
reactHooks.push(node.callee);
5767757719
}
5767857720
const nodeWithoutNamespace = getNodeWithoutReactNamespace(node.callee);
57679-
if ((isEffectIdentifier(nodeWithoutNamespace) ||
57721+
if ((isEffectIdentifier(nodeWithoutNamespace, additionalEffectHooks) ||
5768057722
isUseEffectEventIdentifier(nodeWithoutNamespace)) &&
5768157723
node.arguments.length > 0) {
5768257724
lastEffect = node;
5768357725
}
5768457726
},
5768557727
Identifier(node) {
5768657728
if (lastEffect == null && useEffectEventFunctions.has(node)) {
57687-
const message = `\`${getSourceCode().getText(node)}\` is a function created with React Hook "useEffectEvent", and can only be called from ` +
57688-
'the same component.' +
57689-
(node.parent.type === 'CallExpression'
57690-
? ''
57691-
: ' They cannot be assigned to variables or passed down.');
57729+
const message = useEffectEventError(getSourceCode().getText(node), node.parent.type === 'CallExpression');
5769257730
context.report({
5769357731
node,
5769457732
message,
@@ -57755,12 +57793,10 @@ function last(array) {
5775557793
}
5775657794

5775757795
const rules = Object.assign({ 'exhaustive-deps': rule$1, 'rules-of-hooks': rule }, Object.fromEntries(Object.entries(allRules).map(([name, config]) => [name, config.rule])));
57758-
const ruleConfigs = Object.assign({ 'react-hooks/rules-of-hooks': 'error', 'react-hooks/exhaustive-deps': 'warn' }, Object.fromEntries(Object.entries(recommendedRules).map(([name, ruleConfig]) => {
57759-
return [
57760-
'react-hooks/' + name,
57761-
mapErrorSeverityToESlint(ruleConfig.severity),
57762-
];
57763-
})));
57796+
const ruleConfigs = {
57797+
'react-hooks/rules-of-hooks': 'error',
57798+
'react-hooks/exhaustive-deps': 'warn',
57799+
};
5776457800
const plugin = {
5776557801
meta: {
5776657802
name: 'eslint-plugin-react-hooks',

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
ef8894452b826f905d69e61435c6f2c30731bfa6
1+
2e68dc76a41165d16b35d6eb2e7bf13aafed9aef
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
ef8894452b826f905d69e61435c6f2c30731bfa6
1+
2e68dc76a41165d16b35d6eb2e7bf13aafed9aef

compiled/facebook-www/React-dev.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1458,7 +1458,7 @@ __DEV__ &&
14581458
exports.useTransition = function () {
14591459
return resolveDispatcher().useTransition();
14601460
};
1461-
exports.version = "19.2.0-www-classic-ef889445-20250930";
1461+
exports.version = "19.3.0-www-classic-2e68dc76-20251002";
14621462
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
14631463
"function" ===
14641464
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-dev.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1458,7 +1458,7 @@ __DEV__ &&
14581458
exports.useTransition = function () {
14591459
return resolveDispatcher().useTransition();
14601460
};
1461-
exports.version = "19.2.0-www-modern-ef889445-20250930";
1461+
exports.version = "19.3.0-www-modern-2e68dc76-20251002";
14621462
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
14631463
"function" ===
14641464
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-prod.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -604,4 +604,4 @@ exports.useSyncExternalStore = function (
604604
exports.useTransition = function () {
605605
return ReactSharedInternals.H.useTransition();
606606
};
607-
exports.version = "19.2.0-www-classic-ef889445-20250930";
607+
exports.version = "19.3.0-www-classic-2e68dc76-20251002";

compiled/facebook-www/React-prod.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -604,4 +604,4 @@ exports.useSyncExternalStore = function (
604604
exports.useTransition = function () {
605605
return ReactSharedInternals.H.useTransition();
606606
};
607-
exports.version = "19.2.0-www-modern-ef889445-20250930";
607+
exports.version = "19.3.0-www-modern-2e68dc76-20251002";

compiled/facebook-www/React-profiling.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ exports.useSyncExternalStore = function (
608608
exports.useTransition = function () {
609609
return ReactSharedInternals.H.useTransition();
610610
};
611-
exports.version = "19.2.0-www-classic-ef889445-20250930";
611+
exports.version = "19.3.0-www-classic-2e68dc76-20251002";
612612
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
613613
"function" ===
614614
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-profiling.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ exports.useSyncExternalStore = function (
608608
exports.useTransition = function () {
609609
return ReactSharedInternals.H.useTransition();
610610
};
611-
exports.version = "19.2.0-www-modern-ef889445-20250930";
611+
exports.version = "19.3.0-www-modern-2e68dc76-20251002";
612612
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
613613
"function" ===
614614
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

0 commit comments

Comments
 (0)