{- Copyright 2012-2015 Vidar Holen This file is part of ShellCheck. https://www.shellcheck.net ShellCheck is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ShellCheck is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . -} module ShellCheck.Interface ( SystemInterface(..) , CheckSpec(csFilename, csScript, csCheckSourced, csExcludedWarnings, csShellTypeOverride, csMinSeverity) , CheckResult(crFilename, crComments) , ParseSpec(psFilename, psScript, psCheckSourced, psShellTypeOverride) , ParseResult(prComments, prTokenPositions, prRoot) , AnalysisSpec(asScript, asShellType, asExecutionMode, asCheckSourced) , AnalysisResult(arComments) , FormatterOptions(foColorOption, foWikiLinkCount) , Shell(Ksh, Sh, Bash, Dash) , ExecutionMode(Executed, Sourced) , ErrorMessage , Code , Severity(ErrorC, WarningC, InfoC, StyleC) , Position(posFile, posLine, posColumn) , Comment(cSeverity, cCode, cMessage) , PositionedComment(pcStartPos , pcEndPos , pcComment) , ColorOption(ColorAuto, ColorAlways, ColorNever) , TokenComment(tcId, tcComment) , emptyCheckResult , newParseResult , newAnalysisSpec , newAnalysisResult , newFormatterOptions , newPosition , newTokenComment , mockedSystemInterface , newParseSpec , emptyCheckSpec , newPositionedComment , newComment ) where import ShellCheck.AST import Control.Monad.Identity import qualified Data.Map as Map newtype SystemInterface m = SystemInterface { -- Read a file by filename, or return an error siReadFile :: String -> m (Either ErrorMessage String) } -- ShellCheck input and output data CheckSpec = CheckSpec { csFilename :: String, csScript :: String, csCheckSourced :: Bool, csExcludedWarnings :: [Integer], csShellTypeOverride :: Maybe Shell, csMinSeverity :: Severity } deriving (Show, Eq) data CheckResult = CheckResult { crFilename :: String, crComments :: [PositionedComment] } deriving (Show, Eq) emptyCheckResult :: CheckResult emptyCheckResult = CheckResult { crFilename = "", crComments = [] } emptyCheckSpec :: CheckSpec emptyCheckSpec = CheckSpec { csFilename = "", csScript = "", csCheckSourced = False, csExcludedWarnings = [], csShellTypeOverride = Nothing, csMinSeverity = StyleC } newParseSpec :: ParseSpec newParseSpec = ParseSpec { psFilename = "", psScript = "", psCheckSourced = False, psShellTypeOverride = Nothing } -- Parser input and output data ParseSpec = ParseSpec { psFilename :: String, psScript :: String, psCheckSourced :: Bool, psShellTypeOverride :: Maybe Shell } deriving (Show, Eq) data ParseResult = ParseResult { prComments :: [PositionedComment], prTokenPositions :: Map.Map Id (Position, Position), prRoot :: Maybe Token } deriving (Show, Eq) newParseResult :: ParseResult newParseResult = ParseResult { prComments = [], prTokenPositions = Map.empty, prRoot = Nothing } -- Analyzer input and output data AnalysisSpec = AnalysisSpec { asScript :: Token, asShellType :: Maybe Shell, asExecutionMode :: ExecutionMode, asCheckSourced :: Bool } newAnalysisSpec token = AnalysisSpec { asScript = token, asShellType = Nothing, asExecutionMode = Executed, asCheckSourced = False } newtype AnalysisResult = AnalysisResult { arComments :: [TokenComment] } newAnalysisResult = AnalysisResult { arComments = [] } -- Formatter options data FormatterOptions = FormatterOptions { foColorOption :: ColorOption, foWikiLinkCount :: Integer } newFormatterOptions = FormatterOptions { foColorOption = ColorAuto, foWikiLinkCount = 3 } -- Supporting data types data Shell = Ksh | Sh | Bash | Dash deriving (Show, Eq) data ExecutionMode = Executed | Sourced deriving (Show, Eq) type ErrorMessage = String type Code = Integer data Severity = ErrorC | WarningC | InfoC | StyleC deriving (Show, Eq, Ord) data Position = Position { posFile :: String, -- Filename posLine :: Integer, -- 1 based source line posColumn :: Integer -- 1 based source column, where tabs are 8 } deriving (Show, Eq) newPosition :: Position newPosition = Position { posFile = "", posLine = 1, posColumn = 1 } data Comment = Comment { cSeverity :: Severity, cCode :: Code, cMessage :: String } deriving (Show, Eq) newComment :: Comment newComment = Comment { cSeverity = StyleC, cCode = 0, cMessage = "" } data PositionedComment = PositionedComment { pcStartPos :: Position, pcEndPos :: Position, pcComment :: Comment } deriving (Show, Eq) newPositionedComment :: PositionedComment newPositionedComment = PositionedComment { pcStartPos = newPosition, pcEndPos = newPosition, pcComment = newComment } data TokenComment = TokenComment { tcId :: Id, tcComment :: Comment } deriving (Show, Eq) newTokenComment = TokenComment { tcId = Id 0, tcComment = newComment } data ColorOption = ColorAuto | ColorAlways | ColorNever deriving (Ord, Eq, Show) -- For testing mockedSystemInterface :: [(String, String)] -> SystemInterface Identity mockedSystemInterface files = SystemInterface { siReadFile = rf } where rf file = case filter ((== file) . fst) files of [] -> return $ Left "File not included in mock." [(_, contents)] -> return $ Right contents