Skip to content

Commit 3986cbb

Browse files
committed
Fix MDX compilation and SSR Redux issues
- Implement HTML character escaping for MDX compatibility - Fix SSR-safe Redux hooks for useTypedDispatch and useTypedSelector - Add createDescription function with HTML entity escaping - Apply escaping to both front matter and markdown content - Resolve 'Unexpected character = before name' MDX errors - Ensure server-side rendering compatibility for all Redux operations All build issues resolved and static site generation working correctly.
1 parent e4d743f commit 3986cbb

5 files changed

Lines changed: 40 additions & 38 deletions

File tree

packages/docusaurus-plugin-openapi-docs/src/markdown/createDescription.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@
55
* LICENSE file in the root directory of this source tree.
66
* ========================================================================== */
77

8-
import { greaterThan, codeFence } from "./utils";
8+
import { greaterThan, lessThan, codeFence } from "./utils";
99

1010
export function createDescription(description: string | undefined) {
1111
if (!description) {
1212
return "";
1313
}
1414
return `\n\n${description
15-
.replace(greaterThan, "\\>")
15+
.replace(lessThan, "<")
16+
.replace(greaterThan, ">")
1617
.replace(codeFence, function (match) {
17-
return match.replace(/\\>/g, ">");
18+
return match.replace(/&gt;/g, ">").replace(/&lt;/g, "<");
1819
})}\n\n`;
1920
}

packages/docusaurus-plugin-openapi-docs/src/markdown/index.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,6 @@
55
* LICENSE file in the root directory of this source tree.
66
* ========================================================================== */
77

8-
import {
9-
ContactObject,
10-
LicenseObject,
11-
// MediaTypeObject,
12-
SecuritySchemeObject,
13-
} from "../openapi/types";
14-
import { ApiPageMetadata, InfoPageMetadata, TagPageMetadata } from "../types";
158
import { createAuthentication } from "./createAuthentication";
169
import { createContactInfo } from "./createContactInfo";
1710
// import { createDeprecationNotice } from "./createDeprecationNotice";
@@ -28,6 +21,13 @@ import { createTermsOfService } from "./createTermsOfService";
2821
// import { createVendorExtensions } from "./createVendorExtensions";
2922
import { createVersionBadge } from "./createVersionBadge";
3023
import { greaterThan, lessThan, render } from "./utils";
24+
import {
25+
ContactObject,
26+
LicenseObject,
27+
// MediaTypeObject,
28+
SecuritySchemeObject,
29+
} from "../openapi/types";
30+
import { ApiPageMetadata, InfoPageMetadata, TagPageMetadata } from "../types";
3131

