require-emit-validator.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /**
  2. * @fileoverview Emit definitions should be detailed
  3. * @author Pig Fang
  4. */
  5. 'use strict'
  6. const utils = require('../utils')
  7. /**
  8. * @typedef {import('../utils').ComponentArrayEmit} ComponentArrayEmit
  9. * @typedef {import('../utils').ComponentObjectEmit} ComponentObjectEmit
  10. * @typedef {import('../utils').ComponentTypeEmit} ComponentTypeEmit
  11. */
  12. // ------------------------------------------------------------------------------
  13. // Rule Definition
  14. // ------------------------------------------------------------------------------
  15. module.exports = {
  16. meta: {
  17. hasSuggestions: true,
  18. type: 'suggestion',
  19. docs: {
  20. description: 'require type definitions in emits',
  21. categories: undefined,
  22. url: 'https://eslint.vuejs.org/rules/require-emit-validator.html'
  23. },
  24. fixable: null,
  25. messages: {
  26. missing: 'Emit "{{name}}" should define at least its validator function.',
  27. skipped:
  28. 'Emit "{{name}}" should not skip validation, or you may define a validator function with no parameters.',
  29. emptyValidation: 'Replace with a validator function with no parameters.'
  30. },
  31. schema: []
  32. },
  33. /** @param {RuleContext} context */
  34. create(context) {
  35. // ----------------------------------------------------------------------
  36. // Helpers
  37. // ----------------------------------------------------------------------
  38. /**
  39. * @param {ComponentArrayEmit|ComponentObjectEmit} emit
  40. */
  41. function checker({ value, node, emitName }) {
  42. const hasType =
  43. !!value &&
  44. (value.type === 'ArrowFunctionExpression' ||
  45. value.type === 'FunctionExpression' ||
  46. // validator may from outer scope
  47. value.type === 'Identifier')
  48. if (!hasType) {
  49. const name =
  50. emitName ||
  51. (node.type === 'Identifier' && node.name) ||
  52. 'Unknown emit'
  53. if (value && value.type === 'Literal' && value.value === null) {
  54. context.report({
  55. node,
  56. messageId: 'skipped',
  57. data: { name },
  58. suggest: [
  59. {
  60. messageId: 'emptyValidation',
  61. fix: (fixer) => fixer.replaceText(value, '() => true')
  62. }
  63. ]
  64. })
  65. return
  66. }
  67. context.report({
  68. node,
  69. messageId: 'missing',
  70. data: { name }
  71. })
  72. }
  73. }
  74. // ----------------------------------------------------------------------
  75. // Public
  76. // ----------------------------------------------------------------------
  77. return utils.compositingVisitors(
  78. utils.executeOnVue(context, (obj) => {
  79. utils.getComponentEmits(obj).forEach(checker)
  80. }),
  81. utils.defineScriptSetupVisitor(context, {
  82. onDefineEmitsEnter(_node, emits) {
  83. for (const emit of emits) {
  84. if (emit.type === 'type') {
  85. continue
  86. }
  87. checker(emit)
  88. }
  89. }
  90. })
  91. )
  92. }
  93. }