Skip to content

Commit 5d26e94

Browse files
authored
Breaking: support new syntax in Vue.js 2.6 (#807)
1 parent db700ff commit 5d26e94

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+532
-182
lines changed

docs/rules/attributes-order.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ This rule aims to enforce ordering of component attributes. The default order is
2525
- `GLOBAL`
2626
ex: 'id'
2727
- `UNIQUE`
28-
ex: 'ref', 'key', 'slot'
28+
ex: 'ref', 'key', 'v-slot', 'slot'
2929
- `TWO_WAY_BINDING`
3030
ex: 'v-model'
3131
- `OTHER_DIRECTIVES`

lib/rules/array-bracket-spacing.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@
55

66
const { wrapCoreRule } = require('../utils')
77

8-
// eslint-disable-next-line
9-
module.exports = wrapCoreRule(require('eslint/lib/rules/array-bracket-spacing'))
8+
// eslint-disable-next-line no-invalid-meta
9+
module.exports = wrapCoreRule(
10+
require('eslint/lib/rules/array-bracket-spacing'),
11+
{ skipDynamicArguments: true }
12+
)

lib/rules/attribute-hyphenation.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,10 @@ module.exports = {
9292
VAttribute (node) {
9393
if (!utils.isCustomComponent(node.parent.parent)) return
9494

95-
const name = !node.directive ? node.key.rawName : node.key.name === 'bind' ? node.key.raw.argument : false
95+
const name =
96+
!node.directive ? node.key.rawName
97+
: node.key.name.name === 'bind' ? node.key.argument && node.key.argument.rawName
98+
: /* otherwise */ false
9699
if (!name || isIgnoredAttribute(name)) return
97100

98101
reportIssue(node, name)

lib/rules/attributes-order.js

+14-8
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@ const utils = require('../utils')
99
// Rule Definition
1010
// ------------------------------------------------------------------------------
1111

12-
function getAttributeType (name, isDirective) {
13-
if (isDirective) {
12+
function getAttributeType (attribute, sourceCode) {
13+
const isBind = attribute.directive && attribute.key.name.name === 'bind'
14+
const name = isBind
15+
? (attribute.key.argument ? sourceCode.getText(attribute.key.argument) : '')
16+
: (attribute.directive ? attribute.key.name.name : attribute.key.name)
17+
18+
if (attribute.directive && !isBind) {
1419
if (name === 'for') {
1520
return 'LIST_RENDERING'
1621
} else if (name === 'if' || name === 'else-if' || name === 'else' || name === 'show' || name === 'cloak') {
@@ -23,6 +28,8 @@ function getAttributeType (name, isDirective) {
2328
return 'EVENTS'
2429
} else if (name === 'html' || name === 'text') {
2530
return 'CONTENT'
31+
} else if (name === 'slot') {
32+
return 'UNIQUE'
2633
} else {
2734
return 'OTHER_DIRECTIVES'
2835
}
@@ -38,10 +45,9 @@ function getAttributeType (name, isDirective) {
3845
}
3946
}
4047
}
41-
function getPosition (attribute, attributePosition) {
42-
const attributeType = attribute.directive && attribute.key.name === 'bind'
43-
? getAttributeType(attribute.key.argument, false)
44-
: getAttributeType(attribute.key.name, attribute.directive)
48+
49+
function getPosition (attribute, attributePosition, sourceCode) {
50+
const attributeType = getAttributeType(attribute, sourceCode)
4551
return attributePosition.hasOwnProperty(attributeType) ? attributePosition[attributeType] : -1
4652
}
4753

@@ -91,8 +97,8 @@ function create (context) {
9197
previousNode = null
9298
},
9399
'VAttribute' (node) {
94-
if ((currentPosition === -1) || (currentPosition <= getPosition(node, attributePosition))) {
95-
currentPosition = getPosition(node, attributePosition)
100+
if ((currentPosition === -1) || (currentPosition <= getPosition(node, attributePosition, sourceCode))) {
101+
currentPosition = getPosition(node, attributePosition, sourceCode)
96102
previousNode = node
97103
} else {
98104
reportIssue(node, previousNode)

lib/rules/block-spacing.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@
55

66
const { wrapCoreRule } = require('../utils')
77

8-
// eslint-disable-next-line
9-
module.exports = wrapCoreRule(require('eslint/lib/rules/block-spacing'))
8+
// eslint-disable-next-line no-invalid-meta
9+
module.exports = wrapCoreRule(
10+
require('eslint/lib/rules/block-spacing'),
11+
{ skipDynamicArguments: true }
12+
)

lib/rules/brace-style.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,9 @@
55

66
const { wrapCoreRule } = require('../utils')
77

8-
// eslint-disable-next-line
9-
module.exports = wrapCoreRule(require('eslint/lib/rules/brace-style'))
8+
// eslint-disable-next-line no-invalid-meta
9+
module.exports = wrapCoreRule(
10+
require('eslint/lib/rules/brace-style'),
11+
{ skipDynamicArguments: true }
12+
)
13+

lib/rules/key-spacing.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@
55

66
const { wrapCoreRule } = require('../utils')
77

8-
// eslint-disable-next-line
9-
module.exports = wrapCoreRule(require('eslint/lib/rules/key-spacing'))
8+
// eslint-disable-next-line no-invalid-meta
9+
module.exports = wrapCoreRule(
10+
require('eslint/lib/rules/key-spacing'),
11+
{ skipDynamicArguments: true }
12+
)

lib/rules/max-attributes-per-line.js

+3-19
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ module.exports = {
6767
},
6868

6969
create: function (context) {
70+
const sourceCode = context.getSourceCode()
7071
const configuration = parseOptions(context.options[0])
7172
const multilineMaximum = configuration.multiline
7273
const singlelinemMaximum = configuration.singleline
@@ -130,23 +131,6 @@ module.exports = {
130131
return defaults
131132
}
132133

133-
function getPropData (prop) {
134-
let propType = 'Attribute'
135-
let propName = prop.key.name
136-
137-
if (utils.isBindingAttribute(prop)) {
138-
propType = 'Binding'
139-
propName = prop.key.raw.argument
140-
} else if (utils.isEventAttribute(prop)) {
141-
propType = 'Event'
142-
propName = prop.key.raw.argument
143-
} else if (prop.directive) {
144-
propType = 'Directive'
145-
}
146-
147-
return { propType, propName }
148-
}
149-
150134
function showErrors (attributes) {
151135
attributes.forEach((prop, i) => {
152136
const fix = (fixer) => {
@@ -166,8 +150,8 @@ module.exports = {
166150
context.report({
167151
node: prop,
168152
loc: prop.loc,
169-
message: '{{propType}} "{{propName}}" should be on a new line.',
170-
data: getPropData(prop),
153+
message: '\'{{name}}\' should be on a new line.',
154+
data: { name: sourceCode.getText(prop.key) },
171155
fix
172156
})
173157
})

lib/rules/no-confusing-v-for-v-if.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ module.exports = {
5050

5151
create (context) {
5252
return utils.defineTemplateBodyVisitor(context, {
53-
"VAttribute[directive=true][key.name='if']" (node) {
53+
"VAttribute[directive=true][key.name.name='if']" (node) {
5454
const element = node.parent.parent
5555

5656
if (utils.hasDirective(element, 'for') && !isUsingIterationVar(node)) {

lib/rules/no-duplicate-attributes.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ function getName (attribute) {
2424
if (!attribute.directive) {
2525
return attribute.key.name
2626
}
27-
if (attribute.key.name === 'bind') {
28-
return attribute.key.argument || null
27+
if (attribute.key.name.name === 'bind') {
28+
return (attribute.key.argument && attribute.key.argument.name) || null
2929
}
3030
return null
3131
}

lib/rules/no-unused-components.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ module.exports = {
5555

5656
usedComponents.add(node.rawName)
5757
},
58-
"VAttribute[directive=true][key.name='bind'][key.argument='is']" (node) {
58+
"VAttribute[directive=true][key.name.name='bind'][key.argument.name='is']" (node) {
5959
if (
6060
!node.value || // `<component :is>`
6161
node.value.type !== 'VExpressionContainer' ||

lib/rules/no-use-v-if-with-v-for.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ module.exports = {
7070
const options = context.options[0] || {}
7171
const allowUsingIterationVar = options.allowUsingIterationVar === true // default false
7272
return utils.defineTemplateBodyVisitor(context, {
73-
"VAttribute[directive=true][key.name='if']" (node) {
73+
"VAttribute[directive=true][key.name.name='if']" (node) {
7474
const element = node.parent.parent
7575

7676
if (utils.hasDirective(element, 'for')) {

lib/rules/no-v-html.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ module.exports = {
2222
},
2323
create (context) {
2424
return utils.defineTemplateBodyVisitor(context, {
25-
"VAttribute[directive=true][key.name='html']" (node) {
25+
"VAttribute[directive=true][key.name.name='html']" (node) {
2626
context.report({
2727
node,
2828
loc: node.loc,

lib/rules/object-curly-spacing.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@
55

66
const { wrapCoreRule } = require('../utils')
77

8-
// eslint-disable-next-line
9-
module.exports = wrapCoreRule(require('eslint/lib/rules/object-curly-spacing'))
8+
// eslint-disable-next-line no-invalid-meta
9+
module.exports = wrapCoreRule(
10+
require('eslint/lib/rules/object-curly-spacing'),
11+
{ skipDynamicArguments: true }
12+
)

lib/rules/require-v-for-key.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ module.exports = {
4949
}
5050

5151
return utils.defineTemplateBodyVisitor(context, {
52-
"VAttribute[directive=true][key.name='for']" (node) {
52+
"VAttribute[directive=true][key.name.name='for']" (node) {
5353
checkKey(node.parent.parent)
5454
}
5555
})

lib/rules/space-infix-ops.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@
55

66
const { wrapCoreRule } = require('../utils')
77

8-
// eslint-disable-next-line
9-
module.exports = wrapCoreRule(require('eslint/lib/rules/space-infix-ops'))
8+
// eslint-disable-next-line no-invalid-meta
9+
module.exports = wrapCoreRule(
10+
require('eslint/lib/rules/space-infix-ops'),
11+
{ skipDynamicArguments: true }
12+
)

lib/rules/space-unary-ops.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@
55

66
const { wrapCoreRule } = require('../utils')
77

8-
// eslint-disable-next-line
9-
module.exports = wrapCoreRule(require('eslint/lib/rules/space-unary-ops'))
8+
// eslint-disable-next-line no-invalid-meta
9+
module.exports = wrapCoreRule(
10+
require('eslint/lib/rules/space-unary-ops'),
11+
{ skipDynamicArguments: true }
12+
)

lib/rules/this-in-template.js

+5
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ module.exports = {
8484
}
8585
: {
8686
'VExpressionContainer' (node) {
87+
if (node.parent.type === 'VDirectiveKey') {
88+
// We cannot use `.` in dynamic arguments because the right of the `.` becomes a modifier.
89+
// For example, In `:[this.prop]` case, `:[this` is an argument and `prop]` is a modifier.
90+
return
91+
}
8792
if (node.references) {
8893
for (const reference of node.references) {
8994
if (!scope.nodes.some(el => el.name === reference.id.name)) {

lib/rules/use-v-on-exact.js

+8-5
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,19 @@ const SYSTEM_MODIFIERS = new Set(['ctrl', 'shift', 'alt', 'meta'])
2020
* Finds and returns all keys for event directives
2121
*
2222
* @param {array} attributes Element attributes
23+
* @param {SourceCode} sourceCode The source code object.
2324
* @returns {array[object]} [{ name, node, modifiers }]
2425
*/
25-
function getEventDirectives (attributes) {
26+
function getEventDirectives (attributes, sourceCode) {
2627
return attributes
2728
.filter(attribute =>
2829
attribute.directive &&
29-
attribute.key.name === 'on'
30+
attribute.key.name.name === 'on'
3031
)
3132
.map(attribute => ({
32-
name: attribute.key.argument,
33+
name: attribute.key.argument ? sourceCode.getText(attribute.key.argument) : '',
3334
node: attribute.key,
34-
modifiers: attribute.key.modifiers
35+
modifiers: attribute.key.modifiers.map(modifier => modifier.name)
3536
}))
3637
}
3738

@@ -149,12 +150,14 @@ module.exports = {
149150
* @returns {Object} AST event handlers.
150151
*/
151152
create (context) {
153+
const sourceCode = context.getSourceCode()
154+
152155
return utils.defineTemplateBodyVisitor(context, {
153156
VStartTag (node) {
154157
if (node.attributes.length === 0) return
155158

156159
const isCustomComponent = utils.isCustomComponent(node.parent)
157-
let events = getEventDirectives(node.attributes)
160+
let events = getEventDirectives(node.attributes, sourceCode)
158161

159162
if (isCustomComponent) {
160163
// For components consider only events with `native` modifier

lib/rules/v-bind-style.js

+28-9
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,42 @@ module.exports = {
3030
},
3131

3232
create (context) {
33-
const shorthand = context.options[0] !== 'longform'
33+
const preferShorthand = context.options[0] !== 'longform'
3434

3535
return utils.defineTemplateBodyVisitor(context, {
36-
"VAttribute[directive=true][key.name='bind'][key.argument!=null]" (node) {
37-
if (node.key.shorthand === shorthand) {
36+
"VAttribute[directive=true][key.name.name='bind'][key.argument!=null]" (node) {
37+
const shorthandProp = node.key.name.rawName === '.'
38+
const shorthand = node.key.name.rawName === ':' || shorthandProp
39+
if (shorthand === preferShorthand) {
3840
return
3941
}
4042

4143
context.report({
4244
node,
4345
loc: node.loc,
44-
message: shorthand
45-
? "Unexpected 'v-bind' before ':'."
46-
: "Expected 'v-bind' before ':'.",
47-
fix: (fixer) => shorthand
48-
? fixer.removeRange([node.range[0], node.range[0] + 6])
49-
: fixer.insertTextBefore(node, 'v-bind')
46+
message:
47+
preferShorthand ? "Unexpected 'v-bind' before ':'."
48+
: shorthandProp ? "Expected 'v-bind:' instead of '.'."
49+
/* otherwise */ : "Expected 'v-bind' before ':'.",
50+
* fix (fixer) {
51+
if (preferShorthand) {
52+
yield fixer.remove(node.key.name)
53+
} else {
54+
yield fixer.insertTextBefore(node, 'v-bind')
55+
56+
if (shorthandProp) {
57+
// Replace `.` by `:`.
58+
yield fixer.replaceText(node.key.name, ':')
59+
60+
// Insert `.prop` modifier if it doesn't exist.
61+
const modifier = node.key.modifiers[0]
62+
const isAutoGeneratedPropModifier = modifier.name === 'prop' && modifier.rawName === ''
63+
if (isAutoGeneratedPropModifier) {
64+
yield fixer.insertTextBefore(modifier, '.prop')
65+
}
66+
}
67+
}
68+
}
5069
})
5170
}
5271
})

lib/rules/v-on-function-call.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ module.exports = {
3131
const always = context.options[0] === 'always'
3232

3333
return utils.defineTemplateBodyVisitor(context, {
34-
"VAttribute[directive=true][key.name='on'][key.argument!=null] > VExpressionContainer > Identifier" (node) {
34+
"VAttribute[directive=true][key.name.name='on'][key.argument!=null] > VExpressionContainer > Identifier" (node) {
3535
if (!always) return
3636
context.report({
3737
node,
@@ -40,7 +40,7 @@ module.exports = {
4040
})
4141
},
4242

43-
"VAttribute[directive=true][key.name='on'][key.argument!=null] VOnExpression > ExpressionStatement > *" (node) {
43+
"VAttribute[directive=true][key.name.name='on'][key.argument!=null] VOnExpression > ExpressionStatement > *" (node) {
4444
if (!always && node.type === 'CallExpression' && node.arguments.length === 0) {
4545
context.report({
4646
node,

lib/rules/v-on-style.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,23 @@ module.exports = {
3030
},
3131

3232
create (context) {
33-
const shorthand = context.options[0] !== 'longform'
33+
const preferShorthand = context.options[0] !== 'longform'
3434

3535
return utils.defineTemplateBodyVisitor(context, {
36-
"VAttribute[directive=true][key.name='on'][key.argument!=null]" (node) {
37-
if (node.key.shorthand === shorthand) {
36+
"VAttribute[directive=true][key.name.name='on'][key.argument!=null]" (node) {
37+
const shorthand = node.key.name.rawName === '@'
38+
if (shorthand === preferShorthand) {
3839
return
3940
}
4041

4142
const pos = node.range[0]
4243
context.report({
4344
node,
4445
loc: node.loc,
45-
message: shorthand
46+
message: preferShorthand
4647
? "Expected '@' instead of 'v-on:'."
4748
: "Expected 'v-on:' instead of '@'.",
48-
fix: (fixer) => shorthand
49+
fix: (fixer) => preferShorthand
4950
? fixer.replaceTextRange([pos, pos + 5], '@')
5051
: fixer.replaceTextRange([pos, pos + 1], 'v-on:')
5152
})

0 commit comments

Comments
 (0)