mhtml-stream 1.0.4 → 2.0.0
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/headers.d.ts +6 -6
- package/dist/index.d.ts +7 -11
- package/dist/index.js +4 -6
- package/dist/index.spec.d.ts +1 -0
- package/dist/index.spec.js +248 -0
- package/dist/mhtml.esm.min.js +1 -0
- package/dist/utils.d.ts +1 -8
- package/dist/utils.js +1 -16
- package/dist/utils.spec.d.ts +1 -0
- package/dist/utils.spec.js +148 -0
- package/package.json +19 -87
- package/bundle/mhtml.cjs.min.js +0 -1
- package/bundle/mhtml.esm.min.js +0 -1
- package/bundle/mhtml.iife.min.js +0 -1
package/dist/headers.d.ts
CHANGED
|
@@ -15,9 +15,9 @@ export interface MhtmlHeaders extends Iterable<[string, string]> {
|
|
|
15
15
|
* iterate over all key-value pairs
|
|
16
16
|
*
|
|
17
17
|
* Multiple values for the same key will be joined in the order they were
|
|
18
|
-
* added by `
|
|
18
|
+
* added by `delimiter`.
|
|
19
19
|
*/
|
|
20
|
-
entries(
|
|
20
|
+
entries(delimiter?: string): IterableIterator<[string, string]>;
|
|
21
21
|
/**
|
|
22
22
|
* iterate over all key-value pairs
|
|
23
23
|
*
|
|
@@ -29,9 +29,9 @@ export interface MhtmlHeaders extends Iterable<[string, string]> {
|
|
|
29
29
|
* get the value for a key
|
|
30
30
|
*
|
|
31
31
|
* If the key is missing, null will be returned, if multiple values for the
|
|
32
|
-
* key are present, they will be joined be `
|
|
32
|
+
* key are present, they will be joined be `delimiter`.
|
|
33
33
|
*/
|
|
34
|
-
get(key: string,
|
|
34
|
+
get(key: string, delimiter?: string): string | null;
|
|
35
35
|
/** get all values for a key */
|
|
36
36
|
getAll(key: string): string[];
|
|
37
37
|
/** whether key has any values associated with it */
|
|
@@ -41,9 +41,9 @@ export interface MhtmlHeaders extends Iterable<[string, string]> {
|
|
|
41
41
|
/**
|
|
42
42
|
* iterate over all values
|
|
43
43
|
*
|
|
44
|
-
* If a key has multiple values they will be joined by `
|
|
44
|
+
* If a key has multiple values they will be joined by `delimiter`.
|
|
45
45
|
*/
|
|
46
|
-
values(
|
|
46
|
+
values(delimiter?: string): IterableIterator<string>;
|
|
47
47
|
/** iterate over all values added */
|
|
48
48
|
valuesAll(): IterableIterator<string>;
|
|
49
49
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,16 +7,12 @@ export interface MhtmlFile {
|
|
|
7
7
|
/** the file's content */
|
|
8
8
|
content: Uint8Array;
|
|
9
9
|
}
|
|
10
|
-
/** The decoder of any Content-Transfer-Encoding
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
* @returns data - decoded lines
|
|
17
|
-
*/
|
|
18
|
-
(lines: AsyncIterable<Uint8Array>): AsyncIterable<Uint8Array>;
|
|
19
|
-
}
|
|
10
|
+
/** The decoder of any Content-Transfer-Encoding
|
|
11
|
+
*
|
|
12
|
+
* @param lines - each line of raw bytes
|
|
13
|
+
* @returns data - decoded lines
|
|
14
|
+
*/
|
|
15
|
+
export type Decoder = (lines: AsyncIterable<Uint8Array>) => AsyncIterable<Uint8Array>;
|
|
20
16
|
/** options for mhtml parsing */
|
|
21
17
|
export interface ParseOptions {
|
|
22
18
|
/** custom decoders for other Content-Transfer-Encodings */
|
|
@@ -28,4 +24,4 @@ export interface ParseOptions {
|
|
|
28
24
|
* decoderOverrides can be used to overwrite default encoders or specify your
|
|
29
25
|
* own if a Content-Transfer-Encoding isn't handled properly
|
|
30
26
|
*/
|
|
31
|
-
export declare function parseMhtml(stream: AsyncIterable<
|
|
27
|
+
export declare function parseMhtml(stream: AsyncIterable<Uint8Array>, { decoderOverrides }?: ParseOptions): AsyncIterableIterator<MhtmlFile>;
|
package/dist/index.js
CHANGED
|
@@ -41,16 +41,12 @@ function decodeLine(line) {
|
|
|
41
41
|
if (match) {
|
|
42
42
|
const [, charset, encoding, text] = match;
|
|
43
43
|
let buff;
|
|
44
|
-
/* istanbul ignore else */
|
|
45
44
|
if (encoding === "Q") {
|
|
46
45
|
buff = decodeQEncoding(text);
|
|
47
46
|
}
|
|
48
|
-
else if (encoding === "B") {
|
|
49
|
-
buff = toByteArray(text);
|
|
50
|
-
}
|
|
51
47
|
else {
|
|
52
|
-
//
|
|
53
|
-
|
|
48
|
+
// encoding === "B"
|
|
49
|
+
buff = toByteArray(text);
|
|
54
50
|
}
|
|
55
51
|
return new TextDecoder(charset).decode(buff);
|
|
56
52
|
}
|
|
@@ -106,6 +102,7 @@ const defaultDecoders = new Map([
|
|
|
106
102
|
["8bit", decodeIdentity],
|
|
107
103
|
["binary", decodeBinary],
|
|
108
104
|
]);
|
|
105
|
+
// eslint-disable-next-line spellcheck/spell-checker
|
|
109
106
|
/**
|
|
110
107
|
* extract the boundary condition from a multipart header
|
|
111
108
|
*
|
|
@@ -153,6 +150,7 @@ export async function* parseMhtml(stream, { decoderOverrides = new Map() } = {})
|
|
|
153
150
|
const lines = splitStream(stream, crlf);
|
|
154
151
|
let bound = null;
|
|
155
152
|
let cont = true;
|
|
153
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
156
154
|
while (cont) {
|
|
157
155
|
// parse out headers and get encoding for content
|
|
158
156
|
const headers = await parseHeaders(lines);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { parseMhtml } from ".";
|
|
3
|
+
import { Headers } from "./headers";
|
|
4
|
+
const encoder = new TextEncoder();
|
|
5
|
+
const decoder = new TextDecoder();
|
|
6
|
+
// from https://en.wikipedia.org/wiki/MIME#Multipart_messages
|
|
7
|
+
// eslint-disable-next-line spellcheck/spell-checker
|
|
8
|
+
const example = `MIME-Version: 1.0
|
|
9
|
+
Subject: =?iso-8859-1?Q?=A1Hola,_se=F1or!?=
|
|
10
|
+
Content-Type: multipart/mixed; boundary=frontier
|
|
11
|
+
|
|
12
|
+
This is a message with multiple parts in MIME format.
|
|
13
|
+
--frontier
|
|
14
|
+
Content-Type: text/plain
|
|
15
|
+
|
|
16
|
+
This is the body of the message.
|
|
17
|
+
--frontier
|
|
18
|
+
Content-Type: application/octet-stream
|
|
19
|
+
Content-Transfer-Encoding: base64
|
|
20
|
+
|
|
21
|
+
PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg
|
|
22
|
+
Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg==
|
|
23
|
+
--frontier--
|
|
24
|
+
`;
|
|
25
|
+
const newYorker = `From: <Saved by Blink>
|
|
26
|
+
Snapshot-Content-Location: https://www.newyorker.com/culture/cultural-comment/what-the-twilight-zone-reveals-about-todays-prestige-tv
|
|
27
|
+
Subject: =?utf-8?Q?What=20=E2=80=9CThe=20Twilight=20Zone=E2=80=9D=20Reveals=20Abou?=
|
|
28
|
+
=?utf-8?Q?t=20Today=E2=80=99s=20Prestige=20TV=20|=20The=20New=20Yorker?=
|
|
29
|
+
Date: Sat, 16 Apr 2022 17:48:31 -0000
|
|
30
|
+
MIME-Version: 1.0
|
|
31
|
+
Content-Type: multipart/related;
|
|
32
|
+
type="text/html";
|
|
33
|
+
boundary="----MultipartBoundary--NYswbLinUCqE8KaJecg8DEV6giqFeyGLtHeT0qLB4h----"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
------MultipartBoundary--NYswbLinUCqE8KaJecg8DEV6giqFeyGLtHeT0qLB4h------
|
|
37
|
+
`;
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
39
|
+
async function* stringToStream(file) {
|
|
40
|
+
yield encoder.encode(file.replaceAll("\n", "\r\n"));
|
|
41
|
+
}
|
|
42
|
+
async function consume(iter) {
|
|
43
|
+
for await (const _ of iter) {
|
|
44
|
+
//
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
describe("parseMhtml()", () => {
|
|
48
|
+
test("example", async () => {
|
|
49
|
+
const files = [];
|
|
50
|
+
for await (const file of parseMhtml(stringToStream(example))) {
|
|
51
|
+
files.push(file);
|
|
52
|
+
}
|
|
53
|
+
const headers = files.map(({ headers }) => Object.fromEntries(headers));
|
|
54
|
+
const expectedHeaders = [
|
|
55
|
+
{
|
|
56
|
+
"MIME-Version": "1.0",
|
|
57
|
+
// eslint-disable-next-line spellcheck/spell-checker
|
|
58
|
+
Subject: "¡Hola, señor!",
|
|
59
|
+
"Content-Type": "multipart/mixed; boundary=frontier",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"Content-Type": "text/plain",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"Content-Type": "application/octet-stream",
|
|
66
|
+
"Content-Transfer-Encoding": "base64",
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
expect(headers).toEqual(expectedHeaders);
|
|
70
|
+
const text = files
|
|
71
|
+
.slice(0, 2)
|
|
72
|
+
.map(({ content }) => decoder.decode(content));
|
|
73
|
+
const expectedText = [
|
|
74
|
+
"This is a message with multiple parts in MIME format.",
|
|
75
|
+
"This is the body of the message.",
|
|
76
|
+
];
|
|
77
|
+
expect(text).toEqual(expectedText);
|
|
78
|
+
});
|
|
79
|
+
test("other headers", async () => {
|
|
80
|
+
// eslint-disable-next-line spellcheck/spell-checker
|
|
81
|
+
const content = `MIME-Version: 1.0
|
|
82
|
+
From: this is a wrapped: header
|
|
83
|
+
with an extra delimiter in: both sections
|
|
84
|
+
Subject: =?utf-8?B?QmFzZSA2NCDigJQgTW96aWxsYSBEZXZlbG9wZXIgTmV0d29yaw==?=
|
|
85
|
+
Content-Type: multipart/mixed; boundary="quoted-frontier"
|
|
86
|
+
|
|
87
|
+
This is a message with multiple parts in MIME format.
|
|
88
|
+
--quoted-frontier--
|
|
89
|
+
`;
|
|
90
|
+
const files = [];
|
|
91
|
+
for await (const file of parseMhtml(stringToStream(content))) {
|
|
92
|
+
files.push(file);
|
|
93
|
+
}
|
|
94
|
+
const headers = files.map(({ headers }) => Object.fromEntries(headers));
|
|
95
|
+
const expectedHeaders = [
|
|
96
|
+
{
|
|
97
|
+
"MIME-Version": "1.0",
|
|
98
|
+
From: "this is a wrapped: header with an extra delimiter in: both sections",
|
|
99
|
+
Subject: "Base 64 \u2014 Mozilla Developer Network",
|
|
100
|
+
"Content-Type": 'multipart/mixed; boundary="quoted-frontier"',
|
|
101
|
+
},
|
|
102
|
+
];
|
|
103
|
+
expect(headers).toEqual(expectedHeaders);
|
|
104
|
+
const text = files.map(({ content }) => decoder.decode(content));
|
|
105
|
+
const expectedText = [
|
|
106
|
+
"This is a message with multiple parts in MIME format.",
|
|
107
|
+
];
|
|
108
|
+
expect(text).toEqual(expectedText);
|
|
109
|
+
});
|
|
110
|
+
test("escaped multi-line headers", async () => {
|
|
111
|
+
const files = [];
|
|
112
|
+
for await (const file of parseMhtml(stringToStream(newYorker))) {
|
|
113
|
+
files.push(file);
|
|
114
|
+
}
|
|
115
|
+
const headers = files.map(({ headers }) => Object.fromEntries(headers));
|
|
116
|
+
const expectedHeaders = [
|
|
117
|
+
{
|
|
118
|
+
// eslint-disable-next-line spellcheck/spell-checker
|
|
119
|
+
"Content-Type": `multipart/related;type="text/html";boundary="----MultipartBoundary--NYswbLinUCqE8KaJecg8DEV6giqFeyGLtHeT0qLB4h----"`,
|
|
120
|
+
Date: "Sat, 16 Apr 2022 17:48:31 -0000",
|
|
121
|
+
From: "<Saved by Blink>",
|
|
122
|
+
"MIME-Version": "1.0",
|
|
123
|
+
"Snapshot-Content-Location": "https://www.newyorker.com/culture/cultural-comment/what-the-twilight-zone-reveals-about-todays-prestige-tv",
|
|
124
|
+
Subject:
|
|
125
|
+
// eslint-disable-next-line spellcheck/spell-checker
|
|
126
|
+
"What “The Twilight Zone” Reveals About Today’s Prestige TV | The New Yorker",
|
|
127
|
+
},
|
|
128
|
+
];
|
|
129
|
+
expect(headers).toEqual(expectedHeaders);
|
|
130
|
+
const text = files.map(({ content }) => decoder.decode(content));
|
|
131
|
+
const expectedText = [""];
|
|
132
|
+
expect(text).toEqual(expectedText);
|
|
133
|
+
});
|
|
134
|
+
test("fails non-ascii in q-encoding", async () => {
|
|
135
|
+
// eslint-disable-next-line spellcheck/spell-checker
|
|
136
|
+
const content = `MIME-Version: 1.0
|
|
137
|
+
Subject: =?iso-8859-1?Q?=A1Hola,\xffse=F1or!?=
|
|
138
|
+
`;
|
|
139
|
+
const parser = parseMhtml(stringToStream(content));
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression,@typescript-eslint/await-thenable
|
|
141
|
+
await expect(consume(parser)).rejects.toThrow("got non-ascii character when decoding q-quoted word");
|
|
142
|
+
});
|
|
143
|
+
test("fails without empty header delimiter", async () => {
|
|
144
|
+
const content = `MIME-Version: 1.0`;
|
|
145
|
+
const parser = parseMhtml(stringToStream(content));
|
|
146
|
+
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression,@typescript-eslint/await-thenable
|
|
147
|
+
await expect(consume(parser)).rejects.toThrow("didn't find an empty line to signify the end of header parsing");
|
|
148
|
+
});
|
|
149
|
+
test("fails with invalid header", async () => {
|
|
150
|
+
const content = `MIME-Version: 1.0
|
|
151
|
+
invalid header
|
|
152
|
+
|
|
153
|
+
`;
|
|
154
|
+
const parser = parseMhtml(stringToStream(content));
|
|
155
|
+
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression,@typescript-eslint/await-thenable
|
|
156
|
+
await expect(consume(parser)).rejects.toThrow("header line didn't have key-value delimiter");
|
|
157
|
+
});
|
|
158
|
+
test("fails with missing Content-Type", async () => {
|
|
159
|
+
const content = `MIME-Version: 1.0
|
|
160
|
+
|
|
161
|
+
`;
|
|
162
|
+
const parser = parseMhtml(stringToStream(content));
|
|
163
|
+
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression,@typescript-eslint/await-thenable
|
|
164
|
+
await expect(consume(parser)).rejects.toThrow("first headers didn't contain a content type");
|
|
165
|
+
});
|
|
166
|
+
test("fails with missing multipart", async () => {
|
|
167
|
+
const content = `MIME-Version: 1.0
|
|
168
|
+
Content-Type: text/plain; boundary=frontier
|
|
169
|
+
|
|
170
|
+
`;
|
|
171
|
+
const parser = parseMhtml(stringToStream(content));
|
|
172
|
+
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression,@typescript-eslint/await-thenable
|
|
173
|
+
await expect(consume(parser)).rejects.toThrow("first content type header didn't contain");
|
|
174
|
+
});
|
|
175
|
+
test("fails with missing boundary", async () => {
|
|
176
|
+
const content = `MIME-Version: 1.0
|
|
177
|
+
Content-Type: multipart/mixed
|
|
178
|
+
|
|
179
|
+
`;
|
|
180
|
+
const parser = parseMhtml(stringToStream(content));
|
|
181
|
+
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression,@typescript-eslint/await-thenable
|
|
182
|
+
await expect(consume(parser)).rejects.toThrow("first content type header didn't contain");
|
|
183
|
+
});
|
|
184
|
+
test("fails with missing decoder", async () => {
|
|
185
|
+
const content = `MIME-Version: 1.0
|
|
186
|
+
Content-Transfer-Encoding: unknown
|
|
187
|
+
Content-Type: multipart/mixed; boundary=frontier
|
|
188
|
+
|
|
189
|
+
`;
|
|
190
|
+
const parser = parseMhtml(stringToStream(content));
|
|
191
|
+
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression,@typescript-eslint/await-thenable
|
|
192
|
+
await expect(consume(parser)).rejects.toThrow("unhandled encoding type: unknown");
|
|
193
|
+
});
|
|
194
|
+
test("fails without terminus", async () => {
|
|
195
|
+
const content = `MIME-Version: 1.0
|
|
196
|
+
Content-Type: multipart/mixed; boundary=frontier
|
|
197
|
+
|
|
198
|
+
This is a message with multiple parts in MIME format.
|
|
199
|
+
`;
|
|
200
|
+
const parser = parseMhtml(stringToStream(content));
|
|
201
|
+
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression,@typescript-eslint/await-thenable
|
|
202
|
+
await expect(consume(parser)).rejects.toThrow("stream didn't end with the appropriate termination boundary");
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
describe("MhtmlHeaders", () => {
|
|
206
|
+
const headers = new Headers();
|
|
207
|
+
headers.append("a", "b");
|
|
208
|
+
headers.append("a", "c");
|
|
209
|
+
headers.append("d", "e");
|
|
210
|
+
test("entries()", () => {
|
|
211
|
+
const entries = Object.fromEntries(headers.entries());
|
|
212
|
+
expect(entries).toEqual({ a: "b, c", d: "e" });
|
|
213
|
+
});
|
|
214
|
+
test("entriesAll()", () => {
|
|
215
|
+
const entriesAll = [...headers.entriesAll()].sort();
|
|
216
|
+
expect(entriesAll).toEqual([
|
|
217
|
+
["a", "b"],
|
|
218
|
+
["a", "c"],
|
|
219
|
+
["d", "e"],
|
|
220
|
+
]);
|
|
221
|
+
});
|
|
222
|
+
test("get()", () => {
|
|
223
|
+
expect(headers.get("a")).toStrictEqual("b, c");
|
|
224
|
+
expect(headers.get("d")).toStrictEqual("e");
|
|
225
|
+
expect(headers.get("f")).toStrictEqual(null);
|
|
226
|
+
});
|
|
227
|
+
test("getAll()", () => {
|
|
228
|
+
expect(headers.getAll("a")).toEqual(["b", "c"]);
|
|
229
|
+
expect(headers.getAll("d")).toEqual(["e"]);
|
|
230
|
+
expect(headers.getAll("f")).toEqual([]);
|
|
231
|
+
});
|
|
232
|
+
test("has()", () => {
|
|
233
|
+
expect(headers.has("a")).toBe(true);
|
|
234
|
+
expect(headers.has("f")).toBe(false);
|
|
235
|
+
});
|
|
236
|
+
test("keys()", () => {
|
|
237
|
+
const keys = [...headers.keys()].sort();
|
|
238
|
+
expect(keys).toEqual(["a", "d"]);
|
|
239
|
+
});
|
|
240
|
+
test("values()", () => {
|
|
241
|
+
const values = [...headers.values()].sort();
|
|
242
|
+
expect(values).toEqual(["b, c", "e"]);
|
|
243
|
+
});
|
|
244
|
+
test("valuesAll()", () => {
|
|
245
|
+
const valuesAll = [...headers.valuesAll()].sort();
|
|
246
|
+
expect(valuesAll).toEqual(["b", "c", "e"]);
|
|
247
|
+
});
|
|
248
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var f=function(M){var Y=M.length;if(Y%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var W=M.indexOf("=");if(W===-1)W=Y;var z=W===Y?0:4-W%4;return[W,z]};var h=function(M,Y,W){return(Y+W)*3/4-W},v=function(M){var Y,W=f(M),z=W[0],G=W[1],J=new m(h(M,z,G)),K=0,R=G>0?z-4:z,U;for(U=0;U<R;U+=4)Y=V[M.charCodeAt(U)]<<18|V[M.charCodeAt(U+1)]<<12|V[M.charCodeAt(U+2)]<<6|V[M.charCodeAt(U+3)],J[K++]=Y>>16&255,J[K++]=Y>>8&255,J[K++]=Y&255;if(G===2)Y=V[M.charCodeAt(U)]<<2|V[M.charCodeAt(U+1)]>>4,J[K++]=Y&255;if(G===1)Y=V[M.charCodeAt(U)]<<10|V[M.charCodeAt(U+1)]<<4|V[M.charCodeAt(U+2)]>>2,J[K++]=Y>>8&255,J[K++]=Y&255;return J};var j=v;var g=[],V=[],m=typeof Uint8Array!=="undefined"?Uint8Array:Array,E="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(X=0,_=E.length;X<_;++X)g[X]=E[X],V[E.charCodeAt(X)]=X;var X,_;V["-".charCodeAt(0)]=62;V["_".charCodeAt(0)]=63;class F{#M=new Map;[Symbol.iterator](){return this.entries()}append(M,Y){const W=this.#M.get(M);if(W===void 0)this.#M.set(M,[Y]);else W.push(Y)}*entries(M=", "){for(let[Y,W]of this.#M.entries())yield[Y,W.join(M)]}*entriesAll(){for(let[M,Y]of this.#M.entries())for(let W of Y)yield[M,W]}get(M,Y=", "){const W=this.#M.get(M);if(W===void 0)return null;else return W.join(Y)}getAll(M){return this.#M.get(M)??[]}has(M){return this.#M.has(M)}keys(){return this.#M.keys()}*values(M=", "){for(let Y of this.#M.values())yield Y.join(M)}*valuesAll(){for(let M of this.#M.values())yield*M}}function N(M,Y){if(M.length!==Y.length)return!1;else if(M.byteOffset%4===Y.byteOffset%4){const W=(4-M.byteOffset%4)%4,z=Math.floor((M.byteLength-W)/4),G=W+z*4,J=new Uint32Array(M.buffer,M.byteOffset+W,z),K=new Uint32Array(Y.buffer,Y.byteOffset+W,z);for(let R=0;R<W;++R)if(M[R]!==Y[R])return!1;for(let R=0;R<z;++R)if(J[R]!==K[R])return!1;for(let R=G;R<M.length;++R)if(M[R]!==Y[R])return!1;return!0}else{for(let W of M.keys())if(M[W]!==Y[W])return!1;return!0}}function y(M,Y){return M.findIndex((W,z)=>{if(W!==Y[0]||z+Y.length>M.length)return!1;else{for(let G=1;G<Y.length;++G)if(M[z+G]!==Y[G])return!1;return!0}})}async function*q(M,Y){let W=new Uint8Array(0);for await(let z of M){W=W.length?A([W,z]):z;let G;while((G=y(W,Y))!==-1)yield W.subarray(0,G),W=W.subarray(G+Y.length)}yield W}var A=function(M){const Y=M.reduce((G,J)=>G+J.length,0),W=new Uint8Array(Y);let z=0;for(let G of M)W.set(G,z),z+=G.length;return W};async function C(M){const Y=[];for await(let W of M)Y.push(W);return A(Y)}async function*O(M,Y=b){for await(let W of M){const z=new Uint8Array(W.length+Y.length);let G=!1,J=0;for(let K=0;K<W.length;++K){const R=W[K];if(R>=128)throw new Error(`got non-ascii character when decoding quoted printable: ${R}`);if(R!==61)z[J++]=R;else{const U=W[++K];if(U===void 0)G=!0;else{const $=W[++K];if($===void 0)throw new Error("quoted printable escape (=) was not followed by two bytes");let Z=parseInt(String.fromCharCode(U),16);Z*=16,Z+=parseInt(String.fromCharCode($),16),z[J++]=Z}}}if(!G)z.set(Y,J),J+=Y.length;yield z.subarray(0,J)}}async function*Q(M){for await(let Y of M)yield j(L.decode(Y))}async function*P(M){for await(let Y of M)yield Y}function T(){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 b=new Uint8Array([10]),L=new TextDecoder;var k=function(M){const Y=new Uint8Array(M.length);let W=0;for(let z=0;z<M.length;++z){const G=M.charCodeAt(z);let J;if(G>=128)throw new Error(`got non-ascii character when decoding q-quoted word: "${M}"`);else if(G===95)J=32;else if(G===61)J=parseInt(M[++z],16),J*=16,J+=parseInt(M[++z],16);else J=G;Y[W++]=J}return Y.subarray(0,W)},H=function(M){const Y=p.exec(M);if(Y){const[,W,z,G]=Y;let J;if(z==="Q")J=k(G);else J=j(G);return new TextDecoder(W).decode(J)}else return M};async function c(M){const Y=new F;let W="",z="";for(;;){const{done:G,value:J}=await M.next();if(G)throw new Error("didn't find an empty line to signify the end of header parsing");const K=I.decode(J);if(/^\s/.test(K))z+=H(K.substr(1));else{if(W)Y.append(W,z);if(K){const R=K.indexOf(": ");if(R===-1)throw new Error(`header line didn't have key-value delimiter: "${K}"`);W=K.slice(0,R),z=H(K.slice(R+2))}else return Y}}}var s=function(M){const Y=M.get("Content-Type");if(Y===null)throw new Error(`first headers didn't contain a content type: ${JSON.stringify(Object.fromEntries(M))}`);let W=void 0,z=!1;for(let K of Y.split(/;\s*/))if(K.startsWith("multipart/"))z=!0;else if(K.startsWith("boundary=")){if(W=K.slice(9),W.startsWith('"')&&W.endsWith('"'))W=W.slice(1,-1)}if(!z||W===void 0)throw new Error("first content type header didn't contain 'multipart/...' and a boundary string");const G=w.encode(`--${W}`),J=w.encode(`--${W}--`);return[G,J]};async function*e(M,{decoderOverrides:Y=new Map}={}){const W=new Map([...a.entries(),...Y.entries()]),z=new Uint8Array([13,10]),G=q(M,z);let J=null,K=!0;while(K){const R=await c(G),[U,$]=J??(J=s(R)),Z=R.get("Content-Transfer-Encoding")??"7bit",S=W.get(Z);if(S===void 0)throw new Error(`unhandled encoding type: ${Z}`);const B=await C(S({[Symbol.asyncIterator](){return{async next(){const{done:x,value:D}=await G.next();if(x)throw new Error(`stream didn't end with the appropriate termination boundary: ${I.decode($)}`);else if(N(D,U))return{done:!0,value:void 0};else if(N(D,$))return K=!1,{done:!0,value:void 0};else return{value:D}}}}}));yield{headers:R,content:B}}}var w=new TextEncoder,I=new TextDecoder,p=/^=\?([^?\s]+)\?([BQ])\?([^?\s]+)\?=$/,a=new Map([["7bit",P],["base64",Q],["quoted-printable",O],["8bit",P],["binary",T]]);export{e as parseMhtml};
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* create a Uint8Array from a buffer
|
|
3
|
-
*
|
|
4
|
-
* This method is necessary since creating a Uint8Array from a view will copy
|
|
5
|
-
* the elements instead of creating a view of the underling buffer.
|
|
6
|
-
*/
|
|
7
|
-
export declare function toBytes(buff: ArrayBuffer): Uint8Array;
|
|
8
1
|
/**
|
|
9
2
|
* Compare two byte arrays for equality
|
|
10
3
|
*/
|
|
@@ -20,7 +13,7 @@ export declare function indexOf(haystack: Uint8Array, needle: Uint8Array): numbe
|
|
|
20
13
|
* compatibility between node and web, and splits it into an async iterator
|
|
21
14
|
* where each value is delimited by the split sequence.
|
|
22
15
|
*/
|
|
23
|
-
export declare function splitStream(iter: AsyncIterable<
|
|
16
|
+
export declare function splitStream(iter: AsyncIterable<Uint8Array>, split: Uint8Array): AsyncIterableIterator<Uint8Array>;
|
|
24
17
|
/**
|
|
25
18
|
* collect an async iterable of buffers into one
|
|
26
19
|
*/
|
package/dist/utils.js
CHANGED
|
@@ -8,20 +8,6 @@
|
|
|
8
8
|
* @packageDocumentation
|
|
9
9
|
*/
|
|
10
10
|
import { toByteArray } from "base64-js";
|
|
11
|
-
/**
|
|
12
|
-
* create a Uint8Array from a buffer
|
|
13
|
-
*
|
|
14
|
-
* This method is necessary since creating a Uint8Array from a view will copy
|
|
15
|
-
* the elements instead of creating a view of the underling buffer.
|
|
16
|
-
*/
|
|
17
|
-
export function toBytes(buff) {
|
|
18
|
-
if (ArrayBuffer.isView(buff)) {
|
|
19
|
-
return new Uint8Array(buff.buffer, buff.byteOffset, buff.byteLength);
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
return new Uint8Array(buff);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
11
|
/**
|
|
26
12
|
* Compare two byte arrays for equality
|
|
27
13
|
*/
|
|
@@ -91,8 +77,7 @@ export function indexOf(haystack, needle) {
|
|
|
91
77
|
export async function* splitStream(iter, split) {
|
|
92
78
|
let current = new Uint8Array(0);
|
|
93
79
|
for await (const chunk of iter) {
|
|
94
|
-
|
|
95
|
-
current = current.length ? concat([current, next]) : next;
|
|
80
|
+
current = current.length ? concat([current, chunk]) : chunk;
|
|
96
81
|
let nextInd;
|
|
97
82
|
while ((nextInd = indexOf(current, split)) !== -1) {
|
|
98
83
|
yield current.subarray(0, nextInd);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { bytesEqual, collect, decodeBinary, decodeIdentity, decodeQuotedPrintable, indexOf, splitStream, } from "./utils";
|
|
3
|
+
const encoder = new TextEncoder();
|
|
4
|
+
const decoder = new TextDecoder();
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
6
|
+
async function* toAsyncIterable(items) {
|
|
7
|
+
for (const item of items) {
|
|
8
|
+
yield item;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
describe("bytesEqual()", () => {
|
|
12
|
+
test("length failure", () => {
|
|
13
|
+
const left = new Uint8Array([1, 2, 3]);
|
|
14
|
+
const right = new Uint8Array([1, 2, 3, 4]);
|
|
15
|
+
expect(bytesEqual(left, right)).toBe(false);
|
|
16
|
+
});
|
|
17
|
+
test("simple success", () => {
|
|
18
|
+
const left = new Uint8Array([1, 2, 3]);
|
|
19
|
+
const right = new Uint8Array([1, 2, 3]);
|
|
20
|
+
expect(bytesEqual(left, right)).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
test("simple failure", () => {
|
|
23
|
+
const left = new Uint8Array([1, 2, 3]);
|
|
24
|
+
const right = new Uint8Array([1, 2, 4]);
|
|
25
|
+
expect(bytesEqual(left, right)).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
test("fast path success", () => {
|
|
28
|
+
const left = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]).subarray(1);
|
|
29
|
+
const right = new Uint8Array([0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7]).subarray(5);
|
|
30
|
+
expect(bytesEqual(left, right)).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
test("fast path failure start", () => {
|
|
33
|
+
const left = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]).subarray(1);
|
|
34
|
+
const right = new Uint8Array([0, 0, 0, 0, 0, 2, 2, 3, 4, 5, 6, 7]).subarray(5);
|
|
35
|
+
expect(bytesEqual(left, right)).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
test("fast path failure middle", () => {
|
|
38
|
+
const left = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]).subarray(1);
|
|
39
|
+
const right = new Uint8Array([0, 0, 0, 0, 0, 1, 2, 4, 4, 5, 6, 7]).subarray(5);
|
|
40
|
+
expect(bytesEqual(left, right)).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
test("fast path failure end", () => {
|
|
43
|
+
const left = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]).subarray(1);
|
|
44
|
+
const right = new Uint8Array([0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 8]).subarray(5);
|
|
45
|
+
expect(bytesEqual(left, right)).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
test("slow path success", () => {
|
|
48
|
+
const left = new Uint8Array([1, 2, 3, 4, 5]);
|
|
49
|
+
const right = new Uint8Array([0, 1, 2, 3, 4, 5]).subarray(1);
|
|
50
|
+
expect(bytesEqual(left, right)).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
test("slow path failure", () => {
|
|
53
|
+
const left = new Uint8Array([1, 2, 3, 4, 5]);
|
|
54
|
+
const right = new Uint8Array([0, 1, 2, 3, 4, 6]).subarray(1);
|
|
55
|
+
expect(bytesEqual(left, right)).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe("indexOf()", () => {
|
|
59
|
+
test("simple success", () => {
|
|
60
|
+
const haystack = new Uint8Array([0, 1, 2]);
|
|
61
|
+
const needle = new Uint8Array([1]);
|
|
62
|
+
expect(indexOf(haystack, needle)).toEqual(1);
|
|
63
|
+
});
|
|
64
|
+
test("simple failure", () => {
|
|
65
|
+
const haystack = new Uint8Array([0, 1, 2]);
|
|
66
|
+
const needle = new Uint8Array([3]);
|
|
67
|
+
expect(indexOf(haystack, needle)).toEqual(-1);
|
|
68
|
+
});
|
|
69
|
+
test("complex success", () => {
|
|
70
|
+
const haystack = new Uint8Array([0, 1, 3, 1, 2, 3]);
|
|
71
|
+
const needle = new Uint8Array([1, 2]);
|
|
72
|
+
expect(indexOf(haystack, needle)).toEqual(3);
|
|
73
|
+
});
|
|
74
|
+
test("complex failure", () => {
|
|
75
|
+
const haystack = new Uint8Array([0, 1, 3, 1, 4, 3]);
|
|
76
|
+
const needle = new Uint8Array([1, 2]);
|
|
77
|
+
expect(indexOf(haystack, needle)).toEqual(-1);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
test("splitStream()", async () => {
|
|
81
|
+
const split = new Uint8Array([1, 2]);
|
|
82
|
+
const input = [
|
|
83
|
+
new Uint8Array([255, 1, 2, 3, 4, 1, 2, 1]),
|
|
84
|
+
new Uint8Array([2, 5, 6, 7, 8]),
|
|
85
|
+
new Uint8Array([9, 10, 11, 2, 1, 12, 13]),
|
|
86
|
+
new Uint8Array([14, 15, 1, 2, 16]),
|
|
87
|
+
];
|
|
88
|
+
const parts = [];
|
|
89
|
+
for await (const part of splitStream(toAsyncIterable(input), split)) {
|
|
90
|
+
parts.push(part);
|
|
91
|
+
}
|
|
92
|
+
const expected = [
|
|
93
|
+
new Uint8Array([255]),
|
|
94
|
+
new Uint8Array([3, 4]),
|
|
95
|
+
new Uint8Array(0),
|
|
96
|
+
new Uint8Array([5, 6, 7, 8, 9, 10, 11, 2, 1, 12, 13, 14, 15]),
|
|
97
|
+
new Uint8Array([16]),
|
|
98
|
+
];
|
|
99
|
+
expect(parts.length).toEqual(expected.length);
|
|
100
|
+
for (const [i, part] of parts.entries()) {
|
|
101
|
+
expect(bytesEqual(part, expected[i])).toBe(true);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
test("collect()", async () => {
|
|
105
|
+
const res = await collect(toAsyncIterable([
|
|
106
|
+
new Uint8Array([0, 1]),
|
|
107
|
+
new Uint8Array([2, 3, 4]),
|
|
108
|
+
new Uint8Array([5, 6]),
|
|
109
|
+
]));
|
|
110
|
+
const expected = new Uint8Array([0, 1, 2, 3, 4, 5, 6]);
|
|
111
|
+
expect(bytesEqual(res, expected)).toBe(true);
|
|
112
|
+
});
|
|
113
|
+
describe("decodeQuotedPrintable()", () => {
|
|
114
|
+
test("success", async () => {
|
|
115
|
+
// eslint-disable-next-line spellcheck/spell-checker
|
|
116
|
+
const input = ["key=3Dvalue", "this line continues =", "on the next line"];
|
|
117
|
+
const res = decoder.decode(await collect(decodeQuotedPrintable(toAsyncIterable(input.map((l) => encoder.encode(l))))));
|
|
118
|
+
expect(res).toStrictEqual("key=value\nthis line continues on the next line\n");
|
|
119
|
+
});
|
|
120
|
+
test("ascii failure", async () => {
|
|
121
|
+
const input = ["\xff"];
|
|
122
|
+
const decoded = decodeQuotedPrintable(toAsyncIterable(input.map((l) => encoder.encode(l))));
|
|
123
|
+
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression,@typescript-eslint/await-thenable
|
|
124
|
+
await expect((async () => {
|
|
125
|
+
for await (const _ of decoded) {
|
|
126
|
+
//
|
|
127
|
+
}
|
|
128
|
+
})()).rejects.toThrow("non-ascii");
|
|
129
|
+
});
|
|
130
|
+
test("encoding failure", async () => {
|
|
131
|
+
const input = ["a=0"];
|
|
132
|
+
const decoded = decodeQuotedPrintable(toAsyncIterable(input.map((l) => encoder.encode(l))));
|
|
133
|
+
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression,@typescript-eslint/await-thenable
|
|
134
|
+
await expect((async () => {
|
|
135
|
+
for await (const _ of decoded) {
|
|
136
|
+
//
|
|
137
|
+
}
|
|
138
|
+
})()).rejects.toThrow("quoted printable escape");
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
test("decodeIdentity()", async () => {
|
|
142
|
+
const input = ["line ", "not ascii \xff"];
|
|
143
|
+
const res = decoder.decode(await collect(decodeIdentity(toAsyncIterable(input.map((l) => encoder.encode(l))))));
|
|
144
|
+
expect(res).toStrictEqual("line not ascii \xff");
|
|
145
|
+
});
|
|
146
|
+
test("decodeBinary()", () => {
|
|
147
|
+
expect(decodeBinary).toThrow("explicitly");
|
|
148
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mhtml-stream",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Zero dependency stream MHTML parser",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mhtml",
|
|
@@ -12,104 +12,37 @@
|
|
|
12
12
|
},
|
|
13
13
|
"author": "Erik Brinkman <erik.brinkman@gmail.com>",
|
|
14
14
|
"license": "MIT",
|
|
15
|
+
"type": "module",
|
|
15
16
|
"types": "dist/index.d.ts",
|
|
16
|
-
"module": "
|
|
17
|
-
"main": "bundle/mhtml.cjs.min.js",
|
|
18
|
-
"unpkg": "bundle/mhtml.iife.min.js",
|
|
17
|
+
"module": "dist/mhtml.esm.min.js",
|
|
19
18
|
"files": [
|
|
20
|
-
"/bundle/*.js",
|
|
21
19
|
"/dist/**/*.js",
|
|
22
20
|
"/dist/**/*.d.ts"
|
|
23
21
|
],
|
|
24
|
-
"type": "module",
|
|
25
22
|
"scripts": {
|
|
26
|
-
"fmt": "
|
|
27
|
-
"lint
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"test": "jest --coverage",
|
|
32
|
-
"doc": "pnpify typedoc",
|
|
33
|
-
"build": "pnpify tsc -p tsconfig.build.json && node bundle.mjs",
|
|
34
|
-
"prepack": "yarn lint && yarn test && yarn build"
|
|
23
|
+
"fmt": "prettier --cache --write 'src/*.ts' '*.{js,json}'",
|
|
24
|
+
"lint": "tsc && eslint --cache 'src/*.ts' && typedoc --emit none",
|
|
25
|
+
"doc": "typedoc",
|
|
26
|
+
"export": "tsc -p tsconfig.build.json && bun build src/index.ts --minify --outfile dist/mhtml.esm.min.js",
|
|
27
|
+
"prepack": "bun lint && bun test --coverage && bun export"
|
|
35
28
|
},
|
|
36
29
|
"dependencies": {
|
|
37
30
|
"base64-js": "^1.5.1"
|
|
38
31
|
},
|
|
39
32
|
"devDependencies": {
|
|
40
|
-
"@
|
|
41
|
-
"@
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"@types/jest": "^29.5.3",
|
|
45
|
-
"@types/node": "^20.4.2",
|
|
46
|
-
"@typescript-eslint/eslint-plugin": "^6.1.0",
|
|
47
|
-
"@typescript-eslint/parser": "^6.1.0",
|
|
48
|
-
"@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.15",
|
|
49
|
-
"@yarnpkg/pnpify": "^4.0.0-rc.48",
|
|
50
|
-
"babel-jest": "^29.6.1",
|
|
51
|
-
"chalk": "5.3.0",
|
|
52
|
-
"esbuild": "^0.18.14",
|
|
53
|
-
"eslint": "^8.45.0",
|
|
54
|
-
"eslint-config-prettier": "^8.8.0",
|
|
55
|
-
"eslint-plugin-jest": "^27.2.3",
|
|
33
|
+
"@types/base64-js": "^1.3.2",
|
|
34
|
+
"@types/bun": "^1.1.0",
|
|
35
|
+
"eslint": "^9.0.0",
|
|
36
|
+
"eslint-config-prettier": "^9.1.0",
|
|
56
37
|
"eslint-plugin-spellcheck": "^0.0.20",
|
|
57
38
|
"eslint-plugin-tsdoc": "^0.2.17",
|
|
58
|
-
"
|
|
59
|
-
"prettier": "^3.
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"typescript": "
|
|
63
|
-
},
|
|
64
|
-
"resolutions": {
|
|
65
|
-
"minimist": "1.2.6",
|
|
66
|
-
"minimatch": "^3.0.5"
|
|
67
|
-
},
|
|
68
|
-
"prettier": {
|
|
69
|
-
"plugins": [
|
|
70
|
-
"prettier-plugin-organize-imports"
|
|
71
|
-
]
|
|
72
|
-
},
|
|
73
|
-
"jest": {
|
|
74
|
-
"testEnvironment": "node"
|
|
75
|
-
},
|
|
76
|
-
"babel": {
|
|
77
|
-
"presets": [
|
|
78
|
-
[
|
|
79
|
-
"@babel/preset-env",
|
|
80
|
-
{
|
|
81
|
-
"targets": {
|
|
82
|
-
"node": "current"
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
],
|
|
86
|
-
"@babel/preset-typescript"
|
|
87
|
-
]
|
|
39
|
+
"prettier": "^3.2.5",
|
|
40
|
+
"prettier-plugin-organize-imports": "^3.2.4",
|
|
41
|
+
"typedoc": "^0.25.8",
|
|
42
|
+
"typescript": "^5.3.3",
|
|
43
|
+
"typescript-eslint": "^7.7.0"
|
|
88
44
|
},
|
|
89
45
|
"eslintConfig": {
|
|
90
|
-
"root": true,
|
|
91
|
-
"parser": "@typescript-eslint/parser",
|
|
92
|
-
"plugins": [
|
|
93
|
-
"@typescript-eslint",
|
|
94
|
-
"jest",
|
|
95
|
-
"spellcheck",
|
|
96
|
-
"eslint-plugin-tsdoc"
|
|
97
|
-
],
|
|
98
|
-
"extends": [
|
|
99
|
-
"eslint:recommended",
|
|
100
|
-
"plugin:@typescript-eslint/recommended",
|
|
101
|
-
"plugin:@typescript-eslint/recommended-requiring-type-checking",
|
|
102
|
-
"plugin:jest/recommended",
|
|
103
|
-
"prettier"
|
|
104
|
-
],
|
|
105
|
-
"parserOptions": {
|
|
106
|
-
"project": [
|
|
107
|
-
"./tsconfig.json"
|
|
108
|
-
]
|
|
109
|
-
},
|
|
110
|
-
"env": {
|
|
111
|
-
"node": true
|
|
112
|
-
},
|
|
113
46
|
"rules": {
|
|
114
47
|
"@typescript-eslint/no-inferrable-types": "off",
|
|
115
48
|
"@typescript-eslint/no-non-null-assertion": "off",
|
|
@@ -158,6 +91,5 @@
|
|
|
158
91
|
}
|
|
159
92
|
]
|
|
160
93
|
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
}
|
|
94
|
+
}
|
|
95
|
+
}
|
package/bundle/mhtml.cjs.min.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
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: ${i}`);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});
|
package/bundle/mhtml.esm.min.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
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: ${i}`);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};
|
package/bundle/mhtml.iife.min.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
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: ${i}`);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);})();
|