eslint-plugin-vuetify 2.0.0-beta.0 → 2.0.0-beta.2

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
@@ -42,6 +42,7 @@ These rules will help you avoid deprecated components, props, and classes. They
42
42
 
43
43
  - Prevent the use of components that have been removed from Vuetify ([`no-deprecated-components`])
44
44
  - Prevent the use of props that have been removed from Vuetify ([`no-deprecated-props`])
45
+ - Prevent the use of events that have been removed from Vuetify ([`no-deprecated-events`])
45
46
  - Prevent the use of classes that have been removed from Vuetify ([`no-deprecated-classes`])
46
47
  - Prevent the use of the old theme class syntax ([`no-deprecated-colors`])
47
48
 
@@ -55,6 +56,7 @@ These rules are designed to help migrate to the new grid system in Vuetify v2. T
55
56
  [`grid-unknown-attributes`]: ./docs/rules/grid-unknown-attributes.md
56
57
  [`no-deprecated-components`]: ./docs/rules/no-deprecated-components.md
57
58
  [`no-deprecated-props`]: ./docs/rules/no-deprecated-props.md
59
+ [`no-deprecated-events`]: ./docs/rules/no-deprecated-events.md
58
60
  [`no-deprecated-classes`]: ./docs/rules/no-deprecated-classes.md
59
61
  [`no-deprecated-colors`]: ./docs/rules/no-deprecated-colors.md
60
62
 
@@ -9,6 +9,7 @@ module.exports = {
9
9
  'vuetify/no-deprecated-classes': 'error',
10
10
  'vuetify/no-deprecated-colors': 'error',
11
11
  'vuetify/no-deprecated-components': 'error',
12
+ 'vuetify/no-deprecated-events': 'error',
12
13
  'vuetify/no-deprecated-props': 'error'
13
14
  }
14
15
  };
@@ -14,7 +14,7 @@ const {
14
14
  } = require('../util/fixers');
