Skip to content

Commit

Permalink
Merge branch 'main' into turbo/cache-coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] authored Nov 19, 2022
2 parents f8cda16 + 8ed5c1b commit 014e6d8
Show file tree
Hide file tree
Showing 16 changed files with 124 additions and 12 deletions.
19 changes: 19 additions & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,25 @@ To get ready to work on the codebase, please do the following:
5. Run `yarn test` to run ESLint and ensure any JSDoc changes are valid
6. [Submit a pull request](https://github.com/discordjs/discord.js/compare) (Make sure you follow the [conventional commit format](https://github.com/discordjs/discord.js/blob/main/.github/COMMIT_CONVENTION.md))

## Testing changes locally

If you want to test changes you've made locally, you can do so by using `yarn link`. This will create a symlink to your local copy of the discord.js libraries.

1. Create a new directory `mkdir discordjs-test` and move into it `cd discordjs-test`
2. Initialize a new yarn 3 project `yarn init -2`
3. Disable pnp `yarn config set nodeLinker node-modules`
4. Now link the local discord.js project you cloned earlier `yarn link -A {PATH_TO_DISCORDJS_REPO}`
5. Install packages you'd like to test locally `yarn add discord.js@latest`, `yarn add @discordjs/rest@latest`, etc. **Note: Make sure you use `latest` tag or else yarn will try to install the remote package from npm**
6. Import the package in your source code and test them out!

### Working with TypeScript packages

When testing local changes, you may notice you need to manually recompile TypeScript projects on every change in order to get the latest code changes to test locally.

To avoid this you can use the `--watch` parameter in the package build script to automatically recompile the project when changes are detected.

For example, to automatically recompile the `@discordjs/rest` project when changes are detected, run `yarn turbo run build --filter=@discordjs/rest -- --watch` in the root folder of where you cloned the discord.js repo.

## Adding new packages

If you'd like to create another package under the `@discordjs` organization run the following command:
Expand Down
21 changes: 17 additions & 4 deletions packages/collection/__tests__/collection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
import { describe, test, expect } from 'vitest';
import { Collection } from '../src/index.js';

type TestCollection = Collection<string, number>;
type TestCollection<V> = Collection<string, V>;

function createCollection(): TestCollection {
function createCollection<V = number>(): TestCollection<V> {
return new Collection();
}

function createCollectionFrom(...entries: [key: string, value: number][]): TestCollection {
function createCollectionFrom<V = number>(...entries: [key: string, value: V][]): TestCollection<V> {
return new Collection(entries);
}

function createTestCollection(): TestCollection {
function createTestCollection(): TestCollection<number> {
return createCollectionFrom(['a', 1], ['b', 2], ['c', 3]);
}

Expand Down Expand Up @@ -770,6 +770,19 @@ describe('sort() tests', () => {
});
});

describe('subtract() tests', () => {
const coll1 = createCollectionFrom(['a', 1], ['b', 2], ['c', 3], ['d', undefined]);
const coll2 = createCollectionFrom(['b', 2], ['c', 0]);

test('it returns a new collection', () => {
const c = coll1.subtract(coll2);
expect(c).toBeInstanceOf(Collection);
expect(c.size).toStrictEqual(3);

expect(c).toStrictEqual(createCollectionFrom(['a', 1], ['c', 3], ['d', undefined]));
});
});

describe('sweep() test', () => {
const coll = createTestCollection();

Expand Down
16 changes: 16 additions & 0 deletions packages/collection/src/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,22 @@ export class Collection<K, V> extends Map<K, V> {
return coll;
}

/**
* The subtract method returns a new structure containing items where the keys and values of the original structure are not present in the other.
*
* @param other - The other Collection to filter against
*/
public subtract<T>(other: ReadonlyCollection<K, T>): Collection<K, V> {
const coll = new this.constructor[Symbol.species]<K, V>();
for (const [k, v] of this) {
if (!other.has(k) || !Object.is(v, other.get(k))) {
coll.set(k, v);
}
}

return coll;
}

/**
* The difference method returns a new structure containing items where the key is present in one of the original structures but not the other.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ class ChannelSelectMenuInteraction extends MessageComponentInteraction {
constructor(client, data) {
super(client, data);

/**
* An array of the selected channel ids
* @type {Snowflake[]}
*/
this.values = data.data.values ?? [];

/**
* Collection of the selected channels
* @type {Collection<Snowflake, Channel|APIChannel>}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ class MentionableSelectMenuInteraction extends MessageComponentInteraction {
constructor(client, data) {
super(client, data);

/**
* An array of the selected user and role ids
* @type {Snowflake[]}
*/
this.values = data.data.values ?? [];

const { members, users, roles } = data.data.resolved ?? {};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ class RoleSelectMenuInteraction extends MessageComponentInteraction {
constructor(client, data) {
super(client, data);

/**
* An array of the selected role ids
* @type {Snowflake[]}
*/
this.values = data.data.values ?? [];

/**
* Collection of the selected roles
* @type {Collection<Snowflake, Role|APIRole>}
Expand Down
1 change: 1 addition & 0 deletions packages/discord.js/src/structures/SelectMenuBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ let deprecationEmitted = false;

/**
* @deprecated Use {@link StringSelectMenuBuilder} instead.
* @extends {StringSelectMenuBuilder}
*/
class SelectMenuBuilder extends StringSelectMenuBuilder {
constructor(...params) {
Expand Down
1 change: 1 addition & 0 deletions packages/discord.js/src/structures/SelectMenuComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ let deprecationEmitted = false;

/**
* @deprecated Use {@link StringSelectMenuComponent} instead.
* @extends {StringSelectMenuComponent}
*/
class SelectMenuComponent extends StringSelectMenuComponent {
constructor(...params) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ let deprecationEmitted = false;

/**
* @deprecated Use {@link StringSelectMenuInteraction} instead.
* @extends {StringSelectMenuInteraction}
*/
class SelectMenuInteraction extends StringSelectMenuInteraction {
constructor(...params) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ let deprecationEmitted = false;

/**
* @deprecated Use {@link StringSelectMenuOptionBuilder} instead.
* @extends {StringSelectMenuOptionBuilder}
*/
class SelectMenuOptionBuilder extends StringSelectMenuOptionBuilder {
constructor(...params) {
Expand Down
20 changes: 19 additions & 1 deletion packages/discord.js/src/structures/ThreadChannel.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

const { ChannelType, PermissionFlagsBits, Routes } = require('discord-api-types/v10');
const { ChannelType, PermissionFlagsBits, Routes, ChannelFlags } = require('discord-api-types/v10');
const { BaseChannel } = require('./BaseChannel');
const TextBasedChannel = require('./interfaces/TextBasedChannel');
const { DiscordjsRangeError, ErrorCodes } = require('../errors');
Expand Down Expand Up @@ -457,6 +457,24 @@ class ThreadChannel extends BaseChannel {
return this.edit({ appliedTags, reason });
}

/**
* Pins this thread from the forum channel (only applicable to forum threads).
* @param {string} [reason] Reason for pinning
* @returns {Promise<ThreadChannel>}
*/
pin(reason) {
return this.edit({ flags: this.flags.add(ChannelFlags.Pinned), reason });
}

/**
* Unpins this thread from the forum channel (only applicable to forum threads).
* @param {string} [reason] Reason for unpinning
* @returns {Promise<ThreadChannel>}
*/
unpin(reason) {
return this.edit({ flags: this.flags.remove(ChannelFlags.Pinned), reason });
}

/**
* Whether the client user is a member of the thread.
* @type {boolean}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ class UserSelectMenuInteraction extends MessageComponentInteraction {
constructor(client, data) {
super(client, data);

/**
* An array of the selected user ids
* @type {Snowflake[]}
*/
this.values = data.data.values ?? [];

/**
* Collection of the selected users
* @type {Collection<Snowflake, User>}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class TextBasedChannel {
* (see [here](https://discord.com/developers/docs/resources/channel#allowed-mentions-object) for more details)
* @property {Array<JSONEncodable<AttachmentPayload>>|BufferResolvable[]|Attachment[]|AttachmentBuilder[]} [files]
* The files to send with the message.
* @property {ActionRow[]|ActionRowOptions[]} [components]
* @property {ActionRow[]|ActionRowBuilder[]} [components]
* Action rows containing interactive components for the message (buttons, select menus)
*/

Expand Down
2 changes: 2 additions & 0 deletions packages/discord.js/src/util/Transformers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict';

const { isJSONEncodable } = require('@discordjs/util');
const snakeCase = require('lodash.snakecase');

/**
Expand All @@ -10,6 +11,7 @@ const snakeCase = require('lodash.snakecase');
function toSnakeCase(obj) {
if (typeof obj !== 'object' || !obj) return obj;
if (obj instanceof Date) return obj;
if (isJSONEncodable(obj)) return toSnakeCase(obj.toJSON());
if (Array.isArray(obj)) return obj.map(toSnakeCase);
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [snakeCase(key), toSnakeCase(value)]));
}
Expand Down
2 changes: 1 addition & 1 deletion packages/discord.js/src/util/Util.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,14 @@ function escapeMarkdown(
})
.join(inlineCode ? '\\`' : '`');
}
if (escape) text = escapeEscape(text);
if (inlineCode) text = escapeInlineCode(text);
if (codeBlock) text = escapeCodeBlock(text);
if (italic) text = escapeItalic(text);
if (bold) text = escapeBold(text);
if (underline) text = escapeUnderline(text);
if (strikethrough) text = escapeStrikethrough(text);
if (spoiler) text = escapeSpoiler(text);
if (escape) text = escapeEscape(text);
if (heading) text = escapeHeading(text);
if (bulletedList) text = escapeBulletedList(text);
if (numberedList) text = escapeNumberedList(text);
Expand Down
26 changes: 21 additions & 5 deletions packages/discord.js/typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2371,8 +2371,12 @@ export class UserSelectMenuInteraction<
UserSelectMenuComponent | APIUserSelectComponent
>;
public componentType: ComponentType.UserSelect;
public values: Snowflake[];
public users: Collection<Snowflake, User>;
public members: Collection<Snowflake, CacheTypeReducer<Cached, GuildMember, APIGuildMember>>;
public members: Collection<
Snowflake,
CacheTypeReducer<Cached, GuildMember, APIGuildMember, GuildMember | APIGuildMember, GuildMember | APIGuildMember>
>;
public inGuild(): this is UserSelectMenuInteraction<'raw' | 'cached'>;
public inCachedGuild(): this is UserSelectMenuInteraction<'cached'>;
public inRawGuild(): this is UserSelectMenuInteraction<'raw'>;
Expand All @@ -2390,7 +2394,8 @@ export class RoleSelectMenuInteraction<
RoleSelectMenuComponent | APIRoleSelectComponent
>;
public componentType: ComponentType.RoleSelect;
public roles: Collection<Snowflake, CacheTypeReducer<Cached, Role, APIRole>>;
public values: Snowflake[];
public roles: Collection<Snowflake, CacheTypeReducer<Cached, Role, APIRole, Role | APIRole, Role | APIRole>>;
public inGuild(): this is RoleSelectMenuInteraction<'raw' | 'cached'>;
public inCachedGuild(): this is RoleSelectMenuInteraction<'cached'>;
public inRawGuild(): this is RoleSelectMenuInteraction<'raw'>;
Expand All @@ -2408,9 +2413,13 @@ export class MentionableSelectMenuInteraction<
MentionableSelectMenuComponent | APIMentionableSelectComponent
>;
public componentType: ComponentType.MentionableSelect;
public values: Snowflake[];
public users: Collection<Snowflake, User>;
public members: Collection<Snowflake, CacheTypeReducer<Cached, GuildMember, APIGuildMember>>;
public roles: Collection<Snowflake, CacheTypeReducer<Cached, Role, APIRole>>;
public members: Collection<
Snowflake,
CacheTypeReducer<Cached, GuildMember, APIGuildMember, GuildMember | APIGuildMember, GuildMember | APIGuildMember>
>;
public roles: Collection<Snowflake, CacheTypeReducer<Cached, Role, APIRole, Role | APIRole, Role | APIRole>>;
public inGuild(): this is MentionableSelectMenuInteraction<'raw' | 'cached'>;
public inCachedGuild(): this is MentionableSelectMenuInteraction<'cached'>;
public inRawGuild(): this is MentionableSelectMenuInteraction<'raw'>;
Expand All @@ -2428,7 +2437,11 @@ export class ChannelSelectMenuInteraction<
ChannelSelectMenuComponent | APIChannelSelectComponent
>;
public componentType: ComponentType.ChannelSelect;
public channels: Collection<Snowflake, CacheTypeReducer<Cached, Channel, APIChannel>>;
public values: Snowflake[];
public channels: Collection<
Snowflake,
CacheTypeReducer<Cached, Channel, APIChannel, Channel | APIChannel, Channel | APIChannel>
>;
public inGuild(): this is ChannelSelectMenuInteraction<'raw' | 'cached'>;
public inCachedGuild(): this is ChannelSelectMenuInteraction<'cached'>;
public inRawGuild(): this is ChannelSelectMenuInteraction<'raw'>;
Expand Down Expand Up @@ -2816,7 +2829,10 @@ export class ThreadChannel<Forum extends boolean = boolean> extends TextBasedCha
public setInvitable(invitable?: boolean, reason?: string): Promise<AnyThreadChannel>;
public setLocked(locked?: boolean, reason?: string): Promise<AnyThreadChannel>;
public setName(name: string, reason?: string): Promise<AnyThreadChannel>;
// The following 3 methods can only be run on forum threads.
public setAppliedTags(appliedTags: Snowflake[], reason?: string): Promise<ThreadChannel<true>>;
public pin(reason?: string): Promise<ThreadChannel<true>>;
public unpin(reason?: string): Promise<ThreadChannel<true>>;
public toString(): ChannelMention;
}

Expand Down

0 comments on commit 014e6d8

Please sign in to comment.