docusaurus-plugin-openapi-docs 2.1.3 → 2.2.1

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.
@@ -12,14 +12,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.getTagDisplayName = exports.processOpenapiFile = exports.processOpenapiFiles = exports.readOpenapiFiles = void 0;
13
13
  const path_1 = __importDefault(require("path"));
14
14
  const utils_1 = require("@docusaurus/utils");
15
- const openapi_to_postmanv2_1 = __importDefault(require("@paloaltonetworks/openapi-to-postmanv2"));
16
- const postman_collection_1 = __importDefault(require("@paloaltonetworks/postman-collection"));
17
15
  const chalk_1 = __importDefault(require("chalk"));
18
16
  const fs_extra_1 = __importDefault(require("fs-extra"));
19
17
  const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
20
18
  const kebabCase_1 = __importDefault(require("lodash/kebabCase"));
21
19
  const unionBy_1 = __importDefault(require("lodash/unionBy"));
22
20
  const uniq_1 = __importDefault(require("lodash/uniq"));
21
+ const openapi_to_postmanv2_1 = __importDefault(require("openapi-to-postmanv2"));
22
+ const postman_collection_1 = __importDefault(require("postman-collection"));
23
23
  const createRequestExample_1 = require("./createRequestExample");
24
24
  const loadAndResolveSpec_1 = require("./utils/loadAndResolveSpec");
25
25
  const index_1 = require("../index");
@@ -61,7 +61,7 @@ async function createPostmanCollection(openapiData) {
61
61
  return await jsonToCollection(data);
62
62
  }
63
63
  function createItems(openapiData, options, sidebarOptions) {
64
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4;
64
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6;
65
65
  // TODO: Find a better way to handle this
66
66
  let items = [];
67
67
  const infoIdSpaces = openapiData.info.title.replace(" ", "-").toLowerCase();
@@ -324,42 +324,47 @@ function createItems(openapiData, options, sidebarOptions) {
324
324
  items.push(apiPage);
325
325
  }
326
326
  }
