imapflow 1.7.7 → 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.
Files changed (296) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +8 -2
  3. package/dist/cjs/charsets.d.ts +1 -0
  4. package/dist/cjs/charsets.js +294 -0
  5. package/dist/cjs/commands/append.d.ts +22 -0
  6. package/dist/cjs/commands/append.js +151 -0
  7. package/dist/cjs/commands/authenticate.d.ts +24 -0
  8. package/dist/cjs/commands/authenticate.js +223 -0
  9. package/dist/cjs/commands/capability.d.ts +8 -0
  10. package/dist/cjs/commands/capability.js +32 -0
  11. package/dist/cjs/commands/close.d.ts +8 -0
  12. package/dist/cjs/commands/close.js +39 -0
  13. package/dist/cjs/commands/compress.d.ts +8 -0
  14. package/dist/cjs/commands/compress.js +56 -0
  15. package/dist/cjs/commands/copy.d.ts +13 -0
  16. package/dist/cjs/commands/copy.js +44 -0
  17. package/dist/cjs/commands/copyuid-parser.d.ts +11 -0
  18. package/dist/cjs/commands/copyuid-parser.js +32 -0
  19. package/dist/cjs/commands/create.d.ts +11 -0
  20. package/dist/cjs/commands/create.js +80 -0
  21. package/dist/cjs/commands/delete.d.ts +11 -0
  22. package/dist/cjs/commands/delete.js +40 -0
  23. package/dist/cjs/commands/enable.d.ts +9 -0
  24. package/dist/cjs/commands/enable.js +61 -0
  25. package/dist/cjs/commands/esearch-parser.d.ts +17 -0
  26. package/dist/cjs/commands/esearch-parser.js +91 -0
  27. package/dist/cjs/commands/expunge.d.ts +12 -0
  28. package/dist/cjs/commands/expunge.js +60 -0
  29. package/dist/cjs/commands/fetch.d.ts +30 -0
  30. package/dist/cjs/commands/fetch.js +241 -0
  31. package/dist/cjs/commands/id.d.ts +10 -0
  32. package/dist/cjs/commands/id.js +80 -0
  33. package/dist/cjs/commands/idle.d.ts +9 -0
  34. package/dist/cjs/commands/idle.js +347 -0
  35. package/dist/cjs/commands/list.d.ts +16 -0
  36. package/dist/cjs/commands/list.js +518 -0
  37. package/dist/cjs/commands/login.d.ts +11 -0
  38. package/dist/cjs/commands/login.js +42 -0
  39. package/dist/cjs/commands/logout.d.ts +8 -0
  40. package/dist/cjs/commands/logout.js +47 -0
  41. package/dist/cjs/commands/move.d.ts +13 -0
  42. package/dist/cjs/commands/move.js +57 -0
  43. package/dist/cjs/commands/namespace.d.ts +25 -0
  44. package/dist/cjs/commands/namespace.js +139 -0
  45. package/dist/cjs/commands/noop.d.ts +8 -0
  46. package/dist/cjs/commands/noop.js +22 -0
  47. package/dist/cjs/commands/quota.d.ts +10 -0
  48. package/dist/cjs/commands/quota.js +119 -0
  49. package/dist/cjs/commands/rename.d.ts +12 -0
  50. package/dist/cjs/commands/rename.js +48 -0
  51. package/dist/cjs/commands/search.d.ts +15 -0
  52. package/dist/cjs/commands/search.js +228 -0
  53. package/dist/cjs/commands/select.d.ts +25 -0
  54. package/dist/cjs/commands/select.js +250 -0
  55. package/dist/cjs/commands/starttls.d.ts +8 -0
  56. package/dist/cjs/commands/starttls.js +30 -0
  57. package/dist/cjs/commands/status-fields.d.ts +14 -0
  58. package/dist/cjs/commands/status-fields.js +61 -0
  59. package/dist/cjs/commands/status.d.ts +12 -0
  60. package/dist/cjs/commands/status.js +108 -0
  61. package/dist/cjs/commands/store.d.ts +19 -0
  62. package/dist/cjs/commands/store.js +93 -0
  63. package/dist/cjs/commands/subscribe.d.ts +9 -0
  64. package/dist/cjs/commands/subscribe.js +31 -0
  65. package/dist/cjs/commands/unsubscribe.d.ts +9 -0
  66. package/dist/cjs/commands/unsubscribe.js +31 -0
  67. package/dist/cjs/connection-deadline.d.ts +49 -0
  68. package/dist/cjs/connection-deadline.js +91 -0
  69. package/dist/cjs/errors.d.ts +83 -0
  70. package/dist/cjs/errors.js +13 -0
  71. package/dist/cjs/handler/imap-compiler.d.ts +24 -0
  72. package/dist/cjs/handler/imap-compiler.js +285 -0
  73. package/dist/cjs/handler/imap-formal-syntax.d.ts +28 -0
  74. package/dist/cjs/handler/imap-formal-syntax.js +121 -0
  75. package/dist/cjs/handler/imap-handler.d.ts +9 -0
  76. package/dist/cjs/handler/imap-handler.js +10 -0
  77. package/dist/cjs/handler/imap-parser.d.ts +16 -0
  78. package/dist/cjs/handler/imap-parser.js +90 -0
  79. package/dist/cjs/handler/imap-stream.d.ts +181 -0
  80. package/dist/cjs/handler/imap-stream.js +446 -0
  81. package/dist/cjs/handler/limits.d.ts +25 -0
  82. package/dist/cjs/handler/limits.js +51 -0
  83. package/dist/cjs/handler/parser-instance.d.ts +68 -0
  84. package/dist/cjs/handler/parser-instance.js +223 -0
  85. package/dist/cjs/handler/token-parser.d.ts +91 -0
  86. package/dist/cjs/handler/token-parser.js +673 -0
  87. package/dist/cjs/handler/types.d.ts +91 -0
  88. package/dist/cjs/handler/types.js +4 -0
  89. package/dist/cjs/imap-commands.d.ts +16 -0
  90. package/dist/cjs/imap-commands.js +74 -0
  91. package/dist/cjs/imap-flow.d.ts +676 -0
  92. package/dist/cjs/imap-flow.js +3949 -0
  93. package/dist/cjs/jp-decoder.d.ts +12 -0
  94. package/dist/cjs/jp-decoder.js +79 -0
  95. package/dist/cjs/limited-passthrough.d.ts +25 -0
  96. package/dist/cjs/limited-passthrough.js +54 -0
  97. package/dist/cjs/logger.d.ts +3 -0
  98. package/dist/cjs/logger.js +11 -0
  99. package/dist/cjs/package-info.d.ts +3 -0
  100. package/dist/cjs/package-info.js +7 -0
  101. package/dist/cjs/package.json +3 -0
  102. package/dist/cjs/proxy-connection.d.ts +33 -0
  103. package/dist/cjs/proxy-connection.js +392 -0
  104. package/dist/cjs/search-compiler.d.ts +34 -0
  105. package/dist/cjs/search-compiler.js +476 -0
  106. package/dist/cjs/special-use.d.ts +22 -0
  107. package/dist/cjs/special-use.js +911 -0
  108. package/dist/cjs/tools.d.ts +427 -0
  109. package/dist/cjs/tools.js +1496 -0
  110. package/{lib/imap-flow.d.ts → dist/cjs/types.d.ts} +386 -516
  111. package/dist/cjs/types.js +5 -0
  112. package/dist/esm/charsets.d.ts +1 -0
  113. package/{lib → dist/esm}/charsets.js +1 -6
  114. package/dist/esm/commands/append.d.ts +22 -0
  115. package/{lib → dist/esm}/commands/append.js +22 -52
  116. package/dist/esm/commands/authenticate.d.ts +24 -0
  117. package/{lib → dist/esm}/commands/authenticate.js +62 -87
  118. package/dist/esm/commands/capability.d.ts +8 -0
  119. package/{lib → dist/esm}/commands/capability.js +6 -9
  120. package/dist/esm/commands/close.d.ts +8 -0
  121. package/{lib → dist/esm}/commands/close.js +6 -10
  122. package/dist/esm/commands/compress.d.ts +8 -0
  123. package/{lib → dist/esm}/commands/compress.js +7 -11
  124. package/dist/esm/commands/copy.d.ts +13 -0
  125. package/{lib → dist/esm}/commands/copy.js +12 -20
  126. package/dist/esm/commands/copyuid-parser.d.ts +11 -0
  127. package/{lib → dist/esm}/commands/copyuid-parser.js +9 -15
  128. package/dist/esm/commands/create.d.ts +11 -0
  129. package/{lib → dist/esm}/commands/create.js +13 -27
  130. package/dist/esm/commands/delete.d.ts +11 -0
  131. package/{lib → dist/esm}/commands/delete.js +9 -14
  132. package/dist/esm/commands/enable.d.ts +9 -0
  133. package/{lib → dist/esm}/commands/enable.js +23 -30
  134. package/dist/esm/commands/esearch-parser.d.ts +17 -0
  135. package/dist/esm/commands/esearch-parser.js +88 -0
  136. package/dist/esm/commands/expunge.d.ts +12 -0
  137. package/{lib → dist/esm}/commands/expunge.js +17 -22
  138. package/dist/esm/commands/fetch.d.ts +30 -0
  139. package/{lib → dist/esm}/commands/fetch.js +32 -64
  140. package/dist/esm/commands/id.d.ts +10 -0
  141. package/{lib → dist/esm}/commands/id.js +17 -23
  142. package/dist/esm/commands/idle.d.ts +9 -0
  143. package/{lib → dist/esm}/commands/idle.js +47 -81
  144. package/dist/esm/commands/list.d.ts +16 -0
  145. package/{lib → dist/esm}/commands/list.js +56 -121
  146. package/dist/esm/commands/login.d.ts +11 -0
  147. package/{lib → dist/esm}/commands/login.js +10 -15
  148. package/dist/esm/commands/logout.d.ts +8 -0
  149. package/{lib → dist/esm}/commands/logout.js +9 -11
  150. package/dist/esm/commands/move.d.ts +13 -0
  151. package/{lib → dist/esm}/commands/move.js +13 -21
  152. package/dist/esm/commands/namespace.d.ts +25 -0
  153. package/{lib → dist/esm}/commands/namespace.js +34 -44
  154. package/dist/esm/commands/noop.d.ts +8 -0
  155. package/{lib → dist/esm}/commands/noop.js +6 -7
  156. package/dist/esm/commands/quota.d.ts +10 -0
  157. package/{lib → dist/esm}/commands/quota.js +18 -36
  158. package/dist/esm/commands/rename.d.ts +12 -0
  159. package/{lib → dist/esm}/commands/rename.js +10 -15
  160. package/dist/esm/commands/search.d.ts +15 -0
  161. package/{lib → dist/esm}/commands/search.js +36 -135
  162. package/dist/esm/commands/select.d.ts +25 -0
  163. package/{lib → dist/esm}/commands/select.js +33 -64
  164. package/dist/esm/commands/starttls.d.ts +8 -0
  165. package/{lib → dist/esm}/commands/starttls.js +6 -8
  166. package/dist/esm/commands/status-fields.d.ts +14 -0
  167. package/{lib → dist/esm}/commands/status-fields.js +5 -16
  168. package/dist/esm/commands/status.d.ts +12 -0
  169. package/{lib → dist/esm}/commands/status.js +18 -29
  170. package/dist/esm/commands/store.d.ts +19 -0
  171. package/{lib → dist/esm}/commands/store.js +24 -37
  172. package/dist/esm/commands/subscribe.d.ts +9 -0
  173. package/{lib → dist/esm}/commands/subscribe.js +8 -12
  174. package/dist/esm/commands/unsubscribe.d.ts +9 -0
  175. package/{lib → dist/esm}/commands/unsubscribe.js +8 -12
  176. package/dist/esm/connection-deadline.d.ts +49 -0
  177. package/{lib → dist/esm}/connection-deadline.js +14 -25
  178. package/dist/esm/errors.d.ts +83 -0
  179. package/dist/esm/errors.js +9 -0
  180. package/dist/esm/handler/imap-compiler.d.ts +24 -0
  181. package/{lib → dist/esm}/handler/imap-compiler.js +22 -80
  182. package/dist/esm/handler/imap-formal-syntax.d.ts +28 -0
  183. package/dist/esm/handler/imap-formal-syntax.js +117 -0
  184. package/dist/esm/handler/imap-handler.d.ts +9 -0
  185. package/dist/esm/handler/imap-handler.js +9 -0
  186. package/dist/esm/handler/imap-parser.d.ts +16 -0
  187. package/{lib → dist/esm}/handler/imap-parser.js +31 -44
  188. package/dist/esm/handler/imap-stream.d.ts +181 -0
  189. package/{lib → dist/esm}/handler/imap-stream.js +29 -121
  190. package/dist/esm/handler/limits.d.ts +25 -0
  191. package/{lib → dist/esm}/handler/limits.js +13 -22
  192. package/dist/esm/handler/parser-instance.d.ts +68 -0
  193. package/{lib → dist/esm}/handler/parser-instance.js +19 -47
  194. package/dist/esm/handler/token-parser.d.ts +91 -0
  195. package/{lib → dist/esm}/handler/token-parser.js +71 -155
  196. package/dist/esm/handler/types.d.ts +91 -0
  197. package/dist/esm/handler/types.js +3 -0
  198. package/dist/esm/imap-commands.d.ts +16 -0
  199. package/dist/esm/imap-commands.js +67 -0
  200. package/dist/esm/imap-flow.d.ts +676 -0
  201. package/{lib → dist/esm}/imap-flow.js +785 -1802
  202. package/dist/esm/jp-decoder.d.ts +12 -0
  203. package/{lib → dist/esm}/jp-decoder.js +6 -21
  204. package/dist/esm/limited-passthrough.d.ts +25 -0
  205. package/{lib → dist/esm}/limited-passthrough.js +7 -20
  206. package/dist/esm/logger.d.ts +3 -0
  207. package/dist/esm/logger.js +4 -0
  208. package/dist/esm/package-info.d.ts +3 -0
  209. package/dist/esm/package-info.js +4 -0
  210. package/dist/esm/package.json +3 -0
  211. package/dist/esm/proxy-connection.d.ts +33 -0
  212. package/{lib → dist/esm}/proxy-connection.js +56 -127
  213. package/dist/esm/search-compiler.d.ts +34 -0
  214. package/{lib → dist/esm}/search-compiler.js +54 -110
  215. package/dist/esm/special-use.d.ts +22 -0
  216. package/dist/esm/special-use.js +907 -0
  217. package/dist/esm/tools.d.ts +427 -0
  218. package/dist/esm/tools.js +1446 -0
  219. package/dist/esm/types.d.ts +828 -0
  220. package/dist/esm/types.js +4 -0
  221. package/package.json +60 -20
  222. package/.gitattributes +0 -1
  223. package/.github/CODE_OF_CONDUCT.md +0 -76
  224. package/.github/FUNDING.yml +0 -4
  225. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  226. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
  227. package/.github/contributing.md +0 -17
  228. package/.github/workflows/release.yaml +0 -36
  229. package/.github/workflows/stale.yml +0 -29
  230. package/.github/workflows/test.yml +0 -51
  231. package/.ncurc.js +0 -4
  232. package/.prettierignore +0 -4
  233. package/.prettierrc.js +0 -8
  234. package/.release-please-manifest.json +0 -3
  235. package/CLAUDE.md +0 -104
  236. package/Gruntfile.js +0 -23
  237. package/eslint.config.js +0 -45
  238. package/lib/handler/imap-formal-syntax.js +0 -189
  239. package/lib/handler/imap-handler.js +0 -17
  240. package/lib/imap-commands.js +0 -45
  241. package/lib/logger.js +0 -5
  242. package/lib/special-use.js +0 -923
  243. package/lib/tools.js +0 -1612
  244. package/release-please-config.json +0 -10
  245. package/test/authentication-test.js +0 -101
  246. package/test/auto-idle-test.js +0 -470
  247. package/test/bodystructure-test.js +0 -899
  248. package/test/charsets-test.js +0 -161
  249. package/test/commands-branches-test.js +0 -1095
  250. package/test/commands-integration-test.js +0 -11124
  251. package/test/commands-test.js +0 -73
  252. package/test/connection-edge-cases-test.js +0 -1828
  253. package/test/connection-test.js +0 -162
  254. package/test/copyuid-parser-test.js +0 -173
  255. package/test/fetch-generator-test.js +0 -218
  256. package/test/fixtures/fake-timers.js +0 -115
  257. package/test/fixtures/serialized-mimetorture.js +0 -2738
  258. package/test/fixtures/test-client.js +0 -57
  259. package/test/fixtures/test-tls.js +0 -8
  260. package/test/handler-branches-test.js +0 -310
  261. package/test/idle-polling-test.js +0 -518
  262. package/test/imap-compiler-test.js +0 -809
  263. package/test/imap-flow-compress-test.js +0 -166
  264. package/test/imap-flow-coverage-test.js +0 -612
  265. package/test/imap-flow-fetch-download-test.js +0 -873
  266. package/test/imap-flow-internals-test.js +0 -725
  267. package/test/imap-flow-methods-test.js +0 -889
  268. package/test/imap-flow-proxy-paths-test.js +0 -366
  269. package/test/imap-flow-secure-test.js +0 -573
  270. package/test/imap-flow-server-test.js +0 -1474
  271. package/test/imap-formal-syntax-test.js +0 -293
  272. package/test/imap-parser-test.js +0 -1474
  273. package/test/imap-stream-edge-cases-test.js +0 -666
  274. package/test/imap-stream-test.js +0 -177
  275. package/test/imapflow-test.js +0 -258
  276. package/test/integration/README.md +0 -52
  277. package/test/integration/dovecot-test.conf +0 -27
  278. package/test/integration/rev2-live-test.js +0 -431
  279. package/test/integration/run-rev2-tests.sh +0 -75
  280. package/test/integration-test.js +0 -83
  281. package/test/jp-decoder-test.js +0 -304
  282. package/test/limited-passthrough-test.js +0 -299
  283. package/test/memory-cleanup-test.js +0 -144
  284. package/test/memory-leak-test.js +0 -667
  285. package/test/parser-limits-test.js +0 -292
  286. package/test/proxy-connection-test.js +0 -738
  287. package/test/reliability-improvements-test.js +0 -548
  288. package/test/search-compiler-test.js +0 -1300
  289. package/test/search-test.js +0 -329
  290. package/test/special-use-test.js +0 -418
  291. package/test/starttls-injection-test.js +0 -181
  292. package/test/tag-correlation-test.js +0 -333
  293. package/test/timer-policy-test.js +0 -227
  294. package/test/token-parser-test.js +0 -456
  295. package/test/tools-test.js +0 -2013
  296. package/test/unhandled-rejection-test.js +0 -593
