diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Revision history for nestedtext
 
+## 0.1.3 -- 2025/02/22
+
+* chore(deps): Move microlens-platform from common depends
+* style(treewide): Apply stylish-haskell
+* test(Empty): Parse empty string
+* refactor(treewide): Apply hlint
+
 ## 0.1.2 -- 2025/02/16
 
 * fix(test/Official): Disable empty\_1 test
diff --git a/nestedtext.cabal b/nestedtext.cabal
--- a/nestedtext.cabal
+++ b/nestedtext.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.8
 name:               nestedtext
-version:            0.1.2
+version:            0.1.3
 synopsis:           NestedText: A Human Friendly Data Format
 description:
     Haskell implementation of [NestedText](https://nestedtext.org/) 3.7
@@ -36,7 +36,6 @@
         base >= 4.17 && < 4.22,
         bytestring >= 0.11 && < 0.13,
         containers >= 0.6.5 && < 0.8,
-        microlens-platform >= 0.4.3.1 && < 0.5,
         pipes >= 4.0 && < 4.4,
         pipes-text >= 1.0 && < 1.1,
         text >= 2.0 && < 2.2,
@@ -54,6 +53,7 @@
         binary >= 0.8 && < 0.9,
         free >= 3.2 && < 5.3,
         generic-data >= 1.1 && < 1.2,
+        microlens-platform >= 0.4.3.1 && < 0.5,
         pipes-parse >= 3.0 && < 3.1,
         transformers >= 0.6 && < 0.7,
     exposed-modules:
@@ -85,6 +85,7 @@
         tasty-hedgehog,
         tasty-hunit,
     other-modules:
+        Empty,
         Official,
         Property,
         Util,
diff --git a/src/Data/NestedText/Decode.hs b/src/Data/NestedText/Decode.hs
--- a/src/Data/NestedText/Decode.hs
+++ b/src/Data/NestedText/Decode.hs
@@ -4,12 +4,12 @@
 
 module Data.NestedText.Decode where
 
+import Data.NestedText.From
+import Data.NestedText.Parse
+
 import Data.Bifunctor (first)
 import qualified Data.Text.Lazy as TL
 import Generic.Data
-
-import Data.NestedText.From
-import Data.NestedText.Parse
 
 data DecodeError a
   = DecodeError'ParseError ParseError
diff --git a/src/Data/NestedText/Encode.hs b/src/Data/NestedText/Encode.hs
--- a/src/Data/NestedText/Encode.hs
+++ b/src/Data/NestedText/Encode.hs
@@ -4,14 +4,14 @@
 
 module Data.NestedText.Encode where
 
+import Data.NestedText.Serialize
+import Data.NestedText.To
+
 import Data.Bifunctor (first)
 import qualified Data.Text.Lazy as TL
 import Generic.Data
 
-import Data.NestedText.To
-import Data.NestedText.Serialize
-
-data EncodeError a
+newtype EncodeError a
   = EncodeError'ToItemError (ToItemError a)
   deriving (Generic)
 instance Eq (ToItemError a) => Eq (EncodeError a) where
diff --git a/src/Data/NestedText/From.hs b/src/Data/NestedText/From.hs
--- a/src/Data/NestedText/From.hs
+++ b/src/Data/NestedText/From.hs
@@ -5,6 +5,8 @@
 
 module Data.NestedText.From where
 
+import Data.NestedText.Type
+
 import Control.Monad (forM)
 import Data.Bifunctor (Bifunctor(first))
 import qualified Data.Binary.Builder as BB
@@ -20,8 +22,6 @@
 import qualified Data.Vector as V
 import Data.Void (Void)
 import Generic.Data
-
-import Data.NestedText.Type
 
 class FromItem a where
   type FromItemError a :: Type
diff --git a/src/Data/NestedText/Parse.hs b/src/Data/NestedText/Parse.hs
--- a/src/Data/NestedText/Parse.hs
+++ b/src/Data/NestedText/Parse.hs
@@ -10,7 +10,11 @@
   , parseDocument
   ) where
 
-import Control.Monad (when)
+import Data.NestedText.To (ToItem(..), ToKey(..))
+import Data.NestedText.Type
+import Data.NestedText.Util
+
+import Control.Monad (unless, when)
 import Control.Monad.Trans.Class (MonadTrans(..))
 import qualified Control.Monad.Trans.State.Strict as StateT
 import qualified Data.Char as C
@@ -27,10 +31,6 @@
 import qualified Pipes.Text as PT
 import Prelude hiding (readList)
 
-import Data.NestedText.To (ToItem(..), ToKey(..))
-import Data.NestedText.Type
-import Data.NestedText.Util
-
 data Line
   = Line'Blank
   | Line'Comment Int T.Text
