about summary refs log tree commit diff
path: root/src/lib/strings
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/strings')
-rw-r--r--src/lib/strings/__tests__/email.test.ts82
-rw-r--r--src/lib/strings/email.ts9
2 files changed, 91 insertions, 0 deletions
diff --git a/src/lib/strings/__tests__/email.test.ts b/src/lib/strings/__tests__/email.test.ts
new file mode 100644
index 000000000..4dfda658f
--- /dev/null
+++ b/src/lib/strings/__tests__/email.test.ts
@@ -0,0 +1,82 @@
+import {describe, expect, it} from '@jest/globals'
+import tldts from 'tldts'
+
+import {isEmailMaybeInvalid} from '#/lib/strings/email'
+
+describe('emailTypoChecker', () => {
+  const invalidCases = [
+    'gnail.com',
+    'gnail.co',
+    'gmaill.com',
+    'gmaill.co',
+    'gmai.com',
+    'gmai.co',
+    'gmal.com',
+    'gmal.co',
+    'gmail.co',
+    'iclod.com',
+    'iclod.co',
+    'outllok.com',
+    'outllok.co',
+    'outlook.co',
+    'yaoo.com',
+    'yaoo.co',
+    'yaho.com',
+    'yaho.co',
+    'yahooo.com',
+    'yahooo.co',
+    'yahoo.co',
+    'hithere.jul',
+    'agpowj.notshop',
+    'thisisnot.avalid.tld.nope',
+    // old tld for czechoslovakia
+    'czechoslovakia.cs',
+    // tlds that cbs was registering in 2024 but cancelled
+    'liveon.cbs',
+    'its.showtime',
+  ]
+  const validCases = [
+    'gmail.com',
+    // subdomains (tests end of string)
+    'gnail.com.test.com',
+    'outlook.com',
+    'yahoo.com',
+    'icloud.com',
+    'firefox.com',
+    'firefox.co',
+    'hello.world.com',
+    'buy.me.a.coffee.shop',
+    'mayotte.yt',
+    'aland.ax',
+    'bouvet.bv',
+    'uk.gb',
+    'chad.td',
+    'somalia.so',
+    'plane.aero',
+    'cute.cat',
+    'together.coop',
+    'findme.jobs',
+    'nightatthe.museum',
+    'industrial.mil',
+    'czechrepublic.cz',
+    'lovakia.sk',
+    // new gtlds in 2024
+    'whatsinyour.locker',
+    'letsmakea.deal',
+    'skeet.now',
+    'everyone.みんな',
+    'bourgeois.lifestyle',
+    'california.living',
+    'skeet.ing',
+    'listeningto.music',
+    'createa.meme',
+  ]
+
+  it.each(invalidCases)(`should be invalid: abcde@%s`, domain => {
+    expect(isEmailMaybeInvalid(`abcde@${domain}`, tldts)).toEqual(true)
+  })
+
+  it.each(validCases)(`should be valid: abcde@%s`, domain => {
+    expect(isEmailMaybeInvalid(`abcde@${domain}`, tldts)).toEqual(false)
+  })
+})
diff --git a/src/lib/strings/email.ts b/src/lib/strings/email.ts
new file mode 100644
index 000000000..04b603847
--- /dev/null
+++ b/src/lib/strings/email.ts
@@ -0,0 +1,9 @@
+import type tldts from 'tldts'
+
+const COMMON_ERROR_PATTERN =
+  /([a-zA-Z0-9._%+-]+)@(gnail\.(co|com)|gmaill\.(co|com)|gmai\.(co|com)|gmail\.co|gmal\.(co|com)|iclod\.(co|com)|icloud\.co|outllok\.(co|com)|outlok\.(co|com)|outlook\.co|yaoo\.(co|com)|yaho\.(co|com)|yahoo\.co|yahooo\.(co|com))$/
+
+export function isEmailMaybeInvalid(email: string, dynamicTldts: typeof tldts) {
+  const isIcann = dynamicTldts.parse(email).isIcann
+  return !isIcann || COMMON_ERROR_PATTERN.test(email)
+}