-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathnpm.ts
More file actions
100 lines (94 loc) · 3.17 KB
/
npm.ts
File metadata and controls
100 lines (94 loc) · 3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import {
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
Collection,
EmbedBuilder,
type MessageActionRowComponentBuilder,
StringSelectMenuBuilder,
StringSelectMenuOptionBuilder,
} from 'discord.js';
import { CHAIN_EMOJI } from '../../constants/emoji.js';
import { clampText } from '../../util/text.js';
import type { ProviderConfig } from './types.js';
import { createBaseConfig, getSearchUrl, SEARCH_TERM, TERM } from './utils.js';
type SearchItem = {
name: string;
version: string;
description: string;
license: string;
links: {
npm: string;
homepage?: string;
repository?: string;
};
};
type SearchResult = {
objects: Array<{
package: SearchItem;
}>;
};
const baseConfig = createBaseConfig({
color: 0xfb_3e_44,
icon: 'https://avatars0.githubusercontent.com/u/6078720',
directUrl: `https://www.npmjs.com/package/${TERM}`,
commandDescription: 'Search NPM for JavaScript packages',
});
export const npmProvider: ProviderConfig<SearchItem> = {
...baseConfig,
getFilteredData: async (query: string) => {
const response = await fetch(
getSearchUrl(`https://registry.npmjs.org/-/v1/search?text=${SEARCH_TERM}&size=10`, query)
);
if (!response.ok) {
throw new Error(`Error fetching NPM data: ${response.status} ${response.statusText}`);
}
const data = (await response.json()) as SearchResult;
return data.objects.map((obj) => obj.package);
},
createCollection: (items) => new Collection(items.map((item) => [item.name, item])),
createActionBuilders: (data) => {
const selectRow = new ActionRowBuilder<MessageActionRowComponentBuilder>().addComponents(
new StringSelectMenuBuilder()
.setCustomId('npm-select')
.setPlaceholder('Select a package')
.setMinValues(1)
.setMaxValues(1)
.addOptions(
...data.map((pkg) =>
new StringSelectMenuOptionBuilder()
.setLabel(pkg.name)
.setDescription(clampText(pkg.description, 100))
.setValue(pkg.name)
)
)
);
const buttonRow = new ActionRowBuilder<MessageActionRowComponentBuilder>().addComponents(
new ButtonBuilder().setCustomId('npm-cancel').setLabel('Cancel').setStyle(ButtonStyle.Danger)
);
return { selectRow, buttonRow };
},
createResultEmbeds: (selectedItems) =>
selectedItems.map((pkg) =>
new EmbedBuilder()
.setTitle(`${CHAIN_EMOJI} ${pkg.name}`)
.setThumbnail(baseConfig.icon)
.setURL(pkg.links.npm)
.setColor(baseConfig.color)
.setDescription(clampText(pkg.description, 200))
.setFields(
Object.entries(pkg.links)
.filter(([key, value]) => key !== 'npm' && value !== undefined)
.map(([key, value]) => ({
name: key,
value,
}))
)
.setFooter({ text: `Version ${pkg.version} | License: ${pkg.license ?? 'N/A'}` })
.setTimestamp()
),
getDisplayTitle: (item) => item.name,
getSelectionMessage: (query) => `Select a package for **${query}**:`,
getDisplayMessage: (selectedTitles) =>
`Displaying Result for **${new Intl.ListFormat('en-US').format(selectedTitles)}**:`,
};