Skip to content

Commit 6c5ba16

Browse files
committed
feat: generate API docs
1 parent 7db000c commit 6c5ba16

File tree

6 files changed

+540
-4
lines changed

6 files changed

+540
-4
lines changed

docs/src/pages/reference/configuration/output.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,26 @@ Default Value: `en`.
386386

387387
Give you the possibility to set the locale for the mock generation. It is used by faker, see the list of available options [here](https://fakerjs.dev/guide/localization.html#available-locales). It should also be strongly typed using `defineConfig`.
388388

389+
### docs
390+
391+
Type: `Boolean | Object`.
392+
393+
Default Value: `false`.
394+
395+
Will generate API docs using [TypeDoc](https://typedoc.org/). by default these docs will be in Markdown format.
396+
397+
TypeDoc can be configured by creating a config file e.g. `typedoc.config.mjs` in your project root (see the [config docs](https://typedoc.org/options/configuration/#options) for a full list of supported file names) or by passing a config filename to the `config` option below.
398+
399+
See the TypeDoc [configuration documentation](https://typedoc.org/options/) for more details.
400+
401+
The `docs` option can take some properties to customize the generation if you set it to an object. If you set it to `true`, the default options will be used.
402+
403+
#### config
404+
405+
Type: `String`.
406+
407+
Use to specify a TypeDoc config filename. This can be useful if your project already has a TypeDoc config for other docs.
408+
389409
### clean
390410

391411
Type: `Boolean | String[]`.

packages/core/src/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export type NormalizedOutputOptions = {
5050
client: OutputClient | OutputClientFunc;
5151
httpClient: OutputHttpClient;
5252
clean: boolean | string[];
53+
docs: boolean | OutputDocsOptions;
5354
prettier: boolean;
5455
tslint: boolean;
5556
biome: boolean;
@@ -174,6 +175,7 @@ export type OutputOptions = {
174175
client?: OutputClient | OutputClientFunc;
175176
httpClient?: OutputHttpClient;
176177
clean?: boolean | string[];
178+
docs?: boolean | OutputDocsOptions;
177179
prettier?: boolean;
178180
tslint?: boolean;
179181
biome?: boolean;
@@ -239,6 +241,10 @@ export const OutputMode = {
239241

240242
export type OutputMode = (typeof OutputMode)[keyof typeof OutputMode];
241243

244+
export type OutputDocsOptions = {
245+
config: string;
246+
};
247+
242248
// TODO: add support for other mock types (like cypress or playwright)
243249
export const OutputMockType = {
244250
MSW: 'msw',

packages/orval/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@
7575
"lodash.uniq": "^4.5.0",
7676
"openapi3-ts": "4.2.2",
7777
"string-argv": "^0.3.2",
78-
"tsconfck": "^2.0.1"
78+
"tsconfck": "^2.0.1",
79+
"typedoc": "0.26.11",
80+
"typedoc-plugin-markdown": "4.2.10",
81+
"typescript": "^5.6.3"
7982
}
8083
}

packages/orval/src/utils/options.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ export const normalizeOptions = async (
148148
mode: normalizeOutputMode(outputOptions.mode ?? mode),
149149
mock,
150150
clean: outputOptions.clean ?? clean ?? false,
151+
docs: outputOptions.docs ?? false,
151152
prettier: outputOptions.prettier ?? prettier ?? false,
152153
tslint: outputOptions.tslint ?? tslint ?? false,
153154
biome: outputOptions.biome ?? biome ?? false,

packages/orval/src/write-specs.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
import chalk from 'chalk';
1919
import execa from 'execa';
2020
import fs from 'fs-extra';
21+
import { Application } from 'typedoc';
2122
import uniq from 'lodash.uniq';
2223
import { InfoObject } from 'openapi3-ts/oas30';
2324
import { executeHook } from './utils';
@@ -198,6 +199,51 @@ export const writeSpecs = async (
198199
}
199200
}
200201

202+
if (output.docs) {
203+
try {
204+
const app = await Application.bootstrapWithPlugins({
205+
entryPoints: paths,
206+
// Set the custom config location if it has been provided.
207+
...(typeof output.docs === 'object'
208+
? { options: output.docs.config }
209+
: {}),
210+
plugin: ['typedoc-plugin-markdown'],
211+
});
212+
// Set defaults if the have not been provided by the external config.
213+
if (!app.options.isSet('readme')) {
214+
app.options.setValue('readme', 'none');
215+
}
216+
if (!app.options.isSet('logLevel')) {
217+
app.options.setValue('logLevel', 'None');
218+
}
219+
const project = await app.convert();
220+
if (project) {
221+
let out = 'docs';
222+
if (app.options.isSet('out')) {
223+
// Use the output location if it has been set in the external config.
224+
out = app.options.getValue('out');
225+
} else if (output.workspace) {
226+
// Generate the docs in the workspace.
227+
out = upath.join(output.workspace, 'docs');
228+
} else if (output.target) {
229+
const base = upath.dirname(output.target);
230+
// Generate the docs along side the output target.
231+
out = upath.join(base, 'docs');
232+
}
233+
await app.generateDocs(project, out);
234+
} else {
235+
throw new Error('TypeDoc not initialised');
236+
}
237+
} catch (e: any) {
238+
const message =
239+
e.exitCode === 1
240+
? e.stdout + e.stderr
241+
: `⚠️ ${projectTitle ? `${projectTitle} - ` : ''}Unable to generate docs`;
242+
243+
log(chalk.yellow(message));
244+
}
245+
}
246+
201247
createSuccessMessage(projectTitle);
202248
};
203249

0 commit comments

Comments
 (0)