Skip to content

Commit b910fba

Browse files
committed
fix(core): handle duplicate symbols with leading underscores
1 parent 683b2c0 commit b910fba

24 files changed

+610
-268
lines changed

.changeset/empty-badgers-lick.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'typedoc-plugin-markdown': patch
3+
---
4+
5+
- Handle duplicate symbols with leading underscores

packages/typedoc-plugin-markdown/src/internationalization/setup.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import { en, jp, ko, zh } from '@plugin/internationalization/index.js';
22
import { Application, Converter } from 'typedoc';
33

4+
/**
5+
* Returns subset of translatable strings for the plugin.
6+
*
7+
* These will then be merged with the main set of TypeDoc string.
8+
*
9+
* @category Functions
10+
*/
411
export function setupInternationalization(app: Application): void {
512
app.converter.on(Converter.EVENT_BEGIN, () => {
613
app.internationalization.addTranslations(
@@ -12,11 +19,7 @@ export function setupInternationalization(app: Application): void {
1219
}
1320

1421
/**
15-
* Returns subset of translatable strings for the plugin.
16-
*
17-
* These will then be merged with the main set of TypeDoc string.
18-
*
19-
* @category Functions
22+
2023
*/
2124
function getTranslatable(app: Application) {
2225
const LOCALES = {

packages/typedoc-plugin-markdown/src/theme/base/url-builder.ts

+18-10
Original file line numberDiff line numberDiff line change
@@ -349,15 +349,23 @@ export class UrlBuilder {
349349
url = removeFirstScopedDirectory(url);
350350
}
351351

352-
const duplicateUrls = this.urls.filter(
353-
(urlMapping) =>
354-
urlMapping.url.toLowerCase() === url.toLowerCase() &&
355-
urlMapping.url !== url,
356-
);
357-
358-
if (duplicateUrls.length > 0) {
352+
while (
353+
this.urls.some(
354+
(urlMapping) =>
355+
urlMapping.url.toLowerCase() === url.toLowerCase() &&
356+
urlMapping.model.name !== reflection.name,
357+
)
358+
) {
359359
const urlParts = url.split('.');
360-
urlParts[urlParts.length - 2] += `-${duplicateUrls.length}`;
360+
const baseName = urlParts.slice(0, -1).join('.');
361+
const match = baseName.match(/-(\d+)$/);
362+
const currentCount = match ? parseInt(match[1], 10) : 0;
363+
const baseWithoutSuffix = match
364+
? baseName.slice(0, match.index)
365+
: baseName;
366+
367+
urlParts[urlParts.length - 2] =
368+
`${baseWithoutSuffix}-${currentCount + 1}`;
361369
url = urlParts.join('.');
362370
}
363371
}
@@ -389,7 +397,7 @@ export class UrlBuilder {
389397
});
390398
} else {
391399
reflection.traverse((child) => {
392-
this.applyAnchorUrl(child as any, reflection.url || '');
400+
this.applyAnchorUrl(child, reflection.url || '');
393401
});
394402
}
395403
} else if (reflection.parent) {
@@ -590,7 +598,7 @@ export class UrlBuilder {
590598
return null;
591599
}
592600
if (reflection.kind === ReflectionKind.Constructor) {
593-
return 'Constructors';
601+
return `constructors`;
594602
}
595603
const anchorParts = [reflection.name.replace(/[\\[\]]/g, '')];
596604
const typeParams = (reflection as DeclarationReflection)?.typeParameters;

packages/typedoc-plugin-markdown/src/theme/context/partials/container.body.ts

+22-21
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
import { heading, horizontalRule } from '@plugin/libs/markdown/index.js';
12
import { MarkdownThemeContext } from '@plugin/theme/index.js';
23
import {
34
ContainerReflection,
45
DeclarationReflection,
5-
DocumentReflection,
66
ReflectionKind,
77
} from 'typedoc';
88

@@ -37,30 +37,31 @@ export function body(
3737
}),
3838
);
3939
} else {
40-
if (model.children) {
41-
const groupChildren = model.groups
42-
?.filter(
43-
(group) =>
44-
!(group.owningReflection instanceof DocumentReflection),
45-
)
46-
.reduce((acc, group) => {
47-
return [...acc, ...group.children];
48-
}, []);
49-
md.push(
50-
this.partials.members(groupChildren as DeclarationReflection[], {
51-
headingLevel: options.headingLevel,
52-
}),
53-
);
40+
if (model.groups?.length) {
41+
model.groups.forEach((group, i) => {
42+
if (group.allChildrenHaveOwnDocument()) {
43+
md.push(heading(options.headingLevel, group.title));
44+
md.push(this.partials.groupIndex(group));
45+
} else {
46+
md.push(
47+
this.partials.members(
48+
group.children as DeclarationReflection[],
49+
{
50+
headingLevel: options.headingLevel,
51+
},
52+
),
53+
);
54+
if (model.groups && i < model.groups?.length - 1) {
55+
md.push(horizontalRule());
56+
}
57+
}
58+
});
5459
}
5560
}
5661
} else {
57-
const groups = model.groups?.filter(
58-
(group) => !(group.owningReflection instanceof DocumentReflection),
59-
);
60-
61-
if (groups?.length) {
62+
if (model.groups?.length) {
6263
md.push(
63-
this.partials.groups(groups, {
64+
this.partials.groups(model, {
6465
headingLevel: options.headingLevel,
6566
kind: model.kind,
6667
}),

packages/typedoc-plugin-markdown/src/theme/context/partials/container.categories.ts

+11-5
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,18 @@ import {
88

99
export function categories(
1010
this: MarkdownThemeContext,
11-
model: ReflectionCategory[],
11+
models: ReflectionCategory[],
1212
options: { headingLevel: number },
1313
) {
1414
const md: string[] = [];
15-
model
16-
?.filter((category) => !category.allChildrenHaveOwnDocument())
17-
.forEach((category) => {
15+
models.forEach((category) => {
16+
if (category.allChildrenHaveOwnDocument()) {
17+
md.push(heading(options.headingLevel, category.title));
18+
if (category.description) {
19+
md.push(this.helpers.getCommentParts(category.description));
20+
}
21+
md.push(this.partials.groupIndex(category));
22+
} else {
1823
const categoryChildren = category.children?.filter(
1924
(child) => child.kind !== ReflectionKind.Constructor,
2025
);
@@ -29,6 +34,7 @@ export function categories(
2934
}),
3035
);
3136
}
32-
});
37+
}
38+
});
3339
return md.join('\n\n');
3440
}

packages/typedoc-plugin-markdown/src/theme/context/partials/container.groups.ts

+80-49
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,109 @@
11
import { heading } from '@plugin/libs/markdown/index.js';
22
import { MarkdownThemeContext } from '@plugin/theme/index.js';
33
import {
4+
ContainerReflection,
45
DeclarationReflection,
5-
ReflectionGroup,
6+
ProjectReflection,
67
ReflectionKind,
78
} from 'typedoc';
89

910
export function groups(
1011
this: MarkdownThemeContext,
11-
model: ReflectionGroup[],
12+
model: ContainerReflection,
1213
options: { headingLevel: number; kind: ReflectionKind },
1314
) {
14-
const groupsWithChildren = model?.filter(
15-
(group) => !group.allChildrenHaveOwnDocument(),
16-
);
17-
1815
const md: string[] = [];
1916

2017
const getGroupTitle = (groupTitle: string) => {
2118
return groupTitle;
2219
};
2320

24-
groupsWithChildren?.forEach((group) => {
25-
const isEventProps = getGroupTitle(group.title) === 'Events';
26-
if (group.categories) {
27-
md.push(heading(options.headingLevel, getGroupTitle(group.title)));
28-
if (group.description) {
29-
md.push(this.helpers.getCommentParts(group.description));
21+
model.groups?.forEach((group) => {
22+
if (
23+
group.title === this.i18n.kind_plural_module() ||
24+
group.allChildrenHaveOwnDocument()
25+
) {
26+
const isPackages =
27+
this.options.getValue('entryPointStrategy') === 'packages' &&
28+
this.getPackagesCount() > 1 &&
29+
group.title === this.i18n.kind_plural_module() &&
30+
model.kind === ReflectionKind.Project;
31+
if (isPackages) {
32+
md.push(heading(options.headingLevel, this.i18n.theme_packages()));
33+
} else {
34+
md.push(heading(options.headingLevel, group.title));
3035
}
31-
md.push(
32-
this.partials.categories(group.categories, {
33-
headingLevel: options.headingLevel + 1,
34-
}),
35-
);
36-
} else {
37-
const isPropertiesGroup = group.children.every(
38-
(child) => child.kind === ReflectionKind.Property,
39-
);
40-
41-
const isEnumGroup = group.children.every(
42-
(child) => child.kind === ReflectionKind.EnumMember,
43-
);
44-
45-
md.push(heading(options.headingLevel, getGroupTitle(group.title)));
46-
4736
if (group.description) {
4837
md.push(this.helpers.getCommentParts(group.description));
4938
}
50-
if (
51-
isPropertiesGroup &&
52-
this.helpers.useTableFormat('properties', options.kind)
53-
) {
54-
md.push(
55-
this.partials.propertiesTable(
56-
group.children as DeclarationReflection[],
57-
{
58-
isEventProps,
59-
},
60-
),
61-
);
62-
} else if (isEnumGroup && this.helpers.useTableFormat('enums')) {
39+
if (group.categories) {
40+
group.categories.forEach((categoryGroup) => {
41+
md.push(heading(options.headingLevel + 1, categoryGroup.title));
42+
if (categoryGroup.description) {
43+
md.push(this.helpers.getCommentParts(categoryGroup.description));
44+
}
45+
md.push(this.partials.groupIndex(categoryGroup));
46+
});
47+
} else {
48+
if (isPackages) {
49+
md.push(this.partials.packagesIndex(model as ProjectReflection));
50+
} else {
51+
md.push(this.partials.groupIndex(group));
52+
}
53+
}
54+
} else {
55+
const isEventProps = getGroupTitle(group.title) === 'Events';
56+
if (group.categories) {
57+
md.push(heading(options.headingLevel, getGroupTitle(group.title)));
58+
if (group.description) {
59+
md.push(this.helpers.getCommentParts(group.description));
60+
}
6361
md.push(
64-
this.partials.enumMembersTable(
65-
group.children as DeclarationReflection[],
66-
),
62+
this.partials.categories(group.categories, {
63+
headingLevel: options.headingLevel + 1,
64+
}),
6765
);
6866
} else {
69-
if (group.children) {
67+
const isPropertiesGroup = group.children.every(
68+
(child) => child.kind === ReflectionKind.Property,
69+
);
70+
71+
const isEnumGroup = group.children.every(
72+
(child) => child.kind === ReflectionKind.EnumMember,
73+
);
74+
75+
md.push(heading(options.headingLevel, getGroupTitle(group.title)));
76+
77+
if (group.description) {
78+
md.push(this.helpers.getCommentParts(group.description));
79+
}
80+
if (
81+
isPropertiesGroup &&
82+
this.helpers.useTableFormat('properties', options.kind)
83+
) {
84+
md.push(
85+
this.partials.propertiesTable(
86+
group.children as DeclarationReflection[],
87+
{
88+
isEventProps,
89+
},
90+
),
91+
);
92+
} else if (isEnumGroup && this.helpers.useTableFormat('enums')) {
7093
md.push(
71-
this.partials.members(group.children as DeclarationReflection[], {
72-
headingLevel: options.headingLevel + 1,
73-
groupTitle: group.title,
74-
}),
94+
this.partials.enumMembersTable(
95+
group.children as DeclarationReflection[],
96+
),
7597
);
98+
} else {
99+
if (group.children) {
100+
md.push(
101+
this.partials.members(group.children as DeclarationReflection[], {
102+
headingLevel: options.headingLevel + 1,
103+
groupTitle: group.title,
104+
}),
105+
);
106+
}
76107
}
77108
}
78109
}

packages/typedoc-plugin-markdown/src/theme/context/partials/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ export * from './member.parametersList.js';
2121
export * from './member.parametersTable.js';
2222
export * from './member.propertiesTable.js';
2323
export * from './member.reference.js';
24-
export * from './member.reflectionIndex.js';
2524
export * from './member.signature.js';
2625
export * from './member.signatureParameters.js';
2726
export * from './member.signatureReturns.js';

packages/typedoc-plugin-markdown/src/theme/context/partials/member.memberWithGroups.ts

-11
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,6 @@ export function memberWithGroups(
9797
});
9898
}
9999

100-
if (
101-
model.documents ||
102-
model?.groups?.some((group) => group.allChildrenHaveOwnDocument())
103-
) {
104-
md.push(
105-
this.partials.reflectionIndex(model, {
106-
headingLevel: options.headingLevel,
107-
}),
108-
);
109-
}
110-
111100
md.push(this.partials.body(model, { headingLevel: options.headingLevel }));
112101

113102
return md.join('\n\n');

0 commit comments

Comments
 (0)