docusaurus-plugin-openapi-docs 1.1.8 → 1.1.11

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.
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ /* ============================================================================
3
+ * Copyright (c) Palo Alto Networks
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ * ========================================================================== */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.sampleResponseFromSchema = void 0;
13
+ const chalk_1 = __importDefault(require("chalk"));
14
+ const createResponseSchema_1 = require("../markdown/createResponseSchema");
15
+ const primitives = {
16
+ string: {
17
+ default: () => "string",
18
+ email: () => "user@example.com",
19
+ date: () => new Date().toISOString().substring(0, 10),
20
+ "date-time": () => new Date().toISOString().substring(0, 10),
21
+ uuid: () => "3fa85f64-5717-4562-b3fc-2c963f66afa6",
22
+ hostname: () => "example.com",
23
+ ipv4: () => "198.51.100.42",
24
+ ipv6: () => "2001:0db8:5b96:0000:0000:426f:8e17:642a",
25
+ },
26
+ number: {
27
+ default: () => 0,
28
+ float: () => 0.0,
29
+ },
30
+ integer: {
31
+ default: () => 0,
32
+ },
33
+ boolean: {
34
+ default: (schema) => typeof schema.default === "boolean" ? schema.default : true,
35
+ },
36
+ object: {},
37
+ array: {},
38
+ };
39
+ function sampleResponseFromProp(name, prop, obj) {
40
+ // Handle resolved circular props
41
+ if (typeof prop === "object" && Object.keys(prop).length === 0) {
42
+ obj[name] = prop;
43
+ return obj;
44
+ }
45
+ // TODO: handle discriminators
46
+ if (prop.oneOf) {
47
+ obj[name] = (0, exports.sampleResponseFromSchema)(prop.oneOf[0]);
48
+ }
49
+ else if (prop.anyOf) {
50
+ obj[name] = (0, exports.sampleResponseFromSchema)(prop.anyOf[0]);
51
+ }
52
+ else if (prop.allOf) {
53
+ const { mergedSchemas } = (0, createResponseSchema_1.mergeAllOf)(prop.allOf);
54
+ sampleResponseFromProp(name, mergedSchemas, obj);
55
+ }
56
+ else {
57
+ obj[name] = (0, exports.sampleResponseFromSchema)(prop);
58
+ }
59
+ return obj;
60
+ }
61
+ const sampleResponseFromSchema = (schema = {}) => {
62
+ try {
63
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
64
+ let { type, example, allOf, oneOf, anyOf, properties, items } = schema;
65
+ // TODO: determine if we should always ignore the example when creating from schema
66
+ // if (example !== undefined) {
67
+ // return example;
68
+ // }
69
+ if (allOf) {
70
+ const { mergedSchemas } = (0, createResponseSchema_1.mergeAllOf)(allOf);
71
+ if (mergedSchemas.properties) {
72
+ for (const [key, value] of Object.entries(mergedSchemas.properties)) {
73
+ if (value.writeOnly && value.writeOnly === true) {
74
+ delete mergedSchemas.properties[key];
75
+ }
76
+ }
77
+ }
78
+ return (0, exports.sampleResponseFromSchema)(mergedSchemas);
79
+ }
80
+ if (oneOf) {
81
+ // Just go with first schema
82
+ return (0, exports.sampleResponseFromSchema)(oneOf[0]);
83
+ }
84
+ if (anyOf) {
85
+ // Just go with first schema
86
+ return (0, exports.sampleResponseFromSchema)(anyOf[0]);
87
+ }
88
+ if (!type) {
89
+ if (properties) {
90
+ type = "object";
91
+ }
92
+ else if (items) {
93
+ type = "array";
94
+ }
95
+ else {
96
+ return;
97
+ }
98
+ }
99
+ if (type === "object") {
100
+ let obj = {};
101
+ for (let [name, prop] of Object.entries(properties !== null && properties !== void 0 ? properties : {})) {
102
+ if (prop.properties) {
103
+ for (const [key, value] of Object.entries(prop.properties)) {
104
+ if (value.writeOnly && value.writeOnly === true) {
105
+ delete prop.properties[key];
106
+ }
107
+ }
108
+ }
109
+ if (prop.items && prop.items.properties) {
110
+ for (const [key, value] of Object.entries(prop.items.properties)) {
111
+ if (value.writeOnly && value.writeOnly === true) {
112
+ delete prop.items.properties[key];
113
+ }
114
+ }
115
+ }
116
+ if (prop.deprecated) {
117
+ continue;
118
+ }
119
+ // Resolve schema from prop recursively
120
+ obj = sampleResponseFromProp(name, prop, obj);
121
+ }
122
+ return obj;
123
+ }
124
+ if (type === "array") {
125
+ if (Array.isArray(items === null || items === void 0 ? void 0 : items.anyOf)) {
126
+ return items === null || items === void 0 ? void 0 : items.anyOf.map((item) => (0, exports.sampleResponseFromSchema)(item));
127
+ }
128
+ if (Array.isArray(items === null || items === void 0 ? void 0 : items.oneOf)) {
129
+ return items === null || items === void 0 ? void 0 : items.oneOf.map((item) => (0, exports.sampleResponseFromSchema)(item));
130
+ }
131
+ return [(0, exports.sampleResponseFromSchema)(items)];
132
+ }
133
+ if (schema.enum) {
134
+ if (schema.default) {
135
+ return schema.default;
136
+ }
137
+ return normalizeArray(schema.enum)[0];
138
+ }
139
+ if (schema.writeOnly && schema.writeOnly === true) {
140
+ return undefined;
141
+ }
142
+ return primitive(schema);
143
+ }
144
+ catch (err) {
145
+ console.error(chalk_1.default.yellow("WARNING: failed to create example from schema object:", err));
146
+ return;
147
+ }
148
+ };
149
+ exports.sampleResponseFromSchema = sampleResponseFromSchema;
150
+ function primitive(schema = {}) {
151
+ let { type, format } = schema;
152
+ if (type === undefined) {
153
+ return;
154
+ }
155
+ let fn = schema.default ? () => schema.default : primitives[type].default;
156
+ if (format !== undefined) {
157
+ fn = primitives[type][format] || fn;
158
+ }
159
+ if (fn) {
160
+ return fn(schema);
161
+ }
162
+ return "Unknown Type: " + schema.type;
163
+ }
164
+ function normalizeArray(arr) {
165
+ if (Array.isArray(arr)) {
166
+ return arr;
167
+ }
168
+ return [arr];
169
+ }
@@ -19,7 +19,7 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
19
19
  const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
