.
This commit is contained in:
		
							
								
								
									
										170
									
								
								qwen/nodejs/node_modules/@sideway/address/lib/email.js
									
									
									
										generated
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										170
									
								
								qwen/nodejs/node_modules/@sideway/address/lib/email.js
									
									
									
										generated
									
									
										vendored
									
									
										Executable file
									
								
							@@ -0,0 +1,170 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
const Util = require('util');
 | 
			
		||||
 | 
			
		||||
const Domain = require('./domain');
 | 
			
		||||
const Errors = require('./errors');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const internals = {
 | 
			
		||||
    nonAsciiRx: /[^\x00-\x7f]/,
 | 
			
		||||
    encoder: new (Util.TextEncoder || TextEncoder)()                                            // $lab:coverage:ignore$
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
exports.analyze = function (email, options) {
 | 
			
		||||
 | 
			
		||||
    return internals.email(email, options);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
exports.isValid = function (email, options) {
 | 
			
		||||
 | 
			
		||||
    return !internals.email(email, options);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
internals.email = function (email, options = {}) {
 | 
			
		||||
 | 
			
		||||
    if (typeof email !== 'string') {
 | 
			
		||||
        throw new Error('Invalid input: email must be a string');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!email) {
 | 
			
		||||
        return Errors.code('EMPTY_STRING');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Unicode
 | 
			
		||||
 | 
			
		||||
    const ascii = !internals.nonAsciiRx.test(email);
 | 
			
		||||
    if (!ascii) {
 | 
			
		||||
        if (options.allowUnicode === false) {                                                   // Defaults to true
 | 
			
		||||
            return Errors.code('FORBIDDEN_UNICODE');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        email = email.normalize('NFC');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Basic structure
 | 
			
		||||
 | 
			
		||||
    const parts = email.split('@');
 | 
			
		||||
    if (parts.length !== 2) {
 | 
			
		||||
        return parts.length > 2 ? Errors.code('MULTIPLE_AT_CHAR') : Errors.code('MISSING_AT_CHAR');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const [local, domain] = parts;
 | 
			
		||||
 | 
			
		||||
    if (!local) {
 | 
			
		||||
        return Errors.code('EMPTY_LOCAL');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!options.ignoreLength) {
 | 
			
		||||
        if (email.length > 254) {                                           // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.3
 | 
			
		||||
            return Errors.code('ADDRESS_TOO_LONG');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (internals.encoder.encode(local).length > 64) {                  // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.1
 | 
			
		||||
            return Errors.code('LOCAL_TOO_LONG');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Validate parts
 | 
			
		||||
 | 
			
		||||
    return internals.local(local, ascii) || Domain.analyze(domain, options);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
internals.local = function (local, ascii) {
 | 
			
		||||
 | 
			
		||||
    const segments = local.split('.');
 | 
			
		||||
    for (const segment of segments) {
 | 
			
		||||
        if (!segment.length) {
 | 
			
		||||
            return Errors.code('EMPTY_LOCAL_SEGMENT');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (ascii) {
 | 
			
		||||
            if (!internals.atextRx.test(segment)) {
 | 
			
		||||
                return Errors.code('INVALID_LOCAL_CHARS');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (const char of segment) {
 | 
			
		||||
            if (internals.atextRx.test(char)) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const binary = internals.binary(char);
 | 
			
		||||
            if (!internals.atomRx.test(binary)) {
 | 
			
		||||
                return Errors.code('INVALID_LOCAL_CHARS');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
internals.binary = function (char) {
 | 
			
		||||
 | 
			
		||||
    return Array.from(internals.encoder.encode(char)).map((v) => String.fromCharCode(v)).join('');
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    From RFC 5321:
 | 
			
		||||
 | 
			
		||||
        Mailbox         =   Local-part "@" ( Domain / address-literal )
 | 
			
		||||
 | 
			
		||||
        Local-part      =   Dot-string / Quoted-string
 | 
			
		||||
        Dot-string      =   Atom *("."  Atom)
 | 
			
		||||
        Atom            =   1*atext
 | 
			
		||||
        atext           =   ALPHA / DIGIT / "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~"
 | 
			
		||||
 | 
			
		||||
        Domain          =   sub-domain *("." sub-domain)
 | 
			
		||||
        sub-domain      =   Let-dig [Ldh-str]
 | 
			
		||||
        Let-dig         =   ALPHA / DIGIT
 | 
			
		||||
        Ldh-str         =   *( ALPHA / DIGIT / "-" ) Let-dig
 | 
			
		||||
 | 
			
		||||
        ALPHA           =   %x41-5A / %x61-7A        ; a-z, A-Z
 | 
			
		||||
        DIGIT           =   %x30-39                  ; 0-9
 | 
			
		||||
 | 
			
		||||
    From RFC 6531:
 | 
			
		||||
 | 
			
		||||
        sub-domain      =/  U-label
 | 
			
		||||
        atext           =/  UTF8-non-ascii
 | 
			
		||||
 | 
			
		||||
        UTF8-non-ascii  =   UTF8-2 / UTF8-3 / UTF8-4
 | 
			
		||||
 | 
			
		||||
        UTF8-2          =   %xC2-DF UTF8-tail
 | 
			
		||||
        UTF8-3          =   %xE0 %xA0-BF UTF8-tail /
 | 
			
		||||
                            %xE1-EC 2( UTF8-tail ) /
 | 
			
		||||
                            %xED %x80-9F UTF8-tail /
 | 
			
		||||
                            %xEE-EF 2( UTF8-tail )
 | 
			
		||||
        UTF8-4          =   %xF0 %x90-BF 2( UTF8-tail ) /
 | 
			
		||||
                            %xF1-F3 3( UTF8-tail ) /
 | 
			
		||||
                            %xF4 %x80-8F 2( UTF8-tail )
 | 
			
		||||
 | 
			
		||||
        UTF8-tail       =   %x80-BF
 | 
			
		||||
 | 
			
		||||
    Note: The following are not supported:
 | 
			
		||||
 | 
			
		||||
        RFC 5321: address-literal, Quoted-string
 | 
			
		||||
        RFC 5322: obs-*, CFWS
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
internals.atextRx = /^[\w!#\$%&'\*\+\-/=\?\^`\{\|\}~]+$/;               // _ included in \w
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
internals.atomRx = new RegExp([
 | 
			
		||||
 | 
			
		||||
    //  %xC2-DF UTF8-tail
 | 
			
		||||
    '(?:[\\xc2-\\xdf][\\x80-\\xbf])',
 | 
			
		||||
 | 
			
		||||
    //  %xE0 %xA0-BF UTF8-tail              %xE1-EC 2( UTF8-tail )            %xED %x80-9F UTF8-tail              %xEE-EF 2( UTF8-tail )
 | 
			
		||||
    '(?:\\xe0[\\xa0-\\xbf][\\x80-\\xbf])|(?:[\\xe1-\\xec][\\x80-\\xbf]{2})|(?:\\xed[\\x80-\\x9f][\\x80-\\xbf])|(?:[\\xee-\\xef][\\x80-\\xbf]{2})',
 | 
			
		||||
 | 
			
		||||
    //  %xF0 %x90-BF 2( UTF8-tail )            %xF1-F3 3( UTF8-tail )            %xF4 %x80-8F 2( UTF8-tail )
 | 
			
		||||
    '(?:\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2})|(?:[\\xf1-\\xf3][\\x80-\\xbf]{3})|(?:\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2})'
 | 
			
		||||
 | 
			
		||||
].join('|'));
 | 
			
		||||
		Reference in New Issue
	
	Block a user