{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} -- | Module that contains the high-level checking functions module CheckMap (loadAndLintMap, MapResult(..)) where import Data.Aeson (ToJSON) import Data.Map (Map, fromList, toList) import Data.Maybe (mapMaybe) import Data.Text (Text) import qualified Data.Text as T import qualified Data.Vector as V import GHC.Generics (Generic) import LintWriter (LintResult (..), LintWriter, askContext, lintToDep, resultToDeps, resultToLints, runLintWriter) import Properties (checkLayerProperty, checkMap) import Tiled2 (Layer (layerName, layerProperties), Tiledmap (tiledmapLayers), loadTiledmap) import Types (Dep, Level (..), Lint (..), hint) import Util (PrettyPrint (prettyprint), prettyprint) -- | What this linter produces: lints for a single map data MapResult = MapResult { mapresultLayer :: Maybe (Map Text (LintResult Layer)) , mapresultGeneral :: [Lint] , mapresultDepends :: [Dep] } deriving (Generic, ToJSON) -- | this module's raison d'ĂȘtre loadAndLintMap :: FilePath -> IO MapResult loadAndLintMap path = loadTiledmap path >>= pure . \case Left err -> MapResult { mapresultLayer = Nothing , mapresultDepends = [] , mapresultGeneral = [ hint Fatal . T.pack $ path <> ": Fatal: " <> err ] } Right waMap -> runLinter waMap -- | lint a loaded map runLinter :: Tiledmap -> MapResult runLinter tiledmap = MapResult { mapresultLayer = Just layerMap , mapresultGeneral = generalLints -- no general lints for now , mapresultDepends = concatMap (resultToDeps . snd) layer <> mapMaybe lintToDep generalLints } where layerMap :: Map Text (LintResult Layer) layerMap = fromList layer layer = V.toList . V.map runCheck $ tiledmapLayers tiledmap where runCheck l = (layerName l, runLintWriter l 0 checkLayer) -- lints collected from properties generalLints = resultToLints $ runLintWriter tiledmap 0 checkMap -- | collect lints on a single map layer checkLayer :: LintWriter Layer checkLayer = do layer <- askContext mapM_ checkLayerProperty (layerProperties layer) -- human-readable lint output, e.g. for consoles instance PrettyPrint MapResult where prettyprint mapResult = T.concat $ prettyGeneral <> prettyLayer where -- TODO: this can be simplified further prettyLayer :: [Text] prettyLayer = map (prettyprint . snd) (maybe [] toList . mapresultLayer $ mapResult) prettyGeneral :: [Text] prettyGeneral = flip (<>) "\n" . prettyprint <$> mapresultGeneral mapResult