Skip to content

Allow passing spec directly to various components #347

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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,8 @@
"printWidth": 80,
"tabWidth": 2
},
"packageManager": "[email protected]"
"packageManager": "[email protected]",
"volta": {
"node": "18.12.0"
}
}
18 changes: 11 additions & 7 deletions packages/docusaurus-plugin-redoc/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
PluginDirectUsageOptions,
DEFAULT_OPTIONS,
} from './options';
import type { SpecProps, ApiDocProps } from './types/common';
import type { SpecDataResult, ApiDocProps } from './types/common';
import { loadSpecWithConfig } from './loadSpec';
import { loadRedoclyConfig } from './loadRedoclyConfig';

Expand All @@ -33,6 +33,10 @@ const version = require('../package.json').version;

export { PluginOptions, PluginDirectUsageOptions, loadRedoclyConfig };

function getIsExternalUrl(url = '') {
return ['http://', 'https://'].some((protocol) => url.startsWith(protocol));
}

export default function redocPlugin(
context: LoadContext,
opts: PluginOptions,
Expand All @@ -45,12 +49,13 @@ export default function redocPlugin(
const { debug, spec, url: downloadUrl, config, themeId } = options;

let url = downloadUrl;
const isSpecFile = fs.existsSync(spec);
const isExternalUrl = getIsExternalUrl(url);

const fileName = path.join(
'redocusaurus',
`${options.id || 'api-spec'}.yaml`,
);
let filesToWatch: string[] = isSpecFile ? [path.resolve(spec)] : [];
let filesToWatch: string[] = !isExternalUrl ? [path.resolve(spec)] : [];

if (debug) {
console.error('[REDOCUSAURUS_PLUGIN] Opts Input:', opts);
Expand All @@ -67,7 +72,7 @@ export default function redocPlugin(

let bundledSpec: Document, problems: NormalizedProblem[];

if (!isSpecFile) {
if (isExternalUrl) {
// If spec is a remote url then add it as download url also as a default
url = url || spec;
if (debug) {
Expand Down Expand Up @@ -123,10 +128,9 @@ export default function redocPlugin(
throw new Error(`[Redocusaurus] Spec could not be parsed: ${spec}`);
}

const data: SpecProps = {
const data: SpecDataResult = {
url,
themeId,
isSpecFile,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
spec: content.converted as any,
};
Expand Down Expand Up @@ -165,7 +169,7 @@ export default function redocPlugin(
}
},
async postBuild({ content }) {
if (!isSpecFile || downloadUrl) {
if (isExternalUrl || downloadUrl) {
return;
}
// Create a static file from bundled spec
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React, { useMemo } from 'react';
import Redoc from '@theme/Redoc';
import useSpecData from '@theme/useSpecData';
import { MdxProps as Props } from '../../types/common';
import { MdxProps } from '../../types/common';
import '../ApiSchema/styles.css';

const ApiDocMdx: React.FC<Props> = ({ id }: Props): JSX.Element => {
const ApiDocMdx: React.FC<MdxProps> = ({ id }: MdxProps): JSX.Element => {
const specProps = useSpecData(id);
const optionsOverrides = useMemo(() => {
return {
Expand Down
28 changes: 17 additions & 11 deletions packages/docusaurus-theme-redoc/src/theme/ApiSchema/ApiSchema.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,25 @@ import clsx from 'clsx';
import { ThemeProvider } from 'styled-components';
import '../../global';
import { SchemaDefinition } from 'redoc';
import { useSpec } from '../../utils/useSpec';
import { useSpecData } from '../useSpecData';
import { ApiSchemaProps as Props } from '../../types/common';
import useSpec from '@theme/useSpec';
import '../Redoc/styles.css';
import './styles.css';

const ApiSchema: React.FC<Props> = ({
id,
example,
const ApiSchema: React.FC<ApiSchemaProps> = ({
showExample,
pointer,
id,
spec,
optionsOverrides,
...rest
}: Props): JSX.Element => {
const specProps = useSpecData(id);
const { store } = useSpec(specProps);
}: ApiSchemaProps): JSX.Element => {
const { store } = useSpec(
{
id,
spec,
},
optionsOverrides,
);

useEffect(() => {
/**
Expand All @@ -31,13 +36,14 @@ const ApiSchema: React.FC<Props> = ({
className={clsx([
'redocusaurus',
'redocusaurus-schema',
example ? null : 'hide-example',
showExample ? null : 'hide-example',
])}
>
<SchemaDefinition
parser={store.spec.parser}
options={store.options}
schemaRef={pointer}
showExample={showExample}
{...rest}
/>
</div>
Expand All @@ -46,7 +52,7 @@ const ApiSchema: React.FC<Props> = ({
};

ApiSchema.defaultProps = {
example: false,
showExample: false,
};

export default ApiSchema;
23 changes: 10 additions & 13 deletions packages/docusaurus-theme-redoc/src/theme/Redoc/Redoc.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,34 @@
import React from 'react';
import clsx from 'clsx';
import '../../global';
import { RedocStandalone, RedocRawOptions } from 'redoc';
import { SpecProps } from '../../types/common';
import { useSpecOptions } from '../../utils/useSpecOptions';
import { RedocStandalone } from 'redoc';
import useSpecOptions from '@theme/useSpecOptions';
import './styles.css';
import ServerRedoc from './ServerRedoc';

function getIsExternalUrl(url = '') {
return ['http://', 'https://'].some((protocol) => url.startsWith(protocol));
}

/*!
* Redocusaurus
* https://redocusaurus.vercel.app/
* (c) 2024 Rohit Gohri
* Released under the MIT License
*/
function Redoc(
props: Partial<SpecProps> & {
className?: string;
optionsOverrides?: RedocRawOptions;
},
): JSX.Element {
const { className, optionsOverrides, spec, url, themeId, isSpecFile } = props;
function Redoc(props: RedocProps): JSX.Element {
const { className, optionsOverrides, url, themeId } = props;
const { options } = useSpecOptions(themeId, optionsOverrides);
const isDevMode = process.env.NODE_ENV === 'development';

if ((isDevMode && isSpecFile === false) || !spec) {
if (getIsExternalUrl(url)) {
return (
<div className={clsx(['redocusaurus', className])}>
<RedocStandalone specUrl={url} options={options} />
</div>
);
}

return <ServerRedoc {...props} spec={spec} />;
return <ServerRedoc {...props} />;
}

export default Redoc;
25 changes: 12 additions & 13 deletions packages/docusaurus-theme-redoc/src/theme/Redoc/ServerRedoc.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import React from 'react';
import clsx from 'clsx';
import '../../global';
import { Redoc as RedocComponent, RedocRawOptions } from 'redoc';
import { SpecProps } from '../../types/common';
import { useSpec } from '../../utils/useSpec';
import { Redoc as RedocComponent } from 'redoc';
import useSpec from '@theme/useSpec';
import { ServerStyles } from './Styles';
import './styles.css';

Expand All @@ -13,22 +12,22 @@ import './styles.css';
* (c) 2024 Rohit Gohri
* Released under the MIT License
*/
function ServerRedoc(
props: SpecProps & {
className?: string;
optionsOverrides?: RedocRawOptions;
},
): JSX.Element {
const { className, optionsOverrides, ...specProps } = props;
const { store, darkThemeOptions, lightThemeOptions, hasLogo } = useSpec(
specProps,
function ServerRedoc(props: RedocProps): JSX.Element {
const { className, optionsOverrides, url, id, themeId } = props;
const { store, spec, darkThemeOptions, lightThemeOptions, hasLogo } = useSpec(
{
spec: props.spec,
themeId,
id,
},
optionsOverrides,
);

return (
<>
<ServerStyles
specProps={specProps}
spec={spec}
url={url}
lightThemeOptions={lightThemeOptions}
darkThemeOptions={darkThemeOptions}
/>
Expand Down
23 changes: 14 additions & 9 deletions packages/docusaurus-theme-redoc/src/theme/Redoc/ServerStyles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import '../../global';
import useBaseUrl from '@docusaurus/useBaseUrl';
import { AppStore, Redoc, RedocRawOptions } from 'redoc';
import type { OpenAPISpec } from 'redoc/typings/types';
// eslint-disable-next-line import/no-extraneous-dependencies
import { renderToString } from 'react-dom/server';
import { ServerStyleSheet } from 'styled-components';
Expand Down Expand Up @@ -53,22 +54,26 @@ const prefixCssSelectors = function (rules: string, className: string) {
const LIGHT_MODE_PREFIX = "html:not([data-theme='dark'])";
const DARK_MODE_PREFIX = "html([data-theme='dark'])";

export type ServerStylesProps = {
spec: OpenAPISpec;
url?: string;
lightThemeOptions: RedocRawOptions;
darkThemeOptions: RedocRawOptions;
};

export function ServerStyles({
specProps,
spec,
url,
lightThemeOptions,
darkThemeOptions,
}: {
specProps: SpecProps;
lightThemeOptions: RedocRawOptions;
darkThemeOptions: RedocRawOptions;
}) {
const fullUrl = useBaseUrl(specProps.url, { absolute: true });
}: ServerStylesProps) {
const fullUrl = useBaseUrl(url, { absolute: true });
const css = {
light: '',
dark: '',
};
const lightSheet = new ServerStyleSheet();
const lightStore = new AppStore(specProps.spec, fullUrl, lightThemeOptions);
const lightStore = new AppStore(spec, fullUrl, lightThemeOptions);
renderToString(
lightSheet.collectStyles(React.createElement(Redoc, { store: lightStore })),
);
Expand All @@ -78,7 +83,7 @@ export function ServerStyles({
css.light = prefixCssSelectors(lightCss, LIGHT_MODE_PREFIX);

const darkSheet = new ServerStyleSheet();
const darkStore = new AppStore(specProps.spec, fullUrl, darkThemeOptions);
const darkStore = new AppStore(spec, fullUrl, darkThemeOptions);
renderToString(
darkSheet.collectStyles(React.createElement(Redoc, { store: darkStore })),
);
Expand Down
8 changes: 2 additions & 6 deletions packages/docusaurus-theme-redoc/src/theme/Redoc/Styles.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import React from 'react';
import '../../global';
import type { RedocRawOptions } from 'redoc';
import type { ServerStylesProps } from './ServerStyles';

/**
* Don't hydrate/replace server styles
* @see https://github.com/facebook/react/issues/10923#issuecomment-338715787
*/
export function ServerStyles(_props: {
specProps: SpecProps;
lightThemeOptions: RedocRawOptions;
darkThemeOptions: RedocRawOptions;
}) {
export function ServerStyles(_props: ServerStylesProps) {
return <div className="redocusaurus-styles"></div>;
}
3 changes: 3 additions & 0 deletions packages/docusaurus-theme-redoc/src/theme/useSpec/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { useSpec } from './useSpec';

export default useSpec;
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { useMemo, useEffect } from 'react';
import useBaseUrl from '@docusaurus/useBaseUrl';
import useIsBrowser from '@docusaurus/useIsBrowser';
import { useColorMode } from '@docusaurus/theme-common';
import '../global';
import useSpecData from '@theme/useSpecData';
import useSpecOptions from '@theme/useSpecOptions';
import '../../global';
import { AppStore, RedocRawOptions } from 'redoc';
import { SpecProps } from '../types/common';
import { useSpecOptions } from './useSpecOptions';

// the current store singleton in the app's instance
let currentStore: AppStore | null = null;
Expand All @@ -17,9 +17,14 @@ let currentStore: AppStore | null = null;
* Released under the MIT License
*/
export function useSpec(
{ spec, url, themeId }: SpecProps,
specInfo: SpecProps,
optionsOverrides?: RedocRawOptions,
) {
): SpecResult {
const { spec, url, themeId } = useSpecData(
specInfo.id,
specInfo.spec,
specInfo.themeId,
);
const specOptions = useSpecOptions(themeId, optionsOverrides);
const fullUrl = useBaseUrl(url, { absolute: true });
const isBrowser = useIsBrowser();
Expand All @@ -36,6 +41,7 @@ export function useSpec(
// @ts-expect-error extra prop
hasLogo: !!spec.info?.['x-logo'],
store: currentStore,
spec,
};
}, [isBrowser, spec, fullUrl, specOptions]);

Expand Down
18 changes: 0 additions & 18 deletions packages/docusaurus-theme-redoc/src/theme/useSpecData.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { useSpecData } from './useSpecData';

export default useSpecData;
Loading
Loading