react/.eslintrc.js

273 lines
8.2 KiB
JavaScript
Raw Normal View History

'use strict';
const {
es5Paths,
esNextPaths,
} = require('./scripts/shared/pathsByLanguageVersion');
const restrictedGlobals = require('confusing-browser-globals');
2016-03-02 07:40:52 +08:00
const OFF = 0;
const ERROR = 2;
module.exports = {
Add test run that uses www feature flags (#18234) In CI, we run our test suite against multiple build configurations. For example, we run our tests in both dev and prod, and in both the experimental and stable release channels. This is to prevent accidental deviations in behavior between the different builds. If there's an intentional deviation in behavior, the test author must account for them. However, we currently don't run tests against the www builds. That's a problem, because it's common for features to land in www before they land anywhere else, including the experimental release channel. Typically we do this so we can gradually roll out the feature behind a flag before deciding to enable it. The way we test those features today is by mutating the `shared/ReactFeatureFlags` module. There are a few downsides to this approach, though. The flag is only overridden for the specific tests or test suites where you apply the override. But usually what you want is to run *all* tests with the flag enabled, to protect against unexpected regressions. Also, mutating the feature flags module only works when running the tests against source, not against the final build artifacts, because the ReactFeatureFlags module is inlined by the build script. Instead, we should run the test suite against the www configuration, just like we do for prod, experimental, and so on. I've added a new command, `yarn test-www`. It automatically runs in CI. Some of the www feature flags are dynamic; that is, they depend on a runtime condition (i.e. a GK). These flags are imported from an external module that lives in www. Those flags will be enabled for some clients and disabled for others, so we should run the tests against *both* modes. So I've added a new global `__VARIANT__`, and a new test command `yarn test-www-variant`. `__VARIANT__` is set to false by default; when running `test-www-variant`, it's set to true. If we were going for *really* comprehensive coverage, we would run the tests against every possible configuration of feature flags: 2 ^ numberOfFlags total combinations. That's not practical, though, so instead we only run against two combinations: once with `__VARIANT__` set to `true`, and once with it set to `false`. We generally assume that flags can be toggled independently, so in practice this should be enough. You can also refer to `__VARIANT__` in tests to detect which mode you're running in. Or, you can import `shared/ReactFeatureFlags` and read the specific flag you can about. However, we should stop mutating that module going forward. Treat it as read-only. In this commit, I have only setup the www tests to run against source. I'll leave running against build for a follow up. Many of our tests currently assume they run only in the default configuration, and break when certain flags are toggled. Rather than fix these all up front, I've hard-coded the relevant flags to the default values. We can incrementally migrate those tests later.
2020-03-07 01:29:05 +08:00
extends: ['fbjs', 'prettier'],
2016-03-02 07:40:52 +08:00
// Stop ESLint from looking for a configuration file in parent folders
root: true,
plugins: [
'jest',
'no-for-of-loops',
'no-function-declare-after-return',
'react',
'react-internal',
],
2016-03-02 07:40:52 +08:00
parser: 'babel-eslint',
parserOptions: {
ecmaVersion: 9,
sourceType: 'script',
},
2016-03-02 07:40:52 +08:00
// We're stricter than the default config, mostly. We'll override a few rules
// and then enable some React specific ones.
rules: {
'accessor-pairs': OFF,
'brace-style': [ERROR, '1tbs'],
'consistent-return': OFF,
2016-03-02 07:40:52 +08:00
'dot-location': [ERROR, 'property'],
// We use console['error']() as a signal to not transform it:
'dot-notation': [ERROR, {allowPattern: '^(error|warn)$'}],
2016-03-02 07:40:52 +08:00
'eol-last': ERROR,
eqeqeq: [ERROR, 'allow-null'],
indent: OFF,
2016-03-02 07:40:52 +08:00
'jsx-quotes': [ERROR, 'prefer-double'],
'keyword-spacing': [ERROR, {after: true, before: true}],
2016-03-02 07:40:52 +08:00
'no-bitwise': OFF,
'no-console': OFF,
'no-inner-declarations': [ERROR, 'functions'],
2016-03-02 07:40:52 +08:00
'no-multi-spaces': ERROR,
'no-restricted-globals': [ERROR].concat(restrictedGlobals),
2016-03-02 07:40:52 +08:00
'no-restricted-syntax': [ERROR, 'WithStatement'],
'no-shadow': ERROR,
'no-unused-expressions': ERROR,
'no-unused-vars': [ERROR, {args: 'none'}],
'no-use-before-define': OFF,
'no-useless-concat': OFF,
quotes: [ERROR, 'single', {avoidEscape: true, allowTemplateLiterals: true}],
2016-03-02 07:40:52 +08:00
'space-before-blocks': ERROR,
'space-before-function-paren': OFF,
'valid-typeof': [ERROR, {requireStringLiterals: true}],
// Flow fails with non-string literal keys
'no-useless-computed-key': OFF,
2016-03-02 07:40:52 +08:00
// We apply these settings to files that should run on Node.
// They can't use JSX or ES6 modules, and must be in strict mode.
// They can, however, use other ES6 features.
// (Note these rules are overridden later for source files.)
'no-var': ERROR,
strict: ERROR,
// Enforced by Prettier
// TODO: Prettier doesn't handle long strings or long comments. Not a big
// deal. But I turned it off because loading the plugin causes some obscure
// syntax error and it didn't seem worth investigating.
'max-len': OFF,
// Prettier forces semicolons in a few places
'flowtype/object-type-delimiter': OFF,
2016-03-02 07:40:52 +08:00
// React & JSX
// Our transforms set this automatically
'react/jsx-boolean-value': [ERROR, 'always'],
'react/jsx-no-undef': ERROR,
// We don't care to do this
'react/jsx-sort-prop-types': OFF,
'react/jsx-space-before-closing': ERROR,
2016-03-02 07:40:52 +08:00
'react/jsx-uses-react': ERROR,
'react/no-is-mounted': OFF,
2016-03-02 07:40:52 +08:00
// This isn't useful in our test code
'react/react-in-jsx-scope': ERROR,
'react/self-closing-comp': ERROR,
// We don't care to do this
'react/jsx-wrap-multilines': [
ERROR,
{declaration: false, assignment: false},
],
2016-03-02 07:40:52 +08:00
// Prevent for...of loops because they require a Symbol polyfill.
// You can disable this rule for code that isn't shipped (e.g. build scripts and tests).
'no-for-of-loops/no-for-of-loops': ERROR,
// Prevent function declarations after return statements
'no-function-declare-after-return/no-function-declare-after-return': ERROR,
2016-03-02 07:40:52 +08:00
// CUSTOM RULES
// the second argument of warning/invariant should be a literal string
'react-internal/no-primitive-constructors': ERROR,
Improve DEV errors if string coercion throws (Temporal.*, Symbol, etc.) (#22064) * Revise ESLint rules for string coercion Currently, react uses `'' + value` to coerce mixed values to strings. This code will throw for Temporal objects or symbols. To make string-coercion safer and to improve user-facing error messages, This commit adds a new ESLint rule called `safe-string-coercion`. This rule has two modes: a production mode and a non-production mode. * If the `isProductionUserAppCode` option is true, then `'' + value` coercions are allowed (because they're faster, although they may throw) and `String(value)` coercions are disallowed. Exception: when building error messages or running DEV-only code in prod files, `String()` should be used because it won't throw. * If the `isProductionUserAppCode` option is false, then `'' + value` coercions are disallowed (because they may throw, and in non-prod code it's not worth the risk) and `String(value)` are allowed. Production mode is used for all files which will be bundled with developers' userland apps. Non-prod mode is used for all other React code: tests, DEV blocks, devtools extension, etc. In production mode, in addiiton to flagging `String(value)` calls, the rule will also flag `'' + value` or `value + ''` coercions that may throw. The rule is smart enough to silence itself in the following "will never throw" cases: * When the coercion is wrapped in a `typeof` test that restricts to safe (non-symbol, non-object) types. Example: if (typeof value === 'string' || typeof value === 'number') { thisWontReport('' + value); } * When what's being coerced is a unary function result, because unary functions never return an object or a symbol. * When the coerced value is a commonly-used numeric identifier: `i`, `idx`, or `lineNumber`. * When the statement immeidately before the coercion is a DEV-only call to a function from shared/CheckStringCoercion.js. This call is a no-op in production, but in DEV it will show a console error explaining the problem, then will throw right after a long explanatory code comment so that debugger users will have an idea what's going on. The check function call must be in the following format: if (__DEV__) { checkXxxxxStringCoercion(value); }; Manually disabling the rule is usually not necessary because almost all prod use of the `'' + value` pattern falls into one of the categories above. But in the rare cases where the rule isn't smart enough to detect safe usage (e.g. when a coercion is inside a nested ternary operator), manually disabling the rule will be needed. The rule should also be manually disabled in prod error handling code where `String(value)` should be used for coercions, because it'd be bad to throw while building an error message or stack trace! The prod and non-prod modes have differentiated error messages to explain how to do a proper coercion in that mode. If a production check call is needed but is missing or incorrect (e.g. not in a DEV block or not immediately before the coercion), then a context-sensitive error message will be reported so that developers can figure out what's wrong and how to fix the problem. Because string coercions are now handled by the `safe-string-coercion` rule, the `no-primitive-constructor` rule no longer flags `String()` usage. It still flags `new String(value)` because that usage is almost always a bug. * Add DEV-only string coercion check functions This commit adds DEV-only functions to check whether coercing values to strings using the `'' + value` pattern will throw. If it will throw, these functions will: 1. Display a console error with a friendly error message describing the problem and the developer can fix it. 2. Perform the coercion, which will throw. Right before the line where the throwing happens, there's a long code comment that will help debugger users (or others looking at the exception call stack) figure out what happened and how to fix the problem. One of these check functions should be called before all string coercion of user-provided values, except when the the coercion is guaranteed not to throw, e.g. * if inside a typeof check like `if (typeof value === 'string')` * if coercing the result of a unary function like `+value` or `value++` * if coercing a variable named in a whitelist of numeric identifiers: `i`, `idx`, or `lineNumber`. The new `safe-string-coercion` internal ESLint rule enforces that these check functions are called when they are required. Only use these check functions in production code that will be bundled with user apps. For non-prod code (and for production error-handling code), use `String(value)` instead which may be a little slower but will never throw. * Add failing tests for string coercion Added failing tests to verify: * That input, select, and textarea elements with value and defaultValue set to Temporal-like objects which will throw when coerced to string using the `'' + value` pattern. * That text elements will throw for Temporal-like objects * That dangerouslySetInnerHTML will *not* throw for Temporal-like objects because this value is not cast to a string before passing to the DOM. * That keys that are Temporal-like objects will throw All tests above validate the friendly error messages thrown. * Use `String(value)` for coercion in non-prod files This commit switches non-production code from `'' + value` (which throws for Temporal objects and symbols) to instead use `String(value)` which won't throw for these or other future plus-phobic types. "Non-produciton code" includes anything not bundled into user apps: * Tests and test utilities. Note that I didn't change legacy React test fixtures because I assumed it was good for those files to act just like old React, including coercion behavior. * Build scripts * Dev tools package - In addition to switching to `String`, I also removed special-case code for coercing symbols which is now unnecessary. * Add DEV-only string coercion checks to prod files This commit adds DEV-only function calls to to check if string coercion using `'' + value` will throw, which it will if the value is a Temporal object or a symbol because those types can't be added with `+`. If it will throw, then in DEV these checks will show a console error to help the user undertsand what went wrong and how to fix the problem. After emitting the console error, the check functions will retry the coercion which will throw with a call stack that's easy (or at least easier!) to troubleshoot because the exception happens right after a long comment explaining the issue. So whether the user is in a debugger, looking at the browser console, or viewing the in-browser DEV call stack, it should be easy to understand and fix the problem. In most cases, the safe-string-coercion ESLint rule is smart enough to detect when a coercion is safe. But in rare cases (e.g. when a coercion is inside a ternary) this rule will have to be manually disabled. This commit also switches error-handling code to use `String(value)` for coercion, because it's bad to crash when you're trying to build an error message or a call stack! Because `String()` is usually disallowed by the `safe-string-coercion` ESLint rule in production code, the rule must be disabled when `String()` is used.
2021-09-28 01:05:07 +08:00
'react-internal/safe-string-coercion': [
ERROR,
{isProductionUserAppCode: true},
],
'react-internal/no-to-warn-dev-within-to-throw': ERROR,
'react-internal/warning-args': ERROR,
'react-internal/no-production-logging': ERROR,
},
overrides: [
{
[RFC] Codemod invariant -> throw new Error (#22435) * Hoist error codes import to module scope When this code was written, the error codes map (`codes.json`) was created on-the-fly, so we had to lazily require from inside the visitor. Because `codes.json` is now checked into source, we can import it a single time in module scope. * Minify error constructors in production We use a script to minify our error messages in production. Each message is assigned an error code, defined in `scripts/error-codes/codes.json`. Then our build script replaces the messages with a link to our error decoder page, e.g. https://reactjs.org/docs/error-decoder.html/?invariant=92 This enables us to write helpful error messages without increasing the bundle size. Right now, the script only works for `invariant` calls. It does not work if you throw an Error object. This is an old Facebookism that we don't really need, other than the fact that our error minification script relies on it. So, I've updated the script to minify error constructors, too: Input: Error(`A ${adj} message that contains ${noun}`); Output: Error(formatProdErrorMessage(ERR_CODE, adj, noun)); It only works for constructors that are literally named Error, though we could add support for other names, too. As a next step, I will add a lint rule to enforce that errors written this way must have a corresponding error code. * Minify "no fallback UI specified" error in prod This error message wasn't being minified because it doesn't use invariant. The reason it didn't use invariant is because this particular error is created without begin thrown — it doesn't need to be thrown because it's located inside the error handling part of the runtime. Now that the error minification script supports Error constructors, we can minify it by assigning it a production error code in `scripts/error-codes/codes.json`. To support the use of Error constructors more generally, I will add a lint rule that enforces each message has a corresponding error code. * Lint rule to detect unminified errors Adds a lint rule that detects when an Error constructor is used without a corresponding production error code. We already have this for `invariant`, but not for regular errors, i.e. `throw new Error(msg)`. There's also nothing that enforces the use of `invariant` besides convention. There are some packages where we don't care to minify errors. These are packages that run in environments where bundle size is not a concern, like react-pg. I added an override in the ESLint config to ignore these. * Temporarily add invariant codemod script I'm adding this codemod to the repo temporarily, but I'll revert it in the same PR. That way we don't have to check it in but it's still accessible (via the PR) if we need it later. * [Automated] Codemod invariant -> Error This commit contains only automated changes: npx jscodeshift -t scripts/codemod-invariant.js packages --ignore-pattern="node_modules/**/*" yarn linc --fix yarn prettier I will do any manual touch ups in separate commits so they're easier to review. * Remove temporary codemod script This reverts the codemod script and ESLint config I added temporarily in order to perform the invariant codemod. * Manual touch ups A few manual changes I made after the codemod ran. * Enable error code transform per package Currently we're not consistent about which packages should have their errors minified in production and which ones should. This adds a field to the bundle configuration to control whether to apply the transform. We should decide what the criteria is going forward. I think it's probably a good idea to minify any package that gets sent over the network. So yes to modules that run in the browser, and no to modules that run on the server and during development only.
2021-10-01 03:01:28 +08:00
// By default, anything error message that appears the packages directory
// must have a corresponding error code. The exceptions are defined
// in the next override entry.
files: ['packages/**/*.js'],
rules: {
'react-internal/prod-error-codes': ERROR,
},
},
{
// These are files where it's OK to have unminified error messages. These
// are environments where bundle size isn't a concern, like tests
// or Node.
files: [
'packages/react-dom/src/test-utils/**/*.js',
'packages/react-devtools-shared/**/*.js',
'packages/react-noop-renderer/**/*.js',
'packages/react-refresh/**/*.js',
'packages/react-server-dom-webpack/**/*.js',
'packages/react-test-renderer/**/*.js',
'packages/react-debug-tools/**/*.js',
'packages/react-devtools-extensions/**/*.js',
'packages/react-devtools-timeline/**/*.js',
[RFC] Codemod invariant -> throw new Error (#22435) * Hoist error codes import to module scope When this code was written, the error codes map (`codes.json`) was created on-the-fly, so we had to lazily require from inside the visitor. Because `codes.json` is now checked into source, we can import it a single time in module scope. * Minify error constructors in production We use a script to minify our error messages in production. Each message is assigned an error code, defined in `scripts/error-codes/codes.json`. Then our build script replaces the messages with a link to our error decoder page, e.g. https://reactjs.org/docs/error-decoder.html/?invariant=92 This enables us to write helpful error messages without increasing the bundle size. Right now, the script only works for `invariant` calls. It does not work if you throw an Error object. This is an old Facebookism that we don't really need, other than the fact that our error minification script relies on it. So, I've updated the script to minify error constructors, too: Input: Error(`A ${adj} message that contains ${noun}`); Output: Error(formatProdErrorMessage(ERR_CODE, adj, noun)); It only works for constructors that are literally named Error, though we could add support for other names, too. As a next step, I will add a lint rule to enforce that errors written this way must have a corresponding error code. * Minify "no fallback UI specified" error in prod This error message wasn't being minified because it doesn't use invariant. The reason it didn't use invariant is because this particular error is created without begin thrown — it doesn't need to be thrown because it's located inside the error handling part of the runtime. Now that the error minification script supports Error constructors, we can minify it by assigning it a production error code in `scripts/error-codes/codes.json`. To support the use of Error constructors more generally, I will add a lint rule that enforces each message has a corresponding error code. * Lint rule to detect unminified errors Adds a lint rule that detects when an Error constructor is used without a corresponding production error code. We already have this for `invariant`, but not for regular errors, i.e. `throw new Error(msg)`. There's also nothing that enforces the use of `invariant` besides convention. There are some packages where we don't care to minify errors. These are packages that run in environments where bundle size is not a concern, like react-pg. I added an override in the ESLint config to ignore these. * Temporarily add invariant codemod script I'm adding this codemod to the repo temporarily, but I'll revert it in the same PR. That way we don't have to check it in but it's still accessible (via the PR) if we need it later. * [Automated] Codemod invariant -> Error This commit contains only automated changes: npx jscodeshift -t scripts/codemod-invariant.js packages --ignore-pattern="node_modules/**/*" yarn linc --fix yarn prettier I will do any manual touch ups in separate commits so they're easier to review. * Remove temporary codemod script This reverts the codemod script and ESLint config I added temporarily in order to perform the invariant codemod. * Manual touch ups A few manual changes I made after the codemod ran. * Enable error code transform per package Currently we're not consistent about which packages should have their errors minified in production and which ones should. This adds a field to the bundle configuration to control whether to apply the transform. We should decide what the criteria is going forward. I think it's probably a good idea to minify any package that gets sent over the network. So yes to modules that run in the browser, and no to modules that run on the server and during development only.
2021-10-01 03:01:28 +08:00
'packages/react-native-renderer/**/*.js',
'packages/eslint-plugin-react-hooks/**/*.js',
'packages/jest-react/**/*.js',
'packages/**/__tests__/*.js',
'packages/**/npm/*.js',
],
rules: {
'react-internal/prod-error-codes': OFF,
},
},
{
// We apply these settings to files that we ship through npm.
// They must be ES5.
files: es5Paths,
parser: 'espree',
parserOptions: {
ecmaVersion: 5,
sourceType: 'script',
},
rules: {
'no-var': OFF,
strict: ERROR,
},
},
{
// We apply these settings to the source files that get compiled.
// They can use all features including JSX (but shouldn't use `var`).
files: esNextPaths,
parser: 'babel-eslint',
parserOptions: {
ecmaVersion: 8,
sourceType: 'module',
},
rules: {
'no-var': ERROR,
'prefer-const': ERROR,
strict: OFF,
},
},
{
files: ['**/__tests__/*.js'],
rules: {
// https://github.com/jest-community/eslint-plugin-jest
'jest/no-focused-tests': ERROR,
'jest/valid-expect': ERROR,
'jest/valid-expect-in-promise': ERROR,
},
},
{
files: [
'**/__tests__/**/*.js',
'scripts/**/*.js',
'packages/*/npm/**/*.js',
'packages/dom-event-testing-library/**/*.js',
Add test run that uses www feature flags (#18234) In CI, we run our test suite against multiple build configurations. For example, we run our tests in both dev and prod, and in both the experimental and stable release channels. This is to prevent accidental deviations in behavior between the different builds. If there's an intentional deviation in behavior, the test author must account for them. However, we currently don't run tests against the www builds. That's a problem, because it's common for features to land in www before they land anywhere else, including the experimental release channel. Typically we do this so we can gradually roll out the feature behind a flag before deciding to enable it. The way we test those features today is by mutating the `shared/ReactFeatureFlags` module. There are a few downsides to this approach, though. The flag is only overridden for the specific tests or test suites where you apply the override. But usually what you want is to run *all* tests with the flag enabled, to protect against unexpected regressions. Also, mutating the feature flags module only works when running the tests against source, not against the final build artifacts, because the ReactFeatureFlags module is inlined by the build script. Instead, we should run the test suite against the www configuration, just like we do for prod, experimental, and so on. I've added a new command, `yarn test-www`. It automatically runs in CI. Some of the www feature flags are dynamic; that is, they depend on a runtime condition (i.e. a GK). These flags are imported from an external module that lives in www. Those flags will be enabled for some clients and disabled for others, so we should run the tests against *both* modes. So I've added a new global `__VARIANT__`, and a new test command `yarn test-www-variant`. `__VARIANT__` is set to false by default; when running `test-www-variant`, it's set to true. If we were going for *really* comprehensive coverage, we would run the tests against every possible configuration of feature flags: 2 ^ numberOfFlags total combinations. That's not practical, though, so instead we only run against two combinations: once with `__VARIANT__` set to `true`, and once with it set to `false`. We generally assume that flags can be toggled independently, so in practice this should be enough. You can also refer to `__VARIANT__` in tests to detect which mode you're running in. Or, you can import `shared/ReactFeatureFlags` and read the specific flag you can about. However, we should stop mutating that module going forward. Treat it as read-only. In this commit, I have only setup the www tests to run against source. I'll leave running against build for a follow up. Many of our tests currently assume they run only in the default configuration, and break when certain flags are toggled. Rather than fix these all up front, I've hard-coded the relevant flags to the default values. We can incrementally migrate those tests later.
2020-03-07 01:29:05 +08:00
'packages/react-devtools*/**/*.js',
Improve DEV errors if string coercion throws (Temporal.*, Symbol, etc.) (#22064) * Revise ESLint rules for string coercion Currently, react uses `'' + value` to coerce mixed values to strings. This code will throw for Temporal objects or symbols. To make string-coercion safer and to improve user-facing error messages, This commit adds a new ESLint rule called `safe-string-coercion`. This rule has two modes: a production mode and a non-production mode. * If the `isProductionUserAppCode` option is true, then `'' + value` coercions are allowed (because they're faster, although they may throw) and `String(value)` coercions are disallowed. Exception: when building error messages or running DEV-only code in prod files, `String()` should be used because it won't throw. * If the `isProductionUserAppCode` option is false, then `'' + value` coercions are disallowed (because they may throw, and in non-prod code it's not worth the risk) and `String(value)` are allowed. Production mode is used for all files which will be bundled with developers' userland apps. Non-prod mode is used for all other React code: tests, DEV blocks, devtools extension, etc. In production mode, in addiiton to flagging `String(value)` calls, the rule will also flag `'' + value` or `value + ''` coercions that may throw. The rule is smart enough to silence itself in the following "will never throw" cases: * When the coercion is wrapped in a `typeof` test that restricts to safe (non-symbol, non-object) types. Example: if (typeof value === 'string' || typeof value === 'number') { thisWontReport('' + value); } * When what's being coerced is a unary function result, because unary functions never return an object or a symbol. * When the coerced value is a commonly-used numeric identifier: `i`, `idx`, or `lineNumber`. * When the statement immeidately before the coercion is a DEV-only call to a function from shared/CheckStringCoercion.js. This call is a no-op in production, but in DEV it will show a console error explaining the problem, then will throw right after a long explanatory code comment so that debugger users will have an idea what's going on. The check function call must be in the following format: if (__DEV__) { checkXxxxxStringCoercion(value); }; Manually disabling the rule is usually not necessary because almost all prod use of the `'' + value` pattern falls into one of the categories above. But in the rare cases where the rule isn't smart enough to detect safe usage (e.g. when a coercion is inside a nested ternary operator), manually disabling the rule will be needed. The rule should also be manually disabled in prod error handling code where `String(value)` should be used for coercions, because it'd be bad to throw while building an error message or stack trace! The prod and non-prod modes have differentiated error messages to explain how to do a proper coercion in that mode. If a production check call is needed but is missing or incorrect (e.g. not in a DEV block or not immediately before the coercion), then a context-sensitive error message will be reported so that developers can figure out what's wrong and how to fix the problem. Because string coercions are now handled by the `safe-string-coercion` rule, the `no-primitive-constructor` rule no longer flags `String()` usage. It still flags `new String(value)` because that usage is almost always a bug. * Add DEV-only string coercion check functions This commit adds DEV-only functions to check whether coercing values to strings using the `'' + value` pattern will throw. If it will throw, these functions will: 1. Display a console error with a friendly error message describing the problem and the developer can fix it. 2. Perform the coercion, which will throw. Right before the line where the throwing happens, there's a long code comment that will help debugger users (or others looking at the exception call stack) figure out what happened and how to fix the problem. One of these check functions should be called before all string coercion of user-provided values, except when the the coercion is guaranteed not to throw, e.g. * if inside a typeof check like `if (typeof value === 'string')` * if coercing the result of a unary function like `+value` or `value++` * if coercing a variable named in a whitelist of numeric identifiers: `i`, `idx`, or `lineNumber`. The new `safe-string-coercion` internal ESLint rule enforces that these check functions are called when they are required. Only use these check functions in production code that will be bundled with user apps. For non-prod code (and for production error-handling code), use `String(value)` instead which may be a little slower but will never throw. * Add failing tests for string coercion Added failing tests to verify: * That input, select, and textarea elements with value and defaultValue set to Temporal-like objects which will throw when coerced to string using the `'' + value` pattern. * That text elements will throw for Temporal-like objects * That dangerouslySetInnerHTML will *not* throw for Temporal-like objects because this value is not cast to a string before passing to the DOM. * That keys that are Temporal-like objects will throw All tests above validate the friendly error messages thrown. * Use `String(value)` for coercion in non-prod files This commit switches non-production code from `'' + value` (which throws for Temporal objects and symbols) to instead use `String(value)` which won't throw for these or other future plus-phobic types. "Non-produciton code" includes anything not bundled into user apps: * Tests and test utilities. Note that I didn't change legacy React test fixtures because I assumed it was good for those files to act just like old React, including coercion behavior. * Build scripts * Dev tools package - In addition to switching to `String`, I also removed special-case code for coercing symbols which is now unnecessary. * Add DEV-only string coercion checks to prod files This commit adds DEV-only function calls to to check if string coercion using `'' + value` will throw, which it will if the value is a Temporal object or a symbol because those types can't be added with `+`. If it will throw, then in DEV these checks will show a console error to help the user undertsand what went wrong and how to fix the problem. After emitting the console error, the check functions will retry the coercion which will throw with a call stack that's easy (or at least easier!) to troubleshoot because the exception happens right after a long comment explaining the issue. So whether the user is in a debugger, looking at the browser console, or viewing the in-browser DEV call stack, it should be easy to understand and fix the problem. In most cases, the safe-string-coercion ESLint rule is smart enough to detect when a coercion is safe. But in rare cases (e.g. when a coercion is inside a ternary) this rule will have to be manually disabled. This commit also switches error-handling code to use `String(value)` for coercion, because it's bad to crash when you're trying to build an error message or a call stack! Because `String()` is usually disallowed by the `safe-string-coercion` ESLint rule in production code, the rule must be disabled when `String()` is used.
2021-09-28 01:05:07 +08:00
'dangerfile.js',
'fixtures',
'packages/react-dom/src/test-utils/*.js',
],
rules: {
'react-internal/no-production-logging': OFF,
'react-internal/warning-args': OFF,
Improve DEV errors if string coercion throws (Temporal.*, Symbol, etc.) (#22064) * Revise ESLint rules for string coercion Currently, react uses `'' + value` to coerce mixed values to strings. This code will throw for Temporal objects or symbols. To make string-coercion safer and to improve user-facing error messages, This commit adds a new ESLint rule called `safe-string-coercion`. This rule has two modes: a production mode and a non-production mode. * If the `isProductionUserAppCode` option is true, then `'' + value` coercions are allowed (because they're faster, although they may throw) and `String(value)` coercions are disallowed. Exception: when building error messages or running DEV-only code in prod files, `String()` should be used because it won't throw. * If the `isProductionUserAppCode` option is false, then `'' + value` coercions are disallowed (because they may throw, and in non-prod code it's not worth the risk) and `String(value)` are allowed. Production mode is used for all files which will be bundled with developers' userland apps. Non-prod mode is used for all other React code: tests, DEV blocks, devtools extension, etc. In production mode, in addiiton to flagging `String(value)` calls, the rule will also flag `'' + value` or `value + ''` coercions that may throw. The rule is smart enough to silence itself in the following "will never throw" cases: * When the coercion is wrapped in a `typeof` test that restricts to safe (non-symbol, non-object) types. Example: if (typeof value === 'string' || typeof value === 'number') { thisWontReport('' + value); } * When what's being coerced is a unary function result, because unary functions never return an object or a symbol. * When the coerced value is a commonly-used numeric identifier: `i`, `idx`, or `lineNumber`. * When the statement immeidately before the coercion is a DEV-only call to a function from shared/CheckStringCoercion.js. This call is a no-op in production, but in DEV it will show a console error explaining the problem, then will throw right after a long explanatory code comment so that debugger users will have an idea what's going on. The check function call must be in the following format: if (__DEV__) { checkXxxxxStringCoercion(value); }; Manually disabling the rule is usually not necessary because almost all prod use of the `'' + value` pattern falls into one of the categories above. But in the rare cases where the rule isn't smart enough to detect safe usage (e.g. when a coercion is inside a nested ternary operator), manually disabling the rule will be needed. The rule should also be manually disabled in prod error handling code where `String(value)` should be used for coercions, because it'd be bad to throw while building an error message or stack trace! The prod and non-prod modes have differentiated error messages to explain how to do a proper coercion in that mode. If a production check call is needed but is missing or incorrect (e.g. not in a DEV block or not immediately before the coercion), then a context-sensitive error message will be reported so that developers can figure out what's wrong and how to fix the problem. Because string coercions are now handled by the `safe-string-coercion` rule, the `no-primitive-constructor` rule no longer flags `String()` usage. It still flags `new String(value)` because that usage is almost always a bug. * Add DEV-only string coercion check functions This commit adds DEV-only functions to check whether coercing values to strings using the `'' + value` pattern will throw. If it will throw, these functions will: 1. Display a console error with a friendly error message describing the problem and the developer can fix it. 2. Perform the coercion, which will throw. Right before the line where the throwing happens, there's a long code comment that will help debugger users (or others looking at the exception call stack) figure out what happened and how to fix the problem. One of these check functions should be called before all string coercion of user-provided values, except when the the coercion is guaranteed not to throw, e.g. * if inside a typeof check like `if (typeof value === 'string')` * if coercing the result of a unary function like `+value` or `value++` * if coercing a variable named in a whitelist of numeric identifiers: `i`, `idx`, or `lineNumber`. The new `safe-string-coercion` internal ESLint rule enforces that these check functions are called when they are required. Only use these check functions in production code that will be bundled with user apps. For non-prod code (and for production error-handling code), use `String(value)` instead which may be a little slower but will never throw. * Add failing tests for string coercion Added failing tests to verify: * That input, select, and textarea elements with value and defaultValue set to Temporal-like objects which will throw when coerced to string using the `'' + value` pattern. * That text elements will throw for Temporal-like objects * That dangerouslySetInnerHTML will *not* throw for Temporal-like objects because this value is not cast to a string before passing to the DOM. * That keys that are Temporal-like objects will throw All tests above validate the friendly error messages thrown. * Use `String(value)` for coercion in non-prod files This commit switches non-production code from `'' + value` (which throws for Temporal objects and symbols) to instead use `String(value)` which won't throw for these or other future plus-phobic types. "Non-produciton code" includes anything not bundled into user apps: * Tests and test utilities. Note that I didn't change legacy React test fixtures because I assumed it was good for those files to act just like old React, including coercion behavior. * Build scripts * Dev tools package - In addition to switching to `String`, I also removed special-case code for coercing symbols which is now unnecessary. * Add DEV-only string coercion checks to prod files This commit adds DEV-only function calls to to check if string coercion using `'' + value` will throw, which it will if the value is a Temporal object or a symbol because those types can't be added with `+`. If it will throw, then in DEV these checks will show a console error to help the user undertsand what went wrong and how to fix the problem. After emitting the console error, the check functions will retry the coercion which will throw with a call stack that's easy (or at least easier!) to troubleshoot because the exception happens right after a long comment explaining the issue. So whether the user is in a debugger, looking at the browser console, or viewing the in-browser DEV call stack, it should be easy to understand and fix the problem. In most cases, the safe-string-coercion ESLint rule is smart enough to detect when a coercion is safe. But in rare cases (e.g. when a coercion is inside a ternary) this rule will have to be manually disabled. This commit also switches error-handling code to use `String(value)` for coercion, because it's bad to crash when you're trying to build an error message or a call stack! Because `String()` is usually disallowed by the `safe-string-coercion` ESLint rule in production code, the rule must be disabled when `String()` is used.
2021-09-28 01:05:07 +08:00
'react-internal/safe-string-coercion': [
ERROR,
{isProductionUserAppCode: false},
],
// Disable accessibility checks
'jsx-a11y/aria-role': OFF,
'jsx-a11y/no-noninteractive-element-interactions': OFF,
'jsx-a11y/no-static-element-interactions': OFF,
'jsx-a11y/role-has-required-aria-props': OFF,
'jsx-a11y/no-noninteractive-tabindex': OFF,
'jsx-a11y/tabindex-no-positive': OFF,
},
},
{
files: [
'scripts/eslint-rules/*.js',
Improve DEV errors if string coercion throws (Temporal.*, Symbol, etc.) (#22064) * Revise ESLint rules for string coercion Currently, react uses `'' + value` to coerce mixed values to strings. This code will throw for Temporal objects or symbols. To make string-coercion safer and to improve user-facing error messages, This commit adds a new ESLint rule called `safe-string-coercion`. This rule has two modes: a production mode and a non-production mode. * If the `isProductionUserAppCode` option is true, then `'' + value` coercions are allowed (because they're faster, although they may throw) and `String(value)` coercions are disallowed. Exception: when building error messages or running DEV-only code in prod files, `String()` should be used because it won't throw. * If the `isProductionUserAppCode` option is false, then `'' + value` coercions are disallowed (because they may throw, and in non-prod code it's not worth the risk) and `String(value)` are allowed. Production mode is used for all files which will be bundled with developers' userland apps. Non-prod mode is used for all other React code: tests, DEV blocks, devtools extension, etc. In production mode, in addiiton to flagging `String(value)` calls, the rule will also flag `'' + value` or `value + ''` coercions that may throw. The rule is smart enough to silence itself in the following "will never throw" cases: * When the coercion is wrapped in a `typeof` test that restricts to safe (non-symbol, non-object) types. Example: if (typeof value === 'string' || typeof value === 'number') { thisWontReport('' + value); } * When what's being coerced is a unary function result, because unary functions never return an object or a symbol. * When the coerced value is a commonly-used numeric identifier: `i`, `idx`, or `lineNumber`. * When the statement immeidately before the coercion is a DEV-only call to a function from shared/CheckStringCoercion.js. This call is a no-op in production, but in DEV it will show a console error explaining the problem, then will throw right after a long explanatory code comment so that debugger users will have an idea what's going on. The check function call must be in the following format: if (__DEV__) { checkXxxxxStringCoercion(value); }; Manually disabling the rule is usually not necessary because almost all prod use of the `'' + value` pattern falls into one of the categories above. But in the rare cases where the rule isn't smart enough to detect safe usage (e.g. when a coercion is inside a nested ternary operator), manually disabling the rule will be needed. The rule should also be manually disabled in prod error handling code where `String(value)` should be used for coercions, because it'd be bad to throw while building an error message or stack trace! The prod and non-prod modes have differentiated error messages to explain how to do a proper coercion in that mode. If a production check call is needed but is missing or incorrect (e.g. not in a DEV block or not immediately before the coercion), then a context-sensitive error message will be reported so that developers can figure out what's wrong and how to fix the problem. Because string coercions are now handled by the `safe-string-coercion` rule, the `no-primitive-constructor` rule no longer flags `String()` usage. It still flags `new String(value)` because that usage is almost always a bug. * Add DEV-only string coercion check functions This commit adds DEV-only functions to check whether coercing values to strings using the `'' + value` pattern will throw. If it will throw, these functions will: 1. Display a console error with a friendly error message describing the problem and the developer can fix it. 2. Perform the coercion, which will throw. Right before the line where the throwing happens, there's a long code comment that will help debugger users (or others looking at the exception call stack) figure out what happened and how to fix the problem. One of these check functions should be called before all string coercion of user-provided values, except when the the coercion is guaranteed not to throw, e.g. * if inside a typeof check like `if (typeof value === 'string')` * if coercing the result of a unary function like `+value` or `value++` * if coercing a variable named in a whitelist of numeric identifiers: `i`, `idx`, or `lineNumber`. The new `safe-string-coercion` internal ESLint rule enforces that these check functions are called when they are required. Only use these check functions in production code that will be bundled with user apps. For non-prod code (and for production error-handling code), use `String(value)` instead which may be a little slower but will never throw. * Add failing tests for string coercion Added failing tests to verify: * That input, select, and textarea elements with value and defaultValue set to Temporal-like objects which will throw when coerced to string using the `'' + value` pattern. * That text elements will throw for Temporal-like objects * That dangerouslySetInnerHTML will *not* throw for Temporal-like objects because this value is not cast to a string before passing to the DOM. * That keys that are Temporal-like objects will throw All tests above validate the friendly error messages thrown. * Use `String(value)` for coercion in non-prod files This commit switches non-production code from `'' + value` (which throws for Temporal objects and symbols) to instead use `String(value)` which won't throw for these or other future plus-phobic types. "Non-produciton code" includes anything not bundled into user apps: * Tests and test utilities. Note that I didn't change legacy React test fixtures because I assumed it was good for those files to act just like old React, including coercion behavior. * Build scripts * Dev tools package - In addition to switching to `String`, I also removed special-case code for coercing symbols which is now unnecessary. * Add DEV-only string coercion checks to prod files This commit adds DEV-only function calls to to check if string coercion using `'' + value` will throw, which it will if the value is a Temporal object or a symbol because those types can't be added with `+`. If it will throw, then in DEV these checks will show a console error to help the user undertsand what went wrong and how to fix the problem. After emitting the console error, the check functions will retry the coercion which will throw with a call stack that's easy (or at least easier!) to troubleshoot because the exception happens right after a long comment explaining the issue. So whether the user is in a debugger, looking at the browser console, or viewing the in-browser DEV call stack, it should be easy to understand and fix the problem. In most cases, the safe-string-coercion ESLint rule is smart enough to detect when a coercion is safe. But in rare cases (e.g. when a coercion is inside a ternary) this rule will have to be manually disabled. This commit also switches error-handling code to use `String(value)` for coercion, because it's bad to crash when you're trying to build an error message or a call stack! Because `String()` is usually disallowed by the `safe-string-coercion` ESLint rule in production code, the rule must be disabled when `String()` is used.
2021-09-28 01:05:07 +08:00
'packages/eslint-plugin-react-hooks/src/*.js',
],
plugins: ['eslint-plugin'],
rules: {
'eslint-plugin/prefer-object-rule': ERROR,
'eslint-plugin/require-meta-fixable': [
ERROR,
{catchNoFixerButFixableProperty: true},
],
'eslint-plugin/require-meta-has-suggestions': ERROR,
},
},
{
files: [
'packages/react-native-renderer/**/*.js',
'packages/react-server-native-relay/**/*.js',
],
globals: {
nativeFabricUIManager: 'readonly',
},
},
{
files: ['packages/react-server-dom-webpack/**/*.js'],
globals: {
__webpack_chunk_load__: 'readonly',
__webpack_require__: 'readonly',
},
},
{
files: ['packages/scheduler/**/*.js'],
globals: {
TaskController: 'readonly',
},
},
],
globals: {
spyOnDev: 'readonly',
spyOnDevAndProd: 'readonly',
spyOnProd: 'readonly',
__EXPERIMENTAL__: 'readonly',
__EXTENSION__: 'readonly',
__PROFILE__: 'readonly',
__TEST__: 'readonly',
__UMD__: 'readonly',
__VARIANT__: 'readonly',
gate: 'readonly',
trustedTypes: 'readonly',
IS_REACT_ACT_ENVIRONMENT: 'readonly',
AsyncLocalStorage: 'readonly',
globalThis: 'readonly',
},
2016-03-02 07:40:52 +08:00
};