mhtml-stream 2.0.0 → 2.0.1
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/dist/cli.d.ts +1 -0
- package/dist/cli.js +45 -0
- package/dist/index.js +1 -1
- package/dist/mhtml.esm.min.js +1 -1
- package/package.json +14 -10
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { argv } from "bun";
|
|
3
|
+
import { mkdir } from "node:fs/promises";
|
|
4
|
+
import yargs from "yargs";
|
|
5
|
+
import { parseMhtml } from ".";
|
|
6
|
+
async function* readFile(name) {
|
|
7
|
+
const file = Bun.file(name);
|
|
8
|
+
yield await file.bytes();
|
|
9
|
+
}
|
|
10
|
+
async function saveOutput(mkdir, path, content) {
|
|
11
|
+
await mkdir;
|
|
12
|
+
await Bun.write(path, content);
|
|
13
|
+
}
|
|
14
|
+
void (async () => {
|
|
15
|
+
const args = await yargs(argv.slice(2))
|
|
16
|
+
.scriptName("mhtml_stream")
|
|
17
|
+
.usage("$0 <mhtml>", "parse mhtml and extract component files")
|
|
18
|
+
.positional("mhtml", {
|
|
19
|
+
describe: "the mhtml file to parse",
|
|
20
|
+
type: "string",
|
|
21
|
+
})
|
|
22
|
+
.option("output", {
|
|
23
|
+
alias: "o",
|
|
24
|
+
describe: "output directory",
|
|
25
|
+
type: "string",
|
|
26
|
+
})
|
|
27
|
+
.help()
|
|
28
|
+
.alias("h", "help")
|
|
29
|
+
.demandOption("mhtml")
|
|
30
|
+
.strict().argv;
|
|
31
|
+
const makeOut = args.output ? mkdir(args.output, { recursive: true }) : null;
|
|
32
|
+
const proms = [];
|
|
33
|
+
for await (const file of parseMhtml(readFile(args.mhtml))) {
|
|
34
|
+
for (const [key, val] of file.headers) {
|
|
35
|
+
console.log(key, ":", val);
|
|
36
|
+
}
|
|
37
|
+
const loc = file.headers.get("Content-Location");
|
|
38
|
+
if (loc && args.output && makeOut) {
|
|
39
|
+
const path = `${args.output}/${loc.replaceAll(/[:/]/g, "_")}`;
|
|
40
|
+
proms.push(saveOutput(makeOut, path, file.content));
|
|
41
|
+
}
|
|
42
|
+
await Promise.all(proms);
|
|
43
|
+
console.log("[done]");
|
|
44
|
+
}
|
|
45
|
+
})();
|
package/dist/index.js
CHANGED
package/dist/mhtml.esm.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var f=function(
|
|
1
|
+
var D=L;var g=[],Y=[],f=typeof Uint8Array!=="undefined"?Uint8Array:Array,P="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(Z=0,F=P.length;Z<F;++Z)g[Z]=P[Z],Y[P.charCodeAt(Z)]=Z;var Z,F;Y[45]=62;Y[95]=63;function m(G){var K=G.length;if(K%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var J=G.indexOf("=");if(J===-1)J=K;var M=J===K?0:4-J%4;return[J,M]}function v(G,K,J){return(K+J)*3/4-J}function L(G){var K,J=m(G),M=J[0],R=J[1],U=new f(v(G,M,R)),V=0,W=R>0?M-4:M,X;for(X=0;X<W;X+=4)K=Y[G.charCodeAt(X)]<<18|Y[G.charCodeAt(X+1)]<<12|Y[G.charCodeAt(X+2)]<<6|Y[G.charCodeAt(X+3)],U[V++]=K>>16&255,U[V++]=K>>8&255,U[V++]=K&255;if(R===2)K=Y[G.charCodeAt(X)]<<2|Y[G.charCodeAt(X+1)]>>4,U[V++]=K&255;if(R===1)K=Y[G.charCodeAt(X)]<<10|Y[G.charCodeAt(X+1)]<<4|Y[G.charCodeAt(X+2)]>>2,U[V++]=K>>8&255,U[V++]=K&255;return U}class S{#G=new Map;[Symbol.iterator](){return this.entries()}append(G,K){let J=this.#G.get(G);if(J===void 0)this.#G.set(G,[K]);else J.push(K)}*entries(G=", "){for(let[K,J]of this.#G.entries())yield[K,J.join(G)]}*entriesAll(){for(let[G,K]of this.#G.entries())for(let J of K)yield[G,J]}get(G,K=", "){let J=this.#G.get(G);if(J===void 0)return null;else return J.join(K)}getAll(G){return this.#G.get(G)??[]}has(G){return this.#G.has(G)}keys(){return this.#G.keys()}*values(G=", "){for(let K of this.#G.values())yield K.join(G)}*valuesAll(){for(let G of this.#G.values())yield*G}}function _(G,K){if(G.length!==K.length)return!1;else if(G.byteOffset%4===K.byteOffset%4){let J=(4-G.byteOffset%4)%4,M=Math.floor((G.byteLength-J)/4),R=J+M*4,U=new Uint32Array(G.buffer,G.byteOffset+J,M),V=new Uint32Array(K.buffer,K.byteOffset+J,M);for(let W=0;W<J;++W)if(G[W]!==K[W])return!1;for(let W=0;W<M;++W)if(U[W]!==V[W])return!1;for(let W=R;W<G.length;++W)if(G[W]!==K[W])return!1;return!0}else{for(let J of G.keys())if(G[J]!==K[J])return!1;return!0}}function h(G,K){return G.findIndex((J,M)=>{if(J!==K[0]||M+K.length>G.length)return!1;else{for(let R=1;R<K.length;++R)if(G[M+R]!==K[R])return!1;return!0}})}async function*Q(G,K){let J=new Uint8Array(0);for await(let M of G){J=J.length?E([J,M]):M;let R;while((R=h(J,K))!==-1)yield J.subarray(0,R),J=J.subarray(R+K.length)}yield J}function E(G){let K=G.reduce((R,U)=>R+U.length,0),J=new Uint8Array(K),M=0;for(let R of G)J.set(R,M),M+=R.length;return J}async function O(G){let K=[];for await(let J of G)K.push(J);return E(K)}var k=new Uint8Array([10]);async function*T(G,K=k){for await(let J of G){let M=new Uint8Array(J.length+K.length),R=!1,U=0;for(let V=0;V<J.length;++V){let W=J[V];if(W>=128)throw new Error(`got non-ascii character when decoding quoted printable: ${W}`);if(W!==61)M[U++]=W;else{let X=J[++V];if(X===void 0)R=!0;else{let z=J[++V];if(z===void 0)throw new Error("quoted printable escape (=) was not followed by two bytes");let $=parseInt(String.fromCharCode(X),16);$*=16,$+=parseInt(String.fromCharCode(z),16),M[U++]=$}}}if(!R)M.set(K,U),U+=K.length;yield M.subarray(0,U)}}var y=new TextDecoder;async function*C(G){for await(let K of G)yield D(y.decode(K))}async function*j(G){for await(let K of G)yield K}function A(){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 I=new TextEncoder,B=new TextDecoder;function b(G){let K=new Uint8Array(G.length),J=0;for(let M=0;M<G.length;++M){let R=G.charCodeAt(M),U;if(R>=128)throw new Error(`got non-ascii character when decoding q-quoted word: "${G}"`);else if(R===95)U=32;else if(R===61)U=parseInt(G[++M],16),U*=16,U+=parseInt(G[++M],16);else U=R;K[J++]=U}return K.subarray(0,J)}var p=/^=\?([^?\s]+)\?([BQ])\?([^?\s]+)\?=$/;function H(G){let K=p.exec(G);if(K){let[,J,M,R]=K,U;if(M==="Q")U=b(R);else U=D(R);return new TextDecoder(J).decode(U)}else return G}async function c(G){let K=new S,J="",M="";for(;;){let{done:R,value:U}=await G.next();if(R)throw new Error("didn't find an empty line to signify the end of header parsing");let V=B.decode(U);if(/^\s/.test(V))M+=H(V.substring(1));else{if(J)K.append(J,M);if(V){let W=V.indexOf(": ");if(W===-1)throw new Error(`header line didn't have key-value delimiter: "${V}"`);J=V.slice(0,W),M=H(V.slice(W+2))}else return K}}}var u=new Map([["7bit",j],["base64",C],["quoted-printable",T],["8bit",j],["binary",A]]);function s(G){let K=G.get("Content-Type");if(K===null)throw new Error(`first headers didn't contain a content type: ${JSON.stringify(Object.fromEntries(G))}`);let J=void 0,M=!1;for(let V of K.split(/;\s*/))if(V.startsWith("multipart/"))M=!0;else if(V.startsWith("boundary=")){if(J=V.slice(9),J.startsWith('"')&&J.endsWith('"'))J=J.slice(1,-1)}if(!M||J===void 0)throw new Error("first content type header didn't contain 'multipart/...' and a boundary string");let R=I.encode(`--${J}`),U=I.encode(`--${J}--`);return[R,U]}async function*e(G,{decoderOverrides:K=new Map}={}){let J=new Map([...u.entries(),...K.entries()]),M=new Uint8Array([13,10]),R=Q(G,M),U=null,V=!0;while(V){let W=await c(R),[X,z]=U??(U=s(W)),$=W.get("Content-Transfer-Encoding")??"7bit",q=J.get($);if(q===void 0)throw new Error(`unhandled encoding type: ${$}`);let w=await O(q({[Symbol.asyncIterator](){return{async next(){let{done:x,value:N}=await R.next();if(x)throw new Error(`stream didn't end with the appropriate termination boundary: ${B.decode(z)}`);else if(_(N,X))return{done:!0,value:void 0};else if(_(N,z))return V=!1,{done:!0,value:void 0};else return{value:N}}}}}));yield{headers:W,content:w}}}export{e as parseMhtml};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mhtml-stream",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Zero dependency stream MHTML parser",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mhtml",
|
|
@@ -8,18 +8,20 @@
|
|
|
8
8
|
],
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "https://github.com/erikbrinkman/mhtml-stream.git"
|
|
11
|
+
"url": "git+https://github.com/erikbrinkman/mhtml-stream.git"
|
|
12
12
|
},
|
|
13
13
|
"author": "Erik Brinkman <erik.brinkman@gmail.com>",
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"types": "dist/index.d.ts",
|
|
17
17
|
"module": "dist/mhtml.esm.min.js",
|
|
18
|
+
"exports": "./dist/mhtml.esm.min.js",
|
|
18
19
|
"files": [
|
|
19
20
|
"/dist/**/*.js",
|
|
20
21
|
"/dist/**/*.d.ts"
|
|
21
22
|
],
|
|
22
23
|
"scripts": {
|
|
24
|
+
"cli": "bun src/cli.ts",
|
|
23
25
|
"fmt": "prettier --cache --write 'src/*.ts' '*.{js,json}'",
|
|
24
26
|
"lint": "tsc && eslint --cache 'src/*.ts' && typedoc --emit none",
|
|
25
27
|
"doc": "typedoc",
|
|
@@ -31,16 +33,18 @@
|
|
|
31
33
|
},
|
|
32
34
|
"devDependencies": {
|
|
33
35
|
"@types/base64-js": "^1.3.2",
|
|
34
|
-
"@types/bun": "^1.1.
|
|
35
|
-
"
|
|
36
|
+
"@types/bun": "^1.1.14",
|
|
37
|
+
"@types/yargs": "^17.0.33",
|
|
38
|
+
"eslint": "^9.17.0",
|
|
36
39
|
"eslint-config-prettier": "^9.1.0",
|
|
37
40
|
"eslint-plugin-spellcheck": "^0.0.20",
|
|
38
|
-
"eslint-plugin-tsdoc": "^0.
|
|
39
|
-
"prettier": "^3.2
|
|
40
|
-
"prettier-plugin-organize-imports": "^
|
|
41
|
-
"typedoc": "^0.
|
|
42
|
-
"typescript": "^5.
|
|
43
|
-
"typescript-eslint": "^
|
|
41
|
+
"eslint-plugin-tsdoc": "^0.4.0",
|
|
42
|
+
"prettier": "^3.4.2",
|
|
43
|
+
"prettier-plugin-organize-imports": "^4.1.0",
|
|
44
|
+
"typedoc": "^0.27.5",
|
|
45
|
+
"typescript": "^5.7.2",
|
|
46
|
+
"typescript-eslint": "^8.18.1",
|
|
47
|
+
"yargs": "^17.7.2"
|
|
44
48
|
},
|
|
45
49
|
"eslintConfig": {
|
|
46
50
|
"rules": {
|