xref: /expo/packages/@expo/cli/src/utils/url.ts (revision af644ed4)
1import dns from 'dns';
2import fetch from 'node-fetch';
3import { URL } from 'url';
4
5/** Check if a server is available based on the URL. */
6export function isUrlAvailableAsync(url: string): Promise<boolean> {
7  return new Promise<boolean>((resolve) => {
8    dns.lookup(url, (err) => {
9      resolve(!err);
10    });
11  });
12}
13
14/** Check if a request to the given URL is `ok` (status 200). */
15export async function isUrlOk(url: string): Promise<boolean> {
16  try {
17    const res = await fetch(url);
18    return res.ok;
19  } catch {
20    return false;
21  }
22}
23
24/** Determine if a string is a valid URL, can optionally ensure certain protocols (like `https` or `exp`) are adhered to. */
25export function validateUrl(
26  urlString: string,
27  {
28    protocols,
29    requireProtocol,
30  }: {
31    /** Set of allowed protocols for the string to adhere to. @example ['exp', 'https'] */
32    protocols?: string[];
33    /** Ensure the URL has a protocol component (prefix before `://`). */
34    requireProtocol?: boolean;
35  } = {}
36) {
37  try {
38    const results = new URL(urlString);
39    if (!results.protocol && !requireProtocol) {
40      return true;
41    }
42    return protocols
43      ? results.protocol
44        ? protocols.map((x) => `${x.toLowerCase()}:`).includes(results.protocol)
45        : false
46      : true;
47  } catch {
48    return false;
49  }
50}
51
52/** Remove the port from a given `host` URL string. */
53export function stripPort(host?: string): string | null {
54  return coerceUrl(host)?.hostname ?? null;
55}
56
57function coerceUrl(urlString?: string): URL | null {
58  if (!urlString) {
59    return null;
60  }
61  try {
62    return new URL('/', urlString);
63  } catch (error: any) {
64    if (error.code !== 'ERR_INVALID_URL') {
65      throw error;
66    }
67    return new URL('/', `http://${urlString}`);
68  }
69}
70
71/** Strip a given extension from a URL string. */
72export function stripExtension(url: string, extension: string): string {
73  return url.replace(new RegExp(`.${extension}$`), '');
74}
75