@samitouri / QOS-React / commits / 60d9b9740d

[compiler] Derive ErrorSeverity from ErrorCategory (#34401)

With #34176 we now have granular lint rules created for each compiler ErrorCategory. However, we had remnants of our old error severities still in use which makes reporting errors quite clunky. Previously you would need to specify both a category and severity which often ended up being the same. This PR moves severity definition into our rules which are generated from our categories. For now I decided to defer "upgrading" categories from a simple string to a sum type since we are only using severities to map errors to eslint severity. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/34401). * #34409 * #34404 * #34403 * #34402 * __->__ #34401

lauren committed Sep 6, 2025 at 12:41 UTC 60d9b9740d77bd2715f5f725245093a23f95e347
63 files changed +379 -395
compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts
+210 -144
@@ -14,50 +14,28 @@ import invariant from 'invariant';
14
15 export enum ErrorSeverity {
16 /**
17 - * Invalid JS syntax, or valid syntax that is semantically invalid which may indicate some
18 - * misunderstanding on the user’s part.
17 + * An actionable error that the developer can fix. For example, product code errors should be
18 + * reported as such.
19 */
20 - InvalidJS = 'InvalidJS',
20 + Error = 'Error',
21 /**
22 - * JS syntax that is not supported and which we do not plan to support. Developers should
23 - * rewrite to use supported forms.
22 + * An error that the developer may not necessarily be able to fix. For example, syntax not
23 + * supported by the compiler does not indicate any fault in the product code.
24 */
25 - UnsupportedJS = 'UnsupportedJS',
25 + Warning = 'Warning',
26 /**
27 - * Code that breaks the rules of React.
27 + * Not an error. These will not be surfaced in ESLint, but may be surfaced in other ways
28 + * (eg Forgive) where informational hints can be shown.
29 */
29 - InvalidReact = 'InvalidReact',
30 + Hint = 'Hint',
31 /**
31 - * Incorrect configuration of the compiler.
32 + * These errors will not be reported anywhere. Useful for work in progress validations.
33 */
33 - InvalidConfig = 'InvalidConfig',
34 - /**
35 - * Code that can reasonably occur and that doesn't break any rules, but is unsafe to preserve
36 - * memoization.
37 - */
38 - CannotPreserveMemoization = 'CannotPreserveMemoization',
39 - /**
40 - * An API that is known to be incompatible with the compiler. Generally as a result of
41 - * the library using "interior mutability", ie having a value whose referential identity
42 - * stays the same but which provides access to values that can change. For example a
43 - * function that doesn't change but returns different results, or an object that doesn't
44 - * change identity but whose properties change.
45 - */
46 - IncompatibleLibrary = 'IncompatibleLibrary',
47 - /**
48 - * Unhandled syntax that we don't support yet.
49 - */
50 - Todo = 'Todo',
51 - /**
52 - * An unexpected internal error in the compiler that indicates critical issues that can panic
53 - * the compiler.
54 - */
55 - Invariant = 'Invariant',
34 + Off = 'Off',
35 }
36
37 export type CompilerDiagnosticOptions = {
38 category: ErrorCategory;
60 - severity: ErrorSeverity;
39 reason: string;
40 description: string;
41 details: Array<CompilerDiagnosticDetail>;
@@ -102,7 +80,6 @@ export type CompilerSuggestion =
80
81 export type CompilerErrorDetailOptions = {
82 category: ErrorCategory;
105 - severity: ErrorSeverity;
83 reason: string;
84 description?: string | null | undefined;
85 loc: SourceLocation | null;
@@ -136,8 +113,8 @@ export class CompilerDiagnostic {
113 get description(): CompilerDiagnosticOptions['description'] {
114 return this.options.description;
115 }
139 - get severity(): CompilerDiagnosticOptions['severity'] {
140 - return this.options.severity;
116 + get severity(): ErrorSeverity {
117 + return getRuleForCategory(this.category).severity;
118 }
119 get suggestions(): CompilerDiagnosticOptions['suggestions'] {
120 return this.options.suggestions;
@@ -162,7 +139,7 @@ export class CompilerDiagnostic {
139
140 printErrorMessage(source: string, options: PrintErrorMessageOptions): string {
141 const buffer = [
165 - printErrorSummary(this.severity, this.reason),
142 + printErrorSummary(this.category, this.reason),
143 '\n\n',
144 this.description,
145 ];
@@ -207,7 +184,7 @@ export class CompilerDiagnostic {
184 }
185
186 toString(): string {
210 - const buffer = [printErrorSummary(this.severity, this.reason)];
187 + const buffer = [printErrorSummary(this.category, this.reason)];
188 if (this.description != null) {
189 buffer.push(`. ${this.description}.`);
190 }
@@ -236,8 +213,8 @@ export class CompilerErrorDetail {
213 get description(): CompilerErrorDetailOptions['description'] {
214 return this.options.description;
215 }
239 - get severity(): CompilerErrorDetailOptions['severity'] {
240 - return this.options.severity;
216 + get severity(): ErrorSeverity {
217 + return getRuleForCategory(this.category).severity;
218 }
219 get loc(): CompilerErrorDetailOptions['loc'] {
220 return this.options.loc;
@@ -254,7 +231,7 @@ export class CompilerErrorDetail {
231 }
232
233 printErrorMessage(source: string, options: PrintErrorMessageOptions): string {
257 - const buffer = [printErrorSummary(this.severity, this.reason)];
234 + const buffer = [printErrorSummary(this.category, this.reason)];
235 if (this.description != null) {
236 buffer.push(`\n\n${this.description}.`);
237 }
@@ -279,7 +256,7 @@ export class CompilerErrorDetail {
256 }
257
258 toString(): string {
282 - const buffer = [printErrorSummary(this.severity, this.reason)];
259 + const buffer = [printErrorSummary(this.category, this.reason)];
260 if (this.description != null) {
261 buffer.push(`. ${this.description}.`);
262 }
@@ -305,7 +282,6 @@ export class CompilerError extends Error {
282 new CompilerErrorDetail({
283 ...options,
284 category: ErrorCategory.Invariant,
308 - severity: ErrorSeverity.Invariant,
285 }),
286 );
287 throw errors;
@@ -325,7 +301,6 @@ export class CompilerError extends Error {
301 errors.pushErrorDetail(
302 new CompilerErrorDetail({
303 ...options,
328 - severity: ErrorSeverity.Todo,
304 category: ErrorCategory.Todo,
305 }),
306 );
@@ -339,7 +314,6 @@ export class CompilerError extends Error {
314 errors.pushErrorDetail(
315 new CompilerErrorDetail({
316 ...options,
342 - severity: ErrorSeverity.InvalidJS,
317 category: ErrorCategory.Syntax,
318 }),
319 );
@@ -350,12 +324,7 @@ export class CompilerError extends Error {
324 options: Omit<CompilerErrorDetailOptions, 'severity'>,
325 ): never {
326 const errors = new CompilerError();
353 - errors.pushErrorDetail(
354 - new CompilerErrorDetail({
355 - ...options,
356 - severity: ErrorSeverity.InvalidReact,
357 - }),
358 - );
327 + errors.pushErrorDetail(new CompilerErrorDetail(options));
328 throw errors;
329 }
330
@@ -366,7 +335,6 @@ export class CompilerError extends Error {
335 errors.pushErrorDetail(
336 new CompilerErrorDetail({
337 ...options,
369 - severity: ErrorSeverity.InvalidConfig,
338 category: ErrorCategory.Config,
339 }),
340 );
@@ -434,7 +402,6 @@ export class CompilerError extends Error {
402 category: options.category,
403 reason: options.reason,
404 description: options.description ?? null,
437 - severity: options.severity,
405 suggestions: options.suggestions,
406 loc: typeof options.loc === 'symbol' ? null : options.loc,
407 });
@@ -454,31 +421,58 @@ export class CompilerError extends Error {
421 return this.hasErrors() ? Err(this) : Ok(undefined);
422 }
423
457 - /*
458 - * An error is critical if it means the compiler has entered into a broken state and cannot
459 - * continue safely. Other expected errors such as Todos mean that we can skip over that component
460 - * but otherwise continue compiling the rest of the app.
461 - */
462 - isCritical(): boolean {
463 - return this.details.some(detail => {
464 - switch (detail.severity) {
465 - case ErrorSeverity.Invariant:
466 - case ErrorSeverity.InvalidJS:
467 - case ErrorSeverity.InvalidReact:
468 - case ErrorSeverity.InvalidConfig:
469 - case ErrorSeverity.UnsupportedJS:
470 - case ErrorSeverity.IncompatibleLibrary: {
471 - return true;
472 - }
473 - case ErrorSeverity.CannotPreserveMemoization:
474 - case ErrorSeverity.Todo: {
475 - return false;
476 - }
477 - default: {
478 - assertExhaustive(detail.severity, 'Unhandled error severity');
479 - }
424 + /**
425 + * Returns true if any of the error details are of severity Error.
426 + */
427 + isError(): boolean {
428 + let res = false;
429 + for (const detail of this.details) {
430 + if (detail.severity === ErrorSeverity.Off) {
431 + return false;
432 }
481 - });
433 + if (detail.severity === ErrorSeverity.Error) {
434 + res = true;
435 + }
436 + }
437 + return res;
438 + }
439 +
440 + /**
441 + * Returns true if there are no Errors and there is at least one Warning.
442 + */
443 + isWarning(): boolean {
444 + let res = false;
445 + for (const detail of this.details) {
446 + if (detail.severity === ErrorSeverity.Off) {
447 + return false;
448 + }
449 + if (detail.severity === ErrorSeverity.Error) {
450 + return false;
451 + }
452 + if (detail.severity === ErrorSeverity.Warning) {
453 + res = true;
454 + }
455 + }
456 + return res;
457 + }
458 +
459 + isHint(): boolean {
460 + let res = false;
461 + for (const detail of this.details) {
462 + if (detail.severity === ErrorSeverity.Off) {
463 + return false;
464 + }
465 + if (detail.severity === ErrorSeverity.Error) {
466 + return false;
467 + }
468 + if (detail.severity === ErrorSeverity.Warning) {
469 + return false;
470 + }
471 + if (detail.severity === ErrorSeverity.Hint) {
472 + res = true;
473 + }
474 + }
475 + return res;
476 }
477 }
478
@@ -505,115 +499,158 @@ function printCodeFrame(
499 );
500 }
501
508 -function printErrorSummary(severity: ErrorSeverity, message: string): string {
509 - let severityCategory: string;
510 - switch (severity) {
511 - case ErrorSeverity.InvalidConfig:
512 - case ErrorSeverity.InvalidJS:
513 - case ErrorSeverity.InvalidReact:
514 - case ErrorSeverity.UnsupportedJS: {
515 - severityCategory = 'Error';
502 +function printErrorSummary(category: ErrorCategory, message: string): string {
503 + let heading: string;
504 + switch (category) {
505 + case ErrorCategory.AutomaticEffectDependencies:
506 + case ErrorCategory.CapitalizedCalls:
507 + case ErrorCategory.Config:
508 + case ErrorCategory.EffectDerivationsOfState:
509 + case ErrorCategory.EffectSetState:
510 + case ErrorCategory.ErrorBoundaries:
511 + case ErrorCategory.Factories:
512 + case ErrorCategory.FBT:
513 + case ErrorCategory.Fire:
514 + case ErrorCategory.Gating:
515 + case ErrorCategory.Globals:
516 + case ErrorCategory.Hooks:
517 + case ErrorCategory.Immutability:
518 + case ErrorCategory.Purity:
519 + case ErrorCategory.Refs:
520 + case ErrorCategory.RenderSetState:
521 + case ErrorCategory.StaticComponents:
522 + case ErrorCategory.Suppression:
523 + case ErrorCategory.Syntax:
524 + case ErrorCategory.UseMemo: {
525 + heading = 'Error';
526 break;
527 }
518 - case ErrorSeverity.IncompatibleLibrary:
519 - case ErrorSeverity.CannotPreserveMemoization: {
520 - severityCategory = 'Compilation Skipped';
528 + case ErrorCategory.EffectDependencies:
529 + case ErrorCategory.IncompatibleLibrary:
530 + case ErrorCategory.PreserveManualMemo:
531 + case ErrorCategory.UnsupportedSyntax: {
532 + heading = 'Compilation Skipped';
533 break;
534 }
523 - case ErrorSeverity.Invariant: {
524 - severityCategory = 'Invariant';
535 + case ErrorCategory.Invariant: {
536 + heading = 'Invariant';
537 break;
538 }
527 - case ErrorSeverity.Todo: {
528 - severityCategory = 'Todo';
539 + case ErrorCategory.Todo: {
540 + heading = 'Todo';
541 break;
542 }
543 default: {
532 - assertExhaustive(severity, `Unexpected severity '${severity}'`);
544 + assertExhaustive(category, `Unhandled category '${category}'`);
545 }
546 }
535 - return `${severityCategory}: ${message}`;
547 + return `${heading}: ${message}`;
548 }
549
550 /**
551 * See getRuleForCategory() for how these map to ESLint rules
552 */
553 export enum ErrorCategory {
542 - // Checking for valid hooks usage (non conditional, non-first class, non reactive, etc)
554 + /**
555 + * Checking for valid hooks usage (non conditional, non-first class, non reactive, etc)
556 + */
557 Hooks = 'Hooks',
544 -
545 - // Checking for no capitalized calls (not definitively an error, hence separating)
558 + /**
559 + * Checking for no capitalized calls (not definitively an error, hence separating)
560 + */
561 CapitalizedCalls = 'CapitalizedCalls',
547 -
548 - // Checking for static components
562 + /**
563 + * Checking for static components
564 + */
565 StaticComponents = 'StaticComponents',
550 -
551 - // Checking for valid usage of manual memoization
566 + /**
567 + * Checking for valid usage of manual memoization
568 + */
569 UseMemo = 'UseMemo',
553 -
554 - // Checking for higher order functions acting as factories for components/hooks
570 + /**
571 + * Checking for higher order functions acting as factories for components/hooks
572 + */
573 Factories = 'Factories',
556 -
557 - // Checks that manual memoization is preserved
574 + /**
575 + * Checks that manual memoization is preserved
576 + */
577 PreserveManualMemo = 'PreserveManualMemo',
559 -
560 - // Checks for known incompatible libraries
578 + /**
579 + * Checks for known incompatible libraries
580 + */
581 IncompatibleLibrary = 'IncompatibleLibrary',
562 -
563 - // Checking for no mutations of props, hook arguments, hook return values
582 + /**
583 + * Checking for no mutations of props, hook arguments, hook return values
584 + */
585 Immutability = 'Immutability',
565 -
566 - // Checking for assignments to globals
586 + /**
587 + * Checking for assignments to globals
588 + */
589 Globals = 'Globals',
568 -
569 - // Checking for valid usage of refs, ie no access during render
590 + /**
591 + * Checking for valid usage of refs, ie no access during render
592 + */
593 Refs = 'Refs',
571 -
572 - // Checks for memoized effect deps
594 + /**
595 + * Checks for memoized effect deps
596 + */
597 EffectDependencies = 'EffectDependencies',
574 -
575 - // Checks for no setState in effect bodies
598 + /**
599 + * Checks for no setState in effect bodies
600 + */
601 EffectSetState = 'EffectSetState',
577 -
602 EffectDerivationsOfState = 'EffectDerivationsOfState',
579 -
580 - // Validates against try/catch in place of error boundaries
603 + /**
604 + * Validates against try/catch in place of error boundaries
605 + */
606 ErrorBoundaries = 'ErrorBoundaries',
582 -
583 - // Checking for pure functions
607 + /**
608 + * Checking for pure functions
609 + */
610 Purity = 'Purity',
585 -
586 - // Validates against setState in render
611 + /**
612 + * Validates against setState in render
613 + */
614 RenderSetState = 'RenderSetState',
588 -
589 - // Internal invariants
615 + /**
616 + * Internal invariants
617 + */
618 Invariant = 'Invariant',
591 -
592 - // Todos
619 + /**
620 + * Todos
621 + */
622 Todo = 'Todo',
594 -
595 - // Syntax errors
623 + /**
624 + * Syntax errors
625 + */
626 Syntax = 'Syntax',
597 -
598 - // Checks for use of unsupported syntax
627 + /**
628 + * Checks for use of unsupported syntax
629 + */
630 UnsupportedSyntax = 'UnsupportedSyntax',
600 -
601 - // Config errors
631 + /**
632 + * Config errors
633 + */
634 Config = 'Config',
603 -
604 - // Gating error
635 + /**
636 + * Gating error
637 + */
638 Gating = 'Gating',
606 -
607 - // Suppressions
639 + /**
640 + * Suppressions
641 + */
642 Suppression = 'Suppression',
609 -
610 - // Issues with auto deps
643 + /**
644 + * Issues with auto deps
645 + */
646 AutomaticEffectDependencies = 'AutomaticEffectDependencies',
612 -
613 - // Issues with `fire`
647 + /**
648 + * Issues with `fire`
649 + */
650 Fire = 'Fire',
615 -
616 - // fbt-specific issues
651 + /**
652 + * fbt-specific issues
653 + */
654 FBT = 'FBT',
655 }
656
@@ -621,6 +658,9 @@ export type LintRule = {
658 // Stores the category the rule corresponds to, used to filter errors when reporting
659 category: ErrorCategory;
660
661 + // Stores the severity of the error, which is used to map to lint levels such as error/warning.
662 + severity: ErrorSeverity;
663 +
664 /**
665 * The "name" of the rule as it will be used by developers to enable/disable, eg
666 * "eslint-disable-nest line <name>"
@@ -661,6 +701,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
701 case ErrorCategory.AutomaticEffectDependencies: {
702 return {
703 category,
704 + severity: ErrorSeverity.Error,
705 name: 'automatic-effect-dependencies',
706 description:
707 'Verifies that automatic effect dependencies are compiled if opted-in',
@@ -670,6 +711,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
711 case ErrorCategory.CapitalizedCalls: {
712 return {
713 category,
714 + severity: ErrorSeverity.Error,
715 name: 'capitalized-calls',
716 description:
717 'Validates against calling capitalized functions/methods instead of using JSX',
@@ -679,6 +721,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
721 case ErrorCategory.Config: {
722 return {
723 category,
724 + severity: ErrorSeverity.Error,
725 name: 'config',
726 description: 'Validates the compiler configuration options',
727 recommended: true,
@@ -687,6 +730,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
730 case ErrorCategory.EffectDependencies: {
731 return {
732 category,
733 + severity: ErrorSeverity.Error,
734 name: 'memoized-effect-dependencies',
735 description: 'Validates that effect dependencies are memoized',
736 recommended: false,
@@ -695,6 +739,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
739 case ErrorCategory.EffectDerivationsOfState: {
740 return {
741 category,
742 + severity: ErrorSeverity.Error,
743 name: 'no-deriving-state-in-effects',
744 description:
745 'Validates against deriving values from state in an effect',
@@ -704,6 +749,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
749 case ErrorCategory.EffectSetState: {
750 return {
751 category,
752 + severity: ErrorSeverity.Error,
753 name: 'set-state-in-effect',
754 description:
755 'Validates against calling setState synchronously in an effect, which can lead to re-renders that degrade performance',
@@ -713,6 +759,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
759 case ErrorCategory.ErrorBoundaries: {
760 return {
761 category,
762 + severity: ErrorSeverity.Error,
763 name: 'error-boundaries',
764 description:
765 'Validates usage of error boundaries instead of try/catch for errors in child components',
@@ -722,6 +769,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
769 case ErrorCategory.Factories: {
770 return {
771 category,
772 + severity: ErrorSeverity.Error,
773 name: 'component-hook-factories',
774 description:
775 'Validates against higher order functions defining nested components or hooks. ' +
@@ -732,6 +780,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
780 case ErrorCategory.FBT: {
781 return {
782 category,
783 + severity: ErrorSeverity.Error,
784 name: 'fbt',
785 description: 'Validates usage of fbt',
786 recommended: false,
@@ -740,6 +789,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
789 case ErrorCategory.Fire: {
790 return {
791 category,
792 + severity: ErrorSeverity.Error,
793 name: 'fire',
794 description: 'Validates usage of `fire`',
795 recommended: false,
@@ -748,6 +798,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
798 case ErrorCategory.Gating: {
799 return {
800 category,
801 + severity: ErrorSeverity.Error,
802 name: 'gating',
803 description:
804 'Validates configuration of [gating mode](https://react.dev/reference/react-compiler/gating)',
@@ -757,6 +808,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
808 case ErrorCategory.Globals: {
809 return {
810 category,
811 + severity: ErrorSeverity.Error,
812 name: 'globals',
813 description:
814 'Validates against assignment/mutation of globals during render, part of ensuring that ' +
@@ -767,6 +819,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
819 case ErrorCategory.Hooks: {
820 return {
821 category,
822 + severity: ErrorSeverity.Error,
823 name: 'hooks',
824 description: 'Validates the rules of hooks',
825 /**
@@ -780,6 +833,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
833 case ErrorCategory.Immutability: {
834 return {
835 category,
836 + severity: ErrorSeverity.Error,
837 name: 'immutability',
838 description:
839 'Validates against mutating props, state, and other values that [are immutable](https://react.dev/reference/rules/components-and-hooks-must-be-pure#props-and-state-are-immutable)',
@@ -789,6 +843,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
843 case ErrorCategory.Invariant: {
844 return {
845 category,
846 + severity: ErrorSeverity.Error,
847 name: 'invariant',
848 description: 'Internal invariants',
849 recommended: false,
@@ -797,6 +852,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
852 case ErrorCategory.PreserveManualMemo: {
853 return {
854 category,
855 + severity: ErrorSeverity.Error,
856 name: 'preserve-manual-memoization',
857 description:
858 'Validates that existing manual memoized is preserved by the compiler. ' +
@@ -808,6 +864,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
864 case ErrorCategory.Purity: {
865 return {
866 category,
867 + severity: ErrorSeverity.Error,
868 name: 'purity',
869 description:
870 'Validates that [components/hooks are pure](https://react.dev/reference/rules/components-and-hooks-must-be-pure) by checking that they do not call known-impure functions',
@@ -817,6 +874,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
874 case ErrorCategory.Refs: {
875 return {
876 category,
877 + severity: ErrorSeverity.Error,
878 name: 'refs',
879 description:
880 'Validates correct usage of refs, not reading/writing during render. See the "pitfalls" section in [`useRef()` usage](https://react.dev/reference/react/useRef#usage)',
@@ -826,6 +884,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
884 case ErrorCategory.RenderSetState: {
885 return {
886 category,
887 + severity: ErrorSeverity.Error,
888 name: 'set-state-in-render',
889 description:
890 'Validates against setting state during render, which can trigger additional renders and potential infinite render loops',
@@ -835,6 +894,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
894 case ErrorCategory.StaticComponents: {
895 return {
896 category,
897 + severity: ErrorSeverity.Error,
898 name: 'static-components',
899 description:
900 'Validates that components are static, not recreated every render. Components that are recreated dynamically can reset state and trigger excessive re-rendering',
@@ -844,6 +904,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
904 case ErrorCategory.Suppression: {
905 return {
906 category,
907 + severity: ErrorSeverity.Error,
908 name: 'rule-suppression',
909 description: 'Validates against suppression of other rules',
910 recommended: false,
@@ -852,6 +913,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
913 case ErrorCategory.Syntax: {
914 return {
915 category,
916 + severity: ErrorSeverity.Error,
917 name: 'syntax',
918 description: 'Validates against invalid syntax',
919 recommended: false,
@@ -860,6 +922,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
922 case ErrorCategory.Todo: {
923 return {
924 category,
925 + severity: ErrorSeverity.Hint,
926 name: 'todo',
927 description: 'Unimplemented features',
928 recommended: false,
@@ -868,6 +931,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
931 case ErrorCategory.UnsupportedSyntax: {
932 return {
933 category,
934 + severity: ErrorSeverity.Warning,
935 name: 'unsupported-syntax',
936 description:
937 'Validates against syntax that we do not plan to support in React Compiler',
@@ -877,6 +941,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
941 case ErrorCategory.UseMemo: {
942 return {
943 category,
944 + severity: ErrorSeverity.Error,
945 name: 'use-memo',
946 description:
947 'Validates usage of the useMemo() hook against common mistakes. See [`useMemo()` docs](https://react.dev/reference/react/useMemo) for more information.',
@@ -886,6 +951,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule {
951 case ErrorCategory.IncompatibleLibrary: {
952 return {
953 category,
954 + severity: ErrorSeverity.Warning,
955 name: 'incompatible-library',
956 description:
957 'Validates against usage of libraries which are incompatible with memoization (manual or automatic)',
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts
+1 -3
@@ -9,7 +9,7 @@ import {NodePath} from '@babel/core';
9 import * as t from '@babel/types';
10 import {Scope as BabelScope} from '@babel/traverse';
11
12 -import {CompilerError, ErrorCategory, ErrorSeverity} from '../CompilerError';
12 +import {CompilerError, ErrorCategory} from '../CompilerError';
13 import {
14 EnvironmentConfig,
15 GeneratedSource,
@@ -39,7 +39,6 @@ export function validateRestrictedImports(
39 if (restrictedImports.has(importDeclPath.node.source.value)) {
40 error.push({
41 category: ErrorCategory.Todo,
42 - severity: ErrorSeverity.Todo,
42 reason: 'Bailing out due to blocklisted import',
43 description: `Import from module ${importDeclPath.node.source.value}`,
44 loc: importDeclPath.node.loc ?? null,
@@ -207,7 +206,6 @@ export class ProgramContext {
206 const error = new CompilerError();
207 error.push({
208 category: ErrorCategory.Todo,
210 - severity: ErrorSeverity.Todo,
209 reason: 'Encountered conflicting global in generated program',
210 description: `Conflict from local binding ${name}`,
211 loc: scope.getBinding(name)?.path.node.loc ?? null,
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts
+4 -13
@@ -11,7 +11,6 @@ import {
11 CompilerError,
12 CompilerErrorDetail,
13 ErrorCategory,
14 - ErrorSeverity,
14 } from '../CompilerError';
15 import {ExternalFunction, ReactFunctionType} from '../HIR/Environment';
16 import {CodegenFunction} from '../ReactiveScopes';
@@ -105,7 +104,6 @@ function findDirectivesDynamicGating(
104 errors.push({
105 reason: `Dynamic gating directive is not a valid JavaScript identifier`,
106 description: `Found '${directive.value.value}'`,
108 - severity: ErrorSeverity.InvalidReact,
107 category: ErrorCategory.Gating,
108 loc: directive.loc ?? null,
109 suggestions: null,
@@ -122,7 +120,6 @@ function findDirectivesDynamicGating(
120 description: `Expected a single directive but found [${result
121 .map(r => r.directive.value.value)
122 .join(', ')}]`,
125 - severity: ErrorSeverity.InvalidReact,
123 category: ErrorCategory.Gating,
124 loc: result[0].directive.loc ?? null,
125 suggestions: null,
@@ -141,15 +138,13 @@ function findDirectivesDynamicGating(
138 }
139 }
140
144 -function isCriticalError(err: unknown): boolean {
145 - return !(err instanceof CompilerError) || err.isCritical();
141 +function isError(err: unknown): boolean {
142 + return !(err instanceof CompilerError) || err.isError();
143 }
144
145 function isConfigError(err: unknown): boolean {
146 if (err instanceof CompilerError) {
150 - return err.details.some(
151 - detail => detail.severity === ErrorSeverity.InvalidConfig,
152 - );
147 + return err.details.some(detail => detail.category === ErrorCategory.Config);
148 }
149 return false;
150 }
@@ -214,8 +209,7 @@ function handleError(
209 logError(err, context, fnLoc);
210 if (
211 context.opts.panicThreshold === 'all_errors' ||
217 - (context.opts.panicThreshold === 'critical_errors' &&
218 - isCriticalError(err)) ||
212 + (context.opts.panicThreshold === 'critical_errors' && isError(err)) ||
213 isConfigError(err) // Always throws regardless of panic threshold
214 ) {
215 throw err;
@@ -458,7 +452,6 @@ export function compileProgram(
452 new CompilerErrorDetail({
453 reason:
454 'Unexpected compiled functions when module scope opt-out is present',
461 - severity: ErrorSeverity.Invariant,
455 category: ErrorCategory.Invariant,
456 loc: null,
457 }),
@@ -827,7 +820,6 @@ function shouldSkipCompilation(
820 reason: `Expected a filename but found none.`,
821 description:
822 "When the 'sources' config options is specified, the React compiler will only compile files with a name",
830 - severity: ErrorSeverity.InvalidConfig,
823 category: ErrorCategory.Config,
824 loc: null,
825 }),
@@ -890,7 +882,6 @@ function validateNoDynamicallyCreatedComponentsOrHooks(
882 if (nestedFnType === 'Component' || nestedFnType === 'Hook') {
883 CompilerError.throwDiagnostic({
884 category: ErrorCategory.Factories,
893 - severity: ErrorSeverity.InvalidReact,
885 reason: `Components and hooks cannot be created dynamically`,
886 description: `The function \`${nestedName}\` appears to be a React ${nestedFnType.toLowerCase()}, but it's defined inside \`${parentName}\`. Components and Hooks should always be declared at module scope`,
887 details: [
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts
-2
@@ -12,7 +12,6 @@ import {
12 CompilerError,
13 CompilerSuggestionOperation,
14 ErrorCategory,
15 - ErrorSeverity,
15 } from '../CompilerError';
16 import {assertExhaustive} from '../Utils/utils';
17 import {GeneratedSource} from '../HIR';
@@ -186,7 +185,6 @@ export function suppressionsToCompilerError(
185 CompilerDiagnostic.create({
186 reason: reason,
187 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()}\``,
189 - severity: ErrorSeverity.InvalidReact,
188 category: ErrorCategory.Suppression,
189 suggestions: [
190 {
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/ValidateNoUntransformedReferences.ts
+4 -8
@@ -8,7 +8,7 @@
8 import {NodePath} from '@babel/core';
9 import * as t from '@babel/types';
10
11 -import {CompilerError, EnvironmentConfig, ErrorSeverity, Logger} from '..';
11 +import {CompilerError, EnvironmentConfig, Logger} from '..';
12 import {getOrInsertWith} from '../Utils/utils';
13 import {Environment, GeneratedSource} from '../HIR';
14 import {DEFAULT_EXPORT} from '../HIR/Environment';
@@ -20,19 +20,15 @@ import {
20 } from '../CompilerError';
21
22 function throwInvalidReact(
23 - options: Omit<CompilerDiagnosticOptions, 'severity'>,
23 + options: CompilerDiagnosticOptions,
24 {logger, filename}: TraversalState,
25 ): never {
26 - const detail: CompilerDiagnosticOptions = {
27 - severity: ErrorSeverity.InvalidReact,
28 - ...options,
29 - };
26 logger?.logEvent(filename, {
27 kind: 'CompileError',
28 fnLoc: null,
33 - detail: new CompilerDiagnostic(detail),
29 + detail: new CompilerDiagnostic(options),
30 });
35 - CompilerError.throwDiagnostic(detail);
31 + CompilerError.throwDiagnostic(options);
32 }
33
34 function isAutodepsSigil(
compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts
+1 -76
@@ -13,7 +13,6 @@ import {
13 CompilerError,
14 CompilerSuggestionOperation,
15 ErrorCategory,
16 - ErrorSeverity,
16 } from '../CompilerError';
17 import {Err, Ok, Result} from '../Utils/Result';
18 import {assertExhaustive, hasNode} from '../Utils/utils';
@@ -108,7 +107,6 @@ export function lower(
107 if (binding.kind !== 'Identifier') {
108 builder.errors.pushDiagnostic(
109 CompilerDiagnostic.create({
111 - severity: ErrorSeverity.Invariant,
110 category: ErrorCategory.Invariant,
111 reason: 'Could not find binding',
112 description: `[BuildHIR] Could not find binding for param \`${param.node.name}\`.`,
@@ -173,7 +171,6 @@ export function lower(
171 } else {
172 builder.errors.pushDiagnostic(
173 CompilerDiagnostic.create({
176 - severity: ErrorSeverity.Todo,
174 category: ErrorCategory.Todo,
175 reason: `Handle ${param.node.type} parameters`,
176 description: `[BuildHIR] Add support for ${param.node.type} parameters.`,
@@ -205,7 +202,6 @@ export function lower(
202 } else {
203 builder.errors.pushDiagnostic(
204 CompilerDiagnostic.create({
208 - severity: ErrorSeverity.InvalidJS,
205 category: ErrorCategory.Syntax,
206 reason: `Unexpected function body kind`,
207 description: `Expected function body to be an expression or a block statement, got \`${body.type}\`.`,
@@ -276,7 +272,6 @@ function lowerStatement(
272 builder.errors.push({
273 reason:
274 '(BuildHIR::lowerStatement) Support ThrowStatement inside of try/catch',
279 - severity: ErrorSeverity.Todo,
275 category: ErrorCategory.Todo,
276 loc: stmt.node.loc ?? null,
277 suggestions: null,
@@ -464,7 +459,6 @@ function lowerStatement(
459 kind = InstructionKind.HoistedFunction;
460 } else if (!binding.path.isVariableDeclarator()) {
461 builder.errors.push({
467 - severity: ErrorSeverity.Todo,
462 category: ErrorCategory.Todo,
463 reason: 'Unsupported declaration type for hoisting',
464 description: `variable "${binding.identifier.name}" declared with ${binding.path.type}`,
@@ -474,7 +468,6 @@ function lowerStatement(
468 continue;
469 } else {
470 builder.errors.push({
477 - severity: ErrorSeverity.Todo,
471 category: ErrorCategory.Todo,
472 reason: 'Handle non-const declarations for hoisting',
473 description: `variable "${binding.identifier.name}" declared with ${binding.kind}`,
@@ -555,7 +548,6 @@ function lowerStatement(
548 builder.errors.push({
549 reason:
550 '(BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement',
558 - severity: ErrorSeverity.Todo,
551 category: ErrorCategory.Todo,
552 loc: stmt.node.loc ?? null,
553 suggestions: null,
@@ -628,7 +620,6 @@ function lowerStatement(
620 if (test.node == null) {
621 builder.errors.push({
622 reason: `(BuildHIR::lowerStatement) Handle empty test in ForStatement`,
631 - severity: ErrorSeverity.Todo,
623 category: ErrorCategory.Todo,
624 loc: stmt.node.loc ?? null,
625 suggestions: null,
@@ -780,7 +771,6 @@ function lowerStatement(
771 if (hasDefault) {
772 builder.errors.push({
773 reason: `Expected at most one \`default\` branch in a switch statement, this code should have failed to parse`,
783 - severity: ErrorSeverity.InvalidJS,
774 category: ErrorCategory.Syntax,
775 loc: case_.node.loc ?? null,
776 suggestions: null,
@@ -853,7 +843,6 @@ function lowerStatement(
843 if (nodeKind === 'var') {
844 builder.errors.push({
845 reason: `(BuildHIR::lowerStatement) Handle ${nodeKind} kinds in VariableDeclaration`,
856 - severity: ErrorSeverity.Todo,
846 category: ErrorCategory.Todo,
847 loc: stmt.node.loc ?? null,
848 suggestions: null,
@@ -882,7 +871,6 @@ function lowerStatement(
871 if (binding.kind !== 'Identifier') {
872 builder.errors.push({
873 reason: `(BuildHIR::lowerAssignment) Could not find binding for declaration.`,
885 - severity: ErrorSeverity.Invariant,
874 category: ErrorCategory.Invariant,
875 loc: id.node.loc ?? null,
876 suggestions: null,
@@ -900,7 +888,6 @@ function lowerStatement(
888 const declRangeStart = declaration.parentPath.node.start!;
889 builder.errors.push({
890 reason: `Expect \`const\` declaration not to be reassigned`,
903 - severity: ErrorSeverity.InvalidJS,
891 category: ErrorCategory.Syntax,
892 loc: id.node.loc ?? null,
893 suggestions: [
@@ -948,7 +935,6 @@ function lowerStatement(
935 builder.errors.push({
936 reason: `Expected variable declaration to be an identifier if no initializer was provided`,
937 description: `Got a \`${id.type}\``,
951 - severity: ErrorSeverity.InvalidJS,
938 category: ErrorCategory.Syntax,
939 loc: stmt.node.loc ?? null,
940 suggestions: null,
@@ -1057,7 +1043,6 @@ function lowerStatement(
1043 if (stmt.node.await) {
1044 builder.errors.push({
1045 reason: `(BuildHIR::lowerStatement) Handle for-await loops`,
1060 - severity: ErrorSeverity.Todo,
1046 category: ErrorCategory.Todo,
1047 loc: stmt.node.loc ?? null,
1048 suggestions: null,
@@ -1290,7 +1275,6 @@ function lowerStatement(
1275 if (!hasNode(handlerPath)) {
1276 builder.errors.push({
1277 reason: `(BuildHIR::lowerStatement) Handle TryStatement without a catch clause`,
1293 - severity: ErrorSeverity.Todo,
1278 category: ErrorCategory.Todo,
1279 loc: stmt.node.loc ?? null,
1280 suggestions: null,
@@ -1300,7 +1284,6 @@ function lowerStatement(
1284 if (hasNode(stmt.get('finalizer'))) {
1285 builder.errors.push({
1286 reason: `(BuildHIR::lowerStatement) Handle TryStatement with a finalizer ('finally') clause`,
1303 - severity: ErrorSeverity.Todo,
1287 category: ErrorCategory.Todo,
1288 loc: stmt.node.loc ?? null,
1289 suggestions: null,
@@ -1394,7 +1377,6 @@ function lowerStatement(
1377 builder.errors.push({
1378 reason: `JavaScript 'with' syntax is not supported`,
1379 description: `'with' syntax is considered deprecated and removed from JavaScript standards, consider alternatives`,
1397 - severity: ErrorSeverity.UnsupportedJS,
1380 category: ErrorCategory.UnsupportedSyntax,
1381 loc: stmtPath.node.loc ?? null,
1382 suggestions: null,
@@ -1415,7 +1397,6 @@ function lowerStatement(
1397 builder.errors.push({
1398 reason: 'Inline `class` declarations are not supported',
1399 description: `Move class declarations outside of components/hooks`,
1418 - severity: ErrorSeverity.UnsupportedJS,
1400 category: ErrorCategory.UnsupportedSyntax,
1401 loc: stmtPath.node.loc ?? null,
1402 suggestions: null,
@@ -1445,7 +1426,6 @@ function lowerStatement(
1426 builder.errors.push({
1427 reason:
1428 'JavaScript `import` and `export` statements may only appear at the top level of a module',
1448 - severity: ErrorSeverity.InvalidJS,
1429 category: ErrorCategory.Syntax,
1430 loc: stmtPath.node.loc ?? null,
1431 suggestions: null,
@@ -1461,7 +1441,6 @@ function lowerStatement(
1441 builder.errors.push({
1442 reason:
1443 'TypeScript `namespace` statements may only appear at the top level of a module',
1464 - severity: ErrorSeverity.InvalidJS,
1444 category: ErrorCategory.Syntax,
1445 loc: stmtPath.node.loc ?? null,
1446 suggestions: null,
@@ -1540,7 +1519,6 @@ function lowerObjectPropertyKey(
1519 */
1520 builder.errors.push({
1521 reason: `(BuildHIR::lowerExpression) Expected Identifier, got ${key.type} key in ObjectExpression`,
1543 - severity: ErrorSeverity.Todo,
1522 category: ErrorCategory.Todo,
1523 loc: key.node.loc ?? null,
1524 suggestions: null,
@@ -1566,7 +1544,6 @@ function lowerObjectPropertyKey(
1544
1545 builder.errors.push({
1546 reason: `(BuildHIR::lowerExpression) Expected Identifier, got ${key.type} key in ObjectExpression`,
1569 - severity: ErrorSeverity.Todo,
1547 category: ErrorCategory.Todo,
1548 loc: key.node.loc ?? null,
1549 suggestions: null,
@@ -1624,7 +1601,6 @@ function lowerExpression(
1601 if (!valuePath.isExpression()) {
1602 builder.errors.push({
1603 reason: `(BuildHIR::lowerExpression) Handle ${valuePath.type} values in ObjectExpression`,
1627 - severity: ErrorSeverity.Todo,
1604 category: ErrorCategory.Todo,
1605 loc: valuePath.node.loc ?? null,
1606 suggestions: null,
@@ -1651,7 +1627,6 @@ function lowerExpression(
1627 if (propertyPath.node.kind !== 'method') {
1628 builder.errors.push({
1629 reason: `(BuildHIR::lowerExpression) Handle ${propertyPath.node.kind} functions in ObjectExpression`,
1654 - severity: ErrorSeverity.Todo,
1630 category: ErrorCategory.Todo,
1631 loc: propertyPath.node.loc ?? null,
1632 suggestions: null,
@@ -1673,7 +1648,6 @@ function lowerExpression(
1648 } else {
1649 builder.errors.push({
1650 reason: `(BuildHIR::lowerExpression) Handle ${propertyPath.type} properties in ObjectExpression`,
1676 - severity: ErrorSeverity.Todo,
1651 category: ErrorCategory.Todo,
1652 loc: propertyPath.node.loc ?? null,
1653 suggestions: null,
@@ -1707,7 +1681,6 @@ function lowerExpression(
1681 } else {
1682 builder.errors.push({
1683 reason: `(BuildHIR::lowerExpression) Handle ${element.type} elements in ArrayExpression`,
1710 - severity: ErrorSeverity.Todo,
1684 category: ErrorCategory.Todo,
1685 loc: element.node.loc ?? null,
1686 suggestions: null,
@@ -1728,7 +1701,6 @@ function lowerExpression(
1701 builder.errors.push({
1702 reason: `Expected an expression as the \`new\` expression receiver (v8 intrinsics are not supported)`,
1703 description: `Got a \`${calleePath.node.type}\``,
1731 - severity: ErrorSeverity.InvalidJS,
1704 category: ErrorCategory.Syntax,
1705 loc: calleePath.node.loc ?? null,
1706 suggestions: null,
@@ -1755,7 +1727,6 @@ function lowerExpression(
1727 if (!calleePath.isExpression()) {
1728 builder.errors.push({
1729 reason: `Expected Expression, got ${calleePath.type} in CallExpression (v8 intrinsics not supported). This error is likely caused by a bug in React Compiler. Please file an issue`,
1758 - severity: ErrorSeverity.Todo,
1730 category: ErrorCategory.Todo,
1731 loc: calleePath.node.loc ?? null,
1732 suggestions: null,
@@ -1790,7 +1761,6 @@ function lowerExpression(
1761 if (!leftPath.isExpression()) {
1762 builder.errors.push({
1763 reason: `(BuildHIR::lowerExpression) Expected Expression, got ${leftPath.type} lval in BinaryExpression`,
1793 - severity: ErrorSeverity.Todo,
1764 category: ErrorCategory.Todo,
1765 loc: leftPath.node.loc ?? null,
1766 suggestions: null,
@@ -1803,7 +1773,6 @@ function lowerExpression(
1773 if (operator === '|>') {
1774 builder.errors.push({
1775 reason: `(BuildHIR::lowerExpression) Pipe operator not supported`,
1806 - severity: ErrorSeverity.Todo,
1776 category: ErrorCategory.Todo,
1777 loc: leftPath.node.loc ?? null,
1778 suggestions: null,
@@ -1833,7 +1802,6 @@ function lowerExpression(
1802 if (last === null) {
1803 builder.errors.push({
1804 reason: `Expected sequence expression to have at least one expression`,
1836 - severity: ErrorSeverity.InvalidJS,
1805 category: ErrorCategory.Syntax,
1806 loc: expr.node.loc ?? null,
1807 suggestions: null,
@@ -2046,7 +2014,6 @@ function lowerExpression(
2014 builder.errors.push({
2015 reason: `(BuildHIR::lowerExpression) Unsupported syntax on the left side of an AssignmentExpression`,
2016 description: `Expected an LVal, got: ${left.type}`,
2049 - severity: ErrorSeverity.Todo,
2017 category: ErrorCategory.Todo,
2018 loc: left.node.loc ?? null,
2019 suggestions: null,
@@ -2075,7 +2042,6 @@ function lowerExpression(
2042 if (binaryOperator == null) {
2043 builder.errors.push({
2044 reason: `(BuildHIR::lowerExpression) Handle ${operator} operators in AssignmentExpression`,
2078 - severity: ErrorSeverity.Todo,
2045 category: ErrorCategory.Todo,
2046 loc: expr.node.loc ?? null,
2047 suggestions: null,
@@ -2175,7 +2141,6 @@ function lowerExpression(
2141 default: {
2142 builder.errors.push({
2143 reason: `(BuildHIR::lowerExpression) Expected Identifier or MemberExpression, got ${expr.type} lval in AssignmentExpression`,
2178 - severity: ErrorSeverity.Todo,
2144 category: ErrorCategory.Todo,
2145 loc: expr.node.loc ?? null,
2146 suggestions: null,
@@ -2215,7 +2180,6 @@ function lowerExpression(
2180 if (!attribute.isJSXAttribute()) {
2181 builder.errors.push({
2182 reason: `(BuildHIR::lowerExpression) Handle ${attribute.type} attributes in JSXElement`,
2218 - severity: ErrorSeverity.Todo,
2183 category: ErrorCategory.Todo,
2184 loc: attribute.node.loc ?? null,
2185 suggestions: null,
@@ -2229,7 +2193,6 @@ function lowerExpression(
2193 if (propName.indexOf(':') !== -1) {
2194 builder.errors.push({
2195 reason: `(BuildHIR::lowerExpression) Unexpected colon in attribute name \`${propName}\``,
2232 - severity: ErrorSeverity.Todo,
2196 category: ErrorCategory.Todo,
2197 loc: namePath.node.loc ?? null,
2198 suggestions: null,
@@ -2260,7 +2223,6 @@ function lowerExpression(
2223 if (!valueExpr.isJSXExpressionContainer()) {
2224 builder.errors.push({
2225 reason: `(BuildHIR::lowerExpression) Handle ${valueExpr.type} attribute values in JSXElement`,
2263 - severity: ErrorSeverity.Todo,
2226 category: ErrorCategory.Todo,
2227 loc: valueExpr.node?.loc ?? null,
2228 suggestions: null,
@@ -2271,7 +2233,6 @@ function lowerExpression(
2233 if (!expression.isExpression()) {
2234 builder.errors.push({
2235 reason: `(BuildHIR::lowerExpression) Handle ${expression.type} expressions in JSXExpressionContainer within JSXElement`,
2274 - severity: ErrorSeverity.Todo,
2236 category: ErrorCategory.Todo,
2237 loc: valueExpr.node.loc ?? null,
2238 suggestions: null,
@@ -2329,8 +2290,7 @@ function lowerExpression(
2290 for (const [name, locations] of Object.entries(fbtLocations)) {
2291 if (locations.length > 1) {
2292 CompilerError.throwDiagnostic({
2332 - severity: ErrorSeverity.Todo,
2333 - category: ErrorCategory.FBT,
2293 + category: ErrorCategory.Todo,
2294 reason: 'Support duplicate fbt tags',
2295 description: `Support \`<${tagName}>\` tags with multiple \`<${tagName}:${name}>\` values`,
2296 details: locations.map(loc => {
@@ -2391,7 +2351,6 @@ function lowerExpression(
2351 builder.errors.push({
2352 reason:
2353 '(BuildHIR::lowerExpression) Handle tagged template with interpolations',
2394 - severity: ErrorSeverity.Todo,
2354 category: ErrorCategory.Todo,
2355 loc: exprPath.node.loc ?? null,
2356 suggestions: null,
@@ -2410,7 +2369,6 @@ function lowerExpression(
2369 builder.errors.push({
2370 reason:
2371 '(BuildHIR::lowerExpression) Handle tagged template where cooked value is different from raw value',
2413 - severity: ErrorSeverity.Todo,
2372 category: ErrorCategory.Todo,
2373 loc: exprPath.node.loc ?? null,
2374 suggestions: null,
@@ -2433,7 +2391,6 @@ function lowerExpression(
2391 if (subexprs.length !== quasis.length - 1) {
2392 builder.errors.push({
2393 reason: `Unexpected quasi and subexpression lengths in template literal`,
2436 - severity: ErrorSeverity.InvalidJS,
2394 category: ErrorCategory.Syntax,
2395 loc: exprPath.node.loc ?? null,
2396 suggestions: null,
@@ -2444,7 +2401,6 @@ function lowerExpression(
2401 if (subexprs.some(e => !e.isExpression())) {
2402 builder.errors.push({
2403 reason: `(BuildHIR::lowerAssignment) Handle TSType in TemplateLiteral.`,
2447 - severity: ErrorSeverity.Todo,
2404 category: ErrorCategory.Todo,
2405 loc: exprPath.node.loc ?? null,
2406 suggestions: null,
@@ -2487,7 +2443,6 @@ function lowerExpression(
2443 } else {
2444 builder.errors.push({
2445 reason: `Only object properties can be deleted`,
2490 - severity: ErrorSeverity.InvalidJS,
2446 category: ErrorCategory.Syntax,
2447 loc: expr.node.loc ?? null,
2448 suggestions: [
@@ -2503,7 +2458,6 @@ function lowerExpression(
2458 } else if (expr.node.operator === 'throw') {
2459 builder.errors.push({
2460 reason: `Throw expressions are not supported`,
2506 - severity: ErrorSeverity.InvalidJS,
2461 category: ErrorCategory.Syntax,
2462 loc: expr.node.loc ?? null,
2463 suggestions: [
@@ -2625,7 +2579,6 @@ function lowerExpression(
2579 if (!argument.isIdentifier()) {
2580 builder.errors.push({
2581 reason: `(BuildHIR::lowerExpression) Handle UpdateExpression with ${argument.type} argument`,
2628 - severity: ErrorSeverity.Todo,
2582 category: ErrorCategory.Todo,
2583 loc: exprPath.node.loc ?? null,
2584 suggestions: null,
@@ -2634,7 +2587,6 @@ function lowerExpression(
2587 } else if (builder.isContextIdentifier(argument)) {
2588 builder.errors.push({
2589 reason: `(BuildHIR::lowerExpression) Handle UpdateExpression to variables captured within lambdas.`,
2637 - severity: ErrorSeverity.Todo,
2590 category: ErrorCategory.Todo,
2591 loc: exprPath.node.loc ?? null,
2592 suggestions: null,
@@ -2655,7 +2607,6 @@ function lowerExpression(
2607 if (!builder.errors.hasErrors()) {
2608 builder.errors.push({
2609 reason: `(BuildHIR::lowerExpression) Found an invalid UpdateExpression without a previously reported error`,
2658 - severity: ErrorSeverity.Invariant,
2610 category: ErrorCategory.Invariant,
2611 loc: exprLoc,
2612 suggestions: null,
@@ -2665,7 +2616,6 @@ function lowerExpression(
2616 } else if (lvalue.kind === 'Global') {
2617 builder.errors.push({
2618 reason: `(BuildHIR::lowerExpression) Support UpdateExpression where argument is a global`,
2668 - severity: ErrorSeverity.Todo,
2619 category: ErrorCategory.Todo,
2620 loc: exprLoc,
2621 suggestions: null,
@@ -2721,7 +2671,6 @@ function lowerExpression(
2671
2672 builder.errors.push({
2673 reason: `(BuildHIR::lowerExpression) Handle MetaProperty expressions other than import.meta`,
2724 - severity: ErrorSeverity.Todo,
2674 category: ErrorCategory.Todo,
2675 loc: exprPath.node.loc ?? null,
2676 suggestions: null,
@@ -2731,7 +2680,6 @@ function lowerExpression(
2680 default: {
2681 builder.errors.push({
2682 reason: `(BuildHIR::lowerExpression) Handle ${exprPath.type} expressions`,
2734 - severity: ErrorSeverity.Todo,
2683 category: ErrorCategory.Todo,
2684 loc: exprPath.node.loc ?? null,
2685 suggestions: null,
@@ -3029,7 +2977,6 @@ function lowerReorderableExpression(
2977 if (!isReorderableExpression(builder, expr, true)) {
2978 builder.errors.push({
2979 reason: `(BuildHIR::node.lowerReorderableExpression) Expression type \`${expr.type}\` cannot be safely reordered`,
3032 - severity: ErrorSeverity.Todo,
2980 category: ErrorCategory.Todo,
2981 loc: expr.node.loc ?? null,
2982 suggestions: null,
@@ -3226,7 +3173,6 @@ function lowerArguments(
3173 } else {
3174 builder.errors.push({
3175 reason: `(BuildHIR::lowerExpression) Handle ${argPath.type} arguments in CallExpression`,
3229 - severity: ErrorSeverity.Todo,
3176 category: ErrorCategory.Todo,
3177 loc: argPath.node.loc ?? null,
3178 suggestions: null,
@@ -3262,7 +3208,6 @@ function lowerMemberExpression(
3208 } else {
3209 builder.errors.push({
3210 reason: `(BuildHIR::lowerMemberExpression) Handle ${propertyNode.type} property`,
3265 - severity: ErrorSeverity.Todo,
3211 category: ErrorCategory.Todo,
3212 loc: propertyNode.node.loc ?? null,
3213 suggestions: null,
@@ -3284,7 +3229,6 @@ function lowerMemberExpression(
3229 if (!propertyNode.isExpression()) {
3230 builder.errors.push({
3231 reason: `(BuildHIR::lowerMemberExpression) Expected Expression, got ${propertyNode.type} property`,
3287 - severity: ErrorSeverity.Todo,
3232 category: ErrorCategory.Todo,
3233 loc: propertyNode.node.loc ?? null,
3234 suggestions: null,
@@ -3344,7 +3288,6 @@ function lowerJsxElementName(
3288 builder.errors.push({
3289 reason: `Expected JSXNamespacedName to have no colons in the namespace or name`,
3290 description: `Got \`${namespace}\` : \`${name}\``,
3347 - severity: ErrorSeverity.InvalidJS,
3291 category: ErrorCategory.Syntax,
3292 loc: exprPath.node.loc ?? null,
3293 suggestions: null,
@@ -3359,7 +3302,6 @@ function lowerJsxElementName(
3302 } else {
3303 builder.errors.push({
3304 reason: `(BuildHIR::lowerJsxElementName) Handle ${exprPath.type} tags`,
3362 - severity: ErrorSeverity.Todo,
3305 category: ErrorCategory.Todo,
3306 loc: exprPath.node.loc ?? null,
3307 suggestions: null,
@@ -3458,7 +3400,6 @@ function lowerJsxElement(
3400 } else {
3401 builder.errors.push({
3402 reason: `(BuildHIR::lowerJsxElement) Unhandled JsxElement, got: ${exprPath.type}`,
3461 - severity: ErrorSeverity.Todo,
3403 category: ErrorCategory.Todo,
3404 loc: exprPath.node.loc ?? null,
3405 suggestions: null,
@@ -3646,7 +3587,6 @@ function lowerIdentifier(
3587 reason: `The 'eval' function is not supported`,
3588 description:
3589 'Eval is an anti-pattern in JavaScript, and the code executed cannot be evaluated by React Compiler',
3649 - severity: ErrorSeverity.UnsupportedJS,
3590 category: ErrorCategory.UnsupportedSyntax,
3591 loc: exprPath.node.loc ?? null,
3592 suggestions: null,
@@ -3703,7 +3643,6 @@ function lowerIdentifierForAssignment(
3643 // Else its an internal error bc we couldn't find the binding
3644 builder.errors.push({
3645 reason: `(BuildHIR::lowerAssignment) Could not find binding for declaration.`,
3706 - severity: ErrorSeverity.Invariant,
3646 category: ErrorCategory.Invariant,
3647 loc: path.node.loc ?? null,
3648 suggestions: null,
@@ -3716,7 +3655,6 @@ function lowerIdentifierForAssignment(
3655 ) {
3656 builder.errors.push({
3657 reason: `Cannot reassign a \`const\` variable`,
3719 - severity: ErrorSeverity.InvalidJS,
3658 category: ErrorCategory.Syntax,
3659 loc: path.node.loc ?? null,
3660 description:
@@ -3774,7 +3712,6 @@ function lowerAssignment(
3712 if (kind === InstructionKind.Const && !isHoistedIdentifier) {
3713 builder.errors.push({
3714 reason: `Expected \`const\` declaration not to be reassigned`,
3777 - severity: ErrorSeverity.InvalidJS,
3715 category: ErrorCategory.Syntax,
3716 loc: lvalue.node.loc ?? null,
3717 suggestions: null,
@@ -3789,7 +3726,6 @@ function lowerAssignment(
3726 ) {
3727 builder.errors.push({
3728 reason: `Unexpected context variable kind`,
3792 - severity: ErrorSeverity.InvalidJS,
3729 category: ErrorCategory.Syntax,
3730 loc: lvalue.node.loc ?? null,
3731 suggestions: null,
@@ -3861,7 +3797,6 @@ function lowerAssignment(
3797 } else {
3798 builder.errors.push({
3799 reason: `(BuildHIR::lowerAssignment) Handle ${property.type} properties in MemberExpression`,
3864 - severity: ErrorSeverity.Todo,
3800 category: ErrorCategory.Todo,
3801 loc: property.node.loc ?? null,
3802 suggestions: null,
@@ -3874,7 +3809,6 @@ function lowerAssignment(
3809 builder.errors.push({
3810 reason:
3811 '(BuildHIR::lowerAssignment) Expected private name to appear as a non-computed property',
3877 - severity: ErrorSeverity.Todo,
3812 category: ErrorCategory.Todo,
3813 loc: property.node.loc ?? null,
3814 suggestions: null,
@@ -3940,7 +3874,6 @@ function lowerAssignment(
3874 continue;
3875 } else if (identifier.kind === 'Global') {
3876 builder.errors.push({
3943 - severity: ErrorSeverity.Todo,
3877 category: ErrorCategory.Todo,
3878 reason:
3879 'Expected reassignment of globals to enable forceTemporaries',
@@ -3980,7 +3913,6 @@ function lowerAssignment(
3913 continue;
3914 } else if (identifier.kind === 'Global') {
3915 builder.errors.push({
3983 - severity: ErrorSeverity.Todo,
3916 category: ErrorCategory.Todo,
3917 reason:
3918 'Expected reassignment of globals to enable forceTemporaries',
@@ -4054,7 +3986,6 @@ function lowerAssignment(
3986 if (!argument.isIdentifier()) {
3987 builder.errors.push({
3988 reason: `(BuildHIR::lowerAssignment) Handle ${argument.node.type} rest element in ObjectPattern`,
4057 - severity: ErrorSeverity.Todo,
3989 category: ErrorCategory.Todo,
3990 loc: argument.node.loc ?? null,
3991 suggestions: null,
@@ -4086,7 +4017,6 @@ function lowerAssignment(
4017 continue;
4018 } else if (identifier.kind === 'Global') {
4019 builder.errors.push({
4089 - severity: ErrorSeverity.Todo,
4020 category: ErrorCategory.Todo,
4021 reason:
4022 'Expected reassignment of globals to enable forceTemporaries',
@@ -4104,7 +4034,6 @@ function lowerAssignment(
4034 if (!property.isObjectProperty()) {
4035 builder.errors.push({
4036 reason: `(BuildHIR::lowerAssignment) Handle ${property.type} properties in ObjectPattern`,
4107 - severity: ErrorSeverity.Todo,
4037 category: ErrorCategory.Todo,
4038 loc: property.node.loc ?? null,
4039 suggestions: null,
@@ -4114,7 +4043,6 @@ function lowerAssignment(
4043 if (property.node.computed) {
4044 builder.errors.push({
4045 reason: `(BuildHIR::lowerAssignment) Handle computed properties in ObjectPattern`,
4117 - severity: ErrorSeverity.Todo,
4046 category: ErrorCategory.Todo,
4047 loc: property.node.loc ?? null,
4048 suggestions: null,
@@ -4129,7 +4057,6 @@ function lowerAssignment(
4057 if (!element.isLVal()) {
4058 builder.errors.push({
4059 reason: `(BuildHIR::lowerAssignment) Expected object property value to be an LVal, got: ${element.type}`,
4132 - severity: ErrorSeverity.Todo,
4060 category: ErrorCategory.Todo,
4061 loc: element.node.loc ?? null,
4062 suggestions: null,
@@ -4152,7 +4079,6 @@ function lowerAssignment(
4079 continue;
4080 } else if (identifier.kind === 'Global') {
4081 builder.errors.push({
4155 - severity: ErrorSeverity.Todo,
4082 category: ErrorCategory.Todo,
4083 reason:
4084 'Expected reassignment of globals to enable forceTemporaries',
@@ -4302,7 +4228,6 @@ function lowerAssignment(
4228 default: {
4229 builder.errors.push({
4230 reason: `(BuildHIR::lowerAssignment) Handle ${lvaluePath.type} assignments`,
4305 - severity: ErrorSeverity.Todo,
4231 category: ErrorCategory.Todo,
4232 loc: lvaluePath.node.loc ?? null,
4233 suggestions: null,
compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts
+2 -4
@@ -7,7 +7,7 @@
7
8 import {Binding, NodePath} from '@babel/traverse';
9 import * as t from '@babel/types';
10 -import {CompilerError, ErrorCategory, ErrorSeverity} from '../CompilerError';
10 +import {CompilerError, ErrorCategory} from '../CompilerError';
11 import {Environment} from './Environment';
12 import {
13 BasicBlock,
@@ -309,8 +309,7 @@ export default class HIRBuilder {
309 resolveBinding(node: t.Identifier): Identifier {
310 if (node.name === 'fbt') {
311 CompilerError.throwDiagnostic({
312 - severity: ErrorSeverity.Todo,
313 - category: ErrorCategory.FBT,
312 + category: ErrorCategory.Todo,
313 reason: 'Support local variables named `fbt`',
314 description:
315 'Local variables named `fbt` may conflict with the fbt plugin and are not yet supported',
@@ -325,7 +324,6 @@ export default class HIRBuilder {
324 }
325 if (node.name === 'this') {
326 CompilerError.throwDiagnostic({
328 - severity: ErrorSeverity.UnsupportedJS,
327 category: ErrorCategory.UnsupportedSyntax,
328 reason: '`this` is not supported syntax',
329 description:
compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts
+1 -12
@@ -5,12 +5,7 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {
9 - CompilerDiagnostic,
10 - CompilerError,
11 - ErrorSeverity,
12 - SourceLocation,
13 -} from '..';
8 +import {CompilerDiagnostic, CompilerError, SourceLocation} from '..';
9 import {ErrorCategory} from '../CompilerError';
10 import {
11 CallExpression,
@@ -302,7 +297,6 @@ function extractManualMemoizationArgs(
297 errors.pushDiagnostic(
298 CompilerDiagnostic.create({
299 category: ErrorCategory.UseMemo,
305 - severity: ErrorSeverity.InvalidReact,
300 reason: `Expected a callback function to be passed to ${kind}`,
301 description: `Expected a callback function to be passed to ${kind}`,
302 suggestions: null,
@@ -318,7 +312,6 @@ function extractManualMemoizationArgs(
312 errors.pushDiagnostic(
313 CompilerDiagnostic.create({
314 category: ErrorCategory.UseMemo,
321 - severity: ErrorSeverity.InvalidReact,
315 reason: `Unexpected spread argument to ${kind}`,
316 description: `Unexpected spread argument to ${kind}`,
317 suggestions: null,
@@ -339,7 +332,6 @@ function extractManualMemoizationArgs(
332 errors.pushDiagnostic(
333 CompilerDiagnostic.create({
334 category: ErrorCategory.UseMemo,
342 - severity: ErrorSeverity.InvalidReact,
335 reason: `Expected the dependency list for ${kind} to be an array literal`,
336 description: `Expected the dependency list for ${kind} to be an array literal`,
337 suggestions: null,
@@ -358,7 +350,6 @@ function extractManualMemoizationArgs(
350 errors.pushDiagnostic(
351 CompilerDiagnostic.create({
352 category: ErrorCategory.UseMemo,
361 - severity: ErrorSeverity.InvalidReact,
353 reason: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
354 description: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
355 suggestions: null,
@@ -463,7 +454,6 @@ export function dropManualMemoization(
454 if (!hasNonVoidReturn(funcToCheck.loweredFunc.func)) {
455 errors.pushDiagnostic(
456 CompilerDiagnostic.create({
466 - severity: ErrorSeverity.InvalidReact,
457 category: ErrorCategory.UseMemo,
458 reason: 'useMemo() callbacks must return a value',
459 description: `This ${
@@ -505,7 +495,6 @@ export function dropManualMemoization(
495 errors.pushDiagnostic(
496 CompilerDiagnostic.create({
497 category: ErrorCategory.UseMemo,
508 - severity: ErrorSeverity.InvalidReact,
498 reason: `Expected the first argument to be an inline function expression`,
499 description: `Expected the first argument to be an inline function expression`,
500 suggestions: [],
compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts
-7
@@ -9,7 +9,6 @@ import {
9 CompilerDiagnostic,
10 CompilerError,
11 Effect,
12 - ErrorSeverity,
12 SourceLocation,
13 ValueKind,
14 } from '..';
@@ -455,7 +454,6 @@ function applySignature(
454 : 'value';
455 const diagnostic = CompilerDiagnostic.create({
456 category: ErrorCategory.Immutability,
458 - severity: ErrorSeverity.InvalidReact,
457 reason: 'This value cannot be modified',
458 description: `${reason}.`,
459 }).withDetail({
@@ -1040,7 +1038,6 @@ function applyEffect(
1038 );
1039 const diagnostic = CompilerDiagnostic.create({
1040 category: ErrorCategory.Immutability,
1043 - severity: ErrorSeverity.InvalidReact,
1041 reason: 'Cannot access variable before it is declared',
1042 description: `${variable ?? 'This variable'} is accessed before it is declared, which prevents the earlier access from updating when this value changes over time.`,
1043 });
@@ -1080,7 +1077,6 @@ function applyEffect(
1077 : 'value';
1078 const diagnostic = CompilerDiagnostic.create({
1079 category: ErrorCategory.Immutability,
1083 - severity: ErrorSeverity.InvalidReact,
1080 reason: 'This value cannot be modified',
1081 description: `${reason}.`,
1082 }).withDetail({
@@ -2056,7 +2052,6 @@ function computeSignatureForInstruction(
2052 place: value.value,
2053 error: CompilerDiagnostic.create({
2054 category: ErrorCategory.Globals,
2059 - severity: ErrorSeverity.InvalidReact,
2055 reason:
2056 'Cannot reassign variables declared outside of the component/hook',
2057 description: `Variable ${variable} is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render)`,
@@ -2156,7 +2151,6 @@ function computeEffectsForLegacySignature(
2151 place: receiver,
2152 error: CompilerDiagnostic.create({
2153 category: ErrorCategory.Purity,
2159 - severity: ErrorSeverity.InvalidReact,
2154 reason: 'Cannot call impure function during render',
2155 description:
2156 (signature.canonicalName != null
@@ -2175,7 +2169,6 @@ function computeEffectsForLegacySignature(
2169 errors.pushDiagnostic(
2170 CompilerDiagnostic.create({
2171 category: ErrorCategory.IncompatibleLibrary,
2178 - severity: ErrorSeverity.IncompatibleLibrary,
2172 reason: 'Use of incompatible library',
2173 description: [
2174 'This API returns functions which cannot be memoized without leading to stale UI. ' +
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts
+1 -3
@@ -13,7 +13,7 @@ import {
13 pruneUnusedLabels,
14 renameVariables,
15 } from '.';
16 -import {CompilerError, ErrorCategory, ErrorSeverity} from '../CompilerError';
16 +import {CompilerError, ErrorCategory} from '../CompilerError';
17 import {Environment, ExternalFunction} from '../HIR';
18 import {
19 ArrayPattern,
@@ -2184,7 +2184,6 @@ function codegenInstructionValue(
2184 reason: `(CodegenReactiveFunction::codegenInstructionValue) Cannot declare variables in a value block, tried to declare '${
2185 (declarator.id as t.Identifier).name
2186 }'`,
2187 - severity: ErrorSeverity.Todo,
2187 category: ErrorCategory.Todo,
2188 loc: declarator.loc ?? null,
2189 suggestions: null,
@@ -2193,7 +2192,6 @@ function codegenInstructionValue(
2192 } else {
2193 cx.errors.push({
2194 reason: `(CodegenReactiveFunction::codegenInstructionValue) Handle conversion of ${stmt.type} to expression`,
2196 - severity: ErrorSeverity.Todo,
2195 category: ErrorCategory.Todo,
2196 loc: stmt.loc ?? null,
2197 suggestions: null,
compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts
+1 -14
@@ -5,12 +5,7 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {
9 - CompilerError,
10 - CompilerErrorDetailOptions,
11 - ErrorSeverity,
12 - SourceLocation,
13 -} from '..';
8 +import {CompilerError, CompilerErrorDetailOptions, SourceLocation} from '..';
9 import {
10 ArrayExpression,
11 CallExpression,
@@ -133,7 +128,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void {
128 context.pushError({
129 loc: value.loc,
130 description: null,
136 - severity: ErrorSeverity.Invariant,
131 category: ErrorCategory.Invariant,
132 reason: '[InsertFire] No LoadGlobal found for useEffect call',
133 suggestions: null,
@@ -180,7 +174,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void {
174 loc: value.args[1].loc,
175 description:
176 'You must use an array literal for an effect dependency array when that effect uses `fire()`',
183 - severity: ErrorSeverity.Invariant,
177 category: ErrorCategory.Fire,
178 reason: CANNOT_COMPILE_FIRE,
179 suggestions: null,
@@ -191,7 +184,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void {
184 loc: value.args[1].place.loc,
185 description:
186 'You must use an array literal for an effect dependency array when that effect uses `fire()`',
194 - severity: ErrorSeverity.Invariant,
187 category: ErrorCategory.Fire,
188 reason: CANNOT_COMPILE_FIRE,
189 suggestions: null,
@@ -226,7 +218,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void {
218 context.pushError({
219 loc: value.loc,
220 description: null,
229 - severity: ErrorSeverity.Invariant,
221 category: ErrorCategory.Invariant,
222 reason:
223 '[InsertFire] No loadLocal found for fire call argument',
@@ -250,7 +241,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void {
241 loc: value.loc,
242 description:
243 '`fire()` can only receive a function call such as `fire(fn(a,b)). Method calls and other expressions are not allowed',
253 - severity: ErrorSeverity.InvalidReact,
244 category: ErrorCategory.Fire,
245 reason: CANNOT_COMPILE_FIRE,
246 suggestions: null,
@@ -269,7 +259,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void {
259 context.pushError({
260 loc: value.loc,
261 description,
272 - severity: ErrorSeverity.InvalidReact,
262 category: ErrorCategory.Fire,
263 reason: CANNOT_COMPILE_FIRE,
264 suggestions: null,
@@ -401,7 +390,6 @@ function ensureNoRemainingCalleeCaptures(
390 description: `All uses of ${calleeName} must be either used with a fire() call in \
391 this effect or not used with a fire() call at all. ${calleeName} was used with fire() on line \
392 ${printSourceLocationLine(calleeInfo.fireLoc)} in this effect`,
404 - severity: ErrorSeverity.InvalidReact,
393 category: ErrorCategory.Fire,
394 reason: CANNOT_COMPILE_FIRE,
395 suggestions: null,
@@ -420,7 +408,6 @@ function ensureNoMoreFireUses(fn: HIRFunction, context: Context): void {
408 loc: place.identifier.loc,
409 description: 'Cannot use `fire` outside of a useEffect function',
410 category: ErrorCategory.Fire,
423 - severity: ErrorSeverity.Invariant,
411 reason: CANNOT_COMPILE_FIRE,
412 suggestions: null,
413 });
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateHooksUsage.ts
-5
@@ -10,7 +10,6 @@ import {
10 CompilerError,
11 CompilerErrorDetail,
12 ErrorCategory,
13 - ErrorSeverity,
13 } from '../CompilerError';
14 import {computeUnconditionalBlocks} from '../HIR/ComputeUnconditionalBlocks';
15 import {isHookName} from '../HIR/Environment';
@@ -129,7 +128,6 @@ export function validateHooksUsage(
128 description: null,
129 reason,
130 loc: place.loc,
132 - severity: ErrorSeverity.InvalidReact,
131 suggestions: null,
132 }),
133 );
@@ -147,7 +145,6 @@ export function validateHooksUsage(
145 reason:
146 'Hooks may not be referenced as normal values, they must be called. See https://react.dev/reference/rules/react-calls-components-and-hooks#never-pass-around-hooks-as-regular-values',
147 loc: place.loc,
150 - severity: ErrorSeverity.InvalidReact,
148 suggestions: null,
149 }),
150 );
@@ -165,7 +162,6 @@ export function validateHooksUsage(
162 reason:
163 'Hooks must be the same function on every render, but this value may change over time to a different function. See https://react.dev/reference/rules/react-calls-components-and-hooks#dont-dynamically-use-hooks',
164 loc: place.loc,
168 - severity: ErrorSeverity.InvalidReact,
165 suggestions: null,
166 }),
167 );
@@ -453,7 +449,6 @@ function visitFunctionExpression(errors: CompilerError, fn: HIRFunction): void {
449 errors.pushErrorDetail(
450 new CompilerErrorDetail({
451 category: ErrorCategory.Hooks,
456 - severity: ErrorSeverity.InvalidReact,
452 reason:
453 'Hooks must be called at the top level in the body of a function component or custom hook, and may not be called within function expressions. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning)',
454 loc: callee.loc,
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateLocalsNotReassignedAfterRender.ts
+1 -3
@@ -5,7 +5,7 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {CompilerDiagnostic, CompilerError, Effect, ErrorSeverity} from '..';
8 +import {CompilerDiagnostic, CompilerError, Effect} from '..';
9 import {ErrorCategory} from '../CompilerError';
10 import {HIRFunction, IdentifierId, Place} from '../HIR';
11 import {
@@ -38,7 +38,6 @@ export function validateLocalsNotReassignedAfterRender(fn: HIRFunction): void {
38 errors.pushDiagnostic(
39 CompilerDiagnostic.create({
40 category: ErrorCategory.Immutability,
41 - severity: ErrorSeverity.InvalidReact,
41 reason: 'Cannot reassign variable after render completes',
42 description: `Reassigning ${variable} after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead.`,
43 }).withDetail({
@@ -94,7 +93,6 @@ function getContextReassignment(
93 errors.pushDiagnostic(
94 CompilerDiagnostic.create({
95 category: ErrorCategory.Immutability,
97 - severity: ErrorSeverity.InvalidReact,
96 reason: 'Cannot reassign variable in async function',
97 description:
98 'Reassigning a variable in an async function can cause inconsistent behavior on subsequent renders. Consider using state instead',
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateMemoizedEffectDependencies.ts
+1 -2
@@ -5,7 +5,7 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {CompilerError, ErrorSeverity} from '..';
8 +import {CompilerError} from '..';
9 import {ErrorCategory} from '../CompilerError';
10 import {
11 Identifier,
@@ -113,7 +113,6 @@ class Visitor extends ReactiveFunctionVisitor<CompilerError> {
113 reason:
114 'React Compiler has skipped optimizing this component because the effect dependencies could not be memoized. Unmemoized effect dependencies can trigger an infinite loop or other unexpected behavior',
115 description: null,
116 - severity: ErrorSeverity.CannotPreserveMemoization,
116 loc: typeof instruction.loc !== 'symbol' ? instruction.loc : null,
117 suggestions: null,
118 });
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoCapitalizedCalls.ts
+1 -2
@@ -5,7 +5,7 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {CompilerError, EnvironmentConfig, ErrorSeverity} from '..';
8 +import {CompilerError, EnvironmentConfig} from '..';
9 import {ErrorCategory} from '../CompilerError';
10 import {HIRFunction, IdentifierId} from '../HIR';
11 import {DEFAULT_GLOBALS} from '../HIR/Globals';
@@ -82,7 +82,6 @@ export function validateNoCapitalizedCalls(
82 if (propertyName != null) {
83 errors.push({
84 category: ErrorCategory.CapitalizedCalls,
85 - severity: ErrorSeverity.InvalidReact,
85 reason,
86 description: `${propertyName} may be a component.`,
87 loc: value.loc,
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects.ts
+1 -2
@@ -5,7 +5,7 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {CompilerError, ErrorSeverity, SourceLocation} from '..';
8 +import {CompilerError, SourceLocation} from '..';
9 import {ErrorCategory} from '../CompilerError';
10 import {
11 ArrayExpression,
@@ -224,7 +224,6 @@ function validateEffect(
224 reason:
225 'Values derived from props and state should be calculated during render, not in an effect. (https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state)',
226 description: null,
227 - severity: ErrorSeverity.InvalidReact,
227 loc,
228 suggestions: null,
229 });
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoFreezingKnownMutableFunctions.ts
+1 -2
@@ -5,7 +5,7 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {CompilerDiagnostic, CompilerError, Effect, ErrorSeverity} from '..';
8 +import {CompilerDiagnostic, CompilerError, Effect} from '..';
9 import {ErrorCategory} from '../CompilerError';
10 import {
11 HIRFunction,
@@ -66,7 +66,6 @@ export function validateNoFreezingKnownMutableFunctions(
66 errors.pushDiagnostic(
67 CompilerDiagnostic.create({
68 category: ErrorCategory.Immutability,
69 - severity: ErrorSeverity.InvalidReact,
69 reason: 'Cannot modify local variables after render completes',
70 description: `This argument is a function which may reassign or mutate ${variable} after render, which can cause inconsistent behavior on subsequent renders. Consider using state instead.`,
71 })
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoImpureFunctionsInRender.ts
+1 -2
@@ -5,7 +5,7 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {CompilerDiagnostic, CompilerError, ErrorSeverity} from '..';
8 +import {CompilerDiagnostic, CompilerError} from '..';
9 import {ErrorCategory} from '../CompilerError';
10 import {HIRFunction} from '../HIR';
11 import {getFunctionCallSignature} from '../Inference/InferMutationAliasingEffects';
@@ -44,7 +44,6 @@ export function validateNoImpureFunctionsInRender(
44 ? `\`${signature.canonicalName}\` is an impure function. `
45 : '') +
46 'Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent)',
47 - severity: ErrorSeverity.InvalidReact,
47 suggestions: null,
48 }).withDetail({
49 kind: 'error',
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoJSXInTryStatement.ts
+1 -2
@@ -5,7 +5,7 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {CompilerDiagnostic, CompilerError, ErrorSeverity} from '..';
8 +import {CompilerDiagnostic, CompilerError} from '..';
9 import {ErrorCategory} from '../CompilerError';
10 import {BlockId, HIRFunction} from '../HIR';
11 import {Result} from '../Utils/Result';
@@ -38,7 +38,6 @@ export function validateNoJSXInTryStatement(
38 errors.pushDiagnostic(
39 CompilerDiagnostic.create({
40 category: ErrorCategory.ErrorBoundaries,
41 - severity: ErrorSeverity.InvalidReact,
41 reason: 'Avoid constructing JSX within try/catch',
42 description: `React does not immediately render components when JSX is rendered, so any errors from this component will not be caught by the try/catch. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)`,
43 }).withDetail({
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts
-7
@@ -9,7 +9,6 @@ import {
9 CompilerDiagnostic,
10 CompilerError,
11 ErrorCategory,
12 - ErrorSeverity,
12 } from '../CompilerError';
13 import {
14 BlockId,
@@ -470,7 +469,6 @@ function validateNoRefAccessInRenderImpl(
469 errors.pushDiagnostic(
470 CompilerDiagnostic.create({
471 category: ErrorCategory.Refs,
473 - severity: ErrorSeverity.InvalidReact,
472 reason: 'Cannot access refs during render',
473 description: ERROR_DESCRIPTION,
474 }).withDetail({
@@ -734,7 +732,6 @@ function guardCheck(errors: CompilerError, operand: Place, env: Env): void {
732 errors.pushDiagnostic(
733 CompilerDiagnostic.create({
734 category: ErrorCategory.Refs,
737 - severity: ErrorSeverity.InvalidReact,
735 reason: 'Cannot access refs during render',
736 description: ERROR_DESCRIPTION,
737 }).withDetail({
@@ -759,7 +756,6 @@ function validateNoRefValueAccess(
756 errors.pushDiagnostic(
757 CompilerDiagnostic.create({
758 category: ErrorCategory.Refs,
762 - severity: ErrorSeverity.InvalidReact,
759 reason: 'Cannot access refs during render',
760 description: ERROR_DESCRIPTION,
761 }).withDetail({
@@ -786,7 +782,6 @@ function validateNoRefPassedToFunction(
782 errors.pushDiagnostic(
783 CompilerDiagnostic.create({
784 category: ErrorCategory.Refs,
789 - severity: ErrorSeverity.InvalidReact,
785 reason: 'Cannot access refs during render',
786 description: ERROR_DESCRIPTION,
787 }).withDetail({
@@ -809,7 +804,6 @@ function validateNoRefUpdate(
804 errors.pushDiagnostic(
805 CompilerDiagnostic.create({
806 category: ErrorCategory.Refs,
812 - severity: ErrorSeverity.InvalidReact,
807 reason: 'Cannot access refs during render',
808 description: ERROR_DESCRIPTION,
809 }).withDetail({
@@ -831,7 +825,6 @@ function validateNoDirectRefValueAccess(
825 errors.pushDiagnostic(
826 CompilerDiagnostic.create({
827 category: ErrorCategory.Refs,
834 - severity: ErrorSeverity.InvalidReact,
828 reason: 'Cannot access refs during render',
829 description: ERROR_DESCRIPTION,
830 }).withDetail({
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInEffects.ts
-2
@@ -9,7 +9,6 @@ import {
9 CompilerDiagnostic,
10 CompilerError,
11 ErrorCategory,
12 - ErrorSeverity,
12 } from '../CompilerError';
13 import {
14 HIRFunction,
@@ -107,7 +106,6 @@ export function validateNoSetStateInEffects(
106 '* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\n' +
107 'Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. ' +
108 '(https://react.dev/learn/you-might-not-need-an-effect)',
110 - severity: ErrorSeverity.InvalidReact,
109 suggestions: null,
110 }).withDetail({
111 kind: 'error',
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInRender.ts
-3
@@ -9,7 +9,6 @@ import {
9 CompilerDiagnostic,
10 CompilerError,
11 ErrorCategory,
12 - ErrorSeverity,
12 } from '../CompilerError';
13 import {HIRFunction, IdentifierId, isSetStateType} from '../HIR';
14 import {computeUnconditionalBlocks} from '../HIR/ComputeUnconditionalBlocks';
@@ -134,7 +133,6 @@ function validateNoSetStateInRenderImpl(
133 'Calling setState from useMemo may trigger an infinite loop',
134 description:
135 'Each time the memo callback is evaluated it will change state. This can cause a memoization dependency to change, running the memo function again and causing an infinite loop. Instead of setting state in useMemo(), prefer deriving the value during render. (https://react.dev/reference/react/useState)',
137 - severity: ErrorSeverity.InvalidReact,
136 suggestions: null,
137 }).withDetail({
138 kind: 'error',
@@ -150,7 +148,6 @@ function validateNoSetStateInRenderImpl(
148 'Calling setState during render may trigger an infinite loop',
149 description:
150 'Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)',
153 - severity: ErrorSeverity.InvalidReact,
151 suggestions: null,
152 }).withDetail({
153 kind: 'error',
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts
-4
@@ -9,7 +9,6 @@ import {
9 CompilerDiagnostic,
10 CompilerError,
11 ErrorCategory,
12 - ErrorSeverity,
12 } from '../CompilerError';
13 import {
14 DeclarationId,
@@ -283,7 +282,6 @@ function validateInferredDep(
282 errorState.pushDiagnostic(
283 CompilerDiagnostic.create({
284 category: ErrorCategory.PreserveManualMemo,
286 - severity: ErrorSeverity.CannotPreserveMemoization,
285 reason: 'Existing memoization could not be preserved',
286 description: [
287 'React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. ',
@@ -537,7 +535,6 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
535 state.errors.pushDiagnostic(
536 CompilerDiagnostic.create({
537 category: ErrorCategory.PreserveManualMemo,
540 - severity: ErrorSeverity.CannotPreserveMemoization,
538 reason: 'Existing memoization could not be preserved',
539 description: [
540 'React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. ',
@@ -585,7 +582,6 @@ class Visitor extends ReactiveFunctionVisitor<VisitorState> {
582 state.errors.pushDiagnostic(
583 CompilerDiagnostic.create({
584 category: ErrorCategory.PreserveManualMemo,
588 - severity: ErrorSeverity.CannotPreserveMemoization,
585 reason: 'Existing memoization could not be preserved',
586 description: [
587 'React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output. ',
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateStaticComponents.ts
-2
@@ -9,7 +9,6 @@ import {
9 CompilerDiagnostic,
10 CompilerError,
11 ErrorCategory,
12 - ErrorSeverity,
12 } from '../CompilerError';
13 import {HIRFunction, IdentifierId, SourceLocation} from '../HIR';
14 import {Result} from '../Utils/Result';
@@ -67,7 +66,6 @@ export function validateStaticComponents(
66 error.pushDiagnostic(
67 CompilerDiagnostic.create({
68 category: ErrorCategory.StaticComponents,
70 - severity: ErrorSeverity.InvalidReact,
69 reason: 'Cannot create components during render',
70 description: `Components created during render will reset their state each time they are created. Declare components outside of render. `,
71 })
compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateUseMemo.ts
-3
@@ -9,7 +9,6 @@ import {
9 CompilerDiagnostic,
10 CompilerError,
11 ErrorCategory,
12 - ErrorSeverity,
12 } from '../CompilerError';
13 import {FunctionExpression, HIRFunction, IdentifierId} from '../HIR';
14 import {Result} from '../Utils/Result';
@@ -76,7 +75,6 @@ export function validateUseMemo(fn: HIRFunction): Result<void, CompilerError> {
75 errors.pushDiagnostic(
76 CompilerDiagnostic.create({
77 category: ErrorCategory.UseMemo,
79 - severity: ErrorSeverity.InvalidReact,
78 reason: 'useMemo() callbacks may not accept parameters',
79 description:
80 'useMemo() callbacks are called by React to cache calculations across re-renders. They should not take parameters. Instead, directly reference the props, state, or local variables needed for the computation.',
@@ -93,7 +91,6 @@ export function validateUseMemo(fn: HIRFunction): Result<void, CompilerError> {
91 errors.pushDiagnostic(
92 CompilerDiagnostic.create({
93 category: ErrorCategory.UseMemo,
96 - severity: ErrorSeverity.InvalidReact,
94 reason:
95 'useMemo() callbacks may not be async or generator functions',
96 description:
compiler/packages/babel-plugin-react-compiler/src/__tests__/Logger-test.ts
+1 -1
@@ -56,7 +56,7 @@ it('logs failed compilation', () => {
56 expect(event.kind).toEqual('CompileError');
57 invariant(event.kind === 'CompileError', 'typescript be smarter');
58
59 - expect(event.detail.severity).toEqual('InvalidReact');
59 + expect(event.detail.severity).toEqual('Error');
60 //@ts-ignore
61 const {start, end, identifierName} =
62 event.detail.primaryLocation() as t.SourceLocation;
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.expect.md
+1 -1
@@ -24,7 +24,7 @@ function useThing(fn) {
24 ```
25 Found 1 error:
26
27 -Error: `this` is not supported syntax
27 +Compilation Skipped: `this` is not supported syntax
28
29 React Compiler does not support compiling functions that use `this`
30
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-eval-unsupported.expect.md
+1 -1
@@ -15,7 +15,7 @@ function Component(props) {
15 ```
16 Found 1 error:
17
18 -Error: The 'eval' function is not supported
18 +Compilation Skipped: The 'eval' function is not supported
19
20 Eval is an anti-pattern in JavaScript, and the code executed cannot be evaluated by React Compiler.
21
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md
+1 -1
@@ -92,7 +92,7 @@ error.todo-kitchensink.ts:3:2
92 5 | class Bar {
93 6 | #secretSauce = 42;
94
95 -Error: Inline `class` declarations are not supported
95 +Compilation Skipped: Inline `class` declarations are not supported
96
97 Move class declarations outside of components/hooks.
98
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-bailout-nopanic.expect.md
+1 -1
@@ -58,7 +58,7 @@ export const FIXTURE_ENTRYPOINT = {
58 ## Logs
59
60 ```
61 -{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":206},"end":{"line":16,"column":1,"index":433},"filename":"dynamic-gating-bailout-nopanic.ts"},"detail":{"options":{"category":"PreserveManualMemo","severity":"CannotPreserveMemoization","reason":"Existing memoization could not be preserved","description":"React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `value`, but the source dependencies were []. Inferred dependency not present in source.","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":9,"column":31,"index":288},"end":{"line":9,"column":52,"index":309},"filename":"dynamic-gating-bailout-nopanic.ts"},"message":"Could not preserve existing manual memoization"}]}}}
61 +{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":206},"end":{"line":16,"column":1,"index":433},"filename":"dynamic-gating-bailout-nopanic.ts"},"detail":{"options":{"category":"PreserveManualMemo","reason":"Existing memoization could not be preserved","description":"React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. The inferred dependency was `value`, but the source dependencies were []. Inferred dependency not present in source.","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":9,"column":31,"index":288},"end":{"line":9,"column":52,"index":309},"filename":"dynamic-gating-bailout-nopanic.ts"},"message":"Could not preserve existing manual memoization"}]}}}
62 ```
63
64 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-invalid-multiple.expect.md
+1 -1
@@ -38,7 +38,7 @@ export const FIXTURE_ENTRYPOINT = {
38 ## Logs
39
40 ```
41 -{"kind":"CompileError","fnLoc":{"start":{"line":3,"column":0,"index":86},"end":{"line":7,"column":1,"index":190},"filename":"dynamic-gating-invalid-multiple.ts"},"detail":{"options":{"category":"Gating","reason":"Multiple dynamic gating directives found","description":"Expected a single directive but found [use memo if(getTrue), use memo if(getFalse)]","severity":"InvalidReact","suggestions":null,"loc":{"start":{"line":4,"column":2,"index":105},"end":{"line":4,"column":25,"index":128},"filename":"dynamic-gating-invalid-multiple.ts"}}}}
41 +{"kind":"CompileError","fnLoc":{"start":{"line":3,"column":0,"index":86},"end":{"line":7,"column":1,"index":190},"filename":"dynamic-gating-invalid-multiple.ts"},"detail":{"options":{"category":"Gating","reason":"Multiple dynamic gating directives found","description":"Expected a single directive but found [use memo if(getTrue), use memo if(getFalse)]","suggestions":null,"loc":{"start":{"line":4,"column":2,"index":105},"end":{"line":4,"column":25,"index":128},"filename":"dynamic-gating-invalid-multiple.ts"}}}}
42 ```
43
44 ### Eval output
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-optional-chain.expect.md
+1 -1
@@ -48,7 +48,7 @@ export const FIXTURE_ENTRYPOINT = {
48 ## Logs
49
50 ```
51 -{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":149},"end":{"line":12,"column":1,"index":404},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"options":{"category":"Immutability","severity":"InvalidReact","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect().","details":[{"kind":"error","loc":{"start":{"line":10,"column":2,"index":365},"end":{"line":10,"column":5,"index":368},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}}
51 +{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":149},"end":{"line":12,"column":1,"index":404},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect().","details":[{"kind":"error","loc":{"start":{"line":10,"column":2,"index":365},"end":{"line":10,"column":5,"index":368},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}}
52 {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":9,"column":2,"index":314},"end":{"line":9,"column":49,"index":361},"filename":"mutate-after-useeffect-optional-chain.ts"},"decorations":[{"start":{"line":9,"column":24,"index":336},"end":{"line":9,"column":27,"index":339},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}]}
53 {"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":149},"end":{"line":12,"column":1,"index":404},"filename":"mutate-after-useeffect-optional-chain.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
54 ```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-ref-access.expect.md
+1 -1
@@ -47,7 +47,7 @@ export const FIXTURE_ENTRYPOINT = {
47 ## Logs
48
49 ```
50 -{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":158},"end":{"line":11,"column":1,"index":331},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"options":{"category":"Refs","severity":"InvalidReact","reason":"Cannot access refs during render","description":"React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":289},"end":{"line":9,"column":16,"index":303},"filename":"mutate-after-useeffect-ref-access.ts"},"message":"Cannot update ref during render"}]}}}
50 +{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":158},"end":{"line":11,"column":1,"index":331},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"options":{"category":"Refs","reason":"Cannot access refs during render","description":"React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":289},"end":{"line":9,"column":16,"index":303},"filename":"mutate-after-useeffect-ref-access.ts"},"message":"Cannot update ref during render"}]}}}
51 {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":237},"end":{"line":8,"column":50,"index":285},"filename":"mutate-after-useeffect-ref-access.ts"},"decorations":[{"start":{"line":8,"column":24,"index":259},"end":{"line":8,"column":30,"index":265},"filename":"mutate-after-useeffect-ref-access.ts","identifierName":"arrRef"}]}
52 {"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":158},"end":{"line":11,"column":1,"index":331},"filename":"mutate-after-useeffect-ref-access.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
53 ```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect.expect.md
+1 -1
@@ -47,7 +47,7 @@ export const FIXTURE_ENTRYPOINT = {
47 ## Logs
48
49 ```
50 -{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":111},"end":{"line":11,"column":1,"index":242},"filename":"mutate-after-useeffect.ts"},"detail":{"options":{"category":"Immutability","severity":"InvalidReact","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect().","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":214},"end":{"line":9,"column":5,"index":217},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}}
50 +{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":111},"end":{"line":11,"column":1,"index":242},"filename":"mutate-after-useeffect.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect().","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":214},"end":{"line":9,"column":5,"index":217},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}}
51 {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":6,"column":2,"index":159},"end":{"line":8,"column":14,"index":210},"filename":"mutate-after-useeffect.ts"},"decorations":[{"start":{"line":7,"column":4,"index":181},"end":{"line":7,"column":7,"index":184},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":4,"index":181},"end":{"line":7,"column":7,"index":184},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":13,"index":190},"end":{"line":7,"column":16,"index":193},"filename":"mutate-after-useeffect.ts","identifierName":"foo"}]}
52 {"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":111},"end":{"line":11,"column":1,"index":242},"filename":"mutate-after-useeffect.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
53 ```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/no-emit/retry-no-emit.expect.md
+1 -1
@@ -54,7 +54,7 @@ export const FIXTURE_ENTRYPOINT = {
54 ## Logs
55
56 ```
57 -{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":195},"end":{"line":14,"column":1,"index":409},"filename":"retry-no-emit.ts"},"detail":{"options":{"category":"Immutability","severity":"InvalidReact","reason":"This value cannot be modified","description":"Modifying a value previously passed as an argument to a hook is not allowed. Consider moving the modification before calling the hook.","details":[{"kind":"error","loc":{"start":{"line":12,"column":2,"index":372},"end":{"line":12,"column":6,"index":376},"filename":"retry-no-emit.ts","identifierName":"arr2"},"message":"value cannot be modified"}]}}}
57 +{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":195},"end":{"line":14,"column":1,"index":409},"filename":"retry-no-emit.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value previously passed as an argument to a hook is not allowed. Consider moving the modification before calling the hook.","details":[{"kind":"error","loc":{"start":{"line":12,"column":2,"index":372},"end":{"line":12,"column":6,"index":376},"filename":"retry-no-emit.ts","identifierName":"arr2"},"message":"value cannot be modified"}]}}}
58 {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":248},"end":{"line":8,"column":46,"index":292},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":8,"column":31,"index":277},"end":{"line":8,"column":34,"index":280},"filename":"retry-no-emit.ts","identifierName":"arr"}]}
59 {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":11,"column":2,"index":316},"end":{"line":11,"column":54,"index":368},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":11,"column":25,"index":339},"end":{"line":11,"column":29,"index":343},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":11,"column":25,"index":339},"end":{"line":11,"column":29,"index":343},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":11,"column":35,"index":349},"end":{"line":11,"column":42,"index":356},"filename":"retry-no-emit.ts","identifierName":"propVal"}]}
60 {"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":195},"end":{"line":14,"column":1,"index":409},"filename":"retry-no-emit.ts"},"fnName":"Foo","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.expect.md
+1 -1
@@ -65,7 +65,7 @@ function Component(props) {
65 ## Logs
66
67 ```
68 -{"kind":"CompileError","detail":{"options":{"category":"ErrorBoundaries","severity":"InvalidReact","reason":"Avoid constructing JSX within try/catch","description":"React does not immediately render components when JSX is rendered, so any errors from this component will not be caught by the try/catch. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)","details":[{"kind":"error","loc":{"start":{"line":11,"column":11,"index":222},"end":{"line":11,"column":32,"index":243},"filename":"invalid-jsx-in-catch-in-outer-try-with-catch.ts"},"message":"Avoid constructing JSX within try/catch"}]}},"fnLoc":null}
68 +{"kind":"CompileError","detail":{"options":{"category":"ErrorBoundaries","reason":"Avoid constructing JSX within try/catch","description":"React does not immediately render components when JSX is rendered, so any errors from this component will not be caught by the try/catch. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)","details":[{"kind":"error","loc":{"start":{"line":11,"column":11,"index":222},"end":{"line":11,"column":32,"index":243},"filename":"invalid-jsx-in-catch-in-outer-try-with-catch.ts"},"message":"Avoid constructing JSX within try/catch"}]}},"fnLoc":null}
69 {"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":91},"end":{"line":17,"column":1,"index":298},"filename":"invalid-jsx-in-catch-in-outer-try-with-catch.ts"},"fnName":"Component","memoSlots":4,"memoBlocks":2,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0}
70 ```
71
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.expect.md
+1 -1
@@ -42,7 +42,7 @@ function Component(props) {
42 ## Logs
43
44 ```
45 -{"kind":"CompileError","detail":{"options":{"category":"ErrorBoundaries","severity":"InvalidReact","reason":"Avoid constructing JSX within try/catch","description":"React does not immediately render components when JSX is rendered, so any errors from this component will not be caught by the try/catch. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)","details":[{"kind":"error","loc":{"start":{"line":5,"column":9,"index":104},"end":{"line":5,"column":16,"index":111},"filename":"invalid-jsx-in-try-with-catch.ts"},"message":"Avoid constructing JSX within try/catch"}]}},"fnLoc":null}
45 +{"kind":"CompileError","detail":{"options":{"category":"ErrorBoundaries","reason":"Avoid constructing JSX within try/catch","description":"React does not immediately render components when JSX is rendered, so any errors from this component will not be caught by the try/catch. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)","details":[{"kind":"error","loc":{"start":{"line":5,"column":9,"index":104},"end":{"line":5,"column":16,"index":111},"filename":"invalid-jsx-in-try-with-catch.ts"},"message":"Avoid constructing JSX within try/catch"}]}},"fnLoc":null}
46 {"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":49},"end":{"line":10,"column":1,"index":160},"filename":"invalid-jsx-in-try-with-catch.ts"},"fnName":"Component","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
47 ```
48
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.expect.md
+1 -1
@@ -65,7 +65,7 @@ function _temp(s) {
65 ## Logs
66
67 ```
68 -{"kind":"CompileError","detail":{"options":{"category":"EffectSetState","reason":"Calling setState synchronously within an effect can trigger cascading renders","description":"Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:\n* Update external systems with the latest state from React.\n* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\nCalling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect)","severity":"InvalidReact","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":13,"column":4,"index":265},"end":{"line":13,"column":5,"index":266},"filename":"invalid-setState-in-useEffect-transitive.ts","identifierName":"g"},"message":"Avoid calling setState() directly within an effect"}]}},"fnLoc":null}
68 +{"kind":"CompileError","detail":{"options":{"category":"EffectSetState","reason":"Calling setState synchronously within an effect can trigger cascading renders","description":"Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:\n* Update external systems with the latest state from React.\n* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\nCalling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect)","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":13,"column":4,"index":265},"end":{"line":13,"column":5,"index":266},"filename":"invalid-setState-in-useEffect-transitive.ts","identifierName":"g"},"message":"Avoid calling setState() directly within an effect"}]}},"fnLoc":null}
69 {"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":92},"end":{"line":16,"column":1,"index":293},"filename":"invalid-setState-in-useEffect-transitive.ts"},"fnName":"Component","memoSlots":2,"memoBlocks":2,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0}
70 ```
71
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.expect.md
+1 -1
@@ -45,7 +45,7 @@ function _temp(s) {
45 ## Logs
46
47 ```
48 -{"kind":"CompileError","detail":{"options":{"category":"EffectSetState","reason":"Calling setState synchronously within an effect can trigger cascading renders","description":"Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:\n* Update external systems with the latest state from React.\n* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\nCalling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect)","severity":"InvalidReact","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":7,"column":4,"index":180},"end":{"line":7,"column":12,"index":188},"filename":"invalid-setState-in-useEffect.ts","identifierName":"setState"},"message":"Avoid calling setState() directly within an effect"}]}},"fnLoc":null}
48 +{"kind":"CompileError","detail":{"options":{"category":"EffectSetState","reason":"Calling setState synchronously within an effect can trigger cascading renders","description":"Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:\n* Update external systems with the latest state from React.\n* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\nCalling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect)","suggestions":null,"details":[{"kind":"error","loc":{"start":{"line":7,"column":4,"index":180},"end":{"line":7,"column":12,"index":188},"filename":"invalid-setState-in-useEffect.ts","identifierName":"setState"},"message":"Avoid calling setState() directly within an effect"}]}},"fnLoc":null}
49 {"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":92},"end":{"line":10,"column":1,"index":225},"filename":"invalid-setState-in-useEffect.ts"},"fnName":"Component","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
50 ```
51
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.expect.md
+1 -1
@@ -48,7 +48,7 @@ export const FIXTURE_ENTRYPOINT = {
48 ## Logs
49
50 ```
51 -{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":181},"end":{"line":12,"column":1,"index":436},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"options":{"category":"Immutability","severity":"InvalidReact","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect().","details":[{"kind":"error","loc":{"start":{"line":10,"column":2,"index":397},"end":{"line":10,"column":5,"index":400},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}}
51 +{"kind":"CompileError","fnLoc":{"start":{"line":5,"column":0,"index":181},"end":{"line":12,"column":1,"index":436},"filename":"mutate-after-useeffect-optional-chain.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect().","details":[{"kind":"error","loc":{"start":{"line":10,"column":2,"index":397},"end":{"line":10,"column":5,"index":400},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}}
52 {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":9,"column":2,"index":346},"end":{"line":9,"column":49,"index":393},"filename":"mutate-after-useeffect-optional-chain.ts"},"decorations":[{"start":{"line":9,"column":24,"index":368},"end":{"line":9,"column":27,"index":371},"filename":"mutate-after-useeffect-optional-chain.ts","identifierName":"arr"}]}
53 {"kind":"CompileSuccess","fnLoc":{"start":{"line":5,"column":0,"index":181},"end":{"line":12,"column":1,"index":436},"filename":"mutate-after-useeffect-optional-chain.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
54 ```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.expect.md
+1 -1
@@ -47,7 +47,7 @@ export const FIXTURE_ENTRYPOINT = {
47 ## Logs
48
49 ```
50 -{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":190},"end":{"line":11,"column":1,"index":363},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"options":{"category":"Refs","severity":"InvalidReact","reason":"Cannot access refs during render","description":"React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":321},"end":{"line":9,"column":16,"index":335},"filename":"mutate-after-useeffect-ref-access.ts"},"message":"Cannot update ref during render"}]}}}
50 +{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":190},"end":{"line":11,"column":1,"index":363},"filename":"mutate-after-useeffect-ref-access.ts"},"detail":{"options":{"category":"Refs","reason":"Cannot access refs during render","description":"React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef)","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":321},"end":{"line":9,"column":16,"index":335},"filename":"mutate-after-useeffect-ref-access.ts"},"message":"Cannot update ref during render"}]}}}
51 {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":269},"end":{"line":8,"column":50,"index":317},"filename":"mutate-after-useeffect-ref-access.ts"},"decorations":[{"start":{"line":8,"column":24,"index":291},"end":{"line":8,"column":30,"index":297},"filename":"mutate-after-useeffect-ref-access.ts","identifierName":"arrRef"}]}
52 {"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":190},"end":{"line":11,"column":1,"index":363},"filename":"mutate-after-useeffect-ref-access.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
53 ```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.expect.md
+1 -1
@@ -47,7 +47,7 @@ export const FIXTURE_ENTRYPOINT = {
47 ## Logs
48
49 ```
50 -{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":143},"end":{"line":11,"column":1,"index":274},"filename":"mutate-after-useeffect.ts"},"detail":{"options":{"category":"Immutability","severity":"InvalidReact","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect().","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":246},"end":{"line":9,"column":5,"index":249},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}}
50 +{"kind":"CompileError","fnLoc":{"start":{"line":4,"column":0,"index":143},"end":{"line":11,"column":1,"index":274},"filename":"mutate-after-useeffect.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value used previously in an effect function or as an effect dependency is not allowed. Consider moving the modification before calling useEffect().","details":[{"kind":"error","loc":{"start":{"line":9,"column":2,"index":246},"end":{"line":9,"column":5,"index":249},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},"message":"value cannot be modified"}]}}}
51 {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":6,"column":2,"index":191},"end":{"line":8,"column":14,"index":242},"filename":"mutate-after-useeffect.ts"},"decorations":[{"start":{"line":7,"column":4,"index":213},"end":{"line":7,"column":7,"index":216},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":4,"index":213},"end":{"line":7,"column":7,"index":216},"filename":"mutate-after-useeffect.ts","identifierName":"arr"},{"start":{"line":7,"column":13,"index":222},"end":{"line":7,"column":16,"index":225},"filename":"mutate-after-useeffect.ts","identifierName":"foo"}]}
52 {"kind":"CompileSuccess","fnLoc":{"start":{"line":4,"column":0,"index":143},"end":{"line":11,"column":1,"index":274},"filename":"mutate-after-useeffect.ts"},"fnName":"Component","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
53 ```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.expect.md
+1 -1
@@ -54,7 +54,7 @@ export const FIXTURE_ENTRYPOINT = {
54 ## Logs
55
56 ```
57 -{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":227},"end":{"line":14,"column":1,"index":441},"filename":"retry-no-emit.ts"},"detail":{"options":{"category":"Immutability","severity":"InvalidReact","reason":"This value cannot be modified","description":"Modifying a value previously passed as an argument to a hook is not allowed. Consider moving the modification before calling the hook.","details":[{"kind":"error","loc":{"start":{"line":12,"column":2,"index":404},"end":{"line":12,"column":6,"index":408},"filename":"retry-no-emit.ts","identifierName":"arr2"},"message":"value cannot be modified"}]}}}
57 +{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":227},"end":{"line":14,"column":1,"index":441},"filename":"retry-no-emit.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value previously passed as an argument to a hook is not allowed. Consider moving the modification before calling the hook.","details":[{"kind":"error","loc":{"start":{"line":12,"column":2,"index":404},"end":{"line":12,"column":6,"index":408},"filename":"retry-no-emit.ts","identifierName":"arr2"},"message":"value cannot be modified"}]}}}
58 {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":280},"end":{"line":8,"column":46,"index":324},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":8,"column":31,"index":309},"end":{"line":8,"column":34,"index":312},"filename":"retry-no-emit.ts","identifierName":"arr"}]}
59 {"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":11,"column":2,"index":348},"end":{"line":11,"column":54,"index":400},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":11,"column":25,"index":371},"end":{"line":11,"column":29,"index":375},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":11,"column":25,"index":371},"end":{"line":11,"column":29,"index":375},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":11,"column":35,"index":381},"end":{"line":11,"column":42,"index":388},"filename":"retry-no-emit.ts","identifierName":"propVal"}]}
60 {"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":227},"end":{"line":14,"column":1,"index":441},"filename":"retry-no-emit.ts"},"fnName":"Foo","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.expect.md
+1 -1
@@ -50,7 +50,7 @@ function Example(props) {
50 ## Logs
51
52 ```
53 -{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","severity":"InvalidReact","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render. ","details":[{"kind":"error","loc":{"start":{"line":9,"column":10,"index":202},"end":{"line":9,"column":19,"index":211},"filename":"invalid-conditionally-assigned-dynamically-constructed-component-in-render.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":5,"column":16,"index":124},"end":{"line":5,"column":33,"index":141},"filename":"invalid-conditionally-assigned-dynamically-constructed-component-in-render.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
53 +{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render. ","details":[{"kind":"error","loc":{"start":{"line":9,"column":10,"index":202},"end":{"line":9,"column":19,"index":211},"filename":"invalid-conditionally-assigned-dynamically-constructed-component-in-render.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":5,"column":16,"index":124},"end":{"line":5,"column":33,"index":141},"filename":"invalid-conditionally-assigned-dynamically-constructed-component-in-render.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
54 {"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":45},"end":{"line":10,"column":1,"index":217},"filename":"invalid-conditionally-assigned-dynamically-constructed-component-in-render.ts"},"fnName":"Example","memoSlots":3,"memoBlocks":2,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0}
55 ```
56
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.expect.md
+1 -1
@@ -32,7 +32,7 @@ function Example(props) {
32 ## Logs
33
34 ```
35 -{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","severity":"InvalidReact","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render. ","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":120},"end":{"line":4,"column":19,"index":129},"filename":"invalid-dynamically-construct-component-in-render.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":91},"end":{"line":3,"column":37,"index":108},"filename":"invalid-dynamically-construct-component-in-render.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
35 +{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render. ","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":120},"end":{"line":4,"column":19,"index":129},"filename":"invalid-dynamically-construct-component-in-render.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":91},"end":{"line":3,"column":37,"index":108},"filename":"invalid-dynamically-construct-component-in-render.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
36 {"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":45},"end":{"line":5,"column":1,"index":135},"filename":"invalid-dynamically-construct-component-in-render.ts"},"fnName":"Example","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
37 ```
38
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.expect.md
+1 -1
@@ -37,7 +37,7 @@ function Example(props) {
37 ## Logs
38
39 ```
40 -{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","severity":"InvalidReact","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render. ","details":[{"kind":"error","loc":{"start":{"line":6,"column":10,"index":130},"end":{"line":6,"column":19,"index":139},"filename":"invalid-dynamically-constructed-component-function.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":2,"index":73},"end":{"line":5,"column":3,"index":119},"filename":"invalid-dynamically-constructed-component-function.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
40 +{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render. ","details":[{"kind":"error","loc":{"start":{"line":6,"column":10,"index":130},"end":{"line":6,"column":19,"index":139},"filename":"invalid-dynamically-constructed-component-function.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":2,"index":73},"end":{"line":5,"column":3,"index":119},"filename":"invalid-dynamically-constructed-component-function.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
41 {"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":45},"end":{"line":7,"column":1,"index":145},"filename":"invalid-dynamically-constructed-component-function.ts"},"fnName":"Example","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
42 ```
43
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.expect.md
+1 -1
@@ -41,7 +41,7 @@ function Example(props) {
41 ## Logs
42
43 ```
44 -{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","severity":"InvalidReact","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render. ","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":118},"end":{"line":4,"column":19,"index":127},"filename":"invalid-dynamically-constructed-component-method-call.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":91},"end":{"line":3,"column":35,"index":106},"filename":"invalid-dynamically-constructed-component-method-call.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
44 +{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render. ","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":118},"end":{"line":4,"column":19,"index":127},"filename":"invalid-dynamically-constructed-component-method-call.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":91},"end":{"line":3,"column":35,"index":106},"filename":"invalid-dynamically-constructed-component-method-call.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
45 {"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":45},"end":{"line":5,"column":1,"index":133},"filename":"invalid-dynamically-constructed-component-method-call.ts"},"fnName":"Example","memoSlots":4,"memoBlocks":2,"memoValues":2,"prunedMemoBlocks":0,"prunedMemoValues":0}
46 ```
47
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.expect.md
+1 -1
@@ -32,7 +32,7 @@ function Example(props) {
32 ## Logs
33
34 ```
35 -{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","severity":"InvalidReact","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render. ","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":125},"end":{"line":4,"column":19,"index":134},"filename":"invalid-dynamically-constructed-component-new.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":91},"end":{"line":3,"column":42,"index":113},"filename":"invalid-dynamically-constructed-component-new.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
35 +{"kind":"CompileError","detail":{"options":{"category":"StaticComponents","reason":"Cannot create components during render","description":"Components created during render will reset their state each time they are created. Declare components outside of render. ","details":[{"kind":"error","loc":{"start":{"line":4,"column":10,"index":125},"end":{"line":4,"column":19,"index":134},"filename":"invalid-dynamically-constructed-component-new.ts"},"message":"This component is created during render"},{"kind":"error","loc":{"start":{"line":3,"column":20,"index":91},"end":{"line":3,"column":42,"index":113},"filename":"invalid-dynamically-constructed-component-new.ts"},"message":"The component is created during render here"}]}},"fnLoc":null}
36 {"kind":"CompileSuccess","fnLoc":{"start":{"line":2,"column":0,"index":45},"end":{"line":5,"column":1,"index":140},"filename":"invalid-dynamically-constructed-component-new.ts"},"fnName":"Example","memoSlots":1,"memoBlocks":1,"memoValues":1,"prunedMemoBlocks":0,"prunedMemoValues":0}
37 ```
38
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-outside-effect.expect.md
+2 -2
@@ -26,7 +26,7 @@ function Component({props, bar}) {
26 ```
27 Found 2 errors:
28
29 -Invariant: Cannot compile `fire`
29 +Error: Cannot compile `fire`
30
31 Cannot use `fire` outside of a useEffect function.
32
@@ -39,7 +39,7 @@ error.invalid-outside-effect.ts:8:2
39 10 | useCallback(() => {
40 11 | fire(foo(props));
41
42 -Invariant: Cannot compile `fire`
42 +Error: Cannot compile `fire`
43
44 Cannot use `fire` outside of a useEffect function.
45
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-no-array-literal.expect.md
+1 -1
@@ -27,7 +27,7 @@ function Component(props) {
27 ```
28 Found 1 error:
29
30 -Invariant: Cannot compile `fire`
30 +Error: Cannot compile `fire`
31
32 You must use an array literal for an effect dependency array when that effect uses `fire()`.
33
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-spread.expect.md
+1 -1
@@ -30,7 +30,7 @@ function Component(props) {
30 ```
31 Found 1 error:
32
33 -Invariant: Cannot compile `fire`
33 +Error: Cannot compile `fire`
34
35 You must use an array literal for an effect dependency array when that effect uses `fire()`.
36
compiler/packages/eslint-plugin-react-compiler/__tests__/ImpureFunctionCallsRule-test.ts
+1 -1
@@ -14,7 +14,7 @@ import {allRules} from '../src/rules/ReactCompilerRule';
14
15 testRule(
16 'no impure function calls rule',
17 - allRules[getRuleForCategory(ErrorCategory.Purity).name],
17 + allRules[getRuleForCategory(ErrorCategory.Purity).name].rule,
18 {
19 valid: [],
20 invalid: [
compiler/packages/eslint-plugin-react-compiler/__tests__/InvalidHooksRule-test.ts
+1 -1
@@ -14,7 +14,7 @@ import {allRules} from '../src/rules/ReactCompilerRule';
14
15 testRule(
16 'rules-of-hooks',
17 - allRules[getRuleForCategory(ErrorCategory.Hooks).name],
17 + allRules[getRuleForCategory(ErrorCategory.Hooks).name].rule,
18 {
19 valid: [
20 {
compiler/packages/eslint-plugin-react-compiler/__tests__/NoAmbiguousJsxRule-test.ts
+1 -1
@@ -14,7 +14,7 @@ import {allRules} from '../src/rules/ReactCompilerRule';
14
15 testRule(
16 'no ambiguous JSX rule',
17 - allRules[getRuleForCategory(ErrorCategory.ErrorBoundaries).name],
17 + allRules[getRuleForCategory(ErrorCategory.ErrorBoundaries).name].rule,
18 {
19 valid: [],
20 invalid: [
compiler/packages/eslint-plugin-react-compiler/__tests__/NoCapitalizedCallsRule-test.ts
+1 -1
@@ -13,7 +13,7 @@ import {allRules} from '../src/rules/ReactCompilerRule';
13
14 testRule(
15 'no-capitalized-calls',
16 - allRules[getRuleForCategory(ErrorCategory.CapitalizedCalls).name],
16 + allRules[getRuleForCategory(ErrorCategory.CapitalizedCalls).name].rule,
17 {
18 valid: [],
19 invalid: [
compiler/packages/eslint-plugin-react-compiler/__tests__/NoRefAccessInRender-tests.ts
+1 -1
@@ -14,7 +14,7 @@ import {allRules} from '../src/rules/ReactCompilerRule';
14
15 testRule(
16 'no ref access in render rule',
17 - allRules[getRuleForCategory(ErrorCategory.Refs).name],
17 + allRules[getRuleForCategory(ErrorCategory.Refs).name].rule,
18 {
19 valid: [],
20 invalid: [
compiler/packages/eslint-plugin-react-compiler/__tests__/shared-utils.ts
+2 -2
@@ -61,10 +61,10 @@ export const TestRecommendedRules: Rule.RuleModule = {
61 schema: [{type: 'object', additionalProperties: true}],
62 },
63 create(context) {
64 - for (const rule of Object.values(
64 + for (const ruleConfig of Object.values(
65 configs.recommended.plugins['react-compiler'].rules,
66 )) {
67 - const listener = rule.create(context);
67 + const listener = ruleConfig.rule.create(context);
68 if (Object.entries(listener).length !== 0) {
69 throw new Error('TODO: handle rules that return listeners to eslint');
70 }
compiler/packages/eslint-plugin-react-compiler/src/index.ts
+13 -6
@@ -5,7 +5,12 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {allRules, recommendedRules} from './rules/ReactCompilerRule';
8 +import {type Linter} from 'eslint';
9 +import {
10 + allRules,
11 + mapErrorSeverityToESlint,
12 + recommendedRules,
13 +} from './rules/ReactCompilerRule';
14
15 const meta = {
16 name: 'eslint-plugin-react-compiler',
@@ -19,11 +24,13 @@ const configs = {
24 },
25 },
26 rules: Object.fromEntries(
22 - Object.keys(recommendedRules).map(ruleName => [
23 - 'react-compiler/' + ruleName,
24 - 'error',
25 - ]),
26 - ) as Record<string, 'error' | 'warn'>,
27 + Object.entries(recommendedRules).map(([name, ruleConfig]) => {
28 + return [
29 + 'react-compiler/' + name,
30 + mapErrorSeverityToESlint(ruleConfig.severity),
31 + ];
32 + }),
33 + ) as Record<string, Linter.StringSeverity>,
34 },
35 };
36
compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts
+39 -10
@@ -11,9 +11,10 @@ import {
11 CompilerErrorDetailOptions,
12 CompilerSuggestionOperation,
13 } from 'babel-plugin-react-compiler/src';
14 -import type {Rule} from 'eslint';
14 +import type {Linter, Rule} from 'eslint';
15 import runReactCompiler, {RunCacheEntry} from '../shared/RunReactCompiler';
16 import {
17 + ErrorSeverity,
18 LintRules,
19 type LintRule,
20 } from 'babel-plugin-react-compiler/src/CompilerError';
@@ -192,26 +193,54 @@ export const NoUnusedDirectivesRule: Rule.RuleModule = {
193 },
194 };
195
195 -type RulesObject = {[name: string]: Rule.RuleModule};
196 +type RulesConfig = {
197 + [name: string]: {rule: Rule.RuleModule; severity: ErrorSeverity};
198 +};
199
197 -export const allRules: RulesObject = LintRules.reduce(
200 +export const allRules: RulesConfig = LintRules.reduce(
201 (acc, rule) => {
199 - acc[rule.name] = makeRule(rule);
202 + acc[rule.name] = {rule: makeRule(rule), severity: rule.severity};
203 return acc;
204 },
205 {
203 - 'no-unused-directives': NoUnusedDirectivesRule,
204 - } as RulesObject,
206 + 'no-unused-directives': {
207 + rule: NoUnusedDirectivesRule,
208 + severity: ErrorSeverity.Error,
209 + },
210 + } as RulesConfig,
211 );
212
207 -export const recommendedRules: RulesObject = LintRules.filter(
213 +export const recommendedRules: RulesConfig = LintRules.filter(
214 rule => rule.recommended,
215 ).reduce(
216 (acc, rule) => {
211 - acc[rule.name] = makeRule(rule);
217 + acc[rule.name] = {rule: makeRule(rule), severity: rule.severity};
218 return acc;
219 },
220 {
215 - 'no-unused-directives': NoUnusedDirectivesRule,
216 - } as RulesObject,
221 + 'no-unused-directives': {
222 + rule: NoUnusedDirectivesRule,
223 + severity: ErrorSeverity.Error,
224 + },
225 + } as RulesConfig,
226 );
227 +
228 +export function mapErrorSeverityToESlint(
229 + severity: ErrorSeverity,
230 +): Linter.StringSeverity {
231 + switch (severity) {
232 + case ErrorSeverity.Error: {
233 + return 'error';
234 + }
235 + case ErrorSeverity.Warning: {
236 + return 'warn';
237 + }
238 + case ErrorSeverity.Hint:
239 + case ErrorSeverity.Off: {
240 + return 'off';
241 + }
242 + default: {
243 + assertExhaustive(severity, `Unhandled severity: ${severity}`);
244 + }
245 + }
246 +}
compiler/scripts/build-eslint-docs.js
+6 -4
@@ -19,12 +19,14 @@ const combinedRules = [
19 ];
20
21 const printed = combinedRules
22 - .filter(rule => rule.recommended)
23 - .map(rule => {
22 + .filter(
23 + ruleConfig => ruleConfig.rule.recommended && ruleConfig.severity !== 'Off'
24 + )
25 + .map(ruleConfig => {
26 return `
25 -## \`react-hooks/${rule.name}\`
27 +## \`react-hooks/${ruleConfig.rule.name}\`
28
27 -${rule.description}
29 +${ruleConfig.rule.description}
30 `.trim();
31 })
32 .join('\n\n');
packages/eslint-plugin-react-hooks/__tests__/ReactCompilerRuleTypescript-test.ts
+1 -1
@@ -74,4 +74,4 @@ const tests: CompilerTestCases = {
74 const eslintTester = new ESLintTesterV8({
75 parser: require.resolve('@typescript-eslint/parser-v5'),
76 });
77 -eslintTester.run('react-compiler', allRules['immutability'], tests);
77 +eslintTester.run('react-compiler', allRules['immutability'].rule, tests);
packages/eslint-plugin-react-hooks/src/index.ts
+15 -3
@@ -7,22 +7,34 @@
7 import type {Linter, Rule} from 'eslint';
8
9 import ExhaustiveDeps from './rules/ExhaustiveDeps';
10 -import {allRules, recommendedRules} from './shared/ReactCompiler';
10 +import {
11 + allRules,
12 + mapErrorSeverityToESlint,
13 + recommendedRules,
14 +} from './shared/ReactCompiler';
15 import RulesOfHooks from './rules/RulesOfHooks';
16
17 // All rules
18 const rules = {
19 'exhaustive-deps': ExhaustiveDeps,
20 'rules-of-hooks': RulesOfHooks,
17 - ...allRules,
21 + ...Object.fromEntries(
22 + Object.entries(allRules).map(([name, config]) => [name, config.rule])
23 + ),
24 } satisfies Record<string, Rule.RuleModule>;
25
26 // Config rules
27 const ruleConfigs = {
28 'react-hooks/rules-of-hooks': 'error',
29 'react-hooks/exhaustive-deps': 'warn',
30 + // Compiler rules
31 ...Object.fromEntries(
25 - Object.keys(recommendedRules).map(name => ['react-hooks/' + name, 'error']),
32 + Object.entries(recommendedRules).map(([name, ruleConfig]) => {
33 + return [
34 + 'react-hooks/' + name,
35 + mapErrorSeverityToESlint(ruleConfig.severity),
36 + ];
37 + }),
38 ),
39 } satisfies Linter.RulesRecord;
40
packages/eslint-plugin-react-hooks/src/shared/ReactCompiler.ts
+39 -10
@@ -13,8 +13,9 @@ import {
13 CompilerSuggestionOperation,
14 LintRules,
15 type LintRule,
16 + ErrorSeverity,
17 } from 'babel-plugin-react-compiler';
17 -import type {Rule} from 'eslint';
18 +import {type Linter, type Rule} from 'eslint';
19 import runReactCompiler, {RunCacheEntry} from './RunReactCompiler';
20
21 function assertExhaustive(_: never, errorMsg: string): never {
@@ -191,26 +192,54 @@ export const NoUnusedDirectivesRule: Rule.RuleModule = {
192 },
193 };
194
194 -type RulesObject = {[name: string]: Rule.RuleModule};
195 +type RulesConfig = {
196 + [name: string]: {rule: Rule.RuleModule; severity: ErrorSeverity};
197 +};
198
196 -export const allRules: RulesObject = LintRules.reduce(
199 +export const allRules: RulesConfig = LintRules.reduce(
200 (acc, rule) => {
198 - acc[rule.name] = makeRule(rule);
201 + acc[rule.name] = {rule: makeRule(rule), severity: rule.severity};
202 return acc;
203 },
204 {
202 - 'no-unused-directives': NoUnusedDirectivesRule,
203 - } as RulesObject,
205 + 'no-unused-directives': {
206 + rule: NoUnusedDirectivesRule,
207 + severity: ErrorSeverity.Error,
208 + },
209 + } as RulesConfig,
210 );
211
206 -export const recommendedRules: RulesObject = LintRules.filter(
212 +export const recommendedRules: RulesConfig = LintRules.filter(
213 rule => rule.recommended,
214 ).reduce(
215 (acc, rule) => {
210 - acc[rule.name] = makeRule(rule);
216 + acc[rule.name] = {rule: makeRule(rule), severity: rule.severity};
217 return acc;
218 },
219 {
214 - 'no-unused-directives': NoUnusedDirectivesRule,
215 - } as RulesObject,
220 + 'no-unused-directives': {
221 + rule: NoUnusedDirectivesRule,
222 + severity: ErrorSeverity.Error,
223 + },
224 + } as RulesConfig,
225 );
226 +
227 +export function mapErrorSeverityToESlint(
228 + severity: ErrorSeverity,
229 +): Linter.StringSeverity {
230 + switch (severity) {
231 + case ErrorSeverity.Error: {
232 + return 'error';
233 + }
234 + case ErrorSeverity.Warning: {
235 + return 'warn';
236 + }
237 + case ErrorSeverity.Hint:
238 + case ErrorSeverity.Off: {
239 + return 'off';
240 + }
241 + default: {
242 + assertExhaustive(severity, `Unhandled severity: ${severity}`);
243 + }
244 + }
245 +}