expressions-processor.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. var EscapeStore = require('./escape-store');
  2. var EXPRESSION_NAME = 'expression';
  3. var EXPRESSION_START = '(';
  4. var EXPRESSION_END = ')';
  5. var EXPRESSION_PREFIX = EXPRESSION_NAME + EXPRESSION_START;
  6. var BODY_START = '{';
  7. var BODY_END = '}';
  8. var lineBreak = require('os').EOL;
  9. function findEnd(data, start) {
  10. var end = start + EXPRESSION_NAME.length;
  11. var level = 0;
  12. var quoted = false;
  13. var braced = false;
  14. while (true) {
  15. var current = data[end++];
  16. if (quoted) {
  17. quoted = current != '\'' && current != '"';
  18. } else {
  19. quoted = current == '\'' || current == '"';
  20. if (current == EXPRESSION_START)
  21. level++;
  22. if (current == EXPRESSION_END)
  23. level--;
  24. if (current == BODY_START)
  25. braced = true;
  26. if (current == BODY_END && !braced && level == 1) {
  27. end--;
  28. level--;
  29. }
  30. }
  31. if (level === 0 && current == EXPRESSION_END)
  32. break;
  33. if (!current) {
  34. end = data.substring(0, end).lastIndexOf(BODY_END);
  35. break;
  36. }
  37. }
  38. return end;
  39. }
  40. function ExpressionsProcessor(saveWaypoints) {
  41. this.expressions = new EscapeStore('EXPRESSION');
  42. this.saveWaypoints = saveWaypoints;
  43. }
  44. ExpressionsProcessor.prototype.escape = function (data) {
  45. var nextStart = 0;
  46. var nextEnd = 0;
  47. var cursor = 0;
  48. var tempData = [];
  49. var indent = 0;
  50. var breaksCount;
  51. var lastBreakAt;
  52. var newIndent;
  53. var saveWaypoints = this.saveWaypoints;
  54. for (; nextEnd < data.length;) {
  55. nextStart = data.indexOf(EXPRESSION_PREFIX, nextEnd);
  56. if (nextStart == -1)
  57. break;
  58. nextEnd = findEnd(data, nextStart);
  59. var expression = data.substring(nextStart, nextEnd);
  60. if (saveWaypoints) {
  61. breaksCount = expression.split(lineBreak).length - 1;
  62. lastBreakAt = expression.lastIndexOf(lineBreak);
  63. newIndent = lastBreakAt > 0 ?
  64. expression.substring(lastBreakAt + lineBreak.length).length :
  65. indent + expression.length;
  66. }
  67. var metadata = saveWaypoints ? [breaksCount, newIndent] : null;
  68. var placeholder = this.expressions.store(expression, metadata);
  69. tempData.push(data.substring(cursor, nextStart));
  70. tempData.push(placeholder);
  71. if (saveWaypoints)
  72. indent = newIndent + 1;
  73. cursor = nextEnd;
  74. }
  75. return tempData.length > 0 ?
  76. tempData.join('') + data.substring(cursor, data.length) :
  77. data;
  78. };
  79. ExpressionsProcessor.prototype.restore = function (data) {
  80. var tempData = [];
  81. var cursor = 0;
  82. for (; cursor < data.length;) {
  83. var nextMatch = this.expressions.nextMatch(data, cursor);
  84. if (nextMatch.start < 0)
  85. break;
  86. tempData.push(data.substring(cursor, nextMatch.start));
  87. var comment = this.expressions.restore(nextMatch.match);
  88. tempData.push(comment);
  89. cursor = nextMatch.end;
  90. }
  91. return tempData.length > 0 ?
  92. tempData.join('') + data.substring(cursor, data.length) :
  93. data;
  94. };
  95. module.exports = ExpressionsProcessor;