git.iko.soy/typeable/servant
on master help sign in
no opinion on valid function names in servant-foreign
commitb59a62e01207ade90b4795e04ebad5476cf8a9ec authorDenis Redozubov <denis.redozubov@gmail.com> dateTue 22 Sep 2015, 13:17 (11 years ago) parent7ff9e52
8 files changed+63−65
servant-foreign/servant-foreign.cabal−2 servant-foreign/src/Servant/Foreign.hs+2−57 servant-js/servant-js.cabal+3 servant-js/src/Servant/JS/Angular.hs+1−1 servant-js/src/Servant/JS/Axios.hs+1−1 servant-js/src/Servant/JS/Internal.hs+54−2 servant-js/src/Servant/JS/JQuery.hs+1−1 servant-js/src/Servant/JS/Vanilla.hs+1−1
servant-foreign/servant-foreign.cabal−2
@@ -20,10 +20,8 @@ source-repository head
2020library
2121 exposed-modules: Servant.Foreign
2222 build-depends: base == 4.*
23− , charset
2423 , lens >= 4
2524 , servant >= 0.5
26− , text
2725 hs-source-dirs: src
2826 default-language: Haskell2010
2927 ghc-options: -Wall
servant-foreign/src/Servant/Foreign.hs+2−57
@@ -21,7 +21,6 @@ module Servant.Foreign
2121 , HeaderArg(..)
2222 , ArgType(..)
2323 , Req
24− , toValidFunctionName
2524 , captureArg
2625 , defReq
2726 , concatCase
@@ -48,12 +47,8 @@ import Control.Applicative
4847#endif
4948import Control.Lens hiding (List)
5049import Data.Char (toLower, toUpper)
51−import qualified Data.CharSet as Set
52−import qualified Data.CharSet.Unicode.Category as Set
5350import Data.List
54−import Data.Monoid
5551import Data.Proxy
56−import qualified Data.Text as T
5752import GHC.Exts (Constraint)
5853import GHC.TypeLits
5954import Servant.API
@@ -105,58 +100,8 @@ data HeaderArg = HeaderArg
105100 | ReplaceHeaderArg
106101 { headerArgName :: String
107102 , headerPattern :: String
108− } deriving (Eq)
109−
110−
111−-- |
112−instance Show HeaderArg where
113− show (HeaderArg n) = toValidFunctionName ("header" <> n)
114− show (ReplaceHeaderArg n p)
115− | pn `isPrefixOf` p = pv <> " + \"" <> rp <> "\""
116− | pn `isSuffixOf` p = "\"" <> rp <> "\" + " <> pv
117− | pn `isInfixOf` p = "\"" <> (replace pn ("\" + " <> pv <> " + \"") p)
118− <> "\""
119− | otherwise = p
120− where
121− pv = toValidFunctionName ("header" <> n)
122− pn = "{" <> n <> "}"
123− rp = replace pn "" p
124− -- Use replace method from Data.Text
125− replace old new = T.unpack .
126− T.replace (T.pack old) (T.pack new) .
127− T.pack
128−
129−-- | Attempts to reduce the function name provided to that allowed by @'Foreign'@.
130−--
131−-- Here we are making an assumption that js identifiers are common enough.
132−-- https://mathiasbynens.be/notes/javascript-identifiers
133−-- Couldn't work out how to handle zero-width characters.
134−-- TODO: compare it with other generated languages(such as ruby via lackey)
135−-- and generalize.
136−--
137−-- @TODO: specify better default function name, or throw error?
138−toValidFunctionName :: String -> String
139−toValidFunctionName (x:xs) = [setFirstChar x] <> filter remainder xs
140− where
141− setFirstChar c = if firstChar c
142− then c
143− else '_'
144− firstChar c = prefixOK c || any (Set.member c) firstLetterOK
145− remainder c = prefixOK c || any (Set.member c) remainderOK
146− -- Valid prefixes
147− prefixOK c = c `elem` ['$','_']
148− -- Unicode character sets
149− firstLetterOK = [ Set.lowercaseLetter
150− , Set.uppercaseLetter
151− , Set.titlecaseLetter
152− , Set.modifierLetter
153− , Set.otherLetter
154− , Set.letterNumber ]
155− remainderOK = firstLetterOK <> [ Set.nonSpacingMark
156− , Set.spacingCombiningMark
157− , Set.decimalNumber
158− , Set.connectorPunctuation ]
159−toValidFunctionName [] = "_"
103+ } deriving (Eq, Show)
104+
160105
161106type MatrixArg = QueryArg
162107
servant-js/servant-js.cabal+3
@@ -41,8 +41,10 @@ library
4141 Servant.JS.JQuery
4242 Servant.JS.Vanilla
4343 build-depends: base >=4.5 && <5
44+ , charset
4445 , lens >= 4
4546 , servant-foreign >= 0.1
47+ , text
4648 hs-source-dirs: src
4749 default-language: Haskell2010
4850 ghc-options: -Wall
@@ -82,4 +84,5 @@ test-suite spec
8284 , lens >= 4
8385 , servant
8486 , servant-js
87+ , text
8588 default-language: Haskell2010
servant-js/src/Servant/JS/Angular.hs+1−1
@@ -109,7 +109,7 @@ generateAngularJSWith ngOptions opts req = "\n" <>
109109 where headersStr = intercalate ", " $ map headerStr hs
110110 headerStr header = "\"" ++
111111 headerArgName header ++
112− "\": " ++ show header
112+ "\": " ++ toJSHeader header
113113
114114 namespace =
115115 if hasService
servant-js/src/Servant/JS/Axios.hs+1−1
@@ -104,7 +104,7 @@ generateAxiosJSWith aopts opts req = "\n" <>
104104 where headersStr = intercalate ", " $ map headerStr hs
105105 headerStr header = "\"" ++
106106 headerArgName header ++
107− "\": " ++ show header
107+ "\": " ++ toJSHeader header
108108
109109 namespace =
110110 if hasNoModule
servant-js/src/Servant/JS/Internal.hs+54−2
@@ -10,6 +10,8 @@ module Servant.JS.Internal
1010 , jsGParams
1111 , jsMParams
1212 , paramToStr
13+ , toValidFunctionName
14+ , toJSHeader
1315 -- re-exports
1416 , (:<|>)(..)
1517 , (:>)
@@ -29,8 +31,13 @@ module Servant.JS.Internal
2931 , Header
3032 ) where
3133
32−import Control.Lens hiding (List)
33−import Servant.Foreign
34+import Control.Lens hiding (List)
35+import qualified Data.CharSet as Set
36+import qualified Data.CharSet.Unicode.Category as Set
37+import Data.List
38+import Data.Monoid
39+import qualified Data.Text as T
40+import Servant.Foreign
3441
3542type AjaxReq = Req
3643
@@ -74,6 +81,51 @@ defCommonGeneratorOptions = CommonGeneratorOptions
7481 , urlPrefix = ""
7582 }
7683
84+-- | Attempts to reduce the function name provided to that allowed by @'Foreign'@.
85+--
86+-- https://mathiasbynens.be/notes/javascript-identifiers
87+-- Couldn't work out how to handle zero-width characters.
88+--
89+-- @TODO: specify better default function name, or throw error?
90+toValidFunctionName :: String -> String
91+toValidFunctionName (x:xs) = [setFirstChar x] <> filter remainder xs
92+ where
93+ setFirstChar c = if firstChar c then c else '_'
94+ firstChar c = prefixOK c || any (Set.member c) firstLetterOK
95+ remainder c = prefixOK c || any (Set.member c) remainderOK
96+ -- Valid prefixes
97+ prefixOK c = c `elem` ['$','_']
98+ -- Unicode character sets
99+ firstLetterOK = [ Set.lowercaseLetter
100+ , Set.uppercaseLetter
101+ , Set.titlecaseLetter
102+ , Set.modifierLetter
103+ , Set.otherLetter
104+ , Set.letterNumber ]
105+ remainderOK = firstLetterOK
106+ <> [ Set.nonSpacingMark
107+ , Set.spacingCombiningMark
108+ , Set.decimalNumber
109+ , Set.connectorPunctuation ]
110+toValidFunctionName [] = "_"
111+
112+toJSHeader :: HeaderArg -> String
113+toJSHeader (HeaderArg n) = toValidFunctionName ("header" <> n)
114+toJSHeader (ReplaceHeaderArg n p)
115+ | pn `isPrefixOf` p = pv <> " + \"" <> rp <> "\""
116+ | pn `isSuffixOf` p = "\"" <> rp <> "\" + " <> pv
117+ | pn `isInfixOf` p = "\"" <> (replace pn ("\" + " <> pv <> " + \"") p)
118+ <> "\""
119+ | otherwise = p
120+ where
121+ pv = toValidFunctionName ("header" <> n)
122+ pn = "{" <> n <> "}"
123+ rp = replace pn "" p
124+ -- Use replace method from Data.Text
125+ replace old new = T.unpack
126+ . T.replace (T.pack old) (T.pack new)
127+ . T.pack
128+
77129jsSegments :: [Segment] -> String
78130jsSegments [] = ""
79131jsSegments [x] = "/" ++ segmentToStr x False
servant-js/src/Servant/JS/JQuery.hs+1−1
@@ -72,7 +72,7 @@ generateJQueryJSWith opts req = "\n" <>
7272 where headersStr = intercalate ", " $ map headerStr hs
7373 headerStr header = "\"" ++
7474 headerArgName header ++
75− "\": " ++ show header
75+ "\": " ++ toJSHeader header
7676
7777 namespace = if null (moduleName opts)
7878 then "var "
servant-js/src/Servant/JS/Vanilla.hs+1−1
@@ -79,7 +79,7 @@ generateVanillaJSWith opts req = "\n" <>
7979 where headersStr = intercalate "\n" $ map headerStr hs
8080 headerStr header = " xhr.setRequestHeader(\"" ++
8181 headerArgName header ++
82− "\", " ++ show header ++ ");"
82+ "\", " ++ toJSHeader header ++ ");"
8383
8484 namespace = if null (moduleName opts)
8585 then "var "