Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create ESLint plugin for Griffel #99

Merged
merged 2 commits into from
Apr 22, 2022
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "none",
"comment": "add a comment to exports",
"packageName": "@griffel/core",
"email": "[email protected]",
"dependentChangeType": "none"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "major",
"comment": "initial release",
"packageName": "@griffel/eslint-plugin",
"email": "[email protected]",
"dependentChangeType": "patch"
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"@emotion/hash": "^0.8.0",
"@linaria/babel-preset": "^3.0.0-beta.14",
"@linaria/shaker": "^3.0.0-beta.14",
"@typescript-eslint/utils": "^5.20.0",
"ajv": "^8.4.0",
"csstype": "^3.0.10",
"enhanced-resolve": "^5.8.2",
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,5 @@ export type {
GriffelRenderer,
} from './types';

// Private exports, are used by devtools
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe prefix with @internal and then strip on build and use stripInternal in the tsconfig ?

you'll be able to use it with aliases in the monorepo but the types will be stripped on build

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't know about stripInternal, it's a good idea. I will try it in another PR.

export type { DebugCSSRules, DebugSequence, DebugResult } from './devtools';
3 changes: 3 additions & 0 deletions packages/eslint-plugin/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]]
}
18 changes: 18 additions & 0 deletions packages/eslint-plugin/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
44 changes: 44 additions & 0 deletions packages/eslint-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# ESLint plugin for Griffel

ESLint plugin to follow best practices and anticipate common mistakes when writing styles with Griffel

## Install

```bash
yarn add --dev @griffel/eslint-plugin
# or
npm install --dev @griffel/eslint-plugin
```

## Usage

Add `@griffel/eslint-plugin` to the extends section of your `.eslintrc` configuration file:

```json
{
"extends": ["@griffel"]
}
```

## Shareable configurations

This plugin exports recommended configuration that enforce good practices, but you can use only uses that are required for your use case:

```json
{
"plugins": ["@griffel"],
"rules": {
"@griffel/no-shorthands": "warn"
}
}
```

You can find more info about enabled rules in the [Supported Rules section](#supported-rules) below.

## Supported Rules

**Key**: 🔧 = fixable

| Name | Description | 🔧 |
| -------------------------------------------------------- | ------------------------------ | --- |
| [`@griffel/no-shorthands`](./src/rules/no-shorthands.md) | Enforce usage of CSS longhands | |
15 changes: 15 additions & 0 deletions packages/eslint-plugin/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module.exports = {
displayName: 'eslint-plugin',
preset: '../../jest.preset.js',
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
},
},
testEnvironment: 'node',
transform: {
'^.+\\.[tj]sx?$': 'ts-jest',
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/packages/eslint-plugin',
};
17 changes: 17 additions & 0 deletions packages/eslint-plugin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@griffel/eslint-plugin",
"version": "0.0.1",
"description": "ESLint plugin with lint rules for Griffel",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/microsoft/griffel"
},
"dependencies": {
"csstype": "^3.0.10",
"@typescript-eslint/utils": "^5.20.0"
},
"peerDependencies": {
"eslint": "^7.5.0 || ^8.0.0"
}
}
49 changes: 49 additions & 0 deletions packages/eslint-plugin/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"root": "packages/eslint-plugin",
"sourceRoot": "packages/eslint-plugin/src",
"projectType": "library",
"targets": {
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["packages/eslint-plugin/**/*.ts"]
}
},
"test": {
"executor": "@nrwl/jest:jest",
"outputs": ["coverage/packages/eslint-plugin"],
"options": {
"jestConfig": "packages/eslint-plugin/jest.config.js",
"passWithNoTests": true
}
},
"build": {
"executor": "@nrwl/node:package",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/packages/eslint-plugin",
"tsConfig": "packages/eslint-plugin/tsconfig.lib.json",
"packageJson": "packages/eslint-plugin/package.json",
"main": "packages/eslint-plugin/src/index.ts",
"assets": [
"packages/eslint-plugin/README.md",
{
"glob": "LICENSE.md",
"input": ".",
"output": "."
}
]
}
},
"type-check": {
"executor": "@nrwl/workspace:run-commands",
"options": {
"cwd": "packages/babel-preset",
"commands": [{ "command": "tsc -b --pretty" }],
"outputPath": []
}
}
},
"tags": []
}
6 changes: 6 additions & 0 deletions packages/eslint-plugin/src/configs/recommended.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const recommendedConfig = {
plugins: ['@griffel'],
rules: {
'@griffel/no-shorthands': 'error',
},
};
11 changes: 11 additions & 0 deletions packages/eslint-plugin/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { recommendedConfig } from './configs/recommended';
import { noShorthandsRule } from './rules/no-shorthands';

export = {
configs: {
recommended: recommendedConfig,
},
rules: {
'no-shorthands': noShorthandsRule,
},
};
34 changes: 34 additions & 0 deletions packages/eslint-plugin/src/rules/no-shorthands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Enforce usage of CSS longhands (`@griffel/no-shorthands`)

Ensure that rules passed to `makeStyles()` function do not contain [CSS shorthands](https://developer.mozilla.org/en-US/docs/Web/CSS/Shorthand_properties).

## Rule Details

Griffel does not support usage of CSS shorthands, [microsoft/griffel#30](https://github.com/microsoft/griffel/issues/30#issuecomment-1045959297).
This is enforced by typings, but there are cases when they don't work as expected [microsoft/griffel#78](https://github.com/microsoft/griffel/issues/78).

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

```js
import { makeStyles } from '@griffel/react';

export const useStyles = makeStyles({
root: {
background: 'red',
padding: '10px 20px',
},
});
```

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

```js
import { makeStyles } from '@griffel/react';

export const useStyles = makeStyles({
root: {
backgroundColor: 'red',
...shorthands.padding('10px', '20px'),
},
});
```
64 changes: 64 additions & 0 deletions packages/eslint-plugin/src/rules/no-shorthands.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { TSESLint } from '@typescript-eslint/utils';
import * as path from 'path';

import { noShorthandsRule, RULE_NAME } from './no-shorthands';

const ruleTester = new TSESLint.RuleTester({
parser: path.resolve('./node_modules/@typescript-eslint/parser'),
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
},
});

ruleTester.run(RULE_NAME, noShorthandsRule, {
valid: [
{
name: 'without CSS shorthands',
code: `
import { makeStyles } from '@griffel/react';

export const useStyles = makeStyles({
root: { backgroundColor: 'red' },
});
`,
},
{
name: 'CSS shorthands can be used as slot names',
code: `
import { makeStyles } from '@griffel/react';

export const useStyles = makeStyles({
background: { backgroundColor: 'red' },
});
`,
},
],

invalid: [
{
name: 'CSS shorthand or root level',
code: `
import { makeStyles } from '@griffel/react';

export const useStyles = makeStyles({
root: { background: 'red' },
});
`,
errors: [{ messageId: 'shorthandFound' }],
},
{
name: 'CSS shorthand in a selector',
code: `
import { makeStyles } from '@griffel/react';

export const useStyles = makeStyles({
root: {
':hover': { background: 'red' }
},
});
`,
errors: [{ messageId: 'shorthandFound' }],
},
],
});
Loading