params.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = convertFunctionParams;
  6. var _core = require("@babel/core");
  7. const buildDefaultParam = (0, _core.template)(`
  8. let VARIABLE_NAME =
  9. arguments.length > ARGUMENT_KEY && arguments[ARGUMENT_KEY] !== undefined ?
  10. arguments[ARGUMENT_KEY]
  11. :
  12. DEFAULT_VALUE;
  13. `);
  14. const buildLooseDefaultParam = (0, _core.template)(`
  15. if (ASSIGNMENT_IDENTIFIER === UNDEFINED) {
  16. ASSIGNMENT_IDENTIFIER = DEFAULT_VALUE;
  17. }
  18. `);
  19. const buildLooseDestructuredDefaultParam = (0, _core.template)(`
  20. let ASSIGNMENT_IDENTIFIER = PARAMETER_NAME === UNDEFINED ? DEFAULT_VALUE : PARAMETER_NAME ;
  21. `);
  22. const buildSafeArgumentsAccess = (0, _core.template)(`
  23. let $0 = arguments.length > $1 ? arguments[$1] : undefined;
  24. `);
  25. const iifeVisitor = {
  26. "ReferencedIdentifier|BindingIdentifier"(path, state) {
  27. const {
  28. scope,
  29. node
  30. } = path;
  31. const {
  32. name
  33. } = node;
  34. if (name === "eval" || scope.getBinding(name) === state.scope.parent.getBinding(name) && state.scope.hasOwnBinding(name)) {
  35. state.needsOuterBinding = true;
  36. path.stop();
  37. }
  38. },
  39. "TypeAnnotation|TSTypeAnnotation|TypeParameterDeclaration|TSTypeParameterDeclaration": path => path.skip()
  40. };
  41. function convertFunctionParams(path, ignoreFunctionLength, shouldTransformParam, replaceRestElement) {
  42. const params = path.get("params");
  43. const isSimpleParameterList = params.every(param => param.isIdentifier());
  44. if (isSimpleParameterList) return false;
  45. const {
  46. node,
  47. scope
  48. } = path;
  49. const state = {
  50. stop: false,
  51. needsOuterBinding: false,
  52. scope
  53. };
  54. const body = [];
  55. const shadowedParams = new Set();
  56. for (const param of params) {
  57. for (const name of Object.keys(param.getBindingIdentifiers())) {
  58. var _scope$bindings$name;
  59. const constantViolations = (_scope$bindings$name = scope.bindings[name]) == null ? void 0 : _scope$bindings$name.constantViolations;
  60. if (constantViolations) {
  61. for (const redeclarator of constantViolations) {
  62. const node = redeclarator.node;
  63. switch (node.type) {
  64. case "VariableDeclarator":
  65. {
  66. if (node.init === null) {
  67. const declaration = redeclarator.parentPath;
  68. if (!declaration.parentPath.isFor() || declaration.parentPath.get("body") === declaration) {
  69. redeclarator.remove();
  70. break;
  71. }
  72. }
  73. shadowedParams.add(name);
  74. break;
  75. }
  76. case "FunctionDeclaration":
  77. shadowedParams.add(name);
  78. break;
  79. }
  80. }
  81. }
  82. }
  83. }
  84. if (shadowedParams.size === 0) {
  85. for (const param of params) {
  86. if (!param.isIdentifier()) param.traverse(iifeVisitor, state);
  87. if (state.needsOuterBinding) break;
  88. }
  89. }
  90. let firstOptionalIndex = null;
  91. for (let i = 0; i < params.length; i++) {
  92. const param = params[i];
  93. if (shouldTransformParam && !shouldTransformParam(i)) {
  94. continue;
  95. }
  96. const transformedRestNodes = [];
  97. if (replaceRestElement) {
  98. replaceRestElement(param.parentPath, param, transformedRestNodes);
  99. }
  100. const paramIsAssignmentPattern = param.isAssignmentPattern();
  101. if (paramIsAssignmentPattern && (ignoreFunctionLength || node.kind === "set")) {
  102. const left = param.get("left");
  103. const right = param.get("right");
  104. const undefinedNode = scope.buildUndefinedNode();
  105. if (left.isIdentifier()) {
  106. body.push(buildLooseDefaultParam({
  107. ASSIGNMENT_IDENTIFIER: _core.types.cloneNode(left.node),
  108. DEFAULT_VALUE: right.node,
  109. UNDEFINED: undefinedNode
  110. }));
  111. param.replaceWith(left.node);
  112. } else if (left.isObjectPattern() || left.isArrayPattern()) {
  113. const paramName = scope.generateUidIdentifier();
  114. body.push(buildLooseDestructuredDefaultParam({
  115. ASSIGNMENT_IDENTIFIER: left.node,
  116. DEFAULT_VALUE: right.node,
  117. PARAMETER_NAME: _core.types.cloneNode(paramName),
  118. UNDEFINED: undefinedNode
  119. }));
  120. param.replaceWith(paramName);
  121. }
  122. } else if (paramIsAssignmentPattern) {
  123. if (firstOptionalIndex === null) firstOptionalIndex = i;
  124. const left = param.get("left");
  125. const right = param.get("right");
  126. const defNode = buildDefaultParam({
  127. VARIABLE_NAME: left.node,
  128. DEFAULT_VALUE: right.node,
  129. ARGUMENT_KEY: _core.types.numericLiteral(i)
  130. });
  131. body.push(defNode);
  132. } else if (firstOptionalIndex !== null) {
  133. const defNode = buildSafeArgumentsAccess([param.node, _core.types.numericLiteral(i)]);
  134. body.push(defNode);
  135. } else if (param.isObjectPattern() || param.isArrayPattern()) {
  136. const uid = path.scope.generateUidIdentifier("ref");
  137. const defNode = _core.types.variableDeclaration("let", [_core.types.variableDeclarator(param.node, uid)]);
  138. body.push(defNode);
  139. param.replaceWith(_core.types.cloneNode(uid));
  140. }
  141. if (transformedRestNodes) {
  142. for (const transformedNode of transformedRestNodes) {
  143. body.push(transformedNode);
  144. }
  145. }
  146. }
  147. if (firstOptionalIndex !== null) {
  148. node.params = node.params.slice(0, firstOptionalIndex);
  149. }
  150. path.ensureBlock();
  151. if (state.needsOuterBinding || shadowedParams.size > 0) {
  152. body.push(buildScopeIIFE(shadowedParams, path.get("body").node));
  153. path.set("body", _core.types.blockStatement(body));
  154. const bodyPath = path.get("body.body");
  155. const arrowPath = bodyPath[bodyPath.length - 1].get("argument.callee");
  156. arrowPath.arrowFunctionToExpression();
  157. arrowPath.node.generator = path.node.generator;
  158. arrowPath.node.async = path.node.async;
  159. path.node.generator = false;
  160. } else {
  161. path.get("body").unshiftContainer("body", body);
  162. }
  163. return true;
  164. }
  165. function buildScopeIIFE(shadowedParams, body) {
  166. const args = [];
  167. const params = [];
  168. for (const name of shadowedParams) {
  169. args.push(_core.types.identifier(name));
  170. params.push(_core.types.identifier(name));
  171. }
  172. return _core.types.returnStatement(_core.types.callExpression(_core.types.arrowFunctionExpression(params, body), args));
  173. }