single-file.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /*
  2. * Copyright 2010-2019 Gildas Lormeau
  3. * contact : gildas.lormeau <at> gmail.com
  4. *
  5. * This file is part of SingleFile.
  6. *
  7. * The code in this file is free software: you can redistribute it and/or
  8. * modify it under the terms of the GNU Affero General Public License
  9. * (GNU AGPL) as published by the Free Software Foundation, either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * The code in this file is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
  15. * General Public License for more details.
  16. *
  17. * As additional permission under GNU AGPL version 3 section 7, you may
  18. * distribute UNMODIFIED VERSIONS OF THIS file without the copy of the GNU
  19. * AGPL normally required by section 4, provided you include this license
  20. * notice and a URL through which recipients can access the Corresponding
  21. * Source.
  22. */
  23. /* global
  24. crypto,
  25. fetch,
  26. Blob,
  27. FileReader,
  28. TextDecoder,
  29. TextEncoder */
  30. this.singlefile.lib.SingleFile = this.singlefile.lib.SingleFile || (() => {
  31. const singlefile = this.singlefile;
  32. const modules = {
  33. helper: singlefile.lib.helper,
  34. srcsetParser: singlefile.lib.vendor.srcsetParser,
  35. cssMinifier: singlefile.lib.vendor.cssMinifier,
  36. htmlMinifier: singlefile.lib.modules.htmlMinifier,
  37. serializer: singlefile.lib.modules.serializer,
  38. fontsMinifier: singlefile.lib.modules.fontsMinifier,
  39. fontsAltMinifier: singlefile.lib.modules.fontsAltMinifier,
  40. cssRulesMinifier: singlefile.lib.modules.cssRulesMinifier,
  41. matchedRules: singlefile.lib.modules.matchedRules,
  42. mediasAltMinifier: singlefile.lib.modules.mediasAltMinifier,
  43. imagesAltMinifier: singlefile.lib.modules.imagesAltMinifier
  44. };
  45. const util = {
  46. getResourceContent,
  47. digestText
  48. };
  49. const SingleFile = singlefile.lib.core.getClass(singlefile.lib.util.getInstance(modules, util), singlefile.lib.vendor.cssTree);
  50. const fetchResource = (singlefile.lib.fetch.content.resources && singlefile.lib.fetch.content.resources.fetch) || fetch;
  51. return {
  52. getClass: () => SingleFile
  53. };
  54. async function getResourceContent(resourceURL, options) {
  55. const resourceContent = await fetchResource(resourceURL, {
  56. referrerPolicy: options.referrerPolicy,
  57. credentials: options.credentials
  58. });
  59. const buffer = await resourceContent.arrayBuffer();
  60. return {
  61. getUrl() {
  62. return resourceContent.url || resourceURL;
  63. },
  64. getContentType() {
  65. return resourceContent.headers && resourceContent.headers.get("content-type");
  66. },
  67. getStatusCode() {
  68. return resourceContent.status;
  69. },
  70. getSize() {
  71. return buffer.byteLength;
  72. },
  73. getText(charset) {
  74. return new TextDecoder(charset).decode(buffer);
  75. },
  76. async getDataUri(contentType) {
  77. const reader = new FileReader();
  78. reader.readAsDataURL(new Blob([buffer], { type: contentType || this.getContentType() }));
  79. return new Promise((resolve, reject) => {
  80. reader.addEventListener("load", () => resolve(reader.result), false);
  81. reader.addEventListener("error", reject, false);
  82. });
  83. }
  84. };
  85. }
  86. async function digestText(algo, text) {
  87. const hash = await crypto.subtle.digest(algo, new TextEncoder("utf-8").encode(text));
  88. return hex(hash);
  89. }
  90. // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest
  91. function hex(buffer) {
  92. const hexCodes = [];
  93. const view = new DataView(buffer);
  94. for (let i = 0; i < view.byteLength; i += 4) {
  95. const value = view.getUint32(i);
  96. const stringValue = value.toString(16);
  97. const padding = "00000000";
  98. const paddedValue = (padding + stringValue).slice(-padding.length);
  99. hexCodes.push(paddedValue);
  100. }
  101. return hexCodes.join("");
  102. }
  103. })();