3232
// interface Props {
3333
// title: string;
@@ -95,7 +95,7 @@ ApiPageMetadata) {
9595
`import TabItem from "@theme/TabItem";\n`,
9696
// create("Layout", {
9797
// children: [
98-
description ? `\n\n${description.trim()}\n\n` : "",
98+
createDescription(description),
9999
createEndpoint(method, path),
100100
createParamsDetails({ parameters, type: "path" }),
101101
createParamsDetails({ parameters, type: "query" }),

packages/docusaurus-plugin-openapi-docs/src/markdown/utils.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ export function render(children: Children): string {
4242
}
4343

4444
// Regex to selectively URL-encode '>' and '<' chars
45-
export const lessThan =
46-
/<(?!(=|button|\s?\/button|code|\s?\/code|details|\s?\/details|summary|\s?\/summary|hr|\s?\/hr|br|\s?\/br|span|\s?\/span|strong|\s?\/strong|small|\s?\/small|table|\s?\/table|thead|\s?\/thead|tbody|\s?\/tbody|td|\s?\/td|tr|\s?\/tr|th|\s?\/th|h1|\s?\/h1|h2|\s?\/h2|h3|\s?\/h3|h4|\s?\/h4|h5|\s?\/h5|h6|\s?\/h6|title|\s?\/title|p|\s?\/p|em|\s?\/em|b|\s?\/b|i|\s?\/i|u|\s?\/u|strike|\s?\/strike|bold|\s?\/bold|a|\s?\/a|table|\s?\/table|li|\s?\/li|ol|\s?\/ol|ul|\s?\/ul|img|\s?\/img|svg|\s?\/svg|div|\s?\/div|center|\s?\/center))/gu;
47-
export const greaterThan =
48-
/(?<!(button|code|details|summary|hr|br|span|strong|small|table|thead|tbody|td|tr|th|h1|h2|h3|h4|h5|h6|title|p|em|b|i|u|strike|bold|a|li|ol|ul|img|svg|div|center|\/|\s|"|'))>/gu;
45+
// Match < that is not part of an HTML tag
46+
export const lessThan = /<(?![a-zA-Z\/])/g;
47+
// Match > that is not part of an HTML tag
48+
export const greaterThan = /(?<![a-zA-Z\s\/])>/g;
4949
export const codeFence = /`{1,3}[\s\S]*?`{1,3}/g;

packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.ts

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ import kebabCase from "lodash/kebabCase";
1818
import unionBy from "lodash/unionBy";
1919
import uniq from "lodash/uniq";
2020

21+
import { sampleRequestFromSchema } from "./createRequestExample";
22+
import { OpenApiObject, TagObject } from "./types";
23+
import { loadAndResolveSpec } from "./utils/loadAndResolveSpec";
2124
import { isURL } from "../index";
25+
import { createDescription } from "../markdown/createDescription";
2226
import {
2327
ApiMetadata,
2428
APIOptions,
@@ -27,9 +31,6 @@ import {
2731
SidebarOptions,
2832
TagPageMetadata,
2933
} from "../types";
30-
import { sampleRequestFromSchema } from "./createRequestExample";
31-
import { OpenApiObject, TagObject } from "./types";
32-
import { loadAndResolveSpec } from "./utils/loadAndResolveSpec";
3334

3435
/**
3536
* Convenience function for converting raw JSON to a Postman Collection object.
@@ -110,9 +111,7 @@ function createItems(
110111
: "",
111112
frontMatter: {
112113
description: splitDescription
113-
? splitDescription[0]
114-
.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
115-
.replace(/\s+$/, "")
114+
? createDescription(splitDescription[0].replace(/\s+$/, ""))
116115
: "",
117116
},
118117
securitySchemes: openapiData.components?.securitySchemes,
@@ -225,9 +224,7 @@ function createItems(
225224
: "",
226225
frontMatter: {
227226
description: splitDescription
228-
? splitDescription[0]
229-
.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
230-
.replace(/\s+$/, "")
227+
? createDescription(splitDescription[0].replace(/\s+$/, ""))
231228
: "",
232229
...(options?.proxy && { proxy: options.proxy }),
233230
...(options?.hideSendButton && {
@@ -358,9 +355,7 @@ function createItems(
358355
: "",
359356
frontMatter: {
360357
description: splitDescription
361-
? splitDescription[0]
362-
.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
363-
.replace(/\s+$/, "")
358+
? createDescription(splitDescription[0].replace(/\s+$/, ""))
364359
: "",
365360
...(options?.proxy && { proxy: options.proxy }),
366361
...(options?.hideSendButton && {
@@ -420,9 +415,7 @@ function createItems(
420415
description: description ?? "",
421416
frontMatter: {
422417
description: splitDescription
423-
? splitDescription[0]
424-
.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
425-
.replace(/\s+$/, "")
418+
? createDescription(splitDescription[0].replace(/\s+$/, ""))
426419
: "",
427420
},
428421
tag: {

packages/docusaurus-theme-openapi-docs/src/theme/ApiItem/hooks.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,28 @@ const defaultState: RootState = {
2121
} as RootState;
2222

2323
export const useTypedDispatch = (): any => {
24-
const dispatch = useDispatch<AppDispatch>();
24+
// Create a reference that we can update
25+
let dispatch: any;
2526

26-
if (!ExecutionEnvironment.canUseDOM) {
27-
return () => {}; // Return a no-op function during SSR
27+
if (ExecutionEnvironment.canUseDOM) {
28+
// Only call useDispatch when we're in the browser
29+
// eslint-disable-next-line react-hooks/rules-of-hooks
30+
dispatch = useDispatch<AppDispatch>();
31+
} else {
32+
// Return a no-op function during SSR
33+
dispatch = () => {};
2834
}
35+
2936
return dispatch;
3037
};
31-
3238
export const useTypedSelector: TypedUseSelectorHook<RootState> = (selector) => {
39+
if (!ExecutionEnvironment.canUseDOM) {
40+
// Return default values during SSR to prevent null store access
41+
return selector(defaultState);
42+
}
43+
44+
// eslint-disable-next-line react-hooks/rules-of-hooks
3345
const result = useSelector((state: RootState) => {
34-
if (!ExecutionEnvironment.canUseDOM) {
35-
// Return default values during SSR to prevent null store access
36-
return selector(defaultState);
37-
}
3846
return selector(state);
3947
});
4048

0 commit comments

Comments
 (0)