From 1e0167ba151b2f10be7228612e69cfd97f03c0d3 Mon Sep 17 00:00:00 2001 From: llastflowers Date: Wed, 19 Aug 2026 14:23:09 -0700 Subject: [PATCH 1/3] Add lint rule for deprecated Flash usage Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 70736adb-aaef-4999-bbdd-c76914f5f8aa --- README.md | 1 + docs/rules/no-deprecated-components.md | 22 +++++++ src/configs/recommended.js | 1 + src/index.js | 1 + .../no-deprecated-components.test.js | 55 ++++++++++++++++ src/rules/no-deprecated-components.js | 66 +++++++++++++++++++ 6 files changed, 146 insertions(+) create mode 100644 docs/rules/no-deprecated-components.md create mode 100644 src/rules/__tests__/no-deprecated-components.test.js create mode 100644 src/rules/no-deprecated-components.js diff --git a/README.md b/README.md index 9a151f8c..62bcdbf8 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ ESLint rules for Primer React - [enforce-css-module-default-import](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/enforce-css-module-default-import.md) - [enforce-css-module-identifier-casing](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/enforce-css-module-identifier-casing.md) - [new-color-css-vars](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/new-color-css-vars.md) +- [no-deprecated-components](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/no-deprecated-components.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-props](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/no-deprecated-props.md) diff --git a/docs/rules/no-deprecated-components.md b/docs/rules/no-deprecated-components.md new file mode 100644 index 00000000..a20d942f --- /dev/null +++ b/docs/rules/no-deprecated-components.md @@ -0,0 +1,22 @@ +# No deprecated components + +## Rule details + +This rule discourages imports of deprecated Primer React components 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..3611c978 100644 --- a/src/configs/recommended.js +++ b/src/configs/recommended.js @@ -11,6 +11,7 @@ module.exports = { rules: { 'primer-react/direct-slot-children': 'error', + 'primer-react/no-deprecated-components': 'warn', 'primer-react/no-deprecated-experimental-components': 'warn', 'primer-react/a11y-tooltip-interactive-trigger': 'error', 'primer-react/new-color-css-vars': 'error', diff --git a/src/index.js b/src/index.js index 8e8aa53d..961b0e29 100644 --- a/src/index.js +++ b/src/index.js @@ -12,6 +12,7 @@ module.exports = { 'enforce-css-module-default-import': require('./rules/enforce-css-module-default-import'), 'enforce-css-module-identifier-casing': require('./rules/enforce-css-module-identifier-casing'), 'new-color-css-vars': require('./rules/new-color-css-vars'), + 'no-deprecated-components': require('./rules/no-deprecated-components'), 'no-deprecated-entrypoints': require('./rules/no-deprecated-entrypoints'), 'no-deprecated-experimental-components': require('./rules/no-deprecated-experimental-components'), 'no-deprecated-props': require('./rules/no-deprecated-props'), diff --git a/src/rules/__tests__/no-deprecated-components.test.js b/src/rules/__tests__/no-deprecated-components.test.js new file mode 100644 index 00000000..c72ab7bf --- /dev/null +++ b/src/rules/__tests__/no-deprecated-components.test.js @@ -0,0 +1,55 @@ +'use strict' + +const {RuleTester} = require('eslint') +const rule = require('../no-deprecated-components') + +const ruleTester = new RuleTester({ + languageOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, +}) + +const error = { + messageId: 'deprecatedComponent', + data: { + component: 'Flash', + replacement: 'Banner', + migrationGuide: 'https://primer.style/product/getting-started/react/migration-guides/primer-flash', + }, +} + +ruleTester.run('no-deprecated-components', 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-components.js b/src/rules/no-deprecated-components.js new file mode 100644 index 00000000..94207c12 --- /dev/null +++ b/src/rules/no-deprecated-components.js @@ -0,0 +1,66 @@ +'use strict' + +const url = require('../url') + +const migrationGuide = 'https://primer.style/product/getting-started/react/migration-guides/primer-flash' + +const deprecatedComponents = new Map([ + [ + 'Flash', + { + replacement: 'Banner', + migrationGuide, + }, + ], +]) + +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 deprecated Primer React components', + recommended: true, + url: url(module), + }, + messages: { + deprecatedComponent: + '`{{component}}` is deprecated. Use `{{replacement}}` 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 + } + + const component = deprecatedComponents.get(specifier.imported.name) + if (!component) { + continue + } + + context.report({ + node: specifier, + messageId: 'deprecatedComponent', + data: { + component: specifier.imported.name, + replacement: component.replacement, + migrationGuide: component.migrationGuide, + }, + }) + } + }, + } + }, +} From f2235092a4afb61e868905ca75fa5fb3fd6722bd Mon Sep 17 00:00:00 2001 From: "Brittany L. Houtz" <55068883+llastflowers@users.noreply.github.com> Date: Wed, 19 Aug 2026 14:27:52 -0700 Subject: [PATCH 2/3] Create curly-horses-fold.md --- .changeset/curly-horses-fold.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/curly-horses-fold.md 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 From b6fab6dad504ee9724159976f92c8f913420cf67 Mon Sep 17 00:00:00 2001 From: llastflowers Date: Wed, 19 Aug 2026 14:52:46 -0700 Subject: [PATCH 3/3] Make deprecated rule specific to Flash Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 70736adb-aaef-4999-bbdd-c76914f5f8aa --- README.md | 2 +- ...d-components.md => no-deprecated-flash.md} | 4 +-- src/configs/recommended.js | 2 +- src/index.js | 2 +- ...ts.test.js => no-deprecated-flash.test.js} | 13 +++------- ...d-components.js => no-deprecated-flash.js} | 26 +++---------------- 6 files changed, 12 insertions(+), 37 deletions(-) rename docs/rules/{no-deprecated-components.md => no-deprecated-flash.md} (80%) rename src/rules/__tests__/{no-deprecated-components.test.js => no-deprecated-flash.test.js} (72%) rename src/rules/{no-deprecated-components.js => no-deprecated-flash.js} (55%) diff --git a/README.md b/README.md index 62bcdbf8..d8153d55 100644 --- a/README.md +++ b/README.md @@ -43,9 +43,9 @@ ESLint rules for Primer React - [enforce-css-module-default-import](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/enforce-css-module-default-import.md) - [enforce-css-module-identifier-casing](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/enforce-css-module-identifier-casing.md) - [new-color-css-vars](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/new-color-css-vars.md) -- [no-deprecated-components](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/no-deprecated-components.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-components.md b/docs/rules/no-deprecated-flash.md similarity index 80% rename from docs/rules/no-deprecated-components.md rename to docs/rules/no-deprecated-flash.md index a20d942f..bb150a0c 100644 --- a/docs/rules/no-deprecated-components.md +++ b/docs/rules/no-deprecated-flash.md @@ -1,8 +1,8 @@ -# No deprecated components +# No deprecated Flash ## Rule details -This rule discourages imports of deprecated Primer React components from +This rule discourages imports of the deprecated `Flash` component from `@primer/react` and `@primer/react/deprecated`. 👎 Example of **incorrect** code for this rule: diff --git a/src/configs/recommended.js b/src/configs/recommended.js index 3611c978..5795b610 100644 --- a/src/configs/recommended.js +++ b/src/configs/recommended.js @@ -11,8 +11,8 @@ module.exports = { rules: { 'primer-react/direct-slot-children': 'error', - 'primer-react/no-deprecated-components': 'warn', '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 961b0e29..83981e91 100644 --- a/src/index.js +++ b/src/index.js @@ -12,9 +12,9 @@ module.exports = { 'enforce-css-module-default-import': require('./rules/enforce-css-module-default-import'), 'enforce-css-module-identifier-casing': require('./rules/enforce-css-module-identifier-casing'), 'new-color-css-vars': require('./rules/new-color-css-vars'), - 'no-deprecated-components': require('./rules/no-deprecated-components'), '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-components.test.js b/src/rules/__tests__/no-deprecated-flash.test.js similarity index 72% rename from src/rules/__tests__/no-deprecated-components.test.js rename to src/rules/__tests__/no-deprecated-flash.test.js index c72ab7bf..3697c7da 100644 --- a/src/rules/__tests__/no-deprecated-components.test.js +++ b/src/rules/__tests__/no-deprecated-flash.test.js @@ -1,7 +1,7 @@ 'use strict' const {RuleTester} = require('eslint') -const rule = require('../no-deprecated-components') +const rule = require('../no-deprecated-flash') const ruleTester = new RuleTester({ languageOptions: { @@ -10,16 +10,9 @@ const ruleTester = new RuleTester({ }, }) -const error = { - messageId: 'deprecatedComponent', - data: { - component: 'Flash', - replacement: 'Banner', - migrationGuide: 'https://primer.style/product/getting-started/react/migration-guides/primer-flash', - }, -} +const error = {messageId: 'deprecatedFlash'} -ruleTester.run('no-deprecated-components', rule, { +ruleTester.run('no-deprecated-flash', rule, { valid: [ { code: `import {Banner} from '@primer/react'`, diff --git a/src/rules/no-deprecated-components.js b/src/rules/no-deprecated-flash.js similarity index 55% rename from src/rules/no-deprecated-components.js rename to src/rules/no-deprecated-flash.js index 94207c12..3968ffd8 100644 --- a/src/rules/no-deprecated-components.js +++ b/src/rules/no-deprecated-flash.js @@ -3,17 +3,6 @@ const url = require('../url') const migrationGuide = 'https://primer.style/product/getting-started/react/migration-guides/primer-flash' - -const deprecatedComponents = new Map([ - [ - 'Flash', - { - replacement: 'Banner', - migrationGuide, - }, - ], -]) - const primerReactEntrypoints = new Set(['@primer/react', '@primer/react/deprecated']) /** @@ -23,13 +12,12 @@ module.exports = { meta: { type: 'problem', docs: { - description: 'Discourage the use of deprecated Primer React components', + description: 'Discourage the use of the deprecated Flash component', recommended: true, url: url(module), }, messages: { - deprecatedComponent: - '`{{component}}` is deprecated. Use `{{replacement}}` from `@primer/react` instead. See the migration guide: {{migrationGuide}}', + deprecatedFlash: `\`Flash\` is deprecated. Use \`Banner\` from \`@primer/react\` instead. See the migration guide: ${migrationGuide}`, }, schema: [], }, @@ -45,19 +33,13 @@ module.exports = { continue } - const component = deprecatedComponents.get(specifier.imported.name) - if (!component) { + if (specifier.imported.name !== 'Flash') { continue } context.report({ node: specifier, - messageId: 'deprecatedComponent', - data: { - component: specifier.imported.name, - replacement: component.replacement, - migrationGuide: component.migrationGuide, - }, + messageId: 'deprecatedFlash', }) } },