Skip to content

Commit

Permalink
Add flat config preset for compiled & fix docs (#1727)
Browse files Browse the repository at this point in the history
* JFP-1155: Add flat config preset for compiled

* JFP-1155: Make recommended property of eslint rule docs match the recommended config

* JFP-1155: Fix tsconfig setup for eslint plugin for package.json file

* JFP-1155: Add typescript transformer to eslint plugin for name and version

* Fix typo in readme

Co-authored-by: Grant Wong <[email protected]>

---------

Co-authored-by: Grant Wong <[email protected]>
  • Loading branch information
AllySummers and dddlr authored Oct 24, 2024
1 parent 944518e commit e8b09ec
Show file tree
Hide file tree
Showing 19 changed files with 189 additions and 21 deletions.
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.\
🔧 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;
},
},
},
},
} 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,
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" }]
}

0 comments on commit e8b09ec

Please sign in to comment.