@sapphire/cli 1.6.0-next.afa4afb.0 → 1.6.0

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/CHANGELOG.md CHANGED
@@ -2,6 +2,32 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ # [1.6.0](https://github.com/sapphiredev/cli/compare/v1.5.0...v1.6.0) - (2023-04-12)
6
+
7
+ ## 🏠 Refactor
8
+
9
+ - Remove `with-docker` template ([1b485f8](https://github.com/sapphiredev/cli/commit/1b485f836d656022dd761cc13862fa9a970142a7))
10
+ - Stricter typing for config parsing ([ab0efb3](https://github.com/sapphiredev/cli/commit/ab0efb3c602843b76bf64e135c0a448288227462))
11
+ - **new:** Make yarn v3 the default ([30499ea](https://github.com/sapphiredev/cli/commit/30499ea72a52c31220794f41da695494145c9b08))
12
+ - **CreateFileFromTemplate:** Better internal code naming ([3189772](https://github.com/sapphiredev/cli/commit/3189772a1b85ecc2bad2949ed8d339ff0541cebf))
13
+ - Better error messages for `generate` when template doesn't exist ([dc34e1e](https://github.com/sapphiredev/cli/commit/dc34e1ecda585eeb7024d716fbf401e8e18a9b93))
14
+
15
+ ## 🐛 Bug Fixes
16
+
17
+ - Better error messages when creating file ([afa4afb](https://github.com/sapphiredev/cli/commit/afa4afba579f4877eecbe447a9728b71b4042b0c))
18
+ - Fixed JSON config file ([6fe3d0c](https://github.com/sapphiredev/cli/commit/6fe3d0c87a0ba70a802d73c73028832b77c0077b))
19
+ - **templates:** Adhere to strict type checking rules ([b455738](https://github.com/sapphiredev/cli/commit/b455738705d475d99357f758d9eeea505d43c2f2))
20
+
21
+ ## 🚀 Features
22
+
23
+ - Add route in prompt (#220) ([60451d6](https://github.com/sapphiredev/cli/commit/60451d6e2c92ef42c07f592d2923177aa9386595))
24
+ - **templates:** Add interaction handler templates (#216) ([650ec76](https://github.com/sapphiredev/cli/commit/650ec76c3c17e2ae5d480994daac4b42bacbfc34))
25
+ - Add `interactive-tools` plugin for yarn v3 installs ([c417d97](https://github.com/sapphiredev/cli/commit/c417d970f139da1827fe914f69903f90df436907))
26
+
27
+ ## 🪞 Styling
28
+
29
+ - Add prettierignore file ([2d24595](https://github.com/sapphiredev/cli/commit/2d24595e347a9e4d24ca6926e35fb60945e11725))
30
+
5
31
  # [1.5.0](https://github.com/sapphiredev/cli/compare/v1.4.0...v1.5.0) - (2023-04-10)
6
32
 
7
33
  ## 🐛 Bug Fixes
@@ -40,8 +40,16 @@ async function fetchConfig() {
40
40
  * @returns A string with a hint for the user
41
41
  */
42
42
  function parseCommonHints(component) {
43
- if (component.toLowerCase() === 'command' || component.toLowerCase() === 'commands') {
44
- return `\nHint: You wrote "${component}", instead of "messagecommand", "slashcommand", or "contextmenucommand"`;
43
+ const newLine = '\n';
44
+ const lowerCaseComponent = component.toLowerCase();
45
+ if (lowerCaseComponent === 'command' || lowerCaseComponent === 'commands') {
46
+ return `${newLine}Hint: You wrote "${component}", instead of "messagecommand", "slashcommand", or "contextmenucommand"`;
47
+ }
48
+ if (lowerCaseComponent === 'interaction-handler' ||
49
+ lowerCaseComponent === 'interaction-handlers' ||
50
+ lowerCaseComponent === 'interactionhandler' ||
51
+ lowerCaseComponent === 'interactionhandlers') {
52
+ return `${newLine}Hint: You wrote "${component}", instead of "buttoninteractionhandler", "autocompleteinteractionhandler", "modalinteractionhandler", or "selectmenuinteractionhandler"`;
45
53
  }
46
54
  return '';
47
55
  }
@@ -20,7 +20,9 @@ export default async () => {
20
20
  arguments: response.arguments,
21
21
  commands: response.commands,
22
22
  listeners: response.listeners,
23
- preconditions: response.preconditions
23
+ preconditions: response.preconditions,
24
+ 'interaction-handlers': response['interaction-handlers'],
25
+ routes: response.routes ?? ''
24
26
  },
25
27
  customFileTemplates: {
26
28
  enabled: response.cftEnabled,
@@ -47,6 +47,23 @@ export const PromptInit = [
47
47
  message: 'Where do you store your preconditions? (do not include the base)',
48
48
  initial: 'preconditions'
49
49
  },
50
+ {
51
+ type: 'text',
52
+ name: 'interaction-handlers',
53
+ message: 'Where do you store your interaction handlers? (do not include the base)',
54
+ initial: 'interaction-handlers'
55
+ },
56
+ {
57
+ type: 'confirm',
58
+ name: 'rEnabled',
59
+ message: 'Would you use the api plugin?'
60
+ },
61
+ {
62
+ type: (prev) => (prev ? 'text' : null),
63
+ name: 'rLocation',
64
+ message: 'Where do you store your routes? (do not include the base)',
65
+ initial: 'routes'
66
+ },
50
67
  {
51
68
  type: 'confirm',
52
69
  name: 'cftEnabled',
@@ -1,7 +1,6 @@
1
1
  const tsTemplates = [
2
2
  { title: 'Starter template (Recommended)', value: 'with-typescript-starter' },
3
3
  { title: 'Complete template', value: 'with-typescript-complete' },
4
- { title: 'with Docker', value: 'with-docker' },
5
4
  { title: 'with tsup', value: 'with-tsup' },
6
5
  { title: 'with SWC', value: 'with-swc' }
7
6
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sapphire/cli",
3
- "version": "1.6.0-next.afa4afb.0",
3
+ "version": "1.6.0",
4
4
  "description": "CLI for Sapphire Framework",
5
5
  "author": "@sapphire",
6
6
  "license": "MIT",
@@ -48,7 +48,10 @@
48
48
  "@commitlint/config-conventional": "^17.4.4",
49
49
  "@favware/cliff-jumper": "^2.0.0",
50
50
  "@favware/npm-deprecate": "^1.0.7",
51
+ "@sapphire/decorators": "*",
51
52
  "@sapphire/eslint-config": "^4.4.0",
53
+ "@sapphire/framework": "*",
54
+ "@sapphire/plugin-api": "*",
52
55
  "@sapphire/prettier-config": "^1.4.5",
53
56
  "@sapphire/ts-config": "^4.0.0",
54
57
  "@types/js-yaml": "^4.0.5",
@@ -57,6 +60,7 @@
57
60
  "@typescript-eslint/eslint-plugin": "^5.58.0",
58
61
  "@typescript-eslint/parser": "^5.58.0",
59
62
  "cz-conventional-changelog": "^3.3.0",
63
+ "discord.js": "*",
60
64
  "eslint": "^8.38.0",
61
65
  "eslint-config-prettier": "^8.8.0",
62
66
  "eslint-plugin-prettier": "^4.2.1",
@@ -6,6 +6,7 @@
6
6
  "commands": "commands",
7
7
  "listeners": "listeners",
8
8
  "preconditions": "preconditions",
9
+ "interaction-handlers": "interaction-handlers",
9
10
  "routes": "routes"
10
11
  },
11
12
  "customFileTemplates": {
@@ -5,6 +5,7 @@ locations:
5
5
  commands: commands
6
6
  listeners: listeners
7
7
  preconditions: preconditions
8
+ interaction-handlers: interaction-handlers
8
9
  routes: routes
9
10
  customFileTemplates:
10
11
  enabled: false
@@ -0,0 +1,50 @@
1
+ { "category": "interaction-handlers" }
2
+ ---
3
+ const { InteractionHandler, InteractionHandlerTypes } = require('@sapphire/framework');
4
+ const { InteractionHandler, InteractionHandlerTypes } = require('@sapphire/framework');
5
+
6
+ class AutocompleteHandler extends InteractionHandler {
7
+ /**
8
+ * @param {InteractionHandler.Context} context
9
+ * @param {InteractionHandler.Options} options
10
+ */
11
+ constructor(context, options) {
12
+ super(context, {
13
+ ...options,
14
+ interactionHandlerType: InteractionHandlerTypes.Autocomplete
15
+ });
16
+ }
17
+
18
+ /**
19
+ * @param {import('discord.js').AutocompleteInteraction} interaction
20
+ * @param {import('discord.js').ApplicationCommandOptionChoiceData[]} result
21
+ */
22
+ async run(interaction, result) {
23
+ return interaction.respond(result);
24
+ }
25
+
26
+ /**
27
+ * @param {import('discord.js').AutocompleteInteraction} interaction
28
+ */
29
+ async parse(interaction) {
30
+ // Only run this interaction for the command with ID '1000000000000000000'
31
+ if (interaction.commandId !== '1000000000000000000') return this.none();
32
+ // Get the focussed (current) option
33
+ const focusedOption = interaction.options.getFocused(true);
34
+ // Ensure that the option name is one that can be autocompleted, or return none if not.
35
+ switch (focusedOption.name) {
36
+ case 'search': {
37
+ // Search your API or similar. This is example code!
38
+ const searchResult = await myApi.searchForSomething(focusedOption.value);
39
+ // Map the search results to the structure required for Autocomplete
40
+ return this.some(searchResult.map((match) => ({ name: match.name, value: match.key })));
41
+ }
42
+ default:
43
+ return this.none();
44
+ }
45
+ }
46
+ }
47
+
48
+ module.exports = {
49
+ AutocompleteHandler
50
+ };
@@ -0,0 +1,32 @@
1
+ { "category": "interaction-handlers" }
2
+ ---
3
+ import { ApplyOptions } from '@sapphire/decorators';
4
+ import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework';
5
+ import { AutocompleteInteraction, type ApplicationCommandOptionChoiceData } from 'discord.js';
6
+
7
+ @ApplyOptions<InteractionHandler.Options>({
8
+ interactionHandlerType: InteractionHandlerTypes.Autocomplete
9
+ })
10
+ export class AutocompleteHandler extends InteractionHandler {
11
+ public override async run(interaction: AutocompleteInteraction, result: ApplicationCommandOptionChoiceData[]) {
12
+ return interaction.respond(result);
13
+ }
14
+
15
+ public override async parse(interaction: AutocompleteInteraction) {
16
+ // Only run this interaction for the command with ID '1000000000000000000'
17
+ if (interaction.commandId !== '1000000000000000000') return this.none();
18
+ // Get the focussed (current) option
19
+ const focusedOption = interaction.options.getFocused(true);
20
+ // Ensure that the option name is one that can be autocompleted, or return none if not.
21
+ switch (focusedOption.name) {
22
+ case 'search': {
23
+ // Search your API or similar. This is example code!
24
+ const searchResult = await myApi.searchForSomething(focusedOption.value);
25
+ // Map the search results to the structure required for Autocomplete
26
+ return this.some(searchResult.map((match) => ({ name: match.name, value: match.key })));
27
+ }
28
+ default:
29
+ return this.none();
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,39 @@
1
+ { "category": "interaction-handlers" }
2
+ ---
3
+ const { InteractionHandler, InteractionHandlerTypes } = require('@sapphire/framework');
4
+
5
+ class ButtonHandler extends InteractionHandler {
6
+ /**
7
+ * @param {InteractionHandler.Context} context
8
+ * @param {InteractionHandler.Options} options
9
+ */
10
+ constructor(context, options) {
11
+ super(context, {
12
+ ...options,
13
+ interactionHandlerType: InteractionHandlerTypes.Button
14
+ });
15
+ }
16
+
17
+ /**
18
+ * @param {import('discord.js').ButtonInteraction} interaction
19
+ */
20
+ async run(interaction) {
21
+ await interaction.reply({
22
+ content: 'Hello from a button interaction handler!',
23
+ // Let's make it so only the person who pressed the button can see this message!
24
+ ephemeral: true
25
+ });
26
+ }
27
+
28
+ /**
29
+ * @param {import('discord.js').ButtonInteraction} interaction
30
+ */
31
+ parse(interaction) {
32
+ if (interaction.customId !== 'my-awesome-button') return this.none();
33
+ return this.some();
34
+ }
35
+ }
36
+
37
+ module.exports = {
38
+ ButtonHandler
39
+ };
@@ -0,0 +1,24 @@
1
+ { "category": "interaction-handlers" }
2
+ ---
3
+ import { ApplyOptions } from '@sapphire/decorators';
4
+ import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework';
5
+ import type { ButtonInteraction } from 'discord.js';
6
+
7
+ @ApplyOptions<InteractionHandler.Options>({
8
+ interactionHandlerType: InteractionHandlerTypes.Button
9
+ })
10
+ export class ButtonHandler extends InteractionHandler {
11
+ public async run(interaction: ButtonInteraction) {
12
+ await interaction.reply({
13
+ content: 'Hello from a button interaction handler!',
14
+ // Let's make it so only the person who pressed the button can see this message!
15
+ ephemeral: true
16
+ });
17
+ }
18
+
19
+ public override parse(interaction: ButtonInteraction) {
20
+ if (interaction.customId !== 'my-awesome-button') return this.none();
21
+
22
+ return this.some();
23
+ }
24
+ }
@@ -0,0 +1,39 @@
1
+ { "category": "interaction-handlers" }
2
+ ---
3
+ const { InteractionHandler, InteractionHandlerTypes } = require('@sapphire/framework');
4
+
5
+ class ModalHandler extends InteractionHandler {
6
+ /**
7
+ * @param {InteractionHandler.Context} context
8
+ * @param {InteractionHandler.Options} options
9
+ */
10
+ constructor(context, options) {
11
+ super(context, {
12
+ ...options,
13
+ interactionHandlerType: InteractionHandlerTypes.ModalSubmit
14
+ });
15
+ }
16
+
17
+ /**
18
+ * @param {import('discord.js').ModalSubmitInteraction} interaction
19
+ */
20
+ async run(interaction) {
21
+ await interaction.reply({
22
+ content: 'Thank you for submitting the form!',
23
+ ephemeral: true
24
+ });
25
+ }
26
+
27
+ /**
28
+ * @param {import('discord.js').ModalSubmitInteraction} interaction
29
+ */
30
+ parse(interaction) {
31
+ if (interaction.customId !== 'hello-popup') return this.none();
32
+
33
+ return this.some();
34
+ }
35
+ }
36
+
37
+ module.exports = {
38
+ ModalHandler
39
+ };
@@ -0,0 +1,23 @@
1
+ { "category": "interaction-handlers" }
2
+ ---
3
+ import { ApplyOptions } from '@sapphire/decorators';
4
+ import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework';
5
+ import type { ModalSubmitInteraction } from 'discord.js';
6
+
7
+ @ApplyOptions<InteractionHandler.Options>({
8
+ interactionHandlerType: InteractionHandlerTypes.ModalSubmit
9
+ })
10
+ export class ModalHandler extends InteractionHandler {
11
+ public async run(interaction: ModalSubmitInteraction) {
12
+ await interaction.reply({
13
+ content: 'Thank you for submitting the form!',
14
+ ephemeral: true
15
+ });
16
+ }
17
+
18
+ public override parse(interaction: ModalSubmitInteraction) {
19
+ if (interaction.customId !== 'hello-popup') return this.none();
20
+
21
+ return this.some();
22
+ }
23
+ }
@@ -1,6 +1,7 @@
1
1
  { "category": "routes" }
2
2
  ---
3
3
  const { methods, Route } = require('@sapphire/plugin-api');
4
+
4
5
  class UserRoute extends Route {
5
6
  /**
6
7
  * @param {Route.Context} context
@@ -0,0 +1,39 @@
1
+ { "category": "interaction-handlers" }
2
+ ---
3
+ const { InteractionHandler, InteractionHandlerTypes } = require('@sapphire/framework');
4
+
5
+ class MenuHandler extends InteractionHandler {
6
+ /**
7
+ * @param {InteractionHandler.Context} context
8
+ * @param {InteractionHandler.Options} options
9
+ */
10
+ constructor(context, options) {
11
+ super(context, {
12
+ ...options,
13
+ interactionHandlerType: InteractionHandlerTypes.SelectMenu
14
+ });
15
+ }
16
+
17
+ /**
18
+ * @param {import('discord.js').StringSelectMenuInteraction} interaction
19
+ */
20
+ async run(interaction) {
21
+ await interaction.reply({
22
+ // Remember how we can have multiple values? Let's get the first one!
23
+ content: `You selected: ${interaction.values[0]}`
24
+ });
25
+ }
26
+
27
+ /**
28
+ * @param {import('discord.js').StringSelectMenuInteraction} interaction
29
+ */
30
+ parse(interaction) {
31
+ if (interaction.customId !== 'my-echo-select') return this.none();
32
+
33
+ return this.some();
34
+ }
35
+ }
36
+
37
+ module.exports = {
38
+ MenuHandler
39
+ };
@@ -0,0 +1,23 @@
1
+ { "category": "interaction-handlers" }
2
+ ---
3
+ import { ApplyOptions } from '@sapphire/decorators';
4
+ import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework';
5
+ import type { StringSelectMenuInteraction } from 'discord.js';
6
+
7
+ @ApplyOptions<InteractionHandler.Options>({
8
+ interactionHandlerType: InteractionHandlerTypes.SelectMenu
9
+ })
10
+ export class MenuHandler extends InteractionHandler {
11
+ public override async run(interaction: StringSelectMenuInteraction) {
12
+ await interaction.reply({
13
+ // Remember how we can have multiple values? Let's get the first one!
14
+ content: `You selected: ${interaction.values[0]}`
15
+ });
16
+ }
17
+
18
+ public override parse(interaction: StringSelectMenuInteraction) {
19
+ if (interaction.customId !== 'my-echo-select') return this.none();
20
+
21
+ return this.some();
22
+ }
23
+ }
@@ -27,11 +27,14 @@
27
27
  "preconditions": {
28
28
  "type": "string"
29
29
  },
30
+ "interaction-handlers": {
31
+ "type": "string"
32
+ },
30
33
  "routes": {
31
34
  "type": "string"
32
35
  }
33
36
  },
34
- "required": ["base", "arguments", "commands", "listeners", "preconditions"]
37
+ "required": ["base", "arguments", "commands", "listeners", "preconditions", "interaction-handlers"]
35
38
  },
36
39
  "customFileTemplates": {
37
40
  "description": "Settings about custom component (piece) templates",