20
20
  const kebabCase_1 = __importDefault(require("lodash/kebabCase"));
21
21
  const index_1 = require("../index");
22
- const createExample_1 = require("./createExample");
22
+ const createRequestExample_1 = require("./createRequestExample");
23
23
  const loadAndResolveSpec_1 = require("./utils/loadAndResolveSpec");
24
24
  /**
25
25
  * Convenience function for converting raw JSON to a Postman Collection object.
@@ -134,7 +134,7 @@ function createItems(openapiData, sidebarOptions) {
134
134
  let jsonRequestBodyExample;
135
135
  const body = (_o = (_m = operationObject.requestBody) === null || _m === void 0 ? void 0 : _m.content) === null || _o === void 0 ? void 0 : _o["application/json"];
136
136
  if (body === null || body === void 0 ? void 0 : body.schema) {
137
- jsonRequestBodyExample = (0, createExample_1.sampleFromSchema)(body.schema);
137
+ jsonRequestBodyExample = (0, createRequestExample_1.sampleRequestFromSchema)(body.schema);
138
138
  }
139
139
  // Handle vendor JSON media types
140
140
  const bodyContent = (_p = operationObject.requestBody) === null || _p === void 0 ? void 0 : _p.content;
@@ -143,7 +143,7 @@ function createItems(openapiData, sidebarOptions) {
143
143
  if (firstBodyContentKey.endsWith("+json")) {
144
144
  const firstBody = bodyContent[firstBodyContentKey];
145
145
  if (firstBody === null || firstBody === void 0 ? void 0 : firstBody.schema) {
146
- jsonRequestBodyExample = (0, createExample_1.sampleFromSchema)(firstBody.schema);
146
+ jsonRequestBodyExample = (0, createRequestExample_1.sampleRequestFromSchema)(firstBody.schema);
147
147
  }
148
148
  }
149
149
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "docusaurus-plugin-openapi-docs",
3
3
  "description": "OpenAPI plugin for Docusaurus.",
4
- "version": "1.1.8",
4
+ "version": "1.1.11",
5
5
  "license": "MIT",
6
6
  "keywords": [
7
7
  "openapi",
@@ -59,7 +59,8 @@
59
59
  "slugify": "^1.6.5",
60
60
  "swagger2openapi": "^7.0.8",
61
61
  "url-template": "^3.0.0",
62
- "webpack": "^5.61.0"
62
+ "webpack": "^5.61.0",
63
+ "xml-formatter": "^2.6.1"
63
64
  },
64
65
  "peerDependencies": {
65
66
  "react": "^16.8.4 || ^17.0.0"
@@ -67,5 +68,5 @@
67
68
  "engines": {
68
69
  "node": ">=14"
69
70
  },
70
- "gitHead": "619aa16c52e6de8fd752ff583681b0da093b679c"
71
+ "gitHead": "329709c2d588d2a689a2f84d392b5cc11d6cdd02"
71
72
  }
package/src/index.ts CHANGED
@@ -23,41 +23,51 @@ export function isURL(str: string): boolean {
23
23
  return /^(https?:)\/\//m.test(str);
24
24
  }
25
25
 
26
- export function getDocsData(
27
- dataArray: any[],
28
- filter: string
26
+ export function getDocsPluginConfig(
27
+ presetsPlugins: any[],
28
+ pluginId: string
29
29
  ): Object | undefined {
30
30
  // eslint-disable-next-line array-callback-return
31
- const filteredData = dataArray.filter((data) => {
32
- if (data[0] === filter) {
31
+ const filteredConfig = presetsPlugins.filter((data) => {
32
+ if (data[0] === pluginId) {
33
33
  return data[1];
34
34
  }
35
35
 
36
36
  // Search plugin-content-docs instances
37
37
  if (data[0] === "@docusaurus/plugin-content-docs") {
38
- const pluginId = data[1].id ? data[1].id : "default";
39
- if (pluginId === filter) {
38
+ const configPluginId = data[1].id ? data[1].id : "default";
39
+ if (configPluginId === pluginId) {
40
40
  return data[1];
41
41
  }
42
42
  }
43
43
  })[0];
44
- if (filteredData) {
44
+ if (filteredConfig) {
45
45
  // Search presets, e.g. "classic"
46
- if (filteredData[0] === filter) {
47
- return filteredData[1].docs;
46
+ if (filteredConfig[0] === pluginId) {
47
+ return filteredConfig[1].docs;
48
48
  }
49
49
 
50
50
  // Search plugin-content-docs instances
51
- if (filteredData[0] === "@docusaurus/plugin-content-docs") {
52
- const pluginId = filteredData[1].id ? filteredData[1].id : "default";
53
- if (pluginId === filter) {
54
- return filteredData[1];
51
+ if (filteredConfig[0] === "@docusaurus/plugin-content-docs") {
52
+ const configPluginId = filteredConfig[1].id
53
+ ? filteredConfig[1].id
54
+ : "default";
55
+ if (configPluginId === pluginId) {
56
+ return filteredConfig[1];
55
57
  }
56
58
  }
57
59
  }
58
60
  return;
59
61
  }
60
62
 
63
+ function getPluginConfig(plugins: any[], pluginId: string): any {
64
+ return plugins.filter((data) => data[1].id === pluginId)[0][1];
65
+ }
66
+
67
+ function getPluginInstances(plugins: any[]): any {
68
+ return plugins.filter((data) => data[0] === "docusaurus-plugin-openapi-docs");
69
+ }
70
+
61
71
  export default function pluginOpenAPIDocs(
62
72
  context: LoadContext,
63
73
  options: PluginOptions
@@ -69,7 +79,7 @@ export default function pluginOpenAPIDocs(
69
79
  const presets: any = siteConfig.presets;
70
80
  const plugins: any = siteConfig.plugins;
71
81
  const presetsPlugins = presets.concat(plugins);
72
- const docData: any = getDocsData(presetsPlugins, docsPluginId);
82
+ const docData: any = getDocsPluginConfig(presetsPlugins, docsPluginId);
73
83
  const docRouteBasePath = docData ? docData.routeBasePath : undefined;
74
84
  const docPath = docData ? (docData.path ? docData.path : "docs") : undefined;
75
85
 
@@ -108,9 +118,7 @@ export default function pluginOpenAPIDocs(
108
118
  docPath
109
119
  );
110
120
 
111
- const sidebarSliceTemplate = template
112
- ? fs.readFileSync(template).toString()
113
- : `module.exports = {{{slice}}};`;
121
+ const sidebarSliceTemplate = `module.exports = {{{slice}}};`;
114
122
 
115
123
  const view = render(sidebarSliceTemplate, {
116
124
  slice: JSON.stringify(sidebarSlice),
@@ -162,12 +170,11 @@ info_path: {{{infoPath}}}
162
170
  {{{markdown}}}
163
171
  `;
164
172
 
165
- const infoMdTemplate = template
166
- ? fs.readFileSync(template).toString()
167
- : `---
173
+ const infoMdTemplate = `---
168
174
  id: {{{id}}}
169
175
  sidebar_label: {{{title}}}
170
176
  hide_title: true
177
+ custom_edit_url: null
171
178
  ---
172
179
 
173
180
  {{{markdown}}}
@@ -180,12 +187,11 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
180
187
  \`\`\`
181
188
  `;
182
189
 
183
- const tagMdTemplate = template
184
- ? fs.readFileSync(template).toString()
185
- : `---
190
+ const tagMdTemplate = `---
186
191
  id: {{{id}}}
187
192
  title: {{{description}}}
188
193
  description: {{{description}}}
194
+ custom_edit_url: null
189
195
  ---
190
196
 
191
197
  {{{markdown}}}
@@ -392,25 +398,52 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
392
398
  )
393
399
  .usage("<id>")
394
400
  .arguments("<id>")
395
- .action(async (id) => {
401
+ .option("-p, --plugin-id <plugin>", "OpenAPI docs plugin ID.")
402
+ .action(async (id, instance) => {
403
+ const options = instance.opts();
404
+ const pluginId = options.pluginId;
405
+ const pluginInstances = getPluginInstances(plugins);
406
+ let targetConfig: any;
407
+ if (pluginId) {
408
+ try {
409
+ const pluginConfig = getPluginConfig(plugins, pluginId);
410
+ targetConfig = pluginConfig.config ?? {};
411
+ } catch {
412
+ console.error(
413
+ chalk.red(`OpenAPI docs plugin ID '${pluginId}' not found.`)
414
+ );
415
+ return;
416
+ }
417
+ } else {
418
+ if (pluginInstances.length > 1) {
419
+ console.error(
420
+ chalk.red(
421
+ "OpenAPI docs plugin ID must be specified when more than one plugin instance exists."
422
+ )
423
+ );
424
+ return;
425
+ }
426
+ targetConfig = config;
427
+ }
428
+
396
429
  if (id === "all") {
397
- if (config[id]) {
430
+ if (targetConfig[id]) {
398
431
  console.error(
399
432
  chalk.red(
400
433
  "Can't use id 'all' for OpenAPI docs configuration key."
401
434
  )
402
435
  );
403
436
  } else {
404
- Object.keys(config).forEach(async function (key) {
405
- await generateApiDocs(config[key]);
437
+ Object.keys(targetConfig).forEach(async function (key) {
438
+ await generateApiDocs(targetConfig[key]);
406
439
  });
407
440
  }
408
- } else if (!config[id]) {
441
+ } else if (!targetConfig[id]) {
409
442
  console.error(
410
443
  chalk.red(`ID '${id}' does not exist in OpenAPI docs config.`)
411
444
  );
412
445
  } else {
413
- await generateApiDocs(config[id]);
446
+ await generateApiDocs(targetConfig[id]);
414
447
  }
415
448
  });
416
449
 
@@ -421,9 +454,35 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
421
454
  )
422
455
  .usage("<id:version>")
423
456
  .arguments("<id:version>")
424
- .action(async (id) => {
457
+ .option("-p, --plugin-id <plugin>", "OpenAPI docs plugin ID.")
458
+ .action(async (id, instance) => {
459
+ const options = instance.opts();
460
+ const pluginId = options.pluginId;
461
+ const pluginInstances = getPluginInstances(plugins);
462
+ let targetConfig: any;
463
+ if (pluginId) {
464
+ try {
465
+ const pluginConfig = getPluginConfig(plugins, pluginId);
466
+ targetConfig = pluginConfig.config ?? {};
467
+ } catch {
468
+ console.error(
469
+ chalk.red(`OpenAPI docs plugin ID '${pluginId}' not found.`)
470
+ );
471
+ return;
472
+ }
473
+ } else {
474
+ if (pluginInstances.length > 1) {
475
+ console.error(
476
+ chalk.red(
477
+ "OpenAPI docs plugin ID must be specified when more than one plugin instance exists."
478
+ )
479
+ );
480
+ return;
481
+ }
482
+ targetConfig = config;
483
+ }
425
484
  const [parentId, versionId] = id.split(":");
426
- const parentConfig = Object.assign({}, config[parentId]);
485
+ const parentConfig = Object.assign({}, targetConfig[parentId]);
427
486
 
428
487
  const version = parentConfig.version as string;
429
488
  const label = parentConfig.label as string;
@@ -432,7 +491,7 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
432
491
  let parentVersion = {} as any;
433
492
  parentVersion[version] = { label: label, baseUrl: baseUrl };
434
493
 
435
- const { versions } = config[parentId] as any;
494
+ const { versions } = targetConfig[parentId] as any;
436
495
  const mergedVersions = Object.assign(parentVersion, versions);
437
496
 
438
497
  // Prepare for merge
@@ -484,21 +543,47 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
484
543
  )
485
544
  .usage("<id>")
486
545
  .arguments("<id>")
487
- .action(async (id) => {
546
+ .option("-p, --plugin-id <plugin>", "OpenAPI docs plugin ID.")
547
+ .action(async (id, instance) => {
548
+ const options = instance.opts();
549
+ const pluginId = options.pluginId;
550
+ const pluginInstances = getPluginInstances(plugins);
551
+ let targetConfig: any;
552
+ if (pluginId) {
553
+ try {
554
+ const pluginConfig = getPluginConfig(plugins, pluginId);
555
+ targetConfig = pluginConfig.config ?? {};
556
+ } catch {
557
+ console.error(
558
+ chalk.red(`OpenAPI docs plugin ID '${pluginId}' not found.`)
559
+ );
560
+ return;
561
+ }
562
+ } else {
563
+ if (pluginInstances.length > 1) {
564
+ console.error(
565
+ chalk.red(
566
+ "OpenAPI docs plugin ID must be specified when more than one plugin instance exists."
567
+ )
568
+ );
569
+ return;
570
+ }
571
+ targetConfig = config;
572
+ }
488
573
  if (id === "all") {
489
- if (config[id]) {
574
+ if (targetConfig[id]) {
490
575
  console.error(
491
576
  chalk.red(
492
577
  "Can't use id 'all' for OpenAPI docs configuration key."
493
578
  )
494
579
  );
495
580
  } else {
496
- Object.keys(config).forEach(async function (key) {
497
- await cleanApiDocs(config[key]);
581
+ Object.keys(targetConfig).forEach(async function (key) {
582
+ await cleanApiDocs(targetConfig[key]);
498
583
  });
499
584
  }
500
585
  } else {
501
- await cleanApiDocs(config[id]);
586
+ await cleanApiDocs(targetConfig[id]);
502
587
  }
503
588
  });
504
589
 
@@ -509,11 +594,37 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
509
594
  )
510
595
  .usage("<id:version>")
511
596
  .arguments("<id:version>")
512
- .action(async (id) => {
597
+ .option("-p, --plugin-id <plugin>", "OpenAPI docs plugin ID.")
598
+ .action(async (id, instance) => {
599
+ const options = instance.opts();
600
+ const pluginId = options.pluginId;
601
+ const pluginInstances = getPluginInstances(plugins);
602
+ let targetConfig: any;
603
+ if (pluginId) {
604
+ try {
605
+ const pluginConfig = getPluginConfig(plugins, pluginId);
606
+ targetConfig = pluginConfig.config ?? {};
607
+ } catch {
608
+ console.error(
609
+ chalk.red(`OpenAPI docs plugin ID '${pluginId}' not found.`)
610
+ );
611
+ return;
612
+ }
613
+ } else {
614
+ if (pluginInstances.length > 1) {
615
+ console.error(
616
+ chalk.red(
617
+ "OpenAPI docs plugin ID must be specified when more than one plugin instance exists."
618
+ )
619
+ );
620
+ return;
621
+ }
622
+ targetConfig = config;
623
+ }
513
624
  const [parentId, versionId] = id.split(":");
514
- const { versions } = config[parentId] as any;
625
+ const { versions } = targetConfig[parentId] as any;
515
626
 
516
- const parentConfig = Object.assign({}, config[parentId]);
627
+ const parentConfig = Object.assign({}, targetConfig[parentId]);
517
628
  delete parentConfig.versions;
518
629
 
519
630
  if (versionId === "all") {