Skip to content

fix: Update getInitialsFromName to sanitize name#3743

Closed
mannycarrera4 wants to merge 5 commits intoWorkday:masterfrom
mannycarrera4:mc-fix-avatar-initials-sanitize
Closed

fix: Update getInitialsFromName to sanitize name#3743
mannycarrera4 wants to merge 5 commits intoWorkday:masterfrom
mannycarrera4:mc-fix-avatar-initials-sanitize

Conversation

@mannycarrera4
Copy link
Contributor

@mannycarrera4 mannycarrera4 commented Feb 4, 2026

Summary

Fixes: #3740

Release Category

Components


Checklist

For the Reviewer

  • PR title is short and descriptive
  • PR summary describes the change (Fixes/Resolves linked correctly)
  • PR Release Notes describes additional information useful to call out in a release message or removed if not applicable
  • Breaking Changes provides useful information to upgrade to this code or removed if not applicable

Where Should the Reviewer Start?

Areas for Feedback? (optional)

  • Code
  • Documentation
  • Testing
  • Codemods

Testing Manually

Screenshots or GIFs (if applicable)

Thank You Gif (optional)

@cypress
Copy link

cypress bot commented Feb 4, 2026

Workday/canvas-kit    Run #10362

Run Properties:  status check passed Passed #10362  •  git commit 4b017de31f ℹ️: Merge e5ee43ed4c5c56d530046c32210a372c3d17b192 into 4dfa021c4798122cacd6b18b660d...
Project Workday/canvas-kit
Branch Review mc-fix-avatar-initials-sanitize
Run status status check passed Passed #10362
Run duration 02m 24s
Commit git commit 4b017de31f ℹ️: Merge e5ee43ed4c5c56d530046c32210a372c3d17b192 into 4dfa021c4798122cacd6b18b660d...
Committer Manuel Carrera
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 1
Tests that did not run due to a developer annotating a test with .skip  Pending 86
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 862
View all changes introduced in this branch ↗︎
UI Coverage  19.36%
  Untested elements 1539  
  Tested elements 367  
Accessibility  99.33%
  Failed rules  6 critical   5 serious   0 moderate   2 minor
  Failed elements 77  

@mannycarrera4 mannycarrera4 added the ready for review Code is ready for review label Feb 9, 2026
@mannycarrera4 mannycarrera4 marked this pull request as ready for review February 9, 2026 22:59
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a bug where getInitialsFromName didn't handle names with parenthetical content (like titles or departments). The implementation now sanitizes names by removing parenthetical content and filtering out numeric and Roman numeral suffixes before extracting initials.

Changes:

  • Updated getInitialsFromName to remove parenthetical content using regex
  • Added filtering for numeric suffixes and Roman numeral suffixes (III, IV, etc.)
  • Added comprehensive test suite with 14 test cases covering various edge cases

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 8 comments.

File Description
modules/preview-react/avatar/lib/getInitialsFromName.ts Enhanced sanitization logic to handle parenthetical content and suffix filtering
modules/preview-react/avatar/spec/getInitialsFromName.spec.tsx New comprehensive test suite covering various name formats and edge cases

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +48 to +49
expect(getInitialsFromName('Mohammed Al-Rashid')).toBe('MA');
});
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function doesn't handle hyphenated names or names with apostrophes consistently. For example:

  • "Mary-Jane Smith" would produce "MS" (treating "Mary-Jane" as one word)
  • "O'Brien" would be treated as one word
  • "Jean-Luc Picard" would produce "JP"

While the current behavior may be acceptable, consider whether hyphenated first/last names should be split or kept together. The test case for "Mohammed Al-Rashid" expects "MA", which suggests the current behavior is intentional, but this should be explicitly tested for various hyphenation scenarios to ensure consistency.

Copilot uses AI. Check for mistakes.
expect(getInitialsFromName('Logan McNeil iii')).toBe('LM');
expect(getInitialsFromName('Logan McNeil Iii')).toBe('LM');
});
});
Copy link

Copilot AI Feb 10, 2026

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 uses AI. Check for mistakes.
// Filter out parts that are purely numeric or Roman numerals (suffixes like III, IV)
const filteredParts = nameParts.filter(part => {
const isNumeric = /^\d+$/.test(part);
const isRomanNumeral = /^[IVX]+$/i.test(part);
Copy link

Copilot AI Feb 10, 2026

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

Suggested change
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);

Copilot uses AI. Check for mistakes.
Copy link
Member

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.

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');
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These test cases expose a flaw in the implementation. "Iii" and "iii" are not valid Roman numerals (the valid form is "III"), yet the implementation's regex /^[IVX]+$/i will match them. This test passes because it validates the current buggy behavior.

When the Roman numeral regex is fixed to only match valid Roman numerals, these tests should be updated to either:

  1. Expect "LI" as the result (treating "Iii" as a name part, not a suffix), or
  2. Use valid Roman numerals like "III" if the intent is to test suffix filtering
Suggested change
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 uses AI. Check for mistakes.
expect(getInitialsFromName('Logan McNeil iii')).toBe('LM');
expect(getInitialsFromName('Logan McNeil Iii')).toBe('LM');
});
});
Copy link

Copilot AI Feb 10, 2026

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.

Copilot uses AI. Check for mistakes.
// 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();
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parenthetical content removal only handles round parentheses (). If the intent is to sanitize titles, departments, or similar metadata, you should also consider removing content in other bracket types like square brackets [] or curly braces {}, which are also commonly used for similar purposes.

For example, the current implementation won't sanitize "John Smith [Engineering]" or "John Smith {CEO}". Consider using a pattern like /[\(\[\{][^\)\]\}]*[\)\]\}]/g if you want to handle all bracket types.

Suggested change
const sanitized = name.replace(/\([^)]*\)/g, '').trim();
const sanitized = name.replace(/[\(\[\{][^\)\]\}]*[\)\]\}]/g, '').trim();

Copilot uses AI. Check for mistakes.
@@ -1,10 +1,20 @@
export const getInitialsFromName = (name: string) => {
Copy link

Copilot AI Feb 10, 2026

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:
/**

  • Extracts initials from a person's name by taking the first letter of the first and last name parts.
  • Removes parenthetical content (e.g., titles, departments) and filters out numeric and Roman numeral suffixes.
  • @param name - The full name to extract initials from
  • @returns A string containing the extracted initials in uppercase, or an empty string if no valid name parts are found
    */

Copilot uses AI. Check for mistakes.
mannycarrera4 and others added 2 commits February 18, 2026 15:10
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Alan B Smith <a.bax.smith@gmail.com>
@mannycarrera4
Copy link
Contributor Author

I'm gonna close this PR, there's too many edge cases, unless we come up with a standard to handle all of these, this is just going to cause more confusion, teams should use preferredInitials

@github-project-automation github-project-automation bot moved this to ✅ Done in Canvas Kit Feb 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready for review Code is ready for review

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

Update getInitialsFromName to sanitize the name for a better output

2 participants

Comments