parse-domain
Version:
Splits a hostname into subdomains, domain and (effective) top-level domains
93 lines • 3.82 kB
JavaScript
import { icannTrie, privateTrie } from "./serialized-tries.js";
import { lookUpTldsInTrie } from "./trie/look-up.js";
import { sanitize, SanitizationResultType, } from "./sanitize.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;
if (hostname === "" ||
RESERVED_TOP_LEVEL_DOMAINS.includes(labels[labels.length - 1])) {
return {
type: ParseResultType.Reserved,
hostname: domain,
labels,
};
}
// Parse the serialized trie lazily
parsedIcannTrie = parsedIcannTrie !== null && parsedIcannTrie !== void 0 ? parsedIcannTrie : parseTrie(icannTrie);
parsedPrivateTrie = parsedPrivateTrie !== null && parsedPrivateTrie !== void 0 ? 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 Object.assign({ type: ParseResultType.Listed, hostname: domain, labels, icann: splitLabelsIntoDomains(labels, indexOfIcannDomain) }, splitLabelsIntoDomains(labels, indexOfPublicSuffixDomain));
};
//# sourceMappingURL=parse-domain.js.map