eslint-config-decent 1.4.0 → 1.5.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/dist/index.cjs CHANGED
@@ -1,11 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  const eslint = require('@eslint/js');
4
+ const prettier = require('eslint-plugin-prettier/recommended');
4
5
  const globals = require('globals');
5
6
  const tsEslint = require('typescript-eslint');
6
- const prettier = require('eslint-plugin-prettier/recommended');
7
7
  const fs = require('fs');
8
8
  const path = require('path');
9
+ const utils = require('@typescript-eslint/utils');
10
+ const importPlugin = require('eslint-plugin-import-x');
9
11
  const jsdoc = require('eslint-plugin-jsdoc');
10
12
  const mocha = require('eslint-plugin-mocha');
11
13
  const promise = require('eslint-plugin-promise');
@@ -19,9 +21,10 @@ const unicorn = require('eslint-plugin-unicorn');
19
21
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
20
22
 
21
23
  const eslint__default = /*#__PURE__*/_interopDefaultCompat(eslint);
24
+ const prettier__default = /*#__PURE__*/_interopDefaultCompat(prettier);
22
25
  const globals__default = /*#__PURE__*/_interopDefaultCompat(globals);
23
26
  const tsEslint__default = /*#__PURE__*/_interopDefaultCompat(tsEslint);
24
- const prettier__default = /*#__PURE__*/_interopDefaultCompat(prettier);
27
+ const importPlugin__default = /*#__PURE__*/_interopDefaultCompat(importPlugin);
25
28
  const jsdoc__default = /*#__PURE__*/_interopDefaultCompat(jsdoc);
26
29
  const mocha__default = /*#__PURE__*/_interopDefaultCompat(mocha);
27
30
  const promise__default = /*#__PURE__*/_interopDefaultCompat(promise);
