Files
discord.js/apps/website/src/components/documentation/util.ts
Qjuh 802ec63a48 fix(website): cross package deprecated links (#9981)
* refactor: minify api.json by shortening keys

* fix: links to other packages

* refactor: get doclink from canonicalReference, not model

* fix: types

* fix: again

* fix: @link tags with alt texts

* fix(website): cross-package links in @deprecated
2023-11-18 11:45:32 +01:00

172 lines
5.6 KiB
TypeScript

import { ApiItemKind, Meaning } from '@discordjs/api-extractor-model';
import type {
ApiItem,
ApiItemContainerMixin,
ApiMethod,
ApiMethodSignature,
ApiProperty,
ApiPropertySignature,
ApiDocumentedItem,
ApiParameterListMixin,
ApiEvent,
} from '@discordjs/api-extractor-model';
import type { DocDeclarationReference } from '@microsoft/tsdoc';
import { SelectorKind } from '@microsoft/tsdoc';
import type { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference';
import { METHOD_SEPARATOR, OVERLOAD_SEPARATOR } from '~/util/constants';
import { resolveMembers } from '~/util/members';
import { resolveParameters } from '~/util/model';
import type { TableOfContentsSerialized } from '../TableOfContentItems';
export type ApiItemLike = {
[K in keyof ApiItem]?: K extends 'displayName' | 'kind'
? ApiItem[K]
: K extends 'parent'
? ApiItemLike | undefined
: ApiItem[K] | undefined;
};
interface ResolvedCanonicalReference {
item: ApiItemLike;
package: string | undefined;
}
export function hasProperties(item: ApiItemContainerMixin) {
return resolveMembers(item, memberPredicate).some(
({ item: member }) => member.kind === ApiItemKind.Property || member.kind === ApiItemKind.PropertySignature,
);
}
export function hasMethods(item: ApiItemContainerMixin) {
return resolveMembers(item, memberPredicate).some(
({ item: member }) => member.kind === ApiItemKind.Method || member.kind === ApiItemKind.MethodSignature,
);
}
export function hasEvents(item: ApiItemContainerMixin) {
return resolveMembers(item, memberPredicate).some(({ item: member }) => member.kind === ApiItemKind.Event);
}
export function resolveItemURI(item: ApiItemLike): string {
return !item.parent || item.parent.kind === ApiItemKind.EntryPoint
? `${item.displayName}${OVERLOAD_SEPARATOR}${item.kind}`
: `${item.parent.displayName}${OVERLOAD_SEPARATOR}${item.parent.kind}${METHOD_SEPARATOR}${item.displayName}`;
}
export function resolveCanonicalReference(
canonicalReference: DeclarationReference | DocDeclarationReference,
): ResolvedCanonicalReference | null {
if (
'source' in canonicalReference &&
canonicalReference.source &&
'packageName' in canonicalReference.source &&
canonicalReference.symbol?.componentPath &&
canonicalReference.symbol.meaning
)
return {
package: canonicalReference.source.unscopedPackageName,
item: {
kind: mapMeaningToKind(canonicalReference.symbol.meaning as unknown as Meaning),
displayName: canonicalReference.symbol.componentPath.component.toString(),
containerKey: `|${
canonicalReference.symbol.meaning
}|${canonicalReference.symbol.componentPath.component.toString()}`,
},
};
else if (
'memberReferences' in canonicalReference &&
canonicalReference.memberReferences.length &&
canonicalReference.memberReferences[0]?.memberIdentifier &&
canonicalReference.memberReferences[0]?.selector?.selectorKind === SelectorKind.System
) {
const member = canonicalReference.memberReferences[0]!;
return {
package: canonicalReference.packageName?.replace('@discordjs/', ''),
item: {
kind: member.selector!.selector as ApiItemKind,
displayName: member.memberIdentifier!.identifier,
containerKey: `|${member.selector!.selector}|${member.memberIdentifier!.identifier}`,
},
};
}
return null;
}
function mapMeaningToKind(meaning: Meaning): ApiItemKind {
switch (meaning) {
case Meaning.CallSignature:
return ApiItemKind.CallSignature;
case Meaning.Class:
return ApiItemKind.Class;
case Meaning.ComplexType:
throw new Error('Not a valid canonicalReference: Meaning.ComplexType');
case Meaning.ConstructSignature:
return ApiItemKind.ConstructSignature;
case Meaning.Constructor:
return ApiItemKind.Constructor;
case Meaning.Enum:
return ApiItemKind.Enum;
case Meaning.Event:
return ApiItemKind.Event;
case Meaning.Function:
return ApiItemKind.Function;
case Meaning.IndexSignature:
return ApiItemKind.IndexSignature;
case Meaning.Interface:
return ApiItemKind.Interface;
case Meaning.Member:
return ApiItemKind.Property;
case Meaning.Namespace:
return ApiItemKind.Namespace;
case Meaning.TypeAlias:
return ApiItemKind.TypeAlias;
case Meaning.Variable:
return ApiItemKind.Variable;
}
}
export function memberPredicate(
item: ApiItem,
): item is ApiEvent | ApiMethod | ApiMethodSignature | ApiProperty | ApiPropertySignature {
return (
item.kind === ApiItemKind.Property ||
item.kind === ApiItemKind.PropertySignature ||
item.kind === ApiItemKind.Method ||
item.kind === ApiItemKind.MethodSignature ||
item.kind === ApiItemKind.Event
);
}
export function serializeMembers(clazz: ApiItemContainerMixin): TableOfContentsSerialized[] {
return resolveMembers(clazz, memberPredicate).map(({ item: member }) => {
if (member.kind === 'Method' || member.kind === 'MethodSignature') {
return {
kind: member.kind as 'Method' | 'MethodSignature',
name: member.displayName,
};
} else if (member.kind === 'Event') {
return {
kind: member.kind as 'Event',
name: member.displayName,
};
} else {
return {
kind: member.kind as 'Property' | 'PropertySignature',
name: member.displayName,
overloadIndex: (member as ApiMethod | ApiMethodSignature).overloadIndex,
};
}
});
}
export function parametersString(item: ApiDocumentedItem & ApiParameterListMixin) {
return resolveParameters(item).reduce((prev, cur, index) => {
if (index === 0) {
return `${prev}${cur.isRest ? '...' : ''}${cur.isOptional ? `${cur.name}?` : cur.name}`;
}
return `${prev}, ${cur.isRest ? '...' : ''}${cur.isOptional ? `${cur.name}?` : cur.name}`;
}, '');
}