mhtml-stream 0.0.1 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,6 +2,8 @@ MHTML Stream
2
2
  ============
3
3
  [![build](https://github.com/erikbrinkman/mhtml-stream/actions/workflows/node.js.yml/badge.svg)](https://github.com/erikbrinkman/mhtml-stream/actions/workflows/node.js.yml)
4
4
  [![docs](https://img.shields.io/badge/docs-docs-blue)](https://erikbrinkman.github.io/mhtml-stream/)
5
+ [![npm](https://img.shields.io/npm/v/mhtml-stream)](https://www.npmjs.com/package/mhtml-stream)
6
+ [![license](https://img.shields.io/github/license/erikbrinkman/mhtml-stream)](LICENSE)
5
7
 
6
8
  Zero-dependency library for parsing MHTML data as streams using modern WHATWG
7
9
  streams and async iterators. Because it relies on modern cross javascript
@@ -25,3 +27,11 @@ for await (const { headers, content } of parseMhtml(...)) {
25
27
  // for how to parse each individual included file.
26
28
  }
27
29
  ```
30
+
31
+ Notes
32
+ -----
33
+
34
+ - As far as I can tell, header folding behavior is not well defined when it
35
+ comes to whether whitespace should be added when unfolding. This currently
36
+ uses the first whitespace character to indicate folding, and preservers any
37
+ others.
@@ -0,0 +1 @@
1
+ var j=Object.create;var h=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var W=Object.getOwnPropertyNames;var N=Object.getPrototypeOf,J=Object.prototype.hasOwnProperty;var R=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),V=(t,e)=>{for(var r in e)h(t,r,{get:e[r],enumerable:!0})},x=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of W(e))!J.call(t,o)&&o!==r&&h(t,o,{get:()=>e[o],enumerable:!(n=Q(e,o))||n.enumerable});return t};var U=(t,e,r)=>(r=t!=null?j(N(t)):{},x(e||!t||!t.__esModule?h(r,"default",{value:t,enumerable:!0}):r,t)),_=t=>x(h({},"__esModule",{value:!0}),t);var w=R(g=>{"use strict";g.byteLength=G;g.toByteArray=X;g.fromByteArray=ee;var c=[],d=[],z=typeof Uint8Array<"u"?Uint8Array:Array,b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(f=0,F=b.length;f<F;++f)c[f]=b[f],d[b.charCodeAt(f)]=f;var f,F;d["-".charCodeAt(0)]=62;d["_".charCodeAt(0)]=63;function B(t){var e=t.length;if(e%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var r=t.indexOf("=");r===-1&&(r=e);var n=r===e?0:4-r%4;return[r,n]}function G(t){var e=B(t),r=e[0],n=e[1];return(r+n)*3/4-n}function K(t,e,r){return(e+r)*3/4-r}function X(t){var e,r=B(t),n=r[0],o=r[1],a=new z(K(t,n,o)),s=0,i=o>0?n-4:n,l;for(l=0;l<i;l+=4)e=d[t.charCodeAt(l)]<<18|d[t.charCodeAt(l+1)]<<12|d[t.charCodeAt(l+2)]<<6|d[t.charCodeAt(l+3)],a[s++]=e>>16&255,a[s++]=e>>8&255,a[s++]=e&255;return o===2&&(e=d[t.charCodeAt(l)]<<2|d[t.charCodeAt(l+1)]>>4,a[s++]=e&255),o===1&&(e=d[t.charCodeAt(l)]<<10|d[t.charCodeAt(l+1)]<<4|d[t.charCodeAt(l+2)]>>2,a[s++]=e>>8&255,a[s++]=e&255),a}function Y(t){return c[t>>18&63]+c[t>>12&63]+c[t>>6&63]+c[t&63]}function Z(t,e,r){for(var n,o=[],a=e;a<r;a+=3)n=(t[a]<<16&16711680)+(t[a+1]<<8&65280)+(t[a+2]&255),o.push(Y(n));return o.join("")}function ee(t){for(var e,r=t.length,n=r%3,o=[],a=16383,s=0,i=r-n;s<i;s+=a)o.push(Z(t,s,s+a>i?i:s+a));return n===1?(e=t[r-1],o.push(c[e>>2]+c[e<<4&63]+"==")):n===2&&(e=(t[r-2]<<8)+t[r-1],o.push(c[e>>10]+c[e>>4&63]+c[e<<2&63]+"=")),o.join("")}});var fe={};V(fe,{parseMhtml:()=>ce});module.exports=_(fe);var q=U(w());var p=class{#e=new Map;[Symbol.iterator](){return this.entries()}append(e,r){let n=this.#e.get(e);n===void 0?this.#e.set(e,[r]):n.push(r)}*entries(e=", "){for(let[r,n]of this.#e.entries())yield[r,n.join(e)]}*entriesAll(){for(let[e,r]of this.#e.entries())for(let n of r)yield[e,n]}get(e,r=", "){let n=this.#e.get(e);return n===void 0?null:n.join(r)}getAll(e){return this.#e.get(e)??[]}has(e){return this.#e.has(e)}keys(){return this.#e.keys()}*values(e=", "){for(let r of this.#e.values())yield r.join(e)}*valuesAll(){for(let e of this.#e.values())yield*e}};var C=U(w());function te(t){return ArrayBuffer.isView(t)?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):new Uint8Array(t)}function v(t,e){if(t.length!==e.length)return!1;if(t.byteOffset%4===e.byteOffset%4){let r=(4-t.byteOffset%4)%4,n=Math.floor((t.byteLength-r)/4),o=r+n*4,a=new Uint32Array(t.buffer,t.byteOffset+r,n),s=new Uint32Array(e.buffer,e.byteOffset+r,n);for(let i=0;i<r;++i)if(t[i]!==e[i])return!1;for(let i=0;i<n;++i)if(a[i]!==s[i])return!1;for(let i=o;i<t.length;++i)if(t[i]!==e[i])return!1;return!0}else{for(let r of t.keys())if(t[r]!==e[r])return!1;return!0}}function re(t,e){return t.findIndex((r,n)=>{if(r!==e[0]||n+e.length>t.length)return!1;for(let o=1;o<e.length;++o)if(t[n+o]!==e[o])return!1;return!0})}async function*k(t,e){let r=new Uint8Array(0);for await(let n of t){let o=te(n);r=r.length?E([r,o]):o;let a;for(;(a=re(r,e))!==-1;)yield r.subarray(0,a),r=r.subarray(a+e.length)}yield r}function E(t){let e=t.reduce((o,a)=>o+a.length,0),r=new Uint8Array(e),n=0;for(let o of t)r.set(o,n),n+=o.length;return r}async function M(t){let e=[];for await(let r of t)e.push(r);return E(e)}var ne=new Uint8Array([10]);async function*L(t,e=ne){for await(let r of t){let n=new Uint8Array(r.length+e.length),o=!1,a=0;for(let s=0;s<r.length;++s){let i=r[s];if(i>=128)throw new Error(`got non-ascii character when decoding quoted printable: ${r}`);if(i!==61)n[a++]=i;else{let l=r[++s];if(l===void 0)o=!0;else{let u=r[++s];if(u===void 0)throw new Error("quoted printable escape (=) was not followed by two bytes");let y=parseInt(String.fromCharCode(l),16);y*=16,y+=parseInt(String.fromCharCode(u),16),n[a++]=y}}}o||(n.set(e,a),a+=e.length),yield n.subarray(0,a)}}var oe=new TextDecoder;async function*O(t){for await(let e of t)yield(0,C.toByteArray)(oe.decode(e))}async function*m(t){for await(let e of t)yield e}function H(){throw new Error("binary transfer-encoding is explicitly not supported and trying to add an implementation will likely result in unexpected results, but if you want to ignore anyway, set binary to `decode8bit`")}var $=new TextEncoder,D=new TextDecoder;function ae(t){let e=new Uint8Array(t.length),r=0;for(let n=0;n<t.length;++n){let o=t.charCodeAt(n),a;if(o>=128)throw new Error(`got non-ascii character when decoding q-quoted word: "${t}"`);o===95?a=32:o===61?(a=parseInt(t[++n],16),a*=16,a+=parseInt(t[++n],16)):a=o,e[r++]=a}return e.subarray(0,r)}var se=/^=\?([^?\s]+)\?([BQ])\?([^?\s]+)\?=$/;function T(t){let e=se.exec(t);if(e){let[,r,n,o]=e,a;if(n==="Q")a=ae(o);else if(n==="B")a=(0,q.toByteArray)(o);else throw new Error(`unknown encoding for header value encoding: ${n}`);return new TextDecoder(r).decode(a)}else return t}async function ie(t){let e=new p,r="",n="";for(;;){let{done:o,value:a}=await t.next();if(o)throw new Error("didn't find an empty line to signify the end of header parsing");let s=D.decode(a);if(/^\s/.test(s))n+=T(s.substr(1));else if(r&&e.append(r,n),s){let i=s.indexOf(": ");if(i===-1)throw new Error(`header line didn't have key-value delimiter: "${s}"`);r=s.slice(0,i),n=T(s.slice(i+2))}else return e}}var le=new Map([["7bit",m],["base64",O],["quoted-printable",L],["8bit",m],["binary",H]]);function de(t){let e=t.get("Content-Type");if(e===null)throw new Error(`first headers didn't contain a content type: ${JSON.stringify(Object.fromEntries(t))}`);let r,n=!1;for(let s of e.split(/;\s*/))s.startsWith("multipart/")?n=!0:s.startsWith("boundary=")&&(r=s.slice(9),r.startsWith('"')&&r.endsWith('"')&&(r=r.slice(1,-1)));if(!n||r===void 0)throw new Error("first content type header didn't contain 'multipart/...' and a boundary string");let o=$.encode(`--${r}`),a=$.encode(`--${r}--`);return[o,a]}async function*ce(t,{decoderOverrides:e=new Map}={}){let r=new Map([...le.entries(),...e.entries()]),n=new Uint8Array([13,10]),o=k(t,n),a=null,s=!0;for(;s;){let i=await ie(o),[l,u]=a??(a=de(i)),y=i.get("Content-Transfer-Encoding")??"7bit",I=r.get(y);if(I===void 0)throw new Error(`unhandled encoding type: ${y}`);let P=await M(I({[Symbol.asyncIterator](){return{async next(){let{done:S,value:A}=await o.next();if(S)throw new Error(`stream didn't end with the appropriate termination boundary: ${D.decode(u)}`);return v(A,l)?{done:!0,value:void 0}:v(A,u)?(s=!1,{done:!0,value:void 0}):{value:A}}}}}));yield{headers:i,content:P}}}0&&(module.exports={parseMhtml});
@@ -0,0 +1 @@
1
+ var S=Object.create;var I=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var Q=Object.getOwnPropertyNames;var W=Object.getPrototypeOf,N=Object.prototype.hasOwnProperty;var J=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var R=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Q(e))!N.call(t,o)&&o!==r&&I(t,o,{get:()=>e[o],enumerable:!(n=j(e,o))||n.enumerable});return t};var x=(t,e,r)=>(r=t!=null?S(W(t)):{},R(e||!t||!t.__esModule?I(r,"default",{value:t,enumerable:!0}):r,t));var b=J(h=>{"use strict";h.byteLength=_;h.toByteArray=G;h.fromByteArray=Y;var c=[],d=[],V=typeof Uint8Array<"u"?Uint8Array:Array,A="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(f=0,U=A.length;f<U;++f)c[f]=A[f],d[A.charCodeAt(f)]=f;var f,U;d["-".charCodeAt(0)]=62;d["_".charCodeAt(0)]=63;function F(t){var e=t.length;if(e%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var r=t.indexOf("=");r===-1&&(r=e);var n=r===e?0:4-r%4;return[r,n]}function _(t){var e=F(t),r=e[0],n=e[1];return(r+n)*3/4-n}function z(t,e,r){return(e+r)*3/4-r}function G(t){var e,r=F(t),n=r[0],o=r[1],a=new V(z(t,n,o)),s=0,i=o>0?n-4:n,l;for(l=0;l<i;l+=4)e=d[t.charCodeAt(l)]<<18|d[t.charCodeAt(l+1)]<<12|d[t.charCodeAt(l+2)]<<6|d[t.charCodeAt(l+3)],a[s++]=e>>16&255,a[s++]=e>>8&255,a[s++]=e&255;return o===2&&(e=d[t.charCodeAt(l)]<<2|d[t.charCodeAt(l+1)]>>4,a[s++]=e&255),o===1&&(e=d[t.charCodeAt(l)]<<10|d[t.charCodeAt(l+1)]<<4|d[t.charCodeAt(l+2)]>>2,a[s++]=e>>8&255,a[s++]=e&255),a}function K(t){return c[t>>18&63]+c[t>>12&63]+c[t>>6&63]+c[t&63]}function X(t,e,r){for(var n,o=[],a=e;a<r;a+=3)n=(t[a]<<16&16711680)+(t[a+1]<<8&65280)+(t[a+2]&255),o.push(K(n));return o.join("")}function Y(t){for(var e,r=t.length,n=r%3,o=[],a=16383,s=0,i=r-n;s<i;s+=a)o.push(X(t,s,s+a>i?i:s+a));return n===1?(e=t[r-1],o.push(c[e>>2]+c[e<<4&63]+"==")):n===2&&(e=(t[r-2]<<8)+t[r-1],o.push(c[e>>10]+c[e>>4&63]+c[e<<2&63]+"=")),o.join("")}});var T=x(b());var g=class{#e=new Map;[Symbol.iterator](){return this.entries()}append(e,r){let n=this.#e.get(e);n===void 0?this.#e.set(e,[r]):n.push(r)}*entries(e=", "){for(let[r,n]of this.#e.entries())yield[r,n.join(e)]}*entriesAll(){for(let[e,r]of this.#e.entries())for(let n of r)yield[e,n]}get(e,r=", "){let n=this.#e.get(e);return n===void 0?null:n.join(r)}getAll(e){return this.#e.get(e)??[]}has(e){return this.#e.has(e)}keys(){return this.#e.keys()}*values(e=", "){for(let r of this.#e.values())yield r.join(e)}*valuesAll(){for(let e of this.#e.values())yield*e}};var B=x(b());function Z(t){return ArrayBuffer.isView(t)?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):new Uint8Array(t)}function w(t,e){if(t.length!==e.length)return!1;if(t.byteOffset%4===e.byteOffset%4){let r=(4-t.byteOffset%4)%4,n=Math.floor((t.byteLength-r)/4),o=r+n*4,a=new Uint32Array(t.buffer,t.byteOffset+r,n),s=new Uint32Array(e.buffer,e.byteOffset+r,n);for(let i=0;i<r;++i)if(t[i]!==e[i])return!1;for(let i=0;i<n;++i)if(a[i]!==s[i])return!1;for(let i=o;i<t.length;++i)if(t[i]!==e[i])return!1;return!0}else{for(let r of t.keys())if(t[r]!==e[r])return!1;return!0}}function ee(t,e){return t.findIndex((r,n)=>{if(r!==e[0]||n+e.length>t.length)return!1;for(let o=1;o<e.length;++o)if(t[n+o]!==e[o])return!1;return!0})}async function*C(t,e){let r=new Uint8Array(0);for await(let n of t){let o=Z(n);r=r.length?k([r,o]):o;let a;for(;(a=ee(r,e))!==-1;)yield r.subarray(0,a),r=r.subarray(a+e.length)}yield r}function k(t){let e=t.reduce((o,a)=>o+a.length,0),r=new Uint8Array(e),n=0;for(let o of t)r.set(o,n),n+=o.length;return r}async function E(t){let e=[];for await(let r of t)e.push(r);return k(e)}var te=new Uint8Array([10]);async function*M(t,e=te){for await(let r of t){let n=new Uint8Array(r.length+e.length),o=!1,a=0;for(let s=0;s<r.length;++s){let i=r[s];if(i>=128)throw new Error(`got non-ascii character when decoding quoted printable: ${r}`);if(i!==61)n[a++]=i;else{let l=r[++s];if(l===void 0)o=!0;else{let u=r[++s];if(u===void 0)throw new Error("quoted printable escape (=) was not followed by two bytes");let y=parseInt(String.fromCharCode(l),16);y*=16,y+=parseInt(String.fromCharCode(u),16),n[a++]=y}}}o||(n.set(e,a),a+=e.length),yield n.subarray(0,a)}}var re=new TextDecoder;async function*L(t){for await(let e of t)yield(0,B.toByteArray)(re.decode(e))}async function*v(t){for await(let e of t)yield e}function O(){throw new Error("binary transfer-encoding is explicitly not supported and trying to add an implementation will likely result in unexpected results, but if you want to ignore anyway, set binary to `decode8bit`")}var H=new TextEncoder,q=new TextDecoder;function ne(t){let e=new Uint8Array(t.length),r=0;for(let n=0;n<t.length;++n){let o=t.charCodeAt(n),a;if(o>=128)throw new Error(`got non-ascii character when decoding q-quoted word: "${t}"`);o===95?a=32:o===61?(a=parseInt(t[++n],16),a*=16,a+=parseInt(t[++n],16)):a=o,e[r++]=a}return e.subarray(0,r)}var oe=/^=\?([^?\s]+)\?([BQ])\?([^?\s]+)\?=$/;function $(t){let e=oe.exec(t);if(e){let[,r,n,o]=e,a;if(n==="Q")a=ne(o);else if(n==="B")a=(0,T.toByteArray)(o);else throw new Error(`unknown encoding for header value encoding: ${n}`);return new TextDecoder(r).decode(a)}else return t}async function ae(t){let e=new g,r="",n="";for(;;){let{done:o,value:a}=await t.next();if(o)throw new Error("didn't find an empty line to signify the end of header parsing");let s=q.decode(a);if(/^\s/.test(s))n+=$(s.substr(1));else if(r&&e.append(r,n),s){let i=s.indexOf(": ");if(i===-1)throw new Error(`header line didn't have key-value delimiter: "${s}"`);r=s.slice(0,i),n=$(s.slice(i+2))}else return e}}var se=new Map([["7bit",v],["base64",L],["quoted-printable",M],["8bit",v],["binary",O]]);function ie(t){let e=t.get("Content-Type");if(e===null)throw new Error(`first headers didn't contain a content type: ${JSON.stringify(Object.fromEntries(t))}`);let r,n=!1;for(let s of e.split(/;\s*/))s.startsWith("multipart/")?n=!0:s.startsWith("boundary=")&&(r=s.slice(9),r.startsWith('"')&&r.endsWith('"')&&(r=r.slice(1,-1)));if(!n||r===void 0)throw new Error("first content type header didn't contain 'multipart/...' and a boundary string");let o=H.encode(`--${r}`),a=H.encode(`--${r}--`);return[o,a]}async function*ge(t,{decoderOverrides:e=new Map}={}){let r=new Map([...se.entries(),...e.entries()]),n=new Uint8Array([13,10]),o=C(t,n),a=null,s=!0;for(;s;){let i=await ae(o),[l,u]=a??(a=ie(i)),y=i.get("Content-Transfer-Encoding")??"7bit",m=r.get(y);if(m===void 0)throw new Error(`unhandled encoding type: ${y}`);let D=await E(m({[Symbol.asyncIterator](){return{async next(){let{done:P,value:p}=await o.next();if(P)throw new Error(`stream didn't end with the appropriate termination boundary: ${q.decode(u)}`);return w(p,l)?{done:!0,value:void 0}:w(p,u)?(s=!1,{done:!0,value:void 0}):{value:p}}}}}));yield{headers:i,content:D}}}export{ge as parseMhtml};
@@ -0,0 +1 @@
1
+ var mhtml=(()=>{var j=Object.create;var h=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var W=Object.getOwnPropertyNames;var N=Object.getPrototypeOf,J=Object.prototype.hasOwnProperty;var R=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),V=(t,e)=>{for(var r in e)h(t,r,{get:e[r],enumerable:!0})},x=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of W(e))!J.call(t,o)&&o!==r&&h(t,o,{get:()=>e[o],enumerable:!(n=Q(e,o))||n.enumerable});return t};var U=(t,e,r)=>(r=t!=null?j(N(t)):{},x(e||!t||!t.__esModule?h(r,"default",{value:t,enumerable:!0}):r,t)),_=t=>x(h({},"__esModule",{value:!0}),t);var w=R(g=>{"use strict";g.byteLength=G;g.toByteArray=X;g.fromByteArray=ee;var c=[],d=[],z=typeof Uint8Array<"u"?Uint8Array:Array,b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(f=0,F=b.length;f<F;++f)c[f]=b[f],d[b.charCodeAt(f)]=f;var f,F;d["-".charCodeAt(0)]=62;d["_".charCodeAt(0)]=63;function B(t){var e=t.length;if(e%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var r=t.indexOf("=");r===-1&&(r=e);var n=r===e?0:4-r%4;return[r,n]}function G(t){var e=B(t),r=e[0],n=e[1];return(r+n)*3/4-n}function K(t,e,r){return(e+r)*3/4-r}function X(t){var e,r=B(t),n=r[0],o=r[1],a=new z(K(t,n,o)),s=0,i=o>0?n-4:n,l;for(l=0;l<i;l+=4)e=d[t.charCodeAt(l)]<<18|d[t.charCodeAt(l+1)]<<12|d[t.charCodeAt(l+2)]<<6|d[t.charCodeAt(l+3)],a[s++]=e>>16&255,a[s++]=e>>8&255,a[s++]=e&255;return o===2&&(e=d[t.charCodeAt(l)]<<2|d[t.charCodeAt(l+1)]>>4,a[s++]=e&255),o===1&&(e=d[t.charCodeAt(l)]<<10|d[t.charCodeAt(l+1)]<<4|d[t.charCodeAt(l+2)]>>2,a[s++]=e>>8&255,a[s++]=e&255),a}function Y(t){return c[t>>18&63]+c[t>>12&63]+c[t>>6&63]+c[t&63]}function Z(t,e,r){for(var n,o=[],a=e;a<r;a+=3)n=(t[a]<<16&16711680)+(t[a+1]<<8&65280)+(t[a+2]&255),o.push(Y(n));return o.join("")}function ee(t){for(var e,r=t.length,n=r%3,o=[],a=16383,s=0,i=r-n;s<i;s+=a)o.push(Z(t,s,s+a>i?i:s+a));return n===1?(e=t[r-1],o.push(c[e>>2]+c[e<<4&63]+"==")):n===2&&(e=(t[r-2]<<8)+t[r-1],o.push(c[e>>10]+c[e>>4&63]+c[e<<2&63]+"=")),o.join("")}});var fe={};V(fe,{parseMhtml:()=>ce});var q=U(w());var p=class{#e=new Map;[Symbol.iterator](){return this.entries()}append(e,r){let n=this.#e.get(e);n===void 0?this.#e.set(e,[r]):n.push(r)}*entries(e=", "){for(let[r,n]of this.#e.entries())yield[r,n.join(e)]}*entriesAll(){for(let[e,r]of this.#e.entries())for(let n of r)yield[e,n]}get(e,r=", "){let n=this.#e.get(e);return n===void 0?null:n.join(r)}getAll(e){return this.#e.get(e)??[]}has(e){return this.#e.has(e)}keys(){return this.#e.keys()}*values(e=", "){for(let r of this.#e.values())yield r.join(e)}*valuesAll(){for(let e of this.#e.values())yield*e}};var C=U(w());function te(t){return ArrayBuffer.isView(t)?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):new Uint8Array(t)}function v(t,e){if(t.length!==e.length)return!1;if(t.byteOffset%4===e.byteOffset%4){let r=(4-t.byteOffset%4)%4,n=Math.floor((t.byteLength-r)/4),o=r+n*4,a=new Uint32Array(t.buffer,t.byteOffset+r,n),s=new Uint32Array(e.buffer,e.byteOffset+r,n);for(let i=0;i<r;++i)if(t[i]!==e[i])return!1;for(let i=0;i<n;++i)if(a[i]!==s[i])return!1;for(let i=o;i<t.length;++i)if(t[i]!==e[i])return!1;return!0}else{for(let r of t.keys())if(t[r]!==e[r])return!1;return!0}}function re(t,e){return t.findIndex((r,n)=>{if(r!==e[0]||n+e.length>t.length)return!1;for(let o=1;o<e.length;++o)if(t[n+o]!==e[o])return!1;return!0})}async function*k(t,e){let r=new Uint8Array(0);for await(let n of t){let o=te(n);r=r.length?E([r,o]):o;let a;for(;(a=re(r,e))!==-1;)yield r.subarray(0,a),r=r.subarray(a+e.length)}yield r}function E(t){let e=t.reduce((o,a)=>o+a.length,0),r=new Uint8Array(e),n=0;for(let o of t)r.set(o,n),n+=o.length;return r}async function M(t){let e=[];for await(let r of t)e.push(r);return E(e)}var ne=new Uint8Array([10]);async function*L(t,e=ne){for await(let r of t){let n=new Uint8Array(r.length+e.length),o=!1,a=0;for(let s=0;s<r.length;++s){let i=r[s];if(i>=128)throw new Error(`got non-ascii character when decoding quoted printable: ${r}`);if(i!==61)n[a++]=i;else{let l=r[++s];if(l===void 0)o=!0;else{let u=r[++s];if(u===void 0)throw new Error("quoted printable escape (=) was not followed by two bytes");let y=parseInt(String.fromCharCode(l),16);y*=16,y+=parseInt(String.fromCharCode(u),16),n[a++]=y}}}o||(n.set(e,a),a+=e.length),yield n.subarray(0,a)}}var oe=new TextDecoder;async function*O(t){for await(let e of t)yield(0,C.toByteArray)(oe.decode(e))}async function*m(t){for await(let e of t)yield e}function H(){throw new Error("binary transfer-encoding is explicitly not supported and trying to add an implementation will likely result in unexpected results, but if you want to ignore anyway, set binary to `decode8bit`")}var $=new TextEncoder,D=new TextDecoder;function ae(t){let e=new Uint8Array(t.length),r=0;for(let n=0;n<t.length;++n){let o=t.charCodeAt(n),a;if(o>=128)throw new Error(`got non-ascii character when decoding q-quoted word: "${t}"`);o===95?a=32:o===61?(a=parseInt(t[++n],16),a*=16,a+=parseInt(t[++n],16)):a=o,e[r++]=a}return e.subarray(0,r)}var se=/^=\?([^?\s]+)\?([BQ])\?([^?\s]+)\?=$/;function T(t){let e=se.exec(t);if(e){let[,r,n,o]=e,a;if(n==="Q")a=ae(o);else if(n==="B")a=(0,q.toByteArray)(o);else throw new Error(`unknown encoding for header value encoding: ${n}`);return new TextDecoder(r).decode(a)}else return t}async function ie(t){let e=new p,r="",n="";for(;;){let{done:o,value:a}=await t.next();if(o)throw new Error("didn't find an empty line to signify the end of header parsing");let s=D.decode(a);if(/^\s/.test(s))n+=T(s.substr(1));else if(r&&e.append(r,n),s){let i=s.indexOf(": ");if(i===-1)throw new Error(`header line didn't have key-value delimiter: "${s}"`);r=s.slice(0,i),n=T(s.slice(i+2))}else return e}}var le=new Map([["7bit",m],["base64",O],["quoted-printable",L],["8bit",m],["binary",H]]);function de(t){let e=t.get("Content-Type");if(e===null)throw new Error(`first headers didn't contain a content type: ${JSON.stringify(Object.fromEntries(t))}`);let r,n=!1;for(let s of e.split(/;\s*/))s.startsWith("multipart/")?n=!0:s.startsWith("boundary=")&&(r=s.slice(9),r.startsWith('"')&&r.endsWith('"')&&(r=r.slice(1,-1)));if(!n||r===void 0)throw new Error("first content type header didn't contain 'multipart/...' and a boundary string");let o=$.encode(`--${r}`),a=$.encode(`--${r}--`);return[o,a]}async function*ce(t,{decoderOverrides:e=new Map}={}){let r=new Map([...le.entries(),...e.entries()]),n=new Uint8Array([13,10]),o=k(t,n),a=null,s=!0;for(;s;){let i=await ie(o),[l,u]=a??(a=de(i)),y=i.get("Content-Transfer-Encoding")??"7bit",I=r.get(y);if(I===void 0)throw new Error(`unhandled encoding type: ${y}`);let P=await M(I({[Symbol.asyncIterator](){return{async next(){let{done:S,value:A}=await o.next();if(S)throw new Error(`stream didn't end with the appropriate termination boundary: ${D.decode(u)}`);return v(A,l)?{done:!0,value:void 0}:v(A,u)?(s=!1,{done:!0,value:void 0}):{value:A}}}}}));yield{headers:i,content:P}}}return _(fe);})();
@@ -0,0 +1,62 @@
1
+ /**
2
+ * class for storing headers parse from MHTML
3
+ *
4
+ * Tries to somewhat mimic the behavior of the fetch-api Headers object, with
5
+ * some differences, notably that it does no validation.
6
+ */
7
+ export interface MhtmlHeaders extends Iterable<[string, string]> {
8
+ /**
9
+ * add a key-value pair
10
+ *
11
+ * If key is already present it will be appended.
12
+ */
13
+ append(key: string, value: string): void;
14
+ /**
15
+ * iterate over all key-value pairs
16
+ *
17
+ * Multiple values for the same key will be joined in the order they were
18
+ * added by `delim`.
19
+ */
20
+ entries(delim?: string): IterableIterator<[string, string]>;
21
+ /**
22
+ * iterate over all key-value pairs
23
+ *
24
+ * Multiple values for the same key will get iterated in the order they were
25
+ * added.
26
+ */
27
+ entriesAll(): IterableIterator<[string, string]>;
28
+ /**
29
+ * get the value for a key
30
+ *
31
+ * If the key is missing, null will be returned, if multiple values for the
32
+ * key are present, they will be joined be `delim`.
33
+ */
34
+ get(key: string, delim?: string): string | null;
35
+ /** get all values for a key */
36
+ getAll(key: string): string[];
37
+ /** whether key has any values associated with it */
38
+ has(key: string): boolean;
39
+ /** all keys with at least one value */
40
+ keys(): Iterable<string>;
41
+ /**
42
+ * iterate over all values
43
+ *
44
+ * If a key has multiple values they will be joined by `delim`.
45
+ */
46
+ values(delim?: string): IterableIterator<string>;
47
+ /** iterate over all values added */
48
+ valuesAll(): IterableIterator<string>;
49
+ }
50
+ export declare class Headers implements MhtmlHeaders {
51
+ #private;
52
+ [Symbol.iterator](): Iterator<[string, string]>;
53
+ append(key: string, value: string): void;
54
+ entries(delim?: string): IterableIterator<[string, string]>;
55
+ entriesAll(): IterableIterator<[string, string]>;
56
+ get(key: string, delim?: string): string | null;
57
+ getAll(key: string): string[];
58
+ has(key: string): boolean;
59
+ keys(): Iterable<string>;
60
+ values(delim?: string): IterableIterator<string>;
61
+ valuesAll(): IterableIterator<string>;
62
+ }
@@ -0,0 +1,55 @@
1
+ export class Headers {
2
+ #raw = new Map();
3
+ [Symbol.iterator]() {
4
+ return this.entries();
5
+ }
6
+ append(key, value) {
7
+ const list = this.#raw.get(key);
8
+ if (list === undefined) {
9
+ this.#raw.set(key, [value]);
10
+ }
11
+ else {
12
+ list.push(value);
13
+ }
14
+ }
15
+ *entries(delim = ", ") {
16
+ for (const [key, values] of this.#raw.entries()) {
17
+ yield [key, values.join(delim)];
18
+ }
19
+ }
20
+ *entriesAll() {
21
+ for (const [key, values] of this.#raw.entries()) {
22
+ for (const val of values) {
23
+ yield [key, val];
24
+ }
25
+ }
26
+ }
27
+ get(key, delim = ", ") {
28
+ const vals = this.#raw.get(key);
29
+ if (vals === undefined) {
30
+ return null;
31
+ }
32
+ else {
33
+ return vals.join(delim);
34
+ }
35
+ }
36
+ getAll(key) {
37
+ return this.#raw.get(key) ?? [];
38
+ }
39
+ has(key) {
40
+ return this.#raw.has(key);
41
+ }
42
+ keys() {
43
+ return this.#raw.keys();
44
+ }
45
+ *values(delim = ", ") {
46
+ for (const vals of this.#raw.values()) {
47
+ yield vals.join(delim);
48
+ }
49
+ }
50
+ *valuesAll() {
51
+ for (const vals of this.#raw.values()) {
52
+ yield* vals;
53
+ }
54
+ }
55
+ }
package/dist/index.d.ts CHANGED
@@ -1,81 +1,25 @@
1
- /**
2
- * class for storing headers parse from MHTML
3
- *
4
- * Tries to somewhat mimic the behavior of the fetch-api Headers object, with
5
- * some differences, notably that it does no validation.
6
- */
7
- export declare class MhtmlHeaders {
8
- #private;
9
- [Symbol.iterator](): Iterator<[string, string]>;
10
- /**
11
- * add a key-value pair
12
- *
13
- * If key is already present it will be appended.
14
- */
15
- append(key: string, value: string): void;
16
- /**
17
- * iterate over all key-value pairs
18
- *
19
- * Multiple values for the same key will be joined in the order they were
20
- * added by `delim`.
21
- */
22
- entries(delim?: string): IterableIterator<[string, string]>;
23
- /**
24
- * iterate over all key-value pairs
25
- *
26
- * Multiple values for the same key will get iterated in the order they were
27
- * added.
28
- */
29
- entriesAll(): IterableIterator<[string, string]>;
30
- /**
31
- * get the value for a key
32
- *
33
- * If the key is missing, null will be returned, if multiple values for the
34
- * key are present, they will be joined be `delim`.
35
- */
36
- get(key: string, delim?: string): string | null;
37
- /**
38
- * get all values for a key
39
- */
40
- getAll(key: string): string[];
41
- /**
42
- * whether key has any values associated with it
43
- */
44
- has(key: string): boolean;
45
- /**
46
- * all keys with at least one value
47
- */
48
- keys(): Iterable<string>;
49
- /**
50
- * iterate over all values
51
- *
52
- * If a key has multiple values they will be joined by `delim`.
53
- */
54
- values(delim?: string): IterableIterator<string>;
55
- /**
56
- * iterate over all values added
57
- */
58
- valuesAll(): IterableIterator<string>;
59
- }
60
- /**
61
- * a file that was encoded in MHTML format
62
- */
1
+ import { MhtmlHeaders } from "./headers";
2
+ export type { MhtmlHeaders };
3
+ /** a file that was encoded in MHTML format */
63
4
  export interface MhtmlFile {
5
+ /** the files's headers */
64
6
  headers: MhtmlHeaders;
7
+ /** the file's content */
65
8
  content: Uint8Array;
66
9
  }
67
- /**
68
- * The decoder of any Content-Transfer-Encoding
69
- */
10
+ /** The decoder of any Content-Transfer-Encoding */
70
11
  export interface Decoder {
71
12
  (lines: AsyncIterable<Uint8Array>): AsyncIterable<Uint8Array>;
72
13
  }
14
+ /** options for mhtml parsing */
15
+ export interface ParseOptions {
16
+ /** custom decoders for other Content-Transfer-Encodings */
17
+ decoderOverrides?: Map<string, Decoder>;
18
+ }
73
19
  /**
74
20
  * parse a readable stream into an async iterator of MHTML files
75
21
  *
76
22
  * decoderOverrides can be used to overwrite default encoders or specify your
77
23
  * own if a Content-Transfer-Encoding isn't handled properly
78
24
  */
79
- export declare function parseMhtml(stream: ReadableStream<ArrayBuffer>, { decoderOverrides, }?: {
80
- decoderOverrides?: Map<string, Decoder>;
81
- }): AsyncIterableIterator<MhtmlFile>;
25
+ export declare function parseMhtml(stream: AsyncIterable<ArrayBuffer>, { decoderOverrides }?: ParseOptions): AsyncIterableIterator<MhtmlFile>;
package/dist/index.js CHANGED
@@ -1,113 +1,11 @@
1
- import { decodeBase64 as decodeBEncoding } from "./base64";
2
- import { asIterable, bytesEqual, collect, decodeBase64, decodeBinary, decodeIdentity, decodeQuotedPrintable, splitStream, } from "./utils";
1
+ import { toByteArray } from "base64-js";
2
+ import { Headers } from "./headers";
3
+ import { bytesEqual, collect, decodeBase64, decodeBinary, decodeIdentity, decodeQuotedPrintable, splitStream, } from "./utils";
3
4
  // NOTE we use this for ascii because it's faster than manual, but may cause
4
5
  // unexpected errors if the assumption is violated
5
6
  const encoder = new TextEncoder();
6
7
  const decoder = new TextDecoder();
7
- /**
8
- * class for storing headers parse from MHTML
9
- *
10
- * Tries to somewhat mimic the behavior of the fetch-api Headers object, with
11
- * some differences, notably that it does no validation.
12
- */
13
- export class MhtmlHeaders {
14
- #raw = new Map();
15
- [Symbol.iterator]() {
16
- return this.entries();
17
- }
18
- /**
19
- * add a key-value pair
20
- *
21
- * If key is already present it will be appended.
22
- */
23
- append(key, value) {
24
- const list = this.#raw.get(key);
25
- if (list === undefined) {
26
- this.#raw.set(key, [value]);
27
- }
28
- else {
29
- list.push(value);
30
- }
31
- }
32
- /**
33
- * iterate over all key-value pairs
34
- *
35
- * Multiple values for the same key will be joined in the order they were
36
- * added by `delim`.
37
- */
38
- *entries(delim = ", ") {
39
- for (const [key, values] of this.#raw.entries()) {
40
- yield [key, values.join(delim)];
41
- }
42
- }
43
- /**
44
- * iterate over all key-value pairs
45
- *
46
- * Multiple values for the same key will get iterated in the order they were
47
- * added.
48
- */
49
- *entriesAll() {
50
- for (const [key, values] of this.#raw.entries()) {
51
- for (const val of values) {
52
- yield [key, val];
53
- }
54
- }
55
- }
56
- /**
57
- * get the value for a key
58
- *
59
- * If the key is missing, null will be returned, if multiple values for the
60
- * key are present, they will be joined be `delim`.
61
- */
62
- get(key, delim = ", ") {
63
- const vals = this.#raw.get(key);
64
- if (vals === undefined) {
65
- return null;
66
- }
67
- else {
68
- return vals.join(delim);
69
- }
70
- }
71
- /**
72
- * get all values for a key
73
- */
74
- getAll(key) {
75
- return this.#raw.get(key) ?? [];
76
- }
77
- /**
78
- * whether key has any values associated with it
79
- */
80
- has(key) {
81
- return this.#raw.has(key);
82
- }
83
- /**
84
- * all keys with at least one value
85
- */
86
- keys() {
87
- return this.#raw.keys();
88
- }
89
- /**
90
- * iterate over all values
91
- *
92
- * If a key has multiple values they will be joined by `delim`.
93
- */
94
- *values(delim = ", ") {
95
- for (const vals of this.#raw.values()) {
96
- yield vals.join(delim);
97
- }
98
- }
99
- /**
100
- * iterate over all values added
101
- */
102
- *valuesAll() {
103
- for (const vals of this.#raw.values()) {
104
- yield* vals;
105
- }
106
- }
107
- }
108
- /**
109
- * decode a q-encoded token
110
- */
8
+ /** decode a q-encoded token */
111
9
  function decodeQEncoding(text) {
112
10
  const res = new Uint8Array(text.length);
113
11
  let destInd = 0;
@@ -136,9 +34,7 @@ function decodeQEncoding(text) {
136
34
  return res.subarray(0, destInd);
137
35
  }
138
36
  const encodeFormat = /^=\?([^?\s]+)\?([BQ])\?([^?\s]+)\?=$/;
139
- /**
140
- * decode a header line that may have an extra encoding in it
141
- */
37
+ /** decode a header line that may have an extra encoding in it */
142
38
  function decodeLine(line) {
143
39
  // TODO this might make more sense as a function as part of a regex replaceAll
144
40
  const match = encodeFormat.exec(line);
@@ -150,7 +46,7 @@ function decodeLine(line) {
150
46
  buff = decodeQEncoding(text);
151
47
  }
152
48
  else if (encoding === "B") {
153
- buff = decodeBEncoding(text);
49
+ buff = toByteArray(text);
154
50
  }
155
51
  else {
156
52
  // NOTE should be impossible
@@ -170,7 +66,7 @@ function decodeLine(line) {
170
66
  * keys instead of storing multiple
171
67
  */
172
68
  async function parseHeaders(iter) {
173
- const headers = new MhtmlHeaders();
69
+ const headers = new Headers();
174
70
  let key = "";
175
71
  let val = "";
176
72
  for (;;) {
@@ -181,8 +77,7 @@ async function parseHeaders(iter) {
181
77
  const line = decoder.decode(value);
182
78
  if (/^\s/.test(line)) {
183
79
  // header folded
184
- val += " ";
185
- val += decodeLine(line.trimStart());
80
+ val += decodeLine(line.substr(1));
186
81
  }
187
82
  else {
188
83
  if (key) {
@@ -222,7 +117,7 @@ function getBoundary(headers) {
222
117
  }
223
118
  let bound = undefined;
224
119
  let multipart = false;
225
- for (const field of contentType.split("; ")) {
120
+ for (const field of contentType.split(/;\s*/)) {
226
121
  if (field.startsWith("multipart/")) {
227
122
  multipart = true;
228
123
  }
@@ -247,14 +142,14 @@ function getBoundary(headers) {
247
142
  * decoderOverrides can be used to overwrite default encoders or specify your
248
143
  * own if a Content-Transfer-Encoding isn't handled properly
249
144
  */
250
- export async function* parseMhtml(stream, { decoderOverrides = new Map(), } = {}) {
145
+ export async function* parseMhtml(stream, { decoderOverrides = new Map() } = {}) {
251
146
  // initial setup
252
147
  const decoders = new Map([
253
148
  ...defaultDecoders.entries(),
254
149
  ...decoderOverrides.entries(),
255
150
  ]);
256
151
  const crlf = new Uint8Array([13, 10]);
257
- const lines = splitStream(asIterable(stream), crlf);
152
+ const lines = splitStream(stream, crlf);
258
153
  let bound = null;
259
154
  let cont = true;
260
155
  while (cont) {
package/dist/utils.d.ts CHANGED
@@ -9,10 +9,6 @@ export declare function toBytes(buff: ArrayBuffer): Uint8Array;
9
9
  * Compare two byte arrays for equality
10
10
  */
11
11
  export declare function bytesEqual(left: Uint8Array, right: Uint8Array): boolean;
12
- /**
13
- * convert readable stream to async iterator
14
- */
15
- export declare function asIterable<T extends ArrayBuffer>(stream: ReadableStream<T>): AsyncIterable<T>;
16
12
  /**
17
13
  * Find index of one byte array in another
18
14
  */
package/dist/utils.js CHANGED
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * @packageDocumentation
9
9
  */
10
- import { decodeBase64 as db64 } from "./base64";
10
+ import { toByteArray } from "base64-js";
11
11
  /**
12
12
  * create a Uint8Array from a buffer
13
13
  *
@@ -63,28 +63,6 @@ export function bytesEqual(left, right) {
63
63
  return true;
64
64
  }
65
65
  }
66
- /**
67
- * convert readable stream to async iterator
68
- */
69
- export function asIterable(stream) {
70
- return {
71
- [Symbol.asyncIterator]() {
72
- const reader = stream.getReader();
73
- return {
74
- // NOTE this complexity is for typescript
75
- async next() {
76
- const res = await reader.read();
77
- if (res.done) {
78
- return { done: true, value: undefined };
79
- }
80
- else {
81
- return { done: false, value: res.value };
82
- }
83
- },
84
- };
85
- },
86
- };
87
- }
88
66
  /**
89
67
  * Find index of one byte array in another
90
68
  */
@@ -199,7 +177,7 @@ const decoder = new TextDecoder();
199
177
  */
200
178
  export async function* decodeBase64(lines) {
201
179
  for await (const bytes of lines) {
202
- yield db64(decoder.decode(bytes));
180
+ yield toByteArray(decoder.decode(bytes));
203
181
  }
204
182
  }
205
183
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mhtml-stream",
3
- "version": "0.0.1",
3
+ "version": "0.0.4",
4
4
  "description": "Zero dependency stream MHTML parser",
5
5
  "keywords": [
6
6
  "mhtml",
@@ -12,41 +12,141 @@
12
12
  },
13
13
  "author": "Erik Brinkman <erik.brinkman@gmail.com>",
14
14
  "license": "MIT",
15
- "module": "dist/index.js",
16
15
  "types": "dist/index.d.ts",
17
- "main": "dist/index.cjs.min.js",
18
- "unpkg": "dist/index.iife.min.js",
16
+ "module": "bundle/mhtml.esm.min.js",
17
+ "main": "bundle/mhtml.cjs.min.js",
18
+ "unpkg": "bundle/mhtml.iife.min.js",
19
19
  "files": [
20
+ "/bundle/*.js",
20
21
  "/dist/**/*.js",
21
22
  "/dist/**/*.d.ts"
22
23
  ],
23
24
  "type": "module",
24
25
  "scripts": {
25
- "fmt": "prettier --write 'src/*.ts' '*.json'",
26
- "lint": "tsc && eslint 'src/*.ts'",
26
+ "fmt": "prettier --write 'src/*.ts' '*.json' bundle.mjs",
27
+ "lint": "tsc && eslint --cache 'src/*.ts' && typedoc --emit none",
27
28
  "test": "jest --coverage",
28
29
  "doc": "typedoc",
29
- "build": "tsc -p tsconfig.build.json && esbuild src/index.ts --bundle --minify --format=cjs --outfile=dist/index.cjs.min.js && esbuild src/index.ts --bundle --minify --global-name=mhtmlStream --outfile=dist/index.iife.min.js",
30
- "prepare": "yarn lint && yarn test && yarn build"
30
+ "build": "tsc -p tsconfig.build.json && node bundle.mjs",
31
+ "prepack": "yarn lint && yarn test && yarn build"
32
+ },
33
+ "dependencies": {
34
+ "base64-js": "^1.5.1"
31
35
  },
32
36
  "devDependencies": {
33
- "@types/node": "^17.0.14",
34
- "esbuild": "^0.14.17",
35
- "@babel/core": "^7.16.12",
36
- "@babel/preset-env": "^7.16.11",
37
- "@babel/preset-typescript": "^7.16.7",
38
- "@types/jest": "^27.4.0",
39
- "@typescript-eslint/eslint-plugin": "^5.10.0",
40
- "@typescript-eslint/parser": "^5.10.0",
41
- "babel-jest": "^27.4.6",
42
- "eslint": "^8.7.0",
43
- "eslint-config-prettier": "^8.3.0",
44
- "eslint-plugin-jest": "^26.0.0",
37
+ "@babel/core": "^7.18.5",
38
+ "@babel/preset-env": "^7.18.2",
39
+ "@babel/preset-typescript": "^7.17.12",
40
+ "@types/base64-js": "^1.3.0",
41
+ "@types/jest": "^28.1.3",
42
+ "@types/node": "^18.0.0",
43
+ "@typescript-eslint/eslint-plugin": "^5.29.0",
44
+ "@typescript-eslint/parser": "^5.29.0",
45
+ "@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.9",
46
+ "babel-jest": "^28.1.1",
47
+ "chalk": "5.0.1",
48
+ "esbuild": "^0.14.47",
49
+ "eslint": "^8.18.0",
50
+ "eslint-config-prettier": "^8.5.0",
51
+ "eslint-plugin-jest": "^26.5.3",
45
52
  "eslint-plugin-spellcheck": "^0.0.19",
46
- "jest": "^27.4.7",
47
- "prettier": "^2.5.1",
48
- "prettier-plugin-organize-imports": "^2.3.4",
49
- "typedoc": "^0.22.11",
50
- "typescript": "^4.5.5"
51
- }
52
- }
53
+ "eslint-plugin-tsdoc": "^0.2.16",
54
+ "jest": "^28.1.1",
55
+ "prettier": "^2.7.1",
56
+ "prettier-plugin-organize-imports": "^3.0.0",
57
+ "typedoc": "^0.22.17",
58
+ "typescript": "^4.6.4"
59
+ },
60
+ "resolutions": {
61
+ "minimist": "1.2.6"
62
+ },
63
+ "prettier": {
64
+ "plugins": [
65
+ "prettier-plugin-organize-imports"
66
+ ]
67
+ },
68
+ "jest": {
69
+ "testEnvironment": "node"
70
+ },
71
+ "babel": {
72
+ "presets": [
73
+ [
74
+ "@babel/preset-env",
75
+ {
76
+ "targets": {
77
+ "node": "current"
78
+ }
79
+ }
80
+ ],
81
+ "@babel/preset-typescript"
82
+ ]
83
+ },
84
+ "eslintConfig": {
85
+ "root": true,
86
+ "parser": "@typescript-eslint/parser",
87
+ "plugins": [
88
+ "@typescript-eslint",
89
+ "jest",
90
+ "spellcheck",
91
+ "eslint-plugin-tsdoc"
92
+ ],
93
+ "extends": [
94
+ "eslint:recommended",
95
+ "plugin:@typescript-eslint/recommended",
96
+ "plugin:jest/recommended",
97
+ "prettier"
98
+ ],
99
+ "env": {
100
+ "node": true
101
+ },
102
+ "rules": {
103
+ "@typescript-eslint/no-inferrable-types": "off",
104
+ "@typescript-eslint/no-non-null-assertion": "off",
105
+ "@typescript-eslint/no-unused-vars": [
106
+ "error",
107
+ {
108
+ "varsIgnorePattern": "^_+$"
109
+ }
110
+ ],
111
+ "prefer-const": [
112
+ "error",
113
+ {
114
+ "destructuring": "all"
115
+ }
116
+ ],
117
+ "no-warning-comments": [
118
+ "error",
119
+ {
120
+ "terms": [
121
+ "fixme"
122
+ ],
123
+ "location": "anywhere"
124
+ }
125
+ ],
126
+ "spellcheck/spell-checker": [
127
+ "error",
128
+ {
129
+ "identifiers": false,
130
+ "skipIfMatch": [
131
+ "[^\\s]{20,}"
132
+ ],
133
+ "skipWords": [
134
+ "0x7fffffff",
135
+ "Chr",
136
+ "Dvalue",
137
+ "Hola",
138
+ "Mhtml",
139
+ "Today’s",
140
+ "Uint",
141
+ "Yorker",
142
+ "ascii",
143
+ "delim",
144
+ "multipart",
145
+ "versa"
146
+ ]
147
+ }
148
+ ]
149
+ }
150
+ },
151
+ "packageManager": "yarn@3.2.0"
152
+ }
package/dist/base64.d.ts DELETED
@@ -1,8 +0,0 @@
1
- /**
2
- * decode base 64 string as bytes
3
- */
4
- export declare function decodeBase64(sBase64: string, nBlocksSize?: number): Uint8Array;
5
- /**
6
- * encode bytes as base64 string
7
- */
8
- export declare function encodeBase64(aBytes: Uint8Array): string;
package/dist/base64.js DELETED
@@ -1,77 +0,0 @@
1
- /*\
2
- |*|
3
- |*| Base64 / binary data / UTF-8 strings utilities
4
- |*|
5
- |*| https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
6
- |*|
7
- \*/
8
- /* Array of bytes to Base64 string decoding */
9
- function b64ToUint6(nChr) {
10
- return nChr > 64 && nChr < 91
11
- ? nChr - 65
12
- : nChr > 96 && nChr < 123
13
- ? nChr - 71
14
- : nChr > 47 && nChr < 58
15
- ? nChr + 4
16
- : nChr === 43
17
- ? 62
18
- : nChr === 47
19
- ? 63
20
- : /* istanbul ignore next */
21
- 0;
22
- }
23
- /**
24
- * decode base 64 string as bytes
25
- */
26
- export function decodeBase64(sBase64, nBlocksSize) {
27
- const sB64Enc = sBase64.replace(/[^A-Za-z0-9+/]/g, "");
28
- const nInLen = sB64Enc.length;
29
- const nOutLen = nBlocksSize
30
- ? Math.ceil(((nInLen * 3 + 1) >> 2) / nBlocksSize) * nBlocksSize
31
- : (nInLen * 3 + 1) >> 2;
32
- const taBytes = new Uint8Array(nOutLen);
33
- for (let nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
34
- const nMod4 = nInIdx & 3;
35
- nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << (6 * (3 - nMod4));
36
- if (nMod4 === 3 || nInLen - nInIdx === 1) {
37
- for (let nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
38
- taBytes[nOutIdx] = (nUint24 >>> ((16 >>> nMod3) & 24)) & 255;
39
- }
40
- nUint24 = 0;
41
- }
42
- }
43
- return taBytes;
44
- }
45
- /* Base64 string to array encoding */
46
- function uint6ToB64(nUint6) {
47
- return nUint6 < 26
48
- ? nUint6 + 65
49
- : nUint6 < 52
50
- ? nUint6 + 71
51
- : nUint6 < 62
52
- ? nUint6 - 4
53
- : nUint6 === 62
54
- ? 43
55
- : nUint6 === 63
56
- ? 47
57
- : /* istanbul ignore next */
58
- 65;
59
- }
60
- /**
61
- * encode bytes as base64 string
62
- */
63
- export function encodeBase64(aBytes) {
64
- const nLen = aBytes.length;
65
- let nMod3 = 2;
66
- let sB64Enc = "";
67
- for (let nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) {
68
- nMod3 = nIdx % 3;
69
- nUint24 |= aBytes[nIdx] << ((16 >>> nMod3) & 24);
70
- if (nMod3 === 2 || aBytes.length - nIdx === 1) {
71
- sB64Enc += String.fromCodePoint(uint6ToB64((nUint24 >>> 18) & 63), uint6ToB64((nUint24 >>> 12) & 63), uint6ToB64((nUint24 >>> 6) & 63), uint6ToB64(nUint24 & 63));
72
- nUint24 = 0;
73
- }
74
- }
75
- return (sB64Enc.substr(0, sB64Enc.length - 2 + nMod3) +
76
- (nMod3 === 2 ? "" : nMod3 === 1 ? "=" : "=="));
77
- }
@@ -1 +0,0 @@
1
- var y=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var q=e=>y(e,"__esModule",{value:!0});var D=(e,t)=>{for(var r in t)y(e,r,{get:t[r],enumerable:!0})},L=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of $(t))!k.call(e,o)&&(r||o!=="default")&&y(e,o,{get:()=>t[o],enumerable:!(n=S(t,o))||n.enumerable});return e};var P=(e=>(t,r)=>e&&e.get(t)||(r=L(q({}),t,1),e&&e.set(t,r),r))(typeof WeakMap!="undefined"?new WeakMap:0);var K={};D(K,{MhtmlHeaders:()=>h,parseMhtml:()=>G});function Q(e){return e>64&&e<91?e-65:e>96&&e<123?e-71:e>47&&e<58?e+4:e===43?62:e===47?63:0}function f(e,t){let r=e.replace(/[^A-Za-z0-9+/]/g,""),n=r.length,o=t?Math.ceil((n*3+1>>2)/t)*t:n*3+1>>2,s=new Uint8Array(o);for(let a=0,i=0,d=0;d<n;d++){let l=d&3;if(a|=Q(r.charCodeAt(d))<<6*(3-l),l===3||n-d===1){for(let c=0;c<3&&i<o;c++,i++)s[i]=a>>>(16>>>c&24)&255;a=0}}return s}function j(e){return ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e)}function g(e,t){if(e.length!==t.length)return!1;if(e.byteOffset%4===t.byteOffset%4){let r=(4-e.byteOffset%4)%4,n=Math.floor((e.byteLength-r)/4),o=r+n*4,s=new Uint32Array(e.buffer,e.byteOffset+r,n),a=new Uint32Array(t.buffer,t.byteOffset+r,n);for(let i=0;i<r;++i)if(e[i]!==t[i])return!1;for(let i=0;i<n;++i)if(s[i]!==a[i])return!1;for(let i=o;i<e.length;++i)if(e[i]!==t[i])return!1;return!0}else{for(let r of e.keys())if(e[r]!==t[r])return!1;return!0}}function A(e){return{[Symbol.asyncIterator](){let t=e.getReader();return{async next(){let r=await t.read();return r.done?{done:!0,value:void 0}:{done:!1,value:r.value}}}}}}function H(e,t){return e.findIndex((r,n)=>{if(r!==t[0]||n+t.length>e.length)return!1;for(let o=1;o<t.length;++o)if(e[n+o]!==t[o])return!1;return!0})}async function*p(e,t){let r=new Uint8Array(0);for await(let n of e){let o=j(n);r=r.length?I([r,o]):o;let s;for(;(s=H(r,t))!==-1;)yield r.subarray(0,s),r=r.subarray(s+t.length)}yield r}function I(e){let t=e.reduce((o,s)=>o+s.length,0),r=new Uint8Array(t),n=0;for(let o of e)r.set(o,n),n+=o.length;return r}async function m(e){let t=[];for await(let r of e)t.push(r);return I(t)}var R=new Uint8Array([10]);async function*U(e,t=R){for await(let r of e){let n=new Uint8Array(r.length+t.length),o=!1,s=0;for(let a=0;a<r.length;++a){let i=r[a];if(i>=128)throw new Error(`got non-ascii character when decoding quoted printable: ${r}`);if(i!==61)n[s++]=i;else{let d=r[++a];if(d===void 0)o=!0;else{let l=r[++a];if(l===void 0)throw new Error("quoted printable escape (=) was not followed by two bytes");let c=parseInt(String.fromCharCode(d),16);c*=16,c+=parseInt(String.fromCharCode(l),16),n[s++]=c}}}o||(n.set(t,s),s+=t.length),yield n.subarray(0,s)}}var W=new TextDecoder;async function*x(e){for await(let t of e)yield f(W.decode(t))}async function*b(e){for await(let t of e)yield t}function v(){throw new Error("binary transfer-encoding is explicitly not supported and trying to add an implementation will likely result in unexpected results, but if you want to ignore anyway, set binary to `decode8bit`")}var E=new TextEncoder,M=new TextDecoder,h=class{#e=new Map;[Symbol.iterator](){return this.entries()}append(t,r){let n=this.#e.get(t);n===void 0?this.#e.set(t,[r]):n.push(r)}*entries(t=", "){for(let[r,n]of this.#e.entries())yield[r,n.join(t)]}*entriesAll(){for(let[t,r]of this.#e.entries())for(let n of r)yield[t,n]}get(t,r=", "){let n=this.#e.get(t);return n===void 0?null:n.join(r)}getAll(t){return this.#e.get(t)??[]}has(t){return this.#e.has(t)}keys(){return this.#e.keys()}*values(t=", "){for(let r of this.#e.values())yield r.join(t)}*valuesAll(){for(let t of this.#e.values())yield*t}};function F(e){let t=new Uint8Array(e.length),r=0;for(let n=0;n<e.length;++n){let o=e.charCodeAt(n),s;if(o>=128)throw new Error(`got non-ascii character when decoding q-quoted word: "${e}"`);o===95?s=32:o===61?(s=parseInt(e[++n],16),s*=16,s+=parseInt(e[++n],16)):s=o,t[r++]=s}return t.subarray(0,r)}var N=/^=\?([^?\s]+)\?([BQ])\?([^?\s]+)\?=$/;function B(e){let t=N.exec(e);if(t){let[,r,n,o]=t,s;if(n==="Q")s=F(o);else if(n==="B")s=f(o);else throw new Error(`unknown encoding for header value encoding: ${n}`);return new TextDecoder(r).decode(s)}else return e}async function J(e){let t=new h,r="",n="";for(;;){let{done:o,value:s}=await e.next();if(o)throw new Error("didn't find an empty line to signify the end of header parsing");let a=M.decode(s);if(/^\s/.test(a))n+=" ",n+=B(a.trimStart());else if(r&&t.append(r,n),a){let i=a.indexOf(": ");if(i===-1)throw new Error(`header line didn't have key-value delimiter: "${a}"`);r=a.slice(0,i),n=B(a.slice(i+2))}else return t}}var V=new Map([["7bit",b],["base64",x],["quoted-printable",U],["8bit",b],["binary",v]]);function Z(e){let t=e.get("Content-Type");if(t===null)throw new Error(`first headers didn't contain a content type: ${JSON.stringify(Object.fromEntries(e))}`);let r,n=!1;for(let a of t.split("; "))a.startsWith("multipart/")?n=!0:a.startsWith("boundary=")&&(r=a.slice(9),r.startsWith('"')&&r.endsWith('"')&&(r=r.slice(1,-1)));if(!n||r===void 0)throw new Error("first content type header didn't contain 'multipart/...' and a boundary string");let o=E.encode(`--${r}`),s=E.encode(`--${r}--`);return[o,s]}async function*G(e,{decoderOverrides:t=new Map}={}){let r=new Map([...V.entries(),...t.entries()]),n=new Uint8Array([13,10]),o=p(A(e),n),s=null,a=!0;for(;a;){let i=await J(o),[d,l]=s??(s=Z(i)),c=i.get("Content-Transfer-Encoding")??"7bit",w=r.get(c);if(w===void 0)throw new Error(`unhandled encoding type: ${c}`);let O=await m(w({[Symbol.asyncIterator](){return{async next(){let{done:T,value:u}=await o.next();if(T)throw new Error(`stream didn't end with the appropriate termination boundary: ${M.decode(l)}`);return g(u,d)?{done:!0,value:void 0}:g(u,l)?(a=!1,{done:!0,value:void 0}):{value:u}}}}}));yield{headers:i,content:O}}}module.exports=P(K);
@@ -1 +0,0 @@
1
- var mhtmlStream=(()=>{var y=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var q=e=>y(e,"__esModule",{value:!0});var D=(e,t)=>{for(var r in t)y(e,r,{get:t[r],enumerable:!0})},L=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of $(t))!k.call(e,o)&&(r||o!=="default")&&y(e,o,{get:()=>t[o],enumerable:!(n=S(t,o))||n.enumerable});return e};var P=(e=>(t,r)=>e&&e.get(t)||(r=L(q({}),t,1),e&&e.set(t,r),r))(typeof WeakMap!="undefined"?new WeakMap:0);var K={};D(K,{MhtmlHeaders:()=>h,parseMhtml:()=>G});function Q(e){return e>64&&e<91?e-65:e>96&&e<123?e-71:e>47&&e<58?e+4:e===43?62:e===47?63:0}function f(e,t){let r=e.replace(/[^A-Za-z0-9+/]/g,""),n=r.length,o=t?Math.ceil((n*3+1>>2)/t)*t:n*3+1>>2,s=new Uint8Array(o);for(let a=0,i=0,d=0;d<n;d++){let l=d&3;if(a|=Q(r.charCodeAt(d))<<6*(3-l),l===3||n-d===1){for(let c=0;c<3&&i<o;c++,i++)s[i]=a>>>(16>>>c&24)&255;a=0}}return s}function j(e){return ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e)}function g(e,t){if(e.length!==t.length)return!1;if(e.byteOffset%4===t.byteOffset%4){let r=(4-e.byteOffset%4)%4,n=Math.floor((e.byteLength-r)/4),o=r+n*4,s=new Uint32Array(e.buffer,e.byteOffset+r,n),a=new Uint32Array(t.buffer,t.byteOffset+r,n);for(let i=0;i<r;++i)if(e[i]!==t[i])return!1;for(let i=0;i<n;++i)if(s[i]!==a[i])return!1;for(let i=o;i<e.length;++i)if(e[i]!==t[i])return!1;return!0}else{for(let r of e.keys())if(e[r]!==t[r])return!1;return!0}}function A(e){return{[Symbol.asyncIterator](){let t=e.getReader();return{async next(){let r=await t.read();return r.done?{done:!0,value:void 0}:{done:!1,value:r.value}}}}}}function H(e,t){return e.findIndex((r,n)=>{if(r!==t[0]||n+t.length>e.length)return!1;for(let o=1;o<t.length;++o)if(e[n+o]!==t[o])return!1;return!0})}async function*p(e,t){let r=new Uint8Array(0);for await(let n of e){let o=j(n);r=r.length?I([r,o]):o;let s;for(;(s=H(r,t))!==-1;)yield r.subarray(0,s),r=r.subarray(s+t.length)}yield r}function I(e){let t=e.reduce((o,s)=>o+s.length,0),r=new Uint8Array(t),n=0;for(let o of e)r.set(o,n),n+=o.length;return r}async function m(e){let t=[];for await(let r of e)t.push(r);return I(t)}var R=new Uint8Array([10]);async function*U(e,t=R){for await(let r of e){let n=new Uint8Array(r.length+t.length),o=!1,s=0;for(let a=0;a<r.length;++a){let i=r[a];if(i>=128)throw new Error(`got non-ascii character when decoding quoted printable: ${r}`);if(i!==61)n[s++]=i;else{let d=r[++a];if(d===void 0)o=!0;else{let l=r[++a];if(l===void 0)throw new Error("quoted printable escape (=) was not followed by two bytes");let c=parseInt(String.fromCharCode(d),16);c*=16,c+=parseInt(String.fromCharCode(l),16),n[s++]=c}}}o||(n.set(t,s),s+=t.length),yield n.subarray(0,s)}}var W=new TextDecoder;async function*x(e){for await(let t of e)yield f(W.decode(t))}async function*b(e){for await(let t of e)yield t}function v(){throw new Error("binary transfer-encoding is explicitly not supported and trying to add an implementation will likely result in unexpected results, but if you want to ignore anyway, set binary to `decode8bit`")}var E=new TextEncoder,M=new TextDecoder,h=class{#e=new Map;[Symbol.iterator](){return this.entries()}append(t,r){let n=this.#e.get(t);n===void 0?this.#e.set(t,[r]):n.push(r)}*entries(t=", "){for(let[r,n]of this.#e.entries())yield[r,n.join(t)]}*entriesAll(){for(let[t,r]of this.#e.entries())for(let n of r)yield[t,n]}get(t,r=", "){let n=this.#e.get(t);return n===void 0?null:n.join(r)}getAll(t){return this.#e.get(t)??[]}has(t){return this.#e.has(t)}keys(){return this.#e.keys()}*values(t=", "){for(let r of this.#e.values())yield r.join(t)}*valuesAll(){for(let t of this.#e.values())yield*t}};function F(e){let t=new Uint8Array(e.length),r=0;for(let n=0;n<e.length;++n){let o=e.charCodeAt(n),s;if(o>=128)throw new Error(`got non-ascii character when decoding q-quoted word: "${e}"`);o===95?s=32:o===61?(s=parseInt(e[++n],16),s*=16,s+=parseInt(e[++n],16)):s=o,t[r++]=s}return t.subarray(0,r)}var N=/^=\?([^?\s]+)\?([BQ])\?([^?\s]+)\?=$/;function B(e){let t=N.exec(e);if(t){let[,r,n,o]=t,s;if(n==="Q")s=F(o);else if(n==="B")s=f(o);else throw new Error(`unknown encoding for header value encoding: ${n}`);return new TextDecoder(r).decode(s)}else return e}async function J(e){let t=new h,r="",n="";for(;;){let{done:o,value:s}=await e.next();if(o)throw new Error("didn't find an empty line to signify the end of header parsing");let a=M.decode(s);if(/^\s/.test(a))n+=" ",n+=B(a.trimStart());else if(r&&t.append(r,n),a){let i=a.indexOf(": ");if(i===-1)throw new Error(`header line didn't have key-value delimiter: "${a}"`);r=a.slice(0,i),n=B(a.slice(i+2))}else return t}}var V=new Map([["7bit",b],["base64",x],["quoted-printable",U],["8bit",b],["binary",v]]);function Z(e){let t=e.get("Content-Type");if(t===null)throw new Error(`first headers didn't contain a content type: ${JSON.stringify(Object.fromEntries(e))}`);let r,n=!1;for(let a of t.split("; "))a.startsWith("multipart/")?n=!0:a.startsWith("boundary=")&&(r=a.slice(9),r.startsWith('"')&&r.endsWith('"')&&(r=r.slice(1,-1)));if(!n||r===void 0)throw new Error("first content type header didn't contain 'multipart/...' and a boundary string");let o=E.encode(`--${r}`),s=E.encode(`--${r}--`);return[o,s]}async function*G(e,{decoderOverrides:t=new Map}={}){let r=new Map([...V.entries(),...t.entries()]),n=new Uint8Array([13,10]),o=p(A(e),n),s=null,a=!0;for(;a;){let i=await J(o),[d,l]=s??(s=Z(i)),c=i.get("Content-Transfer-Encoding")??"7bit",w=r.get(c);if(w===void 0)throw new Error(`unhandled encoding type: ${c}`);let O=await m(w({[Symbol.asyncIterator](){return{async next(){let{done:T,value:u}=await o.next();if(T)throw new Error(`stream didn't end with the appropriate termination boundary: ${M.decode(l)}`);return g(u,d)?{done:!0,value:void 0}:g(u,l)?(a=!1,{done:!0,value:void 0}):{value:u}}}}}));yield{headers:i,content:O}}}return P(K);})();