Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughThe changes refactor the Changes
Sequence Diagram(s)sequenceDiagram
participant Caller
participant EmailUtils
Caller->>EmailUtils: extractEmailAddress(input)
alt Input contains angle-bracketed email at end
EmailUtils->>EmailUtils: isValidEmail(candidate)
alt Valid
EmailUtils-->>Caller: Return extracted email
else Invalid
EmailUtils->>EmailUtils: Check if trimmed input is valid email
alt Valid
EmailUtils-->>Caller: Return input
else Invalid
EmailUtils->>EmailUtils: Find all email-like substrings
EmailUtils->>EmailUtils: isValidEmail(each candidate)
alt Found valid
EmailUtils-->>Caller: Return first valid email
else None valid
EmailUtils-->>Caller: Return empty string
end
end
end
end
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
apps/web/utils/email.test.tsOops! Something went wrong! :( ESLint: 9.28.0 ESLint couldn't find an eslint.config.(js|mjs|cjs) file. From ESLint v9.0.0, the default configuration file is now eslint.config.js. https://eslint.org/docs/latest/use/configure/migration-guide If you still have problems after following the migration guide, please stop by apps/web/utils/email.tsOops! Something went wrong! :( ESLint: 9.28.0 ESLint couldn't find an eslint.config.(js|mjs|cjs) file. From ESLint v9.0.0, the default configuration file is now eslint.config.js. https://eslint.org/docs/latest/use/configure/migration-guide If you still have problems after following the migration guide, please stop by ✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
apps/web/utils/email.ts (1)
34-45: Regex under-matches international addresses & emails ending with punctuation
/\b[^\s<>]+@[^\s<>]+\.[^\s<>]+\b/excludes:
- IDN domains (
用户@例子.公司.cn) because\w-like classes don’t include Unicode by default.- Addresses that appear at sentence end (
hello@example.com.) because the trailing.becomes part of the match and subsequently failsisValidEmail.Consider relaxing the pattern and rely on
isValidEmailfor the heavy lifting:-const emailPattern = /\b[^\s<>]+@[^\s<>]+\.[^\s<>]+\b/gu; +// Allow almost anything up to the next whitespace / angle-bracket. +// Unicode flag (`u`) enables IDN capture; we’ll filter with isValidEmail(). +const emailPattern = /[^\s<>]+@[^\s<>]+/gu;apps/web/utils/email.test.ts (1)
141-163: Nice coverage, but consider adding a negative testYou added a wide range of complex addresses 👍. Adding a deliberate invalid case with similar punctuation (e.g.
"user-@example..com") will guard against future regex regressions that accidentally over-match.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/web/utils/email.test.ts(1 hunks)apps/web/utils/email.ts(2 hunks)version.txt(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: test
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
version.txt (1)
1-1: Version bump looks correct but please tag the repository.The change to
v1.6.0follows SemVer for a feature-level update.
Don’t forget to create a matching Git tag / release note before merging so downstream tooling can pick up the new version.apps/web/utils/email.ts (1)
2-2: Verifyzodis listed as a dependency
import { z } from "zod";adds a runtime dependency. Ensure the workspace root or theapps/webpackage.json declares"zod": "^3.x"(or desired range); otherwise consumers will face a runtime module-not-found error.apps/web/utils/email.test.ts (1)
88-121: A couple of “hyphen edge” test cases are actually invalid per RFC
"-test@example.com"and"test-@example.com"violate RFC 5322 (local part cannot start or end with ‘.’ but may with ‘-’; however many validators – including Zod’s – reject trailing hyphens).
If the objective is to accept what Zod accepts, keep them; otherwise mark them as invalid and expect""to avoid false positives.
| // Use Zod's built-in email validation | ||
| function isValidEmail(email: string): boolean { | ||
| return z.string().email().safeParse(email).success; | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Cache the Zod schema to avoid re-allocating on every call
z.string().email() allocates a new schema object each invocation, which is unnecessary and can become hot in tight loops.
-// Use Zod's built-in email validation
-function isValidEmail(email: string): boolean {
- return z.string().email().safeParse(email).success;
-}
+const emailSchema = z.string().email();
+
+function isValidEmail(email: string): boolean {
+ return emailSchema.safeParse(email).success;
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Use Zod's built-in email validation | |
| function isValidEmail(email: string): boolean { | |
| return z.string().email().safeParse(email).success; | |
| } | |
| const emailSchema = z.string().email(); | |
| function isValidEmail(email: string): boolean { | |
| return emailSchema.safeParse(email).success; | |
| } |
🤖 Prompt for AI Agents
In apps/web/utils/email.ts around lines 49 to 52, the isValidEmail function
creates a new Zod schema on every call, causing unnecessary allocations. To fix
this, define the Zod email schema once outside the function as a constant, then
reuse this cached schema inside isValidEmail to perform the validation. This
avoids repeated schema creation and improves performance.
| // Try to extract from angle brackets first | ||
| const bracketMatch = email.match(/<([^<>]+)>$/); | ||
| if (bracketMatch) { | ||
| const candidate = bracketMatch[1].trim(); | ||
| if (isValidEmail(candidate)) { | ||
| return candidate; | ||
| } | ||
| } | ||
|
|
||
| // If no brackets or invalid email in brackets, try the whole string | ||
| if (isValidEmail(email.trim())) { | ||
| return email.trim(); | ||
| } | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Trim the input once to avoid bracket-match edge cases and double work
/<([^<>]+)>$/ only matches when the closing > is the last non-newline character.
Strings such as "John <john@example.com> " (trailing space) or " John <john@example.com>" (leading space) will miss the fast-path even though they are perfectly valid.
-export function extractEmailAddress(email: string): string {
- if (!email) return "";
+export function extractEmailAddress(email: string): string {
+ if (!email) return "";
+ const trimmed = email.trim();
- // Try to extract from angle brackets first
- const bracketMatch = email.match(/<([^<>]+)>$/);
+ // Try to extract from angle brackets first
+ const bracketMatch = trimmed.match(/<([^<>]+)>\s*$/);Besides tightening correctness, this avoids calling trim() repeatedly further down the function.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Try to extract from angle brackets first | |
| const bracketMatch = email.match(/<([^<>]+)>$/); | |
| if (bracketMatch) { | |
| const candidate = bracketMatch[1].trim(); | |
| if (isValidEmail(candidate)) { | |
| return candidate; | |
| } | |
| } | |
| // If no brackets or invalid email in brackets, try the whole string | |
| if (isValidEmail(email.trim())) { | |
| return email.trim(); | |
| } | |
| export function extractEmailAddress(email: string): string { | |
| if (!email) return ""; | |
| const trimmed = email.trim(); | |
| // Try to extract from angle brackets first | |
| const bracketMatch = trimmed.match(/<([^<>]+)>\s*$/); | |
| if (bracketMatch) { | |
| const candidate = bracketMatch[1].trim(); | |
| if (isValidEmail(candidate)) { | |
| return candidate; | |
| } | |
| } | |
| // If no brackets or invalid email in brackets, try the whole string | |
| if (isValidEmail(email.trim())) { | |
| return email.trim(); | |
| } | |
| // …rest of function… | |
| } |
🤖 Prompt for AI Agents
In apps/web/utils/email.ts around lines 20 to 33, the email input should be
trimmed once at the start to handle cases with leading or trailing spaces that
cause the regex /<([^<>]+)>$/ to miss valid emails inside angle brackets. Trim
the email string once before applying the regex and subsequent validation to
improve correctness and avoid multiple trim calls.
Summary by CodeRabbit