UNPKG

4.53 kBJavaScriptView Raw
1import { Constants } from 'expo-constants';
2import { Linking } from 'react-native';
3import qs from 'qs';
4const { manifest } = Constants;
5const USES_CUSTOM_SCHEME = Constants.appOwnership === 'standalone' && manifest.scheme;
6let HOST_URI = manifest.hostUri;
7if (!HOST_URI && !USES_CUSTOM_SCHEME) {
8 // we're probably not using up-to-date xdl, so just fake it for now
9 // we have to remove the /--/ on the end since this will be inserted again later
10 HOST_URI = _removeScheme(Constants.linkingUri).replace(/\/--($|\/.*$)/, '');
11}
12const IS_EXPO_HOSTED = HOST_URI &&
13 (/^(.*\.)?(expo\.io|exp\.host|exp\.direct|expo\.test)(:.*)?(\/.*)?$/.test(HOST_URI) ||
14 manifest.developer);
15function _removeScheme(url) {
16 return url.replace(/^[a-zA-Z0-9+.-]+:\/\//, '');
17}
18function _removePort(url) {
19 return url.replace(/(?=([a-zA-Z0-9+.-]+:\/\/)?[^/]):\d+/, '');
20}
21function _removeLeadingSlash(url) {
22 return url.replace(/^\//, '');
23}
24function _removeTrailingSlash(url) {
25 return url.replace(/\/$/, '');
26}
27function _removeTrailingSlashAndQueryString(url) {
28 return url.replace(/\/?\?.*$/, '');
29}
30function makeUrl(path = '', queryParams = {}) {
31 let scheme = 'exp';
32 if (Constants.appOwnership === 'standalone') {
33 scheme = manifest.scheme || (manifest.detach && manifest.detach.scheme);
34 }
35 if (!scheme) {
36 throw new Error('Cannot make a deep link into a standalone app with no custom scheme defined');
37 }
38 let hostUri = HOST_URI || '';
39 if (USES_CUSTOM_SCHEME && IS_EXPO_HOSTED) {
40 hostUri = '';
41 }
42 if (path) {
43 if (IS_EXPO_HOSTED && hostUri) {
44 path = `/--/${_removeLeadingSlash(path)}`;
45 }
46 if (!path.startsWith('/') && hostUri) {
47 path = `/${path}`;
48 }
49 else if (path.startsWith('/') && !hostUri) {
50 path = path.substr(1);
51 }
52 }
53 else {
54 path = '';
55 }
56 // merge user-provided query params with any that were already in the hostUri
57 // e.g. release-channel
58 let queryString = '';
59 let queryStringMatchResult = hostUri.match(/(.*)\?(.+)/);
60 if (queryStringMatchResult) {
61 hostUri = queryStringMatchResult[1];
62 queryString = queryStringMatchResult[2];
63 let paramsFromHostUri = {};
64 try {
65 let parsedParams = qs.parse(queryString);
66 if (typeof parsedParams === 'object') {
67 paramsFromHostUri = parsedParams;
68 }
69 }
70 catch (e) { }
71 queryParams = {
72 ...queryParams,
73 ...paramsFromHostUri,
74 };
75 }
76 queryString = qs.stringify(queryParams);
77 if (queryString) {
78 queryString = `?${queryString}`;
79 }
80 hostUri = _removeTrailingSlash(hostUri);
81 return encodeURI(`${scheme}://${hostUri}${path}${queryString}`);
82}
83function parse(url) {
84 if (!url) {
85 throw new Error('parse cannot be called with a null value');
86 }
87 // iOS client sometimes strips out the port from the initial URL
88 // even when it's included in the hostUri.
89 // This function should be able to handle both cases, so we strip off the port
90 // both here and from the hostUri.
91 let decodedUrl = _removePort(decodeURI(url));
92 let path;
93 let queryParams = {};
94 let queryStringMatchResult = decodedUrl.match(/(.*)\?(.+)/);
95 if (queryStringMatchResult) {
96 decodedUrl = queryStringMatchResult[1];
97 queryParams = qs.parse(queryStringMatchResult[2]);
98 }
99 // strip off the hostUri from the host and path
100 let hostUri = HOST_URI || '';
101 let hostUriStripped = _removePort(_removeTrailingSlashAndQueryString(hostUri));
102 if (hostUriStripped && decodedUrl.indexOf(hostUriStripped) > -1) {
103 path = decodedUrl.substr(decodedUrl.indexOf(hostUriStripped) + hostUriStripped.length);
104 }
105 else {
106 path = _removeScheme(decodedUrl);
107 }
108 path = _removeLeadingSlash(path);
109 if (IS_EXPO_HOSTED && !USES_CUSTOM_SCHEME && path.startsWith('--/')) {
110 path = path.substr(3);
111 }
112 else if (path.indexOf('+') > -1) {
113 path = path.substr(path.indexOf('+') + 1);
114 }
115 return { path, queryParams };
116}
117async function parseInitialURLAsync() {
118 const initialUrl = await Linking.getInitialURL();
119 return parse(initialUrl);
120}
121// @ts-ignore fix this...
122let newLinking = new Linking.constructor();
123newLinking.makeUrl = makeUrl;
124newLinking.parse = parse;
125newLinking.parseInitialURLAsync = parseInitialURLAsync;
126export default newLinking;
127//# sourceMappingURL=Linking.js.map
\No newline at end of file