source: node_modules/@swagger-api/apidom-reference/es/util/url.mjs@ d24f17c

main
Last change on this file since d24f17c was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 7.6 KB
Line 
1import process from 'process';
2import { pathSatisfies, propOr, pipe, test, last } from 'ramda';
3import { isUndefined, replaceAll, isNotUndefined, trimCharsEnd } from 'ramda-adjunct';
4
5/**
6 * SPDX-FileCopyrightText: Copyright (c) 2015 James Messinger
7 *
8 * SPDX-License-Identifier: MIT
9 */
10
11const isWindows = () => pathSatisfies(test(/^win/), ['platform'], process);
12
13/**
14 * Returns the protocol of the given URL, or `undefined` if it has no protocol.
15 */
16export const getProtocol = url => {
17 try {
18 const parsedUrl = new URL(url);
19 return trimCharsEnd(':', parsedUrl.protocol);
20 } catch {
21 return undefined;
22 }
23};
24
25/**
26 * Returns true if given URL has protocol.
27 */
28export const hasProtocol = pipe(getProtocol, isNotUndefined);
29
30/**
31 * Returns the lower-cased file extension of the given URL,
32 * or an empty string if it has no extension.
33 */
34export const getExtension = url => {
35 const lastDotPosition = url.lastIndexOf('.');
36 if (lastDotPosition >= 0) {
37 return url.substring(lastDotPosition).toLowerCase();
38 }
39 return '';
40};
41
42/**
43 * Determines whether the given path is a filesystem path.
44 * This includes "file://" URLs.
45 */
46export const isFileSystemPath = uri => {
47 // @ts-ignore
48 if (process.browser) {
49 /**
50 * We're running in a browser, so assume that all paths are URLs.
51 * This way, even relative paths will be treated as URLs rather than as filesystem paths.
52 */
53 return false;
54 }
55 const protocol = getProtocol(uri);
56 return isUndefined(protocol) || protocol === 'file' || /^[a-zA-Z]$/.test(protocol);
57};
58
59/**
60 * Determines whether the given URI is an HTTP(S) URL.
61 */
62export const isHttpUrl = url => {
63 const protocol = getProtocol(url);
64 return protocol === 'http' || protocol === 'https';
65};
66
67/**
68 * Determines whether the given URI
69 * @param uri
70 */
71export const isURI = uri => {
72 try {
73 return new URL(uri) && true;
74 } catch {
75 return false;
76 }
77};
78/**
79 * Converts a URL to a local filesystem path.
80 */
81export const toFileSystemPath = (uri, options) => {
82 // RegExp patterns to URL-decode special characters for local filesystem paths
83 const urlDecodePatterns = [/%23/g, '#', /%24/g, '$', /%26/g, '&', /%2C/g, ',', /%40/g, '@'];
84 const keepFileProtocol = propOr(false, 'keepFileProtocol', options);
85 const isWindowsPredicate = propOr(isWindows, 'isWindows', options);
86
87 // Step 1: `decodeURI` will decode characters such as Cyrillic characters, spaces, etc.
88 let path = decodeURI(uri);
89
90 // Step 2: Manually decode characters that are not decoded by `decodeURI`.
91 // This includes characters such as "#" and "?", which have special meaning in URLs,
92 // but are just normal characters in a filesystem path.
93 for (let i = 0; i < urlDecodePatterns.length; i += 2) {
94 // @ts-ignore
95 path = path.replace(urlDecodePatterns[i], urlDecodePatterns[i + 1]);
96 }
97
98 // Step 3: If it's a "file://" URL, then format it consistently
99 // or convert it to a local filesystem path
100 let isFileUrl = path.substring(0, 7).toLowerCase() === 'file://';
101 if (isFileUrl) {
102 // Strip-off the protocol, and the initial "/", if there is one
103 path = path[7] === '/' ? path.substring(8) : path.substring(7);
104
105 // insert a colon (":") after the drive letter on Windows
106 if (isWindowsPredicate() && path[1] === '/') {
107 path = `${path[0]}:${path.substring(1)}`;
108 }
109 if (keepFileProtocol) {
110 // Return the consistently-formatted "file://" URL
111 path = `file:///${path}`;
112 } else {
113 // Convert the "file://" URL to a local filesystem path.
114 // On Windows, it will start with something like "C:/".
115 // On Posix, it will start with "/"
116 isFileUrl = false;
117 path = isWindowsPredicate() ? path : `/${path}`;
118 }
119 }
120
121 // Step 4: Normalize Windows paths (unless it's a "file://" URL)
122 if (isWindowsPredicate() && !isFileUrl) {
123 // Replace forward slashes with backslashes
124 path = replaceAll('/', '\\', path);
125
126 // Capitalize the drive letter
127 if (path.substring(1, 3) === ':\\') {
128 path = path[0].toUpperCase() + path.substring(1);
129 }
130 }
131 return path;
132};
133
134/**
135 * Converts a filesystem path to a properly-encoded URL.
136 *
137 * This is intended to handle situations where resolver is called
138 * with a filesystem path that contains characters which are not allowed in URLs.
139 *
140 * @example
141 * The following filesystem paths would be converted to the following URLs:
142 *
143 * <"!@#$%^&*+=?'>.json ==> %3C%22!@%23$%25%5E&*+=%3F\'%3E.json
144 * C:\\My Documents\\File (1).json ==> C:/My%20Documents/File%20(1).json
145 * file://Project #42/file.json ==> file://Project%20%2342/file.json
146 */
147export const fromFileSystemPath = uri => {
148 const urlEncodePatterns = [/\?/g, '%3F', /#/g, '%23'];
149 let path = uri;
150
151 // Step 1: On Windows, replace backslashes with forward slashes,
152 // rather than encoding them as "%5C"
153 if (isWindows()) {
154 path = path.replace(/\\/g, '/');
155 }
156
157 // Step 2: `encodeURI` will take care of MOST characters
158 path = encodeURI(path);
159
160 // Step 3: Manually encode characters that are not encoded by `encodeURI`.
161 // This includes characters such as "#" and "?", which have special meaning in URLs,
162 // but are just normal characters in a filesystem path.
163 for (let i = 0; i < urlEncodePatterns.length; i += 2) {
164 // @ts-ignore
165 path = path.replace(urlEncodePatterns[i], urlEncodePatterns[i + 1]);
166 }
167 return path;
168};
169
170/**
171 * Returns the hash (URL fragment), of the given path.
172 * If there is no hash, then the root hash ("#") is returned.
173 */
174export const getHash = uri => {
175 const hashIndex = uri.indexOf('#');
176 if (hashIndex !== -1) {
177 return uri.substring(hashIndex);
178 }
179 return '#';
180};
181
182/**
183 * Removes the hash (URL fragment), if any, from the given path.
184 */
185export const stripHash = uri => {
186 const hashIndex = uri.indexOf('#');
187 let hashStrippedUri = uri;
188 if (hashIndex >= 0) {
189 hashStrippedUri = uri.substring(0, hashIndex);
190 }
191 return hashStrippedUri;
192};
193
194/**
195 * Returns the current working directory (in Node) or the current page URL (in browsers).
196 */
197export const cwd = () => {
198 // @ts-ignore
199 if (process.browser) {
200 return stripHash(globalThis.location.href);
201 }
202 const path = process.cwd();
203 const lastChar = last(path);
204 if (['/', '\\'].includes(lastChar)) {
205 return path;
206 }
207 return path + (isWindows() ? '\\' : '/');
208};
209
210/**
211 * Resolves a target URI relative to a base URI in a manner similar to that of a Web browser resolving an anchor tag HREF.
212 */
213export const resolve = (from, to) => {
214 const resolvedUrl = new URL(to, new URL(from, 'resolve://'));
215 if (resolvedUrl.protocol === 'resolve:') {
216 // `from` is a relative URL.
217 const {
218 pathname,
219 search,
220 hash
221 } = resolvedUrl;
222 return pathname + search + hash;
223 }
224 return resolvedUrl.toString();
225};
226
227/**
228 * Sanitizes/Encodes URI to it's url encoded form.
229 *
230 * The functional will compensate with the usecase when
231 * already sanitized URI is passed to it,
232 * by first unsatizing it and then performing sanitization again.
233 */
234
235export const sanitize = uri => {
236 if (isFileSystemPath(uri)) {
237 return fromFileSystemPath(toFileSystemPath(uri));
238 }
239 try {
240 return new URL(uri).toString();
241 } catch {
242 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI#encoding_for_ipv6
243 return encodeURI(decodeURI(uri)).replace(/%5B/g, '[').replace(/%5D/g, ']');
244 }
245};
246
247/**
248 * Unsanitizes/Decodes URI to it's url encoded form.
249 * This function already assumes that hash part of the URI
250 * has been removed prior to transforming it to it's sanitized form.
251 */
252
253export const unsanitize = uri => {
254 if (isFileSystemPath(uri)) {
255 return toFileSystemPath(uri);
256 }
257 return decodeURI(uri);
258};
Note: See TracBrowser for help on using the repository browser.