Skip to content

Commit

Permalink
chore(eslint): add eslint support (#89)
Browse files Browse the repository at this point in the history
* chore(deps): add eslint dependencies

* ci: add lint job

* chore(eslint): update eslint config

* refactor: update code to fix eslint errors

* chore: change in to of

* Update ci.yml

* chore: run prettier, add markdownlint

* ci: add lint:md task to lint job, add format job

* chore: run format
  • Loading branch information
joshblack authored Oct 12, 2023
1 parent fc0af87 commit 5257a79
Show file tree
Hide file tree
Showing 25 changed files with 1,284 additions and 480 deletions.
6 changes: 3 additions & 3 deletions .changeset/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Changesets

Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works with
multi-package repos, or single-package repos to help you version and publish your code. You can find the full
documentation for it [in our repository](https://github.com/changesets/changesets)

We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
39 changes: 39 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use strict'

/**
* @type {import('eslint').Linter.Config}
*/
module.exports = {
extends: ['eslint:recommended', 'plugin:github/recommended'],
parserOptions: {
ecmaVersion: 'latest'
},
env: {
commonjs: true,
node: true
},
rules: {
'import/no-commonjs': 'off',
'no-shadow': 'off',
'no-unused-vars': [
'error',
{
varsIgnorePattern: '^_'
}
]
},
overrides: [
{
files: ['**/*.test.js'],
env: {
jest: true
}
},
{
files: ['.eslintrc.js'],
rules: {
'filenames/match-regex': 'off'
}
}
]
}
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ on:
branches: [main]

jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 18
cache: 'npm'
- run: npm ci
- run: npm run format:check

test:
runs-on: ubuntu-latest
steps:
Expand All @@ -17,3 +29,16 @@ jobs:
cache: 'npm'
- run: npm ci
- run: npm test

lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 18
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run lint:md
26 changes: 26 additions & 0 deletions .markdownlint-cli2.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use strict'

const githubMarkdownOpinions = require('@github/markdownlint-github')

const options = githubMarkdownOpinions.init({
// Rules we don't care to enforce (usually stylistic)
'line-length': false,
'blanks-around-headings': false,
'blanks-around-lists': false,
'no-trailing-spaces': false,
'no-multiple-blanks': false,
'no-trailing-punctuation': false,
'single-trailing-newline': false,
'ul-indent': false,
'ul-style': false,
'no-hard-tabs': false,
'first-line-heading': false,
'no-space-in-emphasis': false,
'blanks-around-fences': false
})

module.exports = {
config: options,
customRules: ['@github/markdownlint-github'],
outputFormatters: [['markdownlint-cli2-formatter-pretty', {appendLink: true}]]
}
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.changeset
node_modules
CHANGELOG.md
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ ESLint rules for Primer React

## Installation

1. Assuming you already have [ESLint](https://www.npmjs.com/package/eslint) and [Primer React](https://github.com/primer/react) installed, run:
1. Assuming you already have [ESLint](https://www.npmjs.com/package/eslint) and
[Primer React](https://github.com/primer/react) installed, run:

```shell
npm install --save-dev eslint-plugin-primer-react
Expand All @@ -16,7 +17,8 @@ ESLint rules for Primer React
yarn add --dev eslint-plugin-primer-react
```

2. In your [ESLint configuration file](https://eslint.org/docs/user-guide/configuring/configuration-files), extend the recommended Primer React ESLint config:
2. In your [ESLint configuration file](https://eslint.org/docs/user-guide/configuring/configuration-files), extend the
recommended Primer React ESLint config:

```js
{
Expand Down
24 changes: 17 additions & 7 deletions docs/rules/a11y-explicit-heading.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,47 @@
## Require explicit heading level on `<Heading>` component

The `Heading` component does not require you to use `as` to specify the heading level, as it will default to an `h2` if one isn't specified. This may lead to inaccessible usage if the default is out of order in the existing heading hierarchy.
The `Heading` component does not require you to use `as` to specify the heading level, as it will default to an `h2` if
one isn't specified. This may lead to inaccessible usage if the default is out of order in the existing heading
hierarchy.

## Rule Details

This rule enforces using `as` on the `<Heading>` component to specify a heading level (`h1`-`h6`). In addition, it enforces `as` usage to only be used for headings.
This rule enforces using `as` on the `<Heading>` component to specify a heading level (`h1`-`h6`). In addition, it
enforces `as` usage to only be used for headings.

👎 Examples of **incorrect** code for this rule

```jsx
import {Heading} from '@primer/react'

<Heading>Heading without explicit heading level</Heading>
function ExampleComponent() {
return <Heading>Heading without explicit heading level</Heading>
}
```

`as` must only be for headings (`h1`-`h6`)

```jsx
import {Heading} from '@primer/react'

<Heading as="span">Heading component used as "span"</Heading>
function ExampleComponent() {
return <Heading as="span">Heading component used as "span"</Heading>
}
```

👍 Examples of **correct** code for this rule:

```jsx
import {Heading} from '@primer/react';
import {Heading} from '@primer/react'

<Heading as="h2">Heading level 2</Heading>
function ExampleComponent() {
return <Heading as="h2">Heading level 2</Heading>
}
```

## Options

- `skipImportCheck` (default: `false`)

By default, the `a11y-explicit-heading` rule will only check for `<Heading>` components imported directly from `@primer/react`. You can disable this behavior by setting `skipImportCheck` to `true`.
By default, the `a11y-explicit-heading` rule will only check for `<Heading>` components imported directly from
`@primer/react`. You can disable this behavior by setting `skipImportCheck` to `true`.
8 changes: 6 additions & 2 deletions docs/rules/a11y-tooltip-interactive-trigger.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
## Rule Details

This rule enforces to use interactive elements as tooltip triggers. Interactive elements can be Primer `Button`, `IconButton` and `Link` components or native elements like `button`, `a` with an `href` attribute, `select`, `textarea`, `summary` and `input` (that is not a `hidden` type).
This rule enforces to use interactive elements as tooltip triggers. Interactive elements can be Primer `Button`,
`IconButton` and `Link` components or native elements like `button`, `a` with an `href` attribute, `select`, `textarea`,
`summary` and `input` (that is not a `hidden` type).

👎 Examples of **incorrect** code for this rule:

Expand Down Expand Up @@ -38,4 +40,6 @@ const App = () => (

- `skipImportCheck` (default: `false`)

By default, the `a11y-tooltip-interactive-trigger` rule will only check for interactive elements in components that are imported from `@primer/react`. You can disable this behavior by setting `skipImportCheck` to `true`. This is used for internal linting in the [primer/react](https://github.com/prime/react) repository.
By default, the `a11y-tooltip-interactive-trigger` rule will only check for interactive elements in components that
are imported from `@primer/react`. You can disable this behavior by setting `skipImportCheck` to `true`. This is used
for internal linting in the [primer/react](https://github.com/prime/react) repository.
95 changes: 49 additions & 46 deletions docs/rules/direct-slot-children.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,49 @@
# Enforce direct parent-child relationship of slot components (direct-slot-children)

Some Primer React components use a slots pattern under the hood to render subcomponents in specific places. For example, the `PageLayout` component renders `PageLayout.Header` in the header area, and `PageLayout.Footer` in the footer area. These subcomponents must be direct children of the parent component, and cannot be nested inside other components.

## Rule details

This rule enforces that slot components are direct children of their parent component.

👎 Examples of **incorrect** code for this rule:

```jsx
/* eslint primer-react/direct-slot-children: "error" */
import {PageLayout} from '@primer/react'

const MyHeader = () => <PageLayout.Header>Header</PageLayout.Header>

const App = () => (
<PageLayout>
<MyHeader />
</PageLayout>
)
```

👍 Examples of **correct** code for this rule:

```jsx
/* eslint primer-react/direct-slot-children: "error" */
import {PageLayout} from '@primer/react'

const MyHeader = () => <div>Header</div>

const App = () => (
<PageLayout>
<PageLayout.Header>
<MyHeader />
</PageLayout.Header>
</PageLayout>
)
```

## Options

- `skipImportCheck` (default: `false`)

By default, the `direct-slot-children` rule will only check for direct slot children in components that are imported from `@primer/react`. You can disable this behavior by setting `skipImportCheck` to `true`. This is used for internal linting in the [primer/react](https://github.com/prime/react) repository.

# Enforce direct parent-child relationship of slot components (direct-slot-children)

Some Primer React components use a slots pattern under the hood to render subcomponents in specific places. For example,
the `PageLayout` component renders `PageLayout.Header` in the header area, and `PageLayout.Footer` in the footer area.
These subcomponents must be direct children of the parent component, and cannot be nested inside other components.

## Rule details

This rule enforces that slot components are direct children of their parent component.

👎 Examples of **incorrect** code for this rule:

```jsx
/* eslint primer-react/direct-slot-children: "error" */
import {PageLayout} from '@primer/react'

const MyHeader = () => <PageLayout.Header>Header</PageLayout.Header>

const App = () => (
<PageLayout>
<MyHeader />
</PageLayout>
)
```

👍 Examples of **correct** code for this rule:

```jsx
/* eslint primer-react/direct-slot-children: "error" */
import {PageLayout} from '@primer/react'

const MyHeader = () => <div>Header</div>

const App = () => (
<PageLayout>
<PageLayout.Header>
<MyHeader />
</PageLayout.Header>
</PageLayout>
)
```

## Options

- `skipImportCheck` (default: `false`)

By default, the `direct-slot-children` rule will only check for direct slot children in components that are imported
from `@primer/react`. You can disable this behavior by setting `skipImportCheck` to `true`. This is used for internal
linting in the [primer/react](https://github.com/prime/react) repository.
33 changes: 19 additions & 14 deletions docs/rules/new-css-color-vars.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
## Upgrade legacy color CSS variables to Primitives v8 in sx prop

CSS variables are allowed within the `sx` prop in Primer React components. However, the legacy color CSS variables are deprecated in favor of the new CSS variables introduced in Primitives v8. This rule will warn you if you are using the deprecated color CSS variables in the `sx` prop, and autofix it including a fallback to the old value.
CSS variables are allowed within the `sx` prop in Primer React components. However, the legacy color CSS variables are
deprecated in favor of the new CSS variables introduced in Primitives v8. This rule will warn you if you are using the
deprecated color CSS variables in the `sx` prop, and autofix it including a fallback to the old value.

## Rule Details

This rule looks inside the `sx` prop for the following properties:

```
'bg',
'backgroundColor',
'color',
'borderColor',
'borderTopColor',
'borderRightColor',
'borderBottomColor',
'borderLeftColor',
'border',
'boxShadow',
'caretColor'
```json
[
"bg",
"backgroundColor",
"color",
"borderColor",
"borderTopColor",
"borderRightColor",
"borderBottomColor",
"borderLeftColor",
"border",
"boxShadow",
"caretColor"
]
```

The rule references a static JSON file called `css-variable-map.json` that matches the old color CSS variables to a new one based on the property. We only check `sx` because `stylelint` is used to lint other forms of CSS-in-JS.
The rule references a static JSON file called `css-variable-map.json` that matches the old color CSS variables to a new
one based on the property. We only check `sx` because `stylelint` is used to lint other forms of CSS-in-JS.

👎 Examples of **incorrect** code for this rule

Expand Down
Loading

0 comments on commit 5257a79

Please sign in to comment.