packages feed

hakyll-typescript (empty) → 0.0.1.0

raw patch · 12 files changed

+515/−0 lines, 12 filesdep +basedep +bytestringdep +directorysetup-changed

Dependencies added: base, bytestring, directory, hakyll, hakyll-typescript, hjsmin, tasty, tasty-hunit, typed-process

Files

+ CHANGELOG.md view
@@ -0,0 +1,16 @@+# Changelog++All notable changes to this project will be documented here.++The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),+and this project adheres to [Haskell Package Versioning Policy](https://pvp.haskell.org/).++## [0.1.0] - 2019-09-29+### Added++- Initial Hakyll compilers for typescript and javascript.+  - Supports passing arbitrary arguments to the typescript compiler+  - Provides various helper compilers that pass commonly used typescript arguments+  - Supports minification of javascript source as a compiler+  - Provides helper compilers to compile typescript source to minified javascript.+
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Jim McStanton (c) 2019++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * 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.++    * Neither the name of Jim McStanton nor the names of other+      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+OWNER 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.
+ README.md view
@@ -0,0 +1,37 @@+# hakyll-typescript++A simple [`hakyll`](http://hackage.haskell.org/package/hakyll)+typescript compiler for typescript and javascript resources. Uses+[`hjsmin`](http://hackage.haskell.org/package/hjsmin) for compression.++Assumes that the typescript compiler is installed and available to the+user running `hakyll`.++## Example Usage++In your hakyll site simply import the compiler you are interested in using+and provide it as the compiler for your relevant script files.++```haskell+import Hakyll.Typescript.TS++main = hakyll $ do+  -- Matches any file inside a the directory ./scripts+  match "scripts/**" $ do+    route   $ setExtension "js"+    -- compiles all typescript and javascript to the js target+    -- then compresses the result+    compile compressJtsCompiler+```++See the documentation for other available compilers.++## Build the Source++This project uses `stack`. Clone the project, then run `stack build` from the root.++## Build the Docs++For whatever reason `stack haddock` fails to pull down some necessary packages.+To build the docs run `stack exec haddock --  --html --hoogle --html-location=../$pkg-$version/ --hyperlinked-source --quickjump src/**/*.hs  -o doc`. The index+will be found in `./doc/`.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ hakyll-typescript.cabal view
@@ -0,0 +1,51 @@+name:                hakyll-typescript+version:             0.0.1.0+synopsis:            Typescript and javascript hakyll compilers.+description:         Provides typescript to javascript hakyll compilers and a+                     js minifying hakyll compiler. This is a simple wrapper+                     around other common utilities found in hakyll projects,+                     particularly `hjsmin`. +homepage:            https://github.com/jhmcstanton/hakyll-typescript#readme+license:             BSD3+license-file:        LICENSE+author:              Jim McStanton+maintainer:          jim@jhmcstanton.com+copyright:           2019 Jim McStanton+category:            web+build-type:          Simple+extra-source-files:  README.md+cabal-version:       >=1.10+extra-source-files:  CHANGELOG.md++library+  ghc-options:         -Wall+  hs-source-dirs:      src+  exposed-modules:     Hakyll.Typescript.JS+                     , Hakyll.Typescript.TS+  other-modules:       Hakyll.Typescript.Internal+  build-depends:       base          >= 4.7      && < 5+                     , bytestring    >= 0.10.8.2 && < 0.11+                     , hakyll        >= 4.12.4.0 && < 4.13+                     , hjsmin        >= 0.2.0.2  && < 0.3 +                     , typed-process >= 0.2.3.0  && < 0.3+  default-language:    Haskell2010++test-suite test-hakyll-typescript+  ghc-options:         -Wall+  type:                exitcode-stdio-1.0+  hs-source-dirs:      tests+  main-is:             TestSuite.hs+  other-modules:       Hakyll.Typescript.TestResources+                     , Hakyll.Typescript.JS.Tests+                     , Hakyll.Typescript.TS.Tests+  build-depends:       base          >= 4.7      && < 5+                     , directory     >= 1.3.1.5  && < 1.4+                     , hakyll        >= 4.12.4.0 && < 4.13+                     , hakyll-typescript+                     , tasty         >= 1.1.0.4  && < 1.2+                     , tasty-hunit   >= 0.10.0.1 && < 0.11+  default-language:    Haskell2010++source-repository head+  type:     git+  location: https://github.com/jhmcstanton/hakyll-typescript
+ src/Hakyll/Typescript/Internal.hs view
@@ -0,0 +1,18 @@+-- |Internal helper utilities. Subject to change. Avoid relying on anything+-- found in here.+module Hakyll.Typescript.Internal+  (+    minifyJs,+    withMinifyJs+  )+  where++import           Data.ByteString.Lazy (ByteString)+import           Hakyll (withItemBody, Compiler, Item)+import           Text.Jasmine++minifyJs :: ByteString -> Compiler ByteString+minifyJs = pure . minify++withMinifyJs :: Compiler (Item ByteString) -> Compiler (Item ByteString)+withMinifyJs m = m >>= withItemBody minifyJs
+ src/Hakyll/Typescript/JS.hs view
@@ -0,0 +1,17 @@+-- |Exports 'compressJsCompiler', which simply minifies+-- javascript files (but not typescript). This is strictly less+-- general than the functions found in "Hakyll.Typescript.TS", but+-- is useful when you want to skip over running the typescript compiler.+module Hakyll.Typescript.JS+  (+    compressJsCompiler+  )+  where++import           Data.ByteString.Lazy+import           Hakyll.Typescript.Internal+import           Hakyll++-- |Minifies the javascript 'Hakyll.Core.Item.Item'.+compressJsCompiler :: Compiler (Item ByteString)+compressJsCompiler = withMinifyJs getResourceLBS
+ src/Hakyll/Typescript/TS.hs view
@@ -0,0 +1,96 @@+-- |Compilers for compiling and compressing typescript resources.+-- There are various helper compilers for common compilation cases.+-- In particular, 'compressJtsCompiler' will compile both typescript+-- and javascript files, then compress them.+--+-- There are other variations that may be useful as well. 'compressTsCompiler'+-- is similar to 'compressJtsCompiler', but is more strict and will not accept+-- arbitrary javascript. 'compressTsCompilerWith' is the most general combinator,+-- using this you can pass arbitrary arguments to the typescript compiler prior+-- to compilation. These results are then minified as well.+--+-- Finally, if you just want to compile typescript without minification, perhaps+-- for readability, use any of the functions that are not prefixed with "compress".+-- Again, here 'tsCompilerWith' is the most general, allowing additional compiler+-- arguments to be passed prior to compilation. 'jtsCompiler' is provided for+-- convenience to support flexibly compiling javascript and typescript without+-- compression.+module Hakyll.Typescript.TS+  (+    compressJtsCompiler,+    compressJtsCompilerWith,+    compressTsCompiler,+    compressTsCompilerWith,+    jtsCompiler,+    jtsCompilerWith,+    tsCompiler,+    tsCompilerWith,+    TSArgs+  )+  where++import           Data.ByteString.Lazy.Char8 (ByteString)+import           GHC.Conc                   (atomically)+import           Hakyll.Core.Item+import           Hakyll.Core.Compiler+import           System.Process.Typed++import           Hakyll.Typescript.Internal++-- |Arguments to pass to the typescript compiler.+type TSArgs = [String]++-- |Compiles the typescript or javascript 'Hakyll.Core.Item.Item' to javascript.+compressJtsCompiler :: Compiler (Item ByteString)+compressJtsCompiler = compressJtsCompilerWith mempty++-- |Compiles the typescript 'Hakyll.Core.Item.Item' to javascript, then+-- minifies the result.+compressTsCompiler :: Compiler (Item ByteString)+compressTsCompiler = compressTsCompilerWith mempty++-- |Compiles the typescript or javascript 'Hakyll.Core.Item.Item' to javascript,+-- then minifies the result+compressJtsCompilerWith :: TSArgs -> Compiler (Item ByteString)+compressJtsCompilerWith args = withMinifyJs $ jtsCompilerWith args++-- |Compiles the typescript 'Hakyll.Core.Item.Item' to javascript, then+-- minifies the result. Passes all typescript arguments to the typescript+-- compiler for compilation.+compressTsCompilerWith :: TSArgs -> Compiler (Item ByteString)+compressTsCompilerWith args = withMinifyJs $ tsCompilerWith args++-- |Compiles the typescript or javascript 'Hakyll.Core.Item.Item' to javascript.+jtsCompiler :: Compiler (Item ByteString)+jtsCompiler = jtsCompilerWith mempty++-- |Compiles the typescript 'Hakyll.Core.Item.Item' to javascript.+tsCompiler :: Compiler (Item ByteString)+tsCompiler = tsCompilerWith mempty++-- |Compiles the typescript or javascript 'Hakyll.Core.Item.Item' to javascript.+-- Passes the provided 'TSArgs' to the typescript compiler.+jtsCompilerWith :: TSArgs -> Compiler (Item ByteString)+jtsCompilerWith args = tsCompilerWith $ ["--allowJs", "true"] <> args++-- |Compiles the typescript 'Hakyll.Core.Item.Item' to javascript.+-- Passes the provided 'TSArgs' to the typescript compiler.+tsCompilerWith :: TSArgs -> Compiler (Item ByteString)+tsCompilerWith args = do+  -- this won't work on Windows, but that's probably fine+  let defaultArgs = ["--outFile", "/dev/stdout"]+  tsPath <- getResourceFilePath+  let fullArgs = defaultArgs <> args <> [tsPath]+  jsBody <- unsafeCompiler $ tsc fullArgs+  -- just using this to get at the item+  oldTsBody <- getResourceString+  pure $ itemSetBody jsBody oldTsBody++tsc :: TSArgs -> IO ByteString+tsc args = withProcess procConf waitJsOutput where+  procConf = setStdout byteStringOutput . proc "tsc" $ args+  waitJsOutput process = do+    let stmJs = getStdout process+    js <- atomically stmJs+    checkExitCode process+    pure js
+ tests/Hakyll/Typescript/JS/Tests.hs view
@@ -0,0 +1,27 @@+module Hakyll.Typescript.JS.Tests+  (+    tests+  )+  where++import           Hakyll.Typescript.JS+import           Hakyll.Typescript.TestResources++import           Test.Tasty+import           Test.Tasty.HUnit++tests :: TestTree+tests = testGroup "Hakyll.Typescript.JS.Tests"+  [+    fileSizeSmaller,+    errorsOnBadJs+  ]++fileSizeSmaller :: TestTree+fileSizeSmaller = testCase "Valid js output is smaller than input" $+  runTestCompiler helloWorldJS compressJsCompiler+                  "Compression failed" (outputSmaller helloWorldJS)++errorsOnBadJs :: TestTree+errorsOnBadJs = testCase "Raises an exception when Js is invalid" $+  runExceptionCompiler bad compressJsCompiler
+ tests/Hakyll/Typescript/TS/Tests.hs view
@@ -0,0 +1,108 @@+module Hakyll.Typescript.TS.Tests+  (+    tests+  )+  where++import           Hakyll.Typescript.TS+import           Hakyll.Typescript.TestResources++import           Test.Tasty+import           Test.Tasty.HUnit++tests :: TestTree+tests = testGroup "Hakyll.Typescript.TS.Tests"+  [+    compilesTs,+    errorsOnBadTs,+    tscErrorsReported,+    handlesUserArgs,+    compressedFileSizeSmaller,+    compressedFileSizeSmallerWithArgs,+    compressionErrorsReported,+    jtsCompilerWithCompilesJSWithArgs,+    jtsCompilerCompilesJs,+    jtsCompilerCompilesTs,+    compressJtsCompilerCompressesJs,+    compressJtsCompilerCompressesTs,+    compressJtsCompilerWithCompressesWithArgs,+    compressJtsCompilerWithReportsErrors+  ]++compilesTs :: TestTree+compilesTs = testCase "Compiles Valid TS" $ do+  runTestCompiler helloWorldTS tsCompiler+                  "tsc compiler error" expectSuccess++errorsOnBadTs :: TestTree+errorsOnBadTs = testCase "Raises an exception on invalid TS" $ do+  runTestCompiler bad tsCompiler+                  "tsc compilation success (but it shouldn't have)"+                  expectFailure++tscErrorsReported :: TestTree+tscErrorsReported = testCase "Compilation errors reported" $ do+  runTestCompiler helloWorldJS tsCompiler+                  "tsc compilation success (but it shouldn't have)"+                  expectFailure++handlesUserArgs :: TestTree+handlesUserArgs = testCase "Successfully passes user arguments to tsc" $ do+  runTestCompiler helloWorldJS (tsCompilerWith ["--allowJs", "true"])+                  "tsc compilation failure" expectSuccess++compressedFileSizeSmaller :: TestTree+compressedFileSizeSmaller = testCase "Valid TS minifies successfully" $ do+  runTestCompiler helloWorldTS compressTsCompiler+                  "tsc compilation failure" expectSuccess++compressedFileSizeSmallerWithArgs :: TestTree+compressedFileSizeSmallerWithArgs = testCase "Valid JS minifies successfully" $ do+  runTestCompiler helloWorldTS (compressTsCompilerWith ["--allowJs", "true"])+                  "tsc compilation failure" expectSuccess++compressionErrorsReported :: TestTree+compressionErrorsReported =+  testCase "Compilation errors in compress ts compiler are reported" $ do+    runTestCompiler helloWorldJS compressTsCompiler+                  "tsc compilation success" expectFailure++jtsCompilerWithCompilesJSWithArgs :: TestTree+jtsCompilerWithCompilesJSWithArgs =+  testCase "Compiles js and accepts more args" $ do+    runTestCompiler helloWorldJS (jtsCompilerWith ["--target", "ES6"])+                  "tsc compilation failed" expectSuccess++jtsCompilerCompilesJs :: TestTree+jtsCompilerCompilesJs = testCase "Compiles js successfully" $ do+    runTestCompiler helloWorldJS jtsCompiler+                  "tsc compilation failed" expectSuccess++jtsCompilerCompilesTs :: TestTree+jtsCompilerCompilesTs = testCase "Compiles ts successfully" $ do+    runTestCompiler helloWorldTS jtsCompiler+                  "tsc compilation failed" expectSuccess++compressJtsCompilerWithCompressesWithArgs :: TestTree+compressJtsCompilerWithCompressesWithArgs =+  testCase "Compresses and uses more args" $ do+    runTestCompiler helloWorldTS (compressJtsCompilerWith ["--target", "ES5"])+                  "tsc compilation failed" expectSuccess++compressJtsCompilerCompressesTs :: TestTree+compressJtsCompilerCompressesTs =+  testCase "Compresses ts" $ do+    runTestCompiler helloWorldTS compressJtsCompiler+                  "tsc compilation failed" expectSuccess++compressJtsCompilerCompressesJs :: TestTree+compressJtsCompilerCompressesJs =+  testCase "Compresses js" $ do+    runTestCompiler helloWorldJS compressJtsCompiler+                  "tsc compilation failed" expectSuccess++compressJtsCompilerWithReportsErrors :: TestTree+compressJtsCompilerWithReportsErrors =+  testCase "jts compiler reports errors" $ do+    runExceptionCompiler helloWorldTS+      (compressJtsCompilerWith ["--target", "ES2020"])
+ tests/Hakyll/Typescript/TestResources.hs view
@@ -0,0 +1,101 @@+{-# LANGUAGE PartialTypeSignatures #-}+module Hakyll.Typescript.TestResources+  (+    bad,+    expectFailure,+    expectSuccess,+    fileSize,+    helloWorldJS,+    helloWorldTS,+    outputSmaller,+    resourceRoot,+    runExceptionCompiler,+    runTestCompiler+  )+  where++import           Control.Exception   (handle, SomeException)+import           Hakyll+import           Hakyll.Core.Logger  (new, Verbosity(..))+import           Hakyll.Core.Runtime+import           System.Directory    (removeDirectoryRecursive)+import           System.Exit+import           System.IO+import           Test.Tasty.HUnit    ((@?), assertFailure)++resourceRoot :: FilePath+resourceRoot = "tests/resources/"++helloWorldTS :: FilePath+helloWorldTS = resourceRoot <> "hello_world.ts"++helloWorldJS :: FilePath+helloWorldJS = resourceRoot <> "hello_world.js"++bad          :: FilePath+bad          = resourceRoot <> "bad.ts"++testTmpDir :: FilePath+testTmpDir = "_test/"++testSiteDir :: FilePath+testSiteDir = testTmpDir <> "site/"++testToSitePath :: FilePath -> FilePath+testToSitePath p = testSiteDir <> name <> ".js" where+  name = reverse . drop 3 . reverse $ p++testConfiguration :: Configuration+testConfiguration = defaultConfiguration+  {+    destinationDirectory = testSiteDir+  , storeDirectory       = testTmpDir <> "store"+  , tmpDirectory         = testTmpDir <> "tmp"+  , providerDirectory    = "."+  }++runTestCompiler :: _+                => FilePath+                -> Compiler (Item a)+                -> String -- assertion failure message+                -> (ExitCode -> IO Bool) -- assertion. Should not throw!+                -> IO ()+runTestCompiler testResource testCompiler msg assertion = do+  logger        <- new Error+  (exitCode, _) <- run testConfiguration logger $ do+    match (fromGlob testResource) $ do+      route $ setExtension "js"+      compile testCompiler+  assertResult  <- assertion exitCode+  removeDirectoryRecursive testTmpDir+  assertResult @? msg++runExceptionCompiler :: _ => FilePath -> Compiler (Item a) -> IO ()+runExceptionCompiler testResource testCompiler = do+  logger <- new Error+  result <- handle (\e -> printException e >> pure True) $ do+    _ <- run testConfiguration logger $ do+      match (fromGlob testResource) $ do+        route $ setExtension "js"+        compile testCompiler+    pure False+  removeDirectoryRecursive testTmpDir+  result @? "Expected exception."++expectSuccess :: ExitCode -> IO Bool+expectSuccess = pure . (== ExitSuccess)++expectFailure :: ExitCode -> IO Bool+expectFailure = pure . (== ExitFailure 1)++printException :: SomeException -> IO ()+printException e = putStrLn $ "Caught exception: " ++ show e++fileSize :: FilePath -> IO Integer+fileSize p = withFile p ReadMode hFileSize++outputSmaller :: FilePath -> ExitCode -> IO Bool+outputSmaller testPath exitCode = do+  origSize <- fileSize testPath+  siteSize <- fileSize $ testToSitePath testPath+  pure $ exitCode == ExitSuccess && siteSize < origSize
+ tests/TestSuite.hs view
@@ -0,0 +1,12 @@+module Main where++import qualified Hakyll.Typescript.JS.Tests as JS+import qualified Hakyll.Typescript.TS.Tests as TS+import           Test.Tasty (defaultMain, testGroup)++main :: IO ()+main = defaultMain $ testGroup "hakyll-typescript"+  [+    JS.tests+  , TS.tests+  ]