15
15
  const {
16
16
  components
17
- } = require('vuetify');
17
+ } = require('vuetify/dist/vuetify.js');
18
18
  const VGrid = {
19
19
  VContainer: components.VContainer,
20
20
  VRow: components.VRow,
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  /** @type {Map<RegExp, (args: string[]) => string> | Map<string, string>} */
4
- const replacements = new Map([[/^rounded-(r|l|tr|tl|br|bl)(.*)$/, ([side, rest]) => {
4
+ const replacements = new Map([[/^rounded-(r|l|tr|tl|br|bl)(-.*)?$/, ([side, rest]) => {
5
5
  side = {
6
6
  r: 'e',
7
7
  l: 's',
@@ -10,7 +10,7 @@ const replacements = new Map([[/^rounded-(r|l|tr|tl|br|bl)(.*)$/, ([side, rest])
10
10
  br: 'be',
11
11
  bl: 'bs'
12
12
  }[side];
13
- return `rounded-${side}${rest}`;
13
+ return `rounded-${side}${rest || ''}`;
14
14
  }], [/^border-([rl])(.*)$/, ([side, rest]) => {
15
15
  side = {
16
16
  r: 'e',
@@ -26,6 +26,7 @@ const replacements = {
26
26
  VDataIterator: false,
27
27
  VDataTable: false,
28
28
  VDatePicker: false,
29
+ VListItemGroup: false,
29
30
  VOtpInput: false,
30
31
  VOverflowBtn: false,
31
32
  VPicker: false,
@@ -0,0 +1,209 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ hyphenate,
5
+ classify
6
+ } = require('../util/helpers');
7
+ const model = {
8
+ input: 'update:modelValue'
9
+ };
10
+ const inputs = {
11
+ ...model,
12
+ 'click:appendOuter': 'click:append',
13
+ 'update:error': false
14
+ };
15
+ const combobox = {
16
+ ...inputs,
17
+ 'update:searchInput': 'update:search',
18
+ 'update:listIndex': false
19
+ };
20
+ const replacements = {
21
+ VTextField: inputs,
22
+ VTextarea: inputs,
23
+ VFileInput: inputs,
24
+ VCombobox: {
25
+ ...combobox,
26
+ change: false
27
+ },
28
+ VAutocomplete: {
29
+ ...combobox,
30
+ change: 'update:modelValue'
31
+ },
32
+ VSelect: {
33
+ ...combobox,
34
+ change: 'update:modelValue'
35
+ },
36
+ VAlert: model,
37
+ VTabs: {
38
+ ...model,
39
+ 'call:slider': false,
40
+ change: 'update:modelValue',
41
+ next: false,
42
+ prev: false
43
+ },
44
+ VTab: {
45
+ change: 'group:selected'
46
+ },
47
+ VBottomNavigation: {
48
+ change: 'update:modelValue',
49
+ 'update:inputValue': false
50
+ },
51
+ VBtn: {
52
+ change: 'group:selected'
53
+ },
54
+ VBtnToggle: {
55
+ change: 'update:modelValue'
56
+ },
57
+ VCarousel: {
58
+ change: 'update:modelValue'
59
+ },
60
+ VCheckbox: {
61
+ change: 'update:modelValue',
62
+ 'update:error': false
63
+ },
64
+ VChip: {
65
+ ...model,
66
+ 'update:active': 'update:modelValue'
67
+ },
68
+ VChipGroup: {
69
+ change: 'update:modelValue'
70
+ },
71
+ VColorPicker: {
72
+ ...model,
73
+ 'update:color': 'update:modelValue'
74
+ },
75
+ VDialog: {
76
+ ...model,
77
+ 'update:returnValue': false
78
+ },
79
+ VExpansionPanels: {
80
+ change: 'update:modelValue'
81
+ },
82
+ VExpansionPanel: {
83
+ change: 'group:selected'
84
+ },
85
+ VForm: {
86
+ input: 'update:modelValue'
87
+ },
88
+ VHover: model,
89
+ VItemGroup: {
90
+ change: 'update:modelValue'
91
+ },
92
+ VMenu: {
93
+ ...model,
94
+ 'update:returnValue': false
95
+ },
96
+ VNavigationDrawer: {
97
+ ...model,
98
+ 'update:miniVariant': false
99
+ },
100
+ VPagination: {
101
+ ...model,
102
+ previous: 'prev'
103
+ },
104
+ VProgressLinear: {
105
+ change: 'update:modelValue'
106
+ },
107
+ VRadioGroup: {
108
+ change: 'update:modelValue',
109
+ 'update:error': false
110
+ },
111
+ VRadio: {
112
+ change: 'update:modelValue',
113
+ 'update:error': false
114
+ },
115
+ VRangeSlider: {
116
+ ...model,
117
+ change: false,
118
+ 'update:error': false,
119
+ start: false,
120
+ end: false
121
+ },
122
+ VRating: model,
123
+ VSlider: {
124
+ ...model,
125
+ change: false,
126
+ 'update:error': false,
127
+ start: false,
128
+ end: false
129
+ },
130
+ VSlideGroup: {
131
+ change: 'update:modelValue',
132
+ next: false,
133
+ prev: false
134
+ },
135
+ VSnackbar: model,
136
+ VSwitch: {
137
+ change: 'update:modelValue',
138
+ 'update:error': false
139
+ },
140
+ VWindow: {
141
+ change: 'update:modelValue'
142
+ }
143
+ };
144
+
145
+ // ------------------------------------------------------------------------------
146
+ // Rule Definition
147
+ // ------------------------------------------------------------------------------
148
+
149
+ module.exports = {
150
+ meta: {
151
+ docs: {
152
+ description: 'Prevent the use of removed and deprecated events.',
153
+ category: 'recommended'
154
+ },
155
+ fixable: 'code',
156
+ schema: [],
157
+ messages: {
158
+ replacedWith: `{{ tag }}: @{{ a }} has been replaced with @{{ b }}`,
159
+ removed: `{{ tag }}: @{{ name }} has been removed`
160
+ }
161
+ },
162
+ create(context) {
163
+ return context.parserServices.defineTemplateBodyVisitor({
164
+ VAttribute(attr) {
165
+ if (!(attr.directive && attr.key.name.name === 'on' && attr.key.argument?.type === 'VIdentifier')) return;
166
+ const tag = classify(attr.parent.parent.rawName);
167
+ if (!Object.keys(replacements).includes(tag)) return;
168
+ const eventNameNode = attr.key.argument;
169
+ const eventName = hyphenate(eventNameNode.rawName);
170
+ Object.entries(replacements[tag]).forEach(([test, replace]) => {
171
+ if (hyphenate(test) === eventName) {
172
+ if (replace === false) {
173
+ context.report({
174
+ messageId: 'removed',
175
+ data: {
176
+ tag,
177
+ name: eventName
178
+ },
179
+ node: eventNameNode
180
+ });
181
+ } else if (typeof replace === 'string') {
182
+ context.report({
183
+ messageId: 'replacedWith',
184
+ data: {
185
+ tag,
186
+ a: eventName,
187
+ b: replace
188
+ },
189
+ node: eventNameNode,
190
+ fix(fixer) {
191
+ return fixer.replaceText(eventNameNode, hyphenate(replace));
192
+ }
193
+ });
194
+ } else if (typeof replace === 'object' && 'custom' in replace) {
195
+ context.report({
196
+ messageId: 'replacedWith',
197
+ data: {
198
+ a: eventName,
199
+ b: replace.custom
200
+ },
201
+ node: eventNameNode
202
+ });
203
+ }
204
+ }
205
+ });
206
+ }
207
+ });
208
+ }
209
+ };
@@ -107,13 +107,11 @@ const link = {
107
107
  const overlay = {
108
108
  hideOverlay: {
109
109
  name: 'scrim',
110
+ bind: true,
110
111
  value: false
111
112
  },
112
113
  internalActivator: false,
113
- overlayColor: {
114
- name: 'scrim',
115
- value: value => value
116
- },
114
+ overlayColor: 'scrim',
117
115
  overlayOpacity: false,
118
116
  value: 'model-value',
119
117
  returnValue: false
@@ -148,7 +146,7 @@ const replacements = {
148
146
  value: value => ({
149
147
  right: 'end',
150
148
  left: 'start'
151
- })[value]
149
+ })[value] || value
152
150
  },
153
151
  outline: {
154
152
  name: 'variant',
@@ -202,10 +200,11 @@ const replacements = {
202
200
  app: false,
203
201
  fixed: false,
204
202
  hideOnScroll: false,
205
- inputValue: 'model-value',
203
+ inputValue: false,
206
204
  scrollTarget: false,
207
205
  scrollThreshold: false,
208
206
  width: false,
207
+ value: 'model-value',
209
208
  ...size
210
209
  },
211
210
  VBreadcrumbs: {
@@ -225,7 +224,7 @@ const replacements = {
225
224
  },
226
225
  depressed: {
227
226
  name: 'variant',
228
- value: 'depressed'
227
+ value: 'flat'
229
228
  },
230
229
  fab: false,
231
230
  flat: {
@@ -354,7 +353,7 @@ const replacements = {
354
353
  },
355
354
  VChip: {
356
355
  active: false,
357
- close: 'cloasable',
356
+ close: 'closable',
358
357
  inputValue: 'model-value',
359
358
  outline: {
360
359
  name: 'variant',
@@ -420,14 +419,17 @@ const replacements = {
420
419
  allowOverflow: false,
421
420
  auto: false,
422
421
  bottom: {
423
- custom: 'location and origin'
422
+ name: 'location',
423
+ value: 'bottom'
424
424
  },
425
425
  closeOnClick: {
426
426
  name: 'persistent',
427
- value: true
427
+ bind: true,
428
+ value: value => value ? `!(${value})` : false
428
429
  },
429
430
  left: {
430
- custom: 'location and origin'
431
+ name: 'location',
432
+ value: 'left'
431
433
  },
432
434
  nudgeBottom: {
433
435
  custom: 'offset'
@@ -447,12 +449,14 @@ const replacements = {
447
449
  positionX: false,
448
450
  positionY: false,
449
451
  right: {
450
- custom: 'location and origin'
452
+ name: 'location',
453
+ value: 'right'
451
454
  },
452
455
  rounded: false,
453
456
  tile: false,
454
457
  top: {
455
- custom: 'location and origin'
458
+ name: 'location',
459
+ value: 'top'
456
460
  },
457
461
  value: 'model-value',
458
462
  ...overlay
@@ -476,7 +480,8 @@ const replacements = {
476
480
  dense: false,
477
481
  disabled: false,
478
482
  left: 'start',
479
- right: 'end'
483
+ right: 'end',
484
+ ...sizes
480
485
  },
481
486
  VImg: {
482
487
  contain: {
@@ -553,15 +558,13 @@ const replacements = {
553
558
  height: false,
554
559
  hideOverlay: {
555
560
  name: 'scrim',
561
+ bind: true,
556
562
  value: false
557
563
  },
558
564
  miniVariant: 'rail',
559
565
  miniVariantWidth: 'rail-width',
560
566
  mobileBreakPoint: false,
561
- overlayColor: {
562
- name: 'scrim',
563
- value: value => value
564
- },
567
+ overlayColor: 'scrim',
565
568
  overlayOpacity: false,
566
569
  right: {
567
570
  name: 'location',
@@ -572,10 +575,7 @@ const replacements = {
572
575
  value: 'model-value'
573
576
  },
574
577
  VOverlay: {
575
- color: {
576
- name: 'scrim',
577
- value: value => value
578
- },
578
+ color: 'scrim',
579
579
  opacity: false,
580
580
  value: 'model-value'
581
581
  },
@@ -599,6 +599,7 @@ const replacements = {
599
599
  value: 'model-value'
600
600
  },
601
601
  VRadio: {
602
+ inputValue: 'model-value',
602
603
  activeClass: 'false',
603
604
  offIcon: 'false-icon',
604
605
  onIcon: 'true-icon',
@@ -698,7 +699,8 @@ const replacements = {
698
699
  value: 'model-value'
699
700
  },
700
701
  VSwitch: {
701
- ...inputs
702
+ ...inputs,
703
+ value: undefined
702
704
  },
703
705
  VSystemBar: {
704
706
  app: false,
@@ -754,14 +756,16 @@ const replacements = {
754
756
  VTooltip: {
755
757
  allowOverflow: false,
756
758
  bottom: {
757
- custom: 'location and origin'
759
+ name: 'location',
760
+ value: 'bottom'
758
761
  },
759
762
  closeOnClick: {
760
763
  name: 'persistent',
761
764
  value: true
762
765
  },
763
766
  left: {
764
- custom: 'location and origin'
767
+ name: 'location',
768
+ value: 'left'
765
769
  },
766
770
  nudgeBottom: {
767
771
  custom: 'offset'
@@ -778,10 +782,12 @@ const replacements = {
778
782
  positionX: false,
779
783
  positionY: false,
780
784
  right: {
781
- custom: 'location and origin'
785
+ name: 'location',
786
+ value: 'right'
782
787
  },
783
788
  top: {
784
- custom: 'location and origin'
789
+ name: 'location',
790
+ value: 'top'
785
791
  },
786
792
  value: 'model-value',
787
793
  ...overlay
@@ -826,7 +832,7 @@ module.exports = {
826
832
  const tag = classify(attr.parent.parent.rawName);
827
833
  if (!Object.keys(replacements).includes(tag)) return;
828
834
  const propName = attr.directive ? hyphenate(attr.key.argument.rawName) : hyphenate(attr.key.rawName);
829
- const propNameNode = attr.directive ? attr.key.argument : attr;
835
+ const propNameNode = attr.directive ? attr.key.argument : attr.key;
830
836
  Object.entries(replacements[tag]).forEach(([test, replace]) => {
831
837
  if (hyphenate(test) === propName) {
832
838
  if (replace === false) {
@@ -850,7 +856,7 @@ module.exports = {
850
856
  }
851
857
  });
852
858
  } else if (typeof replace === 'object' && 'name' in replace && 'value' in replace) {
853
- const value = typeof replace.value === 'function' ? replace.value(attr.value?.value) : replace.value;
859
+ const value = typeof replace.value === 'function' ? replace.value(attr.directive ? context.getSourceCode().getText(attr.value.expression) : attr.value?.value) : replace.value;
854
860
  if (value == null) return;
855
861
  context.report({
856
862
  messageId: 'replacedWith',
@@ -861,10 +867,17 @@ module.exports = {
861
867
  node: propNameNode,
862
868
  fix(fixer) {
863
869
  if (attr.directive) {
864
- const expression = attr.value.expression.raw;
865
- return [fixer.replaceText(propNameNode, replace.name), fixer.replaceText(attr.value, `"${expression} && '${value}'"`)];
870
+ if (replace.bind) {
871
+ if (value === 'true' || value === '!(false)') {
872
+ return fixer.replaceText(attr, replace.name);
873
+ }
874
+ return [fixer.replaceText(propNameNode, replace.name), fixer.replaceText(attr.value, `"${value}"`)];
875
+ } else {
876
+ const expression = context.getSourceCode().getText(attr.value.expression);
877
+ return [fixer.replaceText(propNameNode, replace.name), fixer.replaceText(attr.value, `"${expression} && '${value}'"`)];
878
+ }
866
879
  } else {
867
- return fixer.replaceText(attr, `${replace.name}="${value}"`);
880
+ return fixer.replaceText(attr, `${replace.bind ? ':' : ''}${replace.name}="${value}"`);
868
881
  }
869
882
  }
870
883
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-vuetify",
3
- "version": "2.0.0-beta.0",
3
+ "version": "2.0.0-beta.2",
4
4
  "description": "An eslint plugin for Vuetify",
5
5
  "main": "lib/index.js",
6
6
  "author": "Kael Watts-Deuchar <kaelwd@gmail.com>",
@@ -36,7 +36,7 @@
36
36
  "nyc": "^15.1.0",
37
37
  "rimraf": "^3.0.2",
38
38
  "vue": "^3.2.41",
39
- "vuetify": "^3.0.0-beta.15"
39
+ "vuetify": "^3.0.0"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "eslint": "^8.0.0",