Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

💥 Use build time parsing of schemas 💥 #138

Merged
merged 33 commits into from
Mar 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
474d421
fix config
rohit-gohri Mar 12, 2022
62bafc2
add vercel support
rohit-gohri Mar 12, 2022
4a61225
💥 parse specUrls
rohit-gohri Mar 12, 2022
73910c3
💥 always render via store
rohit-gohri Mar 12, 2022
105c61b
use base url for specUrl
rohit-gohri Mar 12, 2022
3f58d0a
update examples
rohit-gohri Mar 12, 2022
9881df9
export hooks
rohit-gohri Mar 12, 2022
7d3710e
fix example build
rohit-gohri Mar 12, 2022
cd9f19f
fix schema imports
rohit-gohri Mar 12, 2022
8ec6df3
fix dev scripts
rohit-gohri Mar 12, 2022
e80c03a
docs(changeset): Parse schema at build time for urls too, remove supp…
rohit-gohri Mar 12, 2022
f7df055
fix url for vercel
rohit-gohri Mar 12, 2022
8adedfa
Merge branch 'main' of https://github.com/rohit-gohri/redocusaurus in…
rohit-gohri Mar 12, 2022
d24dfee
add common symlinked types
rohit-gohri Mar 12, 2022
37df72d
don't hide download button by default
rohit-gohri Mar 12, 2022
33627d2
💥 simplify plugin options
rohit-gohri Mar 12, 2022
3211730
💥 update theme options
rohit-gohri Mar 12, 2022
1d74856
fix plugin validation
rohit-gohri Mar 12, 2022
4213497
color needs to be a hex value
rohit-gohri Mar 12, 2022
bb214d6
💥 update theme components to match new plugin data
rohit-gohri Mar 12, 2022
3151f54
rename hook
rohit-gohri Mar 12, 2022
162aefa
fix type error
rohit-gohri Mar 12, 2022
e697ed6
custom simpler merge fn
rohit-gohri Mar 12, 2022
e45d3a0
update examples
rohit-gohri Mar 12, 2022
9e334be
set url automatically
rohit-gohri Mar 12, 2022
310984d
update types for modules
rohit-gohri Mar 12, 2022
d3d2a8c
use default only if id is not provided
rohit-gohri Mar 12, 2022
8d65f94
fix build
rohit-gohri Mar 12, 2022
ff71868
fix types for ServerStyle
rohit-gohri Mar 12, 2022
faa6eb1
🔨 do initial build for dev cmd
rohit-gohri Mar 12, 2022
117563e
docs(changeset): Simplify plugin/theme options
rohit-gohri Mar 12, 2022
8c26b35
docs(changeset): Add new `useSpecData` hook for programmatic use of p…
rohit-gohri Mar 12, 2022
25fada0
docs(changeset): Change default redoc options, download button not hi…
rohit-gohri Mar 12, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/many-trees-hug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'docusaurus-plugin-redoc': major
'docusaurus-theme-redoc': major
---

Parse schema at build time for urls too, remove support for relative urls
5 changes: 5 additions & 0 deletions .changeset/plenty-months-double.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'docusaurus-theme-redoc': major
---

Change default redoc options, download button not hidden by default
5 changes: 5 additions & 0 deletions .changeset/proud-lizards-itch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'docusaurus-theme-redoc': minor
---

Add new `useSpecData` hook for programmatic use of plugin data
7 changes: 7 additions & 0 deletions .changeset/sixty-cougars-ring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'docusaurus-plugin-redoc': major
'docusaurus-theme-redoc': major
'redocusaurus': major
---

Simplify plugin/theme options
83 changes: 41 additions & 42 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,43 +1,42 @@
{
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"graphql"
],
"eslint.options": {
"extentions": [".js", ".jsx", ".ts", ".tsx", ".graphql"]
},
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[javascript]": {
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll": true
}
},
"[javascriptreact]": {
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll": true
}
},
"[typescript]": {
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll": true
}
},
"[typescriptreact]": {
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll": true
}
},
"editor.tabCompletion": "on",
"editor.tabSize": 2,
"editor.rulers": [80, 120],
"typescript.tsdk": "node_modules/typescript/lib"
}

"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"graphql"
],
"eslint.options": {
"extensions": [".js", ".jsx", ".ts", ".tsx", ".graphql"]
},
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[javascript]": {
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll": true
}
},
"[javascriptreact]": {
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll": true
}
},
"[typescript]": {
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll": true
}
},
"[typescriptreact]": {
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll": true
}
},
"editor.tabCompletion": "on",
"editor.tabSize": 2,
"editor.rulers": [80, 120],
"typescript.tsdk": "node_modules/typescript/lib"
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"build:packages": "yarn workspaces foreach --exclude redocusaurus-website --exclude redocusaurus-monorepo -tpv run build",
"build:website": "yarn workspace redocusaurus exec 'echo \\\"$npm_package_version\\\" > $PROJECT_CWD/website/version.json' && yarn workspace redocusaurus-website run build",
"clean": "yarn workspaces foreach -Atv exec \"rm -rf dist* .tsbuild*.info\"",
"dev": "concurrently 'yarn dev:packages' 'yarn dev:website'",
"dev": "yarn build:packages && yarn workspaces foreach --exclude redocusaurus-monorepo -piv run dev",
"dev:packages": "yarn workspaces foreach --exclude redocusaurus-website --exclude redocusaurus-monorepo -piv run dev",
"dev:website": "yarn workspace redocusaurus-website run dev",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
Expand Down
29 changes: 11 additions & 18 deletions packages/docusaurus-plugin-redoc/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,28 @@

