@josundt/eslint-config 5.4.1 → 5.6.3

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,6 +1,6 @@
1
1
  # @josundt/eslint-config #
2
2
 
3
- ESLint ruleset including required ESLint plugins for jorundt TypeScript projects
3
+ ESLint ruleset including required ESLint plugins for josundt TypeScript projects
4
4
 
5
5
  ## Usage ##
6
6
  1. Make sure you have installed and configured `@josundt/prettier-config` first
@@ -10,20 +10,37 @@ ESLint ruleset including required ESLint plugins for jorundt TypeScript projects
10
10
  npm install @josundt/eslint-config
11
11
  ```
12
12
 
13
- 3. Create an `.eslintrc` file in the root directory of your project with the following content:
13
+ 3. Create an `eslint.config.js` file in the root directory of your project with approximately the following content:
14
14
  ```javascript
15
- {
16
- "extends": ["@josundt"]
17
- }
18
- ```
19
- > `["@josundt"]` is the default configuration for __typescript__ __web__ projects with __jasmine__ unit tests
15
+ import tsBrowserConfig from "@josundt/eslint-config/ts-browser";
16
+ import tsJestBrowserConfig from "@josundt/eslint-config/ts-jest-browser";
17
+
18
+ // When the project has JEST tests
19
+ const config = [
20
+ {
21
+ ...tsBrowserConfig,
22
+ files: ["src/**/*.ts"]
23
+ },
24
+ {
25
+ ...tsJestBrowserConfig,
26
+ files: ["test/**/?(*.)+(spec).ts?(x)"]
27
+ }
28
+ ];
20
29
 
21
- Other configurations:
22
- * `["@josundt/eslint-config/typescript-web"]` (same as default; only without __jasmine__ linting support).
30
+ // Otherwise
31
+ const config = {
32
+ ...tsBrowserConfig,
33
+ files: ["src/**/*.ts"]
34
+ };
23
35
 
24
- * `["@josundt/eslint-config/typescript-node-jasmine"]` (same as default; but without __browser__ environment).
36
+ export default config;
37
+ ```
25
38
 
26
- * `["@josundt/eslint-config/typescript-node"]` (same as default; but without __browser__ environment and __jasmine__ linting support) .
39
+ All configurations:
40
+ * `["@josundt/eslint-config/ts-browser"]` (for browser environment code).
41
+ * `["@josundt/eslint-config/ts-node"]` (for node environment code).
42
+ * `["@josundt/eslint-config/ts-jest-browser"]` (for Jest tests for browser environment code).
43
+ * `["@josundt/eslint-config/ts-jest-node"]` (for Jest tests for node environment code).
27
44
 
28
45
 
29
46
  4. Add `lint:ts` script to your project's package.json file:
@@ -32,7 +49,7 @@ ESLint ruleset including required ESLint plugins for jorundt TypeScript projects
32
49
  // ...
33
50
  "scripts": {
34
51
  // ...
35
- "lint:ts": "eslint ./src --format visualstudio --ext .ts,.tsx"
52
+ "lint:ts": "eslint src test --format visualstudio"
36
53
  // ...
37
54
  }
38
55
  // ...
@@ -44,10 +61,26 @@ ESLint ruleset including required ESLint plugins for jorundt TypeScript projects
44
61
  npm run lint:ts
45
62
  ```
46
63
 
47
- 6. Live Code Analysis in Visual Studio Code:
48
- - Add a `.eslintignore` file in the root directory of your project with the following content:
49
- ```text
50
- # Ignore js files; only analyze typescript files:
51
- **/*.js
52
- ```
64
+ 6. Task in Visual Studio Code:
65
+ - Add the following to `.vscode/tasks.json`:
66
+ ```json
67
+ {
68
+ //...
69
+ "tasks": [
70
+ //...
71
+ {
72
+ "label": "lint:ts",
73
+ "type": "shell",
74
+ "command": "npx",
75
+ "args": ["eslint", "src", "test", "-f", "stylish"],
76
+ "group": "build",
77
+ "problemMatcher": "$eslint-stylish"
78
+ },
79
+ //...
80
+ ]
81
+ //...
82
+ }
83
+ ```
84
+
85
+ 7. Live Code Analysis in Visual Studio Code:
53
86
  - Install extension for VSCode: __ESLint (_dbaeumer.vscode-eslint_)__
package/index.js CHANGED
@@ -1 +1,3 @@
1
- module.exports = require("./typescript-web-jest");
1
+ import tsWebJest from "./typescript-web-jest.js";
2
+
3
+ export default tsWebJest;
package/package.json CHANGED
@@ -1,8 +1,19 @@
1
1
  {
2
2
  "name": "@josundt/eslint-config",
3
- "version": "5.4.1",
3
+ "version": "5.6.3",
4
4
  "description": "ESLint ruleset with required plugins for josundt TypeScript projects",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": "./index.js",
8
+ "./ts-browser": "./ts-browser.js",
9
+ "./ts-jest-browser": "./ts-jest-browser.js",
10
+ "./ts-node": "./ts-node.js",
11
+ "./ts-jest-node": "./ts-jest-node.js"
12
+ },
5
13
  "main": "index.js",
14
+ "engines": {
15
+ "node": "^20.9.0 || >=21.1.0"
16
+ },
6
17
  "scripts": {
7
18
  "lint": "echo \"No linting for this project\"",
8
19
  "build": "echo \"No build for this project\"",
@@ -27,22 +38,25 @@
27
38
  "utils/**/*.js"
28
39
  ],
29
40
  "peerDependencies": {
30
- "typescript": ">=5.4.2"
41
+ "typescript": ">=5.6.3"
31
42
  },