@@ -1,23 +1,16 @@
1
1
  /* eslint new-cap: 0 */
2
-
3
- 'use strict';
4
-
5
- const imapFormalSyntax = require('./imap-formal-syntax');
6
- const { MAX_LITERAL_SIZE, normalizeLimit, createLiteralTooLargeError } = require('./limits');
7
-
2
+ import imapFormalSyntax from './imap-formal-syntax.js';
3
+ import { MAX_LITERAL_SIZE, normalizeLimit, createLiteralTooLargeError } from './limits.js';
8
4
  const STATE_ATOM = 0x001;
9
5
  const STATE_LITERAL = 0x002;
10
6
  const STATE_NORMAL = 0x003;
11
7
  const STATE_PARTIAL = 0x004;
12
8
  const STATE_SEQUENCE = 0x005;
13
9
  const STATE_STRING = 0x006;
14
-
15
10
  const RE_DIGITS = /^\d+$/;
16
11
  const RE_SINGLE_DIGIT = /^\d$/;
17
-
18
12
  // Prevents stack overflow from maliciously crafted deeply-nested IMAP input (e.g., (((((...))))))
19
13
  const MAX_NODE_DEPTH = 25;
20
-
21
14
  /**
22
15
  * Tokenizes an IMAP attribute string into a tree of typed nodes.
23
16
  * Handles all IMAP data types: atoms, quoted strings, literals (including literal8),
@@ -25,61 +18,52 @@ const MAX_NODE_DEPTH = 25;
25
18
  * Enforces a maximum nesting depth of {@link MAX_NODE_DEPTH} to prevent stack overflow
26
19
  * from malicious input.
27
20
  */
