Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

155 строки
5.1 KiB

  1. /**
  2. * @fileoverview Enforce consistent usage of destructuring assignment of props, state, and context.
  3. **/
  4. 'use strict';
  5. const Components = require('../util/Components');
  6. const docsUrl = require('../util/docsUrl');
  7. const DEFAULT_OPTION = 'always';
  8. module.exports = {
  9. meta: {
  10. docs: {
  11. description: 'Enforce consistent usage of destructuring assignment of props, state, and context',
  12. category: 'Stylistic Issues',
  13. recommended: false,
  14. url: docsUrl('destructuring-assignment')
  15. },
  16. schema: [{
  17. type: 'string',
  18. enum: [
  19. 'always',
  20. 'never'
  21. ]
  22. }, {
  23. type: 'object',
  24. properties: {
  25. ignoreClassFields: {
  26. type: 'boolean'
  27. }
  28. },
  29. additionalProperties: false
  30. }]
  31. },
  32. create: Components.detect((context, components, utils) => {
  33. const configuration = context.options[0] || DEFAULT_OPTION;
  34. const ignoreClassFields = context.options[1] && context.options[1].ignoreClassFields === true || false;
  35. /**
  36. * Checks if a prop is being assigned a value props.bar = 'bar'
  37. * @param {ASTNode} node The AST node being checked.
  38. * @returns {Boolean}
  39. */
  40. function isAssignmentToProp(node) {
  41. return (
  42. node.parent &&
  43. node.parent.type === 'AssignmentExpression' &&
  44. node.parent.left === node
  45. );
  46. }
  47. /**
  48. * @param {ASTNode} node We expect either an ArrowFunctionExpression,
  49. * FunctionDeclaration, or FunctionExpression
  50. */
  51. function handleStatelessComponent(node) {
  52. const destructuringProps = node.params && node.params[0] && node.params[0].type === 'ObjectPattern';
  53. const destructuringContext = node.params && node.params[1] && node.params[1].type === 'ObjectPattern';
  54. if (destructuringProps && components.get(node) && configuration === 'never') {
  55. context.report({
  56. node: node,
  57. message: 'Must never use destructuring props assignment in SFC argument'
  58. });
  59. } else if (destructuringContext && components.get(node) && configuration === 'never') {
  60. context.report({
  61. node: node,
  62. message: 'Must never use destructuring context assignment in SFC argument'
  63. });
  64. }
  65. }
  66. function handleSFCUsage(node) {
  67. // props.aProp || context.aProp
  68. const isPropUsed = (node.object.name === 'props' || node.object.name === 'context') && !isAssignmentToProp(node);
  69. if (isPropUsed && configuration === 'always') {
  70. context.report({
  71. node: node,
  72. message: `Must use destructuring ${node.object.name} assignment`
  73. });
  74. }
  75. }
  76. function handleClassUsage(node) {
  77. // this.props.Aprop || this.context.aProp || this.state.aState
  78. const isPropUsed = (
  79. node.object.type === 'MemberExpression' && node.object.object.type === 'ThisExpression' &&
  80. (node.object.property.name === 'props' || node.object.property.name === 'context' || node.object.property.name === 'state') &&
  81. !isAssignmentToProp(node)
  82. );
  83. if (
  84. isPropUsed && configuration === 'always' &&
  85. !(ignoreClassFields && node.parent.type === 'ClassProperty')
  86. ) {
  87. context.report({
  88. node: node,
  89. message: `Must use destructuring ${node.object.property.name} assignment`
  90. });
  91. }
  92. }
  93. return {
  94. FunctionDeclaration: handleStatelessComponent,
  95. ArrowFunctionExpression: handleStatelessComponent,
  96. FunctionExpression: handleStatelessComponent,
  97. MemberExpression: function(node) {
  98. const SFCComponent = components.get(context.getScope(node).block);
  99. const classComponent = utils.getParentComponent(node);
  100. if (SFCComponent) {
  101. handleSFCUsage(node);
  102. }
  103. if (classComponent) {
  104. handleClassUsage(node, classComponent);
  105. }
  106. },
  107. VariableDeclarator: function(node) {
  108. const classComponent = utils.getParentComponent(node);
  109. const SFCComponent = components.get(context.getScope(node).block);
  110. const destructuring = (node.init && node.id && node.id.type === 'ObjectPattern');
  111. // let {foo} = props;
  112. const destructuringSFC = destructuring && (node.init.name === 'props' || node.init.name === 'context');
  113. // let {foo} = this.props;
  114. const destructuringClass = destructuring && node.init.object && node.init.object.type === 'ThisExpression' && (
  115. node.init.property.name === 'props' || node.init.property.name === 'context' || node.init.property.name === 'state'
  116. );
  117. if (SFCComponent && destructuringSFC && configuration === 'never') {
  118. context.report({
  119. node: node,
  120. message: `Must never use destructuring ${node.init.name} assignment`
  121. });
  122. }
  123. if (
  124. classComponent && destructuringClass && configuration === 'never' &&
  125. !(ignoreClassFields && node.parent.type === 'ClassProperty')
  126. ) {
  127. context.report({
  128. node: node,
  129. message: `Must never use destructuring ${node.init.property.name} assignment`
  130. });
  131. }
  132. }
  133. };
  134. })
  135. };