Skip to content

Commit cd0a1b1

Browse files
authored
fix: Escape symbols to support MDX 2/3 changes. (#121)
* Add file. * Add escaping. * Fix type.
1 parent b02c7c8 commit cd0a1b1

File tree

14 files changed

+317
-46
lines changed

14 files changed

+317
-46
lines changed

fixtures/polyrepo/src/boolean.ts

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
// https://github.com/milesj/docusaurus-plugin-typedoc-api/issues/120
2+
3+
/**
4+
* Module interface for values that have equivalence relation
5+
*/
6+
export interface Equal<T> {
7+
/**
8+
* Alias to '=='
9+
*
10+
* @example
11+
* ```ts
12+
* type T = // ...
13+
* const TEqual: Equal<T>;
14+
* TEqual.equals(value, value); // true
15+
* TEqual.equals(value, otherValue); // false
16+
* ```
17+
* @category Comparator
18+
*/
19+
equals(this: void, left: T, right: T): boolean;
20+
/**
21+
* "Not equal to" operator
22+
*
23+
* @example
24+
* ```ts
25+
* const TEqual: Equal<T>;
26+
* TEqual['!='](value, otherValue); // true
27+
* TEqual['!='](value, value); // false
28+
* ```
29+
* @category Comparator
30+
*/
31+
'!='(this: void, left: T, right: T): boolean;
32+
/**
33+
* "Equal to" operator
34+
*
35+
* @example
36+
* ```ts
37+
* type T = // ...
38+
* const TEqual: Equal<T>;
39+
* TEqual['=='](value, value); // true
40+
* TEqual['=='](value, otherValue); // false
41+
* ```
42+
* @category Comparator
43+
*/
44+
'=='(this: void, left: T, right: T): boolean;
45+
}
46+
47+
/**
48+
* Equal module constructor
49+
*
50+
* @example
51+
* ```ts
52+
* type T;
53+
* const TEqual = Equal<T>({
54+
* '==': (left, right) => { /* ... *\/ },
55+
* });
56+
* const value: T;
57+
*
58+
* TEqual['=='](value, value); // true;
59+
* ```
60+
* @category Functor
61+
*/
62+
export function Equal<T>(properties: { equals: (left: T, right: T) => boolean }): Equal<T> {
63+
const equals = (left: T, right: T) => properties.equals(left, right);
64+
const notEquals = (left: T, right: T) => !properties.equals(left, right);
65+
return {
66+
equals: properties.equals,
67+
'==': equals,
68+
'!=': notEquals,
69+
};
70+
}
71+
72+
/**
73+
* Module interface for values that have total order
74+
*/
75+
export interface Comparable<T> extends Equal<T> {
76+
/**
77+
* Return a number that represents comparison
78+
*
79+
* @example
80+
* ```ts
81+
* type T;
82+
* const TCompare: Comparable<T>;
83+
* const sorted = [3, 1, 1].sort(TCompare.compare);
84+
* ```
85+
* @category Comparator
86+
*/
87+
compare(this: void, left: T, right: T): number;
88+
/**
89+
* "Less than or equal to" operator
90+
*
91+
* @example
92+
* ```ts
93+
* type T;
94+
* const TCompare: Comparable<T>;
95+
* const smallerT: T;
96+
* const greaterT: T;
97+
* TCompare['<='](smallerT, smallerT); // true
98+
* TCompare['<='](smallerT, greaterT); // true
99+
* TCompare['<='](greaterT, smallerT); // false
100+
* ```
101+
* @category Comparator
102+
*/
103+
'<='(this: void, left: T, right: T): boolean;
104+
/**
105+
* "Less than" operator
106+
*
107+
* @example
108+
* ```ts
109+
* type T;
110+
* const TCompare: Comparable<T>;
111+
* const smallerT: T;
112+
* const greaterT: T;
113+
* TCompare['<'](smallerT, smallerT); // false
114+
* TCompare['<'](smallerT, greaterT); // true
115+
* TCompare['<'](greaterT, smallerT); // false
116+
* ```
117+
* @category Comparator
118+
*/
119+
'<'(this: void, left: T, right: T): boolean;
120+
/**
121+
* "Greater than or equal to" operator
122+
*
123+
* @example
124+
* ```ts
125+
* type T;
126+
* const TCompare: Comparable<T>;
127+
* const smallerT: T;
128+
* const greaterT: T;
129+
* TCompare['>='](smallerT, smallerT); // true
130+
* TCompare['>='](smallerT, greaterT); // false
131+
* TCompare['>='](greaterT, smallerT); // true
132+
* ```
133+
* @category Comparator
134+
*/
135+
'>='(this: void, left: T, right: T): boolean;
136+
/**
137+
* "Greater than" operator
138+
*
139+
* @example
140+
* ```ts
141+
* type T;
142+
* const TCompare: Comparable<T>;
143+
* const smallerT: T;
144+
* const greaterT: T;
145+
* TCompare['>'](smallerT, smallerT); // false
146+
* TCompare['>'](smallerT, greaterT); // false
147+
* TCompare['>'](greaterT, smallerT); // true
148+
* ```
149+
* @category Comparator
150+
*/
151+
'>'(this: void, left: T, right: T): boolean;
152+
/**
153+
* "minimum" operator
154+
*
155+
* @example
156+
* ```ts
157+
* type T;
158+
* const TCompare: Comparable<T>;
159+
* const smallerT: T;
160+
* const greaterT: T;
161+
* TCompare.min(smallerT, greaterT); // smallerT
162+
* ```
163+
* @category Comparator
164+
*/
165+
min(this: void, left: T, right: T): T;
166+
/**
167+
* "maximum" operator
168+
*
169+
* @example
170+
* ```ts
171+
* type T;
172+
* const TCompare: Comparable<T>;
173+
* const smallerT: T;
174+
* const greaterT: T;
175+
* TCompare.max(smallerT, greaterT); // greaterT
176+
* ```
177+
* @category Comparator
178+
*/
179+
max(this: void, left: T, right: T): T;
180+
}
181+
182+
/**
183+
* Construct Comparable instance
184+
*
185+
* @example
186+
* ```ts
187+
* const NumberComparable = Comparable({
188+
* compare: (left, right) => left - right,
189+
* });
190+
* NumberComparable['=='](0, 0); // true
191+
* NumberComparable['<'](0, 1); // true
192+
* NumberComparable['>'](0, 1); // false
193+
* ```
194+
* @category Functor
195+
* @param properties
196+
* @param properties.compare - the comparison function
197+
*/
198+
export function Comparable<T>(properties: {
199+
compare: (left: T, right: T) => number;
200+
}): Comparable<T> {
201+
const { compare } = properties;
202+
const equals = (left: T, right: T) => compare(left, right) === 0;
203+
return {
204+
compare,
205+
equals,
206+
'==': equals,
207+
'!=': (left: T, right: T) => compare(left, right) !== 0,
208+
'<': (left: T, right: T) => compare(left, right) < 0,
209+
'<=': (left: T, right: T) => compare(left, right) <= 0,
210+
'>': (left: T, right: T) => compare(left, right) > 0,
211+
'>=': (left: T, right: T) => compare(left, right) >= 0,
212+
min: (left: T, right: T) => (compare(left, right) <= 0 ? left : right),
213+
max: (left: T, right: T) => (compare(left, right) > 0 ? left : right),
214+
};
215+
}
216+
217+
const BooleanComparable = Comparable<boolean>({
218+
compare(left, right) {
219+
return left === right ? 0 : left < right ? -1 : 1;
220+
},
221+
});
222+
223+
/**
224+
* A collection of functions to manipulate `boolean`
225+
*
226+
* @example
227+
* ```typescript
228+
* import { Boolean } from '@w5s/core';
229+
*
230+
* if (Boolean.hasInstance(unknownValue)) {
231+
* // typeof unknownValue === 'boolean'
232+
* }
233+
* ```
234+
* @namespace
235+
*/
236+
export const Boolean = {
237+
...BooleanComparable,
238+
239+
/**
240+
* Return true if `anyValue` is a `boolean`
241+
*
242+
* @example
243+
* ```typescript
244+
* Boolean.hasInstance(false) // true
245+
* Boolean.hasInstance(null)) // false
246+
* ```
247+
* @category Guard
248+
* @param anyValue - a tested value
249+
*/
250+
hasInstance(anyValue: unknown): anyValue is boolean {
251+
return typeof anyValue === 'boolean';
252+
},
253+
};

fixtures/polyrepo/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
export type Type = 'standard';
22

33
export function foo() {}
4+
5+
export * from './boolean';

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
"devDependencies": {
1616
"@moonrepo/dev": "^2.0.1",
1717
"@types/marked": "^6.0.0",
18-
"@types/react": "^18.2.33",
19-
"eslint": "^8.52.0",
18+
"@types/react": "^18.2.34",
19+
"eslint": "^8.53.0",
2020
"eslint-config-moon": "^2.0.11",
2121
"lerna": "^7.4.2",
2222
"packemon": "^3.2.2",

packages/plugin/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"@docusaurus/types": "^3.0.0",
5050
"@docusaurus/utils": "^3.0.0",
5151
"@vscode/codicons": "^0.0.35",
52-
"marked": "^9.1.4",
52+
"marked": "^9.1.5",
5353
"marked-smartypants": "^1.1.3",
5454
"typedoc": "^0.25.3"
5555
},

packages/plugin/src/components/ApiItem.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { Props as DocItemProps } from '@theme/DocItem';
44
import { useReflection } from '../hooks/useReflection';
55
import { useReflectionMap } from '../hooks/useReflectionMap';
66
import type { TOCItem, TSDDeclarationReflection, TSDDeclarationReflectionMap } from '../types';
7+
import { escapeMdx } from '../utils/helpers';
78
import { getKindIconHtml } from '../utils/icons';
89
import ApiItemLayout from './ApiItemLayout';
910
import { displayPartsToMarkdown } from './Comment';
@@ -23,14 +24,15 @@ function extractTOC(item: TSDDeclarationReflection, map: TSDDeclarationReflectio
2324
return;
2425
}
2526

26-
const iconHtml = getKindIconHtml(child.kind, child.name);
27-
2827
if (!child.permalink || child.permalink.includes('#')) {
28+
const iconHtml = getKindIconHtml(child.kind, child.name);
29+
const value = escapeMdx(child.name);
30+
2931
toc.push({
3032
// @ts-expect-error Not typed upstream
3133
children: [],
3234
id: child.name,
33-
value: iconHtml ? `${iconHtml} ${child.name}` : child.name,
35+
value: iconHtml ? `${iconHtml} ${value}` : value,
3436
level: 1,
3537
});
3638

@@ -59,13 +61,13 @@ export default function ApiItem({ readme: Readme, route }: ApiItemProps) {
5961
next: nextItem
6062
? {
6163
permalink: nextItem.permalink,
62-
title: nextItem.name,
64+
title: escapeMdx(nextItem.name),
6365
}
6466
: undefined,
6567
previous: prevItem
6668
? {
6769
permalink: prevItem.permalink,
68-
title: prevItem.name,
70+
title: escapeMdx(prevItem.name),
6971
}
7072
: undefined,
7173
}),
@@ -79,7 +81,7 @@ export default function ApiItem({ readme: Readme, route }: ApiItemProps) {
7981
<span className="tsd-header-flags">
8082
<Flags flags={item.flags} />
8183
</span>
82-
{item.name} <TypeParametersGeneric params={item.typeParameters} />
84+
{escapeMdx(item.name)} <TypeParametersGeneric params={item.typeParameters} />
8385
</>
8486
}
8587
pageMetadata={

packages/plugin/src/components/Index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Fragment } from 'react';
22
import Link from '@docusaurus/Link';
33
import { useReflection } from '../hooks/useReflection';
44
import type { TSDDeclarationReflection } from '../types';
5+
import { escapeMdx } from '../utils/helpers';
56
import { AnchorLink } from './AnchorLink';
67
import { Icon } from './Icon';
78

@@ -16,7 +17,7 @@ function IndexChild({ id }: IndexChildProps) {
1617
<li>
1718
<Link className="tsd-kind-icon" to={reflection.permalink ?? `#${reflection.name}`}>
1819
<Icon reflection={reflection} />
19-
{reflection.name}
20+
{escapeMdx(reflection.name)}
2021
</Link>
2122
</li>
2223
);

packages/plugin/src/components/Member.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Fragment } from 'react';
44
import type { JSONOutput } from 'typedoc';
55
import { useReflection } from '../hooks/useReflection';
66
import { useReflectionMap } from '../hooks/useReflectionMap';
7+
import { escapeMdx } from '../utils/helpers';
78
import { hasOwnDocument } from '../utils/visibility';
89
import { AnchorLink } from './AnchorLink';
910
import { CommentBadges, isCommentWithModifiers } from './CommentBadges';
@@ -46,7 +47,7 @@ export function Member({ id }: MemberProps) {
4647
<AnchorLink id={reflection.name} />
4748
<SourceLink sources={reflection.sources} />
4849
<Flags flags={reflection.flags} />
49-
{reflection.name}
50+
{escapeMdx(reflection.name)}
5051
{isCommentWithModifiers(comment) && <CommentBadges comment={comment} />}
5152
</h3>
5253

packages/plugin/src/components/MemberDeclaration.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { useMinimalLayout } from '../hooks/useMinimalLayout';
44
import { useReflection } from '../hooks/useReflection';
5+
import { escapeMdx } from '../utils/helpers';
56
import { Comment, hasComment } from './Comment';
67
import { DefaultValue } from './DefaultValue';
78
import { Icon } from './Icon';
@@ -26,7 +27,7 @@ export function MemberDeclaration({ id }: MemberDeclarationProps) {
2627
<div className="tsd-panel-content">
2728
<div className="tsd-signature tsd-kind-icon">
2829
<Icon reflection={reflection} />
29-
{reflection.name}
30+
{escapeMdx(reflection.name)}
3031
<TypeParametersGeneric params={reflection.typeParameters} />
3132
<span className="tsd-signature-symbol">{reflection.flags?.isOptional && '?'}: </span>{' '}
3233
<Type type={reflection.type} />

0 commit comments

Comments
 (0)