openapi-explorer 0.8.301 → 0.9.305

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openapi-explorer",
3
- "version": "0.8.301",
3
+ "version": "0.9.305",
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
  "repository": {
@@ -39,22 +39,20 @@
39
39
  ],
40
40
  "mode": "production",
41
41
  "dependencies": {
42
- "authress-login": "^1.1.77",
42
+ "authress-login": "^1.2.104",
43
43
  "base64url": "^3.0.1",
44
44
  "buffer": "^6.0.3",
45
45
  "color": "^4.2.3",
46
46
  "create-hash": "^1.2.0",
47
- "js-yaml": "^4.0",
48
47
  "lit-element": "2.4.0",
49
48
  "lit-html": "^1.1.1",
50
49
  "lodash.clonedeep": "^4.5.0",
51
50
  "marked": "^4.0.16",
52
- "mime-types": "^2.1.32",
51
+ "mime-db": "^1.52.0",
53
52
  "openapi-data-validator": "^2.0.40",
54
- "path-browserify": "^1.0.1",
53
+ "openapi-resolver": "^4.0.17",
55
54
  "prismjs": "^1.23.0",
56
55
  "regex-to-strings": "^2.0.3",
57
- "swagger-client": "^3.13",
58
56
  "xml-but-prettier": "^1.0.1"
59
57
  },
