no-boolean-default.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /**
  2. * @fileoverview Prevents boolean defaults from being set
  3. * @author Hiroki Osame
  4. */
  5. 'use strict'
  6. const utils = require('../utils')
  7. /**
  8. * @typedef {import('../utils').ComponentArrayProp} ComponentArrayProp
  9. * @typedef {import('../utils').ComponentObjectProp} ComponentObjectProp
  10. * @typedef {import('../utils').ComponentTypeProp} ComponentTypeProp
  11. */
  12. // ------------------------------------------------------------------------------
  13. // Rule Definition
  14. // ------------------------------------------------------------------------------
  15. /**
  16. * @param {Property | SpreadElement} prop
  17. */
  18. function isBooleanProp(prop) {
  19. return (
  20. prop.type === 'Property' &&
  21. prop.key.type === 'Identifier' &&
  22. prop.key.name === 'type' &&
  23. prop.value.type === 'Identifier' &&
  24. prop.value.name === 'Boolean'
  25. )
  26. }
  27. /**
  28. * @param {ObjectExpression} propDefValue
  29. */
  30. function getDefaultNode(propDefValue) {
  31. return utils.findProperty(propDefValue, 'default')
  32. }
  33. module.exports = {
  34. meta: {
  35. type: 'suggestion',
  36. docs: {
  37. description: 'disallow boolean defaults',
  38. categories: undefined,
  39. url: 'https://eslint.vuejs.org/rules/no-boolean-default.html'
  40. },
  41. fixable: 'code',
  42. schema: [
  43. {
  44. enum: ['default-false', 'no-default']
  45. }
  46. ]
  47. },
  48. /** @param {RuleContext} context */
  49. create(context) {
  50. const booleanType = context.options[0] || 'no-default'
  51. /**
  52. * @param {ComponentArrayProp | ComponentObjectProp | ComponentTypeProp} prop
  53. * @param { { [key: string]: Expression | undefined } } [withDefaultsExpressions]
  54. */
  55. function processProp(prop, withDefaultsExpressions) {
  56. if (prop.type === 'object') {
  57. if (prop.value.type !== 'ObjectExpression') {
  58. return
  59. }
  60. if (!prop.value.properties.some(isBooleanProp)) {
  61. return
  62. }
  63. const defaultNode = getDefaultNode(prop.value)
  64. if (!defaultNode) {
  65. return
  66. }
  67. verifyDefaultExpression(defaultNode.value)
  68. } else if (prop.type === 'type') {
  69. if (prop.types.length !== 1 || prop.types[0] !== 'Boolean') {
  70. return
  71. }
  72. const defaultNode =
  73. withDefaultsExpressions && withDefaultsExpressions[prop.propName]
  74. if (!defaultNode) {
  75. return
  76. }
  77. verifyDefaultExpression(defaultNode)
  78. }
  79. }
  80. /**
  81. * @param {(ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[]} props
  82. * @param { { [key: string]: Expression | undefined } } [withDefaultsExpressions]
  83. */
  84. function processProps(props, withDefaultsExpressions) {
  85. for (const prop of props) {
  86. processProp(prop, withDefaultsExpressions)
  87. }
  88. }
  89. /**
  90. * @param {Expression} defaultNode
  91. */
  92. function verifyDefaultExpression(defaultNode) {
  93. switch (booleanType) {
  94. case 'no-default':
  95. context.report({
  96. node: defaultNode,
  97. message:
  98. 'Boolean prop should not set a default (Vue defaults it to false).'
  99. })
  100. break
  101. case 'default-false':
  102. if (defaultNode.type !== 'Literal' || defaultNode.value !== false) {
  103. context.report({
  104. node: defaultNode,
  105. message: 'Boolean prop should only be defaulted to false.'
  106. })
  107. }
  108. break
  109. }
  110. }
  111. return utils.compositingVisitors(
  112. utils.executeOnVueComponent(context, (obj) => {
  113. processProps(utils.getComponentProps(obj))
  114. }),
  115. utils.defineScriptSetupVisitor(context, {
  116. onDefinePropsEnter(node, props) {
  117. processProps(props, utils.getWithDefaultsPropExpressions(node))
  118. }
  119. })
  120. )
  121. }
  122. }