docusaurus-plugin-openapi-docs 1.0.3 → 1.0.6

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/lib/options.js CHANGED
@@ -6,13 +6,42 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  * ========================================================================== */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.OptionsSchema = exports.DEFAULT_OPTIONS = void 0;
9
+ exports.OptionsSchema = void 0;
10
10
  const utils_validation_1 = require("@docusaurus/utils-validation");
11
- exports.DEFAULT_OPTIONS = {
12
- id: "default",
13
- config: {},
14
- };
11
+ const sidebarOptions = utils_validation_1.Joi.object({
12
+ groupPathsBy: utils_validation_1.Joi.string().valid("tag"),
13
+ categoryLinkSource: utils_validation_1.Joi.string().valid("tag", "info"),
14
+ customProps: utils_validation_1.Joi.object(),
15
+ sidebarCollapsible: utils_validation_1.Joi.boolean(),
16
+ sidebarCollapsed: utils_validation_1.Joi.boolean(),
17
+ });
15
18
  exports.OptionsSchema = utils_validation_1.Joi.object({
16
- id: utils_validation_1.Joi.string().default(exports.DEFAULT_OPTIONS.id),
17
- config: utils_validation_1.Joi.object().default(exports.DEFAULT_OPTIONS.config),
19
+ id: utils_validation_1.Joi.string().required(),
20
+ docsPluginId: utils_validation_1.Joi.string().required(),
21
+ config: utils_validation_1.Joi.object()
22
+ .pattern(/^/, utils_validation_1.Joi.object({
23
+ specPath: utils_validation_1.Joi.string().required(),
24
+ outputDir: utils_validation_1.Joi.string().required(),
25
+ template: utils_validation_1.Joi.string(),
26
+ sidebarOptions: sidebarOptions,
27
+ version: utils_validation_1.Joi.string().when("versions", {
28
+ is: utils_validation_1.Joi.exist(),
29
+ then: utils_validation_1.Joi.required(),
30
+ }),
31
+ label: utils_validation_1.Joi.string().when("versions", {
32
+ is: utils_validation_1.Joi.exist(),
33
+ then: utils_validation_1.Joi.required(),
34
+ }),
35
+ baseUrl: utils_validation_1.Joi.string().when("versions", {
36
+ is: utils_validation_1.Joi.exist(),
37
+ then: utils_validation_1.Joi.required(),
38
+ }),
39
+ versions: utils_validation_1.Joi.object().pattern(/^/, utils_validation_1.Joi.object({
40
+ specPath: utils_validation_1.Joi.string().required(),
41
+ outputDir: utils_validation_1.Joi.string().required(),
42
+ label: utils_validation_1.Joi.string().required(),
43
+ baseUrl: utils_validation_1.Joi.string().required(),
44
+ })),
45
+ }))
46
+ .required(),
18
47
  });
@@ -1,4 +1,4 @@
1
1
  import { ProcessedSidebar } from "@docusaurus/plugin-content-docs/src/sidebars/types";
2
2
  import { TagObject } from "../openapi/types";
3
3
  import type { SidebarOptions, APIOptions, ApiMetadata } from "../types";
