fbp-language 1.1.4 → 1.1.7
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 +74 -2
- package/dist/cli.js +1 -1
- package/dist/compiler.js +156 -5
- package/package.json +2 -2
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.
|
|
26
|
+
"fbp-language": "^1.1.6"
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
```
|
|
@@ -129,7 +129,7 @@ npm test
|
|
|
129
129
|
Les fichiers d'essai internes se trouvent dans `tests/fixtures`. Ils ne font pas partie du paquet publié.
|
|
130
130
|
|
|
131
131
|
|
|
132
|
-
## Informations Discord dynamiques (v1.1.
|
|
132
|
+
## Informations Discord dynamiques (v1.1.6)
|
|
133
133
|
|
|
134
134
|
Les champs d'un embed peuvent récupérer les informations accessibles au moment où la commande est utilisée. Exemple :
|
|
135
135
|
|
|
@@ -149,3 +149,75 @@ discordChampDynamique("serveur-info", "Avatar", "discordAvatar")
|
|
|
149
149
|
```
|
|
150
150
|
|
|
151
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.
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
## Options des commandes slash (v1.1.6)
|
|
155
|
+
|
|
156
|
+
Les commandes slash peuvent maintenant recevoir des options texte, nombre, entier ou booléen. Le dernier argument indique si l'option est obligatoire ; il est facultatif et vaut `false` par défaut.
|
|
157
|
+
|
|
158
|
+
```fbp
|
|
159
|
+
discordConnexion()
|
|
160
|
+
discordCommande("bonjour", "Salut {{prenom}} !")
|
|
161
|
+
discordOptionTexte("bonjour", "prenom", "Ton prénom", true)
|
|
162
|
+
discordOptionEntier("bonjour", "age", "Ton âge")
|
|
163
|
+
discordOptionNombre("bonjour", "note", "Une valeur décimale")
|
|
164
|
+
discordOptionBooleen("bonjour", "confirme", "Confirmer ?")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Dans une réponse texte, `{{prenom}}` est remplacé par la valeur saisie. Pour les embeds, les champs dynamiques peuvent lire une option avec `discordChampDynamique("commande", "Champ", "option.prenom")` (ou `discordOption.prenom`). Les options absentes ne sont pas remplacées et une option obligatoire inaccessible produit une réponse d'erreur.
|
|
168
|
+
|
|
169
|
+
Fonctions disponibles :
|
|
170
|
+
|
|
171
|
+
- `discordOptionTexte(commande, nom, description, obligatoire)`
|
|
172
|
+
- `discordOptionNombre(commande, nom, description, obligatoire)`
|
|
173
|
+
- `discordOptionEntier(commande, nom, description, obligatoire)`
|
|
174
|
+
- `discordOptionBooleen(commande, nom, description, obligatoire)`
|
|
175
|
+
- `discordOptionUtilisateur(commande, nom, description)` pour le sélecteur de membre existant des commandes embed.
|
|
176
|
+
|
|
177
|
+
Les noms d'options doivent respecter les règles Discord (minuscules, chiffres, tirets et underscores, 1 à 32 caractères). Une commande peut avoir jusqu'à 25 options. Les types d'options sont déclarés lors de l'enregistrement des commandes ; redémarre le bot après avoir modifié leur définition. Le bot a besoin du scope `applications.commands` et de l'accès au serveur concerné. Aucun intent privilégié supplémentaire n'est requis pour ces options.
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
## Choix prédéfinis des options (v1.1.6)
|
|
181
|
+
|
|
182
|
+
Pour limiter les réponses possibles d'une option, ajoute des choix après avoir déclaré l'option :
|
|
183
|
+
|
|
184
|
+
```fbp
|
|
185
|
+
discordConnexion()
|
|
186
|
+
discordCommande("couleur", "Couleur choisie : {{couleur}}")
|
|
187
|
+
discordOptionTexte("couleur", "couleur", "Choisis une couleur", true)
|
|
188
|
+
discordChoixTexte("couleur", "couleur", "Bleu", "bleu")
|
|
189
|
+
discordChoixTexte("couleur", "couleur", "Rouge", "rouge")
|
|
190
|
+
|
|
191
|
+
discordCommande("difficulte", "Niveau choisi : {{niveau}}")
|
|
192
|
+
discordOptionEntier("difficulte", "niveau", "Choisis un niveau", true)
|
|
193
|
+
discordChoixEntier("difficulte", "niveau", "Facile", 1)
|
|
194
|
+
discordChoixEntier("difficulte", "niveau", "Normal", 2)
|
|
195
|
+
discordChoixEntier("difficulte", "niveau", "Difficile", 3)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
- `discordChoixTexte(commande, option, nomChoix, valeur)` ajoute un choix à une option texte.
|
|
199
|
+
- `discordChoixEntier(commande, option, nomChoix, valeur)` ajoute un choix à une option entière.
|
|
200
|
+
- Déclare toujours l'option avant ses choix.
|
|
201
|
+
- Une option peut avoir jusqu'à 25 choix. Les noms de choix sont limités à 100 caractères.
|
|
202
|
+
- Les choix sont présentés par Discord sous forme de liste et la valeur choisie est récupérable comme les autres options.
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
## Limites numériques des options (v1.1.7)
|
|
206
|
+
|
|
207
|
+
Les options slash de type nombre et entier peuvent imposer une valeur minimale et maximale. Déclare l'option d'abord, puis ses limites :
|
|
208
|
+
|
|
209
|
+
```fbp
|
|
210
|
+
discordConnexion()
|
|
211
|
+
discordCommande("age", "Âge sélectionné : {{age}}")
|
|
212
|
+
discordOptionEntier("age", "age", "Choisis un âge", true)
|
|
213
|
+
discordOptionEntierLimites("age", "age", 13, 99)
|
|
214
|
+
|
|
215
|
+
discordCommande("note", "Note sélectionnée : {{note}}")
|
|
216
|
+
discordOptionNombre("note", "note", "Choisis une note", true)
|
|
217
|
+
discordOptionNombreLimites("note", "note", 0, 20)
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
- `discordOptionEntierLimites(commande, option, minimum, maximum)` accepte uniquement des bornes entières.
|
|
221
|
+
- `discordOptionNombreLimites(commande, option, minimum, maximum)` accepte des bornes numériques, y compris décimales.
|
|
222
|
+
- Le minimum doit être inférieur ou égal au maximum.
|
|
223
|
+
- Les limites s'appliquent à l'interface Discord. Une option avec des choix prédéfinis ne peut pas recevoir de limites.
|
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.
|
|
11
|
+
const VERSION = "1.1.7";
|
|
12
12
|
function help() {
|
|
13
13
|
console.log(`FBP — French Bot Programming
|
|
14
14
|
|
package/dist/compiler.js
CHANGED
|
@@ -112,7 +112,7 @@ class FbpCompiler {
|
|
|
112
112
|
constructor(options = {}) {
|
|
113
113
|
this.output = options.onOutput ?? (value => console.log(value));
|
|
114
114
|
}
|
|
115
|
-
resolveDiscordValue(source, interaction, selectedUser, selectedMember) {
|
|
115
|
+
resolveDiscordValue(source, interaction, selectedUser, selectedMember, optionValues) {
|
|
116
116
|
const guild = interaction.guild;
|
|
117
117
|
const values = {
|
|
118
118
|
"discordServeur.nom": guild?.name ?? "Serveur indisponible",
|
|
@@ -130,6 +130,9 @@ class FbpCompiler {
|
|
|
130
130
|
"discordLatence": String(Math.max(0, Math.round(interaction.client.ws.ping))) + " ms",
|
|
131
131
|
"discordAvatar": selectedUser?.displayAvatarURL({ size: 256 }) ?? interaction.user.displayAvatarURL({ size: 256 })
|
|
132
132
|
};
|
|
133
|
+
const optionMatch = source.trim().match(/^(?:discordOption|option)\.([a-z0-9_-]{1,32})$/);
|
|
134
|
+
if (optionMatch)
|
|
135
|
+
return optionValues.get(optionMatch[1]) ?? "Option indisponible : " + optionMatch[1];
|
|
133
136
|
return source.trim() in values ? values[source.trim()] : "Source inconnue : " + source.trim();
|
|
134
137
|
}
|
|
135
138
|
runFile(filePath) {
|
|
@@ -217,6 +220,41 @@ class FbpCompiler {
|
|
|
217
220
|
.setDescription(response.userOption.description)
|
|
218
221
|
.setRequired(false));
|
|
219
222
|
}
|
|
223
|
+
for (const option of response.options ?? []) {
|
|
224
|
+
const add = {
|
|
225
|
+
texte: () => builder.addStringOption(item => {
|
|
226
|
+
item.setName(option.name).setDescription(option.description).setRequired(option.required);
|
|
227
|
+
for (const choice of option.choices ?? [])
|
|
228
|
+
if (typeof choice.value === "string")
|
|
229
|
+
item.addChoices({ name: choice.name, value: choice.value });
|
|
230
|
+
return item;
|
|
231
|
+
}),
|
|
232
|
+
nombre: () => builder.addNumberOption(item => {
|
|
233
|
+
item.setName(option.name).setDescription(option.description).setRequired(option.required);
|
|
234
|
+
if (option.minValue !== undefined)
|
|
235
|
+
item.setMinValue(option.minValue);
|
|
236
|
+
if (option.maxValue !== undefined)
|
|
237
|
+
item.setMaxValue(option.maxValue);
|
|
238
|
+
for (const choice of option.choices ?? [])
|
|
239
|
+
if (typeof choice.value === "number")
|
|
240
|
+
item.addChoices({ name: choice.name, value: choice.value });
|
|
241
|
+
return item;
|
|
242
|
+
}),
|
|
243
|
+
entier: () => builder.addIntegerOption(item => {
|
|
244
|
+
item.setName(option.name).setDescription(option.description).setRequired(option.required);
|
|
245
|
+
if (option.minValue !== undefined)
|
|
246
|
+
item.setMinValue(option.minValue);
|
|
247
|
+
if (option.maxValue !== undefined)
|
|
248
|
+
item.setMaxValue(option.maxValue);
|
|
249
|
+
for (const choice of option.choices ?? [])
|
|
250
|
+
if (typeof choice.value === "number")
|
|
251
|
+
item.addChoices({ name: choice.name, value: choice.value });
|
|
252
|
+
return item;
|
|
253
|
+
}),
|
|
254
|
+
booleen: () => builder.addBooleanOption(item => item.setName(option.name).setDescription(option.description).setRequired(option.required))
|
|
255
|
+
}[option.type];
|
|
256
|
+
add();
|
|
257
|
+
}
|
|
220
258
|
return builder.toJSON();
|
|
221
259
|
});
|
|
222
260
|
const manager = client.application?.commands;
|
|
@@ -244,8 +282,33 @@ class FbpCompiler {
|
|
|
244
282
|
if (response === undefined)
|
|
245
283
|
return;
|
|
246
284
|
try {
|
|
285
|
+
const optionValues = new Map();
|
|
286
|
+
for (const option of response.options ?? []) {
|
|
287
|
+
let value = null;
|
|
288
|
+
if (option.type === "texte")
|
|
289
|
+
value = interaction.options.getString(option.name);
|
|
290
|
+
else if (option.type === "nombre") {
|
|
291
|
+
const number = interaction.options.getNumber(option.name);
|
|
292
|
+
value = number === null ? null : String(number);
|
|
293
|
+
}
|
|
294
|
+
else if (option.type === "entier") {
|
|
295
|
+
const number = interaction.options.getInteger(option.name);
|
|
296
|
+
value = number === null ? null : String(number);
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
const boolean = interaction.options.getBoolean(option.name);
|
|
300
|
+
value = boolean === null ? null : String(boolean);
|
|
301
|
+
}
|
|
302
|
+
if (value === null && option.required) {
|
|
303
|
+
await interaction.reply({ content: "Option obligatoire indisponible : " + option.name, ephemeral: true });
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
if (value !== null)
|
|
307
|
+
optionValues.set(option.name, value);
|
|
308
|
+
}
|
|
247
309
|
if (response.type === "text") {
|
|
248
|
-
|
|
310
|
+
const content = response.content.replace(/\{\{([a-z0-9_-]{1,32})\}\}/g, (match, name) => optionValues.has(name) ? optionValues.get(name) : match);
|
|
311
|
+
await interaction.reply(content);
|
|
249
312
|
}
|
|
250
313
|
else {
|
|
251
314
|
const embed = new discord_js_1.EmbedBuilder()
|
|
@@ -255,9 +318,11 @@ class FbpCompiler {
|
|
|
255
318
|
const guild = interaction.guild;
|
|
256
319
|
const selectedUser = response.userOption ? interaction.options.getUser(response.userOption.name) : null;
|
|
257
320
|
const selectedMember = selectedUser && guild ? await guild.members.fetch(selectedUser.id).catch(() => null) : null;
|
|
321
|
+
if (response.userOption && selectedUser)
|
|
322
|
+
optionValues.set(response.userOption.name, selectedMember?.displayName ?? selectedUser.username);
|
|
258
323
|
const fields = response.fields.map(field => ({
|
|
259
324
|
name: field.name,
|
|
260
|
-
value: field.dynamic ? this.resolveDiscordValue(field.value, interaction, selectedUser, selectedMember) : field.value,
|
|
325
|
+
value: field.dynamic ? this.resolveDiscordValue(field.value, interaction, selectedUser, selectedMember, optionValues) : field.value.replace(/\{\{([a-z0-9_-]{1,32})\}\}/g, (match, name) => optionValues.get(name) ?? match),
|
|
261
326
|
inline: false
|
|
262
327
|
}));
|
|
263
328
|
if (fields.length)
|
|
@@ -266,7 +331,11 @@ class FbpCompiler {
|
|
|
266
331
|
}
|
|
267
332
|
}
|
|
268
333
|
catch (error) {
|
|
334
|
+
const message = "Une erreur est survenue pendant l'exécution de cette commande.";
|
|
269
335
|
this.output("Erreur Discord : " + (error instanceof Error ? error.message : String(error)));
|
|
336
|
+
if (!interaction.replied && !interaction.deferred) {
|
|
337
|
+
await interaction.reply({ content: message, ephemeral: true }).catch(() => undefined);
|
|
338
|
+
}
|
|
270
339
|
}
|
|
271
340
|
});
|
|
272
341
|
void client.login(token).catch((error) => this.output("Connexion Discord impossible : " + (error instanceof Error ? error.message : String(error))));
|
|
@@ -282,7 +351,7 @@ class FbpCompiler {
|
|
|
282
351
|
if (!/^[a-z0-9_-]{1,32}$/.test(commandName)) {
|
|
283
352
|
throw new errors_1.FbpError("Le nom d'une commande slash doit contenir 1 à 32 caractères : lettres minuscules, chiffres, tirets ou underscores.", undefined, line);
|
|
284
353
|
}
|
|
285
|
-
this.discordCommands.set(commandName, { type: "text", content: values[1] });
|
|
354
|
+
this.discordCommands.set(commandName, { type: "text", content: values[1], options: [] });
|
|
286
355
|
return;
|
|
287
356
|
}
|
|
288
357
|
if (name === "discordCommandeEmbed") {
|
|
@@ -296,7 +365,7 @@ class FbpCompiler {
|
|
|
296
365
|
throw new errors_1.FbpError("Le nom d'une commande slash doit contenir 1 à 32 caractères : lettres minuscules, chiffres, tirets ou underscores.", undefined, line);
|
|
297
366
|
if (!/^#[0-9a-fA-F]{6}$/.test(color))
|
|
298
367
|
throw new errors_1.FbpError("La couleur d'un embed doit être au format hexadécimal, par exemple #5865F2.", undefined, line);
|
|
299
|
-
this.discordCommands.set(commandName, { type: "embed", title, description, color, fields: [] });
|
|
368
|
+
this.discordCommands.set(commandName, { type: "embed", title, description, color, fields: [], options: [] });
|
|
300
369
|
return;
|
|
301
370
|
}
|
|
302
371
|
if (name === "discordChampDynamique") {
|
|
@@ -314,6 +383,83 @@ class FbpCompiler {
|
|
|
314
383
|
command.fields.push({ name: fieldName, value: source, dynamic: true });
|
|
315
384
|
return;
|
|
316
385
|
}
|
|
386
|
+
if (name === "discordChoixTexte" || name === "discordChoixEntier") {
|
|
387
|
+
if (values.length !== 4 || values.some(value => typeof value !== "string" && typeof value !== "number")) {
|
|
388
|
+
throw new errors_1.FbpError("Utilisation : discordChoixTexte(nomCommande, nomOption, nomChoix, valeur) ou discordChoixEntier(...).", undefined, line);
|
|
389
|
+
}
|
|
390
|
+
const [commandName, optionName, choiceName, choiceValue] = values;
|
|
391
|
+
if (typeof commandName !== "string" || typeof optionName !== "string" || typeof choiceName !== "string") {
|
|
392
|
+
throw new errors_1.FbpError("Le nom de la commande, de l'option et du choix doivent être du texte.", undefined, line);
|
|
393
|
+
}
|
|
394
|
+
const command = this.discordCommands.get(commandName);
|
|
395
|
+
if (!command)
|
|
396
|
+
throw new errors_1.FbpError("La commande « " + commandName + " » n'est pas déclarée.", undefined, line);
|
|
397
|
+
const option = (command.options ?? []).find(item => item.name === optionName);
|
|
398
|
+
const expectedType = name === "discordChoixTexte" ? "texte" : "entier";
|
|
399
|
+
if (!option || option.type !== expectedType)
|
|
400
|
+
throw new errors_1.FbpError("L'option « " + optionName + " » n'existe pas ou n'a pas le bon type.", undefined, line);
|
|
401
|
+
if (!choiceName.trim() || choiceName.length > 100)
|
|
402
|
+
throw new errors_1.FbpError("Le nom d'un choix doit contenir de 1 à 100 caractères.", undefined, line);
|
|
403
|
+
if (expectedType === "texte" && typeof choiceValue !== "string")
|
|
404
|
+
throw new errors_1.FbpError("La valeur d'un choix texte doit être du texte.", undefined, line);
|
|
405
|
+
if (expectedType === "entier" && (typeof choiceValue !== "number" || !Number.isInteger(choiceValue)))
|
|
406
|
+
throw new errors_1.FbpError("La valeur d'un choix entier doit être un nombre entier.", undefined, line);
|
|
407
|
+
if (option.minValue !== undefined || option.maxValue !== undefined)
|
|
408
|
+
throw new errors_1.FbpError("Une option avec des limites numériques ne peut pas recevoir de choix prédéfinis.", undefined, line);
|
|
409
|
+
const choices = option.choices ?? (option.choices = []);
|
|
410
|
+
if (choices.some(choice => choice.name === choiceName || choice.value === choiceValue))
|
|
411
|
+
throw new errors_1.FbpError("Ce nom ou cette valeur de choix existe déjà.", undefined, line);
|
|
412
|
+
if (choices.length >= 25)
|
|
413
|
+
throw new errors_1.FbpError("Une option Discord ne peut pas contenir plus de 25 choix.", undefined, line);
|
|
414
|
+
choices.push({ name: choiceName, value: choiceValue });
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
if (name === "discordOptionNombreLimites" || name === "discordOptionEntierLimites") {
|
|
418
|
+
if (values.length !== 4 || typeof values[0] !== "string" || typeof values[1] !== "string" || typeof values[2] !== "number" || typeof values[3] !== "number") {
|
|
419
|
+
throw new errors_1.FbpError("Utilisation : discordOptionNombreLimites(commande, option, minimum, maximum) ou discordOptionEntierLimites(...).", undefined, line);
|
|
420
|
+
}
|
|
421
|
+
const [commandName, optionName, minimum, maximum] = values;
|
|
422
|
+
const command = this.discordCommands.get(commandName);
|
|
423
|
+
if (!command)
|
|
424
|
+
throw new errors_1.FbpError("La commande « " + commandName + " » n'est pas déclarée.", undefined, line);
|
|
425
|
+
const expectedType = name === "discordOptionNombreLimites" ? "nombre" : "entier";
|
|
426
|
+
const option = (command.options ?? []).find(item => item.name === optionName);
|
|
427
|
+
if (!option || option.type !== expectedType)
|
|
428
|
+
throw new errors_1.FbpError("L'option « " + optionName + " » n'existe pas ou n'a pas le type numérique attendu.", undefined, line);
|
|
429
|
+
if (!Number.isFinite(minimum) || !Number.isFinite(maximum) || minimum > maximum || (expectedType === "entier" && (!Number.isInteger(minimum) || !Number.isInteger(maximum)))) {
|
|
430
|
+
throw new errors_1.FbpError("Les limites doivent être des nombres valides, minimum inférieur ou égal au maximum ; elles doivent être entières pour une option entière.", undefined, line);
|
|
431
|
+
}
|
|
432
|
+
if (option.choices?.length)
|
|
433
|
+
throw new errors_1.FbpError("Une option avec des choix prédéfinis ne peut pas recevoir de limites numériques.", undefined, line);
|
|
434
|
+
option.minValue = minimum;
|
|
435
|
+
option.maxValue = maximum;
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
if (name === "discordOptionTexte" || name === "discordOptionNombre" || name === "discordOptionEntier" || name === "discordOptionBooleen") {
|
|
439
|
+
if (values.length < 3 || values.length > 4 || values.some(value => typeof value !== "string" && typeof value !== "boolean")) {
|
|
440
|
+
throw new errors_1.FbpError("Utilisation : discordOptionTexte/Nombre/Entier/Booleen(nomCommande, nomOption, description, obligatoire).", undefined, line);
|
|
441
|
+
}
|
|
442
|
+
const [commandName, optionName, description] = values;
|
|
443
|
+
const required = values.length === 4 ? values[3] : false;
|
|
444
|
+
if (typeof commandName !== "string" || typeof optionName !== "string" || typeof description !== "string" || typeof required !== "boolean") {
|
|
445
|
+
throw new errors_1.FbpError("Les trois premiers arguments doivent être du texte et le quatrième, facultatif, doit être true ou false.", undefined, line);
|
|
446
|
+
}
|
|
447
|
+
const command = this.discordCommands.get(commandName);
|
|
448
|
+
if (!command)
|
|
449
|
+
throw new errors_1.FbpError("La commande « " + commandName + " » n'est pas déclarée.", undefined, line);
|
|
450
|
+
if (!/^[a-z0-9_-]{1,32}$/.test(optionName))
|
|
451
|
+
throw new errors_1.FbpError("Le nom de l'option doit contenir 1 à 32 caractères minuscules, chiffres, tirets ou underscores.", undefined, line);
|
|
452
|
+
if (!description.trim() || description.length > 100)
|
|
453
|
+
throw new errors_1.FbpError("La description de l'option doit contenir 1 à 100 caractères.", undefined, line);
|
|
454
|
+
const options = command.options ?? (command.options = []);
|
|
455
|
+
if (options.some(option => option.name === optionName) || (command.type === "embed" && command.userOption?.name === optionName))
|
|
456
|
+
throw new errors_1.FbpError("L'option « " + optionName + " » existe déjà pour cette commande.", undefined, line);
|
|
457
|
+
if (options.length + (command.type === "embed" && command.userOption ? 1 : 0) >= 25)
|
|
458
|
+
throw new errors_1.FbpError("Une commande slash Discord ne peut pas contenir plus de 25 options.", undefined, line);
|
|
459
|
+
const type = name === "discordOptionTexte" ? "texte" : name === "discordOptionNombre" ? "nombre" : name === "discordOptionEntier" ? "entier" : "booleen";
|
|
460
|
+
options.push({ name: optionName, description, type, required });
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
317
463
|
if (name === "discordOptionUtilisateur") {
|
|
318
464
|
if (values.length !== 3 || values.some(value => typeof value !== "string")) {
|
|
319
465
|
throw new errors_1.FbpError("Utilisation : discordOptionUtilisateur(nomCommande, nomOption, description).", undefined, line);
|
|
@@ -326,6 +472,11 @@ class FbpCompiler {
|
|
|
326
472
|
throw new errors_1.FbpError("Le nom de l'option doit contenir 1 à 32 caractères minuscules, chiffres, tirets ou underscores.", undefined, line);
|
|
327
473
|
if (!description.trim() || description.length > 100)
|
|
328
474
|
throw new errors_1.FbpError("La description de l'option doit contenir 1 à 100 caractères.", undefined, line);
|
|
475
|
+
const options = command.options ?? (command.options = []);
|
|
476
|
+
if (options.some(option => option.name === optionName) || command.userOption?.name === optionName)
|
|
477
|
+
throw new errors_1.FbpError("L'option « " + optionName + " » existe déjà pour cette commande.", undefined, line);
|
|
478
|
+
if (options.length + 1 > 25)
|
|
479
|
+
throw new errors_1.FbpError("Une commande slash Discord ne peut pas contenir plus de 25 options.", undefined, line);
|
|
329
480
|
command.userOption = { name: optionName, description };
|
|
330
481
|
return;
|
|
331
482
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fbp-language",
|
|
3
3
|
"displayName": "FBP - French Bot Programming",
|
|
4
|
-
"description": "Langage FBP avec
|
|
5
|
-
"version": "1.1.
|
|
4
|
+
"description": "Langage FBP avec options slash Discord, limites numériques, choix prédéfinis et embeds dynamiques.",
|
|
5
|
+
"version": "1.1.7",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"main": "dist/compiler.js",
|
|
8
8
|
"bin": {
|