-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmod.ts
144 lines (144 loc) · 3.94 KB
/
mod.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import regexpIP from "https://esm.sh/ip-regex@^5.0.0";
import tlds from "https://esm.sh/tlds@^1.255.0";
function sortTLDs(input: readonly string[]): string[] {
return Array.from(input).sort((a: string, b: string): number => {
return (b.length - a.length);
});
}
const regexpPartAuth = "(?:\\S+(?::\\S*)?@)?";
const regexpPartDomain = "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*";
const regexpPartHost = "(?:(?:[a-z\\u00a1-\\uffff0-9][-_]*)*[a-z\\u00a1-\\uffff0-9]+)";
const regexpPartIPv4: string = regexpIP.v4().source;
const regexpPartIPv6: string = regexpIP.v6().source;
const regexpPartPort = "(?::\\d{2,5})?";
const regexpPartTLDStrict = "(?:[a-z\\u00a1-\\uffff]{2,})";
export interface URLRegExpOptions {
/**
* Whether to accept apostrophes (`'`).
* @default {false}
*/
apostrophes?: boolean;
/**
* Whether to match the URLs with HTTP basic authentication.
* @default {false}
*/
auth?: boolean;
/**
* Custom TLDs.
*/
tldsCustom?: readonly string[];
/**
* Whether to use the default TLDs.
* @default {true}
*/
tldsDefault?: boolean;
/**
* Whether to match exactly.
* @default {false}
*/
exact?: boolean;
/**
* Whether to accept IPv4 in the URL hostname portion.
* @default {true}
*/
ipv4?: boolean;
/**
* Whether to accept IPv6 in the URL hostname portion.
* @default {true}
*/
ipv6?: boolean;
/**
* Whether to accept localhost in the URL hostname portion.
* @default {true}
*/
localhost?: boolean;
/**
* Whether to accept closing parenthesis.
* @default {false}
*/
parens?: boolean;
/**
* Whether to return the regular expression source string instead of a `RegExp`.
* @default {false}
*/
returnString?: boolean;
/**
* Whether to force the URLs start with a valid protocol or `www`.
* @default {false}
*/
strict?: boolean;
/**
* Whether to accept trailing periods (`.`).
* @default {false}
*/
trailingPeriod?: boolean;
}
/**
* Get the regular expression for the URLs.
* @param {URLRegExpOptions & { returnString?: false; }} [options={}] Options.
* @returns {RegExp}
*/
export function urlRegExp(options?: URLRegExpOptions & { returnString?: false; }): RegExp;
/**
* Get the regular expression source string for the URLs.
* @param {URLRegExpOptions & { returnString: true; }} options Options.
* @returns {string}
*/
export function urlRegExp(options: URLRegExpOptions & { returnString: true; }): string;
export function urlRegExp(options: URLRegExpOptions = {}): string | RegExp {
const {
apostrophes = false,
auth = false,
exact = false,
ipv4 = true,
ipv6 = true,
localhost = true,
parens = false,
returnString = false,
strict = false,
tldsCustom,
tldsDefault = true,
trailingPeriod = false
}: URLRegExpOptions = options;
const partProtocol = `(?:(?:[a-z]+:)?//)${strict ? "" : "?"}`;
if ((tldsCustom?.length ?? 0) === 0 && !tldsDefault) {
throw new Error(`TLDs are not defined!`);
}
const tldsFinal: string[] = [];
if (typeof tldsCustom !== "undefined") {
tldsFinal.push(...tldsCustom);
}
if (tldsDefault) {
tldsFinal.push(...tlds);
}
const partTLD = `(?:\\.${strict ? regexpPartTLDStrict : `(?:${sortTLDs(tldsFinal).join("|")})`})${trailingPeriod ? "\\.?" : ""}`;
let partDisallowCharacters: string = "\\s\"";
if (!parens) {
partDisallowCharacters += "\\)";
}
if (!apostrophes) {
partDisallowCharacters += "'";
}
const partPath: string = trailingPeriod
? `(?:[/?#][^${partDisallowCharacters}]*)?`
: `(?:(?:[/?#][^${partDisallowCharacters}]*[^${partDisallowCharacters}.?!])|[/])?`;
let regex: string = `(?:${partProtocol}|www\\.)${auth ? regexpPartAuth : ""}(?:`;
if (localhost) {
regex += "localhost|";
}
if (ipv4) {
regex += `${regexpPartIPv4}|`;
}
if (ipv6) {
regex += `${regexpPartIPv6}|`;
}
regex += `${regexpPartHost}${regexpPartDomain}${partTLD})${regexpPartPort}${partPath}`;
if (returnString) {
return regex;
}
return (exact
? new RegExp(`(?:^${regex}$)`, "i")
: new RegExp(regex, "ig")
);
}
export default urlRegExp;