params.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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. };
  40. function convertFunctionParams(path, loose) {
  41. const params = path.get("params");
  42. const isSimpleParameterList = params.every(param => param.isIdentifier());
  43. if (isSimpleParameterList) return false;
  44. const {
  45. node,
  46. scope
  47. } = path;
  48. const state = {
  49. stop: false,
  50. needsOuterBinding: false,
  51. scope
  52. };
  53. const body = [];
  54. const shadowedParams = new Set();
  55. for (const param of params) {
  56. for (const name of Object.keys(param.getBindingIdentifiers())) {
  57. var _scope$bindings$name;
  58. const constantViolations = (_scope$bindings$name = scope.bindings[name]) == null ? void 0 : _scope$bindings$name.constantViolations;
  59. if (constantViolations) {
  60. for (const redeclarator of constantViolations) {
  61. const node = redeclarator.node;
  62. switch (node.type) {
  63. case "VariableDeclarator":
  64. {
  65. if (node.init === null) {
  66. const declaration = redeclarator.parentPath;
  67. if (!declaration.parentPath.isFor() || declaration.parentPath.get("body") === declaration) {
  68. redeclarator.remove();
  69. break;
  70. }
  71. }
  72. shadowedParams.add(name);
  73. break;
  74. }
  75. case "FunctionDeclaration":
  76. shadowedParams.add(name);
  77. break;
  78. }
  79. }
  80. }
  81. }
  82. }
  83. if (shadowedParams.size === 0) {
  84. for (const param of params) {
  85. if (!param.isIdentifier()) param.traverse(iifeVisitor, state);
  86. if (state.needsOuterBinding) break;
  87. }
  88. }
  89. let firstOptionalIndex = null;
  90. for (let i = 0; i < params.length; i++) {
  91. const param = params[i];
  92. const paramIsAssignmentPattern = param.isAssignmentPattern();
  93. if (paramIsAssignmentPattern && (loose || node.kind === "set")) {
  94. const left = param.get("left");
  95. const right = param.get("right");
  96. const undefinedNode = scope.buildUndefinedNode();
  97. if (left.isIdentifier()) {
  98. body.push(buildLooseDefaultParam({
  99. ASSIGNMENT_IDENTIFIER: _core.types.cloneNode(left.node),
  100. DEFAULT_VALUE: right.node,
  101. UNDEFINED: undefinedNode
  102. }));
  103. param.replaceWith(left.node);
  104. } else if (left.isObjectPattern() || left.isArrayPattern()) {
  105. const paramName = scope.generateUidIdentifier();
  106. body.push(buildLooseDestructuredDefaultParam({
  107. ASSIGNMENT_IDENTIFIER: left.node,
  108. DEFAULT_VALUE: right.node,
  109. PARAMETER_NAME: _core.types.cloneNode(paramName),
  110. UNDEFINED: undefinedNode
  111. }));
  112. param.replaceWith(paramName);
  113. }
  114. } else if (paramIsAssignmentPattern) {
  115. if (firstOptionalIndex === null) firstOptionalIndex = i;
  116. const left = param.get("left");
  117. const right = param.get("right");
  118. const defNode = buildDefaultParam({
  119. VARIABLE_NAME: left.node,
  120. DEFAULT_VALUE: right.node,
  121. ARGUMENT_KEY: _core.types.numericLiteral(i)
  122. });
  123. body.push(defNode);
  124. } else if (firstOptionalIndex !== null) {
  125. const defNode = buildSafeArgumentsAccess([param.node, _core.types.numericLiteral(i)]);
  126. body.push(defNode);
  127. } else if (param.isObjectPattern() || param.isArrayPattern()) {
  128. const uid = path.scope.generateUidIdentifier("ref");
  129. const defNode = _core.types.variableDeclaration("let", [_core.types.variableDeclarator(param.node, uid)]);
  130. body.push(defNode);
  131. param.replaceWith(_core.types.cloneNode(uid));
  132. }
  133. }
  134. if (firstOptionalIndex !== null) {
  135. node.params = node.params.slice(0, firstOptionalIndex);
  136. }
  137. path.ensureBlock();
  138. if (state.needsOuterBinding || shadowedParams.size > 0) {
  139. body.push(buildScopeIIFE(shadowedParams, path.get("body").node));
  140. path.set("body", _core.types.blockStatement(body));
  141. const bodyPath = path.get("body.body");
  142. const arrowPath = bodyPath[bodyPath.length - 1].get("argument.callee");
  143. arrowPath.arrowFunctionToExpression();
  144. } else {
  145. path.get("body").unshiftContainer("body", body);
  146. }
  147. return true;
  148. }
  149. function buildScopeIIFE(shadowedParams, body) {
  150. const args = [];
  151. const params = [];
  152. for (const name of shadowedParams) {
  153. args.push(_core.types.identifier(name));
  154. params.push(_core.types.identifier(name));
  155. }
  156. return _core.types.returnStatement(_core.types.callExpression(_core.types.arrowFunctionExpression(params, body), params));
  157. }