exadev-eslint-config 2.12.2 → 2.13.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 +1 -0
- package/dist/index.cjs +89 -4
- package/dist/index.js +89 -4
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -170,6 +170,7 @@ Trailing arguments are arbitrary flat-config objects, appended in order after ev
|
|
|
170
170
|
| `no-non-barrel-reexport` | ✓ | Re-exports belong only in a barrel. Catches the split form across two statements (`import { x } from './y'; export { x };` or `export default x;`) which no AST selector alone can match. Autofix deletes the export and the now-pointless import when it was the import's only use. Self-scopes away from any index file. |
|
|
171
171
|
| `no-side-effects-in-index` | | A barrel file may contain only re-export statements -- nothing that could execute at import time. Self-scopes to any index file. |
|
|
172
172
|
| `barrel-direct-siblings-only` | | A barrel may re-export only from a direct sibling (`./module`), never a nested path, parent, or bare package specifier (mode 3). |
|
|
173
|
+
| `no-control-flow` | | Bans `if`/`switch`/`for`/`for-in`/`for-of`/`while`/`do-while`/the ternary operator outright. Not part of `recommended` or `barrel` -- ordinary code legitimately needs control flow, so this is opt-in, wired via a consumer's own `files` glob for the specific packages that want it (a composition-root package selecting an adapter/strategy by a validated key, say): a lookup table replaces a branch, a declarative array method (`map`/`filter`/`some`/`every`/...) replaces a loop. Requires no type information. |
|
|
173
174
|
| `no-pointless-reassignment` | ✓ | `const foo = bar` where both sides are plain identifiers and the alias adds no transformation. Autofix rewrites every read to the original name and deletes the declaration (including its `export` keyword, when exported). Still reported but deliberately not auto-fixable where collapsing the alias would change meaning: an explicit type annotation (`const exhaustive: never = item` -- the annotation is the point), a read where the original name is shadowed, a read as a shorthand object property, more than one declarator in the statement, or a source that is written to anywhere. |
|
|
174
175
|
| `no-object-assign` | ✓/suggestion | `Object.assign` does not check a source object's properties against the target's declared types, unlike object spread. A fresh object-literal target autofixes to `{ ...target, ...source }`; mutating an existing reassignable binding offers a suggestion only (changes the object's identity); a `const` binding or a non-statement call site gets a plain report with no fix. |
|
|
175
176
|
| `no-mutable-union-array-param` | ✓ | A function parameter typed as an array of a union (`(string \| number)[]`) accepts a narrower caller array (`number[]`) by covariance; calling `push`/`unshift`/`splice`/`fill`/`copyWithin` on it can then insert a value the caller's own array was never declared to hold. Autofix marks the parameter `readonly`, turning the mutating call into a real compile error to resolve deliberately. Requires no type information. |
|
package/dist/index.cjs
CHANGED
|
@@ -39,6 +39,7 @@ let typescript = require("typescript");
|
|
|
39
39
|
typescript = __toESM(typescript, 1);
|
|
40
40
|
let ts_api_utils = require("ts-api-utils");
|
|
41
41
|
//#region src/jsdoc.ts
|
|
42
|
+
const JS_TS_FILE_PATTERNS$1 = "**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}";
|
|
42
43
|
const jsdocConfig = eslint_plugin_jsdoc.default.configs["flat/recommended-tsdoc-error"];
|
|
43
44
|
const REQUIREMENTS_TIER_RULES = [
|
|
44
45
|
"jsdoc/require-example",
|
|
@@ -61,12 +62,14 @@ const REQUIREMENTS_TIER_RULES = [
|
|
|
61
62
|
"jsdoc/require-yields-type"
|
|
62
63
|
];
|
|
63
64
|
const jsdocAndTsdoc = [{
|
|
65
|
+
files: [JS_TS_FILE_PATTERNS$1],
|
|
64
66
|
...jsdocConfig,
|
|
65
67
|
rules: {
|
|
66
68
|
...jsdocConfig.rules,
|
|
67
69
|
...Object.fromEntries(REQUIREMENTS_TIER_RULES.map((rule) => [rule, "off"]))
|
|
68
70
|
}
|
|
69
71
|
}, {
|
|
72
|
+
files: [JS_TS_FILE_PATTERNS$1],
|
|
70
73
|
plugins: { tsdoc: eslint_plugin_tsdoc.default },
|
|
71
74
|
rules: { "tsdoc/syntax": "error" }
|
|
72
75
|
}];
|
|
@@ -156,7 +159,7 @@ function buildReactConfig(options = {}) {
|
|
|
156
159
|
}
|
|
157
160
|
//#endregion
|
|
158
161
|
//#region package.json
|
|
159
|
-
var version = "2.
|
|
162
|
+
var version = "2.13.0";
|
|
160
163
|
//#endregion
|
|
161
164
|
//#region src/rules/barrel-helpers.ts
|
|
162
165
|
const INDEX_BASENAME$1 = /^index\.[cm]?[tj]sx?$/;
|
|
@@ -513,6 +516,76 @@ const noArrayIsArrayMutation = createRule$7({
|
|
|
513
516
|
}
|
|
514
517
|
});
|
|
515
518
|
//#endregion
|
|
519
|
+
//#region src/rules/no-control-flow.ts
|
|
520
|
+
const noControlFlow = {
|
|
521
|
+
meta: {
|
|
522
|
+
type: "problem",
|
|
523
|
+
schema: [],
|
|
524
|
+
messages: {
|
|
525
|
+
ifStatement: "Use a lookup table, not an if/else branch.",
|
|
526
|
+
switchStatement: "Use a lookup table, not a switch branch.",
|
|
527
|
+
forStatement: "Use a lookup table or a declarative array method, not a for loop.",
|
|
528
|
+
forInStatement: "Use a lookup table or Object.entries, not a for-in loop.",
|
|
529
|
+
forOfStatement: "Use a declarative array method, not a for-of loop.",
|
|
530
|
+
whileStatement: "Use a lookup table or a declarative array method, not a while loop.",
|
|
531
|
+
doWhileStatement: "Use a lookup table or a declarative array method, not a do-while loop.",
|
|
532
|
+
conditionalExpression: "Use a lookup table, not a ternary."
|
|
533
|
+
}
|
|
534
|
+
},
|
|
535
|
+
create(context) {
|
|
536
|
+
return {
|
|
537
|
+
IfStatement(node) {
|
|
538
|
+
context.report({
|
|
539
|
+
node,
|
|
540
|
+
messageId: "ifStatement"
|
|
541
|
+
});
|
|
542
|
+
},
|
|
543
|
+
SwitchStatement(node) {
|
|
544
|
+
context.report({
|
|
545
|
+
node,
|
|
546
|
+
messageId: "switchStatement"
|
|
547
|
+
});
|
|
548
|
+
},
|
|
549
|
+
ForStatement(node) {
|
|
550
|
+
context.report({
|
|
551
|
+
node,
|
|
552
|
+
messageId: "forStatement"
|
|
553
|
+
});
|
|
554
|
+
},
|
|
555
|
+
ForInStatement(node) {
|
|
556
|
+
context.report({
|
|
557
|
+
node,
|
|
558
|
+
messageId: "forInStatement"
|
|
559
|
+
});
|
|
560
|
+
},
|
|
561
|
+
ForOfStatement(node) {
|
|
562
|
+
context.report({
|
|
563
|
+
node,
|
|
564
|
+
messageId: "forOfStatement"
|
|
565
|
+
});
|
|
566
|
+
},
|
|
567
|
+
WhileStatement(node) {
|
|
568
|
+
context.report({
|
|
569
|
+
node,
|
|
570
|
+
messageId: "whileStatement"
|
|
571
|
+
});
|
|
572
|
+
},
|
|
573
|
+
DoWhileStatement(node) {
|
|
574
|
+
context.report({
|
|
575
|
+
node,
|
|
576
|
+
messageId: "doWhileStatement"
|
|
577
|
+
});
|
|
578
|
+
},
|
|
579
|
+
ConditionalExpression(node) {
|
|
580
|
+
context.report({
|
|
581
|
+
node,
|
|
582
|
+
messageId: "conditionalExpression"
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
//#endregion
|
|
516
589
|
//#region src/rules/no-enum-number-widening.ts
|
|
517
590
|
const noEnumNumberWidening = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/ExaDev/eslint-config/blob/main/src/rules/${name}.ts`)({
|
|
518
591
|
name: "no-enum-number-widening",
|
|
@@ -1353,6 +1426,7 @@ const plugin = {
|
|
|
1353
1426
|
"barrel-direct-siblings-only": barrelDirectSiblingsOnly,
|
|
1354
1427
|
"barrel-policy": barrelPolicy,
|
|
1355
1428
|
"no-array-isarray-mutation": noArrayIsArrayMutation,
|
|
1429
|
+
"no-control-flow": noControlFlow,
|
|
1356
1430
|
"no-enum-number-widening": noEnumNumberWidening,
|
|
1357
1431
|
"no-enum-reverse-lookup-widening": noEnumReverseLookupWidening,
|
|
1358
1432
|
"no-index-files": noIndexFiles,
|
|
@@ -1399,11 +1473,22 @@ const plugin = {
|
|
|
1399
1473
|
//#endregion
|
|
1400
1474
|
//#region src/recommended-type-checked.ts
|
|
1401
1475
|
const TEST_FILE_PATTERNS = "**/*.{test,spec}.{ts,tsx,mts,cts,js,jsx,mjs,cjs}";
|
|
1476
|
+
const JS_TS_FILE_PATTERNS = "**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}";
|
|
1477
|
+
function scopeToJsTs(configs) {
|
|
1478
|
+
return configs.map((config) => config.files ? config : {
|
|
1479
|
+
...config,
|
|
1480
|
+
files: [JS_TS_FILE_PATTERNS]
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1402
1483
|
const recommendedTypeChecked = [
|
|
1403
|
-
_eslint_js.default.configs.recommended,
|
|
1404
|
-
...typescript_eslint.default.configs.strictTypeChecked,
|
|
1405
|
-
...typescript_eslint.default.configs.stylisticTypeChecked,
|
|
1406
1484
|
{
|
|
1485
|
+
..._eslint_js.default.configs.recommended,
|
|
1486
|
+
files: [JS_TS_FILE_PATTERNS]
|
|
1487
|
+
},
|
|
1488
|
+
...scopeToJsTs(typescript_eslint.default.configs.strictTypeChecked),
|
|
1489
|
+
...scopeToJsTs(typescript_eslint.default.configs.stylisticTypeChecked),
|
|
1490
|
+
{
|
|
1491
|
+
files: [JS_TS_FILE_PATTERNS],
|
|
1407
1492
|
plugins: { exadev: plugin },
|
|
1408
1493
|
linterOptions: { noInlineConfig: true },
|
|
1409
1494
|
rules: {
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import { AST_NODE_TYPES, ESLintUtils, TSESLint } from "@typescript-eslint/utils"
|
|
|
8
8
|
import * as ts from "typescript";
|
|
9
9
|
import { isPropertyReadonlyInType, isTypeReference } from "ts-api-utils";
|
|
10
10
|
//#region src/jsdoc.ts
|
|
11
|
+
const JS_TS_FILE_PATTERNS$1 = "**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}";
|
|
11
12
|
const jsdocConfig = jsdoc.configs["flat/recommended-tsdoc-error"];
|
|
12
13
|
const REQUIREMENTS_TIER_RULES = [
|
|
13
14
|
"jsdoc/require-example",
|
|
@@ -30,12 +31,14 @@ const REQUIREMENTS_TIER_RULES = [
|
|
|
30
31
|
"jsdoc/require-yields-type"
|
|
31
32
|
];
|
|
32
33
|
const jsdocAndTsdoc = [{
|
|
34
|
+
files: [JS_TS_FILE_PATTERNS$1],
|
|
33
35
|
...jsdocConfig,
|
|
34
36
|
rules: {
|
|
35
37
|
...jsdocConfig.rules,
|
|
36
38
|
...Object.fromEntries(REQUIREMENTS_TIER_RULES.map((rule) => [rule, "off"]))
|
|
37
39
|
}
|
|
38
40
|
}, {
|
|
41
|
+
files: [JS_TS_FILE_PATTERNS$1],
|
|
39
42
|
plugins: { tsdoc },
|
|
40
43
|
rules: { "tsdoc/syntax": "error" }
|
|
41
44
|
}];
|
|
@@ -125,7 +128,7 @@ function buildReactConfig(options = {}) {
|
|
|
125
128
|
}
|
|
126
129
|
//#endregion
|
|
127
130
|
//#region package.json
|
|
128
|
-
var version = "2.
|
|
131
|
+
var version = "2.13.0";
|
|
129
132
|
//#endregion
|
|
130
133
|
//#region src/rules/barrel-helpers.ts
|
|
131
134
|
const INDEX_BASENAME$1 = /^index\.[cm]?[tj]sx?$/;
|
|
@@ -482,6 +485,76 @@ const noArrayIsArrayMutation = createRule$7({
|
|
|
482
485
|
}
|
|
483
486
|
});
|
|
484
487
|
//#endregion
|
|
488
|
+
//#region src/rules/no-control-flow.ts
|
|
489
|
+
const noControlFlow = {
|
|
490
|
+
meta: {
|
|
491
|
+
type: "problem",
|
|
492
|
+
schema: [],
|
|
493
|
+
messages: {
|
|
494
|
+
ifStatement: "Use a lookup table, not an if/else branch.",
|
|
495
|
+
switchStatement: "Use a lookup table, not a switch branch.",
|
|
496
|
+
forStatement: "Use a lookup table or a declarative array method, not a for loop.",
|
|
497
|
+
forInStatement: "Use a lookup table or Object.entries, not a for-in loop.",
|
|
498
|
+
forOfStatement: "Use a declarative array method, not a for-of loop.",
|
|
499
|
+
whileStatement: "Use a lookup table or a declarative array method, not a while loop.",
|
|
500
|
+
doWhileStatement: "Use a lookup table or a declarative array method, not a do-while loop.",
|
|
501
|
+
conditionalExpression: "Use a lookup table, not a ternary."
|
|
502
|
+
}
|
|
503
|
+
},
|
|
504
|
+
create(context) {
|
|
505
|
+
return {
|
|
506
|
+
IfStatement(node) {
|
|
507
|
+
context.report({
|
|
508
|
+
node,
|
|
509
|
+
messageId: "ifStatement"
|
|
510
|
+
});
|
|
511
|
+
},
|
|
512
|
+
SwitchStatement(node) {
|
|
513
|
+
context.report({
|
|
514
|
+
node,
|
|
515
|
+
messageId: "switchStatement"
|
|
516
|
+
});
|
|
517
|
+
},
|
|
518
|
+
ForStatement(node) {
|
|
519
|
+
context.report({
|
|
520
|
+
node,
|
|
521
|
+
messageId: "forStatement"
|
|
522
|
+
});
|
|
523
|
+
},
|
|
524
|
+
ForInStatement(node) {
|
|
525
|
+
context.report({
|
|
526
|
+
node,
|
|
527
|
+
messageId: "forInStatement"
|
|
528
|
+
});
|
|
529
|
+
},
|
|
530
|
+
ForOfStatement(node) {
|
|
531
|
+
context.report({
|
|
532
|
+
node,
|
|
533
|
+
messageId: "forOfStatement"
|
|
534
|
+
});
|
|
535
|
+
},
|
|
536
|
+
WhileStatement(node) {
|
|
537
|
+
context.report({
|
|
538
|
+
node,
|
|
539
|
+
messageId: "whileStatement"
|
|
540
|
+
});
|
|
541
|
+
},
|
|
542
|
+
DoWhileStatement(node) {
|
|
543
|
+
context.report({
|
|
544
|
+
node,
|
|
545
|
+
messageId: "doWhileStatement"
|
|
546
|
+
});
|
|
547
|
+
},
|
|
548
|
+
ConditionalExpression(node) {
|
|
549
|
+
context.report({
|
|
550
|
+
node,
|
|
551
|
+
messageId: "conditionalExpression"
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
//#endregion
|
|
485
558
|
//#region src/rules/no-enum-number-widening.ts
|
|
486
559
|
const noEnumNumberWidening = ESLintUtils.RuleCreator((name) => `https://github.com/ExaDev/eslint-config/blob/main/src/rules/${name}.ts`)({
|
|
487
560
|
name: "no-enum-number-widening",
|
|
@@ -1322,6 +1395,7 @@ const plugin = {
|
|
|
1322
1395
|
"barrel-direct-siblings-only": barrelDirectSiblingsOnly,
|
|
1323
1396
|
"barrel-policy": barrelPolicy,
|
|
1324
1397
|
"no-array-isarray-mutation": noArrayIsArrayMutation,
|
|
1398
|
+
"no-control-flow": noControlFlow,
|
|
1325
1399
|
"no-enum-number-widening": noEnumNumberWidening,
|
|
1326
1400
|
"no-enum-reverse-lookup-widening": noEnumReverseLookupWidening,
|
|
1327
1401
|
"no-index-files": noIndexFiles,
|
|
@@ -1368,11 +1442,22 @@ const plugin = {
|
|
|
1368
1442
|
//#endregion
|
|
1369
1443
|
//#region src/recommended-type-checked.ts
|
|
1370
1444
|
const TEST_FILE_PATTERNS = "**/*.{test,spec}.{ts,tsx,mts,cts,js,jsx,mjs,cjs}";
|
|
1445
|
+
const JS_TS_FILE_PATTERNS = "**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}";
|
|
1446
|
+
function scopeToJsTs(configs) {
|
|
1447
|
+
return configs.map((config) => config.files ? config : {
|
|
1448
|
+
...config,
|
|
1449
|
+
files: [JS_TS_FILE_PATTERNS]
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1371
1452
|
const recommendedTypeChecked = [
|
|
1372
|
-
js.configs.recommended,
|
|
1373
|
-
...tseslint.configs.strictTypeChecked,
|
|
1374
|
-
...tseslint.configs.stylisticTypeChecked,
|
|
1375
1453
|
{
|
|
1454
|
+
...js.configs.recommended,
|
|
1455
|
+
files: [JS_TS_FILE_PATTERNS]
|
|
1456
|
+
},
|
|
1457
|
+
...scopeToJsTs(tseslint.configs.strictTypeChecked),
|
|
1458
|
+
...scopeToJsTs(tseslint.configs.stylisticTypeChecked),
|
|
1459
|
+
{
|
|
1460
|
+
files: [JS_TS_FILE_PATTERNS],
|
|
1376
1461
|
plugins: { exadev: plugin },
|
|
1377
1462
|
linterOptions: { noInlineConfig: true },
|
|
1378
1463
|
rules: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "exadev-eslint-config",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.13.0",
|
|
4
4
|
"description": "Shared custom ESLint rules and plugin for ExaDev projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"@arethetypeswrong/cli": "^0.18.5",
|
|
64
64
|
"@commitlint/cli": "^21.2.1",
|
|
65
65
|
"@commitlint/config-conventional": "^21.2.0",
|
|
66
|
+
"@eslint/json": "2.1.0",
|
|
66
67
|
"@next/eslint-plugin-next": "^16.3.2",
|
|
67
68
|
"@semantic-release/changelog": "^7.0.0",
|
|
68
69
|
"@semantic-release/git": "^11.0.1",
|
|
@@ -85,7 +86,7 @@
|
|
|
85
86
|
},
|
|
86
87
|
"dependencies": {
|
|
87
88
|
"@eslint/js": "^10.0.1",
|
|
88
|
-
"@typescript-eslint/utils": "
|
|
89
|
+
"@typescript-eslint/utils": "8.67.0",
|
|
89
90
|
"eslint-plugin-jsdoc": "64.3.6",
|
|
90
91
|
"eslint-plugin-tsdoc": "^0.5.2",
|
|
91
92
|
"ts-api-utils": "^2.5.0"
|