UNPKG

openapi-explorer

Version:

OpenAPI Explorer - API viewer with dynamically generated components, documentation, and interaction console

172 lines (169 loc) 7.15 kB
import { marked } from 'marked'; import { getI18nText } from '../languages/index.js'; /* For Delayed Event Handler Execution */ export function debounce(fn, delay) { let timeoutID = null; return (...args) => { clearTimeout(timeoutID); const that = this; timeoutID = setTimeout(() => { fn.apply(that, args); }, delay); }; } export const invalidCharsRegEx = new RegExp(/[\s#:?&={}-]+/, 'g'); // used for generating valid html element ids by replacing the invalid chars with hyphen (-) export function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } export function copyToClipboard(copyData, eventTarget) { // In lots of places we have more than a couple of spaces for <pre> display purposes, we remove those extra spaces here. let data = copyData === null || copyData === void 0 ? void 0 : copyData.trim().replace(/\s{8}/g, ' '); try { // If the parsed type is a number, then leave it alone if (typeof JSON.parse(data) === 'object') { // Convert to 2 spaces in all JSON text data = JSON.stringify(JSON.parse(data), null, 2).trim(); } } catch (error) { // Ignore non JSON text; } const textArea = document.createElement('textarea'); textArea.value = data; textArea.style.position = 'fixed'; // avoid scrolling to bottom document.body.appendChild(textArea); textArea.focus(); textArea.select(); try { document.execCommand('copy'); const btnEl = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.target; if (btnEl) { btnEl.innerText = getI18nText('operations.copied'); setTimeout(() => { btnEl.innerText = getI18nText('operations.copy'); }, 5000); } } catch (err) { console.error('Unable to copy', err); // eslint-disable-line no-console } document.body.removeChild(textArea); } export function getBaseUrlFromUrl(url) { const pathArray = url.split('/'); return `${pathArray[0]}//${pathArray[2]}`; } export function componentIsInSearch(searchVal, component) { return !searchVal || component.name.toLowerCase().includes(searchVal.toLowerCase()); } export function pathIsInSearch(searchVal, path) { if (!searchVal) { return true; } const stringToSearch = `${path.method} ${path.path} ${path.summary || ''} ${path.description || ''} ${path.operationId || ''}`; return stringToSearch.includes(searchVal) || stringToSearch.toLowerCase().includes(searchVal) || stringToSearch.normalize('NFD').replace(/[\u0300-\u036f]/g, '').includes(searchVal) || stringToSearch.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '').includes(searchVal); } function schemaKeys(schemaProps, result = new Set()) { if (!schemaProps) { return result; } Object.keys(schemaProps).forEach(key => { result.add(key); if (schemaProps[key].properties) { schemaKeys(schemaProps[key].properties, result); } else if (schemaProps[key].items && schemaProps[key].items.properties) { schemaKeys(schemaProps[key].items.properties, result); } }); return result; } export function advancedSearch(searchVal, allSpecTags, searchOptions = []) { if (!searchVal.trim() || searchOptions.length === 0) { return undefined; } const pathsMatched = []; allSpecTags.forEach(tag => { tag.paths.forEach(path => { let stringToSearch = ''; if (searchOptions.includes('search-api-path')) { stringToSearch = path.path; } if (searchOptions.includes('search-api-descr')) { stringToSearch = `${stringToSearch} ${path.summary || path.description || ''}`; } if (searchOptions.includes('search-api-params')) { stringToSearch = `${stringToSearch} ${path.parameters && path.parameters.map(v => v.name).join(' ') || ''}`; } if (searchOptions.includes('search-api-request-body') && path.requestBody) { let schemaKeySet = new Set(); for (const contentType in path.requestBody && path.requestBody.content) { if (path.requestBody.content[contentType].schema && path.requestBody.content[contentType].schema.properties) { schemaKeySet = schemaKeys(path.requestBody.content[contentType].schema.properties); } stringToSearch = `${stringToSearch} ${[...schemaKeySet].join(' ')}`; } } if (searchOptions.includes('search-api-resp-descr')) { stringToSearch = `${stringToSearch} ${Object.values(path.responses).map(v => v.description || '').join(' ')}`; } if (stringToSearch.toLowerCase().includes(searchVal.trim().toLowerCase())) { pathsMatched.push({ elementId: path.elementId, method: path.method, path: path.path, summary: path.summary || path.description || '', deprecated: path.deprecated }); } }); }); return pathsMatched; } export function getCurrentElement() { const currentQuery = (window.location.hash || '').split('?')[1]; const query = new URLSearchParams(currentQuery); return decodeURIComponent(query.get('route') || ''); } export function replaceState(rawElementId) { const elementId = rawElementId && rawElementId.replace(/^#/, '') || ''; const currentNavigationHashPart = (window.location.hash || '').split('?')[0].replace(/^#/, ''); const currentQuery = (window.location.hash || '').split('?')[1]; const query = new URLSearchParams(currentQuery); query.delete('route'); const newQuery = query.toString().length > 1 ? `${query.toString()}&route=${elementId}` : `route=${elementId}`; const fragment = `#${currentNavigationHashPart}?${newQuery}`; const currentHref = window.location.href; const url = new URL(fragment, currentHref); if (url.href !== currentHref) { window.history.pushState(null, null, url.href); } } export function toMarkdown(markdownStringRaw) { const sanitizedMarkdownString = (markdownStringRaw || '' // Convert scripts tags to correct markdown format ).replace(/[<]script[^>]*>/gi, '<div>```').replace(/[<][/]script/gi, '```</div') // Remove unnecessary attributes from img tag .replace(/onerror=/ig, 'attribute'); const markdownResult = marked(sanitizedMarkdownString || ''); return markdownResult; } export function getSanitizedUrl(urlString) { if (!urlString) { return ''; } try { // eslint-disable-next-line no-new const url = new URL(urlString); return url.protocol === 'http' || url.protocol === 'https' ? url : ''; } catch (error) { return ''; } } export function getSanitizedEmail(emailRaw) { if (!emailRaw) { return ''; } // eslint-disable-next-line max-len, no-control-regex if (emailRaw.match(/(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/)) { return emailRaw; } return ''; }