4
- export default function generateSidebarSlice(sidebarOptions: SidebarOptions, options: APIOptions, api: ApiMetadata[], tags: TagObject[]): ProcessedSidebar;
4
+ export default function generateSidebarSlice(sidebarOptions: SidebarOptions, options: APIOptions, api: ApiMetadata[], tags: TagObject[], docPath: string): ProcessedSidebar;
@@ -18,8 +18,8 @@ function isApiItem(item) {
18
18
  function isInfoItem(item) {
19
19
  return item.type === "info";
20
20
  }
21
- function groupByTags(items, sidebarOptions, options, tags) {
22
- const { outputDir } = options;
21
+ function groupByTags(items, sidebarOptions, options, tags, docPath) {
22
+ const { outputDir, label } = options;
23
23
  const { sidebarCollapsed, sidebarCollapsible, customProps, categoryLinkSource, } = sidebarOptions;
24
24
  const apiItems = items.filter(isApiItem);
25
25
  const infoItems = items.filter(isInfoItem);
@@ -35,10 +35,9 @@ function groupByTags(items, sidebarOptions, options, tags) {
35
35
  const apiTags = (0, uniq_1.default)(apiItems
36
36
  .flatMap((item) => item.api.tags)
37
37
  .filter((item) => !!item));
38
- // TODO: optimize this or make it a function
39
- const basePath = outputDir
40
- .slice(outputDir.indexOf("/", 1))
41
- .replace(/^\/+/g, "");
38
+ const basePath = docPath
39
+ ? outputDir.split(docPath)[1].replace(/^\/+/g, "")
40
+ : outputDir.slice(outputDir.indexOf("/", 1)).replace(/^\/+/g, "");
42
41
  function createDocItem(item) {
43
42
  var _a, _b;
44
43
  const sidebar_label = item.frontMatter.sidebar_label;
@@ -46,7 +45,7 @@ function groupByTags(items, sidebarOptions, options, tags) {
46
45
  const id = item.id;
47
46
  return {
48
47
  type: "doc",
49
- id: `${basePath}/${item.id}`,
48
+ id: basePath === "" || undefined ? `${item.id}` : `${basePath}/${item.id}`,
50
49
  label: (_b = (_a = sidebar_label) !== null && _a !== void 0 ? _a : title) !== null && _b !== void 0 ? _b : id,
51
50
  customProps: customProps,
52
51
  className: (0, clsx_1.default)({
@@ -96,7 +95,9 @@ function groupByTags(items, sidebarOptions, options, tags) {
96
95
  linkConfig = {
97
96
  type: "generated-index",
98
97
  title: tag,
99
- slug: "/category/" + (0, lodash_1.kebabCase)(tag),
98
+ slug: label
99
+ ? "/category/" + (0, lodash_1.kebabCase)(label) + "/" + (0, lodash_1.kebabCase)(tag)
100
+ : "/category/" + (0, lodash_1.kebabCase)(tag),
100
101
  };
101
102
  }
102
103
  return {
@@ -136,10 +137,10 @@ function groupByTags(items, sidebarOptions, options, tags) {
136
137
  }
137
138
  return [...tagged, ...untagged];
138
139
  }
139
- function generateSidebarSlice(sidebarOptions, options, api, tags) {
140
+ function generateSidebarSlice(sidebarOptions, options, api, tags, docPath) {
140
141
  let sidebarSlice = [];
141
142
  if (sidebarOptions.groupPathsBy === "tag") {
142
- sidebarSlice = groupByTags(api, sidebarOptions, options, tags);
143
+ sidebarSlice = groupByTags(api, sidebarOptions, options, tags, docPath);
143
144
  }
144
145
  return sidebarSlice;
145
146
  }
@@ -0,0 +1,2 @@
1
+ export declare function versionSelector(versions: object[]): string;
2
+ export declare function versionCrumb(version: string): string;
@@ -0,0 +1,31 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.versionCrumb = exports.versionSelector = void 0;
10
+ const mustache_1 = require("mustache");
11
+ function versionSelector(versions) {
12
+ const template = `<div class="dropdown dropdown--hoverable dropdown--right">
13
+ <button class="button button--block button--sm button--secondary"><span>Select API Version</span></button>
14
+ <ul class="dropdown__menu">
15
+ {{#.}}<li><a class="dropdown__link" href="{{{baseUrl}}}">{{{label}}}</a></li>{{/.}}
16
+ </ul>
17
+ </div>
18
+ `;
19
+ const view = (0, mustache_1.render)(template, versions);
20
+ return view;
21
+ }
22
+ exports.versionSelector = versionSelector;
23
+ function versionCrumb(version) {
24
+ const template = `<ul style="display: flex;" class="breadcrumbs breadcrumbs--sm">
25
+ <li style="margin-left: auto; margin-right: 0;" class="breadcrumbs__item breadcrumbs__item--active">
26
+ <a class="breadcrumbs__link"><span>{{{.}}}</span></a></li></ul>
27
+ `;
28
+ const view = (0, mustache_1.render)(template, version);
29
+ return view;
30
+ }
31
+ exports.versionCrumb = versionCrumb;
package/lib/types.d.ts CHANGED
@@ -3,6 +3,7 @@ import { InfoObject, OperationObject, SecuritySchemeObject, TagObject } from "./
3
3
  export type { PropSidebarItemCategory, SidebarItemLink, PropSidebar, PropSidebarItem, } from "@docusaurus/plugin-content-docs-types";
4
4
  export interface PluginOptions {
5
5
  id?: string;
6
+ docsPluginId: string;
6
7
  config: {
7
8
  [key: string]: APIOptions;
8
9
  };
@@ -12,6 +13,27 @@ export interface APIOptions {
12
13
  outputDir: string;
13
14
  template?: string;
14
15
  sidebarOptions?: SidebarOptions;
16
+ version?: string;
17
+ label?: string;
18
+ baseUrl?: string;
19
+ versions?: {
20
+ [key: string]: APIVersionOptions;
21
+ };
22
+ }
23
+ export interface SidebarOptions {
24
+ groupPathsBy?: string;
25
+ categoryLinkSource?: string;
26
+ customProps?: {
27
+ [key: string]: unknown;
28
+ };
29
+ sidebarCollapsible?: boolean;
30
+ sidebarCollapsed?: boolean;
31
+ }
32
+ export interface APIVersionOptions {
33
+ specPath: string;
34
+ outputDir: string;
35
+ label: string;
36
+ baseUrl: string;
15
37
  }
16
38
  export interface LoadedContent {
17
39
  loadedApi: ApiMetadata[];
@@ -68,12 +90,3 @@ export interface ApiNavLink {
68
90
  title: string;
69
91
  permalink: string;
70
92
  }
71
- export interface SidebarOptions {
72
- groupPathsBy?: string;
73
- categoryLinkSource?: string;
74
- customProps?: {
75
- [key: string]: unknown;
76
- };
77
- sidebarCollapsible?: boolean;
78
- sidebarCollapsed?: boolean;
79
- }
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.0.3",
4
+ "version": "1.0.6",
5
5
  "license": "MIT",
6
6
  "keywords": [
7
7
  "openapi",
@@ -36,6 +36,7 @@
36
36
  "utility-types": "^3.10.0"
37
37
  },
38
38
  "dependencies": {
39
+ "@apidevtools/json-schema-ref-parser": "^9.0.9",
39
40
  "@docusaurus/mdx-loader": "2.0.0-beta.21",
40
41
  "@docusaurus/plugin-content-docs": "2.0.0-beta.21",
41
42
  "@docusaurus/utils": "2.0.0-beta.21",
@@ -62,5 +63,5 @@
62
63
  "engines": {
63
64
  "node": ">=14"
64
65
  },
65
- "gitHead": "618a438ec42148f525fb92cb11d291ce50d2ad06"
66
+ "gitHead": "ff7622e334e96e7f39b0daf5ef2cb17bfa832834"
66
67
  }
package/src/index.ts CHANGED
@@ -15,6 +15,7 @@ import { render } from "mustache";
15
15
 
16
16
  import { createApiPageMD, createInfoPageMD, createTagPageMD } from "./markdown";
17
17
  import { readOpenapiFiles, processOpenapiFiles } from "./openapi";
18
+ import { OptionsSchema } from "./options";
18
19
  import generateSidebarSlice from "./sidebars";
19
20
  import type { PluginOptions, LoadedContent, APIOptions } from "./types";
20
21
 
@@ -22,12 +23,55 @@ export function isURL(str: string): boolean {
22
23
  return /^(https?:)\/\//m.test(str);
23
24
  }
24
25
 
25
- export default function pluginOpenAPI(
26
+ export function getDocsData(
27
+ dataArray: any[],
28
+ filter: string
29
+ ): Object | undefined {
30
+ // eslint-disable-next-line array-callback-return
31
+ const filteredData = dataArray.filter((data) => {
32
+ if (data[0] === filter) {
33
+ return data[1];
34
+ }
35
+
36
+ // Search plugin-content-docs instances
37
+ if (data[0] === "@docusaurus/plugin-content-docs") {
38
+ const pluginId = data[1].id ? data[1].id : "default";
39
+ if (pluginId === filter) {
40
+ return data[1];
41
+ }
42
+ }
43
+ })[0];
44
+ if (filteredData) {
45
+ // Search presets, e.g. "classic"
46
+ if (filteredData[0] === filter) {
47
+ return filteredData[1].docs;
48
+ }
49
+
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];
55
+ }
56
+ }
57
+ }
58
+ return;
59
+ }
60
+
61
+ export default function pluginOpenAPIDocs(
26
62
  context: LoadContext,
27
63
  options: PluginOptions
28
64
  ): Plugin<LoadedContent> {
29
- let { config } = options;
30
- let { siteDir } = context;
65
+ const { config, docsPluginId } = options;
66
+ const { siteDir, siteConfig } = context;
67
+
68
+ // Get routeBasePath and path from plugin-content-docs or preset
69
+ const presets: any = siteConfig.presets;
70
+ const plugins: any = siteConfig.plugins;
71
+ const presetsPlugins = presets.concat(plugins);
72
+ const docData: any = getDocsData(presetsPlugins, docsPluginId);
73
+ const docRouteBasePath = docData ? docData.routeBasePath : undefined;
74
+ const docPath = docData ? (docData.path ? docData.path : "docs") : undefined;
31
75
 
32
76
  async function generateApiDocs(options: APIOptions) {
33
77
  let { specPath, outputDir, template, sidebarOptions } = options;
@@ -37,7 +81,7 @@ export default function pluginOpenAPI(
37
81
  : path.resolve(siteDir, specPath);
38
82
 
39
83
  try {
40
- const openapiFiles = await readOpenapiFiles(contentPath, {});
84
+ const openapiFiles = await readOpenapiFiles(contentPath, options);
41
85
  const [loadedApi, tags] = await processOpenapiFiles(
42
86
  openapiFiles,
43
87
  sidebarOptions!
@@ -57,10 +101,11 @@ export default function pluginOpenAPI(
57
101
  // TODO: figure out better way to set default
58
102
  if (Object.keys(sidebarOptions ?? {}).length > 0) {
59
103
  const sidebarSlice = generateSidebarSlice(
60
- sidebarOptions!, // TODO: find a better way to handle null
104
+ sidebarOptions!,
61
105
  options,
62
106
  loadedApi,
63
- tags
107
+ tags,
108
+ docPath
64
109
  );
65
110
 
66
111
  const sidebarSliceTemplate = template
@@ -163,7 +208,13 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
163
208
  item.markdown = markdown;
164
209
  if (item.type === "api") {
165
210
  item.json = JSON.stringify(item.api);
166
- if (item.infoId) item.infoPath = `${outputDir}/${item.infoId}`;
211
+ let infoBasePath = `${outputDir}/${item.infoId}`;
212
+ if (docRouteBasePath) {
213
+ infoBasePath = `${docRouteBasePath}/${outputDir
214
+ .split(docPath!)[1]
215
+ .replace(/^\/+/g, "")}/${item.infoId}`.replace(/^\/+/g, "");
216
+ }
217
+ if (item.infoId) item.infoPath = infoBasePath;
167
218
  }
168
219
 
169
220
  const view = render(mdTemplate, item);
@@ -254,9 +305,11 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
254
305
  const apiDir = path.join(siteDir, outputDir);
255
306
  const apiMdxFiles = await Globby(["*.api.mdx", "*.info.mdx", "*.tag.mdx"], {
256
307
  cwd: path.resolve(apiDir),
308
+ deep: 1,
257
309
  });
258
310
  const sidebarFile = await Globby(["sidebar.js"], {
259
311
  cwd: path.resolve(apiDir),
312
+ deep: 1,
260
313
  });
261
314
  apiMdxFiles.map((mdx) =>
262
315
  fs.unlink(`${apiDir}/${mdx}`, (err) => {
@@ -287,21 +340,66 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
287
340
  );
288
341
  }
289
342
 
343
+ async function generateVersions(versions: object, outputDir: string) {
344
+ let versionsArray = [] as object[];
345
+ for (const [version, metadata] of Object.entries(versions)) {
346
+ versionsArray.push({
347
+ version: version,
348
+ label: metadata.label,
349
+ baseUrl: metadata.baseUrl,
350
+ });
351
+ }
352
+
353
+ const versionsJson = JSON.stringify(versionsArray, null, 2);
354
+ try {
355
+ fs.writeFileSync(`${outputDir}/versions.json`, versionsJson, "utf8");
356
+ console.log(
357
+ chalk.green(`Successfully created "${outputDir}/versions.json"`)
358
+ );
359
+ } catch (err) {
360
+ console.error(
361
+ chalk.red(`Failed to write "${outputDir}/versions.json"`),
362
+ chalk.yellow(err)
363
+ );
364
+ }
365
+ }
366
+
367
+ async function cleanVersions(outputDir: string) {
368
+ if (fs.existsSync(`${outputDir}/versions.json`)) {
369
+ fs.unlink(`${outputDir}/versions.json`, (err) => {
370
+ if (err) {
371
+ console.error(
372
+ chalk.red(`Cleanup failed for "${outputDir}/versions.json"`),
373
+ chalk.yellow(err)
374
+ );
375
+ } else {
376
+ console.log(
377
+ chalk.green(`Cleanup succeeded for "${outputDir}/versions.json"`)
378
+ );
379
+ }
380
+ });
381
+ }
382
+ }
383
+
290
384
  return {
291
- name: `docusaurus-plugin-openapi`,
385
+ name: `docusaurus-plugin-openapi-docs`,
292
386
 
293
387
  extendCli(cli): void {
294
388
  cli
295
389
  .command(`gen-api-docs`)
296
- .description(`Generates API Docs mdx and sidebars.`)
297
- .usage(
298
- "[options] <id key value in plugin config within docusaurus.config.js>"
390
+ .description(
391
+ `Generates OpenAPI docs in MDX file format and sidebar.js (if enabled).`
299
392
  )
393
+ .usage("<id>")
300
394
  .arguments("<id>")
301
395
  .action(async (id) => {
302
396
  if (id === "all") {
303
397
  if (config[id]) {
304
- console.error(chalk.red("Can't use id 'all' for API Doc."));
398
+ console.error(
399
+ chalk.red(
400
+ "Can't use id 'all' for OpenAPI docs configuration key."
401
+ )
402
+ );
305
403
  } else {
306
404
  Object.keys(config).forEach(async function (key) {
307
405
  await generateApiDocs(config[key]);
@@ -309,24 +407,91 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
309
407
  }
310
408
  } else if (!config[id]) {
311
409
  console.error(
312
- chalk.red(`ID ${id} does not exist in openapi-plugin config`)
410
+ chalk.red(`ID '${id}' does not exist in OpenAPI docs config.`)
313
411
  );
314
412
  } else {
315
413
  await generateApiDocs(config[id]);
316
414
  }
317
415
  });
318
416
 
417
+ cli
418
+ .command(`gen-api-docs:version`)
419
+ .description(
420
+ `Generates versioned OpenAPI docs in MDX file format, versions.js and sidebar.js (if enabled).`
421
+ )
422
+ .usage("<id:version>")
423
+ .arguments("<id:version>")
424
+ .action(async (id) => {
425
+ const [parentId, versionId] = id.split(":");
426
+ const parentConfig = Object.assign({}, config[parentId]);
427
+
428
+ const version = parentConfig.version as string;
429
+ const label = parentConfig.label as string;
430
+ const baseUrl = parentConfig.baseUrl as string;
431
+
432
+ let parentVersion = {} as any;
433
+ parentVersion[version] = { label: label, baseUrl: baseUrl };
434
+
435
+ const { versions } = config[parentId] as any;
436
+ const mergedVersions = Object.assign(parentVersion, versions);
437
+
438
+ // Prepare for merge
439
+ delete parentConfig.versions;
440
+ delete parentConfig.version;
441
+ delete parentConfig.label;
442
+ delete parentConfig.baseUrl;
443
+
444
+ // TODO: handle when no versions are defined by version command is passed
445
+ if (versionId === "all") {
446
+ if (versions[id]) {
447
+ console.error(
448
+ chalk.red(
449
+ "Can't use id 'all' for OpenAPI docs versions configuration key."
450
+ )
451
+ );
452
+ } else {
453
+ await generateVersions(mergedVersions, parentConfig.outputDir);
454
+ Object.keys(versions).forEach(async (key) => {
455
+ const versionConfig = versions[key];
456
+ const mergedConfig = {
457
+ ...parentConfig,
458
+ ...versionConfig,
459
+ };
460
+ await generateApiDocs(mergedConfig);
461
+ });
462
+ }
463
+ } else if (!versions[versionId]) {
464
+ console.error(
465
+ chalk.red(
466
+ `Version ID '${versionId}' does not exist in OpenAPI docs versions config.`
467
+ )
468
+ );
469
+ } else {
470
+ const versionConfig = versions[versionId];
471
+ const mergedConfig = {
472
+ ...parentConfig,
473
+ ...versionConfig,
474
+ };
475
+ await generateVersions(mergedVersions, parentConfig.outputDir);
476
+ await generateApiDocs(mergedConfig);
477
+ }
478
+ });
479
+
319
480
  cli
320
481
  .command(`clean-api-docs`)
321
- .description(`Clears the Generated API Docs mdx and sidebars.`)
322
- .usage(
323
- "[options] <id key value in plugin config within docusaurus.config.js>"
482
+ .description(
483
+ `Clears the generated OpenAPI docs MDX files and sidebar.js (if enabled).`
324
484
  )
485
+ .usage("<id>")
325
486
  .arguments("<id>")
326
487
  .action(async (id) => {
327
488
  if (id === "all") {
328
489
  if (config[id]) {
329
- console.error(chalk.red("Can't use id 'all' for API Doc."));
490
+ console.error(
491
+ chalk.red(
492
+ "Can't use id 'all' for OpenAPI docs configuration key."
493
+ )
494
+ );
330
495
  } else {
331
496
  Object.keys(config).forEach(async function (key) {
332
497
  await cleanApiDocs(config[key]);
@@ -336,6 +501,51 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
336
501
  await cleanApiDocs(config[id]);
337
502
  }
338
503
  });
504
+
505
+ cli
506
+ .command(`clean-api-docs:version`)
507
+ .description(
508
+ `Clears the versioned, generated OpenAPI docs MDX files, versions.json and sidebar.js (if enabled).`
509
+ )
510
+ .usage("<id:version>")
511
+ .arguments("<id:version>")
512
+ .action(async (id) => {
513
+ const [parentId, versionId] = id.split(":");
514
+ const { versions } = config[parentId] as any;
515
+
516
+ const parentConfig = Object.assign({}, config[parentId]);
517
+ delete parentConfig.versions;
518
+
519
+ if (versionId === "all") {
520
+ if (versions[id]) {
521
+ chalk.red(
522
+ "Can't use id 'all' for OpenAPI docs versions configuration key."
523
+ );
524
+ } else {
525
+ await cleanVersions(parentConfig.outputDir);
526
+ Object.keys(versions).forEach(async (key) => {
527
+ const versionConfig = versions[key];
528
+ const mergedConfig = {
529
+ ...parentConfig,
530
+ ...versionConfig,
531
+ };
532
+ await cleanApiDocs(mergedConfig);
533
+ });
534
+ }
535
+ } else {
536
+ const versionConfig = versions[versionId];
537
+ const mergedConfig = {
538
+ ...parentConfig,
539
+ ...versionConfig,
540
+ };
541
+ await cleanApiDocs(mergedConfig);
542
+ }
543
+ });
339
544
  },
340
545
  };
341
546
  }
547
+
548
+ pluginOpenAPIDocs.validateOptions = ({ options, validate }: any) => {
549
+ const validatedOptions = validate(OptionsSchema, options);
550
+ return validatedOptions;
551
+ };
@@ -25,6 +25,8 @@ export function createParamsDetails({ parameters, type }: Props) {
25
25
  }
26
26
 
27
27
  return createDetails({
28
+ "data-collapsed": false,
29
+ open: true,
28
30
  style: { marginBottom: "1rem" },
29
31
  children: [
30
32
  createDetailsSummary({
@@ -269,6 +269,8 @@ export function createSchemaDetails({ title, body, ...rest }: Props) {
269
269
  }
270
270
 
271
271
  return createDetails({
272
+ "data-collapsed": false,
273
+ open: true,
272
274
  ...rest,
273
275
  children: [
274
276
  createDetailsSummary({
@@ -59,7 +59,7 @@ export function createInfoPageMD({
59
59
  }: InfoPageMetadata) {
60
60
  return render([
61
61
  `import Tabs from "@theme/Tabs";\n`,
62
- `import TabItem from "@theme/TabItem";\n`,
62
+ `import TabItem from "@theme/TabItem";\n\n`,
63
63
  createVersionBadge(version),
64
64
  `# ${escape(title)}\n\n`,
65
65
  createDescription(description),
@@ -16,7 +16,7 @@ describe("openapi", () => {
16
16
  it("readOpenapiFiles", async () => {
17
17
  const results = await readOpenapiFiles(
18
18
  path.join(__dirname, "__fixtures__/examples"),
19
- {}
19
+ { specPath: "./", outputDir: "./" }
20
20
  );
21
21
  const categoryMeta = results.find((x) =>
22
22
  x.source.endsWith("_category_.json")
@@ -19,6 +19,7 @@ import { kebabCase } from "lodash";
19
19
  import { isURL } from "../index";
20
20
  import {
21
21
  ApiMetadata,
22
+ APIOptions,
22
23
  ApiPageMetadata,
23
24
  InfoPageMetadata,
24
25
  SidebarOptions,
@@ -247,8 +248,12 @@ interface OpenApiFiles {
247
248
 
248
249
  export async function readOpenapiFiles(
249
250
  openapiPath: string,
250
- _options: {}
251
+ options: APIOptions
251
252
  ): Promise<OpenApiFiles[]> {
253
+ // TODO: determine if this should be an API option
254
+ // Forces the json-schema-ref-parser
255
+ const parseJsonRefs = true;
256
+
252
257
  if (!isURL(openapiPath)) {
253
258
  const stat = await fs.lstat(openapiPath);
254
259
  if (stat.isDirectory()) {
@@ -270,7 +275,8 @@ export async function readOpenapiFiles(
270
275
  // TODO: make a function for this
271
276
  const fullPath = path.join(openapiPath, source);
272
277
  const data = (await loadAndBundleSpec(
273
- fullPath
278
+ fullPath,
279
+ parseJsonRefs
274
280
  )) as OpenApiObjectWithRef;
275
281
  return {
276
282
  source: fullPath, // This will be aliased in process.
@@ -281,7 +287,10 @@ export async function readOpenapiFiles(
281
287
  );
282
288
  }
283
289
  }
284
- const data = (await loadAndBundleSpec(openapiPath)) as OpenApiObjectWithRef;
290
+ const data = (await loadAndBundleSpec(
291
+ openapiPath,
292
+ parseJsonRefs
293
+ )) as OpenApiObjectWithRef;
285
294
  return [
286
295
  {
287
296
  source: openapiPath, // This will be aliased in process.