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/README.md CHANGED
@@ -20,6 +20,13 @@ OpenAPI plugin for generating API reference docs in Docusaurus v2.
20
20
 
21
21
  The `docusaurus-plugin-openapi-docs` package extends the Docusaurus CLI with commands for generating MDX using the OpenAPI specification as the source. The resulting MDX is fully compatible with [plugin-content-docs](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-docs) and can be used to render beautiful reference API docs by setting `docItemComponent` to `@theme/ApiItem`, a custom component included in the `docusaurus-theme-openapi-docs` theme.
22
22
 
23
+ Key Features:
24
+
25
+ - **Compatible:** Works with Swagger 2.0 and OpenAPI 3.x.
26
+ - **Fast:** Convert large OpenAPI specs into MDX docs in seconds. 🔥
27
+ - **Stylish:** Based on the same [Infima styling framework](https://infima.dev/) that powers the Docusaurus UI.
28
+ - **Capable:** Supports single, multi and _even micro_ OpenAPI specs.
29
+
23
30
  ## Installation
24
31
 
25
32
  Plugin:
@@ -71,10 +78,10 @@ Here is an example of properly configuring your `docusaurus.config.js` file for
71
78
  ],
72
79
 
73
80
  plugins: [
74
- [
75
81
  'docusaurus-plugin-openapi-docs',
76
82
  {
77
83
  id: "apiDocs",
84
+ docsPluginId: "classic",
78
85
  config: {
79
86
  petstore: { // Note: petstore key is treated as the <id> and can be used to specify an API doc instance when using CLI commands
80
87
  specPath: "examples/petstore.yaml", // Path to designated spec file
@@ -97,28 +104,53 @@ Here is an example of properly configuring your `docusaurus.config.js` file for
97
104
 
98
105
  > Note: You may optionally configure a dedicated `@docusaurus/plugin-content-docs` instance for use with `docusaurus-theme-openapi-docs` by setting `docItemComponent` to `@theme/ApiItem`.
99
106
 
100
- ### Plugin Configuration Options
107
+ ## Plugin Configuration Options
108
+
109
+ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following options:
110
+
111
+ | Name | Type | Default | Description |
112
+ | -------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
113
+ | `id` | `string` | `null` | A unique document id. |
114
+ | `docsPluginId` | `string` | `null` | The ID associated with the `plugin-content-docs` or `preset` instance used to render the OpenAPI docs (e.g. "your-plugin-id", "classic", "default"). |
115
+
116
+ ### config
101
117
 
102
- `docusaurus-plugin-openapi-docs` can be configured with the following options:
118
+ `config` can be configured with the following options:
103
119
 
104
- | Name | Type | Default | Description |
105
- | ---------------- | -------- | ------- | -------------------------------------------------------------------------------------------------------------------- |
106
- | `specPath` | `string` | `null` | Designated path to the source of an OpenAPI specification file or directory of multiple OpenAPI specification files. |
107
- | `ouputDir` | `string` | `null` | Desired output path for generated MDX files. |
108
- | `template` | `string` | `null` | _Optional:_ Customize MDX content with a desired template. |
109
- | `sidebarOptions` | `object` | `null` | _Optional:_ Set of options for sidebar configuration. See below for a list of supported options. |
120
+ | Name | Type | Default | Description |
121
+ | ---------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------- |
122
+ | `specPath` | `string` | `null` | Designated URL or path to the source of an OpenAPI specification file or directory of multiple OpenAPI specification files. |
123
+ | `ouputDir` | `string` | `null` | Desired output path for generated MDX files. |
124
+ | `ouputDir` | `string` | `null` | Desired output path for generated MDX files. |
125
+ | `template` | `string` | `null` | _Optional:_ Customize MDX content with a desired template. |
126
+ | `sidebarOptions` | `object` | `null` | _Optional:_ Set of options for sidebar configuration. See below for a list of supported options. |
127
+ | `version` | `string` | `null` | _Optional:_ Version assigned to single or micro-spec API specified in `specPath`. |
128
+ | `label` | `string` | `null` | _Optional:_ Version label used when generating version selector dropdown menu. |
129
+ | `baseUrl` | `string` | `null` | _Optional:_ Version base URL used when generating version selector dropdown menu. |
130
+ | `versions` | `object` | `null` | _Optional:_ Set of options for versioning configuration. See below for a list of supported options. |
110
131
 
111
132
  `sidebarOptions` can be configured with the following options:
112
133
 
113
134
  | Name | Type | Default | Description |
114
135
  | -------------------- | --------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
115
136
  | `groupPathsBy` | `string` | `null` | Organize and group sidebar slice by specified option. Note: Currently, `groupPathsBy` only contains support for grouping by `tag`. |
116
- | `categoryLinkSource` | `string` | `null` | Defines what source to use for rendering category link pages when grouping paths by tag. <br/></br>The supported options are as follows: <br/></br> `tag`: Sets the category link config type to `generated-index` and uses the tag description as the link config description. <br/><br/>`info`: Sets the category link config type to `doc` and renders the `info` section as the category link (recommended only for multi/micro-spec scenarios). |
137
+ | `categoryLinkSource` | `string` | `null` | Defines what source to use for rendering category link pages when grouping paths by tag. <br/><br/>The supported options are as follows: <br/><br/> `tag`: Sets the category link config type to `generated-index` and uses the tag description as the link config description. <br/><br/>`info`: Sets the category link config type to `doc` and renders the `info` section as the category link (recommended only for multi/micro-spec scenarios). |
117
138
  | `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. |
118
139
  | `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. |
119
140
  | `customProps` | `object` | `null` | Additional props for customizing a sidebar item. |
120
141
 
121
- > Note: You may optionally configure a `sidebarOptions`. In doing so, an individual `sidebar.js` slice with the configured options will be generated within the respective `outputDir`.
142
+ > You may optionally configure a `sidebarOptions`. In doing so, an individual `sidebar.js` slice with the configured options will be generated within the respective `outputDir`.
143
+
144
+ `versions` can be configured with the following options:
145
+
146
+ | Name | Type | Default | Description |
147
+ | ---------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------ |
148
+ | `specPath` | `string` | `null` | Designated URL or path to the source of an OpenAPI specification file or directory of micro OpenAPI specification files. |
149
+ | `ouputDir` | `string` | `null` | Desired output path for versioned, generated MDX files. |
150
+ | `label` | `string` | `null` | _Optional:_ Version label used when generating version selector dropdown menu. |
151
+ | `baseUrl` | `string` | `null` | _Optional:_ Version base URL used when generating version selector dropdown menu. |
152
+
153
+ > All versions will automatically inherit `sidebarOptions` from the parent/base config.
122
154
 
123
155
  ## CLI Usage
124
156
 
@@ -139,9 +171,11 @@ Commands:
139
171
  write-translations [options] [siteDir] Extract required translations of your site.
140
172
  write-heading-ids [options] [siteDir] [files...] Generate heading ids in Markdown content.
141
173
  docs:version <version> Tag a new docs version
142
- gen-api-docs <id> Generates API Docs mdx and sidebars.
143
- clean-api-docs <id> Clears the Generated API Docs mdx and sidebars.
144
- docs:version:openapi <version> Tag a new docs version (openapi)
174
+ gen-api-docs <id> Generates OpenAPI docs in MDX file format and sidebar.js (if enabled).
175
+ gen-api-docs:version <id:version> Generates versioned OpenAPI docs in MDX file format, versions.js and sidebar.js (if enabled).
176
+ clean-api-docs <id> Clears the generated OpenAPI docs MDX files and sidebar.js (if enabled).
177
+ clean-api-docs:version <id:version> Clears the versioned, generated OpenAPI docs MDX files, versions.json and sidebar.js (if
178
+ enabled).
145
179
  ```
146
180
 
147
181
  ### Generating OpenAPI Docs
@@ -190,6 +224,61 @@ yarn docusaurus clean-api-docs burgers
190
224
 
191
225
  > The example above will remove all API docs relative to `burgers`.
192
226
 
227
+ ### Versioning OpenAPI docs
228
+
229
+ To generate _all_ versioned OpenAPI docs, run the following command from the root directory of your project:
230
+
231
+ ```bash
232
+ yarn docusaurus gen-api-docs:version <id>:all
233
+ ```
234
+
235
+ Example:
236
+
237
+ ```bash
238
+ yarn docusaurus gen-api-docs:version petstore:all
239
+ ```
240
+
241
+ > This will generate API docs for all of the OpenAPI specification (OAS) files referenced in your `versions` config and will also generate a `versions.json` file.
242
+
243
+ > Substitue `all` with a specific version ID to generate/clean a specific version. Generating for `all` or a specific version ID will automatically update the `versions.json` file.
244
+
245
+ ## Installing from Template
246
+
247
+ Run the following to bootstrap a Docsaurus v2 site (classic theme) with `docusaurus-openapi-docs`:
248
+
249
+ ```bash
250
+ npx create-docusaurus@2.0.0-beta.21 my-website --package-manager yarn
251
+ ```
252
+
253
+ > When prompted to select a template choose `Git repository`.
254
+
255
+ Template Repository URL:
256
+
257
+ ```bash
258
+ https://github.com/PaloAltoNetworks/docusaurus-template-openapi-docs.git
259
+ ```
260
+
261
+ > When asked how the template repo should be cloned choose "copy" (unless you know better).
262
+
263
+ ```bash
264
+ cd my-website
265
+ yarn
266
+ ```
267
+
268
+ ## Developer Quick Start
269
+
270
+ > Looking to make a contribution? Make sure to checkout out our contributing guide.
271
+
272
+ After [forking](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/fork) the main repository, run the following:
273
+
274
+ ```bash
275
+ git clone https://github.com/<your account>/docusaurus-openapi-docs.git
276
+ cd docusaurus-openapi-docs
277
+ yarn
278
+ yarn build-packages
279
+ yarn watch:demo
280
+ ```
281
+
193
282
  ## Support
194
283
 
195
- Please read [SUPPORT.md](SUPPORT.md) for details on how to get support for this project.
284
+ Please read [SUPPORT.md](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/blob/main/SUPPORT.md) for details on how to get support for this project.
package/lib/index.d.ts CHANGED
@@ -1,4 +1,9 @@
1
1
  import type { LoadContext, Plugin } from "@docusaurus/types";
2
2
  import type { PluginOptions, LoadedContent } from "./types";
3
3
  export declare function isURL(str: string): boolean;
4
- export default function pluginOpenAPI(context: LoadContext, options: PluginOptions): Plugin<LoadedContent>;
4
+ export declare function getDocsData(dataArray: any[], filter: string): Object | undefined;
5
+ declare function pluginOpenAPIDocs(context: LoadContext, options: PluginOptions): Plugin<LoadedContent>;
6
+ declare namespace pluginOpenAPIDocs {
7
+ var validateOptions: ({ options, validate }: any) => any;
8
+ }
9
+ export default pluginOpenAPIDocs;
package/lib/index.js CHANGED
@@ -9,7 +9,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
9
9
  return (mod && mod.__esModule) ? mod : { "default": mod };
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.isURL = void 0;
12
+ exports.getDocsData = exports.isURL = void 0;
13
13
  const fs_1 = __importDefault(require("fs"));
14
14
  const path_1 = __importDefault(require("path"));
15
15
  const utils_1 = require("@docusaurus/utils");
@@ -17,21 +17,59 @@ const chalk_1 = __importDefault(require("chalk"));
17
17
  const mustache_1 = require("mustache");
18
18
  const markdown_1 = require("./markdown");
19
19
  const openapi_1 = require("./openapi");
20
+ const options_1 = require("./options");
20
21
  const sidebars_1 = __importDefault(require("./sidebars"));
21
22
  function isURL(str) {
22
23
  return /^(https?:)\/\//m.test(str);
23
24
  }
24
25
  exports.isURL = isURL;
25
- function pluginOpenAPI(context, options) {
26
- let { config } = options;
27
- let { siteDir } = context;
26
+ function getDocsData(dataArray, filter) {
27
+ // eslint-disable-next-line array-callback-return
28
+ const filteredData = dataArray.filter((data) => {
29
+ if (data[0] === filter) {
30
+ return data[1];
31
+ }
32
+ // Search plugin-content-docs instances
33
+ if (data[0] === "@docusaurus/plugin-content-docs") {
34
+ const pluginId = data[1].id ? data[1].id : "default";
35
+ if (pluginId === filter) {
36
+ return data[1];
37
+ }
38
+ }
39
+ })[0];
40
+ if (filteredData) {
41
+ // Search presets, e.g. "classic"
42
+ if (filteredData[0] === filter) {
43
+ return filteredData[1].docs;
44
+ }
45
+ // Search plugin-content-docs instances
46
+ if (filteredData[0] === "@docusaurus/plugin-content-docs") {
47
+ const pluginId = filteredData[1].id ? filteredData[1].id : "default";
48
+ if (pluginId === filter) {
49
+ return filteredData[1];
50
+ }
51
+ }
52
+ }
53
+ return;
54
+ }
55
+ exports.getDocsData = getDocsData;
56
+ function pluginOpenAPIDocs(context, options) {
57
+ const { config, docsPluginId } = options;
58
+ const { siteDir, siteConfig } = context;
59
+ // Get routeBasePath and path from plugin-content-docs or preset
60
+ const presets = siteConfig.presets;
61
+ const plugins = siteConfig.plugins;
62
+ const presetsPlugins = presets.concat(plugins);
63
+ const docData = getDocsData(presetsPlugins, docsPluginId);
64
+ const docRouteBasePath = docData ? docData.routeBasePath : undefined;
65
+ const docPath = docData ? (docData.path ? docData.path : "docs") : undefined;
28
66
  async function generateApiDocs(options) {
29
67
  let { specPath, outputDir, template, sidebarOptions } = options;
30
68
  const contentPath = isURL(specPath)
31
69
  ? specPath
32
70
  : path_1.default.resolve(siteDir, specPath);
33
71
  try {
34
- const openapiFiles = await (0, openapi_1.readOpenapiFiles)(contentPath, {});
72
+ const openapiFiles = await (0, openapi_1.readOpenapiFiles)(contentPath, options);
35
73
  const [loadedApi, tags] = await (0, openapi_1.processOpenapiFiles)(openapiFiles, sidebarOptions);
36
74
  if (!fs_1.default.existsSync(outputDir)) {
37
75
  try {
@@ -44,8 +82,7 @@ function pluginOpenAPI(context, options) {
44
82
  }
45
83
  // TODO: figure out better way to set default
46
84
  if (Object.keys(sidebarOptions !== null && sidebarOptions !== void 0 ? sidebarOptions : {}).length > 0) {
47
- const sidebarSlice = (0, sidebars_1.default)(sidebarOptions, // TODO: find a better way to handle null
48
- options, loadedApi, tags);
85
+ const sidebarSlice = (0, sidebars_1.default)(sidebarOptions, options, loadedApi, tags, docPath);
49
86
  const sidebarSliceTemplate = template
50
87
  ? fs_1.default.readFileSync(template).toString()
51
88
  : `module.exports = {{{slice}}};`;
@@ -135,8 +172,14 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
135
172
  item.markdown = markdown;
136
173
  if (item.type === "api") {
137
174
  item.json = JSON.stringify(item.api);
175
+ let infoBasePath = `${outputDir}/${item.infoId}`;
176
+ if (docRouteBasePath) {
177
+ infoBasePath = `${docRouteBasePath}/${outputDir
178
+ .split(docPath)[1]
179
+ .replace(/^\/+/g, "")}/${item.infoId}`.replace(/^\/+/g, "");
180
+ }
138
181
  if (item.infoId)
139
- item.infoPath = `${outputDir}/${item.infoId}`;
182
+ item.infoPath = infoBasePath;
140
183
  }
141
184
  const view = (0, mustache_1.render)(mdTemplate, item);
142
185
  const utils = (0, mustache_1.render)(infoMdTemplate, item);
@@ -192,9 +235,11 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
192
235
  const apiDir = path_1.default.join(siteDir, outputDir);
193
236
  const apiMdxFiles = await (0, utils_1.Globby)(["*.api.mdx", "*.info.mdx", "*.tag.mdx"], {
194
237
  cwd: path_1.default.resolve(apiDir),
238
+ deep: 1,
195
239
  });
196
240
  const sidebarFile = await (0, utils_1.Globby)(["sidebar.js"], {
197
241
  cwd: path_1.default.resolve(apiDir),
242
+ deep: 1,
198
243
  });
199
244
  apiMdxFiles.map((mdx) => fs_1.default.unlink(`${apiDir}/${mdx}`, (err) => {
200
245
  if (err) {
@@ -213,18 +258,48 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
213
258
  }
214
259
  }));
215
260
  }
261
+ async function generateVersions(versions, outputDir) {
262
+ let versionsArray = [];
263
+ for (const [version, metadata] of Object.entries(versions)) {
264
+ versionsArray.push({
265
+ version: version,
266
+ label: metadata.label,
267
+ baseUrl: metadata.baseUrl,
268
+ });
269
+ }
270
+ const versionsJson = JSON.stringify(versionsArray, null, 2);
271
+ try {
272
+ fs_1.default.writeFileSync(`${outputDir}/versions.json`, versionsJson, "utf8");
273
+ console.log(chalk_1.default.green(`Successfully created "${outputDir}/versions.json"`));
274
+ }
275
+ catch (err) {
276
+ console.error(chalk_1.default.red(`Failed to write "${outputDir}/versions.json"`), chalk_1.default.yellow(err));
277
+ }
278
+ }
279
+ async function cleanVersions(outputDir) {
280
+ if (fs_1.default.existsSync(`${outputDir}/versions.json`)) {
281
+ fs_1.default.unlink(`${outputDir}/versions.json`, (err) => {
282
+ if (err) {
283
+ console.error(chalk_1.default.red(`Cleanup failed for "${outputDir}/versions.json"`), chalk_1.default.yellow(err));
284
+ }
285
+ else {
286
+ console.log(chalk_1.default.green(`Cleanup succeeded for "${outputDir}/versions.json"`));
287
+ }
288
+ });
289
+ }
290
+ }
216
291
  return {
217
- name: `docusaurus-plugin-openapi`,
292
+ name: `docusaurus-plugin-openapi-docs`,
218
293
  extendCli(cli) {
219
294
  cli
220
295
  .command(`gen-api-docs`)
221
- .description(`Generates API Docs mdx and sidebars.`)
222
- .usage("[options] <id key value in plugin config within docusaurus.config.js>")
296
+ .description(`Generates OpenAPI docs in MDX file format and sidebar.js (if enabled).`)
297
+ .usage("<id>")
223
298
  .arguments("<id>")
224
299
  .action(async (id) => {
225
300
  if (id === "all") {
226
301
  if (config[id]) {
227
- console.error(chalk_1.default.red("Can't use id 'all' for API Doc."));
302
+ console.error(chalk_1.default.red("Can't use id 'all' for OpenAPI docs configuration key."));
228
303
  }
229
304
  else {
230
305
  Object.keys(config).forEach(async function (key) {
@@ -233,21 +308,71 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
233
308
  }
234
309
  }
235
310
  else if (!config[id]) {
236
- console.error(chalk_1.default.red(`ID ${id} does not exist in openapi-plugin config`));
311
+ console.error(chalk_1.default.red(`ID '${id}' does not exist in OpenAPI docs config.`));
237
312
  }
238
313
  else {
239
314
  await generateApiDocs(config[id]);
240
315
  }
241
316
  });
317
+ cli
318
+ .command(`gen-api-docs:version`)
319
+ .description(`Generates versioned OpenAPI docs in MDX file format, versions.js and sidebar.js (if enabled).`)
320
+ .usage("<id:version>")
321
+ .arguments("<id:version>")
322
+ .action(async (id) => {
323
+ const [parentId, versionId] = id.split(":");
324
+ const parentConfig = Object.assign({}, config[parentId]);
325
+ const version = parentConfig.version;
326
+ const label = parentConfig.label;
327
+ const baseUrl = parentConfig.baseUrl;
328
+ let parentVersion = {};
329
+ parentVersion[version] = { label: label, baseUrl: baseUrl };
330
+ const { versions } = config[parentId];
331
+ const mergedVersions = Object.assign(parentVersion, versions);
332
+ // Prepare for merge
333
+ delete parentConfig.versions;
334
+ delete parentConfig.version;
335
+ delete parentConfig.label;
336
+ delete parentConfig.baseUrl;
337
+ // TODO: handle when no versions are defined by version command is passed
338
+ if (versionId === "all") {
339
+ if (versions[id]) {
340
+ console.error(chalk_1.default.red("Can't use id 'all' for OpenAPI docs versions configuration key."));
341
+ }
342
+ else {
343
+ await generateVersions(mergedVersions, parentConfig.outputDir);
344
+ Object.keys(versions).forEach(async (key) => {
345
+ const versionConfig = versions[key];
346
+ const mergedConfig = {
347
+ ...parentConfig,
348
+ ...versionConfig,
349
+ };
350
+ await generateApiDocs(mergedConfig);
351
+ });
352
+ }
353
+ }
354
+ else if (!versions[versionId]) {
355
+ console.error(chalk_1.default.red(`Version ID '${versionId}' does not exist in OpenAPI docs versions config.`));
356
+ }
357
+ else {
358
+ const versionConfig = versions[versionId];
359
+ const mergedConfig = {
360
+ ...parentConfig,
361
+ ...versionConfig,
362
+ };
363
+ await generateVersions(mergedVersions, parentConfig.outputDir);
364
+ await generateApiDocs(mergedConfig);
365
+ }
366
+ });
242
367
  cli
243
368
  .command(`clean-api-docs`)
244
- .description(`Clears the Generated API Docs mdx and sidebars.`)
245
- .usage("[options] <id key value in plugin config within docusaurus.config.js>")
369
+ .description(`Clears the generated OpenAPI docs MDX files and sidebar.js (if enabled).`)
370
+ .usage("<id>")
246
371
  .arguments("<id>")
247
372
  .action(async (id) => {
248
373
  if (id === "all") {
249
374
  if (config[id]) {
250
- console.error(chalk_1.default.red("Can't use id 'all' for API Doc."));
375
+ console.error(chalk_1.default.red("Can't use id 'all' for OpenAPI docs configuration key."));
251
376
  }
252
377
  else {
253
378
  Object.keys(config).forEach(async function (key) {
@@ -259,7 +384,46 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
259
384
  await cleanApiDocs(config[id]);
260
385
  }
261
386
  });
387
+ cli
388
+ .command(`clean-api-docs:version`)
389
+ .description(`Clears the versioned, generated OpenAPI docs MDX files, versions.json and sidebar.js (if enabled).`)
390
+ .usage("<id:version>")
391
+ .arguments("<id:version>")
392
+ .action(async (id) => {
393
+ const [parentId, versionId] = id.split(":");
394
+ const { versions } = config[parentId];
395
+ const parentConfig = Object.assign({}, config[parentId]);
396
+ delete parentConfig.versions;
397
+ if (versionId === "all") {
398
+ if (versions[id]) {
399
+ chalk_1.default.red("Can't use id 'all' for OpenAPI docs versions configuration key.");
400
+ }
401
+ else {
402
+ await cleanVersions(parentConfig.outputDir);
403
+ Object.keys(versions).forEach(async (key) => {
404
+ const versionConfig = versions[key];
405
+ const mergedConfig = {
406
+ ...parentConfig,
407
+ ...versionConfig,
408
+ };
409
+ await cleanApiDocs(mergedConfig);
410
+ });
411
+ }
412
+ }
413
+ else {
414
+ const versionConfig = versions[versionId];
415
+ const mergedConfig = {
416
+ ...parentConfig,
417
+ ...versionConfig,
418
+ };
419
+ await cleanApiDocs(mergedConfig);
420
+ }
421
+ });
262
422
  },
263
423
  };
264
424
  }
265
- exports.default = pluginOpenAPI;
425
+ exports.default = pluginOpenAPIDocs;
426
+ pluginOpenAPIDocs.validateOptions = ({ options, validate }) => {
427
+ const validatedOptions = validate(options_1.OptionsSchema, options);
428
+ return validatedOptions;
429
+ };
@@ -19,6 +19,8 @@ function createParamsDetails({ parameters, type }) {
19
19
  return undefined;
20
20
  }
21
21
  return (0, createDetails_1.createDetails)({
22
+ "data-collapsed": false,
23
+ open: true,
22
24
  style: { marginBottom: "1rem" },
23
25
  children: [
24
26
  (0, createDetailsSummary_1.createDetailsSummary)({
@@ -206,6 +206,8 @@ function createSchemaDetails({ title, body, ...rest }) {
206
206
  }
207
207
  }
208
208
  return (0, createDetails_1.createDetails)({
209
+ "data-collapsed": false,
210
+ open: true,
209
211
  ...rest,
210
212
  children: [
211
213
  (0, createDetailsSummary_1.createDetailsSummary)({
@@ -40,7 +40,7 @@ exports.createApiPageMD = createApiPageMD;
40
40
  function createInfoPageMD({ info: { title, version, description, contact, license, termsOfService }, securitySchemes, }) {
41
41
  return (0, utils_1.render)([
42
42
  `import Tabs from "@theme/Tabs";\n`,
43
- `import TabItem from "@theme/TabItem";\n`,
43
+ `import TabItem from "@theme/TabItem";\n\n`,
44
44
  (0, createVersionBadge_1.createVersionBadge)(version),
45
45
  `# ${(0, lodash_1.escape)(title)}\n\n`,
46
46
  (0, createDescription_1.createDescription)(description),
@@ -1,11 +1,11 @@
1
- import { ApiMetadata, SidebarOptions } from "../types";
1
+ import { ApiMetadata, APIOptions, SidebarOptions } from "../types";
2
2
  import { OpenApiObjectWithRef, TagObject } from "./types";
3
3
  interface OpenApiFiles {
4
4
  source: string;
5
5
  sourceDirName: string;
6
6
  data: OpenApiObjectWithRef;
7
7
  }
8
- export declare function readOpenapiFiles(openapiPath: string, _options: {}): Promise<OpenApiFiles[]>;
8
+ export declare function readOpenapiFiles(openapiPath: string, options: APIOptions): Promise<OpenApiFiles[]>;
9
9
  export declare function processOpenapiFiles(files: OpenApiFiles[], sidebarOptions: SidebarOptions): Promise<[ApiMetadata[], TagObject[]]>;
10
10
  export declare function processOpenapiFile(openapiDataWithRefs: OpenApiObjectWithRef, sidebarOptions: SidebarOptions): Promise<[ApiMetadata[], TagObject[]]>;
11
11
  export declare function getTagDisplayName(tagName: string, tags: TagObject[]): string;
@@ -188,7 +188,10 @@ function bindCollectionToApiItems(items, postmanCollection) {
188
188
  }
189
189
  });
190
190
  }
191
- async function readOpenapiFiles(openapiPath, _options) {
191
+ async function readOpenapiFiles(openapiPath, options) {
192
+ // TODO: determine if this should be an API option
193
+ // Forces the json-schema-ref-parser
194
+ const parseJsonRefs = true;
192
195
  if (!(0, index_1.isURL)(openapiPath)) {
193
196
  const stat = await fs_extra_1.default.lstat(openapiPath);
194
197
  if (stat.isDirectory()) {
@@ -203,7 +206,7 @@ async function readOpenapiFiles(openapiPath, _options) {
203
206
  return Promise.all(sources.map(async (source) => {
204
207
  // TODO: make a function for this
205
208
  const fullPath = path_1.default.join(openapiPath, source);
206
- const data = (await (0, loadAndBundleSpec_1.loadAndBundleSpec)(fullPath));
209
+ const data = (await (0, loadAndBundleSpec_1.loadAndBundleSpec)(fullPath, parseJsonRefs));
207
210
  return {
208
211
  source: fullPath,
209
212
  sourceDirName: path_1.default.dirname(source),
@@ -212,7 +215,7 @@ async function readOpenapiFiles(openapiPath, _options) {
212
215
  }));
213
216
  }
214
217
  }
215
- const data = (await (0, loadAndBundleSpec_1.loadAndBundleSpec)(openapiPath));
218
+ const data = (await (0, loadAndBundleSpec_1.loadAndBundleSpec)(openapiPath, parseJsonRefs));
216
219
  return [
217
220
  {
218
221
  source: openapiPath,
@@ -15,7 +15,7 @@ const _1 = require(".");
15
15
  describe("openapi", () => {
16
16
  describe("readOpenapiFiles", () => {
17
17
  it("readOpenapiFiles", async () => {
18
- const results = await (0, _1.readOpenapiFiles)(path_1.default.join(__dirname, "__fixtures__/examples"), {});
18
+ const results = await (0, _1.readOpenapiFiles)(path_1.default.join(__dirname, "__fixtures__/examples"), { specPath: "./", outputDir: "./" });
19
19
  const categoryMeta = results.find((x) => x.source.endsWith("_category_.json"));
20
20
  expect(categoryMeta).toBeFalsy();
21
21
  // console.log(results);
@@ -1,3 +1,3 @@
1
1
  import { OpenAPISpec } from "./types";
2
- export declare function loadAndBundleSpec(specUrlOrObject: object | string): Promise<OpenAPISpec>;
2
+ export declare function loadAndBundleSpec(specUrlOrObject: object | string, parseJsonRefs: boolean | undefined): Promise<OpenAPISpec>;
3
3
  export declare function convertSwagger2OpenAPI(spec: any): Promise<OpenAPISpec>;
@@ -5,12 +5,39 @@
5
5
  * This source code is licensed under the MIT license found in the
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  * ========================================================================== */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
8
11
  Object.defineProperty(exports, "__esModule", { value: true });
9
12
  exports.convertSwagger2OpenAPI = exports.loadAndBundleSpec = void 0;
13
+ // @ts-nocheck
14
+ const json_schema_ref_parser_1 = __importDefault(require("@apidevtools/json-schema-ref-parser"));
10
15
  const bundle_1 = require("@redocly/openapi-core/lib/bundle");
11
16
  const config_1 = require("@redocly/openapi-core/lib/config/config");
17
+ const chalk_1 = __importDefault(require("chalk"));
12
18
  const swagger2openapi_1 = require("swagger2openapi");
13
- async function loadAndBundleSpec(specUrlOrObject) {
19
+ async function resolveJsonRefs(specUrlOrObject) {
20
+ var _a, _b;
21
+ try {
22
+ let schema = await json_schema_ref_parser_1.default.dereference(specUrlOrObject, {
23
+ continueOnError: true,
24
+ resolve: {
25
+ http: {
26
+ timeout: 15000, // 15 sec timeout
27
+ },
28
+ },
29
+ dereference: {
30
+ circular: "ignore",
31
+ },
32
+ });
33
+ return schema;
34
+ }
35
+ catch (err) {
36
+ console.error(chalk_1.default.yellow((_b = (_a = err.errors[0]) === null || _a === void 0 ? void 0 : _a.message) !== null && _b !== void 0 ? _b : err));
37
+ return;
38
+ }
39
+ }
40
+ async function loadAndBundleSpec(specUrlOrObject, parseJsonRefs) {
14
41
  const config = new config_1.Config({});
15
42
  const bundleOpts = {
16
43
  config,
@@ -28,6 +55,14 @@ async function loadAndBundleSpec(specUrlOrObject) {
28
55
  // Force dereference ?
29
56
  // bundleOpts["dereference"] = true;
30
57
  const { bundle: { parsed }, } = await (0, bundle_1.bundle)(bundleOpts);
58
+ if (parseJsonRefs) {
59
+ const resolved = resolveJsonRefs(parsed);
60
+ return typeof resolved === Object
61
+ ? resolved.swagger !== undefined
62
+ ? convertSwagger2OpenAPI(resolved)
63
+ : resolved
64
+ : parsed;
65
+ }
31
66
  return parsed.swagger !== undefined ? convertSwagger2OpenAPI(parsed) : parsed;
32
67
  }
33
68
  exports.loadAndBundleSpec = loadAndBundleSpec;
package/lib/options.d.ts CHANGED
@@ -1,4 +1,2 @@
1
1
  import { Joi } from "@docusaurus/utils-validation";
2
- import type { PluginOptions } from "./types";
3
- export declare const DEFAULT_OPTIONS: PluginOptions;
4
2
  export declare const OptionsSchema: Joi.ObjectSchema<any>;