Skip to content

Commit

Permalink
Add support for the @group tag
Browse files Browse the repository at this point in the history
Resolves #1652
  • Loading branch information
Gerrit0 committed Apr 17, 2022
1 parent f09a1e9 commit e9c143f
Show file tree
Hide file tree
Showing 35 changed files with 150 additions and 503 deletions.
6 changes: 3 additions & 3 deletions CHANGELOG.md
Expand Up @@ -8,8 +8,6 @@ These TODOs will be resolved before a full release. ([GitHub project](https://gi
- Make comment parser options configurable (read tsdoc.json?).
- Full support for declaration references, #262, #488, #1326, #1845.
- Add support for additional comment styles, #1433.
- Add support for `@group` tags, #1652.
- Add support for `@eventProperty`, and rework `@event` to be equivalent, in defining an element to be part of the "Events" group.
- Theme: Custom rendering for `@see` tags.
- Theme: Show toggles for all modifier tags used in a project to allow users to filter by deprecated/alpha/beta, etc.
- Add option to control default values (merge #1816. Same option? Different one since it's based on comments?)
Expand All @@ -30,11 +28,13 @@ These TODOs will be resolved before a full release. ([GitHub project](https://gi
- Constant variables which are interpreted as functions will no longer have the `ReflectionFlag.Const` flag set.
- Removed deprecated `removeReaderByName`, `addDeclarations` and `removeDeclarationByName` methods on `Options`.
- Removed `ProjectReflection.directory`, it was unused by TypeDoc and not properly tested.
- Removed `ProjectReflection.files`, this was an internal cache that should not have been exposed.
- Removed `ProjectReflection.files`, this was an internal cache that should not have been exposed, and shouldn't have existed in the first place, since removing it made TypeDoc faster.
- Removed `ReflectionKind.Event`, the `@event` tag is now an alias for `@group Events`.
- Themes are now set on the document element rather than on body, #1706.

### Features

- TypeDoc now supports the `@group` tag to group reflections in a page. If no `@group` tag is specified, reflections will be grouped according to their kind, #1652.
- TypeDoc will now search for `typedoc.js(on)` in the `.config` folder in the current working directory.
- If an exported symbol has multiple declarations, TypeDoc will now check all appropriate declarations for comments, and warn if more than one declaration contains a comment, #1855.
- Improved support for JSDoc style `@example` tags. If the tag content does not include a code block, TypeDoc now follows VSCode's behavior of treating the entire block as a code block, #135.
Expand Down
1 change: 0 additions & 1 deletion src/lib/converter/comments/discovery.ts
Expand Up @@ -73,7 +73,6 @@ const wantedKinds: Record<ReflectionKind, ts.SyntaxKind[]> = {
[ReflectionKind.SetSignature]: [ts.SyntaxKind.SetAccessor],
[ReflectionKind.ObjectLiteral]: [ts.SyntaxKind.ObjectLiteralExpression],
[ReflectionKind.TypeAlias]: [ts.SyntaxKind.TypeAliasDeclaration],
[ReflectionKind.Event]: [], /// this needs to go away
[ReflectionKind.Reference]: [
ts.SyntaxKind.NamespaceExport,
ts.SyntaxKind.ExportSpecifier,
Expand Down
2 changes: 2 additions & 0 deletions src/lib/converter/context.ts
Expand Up @@ -175,6 +175,7 @@ export class Context {
// TypeDoc specific
"@module",
"@inheritDoc",
"@group",
]),
inlineTags: new Set(["@link", "@inheritDoc", "@label"]),
modifierTags: new Set([
Expand All @@ -185,6 +186,7 @@ export class Context {
"@internal",
"@readonly",
"@packageDocumentation",
"@eventProperty",
"@deprecated",
"@alpha",
"@beta",
Expand Down
84 changes: 0 additions & 84 deletions src/lib/converter/converter.ts
Expand Up @@ -171,90 +171,6 @@ export class Converter extends ChildableComponent<
return convertType(context, node);
}

/** @internal */
getNodesForSymbol(symbol: ts.Symbol, kind: ReflectionKind) {
const wantedKinds: ts.SyntaxKind[] = {
[ReflectionKind.Project]: [ts.SyntaxKind.SourceFile],
[ReflectionKind.Module]: [ts.SyntaxKind.SourceFile],
[ReflectionKind.Namespace]: [
ts.SyntaxKind.ModuleDeclaration,
ts.SyntaxKind.SourceFile,
],
[ReflectionKind.Enum]: [
ts.SyntaxKind.EnumDeclaration,
ts.SyntaxKind.VariableDeclaration,
],
[ReflectionKind.EnumMember]: [
ts.SyntaxKind.EnumMember,
ts.SyntaxKind.PropertyAssignment,
ts.SyntaxKind.PropertySignature,
],
[ReflectionKind.Variable]: [
ts.SyntaxKind.VariableDeclaration,
ts.SyntaxKind.ExportAssignment,
],
[ReflectionKind.Function]: [
ts.SyntaxKind.FunctionDeclaration,
ts.SyntaxKind.VariableDeclaration,
],
[ReflectionKind.Class]: [ts.SyntaxKind.ClassDeclaration],
[ReflectionKind.Interface]: [
ts.SyntaxKind.InterfaceDeclaration,
ts.SyntaxKind.JSDocTypedefTag,
],
[ReflectionKind.Constructor]: [ts.SyntaxKind.Constructor],
[ReflectionKind.Property]: [
ts.SyntaxKind.PropertyDeclaration,
ts.SyntaxKind.PropertyAssignment,
ts.SyntaxKind.PropertySignature,
ts.SyntaxKind.JSDocPropertyTag,
ts.SyntaxKind.BinaryExpression,
],
[ReflectionKind.Method]: [
ts.SyntaxKind.MethodDeclaration,
ts.SyntaxKind.PropertyDeclaration,
ts.SyntaxKind.PropertySignature,
],
[ReflectionKind.CallSignature]: [
ts.SyntaxKind.FunctionDeclaration,
ts.SyntaxKind.VariableDeclaration,
ts.SyntaxKind.MethodDeclaration,
ts.SyntaxKind.MethodDeclaration,
ts.SyntaxKind.PropertyDeclaration,
ts.SyntaxKind.PropertySignature,
ts.SyntaxKind.CallSignature,
],
[ReflectionKind.IndexSignature]: [ts.SyntaxKind.IndexSignature],
[ReflectionKind.ConstructorSignature]: [
ts.SyntaxKind.ConstructSignature,
],
[ReflectionKind.Parameter]: [ts.SyntaxKind.Parameter],
[ReflectionKind.TypeLiteral]: [ts.SyntaxKind.TypeLiteral],
[ReflectionKind.TypeParameter]: [ts.SyntaxKind.TypeParameter],
[ReflectionKind.Accessor]: [
ts.SyntaxKind.GetAccessor,
ts.SyntaxKind.SetAccessor,
],
[ReflectionKind.GetSignature]: [ts.SyntaxKind.GetAccessor],
[ReflectionKind.SetSignature]: [ts.SyntaxKind.SetAccessor],
[ReflectionKind.ObjectLiteral]: [
ts.SyntaxKind.ObjectLiteralExpression,
],
[ReflectionKind.TypeAlias]: [
ts.SyntaxKind.TypeAliasDeclaration,
ts.SyntaxKind.JSDocTypedefTag,
],
[ReflectionKind.Event]: [], /// this needs to go away
[ReflectionKind.Reference]: [
ts.SyntaxKind.NamespaceExport,
ts.SyntaxKind.ExportSpecifier,
],
}[kind];

const declarations = symbol.getDeclarations() ?? [];
return declarations.filter((d) => wantedKinds.includes(d.kind));
}

/**
* Compile the files within the given context and convert the compiler symbols to reflections.
*
Expand Down
3 changes: 3 additions & 0 deletions src/lib/converter/plugins/CategoryPlugin.ts
Expand Up @@ -175,6 +175,9 @@ export class CategoryPlugin extends ConverterComponent {
*
* @param reflection The reflection.
* @returns The category the reflection belongs to
*
* @privateRemarks
* If you change this, also update getGroups in GroupPlugin accordingly.
*/
static getCategories(reflection: DeclarationReflection) {
const categories = new Set<string>();
Expand Down
16 changes: 9 additions & 7 deletions src/lib/converter/plugins/CommentPlugin.ts
Expand Up @@ -13,6 +13,7 @@ import {
ReflectionType,
SourceReference,
TypeVisitor,
CommentTag,
} from "../../models";
import {
BindOption,
Expand Down Expand Up @@ -97,14 +98,15 @@ export class CommentPlugin extends ConverterComponent {
comment.removeModifier("@public");
}

if (comment.hasModifier("@event")) {
if (reflection.kindOf(ReflectionKind.CallSignature)) {
if (reflection.parent) {
reflection.parent.kind = ReflectionKind.Event;
}
}
reflection.kind = ReflectionKind.Event;
if (
comment.hasModifier("@event") ||
comment.hasModifier("@eventProperty")
) {
comment.blockTags.push(
new CommentTag("@group", [{ kind: "text", text: "Events" }])
);
comment.removeModifier("@event");
comment.removeModifier("@eventProperty");
}

if (
Expand Down
74 changes: 53 additions & 21 deletions src/lib/converter/plugins/GroupPlugin.ts
Expand Up @@ -9,7 +9,8 @@ import { Component, ConverterComponent } from "../components";
import { Converter } from "../converter";
import type { Context } from "../context";
import { sortReflections, SortStrategy } from "../../utils/sort";
import { BindOption } from "../../utils";
import { BindOption, removeIf } from "../../utils";
import { Comment } from "../../models";

/**
* A handler that sorts and groups the found reflections in the resolving phase.
Expand Down Expand Up @@ -87,6 +88,45 @@ export class GroupPlugin extends ConverterComponent {
}
}

/**
* Extracts the groups for a given reflection.
*
* @privateRemarks
* If you change this, also update getCategories in CategoryPlugin accordingly.
*/
static getGroups(reflection: DeclarationReflection) {
const groups = new Set<string>();
function extractGroupTags(comment: Comment | undefined) {
if (!comment) return;
removeIf(comment.blockTags, (tag) => {
if (tag.tag === "@group") {
groups.add(Comment.combineDisplayParts(tag.content).trim());

return true;
}
return false;
});
}

extractGroupTags(reflection.comment);
for (const sig of reflection.getNonIndexSignatures()) {
extractGroupTags(sig.comment);
}

if (reflection.type?.type === "reflection") {
extractGroupTags(reflection.type.declaration.comment);
for (const sig of reflection.type.declaration.getNonIndexSignatures()) {
extractGroupTags(sig.comment);
}
}

groups.delete("");
if (groups.size === 0) {
groups.add(GroupPlugin.getKindPlural(reflection.kind));
}
return groups;
}

/**
* Create a grouped representation of the given list of reflections.
*
Expand All @@ -98,24 +138,17 @@ export class GroupPlugin extends ConverterComponent {
static getReflectionGroups(
reflections: DeclarationReflection[]
): ReflectionGroup[] {
const groups: ReflectionGroup[] = [];
const groups = new Map<string, ReflectionGroup>();
reflections.forEach((child) => {
for (let i = 0; i < groups.length; i++) {
const group = groups[i];
if (group.kind !== child.kind) {
continue;
for (const name of GroupPlugin.getGroups(child)) {
let group = groups.get(name);
if (!group) {
group = new ReflectionGroup(name);
groups.set(name, group);
}

group.children.push(child);
return;
}

const group = new ReflectionGroup(
GroupPlugin.getKindPlural(child.kind),
child.kind
);
group.children.push(child);
groups.push(group);
});

groups.forEach((group) => {
Expand All @@ -125,14 +158,13 @@ export class GroupPlugin extends ConverterComponent {
let allExternal = true;

group.children.forEach((child) => {
allPrivate = child.flags.isPrivate && allPrivate;
allProtected =
(child.flags.isPrivate || child.flags.isProtected) &&
allProtected;
allExternal = child.flags.isExternal && allExternal;
allPrivate &&= child.flags.isPrivate;
allProtected &&=
child.flags.isPrivate || child.flags.isProtected;
allExternal &&= child.flags.isExternal;

if (child instanceof DeclarationReflection) {
allInherited = !!child.inheritedFrom && allInherited;
allInherited &&= !!child.inheritedFrom;
} else {
allInherited = false;
}
Expand All @@ -144,7 +176,7 @@ export class GroupPlugin extends ConverterComponent {
group.allChildrenAreExternal = allExternal;
});

return groups;
return Array.from(groups.values());
}

/**
Expand Down
11 changes: 1 addition & 10 deletions src/lib/models/ReflectionGroup.ts
@@ -1,4 +1,3 @@
import type { ReflectionKind } from "./reflections/kind";
import type { ReflectionCategory } from "./ReflectionCategory";
import type { DeclarationReflection } from ".";
import type { Serializer, JSONOutput } from "../serialization";
Expand All @@ -16,11 +15,6 @@ export class ReflectionGroup {
*/
title: string;

/**
* The original typescript kind of the children of this group.
*/
kind: ReflectionKind;

/**
* All reflections of this group.
*/
Expand Down Expand Up @@ -61,11 +55,9 @@ export class ReflectionGroup {
* Create a new ReflectionGroup instance.
*
* @param title The title of this group.
* @param kind The original typescript kind of the children of this group.
*/
constructor(title: string, kind: ReflectionKind) {
constructor(title: string) {
this.title = title;
this.kind = kind;
}

/**
Expand All @@ -78,7 +70,6 @@ export class ReflectionGroup {
toObject(serializer: Serializer): JSONOutput.ReflectionGroup {
return {
title: this.title,
kind: this.kind,
children:
this.children.length > 0
? this.children.map((child) => child.id)
Expand Down
7 changes: 7 additions & 0 deletions src/lib/models/comments/comment.ts
Expand Up @@ -212,6 +212,13 @@ export class Comment {
return this.blockTags.find((tag) => tag.tag === tagName);
}

/**
* Get all tags with the given tag name.
*/
getTags(tagName: `@${string}`): CommentTag[] {
return this.blockTags.filter((tag) => tag.tag === tagName);
}

getIdentifiedTag(identifier: string, tagName: `@${string}`) {
return this.blockTags.find(
(tag) => tag.tag === tagName && tag.name === identifier
Expand Down
4 changes: 1 addition & 3 deletions src/lib/models/reflections/kind.ts
Expand Up @@ -25,7 +25,6 @@ export enum ReflectionKind {
SetSignature = 0x100000,
ObjectLiteral = 0x200000,
TypeAlias = 0x400000,
Event = 0x800000,
Reference = 0x1000000,
}

Expand All @@ -43,8 +42,7 @@ export namespace ReflectionKind {
ReflectionKind.Accessor |
ReflectionKind.Constructor |
ReflectionKind.Method |
ReflectionKind.Property |
ReflectionKind.Event;
ReflectionKind.Property;
export const SomeSignature =
ReflectionKind.CallSignature |
ReflectionKind.IndexSignature |
Expand Down
9 changes: 0 additions & 9 deletions src/lib/output/themes/default/partials/icon.tsx
Expand Up @@ -70,15 +70,6 @@ export const icons: Record<ReflectionKind, () => JSX.Element | null> & UtilityIc
[ReflectionKind.EnumMember]() {
return this[ReflectionKind.Property]();
},
[ReflectionKind.Event]: () =>
kindIcon(
<path
d="M9.45 16V7.24H14.49V8.224H10.518V10.936H14.07V11.908H10.518V15.016H14.49V16H9.45Z"
fill="var(--color-text)"
/>,
"#7FDE21",
true
),
[ReflectionKind.Function]: () =>
kindIcon(
<path d="M9.39 16V7.24H14.55V8.224H10.446V11.128H14.238V12.112H10.47V16H9.39Z" fill="var(--color-text)" />,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/serialization/schema.ts
Expand Up @@ -100,7 +100,7 @@ type S<T, K extends keyof T> = {
// Reflections

export interface ReflectionGroup
extends S<M.ReflectionGroup, "title" | "kind" | "categories"> {
extends S<M.ReflectionGroup, "title" | "categories"> {
children?: M.ReflectionGroup["children"][number]["id"][];
}

Expand Down
1 change: 0 additions & 1 deletion src/lib/utils/sort.ts
Expand Up @@ -115,7 +115,6 @@ const sorts: Record<
ReflectionKind.TypeAlias,

ReflectionKind.Constructor,
ReflectionKind.Event,
ReflectionKind.Property,
ReflectionKind.Variable,
ReflectionKind.Function,
Expand Down

0 comments on commit e9c143f

Please sign in to comment.