eslint-plugin-vuetify 2.4.0 → 2.5.1
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 +16 -3
- package/lib/configs/flat/base.js +11 -0
- package/lib/configs/flat/recommended.js +10 -0
- package/lib/index.js +6 -1
- package/lib/rules/grid-unknown-attributes.js +4 -2
- package/lib/rules/icon-button-variant.js +4 -2
- package/lib/rules/no-deprecated-classes.js +8 -4
- package/lib/rules/no-deprecated-colors.js +5 -1
- package/lib/rules/no-deprecated-components.js +6 -5
- package/lib/rules/no-deprecated-events.js +4 -2
- package/lib/rules/no-deprecated-props.js +8 -5
- package/lib/rules/no-deprecated-slots.js +5 -3
- package/lib/util/fixers.js +2 -2
- package/lib/util/helpers.js +10 -2
- package/package.json +12 -10
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ This package is for migrating from Vuetify v2 to v3, use [eslint-plugin-vuetify@
|
|
|
15
15
|
|
|
16
16
|
## 💿 Install
|
|
17
17
|
|
|
18
|
-
You should have [`eslint`](https://eslint.org/docs/
|
|
18
|
+
You should have [`eslint`](https://eslint.org/docs/latest/use/getting-started) and [`eslint-plugin-vue`](https://eslint.vuejs.org/user-guide/#installation) set up first.
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
21
|
yarn add eslint-plugin-vuetify -D
|
|
@@ -23,6 +23,19 @@ yarn add eslint-plugin-vuetify -D
|
|
|
23
23
|
npm install eslint-plugin-vuetify --save-dev
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
```js
|
|
27
|
+
// eslint.config.js
|
|
28
|
+
import vue from 'eslint-plugin-vue'
|
|
29
|
+
import vuetify from 'eslint-plugin-vuetify'
|
|
30
|
+
|
|
31
|
+
export default [
|
|
32
|
+
...vue.configs['flat/base'],
|
|
33
|
+
...vuetify.configs['flat/base'],
|
|
34
|
+
]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Eslint 8 can alternatively use the older configuration format:
|
|
38
|
+
|
|
26
39
|
```js
|
|
27
40
|
// .eslintrc.js
|
|
28
41
|
module.exports = {
|
|
@@ -40,7 +53,7 @@ module.exports = {
|
|
|
40
53
|
|
|
41
54
|
### Deprecations
|
|
42
55
|
|
|
43
|
-
These rules will help you avoid deprecated components, props, and classes. They are included in the `
|
|
56
|
+
These rules will help you avoid deprecated components, props, and classes. They are included in the `base` preset.
|
|
44
57
|
|
|
45
58
|
- Prevent the use of components that have been removed from Vuetify ([`no-deprecated-components`])
|
|
46
59
|
- Prevent the use of props that have been removed from Vuetify ([`no-deprecated-props`])
|
|
@@ -52,7 +65,7 @@ These rules will help you avoid deprecated components, props, and classes. They
|
|
|
52
65
|
|
|
53
66
|
### Grid system
|
|
54
67
|
|
|
55
|
-
These rules are designed to help migrate to the new grid system in Vuetify v2. They are included in the `
|
|
68
|
+
These rules are designed to help migrate to the new grid system in Vuetify v2. They are included in the `recommended` preset.
|
|
56
69
|
|
|
57
70
|
- Warn about unknown attributes not being converted to classes on new grid components ([`grid-unknown-attributes`])
|
|
58
71
|
|
package/lib/index.js
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const requireindex = require('requireindex');
|
|
5
5
|
module.exports = {
|
|
6
|
-
configs:
|
|
6
|
+
configs: {
|
|
7
|
+
base: require('./configs/base'),
|
|
8
|
+
recommended: require('./configs/recommended'),
|
|
9
|
+
'flat/base': require('./configs/flat/base'),
|
|
10
|
+
'flat/recommended': require('./configs/flat/recommended')
|
|
11
|
+
},
|
|
7
12
|
rules: requireindex(path.join(__dirname, './rules'))
|
|
8
13
|
};
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
const {
|
|
4
4
|
hyphenate,
|
|
5
5
|
classify,
|
|
6
|
-
getAttributes
|
|
6
|
+
getAttributes,
|
|
7
|
+
isVueTemplate
|
|
7
8
|
} = require('../util/helpers');
|
|
8
9
|
const {
|
|
9
10
|
isGridAttribute
|
|
@@ -39,7 +40,8 @@ module.exports = {
|
|
|
39
40
|
schema: []
|
|
40
41
|
},
|
|
41
42
|
create(context) {
|
|
42
|
-
return
|
|
43
|
+
if (!isVueTemplate(context)) return {};
|
|
44
|
+
return context.sourceCode.parserServices.defineTemplateBodyVisitor({
|
|
43
45
|
VElement(element) {
|
|
44
46
|
const tag = classify(element.rawName);
|
|
45
47
|
if (!Object.keys(tags).includes(tag)) return;
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
4
|
classify,
|
|
5
|
-
getAttributes
|
|
5
|
+
getAttributes,
|
|
6
|
+
isVueTemplate
|
|
6
7
|
} = require('../util/helpers');
|
|
7
8
|
|
|
8
9
|
// ------------------------------------------------------------------------------
|
|
@@ -24,7 +25,8 @@ module.exports = {
|
|
|
24
25
|
}
|
|
25
26
|
},
|
|
26
27
|
create(context) {
|
|
27
|
-
return
|
|
28
|
+
if (!isVueTemplate(context)) return {};
|
|
29
|
+
return context.sourceCode.parserServices.defineTemplateBodyVisitor({
|
|
28
30
|
VElement(element) {
|
|
29
31
|
const tag = classify(element.rawName);
|
|
30
32
|
if (tag !== 'VBtn') return;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const {
|
|
4
|
+
isVueTemplate
|
|
5
|
+
} = require('../util/helpers');
|
|
6
|
+
|
|
3
7
|
/** @type {Map<RegExp, ((args: string[]) => string | false) | false> | Map<string, string | false>} */
|
|
4
8
|
const replacements = new Map([[/^rounded-(r|l|tr|tl|br|bl)(-.*)?$/, ([side, rest]) => {
|
|
5
9
|
side = {
|
|
@@ -30,11 +34,11 @@ module.exports = {
|
|
|
30
34
|
}
|
|
31
35
|
},
|
|
32
36
|
create(context) {
|
|
33
|
-
return
|
|
37
|
+
if (!isVueTemplate(context)) return {};
|
|
38
|
+
return context.sourceCode.parserServices.defineTemplateBodyVisitor({
|
|
34
39
|
'VAttribute[key.name="class"]'(node) {
|
|
35
40
|
if (!node.value || !node.value.value) return;
|
|
36
41
|
const classes = node.value.value.split(/\s+/).filter(s => !!s);
|
|
37
|
-
const source = context.getSourceCode();
|
|
38
42
|
const changed = [];
|
|
39
43
|
classes.forEach(className => {
|
|
40
44
|
for (const replacer of replacements) {
|
|
@@ -58,8 +62,8 @@ module.exports = {
|
|
|
58
62
|
const idx = node.value.value.indexOf(change[0]) + 1;
|
|
59
63
|
const range = [node.value.range[0] + idx, node.value.range[0] + idx + change[0].length];
|
|
60
64
|
const loc = {
|
|
61
|
-
start:
|
|
62
|
-
end:
|
|
65
|
+
start: context.sourceCode.getLocFromIndex(range[0]),
|
|
66
|
+
end: context.sourceCode.getLocFromIndex(range[1])
|
|
63
67
|
};
|
|
64
68
|
if (change[1]) {
|
|
65
69
|
context.report({
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const {
|
|
4
|
+
isVueTemplate
|
|
5
|
+
} = require('../util/helpers');
|
|
3
6
|
const cssColors = ['red', 'pink', 'purple', 'deep-purple', 'indigo', 'blue', 'light-blue', 'cyan', 'teal', 'green', 'light-green', 'lime', 'yellow', 'amber', 'orange', 'deep-orange', 'brown', 'blue-grey', 'grey', 'black', 'white', 'transparent'];
|
|
4
7
|
const cssTextColors = cssColors.map(v => `${v}--text`);
|
|
5
8
|
const variants = ['lighten-1', 'lighten-2', 'lighten-3', 'lighten-4', 'lighten-5', 'darken-1', 'darken-2', 'darken-3', 'darken-4', 'accent-1', 'accent-2', 'accent-3', 'accent-4'];
|
|
@@ -33,6 +36,7 @@ module.exports = {
|
|
|
33
36
|
}
|
|
34
37
|
},
|
|
35
38
|
create(context) {
|
|
39
|
+
if (!isVueTemplate(context)) return {};
|
|
36
40
|
const themeColors = ['primary', 'secondary', 'accent', 'error', 'warning', 'info', 'success', ...(context.options[0]?.themeColors || [])];
|
|
37
41
|
const themeTextColors = themeColors.map(v => `${v}--text`);
|
|
38
42
|
function findColor(classes) {
|
|
@@ -45,7 +49,7 @@ module.exports = {
|
|
|
45
49
|
const variant = classes.findIndex(t => textVariants.includes(t));
|
|
46
50
|
return [base, variant];
|
|
47
51
|
}
|
|
48
|
-
return context.parserServices.defineTemplateBodyVisitor({
|
|
52
|
+
return context.sourceCode.parserServices.defineTemplateBodyVisitor({
|
|
49
53
|
'VAttribute[key.name="color"]'(node) {
|
|
50
54
|
if (!node.value || !node.value.value) return;
|
|
51
55
|
const color = node.value.value.split(/\s+/).filter(s => !!s);
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
4
|
hyphenate,
|
|
5
|
-
classify
|
|
5
|
+
classify,
|
|
6
|
+
isVueTemplate
|
|
6
7
|
} = require('../util/helpers');
|
|
7
8
|
const replacements = {
|
|
8
9
|
VListTile: 'v-list-item',
|
|
@@ -38,8 +39,7 @@ const replacements = {
|
|
|
38
39
|
VSimpleTable: 'v-table',
|
|
39
40
|
VTabsSlider: false,
|
|
40
41
|
VTabsItems: false,
|
|
41
|
-
VTabItem: false
|
|
42
|
-
VTimePicker: false
|
|
42
|
+
VTabItem: false
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
// ------------------------------------------------------------------------------
|
|
@@ -61,10 +61,11 @@ module.exports = {
|
|
|
61
61
|
}
|
|
62
62
|
},
|
|
63
63
|
create(context) {
|
|
64
|
-
return
|
|
64
|
+
if (!isVueTemplate(context)) return {};
|
|
65
|
+
return context.sourceCode.parserServices.defineTemplateBodyVisitor({
|
|
65
66
|
VElement(element) {
|
|
66
67
|
const tag = classify(element.rawName);
|
|
67
|
-
const tokens = context.parserServices.getTemplateBodyTokenStore();
|
|
68
|
+
const tokens = context.sourceCode.parserServices.getTemplateBodyTokenStore();
|
|
68
69
|
if (Object.prototype.hasOwnProperty.call(replacements, tag)) {
|
|
69
70
|
const replacement = replacements[tag];
|
|
70
71
|
if (typeof replacement === 'object' && 'custom' in replacement) {
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
4
|
hyphenate,
|
|
5
|
-
classify
|
|
5
|
+
classify,
|
|
6
|
+
isVueTemplate
|
|
6
7
|
} = require('../util/helpers');
|
|
7
8
|
const model = {
|
|
8
9
|
input: 'update:modelValue'
|
|
@@ -156,7 +157,8 @@ module.exports = {
|
|
|
156
157
|
}
|
|
157
158
|
},
|
|
158
159
|
create(context) {
|
|
159
|
-
return
|
|
160
|
+
if (!isVueTemplate(context)) return {};
|
|
161
|
+
return context.sourceCode.parserServices.defineTemplateBodyVisitor({
|
|
160
162
|
VAttribute(attr) {
|
|
161
163
|
if (!(attr.directive && attr.key.name.name === 'on' && attr.key.argument?.type === 'VIdentifier')) return;
|
|
162
164
|
const tag = classify(attr.parent.parent.rawName);
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
4
|
hyphenate,
|
|
5
|
-
classify
|
|
5
|
+
classify,
|
|
6
|
+
isVueTemplate
|
|
6
7
|
} = require('../util/helpers');
|
|
7
8
|
const size = {
|
|
8
9
|
maxHeight: false,
|
|
@@ -539,7 +540,8 @@ const replacements = {
|
|
|
539
540
|
...size
|
|
540
541
|
},
|
|
541
542
|
VForm: {
|
|
542
|
-
value: 'model-value'
|
|
543
|
+
value: 'model-value',
|
|
544
|
+
lazyValidation: false
|
|
543
545
|
},
|
|
544
546
|
VHover: {
|
|
545
547
|
value: 'model-value'
|
|
@@ -937,7 +939,8 @@ module.exports = {
|
|
|
937
939
|
}
|
|
938
940
|
},
|
|
939
941
|
create(context) {
|
|
940
|
-
return
|
|
942
|
+
if (!isVueTemplate(context)) return {};
|
|
943
|
+
return context.sourceCode.parserServices.defineTemplateBodyVisitor({
|
|
941
944
|
VStartTag(tag) {
|
|
942
945
|
const attrGroups = {};
|
|
943
946
|
tag.attributes.forEach(attr => {
|
|
@@ -993,7 +996,7 @@ module.exports = {
|
|
|
993
996
|
}
|
|
994
997
|
});
|
|
995
998
|
} else if (typeof replace === 'object' && 'name' in replace && 'value' in replace) {
|
|
996
|
-
const oldValue = attr.directive ? context.
|
|
999
|
+
const oldValue = attr.directive ? context.sourceCode.getText(attr.value.expression) : attr.value?.value;
|
|
997
1000
|
const value = typeof replace.value === 'function' ? replace.value(oldValue) : replace.value;
|
|
998
1001
|
if (value == null || value === oldValue) return;
|
|
999
1002
|
context.report({
|
|
@@ -1011,7 +1014,7 @@ module.exports = {
|
|
|
1011
1014
|
}
|
|
1012
1015
|
return [fixer.replaceText(propNameNode, replace.name), fixer.replaceText(attr.value, `"${value}"`)];
|
|
1013
1016
|
} else {
|
|
1014
|
-
const expression = context.
|
|
1017
|
+
const expression = context.sourceCode.getText(attr.value.expression);
|
|
1015
1018
|
return [fixer.replaceText(propNameNode, replace.name), fixer.replaceText(attr.value, `"${expression} ? '${value}' : undefined"`)];
|
|
1016
1019
|
}
|
|
1017
1020
|
} else {
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
4
|
classify,
|
|
5
|
-
getAttributes
|
|
5
|
+
getAttributes,
|
|
6
|
+
isVueTemplate
|
|
6
7
|
} = require('../util/helpers');
|
|
7
8
|
const groups = [{
|
|
8
9
|
components: ['VDialog', 'VMenu', 'VTooltip'],
|
|
@@ -96,7 +97,7 @@ const groups = [{
|
|
|
96
97
|
yield fixer.replaceText(ref.id.parent.parent, `v-bind="props"`);
|
|
97
98
|
}
|
|
98
99
|
if (boundVariables.attrs) {
|
|
99
|
-
const template = context.parserServices.getTemplateBodyTokenStore();
|
|
100
|
+
const template = context.sourceCode.parserServices.getTemplateBodyTokenStore();
|
|
100
101
|
const ref = boundVariables.attrs;
|
|
101
102
|
const isLast = ref.prop === param.properties.at(-1);
|
|
102
103
|
if (isLast) {
|
|
@@ -187,8 +188,9 @@ module.exports = {
|
|
|
187
188
|
}
|
|
188
189
|
},
|
|
189
190
|
create(context) {
|
|
191
|
+
if (!isVueTemplate(context)) return {};
|
|
190
192
|
let scopeStack;
|
|
191
|
-
return context.parserServices.defineTemplateBodyVisitor({
|
|
193
|
+
return context.sourceCode.parserServices.defineTemplateBodyVisitor({
|
|
192
194
|
VElement(node) {
|
|
193
195
|
scopeStack = {
|
|
194
196
|
parent: scopeStack,
|
package/lib/util/fixers.js
CHANGED
|
@@ -10,11 +10,11 @@ function addClass(context, fixer, element, className) {
|
|
|
10
10
|
return fixer.insertTextAfter(classNode, `="${className}"`);
|
|
11
11
|
} else {
|
|
12
12
|
// nothing
|
|
13
|
-
return fixer.insertTextAfter(context.parserServices.getTemplateBodyTokenStore().getFirstToken(element.startTag), ` class="${className}"`);
|
|
13
|
+
return fixer.insertTextAfter(context.sourceCode.parserServices.getTemplateBodyTokenStore().getFirstToken(element.startTag), ` class="${className}"`);
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
function removeAttr(context, fixer, node) {
|
|
17
|
-
const source = context.
|
|
17
|
+
const source = context.sourceCode.text;
|
|
18
18
|
let [start, end] = node.range;
|
|
19
19
|
// Remove extra whitespace before attributes
|
|
20
20
|
start -= /\s*$/g.exec(source.substring(0, start))[0].length;
|
package/lib/util/helpers.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
function hyphenate(/* istanbul ignore next */
|
|
4
5
|
str = '') {
|
|
5
6
|
return str.replace(/\B([A-Z])/g, '-$1').toLowerCase();
|
|
6
7
|
}
|
|
@@ -41,11 +42,18 @@ function mergeDeep(source, target) {
|
|
|
41
42
|
}
|
|
42
43
|
return source;
|
|
43
44
|
}
|
|
45
|
+
function isVueTemplate(context) {
|
|
46
|
+
if (context.sourceCode.parserServices.defineTemplateBodyVisitor == null) {
|
|
47
|
+
return path.extname(context.getFilename()) === '.vue';
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
44
51
|
module.exports = {
|
|
45
52
|
hyphenate,
|
|
46
53
|
classify,
|
|
47
54
|
isBuiltinAttribute,
|
|
48
55
|
getAttributes,
|
|
49
56
|
isObject,
|
|
50
|
-
mergeDeep
|
|
57
|
+
mergeDeep,
|
|
58
|
+
isVueTemplate
|
|
51
59
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-vuetify",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.1",
|
|
4
4
|
"description": "An eslint plugin for Vuetify",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"author": "Kael Watts-Deuchar <kaelwd@gmail.com>",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "rimraf lib && babel src --out-dir lib",
|
|
11
11
|
"test": "mocha tests --recursive --reporter dot",
|
|
12
|
+
"test:8": "ESLINT8=true mocha tests --recursive --reporter dot",
|
|
12
13
|
"test:coverage": "nyc mocha tests --recursive --reporter dot",
|
|
13
14
|
"test:ci": "nyc --reporter=lcov mocha tests --recursive --reporter dot",
|
|
14
15
|
"lint": "eslint src tests",
|
|
@@ -26,23 +27,24 @@
|
|
|
26
27
|
"@babel/cli": "^7.19.3",
|
|
27
28
|
"@babel/core": "^7.19.6",
|
|
28
29
|
"@babel/preset-env": "^7.19.4",
|
|
30
|
+
"@stylistic/eslint-plugin": "^2.10.1",
|
|
29
31
|
"conventional-changelog-cli": "^2.2.2",
|
|
30
32
|
"conventional-changelog-vuetify": "^1.1.0",
|
|
31
33
|
"conventional-github-releaser": "^3.1.5",
|
|
32
|
-
"eslint": "^
|
|
33
|
-
"
|
|
34
|
-
"eslint-plugin-import": "^2.26.0",
|
|
35
|
-
"eslint-plugin-n": "^15.3.0",
|
|
36
|
-
"eslint-plugin-promise": "^6.1.1",
|
|
34
|
+
"eslint": "^9.14.0",
|
|
35
|
+
"eslint8": "npm:eslint@8.57.1",
|
|
37
36
|
"husky": "^8.0.1",
|
|
38
37
|
"mocha": "^10.1.0",
|
|
38
|
+
"neostandard": "^0.11.8",
|
|
39
39
|
"nyc": "^15.1.0",
|
|
40
40
|
"rimraf": "^3.0.2",
|
|
41
|
-
"vue": "^3.
|
|
42
|
-
"
|
|
41
|
+
"vue": "^3.5.12",
|
|
42
|
+
"vue-eslint-parser": "^9.4.3",
|
|
43
|
+
"vuetify": "^3.7.4"
|
|
43
44
|
},
|
|
44
45
|
"peerDependencies": {
|
|
45
|
-
"eslint": "^8.0.0",
|
|
46
|
+
"eslint": "^8.0.0 || ^9.0.0",
|
|
46
47
|
"vuetify": "^3.0.0"
|
|
47
|
-
}
|
|
48
|
+
},
|
|
49
|
+
"packageManager": "pnpm@9.13.2"
|
|
48
50
|
}
|