UNPKG

parse-domain

Version:

Splits a hostname into subdomains, domain and (effective) top-level domains

105 lines 4.01 kB
import { NO_HOSTNAME } from "./from-url.js"; import { SanitizationResultType, sanitize, Validation, } from "./sanitize.js"; import { icannTrie, privateTrie } from "./serialized-tries.js"; import { lookUpTldsInTrie } from "./trie/look-up.js"; import { parseTrie } from "./trie/parse-trie.js"; export const RESERVED_TOP_LEVEL_DOMAINS = [ "localhost", "local", "example", "invalid", "test", ]; export var ParseResultType; (function (ParseResultType) { /** * This parse result is returned in case the given hostname does not adhere to * [RFC 1034](https://tools.ietf.org/html/rfc1034). */ ParseResultType["Invalid"] = "INVALID"; /** This parse result is returned if the given hostname was an IPv4 or IPv6. */ ParseResultType["Ip"] = "IP"; /** * This parse result is returned when the given hostname * * - Is the root domain (the empty string `""`) * - Belongs to the top-level domain `localhost`, `local`, `example`, `invalid` * or `test` */ ParseResultType["Reserved"] = "RESERVED"; /** * This parse result is returned when the given hostname is valid and does not * belong to a reserved top-level domain, but is not listed in the public * suffix list. */ ParseResultType["NotListed"] = "NOT_LISTED"; /** * This parse result is returned when the given hostname belongs to a * top-level domain that is listed in the public suffix list. */ ParseResultType["Listed"] = "LISTED"; })(ParseResultType || (ParseResultType = {})); const getAtIndex = (array, index) => { return index >= 0 && index < array.length ? array[index] : undefined; }; const splitLabelsIntoDomains = (labels, index) => { return { subDomains: labels.slice(0, Math.max(0, index)), domain: getAtIndex(labels, index), topLevelDomains: labels.slice(index + 1), }; }; let parsedIcannTrie; let parsedPrivateTrie; /** Splits the given hostname in topLevelDomains, a domain and subDomains. */ export const parseDomain = (hostname, options) => { const sanitizationResult = sanitize(hostname, options); if (sanitizationResult.type === SanitizationResultType.Error) { return { type: ParseResultType.Invalid, hostname, errors: sanitizationResult.errors, }; } if (sanitizationResult.type === SanitizationResultType.ValidIp) { return { type: ParseResultType.Ip, hostname: sanitizationResult.ip, ipVersion: sanitizationResult.ipVersion, }; } const { labels, domain } = sanitizationResult; // We do not want to break compatibility with older engines unnecessarily. // eslint-disable-next-line unicorn/prefer-at const lastLabel = labels[labels.length - 1]; if (hostname === "" || (lastLabel !== undefined && RESERVED_TOP_LEVEL_DOMAINS.includes(lastLabel))) { return { type: ParseResultType.Reserved, hostname: domain, labels, }; } // Parse the serialized trie lazily parsedIcannTrie = parsedIcannTrie ?? parseTrie(icannTrie); parsedPrivateTrie = parsedPrivateTrie ?? parseTrie(privateTrie); const icannTlds = lookUpTldsInTrie(labels, parsedIcannTrie); const privateTlds = lookUpTldsInTrie(labels, parsedPrivateTrie); if (icannTlds.length === 0 && privateTlds.length === 0) { return { type: ParseResultType.NotListed, hostname: domain, labels, }; } const indexOfPublicSuffixDomain = labels.length - Math.max(privateTlds.length, icannTlds.length) - 1; const indexOfIcannDomain = labels.length - icannTlds.length - 1; return { type: ParseResultType.Listed, hostname: domain, labels, icann: splitLabelsIntoDomains(labels, indexOfIcannDomain), ...splitLabelsIntoDomains(labels, indexOfPublicSuffixDomain), }; }; //# sourceMappingURL=parse-domain.js.map