@todesktop/dev-config 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -0
- package/eslint/configs/base.js +69 -0
- package/eslint/configs/esm.js +17 -0
- package/eslint/configs/node.js +39 -0
- package/eslint/configs/nodeCommonJs.js +22 -0
- package/eslint/configs/prettier.js +17 -0
- package/eslint/configs/react.js +52 -0
- package/eslint/configs/reactStrict.js +25 -0
- package/eslint/configs/strict.js +157 -0
- package/eslint/configs/ts.js +21 -0
- package/eslint/configs/tsStrict.js +21 -0
- package/eslint/configs/unicorn.js +46 -0
- package/eslint/index.js +51 -0
- package/eslint/utils/flatArrayConfig.js +19 -0
- package/eslint.config.mjs +8 -0
- package/package.json +36 -0
- package/prettier/index.js +13 -0
- package/tsconfig.json +12 -0
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# dev-config
|
|
2
|
+
|
|
3
|
+
This package provides reusable development configuration files used across the
|
|
4
|
+
repository: ESLint, Prettier, and a base `tsconfig`.
|
|
5
|
+
|
|
6
|
+
## ESLint
|
|
7
|
+
|
|
8
|
+
The ESLint configuration is based on
|
|
9
|
+
[eslint-config-airbnb-extended](https://github.com/NishargShah/eslint-config-airbnb-extended),
|
|
10
|
+
which modernizes and replaces parts of
|
|
11
|
+
[eslint-config-airbnb](https://github.com/airbnb/javascript) and
|
|
12
|
+
[eslint-config-airbnb-typescript](https://github.com/iamturns/eslint-config-airbnb-typescript).
|
|
13
|
+
|
|
14
|
+
All projects extend the root config at
|
|
15
|
+
[eslint.config.mjs](../../eslint.config.mjs). If a project needs a different
|
|
16
|
+
configuration, add or override rules in that project's `eslint.config.mjs` (for
|
|
17
|
+
example, [tdutils](../tdutils/eslint.config.mjs)).
|
|
18
|
+
|
|
19
|
+
A typical project config that reuses these shared configs looks like this:
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
import { configs, defineConfig } from '@todesktop/dev-config/eslint';
|
|
23
|
+
|
|
24
|
+
export default defineConfig(
|
|
25
|
+
configs.base,
|
|
26
|
+
configs.ts,
|
|
27
|
+
configs.prettier,
|
|
28
|
+
configs.react,
|
|
29
|
+
configs.nodeCommonJs,
|
|
30
|
+
|
|
31
|
+
{
|
|
32
|
+
rules: {
|
|
33
|
+
'no-console': 'off',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Predefined configs from this package are applied first, then any
|
|
40
|
+
project-specific rules are merged on top.
|
|
41
|
+
|
|
42
|
+
See `eslint/index.js` in this package for a list of available configs and short
|
|
43
|
+
descriptions.
|
|
44
|
+
|
|
45
|
+
Some configs come in multiple strictness levels. When you choose a strict
|
|
46
|
+
variant, also include the base config, since it's not inherited.
|
|
47
|
+
|
|
48
|
+
| Base | Strict | Description |
|
|
49
|
+
| ------------ | ----------- | ------------------------------------------------------------------- |
|
|
50
|
+
| base | strict | JavaScript rules |
|
|
51
|
+
| ts | tsStrict | TypeScript rules |
|
|
52
|
+
| react | reactStrict | React-specific rules |
|
|
53
|
+
| prettier | - | Loads Prettier-related rule adjustments |
|
|
54
|
+
| node | - | Best practices for Node.js |
|
|
55
|
+
| nodeCommonJs | - | For CommonJS `.js`/`.cjs` files (configs, scripts, not source code) |
|
|
56
|
+
| esm | - | ESM-specific rules |
|
|
57
|
+
| unicorn | - | Rules from `eslint-plugin-unicorn` |
|
|
58
|
+
|
|
59
|
+
## Prettier
|
|
60
|
+
|
|
61
|
+
A shared Prettier configuration is provided and applied from the repository
|
|
62
|
+
root, so you usually do not need to add a separate Prettier config inside each
|
|
63
|
+
subpackage.
|
|
64
|
+
|
|
65
|
+
## tsconfig
|
|
66
|
+
|
|
67
|
+
A shared TypeScript base config is available. To reuse it, extend it from your
|
|
68
|
+
package's `tsconfig.json`:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"extends": "@todesktop/dev-config/tsconfig.json",
|
|
73
|
+
"include": ["src/**/*.ts"]
|
|
74
|
+
}
|
|
75
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import airbnb from 'eslint-config-airbnb-extended';
|
|
2
|
+
|
|
3
|
+
/** @type {import('eslint').Linter.Config} */
|
|
4
|
+
export default {
|
|
5
|
+
name: '@todesktop/dev-config/eslint/base',
|
|
6
|
+
|
|
7
|
+
languageOptions: {
|
|
8
|
+
ecmaVersion: 'latest',
|
|
9
|
+
sourceType: 'module',
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
rules: {
|
|
13
|
+
// https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/errors.ts
|
|
14
|
+
...airbnb.rules.base.errors.rules,
|
|
15
|
+
|
|
16
|
+
// https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/es6.ts
|
|
17
|
+
...airbnb.rules.base.es6.rules,
|
|
18
|
+
|
|
19
|
+
// https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/strict.ts
|
|
20
|
+
...airbnb.rules.base.strict.rules,
|
|
21
|
+
|
|
22
|
+
// https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/style.ts
|
|
23
|
+
...airbnb.rules.base.style.rules,
|
|
24
|
+
|
|
25
|
+
// https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/variables.ts
|
|
26
|
+
...airbnb.rules.base.variables.rules,
|
|
27
|
+
|
|
28
|
+
// Together with enabling for..of
|
|
29
|
+
// https://eslint.org/docs/latest/rules/no-restricted-syntax
|
|
30
|
+
'no-continue': 'off',
|
|
31
|
+
|
|
32
|
+
// Re-enabled in strict
|
|
33
|
+
// https://eslint.org/docs/latest/rules/no-nested-ternary
|
|
34
|
+
'no-nested-ternary': 'off',
|
|
35
|
+
|
|
36
|
+
// Re-enabled in strict, keep `Promise((r) => setTimeout(r, 10))` syntax
|
|
37
|
+
// https://eslint.org/docs/rules/no-promise-executor-return
|
|
38
|
+
'no-promise-executor-return': 'off',
|
|
39
|
+
|
|
40
|
+
// Allow for..of
|
|
41
|
+
// https://eslint.org/docs/latest/rules/no-restricted-syntax
|
|
42
|
+
'no-restricted-syntax': [
|
|
43
|
+
'error',
|
|
44
|
+
{
|
|
45
|
+
message:
|
|
46
|
+
'for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.',
|
|
47
|
+
selector: 'ForInStatement',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
message:
|
|
51
|
+
'Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.',
|
|
52
|
+
selector: 'LabeledStatement',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
message:
|
|
56
|
+
'`with` is disallowed in strict mode because it makes code impossible to predict and optimize.',
|
|
57
|
+
selector: 'WithStatement',
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
|
|
61
|
+
// Using before definition allows placing the primary code on the top
|
|
62
|
+
// https://eslint.org/docs/latest/rules/no-use-before-define
|
|
63
|
+
'no-use-before-define': 'off',
|
|
64
|
+
|
|
65
|
+
// We have a lot of code where it'd be less readable on applying
|
|
66
|
+
// https://eslint.org/docs/latest/rules/prefer-template
|
|
67
|
+
'prefer-template': 'off',
|
|
68
|
+
},
|
|
69
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** @type {import('eslint').Linter.Config} */
|
|
2
|
+
export default {
|
|
3
|
+
name: '@todesktop/dev-config/eslint/esm',
|
|
4
|
+
|
|
5
|
+
files: ['**/*.js', '**/*.mjs'],
|
|
6
|
+
|
|
7
|
+
languageOptions: {
|
|
8
|
+
ecmaVersion: 2022,
|
|
9
|
+
sourceType: 'module',
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
rules: {
|
|
13
|
+
// ESM files couldn't use directory imports
|
|
14
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-useless-path-segments.md
|
|
15
|
+
'import-x/no-useless-path-segments': 'off',
|
|
16
|
+
},
|
|
17
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import airbnb from 'eslint-config-airbnb-extended';
|
|
2
|
+
import globals from 'globals';
|
|
3
|
+
|
|
4
|
+
/** @type {import('eslint').Linter.Config} */
|
|
5
|
+
export default {
|
|
6
|
+
name: '@todesktop/dev-config/eslint/node',
|
|
7
|
+
|
|
8
|
+
languageOptions: {
|
|
9
|
+
globals: {
|
|
10
|
+
...globals.node,
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
plugins: {
|
|
15
|
+
...airbnb.plugins.node.plugins,
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
rules: {
|
|
19
|
+
// https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/node/nodeBase.ts
|
|
20
|
+
...airbnb.rules.node.base.rules,
|
|
21
|
+
|
|
22
|
+
// https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/node/nodeGlobals.ts
|
|
23
|
+
...airbnb.rules.node.globals.rules,
|
|
24
|
+
|
|
25
|
+
// https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/node/nodeNoUnsupportedFeatures.ts
|
|
26
|
+
...airbnb.rules.node.promises.rules,
|
|
27
|
+
|
|
28
|
+
// https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/node/nodePromises.ts
|
|
29
|
+
...airbnb.rules.node.noUnsupportedFeatures.rules,
|
|
30
|
+
|
|
31
|
+
// Requires type information
|
|
32
|
+
// https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/no-sync.md
|
|
33
|
+
'n/no-sync': 'off',
|
|
34
|
+
|
|
35
|
+
// Strict flag depends on sourceType
|
|
36
|
+
// https://eslint.org/docs/latest/rules/strict
|
|
37
|
+
'strict': ['error', 'global'],
|
|
38
|
+
},
|
|
39
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import globals from 'globals';
|
|
2
|
+
|
|
3
|
+
/** @type {import('eslint').Linter.Config} */
|
|
4
|
+
export default {
|
|
5
|
+
name: '@todesktop/dev-config/eslint/nodeCommonJs',
|
|
6
|
+
|
|
7
|
+
files: ['**/*.js', '**/*.cjs'],
|
|
8
|
+
|
|
9
|
+
languageOptions: {
|
|
10
|
+
ecmaVersion: 2022,
|
|
11
|
+
globals: {
|
|
12
|
+
...globals.node,
|
|
13
|
+
},
|
|
14
|
+
sourceType: 'commonjs',
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
rules: {
|
|
18
|
+
// Require 'use strict' for commonJs files
|
|
19
|
+
// https://eslint.org/docs/latest/rules/strict
|
|
20
|
+
strict: ['error', 'global'],
|
|
21
|
+
},
|
|
22
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import prettierConfig from 'eslint-config-prettier/flat';
|
|
2
|
+
import prettierPlugin from 'eslint-plugin-prettier';
|
|
3
|
+
|
|
4
|
+
/** @type {import('eslint').Linter.Config} */
|
|
5
|
+
export default {
|
|
6
|
+
name: '@todesktop/dev-config/eslint/prettier',
|
|
7
|
+
|
|
8
|
+
plugins: { prettier: prettierPlugin },
|
|
9
|
+
|
|
10
|
+
rules: {
|
|
11
|
+
// https://github.com/prettier/eslint-config-prettier/blob/main/index.js
|
|
12
|
+
...prettierConfig.rules,
|
|
13
|
+
|
|
14
|
+
// https://github.com/prettier/eslint-plugin-prettier/blob/main/eslint-plugin-prettier.js
|
|
15
|
+
...prettierPlugin.configs.recommended.rules,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import airbnb from 'eslint-config-airbnb-extended';
|
|
2
|
+
|
|
3
|
+
/** @type {import('eslint').Linter.Config} */
|
|
4
|
+
export default {
|
|
5
|
+
name: '@todesktop/dev-config/eslint/react',
|
|
6
|
+
|
|
7
|
+
languageOptions: {
|
|
8
|
+
...airbnb.plugins.react.plugins.languageOptions,
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
plugins: {
|
|
12
|
+
...airbnb.plugins.react.plugins,
|
|
13
|
+
...airbnb.plugins.reactHooks.plugins,
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
rules: {
|
|
17
|
+
// https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/react/react.ts
|
|
18
|
+
...airbnb.rules.react.base.rules,
|
|
19
|
+
|
|
20
|
+
// https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/react/reactHooks.ts
|
|
21
|
+
...airbnb.rules.react.hooks.rules,
|
|
22
|
+
|
|
23
|
+
// Add tsx extension
|
|
24
|
+
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md
|
|
25
|
+
'react/jsx-filename-extension': [
|
|
26
|
+
'error',
|
|
27
|
+
{
|
|
28
|
+
extensions: ['.jsx', '.tsx'],
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
|
|
32
|
+
// Re-enabled in reactStrict
|
|
33
|
+
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/destructuring-assignment.md
|
|
34
|
+
'react/destructuring-assignment': 'off',
|
|
35
|
+
|
|
36
|
+
// There are a lot of existed cases that would look worse after applying
|
|
37
|
+
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-one-expression-per-line.md
|
|
38
|
+
'react/jsx-one-expression-per-line': 'off',
|
|
39
|
+
|
|
40
|
+
// We already have a lot of components defined as arrow functions
|
|
41
|
+
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/function-component-definition.md
|
|
42
|
+
'react/function-component-definition': 'off',
|
|
43
|
+
|
|
44
|
+
// I think only web-app doesn't use react-jsx runtime
|
|
45
|
+
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/react-in-jsx-scope.md
|
|
46
|
+
'react/react-in-jsx-scope': 'off',
|
|
47
|
+
|
|
48
|
+
// It's better handled by TSC
|
|
49
|
+
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/prop-types.md
|
|
50
|
+
'react/require-default-props': 'off',
|
|
51
|
+
},
|
|
52
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import airbnb from 'eslint-config-airbnb-extended';
|
|
2
|
+
|
|
3
|
+
/** @type {import('eslint').Linter.Config} */
|
|
4
|
+
export default {
|
|
5
|
+
name: '@todesktop/dev-config/eslint/reactStrict',
|
|
6
|
+
|
|
7
|
+
rules: {
|
|
8
|
+
// https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/react/reactStrict.ts
|
|
9
|
+
...airbnb.rules.react.strict.rules,
|
|
10
|
+
|
|
11
|
+
// Re-enabling
|
|
12
|
+
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/destructuring-assignment.md
|
|
13
|
+
'react/destructuring-assignment': 'error',
|
|
14
|
+
|
|
15
|
+
// Re-enabling
|
|
16
|
+
// https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/function-component-definition.md
|
|
17
|
+
'react/function-component-definition': [
|
|
18
|
+
'error',
|
|
19
|
+
{
|
|
20
|
+
namedComponents: ['function-declaration', 'function-expression'],
|
|
21
|
+
unnamedComponents: 'function-expression',
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import airbnb from 'eslint-config-airbnb-extended';
|
|
2
|
+
import perfectionist from 'eslint-plugin-perfectionist';
|
|
3
|
+
|
|
4
|
+
/** @type {import('eslint').Linter.Config} */
|
|
5
|
+
export default {
|
|
6
|
+
name: '@todesktop/dev-config/eslint/strict',
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
import-x replaces an old import plugin. It's much more powerful, but some
|
|
10
|
+
things work wired. If there are any issues with this plugin in the future,
|
|
11
|
+
it makes sense to completely remove it.
|
|
12
|
+
*/
|
|
13
|
+
plugins: {
|
|
14
|
+
...airbnb.plugins.importX.plugins,
|
|
15
|
+
perfectionist,
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
rules: {
|
|
19
|
+
// https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/best-practices.ts
|
|
20
|
+
...airbnb.rules.base.bestPractices.rules,
|
|
21
|
+
|
|
22
|
+
// https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/imports.ts
|
|
23
|
+
...airbnb.rules.base.imports.rules,
|
|
24
|
+
|
|
25
|
+
// It's too hard to configure it properly for different project types
|
|
26
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/extensions.md
|
|
27
|
+
'import-x/extensions': 'off',
|
|
28
|
+
|
|
29
|
+
// Reports if a module's default export is unnamed
|
|
30
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-anonymous-default-export.md
|
|
31
|
+
'import-x/no-anonymous-default-export': [
|
|
32
|
+
'error',
|
|
33
|
+
{
|
|
34
|
+
allowArray: true,
|
|
35
|
+
allowObject: true,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
|
|
39
|
+
// It's often useful to rename default exports
|
|
40
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-rename-default.md
|
|
41
|
+
'import-x/no-rename-default': 'off',
|
|
42
|
+
|
|
43
|
+
// It's too hard to configure it properly for different project types
|
|
44
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-unresolved.md
|
|
45
|
+
'import-x/no-unresolved': 'off',
|
|
46
|
+
|
|
47
|
+
// perfectionist is used instead
|
|
48
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/order.md
|
|
49
|
+
'import-x/order': 'off',
|
|
50
|
+
|
|
51
|
+
// That's not always useful
|
|
52
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/prefer-default-export.md
|
|
53
|
+
'import-x/prefer-default-export': 'off',
|
|
54
|
+
|
|
55
|
+
// Re-enabling
|
|
56
|
+
// https://eslint.org/docs/latest/rules/no-nested-ternary
|
|
57
|
+
'no-nested-ternary': 'error',
|
|
58
|
+
|
|
59
|
+
// Re-enabling
|
|
60
|
+
// https://eslint.org/docs/rules/no-promise-executor-return
|
|
61
|
+
'no-promise-executor-return': 'error',
|
|
62
|
+
|
|
63
|
+
// https://perfectionist.dev/rules/sort-array-includes
|
|
64
|
+
'perfectionist/sort-array-includes': [
|
|
65
|
+
'error',
|
|
66
|
+
{ order: 'asc', type: 'alphabetical' },
|
|
67
|
+
],
|
|
68
|
+
|
|
69
|
+
// https://perfectionist.dev/rules/sort-enums
|
|
70
|
+
'perfectionist/sort-enums': [
|
|
71
|
+
'error',
|
|
72
|
+
{ order: 'asc', type: 'alphabetical' },
|
|
73
|
+
],
|
|
74
|
+
|
|
75
|
+
// https://perfectionist.dev/rules/sort-exports
|
|
76
|
+
'perfectionist/sort-exports': [
|
|
77
|
+
'error',
|
|
78
|
+
{ order: 'asc', type: 'alphabetical' },
|
|
79
|
+
],
|
|
80
|
+
|
|
81
|
+
// https://perfectionist.dev/rules/sort-imports
|
|
82
|
+
'perfectionist/sort-imports': [
|
|
83
|
+
'error',
|
|
84
|
+
{
|
|
85
|
+
groups: ['import', 'parent', 'sibling', 'unknown'],
|
|
86
|
+
newlinesBetween: 0,
|
|
87
|
+
order: 'asc',
|
|
88
|
+
type: 'alphabetical',
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
|
|
92
|
+
// https://perfectionist.dev/rules/sort-interfaces
|
|
93
|
+
'perfectionist/sort-interfaces': [
|
|
94
|
+
'error',
|
|
95
|
+
{ order: 'asc', type: 'alphabetical' },
|
|
96
|
+
],
|
|
97
|
+
|
|
98
|
+
// https://perfectionist.dev/rules/sort-intersection-types
|
|
99
|
+
'perfectionist/sort-intersection-types': [
|
|
100
|
+
'error',
|
|
101
|
+
{ order: 'asc', type: 'alphabetical' },
|
|
102
|
+
],
|
|
103
|
+
|
|
104
|
+
// https://perfectionist.dev/rules/sort-jsx-props
|
|
105
|
+
'perfectionist/sort-jsx-props': [
|
|
106
|
+
'error',
|
|
107
|
+
{ order: 'asc', type: 'alphabetical' },
|
|
108
|
+
],
|
|
109
|
+
|
|
110
|
+
// https://perfectionist.dev/rules/sort-modules
|
|
111
|
+
'perfectionist/sort-modules': [
|
|
112
|
+
'error',
|
|
113
|
+
{ order: 'asc', type: 'alphabetical' },
|
|
114
|
+
],
|
|
115
|
+
|
|
116
|
+
// https://perfectionist.dev/rules/sort-named-exports
|
|
117
|
+
'perfectionist/sort-named-exports': [
|
|
118
|
+
'error',
|
|
119
|
+
{ order: 'asc', type: 'alphabetical' },
|
|
120
|
+
],
|
|
121
|
+
|
|
122
|
+
// https://perfectionist.dev/rules/sort-named-imports
|
|
123
|
+
'perfectionist/sort-named-imports': [
|
|
124
|
+
'error',
|
|
125
|
+
{ order: 'asc', type: 'alphabetical' },
|
|
126
|
+
],
|
|
127
|
+
|
|
128
|
+
// https://perfectionist.dev/rules/sort-object-types
|
|
129
|
+
'perfectionist/sort-object-types': [
|
|
130
|
+
'error',
|
|
131
|
+
{ order: 'asc', type: 'alphabetical' },
|
|
132
|
+
],
|
|
133
|
+
|
|
134
|
+
// https://perfectionist.dev/rules/sort-objects
|
|
135
|
+
'perfectionist/sort-objects': [
|
|
136
|
+
'error',
|
|
137
|
+
{
|
|
138
|
+
order: 'asc',
|
|
139
|
+
partitionByComment: true,
|
|
140
|
+
partitionByNewLine: true,
|
|
141
|
+
type: 'alphabetical',
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
|
|
145
|
+
// https://perfectionist.dev/rules/sort-switch-case
|
|
146
|
+
'perfectionist/sort-switch-case': [
|
|
147
|
+
'error',
|
|
148
|
+
{ order: 'asc', type: 'alphabetical' },
|
|
149
|
+
],
|
|
150
|
+
|
|
151
|
+
// https://perfectionist.dev/rules/sort-union-types
|
|
152
|
+
'perfectionist/sort-union-types': [
|
|
153
|
+
'error',
|
|
154
|
+
{ order: 'asc', type: 'alphabetical' },
|
|
155
|
+
],
|
|
156
|
+
},
|
|
157
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import ts from 'typescript-eslint';
|
|
2
|
+
import flatArrayConfig from '../utils/flatArrayConfig.js';
|
|
3
|
+
|
|
4
|
+
const recommendedConfig = flatArrayConfig(ts.configs.recommended);
|
|
5
|
+
|
|
6
|
+
/** @type {import('eslint').Linter.Config} */
|
|
7
|
+
export default {
|
|
8
|
+
...recommendedConfig,
|
|
9
|
+
name: '@todesktop/dev-config/eslint/ts',
|
|
10
|
+
|
|
11
|
+
files: ['**/*.ts', '**/*.tsx'],
|
|
12
|
+
|
|
13
|
+
rules: {
|
|
14
|
+
// https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/flat/recommended.ts
|
|
15
|
+
...recommendedConfig.rules,
|
|
16
|
+
|
|
17
|
+
// Re-enabled in tsStrict
|
|
18
|
+
// https://typescript-eslint.io/rules/no-explicit-any/
|
|
19
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
20
|
+
},
|
|
21
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import ts from 'typescript-eslint';
|
|
2
|
+
import flatArrayConfig from '../utils/flatArrayConfig.js';
|
|
3
|
+
|
|
4
|
+
const strictConfig = flatArrayConfig(ts.configs.strict);
|
|
5
|
+
|
|
6
|
+
/** @type {import('eslint').Linter.Config} */
|
|
7
|
+
export default {
|
|
8
|
+
...strictConfig,
|
|
9
|
+
name: '@todesktop/dev-config/eslint/tsStrict',
|
|
10
|
+
|
|
11
|
+
files: ['**/*.ts', '**/*.tsx'],
|
|
12
|
+
|
|
13
|
+
rules: {
|
|
14
|
+
// https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/flat/strict.ts
|
|
15
|
+
...strictConfig.rules,
|
|
16
|
+
|
|
17
|
+
// Re-enabled after ts config
|
|
18
|
+
// https://typescript-eslint.io/rules/no-explicit-any/
|
|
19
|
+
'@typescript-eslint/no-explicit-any': 'error',
|
|
20
|
+
},
|
|
21
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// I have no idea why import-x's parser has an error passing this lib
|
|
2
|
+
// eslint-disable-next-line
|
|
3
|
+
import unicorn from 'eslint-plugin-unicorn';
|
|
4
|
+
|
|
5
|
+
/** @type {import('eslint').Linter.Config} */
|
|
6
|
+
export default {
|
|
7
|
+
name: '@todesktop/dev-config/eslint/unicorn',
|
|
8
|
+
|
|
9
|
+
plugins: { unicorn },
|
|
10
|
+
|
|
11
|
+
rules: {
|
|
12
|
+
...unicorn.configs.recommended.rules,
|
|
13
|
+
|
|
14
|
+
// Sometimes following the rule makes code less readable
|
|
15
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-function-scoping.md
|
|
16
|
+
'unicorn/consistent-function-scoping': 'off',
|
|
17
|
+
|
|
18
|
+
// e as the name of a handled error is widely used
|
|
19
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/catch-error-name.md
|
|
20
|
+
'unicorn/catch-error-name': 'off',
|
|
21
|
+
|
|
22
|
+
// We use camelCase for many files
|
|
23
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/filename-case.md
|
|
24
|
+
'unicorn/filename-case': 'off',
|
|
25
|
+
|
|
26
|
+
// Ofter `return undefined` specifies the return type explicitly
|
|
27
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-undefined.md
|
|
28
|
+
'unicorn/no-useless-undefined': 'off',
|
|
29
|
+
|
|
30
|
+
// We allow abbreviations in identifiers
|
|
31
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prevent-abbreviations.md
|
|
32
|
+
'unicorn/prevent-abbreviations': 'off',
|
|
33
|
+
|
|
34
|
+
// It's handled by other plugins
|
|
35
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-module.md
|
|
36
|
+
'unicorn/prefer-module': 'off',
|
|
37
|
+
|
|
38
|
+
// Already handled by n/prefer-node-protocol
|
|
39
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-node-protocol.md
|
|
40
|
+
'unicorn/prefer-node-protocol': 'off',
|
|
41
|
+
|
|
42
|
+
// Since most projects are compiled to CommonJS, that's not possible now
|
|
43
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-top-level-await.md
|
|
44
|
+
'unicorn/prefer-top-level-await': 'off',
|
|
45
|
+
},
|
|
46
|
+
};
|
package/eslint/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import base from './configs/base.js';
|
|
2
|
+
import esm from './configs/esm.js';
|
|
3
|
+
import node from './configs/node.js';
|
|
4
|
+
import nodeCommonJs from './configs/nodeCommonJs.js';
|
|
5
|
+
import prettier from './configs/prettier.js';
|
|
6
|
+
import react from './configs/react.js';
|
|
7
|
+
import reactStrict from './configs/reactStrict.js';
|
|
8
|
+
import strict from './configs/strict.js';
|
|
9
|
+
import ts from './configs/ts.js';
|
|
10
|
+
import tsStrict from './configs/tsStrict.js';
|
|
11
|
+
import unicorn from './configs/unicorn.js';
|
|
12
|
+
|
|
13
|
+
// eslint-disable-next-line import-x/no-extraneous-dependencies
|
|
14
|
+
export { defineConfig } from 'eslint/config';
|
|
15
|
+
|
|
16
|
+
export const configs = {
|
|
17
|
+
// Mostly Airbnb base rules
|
|
18
|
+
base,
|
|
19
|
+
|
|
20
|
+
// ESM files, *.js, *.mjs only.
|
|
21
|
+
esm,
|
|
22
|
+
|
|
23
|
+
// Node.js best practices
|
|
24
|
+
node,
|
|
25
|
+
|
|
26
|
+
// CommonJS files, *.js, *.cjs only. Mostly it's deploying scripts and configs
|
|
27
|
+
nodeCommonJs,
|
|
28
|
+
|
|
29
|
+
// Recommended prettier rules
|
|
30
|
+
prettier,
|
|
31
|
+
|
|
32
|
+
// React + React Hooks rules
|
|
33
|
+
react,
|
|
34
|
+
|
|
35
|
+
// Strict rules for React
|
|
36
|
+
reactStrict,
|
|
37
|
+
|
|
38
|
+
// A bit more strict and contains less autofixes than the base config
|
|
39
|
+
strict,
|
|
40
|
+
|
|
41
|
+
// Rules from typescript-eslint
|
|
42
|
+
ts,
|
|
43
|
+
|
|
44
|
+
// Rules from typescript-eslint
|
|
45
|
+
tsStrict,
|
|
46
|
+
|
|
47
|
+
// https://github.com/sindresorhus/eslint-plugin-unicorn
|
|
48
|
+
unicorn,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default { configs };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export default function flatArrayConfig(arrayConfig) {
|
|
2
|
+
if (Array.isArray(arrayConfig)) {
|
|
3
|
+
const mergedConfig = { languageOptions: {}, plugins: {}, rules: {} };
|
|
4
|
+
|
|
5
|
+
for (const config of arrayConfig) {
|
|
6
|
+
Object.assign(mergedConfig.languageOptions, config.languageOptions);
|
|
7
|
+
Object.assign(mergedConfig.plugins, config.plugins);
|
|
8
|
+
Object.assign(mergedConfig.rules, config.rules);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return mergedConfig;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (typeof arrayConfig === 'object' && arrayConfig !== null) {
|
|
15
|
+
return arrayConfig;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
throw new Error('Invalid array config');
|
|
19
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@todesktop/dev-config",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Shared dev configs for ESLint, Prettier, TypeScript, etc",
|
|
5
|
+
"author": "ToDesktop <hello@todesktop.com>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"format": "prettier . --write && eslint --fix",
|
|
10
|
+
"lint": "prettier . --check && eslint"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
"./*": "./*",
|
|
14
|
+
"./eslint": "./eslint/index.js",
|
|
15
|
+
"./prettier": "./prettier/index.js"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@eslint/js": "^9.37.0",
|
|
19
|
+
"eslint-config-airbnb-extended": "^2.3.2",
|
|
20
|
+
"eslint-config-prettier": "^10.1.8",
|
|
21
|
+
"eslint-import-resolver-typescript": "^4.4.4",
|
|
22
|
+
"eslint-plugin-import-x": "^4.16.1",
|
|
23
|
+
"eslint-plugin-n": "^17.23.1",
|
|
24
|
+
"eslint-plugin-perfectionist": "^4.15.1",
|
|
25
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
26
|
+
"eslint-plugin-react": "^7.37.5",
|
|
27
|
+
"eslint-plugin-react-hooks": "^7.0.0",
|
|
28
|
+
"eslint-plugin-unicorn": "^61.0.2",
|
|
29
|
+
"globals": "^15.15.0",
|
|
30
|
+
"typescript-eslint": "^8.46.1"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"eslint": "^9.37.0",
|
|
34
|
+
"prettier": "^3.6.2"
|
|
35
|
+
}
|
|
36
|
+
}
|