Skip to content

Commit 3024c8a

Browse files
migrate to v13
1 parent a696b7b commit 3024c8a

File tree

3 files changed

+154
-121
lines changed

3 files changed

+154
-121
lines changed

package-lock.json

Lines changed: 45 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
"discord.js": "^13.3.1",
2121
"discord.js-docs": "github:BenjammingKirby/discord.js-docs#typescriptRewrite",
2222
"dotenv": "^10.0.0",
23+
"fast-xml-parser": "^4.0.0-beta.7",
24+
"flexsearch": "^0.7.21",
2325
"glob": "^7.2.0",
2426
"pm2": "^5.1.2"
2527
},

src/commands/docs/mdn.ts

Lines changed: 107 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,145 +1,131 @@
1-
import { Command } from "discord-akairo";
2-
import { Message } from "discord.js";
1+
import { MessageEmbed } from "discord.js";
32
import { gunzipSync } from "zlib";
43
import { XMLParser } from "fast-xml-parser";
5-
import BotClient from "../../client/client";
64
import fetch from "node-fetch";
75
import flexsearch from "flexsearch";
86

7+
import { Command } from "../../interfaces";
8+
import { SlashCommandBuilder } from "@discordjs/builders";
99
interface SitemapEntry<T extends string | number> {
10-
loc: string;
11-
lastmod: T;
10+
loc: string;
11+
lastmod: T;
1212
}
1313
type Sitemap<T extends string | number> = SitemapEntry<T>[];
1414