60
58
  "scripts": {
@@ -93,10 +91,12 @@
93
91
  "fs-extra": "^8.1.0",
94
92
  "glob": "^7.1.6",
95
93
  "html-webpack-plugin": "^5.3.1",
94
+ "https-browserify": "^1.0.0",
96
95
  "inspectpack": "^4.7.1",
97
96
  "mocha": "^7.2.0",
98
97
  "sinon": "^7.5.0",
99
98
  "sinon-chai": "^3.3.0",
99
+ "stream-http": "^3.2.0",
100
100
  "style-loader": "^2.0.0",
101
101
  "terser-webpack-plugin": "^5.1.1",
102
102
  "webpack": "^5.30.0",
@@ -1,7 +1,7 @@
1
1
  import { LitElement, html } from 'lit-element';
2
2
  import { marked } from 'marked';
3
3
  import Prism from 'prismjs';
4
- import mime from 'mime-types';
4
+ import mimeTypeResolver from './mime-types';
5
5
 
6
6
  import { unsafeHTML } from 'lit-html/directives/unsafe-html';
7
7
  import formatXml from 'xml-but-prettier';
@@ -1103,7 +1103,7 @@ export default class ApiRequest extends LitElement {
1103
1103
  const contentDisposition = fetchResponse.headers.get('content-disposition');
1104
1104
  const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
1105
1105
  const filename = filenameRegex.exec(contentDisposition);
1106
- this.respContentDisposition = filename && filename[1] && filename[1].replace(/['"]/g, '') || `download.${mime.extension(contentType) || 'file'}`;
1106
+ this.respContentDisposition = filename && filename[1] && filename[1].replace(/['"]/g, '') || `download.${mimeTypeResolver.extension(contentType) || 'file'}`;
1107
1107
  respBlob = await fetchResponse.blob();
1108
1108
  this.responseBlobUrl = URL.createObjectURL(respBlob);
1109
1109
  }
@@ -0,0 +1,67 @@
1
+ const db = require('mime-db');
2
+
3
+ const EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/;
4
+ /**
5
+ * Get the default extension for a MIME type.
6
+ *
7
+ * @param {string} type
8
+ * @return {boolean|string}
9
+ */
10
+
11
+ export default function extension(type) {
12
+ if (!type || typeof type !== 'string') {
13
+ return false;
14
+ }
15
+
16
+ // TODO: use media-typer
17
+ const match = EXTRACT_TYPE_REGEXP.exec(type);
18
+
19
+ // get extensions
20
+ const exts = match && exports.extensions[match[1].toLowerCase()];
21
+
22
+ if (!exts || !exts.length) {
23
+ return false;
24
+ }
25
+
26
+ return exts[0];
27
+ }
28
+
29
+ const extensions = {};
30
+ const types = {};
31
+ populateMaps();
32
+
33
+ function populateMaps() {
34
+ // source preference (least -> most)
35
+ const preference = ['nginx', 'apache', undefined, 'iana'];
36
+
37
+ Object.keys(db).forEach(function forEachMimeType(type) {
38
+ const mime = db[type];
39
+ const exts = mime.extensions;
40
+
41
+ if (!exts || !exts.length) {
42
+ return;
43
+ }
44
+
45
+ // mime -> extensions
46
+ extensions[type] = exts;
47
+
48
+ // extension -> mime
49
+ for (let i = 0; i < exts.length; i++) {
50
+ const extensionToTest = exts[i];
51
+
52
+ if (types[extensionToTest]) {
53
+ const from = preference.indexOf(db[types[extensionToTest]].source);
54
+ const to = preference.indexOf(mime.source);
55
+
56
+ if (types[extensionToTest] !== 'application/octet-stream'
57
+ && (from > to || (from === to && types[extensionToTest].substr(0, 12) === 'application/'))) {
58
+ // skip the remapping
59
+ continue;
60
+ }
61
+ }
62
+
63
+ // set the extension -> mime
64
+ types[extensionToTest] = type;
65
+ }
66
+ });
67
+ }
@@ -74,7 +74,6 @@ export default class OpenApiExplorer extends LitElement {
74
74
  serverUrl: { type: String, attribute: 'server-url' },
75
75
 
76
76
  // Hide/Show Sections & Enable Disable actions
77
- showSideNav: { type: String, attribute: 'show-side-nav' },
78
77
  showInfo: { type: String, attribute: 'show-info' },
79
78
  allowAuthentication: { type: String, attribute: 'show-authentication' },
80
79
  allowTry: { type: String, attribute: 'enable-console' },
@@ -392,7 +391,6 @@ export default class OpenApiExplorer extends LitElement {
392
391
  if (!this.allowServerSelection || !'true, false,'.includes(`${this.allowServerSelection},`)) { this.allowServerSelection = 'true'; }
393
392
  if (!this.allowAuthentication || !'true, false,'.includes(`${this.allowAuthentication},`)) { this.allowAuthentication = 'true'; }
394
393
 
395
- if (!this.showSideNav || !'true false'.includes(this.showSideNav)) { this.showSideNav = 'true'; }
396
394
  if (!this.showComponents || !'true false'.includes(this.showComponents)) { this.showComponents = 'false'; }
397
395
  if (!this.fetchCredentials || !'omit, same-origin, include,'.includes(`${this.fetchCredentials},`)) { this.fetchCredentials = ''; }
398
396
 
@@ -33,10 +33,7 @@ export default function responsiveViewMainBodyTemplate() {
33
33
 
34
34
  <div id='the-main-body' class="body">
35
35
  <!-- Side Nav -->
36
- ${((this.renderStyle === 'read' || this.renderStyle === 'focused')
37
- && this.showSideNav === 'true'
38
- && this.resolvedSpec
39
- ) ? navbarTemplate.call(this) : ''
36
+ ${(this.renderStyle === 'focused' && this.resolvedSpec) ? navbarTemplate.call(this) : ''
40
37
  }
41
38
 
42
39
  <!-- Main Content -->
@@ -1,30 +1,20 @@
1
- import SwaggerClient from 'swagger-client';
1
+ import OpenApiResolver from 'openapi-resolver/dist/openapi-resolver.browser';
2
2
  import { marked } from 'marked';
3
- import yaml from 'js-yaml';
4
3
  import { invalidCharsRegEx } from './common-utils';
5
4
 
6
5
  export default async function ProcessSpec(specUrlOrObject, serverUrl = '') {
7
6
  const inputSpecIsAUrl = typeof specUrlOrObject === 'string' && specUrlOrObject.match(/^http/) || typeof specUrlOrObject === 'object' && typeof specUrlOrObject.href === 'string';
8
- let specMeta;
9
7
 
10
- // Dynamically resolve non yaml or json files and insert their descriptions where necessary
11
- function responseInterceptor(val) {
12
- if (val.ok && val.text && val.parseError && val.parseError.name === 'YAMLException' && (!val.headers['content-type'] || val.headers['content-type'].match('text/plain'))) {
13
- val.body = val.text;
14
- }
15
- return val;
16
- }
17
-
18
- if (inputSpecIsAUrl) {
19
- specMeta = await SwaggerClient({ allowMetaPatches: false, url: specUrlOrObject.toString(), responseInterceptor });
20
- } else if (typeof specUrlOrObject === 'string') {
21
- specMeta = await SwaggerClient({ allowMetaPatches: false, spec: yaml.load(specUrlOrObject), responseInterceptor });
22
- } else {
23
- specMeta = await SwaggerClient({ allowMetaPatches: false, spec: specUrlOrObject, responseInterceptor });
8
+ let jsonParsedSpec;
9
+ try {
10
+ jsonParsedSpec = await OpenApiResolver(specUrlOrObject);
11
+ } catch (error) {
12
+ // eslint-disable-next-line no-console
13
+ console.error('Error parsing specification', error);
14
+ throw Error('SpecificationNotFound');
24
15
  }
25
16
 
26
- const jsonParsedSpec = specMeta.spec;
27
- if (specMeta.message === 'Not Found' || !jsonParsedSpec) {
17
+ if (!jsonParsedSpec) {
28
18
  throw Error('SpecificationNotFound');
29
19
  }
30
20
 
@@ -233,7 +223,7 @@ function groupByTags(openApiSpec) {
233
223
  if (pathsAndWebhooks[pathOrHookName][methodName]) {
234
224
  const pathOrHookObj = openApiSpec.paths[pathOrHookName][methodName];
235
225
  // If path.methods are tagged, else generate it from path
236
- const pathTags = pathOrHookObj.tags || [];
226
+ const pathTags = Array.isArray(pathOrHookObj.tags) ? pathOrHookObj.tags : pathOrHookObj.tags && [pathOrHookObj.tags] || [];
237
227
  if (pathTags.length === 0) {
238
228
  pathTags.push('General ⦂');
239
229
  }
@@ -18,7 +18,7 @@ function escapeForXML(string) {
18
18
 
19
19
  const DEFAULT_INDENT = ' ';
20
20
 
21
- function xml(input, rawOptions) {
21
+ export default function xml(input, rawOptions) {
22
22
  let options = rawOptions;
23
23
  if (typeof options !== 'object') {
24
24
  options = {
@@ -80,32 +80,6 @@ function xml(input, rawOptions) {
80
80
  return output;
81
81
  }
82
82
 
83
- function element(/* input, …*/) {
84
- const input = Array.prototype.slice.call(arguments);
85
- const self = {
86
- _elem: resolve(input)
87
- };
88
-
89
- self.push = function(pushInput) {
90
- if (!this.append) {
91
- throw new Error('not assigned to a parent!');
92
- }
93
- const that = this;
94
- const indent = this._elem.indent;
95
- format(this.append, resolve(
96
- pushInput, indent, this._elem.icount + (indent ? 1 : 0)),
97
- function() { that.append(true); });
98
- };
99
-
100
- self.close = function(closeInput) {
101
- if (closeInput !== undefined) {
102
- this.push(closeInput);
103
- }
104
- };
105
-
106
- return self;
107
- }
108
-
109
83
  function create_indent(character, count) {
110
84
  return (new Array(count || 0).join(character || ''));
111
85
  }
@@ -254,5 +228,3 @@ function attribute(key, value) {
254
228
  return `${key}=` + `"${escapeForXML(value)}"`;
255
229
  }
256
230
 
257
- module.exports = xml;
258
- module.exports.element = module.exports.Element = element;