meocord 4.1.0 → 4.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "meocordVersion": "4.1.0",
3
+ "meocordVersion": "4.1.2",
4
4
  "name": "meocord",
5
5
  "description": "CLI for managing the MeoCord application",
6
6
  "usage": "[options] [command]",
@@ -8,10 +8,16 @@ const warned = new Set();
8
8
  */ function warnDeprecatedBehaviour(logger, old, outcome, replacement) {
9
9
  warnOnce(logger, `${old} is deprecated; in the next major version (5.0) it ${outcome}. Use ${replacement} instead.`);
10
10
  }
11
+ /**
12
+ * Warns once per run that a mock reads `value` as a placeholder where discord.js computes it, saying what 5.0 gives
13
+ * and how to set it.
14
+ */ function warnPlaceholder(logger, value, outcome, how) {
15
+ warnOnce(logger, `${value} reads a placeholder here; in the next major version (5.0) ${outcome}. ${how}`);
16
+ }
11
17
  function warnOnce(logger, text) {
12
18
  if (warned.has(text)) return;
13
19
  warned.add(text);
14
20
  logger.warn(text);
15
21
  }
16
22
 
17
- export { warnDeprecated, warnDeprecatedBehaviour };
23
+ export { warnDeprecated, warnDeprecatedBehaviour, warnPlaceholder };
@@ -1,4 +1,4 @@
1
- var version = "4.1.0";
1
+ var version = "4.1.2";
2
2
  var engines = {
3
3
  node: ">=22.13"
4
4
  };
@@ -1,6 +1,7 @@
1
- import { GuildPremiumTier, GuildVerificationLevel, GuildNSFWLevel, Locale, Guild, ClientUser, User, GuildMember, PermissionsBitField, Role, MessageType, Message, CommandInteraction, AutocompleteInteraction, BaseInteraction, ChannelType, TextChannel, NewsChannel, VoiceChannel, ForumChannel, MediaChannel, ThreadChannel, DMChannel, GuildChannel, BaseChannel, Client, SnowflakeUtil } from 'discord.js';
2
- import { memberRoles, createMockUser } from './mock-interaction.js';
1
+ import { GuildPremiumTier, GuildVerificationLevel, GuildNSFWLevel, Locale, Guild, ClientUser, User, GuildMember, Role, Collection, MessageType, Message, CommandInteraction, AutocompleteInteraction, GuildChannel, BaseInteraction, ChannelType, TextChannel, NewsChannel, VoiceChannel, ForumChannel, MediaChannel, ThreadChannel, DMChannel, BaseChannel, Client, BaseGuild, SnowflakeUtil, PermissionsBitField } from 'discord.js';
2
+ import { memberRoles, createMockUser, createMockGuild } from './mock-interaction.js';
3
3
 
4
+ /** A permission set with none, frozen as discord.js freezes the ones it gives. */ const noPermissions = ()=>new PermissionsBitField().freeze();
4
5
  /** A property discord.js computes from the others: its own getter runs, reading the mock's values. */ const REAL_GETTER = Symbol('real getter');
5
6
  const snowflake = ()=>SnowflakeUtil.generate().toString();
6
7
  /** A class and its defaults, typed together so a default that stops fitting its property fails to compile. */ const defaultsOf = (Class, defaults)=>[
@@ -44,6 +45,7 @@ const snowflake = ()=>SnowflakeUtil.generate().toString();
44
45
  system: ()=>false,
45
46
  tag: REAL_GETTER,
46
47
  displayName: REAL_GETTER,
48
+ defaultAvatarURL: REAL_GETTER,
47
49
  createdTimestamp: REAL_GETTER,
48
50
  createdAt: REAL_GETTER
49
51
  }),
@@ -52,7 +54,12 @@ const snowflake = ()=>SnowflakeUtil.generate().toString();
52
54
  id: REAL_GETTER,
53
55
  nickname: ()=>null,
54
56
  avatar: ()=>null,
55
- joinedTimestamp: ()=>null,
57
+ // In the server since the mock was made, as a member Discord sends always is
58
+ joinedTimestamp: ()=>Date.now(),
59
+ joinedAt: REAL_GETTER,
60
+ partial: REAL_GETTER,
61
+ premiumSince: REAL_GETTER,
62
+ communicationDisabledUntil: REAL_GETTER,
56
63
  premiumSinceTimestamp: ()=>null,
57
64
  communicationDisabledUntilTimestamp: ()=>null,
