diff --git a/packages/docgen/src/documentation.ts b/packages/docgen/src/documentation.ts index 5cf0bf2a5..04184d69d 100644 --- a/packages/docgen/src/documentation.ts +++ b/packages/docgen/src/documentation.ts @@ -36,7 +36,7 @@ export class Documentation { case 'Class': { this.classes.set(item.name, new DocumentedClass(item, config)); if (item.children) { - this.parse(item.children, item.name); + this.parse(item.children, item); } break; } @@ -51,7 +51,7 @@ export class Documentation { case 'Enumeration': this.typedefs.set(item.name, new DocumentedTypeDef(item, config)); if (item.children) { - this.parse(item.children, item.name); + this.parse(item.children, item); } break; @@ -101,7 +101,7 @@ export class Documentation { } } - public parse(items: ChildTypes[] | DeclarationReflection[], memberOf = '') { + public parse(items: ChildTypes[] | DeclarationReflection[], p?: DeclarationReflection) { if (this.config.typescript) { const it = items as DeclarationReflection[]; @@ -114,6 +114,12 @@ export class Documentation { break; } case 'Method': { + const event = p?.groups?.find((group) => group.title === 'Events'); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if ((event?.children as unknown as number[])?.includes(member.id)) { + item = new DocumentedEvent(member, this.config); + break; + } item = new DocumentedMethod(member, this.config); break; } @@ -121,17 +127,13 @@ export class Documentation { item = new DocumentedMember(member, this.config); break; } - case 'Event': { - item = new DocumentedEvent(member, this.config); - break; - } default: { // eslint-disable-next-line @typescript-eslint/restrict-template-expressions console.warn(`- Unknown documentation kind "${member.kindString}" - \n${JSON.stringify(member)}\n`); } } - const parent = this.classes.get(memberOf) ?? this.interfaces.get(memberOf); + const parent = this.classes.get(p!.name) ?? this.interfaces.get(p!.name); if (parent) { if (item) { parent.add(item); @@ -154,8 +156,8 @@ export class Documentation { path: dirname(member.sources?.[0]?.fileName ?? ''), }; - if (memberOf) { - info.push(`member of "${memberOf}"`); + if (p!.name) { + info.push(`member of "${p!.name}"`); } if (meta) { info.push( diff --git a/packages/docgen/src/types/event.ts b/packages/docgen/src/types/event.ts index f3f962e35..0158b7ebb 100644 --- a/packages/docgen/src/types/event.ts +++ b/packages/docgen/src/types/event.ts @@ -2,7 +2,9 @@ import type { DeclarationReflection, SignatureReflection } from 'typedoc'; import { DocumentedItemMeta } from './item-meta.js'; import { DocumentedItem } from './item.js'; import { DocumentedParam } from './param.js'; +import { DocumentedVarType } from './var-type.js'; import type { Event } from '../interfaces/index.js'; +import { parseType } from '../util/parseType.js'; export class DocumentedEvent extends DocumentedItem { public override serializer() { @@ -23,11 +25,27 @@ export class DocumentedEvent extends DocumentedItem t.content.find((c) => c.kind === 'text')?.text.trim()) : undefined; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + const examples = signature.comment?.blockTags?.filter((t) => t.tag === '@example').length + ? signature.comment.blockTags + .filter((t) => t.tag === '@example') + .map((t) => t.content.reduce((prev, curr) => (prev += curr.text), '').trim()) + : undefined; + return { - name: signature.name, + // @ts-expect-error + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access + name: signature.parameters?.[0]?.type?.value, // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, @typescript-eslint/prefer-nullish-coalescing description: signature.comment?.summary?.reduce((prev, curr) => (prev += curr.text), '').trim() || undefined, see, + access: + data.flags.isPrivate || + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + signature.comment?.blockTags?.some((t) => t.tag === '@private' || t.tag === '@internal') + ? 'private' + : undefined, + examples, // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition deprecated: signature.comment?.blockTags?.some((t) => t.tag === '@deprecated') ? signature.comment.blockTags @@ -37,8 +55,34 @@ export class DocumentedEvent extends DocumentedItem new DocumentedParam(p, this.config).serialize()) + ? (signature as SignatureReflection).parameters + ?.slice(1) + .map((p) => new DocumentedParam(p, this.config).serialize()) : undefined, + returns: signature.type + ? [ + new DocumentedVarType( + { + names: [parseType(signature.type)], + description: + signature.comment?.blockTags + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + ?.find((t) => t.tag === '@returns') + ?.content.reduce((prev, curr) => (prev += curr.text), '') + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + .trim() || undefined, + }, + this.config, + ).serialize(), + ] + : undefined, + returnsDescription: + signature.comment?.blockTags + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + ?.find((t) => t.tag === '@returns') + ?.content.reduce((prev, curr) => (prev += curr.text), '') + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + .trim() || undefined, meta, }; } diff --git a/packages/voice/__tests__/SpeakingMap.test.ts b/packages/voice/__tests__/SpeakingMap.test.ts index 92087ebd3..4f9a27462 100644 --- a/packages/voice/__tests__/SpeakingMap.test.ts +++ b/packages/voice/__tests__/SpeakingMap.test.ts @@ -11,8 +11,8 @@ describe('SpeakingMap', () => { const starts: string[] = []; const ends: string[] = []; - speaking.on('start', (userId) => void starts.push(userId)); - speaking.on('end', (userId) => void ends.push(userId)); + speaking.on('start', (userId: string) => void starts.push(userId)); + speaking.on('end', (userId: string) => void ends.push(userId)); for (let i = 0; i < 10; i++) { speaking.onPacket(userId); diff --git a/packages/voice/package.json b/packages/voice/package.json index 8c17ae5b2..11e573703 100644 --- a/packages/voice/package.json +++ b/packages/voice/package.json @@ -54,7 +54,6 @@ "@types/ws": "^8.5.3", "discord-api-types": "^0.33.5", "prism-media": "^1.3.2", - "tiny-typed-emitter": "^2.1.0", "tslib": "^2.4.0", "ws": "^8.8.0" }, diff --git a/packages/voice/src/VoiceConnection.ts b/packages/voice/src/VoiceConnection.ts index b326a0061..78001934a 100644 --- a/packages/voice/src/VoiceConnection.ts +++ b/packages/voice/src/VoiceConnection.ts @@ -1,6 +1,5 @@ -/* eslint-disable @typescript-eslint/prefer-ts-expect-error */ +import { EventEmitter } from 'node:events'; import type { GatewayVoiceServerUpdateDispatchData, GatewayVoiceStateUpdateDispatchData } from 'discord-api-types/v10'; -import { TypedEmitter } from 'tiny-typed-emitter'; import type { CreateVoiceConnectionOptions } from '.'; import { getVoiceConnection, @@ -15,7 +14,7 @@ import type { VoiceWebSocket, VoiceUDPSocket } from './networking'; import { Networking, NetworkingState, NetworkingStatusCode } from './networking/Networking'; import { VoiceReceiver } from './receive'; import type { DiscordGatewayAdapterImplementerMethods } from './util/adapter'; -import { Awaited, noop } from './util/util'; +import { noop } from './util/util'; /** * The various status codes a voice connection can hold at any one time. @@ -162,21 +161,10 @@ export type VoiceConnectionState = | VoiceConnectionReadyState | VoiceConnectionDestroyedState; -export type VoiceConnectionEvents = { - error: (error: Error) => Awaited; - debug: (message: string) => Awaited; - stateChange: (oldState: VoiceConnectionState, newState: VoiceConnectionState) => Awaited; -} & { - [status in VoiceConnectionStatus]: ( - oldState: VoiceConnectionState, - newState: VoiceConnectionState & { status: status }, - ) => Awaited; -}; - /** * A connection to the voice server of a Guild, can be used to play audio in voice channels. */ -export class VoiceConnection extends TypedEmitter { +export class VoiceConnection extends EventEmitter { /** * The number of consecutive rejoin attempts. Initially 0, and increments for each rejoin. * When a connection is successfully established, it resets to 0. @@ -673,7 +661,6 @@ export class VoiceConnection extends TypedEmitter { * * @param subscription - The removed subscription */ - // @ts-ignore private onSubscriptionRemoved(subscription: PlayerSubscription) { if (this.state.status !== VoiceConnectionStatus.Destroyed && this.state.subscription === subscription) { this.state = { diff --git a/packages/voice/src/audio/AudioPlayer.ts b/packages/voice/src/audio/AudioPlayer.ts index ddb834153..e5cd47f6b 100644 --- a/packages/voice/src/audio/AudioPlayer.ts +++ b/packages/voice/src/audio/AudioPlayer.ts @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/prefer-ts-expect-error */ -import { TypedEmitter } from 'tiny-typed-emitter'; +import EventEmitter from 'node:events'; import { AudioPlayerError } from './AudioPlayerError'; import type { AudioResource } from './AudioResource'; import { PlayerSubscription } from './PlayerSubscription'; import { addAudioPlayer, deleteAudioPlayer } from '../DataStore'; import { VoiceConnection, VoiceConnectionStatus } from '../VoiceConnection'; -import { Awaited, noop } from '../util/util'; +import { noop } from '../util/util'; // The Opus "silent" frame export const SILENCE_FRAME = Buffer.from([0xf8, 0xff, 0xfe]); @@ -151,18 +151,14 @@ export type AudioPlayerState = | AudioPlayerPlayingState | AudioPlayerPausedState; -export type AudioPlayerEvents = { - error: (error: AudioPlayerError) => Awaited; - debug: (message: string) => Awaited; - stateChange: (oldState: AudioPlayerState, newState: AudioPlayerState) => Awaited; - subscribe: (subscription: PlayerSubscription) => Awaited; - unsubscribe: (subscription: PlayerSubscription) => Awaited; -} & { - [status in AudioPlayerStatus]: ( - oldState: AudioPlayerState, - newState: AudioPlayerState & { status: status }, - ) => Awaited; -}; +export interface AudioPlayer extends EventEmitter { + /** + * Emitted when there is an error emitted from the audio resource played by the audio player + * + * @event + */ + on: (event: 'error', listener: (error: AudioPlayerError) => void) => this; +} /** * Stringifies an AudioPlayerState instance. @@ -187,7 +183,7 @@ function stringifyState(state: AudioPlayerState) { * The AudioPlayer drives the timing of playback, and therefore is unaffected by voice connections * becoming unavailable. Its behavior in these scenarios can be configured. */ -export class AudioPlayer extends TypedEmitter { +export class AudioPlayer extends EventEmitter { /** * The state that the AudioPlayer is in. */ @@ -372,12 +368,6 @@ export class AudioPlayer extends TypedEmitter { // state if the resource is still being used. const onStreamError = (error: Error) => { if (this.state.status !== AudioPlayerStatus.Idle) { - /** - * Emitted when there is an error emitted from the audio resource played by the audio player - * - * @event AudioPlayer#error - * @type {AudioPlayerError} - */ this.emit('error', new AudioPlayerError(error, this.state.resource)); } diff --git a/packages/voice/src/audio/index.ts b/packages/voice/src/audio/index.ts index a01f5418b..88999d6de 100644 --- a/packages/voice/src/audio/index.ts +++ b/packages/voice/src/audio/index.ts @@ -9,7 +9,6 @@ export { AudioPlayerPausedState, AudioPlayerPlayingState, CreateAudioPlayerOptions, - AudioPlayerEvents, } from './AudioPlayer'; export { AudioPlayerError } from './AudioPlayerError'; diff --git a/packages/voice/src/index.ts b/packages/voice/src/index.ts index dbc1492d4..b9c9fee71 100644 --- a/packages/voice/src/index.ts +++ b/packages/voice/src/index.ts @@ -16,7 +16,6 @@ export { VoiceConnectionDisconnectReason, VoiceConnectionReadyState, VoiceConnectionSignallingState, - VoiceConnectionEvents, } from './VoiceConnection'; export { JoinConfig, getVoiceConnection, getVoiceConnections, getGroups } from './DataStore'; diff --git a/packages/voice/src/networking/Networking.ts b/packages/voice/src/networking/Networking.ts index d8452dd6b..68969df1e 100644 --- a/packages/voice/src/networking/Networking.ts +++ b/packages/voice/src/networking/Networking.ts @@ -1,10 +1,11 @@ +/* eslint-disable @typescript-eslint/method-signature-style */ +import { EventEmitter } from 'node:events'; import { VoiceOpcodes } from 'discord-api-types/voice/v4'; -import { TypedEmitter } from 'tiny-typed-emitter'; import type { CloseEvent } from 'ws'; import { VoiceUDPSocket } from './VoiceUDPSocket'; import { VoiceWebSocket } from './VoiceWebSocket'; import * as secretbox from '../util/Secretbox'; -import { Awaited, noop } from '../util/util'; +import { noop } from '../util/util'; // The number of audio channels required by Discord const CHANNELS = 2; @@ -150,11 +151,16 @@ export interface ConnectionData { */ const nonce = Buffer.alloc(24); -export interface NetworkingEvents { - debug: (message: string) => Awaited; - error: (error: Error) => Awaited; - stateChange: (oldState: NetworkingState, newState: NetworkingState) => Awaited; - close: (code: number) => Awaited; +export interface Networking extends EventEmitter { + /** + * Debug event for Networking. + * + * @event + */ + on(event: 'debug', listener: (message: string) => void): this; + on(event: 'error', listener: (error: Error) => void): this; + on(event: 'stateChange', listener: (oldState: NetworkingState, newState: NetworkingState) => void): this; + on(event: 'close', listener: (code: number) => void): this; } /** @@ -195,7 +201,7 @@ function randomNBit(n: number) { /** * Manages the networking required to maintain a voice connection and dispatch audio packets */ -export class Networking extends TypedEmitter { +export class Networking extends EventEmitter { private _state: NetworkingState; /** @@ -274,12 +280,6 @@ export class Networking extends TypedEmitter { this._state = newState; this.emit('stateChange', oldState, newState); - /** - * Debug event for Networking. - * - * @event Networking#debug - * @type {string} - */ this.debug?.(`state change:\nfrom ${stringifyState(oldState)}\nto ${stringifyState(newState)}`); } diff --git a/packages/voice/src/networking/VoiceUDPSocket.ts b/packages/voice/src/networking/VoiceUDPSocket.ts index 0b60922cf..82d8589b0 100644 --- a/packages/voice/src/networking/VoiceUDPSocket.ts +++ b/packages/voice/src/networking/VoiceUDPSocket.ts @@ -1,7 +1,6 @@ import { createSocket, Socket } from 'node:dgram'; +import { EventEmitter } from 'node:events'; import { isIPv4 } from 'node:net'; -import { TypedEmitter } from 'tiny-typed-emitter'; -import type { Awaited } from '../util/util'; /** * Stores an IP address and port. Used to store socket details for the local client as well as @@ -17,13 +16,6 @@ interface KeepAlive { timestamp: number; } -export interface VoiceUDPSocketEvents { - error: (error: Error) => Awaited; - close: () => Awaited; - debug: (message: string) => Awaited; - message: (message: Buffer) => Awaited; -} - /** * Parses the response from Discord to aid with local IP discovery. * @@ -61,7 +53,7 @@ const MAX_COUNTER_VALUE = 2 ** 32 - 1; /** * Manages the UDP networking for a voice connection. */ -export class VoiceUDPSocket extends TypedEmitter { +export class VoiceUDPSocket extends EventEmitter { /** * The underlying network Socket for the VoiceUDPSocket. */ diff --git a/packages/voice/src/networking/VoiceWebSocket.ts b/packages/voice/src/networking/VoiceWebSocket.ts index 0c74b41d3..1e4445114 100644 --- a/packages/voice/src/networking/VoiceWebSocket.ts +++ b/packages/voice/src/networking/VoiceWebSocket.ts @@ -1,28 +1,31 @@ +/* eslint-disable @typescript-eslint/method-signature-style */ +import { EventEmitter } from 'node:events'; import { VoiceOpcodes } from 'discord-api-types/voice/v4'; -import { TypedEmitter } from 'tiny-typed-emitter'; import WebSocket, { MessageEvent } from 'ws'; -import type { Awaited } from '../util/util'; -/** - * Debug event for VoiceWebSocket. - * - * @event VoiceWebSocket#debug - * @type {string} - */ - -export interface VoiceWebSocketEvents { - error: (error: Error) => Awaited; - open: (event: WebSocket.Event) => Awaited; - close: (event: WebSocket.CloseEvent) => Awaited; - debug: (message: string) => Awaited; - packet: (packet: any) => Awaited; +export interface VoiceWebSocket extends EventEmitter { + on(event: 'error', listener: (error: Error) => void): this; + on(event: 'open', listener: (event: WebSocket.Event) => void): this; + on(event: 'close', listener: (event: WebSocket.CloseEvent) => void): this; + /** + * Debug event for VoiceWebSocket. + * + * @event + */ + on(event: 'debug', listener: (message: string) => void): this; + /** + * Packet event. + * + * @event + */ + on(event: 'packet', listener: (packet: any) => void): this; } /** * An extension of the WebSocket class to provide helper functionality when interacting * with the Discord Voice gateway. */ -export class VoiceWebSocket extends TypedEmitter { +export class VoiceWebSocket extends EventEmitter { /** * The current heartbeat interval, if any. */ @@ -122,12 +125,6 @@ export class VoiceWebSocket extends TypedEmitter { this.ping = this.lastHeartbeatAck - this.lastHeartbeatSend; } - /** - * Packet event. - * - * @event VoiceWebSocket#packet - * @type {any} - */ this.emit('packet', packet); } diff --git a/packages/voice/src/receive/SSRCMap.ts b/packages/voice/src/receive/SSRCMap.ts index 0e7f74fc6..0d0fde291 100644 --- a/packages/voice/src/receive/SSRCMap.ts +++ b/packages/voice/src/receive/SSRCMap.ts @@ -1,5 +1,4 @@ -import { TypedEmitter } from 'tiny-typed-emitter'; -import type { Awaited } from '../util/util'; +import { EventEmitter } from 'node:events'; /** * The known data for a user in a Discord voice connection. @@ -22,19 +21,10 @@ export interface VoiceUserData { userId: string; } -/** - * The events that an SSRCMap may emit. - */ -export interface SSRCMapEvents { - create: (newData: VoiceUserData) => Awaited; - update: (oldData: VoiceUserData | undefined, newData: VoiceUserData) => Awaited; - delete: (deletedData: VoiceUserData) => Awaited; -} - /** * Maps audio SSRCs to data of users in voice connections. */ -export class SSRCMap extends TypedEmitter { +export class SSRCMap extends EventEmitter { /** * The underlying map. */ diff --git a/packages/voice/src/receive/SpeakingMap.ts b/packages/voice/src/receive/SpeakingMap.ts index 985b6205f..faa2864ca 100644 --- a/packages/voice/src/receive/SpeakingMap.ts +++ b/packages/voice/src/receive/SpeakingMap.ts @@ -1,25 +1,9 @@ -import { TypedEmitter } from 'tiny-typed-emitter'; -import type { Awaited } from '../util/util'; - -/** - * The events that a SpeakingMap can emit. - */ -export interface SpeakingMapEvents { - /** - * Emitted when a user starts speaking. - */ - start: (userId: string) => Awaited; - - /** - * Emitted when a user stops speaking. - */ - end: (userId: string) => Awaited; -} +import { EventEmitter } from 'node:events'; /** * Tracks the speaking states of users in a voice channel. */ -export class SpeakingMap extends TypedEmitter { +export class SpeakingMap extends EventEmitter { /** * The delay after a packet is received from a user until they're marked as not speaking anymore. */ diff --git a/packages/voice/src/util/util.ts b/packages/voice/src/util/util.ts index b9d160ffd..4b1407a80 100644 --- a/packages/voice/src/util/util.ts +++ b/packages/voice/src/util/util.ts @@ -1,4 +1,2 @@ // eslint-disable-next-line @typescript-eslint/no-empty-function export const noop = () => {}; - -export type Awaited = T | Promise; diff --git a/yarn.lock b/yarn.lock index eefc697ba..798442ed7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2019,7 +2019,6 @@ __metadata: mock-socket: ^9.1.5 prettier: ^2.6.2 prism-media: ^1.3.2 - tiny-typed-emitter: ^2.1.0 tslib: ^2.4.0 tsup: ^6.1.0 tweetnacl: ^1.0.3 @@ -15927,13 +15926,6 @@ dts-critic@latest: languageName: node linkType: hard -"tiny-typed-emitter@npm:^2.1.0": - version: 2.1.0 - resolution: "tiny-typed-emitter@npm:2.1.0" - checksum: 709bca410054e08df4dc29d5ea0916328bb2900d60245c6a743068ea223887d9fd2c945b6070eb20336275a557a36c2808e5c87d2ed4b60633458632be4a3e10 - languageName: node - linkType: hard - "tinypool@npm:^0.1.3": version: 0.1.3 resolution: "tinypool@npm:0.1.3"