require-prop-comment.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /**
  2. * @author CZB
  3. * See LICENSE file in root directory for full license.
  4. */
  5. 'use strict'
  6. const utils = require('../utils')
  7. const { isBlockComment, isJSDocComment } = require('../utils/comments.js')
  8. module.exports = {
  9. meta: {
  10. type: 'suggestion',
  11. docs: {
  12. description: 'require props to have a comment',
  13. categories: undefined,
  14. url: 'https://eslint.vuejs.org/rules/require-prop-comment.html'
  15. },
  16. fixable: null,
  17. schema: [
  18. {
  19. type: 'object',
  20. properties: {
  21. type: { enum: ['JSDoc', 'line', 'block', 'any'] }
  22. },
  23. additionalProperties: false
  24. }
  25. ],
  26. messages: {
  27. requireAnyComment: 'The "{{name}}" property should have a comment.',
  28. requireLineComment: 'The "{{name}}" property should have a line comment.',
  29. requireBlockComment:
  30. 'The "{{name}}" property should have a block comment.',
  31. requireJSDocComment:
  32. 'The "{{name}}" property should have a JSDoc comment.'
  33. }
  34. },
  35. /** @param {RuleContext} context */
  36. create(context) {
  37. /** @type {{type?: "JSDoc" | "line" | "block" | "any"}|undefined} */
  38. const schema = context.options[0]
  39. const type = (schema && schema.type) || 'JSDoc'
  40. const sourceCode = context.getSourceCode()
  41. /** @param {Comment | undefined} comment */
  42. const verifyBlock = (comment) =>
  43. comment && isBlockComment(comment) ? undefined : 'requireBlockComment'
  44. /** @param {Comment | undefined} comment */
  45. const verifyLine = (comment) =>
  46. comment && comment.type === 'Line' ? undefined : 'requireLineComment'
  47. /** @param {Comment | undefined} comment */
  48. const verifyAny = (comment) => (comment ? undefined : 'requireAnyComment')
  49. /** @param {Comment | undefined} comment */
  50. const verifyJSDoc = (comment) =>
  51. comment && isJSDocComment(comment) ? undefined : 'requireJSDocComment'
  52. /**
  53. * @param {import('../utils').ComponentProp[]} props
  54. */
  55. function verifyProps(props) {
  56. for (const prop of props) {
  57. if (!prop.propName) {
  58. continue
  59. }
  60. const precedingComments = sourceCode.getCommentsBefore(prop.node)
  61. const lastPrecedingComment =
  62. precedingComments.length > 0
  63. ? precedingComments[precedingComments.length - 1]
  64. : undefined
  65. /** @type {string|undefined} */
  66. let messageId
  67. switch (type) {
  68. case 'block':
  69. messageId = verifyBlock(lastPrecedingComment)
  70. break
  71. case 'line':
  72. messageId = verifyLine(lastPrecedingComment)
  73. break
  74. case 'any':
  75. messageId = verifyAny(lastPrecedingComment)
  76. break
  77. default:
  78. messageId = verifyJSDoc(lastPrecedingComment)
  79. break
  80. }
  81. if (!messageId) {
  82. continue
  83. }
  84. context.report({
  85. node: prop.node,
  86. messageId,
  87. data: {
  88. name: prop.propName
  89. }
  90. })
  91. }
  92. }
  93. return utils.compositingVisitors(
  94. utils.defineScriptSetupVisitor(context, {
  95. onDefinePropsEnter(_node, props) {
  96. verifyProps(props)
  97. }
  98. }),
  99. utils.defineVueVisitor(context, {
  100. onVueObjectEnter(node) {
  101. verifyProps(utils.getComponentPropsFromOptions(node))
  102. }
  103. })
  104. )
  105. }
  106. }