1515
const baseURL = "https://developer.mozilla.org/en-US/docs/" as const;
1616
let sources = {
17-
index: null as flexsearch.Index,
18-
sitemap: null as Sitemap<number>,
19-
lastUpdated: null as number,
17+
index: null as flexsearch.Index,
18+
sitemap: null as Sitemap<number>,
19+
lastUpdated: null as number,
2020
};
21+
const MDN_BLUE_COLOR = 0x83bfff as const;
22+
const MDN_ICON_URL = "https://i.imgur.com/1P4wotC.png" as const;
23+
const command: Command = {
24+
data: new SlashCommandBuilder()
25+
.setName("mdn")
26+
.setDescription("Searches MDN documentation.")
27+
.addStringOption((opt) =>
28+
opt
29+
.setName("query")
30+
.setDescription("Enter the phrase you'd like to search for. Example: Array.filter")
31+
.setRequired(true),
32+
),
33+
async execute(interaction) {
34+
const query = interaction.options.getString("query");
35+
const { index, sitemap } = await getSources();
36+
const search: string[] = index.search(query, { limit: 10 }).map((id) => sitemap[<number>id].loc);
37+
const embed = new MessageEmbed()
38+
.setColor(MDN_BLUE_COLOR)
39+
.setAuthor("MDN Documentation", MDN_ICON_URL)
40+
.setTitle(`Search for: ${query}`);
2141

22-
async function getSources(): Promise<typeof sources> {
23-
if (sources.lastUpdated && Date.now() - sources.lastUpdated < 43200000 /* 12 hours */) return sources;
24-
25-
const res = await fetch("https://developer.mozilla.org/sitemaps/en-us/sitemap.xml.gz");
26-
if (!res.ok) return sources; // Fallback to old sources if the new ones are not available for any reason
27-
28-
const sitemap: Sitemap<number> = new XMLParser()
29-
.parse(gunzipSync(await res.buffer()).toString()).urlset.url
30-
.map((entry: SitemapEntry<string>) => ({
31-
loc: entry.loc.slice(baseURL.length),
32-
lastmod: new Date(entry.lastmod).valueOf()
33-
}));
34-
35-
const index = new flexsearch.Index();
36-
sitemap.forEach((entry, idx) => index.add(idx, entry.loc));
42+
if (!search.length) {
43+
embed.setColor(0xff0000).setDescription("No results found...");
44+
interaction.editReply({ embeds: [embed] });
45+
return;
46+
}
3747

38-
sources = { index, sitemap, lastUpdated: Date.now() };
39-
return sources;
40-
}
48+
if (search.length === 1) {
49+
const res = await fetch(`${baseURL + search[0]}/index.json`);
50+
const doc: MdnDoc = (await res.json()).doc;
51+
const docEmbed = embed
52+
.setColor(0xffffff)
53+
.setTitle(doc.pageTitle)
54+
.setURL(`https://developer.mozilla.org/${doc.mdn_url}`)
55+
.setThumbnail(this.MDN_ICON_URL)
56+
.setDescription(doc.summary);
57+
interaction.editReply({ embeds: [docEmbed] });
58+
return;
59+
}
4160

42-
export default class MdnCommand extends Command {
43-
public client: BotClient;
44-
private MDN_BLUE_COLOR = 0x83BFFF as const;
45-
private MDN_ICON_URL = "https://i.imgur.com/1P4wotC.png" as const;
61+
const results = search.map((path) => `**• [${path.replace(/_|-/g, " ")}](${baseURL}${path})**`);
62+
embed.setDescription(results.join("\n"));
63+
interaction.editReply({ embeds: [embed] });
64+
return;
65+
},
66+
};
4667

47-
public constructor() {
48-
super("mdn-docs", {
49-
aliases: ["mdn", "mdndocs"],
50-
description: {
51-
content: "Searches MDN documentation.",
52-
usage: "<query>",
53-
examples: ['TODO']
54-
},
55-
channel: "guild",
56-
clientPermissions: ["EMBED_LINKS"],
57-
ratelimit: 2,
58-
args: [
59-
{
60-
id: "query",
61-
match: "rest",
62-
type: "string",
63-
prompt: {
64-
start: "```\n" + "Enter the phrase you'd like to search for.\n" + "Example: Array.filter" + "```",
65-
retry: "Not a valid search phrase.",
66-
},
67-
}
68-
],
69-
});
70-
}
68+
async function getSources(): Promise<typeof sources> {
69+
if (sources.lastUpdated && Date.now() - sources.lastUpdated < 43200000 /* 12 hours */) return sources;
7170

72-
public async exec(message: Message, { query }: { query: string }): Promise<Message | Message[]> {
73-
const { index, sitemap } = await getSources();
74-
const search: string[] = index.search(query, { limit: 10 }).map((id) => sitemap[<number>id].loc);
75-
const embed = this.client.util
76-
.embed()
77-
.setColor(this.MDN_BLUE_COLOR)
78-
.setAuthor("MDN Documentation", this.MDN_ICON_URL)
79-
.setTitle(`Search for: ${query}`);
71+
const res = await fetch("https://developer.mozilla.org/sitemaps/en-us/sitemap.xml.gz");
72+
if (!res.ok) return sources; // Fallback to old sources if the new ones are not available for any reason
8073

81-
if (!search.length) {
82-
embed.setColor(0xFF0000).setDescription("No results found...");
83-
return message.util.send(embed);
84-
}
74+
const sitemap: Sitemap<number> = new XMLParser()
75+
.parse(gunzipSync(await res.buffer()).toString())
76+
.urlset.url.map((entry: SitemapEntry<string>) => ({
77+
loc: entry.loc.slice(baseURL.length),
78+
lastmod: new Date(entry.lastmod).valueOf(),
79+
}));
8580

86-
if (search.length === 1) {
87-
const res = await fetch(`${baseURL + search[0]}/index.json`);
88-
const doc: MdnDoc = (await res.json()).doc;
89-
const docEmbed = this.client.util
90-
.embed()
91-
.setColor(0xFFFFFF)
92-
.setTitle(doc.pageTitle)
93-
.setURL(`https://developer.mozilla.org/${doc.mdn_url}`)
94-
.setThumbnail(this.MDN_ICON_URL)
95-
.setDescription(doc.summary);
96-
return message.util.send(docEmbed);
97-
}
81+
const index = new flexsearch.Index();
82+
sitemap.forEach((entry, idx) => index.add(idx, entry.loc));
9883

99-
let results = search.map((path) => `**• [${path.replace(/_|-/g, " ")}](${baseURL}${path})**`);
100-
embed.setDescription(results.join("\n"));
101-
return message.util.send(embed);
102-
}
84+
sources = { index, sitemap, lastUpdated: Date.now() };
85+
return sources;
10386
}
10487

10588
interface MdnDoc {
106-
isMarkdown: boolean,
107-
isTranslated: boolean,
108-
isActive: boolean,
109-
flaws: {},
110-
title: string,
111-
mdn_url: string,
112-
locale: string,
113-
native: string,
114-
sidebarHTML: string,
115-
body: ({
116-
type: "prose" | "specifications" | "browser_compatibility",
117-
value: {
118-
id: string | null,
119-
title: string | null,
120-
isH3: boolean,
121-
// type:prose
122-
content?: string,
123-
// type:specifications
124-
specifications?: ({ bcdSpecificationURL: string, title: string, shortTitle: string })[],
125-
// type:browser_compatibility
126-
dataURL?: string,
127-
// type:specifications | type:browser_compatibility
128-
query?: string,
129-
}
130-
})[],
131-
toc: ({ text: string, id: string })[],
132-
summary: string,
133-
popularity: number,
134-
modified: string, // ISO Date String
135-
other_translations: ({ title: string, locale: string, native: string })[],
136-
source: {
137-
folder: string,
138-
github_url: string,
139-
last_commit_url: string,
140-
filename: string
141-
},
142-
parents: ({ uri: string, title: string })[],
143-
pageTitle: string,
144-
noIndexing: boolean
89+
isMarkdown: boolean;
90+
isTranslated: boolean;
91+
isActive: boolean;
92+
//TODO Fix this
93+
// eslint-disable-next-line
94+
flaws: {};
95+
title: string;
96+
mdn_url: string;
97+
locale: string;
98+
native: string;
99+
sidebarHTML: string;
100+
body: {
101+
type: "prose" | "specifications" | "browser_compatibility";
102+
value: {
103+
id: string | null;
104+
title: string | null;
105+
isH3: boolean;
106+
// type:prose
107+
content?: string;
108+
// type:specifications
109+
specifications?: { bcdSpecificationURL: string; title: string; shortTitle: string }[];
110+
// type:browser_compatibility
111+
dataURL?: string;
112+
// type:specifications | type:browser_compatibility
113+
query?: string;
114+
};
115+
}[];
116+
toc: { text: string; id: string }[];
117+
summary: string;
118+
popularity: number;
119+
modified: string; // ISO Date String
120+
other_translations: { title: string; locale: string; native: string }[];
121+
source: {
122+
folder: string;
123+
github_url: string;
124+
last_commit_url: string;
125+
filename: string;
126+
};
127+
parents: { uri: string; title: string }[];
128+
pageTitle: string;
129+
noIndexing: boolean;
145130
}
131+
export default command;

0 commit comments

Comments
 (0)