openapi-explorer 1.0.571 → 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
  }
@@ -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,7 @@ class ApiRequest extends _lit.LitElement {
43
43
 
44
44
  constructor() {
45
45
  super();
46
+ this.duplicatedRowsByKey = {};
46
47
  this.storedParamValues = {};
47
48
  this.responseMessage = '';
48
49
  this.responseStatus = '';
@@ -160,6 +161,10 @@ class ApiRequest extends _lit.LitElement {
160
161
  attribute: 'fetch-credentials'
161
162
  },
162
163
  // properties for internal tracking
164
+ duplicatedRowsByKey: {
165
+ type: Object
166
+ },
167
+ // Tracking duplicated rows in form table
163
168
  activeResponseTab: {
164
169
  type: String
165
170
  },
@@ -183,13 +188,8 @@ class ApiRequest extends _lit.LitElement {
183
188
  }
184
189
 
185
190
  updated(changedProperties) {
186
- if (changedProperties.has('elementId')) {
187
- this.selectedRequestBodyType = '';
188
- this.selectedRequestBodyExample = '';
189
- } // 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.
190
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
191
-
192
-
193
193
  if (this.renderStyle !== 'focused') {
194
194
  return;
195
195
  } // dont update example as only tabs is switched
@@ -432,7 +432,7 @@ class ApiRequest extends _lit.LitElement {
432
432
  }
433
433
  }
434
434
 
435
- 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 => {
436
436
  if (e.target.tagName.toLowerCase() === 'button') {
437
437
  this.activeSchemaTab = e.target.dataset.tab;
438
438
  }
@@ -499,7 +499,8 @@ class ApiRequest extends _lit.LitElement {
499
499
  }
500
500
  };
501
501
  this.dispatchEvent(new CustomEvent('event', event));
502
- }
502
+ } // onExecuteButtonClicked
503
+
503
504
 
504
505
  async onTryClick() {
505
506
  const tryBtnEl = this.querySelectorAll('.btn-execute')[0];
@@ -624,14 +625,19 @@ class ApiRequest extends _lit.LitElement {
624
625
  fetchOptions.headers.append(el.dataset.pname, el.value);
625
626
  }
626
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));
627
636
 
628
637
  if (requestBodyContainerEl) {
629
638
  const requestBodyType = requestBodyContainerEl.dataset.selectedRequestBodyType;
630
639
 
631
640
  if (requestBodyType.includes('form-urlencoded')) {
632
- // url-encoded Form Params (dynamic) - Parse JSON and generate Params
633
- const formUrlDynamicTextAreaEl = requestPanelEl.querySelector("[data-ptype='dynamic-form']");
634
-
635
641
  if (formUrlDynamicTextAreaEl) {
636
642
  const val = formUrlDynamicTextAreaEl.value;
637
643
  const formUrlDynParams = new URLSearchParams();
@@ -658,17 +664,23 @@ class ApiRequest extends _lit.LitElement {
658
664
  curlData = ` \\\n -d ${formUrlDynParams.toString()}`;
659
665
  }
660
666
  } else {
661
- // url-encoded Form Params (regular)
662
- const formUrlEls = [...requestPanelEl.querySelectorAll("[data-ptype='form-urlencode']")];
663
667
  const formUrlParams = new URLSearchParams();
664
- 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
+
665
677
  if (el.dataset.array === 'false') {
666
678
  if (el.value) {
667
- formUrlParams.append(el.dataset.pname, el.value);
679
+ formUrlParams.append(keyName, el.value);
668
680
  }
669
681
  } else {
670
682
  const vals = el.value && Array.isArray(el.value) ? el.value.join(',') : '';
671
- formUrlParams.append(el.dataset.pname, vals);
683
+ formUrlParams.append(keyName, vals);
672
684
  }
673
685
  });
674
686
  fetchOptions.body = formUrlParams;
@@ -676,21 +688,24 @@ class ApiRequest extends _lit.LitElement {
676
688
  }
677
689
  } else if (requestBodyType.includes('form-data')) {
678
690
  const formDataParams = new FormData();
679
- const formDataEls = [...requestPanelEl.querySelectorAll("[data-ptype='form-data']")];
680
- 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
+
681
696
  if (el.dataset.array === 'false') {
682
697
  if (el.type === 'file' && el.files[0]) {
683
- formDataParams.append(el.dataset.pname, el.files[0], el.files[0].name);
684
- 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}"`;
685
700
  } else if (el.value) {
686
- formDataParams.append(el.dataset.pname, el.value);
687
- curlForm += ` \\\n -F "${el.dataset.pname}=${el.value}"`;
701
+ formDataParams.append(keyName, el.value);
702
+ curlForm += ` \\\n -F "${keyName}=${el.value}"`;
688
703
  }
689
704
  } else if (el.value && Array.isArray(el.value)) {
690
705
  el.value.forEach(v => {
691
- curlForm += ` \\\n -F "${el.dataset.pname}[]=${v}"`;
706
+ curlForm += ` \\\n -F "${keyName}[]=${v}"`;
692
707
  });
693
- formDataParams.append(el.dataset.pname, el.value.join(','));
708
+ formDataParams.append(keyName, el.value.join(','));
694
709
  }
