exadev-eslint-config 2.6.2 → 2.7.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 CHANGED
@@ -16,7 +16,7 @@ Consumers need `eslint >=10.0.0` and `typescript-eslint >=8.0.0` as required pee
16
16
  pnpm add -D @exadev/eslint-config typescript-eslint eslint
17
17
  ```
18
18
 
19
- The default export is the full, type-checked ruleset: typescript-eslint's `recommendedTypeChecked` + `stylisticTypeChecked` presets, `exadev/barrel-policy` at `mode: 'banned'` (see [Barrel policy](#barrel-policy)), `exadev/no-object-assign`, `exadev/no-mutable-union-array-param`, `exadev/no-array-isarray-mutation`, `exadev/no-enum-number-widening`, `exadev/no-enum-reverse-lookup-widening`, `exadev/no-map-instanceof-mutation`, `exadev/no-set-instanceof-mutation`, `exadev/prefer-readonly-array-param`, `exadev/prefer-readonly-object-param`, `exadev/prefer-numeric-sort-compare`, `exadev/no-pointless-reassignment`, `linterOptions.noInlineConfig`, `@typescript-eslint/consistent-type-assertions` banning all type assertions, `@typescript-eslint/consistent-type-imports`, `@typescript-eslint/consistent-type-exports`, `@typescript-eslint/no-non-null-assertion` banning the `!` operator (the same manual-override escape hatch as a type assertion, under a different spelling), `@typescript-eslint/ban-ts-comment` banning `@ts-expect-error` outright, `@typescript-eslint/method-signature-style` set to `'property'` (method-shorthand signatures are checked bivariantly under `strictFunctionTypes`, which is unsound), `@typescript-eslint/no-deprecated`, `@typescript-eslint/no-misused-spread`, `@typescript-eslint/no-mixed-enums`, `@typescript-eslint/no-unnecessary-condition`, `@typescript-eslint/prefer-readonly`, `@typescript-eslint/promise-function-async`, `@typescript-eslint/require-array-sort-compare`, `@typescript-eslint/switch-exhaustiveness-check`, `@typescript-eslint/use-unknown-in-catch-callback-variable`, `@typescript-eslint/strict-boolean-expressions` at the rule's own bare defaults (an unambiguous non-nullable truthy check stays allowed; an ambiguous nullable check does not), and `@typescript-eslint/no-magic-numbers` tuned to exempt array indexes, enum members, readonly class properties, default parameter values, and the handful of universally-idiomatic bare numbers (`-1`, `0`, `1`, `2`) -- the type-assertion and ts-comment rules are relaxed in test files, and `no-magic-numbers` is not (see below). Spread it directly into `tseslint.config(...)`:
19
+ The default export is the full, type-checked ruleset: typescript-eslint's `strictTypeChecked` + `stylisticTypeChecked` presets (`strictTypeChecked` subsumes `recommendedTypeChecked`, so it already includes `no-deprecated`, `no-misused-spread`, `no-mixed-enums`, `no-unnecessary-condition`, `use-unknown-in-catch-callback-variable`, `return-await`, `related-getter-setter-pairs`, `no-unnecessary-type-parameters`, and more -- those are no longer re-listed below), `exadev/barrel-policy` at `mode: 'banned'` (see [Barrel policy](#barrel-policy)), `exadev/no-object-assign`, `exadev/no-mutable-union-array-param`, `exadev/no-array-isarray-mutation`, `exadev/no-enum-number-widening`, `exadev/no-enum-reverse-lookup-widening`, `exadev/no-map-instanceof-mutation`, `exadev/no-set-instanceof-mutation`, `exadev/prefer-readonly-array-param`, `exadev/prefer-readonly-object-param`, `exadev/prefer-numeric-sort-compare`, `exadev/no-pointless-reassignment`, `linterOptions.noInlineConfig`, `@typescript-eslint/consistent-type-assertions` banning all type assertions, `@typescript-eslint/consistent-type-imports`, `@typescript-eslint/consistent-type-exports`, `@typescript-eslint/no-non-null-assertion` banning the `!` operator (the same manual-override escape hatch as a type assertion, under a different spelling), `@typescript-eslint/ban-ts-comment` banning `@ts-expect-error` outright, `@typescript-eslint/method-signature-style` set to `'property'` (method-shorthand signatures are checked bivariantly under `strictFunctionTypes`, which is unsound), `@typescript-eslint/prefer-readonly`, `@typescript-eslint/promise-function-async`, `@typescript-eslint/require-array-sort-compare`, `@typescript-eslint/switch-exhaustiveness-check`, `@typescript-eslint/strict-boolean-expressions` at the rule's own bare defaults (an unambiguous non-nullable truthy check stays allowed; an ambiguous nullable check does not), and `@typescript-eslint/no-magic-numbers` tuned to exempt array indexes, enum members, readonly class properties, default parameter values, and the handful of universally-idiomatic bare numbers (`-1`, `0`, `1`, `2`) -- the type-assertion and ts-comment rules are relaxed in test files, and `no-magic-numbers` is not (see below). Spread it directly into `tseslint.config(...)`:
20
20
 
21
21
  ```ts
