packages feed

shomei-core-0.2.0.0: src/Shomei/Account/Email/Domain.hs

-- | Normalized email addresses.
--
-- The raw 'Email' constructor is not exported: the only way to build one is 'mkEmail',
-- which trims whitespace, lowercases the address, and rejects malformed input. This
-- makes invalid emails unrepresentable outside this module.
module Shomei.Account.Email.Domain
  ( Email,
    mkEmail,
    emailText,
  )
where

import Data.Text qualified as Text
import Shomei.Error (AuthError (..))
import Shomei.Prelude

newtype Email = Email Text
  deriving stock (Generic)
  deriving newtype (Eq, Ord, Show, FromJSON, ToJSON)

emailText :: Email -> Text
emailText (Email t) = t

-- | Trim whitespace; lowercase the whole address (initial impl); reject invalid shape.
-- Does NOT collapse gmail dots or plus-addressing.
mkEmail :: Text -> Either AuthError Email
mkEmail raw =
  let t = Text.toLower (Text.strip raw)
   in if isValidShape t then Right (Email t) else Left InvalidEmail
  where
    isValidShape t = case Text.splitOn "@" t of
      [local, domain] ->
        not (Text.null local)
          && not (Text.null domain)
          && Text.isInfixOf "." domain
          && not (Text.isInfixOf " " t)
      _ -> False