openapi-explorer 1.0.543 → 1.0.546

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"openapi-explorer.min.js","mappings":";;AA8BA;ACgeA;AA5BA;AAmDA","sources":["webpack://openapi-explorer/./src/templates/code-samples-template.js","webpack://openapi-explorer/./src/components/api-request.js"],"sourcesContent":["import { html } from 'lit';\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\nimport Prism from 'prismjs';\nimport { copyToClipboard } from '../utils/common-utils';\nimport { getI18nText } from '../languages';\n\n/* eslint-disable indent */\nexport default function codeSamplesTemplate(xCodeSamples) {\n return html`\n <section class=\"table-title top-gap\"> CODE SAMPLES </div>\n <div class=\"tab-panel col\"\n @click=\"${\n (e) => {\n if (!e.target.classList.contains('tab-btn')) { return; }\n const clickedTab = e.target.dataset.tab;\n\n const tabButtons = [...e.currentTarget.querySelectorAll('.tab-btn')];\n const tabContents = [...e.currentTarget.querySelectorAll('.tab-content')];\n tabButtons.forEach((tabBtnEl) => tabBtnEl.classList[tabBtnEl.dataset.tab === clickedTab ? 'add' : 'remove']('active'));\n tabContents.forEach((tabBodyEl) => { tabBodyEl.style.display = (tabBodyEl.dataset.tab === clickedTab ? 'block' : 'none'); });\n }\n }\">\n <div class=\"tab-buttons row\" style=\"width:100; overflow\">\n ${xCodeSamples.map((v, i) => html`<button class=\"tab-btn ${i === 0 ? 'active' : ''}\" data-tab = '${v.lang}${i}'> ${v.label || v.lang} </button>`)}\n </div>\n ${xCodeSamples.map((v, i) => {\n const paddingToRemove = Math.min(...v.source.split('\\n').slice(1).map(l => l.match(/^(\\s+).*$/)?.[1].length).filter(l => typeof l !== 'undefined'));\n const sanitizedSource = v.source.split('\\n').map(s => s.substring(0, paddingToRemove).match(/^\\s+$/) ? s.substring(paddingToRemove) : s);\n const fullSource = sanitizedSource.join('\\n');\n return html`\n <div class=\"tab-content m-markdown code-sample-wrapper\" style= \"display:${i === 0 ? 'block' : 'none'}\" data-tab = '${v.lang}${i}'>\n <button class=\"m-btn outline-primary toolbar-copy-btn\" @click='${(e) => { copyToClipboard(v.source, e); }}'>${getI18nText('operations.copy')}</button>\n <pre><code>${Prism.languages[v.lang?.toLowerCase()] ? unsafeHTML(Prism.highlight(fullSource, Prism.languages[v.lang?.toLowerCase()], v.lang?.toLowerCase())) : fullSource}\n </code></pre>\n </div>`;\n })\n }\n </section>`;\n}\n/* eslint-enable indent */\n","import { LitElement, html } from 'lit';\nimport { marked } from 'marked';\nimport Prism from 'prismjs';\nimport mimeTypeResolver from './mime-types';\n\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\nimport formatXml from 'xml-but-prettier';\n\nimport { copyToClipboard } from '../utils/common-utils';\nimport { getI18nText } from '../languages';\nimport { schemaInObjectNotation, getTypeInfo, generateExample } from '../utils/schema-utils';\nimport './json-tree';\nimport './schema-tree';\nimport getRequestFormTable from './request-form-table';\nimport './tag-input';\n\nconst textFileRegex = RegExp('^font/|tar$|zip$|7z$|rtf$|msword$|excel$|/pdf$|/octet-stream$|^application/vnd.');\nconst mediaFileRegex = RegExp('^audio/|^image/|^video/');\n\nexport default class ApiRequest extends LitElement {\n createRenderRoot() { return this; }\n\n constructor() {\n super();\n this.responseMessage = '';\n this.responseStatus = '';\n this.responseHeaders = '';\n this.responseText = '';\n this.responseUrl = '';\n this.responseElapsedMs = 0;\n this.curlSyntax = '';\n this.activeResponseTab = 'response'; // allowed values: response, headers, curl\n this.selectedRequestBodyType = '';\n this.selectedRequestBodyExample = '';\n }\n\n static get properties() {\n return {\n serverUrl: { type: String, attribute: 'server-url' },\n servers: { type: Array },\n method: { type: String },\n path: { type: String },\n elementId: { type: String, attribute: 'element-id' },\n parameters: { type: Array },\n request_body: { type: Object },\n api_keys: { type: Array },\n parser: { type: Object },\n accept: { type: String },\n callback: { type: String },\n responseMessage: { type: String, attribute: false },\n responseText: { type: String, attribute: false },\n responseHeaders: { type: String, attribute: false },\n responseStatus: { type: String, attribute: false },\n responseUrl: { type: String, attribute: false },\n responseElapsedMs: { type: Number, attribute: false },\n fillRequestWithDefault: { type: String, attribute: 'fill-defaults' },\n includeNulls: { type: Boolean, attribute: 'display-nulls', converter(value) { return value === 'true'; } },\n allowTry: { type: String, attribute: 'enable-console' },\n renderStyle: { type: String, attribute: 'render-style' },\n schemaStyle: { type: String, attribute: 'schema-style' },\n activeSchemaTab: { type: String, attribute: 'active-schema-tab' },\n schemaExpandLevel: { type: Number, attribute: 'schema-expand-level' },\n schemaHideReadOnly: { type: String, attribute: 'schema-hide-read-only' },\n fetchCredentials: { type: String, attribute: 'fetch-credentials' },\n\n // properties for internal tracking\n activeResponseTab: { type: String }, // internal tracking of response-tab not exposed as a attribute\n selectedRequestBodyType: { type: String, attribute: 'selected-request-body-type' }, // internal tracking of selected request-body type\n selectedRequestBodyExample: { type: String, attribute: 'selected-request-body-example' }, // internal tracking of selected request-body example\n };\n }\n\n render() {\n return html`\n <div class=\"api-request col regular-font request-panel ${(this.renderStyle === 'focused' || this.callback === 'true') ? 'focused-mode' : 'view-mode'}\">\n <div class=\" ${this.callback === 'true' ? 'tiny-title' : 'req-res-title'} \"> \n ${this.callback === 'true' ? 'CALLBACK REQUEST' : getI18nText('operations.request')}\n </div>\n <div>\n ${this.inputParametersTemplate('path')}\n ${this.inputParametersTemplate('query')}\n ${this.requestBodyTemplate()}\n ${this.inputParametersTemplate('header')}\n ${this.inputParametersTemplate('cookie')}\n ${this.allowTry === 'false' ? '' : html`${this.apiCallTemplate()}`}\n </div> \n </div>\n `;\n }\n\n updated(changedProperties) {\n // In focused mode after rendering the request component, update the text-areas(which contains examples) using the original values from hidden textareas.\n // This is done coz, user may update the dom by editing the textarea's and once the DOM is updated externally change detection wont happen, therefore update the values manually\n if (this.renderStyle !== 'focused') {\n return;\n }\n\n // dont update example as only tabs is switched\n if (changedProperties.size === 1 && changedProperties.has('activeSchemaTab')) {\n return;\n }\n\n const exampleTextAreaEls = [...this.querySelectorAll('textarea[data-ptype=\"form-data\"]')];\n exampleTextAreaEls.forEach((el) => {\n const origExampleEl = this.querySelector(`textarea[data-pname='hidden-${el.dataset.pname}']`);\n if (origExampleEl) {\n el.value = origExampleEl.value;\n }\n });\n }\n\n /* eslint-disable indent */\n inputParametersTemplate(paramType) {\n const filteredParams = this.parameters ? this.parameters.filter((param) => param.in === paramType) : [];\n if (filteredParams.length === 0) {\n return '';\n }\n\n const title = {\n path: 'PATH PARAMETERS',\n query: 'QUERY-STRING PARAMETERS',\n header: 'REQUEST HEADERS',\n cookie: 'COOKIES'\n }[paramType];\n\n const tableRows = [];\n for (const param of filteredParams) {\n if (!param.schema) {\n continue;\n }\n const paramSchema = getTypeInfo(param.schema, { includeNulls: this.includeNulls });\n if (!paramSchema) {\n continue;\n }\n const defaultVal = Array.isArray(paramSchema.default) ? paramSchema.default : `${paramSchema.default}`;\n let paramStyle = 'form';\n let paramExplode = true;\n if (paramType === 'query') {\n if (param.style && 'form spaceDelimited pipeDelimited'.includes(param.style)) {\n paramStyle = param.style;\n }\n if (typeof param.explode === 'boolean') {\n paramExplode = param.explode;\n }\n }\n\n tableRows.push(html`\n <tr> \n <td colspan=\"1\" style=\"width:160px; min-width:50px;\">\n <div class=\"param-name ${paramSchema.deprecated ? 'deprecated' : ''}\">\n ${param.name}${!paramSchema.deprecated && param.required ? html`<span style='color:var(--red);'>*</span>` : ''}\n </div>\n <div class=\"param-type\">\n ${paramSchema.type === 'array'\n ? `${paramSchema.arrayType}`\n : `${paramSchema.format ? paramSchema.format : paramSchema.type}`\n }${!paramSchema.deprecated && param.required ? html`<span style='opacity: 0;'>*</span>` : ''}\n </div>\n </td> \n ${this.allowTry === 'true'\n ? html`\n <td colspan=\"2\" style=\"min-width:160px;\">\n ${paramSchema.type === 'array' && html`\n <tag-input class=\"request-param\" \n style = \"width:100%;\" \n data-ptype = \"${paramType}\"\n data-pname = \"${param.name}\"\n data-default = \"${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}\"\n data-param-serialize-style = \"${paramStyle}\"\n data-param-serialize-explode = \"${paramExplode}\"\n data-array = \"true\"\n placeholder=\"${paramSchema.example || (Array.isArray(defaultVal) ? defaultVal[0] : defaultVal) || 'add-multiple ↩'}\"\n .value = \"${Array.isArray(defaultVal) ? defaultVal : defaultVal.split(',')}\"></tag-input>`\n || paramSchema.type === 'object' && html`\n <textarea \n class = \"textarea small request-param\"\n part = \"textarea small textarea-param\"\n rows = 3\n data-ptype = \"${paramType}\"\n data-pname = \"${param.name}\"\n data-default = \"${defaultVal}\"\n data-param-serialize-style = \"${paramStyle}\"\n data-param-serialize-explode = \"${paramExplode}\"\n spellcheck = \"false\"\n placeholder=\"${paramSchema.example || defaultVal || ''}\"\n style = \"width:100%;\"\n .value=\"${this.fillRequestWithDefault === 'true' ? defaultVal : ''}\"></textarea>`\n || html`\n <input type=\"${paramSchema.format === 'password' ? 'password' : 'text'}\" spellcheck=\"false\" style=\"width:100%\" placeholder=\"${paramSchema.example || defaultVal || ''}\"\n class=\"request-param\"\n part=\"textbox textbox-param\"\n data-ptype=\"${paramType}\"\n data-pname=\"${param.name}\" \n data-default=\"${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}\"\n data-array=\"false\"\n @keyup=\"${this.requestParamFunction}\"\n .value=\"${this.fillRequestWithDefault === 'true' ? defaultVal : ''}\"\n />`\n }\n </td>`\n : ''\n }\n ${this.renderStyle === 'focused'\n ? html`\n <td colspan=\"2\">\n ${param.description\n ? html`\n <div class=\"param-description\">\n ${unsafeHTML(marked(param.description))}\n </div>`\n : ''\n }\n ${paramSchema.default || paramSchema.constraint || paramSchema.allowedValues || paramSchema.pattern\n ? html`\n <div class=\"param-constraint\">\n ${paramSchema.constraint ? html`<span style=\"font-weight:bold\">Constraints: </span>${paramSchema.constraint}<br>` : ''}\n ${paramSchema.pattern ? html`\n <div class=\"tooltip tooltip-replace\" style=\"cursor: pointer; max-width: 100%; display: flex;\">\n <div style=\"white-space:nowrap; font-weight:bold; margin-right: 2px;\">Pattern: </div>\n <div style=\"white-space:nowrap; text-overflow:ellipsis; max-width:100%; overflow:hidden;\">${paramSchema.pattern}</div>\n <br>\n <div class=\"tooltip-text\" style=\"position: absolute; display:block;\">${paramSchema.pattern}</div>\n </div>\n ` : ''}\n ${paramSchema.allowedValues && paramSchema.allowedValues.split('┃').map((v, i) => html`\n ${i > 0 ? '|' : html`<span style=\"font-weight:bold\">Allowed: </span>`}\n ${html`\n <a part=\"anchor anchor-param-constraint\" class = \"${this.allowTry === 'true' ? '' : 'inactive-link'}\"\n data-type=\"${paramSchema.type === 'array' ? 'array' : 'string'}\"\n data-enum=\"${v.trim()}\"\n @click=\"${(e) => {\n const inputEl = e.target.closest('table').querySelector(`[data-pname=\"${param.name}\"]`);\n if (inputEl) {\n if (e.target.dataset.type === 'array') {\n inputEl.value = [e.target.dataset.enum];\n } else {\n inputEl.value = e.target.dataset.enum;\n }\n }\n }}\"\n >\n ${v} \n </a>`\n }`)}\n </div>`\n : ''\n }\n </td> \n </tr>`\n : ''\n }\n `);\n }\n\n return html`\n <div class=\"table-title top-gap\">${title}${paramType === 'path' ? html`<span style='color:var(--red);'>*</span>` : ''}</div>\n <div style=\"display:block; overflow-x:auto; max-width:100%;\">\n <table role=\"presentation\" class=\"m-table\" style=\"width:100%; word-break:break-word;\">\n ${tableRows}\n </table>\n </div>`;\n }\n\n resetRequestBodySelection() {\n this.selectedRequestBodyType = '';\n this.selectedRequestBodyExample = '';\n this.clearResponseData();\n }\n\n // Request-Body Event Handlers\n onSelectExample(e) {\n this.selectedRequestBodyExample = e.target.value;\n const exampleDropdownEl = e.target;\n window.setTimeout((selectEl) => {\n const exampleTextareaEl = selectEl.closest('.example-panel').querySelector('.request-body-param');\n const userInputExampleTextareaEl = selectEl.closest('.example-panel').querySelector('.request-body-param-user-input');\n userInputExampleTextareaEl.value = exampleTextareaEl.value;\n }, 0, exampleDropdownEl);\n }\n\n onMimeTypeChange(e) {\n this.selectedRequestBodyType = e.target.value;\n const mimeDropdownEl = e.target;\n this.selectedRequestBodyExample = '';\n window.setTimeout((selectEl) => {\n const exampleTextareaEl = selectEl.closest('.request-body-container').querySelector('.request-body-param');\n if (exampleTextareaEl) {\n const userInputExampleTextareaEl = selectEl.closest('.request-body-container').querySelector('.request-body-param-user-input');\n userInputExampleTextareaEl.value = exampleTextareaEl.value;\n }\n }, 0, mimeDropdownEl);\n }\n\n requestBodyTemplate() {\n if (!this.request_body) {\n return '';\n }\n if (Object.keys(this.request_body).length === 0) {\n return '';\n }\n\n if (this.method === 'get' || this.method === 'head') {\n return '';\n }\n\n // Variable to store partial HTMLs\n let reqBodyTypeSelectorHtml = '';\n let reqBodyFileInputHtml = '';\n let reqBodySchemaHtml = '';\n let reqBodyDefaultHtml = '';\n let bodyTabNameUseBody = true;\n\n const requestBodyTypes = [];\n const content = this.request_body.content;\n for (const mimeType in content) {\n requestBodyTypes.push({\n mimeType,\n schema: content[mimeType].schema,\n example: content[mimeType].example,\n examples: content[mimeType].examples,\n });\n if (!this.selectedRequestBodyType) {\n this.selectedRequestBodyType = mimeType;\n }\n }\n // MIME Type selector\n reqBodyTypeSelectorHtml = requestBodyTypes.length === 1\n ? ''\n : html`\n <select aria-label=\"mime type\" style=\"min-width:100px; max-width:100%; margin-bottom:-1px;\" @change = '${(e) => this.onMimeTypeChange(e)}'>\n ${requestBodyTypes.map((reqBody) => html`\n <option value = '${reqBody.mimeType}' ?selected = '${reqBody.mimeType === this.selectedRequestBodyType}'>\n ${reqBody.mimeType}\n </option> `)\n }\n </select>\n `;\n\n // For Loop - Main\n const reqBody = requestBodyTypes.find(req => req.mimeType === this.selectedRequestBodyType);\n // Generate Example\n if (this.selectedRequestBodyType.includes('json') || this.selectedRequestBodyType.includes('xml') || this.selectedRequestBodyType.includes('text')) {\n const reqBodyExamples = generateExample(\n reqBody.examples ? reqBody.examples : '',\n reqBody.example ? reqBody.example : '',\n reqBody.schema,\n reqBody.mimeType,\n false,\n true,\n 'text',\n true\n );\n\n if (!this.selectedRequestBodyExample) {\n this.selectedRequestBodyExample = (reqBodyExamples.length > 0 ? reqBodyExamples[0].exampleId : '');\n }\n const displayedBodyExample = reqBodyExamples.find(v => v.exampleId === this.selectedRequestBodyExample);\n reqBodyDefaultHtml = html`\n <div class = 'example-panel border-top pad-top-8'>\n ${reqBodyExamples.length === 1\n ? ''\n : html`\n <select aria-label='request body example' style=\"min-width:100px; max-width:100%; margin-bottom:-1px;\" @change='${(e) => this.onSelectExample(e)}'>\n ${reqBodyExamples.map((v) => html`<option value=\"${v.exampleId}\" ?selected=${v.exampleId === this.selectedRequestBodyExample}> \n ${v.exampleSummary.length > 80 ? v.exampleId : v.exampleSummary ? v.exampleSummary : v.exampleId} \n </option>`)}\n </select>`\n }\n <div class=\"example\" data-default = '${displayedBodyExample.exampleId}'>\n ${displayedBodyExample.exampleSummary && displayedBodyExample.exampleSummary.length > 80 ? html`<div style=\"padding: 4px 0\"> ${displayedBodyExample.exampleSummary} </div>` : ''}\n ${displayedBodyExample.exampleDescription ? html`<div class=\"m-markdown-small\" style=\"padding: 4px 0\"> ${unsafeHTML(marked(displayedBodyExample.exampleDescription || ''))} </div>` : ''}\n <!-- this textarea is for user to edit the example -->\n <slot name=\"${this.elementId}--request-body\">\n <textarea \n class = \"textarea request-body-param-user-input\"\n part = \"textarea textarea-param\"\n spellcheck = \"false\"\n data-ptype = \"${reqBody.mimeType}\" \n data-default = \"${displayedBodyExample.exampleFormat === 'text' ? displayedBodyExample.exampleValue : JSON.stringify(displayedBodyExample.exampleValue, null, 8)}\"\n data-default-format = \"${displayedBodyExample.exampleFormat}\"\n style=\"width:100%; resize:vertical;\"\n .value=\"${this.fillRequestWithDefault === 'true' ? (displayedBodyExample.exampleFormat === 'text' ? displayedBodyExample.exampleValue : JSON.stringify(displayedBodyExample.exampleValue, null, 8)) : ''}\"\n ></textarea>\n </slot>\n\n <!-- This textarea(hidden) is to store the original example value, this will remain unchanged when users switches from one example to another, its is used to populate the editable textarea -->\n <textarea \n class = \"textarea is-hidden request-body-param ${reqBody.mimeType.substring(reqBody.mimeType.indexOf('/') + 1)}\" \n spellcheck = \"false\"\n data-ptype = \"${reqBody.mimeType}\" \n style=\"width:100%; resize:vertical; display:none\"\n .value=\"${(displayedBodyExample.exampleFormat === 'text' ? displayedBodyExample.exampleValue : JSON.stringify(displayedBodyExample.exampleValue, null, 8))}\"\n ></textarea>\n </div> \n\n </div>\n `;\n } else if (this.selectedRequestBodyType.includes('form-urlencoded') || this.selectedRequestBodyType.includes('form-data')) {\n bodyTabNameUseBody = false;\n const schemaAsObj = schemaInObjectNotation(reqBody.schema, { includeNulls: this.includeNulls });\n reqBodyDefaultHtml = getRequestFormTable.call(this, schemaAsObj, this.selectedRequestBodyType);\n } else if (mediaFileRegex.test(this.selectedRequestBodyType) || textFileRegex.test(this.selectedRequestBodyType)) {\n reqBodyFileInputHtml = html`\n <div class = \"small-font-size bold-text row\">\n <input type=\"file\" part=\"file-input\" style=\"max-width:100%\" class=\"request-body-param-file\" data-ptype=\"${reqBody.mimeType}\" spellcheck=\"false\" />\n </div> \n `;\n }\n\n // Generate Schema\n if (reqBody.mimeType.includes('json') || reqBody.mimeType.includes('xml') || reqBody.mimeType.includes('text') || reqBody.mimeType.includes('form-')) {\n const schemaAsObj = schemaInObjectNotation(reqBody.schema, { includeNulls: this.includeNulls });\n if (this.schemaStyle === 'table') {\n reqBodySchemaHtml = html`\n ${reqBodySchemaHtml}\n <schema-table\n class = '${reqBody.mimeType.substring(reqBody.mimeType.indexOf('/') + 1)} pad-top-8'\n style = 'display: ${this.selectedRequestBodyType === reqBody.mimeType ? 'block' : 'none'};'\n .data = '${schemaAsObj}'\n schema-expand-level = \"${this.schemaExpandLevel}\"\n schema-hide-read-only = \"${this.schemaHideReadOnly.includes(this.method)}\"\n schema-hide-write-only = false\n > </schema-table>\n `;\n } else {\n reqBodySchemaHtml = html`\n ${reqBodySchemaHtml}\n <schema-tree\n class = '${reqBody.mimeType.substring(reqBody.mimeType.indexOf('/') + 1)} pad-top-8'\n style = 'display: ${this.selectedRequestBodyType === reqBody.mimeType ? 'block' : 'none'};'\n .data = '${schemaAsObj}'\n schema-expand-level = \"${this.schemaExpandLevel}\"\n schema-hide-read-only = \"${this.schemaHideReadOnly.includes(this.method)}\"\n schema-hide-write-only = false\n > </schema-tree>\n `;\n }\n }\n\n return html`\n <div class='request-body-container' data-selected-request-body-type=\"${this.selectedRequestBodyType}\">\n <div class=\"table-title top-gap row\">\n REQUEST BODY ${this.request_body.required ? html`<span class=\"mono-font\" style='color:var(--red)'>*</span>` : ''} \n <span style = \"font-weight:normal; margin-left:5px\"> ${this.selectedRequestBodyType}</span>\n <span style=\"flex:1\"></span>\n ${reqBodyTypeSelectorHtml}\n </div>\n ${this.request_body.description ? html`<div class=\"m-markdown\" style=\"margin-bottom:12px\">${unsafeHTML(marked(this.request_body.description))}</div>` : ''}\n \n ${reqBodySchemaHtml || reqBodyDefaultHtml\n ? html`\n <div class=\"tab-panel col\" style=\"border-width:0 0 1px 0;\">\n <div class=\"tab-buttons row\" @click=\"${(e) => { if (e.target.tagName.toLowerCase() === 'button') { this.activeSchemaTab = e.target.dataset.tab; } }}\">\n <button class=\"tab-btn ${this.activeSchemaTab === 'model' ? 'active' : ''}\" data-tab=\"model\" >${getI18nText('operations.model')}</button>\n <button class=\"tab-btn ${this.activeSchemaTab !== 'model' ? 'active' : ''}\" data-tab=\"body\">${bodyTabNameUseBody ? getI18nText('operations.body') : getI18nText('operations.form')}</button>\n </div>\n ${html`<div class=\"tab-content col\" style=\"display: ${this.activeSchemaTab === 'model' ? 'block' : 'none'}\"> ${reqBodySchemaHtml}</div>`}\n ${html`<div class=\"tab-content col\" style=\"display: ${this.activeSchemaTab === 'model' ? 'none' : 'block'}\"> ${reqBodyDefaultHtml}</div>`}\n </div>`\n : html`${reqBodyFileInputHtml}`\n }\n </div> \n `;\n }\n\n // formDataTemplate(schema, mimeType, exampleValue = '') {\n // return html`\n // <textarea\n // class = \"textarea dynamic-form-param ${mimeType}\"\n // part = \"textarea textarea-param\"\n // spellcheck = \"false\"\n // data-pname=\"dynamic-form\"\n // data-ptype=\"${mimeType}\"\n // style=\"width:100%\"\n // >${exampleValue}</textarea>\n // ${schema.description ? html`<span class=\"m-markdown-small\">${unsafeHTML(marked(schema.description))}</span>` : ''}\n // `;\n // }\n\n apiResponseTabTemplate() {\n const responseFormat = this.responseHeaders.includes('json') ? 'json' : (this.responseHeaders.includes('html') || this.responseHeaders.includes('xml')) ? 'html' : '';\n return html`\n <div class=\"row\" style=\"font-size:var(--font-size-small); margin:5px 0\">\n ${this.responseMessage\n ? html`<div class=\"response-message ${this.responseStatus}\">Response Status: ${this.responseMessage}\n ${this.responseElapsedMs ? html`<span><br>Execution Time: ${this.responseElapsedMs}ms</span>` : ''}\n </div>` : ''\n }\n <div style=\"flex:1\"></div>\n <button class=\"m-btn\" part=\"btn btn-outline\" @click=\"${this.clearResponseData}\">CLEAR RESPONSE</button>\n </div>\n <div class=\"tab-panel col\" style=\"border-width:0 0 1px 0;\">\n <div id=\"tab_buttons\" class=\"tab-buttons row\" @click=\"${(e) => {\n if (e.target.classList.contains('tab-btn') === false) { return; }\n this.activeResponseTab = e.target.dataset.tab;\n }}\">\n <button class=\"tab-btn ${this.activeResponseTab === 'response' ? 'active' : ''}\" data-tab = 'response'>${getI18nText('operations.response')}</button>\n <button class=\"tab-btn ${this.activeResponseTab === 'headers' ? 'active' : ''}\" data-tab = 'headers'>${getI18nText('operations.response-headers')}</button>\n <button class=\"tab-btn ${this.activeResponseTab === 'curl' ? 'active' : ''}\" data-tab = 'curl'>CURL</button>\n </div>\n ${this.responseIsBlob\n ? html`\n <div class=\"tab-content col\" style=\"flex:1; display:${this.activeResponseTab === 'response' ? 'flex' : 'none'};\">\n <button class=\"m-btn thin-border mar-top-8\" style=\"width:135px\" @click=\"${this.downloadResponseBlob}\" part=\"btn btn-outline\">DOWNLOAD</button>\n ${this.responseBlobType === 'view'\n ? html`<button class=\"m-btn thin-border mar-top-8\" style=\"width:135px\" @click=\"${this.viewResponseBlob}\" part=\"btn btn-outline\">VIEW (NEW TAB)</button>`\n : ''\n }\n </div>`\n : html`\n <div class=\"tab-content col m-markdown\" style=\"flex:1; display:${this.activeResponseTab === 'response' ? 'flex' : 'none'};\" >\n ${this.responseText\n ? html`<button class=\"m-btn outline-primary toolbar-copy-btn\" @click='${(e) => { copyToClipboard(this.responseText, e); }}' part=\"btn btn-fill\">${getI18nText('operations.copy')}</button>`\n : ''\n }\n <pre style=\"min-height: 60px\" @copy='${() => { copyToClipboard(window.getSelection().toString()); }}'>${responseFormat\n ? html`<code>${unsafeHTML(Prism.highlight(this.responseText, Prism.languages[responseFormat], responseFormat))}</code>`\n : `${this.responseText}`\n }\n </pre>\n </div>`\n }\n <div class=\"tab-content col m-markdown\" style=\"flex:1;display:${this.activeResponseTab === 'headers' ? 'flex' : 'none'};\" >\n <button class=\"m-btn outline-primary toolbar-copy-btn\" @click='${(e) => { copyToClipboard(this.responseHeaders, e); }}' part=\"btn btn-fill\">${getI18nText('operations.copy')}</button>\n <pre><code>${unsafeHTML(Prism.highlight(this.responseHeaders, Prism.languages.css, 'css'))}</code></pre>\n </div>\n <div class=\"tab-content col m-markdown\" style=\"flex:1;display:${this.activeResponseTab === 'curl' ? 'flex' : 'none'};\">\n <button class=\"m-btn outline-primary toolbar-copy-btn\" @click='${(e) => { copyToClipboard(this.curlSyntax, e); }}' part=\"btn btn-fill\">${getI18nText('operations.copy')}</button>\n <pre class=\"fs-exclude\" data-hj-suppress data-sl=\"mask\">\n <code>${unsafeHTML(Prism.highlight(this.curlSyntax.trim(), Prism.languages.shell, 'shell'))}</code>\n </pre>\n </div>\n </div>`;\n }\n\n apiCallTemplate() {\n return html`\n <div style=\"display:flex; align-items:flex-end; margin:16px 0; font-size:var(--font-size-small);\">\n ${\n this.parameters.length > 0 || this.request_body\n ? html`\n <button class=\"m-btn thin-border\" part=\"btn btn-outline\" style=\"margin-right:5px;\" @click=\"${this.onClearRequestData}\">\n ${getI18nText('operations.clear')}\n </button>`\n : ''\n }\n <button class=\"m-btn primary btn-execute thin-border\" part=\"btn btn-fill btn-try\" @click=\"${this.onTryClick}\">${getI18nText('operations.execute')}</button>\n </div>\n ${this.responseMessage === '' ? '' : this.apiResponseTabTemplate()}\n `;\n }\n /* eslint-enable indent */\n\n onClearRequestData(e) {\n const requestPanelEl = e.target.closest('.request-panel');\n const requestPanelInputEls = [...requestPanelEl.querySelectorAll('input, tag-input, textarea:not(.is-hidden)')];\n requestPanelInputEls.forEach((el) => { el.value = ''; });\n\n const event = { bubbles: true, composed: true, detail: { explorerLocation: this.elementId, operation: { method: this.method, path: this.path }, type: 'RequestCleared' } };\n this.dispatchEvent(new CustomEvent('event', event));\n }\n\n async onTryClick() {\n const tryBtnEl = this.querySelectorAll('.btn-execute')[0];\n let curlData = '';\n let curlForm = '';\n const closestRespContainer = this.closest('.expanded-req-resp-container, .req-resp-container');\n const respEl = closestRespContainer && closestRespContainer.getElementsByTagName('api-response')[0];\n const acceptHeader = respEl?.selectedMimeType;\n const requestPanelEl = this.closest('.request-panel');\n const pathParamEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='path']\")];\n const queryParamEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='query']\")];\n const queryParamObjTypeEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='query-object']\")];\n const headerParamEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='header']\")];\n const requestBodyContainerEl = requestPanelEl.querySelector('.request-body-container');\n\n let pathUrl = `${this.serverUrl.replace(/\\/$/, '')}${this.path.replaceAll(' ', '')}`;\n\n // Generate URL using Path Params\n pathParamEls.map((el) => {\n pathUrl = pathUrl.replace(`{${el.dataset.pname}}`, encodeURIComponent(el.value) || '-');\n });\n\n // Handle relative serverUrls\n if (!pathUrl.startsWith('http')) {\n const newUrl = new URL(pathUrl, window.location.href);\n pathUrl = newUrl.toString();\n }\n\n const fetchUrl = new URL(pathUrl);\n\n const fetchOptions = {\n method: this.method.toUpperCase(),\n headers: new Headers()\n };\n\n // Query Params\n if (queryParamEls.length > 0) {\n queryParamEls.forEach((el) => {\n if (el.dataset.array === 'false') {\n if (el.value !== '') {\n fetchUrl.searchParams.append(el.dataset.pname, el.value);\n }\n } else {\n const paramSerializeStyle = el.dataset.paramSerializeStyle;\n const paramSerializeExplode = el.dataset.paramSerializeExplode;\n let vals = ((el.value && Array.isArray(el.value)) ? el.value : []);\n vals = Array.isArray(vals) ? vals.filter((v) => v !== '') : [];\n if (vals.length > 0) {\n if (paramSerializeStyle === 'spaceDelimited') {\n fetchUrl.searchParams.append(el.dataset.pname, vals.join(' ').replace(/^\\s|\\s$/g, ''));\n } else if (paramSerializeStyle === 'pipeDelimited') {\n fetchUrl.searchParams.append(el.dataset.pname, vals.join('|').replace(/^\\||\\|$/g, ''));\n } else {\n if (paramSerializeExplode === 'true') { // eslint-disable-line no-lonely-if\n vals.forEach((v) => { fetchUrl.searchParams.append(el.dataset.pname, v); });\n } else {\n fetchUrl.searchParams.append(el.dataset.pname, vals.join(',').replace(/^,|,$/g, ''));\n }\n }\n }\n }\n });\n }\n\n // Query Params (Dynamic - create from JSON)\n if (queryParamObjTypeEls.length > 0) {\n queryParamObjTypeEls.map((el) => {\n try {\n let queryParamObj = {};\n const paramSerializeStyle = el.dataset.paramSerializeStyle;\n const paramSerializeExplode = el.dataset.paramSerializeExplode;\n queryParamObj = Object.assign(queryParamObj, JSON.parse(el.value.replace(/\\s+/g, ' ')));\n for (const key in queryParamObj) {\n if (typeof queryParamObj[key] === 'object') {\n if (Array.isArray(queryParamObj[key])) {\n if (paramSerializeStyle === 'spaceDelimited') {\n fetchUrl.searchParams.append(key, queryParamObj[key].join(' '));\n } else if (paramSerializeStyle === 'pipeDelimited') {\n fetchUrl.searchParams.append(key, queryParamObj[key].join('|'));\n } else {\n if (paramSerializeExplode === 'true') { // eslint-disable-line no-lonely-if\n queryParamObj[key].forEach((v) => {\n fetchUrl.searchParams.append(key, v);\n });\n } else {\n fetchUrl.searchParams.append(key, queryParamObj[key]);\n }\n }\n }\n } else {\n fetchUrl.searchParams.append(key, queryParamObj[key]);\n }\n }\n } catch (err) {\n console.log('OpenAPI Explorer: unable to parse %s into object', el.value); // eslint-disable-line no-console\n }\n });\n }\n\n // Add Authentication api keys if provided\n this.api_keys.filter((v) => v.finalKeyValue).forEach((v) => {\n if (v.in === 'query') {\n fetchUrl.searchParams.append(v.name, v.finalKeyValue);\n return;\n }\n\n // Otherwise put it in the header\n fetchOptions.headers.append(v.name, v.finalKeyValue);\n });\n\n if (acceptHeader) {\n // Uses the acceptHeader from Response panel\n fetchOptions.headers.append('Accept', acceptHeader);\n } else if (this.accept) {\n fetchOptions.headers.append('Accept', this.accept);\n }\n\n // Add Header Params\n headerParamEls.map((el) => {\n if (el.value) {\n fetchOptions.headers.append(el.dataset.pname, el.value);\n }\n });\n\n // Request Body Params\n if (requestBodyContainerEl) {\n const requestBodyType = requestBodyContainerEl.dataset.selectedRequestBodyType;\n if (requestBodyType.includes('form-urlencoded')) {\n // url-encoded Form Params (dynamic) - Parse JSON and generate Params\n const formUrlDynamicTextAreaEl = requestPanelEl.querySelector(\"[data-ptype='dynamic-form']\");\n if (formUrlDynamicTextAreaEl) {\n const val = formUrlDynamicTextAreaEl.value;\n const formUrlDynParams = new URLSearchParams();\n let proceed = true;\n let tmpObj;\n if (val) {\n try {\n tmpObj = JSON.parse(val);\n } catch (err) {\n proceed = false;\n console.warn('OpenAPI Explorer: Invalid JSON provided', err); // eslint-disable-line no-console\n }\n } else {\n proceed = false;\n }\n if (proceed) {\n for (const prop in tmpObj) {\n formUrlDynParams.append(prop, JSON.stringify(tmpObj[prop]));\n }\n fetchOptions.body = formUrlDynParams;\n curlData = ` \\\\\\n -d ${formUrlDynParams.toString()}`;\n }\n } else {\n // url-encoded Form Params (regular)\n const formUrlEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='form-urlencode']\")];\n const formUrlParams = new URLSearchParams();\n formUrlEls\n .filter((v) => (v.type !== 'file'))\n .forEach((el) => {\n if (el.dataset.array === 'false') {\n if (el.value) {\n formUrlParams.append(el.dataset.pname, el.value);\n }\n } else {\n const vals = (el.value && Array.isArray(el.value)) ? el.value.join(',') : '';\n formUrlParams.append(el.dataset.pname, vals);\n }\n });\n fetchOptions.body = formUrlParams;\n curlData = ` \\\\\\n -d ${formUrlParams.toString()}`;\n }\n } else if (requestBodyType.includes('form-data')) {\n const formDataParams = new FormData();\n const formDataEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='form-data']\")];\n formDataEls.forEach((el) => {\n if (el.dataset.array === 'false') {\n if (el.type === 'file' && el.files[0]) {\n formDataParams.append(el.dataset.pname, el.files[0], el.files[0].name);\n curlForm += ` \\\\\\n -F \"${el.dataset.pname}=@${el.files[0].name}\"`;\n } else if (el.value) {\n formDataParams.append(el.dataset.pname, el.value);\n curlForm += ` \\\\\\n -F \"${el.dataset.pname}=${el.value}\"`;\n }\n } else if (el.value && Array.isArray(el.value)) {\n el.value.forEach((v) => {\n curlForm += ` \\\\\\n -F \"${el.dataset.pname}[]=${v}\"`;\n });\n formDataParams.append(el.dataset.pname, el.value.join(','));\n }\n });\n fetchOptions.body = formDataParams;\n } else if (mediaFileRegex.test(requestBodyType) || textFileRegex.test(requestBodyType)) {\n const bodyParamFileEl = requestPanelEl.querySelector('.request-body-param-file');\n if (bodyParamFileEl && bodyParamFileEl.files[0]) {\n fetchOptions.body = bodyParamFileEl.files[0];\n curlData = ` \\\\\\n --data-binary @${bodyParamFileEl.files[0].name}`;\n }\n } else if (requestBodyType.includes('json') || requestBodyType.includes('xml') || requestBodyType.includes('text')) {\n const exampleTextAreaEl = requestPanelEl.querySelector('.request-body-param-user-input');\n if (exampleTextAreaEl && exampleTextAreaEl.value) {\n fetchOptions.body = exampleTextAreaEl.value;\n if (requestBodyType.includes('json')) {\n try {\n curlData = ` \\\\\\n -d '${JSON.stringify(JSON.parse(exampleTextAreaEl.value))}'`;\n } catch (err) { /* Ignore unparseable JSON */ }\n }\n\n if (!curlData) {\n // Save single quotes wrapped => 'text' => `\"'\"text\"'\"`\n curlData = ` \\\\\\n -d '${exampleTextAreaEl.value.replace(/'/g, '\\'\"\\'\"\\'')}'`;\n }\n }\n }\n // Common for all request-body\n if (!requestBodyType.includes('form-data')) {\n // For multipart/form-data don't set the content-type to allow creation of browser generated part boundaries\n fetchOptions.headers.append('Content-Type', requestBodyType);\n }\n }\n\n this.responseIsBlob = false;\n this.respContentDisposition = '';\n if (this.responseBlobUrl) {\n URL.revokeObjectURL(this.responseBlobUrl);\n this.responseBlobUrl = '';\n }\n\n if (this.fetchCredentials) {\n fetchOptions.credentials = this.fetchCredentials;\n }\n\n // Options is legacy usage, documentation has been updated to reference properties of the fetch option directly, but older usages may still be using options\n const fetchRequest = { explorerLocation: this.elementId, url: fetchUrl.toString(), options: fetchOptions, ...fetchOptions };\n const event = {\n bubbles: true,\n composed: true,\n detail: {\n request: fetchRequest,\n },\n };\n this.dispatchEvent(new CustomEvent('before-try', event));\n this.dispatchEvent(new CustomEvent('request', event));\n const newFetchOptions = {\n method: fetchRequest.method || fetchOptions.method,\n headers: fetchRequest.headers || fetchOptions.headers,\n credentials: fetchRequest.credentials || fetchOptions.credentials,\n body: fetchRequest.body || fetchOptions.body\n };\n const fetchRequestObject = new Request(fetchRequest.url, newFetchOptions);\n\n const curl = `curl -X ${this.method.toUpperCase()} \"${fetchUrl.toString()}\"`;\n const curlHeaders = [...newFetchOptions.headers.entries()].reduce((acc, [key, value]) => `${acc} \\\\\\n -H \"${key}: ${value}\"`, '');\n this.curlSyntax = `${curl}${curlHeaders}${curlData}${curlForm}`;\n\n let fetchResponse;\n try {\n let respBlob;\n let respJson;\n let respText;\n tryBtnEl.disabled = true;\n const fetchStart = new Date();\n\n this.responseStatus = '';\n this.responseMessage = '';\n this.responseUrl = '';\n this.responseHeaders = '';\n this.responseText = '⌛';\n\n this.requestUpdate();\n const awaiter = new Promise(resolve => setTimeout(resolve, 200));\n fetchResponse = await fetch(fetchRequestObject);\n this.responseElapsedMs = new Date() - fetchStart;\n await awaiter;\n\n tryBtnEl.disabled = false;\n this.responseStatus = fetchResponse.ok ? 'success' : 'error';\n this.responseMessage = fetchResponse.statusText ? `${fetchResponse.statusText} (${fetchResponse.status})` : fetchResponse.status;\n this.responseUrl = fetchResponse.url;\n this.responseHeaders = '';\n const headers = {};\n fetchResponse.headers.forEach((hdrVal, hdr) => {\n this.responseHeaders = `${this.responseHeaders}${hdr.trim()}: ${hdrVal}\\n`;\n headers[hdr.trim()] = hdrVal && hdrVal.trim();\n });\n const contentType = fetchResponse.headers.get('content-type');\n const respEmpty = (await fetchResponse.clone().text()).length === 0;\n if (respEmpty) {\n this.responseText = '';\n } else if (contentType) {\n if (contentType.includes('json')) {\n if ((/charset=[^\"']+/).test(contentType)) {\n const encoding = contentType.split('charset=')[1];\n const buffer = await fetchResponse.arrayBuffer();\n try {\n respText = new TextDecoder(encoding).decode(buffer);\n } catch {\n respText = new TextDecoder('utf-8').decode(buffer);\n }\n try {\n this.responseText = JSON.stringify(JSON.parse(respText), null, 8);\n } catch {\n this.responseText = respText;\n }\n } else {\n respJson = await fetchResponse.json();\n this.responseText = JSON.stringify(respJson, null, 8);\n }\n } else if (textFileRegex.test(contentType)) {\n this.responseIsBlob = true;\n this.responseBlobType = 'download';\n } else if (mediaFileRegex.test(contentType)) {\n this.responseIsBlob = true;\n this.responseBlobType = 'view';\n } else {\n respText = await fetchResponse.text();\n if (contentType.includes('xml')) {\n this.responseText = formatXml(respText, { textNodesOnSameLine: true, indentor: ' ' });\n } else {\n this.responseText = respText;\n }\n }\n if (this.responseIsBlob) {\n const contentDisposition = fetchResponse.headers.get('content-disposition');\n const filenameRegex = /filename[^;=\\n]*=((['\"]).*?\\2|[^;\\n]*)/;\n const filename = filenameRegex.exec(contentDisposition);\n this.respContentDisposition = filename && filename[1] && filename[1].replace(/['\"]/g, '') || `download.${mimeTypeResolver.extension(contentType) || 'file'}`;\n respBlob = await fetchResponse.blob();\n this.responseBlobUrl = URL.createObjectURL(respBlob);\n }\n } else {\n respText = await fetchResponse.text();\n this.responseText = respText;\n }\n const responseEvent = {\n bubbles: true,\n composed: true,\n detail: {\n explorerLocation: this.elementId,\n request: fetchRequest,\n response: {\n headers,\n body: respJson || respText || respBlob || fetchResponse.body,\n status: fetchResponse.status,\n },\n },\n };\n this.dispatchEvent(new CustomEvent('after-try', responseEvent));\n this.dispatchEvent(new CustomEvent('response', responseEvent));\n } catch (error) {\n tryBtnEl.disabled = false;\n this.responseMessage = `${error.message} (Check the browser network tab for more information.)`;\n this.responseStatus = 'error';\n const responseEvent = {\n bubbles: true,\n composed: true,\n detail: {\n explorerLocation: this.elementId,\n error,\n request: fetchRequest,\n },\n };\n document.dispatchEvent(new CustomEvent('after-try', responseEvent));\n document.dispatchEvent(new CustomEvent('response', responseEvent));\n }\n }\n\n onAddRemoveFileInput(e, pname, ptype) {\n if (e.target.tagName.toLowerCase() !== 'button') {\n return;\n }\n\n if (e.target.classList.contains('file-input-remove-btn')) {\n // Remove File Input Set\n const el = e.target.closest('.input-set');\n el.remove();\n return;\n }\n const el = e.target.closest('.file-input-container');\n\n // Add File Input Set\n\n // Container\n const newInputContainerEl = document.createElement('div');\n newInputContainerEl.setAttribute('class', 'input-set row');\n\n // File Input\n const newInputEl = document.createElement('input');\n newInputEl.type = 'file';\n newInputEl.setAttribute('class', 'file-input');\n newInputEl.setAttribute('data-pname', pname);\n newInputEl.setAttribute('data-ptype', ptype.includes('form-urlencode') ? 'form-urlencode' : 'form-data');\n newInputEl.setAttribute('data-array', 'false');\n newInputEl.setAttribute('data-file-array', 'true');\n\n // Remover Button\n const newRemoveBtnEl = document.createElement('button');\n newRemoveBtnEl.setAttribute('class', 'file-input-remove-btn');\n newRemoveBtnEl.innerHTML = '&#x2715;';\n\n newInputContainerEl.appendChild(newInputEl);\n newInputContainerEl.appendChild(newRemoveBtnEl);\n el.insertBefore(newInputContainerEl, e.target);\n // el.appendChild(newInputContainerEl);\n }\n\n downloadResponseBlob() {\n if (this.responseBlobUrl) {\n const a = document.createElement('a');\n document.body.appendChild(a);\n a.style = 'display: none';\n a.href = this.responseBlobUrl;\n a.download = this.respContentDisposition;\n a.click();\n a.remove();\n }\n }\n\n viewResponseBlob() {\n if (this.responseBlobUrl) {\n const a = document.createElement('a');\n document.body.appendChild(a);\n a.style = 'display: none';\n a.href = this.responseBlobUrl;\n a.target = '_blank';\n a.click();\n a.remove();\n }\n }\n\n clearResponseData() {\n this.responseUrl = '';\n this.responseHeaders = '';\n this.responseText = '';\n this.responseStatus = '';\n this.responseMessage = '';\n this.responseElapsedMs = 0;\n this.responseIsBlob = false;\n this.responseBlobType = '';\n this.respContentDisposition = '';\n if (this.responseBlobUrl) {\n URL.revokeObjectURL(this.responseBlobUrl);\n this.responseBlobUrl = '';\n }\n }\n\n requestParamFunction(event) {\n if (event.key === 'Enter') {\n this.onTryClick();\n event.preventDefault();\n }\n }\n\n disconnectedCallback() {\n // Cleanup ObjectURL forthe blob data if this component created one\n if (this.responseBlobUrl) {\n URL.revokeObjectURL(this.responseBlobUrl);\n this.responseBlobUrl = '';\n }\n super.disconnectedCallback();\n }\n}\n\n// Register the element with the browser\nif (!customElements.get('openapi-explorer')) {\n customElements.define('api-request', ApiRequest);\n}\n"],"names":[],"sourceRoot":""}
1
+ {"version":3,"file":"openapi-explorer.min.js","mappings":";;AA8BA;ACgeA;AA5BA;AAmDA","sources":["webpack://openapi-explorer/./src/templates/code-samples-template.js","webpack://openapi-explorer/./src/components/api-request.js"],"sourcesContent":["import { html } from 'lit';\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\nimport Prism from 'prismjs';\nimport { copyToClipboard } from '../utils/common-utils';\nimport { getI18nText } from '../languages';\n\n/* eslint-disable indent */\nexport default function codeSamplesTemplate(xCodeSamples) {\n return html`\n <section class=\"table-title top-gap\"> CODE SAMPLES </div>\n <div class=\"tab-panel col\"\n @click=\"${\n (e) => {\n if (!e.target.classList.contains('tab-btn')) { return; }\n const clickedTab = e.target.dataset.tab;\n\n const tabButtons = [...e.currentTarget.querySelectorAll('.tab-btn')];\n const tabContents = [...e.currentTarget.querySelectorAll('.tab-content')];\n tabButtons.forEach((tabBtnEl) => tabBtnEl.classList[tabBtnEl.dataset.tab === clickedTab ? 'add' : 'remove']('active'));\n tabContents.forEach((tabBodyEl) => { tabBodyEl.style.display = (tabBodyEl.dataset.tab === clickedTab ? 'block' : 'none'); });\n }\n }\">\n <div class=\"tab-buttons row\" style=\"width:100; overflow\">\n ${xCodeSamples.map((v, i) => html`<button class=\"tab-btn ${i === 0 ? 'active' : ''}\" data-tab = '${v.lang}${i}'> ${v.label || v.lang} </button>`)}\n </div>\n ${xCodeSamples.map((v, i) => {\n const paddingToRemove = Math.min(...v.source.split('\\n').slice(1).map(l => l.match(/^(\\s+).*$/)?.[1].length).filter(l => typeof l !== 'undefined'));\n const sanitizedSource = v.source.split('\\n').map(s => s.substring(0, paddingToRemove).match(/^\\s+$/) ? s.substring(paddingToRemove) : s);\n const fullSource = sanitizedSource.join('\\n');\n return html`\n <div class=\"tab-content m-markdown code-sample-wrapper\" style= \"display:${i === 0 ? 'block' : 'none'}\" data-tab = '${v.lang}${i}'>\n <button class=\"m-btn outline-primary toolbar-copy-btn\" @click='${(e) => { copyToClipboard(v.source, e); }}'>${getI18nText('operations.copy')}</button>\n <pre><code>${Prism.languages[v.lang?.toLowerCase()] ? unsafeHTML(Prism.highlight(fullSource, Prism.languages[v.lang?.toLowerCase()], v.lang?.toLowerCase())) : fullSource}\n </code></pre>\n </div>`;\n })\n }\n </section>`;\n}\n/* eslint-enable indent */\n","import { LitElement, html } from 'lit';\nimport { marked } from 'marked';\nimport Prism from 'prismjs';\nimport mimeTypeResolver from './mime-types';\n\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\nimport formatXml from 'xml-but-prettier';\n\nimport { copyToClipboard } from '../utils/common-utils';\nimport { getI18nText } from '../languages';\nimport { schemaInObjectNotation, getTypeInfo, generateExample } from '../utils/schema-utils';\nimport './json-tree';\nimport './schema-tree';\nimport getRequestFormTable from './request-form-table';\nimport './tag-input';\n\nconst textFileRegex = RegExp('^font/|tar$|zip$|7z$|rtf$|msword$|excel$|/pdf$|/octet-stream$|^application/vnd.');\nconst mediaFileRegex = RegExp('^audio/|^image/|^video/');\n\nexport default class ApiRequest extends LitElement {\n createRenderRoot() { return this; }\n\n constructor() {\n super();\n this.responseMessage = '';\n this.responseStatus = '';\n this.responseHeaders = '';\n this.responseText = '';\n this.responseUrl = '';\n this.responseElapsedMs = 0;\n this.curlSyntax = '';\n this.activeResponseTab = 'response'; // allowed values: response, headers, curl\n this.selectedRequestBodyType = '';\n this.selectedRequestBodyExample = '';\n }\n\n static get properties() {\n return {\n serverUrl: { type: String, attribute: 'server-url' },\n servers: { type: Array },\n method: { type: String },\n path: { type: String },\n elementId: { type: String, attribute: 'element-id' },\n parameters: { type: Array },\n request_body: { type: Object },\n api_keys: { type: Array },\n parser: { type: Object },\n accept: { type: String },\n callback: { type: String },\n responseMessage: { type: String, attribute: false },\n responseText: { type: String, attribute: false },\n responseHeaders: { type: String, attribute: false },\n responseStatus: { type: String, attribute: false },\n responseUrl: { type: String, attribute: false },\n responseElapsedMs: { type: Number, attribute: false },\n fillRequestWithDefault: { type: String, attribute: 'fill-defaults' },\n includeNulls: { type: Boolean, attribute: 'display-nulls', converter(value) { return value === 'true'; } },\n allowTry: { type: String, attribute: 'enable-console' },\n renderStyle: { type: String, attribute: 'render-style' },\n schemaStyle: { type: String, attribute: 'schema-style' },\n activeSchemaTab: { type: String, attribute: 'active-schema-tab' },\n schemaExpandLevel: { type: Number, attribute: 'schema-expand-level' },\n schemaHideReadOnly: { type: String, attribute: 'schema-hide-read-only' },\n fetchCredentials: { type: String, attribute: 'fetch-credentials' },\n\n // properties for internal tracking\n activeResponseTab: { type: String }, // internal tracking of response-tab not exposed as a attribute\n selectedRequestBodyType: { type: String, attribute: 'selected-request-body-type' }, // internal tracking of selected request-body type\n selectedRequestBodyExample: { type: String, attribute: 'selected-request-body-example' }, // internal tracking of selected request-body example\n };\n }\n\n render() {\n return html`\n <div class=\"api-request col regular-font request-panel ${(this.renderStyle === 'focused' || this.callback === 'true') ? 'focused-mode' : 'view-mode'}\">\n <div class=\" ${this.callback === 'true' ? 'tiny-title' : 'req-res-title'} \"> \n ${this.callback === 'true' ? 'CALLBACK REQUEST' : getI18nText('operations.request')}\n </div>\n <div>\n ${this.inputParametersTemplate('path')}\n ${this.inputParametersTemplate('query')}\n ${this.requestBodyTemplate()}\n ${this.inputParametersTemplate('header')}\n ${this.inputParametersTemplate('cookie')}\n ${this.allowTry === 'false' ? '' : html`${this.apiCallTemplate()}`}\n </div> \n </div>\n `;\n }\n\n updated(changedProperties) {\n // In focused mode after rendering the request component, update the text-areas(which contains examples) using the original values from hidden textareas.\n // This is done coz, user may update the dom by editing the textarea's and once the DOM is updated externally change detection wont happen, therefore update the values manually\n if (this.renderStyle !== 'focused') {\n return;\n }\n\n // dont update example as only tabs is switched\n if (changedProperties.size === 1 && changedProperties.has('activeSchemaTab')) {\n return;\n }\n\n const exampleTextAreaEls = [...this.querySelectorAll('textarea[data-ptype=\"form-data\"]')];\n exampleTextAreaEls.forEach((el) => {\n const origExampleEl = this.querySelector(`textarea[data-pname='hidden-${el.dataset.pname}']`);\n if (origExampleEl) {\n el.value = origExampleEl.value;\n }\n });\n }\n\n /* eslint-disable indent */\n inputParametersTemplate(paramType) {\n const filteredParams = this.parameters ? this.parameters.filter((param) => param.in === paramType) : [];\n if (filteredParams.length === 0) {\n return '';\n }\n\n const title = {\n path: 'PATH PARAMETERS',\n query: 'QUERY-STRING PARAMETERS',\n header: 'REQUEST HEADERS',\n cookie: 'COOKIES'\n }[paramType];\n\n const tableRows = [];\n for (const param of filteredParams) {\n if (!param.schema) {\n continue;\n }\n const paramSchema = getTypeInfo(param.schema, { includeNulls: this.includeNulls });\n if (!paramSchema) {\n continue;\n }\n const defaultVal = Array.isArray(paramSchema.default) ? paramSchema.default : `${paramSchema.default}`;\n let paramStyle = 'form';\n let paramExplode = true;\n if (paramType === 'query') {\n if (param.style && 'form spaceDelimited pipeDelimited'.includes(param.style)) {\n paramStyle = param.style;\n }\n if (typeof param.explode === 'boolean') {\n paramExplode = param.explode;\n }\n }\n\n tableRows.push(html`\n <tr> \n <td colspan=\"1\" style=\"width:160px; min-width:50px;\">\n <div class=\"param-name ${paramSchema.deprecated ? 'deprecated' : ''}\">\n ${param.name}${!paramSchema.deprecated && param.required ? html`<span style='color:var(--red);'>*</span>` : ''}\n </div>\n <div class=\"param-type\">\n ${paramSchema.type === 'array'\n ? `${paramSchema.arrayType}`\n : `${paramSchema.format ? paramSchema.format : paramSchema.type}`\n }${!paramSchema.deprecated && param.required ? html`<span style='opacity: 0;'>*</span>` : ''}\n </div>\n </td> \n ${this.allowTry === 'true'\n ? html`\n <td colspan=\"2\" style=\"min-width:160px;\">\n ${paramSchema.type === 'array' && html`\n <tag-input class=\"request-param\" \n style = \"width:100%;\" \n data-ptype = \"${paramType}\"\n data-pname = \"${param.name}\"\n data-default = \"${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}\"\n data-param-serialize-style = \"${paramStyle}\"\n data-param-serialize-explode = \"${paramExplode}\"\n data-array = \"true\"\n placeholder=\"${paramSchema.example || (Array.isArray(defaultVal) ? defaultVal[0] : defaultVal) || 'add-multiple ↩'}\"\n .value = \"${Array.isArray(defaultVal) ? defaultVal : defaultVal.split(',')}\"></tag-input>`\n || paramSchema.type === 'object' && html`\n <textarea \n class = \"textarea small request-param\"\n part = \"textarea small textarea-param\"\n rows = 3\n data-ptype = \"${paramType}\"\n data-pname = \"${param.name}\"\n data-default = \"${defaultVal}\"\n data-param-serialize-style = \"${paramStyle}\"\n data-param-serialize-explode = \"${paramExplode}\"\n spellcheck = \"false\"\n placeholder=\"${paramSchema.example || defaultVal || ''}\"\n style = \"width:100%;\"\n .value=\"${this.fillRequestWithDefault === 'true' ? defaultVal : ''}\"></textarea>`\n || html`\n <input type=\"${paramSchema.format === 'password' ? 'password' : 'text'}\" spellcheck=\"false\" style=\"width:100%\" placeholder=\"${paramSchema.example || defaultVal || ''}\"\n class=\"request-param\"\n part=\"textbox textbox-param\"\n data-ptype=\"${paramType}\"\n data-pname=\"${param.name}\" \n data-default=\"${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}\"\n data-array=\"false\"\n @keyup=\"${this.requestParamFunction}\"\n .value=\"${this.fillRequestWithDefault === 'true' ? defaultVal : ''}\"\n />`\n }\n </td>`\n : ''\n }\n ${this.renderStyle === 'focused'\n ? html`\n <td colspan=\"2\">\n ${param.description\n ? html`\n <div class=\"param-description\">\n ${unsafeHTML(marked(param.description))}\n </div>`\n : ''\n }\n ${paramSchema.default || paramSchema.constraint || paramSchema.allowedValues || paramSchema.pattern\n ? html`\n <div class=\"param-constraint\">\n ${paramSchema.constraint ? html`<span style=\"font-weight:bold\">Constraints: </span>${paramSchema.constraint}<br>` : ''}\n ${paramSchema.pattern ? html`\n <div class=\"tooltip tooltip-replace\" style=\"cursor: pointer; max-width: 100%; display: flex;\">\n <div style=\"white-space:nowrap; font-weight:bold; margin-right: 2px;\">Pattern: </div>\n <div style=\"white-space:nowrap; text-overflow:ellipsis; max-width:100%; overflow:hidden;\">${paramSchema.pattern}</div>\n <br>\n <div class=\"tooltip-text\" style=\"position: absolute; display:block;\">${paramSchema.pattern}</div>\n </div>\n ` : ''}\n ${paramSchema.allowedValues && paramSchema.allowedValues.split('┃').map((v, i) => html`\n ${i > 0 ? '|' : html`<span style=\"font-weight:bold\">Allowed: </span>`}\n ${html`\n <a part=\"anchor anchor-param-constraint\" class = \"${this.allowTry === 'true' ? '' : 'inactive-link'}\"\n data-type=\"${paramSchema.type === 'array' ? 'array' : 'string'}\"\n data-enum=\"${v.trim()}\"\n @click=\"${(e) => {\n const inputEl = e.target.closest('table').querySelector(`[data-pname=\"${param.name}\"]`);\n if (inputEl) {\n if (e.target.dataset.type === 'array') {\n inputEl.value = [e.target.dataset.enum];\n } else {\n inputEl.value = e.target.dataset.enum;\n }\n }\n }}\"\n >\n ${v} \n </a>`\n }`)}\n </div>`\n : ''\n }\n </td> \n </tr>`\n : ''\n }\n `);\n }\n\n return html`\n <div class=\"table-title top-gap\">${title}${paramType === 'path' ? html`<span style='color:var(--red);'>*</span>` : ''}</div>\n <div style=\"display:block; overflow-x:auto; max-width:100%;\">\n <table role=\"presentation\" class=\"m-table\" style=\"width:100%; word-break:break-word;\">\n ${tableRows}\n </table>\n </div>`;\n }\n\n resetRequestBodySelection() {\n this.selectedRequestBodyType = '';\n this.selectedRequestBodyExample = '';\n this.clearResponseData();\n }\n\n // Request-Body Event Handlers\n onSelectExample(e) {\n this.selectedRequestBodyExample = e.target.value;\n const exampleDropdownEl = e.target;\n window.setTimeout((selectEl) => {\n const exampleTextareaEl = selectEl.closest('.example-panel').querySelector('.request-body-param');\n const userInputExampleTextareaEl = selectEl.closest('.example-panel').querySelector('.request-body-param-user-input');\n userInputExampleTextareaEl.value = exampleTextareaEl.value;\n }, 0, exampleDropdownEl);\n }\n\n onMimeTypeChange(e) {\n this.selectedRequestBodyType = e.target.value;\n const mimeDropdownEl = e.target;\n this.selectedRequestBodyExample = '';\n window.setTimeout((selectEl) => {\n const exampleTextareaEl = selectEl.closest('.request-body-container').querySelector('.request-body-param');\n if (exampleTextareaEl) {\n const userInputExampleTextareaEl = selectEl.closest('.request-body-container').querySelector('.request-body-param-user-input');\n userInputExampleTextareaEl.value = exampleTextareaEl.value;\n }\n }, 0, mimeDropdownEl);\n }\n\n requestBodyTemplate() {\n if (!this.request_body) {\n return '';\n }\n if (Object.keys(this.request_body).length === 0) {\n return '';\n }\n\n if (this.method === 'get' || this.method === 'head') {\n return '';\n }\n\n // Variable to store partial HTMLs\n let reqBodyTypeSelectorHtml = '';\n let reqBodyFileInputHtml = '';\n let reqBodySchemaHtml = '';\n let reqBodyDefaultHtml = '';\n let bodyTabNameUseBody = true;\n\n const requestBodyTypes = [];\n const content = this.request_body.content;\n for (const mimeType in content) {\n requestBodyTypes.push({\n mimeType,\n schema: content[mimeType].schema,\n example: content[mimeType].example,\n examples: content[mimeType].examples,\n });\n if (!this.selectedRequestBodyType) {\n this.selectedRequestBodyType = mimeType;\n }\n }\n // MIME Type selector\n reqBodyTypeSelectorHtml = requestBodyTypes.length === 1\n ? ''\n : html`\n <select aria-label=\"mime type\" style=\"min-width:100px; max-width:100%; margin-bottom:-1px;\" @change = '${(e) => this.onMimeTypeChange(e)}'>\n ${requestBodyTypes.map((reqBody) => html`\n <option value = '${reqBody.mimeType}' ?selected = '${reqBody.mimeType === this.selectedRequestBodyType}'>\n ${reqBody.mimeType}\n </option> `)\n }\n </select>\n `;\n\n // For Loop - Main\n const reqBody = requestBodyTypes.find(req => req.mimeType === this.selectedRequestBodyType);\n // Generate Example\n if (this.selectedRequestBodyType.includes('json') || this.selectedRequestBodyType.includes('xml') || this.selectedRequestBodyType.includes('text')) {\n const reqBodyExamples = generateExample(\n reqBody.examples ? reqBody.examples : '',\n reqBody.example ? reqBody.example : '',\n reqBody.schema,\n reqBody.mimeType,\n false,\n true,\n 'text',\n true\n );\n\n if (!this.selectedRequestBodyExample) {\n this.selectedRequestBodyExample = (reqBodyExamples.length > 0 ? reqBodyExamples[0].exampleId : '');\n }\n const displayedBodyExample = reqBodyExamples.find(v => v.exampleId === this.selectedRequestBodyExample);\n reqBodyDefaultHtml = html`\n <div class = 'example-panel border-top pad-top-8'>\n ${reqBodyExamples.length === 1\n ? ''\n : html`\n <select aria-label='request body example' style=\"min-width:100px; max-width:100%; margin-bottom:-1px;\" @change='${(e) => this.onSelectExample(e)}'>\n ${reqBodyExamples.map((v) => html`<option value=\"${v.exampleId}\" ?selected=${v.exampleId === this.selectedRequestBodyExample}> \n ${v.exampleSummary.length > 80 ? v.exampleId : v.exampleSummary ? v.exampleSummary : v.exampleId} \n </option>`)}\n </select>`\n }\n <div class=\"example\" data-default = '${displayedBodyExample.exampleId}'>\n ${displayedBodyExample.exampleSummary && displayedBodyExample.exampleSummary.length > 80 ? html`<div style=\"padding: 4px 0\"> ${displayedBodyExample.exampleSummary} </div>` : ''}\n ${displayedBodyExample.exampleDescription ? html`<div class=\"m-markdown-small\" style=\"padding: 4px 0\"> ${unsafeHTML(marked(displayedBodyExample.exampleDescription || ''))} </div>` : ''}\n <!-- this textarea is for user to edit the example -->\n <slot name=\"${this.elementId}--request-body\">\n <textarea \n class = \"textarea request-body-param-user-input\"\n part = \"textarea textarea-param\"\n spellcheck = \"false\"\n data-ptype = \"${reqBody.mimeType}\" \n data-default = \"${displayedBodyExample.exampleFormat === 'text' ? displayedBodyExample.exampleValue : JSON.stringify(displayedBodyExample.exampleValue, null, 8)}\"\n data-default-format = \"${displayedBodyExample.exampleFormat}\"\n style=\"width:100%; resize:vertical;\"\n .value=\"${this.fillRequestWithDefault === 'true' ? (displayedBodyExample.exampleFormat === 'text' ? displayedBodyExample.exampleValue : JSON.stringify(displayedBodyExample.exampleValue, null, 8)) : ''}\"\n ></textarea>\n </slot>\n\n <!-- This textarea(hidden) is to store the original example value, this will remain unchanged when users switches from one example to another, its is used to populate the editable textarea -->\n <textarea \n class = \"textarea is-hidden request-body-param ${reqBody.mimeType.substring(reqBody.mimeType.indexOf('/') + 1)}\" \n spellcheck = \"false\"\n data-ptype = \"${reqBody.mimeType}\" \n style=\"width:100%; resize:vertical; display:none\"\n .value=\"${(displayedBodyExample.exampleFormat === 'text' ? displayedBodyExample.exampleValue : JSON.stringify(displayedBodyExample.exampleValue, null, 8))}\"\n ></textarea>\n </div> \n\n </div>\n `;\n } else if (this.selectedRequestBodyType.includes('form-urlencoded') || this.selectedRequestBodyType.includes('form-data')) {\n bodyTabNameUseBody = false;\n const schemaAsObj = schemaInObjectNotation(reqBody.schema, { includeNulls: this.includeNulls });\n reqBodyDefaultHtml = getRequestFormTable.call(this, schemaAsObj, this.selectedRequestBodyType);\n } else if (mediaFileRegex.test(this.selectedRequestBodyType) || textFileRegex.test(this.selectedRequestBodyType)) {\n reqBodyFileInputHtml = html`\n <div class = \"small-font-size bold-text row\">\n <input type=\"file\" part=\"file-input\" style=\"max-width:100%\" class=\"request-body-param-file\" data-ptype=\"${reqBody.mimeType}\" spellcheck=\"false\" />\n </div> \n `;\n }\n\n // Generate Schema\n if (reqBody.mimeType.includes('json') || reqBody.mimeType.includes('xml') || reqBody.mimeType.includes('text') || reqBody.mimeType.includes('form-')) {\n const schemaAsObj = schemaInObjectNotation(reqBody.schema, { includeNulls: this.includeNulls });\n if (this.schemaStyle === 'table') {\n reqBodySchemaHtml = html`\n ${reqBodySchemaHtml}\n <schema-table\n class = '${reqBody.mimeType.substring(reqBody.mimeType.indexOf('/') + 1)} pad-top-8'\n style = 'display: ${this.selectedRequestBodyType === reqBody.mimeType ? 'block' : 'none'};'\n .data = '${schemaAsObj}'\n schema-expand-level = \"${this.schemaExpandLevel}\"\n schema-hide-read-only = \"${this.schemaHideReadOnly.includes(this.method)}\"\n schema-hide-write-only = false\n > </schema-table>\n `;\n } else {\n reqBodySchemaHtml = html`\n ${reqBodySchemaHtml}\n <schema-tree\n class = '${reqBody.mimeType.substring(reqBody.mimeType.indexOf('/') + 1)} pad-top-8'\n style = 'display: ${this.selectedRequestBodyType === reqBody.mimeType ? 'block' : 'none'};'\n .data = '${schemaAsObj}'\n schema-expand-level = \"${this.schemaExpandLevel}\"\n schema-hide-read-only = \"${this.schemaHideReadOnly.includes(this.method)}\"\n schema-hide-write-only = false\n > </schema-tree>\n `;\n }\n }\n\n return html`\n <div class='request-body-container' data-selected-request-body-type=\"${this.selectedRequestBodyType}\">\n <div class=\"table-title top-gap row\">\n REQUEST BODY ${this.request_body.required ? html`<span class=\"mono-font\" style='color:var(--red)'>*</span>` : ''} \n <span style = \"font-weight:normal; margin-left:5px\"> ${this.selectedRequestBodyType}</span>\n <span style=\"flex:1\"></span>\n ${reqBodyTypeSelectorHtml}\n </div>\n ${this.request_body.description ? html`<div class=\"m-markdown\" style=\"margin-bottom:12px\">${unsafeHTML(marked(this.request_body.description))}</div>` : ''}\n \n ${reqBodySchemaHtml || reqBodyDefaultHtml\n ? html`\n <div class=\"tab-panel col\" style=\"border-width:0 0 1px 0;\">\n <div class=\"tab-buttons row\" @click=\"${(e) => { if (e.target.tagName.toLowerCase() === 'button') { this.activeSchemaTab = e.target.dataset.tab; } }}\">\n <button class=\"tab-btn ${this.activeSchemaTab === 'model' ? 'active' : ''}\" data-tab=\"model\" >${getI18nText('operations.model')}</button>\n <button class=\"tab-btn ${this.activeSchemaTab !== 'model' ? 'active' : ''}\" data-tab=\"body\">${bodyTabNameUseBody ? getI18nText('operations.body') : getI18nText('operations.form')}</button>\n </div>\n ${html`<div class=\"tab-content col\" style=\"display: ${this.activeSchemaTab === 'model' ? 'block' : 'none'}\"> ${reqBodySchemaHtml}</div>`}\n ${html`<div class=\"tab-content col\" style=\"display: ${this.activeSchemaTab === 'model' ? 'none' : 'block'}\"> ${reqBodyDefaultHtml}</div>`}\n </div>`\n : html`${reqBodyFileInputHtml}`\n }\n </div> \n `;\n }\n\n // formDataTemplate(schema, mimeType, exampleValue = '') {\n // return html`\n // <textarea\n // class = \"textarea dynamic-form-param ${mimeType}\"\n // part = \"textarea textarea-param\"\n // spellcheck = \"false\"\n // data-pname=\"dynamic-form\"\n // data-ptype=\"${mimeType}\"\n // style=\"width:100%\"\n // >${exampleValue}</textarea>\n // ${schema.description ? html`<span class=\"m-markdown-small\">${unsafeHTML(marked(schema.description))}</span>` : ''}\n // `;\n // }\n\n apiResponseTabTemplate() {\n const responseFormat = this.responseHeaders.includes('json') ? 'json' : (this.responseHeaders.includes('html') || this.responseHeaders.includes('xml')) ? 'html' : '';\n return html`\n <div class=\"row\" style=\"font-size:var(--font-size-small); margin:5px 0\">\n ${this.responseMessage\n ? html`<div class=\"response-message ${this.responseStatus}\">Response Status: ${this.responseMessage}\n ${this.responseElapsedMs ? html`<span><br>Execution Time: ${this.responseElapsedMs}ms</span>` : ''}\n </div>` : ''\n }\n <div style=\"flex:1\"></div>\n <button class=\"m-btn\" part=\"btn btn-outline\" @click=\"${this.clearResponseData}\">CLEAR RESPONSE</button>\n </div>\n <div class=\"tab-panel col\" style=\"border-width:0 0 1px 0;\">\n <div id=\"tab_buttons\" class=\"tab-buttons row\" @click=\"${(e) => {\n if (e.target.classList.contains('tab-btn') === false) { return; }\n this.activeResponseTab = e.target.dataset.tab;\n }}\">\n <button class=\"tab-btn ${this.activeResponseTab === 'response' ? 'active' : ''}\" data-tab = 'response'>${getI18nText('operations.response')}</button>\n <button class=\"tab-btn ${this.activeResponseTab === 'headers' ? 'active' : ''}\" data-tab = 'headers'>${getI18nText('operations.response-headers')}</button>\n <button class=\"tab-btn ${this.activeResponseTab === 'curl' ? 'active' : ''}\" data-tab = 'curl'>CURL</button>\n </div>\n ${this.responseIsBlob\n ? html`\n <div class=\"tab-content col\" style=\"flex:1; display:${this.activeResponseTab === 'response' ? 'flex' : 'none'};\">\n <button class=\"m-btn thin-border mar-top-8\" style=\"width:135px\" @click=\"${this.downloadResponseBlob}\" part=\"btn btn-outline\">DOWNLOAD</button>\n ${this.responseBlobType === 'view'\n ? html`<button class=\"m-btn thin-border mar-top-8\" style=\"width:135px\" @click=\"${this.viewResponseBlob}\" part=\"btn btn-outline\">VIEW (NEW TAB)</button>`\n : ''\n }\n </div>`\n : html`\n <div class=\"tab-content col m-markdown\" style=\"flex:1; display:${this.activeResponseTab === 'response' ? 'flex' : 'none'};\" >\n ${this.responseText\n ? html`<button class=\"m-btn outline-primary toolbar-copy-btn\" @click='${(e) => { copyToClipboard(this.responseText, e); }}' part=\"btn btn-fill\">${getI18nText('operations.copy')}</button>`\n : ''\n }\n <pre style=\"min-height: 60px\" @copy='${() => { copyToClipboard(window.getSelection().toString()); }}'>${responseFormat\n ? html`<code>${unsafeHTML(Prism.highlight(this.responseText, Prism.languages[responseFormat], responseFormat))}</code>`\n : `${this.responseText}`\n }\n </pre>\n </div>`\n }\n <div class=\"tab-content col m-markdown\" style=\"flex:1;display:${this.activeResponseTab === 'headers' ? 'flex' : 'none'};\" >\n <button class=\"m-btn outline-primary toolbar-copy-btn\" @click='${(e) => { copyToClipboard(this.responseHeaders, e); }}' part=\"btn btn-fill\">${getI18nText('operations.copy')}</button>\n <pre><code>${unsafeHTML(Prism.highlight(this.responseHeaders, Prism.languages.css, 'css'))}</code></pre>\n </div>\n <div class=\"tab-content col m-markdown\" style=\"flex:1;display:${this.activeResponseTab === 'curl' ? 'flex' : 'none'};\">\n <button class=\"m-btn outline-primary toolbar-copy-btn\" @click='${(e) => { copyToClipboard(this.curlSyntax, e); }}' part=\"btn btn-fill\">${getI18nText('operations.copy')}</button>\n <pre class=\"fs-exclude\" data-hj-suppress data-sl=\"mask\">\n <code>${unsafeHTML(Prism.highlight(this.curlSyntax.trim(), Prism.languages.shell, 'shell'))}</code>\n </pre>\n </div>\n </div>`;\n }\n\n apiCallTemplate() {\n return html`\n <div style=\"display:flex; align-items:flex-end; margin:16px 0; font-size:var(--font-size-small);\">\n ${\n this.parameters.length > 0 || this.request_body\n ? html`\n <button class=\"m-btn thin-border\" part=\"btn btn-outline\" style=\"margin-right:5px;\" @click=\"${this.onClearRequestData}\">\n ${getI18nText('operations.clear')}\n </button>`\n : ''\n }\n <button class=\"m-btn primary btn-execute thin-border\" part=\"btn btn-fill btn-try\" @click=\"${this.onTryClick}\">${getI18nText('operations.execute')}</button>\n </div>\n ${this.responseMessage === '' ? '' : this.apiResponseTabTemplate()}\n `;\n }\n /* eslint-enable indent */\n\n onClearRequestData(e) {\n const requestPanelEl = e.target.closest('.request-panel');\n const requestPanelInputEls = [...requestPanelEl.querySelectorAll('input, tag-input, textarea:not(.is-hidden)')];\n requestPanelInputEls.forEach((el) => { el.value = ''; });\n\n const event = { bubbles: true, composed: true, detail: { explorerLocation: this.elementId, operation: { method: this.method, path: this.path }, type: 'RequestCleared' } };\n this.dispatchEvent(new CustomEvent('event', event));\n }\n\n async onTryClick() {\n const tryBtnEl = this.querySelectorAll('.btn-execute')[0];\n let curlData = '';\n let curlForm = '';\n const closestRespContainer = this.closest('.expanded-req-resp-container, .req-resp-container');\n const respEl = closestRespContainer && closestRespContainer.getElementsByTagName('api-response')[0];\n const acceptHeader = respEl?.selectedMimeType;\n const requestPanelEl = this.closest('.request-panel');\n const pathParamEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='path']\")];\n const queryParamEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='query']\")];\n const queryParamObjTypeEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='query-object']\")];\n const headerParamEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='header']\")];\n const requestBodyContainerEl = requestPanelEl.querySelector('.request-body-container');\n\n let pathUrl = `${this.serverUrl.replace(/\\/$/, '')}${this.path.replaceAll(' ', '')}`;\n\n // Generate URL using Path Params\n pathParamEls.map((el) => {\n pathUrl = pathUrl.replace(`{${el.dataset.pname}}`, encodeURIComponent(el.value) || '-');\n });\n\n // Handle relative serverUrls\n if (!pathUrl.startsWith('http')) {\n const newUrl = new URL(pathUrl, window.location.href);\n pathUrl = newUrl.toString();\n }\n\n const fetchUrl = new URL(pathUrl);\n\n const fetchOptions = {\n method: this.method.toUpperCase(),\n headers: new Headers()\n };\n\n // Query Params\n if (queryParamEls.length > 0) {\n queryParamEls.forEach((el) => {\n if (el.dataset.array === 'false') {\n if (el.value !== '') {\n fetchUrl.searchParams.append(el.dataset.pname, el.value);\n }\n } else {\n const paramSerializeStyle = el.dataset.paramSerializeStyle;\n const paramSerializeExplode = el.dataset.paramSerializeExplode;\n let vals = ((el.value && Array.isArray(el.value)) ? el.value : []);\n vals = Array.isArray(vals) ? vals.filter((v) => v !== '') : [];\n if (vals.length > 0) {\n if (paramSerializeStyle === 'spaceDelimited') {\n fetchUrl.searchParams.append(el.dataset.pname, vals.join(' ').replace(/^\\s|\\s$/g, ''));\n } else if (paramSerializeStyle === 'pipeDelimited') {\n fetchUrl.searchParams.append(el.dataset.pname, vals.join('|').replace(/^\\||\\|$/g, ''));\n } else {\n if (paramSerializeExplode === 'true') { // eslint-disable-line no-lonely-if\n vals.forEach((v) => { fetchUrl.searchParams.append(el.dataset.pname, v); });\n } else {\n fetchUrl.searchParams.append(el.dataset.pname, vals.join(',').replace(/^,|,$/g, ''));\n }\n }\n }\n }\n });\n }\n\n // Query Params (Dynamic - create from JSON)\n if (queryParamObjTypeEls.length > 0) {\n queryParamObjTypeEls.map((el) => {\n try {\n let queryParamObj = {};\n const paramSerializeStyle = el.dataset.paramSerializeStyle;\n const paramSerializeExplode = el.dataset.paramSerializeExplode;\n queryParamObj = Object.assign(queryParamObj, JSON.parse(el.value.replace(/\\s+/g, ' ')));\n for (const key in queryParamObj) {\n if (typeof queryParamObj[key] === 'object') {\n if (Array.isArray(queryParamObj[key])) {\n if (paramSerializeStyle === 'spaceDelimited') {\n fetchUrl.searchParams.append(key, queryParamObj[key].join(' '));\n } else if (paramSerializeStyle === 'pipeDelimited') {\n fetchUrl.searchParams.append(key, queryParamObj[key].join('|'));\n } else {\n if (paramSerializeExplode === 'true') { // eslint-disable-line no-lonely-if\n queryParamObj[key].forEach((v) => {\n fetchUrl.searchParams.append(key, v);\n });\n } else {\n fetchUrl.searchParams.append(key, queryParamObj[key]);\n }\n }\n }\n } else {\n fetchUrl.searchParams.append(key, queryParamObj[key]);\n }\n }\n } catch (err) {\n console.log('OpenAPI Explorer: unable to parse %s into object', el.value); // eslint-disable-line no-console\n }\n });\n }\n\n // Add Authentication api keys if provided\n this.api_keys.filter((v) => v.finalKeyValue).forEach((v) => {\n if (v.in === 'query') {\n fetchUrl.searchParams.append(v.name, v.finalKeyValue);\n return;\n }\n\n // Otherwise put it in the header\n fetchOptions.headers.append(v.name, v.finalKeyValue);\n });\n\n if (acceptHeader) {\n // Uses the acceptHeader from Response panel\n fetchOptions.headers.append('Accept', acceptHeader);\n } else if (this.accept) {\n fetchOptions.headers.append('Accept', this.accept);\n }\n\n // Add Header Params\n headerParamEls.map((el) => {\n if (el.value) {\n fetchOptions.headers.append(el.dataset.pname, el.value);\n }\n });\n\n // Request Body Params\n if (requestBodyContainerEl) {\n const requestBodyType = requestBodyContainerEl.dataset.selectedRequestBodyType;\n if (requestBodyType.includes('form-urlencoded')) {\n // url-encoded Form Params (dynamic) - Parse JSON and generate Params\n const formUrlDynamicTextAreaEl = requestPanelEl.querySelector(\"[data-ptype='dynamic-form']\");\n if (formUrlDynamicTextAreaEl) {\n const val = formUrlDynamicTextAreaEl.value;\n const formUrlDynParams = new URLSearchParams();\n let proceed = true;\n let tmpObj;\n if (val) {\n try {\n tmpObj = JSON.parse(val);\n } catch (err) {\n proceed = false;\n console.warn('OpenAPI Explorer: Invalid JSON provided', err); // eslint-disable-line no-console\n }\n } else {\n proceed = false;\n }\n if (proceed) {\n for (const prop in tmpObj) {\n formUrlDynParams.append(prop, JSON.stringify(tmpObj[prop]));\n }\n fetchOptions.body = formUrlDynParams;\n curlData = ` \\\\\\n -d ${formUrlDynParams.toString()}`;\n }\n } else {\n // url-encoded Form Params (regular)\n const formUrlEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='form-urlencode']\")];\n const formUrlParams = new URLSearchParams();\n formUrlEls\n .filter((v) => (v.type !== 'file'))\n .forEach((el) => {\n if (el.dataset.array === 'false') {\n if (el.value) {\n formUrlParams.append(el.dataset.pname, el.value);\n }\n } else {\n const vals = (el.value && Array.isArray(el.value)) ? el.value.join(',') : '';\n formUrlParams.append(el.dataset.pname, vals);\n }\n });\n fetchOptions.body = formUrlParams;\n curlData = ` \\\\\\n -d ${formUrlParams.toString()}`;\n }\n } else if (requestBodyType.includes('form-data')) {\n const formDataParams = new FormData();\n const formDataEls = [...requestPanelEl.querySelectorAll(\"[data-ptype='form-data']\")];\n formDataEls.forEach((el) => {\n if (el.dataset.array === 'false') {\n if (el.type === 'file' && el.files[0]) {\n formDataParams.append(el.dataset.pname, el.files[0], el.files[0].name);\n curlForm += ` \\\\\\n -F \"${el.dataset.pname}=@${el.files[0].name}\"`;\n } else if (el.value) {\n formDataParams.append(el.dataset.pname, el.value);\n curlForm += ` \\\\\\n -F \"${el.dataset.pname}=${el.value}\"`;\n }\n } else if (el.value && Array.isArray(el.value)) {\n el.value.forEach((v) => {\n curlForm += ` \\\\\\n -F \"${el.dataset.pname}[]=${v}\"`;\n });\n formDataParams.append(el.dataset.pname, el.value.join(','));\n }\n });\n fetchOptions.body = formDataParams;\n } else if (mediaFileRegex.test(requestBodyType) || textFileRegex.test(requestBodyType)) {\n const bodyParamFileEl = requestPanelEl.querySelector('.request-body-param-file');\n if (bodyParamFileEl && bodyParamFileEl.files[0]) {\n fetchOptions.body = bodyParamFileEl.files[0];\n curlData = ` \\\\\\n --data-binary @${bodyParamFileEl.files[0].name}`;\n }\n } else if (requestBodyType.includes('json') || requestBodyType.includes('xml') || requestBodyType.includes('text')) {\n const exampleTextAreaEl = requestPanelEl.querySelector('.request-body-param-user-input');\n if (exampleTextAreaEl && exampleTextAreaEl.value) {\n fetchOptions.body = exampleTextAreaEl.value;\n if (requestBodyType.includes('json')) {\n try {\n curlData = ` \\\\\\n -d '${JSON.stringify(JSON.parse(exampleTextAreaEl.value))}'`;\n } catch (err) { /* Ignore unparseable JSON */ }\n }\n\n if (!curlData) {\n // Save single quotes wrapped => 'text' => `\"'\"text\"'\"`\n curlData = ` \\\\\\n -d '${exampleTextAreaEl.value.replace(/'/g, '\\'\"\\'\"\\'')}'`;\n }\n }\n }\n // Common for all request-body\n if (!requestBodyType.includes('form-data')) {\n // For multipart/form-data don't set the content-type to allow creation of browser generated part boundaries\n fetchOptions.headers.append('Content-Type', requestBodyType);\n }\n }\n\n this.responseIsBlob = false;\n this.respContentDisposition = '';\n if (this.responseBlobUrl) {\n URL.revokeObjectURL(this.responseBlobUrl);\n this.responseBlobUrl = '';\n }\n\n if (this.fetchCredentials) {\n fetchOptions.credentials = this.fetchCredentials;\n }\n\n // Options is legacy usage, documentation has been updated to reference properties of the fetch option directly, but older usages may still be using options\n const fetchRequest = { explorerLocation: this.elementId, url: fetchUrl.toString(), options: fetchOptions, ...fetchOptions };\n const event = {\n bubbles: true,\n composed: true,\n detail: {\n request: fetchRequest,\n },\n };\n this.dispatchEvent(new CustomEvent('before-try', event));\n this.dispatchEvent(new CustomEvent('request', event));\n const newFetchOptions = {\n method: fetchRequest.method || fetchOptions.method,\n headers: fetchRequest.headers || fetchOptions.headers,\n credentials: fetchRequest.credentials || fetchOptions.credentials,\n body: fetchRequest.body || fetchOptions.body\n };\n const fetchRequestObject = new Request(fetchRequest.url, newFetchOptions);\n\n const curl = `curl -X ${this.method.toUpperCase()} \"${fetchUrl.toString()}\"`;\n const curlHeaders = [...newFetchOptions.headers.entries()].reduce((acc, [key, value]) => `${acc} \\\\\\n -H \"${key}: ${value}\"`, '');\n this.curlSyntax = `${curl}${curlHeaders}${curlData}${curlForm}`;\n\n let fetchResponse;\n try {\n let respBlob;\n let respJson;\n let respText;\n tryBtnEl.disabled = true;\n const fetchStart = new Date();\n\n this.responseStatus = '';\n this.responseMessage = '';\n this.responseUrl = '';\n this.responseHeaders = '';\n this.responseText = '⌛';\n\n this.requestUpdate();\n const awaiter = new Promise(resolve => setTimeout(resolve, 200));\n fetchResponse = await fetch(fetchRequestObject);\n this.responseElapsedMs = new Date() - fetchStart;\n await awaiter;\n\n tryBtnEl.disabled = false;\n this.responseStatus = fetchResponse.ok ? 'success' : 'error';\n this.responseMessage = fetchResponse.statusText ? `${fetchResponse.statusText} (${fetchResponse.status})` : fetchResponse.status;\n this.responseUrl = fetchResponse.url;\n this.responseHeaders = '';\n const headers = {};\n fetchResponse.headers.forEach((hdrVal, hdr) => {\n this.responseHeaders = `${this.responseHeaders}${hdr.trim()}: ${hdrVal}\\n`;\n headers[hdr.trim()] = hdrVal && hdrVal.trim();\n });\n const contentType = fetchResponse.headers.get('content-type');\n const respEmpty = (await fetchResponse.clone().text()).length === 0;\n if (respEmpty) {\n this.responseText = '';\n } else if (contentType) {\n if (contentType.includes('json')) {\n if ((/charset=[^\"']+/).test(contentType)) {\n const encoding = contentType.split('charset=')[1];\n const buffer = await fetchResponse.arrayBuffer();\n try {\n respText = new TextDecoder(encoding).decode(buffer);\n } catch (_) {\n respText = new TextDecoder('utf-8').decode(buffer);\n }\n try {\n this.responseText = JSON.stringify(JSON.parse(respText), null, 8);\n } catch (_) {\n this.responseText = respText;\n }\n } else {\n respJson = await fetchResponse.json();\n this.responseText = JSON.stringify(respJson, null, 8);\n }\n } else if (textFileRegex.test(contentType)) {\n this.responseIsBlob = true;\n this.responseBlobType = 'download';\n } else if (mediaFileRegex.test(contentType)) {\n this.responseIsBlob = true;\n this.responseBlobType = 'view';\n } else {\n respText = await fetchResponse.text();\n if (contentType.includes('xml')) {\n this.responseText = formatXml(respText, { textNodesOnSameLine: true, indentor: ' ' });\n } else {\n this.responseText = respText;\n }\n }\n if (this.responseIsBlob) {\n const contentDisposition = fetchResponse.headers.get('content-disposition');\n const filenameRegex = /filename[^;=\\n]*=((['\"]).*?\\2|[^;\\n]*)/;\n const filename = filenameRegex.exec(contentDisposition);\n this.respContentDisposition = filename && filename[1] && filename[1].replace(/['\"]/g, '') || `download.${mimeTypeResolver.extension(contentType) || 'file'}`;\n respBlob = await fetchResponse.blob();\n this.responseBlobUrl = URL.createObjectURL(respBlob);\n }\n } else {\n respText = await fetchResponse.text();\n this.responseText = respText;\n }\n const responseEvent = {\n bubbles: true,\n composed: true,\n detail: {\n explorerLocation: this.elementId,\n request: fetchRequest,\n response: {\n headers,\n body: respJson || respText || respBlob || fetchResponse.body,\n status: fetchResponse.status,\n },\n },\n };\n this.dispatchEvent(new CustomEvent('after-try', responseEvent));\n this.dispatchEvent(new CustomEvent('response', responseEvent));\n } catch (error) {\n tryBtnEl.disabled = false;\n this.responseMessage = `${error.message} (Check the browser network tab for more information.)`;\n this.responseStatus = 'error';\n const responseEvent = {\n bubbles: true,\n composed: true,\n detail: {\n explorerLocation: this.elementId,\n error,\n request: fetchRequest,\n },\n };\n document.dispatchEvent(new CustomEvent('after-try', responseEvent));\n document.dispatchEvent(new CustomEvent('response', responseEvent));\n }\n }\n\n onAddRemoveFileInput(e, pname, ptype) {\n if (e.target.tagName.toLowerCase() !== 'button') {\n return;\n }\n\n if (e.target.classList.contains('file-input-remove-btn')) {\n // Remove File Input Set\n const el = e.target.closest('.input-set');\n el.remove();\n return;\n }\n const el = e.target.closest('.file-input-container');\n\n // Add File Input Set\n\n // Container\n const newInputContainerEl = document.createElement('div');\n newInputContainerEl.setAttribute('class', 'input-set row');\n\n // File Input\n const newInputEl = document.createElement('input');\n newInputEl.type = 'file';\n newInputEl.setAttribute('class', 'file-input');\n newInputEl.setAttribute('data-pname', pname);\n newInputEl.setAttribute('data-ptype', ptype.includes('form-urlencode') ? 'form-urlencode' : 'form-data');\n newInputEl.setAttribute('data-array', 'false');\n newInputEl.setAttribute('data-file-array', 'true');\n\n // Remover Button\n const newRemoveBtnEl = document.createElement('button');\n newRemoveBtnEl.setAttribute('class', 'file-input-remove-btn');\n newRemoveBtnEl.innerHTML = '&#x2715;';\n\n newInputContainerEl.appendChild(newInputEl);\n newInputContainerEl.appendChild(newRemoveBtnEl);\n el.insertBefore(newInputContainerEl, e.target);\n // el.appendChild(newInputContainerEl);\n }\n\n downloadResponseBlob() {\n if (this.responseBlobUrl) {\n const a = document.createElement('a');\n document.body.appendChild(a);\n a.style = 'display: none';\n a.href = this.responseBlobUrl;\n a.download = this.respContentDisposition;\n a.click();\n a.remove();\n }\n }\n\n viewResponseBlob() {\n if (this.responseBlobUrl) {\n const a = document.createElement('a');\n document.body.appendChild(a);\n a.style = 'display: none';\n a.href = this.responseBlobUrl;\n a.target = '_blank';\n a.click();\n a.remove();\n }\n }\n\n clearResponseData() {\n this.responseUrl = '';\n this.responseHeaders = '';\n this.responseText = '';\n this.responseStatus = '';\n this.responseMessage = '';\n this.responseElapsedMs = 0;\n this.responseIsBlob = false;\n this.responseBlobType = '';\n this.respContentDisposition = '';\n if (this.responseBlobUrl) {\n URL.revokeObjectURL(this.responseBlobUrl);\n this.responseBlobUrl = '';\n }\n }\n\n requestParamFunction(event) {\n if (event.key === 'Enter') {\n this.onTryClick();\n event.preventDefault();\n }\n }\n\n disconnectedCallback() {\n // Cleanup ObjectURL forthe blob data if this component created one\n if (this.responseBlobUrl) {\n URL.revokeObjectURL(this.responseBlobUrl);\n this.responseBlobUrl = '';\n }\n super.disconnectedCallback();\n }\n}\n\n// Register the element with the browser\nif (!customElements.get('openapi-explorer')) {\n customElements.define('api-request', ApiRequest);\n}\n"],"names":[],"sourceRoot":""}
@@ -718,13 +718,13 @@ export default class ApiRequest extends LitElement {
718
718
 
719
719
  try {
720
720
  respText = new TextDecoder(encoding).decode(buffer);
721
- } catch {
721
+ } catch (_) {
722
722
  respText = new TextDecoder('utf-8').decode(buffer);
723
723
  }
724
724
 
725
725
  try {
726
726
  this.responseText = JSON.stringify(JSON.parse(respText), null, 8);
727
- } catch {
727
+ } catch (_) {
728
728
  this.responseText = respText;
729
729
  }
730
730
  } else {
@@ -58,7 +58,7 @@ export default class SchemaTable extends LitElement {
58
58
  return html` ${this.data && this.data['::description'] ? html`<span class="m-markdown" style="padding-bottom:8px"> ${unsafeHTML(marked(this.data['::description'] || ''))}</span>` : ''} <div class="table"> <div style="border:1px solid var(--light-border-color)"> <div style="display:flex;background-color:var(--bg2);padding:8px 4px;border-bottom:1px solid var(--light-border-color)"> <div class="key" style="font-family:var(--font-regular);font-weight:700;color:var(--fg);padding-left:${firstColumnInitialPadding}px"> Field </div> <div class="key-type" style="font-family:var(--font-regular);font-weight:700;color:var(--fg)"> Type </div> <div class="key-descr" style="font-family:var(--font-regular);font-weight:700;color:var(--fg)"> Description </div> </div> ${this.data ? html`${this.generateTree(this.data['::type'] === 'array' ? this.data['::props'] : this.data, this.data['::type'])}` : ''} </div> </div> `;
59
59
  }
60
60
 
61
- generateTree(data, dataType = 'object', key = '', description = '', schemaLevel = 0, indentLevel = 0) {
61
+ generateTree(data, dataType = 'object', key = '', title = '', description = '', schemaLevel = 0, indentLevel = 0) {
62
62
  var _keyLabel;
63
63
 
64
64
  const newSchemaLevel = data['::type'] && data['::type'].startsWith('xxx-of') ? schemaLevel : schemaLevel + 1;
@@ -118,8 +118,8 @@ export default class SchemaTable extends LitElement {
118
118
  return undefined;
119
119
  }
120
120
 
121
- const displayLine = [description].filter(v => v).join(' ');
122
- return html` ${newSchemaLevel >= 0 && key ? html` <div class="tr ${newSchemaLevel <= this.schemaExpandLevel ? '' : 'collapsed'} ${data['::type']}" data-obj="${keyLabel}"> <div class="td no-select key ${data['::deprecated'] ? 'deprecated' : ''}" style="padding-left:${leftPadding}px;cursor:pointer" @click="${e => this.toggleObjectExpand(e, keyLabel)}"> <div style="display:flex;align-items:center"> ${keyLabel || keyDescr ? html`<div class="obj-toggle" data-obj="${keyLabel}">▾</div>` : ''} ${data['::type'] === 'xxx-of-option' || data['::type'] === 'xxx-of-array' || key.startsWith('::OPTION') ? html`<span class="xxx-of-key" style="margin-left:-6px">${keyLabel}</span><span class="${isOneOfLabel ? 'xxx-of-key' : 'xxx-of-descr'}">${keyDescr}</span>` : keyLabel.endsWith('*') ? html`<span class="key-label" style="display:inline-block;margin-left:-6px"> ${keyLabel.substring(0, keyLabel.length - 1)}</span><span style="color:var(--red)">*</span>` : html`<span class="key-label" style="display:inline-block;margin-left:-6px">${keyLabel === '::props' ? '' : keyLabel}</span>`} </div> </div> <div class="td key-type"> <div>${(data['::type'] || '').includes('xxx-of') ? '' : detailObjType}</div> <div class="attributes" title="${flags['🆁'] && 'Read only attribute' || flags['🆆'] && 'Write only attribute' || ''}">${flags['🆁'] || flags['🆆'] || ''}</div> </div> <div class="td key-descr m-markdown-small">${unsafeHTML(marked(displayLine))}</div> </div>` : html` ${data['::type'] === 'array' && dataType === 'array' ? html`<div class="tr"> <div class="td"> ${dataType} </div> </div>` : ''} `} <div class="object-body"> ${Array.isArray(data) && data[0] ? html`${this.generateTree(data[0], 'xxx-of-option', '::ARRAY~OF', '', newSchemaLevel, newIndentLevel)}` : html` ${Object.keys(data).map(dataKey => !['::title', '::description', '::type', '::props', '::deprecated', '::array-type', '::dataTypeLabel', '::flags'].includes(dataKey) || data[dataKey]['::type'] === 'array' && data[dataKey]['::type'] === 'object' ? html`${this.generateTree(data[dataKey]['::type'] === 'array' ? data[dataKey]['::props'] : data[dataKey], data[dataKey]['::type'], dataKey, data[dataKey]['::description'], newSchemaLevel, newIndentLevel)}` : '')}`} <div> </div></div>`;
121
+ const displayLine = [title && `**${title}:**`, description].filter(v => v).join(' ');
122
+ return html` ${newSchemaLevel >= 0 && key ? html` <div class="tr ${newSchemaLevel <= this.schemaExpandLevel ? '' : 'collapsed'} ${data['::type']}" data-obj="${keyLabel}"> <div class="td no-select key ${data['::deprecated'] ? 'deprecated' : ''}" style="padding-left:${leftPadding}px;cursor:pointer" @click="${e => this.toggleObjectExpand(e, keyLabel)}"> <div style="display:flex;align-items:center"> ${keyLabel || keyDescr ? html`<div class="obj-toggle" data-obj="${keyLabel}">▾</div>` : ''} ${data['::type'] === 'xxx-of-option' || data['::type'] === 'xxx-of-array' || key.startsWith('::OPTION') ? html`<span class="xxx-of-key" style="margin-left:-6px">${keyLabel}</span><span class="${isOneOfLabel ? 'xxx-of-key' : 'xxx-of-descr'}">${keyDescr}</span>` : keyLabel.endsWith('*') ? html`<span class="key-label" style="display:inline-block;margin-left:-6px"> ${keyLabel.substring(0, keyLabel.length - 1)}</span><span style="color:var(--red)">*</span>` : html`<span class="key-label" style="display:inline-block;margin-left:-6px">${keyLabel === '::props' ? '' : keyLabel}</span>`} </div> </div> <div class="td key-type"> <div>${(data['::type'] || '').includes('xxx-of') ? '' : detailObjType}</div> <div class="attributes" title="${flags['🆁'] && 'Read only attribute' || flags['🆆'] && 'Write only attribute' || ''}">${flags['🆁'] || flags['🆆'] || ''}</div> </div> <div class="td key-descr m-markdown-small">${unsafeHTML(marked(displayLine))}</div> </div>` : html` ${data['::type'] === 'array' && dataType === 'array' ? html`<div class="tr"> <div class="td"> ${dataType} </div> </div>` : ''} `} <div class="object-body"> ${Array.isArray(data) && data[0] ? html`${this.generateTree(data[0], 'xxx-of-option', '::ARRAY~OF', data[0]['::title'], data[0]['::description'], newSchemaLevel, newIndentLevel)}` : html` ${Object.keys(data).map(dataKey => !['::title', '::description', '::type', '::props', '::deprecated', '::array-type', '::dataTypeLabel', '::flags'].includes(dataKey) || data[dataKey]['::type'] === 'array' && data[dataKey]['::type'] === 'object' ? html`${this.generateTree(data[dataKey]['::type'] === 'array' ? data[dataKey]['::props'] : data[dataKey], data[dataKey]['::type'], dataKey, data[dataKey]['::title'], data[dataKey]['::description'], newSchemaLevel, newIndentLevel)}` : '')}`} <div> </div></div>`;
123
123
  } // For Primitive Data types
124
124
 
125
125
 
@@ -146,7 +146,7 @@ export default class SchemaTable extends LitElement {
146
146
  return undefined;
147
147
  }
148
148
 
149
- return html` <div class="tr"> <div class="td key ${deprecated ? 'deprecated' : ''}" style="padding-left:${leftPadding}px"> ${(_keyLabel = keyLabel) !== null && _keyLabel !== void 0 && _keyLabel.endsWith('*') ? html`<span class="key-label">${keyLabel.substring(0, keyLabel.length - 1)}</span><span style="color:var(--red)">*</span>` : key.startsWith('::OPTION') ? html`<span class="xxx-of-key">${keyLabel}</span><span class="xxx-of-descr">${keyDescr}</span>` : html`${keyLabel ? html`<span class="key-label"> ${keyLabel}</span>` : html`<span class="xxx-of-descr">${schemaTitle}</span>`}`} </div> <div class="td key-type"> <div>${dataType === 'array' ? '[' : ''}<span class="${cssType}">${format || type}</span>${dataType === 'array' ? ']' : ''}</div> <div class="attributes ${cssType}" style="font-family:var(--font-mono)" title="${readOrWriteOnly === '🆁' && 'Read only attribute' || readOrWriteOnly === '🆆' && 'Write only attribute' || ''}">${readOrWriteOnly}</div> </div> <div class="td key-descr"> ${dataType === 'array' ? html`<span class="m-markdown-small">${unsafeHTML(marked(description))}</span>` : ''} <span class="m-markdown-small" style="vertical-align:middle"> ${unsafeHTML(marked(`${dataType === 'array' && description || `${schemaTitle ? `**${schemaTitle}:**` : ''} ${schemaDescription}` || ''}`))} </span> ${this.schemaDescriptionExpanded ? html` ${constraint ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Constraints: </span>${constraint}</div><br>` : ''} ${defaultValue ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Default: </span>${defaultValue}</div><br>` : ''} ${allowedValues ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Allowed: </span>${allowedValues}</div><br>` : ''} ${pattern ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Pattern: </span>${pattern}</div><br>` : ''} ${example ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Example: </span>${example}</div><br>` : ''}` : ''} </div> </div> `;
149
+ return html` <div class="tr"> <div class="td key ${deprecated ? 'deprecated' : ''}" style="padding-left:${leftPadding}px"> ${(_keyLabel = keyLabel) !== null && _keyLabel !== void 0 && _keyLabel.endsWith('*') ? html`<span class="key-label">${keyLabel.substring(0, keyLabel.length - 1)}</span><span style="color:var(--red)">*</span>` : key.startsWith('::OPTION') ? html`<span class="xxx-of-key">${keyLabel}</span><span class="xxx-of-descr">${keyDescr}</span>` : html`${keyLabel ? html`<span class="key-label"> ${keyLabel}</span>` : html`<span class="xxx-of-descr">${schemaTitle}</span>`}`} </div> <div class="td key-type"> <div>${dataType === 'array' ? '[' : ''}<span class="${cssType}">${format || type}</span>${dataType === 'array' ? ']' : ''}</div> <div class="attributes ${cssType}" style="font-family:var(--font-mono)" title="${readOrWriteOnly === '🆁' && 'Read only attribute' || readOrWriteOnly === '🆆' && 'Write only attribute' || ''}">${readOrWriteOnly}</div> </div> <div class="td key-descr"> <span class="m-markdown-small" style="vertical-align:middle"> ${unsafeHTML(marked(`${`${schemaTitle || title ? `**${schemaTitle || title}:**` : ''} ${schemaDescription || description}` || ''}`))} </span> ${this.schemaDescriptionExpanded ? html` ${constraint ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Constraints: </span>${constraint}</div><br>` : ''} ${defaultValue ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Default: </span>${defaultValue}</div><br>` : ''} ${allowedValues ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Allowed: </span>${allowedValues}</div><br>` : ''} ${pattern ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Pattern: </span>${pattern}</div><br>` : ''} ${example ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Example: </span>${example}</div><br>` : ''}` : ''} </div> </div> `;
150
150
  }
151
151
  /* eslint-enable indent */
152
152
 
@@ -63,7 +63,7 @@ export default class SchemaTree extends LitElement {
63
63
  this.requestUpdate();
64
64
  }
65
65
 
66
- generateTree(data, dataType = 'object', arrayType = '', flags = {}, key = '', description = '', schemaLevel = 0, indentLevel = 0) {
66
+ generateTree(data, dataType = 'object', arrayType = '', flags = {}, key = '', title = '', description = '', schemaLevel = 0, indentLevel = 0) {
67
67
  if (!data) {
68
68
  return html`<div class="null" style="display:inline"> <span class="key-label xxx-of-key"> ${key.replace('::OPTION~', '')}</span> ${dataType === 'array' ? html`<span class="mono-font"> [ ] </span>` : dataType === 'object' ? html`<span class="mono-font"> { } </span>` : html`<span class="mono-font"> schema undefined </span>`} </div>`;
69
69
  }
@@ -150,8 +150,8 @@ export default class SchemaTree extends LitElement {
150
150
  return undefined;
151
151
  }
152
152
 
153
- const displayLine = [flags['🆁'] || flags['🆆'], description].filter(v => v).join(' ');
154
- return html` <div class="tr ${schemaLevel < this.schemaExpandLevel || data['::type'] && data['::type'].startsWith('xxx-of') ? '' : 'collapsed'} ${data['::type'] || 'no-type-info'}"> <div class="td key ${data['::deprecated'] ? 'deprecated' : ''}" style="min-width:${minFieldColWidth}px"> ${data['::type'] === 'xxx-of-option' || data['::type'] === 'xxx-of-array' || key.startsWith('::OPTION') ? html`<span class="key-label xxx-of-key">${keyLabel}</span><span class="xxx-of-descr">${keyDescr}</span>` : keyLabel === '::props' || keyLabel === '::ARRAY~OF' ? '' : schemaLevel > 0 ? html`<span class="key-label"> ${keyLabel.replace(/\*$/, '')}${keyLabel.endsWith('*') ? html`<span style="color:var(--red)">*</span>` : ''}: </span>` : ''} ${openBracket} </div> <div class="td key-descr"> <span class="m-markdown-small" style="vertical-align:middle" title="${flags['🆁'] && 'Read only attribute' || flags['🆆'] && 'Write only attribute' || ''}"> ${unsafeHTML(marked(displayLine))} </span> </div> </div> <div class="inside-bracket-wrapper"> <div class="inside-bracket ${data['::type'] || 'no-type-info'}" style="padding-left:${data['::type'] === 'xxx-of-option' || data['::type'] === 'xxx-of-array' ? 0 : leftPadding}px"> ${Array.isArray(data) && data[0] ? html`${this.generateTree(data[0], 'xxx-of-option', '', data[0]['::flags'] || {}, '::ARRAY~OF', '', newSchemaLevel, newIndentLevel)}` : html` ${Object.keys(data).map(dataKey => !['::title', '::description', '::type', '::props', '::deprecated', '::array-type', '::dataTypeLabel', '::flags'].includes(dataKey) || data[dataKey]['::type'] === 'array' && data[dataKey]['::type'] === 'object' ? html`${this.generateTree(data[dataKey]['::type'] === 'array' ? data[dataKey]['::props'] : data[dataKey], data[dataKey]['::type'], data[dataKey]['::array-type'] || '', data[dataKey]['::flags'], dataKey, data[dataKey]['::description'], newSchemaLevel, newIndentLevel)}` : '')}`} </div> ${data['::type'] && data['::type'].includes('xxx-of') ? '' : html`<div class="close-bracket"> ${closeBracket} </div>`} </div> `;
153
+ const displayLine = [flags['🆁'] || flags['🆆'], title && `**${title}:**`, description].filter(v => v).join(' ');
154
+ return html` <div class="tr ${schemaLevel < this.schemaExpandLevel || data['::type'] && data['::type'].startsWith('xxx-of') ? '' : 'collapsed'} ${data['::type'] || 'no-type-info'}"> <div class="td key ${data['::deprecated'] ? 'deprecated' : ''}" style="min-width:${minFieldColWidth}px"> ${data['::type'] === 'xxx-of-option' || data['::type'] === 'xxx-of-array' || key.startsWith('::OPTION') ? html`<span class="key-label xxx-of-key">${keyLabel}</span><span class="xxx-of-descr">${keyDescr}</span>` : keyLabel === '::props' || keyLabel === '::ARRAY~OF' ? '' : schemaLevel > 0 ? html`<span class="key-label"> ${keyLabel.replace(/\*$/, '')}${keyLabel.endsWith('*') ? html`<span style="color:var(--red)">*</span>` : ''}: </span>` : ''} ${openBracket} </div> <div class="td key-descr"> <span class="m-markdown-small" style="vertical-align:middle" title="${flags['🆁'] && 'Read only attribute' || flags['🆆'] && 'Write only attribute' || ''}"> ${unsafeHTML(marked(displayLine))} </span> </div> </div> <div class="inside-bracket-wrapper"> <div class="inside-bracket ${data['::type'] || 'no-type-info'}" style="padding-left:${data['::type'] === 'xxx-of-option' || data['::type'] === 'xxx-of-array' ? 0 : leftPadding}px"> ${Array.isArray(data) && data[0] ? html`${this.generateTree(data[0], 'xxx-of-option', '', data[0]['::flags'] || {}, '::ARRAY~OF', data[0]['::title'], data[0]['::description'], newSchemaLevel, newIndentLevel)}` : html` ${Object.keys(data).map(dataKey => !['::title', '::description', '::type', '::props', '::deprecated', '::array-type', '::dataTypeLabel', '::flags'].includes(dataKey) || data[dataKey]['::type'] === 'array' && data[dataKey]['::type'] === 'object' ? html`${this.generateTree(data[dataKey]['::type'] === 'array' ? data[dataKey]['::props'] : data[dataKey], data[dataKey]['::type'], data[dataKey]['::array-type'] || '', data[dataKey]['::flags'], dataKey, data[dataKey]['::title'], data[dataKey]['::description'], newSchemaLevel, newIndentLevel)}` : '')}`} </div> ${data['::type'] && data['::type'].includes('xxx-of') ? '' : html`<div class="close-bracket"> ${closeBracket} </div>`} </div> `;
155
155
  } // For Primitive Data types
156
156
 
157
157
 
@@ -178,7 +178,7 @@ export default class SchemaTree extends LitElement {
178
178
  return undefined;
179
179
  }
180
180
 
181
- return html` <div class="tr"> <div class="td key ${deprecated ? 'deprecated' : ''}" style="min-width:${minFieldColWidth}px"> ${keyLabel.endsWith('*') ? html`<span class="key-label">${keyLabel.substring(0, keyLabel.length - 1)}</span><span style="color:var(--red)">*</span>:` : key.startsWith('::OPTION') ? html`<span class="key-label xxx-of-key">${keyLabel}</span><span class="xxx-of-descr">${keyDescr}</span>` : schemaLevel > 0 ? html`<span class="key-label">${keyLabel}:</span>` : ''} <span>${dataType === 'array' ? '[' : ''}<span class="${cssType}">${format || type}</span>${dataType === 'array' ? ']' : ''}</span> </div> <div class="td key-descr"> <span class="m-markdown-small" style="vertical-align:middle" title="${readOrWriteOnly === '🆁' && 'Read only attribute' || readOrWriteOnly === '🆆' && 'Write only attribute' || ''}"> ${unsafeHTML(marked(`${readOrWriteOnly && `${readOrWriteOnly} ` || ''}${dataType === 'array' && description || `${schemaTitle ? `**${schemaTitle}:**` : ''} ${schemaDescription}` || ''}`))} </span> ${this.schemaDescriptionExpanded ? html` ${constraint ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Constraints: </span>${constraint}</div><br>` : ''} ${defaultValue ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Default: </span>${defaultValue}</div><br>` : ''} ${allowedValues ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Allowed: </span>${allowedValues}</div><br>` : ''} ${pattern ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Pattern: </span>${pattern}</div><br>` : ''} ${example ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Example: </span>${example}</div><br>` : ''}` : ''} </div> </div> `;
181
+ return html` <div class="tr"> <div class="td key ${deprecated ? 'deprecated' : ''}" style="min-width:${minFieldColWidth}px"> ${keyLabel.endsWith('*') ? html`<span class="key-label">${keyLabel.substring(0, keyLabel.length - 1)}</span><span style="color:var(--red)">*</span>:` : key.startsWith('::OPTION') ? html`<span class="key-label xxx-of-key">${keyLabel}</span><span class="xxx-of-descr">${keyDescr}</span>` : schemaLevel > 0 ? html`<span class="key-label">${keyLabel}:</span>` : ''} <span>${dataType === 'array' ? '[' : ''}<span class="${cssType}">${format || type}</span>${dataType === 'array' ? ']' : ''}</span> </div> <div class="td key-descr"> <span class="m-markdown-small" style="vertical-align:middle" title="${readOrWriteOnly === '🆁' && 'Read only attribute' || readOrWriteOnly === '🆆' && 'Write only attribute' || ''}"> ${unsafeHTML(marked(`${readOrWriteOnly && `${readOrWriteOnly} ` || ''}${`${schemaTitle || title ? `**${schemaTitle || title}:**` : ''} ${schemaDescription || description}` || ''}`))} </span> ${this.schemaDescriptionExpanded ? html` ${constraint ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Constraints: </span>${constraint}</div><br>` : ''} ${defaultValue ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Default: </span>${defaultValue}</div><br>` : ''} ${allowedValues ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Allowed: </span>${allowedValues}</div><br>` : ''} ${pattern ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Pattern: </span>${pattern}</div><br>` : ''} ${example ? html`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Example: </span>${example}</div><br>` : ''}` : ''} </div> </div> `;
182
182
  }
183
183
  /* eslint-enable indent */
184
184
 
@@ -472,6 +472,8 @@ export function schemaInObjectNotation(rawSchema, options, level = 0, suffix = '
472
472
  '🆁': readOnly && '🆁',
473
473
  '🆆': writeOnly && '🆆'
474
474
  };
475
+ resultObj['::title'] = schema.title || '';
476
+ resultObj['::description'] = schema.description || '';
475
477
  return resultObj;
476
478
  } else if (Array.isArray(schema.type)) {
477
479
  const obj = {
@@ -607,7 +609,7 @@ export function schemaInObjectNotation(rawSchema, options, level = 0, suffix = '
607
609
  '::type': ''
608
610
  };
609
611
  obj['::title'] = schema.title || '';
610
- obj['::description'] = schema.description ? schema.description : (_schema$items2 = schema.items) !== null && _schema$items2 !== void 0 && _schema$items2.description ? `array&lt;${schema.items.description}&gt;` : '';
612
+ obj['::description'] = schema.description || ((_schema$items2 = schema.items) !== null && _schema$items2 !== void 0 && _schema$items2.description ? `array&lt;${schema.items.description}&gt;` : '');
611
613
  obj['::flags'] = {
612
614
  '🆁': schema.readOnly && '🆁',
613
615
  '🆆': schema.writeOnly && '🆆'
@@ -739,13 +739,13 @@ class ApiRequest extends _lit.LitElement {
739
739
 
740
740
  try {
741
741
  respText = new TextDecoder(encoding).decode(buffer);
742
- } catch {
742
+ } catch (_) {
743
743
  respText = new TextDecoder('utf-8').decode(buffer);
744
744
  }
745
745
 
746
746
  try {
747
747
  this.responseText = JSON.stringify(JSON.parse(respText), null, 8);
748
- } catch {
748
+ } catch (_) {
749
749
  this.responseText = respText;
750
750
  }
751
751
  } else {
@@ -72,7 +72,7 @@ class SchemaTable extends _lit.LitElement {
72
72
  return (0, _lit.html)` ${this.data && this.data['::description'] ? (0, _lit.html)`<span class="m-markdown" style="padding-bottom:8px"> ${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(this.data['::description'] || ''))}</span>` : ''} <div class="table"> <div style="border:1px solid var(--light-border-color)"> <div style="display:flex;background-color:var(--bg2);padding:8px 4px;border-bottom:1px solid var(--light-border-color)"> <div class="key" style="font-family:var(--font-regular);font-weight:700;color:var(--fg);padding-left:${firstColumnInitialPadding}px"> Field </div> <div class="key-type" style="font-family:var(--font-regular);font-weight:700;color:var(--fg)"> Type </div> <div class="key-descr" style="font-family:var(--font-regular);font-weight:700;color:var(--fg)"> Description </div> </div> ${this.data ? (0, _lit.html)`${this.generateTree(this.data['::type'] === 'array' ? this.data['::props'] : this.data, this.data['::type'])}` : ''} </div> </div> `;
73
73
  }
74
74
 
75
- generateTree(data, dataType = 'object', key = '', description = '', schemaLevel = 0, indentLevel = 0) {
75
+ generateTree(data, dataType = 'object', key = '', title = '', description = '', schemaLevel = 0, indentLevel = 0) {
76
76
  var _keyLabel;
77
77
 
78
78
  const newSchemaLevel = data['::type'] && data['::type'].startsWith('xxx-of') ? schemaLevel : schemaLevel + 1;
@@ -132,8 +132,8 @@ class SchemaTable extends _lit.LitElement {
132
132
  return undefined;
133
133
  }
134
134
 
135
- const displayLine = [description].filter(v => v).join(' ');
136
- return (0, _lit.html)` ${newSchemaLevel >= 0 && key ? (0, _lit.html)` <div class="tr ${newSchemaLevel <= this.schemaExpandLevel ? '' : 'collapsed'} ${data['::type']}" data-obj="${keyLabel}"> <div class="td no-select key ${data['::deprecated'] ? 'deprecated' : ''}" style="padding-left:${leftPadding}px;cursor:pointer" @click="${e => this.toggleObjectExpand(e, keyLabel)}"> <div style="display:flex;align-items:center"> ${keyLabel || keyDescr ? (0, _lit.html)`<div class="obj-toggle" data-obj="${keyLabel}">▾</div>` : ''} ${data['::type'] === 'xxx-of-option' || data['::type'] === 'xxx-of-array' || key.startsWith('::OPTION') ? (0, _lit.html)`<span class="xxx-of-key" style="margin-left:-6px">${keyLabel}</span><span class="${isOneOfLabel ? 'xxx-of-key' : 'xxx-of-descr'}">${keyDescr}</span>` : keyLabel.endsWith('*') ? (0, _lit.html)`<span class="key-label" style="display:inline-block;margin-left:-6px"> ${keyLabel.substring(0, keyLabel.length - 1)}</span><span style="color:var(--red)">*</span>` : (0, _lit.html)`<span class="key-label" style="display:inline-block;margin-left:-6px">${keyLabel === '::props' ? '' : keyLabel}</span>`} </div> </div> <div class="td key-type"> <div>${(data['::type'] || '').includes('xxx-of') ? '' : detailObjType}</div> <div class="attributes" title="${flags['🆁'] && 'Read only attribute' || flags['🆆'] && 'Write only attribute' || ''}">${flags['🆁'] || flags['🆆'] || ''}</div> </div> <div class="td key-descr m-markdown-small">${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(displayLine))}</div> </div>` : (0, _lit.html)` ${data['::type'] === 'array' && dataType === 'array' ? (0, _lit.html)`<div class="tr"> <div class="td"> ${dataType} </div> </div>` : ''} `} <div class="object-body"> ${Array.isArray(data) && data[0] ? (0, _lit.html)`${this.generateTree(data[0], 'xxx-of-option', '::ARRAY~OF', '', newSchemaLevel, newIndentLevel)}` : (0, _lit.html)` ${Object.keys(data).map(dataKey => !['::title', '::description', '::type', '::props', '::deprecated', '::array-type', '::dataTypeLabel', '::flags'].includes(dataKey) || data[dataKey]['::type'] === 'array' && data[dataKey]['::type'] === 'object' ? (0, _lit.html)`${this.generateTree(data[dataKey]['::type'] === 'array' ? data[dataKey]['::props'] : data[dataKey], data[dataKey]['::type'], dataKey, data[dataKey]['::description'], newSchemaLevel, newIndentLevel)}` : '')}`} <div> </div></div>`;
135
+ const displayLine = [title && `**${title}:**`, description].filter(v => v).join(' ');
136
+ return (0, _lit.html)` ${newSchemaLevel >= 0 && key ? (0, _lit.html)` <div class="tr ${newSchemaLevel <= this.schemaExpandLevel ? '' : 'collapsed'} ${data['::type']}" data-obj="${keyLabel}"> <div class="td no-select key ${data['::deprecated'] ? 'deprecated' : ''}" style="padding-left:${leftPadding}px;cursor:pointer" @click="${e => this.toggleObjectExpand(e, keyLabel)}"> <div style="display:flex;align-items:center"> ${keyLabel || keyDescr ? (0, _lit.html)`<div class="obj-toggle" data-obj="${keyLabel}">▾</div>` : ''} ${data['::type'] === 'xxx-of-option' || data['::type'] === 'xxx-of-array' || key.startsWith('::OPTION') ? (0, _lit.html)`<span class="xxx-of-key" style="margin-left:-6px">${keyLabel}</span><span class="${isOneOfLabel ? 'xxx-of-key' : 'xxx-of-descr'}">${keyDescr}</span>` : keyLabel.endsWith('*') ? (0, _lit.html)`<span class="key-label" style="display:inline-block;margin-left:-6px"> ${keyLabel.substring(0, keyLabel.length - 1)}</span><span style="color:var(--red)">*</span>` : (0, _lit.html)`<span class="key-label" style="display:inline-block;margin-left:-6px">${keyLabel === '::props' ? '' : keyLabel}</span>`} </div> </div> <div class="td key-type"> <div>${(data['::type'] || '').includes('xxx-of') ? '' : detailObjType}</div> <div class="attributes" title="${flags['🆁'] && 'Read only attribute' || flags['🆆'] && 'Write only attribute' || ''}">${flags['🆁'] || flags['🆆'] || ''}</div> </div> <div class="td key-descr m-markdown-small">${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(displayLine))}</div> </div>` : (0, _lit.html)` ${data['::type'] === 'array' && dataType === 'array' ? (0, _lit.html)`<div class="tr"> <div class="td"> ${dataType} </div> </div>` : ''} `} <div class="object-body"> ${Array.isArray(data) && data[0] ? (0, _lit.html)`${this.generateTree(data[0], 'xxx-of-option', '::ARRAY~OF', data[0]['::title'], data[0]['::description'], newSchemaLevel, newIndentLevel)}` : (0, _lit.html)` ${Object.keys(data).map(dataKey => !['::title', '::description', '::type', '::props', '::deprecated', '::array-type', '::dataTypeLabel', '::flags'].includes(dataKey) || data[dataKey]['::type'] === 'array' && data[dataKey]['::type'] === 'object' ? (0, _lit.html)`${this.generateTree(data[dataKey]['::type'] === 'array' ? data[dataKey]['::props'] : data[dataKey], data[dataKey]['::type'], dataKey, data[dataKey]['::title'], data[dataKey]['::description'], newSchemaLevel, newIndentLevel)}` : '')}`} <div> </div></div>`;
137
137
  } // For Primitive Data types
138
138
 
139
139
 
@@ -160,7 +160,7 @@ class SchemaTable extends _lit.LitElement {
160
160
  return undefined;
161
161
  }
162
162
 
163
- return (0, _lit.html)` <div class="tr"> <div class="td key ${deprecated ? 'deprecated' : ''}" style="padding-left:${leftPadding}px"> ${(_keyLabel = keyLabel) !== null && _keyLabel !== void 0 && _keyLabel.endsWith('*') ? (0, _lit.html)`<span class="key-label">${keyLabel.substring(0, keyLabel.length - 1)}</span><span style="color:var(--red)">*</span>` : key.startsWith('::OPTION') ? (0, _lit.html)`<span class="xxx-of-key">${keyLabel}</span><span class="xxx-of-descr">${keyDescr}</span>` : (0, _lit.html)`${keyLabel ? (0, _lit.html)`<span class="key-label"> ${keyLabel}</span>` : (0, _lit.html)`<span class="xxx-of-descr">${schemaTitle}</span>`}`} </div> <div class="td key-type"> <div>${dataType === 'array' ? '[' : ''}<span class="${cssType}">${format || type}</span>${dataType === 'array' ? ']' : ''}</div> <div class="attributes ${cssType}" style="font-family:var(--font-mono)" title="${readOrWriteOnly === '🆁' && 'Read only attribute' || readOrWriteOnly === '🆆' && 'Write only attribute' || ''}">${readOrWriteOnly}</div> </div> <div class="td key-descr"> ${dataType === 'array' ? (0, _lit.html)`<span class="m-markdown-small">${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(description))}</span>` : ''} <span class="m-markdown-small" style="vertical-align:middle"> ${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(`${dataType === 'array' && description || `${schemaTitle ? `**${schemaTitle}:**` : ''} ${schemaDescription}` || ''}`))} </span> ${this.schemaDescriptionExpanded ? (0, _lit.html)` ${constraint ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Constraints: </span>${constraint}</div><br>` : ''} ${defaultValue ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Default: </span>${defaultValue}</div><br>` : ''} ${allowedValues ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Allowed: </span>${allowedValues}</div><br>` : ''} ${pattern ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Pattern: </span>${pattern}</div><br>` : ''} ${example ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Example: </span>${example}</div><br>` : ''}` : ''} </div> </div> `;
163
+ return (0, _lit.html)` <div class="tr"> <div class="td key ${deprecated ? 'deprecated' : ''}" style="padding-left:${leftPadding}px"> ${(_keyLabel = keyLabel) !== null && _keyLabel !== void 0 && _keyLabel.endsWith('*') ? (0, _lit.html)`<span class="key-label">${keyLabel.substring(0, keyLabel.length - 1)}</span><span style="color:var(--red)">*</span>` : key.startsWith('::OPTION') ? (0, _lit.html)`<span class="xxx-of-key">${keyLabel}</span><span class="xxx-of-descr">${keyDescr}</span>` : (0, _lit.html)`${keyLabel ? (0, _lit.html)`<span class="key-label"> ${keyLabel}</span>` : (0, _lit.html)`<span class="xxx-of-descr">${schemaTitle}</span>`}`} </div> <div class="td key-type"> <div>${dataType === 'array' ? '[' : ''}<span class="${cssType}">${format || type}</span>${dataType === 'array' ? ']' : ''}</div> <div class="attributes ${cssType}" style="font-family:var(--font-mono)" title="${readOrWriteOnly === '🆁' && 'Read only attribute' || readOrWriteOnly === '🆆' && 'Write only attribute' || ''}">${readOrWriteOnly}</div> </div> <div class="td key-descr"> <span class="m-markdown-small" style="vertical-align:middle"> ${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(`${`${schemaTitle || title ? `**${schemaTitle || title}:**` : ''} ${schemaDescription || description}` || ''}`))} </span> ${this.schemaDescriptionExpanded ? (0, _lit.html)` ${constraint ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Constraints: </span>${constraint}</div><br>` : ''} ${defaultValue ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Default: </span>${defaultValue}</div><br>` : ''} ${allowedValues ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Allowed: </span>${allowedValues}</div><br>` : ''} ${pattern ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Pattern: </span>${pattern}</div><br>` : ''} ${example ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Example: </span>${example}</div><br>` : ''}` : ''} </div> </div> `;
164
164
  }
165
165
  /* eslint-enable indent */
166
166
 
@@ -78,7 +78,7 @@ class SchemaTree extends _lit.LitElement {
78
78
  this.requestUpdate();
79
79
  }
80
80
 
81
- generateTree(data, dataType = 'object', arrayType = '', flags = {}, key = '', description = '', schemaLevel = 0, indentLevel = 0) {
81
+ generateTree(data, dataType = 'object', arrayType = '', flags = {}, key = '', title = '', description = '', schemaLevel = 0, indentLevel = 0) {
82
82
  if (!data) {
83
83
  return (0, _lit.html)`<div class="null" style="display:inline"> <span class="key-label xxx-of-key"> ${key.replace('::OPTION~', '')}</span> ${dataType === 'array' ? (0, _lit.html)`<span class="mono-font"> [ ] </span>` : dataType === 'object' ? (0, _lit.html)`<span class="mono-font"> { } </span>` : (0, _lit.html)`<span class="mono-font"> schema undefined </span>`} </div>`;
84
84
  }
@@ -165,8 +165,8 @@ class SchemaTree extends _lit.LitElement {
165
165
  return undefined;
166
166
  }
167
167
 
168
- const displayLine = [flags['🆁'] || flags['🆆'], description].filter(v => v).join(' ');
169
- return (0, _lit.html)` <div class="tr ${schemaLevel < this.schemaExpandLevel || data['::type'] && data['::type'].startsWith('xxx-of') ? '' : 'collapsed'} ${data['::type'] || 'no-type-info'}"> <div class="td key ${data['::deprecated'] ? 'deprecated' : ''}" style="min-width:${minFieldColWidth}px"> ${data['::type'] === 'xxx-of-option' || data['::type'] === 'xxx-of-array' || key.startsWith('::OPTION') ? (0, _lit.html)`<span class="key-label xxx-of-key">${keyLabel}</span><span class="xxx-of-descr">${keyDescr}</span>` : keyLabel === '::props' || keyLabel === '::ARRAY~OF' ? '' : schemaLevel > 0 ? (0, _lit.html)`<span class="key-label"> ${keyLabel.replace(/\*$/, '')}${keyLabel.endsWith('*') ? (0, _lit.html)`<span style="color:var(--red)">*</span>` : ''}: </span>` : ''} ${openBracket} </div> <div class="td key-descr"> <span class="m-markdown-small" style="vertical-align:middle" title="${flags['🆁'] && 'Read only attribute' || flags['🆆'] && 'Write only attribute' || ''}"> ${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(displayLine))} </span> </div> </div> <div class="inside-bracket-wrapper"> <div class="inside-bracket ${data['::type'] || 'no-type-info'}" style="padding-left:${data['::type'] === 'xxx-of-option' || data['::type'] === 'xxx-of-array' ? 0 : leftPadding}px"> ${Array.isArray(data) && data[0] ? (0, _lit.html)`${this.generateTree(data[0], 'xxx-of-option', '', data[0]['::flags'] || {}, '::ARRAY~OF', '', newSchemaLevel, newIndentLevel)}` : (0, _lit.html)` ${Object.keys(data).map(dataKey => !['::title', '::description', '::type', '::props', '::deprecated', '::array-type', '::dataTypeLabel', '::flags'].includes(dataKey) || data[dataKey]['::type'] === 'array' && data[dataKey]['::type'] === 'object' ? (0, _lit.html)`${this.generateTree(data[dataKey]['::type'] === 'array' ? data[dataKey]['::props'] : data[dataKey], data[dataKey]['::type'], data[dataKey]['::array-type'] || '', data[dataKey]['::flags'], dataKey, data[dataKey]['::description'], newSchemaLevel, newIndentLevel)}` : '')}`} </div> ${data['::type'] && data['::type'].includes('xxx-of') ? '' : (0, _lit.html)`<div class="close-bracket"> ${closeBracket} </div>`} </div> `;
168
+ const displayLine = [flags['🆁'] || flags['🆆'], title && `**${title}:**`, description].filter(v => v).join(' ');
169
+ return (0, _lit.html)` <div class="tr ${schemaLevel < this.schemaExpandLevel || data['::type'] && data['::type'].startsWith('xxx-of') ? '' : 'collapsed'} ${data['::type'] || 'no-type-info'}"> <div class="td key ${data['::deprecated'] ? 'deprecated' : ''}" style="min-width:${minFieldColWidth}px"> ${data['::type'] === 'xxx-of-option' || data['::type'] === 'xxx-of-array' || key.startsWith('::OPTION') ? (0, _lit.html)`<span class="key-label xxx-of-key">${keyLabel}</span><span class="xxx-of-descr">${keyDescr}</span>` : keyLabel === '::props' || keyLabel === '::ARRAY~OF' ? '' : schemaLevel > 0 ? (0, _lit.html)`<span class="key-label"> ${keyLabel.replace(/\*$/, '')}${keyLabel.endsWith('*') ? (0, _lit.html)`<span style="color:var(--red)">*</span>` : ''}: </span>` : ''} ${openBracket} </div> <div class="td key-descr"> <span class="m-markdown-small" style="vertical-align:middle" title="${flags['🆁'] && 'Read only attribute' || flags['🆆'] && 'Write only attribute' || ''}"> ${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(displayLine))} </span> </div> </div> <div class="inside-bracket-wrapper"> <div class="inside-bracket ${data['::type'] || 'no-type-info'}" style="padding-left:${data['::type'] === 'xxx-of-option' || data['::type'] === 'xxx-of-array' ? 0 : leftPadding}px"> ${Array.isArray(data) && data[0] ? (0, _lit.html)`${this.generateTree(data[0], 'xxx-of-option', '', data[0]['::flags'] || {}, '::ARRAY~OF', data[0]['::title'], data[0]['::description'], newSchemaLevel, newIndentLevel)}` : (0, _lit.html)` ${Object.keys(data).map(dataKey => !['::title', '::description', '::type', '::props', '::deprecated', '::array-type', '::dataTypeLabel', '::flags'].includes(dataKey) || data[dataKey]['::type'] === 'array' && data[dataKey]['::type'] === 'object' ? (0, _lit.html)`${this.generateTree(data[dataKey]['::type'] === 'array' ? data[dataKey]['::props'] : data[dataKey], data[dataKey]['::type'], data[dataKey]['::array-type'] || '', data[dataKey]['::flags'], dataKey, data[dataKey]['::title'], data[dataKey]['::description'], newSchemaLevel, newIndentLevel)}` : '')}`} </div> ${data['::type'] && data['::type'].includes('xxx-of') ? '' : (0, _lit.html)`<div class="close-bracket"> ${closeBracket} </div>`} </div> `;
170
170
  } // For Primitive Data types
171
171
 
172
172
 
@@ -193,7 +193,7 @@ class SchemaTree extends _lit.LitElement {
193
193
  return undefined;
194
194
  }
195
195
 
196
- return (0, _lit.html)` <div class="tr"> <div class="td key ${deprecated ? 'deprecated' : ''}" style="min-width:${minFieldColWidth}px"> ${keyLabel.endsWith('*') ? (0, _lit.html)`<span class="key-label">${keyLabel.substring(0, keyLabel.length - 1)}</span><span style="color:var(--red)">*</span>:` : key.startsWith('::OPTION') ? (0, _lit.html)`<span class="key-label xxx-of-key">${keyLabel}</span><span class="xxx-of-descr">${keyDescr}</span>` : schemaLevel > 0 ? (0, _lit.html)`<span class="key-label">${keyLabel}:</span>` : ''} <span>${dataType === 'array' ? '[' : ''}<span class="${cssType}">${format || type}</span>${dataType === 'array' ? ']' : ''}</span> </div> <div class="td key-descr"> <span class="m-markdown-small" style="vertical-align:middle" title="${readOrWriteOnly === '🆁' && 'Read only attribute' || readOrWriteOnly === '🆆' && 'Write only attribute' || ''}"> ${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(`${readOrWriteOnly && `${readOrWriteOnly} ` || ''}${dataType === 'array' && description || `${schemaTitle ? `**${schemaTitle}:**` : ''} ${schemaDescription}` || ''}`))} </span> ${this.schemaDescriptionExpanded ? (0, _lit.html)` ${constraint ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Constraints: </span>${constraint}</div><br>` : ''} ${defaultValue ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Default: </span>${defaultValue}</div><br>` : ''} ${allowedValues ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Allowed: </span>${allowedValues}</div><br>` : ''} ${pattern ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Pattern: </span>${pattern}</div><br>` : ''} ${example ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Example: </span>${example}</div><br>` : ''}` : ''} </div> </div> `;
196
+ return (0, _lit.html)` <div class="tr"> <div class="td key ${deprecated ? 'deprecated' : ''}" style="min-width:${minFieldColWidth}px"> ${keyLabel.endsWith('*') ? (0, _lit.html)`<span class="key-label">${keyLabel.substring(0, keyLabel.length - 1)}</span><span style="color:var(--red)">*</span>:` : key.startsWith('::OPTION') ? (0, _lit.html)`<span class="key-label xxx-of-key">${keyLabel}</span><span class="xxx-of-descr">${keyDescr}</span>` : schemaLevel > 0 ? (0, _lit.html)`<span class="key-label">${keyLabel}:</span>` : ''} <span>${dataType === 'array' ? '[' : ''}<span class="${cssType}">${format || type}</span>${dataType === 'array' ? ']' : ''}</span> </div> <div class="td key-descr"> <span class="m-markdown-small" style="vertical-align:middle" title="${readOrWriteOnly === '🆁' && 'Read only attribute' || readOrWriteOnly === '🆆' && 'Write only attribute' || ''}"> ${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(`${readOrWriteOnly && `${readOrWriteOnly} ` || ''}${`${schemaTitle || title ? `**${schemaTitle || title}:**` : ''} ${schemaDescription || description}` || ''}`))} </span> ${this.schemaDescriptionExpanded ? (0, _lit.html)` ${constraint ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Constraints: </span>${constraint}</div><br>` : ''} ${defaultValue ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Default: </span>${defaultValue}</div><br>` : ''} ${allowedValues ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Allowed: </span>${allowedValues}</div><br>` : ''} ${pattern ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Pattern: </span>${pattern}</div><br>` : ''} ${example ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Example: </span>${example}</div><br>` : ''}` : ''} </div> </div> `;
197
197
  }
198
198
  /* eslint-enable indent */
199
199
 
@@ -489,6 +489,8 @@ function schemaInObjectNotation(rawSchema, options, level = 0, suffix = '') {
489
489
  '🆁': readOnly && '🆁',
490
490
  '🆆': writeOnly && '🆆'
491
491
  };
492
+ resultObj['::title'] = schema.title || '';
493
+ resultObj['::description'] = schema.description || '';
492
494
  return resultObj;
493
495
  } else if (Array.isArray(schema.type)) {
494
496
  const obj = {
@@ -624,7 +626,7 @@ function schemaInObjectNotation(rawSchema, options, level = 0, suffix = '') {
624
626
  '::type': ''
625
627
  };
626
628
  obj['::title'] = schema.title || '';
627
- obj['::description'] = schema.description ? schema.description : (_schema$items2 = schema.items) !== null && _schema$items2 !== void 0 && _schema$items2.description ? `array&lt;${schema.items.description}&gt;` : '';
629
+ obj['::description'] = schema.description || ((_schema$items2 = schema.items) !== null && _schema$items2 !== void 0 && _schema$items2.description ? `array&lt;${schema.items.description}&gt;` : '');
628
630
  obj['::flags'] = {
629
631
  '🆁': schema.readOnly && '🆁',
630
632
  '🆆': schema.writeOnly && '🆆'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openapi-explorer",
3
- "version": "1.0.543",
3
+ "version": "1.0.546",
4
4
  "description": "OpenAPI Explorer - API viewer with dynamically generated components, documentation, and interaction console",
5
5
  "author": "Rhosys Developers <developers@rhosys.ch>",
6
6
  "type": "module",