eslint-plugin-vuetify 1.1.0 → 2.0.0-beta.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 +2 -4
- package/lib/configs/base.js +6 -8
- package/lib/configs/recommended.js +2 -3
- package/lib/index.js +4 -4
- package/lib/rules/grid-unknown-attributes.js +42 -38
- package/lib/rules/no-deprecated-classes.js +38 -129
- package/lib/rules/no-deprecated-colors.js +99 -0
- package/lib/rules/no-deprecated-components.js +47 -34
- package/lib/rules/no-deprecated-props.js +819 -106
- package/lib/util/fixers.js +12 -16
- package/lib/util/get-installed-vuetify-version.js +9 -22
- package/lib/util/grid-attributes.js +10 -18
- package/lib/util/helpers.js +30 -53
- package/package.json +20 -14
- package/lib/rules/no-legacy-grid.js +0 -107
- package/lib/util/load-module.js +0 -22
package/README.md
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
# eslint-plugin-vuetify
|
|
2
|
-
> An eslint plugin for Vuetify.
|
|
3
|
-
> Built for https://github.com/vuetifyjs/vuetify/pull/7327, requires vuetify >=2.0.0
|
|
4
2
|
|
|
5
3
|
<br>
|
|
6
4
|
|
|
@@ -45,20 +43,20 @@ These rules will help you avoid deprecated components, props, and classes. They
|
|
|
45
43
|
- Prevent the use of components that have been removed from Vuetify ([`no-deprecated-components`])
|
|
46
44
|
- Prevent the use of props that have been removed from Vuetify ([`no-deprecated-props`])
|
|
47
45
|
- Prevent the use of classes that have been removed from Vuetify ([`no-deprecated-classes`])
|
|
46
|
+
- Prevent the use of the old theme class syntax ([`no-deprecated-colors`])
|
|
48
47
|
|
|
49
48
|
### Grid system
|
|
50
49
|
|
|
51
50
|
These rules are designed to help migrate to the new grid system in Vuetify v2. They are included in the `plugin:vuetify/recommended` preset.
|
|
52
51
|
|
|
53
|
-
- Prevent the use of legacy grid components and props ([`no-legacy-grid`])
|
|
54
52
|
- Warn about unknown attributes not being converted to classes on new grid components ([`grid-unknown-attributes`])
|
|
55
53
|
|
|
56
54
|
|
|
57
|
-
[`no-legacy-grid`]: ./docs/rules/no-legacy-grid.md
|
|
58
55
|
[`grid-unknown-attributes`]: ./docs/rules/grid-unknown-attributes.md
|
|
59
56
|
[`no-deprecated-components`]: ./docs/rules/no-deprecated-components.md
|
|
60
57
|
[`no-deprecated-props`]: ./docs/rules/no-deprecated-props.md
|
|
61
58
|
[`no-deprecated-classes`]: ./docs/rules/no-deprecated-classes.md
|
|
59
|
+
[`no-deprecated-colors`]: ./docs/rules/no-deprecated-colors.md
|
|
62
60
|
|
|
63
61
|
|
|
64
62
|
## 💪 Supporting Vuetify
|
package/lib/configs/base.js
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
'use strict'
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
|
-
plugins: [
|
|
5
|
-
'vuetify'
|
|
6
|
-
],
|
|
4
|
+
plugins: ['vuetify'],
|
|
7
5
|
rules: {
|
|
8
6
|
'vue/valid-v-slot': ['error', {
|
|
9
7
|
allowModifiers: true
|
|
10
8
|
}],
|
|
11
|
-
|
|
9
|
+
'vuetify/no-deprecated-classes': 'error',
|
|
10
|
+
'vuetify/no-deprecated-colors': 'error',
|
|
12
11
|
'vuetify/no-deprecated-components': 'error',
|
|
13
|
-
'vuetify/no-deprecated-props': 'error'
|
|
14
|
-
'vuetify/no-deprecated-classes': 'error'
|
|
12
|
+
'vuetify/no-deprecated-props': 'error'
|
|
15
13
|
}
|
|
16
|
-
}
|
|
14
|
+
};
|
package/lib/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
const path = require('path')
|
|
3
|
-
const requireindex = require('requireindex')
|
|
1
|
+
'use strict';
|
|
4
2
|
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const requireindex = require('requireindex');
|
|
5
5
|
module.exports = {
|
|
6
6
|
configs: requireindex(path.join(__dirname, './configs')),
|
|
7
7
|
rules: requireindex(path.join(__dirname, './rules'))
|
|
8
|
-
}
|
|
8
|
+
};
|
|
@@ -1,21 +1,29 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const loadModule = require('../util/load-module')
|
|
4
|
-
const { hyphenate, classify, getAttributes } = require('../util/helpers')
|
|
5
|
-
const { isGridAttribute } = require('../util/grid-attributes')
|
|
6
|
-
const { addClass, removeAttr } = require('../util/fixers')
|
|
1
|
+
'use strict';
|
|
7
2
|
|
|
3
|
+
const {
|
|
4
|
+
hyphenate,
|
|
5
|
+
classify,
|
|
6
|
+
getAttributes
|
|
7
|
+
} = require('../util/helpers');
|
|
8
|
+
const {
|
|
9
|
+
isGridAttribute
|
|
10
|
+
} = require('../util/grid-attributes');
|
|
11
|
+
const {
|
|
12
|
+
addClass,
|
|
13
|
+
removeAttr
|
|
14
|
+
} = require('../util/fixers');
|
|
15
|
+
const {
|
|
16
|
+
components
|
|
17
|
+
} = require('vuetify/dist/vuetify.js');
|
|
8
18
|
const VGrid = {
|
|
9
|
-
VContainer:
|
|
10
|
-
VRow:
|
|
11
|
-
VCol:
|
|
12
|
-
}
|
|
13
|
-
|
|
19
|
+
VContainer: components.VContainer,
|
|
20
|
+
VRow: components.VRow,
|
|
21
|
+
VCol: components.VCol
|
|
22
|
+
};
|
|
14
23
|
const tags = Object.keys(VGrid).reduce((t, k) => {
|
|
15
|
-
t[classify(k)] = Object.keys(VGrid[k].
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}, {})
|
|
24
|
+
t[classify(k)] = Object.keys(VGrid[k].props).map(p => hyphenate(p)).sort();
|
|
25
|
+
return t;
|
|
26
|
+
}, {});
|
|
19
27
|
|
|
20
28
|
// ------------------------------------------------------------------------------
|
|
21
29
|
// Rule Definition
|
|
@@ -30,16 +38,16 @@ module.exports = {
|
|
|
30
38
|
fixable: 'code',
|
|
31
39
|
schema: []
|
|
32
40
|
},
|
|
33
|
-
create
|
|
41
|
+
create(context) {
|
|
34
42
|
return context.parserServices.defineTemplateBodyVisitor({
|
|
35
|
-
VElement
|
|
36
|
-
const tag = classify(element.rawName)
|
|
37
|
-
if (!Object.keys(tags).includes(tag)) return
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
VElement(element) {
|
|
44
|
+
const tag = classify(element.rawName);
|
|
45
|
+
if (!Object.keys(tags).includes(tag)) return;
|
|
46
|
+
const attributes = getAttributes(element).filter(({
|
|
47
|
+
name
|
|
48
|
+
}) => {
|
|
49
|
+
return !tags[tag].includes(name) && !isGridAttribute(tag, name);
|
|
50
|
+
});
|
|
43
51
|
if (attributes.length) {
|
|
44
52
|
context.report({
|
|
45
53
|
node: element.startTag,
|
|
@@ -48,21 +56,17 @@ module.exports = {
|
|
|
48
56
|
end: attributes[attributes.length - 1].node.loc.end
|
|
49
57
|
},
|
|
50
58
|
message: 'Attributes are no longer converted into classes',
|
|
51
|
-
fix
|
|
52
|
-
const fixableAttrs = attributes.map(({
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (!fixableAttrs.length) return
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return [
|
|
59
|
-
addClass(context, fixer, element, className),
|
|
60
|
-
...fixableAttrs.map(removeAttr.bind(this, context, fixer))
|
|
61
|
-
]
|
|
59
|
+
fix(fixer) {
|
|
60
|
+
const fixableAttrs = attributes.map(({
|
|
61
|
+
node
|
|
62
|
+
}) => node).filter(attr => !attr.directive);
|
|
63
|
+
if (!fixableAttrs.length) return;
|
|
64
|
+
const className = fixableAttrs.map(node => node.key.rawName).join(' ');
|
|
65
|
+
return [addClass(context, fixer, element, className), ...fixableAttrs.map(removeAttr.bind(this, context, fixer))];
|
|
62
66
|
}
|
|
63
|
-
})
|
|
67
|
+
});
|
|
64
68
|
}
|
|
65
69
|
}
|
|
66
|
-
})
|
|
70
|
+
});
|
|
67
71
|
}
|
|
68
|
-
}
|
|
72
|
+
};
|
|
@@ -1,53 +1,23 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { classify, getAttributes } = require('../util/helpers')
|
|
4
|
-
const { removeAttr } = require('../util/fixers')
|
|
5
|
-
const { getInstalledVuetifyVersion } = require('../util/get-installed-vuetify-version')
|
|
6
|
-
|
|
7
|
-
// const spacers = {
|
|
8
|
-
// 0: 0,
|
|
9
|
-
// 1: 1,
|
|
10
|
-
// 2: 2,
|
|
11
|
-
// 3: 4,
|
|
12
|
-
// 4: 6,
|
|
13
|
-
// 5: 12
|
|
14
|
-
// }
|
|
1
|
+
'use strict';
|
|
15
2
|
|
|
16
3
|
/** @type {Map<RegExp, (args: string[]) => string> | Map<string, string>} */
|
|
17
|
-
const replacements = new Map([
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
[
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
]
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
replacements
|
|
35
|
-
.set('display-4', 'text-h1')
|
|
36
|
-
.set('display-3', 'text-h2')
|
|
37
|
-
.set('display-2', 'text-h3')
|
|
38
|
-
.set('display-1', 'text-h4')
|
|
39
|
-
.set('headline', 'text-h5')
|
|
40
|
-
.set('title', 'text-h6')
|
|
41
|
-
.set('subtitle-1', 'text-subtitle-1')
|
|
42
|
-
.set('subtitle-2', 'text-subtitle-2')
|
|
43
|
-
.set('body-1', 'text-body-1')
|
|
44
|
-
.set('body-2', 'text-body-2')
|
|
45
|
-
.set('caption', 'text-caption')
|
|
46
|
-
.set('overline', 'text-overline')
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// These components treat attributes like classes
|
|
50
|
-
const gridComponents = ['VContainer', 'VLayout', 'VFlex', 'VSpacer']
|
|
4
|
+
const replacements = new Map([[/^rounded-(r|l|tr|tl|br|bl)(.*)$/, ([side, rest]) => {
|
|
5
|
+
side = {
|
|
6
|
+
r: 'e',
|
|
7
|
+
l: 's',
|
|
8
|
+
tr: 'te',
|
|
9
|
+
tl: 'ts',
|
|
10
|
+
br: 'be',
|
|
11
|
+
bl: 'bs'
|
|
12
|
+
}[side];
|
|
13
|
+
return `rounded-${side}${rest}`;
|
|
14
|
+
}], [/^border-([rl])(.*)$/, ([side, rest]) => {
|
|
15
|
+
side = {
|
|
16
|
+
r: 'e',
|
|
17
|
+
l: 's'
|
|
18
|
+
}[side];
|
|
19
|
+
return `border-${side}${rest}`;
|
|
20
|
+
}], [/^text-xs-(left|right|center|justify)$/, ([align]) => `text-${align}`], ['scroll-y', 'overflow-y-auto'], ['hide-overflow', 'overflow-hidden'], ['show-overflow', 'overflow-visible'], ['no-wrap', 'text-no-wrap'], ['ellipsis', 'text-truncate'], ['left', 'float-left'], ['right', 'float-right'], ['display-4', 'text-h1'], ['display-3', 'text-h2'], ['display-2', 'text-h3'], ['display-1', 'text-h4'], ['headline', 'text-h5'], ['title', 'text-h6'], ['subtitle-1', 'text-subtitle-1'], ['subtitle-2', 'text-subtitle-2'], ['body-1', 'text-body-1'], ['body-2', 'text-body-2'], ['caption', 'text-caption'], ['caption', 'text-caption'], ['overline', 'text-overline']]);
|
|
51
21
|
|
|
52
22
|
// ------------------------------------------------------------------------------
|
|
53
23
|
// Rule Definition
|
|
@@ -65,95 +35,34 @@ module.exports = {
|
|
|
65
35
|
removed: `'{{ name }}' has been removed`
|
|
66
36
|
}
|
|
67
37
|
},
|
|
68
|
-
|
|
69
|
-
create (context) {
|
|
38
|
+
create(context) {
|
|
70
39
|
return context.parserServices.defineTemplateBodyVisitor({
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
getAttributes(element).forEach(attr => {
|
|
77
|
-
for (const replacer of replacements) {
|
|
78
|
-
if (typeof replacer[0] === 'string' && replacer[0] === attr.name) {
|
|
79
|
-
const replacement = replacer[1]
|
|
80
|
-
return context.report({
|
|
81
|
-
messageId: 'replacedWith',
|
|
82
|
-
data: {
|
|
83
|
-
a: attr.name,
|
|
84
|
-
b: replacement
|
|
85
|
-
},
|
|
86
|
-
node: attr.node,
|
|
87
|
-
fix (fixer) {
|
|
88
|
-
return fixer.replaceText(attr.node, replacement)
|
|
89
|
-
}
|
|
90
|
-
})
|
|
91
|
-
}
|
|
92
|
-
if (replacer[0] instanceof RegExp) {
|
|
93
|
-
const matches = (replacer[0].exec(attr.name) || []).slice(1)
|
|
94
|
-
const replace = replacer[1]
|
|
95
|
-
if (matches.length && typeof replace === 'function') {
|
|
96
|
-
const replacement = replace(matches)
|
|
97
|
-
return context.report({
|
|
98
|
-
messageId: 'replacedWith',
|
|
99
|
-
data: {
|
|
100
|
-
a: attr.name,
|
|
101
|
-
b: replacement
|
|
102
|
-
},
|
|
103
|
-
node: attr.node,
|
|
104
|
-
fix (fixer) {
|
|
105
|
-
return fixer.replaceText(attr.node, replacement)
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Remove <v-layout row> as it conflicts with <v-row> styles
|
|
113
|
-
// https://github.com/vuetifyjs/vuetify/commit/3f435b5a
|
|
114
|
-
if (tag === 'VLayout' && attr.name === 'row') {
|
|
115
|
-
return context.report({
|
|
116
|
-
node: attr.node,
|
|
117
|
-
message: `Don't use "row" on <v-layout>, see https://github.com/vuetifyjs/vuetify/commit/3f435b5a`,
|
|
118
|
-
fix (fixer) {
|
|
119
|
-
if (!attr.node.directive) return removeAttr(context, fixer, attr.node)
|
|
120
|
-
}
|
|
121
|
-
})
|
|
122
|
-
}
|
|
123
|
-
})
|
|
124
|
-
},
|
|
125
|
-
'VAttribute[key.name="class"]' (node) {
|
|
126
|
-
if (!node.value || !node.value.value) return
|
|
127
|
-
|
|
128
|
-
const classes = node.value.value.split(/\s+/).filter(s => !!s)
|
|
129
|
-
const source = context.getSourceCode()
|
|
130
|
-
|
|
131
|
-
const changed = []
|
|
40
|
+
'VAttribute[key.name="class"]'(node) {
|
|
41
|
+
if (!node.value || !node.value.value) return;
|
|
42
|
+
const classes = node.value.value.split(/\s+/).filter(s => !!s);
|
|
43
|
+
const source = context.getSourceCode();
|
|
44
|
+
const changed = [];
|
|
132
45
|
classes.forEach(className => {
|
|
133
46
|
for (const replacer of replacements) {
|
|
134
47
|
if (typeof replacer[0] === 'string' && replacer[0] === className) {
|
|
135
|
-
return changed.push([className, replacer[1]])
|
|
48
|
+
return changed.push([className, replacer[1]]);
|
|
136
49
|
}
|
|
137
50
|
if (replacer[0] instanceof RegExp) {
|
|
138
|
-
const matches = (replacer[0].exec(className) || []).slice(1)
|
|
139
|
-
const replace = replacer[1]
|
|
51
|
+
const matches = (replacer[0].exec(className) || []).slice(1);
|
|
52
|
+
const replace = replacer[1];
|
|
140
53
|
if (matches.length && typeof replace === 'function') {
|
|
141
|
-
return changed.push([className, replace(matches)])
|
|
54
|
+
return changed.push([className, replace(matches)]);
|
|
142
55
|
}
|
|
143
56
|
}
|
|
144
57
|
}
|
|
145
|
-
})
|
|
146
|
-
|
|
58
|
+
});
|
|
147
59
|
changed.forEach(change => {
|
|
148
|
-
const idx = node.value.value.indexOf(change[0]) + 1
|
|
149
|
-
const range = [
|
|
150
|
-
node.value.range[0] + idx,
|
|
151
|
-
node.value.range[0] + idx + change[0].length
|
|
152
|
-
]
|
|
60
|
+
const idx = node.value.value.indexOf(change[0]) + 1;
|
|
61
|
+
const range = [node.value.range[0] + idx, node.value.range[0] + idx + change[0].length];
|
|
153
62
|
const loc = {
|
|
154
63
|
start: source.getLocFromIndex(range[0]),
|
|
155
64
|
end: source.getLocFromIndex(range[1])
|
|
156
|
-
}
|
|
65
|
+
};
|
|
157
66
|
context.report({
|
|
158
67
|
loc,
|
|
159
68
|
messageId: 'replacedWith',
|
|
@@ -161,12 +70,12 @@ module.exports = {
|
|
|
161
70
|
a: change[0],
|
|
162
71
|
b: change[1]
|
|
163
72
|
},
|
|
164
|
-
fix
|
|
165
|
-
return fixer.replaceTextRange(range, change[1])
|
|
73
|
+
fix(fixer) {
|
|
74
|
+
return fixer.replaceTextRange(range, change[1]);
|
|
166
75
|
}
|
|
167
|
-
})
|
|
168
|
-
})
|
|
76
|
+
});
|
|
77
|
+
});
|
|
169
78
|
}
|
|
170
|
-
})
|
|
79
|
+
});
|
|
171
80
|
}
|
|
172
|
-
}
|
|
81
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
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
|
+
const cssTextColors = cssColors.map(v => `${v}--text`);
|
|
5
|
+
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'];
|
|
6
|
+
const textVariants = variants.map(v => `text--${v}`);
|
|
7
|
+
|
|
8
|
+
// ------------------------------------------------------------------------------
|
|
9
|
+
// Rule Definition
|
|
10
|
+
// ------------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
meta: {
|
|
14
|
+
docs: {
|
|
15
|
+
description: 'Disallow the use of classes that have been removed from Vuetify'
|
|
16
|
+
},
|
|
17
|
+
fixable: 'code',
|
|
18
|
+
schema: [{
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
themeColors: {
|
|
22
|
+
type: 'array',
|
|
23
|
+
items: {
|
|
24
|
+
type: 'string'
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
additionalProperties: false
|
|
29
|
+
}],
|
|
30
|
+
messages: {
|
|
31
|
+
replacedWith: `'{{ a }}' has been replaced with '{{ b }}'`,
|
|
32
|
+
removed: `'{{ name }}' cannot be used alone, it must be combined with a color`
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
create(context) {
|
|
36
|
+
const themeColors = ['primary', 'secondary', 'accent', 'error', 'warning', 'info', 'success', ...(context.options[0]?.themeColors || [])];
|
|
37
|
+
const themeTextColors = themeColors.map(v => `${v}--text`);
|
|
38
|
+
function findColor(classes) {
|
|
39
|
+
const base = classes.findIndex(t => themeColors.includes(t) || cssColors.includes(t));
|
|
40
|
+
const variant = classes.findIndex(t => variants.includes(t));
|
|
41
|
+
return [base, variant];
|
|
42
|
+
}
|
|
43
|
+
function findTextColor(classes) {
|
|
44
|
+
const base = classes.findIndex(t => themeTextColors.includes(t) || cssTextColors.includes(t));
|
|
45
|
+
const variant = classes.findIndex(t => textVariants.includes(t));
|
|
46
|
+
return [base, variant];
|
|
47
|
+
}
|
|
48
|
+
return context.parserServices.defineTemplateBodyVisitor({
|
|
49
|
+
'VAttribute[key.name="color"]'(node) {
|
|
50
|
+
if (!node.value || !node.value.value) return;
|
|
51
|
+
const color = node.value.value.split(/\s+/).filter(s => !!s);
|
|
52
|
+
const [base, variant] = findColor(color);
|
|
53
|
+
if (~base && ~variant) {
|
|
54
|
+
context.report({
|
|
55
|
+
node,
|
|
56
|
+
messageId: 'replacedWith',
|
|
57
|
+
data: {
|
|
58
|
+
a: node.value.value,
|
|
59
|
+
b: `${color[base]}-${color[variant]}`
|
|
60
|
+
},
|
|
61
|
+
fix: fixer => fixer.replaceTextRange(node.value.range, `"${color[base]}-${color[variant]}"`)
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
'VAttribute[key.name="class"]'(node) {
|
|
66
|
+
if (!node.value || !node.value.value) return;
|
|
67
|
+
const classes = node.value.value.split(/\s+/).filter(s => !!s);
|
|
68
|
+
for (const [find, prefix] of [[findColor, 'bg'], [findTextColor, 'text']]) {
|
|
69
|
+
const [base, variant] = find(classes);
|
|
70
|
+
if (~base || ~base && ~variant) {
|
|
71
|
+
const newColor = ~variant ? `${prefix}-${classes[base].replace('--text', '')}-${classes[variant].replace('text--', '')}` : `${prefix}-${classes[base].replace('--text', '')}`;
|
|
72
|
+
context.report({
|
|
73
|
+
node,
|
|
74
|
+
messageId: 'replacedWith',
|
|
75
|
+
data: {
|
|
76
|
+
a: ~variant ? `${classes[base]} ${classes[variant]}` : classes[base],
|
|
77
|
+
b: newColor
|
|
78
|
+
},
|
|
79
|
+
fix: fixer => {
|
|
80
|
+
const newClasses = classes.slice();
|
|
81
|
+
newClasses.splice(base, 1, newColor);
|
|
82
|
+
if (~variant) newClasses.splice(variant, 1);
|
|
83
|
+
return fixer.replaceTextRange(node.value.range, `"${newClasses.join(' ')}"`);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
} else if (~variant) {
|
|
87
|
+
context.report({
|
|
88
|
+
node,
|
|
89
|
+
messageId: 'removed',
|
|
90
|
+
data: {
|
|
91
|
+
name: classes[variant]
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
};
|
|
@@ -1,27 +1,43 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { hyphenate, classify } = require('../util/helpers')
|
|
4
|
-
const { getInstalledVuetifyVersion } = require('../util/get-installed-vuetify-version')
|
|
1
|
+
'use strict';
|
|
5
2
|
|
|
3
|
+
const {
|
|
4
|
+
hyphenate,
|
|
5
|
+
classify
|
|
6
|
+
} = require('../util/helpers');
|
|
6
7
|
const replacements = {
|
|
7
8
|
VListTile: 'v-list-item',
|
|
8
9
|
VListTileAction: 'v-list-item-action',
|
|
9
|
-
VListTileAvatar:
|
|
10
|
+
VListTileAvatar: false,
|
|
10
11
|
VListTileActionText: 'v-list-item-action-text',
|
|
11
|
-
VListTileContent:
|
|
12
|
+
VListTileContent: false,
|
|
12
13
|
VListTileTitle: 'v-list-item-title',
|
|
13
14
|
VListTileSubTitle: 'v-list-item-subtitle',
|
|
14
15
|
VJumbotron: false,
|
|
15
16
|
VToolbarSideIcon: 'v-app-bar-nav-icon',
|
|
16
|
-
|
|
17
17
|
// Possible typos
|
|
18
18
|
VListItemSubTitle: 'v-list-item-subtitle',
|
|
19
|
-
VListTileSubtitle: 'v-list-item-subtitle'
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
VListTileSubtitle: 'v-list-item-subtitle',
|
|
20
|
+
VContent: 'v-main',
|
|
21
|
+
VBannerActions: false,
|
|
22
|
+
VBannerText: false,
|
|
23
|
+
VBottomSheet: false,
|
|
24
|
+
VCalendar: false,
|
|
25
|
+
VData: false,
|
|
26
|
+
VDataIterator: false,
|
|
27
|
+
VDataTable: false,
|
|
28
|
+
VDatePicker: false,
|
|
29
|
+
VOtpInput: false,
|
|
30
|
+
VOverflowBtn: false,
|
|
31
|
+
VPicker: false,
|
|
32
|
+
VSimpleCheckbox: 'v-checkbox-btn',
|
|
33
|
+
VSkeletonLoader: false,
|
|
34
|
+
VSparkline: false,
|
|
35
|
+
VSpeedDial: false,
|
|
36
|
+
VStepper: false,
|
|
37
|
+
VTimePicker: false,
|
|
38
|
+
VTreeview: false,
|
|
39
|
+
VVirtualScroll: false
|
|
40
|
+
};
|
|
25
41
|
|
|
26
42
|
// ------------------------------------------------------------------------------
|
|
27
43
|
// Rule Definition
|
|
@@ -40,15 +56,13 @@ module.exports = {
|
|
|
40
56
|
removed: `'{{ name }}' has been removed`
|
|
41
57
|
}
|
|
42
58
|
},
|
|
43
|
-
create
|
|
59
|
+
create(context) {
|
|
44
60
|
return context.parserServices.defineTemplateBodyVisitor({
|
|
45
|
-
VElement
|
|
46
|
-
const tag = classify(element.rawName)
|
|
47
|
-
|
|
48
|
-
const tokens = context.parserServices.getTemplateBodyTokenStore()
|
|
49
|
-
|
|
61
|
+
VElement(element) {
|
|
62
|
+
const tag = classify(element.rawName);
|
|
63
|
+
const tokens = context.parserServices.getTemplateBodyTokenStore();
|
|
50
64
|
if (Object.prototype.hasOwnProperty.call(replacements, tag)) {
|
|
51
|
-
const replacement = replacements[tag]
|
|
65
|
+
const replacement = replacements[tag];
|
|
52
66
|
if (replacement) {
|
|
53
67
|
context.report({
|
|
54
68
|
node: element,
|
|
@@ -57,28 +71,27 @@ module.exports = {
|
|
|
57
71
|
a: hyphenate(tag),
|
|
58
72
|
b: replacement
|
|
59
73
|
},
|
|
60
|
-
fix
|
|
61
|
-
const open = tokens.getFirstToken(element.startTag)
|
|
62
|
-
const endTag = element.endTag
|
|
74
|
+
fix(fixer) {
|
|
75
|
+
const open = tokens.getFirstToken(element.startTag);
|
|
76
|
+
const endTag = element.endTag;
|
|
63
77
|
if (!endTag) {
|
|
64
|
-
return fixer.replaceText(open, `<${replacement}`)
|
|
78
|
+
return fixer.replaceText(open, `<${replacement}`);
|
|
65
79
|
}
|
|
66
|
-
const endTagOpen = tokens.getFirstToken(endTag)
|
|
67
|
-
return [
|
|
68
|
-
fixer.replaceText(open, `<${replacement}`),
|
|
69
|
-
fixer.replaceText(endTagOpen, `</${replacement}`)
|
|
70
|
-
]
|
|
80
|
+
const endTagOpen = tokens.getFirstToken(endTag);
|
|
81
|
+
return [fixer.replaceText(open, `<${replacement}`), fixer.replaceText(endTagOpen, `</${replacement}`)];
|
|
71
82
|
}
|
|
72
|
-
})
|
|
83
|
+
});
|
|
73
84
|
} else {
|
|
74
85
|
context.report({
|
|
75
86
|
node: element,
|
|
76
87
|
messageId: 'removed',
|
|
77
|
-
data: {
|
|
78
|
-
|
|
88
|
+
data: {
|
|
89
|
+
name: hyphenate(tag)
|
|
90
|
+
}
|
|
91
|
+
});
|
|
79
92
|
}
|
|
80
93
|
}
|
|
81
94
|
}
|
|
82
|
-
})
|
|
95
|
+
});
|
|
83
96
|
}
|
|
84
|
-
}
|
|
97
|
+
};
|