no-boolean-default.js 3.4 KB

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