1import Constants from 'expo-constants';
2import qs from 'qs';
3import URL from 'url-parse';
4import { hasCustomScheme, resolveScheme } from './Schemes';
5import { validateURL } from './validateURL';
6function getHostUri() {
7    if (Constants.expoConfig?.hostUri) {
8        return Constants.expoConfig.hostUri;
9    }
10    else if (!hasCustomScheme()) {
11        // we're probably not using up-to-date xdl, so just fake it for now
12        // we have to remove the /--/ on the end since this will be inserted again later
13        return removeScheme(Constants.linkingUri).replace(/\/--($|\/.*$)/, '');
14    }
15    else {
16        return null;
17    }
18}
19function isExpoHosted() {
20    const hostUri = getHostUri();
21    return !!(hostUri &&
22        (/^(.*\.)?(expo\.io|exp\.host|exp\.direct|expo\.test|expo\.dev)(:.*)?(\/.*)?$/.test(hostUri) ||
23            Constants.expoGoConfig?.developer));
24}
25function removeScheme(url) {
26    return url.replace(/^[a-zA-Z0-9+.-]+:\/\//, '');
27}
28function removePort(url) {
29    return url.replace(/(?=([a-zA-Z0-9+.-]+:\/\/)?[^/]):\d+/, '');
30}
31function removeLeadingSlash(url) {
32    return url.replace(/^\//, '');
33}
34function removeTrailingSlashAndQueryString(url) {
35    return url.replace(/\/?\?.*$/, '');
36}
37function ensureLeadingSlash(input, shouldAppend) {
38    const hasSlash = input.startsWith('/');
39    if (hasSlash && !shouldAppend) {
40        return input.substring(1);
41    }
42    else if (!hasSlash && shouldAppend) {
43        return `/${input}`;
44    }
45    return input;
46}
47// @needsAudit
48/**
49 * Helper method for constructing a deep link into your app, given an optional path and set of query
50 * parameters. Creates a URI scheme with two slashes by default.
51 *
52 * The scheme in bare and standalone must be defined in the Expo config (`app.config.js` or `app.json`)
53 * under `expo.scheme`.
54 *
55 * # Examples
56 * - Bare: `<scheme>://path` - uses provided scheme or scheme from Expo config `scheme`.
57 * - Standalone, Custom: `yourscheme://path`
58 * - Web (dev): `https://localhost:19006/path`
59 * - Web (prod): `https://myapp.com/path`
60 * - Expo Client (dev): `exp://128.0.0.1:8081/--/path`
61 * - Expo Client (prod): `exp://exp.host/@yourname/your-app/--/path`
62 *
63 * @param path Addition path components to append to the base URL.
64 * @param namedParameters Additional options object.
65 * @return A URL string which points to your app with the given deep link information.
66 */
67export function createURL(path, { scheme, queryParams = {}, isTripleSlashed = false } = {}) {
68    const resolvedScheme = resolveScheme({ scheme });
69    let hostUri = getHostUri() || '';
70    if (hasCustomScheme() && isExpoHosted()) {
71        hostUri = '';
72    }
73    if (path) {
74        if (isExpoHosted() && hostUri) {
75            path = `/--/${removeLeadingSlash(path)}`;
76        }
77        if (isTripleSlashed && !path.startsWith('/')) {
78            path = `/${path}`;
79        }
80    }
81    else {
82        path = '';
83    }
84    // merge user-provided query params with any that were already in the hostUri
85    // e.g. release-channel
86    let queryString = '';
87    const queryStringMatchResult = hostUri.match(/(.*)\?(.+)/);
88    if (queryStringMatchResult) {
89        hostUri = queryStringMatchResult[1];
90        queryString = queryStringMatchResult[2];
91        let paramsFromHostUri = {};
92        try {
93            const parsedParams = qs.parse(queryString);
94            if (typeof parsedParams === 'object') {
95                paramsFromHostUri = parsedParams;
96            }
97        }
98        catch { }
99        queryParams = {
100            ...queryParams,
101            ...paramsFromHostUri,
102        };
103    }
104    queryString = qs.stringify(queryParams);
105    if (queryString) {
106        queryString = `?${queryString}`;
107    }
108    hostUri = ensureLeadingSlash(hostUri, !isTripleSlashed);
109    return encodeURI(`${resolvedScheme}:${isTripleSlashed ? '/' : ''}/${hostUri}${path}${queryString}`);
110}
111// @needsAudit
112/**
113 * Helper method for parsing out deep link information from a URL.
114 * @param url A URL that points to the currently running experience (e.g. an output of `Linking.createURL()`).
115 * @return A `ParsedURL` object.
116 */
117export function parse(url) {
118    validateURL(url);
119    const parsed = URL(url, /* parseQueryString */ true);
120    for (const param in parsed.query) {
121        parsed.query[param] = decodeURIComponent(parsed.query[param]);
122    }
123    const queryParams = parsed.query;
124    const hostUri = getHostUri() || '';
125    const hostUriStripped = removePort(removeTrailingSlashAndQueryString(hostUri));
126    let path = parsed.pathname || null;
127    let hostname = parsed.hostname || null;
128    let scheme = parsed.protocol || null;
129    if (scheme) {
130        // Remove colon at end
131        scheme = scheme.substring(0, scheme.length - 1);
132    }
133    if (path) {
134        path = removeLeadingSlash(path);
135        let expoPrefix = null;
136        if (hostUriStripped) {
137            const parts = hostUriStripped.split('/');
138            expoPrefix = parts.slice(1).concat(['--/']).join('/');
139        }
140        if (isExpoHosted() && !hasCustomScheme() && expoPrefix && path.startsWith(expoPrefix)) {
141            path = path.substring(expoPrefix.length);
142            hostname = null;
143        }
144        else if (path.indexOf('+') > -1) {
145            path = path.substring(path.indexOf('+') + 1);
146        }
147    }
148    return {
149        hostname,
150        path,
151        queryParams,
152        scheme,
153    };
154}
155//# sourceMappingURL=createURL.js.map