@email-utils/validator-syntax 1.0.0-rc.1 → 1.0.0-rc.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["tlds"],"sources":["../src/chars.ts","../src/options.ts","../src/idn.ts","../src/ip.ts","../node_modules/tlds/index.json","../src/tld.ts","../src/parse.ts","../src/index.ts"],"sourcesContent":["// Character classes as bit flags over ASCII, so each preset names the class\n// its atoms and labels are made of and the scanner tests one table entry.\n\n/** RFC 5322 atext: letters, digits, and ``!#$%&'*+-/=?^_`{|}~``. */\nexport const ATEXT = 1;\n/** atext without the `%` and `!` route characters. */\nexport const PRACTICAL = 2;\n/** The WHATWG `input[type=email]` local part: atext plus `.` anywhere. */\nexport const HTML5 = 4;\n/** A hostname label: letters, digits, and `-`. */\nexport const LDH = 8;\n\nconst table = new Uint8Array(128);\n\nfunction mark(chars: string, flag: number): void {\n for (let i = 0; i < chars.length; i++) {\n table[chars.charCodeAt(i)]! |= flag;\n }\n}\n\nconst alnum = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';\nmark(alnum + \"!#$%&'*+-/=?^_`{|}~\", ATEXT);\nmark(alnum + \"#$&'*+-/=?^_`{|}~\", PRACTICAL);\nmark(alnum + \"!#$%&'*+-/=?^_`{|}~.\", HTML5);\nmark(alnum + '-', LDH);\n\n/** Whether the character with this code is in the class `flag`. */\nexport function inClass(code: number, flag: number): boolean {\n return code < 128 && (table[code]! & flag) !== 0;\n}\n\n/** Space, tab, CR, and LF: the characters folding whitespace is made of. */\nexport function isWhitespace(code: number): boolean {\n return code === 32 || code === 9 || code === 13 || code === 10;\n}\n\n/**\n * The code units in the non-ASCII code point at `i`, before `end`: 2 for a\n * surrogate pair, 1 for anything else outside ASCII, and 0 for ASCII or a\n * lone surrogate, which no UTF-8 text can hold.\n */\nexport function nonAsciiAt(text: string, i: number, end: number): number {\n const code = text.charCodeAt(i);\n if (code < 128 || (code >= 0xdc00 && code <= 0xdfff)) {\n return 0;\n }\n if (code < 0xd800 || code > 0xdbff) {\n return 1;\n }\n const low = i + 1 < end ? text.charCodeAt(i + 1) : 0;\n return low >= 0xdc00 && low <= 0xdfff ? 2 : 0;\n}\n\n/** The length of `text` in UTF-8 octets, the unit RFC 6531 caps a local part in. */\nexport function utf8Length(text: string): number {\n let octets = text.length;\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n // A surrogate pair is 2 units and 4 octets; the rest outside ASCII are\n // 1 unit and 2 or 3 octets.\n if (code >= 0x800 && (code < 0xd800 || code > 0xdfff)) {\n octets += 2;\n } else if (code >= 0x80) {\n octets += 1;\n }\n }\n return octets;\n}\n","// The presets and the flat overrides on top of them (docs/api/\n// validator-syntax.md in meta, decision S1), resolved once into the rules\n// the parser runs.\nimport { ATEXT, HTML5, LDH, PRACTICAL } from './chars';\n\n/** A base rule set; see {@link SyntaxOptions.preset}. */\nexport type Preset = 'practical' | 'rfc5321' | 'rfc5322' | 'html5';\n\n/** Options for {@link parseAddress} and the other entry points. */\nexport interface SyntaxOptions {\n /**\n * The base rule set:\n *\n * - `practical`: what real mailboxes look like. Dot-atom local parts, hostname\n * domains, a TLD from the IANA set.\n * - `rfc5321`: what SMTP accepts on the wire, quoted local parts and IP\n * address literals included.\n * - `rfc5322`: RFC 5322's full addr-spec, comments, folding whitespace, and\n * obsolete syntax included.\n * - `html5`: exactly what a browser's `input[type=email]` accepts.\n *\n * @defaultValue `'practical'`\n */\n preset?: Preset | undefined;\n /**\n * Check the TLD against the IANA set.\n *\n * @defaultValue `true` in `practical`, `false` elsewhere\n */\n checkTld?: boolean | undefined;\n /**\n * Accept a domain with no dot, like `localhost`.\n *\n * @defaultValue `true` in `html5`, `false` elsewhere\n */\n allowNoTld?: boolean | undefined;\n /**\n * Accept RFC 5322 comments, like `ada(work)@example.com`. In `practical`\n * they may sit only at the ends of the local part and the domain; in\n * `rfc5322`, around every word and label too.\n *\n * @remarks\n * Throws `TypeError` when `true` with `rfc5321` or `html5`, whose grammars\n * have no comments.\n *\n * @defaultValue `true` in `rfc5322`, `false` elsewhere\n */\n allowComments?: boolean | undefined;\n /**\n * Accept non-ASCII characters in the local part, as RFC 6531 (SMTPUTF8)\n * does, like `用户@example.com`: in atoms and quoted strings, and in\n * comments where they're allowed. The 64 cap then counts UTF-8 octets.\n *\n * @remarks\n * Throws `TypeError` when `true` with `html5`, whose grammar is ASCII.\n *\n * @defaultValue `false`\n */\n allowUnicode?: boolean | undefined;\n /**\n * Accept internationalized domain names written as U-labels, like\n * `ada@bücher.example`. Each label must convert to an A-label\n * (`xn--bcher-kva`) under UTS #46, and the 63 and 253 caps apply to the\n * A-label form. `ParsedAddress.domain` and `tld` keep the labels as\n * written. A-labels are hostname labels, so every preset accepts them\n * without this.\n *\n * @remarks\n * Throws `TypeError` when `true` with `html5`, whose grammar is ASCII.\n *\n * @defaultValue `false`\n */\n allowIdn?: boolean | undefined;\n /**\n * Accept a domain literal: an IPv4 or `IPv6:` address literal\n * (`ada@[192.0.2.1]`), or in `rfc5322`, any text its grammar allows in\n * brackets. `false` turns them off in the RFC presets.\n *\n * @remarks\n * Throws `TypeError` when `true` with `html5`, whose grammar has none.\n *\n * @defaultValue `true` in `rfc5321` and `rfc5322`, `false` elsewhere\n */\n allowIpLiteral?: boolean | undefined;\n}\n\n/** What the parser checks, resolved from a preset and its overrides. */\nexport interface Rules {\n /** The character class of local-part atoms. */\n local: number;\n /** The character class of domain labels. */\n domain: number;\n /**\n * Quoted strings: the whole local part in `rfc5321`, any word of it with\n * `obs`.\n */\n quotes: boolean;\n /**\n * Domain literals: IPv4 and IPv6 address literals, or any dtext with `obs`.\n */\n literals: boolean;\n comments: boolean;\n /**\n * RFC 5322's obsolete syntax: folding whitespace between tokens, comments\n * between words and labels, quoted strings and atoms mixed, and control\n * characters in quoted strings, comments, escapes, and literals.\n */\n obs: boolean;\n /** The longest local part allowed. */\n localCap: number;\n /** The longest domain allowed. */\n domainCap: number;\n checkTld: boolean;\n allowNoTld: boolean;\n /** Non-ASCII in local-part atoms, quoted strings, and comments. */\n unicode: boolean;\n /** U-label domain labels. */\n idn: boolean;\n}\n\nconst presets: Readonly<Record<Preset, Readonly<Rules>>> = {\n practical: {\n local: PRACTICAL,\n domain: LDH,\n quotes: false,\n literals: false,\n comments: false,\n obs: false,\n localCap: 64,\n domainCap: 253,\n checkTld: true,\n allowNoTld: false,\n unicode: false,\n idn: false,\n },\n rfc5321: {\n local: ATEXT,\n domain: LDH,\n quotes: true,\n literals: true,\n comments: false,\n obs: false,\n localCap: 64,\n domainCap: 253,\n checkTld: false,\n allowNoTld: false,\n unicode: false,\n idn: false,\n },\n rfc5322: {\n local: ATEXT,\n domain: ATEXT,\n quotes: true,\n literals: true,\n comments: true,\n obs: true,\n localCap: Infinity,\n domainCap: 253,\n checkTld: false,\n allowNoTld: false,\n unicode: false,\n idn: false,\n },\n html5: {\n local: HTML5,\n domain: LDH,\n quotes: false,\n literals: false,\n comments: false,\n obs: false,\n localCap: Infinity,\n domainCap: Infinity,\n checkTld: false,\n allowNoTld: true,\n unicode: false,\n idn: false,\n },\n};\n\nconst overrides = [\n 'checkTld',\n 'allowNoTld',\n 'allowComments',\n 'allowUnicode',\n 'allowIdn',\n 'allowIpLiteral',\n] as const;\n\n// What each preset's grammar has no room for, so turning it on throws.\nconst unsupported: Readonly<\n Record<Preset, readonly (typeof overrides)[number][]>\n> = {\n practical: [],\n rfc5321: ['allowComments'],\n rfc5322: [],\n html5: ['allowComments', 'allowUnicode', 'allowIdn', 'allowIpLiteral'],\n};\n\n/**\n * Resolves `options` into the rules they select.\n *\n * @throws TypeError when `options` isn't an object, names an unknown option\n * or preset, gives a non-boolean override, or turns on something the\n * preset's grammar has no room for.\n */\nexport function resolve(options: SyntaxOptions | undefined): Readonly<Rules> {\n if (options === undefined) {\n return presets.practical;\n }\n if (typeof options !== 'object' || options === null) {\n throw new TypeError('Expected the options to be an object');\n }\n for (const key of Object.keys(options)) {\n if (key !== 'preset' && !(overrides as readonly string[]).includes(key)) {\n throw new TypeError(`Unknown option: ${key}`);\n }\n }\n const preset = options.preset ?? 'practical';\n if (!Object.hasOwn(presets, preset)) {\n throw new TypeError(`Unknown preset: ${preset}`);\n }\n const base = presets[preset];\n for (const key of overrides) {\n const value = options[key];\n if (value !== undefined && typeof value !== 'boolean') {\n throw new TypeError(`Expected ${key} to be a boolean`);\n }\n }\n for (const key of unsupported[preset]) {\n if (options[key] === true) {\n throw new TypeError(`${key} can’t be true with the ${preset} preset`);\n }\n }\n if (overrides.every((key) => options[key] === undefined)) {\n return base;\n }\n return {\n ...base,\n checkTld: options.checkTld ?? base.checkTld,\n allowNoTld: options.allowNoTld ?? base.allowNoTld,\n comments: options.allowComments ?? base.comments,\n unicode: options.allowUnicode ?? base.unicode,\n idn: options.allowIdn ?? base.idn,\n literals: options.allowIpLiteral ?? base.literals,\n };\n}\n","// IDN labels: a U-label (`bücher`) and its A-label (`xn--bcher-kva`), the\n// form DNS carries it in.\n\nconst ldh = /^[\\da-z-]+$/;\n\n/**\n * The A-label for a U-label, or `undefined` when UTS #46 rejects it or maps\n * it to something other than one IDN label (plain ASCII, or two labels, as\n * `。` becomes a dot).\n *\n * @remarks\n * Converts by way of the WHATWG URL host parser, which every runtime the\n * package supports has and which applies UTS #46 with its bidi and joiner\n * checks. It leaves hyphens and lengths alone, so the caller checks those.\n */\nexport function toALabel(label: string): string | undefined {\n let host: string;\n try {\n host = new URL(`http://x.${label}`).hostname;\n } catch {\n return undefined;\n }\n const aLabel = host.slice(2);\n return aLabel.startsWith('xn--') && ldh.test(aLabel) ? aLabel : undefined;\n}\n","// RFC 5321 §4.1.3 address literals: the text between the brackets of\n// `[192.0.2.1]` or `[IPv6:2001:db8::1]`.\n\nconst octet = /^\\d{1,3}$/;\nconst hexGroup = /^[\\dA-Fa-f]{1,4}$/;\n\n/** An IPv4 address: four dot-separated decimal octets, each 0–255. */\nexport function isIPv4(text: string): boolean {\n const parts = text.split('.');\n return (\n parts.length === 4 &&\n parts.every((part) => octet.test(part) && Number(part) <= 255)\n );\n}\n\n/**\n * An IPv6 address as RFC 5321 writes it: eight hex groups, or a `::` with no\n * more than six groups beside it, and either may end in an IPv4 address in\n * place of the last two groups.\n */\nexport function isIPv6(text: string): boolean {\n const colon = text.lastIndexOf(':');\n const tail = text.slice(colon + 1);\n if (tail.includes('.')) {\n // An IPv4 tail stands in for two groups, which gives RFC 5321's limits\n // for the IPv6v4 forms: six groups in full, four beside a `::`.\n if (!isIPv4(tail)) {\n return false;\n }\n text = `${text.slice(0, colon + 1)}0:0`;\n }\n const halves = text.split('::');\n if (halves.length > 2) {\n return false;\n }\n const groups = halves.flatMap((half) => (half === '' ? [] : half.split(':')));\n return (\n groups.every((group) => hexGroup.test(group)) &&\n (halves.length === 1 ? groups.length === 8 : groups.length <= 6)\n );\n}\n\n/** The text of an RFC 5321 address literal: IPv4, or `IPv6:` and IPv6. */\nexport function isAddressLiteral(text: string): boolean {\n return /^IPv6:/i.test(text) ? isIPv6(text.slice(5)) : isIPv4(text);\n}\n","","// The IANA TLD set, from the `tlds` package, which the build inlines. Built\n// on first use so importing the package costs nothing until a TLD is\n// checked. `tlds` lists IDN TLDs by their U-labels (`рф`) only, so the set\n// adds each one's A-label (`xn--p1ai`), which is the form a DNS name uses.\nimport tlds from 'tlds/index.json' with { type: 'json' };\nimport { toALabel } from './idn';\n\nlet known: ReadonlySet<string> | undefined;\n\n/** Whether `tld` is in the IANA set, as a U-label or A-label, ignoring case. */\nexport function isKnownTld(tld: string): boolean {\n known ??= buildSet();\n return known.has(tld.toLowerCase());\n}\n\nfunction buildSet(): Set<string> {\n const set = new Set(tlds);\n for (const tld of tlds) {\n if (!/^[a-z\\d]+$/.test(tld)) {\n const aLabel = toALabel(tld);\n if (aLabel !== undefined) {\n set.add(aLabel);\n }\n }\n }\n return set;\n}\n","// The address parser. One pass finds the last `@` outside a quoted string,\n// comment, or domain literal; then the local part and the domain are each\n// scanned left to right against the preset's rules, and the lengths, the\n// dot, and the TLD are checked last. The first failure wins, in the order\n// the corpus sets out (src/fixtures/index.ts).\nimport { inClass, isWhitespace, nonAsciiAt, utf8Length } from './chars';\nimport { toALabel } from './idn';\nimport { isAddressLiteral } from './ip';\nimport type { Rules } from './options';\nimport type { ReasonCode, Result } from './result';\nimport { isKnownTld } from './tld';\n\n/** An address split into its parts, as {@link parseAddress} returns it. */\nexport interface ParsedAddress {\n /** The local part, without comments or folding whitespace. */\n local: string;\n /** The domain, without comments or folding whitespace. */\n domain: string;\n /**\n * The last label; absent for a domain literal, or a dotless domain the\n * preset allows.\n */\n tld?: string;\n /** Comments in input order; empty when there are none or they aren't allowed. */\n comments: AddressComment[];\n}\n\n/** A comment lifted out of an address. */\nexport interface AddressComment {\n /** The comment's text, without the parentheses. */\n text: string;\n /**\n * Where the comment sat. RFC 5322's obsolete syntax also allows comments\n * between the words of the local part and the labels of the domain\n * (`test.(comment)test@example.com`): those are `inside-local` and\n * `inside-domain`.\n */\n position:\n | 'before-local'\n | 'inside-local'\n | 'after-local'\n | 'before-domain'\n | 'inside-domain'\n | 'after-domain';\n}\n\ntype Failure = Extract<Result<never>, { ok: false }>;\n\nconst messages: Readonly<Record<ReasonCode, string>> = {\n 'syntax.address.empty': 'The address is empty',\n 'syntax.address.no_at': 'The address has no @',\n 'syntax.address.too_long': 'The address is longer than 254 characters',\n 'syntax.local.empty': 'Nothing comes before the @',\n 'syntax.local.too_long': 'The local part is longer than 64 characters',\n 'syntax.local.invalid_char': 'The local part has a character it can’t hold',\n 'syntax.local.consecutive_dots': 'The local part has two dots in a row',\n 'syntax.local.unquoted_space': 'The local part has a space outside quotes',\n 'syntax.domain.empty': 'Nothing comes after the @',\n 'syntax.domain.no_dot': 'The domain has no dot',\n 'syntax.domain.label_invalid':\n 'A domain label is empty, too long, or starts or ends with a hyphen',\n 'syntax.domain.literal_invalid': 'The domain literal isn’t accepted',\n 'syntax.domain.too_long': 'The domain is longer than 253 characters',\n 'syntax.domain.invalid_char': 'The domain has a character it can’t hold',\n 'syntax.comment.not_allowed': 'Comments aren’t allowed here',\n 'syntax.comment.unterminated': 'A comment is missing its closing parenthesis',\n 'syntax.tld.unknown': 'The TLD isn’t in the IANA set',\n};\n\nfunction fail(reason: ReasonCode, index?: number): Failure {\n const message = messages[reason];\n return index === undefined\n ? { ok: false, reason, message }\n : { ok: false, reason, message, index };\n}\n\nconst NORMAL = 0;\nconst QUOTED = 1;\nconst COMMENT = 2;\nconst LITERAL = 3;\n\n/**\n * Finds the `@` that splits `email`: the last one outside a quoted string,\n * comment, or domain literal, or -1 when there's none.\n *\n * @remarks\n * A quoted string opens only at the start of a word, and a literal only at\n * the start of the domain; both, and comments, take backslash escapes. One\n * left open runs to the end, taking any `@` with it.\n */\nexport function findAt(email: string, rules: Readonly<Rules>): number {\n let state = NORMAL;\n // Whitespace and comments don't end a word start or a domain start.\n let wordStart = true;\n let domainStart = false;\n let depth = 0;\n let at = -1;\n for (let i = 0; i < email.length; i++) {\n const code = email.charCodeAt(i);\n if (state === NORMAL) {\n if (code === 64 /* @ */) {\n at = i;\n wordStart = true;\n domainStart = true;\n } else if (code === 40 /* ( */ && rules.comments) {\n state = COMMENT;\n depth = 1;\n } else if (!isWhitespace(code)) {\n if (code === 34 /* \" */ && rules.quotes && wordStart) {\n state = QUOTED;\n } else if (code === 91 /* [ */ && rules.literals && domainStart) {\n state = LITERAL;\n }\n wordStart = code === 46; /* . */\n domainStart = false;\n }\n } else if (code === 92 /* \\ */) {\n i++;\n } else if (state === COMMENT) {\n if (code === 40) {\n depth++;\n } else if (code === 41 /* ) */ && --depth === 0) {\n state = NORMAL;\n }\n } else if (code === (state === QUOTED ? 34 : 93) /* \" or ] */) {\n state = NORMAL;\n }\n }\n return at;\n}\n\n/**\n * Parses `email` under `rules`.\n *\n * @throws TypeError when `email` isn't a string.\n */\nexport function parse(\n email: string,\n rules: Readonly<Rules>,\n): Result<ParsedAddress> {\n if (typeof email !== 'string') {\n throw new TypeError(`Expected a string, got ${typeof email}`);\n }\n if (email === '') {\n return fail('syntax.address.empty');\n }\n const at = findAt(email, rules);\n if (at < 0) {\n return fail('syntax.address.no_at');\n }\n const comments: AddressComment[] = [];\n const local = scanLocal(email, at, rules, comments);\n if (typeof local !== 'string') {\n return local;\n }\n // RFC 6531 keeps the caps in octets, and DNS counts a domain's A-labels.\n const localSize = rules.unicode ? utf8Length(local) : local.length;\n if (localSize > rules.localCap) {\n return fail('syntax.local.too_long');\n }\n const domain = scanDomain(email, at, rules, comments);\n if ('reason' in domain) {\n return domain;\n }\n if (domain.size > rules.domainCap) {\n return fail('syntax.domain.too_long');\n }\n if (localSize + 1 + domain.size > 254) {\n return fail('syntax.address.too_long');\n }\n const { tld } = domain;\n if (tld === undefined && !domain.literal && !rules.allowNoTld) {\n return fail('syntax.domain.no_dot');\n }\n if (tld !== undefined && rules.checkTld && !isKnownTld(tld)) {\n return fail('syntax.tld.unknown');\n }\n return {\n ok: true,\n value:\n tld === undefined\n ? { local, domain: domain.domain, comments }\n : { local, domain: domain.domain, tld, comments },\n };\n}\n\n/**\n * Scans the local part, `email` up to `at`, and returns it without comments\n * or folding whitespace.\n */\nfunction scanLocal(\n email: string,\n at: number,\n rules: Readonly<Rules>,\n comments: AddressComment[],\n): string | Failure {\n let local = '';\n let words = 0;\n // The last token was a word, so a dot or the end comes next.\n let afterWord = false;\n // An rfc5321 quoted string, which must be the whole local part.\n let closed = false;\n // The dot a word should follow next, or -1.\n let dot = -1;\n // The first whitespace since the last word, or -1.\n let space = -1;\n // A comment after a word where only the end may follow it, or -1.\n let edge = -1;\n // Comments from here on have no word after them.\n let trailing = comments.length;\n\n let i = 0;\n while (i < at) {\n const code = email.charCodeAt(i);\n const quote = code === 34 && rules.quotes && (rules.obs || i === 0);\n const atom = inClass(code, rules.local);\n if (quote || atom || (rules.unicode && nonAsciiAt(email, i, at) > 0)) {\n if (edge >= 0) {\n return fail('syntax.comment.not_allowed', edge);\n }\n if (afterWord) {\n return space >= 0\n ? fail('syntax.local.unquoted_space', space)\n : fail('syntax.local.invalid_char', i);\n }\n let next: number;\n if (quote) {\n next = skipQuoted(email, i, at, rules.obs, rules.unicode);\n if (next < 0) {\n return fail('syntax.local.invalid_char', -1 - next);\n }\n closed = !rules.obs;\n } else {\n next = atom ? i + 1 : i;\n while (next < at && inClass(email.charCodeAt(next), rules.local)) {\n next++;\n }\n if (rules.unicode) {\n next = skipUnicode(email, next, at, rules.local);\n }\n }\n local += unfold(email.slice(i, next));\n words++;\n afterWord = true;\n dot = -1;\n space = -1;\n trailing = comments.length;\n i = next;\n } else if (code === 46 /* . */) {\n if (edge >= 0) {\n return fail('syntax.comment.not_allowed', edge);\n }\n if (!afterWord || closed) {\n return dot >= 0\n ? fail('syntax.local.consecutive_dots', i)\n : fail('syntax.local.invalid_char', i);\n }\n local += '.';\n afterWord = false;\n dot = i;\n space = -1;\n i++;\n } else if (code === 40 /* ( */ && rules.comments) {\n if (!rules.obs && words > 0) {\n // Without the obsolete syntax, comments sit only at the ends.\n if (!afterWord) {\n return fail('syntax.comment.not_allowed', i);\n }\n edge = edge < 0 ? i : edge;\n }\n const next = skipComment(email, i, at, rules.unicode);\n if (next < 0) {\n return fail('syntax.local.invalid_char', -1 - next);\n }\n comments.push({\n text: email.slice(i + 1, next - 1),\n position: words === 0 ? 'before-local' : 'inside-local',\n });\n i = next;\n } else if (code === 40) {\n return fail('syntax.comment.not_allowed', i);\n } else if (rules.obs && isWhitespace(code)) {\n const next = skipSpace(email, i, at);\n if (next < 0) {\n return fail('syntax.local.invalid_char', i);\n }\n space = space < 0 ? i : space;\n i = next;\n } else {\n return code === 32\n ? fail('syntax.local.unquoted_space', i)\n : fail('syntax.local.invalid_char', i);\n }\n }\n\n if (words === 0) {\n return fail('syntax.local.empty');\n }\n if (dot >= 0) {\n return fail('syntax.local.invalid_char', dot);\n }\n settle(comments, trailing, 'after-local');\n return local;\n}\n\ninterface Domain {\n domain: string;\n tld?: string;\n literal: boolean;\n /** The domain's length with its U-labels as A-labels. */\n size: number;\n}\n\n/**\n * Scans the domain, `email` after `at`, and returns it without comments or\n * folding whitespace.\n */\nfunction scanDomain(\n email: string,\n at: number,\n rules: Readonly<Rules>,\n comments: AddressComment[],\n): Domain | Failure {\n const end = email.length;\n let domain = '';\n let labels = 0;\n let afterLabel = false;\n let literal = false;\n let dot = -1;\n let space = -1;\n let edge = -1;\n let trailing = comments.length;\n let tld = '';\n // What converting the U-labels to A-labels adds to the length.\n let growth = 0;\n\n let i = at + 1;\n while (i < end) {\n const code = email.charCodeAt(i);\n const opensLiteral = code === 91 && rules.literals && labels === 0;\n const ldh = inClass(code, rules.domain);\n if (opensLiteral || ldh || (rules.idn && nonAsciiAt(email, i, end) > 0)) {\n if (edge >= 0) {\n return fail('syntax.comment.not_allowed', edge);\n }\n if (afterLabel) {\n return fail('syntax.domain.invalid_char', space >= 0 ? space : i);\n }\n let next: number;\n if (opensLiteral) {\n next = rules.obs\n ? skipLiteral(email, i, end)\n : skipAddressLiteral(email, i, end);\n if (next < 0) {\n return fail('syntax.domain.literal_invalid', i);\n }\n literal = true;\n } else {\n next = ldh ? i + 1 : i;\n while (next < end && inClass(email.charCodeAt(next), rules.domain)) {\n next++;\n }\n const ascii = next;\n if (rules.idn) {\n next = skipUnicode(email, next, end, rules.domain);\n }\n let size = next - i;\n // The ASCII run stopped short, so the label is a U-label.\n if (next > ascii) {\n const aLabel = toALabel(email.slice(i, next));\n if (aLabel === undefined) {\n return fail('syntax.domain.label_invalid', i);\n }\n size = aLabel.length;\n growth += size - (next - i);\n }\n const bad = checkLabel(email, i, next, size);\n if (bad >= 0) {\n return fail('syntax.domain.label_invalid', bad);\n }\n }\n tld = unfold(email.slice(i, next));\n domain += tld;\n labels++;\n afterLabel = true;\n dot = -1;\n space = -1;\n trailing = comments.length;\n i = next;\n } else if (code === 46 /* . */) {\n if (edge >= 0) {\n return fail('syntax.comment.not_allowed', edge);\n }\n if (!afterLabel || literal) {\n return literal\n ? fail('syntax.domain.invalid_char', i)\n : fail('syntax.domain.label_invalid', i);\n }\n domain += '.';\n afterLabel = false;\n dot = i;\n space = -1;\n i++;\n } else if (code === 40 /* ( */ && rules.comments) {\n if (!rules.obs && labels > 0) {\n if (!afterLabel) {\n return fail('syntax.comment.not_allowed', i);\n }\n edge = edge < 0 ? i : edge;\n }\n const next = skipComment(email, i, end, rules.unicode);\n if (next < 0) {\n return -1 - next === i\n ? fail('syntax.comment.unterminated', i)\n : fail('syntax.domain.invalid_char', -1 - next);\n }\n comments.push({\n text: email.slice(i + 1, next - 1),\n position: labels === 0 ? 'before-domain' : 'inside-domain',\n });\n i = next;\n } else if (code === 40) {\n return fail('syntax.comment.not_allowed', i);\n } else if (rules.obs && isWhitespace(code)) {\n const next = skipSpace(email, i, end);\n if (next < 0) {\n return fail('syntax.domain.invalid_char', i);\n }\n space = space < 0 ? i : space;\n i = next;\n } else {\n return fail('syntax.domain.invalid_char', i);\n }\n }\n\n if (labels === 0) {\n return fail('syntax.domain.empty');\n }\n if (dot >= 0) {\n return fail('syntax.domain.label_invalid', dot);\n }\n settle(comments, trailing, 'after-domain');\n const size = domain.length + growth;\n return literal || labels === 1\n ? { domain, literal, size }\n : { domain, tld, literal, size };\n}\n\n/**\n * Carries an atom or label on from `i`, where its ASCII run stopped, through\n * any non-ASCII characters and the class-`flag` characters after them.\n */\nfunction skipUnicode(\n email: string,\n i: number,\n end: number,\n flag: number,\n): number {\n let width = i < end ? nonAsciiAt(email, i, end) : 0;\n while (width > 0) {\n i += width;\n while (i < end && inClass(email.charCodeAt(i), flag)) {\n i++;\n }\n width = i < end ? nonAsciiAt(email, i, end) : 0;\n }\n return i;\n}\n\n/**\n * Checks the hostname label from `start` to `end`, `size` characters long as\n * an A-label: returns the index of a leading or trailing hyphen, the start of\n * a label over 63 characters, or -1.\n */\nfunction checkLabel(\n email: string,\n start: number,\n end: number,\n size: number,\n): number {\n if (email.charCodeAt(start) === 45 /* - */) {\n return start;\n }\n if (size > 63) {\n return start;\n }\n return email.charCodeAt(end - 1) === 45 ? end - 1 : -1;\n}\n\n/** Marks the comments from `from` on, which no word follows, as trailing. */\nfunction settle(\n comments: AddressComment[],\n from: number,\n position: 'after-local' | 'after-domain',\n): void {\n for (let c = from; c < comments.length; c++) {\n const comment = comments[c]!;\n if (comment.position.startsWith('inside')) {\n comment.position = position;\n }\n }\n}\n\n/** Removes the CRLFs of folding whitespace, keeping the space or tab after. */\nfunction unfold(text: string): string {\n return text.includes('\\r') ? text.replaceAll('\\r\\n', '') : text;\n}\n\n// The skip functions below return the index after what they scanned, or\n// `-1 - j` for the first character `j` that breaks it.\n\n/**\n * Skips one character of folding whitespace: a space, a tab, or a CRLF with\n * a space or tab after it. A lone CR or LF breaks it.\n */\nfunction skipSpace(email: string, i: number, end: number): number {\n const code = email.charCodeAt(i);\n if (code === 32 || code === 9) {\n return i + 1;\n }\n return code === 13 &&\n i + 2 < end &&\n email.charCodeAt(i + 1) === 10 &&\n (email.charCodeAt(i + 2) === 32 || email.charCodeAt(i + 2) === 9)\n ? i + 2\n : -1 - i;\n}\n\n/** Whether a backslash may escape `code`: any ASCII with `obs`, else VCHAR and space. */\nfunction escapable(code: number, obs: boolean): boolean {\n return obs ? code < 128 : code >= 32 && code <= 126;\n}\n\n/**\n * Skips the quoted string opening at `open`. `obs` allows folding whitespace\n * and control characters other than NUL; without it, the string follows\n * RFC 5321: printable ASCII and spaces only. `unicode` adds non-ASCII.\n */\nfunction skipQuoted(\n email: string,\n open: number,\n end: number,\n obs: boolean,\n unicode: boolean,\n): number {\n let i = open + 1;\n while (i < end) {\n const code = email.charCodeAt(i);\n if (code === 34) {\n return i + 1;\n }\n if (code === 92) {\n if (!escapable(email.charCodeAt(i + 1), obs)) {\n return -2 - i;\n }\n i += 2;\n } else if (obs && isWhitespace(code)) {\n i = skipSpace(email, i, end);\n if (i < 0) {\n return i;\n }\n } else if (obs ? code === 0 || code > 127 : code < 32 || code > 126) {\n const width = unicode ? nonAsciiAt(email, i, end) : 0;\n if (width === 0) {\n return -1 - i;\n }\n i += width;\n } else {\n i++;\n }\n }\n // findAt only splits after a quoted string that closes.\n return -1 - open;\n}\n\n/**\n * Skips the comment opening at `open`, nested comments included. Its text\n * may hold any ASCII but NUL, with folding whitespace, and non-ASCII with\n * `unicode`; returns `-1 - open` when it never closes.\n */\nfunction skipComment(\n email: string,\n open: number,\n end: number,\n unicode: boolean,\n): number {\n let depth = 1;\n let i = open + 1;\n while (i < end) {\n const code = email.charCodeAt(i);\n if (code === 40 /* ( */ || code === 41 /* ) */) {\n depth += code === 40 ? 1 : -1;\n i++;\n if (depth === 0) {\n return i;\n }\n } else if (code === 92) {\n if (i + 1 >= end) {\n break;\n }\n if (!escapable(email.charCodeAt(i + 1), true)) {\n return -2 - i;\n }\n i += 2;\n } else if (isWhitespace(code)) {\n i = skipSpace(email, i, end);\n if (i < 0) {\n return i;\n }\n } else if (code === 0 || code > 127) {\n const width = unicode ? nonAsciiAt(email, i, end) : 0;\n if (width === 0) {\n return -1 - i;\n }\n i += width;\n } else {\n i++;\n }\n }\n return -1 - open;\n}\n\n/**\n * Skips the RFC 5322 domain literal opening at `open`: any ASCII but NUL,\n * `[`, and `]`, with escapes and folding whitespace. Returns -1 when it's\n * malformed or never closes.\n */\nfunction skipLiteral(email: string, open: number, end: number): number {\n let i = open + 1;\n while (i < end) {\n const code = email.charCodeAt(i);\n if (code === 93 /* ] */) {\n return i + 1;\n }\n if (code === 92) {\n if (i + 1 >= end || !escapable(email.charCodeAt(i + 1), true)) {\n return -1;\n }\n i += 2;\n } else if (isWhitespace(code)) {\n i = skipSpace(email, i, end);\n if (i < 0) {\n return -1;\n }\n } else if (code === 0 || code === 91 || code > 127) {\n return -1;\n } else {\n i++;\n }\n }\n return -1;\n}\n\n/**\n * Skips the RFC 5321 address literal opening at `open`: an IPv4 address or\n * `IPv6:` and an IPv6 address. Returns -1 for anything else.\n */\nfunction skipAddressLiteral(email: string, open: number, end: number): number {\n const close = email.indexOf(']', open + 1);\n return close >= 0 &&\n close < end &&\n isAddressLiteral(email.slice(open + 1, close))\n ? close + 1\n : -1;\n}\n","/**\n * Is the address well-formed? A quote-aware parser with four presets:\n * `practical` (the default), `rfc5321`, `rfc5322`, and `html5`.\n *\n * @packageDocumentation\n */\nimport { type SyntaxOptions, resolve } from './options';\nimport { type ParsedAddress, parse } from './parse';\nimport type { Result } from './result';\n\nexport type { Preset, SyntaxOptions } from './options';\nexport type { AddressComment, ParsedAddress } from './parse';\nexport type { ReasonCode, Result } from './result';\n\n/**\n * Parses `email` into its local part, domain, TLD, and comments, or returns\n * the first check it fails.\n *\n * @remarks\n * The local part is checked before the domain, each left to right, then the\n * lengths, then a dotless domain, then the TLD. `index`, where a failure has\n * one, points at the offending character.\n *\n * @example\n * ```ts\n * const result = parseAddress('ada.lovelace@example.co.uk');\n * if (result.ok) {\n * result.value.tld; // 'uk'\n * } else {\n * result.reason; // e.g. 'syntax.local.invalid_char'\n * }\n * ```\n *\n * @throws TypeError when `email` isn't a string, or `options` are malformed.\n */\nexport function parseAddress(\n email: string,\n options?: SyntaxOptions,\n): Result<ParsedAddress> {\n return parse(email, resolve(options));\n}\n\n/**\n * Whether `email` is well-formed: exactly `parseAddress(email, options).ok`.\n *\n * @example\n * ```ts\n * isValidSyntax('ada@example.com'); // true\n * isValidSyntax('\"ada\"@example.com'); // false\n * isValidSyntax('\"ada\"@example.com', { preset: 'rfc5321' }); // true\n * ```\n *\n * @throws TypeError when `email` isn't a string, or `options` are malformed.\n */\nexport function isValidSyntax(email: string, options?: SyntaxOptions): boolean {\n return parse(email, resolve(options)).ok;\n}\n\n/** {@link parseAddress} and {@link isValidSyntax} with options bound. */\nexport interface SyntaxValidator {\n parse(email: string): Result<ParsedAddress>;\n isValid(email: string): boolean;\n}\n\n/**\n * Binds `options` once, checking them up front, and returns\n * {@link parseAddress} and {@link isValidSyntax} with them applied.\n *\n * @example\n * ```ts\n * const strict = createSyntaxValidator({ preset: 'rfc5321' });\n * strict.parse('a b@example.com'); // { ok: false, reason: 'syntax.local.unquoted_space', … }\n * strict.isValid('\"a b\"@example.com'); // true\n * ```\n *\n * @throws TypeError when `options` are malformed.\n */\nexport function createSyntaxValidator(\n options?: SyntaxOptions,\n): SyntaxValidator {\n const rules = resolve(options);\n return {\n parse: (email) => parse(email, rules),\n isValid: (email) => parse(email, rules).ok,\n };\n}\n"],"x_google_ignoreList":[4],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
1
+ {"version":3,"file":"index.mjs","names":["tlds"],"sources":["../src/chars.ts","../src/options.ts","../src/idn.ts","../src/ip.ts","../node_modules/tlds/index.json","../src/tld.ts","../src/parse.ts","../src/index.ts"],"sourcesContent":["// Character classes as bit flags over ASCII, so each preset names the class\n// its atoms and labels are made of and the scanner tests one table entry.\n\n// oxlint-disable-next-line typescript/unbound-method -- only ever called with `.call`\nconst charCodeAt = String.prototype.charCodeAt;\n\n/**\n * `text.charCodeAt(i)`, through the builtin itself. Called as a method,\n * `charCodeAt` is looked up on the string, and a call site that has seen\n * enough kinds of string (one-byte and two-byte, flat, sliced, and\n * concatenated) goes megamorphic: V8 stops inlining it, and after arbitrary\n * Unicode input every scan ran 2–3× slower (validator-syntax#15).\n */\nexport function codeAt(text: string, i: number): number {\n return charCodeAt.call(text, i);\n}\n\n/** RFC 5322 atext: letters, digits, and ``!#$%&'*+-/=?^_`{|}~``. */\nexport const ATEXT = 1;\n/** atext without the `%` and `!` route characters. */\nexport const PRACTICAL = 2;\n/** The WHATWG `input[type=email]` local part: atext plus `.` anywhere. */\nexport const HTML5 = 4;\n/** A hostname label: letters, digits, and `-`. */\nexport const LDH = 8;\n\nconst table = new Uint8Array(128);\n\nfunction mark(chars: string, flag: number): void {\n for (let i = 0; i < chars.length; i++) {\n table[codeAt(chars, i)]! |= flag;\n }\n}\n\nconst alnum = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';\nmark(alnum + \"!#$%&'*+-/=?^_`{|}~\", ATEXT);\nmark(alnum + \"#$&'*+-/=?^_`{|}~\", PRACTICAL);\nmark(alnum + \"!#$%&'*+-/=?^_`{|}~.\", HTML5);\nmark(alnum + '-', LDH);\n\n/** Whether the character with this code is in the class `flag`. */\nexport function inClass(code: number, flag: number): boolean {\n return code < 128 && (table[code]! & flag) !== 0;\n}\n\n/** Space, tab, CR, and LF: the characters folding whitespace is made of. */\nexport function isWhitespace(code: number): boolean {\n return code === 32 || code === 9 || code === 13 || code === 10;\n}\n\n/**\n * The code units in the non-ASCII code point at `i`, before `end`: 2 for a\n * surrogate pair, 1 for anything else outside ASCII, and 0 for ASCII or a\n * lone surrogate, which no UTF-8 text can hold.\n */\nexport function nonAsciiAt(text: string, i: number, end: number): number {\n const code = codeAt(text, i);\n if (code < 128 || (code >= 0xdc00 && code <= 0xdfff)) {\n return 0;\n }\n if (code < 0xd800 || code > 0xdbff) {\n return 1;\n }\n const low = i + 1 < end ? codeAt(text, i + 1) : 0;\n return low >= 0xdc00 && low <= 0xdfff ? 2 : 0;\n}\n\n/** The length of `text` in UTF-8 octets, the unit RFC 6531 caps a local part in. */\nexport function utf8Length(text: string): number {\n const end = text.length;\n let octets = end;\n for (let i = 0; i < end; i++) {\n const code = codeAt(text, i);\n // A surrogate pair is 2 units and 4 octets; the rest outside ASCII are\n // 1 unit and 2 or 3 octets.\n if (code >= 0x800 && (code < 0xd800 || code > 0xdfff)) {\n octets += 2;\n } else if (code >= 0x80) {\n octets += 1;\n }\n }\n return octets;\n}\n\n/**\n * The code points in `text` from `start` to `end`, which must not split a\n * surrogate pair: its length with each pair counted once.\n */\nexport function codePoints(text: string, start: number, end: number): number {\n let count = end - start;\n for (let i = start; i < end; i++) {\n const code = codeAt(text, i);\n if (code >= 0xdc00 && code <= 0xdfff) {\n count--;\n }\n }\n return count;\n}\n","// The presets and the flat overrides on top of them (docs/api/\n// validator-syntax.md in meta, decision S1), resolved once into the rules\n// the parser runs.\nimport { ATEXT, HTML5, LDH, PRACTICAL } from './chars';\n\n/** A base rule set; see {@link SyntaxOptions.preset}. */\nexport type Preset = 'practical' | 'rfc5321' | 'rfc5322' | 'html5';\n\n/** Options for {@link parseAddress} and the other entry points. */\nexport interface SyntaxOptions {\n /**\n * The base rule set:\n *\n * - `practical`: what real mailboxes look like. Dot-atom local parts, hostname\n * domains, a TLD from the IANA set.\n * - `rfc5321`: what SMTP accepts on the wire, quoted local parts and IP\n * address literals included.\n * - `rfc5322`: RFC 5322's full addr-spec, comments, folding whitespace, and\n * obsolete syntax included.\n * - `html5`: exactly what a browser's `input[type=email]` accepts.\n *\n * @defaultValue `'practical'`\n */\n preset?: Preset | undefined;\n /**\n * Check the TLD against the IANA set.\n *\n * @defaultValue `true` in `practical`, `false` elsewhere\n */\n checkTld?: boolean | undefined;\n /**\n * Accept a domain with no dot, like `localhost`.\n *\n * @defaultValue `true` in `html5`, `false` elsewhere\n */\n allowNoTld?: boolean | undefined;\n /**\n * Accept RFC 5322 comments, like `ada(work)@example.com`. In `practical`\n * they may sit only at the ends of the local part and the domain; in\n * `rfc5322`, around every word and label too.\n *\n * @remarks\n * Throws `TypeError` when `true` with `rfc5321` or `html5`, whose grammars\n * have no comments.\n *\n * @defaultValue `true` in `rfc5322`, `false` elsewhere\n */\n allowComments?: boolean | undefined;\n /**\n * Accept non-ASCII characters in the local part, as RFC 6531 (SMTPUTF8)\n * does, like `用户@example.com`: in atoms and quoted strings, and in\n * comments where they're allowed. The 64 cap then counts UTF-8 octets.\n *\n * @remarks\n * Throws `TypeError` when `true` with `html5`, whose grammar is ASCII.\n *\n * @defaultValue `false`\n */\n allowUnicode?: boolean | undefined;\n /**\n * Accept internationalized domain names written as U-labels, like\n * `ada@bücher.example`. Each label must convert to an A-label\n * (`xn--bcher-kva`) under UTS #46, and the 63 and 253 caps apply to the\n * A-label form. `ParsedAddress.domain` and `tld` keep the labels as\n * written. A-labels are hostname labels, so every preset accepts them\n * without this.\n *\n * @remarks\n * Throws `TypeError` when `true` with `html5`, whose grammar is ASCII.\n *\n * @defaultValue `false`\n */\n allowIdn?: boolean | undefined;\n /**\n * Accept a domain literal: an IPv4 or `IPv6:` address literal\n * (`ada@[192.0.2.1]`), or in `rfc5322`, any text its grammar allows in\n * brackets. `false` turns them off in the RFC presets.\n *\n * @remarks\n * Throws `TypeError` when `true` with `html5`, whose grammar has none.\n *\n * @defaultValue `true` in `rfc5321` and `rfc5322`, `false` elsewhere\n */\n allowIpLiteral?: boolean | undefined;\n /**\n * The longest input accepted, counted in UTF-16 code units, as\n * `email.length` counts. Longer input fails as `syntax.address.too_long`\n * before it's scanned, so it's rejected in constant time however long it\n * is. A positive integer, or `Infinity` for no limit.\n *\n * @remarks\n * The address caps (254 characters, and 64 and 253 for the local part and\n * domain where the preset has them) still apply within it. This bounds the\n * input as written, comments and folding whitespace included, which those\n * caps don't count. Throws `TypeError` when it isn't a positive integer or\n * `Infinity`.\n *\n * @defaultValue `512` in every preset\n */\n maxLength?: number | undefined;\n}\n\n/** What the parser checks, resolved from a preset and its overrides. */\nexport interface Rules {\n /** The character class of local-part atoms. */\n local: number;\n /** The character class of domain labels. */\n domain: number;\n /**\n * Quoted strings: the whole local part in `rfc5321`, any word of it with\n * `obs`.\n */\n quotes: boolean;\n /**\n * Domain literals: IPv4 and IPv6 address literals, or any dtext with `obs`.\n */\n literals: boolean;\n comments: boolean;\n /**\n * RFC 5322's obsolete syntax: folding whitespace between tokens, comments\n * between words and labels, quoted strings and atoms mixed, and control\n * characters in quoted strings, comments, escapes, and literals.\n */\n obs: boolean;\n /** The longest local part allowed. */\n localCap: number;\n /** The longest domain allowed. */\n domainCap: number;\n checkTld: boolean;\n allowNoTld: boolean;\n /** Non-ASCII in local-part atoms, quoted strings, and comments. */\n unicode: boolean;\n /** U-label domain labels. */\n idn: boolean;\n /** The longest input scanned, in UTF-16 code units. */\n maxLength: number;\n}\n\nconst presets: Readonly<Record<Preset, Readonly<Rules>>> = {\n practical: {\n local: PRACTICAL,\n domain: LDH,\n quotes: false,\n literals: false,\n comments: false,\n obs: false,\n localCap: 64,\n domainCap: 253,\n checkTld: true,\n allowNoTld: false,\n unicode: false,\n idn: false,\n maxLength: 512,\n },\n rfc5321: {\n local: ATEXT,\n domain: LDH,\n quotes: true,\n literals: true,\n comments: false,\n obs: false,\n localCap: 64,\n domainCap: 253,\n checkTld: false,\n allowNoTld: false,\n unicode: false,\n idn: false,\n maxLength: 512,\n },\n rfc5322: {\n local: ATEXT,\n domain: ATEXT,\n quotes: true,\n literals: true,\n comments: true,\n obs: true,\n localCap: Infinity,\n domainCap: 253,\n checkTld: false,\n allowNoTld: false,\n unicode: false,\n idn: false,\n maxLength: 512,\n },\n html5: {\n local: HTML5,\n domain: LDH,\n quotes: false,\n literals: false,\n comments: false,\n obs: false,\n localCap: Infinity,\n domainCap: Infinity,\n checkTld: false,\n allowNoTld: true,\n unicode: false,\n idn: false,\n maxLength: 512,\n },\n};\n\nconst overrides = [\n 'checkTld',\n 'allowNoTld',\n 'allowComments',\n 'allowUnicode',\n 'allowIdn',\n 'allowIpLiteral',\n] as const;\n\n// What each preset's grammar has no room for, so turning it on throws.\nconst unsupported: Readonly<\n Record<Preset, readonly (typeof overrides)[number][]>\n> = {\n practical: [],\n rfc5321: ['allowComments'],\n rfc5322: [],\n html5: ['allowComments', 'allowUnicode', 'allowIdn', 'allowIpLiteral'],\n};\n\n/**\n * Resolves `options` into the rules they select.\n *\n * @throws TypeError when `options` isn't an object, names an unknown option\n * or preset, gives a non-boolean override or a `maxLength` that isn't a\n * positive integer or `Infinity`, or turns on something the preset's grammar\n * has no room for.\n */\nexport function resolve(options: SyntaxOptions | undefined): Readonly<Rules> {\n if (options === undefined) {\n return presets.practical;\n }\n if (typeof options !== 'object' || options === null) {\n throw new TypeError('Expected the options to be an object');\n }\n for (const key of Object.keys(options)) {\n if (\n key !== 'preset' &&\n key !== 'maxLength' &&\n !(overrides as readonly string[]).includes(key)\n ) {\n throw new TypeError(`Unknown option: ${key}`);\n }\n }\n const preset = options.preset ?? 'practical';\n if (!Object.hasOwn(presets, preset)) {\n throw new TypeError(`Unknown preset: ${preset}`);\n }\n const base = presets[preset];\n for (const key of overrides) {\n const value = options[key];\n if (value !== undefined && typeof value !== 'boolean') {\n throw new TypeError(`Expected ${key} to be a boolean`);\n }\n }\n const { maxLength } = options;\n if (\n maxLength !== undefined &&\n maxLength !== Infinity &&\n !(Number.isInteger(maxLength) && maxLength > 0)\n ) {\n throw new TypeError(\n 'Expected maxLength to be a positive integer or Infinity',\n );\n }\n for (const key of unsupported[preset]) {\n if (options[key] === true) {\n throw new TypeError(`${key} can’t be true with the ${preset} preset`);\n }\n }\n if (\n maxLength === undefined &&\n overrides.every((key) => options[key] === undefined)\n ) {\n return base;\n }\n return {\n ...base,\n checkTld: options.checkTld ?? base.checkTld,\n allowNoTld: options.allowNoTld ?? base.allowNoTld,\n comments: options.allowComments ?? base.comments,\n unicode: options.allowUnicode ?? base.unicode,\n idn: options.allowIdn ?? base.idn,\n literals: options.allowIpLiteral ?? base.literals,\n maxLength: maxLength ?? base.maxLength,\n };\n}\n","// IDN labels: a U-label (`bücher`) and its A-label (`xn--bcher-kva`), the\n// form DNS carries it in.\n\nconst ldh = /^[\\da-z-]+$/;\n\n/**\n * The hostname of `http://x.` and `host`, or `undefined` when the WHATWG URL\n * parser rejects it. `URL.parse` says so without the cost of throwing, a few\n * µs a time, so an address built to fail many conversions stays fast;\n * runtimes that predate it (Node before 22.1) throw instead.\n */\nconst hostnameOf: (host: string) => string | undefined =\n typeof URL.parse === 'function'\n ? (host) => URL.parse(`http://x.${host}`)?.hostname\n : (host) => {\n try {\n return new URL(`http://x.${host}`).hostname;\n } catch {\n return undefined;\n }\n };\n\n/**\n * The A-label for a U-label, or `undefined` when UTS #46 rejects it or maps\n * it to something other than one IDN label (plain ASCII, or two labels, as\n * `。` becomes a dot).\n *\n * @remarks\n * Converts by way of the WHATWG URL host parser, which every runtime the\n * package supports has and which applies UTS #46 with its bidi and joiner\n * checks. It leaves hyphens and lengths alone, so the caller checks those.\n */\nexport function toALabel(label: string): string | undefined {\n const aLabel = hostnameOf(label)?.slice(2);\n return aLabel?.startsWith('xn--') === true && ldh.test(aLabel)\n ? aLabel\n : undefined;\n}\n\n// Characters of the right-to-left scripts, and the ones UTS #46 maps to\n// them (ℵ to א). A domain with one is a Bidi domain name, which UTS #46 holds\n// to RFC 5893's rules label by label.\nconst rtl =\n /[\\u0590-\\u08ff\\u2135-\\u2138\\ufb1d-\\ufdff\\ufe70-\\ufeff\\u{10800}-\\u{10fff}\\u{1e800}-\\u{1efff}]/u;\n\n/**\n * The A-label for each U-label in `labels`, as {@link toALabel} gives it,\n * converted as few domains as it can: one URL costs about as much as one\n * label does.\n *\n * @remarks\n * Every entry up to the first `undefined` is exact; entries after it may be\n * left `undefined` unconverted. Converted together, a right-to-left label\n * would hold the others to RFC 5893's rules too, which it doesn't alone, so\n * right-to-left labels go in a domain of their own. Converting more labels\n * at once only adds rules, so a domain that converts means every label\n * would alone; one that doesn't is narrowed down to its first label that\n * fails alone.\n */\nexport function toALabels(labels: readonly string[]): (string | undefined)[] {\n if (!labels.some((label) => rtl.test(label))) {\n return convertGroup(labels);\n }\n const aLabels: (string | undefined)[] = labels.map(() => undefined);\n for (const bidi of [false, true]) {\n const members: number[] = [];\n labels.forEach((label, k) => {\n if (rtl.test(label) === bidi) {\n members.push(k);\n }\n });\n if (members.length > 0) {\n const converted = convertGroup(members.map((k) => labels[k]!));\n converted.forEach((aLabel, j) => {\n aLabels[members[j]!] = aLabel;\n });\n }\n }\n return aLabels;\n}\n\n/** {@link toALabels} for labels converted together. */\nfunction convertGroup(labels: readonly string[]): (string | undefined)[] {\n const all = convert(labels);\n if (all !== undefined) {\n return all;\n }\n // The shortest run of labels from the start that fails: `pass` converts,\n // and the first `failing` labels don't.\n let pass: string[] = [];\n let failing = labels.length;\n while (failing - pass.length > 1) {\n const some = convert(labels.slice(0, (pass.length + failing) >> 1));\n if (some === undefined) {\n failing = (pass.length + failing) >> 1;\n } else {\n pass = some;\n }\n }\n // Its last label fails, unless only alongside the others; then the labels\n // after it are converted alone, up to the first that fails.\n const aLabels: (string | undefined)[] = pass;\n for (let k = pass.length; k < labels.length; k++) {\n const aLabel = toALabel(labels[k]!);\n aLabels.push(aLabel);\n if (aLabel === undefined) {\n break;\n }\n }\n return aLabels;\n}\n\n// A converted host: `x`, then A-labels.\nconst aLabelHost = /^x(?:\\.xn--[\\da-z-]+)+$/;\n\n/** `labels` converted as one domain, or `undefined`. */\nfunction convert(labels: readonly string[]): string[] | undefined {\n const hostname = hostnameOf(labels.join('.'));\n if (hostname === undefined || !aLabelHost.test(hostname)) {\n return undefined;\n }\n const aLabels = hostname.split('.');\n aLabels.shift();\n return aLabels.length === labels.length ? aLabels : undefined;\n}\n","// RFC 5321 §4.1.3 address literals: the text between the brackets of\n// `[192.0.2.1]` or `[IPv6:2001:db8::1]`.\n\nconst octet = /^\\d{1,3}$/;\nconst hexGroup = /^[\\dA-Fa-f]{1,4}$/;\n\n/** An IPv4 address: four dot-separated decimal octets, each 0–255. */\nexport function isIPv4(text: string): boolean {\n // `255.255.255.255` is the longest, and splitting costs more than this.\n if (text.length > 15) {\n return false;\n }\n const parts = text.split('.');\n return (\n parts.length === 4 &&\n parts.every((part) => octet.test(part) && Number(part) <= 255)\n );\n}\n\n/**\n * An IPv6 address as RFC 5321 writes it: eight hex groups, or a `::` with no\n * more than six groups beside it, and either may end in an IPv4 address in\n * place of the last two groups.\n */\nexport function isIPv6(text: string): boolean {\n // Eight groups of four, or six and an IPv4 address, is the longest: 45\n // characters. Splitting a longer one would cost more than this.\n if (text.length > 45) {\n return false;\n }\n const colon = text.lastIndexOf(':');\n const tail = text.slice(colon + 1);\n if (tail.includes('.')) {\n // An IPv4 tail stands in for two groups, which gives RFC 5321's limits\n // for the IPv6v4 forms: six groups in full, four beside a `::`.\n if (!isIPv4(tail)) {\n return false;\n }\n text = `${text.slice(0, colon + 1)}0:0`;\n }\n const halves = text.split('::');\n if (halves.length > 2) {\n return false;\n }\n const groups = halves.flatMap((half) => (half === '' ? [] : half.split(':')));\n return (\n groups.every((group) => hexGroup.test(group)) &&\n (halves.length === 1 ? groups.length === 8 : groups.length <= 6)\n );\n}\n\n/** The text of an RFC 5321 address literal: IPv4, or `IPv6:` and IPv6. */\nexport function isAddressLiteral(text: string): boolean {\n return /^IPv6:/i.test(text) ? isIPv6(text.slice(5)) : isIPv4(text);\n}\n","","// The IANA TLD set, from the `tlds` package, which the build inlines. Built\n// on first use so importing the package costs nothing until a TLD is\n// checked. `tlds` lists IDN TLDs by their U-labels (`рф`) only, so the set\n// adds each one's A-label (`xn--p1ai`), which is the form a DNS name uses.\nimport tlds from 'tlds/index.json' with { type: 'json' };\nimport { toALabel } from './idn';\n\nlet known: ReadonlySet<string> | undefined;\n\n/** Whether `tld` is in the IANA set, as a U-label or A-label, ignoring case. */\nexport function isKnownTld(tld: string): boolean {\n known ??= buildSet();\n return known.has(tld.toLowerCase());\n}\n\nfunction buildSet(): Set<string> {\n const set = new Set(tlds);\n for (const tld of tlds) {\n if (!/^[a-z\\d]+$/.test(tld)) {\n const aLabel = toALabel(tld);\n if (aLabel !== undefined) {\n set.add(aLabel);\n }\n }\n }\n return set;\n}\n","// The address parser. One pass finds the last `@` outside a quoted string,\n// comment, or domain literal; then the local part and the domain are each\n// scanned left to right against the preset's rules, and the lengths, the\n// dot, and the TLD are checked last. The first failure wins, in the order\n// the corpus sets out (src/fixtures/index.ts).\nimport {\n codeAt,\n codePoints,\n inClass,\n isWhitespace,\n nonAsciiAt,\n utf8Length,\n} from './chars';\nimport { toALabels } from './idn';\nimport { isAddressLiteral } from './ip';\nimport type { Rules } from './options';\nimport type { ReasonCode, Result } from './result';\nimport { isKnownTld } from './tld';\n\n/** An address split into its parts, as {@link parseAddress} returns it. */\nexport interface ParsedAddress {\n /** The local part, without comments or folding whitespace. */\n local: string;\n /** The domain, without comments or folding whitespace. */\n domain: string;\n /**\n * The last label; absent for a domain literal, or a dotless domain the\n * preset allows.\n */\n tld?: string;\n /** Comments in input order; empty when there are none or they aren't allowed. */\n comments: AddressComment[];\n}\n\n/** A comment lifted out of an address. */\nexport interface AddressComment {\n /** The comment's text, without the parentheses. */\n text: string;\n /**\n * Where the comment sat. RFC 5322's obsolete syntax also allows comments\n * between the words of the local part and the labels of the domain\n * (`test.(comment)test@example.com`): those are `inside-local` and\n * `inside-domain`.\n */\n position:\n | 'before-local'\n | 'inside-local'\n | 'after-local'\n | 'before-domain'\n | 'inside-domain'\n | 'after-domain';\n}\n\ntype Failure = Extract<Result<never>, { ok: false }>;\n\nconst messages: Readonly<Record<ReasonCode, string>> = {\n 'syntax.address.empty': 'The address is empty',\n 'syntax.address.no_at': 'The address has no @',\n 'syntax.address.too_long': 'The address is longer than 254 characters',\n 'syntax.local.empty': 'Nothing comes before the @',\n 'syntax.local.too_long': 'The local part is longer than 64 characters',\n 'syntax.local.invalid_char': 'The local part has a character it can’t hold',\n 'syntax.local.consecutive_dots': 'The local part has two dots in a row',\n 'syntax.local.unquoted_space': 'The local part has whitespace outside quotes',\n 'syntax.domain.empty': 'Nothing comes after the @',\n 'syntax.domain.no_dot': 'The domain has no dot',\n 'syntax.domain.label_invalid':\n 'A domain label is empty, too long, or starts or ends with a hyphen',\n 'syntax.domain.literal_invalid': 'The domain literal isn’t accepted',\n 'syntax.domain.too_long': 'The domain is longer than 253 characters',\n 'syntax.domain.invalid_char': 'The domain has a character it can’t hold',\n 'syntax.comment.not_allowed': 'Comments aren’t allowed here',\n 'syntax.comment.unterminated': 'A comment is missing its closing parenthesis',\n 'syntax.tld.unknown': 'The TLD isn’t in the IANA set',\n};\n\nfunction fail(reason: ReasonCode, index?: number): Failure {\n const message = messages[reason];\n return index === undefined\n ? { ok: false, reason, message }\n : { ok: false, reason, message, index };\n}\n\nconst NORMAL = 0;\nconst QUOTED = 1;\nconst COMMENT = 2;\nconst LITERAL = 3;\n\n/**\n * Finds the `@` that splits `email`: the last one outside a quoted string,\n * comment, or domain literal, or -1 when there's none.\n *\n * @remarks\n * A quoted string opens only at the start of a word, and a literal only at\n * the start of the domain; both, and comments, take backslash escapes. One\n * left open runs to the end, taking any `@` with it.\n */\nexport function findAt(email: string, rules: Readonly<Rules>): number {\n let state = NORMAL;\n // Whitespace and comments don't end a word start or a domain start.\n let wordStart = true;\n let domainStart = false;\n let depth = 0;\n let at = -1;\n const end = email.length;\n for (let i = 0; i < end; i++) {\n const code = codeAt(email, i);\n if (state === NORMAL) {\n if (code === 64 /* @ */) {\n at = i;\n wordStart = true;\n domainStart = true;\n } else if (code === 40 /* ( */ && rules.comments) {\n state = COMMENT;\n depth = 1;\n } else if (!isWhitespace(code)) {\n if (code === 34 /* \" */ && rules.quotes && wordStart) {\n state = QUOTED;\n } else if (code === 91 /* [ */ && rules.literals && domainStart) {\n state = LITERAL;\n }\n wordStart = code === 46; /* . */\n domainStart = false;\n }\n } else if (code === 92 /* \\ */) {\n i++;\n } else if (state === COMMENT) {\n if (code === 40) {\n depth++;\n } else if (code === 41 /* ) */ && --depth === 0) {\n state = NORMAL;\n }\n } else if (code === (state === QUOTED ? 34 : 93) /* \" or ] */) {\n state = NORMAL;\n }\n }\n return at;\n}\n\n/**\n * Parses `email` under `rules`.\n *\n * @throws TypeError when `email` isn't a string.\n */\nexport function parse(\n email: string,\n rules: Readonly<Rules>,\n): Result<ParsedAddress> {\n if (typeof email !== 'string') {\n throw new TypeError(`Expected a string, got ${typeof email}`);\n }\n if (email === '') {\n return fail('syntax.address.empty');\n }\n // Before anything is scanned, so input of any size is rejected in\n // constant time (validator-syntax#15).\n if (email.length > rules.maxLength) {\n return fail('syntax.address.too_long');\n }\n const at = findAt(email, rules);\n if (at < 0) {\n return fail('syntax.address.no_at');\n }\n const comments: AddressComment[] = [];\n const local = scanLocal(email, at, rules, comments);\n if (typeof local !== 'string') {\n return local;\n }\n // RFC 6531 keeps the caps in octets, and DNS counts a domain's A-labels.\n const localSize = rules.unicode ? utf8Length(local) : local.length;\n if (localSize > rules.localCap) {\n return fail('syntax.local.too_long');\n }\n const domain = scanDomain(email, at, rules, comments);\n if ('reason' in domain) {\n return domain;\n }\n if (domain.size > rules.domainCap) {\n return fail('syntax.domain.too_long');\n }\n if (localSize + 1 + domain.size > 254) {\n return fail('syntax.address.too_long');\n }\n const { tld } = domain;\n if (tld === undefined && !domain.literal && !rules.allowNoTld) {\n return fail('syntax.domain.no_dot');\n }\n if (tld !== undefined && rules.checkTld && !isKnownTld(tld)) {\n return fail('syntax.tld.unknown');\n }\n return {\n ok: true,\n value:\n tld === undefined\n ? { local, domain: domain.domain, comments }\n : { local, domain: domain.domain, tld, comments },\n };\n}\n\n/**\n * Scans the local part, `email` up to `at`, and returns it without comments\n * or folding whitespace.\n */\nfunction scanLocal(\n email: string,\n at: number,\n rules: Readonly<Rules>,\n comments: AddressComment[],\n): string | Failure {\n let local = '';\n let words = 0;\n // The last token was a word, so a dot or the end comes next.\n let afterWord = false;\n // An rfc5321 quoted string, which must be the whole local part.\n let closed = false;\n // The dot a word should follow next, or -1.\n let dot = -1;\n // The first whitespace since the last word, or -1.\n let space = -1;\n // A comment after a word where only the end may follow it, or -1.\n let edge = -1;\n // Comments from here on have no word after them.\n let trailing = comments.length;\n\n let i = 0;\n while (i < at) {\n const code = codeAt(email, i);\n const quote = code === 34 && rules.quotes && (rules.obs || i === 0);\n const atom = inClass(code, rules.local);\n if (quote || atom || (rules.unicode && nonAsciiAt(email, i, at) > 0)) {\n if (edge >= 0) {\n return fail('syntax.comment.not_allowed', edge);\n }\n if (afterWord) {\n return space >= 0\n ? fail('syntax.local.unquoted_space', space)\n : fail('syntax.local.invalid_char', i);\n }\n let next: number;\n if (quote) {\n next = skipQuoted(email, i, at, rules.obs, rules.unicode);\n if (next < 0) {\n return fail('syntax.local.invalid_char', -1 - next);\n }\n closed = !rules.obs;\n } else {\n next = atom ? i + 1 : i;\n while (next < at && inClass(codeAt(email, next), rules.local)) {\n next++;\n }\n if (rules.unicode) {\n next = skipUnicode(email, next, at, rules.local);\n }\n }\n local += unfold(email, i, next);\n words++;\n afterWord = true;\n dot = -1;\n space = -1;\n trailing = comments.length;\n i = next;\n } else if (code === 46 /* . */) {\n if (edge >= 0) {\n return fail('syntax.comment.not_allowed', edge);\n }\n if (!afterWord || closed) {\n return dot >= 0\n ? fail('syntax.local.consecutive_dots', i)\n : fail('syntax.local.invalid_char', i);\n }\n local += '.';\n afterWord = false;\n dot = i;\n space = -1;\n i++;\n } else if (code === 40 /* ( */ && rules.comments) {\n if (!rules.obs && words > 0) {\n // Without the obsolete syntax, comments sit only at the ends.\n if (!afterWord) {\n return fail('syntax.comment.not_allowed', i);\n }\n edge = edge < 0 ? i : edge;\n }\n const next = skipComment(email, i, at, rules.unicode);\n if (next < 0) {\n return fail('syntax.local.invalid_char', -1 - next);\n }\n comments.push({\n text: email.slice(i + 1, next - 1),\n position: words === 0 ? 'before-local' : 'inside-local',\n });\n i = next;\n } else if (code === 40) {\n return fail('syntax.comment.not_allowed', i);\n } else if (rules.obs && isWhitespace(code)) {\n const next = skipSpace(email, i, at);\n if (next < 0) {\n return fail('syntax.local.invalid_char', i);\n }\n space = space < 0 ? i : space;\n i = next;\n } else {\n return code === 32\n ? fail('syntax.local.unquoted_space', i)\n : fail('syntax.local.invalid_char', i);\n }\n }\n\n if (words === 0) {\n return fail('syntax.local.empty');\n }\n if (dot >= 0) {\n return fail('syntax.local.invalid_char', dot);\n }\n settle(comments, trailing, 'after-local');\n return local;\n}\n\ninterface Domain {\n domain: string;\n tld?: string;\n literal: boolean;\n /** The domain's length with its U-labels as A-labels. */\n size: number;\n}\n\n/**\n * Scans the domain, `email` after `at`, and returns it without comments or\n * folding whitespace.\n */\nfunction scanDomain(\n email: string,\n at: number,\n rules: Readonly<Rules>,\n comments: AddressComment[],\n): Domain | Failure {\n const uLabels: number[] = [];\n const domain = scanLabels(email, at, rules, comments, uLabels);\n if (uLabels.length === 0) {\n return domain;\n }\n // Each U-label was checked in the scan as it ended, so a failure among\n // them comes before any failure the scan found later.\n const growth = checkULabels(email, uLabels, rules.domainCap);\n if (typeof growth !== 'number') {\n return growth;\n }\n if (!('reason' in domain)) {\n domain.size += growth;\n }\n return domain;\n}\n\n/**\n * Checks the U-labels at `spans`, triples of start, end, and the length of\n * the domain before it, as A-labels: each must convert, and pass the\n * hostname rules as its A-label. Returns the first failure, or what the\n * A-labels add to the domain's length: `Infinity` once it's past `cap`.\n *\n * @remarks\n * The U-labels are converted a few at a time, about 32 characters of them\n * in each URL: one URL costs about as much as one label alone, and a small\n * batch wastes little past the first failure or past `cap`. Once the\n * A-labels take the domain past `cap`, the rest aren't checked: the domain\n * fails as too long, unless the scan found something earlier. Punycode's\n * cost grows with the square of a label's length, so converting labels that\n * can't change the outcome would cost the most on input built to be slow\n * (validator-syntax#15).\n */\nfunction checkULabels(\n email: string,\n spans: readonly number[],\n cap: number,\n): number | Failure {\n let growth = 0;\n for (let first = 0; first < spans.length;) {\n const chunk: string[] = [];\n let written = 0;\n let next = first;\n while (next < spans.length && written < 32) {\n const label = email.slice(spans[next], spans[next + 1]);\n chunk.push(label);\n written += label.length;\n next += 3;\n }\n const aLabels = toALabels(chunk);\n for (let k = 0; k < chunk.length; k++) {\n const start = spans[first + 3 * k]!;\n const end = spans[first + 3 * k + 1]!;\n const aLabel = aLabels[k];\n if (aLabel === undefined) {\n return fail('syntax.domain.label_invalid', start);\n }\n const bad = checkLabel(email, start, end, aLabel.length);\n if (bad >= 0) {\n return fail('syntax.domain.label_invalid', bad);\n }\n growth += aLabel.length - (end - start);\n // The domain up to the end of this label, as A-labels.\n if (spans[first + 3 * k + 2]! + (end - start) + growth > cap) {\n return Infinity;\n }\n }\n first = next;\n }\n return growth;\n}\n\n/**\n * The scan behind {@link scanDomain}, which leaves the U-labels it finds in\n * `uLabels`, as triples of start, end, and the domain's length before it,\n * unchecked but for their length.\n */\nfunction scanLabels(\n email: string,\n at: number,\n rules: Readonly<Rules>,\n comments: AddressComment[],\n uLabels: number[],\n): Domain | Failure {\n const end = email.length;\n let domain = '';\n let labels = 0;\n let afterLabel = false;\n let literal = false;\n let dot = -1;\n let space = -1;\n let edge = -1;\n let trailing = comments.length;\n let tld = '';\n\n let i = at + 1;\n while (i < end) {\n const code = codeAt(email, i);\n const opensLiteral = code === 91 && rules.literals && labels === 0;\n const ldh = inClass(code, rules.domain);\n if (opensLiteral || ldh || (rules.idn && nonAsciiAt(email, i, end) > 0)) {\n if (edge >= 0) {\n return fail('syntax.comment.not_allowed', edge);\n }\n if (afterLabel) {\n return fail('syntax.domain.invalid_char', space >= 0 ? space : i);\n }\n let next: number;\n if (opensLiteral) {\n next = rules.obs\n ? skipLiteral(email, i, end)\n : skipAddressLiteral(email, i, end);\n if (next < 0) {\n return fail('syntax.domain.literal_invalid', i);\n }\n literal = true;\n } else {\n next = ldh ? i + 1 : i;\n while (next < end && inClass(codeAt(email, next), rules.domain)) {\n next++;\n }\n const ascii = next;\n if (rules.idn) {\n next = skipUnicode(email, next, end, rules.domain);\n }\n // The ASCII run stopped short, so the label is a U-label. It's\n // checked with the others after the scan, converted in one go\n // (checkULabels).\n if (next > ascii) {\n // An A-label takes `xn--` and at least a character for each code\n // point, so a U-label of more than 63 can't make one of 63. Only\n // text UTS #46 shrinks, which IDNA2008 doesn't allow in a U-label\n // (decomposed characters, or ones it drops), could. Failing it\n // here keeps Punycode, whose cost grows with the square of a\n // label's length, to short labels (validator-syntax#15).\n if (codePoints(email, i, next) > 63) {\n return fail('syntax.domain.label_invalid', i);\n }\n uLabels.push(i, next, domain.length);\n } else {\n const bad = checkLabel(email, i, next, next - i);\n if (bad >= 0) {\n return fail('syntax.domain.label_invalid', bad);\n }\n }\n }\n tld = unfold(email, i, next);\n domain += tld;\n labels++;\n afterLabel = true;\n dot = -1;\n space = -1;\n trailing = comments.length;\n i = next;\n } else if (code === 46 /* . */) {\n if (edge >= 0) {\n return fail('syntax.comment.not_allowed', edge);\n }\n if (!afterLabel || literal) {\n return literal\n ? fail('syntax.domain.invalid_char', i)\n : fail('syntax.domain.label_invalid', i);\n }\n domain += '.';\n afterLabel = false;\n dot = i;\n space = -1;\n i++;\n } else if (code === 40 /* ( */ && rules.comments) {\n if (!rules.obs && labels > 0) {\n if (!afterLabel) {\n return fail('syntax.comment.not_allowed', i);\n }\n edge = edge < 0 ? i : edge;\n }\n const next = skipComment(email, i, end, rules.unicode);\n if (next < 0) {\n return -1 - next === i\n ? fail('syntax.comment.unterminated', i)\n : fail('syntax.domain.invalid_char', -1 - next);\n }\n comments.push({\n text: email.slice(i + 1, next - 1),\n position: labels === 0 ? 'before-domain' : 'inside-domain',\n });\n i = next;\n } else if (code === 40) {\n return fail('syntax.comment.not_allowed', i);\n } else if (rules.obs && isWhitespace(code)) {\n const next = skipSpace(email, i, end);\n if (next < 0) {\n return fail('syntax.domain.invalid_char', i);\n }\n space = space < 0 ? i : space;\n i = next;\n } else {\n return fail('syntax.domain.invalid_char', i);\n }\n }\n\n if (labels === 0) {\n return fail('syntax.domain.empty');\n }\n if (dot >= 0) {\n return fail('syntax.domain.label_invalid', dot);\n }\n settle(comments, trailing, 'after-domain');\n const size = domain.length;\n return literal || labels === 1\n ? { domain, literal, size }\n : { domain, tld, literal, size };\n}\n\n/**\n * Carries an atom or label on from `i`, where its ASCII run stopped, through\n * any non-ASCII characters and the class-`flag` characters after them.\n */\nfunction skipUnicode(\n email: string,\n i: number,\n end: number,\n flag: number,\n): number {\n let width = i < end ? nonAsciiAt(email, i, end) : 0;\n while (width > 0) {\n i += width;\n while (i < end && inClass(codeAt(email, i), flag)) {\n i++;\n }\n width = i < end ? nonAsciiAt(email, i, end) : 0;\n }\n return i;\n}\n\n/**\n * Checks the hostname label from `start` to `end`, `size` characters long as\n * an A-label: returns the index of a leading or trailing hyphen, the start of\n * a label over 63 characters, or -1.\n */\nfunction checkLabel(\n email: string,\n start: number,\n end: number,\n size: number,\n): number {\n if (codeAt(email, start) === 45 /* - */) {\n return start;\n }\n if (size > 63) {\n return start;\n }\n return codeAt(email, end - 1) === 45 ? end - 1 : -1;\n}\n\n/** Marks the comments from `from` on, which no word follows, as trailing. */\nfunction settle(\n comments: AddressComment[],\n from: number,\n position: 'after-local' | 'after-domain',\n): void {\n for (let c = from; c < comments.length; c++) {\n const comment = comments[c]!;\n if (comment.position.startsWith('inside')) {\n comment.position = position;\n }\n }\n}\n\n// Called through the builtins, not as methods, for the reason codeAt is\n// (src/chars.ts): these run for every word and label.\n// oxlint-disable-next-line typescript/unbound-method -- only ever called with `.call`\nconst { indexOf, slice } = String.prototype;\n\n/**\n * `email` from `start` to `end`, without the CRLFs of folding whitespace,\n * keeping the space or tab after each.\n */\nfunction unfold(email: string, start: number, end: number): string {\n const text = slice.call(email, start, end);\n return indexOf.call(text, '\\r') < 0 ? text : text.replaceAll('\\r\\n', '');\n}\n\n// The skip functions below return the index after what they scanned, or\n// `-1 - j` for the first character `j` that breaks it.\n\n/**\n * Skips one character of folding whitespace: a space, a tab, or a CRLF with\n * a space or tab after it. A lone CR or LF breaks it.\n */\nfunction skipSpace(email: string, i: number, end: number): number {\n const code = codeAt(email, i);\n if (code === 32 || code === 9) {\n return i + 1;\n }\n return code === 13 &&\n i + 2 < end &&\n codeAt(email, i + 1) === 10 &&\n (codeAt(email, i + 2) === 32 || codeAt(email, i + 2) === 9)\n ? i + 2\n : -1 - i;\n}\n\n/** Whether a backslash may escape `code`: any ASCII with `obs`, else VCHAR and space. */\nfunction escapable(code: number, obs: boolean): boolean {\n return obs ? code < 128 : code >= 32 && code <= 126;\n}\n\n/**\n * Skips the quoted string opening at `open`. `obs` allows folding whitespace\n * and control characters other than NUL; without it, the string follows\n * RFC 5321: printable ASCII and spaces only. `unicode` adds non-ASCII.\n */\nfunction skipQuoted(\n email: string,\n open: number,\n end: number,\n obs: boolean,\n unicode: boolean,\n): number {\n let i = open + 1;\n while (i < end) {\n const code = codeAt(email, i);\n if (code === 34) {\n return i + 1;\n }\n if (code === 92) {\n if (!escapable(codeAt(email, i + 1), obs)) {\n return -2 - i;\n }\n i += 2;\n } else if (obs && isWhitespace(code)) {\n i = skipSpace(email, i, end);\n if (i < 0) {\n return i;\n }\n } else if (obs ? code === 0 || code > 127 : code < 32 || code > 126) {\n const width = unicode ? nonAsciiAt(email, i, end) : 0;\n if (width === 0) {\n return -1 - i;\n }\n i += width;\n } else {\n i++;\n }\n }\n // findAt only splits after a quoted string that closes.\n return -1 - open;\n}\n\n/**\n * Skips the comment opening at `open`, nested comments included. Its text\n * may hold any ASCII but NUL, with folding whitespace, and non-ASCII with\n * `unicode`; returns `-1 - open` when it never closes.\n */\nfunction skipComment(\n email: string,\n open: number,\n end: number,\n unicode: boolean,\n): number {\n let depth = 1;\n let i = open + 1;\n while (i < end) {\n const code = codeAt(email, i);\n if (code === 40 /* ( */ || code === 41 /* ) */) {\n depth += code === 40 ? 1 : -1;\n i++;\n if (depth === 0) {\n return i;\n }\n } else if (code === 92) {\n if (i + 1 >= end) {\n break;\n }\n if (!escapable(codeAt(email, i + 1), true)) {\n return -2 - i;\n }\n i += 2;\n } else if (isWhitespace(code)) {\n i = skipSpace(email, i, end);\n if (i < 0) {\n return i;\n }\n } else if (code === 0 || code > 127) {\n const width = unicode ? nonAsciiAt(email, i, end) : 0;\n if (width === 0) {\n return -1 - i;\n }\n i += width;\n } else {\n i++;\n }\n }\n return -1 - open;\n}\n\n/**\n * Skips the RFC 5322 domain literal opening at `open`: any ASCII but NUL,\n * `[`, and `]`, with escapes and folding whitespace. Returns -1 when it's\n * malformed or never closes.\n */\nfunction skipLiteral(email: string, open: number, end: number): number {\n let i = open + 1;\n while (i < end) {\n const code = codeAt(email, i);\n if (code === 93 /* ] */) {\n return i + 1;\n }\n if (code === 92) {\n if (i + 1 >= end || !escapable(codeAt(email, i + 1), true)) {\n return -1;\n }\n i += 2;\n } else if (isWhitespace(code)) {\n i = skipSpace(email, i, end);\n if (i < 0) {\n return -1;\n }\n } else if (code === 0 || code === 91 || code > 127) {\n return -1;\n } else {\n i++;\n }\n }\n return -1;\n}\n\n/**\n * Skips the RFC 5321 address literal opening at `open`: an IPv4 address or\n * `IPv6:` and an IPv6 address. Returns -1 for anything else.\n */\nfunction skipAddressLiteral(email: string, open: number, end: number): number {\n const close = email.indexOf(']', open + 1);\n return close >= 0 &&\n close < end &&\n isAddressLiteral(email.slice(open + 1, close))\n ? close + 1\n : -1;\n}\n","/**\n * Is the address well-formed? A quote-aware parser with four presets:\n * `practical` (the default), `rfc5321`, `rfc5322`, and `html5`.\n *\n * @packageDocumentation\n */\nimport { type SyntaxOptions, resolve } from './options';\nimport { type ParsedAddress, parse } from './parse';\nimport type { Result } from './result';\n\nexport type { Preset, SyntaxOptions } from './options';\nexport type { AddressComment, ParsedAddress } from './parse';\nexport type { ReasonCode, Result } from './result';\n\n/**\n * Parses `email` into its local part, domain, TLD, and comments, or returns\n * the first check it fails.\n *\n * @remarks\n * Input longer than `maxLength` (512 UTF-16 code units by default) fails as\n * `syntax.address.too_long` before it's scanned. Otherwise the local part is\n * checked before the domain, each left to right, then the lengths, then a\n * dotless domain, then the TLD. `index`, where a failure has one, points at\n * the offending character.\n *\n * @example\n * ```ts\n * import { parseAddress } from '@email-utils/validator-syntax';\n *\n * parseAddress('ada.lovelace@example.co.uk');\n * // => { ok: true, value: { local: 'ada.lovelace', tld: 'uk' } }\n * parseAddress('ada..lovelace@example.com');\n * // => { ok: false, reason: 'syntax.local.consecutive_dots', index: 4 }\n * ```\n *\n * @throws TypeError when `email` isn't a string, or `options` are malformed.\n */\nexport function parseAddress(\n email: string,\n options?: SyntaxOptions,\n): Result<ParsedAddress> {\n return parse(email, resolve(options));\n}\n\n/**\n * Whether `email` is well-formed: exactly `parseAddress(email, options).ok`.\n *\n * @example\n * ```ts\n * import { isValidSyntax } from '@email-utils/validator-syntax';\n *\n * isValidSyntax('ada@example.com'); // => true\n * isValidSyntax('\"ada\"@example.com'); // => false\n * isValidSyntax('\"ada\"@example.com', { preset: 'rfc5321' }); // => true\n * ```\n *\n * @throws TypeError when `email` isn't a string, or `options` are malformed.\n */\nexport function isValidSyntax(email: string, options?: SyntaxOptions): boolean {\n return parse(email, resolve(options)).ok;\n}\n\n/** {@link parseAddress} and {@link isValidSyntax} with options bound. */\nexport interface SyntaxValidator {\n parse(email: string): Result<ParsedAddress>;\n isValid(email: string): boolean;\n /**\n * The `maxLength` this validator applies: the one in its options, or the\n * default, 512. `Infinity` when there's no limit.\n *\n * @remarks\n * For a dependent that trims or otherwise pre-processes input before\n * parsing it: checking the raw input's length against this first rejects\n * oversized input before any of that work, and padding can't carry input\n * past the limit. The validator is frozen, so this can't be reassigned.\n *\n * @example\n * ```ts\n * import { createSyntaxValidator } from '@email-utils/validator-syntax';\n *\n * createSyntaxValidator().maxLength; // => 512\n * createSyntaxValidator({ maxLength: 1024 }).maxLength; // => 1024\n *\n * const validator = createSyntaxValidator();\n * const padded = `${' '.repeat(600)}ada@example.com`;\n * padded.length > validator.maxLength; // => true\n * validator.isValid(padded.trim()); // => true\n * ```\n */\n readonly maxLength: number;\n}\n\n/**\n * Binds `options` once, checking them up front, and returns\n * {@link parseAddress} and {@link isValidSyntax} with them applied, and the\n * `maxLength` they resolve to. The validator is frozen.\n *\n * @example\n * ```ts\n * import { createSyntaxValidator } from '@email-utils/validator-syntax';\n *\n * const strict = createSyntaxValidator({ preset: 'rfc5321' });\n * strict.parse('a b@example.com');\n * // => { ok: false, reason: 'syntax.local.unquoted_space', index: 1 }\n * strict.isValid('\"a b\"@example.com'); // => true\n * createSyntaxValidator({ preset: 'html5', allowComments: true });\n * // => throws TypeError\n * ```\n *\n * @throws TypeError when `options` are malformed.\n */\nexport function createSyntaxValidator(\n options?: SyntaxOptions,\n): SyntaxValidator {\n const rules = resolve(options);\n return Object.freeze<SyntaxValidator>({\n parse: (email) => parse(email, rules),\n isValid: (email) => parse(email, rules).ok,\n maxLength: rules.maxLength,\n });\n}\n"],"x_google_ignoreList":[4],"mappings":"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"}
@@ -77,6 +77,22 @@ interface SyntaxOptions {
77
77
  * @defaultValue `true` in `rfc5321` and `rfc5322`, `false` elsewhere
78
78
  */
79
79
  allowIpLiteral?: boolean | undefined;
80
+ /**
81
+ * The longest input accepted, counted in UTF-16 code units, as
82
+ * `email.length` counts. Longer input fails as `syntax.address.too_long`
83
+ * before it's scanned, so it's rejected in constant time however long it
84
+ * is. A positive integer, or `Infinity` for no limit.
85
+ *
86
+ * @remarks
87
+ * The address caps (254 characters, and 64 and 253 for the local part and
88
+ * domain where the preset has them) still apply within it. This bounds the
89
+ * input as written, comments and folding whitespace included, which those
90
+ * caps don't count. Throws `TypeError` when it isn't a positive integer or
91
+ * `Infinity`.
92
+ *
93
+ * @defaultValue `512` in every preset
94
+ */
95
+ maxLength?: number | undefined;
80
96
  }
