packages feed

bunz (empty) → 0.0.1

raw patch · 10 files changed

+292/−0 lines, 10 filesdep +basedep +bunzdep +cmdargssetup-changed

Dependencies added: base, bunz, cmdargs, doctest, hspec, text, unix

Files

+ LICENSE view
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2017 Sendy Halim <sendyhalim93@gmail.com>++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ README.md view
@@ -0,0 +1,2 @@+# Bunz+JSON beautifier cli tool written in Haskell
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ app/Main.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE DeriveDataTypeable #-}++module Main where++import qualified Beautifier             as B+import           System.Console.CmdArgs ((&=))+import qualified System.Console.CmdArgs as CA+import qualified System.Posix.IO        as IO+import qualified System.Posix.Terminal  as T++data Args = Args { jsonString :: String }+  deriving (Show, CA.Data, CA.Typeable)+++args = Args { jsonString = CA.def &= CA.typ "JSON String" &= CA.argPos 0 }+    &= CA.summary "JSON beautifier tool version 0.0.1"++main :: IO ()+main = T.queryTerminal IO.stdInput >>= run++printBeautified :: String -> IO ()+printBeautified = putStrLn . B.beautify++runFromStdInput :: IO ()+runFromStdInput = getContents >>= printBeautified++runFromArgs :: Args -> IO ()+runFromArgs (Args { jsonString = str }) = printBeautified str++run :: Bool -> IO ()+run False = runFromStdInput+run True = CA.cmdArgs args >>= runFromArgs
+ bunz.cabal view
@@ -0,0 +1,49 @@+name:                bunz+version:             0.0.1+synopsis:            CLI tool to beautify JSON string.+description:         CLI tool to beautify JSON string.+homepage:            https://github.com/sendyhalim/bunz+license:             MIT+license-file:        LICENSE+author:              Sendy Halim <sendyhalim93@gmail.com>+maintainer:          Sendy Halim <sendyhalim93@gmail.com>+copyright:           (c) 2017 Sendy Halim+category:            CLI, JSON+build-type:          Simple+extra-source-files:  README.md+cabal-version:       >=1.10++library+  hs-source-dirs:      src+  exposed-modules:     Character+                     , Beautifier+  build-depends:       base >= 4.7 && < 5+                     , text == 1.2.2.2+  default-language:    Haskell2010++executable bunz-exe+  hs-source-dirs:      app+  main-is:             Main.hs+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N+  build-depends:       base+                     , bunz+                     , unix == 2.7.2.1+                     , cmdargs >= 0.10.18+  default-language:    Haskell2010++test-suite bunz-test+  type:                exitcode-stdio-1.0+  hs-source-dirs:      test+  main-is:             MainSpec.hs+  other-modules:       CharacterSpec+                     , BeautifierSpec+  build-depends:       base+                     , bunz+                     , doctest >= 0.11+                     , hspec == 2.4.4+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N+  default-language:    Haskell2010++source-repository head+  type:     git+  location: https://github.com/githubuser/bunz
+ src/Beautifier.hs view
@@ -0,0 +1,121 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns      #-}++module Beautifier+  ( beautify+  , indent+  , firstString+  , splitAtHead+  ) where++import           Data.Monoid ((<>))+import qualified Data.String as S+import qualified Data.Text   as T++-- Doctest setup+-- $setup+-- >>> :set -XOverloadedStrings++type IndentationLevel = Int++indentation :: T.Text+indentation = "  "++newline :: T.Text+newline = "\n"++indent :: IndentationLevel -> T.Text -> T.Text+indent level str = T.replicate level indentation <> str++trimmedTail :: T.Text -> T.Text+trimmedTail = T.stripStart . T.tail++-- | Split the given string at its head while honouring escaped string.+-- Examples:+--+-- >>> splitAtHead "whatsup"+-- ("w","hatsup")+--+-- >>> splitAtHead "\nyeay"+-- ("\n","yeay")+splitAtHead :: T.Text -> (T.Text, T.Text)+splitAtHead "" = ("", "")+splitAtHead str@(T.head -> '\\') = T.splitAt 2 str+splitAtHead str = T.splitAt 1 str++-- | Extract string within double quotes `"` including the double quotes ignoring+-- the suffix after closing quote `"`+--+-- Examples:+--+-- >>> string False "\"test\"whatuppp"+-- "\"test\""+string :: Bool -> T.Text -> T.Text+string False str@(T.head -> '"') = "\"" <> string True (T.tail str)+string True str@(T.head -> '"') = "\""+string True str = let (head, tail) = splitAtHead str in head <> string True tail++-- | Extract the first string value starting from the front.+firstString :: T.Text -> T.Text+firstString str = string False str+++-- | Check if the given character is a whitespace+isWhitespace x+  | x == ' ' = True+  | x == '\r' = True+  | x == '\n' = True+  | x == '\t' = True+  | otherwise = False++-- | Check if the given character is end of json value+isEndOfValue x+ | isWhitespace x = True+ | x == ',' = True+ | x == '}' = True+ | x == ']' = True+ | otherwise = False++-- | Extract json value from the given text+--+-- Examples+--+-- >>> extractJsonValue "123131}"+-- "123131"+--+-- >>> extractJsonValue "false,true,false]"+-- "false"+extractJsonValue :: T.Text -> T.Text+extractJsonValue = T.takeWhile (not . isEndOfValue)++-- |Beautify the given JSON text based on the current indentation level.+beautifyText :: IndentationLevel -> T.Text -> T.Text+beautifyText i str+  | str == "" = ""+  | head == ' ' = stripStartThenParse str+  | head == '\n' = stripStartThenParse str+  | head == '\t' = stripStartThenParse str+  | head == '{' = nextLineAfterOpening "{"+  | head == '[' = nextLineAfterOpening "["+  | head == '}' = nextLineAfterClosing "}"+  | head == ']' = nextLineAfterClosing "]"+  | head == ',' = "," <> newline <> indent i (beautifyText i (trimmedTail str))+  | head == '"' = let groupedString = firstString str+                      restOfTheString = T.drop (T.length groupedString) str+                  in groupedString <> beautifyText i restOfTheString+  | head == ':' = ": " <> beautifyText i (trimmedTail str)+  | otherwise = let value = extractJsonValue str+                in value <> beautifyText i (T.drop (T.length value) str)+  where+    head = T.head str+    stripStartThenParse = beautifyText i . T.stripStart+    nextLineAfterOpening token = token+      <> newline+      <> indent (i + 1) (beautifyText (i + 1) (trimmedTail str))+    nextLineAfterClosing token = newline+      <> indent (i - 1) token+      <> beautifyText (i - 1) (trimmedTail str)+++beautify :: String -> String+beautify = T.unpack . beautifyText 0 . T.pack
+ src/Character.hs view
@@ -0,0 +1,9 @@+module Character+    ( isEscaped+    ) where++import           Control.Monad++isEscaped :: String -> Bool+isEscaped ('\\':x) = True+isEscaped _ = False
+ test/BeautifierSpec.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE OverloadedStrings #-}++module BeautifierSpec (main, spec) where++import qualified Beautifier as B+import           Test.Hspec++main :: IO()+main = hspec spec++spec :: Spec+spec = do+  describe "Beautifier.indent" $ do+    context "When given negative indent level" $ do+      it "should not indent" $ do+        B.indent (-1) "{" `shouldBe` "{"++    context "When given 0 indent level" $ do+      it "should not indent" $ do+        B.indent 0 "{" `shouldBe` "{"++    context "When given 2 indent level" $ do+      it "should indent by 2 levels" $ do+        B.indent 2 "{" `shouldBe` "    {"++  describe "Beautifier.splitAtHead" $ do+    context "when text first character is escaped" $ do+      it "should split escaped character as the head" $ do+        B.splitAtHead "\\\"hithere" `shouldBe` ("\\\"", "hithere")++    context "when the first character is not escaped" $ do+      it "should split correctly" $ do+        B.splitAtHead "testtest" `shouldBe` ("t", "esttest")++    context "when given empty text" $ do+      it "should split into empty strings" $ do+        B.splitAtHead "" `shouldBe` ("", "")
+ test/CharacterSpec.hs view
@@ -0,0 +1,18 @@+module CharacterSpec (main, spec) where++import qualified Character  as C+import           Test.Hspec++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+  describe "Character.isEscaped" $ do+    context "Given character \\t" $ do+      it "should return True" $ do+        C.isEscaped "\\t" `shouldBe` True++    context "Given character \t" $ do+      it "should return False" $ do+        C.isEscaped "\t" `shouldBe` False
+ test/MainSpec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}