diff --git a/compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts b/compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts index e12530a8db5..a2472f09068 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/CompilerError.ts @@ -14,50 +14,28 @@ import invariant from 'invariant'; export enum ErrorSeverity { /** - * Invalid JS syntax, or valid syntax that is semantically invalid which may indicate some - * misunderstanding on the user’s part. + * An actionable error that the developer can fix. For example, product code errors should be + * reported as such. */ - InvalidJS = 'InvalidJS', + Error = 'Error', /** - * JS syntax that is not supported and which we do not plan to support. Developers should - * rewrite to use supported forms. + * An error that the developer may not necessarily be able to fix. For example, syntax not + * supported by the compiler does not indicate any fault in the product code. */ - UnsupportedJS = 'UnsupportedJS', + Warning = 'Warning', /** - * Code that breaks the rules of React. + * Not an error. These will not be surfaced in ESLint, but may be surfaced in other ways + * (eg Forgive) where informational hints can be shown. */ - InvalidReact = 'InvalidReact', + Hint = 'Hint', /** - * Incorrect configuration of the compiler. + * These errors will not be reported anywhere. Useful for work in progress validations. */ - InvalidConfig = 'InvalidConfig', - /** - * Code that can reasonably occur and that doesn't break any rules, but is unsafe to preserve - * memoization. - */ - CannotPreserveMemoization = 'CannotPreserveMemoization', - /** - * An API that is known to be incompatible with the compiler. Generally as a result of - * the library using "interior mutability", ie having a value whose referential identity - * stays the same but which provides access to values that can change. For example a - * function that doesn't change but returns different results, or an object that doesn't - * change identity but whose properties change. - */ - IncompatibleLibrary = 'IncompatibleLibrary', - /** - * Unhandled syntax that we don't support yet. - */ - Todo = 'Todo', - /** - * An unexpected internal error in the compiler that indicates critical issues that can panic - * the compiler. - */ - Invariant = 'Invariant', + Off = 'Off', } export type CompilerDiagnosticOptions = { category: ErrorCategory; - severity: ErrorSeverity; reason: string; description: string; details: Array; @@ -102,7 +80,6 @@ export type CompilerSuggestion = export type CompilerErrorDetailOptions = { category: ErrorCategory; - severity: ErrorSeverity; reason: string; description?: string | null | undefined; loc: SourceLocation | null; @@ -136,8 +113,8 @@ export class CompilerDiagnostic { get description(): CompilerDiagnosticOptions['description'] { return this.options.description; } - get severity(): CompilerDiagnosticOptions['severity'] { - return this.options.severity; + get severity(): ErrorSeverity { + return getRuleForCategory(this.category).severity; } get suggestions(): CompilerDiagnosticOptions['suggestions'] { return this.options.suggestions; @@ -162,7 +139,7 @@ export class CompilerDiagnostic { printErrorMessage(source: string, options: PrintErrorMessageOptions): string { const buffer = [ - printErrorSummary(this.severity, this.reason), + printErrorSummary(this.category, this.reason), '\n\n', this.description, ]; @@ -207,7 +184,7 @@ export class CompilerDiagnostic { } toString(): string { - const buffer = [printErrorSummary(this.severity, this.reason)]; + const buffer = [printErrorSummary(this.category, this.reason)]; if (this.description != null) { buffer.push(`. ${this.description}.`); } @@ -236,8 +213,8 @@ export class CompilerErrorDetail { get description(): CompilerErrorDetailOptions['description'] { return this.options.description; } - get severity(): CompilerErrorDetailOptions['severity'] { - return this.options.severity; + get severity(): ErrorSeverity { + return getRuleForCategory(this.category).severity; } get loc(): CompilerErrorDetailOptions['loc'] { return this.options.loc; @@ -254,7 +231,7 @@ export class CompilerErrorDetail { } printErrorMessage(source: string, options: PrintErrorMessageOptions): string { - const buffer = [printErrorSummary(this.severity, this.reason)]; + const buffer = [printErrorSummary(this.category, this.reason)]; if (this.description != null) { buffer.push(`\n\n${this.description}.`); } @@ -279,7 +256,7 @@ export class CompilerErrorDetail { } toString(): string { - const buffer = [printErrorSummary(this.severity, this.reason)]; + const buffer = [printErrorSummary(this.category, this.reason)]; if (this.description != null) { buffer.push(`. ${this.description}.`); } @@ -305,7 +282,6 @@ export class CompilerError extends Error { new CompilerErrorDetail({ ...options, category: ErrorCategory.Invariant, - severity: ErrorSeverity.Invariant, }), ); throw errors; @@ -325,7 +301,6 @@ export class CompilerError extends Error { errors.pushErrorDetail( new CompilerErrorDetail({ ...options, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, }), ); @@ -339,7 +314,6 @@ export class CompilerError extends Error { errors.pushErrorDetail( new CompilerErrorDetail({ ...options, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, }), ); @@ -350,12 +324,7 @@ export class CompilerError extends Error { options: Omit, ): never { const errors = new CompilerError(); - errors.pushErrorDetail( - new CompilerErrorDetail({ - ...options, - severity: ErrorSeverity.InvalidReact, - }), - ); + errors.pushErrorDetail(new CompilerErrorDetail(options)); throw errors; } @@ -366,7 +335,6 @@ export class CompilerError extends Error { errors.pushErrorDetail( new CompilerErrorDetail({ ...options, - severity: ErrorSeverity.InvalidConfig, category: ErrorCategory.Config, }), ); @@ -434,7 +402,6 @@ export class CompilerError extends Error { category: options.category, reason: options.reason, description: options.description ?? null, - severity: options.severity, suggestions: options.suggestions, loc: typeof options.loc === 'symbol' ? null : options.loc, }); @@ -454,31 +421,58 @@ export class CompilerError extends Error { return this.hasErrors() ? Err(this) : Ok(undefined); } - /* - * An error is critical if it means the compiler has entered into a broken state and cannot - * continue safely. Other expected errors such as Todos mean that we can skip over that component - * but otherwise continue compiling the rest of the app. - */ - isCritical(): boolean { - return this.details.some(detail => { - switch (detail.severity) { - case ErrorSeverity.Invariant: - case ErrorSeverity.InvalidJS: - case ErrorSeverity.InvalidReact: - case ErrorSeverity.InvalidConfig: - case ErrorSeverity.UnsupportedJS: - case ErrorSeverity.IncompatibleLibrary: { - return true; - } - case ErrorSeverity.CannotPreserveMemoization: - case ErrorSeverity.Todo: { - return false; - } - default: { - assertExhaustive(detail.severity, 'Unhandled error severity'); - } + /** + * Returns true if any of the error details are of severity Error. + */ + isError(): boolean { + let res = false; + for (const detail of this.details) { + if (detail.severity === ErrorSeverity.Off) { + return false; } - }); + if (detail.severity === ErrorSeverity.Error) { + res = true; + } + } + return res; + } + + /** + * Returns true if there are no Errors and there is at least one Warning. + */ + isWarning(): boolean { + let res = false; + for (const detail of this.details) { + if (detail.severity === ErrorSeverity.Off) { + return false; + } + if (detail.severity === ErrorSeverity.Error) { + return false; + } + if (detail.severity === ErrorSeverity.Warning) { + res = true; + } + } + return res; + } + + isHint(): boolean { + let res = false; + for (const detail of this.details) { + if (detail.severity === ErrorSeverity.Off) { + return false; + } + if (detail.severity === ErrorSeverity.Error) { + return false; + } + if (detail.severity === ErrorSeverity.Warning) { + return false; + } + if (detail.severity === ErrorSeverity.Hint) { + res = true; + } + } + return res; } } @@ -505,115 +499,158 @@ function printCodeFrame( ); } -function printErrorSummary(severity: ErrorSeverity, message: string): string { - let severityCategory: string; - switch (severity) { - case ErrorSeverity.InvalidConfig: - case ErrorSeverity.InvalidJS: - case ErrorSeverity.InvalidReact: - case ErrorSeverity.UnsupportedJS: { - severityCategory = 'Error'; +function printErrorSummary(category: ErrorCategory, message: string): string { + let heading: string; + switch (category) { + case ErrorCategory.AutomaticEffectDependencies: + case ErrorCategory.CapitalizedCalls: + case ErrorCategory.Config: + case ErrorCategory.EffectDerivationsOfState: + case ErrorCategory.EffectSetState: + case ErrorCategory.ErrorBoundaries: + case ErrorCategory.Factories: + case ErrorCategory.FBT: + case ErrorCategory.Fire: + case ErrorCategory.Gating: + case ErrorCategory.Globals: + case ErrorCategory.Hooks: + case ErrorCategory.Immutability: + case ErrorCategory.Purity: + case ErrorCategory.Refs: + case ErrorCategory.RenderSetState: + case ErrorCategory.StaticComponents: + case ErrorCategory.Suppression: + case ErrorCategory.Syntax: + case ErrorCategory.UseMemo: { + heading = 'Error'; break; } - case ErrorSeverity.IncompatibleLibrary: - case ErrorSeverity.CannotPreserveMemoization: { - severityCategory = 'Compilation Skipped'; + case ErrorCategory.EffectDependencies: + case ErrorCategory.IncompatibleLibrary: + case ErrorCategory.PreserveManualMemo: + case ErrorCategory.UnsupportedSyntax: { + heading = 'Compilation Skipped'; break; } - case ErrorSeverity.Invariant: { - severityCategory = 'Invariant'; + case ErrorCategory.Invariant: { + heading = 'Invariant'; break; } - case ErrorSeverity.Todo: { - severityCategory = 'Todo'; + case ErrorCategory.Todo: { + heading = 'Todo'; break; } default: { - assertExhaustive(severity, `Unexpected severity '${severity}'`); + assertExhaustive(category, `Unhandled category '${category}'`); } } - return `${severityCategory}: ${message}`; + return `${heading}: ${message}`; } /** * See getRuleForCategory() for how these map to ESLint rules */ export enum ErrorCategory { - // Checking for valid hooks usage (non conditional, non-first class, non reactive, etc) + /** + * Checking for valid hooks usage (non conditional, non-first class, non reactive, etc) + */ Hooks = 'Hooks', - - // Checking for no capitalized calls (not definitively an error, hence separating) + /** + * Checking for no capitalized calls (not definitively an error, hence separating) + */ CapitalizedCalls = 'CapitalizedCalls', - - // Checking for static components + /** + * Checking for static components + */ StaticComponents = 'StaticComponents', - - // Checking for valid usage of manual memoization + /** + * Checking for valid usage of manual memoization + */ UseMemo = 'UseMemo', - - // Checking for higher order functions acting as factories for components/hooks + /** + * Checking for higher order functions acting as factories for components/hooks + */ Factories = 'Factories', - - // Checks that manual memoization is preserved + /** + * Checks that manual memoization is preserved + */ PreserveManualMemo = 'PreserveManualMemo', - - // Checks for known incompatible libraries + /** + * Checks for known incompatible libraries + */ IncompatibleLibrary = 'IncompatibleLibrary', - - // Checking for no mutations of props, hook arguments, hook return values + /** + * Checking for no mutations of props, hook arguments, hook return values + */ Immutability = 'Immutability', - - // Checking for assignments to globals + /** + * Checking for assignments to globals + */ Globals = 'Globals', - - // Checking for valid usage of refs, ie no access during render + /** + * Checking for valid usage of refs, ie no access during render + */ Refs = 'Refs', - - // Checks for memoized effect deps + /** + * Checks for memoized effect deps + */ EffectDependencies = 'EffectDependencies', - - // Checks for no setState in effect bodies + /** + * Checks for no setState in effect bodies + */ EffectSetState = 'EffectSetState', - EffectDerivationsOfState = 'EffectDerivationsOfState', - - // Validates against try/catch in place of error boundaries + /** + * Validates against try/catch in place of error boundaries + */ ErrorBoundaries = 'ErrorBoundaries', - - // Checking for pure functions + /** + * Checking for pure functions + */ Purity = 'Purity', - - // Validates against setState in render + /** + * Validates against setState in render + */ RenderSetState = 'RenderSetState', - - // Internal invariants + /** + * Internal invariants + */ Invariant = 'Invariant', - - // Todos + /** + * Todos + */ Todo = 'Todo', - - // Syntax errors + /** + * Syntax errors + */ Syntax = 'Syntax', - - // Checks for use of unsupported syntax + /** + * Checks for use of unsupported syntax + */ UnsupportedSyntax = 'UnsupportedSyntax', - - // Config errors + /** + * Config errors + */ Config = 'Config', - - // Gating error + /** + * Gating error + */ Gating = 'Gating', - - // Suppressions + /** + * Suppressions + */ Suppression = 'Suppression', - - // Issues with auto deps + /** + * Issues with auto deps + */ AutomaticEffectDependencies = 'AutomaticEffectDependencies', - - // Issues with `fire` + /** + * Issues with `fire` + */ Fire = 'Fire', - - // fbt-specific issues + /** + * fbt-specific issues + */ FBT = 'FBT', } @@ -621,6 +658,9 @@ export type LintRule = { // Stores the category the rule corresponds to, used to filter errors when reporting category: ErrorCategory; + // Stores the severity of the error, which is used to map to lint levels such as error/warning. + severity: ErrorSeverity; + /** * The "name" of the rule as it will be used by developers to enable/disable, eg * "eslint-disable-nest line " @@ -661,6 +701,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.AutomaticEffectDependencies: { return { category, + severity: ErrorSeverity.Error, name: 'automatic-effect-dependencies', description: 'Verifies that automatic effect dependencies are compiled if opted-in', @@ -670,6 +711,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.CapitalizedCalls: { return { category, + severity: ErrorSeverity.Error, name: 'capitalized-calls', description: 'Validates against calling capitalized functions/methods instead of using JSX', @@ -679,6 +721,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Config: { return { category, + severity: ErrorSeverity.Error, name: 'config', description: 'Validates the compiler configuration options', recommended: true, @@ -687,6 +730,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.EffectDependencies: { return { category, + severity: ErrorSeverity.Error, name: 'memoized-effect-dependencies', description: 'Validates that effect dependencies are memoized', recommended: false, @@ -695,6 +739,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.EffectDerivationsOfState: { return { category, + severity: ErrorSeverity.Error, name: 'no-deriving-state-in-effects', description: 'Validates against deriving values from state in an effect', @@ -704,6 +749,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.EffectSetState: { return { category, + severity: ErrorSeverity.Error, name: 'set-state-in-effect', description: '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 { case ErrorCategory.ErrorBoundaries: { return { category, + severity: ErrorSeverity.Error, name: 'error-boundaries', description: 'Validates usage of error boundaries instead of try/catch for errors in child components', @@ -722,6 +769,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Factories: { return { category, + severity: ErrorSeverity.Error, name: 'component-hook-factories', description: 'Validates against higher order functions defining nested components or hooks. ' + @@ -732,6 +780,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.FBT: { return { category, + severity: ErrorSeverity.Error, name: 'fbt', description: 'Validates usage of fbt', recommended: false, @@ -740,6 +789,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Fire: { return { category, + severity: ErrorSeverity.Error, name: 'fire', description: 'Validates usage of `fire`', recommended: false, @@ -748,6 +798,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Gating: { return { category, + severity: ErrorSeverity.Error, name: 'gating', description: 'Validates configuration of [gating mode](https://react.dev/reference/react-compiler/gating)', @@ -757,6 +808,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Globals: { return { category, + severity: ErrorSeverity.Error, name: 'globals', description: 'Validates against assignment/mutation of globals during render, part of ensuring that ' + @@ -767,6 +819,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Hooks: { return { category, + severity: ErrorSeverity.Error, name: 'hooks', description: 'Validates the rules of hooks', /** @@ -780,6 +833,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Immutability: { return { category, + severity: ErrorSeverity.Error, name: 'immutability', description: '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 { case ErrorCategory.Invariant: { return { category, + severity: ErrorSeverity.Error, name: 'invariant', description: 'Internal invariants', recommended: false, @@ -797,6 +852,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.PreserveManualMemo: { return { category, + severity: ErrorSeverity.Error, name: 'preserve-manual-memoization', description: 'Validates that existing manual memoized is preserved by the compiler. ' + @@ -808,6 +864,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Purity: { return { category, + severity: ErrorSeverity.Error, name: 'purity', description: '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 { case ErrorCategory.Refs: { return { category, + severity: ErrorSeverity.Error, name: 'refs', description: '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 { case ErrorCategory.RenderSetState: { return { category, + severity: ErrorSeverity.Error, name: 'set-state-in-render', description: '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 { case ErrorCategory.StaticComponents: { return { category, + severity: ErrorSeverity.Error, name: 'static-components', description: '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 { case ErrorCategory.Suppression: { return { category, + severity: ErrorSeverity.Error, name: 'rule-suppression', description: 'Validates against suppression of other rules', recommended: false, @@ -852,6 +913,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Syntax: { return { category, + severity: ErrorSeverity.Error, name: 'syntax', description: 'Validates against invalid syntax', recommended: false, @@ -860,6 +922,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.Todo: { return { category, + severity: ErrorSeverity.Hint, name: 'todo', description: 'Unimplemented features', recommended: false, @@ -868,6 +931,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.UnsupportedSyntax: { return { category, + severity: ErrorSeverity.Warning, name: 'unsupported-syntax', description: 'Validates against syntax that we do not plan to support in React Compiler', @@ -877,6 +941,7 @@ function getRuleForCategoryImpl(category: ErrorCategory): LintRule { case ErrorCategory.UseMemo: { return { category, + severity: ErrorSeverity.Error, name: 'use-memo', description: '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 { case ErrorCategory.IncompatibleLibrary: { return { category, + severity: ErrorSeverity.Warning, name: 'incompatible-library', description: 'Validates against usage of libraries which are incompatible with memoization (manual or automatic)', diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts index 9653c49576a..75f3d26ad0f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts @@ -9,7 +9,7 @@ import {NodePath} from '@babel/core'; import * as t from '@babel/types'; import {Scope as BabelScope} from '@babel/traverse'; -import {CompilerError, ErrorCategory, ErrorSeverity} from '../CompilerError'; +import {CompilerError, ErrorCategory} from '../CompilerError'; import { EnvironmentConfig, GeneratedSource, @@ -39,7 +39,6 @@ export function validateRestrictedImports( if (restrictedImports.has(importDeclPath.node.source.value)) { error.push({ category: ErrorCategory.Todo, - severity: ErrorSeverity.Todo, reason: 'Bailing out due to blocklisted import', description: `Import from module ${importDeclPath.node.source.value}`, loc: importDeclPath.node.loc ?? null, @@ -207,7 +206,6 @@ export class ProgramContext { const error = new CompilerError(); error.push({ category: ErrorCategory.Todo, - severity: ErrorSeverity.Todo, reason: 'Encountered conflicting global in generated program', description: `Conflict from local binding ${name}`, loc: scope.getBinding(name)?.path.node.loc ?? null, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts index 5a9ef9495fa..f57ca5d33e9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts @@ -11,7 +11,6 @@ import { CompilerError, CompilerErrorDetail, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import {ExternalFunction, ReactFunctionType} from '../HIR/Environment'; import {CodegenFunction} from '../ReactiveScopes'; @@ -105,7 +104,6 @@ function findDirectivesDynamicGating( errors.push({ reason: `Dynamic gating directive is not a valid JavaScript identifier`, description: `Found '${directive.value.value}'`, - severity: ErrorSeverity.InvalidReact, category: ErrorCategory.Gating, loc: directive.loc ?? null, suggestions: null, @@ -122,7 +120,6 @@ function findDirectivesDynamicGating( description: `Expected a single directive but found [${result .map(r => r.directive.value.value) .join(', ')}]`, - severity: ErrorSeverity.InvalidReact, category: ErrorCategory.Gating, loc: result[0].directive.loc ?? null, suggestions: null, @@ -141,15 +138,13 @@ function findDirectivesDynamicGating( } } -function isCriticalError(err: unknown): boolean { - return !(err instanceof CompilerError) || err.isCritical(); +function isError(err: unknown): boolean { + return !(err instanceof CompilerError) || err.isError(); } function isConfigError(err: unknown): boolean { if (err instanceof CompilerError) { - return err.details.some( - detail => detail.severity === ErrorSeverity.InvalidConfig, - ); + return err.details.some(detail => detail.category === ErrorCategory.Config); } return false; } @@ -214,8 +209,7 @@ function handleError( logError(err, context, fnLoc); if ( context.opts.panicThreshold === 'all_errors' || - (context.opts.panicThreshold === 'critical_errors' && - isCriticalError(err)) || + (context.opts.panicThreshold === 'critical_errors' && isError(err)) || isConfigError(err) // Always throws regardless of panic threshold ) { throw err; @@ -458,7 +452,6 @@ export function compileProgram( new CompilerErrorDetail({ reason: 'Unexpected compiled functions when module scope opt-out is present', - severity: ErrorSeverity.Invariant, category: ErrorCategory.Invariant, loc: null, }), @@ -827,7 +820,6 @@ function shouldSkipCompilation( reason: `Expected a filename but found none.`, description: "When the 'sources' config options is specified, the React compiler will only compile files with a name", - severity: ErrorSeverity.InvalidConfig, category: ErrorCategory.Config, loc: null, }), @@ -890,7 +882,6 @@ function validateNoDynamicallyCreatedComponentsOrHooks( if (nestedFnType === 'Component' || nestedFnType === 'Hook') { CompilerError.throwDiagnostic({ category: ErrorCategory.Factories, - severity: ErrorSeverity.InvalidReact, reason: `Components and hooks cannot be created dynamically`, 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`, details: [ diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts index a0d06f96f0e..d4327147049 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts @@ -12,7 +12,6 @@ import { CompilerError, CompilerSuggestionOperation, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import {assertExhaustive} from '../Utils/utils'; import {GeneratedSource} from '../HIR'; @@ -186,7 +185,6 @@ export function suppressionsToCompilerError( CompilerDiagnostic.create({ reason: reason, 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()}\``, - severity: ErrorSeverity.InvalidReact, category: ErrorCategory.Suppression, suggestions: [ { diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/ValidateNoUntransformedReferences.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/ValidateNoUntransformedReferences.ts index beaaff0f79a..4f0b80ca918 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/ValidateNoUntransformedReferences.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/ValidateNoUntransformedReferences.ts @@ -8,7 +8,7 @@ import {NodePath} from '@babel/core'; import * as t from '@babel/types'; -import {CompilerError, EnvironmentConfig, ErrorSeverity, Logger} from '..'; +import {CompilerError, EnvironmentConfig, Logger} from '..'; import {getOrInsertWith} from '../Utils/utils'; import {Environment, GeneratedSource} from '../HIR'; import {DEFAULT_EXPORT} from '../HIR/Environment'; @@ -20,19 +20,15 @@ import { } from '../CompilerError'; function throwInvalidReact( - options: Omit, + options: CompilerDiagnosticOptions, {logger, filename}: TraversalState, ): never { - const detail: CompilerDiagnosticOptions = { - severity: ErrorSeverity.InvalidReact, - ...options, - }; logger?.logEvent(filename, { kind: 'CompileError', fnLoc: null, - detail: new CompilerDiagnostic(detail), + detail: new CompilerDiagnostic(options), }); - CompilerError.throwDiagnostic(detail); + CompilerError.throwDiagnostic(options); } function isAutodepsSigil( diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts index 77f2a04e7cf..457f54495f6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts @@ -13,7 +13,6 @@ import { CompilerError, CompilerSuggestionOperation, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import {Err, Ok, Result} from '../Utils/Result'; import {assertExhaustive, hasNode} from '../Utils/utils'; @@ -108,7 +107,6 @@ export function lower( if (binding.kind !== 'Identifier') { builder.errors.pushDiagnostic( CompilerDiagnostic.create({ - severity: ErrorSeverity.Invariant, category: ErrorCategory.Invariant, reason: 'Could not find binding', description: `[BuildHIR] Could not find binding for param \`${param.node.name}\`.`, @@ -173,7 +171,6 @@ export function lower( } else { builder.errors.pushDiagnostic( CompilerDiagnostic.create({ - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, reason: `Handle ${param.node.type} parameters`, description: `[BuildHIR] Add support for ${param.node.type} parameters.`, @@ -205,7 +202,6 @@ export function lower( } else { builder.errors.pushDiagnostic( CompilerDiagnostic.create({ - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, reason: `Unexpected function body kind`, description: `Expected function body to be an expression or a block statement, got \`${body.type}\`.`, @@ -276,7 +272,6 @@ function lowerStatement( builder.errors.push({ reason: '(BuildHIR::lowerStatement) Support ThrowStatement inside of try/catch', - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: stmt.node.loc ?? null, suggestions: null, @@ -464,7 +459,6 @@ function lowerStatement( kind = InstructionKind.HoistedFunction; } else if (!binding.path.isVariableDeclarator()) { builder.errors.push({ - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, reason: 'Unsupported declaration type for hoisting', description: `variable "${binding.identifier.name}" declared with ${binding.path.type}`, @@ -474,7 +468,6 @@ function lowerStatement( continue; } else { builder.errors.push({ - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, reason: 'Handle non-const declarations for hoisting', description: `variable "${binding.identifier.name}" declared with ${binding.kind}`, @@ -555,7 +548,6 @@ function lowerStatement( builder.errors.push({ reason: '(BuildHIR::lowerStatement) Handle non-variable initialization in ForStatement', - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: stmt.node.loc ?? null, suggestions: null, @@ -628,7 +620,6 @@ function lowerStatement( if (test.node == null) { builder.errors.push({ reason: `(BuildHIR::lowerStatement) Handle empty test in ForStatement`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: stmt.node.loc ?? null, suggestions: null, @@ -780,7 +771,6 @@ function lowerStatement( if (hasDefault) { builder.errors.push({ reason: `Expected at most one \`default\` branch in a switch statement, this code should have failed to parse`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: case_.node.loc ?? null, suggestions: null, @@ -853,7 +843,6 @@ function lowerStatement( if (nodeKind === 'var') { builder.errors.push({ reason: `(BuildHIR::lowerStatement) Handle ${nodeKind} kinds in VariableDeclaration`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: stmt.node.loc ?? null, suggestions: null, @@ -882,7 +871,6 @@ function lowerStatement( if (binding.kind !== 'Identifier') { builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Could not find binding for declaration.`, - severity: ErrorSeverity.Invariant, category: ErrorCategory.Invariant, loc: id.node.loc ?? null, suggestions: null, @@ -900,7 +888,6 @@ function lowerStatement( const declRangeStart = declaration.parentPath.node.start!; builder.errors.push({ reason: `Expect \`const\` declaration not to be reassigned`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: id.node.loc ?? null, suggestions: [ @@ -948,7 +935,6 @@ function lowerStatement( builder.errors.push({ reason: `Expected variable declaration to be an identifier if no initializer was provided`, description: `Got a \`${id.type}\``, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: stmt.node.loc ?? null, suggestions: null, @@ -1057,7 +1043,6 @@ function lowerStatement( if (stmt.node.await) { builder.errors.push({ reason: `(BuildHIR::lowerStatement) Handle for-await loops`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: stmt.node.loc ?? null, suggestions: null, @@ -1290,7 +1275,6 @@ function lowerStatement( if (!hasNode(handlerPath)) { builder.errors.push({ reason: `(BuildHIR::lowerStatement) Handle TryStatement without a catch clause`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: stmt.node.loc ?? null, suggestions: null, @@ -1300,7 +1284,6 @@ function lowerStatement( if (hasNode(stmt.get('finalizer'))) { builder.errors.push({ reason: `(BuildHIR::lowerStatement) Handle TryStatement with a finalizer ('finally') clause`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: stmt.node.loc ?? null, suggestions: null, @@ -1394,7 +1377,6 @@ function lowerStatement( builder.errors.push({ reason: `JavaScript 'with' syntax is not supported`, description: `'with' syntax is considered deprecated and removed from JavaScript standards, consider alternatives`, - severity: ErrorSeverity.UnsupportedJS, category: ErrorCategory.UnsupportedSyntax, loc: stmtPath.node.loc ?? null, suggestions: null, @@ -1415,7 +1397,6 @@ function lowerStatement( builder.errors.push({ reason: 'Inline `class` declarations are not supported', description: `Move class declarations outside of components/hooks`, - severity: ErrorSeverity.UnsupportedJS, category: ErrorCategory.UnsupportedSyntax, loc: stmtPath.node.loc ?? null, suggestions: null, @@ -1445,7 +1426,6 @@ function lowerStatement( builder.errors.push({ reason: 'JavaScript `import` and `export` statements may only appear at the top level of a module', - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: stmtPath.node.loc ?? null, suggestions: null, @@ -1461,7 +1441,6 @@ function lowerStatement( builder.errors.push({ reason: 'TypeScript `namespace` statements may only appear at the top level of a module', - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: stmtPath.node.loc ?? null, suggestions: null, @@ -1540,7 +1519,6 @@ function lowerObjectPropertyKey( */ builder.errors.push({ reason: `(BuildHIR::lowerExpression) Expected Identifier, got ${key.type} key in ObjectExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: key.node.loc ?? null, suggestions: null, @@ -1566,7 +1544,6 @@ function lowerObjectPropertyKey( builder.errors.push({ reason: `(BuildHIR::lowerExpression) Expected Identifier, got ${key.type} key in ObjectExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: key.node.loc ?? null, suggestions: null, @@ -1624,7 +1601,6 @@ function lowerExpression( if (!valuePath.isExpression()) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${valuePath.type} values in ObjectExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: valuePath.node.loc ?? null, suggestions: null, @@ -1651,7 +1627,6 @@ function lowerExpression( if (propertyPath.node.kind !== 'method') { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${propertyPath.node.kind} functions in ObjectExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: propertyPath.node.loc ?? null, suggestions: null, @@ -1673,7 +1648,6 @@ function lowerExpression( } else { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${propertyPath.type} properties in ObjectExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: propertyPath.node.loc ?? null, suggestions: null, @@ -1707,7 +1681,6 @@ function lowerExpression( } else { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${element.type} elements in ArrayExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: element.node.loc ?? null, suggestions: null, @@ -1728,7 +1701,6 @@ function lowerExpression( builder.errors.push({ reason: `Expected an expression as the \`new\` expression receiver (v8 intrinsics are not supported)`, description: `Got a \`${calleePath.node.type}\``, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: calleePath.node.loc ?? null, suggestions: null, @@ -1755,7 +1727,6 @@ function lowerExpression( if (!calleePath.isExpression()) { builder.errors.push({ 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`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: calleePath.node.loc ?? null, suggestions: null, @@ -1790,7 +1761,6 @@ function lowerExpression( if (!leftPath.isExpression()) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Expected Expression, got ${leftPath.type} lval in BinaryExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: leftPath.node.loc ?? null, suggestions: null, @@ -1803,7 +1773,6 @@ function lowerExpression( if (operator === '|>') { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Pipe operator not supported`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: leftPath.node.loc ?? null, suggestions: null, @@ -1833,7 +1802,6 @@ function lowerExpression( if (last === null) { builder.errors.push({ reason: `Expected sequence expression to have at least one expression`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: expr.node.loc ?? null, suggestions: null, @@ -2046,7 +2014,6 @@ function lowerExpression( builder.errors.push({ reason: `(BuildHIR::lowerExpression) Unsupported syntax on the left side of an AssignmentExpression`, description: `Expected an LVal, got: ${left.type}`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: left.node.loc ?? null, suggestions: null, @@ -2075,7 +2042,6 @@ function lowerExpression( if (binaryOperator == null) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${operator} operators in AssignmentExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: expr.node.loc ?? null, suggestions: null, @@ -2175,7 +2141,6 @@ function lowerExpression( default: { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Expected Identifier or MemberExpression, got ${expr.type} lval in AssignmentExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: expr.node.loc ?? null, suggestions: null, @@ -2215,7 +2180,6 @@ function lowerExpression( if (!attribute.isJSXAttribute()) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${attribute.type} attributes in JSXElement`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: attribute.node.loc ?? null, suggestions: null, @@ -2229,7 +2193,6 @@ function lowerExpression( if (propName.indexOf(':') !== -1) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Unexpected colon in attribute name \`${propName}\``, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: namePath.node.loc ?? null, suggestions: null, @@ -2260,7 +2223,6 @@ function lowerExpression( if (!valueExpr.isJSXExpressionContainer()) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${valueExpr.type} attribute values in JSXElement`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: valueExpr.node?.loc ?? null, suggestions: null, @@ -2271,7 +2233,6 @@ function lowerExpression( if (!expression.isExpression()) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${expression.type} expressions in JSXExpressionContainer within JSXElement`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: valueExpr.node.loc ?? null, suggestions: null, @@ -2329,8 +2290,7 @@ function lowerExpression( for (const [name, locations] of Object.entries(fbtLocations)) { if (locations.length > 1) { CompilerError.throwDiagnostic({ - severity: ErrorSeverity.Todo, - category: ErrorCategory.FBT, + category: ErrorCategory.Todo, reason: 'Support duplicate fbt tags', description: `Support \`<${tagName}>\` tags with multiple \`<${tagName}:${name}>\` values`, details: locations.map(loc => { @@ -2391,7 +2351,6 @@ function lowerExpression( builder.errors.push({ reason: '(BuildHIR::lowerExpression) Handle tagged template with interpolations', - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -2410,7 +2369,6 @@ function lowerExpression( builder.errors.push({ reason: '(BuildHIR::lowerExpression) Handle tagged template where cooked value is different from raw value', - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -2433,7 +2391,6 @@ function lowerExpression( if (subexprs.length !== quasis.length - 1) { builder.errors.push({ reason: `Unexpected quasi and subexpression lengths in template literal`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: exprPath.node.loc ?? null, suggestions: null, @@ -2444,7 +2401,6 @@ function lowerExpression( if (subexprs.some(e => !e.isExpression())) { builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Handle TSType in TemplateLiteral.`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -2487,7 +2443,6 @@ function lowerExpression( } else { builder.errors.push({ reason: `Only object properties can be deleted`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: expr.node.loc ?? null, suggestions: [ @@ -2503,7 +2458,6 @@ function lowerExpression( } else if (expr.node.operator === 'throw') { builder.errors.push({ reason: `Throw expressions are not supported`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: expr.node.loc ?? null, suggestions: [ @@ -2625,7 +2579,6 @@ function lowerExpression( if (!argument.isIdentifier()) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle UpdateExpression with ${argument.type} argument`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -2634,7 +2587,6 @@ function lowerExpression( } else if (builder.isContextIdentifier(argument)) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle UpdateExpression to variables captured within lambdas.`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -2655,7 +2607,6 @@ function lowerExpression( if (!builder.errors.hasErrors()) { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Found an invalid UpdateExpression without a previously reported error`, - severity: ErrorSeverity.Invariant, category: ErrorCategory.Invariant, loc: exprLoc, suggestions: null, @@ -2665,7 +2616,6 @@ function lowerExpression( } else if (lvalue.kind === 'Global') { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Support UpdateExpression where argument is a global`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprLoc, suggestions: null, @@ -2721,7 +2671,6 @@ function lowerExpression( builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle MetaProperty expressions other than import.meta`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -2731,7 +2680,6 @@ function lowerExpression( default: { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${exprPath.type} expressions`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -3029,7 +2977,6 @@ function lowerReorderableExpression( if (!isReorderableExpression(builder, expr, true)) { builder.errors.push({ reason: `(BuildHIR::node.lowerReorderableExpression) Expression type \`${expr.type}\` cannot be safely reordered`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: expr.node.loc ?? null, suggestions: null, @@ -3226,7 +3173,6 @@ function lowerArguments( } else { builder.errors.push({ reason: `(BuildHIR::lowerExpression) Handle ${argPath.type} arguments in CallExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: argPath.node.loc ?? null, suggestions: null, @@ -3262,7 +3208,6 @@ function lowerMemberExpression( } else { builder.errors.push({ reason: `(BuildHIR::lowerMemberExpression) Handle ${propertyNode.type} property`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: propertyNode.node.loc ?? null, suggestions: null, @@ -3284,7 +3229,6 @@ function lowerMemberExpression( if (!propertyNode.isExpression()) { builder.errors.push({ reason: `(BuildHIR::lowerMemberExpression) Expected Expression, got ${propertyNode.type} property`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: propertyNode.node.loc ?? null, suggestions: null, @@ -3344,7 +3288,6 @@ function lowerJsxElementName( builder.errors.push({ reason: `Expected JSXNamespacedName to have no colons in the namespace or name`, description: `Got \`${namespace}\` : \`${name}\``, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: exprPath.node.loc ?? null, suggestions: null, @@ -3359,7 +3302,6 @@ function lowerJsxElementName( } else { builder.errors.push({ reason: `(BuildHIR::lowerJsxElementName) Handle ${exprPath.type} tags`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -3458,7 +3400,6 @@ function lowerJsxElement( } else { builder.errors.push({ reason: `(BuildHIR::lowerJsxElement) Unhandled JsxElement, got: ${exprPath.type}`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: exprPath.node.loc ?? null, suggestions: null, @@ -3646,7 +3587,6 @@ function lowerIdentifier( reason: `The 'eval' function is not supported`, description: 'Eval is an anti-pattern in JavaScript, and the code executed cannot be evaluated by React Compiler', - severity: ErrorSeverity.UnsupportedJS, category: ErrorCategory.UnsupportedSyntax, loc: exprPath.node.loc ?? null, suggestions: null, @@ -3703,7 +3643,6 @@ function lowerIdentifierForAssignment( // Else its an internal error bc we couldn't find the binding builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Could not find binding for declaration.`, - severity: ErrorSeverity.Invariant, category: ErrorCategory.Invariant, loc: path.node.loc ?? null, suggestions: null, @@ -3716,7 +3655,6 @@ function lowerIdentifierForAssignment( ) { builder.errors.push({ reason: `Cannot reassign a \`const\` variable`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: path.node.loc ?? null, description: @@ -3774,7 +3712,6 @@ function lowerAssignment( if (kind === InstructionKind.Const && !isHoistedIdentifier) { builder.errors.push({ reason: `Expected \`const\` declaration not to be reassigned`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: lvalue.node.loc ?? null, suggestions: null, @@ -3789,7 +3726,6 @@ function lowerAssignment( ) { builder.errors.push({ reason: `Unexpected context variable kind`, - severity: ErrorSeverity.InvalidJS, category: ErrorCategory.Syntax, loc: lvalue.node.loc ?? null, suggestions: null, @@ -3861,7 +3797,6 @@ function lowerAssignment( } else { builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Handle ${property.type} properties in MemberExpression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: property.node.loc ?? null, suggestions: null, @@ -3874,7 +3809,6 @@ function lowerAssignment( builder.errors.push({ reason: '(BuildHIR::lowerAssignment) Expected private name to appear as a non-computed property', - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: property.node.loc ?? null, suggestions: null, @@ -3940,7 +3874,6 @@ function lowerAssignment( continue; } else if (identifier.kind === 'Global') { builder.errors.push({ - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, reason: 'Expected reassignment of globals to enable forceTemporaries', @@ -3980,7 +3913,6 @@ function lowerAssignment( continue; } else if (identifier.kind === 'Global') { builder.errors.push({ - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, reason: 'Expected reassignment of globals to enable forceTemporaries', @@ -4054,7 +3986,6 @@ function lowerAssignment( if (!argument.isIdentifier()) { builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Handle ${argument.node.type} rest element in ObjectPattern`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: argument.node.loc ?? null, suggestions: null, @@ -4086,7 +4017,6 @@ function lowerAssignment( continue; } else if (identifier.kind === 'Global') { builder.errors.push({ - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, reason: 'Expected reassignment of globals to enable forceTemporaries', @@ -4104,7 +4034,6 @@ function lowerAssignment( if (!property.isObjectProperty()) { builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Handle ${property.type} properties in ObjectPattern`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: property.node.loc ?? null, suggestions: null, @@ -4114,7 +4043,6 @@ function lowerAssignment( if (property.node.computed) { builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Handle computed properties in ObjectPattern`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: property.node.loc ?? null, suggestions: null, @@ -4129,7 +4057,6 @@ function lowerAssignment( if (!element.isLVal()) { builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Expected object property value to be an LVal, got: ${element.type}`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: element.node.loc ?? null, suggestions: null, @@ -4152,7 +4079,6 @@ function lowerAssignment( continue; } else if (identifier.kind === 'Global') { builder.errors.push({ - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, reason: 'Expected reassignment of globals to enable forceTemporaries', @@ -4302,7 +4228,6 @@ function lowerAssignment( default: { builder.errors.push({ reason: `(BuildHIR::lowerAssignment) Handle ${lvaluePath.type} assignments`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: lvaluePath.node.loc ?? null, suggestions: null, diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts index 78c756f812d..f60f123fb63 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts @@ -7,7 +7,7 @@ import {Binding, NodePath} from '@babel/traverse'; import * as t from '@babel/types'; -import {CompilerError, ErrorCategory, ErrorSeverity} from '../CompilerError'; +import {CompilerError, ErrorCategory} from '../CompilerError'; import {Environment} from './Environment'; import { BasicBlock, @@ -309,8 +309,7 @@ export default class HIRBuilder { resolveBinding(node: t.Identifier): Identifier { if (node.name === 'fbt') { CompilerError.throwDiagnostic({ - severity: ErrorSeverity.Todo, - category: ErrorCategory.FBT, + category: ErrorCategory.Todo, reason: 'Support local variables named `fbt`', description: 'Local variables named `fbt` may conflict with the fbt plugin and are not yet supported', @@ -325,7 +324,6 @@ export default class HIRBuilder { } if (node.name === 'this') { CompilerError.throwDiagnostic({ - severity: ErrorSeverity.UnsupportedJS, category: ErrorCategory.UnsupportedSyntax, reason: '`this` is not supported syntax', description: diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts index 412efcfe7ae..d17c754662d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts @@ -5,12 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import { - CompilerDiagnostic, - CompilerError, - ErrorSeverity, - SourceLocation, -} from '..'; +import {CompilerDiagnostic, CompilerError, SourceLocation} from '..'; import {ErrorCategory} from '../CompilerError'; import { CallExpression, @@ -302,7 +297,6 @@ function extractManualMemoizationArgs( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.UseMemo, - severity: ErrorSeverity.InvalidReact, reason: `Expected a callback function to be passed to ${kind}`, description: `Expected a callback function to be passed to ${kind}`, suggestions: null, @@ -318,7 +312,6 @@ function extractManualMemoizationArgs( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.UseMemo, - severity: ErrorSeverity.InvalidReact, reason: `Unexpected spread argument to ${kind}`, description: `Unexpected spread argument to ${kind}`, suggestions: null, @@ -339,7 +332,6 @@ function extractManualMemoizationArgs( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.UseMemo, - severity: ErrorSeverity.InvalidReact, reason: `Expected the dependency list for ${kind} to be an array literal`, description: `Expected the dependency list for ${kind} to be an array literal`, suggestions: null, @@ -358,7 +350,6 @@ function extractManualMemoizationArgs( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.UseMemo, - severity: ErrorSeverity.InvalidReact, reason: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`, description: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`, suggestions: null, @@ -463,7 +454,6 @@ export function dropManualMemoization( if (!hasNonVoidReturn(funcToCheck.loweredFunc.func)) { errors.pushDiagnostic( CompilerDiagnostic.create({ - severity: ErrorSeverity.InvalidReact, category: ErrorCategory.UseMemo, reason: 'useMemo() callbacks must return a value', description: `This ${ @@ -505,7 +495,6 @@ export function dropManualMemoization( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.UseMemo, - severity: ErrorSeverity.InvalidReact, reason: `Expected the first argument to be an inline function expression`, description: `Expected the first argument to be an inline function expression`, suggestions: [], diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts index a0e95932688..1f8db2c3c7d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts @@ -9,7 +9,6 @@ import { CompilerDiagnostic, CompilerError, Effect, - ErrorSeverity, SourceLocation, ValueKind, } from '..'; @@ -455,7 +454,6 @@ function applySignature( : 'value'; const diagnostic = CompilerDiagnostic.create({ category: ErrorCategory.Immutability, - severity: ErrorSeverity.InvalidReact, reason: 'This value cannot be modified', description: `${reason}.`, }).withDetail({ @@ -1040,7 +1038,6 @@ function applyEffect( ); const diagnostic = CompilerDiagnostic.create({ category: ErrorCategory.Immutability, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot access variable before it is declared', description: `${variable ?? 'This variable'} is accessed before it is declared, which prevents the earlier access from updating when this value changes over time.`, }); @@ -1080,7 +1077,6 @@ function applyEffect( : 'value'; const diagnostic = CompilerDiagnostic.create({ category: ErrorCategory.Immutability, - severity: ErrorSeverity.InvalidReact, reason: 'This value cannot be modified', description: `${reason}.`, }).withDetail({ @@ -2056,7 +2052,6 @@ function computeSignatureForInstruction( place: value.value, error: CompilerDiagnostic.create({ category: ErrorCategory.Globals, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot reassign variables declared outside of the component/hook', 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( place: receiver, error: CompilerDiagnostic.create({ category: ErrorCategory.Purity, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot call impure function during render', description: (signature.canonicalName != null @@ -2175,7 +2169,6 @@ function computeEffectsForLegacySignature( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.IncompatibleLibrary, - severity: ErrorSeverity.IncompatibleLibrary, reason: 'Use of incompatible library', description: [ 'This API returns functions which cannot be memoized without leading to stale UI. ' + diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts index c02a41f8f0a..5423f04843e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts @@ -13,7 +13,7 @@ import { pruneUnusedLabels, renameVariables, } from '.'; -import {CompilerError, ErrorCategory, ErrorSeverity} from '../CompilerError'; +import {CompilerError, ErrorCategory} from '../CompilerError'; import {Environment, ExternalFunction} from '../HIR'; import { ArrayPattern, @@ -2184,7 +2184,6 @@ function codegenInstructionValue( reason: `(CodegenReactiveFunction::codegenInstructionValue) Cannot declare variables in a value block, tried to declare '${ (declarator.id as t.Identifier).name }'`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: declarator.loc ?? null, suggestions: null, @@ -2193,7 +2192,6 @@ function codegenInstructionValue( } else { cx.errors.push({ reason: `(CodegenReactiveFunction::codegenInstructionValue) Handle conversion of ${stmt.type} to expression`, - severity: ErrorSeverity.Todo, category: ErrorCategory.Todo, loc: stmt.loc ?? null, suggestions: null, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts b/compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts index 393f95d94c4..c7c3a21cf98 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Transform/TransformFire.ts @@ -5,12 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import { - CompilerError, - CompilerErrorDetailOptions, - ErrorSeverity, - SourceLocation, -} from '..'; +import {CompilerError, CompilerErrorDetailOptions, SourceLocation} from '..'; import { ArrayExpression, CallExpression, @@ -133,7 +128,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void { context.pushError({ loc: value.loc, description: null, - severity: ErrorSeverity.Invariant, category: ErrorCategory.Invariant, reason: '[InsertFire] No LoadGlobal found for useEffect call', suggestions: null, @@ -180,7 +174,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void { loc: value.args[1].loc, description: 'You must use an array literal for an effect dependency array when that effect uses `fire()`', - severity: ErrorSeverity.Invariant, category: ErrorCategory.Fire, reason: CANNOT_COMPILE_FIRE, suggestions: null, @@ -191,7 +184,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void { loc: value.args[1].place.loc, description: 'You must use an array literal for an effect dependency array when that effect uses `fire()`', - severity: ErrorSeverity.Invariant, category: ErrorCategory.Fire, reason: CANNOT_COMPILE_FIRE, suggestions: null, @@ -226,7 +218,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void { context.pushError({ loc: value.loc, description: null, - severity: ErrorSeverity.Invariant, category: ErrorCategory.Invariant, reason: '[InsertFire] No loadLocal found for fire call argument', @@ -250,7 +241,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void { loc: value.loc, description: '`fire()` can only receive a function call such as `fire(fn(a,b)). Method calls and other expressions are not allowed', - severity: ErrorSeverity.InvalidReact, category: ErrorCategory.Fire, reason: CANNOT_COMPILE_FIRE, suggestions: null, @@ -269,7 +259,6 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void { context.pushError({ loc: value.loc, description, - severity: ErrorSeverity.InvalidReact, category: ErrorCategory.Fire, reason: CANNOT_COMPILE_FIRE, suggestions: null, @@ -401,7 +390,6 @@ function ensureNoRemainingCalleeCaptures( description: `All uses of ${calleeName} must be either used with a fire() call in \ this effect or not used with a fire() call at all. ${calleeName} was used with fire() on line \ ${printSourceLocationLine(calleeInfo.fireLoc)} in this effect`, - severity: ErrorSeverity.InvalidReact, category: ErrorCategory.Fire, reason: CANNOT_COMPILE_FIRE, suggestions: null, @@ -420,7 +408,6 @@ function ensureNoMoreFireUses(fn: HIRFunction, context: Context): void { loc: place.identifier.loc, description: 'Cannot use `fire` outside of a useEffect function', category: ErrorCategory.Fire, - severity: ErrorSeverity.Invariant, reason: CANNOT_COMPILE_FIRE, suggestions: null, }); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateHooksUsage.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateHooksUsage.ts index af596155253..7259041ec29 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateHooksUsage.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateHooksUsage.ts @@ -10,7 +10,6 @@ import { CompilerError, CompilerErrorDetail, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import {computeUnconditionalBlocks} from '../HIR/ComputeUnconditionalBlocks'; import {isHookName} from '../HIR/Environment'; @@ -129,7 +128,6 @@ export function validateHooksUsage( description: null, reason, loc: place.loc, - severity: ErrorSeverity.InvalidReact, suggestions: null, }), ); @@ -147,7 +145,6 @@ export function validateHooksUsage( reason: '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', loc: place.loc, - severity: ErrorSeverity.InvalidReact, suggestions: null, }), ); @@ -165,7 +162,6 @@ export function validateHooksUsage( reason: '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', loc: place.loc, - severity: ErrorSeverity.InvalidReact, suggestions: null, }), ); @@ -453,7 +449,6 @@ function visitFunctionExpression(errors: CompilerError, fn: HIRFunction): void { errors.pushErrorDetail( new CompilerErrorDetail({ category: ErrorCategory.Hooks, - severity: ErrorSeverity.InvalidReact, reason: '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)', loc: callee.loc, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateLocalsNotReassignedAfterRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateLocalsNotReassignedAfterRender.ts index e1ed71049df..c70a2f0158c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateLocalsNotReassignedAfterRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateLocalsNotReassignedAfterRender.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {CompilerDiagnostic, CompilerError, Effect, ErrorSeverity} from '..'; +import {CompilerDiagnostic, CompilerError, Effect} from '..'; import {ErrorCategory} from '../CompilerError'; import {HIRFunction, IdentifierId, Place} from '../HIR'; import { @@ -38,7 +38,6 @@ export function validateLocalsNotReassignedAfterRender(fn: HIRFunction): void { errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Immutability, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot reassign variable after render completes', description: `Reassigning ${variable} after render has completed can cause inconsistent behavior on subsequent renders. Consider using state instead.`, }).withDetail({ @@ -94,7 +93,6 @@ function getContextReassignment( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Immutability, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot reassign variable in async function', description: 'Reassigning a variable in an async function can cause inconsistent behavior on subsequent renders. Consider using state instead', diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateMemoizedEffectDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateMemoizedEffectDependencies.ts index 186641c3f20..15d0be57fcf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateMemoizedEffectDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateMemoizedEffectDependencies.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {CompilerError, ErrorSeverity} from '..'; +import {CompilerError} from '..'; import {ErrorCategory} from '../CompilerError'; import { Identifier, @@ -113,7 +113,6 @@ class Visitor extends ReactiveFunctionVisitor { reason: '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', description: null, - severity: ErrorSeverity.CannotPreserveMemoization, loc: typeof instruction.loc !== 'symbol' ? instruction.loc : null, suggestions: null, }); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoCapitalizedCalls.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoCapitalizedCalls.ts index d0cf41a13c4..97ca536a971 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoCapitalizedCalls.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoCapitalizedCalls.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {CompilerError, EnvironmentConfig, ErrorSeverity} from '..'; +import {CompilerError, EnvironmentConfig} from '..'; import {ErrorCategory} from '../CompilerError'; import {HIRFunction, IdentifierId} from '../HIR'; import {DEFAULT_GLOBALS} from '../HIR/Globals'; @@ -82,7 +82,6 @@ export function validateNoCapitalizedCalls( if (propertyName != null) { errors.push({ category: ErrorCategory.CapitalizedCalls, - severity: ErrorSeverity.InvalidReact, reason, description: `${propertyName} may be a component.`, loc: value.loc, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects.ts index f1fa5aec407..b911c0f4c7f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoDerivedComputationsInEffects.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {CompilerError, ErrorSeverity, SourceLocation} from '..'; +import {CompilerError, SourceLocation} from '..'; import {ErrorCategory} from '../CompilerError'; import { ArrayExpression, @@ -224,7 +224,6 @@ function validateEffect( reason: '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)', description: null, - severity: ErrorSeverity.InvalidReact, loc, suggestions: null, }); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoFreezingKnownMutableFunctions.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoFreezingKnownMutableFunctions.ts index f49a9a0a475..286c9765309 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoFreezingKnownMutableFunctions.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoFreezingKnownMutableFunctions.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {CompilerDiagnostic, CompilerError, Effect, ErrorSeverity} from '..'; +import {CompilerDiagnostic, CompilerError, Effect} from '..'; import {ErrorCategory} from '../CompilerError'; import { HIRFunction, @@ -66,7 +66,6 @@ export function validateNoFreezingKnownMutableFunctions( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Immutability, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot modify local variables after render completes', 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.`, }) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoImpureFunctionsInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoImpureFunctionsInRender.ts index 868352e050e..82a42ac7256 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoImpureFunctionsInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoImpureFunctionsInRender.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {CompilerDiagnostic, CompilerError, ErrorSeverity} from '..'; +import {CompilerDiagnostic, CompilerError} from '..'; import {ErrorCategory} from '../CompilerError'; import {HIRFunction} from '../HIR'; import {getFunctionCallSignature} from '../Inference/InferMutationAliasingEffects'; @@ -44,7 +44,6 @@ export function validateNoImpureFunctionsInRender( ? `\`${signature.canonicalName}\` is an impure function. ` : '') + '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)', - severity: ErrorSeverity.InvalidReact, suggestions: null, }).withDetail({ kind: 'error', diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoJSXInTryStatement.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoJSXInTryStatement.ts index 158935f9e6e..8c9aaa82053 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoJSXInTryStatement.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoJSXInTryStatement.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {CompilerDiagnostic, CompilerError, ErrorSeverity} from '..'; +import {CompilerDiagnostic, CompilerError} from '..'; import {ErrorCategory} from '../CompilerError'; import {BlockId, HIRFunction} from '../HIR'; import {Result} from '../Utils/Result'; @@ -38,7 +38,6 @@ export function validateNoJSXInTryStatement( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.ErrorBoundaries, - severity: ErrorSeverity.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)`, }).withDetail({ diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts index 679d355e321..2e2742611a6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccessInRender.ts @@ -9,7 +9,6 @@ import { CompilerDiagnostic, CompilerError, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import { BlockId, @@ -470,7 +469,6 @@ function validateNoRefAccessInRenderImpl( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Refs, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot access refs during render', description: ERROR_DESCRIPTION, }).withDetail({ @@ -734,7 +732,6 @@ function guardCheck(errors: CompilerError, operand: Place, env: Env): void { errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Refs, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot access refs during render', description: ERROR_DESCRIPTION, }).withDetail({ @@ -759,7 +756,6 @@ function validateNoRefValueAccess( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Refs, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot access refs during render', description: ERROR_DESCRIPTION, }).withDetail({ @@ -786,7 +782,6 @@ function validateNoRefPassedToFunction( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Refs, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot access refs during render', description: ERROR_DESCRIPTION, }).withDetail({ @@ -809,7 +804,6 @@ function validateNoRefUpdate( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Refs, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot access refs during render', description: ERROR_DESCRIPTION, }).withDetail({ @@ -831,7 +825,6 @@ function validateNoDirectRefValueAccess( errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.Refs, - severity: ErrorSeverity.InvalidReact, reason: 'Cannot access refs during render', description: ERROR_DESCRIPTION, }).withDetail({ diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInEffects.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInEffects.ts index 4a24098a9fe..32f49a5e313 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInEffects.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInEffects.ts @@ -9,7 +9,6 @@ import { CompilerDiagnostic, CompilerError, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import { HIRFunction, @@ -107,7 +106,6 @@ export function validateNoSetStateInEffects( '* Subscribe for updates from some external system, calling setState in a callback function when external state changes.\n\n' + 'Calling 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: ErrorSeverity.InvalidReact, suggestions: null, }).withDetail({ kind: 'error', diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInRender.ts index 2ee9ab64b7e..dcd1882f198 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoSetStateInRender.ts @@ -9,7 +9,6 @@ import { CompilerDiagnostic, CompilerError, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import {HIRFunction, IdentifierId, isSetStateType} from '../HIR'; import {computeUnconditionalBlocks} from '../HIR/ComputeUnconditionalBlocks'; @@ -134,7 +133,6 @@ function validateNoSetStateInRenderImpl( 'Calling setState from useMemo may trigger an infinite loop', description: '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)', - severity: ErrorSeverity.InvalidReact, suggestions: null, }).withDetail({ kind: 'error', @@ -150,7 +148,6 @@ function validateNoSetStateInRenderImpl( 'Calling setState during render may trigger an infinite loop', description: 'Calling setState during render will trigger another render, and can lead to infinite loops. (https://react.dev/reference/react/useState)', - severity: ErrorSeverity.InvalidReact, suggestions: null, }).withDetail({ kind: 'error', diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts index 624cf382b7d..d6d52eda79f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts @@ -9,7 +9,6 @@ import { CompilerDiagnostic, CompilerError, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import { DeclarationId, @@ -283,7 +282,6 @@ function validateInferredDep( errorState.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.PreserveManualMemo, - severity: ErrorSeverity.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. ', @@ -537,7 +535,6 @@ class Visitor extends ReactiveFunctionVisitor { state.errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.PreserveManualMemo, - severity: ErrorSeverity.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. ', @@ -585,7 +582,6 @@ class Visitor extends ReactiveFunctionVisitor { state.errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.PreserveManualMemo, - severity: ErrorSeverity.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. This value was memoized in source but not in compilation output. ', diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateStaticComponents.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateStaticComponents.ts index 375b8e8f011..4d37febd47f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateStaticComponents.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateStaticComponents.ts @@ -9,7 +9,6 @@ import { CompilerDiagnostic, CompilerError, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import {HIRFunction, IdentifierId, SourceLocation} from '../HIR'; import {Result} from '../Utils/Result'; @@ -67,7 +66,6 @@ export function validateStaticComponents( error.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.StaticComponents, - severity: ErrorSeverity.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. `, }) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateUseMemo.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateUseMemo.ts index 3146bbea38a..f13c310354b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateUseMemo.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateUseMemo.ts @@ -9,7 +9,6 @@ import { CompilerDiagnostic, CompilerError, ErrorCategory, - ErrorSeverity, } from '../CompilerError'; import {FunctionExpression, HIRFunction, IdentifierId} from '../HIR'; import {Result} from '../Utils/Result'; @@ -76,7 +75,6 @@ export function validateUseMemo(fn: HIRFunction): Result { errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.UseMemo, - severity: ErrorSeverity.InvalidReact, reason: 'useMemo() callbacks may not accept parameters', description: '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 { errors.pushDiagnostic( CompilerDiagnostic.create({ category: ErrorCategory.UseMemo, - severity: ErrorSeverity.InvalidReact, reason: 'useMemo() callbacks may not be async or generator functions', description: diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/Logger-test.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/Logger-test.ts index 096b723554f..ca386fb2402 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/Logger-test.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/Logger-test.ts @@ -56,7 +56,7 @@ it('logs failed compilation', () => { expect(event.kind).toEqual('CompileError'); invariant(event.kind === 'CompileError', 'typescript be smarter'); - expect(event.detail.severity).toEqual('InvalidReact'); + expect(event.detail.severity).toEqual('Error'); //@ts-ignore const {start, end, identifierName} = event.detail.primaryLocation() as t.SourceLocation; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.expect.md index 986fb8a5b26..4aa65bbfe45 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ecma/error.reserved-words.expect.md @@ -24,7 +24,7 @@ function useThing(fn) { ``` Found 1 error: -Error: `this` is not supported syntax +Compilation Skipped: `this` is not supported syntax React Compiler does not support compiling functions that use `this` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-eval-unsupported.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-eval-unsupported.expect.md index d01aeeb1d48..d766bc03b21 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-eval-unsupported.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-eval-unsupported.expect.md @@ -15,7 +15,7 @@ function Component(props) { ``` Found 1 error: -Error: The 'eval' function is not supported +Compilation Skipped: The 'eval' function is not supported Eval is an anti-pattern in JavaScript, and the code executed cannot be evaluated by React Compiler. diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md index a4d3525757b..32db5b2e7ca 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.expect.md @@ -92,7 +92,7 @@ error.todo-kitchensink.ts:3:2 5 | class Bar { 6 | #secretSauce = 42; -Error: Inline `class` declarations are not supported +Compilation Skipped: Inline `class` declarations are not supported Move class declarations outside of components/hooks. diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-bailout-nopanic.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-bailout-nopanic.expect.md index bb0172c56f8..79e07e0d8b3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-bailout-nopanic.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-bailout-nopanic.expect.md @@ -58,7 +58,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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"}]}}} +{"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"}]}}} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-invalid-multiple.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-invalid-multiple.expect.md index 7f8f1d43310..4650588cc47 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-invalid-multiple.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-invalid-multiple.expect.md @@ -38,7 +38,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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"}}}} +{"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"}}}} ``` ### Eval output diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-optional-chain.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-optional-chain.expect.md index 14bd646bb15..4a97e16c7c8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-optional-chain.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-optional-chain.expect.md @@ -48,7 +48,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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"}]}}} +{"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"}]}}} {"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"}]} {"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} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-ref-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-ref-access.expect.md index 2f930964acd..ea5a887b8bf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-ref-access.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect-ref-access.expect.md @@ -47,7 +47,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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"}]}}} +{"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"}]}}} {"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"}]} {"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} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect.expect.md index 9a8a2a78e06..a0d77507e92 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/bailout-retry/mutate-after-useeffect.expect.md @@ -47,7 +47,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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"}]}}} +{"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"}]}}} {"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"}]} {"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} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/no-emit/retry-no-emit.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/no-emit/retry-no-emit.expect.md index 7ecd65382cc..0a4d7a5b131 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/no-emit/retry-no-emit.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/no-emit/retry-no-emit.expect.md @@ -54,7 +54,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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"}]}}} +{"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"}]}}} {"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"}]} {"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"}]} {"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} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.expect.md index 5c7c4360e7c..5eaa1fd5040 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-catch-in-outer-try-with-catch.expect.md @@ -65,7 +65,7 @@ function Component(props) { ## Logs ``` -{"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} +{"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} {"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} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.expect.md index 88d4849b4f6..323aedd869d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-jsx-in-try-with-catch.expect.md @@ -42,7 +42,7 @@ function Component(props) { ## Logs ``` -{"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} +{"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} {"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} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.expect.md index 9107c896cc0..6e5762f3c88 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect-transitive.expect.md @@ -65,7 +65,7 @@ function _temp(s) { ## Logs ``` -{"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} +{"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} {"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} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.expect.md index cb5203c8816..3c3a5a8053a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/invalid-setState-in-useEffect.expect.md @@ -45,7 +45,7 @@ function _temp(s) { ## Logs ``` -{"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} +{"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} {"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} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.expect.md index 6a9b4d98e28..7b26f3a12d9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-optional-chain.expect.md @@ -48,7 +48,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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"}]}}} +{"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"}]}}} {"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"}]} {"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} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.expect.md index 00473c8eec7..acf9c28cabd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect-ref-access.expect.md @@ -47,7 +47,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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"}]}}} +{"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"}]}}} {"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"}]} {"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} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.expect.md index 825bc4a1df0..d78691790bc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/mutate-after-useeffect.expect.md @@ -47,7 +47,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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"}]}}} +{"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"}]}}} {"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"}]} {"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} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.expect.md index 7d490de8c6a..227ae911b66 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.expect.md @@ -54,7 +54,7 @@ export const FIXTURE_ENTRYPOINT = { ## Logs ``` -{"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"}]}}} +{"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"}]}}} {"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"}]} {"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"}]} {"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} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.expect.md index c0cac509c88..cf57e8143b2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-conditionally-assigned-dynamically-constructed-component-in-render.expect.md @@ -50,7 +50,7 @@ function Example(props) { ## Logs ``` -{"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} +{"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} {"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} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.expect.md index 337997caa59..111d47c0a14 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-construct-component-in-render.expect.md @@ -32,7 +32,7 @@ function Example(props) { ## Logs ``` -{"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} +{"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} {"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} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.expect.md index 019beccdc86..5b9cf90db34 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-function.expect.md @@ -37,7 +37,7 @@ function Example(props) { ## Logs ``` -{"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} +{"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} {"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} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.expect.md index f673b277798..9b87839f7f2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-method-call.expect.md @@ -41,7 +41,7 @@ function Example(props) { ## Logs ``` -{"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} +{"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} {"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} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.expect.md index a44cf6a9f0e..a78825ba872 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/static-components/invalid-dynamically-constructed-component-new.expect.md @@ -32,7 +32,7 @@ function Example(props) { ## Logs ``` -{"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} +{"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} {"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} ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-outside-effect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-outside-effect.expect.md index 81c36a362cf..cdb0726f2e1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-outside-effect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-outside-effect.expect.md @@ -26,7 +26,7 @@ function Component({props, bar}) { ``` Found 2 errors: -Invariant: Cannot compile `fire` +Error: Cannot compile `fire` Cannot use `fire` outside of a useEffect function. @@ -39,7 +39,7 @@ error.invalid-outside-effect.ts:8:2 10 | useCallback(() => { 11 | fire(foo(props)); -Invariant: Cannot compile `fire` +Error: Cannot compile `fire` Cannot use `fire` outside of a useEffect function. diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-no-array-literal.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-no-array-literal.expect.md index 96cea9c08f0..d82f1ee1b22 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-no-array-literal.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-no-array-literal.expect.md @@ -27,7 +27,7 @@ function Component(props) { ``` Found 1 error: -Invariant: Cannot compile `fire` +Error: Cannot compile `fire` You must use an array literal for an effect dependency array when that effect uses `fire()`. diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-spread.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-spread.expect.md index 4dc5336ebe0..a8418136302 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-spread.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/transform-fire/error.invalid-rewrite-deps-spread.expect.md @@ -30,7 +30,7 @@ function Component(props) { ``` Found 1 error: -Invariant: Cannot compile `fire` +Error: Cannot compile `fire` You must use an array literal for an effect dependency array when that effect uses `fire()`. diff --git a/compiler/packages/eslint-plugin-react-compiler/__tests__/ImpureFunctionCallsRule-test.ts b/compiler/packages/eslint-plugin-react-compiler/__tests__/ImpureFunctionCallsRule-test.ts index a745397078a..f89b049d100 100644 --- a/compiler/packages/eslint-plugin-react-compiler/__tests__/ImpureFunctionCallsRule-test.ts +++ b/compiler/packages/eslint-plugin-react-compiler/__tests__/ImpureFunctionCallsRule-test.ts @@ -14,7 +14,7 @@ import {allRules} from '../src/rules/ReactCompilerRule'; testRule( 'no impure function calls rule', - allRules[getRuleForCategory(ErrorCategory.Purity).name], + allRules[getRuleForCategory(ErrorCategory.Purity).name].rule, { valid: [], invalid: [ diff --git a/compiler/packages/eslint-plugin-react-compiler/__tests__/InvalidHooksRule-test.ts b/compiler/packages/eslint-plugin-react-compiler/__tests__/InvalidHooksRule-test.ts index 0ba165011c6..1fd88935575 100644 --- a/compiler/packages/eslint-plugin-react-compiler/__tests__/InvalidHooksRule-test.ts +++ b/compiler/packages/eslint-plugin-react-compiler/__tests__/InvalidHooksRule-test.ts @@ -14,7 +14,7 @@ import {allRules} from '../src/rules/ReactCompilerRule'; testRule( 'rules-of-hooks', - allRules[getRuleForCategory(ErrorCategory.Hooks).name], + allRules[getRuleForCategory(ErrorCategory.Hooks).name].rule, { valid: [ { diff --git a/compiler/packages/eslint-plugin-react-compiler/__tests__/NoAmbiguousJsxRule-test.ts b/compiler/packages/eslint-plugin-react-compiler/__tests__/NoAmbiguousJsxRule-test.ts index 9a09f4c4e05..bb6f4b93b88 100644 --- a/compiler/packages/eslint-plugin-react-compiler/__tests__/NoAmbiguousJsxRule-test.ts +++ b/compiler/packages/eslint-plugin-react-compiler/__tests__/NoAmbiguousJsxRule-test.ts @@ -14,7 +14,7 @@ import {allRules} from '../src/rules/ReactCompilerRule'; testRule( 'no ambiguous JSX rule', - allRules[getRuleForCategory(ErrorCategory.ErrorBoundaries).name], + allRules[getRuleForCategory(ErrorCategory.ErrorBoundaries).name].rule, { valid: [], invalid: [ diff --git a/compiler/packages/eslint-plugin-react-compiler/__tests__/NoCapitalizedCallsRule-test.ts b/compiler/packages/eslint-plugin-react-compiler/__tests__/NoCapitalizedCallsRule-test.ts index c361670e974..5b45a70fa1d 100644 --- a/compiler/packages/eslint-plugin-react-compiler/__tests__/NoCapitalizedCallsRule-test.ts +++ b/compiler/packages/eslint-plugin-react-compiler/__tests__/NoCapitalizedCallsRule-test.ts @@ -13,7 +13,7 @@ import {allRules} from '../src/rules/ReactCompilerRule'; testRule( 'no-capitalized-calls', - allRules[getRuleForCategory(ErrorCategory.CapitalizedCalls).name], + allRules[getRuleForCategory(ErrorCategory.CapitalizedCalls).name].rule, { valid: [], invalid: [ diff --git a/compiler/packages/eslint-plugin-react-compiler/__tests__/NoRefAccessInRender-tests.ts b/compiler/packages/eslint-plugin-react-compiler/__tests__/NoRefAccessInRender-tests.ts index 9042980a807..9953c8c2136 100644 --- a/compiler/packages/eslint-plugin-react-compiler/__tests__/NoRefAccessInRender-tests.ts +++ b/compiler/packages/eslint-plugin-react-compiler/__tests__/NoRefAccessInRender-tests.ts @@ -14,7 +14,7 @@ import {allRules} from '../src/rules/ReactCompilerRule'; testRule( 'no ref access in render rule', - allRules[getRuleForCategory(ErrorCategory.Refs).name], + allRules[getRuleForCategory(ErrorCategory.Refs).name].rule, { valid: [], invalid: [ diff --git a/compiler/packages/eslint-plugin-react-compiler/__tests__/shared-utils.ts b/compiler/packages/eslint-plugin-react-compiler/__tests__/shared-utils.ts index 2ab24581d8d..b0523f522c9 100644 --- a/compiler/packages/eslint-plugin-react-compiler/__tests__/shared-utils.ts +++ b/compiler/packages/eslint-plugin-react-compiler/__tests__/shared-utils.ts @@ -61,10 +61,10 @@ export const TestRecommendedRules: Rule.RuleModule = { schema: [{type: 'object', additionalProperties: true}], }, create(context) { - for (const rule of Object.values( + for (const ruleConfig of Object.values( configs.recommended.plugins['react-compiler'].rules, )) { - const listener = rule.create(context); + const listener = ruleConfig.rule.create(context); if (Object.entries(listener).length !== 0) { throw new Error('TODO: handle rules that return listeners to eslint'); } diff --git a/compiler/packages/eslint-plugin-react-compiler/src/index.ts b/compiler/packages/eslint-plugin-react-compiler/src/index.ts index 1a339e83310..9d49b16c57e 100644 --- a/compiler/packages/eslint-plugin-react-compiler/src/index.ts +++ b/compiler/packages/eslint-plugin-react-compiler/src/index.ts @@ -5,7 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -import {allRules, recommendedRules} from './rules/ReactCompilerRule'; +import {type Linter} from 'eslint'; +import { + allRules, + mapErrorSeverityToESlint, + recommendedRules, +} from './rules/ReactCompilerRule'; const meta = { name: 'eslint-plugin-react-compiler', @@ -19,11 +24,13 @@ const configs = { }, }, rules: Object.fromEntries( - Object.keys(recommendedRules).map(ruleName => [ - 'react-compiler/' + ruleName, - 'error', - ]), - ) as Record, + Object.entries(recommendedRules).map(([name, ruleConfig]) => { + return [ + 'react-compiler/' + name, + mapErrorSeverityToESlint(ruleConfig.severity), + ]; + }), + ) as Record, }, }; diff --git a/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts b/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts index d2e8fdd42e0..3eb6dfa0c71 100644 --- a/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts +++ b/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts @@ -11,9 +11,10 @@ import { CompilerErrorDetailOptions, CompilerSuggestionOperation, } from 'babel-plugin-react-compiler/src'; -import type {Rule} from 'eslint'; +import type {Linter, Rule} from 'eslint'; import runReactCompiler, {RunCacheEntry} from '../shared/RunReactCompiler'; import { + ErrorSeverity, LintRules, type LintRule, } from 'babel-plugin-react-compiler/src/CompilerError'; @@ -192,26 +193,54 @@ export const NoUnusedDirectivesRule: Rule.RuleModule = { }, }; -type RulesObject = {[name: string]: Rule.RuleModule}; +type RulesConfig = { + [name: string]: {rule: Rule.RuleModule; severity: ErrorSeverity}; +}; -export const allRules: RulesObject = LintRules.reduce( +export const allRules: RulesConfig = LintRules.reduce( (acc, rule) => { - acc[rule.name] = makeRule(rule); + acc[rule.name] = {rule: makeRule(rule), severity: rule.severity}; return acc; }, { - 'no-unused-directives': NoUnusedDirectivesRule, - } as RulesObject, + 'no-unused-directives': { + rule: NoUnusedDirectivesRule, + severity: ErrorSeverity.Error, + }, + } as RulesConfig, ); -export const recommendedRules: RulesObject = LintRules.filter( +export const recommendedRules: RulesConfig = LintRules.filter( rule => rule.recommended, ).reduce( (acc, rule) => { - acc[rule.name] = makeRule(rule); + acc[rule.name] = {rule: makeRule(rule), severity: rule.severity}; return acc; }, { - 'no-unused-directives': NoUnusedDirectivesRule, - } as RulesObject, + 'no-unused-directives': { + rule: NoUnusedDirectivesRule, + severity: ErrorSeverity.Error, + }, + } as RulesConfig, ); + +export function mapErrorSeverityToESlint( + severity: ErrorSeverity, +): Linter.StringSeverity { + switch (severity) { + case ErrorSeverity.Error: { + return 'error'; + } + case ErrorSeverity.Warning: { + return 'warn'; + } + case ErrorSeverity.Hint: + case ErrorSeverity.Off: { + return 'off'; + } + default: { + assertExhaustive(severity, `Unhandled severity: ${severity}`); + } + } +} diff --git a/compiler/scripts/build-eslint-docs.js b/compiler/scripts/build-eslint-docs.js index d8d59096d9e..f4e411590e8 100644 --- a/compiler/scripts/build-eslint-docs.js +++ b/compiler/scripts/build-eslint-docs.js @@ -19,12 +19,14 @@ const combinedRules = [ ]; const printed = combinedRules - .filter(rule => rule.recommended) - .map(rule => { + .filter( + ruleConfig => ruleConfig.rule.recommended && ruleConfig.severity !== 'Off' + ) + .map(ruleConfig => { return ` -## \`react-hooks/${rule.name}\` +## \`react-hooks/${ruleConfig.rule.name}\` -${rule.description} +${ruleConfig.rule.description} `.trim(); }) .join('\n\n'); diff --git a/packages/eslint-plugin-react-hooks/__tests__/ReactCompilerRuleTypescript-test.ts b/packages/eslint-plugin-react-hooks/__tests__/ReactCompilerRuleTypescript-test.ts index d9385bdba43..1da7be666af 100644 --- a/packages/eslint-plugin-react-hooks/__tests__/ReactCompilerRuleTypescript-test.ts +++ b/packages/eslint-plugin-react-hooks/__tests__/ReactCompilerRuleTypescript-test.ts @@ -74,4 +74,4 @@ const tests: CompilerTestCases = { const eslintTester = new ESLintTesterV8({ parser: require.resolve('@typescript-eslint/parser-v5'), }); -eslintTester.run('react-compiler', allRules['immutability'], tests); +eslintTester.run('react-compiler', allRules['immutability'].rule, tests); diff --git a/packages/eslint-plugin-react-hooks/src/index.ts b/packages/eslint-plugin-react-hooks/src/index.ts index 462c3104a70..65cb030d006 100644 --- a/packages/eslint-plugin-react-hooks/src/index.ts +++ b/packages/eslint-plugin-react-hooks/src/index.ts @@ -7,22 +7,34 @@ import type {Linter, Rule} from 'eslint'; import ExhaustiveDeps from './rules/ExhaustiveDeps'; -import {allRules, recommendedRules} from './shared/ReactCompiler'; +import { + allRules, + mapErrorSeverityToESlint, + recommendedRules, +} from './shared/ReactCompiler'; import RulesOfHooks from './rules/RulesOfHooks'; // All rules const rules = { 'exhaustive-deps': ExhaustiveDeps, 'rules-of-hooks': RulesOfHooks, - ...allRules, + ...Object.fromEntries( + Object.entries(allRules).map(([name, config]) => [name, config.rule]) + ), } satisfies Record; // Config rules const ruleConfigs = { 'react-hooks/rules-of-hooks': 'error', 'react-hooks/exhaustive-deps': 'warn', + // Compiler rules ...Object.fromEntries( - Object.keys(recommendedRules).map(name => ['react-hooks/' + name, 'error']), + Object.entries(recommendedRules).map(([name, ruleConfig]) => { + return [ + 'react-hooks/' + name, + mapErrorSeverityToESlint(ruleConfig.severity), + ]; + }), ), } satisfies Linter.RulesRecord; diff --git a/packages/eslint-plugin-react-hooks/src/shared/ReactCompiler.ts b/packages/eslint-plugin-react-hooks/src/shared/ReactCompiler.ts index f006b797817..dec46457cce 100644 --- a/packages/eslint-plugin-react-hooks/src/shared/ReactCompiler.ts +++ b/packages/eslint-plugin-react-hooks/src/shared/ReactCompiler.ts @@ -13,8 +13,9 @@ import { CompilerSuggestionOperation, LintRules, type LintRule, + ErrorSeverity, } from 'babel-plugin-react-compiler'; -import type {Rule} from 'eslint'; +import {type Linter, type Rule} from 'eslint'; import runReactCompiler, {RunCacheEntry} from './RunReactCompiler'; function assertExhaustive(_: never, errorMsg: string): never { @@ -191,26 +192,54 @@ export const NoUnusedDirectivesRule: Rule.RuleModule = { }, }; -type RulesObject = {[name: string]: Rule.RuleModule}; +type RulesConfig = { + [name: string]: {rule: Rule.RuleModule; severity: ErrorSeverity}; +}; -export const allRules: RulesObject = LintRules.reduce( +export const allRules: RulesConfig = LintRules.reduce( (acc, rule) => { - acc[rule.name] = makeRule(rule); + acc[rule.name] = {rule: makeRule(rule), severity: rule.severity}; return acc; }, { - 'no-unused-directives': NoUnusedDirectivesRule, - } as RulesObject, + 'no-unused-directives': { + rule: NoUnusedDirectivesRule, + severity: ErrorSeverity.Error, + }, + } as RulesConfig, ); -export const recommendedRules: RulesObject = LintRules.filter( +export const recommendedRules: RulesConfig = LintRules.filter( rule => rule.recommended, ).reduce( (acc, rule) => { - acc[rule.name] = makeRule(rule); + acc[rule.name] = {rule: makeRule(rule), severity: rule.severity}; return acc; }, { - 'no-unused-directives': NoUnusedDirectivesRule, - } as RulesObject, + 'no-unused-directives': { + rule: NoUnusedDirectivesRule, + severity: ErrorSeverity.Error, + }, + } as RulesConfig, ); + +export function mapErrorSeverityToESlint( + severity: ErrorSeverity, +): Linter.StringSeverity { + switch (severity) { + case ErrorSeverity.Error: { + return 'error'; + } + case ErrorSeverity.Warning: { + return 'warn'; + } + case ErrorSeverity.Hint: + case ErrorSeverity.Off: { + return 'off'; + } + default: { + assertExhaustive(severity, `Unhandled severity: ${severity}`); + } + } +}