diff --git a/.changeset/curly-horses-fold.md b/.changeset/curly-horses-fold.md new file mode 100644 index 00000000..933d9f05 --- /dev/null +++ b/.changeset/curly-horses-fold.md @@ -0,0 +1,5 @@ +--- +"eslint-plugin-primer-react": minor +--- + +Add lint rule to discourage Flash usage diff --git a/README.md b/README.md index 9a151f8c..d8153d55 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ ESLint rules for Primer React - [new-color-css-vars](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/new-color-css-vars.md) - [no-deprecated-entrypoints](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/no-deprecated-entrypoints.md) - [no-deprecated-experimental-components](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/no-deprecated-experimental-components.md) +- [no-deprecated-flash](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/no-deprecated-flash.md) - [no-deprecated-props](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/no-deprecated-props.md) - [no-use-responsive-value](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/no-use-responsive-value.md) diff --git a/docs/rules/no-deprecated-flash.md b/docs/rules/no-deprecated-flash.md new file mode 100644 index 00000000..bb150a0c --- /dev/null +++ b/docs/rules/no-deprecated-flash.md @@ -0,0 +1,22 @@ +# No deprecated Flash + +## Rule details + +This rule discourages imports of the deprecated `Flash` component from +`@primer/react` and `@primer/react/deprecated`. + +👎 Example of **incorrect** code for this rule: + +```jsx +import {Flash} from '@primer/react' +``` + +👍 Example of **correct** code for this rule: + +```jsx +import {Banner} from '@primer/react' +``` + +Follow the +[Flash migration guide](https://primer.style/product/getting-started/react/migration-guides/primer-flash) +when replacing `Flash` with `Banner`. diff --git a/src/configs/recommended.js b/src/configs/recommended.js index 7914b805..5795b610 100644 --- a/src/configs/recommended.js +++ b/src/configs/recommended.js @@ -12,6 +12,7 @@ module.exports = { 'primer-react/direct-slot-children': 'error', 'primer-react/no-deprecated-experimental-components': 'warn', + 'primer-react/no-deprecated-flash': 'warn', 'primer-react/a11y-tooltip-interactive-trigger': 'error', 'primer-react/new-color-css-vars': 'error', 'primer-react/a11y-explicit-heading': 'error', diff --git a/src/index.js b/src/index.js index 8e8aa53d..83981e91 100644 --- a/src/index.js +++ b/src/index.js @@ -14,6 +14,7 @@ module.exports = { 'new-color-css-vars': require('./rules/new-color-css-vars'), 'no-deprecated-entrypoints': require('./rules/no-deprecated-entrypoints'), 'no-deprecated-experimental-components': require('./rules/no-deprecated-experimental-components'), + 'no-deprecated-flash': require('./rules/no-deprecated-flash'), 'no-deprecated-props': require('./rules/no-deprecated-props'), 'no-use-responsive-value': require('./rules/no-use-responsive-value'), diff --git a/src/rules/__tests__/no-deprecated-flash.test.js b/src/rules/__tests__/no-deprecated-flash.test.js new file mode 100644 index 00000000..3697c7da --- /dev/null +++ b/src/rules/__tests__/no-deprecated-flash.test.js @@ -0,0 +1,48 @@ +'use strict' + +const {RuleTester} = require('eslint') +const rule = require('../no-deprecated-flash') + +const ruleTester = new RuleTester({ + languageOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, +}) + +const error = {messageId: 'deprecatedFlash'} + +ruleTester.run('no-deprecated-flash', rule, { + valid: [ + { + code: `import {Banner} from '@primer/react'`, + }, + { + code: `import {Flash} from '@example/react'`, + }, + { + code: `import PrimerReact from '@primer/react'`, + }, + { + code: `import * as PrimerReact from '@primer/react'`, + }, + ], + invalid: [ + { + code: `import {Flash} from '@primer/react'`, + errors: [error], + }, + { + code: `import {Flash} from '@primer/react/deprecated'`, + errors: [error], + }, + { + code: `import {Flash as LegacyFlash} from '@primer/react'`, + errors: [error], + }, + { + code: `import {Button, Flash, Link} from '@primer/react'`, + errors: [error], + }, + ], +}) diff --git a/src/rules/no-deprecated-flash.js b/src/rules/no-deprecated-flash.js new file mode 100644 index 00000000..3968ffd8 --- /dev/null +++ b/src/rules/no-deprecated-flash.js @@ -0,0 +1,48 @@ +'use strict' + +const url = require('../url') + +const migrationGuide = 'https://primer.style/product/getting-started/react/migration-guides/primer-flash' +const primerReactEntrypoints = new Set(['@primer/react', '@primer/react/deprecated']) + +/** + * @type {import('eslint').Rule.RuleModule} + */ +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'Discourage the use of the deprecated Flash component', + recommended: true, + url: url(module), + }, + messages: { + deprecatedFlash: `\`Flash\` is deprecated. Use \`Banner\` from \`@primer/react\` instead. See the migration guide: ${migrationGuide}`, + }, + schema: [], + }, + create(context) { + return { + ImportDeclaration(node) { + if (!primerReactEntrypoints.has(node.source.value)) { + return + } + + for (const specifier of node.specifiers) { + if (specifier.type !== 'ImportSpecifier') { + continue + } + + if (specifier.imported.name !== 'Flash') { + continue + } + + context.report({ + node: specifier, + messageId: 'deprecatedFlash', + }) + } + }, + } + }, +}