imapflow 1.0.96 → 1.0.97

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 CHANGED
@@ -1,5 +1,9 @@
1
1
  # CHANGELOG
2
2
 
3
+ - 1.0.97 - 2022-05-29
4
+
5
+ - Allow single quotes in atoms
6
+
3
7
  - 1.0.96 - 2022-05-18
4
8
 
5
9
  - Allow non-standard characters in ATOM if it's the string after NO/OK/BAD response
@@ -109,7 +109,7 @@ module.exports = {
109
109
  },
110
110
 
111
111
  'quoted-specials'() {
112
- let value = this.DQUOTE() + "'\\";
112
+ let value = this.DQUOTE() + '\\';
113
113
  this['quoted-specials'] = function () {
114
114
  return value;
115
115
  };
@@ -60,16 +60,16 @@ class ParserInstance {
60
60
  let match, element, errPos;
61
61
 
62
62
  if (this.remainder.match(/^\s/)) {
63
- throw new Error('Unexpected whitespace at position ' + this.pos);
63
+ throw new Error(`Unexpected whitespace at position ${this.pos} [E1]`);
64
64
  }
65
65
 
66
66
  if ((match = this.remainder.match(/^\s*[^\s]+(?=\s|$)/))) {
67
67
  element = match[0];
68
68
  if ((errPos = imapFormalSyntax.verify(element, syntax)) >= 0) {
69
- throw new Error('Unexpected char at position ' + (this.pos + errPos));
69
+ throw new Error(`Unexpected char at position ${this.pos + errPos} [E2: ${JSON.stringify(element.charAt(errPos))}]`);
70
70
  }
71
71
  } else {
72
- throw new Error('Unexpected end of input at position ' + this.pos);
72
+ throw new Error(`Unexpected end of input at position ${this.pos} [E3]`);
73
73
  }
74
74
 
75
75
  this.pos += match[0].length;
@@ -80,11 +80,11 @@ class ParserInstance {
80
80
 
81
81
  async getSpace() {
82
82
  if (!this.remainder.length) {
83
- throw new Error('Unexpected end of input at position ' + this.pos);
83
+ throw new Error(`Unexpected end of input at position ${this.pos} [E4]`);
84
84
  }
85
85
 
86
86
  if (imapFormalSyntax.verify(this.remainder.charAt(0), imapFormalSyntax.SP()) >= 0) {
87
- throw new Error('Unexpected char at position ' + this.pos);
87
+ throw new Error(`Unexpected char at position ${this.pos} [E5: ${JSON.stringify(this.remainder.charAt(0))}]`);
88
88
  }
89
89
 
90
90
  this.pos++;
@@ -93,11 +93,11 @@ class ParserInstance {
93
93
 
94
94
  async getAttributes() {
95
95
  if (!this.remainder.length) {
96
- throw new Error('Unexpected end of input at position ' + this.pos);
96
+ throw new Error(`Unexpected end of input at position ${this.pos} [E6]`);
97
97
  }
98
98
 
99
99
  if (this.remainder.match(/^\s/)) {
100
- throw new Error('Unexpected whitespace at position ' + this.pos);
100
+ throw new Error(`Unexpected whitespace at position ${this.pos} [E7]`);
101
101
  }
102
102
 
103
103
  const tokenParser = new TokenParser(this, this.pos, this.remainder, this.options);
@@ -36,7 +36,7 @@ class TokenParser {
36
36
 
37
37
  // If the node was never closed, throw it
38
38
  if (!node.isClosed) {
39
- throw new Error('Unexpected end of input at position ' + (this.pos + this.str.length - 1));
39
+ throw new Error(`Unexpected end of input at position ${this.pos + this.str.length - 1} [E6]`);
40
40
  }
41
41
 
42
42
  let type = (node.type || '').toString().toUpperCase();
@@ -149,7 +149,7 @@ class TokenParser {
149
149
  // ) closes a list
150
150
  case ')':
151
151
  if (this.currentNode.type !== 'LIST') {
152
- throw new Error('Unexpected list terminator ) at position ' + (this.pos + i));
152
+ throw new Error(`Unexpected list terminator ) at position ${this.pos + i} [E7]`);
153
153
  }
154
154
 
155
155
  this.currentNode.isClosed = true;
@@ -162,7 +162,7 @@ class TokenParser {
162
162
  // ] closes section group
163
163
  case ']':
164
164
  if (this.currentNode.type !== 'SECTION') {
165
- throw new Error('Unexpected section terminator ] at position ' + (this.pos + i));
165
+ throw new Error(`Unexpected section terminator ] at position ${this.pos + i} [E8]`);
166
166
  }
167
167
  this.currentNode.isClosed = true;
168
168
  this.currentNode.endPos = this.pos + i;
@@ -189,7 +189,7 @@ class TokenParser {
189
189
  case '~': {
190
190
  let nextChr = this.str.charAt(i + 1);
191
191
  if (nextChr !== '{') {
192
- throw new Error('Unexpected literal8 marker at position ' + (this.pos + i));
192
+ throw new Error(`Unexpected literal8 marker at position ${this.pos + i} [E9]`);
193
193
  }
194
194
  this.expectedLiteralType = 'literal8';
195
195
  break;
@@ -270,7 +270,7 @@ class TokenParser {
270
270
  // Allow \ as the first char for atom to support system flags
271
271
  // Allow % to support LIST '' %
272
272
  if (imapFormalSyntax['ATOM-CHAR']().indexOf(chr) < 0 && chr !== '\\' && chr !== '%') {
273
- throw new Error('Unexpected char at position ' + (this.pos + i));
273
+ throw new Error(`Unexpected char at position ${this.pos + i} [E10: ${JSON.stringify(chr)}]`);
274
274
  }
275
275
 
276
276
  this.currentNode = this.createNode(this.currentNode, this.pos + i);
@@ -317,7 +317,7 @@ class TokenParser {
317
317
  if (chr === '[') {
318
318
  // allowed only for selected elements
319
319
  if (['BODY', 'BODY.PEEK', 'BINARY', 'BINARY.PEEK'].indexOf(this.currentNode.value.toUpperCase()) < 0) {
320
- throw new Error('Unexpected section start char [ at position ' + this.pos);
320
+ throw new Error(`Unexpected section start char [ at position ${this.pos} [E11]`);
321
321
  }
322
322
  this.currentNode.endPos = this.pos + i;
323
323
  this.currentNode = this.createNode(this.currentNode.parentNode, this.pos + i);
@@ -328,7 +328,7 @@ class TokenParser {
328
328
  }
329
329
 
330
330
  if (chr === '<') {
331
- throw new Error('Unexpected start of partial at position ' + this.pos);
331
+ throw new Error(`Unexpected start of partial at position ${this.pos} [E12]`);
332
332
  }
333
333
 
334
334
  // if the char is not ATOM compatible, throw. Allow \* as an exception
@@ -338,9 +338,9 @@ class TokenParser {
338
338
  !(chr === '*' && this.currentNode.value === '\\') &&
339
339
  (!this.parent || !this.parent.command || !['NO', 'BAD', 'OK'].includes(this.parent.command))
340
340
  ) {
341
- throw new Error('Unexpected char at position ' + (this.pos + i));
341
+ throw new Error(`Unexpected char at position ${this.pos + i} [E13: ${JSON.stringify(chr)}]`);
342
342
  } else if (this.currentNode.value === '\\*') {
343
- throw new Error('Unexpected char at position ' + (this.pos + i));
343
+ throw new Error(`Unexpected char at position ${this.pos + i} [E14: ${JSON.stringify(chr)}]`);
344
344
  }
345
345
 
346
346
  this.currentNode.value += chr;
@@ -362,7 +362,7 @@ class TokenParser {
362
362
  if (chr === '\\') {
363
363
  i++;
364
364
  if (i >= len) {
365
- throw new Error('Unexpected end of input at position ' + (this.pos + i));
365
+ throw new Error(`Unexpected end of input at position ${this.pos + i} [E15]`);
366
366
  }
367
367
  chr = this.str.charAt(i);
368
368
  }
@@ -373,7 +373,7 @@ class TokenParser {
373
373
  case 'PARTIAL':
374
374
  if (chr === '>') {
375
375
  if (this.currentNode.value.substr(-1) === '.') {
376
- throw new Error('Unexpected end of partial at position ' + this.pos);
376
+ throw new Error(`Unexpected end of partial at position ${this.pos} [E16]`);
377
377
  }
378
378
  this.currentNode.endPos = this.pos + i;
379
379
  this.currentNode.isClosed = true;
@@ -384,15 +384,15 @@ class TokenParser {
384
384
  }
385
385
 
386
386
  if (chr === '.' && (!this.currentNode.value.length || this.currentNode.value.match(/\./))) {
387
- throw new Error('Unexpected partial separator . at position ' + this.pos);
387
+ throw new Error(`Unexpected partial separator . at position ${this.pos} [E17]`);
388
388
  }
389
389
 
390
390
  if (imapFormalSyntax.DIGIT().indexOf(chr) < 0 && chr !== '.') {
391
- throw new Error('Unexpected char at position ' + (this.pos + i));
391
+ throw new Error(`Unexpected char at position ${this.pos + i} [E18: ${JSON.stringify(chr)}]`);
392
392
  }
393
393
 
394
394
  if (this.currentNode.value.match(/^0$|\.0$/) && chr !== '.') {
395
- throw new Error('Invalid partial at position ' + (this.pos + i));
395
+ throw new Error(`Invalid partial at position ${this.pos + i} [E19: ${JSON.stringify(chr)}]`);
396
396
  }
397
397
 
398
398
  this.currentNode.value += chr;
@@ -431,14 +431,14 @@ class TokenParser {
431
431
 
432
432
  if (chr === '}') {
433
433
  if (!('literalLength' in this.currentNode)) {
434
- throw new Error('Unexpected literal prefix end char } at position ' + (this.pos + i));
434
+ throw new Error(`Unexpected literal prefix end char } at position ${this.pos + i} [E20]`);
435
435
  }
436
436
  if (this.str.charAt(i + 1) === '\n') {
437
437
  i++;
438
438
  } else if (this.str.charAt(i + 1) === '\r' && this.str.charAt(i + 2) === '\n') {
439
439
  i += 2;
440
440
  } else {
441
- throw new Error('Unexpected char at position ' + (this.pos + i));
441
+ throw new Error(`Unexpected char at position ${this.pos + i} [E21: ${JSON.stringify(chr)}]`);
442
442
  }
443
443
 
444
444
  this.currentNode.literalLength = Number(this.currentNode.literalLength);
@@ -479,10 +479,10 @@ class TokenParser {
479
479
  break;
480
480
  }
481
481
  if (imapFormalSyntax.DIGIT().indexOf(chr) < 0) {
482
- throw new Error('Unexpected char at position ' + (this.pos + i));
482
+ throw new Error(`Unexpected char at position ${this.pos + i} [E22: ${JSON.stringify(chr)}]`);
483
483
  }
484
484
  if (this.currentNode.literalLength === '0') {
485
- throw new Error('Invalid literal at position ' + (this.pos + i));
485
+ throw new Error(`Invalid literal at position ${this.pos + i} [E23]`);
486
486
  }
487
487
  this.currentNode.literalLength = (this.currentNode.literalLength || '') + chr;
488
488
  break;
@@ -491,11 +491,11 @@ class TokenParser {
491
491
  // space finishes the sequence set
492
492
  if (chr === ' ') {
493
493
  if (!this.currentNode.value.substr(-1).match(/\d/) && this.currentNode.value.substr(-1) !== '*') {
494
- throw new Error('Unexpected whitespace at position ' + (this.pos + i));
494
+ throw new Error(`Unexpected whitespace at position ${this.pos + i} [E24]`);
495
495
  }
496
496
 
497
497
  if (this.currentNode.value !== '*' && this.currentNode.value.substr(-1) === '*' && this.currentNode.value.substr(-2, 1) !== ':') {
498
- throw new Error('Unexpected whitespace at position ' + (this.pos + i));
498
+ throw new Error(`Unexpected whitespace at position ${this.pos + i} [E25]`);
499
499
  }
500
500
 
501
501
  this.currentNode.isClosed = true;
@@ -518,25 +518,25 @@ class TokenParser {
518
518
 
519
519
  if (chr === ':') {
520
520
  if (!this.currentNode.value.substr(-1).match(/\d/) && this.currentNode.value.substr(-1) !== '*') {
521
- throw new Error('Unexpected range separator : at position ' + (this.pos + i));
521
+ throw new Error(`Unexpected range separator : at position ${this.pos + i} [E26]`);
522
522
  }
523
523
  } else if (chr === '*') {
524
524
  if ([',', ':'].indexOf(this.currentNode.value.substr(-1)) < 0) {
525
- throw new Error('Unexpected range wildcard at position ' + (this.pos + i));
525
+ throw new Error(`Unexpected range wildcard at position ${this.pos + i} [E27]`);
526
526
  }
527
527
  } else if (chr === ',') {
528
528
  if (!this.currentNode.value.substr(-1).match(/\d/) && this.currentNode.value.substr(-1) !== '*') {
529
- throw new Error('Unexpected sequence separator , at position ' + (this.pos + i));
529
+ throw new Error(`Unexpected sequence separator , at position ${this.pos + i} [E28]`);
530
530
  }
531
531
  if (this.currentNode.value.substr(-1) === '*' && this.currentNode.value.substr(-2, 1) !== ':') {
532
- throw new Error('Unexpected sequence separator , at position ' + (this.pos + i));
532
+ throw new Error(`Unexpected sequence separator , at position ${this.pos + i} [E29]`);
533
533
  }
534
534
  } else if (!chr.match(/\d/)) {
535
- throw new Error('Unexpected char at position ' + (this.pos + i));
535
+ throw new Error(`Unexpected char at position ${this.pos + i} [E30: ${JSON.stringify(chr)}]`);
536
536
  }
537
537
 
538
538
  if (chr.match(/\d/) && this.currentNode.value.substr(-1) === '*') {
539
- throw new Error('Unexpected number at position ' + (this.pos + i));
539
+ throw new Error(`Unexpected number at position ${this.pos + i} [E31: ${JSON.stringify(chr)}]`);
540
540
  }
541
541
 
542
542
  this.currentNode.value += chr;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imapflow",
3
- "version": "1.0.96",
3
+ "version": "1.0.97",
4
4
  "description": "IMAP Client for Node",
5
5
  "main": "./lib/imap-flow.js",
6
6
  "scripts": {
@@ -921,3 +921,15 @@ module.exports['IMAP Parser, unicode select'] = test =>
921
921
  { type: 'ATOM', value: '[THROTTLED]' }
922
922
  ])
923
923
  );
924
+
925
+ module.exports['IMAP Parser, single quote in atom'] = test =>
926
+ asyncWrapper(test, async test =>
927
+ test.deepEqual((await parser('* LIST (HasNoChildren UnMarked) "/" \'a')).attributes, [
928
+ [
929
+ { type: 'ATOM', value: 'HasNoChildren' },
930
+ { type: 'ATOM', value: 'UnMarked' }
931
+ ],
932
+ { type: 'STRING', value: '/' },
933
+ { type: 'ATOM', value: "'a" }
934
+ ])
935
+ );