Skip to content

Commit

Permalink
feat(recommended): new set of opinionated rules
Browse files Browse the repository at this point in the history
  • Loading branch information
rfgamaral committed Jul 1, 2020
1 parent 8250e97 commit b06e51a
Show file tree
Hide file tree
Showing 13 changed files with 695 additions and 2 deletions.
51 changes: 49 additions & 2 deletions README.md
Expand Up @@ -77,6 +77,36 @@ Extends the Airbnb React configuration with [Hooks rules](https://github.com/air
}
```

### Recommended

Extends the Airbnb configuration with my own [opinionated rules](https://github.com/rfgamaral/eslint-config-typescript-unified/blob/master/tests/recommended.test.js):

```json
{
"extends": "@rfgamaral/eslint-config-typescript-unified/recommended"
}
```

### Recommended (React)

Extends the Airbnb (React) configuration with my own [opinionated rules](https://github.com/rfgamaral/eslint-config-typescript-unified/blob/master/tests/recommended-react.test.js):

```json
{
"extends": "@rfgamaral/eslint-config-typescript-unified/recommended-react"
}
```

### Recommended (React + Hooks)

Extends the Airbnb (React + Hooks) configuration with my own [opinionated rules](https://github.com/rfgamaral/eslint-config-typescript-unified/blob/master/tests/recommended-react-hooks.test.js):

```json
{
"extends": "@rfgamaral/eslint-config-typescript-unified/recommended-react-hooks"
}
```

### Semantics (type-checking)

For all the configurations mentioned above, the TypeScript rules are fast feedback rules which operate purely based on syntax (no type-checking). If you want some additional highly valuable rules that operate on semantics (type-checking), just suffix any of the configuration names above with `-semantics`. You can read a little bit more about it [here](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#usage).
Expand All @@ -89,9 +119,26 @@ This rule is disabled to prevent ESLint from reporting `no-undef` false positive

The TypeScript compiler will catch undeclared variables by default, so we don't need this rule.

### Why are `*.d.ts` files being ignored for all Airbnb configurations?
### Why are `*.d.ts` files being ignored for all Airbnb and Recommended configurations?

Airbnb configurations make use of [`eslint-plugin-import`](https://github.com/benmosher/eslint-plugin-import) which triggers `import/no-cycle` false positives for cyclic dependencies between `type` imports. More details at [benmosher/eslint-plugin-import#1453](https://github.com/benmosher/eslint-plugin-import/issues/1453).
Airbnb and Recommended configurations make use of [`eslint-plugin-import`](https://github.com/benmosher/eslint-plugin-import) which triggers `import/no-cycle` false positives for cyclic dependencies between `type` imports. More details at [benmosher/eslint-plugin-import#1453](https://github.com/benmosher/eslint-plugin-import/issues/1453).

### How to configure a mixed JavaScript/TypeScript codebase with any of the Recommended configurations?

Recommended configurations require explicit return types on functions and class methods ([explicit-function-return-type](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/explicit-function-return-type.md)) which triggers false positives for JavaScript files. To workaround that, please ensure add the following override to disable the rule for `.js` and `.jsx` files:

```json
{
"overrides": [
{
"files": ["*.js", "*.jsx"],
"rules": {
"@typescript-eslint/explicit-function-return-type": ["error"]
}
}
]
}
```

## License

Expand Down
12 changes: 12 additions & 0 deletions recommended-react-hooks-semantics.js
@@ -0,0 +1,12 @@
'use strict';

const recommendedReactHooksConfiguration = require('./recommended-react-hooks');

module.exports = {
...recommendedReactHooksConfiguration,
extends: [
...recommendedReactHooksConfiguration.extends.splice(0, 4),
'plugin:@typescript-eslint/recommended-requiring-type-checking',
...recommendedReactHooksConfiguration.extends,
],
};
12 changes: 12 additions & 0 deletions recommended-react-hooks.js
@@ -0,0 +1,12 @@
'use strict';

const recommendedReactConfiguration = require('./recommended-react');

module.exports = {
...recommendedReactConfiguration,
extends: [
...recommendedReactConfiguration.extends.splice(0, 1),
'airbnb/hooks',
...recommendedReactConfiguration.extends,
],
};
12 changes: 12 additions & 0 deletions recommended-react-semantics.js
@@ -0,0 +1,12 @@
'use strict';

const recommendedReactConfiguration = require('./recommended-react');

module.exports = {
...recommendedReactConfiguration,
extends: [
...recommendedReactConfiguration.extends.splice(0, 3),
'plugin:@typescript-eslint/recommended-requiring-type-checking',
...recommendedReactConfiguration.extends,
],
};
19 changes: 19 additions & 0 deletions recommended-react.js
@@ -0,0 +1,19 @@
'use strict';

const recommendedConfiguration = require('./recommended');

module.exports = {
...recommendedConfiguration,
extends: ['airbnb', ...recommendedConfiguration.extends.splice(1, 4), 'prettier/react'],
rules: {
...recommendedConfiguration.rules,
'import/extensions': [
...recommendedConfiguration.rules['import/extensions'].splice(0, 2),
{
...recommendedConfiguration.rules['import/extensions'][0],
jsx: 'never',
tsx: 'never',
},
],
},
};
12 changes: 12 additions & 0 deletions recommended-semantics.js
@@ -0,0 +1,12 @@
'use strict';

const recommendedConfiguration = require('./recommended');

module.exports = {
...recommendedConfiguration,
extends: [
...recommendedConfiguration.extends.splice(0, 3),
'plugin:@typescript-eslint/recommended-requiring-type-checking',
...recommendedConfiguration.extends,
],
};
46 changes: 46 additions & 0 deletions recommended.js
@@ -0,0 +1,46 @@
'use strict';

const airbnbConfiguration = require('./airbnb');

module.exports = {
...airbnbConfiguration,
rules: {
...airbnbConfiguration.rules,
'@typescript-eslint/explicit-function-return-type': [
'warn',
{
allowExpressions: true,
allowHigherOrderFunctions: true,
allowTypedFunctionExpressions: true,
},
],
'@typescript-eslint/no-unused-vars': 'off',
'import/exports-last': 'error',
'import/group-exports': 'error',
'import/no-extraneous-dependencies': [
'error',
{
devDependencies: [
'**/__{mocks,tests}__/**/*.{js,ts}',
'**/*.{spec,test}.{js,ts}',
'**/*.{config,setup}.{js,ts}',
],
},
],
'import/no-default-export': 'error',
'import/no-deprecated': 'warn',
'import/order': [
'error',
{
alphabetize: {
caseInsensitive: true,
order: 'asc',
},
groups: ['object', 'builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
'newlines-between': 'always',
},
],
'import/prefer-default-export': 'off',
'prettier/prettier': 'warn',
},
};
92 changes: 92 additions & 0 deletions tests/recommended-react-hooks-semantics.test.js
@@ -0,0 +1,92 @@
const recommendedReactHooksSemanticsConfiguration = require('../recommended-react-hooks-semantics');

describe('Airbnb (React + Hooks)', () => {
describe('with semantics rules', () => {
test('configuration is exported correctly', () => {
expect(recommendedReactHooksSemanticsConfiguration).toEqual({
extends: [
'airbnb',
'airbnb/hooks',
'plugin:import/typescript',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:prettier/recommended',
'prettier/@typescript-eslint',
'prettier/react',
],
parser: '@typescript-eslint/parser',
parserOptions: { project: './tsconfig.json' },
rules: {
'@typescript-eslint/explicit-function-return-type': [
'warn',
{
allowExpressions: true,
allowHigherOrderFunctions: true,
allowTypedFunctionExpressions: true,
},
],
'@typescript-eslint/no-unused-vars': 'off',
'no-undef': 'off',
'import/exports-last': 'error',
'import/extensions': [
'error',
'ignorePackages',
{
js: 'never',
jsx: 'never',
mjs: 'never',
ts: 'never',
tsx: 'never',
},
],
'import/group-exports': 'error',
'import/no-extraneous-dependencies': [
'error',
{
devDependencies: [
'**/__{mocks,tests}__/**/*.{js,ts}',
'**/*.{spec,test}.{js,ts}',
'**/*.{config,setup}.{js,ts}',
],
},
],
'import/no-default-export': 'error',
'import/no-deprecated': 'warn',
'import/order': [
'error',
{
alphabetize: {
caseInsensitive: true,
order: 'asc',
},
groups: [
'object',
'builtin',
'external',
'internal',
'parent',
'sibling',
'index',
],
'newlines-between': 'always',
},
],
'import/prefer-default-export': 'off',
'prettier/prettier': 'warn',
},
settings: {
'import/ignore': [
'node_modules',
'\\.d\\.ts$',
'\\.(coffee|scss|css|less|hbs|svg|json)$',
],
'import/resolver': {
typescript: {
alwaysTryTypes: false,
},
},
},
});
});
});
});
89 changes: 89 additions & 0 deletions tests/recommended-react-hooks.test.js
@@ -0,0 +1,89 @@
const recommendedReactHooksConfiguration = require('../recommended-react-hooks');

describe('Airbnb (React + Hooks)', () => {
test('configuration is exported correctly', () => {
expect(recommendedReactHooksConfiguration).toEqual({
extends: [
'airbnb',
'airbnb/hooks',
'plugin:import/typescript',
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
'prettier/@typescript-eslint',
'prettier/react',
],
parser: '@typescript-eslint/parser',
parserOptions: { project: './tsconfig.json' },
rules: {
'@typescript-eslint/explicit-function-return-type': [
'warn',
{
allowExpressions: true,
allowHigherOrderFunctions: true,
allowTypedFunctionExpressions: true,
},
],
'@typescript-eslint/no-unused-vars': 'off',
'no-undef': 'off',
'import/exports-last': 'error',
'import/extensions': [
'error',
'ignorePackages',
{
js: 'never',
mjs: 'never',
ts: 'never',
jsx: 'never',
tsx: 'never',
},
],
'import/group-exports': 'error',
'import/no-extraneous-dependencies': [
'error',
{
devDependencies: [
'**/__{mocks,tests}__/**/*.{js,ts}',
'**/*.{spec,test}.{js,ts}',
'**/*.{config,setup}.{js,ts}',
],
},
],
'import/no-default-export': 'error',
'import/no-deprecated': 'warn',
'import/order': [
'error',
{
alphabetize: {
caseInsensitive: true,
order: 'asc',
},
groups: [
'object',
'builtin',
'external',
'internal',
'parent',
'sibling',
'index',
],
'newlines-between': 'always',
},
],
'import/prefer-default-export': 'off',
'prettier/prettier': 'warn',
},
settings: {
'import/ignore': [
'node_modules',
'\\.d\\.ts$',
'\\.(coffee|scss|css|less|hbs|svg|json)$',
],
'import/resolver': {
typescript: {
alwaysTryTypes: false,
},
},
},
});
});
});

0 comments on commit b06e51a

Please sign in to comment.