no opinion on valid function names in servant-foreign
This commit is contained in:
parent
7ff9e52a50
commit
b59a62e012
8 changed files with 62 additions and 64 deletions
|
@ -20,10 +20,8 @@ source-repository head
|
||||||
library
|
library
|
||||||
exposed-modules: Servant.Foreign
|
exposed-modules: Servant.Foreign
|
||||||
build-depends: base == 4.*
|
build-depends: base == 4.*
|
||||||
, charset
|
|
||||||
, lens >= 4
|
, lens >= 4
|
||||||
, servant >= 0.5
|
, servant >= 0.5
|
||||||
, text
|
|
||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
ghc-options: -Wall
|
ghc-options: -Wall
|
|
@ -21,7 +21,6 @@ module Servant.Foreign
|
||||||
, HeaderArg(..)
|
, HeaderArg(..)
|
||||||
, ArgType(..)
|
, ArgType(..)
|
||||||
, Req
|
, Req
|
||||||
, toValidFunctionName
|
|
||||||
, captureArg
|
, captureArg
|
||||||
, defReq
|
, defReq
|
||||||
, concatCase
|
, concatCase
|
||||||
|
@ -48,12 +47,8 @@ import Control.Applicative
|
||||||
#endif
|
#endif
|
||||||
import Control.Lens hiding (List)
|
import Control.Lens hiding (List)
|
||||||
import Data.Char (toLower, toUpper)
|
import Data.Char (toLower, toUpper)
|
||||||
import qualified Data.CharSet as Set
|
|
||||||
import qualified Data.CharSet.Unicode.Category as Set
|
|
||||||
import Data.List
|
import Data.List
|
||||||
import Data.Monoid
|
|
||||||
import Data.Proxy
|
import Data.Proxy
|
||||||
import qualified Data.Text as T
|
|
||||||
import GHC.Exts (Constraint)
|
import GHC.Exts (Constraint)
|
||||||
import GHC.TypeLits
|
import GHC.TypeLits
|
||||||
import Servant.API
|
import Servant.API
|
||||||
|
@ -105,59 +100,9 @@ data HeaderArg = HeaderArg
|
||||||
| ReplaceHeaderArg
|
| ReplaceHeaderArg
|
||||||
{ headerArgName :: String
|
{ headerArgName :: String
|
||||||
, headerPattern :: String
|
, headerPattern :: String
|
||||||
} deriving (Eq)
|
} deriving (Eq, Show)
|
||||||
|
|
||||||
|
|
||||||
-- |
|
|
||||||
instance Show HeaderArg where
|
|
||||||
show (HeaderArg n) = toValidFunctionName ("header" <> n)
|
|
||||||
show (ReplaceHeaderArg n p)
|
|
||||||
| pn `isPrefixOf` p = pv <> " + \"" <> rp <> "\""
|
|
||||||
| pn `isSuffixOf` p = "\"" <> rp <> "\" + " <> pv
|
|
||||||
| pn `isInfixOf` p = "\"" <> (replace pn ("\" + " <> pv <> " + \"") p)
|
|
||||||
<> "\""
|
|
||||||
| otherwise = p
|
|
||||||
where
|
|
||||||
pv = toValidFunctionName ("header" <> n)
|
|
||||||
pn = "{" <> n <> "}"
|
|
||||||
rp = replace pn "" p
|
|
||||||
-- Use replace method from Data.Text
|
|
||||||
replace old new = T.unpack .
|
|
||||||
T.replace (T.pack old) (T.pack new) .
|
|
||||||
T.pack
|
|
||||||
|
|
||||||
-- | Attempts to reduce the function name provided to that allowed by @'Foreign'@.
|
|
||||||
--
|
|
||||||
-- Here we are making an assumption that js identifiers are common enough.
|
|
||||||
-- https://mathiasbynens.be/notes/javascript-identifiers
|
|
||||||
-- Couldn't work out how to handle zero-width characters.
|
|
||||||
-- TODO: compare it with other generated languages(such as ruby via lackey)
|
|
||||||
-- and generalize.
|
|
||||||
--
|
|
||||||
-- @TODO: specify better default function name, or throw error?
|
|
||||||
toValidFunctionName :: String -> String
|
|
||||||
toValidFunctionName (x:xs) = [setFirstChar x] <> filter remainder xs
|
|
||||||
where
|
|
||||||
setFirstChar c = if firstChar c
|
|
||||||
then c
|
|
||||||
else '_'
|
|
||||||
firstChar c = prefixOK c || any (Set.member c) firstLetterOK
|
|
||||||
remainder c = prefixOK c || any (Set.member c) remainderOK
|
|
||||||
-- Valid prefixes
|
|
||||||
prefixOK c = c `elem` ['$','_']
|
|
||||||
-- Unicode character sets
|
|
||||||
firstLetterOK = [ Set.lowercaseLetter
|
|
||||||
, Set.uppercaseLetter
|
|
||||||
, Set.titlecaseLetter
|
|
||||||
, Set.modifierLetter
|
|
||||||
, Set.otherLetter
|
|
||||||
, Set.letterNumber ]
|
|
||||||
remainderOK = firstLetterOK <> [ Set.nonSpacingMark
|
|
||||||
, Set.spacingCombiningMark
|
|
||||||
, Set.decimalNumber
|
|
||||||
, Set.connectorPunctuation ]
|
|
||||||
toValidFunctionName [] = "_"
|
|
||||||
|
|
||||||
type MatrixArg = QueryArg
|
type MatrixArg = QueryArg
|
||||||
|
|
||||||
data Url = Url
|
data Url = Url
|
||||||
|
|
|
@ -41,8 +41,10 @@ library
|
||||||
Servant.JS.JQuery
|
Servant.JS.JQuery
|
||||||
Servant.JS.Vanilla
|
Servant.JS.Vanilla
|
||||||
build-depends: base >=4.5 && <5
|
build-depends: base >=4.5 && <5
|
||||||
|
, charset
|
||||||
, lens >= 4
|
, lens >= 4
|
||||||
, servant-foreign >= 0.1
|
, servant-foreign >= 0.1
|
||||||
|
, text
|
||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
ghc-options: -Wall
|
ghc-options: -Wall
|
||||||
|
@ -82,4 +84,5 @@ test-suite spec
|
||||||
, lens >= 4
|
, lens >= 4
|
||||||
, servant
|
, servant
|
||||||
, servant-js
|
, servant-js
|
||||||
|
, text
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
|
@ -109,7 +109,7 @@ generateAngularJSWith ngOptions opts req = "\n" <>
|
||||||
where headersStr = intercalate ", " $ map headerStr hs
|
where headersStr = intercalate ", " $ map headerStr hs
|
||||||
headerStr header = "\"" ++
|
headerStr header = "\"" ++
|
||||||
headerArgName header ++
|
headerArgName header ++
|
||||||
"\": " ++ show header
|
"\": " ++ toJSHeader header
|
||||||
|
|
||||||
namespace =
|
namespace =
|
||||||
if hasService
|
if hasService
|
||||||
|
|
|
@ -104,7 +104,7 @@ generateAxiosJSWith aopts opts req = "\n" <>
|
||||||
where headersStr = intercalate ", " $ map headerStr hs
|
where headersStr = intercalate ", " $ map headerStr hs
|
||||||
headerStr header = "\"" ++
|
headerStr header = "\"" ++
|
||||||
headerArgName header ++
|
headerArgName header ++
|
||||||
"\": " ++ show header
|
"\": " ++ toJSHeader header
|
||||||
|
|
||||||
namespace =
|
namespace =
|
||||||
if hasNoModule
|
if hasNoModule
|
||||||
|
|
|
@ -10,6 +10,8 @@ module Servant.JS.Internal
|
||||||
, jsGParams
|
, jsGParams
|
||||||
, jsMParams
|
, jsMParams
|
||||||
, paramToStr
|
, paramToStr
|
||||||
|
, toValidFunctionName
|
||||||
|
, toJSHeader
|
||||||
-- re-exports
|
-- re-exports
|
||||||
, (:<|>)(..)
|
, (:<|>)(..)
|
||||||
, (:>)
|
, (:>)
|
||||||
|
@ -30,6 +32,11 @@ module Servant.JS.Internal
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Lens hiding (List)
|
import Control.Lens hiding (List)
|
||||||
|
import qualified Data.CharSet as Set
|
||||||
|
import qualified Data.CharSet.Unicode.Category as Set
|
||||||
|
import Data.List
|
||||||
|
import Data.Monoid
|
||||||
|
import qualified Data.Text as T
|
||||||
import Servant.Foreign
|
import Servant.Foreign
|
||||||
|
|
||||||
type AjaxReq = Req
|
type AjaxReq = Req
|
||||||
|
@ -74,6 +81,51 @@ defCommonGeneratorOptions = CommonGeneratorOptions
|
||||||
, urlPrefix = ""
|
, urlPrefix = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- | Attempts to reduce the function name provided to that allowed by @'Foreign'@.
|
||||||
|
--
|
||||||
|
-- https://mathiasbynens.be/notes/javascript-identifiers
|
||||||
|
-- Couldn't work out how to handle zero-width characters.
|
||||||
|
--
|
||||||
|
-- @TODO: specify better default function name, or throw error?
|
||||||
|
toValidFunctionName :: String -> String
|
||||||
|
toValidFunctionName (x:xs) = [setFirstChar x] <> filter remainder xs
|
||||||
|
where
|
||||||
|
setFirstChar c = if firstChar c then c else '_'
|
||||||
|
firstChar c = prefixOK c || any (Set.member c) firstLetterOK
|
||||||
|
remainder c = prefixOK c || any (Set.member c) remainderOK
|
||||||
|
-- Valid prefixes
|
||||||
|
prefixOK c = c `elem` ['$','_']
|
||||||
|
-- Unicode character sets
|
||||||
|
firstLetterOK = [ Set.lowercaseLetter
|
||||||
|
, Set.uppercaseLetter
|
||||||
|
, Set.titlecaseLetter
|
||||||
|
, Set.modifierLetter
|
||||||
|
, Set.otherLetter
|
||||||
|
, Set.letterNumber ]
|
||||||
|
remainderOK = firstLetterOK
|
||||||
|
<> [ Set.nonSpacingMark
|
||||||
|
, Set.spacingCombiningMark
|
||||||
|
, Set.decimalNumber
|
||||||
|
, Set.connectorPunctuation ]
|
||||||
|
toValidFunctionName [] = "_"
|
||||||
|
|
||||||
|
toJSHeader :: HeaderArg -> String
|
||||||
|
toJSHeader (HeaderArg n) = toValidFunctionName ("header" <> n)
|
||||||
|
toJSHeader (ReplaceHeaderArg n p)
|
||||||
|
| pn `isPrefixOf` p = pv <> " + \"" <> rp <> "\""
|
||||||
|
| pn `isSuffixOf` p = "\"" <> rp <> "\" + " <> pv
|
||||||
|
| pn `isInfixOf` p = "\"" <> (replace pn ("\" + " <> pv <> " + \"") p)
|
||||||
|
<> "\""
|
||||||
|
| otherwise = p
|
||||||
|
where
|
||||||
|
pv = toValidFunctionName ("header" <> n)
|
||||||
|
pn = "{" <> n <> "}"
|
||||||
|
rp = replace pn "" p
|
||||||
|
-- Use replace method from Data.Text
|
||||||
|
replace old new = T.unpack
|
||||||
|
. T.replace (T.pack old) (T.pack new)
|
||||||
|
. T.pack
|
||||||
|
|
||||||
jsSegments :: [Segment] -> String
|
jsSegments :: [Segment] -> String
|
||||||
jsSegments [] = ""
|
jsSegments [] = ""
|
||||||
jsSegments [x] = "/" ++ segmentToStr x False
|
jsSegments [x] = "/" ++ segmentToStr x False
|
||||||
|
|
|
@ -72,7 +72,7 @@ generateJQueryJSWith opts req = "\n" <>
|
||||||
where headersStr = intercalate ", " $ map headerStr hs
|
where headersStr = intercalate ", " $ map headerStr hs
|
||||||
headerStr header = "\"" ++
|
headerStr header = "\"" ++
|
||||||
headerArgName header ++
|
headerArgName header ++
|
||||||
"\": " ++ show header
|
"\": " ++ toJSHeader header
|
||||||
|
|
||||||
namespace = if null (moduleName opts)
|
namespace = if null (moduleName opts)
|
||||||
then "var "
|
then "var "
|
||||||
|
|
|
@ -79,7 +79,7 @@ generateVanillaJSWith opts req = "\n" <>
|
||||||
where headersStr = intercalate "\n" $ map headerStr hs
|
where headersStr = intercalate "\n" $ map headerStr hs
|
||||||
headerStr header = " xhr.setRequestHeader(\"" ++
|
headerStr header = " xhr.setRequestHeader(\"" ++
|
||||||
headerArgName header ++
|
headerArgName header ++
|
||||||
"\", " ++ show header ++ ");"
|
"\", " ++ toJSHeader header ++ ");"
|
||||||
|
|
||||||
namespace = if null (moduleName opts)
|
namespace = if null (moduleName opts)
|
||||||
then "var "
|
then "var "
|
||||||
|
|
Loading…
Reference in a new issue