imapflow 1.7.8 → 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/CHANGELOG.md +20 -0
- package/README.md +8 -2
- package/dist/cjs/charsets.d.ts +1 -0
- package/dist/cjs/charsets.js +294 -0
- package/dist/cjs/commands/append.d.ts +22 -0
- package/dist/cjs/commands/append.js +151 -0
- package/dist/cjs/commands/authenticate.d.ts +24 -0
- package/dist/cjs/commands/authenticate.js +223 -0
- package/dist/cjs/commands/capability.d.ts +8 -0
- package/dist/cjs/commands/capability.js +32 -0
- package/dist/cjs/commands/close.d.ts +8 -0
- package/dist/cjs/commands/close.js +39 -0
- package/dist/cjs/commands/compress.d.ts +8 -0
- package/dist/cjs/commands/compress.js +56 -0
- package/dist/cjs/commands/copy.d.ts +13 -0
- package/dist/cjs/commands/copy.js +44 -0
- package/dist/cjs/commands/copyuid-parser.d.ts +11 -0
- package/dist/cjs/commands/copyuid-parser.js +32 -0
- package/dist/cjs/commands/create.d.ts +11 -0
- package/dist/cjs/commands/create.js +80 -0
- package/dist/cjs/commands/delete.d.ts +11 -0
- package/dist/cjs/commands/delete.js +40 -0
- package/dist/cjs/commands/enable.d.ts +9 -0
- package/dist/cjs/commands/enable.js +61 -0
- package/dist/cjs/commands/esearch-parser.d.ts +17 -0
- package/dist/cjs/commands/esearch-parser.js +91 -0
- package/dist/cjs/commands/expunge.d.ts +12 -0
- package/dist/cjs/commands/expunge.js +60 -0
- package/dist/cjs/commands/fetch.d.ts +30 -0
- package/dist/cjs/commands/fetch.js +241 -0
- package/dist/cjs/commands/id.d.ts +10 -0
- package/dist/cjs/commands/id.js +80 -0
- package/dist/cjs/commands/idle.d.ts +9 -0
- package/dist/cjs/commands/idle.js +347 -0
- package/dist/cjs/commands/list.d.ts +16 -0
- package/dist/cjs/commands/list.js +518 -0
- package/dist/cjs/commands/login.d.ts +11 -0
- package/dist/cjs/commands/login.js +42 -0
- package/dist/cjs/commands/logout.d.ts +8 -0
- package/dist/cjs/commands/logout.js +47 -0
- package/dist/cjs/commands/move.d.ts +13 -0
- package/dist/cjs/commands/move.js +57 -0
- package/dist/cjs/commands/namespace.d.ts +25 -0
- package/dist/cjs/commands/namespace.js +139 -0
- package/dist/cjs/commands/noop.d.ts +8 -0
- package/dist/cjs/commands/noop.js +22 -0
- package/dist/cjs/commands/quota.d.ts +10 -0
- package/dist/cjs/commands/quota.js +119 -0
- package/dist/cjs/commands/rename.d.ts +12 -0
- package/dist/cjs/commands/rename.js +48 -0
- package/dist/cjs/commands/search.d.ts +15 -0
- package/dist/cjs/commands/search.js +228 -0
- package/dist/cjs/commands/select.d.ts +25 -0
- package/dist/cjs/commands/select.js +250 -0
- package/dist/cjs/commands/starttls.d.ts +8 -0
- package/dist/cjs/commands/starttls.js +30 -0
- package/dist/cjs/commands/status-fields.d.ts +14 -0
- package/dist/cjs/commands/status-fields.js +61 -0
- package/dist/cjs/commands/status.d.ts +12 -0
- package/dist/cjs/commands/status.js +108 -0
- package/dist/cjs/commands/store.d.ts +19 -0
- package/dist/cjs/commands/store.js +93 -0
- package/dist/cjs/commands/subscribe.d.ts +9 -0
- package/dist/cjs/commands/subscribe.js +31 -0
- package/dist/cjs/commands/unsubscribe.d.ts +9 -0
- package/dist/cjs/commands/unsubscribe.js +31 -0
- package/dist/cjs/connection-deadline.d.ts +49 -0
- package/dist/cjs/connection-deadline.js +91 -0
- package/dist/cjs/errors.d.ts +83 -0
- package/dist/cjs/errors.js +13 -0
- package/dist/cjs/handler/imap-compiler.d.ts +24 -0
- package/dist/cjs/handler/imap-compiler.js +285 -0
- package/dist/cjs/handler/imap-formal-syntax.d.ts +28 -0
- package/dist/cjs/handler/imap-formal-syntax.js +121 -0
- package/dist/cjs/handler/imap-handler.d.ts +9 -0
- package/dist/cjs/handler/imap-handler.js +10 -0
- package/dist/cjs/handler/imap-parser.d.ts +16 -0
- package/dist/cjs/handler/imap-parser.js +90 -0
- package/dist/cjs/handler/imap-stream.d.ts +181 -0
- package/dist/cjs/handler/imap-stream.js +446 -0
- package/dist/cjs/handler/limits.d.ts +25 -0
- package/dist/cjs/handler/limits.js +51 -0
- package/dist/cjs/handler/parser-instance.d.ts +68 -0
- package/dist/cjs/handler/parser-instance.js +223 -0
- package/dist/cjs/handler/token-parser.d.ts +91 -0
- package/dist/cjs/handler/token-parser.js +673 -0
- package/dist/cjs/handler/types.d.ts +91 -0
- package/dist/cjs/handler/types.js +4 -0
- package/dist/cjs/imap-commands.d.ts +16 -0
- package/dist/cjs/imap-commands.js +74 -0
- package/dist/cjs/imap-flow.d.ts +676 -0
- package/dist/cjs/imap-flow.js +3949 -0
- package/dist/cjs/jp-decoder.d.ts +12 -0
- package/dist/cjs/jp-decoder.js +79 -0
- package/dist/cjs/limited-passthrough.d.ts +25 -0
- package/dist/cjs/limited-passthrough.js +54 -0
- package/dist/cjs/logger.d.ts +3 -0
- package/dist/cjs/logger.js +11 -0
- package/dist/cjs/package-info.d.ts +3 -0
- package/dist/cjs/package-info.js +7 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/proxy-connection.d.ts +33 -0
- package/dist/cjs/proxy-connection.js +392 -0
- package/dist/cjs/search-compiler.d.ts +34 -0
- package/dist/cjs/search-compiler.js +476 -0
- package/dist/cjs/special-use.d.ts +22 -0
- package/dist/cjs/special-use.js +911 -0
- package/dist/cjs/tools.d.ts +427 -0
- package/dist/cjs/tools.js +1496 -0
- package/{lib/imap-flow.d.ts → dist/cjs/types.d.ts} +386 -516
- package/dist/cjs/types.js +5 -0
- package/dist/esm/charsets.d.ts +1 -0
- package/{lib → dist/esm}/charsets.js +1 -6
- package/dist/esm/commands/append.d.ts +22 -0
- package/{lib → dist/esm}/commands/append.js +22 -52
- package/dist/esm/commands/authenticate.d.ts +24 -0
- package/{lib → dist/esm}/commands/authenticate.js +62 -87
- package/dist/esm/commands/capability.d.ts +8 -0
- package/{lib → dist/esm}/commands/capability.js +6 -9
- package/dist/esm/commands/close.d.ts +8 -0
- package/{lib → dist/esm}/commands/close.js +6 -10
- package/dist/esm/commands/compress.d.ts +8 -0
- package/{lib → dist/esm}/commands/compress.js +7 -11
- package/dist/esm/commands/copy.d.ts +13 -0
- package/{lib → dist/esm}/commands/copy.js +12 -20
- package/dist/esm/commands/copyuid-parser.d.ts +11 -0
- package/{lib → dist/esm}/commands/copyuid-parser.js +9 -15
- package/dist/esm/commands/create.d.ts +11 -0
- package/{lib → dist/esm}/commands/create.js +13 -27
- package/dist/esm/commands/delete.d.ts +11 -0
- package/{lib → dist/esm}/commands/delete.js +9 -14
- package/dist/esm/commands/enable.d.ts +9 -0
- package/{lib → dist/esm}/commands/enable.js +23 -30
- package/dist/esm/commands/esearch-parser.d.ts +17 -0
- package/dist/esm/commands/esearch-parser.js +88 -0
- package/dist/esm/commands/expunge.d.ts +12 -0
- package/{lib → dist/esm}/commands/expunge.js +17 -22
- package/dist/esm/commands/fetch.d.ts +30 -0
- package/{lib → dist/esm}/commands/fetch.js +32 -64
- package/dist/esm/commands/id.d.ts +10 -0
- package/{lib → dist/esm}/commands/id.js +17 -23
- package/dist/esm/commands/idle.d.ts +9 -0
- package/{lib → dist/esm}/commands/idle.js +47 -81
- package/dist/esm/commands/list.d.ts +16 -0
- package/{lib → dist/esm}/commands/list.js +56 -121
- package/dist/esm/commands/login.d.ts +11 -0
- package/{lib → dist/esm}/commands/login.js +10 -15
- package/dist/esm/commands/logout.d.ts +8 -0
- package/{lib → dist/esm}/commands/logout.js +9 -11
- package/dist/esm/commands/move.d.ts +13 -0
- package/{lib → dist/esm}/commands/move.js +13 -21
- package/dist/esm/commands/namespace.d.ts +25 -0
- package/{lib → dist/esm}/commands/namespace.js +34 -44
- package/dist/esm/commands/noop.d.ts +8 -0
- package/{lib → dist/esm}/commands/noop.js +6 -7
- package/dist/esm/commands/quota.d.ts +10 -0
- package/{lib → dist/esm}/commands/quota.js +18 -36
- package/dist/esm/commands/rename.d.ts +12 -0
- package/{lib → dist/esm}/commands/rename.js +10 -15
- package/dist/esm/commands/search.d.ts +15 -0
- package/{lib → dist/esm}/commands/search.js +36 -135
- package/dist/esm/commands/select.d.ts +25 -0
- package/{lib → dist/esm}/commands/select.js +33 -64
- package/dist/esm/commands/starttls.d.ts +8 -0
- package/{lib → dist/esm}/commands/starttls.js +6 -8
- package/dist/esm/commands/status-fields.d.ts +14 -0
- package/{lib → dist/esm}/commands/status-fields.js +5 -16
- package/dist/esm/commands/status.d.ts +12 -0
- package/{lib → dist/esm}/commands/status.js +18 -29
- package/dist/esm/commands/store.d.ts +19 -0
- package/{lib → dist/esm}/commands/store.js +24 -37
- package/dist/esm/commands/subscribe.d.ts +9 -0
- package/{lib → dist/esm}/commands/subscribe.js +8 -12
- package/dist/esm/commands/unsubscribe.d.ts +9 -0
- package/{lib → dist/esm}/commands/unsubscribe.js +8 -12
- package/dist/esm/connection-deadline.d.ts +49 -0
- package/{lib → dist/esm}/connection-deadline.js +14 -25
- package/dist/esm/errors.d.ts +83 -0
- package/dist/esm/errors.js +9 -0
- package/dist/esm/handler/imap-compiler.d.ts +24 -0
- package/{lib → dist/esm}/handler/imap-compiler.js +22 -80
- package/dist/esm/handler/imap-formal-syntax.d.ts +28 -0
- package/dist/esm/handler/imap-formal-syntax.js +117 -0
- package/dist/esm/handler/imap-handler.d.ts +9 -0
- package/dist/esm/handler/imap-handler.js +9 -0
- package/dist/esm/handler/imap-parser.d.ts +16 -0
- package/{lib → dist/esm}/handler/imap-parser.js +31 -44
- package/dist/esm/handler/imap-stream.d.ts +181 -0
- package/{lib → dist/esm}/handler/imap-stream.js +29 -121
- package/dist/esm/handler/limits.d.ts +25 -0
- package/{lib → dist/esm}/handler/limits.js +13 -22
- package/dist/esm/handler/parser-instance.d.ts +68 -0
- package/{lib → dist/esm}/handler/parser-instance.js +19 -47
- package/dist/esm/handler/token-parser.d.ts +91 -0
- package/{lib → dist/esm}/handler/token-parser.js +71 -155
- package/dist/esm/handler/types.d.ts +91 -0
- package/dist/esm/handler/types.js +3 -0
- package/dist/esm/imap-commands.d.ts +16 -0
- package/dist/esm/imap-commands.js +67 -0
- package/dist/esm/imap-flow.d.ts +676 -0
- package/{lib → dist/esm}/imap-flow.js +761 -1789
- package/dist/esm/jp-decoder.d.ts +12 -0
- package/{lib → dist/esm}/jp-decoder.js +6 -21
- package/dist/esm/limited-passthrough.d.ts +25 -0
- package/{lib → dist/esm}/limited-passthrough.js +7 -20
- package/dist/esm/logger.d.ts +3 -0
- package/dist/esm/logger.js +4 -0
- package/dist/esm/package-info.d.ts +3 -0
- package/dist/esm/package-info.js +4 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/proxy-connection.d.ts +33 -0
- package/{lib → dist/esm}/proxy-connection.js +56 -127
- package/dist/esm/search-compiler.d.ts +34 -0
- package/{lib → dist/esm}/search-compiler.js +54 -110
- package/dist/esm/special-use.d.ts +22 -0
- package/dist/esm/special-use.js +907 -0
- package/dist/esm/tools.d.ts +427 -0
- package/dist/esm/tools.js +1446 -0
- package/dist/esm/types.d.ts +828 -0
- package/dist/esm/types.js +4 -0
- package/package.json +60 -20
- package/.gitattributes +0 -1
- package/.github/CODE_OF_CONDUCT.md +0 -76
- package/.github/FUNDING.yml +0 -4
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
- package/.github/contributing.md +0 -17
- package/.github/workflows/release.yaml +0 -36
- package/.github/workflows/stale.yml +0 -29
- package/.github/workflows/test.yml +0 -51
- package/.ncurc.js +0 -4
- package/.prettierignore +0 -4
- package/.prettierrc.js +0 -8
- package/.release-please-manifest.json +0 -3
- package/CLAUDE.md +0 -104
- package/Gruntfile.js +0 -23
- package/eslint.config.js +0 -45
- package/lib/handler/imap-formal-syntax.js +0 -189
- package/lib/handler/imap-handler.js +0 -17
- package/lib/imap-commands.js +0 -45
- package/lib/logger.js +0 -5
- package/lib/special-use.js +0 -923
- package/lib/tools.js +0 -1612
- package/release-please-config.json +0 -10
- package/test/authentication-test.js +0 -101
- package/test/auto-idle-test.js +0 -470
- package/test/bodystructure-test.js +0 -899
- package/test/charsets-test.js +0 -161
- package/test/commands-branches-test.js +0 -1095
- package/test/commands-integration-test.js +0 -11124
- package/test/commands-test.js +0 -73
- package/test/connection-edge-cases-test.js +0 -1828
- package/test/connection-test.js +0 -162
- package/test/copyuid-parser-test.js +0 -173
- package/test/fetch-generator-test.js +0 -218
- package/test/fixtures/fake-timers.js +0 -115
- package/test/fixtures/serialized-mimetorture.js +0 -2738
- package/test/fixtures/test-client.js +0 -101
- package/test/fixtures/test-tls.js +0 -8
- package/test/handler-branches-test.js +0 -310
- package/test/idle-polling-test.js +0 -518
- package/test/imap-compiler-test.js +0 -809
- package/test/imap-flow-compress-test.js +0 -166
- package/test/imap-flow-coverage-test.js +0 -612
- package/test/imap-flow-fetch-download-test.js +0 -909
- package/test/imap-flow-internals-test.js +0 -725
- package/test/imap-flow-methods-test.js +0 -889
- package/test/imap-flow-proxy-paths-test.js +0 -366
- package/test/imap-flow-secure-test.js +0 -573
- package/test/imap-flow-server-test.js +0 -1474
- package/test/imap-formal-syntax-test.js +0 -293
- package/test/imap-parser-test.js +0 -1474
- package/test/imap-stream-edge-cases-test.js +0 -666
- package/test/imap-stream-test.js +0 -177
- package/test/imapflow-test.js +0 -258
- package/test/integration/README.md +0 -52
- package/test/integration/dovecot-test.conf +0 -27
- package/test/integration/rev2-live-test.js +0 -431
- package/test/integration/run-rev2-tests.sh +0 -75
- package/test/integration-test.js +0 -83
- package/test/jp-decoder-test.js +0 -304
- package/test/limited-passthrough-test.js +0 -299
- package/test/memory-cleanup-test.js +0 -144
- package/test/memory-leak-test.js +0 -667
- package/test/parser-limits-test.js +0 -292
- package/test/proxy-connection-test.js +0 -738
- package/test/reliability-improvements-test.js +0 -548
- package/test/search-compiler-test.js +0 -1300
- package/test/search-test.js +0 -329
- package/test/special-use-test.js +0 -418
- package/test/starttls-injection-test.js +0 -181
- package/test/tag-correlation-test.js +0 -333
- package/test/timer-policy-test.js +0 -227
- package/test/token-parser-test.js +0 -456
- package/test/tools-test.js +0 -2013
- package/test/unhandled-rejection-test.js +0 -661
|
@@ -1,24 +1,19 @@
|
|
|
1
1
|
/* eslint new-cap: 0 */
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const imapFormalSyntax = require('./imap-formal-syntax');
|
|
6
|
-
|
|
7
|
-
const { TokenParser } = require('./token-parser');
|
|
8
|
-
|
|
2
|
+
import imapFormalSyntax from './imap-formal-syntax.js';
|
|
3
|
+
import { TokenParser } from './token-parser.js';
|
|
9
4
|
/**
|
|
10
5
|
* Parses a single IMAP response line into its structural components: tag, command,
|
|
11
6
|
* and attributes. Handles status responses (OK, NO, BAD, PREAUTH, BYE) with their
|
|
12
7
|
* human-readable text and response codes, as well as continuation responses ("+").
|
|
13
8
|
*/
|
|
14
|
-
class ParserInstance {
|
|
9
|
+
export class ParserInstance {
|
|
15
10
|
/**
|
|
16
11
|
* Creates a new ParserInstance for parsing an IMAP response line.
|
|
17
12
|
*
|
|
18
|
-
* @param
|
|
19
|
-
* @param
|
|
20
|
-
* @param
|
|
21
|
-
* @param
|
|
13
|
+
* @param input - The raw IMAP response line to parse.
|
|
14
|
+
* @param options - Parser options passed through to the TokenParser for attribute parsing.
|
|
15
|
+
* @param options.literalPlus - Whether the LITERAL+ extension is in use.
|
|
16
|
+
* @param options.literals - Pre-parsed literal values from the stream.
|
|
22
17
|
*/
|
|
23
18
|
constructor(input, options) {
|
|
24
19
|
this.input = (input || '').toString();
|
|
@@ -26,29 +21,27 @@ class ParserInstance {
|
|
|
26
21
|
this.remainder = this.input;
|
|
27
22
|
this.pos = 0;
|
|
28
23
|
}
|
|
29
|
-
|
|
30
24
|
/**
|
|
31
25
|
* Extracts and returns the IMAP tag from the beginning of the response.
|
|
32
26
|
* The tag is typically "*" for untagged responses, "+" for continuation requests,
|
|
33
27
|
* or a client-assigned command tag like "A1".
|
|
34
28
|
*
|
|
35
|
-
* @returns
|
|
29
|
+
* @returns The parsed tag string.
|
|
36
30
|
* @throws {Error} If the tag contains invalid characters.
|
|
37
31
|
*/
|
|
38
32
|
async getTag() {
|
|
39
33
|
if (!this.tag) {
|
|
40
|
-
this.tag = await this.getElement(imapFormalSyntax.tag() + '*+'
|
|
34
|
+
this.tag = await this.getElement(imapFormalSyntax.tag() + '*+');
|
|
41
35
|
}
|
|
42
36
|
return this.tag;
|
|
43
37
|
}
|
|
44
|
-
|
|
45
38
|
/**
|
|
46
39
|
* Extracts and returns the IMAP command or response name from the input.
|
|
47
40
|
* For continuation responses (tag "+"), returns an empty string and stores
|
|
48
41
|
* the remainder as human-readable text. For status responses (OK, NO, BAD,
|
|
49
42
|
* PREAUTH, BYE), separates the optional response code from the human-readable text.
|
|
50
43
|
*
|
|
51
|
-
* @returns
|
|
44
|
+
* @returns The parsed command string.
|
|
52
45
|
* @throws {Error} If the command contains invalid characters or input ends unexpectedly.
|
|
53
46
|
*/
|
|
54
47
|
async getCommand() {
|
|
@@ -56,14 +49,11 @@ class ParserInstance {
|
|
|
56
49
|
// special case
|
|
57
50
|
this.humanReadable = this.remainder.trim();
|
|
58
51
|
this.remainder = '';
|
|
59
|
-
|
|
60
52
|
return '';
|
|
61
53
|
}
|
|
62
|
-
|
|
63
54
|
if (!this.command) {
|
|
64
55
|
this.command = await this.getElement(imapFormalSyntax.command());
|
|
65
56
|
}
|
|
66
|
-
|
|
67
57
|
// Status responses have the format: TAG OK/NO/BAD [response-code] human-readable text
|
|
68
58
|
// Example: * OK [CAPABILITY IMAP4rev1] Server ready
|
|
69
59
|
// Example: A1 NO [AUTHENTICATIONFAILED] Invalid credentials
|
|
@@ -85,10 +75,10 @@ class ParserInstance {
|
|
|
85
75
|
let end = -1;
|
|
86
76
|
for (let i = match[0].length; i < this.remainder.length; i++) {
|
|
87
77
|
let c = this.remainder[i];
|
|
88
|
-
|
|
89
78
|
if (c === '[') {
|
|
90
79
|
nesting++;
|
|
91
|
-
}
|
|
80
|
+
}
|
|
81
|
+
else if (c === ']') {
|
|
92
82
|
nesting--;
|
|
93
83
|
}
|
|
94
84
|
if (!nesting) {
|
|
@@ -96,7 +86,6 @@ class ParserInstance {
|
|
|
96
86
|
break;
|
|
97
87
|
}
|
|
98
88
|
}
|
|
99
|
-
|
|
100
89
|
// Unbalanced '[' inside the code: the RFC 9051 free-text form
|
|
101
90
|
// (`atom [SP 1*<any TEXT-CHAR except "]">]`) permits '[' but not
|
|
102
91
|
// ']', so the code really does end at the first ']' here. Without
|
|
@@ -106,40 +95,36 @@ class ParserInstance {
|
|
|
106
95
|
if (end < 0) {
|
|
107
96
|
end = this.remainder.indexOf(']', match[0].length);
|
|
108
97
|
}
|
|
109
|
-
|
|
110
98
|
if (end >= 0) {
|
|
111
99
|
this.humanReadable = this.remainder.substring(end + 1).trim();
|
|
112
100
|
this.remainder = this.remainder.substring(0, end + 1);
|
|
113
101
|
}
|
|
114
|
-
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
115
104
|
this.humanReadable = this.remainder.trim();
|
|
116
105
|
this.remainder = '';
|
|
117
106
|
}
|
|
118
107
|
}
|
|
119
108
|
break;
|
|
120
109
|
}
|
|
121
|
-
|
|
122
110
|
return this.command;
|
|
123
111
|
}
|
|
124
|
-
|
|
125
112
|
/**
|
|
126
113
|
* Extracts the next whitespace-delimited element from the input and validates it
|
|
127
114
|
* against the given syntax character set. Advances the parser position past the element.
|
|
128
115
|
*
|
|
129
|
-
* @param
|
|
130
|
-
* @returns
|
|
116
|
+
* @param syntax - A string of allowed characters for the element (as returned by imap-formal-syntax methods).
|
|
117
|
+
* @returns The extracted element string.
|
|
131
118
|
* @throws {Error} If the element contains characters not in the syntax set, or if input ends unexpectedly.
|
|
132
119
|
*/
|
|
133
120
|
async getElement(syntax) {
|
|
134
121
|
let match, element, errPos;
|
|
135
|
-
|
|
136
122
|
if (/^\s/.test(this.remainder)) {
|
|
137
123
|
let error = new Error(`Unexpected whitespace at position ${this.pos} [E1]`);
|
|
138
124
|
error.code = 'ParserError1';
|
|
139
125
|
error.parserContext = { input: this.input, pos: this.pos };
|
|
140
126
|
throw error;
|
|
141
127
|
}
|
|
142
|
-
|
|
143
128
|
if ((match = this.remainder.match(/^\s*[^\s]+(?=\s|$)/))) {
|
|
144
129
|
element = match[0];
|
|
145
130
|
if ((errPos = imapFormalSyntax.verify(element, syntax)) >= 0) {
|
|
@@ -162,30 +147,26 @@ class ParserInstance {
|
|
|
162
147
|
};
|
|
163
148
|
throw error;
|
|
164
149
|
}
|
|
165
|
-
|
|
166
150
|
let error = new Error(`Unexpected char at position ${this.pos + errPos} [E2: ${JSON.stringify(element.charAt(errPos))}]`);
|
|
167
151
|
error.code = 'ParserError2';
|
|
168
152
|
error.parserContext = { input: this.input, element, pos: this.pos };
|
|
169
153
|
throw error;
|
|
170
154
|
}
|
|
171
|
-
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
172
157
|
let error = new Error(`Unexpected end of input at position ${this.pos} [E3]`);
|
|
173
158
|
error.code = 'ParserError3';
|
|
174
159
|
error.parserContext = { input: this.input, pos: this.pos };
|
|
175
160
|
throw error;
|
|
176
161
|
}
|
|
177
|
-
|
|
178
162
|
this.pos += match[0].length;
|
|
179
163
|
this.remainder = this.remainder.substr(match[0].length);
|
|
180
|
-
|
|
181
164
|
return element;
|
|
182
165
|
}
|
|
183
|
-
|
|
184
166
|
/**
|
|
185
167
|
* Consumes a single space character from the current position in the input.
|
|
186
168
|
* Advances the parser position by one.
|
|
187
169
|
*
|
|
188
|
-
* @returns {Promise<void>}
|
|
189
170
|
* @throws {Error} If the current character is not a space, or if input has ended unexpectedly.
|
|
190
171
|
*/
|
|
191
172
|
async getSpace() {
|
|
@@ -194,30 +175,26 @@ class ParserInstance {
|
|
|
194
175
|
// special case, empty + response
|
|
195
176
|
return;
|
|
196
177
|
}
|
|
197
|
-
|
|
198
178
|
let error = new Error(`Unexpected end of input at position ${this.pos} [E4]`);
|
|
199
179
|
error.code = 'ParserError4';
|
|
200
180
|
error.parserContext = { input: this.input, pos: this.pos };
|
|
201
181
|
throw error;
|
|
202
182
|
}
|
|
203
|
-
|
|
204
183
|
if (imapFormalSyntax.verify(this.remainder.charAt(0), imapFormalSyntax.SP()) >= 0) {
|
|
205
184
|
let error = new Error(`Unexpected char at position ${this.pos} [E5: ${JSON.stringify(this.remainder.charAt(0))}]`);
|
|
206
185
|
error.code = 'ParserError5';
|
|
207
186
|
error.parserContext = { input: this.input, element: this.remainder, pos: this.pos };
|
|
208
187
|
throw error;
|
|
209
188
|
}
|
|
210
|
-
|
|
211
189
|
this.pos++;
|
|
212
190
|
this.remainder = this.remainder.substr(1);
|
|
213
191
|
}
|
|
214
|
-
|
|
215
192
|
/**
|
|
216
193
|
* Parses the remaining input as IMAP attributes using the TokenParser.
|
|
217
194
|
* This handles complex structures including nested lists, literals, strings,
|
|
218
195
|
* atoms, sections, sequences, and partial ranges.
|
|
219
196
|
*
|
|
220
|
-
* @returns
|
|
197
|
+
* @returns A promise that resolves to an array of parsed attribute objects.
|
|
221
198
|
* @throws {Error} If the input contains unexpected whitespace, invalid characters, or ends unexpectedly.
|
|
222
199
|
*/
|
|
223
200
|
async getAttributes() {
|
|
@@ -227,18 +204,13 @@ class ParserInstance {
|
|
|
227
204
|
error.parserContext = { input: this.input, pos: this.pos };
|
|
228
205
|
throw error;
|
|
229
206
|
}
|
|
230
|
-
|
|
231
207
|
if (/^\s/.test(this.remainder)) {
|
|
232
208
|
let error = new Error(`Unexpected whitespace at position ${this.pos} [E7]`);
|
|
233
209
|
error.code = 'ParserError7';
|
|
234
210
|
error.parserContext = { input: this.input, element: this.remainder, pos: this.pos };
|
|
235
211
|
throw error;
|
|
236
212
|
}
|
|
237
|
-
|
|
238
213
|
const tokenParser = new TokenParser(this, this.pos, this.remainder, this.options);
|
|
239
|
-
|
|
240
214
|
return await tokenParser.getAttributes();
|
|
241
215
|
}
|
|
242
216
|
}
|
|
243
|
-
|
|
244
|
-
module.exports.ParserInstance = ParserInstance;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { ImapAttributeList, ParserOptions } from './types.js';
|
|
2
|
+
import type { ParserInstance } from './parser-instance.js';
|
|
3
|
+
/**
|
|
4
|
+
* A node of the parse tree built by TokenParser. `type` is false for a node that has not
|
|
5
|
+
* been classified yet, 'TREE' for the root, and otherwise the token or structure type
|
|
6
|
+
* (ATOM, string, LITERAL, SEQUENCE, LIST, SECTION, PARTIAL).
|
|
7
|
+
*/
|
|
8
|
+
export interface TokenNode {
|
|
9
|
+
childNodes: TokenNode[];
|
|
10
|
+
type: string | false;
|
|
11
|
+
value: string | Buffer;
|
|
12
|
+
isClosed: boolean;
|
|
13
|
+
parentNode?: TokenNode | undefined;
|
|
14
|
+
depth: number;
|
|
15
|
+
startPos?: number | undefined;
|
|
16
|
+
endPos?: number | undefined;
|
|
17
|
+
literalType?: string | undefined;
|
|
18
|
+
/** Digits accumulated as a string while the literal marker is read, converted to a number once the marker closes */
|
|
19
|
+
literalLength?: string | number | undefined;
|
|
20
|
+
literalPlus?: boolean | undefined;
|
|
21
|
+
started?: boolean | undefined;
|
|
22
|
+
chBuffer?: Buffer | undefined;
|
|
23
|
+
chPos?: number | undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The parent object a TokenParser reads the parsed command from
|
|
27
|
+
*/
|
|
28
|
+
export interface TokenParserParent {
|
|
29
|
+
command?: string | undefined;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Tokenizes an IMAP attribute string into a tree of typed nodes.
|
|
33
|
+
* Handles all IMAP data types: atoms, quoted strings, literals (including literal8),
|
|
34
|
+
* sequences, lists (parenthesized groups), sections (bracketed groups), and partial ranges.
|
|
35
|
+
* Enforces a maximum nesting depth of {@link MAX_NODE_DEPTH} to prevent stack overflow
|
|
36
|
+
* from malicious input.
|
|
37
|
+
*/
|
|
38
|
+
export declare class TokenParser {
|
|
39
|
+
str: string;
|
|
40
|
+
options: ParserOptions;
|
|
41
|
+
parent: TokenParserParent | ParserInstance;
|
|
42
|
+
maxLiteralSize: number;
|
|
43
|
+
tree: TokenNode;
|
|
44
|
+
currentNode: TokenNode;
|
|
45
|
+
pos: number;
|
|
46
|
+
state: number;
|
|
47
|
+
expectedLiteralType?: string | false | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Creates a new TokenParser.
|
|
50
|
+
*
|
|
51
|
+
* @param parent - The parent ParserInstance that owns this token parser. Used to access the parsed command for context-sensitive parsing.
|
|
52
|
+
* @param startPos - The starting position offset in the original input, used for error reporting.
|
|
53
|
+
* @param str - The attribute string to tokenize.
|
|
54
|
+
* @param options - Parser options.
|
|
55
|
+
* @param options.literalPlus - Whether the LITERAL+ extension is in use.
|
|
56
|
+
* @param options.literals - Pre-parsed literal values from the input stream.
|
|
57
|
+
* @param options.maxLiteralSize - Maximum size (in bytes) of a literal parsed inline
|
|
58
|
+
* from the input, i.e. when no pre-parsed literal buffers were supplied. Defaults to 1GB.
|
|
59
|
+
*/
|
|
60
|
+
constructor(parent: TokenParserParent | ParserInstance, startPos?: number | undefined, str?: string | null | undefined, options?: ParserOptions | undefined);
|
|
61
|
+
/**
|
|
62
|
+
* Processes the input string and returns the parsed attributes as a flat array of typed objects.
|
|
63
|
+
* Each attribute is an object with a `type` (e.g., "ATOM", "STRING", "LITERAL", "SEQUENCE")
|
|
64
|
+
* and a `value` property. Lists are represented as nested arrays. Sections and partials are
|
|
65
|
+
* attached as properties on the preceding attribute object.
|
|
66
|
+
*
|
|
67
|
+
* @returns A promise that resolves to an array of parsed attribute objects and nested arrays.
|
|
68
|
+
* @throws {Error} If the input contains syntax errors or unclosed nodes.
|
|
69
|
+
*/
|
|
70
|
+
getAttributes(): Promise<ImapAttributeList>;
|
|
71
|
+
/**
|
|
72
|
+
* Creates a new node in the parse tree. Each node represents a token or structural
|
|
73
|
+
* element (e.g., atom, string, literal, list, section, partial). The node is automatically
|
|
74
|
+
* appended to the parent's childNodes array if a parent is provided.
|
|
75
|
+
*
|
|
76
|
+
* @param parentNode - The parent node to attach this node to. If omitted, creates a root node.
|
|
77
|
+
* @param startPos - The starting position of this node in the original input string.
|
|
78
|
+
* @returns The newly created node with childNodes, type, value, and isClosed properties.
|
|
79
|
+
* @throws {Error} If the nesting depth exceeds MAX_NODE_DEPTH.
|
|
80
|
+
*/
|
|
81
|
+
createNode(parentNode?: TokenNode | undefined, startPos?: number | undefined): TokenNode;
|
|
82
|
+
/**
|
|
83
|
+
* Processes the entire input string character by character using a state machine.
|
|
84
|
+
* Transitions between states (NORMAL, ATOM, STRING, LITERAL, SEQUENCE, PARTIAL, TEXT)
|
|
85
|
+
* based on the current character and builds the parse tree. This is the main parsing
|
|
86
|
+
* loop that drives the tokenization.
|
|
87
|
+
*
|
|
88
|
+
* @throws {Error} If the input contains unexpected characters, unclosed structures, or other syntax errors.
|
|
89
|
+
*/
|
|
90
|
+
processString(): Promise<void>;
|
|
91
|
+
}
|