32
43
  "dependencies": {
33
- "@josundt/prettier-config": "^3.2.5",
34
- "@typescript-eslint/eslint-plugin": "7.2.0",
35
- "@typescript-eslint/parser": "7.2.0",
36
- "eslint": "8.57.0",
37
- "eslint-import-resolver-typescript": "3.6.1",
38
- "eslint-plugin-deprecation": "2.0.0",
44
+ "@josundt/prettier-config": "^3.3.3",
45
+ "@eslint/js": "9.14.0",
46
+ "@typescript-eslint/eslint-plugin": "8.13.0",
47
+ "@typescript-eslint/parser": "8.13.0",
48
+ "eslint": "9.14.0",
49
+ "eslint-formatter-visualstudio": "8.40.0",
50
+ "eslint-import-resolver-typescript": "3.6.3",
39
51
  "eslint-plugin-eslint-comments": "3.2.0",
40
- "eslint-plugin-import": "2.29.1",
41
- "eslint-plugin-jasmine": "4.1.3",
42
- "eslint-plugin-jest": "27.9.0",
43
- "eslint-plugin-jsdoc": "48.2.1",
44
- "eslint-plugin-no-lookahead-lookbehind-regexp": "0.3.0",
45
- "eslint-plugin-prettier": "5.1.3",
46
- "eslint-plugin-unicorn": "51.0.1"
52
+ "eslint-plugin-import": "2.31.0",
53
+ "eslint-plugin-jasmine": "4.2.2",
54
+ "eslint-plugin-jest": "28.9.0",
55
+ "eslint-plugin-jsdoc": "50.4.3",
56
+ "eslint-plugin-prettier": "5.2.1",
57
+ "eslint-plugin-unicorn": "56.0.0"
58
+ },
59
+ "devDependencies": {
60
+ "@types/eslint__js": "8.42.3"
47
61
  }
48
62
  }
