prefer-true-attribute-shorthand.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /**
  2. * @author Pig Fang
  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: 'suggestion',
  16. docs: {
  17. description:
  18. 'require shorthand form attribute when `v-bind` value is `true`',
  19. categories: undefined,
  20. url: 'https://eslint.vuejs.org/rules/prefer-true-attribute-shorthand.html'
  21. },
  22. fixable: null,
  23. hasSuggestions: true,
  24. schema: [{ enum: ['always', 'never'] }],
  25. messages: {
  26. expectShort:
  27. "Boolean prop with 'true' value should be written in shorthand form.",
  28. expectLong:
  29. "Boolean prop with 'true' value should be written in long form.",
  30. rewriteIntoShort: 'Rewrite this prop into shorthand form.',
  31. rewriteIntoLongVueProp:
  32. 'Rewrite this prop into long-form Vue component prop.',
  33. rewriteIntoLongHtmlAttr:
  34. 'Rewrite this prop into long-form HTML attribute.'
  35. }
  36. },
  37. /** @param {RuleContext} context */
  38. create(context) {
  39. /** @type {'always' | 'never'} */
  40. const option = context.options[0] || 'always'
  41. return utils.defineTemplateBodyVisitor(context, {
  42. VAttribute(node) {
  43. if (!utils.isCustomComponent(node.parent.parent)) {
  44. return
  45. }
  46. if (option === 'never' && !node.directive && !node.value) {
  47. context.report({
  48. node,
  49. messageId: 'expectLong',
  50. suggest: [
  51. {
  52. messageId: 'rewriteIntoLongVueProp',
  53. fix: (fixer) =>
  54. fixer.replaceText(node, `:${node.key.rawName}="true"`)
  55. },
  56. {
  57. messageId: 'rewriteIntoLongHtmlAttr',
  58. fix: (fixer) =>
  59. fixer.replaceText(
  60. node,
  61. `${node.key.rawName}="${node.key.rawName}"`
  62. )
  63. }
  64. ]
  65. })
  66. return
  67. }
  68. if (option !== 'always') {
  69. return
  70. }
  71. if (
  72. !node.directive ||
  73. !node.value ||
  74. !node.value.expression ||
  75. node.value.expression.type !== 'Literal' ||
  76. node.value.expression.value !== true
  77. ) {
  78. return
  79. }
  80. const { argument } = node.key
  81. if (!argument) {
  82. return
  83. }
  84. context.report({
  85. node,
  86. messageId: 'expectShort',
  87. suggest: [
  88. {
  89. messageId: 'rewriteIntoShort',
  90. fix: (fixer) => {
  91. const sourceCode = context.getSourceCode()
  92. return fixer.replaceText(node, sourceCode.getText(argument))
  93. }
  94. }
  95. ]
  96. })
  97. }
  98. })
  99. }
  100. }