packages feed

xstatic-th (empty) → 0.1.0

raw patch · 6 files changed

+223/−0 lines, 6 filesdep +SHAdep +basedep +bytestring

Dependencies added: SHA, base, bytestring, mime-types, tasty, tasty-hunit, template-haskell, text, xstatic, xstatic-th, zlib

Files

+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Changelog++## 0.1.0++- Initial release
+ LICENSE view
@@ -0,0 +1,29 @@+BSD 3-Clause License++Copyright (c) 2022, Tristan de Cacqueray+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++1. Redistributions of source code must retain the above copyright notice, this+   list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright notice,+   this list of conditions and the following disclaimer in the documentation+   and/or other materials provided with the distribution.++3. Neither the name of the copyright holder nor the names of its+   contributors may be used to endorse or promote products derived from+   this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ data/test.js view
@@ -0,0 +1,1 @@+true
+ src/XStatic/TH.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE DeriveLift #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE GeneralisedNewtypeDeriving #-}+{-# LANGUAGE ImportQualifiedPost #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TemplateHaskell #-}++{- | Create a 'XStaticFile' served as /\/my-file.txt/ or /\/xstatic\/my-file.txt/:++@+myFile :: XStaticFile+myFile = $(embedXStaticFile ".\/data\/my-file.txt")+@+-}+module XStatic.TH (+    embedXStaticFile,+    embedXStaticFileVersion,++    -- * re-export from "XStatic"+    XStaticFile,+) where++import Codec.Compression.GZip qualified as GZip+import Data.ByteString (ByteString)+import Data.ByteString qualified as BS+import Data.ByteString.Char8 (pack)+import Data.ByteString.Char8 qualified as BS8+import Data.Digest.Pure.SHA qualified as SHA+import Data.List qualified+import Data.Maybe (fromMaybe)+import Data.Text qualified as Text+import Data.Version (Version (..), showVersion)+import Language.Haskell.TH (Exp (AppE))+import Language.Haskell.TH qualified as TH+import Language.Haskell.TH.Syntax qualified as TH+import Network.Mime qualified as Mime+import XStatic (XStaticFile (..), isGzip)++doEmbedXStaticFile ::+    FilePath ->+    Maybe ByteString ->+    TH.Q TH.Exp+doEmbedXStaticFile fp etag = do+    buf <- TH.runIO (BS.readFile fp)+    contentE <- TH.lift (ensureCompress buf)+    nameE <- TH.lift clean_name+    mimeE <- TH.lift (Mime.defaultMimeLookup (Text.pack fp_without_gz))+    etagE <- TH.lift (fromMaybe (hashBuf buf) etag)++    mkXF <- [|XStaticFile|]+    pure $!+        mkXF+            `AppE` nameE+            `AppE` contentE+            `AppE` etagE+            `AppE` mimeE+  where+    hashBuf = pack . SHA.showDigest . SHA.sha1 . BS.fromStrict+    ensureCompress buf+        | isGzip buf = buf+        | otherwise = BS.toStrict (GZip.compress (BS.fromStrict buf))++    fp_without_gz = stripSuffix ".gz" fp+    clean_name =+        pack+            . mappend "/"+            . stripSuffix "index.html"+            . stripPrefix "data/"+            . dropWhile (\c -> c == '.' || c == '/')+            $ fp_without_gz+    stripSuffix :: String -> String -> String+    stripSuffix s n = reverse $ stripPrefix (reverse s) (reverse n)+    stripPrefix :: String -> String -> String+    stripPrefix p n = fromMaybe n (Data.List.stripPrefix p n)++{- | Embed a static file in its compressed form.++The following rules are applied to convert a local filepath to the expected request path:++  * /./, /\// and \"/data\//\" prefix are removed+  * \"/.gz/\" and \"/index.html/\" suffix are removed+-}+embedXStaticFile :: FilePath -> TH.Q TH.Exp+embedXStaticFile fp = doEmbedXStaticFile fp Nothing++-- | Same as 'embedXStaticFile', but using the provided 'Version' for the 'xfETag' value.+embedXStaticFileVersion :: FilePath -> Version -> TH.Q TH.Exp+embedXStaticFileVersion fp version = doEmbedXStaticFile fp (Just $ versionToEtag version)++versionToEtag :: Version -> ByteString+versionToEtag = mconcat . BS8.split '.' . pack . showVersion
+ test/Test.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE ImportQualifiedPost #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}++module Main (main) where++import Codec.Compression.GZip qualified as GZip+import Data.ByteString qualified as BS+import Test.Tasty+import Test.Tasty.HUnit++import Paths_xstatic_th (version)+import XStatic+import XStatic.TH++main :: IO ()+main = defaultMain $ do+    testGroup+        "xstatic-th"+        [ testCase "Test embedXStaticFileVersion" $ do+            let xf :: XStaticFile+                xf = $(embedXStaticFileVersion "./xstatic-th.cabal" version)++            xfPath xf @?= "/xstatic-th.cabal"+            isGzip (xfContent xf) @? "Uncompressed file"+            xfType xf @?= "application/octet-stream"+        , testCase "Test embedXStaticFile" $ do+            let xf :: XStaticFile+                xf = $(embedXStaticFile "./data/test.js")+            xfPath xf @?= "/test.js"+            xfETag xf @?= "724ba28f4a9a1b472057ff99511ed393a45552e1"+            xfType xf @?= "application/javascript"+            xfContent xf @?= BS.toStrict (GZip.compress "true\n")+        ]
+ xstatic-th.cabal view
@@ -0,0 +1,62 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.34.7.+--+-- see: https://github.com/sol/hpack++name:           xstatic-th+version:        0.1.0+synopsis:       Automatic generation of XStaticFile+description:    Automatic generation of XStaticFile.+category:       JavaScript+homepage:       https://github.com/TristanCacqueray/haskell-xstatic#readme+bug-reports:    https://github.com/TristanCacqueray/haskell-xstatic/issues+author:         Tristan Cacqueray+maintainer:     tdecacqu@redhat.com+license:        BSD3+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    CHANGELOG.md+    data/test.js++source-repository head+  type: git+  location: https://github.com/TristanCacqueray/haskell-xstatic++library+  exposed-modules:+      XStatic.TH+  other-modules:+      Paths_xstatic_th+  hs-source-dirs:+      src/+  ghc-options: -Weverything -Wno-implicit-prelude -Wno-missing-kind-signatures -Wno-missing-import-lists -Wno-missing-safe-haskell-mode -Wno-unsafe+  build-depends:+      SHA+    , base <5+    , bytestring >=0.11.2+    , mime-types+    , template-haskell+    , text+    , xstatic+    , zlib+  default-language: Haskell2010++test-suite spec+  type: exitcode-stdio-1.0+  main-is: Test.hs+  other-modules:+      Paths_xstatic_th+  hs-source-dirs:+      test+  ghc-options: -Weverything -Wno-implicit-prelude -Wno-missing-kind-signatures -Wno-missing-import-lists -Wno-missing-safe-haskell-mode -Wno-unsafe+  build-depends:+      base <5+    , bytestring+    , tasty+    , tasty-hunit+    , xstatic+    , xstatic-th+    , zlib+  default-language: Haskell2010