hjsmin 0.2.0.2 → 0.2.0.3
raw patch · 8 files changed
+231/−219 lines, 8 filesdep +directorydep +extradep +filepathdep −blaze-builderdep −containersdep ~basedep ~bytestringdep ~language-javascript
Dependencies added: directory, extra, filepath, process, unix
Dependencies removed: blaze-builder, containers
Dependency ranges changed: base, bytestring, language-javascript, text
Files
- TODO.txt +0/−91
- Text/Jasmine.hs +0/−49
- Text/Jasmine/Pretty.hs +0/−5
- hjsmin.cabal +40/−22
- hjsmin.hs +0/−52
- main/hjsmin.hs +80/−0
- src/Text/Jasmine.hs +54/−0
- test/test-cli.hs +57/−0
− TODO.txt
@@ -1,91 +0,0 @@-Testing:--The following Lint has a strict parser- http://www.javascriptlint.com/online_lint.php--This one does not- http://www.jslint.com/-------Language reference https://developer.mozilla.org/en/JavaScript/Reference-http://msdn.microsoft.com/en-us/library/ttyab5c8.aspx----- --Look at -- http://dean.edwards.name/download/#packer-- http://code.google.com/p/minify/--Examples of parsers-- JSon parser in Parsec- http://snippets.dzone.com/posts/show/3660--GOLD Parser, using the Javascript.grm from-http://www.devincook.com/GOLDParser/grammars/index.htm--http://oss.org.cn/ossdocs/web/js/js20/formal/parser-grammar.html------------------------------ Generate output using standard pretty print library, so it can be- used with various backends---- Sort out semicolon insertion, as per http://oss.org.cn/ossdocs/web/js/js20/rationale/syntax.html- Also: http://inimino.org/~inimino/blog/javascript_semicolons-- Grammatical Semicolon Insertion-- Semicolons before a closing } and the end of the program are- optional in both JavaScript 1.5 and 2.0. In addition, the- JavaScript 2.0 parser allows semicolons to be omitted before the- else of an if-else statement and before the while of a do-while- statement.-- Line-Break Semicolon Insertion-- If the first through the nth tokens of a JavaScript program form- are grammatically valid but the first through the n+1st tokens are- not and there is a line break between the nth tokens and the n+1st- tokens, then the parser tries to parse the program again after- inserting a VirtualSemicolon token between the nth and the n+1st- tokens.--- remove un-needed semicolons in pretty printer--- put in tests for all cases of elementList---- Look at "in" keyword, as used : if (x in list) {}----------------Integrating language-haskell.--------------------------------Baseline before starting, on my laptop (intel Core2 Duo SU7300)--$ time ./dist/build/runtests/runtests--real 0m1.625s-user 0m1.616s-sys 0m0.016s--Baseline 2010-12-20, after getting all tests to pass at last--real 0m0.209s-user 0m0.196s-sys 0m0.004s--After working in unicode, in language-javascript-0.0.3 [2010-12-28]--real 0m0.236s-user 0m0.224s-sys 0m0.012s----EOF
− Text/Jasmine.hs
@@ -1,49 +0,0 @@-module Text.Jasmine- ( minify- , minifym- , minifyBb- , minifyFile- ) where--import Control.Applicative ((<$>))-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-import Language.JavaScript.Process.Minify--import qualified Blaze.ByteString.Builder as BB-import qualified Data.ByteString.Lazy as LB-import qualified Data.ByteString.Lazy.Char8 as S8----minifym :: LB.ByteString -> Either String LB.ByteString-minifym s =- case myParse s of- Left msg -> Left (show msg)- Right p -> Right $ BB.toLazyByteString $ renderJS $ minifyJS p---minifyBb :: LB.ByteString -> Either String BB.Builder-minifyBb s =- case myParse s of- Left msg -> Left (show msg)- Right p -> Right (renderJS $ minifyJS p)---minify :: LB.ByteString -> LB.ByteString-minify s = BB.toLazyByteString . renderJS . minifyJS . readJs $ lbToStr s---minifyFile :: FilePath -> IO LB.ByteString-minifyFile filename = minify <$> LB.readFile filename---myParse :: S8.ByteString -> Either String JSAST-myParse input = parse (lbToStr input) "src"---lbToStr :: S8.ByteString -> String-lbToStr = unpack . decodeUtf8With lenientDecode
− Text/Jasmine/Pretty.hs
@@ -1,5 +0,0 @@-module Text.Jasmine.Pretty- ( renderJS- ) where--import Language.JavaScript.Pretty.Printer (renderJS)
hjsmin.cabal view
@@ -1,5 +1,5 @@ name: hjsmin-version: 0.2.0.2+version: 0.2.0.3 license: BSD3 license-file: LICENSE author: Alan Zimmerman <alan.zimm@gmail.com>@@ -10,38 +10,56 @@ other syntactic elements, without changing the semantics. category: Web stability: unstable-cabal-version: >= 1.9.2+cabal-version: >= 1.10 build-type: Simple homepage: http://github.com/erikd/hjsmin bug-reports: http://github.com/erikd/hjsmin/issues Extra-source-files:- TODO.txt- , Readme.md+ Readme.md library- build-depends: base >= 4.5- , bytestring >= 0.9- , blaze-builder >= 0.2- , text >= 0.8- , containers >= 0.2- , language-javascript >= 0.6 && < 0.7- exposed-modules: Text.Jasmine- other-modules: Text.Jasmine.Pretty- ghc-options: -Wall+ default-language: Haskell2010+ ghc-options: -Wall+ hs-source-dirs: src -executable hjsmin- main-is: hjsmin.hs+ exposed-modules: Text.Jasmine + build-depends: base >= 4.8 && < 5+ , bytestring == 0.10.*+ , language-javascript >= 0.6 && < 0.8+ , text == 1.2.*+++executable hjsmin+ default-language: Haskell2010 ghc-options: -Wall -threaded- build-depends: base >= 4 && < 5- , bytestring >= 0.9- , blaze-builder >= 0.2- , text >= 0.8- , containers >= 0.2- , language-javascript >= 0.6- , optparse-applicative >= 0.7+ 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 >= 4.8 && < 5+ , bytestring == 0.10.*+ , 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
− hjsmin.hs
@@ -1,52 +0,0 @@-{-# LANGUAGE CPP #-}-module Main where--#include "cabal_macros.h"--import Data.Monoid ((<>))-import Options.Applicative-import Text.Jasmine--import qualified Data.ByteString.Lazy as B-import qualified Data.ByteString.Lazy.Char8 as C8---data Options = Options- { inputFile :: String- , outputFile :: Maybe String- }--main :: IO ()-main =- execParser opts >>= minify'- where- opts = info (helper <*> options)- ( fullDesc- <> progDesc- ( "Minify JavaScript files (using language-javascript version "- ++ languageJavascriptVersion ++ ")."- )- <> header "hjsmin - a simple command-line interface to the 'hjsmin' library"- )--options :: Parser Options-options = Options- <$> argument str (metavar "INPUT_FILE"- <> help "The unminified, original JavaScript file")- <*> optional- ( strOption (long "output-file"- <> short 'o'- <> metavar "OUTPUT_FILE"- <> help "The minified output file. Default: stdout")- )--minify' :: Options -> IO ()-minify' o = do- minified <- minifyFile (inputFile o)- case outputFile o of- Nothing -> C8.putStrLn minified- Just f -> B.writeFile f minified---languageJavascriptVersion :: String-languageJavascriptVersion = VERSION_language_javascript
+ main/hjsmin.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE CPP #-}++#include "cabal_macros.h"++import qualified Data.ByteString.Lazy.Char8 as LBS+import Data.Monoid ((<>))+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, ")"+ ]
+ src/Text/Jasmine.hs view
@@ -0,0 +1,54 @@+module Text.Jasmine+ ( minify+ , minifym+ , minifyBb+ , minifyFile+ ) where++import Control.Applicative ((<$>))++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
+ test/test-cli.hs view
@@ -0,0 +1,57 @@+{-# 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)