28
- class TokenParser {
21
+ export class TokenParser {
29
22
  /**
30
23
  * Creates a new TokenParser.
31
24
  *
32
- * @param {ParserInstance} parent - The parent ParserInstance that owns this token parser. Used to access the parsed command for context-sensitive parsing.
33
- * @param {number} startPos - The starting position offset in the original input, used for error reporting.
34
- * @param {string} str - The attribute string to tokenize.
35
- * @param {Object} [options] - Parser options.
36
- * @param {boolean} [options.literalPlus] - Whether the LITERAL+ extension is in use.
37
- * @param {Array<Buffer>} [options.literals] - Pre-parsed literal values from the input stream.
38
- * @param {number} [options.maxLiteralSize] - Maximum size (in bytes) of a literal parsed inline
25
+ * @param parent - The parent ParserInstance that owns this token parser. Used to access the parsed command for context-sensitive parsing.
26
+ * @param startPos - The starting position offset in the original input, used for error reporting.
27
+ * @param str - The attribute string to tokenize.
28
+ * @param options - Parser options.
29
+ * @param options.literalPlus - Whether the LITERAL+ extension is in use.
30
+ * @param options.literals - Pre-parsed literal values from the input stream.
31
+ * @param options.maxLiteralSize - Maximum size (in bytes) of a literal parsed inline
39
32
  * from the input, i.e. when no pre-parsed literal buffers were supplied. Defaults to 1GB.
40
33
  */
41
34
  constructor(parent, startPos, str, options) {
42
35
  this.str = (str || '').toString();
43
36
  this.options = options || {};
44
37
  this.parent = parent;
45
-
46
38
  // Same normalization and default as the streaming parser, so a direct user of this parser
47
39
  // gets the same bound (an explicit 0 means "reject any non-empty inline literal").
48
40
  this.maxLiteralSize = normalizeLimit(this.options.maxLiteralSize, MAX_LITERAL_SIZE);
49
-
50
41
  this.tree = this.currentNode = this.createNode();
51
42
  this.pos = startPos || 0;
52
-
53
43
  this.currentNode.type = 'TREE';
54
-
55
44
  this.state = STATE_NORMAL;
56
45
  }
57
-
58
46
  /**
59
47
  * Processes the input string and returns the parsed attributes as a flat array of typed objects.
60
48
  * Each attribute is an object with a `type` (e.g., "ATOM", "STRING", "LITERAL", "SEQUENCE")
61
49
  * and a `value` property. Lists are represented as nested arrays. Sections and partials are
62
50
  * attached as properties on the preceding attribute object.
63
51
  *
64
- * @returns {Promise<Array>} A promise that resolves to an array of parsed attribute objects and nested arrays.
52
+ * @returns A promise that resolves to an array of parsed attribute objects and nested arrays.
65
53
  * @throws {Error} If the input contains syntax errors or unclosed nodes.
66
54
  */
67
55
  async getAttributes() {
68
56
  await this.processString();
69
-
70
57
  const attributes = [];
71
58
  let branch = attributes;
72
-
73
- let walk = async node => {
59
+ let walk = async (node) => {
74
60
  let curBranch = branch;
75
61
  let elm;
76
62
  let partial;
77
-
78
63
  if (!node.isClosed && node.type === 'SEQUENCE' && node.value === '*') {
79
64
  node.isClosed = true;
80
65
  node.type = 'ATOM';
81
66
  }
82
-
83
67
  // If the node was never closed, throw it
84
68
  if (!node.isClosed) {
85
69
  let error = new Error(`Unexpected end of input at position ${this.pos + this.str.length - 1} [E9]`);
@@ -87,9 +71,7 @@ class TokenParser {
87
71
  error.parserContext = { input: this.str, pos: this.pos + this.str.length - 1 };
88
72
  throw error;
89
73
  }
90
-
91
74
  let type = (node.type || '').toString().toUpperCase();
92
-
93
75
  switch (type) {
94
76
  case 'LITERAL':
95
77
  case 'STRING':
@@ -100,7 +82,6 @@ class TokenParser {
100
82
  };
101
83
  branch.push(elm);
102
84
  break;
103
-
104
85
  case 'ATOM':
105
86
  if (node.value.toUpperCase() === 'NIL') {
106
87
  branch.push(null);
@@ -112,43 +93,35 @@ class TokenParser {
112
93
  };
113
94
  branch.push(elm);
114
95
  break;
115
-
116
96
  case 'SECTION':
117
97
  branch = branch[branch.length - 1].section = [];
118
98
  break;
119
-
120
99
  case 'LIST':
121
100
  elm = [];
122
101
  branch.push(elm);
123
102
  branch = elm;
124
103
  break;
125
-
126
104
  case 'PARTIAL':
127
105
  partial = node.value.split('.').map(Number);
128
106
  branch[branch.length - 1].partial = partial;
129
107
  break;
130
108
  }
131
-
132
109
  for (let childNode of node.childNodes) {
133
110
  await walk(childNode);
134
111
  }
135
-
136
112
  branch = curBranch;
137
113
  };
138
-
139
114
  await walk(this.tree);
140
-
141
115
  return attributes;
142
116
  }
143
-
144
117
  /**
145
118
  * Creates a new node in the parse tree. Each node represents a token or structural
146
119
  * element (e.g., atom, string, literal, list, section, partial). The node is automatically
147
120
  * appended to the parent's childNodes array if a parent is provided.
148
121
  *
149
- * @param {Object} [parentNode] - The parent node to attach this node to. If omitted, creates a root node.
150
- * @param {number} [startPos] - The starting position of this node in the original input string.
151
- * @returns {Object} The newly created node with childNodes, type, value, and isClosed properties.
122
+ * @param parentNode - The parent node to attach this node to. If omitted, creates a root node.
123
+ * @param startPos - The starting position of this node in the original input string.
124
+ * @returns The newly created node with childNodes, type, value, and isClosed properties.
152
125
  * @throws {Error} If the nesting depth exceeds MAX_NODE_DEPTH.
153
126
  */
154
127
  createNode(parentNode, startPos) {
@@ -156,56 +129,66 @@ class TokenParser {
156
129
  childNodes: [],
157
130
  type: false,
158
131
  value: '',
159
- isClosed: true
132
+ isClosed: true,
133
+ depth: 0
160
134
  };
161
-
162
135
  if (parentNode) {
163
136
  node.parentNode = parentNode;
164
137
  node.depth = parentNode.depth + 1;
165
- } else {
138
+ }
139
+ else {
166
140
  node.depth = 0;
167
141
  }
168
-
169
142
  if (node.depth > MAX_NODE_DEPTH) {
170
143
  let error = new Error('Too much nesting in IMAP string');
171
144
  error.code = 'MAX_IMAP_NESTING_REACHED';
172
145
  error._imapStr = this.str;
173
146
  throw error;
174
147
  }
175
-
176
148
  if (typeof startPos === 'number') {
177
149
  node.startPos = startPos;
178
150
  }
179
-
180
151
  if (parentNode) {
181
152
  parentNode.childNodes.push(node);
182
153
  }
183
-
184
154
  return node;
185
155
  }
186
-
187
156
  /**
188
157
  * Processes the entire input string character by character using a state machine.
189
158
  * Transitions between states (NORMAL, ATOM, STRING, LITERAL, SEQUENCE, PARTIAL, TEXT)
190
159
  * based on the current character and builds the parse tree. This is the main parsing
191
160
  * loop that drives the tokenization.
192
161
  *
193
- * @returns {Promise<void>}
194
162
  * @throws {Error} If the input contains unexpected characters, unclosed structures, or other syntax errors.
195
163
  */
196
164
  async processString() {
197
165
  let chr, i, len;
198
-
199
166
  const checkSP = () => {
200
167
  // jump to the next non whitespace pos
201
168
  while (this.str.charAt(i + 1) === ' ') {
202
169
  i++;
203
170
  }
204
171
  };
205
-
172
+ // Any ATOM supported char starts a new Atom sequence, otherwise throw an error
173
+ // Allow \ as the first char for atom to support system flags
174
+ // Allow % to support LIST '' %
175
+ // Allow 8bit characters (presumably unicode)
176
+ // Shared by the default branch and by a '[' that is not a response code section, which
177
+ // used to fall through into the default branch
178
+ const startAtom = () => {
179
+ if (!imapFormalSyntax['ATOM-CHAR']().includes(chr) && chr !== '\\' && chr !== '%' && chr.charCodeAt(0) < 0x80) {
180
+ let error = new Error(`Unexpected char at position ${this.pos + i} [E13: ${JSON.stringify(chr)}]`);
181
+ error.code = 'ParserError13';
182
+ error.parserContext = { input: this.str, pos: this.pos + i, chr };
183
+ throw error;
184
+ }
185
+ this.currentNode = this.createNode(this.currentNode, this.pos + i);
186
+ this.currentNode.type = 'ATOM';
187
+ this.currentNode.value = chr;
188
+ this.state = STATE_ATOM;
189
+ };
206
190
  for (i = 0, len = this.str.length; i < len; i++) {
207
191
  chr = this.str.charAt(i);
208
-
209
192
  switch (this.state) {
210
193
  case STATE_NORMAL:
211
194
  switch (chr) {
@@ -216,14 +199,12 @@ class TokenParser {
216
199
  this.state = STATE_STRING;
217
200
  this.currentNode.isClosed = false;
218
201
  break;
219
-
220
202
  // ( starts a new list
221
203
  case '(':
222
204
  this.currentNode = this.createNode(this.currentNode, this.pos + i);
223
205
  this.currentNode.type = 'LIST';
224
206
  this.currentNode.isClosed = false;
225
207
  break;
226
-
227
208
  // ) closes a list
228
209
  case ')':
229
210
  if (this.currentNode.type !== 'LIST') {
@@ -232,14 +213,11 @@ class TokenParser {
232
213
  error.parserContext = { input: this.str, pos: this.pos + i, chr };
233
214
  throw error;
234
215
  }
235
-
236
216
  this.currentNode.isClosed = true;
237
217
  this.currentNode.endPos = this.pos + i;
238
218
  this.currentNode = this.currentNode.parentNode;
239
-
240
219
  checkSP();
241
220
  break;
242
-
243
221
  // ] closes section group
244
222
  case ']':
245
223
  if (this.currentNode.type !== 'SECTION') {
@@ -251,10 +229,8 @@ class TokenParser {
251
229
  this.currentNode.isClosed = true;
252
230
  this.currentNode.endPos = this.pos + i;
253
231
  this.currentNode = this.currentNode.parentNode;
254
-
255
232
  checkSP();
256
233
  break;
257
-
258
234
  // < starts a new partial byte range (e.g., BODY[]<0.1024>)
259
235
  case '<':
260
236
  // '<' is only a partial range marker when it immediately follows ']',
@@ -265,14 +241,14 @@ class TokenParser {
265
241
  this.currentNode.type = 'ATOM';
266
242
  this.currentNode.value = chr;
267
243
  this.state = STATE_ATOM;
268
- } else {
244
+ }
245
+ else {
269
246
  this.currentNode = this.createNode(this.currentNode, this.pos + i);
270
247
  this.currentNode.type = 'PARTIAL';
271
248
  this.state = STATE_PARTIAL;
272
249
  this.currentNode.isClosed = false;
273
250
  }
274
251
  break;
275
-
276
252
  // literal8 (RFC 3516): uses ~{size} prefix instead of {size}
277
253
  // literal8 allows binary data containing NUL bytes, unlike regular literals
278
254
  case '~': {
@@ -286,7 +262,6 @@ class TokenParser {
286
262
  this.state = STATE_ATOM;
287
263
  break;
288
264
  }
289
-
290
265
  let error = new Error(`Unexpected literal8 marker at position ${this.pos + i} [E12]`);
291
266
  error.code = 'ParserError12';
292
267
  error.parserContext = { input: this.str, pos: this.pos + i, chr };
@@ -296,7 +271,6 @@ class TokenParser {
296
271
  this.expectedLiteralType = 'literal8';
297
272
  break;
298
273
  }
299
-
300
274
  // { starts a new literal (regular {size}\r\n or literal8 ~{size}\r\n)
301
275
  case '{':
302
276
  this.currentNode = this.createNode(this.currentNode, this.pos + i);
@@ -307,7 +281,6 @@ class TokenParser {
307
281
  this.state = STATE_LITERAL;
308
282
  this.currentNode.isClosed = false;
309
283
  break;
310
-
311
284
  // * starts a new sequence
312
285
  case '*':
313
286
  this.currentNode = this.createNode(this.currentNode, this.pos + i);
@@ -316,27 +289,23 @@ class TokenParser {
316
289
  this.currentNode.isClosed = false;
317
290
  this.state = STATE_SEQUENCE;
318
291
  break;
319
-
320
292
  // normally a space should never occur
321
293
  case ' ':
322
294
  // just ignore
323
295
  break;
324
-
325
296
  // [ starts section
326
297
  case '[':
327
298
  // If it is the *first* element after response command, then process as a response argument list
328
299
  // Status responses (OK/NO/BAD/BYE/PREAUTH) use [code] for response codes
329
- if (['OK', 'NO', 'BAD', 'BYE', 'PREAUTH'].includes(this.parent.command.toUpperCase()) && this.currentNode === this.tree) {
300
+ if (['OK', 'NO', 'BAD', 'BYE', 'PREAUTH'].includes(this.parent.command.toUpperCase()) &&
301
+ this.currentNode === this.tree) {
330
302
  this.currentNode.endPos = this.pos + i;
331
-
332
303
  this.currentNode = this.createNode(this.currentNode, this.pos + i);
333
304
  this.currentNode.type = 'ATOM';
334
-
335
305
  this.currentNode = this.createNode(this.currentNode, this.pos + i);
336
306
  this.currentNode.type = 'SECTION';
337
307
  this.currentNode.isClosed = false;
338
308
  this.state = STATE_NORMAL;
339
-
340
309
  // RFC 2221 REFERRAL special case: the payload is an RFC 2192/RFC 5092
341
310
  // IMAP URL (e.g., imap://user@host/mailbox) which contains characters
342
311
  // that would break normal ATOM parsing (colons, slashes, etc.).
@@ -348,7 +317,6 @@ class TokenParser {
348
317
  this.currentNode.endPos = this.pos + i + 8;
349
318
  this.currentNode.value = 'REFERRAL';
350
319
  this.currentNode = this.currentNode.parentNode;
351
-
352
320
  // eat all the way through the ] to be the IMAPURL token.
353
321
  this.currentNode = this.createNode(this.currentNode, this.pos + i + 10);
354
322
  // just call this an ATOM, even though IMAPURL might be more correct
@@ -365,38 +333,21 @@ class TokenParser {
365
333
  this.currentNode.endPos = this.pos + i - 1;
366
334
  this.currentNode.value = this.str.substring(this.currentNode.startPos - this.pos, this.currentNode.endPos - this.pos + 1);
367
335
  this.currentNode = this.currentNode.parentNode;
368
-
369
336
  // close out the SECTION
370
337
  this.currentNode.isClosed = true;
371
338
  this.currentNode = this.currentNode.parentNode;
372
-
373
339
  checkSP();
374
340
  }
375
-
376
341
  break;
377
342
  }
378
-
379
- /* falls through */
343
+ // Not a response code section: handled like any other atom start
344
+ startAtom();
345
+ break;
380
346
  default:
381
- // Any ATOM supported char starts a new Atom sequence, otherwise throw an error
382
- // Allow \ as the first char for atom to support system flags
383
- // Allow % to support LIST '' %
384
- // Allow 8bit characters (presumably unicode)
385
- if (!imapFormalSyntax['ATOM-CHAR']().includes(chr) && chr !== '\\' && chr !== '%' && chr.charCodeAt(0) < 0x80) {
386
- let error = new Error(`Unexpected char at position ${this.pos + i} [E13: ${JSON.stringify(chr)}]`);
387
- error.code = 'ParserError13';
388
- error.parserContext = { input: this.str, pos: this.pos + i, chr };
389
- throw error;
390
- }
391
-
392
- this.currentNode = this.createNode(this.currentNode, this.pos + i);
393
- this.currentNode.type = 'ATOM';
394
- this.currentNode.value = chr;
395
- this.state = STATE_ATOM;
347
+ startAtom();
396
348
  break;
397
349
  }
398
350
  break;
399
-
400
351
  case STATE_ATOM:
401
352
  // An atom is terminated by: space, closing delimiter of parent node,
402
353
  // or encountering a '[' that starts a section for BODY/BINARY commands.
@@ -407,24 +358,18 @@ class TokenParser {
407
358
  this.state = STATE_NORMAL;
408
359
  break;
409
360
  }
410
-
411
361
  // ')' or ']' terminates the atom AND closes the enclosing LIST or SECTION
412
- if (
413
- this.currentNode.parentNode &&
414
- ((chr === ')' && this.currentNode.parentNode.type === 'LIST') || (chr === ']' && this.currentNode.parentNode.type === 'SECTION'))
415
- ) {
362
+ if (this.currentNode.parentNode &&
363
+ ((chr === ')' && this.currentNode.parentNode.type === 'LIST') || (chr === ']' && this.currentNode.parentNode.type === 'SECTION'))) {
416
364
  this.currentNode.endPos = this.pos + i - 1;
417
365
  this.currentNode = this.currentNode.parentNode;
418
-
419
366
  this.currentNode.isClosed = true;
420
367
  this.currentNode.endPos = this.pos + i;
421
368
  this.currentNode = this.currentNode.parentNode;
422
369
  this.state = STATE_NORMAL;
423
370
  checkSP();
424
-
425
371
  break;
426
372
  }
427
-
428
373
  // If the atom so far is all digits and we see ',' or ':', it is actually
429
374
  // a sequence set (e.g., "1:5" or "1,3,5"), so reclassify and switch state
430
375
  if ((chr === ',' || chr === ':') && RE_DIGITS.test(this.currentNode.value)) {
@@ -432,7 +377,6 @@ class TokenParser {
432
377
  this.currentNode.isClosed = true;
433
378
  this.state = STATE_SEQUENCE;
434
379
  }
435
-
436
380
  // [ starts a section group for this element
437
381
  // Allowed only for selected elements, otherwise falls through to regular ATOM processing
438
382
  if (chr === '[' && ['BODY', 'BODY.PEEK', 'BINARY', 'BINARY.PEEK'].includes(this.currentNode.value.toUpperCase())) {
@@ -443,29 +387,25 @@ class TokenParser {
443
387
  this.state = STATE_NORMAL;
444
388
  break;
445
389
  }
446
-
447
390
  // if the char is not ATOM compatible, throw. Allow \* as an exception
448
- if (
449
- !imapFormalSyntax['ATOM-CHAR']().includes(chr) &&
391
+ if (!imapFormalSyntax['ATOM-CHAR']().includes(chr) &&
450
392
  chr.charCodeAt(0) < 0x80 && // allow 8bit (presumably unicode) bytes
451
393
  chr !== ']' &&
452
394
  !(chr === '*' && this.currentNode.value === '\\') &&
453
- (!this.parent || !this.parent.command || !['NO', 'BAD', 'OK'].includes(this.parent.command))
454
- ) {
395
+ (!this.parent || !this.parent.command || !['NO', 'BAD', 'OK'].includes(this.parent.command))) {
455
396
  let error = new Error(`Unexpected char at position ${this.pos + i} [E16: ${JSON.stringify(chr)}]`);
456
397
  error.code = 'ParserError16';
457
398
  error.parserContext = { input: this.str, pos: this.pos + i, chr };
458
399
  throw error;
459
- } else if (this.currentNode.value === '\\*') {
400
+ }
401
+ else if (this.currentNode.value === '\\*') {
460
402
  let error = new Error(`Unexpected char at position ${this.pos + i} [E17: ${JSON.stringify(chr)}]`);
461
403
  error.code = 'ParserError17';
462
404
  error.parserContext = { input: this.str, pos: this.pos + i, chr };
463
405
  throw error;
464
406
  }
465
-
466
407
  this.currentNode.value += chr;
467
408
  break;
468
-
469
409
  case STATE_STRING:
470
410
  // DQUOTE ends the string sequence
471
411
  if (chr === '"') {
@@ -473,11 +413,9 @@ class TokenParser {
473
413
  this.currentNode.isClosed = true;
474
414
  this.currentNode = this.currentNode.parentNode;
475
415
  this.state = STATE_NORMAL;
476
-
477
416
  checkSP();
478
417
  break;
479
418
  }
480
-
481
419
  // \ Escapes the following char
482
420
  if (chr === '\\') {
483
421
  i++;
@@ -489,10 +427,8 @@ class TokenParser {
489
427
  }
490
428
  chr = this.str.charAt(i);
491
429
  }
492
-
493
430
  this.currentNode.value += chr;
494
431
  break;
495
-
496
432
  case STATE_PARTIAL:
497
433
  if (chr === '>') {
498
434
  if (this.currentNode.value.at(-1) === '.') {
@@ -508,35 +444,29 @@ class TokenParser {
508
444
  checkSP();
509
445
  break;
510
446
  }
511
-
512
447
  if (chr === '.' && (this.currentNode.value === '' || this.currentNode.value.includes('.'))) {
513
448
  let error = new Error(`Unexpected partial separator . at position ${this.pos + i} [E20]`);
514
449
  error.code = 'ParserError20';
515
450
  error.parserContext = { input: this.str, pos: this.pos + i, chr };
516
451
  throw error;
517
452
  }
518
-
519
453
  if (!imapFormalSyntax.DIGIT().includes(chr) && chr !== '.') {
520
454
  let error = new Error(`Unexpected char at position ${this.pos + i} [E21: ${JSON.stringify(chr)}]`);
521
455
  error.code = 'ParserError21';
522
456
  error.parserContext = { input: this.str, pos: this.pos + i, chr };
523
457
  throw error;
524
458
  }
525
-
526
459
  if ((this.currentNode.value === '0' || this.currentNode.value.endsWith('.0')) && chr !== '.') {
527
460
  let error = new Error(`Invalid partial at position ${this.pos + i} [E22: ${JSON.stringify(chr)}]`);
528
461
  error.code = 'ParserError22';
529
462
  error.parserContext = { input: this.str, pos: this.pos + i, chr };
530
463
  throw error;
531
464
  }
532
-
533
465
  this.currentNode.value += chr;
534
466
  break;
535
-
536
467
  case STATE_LITERAL:
537
468
  if (this.currentNode.started) {
538
469
  // only relevant if literals are not already parsed out from input
539
-
540
470
  // Disabled NULL byte check
541
471
  // See https://github.com/emailjs/emailjs-imap-handler/commit/f11b2822bedabe492236e8263afc630134a3c41c
542
472
  /*
@@ -544,9 +474,7 @@ class TokenParser {
544
474
  throw new Error('Unexpected \\x00 at position ' + (this.pos + i));
545
475
  }
546
476
  */
547
-
548
477
  this.currentNode.chBuffer[this.currentNode.chPos++] = chr.charCodeAt(0);
549
-
550
478
  if (this.currentNode.chPos >= this.currentNode.literalLength) {
551
479
  this.currentNode.endPos = this.pos + i;
552
480
  this.currentNode.isClosed = true;
@@ -558,12 +486,10 @@ class TokenParser {
558
486
  }
559
487
  break;
560
488
  }
561
-
562
489
  if (chr === '+' && this.options.literalPlus) {
563
490
  this.currentNode.literalPlus = true;
564
491
  break;
565
492
  }
566
-
567
493
  if (chr === '}') {
568
494
  if (!('literalLength' in this.currentNode)) {
569
495
  let error = new Error(`Unexpected literal prefix end char } at position ${this.pos + i} [E23]`);
@@ -573,17 +499,17 @@ class TokenParser {
573
499
  }
574
500
  if (this.str.charAt(i + 1) === '\n') {
575
501
  i++;
576
- } else if (this.str.charAt(i + 1) === '\r' && this.str.charAt(i + 2) === '\n') {
502
+ }
503
+ else if (this.str.charAt(i + 1) === '\r' && this.str.charAt(i + 2) === '\n') {
577
504
  i += 2;
578
- } else {
505
+ }
506
+ else {
579
507
  let error = new Error(`Unexpected char at position ${this.pos + i} [E24: ${JSON.stringify(chr)}]`);
580
508
  error.code = 'ParserError24';
581
509
  error.parserContext = { input: this.str, pos: this.pos + i, chr };
582
510
  throw error;
583
511
  }
584
-
585
512
  this.currentNode.literalLength = Number(this.currentNode.literalLength);
586
-
587
513
  if (!this.currentNode.literalLength) {
588
514
  // special case where literal content length is 0
589
515
  // close the node right away, do not wait for additional input
@@ -599,25 +525,24 @@ class TokenParser {
599
525
  this.currentNode = this.currentNode.parentNode;
600
526
  this.state = STATE_NORMAL;
601
527
  checkSP();
602
- } else if (this.options.literals) {
528
+ }
529
+ else if (this.options.literals) {
603
530
  // use the next precached literal values
604
531
  this.currentNode.value = this.options.literals.shift();
605
-
606
532
  // only APPEND arguments are kept as Buffers
607
533
  /*
608
534
  if ((this.parent.command || '').toString().toUpperCase() !== 'APPEND') {
609
535
  this.currentNode.value = this.currentNode.value.toString('binary');
610
536
  }
611
537
  */
612
-
613
538
  this.currentNode.endPos = this.pos + i + this.currentNode.value.length;
614
-
615
539
  this.currentNode.started = false;
616
540
  this.currentNode.isClosed = true;
617
541
  this.currentNode = this.currentNode.parentNode;
618
542
  this.state = STATE_NORMAL;
619
543
  checkSP();
620
- } else {
544
+ }
545
+ else {
621
546
  // No pre-parsed literal buffers were supplied, so the literal is read
622
547
  // inline from this input and its declared length decides an
623
548
  // allocation. ImapStream always supplies buffers (and has already
@@ -632,15 +557,10 @@ class TokenParser {
632
557
  let literalLength = this.currentNode.literalLength;
633
558
  if (literalLength > this.maxLiteralSize || literalLength > available) {
634
559
  let overMax = literalLength > this.maxLiteralSize;
635
- let error = createLiteralTooLargeError(
636
- literalLength,
637
- overMax ? this.maxLiteralSize : available,
638
- overMax ? null : `the ${available} bytes available in the input`
639
- );
560
+ let error = createLiteralTooLargeError(literalLength, overMax ? this.maxLiteralSize : available, overMax ? null : `the ${available} bytes available in the input`);
640
561
  error.parserContext = { input: this.str, pos: this.pos + i, chr };
641
562
  throw error;
642
563
  }
643
-
644
564
  this.currentNode.started = true;
645
565
  // Allocate expected size buffer.
646
566
  // Maybe should use allocUnsafe instead?
@@ -663,7 +583,6 @@ class TokenParser {
663
583
  }
664
584
  this.currentNode.literalLength = (this.currentNode.literalLength || '') + chr;
665
585
  break;
666
-
667
586
  case STATE_SEQUENCE:
668
587
  // space finishes the sequence set
669
588
  if (chr === ' ') {
@@ -673,32 +592,30 @@ class TokenParser {
673
592
  error.parserContext = { input: this.str, pos: this.pos + i, chr };
674
593
  throw error;
675
594
  }
676
-
677
- if (this.currentNode.value !== '*' && this.currentNode.value.at(-1) === '*' && this.currentNode.value.at(-2) !== ':') {
595
+ if (this.currentNode.value !== '*' &&
596
+ this.currentNode.value.at(-1) === '*' &&
597
+ this.currentNode.value.at(-2) !== ':') {
678
598
  let error = new Error(`Unexpected whitespace at position ${this.pos + i} [E28]`);
679
599
  error.code = 'ParserError28';
680
600
  error.parserContext = { input: this.str, pos: this.pos + i, chr };
681
601
  throw error;
682
602
  }
683
-
684
603
  this.currentNode.isClosed = true;
685
604
  this.currentNode.endPos = this.pos + i - 1;
686
605
  this.currentNode = this.currentNode.parentNode;
687
606
  this.state = STATE_NORMAL;
688
607
  break;
689
- } else if (this.currentNode.parentNode && chr === ']' && this.currentNode.parentNode.type === 'SECTION') {
608
+ }
609
+ else if (this.currentNode.parentNode && chr === ']' && this.currentNode.parentNode.type === 'SECTION') {
690
610
  this.currentNode.endPos = this.pos + i - 1;
691
611
  this.currentNode = this.currentNode.parentNode;
692
-
693
612
  this.currentNode.isClosed = true;
694
613
  this.currentNode.endPos = this.pos + i;
695
614
  this.currentNode = this.currentNode.parentNode;
696
615
  this.state = STATE_NORMAL;
697
-
698
616
  checkSP();
699
617
  break;
700
618
  }
701
-
702
619
  if (chr === ':') {
703
620
  if (!RE_SINGLE_DIGIT.test(this.currentNode.value.at(-1)) && this.currentNode.value.at(-1) !== '*') {
704
621
  let error = new Error(`Unexpected range separator : at position ${this.pos + i} [E29]`);
@@ -706,14 +623,16 @@ class TokenParser {
706
623
  error.parserContext = { input: this.str, pos: this.pos + i, chr };
707
624
  throw error;
708
625
  }
709
- } else if (chr === '*') {
626
+ }
627
+ else if (chr === '*') {
710
628
  if (![',', ':'].includes(this.currentNode.value.at(-1))) {
711
629
  let error = new Error(`Unexpected range wildcard at position ${this.pos + i} [E30]`);
712
630
  error.code = 'ParserError30';
713
631
  error.parserContext = { input: this.str, pos: this.pos + i, chr };
714
632
  throw error;
715
633
  }
716
- } else if (chr === ',') {
634
+ }
635
+ else if (chr === ',') {
717
636
  if (!RE_SINGLE_DIGIT.test(this.currentNode.value.at(-1)) && this.currentNode.value.at(-1) !== '*') {
718
637
  let error = new Error(`Unexpected sequence separator , at position ${this.pos + i} [E31]`);
719
638
  error.code = 'ParserError31';
@@ -726,25 +645,22 @@ class TokenParser {
726
645
  error.parserContext = { input: this.str, pos: this.pos + i, chr };
727
646
  throw error;
728
647
  }
729
- } else if (!RE_SINGLE_DIGIT.test(chr)) {
648
+ }
649
+ else if (!RE_SINGLE_DIGIT.test(chr)) {
730
650
  let error = new Error(`Unexpected char at position ${this.pos + i} [E33: ${JSON.stringify(chr)}]`);
731
651
  error.code = 'ParserError33';
732
652
  error.parserContext = { input: this.str, pos: this.pos + i, chr };
733
653
  throw error;
734
654
  }
735
-
736
655
  if (RE_SINGLE_DIGIT.test(chr) && this.currentNode.value.at(-1) === '*') {
737
656
  let error = new Error(`Unexpected number at position ${this.pos + i} [E34: ${JSON.stringify(chr)}]`);
738
657
  error.code = 'ParserError34';
739
658
  error.parserContext = { input: this.str, pos: this.pos + i, chr };
740
659
  throw error;
741
660
  }
742
-
743
661
  this.currentNode.value += chr;
744
662
  break;
745
663
  }
746
664
  }
747
665
  }
748
666
  }
749
-
750
- module.exports.TokenParser = TokenParser;