comments-processor.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. var EscapeStore = require('./escape-store');
  2. var QuoteScanner = require('../utils/quote-scanner');
  3. var SPECIAL_COMMENT_PREFIX = '/*!';
  4. var COMMENT_PREFIX = '/*';
  5. var COMMENT_SUFFIX = '*/';
  6. var lineBreak = require('os').EOL;
  7. function CommentsProcessor(context, keepSpecialComments, keepBreaks, saveWaypoints) {
  8. this.comments = new EscapeStore('COMMENT');
  9. this.specialComments = new EscapeStore('COMMENT_SPECIAL');
  10. this.context = context;
  11. this.restored = 0;
  12. this.keepAll = keepSpecialComments == '*';
  13. this.keepOne = keepSpecialComments == '1' || keepSpecialComments === 1;
  14. this.keepBreaks = keepBreaks;
  15. this.saveWaypoints = saveWaypoints;
  16. }
  17. function quoteScannerFor(data) {
  18. var quoteMap = [];
  19. new QuoteScanner(data).each(function (quotedString, _, startsAt) {
  20. quoteMap.push([startsAt, startsAt + quotedString.length]);
  21. });
  22. return function (position) {
  23. for (var i = 0, l = quoteMap.length; i < l; i++) {
  24. if (quoteMap[i][0] < position && quoteMap[i][1] > position)
  25. return true;
  26. }
  27. return false;
  28. };
  29. }
  30. CommentsProcessor.prototype.escape = function (data) {
  31. var tempData = [];
  32. var nextStart = 0;
  33. var nextEnd = 0;
  34. var cursor = 0;
  35. var indent = 0;
  36. var breaksCount;
  37. var lastBreakAt;
  38. var newIndent;
  39. var isQuotedAt = quoteScannerFor(data);
  40. var saveWaypoints = this.saveWaypoints;
  41. for (; nextEnd < data.length;) {
  42. nextStart = data.indexOf(COMMENT_PREFIX, cursor);
  43. if (nextStart == -1)
  44. break;
  45. if (isQuotedAt(nextStart)) {
  46. tempData.push(data.substring(cursor, nextStart + COMMENT_PREFIX.length));
  47. cursor = nextStart + COMMENT_PREFIX.length;
  48. continue;
  49. }
  50. nextEnd = data.indexOf(COMMENT_SUFFIX, nextStart + COMMENT_PREFIX.length);
  51. if (nextEnd == -1) {
  52. this.context.warnings.push('Broken comment: \'' + data.substring(nextStart) + '\'.');
  53. nextEnd = data.length - 2;
  54. }
  55. tempData.push(data.substring(cursor, nextStart));
  56. var comment = data.substring(nextStart, nextEnd + COMMENT_SUFFIX.length);
  57. var isSpecialComment = comment.indexOf(SPECIAL_COMMENT_PREFIX) === 0;
  58. if (saveWaypoints) {
  59. breaksCount = comment.split(lineBreak).length - 1;
  60. lastBreakAt = comment.lastIndexOf(lineBreak);
  61. newIndent = lastBreakAt > 0 ?
  62. comment.substring(lastBreakAt + lineBreak.length).length :
  63. indent + comment.length;
  64. }
  65. if (saveWaypoints || isSpecialComment) {
  66. var metadata = saveWaypoints ? [breaksCount, newIndent] : null;
  67. var placeholder = isSpecialComment ?
  68. this.specialComments.store(comment, metadata) :
  69. this.comments.store(comment, metadata);
  70. tempData.push(placeholder);
  71. }
  72. if (saveWaypoints)
  73. indent = newIndent + 1;
  74. cursor = nextEnd + COMMENT_SUFFIX.length;
  75. }
  76. return tempData.length > 0 ?
  77. tempData.join('') + data.substring(cursor, data.length) :
  78. data;
  79. };
  80. function restore(context, data, from, isSpecial) {
  81. var tempData = [];
  82. var cursor = 0;
  83. for (; cursor < data.length;) {
  84. var nextMatch = from.nextMatch(data, cursor);
  85. if (nextMatch.start < 0)
  86. break;
  87. tempData.push(data.substring(cursor, nextMatch.start));
  88. var comment = from.restore(nextMatch.match);
  89. if (isSpecial && (context.keepAll || (context.keepOne && context.restored === 0))) {
  90. context.restored++;
  91. tempData.push(comment);
  92. cursor = nextMatch.end;
  93. } else {
  94. cursor = nextMatch.end + (context.keepBreaks && data.substring(nextMatch.end, nextMatch.end + lineBreak.length) == lineBreak ? lineBreak.length : 0);
  95. }
  96. }
  97. return tempData.length > 0 ?
  98. tempData.join('') + data.substring(cursor, data.length) :
  99. data;
  100. }
  101. CommentsProcessor.prototype.restore = function (data) {
  102. data = restore(this, data, this.comments, false);
  103. data = restore(this, data, this.specialComments, true);
  104. return data;
  105. };
  106. module.exports = CommentsProcessor;