no-multiple-slot-args.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /**
  2. * @author Yosuke Ota
  3. * See LICENSE file in root directory for full license.
  4. */
  5. 'use strict'
  6. const utils = require('../utils')
  7. const { findVariable } = require('@eslint-community/eslint-utils')
  8. module.exports = {
  9. meta: {
  10. type: 'problem',
  11. docs: {
  12. description: 'disallow to pass multiple arguments to scoped slots',
  13. categories: ['vue3-recommended', 'vue2-recommended'],
  14. url: 'https://eslint.vuejs.org/rules/no-multiple-slot-args.html'
  15. },
  16. fixable: null,
  17. schema: [],
  18. messages: {
  19. unexpected: 'Unexpected multiple arguments.',
  20. unexpectedSpread: 'Unexpected spread argument.'
  21. }
  22. },
  23. /** @param {RuleContext} context */
  24. create(context) {
  25. /**
  26. * Verify the given node
  27. * @param {MemberExpression | Identifier} node The node to verify
  28. */
  29. function verify(node) {
  30. const parent = node.parent
  31. if (
  32. parent.type === 'VariableDeclarator' &&
  33. parent.id.type === 'Identifier'
  34. ) {
  35. // const foo = this.$scopedSlots.foo
  36. verifyReferences(parent.id)
  37. return
  38. }
  39. if (
  40. parent.type === 'AssignmentExpression' &&
  41. parent.right === node &&
  42. parent.left.type === 'Identifier'
  43. ) {
  44. // foo = this.$scopedSlots.foo
  45. verifyReferences(parent.left)
  46. return
  47. }
  48. if (parent.type !== 'CallExpression' || parent.arguments.includes(node)) {
  49. return
  50. }
  51. if (parent.arguments.length === 0) {
  52. return
  53. }
  54. if (parent.arguments.length > 1) {
  55. context.report({
  56. node: parent.arguments[1],
  57. messageId: 'unexpected'
  58. })
  59. }
  60. if (parent.arguments[0].type === 'SpreadElement') {
  61. context.report({
  62. node: parent.arguments[0],
  63. messageId: 'unexpectedSpread'
  64. })
  65. }
  66. }
  67. /**
  68. * Verify the references of the given node.
  69. * @param {Identifier} node The node to verify
  70. */
  71. function verifyReferences(node) {
  72. const variable = findVariable(utils.getScope(context, node), node)
  73. if (!variable) {
  74. return
  75. }
  76. for (const reference of variable.references) {
  77. if (!reference.isRead()) {
  78. continue
  79. }
  80. /** @type {Identifier} */
  81. const id = reference.identifier
  82. verify(id)
  83. }
  84. }
  85. return utils.defineVueVisitor(context, {
  86. /** @param {MemberExpression} node */
  87. MemberExpression(node) {
  88. const object = utils.skipChainExpression(node.object)
  89. if (object.type !== 'MemberExpression') {
  90. return
  91. }
  92. const name = utils.getStaticPropertyName(object)
  93. if (!name || (name !== '$slots' && name !== '$scopedSlots')) {
  94. return
  95. }
  96. if (!utils.isThis(object.object, context)) {
  97. return
  98. }
  99. verify(node)
  100. }
  101. })
  102. }
  103. }