extract-domain
Version:
Extract domain name from URL
129 lines (103 loc) • 3.4 kB
text/typescript
function throwTypeError(): never {
throw new TypeError('The given URL is not a string. Please verify your string|array.');
}
const endings = ['/', ':', '?', '#'];
const starters = ['.', '/', '@'];
type Url = string;
type Urls = string | Array<string>;
type ReturnUrls = Array<Url> | Array<Promise<Url>>;
type ReturnUrl = Url | Promise<Url | null>;
/**
* Options to extract domain.
*/
type GetDomainOptions = {
tld?: boolean;
};
/**
* @param {Url} url
* @param {GetDomainOptions} opts `{ tld: true }` permit to get Top Level Domain like `*.co.uk`
* @returns {ReturnUrl} Returns a URL or a promise of a URL if the PSL lib is being used
*/
function getDomainFromUrl(url: Url, opts: GetDomainOptions): ReturnUrl {
let domainInc: number = 0;
let offsetDomain: number = 0;
let offsetStartSlice: number = 0;
let offsetPath: number = 0;
let len: number = url.length;
let i: number = 0;
// Find end offset of domain
while (len-- && ++i) {
if (domainInc && endings.indexOf(url[i]) > -1) {
break;
}
if (url[i] !== '.') {
continue;
}
++domainInc;
offsetDomain = i;
}
offsetPath = i;
i = offsetDomain;
// Find offset before domain name.
while (i--) {
// Look for sub domain, protocol or basic auth
if (starters.indexOf(url[i]) === -1) {
continue;
}
offsetStartSlice = i + 1;
break;
}
if (offsetStartSlice === 0 && offsetPath > 3) {
return url;
}
if (offsetStartSlice > 0 && offsetStartSlice < 2) {
return '';
}
// Very customized if statement for tlds
if (opts.tld) {
let offsetStart: number = 0;
const starters: Array<string> = ['/', '@'];
let i: number = offsetDomain;
while (i--) {
if (starters.indexOf(url[i]) > -1) {
offsetStart = i + 1;
break;
}
}
return import('psl')
.then((psl) => Promise.resolve(psl.get(url.slice(offsetStart, offsetPath))))
.catch((error) => {
console.error(error);
throw Error(
'You must install psl library (https://www.npmjs.com/package/psl) to use `tld` option'
);
});
}
// Tried several approaches slicing a string. Can't get it any faster than this.
return url.slice(offsetStartSlice, offsetPath);
}
/**
* @param {Urls} urls ["https://www.google.com", "https://www.github.com"] or "https://www.google.com"
* @param {GetDomainOptions} opts `{ tld: true }` permit to get Top Level Domain like `*.co.uk`
* @returns {Urls | Promise<Urls>} Return URLs or a promise of URLs if the PSL lib is being used
*/
export default function extractDomain(
urls: Urls,
opts: GetDomainOptions = {}
): ReturnUrl | ReturnUrls | null {
if (typeof urls === 'string') {
return getDomainFromUrl(urls, opts);
} else if (Array.isArray(urls)) {
// lazy type checking (^o^)
const extractedUrls: any = [];
const len: number = urls.length;
let i: number = 0;
for (; i < len; i++) {
const url = getDomainFromUrl(urls[i], opts);
extractedUrls.push(url);
}
return extractedUrls;
} else {
throwTypeError();
}
}