@@ -28,6 +28,7 @@ import {
2828 PLUS ,
2929 POUND ,
3030 PROTOCOL ,
31+ MAILTO ,
3132 QUERY ,
3233 SLASH ,
3334 UNDERSCORE ,
@@ -45,6 +46,7 @@ import {
4546} from './tokens/text' ;
4647
4748import {
49+ MAILTOEMAIL ,
4850 EMAIL ,
4951 NL as MNL ,
5052 TEXT ,
@@ -58,42 +60,46 @@ let S_START = makeState();
5860
5961// Intermediate states for URLs. Note that domains that begin with a protocol
6062// are treated slighly differently from those that don't.
61- let S_PROTOCOL = makeState ( ) ; // e.g., 'http:'
62- let S_PROTOCOL_SLASH = makeState ( ) ; // e.g., '/', 'http:/''
63- let S_PROTOCOL_SLASH_SLASH = makeState ( ) ; // e.g., '//', 'http://'
64- let S_DOMAIN = makeState ( ) ; // parsed string ends with a potential domain name (A)
65- let S_DOMAIN_DOT = makeState ( ) ; // (A) domain followed by DOT
66- let S_TLD = makeState ( URL ) ; // (A) Simplest possible URL with no query string
67- let S_TLD_COLON = makeState ( ) ; // (A) URL followed by colon (potential port number here)
68- let S_TLD_PORT = makeState ( URL ) ; // TLD followed by a port number
69- let S_URL = makeState ( URL ) ; // Long URL with optional port and maybe query string
70- let S_URL_NON_ACCEPTING = makeState ( ) ; // URL followed by some symbols (will not be part of the final URL)
71- let S_URL_OPENBRACE = makeState ( ) ; // URL followed by {
72- let S_URL_OPENBRACKET = makeState ( ) ; // URL followed by [
73- let S_URL_OPENANGLEBRACKET = makeState ( ) ; // URL followed by <
74- let S_URL_OPENPAREN = makeState ( ) ; // URL followed by (
75- let S_URL_OPENBRACE_Q = makeState ( URL ) ; // URL followed by { and some symbols that the URL can end it
76- let S_URL_OPENBRACKET_Q = makeState ( URL ) ; // URL followed by [ and some symbols that the URL can end it
77- let S_URL_OPENANGLEBRACKET_Q = makeState ( URL ) ; // URL followed by < and some symbols that the URL can end it
78- let S_URL_OPENPAREN_Q = makeState ( URL ) ; // URL followed by ( and some symbols that the URL can end it
79- let S_URL_OPENBRACE_SYMS = makeState ( ) ; // S_URL_OPENBRACE_Q followed by some symbols it cannot end it
80- let S_URL_OPENBRACKET_SYMS = makeState ( ) ; // S_URL_OPENBRACKET_Q followed by some symbols it cannot end it
81- let S_URL_OPENANGLEBRACKET_SYMS = makeState ( ) ; // S_URL_OPENANGLEBRACKET_Q followed by some symbols it cannot end it
82- let S_URL_OPENPAREN_SYMS = makeState ( ) ; // S_URL_OPENPAREN_Q followed by some symbols it cannot end it
83- let S_EMAIL_DOMAIN = makeState ( ) ; // parsed string starts with local email info + @ with a potential domain name (C)
84- let S_EMAIL_DOMAIN_DOT = makeState ( ) ; // (C) domain followed by DOT
85- let S_EMAIL = makeState ( EMAIL ) ; // (C) Possible email address (could have more tlds)
86- let S_EMAIL_COLON = makeState ( ) ; // (C) URL followed by colon (potential port number here)
87- let S_EMAIL_PORT = makeState ( EMAIL ) ; // (C) Email address with a port
88- let S_LOCALPART = makeState ( ) ; // Local part of the email address
89- let S_LOCALPART_AT = makeState ( ) ; // Local part of the email address plus @
90- let S_LOCALPART_DOT = makeState ( ) ; // Local part of the email address plus '.' (localpart cannot end in .)
91- let S_NL = makeState ( MNL ) ; // single new line
63+ let S_PROTOCOL = makeState ( ) ; // e.g., 'http:'
64+ let S_MAILTO = makeState ( ) ; // 'mailto:'
65+ let S_PROTOCOL_SLASH = makeState ( ) ; // e.g., '/', 'http:/''
66+ let S_PROTOCOL_SLASH_SLASH = makeState ( ) ; // e.g., '//', 'http://'
67+ let S_DOMAIN = makeState ( ) ; // parsed string ends with a potential domain name (A)
68+ let S_DOMAIN_DOT = makeState ( ) ; // (A) domain followed by DOT
69+ let S_TLD = makeState ( URL ) ; // (A) Simplest possible URL with no query string
70+ let S_TLD_COLON = makeState ( ) ; // (A) URL followed by colon (potential port number here)
71+ let S_TLD_PORT = makeState ( URL ) ; // TLD followed by a port number
72+ let S_URL = makeState ( URL ) ; // Long URL with optional port and maybe query string
73+ let S_URL_NON_ACCEPTING = makeState ( ) ; // URL followed by some symbols (will not be part of the final URL)
74+ let S_URL_OPENBRACE = makeState ( ) ; // URL followed by {
75+ let S_URL_OPENBRACKET = makeState ( ) ; // URL followed by [
76+ let S_URL_OPENANGLEBRACKET = makeState ( ) ; // URL followed by <
77+ let S_URL_OPENPAREN = makeState ( ) ; // URL followed by (
78+ let S_URL_OPENBRACE_Q = makeState ( URL ) ; // URL followed by { and some symbols that the URL can end it
79+ let S_URL_OPENBRACKET_Q = makeState ( URL ) ; // URL followed by [ and some symbols that the URL can end it
80+ let S_URL_OPENANGLEBRACKET_Q = makeState ( URL ) ; // URL followed by < and some symbols that the URL can end it
81+ let S_URL_OPENPAREN_Q = makeState ( URL ) ; // URL followed by ( and some symbols that the URL can end it
82+ let S_URL_OPENBRACE_SYMS = makeState ( ) ; // S_URL_OPENBRACE_Q followed by some symbols it cannot end it
83+ let S_URL_OPENBRACKET_SYMS = makeState ( ) ; // S_URL_OPENBRACKET_Q followed by some symbols it cannot end it
84+ let S_URL_OPENANGLEBRACKET_SYMS = makeState ( ) ; // S_URL_OPENANGLEBRACKET_Q followed by some symbols it cannot end it
85+ let S_URL_OPENPAREN_SYMS = makeState ( ) ; // S_URL_OPENPAREN_Q followed by some symbols it cannot end it
86+ let S_EMAIL_DOMAIN = makeState ( ) ; // parsed string starts with local email info + @ with a potential domain name (C)
87+ let S_EMAIL_DOMAIN_DOT = makeState ( ) ; // (C) domain followed by DOT
88+ let S_EMAIL = makeState ( EMAIL ) ; // (C) Possible email address (could have more tlds)
89+ let S_EMAIL_COLON = makeState ( ) ; // (C) URL followed by colon (potential port number here)
90+ let S_EMAIL_PORT = makeState ( EMAIL ) ; // (C) Email address with a port
91+ let S_MAILTO_EMAIL = makeState ( MAILTOEMAIL ) ; // Email that begins with the mailto prefix (D)
92+ let S_MAILTO_EMAIL_NON_ACCEPTING = makeState ( ) ; // (D) Followed by some non-query string chars
93+ let S_LOCALPART = makeState ( ) ; // Local part of the email address
94+ let S_LOCALPART_AT = makeState ( ) ; // Local part of the email address plus @
95+ let S_LOCALPART_DOT = makeState ( ) ; // Local part of the email address plus '.' (localpart cannot end in .)
96+ let S_NL = makeState ( MNL ) ; // single new line
9297
9398// Make path from start to protocol (with '//')
9499S_START
95100. on ( TNL , S_NL )
96101. on ( PROTOCOL , S_PROTOCOL )
102+ . on ( MAILTO , S_MAILTO )
97103. on ( SLASH , S_PROTOCOL_SLASH ) ;
98104
99105S_PROTOCOL . on ( SLASH , S_PROTOCOL_SLASH ) ;
@@ -255,6 +261,23 @@ S_URL_NON_ACCEPTING.on(qsNonAccepting, S_URL_NON_ACCEPTING);
255261// Note: We are not allowing '/' in email addresses since this would interfere
256262// with real URLs
257263
264+ // For addresses with the mailto prefix
265+ // 'mailto:' followed by anything sane is a valid email
266+ S_MAILTO
267+ . on ( TLD , S_MAILTO_EMAIL )
268+ . on ( DOMAIN , S_MAILTO_EMAIL )
269+ . on ( NUM , S_MAILTO_EMAIL )
270+ . on ( LOCALHOST , S_MAILTO_EMAIL ) ;
271+
272+ // Greedily get more potential valid email values
273+ S_MAILTO_EMAIL
274+ . on ( qsAccepting , S_MAILTO_EMAIL )
275+ . on ( qsNonAccepting , S_MAILTO_EMAIL_NON_ACCEPTING ) ;
276+ S_MAILTO_EMAIL_NON_ACCEPTING
277+ . on ( qsAccepting , S_MAILTO_EMAIL )
278+ . on ( qsNonAccepting , S_MAILTO_EMAIL_NON_ACCEPTING ) ;
279+
280+ // For addresses without the mailto prefix
258281// Tokens allowed in the localpart of the email
259282let localpartAccepting = [
260283 DOMAIN ,
0 commit comments