@@ -85,7 +85,7 @@
           )
         go revks (x:xs) = go (x:revks) xs
    in case drop indentLevel ts0 of
-        [] -> Right $ Line'Blank
+        [] -> Right Line'Blank
         '#':' ':cs1 -> Right $ Line'Comment indentLevel $ T.pack cs1
         '#':cs1 -> Right $ Line'Comment indentLevel $ T.pack cs1
         ['>'] -> Right $ Line'StringItem indentLevel T.empty
@@ -141,7 +141,7 @@
   parser = do
     xi <- readItemIndent [EQ] 0
     b <- PP.isEndOfInput
-    when (not b) $ lift $ Left ParseError'RemainingContent
+    unless b $ lift $ Left ParseError'RemainingContent
     return xi
   toItemWithoutError :: (ToItem a, ToItemError a ~ Void) => a -> Item
   toItemWithoutError x = case toItem x of
@@ -155,7 +155,7 @@
 
   readItemIndent cs i = do
     (item, j) <- readItem
-    when ((i `compare` j) `notElem` cs) $ lift $ Left ParseError'InvalidIndent
+    unless ((i `compare` j) `elem` cs) $ lift $ Left ParseError'InvalidIndent
     return item
   readItem = do
     ml <- PP.peek
@@ -282,7 +282,7 @@
       vs <- readInlineList0
       readInlineSpace
       b <- PP.isEndOfInput
-      when (not b) $ lift $ Left ParseError'RemainingInlineContent
+      unless b $ lift $ Left ParseError'RemainingInlineContent
       return vs
   parseInlineDict = lift . StateT.evalStateT go . mapM_ P.yield . T.unpack
    where
@@ -290,7 +290,7 @@
       dic <- readInlineDict0
       readInlineSpace
       b <- PP.isEndOfInput
-      when (not b) $ lift $ Left ParseError'RemainingInlineContent
+      unless b $ lift $ Left ParseError'RemainingInlineContent
       return dic
   readInlineChar x = do
     mc <- PP.draw
diff --git a/src/Data/NestedText/Serialize.hs b/src/Data/NestedText/Serialize.hs
--- a/src/Data/NestedText/Serialize.hs
+++ b/src/Data/NestedText/Serialize.hs
@@ -5,6 +5,9 @@
   , serialize'
   ) where
 
+import Data.NestedText.Type
+import Data.NestedText.Util
+
 import qualified Data.Char as C
 import Data.Functor.Identity (Identity(..))
 import Data.List (intersperse)
@@ -19,9 +22,6 @@
 import Generic.Data
 import Lens.Micro.Platform
 import qualified Pipes.Text as PT
-
-import Data.NestedText.Type
-import Data.NestedText.Util
 
 data Denote
   = Denote'Null
diff --git a/src/Data/NestedText/To.hs b/src/Data/NestedText/To.hs
--- a/src/Data/NestedText/To.hs
+++ b/src/Data/NestedText/To.hs
@@ -5,6 +5,8 @@
 
 module Data.NestedText.To where
 
+import Data.NestedText.Type
+
 import Control.Monad (forM)
 import Data.Bifunctor (Bifunctor(first))
 import qualified Data.ByteString as BS
@@ -20,8 +22,6 @@
 import Data.Void (Void)
 import Generic.Data
 
-import Data.NestedText.Type
-
 class ToItem a where
   type ToItemError a :: Type
   toItem :: a -> Either (ToItemError a) Item
@@ -52,7 +52,7 @@
   type ToItemError TL.Text = Void
   toItem = Right . Item'String . TL.toStrict
 