@@ -32,7 +35,7 @@ const testingLibrary__default = /*#__PURE__*/_interopDefaultCompat(testingLibrar
32
35
  const security__default = /*#__PURE__*/_interopDefaultCompat(security);
33
36
  const unicorn__default = /*#__PURE__*/_interopDefaultCompat(unicorn);
34
37
 
35
- const base$8 = {
38
+ const base$9 = {
36
39
  rules: {
37
40
  "array-callback-return": ["error", { allowImplicit: true }],
38
41
  "block-scoped-var": "error",
@@ -229,6 +232,14 @@ const base$8 = {
229
232
  }
230
233
  ],
231
234
  "prefer-template": "error",
235
+ "sort-imports": [
236
+ "error",
237
+ {
238
+ ignoreCase: true,
239
+ ignoreDeclarationSort: true,
240
+ allowSeparatedGroups: true
241
+ }
242
+ ],
232
243
  "symbol-description": "error",
233
244
  "unicode-bom": ["error", "never"],
234
245
  "vars-on-top": "error",
@@ -274,34 +285,37 @@ const cjs = {
274
285
  strict: ["error", "global"]
275
286
  }
276
287
  };
277
- const configs$8 = {
278
- base: base$8,
288
+ const configs$9 = {
289
+ base: base$9,
279
290
  cjsAndEsm,
280
291
  cjs
281
292
  };
282
293
 
283
- const requireExtensionRule = {
294
+ const requireExtensionRule = utils.ESLintUtils.RuleCreator(() => "https://github.com/jgeurts/eslint-config-decent/tree/main/src/rules/requireExtensionRule.ts")({
295
+ name: "require-extension",
284
296
  meta: {
285
297
  type: "suggestion",
286
298
  docs: {
287
- description: "Ensure import and export statements include a file extension",
288
- category: "Best Practices",
289
- recommended: true
299
+ description: "Ensure import and export statements include a file extension"
290
300
  },
291
301
  fixable: "code",
292
- schema: []
302
+ schema: [],
303
+ messages: {
304
+ requireExtension: "Relative imports and exports must include a file extension."
305
+ }
293
306
  },
307
+ defaultOptions: [],
294
308
  create(context) {
295
309
  function checkSource(source) {
296
310
  const importPath = source.value;
297
311
  if (!importPath || !importPath.startsWith(".") || importPath.endsWith(".js")) {
298
312
  return;
299
313
  }
300
- const resolvedPath = path.resolve(path.dirname(context.filename), importPath);
314
+ const resolvedPath = path.resolve(path.dirname(context.getFilename()), importPath);
301
315
  if (!fs.existsSync(resolvedPath)) {
302
316
  context.report({
303
317
  node: source,
304
- message: "Relative imports and exports must include a file extension.",
318
+ messageId: "requireExtension",
305
319
  fix(fixer) {
306
320
  const fixedPath = `${importPath}.js`;
307
321
  return fixer.replaceText(source, `'${fixedPath}'`);
@@ -323,19 +337,22 @@ const requireExtensionRule = {
323
337
  }
324
338
  };
325
339
  }
326
- };
340
+ });
327
341
 
328
- const requireIndexRule = {
342
+ const requireIndexRule = utils.ESLintUtils.RuleCreator(() => "https://github.com/jgeurts/eslint-config-decent/tree/main/src/rules/requireIndexRule.ts")({
343
+ name: "require-index",
329
344
  meta: {
330
345
  type: "suggestion",
331
346
  docs: {
332
- description: "Ensure directory import and export statements use index.js",
333
- category: "Best Practices",
334
- recommended: true
347
+ description: "Ensure directory import and export statements use index.js"
335
348
  },
336
349
  fixable: "code",
337
- schema: []
350
+ schema: [],
351
+ messages: {
352
+ requireExtension: "Directory imports and exports must use index.js."
353
+ }
338
354
  },
355
+ defaultOptions: [],
339
356
  create(context) {
340
357
  function checkSource(source) {
341
358
  const importPath = source.value;
@@ -344,7 +361,7 @@ const requireIndexRule = {
344
361
  if (isDirectory) {
345
362
  context.report({
346
363
  node: source,
347
- message: "Directory imports and exports must use index.js.",
364
+ messageId: "requireExtension",
348
365
  fix(fixer) {
349
366
  const fixedPath = importPath.replace(/\/?$/, "/index.js");
350
367
  return fixer.replaceText(source, `'${fixedPath}'`);
@@ -366,9 +383,9 @@ const requireIndexRule = {
366
383
  }
367
384
  };
368
385
  }
369
- };
386
+ });
370
387
 
371
- const base$7 = {
388
+ const base$8 = {
372
389
  plugins: {
373
390
  "decent-extension": {
374
391
  meta: {
@@ -386,6 +403,25 @@ const base$7 = {
386
403
  "decent-extension/require-index": "error"
387
404
  }
388
405
  };
406
+ const configs$8 = {
407
+ base: base$8
408
+ };
409
+
410
+ const base$7 = {
411
+ plugins: {
412
+ import: importPlugin__default
413
+ },
414
+ rules: {
415
+ "import/order": [
416
+ "error",
417
+ {
418
+ "newlines-between": "always",
419
+ alphabetize: { order: "asc", caseInsensitive: true },
420
+ pathGroupsExcludedImportTypes: ["builtin"]
421
+ }
422
+ ]
423
+ }
424
+ };
389
425
  const configs$7 = {
390
426
  base: base$7
391
427
  };
@@ -403,6 +439,7 @@ const base$6 = {
403
439
  }
404
440
  },
405
441
  plugins: {
442
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
406
443
  jsdoc: jsdoc__default
407
444
  },
408
445
  rules: {
@@ -680,6 +717,7 @@ function defaultConfig(options) {
680
717
  name: "eslint-config-decent/base",
681
718
  files: ["**/*.ts", "**/*.js", "**/*.cjs", "**/*.mjs", "**/*.tsx"],
682
719
  plugins: {
720
+ ...configs$8.base.plugins,
683
721
  ...configs$7.base.plugins,
684
722
  ...configs$6.base.plugins,
685
723
  ...configs$4.base.plugins,
@@ -687,8 +725,9 @@ function defaultConfig(options) {
687
725
  ...configs.base.plugins
688
726
  },
689
727
  rules: {
690
- ...configs$8.base.rules,
691
- ...enableRequireExtensionRule ? configs$7.base.rules : {},
728
+ ...configs$9.base.rules,
729
+ ...enableRequireExtensionRule ? configs$8.base.rules : {},
730
+ ...configs$7.base.rules,
692
731
  ...configs$6.base.rules,
693
732
  ...configs$4.base.rules,
694
733
  ...configs$2.base.rules,
@@ -711,7 +750,7 @@ function defaultConfig(options) {
711
750
  languageOptions: {
712
751
  sourceType: "script"
713
752
  },
714
- ...configs$8.cjsAndEsm
753
+ ...configs$9.cjsAndEsm
715
754
  },
716
755
  {
717
756
  name: "eslint-config-decent/cjs",
@@ -719,7 +758,7 @@ function defaultConfig(options) {
719
758
  languageOptions: {
720
759
  sourceType: "script"
721
760
  },
722
- ...configs$8.cjs
761
+ ...configs$9.cjs
723
762
  },
724
763
  {
725
764
  name: "eslint-config-decent/tests",
@@ -731,7 +770,8 @@ function defaultConfig(options) {
731
770
  }
732
771
 
733
772
  exports.defaultConfig = defaultConfig;
734
- exports.eslintConfigs = configs$8;
773
+ exports.eslintConfigs = configs$9;
774
+ exports.importConfigs = configs$7;
735
775
  exports.jsdocConfigs = configs$6;
736
776
  exports.promiseConfigs = configs$4;
737
777
  exports.reactConfigs = configs$3;
package/dist/index.d.cts CHANGED
@@ -1,33 +1,38 @@
1
1
  import { ConfigWithExtends } from 'typescript-eslint';
2
+ import { TSESLint } from '@typescript-eslint/utils';
3
+
4
+ declare const configs$7: {
5
+ base: TSESLint.FlatConfig.Config;
6
+ cjsAndEsm: TSESLint.FlatConfig.Config;
7
+ cjs: TSESLint.FlatConfig.Config;
8
+ };
2
9
 
3
10
  declare const configs$6: {
4
- base: ConfigWithExtends;
5
- cjsAndEsm: ConfigWithExtends;
6
- cjs: ConfigWithExtends;
11
+ base: TSESLint.FlatConfig.Config;
7
12
  };
8
13
 
9
14
  declare const configs$5: {
10
- base: ConfigWithExtends;
15
+ base: TSESLint.FlatConfig.Config;
11
16
  };
12
17
 
13
18
  declare const configs$4: {
14
- base: ConfigWithExtends;
19
+ base: TSESLint.FlatConfig.Config;
15
20
  };
16
21
 
17
22
  declare const configs$3: {
18
- base: ConfigWithExtends;
23
+ base: TSESLint.FlatConfig.Config;
19
24
  };
20
25
 
21
26
  declare const configs$2: {
22
- base: ConfigWithExtends;
27
+ base: TSESLint.FlatConfig.Config;
23
28
  };
24
29
 
25
30
  declare const configs$1: {
26
- base: ConfigWithExtends;
31
+ base: TSESLint.FlatConfig.Config;
27
32
  };
28
33
 
29
34
  declare const configs: {
30
- base: ConfigWithExtends;
35
+ base: TSESLint.FlatConfig.Config;
31
36
  };
32
37
 
33
38
  interface DefaultConfigOptions {
@@ -36,4 +41,4 @@ interface DefaultConfigOptions {
36
41
  }
37
42
  declare function defaultConfig(options?: DefaultConfigOptions): ConfigWithExtends[];
38
43
 
39
- export { type DefaultConfigOptions, defaultConfig, configs$6 as eslintConfigs, configs$5 as jsdocConfigs, configs$4 as promiseConfigs, configs$3 as reactConfigs, configs$2 as securityConfigs, configs$1 as typescriptEslintConfigs, configs as unicornConfigs };
44
+ export { type DefaultConfigOptions, defaultConfig, configs$7 as eslintConfigs, configs$6 as importConfigs, configs$5 as jsdocConfigs, configs$4 as promiseConfigs, configs$3 as reactConfigs, configs$2 as securityConfigs, configs$1 as typescriptEslintConfigs, configs as unicornConfigs };
package/dist/index.d.mts CHANGED
@@ -1,33 +1,38 @@
1
1
  import { ConfigWithExtends } from 'typescript-eslint';
2
+ import { TSESLint } from '@typescript-eslint/utils';
3
+
4
+ declare const configs$7: {
5
+ base: TSESLint.FlatConfig.Config;
6
+ cjsAndEsm: TSESLint.FlatConfig.Config;
7
+ cjs: TSESLint.FlatConfig.Config;
8
+ };
2
9
 
3
10
  declare const configs$6: {
4
- base: ConfigWithExtends;
5
- cjsAndEsm: ConfigWithExtends;
6
- cjs: ConfigWithExtends;
11
+ base: TSESLint.FlatConfig.Config;
7
12
  };
8
13
 
9
14
  declare const configs$5: {
10
- base: ConfigWithExtends;
15
+ base: TSESLint.FlatConfig.Config;
11
16
  };
12
17
 
13
18
  declare const configs$4: {
14
- base: ConfigWithExtends;
19
+ base: TSESLint.FlatConfig.Config;
15
20
  };
16
21
 
17
22
  declare const configs$3: {
18
- base: ConfigWithExtends;
23
+ base: TSESLint.FlatConfig.Config;
19
24
  };
20
25
 
21
26
  declare const configs$2: {
22
- base: ConfigWithExtends;
27
+ base: TSESLint.FlatConfig.Config;
23
28
  };
24
29
 
25
30
  declare const configs$1: {
26
- base: ConfigWithExtends;
31
+ base: TSESLint.FlatConfig.Config;
27
32
  };
28
33
 
29
34
  declare const configs: {
30
- base: ConfigWithExtends;
35
+ base: TSESLint.FlatConfig.Config;
31
36
  };
32
37
 
33
38
  interface DefaultConfigOptions {
@@ -36,4 +41,4 @@ interface DefaultConfigOptions {
36
41
  }
37
42
  declare function defaultConfig(options?: DefaultConfigOptions): ConfigWithExtends[];
38
43
 
39
- export { type DefaultConfigOptions, defaultConfig, configs$6 as eslintConfigs, configs$5 as jsdocConfigs, configs$4 as promiseConfigs, configs$3 as reactConfigs, configs$2 as securityConfigs, configs$1 as typescriptEslintConfigs, configs as unicornConfigs };
44
+ export { type DefaultConfigOptions, defaultConfig, configs$7 as eslintConfigs, configs$6 as importConfigs, configs$5 as jsdocConfigs, configs$4 as promiseConfigs, configs$3 as reactConfigs, configs$2 as securityConfigs, configs$1 as typescriptEslintConfigs, configs as unicornConfigs };
package/dist/index.d.ts CHANGED
@@ -1,33 +1,38 @@
1
1
  import { ConfigWithExtends } from 'typescript-eslint';
2
+ import { TSESLint } from '@typescript-eslint/utils';
3
+
4
+ declare const configs$7: {
5
+ base: TSESLint.FlatConfig.Config;
6
+ cjsAndEsm: TSESLint.FlatConfig.Config;
7
+ cjs: TSESLint.FlatConfig.Config;
8
+ };
2
9
 
3
10
  declare const configs$6: {
4
- base: ConfigWithExtends;
5
- cjsAndEsm: ConfigWithExtends;
6
- cjs: ConfigWithExtends;
11
+ base: TSESLint.FlatConfig.Config;
7
12
  };
8
13
 
9
14
  declare const configs$5: {
10
- base: ConfigWithExtends;
15
+ base: TSESLint.FlatConfig.Config;
11
16
  };
12
17
 
13
18
  declare const configs$4: {
14
- base: ConfigWithExtends;
19
+ base: TSESLint.FlatConfig.Config;
15
20
  };
16
21
 
17
22
  declare const configs$3: {
18
- base: ConfigWithExtends;
23
+ base: TSESLint.FlatConfig.Config;
19
24
  };
20
25
 
21
26
  declare const configs$2: {
22
- base: ConfigWithExtends;
27
+ base: TSESLint.FlatConfig.Config;
23
28
  };
24
29
 
25
30
  declare const configs$1: {
26
- base: ConfigWithExtends;
31
+ base: TSESLint.FlatConfig.Config;
27
32
  };
28
33
 
29
34
  declare const configs: {
30
- base: ConfigWithExtends;
35
+ base: TSESLint.FlatConfig.Config;
31
36
  };
32
37
 
33
38
  interface DefaultConfigOptions {
@@ -36,4 +41,4 @@ interface DefaultConfigOptions {
36
41
  }
37
42
  declare function defaultConfig(options?: DefaultConfigOptions): ConfigWithExtends[];
38
43
 
39
- export { type DefaultConfigOptions, defaultConfig, configs$6 as eslintConfigs, configs$5 as jsdocConfigs, configs$4 as promiseConfigs, configs$3 as reactConfigs, configs$2 as securityConfigs, configs$1 as typescriptEslintConfigs, configs as unicornConfigs };
44
+ export { type DefaultConfigOptions, defaultConfig, configs$7 as eslintConfigs, configs$6 as importConfigs, configs$5 as jsdocConfigs, configs$4 as promiseConfigs, configs$3 as reactConfigs, configs$2 as securityConfigs, configs$1 as typescriptEslintConfigs, configs as unicornConfigs };
package/dist/index.mjs CHANGED
@@ -1,9 +1,11 @@
1
1
  import eslint from '@eslint/js';
2
+ import prettier from 'eslint-plugin-prettier/recommended';
2
3
  import globals from 'globals';
3
4
  import tsEslint from 'typescript-eslint';
4
- import prettier from 'eslint-plugin-prettier/recommended';
5
5
  import { existsSync, lstatSync } from 'fs';
6
6
  import { resolve, dirname } from 'path';
7
+ import { ESLintUtils } from '@typescript-eslint/utils';
8
+ import importPlugin from 'eslint-plugin-import-x';
7
9
  import jsdoc from 'eslint-plugin-jsdoc';
8
10
  import mocha from 'eslint-plugin-mocha';
9
11
  import promise from 'eslint-plugin-promise';
@@ -14,7 +16,7 @@ import testingLibrary from 'eslint-plugin-testing-library';
14
16
  import security from 'eslint-plugin-security';
15
17
  import unicorn from 'eslint-plugin-unicorn';
16
18
 
17
- const base$8 = {
19
+ const base$9 = {
18
20
  rules: {
19
21
  "array-callback-return": ["error", { allowImplicit: true }],
20
22
  "block-scoped-var": "error",
@@ -211,6 +213,14 @@ const base$8 = {
211
213
  }
212
214
  ],
213
215
  "prefer-template": "error",
216
+ "sort-imports": [
217
+ "error",
218
+ {
219
+ ignoreCase: true,
220
+ ignoreDeclarationSort: true,
221
+ allowSeparatedGroups: true
222
+ }
223
+ ],
214
224
  "symbol-description": "error",
215
225
  "unicode-bom": ["error", "never"],
216
226
  "vars-on-top": "error",
@@ -256,34 +266,37 @@ const cjs = {
256
266
  strict: ["error", "global"]
257
267
  }
258
268
  };
259
- const configs$8 = {
260
- base: base$8,
269
+ const configs$9 = {
270
+ base: base$9,
261
271
  cjsAndEsm,
262
272
  cjs
263
273
  };
264
274
 
265
- const requireExtensionRule = {
275
+ const requireExtensionRule = ESLintUtils.RuleCreator(() => "https://github.com/jgeurts/eslint-config-decent/tree/main/src/rules/requireExtensionRule.ts")({
276
+ name: "require-extension",
266
277
  meta: {
267
278
  type: "suggestion",
268
279
  docs: {
269
- description: "Ensure import and export statements include a file extension",
270
- category: "Best Practices",
271
- recommended: true
280
+ description: "Ensure import and export statements include a file extension"
272
281
  },
273
282
  fixable: "code",
274
- schema: []
283
+ schema: [],
284
+ messages: {
285
+ requireExtension: "Relative imports and exports must include a file extension."
286
+ }
275
287
  },
288
+ defaultOptions: [],
276
289
  create(context) {
277
290
  function checkSource(source) {
278
291
  const importPath = source.value;
279
292
  if (!importPath || !importPath.startsWith(".") || importPath.endsWith(".js")) {
280
293
  return;
281
294
  }
282
- const resolvedPath = resolve(dirname(context.filename), importPath);
295
+ const resolvedPath = resolve(dirname(context.getFilename()), importPath);
283
296
  if (!existsSync(resolvedPath)) {
284
297
  context.report({
285
298
  node: source,
286
- message: "Relative imports and exports must include a file extension.",
299
+ messageId: "requireExtension",
287
300
  fix(fixer) {
288
301
  const fixedPath = `${importPath}.js`;
289
302
  return fixer.replaceText(source, `'${fixedPath}'`);
@@ -305,19 +318,22 @@ const requireExtensionRule = {
305
318
  }
306
319
  };
307
320
  }
308
- };
321
+ });
309
322
 
310
- const requireIndexRule = {
323
+ const requireIndexRule = ESLintUtils.RuleCreator(() => "https://github.com/jgeurts/eslint-config-decent/tree/main/src/rules/requireIndexRule.ts")({
324
+ name: "require-index",
311
325
  meta: {
312
326
  type: "suggestion",
313
327
  docs: {
314
- description: "Ensure directory import and export statements use index.js",
315
- category: "Best Practices",
316
- recommended: true
328
+ description: "Ensure directory import and export statements use index.js"
317
329
  },
318
330
  fixable: "code",
319
- schema: []
331
+ schema: [],
332
+ messages: {
333
+ requireExtension: "Directory imports and exports must use index.js."
334
+ }
320
335
  },
336
+ defaultOptions: [],
321
337
  create(context) {
322
338
  function checkSource(source) {
323
339
  const importPath = source.value;
@@ -326,7 +342,7 @@ const requireIndexRule = {
326
342
  if (isDirectory) {
327
343
  context.report({
328
344
  node: source,
329
- message: "Directory imports and exports must use index.js.",
345
+ messageId: "requireExtension",
330
346
  fix(fixer) {
331
347
  const fixedPath = importPath.replace(/\/?$/, "/index.js");
332
348
  return fixer.replaceText(source, `'${fixedPath}'`);
@@ -348,9 +364,9 @@ const requireIndexRule = {
348
364
  }
349
365
  };
350
366
  }
351
- };
367
+ });
352
368
 
353
- const base$7 = {
369
+ const base$8 = {
354
370
  plugins: {
355
371
  "decent-extension": {
356
372
  meta: {
@@ -368,6 +384,25 @@ const base$7 = {
368
384
  "decent-extension/require-index": "error"
369
385
  }
370
386
  };
387
+ const configs$8 = {
388
+ base: base$8
389
+ };
390
+
391
+ const base$7 = {
392
+ plugins: {
393
+ import: importPlugin
394
+ },
395
+ rules: {
396
+ "import/order": [
397
+ "error",
398
+ {
399
+ "newlines-between": "always",
400
+ alphabetize: { order: "asc", caseInsensitive: true },
401
+ pathGroupsExcludedImportTypes: ["builtin"]
402
+ }
403
+ ]
404
+ }
405
+ };
371
406
  const configs$7 = {
372
407
  base: base$7
373
408
  };
@@ -385,6 +420,7 @@ const base$6 = {
385
420
  }
386
421
  },
387
422
  plugins: {
423
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
388
424
  jsdoc
389
425
  },
390
426
  rules: {
@@ -662,6 +698,7 @@ function defaultConfig(options) {
662
698
  name: "eslint-config-decent/base",
663
699
  files: ["**/*.ts", "**/*.js", "**/*.cjs", "**/*.mjs", "**/*.tsx"],
664
700
  plugins: {
701
+ ...configs$8.base.plugins,
665
702
  ...configs$7.base.plugins,
666
703
  ...configs$6.base.plugins,
667
704
  ...configs$4.base.plugins,
@@ -669,8 +706,9 @@ function defaultConfig(options) {
669
706
  ...configs.base.plugins
670
707
  },
671
708
  rules: {
672
- ...configs$8.base.rules,
673
- ...enableRequireExtensionRule ? configs$7.base.rules : {},
709
+ ...configs$9.base.rules,
710
+ ...enableRequireExtensionRule ? configs$8.base.rules : {},
711
+ ...configs$7.base.rules,
674
712
  ...configs$6.base.rules,
675
713
  ...configs$4.base.rules,
676
714
  ...configs$2.base.rules,
@@ -693,7 +731,7 @@ function defaultConfig(options) {
693
731
  languageOptions: {
694
732
  sourceType: "script"
695
733
  },
696
- ...configs$8.cjsAndEsm
734
+ ...configs$9.cjsAndEsm
697
735
  },
698
736
  {
699
737
  name: "eslint-config-decent/cjs",
@@ -701,7 +739,7 @@ function defaultConfig(options) {
701
739
  languageOptions: {
702
740
  sourceType: "script"
703
741
  },
704
- ...configs$8.cjs
742
+ ...configs$9.cjs
705
743
  },
706
744
  {
707
745
  name: "eslint-config-decent/tests",
@@ -712,4 +750,4 @@ function defaultConfig(options) {
712
750
  ];
713
751
  }
714
752
 
715
- export { defaultConfig, configs$8 as eslintConfigs, configs$6 as jsdocConfigs, configs$4 as promiseConfigs, configs$3 as reactConfigs, configs$2 as securityConfigs, configs$1 as typescriptEslintConfigs, configs as unicornConfigs };
753
+ export { defaultConfig, configs$9 as eslintConfigs, configs$7 as importConfigs, configs$6 as jsdocConfigs, configs$4 as promiseConfigs, configs$3 as reactConfigs, configs$2 as securityConfigs, configs$1 as typescriptEslintConfigs, configs as unicornConfigs };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-config-decent",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "A decent ESLint configuration",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -72,31 +72,33 @@
72
72
  "node": ">=20.11.0"
73
73
  },
74
74
  "dependencies": {
75
- "@eslint/js": "^9.6.0",
75
+ "@eslint/js": "^9.7.0",
76
+ "@typescript-eslint/utils": "8.0.0-alpha.46",
76
77
  "eslint-config-prettier": "^9.1.0",
78
+ "eslint-plugin-import-x": "^3.0.1",
77
79
  "eslint-plugin-jsdoc": "^48.7.0",
80
+ "eslint-plugin-jsx-a11y": "^6.9.0",
78
81
  "eslint-plugin-mocha": "^10.4.3",
79
- "eslint-plugin-prettier": "^5.1.3",
82
+ "eslint-plugin-prettier": "^5.2.1",
80
83
  "eslint-plugin-promise": "^6.4.0",
81
- "eslint-plugin-jsx-a11y": "^6.9.0",
82
- "eslint-plugin-react": "^7.34.3",
84
+ "eslint-plugin-react": "^7.34.4",
83
85
  "eslint-plugin-react-hooks": "^4.6.2",
84
86
  "eslint-plugin-security": "^3.0.1",
85
87
  "eslint-plugin-testing-library": "^6.2.2",
86
88
  "eslint-plugin-unicorn": "^54.0.0",
87
89
  "globals": "^15.8.0",
88
- "typescript-eslint": "8.0.0-alpha.41"
90
+ "typescript-eslint": "8.0.0-alpha.46"
89
91
  },
90
92
  "devDependencies": {
91
- "@swc/core": "1.6.13",
93
+ "@swc/core": "1.7.0",
92
94
  "@types/node": ">=20",
93
- "eslint": "^9.6.0",
94
- "husky": "^9.0.11",
95
+ "eslint": "^9.7.0",
96
+ "husky": "^9.1.1",
95
97
  "lint-staged": "^15.2.7",
96
98
  "markdownlint-cli": "^0.41.0",
97
99
  "npm-run-all": "^4.1.5",
98
100
  "pinst": "^3.0.0",
99
- "prettier": "^3.3.2",
101
+ "prettier": "^3.3.3",
100
102
  "typescript": "^5.5.3",
101
103
  "unbuild": "2.0.0"
102
104
  },
package/src/eslint.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { ConfigWithExtends } from 'typescript-eslint';
1
+ import type { TSESLint } from '@typescript-eslint/utils';
2
2
 
3
- const base: ConfigWithExtends = {
3
+ const base: TSESLint.FlatConfig.Config = {
4
4
  rules: {
5
5
  'array-callback-return': ['error', { allowImplicit: true }],
6
6
  'block-scoped-var': 'error',
@@ -194,6 +194,14 @@ const base: ConfigWithExtends = {
194
194
  },
195
195
  ],
196
196
  'prefer-template': 'error',
197
+ 'sort-imports': [
198
+ 'error',
199
+ {
200
+ ignoreCase: true,
201
+ ignoreDeclarationSort: true,
202
+ allowSeparatedGroups: true,
203
+ },
204
+ ],
197
205
  'symbol-description': 'error',
198
206
  'unicode-bom': ['error', 'never'],
199
207
  'vars-on-top': 'error',
@@ -201,7 +209,7 @@ const base: ConfigWithExtends = {
201
209
  },
202
210
  };
203
211
 
204
- const cjsAndEsm: ConfigWithExtends = {
212
+ const cjsAndEsm: TSESLint.FlatConfig.Config = {
205
213
  rules: {
206
214
  curly: ['error', 'multi-line'],
207
215
  'dot-notation': ['error', { allowKeywords: true }],
@@ -236,7 +244,7 @@ const cjsAndEsm: ConfigWithExtends = {
236
244
  },
237
245
  };
238
246
 
239
- const cjs: ConfigWithExtends = {
247
+ const cjs: TSESLint.FlatConfig.Config = {
240
248
  rules: {
241
249
  strict: ['error', 'global'],
242
250
  },
package/src/extension.ts CHANGED
@@ -1,8 +1,9 @@
1
- import type { ConfigWithExtends } from 'typescript-eslint';
1
+ import type { TSESLint } from '@typescript-eslint/utils';
2
+
2
3
  import { requireExtensionRule } from './rules/requireExtensionRule.js';
3
4
  import { requireIndexRule } from './rules/requireIndexRule.js';
4
5
 
5
- const base: ConfigWithExtends = {
6
+ const base: TSESLint.FlatConfig.Config = {
6
7
  plugins: {
7
8
  'decent-extension': {
8
9
  meta: {
package/src/import.ts ADDED
@@ -0,0 +1,26 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
2
+ import importPlugin from 'eslint-plugin-import-x';
3
+
4
+ const base: TSESLint.FlatConfig.Config = {
5
+ plugins: {
6
+ import: importPlugin,
7
+ },
8
+ rules: {
9
+ 'import/order': [
10
+ 'error',
11
+ {
12
+ 'newlines-between': 'always',
13
+ alphabetize: { order: 'asc', caseInsensitive: true },
14
+ pathGroupsExcludedImportTypes: ['builtin'],
15
+ },
16
+ ],
17
+ },
18
+ };
19
+
20
+ export const configs = {
21
+ base,
22
+ };
23
+
24
+ export default {
25
+ configs,
26
+ };
package/src/index.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  import eslint from '@eslint/js';
2
+ import prettier from 'eslint-plugin-prettier/recommended';
2
3
  import globals from 'globals';
3
4
  import tsEslint, { type ConfigWithExtends } from 'typescript-eslint';
4
- import prettier from 'eslint-plugin-prettier/recommended';
5
+
5
6
  import { configs as eslintConfigs } from './eslint.js';
6
7
  import { configs as extensionConfigs } from './extension.js';
8
+ import { configs as importConfigs } from './import.js';
7
9
  import { configs as jsdocConfigs } from './jsdoc.js';
8
10
  import { configs as mochaConfigs } from './mocha.js';
9
11
  import { configs as promiseConfigs } from './promise.js';
@@ -14,6 +16,7 @@ import { configs as unicornConfigs } from './unicorn.js';
14
16
 
15
17
  export {
16
18
  eslintConfigs, //
19
+ importConfigs,
17
20
  jsdocConfigs,
18
21
  promiseConfigs,
19
22
  reactConfigs,
@@ -42,6 +45,7 @@ export function defaultConfig(options?: DefaultConfigOptions): ConfigWithExtends
42
45
  },
43
46
  };
44
47
 
48
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
45
49
  return [
46
50
  {
47
51
  ignores: ['**/dist/**', '**/node_modules/**'],
@@ -75,6 +79,7 @@ export function defaultConfig(options?: DefaultConfigOptions): ConfigWithExtends
75
79
  files: ['**/*.ts', '**/*.js', '**/*.cjs', '**/*.mjs', '**/*.tsx'],
76
80
  plugins: {
77
81
  ...extensionConfigs.base.plugins,
82
+ ...importConfigs.base.plugins,
78
83
  ...jsdocConfigs.base.plugins,
79
84
  ...promiseConfigs.base.plugins,
80
85
  ...securityConfigs.base.plugins,
@@ -83,6 +88,7 @@ export function defaultConfig(options?: DefaultConfigOptions): ConfigWithExtends
83
88
  rules: {
84
89
  ...eslintConfigs.base.rules,
85
90
  ...(enableRequireExtensionRule ? extensionConfigs.base.rules : {}),
91
+ ...importConfigs.base.rules,
86
92
  ...jsdocConfigs.base.rules,
87
93
  ...promiseConfigs.base.rules,
88
94
  ...securityConfigs.base.rules,
package/src/jsdoc.ts CHANGED
@@ -1,7 +1,7 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
1
2
  import jsdoc from 'eslint-plugin-jsdoc';
2
- import type { ConfigWithExtends } from 'typescript-eslint';
3
3
 
4
- const base: ConfigWithExtends = {
4
+ const base: TSESLint.FlatConfig.Config = {
5
5
  settings: {
6
6
  jsdoc: {
7
7
  preferredTypes: {
@@ -14,6 +14,7 @@ const base: ConfigWithExtends = {
14
14
  },
15
15
  },
16
16
  plugins: {
17
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
17
18
  jsdoc,
18
19
  },
19
20
  rules: {
package/src/mocha.ts CHANGED
@@ -1,7 +1,7 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
1
2
  import mocha from 'eslint-plugin-mocha';
2
- import type { ConfigWithExtends } from 'typescript-eslint';
3
3
 
4
- const base: ConfigWithExtends = {
4
+ const base: TSESLint.FlatConfig.Config = {
5
5
  plugins: {
6
6
  mocha,
7
7
  },
package/src/promise.ts CHANGED
@@ -1,7 +1,7 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
1
2
  import promise from 'eslint-plugin-promise';
2
- import type { ConfigWithExtends } from 'typescript-eslint';
3
3
 
4
- const base: ConfigWithExtends = {
4
+ const base: TSESLint.FlatConfig.Config = {
5
5
  plugins: {
6
6
  promise,
7
7
  },
package/src/react.ts CHANGED
@@ -1,10 +1,10 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
1
2
  import a11y from 'eslint-plugin-jsx-a11y';
2
3
  import react from 'eslint-plugin-react';
3
4
  import reactHooks from 'eslint-plugin-react-hooks';
4
5
  import testingLibrary from 'eslint-plugin-testing-library';
5
- import type { ConfigWithExtends } from 'typescript-eslint';
6
6
 
7
- const base: ConfigWithExtends = {
7
+ const base: TSESLint.FlatConfig.Config = {
8
8
  plugins: {
9
9
  'jsx-a11y': a11y,
10
10
  react,
@@ -1,34 +1,42 @@
1
1
  import { existsSync } from 'fs';
2
2
  import { dirname, resolve } from 'path';
3
- import type { Rule } from 'eslint';
4
3
 
5
- export const requireExtensionRule: Rule.RuleModule = {
4
+ import type { TSESTree } from '@typescript-eslint/utils';
5
+ import { ESLintUtils } from '@typescript-eslint/utils';
6
+
7
+ type Options = [];
8
+ type MessageIds = 'requireExtension';
9
+
10
+ export const requireExtensionRule = ESLintUtils.RuleCreator(() => 'https://github.com/jgeurts/eslint-config-decent/tree/main/src/rules/requireExtensionRule.ts')<Options, MessageIds>({
11
+ name: 'require-extension',
6
12
  meta: {
7
13
  type: 'suggestion',
8
14
  docs: {
9
15
  description: 'Ensure import and export statements include a file extension',
10
- category: 'Best Practices',
11
- recommended: true,
12
16
  },
13
17
  fixable: 'code',
14
18
  schema: [],
19
+ messages: {
20
+ requireExtension: 'Relative imports and exports must include a file extension.',
21
+ },
15
22
  },
16
- create(context: Rule.RuleContext) {
17
- function checkSource(source: Parameters<NonNullable<Rule.NodeListener['ImportDeclaration']>>[0]['source']): void {
18
- const importPath = source.value as string;
23
+ defaultOptions: [],
24
+ create(context) {
25
+ function checkSource(source: TSESTree.StringLiteral): void {
26
+ const importPath = source.value;
19
27
 
20
28
  if (!importPath || !importPath.startsWith('.') || importPath.endsWith('.js')) {
21
29
  return;
22
30
  }
23
31
 
24
- const resolvedPath = resolve(dirname(context.filename), importPath);
32
+ const resolvedPath = resolve(dirname(context.getFilename()), importPath);
25
33
 
26
34
  // If the import/export path doesn't end with a file extension, report an error
27
35
  // eslint-disable-next-line security/detect-non-literal-fs-filename
28
36
  if (!existsSync(resolvedPath)) {
29
37
  context.report({
30
38
  node: source,
31
- message: 'Relative imports and exports must include a file extension.',
39
+ messageId: 'requireExtension',
32
40
  fix(fixer) {
33
41
  const fixedPath = `${importPath}.js`;
34
42
  return fixer.replaceText(source, `'${fixedPath}'`);
@@ -38,17 +46,17 @@ export const requireExtensionRule: Rule.RuleModule = {
38
46
  }
39
47
 
40
48
  return {
41
- ImportDeclaration(node: Parameters<NonNullable<Rule.NodeListener['ImportDeclaration']>>[0]): void {
49
+ ImportDeclaration(node: TSESTree.ImportDeclaration): void {
42
50
  checkSource(node.source);
43
51
  },
44
- ExportNamedDeclaration(node: Parameters<NonNullable<Rule.NodeListener['ExportNamedDeclaration']>>[0]): void {
52
+ ExportNamedDeclaration(node: TSESTree.ExportNamedDeclaration): void {
45
53
  if (node.source) {
46
54
  checkSource(node.source);
47
55
  }
48
56
  },
49
- ExportAllDeclaration(node: Parameters<NonNullable<Rule.NodeListener['ExportAllDeclaration']>>[0]): void {
57
+ ExportAllDeclaration(node: TSESTree.ExportAllDeclaration): void {
50
58
  checkSource(node.source);
51
59
  },
52
60
  };
53
61
  },
54
- };
62
+ });
@@ -1,31 +1,40 @@
1
1
  import { existsSync, lstatSync } from 'fs';
2
- import { resolve, dirname } from 'path';
3
- import type { Rule } from 'eslint';
2
+ import { dirname, resolve } from 'path';
4
3
 
5
- export const requireIndexRule: Rule.RuleModule = {
4
+ import type { TSESTree } from '@typescript-eslint/utils';
5
+ import { ESLintUtils } from '@typescript-eslint/utils';
6
+
7
+ type Options = [];
8
+ type MessageIds = 'requireExtension';
9
+
10
+ export const requireIndexRule = ESLintUtils.RuleCreator(() => 'https://github.com/jgeurts/eslint-config-decent/tree/main/src/rules/requireIndexRule.ts')<Options, MessageIds>({
11
+ name: 'require-index',
6
12
  meta: {
7
13
  type: 'suggestion',
8
14
  docs: {
9
15
  description: 'Ensure directory import and export statements use index.js',
10
- category: 'Best Practices',
11
- recommended: true,
12
16
  },
13
17
  fixable: 'code',
14
18
  schema: [],
19
+ messages: {
20
+ requireExtension: 'Directory imports and exports must use index.js.',
21
+ },
15
22
  },
16
- create(context: Rule.RuleContext) {
17
- function checkSource(source: Parameters<NonNullable<Rule.NodeListener['ImportDeclaration']>>[0]['source']): void {
18
- const importPath = source.value as string;
23
+ defaultOptions: [],
24
+ create(context) {
25
+ function checkSource(source: TSESTree.StringLiteral): void {
26
+ const importPath = source.value;
19
27
 
20
28
  // Resolve the path relative to the file being linted
21
29
  const resolvedPath = resolve(dirname(context.filename), importPath);
22
30
 
23
31
  // eslint-disable-next-line security/detect-non-literal-fs-filename
24
32
  const isDirectory = existsSync(resolvedPath) && lstatSync(resolvedPath).isDirectory();
33
+ // If the import/export path doesn't end with a file extension, report an error
25
34
  if (isDirectory) {
26
35
  context.report({
27
36
  node: source,
28
- message: 'Directory imports and exports must use index.js.',
37
+ messageId: 'requireExtension',
29
38
  fix(fixer) {
30
39
  const fixedPath = importPath.replace(/\/?$/, '/index.js');
31
40
  return fixer.replaceText(source, `'${fixedPath}'`);
@@ -35,17 +44,17 @@ export const requireIndexRule: Rule.RuleModule = {
35
44
  }
36
45
 
37
46
  return {
38
- ImportDeclaration(node: Parameters<NonNullable<Rule.NodeListener['ImportDeclaration']>>[0]): void {
47
+ ImportDeclaration(node: TSESTree.ImportDeclaration): void {
39
48
  checkSource(node.source);
40
49
  },
41
- ExportNamedDeclaration(node: Parameters<NonNullable<Rule.NodeListener['ExportNamedDeclaration']>>[0]): void {
50
+ ExportNamedDeclaration(node: TSESTree.ExportNamedDeclaration): void {
42
51
  if (node.source) {
43
52
  checkSource(node.source);
44
53
  }
45
54
  },
46
- ExportAllDeclaration(node: Parameters<NonNullable<Rule.NodeListener['ExportAllDeclaration']>>[0]): void {
55
+ ExportAllDeclaration(node: TSESTree.ExportAllDeclaration): void {
47
56
  checkSource(node.source);
48
57
  },
49
58
  };
50
59
  },
51
- };
60
+ });
package/src/security.ts CHANGED
@@ -1,7 +1,7 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
1
2
  import security from 'eslint-plugin-security';
2
- import type { ConfigWithExtends } from 'typescript-eslint';
3
3
 
4
- const base: ConfigWithExtends = {
4
+ const base: TSESLint.FlatConfig.Config = {
5
5
  plugins: {
6
6
  security,
7
7
  },
@@ -1,8 +1,8 @@
1
1
  declare module '@eslint/js' {
2
- import type { ESLint, Linter } from 'eslint';
3
- const value: ESLint.Plugin & {
2
+ import type { TSESLint } from '@typescript-eslint/utils';
3
+ const value: TSESLint.FlatConfig.Plugin & {
4
4
  configs: {
5
- recommended: Linter.FlatConfig;
5
+ recommended: TSESLint.FlatConfig.Config;
6
6
  };
7
7
  };
8
8
  export default value;
@@ -1,8 +1,8 @@
1
1
  declare module 'eslint-plugin-jsx-a11y' {
2
- import type { ESLint, Linter } from 'eslint';
3
- const value: ESLint.Plugin & {
2
+ import type { TSESLint } from '@typescript-eslint/utils';
3
+ const value: TSESLint.FlatConfig.Plugin & {
4
4
  configs: {
5
- recommended: Linter.FlatConfig;
5
+ recommended: TSESLint.FlatConfig.Config;
6
6
  };
7
7
  };
8
8
  export default value;
@@ -1,8 +1,8 @@
1
1
  declare module 'eslint-plugin-mocha' {
2
- import type { ESLint, Linter } from 'eslint';
3
- const value: ESLint.Plugin & {
2
+ import type { TSESLint } from '@typescript-eslint/utils';
3
+ const value: TSESLint.FlatConfig.Plugin & {
4
4
  configs: {
5
- recommended: Linter.FlatConfig;
5
+ recommended: TSESLint.FlatConfig.Config;
6
6
  };
7
7
  };
8
8
  export default value;
@@ -1,5 +1,5 @@
1
1
  declare module 'eslint-plugin-promise' {
2
- import type { ESLint } from 'eslint';
3
- const value: ESLint.Plugin;
2
+ import type { TSESLint } from '@typescript-eslint/utils';
3
+ const value: TSESLint.FlatConfig.Plugin;
4
4
  export default value;
5
5
  }
@@ -1,5 +1,5 @@
1
1
  declare module 'eslint-plugin-react-hooks' {
2
- import type { ESLint } from 'eslint';
3
- const value: ESLint.Plugin;
2
+ import type { TSESLint } from '@typescript-eslint/utils';
3
+ const value: TSESLint.FlatConfig.Plugin;
4
4
  export default value;
5
5
  }
@@ -1,8 +1,8 @@
1
1
  declare module 'eslint-plugin-react' {
2
- import type { ESLint, Linter } from 'eslint';
3
- const value: ESLint.Plugin & {
2
+ import type { TSESLint } from '@typescript-eslint/utils';
3
+ const value: TSESLint.FlatConfig.Plugin & {
4
4
  configs: {
5
- recommended: Linter.FlatConfig;
5
+ recommended: TSESLint.FlatConfig.Config;
6
6
  };
7
7
  };
8
8
  export default value;
@@ -1,5 +1,5 @@
1
1
  declare module 'eslint-plugin-security' {
2
- import type { ESLint } from 'eslint';
3
- const value: ESLint.Plugin;
2
+ import type { TSESLint } from '@typescript-eslint/utils';
3
+ const value: TSESLint.FlatConfig.Plugin;
4
4
  export default value;
5
5
  }
@@ -1,8 +1,8 @@
1
1
  declare module 'eslint-plugin-testing-library' {
2
- import type { ESLint, Linter } from 'eslint';
3
- const value: ESLint.Plugin & {
2
+ import type { TSESLint } from '@typescript-eslint/utils';
3
+ const value: TSESLint.FlatConfig.Plugin & {
4
4
  configs: {
5
- react: Linter.FlatConfig;
5
+ react: TSESLint.FlatConfig.Config;
6
6
  };
7
7
  };
8
8
  export default value;
@@ -1,5 +1,5 @@
1
1
  declare module 'eslint-plugin-unicorn' {
2
- import type { ESLint } from 'eslint';
3
- const value: ESLint.Plugin;
2
+ import type { TSESLint } from '@typescript-eslint/utils';
3
+ const value: TSESLint.FlatConfig.Plugin;
4
4
  export default value;
5
5
  }
@@ -1,6 +1,6 @@
1
- import type { ConfigWithExtends } from 'typescript-eslint';
1
+ import type { TSESLint } from '@typescript-eslint/utils';
2
2
 
3
- const base: ConfigWithExtends = {
3
+ const base: TSESLint.FlatConfig.Config = {
4
4
  rules: {
5
5
  'no-loss-of-precision': 'off',
6
6
  'no-loop-func': 'off',
package/src/unicorn.ts CHANGED
@@ -1,7 +1,7 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
1
2
  import unicorn from 'eslint-plugin-unicorn';
2
- import type { ConfigWithExtends } from 'typescript-eslint';
3
3
 
4
- const base: ConfigWithExtends = {
4
+ const base: TSESLint.FlatConfig.Config = {
5
5
  plugins: {
6
6
  unicorn,
7
7
  },