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

Add flat config preset for compiled & fix docs #1727

5 changes: 5 additions & 0 deletions .changeset/curvy-flies-develop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@compiled/eslint-plugin': minor
---

Adding flat config preset for `@compiled/eslint-plugin` and adding missing descriptions to ESLint rules
62 changes: 49 additions & 13 deletions packages/eslint-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,42 @@ npm install @compiled/eslint-plugin --save-dev

## Usage

### Flat Config

Import the `@compiled/eslint-plugin` and add it to your plugins like so, then configure the rules you want to use under the "Supported rules" section.

```ts
import compiled from '@compiled/eslint-plugin';

export default [
{
plugins: {
'@compiled': compiled,
},
rules: {
'@compiled/no-js-xcss': 'error',
},
},
];
```

You can also enable the recommended rules for compiled by extending the `flat/recommended` config like so:

```ts
import compiled from '@compiled/eslint-plugin';

export default [compiled.configs['flat/recommended']];
```

### Legacy Config (`.eslintrc`)

Add `@compiled` to the plugins section of your `.eslintrc` configuration file, then configure the rules you want to use under the rules section.

```json
{
"plugins": ["@compiled"],
"rules": {
"@compiled/rule-name": "error"
"@compiled/no-js-xcss": "error"
}
}
```
Expand All @@ -32,15 +61,22 @@ You can also enable the recommended rules for compiled by adding `plugin:@compil

## Supported rules

:white_check_mark: = recommended, :wrench: = automatically fixable, :bulb: = manually fixable

| Name | Description | :white_check_mark: | Fixable |
| -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | :----------------: | :------: |
| [@compiled/jsx-pragma](./src/rules/jsx-pragma) | Enforces a jsx pragma when using the `css` prop | | :wrench: |
| [@compiled/no-css-tagged-template-expression](./src/rules/no-css-tagged-template-expression) | Disallows the `css` tagged template expression | :white_check_mark: | :wrench: |
| [@compiled/no-emotion-css](./src/rules/no-emotion-css) | Disallows `@emotion` usages | | :wrench: |
| [@compiled/no-exported-css](./src/rules/no-exported-css) | Disallows `css` usages from being exported | :white_check_mark: | |
| [@compiled/no-exported-keyframes](./src/rules/no-exported-keyframes) | Disallows `keyframes` usages from being exported | :white_check_mark: | |
| [@compiled/no-keyframes-tagged-template-expression](./src/rules/no-keyframes-tagged-template-expression) | Disallows the `keyframes` tagged template expression | :white_check_mark: | :wrench: |
| [@compiled/no-styled-tagged-template-expression](./src/rules/no-styled-tagged-template-expression) | Disallows the `styled` tagged template expression | :white_check_mark: | :wrench: |
| [@compiled/no-css-prop-without-css-function](./src/rules/no-css-prop-without-css-function) | Disallows css prop without the css function | :white_check_mark: | :wrench: |
✅ Included in the recommended configuration.\
Copy link
Collaborator

Choose a reason for hiding this comment

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

thank you ❤️ ❤️ ❤️

🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\

| Name | Description | Recommended | Fixable |
| -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------: | :-----: |
| [@compiled/jsx-pragma](./src/rules/jsx-pragma) | Enforces a jsx pragma when using the `css` prop | | 🔧 |
| [@compiled/local-cx-xcss](./src/rules/local-cx-xcss) | Ensures the `cx()` function is only used within the `xcss` prop | ✅ | |
| [@compiled/no-css-prop-without-css-function](./src/rules/no-css-prop-without-css-function) | Disallows `css` prop usages where it is either not wrapped in the `css` import from `@compiled/react` or where `@compiled` cannot determine whether the `css` import is included at build time. | ✅ | 🔧 |
| [@compiled/no-css-tagged-template-expression](./src/rules/no-css-tagged-template-expression) | Disallows the `css` tagged template expression | ✅ | 🔧 |
| [@compiled/no-emotion-css](./src/rules/no-emotion-css) | Disallows `@emotion` usages | | 🔧 |
| [@compiled/no-empty-styled-expression](./src/rules/no-empty-styled-expression) | Disallows any `styled` expression to be used when passing empty arguments in `@compiled/react` | ✅ | |
| [@compiled/no-exported-css](./src/rules/no-exported-css) | Disallows `css` usages from being exported | ✅ | |
| [@compiled/no-exported-keyframes](./src/rules/no-exported-keyframes) | Disallows `keyframes` usages from being exported | ✅ | |
| [@compiled/no-invalid-css-map](./src/rules/no-invalid-css-map) | Checks the validity of a CSS map created through cssMap. This is intended to be used alongside TypeScript's type-checking. | ✅ | |
| [@compiled/no-js-xcss](./src/rules/no-js-xcss) | The xcss prop is predicated on adhering to the type contract. Using it without TypeScript breaks this contract and thus is not allowed. | ✅ | |
| [@compiled/no-keyframes-tagged-template-expression](./src/rules/no-keyframes-tagged-template-expression) | Disallows the `keyframes` tagged template expression | ✅ | 🔧 |
| [@compiled/no-styled-tagged-template-expression](./src/rules/no-styled-tagged-template-expression) | Disallows the `styled` tagged template expression | ✅ | 🔧 |
| [@compiled/no-suppress-xcss](./src/rules/no-suppress-xcss) | The xcss prop is predicated on adhering to the type contract. Supressing it breaks this contract and thus is not allowed. | ✅ | |
| [@compiled/shorthand-property-sorting](./src/rules/shorthand-property-sorting) | Prevent unwanted side-effect by ensuring shorthand properties are always defined before their related longhands. | ✅ | |
65 changes: 65 additions & 0 deletions packages/eslint-plugin/add-pkg-info-transform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* @fileoverview
* This file is a transformer to be used with `ttypescript` to replace the version
* and name of the eslint plugin in the source from the package.json at compile time.
*/

// @ts-check
// eslint-disable-next-line import/no-extraneous-dependencies
const ts = require('typescript');

const pkgJson = require('./package.json');

/**
*
* @param {ts.Node} node
* @param {string} name
* @param {string} value
* @returns {node is ts.VariableDeclaration & {name: ts.Identifier, initializer: ts.StringLiteral}}
*/
const isVariableWithProperties = (node, name, value) =>
!!(
ts.isVariableDeclaration(node) &&
ts.isIdentifier(node.name) &&
node.name.text === name &&
node.initializer &&
ts.isStringLiteral(node.initializer) &&
node.initializer.text === value
);

/**
* @param {ts.Program} _ts
* @returns {ts.TransformerFactory<ts.SourceFile>}
*/
const transformer = (_ts) => (context) => (sourceFile) => {
/**
* @param {ts.Node} node
* @returns {ts.Node}
*/
const visitor = (node) => {
if (isVariableWithProperties(node, 'name', '/* NAME */')) {
return ts.factory.updateVariableDeclaration(
node,
node.name,
undefined,
undefined,
ts.factory.createStringLiteral(pkgJson.name)
);
}

if (isVariableWithProperties(node, 'version', '/* VERSION */')) {
return ts.factory.updateVariableDeclaration(
node,
node.name,
undefined,
undefined,
ts.factory.createStringLiteral(pkgJson.version)
);
}

return ts.visitEachChild(node, visitor, context);
};
return ts.visitNode(sourceFile, visitor);
};

module.exports = transformer;
16 changes: 16 additions & 0 deletions packages/eslint-plugin/src/configs/flat-recommended.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const flatRecommended = {
// plugin is not specified here because flat config needs a reference to the plugin
rules: {
'@compiled/local-cx-xcss': 'error',
'@compiled/no-css-prop-without-css-function': 'error',
'@compiled/no-css-tagged-template-expression': 'error',
'@compiled/no-empty-styled-expression': 'error',
'@compiled/no-exported-css': 'error',
'@compiled/no-exported-keyframes': 'error',
'@compiled/no-invalid-css-map': 'error',
'@compiled/no-js-xcss': 'error',
'@compiled/no-keyframes-tagged-template-expression': 'error',
'@compiled/no-styled-tagged-template-expression': 'error',
'@compiled/no-suppress-xcss': 'error',
},
} as const;
2 changes: 1 addition & 1 deletion packages/eslint-plugin/src/configs/recommended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ export const recommended = {
'@compiled/local-cx-xcss': 'error',
'@compiled/no-css-prop-without-css-function': 'error',
'@compiled/no-css-tagged-template-expression': 'error',
'@compiled/no-empty-styled-expression': 'error',
'@compiled/no-exported-css': 'error',
'@compiled/no-exported-keyframes': 'error',
'@compiled/no-invalid-css-map': 'error',
'@compiled/no-js-xcss': 'error',
'@compiled/no-keyframes-tagged-template-expression': 'error',
'@compiled/no-styled-tagged-template-expression': 'error',
'@compiled/no-suppress-xcss': 'error',
'@compiled/no-empty-styled-expression': 'error',
},
};
31 changes: 27 additions & 4 deletions packages/eslint-plugin/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { flatRecommended } from './configs/flat-recommended';
import { recommended } from './configs/recommended';
import { jsxPragmaRule } from './rules/jsx-pragma';
import { localCXXCSSRule } from './rules/local-cx-xcss';
Expand All @@ -14,6 +15,9 @@ import { noStyledTaggedTemplateExpressionRule } from './rules/no-styled-tagged-t
import { noSuppressXCSS } from './rules/no-suppress-xcss';
import { shorthandFirst } from './rules/shorthand-property-sorting';

export const name = '/* NAME */';
export const version = '/* VERSION */';

export const rules = {
'jsx-pragma': jsxPragmaRule,
'local-cx-xcss': localCXXCSSRule,
Expand All @@ -29,8 +33,27 @@ export const rules = {
'no-suppress-xcss': noSuppressXCSS,
'no-empty-styled-expression': noEmptyStyledExpressionRule,
'shorthand-property-sorting': shorthandFirst,
};
} as const;

export const plugin = {
meta: {
name,
version,
},
rules,
configs: {
recommended,
'flat/recommended': {
...flatRecommended,
plugins: {
get '@compiled'() {
return plugin;
},
Comment on lines +49 to +51
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a bit more coherent than plugin.configs['flat/recommended'].plugins['@compiled'] = plugin which is what you'd have to do otherwise, right?

Only real concern is could this ever backfire with some Node support? I feel like it's been around forever but also a syntax I never use (because when it was introduced it wasn't ready to be used)…it's good now, right?

Also, would you ever want to merge this though?

Suggested change
get '@compiled'() {
return plugin;
},
...flatRecommended.plugins,
get '@compiled'() {
return plugin;
},

},
},
},
} as const;

export const configs = plugin.configs;

export const configs = {
recommended,
};
export default plugin;
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/rules/jsx-pragma/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ function createFixer(context: Rule.RuleContext, source: SourceCode, options: Opt
export const jsxPragmaRule: Rule.RuleModule = {
meta: {
docs: {
description: 'Enforces a jsx pragma when using the `css` prop',
url: 'https://github.com/atlassian-labs/compiled/tree/master/packages/eslint-plugin/src/rules/jsx-pragma',
},
fixable: 'code',
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/rules/local-cx-xcss/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ function getParentJSXAttribute(node: Rule.Node) {
export const localCXXCSSRule: Rule.RuleModule = {
meta: {
docs: {
description: 'Ensures the `cx()` function is only used within the `xcss` prop',
recommended: true,
url: 'https://github.com/atlassian-labs/compiled/tree/master/packages/eslint-plugin/src/rules/local-cx-xcss',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export const noCssPropWithoutCssFunctionRule: TSESLint.RuleModule<string> = {
url: 'https://github.com/atlassian-labs/compiled/tree/master/packages/eslint-plugin/src/rules/no-css-prop-without-css-function',
recommended: 'error',
description:
'Disallows `css` prop usages without wrapping in the `css` import from `@compiled/react`. Also forbids `css` prop usages where Compiled cannot determine whether the `css` import is included at build time.',
'Disallows `css` prop usages where it is either not wrapped in the `css` import from `@compiled/react` or where `@compiled` cannot determine whether the `css` import is included at build time.',
},
messages: {
noCssFunction: 'css prop values are required to use the css import from @compiled/react',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { createNoTaggedTemplateExpressionRule, isCss } from '../../utils';
export const noCssTaggedTemplateExpressionRule: Rule.RuleModule = {
meta: {
docs: {
recommended: true,
description: 'Disallows the `css` tagged template expression',
url: 'https://github.com/atlassian-labs/compiled/tree/master/packages/eslint-plugin/src/rules/no-css-tagged-template-expression',
},
fixable: 'code',
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/rules/no-emotion-css/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const noEmotionCssRule: Rule.RuleModule = {
fixable: 'code',
type: 'problem',
docs: {
description: 'Disallows `@emotion` usages',
url: 'https://github.com/atlassian-labs/compiled/tree/master/packages/eslint-plugin/src/rules/no-emotion-css',
},
messages: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ const createNoEmptyStyledExpressionRule =
export const noEmptyStyledExpressionRule: Rule.RuleModule = {
meta: {
docs: {
recommended: true,
description:
'Disallows any `styled` expression to be used when passing empty arguments in `@compiled/react`',
url: 'https://github.com/atlassian-labs/compiled/tree/master/packages/eslint-plugin/src/rules/no-empty-styled-expression',
},
messages: {
Expand Down
2 changes: 2 additions & 0 deletions packages/eslint-plugin/src/rules/no-exported-css/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { createNoExportedRule, isCss } from '../../utils';
export const noExportedCssRule: Rule.RuleModule = {
meta: {
docs: {
recommended: true,
description: 'Disallows `css` usages from being exported',
url: 'https://github.com/atlassian-labs/compiled/tree/master/packages/eslint-plugin/src/rules/no-exported-css',
},
messages: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { createNoExportedRule, isKeyframes } from '../../utils';
export const noExportedKeyframesRule: Rule.RuleModule = {
meta: {
docs: {
recommended: true,
description: 'Disallows `keyframes` usages from being exported',
url: 'https://github.com/atlassian-labs/compiled/tree/master/packages/eslint-plugin/src/rules/no-exported-css',
},
messages: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ const createCssMapRule = (context: Rule.RuleContext): Rule.RuleListener => {
export const noInvalidCssMapRule: Rule.RuleModule = {
meta: {
docs: {
recommended: true,
description:
"Checks the validity of a CSS map created through cssMap. This is intended to be used alongside TypeScript's type-checking.",
url: 'https://github.com/atlassian-labs/compiled/tree/master/packages/eslint-plugin/src/rules/no-invalid-css-map',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { createNoTaggedTemplateExpressionRule, isKeyframes } from '../../utils';
export const noKeyframesTaggedTemplateExpressionRule: Rule.RuleModule = {
meta: {
docs: {
recommended: true,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Adding a few recommended: true could be a problem, but this is a minor bump on a 0.x version which means major to me, LGTM if Eurybia is happy!

description: 'Disallows the `keyframes` tagged template expression',
url: 'https://github.com/atlassian-labs/compiled/tree/master/packages/eslint-plugin/src/rules/no-keyframes-tagged-template-expression',
},
fixable: 'code',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { createNoTaggedTemplateExpressionRule, isStyled } from '../../utils';
export const noStyledTaggedTemplateExpressionRule: Rule.RuleModule = {
meta: {
docs: {
recommended: true,
description: 'Disallows the `styled` tagged template expression',
url: 'https://github.com/atlassian-labs/compiled/tree/master/packages/eslint-plugin/src/rules/no-styled-tagged-template-expression',
},
fixable: 'code',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const shorthandFirst: Rule.RuleModule = {
meta: {
docs: {
description:
'Prevent unwanted side-effect by ensuring shorthand properties are always defined before their related longhands. See more in the README.',
'Prevent unwanted side-effect by ensuring shorthand properties are always defined before their related longhands.',
recommended: true,
url: 'https://github.com/atlassian-labs/compiled/tree/master/packages/eslint-plugin/src/rules/shorthand-property-sorting',
},
Expand Down
8 changes: 7 additions & 1 deletion packages/eslint-plugin/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@
"rootDir": "src",
"outDir": "dist",
"module": "commonjs",
"target": "es2017"
"target": "es2017",
"plugins": [
{
"name": "transform-pkg-info",
"transform": "./add-pkg-info-transform.js"
}
]
},
"references": [{ "path": "../jest" }, { "path": "../utils" }]
}
Loading