UNPKG

openapi-explorer

Version:

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

202 lines (197 loc) 15.5 kB
"use strict"; exports.__esModule = true; exports.default = void 0; var _lit = require("lit"); var _commonUtils = require("../utils/common-utils.js"); var _unsafeHtml = require("lit/directives/unsafe-html.js"); var _index = require("../languages/index.js"); var _fontStyles = _interopRequireDefault(require("../styles/font-styles.js")); var _schemaStyles = _interopRequireDefault(require("../styles/schema-styles.js")); var _borderStyles = _interopRequireDefault(require("../styles/border-styles.js")); var _keyFrameStyles = _interopRequireDefault(require("../styles/key-frame-styles.js")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } class SchemaTree extends _lit.LitElement { static get properties() { return { data: { type: Object }, schemaExpandLevel: { type: Number, attribute: 'schema-expand-level' }, schemaDescriptionExpanded: { type: Boolean }, schemaHideReadOnly: { type: String, attribute: 'schema-hide-read-only' }, schemaHideWriteOnly: { type: String, attribute: 'schema-hide-write-only' } }; } connectedCallback() { super.connectedCallback(); if (!this.schemaExpandLevel || this.schemaExpandLevel < 1) { this.schemaExpandLevel = 99999; } this.schemaDescriptionExpanded = true; if (!this.schemaHideReadOnly || !'true false'.includes(this.schemaHideReadOnly)) { this.schemaHideReadOnly = 'true'; } if (!this.schemaHideWriteOnly || !'true false'.includes(this.schemaHideWriteOnly)) { this.schemaHideWriteOnly = 'true'; } } /** * @param {Map<string, object>} changedProperties Changed Properties */ update(changedProperties) { if (changedProperties.has('data')) { this.interactive = false; } super.update(changedProperties); } updated() { this.interactive = true; // Note: interactive is not a reactive property } static finalizeStyles() { return [_fontStyles.default, _schemaStyles.default, _borderStyles.default, _keyFrameStyles.default, (0, _lit.css)`.tree{min-height:30px;background:var(--bg2);padding:12px;font-size:var(--font-size-small);text-align:left;line-height:calc(var(--font-size-small) + 6px)}.tree .key{max-width:300px}.requiredStar::after{content:'*';color:var(--red);font-size:larger}.key.deprecated .key-label{text-decoration:line-through}.open-bracket{display:inline-block;padding:0 20px 0 0;cursor:pointer;border:1px solid transparent;border-radius:3px}.collapsed .open-bracket{padding-right:0}.td.key>.open-bracket:first-child{margin-left:-2px}.open-bracket:hover{color:var(--primary-color);background-color:var(--hover-color);border:1px solid var(--border-color)}.close-bracket{display:inline-block;font-family:var(--font-mono)}.inside-bracket-wrapper{overflow:hidden}.tree:not(.interactive) .inside-bracket-wrapper{animation-duration:0s!important}.tr:not(.collapsed)+.inside-bracket-wrapper{animation:linear .2s expand-height}.tr.collapsed+.inside-bracket-wrapper{animation:linear .2s collapse-height;max-height:0}.inside-bracket.array,.inside-bracket.object{border-left:1px dotted var(--border-color)}.inside-bracket.xxx-of.option{border-left:1px solid transparent}`]; } /* eslint-disable indent */ render() { var _this$data, _this$data2, _this$data3, _this$data3$Props, _this$data4, _this$data4$Props, _this$data5; const title = ((_this$data = this.data) === null || _this$data === void 0 ? void 0 : _this$data['::title']) || ((_this$data2 = this.data) === null || _this$data2 === void 0 ? void 0 : _this$data2['::type']) === 'array' && ((_this$data3 = this.data) === null || _this$data3 === void 0 ? void 0 : (_this$data3$Props = _this$data3['::props']) === null || _this$data3$Props === void 0 ? void 0 : _this$data3$Props['::title']) && `[${(_this$data4 = this.data) === null || _this$data4 === void 0 ? void 0 : (_this$data4$Props = _this$data4['::props']) === null || _this$data4$Props === void 0 ? void 0 : _this$data4$Props['::title']}]`; const displayLine = [title, (_this$data5 = this.data) === null || _this$data5 === void 0 ? void 0 : _this$data5['::description']].filter(d => d).join(' - '); return (0, _lit.html)` <div class="tree ${this.interactive ? 'interactive' : ''}"> <div class="toolbar"> ${displayLine ? (0, _lit.html)`<span class="m-markdown" style="margin-block-start:0"> ${(0, _unsafeHtml.unsafeHTML)((0, _commonUtils.toMarkdown)(displayLine))}</span>` : (0, _lit.html)`<div>&nbsp;</div>`} <div class="toolbar-item" @click="${() => this.toggleSchemaDescription()}"> ${this.schemaDescriptionExpanded ? (0, _index.getI18nText)('schemas.collapse-desc') : (0, _index.getI18nText)('schemas.expand-desc')} </div> </div> ${this.data ? (0, _lit.html)`${this.generateTree(this.data['::type'] === 'array' ? this.data['::props'] : this.data, this.data['::type'], this.data['::array-type'] || '')}` : (0, _lit.html)`<span class="mono-font" style="color:var(--red)"> ${(0, _index.getI18nText)('schemas.schema-missing')} </span>`} </div> `; } toggleSchemaDescription() { this.schemaDescriptionExpanded = !this.schemaDescriptionExpanded; this.requestUpdate(); } generateTree(data, dataType = 'object', arrayType = '', flags = {}, key = '', title = '', description = '', schemaLevel = 0, indentLevel = 0) { if (!data) { 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"> ${dataType} </span>`} </div>`; } if (Object.keys(data).length === 0) { return (0, _lit.html)`<span class="key object">${key}:{ }</span>`; } let keyLabel = ''; let keyDescr = ''; if (key.startsWith('::ONE~OF') || key.startsWith('::ANY~OF')) { keyLabel = key.replace('::', '').replace('~', ' '); } else if (key.startsWith('::OPTION')) { const parts = key.split('~'); keyLabel = parts[1]; keyDescr = parts[2]; } else { keyLabel = key; } const leftPadding = 16; // Min-width used for model keys: `td key ` const minFieldColWidth = 300 - indentLevel * leftPadding; let openBracket = ''; let closeBracket = ''; const newSchemaLevel = data['::type'] === 'xxx-of-option' ? schemaLevel : schemaLevel + 1; const newIndentLevel = indentLevel + 1; if (data['::type'] === 'array') { if (dataType === 'array') { const arrType = arrayType !== 'object' ? arrayType : ''; if (schemaLevel < this.schemaExpandLevel) { openBracket = (0, _lit.html)`<span class="open-bracket array-of-array" data-array-type="${arrType}" @click="${this.toggleObjectExpand}">[[ ${arrType} </span>`; } else { openBracket = (0, _lit.html)`<span class="open-bracket array-of-array" data-array-type="${arrType}" @click="${this.toggleObjectExpand}">[[...]]</span>`; } closeBracket = ']]'; } else { if (schemaLevel < this.schemaExpandLevel) { openBracket = (0, _lit.html)`<span class="open-bracket array" @click="${this.toggleObjectExpand}">[</span>`; } else { openBracket = (0, _lit.html)`<span class="open-bracket array" @click="${this.toggleObjectExpand}">[...]</span>`; } closeBracket = ']'; } } else if (data['::type'] === 'xxx-of-option') { if (dataType === 'array') { if (schemaLevel < this.schemaExpandLevel) { openBracket = (0, _lit.html)`<span class="open-bracket array" @click="${this.toggleObjectExpand}">[</span>`; } else { openBracket = (0, _lit.html)`<span class="open-bracket array" @click="${this.toggleObjectExpand}">[...]</span>`; } closeBracket = ']'; } } else if (data['::type']) { if (dataType === 'array') { if (schemaLevel < this.schemaExpandLevel) { openBracket = (0, _lit.html)`<span class="open-bracket array-of-object" @click="${this.toggleObjectExpand}">[{</span>`; } else { openBracket = (0, _lit.html)`<span class="open-bracket array-of-object" @click="${this.toggleObjectExpand}">[{...}]</span>`; } closeBracket = '}]'; } else { if (schemaLevel < this.schemaExpandLevel) { openBracket = (0, _lit.html)`<span class="open-bracket object" @click="${this.toggleObjectExpand}">{</span>`; } else { openBracket = (0, _lit.html)`<span class="open-bracket object" @click="${this.toggleObjectExpand}">{...}</span>`; } closeBracket = '}'; } } if (typeof data === 'object') { var _data$Metadata, _data$Metadata$constr; if (flags['🆁'] && this.schemaHideReadOnly === 'true') { return undefined; } if (flags['🆆'] && this.schemaHideWriteOnly === 'true') { return undefined; } const displayLine = [flags['🆁'] || flags['🆆'], title && `**${title}${description ? ':' : ''}**`, description].filter(v => v).join(' '); 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' || 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 class="requiredStar" title="Required"></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, _commonUtils.toMarkdown)(displayLine))} </span> ${this.schemaDescriptionExpanded ? (0, _lit.html)` ${(_data$Metadata = data['::metadata']) !== null && _data$Metadata !== void 0 && (_data$Metadata$constr = _data$Metadata.constraints) !== null && _data$Metadata$constr !== void 0 && _data$Metadata$constr.length ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Constraints: </span>${data['::metadata'].constraints.join(', ')}</div><br>` : ''}` : ''} </div> </div> <div class="inside-bracket-wrapper"> <div class="inside-bracket ${data['::type'] || 'no-type-info'}" style="padding-left:${data['::type'] === 'xxx-of-option' ? 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 => { var _data$dataKey; return !['::metadata', '::title', '::description', '::type', '::link', '::props', '::deprecated', '::array-type', '::dataTypeLabel', '::flags'].includes(dataKey) || (_data$dataKey = data[dataKey]) !== null && _data$dataKey !== void 0 && _data$dataKey['::type'] && !data[dataKey]['::type'].includes('xxx-of') ? (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> `; } // For Primitive Data types const { type, cssType, format, readOrWriteOnly, constraints, defaultValue, example, allowedValues, pattern, schemaDescription, schemaTitle, deprecated } = JSON.parse(data); if (readOrWriteOnly === '🆁' && this.schemaHideReadOnly === 'true') { return undefined; } if (readOrWriteOnly === '🆆' && this.schemaHideWriteOnly === 'true') { return undefined; } const titleString = schemaTitle || title; const descriptionString = schemaDescription || description; 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 requiredStar" title="Required">${keyLabel.substring(0, keyLabel.length - 1)}</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, _commonUtils.toMarkdown)(`${readOrWriteOnly && `${readOrWriteOnly} ` || ''}${`${titleString ? `**${titleString}${descriptionString ? ':' : ''}**` : ''} ${descriptionString}` || ''}`))} </span> ${this.schemaDescriptionExpanded ? (0, _lit.html)` ${constraints.length ? (0, _lit.html)`<div style="display:inline-block;line-break:anywhere;margin-right:8px"><span class="bold-text">Constraints: </span>${constraints.join(', ')}</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.filter(v => v !== null && v !== undefined).join(' ┃ ')}</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> `; } /* eslint-enable indent */ toggleObjectExpand(e) { const rowEl = e.target.closest('.tr'); rowEl.classList.toggle('collapsed'); if (rowEl.classList.contains('collapsed')) { e.target.innerHTML = e.target.classList.contains('array-of-object') ? '[{...}]' : e.target.classList.contains('array-of-array') ? '[[...]]' : e.target.classList.contains('array') ? '[...]' : '{...}'; } else { e.target.innerHTML = e.target.classList.contains('array-of-object') ? '[{' : e.target.classList.contains('array-of-array') ? '[[' : e.target.classList.contains('object') ? '{' : '['; } this.requestUpdate(); } } exports.default = SchemaTree; if (!customElements.get('openapi-explorer')) { customElements.define('schema-tree', SchemaTree); }