81
97
  //#endregion
82
98
  //#region src/result.d.ts
@@ -97,4 +113,4 @@ type Result<T> = {
97
113
  };
98
114
  //#endregion
99
115
  export { SyntaxOptions as i, Result as n, Preset as r, ReasonCode as t };
100
- //# sourceMappingURL=result-BZjmlevS.d.cts.map
116
+ //# sourceMappingURL=result-CNbJ54oT.d.cts.map
@@ -77,6 +77,22 @@ interface SyntaxOptions {
77
77
  * @defaultValue `true` in `rfc5321` and `rfc5322`, `false` elsewhere
78
78
  */
79
79
  allowIpLiteral?: boolean | undefined;
80
+ /**
81
+ * The longest input accepted, counted in UTF-16 code units, as
82
+ * `email.length` counts. Longer input fails as `syntax.address.too_long`
83
+ * before it's scanned, so it's rejected in constant time however long it
84
+ * is. A positive integer, or `Infinity` for no limit.
85
+ *
86
+ * @remarks
87
+ * The address caps (254 characters, and 64 and 253 for the local part and
88
+ * domain where the preset has them) still apply within it. This bounds the
89
+ * input as written, comments and folding whitespace included, which those
90
+ * caps don't count. Throws `TypeError` when it isn't a positive integer or
91
+ * `Infinity`.
92
+ *
93
+ * @defaultValue `512` in every preset
94
+ */
95
+ maxLength?: number | undefined;
80
96
  }
