es7-spread-property-visitors.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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 ES7 object spread property.
  12. * https://gist.github.com/sebmarkbage/aa849c7973cb4452c547
  13. *
  14. * { ...a, x: 1 }
  15. *
  16. * Object.assign({}, a, {x: 1 })
  17. *
  18. */
  19. var Syntax = require('esprima-fb').Syntax;
  20. var utils = require('../src/utils');
  21. function visitObjectLiteralSpread(traverse, node, path, state) {
  22. utils.catchup(node.range[0], state);
  23. utils.append('Object.assign({', state);
  24. // Skip the original {
  25. utils.move(node.range[0] + 1, state);
  26. var lastWasSpread = renderSpreadProperties(
  27. traverse,
  28. node.properties,
  29. path,
  30. state,
  31. false // previousWasSpread
  32. );
  33. // Strip any non-whitespace between the last item and the end.
  34. // We only catch up on whitespace so that we ignore any trailing commas which
  35. // are stripped out for IE8 support. Unfortunately, this also strips out any
  36. // trailing comments.
  37. utils.catchupWhiteSpace(node.range[1] - 1, state);
  38. // Skip the trailing }
  39. utils.move(node.range[1], state);
  40. if (!lastWasSpread) {
  41. utils.append('}', state);
  42. }
  43. utils.append(')', state);
  44. return false;
  45. }
  46. // This method is also used by es6-object-computed-property-visitor.
  47. function renderSpreadProperties(traverse, properties, path, state, previousWasSpread) {
  48. for (var i = 0; i < properties.length; i++) {
  49. var property = properties[i];
  50. if (property.type === Syntax.SpreadProperty) {
  51. // Close the previous object or initial object
  52. if (!previousWasSpread) {
  53. utils.append('}', state);
  54. }
  55. if (i === 0) {
  56. // Normally there will be a comma when we catch up, but not before
  57. // the first property.
  58. utils.append(',', state);
  59. }
  60. utils.catchup(property.range[0], state);
  61. // skip ...
  62. utils.move(property.range[0] + 3, state);
  63. traverse(property.argument, path, state);
  64. utils.catchup(property.range[1], state);
  65. previousWasSpread = true;
  66. } else {
  67. utils.catchup(property.range[0], state);
  68. if (previousWasSpread) {
  69. utils.append('{', state);
  70. }
  71. traverse(property, path, state);
  72. utils.catchup(property.range[1], state);
  73. previousWasSpread = false;
  74. }
  75. }
  76. return previousWasSpread;
  77. }
  78. visitObjectLiteralSpread.test = function(node, path, state) {
  79. if (node.type !== Syntax.ObjectExpression) {
  80. return false;
  81. }
  82. // Tight loop optimization
  83. var hasAtLeastOneSpreadProperty = false;
  84. for (var i = 0; i < node.properties.length; i++) {
  85. var property = node.properties[i];
  86. if (property.type === Syntax.SpreadProperty) {
  87. hasAtLeastOneSpreadProperty = true;
  88. } else if (property.kind !== 'init') {
  89. return false;
  90. }
  91. }
  92. return hasAtLeastOneSpreadProperty;
  93. };
  94. exports.renderSpreadProperties = renderSpreadProperties;
  95. exports.visitorList = [
  96. visitObjectLiteralSpread
  97. ];