valid-v-memo.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /**
  2. * @author Yosuke Ota <https://github.com/ota-meshi>
  3. * See LICENSE file in root directory for full license.
  4. */
  5. 'use strict'
  6. // ------------------------------------------------------------------------------
  7. // Requirements
  8. // ------------------------------------------------------------------------------
  9. const utils = require('../utils')
  10. // ------------------------------------------------------------------------------
  11. // Rule Definition
  12. // ------------------------------------------------------------------------------
  13. module.exports = {
  14. meta: {
  15. type: 'problem',
  16. docs: {
  17. description: 'enforce valid `v-memo` directives',
  18. // TODO Switch to `vue3-essential` in the major version.
  19. // categories: ['vue3-essential'],
  20. categories: undefined,
  21. url: 'https://eslint.vuejs.org/rules/valid-v-memo.html'
  22. },
  23. fixable: null,
  24. schema: [],
  25. messages: {
  26. unexpectedArgument: "'v-memo' directives require no argument.",
  27. unexpectedModifier: "'v-memo' directives require no modifier.",
  28. expectedValue: "'v-memo' directives require that attribute value.",
  29. expectedArray:
  30. "'v-memo' directives require the attribute value to be an array.",
  31. insideVFor: "'v-memo' directive does not work inside 'v-for'."
  32. }
  33. },
  34. /** @param {RuleContext} context */
  35. create(context) {
  36. /** @type {VElement | null} */
  37. let vForElement = null
  38. return utils.defineTemplateBodyVisitor(context, {
  39. VElement(node) {
  40. if (!vForElement && utils.hasDirective(node, 'for')) {
  41. vForElement = node
  42. }
  43. },
  44. 'VElement:exit'(node) {
  45. if (vForElement === node) {
  46. vForElement = null
  47. }
  48. },
  49. /** @param {VDirective} node */
  50. "VAttribute[directive=true][key.name.name='memo']"(node) {
  51. if (vForElement && vForElement !== node.parent.parent) {
  52. context.report({
  53. node: node.key,
  54. messageId: 'insideVFor'
  55. })
  56. }
  57. if (node.key.argument) {
  58. context.report({
  59. node: node.key.argument,
  60. messageId: 'unexpectedArgument'
  61. })
  62. }
  63. if (node.key.modifiers.length > 0) {
  64. context.report({
  65. node,
  66. loc: {
  67. start: node.key.modifiers[0].loc.start,
  68. end: node.key.modifiers[node.key.modifiers.length - 1].loc.end
  69. },
  70. messageId: 'unexpectedModifier'
  71. })
  72. }
  73. if (!node.value || utils.isEmptyValueDirective(node, context)) {
  74. context.report({
  75. node,
  76. messageId: 'expectedValue'
  77. })
  78. return
  79. }
  80. if (!node.value.expression) {
  81. return
  82. }
  83. const expressions = [node.value.expression]
  84. let expression
  85. while ((expression = expressions.pop())) {
  86. if (
  87. expression.type === 'ObjectExpression' ||
  88. expression.type === 'ClassExpression' ||
  89. expression.type === 'ArrowFunctionExpression' ||
  90. expression.type === 'FunctionExpression' ||
  91. expression.type === 'Literal' ||
  92. expression.type === 'TemplateLiteral' ||
  93. expression.type === 'UnaryExpression' ||
  94. expression.type === 'BinaryExpression' ||
  95. expression.type === 'UpdateExpression'
  96. ) {
  97. context.report({
  98. node: expression,
  99. messageId: 'expectedArray'
  100. })
  101. } else if (expression.type === 'AssignmentExpression') {
  102. expressions.push(expression.right)
  103. } else if (expression.type === 'TSAsExpression') {
  104. expressions.push(expression.expression)
  105. } else if (expression.type === 'SequenceExpression') {
  106. expressions.push(
  107. expression.expressions[expression.expressions.length - 1]
  108. )
  109. } else if (expression.type === 'ConditionalExpression') {
  110. expressions.push(expression.consequent, expression.alternate)
  111. }
  112. }
  113. }
  114. })
  115. }
  116. }