{- |
Module      : Antelude.String.Case
Description : Contains some functions for handling cases for Strings.
Maintainer  : dneavesdev@pm.me
-}
module Antelude.String.Case
    ( Case (..)
      -- * String Deconstruction/Reconstruction
    , buildCase
    , identifyCase
    , recase
    , uncase
      -- * Simple Conversions
    , 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
    )

-- | Convert an entire 'String' to lower case. May be good for preprocessing an ambiguous-case string before 'recase'-ing, but results vary depending on the string.
lowerCase :: String -> String
lowerCase :: String -> String
lowerCase = (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
List.map Char -> Char
Char.toLower

-- | Convert an entire 'String' to SCREAMING CASE. May be good for preprocessing an ambiguous-case string before 'recase'-ing, but results vary depending on the string.
screamingCase :: String -> String
screamingCase :: String -> String
screamingCase = (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
List.map Char -> Char
Char.toUpper


-- | Convert an entire 'String' to Title case. Results may vary depending on the string.
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

{- |
A listing of all real and theoretical cases to convert from/to.

For reference:

- sentence cases use spaces like a regular sentence

- snake_cases_use_underscores_between_words

- hyphen-cases-use-hyphens-as-one-would-expect

- dot.cases.use.periods.maybe.useful.for.codegen

- forward\/path\/case\/uses\/forward\/slashes

- back\\path\\case\\uses\\back\\slashes

- camelCase and PascalCase look like these

-}
data Case
    -- sentence cases
    = LowerSentenceCase
    | UpperSentenceCase
    | ScreamingSentenceCase
    | TitleSentenceCase
    -- snake_cases
    | LowerSnakeCase
    | UpperSnakeCase
    | ScreamingSnakeCase
    -- hyphen-cases
    | LowerHyphenCase
    | UpperHyphenCase
    | ScreamingHyphenCase
    -- dot.cases
    | LowerDotCase
    | UpperDotCase
    | ScreamingDotCase
    -- forward/path/case
    | LowerForwardPathCase
    | UpperForwardPathCase
    | ScreamingForwardPathCase
    -- back\path\case
    | LowerBackPathCase
    | UpperBackPathCase
    | ScreamingBackPathCase
    -- camelCases
    | 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)


-- | Identify the 'Case' the 'String' is using
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
        -- Checks indefinitely from here-on
        | (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
    -- Specialies
    | Title
    | Pascal
    | Camel


-- | Construct a 'String' of a desired 'Case' from a 'List' of parts
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
                -- while "titleCase" may look odd here, remember that it's _each word_ being Title-ed
                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
                -- every part of a PascalCase is technically Title-ed
                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
                        -- the tail of a camelCase is technically Title-ed
                        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

{- | Deconstruct a 'String' by identifying its 'Case'.
    Returns a 'Maybe', in case the case could not be identified.
-}
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

{- | Given a desired 'Case' and a 'String', try and convert to the given 'Case'.
    Returns a 'Maybe', in case the original case could not be identified.
-}
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)