You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.js 2.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. const mediaQueryText = require('mediaquery-text');
  2. const cheerio = require('cheerio');
  3. const pick = require('pick-util');
  4. function replaceCodeBlock(html, re, block) {
  5. return html.replace(re, () => block);
  6. }
  7. module.exports = (html, options, callback) => {
  8. const results = {};
  9. const codeBlocks = {
  10. EJS: { start: '<%', end: '%>' },
  11. HBS: { start: '{{', end: '}}' }
  12. };
  13. const codeBlockLookup = [];
  14. const encodeCodeBlocks = _html => {
  15. let __html = _html;
  16. const blocks = Object.assign(codeBlocks, options.codeBlocks);
  17. Object.keys(blocks).forEach(key => {
  18. const re = new RegExp(`${blocks[key].start}([\\S\\s]*?)${blocks[key].end}`, 'g');
  19. __html = __html.replace(re, match => {
  20. codeBlockLookup.push(match);
  21. return `EXCS_CODE_BLOCK_${codeBlockLookup.length - 1}_`;
  22. });
  23. });
  24. return __html;
  25. };
  26. const decodeCodeBlocks = _html => {
  27. let index;
  28. let re;
  29. let __html = _html;
  30. for (index = 0; index < codeBlockLookup.length; index++) {
  31. re = new RegExp(`EXCS_CODE_BLOCK_${index}_(="")?`, 'gi');
  32. __html = replaceCodeBlock(__html, re, codeBlockLookup[index]);
  33. }
  34. return __html;
  35. };
  36. const encodeEntities = _html => encodeCodeBlocks(_html);
  37. const decodeEntities = _html => decodeCodeBlocks(_html);
  38. let $;
  39. let styleDataList;
  40. let styleData;
  41. $ = cheerio.load(encodeEntities(html), Object.assign({
  42. decodeEntities: false
  43. }, pick(options, [
  44. 'xmlMode',
  45. 'decodeEntities',
  46. 'lowerCaseTags',
  47. 'lowerCaseAttributeNames',
  48. 'recognizeCDATA',
  49. 'recognizeSelfClosing'
  50. ])));
  51. results.css = [];
  52. $('style').each((index, element) => {
  53. let mediaQueries;
  54. // if data-embed property exists, skip inlining and removing
  55. if (typeof $(element).data('embed') !== 'undefined') {
  56. return;
  57. }
  58. styleDataList = element.childNodes;
  59. if (styleDataList.length !== 1) {
  60. callback(new Error('empty style element'));
  61. return;
  62. }
  63. styleData = styleDataList[0].data;
  64. if (options.applyStyleTags) {
  65. results.css.push(styleData);
  66. }
  67. if (options.removeStyleTags) {
  68. if (options.preserveMediaQueries) {
  69. mediaQueries = mediaQueryText(element.childNodes[0].nodeValue);
  70. element.childNodes[0].nodeValue = mediaQueries;
  71. }
  72. if (!mediaQueries) {
  73. $(element).remove();
  74. }
  75. }
  76. });
  77. results.html = decodeEntities($.html());
  78. callback(null, results);
  79. };