@@ -6,16 +6,25 @@ import type {
6
6
OptionValidationContext ,
7
7
} from '@docusaurus/types' ;
8
8
import { normalizeUrl } from '@docusaurus/utils' ;
9
- import YAML from 'yaml' ;
10
9
import { loadAndBundleSpec } from 'redoc' ;
10
+ import {
11
+ formatProblems ,
12
+ getTotals ,
13
+ Config ,
14
+ bundle ,
15
+ loadConfig ,
16
+ stringifyYaml ,
17
+ } from '@redocly/openapi-core' ;
11
18
12
19
import {
13
20
PluginOptionSchema ,
14
21
PluginOptions ,
15
22
PluginOptionsWithDefault ,
16
23
DEFAULT_OPTIONS ,
17
24
} from './options' ;
18
- import { ParsedSpec , SpecProps , ApiDocProps } from './types/common' ;
25
+ import { SpecProps , ApiDocProps } from './types/common' ;
26
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
27
+ const version = require ( '../package.json' ) . version ;
19
28
20
29
export { PluginOptions } ;
21
30
@@ -25,50 +34,69 @@ export default function redocPlugin(
25
34
) : Plugin < Record < string , unknown > > {
26
35
const { baseUrl } = context . siteConfig ;
27
36
const options : PluginOptionsWithDefault = { ...DEFAULT_OPTIONS , ...opts } ;
28
- const { debug, spec, url : downloadUrl } = options ;
37
+ const { debug, spec, url : downloadUrl , config } = options ;
38
+
29
39
let url = downloadUrl ;
40
+ const isSpecFile = fs . existsSync ( spec ) ;
41
+ const fileName = path . join (
42
+ 'redocusaurus' ,
43
+ `${ options . id || 'api-spec' } .yaml` ,
44
+ ) ;
45
+
30
46
if ( debug ) {
31
47
console . error ( '[REDOCUSAURUS_PLUGIN] Opts Input:' , opts ) ;
32
48
console . error ( '[REDOCUSAURUS_PLUGIN] Options:' , options ) ;
33
49
}
34
50
return {
35
51
name : 'docusaurus-plugin-redoc' ,
36
52
async loadContent ( ) {
37
- let parsedSpec : ParsedSpec | null = null ;
38
- // If local file
39
- if ( fs . existsSync ( spec ) ) {
53
+ if ( ! isSpecFile ) {
54
+ // If spec is a remote url then add it as download url also as a default
55
+ url = url || spec ;
40
56
if ( debug ) {
41
- console . log ( '[REDOCUSAURUS_PLUGIN] reading file: ' , spec ) ;
57
+ console . log ( '[REDOCUSAURUS_PLUGIN] bundling spec from url ' , spec ) ;
42
58
}
59
+ return loadAndBundleSpec ( spec ! ) ;
60
+ }
61
+
62
+ // If local file
63
+ if ( debug ) {
64
+ console . log ( '[REDOCUSAURUS_PLUGIN] reading file: ' , spec ) ;
65
+ }
43
66
44
- const file = fs . readFileSync ( spec ) . toString ( ) ;
67
+ let redoclyConfig : Config ;
45
68
46
- if ( spec . endsWith ( '.yaml' ) || spec . endsWith ( '.yml' ) ) {
47
- parsedSpec = YAML . parse ( file ) ;
48
- } else parsedSpec = JSON . parse ( file ) ;
69
+ if ( config ) {
70
+ if ( typeof config === 'string' ) {
71
+ redoclyConfig = await loadConfig ( config ) ;
72
+ } else {
73
+ redoclyConfig = new Config ( config ) ;
74
+ }
49
75
} else {
50
- // If spec is a remote url then add it as download url
51
- url = spec ;
76
+ redoclyConfig = await loadConfig ( ) ;
52
77
}
53
78
54
- if ( debug ) {
55
- console . log ( '[REDOCUSAURUS_PLUGIN] bundling spec' ) ;
79
+ const { bundle : bundledSpec , problems } = await bundle ( {
80
+ ref : spec ,
81
+ config : redoclyConfig ,
82
+ } ) ;
83
+
84
+ if ( problems ?. length ) {
85
+ console . error ( '[REDOCUSAURUS_PLUGIN] errors while bundling spec' , spec ) ;
86
+
87
+ formatProblems ( problems , {
88
+ totals : getTotals ( problems ) ,
89
+ version,
90
+ } ) ;
56
91
}
57
- const content = await loadAndBundleSpec ( parsedSpec || spec ! ) ;
58
92
59
93
if ( debug ) {
60
- console . log ( '[REDOCUSAURUS_PLUGIN] Content loaded ' ) ;
94
+ console . log ( '[REDOCUSAURUS_PLUGIN] File Bundled ' ) ;
61
95
}
62
96
63
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
64
- return content as any ;
65
- } ,
66
- getPathsToWatch ( ) {
67
- if ( ! spec ) {
68
- return [ ] ;
69
- }
70
- const contentPath = path . resolve ( context . siteDir , spec ) ;
71
- return [ contentPath ] ;
97
+ // If download url is not provided then use bundled yaml as a static file (see `postBuild`)
98
+ url = url || fileName ;
99
+ return bundledSpec . parsed ;
72
100
} ,
73
101
async contentLoaded ( { content, actions } ) {
74
102
const { createData, addRoute, setGlobalData } = actions ;
@@ -114,6 +142,27 @@ export default function redocPlugin(
114
142
addRoute ( routeOptions ) ;
115
143
}
116
144
} ,
145
+ async postBuild ( props ) {
146
+ if ( ! isSpecFile || downloadUrl ) {
147
+ return ;
148
+ }
149
+ // Create a static file from bundled spec
150
+ const staticFile = path . join ( context . outDir , fileName ) ;
151
+ fs . mkdirSync ( path . dirname ( staticFile ) ) ;
152
+ console . error (
153
+ '[REDOCUSAURUS_PLUGIN] creating static bundle copy for download' ,
154
+ staticFile ,
155
+ ) ;
156
+ // create bundled url
157
+ const bundledYaml = stringifyYaml ( props . content ) ;
158
+ fs . writeFileSync ( staticFile , bundledYaml ) ;
159
+ } ,
160
+ getPathsToWatch ( ) {
161
+ if ( ! isSpecFile ) {
162
+ return [ ] ;
163
+ }
164
+ return [ path . resolve ( spec ) ] ;
165
+ } ,
117
166
} ;
118
167
}
119
168
0 commit comments