@@ -1,5 +1,9 @@
1
- module.exports = {
2
- plugins: ["eslint-plugin-eslint-comments"],
1
+ import plugin from "eslint-plugin-eslint-comments";
2
+ import { ConfigUtil } from "../utils/config-util.js";
3
+
4
+ export default ConfigUtil.getPluginConfig({
5
+ plugin: plugin,
6
+ namespace: "eslint-comments",
3
7
  rules: {
4
8
  "eslint-comments/disable-enable-pair": "warn",
5
9
  "eslint-comments/no-aggregating-enable": "warn",
@@ -8,4 +12,4 @@ module.exports = {
8
12
  "eslint-comments/no-unused-enable": "warn",
9
13
  "eslint-comments/no-unused-disable": "warn"
10
14
  }
11
- };
15
+ });
package/rules/eslint.js CHANGED
@@ -1,6 +1,8 @@
1
- module.exports = {
2
- extends: ["eslint:recommended"],
1
+ import jsPlugin from "@eslint/js";
2
+
3
+ export default {
3
4
  rules: {
5
+ ...jsPlugin.configs.recommended.rules,
4
6
  "arrow-body-style": "error",
5
7
  "arrow-parens": ["error", "as-needed"],
6
8
  "class-methods-use-this": ["off", { enforceForClassFields: true }], // Warn when methods could be static
@@ -38,8 +40,10 @@ module.exports = {
38
40
  "no-array-constructor": "error",
39
41
  "no-bitwise": "error",
40
42
  "no-caller": "error",
43
+ "no-case-declarations": "error",
41
44
  "no-console": "error",
42
45
  "no-constant-binary-expression": "error",
46
+ "no-constant-condition": "error",
43
47
  "no-duplicate-imports": "error",
44
48
  "no-empty-function": [
45
49
  "error",
@@ -48,23 +52,45 @@ module.exports = {
48
52
  }
49
53
  ],
50
54
  "no-empty-static-block": "error",
55
+ "no-extra-boolean-cast": "error",
51
56
  "no-eval": "error",
52
57
  "no-extra-bind": "error",
58
+ "no-fallthrough": "error",
53
59
  "no-implicit-coercion": ["error", { allow: ["!!"] }],
54
60
  "no-implied-eval": "error",
55
- "no-inner-declarations": "off", // Switched off from recommended rules, gave too many issues
61
+ "no-invalid-regexp": "error",
56
62
  "no-invalid-this": "error",
57
- "no-multi-str": "error",
58
63
  "no-lone-blocks": "error",
59
64
  "no-lonely-if": "error",
65
+ "no-loop-func": "off",
66
+ "no-misleading-character-class": "error",
67
+ "no-multi-str": "error",
60
68
  "no-new-func": "error",
69
+ "no-new-native-nonconstructor": "error",
61
70
  "no-new-wrappers": "error",
62
71
  "no-octal-escape": "error",
63
72
  "no-redeclare": "error",
73
+ "no-restricted-exports": [
74
+ "off",
75
+ {
76
+ // restrictedNamedExports: [
77
+ // "default" /* Disallows default exports */,
78
+ // "foo",
79
+ // "bar"
80
+ // ],
81
+ // restrictedNamedExportsPattern: "bar$"
82
+ }
83
+ ],
64
84
  "no-restricted-imports": [
65
85
  "off",
66
86
  {
67
- paths: []
87
+ // paths: [
88
+ // {
89
+ // name: "import-foo",
90
+ // importNames: ["Bar"], // optional - if only certain exports are restricted
91
+ // message: "Please use Bar from /import-bar/baz/ instead."
92
+ // }
93
+ // ]
68
94
  }
69
95
  ],
70
96
  "no-restricted-syntax": [
@@ -118,7 +144,9 @@ module.exports = {
118
144
  allow: [] // array of identifier names for which shadowing is allowed
119
145
  }
120
146
  ],
147
+ "no-sparse-arrays": "error",
121
148
  "no-template-curly-in-string": "error",
149
+ "no-this-before-super": "error",
122
150
  "no-throw-literal": "error",
123
151
  "no-trailing-spaces": "warn",
124
152
  "no-undef-init": "error",
@@ -135,10 +163,16 @@ module.exports = {
135
163
  {
136
164
  vars: "all",
137
165
  args: "none",
138
- destructuredArrayIgnorePattern: "^_"
166
+ destructuredArrayIgnorePattern: "^_",
167
+ ignoreRestSiblings: false,
168
+ caughtErrors: "all",
169
+ ignoreClassWithStaticInitBlock: false,
170
+ reportUsedIgnorePattern: false
139
171
  }
140
172
  ],
141
173
  "no-use-before-define": "error",
174
+ "no-useless-assignment": "error",
175
+ "no-useless-computed-key": "error",
142
176
  "no-useless-constructor": "error",
143
177
  "no-var": "error",
144
178
  "no-void": "error",
@@ -167,8 +201,14 @@ module.exports = {
167
201
  "quote-props": ["error", "consistent-as-needed"],
168
202
  "radix": "error",
169
203
  "require-await": "error",
170
- "require-unicode-regexp": "error",
204
+ "require-unicode-regexp": [
205
+ "error",
206
+ {
207
+ requireFlag: "u" // "v" is superset of "u" but requires ES2024; adds support for "Unicode properties of strings" and "Set notation"
208
+ }
209
+ ],
171
210
  "return-await": "error",
211
+ "use-isnan": "error",
172
212
  "unicode-bom": ["error", "never"],
173
213
  "yoda": "error"
174
214
  }
@@ -1,6 +1,9 @@
1
- module.exports = {
2
- extends: ["./import-typescript-node.js"],
1
+ import nodeConfig from "./import-typescript-node.js";
2
+
3
+ export default {
4
+ ...nodeConfig,
3
5
  rules: {
6
+ ...nodeConfig.rules,
4
7
  "import/no-nodejs-modules": "error" // Disallowed: import * as path from "path"; Allowed: import * as path from "node:path";
5
8
  }
6
9
  };
@@ -1,6 +1,10 @@
1
- module.exports = {
2
- extends: ["plugin:import/typescript"],
3
- plugins: ["import"],
1
+ import plugin from "eslint-plugin-import";
2
+ import { ConfigUtil } from "../utils/config-util.js";
3
+
4
+ export default ConfigUtil.getPluginConfig({
5
+ plugin: plugin,
6
+ namespace: "import",
7
+ templateNames: ["typescript"],
4
8
  rules: {
5
9
  "import/extensions": [
6
10
  // Ensure all local .ts file imports use .js extension
@@ -17,4 +21,4 @@ module.exports = {
17
21
  "import/no-unassigned-import": "error",
18
22
  "import/order": "off"
19
23
  }
20
- };
24
+ });
package/rules/jasmine.js CHANGED
@@ -1,14 +1,15 @@
1
- module.exports = {
2
- extends: ["plugin:jasmine/recommended"],
3
- env: {
4
- jasmine: true
5
- },
6
- plugins: ["jasmine"],
1
+ import plugin from "eslint-plugin-jasmine";
2
+ import { ConfigUtil } from "../utils/config-util.js";
3
+
4
+ export default ConfigUtil.getPluginConfig({
5
+ plugin: plugin,
6
+ namespace: "jasmine",
7
+ templateNames: ["recommended"],
7
8
  rules: {
8
9
  "jasmine/no-suite-dupes": ["error", "branch"],
9
10
  "jasmine/no-spec-dupes": ["error", "branch"],
10
- "jasmine/no-describe-variables": "error",
11
+ "jasmine/no-describe-variables": "off",
11
12
  "jasmine/new-line-between-declarations": "off", // formatting rule conflicting with formatters (e.g. prettier)
12
13
  "jasmine/new-line-before-expect": "off" // formatting rule conflicting with formatters (e.g. prettier)
13
14
  }
14
- };
15
+ });
package/rules/jest.js CHANGED
@@ -1,10 +1,11 @@
1
- module.exports = {
2
- extends: ["plugin:jest/recommended"],
3
- env: {
4
- "jest/globals": true
5
- },
6
- plugins: ["jest"],
1
+ import plugin from "eslint-plugin-jest";
2
+ import { ConfigUtil } from "../utils/config-util.js";
3
+
4
+ export default ConfigUtil.getPluginConfig({
5
+ plugin: plugin,
6
+ namespace: "jest",
7
+ templateNames: ["recommended"],
7
8
  rules: {
8
9
  "jest/unbound-method": "error"
9
10
  }
10
- };
11
+ });
@@ -1,18 +1,11 @@
1
- module.exports = {
2
- extends: ["plugin:jsdoc/recommended"],
3
- plugins: ["jsdoc"],
4
- settings: {
5
- jsdoc: {
6
- mode: "typescript",
7
- tagNamePreference: {
8
- augments: {
9
- message:
10
- "@extends is to be used over @augments as it is more evocative of classes than @augments",
11
- replacement: "extends"
12
- }
13
- }
14
- }
15
- },
1
+ import plugin from "eslint-plugin-jsdoc";
2
+
3
+ import { ConfigUtil } from "../utils/config-util.js";
4
+
5
+ export default ConfigUtil.getPluginConfig({
6
+ plugin: plugin,
7
+ namespace: "jsdoc",
8
+ templateNames: ["recommended"],
16
9
  rules: {
17
10
  "jsdoc/require-jsdoc": "off",
18
11
  "jsdoc/no-types": "error",
@@ -32,5 +25,17 @@ module.exports = {
32
25
  ]
33
26
  }
34
27
  ]
28
+ },
29
+ settings: {
30
+ jsdoc: {
31
+ mode: "typescript",
32
+ tagNamePreference: {
33
+ augments: {
34
+ message:
35
+ "@extends is to be used over @augments as it is more evocative of classes than @augments",
36
+ replacement: "extends"
37
+ }
38
+ }
39
+ }
35
40
  }
36
- };
41
+ });
package/rules/prettier.js CHANGED
@@ -1,6 +1,10 @@
1
- module.exports = {
2
- plugins: ["prettier"],
1
+ import plugin from "eslint-plugin-prettier";
2
+ import { ConfigUtil } from "../utils/config-util.js";
3
+
4
+ export default ConfigUtil.getPluginConfig({
5
+ plugin: plugin,
6
+ namespace: "prettier",
3
7
  rules: {
4
8
  "prettier/prettier": "error"
5
9
  }
6
- };
10
+ });
@@ -1,5 +1,5 @@
1
- const eslintRuleSet = require("../eslint.js");
2
- const { deepMergeObjects } = require("../../utils/merge.js");
1
+ import eslintRuleSet from "../eslint.js";
2
+ import { deepMergeObjects } from "../../utils/merge.js";
3
3
 
4
4
  const eslintRules = eslintRuleSet.rules;
5
5
 
@@ -56,7 +56,6 @@ const extensions = new Map([
56
56
  ["no-implied-eval", true],
57
57
  ["no-invalid-this", false],
58
58
  ["no-loop-func", true],
59
- ["no-loss-of-precision", true],
60
59
  ["no-magic-numbers", true],
61
60
  ["no-redeclare", true],
62
61
  ["no-restricted-imports", true],
@@ -72,9 +71,9 @@ const extensions = new Map([
72
71
  return o;
73
72
  }
74
73
  ],
75
- ["no-throw-literal", true],
74
+ ["no-undef", false], // Causes problems when scanning type annotations in TS code (v8.10.0)
76
75
  ["no-unused-expressions", true],
77
- ["no-unused-vars", false],
76
+ ["no-unused-vars", true],
78
77
  ["no-use-before-define", false],
79
78
  ["no-useless-constructor", false],
80
79
  [
@@ -91,7 +90,7 @@ const extensions = new Map([
91
90
  // console.log("Not converted:", Array.from(extensions.keys()).filter(k => !Object.keys(extensionRules).filter(k => !k.startsWith("@typescript")).includes(k)));
92
91
 
93
92
  // Building eslint-typescript rules for existsing eslint rules and switching off original eslint rule
94
- module.exports.typescriptEslintExtensionrules = Object.entries(
93
+ export const typescriptEslintExtensionrules = Object.entries(
95
94
  eslintRules
96
95
  ).reduce((extRules, [key, value]) => {
97
96
  // Try to get from known extensions map
@@ -21,12 +21,6 @@ const rules = {
21
21
  }
22
22
  ],
23
23
  "ban-tslint-comment": "error", // No longer use tslint - remove rules
24
- "ban-types": [
25
- "error",
26
- {
27
- // Enable additional/disable default disabled types here
28
- }
29
- ],
30
24
  "class-literal-property-style": "off",
31
25
  "consistent-generic-constructors": ["off", "constructor"],
32
26
  "consistent-indexed-object-style": ["error", "record"],
@@ -81,19 +75,6 @@ const rules = {
81
75
  allowedNames: []
82
76
  }
83
77
  ],
84
- "member-delimiter-style": [
85
- "error",
86
- {
87
- multiline: {
88
- delimiter: "semi",
89
- requireLast: true
90
- },
91
- singleline: {
92
- delimiter: "semi",
93
- requireLast: false
94
- }
95
- }
96
- ],
97
78
  "member-ordering": "off",
98
79
  "method-signature-style": "off", // useful rule since lambda method notation enforces stricter type checking, but has somme inconveniences for ovelaoads, "implement interface" refactoring, and general code complexity
99
80
  "naming-convention": [
@@ -146,6 +127,7 @@ const rules = {
146
127
  ignoreArrowShorthand: true
147
128
  }
148
129
  ],
130
+ "no-deprecated": "error",
149
131
  "no-duplicate-enum-values": "error",
150
132
  "no-duplicate-type-constituents": "error",
151
133
  "no-dynamic-delete": "error",
@@ -192,32 +174,51 @@ const rules = {
192
174
  "no-non-null-assertion": "off",
193
175
  "no-redundant-type-constituents": "error",
194
176
  "no-require-imports": "error",
195
- "no-unsafe-enum-comparison": "error",
196
- "no-unsafe-unary-minus": "error",
197
- "no-this-alias": "error",
198
- "no-throw-literal": [
177
+ "no-restricted-types": [
199
178
  "error",
200
179
  {
201
- allowThrowingAny: false, // Default is to allow throwing values of type any
202
- allowThrowingUnknown: true // Default is to allow throwing values of type unknown
180
+ types: {
181
+ // // add a custom message, and tell the plugin how to fix it
182
+ // OldAPI: {
183
+ // message: "Use NewAPI instead",
184
+ // fixWith: "NewAPI"
185
+ // },
186
+ // // add a custom message, and tell the plugin how to suggest a fix
187
+ // SoonToBeOldAPI: {
188
+ // message: "Use NewAPI instead",
189
+ // suggest: ["NewAPIOne", "NewAPITwo"]
190
+ // }
191
+ }
203
192
  }
204
193
  ],
194
+ "no-unsafe-enum-comparison": "error",
195
+ "no-unsafe-unary-minus": "error",
196
+ "no-this-alias": "error",
205
197
  "no-unnecessary-boolean-literal-compare": "error",
206
198
  "no-unnecessary-condition": "off", // allow runtime null checks etc even if reported not necessary by type system
199
+ "no-unnecessary-parameter-property-assignment": "error",
207
200
  "no-unnecessary-qualifier": "error",
208
201
  "no-unnecessary-type-arguments": "off",
209
202
  "no-unnecessary-type-assertion": "off",
210
203
  "no-unnecessary-type-constraint": "error",
204
+ "no-unnecessary-type-parameters": "off", // added but not yet switched on
211
205
  "no-unsafe-argument": "error",
212
206
  "no-unsafe-assignment": "error",
213
207
  "no-unsafe-call": "error",
214
208
  "no-unsafe-member-access": "error",
215
209
  "no-unsafe-return": "error",
216
- "no-unused-vars-experimental": "off", // to strict with method params...
217
210
  "no-useless-empty-export": "error",
218
- "no-useless-template-literals": "error",
211
+ "no-unnecessary-template-expression": "error",
219
212
  "no-var-requires": "error",
220
213
  "non-nullable-type-assertion-style": "error",
214
+ "only-throw-error": [
215
+ "error",
216
+ {
217
+ allow: [],
218
+ allowThrowingAny: false, // Default is to disallow throwing values of type any
219
+ allowThrowingUnknown: false // Default is to disallow throwing values of type unknown
220
+ }
221
+ ],
221
222
  "parameter-properties": [
222
223
  "error",
223
224
  {
@@ -236,9 +237,11 @@ const rules = {
236
237
  "prefer-nullish-coalescing": [
237
238
  "error",
238
239
  {
240
+ allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing: false,
239
241
  ignoreConditionalTests: true,
240
- ignoreTernaryTests: true,
241
- ignoreMixedLogicalExpressions: true,
242
+ ignoreTernaryTests: false,
243
+ ignoreMixedLogicalExpressions: false,
244
+ ignoreBooleanCoercion: false,
242
245
  ignorePrimitives: {
243
246
  string: false,
244
247
  number: false,
@@ -259,7 +262,6 @@ const rules = {
259
262
  allowSingleElementEquality: "never"
260
263
  }
261
264
  ],
262
- "prefer-ts-expect-error": "error",
263
265
  "promise-function-async": "off",
264
266
  "require-array-sort-compare": [
265
267
  "error",
@@ -277,7 +279,9 @@ const rules = {
277
279
  "restrict-template-expressions": [
278
280
  "error",
279
281
  {
282
+ allow: [{ name: ["URL", "URLSearchParams"], from: "lib" }],
280
283
  allowAny: false,
284
+ allowArray: false,
281
285
  allowBoolean: false,
282
286
  allowNever: false,
283
287
  allowNullish: false,
@@ -285,7 +289,6 @@ const rules = {
285
289
  allowRegExp: false
286
290
  }
287
291
  ],
288
- "sort-type-constituents": "off",
289
292
  "strict-boolean-expressions": [
290
293
  "off",
291
294
  {
@@ -302,11 +305,11 @@ const rules = {
302
305
  "error",
303
306
  {
304
307
  allowDefaultCaseForExhaustiveSwitch: true,
308
+ considerDefaultExhaustiveForUnions: true,
305
309
  requireDefaultForNonUnion: false
306
310
  }
307
311
  ],
308
312
  "triple-slash-reference": "error",
309
- "type-annotation-spacing": "error", // This is a formatting rule
310
313
  "typedef": [
311
314
  "error",
312
315
  {
@@ -320,11 +323,12 @@ const rules = {
320
323
  }
321
324
  ],
322
325
  "unbound-method": "error",
323
- "unified-signatures": "off"
326
+ "unified-signatures": "off",
327
+ "use-unknown-in-catch-callback-variable": "error"
324
328
  };
325
329
 
326
330
  // Rules - append "@typescript-eslint/" to rule names
327
- module.exports.typescriptEslintRules = Object.entries(rules).reduce(
331
+ export const typescriptEslintRules = Object.entries(rules).reduce(
328
332
  (aggr, [key, value]) => ({
329
333
  ...aggr,
330
334
  [`@typescript-eslint/${key}`]: value
@@ -1,17 +1,19 @@
1
- const { typescriptEslintRules } = require("./typescript-eslint/rules.js");
2
- const {
3
- typescriptEslintExtensionrules
4
- } = require("./typescript-eslint/extensionrules.js");
1
+ import { ConfigUtil } from "../utils/config-util.js";
5
2
 
6
- module.exports = {
7
- extends: [
8
- "./eslint",
9
- "plugin:@typescript-eslint/recommended",
10
- "plugin:@typescript-eslint/recommended-requiring-type-checking"
11
- ],
12
- plugins: ["@typescript-eslint/eslint-plugin"],
13
- rules: {
14
- ...typescriptEslintRules,
15
- ...typescriptEslintExtensionrules
16
- }
3
+ import { typescriptEslintRules } from "./typescript-eslint/rules.js";
4
+ import { typescriptEslintExtensionrules } from "./typescript-eslint/extensionrules.js";
5
+ import esLintConfig from "./eslint.js";
6
+
7
+ import plugin from "@typescript-eslint/eslint-plugin";
8
+
9
+ export default {
10
+ ...ConfigUtil.mergeSettingsPluginsAndRules(esLintConfig, {
11
+ plugins: { "@typescript-eslint": plugin },
12
+ rules: {
13
+ ...plugin.configs["recommended"].rules,
14
+ ...plugin.configs["recommended-requiring-type-checking"].rules,
15
+ ...typescriptEslintRules,
16
+ ...typescriptEslintExtensionrules
17
+ }
18
+ })
17
19
  };
package/rules/unicorn.js CHANGED
@@ -1,5 +1,7 @@
1
- module.exports = {
2
- plugins: ["unicorn"],
1
+ import plugin from "eslint-plugin-unicorn";
2
+
3
+ export default {
4
+ plugins: { unicorn: plugin },
3
5
  rules: {
4
6
  "unicorn/filename-case": [
5
7
  "error",
package/ts-browser.js ADDED
@@ -0,0 +1,24 @@
1
+ import globals from "globals";
2
+ import { ConfigUtil } from "./utils/config-util.js";
3
+
4
+ import commentsConfig from "./rules/eslint-comments.js";
5
+ import importTsBrowserConfig from "./rules/import-typescript-browser.js";
6
+ import jsdocTsConfig from "./rules/jsdoc-typescript.js";
7
+ import prettierConfig from "./rules/prettier.js";
8
+ import tsEslintConfig from "./rules/typescript-eslint.js";
9
+ import unicornConfig from "./rules/unicorn.js";
10
+
11
+ export default ConfigUtil.createTsConfig(
12
+ {
13
+ ecmaVersion: 2019,
14
+ globals: globals.browser,
15
+ files: ["**/*.{js,mjs,cjs,ts,mts,mjs}"],
16
+ tsConfig: "tsconfig.json"
17
+ },
18
+ commentsConfig,
19
+ importTsBrowserConfig,
20
+ jsdocTsConfig,
21
+ prettierConfig,
22
+ tsEslintConfig,
23
+ unicornConfig
24
+ );
@@ -0,0 +1,26 @@
1
+ import globals from "globals";
2
+ import webOptions from "./ts-browser.js";
3
+ import jestConfig from "./rules/jest.js";
4
+ import jasmineConfig from "./rules/jasmine.js";
5
+ import { ConfigUtil } from "./utils/config-util.js";
6
+
7
+ const config = ConfigUtil.createTsConfig(
8
+ {
9
+ ecmaVersion: 2019,
10
+ globals: {
11
+ ...globals.browser,
12
+ ...globals.jest,
13
+ ...globals.jasmine
14
+ },
15
+ files: ["**/?(*.)+(spec).{js,mjs,cjs,ts,mts,cts}?(x)"],
16
+ tsConfig: "tsconfig.json"
17
+ },
18
+ webOptions,
19
+ jestConfig,
20
+ jasmineConfig
21
+ );
22
+
23
+ // Switch off unbound method rules in tests
24
+ config.rules["@typescript-eslint/unbound-method"] = "off";
25
+
26
+ export default config;
@@ -0,0 +1,26 @@
1
+ import globals from "globals";
2
+ import nodeOptions from "./ts-node.js";
3
+ import jestConfig from "./rules/jest.js";
4
+ import jasmineConfig from "./rules/jasmine.js";
5
+ import { ConfigUtil } from "./utils/config-util.js";
6
+
7
+ const config = ConfigUtil.createTsConfig(
8
+ {
9
+ ecmaVersion: 2021,
10
+ globals: {
11
+ ...globals.node,
12
+ ...globals.jest,
13
+ ...globals.jasmine
14
+ },
15
+ files: ["**/?(*.)+(spec).{js,mjs,cjs,ts,mts,cts}?(x)"],
16
+ tsConfig: "tsconfig.json"
17
+ },
18
+ nodeOptions,
19
+ jestConfig,
20
+ jasmineConfig
21
+ );
22
+
23
+ // Switch off unbound method rules in tests
24
+ config.rules["@typescript-eslint/unbound-method"] = "off";
25
+
26
+ export default config;
package/ts-node.js ADDED
@@ -0,0 +1,24 @@
1
+ import globals from "globals";
2
+ import { ConfigUtil } from "./utils/config-util.js";
3
+
4
+ import commentsConfig from "./rules/eslint-comments.js";
5
+ import importTsNodeConfig from "./rules/import-typescript-node.js";
6
+ import jsdocTsConfig from "./rules/jsdoc-typescript.js";
7
+ import prettierConfig from "./rules/prettier.js";
8
+ import tsEslintConfig from "./rules/typescript-eslint.js";
9
+ import unicornConfig from "./rules/unicorn.js";
10
+
11
+ export default ConfigUtil.createTsConfig(
12
+ {
13
+ ecmaVersion: 2021,
14
+ globals: globals.node,
15
+ files: ["**/*.{js,mjs,cjs,ts,mts,mjs}"],
16
+ tsConfig: "tsconfig.json"
17
+ },
18
+ commentsConfig,
19
+ importTsNodeConfig,
20
+ jsdocTsConfig,
21
+ prettierConfig,
22
+ tsEslintConfig,
23
+ unicornConfig
24
+ );
@@ -0,0 +1,132 @@
1
+ import tsParser from "@typescript-eslint/parser";
2
+
3
+ /** @typedef {import("eslint").Linter.Config} Config */
4
+ /** @typedef {import("eslint").ESLint.Plugin} Plugin */
5
+ /** @typedef {import("eslint").Linter.RulesRecord RulesRecord} */
6
+ /** @typedef {import("eslint").Linter.LanguageOptions} LanguageOptions */
7
+ /** @typedef {Pick<import("eslint").Linter.Config, "settings" | "plugins" | "rules">} SettingsPluginsAndRules */
8
+ /** @typedef {{globals: readonly Record<string, boolean>; ecmaVersion: number; files?: string[]; tsConfig?: string }} CreateTsConfigOptions */
9
+ /** @typedef {{plugin: Plugin; namepace: string; rules: RulesRecord; templateNames?: string[]; settings?: Record<string, any> }} GetPluginConfigOptins */
10
+ export class ConfigUtil {
11
+ /**
12
+ * Creates ESLint configuration language options for TypeScript.
13
+ *
14
+ * @param {readonly Record<string, boolean>} globals
15
+ * @param {number} ecmaVersion
16
+ * @param {string} [tsConfig="tsconfig.json"]
17
+ * @return {LanguageOptions}
18
+ */
19
+ static createTsLangOptions(
20
+ globals,
21
+ ecmaVersion,
22
+ tsConfig = "tsconfig.json"
23
+ ) {
24
+ return {
25
+ ecmaVersion: ecmaVersion,
26
+ globals: { ...globals },
27
+ parser: tsParser,
28
+ parserOptions: {
29
+ ecmaVersion: ecmaVersion,
30
+ project: tsConfig,
31
+ sourceType: "module"
32
+ }
33
+ };
34
+ }
35
+
36
+ /**
37
+ * Merges settings, plugins, and rules from multiple ESLint configs.
38
+ *
39
+ * @param {...SettingsPluginsAndRules>} configs
40
+ * @returns {SettingsPluginsAndRules}
41
+ */
42
+ static mergeSettingsPluginsAndRules(...configs) {
43
+ return configs.reduce((acc, config) => {
44
+ return {
45
+ settings: {
46
+ ...(acc.settings ?? {}),
47
+ ...(config.settings ?? {})
48
+ },
49
+ plugins: {
50
+ ...(acc.plugins ?? {}),
51
+ ...(config.plugins ?? {})
52
+ },
53
+ rules: {
54
+ ...(acc.rules ?? {}),
55
+ ...(config.rules ?? {})
56
+ }
57
+ };
58
+ }, {});
59
+ }
60
+
61
+ /**
62
+ * Creates ESLint configuration for TypeScript.
63
+ *
64
+ * @param {CreateTsConfigOptions} options
65
+ * @param {...SettingsPluginsAndRules>} configs
66
+ * @return {Config}
67
+ */
68
+ static createTsConfig(options, ...configs) {
69
+ return {
70
+ files: options.files ?? ["**/*.{js,mjs,cjs,ts,mts,mjs}"],
71
+ languageOptions: ConfigUtil.createTsLangOptions(
72
+ options.globals,
73
+ options.ecmaVersion,
74
+ options.tsConfig ?? "tsconfig.json"
75
+ ),
76
+ ...ConfigUtil.mergeSettingsPluginsAndRules(...configs)
77
+ };
78
+ }
79
+
80
+ /**
81
+ *
82
+ * @param {GetPluginConfigOptins} options
83
+ * @returns {SettingsPluginsAndRules}
84
+ */
85
+ static getPluginConfig(options) {
86
+ const result = {
87
+ plugins: {},
88
+ rules: {},
89
+ settings: {}
90
+ };
91
+
92
+ const { plugin, namespace, templateNames, rules, settings } = options;
93
+
94
+ result.plugins[namespace] = plugin;
95
+
96
+ if ((templateNames ?? []).length) {
97
+ for (const templateName of templateNames) {
98
+ const templateConfig =
99
+ "flatConfigs" in plugin
100
+ ? plugin.flatConfigs[templateName]
101
+ : plugin.configs[templateName];
102
+ if (!templateConfig) {
103
+ throw new Error(
104
+ `Could not find template config for "${templateName}"`
105
+ );
106
+ }
107
+ result.rules = {
108
+ ...(templateConfig.rules ?? {}),
109
+ ...result.rules
110
+ };
111
+ if (templateConfig.settings) {
112
+ result.settings = {
113
+ ...templateConfig.settings,
114
+ ...result.settings
115
+ };
116
+ }
117
+ }
118
+ }
119
+
120
+ result.rules = {
121
+ ...result.rules,
122
+ ...rules
123
+ };
124
+
125
+ result.settings = {
126
+ ...result.settings,
127
+ ...settings
128
+ };
129
+
130
+ return result;
131
+ }
132
+ }
package/utils/merge.js CHANGED
@@ -3,10 +3,12 @@
3
3
  * @param {any} o
4
4
  * @returns o is {}
5
5
  */
6
- function isPlainObject(value) {
7
- return !!value &&
6
+ function isPlainObject(value) {
7
+ return (
8
+ !!value &&
8
9
  !!(value = Object.getPrototypeOf(value)) &&
9
- !Object.getPrototypeOf(value);
10
+ !Object.getPrototypeOf(value)
11
+ );
10
12
  }
11
13
 
12
14
  /**
@@ -16,9 +18,9 @@
16
18
  * @param {boolean} insertBoth
17
19
  * @returns {any[]}
18
20
  */
19
- function deepMergeArrays(first, second, insertBoth = true) {
20
- let result = [];
21
- for (let i = 0; i < Math.max(first.length, second.length); i++) {
21
+ export function deepMergeArrays(first, second, insertBoth = true) {
22
+ let result = [];
23
+ for (let i = 0; i < Math.max(first.length, second.length); i++) {
22
24
  if (i < second.length) {
23
25
  if (i < first.length) {
24
26
  if (Array.isArray(second[i])) {
@@ -46,8 +48,8 @@
46
48
  } else {
47
49
  result.push(first[i]);
48
50
  }
49
- }
50
- return result;
51
+ }
52
+ return result;
51
53
  }
52
54
 
53
55
  /**
@@ -56,7 +58,7 @@
56
58
  * @param {{}} second
57
59
  * @returns {{}}
58
60
  */
59
- function deepMergeObjects(first, second) {
61
+ export function deepMergeObjects(first, second) {
60
62
  const result = {};
61
63
  const remainingKeysFromSecond = new Set(Object.keys(second));
62
64
  for (const key of Object.keys(first)) {
@@ -86,8 +88,3 @@ function deepMergeObjects(first, second) {
86
88
  }
87
89
  return result;
88
90
  }
89
-
90
- module.exports = {
91
- deepMergeObjects,
92
- deepMergeArrays
93
- };
@@ -1,6 +0,0 @@
1
- module.exports = {
2
- plugins: ["deprecation"],
3
- rules: {
4
- "deprecation/deprecation": "error"
5
- }
6
- };
@@ -1,12 +0,0 @@
1
- module.exports = {
2
- plugins: ["no-lookahead-lookbehind-regexp"],
3
- rules: {
4
- "no-lookahead-lookbehind-regexp/no-lookahead-lookbehind-regexp": [
5
- "error",
6
- "no-lookahead",
7
- "no-lookbehind",
8
- "no-negative-lookahead",
9
- "no-negative-lookbehind"
10
- ]
11
- }
12
- };
@@ -1,37 +0,0 @@
1
- module.exports = {
2
- env: {
3
- node: true,
4
- es6: true,
5
- jest: true,
6
- jasmine: true
7
- },
8
- parser: "@typescript-eslint/parser",
9
- parserOptions: {
10
- ecmaVersion: 2021,
11
- project: "tsconfig.json",
12
- sourceType: "module"
13
- },
14
- extends: [
15
- "./rules/deprecation.js",
16
- // "./rules/eslint.js", -> commented out since "typescript-eslint" rules inherit from this
17
- "./rules/eslint-comments.js",
18
- "./rules/import-typescript-node.js",
19
- "./rules/jsdoc-typescript.js",
20
- "./rules/prettier.js",
21
- "./rules/typescript-eslint.js",
22
- "./rules/unicorn.js"
23
- ].map(require.resolve),
24
- rules: {},
25
- overrides: [
26
- // Overrides for test files
27
- {
28
- files: ["**/?(*.)+(spec).[jt]s?(x)"],
29
- extends: ["./rules/jasmine.js", "./rules/jest.js"].map(
30
- require.resolve
31
- ),
32
- rules: {
33
- "@typescript-eslint/unbound-method": "off"
34
- }
35
- }
36
- ]
37
- };
@@ -1,23 +0,0 @@
1
- module.exports = {
2
- env: {
3
- node: true,
4
- es6: true
5
- },
6
- parser: "@typescript-eslint/parser",
7
- parserOptions: {
8
- ecmaVersion: 2021,
9
- project: "tsconfig.json",
10
- sourceType: "module"
11
- },
12
- extends: [
13
- "./rules/deprecation.js",
14
- // "./rules/eslint.js", -> commented out since "typescript-eslint" rules inherit from this
15
- "./rules/eslint-comments.js",
16
- "./rules/import-typescript-node.js",
17
- "./rules/jsdoc-typescript.js",
18
- "./rules/prettier.js",
19
- "./rules/typescript-eslint.js",
20
- "./rules/unicorn.js"
21
- ].map(require.resolve),
22
- rules: {}
23
- };
@@ -1,38 +0,0 @@
1
- module.exports = {
2
- env: {
3
- browser: true,
4
- es6: true,
5
- jest: true,
6
- jasmine: true
7
- },
8
- parser: "@typescript-eslint/parser",
9
- parserOptions: {
10
- ecmaVersion: 2019,
11
- project: "tsconfig.json",
12
- sourceType: "module"
13
- },
14
- extends: [
15
- "./rules/deprecation.js",
16
- // "./rules/eslint.js", -> commented out since "typescript-eslint" rules inherit from this
17
- "./rules/eslint-comments.js",
18
- "./rules/import-typescript-web.js",
19
- "./rules/jsdoc-typescript.js",
20
- "./rules/no-lookahead-lookbehind-regexp.js",
21
- "./rules/prettier.js",
22
- "./rules/typescript-eslint.js",
23
- "./rules/unicorn.js"
24
- ].map(require.resolve),
25
- rules: {},
26
- overrides: [
27
- // Overrides for test files
28
- {
29
- files: ["**/?(*.)+(spec).[jt]s?(x)"],
30
- extends: ["./rules/jasmine.js", "./rules/jest.js"].map(
31
- require.resolve
32
- ),
33
- rules: {
34
- "@typescript-eslint/unbound-method": "off"
35
- }
36
- }
37
- ]
38
- };
package/typescript-web.js DELETED
@@ -1,24 +0,0 @@
1
- module.exports = {
2
- env: {
3
- browser: true,
4
- es6: true
5
- },
6
- parser: "@typescript-eslint/parser",
7
- parserOptions: {
8
- ecmaVersion: 2019,
9
- project: "tsconfig.json",
10
- sourceType: "module"
11
- },
12
- extends: [
13
- "./rules/deprecation.js",
14
- // "./rules/eslint.js", -> commented out since "typescript-eslint" rules inherit from this
15
- "./rules/eslint-comments.js",
16
- "./rules/import-typescript-web.js",
17
- "./rules/jsdoc-typescript.js",
18
- "./rules/no-lookahead-lookbehind-regexp.js",
19
- "./rules/prettier.js",
20
- "./rules/typescript-eslint.js",
21
- "./rules/unicorn.js"
22
- ].map(require.resolve),
23
- rules: {}
24
- };