//#region node_modules/tldts-experimental/node_modules/tldts-core/dist/es6/src/extract-hostname.js
/**
* Matches an ASCII tab (U+0009) or newline (U+000A / U+000D). The WHATWG URL
* parser strips these before parsing; we only allocate a cleaned copy (and
* re-parse) on the rare input that actually contains one.
*/
var CONTROL_CHARS = /[\t\n\r]/g;
var extractedHostnameValidated = false;
/**
* True if char `code` is a valid hostname character. This is the per-char half
* of `is-valid.ts`'s `isValidAscii` (a-z, 0-9, > U+007F) PLUS three additions:
* A-Z (the host is lowercased before validation, so uppercase ≡ a valid
* lowercase letter) and '-' / '_' (valid inside a label). KEEP IN SYNC with
* `is-valid.ts`: these rules are deliberately duplicated to validate during
* extraction, so any change to the accepted character set there must be
* mirrored here (and vice-versa).
*/
function isValidHostnameChar(code) {
	return code >= 97 && code <= 122 || code >= 48 && code <= 57 || code > 127 || code >= 65 && code <= 90 || code === 45 || code === 95;
}
/**
* Classify scheme `url.slice(schemeStart, colonIndex)` as a WHATWG special
* scheme without allocating a substring (case-insensitive via `| 32`).
* Special schemes: ftp, file, http, https, ws, wss
* (https://url.spec.whatwg.org/#special-scheme).
*
* @returns 0 = not special, 1 = special, 2 = file (its host sits only between
*          "//" and the next slash).
*/
function getSpecialScheme(url, schemeStart, colonIndex) {
	const length = colonIndex - schemeStart;
	const c0 = url.charCodeAt(schemeStart) | 32;
	if (length === 2) return c0 === 119 && (url.charCodeAt(schemeStart + 1) | 32) === 115 ? 1 : 0;
	else if (length === 3) {
		const c1 = url.charCodeAt(schemeStart + 1) | 32;
		const c2 = url.charCodeAt(schemeStart + 2) | 32;
		if (c0 === 119 && c1 === 115 && c2 === 115) return 1;
		if (c0 === 102 && c1 === 116 && c2 === 112) return 1;
		return 0;
	} else if (length === 4) {
		const c1 = url.charCodeAt(schemeStart + 1) | 32;
		const c2 = url.charCodeAt(schemeStart + 2) | 32;
		const c3 = url.charCodeAt(schemeStart + 3) | 32;
		if (c0 === 104 && c1 === 116 && c2 === 116 && c3 === 112) return 1;
		if (c0 === 102 && c1 === 105 && c2 === 108 && c3 === 101) return 2;
		return 0;
	} else if (length === 5) return c0 === 104 && (url.charCodeAt(schemeStart + 1) | 32) === 116 && (url.charCodeAt(schemeStart + 2) | 32) === 116 && (url.charCodeAt(schemeStart + 3) | 32) === 112 && (url.charCodeAt(schemeStart + 4) | 32) === 115 ? 1 : 0;
	return 0;
}
/**
* Extract a hostname from `url`, matching a WHATWG URL parser's host-boundary
* behaviour (https://url.spec.whatwg.org/#concept-basic-url-parser) for tldts'
* scope. It deliberately does NOT normalise the host (no IDNA/punycode or IPv4
* canonicalisation; IPv6 brackets are stripped, not compressed), strips trailing
* dots, and stays lenient where a strict parser rejects (bare host:port,
* out-of-range port, user@host) — all documented deviations.
*
* @param urlIsValidHostname - when true, `url` is already a valid hostname and is
*   returned by the same reference (factory.ts skips re-validation on that
*   identity), keeping the common path allocation-free.
* @param validate - when true, validate the host inline during the authority
*   scan and publish the verdict via `extractedHostnameValidated` so `parseImpl`
*   can skip the redundant `isValidHostname` pass for simple authorities.
*/
function extractHostname(url, urlIsValidHostname, validate = false) {
	let start = 0;
	let end = url.length;
	let hasUpper = false;
	let isSpecial = false;
	extractedHostnameValidated = false;
	if (!urlIsValidHostname) {
		if (url.startsWith("data:")) return null;
		while (start < url.length && url.charCodeAt(start) <= 32) start += 1;
		while (end > start + 1 && url.charCodeAt(end - 1) <= 32) end -= 1;
		if (url.charCodeAt(start) === 47 && url.charCodeAt(start + 1) === 47) start += 2;
		else {
			const indexOfProtocol = url.indexOf(":/", start);
			if (indexOfProtocol !== -1) {
				const special = getSpecialScheme(url, start, indexOfProtocol);
				if (special === 1) {
					isSpecial = true;
					start = indexOfProtocol + 2;
					while (url.charCodeAt(start) === 47 || url.charCodeAt(start) === 92) start += 1;
				} else if (special === 2) {
					isSpecial = true;
					start = indexOfProtocol + 1;
					let slashes = 0;
					while ((url.charCodeAt(start) === 47 || url.charCodeAt(start) === 92) && slashes < 2) {
						start += 1;
						slashes += 1;
					}
					if (slashes < 2) return null;
				} else {
					for (let i = start; i < indexOfProtocol; i += 1) {
						const code = url.charCodeAt(i) | 32;
						if (!(code >= 97 && code <= 122 || code >= 48 && code <= 57 || code === 46 || code === 45 || code === 43)) {
							const raw = url.charCodeAt(i);
							if (raw === 9 || raw === 10 || raw === 13) return extractHostname(url.replace(CONTROL_CHARS, ""), urlIsValidHostname, validate);
							return null;
						}
					}
					if (url.charCodeAt(indexOfProtocol + 2) === 47) start = indexOfProtocol + 3;
					else return null;
				}
			} else if (url.charCodeAt(start) !== 91) {
				let indexOfColon = -1;
				for (let i = start; i < end; i += 1) {
					const code = url.charCodeAt(i);
					if (code === 9 || code === 10 || code === 13) return extractHostname(url.replace(CONTROL_CHARS, ""), urlIsValidHostname, validate);
					if (code === 58) {
						indexOfColon = i;
						break;
					}
					if (code === 47 || code === 92 || code === 63 || code === 35) break;
				}
				if (indexOfColon !== -1) {
					let hasIdentifier = false;
					for (let i = indexOfColon + 1; i < end; i += 1) {
						const code = url.charCodeAt(i);
						if (code === 47 || code === 92 || code === 63 || code === 35) break;
						if (code === 64) {
							hasIdentifier = true;
							break;
						}
					}
					if (!hasIdentifier) {
						let allDigits = true;
						let i = indexOfColon + 1;
						for (; i < end; i += 1) {
							const code = url.charCodeAt(i);
							if (code === 47 || code === 92 || code === 63 || code === 35) break;
							if (code < 48 || code > 57) {
								allDigits = false;
								break;
							}
						}
						if (i === indexOfColon + 1) allDigits = false;
						if (!allDigits) {
							const special = getSpecialScheme(url, start, indexOfColon);
							if (special === 0) {
								let isBareIpv6 = false;
								for (let j = indexOfColon + 1; j < end; j += 1) {
									const code = url.charCodeAt(j);
									if (code === 47 || code === 92 || code === 63 || code === 35) break;
									if (code === 58) {
										isBareIpv6 = true;
										break;
									}
								}
								if (!isBareIpv6) return null;
							} else {
								isSpecial = true;
								start = indexOfColon + 1;
								if (special === 2) {
									let slashes = 0;
									while ((url.charCodeAt(start) === 47 || url.charCodeAt(start) === 92) && slashes < 2) {
										start += 1;
										slashes += 1;
									}
									if (slashes < 2) return null;
								} else while (url.charCodeAt(start) === 47 || url.charCodeAt(start) === 92) start += 1;
							}
						}
					}
				}
			}
		}
		let indexOfIdentifier = -1;
		let indexOfClosingBracket = -1;
		let indexOfPort = -1;
		let indexOfFirstColon = -1;
		let hasControl = false;
		let vValid = validate;
		let vLastDot = start - 1;
		let vLastCode = -1;
		if (validate && start < end) {
			const c0 = url.charCodeAt(start);
			if (!(isValidHostnameChar(c0) || c0 === 46 || c0 === 95) || c0 === 45) vValid = false;
		}
		for (let i = start; i < end; i += 1) {
			const code = url.charCodeAt(i);
			if (code < 64) {
				if (code === 47 || code === 35 || code === 63) {
					end = i;
					break;
				} else if (code === 58) {
					if (indexOfFirstColon === -1) indexOfFirstColon = i;
					indexOfPort = i;
				} else if (code === 9 || code === 10 || code === 13) hasControl = true;
				else if (validate) {
					if (code === 46) {
						if (i - vLastDot > 64 || vLastCode === 46 || vLastCode === 45) vValid = false;
						vLastDot = i;
					} else if (code < 48 || code > 57) {
						if (code !== 45 || vLastCode === 46) vValid = false;
					}
				}
			} else if (isSpecial && code === 92) {
				end = i;
				break;
			} else if (code === 64) {
				indexOfIdentifier = i;
				indexOfFirstColon = -1;
			} else if (code === 93) indexOfClosingBracket = i;
			else if (code >= 65 && code <= 90) hasUpper = true;
			else if (validate && !isValidHostnameChar(code)) vValid = false;
			if (validate) vLastCode = code;
		}
		if (hasControl) return extractHostname(url.replace(CONTROL_CHARS, ""), urlIsValidHostname, validate);
		if (indexOfIdentifier !== -1 && indexOfIdentifier >= start && indexOfIdentifier < end) start = indexOfIdentifier + 1;
		if (url.charCodeAt(start) === 91) {
			if (indexOfClosingBracket !== -1) return url.slice(start + 1, indexOfClosingBracket).toLowerCase();
			return null;
		} else if (indexOfPort !== -1 && indexOfPort > start && indexOfPort < end && indexOfFirstColon === indexOfPort) end = indexOfPort;
		if (start >= end) return null;
		if (validate && vValid && indexOfIdentifier === -1 && indexOfPort === -1 && indexOfClosingBracket === -1 && url.charCodeAt(end - 1) !== 46 && end - start <= 255 && end - vLastDot - 1 <= 63 && vLastCode !== 45) extractedHostnameValidated = true;
	}
	while (end > start + 1 && url.charCodeAt(end - 1) === 46) end -= 1;
	const hostname = start !== 0 || end !== url.length ? url.slice(start, end) : url;
	if (hasUpper) return hostname.toLowerCase();
	return hostname;
}
//#endregion
export { extractHostname as default, extractedHostnameValidated };
