fbp-language 1.1.3 → 1.1.4

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/README.md CHANGED
@@ -23,7 +23,7 @@ Puis, dans le `package.json` de ton projet :
23
23
  "start": "fbp run lancer"
24
24
  },
25
25
  "dependencies": {
26
- "fbp-language": "^1.1.3"
26
+ "fbp-language": "^1.1.4"
27
27
  }
28
28
  }
29
29
  ```
@@ -127,3 +127,25 @@ npm test
127
127
  ```
128
128
 
129
129
  Les fichiers d'essai internes se trouvent dans `tests/fixtures`. Ils ne font pas partie du paquet publié.
130
+
131
+
132
+ ## Informations Discord dynamiques (v1.1.4)
133
+
134
+ Les champs d'un embed peuvent récupérer les informations accessibles au moment où la commande est utilisée. Exemple :
135
+
136
+ ```fbp
137
+ discordConnexion()
138
+ discordCommandeEmbed("serveur-info", "Informations du serveur", "Données actuelles", "#5865F2")
139
+ discordChampDynamique("serveur-info", "Nom", "discordServeur.nom")
140
+ discordChampDynamique("serveur-info", "Identifiant", "discordServeur.id")
141
+ discordChampDynamique("serveur-info", "Création", "discordServeur.creation")
142
+ discordChampDynamique("serveur-info", "Membres", "discordMembres.nombre")
143
+ discordChampDynamique("serveur-info", "Rôles", "discordRoles.nombre")
144
+ discordChampDynamique("serveur-info", "Salons", "discordSalons.nombre")
145
+ discordChampDynamique("serveur-info", "Latence", "discordLatence")
146
+ discordOptionUtilisateur("serveur-info", "membre", "Membre à afficher")
147
+ discordChampDynamique("serveur-info", "Profil", "discordProfil.nom")
148
+ discordChampDynamique("serveur-info", "Avatar", "discordAvatar")
149
+ ```
150
+
151
+ Sources disponibles : `discordServeur.nom`, `discordServeur.id`, `discordServeur.creation`, `discordMembres.nombre`, `discordProfil.nom`, `discordProfil.id`, `discordProfil.avatar`, `discordRoles.nombre`, `discordSalons.nombre`, `discordStatistiques.membres`, `discordStatistiques.roles`, `discordStatistiques.salons`, `discordLatence` et `discordAvatar`. `discordOptionUtilisateur(nomCommande, nomOption, description)` ajoute un sélecteur facultatif de membre à une commande embed. Les données accessibles dépendent des permissions et du cache Discord du bot.
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ const node_fs_1 = __importDefault(require("node:fs"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
9
  const compiler_1 = require("./compiler");
10
10
  const errors_1 = require("./errors");
11
- const VERSION = "1.1.3";
11
+ const VERSION = "1.1.4";
12
12
  function help() {
13
13
  console.log(`FBP — French Bot Programming
14
14
 
package/dist/compiler.js CHANGED
@@ -112,6 +112,26 @@ class FbpCompiler {
112
112
  constructor(options = {}) {
113
113
  this.output = options.onOutput ?? (value => console.log(value));
114
114
  }
115
+ resolveDiscordValue(source, interaction, selectedUser, selectedMember) {
116
+ const guild = interaction.guild;
117
+ const values = {
118
+ "discordServeur.nom": guild?.name ?? "Serveur indisponible",
119
+ "discordServeur.id": guild?.id ?? "Indisponible",
120
+ "discordServeur.creation": guild ? "<t:" + Math.floor(guild.createdTimestamp / 1000) + ":D>" : "Indisponible",
121
+ "discordMembres.nombre": guild ? String(guild.memberCount) : "Indisponible",
122
+ "discordProfil.nom": selectedMember?.displayName ?? selectedUser?.username ?? "Sélectionne un membre",
123
+ "discordProfil.id": selectedUser?.id ?? "Sélectionne un membre",
124
+ "discordProfil.avatar": selectedUser?.displayAvatarURL({ size: 256 }) ?? "Sélectionne un membre",
125
+ "discordRoles.nombre": guild ? String(guild.roles.cache.size) : "Indisponible",
126
+ "discordSalons.nombre": guild ? String(guild.channels.cache.size) : "Indisponible",
127
+ "discordStatistiques.membres": guild ? String(guild.memberCount) : "Indisponible",
128
+ "discordStatistiques.roles": guild ? String(guild.roles.cache.size) : "Indisponible",
129
+ "discordStatistiques.salons": guild ? String(guild.channels.cache.size) : "Indisponible",
130
+ "discordLatence": String(Math.max(0, Math.round(interaction.client.ws.ping))) + " ms",
131
+ "discordAvatar": selectedUser?.displayAvatarURL({ size: 256 }) ?? interaction.user.displayAvatarURL({ size: 256 })
132
+ };
133
+ return source.trim() in values ? values[source.trim()] : "Source inconnue : " + source.trim();
134
+ }
115
135
  runFile(filePath) {
116
136
  const absolute = node_path_1.default.resolve(filePath);
117
137
  if (!node_fs_1.default.existsSync(absolute))
@@ -188,10 +208,17 @@ class FbpCompiler {
188
208
  this.discordClient = client;
189
209
  client.once("ready", async () => {
190
210
  try {
191
- const commands = [...this.discordCommands.entries()].map(([commandName]) => new discord_js_1.SlashCommandBuilder()
192
- .setName(commandName)
193
- .setDescription(`Commande ${commandName} du bot FBP`)
194
- .toJSON());
211
+ const commands = [...this.discordCommands.entries()].map(([commandName, response]) => {
212
+ const builder = new discord_js_1.SlashCommandBuilder()
213
+ .setName(commandName)
214
+ .setDescription(`Commande ${commandName} du bot FBP`);
215
+ if (response.type === "embed" && response.userOption) {
216
+ builder.addUserOption(option => option.setName(response.userOption.name)
217
+ .setDescription(response.userOption.description)
218
+ .setRequired(false));
219
+ }
220
+ return builder.toJSON();
221
+ });
195
222
  const manager = client.application?.commands;
196
223
  if (!manager)
197
224
  throw new Error("L'application Discord n'est pas disponible.");
@@ -225,8 +252,16 @@ class FbpCompiler {
225
252
  .setTitle(response.title)
226
253
  .setDescription(response.description)
227
254
  .setColor(Number.parseInt(response.color.slice(1), 16));
228
- if (response.fields.length)
229
- embed.addFields(response.fields.map(field => ({ name: field.name, value: field.value, inline: false })));
255
+ const guild = interaction.guild;
256
+ const selectedUser = response.userOption ? interaction.options.getUser(response.userOption.name) : null;
257
+ const selectedMember = selectedUser && guild ? await guild.members.fetch(selectedUser.id).catch(() => null) : null;
258
+ const fields = response.fields.map(field => ({
259
+ name: field.name,
260
+ value: field.dynamic ? this.resolveDiscordValue(field.value, interaction, selectedUser, selectedMember) : field.value,
261
+ inline: false
262
+ }));
263
+ if (fields.length)
264
+ embed.addFields(fields);
230
265
  await interaction.reply({ embeds: [embed] });
231
266
  }
232
267
  }
@@ -264,6 +299,36 @@ class FbpCompiler {
264
299
  this.discordCommands.set(commandName, { type: "embed", title, description, color, fields: [] });
265
300
  return;
266
301
  }
302
+ if (name === "discordChampDynamique") {
303
+ if (values.length !== 3 || values.some(value => typeof value !== "string")) {
304
+ throw new errors_1.FbpError("Utilisation : discordChampDynamique(nomCommande, nomChamp, source).", undefined, line);
305
+ }
306
+ const [commandName, fieldName, source] = values;
307
+ const command = this.discordCommands.get(commandName);
308
+ if (!command || command.type !== "embed")
309
+ throw new errors_1.FbpError("La commande « " + commandName + " » n'est pas un embed déclaré.", undefined, line);
310
+ if (command.fields.length >= 25)
311
+ throw new errors_1.FbpError("Un embed Discord ne peut pas contenir plus de 25 champs.", undefined, line);
312
+ if (!fieldName.trim() || !source.trim() || fieldName.length > 256 || source.length > 1024)
313
+ throw new errors_1.FbpError("Un champ dynamique doit avoir un nom et une source valides.", undefined, line);
314
+ command.fields.push({ name: fieldName, value: source, dynamic: true });
315
+ return;
316
+ }
317
+ if (name === "discordOptionUtilisateur") {
318
+ if (values.length !== 3 || values.some(value => typeof value !== "string")) {
319
+ throw new errors_1.FbpError("Utilisation : discordOptionUtilisateur(nomCommande, nomOption, description).", undefined, line);
320
+ }
321
+ const [commandName, optionName, description] = values;
322
+ const command = this.discordCommands.get(commandName);
323
+ if (!command || command.type !== "embed")
324
+ throw new errors_1.FbpError("La commande « " + commandName + " » n'est pas un embed déclaré.", undefined, line);
325
+ if (!/^[a-z0-9_-]{1,32}$/.test(optionName))
326
+ throw new errors_1.FbpError("Le nom de l'option doit contenir 1 à 32 caractères minuscules, chiffres, tirets ou underscores.", undefined, line);
327
+ if (!description.trim() || description.length > 100)
328
+ throw new errors_1.FbpError("La description de l'option doit contenir 1 à 100 caractères.", undefined, line);
329
+ command.userOption = { name: optionName, description };
330
+ return;
331
+ }
267
332
  if (name === "discordChamp") {
268
333
  if (values.length !== 3 || values.some(value => typeof value !== "string")) {
269
334
  throw new errors_1.FbpError("Utilisation : discordChamp(nomCommande, nomChamp, valeur).", undefined, line);
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "fbp-language",
3
3
  "displayName": "FBP - French Bot Programming",
4
4
  "description": "Langage FBP avec prise en charge des commandes slash et des embeds Discord.",
5
- "version": "1.1.3",
5
+ "version": "1.1.4",
6
6
  "type": "commonjs",
7
7
  "main": "dist/compiler.js",
8
8
  "bin": {