695
710
  });
696
711
  fetchOptions.body = formDataParams;
@@ -886,7 +901,7 @@ class ApiRequest extends _lit.LitElement {
886
901
  }
887
902
  }
888
903
 
889
- onAddRemoveFileInput(e, pname, ptype) {
904
+ onAddRemoveFileInput(e, pname) {
890
905
  if (e.target.tagName.toLowerCase() !== 'button') {
891
906
  return;
892
907
  }
@@ -908,7 +923,7 @@ class ApiRequest extends _lit.LitElement {
908
923
  newInputEl.type = 'file';
909
924
  newInputEl.setAttribute('class', 'file-input');
910
925
  newInputEl.setAttribute('data-pname', pname);
911
- newInputEl.setAttribute('data-ptype', ptype.includes('form-urlencode') ? 'form-urlencode' : 'form-data');
926
+ newInputEl.setAttribute('data-ptype', 'form-input');
912
927
  newInputEl.setAttribute('data-array', 'false');
913
928
  newInputEl.setAttribute('data-file-array', 'true'); // Remover Button
914
929
 
@@ -9,6 +9,12 @@ var _marked = require("marked");
9
9
 
10
10
  var _unsafeHtml = require("lit/directives/unsafe-html.js");
11
11
 
12
+ var _schemaUtils = require("../utils/schema-utils");
13
+
14
+ var _map = require("lit/directives/map.js");
15
+
16
+ var _range = require("lit/directives/range.js");
17
+
12
18
  /* eslint-disable indent */
13
19
  function generateFormRows(data, options, dataType = 'object', key = '', description = '', schemaLevel = 0) {
14
20
  const newSchemaLevel = data['::type'] && data['::type'].startsWith('xxx-of') ? schemaLevel : schemaLevel + 1;
@@ -52,6 +58,20 @@ function generateFormRows(data, options, dataType = 'object', key = '', descript
52
58
 
53
59
 
54
60
  const parsedData = JSON.parse(data);
61
+ return generatePrimitiveRow.call(this, parsedData, {
62
+ key,
63
+ keyLabel,
64
+ keyDescr,
65
+ description,
66
+ dataType,
67
+ isRequired,
68
+ options
69
+ });
70
+ }
71
+
72
+ function generatePrimitiveRow(rowData, parentRecursionOptions) {
73
+ var _this$duplicatedRowsB;
74
+
55
75
  const {
56
76
  type,
57
77
  format,
@@ -64,13 +84,46 @@ function generateFormRows(data, options, dataType = 'object', key = '', descript
64
84
  schemaDescription,
65
85
  schemaTitle,
66
86
  deprecated
67
- } = parsedData;
87
+ } = rowData;
88
+ const {
89
+ key,
90
+ keyLabel,
91
+ keyDescr,
92
+ description,
93
+ dataType,
94
+ isRequired,
95
+ options
96
+ } = parentRecursionOptions;
68
97
 
69
98
  if (readOrWriteOnly === '🆁') {
70
99
  return undefined;
71
100
  }
72
101
 
73
- return (0, _lit.html)` <tr> <td style="width:160px;min-width:100px"> <div class="param-name ${deprecated ? 'deprecated' : ''}"> ${!deprecated && isRequired ? (0, _lit.html)`<span class="key-label">${keyLabel}</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="param-type"> ${dataType === 'array' ? (0, _lit.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 ? (0, _lit.html)`<div class="param-description">${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(description))}</div>` : ''} ${defaultValue || constraints || allowedValues || pattern ? (0, _lit.html)` <div class="param-constraint"> ${pattern ? (0, _lit.html)`<span style="font-weight:700">Pattern: </span>${pattern}<br>` : ''} ${constraints.length ? (0, _lit.html)`<span style="font-weight:700">Constraints: </span>${constraints.join(', ')}<br>` : ''} ${allowedValues === null || allowedValues === void 0 ? void 0 : 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" data-type="${type === 'array' ? type : 'string'}" data-enum="${v.trim()}" @click="${e => {
102
+ const elementId = this.elementId || `${this.method}-${this.path}`;
103
+ const duplicateRowGeneratorKey = `${elementId}-${key}`;
104
+
105
+ const rowGenerator = e => {
106
+ var _e$target$dataset, _e$target$dataset2;
107
+
108
+ if (((_e$target$dataset = e.target.dataset) === null || _e$target$dataset === void 0 ? void 0 : _e$target$dataset.ptype) !== 'pattern-property-key' && !(0, _schemaUtils.isPatternProperty)((_e$target$dataset2 = e.target.dataset) === null || _e$target$dataset2 === void 0 ? void 0 : _e$target$dataset2.pname)) {
109
+ return;
110
+ } // If the row key has a value then add another row
111
+
112
+
113
+ const patternPropertyKeyEls = [...this.querySelectorAll("[data-ptype='pattern-property-key']")];
114
+ const patternPropertyInputEls = [...this.querySelectorAll("[data-ptype='form-input']")].filter(el => (0, _schemaUtils.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
115
+
116
+ if (patternPropertyKeyEls.some((keyElement, index) => !keyElement.value || !patternPropertyInputEls[index].value)) {
117
+ return;
118
+ }
119
+
120
+ if (e.target.value) {
121
+ this.duplicatedRowsByKey[duplicateRowGeneratorKey] = (this.duplicatedRowsByKey[duplicateRowGeneratorKey] || 1) + 1;
122
+ this.requestUpdate();
123
+ }
124
+ };
125
+
126
+ return (0, _map.map)((0, _range.range)(((_this$duplicatedRowsB = this.duplicatedRowsByKey) === null || _this$duplicatedRowsB === void 0 ? void 0 : _this$duplicatedRowsB[duplicateRowGeneratorKey]) || 1), () => (0, _lit.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 ? (0, _lit.html)`<div class="param-description">${(0, _unsafeHtml.unsafeHTML)((0, _marked.marked)(description))}</div>` : ''} ${defaultValue || constraints || allowedValues || pattern ? (0, _lit.html)` <div class="param-constraint"> ${pattern ? (0, _lit.html)`<span style="font-weight:700">Pattern: </span>${pattern}<br>` : ''} ${constraints.length ? (0, _lit.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) => (0, _lit.html)` ${i > 0 ? '|' : (0, _lit.html)`<span style="font-weight:700">Allowed: </span>`} ${(0, _lit.html)` <a part="anchor anchor-param-constraint" data-type="${type === 'array' ? type : 'string'}" data-enum="${v.trim()}" @click="${e => {
74
127
  const inputEl = e.target.closest('table').querySelector(`[data-pname="${keyLabel}"]`);
75
128
 
76
129
  if (inputEl) {
@@ -82,7 +135,17 @@ function generateFormRows(data, options, dataType = 'object', key = '', descript
82
135
  if (inputEl) {
83
136
  inputEl.value = e.target.dataset.exampleType === 'array' ? e.target.dataset.example.split('~|~') : e.target.dataset.example;
84
137
  }
85
- }}"> ${type === 'array' ? example.join(', ') : example} </a> ${type === 'array' ? '] ' : ''} </span>` : ''} </td> </tr>` : ''}`;
138
+ }}"> ${type === 'array' ? example.join(', ') : example} </a> ${type === 'array' ? '] ' : ''} </span>` : ''} </td> </tr>` : ''}`);
139
+ }
140
+
141
+ function inputFieldKeyLabel(isOption, keyLabel, keyDescription, dataType, deprecated, isRequired, schemaTitle, format, rowGenerator) {
142
+ if ((0, _schemaUtils.isPatternProperty)(keyLabel)) {
143
+ return (0, _lit.html)` <td style="width:160px;min-width:100px"> <div class="param-name ${deprecated ? 'deprecated' : ''}"> <input placeholder="${keyLabel}" @change="${e => {
144
+ rowGenerator(e);
145
+ }}" .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>`;
146
+ }
147
+
148
+ return (0, _lit.html)` <td style="width:160px;min-width:100px"> <div class="param-name ${deprecated ? 'deprecated' : ''}"> ${!deprecated && isRequired ? (0, _lit.html)`<span class="key-label">${keyLabel}</span><span style="color:var(--red)">*</span>` : isOption ? (0, _lit.html)`<span class="xxx-of-key">${keyLabel}</span><span class="xxx-of-descr">${keyDescription}</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="param-type"> ${dataType === 'array' ? (0, _lit.html)`[<span>${format}</span>]` : `${format}`} </div> </td>`;
86
149
  } // function getObjectFormField(keyLabel, example, defaultValue, format, options) {
87
150
  // return html`
88
151
  // <td>
@@ -93,30 +156,36 @@ function generateFormRows(data, options, dataType = 'object', key = '', descript
93
156
  // part = "textarea textarea-param"
94
157
  // style = "width:100%; border:none; resize:vertical;"
95
158
  // data-array = "false"
96
- // data-ptype = "${options.mimeType.includes('form-urlencode') ? 'form-urlencode' : 'form-data'}"
159
+ // data-ptype = "form-input"
97
160
  // data-pname = "${keyLabel}"
98
161
  // data-default = "${defaultValue || ''}"
99
162
  // spellcheck = "false"
100
163
  // .value="${options.fillRequestWithDefault === 'true' ? defaultValue : ''}"
101
164
  // ></textarea>
102
165
  // <!-- This textarea(hidden) is to store the original example value, in focused mode on navbar change it is used to update the example text -->
103
- // <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>
166
+ // <textarea data-pname = "hidden-${keyLabel}" data-ptype = "hidden-form-input" class="is-hidden" style="display:none" .value="${defaultValue}"></textarea>
104
167
  // </div>
105
168
  // </div>
106
169
  // </td>`;
107
170
  // }
108
171
 
109
172
 
110
- function getArrayFormField(keyLabel, example, defaultValue, format, options) {
173
+ function getArrayFormField(keyLabel, example, defaultValue, format, rowGenerator) {
111
174
  if (format === 'binary') {
112
- return (0, _lit.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>`;
175
+ return (0, _lit.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 => {
176
+ rowGenerator(e);
177
+ }}" 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>`;
113
178
  }
114
179
 
115
- return (0, _lit.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>`;
180
+ return (0, _lit.html)`<td style="min-width:100px"> <tag-input @change="${e => {
181
+ rowGenerator(e);
182
+ }}" 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>`;
116
183
  }
117
184
 
118
- function getPrimitiveFormField(keyLabel, example, defaultValue, format, options) {
119
- return (0, _lit.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>`;
185
+ function getPrimitiveFormField(keyLabel, example, defaultValue, format, options, rowGenerator) {
186
+ return (0, _lit.html)`<td style="min-width:100px"> <input placeholder="${example || defaultValue || ''}" @change="${e => {
187
+ rowGenerator(e);
188
+ }}" .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>`;
120
189
  }
121
190
 
122
191
  function getRequestFormTable(data, mimeType) {
@@ -124,5 +193,5 @@ function getRequestFormTable(data, mimeType) {
124
193
  mimeType: mimeType,
125
194
  fillRequestWithDefault: this.fillRequestWithDefault === 'true'
126
195
  };
127
- return (0, _lit.html)` <table role="presentation" class="request-form-table" style="border:1px solid var(--light-border-color);width:100%"> ${data ? (0, _lit.html)`${generateFormRows.call(this, data['::type'] === 'array' ? data['::props'] : data, options, data['::type'])}` : ''} </table>`;
196
+ return (0, _lit.html)` <table id="request-form-table" role="presentation" class="request-form-table" style="border:1px solid var(--light-border-color);width:100%"> ${data ? (0, _lit.html)`${generateFormRows.call(this, data['::type'] === 'array' ? data['::props'] : data, options, data['::type'])}` : ''} </table>`;
128
197
  }
@@ -5,6 +5,7 @@ exports.generateExample = generateExample;
5
5
  exports.getExampleValuesFromSchema = getExampleValuesFromSchema;
6
6
  exports.getSampleValueByType = getSampleValueByType;
7
7
  exports.getTypeInfo = getTypeInfo;
8
+ exports.isPatternProperty = isPatternProperty;
8
9
  exports.schemaInObjectNotation = schemaInObjectNotation;
9
10
 
10
11
  var _lodash = _interopRequireDefault(require("lodash.clonedeep"));
@@ -402,6 +403,10 @@ function getSimpleValueResult(schema, config, namespace, prefix, xmlAttributes,
402
403
  const value = getSampleValueByType(schema, config.propertyName, config.skipExampleStrings);
403
404
  return [value];
404
405
  }
406
+
407
+ function isPatternProperty(label) {
408
+ return label.match(/^<any-key>|<pattern:/);
409
+ }
405
410
  /**
406
411
  * For changing OpenAPI-Schema to an Object Notation,
407
412
  * This Object would further be an input to UI Components to generate an Object-Tree
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openapi-explorer",
3
- "version": "1.0.571",
3
+ "version": "1.0.577",
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",