invalidChars :: Text -> [(Int, Text)]
invalidChars t = [(-1, "Can't be empty") | T.null t ]
                 ++ [(0, "Can't start with a dot")
                    | anyOf folded (=='.') (firstOf text t)]
                 ++ checkChars t
                 ++ [(T.length t - 1, "Can't end with a dot")
                    | anyOf folded (=='.') (lastOf text t)]
  where checkChars = flip evalState False . runApMonoid
                     . ifoldMapOf text (fmap ApMonoid . lookAtChar)
        lookAtChar :: Int -> Char -> State Bool [(Int, Text)]
        lookAtChar i ch = do
          let isDot = ch == '.'
          lastDot <- get
          put isDot
          return . map (i,) $
            ["Empty module path components aren't allowed" | lastDot && isDot]
            ++ ["Disallowed character: " <> pack [ch] | P.isPathSeparator ch]
            ++ ["Null characters aren't allowed" | '\NUL' == ch]
invalidChars :: Text -> [(Int, Text)]
invalidChars t = [(-1, "Can't be empty") | T.null t ]
                 ++ [(0, "Can't start with a dot")
                    | anyOf folded (=='.') (firstOf text t)]
                 ++ checkChars t
                 ++ [(T.length t - 1, "Can't end with a dot")
                    | anyOf folded (=='.') (lastOf text t)]
  where checkChars = flip evalState False . runApMonoid
                     . ifoldMapOf text (fmap ApMonoid . lookAtChar)
        lookAtChar :: Int -> Char -> State Bool [(Int, Text)]
        lookAtChar i ch = do
          let isDot = ch == '.'
          lastDot <- get
          put isDot
          return . map (i,) $
            ["Empty module path components aren't allowed" | lastDot && isDot]
            ++ ["Disallowed character: " <> pack [ch] | P.isPathSeparator ch]
            ++ ["Null characters aren't allowed" | '\NUL' == ch]
invalidChars t = [(-1, "Can't be empty") | T.null t ]
                 ++ [(0, "Can't start with a dot")
                    | anyOf folded (=='.') (firstOf text t)]
                 ++ checkChars t
                 ++ [(T.length t - 1, "Can't end with a dot")
                    | anyOf folded (=='.') (lastOf text t)]
  where checkChars = flip evalState False . runApMonoid
                     . ifoldMapOf text (fmap ApMonoid . lookAtChar)
        lookAtChar :: Int -> Char -> State Bool [(Int, Text)]
        lookAtChar i ch = do
          let isDot = ch == '.'
          lastDot <- get
          put isDot
          return . map (i,) $
            ["Empty module path components aren't allowed" | lastDot && isDot]
            ++ ["Disallowed character: " <> pack [ch] | P.isPathSeparator ch]
            ++ ["Null characters aren't allowed" | '\NUL' == ch]