@todesktop/dev-config 1.0.1 → 1.0.28

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 CHANGED
@@ -1,20 +1,86 @@
1
1
  # dev-config
2
2
 
3
3
  This package provides reusable development configuration files used across the
4
- repository: ESLint, Prettier, and a base `tsconfig`.
4
+ repository: oxlint, oxfmt, and a base `tsconfig`.
5
5
 
6
- ## ESLint
6
+ ## Oxlint
7
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).
8
+ [Oxlint](https://oxc.rs/docs/guide/usage/linter) is the primary linting tool.
9
+ Shared configs are in `oxlint/` and consumed via each package's
10
+ `oxlint.config.ts`.
11
+
12
+ A typical project config looks like this:
13
+
14
+ ```ts
15
+ import { configs, defineConfig } from '@todesktop/dev-config/oxlint';
16
+
17
+ export default defineConfig({
18
+ overrides: [
19
+ configs.base,
20
+ configs.ts,
21
+ configs.react,
22
+ configs.node,
23
+
24
+ {
25
+ rules: {
26
+ 'no-console': 'off',
27
+ },
28
+ },
29
+ ],
30
+ });
31
+ ```
32
+
33
+ Configs are passed as items in `overrides`. Each item applies to all JS/TS file
34
+ extensions by default. You can also spread a config inline to narrow it to
35
+ specific files:
36
+
37
+ ```ts
38
+ { files: ['**/*.mjs'], ...configs.node }
39
+ ```
40
+
41
+ Available configs:
42
+
43
+ | Config | Strict variant | Description |
44
+ | ------------- | -------------- | ---------------------------------------------------- |
45
+ | base | strict | Airbnb-based JS rules; lenient defaults |
46
+ | ts | tsStrict | TypeScript rules via `@typescript-eslint` |
47
+ | react | reactStrict | React + React Hooks rules |
48
+ | node | - | Node.js best practices + globals |
49
+ | nodeCommonJs | - | CommonJS `.js`/`.cjs` files (configs, scripts) |
50
+ | browser | - | Browser globals |
51
+ | esm | - | ESM-specific rules |
52
+ | unicorn | - | Rules from `eslint-plugin-unicorn` |
53
+ | perfectionist | - | Sorts imports, objects, and types |
54
+ | jest | - | Jest globals (auto-scoped to `**/*.test.ts`) |
55
+ | vitest | - | Vitest globals (auto-scoped to `**/*.test.{ts,tsx}`) |
56
+
57
+ Strict variants tighten rules from their base — for example `tsStrict` turns
58
+ `@typescript-eslint/no-explicit-any` into an error and bans non-null assertions.
59
+ Include the base config alongside its strict variant, as strict does not inherit
60
+ from base automatically.
61
+
62
+ ## tsconfig
63
+
64
+ A shared TypeScript base config is available. To reuse it, extend it from your
65
+ package's `tsconfig.json`:
66
+
67
+ ```json
68
+ {
69
+ "extends": "@todesktop/dev-config/tsconfig.json",
70
+ "include": ["src/**/*.ts"]
71
+ }
72
+ ```
73
+
74
+ ---
75
+
76
+ ## Legacy: ESLint (deprecated)
13
77
 
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)).
78
+ > **ESLint support is legacy.** New projects should use oxlint instead.
79
+
80
+ The ESLint configuration is based on
81
+ [eslint-config-airbnb-extended](https://github.com/NishargShah/eslint-config-airbnb-extended).
82
+ ESLint and all related plugins are optional peer dependencies and will not be
83
+ installed automatically.
18
84
 
19
85
  A typical project config that reuses these shared configs looks like this:
20
86
 
@@ -36,14 +102,7 @@ export default defineConfig(
36
102
  );
37
103
  ```
38
104
 
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.
105
+ Available configs:
47
106
 
48
107
  | Base | Strict | Description |
49
108
  | ------------ | ----------- | ------------------------------------------------------------------- |
@@ -56,20 +115,30 @@ variant, also include the base config, since it's not inherited.
56
115
  | esm | - | ESM-specific rules |
57
116
  | unicorn | - | Rules from `eslint-plugin-unicorn` |
58
117
 
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.
118
+ Since all eslint-related dependencies are removed, you need to install them
119
+ manually:
120
+
121
+ ```sh
122
+ pnpm add -D \
123
+ @eslint/js@^9.37.0 \
124
+ eslint@^9.39.1 \
125
+ eslint-config-airbnb-extended@^2.3.2 \
126
+ eslint-config-prettier@^10.1.8 \
127
+ eslint-import-resolver-typescript@^4.4.4 \
128
+ eslint-plugin-import-x@^4.16.1 \
129
+ eslint-plugin-n@^17.23.1 \
130
+ eslint-plugin-perfectionist@^4.15.1 \
131
+ eslint-plugin-prettier@^5.5.4 \
132
+ eslint-plugin-react@^7.37.5 \
133
+ eslint-plugin-react-hooks@^7.0.0 \
134
+ eslint-plugin-unicorn@^61.0.2 \
135
+ prettier@^3.6.2 \
136
+ typescript-eslint@^8.46.1
137
+ ```
64
138
 
65
- ## tsconfig
139
+ ## Legacy: Prettier (deprecated)
66
140
 
67
- A shared TypeScript base config is available. To reuse it, extend it from your
68
- package's `tsconfig.json`:
141
+ > **Prettier support is legacy.** New projects should use oxfmt instead.
69
142
 
70
- ```json
71
- {
72
- "extends": "@todesktop/dev-config/tsconfig.json",
73
- "include": ["src/**/*.ts"]
74
- }
75
- ```
143
+ A shared Prettier configuration is provided for existing projects. Prettier is
144
+ an optional peer dependency and will not be installed automatically.
@@ -1,4 +1,5 @@
1
1
  import airbnb from 'eslint-config-airbnb-extended';
2
+ import { getConsoleMethods } from './data/console.js';
2
3
 
3
4
  /** @type {import('eslint').Linter.Config} */
4
5
  export default {
@@ -25,15 +26,27 @@ export default {
25
26
  // https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/variables.ts
26
27
  ...airbnb.rules.base.variables.rules,
27
28
 
28
- // Together with enabling for..of
29
- // https://eslint.org/docs/latest/rules/no-restricted-syntax
29
+ // Warn in base, error in strict
30
+ // https://eslint.org/docs/latest/rules/no-await-in-loop
31
+ 'no-await-in-loop': 'warn',
32
+
33
+ // Warn in base, error in strict. console.log should be used only in development mode
34
+ // https://eslint.org/docs/latest/rules/no-console
35
+ 'no-console': ['warn', { allow: getConsoleMethods() }],
36
+
37
+ // Widely used in for..of
38
+ // https://eslint.org/docs/latest/rules/no-continue
30
39
  'no-continue': 'off',
31
40
 
32
- // Re-enabled in strict
41
+ // Warn in base, error in strict
33
42
  // https://eslint.org/docs/latest/rules/no-nested-ternary
34
- 'no-nested-ternary': 'off',
43
+ 'no-nested-ternary': 'warn',
35
44
 
36
- // Re-enabled in strict, keep `Promise((r) => setTimeout(r, 10))` syntax
45
+ // Allow ++ in for loops
46
+ // https://eslint.org/docs/latest/rules/no-plusplus
47
+ 'no-plusplus': ['error', { allowForLoopAfterthoughts: true }],
48
+
49
+ // Off in base, error in strict, keep `Promise((r) => setTimeout(r, 10))` syntax
37
50
  // https://eslint.org/docs/rules/no-promise-executor-return
38
51
  'no-promise-executor-return': 'off',
39
52
 
@@ -58,6 +71,27 @@ export default {
58
71
  },
59
72
  ],
60
73
 
74
+ // Warn in base, error in strict
75
+ // https://eslint.org/docs/latest/rules/no-shadow
76
+ 'no-shadow': 'warn',
77
+
78
+ // Allow underscore in some cases, like destructing third-party objects
79
+ // https://eslint.org/docs/latest/rules/no-underscore-dangle
80
+ 'no-underscore-dangle': [
81
+ 'error',
82
+ {
83
+ allow: ['__mock', '__root'],
84
+ allowAfterSuper: false,
85
+ allowAfterThis: false,
86
+ allowAfterThisConstructor: false,
87
+ allowFunctionParams: true,
88
+ allowInArrayDestructuring: true,
89
+ allowInObjectDestructuring: true,
90
+ enforceInClassFields: false,
91
+ enforceInMethodNames: true,
92
+ },
93
+ ],
94
+
61
95
  // Using before definition allows placing the primary code on the top
62
96
  // https://eslint.org/docs/latest/rules/no-use-before-define
63
97
  'no-use-before-define': 'off',
@@ -0,0 +1,47 @@
1
+ export function getConsoleMethods({ excludeDev = true } = {}) {
2
+ const allMethods = [
3
+ 'assert',
4
+ 'clear',
5
+ 'context',
6
+ 'count',
7
+ 'countReset',
8
+ 'createTask',
9
+ 'debug',
10
+ 'dir',
11
+ 'dirxml',
12
+ 'error',
13
+ 'group',
14
+ 'groupCollapsed',
15
+ 'groupEnd',
16
+ 'info',
17
+ 'log',
18
+ 'profile',
19
+ 'profileEnd',
20
+ 'table',
21
+ 'time',
22
+ 'timeEnd',
23
+ 'timeLog',
24
+ 'timeStamp',
25
+ 'trace',
26
+ 'warn',
27
+ ];
28
+
29
+ const devMethods = [
30
+ 'clear',
31
+ 'count',
32
+ 'countReset',
33
+ 'debug',
34
+ 'log',
35
+ 'profile',
36
+ 'profileEnd',
37
+ 'time',
38
+ 'timeEnd',
39
+ 'timeLog',
40
+ 'timeStamp',
41
+ 'trace',
42
+ ];
43
+
44
+ return excludeDev
45
+ ? allMethods.filter((m) => !devMethods.includes(m))
46
+ : allMethods;
47
+ }
@@ -13,6 +13,12 @@ export default {
13
13
  ...airbnb.plugins.reactHooks.plugins,
14
14
  },
15
15
 
16
+ settings: {
17
+ react: {
18
+ version: 'detect',
19
+ },
20
+ },
21
+
16
22
  rules: {
17
23
  // https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/react/react.ts
18
24
  ...airbnb.rules.react.base.rules,
@@ -20,26 +26,29 @@ export default {
20
26
  // https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/react/reactHooks.ts
21
27
  ...airbnb.rules.react.hooks.rules,
22
28
 
29
+ // Warn in base, error in strict
30
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/destructuring-assignment.md
31
+ 'react/destructuring-assignment': 'warn',
32
+
33
+ // Off in base, error in strict, since it's widely used
34
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/function-component-definition.md
35
+ 'react/function-component-definition': 'off',
36
+
23
37
  // Add tsx extension
24
38
  // 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',
39
+ 'react/jsx-filename-extension': ['error', { extensions: ['.jsx', '.tsx'] }],
40
+
41
+ // Not always useful
42
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md
43
+ 'react/jsx-no-bind': 'off',
35
44
 
36
45
  // There are a lot of existed cases that would look worse after applying
37
46
  // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-one-expression-per-line.md
38
47
  'react/jsx-one-expression-per-line': 'off',
39
48
 
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',
49
+ // Warn in base, error in strict
50
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unescaped-entities.md
51
+ 'react/no-unescaped-entities': 'warn',
43
52
 
44
53
  // I think only web-app doesn't use react-jsx runtime
45
54
  // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/react-in-jsx-scope.md
@@ -48,5 +57,9 @@ export default {
48
57
  // It's better handled by TSC
49
58
  // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/prop-types.md
50
59
  'react/require-default-props': 'off',
60
+
61
+ // Warn in base, error in strict
62
+ // https://react.dev/reference/eslint-plugin-react-hooks/lints/exhaustive-deps
63
+ 'react-hooks/exhaustive-deps': 'warn',
51
64
  },
52
65
  };
@@ -8,11 +8,11 @@ export default {
8
8
  // https://github.com/NishargShah/eslint-config-airbnb-extended/blob/master/packages/eslint-config-airbnb-extended/rules/react/reactStrict.ts
9
9
  ...airbnb.rules.react.strict.rules,
10
10
 
11
- // Re-enabling
11
+ // Warn in base, error in strict
12
12
  // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/destructuring-assignment.md
13
13
  'react/destructuring-assignment': 'error',
14
14
 
15
- // Re-enabling
15
+ // Off in base, error in strict
16
16
  // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/function-component-definition.md
17
17
  'react/function-component-definition': [
18
18
  'error',
@@ -21,5 +21,13 @@ export default {
21
21
  unnamedComponents: 'function-expression',
22
22
  },
23
23
  ],
24
+
25
+ // Warn in base, error in strict
26
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unescaped-entities.md
27
+ 'react/no-unescaped-entities': 'error',
28
+
29
+ // Warn in base, error in strict
30
+ // https://react.dev/reference/eslint-plugin-react-hooks/lints/exhaustive-deps
31
+ 'react-hooks/exhaustive-deps': 'error',
24
32
  },
25
33
  };
@@ -1,5 +1,6 @@
1
1
  import airbnb from 'eslint-config-airbnb-extended';
2
2
  import perfectionist from 'eslint-plugin-perfectionist';
3
+ import { getConsoleMethods } from './data/console.js';
3
4
 
4
5
  /** @type {import('eslint').Linter.Config} */
5
6
  export default {
@@ -36,6 +37,18 @@ export default {
36
37
  },
37
38
  ],
38
39
 
40
+ // Configure whitelist
41
+ // https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-extraneous-dependencies.md
42
+ 'import-x/no-extraneous-dependencies': [
43
+ 'error',
44
+ {
45
+ ...airbnb.rules.base.imports.rules[
46
+ 'import-x/no-extraneous-dependencies'
47
+ ][1],
48
+ whitelist: ['@todesktop/dev-config'],
49
+ },
50
+ ],
51
+
39
52
  // It's often useful to rename default exports
40
53
  // https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-rename-default.md
41
54
  'import-x/no-rename-default': 'off',
@@ -52,14 +65,26 @@ export default {
52
65
  // https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/prefer-default-export.md
53
66
  'import-x/prefer-default-export': 'off',
54
67
 
55
- // Re-enabling
68
+ // Warn in base, error in strict
69
+ // https://eslint.org/docs/latest/rules/no-await-in-loop
70
+ 'no-await-in-loop': 'error',
71
+
72
+ // Warn in base, error in strict. console.log should be used only in development mode
73
+ // https://eslint.org/docs/latest/rules/no-console
74
+ 'no-console': ['error', { allow: getConsoleMethods() }],
75
+
76
+ // Warn in base, error in strict
56
77
  // https://eslint.org/docs/latest/rules/no-nested-ternary
57
78
  'no-nested-ternary': 'error',
58
79
 
59
- // Re-enabling
80
+ // Off in base, error in strict
60
81
  // https://eslint.org/docs/rules/no-promise-executor-return
61
82
  'no-promise-executor-return': 'error',
62
83
 
84
+ // Warn in base, error in strict
85
+ // https://eslint.org/docs/latest/rules/no-shadow
86
+ 'no-shadow': 'error',
87
+
63
88
  // https://perfectionist.dev/rules/sort-array-includes
64
89
  'perfectionist/sort-array-includes': [
65
90
  'error',
@@ -17,5 +17,20 @@ export default {
17
17
  // Re-enabled in tsStrict
18
18
  // https://typescript-eslint.io/rules/no-explicit-any/
19
19
  '@typescript-eslint/no-explicit-any': 'off',
20
+
21
+ // Tune some options
22
+ // https://typescript-eslint.io/rules/no-unused-vars/
23
+ '@typescript-eslint/no-unused-vars': [
24
+ 'error',
25
+ {
26
+ args: 'all',
27
+ argsIgnorePattern: '^_',
28
+ caughtErrors: 'all',
29
+ caughtErrorsIgnorePattern: '^_',
30
+ destructuredArrayIgnorePattern: '^_',
31
+ ignoreRestSiblings: true,
32
+ varsIgnorePattern: '^_',
33
+ },
34
+ ],
20
35
  },
21
36
  };
package/eslint/index.js CHANGED
@@ -10,7 +10,6 @@ import ts from './configs/ts.js';
10
10
  import tsStrict from './configs/tsStrict.js';
11
11
  import unicorn from './configs/unicorn.js';
12
12
 
13
- // eslint-disable-next-line import-x/no-extraneous-dependencies
14
13
  export { defineConfig } from 'eslint/config';
15
14
 
16
15
  export const configs = {