Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .changeset/curvy-pears-perform.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
"eslint-plugin-primer-react": minor
---

Add a `checkAllStrings` option to the `no-deprecated-colors` rule.

If `checkAllStrings` is set to `true`, the `no-deprecated-colors` rule will check for deprecated colors in all strings. This is useful for catching uses of deprecated colors outside system props and the `sx` prop.

```js
/* eslint primer-react/no-deprecated-colors: ["warn", {"checkAllStrings": true}] */
import {Box} from '@primer/components'

function ExampleComponent() {
const styles = {
// Enabling `checkAllStrings` will find deprecated colors used like this:
color: 'text.primary'
}
return <Box sx={styles}>Hello</Box>
}
```
36 changes: 33 additions & 3 deletions docs/rules/no-deprecated-colors.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const SystemPropExample() = () => <Box color="some.deprecated.color">Incorrect</

const SxPropExample() = () => <Box sx={{color: 'some.deprecated.color'}}>Incorrect</Box>

const SxPropExample2() = () => <Box sx={{boxShadow: theme => `0 1px 2px ${theme.colors.some.deprecated.color}`}}>Incorrect</Box>

const ThemeGetExample = styled.div`
color: ${themeGet('colors.some.deprecated.color')};
`
Expand All @@ -31,9 +33,11 @@ const ThemeGetExample = styled.div`
import {Box, themeGet} from '@primer/components'
import styled from 'styled-components'

const SystemPropExample() = () => <Box color="some.color">Incorrect</Box>
const SystemPropExample() = () => <Box color="some.color">Correct</Box>

const SxPropExample() = () => <Box sx={{color: 'some.color'}}>Correct</Box>

const SxPropExample() = () => <Box sx={{color: 'some.color'}}>Incorrect</Box>
const SxPropExample2() = () => <Box sx={{boxShadow: theme => `0 1px 2px ${theme.colors.some.color}`}}>Correct</Box>

const ThemeGetExample = styled.div`
color: ${themeGet('colors.some.color')};
Expand All @@ -46,7 +50,33 @@ const ThemeGetExample = styled.div`

By default, the `no-deprecated-colors` rule will only check for deprecated colors used in functions and components that are imported from `@primer/components`. You can disable this behavior by setting `skipImportCheck` to `true`. This is useful for linting custom components that pass color-related props down to Primer React components.

```js
/* eslint primer-react/no-deprecated-colors: ["warn", {"skipImportCheck": true}] */
import {Box} from '@primer/components'

function MyBox({color, children}) {
return <Box color={color}>{children}</Box>
}

function App() {
// Enabling `skipImportCheck` will find deprecated colors used like this:
return <MyBox color="text.primary">Hello</MyBox>
}
```
"primer-react/no-deprecated-colors": ["warn", {"skipImportCheck": true}]

- `checkAllStrings` (default: `false`)

If `checkAllStrings` is set to `true`, the `no-deprecated-colors` rule will check for deprecated colors in all strings. This is useful for catching uses of deprecated colors outside system props and the `sx` prop.

```js
/* eslint primer-react/no-deprecated-colors: ["warn", {"checkAllStrings": true}] */
import {Box} from '@primer/components'

function ExampleComponent() {
const styles = {
// Enabling `checkAllStrings` will find deprecated colors used like this:
color: 'text.primary'
}
return <Box sx={styles}>Hello</Box>
}
```
13 changes: 12 additions & 1 deletion src/rules/__tests__/no-deprecated-colors.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,20 @@ ruleTester.run('no-deprecated-colors', rule, {
`import {get} from "@other/constants"; get("space.text.primary")`,
`import {Box} from '@primer/components'; <Box sx={styles}>Hello</Box>`,
`import {Box} from '@primer/components'; <Box sx={{color: text.primary}}>Hello</Box>`,
`import {Box} from '@primer/components'; <Box sx={{color: "fg.default"}}>Hello</Box>`
`import {Box} from '@primer/components'; <Box sx={{color: "fg.default"}}>Hello</Box>`,
`{color: 'text.primary'}`
],
invalid: [
{
code: `{color: 'text.primary'}`,
output: `{color: "fg.default"}`,
options: [{checkAllStrings: true}],
errors: [
{
message: '"text.primary" is deprecated. Use "fg.default" instead.'
}
]
},
{
code: `import {Box} from "@primer/components"; function Example() { return <Box color="text.primary">Hello</Box> }`,
output: `import {Box} from "@primer/components"; function Example() { return <Box color="fg.default">Hello</Box> }`,
Expand Down
15 changes: 15 additions & 0 deletions src/rules/no-deprecated-colors.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ module.exports = {
properties: {
skipImportCheck: {
type: 'boolean'
},
checkAllStrings: {
type: 'boolean'
}
},
additionalProperties: false
Expand All @@ -24,7 +27,17 @@ module.exports = {
// used in any components (not just ones that are imported from `@primer/components`).
const skipImportCheck = context.options[0] ? context.options[0].skipImportCheck : false

const checkAllStrings = context.options[0] ? context.options[0].checkAllStrings : false

// Track visited string literals to avoid reporting the same string multiple times
const visitedStrings = new Set()

return {
Literal(node) {
if (checkAllStrings && Object.keys(deprecations).includes(node.value) && !visitedStrings.has(node)) {
replaceDeprecatedColor(context, node, node.value)
}
},
JSXOpeningElement(node) {
// Skip if component was not imported from @primer/components
if (!skipImportCheck && !isPrimerComponent(node.name, context.getScope(node))) {
Expand All @@ -50,6 +63,7 @@ module.exports = {

if (styledSystemColorProps.includes(propName) && Object.keys(deprecations).includes(propValue)) {
replaceDeprecatedColor(context, prop.value, propValue)
visitedStrings.add(prop.value)
}
}

Expand Down Expand Up @@ -86,6 +100,7 @@ module.exports = {
// Check if styled-system color prop is using a deprecated color
if (styledSystemColorProps.includes(propName) && Object.keys(deprecations).includes(propValue)) {
replaceDeprecatedColor(context, attribute.value, propValue)
visitedStrings.add(attribute.value)
}
}
},
Expand Down