packages feed

aeson-tiled 0.0.0.1 → 0.0.1.0

raw patch · 8 files changed

+239/−124 lines, 8 filesdep +hspec-discoverdep ~aesondep ~basedep ~bytestringnew-uploaderPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: hspec-discover

Dependency ranges changed: aeson, base, bytestring, containers, text, vector

API changes (from Hackage documentation)

+ Data.Aeson.Tiled: Isometric :: Orientation
+ Data.Aeson.Tiled: Orientation :: Text -> Orientation
+ Data.Aeson.Tiled: Orthogonal :: Orientation
+ Data.Aeson.Tiled: Staggered :: Orientation
+ Data.Aeson.Tiled: VersionFloat :: Float -> Version
+ Data.Aeson.Tiled: VersionText :: Text -> Version
+ Data.Aeson.Tiled: XYPair :: a -> a -> XYPair a
+ Data.Aeson.Tiled: data Map k a
+ Data.Aeson.Tiled: data Orientation
+ Data.Aeson.Tiled: data Vector a
+ Data.Aeson.Tiled: data Version
+ Data.Aeson.Tiled: data XYPair a
+ Data.Aeson.Tiled: fromXYPair :: XYPair a -> (a, a)
+ Data.Aeson.Tiled: instance Data.Aeson.Types.FromJSON.FromJSON Data.Aeson.Tiled.Orientation
+ Data.Aeson.Tiled: instance Data.Aeson.Types.FromJSON.FromJSON Data.Aeson.Tiled.Version
+ Data.Aeson.Tiled: instance Data.Aeson.Types.FromJSON.FromJSON a => Data.Aeson.Types.FromJSON.FromJSON (Data.Aeson.Tiled.XYPair a)
+ Data.Aeson.Tiled: instance Data.Aeson.Types.ToJSON.ToJSON Data.Aeson.Tiled.Orientation
+ Data.Aeson.Tiled: instance Data.Aeson.Types.ToJSON.ToJSON Data.Aeson.Tiled.Version
+ Data.Aeson.Tiled: instance Data.Aeson.Types.ToJSON.ToJSON a => Data.Aeson.Types.ToJSON.ToJSON (Data.Aeson.Tiled.XYPair a)
+ Data.Aeson.Tiled: instance GHC.Classes.Eq Data.Aeson.Tiled.Orientation
+ Data.Aeson.Tiled: instance GHC.Classes.Eq Data.Aeson.Tiled.Version
+ Data.Aeson.Tiled: instance GHC.Classes.Ord Data.Aeson.Tiled.Orientation
+ Data.Aeson.Tiled: instance GHC.Classes.Ord Data.Aeson.Tiled.Version
+ Data.Aeson.Tiled: instance GHC.Generics.Generic Data.Aeson.Tiled.Orientation
+ Data.Aeson.Tiled: instance GHC.Generics.Generic Data.Aeson.Tiled.Version
+ Data.Aeson.Tiled: instance GHC.Show.Show Data.Aeson.Tiled.Orientation
+ Data.Aeson.Tiled: instance GHC.Show.Show Data.Aeson.Tiled.Version
+ Data.Aeson.Tiled: omitNulls :: Value -> Value
+ Data.Aeson.Tiled: parseDefault :: FromJSON a => Object -> Key -> a -> Parser a
+ Data.Aeson.Tiled: toXYPair :: (a, a) -> XYPair a
- Data.Aeson.Tiled: Layer :: Int -> Int -> String -> String -> Bool -> Int -> Int -> Maybe (Vector GlobalId) -> Maybe (Vector Object) -> Map Text Text -> Float -> String -> Layer
+ Data.Aeson.Tiled: Layer :: Double -> Double -> Text -> Text -> Bool -> Double -> Double -> Maybe (Vector GlobalId) -> Maybe (Vector Object) -> Map Text Text -> Float -> Text -> Layer
- Data.Aeson.Tiled: Object :: Int -> Int -> Int -> String -> String -> Map Text Text -> Bool -> Int -> Int -> Float -> GlobalId -> Bool -> Vector (Int, Int) -> Vector (Int, Int) -> Map Text Text -> Object
+ Data.Aeson.Tiled: Object :: Int -> Double -> Double -> Text -> Text -> Map Text Text -> Bool -> Double -> Double -> Float -> Maybe GlobalId -> Bool -> Maybe (Vector (Double, Double)) -> Maybe (Vector (Double, Double)) -> Map Text Text -> Object
- Data.Aeson.Tiled: Terrain :: String -> LocalId -> Terrain
+ Data.Aeson.Tiled: Terrain :: Text -> LocalId -> Terrain
- Data.Aeson.Tiled: Tiledmap :: Float -> String -> Int -> Int -> Int -> Int -> String -> Vector Layer -> Vector Tileset -> Maybe String -> String -> Map Text Text -> Int -> Tiledmap
+ Data.Aeson.Tiled: Tiledmap :: Version -> Version -> Int -> Int -> Double -> Double -> Orientation -> Vector Layer -> Vector Tileset -> Maybe Text -> Text -> Map Text Text -> Int -> Tiledmap
- Data.Aeson.Tiled: Tileset :: GlobalId -> String -> String -> Int -> Int -> Int -> Int -> Map Text Text -> Map Text Text -> Int -> Int -> Map GlobalId (Map Text Text) -> Vector Terrain -> Int -> Int -> Map LocalId Tile -> Tileset
+ Data.Aeson.Tiled: Tileset :: GlobalId -> FilePath -> Text -> Int -> Int -> Int -> Int -> Map Text Text -> Map Text Text -> Int -> Int -> Map GlobalId (Map Text Text) -> Vector Terrain -> Int -> Int -> Map LocalId Tile -> Tileset
- Data.Aeson.Tiled: TransitiveTilesetMap :: (Map LocalId Value) -> TransitiveTilesetMap
+ Data.Aeson.Tiled: TransitiveTilesetMap :: Map LocalId Value -> TransitiveTilesetMap
- Data.Aeson.Tiled: [layerDraworder] :: Layer -> String
+ Data.Aeson.Tiled: [layerDraworder] :: Layer -> Text
- Data.Aeson.Tiled: [layerHeight] :: Layer -> Int
+ Data.Aeson.Tiled: [layerHeight] :: Layer -> Double
- Data.Aeson.Tiled: [layerName] :: Layer -> String
+ Data.Aeson.Tiled: [layerName] :: Layer -> Text
- Data.Aeson.Tiled: [layerType] :: Layer -> String
+ Data.Aeson.Tiled: [layerType] :: Layer -> Text
- Data.Aeson.Tiled: [layerWidth] :: Layer -> Int
+ Data.Aeson.Tiled: [layerWidth] :: Layer -> Double
- Data.Aeson.Tiled: [layerX] :: Layer -> Int
+ Data.Aeson.Tiled: [layerX] :: Layer -> Double
- Data.Aeson.Tiled: [layerY] :: Layer -> Int
+ Data.Aeson.Tiled: [layerY] :: Layer -> Double
- Data.Aeson.Tiled: [objectGid] :: Object -> GlobalId
+ Data.Aeson.Tiled: [objectGid] :: Object -> Maybe GlobalId
- Data.Aeson.Tiled: [objectHeight] :: Object -> Int
+ Data.Aeson.Tiled: [objectHeight] :: Object -> Double
- Data.Aeson.Tiled: [objectName] :: Object -> String
+ Data.Aeson.Tiled: [objectName] :: Object -> Text
- Data.Aeson.Tiled: [objectPolygon] :: Object -> Vector (Int, Int)
+ Data.Aeson.Tiled: [objectPolygon] :: Object -> Maybe (Vector (Double, Double))
- Data.Aeson.Tiled: [objectPolyline] :: Object -> Vector (Int, Int)
+ Data.Aeson.Tiled: [objectPolyline] :: Object -> Maybe (Vector (Double, Double))
- Data.Aeson.Tiled: [objectType] :: Object -> String
+ Data.Aeson.Tiled: [objectType] :: Object -> Text
- Data.Aeson.Tiled: [objectWidth] :: Object -> Int
+ Data.Aeson.Tiled: [objectWidth] :: Object -> Double
- Data.Aeson.Tiled: [objectX] :: Object -> Int
+ Data.Aeson.Tiled: [objectX] :: Object -> Double
- Data.Aeson.Tiled: [objectY] :: Object -> Int
+ Data.Aeson.Tiled: [objectY] :: Object -> Double
- Data.Aeson.Tiled: [terrainName] :: Terrain -> String
+ Data.Aeson.Tiled: [terrainName] :: Terrain -> Text
- Data.Aeson.Tiled: [tiledmapBackgroundcolor] :: Tiledmap -> Maybe String
+ Data.Aeson.Tiled: [tiledmapBackgroundcolor] :: Tiledmap -> Maybe Text
- Data.Aeson.Tiled: [tiledmapOrientation] :: Tiledmap -> String
+ Data.Aeson.Tiled: [tiledmapOrientation] :: Tiledmap -> Orientation
- Data.Aeson.Tiled: [tiledmapRenderorder] :: Tiledmap -> String
+ Data.Aeson.Tiled: [tiledmapRenderorder] :: Tiledmap -> Text
- Data.Aeson.Tiled: [tiledmapTiledversion] :: Tiledmap -> String
+ Data.Aeson.Tiled: [tiledmapTiledversion] :: Tiledmap -> Version
- Data.Aeson.Tiled: [tiledmapTileheight] :: Tiledmap -> Int
+ Data.Aeson.Tiled: [tiledmapTileheight] :: Tiledmap -> Double
- Data.Aeson.Tiled: [tiledmapTilewidth] :: Tiledmap -> Int
+ Data.Aeson.Tiled: [tiledmapTilewidth] :: Tiledmap -> Double
- Data.Aeson.Tiled: [tiledmapVersion] :: Tiledmap -> Float
+ Data.Aeson.Tiled: [tiledmapVersion] :: Tiledmap -> Version
- Data.Aeson.Tiled: [tilesetImage] :: Tileset -> String
+ Data.Aeson.Tiled: [tilesetImage] :: Tileset -> FilePath
- Data.Aeson.Tiled: [tilesetName] :: Tileset -> String
+ Data.Aeson.Tiled: [tilesetName] :: Tileset -> Text

