@social-mail/shared 1.0.29 → 1.1.3
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/.gitlab-ci.yml +3 -3
- package/dist/.tsbuildinfo +1 -0
- package/dist/QueryIterator.d.ts +1 -9
- package/dist/QueryIterator.d.ts.map +1 -1
- package/dist/QueryIterator.js +3 -14
- package/dist/QueryIterator.js.map +1 -1
- package/dist/ical-parser/Calender.js +36 -92
- package/dist/ical-parser/Calender.js.map +1 -1
- package/dist/ical-parser/parseDate.js +1 -5
- package/dist/ical-parser/parseDate.js.map +1 -1
- package/dist/mime-parser/AttachmentFile.d.ts +5 -11
- package/dist/mime-parser/AttachmentFile.d.ts.map +1 -1
- package/dist/mime-parser/AttachmentFile.js +3 -8
- package/dist/mime-parser/AttachmentFile.js.map +1 -1
- package/dist/mime-parser/HeaderContentDisposition.d.ts +5 -5
- package/dist/mime-parser/HeaderContentDisposition.d.ts.map +1 -1
- package/dist/mime-parser/HeaderContentDisposition.js +2 -5
- package/dist/mime-parser/HeaderContentDisposition.js.map +1 -1
- package/dist/mime-parser/HeaderContentType.d.ts +5 -5
- package/dist/mime-parser/HeaderContentType.d.ts.map +1 -1
- package/dist/mime-parser/HeaderContentType.js +2 -5
- package/dist/mime-parser/HeaderContentType.js.map +1 -1
- package/dist/mime-parser/MimeMessage.d.ts +11 -11
- package/dist/mime-parser/MimeMessage.d.ts.map +1 -1
- package/dist/mime-parser/MimeMessage.js +46 -72
- package/dist/mime-parser/MimeMessage.js.map +1 -1
- package/dist/mime-parser/MimeNode.d.ts +28 -38
- package/dist/mime-parser/MimeNode.d.ts.map +1 -1
- package/dist/mime-parser/MimeNode.js +171 -295
- package/dist/mime-parser/MimeNode.js.map +1 -1
- package/dist/mime-parser/encoder/RawBuffer.d.ts +5 -5
- package/dist/mime-parser/encoder/RawBuffer.d.ts.map +1 -1
- package/dist/mime-parser/encoder/RawBuffer.js +7 -13
- package/dist/mime-parser/encoder/RawBuffer.js.map +1 -1
- package/dist/mime-parser/encoder/base64-to-blob.d.ts +1 -7
- package/dist/mime-parser/encoder/base64-to-blob.d.ts.map +1 -1
- package/dist/mime-parser/encoder/base64-to-blob.js +0 -6
- package/dist/mime-parser/encoder/base64-to-blob.js.map +1 -1
- package/dist/mime-parser/encoder/quoted-printable.d.ts +5 -8
- package/dist/mime-parser/encoder/quoted-printable.d.ts.map +1 -1
- package/dist/mime-parser/encoder/quoted-printable.js +3 -34
- package/dist/mime-parser/encoder/quoted-printable.js.map +1 -1
- package/dist/mime-parser/encoder/word-encoding.d.ts +4 -6
- package/dist/mime-parser/encoder/word-encoding.d.ts.map +1 -1
- package/dist/mime-parser/encoder/word-encoding.js +4 -5
- package/dist/mime-parser/encoder/word-encoding.js.map +1 -1
- package/dist/mime-parser/parsePairs.d.ts +1 -1
- package/dist/mime-parser/parsePairs.d.ts.map +1 -1
- package/dist/mime-parser/parsePairs.js +3 -7
- package/dist/mime-parser/parsePairs.js.map +1 -1
- package/dist/mime-parser/stream/LineStream.d.ts +10 -16
- package/dist/mime-parser/stream/LineStream.d.ts.map +1 -1
- package/dist/mime-parser/stream/LineStream.js +59 -94
- package/dist/mime-parser/stream/LineStream.js.map +1 -1
- package/dist/mime-parser/stream/TextWriter.d.ts +4 -3
- package/dist/mime-parser/stream/TextWriter.d.ts.map +1 -1
- package/dist/mime-parser/stream/TextWriter.js +2 -3
- package/dist/mime-parser/stream/TextWriter.js.map +1 -1
- package/dist/mime-parser/tokenizer.d.ts +3 -3
- package/dist/mime-parser/tokenizer.d.ts.map +1 -1
- package/dist/mime-parser/tokenizer.js +10 -17
- package/dist/mime-parser/tokenizer.js.map +1 -1
- package/package.json +3 -3
- package/src/{QueryIterator.js → QueryIterator.ts} +11 -12
- package/src/ical-parser/Calender.ts +1 -1
- package/src/mime-parser/AttachmentFile.ts +24 -0
- package/src/mime-parser/{HeaderContentDisposition.js → HeaderContentDisposition.ts} +7 -17
- package/src/mime-parser/{HeaderContentType.js → HeaderContentType.ts} +7 -18
- package/src/mime-parser/{MimeMessage.js → MimeMessage.ts} +25 -35
- package/src/mime-parser/{MimeNode.js → MimeNode.ts} +75 -133
- package/src/mime-parser/encoder/{RawBuffer.js → RawBuffer.ts} +15 -17
- package/src/mime-parser/encoder/{base64-to-blob.js → base64-to-blob.ts} +8 -8
- package/src/mime-parser/encoder/{quoted-printable.js → quoted-printable.ts} +9 -11
- package/src/mime-parser/encoder/{word-encoding.js → word-encoding.ts} +6 -6
- package/src/mime-parser/{parsePairs.js → parsePairs.ts} +5 -4
- package/src/mime-parser/stream/{LineStream.js → LineStream.ts} +12 -19
- package/src/mime-parser/stream/{TextWriter.js → TextWriter.ts} +5 -10
- package/src/mime-parser/{tokenizer.js → tokenizer.ts} +24 -21
- package/tsconfig.json +30 -9
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/src/mime-parser/AttachmentFile.js +0 -29
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-redundant-type-constituents */
|
|
2
1
|
// import QueryIterator from "../../common/QueryIterator";
|
|
3
2
|
import { AttachmentFile } from "./AttachmentFile.js";
|
|
4
3
|
import { HeaderContentType } from "./HeaderContentType.js";
|
|
@@ -10,31 +9,13 @@ import { wordEncoding } from "./encoder/word-encoding.js";
|
|
|
10
9
|
import LineStream from "./stream/LineStream.js";
|
|
11
10
|
import TextWriter from "./stream/TextWriter.js";
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// boundary?: string;
|
|
16
|
-
// charset?: string
|
|
17
|
-
// };
|
|
12
|
+
export class CIMap extends Map<string, any> {
|
|
13
|
+
private ci = new Map<string, string>();
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
// export interface IContentDispositionObject {
|
|
22
|
-
// type: string;
|
|
23
|
-
// filename?: string;
|
|
24
|
-
// };
|
|
25
|
-
|
|
26
|
-
// export type IContentDisposition = string | IContentDispositionObject;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
export class CIMap extends Map {
|
|
31
|
-
|
|
32
|
-
ci = new Map();
|
|
33
|
-
|
|
34
|
-
set(key, value) {
|
|
15
|
+
set(key: string, value: any): this {
|
|
35
16
|
if (typeof key === "string") {
|
|
36
17
|
let ck = this.ci.get(key);
|
|
37
|
-
if (ck ===
|
|
18
|
+
if (ck === undefined) {
|
|
38
19
|
ck = key.toLocaleLowerCase();
|
|
39
20
|
this.ci.set(ck, key);
|
|
40
21
|
} else {
|
|
@@ -44,26 +25,29 @@ export class CIMap extends Map {
|
|
|
44
25
|
return super.set(key, value);
|
|
45
26
|
}
|
|
46
27
|
|
|
47
|
-
get(key) {
|
|
28
|
+
get(key: string): any {
|
|
48
29
|
if (typeof key === "string") {
|
|
49
30
|
const ck = key.toLocaleLowerCase();
|
|
50
|
-
key = this.ci.get(ck);
|
|
31
|
+
key = this.ci.get(ck) || key;
|
|
51
32
|
}
|
|
52
33
|
return super.get(key);
|
|
53
34
|
}
|
|
54
|
-
|
|
55
35
|
}
|
|
56
36
|
|
|
57
|
-
|
|
58
37
|
export class MimeNode {
|
|
59
|
-
|
|
60
38
|
static createMessage({
|
|
61
39
|
html,
|
|
62
40
|
subject,
|
|
63
41
|
text = "",
|
|
64
42
|
name = "",
|
|
65
43
|
attachments = []
|
|
66
|
-
}
|
|
44
|
+
}: {
|
|
45
|
+
html?: string;
|
|
46
|
+
subject: string;
|
|
47
|
+
text?: string;
|
|
48
|
+
name?: string;
|
|
49
|
+
attachments?: any[];
|
|
50
|
+
}): MimeNode {
|
|
67
51
|
const root = new MimeNode("multipart/mixed");
|
|
68
52
|
root.setHeader("Subject", subject);
|
|
69
53
|
if (name) {
|
|
@@ -87,11 +71,12 @@ export class MimeNode {
|
|
|
87
71
|
}
|
|
88
72
|
|
|
89
73
|
static create(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
74
|
+
text: string | File,
|
|
75
|
+
type?: string,
|
|
76
|
+
id?: string
|
|
77
|
+
): MimeNode {
|
|
93
78
|
if (typeof text === "string") {
|
|
94
|
-
const node = new MimeNode(type);
|
|
79
|
+
const node = new MimeNode(type || "");
|
|
95
80
|
node.text = text;
|
|
96
81
|
return node;
|
|
97
82
|
}
|
|
@@ -106,23 +91,28 @@ export class MimeNode {
|
|
|
106
91
|
return fileNode;
|
|
107
92
|
}
|
|
108
93
|
|
|
109
|
-
|
|
94
|
+
encoded?: string;
|
|
95
|
+
children?: MimeNode[];
|
|
96
|
+
contentType: HeaderContentType;
|
|
97
|
+
contentDisposition?: HeaderContentDisposition;
|
|
98
|
+
textContent?: string;
|
|
99
|
+
blobData?: Blob;
|
|
100
|
+
headers: CIMap;
|
|
110
101
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
102
|
+
constructor(type?: string) {
|
|
103
|
+
this.headers = new CIMap();
|
|
104
|
+
this.contentType = new HeaderContentType(type);
|
|
105
|
+
this.headers.set("Content-Type", this.contentType);
|
|
106
|
+
}
|
|
116
107
|
|
|
117
|
-
|
|
118
|
-
get text() {
|
|
108
|
+
get text(): string {
|
|
119
109
|
let tc = this.textContent;
|
|
120
110
|
if (tc) {
|
|
121
111
|
return tc;
|
|
122
112
|
}
|
|
123
113
|
let { encoded } = this;
|
|
124
114
|
if (!encoded) {
|
|
125
|
-
return;
|
|
115
|
+
return "";
|
|
126
116
|
}
|
|
127
117
|
// we need to convert byte array to utf8
|
|
128
118
|
const cte = this.contentTransferEncoding?.toLowerCase();
|
|
@@ -145,118 +135,65 @@ export class MimeNode {
|
|
|
145
135
|
return tc;
|
|
146
136
|
}
|
|
147
137
|
|
|
148
|
-
set text(
|
|
138
|
+
set text(v: string) {
|
|
149
139
|
this.contentTransferEncoding = "quoted-printable";
|
|
150
140
|
this.textContent = v;
|
|
151
141
|
}
|
|
152
142
|
|
|
153
|
-
|
|
154
|
-
get blob() {
|
|
143
|
+
get blob(): Blob {
|
|
155
144
|
// this will create blob..
|
|
156
145
|
if (this.contentTransferEncoding?.toLocaleLowerCase() !== "base64") {
|
|
157
146
|
throw new Error("Not supported");
|
|
158
147
|
}
|
|
159
|
-
return this.blobData ??= base64toBlob(this.encoded
|
|
148
|
+
return this.blobData ??= base64toBlob(this.encoded!, this.contentType.type);
|
|
160
149
|
}
|
|
161
150
|
|
|
162
|
-
set blob(
|
|
151
|
+
set blob(v: Blob) {
|
|
163
152
|
this.blobData = v;
|
|
164
153
|
}
|
|
165
154
|
|
|
166
|
-
|
|
167
|
-
get contentTransferEncoding() {
|
|
155
|
+
get contentTransferEncoding(): string | undefined {
|
|
168
156
|
return this.header("Content-Transfer-Encoding");
|
|
169
157
|
}
|
|
170
158
|
|
|
171
|
-
set contentTransferEncoding(
|
|
159
|
+
set contentTransferEncoding(v: string | undefined) {
|
|
172
160
|
this.setHeader("Content-Transfer-Encoding", v);
|
|
173
161
|
}
|
|
174
162
|
|
|
175
|
-
|
|
176
|
-
get boundary() {
|
|
163
|
+
get boundary(): string | undefined {
|
|
177
164
|
return this.contentType.boundary;
|
|
178
165
|
}
|
|
179
166
|
|
|
180
|
-
|
|
181
|
-
get descendent() {
|
|
167
|
+
get descendent(): IterableIterator<MimeNode> {
|
|
182
168
|
return this.enumerate();
|
|
183
169
|
}
|
|
184
170
|
|
|
185
|
-
|
|
186
|
-
/** @type {string} */ textContent;
|
|
187
|
-
|
|
188
|
-
/** @type {Map<string, string | any>} */ headers;
|
|
189
|
-
|
|
190
|
-
constructor( /** @type {string} */ type) {
|
|
191
|
-
this.headers = new CIMap();
|
|
192
|
-
this.contentType = new HeaderContentType(type);
|
|
193
|
-
this.headers.set("Content-Type", this.contentType);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
getFirstChild(
|
|
197
|
-
/** @type {string} */ contentType,
|
|
198
|
-
create = false
|
|
199
|
-
) {
|
|
200
|
-
contentType = contentType.toLocaleLowerCase();
|
|
201
|
-
let child = QueryIterator.first(this.descendent, (x) => x.contentType.type === contentType);
|
|
202
|
-
if (!child && create) {
|
|
203
|
-
child = new MimeNode(contentType);
|
|
204
|
-
(this.children ??= []).push(child);
|
|
205
|
-
}
|
|
206
|
-
return child;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
header(/** @type {string} */ name) {
|
|
171
|
+
header(name: string): any {
|
|
210
172
|
return this.headers.get(name);
|
|
211
173
|
}
|
|
212
174
|
|
|
213
|
-
setHeader(
|
|
214
|
-
/** @type {string} */name,
|
|
215
|
-
/** @type {string} */ value
|
|
216
|
-
) {
|
|
217
|
-
// name = name.toLocaleLowerCase();
|
|
218
|
-
// for (const [key] of this.headers.keys()) {
|
|
219
|
-
// if (key.toLocaleLowerCase() === name) {
|
|
220
|
-
// this.headers.set(key, value);
|
|
221
|
-
// return;
|
|
222
|
-
// }
|
|
223
|
-
// }
|
|
224
|
-
|
|
225
|
-
// // change name...
|
|
226
|
-
// switch(name.toLocaleLowerCase()) {
|
|
227
|
-
// case "content-type":
|
|
228
|
-
// name = "Content-Type";
|
|
229
|
-
// break;
|
|
230
|
-
// case "content-transfer-encoding":
|
|
231
|
-
// name = "Content-Transfer-Encoding";
|
|
232
|
-
// break;
|
|
233
|
-
// case "content-disposition":
|
|
234
|
-
// name = "Content-Disposition";
|
|
235
|
-
// break;
|
|
236
|
-
// }
|
|
237
|
-
|
|
175
|
+
setHeader(name: string, value: any): void {
|
|
238
176
|
this.headers.set(name, value);
|
|
239
177
|
}
|
|
240
178
|
|
|
241
|
-
async asFile() {
|
|
242
|
-
const text = this.encoded
|
|
179
|
+
async asFile(): Promise<AttachmentFile> {
|
|
180
|
+
const text = this.encoded!.split("\n").map((x) => x.trim()).join("");
|
|
243
181
|
const url = `data:${this.contentType.type};base64,${text}`;
|
|
244
182
|
const blob = await fetch(url);
|
|
245
183
|
const af = new AttachmentFile(
|
|
246
184
|
[await blob.blob()],
|
|
247
|
-
this.contentDisposition
|
|
185
|
+
this.contentDisposition!.filename!,
|
|
248
186
|
{
|
|
249
187
|
type: this.contentType.type,
|
|
250
188
|
contentId: this.header("Content-Id"),
|
|
251
|
-
disposition: this.contentDisposition
|
|
189
|
+
disposition: this.contentDisposition!.type as any
|
|
252
190
|
});
|
|
253
191
|
af.node = this;
|
|
254
192
|
return af;
|
|
255
193
|
}
|
|
256
194
|
|
|
257
|
-
async attachments(
|
|
258
|
-
|
|
259
|
-
for (const iterator of this.children) {
|
|
195
|
+
async attachments(files: AttachmentFile[] = []): Promise<AttachmentFile[]> {
|
|
196
|
+
for (const iterator of this.children || []) {
|
|
260
197
|
if (iterator.children) {
|
|
261
198
|
await iterator.attachments(files);
|
|
262
199
|
continue;
|
|
@@ -268,11 +205,7 @@ export class MimeNode {
|
|
|
268
205
|
return files;
|
|
269
206
|
}
|
|
270
207
|
|
|
271
|
-
async parse(
|
|
272
|
-
/** @type {LineStream} */ lines,
|
|
273
|
-
last = ""
|
|
274
|
-
) {
|
|
275
|
-
|
|
208
|
+
async parse(lines: LineStream, last = ""): Promise<boolean> {
|
|
276
209
|
await this.parseHeaders(lines);
|
|
277
210
|
|
|
278
211
|
const end = last + "--";
|
|
@@ -319,15 +252,12 @@ export class MimeNode {
|
|
|
319
252
|
this.children.push(child);
|
|
320
253
|
|
|
321
254
|
if (isLast) {
|
|
322
|
-
return;
|
|
255
|
+
return true;
|
|
323
256
|
}
|
|
324
257
|
}
|
|
325
258
|
}
|
|
326
259
|
|
|
327
|
-
async parseHeaders(
|
|
328
|
-
/** @type {LineStream} */ lines
|
|
329
|
-
) {
|
|
330
|
-
|
|
260
|
+
async parseHeaders(lines: LineStream): Promise<void> {
|
|
331
261
|
let headerName = "";
|
|
332
262
|
let headerValue = "";
|
|
333
263
|
|
|
@@ -366,8 +296,7 @@ export class MimeNode {
|
|
|
366
296
|
}
|
|
367
297
|
}
|
|
368
298
|
|
|
369
|
-
async save(
|
|
370
|
-
|
|
299
|
+
async save(writer: TextWriter): Promise<void> {
|
|
371
300
|
if (this.textContent) {
|
|
372
301
|
this.contentType.charset = "UTF-8";
|
|
373
302
|
}
|
|
@@ -395,7 +324,6 @@ export class MimeNode {
|
|
|
395
324
|
|
|
396
325
|
// check if we have any children...
|
|
397
326
|
if (this.children?.length) {
|
|
398
|
-
|
|
399
327
|
const boundary = `--${this.contentType.boundary}`;
|
|
400
328
|
|
|
401
329
|
for (const iterator of this.children) {
|
|
@@ -404,8 +332,6 @@ export class MimeNode {
|
|
|
404
332
|
}
|
|
405
333
|
|
|
406
334
|
writer.writeLine(boundary + "--");
|
|
407
|
-
|
|
408
|
-
|
|
409
335
|
return;
|
|
410
336
|
}
|
|
411
337
|
|
|
@@ -416,7 +342,7 @@ export class MimeNode {
|
|
|
416
342
|
let start = 0;
|
|
417
343
|
const max = 80;
|
|
418
344
|
for (;;) {
|
|
419
|
-
if (
|
|
345
|
+
if (start + max > base64.length) {
|
|
420
346
|
writer.writeLine(base64.substring(start));
|
|
421
347
|
break;
|
|
422
348
|
}
|
|
@@ -429,23 +355,20 @@ export class MimeNode {
|
|
|
429
355
|
let text = this.text;
|
|
430
356
|
switch(this.contentTransferEncoding) {
|
|
431
357
|
case "quoted-printable":
|
|
432
|
-
text = quotedPrintable.encode(
|
|
358
|
+
text = quotedPrintable.encode(RawBuffer.encode(text));
|
|
433
359
|
writer.writeLine(text);
|
|
434
360
|
break;
|
|
435
361
|
case "base64":
|
|
436
|
-
text = btoa(
|
|
362
|
+
text = btoa(RawBuffer.encode(text, this.contentType.charset));
|
|
437
363
|
writer.writeLine(text);
|
|
438
364
|
break;
|
|
439
365
|
default:
|
|
440
366
|
writer.writeLine(text);
|
|
441
367
|
break;
|
|
442
368
|
}
|
|
443
|
-
// writer.writeLine("");
|
|
444
|
-
return;
|
|
445
369
|
}
|
|
446
370
|
|
|
447
|
-
|
|
448
|
-
*enumerate() {
|
|
371
|
+
*enumerate(): IterableIterator<MimeNode> {
|
|
449
372
|
yield this;
|
|
450
373
|
if (!this.children) {
|
|
451
374
|
return;
|
|
@@ -454,4 +377,23 @@ export class MimeNode {
|
|
|
454
377
|
yield* iterator.enumerate();
|
|
455
378
|
}
|
|
456
379
|
}
|
|
380
|
+
|
|
381
|
+
getFirstChild(contentType: string, create = false): MimeNode | undefined {
|
|
382
|
+
contentType = contentType.toLocaleLowerCase();
|
|
383
|
+
// const child = QueryIterator.first(this.descendent, (x) => x.contentType.type === contentType);
|
|
384
|
+
// The QueryIterator.first is not available, so we'll implement it manually:
|
|
385
|
+
let child: MimeNode | undefined;
|
|
386
|
+
for (const node of this.descendent) {
|
|
387
|
+
if (node.contentType.type === contentType) {
|
|
388
|
+
child = node;
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (!child && create) {
|
|
394
|
+
child = new MimeNode(contentType);
|
|
395
|
+
(this.children ??= []).push(child);
|
|
396
|
+
}
|
|
397
|
+
return child;
|
|
398
|
+
}
|
|
457
399
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
const toBuffer = (
|
|
2
|
-
/** @type {string} */ text
|
|
3
|
-
) => {
|
|
1
|
+
const toBuffer = (text: string): ArrayBuffer => {
|
|
4
2
|
const bytes = new Uint8Array(text.length);
|
|
5
3
|
for (let index = 0; index < text.length; index++) {
|
|
6
4
|
bytes[index] = text.charCodeAt(index);
|
|
@@ -9,10 +7,10 @@ const toBuffer = (
|
|
|
9
7
|
};
|
|
10
8
|
|
|
11
9
|
export const RawBuffer = {
|
|
12
|
-
decode
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
)
|
|
10
|
+
decode(
|
|
11
|
+
bytesAsString: string,
|
|
12
|
+
encoding: string = "utf-8"
|
|
13
|
+
): string {
|
|
16
14
|
if (!encoding) {
|
|
17
15
|
return bytesAsString;
|
|
18
16
|
}
|
|
@@ -20,16 +18,16 @@ export const RawBuffer = {
|
|
|
20
18
|
return te.decode(toBuffer(bytesAsString));
|
|
21
19
|
},
|
|
22
20
|
|
|
23
|
-
encode
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
)
|
|
27
|
-
if (
|
|
21
|
+
encode(
|
|
22
|
+
text: string,
|
|
23
|
+
encoding: string = "utf-8"
|
|
24
|
+
): string {
|
|
25
|
+
if (!/utf\-?8/i.test(encoding)) {
|
|
28
26
|
throw new Error(`Encoding ${encoding} not supported`);
|
|
29
27
|
}
|
|
30
28
|
const te = new TextEncoder();
|
|
31
29
|
const array = te.encode(text);
|
|
32
|
-
const a = [];
|
|
30
|
+
const a: string[] = [];
|
|
33
31
|
for (const iterator of array) {
|
|
34
32
|
a.push(String.fromCharCode(iterator));
|
|
35
33
|
}
|
|
@@ -37,16 +35,16 @@ export const RawBuffer = {
|
|
|
37
35
|
},
|
|
38
36
|
|
|
39
37
|
toBase64Async(
|
|
40
|
-
|
|
41
|
-
asDataUrl = false
|
|
42
|
-
) {
|
|
38
|
+
blob: Blob,
|
|
39
|
+
asDataUrl: boolean = false
|
|
40
|
+
): Promise<string> {
|
|
43
41
|
return new Promise<string>((resolve, reject) => {
|
|
44
42
|
const reader = new FileReader();
|
|
45
43
|
reader.onerror = () => {
|
|
46
44
|
reject(reader.error);
|
|
47
45
|
};
|
|
48
46
|
reader.onload = () => {
|
|
49
|
-
|
|
47
|
+
const text: string = reader.result as string;
|
|
50
48
|
if (asDataUrl) {
|
|
51
49
|
resolve(text);
|
|
52
50
|
return;
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* @param {string} base64Data
|
|
4
|
-
* @param {string} contentType
|
|
5
|
-
* @returns
|
|
2
|
+
* Converts a base64 string to a Blob
|
|
3
|
+
* @param {string} base64Data - The base64 encoded data
|
|
4
|
+
* @param {string} contentType - The content type of the blob
|
|
5
|
+
* @returns {Blob} - The resulting Blob object
|
|
6
6
|
*/
|
|
7
|
-
export function base64toBlob(base64Data, contentType) {
|
|
7
|
+
export function base64toBlob(base64Data: string, contentType: string): Blob {
|
|
8
8
|
contentType = contentType || '';
|
|
9
9
|
const sliceSize = 1024;
|
|
10
10
|
const byteCharacters = atob(base64Data);
|
|
11
11
|
const bytesLength = byteCharacters.length;
|
|
12
12
|
const slicesCount = Math.ceil(bytesLength / sliceSize);
|
|
13
|
-
const byteArrays = new Array(slicesCount);
|
|
13
|
+
const byteArrays: Uint8Array[] = new Array(slicesCount);
|
|
14
14
|
|
|
15
15
|
for (let sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
|
|
16
16
|
const begin = sliceIndex * sliceSize;
|
|
17
17
|
const end = Math.min(begin + sliceSize, bytesLength);
|
|
18
18
|
|
|
19
|
-
const bytes = new Array(end - begin);
|
|
19
|
+
const bytes: number[] = new Array(end - begin);
|
|
20
20
|
for (let offset = begin, i = 0; offset < end; ++i, ++offset) {
|
|
21
21
|
bytes[i] = byteCharacters[offset].charCodeAt(0);
|
|
22
22
|
}
|
|
23
23
|
byteArrays[sliceIndex] = new Uint8Array(bytes);
|
|
24
24
|
}
|
|
25
|
-
return new Blob(byteArrays, { type: contentType });
|
|
25
|
+
return new Blob(byteArrays as any, { type: contentType });
|
|
26
26
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Original Source Code: https://github.com/mathiasbynens/quoted-printable/blob/master/quoted-printable.js
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
const stringFromCharCode = String.fromCharCode;
|
|
5
|
-
|
|
4
|
+
|
|
5
|
+
const decode = function(input: string): string {
|
|
6
6
|
return input
|
|
7
7
|
// https://tools.ietf.org/html/rfc2045#section-6.7, rule 3:
|
|
8
8
|
// “Therefore, when decoding a `Quoted-Printable` body, any trailing white
|
|
@@ -17,26 +17,23 @@ const decode = function(input) {
|
|
|
17
17
|
// combination of two hexidecimal digits. For optimal compatibility,
|
|
18
18
|
// lowercase hexadecimal digits are supported as well. See
|
|
19
19
|
// https://tools.ietf.org/html/rfc2045#section-6.7, note 1.
|
|
20
|
-
.replace(/=([a-fA-F0-9]{2})/g, function($0, $1) {
|
|
20
|
+
.replace(/=([a-fA-F0-9]{2})/g, function($0: string, $1: string): string {
|
|
21
21
|
const codePoint = parseInt($1, 16);
|
|
22
22
|
return stringFromCharCode(codePoint);
|
|
23
23
|
});
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
-
const handleTrailingCharacters =
|
|
27
|
-
function(
|
|
28
|
-
/** @type {string} */
|
|
29
|
-
text) {
|
|
26
|
+
const handleTrailingCharacters = function(text: string): string {
|
|
30
27
|
return text
|
|
31
28
|
.replace(/\x20$/, '=20') // Handle trailing space.
|
|
32
29
|
.replace(/\t$/, '=09'); // Handle trailing tab.
|
|
33
30
|
};
|
|
34
31
|
|
|
35
32
|
const regexUnsafeSymbols = /[\0-\x08\n-\x1F=\x7F-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
|
36
|
-
const encode = function(text) {
|
|
37
33
|
|
|
34
|
+
const encode = function(text: string): string {
|
|
38
35
|
// Encode symbols that are definitely unsafe (i.e. unsafe in any context).
|
|
39
|
-
const encoded = text.replace(regexUnsafeSymbols, function(symbol) {
|
|
36
|
+
const encoded = text.replace(regexUnsafeSymbols, function(symbol: string): string {
|
|
40
37
|
if (symbol > '\xFF') {
|
|
41
38
|
throw RangeError(
|
|
42
39
|
'`quotedPrintable.encode()` expects extended ASCII input only. ' +
|
|
@@ -55,8 +52,9 @@ const encode = function(text) {
|
|
|
55
52
|
const lines = encoded.split(/\r\n?|\n/g);
|
|
56
53
|
let lineIndex = -1;
|
|
57
54
|
const lineCount = lines.length;
|
|
58
|
-
const result = [];
|
|
59
|
-
let buffer;
|
|
55
|
+
const result: string[] = [];
|
|
56
|
+
let buffer: string;
|
|
57
|
+
|
|
60
58
|
while (++lineIndex < lineCount) {
|
|
61
59
|
const line = lines[lineIndex];
|
|
62
60
|
// Leave room for the trailing `=` for soft line breaks.
|
|
@@ -5,20 +5,20 @@ const isEncodedRegEx = /\=\?([^\?\s]+)\?([^\?\s]{1})\?([^\s\?]+)\?\=\s*/gm;
|
|
|
5
5
|
const hexToUnicode = /(\=([0-9a-f]{2}))|(\_)/gmi;
|
|
6
6
|
|
|
7
7
|
const decode = (
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return text.replace(isEncodedRegEx, (matched, encoding, format,
|
|
8
|
+
text: string
|
|
9
|
+
): string => {
|
|
10
|
+
return text.replace(isEncodedRegEx, (matched: string, encoding: string, format: string, buffer: string): string => {
|
|
11
11
|
if (/b/i.test(format)) {
|
|
12
12
|
return RawBuffer.decode(atob(buffer), encoding);
|
|
13
13
|
}
|
|
14
14
|
if (/q/i.test(format)) {
|
|
15
|
-
const replaced = buffer.replace(hexToUnicode, (m, group
|
|
15
|
+
const replaced = buffer.replace(hexToUnicode, (m: string, group: string, code: string): string => {
|
|
16
16
|
if (m === "_") {
|
|
17
17
|
return " ";
|
|
18
18
|
}
|
|
19
19
|
return String.fromCharCode(parseInt(code, 16));
|
|
20
20
|
});
|
|
21
|
-
return RawBuffer.decode(
|
|
21
|
+
return RawBuffer.decode(replaced, encoding);
|
|
22
22
|
}
|
|
23
23
|
return matched;
|
|
24
24
|
});
|
|
@@ -29,7 +29,7 @@ const isSimpleText = /[0-9a-zA-Z\x20]/;
|
|
|
29
29
|
export const wordEncoding = {
|
|
30
30
|
decode,
|
|
31
31
|
|
|
32
|
-
encode: (
|
|
32
|
+
encode: (word: string, ifNeeded: boolean = false): string => {
|
|
33
33
|
|
|
34
34
|
if(ifNeeded) {
|
|
35
35
|
if(isSimpleText.test(word)) {
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { tokenize, tokenizeMax } from "./tokenizer.js";
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
export const parsePairs = (
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
text: string,
|
|
5
|
+
emptyName?: string
|
|
6
|
+
): Record<string, string> & { toString(): string } => {
|
|
7
7
|
const pairs = {
|
|
8
8
|
toString() {
|
|
9
9
|
return text;
|
|
10
10
|
}
|
|
11
|
-
};
|
|
11
|
+
} as Record<string, string> & { toString(): string };
|
|
12
|
+
|
|
12
13
|
for (const iterator of tokenize(text, ";")) {
|
|
13
14
|
const trimmed = iterator.trim();
|
|
14
15
|
if (!trimmed) {
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { tokenize } from "../tokenizer.js";
|
|
2
2
|
|
|
3
3
|
export default class LineStream {
|
|
4
|
-
|
|
5
|
-
/** @type {AsyncGenerator<string, any, any>} */ g;
|
|
4
|
+
protected g?: AsyncGenerator<string, any, any>;
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* @returns {AsyncGenerator<string, any, any>}
|
|
9
8
|
*/
|
|
10
|
-
async *read() {
|
|
9
|
+
async *read(): AsyncGenerator<string, any, any> {
|
|
11
10
|
const g = this.g ??= this.lines();
|
|
12
11
|
for(;;) {
|
|
13
12
|
const { value , done } = await g.next();
|
|
@@ -21,8 +20,8 @@ export default class LineStream {
|
|
|
21
20
|
/**
|
|
22
21
|
* @returns {AsyncGenerator<string, any, any>}
|
|
23
22
|
*/
|
|
24
|
-
async *readRFCHeaders() {
|
|
25
|
-
let last;
|
|
23
|
+
async *readRFCHeaders(): AsyncGenerator<string, any, any> {
|
|
24
|
+
let last: string | undefined;
|
|
26
25
|
const g = this.g ??= this.lines();
|
|
27
26
|
for(;;) {
|
|
28
27
|
const { value , done } = await g.next();
|
|
@@ -30,7 +29,7 @@ export default class LineStream {
|
|
|
30
29
|
break;
|
|
31
30
|
}
|
|
32
31
|
if (/^\s+/i.test(value)) {
|
|
33
|
-
last
|
|
32
|
+
last = last + value.trimStart();
|
|
34
33
|
continue;
|
|
35
34
|
}
|
|
36
35
|
if (last) {
|
|
@@ -44,26 +43,22 @@ export default class LineStream {
|
|
|
44
43
|
}
|
|
45
44
|
|
|
46
45
|
/** @returns {AsyncGenerator<string, any,any>} */
|
|
47
|
-
lines() {
|
|
46
|
+
protected lines(): AsyncGenerator<string, any, any> {
|
|
48
47
|
throw new Error("Not Implemented");
|
|
49
48
|
}
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
export class StringLineStream extends LineStream {
|
|
53
52
|
|
|
54
|
-
/** @type {string} */ text;
|
|
55
|
-
|
|
56
53
|
constructor(
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
protected text: string,
|
|
55
|
+
protected trimR?: boolean
|
|
59
56
|
) {
|
|
60
57
|
super();
|
|
61
|
-
this.text = text;
|
|
62
|
-
this.trimR = trimR;
|
|
63
58
|
}
|
|
64
59
|
|
|
65
60
|
/** @returns {AsyncGenerator<string, any, any>} */
|
|
66
|
-
async *lines() {
|
|
61
|
+
async *lines(): AsyncGenerator<string, any, any> {
|
|
67
62
|
if (this.trimR) {
|
|
68
63
|
for (const iterator of tokenize(this.text, "\n")) {
|
|
69
64
|
yield iterator.replace(/\r*$/, "");
|
|
@@ -77,17 +72,15 @@ export class StringLineStream extends LineStream {
|
|
|
77
72
|
}
|
|
78
73
|
|
|
79
74
|
export class ReadableLineStream extends LineStream {
|
|
75
|
+
protected readable: ReadableStream;
|
|
80
76
|
|
|
81
|
-
|
|
82
|
-
readable;
|
|
83
|
-
|
|
84
|
-
constructor( /** @type {ReadableStream} */ readable) {
|
|
77
|
+
constructor(readable: ReadableStream) {
|
|
85
78
|
super();
|
|
86
79
|
this.readable = readable;
|
|
87
80
|
}
|
|
88
81
|
|
|
89
82
|
/** @returns {AsyncGenerator<string, any, any>} */
|
|
90
|
-
async *lines() {
|
|
83
|
+
async *lines(): AsyncGenerator<string, any, any> {
|
|
91
84
|
const utf8Decoder = new TextDecoder("utf-8");
|
|
92
85
|
const reader = this.readable.getReader();
|
|
93
86
|
let { value: chunk, done: readerDone } = await reader.read();
|