eslint-plugin-primer-react 0.0.0-2021817225727
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.changeset/README.md +8 -0
- package/.changeset/config.json +10 -0
- package/.github/workflows/ci.yml +28 -0
- package/.github/workflows/release.yml +34 -0
- package/.github/workflows/release_canary.yml +61 -0
- package/.github/workflows/release_candidate.yml +59 -0
- package/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/README.md +32 -0
- package/docs/rules/no-deprecated-colors.md +42 -0
- package/package.json +39 -0
- package/src/configs/recommended.js +12 -0
- package/src/index.js +8 -0
- package/src/rules/__tests__/no-deprecated-colors.test.js +194 -0
- package/src/rules/no-deprecated-colors.js +173 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Changesets
|
|
2
|
+
|
|
3
|
+
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
|
4
|
+
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
|
5
|
+
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
|
6
|
+
|
|
7
|
+
We have a quick list of common questions to get you started engaging with this project in
|
|
8
|
+
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://unpkg.com/@changesets/config@1.6.0/schema.json",
|
|
3
|
+
"changelog": ["@changesets/changelog-github", {"repo": "primer/eslint-plugin-primer-react"}],
|
|
4
|
+
"commit": false,
|
|
5
|
+
"linked": [],
|
|
6
|
+
"access": "public",
|
|
7
|
+
"baseBranch": "main",
|
|
8
|
+
"updateInternalDependencies": "patch",
|
|
9
|
+
"ignore": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
strategy:
|
|
15
|
+
matrix:
|
|
16
|
+
node-version: [12.x, 14.x, 16.x]
|
|
17
|
+
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v2
|
|
21
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
22
|
+
uses: actions/setup-node@v2
|
|
23
|
+
with:
|
|
24
|
+
node-version: ${{ matrix.node-version }}
|
|
25
|
+
cache: 'npm'
|
|
26
|
+
- run: npm ci
|
|
27
|
+
- run: npm run build --if-present
|
|
28
|
+
- run: npm test
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- main
|
|
6
|
+
jobs:
|
|
7
|
+
release:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
steps:
|
|
10
|
+
- name: Checkout repository
|
|
11
|
+
uses: actions/checkout@v2
|
|
12
|
+
with:
|
|
13
|
+
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
|
|
14
|
+
fetch-depth: 0
|
|
15
|
+
persist-credentials: false
|
|
16
|
+
|
|
17
|
+
- name: Set up Node.js
|
|
18
|
+
uses: actions/setup-node@v2
|
|
19
|
+
with:
|
|
20
|
+
node-version: 14
|
|
21
|
+
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: npm ci
|
|
24
|
+
|
|
25
|
+
- name: Create release pull request or publish to npm
|
|
26
|
+
id: changesets
|
|
27
|
+
uses: changesets/action@master
|
|
28
|
+
with:
|
|
29
|
+
title: Release Tracking
|
|
30
|
+
# This expects you to have a script called release which does a build for your packages and calls changeset publish
|
|
31
|
+
publish: npm run release
|
|
32
|
+
env:
|
|
33
|
+
GITHUB_TOKEN: ${{ secrets.GPR_AUTH_TOKEN_SHARED }}
|
|
34
|
+
NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN_SHARED }}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: Release (canary)
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches-ignore:
|
|
5
|
+
- 'main'
|
|
6
|
+
- 'changeset-release/main'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
release:
|
|
10
|
+
if: ${{ github.repository == 'primer/eslint-plugin-primer-react' }}
|
|
11
|
+
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout repository
|
|
15
|
+
uses: actions/checkout@v2
|
|
16
|
+
with:
|
|
17
|
+
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
|
|
18
|
+
fetch-depth: 0
|
|
19
|
+
|
|
20
|
+
- name: Set up Node.js
|
|
21
|
+
uses: actions/setup-node@v2
|
|
22
|
+
with:
|
|
23
|
+
node-version: 14.x
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: npm ci
|
|
27
|
+
|
|
28
|
+
- name: Build
|
|
29
|
+
run: npm run build --if-present
|
|
30
|
+
|
|
31
|
+
- name: Create .npmrc
|
|
32
|
+
run: |
|
|
33
|
+
cat << EOF > "$HOME/.npmrc"
|
|
34
|
+
//registry.npmjs.org/:_authToken=$NPM_TOKEN
|
|
35
|
+
EOF
|
|
36
|
+
env:
|
|
37
|
+
NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN_SHARED }}
|
|
38
|
+
|
|
39
|
+
- name: Publish canary version
|
|
40
|
+
run: |
|
|
41
|
+
echo "$( jq '.version = "0.0.0"' package.json )" > package.json
|
|
42
|
+
echo -e "---\n'eslint-plugin-primer-react': patch\n---\n\nFake entry to force publishing" > .changeset/force-snapshot-release.md
|
|
43
|
+
yarn changeset version --snapshot
|
|
44
|
+
yarn changeset publish --tag canary
|
|
45
|
+
env:
|
|
46
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
47
|
+
|
|
48
|
+
- name: Output canary version number
|
|
49
|
+
uses: actions/github-script@v4.0.2
|
|
50
|
+
with:
|
|
51
|
+
script: |
|
|
52
|
+
const package = require(`${process.env.GITHUB_WORKSPACE}/package.json`)
|
|
53
|
+
github.repos.createCommitStatus({
|
|
54
|
+
owner: context.repo.owner,
|
|
55
|
+
repo: context.repo.repo,
|
|
56
|
+
sha: context.sha,
|
|
57
|
+
state: 'success',
|
|
58
|
+
context: `Published ${package.name}`,
|
|
59
|
+
description: package.version,
|
|
60
|
+
target_url: `https://unpkg.com/${package.name}@${package.version}/`
|
|
61
|
+
})
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: Release (candidate)
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- 'changeset-release/main'
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
release:
|
|
9
|
+
if: ${{ github.repository == 'primer/eslint-plugin-primer-react' }}
|
|
10
|
+
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- name: Checkout repository
|
|
14
|
+
uses: actions/checkout@v2
|
|
15
|
+
with:
|
|
16
|
+
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
|
|
17
|
+
fetch-depth: 0
|
|
18
|
+
|
|
19
|
+
- name: Set up Node.js
|
|
20
|
+
uses: actions/setup-node@v2
|
|
21
|
+
with:
|
|
22
|
+
node-version: 14.x
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: npm ci
|
|
26
|
+
|
|
27
|
+
- name: Build
|
|
28
|
+
run: npm run build --if-present
|
|
29
|
+
|
|
30
|
+
- name: Create .npmrc
|
|
31
|
+
run: |
|
|
32
|
+
cat << EOF > "$HOME/.npmrc"
|
|
33
|
+
//registry.npmjs.org/:_authToken=$NPM_TOKEN
|
|
34
|
+
EOF
|
|
35
|
+
env:
|
|
36
|
+
NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN_SHARED }}
|
|
37
|
+
|
|
38
|
+
- name: Publish release candidate
|
|
39
|
+
run: |
|
|
40
|
+
version=$(jq -r .version package.json)
|
|
41
|
+
echo "$( jq ".version = \"$(echo $version)-rc.$(git rev-parse --short HEAD)\"" package.json )" > package.json
|
|
42
|
+
yarn publish --tag next
|
|
43
|
+
env:
|
|
44
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
45
|
+
|
|
46
|
+
- name: Output release candidate version number
|
|
47
|
+
uses: actions/github-script@v4.0.2
|
|
48
|
+
with:
|
|
49
|
+
script: |
|
|
50
|
+
const package = require(`${process.env.GITHUB_WORKSPACE}/package.json`)
|
|
51
|
+
github.repos.createCommitStatus({
|
|
52
|
+
owner: context.repo.owner,
|
|
53
|
+
repo: context.repo.repo,
|
|
54
|
+
sha: context.sha,
|
|
55
|
+
state: 'success',
|
|
56
|
+
context: `Published ${package.name}`,
|
|
57
|
+
description: package.version,
|
|
58
|
+
target_url: `https://unpkg.com/${package.name}@${package.version}/`
|
|
59
|
+
})
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# eslint-plugin-primer-react
|
|
2
|
+
|
|
3
|
+
## 0.0.0-2021817225727
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fake entry to force publishing
|
|
8
|
+
|
|
9
|
+
## 0.4.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#3](https://github.com/primer/eslint-plugin-primer-react/pull/3) [`8e9144f`](https://github.com/primer/eslint-plugin-primer-react/commit/8e9144fd7a9ff1bb99878dca61621351026ddc82) Thanks [@colebemis](https://github.com/colebemis)! - Add type metadata to no-deprecated-colors rule
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Primer
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# eslint-plugin-primer-react
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/eslint-plugin-primer-react)
|
|
4
|
+
|
|
5
|
+
ESLint rules for Primer React
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
1. Assuming you already have [ESLint](https://www.npmjs.com/package/eslint) and [Primer React](https://github.com/primer/react) installed, run:
|
|
10
|
+
|
|
11
|
+
```shell
|
|
12
|
+
npm install --save-dev eslint-plugin-primer-react
|
|
13
|
+
|
|
14
|
+
# or
|
|
15
|
+
|
|
16
|
+
yarn add --dev eslint-plugin-primer-react
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
2. In your [ESLint configuration file](https://eslint.org/docs/user-guide/configuring/configuration-files), extend the recommended Primer React ESLint config:
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
{
|
|
23
|
+
"extends": [
|
|
24
|
+
// ...
|
|
25
|
+
"plugin:primer-react/recommended"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Rules
|
|
31
|
+
|
|
32
|
+
- [no-deprecated-colors](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/no-deprecated-colors.md)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Disallow references to deprecated color variables (no-deprecated-colors)
|
|
2
|
+
|
|
3
|
+
🔧 The `--fix` option on the [ESLint CLI](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule.
|
|
4
|
+
|
|
5
|
+
[Theming](https://primer.style/react/theming) in Primer React is made possible by a theme object that defines your application's colors, spacing, fonts, and more. The color variables in Primer React's [default theme object](https://primer.style/react/theme-reference) are pulled from [Primer Primitives](https://github.com/primer/primitives). When a color variable is deprecated in Primer Primitives, it's important to remove references to that color variable in your application before it's removed from the library.
|
|
6
|
+
|
|
7
|
+
## Rule details
|
|
8
|
+
|
|
9
|
+
This rule disallows references to color variables that are deprecated in [Primer Primitives](https://github.com/primer/primitives).
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
👎 Examples of **incorrect** code for this rule:
|
|
13
|
+
|
|
14
|
+
```jsx
|
|
15
|
+
/* eslint primer-react/no-deprecated-colors: "error" */
|
|
16
|
+
import {Box, themeGet} from '@primer/components'
|
|
17
|
+
import styled from 'styled-components'
|
|
18
|
+
|
|
19
|
+
const SystemPropExample() = () => <Box color="some.deprecated.color">Incorrect</Box>
|
|
20
|
+
|
|
21
|
+
const SxPropExample() = () => <Box sx={{color: 'some.deprecated.color'}}>Incorrect</Box>
|
|
22
|
+
|
|
23
|
+
const ThemeGetExample = styled.div`
|
|
24
|
+
color: ${themeGet('some.deprecated.color')};
|
|
25
|
+
`
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
👍 Examples of **correct** code for this rule:
|
|
29
|
+
|
|
30
|
+
```jsx
|
|
31
|
+
/* eslint primer-react/no-deprecated-colors: "error" */
|
|
32
|
+
import {Box, themeGet} from '@primer/components'
|
|
33
|
+
import styled from 'styled-components'
|
|
34
|
+
|
|
35
|
+
const SystemPropExample() = () => <Box color="some.color">Incorrect</Box>
|
|
36
|
+
|
|
37
|
+
const SxPropExample() = () => <Box sx={{color: 'some.color'}}>Incorrect</Box>
|
|
38
|
+
|
|
39
|
+
const ThemeGetExample = styled.div`
|
|
40
|
+
color: ${themeGet('some.color')};
|
|
41
|
+
`
|
|
42
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "eslint-plugin-primer-react",
|
|
3
|
+
"version": "0.0.0-2021817225727",
|
|
4
|
+
"description": "ESLint rules for Primer React",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "jest",
|
|
8
|
+
"release": "changeset publish"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/primer/eslint-plugin-primer-react.git"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"eslint",
|
|
16
|
+
"eslintplugin"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/primer/eslint-plugin-primer-react/issues"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/primer/eslint-plugin-primer-react#readme",
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@changesets/changelog-github": "^0.4.0",
|
|
25
|
+
"@changesets/cli": "^2.16.0",
|
|
26
|
+
"@github/prettier-config": "0.0.4",
|
|
27
|
+
"@primer/primitives": "^4.6.2",
|
|
28
|
+
"eslint": "^7.32.0",
|
|
29
|
+
"jest": "^27.0.6"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"eslint": ">=4.19.0",
|
|
33
|
+
"@primer/primitives": ">=4.6.2"
|
|
34
|
+
},
|
|
35
|
+
"prettier": "@github/prettier-config",
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"eslint-traverse": "^1.0.0"
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
const rule = require('../no-deprecated-colors')
|
|
2
|
+
const {RuleTester} = require('eslint')
|
|
3
|
+
|
|
4
|
+
const testDeprecations = {
|
|
5
|
+
'text.primary': 'fg.default',
|
|
6
|
+
'bg.primary': 'canvas.default',
|
|
7
|
+
'auto.green.5': ['success.fg', 'success.emphasis'],
|
|
8
|
+
'fade.fg10': null,
|
|
9
|
+
'autocomplete.shadow': 'shadow.medium'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
jest.mock('@primer/primitives/dist/deprecations/colors', () => testDeprecations)
|
|
13
|
+
|
|
14
|
+
const ruleTester = new RuleTester({
|
|
15
|
+
parserOptions: {
|
|
16
|
+
ecmaVersion: 'latest',
|
|
17
|
+
sourceType: 'module',
|
|
18
|
+
ecmaFeatures: {
|
|
19
|
+
jsx: true
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
ruleTester.run('no-deprecated-colors', rule, {
|
|
25
|
+
valid: [
|
|
26
|
+
`import {Box} from '@other/design-system'; <Box color="text.primary">Hello</Box>`,
|
|
27
|
+
`import {Box} from "@primer/components"; <Box color="fg.default">Hello</Box>`,
|
|
28
|
+
`import {hello} from "@primer/components"; hello("colors.text.primary")`,
|
|
29
|
+
`import {themeGet} from "@primer/components"; themeGet("space.text.primary")`,
|
|
30
|
+
`import {themeGet} from "@other/design-system"; themeGet("colors.text.primary")`,
|
|
31
|
+
`import {get} from "@other/constants"; get("space.text.primary")`,
|
|
32
|
+
`import {Box} from '@primer/components'; <Box sx={styles}>Hello</Box>`,
|
|
33
|
+
`import {Box} from '@primer/components'; <Box sx={{color: text.primary}}>Hello</Box>`,
|
|
34
|
+
`import {Box} from '@primer/components'; <Box sx={{color: "fg.default"}}>Hello</Box>`
|
|
35
|
+
],
|
|
36
|
+
invalid: [
|
|
37
|
+
{
|
|
38
|
+
code: `import {Box} from "@primer/components"; function Example() { return <Box color="text.primary">Hello</Box> }`,
|
|
39
|
+
output: `import {Box} from "@primer/components"; function Example() { return <Box color="fg.default">Hello</Box> }`,
|
|
40
|
+
errors: [
|
|
41
|
+
{
|
|
42
|
+
message: '"text.primary" is deprecated. Use "fg.default" instead.'
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
code: `import Box from '@primer/components/lib-esm/Box'; function Example() { return <Box color="text.primary">Hello</Box> }`,
|
|
48
|
+
output: `import Box from '@primer/components/lib-esm/Box'; function Example() { return <Box color="fg.default">Hello</Box> }`,
|
|
49
|
+
errors: [
|
|
50
|
+
{
|
|
51
|
+
message: '"text.primary" is deprecated. Use "fg.default" instead.'
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
code: `import {Box} from "@primer/components"; const Example = () => <Box color="text.primary">Hello</Box>`,
|
|
57
|
+
output: `import {Box} from "@primer/components"; const Example = () => <Box color="fg.default">Hello</Box>`,
|
|
58
|
+
errors: [
|
|
59
|
+
{
|
|
60
|
+
message: '"text.primary" is deprecated. Use "fg.default" instead.'
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
code: `import {Box} from "@primer/components"; <Box bg="bg.primary" m={1} />`,
|
|
66
|
+
output: `import {Box} from "@primer/components"; <Box bg="canvas.default" m={1} />`,
|
|
67
|
+
errors: [
|
|
68
|
+
{
|
|
69
|
+
message: '"bg.primary" is deprecated. Use "canvas.default" instead.'
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
code: `import {Box} from "@primer/components"; <Box sx={{bg: "bg.primary", m: 1, ...rest}} />`,
|
|
75
|
+
output: `import {Box} from "@primer/components"; <Box sx={{bg: "canvas.default", m: 1, ...rest}} />`,
|
|
76
|
+
errors: [
|
|
77
|
+
{
|
|
78
|
+
message: '"bg.primary" is deprecated. Use "canvas.default" instead.'
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
code: `import {Box} from "@primer/components"; <Box sx={{boxShadow: theme => theme.shadows.autocomplete.shadow}} />`,
|
|
84
|
+
output: `import {Box} from "@primer/components"; <Box sx={{boxShadow: theme => theme.shadows.shadow.medium}} />`,
|
|
85
|
+
errors: [
|
|
86
|
+
{
|
|
87
|
+
message: '"theme.shadows.autocomplete.shadow" is deprecated. Use "theme.shadows.shadow.medium" instead.'
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
code: `import {Box} from "@primer/components"; <Box sx={{boxShadow: theme => \`0 1px 2px \${theme.colors.text.primary}\`}} />`,
|
|
93
|
+
output: `import {Box} from "@primer/components"; <Box sx={{boxShadow: theme => \`0 1px 2px \${theme.colors.fg.default}\`}} />`,
|
|
94
|
+
errors: [
|
|
95
|
+
{
|
|
96
|
+
message: '"theme.colors.text.primary" is deprecated. Use "theme.colors.fg.default" instead.'
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
code: `import {Box} from "@primer/components"; <Box sx={{boxShadow: t => \`0 1px 2px \${t.colors.text.primary}\`}} />`,
|
|
102
|
+
output: `import {Box} from "@primer/components"; <Box sx={{boxShadow: t => \`0 1px 2px \${t.colors.fg.default}\`}} />`,
|
|
103
|
+
errors: [
|
|
104
|
+
{
|
|
105
|
+
message: '"t.colors.text.primary" is deprecated. Use "t.colors.fg.default" instead.'
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
code: `import {Box} from "@primer/components"; <Box sx={{"&:hover": {bg: "bg.primary"}}} />`,
|
|
111
|
+
output: `import {Box} from "@primer/components"; <Box sx={{"&:hover": {bg: "canvas.default"}}} />`,
|
|
112
|
+
errors: [
|
|
113
|
+
{
|
|
114
|
+
message: '"bg.primary" is deprecated. Use "canvas.default" instead.'
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
code: `import {Box} from "@primer/components"; <Box color="auto.green.5" />`,
|
|
120
|
+
errors: [
|
|
121
|
+
{
|
|
122
|
+
message: '"auto.green.5" is deprecated.',
|
|
123
|
+
suggestions: [
|
|
124
|
+
{
|
|
125
|
+
desc: 'Use "success.fg" instead.',
|
|
126
|
+
output: `import {Box} from "@primer/components"; <Box color="success.fg" />`
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
desc: 'Use "success.emphasis" instead.',
|
|
130
|
+
output: `import {Box} from "@primer/components"; <Box color="success.emphasis" />`
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
code: `import {Box} from "@primer/components"; <Box color="fade.fg10" />`,
|
|
138
|
+
errors: [
|
|
139
|
+
{
|
|
140
|
+
message:
|
|
141
|
+
'"fade.fg10" is deprecated. Go to https://primer.style/primitives or reach out in the #primer channel on Slack to find a suitable replacement.'
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
code: `import {Box, Text} from "@primer/components"; <Box bg="bg.primary"><Text color="text.primary">Hello</Text></Box>`,
|
|
147
|
+
output: `import {Box, Text} from "@primer/components"; <Box bg="canvas.default"><Text color="fg.default">Hello</Text></Box>`,
|
|
148
|
+
errors: [
|
|
149
|
+
{
|
|
150
|
+
message: '"bg.primary" is deprecated. Use "canvas.default" instead.'
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
message: '"text.primary" is deprecated. Use "fg.default" instead.'
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
code: `import {themeGet} from "@primer/components"; themeGet("colors.text.primary")`,
|
|
159
|
+
output: `import {themeGet} from "@primer/components"; themeGet("colors.fg.default")`,
|
|
160
|
+
errors: [
|
|
161
|
+
{
|
|
162
|
+
message: '"colors.text.primary" is deprecated. Use "colors.fg.default" instead.'
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
code: `import {themeGet} from "@primer/components"; themeGet("shadows.autocomplete.shadow")`,
|
|
168
|
+
output: `import {themeGet} from "@primer/components"; themeGet("shadows.shadow.medium")`,
|
|
169
|
+
errors: [
|
|
170
|
+
{
|
|
171
|
+
message: '"shadows.autocomplete.shadow" is deprecated. Use "shadows.shadow.medium" instead.'
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
code: `import {get} from "./constants"; get("colors.text.primary")`,
|
|
177
|
+
output: `import {get} from "./constants"; get("colors.fg.default")`,
|
|
178
|
+
errors: [
|
|
179
|
+
{
|
|
180
|
+
message: '"colors.text.primary" is deprecated. Use "colors.fg.default" instead.'
|
|
181
|
+
}
|
|
182
|
+
]
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
code: `import {get} from "../constants"; get("colors.text.primary")`,
|
|
186
|
+
output: `import {get} from "../constants"; get("colors.fg.default")`,
|
|
187
|
+
errors: [
|
|
188
|
+
{
|
|
189
|
+
message: '"colors.text.primary" is deprecated. Use "colors.fg.default" instead.'
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
]
|
|
194
|
+
})
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
const deprecations = require('@primer/primitives/dist/deprecations/colors')
|
|
2
|
+
const traverse = require('eslint-traverse')
|
|
3
|
+
|
|
4
|
+
const styledSystemColorProps = ['color', 'bg', 'backgroundColor', 'borderColor', 'textShadow', 'boxShadow']
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
meta: {
|
|
8
|
+
type: 'suggestion',
|
|
9
|
+
fixable: 'code'
|
|
10
|
+
},
|
|
11
|
+
create(context) {
|
|
12
|
+
return {
|
|
13
|
+
JSXOpeningElement(node) {
|
|
14
|
+
// Skip if component was not imported from @primer/components
|
|
15
|
+
if (!isPrimerComponent(node.name, context.getScope(node))) {
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
for (const attribute of node.attributes) {
|
|
20
|
+
if (!attribute.name || !attribute.value) {
|
|
21
|
+
continue
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const propName = attribute.name.name
|
|
25
|
+
const propValue = attribute.value.value
|
|
26
|
+
|
|
27
|
+
// Check for the sx prop
|
|
28
|
+
if (propName === 'sx' && attribute.value.expression.type === 'ObjectExpression') {
|
|
29
|
+
// Search all properties of the sx object (even nested properties)
|
|
30
|
+
traverse(context, attribute.value, path => {
|
|
31
|
+
if (path.node.type === 'Property' && path.node.value.type === 'Literal') {
|
|
32
|
+
const prop = path.node
|
|
33
|
+
const propName = prop.key.name
|
|
34
|
+
const propValue = prop.value.value
|
|
35
|
+
|
|
36
|
+
if (styledSystemColorProps.includes(propName) && Object.keys(deprecations).includes(propValue)) {
|
|
37
|
+
replaceDeprecatedColor(context, prop.value, propValue)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Check functions passed to sx object properties
|
|
42
|
+
// (e.g. boxShadow: theme => `0 1px 2px ${theme.colors.text.primary}` )
|
|
43
|
+
if (path.node.type === 'Property' && path.node.value.type === 'ArrowFunctionExpression') {
|
|
44
|
+
traverse(context, path.node.value.body, path => {
|
|
45
|
+
if (path.node.type === 'MemberExpression') {
|
|
46
|
+
// Convert MemberExpression AST to string
|
|
47
|
+
const code = context.getSourceCode().getText(path.node)
|
|
48
|
+
|
|
49
|
+
const [param, key, ...rest] = code.split('.')
|
|
50
|
+
const name = rest.join('.')
|
|
51
|
+
|
|
52
|
+
if (['colors', 'shadows'].includes(key) && Object.keys(deprecations).includes(name)) {
|
|
53
|
+
replaceDeprecatedColor(
|
|
54
|
+
context,
|
|
55
|
+
path.node,
|
|
56
|
+
name,
|
|
57
|
+
str => [param, key, str].join('.'),
|
|
58
|
+
str => str
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Don't traverse any nested member expressions.
|
|
63
|
+
// The root-level member expression gives us all the data we need.
|
|
64
|
+
return traverse.SKIP
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Check if styled-system color prop is using a deprecated color
|
|
72
|
+
if (styledSystemColorProps.includes(propName) && Object.keys(deprecations).includes(propValue)) {
|
|
73
|
+
replaceDeprecatedColor(context, attribute.value, propValue)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
CallExpression(node) {
|
|
78
|
+
// Skip if not calling the `themeGet` or `get` function
|
|
79
|
+
// `get` is the internal version of `themeGet` that's used in the primer/react repository
|
|
80
|
+
if (!isThemeGet(node.callee, context.getScope(node)) && !isGet(node.callee, context.getScope(node))) {
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const [key, ...path] = node.arguments[0].value.split('.')
|
|
85
|
+
const name = path.join('.')
|
|
86
|
+
|
|
87
|
+
if (['colors', 'shadows'].includes(key) && Object.keys(deprecations).includes(name)) {
|
|
88
|
+
replaceDeprecatedColor(context, node.arguments[0], name, str => [key, str].join('.'))
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get the variable declaration for the given identifier
|
|
97
|
+
*/
|
|
98
|
+
function getVariableDeclaration(scope, identifier) {
|
|
99
|
+
if (scope === null) {
|
|
100
|
+
return null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
for (const variable of scope.variables) {
|
|
104
|
+
if (variable.name === identifier.name) {
|
|
105
|
+
return variable.defs[0]
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return getVariableDeclaration(scope.upper, identifier)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Check if the given identifier is imported from the given module
|
|
114
|
+
*/
|
|
115
|
+
function isImportedFrom(moduleRegex, identifier, scope) {
|
|
116
|
+
const definition = getVariableDeclaration(scope, identifier)
|
|
117
|
+
|
|
118
|
+
// Return true if the variable was imported from the given module
|
|
119
|
+
return definition && definition.type == 'ImportBinding' && moduleRegex.test(definition.parent.source.value)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function isPrimerComponent(identifier, scope) {
|
|
123
|
+
return isImportedFrom(/^@primer\/components/, identifier, scope)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function isThemeGet(identifier, scope) {
|
|
127
|
+
return isImportedFrom(/^@primer\/components/, identifier, scope) && identifier.name === 'themeGet'
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function isGet(identifier, scope) {
|
|
131
|
+
return isImportedFrom(/^\.\.?\/constants$/, identifier, scope) && identifier.name === 'get'
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function replaceDeprecatedColor(
|
|
135
|
+
context,
|
|
136
|
+
node,
|
|
137
|
+
deprecatedName,
|
|
138
|
+
transformName = str => str,
|
|
139
|
+
transformReplacementValue = str => JSON.stringify(str)
|
|
140
|
+
) {
|
|
141
|
+
const replacement = deprecations[deprecatedName]
|
|
142
|
+
|
|
143
|
+
if (replacement === null) {
|
|
144
|
+
// No replacement
|
|
145
|
+
context.report({
|
|
146
|
+
node,
|
|
147
|
+
message: `"${transformName(
|
|
148
|
+
deprecatedName
|
|
149
|
+
)}" is deprecated. Go to https://primer.style/primitives or reach out in the #primer channel on Slack to find a suitable replacement.`
|
|
150
|
+
})
|
|
151
|
+
} else if (Array.isArray(replacement)) {
|
|
152
|
+
// Multiple possible replacements
|
|
153
|
+
context.report({
|
|
154
|
+
node,
|
|
155
|
+
message: `"${transformName(deprecatedName)}" is deprecated.`,
|
|
156
|
+
suggest: replacement.map(replacementValue => ({
|
|
157
|
+
desc: `Use "${transformName(replacementValue)}" instead.`,
|
|
158
|
+
fix(fixer) {
|
|
159
|
+
return fixer.replaceText(node, transformReplacementValue(transformName(replacementValue)))
|
|
160
|
+
}
|
|
161
|
+
}))
|
|
162
|
+
})
|
|
163
|
+
} else {
|
|
164
|
+
// One replacement
|
|
165
|
+
context.report({
|
|
166
|
+
node,
|
|
167
|
+
message: `"${transformName(deprecatedName)}" is deprecated. Use "${transformName(replacement)}" instead.`,
|
|
168
|
+
fix(fixer) {
|
|
169
|
+
return fixer.replaceText(node, transformReplacementValue(transformName(replacement)))
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
}
|