Fix phone validation performance by using Set/Map instead of Array lookups (#17843)
## Summary - **`isValidCountryCode`** was using `Array.includes()` on ~250 country codes (O(n) per call). Replaced with a `Set.has()` lookup (O(1)). - **`getCountryCodesForCallingCode`** was iterating all ~250 countries and calling `getCountryCallingCode()` on each one **every invocation**. Replaced with a precomputed `Map<callingCode, CountryCode[]>` built once at module load (O(1) per call). Both functions are called from `transformPhonesValue` on every phone field mutation, causing cumulative overhead visible in profiling (p95 self-time ~20-35ms). ## Test plan - [ ] Verify phone field creation/update still works correctly (country code validation, calling code resolution) - [ ] Verify spreadsheet import with phone fields still validates properly - [ ] Confirm no regression in `isValidCountryCode` or `getCountryCodesForCallingCode` behavior Made with [Cursor](https://cursor.com) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+23
-8
@@ -1,15 +1,30 @@
|
||||
import { getCountries, getCountryCallingCode } from 'libphonenumber-js';
|
||||
import {
|
||||
type CountryCode,
|
||||
getCountries,
|
||||
getCountryCallingCode,
|
||||
} from 'libphonenumber-js';
|
||||
|
||||
const ALL_COUNTRIES_CODE = getCountries();
|
||||
// Precompute a map from calling code to country codes for O(1) lookups
|
||||
const CALLING_CODE_TO_COUNTRIES = new Map<string, CountryCode[]>();
|
||||
|
||||
export const getCountryCodesForCallingCode = (callingCode: string) => {
|
||||
for (const country of getCountries()) {
|
||||
const callingCode = getCountryCallingCode(country);
|
||||
|
||||
const existing = CALLING_CODE_TO_COUNTRIES.get(callingCode);
|
||||
|
||||
if (existing) {
|
||||
existing.push(country);
|
||||
} else {
|
||||
CALLING_CODE_TO_COUNTRIES.set(callingCode, [country]);
|
||||
}
|
||||
}
|
||||
|
||||
export const getCountryCodesForCallingCode = (
|
||||
callingCode: string,
|
||||
): CountryCode[] => {
|
||||
const cleanCallingCode = callingCode.startsWith('+')
|
||||
? callingCode.slice(1)
|
||||
: callingCode;
|
||||
|
||||
return ALL_COUNTRIES_CODE.filter((country) => {
|
||||
const countryCallingCode = getCountryCallingCode(country);
|
||||
|
||||
return countryCallingCode === cleanCallingCode;
|
||||
});
|
||||
return CALLING_CODE_TO_COUNTRIES.get(cleanCallingCode) ?? [];
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { type CountryCode, getCountries } from 'libphonenumber-js';
|
||||
|
||||
const ALL_COUNTRIES_CODE = getCountries();
|
||||
const ALL_COUNTRIES_CODE_SET = new Set<string>(getCountries());
|
||||
|
||||
export const isValidCountryCode = (input: string): input is CountryCode => {
|
||||
return ALL_COUNTRIES_CODE.includes(input as unknown as CountryCode);
|
||||
return ALL_COUNTRIES_CODE_SET.has(input);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user