packages feed

headroom-0.1.0.0: src/Headroom/Header.hs

{-|
Module      : Headroom.Header
Description : License header manipulation
Copyright   : (c) 2019-2020 Vaclav Svejcar
License     : BSD-3
Maintainer  : vaclav.svejcar@gmail.com
Stability   : experimental
Portability : POSIX

License header is usually the very top comment in source code, holding some
short text about license type, author and copyright. This module provides data
types and functions for adding, dropping and replacing such headers. The license
header is represented by 'Header' data type, where 'FileType' defines for which
programming language source code this header is generated and the header text
itself.
-}
{-# LANGUAGE LambdaCase        #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Headroom.Header
  ( Header(..)
  , addHeader
  , containsHeader
  , dropHeader
  , headerSize
  , replaceHeader
  )
where

import           Headroom.FileType              ( FileType(..) )
import           Headroom.Header.Impl
import qualified Headroom.Text                 as T
import           Headroom.Types                 ( NewLine(..) )
import           RIO
import qualified RIO.List                      as L


-- | Generated license header for specified source code file type.
data Header = Header
  { hFileType :: FileType -- ^ type of the source code
  , hContent  :: Text     -- ^ text of the header
  }
  deriving (Eq, Show)

-- | Adds header to the given source code text if no existing header is
-- detected, otherwise returns the unchanged input text. If you need to replace
-- the header, use the 'replaceHeader' instead.
addHeader :: Header -- ^ license header to add to the input text
          -> Text   -- ^ source code text
          -> Text   -- ^ source code text with added license header
addHeader (Header fileType content) input = output
 where
  output = if containsHeader' then input else content <> newLine <> input
  containsHeader' = containsHeader fileType input
  newLine = T.showNewLine $ fromMaybe LF (T.detectNewLine input)

-- | Checks whether the license header is present in given source code text.
containsHeader :: FileType -- ^ type of the input source code text
               -> Text     -- ^ source code text
               -> Bool     -- ^ result of check
containsHeader fileType input = headerSize fileType input > 0

-- | Drops license header (if detected) from the given source code text.
dropHeader :: FileType  -- ^ type of the input source code text
           -> Text     -- ^ source code text
           -> Text     -- ^ source code text without the license header
dropHeader fileType input = T.unlines' newLine . L.drop numLines $ lines'
 where
  numLines          = headerSize fileType input
  (newLine, lines') = T.lines' input

-- | Detects what is the header size in terms of lines in the given source code
-- text. Returns @0@ if no header detected.
headerSize :: FileType -- ^ type of the input source code text
           -> Text     -- ^ source code text
           -> Int      -- ^ size of the headers (number of lines)
headerSize = \case
  CSS     -> headerSizeCSS
  Haskell -> headerSizeHaskell
  HTML    -> headerSizeHTML
  Java    -> headerSizeJava
  JS      -> headerSizeJS
  Scala   -> headerSizeScala

-- | Replaces already existing (or adds if none detected) license header with
-- the new one in the given source code text. If you need to only add header if
-- none detected and skip if it already contains one, use the 'addHeader'
-- instead.
replaceHeader :: Header -- ^ new license header to use for replacement
              -> Text   -- ^ source code text
              -> Text   -- ^ source code text with replaced license header
replaceHeader h@(Header fileType _) = addHeader h . dropHeader fileType