@rotki/eslint-plugin 0.3.2 → 0.4.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
@@ -4,6 +4,7 @@ const createDebug = require('debug');
4
4
  const node_path = require('node:path');
5
5
  const compat = require('eslint-compat-utils');
6
6
  const scule = require('scule');
7
+ const utils = require('@typescript-eslint/utils');
7
8
 
8
9
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
9
10
 
@@ -23,8 +24,8 @@ const createDebug__default = /*#__PURE__*/_interopDefaultCompat(createDebug);
23
24
  const compat__namespace = /*#__PURE__*/_interopNamespaceCompat(compat);
24
25
 
25
26
  const name = "@rotki/eslint-plugin";
26
- const version = "0.3.2";
27
- const packageManager = "pnpm@8.15.0";
27
+ const version = "0.4.0";
28
+ const packageManager = "pnpm@9.4.0";
28
29
  const type = "module";
29
30
  const license = "AGPL-3.0";
30
31
  const bugs = {
@@ -71,40 +72,40 @@ const peerDependencies = {
71
72
  eslint: "^8.0.0 || ^9.0.0"
72
73
  };
73
74
  const dependencies = {
74
- "@typescript-eslint/utils": "6.19.1",
75
- debug: "4.3.4",
76
- "eslint-compat-utils": "0.4.1",
75
+ "@typescript-eslint/utils": "7.15.0",
76
+ debug: "4.3.5",
77
+ "eslint-compat-utils": "0.5.1",
77
78
  "jsonc-eslint-parser": "2.4.0",
78
- scule: "1.2.0",
79
- "vue-eslint-parser": "9.4.2",
80
- "yaml-eslint-parser": "1.2.2"
79
+ scule: "1.3.0",
80
+ "vue-eslint-parser": "9.4.3",
81
+ "yaml-eslint-parser": "1.2.3"
81
82
  };
82
83
  const devDependencies = {
83
- "@commitlint/cli": "18.6.0",
84
- "@commitlint/config-conventional": "18.6.0",
85
- "@rotki/eslint-config": "2.4.4",
84
+ "@commitlint/cli": "19.3.0",
85
+ "@commitlint/config-conventional": "19.2.2",
86
+ "@rotki/eslint-config": "2.9.0",
86
87
  "@types/debug": "4.1.12",
87
- "@types/eslint": "8.56.2",
88
+ "@types/eslint": "8.56.10",
88
89
  "@types/node": "20",
89
- "@typescript-eslint/eslint-plugin": "6.19.1",
90
- "@typescript-eslint/parser": "6.19.1",
91
- "@typescript-eslint/rule-tester": "6.19.1",
92
- "@vitest/coverage-v8": "^1.2.2",
93
- bumpp: "9.3.0",
94
- debug: "4.3.4",
95
- eslint: "8.56.0",
96
- husky: "9.0.7",
97
- "lint-staged": "15.2.0",
98
- rimraf: "5.0.5",
90
+ "@typescript-eslint/eslint-plugin": "7.15.0",
91
+ "@typescript-eslint/parser": "7.15.0",
92
+ "@typescript-eslint/rule-tester": "7.15.0",
93
+ "@vitest/coverage-v8": "1.6.0",
94
+ bumpp: "9.4.1",
95
+ debug: "4.3.5",
96
+ eslint: "8.57.0",
97
+ husky: "9.0.11",
98
+ "lint-staged": "15.2.7",
99
+ rimraf: "5.0.8",
99
100
  "ts-node": "10.9.2",
100
- typescript: "5.3.3",
101
+ typescript: "5.5.3",
101
102
  unbuild: "2.0.0",
102
- vitepress: "1.0.0-rc.40",
103
- vitest: "1.2.2"
103
+ vitepress: "1.2.3",
104
+ vitest: "1.6.0"
104
105
  };
105
106
  const engines = {
106
107
  node: ">=20",
107
- pnpm: ">=8 <9"
108
+ pnpm: ">=9 <10"
108
109
  };
109
110
  const pkg = {
110
111
  name: name,
@@ -181,6 +182,8 @@ const createEslintRule = RuleCreator(
181
182
  function defineTemplateBodyVisitor(context, templateBodyVisitor, scriptVisitor, options) {
182
183
  const sourceCode = getSourceCode(context);
183
184
  const parserServices = sourceCode.parserServices;
185
+ if (!parserServices)
186
+ throw new Error("missing parserServices");
184
187
  if (!("defineTemplateBodyVisitor" in parserServices) || parserServices.defineTemplateBodyVisitor == null) {
185
188
  const filename = getFilename(context);
186
189
  if (node_path.extname(filename) === ".vue") {
@@ -254,8 +257,8 @@ function createRecommended(plugin, name, flat) {
254
257
  }
255
258
  }
256
259
 
257
- const RULE_NAME$3 = "no-deprecated-classes";
258
- const debug$2 = createDebug__default("@rotki/eslint-plugin:no-deprecated-classes");
260
+ const RULE_NAME$4 = "no-deprecated-classes";
261
+ const debug$3 = createDebug__default("@rotki/eslint-plugin:no-deprecated-classes");
259
262
  const replacements$2 = [
260
263
  ["d-block", "block"],
261
264
  ["d-flex", "flex"],
@@ -315,7 +318,7 @@ function getRange(node) {
315
318
  return node.range;
316
319
  }
317
320
  function reportReplacement(className, replacement, node, context, position = 1) {
318
- debug$2(`found replacement ${replacement} for ${className}`);
321
+ debug$3(`found replacement ${replacement} for ${className}`);
319
322
  const source = getSourceCode(context);
320
323
  const initialRange = getRange(node);
321
324
  const range = [
@@ -428,11 +431,11 @@ const noDeprecatedClasses = createEslintRule({
428
431
  schema: [],
429
432
  type: "problem"
430
433
  },
431
- name: RULE_NAME$3
434
+ name: RULE_NAME$4
432
435
  });
433
436
 
434
- const debug$1 = createDebug__default("@rotki/eslint-plugin:no-deprecated-components");
435
- const RULE_NAME$2 = "no-deprecated-components";
437
+ const debug$2 = createDebug__default("@rotki/eslint-plugin:no-deprecated-components");
438
+ const RULE_NAME$3 = "no-deprecated-components";
436
439
  const vuetify = {
437
440
  VApp: true,
438
441
  VAppBar: true,
@@ -479,13 +482,13 @@ const noDeprecatedComponents = createEslintRule({
479
482
  VElement(element) {
480
483
  const tag = scule.pascalCase(element.rawName);
481
484
  const sourceCode = getSourceCode(context);
482
- if (!("getTemplateBodyTokenStore" in sourceCode.parserServices))
485
+ if (sourceCode?.parserServices && !("getTemplateBodyTokenStore" in sourceCode.parserServices))
483
486
  throw new Error("cannot find getTemplateBodyTokenStore in parserServices");
484
487
  if (!hasReplacement$1(tag))
485
488
  return;
486
489
  const replacement = replacements$1[tag];
487
490
  if (replacement || legacy && skipInLegacy.includes(tag)) {
488
- debug$1(`${tag} has been deprecated`);
491
+ debug$2(`${tag} has been deprecated`);
489
492
  context.report({
490
493
  data: {
491
494
  name: tag
@@ -494,7 +497,7 @@ const noDeprecatedComponents = createEslintRule({
494
497
  node: element
495
498
  });
496
499
  } else {
497
- debug$1(`${tag} has will be removed`);
500
+ debug$2(`${tag} has will be removed`);
498
501
  context.report({
499
502
  data: {
500
503
  name: tag
@@ -537,11 +540,11 @@ const noDeprecatedComponents = createEslintRule({
537
540
  ],
538
541
  type: "problem"
539
542
  },
540
- name: RULE_NAME$2
543
+ name: RULE_NAME$3
541
544
  });
542
545
 
543
- const debug = createDebug__default("@rotki/eslint-plugin:no-deprecated-props");
544
- const RULE_NAME$1 = "no-deprecated-props";
546
+ const debug$1 = createDebug__default("@rotki/eslint-plugin:no-deprecated-props");
547
+ const RULE_NAME$2 = "no-deprecated-props";
545
548
  const replacements = {
546
549
  RuiRadio: {
547
550
  internalValue: "value"
@@ -567,16 +570,16 @@ const noDeprecatedProps = createEslintRule({
567
570
  const tag = scule.pascalCase(node.parent.parent.rawName);
568
571
  if (!hasReplacement(tag))
569
572
  return;
570
- debug(`${tag} has replacement properties`);
573
+ debug$1(`${tag} has replacement properties`);
571
574
  const propName = getPropName(node);
572
575
  const propNameNode = node.directive ? node.key.argument : node.key;
573
576
  if (!propName || !propNameNode) {
574
- debug("could not get prop name and/or node");
577
+ debug$1("could not get prop name and/or node");
575
578
  return;
576
579
  }
577
580
  Object.entries(replacements[tag]).forEach(([prop, replacement]) => {
578
581
  if (scule.kebabCase(prop) === propName) {
579
- debug(`preparing a replacement for ${tag}:${propName} -> ${replacement}`);
582
+ debug$1(`preparing a replacement for ${tag}:${propName} -> ${replacement}`);
580
583
  context.report({
581
584
  data: {
582
585
  prop,
@@ -605,10 +608,10 @@ const noDeprecatedProps = createEslintRule({
605
608
  schema: [],
606
609
  type: "problem"
607
610
  },
608
- name: RULE_NAME$1
611
+ name: RULE_NAME$2
609
612
  });
610
613
 
611
- const RULE_NAME = "no-legacy-library-import";
614
+ const RULE_NAME$1 = "no-legacy-library-import";
612
615
  const legacyLibrary = "@rotki/ui-library-compat";
613
616
  const newLibrary = "@rotki/ui-library";
614
617
  const noLegacyLibraryImport = createEslintRule({
@@ -640,6 +643,105 @@ const noLegacyLibraryImport = createEslintRule({
640
643
  schema: [],
641
644
  type: "problem"
642
645
  },
646
+ name: RULE_NAME$1
647
+ });
648
+
649
+ const debug = createDebug__default("@rotki/eslint-plugin:consistent-ref-type-annotation");
650
+ const RULE_NAME = "consistent-ref-type-annotation";
651
+ const FIXABLE_METHODS = ["ref", "computed"];
652
+ function checkAssignmentDeclaration(context, node, declaration, options) {
653
+ const source = getSourceCode(context);
654
+ const { allowInference } = options;
655
+ let declarationTypeArguments;
656
+ const init = declaration.init;
657
+ if (!(init && init.type === utils.TSESTree.AST_NODE_TYPES.CallExpression))
658
+ return;
659
+ const callee = init.callee;
660
+ if (!(callee && callee.type === utils.TSESTree.AST_NODE_TYPES.Identifier))
661
+ return;
662
+ if (!Array.prototype.includes.call(FIXABLE_METHODS, callee.name))
663
+ return;
664
+ const name = callee.name;
665
+ debug(`found ${name}, checking type arguments`);
666
+ const initializationTypeArguments = init.typeArguments;
667
+ const typeAnnotation = declaration.id.typeAnnotation;
668
+ if (typeAnnotation) {
669
+ const typeNode = typeAnnotation.typeAnnotation;
670
+ if (typeNode && typeNode.type === utils.TSESTree.AST_NODE_TYPES.TSTypeReference)
671
+ declarationTypeArguments = typeNode.typeArguments;
672
+ }
673
+ if (initializationTypeArguments && !declarationTypeArguments)
674
+ return;
675
+ debug(`generating report for ${name}`);
676
+ if (!initializationTypeArguments && !declarationTypeArguments) {
677
+ if (allowInference) {
678
+ debug("type inference is allowed");
679
+ } else {
680
+ context.report({
681
+ data: {
682
+ name
683
+ },
684
+ messageId: "missingType",
685
+ node
686
+ });
687
+ }
688
+ return;
689
+ }
690
+ context.report({
691
+ data: {
692
+ name
693
+ },
694
+ fix(fixer) {
695
+ const fixes = [];
696
+ if (!initializationTypeArguments && callee)
697
+ fixes.push(fixer.insertTextAfter(callee, source.getText(declarationTypeArguments)));
698
+ if (typeAnnotation)
699
+ fixes.push(fixer.remove(typeAnnotation));
700
+ return fixes;
701
+ },
702
+ messageId: "inconsistent",
703
+ node
704
+ });
705
+ }
706
+ const consistentRefTypeAnnotation = createEslintRule({
707
+ create(context, optionsWithDefault) {
708
+ const options = optionsWithDefault[0] || {};
709
+ const allowInference = options.allowInference;
710
+ return {
711
+ VariableDeclaration: (node) => {
712
+ const declarations = node.declarations;
713
+ for (const declaration of declarations) {
714
+ if (declaration.type !== utils.TSESTree.AST_NODE_TYPES.VariableDeclarator)
715
+ continue;
716
+ checkAssignmentDeclaration(context, node, declaration, { allowInference });
717
+ }
718
+ }
719
+ };
720
+ },
721
+ defaultOptions: [{ allowInference: false }],
722
+ meta: {
723
+ docs: {
724
+ description: "Ensures consistent type annotation position for ref, computed assignments",
725
+ recommended: "recommended"
726
+ },
727
+ fixable: "code",
728
+ messages: {
729
+ inconsistent: `Generic type annotation for the {{ name }} call was not on the right side`,
730
+ missingType: `variable assignment for {{ name }} is missing the type annotation`
731
+ },
732
+ schema: [
733
+ {
734
+ additionalProperties: false,
735
+ properties: {
736
+ allowInference: {
737
+ type: "boolean"
738
+ }
739
+ },
740
+ type: "object"
741
+ }
742
+ ],
743
+ type: "problem"
744
+ },
643
745
  name: RULE_NAME
644
746
  });
645
747
 
@@ -649,6 +751,7 @@ const plugin = {
649
751
  version: pkg.version
650
752
  },
651
753
  rules: {
754
+ "consistent-ref-type-annotation": consistentRefTypeAnnotation,
652
755
  "no-deprecated-classes": noDeprecatedClasses,
653
756
  "no-deprecated-components": noDeprecatedComponents,
654
757
  "no-deprecated-props": noDeprecatedProps,
package/dist/index.d.cts CHANGED
@@ -4,18 +4,23 @@ interface PluginRuleModule<TOptions extends readonly unknown[] = []> extends Rul
4
4
  defaultOptions: TOptions;
5
5
  }
6
6
 
7
- type Options = [{
7
+ type Options$1 = [{
8
8
  legacy: boolean;
9
9
  }];
10
10
 
11
+ type Options = [{
12
+ allowInference: boolean;
13
+ }];
14
+
11
15
  declare const plugin: {
12
16
  meta: {
13
17
  name: string;
14
18
  version: string;
15
19
  };
16
20
  rules: {
21
+ 'consistent-ref-type-annotation': PluginRuleModule<Options>;
17
22
  'no-deprecated-classes': PluginRuleModule<[]>;
18
- 'no-deprecated-components': PluginRuleModule<Options>;
23
+ 'no-deprecated-components': PluginRuleModule<Options$1>;
19
24
  'no-deprecated-props': PluginRuleModule<[]>;
20
25
  'no-legacy-library-import': PluginRuleModule<[]>;
21
26
  };
@@ -27,8 +32,9 @@ declare const _default: {
27
32
  version: string;
28
33
  };
29
34
  rules: {
35
+ 'consistent-ref-type-annotation': PluginRuleModule<Options>;
30
36
  'no-deprecated-classes': PluginRuleModule<[]>;
31
- 'no-deprecated-components': PluginRuleModule<Options>;
37
+ 'no-deprecated-components': PluginRuleModule<Options$1>;
32
38
  'no-deprecated-props': PluginRuleModule<[]>;
33
39
  'no-legacy-library-import': PluginRuleModule<[]>;
34
40
  };
@@ -42,8 +48,9 @@ declare const _default: {
42
48
  version: string;
43
49
  };
44
50
  rules: {
51
+ 'consistent-ref-type-annotation': PluginRuleModule<Options>;
45
52
  'no-deprecated-classes': PluginRuleModule<[]>;
46
- 'no-deprecated-components': PluginRuleModule<Options>;
53
+ 'no-deprecated-components': PluginRuleModule<Options$1>;
47
54
  'no-deprecated-props': PluginRuleModule<[]>;
48
55
  'no-legacy-library-import': PluginRuleModule<[]>;
49
56
  };
@@ -66,8 +73,9 @@ declare const _default: {
66
73
  version: string;
67
74
  };
68
75
  rules: {
76
+ 'consistent-ref-type-annotation': PluginRuleModule<Options>;
69
77
  'no-deprecated-classes': PluginRuleModule<[]>;
70
- 'no-deprecated-components': PluginRuleModule<Options>;
78
+ 'no-deprecated-components': PluginRuleModule<Options$1>;
71
79
  'no-deprecated-props': PluginRuleModule<[]>;
72
80
  'no-legacy-library-import': PluginRuleModule<[]>;
73
81
  };
package/dist/index.d.mts CHANGED
@@ -4,18 +4,23 @@ interface PluginRuleModule<TOptions extends readonly unknown[] = []> extends Rul
4
4
  defaultOptions: TOptions;
5
5
  }
6
6
 
7
- type Options = [{
7
+ type Options$1 = [{
8
8
  legacy: boolean;
9
9
  }];
10
10
 
11
+ type Options = [{
12
+ allowInference: boolean;
13
+ }];
14
+
11
15
  declare const plugin: {
12
16
  meta: {
13
17
  name: string;
14
18
  version: string;
15
19
  };
16
20
  rules: {
21
+ 'consistent-ref-type-annotation': PluginRuleModule<Options>;
17
22
  'no-deprecated-classes': PluginRuleModule<[]>;
18
- 'no-deprecated-components': PluginRuleModule<Options>;
23
+ 'no-deprecated-components': PluginRuleModule<Options$1>;
19
24
  'no-deprecated-props': PluginRuleModule<[]>;
20
25
  'no-legacy-library-import': PluginRuleModule<[]>;
21
26
  };
@@ -27,8 +32,9 @@ declare const _default: {
27
32
  version: string;
28
33
  };
29
34
  rules: {
35
+ 'consistent-ref-type-annotation': PluginRuleModule<Options>;
30
36
  'no-deprecated-classes': PluginRuleModule<[]>;
31
- 'no-deprecated-components': PluginRuleModule<Options>;
37
+ 'no-deprecated-components': PluginRuleModule<Options$1>;
32
38
  'no-deprecated-props': PluginRuleModule<[]>;
33
39
  'no-legacy-library-import': PluginRuleModule<[]>;
34
40
  };
@@ -42,8 +48,9 @@ declare const _default: {
42
48
  version: string;
43
49
  };
44
50
  rules: {
51
+ 'consistent-ref-type-annotation': PluginRuleModule<Options>;
45
52
  'no-deprecated-classes': PluginRuleModule<[]>;
46
- 'no-deprecated-components': PluginRuleModule<Options>;
53
+ 'no-deprecated-components': PluginRuleModule<Options$1>;
47
54
  'no-deprecated-props': PluginRuleModule<[]>;
48
55
  'no-legacy-library-import': PluginRuleModule<[]>;
49
56
  };
@@ -66,8 +73,9 @@ declare const _default: {
66
73
  version: string;
67
74
  };
68
75
  rules: {
76
+ 'consistent-ref-type-annotation': PluginRuleModule<Options>;
69
77
  'no-deprecated-classes': PluginRuleModule<[]>;
70
- 'no-deprecated-components': PluginRuleModule<Options>;
78
+ 'no-deprecated-components': PluginRuleModule<Options$1>;
71
79
  'no-deprecated-props': PluginRuleModule<[]>;
72
80
  'no-legacy-library-import': PluginRuleModule<[]>;
73
81
  };
package/dist/index.d.ts CHANGED
@@ -4,18 +4,23 @@ interface PluginRuleModule<TOptions extends readonly unknown[] = []> extends Rul
4
4
  defaultOptions: TOptions;
5
5
  }
6
6
 
7
- type Options = [{
7
+ type Options$1 = [{
8
8
  legacy: boolean;
9
9
  }];
10
10
 
11
+ type Options = [{
12
+ allowInference: boolean;
13
+ }];
14
+
11
15
  declare const plugin: {
12
16
  meta: {
13
17
  name: string;
14
18
  version: string;
15
19
  };
16
20
  rules: {
21
+ 'consistent-ref-type-annotation': PluginRuleModule<Options>;
17
22
  'no-deprecated-classes': PluginRuleModule<[]>;
18
- 'no-deprecated-components': PluginRuleModule<Options>;
23
+ 'no-deprecated-components': PluginRuleModule<Options$1>;
19
24
  'no-deprecated-props': PluginRuleModule<[]>;
20
25
  'no-legacy-library-import': PluginRuleModule<[]>;
21
26
  };
@@ -27,8 +32,9 @@ declare const _default: {
27
32
  version: string;
28
33
  };
29
34
  rules: {
35
+ 'consistent-ref-type-annotation': PluginRuleModule<Options>;
30
36
  'no-deprecated-classes': PluginRuleModule<[]>;
31
- 'no-deprecated-components': PluginRuleModule<Options>;
37
+ 'no-deprecated-components': PluginRuleModule<Options$1>;
32
38
  'no-deprecated-props': PluginRuleModule<[]>;
33
39
  'no-legacy-library-import': PluginRuleModule<[]>;
34
40
  };
@@ -42,8 +48,9 @@ declare const _default: {
42
48
  version: string;
43
49
  };
44
50
  rules: {
51
+ 'consistent-ref-type-annotation': PluginRuleModule<Options>;
45
52
  'no-deprecated-classes': PluginRuleModule<[]>;
46
- 'no-deprecated-components': PluginRuleModule<Options>;
53
+ 'no-deprecated-components': PluginRuleModule<Options$1>;
47
54
  'no-deprecated-props': PluginRuleModule<[]>;
48
55
  'no-legacy-library-import': PluginRuleModule<[]>;
49
56
  };
@@ -66,8 +73,9 @@ declare const _default: {
66
73
  version: string;
67
74
  };
68
75
  rules: {
76
+ 'consistent-ref-type-annotation': PluginRuleModule<Options>;
69
77
  'no-deprecated-classes': PluginRuleModule<[]>;
70
- 'no-deprecated-components': PluginRuleModule<Options>;
78
+ 'no-deprecated-components': PluginRuleModule<Options$1>;
71
79
  'no-deprecated-props': PluginRuleModule<[]>;
72
80
  'no-legacy-library-import': PluginRuleModule<[]>;
73
81
  };
package/dist/index.mjs CHANGED
@@ -2,10 +2,11 @@ import createDebug from 'debug';
2
2
  import { extname } from 'node:path';
3
3
  import * as compat from 'eslint-compat-utils';
4
4
  import { pascalCase, kebabCase } from 'scule';
5
+ import { TSESTree } from '@typescript-eslint/utils';
5
6
 
6
7
  const name = "@rotki/eslint-plugin";
7
- const version = "0.3.2";
8
- const packageManager = "pnpm@8.15.0";
8
+ const version = "0.4.0";
9
+ const packageManager = "pnpm@9.4.0";
9
10
  const type = "module";
10
11
  const license = "AGPL-3.0";
11
12
  const bugs = {
@@ -52,40 +53,40 @@ const peerDependencies = {
52
53
  eslint: "^8.0.0 || ^9.0.0"
53
54
  };
54
55
  const dependencies = {
55
- "@typescript-eslint/utils": "6.19.1",
56
- debug: "4.3.4",
57
- "eslint-compat-utils": "0.4.1",
56
+ "@typescript-eslint/utils": "7.15.0",
57
+ debug: "4.3.5",
58
+ "eslint-compat-utils": "0.5.1",
58
59
  "jsonc-eslint-parser": "2.4.0",
59
- scule: "1.2.0",
60
- "vue-eslint-parser": "9.4.2",
61
- "yaml-eslint-parser": "1.2.2"
60
+ scule: "1.3.0",
61
+ "vue-eslint-parser": "9.4.3",
62
+ "yaml-eslint-parser": "1.2.3"
62
63
  };
63
64
  const devDependencies = {
64
- "@commitlint/cli": "18.6.0",
65
- "@commitlint/config-conventional": "18.6.0",
66
- "@rotki/eslint-config": "2.4.4",
65
+ "@commitlint/cli": "19.3.0",
66
+ "@commitlint/config-conventional": "19.2.2",
67
+ "@rotki/eslint-config": "2.9.0",
67
68
  "@types/debug": "4.1.12",
68
- "@types/eslint": "8.56.2",
69
+ "@types/eslint": "8.56.10",
69
70
  "@types/node": "20",
70
- "@typescript-eslint/eslint-plugin": "6.19.1",
71
- "@typescript-eslint/parser": "6.19.1",
72
- "@typescript-eslint/rule-tester": "6.19.1",
73
- "@vitest/coverage-v8": "^1.2.2",
74
- bumpp: "9.3.0",
75
- debug: "4.3.4",
76
- eslint: "8.56.0",
77
- husky: "9.0.7",
78
- "lint-staged": "15.2.0",
79
- rimraf: "5.0.5",
71
+ "@typescript-eslint/eslint-plugin": "7.15.0",
72
+ "@typescript-eslint/parser": "7.15.0",
73
+ "@typescript-eslint/rule-tester": "7.15.0",
74
+ "@vitest/coverage-v8": "1.6.0",
75
+ bumpp: "9.4.1",
76
+ debug: "4.3.5",
77
+ eslint: "8.57.0",
78
+ husky: "9.0.11",
79
+ "lint-staged": "15.2.7",
80
+ rimraf: "5.0.8",
80
81
  "ts-node": "10.9.2",
81
- typescript: "5.3.3",
82
+ typescript: "5.5.3",
82
83
  unbuild: "2.0.0",
83
- vitepress: "1.0.0-rc.40",
84
- vitest: "1.2.2"
84
+ vitepress: "1.2.3",
85
+ vitest: "1.6.0"
85
86
  };
86
87
  const engines = {
87
88
  node: ">=20",
88
- pnpm: ">=8 <9"
89
+ pnpm: ">=9 <10"
89
90
  };
90
91
  const pkg = {
91
92
  name: name,
@@ -162,6 +163,8 @@ const createEslintRule = RuleCreator(
162
163
  function defineTemplateBodyVisitor(context, templateBodyVisitor, scriptVisitor, options) {
163
164
  const sourceCode = getSourceCode(context);
164
165
  const parserServices = sourceCode.parserServices;
166
+ if (!parserServices)
167
+ throw new Error("missing parserServices");
165
168
  if (!("defineTemplateBodyVisitor" in parserServices) || parserServices.defineTemplateBodyVisitor == null) {
166
169
  const filename = getFilename(context);
167
170
  if (extname(filename) === ".vue") {
@@ -235,8 +238,8 @@ function createRecommended(plugin, name, flat) {
235
238
  }
236
239
  }
237
240
 
238
- const RULE_NAME$3 = "no-deprecated-classes";
239
- const debug$2 = createDebug("@rotki/eslint-plugin:no-deprecated-classes");
241
+ const RULE_NAME$4 = "no-deprecated-classes";
242
+ const debug$3 = createDebug("@rotki/eslint-plugin:no-deprecated-classes");
240
243
  const replacements$2 = [
241
244
  ["d-block", "block"],
242
245
  ["d-flex", "flex"],
@@ -296,7 +299,7 @@ function getRange(node) {
296
299
  return node.range;
297
300
  }
298
301
  function reportReplacement(className, replacement, node, context, position = 1) {
299
- debug$2(`found replacement ${replacement} for ${className}`);
302
+ debug$3(`found replacement ${replacement} for ${className}`);
300
303
  const source = getSourceCode(context);
301
304
  const initialRange = getRange(node);
302
305
  const range = [
@@ -409,11 +412,11 @@ const noDeprecatedClasses = createEslintRule({
409
412
  schema: [],
410
413
  type: "problem"
411
414
  },
412
- name: RULE_NAME$3
415
+ name: RULE_NAME$4
413
416
  });
414
417
 
415
- const debug$1 = createDebug("@rotki/eslint-plugin:no-deprecated-components");
416
- const RULE_NAME$2 = "no-deprecated-components";
418
+ const debug$2 = createDebug("@rotki/eslint-plugin:no-deprecated-components");
419
+ const RULE_NAME$3 = "no-deprecated-components";
417
420
  const vuetify = {
418
421
  VApp: true,
419
422
  VAppBar: true,
@@ -460,13 +463,13 @@ const noDeprecatedComponents = createEslintRule({
460
463
  VElement(element) {
461
464
  const tag = pascalCase(element.rawName);
462
465
  const sourceCode = getSourceCode(context);
463
- if (!("getTemplateBodyTokenStore" in sourceCode.parserServices))
466
+ if (sourceCode?.parserServices && !("getTemplateBodyTokenStore" in sourceCode.parserServices))
464
467
  throw new Error("cannot find getTemplateBodyTokenStore in parserServices");
465
468
  if (!hasReplacement$1(tag))
466
469
  return;
467
470
  const replacement = replacements$1[tag];
468
471
  if (replacement || legacy && skipInLegacy.includes(tag)) {
469
- debug$1(`${tag} has been deprecated`);
472
+ debug$2(`${tag} has been deprecated`);
470
473
  context.report({
471
474
  data: {
472
475
  name: tag
@@ -475,7 +478,7 @@ const noDeprecatedComponents = createEslintRule({
475
478
  node: element
476
479
  });
477
480
  } else {
478
- debug$1(`${tag} has will be removed`);
481
+ debug$2(`${tag} has will be removed`);
479
482
  context.report({
480
483
  data: {
481
484
  name: tag
@@ -518,11 +521,11 @@ const noDeprecatedComponents = createEslintRule({
518
521
  ],
519
522
  type: "problem"
520
523
  },
521
- name: RULE_NAME$2
524
+ name: RULE_NAME$3
522
525
  });
523
526
 
524
- const debug = createDebug("@rotki/eslint-plugin:no-deprecated-props");
525
- const RULE_NAME$1 = "no-deprecated-props";
527
+ const debug$1 = createDebug("@rotki/eslint-plugin:no-deprecated-props");
528
+ const RULE_NAME$2 = "no-deprecated-props";
526
529
  const replacements = {
527
530
  RuiRadio: {
528
531
  internalValue: "value"
@@ -548,16 +551,16 @@ const noDeprecatedProps = createEslintRule({
548
551
  const tag = pascalCase(node.parent.parent.rawName);
549
552
  if (!hasReplacement(tag))
550
553
  return;
551
- debug(`${tag} has replacement properties`);
554
+ debug$1(`${tag} has replacement properties`);
552
555
  const propName = getPropName(node);
553
556
  const propNameNode = node.directive ? node.key.argument : node.key;
554
557
  if (!propName || !propNameNode) {
555
- debug("could not get prop name and/or node");
558
+ debug$1("could not get prop name and/or node");
556
559
  return;
557
560
  }
558
561
  Object.entries(replacements[tag]).forEach(([prop, replacement]) => {
559
562
  if (kebabCase(prop) === propName) {
560
- debug(`preparing a replacement for ${tag}:${propName} -> ${replacement}`);
563
+ debug$1(`preparing a replacement for ${tag}:${propName} -> ${replacement}`);
561
564
  context.report({
562
565
  data: {
563
566
  prop,
@@ -586,10 +589,10 @@ const noDeprecatedProps = createEslintRule({
586
589
  schema: [],
587
590
  type: "problem"
588
591
  },
589
- name: RULE_NAME$1
592
+ name: RULE_NAME$2
590
593
  });
591
594
 
592
- const RULE_NAME = "no-legacy-library-import";
595
+ const RULE_NAME$1 = "no-legacy-library-import";
593
596
  const legacyLibrary = "@rotki/ui-library-compat";
594
597
  const newLibrary = "@rotki/ui-library";
595
598
  const noLegacyLibraryImport = createEslintRule({
@@ -621,6 +624,105 @@ const noLegacyLibraryImport = createEslintRule({
621
624
  schema: [],
622
625
  type: "problem"
623
626
  },
627
+ name: RULE_NAME$1
628
+ });
629
+
630
+ const debug = createDebug("@rotki/eslint-plugin:consistent-ref-type-annotation");
631
+ const RULE_NAME = "consistent-ref-type-annotation";
632
+ const FIXABLE_METHODS = ["ref", "computed"];
633
+ function checkAssignmentDeclaration(context, node, declaration, options) {
634
+ const source = getSourceCode(context);
635
+ const { allowInference } = options;
636
+ let declarationTypeArguments;
637
+ const init = declaration.init;
638
+ if (!(init && init.type === TSESTree.AST_NODE_TYPES.CallExpression))
639
+ return;
640
+ const callee = init.callee;
641
+ if (!(callee && callee.type === TSESTree.AST_NODE_TYPES.Identifier))
642
+ return;
643
+ if (!Array.prototype.includes.call(FIXABLE_METHODS, callee.name))
644
+ return;
645
+ const name = callee.name;
646
+ debug(`found ${name}, checking type arguments`);
647
+ const initializationTypeArguments = init.typeArguments;
648
+ const typeAnnotation = declaration.id.typeAnnotation;
649
+ if (typeAnnotation) {
650
+ const typeNode = typeAnnotation.typeAnnotation;
651
+ if (typeNode && typeNode.type === TSESTree.AST_NODE_TYPES.TSTypeReference)
652
+ declarationTypeArguments = typeNode.typeArguments;
653
+ }
654
+ if (initializationTypeArguments && !declarationTypeArguments)
655
+ return;
656
+ debug(`generating report for ${name}`);
657
+ if (!initializationTypeArguments && !declarationTypeArguments) {
658
+ if (allowInference) {
659
+ debug("type inference is allowed");
660
+ } else {
661
+ context.report({
662
+ data: {
663
+ name
664
+ },
665
+ messageId: "missingType",
666
+ node
667
+ });
668
+ }
669
+ return;
670
+ }
671
+ context.report({
672
+ data: {
673
+ name
674
+ },
675
+ fix(fixer) {
676
+ const fixes = [];
677
+ if (!initializationTypeArguments && callee)
678
+ fixes.push(fixer.insertTextAfter(callee, source.getText(declarationTypeArguments)));
679
+ if (typeAnnotation)
680
+ fixes.push(fixer.remove(typeAnnotation));
681
+ return fixes;
682
+ },
683
+ messageId: "inconsistent",
684
+ node
685
+ });
686
+ }
687
+ const consistentRefTypeAnnotation = createEslintRule({
688
+ create(context, optionsWithDefault) {
689
+ const options = optionsWithDefault[0] || {};
690
+ const allowInference = options.allowInference;
691
+ return {
692
+ VariableDeclaration: (node) => {
693
+ const declarations = node.declarations;
694
+ for (const declaration of declarations) {
695
+ if (declaration.type !== TSESTree.AST_NODE_TYPES.VariableDeclarator)
696
+ continue;
697
+ checkAssignmentDeclaration(context, node, declaration, { allowInference });
698
+ }
699
+ }
700
+ };
701
+ },
702
+ defaultOptions: [{ allowInference: false }],
703
+ meta: {
704
+ docs: {
705
+ description: "Ensures consistent type annotation position for ref, computed assignments",
706
+ recommended: "recommended"
707
+ },
708
+ fixable: "code",
709
+ messages: {
710
+ inconsistent: `Generic type annotation for the {{ name }} call was not on the right side`,
711
+ missingType: `variable assignment for {{ name }} is missing the type annotation`
712
+ },
713
+ schema: [
714
+ {
715
+ additionalProperties: false,
716
+ properties: {
717
+ allowInference: {
718
+ type: "boolean"
719
+ }
720
+ },
721
+ type: "object"
722
+ }
723
+ ],
724
+ type: "problem"
725
+ },
624
726
  name: RULE_NAME
625
727
  });
626
728
 
@@ -630,6 +732,7 @@ const plugin = {
630
732
  version: pkg.version
631
733
  },
632
734
  rules: {
735
+ "consistent-ref-type-annotation": consistentRefTypeAnnotation,
633
736
  "no-deprecated-classes": noDeprecatedClasses,
634
737
  "no-deprecated-components": noDeprecatedComponents,
635
738
  "no-deprecated-props": noDeprecatedProps,
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "@rotki/eslint-plugin",
3
- "version": "0.3.2",
4
- "packageManager": "pnpm@8.15.0",
3
+ "version": "0.4.0",
5
4
  "type": "module",
6
5
  "license": "AGPL-3.0",
7
6
  "bugs": {
@@ -30,40 +29,40 @@
30
29
  "eslint": "^8.0.0 || ^9.0.0"
31
30
  },
32
31
  "dependencies": {
33
- "@typescript-eslint/utils": "6.19.1",
34
- "debug": "4.3.4",
35
- "eslint-compat-utils": "0.4.1",
32
+ "@typescript-eslint/utils": "7.15.0",
33
+ "debug": "4.3.5",
34
+ "eslint-compat-utils": "0.5.1",
36
35
  "jsonc-eslint-parser": "2.4.0",
37
- "scule": "1.2.0",
38
- "vue-eslint-parser": "9.4.2",
39
- "yaml-eslint-parser": "1.2.2"
36
+ "scule": "1.3.0",
37
+ "vue-eslint-parser": "9.4.3",
38
+ "yaml-eslint-parser": "1.2.3"
40
39
  },
41
40
  "devDependencies": {
42
- "@commitlint/cli": "18.6.0",
43
- "@commitlint/config-conventional": "18.6.0",
44
- "@rotki/eslint-config": "2.4.4",
41
+ "@commitlint/cli": "19.3.0",
42
+ "@commitlint/config-conventional": "19.2.2",
43
+ "@rotki/eslint-config": "2.9.0",
45
44
  "@types/debug": "4.1.12",
46
- "@types/eslint": "8.56.2",
45
+ "@types/eslint": "8.56.10",
47
46
  "@types/node": "20",
48
- "@typescript-eslint/eslint-plugin": "6.19.1",
49
- "@typescript-eslint/parser": "6.19.1",
50
- "@typescript-eslint/rule-tester": "6.19.1",
51
- "@vitest/coverage-v8": "^1.2.2",
52
- "bumpp": "9.3.0",
53
- "debug": "4.3.4",
54
- "eslint": "8.56.0",
55
- "husky": "9.0.7",
56
- "lint-staged": "15.2.0",
57
- "rimraf": "5.0.5",
47
+ "@typescript-eslint/eslint-plugin": "7.15.0",
48
+ "@typescript-eslint/parser": "7.15.0",
49
+ "@typescript-eslint/rule-tester": "7.15.0",
50
+ "@vitest/coverage-v8": "1.6.0",
51
+ "bumpp": "9.4.1",
52
+ "debug": "4.3.5",
53
+ "eslint": "8.57.0",
54
+ "husky": "9.0.11",
55
+ "lint-staged": "15.2.7",
56
+ "rimraf": "5.0.8",
58
57
  "ts-node": "10.9.2",
59
- "typescript": "5.3.3",
58
+ "typescript": "5.5.3",
60
59
  "unbuild": "2.0.0",
61
- "vitepress": "1.0.0-rc.40",
62
- "vitest": "1.2.2"
60
+ "vitepress": "1.2.3",
61
+ "vitest": "1.6.0"
63
62
  },
64
63
  "engines": {
65
64
  "node": ">=20",
66
- "pnpm": ">=8 <9"
65
+ "pnpm": ">=9 <10"
67
66
  },
68
67
  "lint-staged": {
69
68
  "*.{js,cjs,ts,vue,yml,json,md}": "eslint"