Skip to content

Commit 96d9825

Browse files
author
Joe Savona
committed
[compiler][wip] Allow suppressions within effects
1 parent 0fba073 commit 96d9825

12 files changed

+329
-62
lines changed

compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import {NodePath} from '@babel/traverse';
99
import * as t from '@babel/types';
1010
import prettyFormat from 'pretty-format';
11-
import {Logger, ProgramContext} from '.';
11+
import {Logger, ProgramContext, SingleLineSuppressionRange} from '.';
1212
import {
1313
HIRFunction,
1414
ReactiveFunction,
@@ -121,6 +121,7 @@ function run(
121121
logger: Logger | null,
122122
filename: string | null,
123123
code: string | null,
124+
suppressions: Array<SingleLineSuppressionRange>,
124125
): CodegenFunction {
125126
const contextIdentifiers = findContextIdentifiers(func);
126127
const env = new Environment(
@@ -134,6 +135,7 @@ function run(
134135
filename,
135136
code,
136137
programContext,
138+
suppressions,
137139
);
138140
env.logger?.debugLogIRs?.({
139141
kind: 'debug',
@@ -567,6 +569,7 @@ export function compileFn(
567569
logger: Logger | null,
568570
filename: string | null,
569571
code: string | null,
572+
singleLineSuppressions: Array<SingleLineSuppressionRange>,
570573
): CodegenFunction {
571574
return run(
572575
func,
@@ -577,5 +580,6 @@ export function compileFn(
577580
logger,
578581
filename,
579582
code,
583+
singleLineSuppressions,
580584
);
581585
}

compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ import {
2727
import {CompilerReactTarget, PluginOptions} from './Options';
2828
import {compileFn} from './Pipeline';
2929
import {
30-
filterSuppressionsThatAffectFunction,
30+
filterSuppressionsThatAffectNode,
3131
findProgramSuppressions,
32+
SingleLineSuppressionRange,
3233
suppressionsToCompilerError,
3334
} from './Suppression';
3435
import {GeneratedSource} from '../HIR';
@@ -691,11 +692,17 @@ function tryCompileFunction(
691692
* Program node itself. We need to figure out whether an eslint suppression range
692693
* applies to this function first.
693694
*/
694-
const suppressionsInFunction = filterSuppressionsThatAffectFunction(
695+
const suppressionsInFunction = filterSuppressionsThatAffectNode(
695696
programContext.suppressions,
696697
fn,
697698
);
698-
if (suppressionsInFunction.length > 0) {
699+
const singleLineSuppressions = suppressionsInFunction.filter(
700+
s => s.kind === 'single-line',
701+
) as Array<SingleLineSuppressionRange>;
702+
const multiLineSuppressions = suppressionsInFunction.filter(
703+
s => s.kind === 'multi-line',
704+
);
705+
if (multiLineSuppressions.length > 0) {
699706
return {
700707
kind: 'error',
701708
error: suppressionsToCompilerError(suppressionsInFunction),
@@ -714,6 +721,7 @@ function tryCompileFunction(
714721
programContext.opts.logger,
715722
programContext.filename,
716723
programContext.code,
724+
singleLineSuppressions,
717725
),
718726
};
719727
} catch (err) {
@@ -752,6 +760,7 @@ function retryCompileFunction(
752760
programContext.opts.logger,
753761
programContext.filename,
754762
programContext.code,
763+
[], // ignore suppressions in the retry pipeline
755764
);
756765

757766
if (!retryResult.hasFireRewrite && !retryResult.hasInferredEffect) {

compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts

Lines changed: 75 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,23 @@ import {GeneratedSource} from '../HIR';
2525
* The enable comment can be missing in the case where only a disable block is present, ie the rest
2626
* of the file has potential React violations.
2727
*/
28-
export type SuppressionRange = {
29-
disableComment: t.Comment;
30-
enableComment: t.Comment | null;
31-
source: SuppressionSource;
32-
};
28+
export type SuppressionRange =
29+
| {
30+
kind: 'single-line';
31+
source: SuppressionSource;
32+
comment: t.Comment;
33+
}
34+
| {
35+
kind: 'multi-line';
36+
source: SuppressionSource;
37+
disableComment: t.Comment;
38+
enableComment: t.Comment | null;
39+
};
40+
41+
export type SingleLineSuppressionRange = Extract<
42+
SuppressionRange,
43+
{kind: 'single-line'}
44+
>;
3345

3446
type SuppressionSource = 'Eslint' | 'Flow';
3547

@@ -38,38 +50,44 @@ type SuppressionSource = 'Eslint' | 'Flow';
3850
* 1. The suppression is within the function's body; or
3951
* 2. The suppression wraps the function
4052
*/
41-
export function filterSuppressionsThatAffectFunction(
42-
suppressionRanges: Array<SuppressionRange>,
43-
fn: NodePath<t.Function>,
44-
): Array<SuppressionRange> {
45-
const suppressionsInScope: Array<SuppressionRange> = [];
46-
const fnNode = fn.node;
53+
export function filterSuppressionsThatAffectNode<T extends SuppressionRange>(
54+
suppressionRanges: Array<T>,
55+
node: NodePath,
56+
): Array<T> {
57+
const suppressionsInScope: Array<T> = [];
58+
const fnNode = node.node;
4759
for (const suppressionRange of suppressionRanges) {
60+
const enableComment =
61+
suppressionRange.kind === 'single-line'
62+
? suppressionRange.comment
63+
: suppressionRange.enableComment;
64+
const disableComment =
65+
suppressionRange.kind === 'single-line'
66+
? suppressionRange.comment
67+
: suppressionRange.disableComment;
4868
if (
49-
suppressionRange.disableComment.start == null ||
69+
disableComment.start == null ||
5070
fnNode.start == null ||
5171
fnNode.end == null
5272
) {
5373
continue;
5474
}
5575
// The suppression is within the function
5676
if (
57-
suppressionRange.disableComment.start > fnNode.start &&
77+
disableComment.start > fnNode.start &&
5878
// If there is no matching enable, the rest of the file has potential violations
59-
(suppressionRange.enableComment === null ||
60-
(suppressionRange.enableComment.end != null &&
61-
suppressionRange.enableComment.end < fnNode.end))
79+
(enableComment === null ||
80+
(enableComment.end != null && enableComment.end < fnNode.end))
6281
) {
6382
suppressionsInScope.push(suppressionRange);
6483
}
6584

6685
// The suppression wraps the function
6786
if (
68-
suppressionRange.disableComment.start < fnNode.start &&
87+
disableComment.start < fnNode.start &&
6988
// If there is no matching enable, the rest of the file has potential violations
70-
(suppressionRange.enableComment === null ||
71-
(suppressionRange.enableComment.end != null &&
72-
suppressionRange.enableComment.end > fnNode.end))
89+
(enableComment === null ||
90+
(enableComment.end != null && enableComment.end > fnNode.end))
7391
) {
7492
suppressionsInScope.push(suppressionRange);
7593
}
@@ -83,9 +101,7 @@ export function findProgramSuppressions(
83101
flowSuppressions: boolean,
84102
): Array<SuppressionRange> {
85103
const suppressionRanges: Array<SuppressionRange> = [];
86-
let disableComment: t.Comment | null = null;
87-
let enableComment: t.Comment | null = null;
88-
let source: SuppressionSource | null = null;
104+
let suppression: SuppressionRange | null = null;
89105

90106
const rulePattern = `(${ruleNames.join('|')})`;
91107
const disableNextLinePattern = new RegExp(
@@ -107,42 +123,49 @@ export function findProgramSuppressions(
107123
* If we're already within a CommentBlock, we should not restart the range prematurely for a
108124
* CommentLine within the block.
109125
*/
110-
disableComment == null &&
126+
suppression == null &&
111127
disableNextLinePattern.test(comment.value)
112128
) {
113-
disableComment = comment;
114-
enableComment = comment;
115-
source = 'Eslint';
129+
suppression = {
130+
kind: 'single-line',
131+
comment,
132+
source: 'Eslint',
133+
};
116134
}
117135

118136
if (
119137
flowSuppressions &&
120-
disableComment == null &&
138+
suppression == null &&
121139
flowSuppressionPattern.test(comment.value)
122140
) {
123-
disableComment = comment;
124-
enableComment = comment;
125-
source = 'Flow';
141+
suppression = {
142+
kind: 'single-line',
143+
comment,
144+
source: 'Flow',
145+
};
126146
}
127147

128148
if (disablePattern.test(comment.value)) {
129-
disableComment = comment;
130-
source = 'Eslint';
149+
suppression = {
150+
kind: 'multi-line',
151+
disableComment: comment,
152+
enableComment: null,
153+
source: 'Eslint',
154+
};
131155
}
132156

133-
if (enablePattern.test(comment.value) && source === 'Eslint') {
134-
enableComment = comment;
157+
if (
158+
enablePattern.test(comment.value) &&
159+
suppression != null &&
160+
suppression.kind === 'multi-line' &&
161+
suppression.source === 'Eslint'
162+
) {
163+
suppression.enableComment = comment;
135164
}
136165

137-
if (disableComment != null && source != null) {
138-
suppressionRanges.push({
139-
disableComment: disableComment,
140-
enableComment: enableComment,
141-
source,
142-
});
143-
disableComment = null;
144-
enableComment = null;
145-
source = null;
166+
if (suppression != null) {
167+
suppressionRanges.push(suppression);
168+
suppression = null;
146169
}
147170
}
148171
return suppressionRanges;
@@ -157,10 +180,11 @@ export function suppressionsToCompilerError(
157180
});
158181
const error = new CompilerError();
159182
for (const suppressionRange of suppressionRanges) {
160-
if (
161-
suppressionRange.disableComment.start == null ||
162-
suppressionRange.disableComment.end == null
163-
) {
183+
const disableComment =
184+
suppressionRange.kind === 'single-line'
185+
? suppressionRange.comment
186+
: suppressionRange.disableComment;
187+
if (disableComment.start == null || disableComment.end == null) {
164188
continue;
165189
}
166190
let reason, suggestion;
@@ -185,22 +209,19 @@ export function suppressionsToCompilerError(
185209
error.pushDiagnostic(
186210
CompilerDiagnostic.create({
187211
reason: reason,
188-
description: `React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression \`${suppressionRange.disableComment.value.trim()}\``,
212+
description: `React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. Found suppression \`${disableComment.value.trim()}\``,
189213
severity: ErrorSeverity.InvalidReact,
190214
category: ErrorCategory.Suppression,
191215
suggestions: [
192216
{
193217
description: suggestion,
194-
range: [
195-
suppressionRange.disableComment.start,
196-
suppressionRange.disableComment.end,
197-
],
218+
range: [disableComment.start, disableComment.end],
198219
op: CompilerSuggestionOperation.Remove,
199220
},
200221
],
201222
}).withDetail({
202223
kind: 'error',
203-
loc: suppressionRange.disableComment.loc ?? null,
224+
loc: disableComment.loc ?? null,
204225
message: 'Found React rule suppression',
205226
}),
206227
);

0 commit comments

Comments
 (0)