-
Notifications
You must be signed in to change notification settings - Fork 4
/
index.ts
128 lines (103 loc) · 3.32 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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();
}
}