Skip to content

Commit 4dfa67b

Browse files
authored
Merge pull request #408 from SableClient/fix-pronoun-regex
Much stricter regex for the pronoun filters
2 parents dd91aca + 1cd3850 commit 4dfa67b

File tree

3 files changed

+38
-48
lines changed

3 files changed

+38
-48
lines changed

src/app/components/user-profile/UserRoomProfile.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ function UserExtendedSection({
9595
const languagesToFilterFor = getSettings().filterPronounsLanguages ?? ['en'];
9696

9797
const pronouns = filterPronounsByLanguage(
98-
profile.pronouns!,
98+
profile.pronouns,
9999
languageFilterEnabled,
100100
languagesToFilterFor
101101
)

src/app/utils/pronouns.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ describe('filterPronounsByLanguage', () => {
8383
});
8484

8585
it('returns empty array for non-array input', () => {
86-
// @ts-expect-error — testing runtime safety
8786
expect(filterPronounsByLanguage(null, true, ['en'])).toEqual([]);
8887
});
8988
});

src/app/utils/pronouns.ts

Lines changed: 37 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ export type PronounSet = {
44
grammatical_gender?: string;
55
};
66

7-
// helper function to convert a comma-separated pronouns string into an array of objects with summary and optional language
8-
export function parsePronounsInput(pronouns: string): { summary: string; language?: string }[] {
7+
export function parsePronounsInput(
8+
pronouns?: string | null
9+
): { summary: string; language?: string }[] {
910
if (!pronouns || typeof pronouns !== 'string') return [];
1011

1112
return pronouns
@@ -17,94 +18,84 @@ export function parsePronounsInput(pronouns: string): { summary: string; languag
1718

1819
if (parts.length === 1) {
1920
return {
20-
summary: (parts[0] || '').slice(0, 16),
21+
summary: (parts[0] ?? '').trim().slice(0, 16),
2122
language: 'en',
2223
};
2324
}
2425

2526
const [language, summary] = parts;
26-
2727
return {
28-
language: (language || 'en').trim() || 'en',
29-
summary: (summary || '').trim().slice(0, 16),
28+
language: (language ?? 'en').trim().toLowerCase() || 'en',
29+
summary: (summary ?? '').trim().slice(0, 16),
3030
};
3131
});
3232
}
3333

34-
export function parsePronounsStringToPronounsSetArray(pronouns: string): PronounSet[] {
35-
return parsePronounsInput(pronouns) as unknown as PronounSet[];
34+
export function parsePronounsStringToPronounsSetArray(pronouns?: string | null): PronounSet[] {
35+
return parsePronounsInput(pronouns) as PronounSet[];
3636
}
3737

38-
// helper function to filter a list of pronouns based on the user's language settings
3938
export function filterPronounsByLanguage(
40-
pronouns: { summary: string; language?: string }[],
41-
enabled: boolean,
42-
languages: string[]
39+
pronouns?: { summary: string; language?: string }[] | null,
40+
enabled?: boolean,
41+
languages?: (string | null | undefined)[]
4342
): { summary: string; language?: string }[] {
4443
if (!Array.isArray(pronouns)) return [];
4544

45+
const sanitize = (p: { summary: string; language?: string }) => ({
46+
...p,
47+
summary: (p?.summary ?? '').slice(0, 16),
48+
});
49+
4650
if (!enabled) {
47-
return pronouns.map((p) => ({
48-
...p,
49-
summary: (p?.summary || '').slice(0, 16),
50-
}));
51+
return pronouns.map(sanitize);
5152
}
5253

53-
const normalizedLanguages = (languages || [])
54-
.filter(Boolean)
54+
const normalizedLanguages = (languages ?? [])
55+
.filter((lang): lang is string => typeof lang === 'string')
5556
.map((lang) => lang.trim().toLowerCase());
5657

5758
const filteredPronouns = pronouns
5859
.filter((p) => {
59-
const lang = (p?.language || 'en').trim().toLowerCase();
60+
const lang = (p?.language ?? 'en').trim().toLowerCase();
6061
return normalizedLanguages.includes(lang);
6162
})
62-
.map((p) => ({
63-
...p,
64-
summary: (p?.summary || '').slice(0, 16),
65-
}));
66-
67-
if (filteredPronouns.length === 0) {
68-
return pronouns.map((p) => ({
69-
...p,
70-
summary: (p?.summary || '').slice(0, 16),
71-
}));
72-
}
63+
.map(sanitize);
7364

74-
return filteredPronouns;
65+
return filteredPronouns.length > 0 ? filteredPronouns : pronouns.map(sanitize);
7566
}
7667

7768
const pronounParseCache = new Map<
7869
string,
7970
{ cleanedDisplayName: string; inlinePronoun: string | null }
8071
>();
8172

82-
export function getParsedPronouns(rawName: string, parseSetting: boolean) {
83-
if (!parseSetting || !rawName) {
84-
return { cleanedDisplayName: rawName, inlinePronoun: null };
73+
export function getParsedPronouns(rawName?: string | null, parseSetting?: boolean) {
74+
if (!parseSetting || !rawName || typeof rawName !== 'string') {
75+
return { cleanedDisplayName: rawName ?? '', inlinePronoun: null };
8576
}
8677

87-
if (pronounParseCache.has(rawName)) {
88-
return pronounParseCache.get(rawName)!;
89-
}
78+
const cached = pronounParseCache.get(rawName);
79+
if (cached) return cached;
9080

91-
// match text like (she/her) or [he/they/them] but not (hi)
92-
const regex = /[([]?([a-zA-Z]+\/[a-zA-Z]+(?:\/[a-zA-Z]+)?)[)\]]?/;
81+
const regex =
82+
/(?:\(([a-zA-Z]+\/[a-zA-Z]+(?:\/[a-zA-Z]+)?)\)|\[([a-zA-Z]+\/[a-zA-Z]+(?:\/[a-zA-Z]+)?)\])/;
9383
const match = rawName.match(regex);
9484

9585
let result: { cleanedDisplayName: string; inlinePronoun: string | null } = {
96-
cleanedDisplayName: rawName,
86+
cleanedDisplayName: rawName.trim(),
9787
inlinePronoun: null,
9888
};
9989

10090
if (match) {
101-
let strippedName = rawName.replace(match[0], '').trim();
102-
if (!strippedName || strippedName === '') {
103-
strippedName = rawName;
104-
}
91+
const fullMatch = match[0];
92+
const capturedPronoun = (match[1] ?? match[2] ?? '').toLowerCase().slice(0, 16);
93+
94+
const strippedName = rawName.replace(fullMatch, '').trim();
95+
10596
result = {
106-
cleanedDisplayName: strippedName,
107-
inlinePronoun: match[1].toLowerCase().slice(0, 16),
97+
cleanedDisplayName: strippedName || rawName,
98+
inlinePronoun: capturedPronoun || null,
10899
};
109100
}
110101

0 commit comments

Comments
 (0)