Skip to content
Merged
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
49 changes: 47 additions & 2 deletions src/components/Comment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,52 @@ export function hasComment(comment?: JSONOutput.Comment): boolean {
);
}

interface SinceReflection {
comment?: JSONOutput.Comment;
inheritedFrom?: JSONOutput.ReferenceType;
sources?: JSONOutput.SourceReference[];
}

// Native runtime symbols: the TypeScript standard library (`lib.*.d.ts`) and
// Node's built-in type definitions (`@types/node`). These have no meaningful
// `@since` of their own — a `@since` on such a member would be copied noise — so
// we always drop it. Other dependencies under `node_modules` are NOT native:
// their `@since` tags (if any) reflect that package's real release history, so
// inherited members keep them.
const NATIVE_SOURCE = /(?:^|\/)node_modules\/(?:typescript\/lib\/|@types\/node\/)/;

function isNativeReflection(reflection: SinceReflection): boolean {
const fileName = reflection.sources?.[0]?.fileName;

return !!fileName && NATIVE_SOURCE.test(fileName);
}

// Return the content of an `@since` tag explicitly present on the reflection.
//
// TypeDoc copies a base member's doc comment onto the members that inherit it,
// so an inherited symbol naturally carries the `@since` it was given in its
// base — we keep that, mirroring how every other inherited doc behaves
// (including symbols inherited from other packages). The exception is members
// inherited from a native runtime type (e.g. `Error`): those carry no real
// version, so we drop it.
export function getSinceContent(
reflection: SinceReflection | undefined,
): JSONOutput.CommentDisplayPart[] | undefined {
const content = reflection?.comment?.blockTags?.find(
(blockTag) => blockTag.tag === '@since',
)?.content;

if (!content) {
return undefined;
}

if (reflection.inheritedFrom && isNativeReflection(reflection)) {
return undefined;
}

return content;
}

