Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: vuejs/eslint-plugin-vue
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v4.0.0-beta.1
Choose a base ref
...
head repository: vuejs/eslint-plugin-vue
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v4.0.0-beta.2
Choose a head ref
  • 3 commits
  • 5 files changed
  • 2 contributors

Commits on Dec 3, 2017

  1. [Update] Improve the range of mustache-interpolation-spacing (#276)

    * Fix: improve range of mustache-interpolation-spacing
    
    * Chore: add linebreaks
    mysticatea authored and michalsnik committed Dec 3, 2017

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    3137c1f View commit details
  2. [Update] Make vue/no-shared-component-data fixable (#278)

    * Update: make vue/no-shared-component-data fixable
    
    * refactoring
    mysticatea authored and michalsnik committed Dec 3, 2017
    Copy the full SHA
    887045a View commit details
  3. 4.0.0-beta.2

    michalsnik committed Dec 3, 2017
    Copy the full SHA
    1ac12f5 View commit details
94 changes: 52 additions & 42 deletions lib/rules/mustache-interpolation-spacing.js
Original file line number Diff line number Diff line change
@@ -29,58 +29,68 @@ module.exports = {
},

create (context) {
const options = context.options[0]
const optSpaces = options !== 'never'
const template = context.parserServices.getTemplateBodyTokenStore && context.parserServices.getTemplateBodyTokenStore()

// ----------------------------------------------------------------------
// Helpers
// ----------------------------------------------------------------------

function checkTokens (leftToken, rightToken) {
if (leftToken.loc.end.line === rightToken.loc.start.line) {
const spaces = rightToken.loc.start.column - leftToken.loc.end.column
const noSpacesFound = spaces === 0

if (optSpaces === noSpacesFound) {
context.report({
node: rightToken,
loc: {
start: leftToken.loc.end,
end: rightToken.loc.start
},
message: 'Found {{spaces}} whitespaces, {{type}} expected.',
data: {
spaces: spaces === 0 ? 'none' : spaces,
type: optSpaces ? '1' : 'none'
},
fix: (fixer) => fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], optSpaces ? ' ' : '')
})
}
}
}
const options = context.options[0] || 'always'
const template =
context.parserServices.getTemplateBodyTokenStore &&
context.parserServices.getTemplateBodyTokenStore()

// ----------------------------------------------------------------------
// Public
// ----------------------------------------------------------------------

return utils.defineTemplateBodyVisitor(context, {
'VExpressionContainer[expression!=null]' (node) {
const tokens = template.getTokens(node, {
includeComments: true,
filter: token => token.type !== 'HTMLWhitespace' // When there is only whitespace between ignore it
})
const openBrace = template.getFirstToken(node)
const closeBrace = template.getLastToken(node)

if (
!openBrace ||
!closeBrace ||
openBrace.type !== 'VExpressionStart' ||
closeBrace.type !== 'VExpressionEnd'
) {
return
}

const startToken = tokens.shift()
if (!startToken || startToken.type !== 'VExpressionStart') return
const endToken = tokens.pop()
if (!endToken || endToken.type !== 'VExpressionEnd') return
const firstToken = template.getTokenAfter(openBrace, { includeComments: true })
const lastToken = template.getTokenBefore(closeBrace, { includeComments: true })

if (tokens.length > 0) {
checkTokens(startToken, tokens[0])
checkTokens(tokens[tokens.length - 1], endToken)
if (options === 'always') {
if (openBrace.range[1] === firstToken.range[0]) {
context.report({
node: openBrace,
message: "Expected 1 space after '{{', but not found.",
fix: (fixer) => fixer.insertTextAfter(openBrace, ' ')
})
}
if (closeBrace.range[0] === lastToken.range[1]) {
context.report({
node: closeBrace,
message: "Expected 1 space before '}}', but not found.",
fix: (fixer) => fixer.insertTextBefore(closeBrace, ' ')
})
}
} else {
checkTokens(startToken, endToken)
if (openBrace.range[1] !== firstToken.range[0]) {
context.report({
loc: {
start: openBrace.loc.start,
end: firstToken.loc.start
},
message: "Expected no space after '{{', but found.",
fix: (fixer) => fixer.removeRange([openBrace.range[1], firstToken.range[0]])
})
}
if (closeBrace.range[0] !== lastToken.range[1]) {
context.report({
loc: {
start: lastToken.loc.end,
end: closeBrace.loc.end
},
message: "Expected no space before '}}', but found.",
fix: (fixer) => fixer.removeRange([lastToken.range[1], closeBrace.range[0]])
})
}
}
}
})
51 changes: 44 additions & 7 deletions lib/rules/no-shared-component-data.js
Original file line number Diff line number Diff line change
@@ -6,10 +6,33 @@

const utils = require('../utils')

function isOpenParen (token) {
return token.type === 'Punctuator' && token.value === '('
}

function isCloseParen (token) {
return token.type === 'Punctuator' && token.value === ')'
}

function getFirstAndLastTokens (node, sourceCode) {
let first = sourceCode.getFirstToken(node)
let last = sourceCode.getLastToken(node)

// If the value enclosed by parentheses, update the 'first' and 'last' by the parentheses.
while (true) {
const prev = sourceCode.getTokenBefore(first)
const next = sourceCode.getTokenAfter(last)
if (isOpenParen(prev) && isCloseParen(next)) {
first = prev
last = next
} else {
return { first, last }
}
}
}

function create (context) {
// ----------------------------------------------------------------------
// Public
// ----------------------------------------------------------------------
const sourceCode = context.getSourceCode()

return utils.executeOnVueComponent(context, (obj) => {
obj.properties
@@ -21,10 +44,24 @@ function create (context) {
p.value.type !== 'ArrowFunctionExpression' &&
p.value.type !== 'Identifier'
)
.forEach(cp => {
.forEach(p => {
context.report({
node: cp.value,
message: '`data` property in component must be a function'
node: p,
message: '`data` property in component must be a function',
fix (fixer) {
const tokens = getFirstAndLastTokens(p.value, sourceCode)

// If we can upgrade requirements to `eslint@>4.1.0`, this code can be replaced by:
// return [
// fixer.insertTextBefore(tokens.first, 'function() {\nreturn '),
// fixer.insertTextAfter(tokens.last, ';\n}')
// ]
// See: https://eslint.org/blog/2017/06/eslint-v4.1.0-released#applying-multiple-autofixes-simultaneously
const range = [tokens.first.range[0], tokens.last.range[1]]
const valueText = sourceCode.text.slice(range[0], range[1])
const replacement = `function() {\nreturn ${valueText};\n}`
return fixer.replaceTextRange(range, replacement)
}
})
})
})
@@ -40,7 +77,7 @@ module.exports = {
description: "enforce component's data property to be a function",
category: 'essential'
},
fixable: null, // or "code" or "whitespace"
fixable: 'code',
schema: []
},

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eslint-plugin-vue",
"version": "4.0.0-beta.1",
"version": "4.0.0-beta.2",
"description": "Official ESLint plugin for Vue.js",
"main": "lib/index.js",
"scripts": {
53 changes: 16 additions & 37 deletions tests/lib/rules/mustache-interpolation-spacing.js
Original file line number Diff line number Diff line change
@@ -90,79 +90,58 @@ ruleTester.run('mustache-interpolation-spacing', rule, {
code: '<template><div>{{ text}}</div></template>',
output: '<template><div>{{ text }}</div></template>',
options: ['always'],
errors: [{
message: 'Found none whitespaces, 1 expected.',
type: 'VExpressionEnd'
}]
errors: ["Expected 1 space before '}}', but not found."]
},
{
filename: 'test.vue',
code: '<template><div>{{text }}</div></template>',
output: '<template><div>{{ text }}</div></template>',
options: ['always'],
errors: [{
message: 'Found none whitespaces, 1 expected.',
type: 'Identifier'
}]
errors: ["Expected 1 space after '{{', but not found."]
},
{
filename: 'test.vue',
code: '<template><div>{{ text}}</div></template>',
output: '<template><div>{{text}}</div></template>',
options: ['never'],
errors: [{
message: 'Found 1 whitespaces, none expected.',
type: 'Identifier'
}]
errors: ["Expected no space after '{{', but found."]
},
{
filename: 'test.vue',
code: '<template><div>{{text }}</div></template>',
output: '<template><div>{{text}}</div></template>',
options: ['never'],
errors: [{
message: 'Found 1 whitespaces, none expected.',
type: 'VExpressionEnd'
}]
errors: ["Expected no space before '}}', but found."]
},
{
filename: 'test.vue',
code: '<template><div>{{text}}</div></template>',
output: '<template><div>{{ text }}</div></template>',
options: ['always'],
errors: [{
message: 'Found none whitespaces, 1 expected.',
type: 'Identifier'
}, {
message: 'Found none whitespaces, 1 expected.',
type: 'VExpressionEnd'
}]
errors: [
"Expected 1 space after '{{', but not found.",
"Expected 1 space before '}}', but not found."
]
},
{
filename: 'test.vue',
code: '<template><div>{{ text }}</div></template>',
output: '<template><div>{{text}}</div></template>',
options: ['never'],
errors: [{
message: 'Found 1 whitespaces, none expected.',
type: 'Identifier'
}, {
message: 'Found 1 whitespaces, none expected.',
type: 'VExpressionEnd'
}]
errors: [
"Expected no space after '{{', but found.",
"Expected no space before '}}', but found."
]
},
{
filename: 'test.vue',
code: '<template><div>{{ text }}</div></template>',
output: '<template><div>{{text}}</div></template>',
options: ['never'],
errors: [{
message: 'Found 3 whitespaces, none expected.',
type: 'Identifier'
}, {
message: 'Found 3 whitespaces, none expected.',
type: 'VExpressionEnd'
}]
errors: [
"Expected no space after '{{', but found.",
"Expected no space before '}}', but found."
]
}
]
})
42 changes: 42 additions & 0 deletions tests/lib/rules/no-shared-component-data.js
Original file line number Diff line number Diff line change
@@ -130,6 +130,15 @@ ruleTester.run('no-shared-component-data', rule, {
}
})
`,
output: `
Vue.component('some-comp', {
data: function() {
return {
foo: 'bar'
};
}
})
`,
parserOptions,
errors: [{
message: '`data` property in component must be a function',
@@ -145,6 +154,39 @@ ruleTester.run('no-shared-component-data', rule, {
}
}
`,
output: `
export default {
data: function() {
return {
foo: 'bar'
};
}
}
`,
parserOptions,
errors: [{
message: '`data` property in component must be a function',
line: 3
}]
},
{
filename: 'test.vue',
code: `
export default {
data: /*a*/ (/*b*/{
foo: 'bar'
})
}
`,
output: `
export default {
data: /*a*/ function() {
return (/*b*/{
foo: 'bar'
});
}
}
`,
parserOptions,
errors: [{
message: '`data` property in component must be a function',