es6-template-visitors.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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. /*jslint node:true*/
  10. /**
  11. * @typechecks
  12. */
  13. 'use strict';
  14. var Syntax = require('esprima-fb').Syntax;
  15. var utils = require('../src/utils');
  16. /**
  17. * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-12.1.9
  18. */
  19. function visitTemplateLiteral(traverse, node, path, state) {
  20. var templateElements = node.quasis;
  21. utils.append('(', state);
  22. for (var ii = 0; ii < templateElements.length; ii++) {
  23. var templateElement = templateElements[ii];
  24. if (templateElement.value.raw !== '') {
  25. utils.append(getCookedValue(templateElement), state);
  26. if (!templateElement.tail) {
  27. // + between element and substitution
  28. utils.append(' + ', state);
  29. }
  30. // maintain line numbers
  31. utils.move(templateElement.range[0], state);
  32. utils.catchupNewlines(templateElement.range[1], state);
  33. } else { // templateElement.value.raw === ''
  34. // Concatenat adjacent substitutions, e.g. `${x}${y}`. Empty templates
  35. // appear before the first and after the last element - nothing to add in
  36. // those cases.
  37. if (ii === 0) {
  38. utils.append('"" + ', state);
  39. }
  40. if (ii > 0 && !templateElement.tail) {
  41. // + between substitution and substitution
  42. utils.append(' + ', state);
  43. }
  44. }
  45. utils.move(templateElement.range[1], state);
  46. if (!templateElement.tail) {
  47. var substitution = node.expressions[ii];
  48. if (substitution.type === Syntax.Identifier ||
  49. substitution.type === Syntax.Literal ||
  50. substitution.type === Syntax.MemberExpression ||
  51. substitution.type === Syntax.CallExpression) {
  52. utils.catchup(substitution.range[1], state);
  53. } else {
  54. utils.append('(', state);
  55. traverse(substitution, path, state);
  56. utils.catchup(substitution.range[1], state);
  57. utils.append(')', state);
  58. }
  59. // if next templateElement isn't empty...
  60. if (templateElements[ii + 1].value.cooked !== '') {
  61. utils.append(' + ', state);
  62. }
  63. }
  64. }
  65. utils.move(node.range[1], state);
  66. utils.append(')', state);
  67. return false;
  68. }
  69. visitTemplateLiteral.test = function(node, path, state) {
  70. return node.type === Syntax.TemplateLiteral;
  71. };
  72. /**
  73. * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-12.2.6
  74. */
  75. function visitTaggedTemplateExpression(traverse, node, path, state) {
  76. var template = node.quasi;
  77. var numQuasis = template.quasis.length;
  78. // print the tag
  79. utils.move(node.tag.range[0], state);
  80. traverse(node.tag, path, state);
  81. utils.catchup(node.tag.range[1], state);
  82. // print array of template elements
  83. utils.append('(function() { var siteObj = [', state);
  84. for (var ii = 0; ii < numQuasis; ii++) {
  85. utils.append(getCookedValue(template.quasis[ii]), state);
  86. if (ii !== numQuasis - 1) {
  87. utils.append(', ', state);
  88. }
  89. }
  90. utils.append(']; siteObj.raw = [', state);
  91. for (ii = 0; ii < numQuasis; ii++) {
  92. utils.append(getRawValue(template.quasis[ii]), state);
  93. if (ii !== numQuasis - 1) {
  94. utils.append(', ', state);
  95. }
  96. }
  97. utils.append(
  98. ']; Object.freeze(siteObj.raw); Object.freeze(siteObj); return siteObj; }()',
  99. state
  100. );
  101. // print substitutions
  102. if (numQuasis > 1) {
  103. for (ii = 0; ii < template.expressions.length; ii++) {
  104. var expression = template.expressions[ii];
  105. utils.append(', ', state);
  106. // maintain line numbers by calling catchupWhiteSpace over the whole
  107. // previous TemplateElement
  108. utils.move(template.quasis[ii].range[0], state);
  109. utils.catchupNewlines(template.quasis[ii].range[1], state);
  110. utils.move(expression.range[0], state);
  111. traverse(expression, path, state);
  112. utils.catchup(expression.range[1], state);
  113. }
  114. }
  115. // print blank lines to push the closing ) down to account for the final
  116. // TemplateElement.
  117. utils.catchupNewlines(node.range[1], state);
  118. utils.append(')', state);
  119. return false;
  120. }
  121. visitTaggedTemplateExpression.test = function(node, path, state) {
  122. return node.type === Syntax.TaggedTemplateExpression;
  123. };
  124. function getCookedValue(templateElement) {
  125. return JSON.stringify(templateElement.value.cooked);
  126. }
  127. function getRawValue(templateElement) {
  128. return JSON.stringify(templateElement.value.raw);
  129. }
  130. exports.visitorList = [
  131. visitTemplateLiteral,
  132. visitTaggedTemplateExpression
  133. ];