export function displayPartsToMarkdown(parts: JSONOutput.CommentDisplayPart[]): string {
return parts
.map((part) => {
Expand All @@ -38,8 +84,7 @@ export function Comment({ comment, root, hideTags = [] }: CommentProps) {
}

// Hide custom tags.
hideTags.push('@reference');
hideTags.push('@since');
hideTags.push('@reference', '@since');

const blockTags =
comment.blockTags?.filter((tag) => {
Expand Down
8 changes: 4 additions & 4 deletions src/components/MemberDeclaration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { useMinimalLayout } from '../hooks/useMinimalLayout';
import { useRequiredReflection } from '../hooks/useReflection';
import { escapeMdx } from '../utils/helpers';
import { Comment, displayPartsToMarkdown, hasComment } from './Comment';
import { Comment, displayPartsToMarkdown, getSinceContent, hasComment } from './Comment';
import { DefaultValue } from './DefaultValue';
import { Icon } from './Icon';
import { Markdown } from './Markdown';
Expand All @@ -22,7 +22,7 @@ export function MemberDeclaration({ id }: MemberDeclarationProps) {
const minimal = useMinimalLayout();
const showTypes = reflection.typeParameters && reflection.typeParameters.length > 0;
const showDeclaration = !minimal && extractDeclarationFromType(reflection.type);
const showSince = reflection.comment?.blockTags?.some((tag) => tag.tag === '@since');
const sinceContent = getSinceContent(reflection);

return (
<>
Expand Down Expand Up @@ -64,9 +64,9 @@ export function MemberDeclaration({ id }: MemberDeclarationProps) {
</div>
)}

{showSince && (
{sinceContent && (
<div className="tsd-comment-since">
<Markdown content={displayPartsToMarkdown(reflection.comment?.blockTags?.find((tag) => tag.tag === '@since')?.content)} />
<Markdown content={displayPartsToMarkdown(sinceContent)} />
</div>
)}
</div>
Expand Down
10 changes: 5 additions & 5 deletions src/components/MemberSignatureBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import { usePluginData } from '@docusaurus/useGlobalData';
import { useMinimalLayout } from '../hooks/useMinimalLayout';
import type { TSDSignatureReflection } from '../types';
import { ApiDataContext } from './ApiDataContext';
import { Comment, displayPartsToMarkdown, hasComment } from './Comment';
import { Comment, displayPartsToMarkdown, getSinceContent, hasComment } from './Comment';
import { CommentBadges, isCommentWithModifiers } from './CommentBadges';
import { DefaultValue } from './DefaultValue';
import { Flags } from './Flags';
import { Markdown } from './Markdown';
import { hasSources, MemberSources } from './MemberSources';
import { Parameter } from './Parameter';
import { extractDeclarationFromType, Type } from './Type';
import { TypeParameters } from './TypeParameters';
import { Markdown } from './Markdown';

export function hasSigBody(
sig: TSDSignatureReflection | undefined,
Expand Down Expand Up @@ -63,9 +63,9 @@ export function MemberSignatureBody({ hideSources, sig }: MemberSignatureBodyPro
const showTypes = sig.typeParameter && sig.typeParameter.length > 0;
const showParams = !minimal && sig.parameters && sig.parameters.length > 0;
const showReturn = !minimal && sig.type;
const showSince = sig.comment?.blockTags?.some((tag) => tag.tag === '@since');

const { reflections } = useContext(ApiDataContext);
const sinceContent = getSinceContent(sig);
const { isPython } = usePluginData('docusaurus-plugin-typedoc-api') as GlobalData;

if (isPython) {
Expand Down Expand Up @@ -218,10 +218,10 @@ export function MemberSignatureBody({ hideSources, sig }: MemberSignatureBodyPro
)}

{
showSince && (
sinceContent && (
<>
<div className="tsd-comment-since">
<Markdown content={displayPartsToMarkdown(sig.comment.blockTags?.find((tag) => tag.tag === '@since')?.content)} />
<Markdown content={displayPartsToMarkdown(sinceContent)} />
</div>
</>
)
Expand Down
15 changes: 14 additions & 1 deletion src/components/Reflection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
import { useMemo } from 'react';
import type { TSDDeclarationReflection, TSDReflection, TSDSignatureReflection } from '../types';
import { createHierarchy } from '../utils/hierarchy';
import { Comment, hasComment } from './Comment';
import { Comment, displayPartsToMarkdown, getSinceContent, hasComment } from './Comment';
import { CommentBadges, isCommentWithModifiers } from './CommentBadges';
import { Hierarchy } from './Hierarchy';
import { Icon } from './Icon';
import { Index } from './Index';
import { Markdown } from './Markdown';
import { Members } from './Members';
import { MemberSignatures } from './MemberSignatures';
import { Parameter } from './Parameter';
Expand All @@ -20,12 +21,24 @@ export interface ReflectionProps {

export function Reflection({ reflection }: ReflectionProps) {
const hierarchy = useMemo(() => createHierarchy(reflection), [reflection]);
// Callable top-level symbols (functions) render `@since` on their signatures
// below, so only surface it here for non-callable symbols (classes,
// interfaces, enums, type aliases, ...) where it would otherwise be missing.
const hasOwnSignatures =
'signatures' in reflection && !!reflection.signatures && reflection.signatures.length > 0;
const sinceContent = hasOwnSignatures ? undefined : getSinceContent(reflection);

return (
<>
{isCommentWithModifiers(reflection.comment) && <CommentBadges comment={reflection.comment} />}
{hasComment(reflection.comment) && <Comment root comment={reflection.comment} />}

{sinceContent && (
<div className="tsd-comment-since">
<Markdown content={displayPartsToMarkdown(sinceContent)} />
</div>
)}

{'typeParameter' in reflection &&
reflection.typeParameter &&
reflection.typeParameter.length > 0 &&
Expand Down
Loading