jsx-helpers.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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. 'use strict';
  11. var Syntax = require('esprima-fb').Syntax;
  12. var utils = require('../src/utils');
  13. function commaAfterLastParen(value) {
  14. var state = 'normal';
  15. var commaPos = 0;
  16. for (var i = 0; i < value.length; ++i) {
  17. if (state === 'normal') {
  18. if (value.substr(i, 2) === '//') {
  19. state = 'singleline';
  20. i += 1;
  21. } else if (value.substr(i, 2) === '/*') {
  22. state = 'multiline';
  23. i += 1;
  24. } else if (value.charAt(i).trim() !== '') {
  25. commaPos = i + 1;
  26. }
  27. } else if (state === 'singleline' && value.charAt(i) === '\n') {
  28. state = 'normal';
  29. } else if (state === 'multiline' &&
  30. value.charAt(i) === '*' &&
  31. i + 1 < value.length &&
  32. value.charAt(i + 1) === '/') {
  33. i += 1;
  34. state = 'normal';
  35. }
  36. }
  37. return value.substring(0, commaPos) + ', ' + trimLeft(value.substring(commaPos));
  38. }
  39. function renderJSXLiteral(object, isLast, state, start, end) {
  40. var lines = object.value.split(/\r\n|\n|\r/);
  41. if (start) {
  42. utils.append(start, state);
  43. }
  44. var lastNonEmptyLine = 0;
  45. lines.forEach(function(line, index) {
  46. if (line.match(/[^ \t]/)) {
  47. lastNonEmptyLine = index;
  48. }
  49. });
  50. lines.forEach(function(line, index) {
  51. var isFirstLine = index === 0;
  52. var isLastLine = index === lines.length - 1;
  53. var isLastNonEmptyLine = index === lastNonEmptyLine;
  54. // replace rendered whitespace tabs with spaces
  55. var trimmedLine = line.replace(/\t/g, ' ');
  56. // trim whitespace touching a newline
  57. if (!isFirstLine) {
  58. trimmedLine = trimmedLine.replace(/^[ ]+/, '');
  59. }
  60. if (!isLastLine) {
  61. trimmedLine = trimmedLine.replace(/[ ]+$/, '');
  62. }
  63. if (!isFirstLine) {
  64. utils.append(line.match(/^[ \t]*/)[0], state);
  65. }
  66. if (trimmedLine || isLastNonEmptyLine) {
  67. utils.append(
  68. JSON.stringify(trimmedLine) +
  69. (!isLastNonEmptyLine ? ' + " " +' : ''),
  70. state);
  71. if (isLastNonEmptyLine) {
  72. if (end) {
  73. utils.append(end, state);
  74. }
  75. if (!isLast) {
  76. utils.append(', ', state);
  77. }
  78. }
  79. // only restore tail whitespace if line had literals
  80. if (trimmedLine && !isLastLine) {
  81. utils.append(line.match(/[ \t]*$/)[0], state);
  82. }
  83. }
  84. if (!isLastLine) {
  85. utils.append('\n', state);
  86. }
  87. });
  88. utils.move(object.range[1], state);
  89. }
  90. function renderJSXExpressionContainer(traverse, object, isLast, path, state) {
  91. // Plus 1 to skip `{`.
  92. utils.move(object.range[0] + 1, state);
  93. utils.catchup(object.expression.range[0], state);
  94. traverse(object.expression, path, state);
  95. if (!isLast && object.expression.type !== Syntax.JSXEmptyExpression) {
  96. // If we need to append a comma, make sure to do so after the expression.
  97. utils.catchup(object.expression.range[1], state, trimLeft);
  98. utils.catchup(object.range[1] - 1, state, commaAfterLastParen);
  99. } else {
  100. // Minus 1 to skip `}`.
  101. utils.catchup(object.range[1] - 1, state, trimLeft);
  102. }
  103. utils.move(object.range[1], state);
  104. return false;
  105. }
  106. function quoteAttrName(attr) {
  107. // Quote invalid JS identifiers.
  108. if (!/^[a-z_$][a-z\d_$]*$/i.test(attr)) {
  109. return '"' + attr + '"';
  110. }
  111. return attr;
  112. }
  113. function trimLeft(value) {
  114. return value.replace(/^[ ]+/, '');
  115. }
  116. exports.renderJSXExpressionContainer = renderJSXExpressionContainer;
  117. exports.renderJSXLiteral = renderJSXLiteral;
  118. exports.quoteAttrName = quoteAttrName;
  119. exports.trimLeft = trimLeft;