personal web client for Bluesky
typescript
solidjs
bluesky
atcute
1const _parse = URL.parse;
2
3// Check for the existence of URL.parse and use that if available, removes the
4// performance hit from try..catch blocks.
5export const safeUrlParse = _parse
6 ? (text: string): URL | null => {
7 const url = _parse(text);
8
9 if (url !== null && (url.protocol === 'https:' || url.protocol === 'http:')) {
10 return url;
11 }
12
13 return null;
14 }
15 : (text: string): URL | null => {
16 try {
17 const url = new URL(text);
18
19 if (url.protocol === 'https:' || url.protocol === 'http:') {
20 return url;
21 }
22 } catch {}
23
24 return null;
25 };
26
27const TRIM_HOST_RE = /^www\./;
28const TRIM_URLTEXT_RE = /^\s*(https?:\/\/)?(?:www\.)?/;
29
30export const isLinkValid = (uri: string, text: string) => {
31 const url = safeUrlParse(uri);
32
33 if (url === null) {
34 return false;
35 }
36
37 const expectedHost = buildHostPart(url);
38 const length = expectedHost.length;
39
40 const normalized = text.replace(TRIM_URLTEXT_RE, '').toLowerCase();
41 const normalizedLength = normalized.length;
42
43 const boundary = normalizedLength >= length ? normalized[length] : undefined;
44
45 return (
46 (boundary === undefined || boundary === '/' || boundary === '?' || boundary === '#') &&
47 normalized.startsWith(expectedHost)
48 );
49};
50
51const buildHostPart = (url: URL) => {
52 const username = url.username;
53 // const password = url.password;
54
55 const hostname = url.hostname.replace(TRIM_HOST_RE, '').toLowerCase();
56 const port = url.port;
57
58 // Perhaps might be best if we always warn on authentication being passed.
59 // const auth = username ? username + (password ? ':' + password : '') + '@' : '';
60 const auth = username ? '\0@@\0' : '';
61
62 const host = hostname + (port ? ':' + port : '');
63
64 return auth + host;
65};