no-shared-component-data.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. /**
  2. * @fileoverview Enforces component's data property to be a function.
  3. * @author Armano
  4. */
  5. 'use strict'
  6. const utils = require('../utils')
  7. function isOpenParen (token) {
  8. return token.type === 'Punctuator' && token.value === '('
  9. }
  10. function isCloseParen (token) {
  11. return token.type === 'Punctuator' && token.value === ')'
  12. }
  13. function getFirstAndLastTokens (node, sourceCode) {
  14. let first = sourceCode.getFirstToken(node)
  15. let last = sourceCode.getLastToken(node)
  16. // If the value enclosed by parentheses, update the 'first' and 'last' by the parentheses.
  17. while (true) {
  18. const prev = sourceCode.getTokenBefore(first)
  19. const next = sourceCode.getTokenAfter(last)
  20. if (isOpenParen(prev) && isCloseParen(next)) {
  21. first = prev
  22. last = next
  23. } else {
  24. return { first, last }
  25. }
  26. }
  27. }
  28. // ------------------------------------------------------------------------------
  29. // Rule Definition
  30. // ------------------------------------------------------------------------------
  31. module.exports = {
  32. meta: {
  33. docs: {
  34. description: "enforce component's data property to be a function",
  35. category: 'essential',
  36. url: 'https://github.com/vuejs/eslint-plugin-vue/blob/v4.7.1/docs/rules/no-shared-component-data.md'
  37. },
  38. fixable: 'code',
  39. schema: []
  40. },
  41. create (context) {
  42. const sourceCode = context.getSourceCode()
  43. return utils.executeOnVueComponent(context, (obj) => {
  44. obj.properties
  45. .filter(p =>
  46. p.type === 'Property' &&
  47. p.key.type === 'Identifier' &&
  48. p.key.name === 'data' &&
  49. p.value.type !== 'FunctionExpression' &&
  50. p.value.type !== 'ArrowFunctionExpression' &&
  51. p.value.type !== 'Identifier'
  52. )
  53. .forEach(p => {
  54. context.report({
  55. node: p,
  56. message: '`data` property in component must be a function.',
  57. fix (fixer) {
  58. const tokens = getFirstAndLastTokens(p.value, sourceCode)
  59. // If we can upgrade requirements to `eslint@>4.1.0`, this code can be replaced by:
  60. // return [
  61. // fixer.insertTextBefore(tokens.first, 'function() {\nreturn '),
  62. // fixer.insertTextAfter(tokens.last, ';\n}')
  63. // ]
  64. // See: https://eslint.org/blog/2017/06/eslint-v4.1.0-released#applying-multiple-autofixes-simultaneously
  65. const range = [tokens.first.range[0], tokens.last.range[1]]
  66. const valueText = sourceCode.text.slice(range[0], range[1])
  67. const replacement = `function() {\nreturn ${valueText};\n}`
  68. return fixer.replaceTextRange(range, replacement)
  69. }
  70. })
  71. })
  72. })
  73. }
  74. }