![npm](https://img.shields.io/npm/v/docusaurus-plugin-redoc?style=flat-square)

This plugin parses your OpenAPI spec files and creates pages using the `ApiDoc` component from your theme. Use with `docusaurus-theme-redoc`.
This plugin parses your OpenAPI spec files and makes them available as plugin data. Can use to creates pages using the `@theme/ApiDoc` component from your theme, or render it through custom react pages.

Read More Here: <https://github.com/rohit-gohri/redocusaurus>
⚠️⚠️⚠️ NOTE: Not recommended for direct use. Use through main package instead: [`redocusaurus`](https://github.com/rohit-gohri/redocusaurus)

## Options

Either of `spec` or `specUrl` is required (both can also be provided).
### spec (required, string: file path or remote absolute url)

### spec
Either a file path to an OpenAPI YAML/JSON file, or a url to one hosted on some website (not the same docusaurus website). Will be **parsed** at build time and forwarded to Redoc component.

A path to a OpenAPI yaml or json file. Will be parsed and forwarded to Redoc component. This has higher priority over specUrl.
### url (optional, string: download url)

### specUrl
A url pointing to an OpenAPI spec. This will be used as download url and `spec` will be used for rendering. This is needed because by default the download url will point to a processed and parsed JSON file.

A url pointing to an OpenAPI spec. If both are present, then this will be used as download url and `spec` for rendering.
### route (optional, string: relative uri)

### layout
Route URL at which docs would be available, this will use the theme component `@theme/ApiDoc` from `docusaurus-theme-redoc` to render the page. You can also skip this option and render the docs as you wish using a custom page.

An object to pass as layout props. Useful to set title/description of the page. See all properties available [here](https://github.com/rohit-gohri/redocusaurus/blob/main/packages/docusaurus-plugin-redoc/src/options.ts#L3).
### layout (optional, object: layoutProps)

### routePath (default: `/api/`)

Route URL at which docs would be available

### apiDocComponent (default: `@theme/ApiDoc`)

If you want to use a custom component to render the spec instead of the one with `docusaurus-theme-redoc` then overwrite this with a path to the component.
It will be forwarded a single prop, see [ApiDoc](https://github.com/rohit-gohri/redocusaurus/blob/main/packages/docusaurus-theme-redoc/src/theme/ApiDoc/ApiDoc.tsx) for example.
An object to pass as layout props. Useful to set title/description of the page. See all properties available [here](./src/options.ts#L3).

## Docs

See: <https://rohit-gohri.github.io/redocusaurus/doc>
See <https://rohit-gohri.github.io/redocusaurus/docs> for examples and programmatic usage.
1 change: 1 addition & 0 deletions packages/docusaurus-plugin-redoc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@docusaurus/types": "^2.0.0-beta.17",
"@docusaurus/utils": "^2.0.0-beta.17",
"joi": "^17.5.0",
"redoc": "^2.0.0-rc.64",
"yaml": "^1.10.2"
},
"engines": {
Expand Down
89 changes: 52 additions & 37 deletions packages/docusaurus-plugin-redoc/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,57 @@ import type {
} from '@docusaurus/types';
import { normalizeUrl } from '@docusaurus/utils';
import YAML from 'yaml';
import { loadAndBundleSpec } from 'redoc';

import {
Spec,
PluginOptionSchema,
PluginOptions,
PluginOptionsWithDefault,
DEFAULT_OPTIONS,
} from './options';
import { ParsedSpec, SpecProps, ApiDocProps } from './types/common';

export { PluginOptions };

export default function redocPlugin(
context: LoadContext,
opts: PluginOptions,
): Plugin<Record<string, unknown> | null> {
): Plugin<Record<string, unknown>> {
const { baseUrl } = context.siteConfig;
const options: PluginOptionsWithDefault = { ...DEFAULT_OPTIONS, ...opts };
const { debug, spec, specUrl } = options;
const { debug, spec, url: downloadUrl } = options;
let url = downloadUrl;
if (debug) {
console.error('[REDOCUSAURUS_PLUGIN] Opts Input:', opts);
console.error('[REDOCUSAURUS_PLUGIN] Options:', options);
}
return {
name: 'docusaurus-plugin-redoc',
async loadContent() {
let content: Record<string, unknown> | null = null;
if (spec) {
let parsedSpec: ParsedSpec | null = null;
// If local file
if (fs.existsSync(spec)) {
if (debug) {
console.log('[REDOCUSAURUS_PLUGIN] reading file: ', spec);
}

const file = fs.readFileSync(spec).toString();

if (spec.endsWith('.yaml') || spec.endsWith('.yml')) {
const parsedSpec = YAML.parse(file);
content = parsedSpec;
} else content = JSON.parse(file);
parsedSpec = YAML.parse(file);
} else parsedSpec = JSON.parse(file);
} else {
// If spec is a remote url then add it as download url
url = spec;
}

if (debug) {
console.error('[REDOCUSAURUS_PLUGIN] Content:', content);
console.log('[REDOCUSAURUS_PLUGIN] bundling spec');
}
return content;
const content = await loadAndBundleSpec(parsedSpec || spec!);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
return content as any;
},
getPathsToWatch() {
if (!spec) {
Expand All @@ -55,38 +68,40 @@ export default function redocPlugin(
},
async contentLoaded({ content, actions }) {
const { createData, addRoute, setGlobalData } = actions;
if (!content && !specUrl) {
console.error('[Redocusaurus] No spec provided');
return;
if (!content) {
throw new Error(`[Redocusaurus] Spec could not be parsed: ${spec}`);
}
const data: Spec = {
specUrl,
type: content ? 'object' : 'url',

const data: SpecProps = {
url,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
content: (content || specUrl) as any,
spec: content as any,
};
setGlobalData(data);
const specData = await createData(
`redocApiSpec-${options.id || '1'}.json`,
JSON.stringify(data),
);
const layoutData = await createData(
`redocApiLayout-${options.id || '1'}.json`,
JSON.stringify(options.layout),
);

if (options.addRoute) {
const routePath = options.routePath.startsWith('/')
? options.routePath.slice(1)
: options.routePath;
if (options.route) {
const specProps = await createData(
`redocApiSpecV1-${options.id || '1'}.json`,
JSON.stringify(data),
);
const layoutProps = await createData(
`redocApiLayoutV1-${options.id || '1'}.json`,
JSON.stringify(options.layout),
);
const routePath = options.route.startsWith('/')
? options.route.slice(1)
: options.route;

const modules: Record<keyof ApiDocProps, string> = {
specProps,
layoutProps,
};

const routeOptions = {
path: normalizeUrl([baseUrl, routePath]),
component: options.apiDocComponent,
modules: {
spec: specData,
layoutProps: layoutData,
},
modules,
component: '@theme/ApiDoc',
exact: true,
path: normalizeUrl([baseUrl, routePath]),
};

if (debug) {
Expand All @@ -100,10 +115,10 @@ export default function redocPlugin(

export function validateOptions({
options,
}: OptionValidationContext<PluginOptions>): Promise<void> {
}: OptionValidationContext<PluginOptions>): PluginOptions {
const { value, error } = PluginOptionSchema.validate(options);
if (error) {
throw error;
}
return value;
return value!;
}
37 changes: 7 additions & 30 deletions packages/docusaurus-plugin-redoc/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,52 +14,29 @@ type LayoutProps = {
};
};

export type Spec = {
specUrl?: string;
} & (
| {
type: 'url';
content: string;
}
| {
type: 'object';
content: Record<string, unknown>;
}
);

export interface PluginOptions {
id?: string;
spec?: string;
specUrl?: string;
spec: string;
url?: string;
route?: string;
layout?: LayoutProps;
debug?: boolean;
addRoute?: boolean;
routePath?: string;
apiDocComponent?: string;
}

export interface PluginOptionsWithDefault extends PluginOptions {
debug: boolean;
addRoute: boolean;
routePath: string;
apiDocComponent: string;
}

export const DEFAULT_OPTIONS: PluginOptionsWithDefault = {
export const DEFAULT_OPTIONS: Omit<PluginOptionsWithDefault, 'spec'> = {
layout: {},
debug: false,
addRoute: true,
routePath: '/api/', // URL Route.
apiDocComponent: '@theme/ApiDoc',
};

export const PluginOptionSchema = Joi.object({
export const PluginOptionSchema = Joi.object<PluginOptions>({
id: Joi.string(),
spec: Joi.string(),
specUrl: Joi.string().uri({ allowRelative: true }),
url: Joi.string().uri({ allowRelative: true }).optional(),
layout: Joi.any().default(DEFAULT_OPTIONS.layout),
debug: Joi.boolean().default(DEFAULT_OPTIONS.debug),
addRoute: Joi.boolean().default(DEFAULT_OPTIONS.addRoute),
routePath: Joi.string().default(DEFAULT_OPTIONS.routePath),
apiDocComponent: Joi.string().default(DEFAULT_OPTIONS.apiDocComponent),
route: Joi.string().uri({ relativeOnly: true }).optional(),
});
1 change: 1 addition & 0 deletions packages/docusaurus-plugin-redoc/src/types/common.d.ts
2 changes: 1 addition & 1 deletion packages/docusaurus-theme-redoc/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ primaryColor: '#1890ff',
* Options to pass to redoc
* @see https://github.com/redocly/redoc#redoc-options-object
*/
redocOptions: { hideDownloadButton: false, disableSearch: true },
redocOptions: { disableSearch: true },
/**
* Options to pass to override RedocThemeObject
* @see https://github.com/Redocly/redoc#redoc-theme-object
Expand Down
Loading