-data ToItemError'List a
+newtype ToItemError'List a
   = ToItemError'List'ElementError (ToItemError a)
   deriving (Generic)
 instance Eq (ToItemError a) => Eq (ToItemError'List a) where
diff --git a/src/Data/NestedText/Util.hs b/src/Data/NestedText/Util.hs
--- a/src/Data/NestedText/Util.hs
+++ b/src/Data/NestedText/Util.hs
@@ -50,13 +50,11 @@
         Right _ -> error "splitLines: unreachable"
 
 freeTToLines :: Monad m => F.FreeT (P.Producer T.Text m) m r -> m [T.Text]
-freeTToLines free = go free
-  where
-    go ft = do
-      step <- F.runFreeT ft
-      case step of
-        F.Pure _ -> return []
-        F.Free p0 -> do
-          (line, p1) <- P.fold' (<>) T.empty id p0
-          rest <- go p1
-          return $ line : rest
+freeTToLines ft = do
+  step <- F.runFreeT ft
+  case step of
+    F.Pure _ -> return []
+    F.Free p0 -> do
+      (line, p1) <- P.fold' (<>) T.empty id p0
+      rest <- freeTToLines p1
+      return $ line : rest
diff --git a/test/Empty.hs b/test/Empty.hs
new file mode 100644
--- /dev/null
+++ b/test/Empty.hs
@@ -0,0 +1,17 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Empty where
+
+import Data.NestedText.Parse
+import Data.NestedText.Type
+
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.HUnit (testCase, (@?=))
+
+test_empty :: TestTree
+test_empty = testGroup "empty"
+  [ testCase "item" $ do
+    parse "" @?= Left ParseError'Empty
+  , testCase "document" $ do
+    parseDocument "" @?= Right Document'Empty
+  ]
diff --git a/test/Official.hs b/test/Official.hs
--- a/test/Official.hs
+++ b/test/Official.hs
@@ -1,5 +1,10 @@
 module Official where
 
+import Data.NestedText.Parse
+import Data.NestedText.Serialize
+import Data.NestedText.Type
+import Data.NestedText.Util
+
 import Control.Monad (forM)
 import Data.Functor.Identity (Identity(..))
 import Data.List (singleton)
@@ -12,21 +17,13 @@
 import qualified Pipes.Text as PT
 import System.Directory (doesFileExist, listDirectory)
 import System.FilePath ((</>))
-import System.IO
-  ( IOMode(..), Newline(..)
-  , hSetEncoding, hSetNewlineMode
-  , nativeNewline, nativeNewlineMode, noNewlineTranslation
-  , openFile, utf8
-  )
+import System.IO (IOMode(..), Newline(..), hSetEncoding, hSetNewlineMode,
+                  nativeNewline, nativeNewlineMode, noNewlineTranslation,
+                  openFile, utf8)
 import Test.Tasty (TestTree, testGroup)
 import Test.Tasty.HUnit (assertFailure, testCase, (@?=))
 import qualified Text.JSON as J
 
-import Data.NestedText.Parse
-import Data.NestedText.Serialize
-import Data.NestedText.Type
-import Data.NestedText.Util
-
 data TestLoad
   = TestLoad'Nothing
   | TestLoad'ShouldSuccess FilePath FilePath
@@ -45,7 +42,7 @@
   readJSON (J.JSString jsstr) =
     J.Ok $ I $ Item'String $ T.pack $ J.fromJSString jsstr
   readJSON (J.JSArray vs) =
-    fmap (I . Item'List . V.fromList) $ forM vs $ \vi -> unI <$> J.readJSON vi
+    fmap (I . Item'List . V.fromList) $ forM vs $ fmap unI . J.readJSON
   readJSON (J.JSObject jsobj) =
     fmap (I . Item'Dictionary . M.fromList)
     $ forM (J.fromJSObject jsobj) $ \(k, v) -> do
@@ -142,7 +139,7 @@
         (False, False) -> error $ d0 ++ ": no expected result"
     return (d0, tl, td)
   forM ts $ \(d, tl, td) -> do
-    tls <- if elem d skipLoad then return [] else case tl of
+    tls <- if d `elem` skipLoad then return [] else case tl of
       TestLoad'Nothing -> return []
       TestLoad'ShouldSuccess fin fout -> do
         mjout <- readJSON fout
@@ -159,7 +156,7 @@
           Right iin ->
             assertFailure $ "load succeed! it should fail. " ++ show iin
           Left _err -> return ()
-    tds <- if elem d skipDump then return [] else case td of
+    tds <- if d `elem` skipDump then return [] else case td of
       TestDump'Nothing -> return []
       TestDump'ShouldSuccess fin fout -> do
         mjin <- readJSON fin
diff --git a/test/Property.hs b/test/Property.hs
--- a/test/Property.hs
+++ b/test/Property.hs
@@ -1,5 +1,9 @@
 module Property where
 
+import Data.NestedText.Parse
+import Data.NestedText.Serialize
+import Data.NestedText.Type
+
 import qualified Data.Char as C
 import qualified Data.Map.Strict as M
 import qualified Data.Text as T
@@ -10,10 +14,6 @@
 import qualified Hedgehog.Range as HR
 import Test.Tasty (TestTree, testGroup)
 import Test.Tasty.Hedgehog (testProperty)
-
-import Data.NestedText.Parse
-import Data.NestedText.Serialize
-import Data.NestedText.Type
 
 genItem :: H.MonadGen m => H.Range Int -> H.Range Int -> H.Range Int -> m Item
 genItem rs rk rn = go
diff --git a/test/Util.hs b/test/Util.hs
--- a/test/Util.hs
+++ b/test/Util.hs
@@ -2,11 +2,11 @@
 
 module Util where
 
+import Data.NestedText.Util
+
 import qualified Pipes as P
 import Test.Tasty (TestTree, testGroup)
 import Test.Tasty.HUnit (testCase, (@?=))
-
-import Data.NestedText.Util
 
 test_lines :: TestTree
 test_lines = testGroup "splitLines" $