327
- if ((options === null || options === void 0 ? void 0 : options.showSchemas) === true) {
327
+ if ((options === null || options === void 0 ? void 0 : options.showSchemas) === true ||
328
+ Object.entries((_1 = (_0 = openapiData === null || openapiData === void 0 ? void 0 : openapiData.components) === null || _0 === void 0 ? void 0 : _0.schemas) !== null && _1 !== void 0 ? _1 : {})
329
+ .flatMap(([_, s]) => s["x-tags"])
330
+ .filter((item) => !!item).length > 0) {
328
331
  // Gather schemas
329
- for (let [schema, schemaObject] of Object.entries((_1 = (_0 = openapiData === null || openapiData === void 0 ? void 0 : openapiData.components) === null || _0 === void 0 ? void 0 : _0.schemas) !== null && _1 !== void 0 ? _1 : {})) {
330
- const baseIdSpaces = (_3 = (_2 = schemaObject === null || schemaObject === void 0 ? void 0 : schemaObject.title) === null || _2 === void 0 ? void 0 : _2.replace(" ", "-").toLowerCase()) !== null && _3 !== void 0 ? _3 : "";
331
- const baseId = (0, kebabCase_1.default)(baseIdSpaces);
332
- const schemaDescription = schemaObject.description;
333
- let splitDescription;
334
- if (schemaDescription) {
335
- splitDescription = schemaDescription.match(/[^\r\n]+/g);
336
- }
337
- const schemaPage = {
338
- type: "schema",
339
- id: baseId,
340
- infoId: infoId !== null && infoId !== void 0 ? infoId : "",
341
- unversionedId: baseId,
342
- title: schemaObject.title
343
- ? schemaObject.title.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
344
- : schema,
345
- description: schemaObject.description
346
- ? schemaObject.description.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
347
- : "",
348
- frontMatter: {
349
- description: splitDescription
350
- ? splitDescription[0]
351
- .replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
352
- .replace(/\s+$/, "")
332
+ for (let [schema, schemaObject] of Object.entries((_3 = (_2 = openapiData === null || openapiData === void 0 ? void 0 : openapiData.components) === null || _2 === void 0 ? void 0 : _2.schemas) !== null && _3 !== void 0 ? _3 : {})) {
333
+ if ((options === null || options === void 0 ? void 0 : options.showSchemas) === true || schemaObject["x-tags"]) {
334
+ const baseIdSpaces = (_5 = (_4 = schemaObject === null || schemaObject === void 0 ? void 0 : schemaObject.title) === null || _4 === void 0 ? void 0 : _4.replace(" ", "-").toLowerCase()) !== null && _5 !== void 0 ? _5 : "";
335
+ const baseId = (0, kebabCase_1.default)(baseIdSpaces);
336
+ const schemaDescription = schemaObject.description;
337
+ let splitDescription;
338
+ if (schemaDescription) {
339
+ splitDescription = schemaDescription.match(/[^\r\n]+/g);
340
+ }
341
+ const schemaPage = {
342
+ type: "schema",
343
+ id: baseId,
344
+ infoId: infoId !== null && infoId !== void 0 ? infoId : "",
345
+ unversionedId: baseId,
346
+ title: schemaObject.title
347
+ ? schemaObject.title.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
348
+ : schema,
349
+ description: schemaObject.description
350
+ ? schemaObject.description.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
353
351
  : "",
354
- },
355
- schema: schemaObject,
356
- };
357
- items.push(schemaPage);
352
+ frontMatter: {
353
+ description: splitDescription
354
+ ? splitDescription[0]
355
+ .replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
356
+ .replace(/\s+$/, "")
357
+ : "",
358
+ },
359
+ schema: schemaObject,
360
+ };
361
+ items.push(schemaPage);
362
+ }
358
363
  }
359
364
  }
360
365
  if ((sidebarOptions === null || sidebarOptions === void 0 ? void 0 : sidebarOptions.categoryLinkSource) === "tag") {
361
366
  // Get global tags
362
- const tags = (_4 = openapiData.tags) !== null && _4 !== void 0 ? _4 : [];
367
+ const tags = (_6 = openapiData.tags) !== null && _6 !== void 0 ? _6 : [];
363
368
  // Get operation tags
364
369
  const apiItems = items.filter((item) => {
365
370
  return item.type === "api";
@@ -17,6 +17,7 @@ const _1 = require(".");
17
17
  describe("openapi", () => {
18
18
  describe("readOpenapiFiles", () => {
19
19
  it("readOpenapiFiles", async () => {
20
+ var _a, _b;
20
21
  const results = await (0, _1.readOpenapiFiles)((0, utils_1.posixPath)(path_1.default.join(__dirname, "__fixtures__/examples")));
21
22
  const categoryMeta = results.find((x) => x.source.endsWith("_category_.json"));
22
23
  expect(categoryMeta).toBeFalsy();
@@ -26,6 +27,7 @@ describe("openapi", () => {
26
27
  expect(yaml === null || yaml === void 0 ? void 0 : yaml.sourceDirName).toBe(".");
27
28
  expect(yaml === null || yaml === void 0 ? void 0 : yaml.data.tags).toBeDefined();
28
29
  expect(yaml === null || yaml === void 0 ? void 0 : yaml.data["x-tagGroups"]).toBeDefined();
30
+ expect((_b = (_a = yaml === null || yaml === void 0 ? void 0 : yaml.data.components) === null || _a === void 0 ? void 0 : _a.schemas) === null || _b === void 0 ? void 0 : _b.HelloString["x-tags"]).toBeDefined();
29
31
  });
30
32
  });
31
33
  });
@@ -278,6 +278,7 @@ export type SchemaObject = Omit<JSONSchema, "type" | "allOf" | "oneOf" | "anyOf"
278
278
  externalDocs?: ExternalDocumentationObject;
279
279
  example?: any;
280
280
  deprecated?: boolean;
281
+ "x-tags"?: string[];
281
282
  };
282
283
  export type SchemaObjectWithRef = Omit<JSONSchema, "type" | "allOf" | "oneOf" | "anyOf" | "not" | "items" | "properties" | "additionalProperties"> & {
283
284
  type?: "string" | "number" | "integer" | "boolean" | "object" | "array";
package/lib/options.js CHANGED
@@ -22,6 +22,7 @@ const markdownGenerators = utils_validation_1.Joi.object({
22
22
  });
23
23
  exports.OptionsSchema = utils_validation_1.Joi.object({
24
24
  id: utils_validation_1.Joi.string().required(),
25
+ docsPlugin: utils_validation_1.Joi.string(),
25
26
  docsPluginId: utils_validation_1.Joi.string().required(),
26
27
  config: utils_validation_1.Joi.object()
27
28
  .pattern(/^/, utils_validation_1.Joi.object({
@@ -35,6 +36,7 @@ exports.OptionsSchema = utils_validation_1.Joi.object({
35
36
  sidebarOptions: sidebarOptions,
36
37
  markdownGenerators: markdownGenerators,
37
38
  showSchemas: utils_validation_1.Joi.boolean(),
39
+ disableCompression: utils_validation_1.Joi.boolean(),
38
40
  version: utils_validation_1.Joi.string().when("versions", {
39
41
  is: utils_validation_1.Joi.exist(),
40
42
  then: utils_validation_1.Joi.required(),
@@ -52,6 +54,7 @@ exports.OptionsSchema = utils_validation_1.Joi.object({
52
54
  outputDir: utils_validation_1.Joi.string().required(),
53
55
  label: utils_validation_1.Joi.string().required(),
54
56
  baseUrl: utils_validation_1.Joi.string().required(),
57
+ downloadUrl: utils_validation_1.Joi.string(),
55
58
  })),
56
59
  }))
57
60
  .required(),
@@ -24,7 +24,7 @@ function isSchemaItem(item) {
24
24
  return item.type === "schema";
25
25
  }
26
26
  function groupByTags(items, sidebarOptions, options, tags, docPath) {
27
- let { outputDir, label } = options;
27
+ let { outputDir, label, showSchemas } = options;
28
28
  // Remove trailing slash before proceeding
29
29
  outputDir = outputDir.replace(/\/$/, "");
30
30
  const { sidebarCollapsed, sidebarCollapsible, customProps, categoryLinkSource, } = sidebarOptions;
@@ -43,16 +43,21 @@ function groupByTags(items, sidebarOptions, options, tags, docPath) {
43
43
  const operationTags = (0, uniq_1.default)(apiItems
44
44
  .flatMap((item) => item.api.tags)
45
45
  .filter((item) => !!item));
46
- // Combine globally defined tags with operation tags
47
- // Only include global tag if referenced in operation tags
46
+ const schemaTags = (0, uniq_1.default)(schemaItems
47
+ .flatMap((item) => item.schema["x-tags"])
48
+ .filter((item) => !!item));
49
+ // Combine globally defined tags with operation and schema tags
50
+ // Only include global tag if referenced in operation/schema tags
48
51
  let apiTags = [];
49
52
  tags.flat().forEach((tag) => {
50
53
  // Should we also check x-displayName?
51
- if (operationTags.includes(tag.name)) {
54
+ if (operationTags.includes(tag.name) || schemaTags.includes(tag.name)) {
52
55
  apiTags.push(tag.name);
53
56
  }
54
57
  });
55
- apiTags = (0, uniq_1.default)(apiTags.concat(operationTags));
58
+ if (sidebarOptions.groupPathsBy !== "tagGroup") {
59
+ apiTags = (0, uniq_1.default)(apiTags.concat(operationTags, schemaTags));
60
+ }
56
61
  const basePath = docPath
57
62
  ? outputDir.split(docPath)[1].replace(/^\/+/g, "")
58
63
  : outputDir.slice(outputDir.indexOf("/", 1)).replace(/^\/+/g, "");
@@ -68,7 +73,7 @@ function groupByTags(items, sidebarOptions, options, tags, docPath) {
68
73
  }, item.api.method)
69
74
  : (0, clsx_1.default)({
70
75
  "menu__list-item--deprecated": item.schema.deprecated,
71
- });
76
+ }, "schema");
72
77
  return {
73
78
  type: "doc",
74
79
  id: basePath === "" || undefined ? `${id}` : `${basePath}/${id}`,
@@ -126,15 +131,15 @@ function groupByTags(items, sidebarOptions, options, tags, docPath) {
126
131
  : (0, utils_1.posixPath)(path_1.default.join("/category", basePath, (0, lodash_1.kebabCase)(tag))),
127
132
  };
128
133
  }
134
+ const taggedApiItems = apiItems.filter((item) => { var _a; return !!((_a = item.api.tags) === null || _a === void 0 ? void 0 : _a.includes(tag)); });
135
+ const taggedSchemaItems = schemaItems.filter((item) => { var _a; return !!((_a = item.schema["x-tags"]) === null || _a === void 0 ? void 0 : _a.includes(tag)); });
129
136
  return {
130
137
  type: "category",
131
138
  label: (_a = tagObject === null || tagObject === void 0 ? void 0 : tagObject["x-displayName"]) !== null && _a !== void 0 ? _a : tag,
132
139
  link: linkConfig,
133
140
  collapsible: sidebarCollapsible,
134
141
  collapsed: sidebarCollapsed,
135
- items: apiItems
136
- .filter((item) => { var _a; return !!((_a = item.api.tags) === null || _a === void 0 ? void 0 : _a.includes(tag)); })
137
- .map(createDocItem),
142
+ items: [...taggedSchemaItems, ...taggedApiItems].map(createDocItem),
138
143
  };
139
144
  })
140
145
  .filter((item) => item.items.length > 0); // Filter out any categories with no items.
@@ -157,14 +162,16 @@ function groupByTags(items, sidebarOptions, options, tags, docPath) {
157
162
  ];
158
163
  }
159
164
  let schemas = [];
160
- if (schemaItems.length > 0) {
165
+ if (showSchemas && schemaItems.length > 0) {
161
166
  schemas = [
162
167
  {
163
168
  type: "category",
164
169
  label: "Schemas",
165
170
  collapsible: sidebarCollapsible,
166
171
  collapsed: sidebarCollapsed,
167
- items: schemaItems.map(createDocItem),
172
+ items: schemaItems
173
+ .filter(({ schema }) => !schema["x-tags"])
174
+ .map(createDocItem),
168
175
  },
169
176
  ];
170
177
  }
@@ -178,7 +185,9 @@ function groupByTags(items, sidebarOptions, options, tags, docPath) {
178
185
  function generateSidebarSlice(sidebarOptions, options, api, tags, docPath, tagGroups) {
179
186
  let sidebarSlice = [];
180
187
  if (sidebarOptions.groupPathsBy === "tagGroup") {
188
+ let schemasGroup = [];
181
189
  tagGroups === null || tagGroups === void 0 ? void 0 : tagGroups.forEach((tagGroup) => {
190
+ var _a;
182
191
  //filter tags only included in group
183
192
  const filteredTags = [];
184
193
  tags[0].forEach((tag) => {
@@ -193,8 +202,18 @@ function generateSidebarSlice(sidebarOptions, options, api, tags, docPath, tagGr
193
202
  collapsed: true,
194
203
  items: groupByTags(api, sidebarOptions, options, [filteredTags], docPath),
195
204
  };
205
+ if (options.showSchemas) {
206
+ // For the first tagGroup, save the generated "Schemas" category for later.
207
+ if (schemasGroup.length === 0) {
208
+ schemasGroup = (_a = groupCategory.items) === null || _a === void 0 ? void 0 : _a.filter((item) => item.type === "category" && item.label === "Schemas");
209
+ }
210
+ // Remove the "Schemas" category from every `groupCategory`.
211
+ groupCategory.items = groupCategory.items.filter((item) => "label" in item ? item.label !== "Schemas" : true);
212
+ }
196
213
  sidebarSlice.push(groupCategory);
197
214
  });
215
+ // Add `schemasGroup` to the end of the sidebar.
216
+ sidebarSlice.push(...schemasGroup);
198
217
  }
199
218
  else if (sidebarOptions.groupPathsBy === "tag") {
200
219
  sidebarSlice = groupByTags(api, sidebarOptions, options, tags, docPath);
package/lib/types.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- import type Request from "@paloaltonetworks/postman-collection";
1
+ import type Request from "postman-collection";
2
2
  import { InfoObject, OperationObject, SchemaObject, SecuritySchemeObject, TagObject } from "./openapi/types";
3
3
  export type { PropSidebarItemCategory, SidebarItemLink, PropSidebar, PropSidebarItem, } from "@docusaurus/plugin-content-docs-types";
4
4
  export interface PluginOptions {
5
5
  id?: string;
6
+ docsPlugin?: string;
6
7
  docsPluginId: string;
7
8
  config: {
8
9
  [key: string]: APIOptions;
@@ -25,6 +26,7 @@ export interface APIOptions {
25
26
  proxy?: string;
26
27
  markdownGenerators?: MarkdownGenerator;
27
28
  showSchemas?: boolean;
29
+ disableCompression?: boolean;
28
30
  }
29
31
  export interface MarkdownGenerator {
30
32
  createApiPageMD?: (pageData: ApiPageMetadata) => string;
@@ -46,6 +48,7 @@ export interface APIVersionOptions {
46
48
  outputDir: string;
47
49
  label: string;
48
50
  baseUrl: string;
51
+ downloadUrl?: string;
49
52
  }
50
53
  export interface LoadedContent {
51
54
  loadedApi: ApiMetadata[];
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": "2.1.3",
4
+ "version": "2.2.1",
5
5
  "license": "MIT",
6
6
  "keywords": [
7
7
  "openapi",
@@ -40,8 +40,6 @@
40
40
  "@docusaurus/plugin-content-docs": ">=2.4.1 <=2.4.3",
41
41
  "@docusaurus/utils": ">=2.4.1 <=2.4.3",
42
42
  "@docusaurus/utils-validation": ">=2.4.1 <=2.4.3",
43
- "@paloaltonetworks/openapi-to-postmanv2": "3.1.0-hotfix.1",
44
- "@paloaltonetworks/postman-collection": "^4.1.0",
45
43
  "@redocly/openapi-core": "^1.10.5",
46
44
  "chalk": "^4.1.2",
47
45
  "clsx": "^1.1.1",
@@ -50,6 +48,8 @@
50
48
  "json-schema-merge-allof": "^0.8.1",
51
49
  "lodash": "^4.17.20",
52
50
  "mustache": "^4.2.0",
51
+ "openapi-to-postmanv2": "^4.21.0",
52
+ "postman-collection": "^4.4.0",
53
53
  "slugify": "^1.6.5",
54
54
  "swagger2openapi": "^7.0.8",
55
55
  "xml-formatter": "^2.6.1"
@@ -60,5 +60,5 @@
60
60
  "engines": {
61
61
  "node": ">=14"
62
62
  },
63
- "gitHead": "3bca23ffd3bc51c3d7f4ebb3916e2ece8c823961"
63
+ "gitHead": "73b212d18343aa7a35ede5136f5353f06b89d25f"
64
64
  }
package/src/index.ts CHANGED
@@ -40,6 +40,7 @@ export function isURL(str: string): boolean {
40
40
 
41
41
  export function getDocsPluginConfig(
42
42
  presetsPlugins: any[],
43
+ plugin: string,
43
44
  pluginId: string
44
45
  ): Object | undefined {
45
46
  // eslint-disable-next-line array-callback-return
@@ -51,10 +52,7 @@ export function getDocsPluginConfig(
51
52
  }
52
53
 
53
54
  // Search plugin-content-docs instances
54
- if (
55
- typeof data[0] === "string" &&
56
- data[0] === "@docusaurus/plugin-content-docs"
57
- ) {
55
+ if (typeof data[0] === "string" && data[0] === plugin) {
58
56
  const configPluginId = data[1].id ? data[1].id : "default";
59
57
  if (configPluginId === pluginId) {
60
58
  return data[1];
@@ -70,7 +68,7 @@ export function getDocsPluginConfig(
70
68
  }
71
69
 
72
70
  // Search plugin-content-docs instances
73
- if (filteredConfig[0] === "@docusaurus/plugin-content-docs") {
71
+ if (filteredConfig[0] === plugin) {
74
72
  const configPluginId = filteredConfig[1].id
75
73
  ? filteredConfig[1].id
76
74
  : "default";
@@ -94,14 +92,22 @@ export default function pluginOpenAPIDocs(
94
92
  context: LoadContext,
95
93
  options: PluginOptions
96
94
  ): Plugin<LoadedContent> {
97
- const { config, docsPluginId } = options;
95
+ const {
96
+ config,
97
+ docsPlugin = "@docusaurus/plugin-content-docs",
98
+ docsPluginId,
99
+ } = options;
98
100
  const { siteDir, siteConfig } = context;
99
101
 
100
102
  // Get routeBasePath and path from plugin-content-docs or preset
101
103
  const presets: any = siteConfig.presets;
102
104
  const plugins: any = siteConfig.plugins;
103
105
  const presetsPlugins = presets.concat(plugins);
104
- let docData: any = getDocsPluginConfig(presetsPlugins, docsPluginId);
106
+ let docData: any = getDocsPluginConfig(
107
+ presetsPlugins,
108
+ docsPlugin,
109
+ docsPluginId
110
+ );
105
111
  let docRouteBasePath = docData ? docData.routeBasePath : undefined;
106
112
  let docPath = docData ? (docData.path ? docData.path : "docs") : undefined;
107
113
 
@@ -113,6 +119,7 @@ export default function pluginOpenAPIDocs(
113
119
  markdownGenerators,
114
120
  downloadUrl,
115
121
  sidebarOptions,
122
+ disableCompression,
116
123
  } = options;
117
124
 
118
125
  // Remove trailing slash before proceeding
@@ -120,7 +127,7 @@ export default function pluginOpenAPIDocs(
120
127
 
121
128
  // Override docPath if pluginId provided
122
129
  if (pluginId) {
123
- docData = getDocsPluginConfig(presetsPlugins, pluginId);
130
+ docData = getDocsPluginConfig(presetsPlugins, docsPlugin, pluginId);
124
131
  docRouteBasePath = docData ? docData.routeBasePath : undefined;
125
132
  docPath = docData ? (docData.path ? docData.path : "docs") : undefined;
126
133
  }
@@ -299,7 +306,7 @@ custom_edit_url: null
299
306
 
300
307
  loadedApi.map(async (item) => {
301
308
  if (item.type === "info") {
302
- if (downloadUrl && isURL(downloadUrl)) {
309
+ if (downloadUrl) {
303
310
  item.downloadUrl = downloadUrl;
304
311
  }
305
312
  }
@@ -313,9 +320,11 @@ custom_edit_url: null
313
320
  // const deserialize = (s: any) => {
314
321
  // return zlib.inflateSync(Buffer.from(s, "base64")).toString();
315
322
  // };
316
- item.json = zlib
317
- .deflateSync(JSON.stringify(item.api))
318
- .toString("base64");
323
+ disableCompression === true
324
+ ? (item.json = JSON.stringify(item.api))
325
+ : (item.json = zlib
326
+ .deflateSync(JSON.stringify(item.api))
327
+ .toString("base64"));
319
328
  let infoBasePath = `${outputDir}/${item.infoId}`;
320
329
  if (docRouteBasePath) {
321
330
  infoBasePath = `${docRouteBasePath}/${outputDir
@@ -468,7 +477,7 @@ custom_edit_url: null
468
477
  cwd: path.resolve(apiDir, "schemas"),
469
478
  deep: 1,
470
479
  });
471
- const sidebarFile = await Globby(["sidebar.js"], {
480
+ const sidebarFile = await Globby(["sidebar.{js,ts}"], {
472
481
  cwd: path.resolve(apiDir),
473
482
  deep: 1,
474
483
  });
@@ -523,6 +532,7 @@ custom_edit_url: null
523
532
  version: version,
524
533
  label: metadata.label,
525
534
  baseUrl: metadata.baseUrl,
535
+ downloadUrl: metadata.downloadUrl,
526
536
  });
527
537
  }
528
538
 
@@ -673,6 +683,7 @@ custom_edit_url: null
673
683
  delete parentConfig.version;
674
684
  delete parentConfig.label;
675
685
  delete parentConfig.baseUrl;
686
+ delete parentConfig.downloadUrl;
676
687
 
677
688
  // TODO: handle when no versions are defined by version command is passed
678
689
  if (versionId === "all") {
@@ -108,12 +108,6 @@ export function createRequestSchema({ title, body, ...rest }: Props) {
108
108
  return undefined;
109
109
  }
110
110
 
111
- // we don't show the table if there is no properties to show
112
- if (firstBody.properties !== undefined) {
113
- if (Object.keys(firstBody.properties).length === 0) {
114
- return undefined;
115
- }
116
- }
117
111
  return create("MimeTabs", {
118
112
  className: "openapi-tabs__mime",
119
113
  children: [
@@ -60,12 +60,6 @@ export function createResponseSchema({ title, body, ...rest }: Props) {
60
60
  return undefined;
61
61
  }
62
62
 
63
- if (firstBody?.properties !== undefined) {
64
- if (Object.keys(firstBody?.properties).length === 0) {
65
- return undefined;
66
- }
67
- }
68
-
69
63
  return create("TabItem", {
70
64
  label: `${mimeType}`,
71
65
  value: `${mimeType}`,
@@ -13,6 +13,7 @@ import { SchemaObject } from "../openapi/types";
13
13
  describe("createNodes", () => {
14
14
  it("should create readable MODs for oneOf primitive properties", () => {
15
15
  const schema: SchemaObject = {
16
+ "x-tags": ["clown"],
16
17
  type: "object",
17
18
  properties: {
18
19
  oneOfProperty: {
@@ -129,6 +129,16 @@ function createAnyOneOf(schema: SchemaObject): any {
129
129
  */
130
130
  function createProperties(schema: SchemaObject) {
131
131
  const discriminator = schema.discriminator;
132
+ if (Object.keys(schema.properties!).length === 0) {
133
+ return create("SchemaItem", {
134
+ collapsible: false,
135
+ name: "",
136
+ required: false,
137
+ schemaName: "object",
138
+ qualifierMessage: undefined,
139
+ schema: {},
140
+ });
141
+ }
132
142
  return Object.entries(schema.properties!).map(([key, val]) => {
133
143
  return createEdges({
134
144
  name: key,
@@ -594,6 +604,18 @@ function createEdges({
594
604
  required,
595
605
  discriminator,
596
606
  }: EdgeProps): any {
607
+ if (SCHEMA_TYPE === "request") {
608
+ if (schema.readOnly && schema.readOnly === true) {
609
+ return undefined;
610
+ }
611
+ }
612
+
613
+ if (SCHEMA_TYPE === "response") {
614
+ if (schema.writeOnly && schema.writeOnly === true) {
615
+ return undefined;
616
+ }
617
+ }
618
+
597
619
  const schemaName = getSchemaName(schema);
598
620
  if (discriminator !== undefined && discriminator.propertyName === name) {
599
621
  return createPropertyDiscriminator(
@@ -619,6 +641,19 @@ function createEdges({
619
641
  const { mergedSchemas }: { mergedSchemas: SchemaObject } = mergeAllOf(
620
642
  schema.allOf
621
643
  );
644
+
645
+ if (SCHEMA_TYPE === "request") {
646
+ if (mergedSchemas.readOnly && mergedSchemas.readOnly === true) {
647
+ return undefined;
648
+ }
649
+ }
650
+
651
+ if (SCHEMA_TYPE === "response") {
652
+ if (mergedSchemas.writeOnly && mergedSchemas.writeOnly === true) {
653
+ return undefined;
654
+ }
655
+ }
656
+
622
657
  const mergedSchemaName = getSchemaName(mergedSchemas);
623
658
  if (
624
659
  mergedSchemas.oneOf !== undefined ||
@@ -664,18 +699,6 @@ function createEdges({
664
699
  );
665
700
  }
666
701
 
667
- if (SCHEMA_TYPE === "request") {
668
- if (mergedSchemas.readOnly && mergedSchemas.readOnly === true) {
669
- return undefined;
670
- }
671
- }
672
-
673
- if (SCHEMA_TYPE === "response") {
674
- if (mergedSchemas.writeOnly && mergedSchemas.writeOnly === true) {
675
- return undefined;
676
- }
677
- }
678
-
679
702
  return create("SchemaItem", {
680
703
  collapsible: false,
681
704
  name,
@@ -727,18 +750,6 @@ function createEdges({
727
750
  );
728
751
  }
729
752
 
730
- if (SCHEMA_TYPE === "request") {
731
- if (schema.readOnly && schema.readOnly === true) {
732
- return undefined;
733
- }
734
- }
735
-
736
- if (SCHEMA_TYPE === "response") {
737
- if (schema.writeOnly && schema.writeOnly === true) {
738
- return undefined;
739
- }
740
- }
741
-
742
753
  // primitives and array of non-objects
743
754
  return create("SchemaItem", {
744
755
  collapsible: false,
@@ -758,6 +769,17 @@ export function createNodes(
758
769
  schemaType: "request" | "response"
759
770
  ): any {
760
771
  SCHEMA_TYPE = schemaType;
772
+ if (SCHEMA_TYPE === "request") {
773
+ if (schema.readOnly && schema.readOnly === true) {
774
+ return undefined;
775
+ }
776
+ }
777
+
778
+ if (SCHEMA_TYPE === "response") {
779
+ if (schema.writeOnly && schema.writeOnly === true) {
780
+ return undefined;
781
+ }
782
+ }
761
783
  const nodes = [];
762
784
  // if (schema.discriminator !== undefined) {
763
785
  // return createDiscriminator(schema);
@@ -285,7 +285,7 @@ export function createStatusCodes({ label, id, responses }: Props) {
285
285
  responseHeaders &&
286
286
  createDetails({
287
287
  className: "openapi-markdown__details",
288
- "data-collaposed": true,
288
+ "data-collapsed": true,
289
289
  open: false,
290
290
  style: { textAlign: "left", marginBottom: "1rem" },
291
291
  children: [
@@ -47,3 +47,25 @@ export const lessThan =
47
47
  export const greaterThan =
48
48
  /(?<!(button|code|details|summary|hr|br|span|strong|small|table|thead|tbody|td|tr|th|h1|h2|h3|h4|h5|h6|title|p|em|b|i|u|strike|bold|a|li|ol|ul|img|svg|div|center|\/|\s|"|'))>/gu;
49
49
  export const codeFence = /`{1,3}[\s\S]*?`{1,3}/g;
50
+ export const curlyBrackets = /([{}])/g;
51
+ export const codeBlock = /(^```.*[\s\S]*?```$|`[^`].+?`)/gm;
52
+
53
+ export function clean(value: string | undefined): string {
54
+ if (!value) {
55
+ return "";
56
+ }
57
+
58
+ let sections = value.split(codeBlock);
59
+ for (let sectionIndex in sections) {
60
+ if (!sections[sectionIndex].startsWith("`")) {
61
+ sections[sectionIndex] = sections[sectionIndex]
62
+ .replace(lessThan, "&lt;")
63
+ .replace(greaterThan, "&gt;")
64
+ .replace(codeFence, function (match) {
65
+ return match.replace(/\\>/g, ">");
66
+ })
67
+ .replace(curlyBrackets, "\\$1");
68
+ }
69
+ }
70
+ return sections.join("");
71
+ }
@@ -40,3 +40,10 @@ x-tagGroups:
40
40
  tags:
41
41
  - tag3
42
42
  - tag4
43
+
44
+ components:
45
+ schemas:
46
+ HelloString:
47
+ x-tags:
48
+ - tag1
49
+ type: string
@@ -31,6 +31,10 @@ describe("openapi", () => {
31
31
 
32
32
  expect(yaml?.data.tags).toBeDefined();
33
33
  expect(yaml?.data["x-tagGroups"]).toBeDefined();
34
+
35
+ expect(
36
+ yaml?.data.components?.schemas?.HelloString["x-tags"]
37
+ ).toBeDefined();
34
38
  });
35
39
  });
36
40
  });