|
1 | 1 | import map from 'lodash/map';
|
2 | 2 | import * as FileSaver from 'file-saver';
|
3 |
| -import { deleteSecretsInEnvs, deleteUidsInEnvs, deleteUidsInItems } from 'utils/collections/export'; |
| 3 | +import { deleteSecretsInEnvs, deleteUidsInEnvs, deleteUidsInItems } from '../collections/export'; |
| 4 | + |
| 5 | +/** |
| 6 | + * Transforms a given URL string into an object representing the protocol, host, path, query, and variables. |
| 7 | + * |
| 8 | + * @param {string} url - The raw URL to be transformed. |
| 9 | + * @param {Object} params - The params object. |
| 10 | + * @returns {Object|null} An object containing the URL's protocol, host, path, query, and variables, or {} if an error occurs. |
| 11 | + */ |
| 12 | +export const transformUrl = (url, params) => { |
| 13 | + if (typeof url !== 'string' || !url.trim()) { |
| 14 | + throw new Error("Invalid URL input"); |
| 15 | + } |
| 16 | + |
| 17 | + const urlRegexPatterns = { |
| 18 | + protocolAndRestSeparator: /:\/\//, |
| 19 | + hostAndPathSeparator: /\/(.+)/, |
| 20 | + domainSegmentSeparator: /\./, |
| 21 | + pathSegmentSeparator: /\//, |
| 22 | + queryStringSeparator: /\?/ |
| 23 | + }; |
| 24 | + |
| 25 | + const postmanUrl = { raw: url }; |
| 26 | + |
| 27 | + /** |
| 28 | + * Splits a URL into its protocol, host and path. |
| 29 | + * |
| 30 | + * @param {string} url - The URL to be split. |
| 31 | + * @returns {Object} An object containing the protocol and the raw host/path string. |
| 32 | + */ |
| 33 | + const splitUrl = (url) => { |
| 34 | + const urlParts = url.split(urlRegexPatterns.protocolAndRestSeparator); |
| 35 | + if (urlParts.length === 1) { |
| 36 | + return { protocol: '', rawHostAndPath: urlParts[0] }; |
| 37 | + } else if (urlParts.length === 2) { |
| 38 | + const [hostAndPath, _] = urlParts[1].split(urlRegexPatterns.queryStringSeparator); |
| 39 | + return { protocol: urlParts[0], rawHostAndPath: hostAndPath }; |
| 40 | + } else { |
| 41 | + throw new Error(`Invalid URL format: ${url}`); |
| 42 | + } |
| 43 | + }; |
| 44 | + |
| 45 | + /** |
| 46 | + * Splits the host and path from a raw host/path string. |
| 47 | + * |
| 48 | + * @param {string} rawHostAndPath - The raw host and path string to be split. |
| 49 | + * @returns {Object} An object containing the host and path. |
| 50 | + */ |
| 51 | + const splitHostAndPath = (rawHostAndPath) => { |
| 52 | + const [host, path = ''] = rawHostAndPath.split(urlRegexPatterns.hostAndPathSeparator); |
| 53 | + return { host, path }; |
| 54 | + }; |
| 55 | + |
| 56 | + try { |
| 57 | + const { protocol, rawHostAndPath } = splitUrl(url); |
| 58 | + postmanUrl.protocol = protocol; |
| 59 | + |
| 60 | + const { host, path } = splitHostAndPath(rawHostAndPath); |
| 61 | + postmanUrl.host = host ? host.split(urlRegexPatterns.domainSegmentSeparator) : []; |
| 62 | + postmanUrl.path = path ? path.split(urlRegexPatterns.pathSegmentSeparator) : []; |
| 63 | + } catch (error) { |
| 64 | + console.error(error.message); |
| 65 | + return {}; |
| 66 | + } |
| 67 | + |
| 68 | + // Construct query params. |
| 69 | + postmanUrl.query = params |
| 70 | + .filter((param) => param.type === 'query') |
| 71 | + .map(({ name, value, description }) => ({ key: name, value, description })); |
| 72 | + |
| 73 | + // Construct path params. |
| 74 | + postmanUrl.variable = params |
| 75 | + .filter((param) => param.type === 'path') |
| 76 | + .map(({ name, value, description }) => ({ key: name, value, description })); |
| 77 | + |
| 78 | + return postmanUrl; |
| 79 | +}; |
| 80 | + |
| 81 | +/** |
| 82 | + * Collapses multiple consecutive slashes (`//`) into a single slash, while skipping the protocol (e.g., `http://` or `https://`). |
| 83 | + * |
| 84 | + * @param {String} url - A URL string |
| 85 | + * @returns {String} The sanitized URL |
| 86 | + * |
| 87 | + */ |
| 88 | +const collapseDuplicateSlashes = (url) => { |
| 89 | + return url.replace(/(?<!:)\/{2,}/g, '/'); |
| 90 | +}; |
| 91 | + |
| 92 | +/** |
| 93 | + * Replaces all `\\` (backslashes) with `//` (forward slashes) and collapses multiple slashes into one. |
| 94 | + * |
| 95 | + * @param {string} url - The URL to sanitize. |
| 96 | + * @returns {string} The sanitized URL. |
| 97 | + * |
| 98 | + */ |
| 99 | +export const sanitizeUrl = (url) => { |
| 100 | + let sanitizedUrl = collapseDuplicateSlashes(url.replace(/\\/g, '//')); |
| 101 | + return sanitizedUrl; |
| 102 | +}; |
4 | 103 |
|
5 | 104 | export const exportCollection = (collection) => {
|
6 | 105 | delete collection.uid;
|
@@ -177,49 +276,17 @@ export const exportCollection = (collection) => {
|
177 | 276 | }
|
178 | 277 | };
|
179 | 278 |
|
180 |
| - const generateHost = (url) => { |
181 |
| - try { |
182 |
| - const { hostname } = new URL(url); |
183 |
| - return hostname.split('.'); |
184 |
| - } catch (error) { |
185 |
| - console.error(`Invalid URL: ${url}`, error); |
186 |
| - return []; |
187 |
| - } |
188 |
| - }; |
189 |
| - |
190 |
| - const generatePathParams = (params) => { |
191 |
| - return params.filter((param) => param.type === 'path').map((param) => `:${param.name}`); |
192 |
| - }; |
193 |
| - |
194 |
| - const generateQueryParams = (params) => { |
195 |
| - return params |
196 |
| - .filter((param) => param.type === 'query') |
197 |
| - .map(({ name, value, description }) => ({ key: name, value, description })); |
198 |
| - }; |
199 |
| - |
200 |
| - const generateVariables = (params) => { |
201 |
| - return params |
202 |
| - .filter((param) => param.type === 'path') |
203 |
| - .map(({ name, value, description }) => ({ key: name, value, description })); |
204 |
| - }; |
205 |
| - |
206 | 279 | const generateRequestSection = (itemRequest) => {
|
207 | 280 | const requestObject = {
|
208 | 281 | method: itemRequest.method,
|
209 | 282 | header: generateHeaders(itemRequest.headers),
|
210 | 283 | auth: generateAuth(itemRequest.auth),
|
211 | 284 | description: itemRequest.docs,
|
212 |
| - url: { |
213 |
| - raw: itemRequest.url, |
214 |
| - host: generateHost(itemRequest.url), |
215 |
| - path: generatePathParams(itemRequest.params), |
216 |
| - query: generateQueryParams(itemRequest.params), |
217 |
| - variable: generateVariables(itemRequest.params) |
218 |
| - }, |
219 |
| - auth: generateAuth(itemRequest.auth) |
| 285 | + // We sanitize the URL to make sure it's in the right format before passing it to the transformUrl func. This means changing backslashes to forward slashes and reducing multiple slashes to a single one, except in the protocol part. |
| 286 | + url: transformUrl(sanitizeUrl(itemRequest.url), itemRequest.params) |
220 | 287 | };
|
221 | 288 |
|
222 |
| - if (itemRequest.body.mode != 'none') { |
| 289 | + if (itemRequest.body.mode !== 'none') { |
223 | 290 | requestObject.body = generateBody(itemRequest.body);
|
224 | 291 | }
|
225 | 292 | return requestObject;
|
|
0 commit comments