module Antelude.String.Case
( Case (..)
, buildCase
, identifyCase
, recase
, uncase
, lowerCase
, screamingCase
, titleCase
) where
import safe Antelude.Bool ( and, otherwise )
import safe qualified Antelude.Bool as Bool ( all )
import safe Antelude.Function ( (.>), (|>) )
import safe Antelude.Internal.TypesClasses
( Bool (..)
, Char
, Eq
, List
, Maybe (..)
, Ord ((>))
, Show
, String
, (<>)
)
import safe qualified Antelude.List as List
import safe qualified Antelude.Maybe as Maybe ( map )
import safe qualified Antelude.String as String
import safe qualified Antelude.Tuple.Pair as Pair ( first )
import safe qualified Data.Char as Char
( isAlpha
, isAlphaNum
, isLowerCase
, isUpperCase
, toLower
, toUpper
)
lowerCase :: String -> String
lowerCase :: String -> String
lowerCase = (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
List.map Char -> Char
Char.toLower
screamingCase :: String -> String
screamingCase :: String -> String
screamingCase = (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
List.map Char -> Char
Char.toUpper
titleCase :: String -> String
titleCase :: String -> String
titleCase String
string =
String -> Maybe (Char, String)
forall a. [a] -> Maybe (a, [a])
List.uncons String
string
Maybe (Char, String) -> (Maybe (Char, String) -> String) -> String
forall a b. a -> (a -> b) -> b
|> \case
Just (Char
head, String
tail) ->
[Char -> Char
Char.toUpper Char
head] String -> String -> String
forall a. Semigroup a => a -> a -> a
<> (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
List.map Char -> Char
Char.toLower String
tail
Maybe (Char, String)
Nothing ->
String
string
data Case
= LowerSentenceCase
| UpperSentenceCase
| ScreamingSentenceCase
| TitleSentenceCase
| LowerSnakeCase
| UpperSnakeCase
| ScreamingSnakeCase
| LowerHyphenCase
| UpperHyphenCase
| ScreamingHyphenCase
| LowerDotCase
| UpperDotCase
| ScreamingDotCase
| LowerForwardPathCase
| UpperForwardPathCase
| ScreamingForwardPathCase
| LowerBackPathCase
| UpperBackPathCase
| ScreamingBackPathCase
| CamelCase
| PascalCase
deriving (Case -> Case -> Bool
(Case -> Case -> Bool) -> (Case -> Case -> Bool) -> Eq Case
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Case -> Case -> Bool
== :: Case -> Case -> Bool
$c/= :: Case -> Case -> Bool
/= :: Case -> Case -> Bool
Eq, Int -> Case -> String -> String
[Case] -> String -> String
Case -> String
(Int -> Case -> String -> String)
-> (Case -> String) -> ([Case] -> String -> String) -> Show Case
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: Int -> Case -> String -> String
showsPrec :: Int -> Case -> String -> String
$cshow :: Case -> String
show :: Case -> String
$cshowList :: [Case] -> String -> String
showList :: [Case] -> String -> String
Show)
identifyCase :: String -> Maybe Case
identifyCase :: String -> Maybe Case
identifyCase String
string =
let checkSingleCase :: (Char -> Bool) -> String -> String -> Bool
checkSingleCase :: (Char -> Bool) -> String -> String -> Bool
checkSingleCase Char -> Bool
func String
sep String
str =
String -> String -> Bool
String.contains String
sep String
str
Bool -> Bool -> Bool
`and`
( String -> String -> List String
String.split String
sep String
str
List String -> (List String -> [Bool]) -> [Bool]
forall a b. a -> (a -> b) -> b
|> (String -> Bool) -> List String -> [Bool]
forall a b. (a -> b) -> [a] -> [b]
List.map
( (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
List.filter Char -> Bool
Char.isAlpha
(String -> String) -> (String -> Bool) -> String -> Bool
forall a b c. (a -> b) -> (b -> c) -> a -> c
.> (Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
List.all Char -> Bool
func
)
[Bool] -> ([Bool] -> Bool) -> Bool
forall a b. a -> (a -> b) -> b
|> [Bool] -> Bool
Bool.all
)
checkCapitalCase :: String -> String -> Bool
checkCapitalCase :: String -> String -> Bool
checkCapitalCase String
sep String
str =
String -> String -> Bool
String.contains String
sep String
str
Bool -> Bool -> Bool
`and`
( String -> String -> List String
String.split String
sep String
str
List String -> (List String -> List String) -> List String
forall a b. a -> (a -> b) -> b
|> (String -> Bool) -> List String -> List String
forall a. (a -> Bool) -> [a] -> [a]
List.filter (\String
s -> String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
List.length String
s Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0)
List String -> (List String -> [Bool]) -> [Bool]
forall a b. a -> (a -> b) -> b
|> (String -> Bool) -> List String -> [Bool]
forall a b. (a -> b) -> [a] -> [b]
List.map
( (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
List.filter Char -> Bool
Char.isAlpha
(String -> String) -> (String -> Bool) -> String -> Bool
forall a b c. (a -> b) -> (b -> c) -> a -> c
.> String -> Maybe (Char, String)
forall a. [a] -> Maybe (a, [a])
List.uncons
(String -> Maybe (Char, String))
-> (Maybe (Char, String) -> Bool) -> String -> Bool
forall a b c. (a -> b) -> (b -> c) -> a -> c
.> \case
Just (Char
head, String
tail) ->
Char -> Bool
Char.isUpperCase Char
head
Bool -> Bool -> Bool
`and`
((Char -> Bool) -> String -> [Bool]
forall a b. (a -> b) -> [a] -> [b]
List.map Char -> Bool
Char.isLowerCase (String -> [Bool]) -> ([Bool] -> Bool) -> String -> Bool
forall a b c. (a -> b) -> (b -> c) -> a -> c
.> [Bool] -> Bool
Bool.all) String
tail
Maybe (Char, String)
Nothing ->
Bool
True
)
[Bool] -> ([Bool] -> Bool) -> Bool
forall a b. a -> (a -> b) -> b
|> [Bool] -> Bool
Bool.all
)
checkTitleCase :: String -> String -> Bool
checkTitleCase :: String -> String -> Bool
checkTitleCase String
sep String
str =
String -> String -> Bool
String.contains String
sep String
str
Bool -> Bool -> Bool
`and`
( String -> Maybe Char
forall a. List a -> Maybe a
List.head String
str
Maybe Char -> (Maybe Char -> Bool) -> Bool
forall a b. a -> (a -> b) -> b
|> \case
Just Char
head ->
Char -> Bool
Char.isUpperCase Char
head
Maybe Char
Nothing ->
Bool
True
)
in
if | (Char -> Bool) -> String -> String -> Bool
checkSingleCase Char -> Bool
Char.isUpperCase String
" " String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
ScreamingSentenceCase
| String -> String -> Bool
checkCapitalCase String
" " String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
UpperSentenceCase
| (Char -> Bool) -> String -> String -> Bool
checkSingleCase Char -> Bool
Char.isLowerCase String
" " String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
LowerSentenceCase
| String -> String -> Bool
checkTitleCase String
" " String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
TitleSentenceCase
| (Char -> Bool) -> String -> String -> Bool
checkSingleCase Char -> Bool
Char.isUpperCase String
"-" String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
ScreamingHyphenCase
| String -> String -> Bool
checkCapitalCase String
"-" String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
UpperHyphenCase
| (Char -> Bool) -> String -> String -> Bool
checkSingleCase Char -> Bool
Char.isLowerCase String
"-" String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
LowerHyphenCase
| (Char -> Bool) -> String -> String -> Bool
checkSingleCase Char -> Bool
Char.isUpperCase String
"_" String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
ScreamingSnakeCase
| String -> String -> Bool
checkCapitalCase String
"_" String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
UpperSnakeCase
| (Char -> Bool) -> String -> String -> Bool
checkSingleCase Char -> Bool
Char.isLowerCase String
"_" String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
LowerSnakeCase
| (Char -> Bool) -> String -> String -> Bool
checkSingleCase Char -> Bool
Char.isUpperCase String
"." String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
ScreamingDotCase
| String -> String -> Bool
checkCapitalCase String
"." String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
UpperDotCase
| (Char -> Bool) -> String -> String -> Bool
checkSingleCase Char -> Bool
Char.isLowerCase String
"." String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
LowerDotCase
| (Char -> Bool) -> String -> String -> Bool
checkSingleCase Char -> Bool
Char.isUpperCase String
"/" String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
ScreamingForwardPathCase
| String -> String -> Bool
checkCapitalCase String
"/" String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
UpperForwardPathCase
| (Char -> Bool) -> String -> String -> Bool
checkSingleCase Char -> Bool
Char.isLowerCase String
"/" String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
LowerForwardPathCase
| (Char -> Bool) -> String -> String -> Bool
checkSingleCase Char -> Bool
Char.isUpperCase String
"\\" String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
ScreamingBackPathCase
| String -> String -> Bool
checkCapitalCase String
"\\" String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
UpperBackPathCase
| (Char -> Bool) -> String -> String -> Bool
checkSingleCase Char -> Bool
Char.isLowerCase String
"\\" String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
LowerBackPathCase
| (Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
List.all Char -> Bool
Char.isAlphaNum String
string
Bool -> Bool -> Bool
`and`
( String -> Maybe Char
forall a. List a -> Maybe a
List.head
(String -> Maybe Char) -> (Maybe Char -> Bool) -> String -> Bool
forall a b c. (a -> b) -> (b -> c) -> a -> c
.> \case
Just Char
head -> Char -> Bool
Char.isLowerCase Char
head
Maybe Char
Nothing -> Bool
False
) String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
CamelCase
| (Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
List.all Char -> Bool
Char.isAlphaNum String
string
Bool -> Bool -> Bool
`and`
( String -> Maybe Char
forall a. List a -> Maybe a
List.head
(String -> Maybe Char) -> (Maybe Char -> Bool) -> String -> Bool
forall a b c. (a -> b) -> (b -> c) -> a -> c
.> \case
Just Char
head -> Char -> Bool
Char.isUpperCase Char
head
Maybe Char
Nothing -> Bool
False
) String
string
-> Case -> Maybe Case
forall a. a -> Maybe a
Just Case
PascalCase
| Bool
otherwise -> Maybe Case
forall a. Maybe a
Nothing
data Format
= Upper
| Lower
| Screaming
| Title
| Pascal
| Camel
buildCase :: Case -> List String -> String
buildCase :: Case -> List String -> String
buildCase Case
destinationCase List String
parts =
let joiner :: String
joiner :: String
joiner =
case Case
destinationCase of
Case
LowerSnakeCase ->
String
"_"
Case
UpperSnakeCase ->
String
"_"
Case
ScreamingSnakeCase ->
String
"_"
Case
LowerHyphenCase ->
String
"-"
Case
UpperHyphenCase ->
String
"-"
Case
ScreamingHyphenCase ->
String
"-"
Case
LowerSentenceCase ->
String
" "
Case
UpperSentenceCase ->
String
" "
Case
ScreamingSentenceCase ->
String
" "
Case
TitleSentenceCase ->
String
" "
Case
LowerDotCase ->
String
"."
Case
UpperDotCase ->
String
"."
Case
ScreamingDotCase ->
String
"."
Case
LowerForwardPathCase ->
String
"/"
Case
UpperForwardPathCase ->
String
"/"
Case
ScreamingForwardPathCase ->
String
"/"
Case
LowerBackPathCase ->
String
"\\"
Case
UpperBackPathCase ->
String
"\\"
Case
ScreamingBackPathCase ->
String
"\\"
Case
CamelCase ->
String
""
Case
PascalCase ->
String
""
format :: Format
format :: Format
format =
case Case
destinationCase of
Case
LowerSnakeCase ->
Format
Lower
Case
UpperSnakeCase ->
Format
Upper
Case
ScreamingSnakeCase ->
Format
Screaming
Case
LowerHyphenCase ->
Format
Lower
Case
UpperHyphenCase ->
Format
Upper
Case
ScreamingHyphenCase ->
Format
Screaming
Case
LowerSentenceCase ->
Format
Lower
Case
UpperSentenceCase ->
Format
Upper
Case
ScreamingSentenceCase ->
Format
Screaming
Case
TitleSentenceCase ->
Format
Title
Case
LowerDotCase ->
Format
Lower
Case
UpperDotCase ->
Format
Upper
Case
ScreamingDotCase ->
Format
Screaming
Case
LowerForwardPathCase ->
Format
Lower
Case
UpperForwardPathCase ->
Format
Upper
Case
ScreamingForwardPathCase ->
Format
Screaming
Case
LowerBackPathCase ->
Format
Lower
Case
UpperBackPathCase ->
Format
Upper
Case
ScreamingBackPathCase ->
Format
Screaming
Case
CamelCase ->
Format
Camel
Case
PascalCase ->
Format
Pascal
in
case Format
format of
Format
Upper ->
(String -> String) -> List String -> List String
forall a b. (a -> b) -> [a] -> [b]
List.map
String -> String
titleCase
List String
parts
List String -> (List String -> String) -> String
forall a b. a -> (a -> b) -> b
|> String -> List String -> String
String.joinWith String
joiner
Format
Lower ->
(String -> String) -> List String -> List String
forall a b. (a -> b) -> [a] -> [b]
List.map
String -> String
lowerCase
List String
parts
List String -> (List String -> String) -> String
forall a b. a -> (a -> b) -> b
|> String -> List String -> String
String.joinWith String
joiner
Format
Screaming ->
(String -> String) -> List String -> List String
forall a b. (a -> b) -> [a] -> [b]
List.map
String -> String
screamingCase
List String
parts
List String -> (List String -> String) -> String
forall a b. a -> (a -> b) -> b
|> String -> List String -> String
String.joinWith String
joiner
Format
Title ->
List String -> Maybe (String, List String)
forall a. [a] -> Maybe (a, [a])
List.uncons List String
parts
Maybe (String, List String)
-> (Maybe (String, List String) -> List String) -> List String
forall a b. a -> (a -> b) -> b
|> \case
Just (String
frst, List String
rest) ->
[ String -> String
titleCase String
frst
]
List String -> List String -> List String
forall a. Semigroup a => a -> a -> a
<> (String -> String) -> List String -> List String
forall a b. (a -> b) -> [a] -> [b]
List.map
String -> String
lowerCase
List String
rest
Maybe (String, List String)
Nothing ->
[String
""]
List String -> (List String -> String) -> String
forall a b. a -> (a -> b) -> b
|> String -> List String -> String
String.joinWith String
joiner
Format
Pascal ->
(String -> String) -> List String -> List String
forall a b. (a -> b) -> [a] -> [b]
List.map
String -> String
titleCase
List String
parts
List String -> (List String -> String) -> String
forall a b. a -> (a -> b) -> b
|> String -> List String -> String
String.joinWith String
joiner
Format
Camel ->
List String -> Maybe (String, List String)
forall a. [a] -> Maybe (a, [a])
List.uncons List String
parts
Maybe (String, List String)
-> (Maybe (String, List String) -> List String) -> List String
forall a b. a -> (a -> b) -> b
|> \case
Just (String
frst, List String
rest) ->
[ String -> String
lowerCase String
frst
]
List String -> List String -> List String
forall a. Semigroup a => a -> a -> a
<> (String -> String) -> List String -> List String
forall a b. (a -> b) -> [a] -> [b]
List.map
String -> String
titleCase
List String
rest
Maybe (String, List String)
Nothing ->
[String
""]
List String -> (List String -> String) -> String
forall a b. a -> (a -> b) -> b
|> String -> List String -> String
String.joinWith String
joiner
uncase :: String -> Maybe (List String)
uncase :: String -> Maybe (List String)
uncase String
string =
let oldCase :: Maybe Case
oldCase :: Maybe Case
oldCase = String -> Maybe Case
identifyCase String
string
folderFunc :: (List String, String) -> (List String, String)
folderFunc :: (List String, String) -> (List String, String)
folderFunc (List String
accm, []) = (List String
accm, [])
folderFunc (List String
accm, String
str) =
let getStr :: String
getStr :: String
getStr =
Int -> String -> String
forall a. Int -> [a] -> [a]
List.take Int
1 String
str
String -> String -> String
forall a. Semigroup a => a -> a -> a
<> ( Int -> String -> String
forall a. Int -> [a] -> [a]
List.drop Int
1 String
str
String -> (String -> String) -> String
forall a b. a -> (a -> b) -> b
|> (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
List.takeWhile Char -> Bool
Char.isLowerCase
)
in (List String, String) -> (List String, String)
folderFunc (List String
accm List String -> List String -> List String
forall a. Semigroup a => a -> a -> a
<> [String
getStr], Int -> String -> String
forall a. Int -> [a] -> [a]
List.drop (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
List.length String
getStr) String
str)
pascalCamelFolder :: String -> List String
pascalCamelFolder :: String -> List String
pascalCamelFolder String
str =
(List String, String) -> (List String, String)
folderFunc ([], String
str)
(List String, String)
-> ((List String, String) -> List String) -> List String
forall a b. a -> (a -> b) -> b
|> (List String, String) -> List String
forall a b. Pair a b -> a
Pair.first
in
(Case -> List String) -> Maybe Case -> Maybe (List String)
forall a b. (a -> b) -> Maybe a -> Maybe b
Maybe.map
(\case
Case
LowerSnakeCase ->
String -> String -> List String
String.split String
"_" String
string
Case
UpperSnakeCase ->
String -> String -> List String
String.split String
"_" String
string
Case
ScreamingSnakeCase ->
String -> String -> List String
String.split String
"_" String
string
Case
LowerHyphenCase ->
String -> String -> List String
String.split String
"-" String
string
Case
UpperHyphenCase ->
String -> String -> List String
String.split String
"-" String
string
Case
ScreamingHyphenCase ->
String -> String -> List String
String.split String
"-" String
string
Case
LowerSentenceCase ->
String -> String -> List String
String.split String
" " String
string
Case
UpperSentenceCase ->
String -> String -> List String
String.split String
" " String
string
Case
ScreamingSentenceCase ->
String -> String -> List String
String.split String
" " String
string
Case
TitleSentenceCase ->
String -> String -> List String
String.split String
" " String
string
Case
LowerDotCase ->
String -> String -> List String
String.split String
"." String
string
Case
UpperDotCase ->
String -> String -> List String
String.split String
"." String
string
Case
ScreamingDotCase ->
String -> String -> List String
String.split String
"." String
string
Case
LowerForwardPathCase ->
String -> String -> List String
String.split String
"/" String
string
Case
UpperForwardPathCase ->
String -> String -> List String
String.split String
"/" String
string
Case
ScreamingForwardPathCase ->
String -> String -> List String
String.split String
"/" String
string
Case
LowerBackPathCase ->
String -> String -> List String
String.split String
"\\" String
string
Case
UpperBackPathCase ->
String -> String -> List String
String.split String
"\\" String
string
Case
ScreamingBackPathCase ->
String -> String -> List String
String.split String
"\\" String
string
Case
CamelCase ->
let firstWord :: String
firstWord :: String
firstWord =
(Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
List.takeWhile Char -> Bool
Char.isLowerCase String
string
restOfWords :: List String
restOfWords :: List String
restOfWords =
String
string
String -> (String -> String) -> String
forall a b. a -> (a -> b) -> b
|> Int -> String -> String
forall a. Int -> [a] -> [a]
List.drop (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
List.length String
firstWord)
String -> (String -> List String) -> List String
forall a b. a -> (a -> b) -> b
|> String -> List String
pascalCamelFolder
in
[String
firstWord] List String -> List String -> List String
forall a. Semigroup a => a -> a -> a
<> List String
restOfWords
Case
PascalCase ->
String -> List String
pascalCamelFolder String
string
)
Maybe Case
oldCase
recase :: Case -> String -> Maybe String
recase :: Case -> String -> Maybe String
recase Case
destinationCase String
string =
String -> Maybe (List String)
uncase String
string
Maybe (List String)
-> (Maybe (List String) -> Maybe String) -> Maybe String
forall a b. a -> (a -> b) -> b
|> (List String -> String) -> Maybe (List String) -> Maybe String
forall a b. (a -> b) -> Maybe a -> Maybe b
Maybe.map (Case -> List String -> String
buildCase Case
destinationCase)