项目原始demo,不改动
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

no-param-reassign.js 6.1 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /**
  2. * @fileoverview Disallow reassignment of function parameters.
  3. * @author Nat Burns
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Rule Definition
  8. //------------------------------------------------------------------------------
  9. const stopNodePattern = /(?:Statement|Declaration|Function(?:Expression)?|Program)$/;
  10. module.exports = {
  11. meta: {
  12. docs: {
  13. description: "disallow reassigning `function` parameters",
  14. category: "Best Practices",
  15. recommended: false,
  16. url: "https://eslint.org/docs/rules/no-param-reassign"
  17. },
  18. schema: [
  19. {
  20. oneOf: [
  21. {
  22. type: "object",
  23. properties: {
  24. props: {
  25. enum: [false]
  26. }
  27. },
  28. additionalProperties: false
  29. },
  30. {
  31. type: "object",
  32. properties: {
  33. props: {
  34. enum: [true]
  35. },
  36. ignorePropertyModificationsFor: {
  37. type: "array",
  38. items: {
  39. type: "string"
  40. },
  41. uniqueItems: true
  42. }
  43. },
  44. additionalProperties: false
  45. }
  46. ]
  47. }
  48. ]
  49. },
  50. create(context) {
  51. const props = context.options[0] && Boolean(context.options[0].props);
  52. const ignoredPropertyAssignmentsFor = context.options[0] && context.options[0].ignorePropertyModificationsFor || [];
  53. /**
  54. * Checks whether or not the reference modifies properties of its variable.
  55. * @param {Reference} reference - A reference to check.
  56. * @returns {boolean} Whether or not the reference modifies properties of its variable.
  57. */
  58. function isModifyingProp(reference) {
  59. let node = reference.identifier;
  60. let parent = node.parent;
  61. while (parent && !stopNodePattern.test(parent.type)) {
  62. switch (parent.type) {
  63. // e.g. foo.a = 0;
  64. case "AssignmentExpression":
  65. return parent.left === node;
  66. // e.g. ++foo.a;
  67. case "UpdateExpression":
  68. return true;
  69. // e.g. delete foo.a;
  70. case "UnaryExpression":
  71. if (parent.operator === "delete") {
  72. return true;
  73. }
  74. break;
  75. // EXCLUDES: e.g. cache.get(foo.a).b = 0;
  76. case "CallExpression":
  77. if (parent.callee !== node) {
  78. return false;
  79. }
  80. break;
  81. // EXCLUDES: e.g. cache[foo.a] = 0;
  82. case "MemberExpression":
  83. if (parent.property === node) {
  84. return false;
  85. }
  86. break;
  87. // EXCLUDES: e.g. ({ [foo]: a }) = bar;
  88. case "Property":
  89. if (parent.key === node) {
  90. return false;
  91. }
  92. break;
  93. // no default
  94. }
  95. node = parent;
  96. parent = node.parent;
  97. }
  98. return false;
  99. }
  100. /**
  101. * Reports a reference if is non initializer and writable.
  102. * @param {Reference} reference - A reference to check.
  103. * @param {int} index - The index of the reference in the references.
  104. * @param {Reference[]} references - The array that the reference belongs to.
  105. * @returns {void}
  106. */
  107. function checkReference(reference, index, references) {
  108. const identifier = reference.identifier;
  109. if (identifier &&
  110. !reference.init &&
  111. /*
  112. * Destructuring assignments can have multiple default value,
  113. * so possibly there are multiple writeable references for the same identifier.
  114. */
  115. (index === 0 || references[index - 1].identifier !== identifier)
  116. ) {
  117. if (reference.isWrite()) {
  118. context.report({ node: identifier, message: "Assignment to function parameter '{{name}}'.", data: { name: identifier.name } });
  119. } else if (props && isModifyingProp(reference) && ignoredPropertyAssignmentsFor.indexOf(identifier.name) === -1) {
  120. context.report({ node: identifier, message: "Assignment to property of function parameter '{{name}}'.", data: { name: identifier.name } });
  121. }
  122. }
  123. }
  124. /**
  125. * Finds and reports references that are non initializer and writable.
  126. * @param {Variable} variable - A variable to check.
  127. * @returns {void}
  128. */
  129. function checkVariable(variable) {
  130. if (variable.defs[0].type === "Parameter") {
  131. variable.references.forEach(checkReference);
  132. }
  133. }
  134. /**
  135. * Checks parameters of a given function node.
  136. * @param {ASTNode} node - A function node to check.
  137. * @returns {void}
  138. */
  139. function checkForFunction(node) {
  140. context.getDeclaredVariables(node).forEach(checkVariable);
  141. }
  142. return {
  143. // `:exit` is needed for the `node.parent` property of identifier nodes.
  144. "FunctionDeclaration:exit": checkForFunction,
  145. "FunctionExpression:exit": checkForFunction,
  146. "ArrowFunctionExpression:exit": checkForFunction
  147. };
  148. }
  149. };