Skip to content

Commit 0f078d0

Browse files
committed
feat: Add RegEx filter commands
1 parent 1626fe9 commit 0f078d0

2 files changed

Lines changed: 94 additions & 0 deletions

File tree

src/i18n/english.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default {
1818
TOO_LATE: 'Too late!',
1919
USER_NOT_FOUND: 'User not found!',
2020
WRONG_ROOM: 'Wrong room.',
21+
INVALID_ARGUMENTS: 'Invalid number of arguments.',
2122

2223
GAME: {
2324
ALREADY_JOINED: 'You have already joined this game.',

src/ps/commands/filter.tsx

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { abilities, items, moves, pokedex } from 'ps-client/data';
2+
3+
import { toId } from '@/tools';
4+
import { ChatError } from '@/utils/chatError';
5+
6+
import type { ToTranslate } from '@/i18n/types';
7+
import type { PSCommand } from '@/types/chat';
8+
import type { ReactElement } from 'react';
9+
10+
function List({ items }: { items: string[] }): ReactElement {
11+
return (
12+
<div className="infobox">
13+
<details>
14+
<summary>{items.length} Match(es)</summary>
15+
<hr />
16+
{items.space(<br />)}
17+
</details>
18+
</div>
19+
);
20+
}
21+
22+
const filterTypes: {
23+
name: string;
24+
initial: string;
25+
aliases: string[];
26+
entries: { id: string; name: string }[];
27+
}[] = [
28+
{
29+
name: 'abilities',
30+
initial: 'a',
31+
aliases: ['abilities', 'ability'],
32+
sources: [abilities],
33+
},
34+
{
35+
name: 'items',
36+
initial: 'i',
37+
aliases: ['items', 'item'],
38+
39+
sources: [items],
40+
},
41+
{
42+
name: 'moves',
43+
initial: 'm',
44+
aliases: ['moves', 'move'],
45+
sources: [moves],
46+
},
47+
{
48+
name: 'pokedex',
49+
initial: 'n',
50+
aliases: ['dex', 'names', 'name'],
51+
sources: [pokedex],
52+
},
53+
54+
{
55+
name: 'all',
56+
initial: '',
57+
aliases: ['all'],
58+
sources: [abilities, items, moves, pokedex],
59+
},
60+
].map(type => ({
61+
...type,
62+
entries: type.sources.flatMap(source => {
63+
return Object.values(source).map(entry => ({
64+
name: entry.name,
65+
id: 'id' in entry ? entry.id : toId(entry.name),
66+
}));
67+
}),
68+
}));
69+
70+
export const command: PSCommand[] = Object.values(filterTypes).map(({ initial, aliases, entries }) => ({
71+
name: `filter${aliases[0]}`,
72+
help: 'Filter matching entries (by RegEx). See https://regexone.com for help.',
73+
syntax: 'CMD [pattern]',
74+
flags: { pmOnly: true },
75+
aliases: [...aliases.slice(1), `f${initial}`],
76+
async run({ message, $T, arg }) {
77+
const basePattern = arg.trim();
78+
if (!basePattern) throw new ChatError($T('INVALID_ARGUMENTS'));
79+
let pattern: RegExp;
80+
try {
81+
pattern = new RegExp(basePattern, 'i');
82+
} catch {
83+
throw new ChatError('Invalid regular expression. Try https://regex101.com for help.' as ToTranslate);
84+
}
85+
86+
const matchedEntries = entries
87+
.filter(entry => pattern.test(entry.id))
88+
.map(entry => entry.name)
89+
.sort();
90+
91+
message.replyHTML(matchedEntries.length > 0 ? <List items={matchedEntries} /> : 'Results: 0');
92+
},
93+
}));

0 commit comments

Comments
 (0)