openapi-explorer 1.0.570 → 1.0.577

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.
@@ -2,6 +2,9 @@
2
2
  import { html } from 'lit';
3
3
  import { marked } from 'marked';
4
4
  import { unsafeHTML } from 'lit/directives/unsafe-html.js';
5
+ import { isPatternProperty } from '../utils/schema-utils';
6
+ import { map } from 'lit/directives/map.js';
7
+ import { range } from 'lit/directives/range.js';
5
8
 
6
9
  function generateFormRows(data, options, dataType = 'object', key = '', description = '', schemaLevel = 0) {
7
10
  const newSchemaLevel = data['::type'] && data['::type'].startsWith('xxx-of') ? schemaLevel : schemaLevel + 1;
@@ -45,6 +48,20 @@ function generateFormRows(data, options, dataType = 'object', key = '', descript
45
48
 
46
49
 
47
50
  const parsedData = JSON.parse(data);
51
+ return generatePrimitiveRow.call(this, parsedData, {
52
+ key,
53
+ keyLabel,
54
+ keyDescr,
55
+ description,
56
+ dataType,
57
+ isRequired,
58
+ options
59
+ });
60
+ }
61
+
62
+ function generatePrimitiveRow(rowData, parentRecursionOptions) {
63
+ var _this$duplicatedRowsB;
64
+
48
65
  const {
49
66
  type,
50
67
  format,
@@ -57,13 +74,46 @@ function generateFormRows(data, options, dataType = 'object', key = '', descript
57
74
  schemaDescription,
58
75
  schemaTitle,
59
76
  deprecated
60
- } = parsedData;
77
+ } = rowData;
78
+ const {
79
+ key,
80
+ keyLabel,
81
+ keyDescr,
82
+ description,
83
+ dataType,
84
+ isRequired,
85
+ options
86
+ } = parentRecursionOptions;
61
87
 
62
88
  if (readOrWriteOnly === '🆁') {
63
89
  return undefined;
64
90
  }
65
91
 
66
- return html` <tr> <td style="width:160px;min-width:100px"> <div class="param-name ${deprecated ? 'deprecated' : ''}"> ${!deprecated && isRequired ? html`<span class="key-label">${keyLabel}</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="param-type"> ${dataType === 'array' ? html`[<span>${format || type}</span>]` : `${format || type}`} </div> </td> ${dataType === 'array' ? getArrayFormField.call(this, keyLabel, example, defaultValue, format, options) : ''} ${dataType !== 'array' ? getPrimitiveFormField.call(this, keyLabel, example, defaultValue, format, options) : ''} <td> ${description ? html`<div class="param-description">${unsafeHTML(marked(description))}</div>` : ''} ${defaultValue || constraints || allowedValues || pattern ? html` <div class="param-constraint"> ${pattern ? html`<span style="font-weight:700">Pattern: </span>${pattern}<br>` : ''} ${constraints.length ? html`<span style="font-weight:700">Constraints: </span>${constraints.join(', ')}<br>` : ''} ${allowedValues === null || allowedValues === void 0 ? void 0 : allowedValues.split('┃').map((v, i) => html` ${i > 0 ? '|' : html`<span style="font-weight:700">Allowed: </span>`} ${html` <a part="anchor anchor-param-constraint" data-type="${type === 'array' ? type : 'string'}" data-enum="${v.trim()}" @click="${e => {
92
+ const elementId = this.elementId || `${this.method}-${this.path}`;
93
+ const duplicateRowGeneratorKey = `${elementId}-${key}`;
94
+
95
+ const rowGenerator = e => {
96
+ var _e$target$dataset, _e$target$dataset2;
97
+
98
+ if (((_e$target$dataset = e.target.dataset) === null || _e$target$dataset === void 0 ? void 0 : _e$target$dataset.ptype) !== 'pattern-property-key' && !isPatternProperty((_e$target$dataset2 = e.target.dataset) === null || _e$target$dataset2 === void 0 ? void 0 : _e$target$dataset2.pname)) {
99
+ return;
100
+ } // If the row key has a value then add another row
101
+
102
+
103
+ const patternPropertyKeyEls = [...this.querySelectorAll("[data-ptype='pattern-property-key']")];
104
+ const patternPropertyInputEls = [...this.querySelectorAll("[data-ptype='form-input']")].filter(el => isPatternProperty(el.dataset.pname)); // If there is still some row that either has an empty key or an empty value, then skip adding a new row
105
+
106
+ if (patternPropertyKeyEls.some((keyElement, index) => !keyElement.value || !patternPropertyInputEls[index].value)) {
107
+ return;
108
+ }
109
+
110
+ if (e.target.value) {
111
+ this.duplicatedRowsByKey[duplicateRowGeneratorKey] = (this.duplicatedRowsByKey[duplicateRowGeneratorKey] || 1) + 1;
112
+ this.requestUpdate();
113
+ }
114
+ };
115
+
116
+ return map(range(((_this$duplicatedRowsB = this.duplicatedRowsByKey) === null || _this$duplicatedRowsB === void 0 ? void 0 : _this$duplicatedRowsB[duplicateRowGeneratorKey]) || 1), () => html` <tr> ${inputFieldKeyLabel.call(this, key.startsWith('::OPTION'), keyLabel, keyDescr, dataType, deprecated, isRequired, schemaTitle, format || type, rowGenerator)} ${dataType === 'array' ? getArrayFormField.call(this, keyLabel, example, defaultValue, format, rowGenerator) : ''} ${dataType !== 'array' ? getPrimitiveFormField.call(this, keyLabel, example, defaultValue, format, options, rowGenerator) : ''} <td> ${description ? html`<div class="param-description">${unsafeHTML(marked(description))}</div>` : ''} ${defaultValue || constraints || allowedValues || pattern ? html` <div class="param-constraint"> ${pattern ? html`<span style="font-weight:700">Pattern: </span>${pattern}<br>` : ''} ${constraints.length ? html`<span style="font-weight:700">Constraints: </span>${constraints.join(', ')}<br>` : ''} ${allowedValues === null || allowedValues === void 0 ? void 0 : allowedValues.split('┃').filter(v => v !== '').map((v, i) => html` ${i > 0 ? '|' : html`<span style="font-weight:700">Allowed: </span>`} ${html` <a part="anchor anchor-param-constraint" data-type="${type === 'array' ? type : 'string'}" data-enum="${v.trim()}" @click="${e => {
67
117
  const inputEl = e.target.closest('table').querySelector(`[data-pname="${keyLabel}"]`);
68
118
 
69
119
  if (inputEl) {
@@ -75,7 +125,17 @@ function generateFormRows(data, options, dataType = 'object', key = '', descript
75
125
  if (inputEl) {
76
126
  inputEl.value = e.target.dataset.exampleType === 'array' ? e.target.dataset.example.split('~|~') : e.target.dataset.example;
77
127
  }
78
- }}"> ${type === 'array' ? example.join(', ') : example} </a> ${type === 'array' ? '] ' : ''} </span>` : ''} </td> </tr>` : ''}`;
128
+ }}"> ${type === 'array' ? example.join(', ') : example} </a> ${type === 'array' ? '] ' : ''} </span>` : ''} </td> </tr>` : ''}`);
129
+ }
130
+
131
+ function inputFieldKeyLabel(isOption, keyLabel, keyDescription, dataType, deprecated, isRequired, schemaTitle, format, rowGenerator) {
132
+ if (isPatternProperty(keyLabel)) {
133
+ return html` <td style="width:160px;min-width:100px"> <div class="param-name ${deprecated ? 'deprecated' : ''}"> <input placeholder="${keyLabel}" @change="${e => {
134
+ rowGenerator(e);
135
+ }}" .value="${''}" spellcheck="false" type="${format === 'binary' ? 'file' : format === 'password' ? 'password' : 'text'}" part="textbox textbox-param" style="width:100%" data-ptype="pattern-property-key" data-pname="${keyLabel}" data-default="${''}" data-array="false"> </div></td>`;
136
+ }
137
+
138
+ return html` <td style="width:160px;min-width:100px"> <div class="param-name ${deprecated ? 'deprecated' : ''}"> ${!deprecated && isRequired ? html`<span class="key-label">${keyLabel}</span><span style="color:var(--red)">*</span>` : isOption ? html`<span class="xxx-of-key">${keyLabel}</span><span class="xxx-of-descr">${keyDescription}</span>` : html`${keyLabel ? html`<span class="key-label"> ${keyLabel}</span>` : html`<span class="xxx-of-descr">${schemaTitle}</span>`}`} </div> <div class="param-type"> ${dataType === 'array' ? html`[<span>${format}</span>]` : `${format}`} </div> </td>`;
79
139
  } // function getObjectFormField(keyLabel, example, defaultValue, format, options) {
80
140
  // return html`
81
141
  // <td>
@@ -86,30 +146,36 @@ function generateFormRows(data, options, dataType = 'object', key = '', descript
86
146
  // part = "textarea textarea-param"
87
147
  // style = "width:100%; border:none; resize:vertical;"
88
148
  // data-array = "false"
89
- // data-ptype = "${options.mimeType.includes('form-urlencode') ? 'form-urlencode' : 'form-data'}"
149
+ // data-ptype = "form-input"
90
150
  // data-pname = "${keyLabel}"
91
151
  // data-default = "${defaultValue || ''}"
92
152
  // spellcheck = "false"
93
153
  // .value="${options.fillRequestWithDefault === 'true' ? defaultValue : ''}"
94
154
  // ></textarea>
95
155
  // <!-- This textarea(hidden) is to store the original example value, in focused mode on navbar change it is used to update the example text -->
96
- // <textarea data-pname = "hidden-${keyLabel}" data-ptype = "${options.mimeType.includes('form-urlencode') ? 'hidden-form-urlencode' : 'hidden-form-data'}" class="is-hidden" style="display:none" .value="${defaultValue}"></textarea>
156
+ // <textarea data-pname = "hidden-${keyLabel}" data-ptype = "hidden-form-input" class="is-hidden" style="display:none" .value="${defaultValue}"></textarea>
97
157
  // </div>
98
158
  // </div>
99
159
  // </td>`;
100
160
  // }
101
161
 
102
162
 
103
- function getArrayFormField(keyLabel, example, defaultValue, format, options) {
163
+ function getArrayFormField(keyLabel, example, defaultValue, format, rowGenerator) {
104
164
  if (format === 'binary') {
105
- return html`<td style="min-width:100px"> <div class="file-input-container col" style="align-items:flex-end" @click="${e => this.onAddRemoveFileInput(e, keyLabel, options.mimeType)}"> <div class="input-set row"> <input type="file" part="file-input" class="file-input" data-pname="${keyLabel}" data-ptype="${options.mimeType.includes('form-urlencode') ? 'form-urlencode' : 'form-data'}" data-array="false" data-file-array="true"> <button class="file-input-remove-btn"> &#x2715; </button> </div> <button class="m-btn primary file-input-add-btn" part="btn btn-fill" style="margin:2px 25px 0 0;padding:2px 6px">ADD</button> </div> </td>`;
165
+ return html`<td style="min-width:100px"> <div class="file-input-container col" style="align-items:flex-end" @click="${e => this.onAddRemoveFileInput(e, keyLabel)}"> <div class="input-set row"> <input @change="${e => {
166
+ rowGenerator(e);
167
+ }}" type="file" part="file-input" class="file-input" data-pname="${keyLabel}" data-ptype="form-input" data-array="false" data-file-array="true"> <button class="file-input-remove-btn"> &#x2715; </button> </div> <button class="m-btn primary file-input-add-btn" part="btn btn-fill" style="margin:2px 25px 0 0;padding:2px 6px">ADD</button> </div> </td>`;
106
168
  }
107
169
 
108
- return html`<td style="min-width:100px"> <tag-input style="width:100%" data-ptype="${options.mimeType.includes('form-urlencode') ? 'form-urlencode' : 'form-data'}" data-pname="${keyLabel}" data-default="${defaultValue || ''}" data-array="true" placeholder="${(Array.isArray(example) ? example[0] : example) || defaultValue || 'add-multiple ↩'}" .value="${defaultValue || ''}"></tag-input> </td>`;
170
+ return html`<td style="min-width:100px"> <tag-input @change="${e => {
171
+ rowGenerator(e);
172
+ }}" style="width:100%" data-ptype="form-input" data-pname="${keyLabel}" data-default="${defaultValue || ''}" data-array="true" placeholder="${(Array.isArray(example) ? example[0] : example) || defaultValue || 'add-multiple ↩'}" .value="${defaultValue || ''}"></tag-input> </td>`;
109
173
  }
110
174
 
111
- function getPrimitiveFormField(keyLabel, example, defaultValue, format, options) {
112
- return html`<td style="min-width:100px"> <input placeholder="${example || defaultValue || ''}" .value="${options.fillRequestWithDefault && defaultValue || ''}" spellcheck="false" type="${format === 'binary' ? 'file' : format === 'password' ? 'password' : 'text'}" part="textbox textbox-param" style="width:100%" data-ptype="${options.mimeType.includes('form-urlencode') ? 'form-urlencode' : 'form-data'}" data-pname="${keyLabel}" data-default="${defaultValue || ''}" data-array="false"> </td>`;
175
+ function getPrimitiveFormField(keyLabel, example, defaultValue, format, options, rowGenerator) {
176
+ return html`<td style="min-width:100px"> <input placeholder="${example || defaultValue || ''}" @change="${e => {
177
+ rowGenerator(e);
178
+ }}" .value="${options.fillRequestWithDefault && defaultValue || ''}" spellcheck="false" type="${format === 'binary' ? 'file' : format === 'password' ? 'password' : 'text'}" part="textbox textbox-param" style="width:100%" data-ptype="form-input" data-pname="${keyLabel}" data-default="${defaultValue || ''}" data-array="false"> </td>`;
113
179
  }
114
180
 
115
181
  export default function getRequestFormTable(data, mimeType) {
@@ -117,5 +183,5 @@ export default function getRequestFormTable(data, mimeType) {
117
183
  mimeType: mimeType,
118
184
  fillRequestWithDefault: this.fillRequestWithDefault === 'true'
119
185
  };
120
- return html` <table role="presentation" class="request-form-table" style="border:1px solid var(--light-border-color);width:100%"> ${data ? html`${generateFormRows.call(this, data['::type'] === 'array' ? data['::props'] : data, options, data['::type'])}` : ''} </table>`;
186
+ return html` <table id="request-form-table" role="presentation" class="request-form-table" style="border:1px solid var(--light-border-color);width:100%"> ${data ? html`${generateFormRows.call(this, data['::type'] === 'array' ? data['::props'] : data, options, data['::type'])}` : ''} </table>`;
121
187
  }
@@ -1,8 +1,12 @@
1
- import { LitElement, html, css } from 'lit';
1
+ import { LitElement, html } from 'lit';
2
2
  export default class TagInput extends LitElement {
3
+ createRenderRoot() {
4
+ return this;
5
+ }
6
+
3
7
  render() {
4
8
  const tagItemTemplate = html`${(this.value || []).filter(v => v.trim()).map(v => html`<span class="tag">${v}</span>`)}`;
5
- return html` <div class="tags" tabindex="0"> ${tagItemTemplate} <input type="text" class="editor" @paste="${e => this.afterPaste(e)}" @keydown="${this.afterKeyDown}" placeholder="${this.placeholder || ''}"> </div> `;
9
+ return html` <div class="tags" tabindex="0"> ${tagItemTemplate} <input type="text" class="editor" @change="${this.handleLeave}" @paste="${e => this.afterPaste(e)}" @keydown="${this.afterKeyDown}" placeholder="${this.placeholder || ''}"> </div> `;
6
10
  }
7
11
 
8
12
  static get properties() {
@@ -41,6 +45,7 @@ export default class TagInput extends LitElement {
41
45
  const pastedArray = pastedData && pastedData.split(',').filter(v => v.trim()) || [];
42
46
  this.value = this.value.concat(pastedArray);
43
47
  e.preventDefault();
48
+ this.emitChanged();
44
49
  }
45
50
 
46
51
  afterKeyDown(e) {
@@ -54,10 +59,24 @@ export default class TagInput extends LitElement {
54
59
  this.value = this.value.slice(0, -1);
55
60
  }
56
61
  }
62
+
63
+ this.emitChanged();
57
64
  }
58
65
 
59
- static finalizeStyles() {
60
- return [css`.tags{display:flex;flex-wrap:wrap;outline:0;padding:0;border-radius:var(--border-radius);border:1px solid var(--border-color);cursor:text;overflow:hidden;background:var(--input-bg)}.editor,.tag{padding:3px;margin:2px}.tag{border:1px solid var(--border-color);background-color:var(--bg3);color:var(--fg3);border-radius:var(--border-radius);word-break:break-all;font-size:var(--font-size-small)}.tag:hover~#cursor{display:block}.editor{flex:1;border:1px solid transparent;color:var(--fg);min-width:60px;outline:0;line-height:inherit;font-family:inherit;background:0 0;font-size:calc(var(--font-size-small) + 1px)}.editor::placeholder{color:var(--placeholder-color);opacity:1}`];
66
+ handleLeave(e) {
67
+ e.stopPropagation();
68
+ this.value = this.value.concat((e.target.value || '').split(',')).filter(v => v !== '');
69
+ e.target.value = '';
70
+ this.emitChanged();
71
+ }
72
+
73
+ emitChanged() {
74
+ const event = new CustomEvent('change', {
75
+ detail: {
76
+ value: this.value
77
+ }
78
+ });
79
+ this.dispatchEvent(event);
61
80
  }
62
81
 
63
82
  } // Register the element with the browser
@@ -21,6 +21,7 @@ import TableStyles from './styles/table-styles';
21
21
  import KeyFrameStyles from './styles/key-frame-styles';
22
22
  import EndpointStyles from './styles/endpoint-styles';
23
23
  import PrismStyles from './styles/prism-styles';
24
+ import TagInputStyles from './styles/tag-input-styles';
24
25
  import TabStyles from './styles/tab-styles';
25
26
  import NavStyles from './styles/nav-styles';
26
27
  import InfoStyles from './styles/info-styles';
@@ -221,7 +222,7 @@ export default class OpenApiExplorer extends LitElement {
221
222
  }
222
223
 
223
224
  static finalizeStyles() {
224
- return [FontStyles, SchemaStyles, InputStyles, FlexStyles, TableStyles, KeyFrameStyles, EndpointStyles, PrismStyles, TabStyles, NavStyles, InfoStyles, advancedSearchStyles, apiRequestStyles, css`:not(:defined){display:none}:host{display:flex;flex-direction:column;width:100%;height:100%;margin:0;padding:0;overflow:hidden;letter-spacing:normal;color:var(--fg);background-color:var(--bg);font-family:var(--font-regular)}.body{display:flex;height:100%;width:100%;overflow:hidden}a{text-decoration:none}.main-content{margin:0;padding:0;display:block;flex:1;height:100%;overflow-y:overlay;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:var(--border-color) transparent}.main-content::-webkit-scrollbar{width:8px;height:8px}.main-content::-webkit-scrollbar-track{background:0 0}.main-content::-webkit-scrollbar-thumb{background-color:var(--border-color)}.section-gap.section-tag{border-bottom:1px solid var(--border-color)}.method-section-gap{margin:0;padding:0 8px 0 4px;border-bottom:1px solid var(--border-color)}.section-gap{padding:24px 0 0}.section-tag-header{position:relative;cursor:n-resize;padding:12px 0}.collapsed .section-tag-header:hover{cursor:s-resize}.section-tag-header:hover{background-image:linear-gradient(to right,rgba(0,0,0,0),var(--border-color),rgba(0,0,0,0))}.collapsed .section-tag-header:hover::after{color:var(--primary-color)}.collapsed .section-tag-body{display:none}.logo{height:36px;width:36px;margin-left:5px}.only-large-screen,.only-large-screen-flex{display:none}.header-title{font-size:calc(var(--font-size-regular) + 8px);padding:0 8px}.tag.title{text-transform:uppercase}.header{background-color:var(--header-bg);color:var(--header-fg);width:100%}input.header-input{background:var(--header-color-darker);color:var(--header-fg);border:1px solid var(--header-color-border);flex:1;padding-right:24px;border-radius:3px}input.header-input::placeholder{opacity:.4}input:disabled{cursor:not-allowed}.loader{margin:16px auto 16px auto;border:4px solid var(--bg3);border-radius:50%;border-top:4px solid var(--primary-color);width:36px;height:36px;animation:spin 2s linear infinite}.expanded-endpoint-body{position:relative;padding:6px 0}.divider{border-top:2px solid var(--border-color);margin:24px 0;width:100%}.security-tooltip{border:1px solid var(--border-color);border-left-width:4px;margin-left:2px}.security-tooltip a{color:var(--fg2);text-decoration:none}.tooltip-text{color:var(--fg2);background-color:var(--bg2);visibility:hidden;overflow-wrap:break-word}.tooltip:hover{color:var(--primary-color);border-color:var(--primary-color)}.tooltip-replace:hover{visibility:hidden}.tooltip:hover a:hover{color:var(--primary-color)}.tooltip:hover .tooltip-text{visibility:visible;cursor:text;opacity:1}@media only screen and (max-width:767.98px){.section-padding{margin:1rem}.sub-title.tag{margin-left:1rem}.section-tag-body .description{margin-left:1rem;margin-right:1rem}}@media only screen and (min-width:768px){.nav-bar{width:260px;display:flex}.only-large-screen{display:block}.only-large-screen-flex{display:flex}.section-gap{padding:24px 24px}.section-gap--read-mode{padding:24px 8px}.section-gap--focused-mode{padding:1.5rem}.endpoint-body{position:relative;padding:36px 0 48px 0}}@media only screen and (min-width:1024px){.nav-bar{width:330px;display:flex}.section-gap--read-mode{padding:24px 24px 12px}.main-content-inner{padding:24px}}`];
225
+ return [FontStyles, SchemaStyles, InputStyles, FlexStyles, TableStyles, KeyFrameStyles, EndpointStyles, PrismStyles, TabStyles, NavStyles, InfoStyles, TagInputStyles, advancedSearchStyles, apiRequestStyles, css`:not(:defined){display:none}:host{display:flex;flex-direction:column;width:100%;height:100%;margin:0;padding:0;overflow:hidden;letter-spacing:normal;color:var(--fg);background-color:var(--bg);font-family:var(--font-regular)}.body{display:flex;height:100%;width:100%;overflow:hidden}a{text-decoration:none}.main-content{margin:0;padding:0;display:block;flex:1;height:100%;overflow-y:overlay;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:var(--border-color) transparent}.main-content::-webkit-scrollbar{width:8px;height:8px}.main-content::-webkit-scrollbar-track{background:0 0}.main-content::-webkit-scrollbar-thumb{background-color:var(--border-color)}.section-gap.section-tag{border-bottom:1px solid var(--border-color)}.method-section-gap{margin:0;padding:0 8px 0 4px;border-bottom:1px solid var(--border-color)}.section-gap{padding:24px 0 0}.section-tag-header{position:relative;cursor:n-resize;padding:12px 0}.collapsed .section-tag-header:hover{cursor:s-resize}.section-tag-header:hover{background-image:linear-gradient(to right,rgba(0,0,0,0),var(--border-color),rgba(0,0,0,0))}.collapsed .section-tag-header:hover::after{color:var(--primary-color)}.collapsed .section-tag-body{display:none}.logo{height:36px;width:36px;margin-left:5px}.only-large-screen,.only-large-screen-flex{display:none}.header-title{font-size:calc(var(--font-size-regular) + 8px);padding:0 8px}.tag.title{text-transform:uppercase}.header{background-color:var(--header-bg);color:var(--header-fg);width:100%}input.header-input{background:var(--header-color-darker);color:var(--header-fg);border:1px solid var(--header-color-border);flex:1;padding-right:24px;border-radius:3px}input.header-input::placeholder{opacity:.4}input:disabled{cursor:not-allowed}.loader{margin:16px auto 16px auto;border:4px solid var(--bg3);border-radius:50%;border-top:4px solid var(--primary-color);width:36px;height:36px;animation:spin 2s linear infinite}.expanded-endpoint-body{position:relative;padding:6px 0}.divider{border-top:2px solid var(--border-color);margin:24px 0;width:100%}.security-tooltip{border:1px solid var(--border-color);border-left-width:4px;margin-left:2px}.security-tooltip a{color:var(--fg2);text-decoration:none}.tooltip-text{color:var(--fg2);background-color:var(--bg2);visibility:hidden;overflow-wrap:break-word}.tooltip:hover{color:var(--primary-color);border-color:var(--primary-color)}.tooltip-replace:hover{visibility:hidden}.tooltip:hover a:hover{color:var(--primary-color)}.tooltip:hover .tooltip-text{visibility:visible;cursor:text;opacity:1}@media only screen and (max-width:767.98px){.section-padding{margin:1rem}.sub-title.tag{margin-left:1rem}.section-tag-body .description{margin-left:1rem;margin-right:1rem}}@media only screen and (min-width:768px){.nav-bar{width:260px;display:flex}.only-large-screen{display:block}.only-large-screen-flex{display:flex}.section-gap{padding:24px 24px}.section-gap--read-mode{padding:24px 8px}.section-gap--focused-mode{padding:1.5rem}.endpoint-body{position:relative;padding:36px 0 48px 0}}@media only screen and (min-width:1024px){.nav-bar{width:330px;display:flex}.section-gap--read-mode{padding:24px 24px 12px}.main-content-inner{padding:24px}}`];
225
226
  } // Startup
226
227
 
227
228
 
@@ -0,0 +1,2 @@
1
+ import { css } from 'lit';
2
+ export default css`tag-input .tags{display:flex;flex-wrap:wrap;outline:0;padding:0;border-radius:var(--border-radius);border:1px solid var(--border-color);cursor:text;overflow:hidden;background:var(--input-bg)}.editor,tag-input .tag{padding:3px;margin:2px}tag-input .tag{align-self:center;border:1px solid var(--border-color);background-color:var(--bg3);color:var(--fg3);border-radius:var(--border-radius);word-break:break-all;font-size:var(--font-size-small)}tag-input .tag:hover~#cursor{display:block}tag-input .editor{flex:1;border:1px solid transparent;color:var(--fg);min-width:60px;outline:0;line-height:inherit;font-family:inherit;background:0 0;font-size:calc(var(--font-size-small) + 1px)}tag-input .editor::placeholder{color:var(--placeholder-color);opacity:1}`;
@@ -54,10 +54,10 @@ export function getTypeInfo(schema, options = {
54
54
  };
55
55
 
56
56
  if (dataType === 'array' && schema.items) {
57
- var _schema$items$default, _schema$const2;
57
+ var _ref, _schema$items$default, _schema$const2;
58
58
 
59
59
  const arrayItemType = schema.items.type;
60
- const arrayItemDefault = (_schema$items$default = schema.items.default) !== null && _schema$items$default !== void 0 ? _schema$items$default : '';
60
+ const arrayItemDefault = (_ref = (_schema$items$default = schema.items.default) !== null && _schema$items$default !== void 0 ? _schema$items$default : schema.default) !== null && _ref !== void 0 ? _ref : '';
61
61
  info.arrayType = `${schema.type} of ${Array.isArray(arrayItemType) ? arrayItemType.join('') : arrayItemType}`;
62
62
  info.default = arrayItemDefault;
63
63
  info.allowedValues = (_schema$const2 = schema.const) !== null && _schema$const2 !== void 0 ? _schema$const2 : Array.isArray(schema.items.enum) ? schema.items.enum.join('┃') : '';
@@ -385,6 +385,10 @@ function getSimpleValueResult(schema, config, namespace, prefix, xmlAttributes,
385
385
  const value = getSampleValueByType(schema, config.propertyName, config.skipExampleStrings);
386
386
  return [value];
387
387
  }
388
+
389
+ export function isPatternProperty(label) {
390
+ return label.match(/^<any-key>|<pattern:/);
391
+ }
388
392
  /**
389
393
  * For changing OpenAPI-Schema to an Object Notation,
390
394
  * This Object would further be an input to UI Components to generate an Object-Tree
@@ -394,7 +398,6 @@ function getSimpleValueResult(schema, config, namespace, prefix, xmlAttributes,
394
398
  * @param {string} suffix - used for suffixing property names to avoid duplicate props during object composition
395
399
  */
396
400
 
397
-
398
401
  export function schemaInObjectNotation(rawSchema, options, level = 0, suffix = '') {
399
402
  if (!rawSchema) {
400
403
  return undefined;
@@ -43,6 +43,8 @@ class ApiRequest extends _lit.LitElement {
43
43
 
44
44
  constructor() {
45
45
  super();
46
+ this.duplicatedRowsByKey = {};
47
+ this.storedParamValues = {};
46
48
  this.responseMessage = '';
47
49
  this.responseStatus = '';
48
50
  this.responseHeaders = '';
@@ -159,6 +161,10 @@ class ApiRequest extends _lit.LitElement {
159
161
  attribute: 'fetch-credentials'
160
162
  },
161
163
  // properties for internal tracking
164
+ duplicatedRowsByKey: {
165
+ type: Object
166
+ },
167
+ // Tracking duplicated rows in form table
162
168
  activeResponseTab: {
163
169
  type: String
164
170
  },
@@ -182,13 +188,8 @@ class ApiRequest extends _lit.LitElement {
182
188
  }
183
189
 
184
190
  updated(changedProperties) {
185
- if (changedProperties.has('elementId')) {
186
- this.selectedRequestBodyType = '';
187
- this.selectedRequestBodyExample = '';
188
- } // In focused mode after rendering the request component, update the text-areas(which contains examples) using the original values from hidden textareas.
191
+ // In focused mode after rendering the request component, update the text-areas(which contains examples) using the original values from hidden textareas.
189
192
  // 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
190
-
191
-
192
193
  if (this.renderStyle !== 'focused') {
193
194
  return;
194
195
  } // dont update example as only tabs is switched
@@ -226,6 +227,8 @@ class ApiRequest extends _lit.LitElement {
226
227
  const tableRows = [];
227
228
 
228
229
  for (const param of filteredParams) {
230
+ var _this$storedParamValu;
231
+
229
232
  if (!param.schema) {
230
233
  continue;
231
234
  }
@@ -252,7 +255,9 @@ class ApiRequest extends _lit.LitElement {
252
255
  }
253
256
  }
254
257
 
255
- tableRows.push((0, _lit.html)` <tr> <td colspan="1" style="width:160px;min-width:50px;vertical-align:top"> <div class="param-name ${paramSchema.deprecated ? 'deprecated' : ''}" style="margin-top:1rem"> ${param.name}${!paramSchema.deprecated && param.required ? (0, _lit.html)`<span style="color:var(--red)">*</span>` : ''} </div> <div class="param-type" style="margin-bottom:1rem"> ${paramSchema.type === 'array' ? `${paramSchema.arrayType}` : `${paramSchema.format ? paramSchema.format : paramSchema.type}`}${!paramSchema.deprecated && param.required ? (0, _lit.html)`<span style="opacity:0">*</span>` : ''} </div> </td> <td colspan="2" style="min-width:160px;vertical-align:top"> ${this.allowTry === 'true' ? paramSchema.type === 'array' && (0, _lit.html)` <tag-input class="request-param" style="width:100%;margin-top:1rem;margin-bottom:1rem" data-ptype="${paramLocation}" data-pname="${param.name}" data-default="${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}" data-param-serialize-style="${paramStyle}" data-param-serialize-explode="${paramExplode}" data-array="true" placeholder="${paramSchema.example || (Array.isArray(defaultVal) ? defaultVal[0] : defaultVal) || 'add-multiple ↩'}" .value="${Array.isArray(defaultVal) ? defaultVal : defaultVal.split(',')}"></tag-input>` || paramSchema.type === 'object' && (0, _lit.html)` <textarea class="textarea small request-param" part="textarea small textarea-param" rows="3" data-ptype="${paramLocation}" data-pname="${param.name}" data-default="${defaultVal}" data-param-serialize-style="${paramStyle}" data-param-serialize-explode="${paramExplode}" spellcheck="false" placeholder="${paramSchema.example || defaultVal || ''}" style="width:100%;margin-top:1rem;margin-bottom:1rem" .value="${this.fillRequestWithDefault === 'true' ? defaultVal : ''}"></textarea>` || (0, _lit.html)` <input type="${paramSchema.format === 'password' ? 'password' : 'text'}" spellcheck="false" style="width:100%;margin-top:1rem;margin-bottom:1rem" placeholder="${paramSchema.example || defaultVal || ''}" class="request-param" part="textbox textbox-param" data-ptype="${paramLocation}" data-pname="${param.name}" data-default="${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}" data-array="false" @keyup="${this.requestParamFunction}" .value="${this.fillRequestWithDefault === 'true' ? defaultVal : ''}">` : ''} ${this.exampleListTemplate.call(this, param, paramSchema.type)} </td> ${this.renderStyle === 'focused' ? (0, _lit.html)` <td colspan="2" style="vertical-align:top"> ${param.description ? (0, _lit.html)` <div class="param-description" style="margin-top:1rem"> ${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(param.description))} </div>` : ''} ${paramSchema.default || paramSchema.s || paramSchema.allowedValues || paramSchema.pattern ? (0, _lit.html)` <div class="param-constraint" style="margin-top:1rem"> ${paramSchema.constraints.length ? (0, _lit.html)`<span style="font-weight:700">Constraints: </span>${paramSchema.constraints.join(', ')}<br>` : ''} ${paramSchema.pattern ? (0, _lit.html)` <div class="tooltip tooltip-replace" style="cursor:pointer;max-width:100%;display:flex"> <div style="white-space:nowrap;font-weight:700;margin-right:2px">Pattern: </div> <div style="white-space:nowrap;text-overflow:ellipsis;max-width:100%;overflow:hidden">${paramSchema.pattern}</div> <br> <div class="tooltip-text" style="position:absolute;display:block">${paramSchema.pattern}</div> </div> ` : ''} ${paramSchema.allowedValues && paramSchema.allowedValues.split('┃').map((v, i) => (0, _lit.html)` ${i > 0 ? '|' : (0, _lit.html)`<span style="font-weight:700">Allowed: </span>`} ${(0, _lit.html)` <a part="anchor anchor-param-constraint" class="${this.allowTry === 'true' ? '' : 'inactive-link'}" data-type="${paramSchema.type === 'array' ? 'array' : 'string'}" data-enum="${v.trim()}" @click="${e => {
258
+ tableRows.push((0, _lit.html)` <tr> <td colspan="1" style="width:160px;min-width:50px;vertical-align:top"> <div class="param-name ${paramSchema.deprecated ? 'deprecated' : ''}" style="margin-top:1rem"> ${param.name}${!paramSchema.deprecated && param.required ? (0, _lit.html)`<span style="color:var(--red)">*</span>` : ''} </div> <div class="param-type" style="margin-bottom:1rem"> ${paramSchema.type === 'array' ? `${paramSchema.arrayType}` : `${paramSchema.format ? paramSchema.format : paramSchema.type}`}${!paramSchema.deprecated && param.required ? (0, _lit.html)`<span style="opacity:0">*</span>` : ''} </div> </td> <td colspan="2" style="min-width:160px;vertical-align:top"> ${this.allowTry === 'true' ? paramSchema.type === 'array' && (0, _lit.html)` <div style="margin-top:1rem;margin-bottom:1rem"> <tag-input class="request-param" style="width:100%" data-ptype="${paramLocation}" data-pname="${param.name}" data-default="${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}" data-param-serialize-style="${paramStyle}" data-param-serialize-explode="${paramExplode}" data-array="true" placeholder="add-multiple " @change="${e => {
259
+ this.storedParamValues[param.name] = e.detail.value;
260
+ }}" .value="${(_this$storedParamValu = this.storedParamValues[param.name]) !== null && _this$storedParamValu !== void 0 ? _this$storedParamValu : this.fillRequestWithDefault === 'true' && Array.isArray(defaultVal) ? defaultVal : defaultVal.split(',')}"></tag-input> </div>` || paramSchema.type === 'object' && (0, _lit.html)` <textarea class="textarea small request-param" part="textarea small textarea-param" rows="3" data-ptype="${paramLocation}" data-pname="${param.name}" data-default="${defaultVal}" data-param-serialize-style="${paramStyle}" data-param-serialize-explode="${paramExplode}" spellcheck="false" placeholder="${paramSchema.example || defaultVal || ''}" style="width:100%;margin-top:1rem;margin-bottom:1rem" .value="${this.fillRequestWithDefault === 'true' ? defaultVal : ''}"></textarea>` || (0, _lit.html)` <input type="${paramSchema.format === 'password' ? 'password' : 'text'}" spellcheck="false" style="width:100%;margin-top:1rem;margin-bottom:1rem" placeholder="${paramSchema.example || defaultVal || ''}" class="request-param" part="textbox textbox-param" data-ptype="${paramLocation}" data-pname="${param.name}" data-default="${Array.isArray(defaultVal) ? defaultVal.join('~|~') : defaultVal}" data-array="false" @keyup="${this.requestParamFunction}" .value="${this.fillRequestWithDefault === 'true' ? defaultVal : ''}">` : ''} ${this.exampleListTemplate.call(this, param, paramSchema.type)} </td> ${this.renderStyle === 'focused' ? (0, _lit.html)` <td colspan="2" style="vertical-align:top"> ${param.description ? (0, _lit.html)` <div class="param-description" style="margin-top:1rem"> ${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(param.description))} </div>` : ''} ${paramSchema.default || paramSchema.s || paramSchema.allowedValues || paramSchema.pattern ? (0, _lit.html)` <div class="param-constraint" style="margin-top:1rem"> ${paramSchema.constraints.length ? (0, _lit.html)`<span style="font-weight:700">Constraints: </span>${paramSchema.constraints.join(', ')}<br>` : ''} ${paramSchema.pattern ? (0, _lit.html)` <div class="tooltip tooltip-replace" style="cursor:pointer;max-width:100%;display:flex"> <div style="white-space:nowrap;font-weight:700;margin-right:2px">Pattern: </div> <div style="white-space:nowrap;text-overflow:ellipsis;max-width:100%;overflow:hidden">${paramSchema.pattern}</div> <br> <div class="tooltip-text" style="position:absolute;display:block">${paramSchema.pattern}</div> </div> ` : ''} ${paramSchema.allowedValues && paramSchema.allowedValues.split('┃').map((v, i) => (0, _lit.html)` ${i > 0 ? '|' : (0, _lit.html)`<span style="font-weight:700">Allowed: </span>`} ${(0, _lit.html)` <a part="anchor anchor-param-constraint" class="${this.allowTry === 'true' ? '' : 'inactive-link'}" data-type="${paramSchema.type === 'array' ? 'array' : 'string'}" data-enum="${v.trim()}" @click="${e => {
256
261
  const inputEl = e.target.closest('table').querySelector(`[data-pname="${param.name}"]`);
257
262
 
258
263
  if (inputEl) {
@@ -427,7 +432,7 @@ class ApiRequest extends _lit.LitElement {
427
432
  }
428
433
  }
429
434
 
430
- return (0, _lit.html)` <div class="request-body-container" data-selected-request-body-type="${this.selectedRequestBodyType}"> <div class="table-title top-gap row"> REQUEST BODY ${this.request_body.required ? (0, _lit.html)`<span class="mono-font" style="color:var(--red)">*</span>` : ''} <span style="font-weight:400;margin-left:5px"> ${this.selectedRequestBodyType}</span> <span style="flex:1"></span> ${reqBodyTypeSelectorHtml} </div> ${this.request_body.description ? (0, _lit.html)`<div class="m-markdown" style="margin-bottom:12px">${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(this.request_body.description))}</div>` : ''} ${reqBodySchemaHtml || reqBodyDefaultHtml ? (0, _lit.html)` <div class="tab-panel col" style="border-width:0 0 1px 0"> <div class="tab-buttons row" @click="${e => {
435
+ return (0, _lit.html)` <div class="request-body-container" data-selected-request-body-type="${this.selectedRequestBodyType}"> <div class="table-title top-gap row"> ${(0, _languages.getI18nText)('operations.request-body')} ${this.request_body.required ? (0, _lit.html)`<span class="mono-font" style="color:var(--red)">*</span>` : ''} <span style="font-weight:400;margin-left:5px"> ${this.selectedRequestBodyType}</span> <span style="flex:1"></span> ${reqBodyTypeSelectorHtml} </div> ${this.request_body.description ? (0, _lit.html)`<div class="m-markdown" style="margin-bottom:12px">${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(this.request_body.description))}</div>` : ''} ${reqBodySchemaHtml || reqBodyDefaultHtml ? (0, _lit.html)` <div class="tab-panel col" style="border-width:0 0 1px 0"> <div class="tab-buttons row" @click="${e => {
431
436
  if (e.target.tagName.toLowerCase() === 'button') {
432
437
  this.activeSchemaTab = e.target.dataset.tab;
433
438
  }
@@ -494,7 +499,8 @@ class ApiRequest extends _lit.LitElement {
494
499
  }
495
500
  };
496
501
  this.dispatchEvent(new CustomEvent('event', event));
497
- }
502
+ } // onExecuteButtonClicked
503
+
498
504
 
499
505
  async onTryClick() {
500
506
  const tryBtnEl = this.querySelectorAll('.btn-execute')[0];
@@ -619,14 +625,19 @@ class ApiRequest extends _lit.LitElement {
619
625
  fetchOptions.headers.append(el.dataset.pname, el.value);
620
626
  }
621
627
  }); // Request Body Params
628
+ // url-encoded Form Params (dynamic) - Parse JSON and generate Params
629
+
630
+ const formUrlDynamicTextAreaEl = requestPanelEl.querySelector("[data-ptype='dynamic-form']"); // url-encoded Form Params (regular)
631
+
632
+ const rawFormInputEls = [...requestPanelEl.querySelectorAll("[data-ptype='form-input']")];
633
+ const patternPropertyKeyEls = [...requestPanelEl.querySelectorAll("[data-ptype='pattern-property-key']")];
634
+ const patternPropertyInputEls = rawFormInputEls.filter(el => (0, _schemaUtils.isPatternProperty)(el.dataset.pname));
635
+ const formInputEls = rawFormInputEls.filter(el => !(0, _schemaUtils.isPatternProperty)(el.dataset.pname));
622
636
 
623
637
  if (requestBodyContainerEl) {
624
638
  const requestBodyType = requestBodyContainerEl.dataset.selectedRequestBodyType;
625
639
 
626
640
  if (requestBodyType.includes('form-urlencoded')) {
627
- // url-encoded Form Params (dynamic) - Parse JSON and generate Params
628
- const formUrlDynamicTextAreaEl = requestPanelEl.querySelector("[data-ptype='dynamic-form']");
629
-
630
641
  if (formUrlDynamicTextAreaEl) {
631
642
  const val = formUrlDynamicTextAreaEl.value;
632
643
  const formUrlDynParams = new URLSearchParams();
@@ -653,17 +664,23 @@ class ApiRequest extends _lit.LitElement {
653
664
  curlData = ` \\\n -d ${formUrlDynParams.toString()}`;
654
665
  }
655
666
  } else {
656
- // url-encoded Form Params (regular)
657
- const formUrlEls = [...requestPanelEl.querySelectorAll("[data-ptype='form-urlencode']")];
658
667
  const formUrlParams = new URLSearchParams();
659
- formUrlEls.filter(v => v.type !== 'file').forEach(el => {
668
+ patternPropertyInputEls.concat(formInputEls).forEach((el, counter) => {
669
+ var _patternPropertyKeyEl;
670
+
671
+ const keyName = ((_patternPropertyKeyEl = patternPropertyKeyEls[counter]) === null || _patternPropertyKeyEl === void 0 ? void 0 : _patternPropertyKeyEl.value) || el.dataset.pname;
672
+
673
+ if (el.type === 'file') {
674
+ return;
675
+ }
676
+
660
677
  if (el.dataset.array === 'false') {
661
678
  if (el.value) {
662
- formUrlParams.append(el.dataset.pname, el.value);
679
+ formUrlParams.append(keyName, el.value);
663
680
  }
664
681
  } else {
665
682
  const vals = el.value && Array.isArray(el.value) ? el.value.join(',') : '';
666
- formUrlParams.append(el.dataset.pname, vals);
683
+ formUrlParams.append(keyName, vals);
667
684
  }
668
685
  });
669
686
  fetchOptions.body = formUrlParams;
@@ -671,21 +688,24 @@ class ApiRequest extends _lit.LitElement {
671
688
  }
672
689
  } else if (requestBodyType.includes('form-data')) {
673
690
  const formDataParams = new FormData();
674
- const formDataEls = [...requestPanelEl.querySelectorAll("[data-ptype='form-data']")];
675
- formDataEls.forEach(el => {
691
+ patternPropertyInputEls.concat(formInputEls).forEach((el, counter) => {
692
+ var _patternPropertyKeyEl2;
693
+
694
+ const keyName = ((_patternPropertyKeyEl2 = patternPropertyKeyEls[counter]) === null || _patternPropertyKeyEl2 === void 0 ? void 0 : _patternPropertyKeyEl2.value) || el.dataset.pname;
695
+
676
696
  if (el.dataset.array === 'false') {
677
697
  if (el.type === 'file' && el.files[0]) {
678
- formDataParams.append(el.dataset.pname, el.files[0], el.files[0].name);
679
- curlForm += ` \\\n -F "${el.dataset.pname}=@${el.files[0].name}"`;
698
+ formDataParams.append(keyName, el.files[0], el.files[0].name);
699
+ curlForm += ` \\\n -F "${keyName}=@${el.files[0].name}"`;
680
700
  } else if (el.value) {
681
- formDataParams.append(el.dataset.pname, el.value);
682
- curlForm += ` \\\n -F "${el.dataset.pname}=${el.value}"`;
701
+ formDataParams.append(keyName, el.value);
702
+ curlForm += ` \\\n -F "${keyName}=${el.value}"`;
683
703
  }
684
704
  } else if (el.value && Array.isArray(el.value)) {
685
705
  el.value.forEach(v => {
686
- curlForm += ` \\\n -F "${el.dataset.pname}[]=${v}"`;
706
+ curlForm += ` \\\n -F "${keyName}[]=${v}"`;
687
707
  });
688
- formDataParams.append(el.dataset.pname, el.value.join(','));
708
+ formDataParams.append(keyName, el.value.join(','));
689
709
  }
690
710
  });
691
711
  fetchOptions.body = formDataParams;
@@ -881,7 +901,7 @@ class ApiRequest extends _lit.LitElement {
881
901
  }
882
902
  }
883
903
 
884
- onAddRemoveFileInput(e, pname, ptype) {
904
+ onAddRemoveFileInput(e, pname) {
885
905
  if (e.target.tagName.toLowerCase() !== 'button') {
886
906
  return;
887
907
  }
@@ -903,7 +923,7 @@ class ApiRequest extends _lit.LitElement {
903
923
  newInputEl.type = 'file';
904
924
  newInputEl.setAttribute('class', 'file-input');
905
925
  newInputEl.setAttribute('data-pname', pname);
906
- newInputEl.setAttribute('data-ptype', ptype.includes('form-urlencode') ? 'form-urlencode' : 'form-data');
926
+ newInputEl.setAttribute('data-ptype', 'form-input');
907
927
  newInputEl.setAttribute('data-array', 'false');
908
928
  newInputEl.setAttribute('data-file-array', 'true'); // Remover Button
909
929