es6-call-spread-visitors.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. /**
  2. * Copyright 2013-present, Facebook, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. */
  9. /*global exports:true*/
  10. /**
  11. * Implements ES6 call spread.
  12. *
  13. * instance.method(a, b, c, ...d)
  14. *
  15. * instance.method.apply(instance, [a, b, c].concat(d))
  16. *
  17. */
  18. var Syntax = require('esprima-fb').Syntax;
  19. var utils = require('../src/utils');
  20. function process(traverse, node, path, state) {
  21. utils.move(node.range[0], state);
  22. traverse(node, path, state);
  23. utils.catchup(node.range[1], state);
  24. }
  25. function visitCallSpread(traverse, node, path, state) {
  26. utils.catchup(node.range[0], state);
  27. if (node.type === Syntax.NewExpression) {
  28. // Input = new Set(1, 2, ...list)
  29. // Output = new (Function.prototype.bind.apply(Set, [null, 1, 2].concat(list)))
  30. utils.append('new (Function.prototype.bind.apply(', state);
  31. process(traverse, node.callee, path, state);
  32. } else if (node.callee.type === Syntax.MemberExpression) {
  33. // Input = get().fn(1, 2, ...more)
  34. // Output = (_ = get()).fn.apply(_, [1, 2].apply(more))
  35. var tempVar = utils.injectTempVar(state);
  36. utils.append('(' + tempVar + ' = ', state);
  37. process(traverse, node.callee.object, path, state);
  38. utils.append(')', state);
  39. if (node.callee.property.type === Syntax.Identifier) {
  40. utils.append('.', state);
  41. process(traverse, node.callee.property, path, state);
  42. } else {
  43. utils.append('[', state);
  44. process(traverse, node.callee.property, path, state);
  45. utils.append(']', state);
  46. }
  47. utils.append('.apply(' + tempVar, state);
  48. } else {
  49. // Input = max(1, 2, ...list)
  50. // Output = max.apply(undefined, [1, 2].concat(list))
  51. var needsToBeWrappedInParenthesis =
  52. node.callee.type === Syntax.FunctionDeclaration ||
  53. node.callee.type === Syntax.FunctionExpression;
  54. if (needsToBeWrappedInParenthesis) {
  55. utils.append('(', state);
  56. }
  57. process(traverse, node.callee, path, state);
  58. if (needsToBeWrappedInParenthesis) {
  59. utils.append(')', state);
  60. }
  61. utils.append('.apply(undefined', state);
  62. }
  63. utils.append(', ', state);
  64. var args = node.arguments.slice();
  65. var spread = args.pop();
  66. if (args.length || node.type === Syntax.NewExpression) {
  67. utils.append('[', state);
  68. if (node.type === Syntax.NewExpression) {
  69. utils.append('null' + (args.length ? ', ' : ''), state);
  70. }
  71. while (args.length) {
  72. var arg = args.shift();
  73. utils.move(arg.range[0], state);
  74. traverse(arg, path, state);
  75. if (args.length) {
  76. utils.catchup(args[0].range[0], state);
  77. } else {
  78. utils.catchup(arg.range[1], state);
  79. }
  80. }
  81. utils.append('].concat(', state);
  82. process(traverse, spread.argument, path, state);
  83. utils.append(')', state);
  84. } else {
  85. process(traverse, spread.argument, path, state);
  86. }
  87. utils.append(node.type === Syntax.NewExpression ? '))' : ')', state);
  88. utils.move(node.range[1], state);
  89. return false;
  90. }
  91. visitCallSpread.test = function(node, path, state) {
  92. return (
  93. (
  94. node.type === Syntax.CallExpression ||
  95. node.type === Syntax.NewExpression
  96. ) &&
  97. node.arguments.length > 0 &&
  98. node.arguments[node.arguments.length - 1].type === Syntax.SpreadElement
  99. );
  100. };
  101. exports.visitorList = [
  102. visitCallSpread
  103. ];