Files

+ ChangeLog.md view
@@ -0,0 +1,16 @@+# Change Log++## [0.0.1.0] - 2022-02-19++Package moved to https://github.com/haskell-game/aeson-tiled++- Fixed frame serialization.+- Updated to match recent Tiled format.+- Maintenance info update.++## [0.0.0.1] - 2017-10-24++Initial release.++[0.0.1.0]: https://github.com/haskell-game/aeson-tiled/releases/tag/v0.0.1.0+[0.0.0.1]: https://github.com/haskell-game/aeson-tiled/releases/tag/v0.0.0.1
README.md view
@@ -1,8 +1,10 @@ # aeson-tiled-[![Build Status](https://travis-ci.org/schell/aeson-tiled.svg?branch=master)](https://travis-ci.org/schell/aeson-tiled)+ [![Hackage](https://img.shields.io/hackage/v/aeson-tiled.svg)](https://hackage.haskell.org/package/aeson-tiled)-`aeson-tiled` is the spiritual successor to `htiled`. `htiled` uses `hxt` which relies-too heavily on Arrows and is rather hard to work with. Tiled's json export-supports 100% of Tiled's features, so there doesn't seem to be much of a-point to maintaining a large Arrows-based project when writing Aeson instances-for Tiled types is much easier. Hence this project!++Types and instances for [Tiled](https://www.mapeditor.org/) map editor `.tmj` files.++> `aeson-tiled` is the spiritual successor to `htiled`.+> `htiled` uses `hxt` which relies too heavily on Arrows and is rather hard to work with.+> Tiled's json export supports 100% of Tiled's features, so there doesn't seem to be much of a point to maintaining a large Arrows-based project when writing Aeson instances for Tiled types is much easier.+> Hence this project!
aeson-tiled.cabal view
@@ -1,40 +1,41 @@ name:                aeson-tiled-version:             0.0.0.1+version:             0.0.1.0 synopsis:            Aeson instances for the Tiled map editor.-description:         The mighty Tiled 2d map editor is an open source+description:         The mighty Tiled 2D map editor is an open source                      app for creating tile based level maps. This package provides                      types and aeson instances to read Tiled json files.-homepage:            https://github.com/schell/aeson-tiled#readme+homepage:            https://github.com/haskell-game/aeson-tiled license:             BSD3 license-file:        LICENSE+maintainer:          aenor.realm@gmai.com author:              Schell Scivally-maintainer:          schell@takt.com-copyright:           Copyright: (c) 2017 Schell Scivally-category:            Game+copyright:           (c) 2017 Schell Scivally+category:            Game Engine build-type:          Simple-extra-source-files:  README.md cabal-version:       >=1.10 +extra-source-files:+  README.md,+  ChangeLog.md+ library   hs-source-dirs:      src   exposed-modules:     Data.Aeson.Tiled-  build-depends:       base >= 4.7 && < 5-                     , bytestring >= 0.10-                     , aeson >= 1.1-                     , containers >= 0.5-                     , text >= 1.2-                     , vector >= 0.12+  build-depends:       base       >= 4.7 && < 5+                     , bytestring >= 0.10 && < 1+                     , aeson      >= 1.0 && < 3+                     , containers >= 0.5 && < 1+                     , text       >= 1.2 && < 3+                     , vector     >= 0.11 && < 1   default-language:    Haskell2010 -executable aeson-tiled-exe-  hs-source-dirs:      app-  main-is:             Main.hs-  ghc-options:         -threaded -rtsopts -with-rtsopts=-N-  build-depends:       base-                     , aeson-tiled-  default-language:    Haskell2010+flag tests+  manual: True+  default: False  test-suite aeson-tiled-test+  if !flag(tests)+    buildable: False   type:                exitcode-stdio-1.0   hs-source-dirs:      test   main-is:             Spec.hs@@ -42,9 +43,10 @@                      , aeson >= 1.1                      , aeson-tiled                      , hspec+                     , hspec-discover+                     , bytestring   ghc-options:         -threaded -rtsopts -with-rtsopts=-N   default-language:    Haskell2010--source-repository head-  type:     git-  location: https://github.com/schell/aeson-tiled+  other-modules:+    ParseObjectSpec+    RoundTripSpec
− app/Main.hs
@@ -1,6 +0,0 @@-module Main where--import Data.Aeson.Tiled--main :: IO ()-main = print =<< loadTiledmap "example.json"
src/Data/Aeson/Tiled.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP                        #-} {-# LANGUAGE DeriveGeneric              #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings          #-}@@ -24,8 +25,10 @@ import qualified Data.ByteString.Lazy.Char8 as C8 import           Data.Map                   (Map) import qualified Data.Map                   as M+import           Data.Maybe                 (fromMaybe) import           Data.Text                  (Text) import           Data.Vector                (Vector)+import           GHC.Exts                   (fromList, toList) import           GHC.Generics               (Generic)  @@ -39,33 +42,68 @@   deriving (Ord, Eq, Enum, Num, Generic, Show, FromJSON, ToJSON, FromJSONKey, ToJSONKey)  +data XYPair a = XYPair a a++instance FromJSON a => FromJSON (XYPair a) where+  parseJSON (A.Object o) =+    XYPair <$> o .: "x"+           <*> o .: "y"+  parseJSON invalid = typeMismatch "Object" invalid++instance ToJSON a => ToJSON (XYPair a) where+  toJSON (XYPair x y) =+    object [ "x" .= x+           , "y" .= y+           ]++fromXYPair :: XYPair a -> (a, a)+fromXYPair (XYPair x y) = (x, y)++toXYPair :: (a, a) -> XYPair a+toXYPair (x, y) = XYPair x y++omitNulls :: Value -> Value+omitNulls (A.Object hs) = A.Object+                        . fromList+                        . filter ((/= Null) . snd)+                        $ toList hs+omitNulls x = x++#if MIN_VERSION_aeson(2,0,0)+parseDefault :: FromJSON a => A.Object -> A.Key -> a -> Parser a+#else+parseDefault :: FromJSON a => A.Object -> Text -> a -> Parser a+#endif+parseDefault o s d = fromMaybe d <$> o .:? s++ data Object = Object { objectId         :: Int                        -- ^ Incremental id - unique across all objects-                     , objectWidth      :: Int+                     , objectWidth      :: Double                        -- ^ Width in pixels. Ignored if using a gid.-                     , objectHeight     :: Int+                     , objectHeight     :: Double                        -- ^ Height in pixels. Ignored if using a gid.-                     , objectName       :: String+                     , objectName       :: Text                        -- ^ String assigned to name field in editor-                     , objectType       :: String+                     , objectType       :: Text                        -- ^ String assigned to type field in editor                      , objectProperties :: Map Text Text                        -- ^ String key-value pairs                      , objectVisible    :: Bool                        -- ^ Whether object is shown in editor.-                     , objectX          :: Int+                     , objectX          :: Double                        -- ^ x coordinate in pixels-                     , objectY          :: Int+                     , objectY          :: Double                        -- ^ y coordinate in pixels                      , objectRotation   :: Float                        -- ^ Angle in degrees clockwise-                     , objectGid        :: GlobalId+                     , objectGid        :: Maybe GlobalId                        -- ^ GID, only if object comes from a Tilemap                      , objectEllipse    :: Bool                        -- ^ Used to mark an object as an ellipse-                     , objectPolygon    :: Vector (Int, Int)+                     , objectPolygon    :: Maybe (Vector (Double, Double))                        -- ^ A list of x,y coordinates in pixels-                     , objectPolyline   :: Vector (Int, Int)+                     , objectPolyline   :: Maybe (Vector (Double, Double))                        -- ^ A list of x,y coordinates in pixels                      , objectText       :: Map Text Text                        -- ^ String key-value pairs@@ -77,50 +115,51 @@                                   <*> o .: "height"                                   <*> o .: "name"                                   <*> o .: "type"-                                  <*> o .: "properties"+                                  <*> parseDefault o "properties" M.empty                                   <*> o .: "visible"                                   <*> o .: "x"                                   <*> o .: "y"                                   <*> o .: "rotation"-                                  <*> o .: "gid"-                                  <*> o .: "ellipse"-                                  <*> o .: "polygon"-                                  <*> o .: "polyline"-                                  <*> o .: "text"+                                  <*> o .:? "gid"+                                  <*> parseDefault o "ellipse" False+                                  <*> (fmap . fmap . fmap) fromXYPair (o .:? "polygon")+                                  <*> (fmap . fmap . fmap) fromXYPair (o .:? "polyline")+                                  <*> parseDefault o "text" M.empty   parseJSON invalid = typeMismatch "Object" invalid  instance ToJSON Object where-  toJSON Object{..} = object [ "id"         .= objectId-                             , "width"      .= objectWidth-                             , "height"     .= objectHeight-                             , "name"       .= objectName-                             , "type"       .= objectType-                             , "properties" .= objectProperties-                             , "visible"    .= objectVisible-                             , "x"          .= objectX-                             , "y"          .= objectY-                             , "rotation"   .= objectRotation-                             , "gid"        .= objectGid-                             , "ellipse"    .= objectEllipse-                             , "polygon"    .= objectPolygon-                             , "polyline"   .= objectPolyline-                             , "text"       .= objectText-                             ]+  toJSON Object{..} = omitNulls $+    object [ "id"         .= objectId+           , "width"      .= objectWidth+           , "height"     .= objectHeight+           , "name"       .= objectName+           , "type"       .= objectType+           , "properties" .= objectProperties+           , "visible"    .= objectVisible+           , "x"          .= objectX+           , "y"          .= objectY+           , "rotation"   .= objectRotation+           , "gid"        .= objectGid+           , "ellipse"    .= objectEllipse+           , "polygon"    .= (fmap . fmap) toXYPair objectPolygon+           , "polyline"   .= (fmap . fmap) toXYPair objectPolyline+           , "text"       .= objectText+           ]  -data Layer = Layer { layerWidth      :: Int+data Layer = Layer { layerWidth      :: Double                      -- ^ Column count. Same as map width for fixed-size maps.-                   , layerHeight     :: Int+                   , layerHeight     :: Double                      -- ^ Row count. Same as map height for fixed-size maps.-                   , layerName       :: String+                   , layerName       :: Text                      -- ^ Name assigned to this layer-                   , layerType       :: String+                   , layerType       :: Text -- TODO: LayerType                      -- ^ “tilelayer”, “objectgroup”, or “imagelayer”                    , layerVisible    :: Bool                      -- ^ Whether layer is shown or hidden in editor-                   , layerX          :: Int+                   , layerX          :: Double                      -- ^ Horizontal layer offset in tiles. Always 0.-                   , layerY          :: Int+                   , layerY          :: Double                      -- ^ Vertical layer offset in tiles. Always 0.                    , layerData       :: Maybe (Vector GlobalId)                      -- ^ Array of GIDs. tilelayer only.@@ -130,7 +169,7 @@                      -- ^ string key-value pairs.                    , layerOpacity    :: Float                      -- ^ Value between 0 and 1-                   , layerDraworder  :: String+                   , layerDraworder  :: Text -- TODO: DrawOrder                      -- ^ “topdown” (default) or “index”. objectgroup only.                    } deriving (Eq, Generic, Show) @@ -143,29 +182,30 @@                                  <*>  o .: "x"                                  <*>  o .: "y"                                  <*> (o .: "data"       <|> pure Nothing)-                                 <*> (o .: "objects"    <|> pure Nothing)+                                 <*> o .:? "objects"                                  <*> (o .: "properties" <|> pure mempty)                                  <*>  o .: "opacity"                                  <*> (o .: "draworder"  <|> pure "topdown")   parseJSON invalid = typeMismatch "Layer" invalid  instance ToJSON Layer where-  toJSON Layer{..} = object [ "width"      .= layerWidth-                            , "height"     .= layerHeight-                            , "name"       .= layerName-                            , "type"       .= layerType-                            , "visible"    .= layerVisible-                            , "x"          .= layerX-                            , "y"          .= layerY-                            , "data"       .= layerData-                            , "objects"    .= layerObjects-                            , "properties" .= layerProperties-                            , "opacity"    .= layerOpacity-                            , "draworder"  .= layerDraworder-                            ]+  toJSON Layer{..} = omitNulls $+    object [ "width"      .= layerWidth+           , "height"     .= layerHeight+           , "name"       .= layerName+           , "type"       .= layerType+           , "visible"    .= layerVisible+           , "x"          .= layerX+           , "y"          .= layerY+           , "data"       .= layerData+           , "objects"    .= layerObjects+           , "properties" .= layerProperties+           , "opacity"    .= layerOpacity+           , "draworder"  .= layerDraworder+           ]  -data Terrain = Terrain { terrainName :: String+data Terrain = Terrain { terrainName :: Text                          -- ^ Name of terrain                        , terrainTile :: LocalId                          -- ^ Local ID of tile representing terrain@@ -189,12 +229,12 @@  instance FromJSON Frame where   parseJSON (A.Object o) = Frame <$> o .: "duration"-                                 <*> o .: "tileId"+                                 <*> o .: "tileid"   parseJSON invalid = typeMismatch "Frame" invalid  instance ToJSON Frame where   toJSON Frame{..} = object [ "duration" .= frameDuration-                            , "tileId"   .= frameTileId+                            , "tileid"   .= frameTileId                             ]  @@ -222,9 +262,9 @@  data Tileset = Tileset { tilesetFirstgid       :: GlobalId                          -- ^ GID corresponding to the first tile in the set-                       , tilesetImage          :: String+                       , tilesetImage          :: FilePath                          -- ^ Image used for tiles in this set-                       , tilesetName           :: String+                       , tilesetName           :: Text                          -- ^ Name given to this tileset                        , tilesetTilewidth      :: Int                          -- ^ Maximum width of tiles in this set@@ -303,29 +343,65 @@                               , "tiles"          .= tilesetTiles                               ] +data Version+  = VersionFloat Float+  | VersionText Text+  deriving (Eq, Ord, Show, Generic) +instance FromJSON Version where+  parseJSON v =+    fmap VersionFloat (parseJSON v) <|>+    fmap VersionText (parseJSON v)++instance ToJSON Version where+  toJSON version = case version of+    VersionFloat f -> toJSON f+    VersionText t  -> toJSON t++data Orientation+  = Orthogonal+  | Isometric+  | Staggered+  | Orientation Text+  deriving (Eq, Ord, Show, Generic)++instance FromJSON Orientation where+  parseJSON = withText "Orientation" $ \t ->+    case t of+      "orthogonal" -> pure Orthogonal+      "isometric"  -> pure Isometric+      "staggered"  -> pure Staggered+      _otherwise   -> pure $ Orientation t++instance ToJSON Orientation where+  toJSON o = toJSON $ case o of+    Orthogonal    -> "orthogonal"+    Isometric     -> "isometric"+    Staggered     -> "staggered"+    Orientation t -> t+ -- | The full monty.-data Tiledmap = Tiledmap { tiledmapVersion         :: Float+data Tiledmap = Tiledmap { tiledmapVersion         :: Version                            -- ^ The JSON format version-                         , tiledmapTiledversion    :: String+                         , tiledmapTiledversion    :: Version                            -- ^ The Tiled version used to save the file                          , tiledmapWidth           :: Int                            -- ^ Number of tile columns                          , tiledmapHeight          :: Int                            -- ^ Number of tile rows-                         , tiledmapTilewidth       :: Int+                         , tiledmapTilewidth       :: Double                            -- ^ Map grid width.-                         , tiledmapTileheight      :: Int+                         , tiledmapTileheight      :: Double                            -- ^ Map grid height.-                         , tiledmapOrientation     :: String+                         , tiledmapOrientation     :: Orientation                            -- ^ Orthogonal, isometric, or staggered                          , tiledmapLayers          :: Vector Layer                            -- ^ Array of Layers                          , tiledmapTilesets        :: Vector Tileset                            -- ^ Array of Tilesets-                         , tiledmapBackgroundcolor :: Maybe String+                         , tiledmapBackgroundcolor :: Maybe Text                            -- ^ Hex-formatted color (#RRGGBB or #AARRGGBB) (optional)-                         , tiledmapRenderorder     :: String+                         , tiledmapRenderorder     :: Text -- TODO: RenderOrder                            -- ^ Rendering direction (orthogonal maps only)                          , tiledmapProperties      :: Map Text Text                            -- ^ String key-value pairs
+ test/ParseObjectSpec.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications  #-}++module ParseObjectSpec where++import Data.Aeson (encode, eitherDecode)+import Test.Hspec+import Data.Either (isRight)+import Control.Monad (forM_)+import qualified Data.ByteString.Lazy.Char8 as C8++import Data.Aeson.Tiled++file :: FilePath+file = "maps/objects/obj1.json"++spec :: Spec+spec = describe "Obj1" $ do+  it "should parse just fine" $ do+    eobj <- fmap (eitherDecode @Object) $ C8.readFile file+    eobj `shouldSatisfy` isRight+
+ test/RoundTripSpec.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE LambdaCase #-}++module RoundTripSpec where++import Data.Aeson (encode, eitherDecode)+import Test.Hspec+import Control.Monad (forM_)++import Data.Aeson.Tiled++files :: [FilePath]+files = [ "maps/example.json"+        , "maps/test1.json"+        , "maps/test2.json"+        , "maps/test3.json"+        , "maps/test4.json"+        ]++spec :: Spec+spec = describe "Round tripping" . forM_ files $ \file ->+    it (file ++ " should roundtrip and end up with the same Tiledmap") $+      loadTiledmap file >>= \case+        Right tm -> do+          let bs = encode tm+          eitherDecode bs `shouldBe` Right tm+        Left x -> fail x
test/Spec.hs view
@@ -1,24 +1,1 @@-{-# LANGUAGE LambdaCase #-}-import Data.Aeson (encode, eitherDecode)-import Test.Hspec-import Control.Monad (forM_)--import Data.Aeson.Tiled--files :: [FilePath]-files = [ "maps/example.json"-        , "maps/test1.json"-        , "maps/test2.json"-        , "maps/test3.json"-        , "maps/test4.json"-        ]--main :: IO ()-main = hspec $ forM_ files $ \file ->-  describe ("With " ++ show file) $-    it "loading and encoding and decoding should end up with the same Tiledmap" $-      loadTiledmap file >>= \case-        Right tm -> do-          let bs = encode tm-          eitherDecode bs `shouldBe` Right tm-        _ -> fail $ "Could not decode Tiledmap from " ++ show file+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}