|
32 | 32 |
|
33 | 33 | import Control.Applicative ((<|>)) |
34 | 34 | import Control.Monad (void) |
| 35 | +import Control.Monad.State (modify) |
| 36 | +import Data.HashMap.Strict qualified as HashMap |
35 | 37 | import Data.List (sortOn) |
36 | 38 | import Data.Maybe (fromMaybe) |
37 | 39 | import Data.Ord (Down (Down)) |
@@ -138,7 +140,7 @@ data PackageVersionSpec = PackageVersionSpec |
138 | 140 | sourceMetaCodec :: TomlCodec PackageVersionSpec |
139 | 141 | sourceMetaCodec = |
140 | 142 | PackageVersionSpec |
141 | | - <$> Toml.dioptional (timeCodec "timestamp") |
| 143 | + <$> optionalTimeCodec "timestamp" |
142 | 144 | .= packageVersionTimestamp |
143 | 145 | <*> packageSourceCodec |
144 | 146 | .= packageVersionSource |
@@ -200,3 +202,37 @@ withDefault :: (Eq a) => a -> TomlCodec a -> TomlCodec a |
200 | 202 | withDefault d c = (fromMaybe d <$> Toml.dioptional c) .= f |
201 | 203 | where |
202 | 204 | f a = if a == d then Nothing else Just a |
| 205 | + |
| 206 | +-- | Codec for a maybe-missing time value. |
| 207 | +-- |
| 208 | +-- Note this is different from dioptional timeCodec. With dioptional timeCodec, |
| 209 | +-- if the user writes |
| 210 | +-- timestamp = '2022-08-22T10:38:45Z' |
| 211 | +-- rather than |
| 212 | +-- timestamp = 2022-08-22T10:38:45Z |
| 213 | +-- the timestamp will parse as Nothing because it won't match the zoneTime |
| 214 | +-- type and it is not an error because it is optional. |
| 215 | +-- |
| 216 | +-- We use a handrolled version of match (matchMaybe) to make it work. |
| 217 | +-- |
| 218 | +-- See discussions at |
| 219 | +-- 1. https://github.com/input-output-hk/foliage/issues/11 |
| 220 | +-- 2. https://github.com/input-output-hk/foliage/pull/57 |
| 221 | +-- 3. https://github.com/kowainik/tomland/issues/223 |
| 222 | +optionalTimeCodec :: Toml.Key -> TomlCodec (Maybe UTCTime) |
| 223 | +optionalTimeCodec key = |
| 224 | + Toml.dimap (fmap $ utcToZonedTime utc) (fmap zonedTimeToUTC) $ matchMaybe Toml._ZonedTime key |
| 225 | + |
| 226 | +matchMaybe :: forall a. Toml.TomlBiMap a Toml.AnyValue -> Toml.Key -> TomlCodec (Maybe a) |
| 227 | +matchMaybe bimap key = Toml.Codec input output |
| 228 | + where |
| 229 | + input :: Toml.TomlEnv (Maybe a) |
| 230 | + input toml = case HashMap.lookup key (Toml.tomlPairs toml) of |
| 231 | + Nothing -> pure Nothing |
| 232 | + Just anyVal -> pure <$> Toml.whenLeftBiMapError key (Toml.backward bimap anyVal) pure |
| 233 | + |
| 234 | + output :: Maybe a -> Toml.TomlState (Maybe a) |
| 235 | + output Nothing = pure Nothing |
| 236 | + output (Just a) = do |
| 237 | + anyVal <- Toml.eitherToTomlState $ Toml.forward bimap a |
| 238 | + Just a <$ modify (Toml.insertKeyAnyVal key anyVal) |
0 commit comments