error-reporting.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import * as utils from './utils';
  2. import browser from './browser';
  3. export default (window, less, options) => {
  4. function errorHTML(e, rootHref) {
  5. const id = `less-error-message:${utils.extractId(rootHref || '')}`;
  6. const template = '<li><label>{line}</label><pre class="{class}">{content}</pre></li>';
  7. const elem = window.document.createElement('div');
  8. let timer;
  9. let content;
  10. const errors = [];
  11. const filename = e.filename || rootHref;
  12. const filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1];
  13. elem.id = id;
  14. elem.className = 'less-error-message';
  15. content = `<h3>${e.type || 'Syntax'}Error: ${e.message || 'There is an error in your .less file'}` +
  16. `</h3><p>in <a href="${filename}">${filenameNoPath}</a> `;
  17. const errorline = (e, i, classname) => {
  18. if (e.extract[i] !== undefined) {
  19. errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1))
  20. .replace(/\{class\}/, classname)
  21. .replace(/\{content\}/, e.extract[i]));
  22. }
  23. };
  24. if (e.line) {
  25. errorline(e, 0, '');
  26. errorline(e, 1, 'line');
  27. errorline(e, 2, '');
  28. content += `on line ${e.line}, column ${e.column + 1}:</p><ul>${errors.join('')}</ul>`;
  29. }
  30. if (e.stack && (e.extract || options.logLevel >= 4)) {
  31. content += `<br/>Stack Trace</br />${e.stack.split('\n').slice(1).join('<br/>')}`;
  32. }
  33. elem.innerHTML = content;
  34. // CSS for error messages
  35. browser.createCSS(window.document, [
  36. '.less-error-message ul, .less-error-message li {',
  37. 'list-style-type: none;',
  38. 'margin-right: 15px;',
  39. 'padding: 4px 0;',
  40. 'margin: 0;',
  41. '}',
  42. '.less-error-message label {',
  43. 'font-size: 12px;',
  44. 'margin-right: 15px;',
  45. 'padding: 4px 0;',
  46. 'color: #cc7777;',
  47. '}',
  48. '.less-error-message pre {',
  49. 'color: #dd6666;',
  50. 'padding: 4px 0;',
  51. 'margin: 0;',
  52. 'display: inline-block;',
  53. '}',
  54. '.less-error-message pre.line {',
  55. 'color: #ff0000;',
  56. '}',
  57. '.less-error-message h3 {',
  58. 'font-size: 20px;',
  59. 'font-weight: bold;',
  60. 'padding: 15px 0 5px 0;',
  61. 'margin: 0;',
  62. '}',
  63. '.less-error-message a {',
  64. 'color: #10a',
  65. '}',
  66. '.less-error-message .error {',
  67. 'color: red;',
  68. 'font-weight: bold;',
  69. 'padding-bottom: 2px;',
  70. 'border-bottom: 1px dashed red;',
  71. '}'
  72. ].join('\n'), { title: 'error-message' });
  73. elem.style.cssText = [
  74. 'font-family: Arial, sans-serif',
  75. 'border: 1px solid #e00',
  76. 'background-color: #eee',
  77. 'border-radius: 5px',
  78. '-webkit-border-radius: 5px',
  79. '-moz-border-radius: 5px',
  80. 'color: #e00',
  81. 'padding: 15px',
  82. 'margin-bottom: 15px'
  83. ].join(';');
  84. if (options.env === 'development') {
  85. timer = setInterval(() => {
  86. const document = window.document;
  87. const body = document.body;
  88. if (body) {
  89. if (document.getElementById(id)) {
  90. body.replaceChild(elem, document.getElementById(id));
  91. } else {
  92. body.insertBefore(elem, body.firstChild);
  93. }
  94. clearInterval(timer);
  95. }
  96. }, 10);
  97. }
  98. }
  99. function removeErrorHTML(path) {
  100. const node = window.document.getElementById(`less-error-message:${utils.extractId(path)}`);
  101. if (node) {
  102. node.parentNode.removeChild(node);
  103. }
  104. }
  105. function removeErrorConsole(path) {
  106. // no action
  107. }
  108. function removeError(path) {
  109. if (!options.errorReporting || options.errorReporting === 'html') {
  110. removeErrorHTML(path);
  111. } else if (options.errorReporting === 'console') {
  112. removeErrorConsole(path);
  113. } else if (typeof options.errorReporting === 'function') {
  114. options.errorReporting('remove', path);
  115. }
  116. }
  117. function errorConsole(e, rootHref) {
  118. const template = '{line} {content}';
  119. const filename = e.filename || rootHref;
  120. const errors = [];
  121. let content = `${e.type || 'Syntax'}Error: ${e.message || 'There is an error in your .less file'} in ${filename}`;
  122. const errorline = (e, i, classname) => {
  123. if (e.extract[i] !== undefined) {
  124. errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1))
  125. .replace(/\{class\}/, classname)
  126. .replace(/\{content\}/, e.extract[i]));
  127. }
  128. };
  129. if (e.line) {
  130. errorline(e, 0, '');
  131. errorline(e, 1, 'line');
  132. errorline(e, 2, '');
  133. content += ` on line ${e.line}, column ${e.column + 1}:\n${errors.join('\n')}`;
  134. }
  135. if (e.stack && (e.extract || options.logLevel >= 4)) {
  136. content += `\nStack Trace\n${e.stack}`;
  137. }
  138. less.logger.error(content);
  139. }
  140. function error(e, rootHref) {
  141. if (!options.errorReporting || options.errorReporting === 'html') {
  142. errorHTML(e, rootHref);
  143. } else if (options.errorReporting === 'console') {
  144. errorConsole(e, rootHref);
  145. } else if (typeof options.errorReporting === 'function') {
  146. options.errorReporting('add', e, rootHref);
  147. }
  148. }
  149. return {
  150. add: error,
  151. remove: removeError
  152. };
  153. };