UNPKG

@uploadcare/file-uploader

Version:

Building blocks for Uploadcare products integration

200 lines (181 loc) 5.33 kB
/** * Trim leading `-/`, `/` and trailing `/` from CDN operation * * @param {String | unknown} [operation] * @returns {String} */ export const normalizeCdnOperation = (operation) => { if (typeof operation !== 'string' || !operation) { return ''; } let str = operation.trim(); if (str.startsWith('-/')) { str = str.slice(2); } else if (str.startsWith('/')) { str = str.slice(1); } if (str.endsWith('/')) { str = str.slice(0, str.length - 1); } return str; }; /** * Join multiple CDN operations into one string without trailing or leading delimeters * * @param {...(String | unknown)} [operations] * @returns {String} */ export const joinCdnOperations = (...operations) => { return operations .filter((op) => typeof op === 'string' && op) .map((op) => normalizeCdnOperation(/** @type {String} */ (op))) .join('/-/'); }; /** * Create string with leading `-/` from passed CDN operations. Do the same as `joinCdnOperations` but adds leading `-/` * and trailing `/` * * @param {...(String | unknown)} [cdnOperations] - * @returns {String} */ export const createCdnUrlModifiers = (...cdnOperations) => { let joined = joinCdnOperations(...cdnOperations); return joined ? `-/${joined}/` : ''; }; /** * Extract filename or file URL * * @param {String} cdnUrl * @returns {String} */ export function extractFilename(cdnUrl) { let url = new URL(cdnUrl); let noOrigin = url.pathname + url.search + url.hash; let urlFilenameIdx = noOrigin.lastIndexOf('http'); let plainFilenameIdx = noOrigin.lastIndexOf('/'); let filename = ''; if (urlFilenameIdx >= 0) { filename = noOrigin.slice(urlFilenameIdx); } else if (plainFilenameIdx >= 0) { filename = noOrigin.slice(plainFilenameIdx + 1); } return filename; } /** * Extract UUID from CDN URL * * @param {string} cdnUrl * @returns {string} */ export function extractUuid(cdnUrl) { let url = new URL(cdnUrl); let { pathname } = url; const slashIndex = pathname.indexOf('/'); const secondSlashIndex = pathname.indexOf('/', slashIndex + 1); return pathname.substring(slashIndex + 1, secondSlashIndex); } /** * Extract operations string from CDN URL * * @param {string} cdnUrl * @returns {string} */ export function extractCdnUrlModifiers(cdnUrl) { let withoutFilename = trimFilename(cdnUrl); let url = new URL(withoutFilename); let operationsMarker = url.pathname.indexOf('/-/'); if (operationsMarker === -1) { return ''; } let operationsStr = url.pathname.substring(operationsMarker).slice(1); return operationsStr; } /** * Extract UUID from CDN URL * * @param {string} cdnUrl * @returns {string[]} */ export function extractOperations(cdnUrl) { let operationsStr = extractCdnUrlModifiers(cdnUrl); return operationsStr .split('/-/') .filter(Boolean) .map((operation) => normalizeCdnOperation(operation)); } /** * Trim filename or file URL * * @param {String} cdnUrl * @returns {String} */ export function trimFilename(cdnUrl) { let url = new URL(cdnUrl); let filename = extractFilename(cdnUrl); let filenamePathPart = isFileUrl(filename) ? splitFileUrl(filename).pathname : filename; url.pathname = url.pathname.replace(filenamePathPart, ''); url.search = ''; url.hash = ''; return url.toString(); } /** * Detect if filename is actually file URL * * @param {String} filename * @returns {Boolean} */ export function isFileUrl(filename) { return filename.startsWith('http'); } /** * Split file URL into the path and search parts * * @param {String} fileUrl * @returns {{ pathname: String; search: String; hash: String }} */ export function splitFileUrl(fileUrl) { let url = new URL(fileUrl); return { pathname: url.origin + url.pathname || '', search: url.search || '', hash: url.hash || '', }; } /** * Create a final CDN URL with CDN modifiers and filename * * @param {String} baseCdnUrl - Base URL to CDN or Proxy, CDN modifiers and filename accepted * @param {String} [cdnModifiers] - CDN modifiers to apply, will be appended to `baseCdnUrl` ones * @param {String} [filename] - Filename for CDN or file URL for Proxy, will override one from `baseCdnUrl` * @returns {String} */ // TODO eadidenko replace arg to pass the object parameter export const createCdnUrl = (baseCdnUrl, cdnModifiers, filename) => { let url = new URL(trimFilename(baseCdnUrl)); filename = filename || extractFilename(baseCdnUrl); // TODO: fix double slash pathname bug (--cfg-cdn-cname: 'https://ucarecdn.com/' - trailing slash case) if (url.pathname.startsWith('//')) { url.pathname = url.pathname.replace('//', '/'); } if (isFileUrl(filename)) { let splitted = splitFileUrl(filename); url.pathname = url.pathname + (cdnModifiers || '') + (splitted.pathname || ''); url.search = splitted.search; url.hash = splitted.hash; } else { url.pathname = url.pathname + (cdnModifiers || '') + (filename || ''); } return url.toString(); }; /** * Create URL for an original file on CDN * * @param {String} cdnUrl - URL to get base domain from, any pathname will be stripped * @param {String} uuid * @returns {String} */ export const createOriginalUrl = (cdnUrl, uuid) => { let url = new URL(cdnUrl); url.pathname = uuid + '/'; return url.toString(); };