58
65
  pending: ()=>false,
@@ -65,7 +72,24 @@ const snowflake = ()=>SnowflakeUtil.generate().toString();
65
72
  name: ()=>'role',
66
73
  // Above @everyone, which a server's role manager makes at position 0
67
74
  position: ()=>1,
68
- permissions: ()=>new PermissionsBitField().freeze()
75
+ // Every role has a server; one made without is in one of its own, unless a guild given it takes it in
76
+ guild: ()=>createMockGuild(),
77
+ rawPosition: (role)=>role.position,
78
+ permissions: noPermissions,
79
+ hoist: ()=>false,
80
+ managed: ()=>false,
81
+ mentionable: ()=>false,
82
+ icon: ()=>null,
83
+ unicodeEmoji: ()=>null,
84
+ tags: ()=>null,
85
+ colors: ()=>({
86
+ primaryColor: 0,
87
+ secondaryColor: null,
88
+ tertiaryColor: null
89
+ }),
90
+ hexColor: REAL_GETTER,
91
+ createdTimestamp: REAL_GETTER,
92
+ createdAt: REAL_GETTER
69
93
  }),
70
94
  // A message's text says which handler it is for, so it stays the test's to give, as a command's name does
71
95
  defaultsOf(Message, {
@@ -78,6 +102,10 @@ const snowflake = ()=>SnowflakeUtil.generate().toString();
78
102
  nonce: ()=>null,
79
103
  position: ()=>null,
80
104
  activity: ()=>null,
105
+ reference: ()=>null,
106
+ poll: ()=>null,
107
+ interactionMetadata: ()=>null,
108
+ stickers: ()=>new Collection(),
81
109
  url: REAL_GETTER
82
110
  }),
83
111
  // A command's name and a component's customId say which handler a call is for, so they stay the test's to give
@@ -95,7 +123,13 @@ const snowflake = ()=>SnowflakeUtil.generate().toString();
95
123
  version: ()=>1,
96
124
  context: ()=>null,
97
125
  // What Discord sends with an interaction in a server, the member's permissions there; typed for a cached one
98
- memberPermissions: (interaction)=>interaction.guildId && interaction.member instanceof GuildMember ? interaction.member.permissions : null
126
+ memberPermissions: (interaction)=>interaction.guildId && interaction.member instanceof GuildMember ? interaction.member.permissions : null,
127
+ // The bot's permissions where the interaction was made: its member's in the channel, or none outside a server
128
+ appPermissions: (interaction)=>{
129
+ const { guild, channel } = interaction;
130
+ const me = guild instanceof Guild ? guild.members.me : null;
131
+ return (me && channel instanceof GuildChannel ? channel.permissionsFor(me) : null) ?? noPermissions();
132
+ }
99
133
  }),
100
134
  defaultsOf(TextChannel, {
101
135
  type: ()=>ChannelType.GuildText,
@@ -142,8 +176,12 @@ const snowflake = ()=>SnowflakeUtil.generate().toString();
142
176
  }),
143
177
  defaultsOf(Client, {
144
178
  readyTimestamp: ()=>Date.now(),
179
+ readyAt: REAL_GETTER,
145
180
  uptime: REAL_GETTER,
146
181
  token: ()=>null
182
+ }),
183
+ defaultsOf(BaseGuild, {
184
+ nameAcronym: REAL_GETTER
147
185
  })
148
186
  ]);
149
187
  /** The default a mock of `target`'s class has for `key`, read from the nearest class that has one. */ function discordDefault(target, key) {
@@ -1,12 +1,8 @@
1
1
  // Framework-agnostic mock function, so `meocord/testing` depends on neither jest nor vitest.
2
2
  // Both detect it through `_isMockFunction` and read `fn.mock.calls` in their assertions.
3
+ // Each call signature of `T`, up to four, as a union: `Parameters` and `ReturnType` read only an overloaded function's
4
+ // last signature, such as the list form of a manager's `fetch`
3
5
  /**
4
- * One call's outcome, as a mock function records it: the value it returned, or the error it threw.
5
- *
6
- * @group Testing
7
- * @category Mocks
8
- * @see {@link MockState}
9
- */ /**
10
6
  * Tells whether a value is a mock function: one from `meocord/testing`, `jest.fn()` or `vi.fn()`.
11
7
  *
12
8
  * Use it in a helper that takes mocks and real functions alike, such as one that sets a default on every mock method.