diff --git a/rest-gen/rest-gen.cabal b/rest-gen/rest-gen.cabal index 8682f1b..c4cab69 100644 --- a/rest-gen/rest-gen.cabal +++ b/rest-gen/rest-gen.cabal @@ -46,6 +46,7 @@ library Rest.Gen.Base.Link Rest.Gen.Base.XML Rest.Gen.Utils + Rest.Gen.JSCompiler build-depends: base >= 4.5 && < 4.9 , Cabal >= 1.16 && < 1.23 @@ -71,6 +72,9 @@ library , uniplate >= 1.6.12 && < 1.7 , unordered-containers == 0.2.* , vector == 0.10.* + , HTTP <= 4000.2.16 + , network == 2.5.* + --Network isn't actually needed, but build will fail w/o it if impl(ghc < 7.8) build-depends: tagged >= 0.2 && < 0.9 diff --git a/rest-gen/src/Rest/Gen.hs b/rest-gen/src/Rest/Gen.hs index 61e70ac..e674472 100644 --- a/rest-gen/src/Rest/Gen.hs +++ b/rest-gen/src/Rest/Gen.hs @@ -20,6 +20,7 @@ import Rest.Gen.JavaScript (mkJsApi) import Rest.Gen.Ruby (mkRbApi) import Rest.Gen.Types import Rest.Gen.Utils +import Rest.Gen.JSCompiler generate :: Config -> String -> Api m -> [H.ModuleName] -> [H.ImportDecl] -> [(H.ModuleName, H.ModuleName)] -> IO () generate config name api sources imports rewrites = @@ -31,7 +32,7 @@ generate config name api sources imports rewrites = let context = DocsContext root ver (fromMaybe "./templates" (getSourceLocation config)) writeDocs context r loc exitSuccess - Just MakeJS -> mkJsApi (overModuleName (++ "Api") moduleName) (get apiPrivate config) ver r >>= toTarget config + Just MakeJS -> mkJsApi (overModuleName (++ "Api") moduleName) (get apiPrivate config) ver r >>= withCompiler (get compiler config)>>= toTarget config Just MakeRb -> mkRbApi (overModuleName (++ "Api") moduleName) (get apiPrivate config) ver r >>= toTarget config Just MakeHS -> do loc <- getTargetDir config "./client" diff --git a/rest-gen/src/Rest/Gen/Config.hs b/rest-gen/src/Rest/Gen/Config.hs index 6e6bc8b..6e9927f 100644 --- a/rest-gen/src/Rest/Gen/Config.hs +++ b/rest-gen/src/Rest/Gen/Config.hs @@ -12,7 +12,7 @@ module Rest.Gen.Config , target , apiVersion , apiPrivate - + , compiler , defaultConfig , parseLocation , options @@ -26,6 +26,7 @@ import Control.Category import Data.Label import System.Console.GetOpt import System.Environment (getArgs) +import Rest.Gen.JSCompiler data Action = MakeDocs String | MakeJS | MakeRb | MakeHS data Location = Default | Stream | Location String @@ -36,6 +37,7 @@ data Config = Config , _target :: Location , _apiVersion :: String , _apiPrivate :: Bool + , _compiler :: Maybe Compiler } mkLabels [''Config] @@ -47,12 +49,19 @@ defaultConfig = Config , _target = Default , _apiVersion = "latest" , _apiPrivate = True + , _compiler = Nothing } parseLocation :: String -> Location parseLocation "-" = Stream parseLocation s = Location s +parseCompiler:: String -> Maybe Compiler +parseCompiler "closure-simple" = Just ClosureSimple +parseCompiler "closure-advanced" = Just ClosureAdvanced +parseCompiler "whitespace" = Just ClosureWhitespace +parseCompiler _ = Nothing + options :: (a :-> Config) -> [OptDescr (a -> a)] options parent = [ Option ['d'] ["documentation"] (ReqArg (set (action . parent) . Just . MakeDocs) "URLROOT") "Generate API documentation, available under the provided URL root." @@ -63,6 +72,7 @@ options parent = , Option ['t'] ["target"] (ReqArg (set (target . parent) . parseLocation) "LOCATION") "The target location for generation." , Option ['v'] ["version"] (ReqArg (set (apiVersion . parent)) "VERSION") "The version of the API under generation. Default latest." , Option ['p'] ["hide-private"] (NoArg (set (apiPrivate . parent) False)) "Generate API for the public, hiding private resources. Not default." + , Option ['c'] ["compiler"] (ReqArg (set (compiler . parent) . parseCompiler) "COMPILER") "Choose a compiler for javascript. \nDefaults to None. \nOptions are closure-simple, closure-advanced, whitespace and command. \nHas no effect if not generating javascript api" ] configFromArgs :: String -> IO Config diff --git a/rest-gen/src/Rest/Gen/JSCompiler.hs b/rest-gen/src/Rest/Gen/JSCompiler.hs new file mode 100644 index 0000000..73e5a91 --- /dev/null +++ b/rest-gen/src/Rest/Gen/JSCompiler.hs @@ -0,0 +1,28 @@ +module Rest.Gen.JSCompiler (Compiler (..), withCompiler) where + +import qualified Network.HTTP as HTTP +import Network.URI (parseURI) +import Data.Maybe + +-- | Represents the Compiler options +data Compiler = ClosureWhitespace | ClosureSimple | ClosureAdvanced + +-- | Use a compiler. Returns code compiled under the compiler. +-- To be use after generation and before returning javascript code +withCompiler:: Maybe Compiler -> String -> IO String +withCompiler Nothing = return . id +withCompiler (Just compiler) = useCompiler compiler + +useCompiler:: Compiler -> String -> IO String +useCompiler ClosureSimple = closureCompile "SIMPLE_OPTIMIZATIONS" +useCompiler ClosureAdvanced = closureCompile "ADVANCED_OPTIMIZATIONS" +useCompiler ClosureWhitespace = closureCompile "WHITESPACE_ONLY" + + +closureCompile:: String -> String -> IO String +closureCompile compilationlevel code_str = HTTP.simpleHTTP mkPostRequest >>= HTTP.getResponseBody + where payload = HTTP.urlEncodeVars [("js_code",code_str), ("compilation_level",compilationlevel),("output_format","text"),("output_info","compiled_code")] + headers = [HTTP.mkHeader HTTP.HdrContentType "application/x-www-form-urlencoded", HTTP.mkHeader HTTP.HdrContentLength (show $ length payload)] + url = parseURI "http://www.closure-compiler.appspot.com/compile" + mkPostRequest = HTTP.Request {HTTP.rqURI = fromJust url, HTTP.rqMethod = HTTP.POST, HTTP.rqHeaders = headers, HTTP.rqBody = payload } +