hjsmin-0.2.1/0000755000000000000000000000000007346545000011173 5ustar0000000000000000hjsmin-0.2.1/LICENSE0000644000000000000000000000276507346545000012212 0ustar0000000000000000Copyright (c)2010, Alan Zimmerman 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 Alan Zimmerman 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. hjsmin-0.2.1/Readme.md0000644000000000000000000000171507346545000012716 0ustar0000000000000000hjsmin ====== [![Build Status](https://secure.travis-ci.org/erikd/hjsmin.png?branch=master)](http://travis-ci.org/erikd/hjsmin) Haskell implementation of a command line javascript minifier. The executable generated from this package simply does command line parsing before handing the off the minification process to the [language-javascript] package which also does the rendering. How to build ------------ cabal clean && cabal configure && cabal build Tests ----- There are currently no tests, because all the heavy lifting is done by [language-javascript]. Reporting Bugs -------------- Bugs like failing to parse certain chunks of Javascript or errors in the minification process should be reported on the [language-javascript] issue tracker. Bugs about failure to handle command line paramters should be reported on the [hjsmin] issue tracker. [hjsmin]: https://github.com/erikd/hjsmin [language-javascript]: https://github.com/erikd/language-javascript hjsmin-0.2.1/Setup.hs0000644000000000000000000000005607346545000012630 0ustar0000000000000000import Distribution.Simple main = defaultMain hjsmin-0.2.1/hjsmin.cabal0000644000000000000000000000404707346545000013454 0ustar0000000000000000name: hjsmin version: 0.2.1 license: BSD3 license-file: LICENSE author: Alan Zimmerman maintainer: Erik de Castro Lopo synopsis: Haskell implementation of a javascript minifier description: Reduces size of javascript files by stripping out extraneous whitespace and other syntactic elements, without changing the semantics. category: Web stability: unstable cabal-version: >= 1.10 build-type: Simple homepage: http://github.com/erikd/hjsmin bug-reports: http://github.com/erikd/hjsmin/issues Extra-source-files: Readme.md test/cli/core/runner test/cli/empty-input/run test/cli/minimal-input/run library default-language: Haskell2010 ghc-options: -Wall hs-source-dirs: src exposed-modules: Text.Jasmine build-depends: base >= 4.9 && < 5 , bytestring >= 0.11 , language-javascript >= 0.6 && < 0.8 , text >= 2 executable hjsmin default-language: Haskell2010 ghc-options: -Wall -threaded hs-source-dirs: src main main-is: hjsmin.hs -- Need this here because the library and the executable have the same name. other-modules: Text.Jasmine build-depends: base , bytestring , language-javascript , optparse-applicative >= 0.7 , text test-suite test-cli type: exitcode-stdio-1.0 ghc-options: -Wall -fwarn-tabs default-language: Haskell2010 hs-source-dirs: test main-is: test-cli.hs build-depends: base , directory , extra , filepath , process , unix source-repository head type: git location: https://github.com/erikd/hjsmin.git hjsmin-0.2.1/main/0000755000000000000000000000000007346545000012117 5ustar0000000000000000hjsmin-0.2.1/main/hjsmin.hs0000644000000000000000000000375207346545000013752 0ustar0000000000000000{-# LANGUAGE CPP #-} #include "cabal_macros.h" import qualified Data.ByteString.Lazy.Char8 as LBS import Options.Applicative (Parser, ParserInfo, ParserPrefs) import qualified Options.Applicative as Opt import Text.Jasmine (minify) import System.IO (hPutStrLn, stderr) import System.Exit (exitFailure) data Command = Process FilePath (Maybe FilePath) main :: IO () main = Opt.customExecParser p opts >>= processFile where opts :: ParserInfo Command opts = Opt.info (Opt.helper <*> pVersion <*> pProcess) ( Opt.fullDesc <> Opt.header "hjsmin - Haskell implementation of a Javascript and JSON minifier" ) p :: ParserPrefs p = Opt.prefs Opt.showHelpOnEmpty pVersion :: Parser (a -> a) pVersion = Opt.infoOption versionString ( Opt.long "version" <> Opt.short 'v' <> Opt.help "Print the version and exit" ) pProcess :: Parser Command pProcess = Process <$> pInputFile <*> pMaybeOutputFile where pInputFile = Opt.strOption ( Opt.long "input" <> Opt.short 'i' <> Opt.metavar "INPUT_FILE" <> Opt.help "The original JavaScript file" ) pMaybeOutputFile = Opt.optional $ Opt.strOption ( Opt.long "output" <> Opt.short 'o' <> Opt.metavar "OUTPUT_FILE" <> Opt.help "The minified output file. Default: stdout" ) processFile :: Command -> IO () processFile (Process inputFile outputFile) = do lbs <- LBS.readFile inputFile if LBS.null lbs then emptyFileError else do let minified = minify lbs case outputFile of Nothing -> LBS.putStrLn minified Just f -> LBS.writeFile f minified where emptyFileError = do hPutStrLn stderr $ "Error: input file '" ++ inputFile ++ "' is empty." exitFailure versionString :: String versionString = concat [ "hjsmin version ", VERSION_hjsmin , " (using language-javascript version ", VERSION_language_javascript, ")" ] hjsmin-0.2.1/src/Text/0000755000000000000000000000000007346545000012706 5ustar0000000000000000hjsmin-0.2.1/src/Text/Jasmine.hs0000644000000000000000000000253307346545000014633 0ustar0000000000000000module Text.Jasmine ( minify , minifym , minifyBb , minifyFile ) where import Data.ByteString.Builder (Builder) import qualified Data.ByteString.Builder as Builder import qualified Data.ByteString.Lazy.Char8 as LBS import Data.Text.Lazy (unpack) import Data.Text.Lazy.Encoding (decodeUtf8With) import Data.Text.Encoding.Error (lenientDecode) import Language.JavaScript.Parser (readJs, parse, JSAST) import Language.JavaScript.Pretty.Printer (renderJS) import Language.JavaScript.Process.Minify (minifyJS) minifym :: LBS.ByteString -> Either String LBS.ByteString minifym s = case myParse s of Left msg -> Left (show msg) Right p -> Right $ Builder.toLazyByteString $ renderJS $ minifyJS p minifyBb :: LBS.ByteString -> Either String Builder minifyBb s = case myParse s of Left msg -> Left (show msg) Right p -> Right (renderJS $ minifyJS p) minify :: LBS.ByteString -> LBS.ByteString minify = Builder.toLazyByteString . renderJS . minifyJS . readJs . lbToStr minifyFile :: FilePath -> IO LBS.ByteString minifyFile filename = minify <$> LBS.readFile filename myParse :: LBS.ByteString -> Either String JSAST myParse input = parse (lbToStr input) "src" lbToStr :: LBS.ByteString -> String lbToStr = unpack . decodeUtf8With lenientDecode hjsmin-0.2.1/test/cli/core/0000755000000000000000000000000007346545000013651 5ustar0000000000000000hjsmin-0.2.1/test/cli/core/runner0000644000000000000000000000271707346545000015114 0ustar0000000000000000if test -d dist-newstyle ; then HJSMIN=$(find dist-newstyle -type f -name hjsmin) elif test -d ../dist-newstyle ; then HJSMIN=$(find ../dist-newstyle -type f -name hjsmin) fi echo echo $HJSMIN echo DIFF=${USE_DIFF:-diff -u} colourReset='\e[0m' colourGreen='\e[0;32m' colourRed='\e[0;31m' colourYellow='\e[0;33m' testname=$(basename $(dirname $0)) # Failure is the default! RESULT="FAILED" type "$HJSMIN" > /dev/null 2>&1 || { echo "No hjsmin executable specified on command line or on path." exit 1 } ROOT=$(dirname "$0")/../../.. ROOT=$(cd "$ROOT" > /dev/null 2>&1 && pwd) TMP=${ROOT}/tmp TEST=${TMP}/test/$$ mkdir -p ${TEST} cleanup () { echo "Cleaning up (${TEST})" rm -rf "${TEST}" echo ${RESULT} echo } trap cleanup EXIT banner () { echo "${colourYellow}== $* ==${colourReset}" echo "== Running in ${TEST} ==" } assert_file_exists () { if test ! -f "$1" ; then echo "Output file '$1' is missing." fail_test fi } pass_test () { RESULT="${colourGreen}PASSED [ ${testname} ]${colourReset}" exit 0 } fail_test () { RESULT="${colourRed}FAILED [ ${testname} ]${colourReset}" exit 1 } sort_diff () { EXP="$1" ACTUAL="$2" EXPECTED_SORTED=${OUTPUT_DIR}/sort_diff.expected.$(basename $EXP) ACTUAL_SORTED=${OUTPUT_DIR}/sort_diff.actual.$(basename $ACTUAL) sort ${EXP} > ${EXPECTED_SORTED} sort ${ACTUAL} > ${ACTUAL_SORTED} diff ${EXPECTED_SORTED} ${ACTUAL_SORTED} } hjsmin-0.2.1/test/cli/empty-input/0000755000000000000000000000000007346545000015214 5ustar0000000000000000hjsmin-0.2.1/test/cli/empty-input/run0000644000000000000000000000064307346545000015746 0ustar0000000000000000#!/bin/sh -eu . $(dirname $0)/../core/runner testname="empty-input" banner "${testname}" #---------- OUTPUT_DIR=${TEST} mkdir -p ${OUTPUT_DIR} INPUT_FILE=${OUTPUT_DIR}/empty OUTPUT_FILE=${OUTPUT_DIR}/output # Create a zero length file touch ${INPUT_FILE} retcode=0 ${HJSMIN} --input ${INPUT_FILE} --output ${OUTPUT_FILE} 2>/dev/null || retcode=1 if test ${retcode} -eq 0 ; then fail_test else pass_test fi hjsmin-0.2.1/test/cli/minimal-input/0000755000000000000000000000000007346545000015504 5ustar0000000000000000hjsmin-0.2.1/test/cli/minimal-input/run0000644000000000000000000000063307346545000016235 0ustar0000000000000000#!/bin/sh -eu . $(dirname $0)/../core/runner testname="minimal-input" banner "${testname}" #---------- OUTPUT_DIR=${TEST} mkdir -p ${OUTPUT_DIR} INPUT_FILE=${OUTPUT_DIR}/empty OUTPUT_FILE=${OUTPUT_DIR}/output # Create a minimal file echo '{}' > ${INPUT_FILE} retcode=0 ${HJSMIN} --input ${INPUT_FILE} --output ${OUTPUT_FILE} || retcode=1 if test ${retcode} -eq 0 ; then pass_test else fail_test fi hjsmin-0.2.1/test/0000755000000000000000000000000007346545000012152 5ustar0000000000000000hjsmin-0.2.1/test/test-cli.hs0000644000000000000000000000404207346545000014232 0ustar0000000000000000{-# LANGUAGE MultiWayIf #-} import Control.Monad (foldM, forM) import Control.Monad.Extra (concatMapM) import System.Directory (canonicalizePath, getCurrentDirectory, listDirectory) import System.Environment (setEnv) import System.FilePath (takeFileName, ()) import System.Exit (ExitCode (..), exitFailure, exitSuccess) import System.Posix.Files (getFileStatus, isDirectory, isRegularFile) import System.Process (rawSystem) import System.IO (BufferMode (..)) import qualified System.IO as IO main :: IO () main = do IO.hSetBuffering IO.stdout LineBuffering IO.hSetBuffering IO.stderr LineBuffering cwd <- getCurrentDirectory topdir <- canonicalizePath $ cwd "dist-newstyle" -- Set an environment variable for all the exectuables we want to test. setExecutableEnvVar "HJSMIN" topdir "hjsmin" tests <- filter (`notElem` ["core", "data"]) <$> listDirectory "test/cli/" res <- forM tests $ \ t -> rawSystem ("test/cli/" ++ t ++ "/run") [] if all (== ExitSuccess) res then exitSuccess else exitFailure setExecutableEnvVar :: String -> FilePath -> FilePath -> IO () setExecutableEnvVar envName startDir target = do xs <- listDirectoryRecursive startDir case filter match xs of [] -> error "Unable to find hjsmin binary" [x] -> setEnv envName x _ -> error $ "Multiple binaries: " ++ show xs where match :: FilePath -> Bool match fp = takeFileName fp == target listDirectoryRecursive :: FilePath -> IO [FilePath] listDirectoryRecursive fpath = do xs <- fmap (fpath ) <$> listDirectory fpath (files, dirs) <- foldM partitioner ([], []) xs rest <- concatMapM listDirectoryRecursive (dirs :: [FilePath]) pure $ files ++ rest where partitioner :: ([FilePath], [FilePath]) -> FilePath -> IO ([FilePath], [FilePath]) partitioner (files, dirs) fp = do st <- getFileStatus fp if | isRegularFile st -> pure (fp : files, dirs) | isDirectory st -> pure (files, fp : dirs) | otherwise -> pure (files, dirs)