22
22
  // eslint.config.ts
@@ -41,7 +41,7 @@ export default tseslint.config(
41
41
  { rules: { 'exadev/barrel-policy': ['error', { mode: 'single' }] } }, // this package keeps its barrel
42
42
  ```
43
43
 
44
- `recommendedTypeChecked` subsumes typescript-eslint's plain `recommended` outright (every rule in `recommended` is also present in `recommendedTypeChecked`), and its base config registers the `@typescript-eslint` plugin and sets `languageOptions.parser` itself. That is why **you must remove your own `...tseslint.configs.recommended`/`recommendedTypeChecked`/`stylisticTypeChecked` spreads** -- flat config rejects two different plugin object instances registered under the same namespace. You still supply `languageOptions.parserOptions.project`/`projectService` pointing at your own tsconfig(s).
44
+ `strictTypeChecked` subsumes both typescript-eslint's plain `recommended` and `recommendedTypeChecked` outright (every rule in each is also present in `strictTypeChecked`), and its base config registers the `@typescript-eslint` plugin and sets `languageOptions.parser` itself. That is why **you must remove your own `...tseslint.configs.recommended`/`recommendedTypeChecked`/`strictTypeChecked`/`stylisticTypeChecked` spreads** -- flat config rejects two different plugin object instances registered under the same namespace. You still supply `languageOptions.parserOptions.project`/`projectService` pointing at your own tsconfig(s).
45
45
 
46
46
  **Test files (`**/*.{test,spec}.{ts,tsx,mts,cts,js,jsx,mjs,cjs}`) get two narrow relaxations of this package's own additions, and only those two.** `@ts-expect-error` reverts to `allow-with-description` (a compile-time-only assertion of a type failure is a legitimate test pattern; `@ts-ignore`/`@ts-nocheck` stay banned since `@ts-expect-error` is strictly better). `consistent-type-assertions` relaxes to `assertionStyle: 'as'` (the legacy `<Type>value` form stays banned everywhere). Nothing inherited from the presets is relaxed.
47
47
 
@@ -157,7 +157,7 @@ The `lint`/`typecheck`/`test`/`build` npm scripts wrap turbo tasks named `_lint`
157
157
 
158
158
  `src/plugin.ts` builds an `ESLint.Plugin` (ESLint's own type) combining `src/rules/` into a flat `rules` map. `configs.recommended` and `configs.barrel` are getters in the object literal -- each references the fully-built `plugin` (`plugins: { exadev: plugin }`), which a plain property initializer can't do mid-construction. `recommended` ships `barrel-policy` at `mode: 'banned'`; `barrel` at `mode: 'single'`.
159
159
 
160
- `src/recommended-type-checked.ts` bundles typescript-eslint's `recommendedTypeChecked` + `stylisticTypeChecked` alongside this plugin's rules into a flat config array. Its value is typed as `ConfigArrayValue = Extract<ConfigValue, unknown[]>` (the array-only member of ESLint's own config-value union), because annotating with the wider union broke `...exadev` with `TS2488`.
160
+ `src/recommended-type-checked.ts` bundles typescript-eslint's `strictTypeChecked` + `stylisticTypeChecked` alongside this plugin's rules into a flat config array. Its value is typed as `ConfigArrayValue = Extract<ConfigValue, unknown[]>` (the array-only member of ESLint's own config-value union), because annotating with the wider union broke `...exadev` with `TS2488`.
161
161
 
162
162
  `src/index.ts` is the entry point: `export { default } from './recommended-type-checked'; export { default as plugin } from './plugin';`. Both exports share one root module, so importing `{ plugin }` alone still resolves `typescript-eslint` via the sibling re-export -- an accepted trade-off (an earlier separate-subpath split proved more awkward in practice).
163
163
 
package/dist/index.cjs CHANGED
@@ -32,7 +32,7 @@ let typescript = require("typescript");
32
32
  typescript = __toESM(typescript, 1);
33
33
  let ts_api_utils = require("ts-api-utils");
34
34
  //#region package.json
35
- var version = "2.6.2";
35
+ var version = "2.7.0";
36
36
  //#endregion
37
37
  //#region src/rules/barrel-helpers.ts
38
38
  const INDEX_BASENAME$1 = /^index\.[cm]?[tj]sx?$/;
@@ -220,7 +220,9 @@ const barrelPolicy = {
220
220
  });
221
221
  }
222
222
  },
223
- ImportDeclaration: (node) => detector.visitImport(node),
223
+ ImportDeclaration: (node) => {
224
+ detector.visitImport(node);
225
+ },
224
226
  ExportNamedDeclaration(node) {
225
227
  detector.visitExportNamed(node);
226
228
  if (hasSource(node)) {
@@ -248,7 +250,9 @@ const barrelPolicy = {
248
250
  data: { source }
249
251
  });
250
252
  },
251
- ExportDefaultDeclaration: (node) => detector.visitExportDefault(node),
253
+ ExportDefaultDeclaration: (node) => {
254
+ detector.visitExportDefault(node);
255
+ },
252
256
  "Program:exit"() {
253
257
  for (const violation of detector.violations()) if (isPermittedBarrel(filename, mode)) {
254
258
  if (mode === "siblings") {
@@ -702,9 +706,15 @@ const noNonBarrelReexport = {
702
706
  if (isIndexFile(context.filename)) return {};
703
707
  const detector = createSplitReexportDetector();
704
708
  return {
705
- ImportDeclaration: (node) => detector.visitImport(node),
706
- ExportNamedDeclaration: (node) => detector.visitExportNamed(node),
707
- ExportDefaultDeclaration: (node) => detector.visitExportDefault(node),
709
+ ImportDeclaration: (node) => {
710
+ detector.visitImport(node);
711
+ },
712
+ ExportNamedDeclaration: (node) => {
713
+ detector.visitExportNamed(node);
714
+ },
715
+ ExportDefaultDeclaration: (node) => {
716
+ detector.visitExportDefault(node);
717
+ },
708
718
  "Program:exit"() {
709
719
  const { sourceCode } = context;
710
720
  for (const violation of detector.violations()) if (violation.kind === "named") {
@@ -1245,7 +1255,7 @@ const plugin = {
1245
1255
  //#region src/recommended-type-checked.ts
1246
1256
  const TEST_FILE_PATTERNS = "**/*.{test,spec}.{ts,tsx,mts,cts,js,jsx,mjs,cjs}";
1247
1257
  const recommendedTypeChecked = [
1248
- ...typescript_eslint.default.configs.recommendedTypeChecked,
1258
+ ...typescript_eslint.default.configs.strictTypeChecked,
1249
1259
  ...typescript_eslint.default.configs.stylisticTypeChecked,
1250
1260
  {
1251
1261
  plugins: { exadev: plugin },
@@ -1268,7 +1278,6 @@ const recommendedTypeChecked = [
1268
1278
  "@typescript-eslint/consistent-type-exports": "error",
1269
1279
  "@typescript-eslint/consistent-type-imports": "error",
1270
1280
  "@typescript-eslint/method-signature-style": ["error", "property"],
1271
- "@typescript-eslint/no-deprecated": "error",
1272
1281
  "@typescript-eslint/no-magic-numbers": ["error", {
1273
1282
  ignore: [
1274
1283
  -1,
@@ -1281,16 +1290,12 @@ const recommendedTypeChecked = [
1281
1290
  ignoreReadonlyClassProperties: true,
1282
1291
  ignoreDefaultValues: true
1283
1292
  }],
1284
- "@typescript-eslint/no-misused-spread": "error",
1285
- "@typescript-eslint/no-mixed-enums": "error",
1286
1293
  "@typescript-eslint/no-non-null-assertion": "error",
1287
- "@typescript-eslint/no-unnecessary-condition": "error",
1288
1294
  "@typescript-eslint/prefer-readonly": "error",
1289
1295
  "@typescript-eslint/promise-function-async": "error",
1290
1296
  "@typescript-eslint/require-array-sort-compare": "error",
1291
1297
  "@typescript-eslint/strict-boolean-expressions": "error",
1292
- "@typescript-eslint/switch-exhaustiveness-check": "error",
1293
- "@typescript-eslint/use-unknown-in-catch-callback-variable": "error"
1298
+ "@typescript-eslint/switch-exhaustiveness-check": "error"
1294
1299
  }
1295
1300
  },
1296
1301
  {
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { AST_NODE_TYPES, ESLintUtils, TSESLint } from "@typescript-eslint/utils"
4
4
  import * as ts from "typescript";
5
5
  import { isPropertyReadonlyInType, isTypeReference } from "ts-api-utils";
6
6
  //#region package.json
7
- var version = "2.6.2";
7
+ var version = "2.7.0";
8
8
  //#endregion
9
9
  //#region src/rules/barrel-helpers.ts
10
10
  const INDEX_BASENAME$1 = /^index\.[cm]?[tj]sx?$/;
@@ -192,7 +192,9 @@ const barrelPolicy = {
192
192
  });
193
193
  }
194
194
  },
195
- ImportDeclaration: (node) => detector.visitImport(node),
195
+ ImportDeclaration: (node) => {
196
+ detector.visitImport(node);
197
+ },
196
198
  ExportNamedDeclaration(node) {
197
199
  detector.visitExportNamed(node);
198
200
  if (hasSource(node)) {
@@ -220,7 +222,9 @@ const barrelPolicy = {
220
222
  data: { source }
221
223
  });
222
224
  },
223
- ExportDefaultDeclaration: (node) => detector.visitExportDefault(node),
225
+ ExportDefaultDeclaration: (node) => {
226
+ detector.visitExportDefault(node);
227
+ },
224
228
  "Program:exit"() {
225
229
  for (const violation of detector.violations()) if (isPermittedBarrel(filename, mode)) {
226
230
  if (mode === "siblings") {
@@ -674,9 +678,15 @@ const noNonBarrelReexport = {
674
678
  if (isIndexFile(context.filename)) return {};
675
679
  const detector = createSplitReexportDetector();
676
680
  return {
677
- ImportDeclaration: (node) => detector.visitImport(node),
678
- ExportNamedDeclaration: (node) => detector.visitExportNamed(node),
679
- ExportDefaultDeclaration: (node) => detector.visitExportDefault(node),
681
+ ImportDeclaration: (node) => {
682
+ detector.visitImport(node);
683
+ },
684
+ ExportNamedDeclaration: (node) => {
685
+ detector.visitExportNamed(node);
686
+ },
687
+ ExportDefaultDeclaration: (node) => {
688
+ detector.visitExportDefault(node);
689
+ },
680
690
  "Program:exit"() {
681
691
  const { sourceCode } = context;
682
692
  for (const violation of detector.violations()) if (violation.kind === "named") {
@@ -1217,7 +1227,7 @@ const plugin = {
1217
1227
  //#region src/recommended-type-checked.ts
1218
1228
  const TEST_FILE_PATTERNS = "**/*.{test,spec}.{ts,tsx,mts,cts,js,jsx,mjs,cjs}";
1219
1229
  const recommendedTypeChecked = [
1220
- ...tseslint.configs.recommendedTypeChecked,
1230
+ ...tseslint.configs.strictTypeChecked,
1221
1231
  ...tseslint.configs.stylisticTypeChecked,
1222
1232
  {
1223
1233
  plugins: { exadev: plugin },
@@ -1240,7 +1250,6 @@ const recommendedTypeChecked = [
1240
1250
  "@typescript-eslint/consistent-type-exports": "error",
1241
1251
  "@typescript-eslint/consistent-type-imports": "error",
1242
1252
  "@typescript-eslint/method-signature-style": ["error", "property"],
1243
- "@typescript-eslint/no-deprecated": "error",
1244
1253
  "@typescript-eslint/no-magic-numbers": ["error", {
1245
1254
  ignore: [
1246
1255
  -1,
@@ -1253,16 +1262,12 @@ const recommendedTypeChecked = [
1253
1262
  ignoreReadonlyClassProperties: true,
1254
1263
  ignoreDefaultValues: true
1255
1264
  }],
1256
- "@typescript-eslint/no-misused-spread": "error",
1257
- "@typescript-eslint/no-mixed-enums": "error",
1258
1265
  "@typescript-eslint/no-non-null-assertion": "error",
1259
- "@typescript-eslint/no-unnecessary-condition": "error",
1260
1266
  "@typescript-eslint/prefer-readonly": "error",
1261
1267
  "@typescript-eslint/promise-function-async": "error",
1262
1268
  "@typescript-eslint/require-array-sort-compare": "error",
1263
1269
  "@typescript-eslint/strict-boolean-expressions": "error",
1264
- "@typescript-eslint/switch-exhaustiveness-check": "error",
1265
- "@typescript-eslint/use-unknown-in-catch-callback-variable": "error"
1270
+ "@typescript-eslint/switch-exhaustiveness-check": "error"
1266
1271
  }
1267
1272
  },
1268
1273
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "exadev-eslint-config",
3
- "version": "2.6.2",
3
+ "version": "2.7.0",
4
4
  "description": "Shared custom ESLint rules and plugin for ExaDev projects",
5
5
  "type": "module",
6
6
  "sideEffects": false,