-
Notifications
You must be signed in to change notification settings - Fork 252
fix: Update getInitialsFromName to sanitize name #3743
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
3abde31
e19e584
aee4431
471a194
e5ee43e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,11 +1,24 @@ | ||||||
| /** | ||||||
| Extracts initials from a person's name by taking the first letter of the first and last name parts. It also sanitizes input to filter out common name prefixes and suffixes. | ||||||
| */ | ||||||
| export const getInitialsFromName = (name: string) => { | ||||||
|
mannycarrera4 marked this conversation as resolved.
|
||||||
| // Trim and split by one or more whitespace characters | ||||||
| const nameParts = name.trim().split(/\s+/).filter(Boolean); | ||||||
| // Remove parenthetical content (e.g., titles, departments) and trim | ||||||
| const sanitized = name.replace(/\([^)]*\)/g, '').trim(); | ||||||
|
||||||
| const sanitized = name.replace(/\([^)]*\)/g, '').trim(); | |
| const sanitized = name.replace(/[\(\[\{][^\)\]\}]*[\)\]\}]/g, '').trim(); |
Copilot
AI
Feb 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Roman numeral regex pattern is too broad and will incorrectly match valid name parts. For example, it will match "Vin" (contains only I, V, X), "Vivi" (contains only I, V, X), or any word composed solely of the letters I, V, and X in any combination. This could incorrectly filter out legitimate names or parts of names.
Consider using a more precise pattern that matches only valid Roman numerals like: /^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/i or a simpler whitelist approach that matches common suffixes: /^(I|II|III|IV|V|VI|VII|VIII|IX|X|XI|XII|XIII|XIV|XV)$/i
| const isRomanNumeral = /^[IVX]+$/i.test(part); | |
| const isRomanNumeral = /^(I|II|III|IV|V|VI|VII|VIII|IX|X|XI|XII|XIII|XIV|XV)$/i.test(part); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I don't think we need to test for roman numerals like LX. Low odds of running into Alan Smith the 60th, but let's say Pope Leo XIV is on Workday. We should probably accommodate his Holiness.
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,55 @@ | ||||||||||||||
| import {getInitialsFromName} from '../lib/getInitialsFromName'; | ||||||||||||||
|
|
||||||||||||||
| describe('getInitialsFromName', () => { | ||||||||||||||
| it('should return initials from a simple first and last name', () => { | ||||||||||||||
| expect(getInitialsFromName('Logan McNeil')).toBe('LM'); | ||||||||||||||
| }); | ||||||||||||||
|
|
||||||||||||||
| it('should return initials from a single name', () => { | ||||||||||||||
| expect(getInitialsFromName('Logan')).toBe('L'); | ||||||||||||||
| }); | ||||||||||||||
|
|
||||||||||||||
| it('should remove parenthetical content', () => { | ||||||||||||||
| expect(getInitialsFromName('Logan McNeil (SFV, VP Director)')).toBe('LM'); | ||||||||||||||
| }); | ||||||||||||||
|
|
||||||||||||||
| it('should filter out Roman numeral suffixes', () => { | ||||||||||||||
| expect(getInitialsFromName('Logan McNeil III')).toBe('LM'); | ||||||||||||||
| expect(getInitialsFromName('John Smith IV')).toBe('JS'); | ||||||||||||||
| expect(getInitialsFromName('Mary Johnson II')).toBe('MJ'); | ||||||||||||||
| }); | ||||||||||||||
|
|
||||||||||||||
| it('should handle multiple middle names', () => { | ||||||||||||||
| expect(getInitialsFromName('John Paul Jones')).toBe('JJ'); | ||||||||||||||
| }); | ||||||||||||||
|
|
||||||||||||||
| it('should handle names with both parenthetical content and suffixes', () => { | ||||||||||||||
| expect(getInitialsFromName('Logan McNeil III (VP Director)')).toBe('LM'); | ||||||||||||||
| }); | ||||||||||||||
|
|
||||||||||||||
| it('should handle extra whitespace', () => { | ||||||||||||||
| expect(getInitialsFromName(' Logan McNeil ')).toBe('LM'); | ||||||||||||||
| }); | ||||||||||||||
|
|
||||||||||||||
| it('should return empty string for empty input', () => { | ||||||||||||||
| expect(getInitialsFromName('')).toBe(''); | ||||||||||||||
| }); | ||||||||||||||
|
|
||||||||||||||
| it('should handle names with only parenthetical content', () => { | ||||||||||||||
| expect(getInitialsFromName('(VP Director)')).toBe(''); | ||||||||||||||
| }); | ||||||||||||||
|
|
||||||||||||||
| it('should handle names with numeric suffixes', () => { | ||||||||||||||
| expect(getInitialsFromName('Logan McNeil 3')).toBe('LM'); | ||||||||||||||
| }); | ||||||||||||||
|
|
||||||||||||||
| it('should work with names from various cultures', () => { | ||||||||||||||
| expect(getInitialsFromName('José García')).toBe('JG'); | ||||||||||||||
| expect(getInitialsFromName('Mohammed Al-Rashid')).toBe('MA'); | ||||||||||||||
| }); | ||||||||||||||
|
Comment on lines
+48
to
+49
|
||||||||||||||
|
|
||||||||||||||
| it('should handle mixed case Roman numerals', () => { | ||||||||||||||
| expect(getInitialsFromName('Logan McNeil iii')).toBe('LM'); | ||||||||||||||
| expect(getInitialsFromName('Logan McNeil Iii')).toBe('LM'); | ||||||||||||||
|
Comment on lines
+51
to
+53
|
||||||||||||||
| it('should handle mixed case Roman numerals', () => { | |
| expect(getInitialsFromName('Logan McNeil iii')).toBe('LM'); | |
| expect(getInitialsFromName('Logan McNeil Iii')).toBe('LM'); | |
| it('should filter valid Roman numeral suffixes', () => { | |
| expect(getInitialsFromName('Logan McNeil III')).toBe('LM'); | |
| expect(getInitialsFromName('Logan McNeil II')).toBe('LM'); |
Copilot
AI
Feb 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing test coverage for edge case where someone has a single-letter name that happens to be I, V, or X (e.g., "X Æ A-12" or "Malcolm X"). Due to the overly broad Roman numeral regex /^[IVX]+$/i, these valid name parts would be incorrectly filtered out.
Add test cases like:
getInitialsFromName('Malcolm X')should return 'MX', not 'M'getInitialsFromName('X Smith')should return 'XS', not 'S'
This edge case will be resolved when the Roman numeral regex is fixed to match only valid Roman numeral suffixes.
Copilot
AI
Feb 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function does not handle unmatched parentheses or other bracket types (e.g., square brackets, curly braces). Consider adding test cases for edge cases like:
- Unmatched opening parenthesis: "John Smith ("
- Unmatched closing parenthesis: "John Smith )"
- Square brackets: "John Smith [Department]"
- Nested parentheses: "John Smith ((nested))"
The current regex /\([^)]*\)/g only handles matched parentheses, which could leave orphaned opening parentheses in the sanitized string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function lacks JSDoc documentation. Based on the codebase convention (see modules/preview-react/select/lib/utils.ts and modules/preview-react/select/lib/scrolling.ts), exported utility functions should have JSDoc comments that describe their purpose, parameters, and return values.
Consider adding JSDoc documentation like:
/**
*/