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 +16/−0
- LICENSE +30/−0
- README.md +37/−0
- Setup.hs +2/−0
- hakyll-typescript.cabal +51/−0
- src/Hakyll/Typescript/Internal.hs +18/−0
- src/Hakyll/Typescript/JS.hs +17/−0
- src/Hakyll/Typescript/TS.hs +96/−0
- tests/Hakyll/Typescript/JS/Tests.hs +27/−0
- tests/Hakyll/Typescript/TS/Tests.hs +108/−0
- tests/Hakyll/Typescript/TestResources.hs +101/−0
- tests/TestSuite.hs +12/−0
+ 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+ ]