Skip to content

Commit f2096c5

Browse files
committedOct 28, 2024··
fix(addressparser): Correctly detect if user local part is attached to domain part
1 parent 81de9eb commit f2096c5

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed
 

‎lib/addressparser/index.js

+22-8
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
* @return {Object} Address object
88
*/
99
function _handleAddress(tokens) {
10-
let token;
1110
let isGroup = false;
1211
let state = 'text';
1312
let address;
@@ -23,7 +22,8 @@ function _handleAddress(tokens) {
2322

2423
// Filter out <addresses>, (comments) and regular text
2524
for (i = 0, len = tokens.length; i < len; i++) {
26-
token = tokens[i];
25+
let token = tokens[i];
26+
let prevToken = i ? tokens[i - 1] : null;
2727
if (token.type === 'operator') {
2828
switch (token.value) {
2929
case '<':
@@ -38,6 +38,7 @@ function _handleAddress(tokens) {
3838
break;
3939
default:
4040
state = 'text';
41+
break;
4142
}
4243
} else if (token.value) {
4344
if (state === 'address') {
@@ -46,7 +47,13 @@ function _handleAddress(tokens) {
4647
// and so will we
4748
token.value = token.value.replace(/^[^<]*<\s*/, '');
4849
}
49-
data[state].push(token.value);
50+
51+
if (prevToken && prevToken.noBreak && data[state].length) {
52+
// join values
53+
data[state][data[state].length - 1] += token.value;
54+
} else {
55+
data[state].push(token.value);
56+
}
5057
}
5158
}
5259

@@ -172,11 +179,12 @@ class Tokenizer {
172179
* @return {Array} An array of operator|text tokens
173180
*/
174181
tokenize() {
175-
let chr,
176-
list = [];
182+
let list = [];
183+
177184
for (let i = 0, len = this.str.length; i < len; i++) {
178-
chr = this.str.charAt(i);
179-
this.checkChar(chr);
185+
let chr = this.str.charAt(i);
186+
let nextChr = i < len - 1 ? this.str.charAt(i + 1) : null;
187+
this.checkChar(chr, nextChr);
180188
}
181189

182190
this.list.forEach(node => {
@@ -194,18 +202,24 @@ class Tokenizer {
194202
*
195203
* @param {String} chr Character from the address field
196204
*/
197-
checkChar(chr) {
205+
checkChar(chr, nextChr) {
198206
if (this.escaped) {
199207
// ignore next condition blocks
200208
} else if (chr === this.operatorExpecting) {
201209
this.node = {
202210
type: 'operator',
203211
value: chr
204212
};
213+
214+
if (nextChr && ![' ', '\t', '\r', '\n', ',', ';'].includes(nextChr)) {
215+
this.node.noBreak = true;
216+
}
217+
205218
this.list.push(this.node);
206219
this.node = null;
207220
this.operatorExpecting = '';
208221
this.escaped = false;
222+
209223
return;
210224
} else if (!this.operatorExpecting && chr in this.operators) {
211225
this.node = {

‎test/addressparser/addressparser-test.js

+11
Original file line numberDiff line numberDiff line change
@@ -298,4 +298,15 @@ describe('#addressparser', () => {
298298
let expected = [{ address: 'test@example.com', name: 'Firstname " \\, Lastname (Test)' }];
299299
assert.deepStrictEqual(addressparser(input), expected);
300300
});
301+
302+
it('should handle quoted usernames', () => {
303+
let input = '"test@subdomain.com"@example.com';
304+
let expected = [
305+
{
306+
address: 'test@subdomain.com@example.com',
307+
name: ''
308+
}
309+
];
310+
assert.deepStrictEqual(addressparser(input), expected);
311+
});
301312
});

0 commit comments

Comments
 (0)
Please sign in to comment.