81
97
  //#endregion
82
98
  //#region src/result.d.ts
@@ -97,4 +113,4 @@ type Result<T> = {
97
113
  };
98
114
  //#endregion
99
115
  export { SyntaxOptions as i, Result as n, Preset as r, ReasonCode as t };
100
- //# sourceMappingURL=result-BZjmlevS.d.mts.map
116
+ //# sourceMappingURL=result-CNbJ54oT.d.mts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@email-utils/validator-syntax",
3
- "version": "1.0.0-rc.1",
3
+ "version": "1.0.0-rc.3",
4
4
  "description": "Configurable email syntax validator.",
5
5
  "keywords": [
6
6
  "email",
@@ -49,23 +49,27 @@
49
49
  "format:check": "prettier --check .",
50
50
  "test": "vitest run",
51
51
  "test:coverage": "vitest run --coverage",
52
- "bench": "vitest bench --run",
53
- "check:package": "publint && attw --pack . --profile node16",
52
+ "bench": "npm run build && vitest bench --run",
53
+ "check:package": "publint && attw --pack . --profile node16 && size-limit && node scripts/import-cost.ts",
54
54
  "pre-commit": "npm run lint && npm run format:check && npm run typecheck",
55
55
  "prepack": "npm run build"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@arethetypeswrong/cli": "^0.18.5",
59
+ "@size-limit/preset-small-lib": "^14.1.0",
59
60
  "@types/node": "^24.0.0",
60
61
  "@vitest/coverage-v8": "^5.0.2",
62
+ "fast-check": "^4.10.2",
61
63
  "lefthook": "^2.1.14",
62
64
  "oxlint": "^1.85.0",
63
65
  "oxlint-tsgolint": "^7.0.2003",
64
66
  "prettier": "^3.9.9",
65
67
  "publint": "^0.3.24",
68
+ "size-limit": "^14.1.0",
66
69
  "tlds": "^1.261.0",
67
70
  "tsdown": "^0.23.0",
68
71
  "typescript": "^7.0.2",
72
+ "validator-syntax-0.0.1": "npm:@email-utils/validator-syntax@0.0.1-9",
69
73
  "vitest": "^5.0.2"
70
74
  },
71
75
  "engines": {