yamlet
Safe HaskellNone
LanguageGHC2021

Yamlet.Decode

Description

Conversion of nodes to Haskell values, with errors that point to the node that caused them.

Synopsis

Class

class FromYaml a where Source #

Types that can be parsed from a node. A type with a Generic instance can derive the instance via GenericYaml.

An instance for a record reads a mapping with withMapping:

>>> :{
data Server = Server {host :: T.Text, port :: Int, tags :: [T.Text]}
  deriving stock (Show)
instance FromYaml Server where
  parseYaml = withMapping $ \o ->
    rejectUnknownKeys ["host", "port", "tags"] o
      *> ( Server
             <$> parseField o "host"
             <*> parseFieldDefault o "port" 80
             <*> parseFieldDefault o "tags" []
         )
:}
>>> decodeText @Server "host: example.com\ntags:\n- web\n"
Right (Server {host = "example.com", port = 80, tags = ["web"]})

The decoder reports the errors of all fields together:

>>> either printErrors print (decodeText @Server "hots: example.com\nport: http\n")
input.yaml:1:1: unknown key "hots", did you mean "host"?
  |
1 | hots: example.com
  | ^
input.yaml:1:1: missing key "host"
  |
1 | hots: example.com
  | ^
input.yaml:2:7: port: expected an integer, but got a string
  |
2 | port: http
  |       ^

The instances of the library copy the texts that they keep, so a decoded value does not keep the input in memory. A value from a hand-written instance can keep the input while it has unevaluated parts, e.g. a lazy list. Evaluate such a value, e.g. with force, to release the input.

Minimal complete definition

parseYaml

Methods

parseYaml :: Node -> Parser a Source #

parseYamlList :: Node -> Parser [a] Source #

Parse a list. The instance for Char parses a string instead.

parseYamlField :: Node -> Node -> Parser a Source #

Parse the value of a mapping entry, with its key, e.g. to keep the comments of the key as Commented does. parseField and the other lookups without a parser argument, the derived decoders and the instances for maps use it. The default ignores the key.

Instances

Instances details
FromYaml IntSet Source #

A list. Two elements that convert to the same value, e.g. 1 and 0x1, are an error.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser IntSet Source #

parseYamlList :: Node -> Parser [IntSet] Source #

parseYamlField :: Node -> Node -> Parser IntSet Source #

FromYaml Void Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml All Source #

The value inside.

Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml Any Source #

The value inside.

Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml Int16 Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser Int16 Source #

parseYamlList :: Node -> Parser [Int16] Source #

parseYamlField :: Node -> Node -> Parser Int16 Source #

FromYaml Int32 Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser Int32 Source #

parseYamlList :: Node -> Parser [Int32] Source #

parseYamlField :: Node -> Node -> Parser Int32 Source #

FromYaml Int64 Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser Int64 Source #

parseYamlList :: Node -> Parser [Int64] Source #

parseYamlField :: Node -> Node -> Parser Int64 Source #

FromYaml Int8 Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml Word16 Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser Word16 Source #

parseYamlList :: Node -> Parser [Word16] Source #

parseYamlField :: Node -> Node -> Parser Word16 Source #

FromYaml Word32 Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser Word32 Source #

parseYamlList :: Node -> Parser [Word32] Source #

parseYamlField :: Node -> Node -> Parser Word32 Source #

FromYaml Word64 Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser Word64 Source #

parseYamlList :: Node -> Parser [Word64] Source #

parseYamlField :: Node -> Node -> Parser Word64 Source #

FromYaml Word8 Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser Word8 Source #

parseYamlList :: Node -> Parser [Word8] Source #

parseYamlField :: Node -> Node -> Parser Word8 Source #

FromYaml Ordering Source #

LT, EQ or GT.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser Ordering Source #

parseYamlList :: Node -> Parser [Ordering] Source #

parseYamlField :: Node -> Node -> Parser Ordering Source #

FromYaml Scientific Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser Scientific Source #

parseYamlList :: Node -> Parser [Scientific] Source #

parseYamlField :: Node -> Node -> Parser Scientific Source #

FromYaml Text Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml Text Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml CalendarDiffDays Source #

A mapping with the keys months and days, e.g. {months: 1, days: 2}.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser CalendarDiffDays Source #

parseYamlList :: Node -> Parser [CalendarDiffDays] Source #

parseYamlField :: Node -> Node -> Parser CalendarDiffDays Source #

FromYaml Day Source #

YYYY-MM-DD, e.g. 2026-09-25. The year has at most 15 digits, here and in the other types with a date.

Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml Month Source #

YYYY-MM, e.g. 2026-09.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser Month Source #

parseYamlList :: Node -> Parser [Month] Source #

parseYamlField :: Node -> Node -> Parser Month Source #

FromYaml Quarter Source #

YYYY-qN, e.g. 2026-q3.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser Quarter Source #

parseYamlList :: Node -> Parser [Quarter] Source #

parseYamlField :: Node -> Node -> Parser Quarter Source #

FromYaml QuarterOfYear Source #

q1 to q4.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser QuarterOfYear Source #

parseYamlList :: Node -> Parser [QuarterOfYear] Source #

parseYamlField :: Node -> Node -> Parser QuarterOfYear Source #

FromYaml DayOfWeek Source #

The English name in any case, e.g. monday.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser DayOfWeek Source #

parseYamlList :: Node -> Parser [DayOfWeek] Source #

parseYamlField :: Node -> Node -> Parser DayOfWeek Source #

FromYaml DiffTime Source #

A number of seconds, rounded down to a picosecond.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser DiffTime Source #

parseYamlList :: Node -> Parser [DiffTime] Source #

parseYamlField :: Node -> Node -> Parser DiffTime Source #

FromYaml NominalDiffTime Source #

A number of seconds, rounded down to a picosecond.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser NominalDiffTime Source #

parseYamlList :: Node -> Parser [NominalDiffTime] Source #

parseYamlField :: Node -> Node -> Parser NominalDiffTime Source #

FromYaml UTCTime Source #

Like ZonedTime, converted to UTC.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser UTCTime Source #

parseYamlList :: Node -> Parser [UTCTime] Source #

parseYamlField :: Node -> Node -> Parser UTCTime Source #

FromYaml CalendarDiffTime Source #

A mapping with the keys months and time, a number of seconds, e.g. {months: 1, time: 1.5}.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser CalendarDiffTime Source #

parseYamlList :: Node -> Parser [CalendarDiffTime] Source #

parseYamlField :: Node -> Node -> Parser CalendarDiffTime Source #

FromYaml LocalTime Source #

A date and a time, separated by T or a space, e.g. 2026-09-25T12:30:00.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser LocalTime Source #

parseYamlList :: Node -> Parser [LocalTime] Source #

parseYamlField :: Node -> Node -> Parser LocalTime Source #

FromYaml TimeOfDay Source #

HH:MM, with optional seconds and a fraction of a second of at most 12 digits, e.g. 12:30:05.25.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser TimeOfDay Source #

parseYamlList :: Node -> Parser [TimeOfDay] Source #

parseYamlField :: Node -> Node -> Parser TimeOfDay Source #

FromYaml ZonedTime Source #

A date, a time and a time zone, e.g. 2026-09-25T12:30:00+02:00. The time zone is Z, +HH:MM, +HHMM or +HH.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser ZonedTime Source #

parseYamlList :: Node -> Parser [ZonedTime] Source #

parseYamlField :: Node -> Node -> Parser ZonedTime Source #

FromYaml UUID Source #

The text form with hyphens, e.g. 123e4567-e89b-12d3-a456-426614174000.

Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml Node Source #

The node of the syntax tree, with its styles and comments, e.g. to write a part of a document back as it was written. An alias in the input gives a copy of the node that it refers to.

The texts of the node are copies, so that a small part of a document does not keep the whole input alive. For a whole document without a copy, use parseDocuments.

Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml Value Source #

The value of the node, with the tags resolved and the aliases replaced.

Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml Integer Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser Integer Source #

parseYamlList :: Node -> Parser [Integer] Source #

parseYamlField :: Node -> Node -> Parser Integer Source #

FromYaml Natural Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser Natural Source #

parseYamlList :: Node -> Parser [Natural] Source #

parseYamlField :: Node -> Node -> Parser Natural Source #

FromYaml () Source #

An empty list, as a tuple without elements.

Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml Bool Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml Char Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml Double Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser Double Source #

parseYamlList :: Node -> Parser [Double] Source #

parseYamlField :: Node -> Node -> Parser Double Source #

FromYaml Float Source #

The nearest float. A conversion by way of Double could round twice.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser Float Source #

parseYamlList :: Node -> Parser [Float] Source #

parseYamlField :: Node -> Node -> Parser Float Source #

FromYaml Int Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml Word Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml a => FromYaml (First a) Source #

The value inside.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (First a) Source #

parseYamlList :: Node -> Parser [First a] Source #

parseYamlField :: Node -> Node -> Parser (First a) Source #

FromYaml a => FromYaml (Last a) Source #

The value inside.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Last a) Source #

parseYamlList :: Node -> Parser [Last a] Source #

parseYamlField :: Node -> Node -> Parser (Last a) Source #

FromYaml a => FromYaml (Max a) Source #

The value inside.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Max a) Source #

parseYamlList :: Node -> Parser [Max a] Source #

parseYamlField :: Node -> Node -> Parser (Max a) Source #

FromYaml a => FromYaml (Min a) Source #

The value inside.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Min a) Source #

parseYamlList :: Node -> Parser [Min a] Source #

parseYamlField :: Node -> Node -> Parser (Min a) Source #

FromYaml v => FromYaml (IntMap v) Source #

Two keys that convert to the same key are an error.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (IntMap v) Source #

parseYamlList :: Node -> Parser [IntMap v] Source #

parseYamlField :: Node -> Node -> Parser (IntMap v) Source #

FromYaml a => FromYaml (Seq a) Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Seq a) Source #

parseYamlList :: Node -> Parser [Seq a] Source #

parseYamlField :: Node -> Node -> Parser (Seq a) Source #

(Ord a, FromYaml a) => FromYaml (Set a) Source #

A list. Two elements that convert to the same value, e.g. 1 and 1.0 for Double, are an error.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Set a) Source #

parseYamlList :: Node -> Parser [Set a] Source #

parseYamlField :: Node -> Node -> Parser (Set a) Source #

FromYaml a => FromYaml (Tree a) Source #

A list of the label and the subtrees, e.g. [a, [[b, []]]].

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Tree a) Source #

parseYamlList :: Node -> Parser [Tree a] Source #

parseYamlField :: Node -> Node -> Parser (Tree a) Source #

FromYaml a => FromYaml (NonEmpty a) Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (NonEmpty a) Source #

parseYamlList :: Node -> Parser [NonEmpty a] Source #

parseYamlField :: Node -> Node -> Parser (NonEmpty a) Source #

FromYaml a => FromYaml (Identity a) Source #

The value inside.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Identity a) Source #

parseYamlList :: Node -> Parser [Identity a] Source #

parseYamlField :: Node -> Node -> Parser (Identity a) Source #

FromYaml a => FromYaml (First a) Source #

The value inside, or null for Nothing.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (First a) Source #

parseYamlList :: Node -> Parser [First a] Source #

parseYamlField :: Node -> Node -> Parser (First a) Source #

FromYaml a => FromYaml (Last a) Source #

The value inside, or null for Nothing.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Last a) Source #

parseYamlList :: Node -> Parser [Last a] Source #

parseYamlField :: Node -> Node -> Parser (Last a) Source #

FromYaml a => FromYaml (Down a) Source #

The value inside.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Down a) Source #

parseYamlList :: Node -> Parser [Down a] Source #

parseYamlField :: Node -> Node -> Parser (Down a) Source #

FromYaml a => FromYaml (Dual a) Source #

The value inside.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Dual a) Source #

parseYamlList :: Node -> Parser [Dual a] Source #

parseYamlField :: Node -> Node -> Parser (Dual a) Source #

FromYaml a => FromYaml (Product a) Source #

The value inside.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Product a) Source #

parseYamlList :: Node -> Parser [Product a] Source #

parseYamlField :: Node -> Node -> Parser (Product a) Source #

FromYaml a => FromYaml (Sum a) Source #

The value inside.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Sum a) Source #

parseYamlList :: Node -> Parser [Sum a] Source #

parseYamlField :: Node -> Node -> Parser (Sum a) Source #

(Integral a, FromYaml a) => FromYaml (Ratio a) Source #

A mapping with the keys numerator and denominator, e.g. {numerator: 1, denominator: 3}.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Ratio a) Source #

parseYamlList :: Node -> Parser [Ratio a] Source #

parseYamlField :: Node -> Node -> Parser (Ratio a) Source #

(Generic a, GenericYamlOptions a, GDatatype (Rep a), Constructors (Rep a) ~ f, GConstructors f, GEncoding (SumEncoding a) f, GFromConstructor f, FromYaml a) => FromYaml (GenericYaml a) Source # 
Instance details

Defined in Yamlet.Generic

FromYaml a => FromYaml (Commented a) Source #

The value with the comments of its entry, or of its node if it has no key, copied like every decoded text.

Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml a => FromYaml (Located a) Source #

The value with the offset of its node. The key of an entry goes to the value inside, e.g. for a Commented value.

Instance details

Defined in Yamlet.Internal.FromYaml

FromYaml a => FromYaml (Maybe a) Source #

Null is Nothing. The key of an entry goes to the value inside, e.g. for a Commented value.

>>> decodeText @[Maybe Int] "- 1\n- null\n- ~\n-\n"
Right [Just 1,Nothing,Nothing,Nothing]
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Maybe a) Source #

parseYamlList :: Node -> Parser [Maybe a] Source #

parseYamlField :: Node -> Node -> Parser (Maybe a) Source #

FromYaml a => FromYaml [a] Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

HasResolution a => FromYaml (Fixed a) Source #

A number that is a multiple of the step of the type, e.g. 1.25 for Centi. A number with more digits after the point is an error, not a rounded value.

If the resolution is not a product of 2s and 5s, e.g. 3, most multiples of the step have no decimal form, so they cannot come from YAML. For such a resolution, use Rational instead.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Fixed a) Source #

parseYamlList :: Node -> Parser [Fixed a] Source #

parseYamlField :: Node -> Node -> Parser (Fixed a) Source #

(Ord k, FromYaml k, FromYaml v) => FromYaml (Map k v) Source #

Two keys that convert to the same key, e.g. 1 and 1.0 for Double, are an error.

Each key decodes with the instance of its type, so a map with Text keys rejects a key such as 404 or true, because YAML reads it as an integer or a boolean. Quote such a key in the input, e.g. "404": not found, or use a key type that matches it, e.g. Int.

>>> decodeText @(M.Map Int T.Text) "404: not found\n"
Right (fromList [(404,"not found")])
>>> either printErrors print (decodeText @(M.Map T.Text T.Text) "404: not found\n")
input.yaml:1:1: expected a string, but got an integer, quote the value, e.g. '404'
  |
1 | 404: not found
  | ^
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Map k v) Source #

parseYamlList :: Node -> Parser [Map k v] Source #

parseYamlField :: Node -> Node -> Parser (Map k v) Source #

(FromYaml a, FromYaml b) => FromYaml (Either a b) Source #

A mapping with one key, Left or Right, e.g. {Left: 1}.

>>> decodeText @(Either Int T.Text) "Left: 1\n"
Right (Left 1)
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Either a b) Source #

parseYamlList :: Node -> Parser [Either a b] Source #

parseYamlField :: Node -> Node -> Parser (Either a b) Source #

(FromYaml a1, FromYaml a2) => FromYaml (a1, a2) Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (a1, a2) Source #

parseYamlList :: Node -> Parser [(a1, a2)] Source #

parseYamlField :: Node -> Node -> Parser (a1, a2) Source #

FromYaml a => FromYaml (Const a b) Source #

The value inside.

Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (Const a b) Source #

parseYamlList :: Node -> Parser [Const a b] Source #

parseYamlField :: Node -> Node -> Parser (Const a b) Source #

(FromYaml a1, FromYaml a2, FromYaml a3) => FromYaml (a1, a2, a3) Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (a1, a2, a3) Source #

parseYamlList :: Node -> Parser [(a1, a2, a3)] Source #

parseYamlField :: Node -> Node -> Parser (a1, a2, a3) Source #

(FromYaml a1, FromYaml a2, FromYaml a3, FromYaml a4) => FromYaml (a1, a2, a3, a4) Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (a1, a2, a3, a4) Source #

parseYamlList :: Node -> Parser [(a1, a2, a3, a4)] Source #

parseYamlField :: Node -> Node -> Parser (a1, a2, a3, a4) Source #

(FromYaml a1, FromYaml a2, FromYaml a3, FromYaml a4, FromYaml a5) => FromYaml (a1, a2, a3, a4, a5) Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (a1, a2, a3, a4, a5) Source #

parseYamlList :: Node -> Parser [(a1, a2, a3, a4, a5)] Source #

parseYamlField :: Node -> Node -> Parser (a1, a2, a3, a4, a5) Source #

(FromYaml a1, FromYaml a2, FromYaml a3, FromYaml a4, FromYaml a5, FromYaml a6) => FromYaml (a1, a2, a3, a4, a5, a6) Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (a1, a2, a3, a4, a5, a6) Source #

parseYamlList :: Node -> Parser [(a1, a2, a3, a4, a5, a6)] Source #

parseYamlField :: Node -> Node -> Parser (a1, a2, a3, a4, a5, a6) Source #

(FromYaml a1, FromYaml a2, FromYaml a3, FromYaml a4, FromYaml a5, FromYaml a6, FromYaml a7) => FromYaml (a1, a2, a3, a4, a5, a6, a7) Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (a1, a2, a3, a4, a5, a6, a7) Source #

parseYamlList :: Node -> Parser [(a1, a2, a3, a4, a5, a6, a7)] Source #

parseYamlField :: Node -> Node -> Parser (a1, a2, a3, a4, a5, a6, a7) Source #

(FromYaml a1, FromYaml a2, FromYaml a3, FromYaml a4, FromYaml a5, FromYaml a6, FromYaml a7, FromYaml a8) => FromYaml (a1, a2, a3, a4, a5, a6, a7, a8) Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (a1, a2, a3, a4, a5, a6, a7, a8) Source #

parseYamlList :: Node -> Parser [(a1, a2, a3, a4, a5, a6, a7, a8)] Source #

parseYamlField :: Node -> Node -> Parser (a1, a2, a3, a4, a5, a6, a7, a8) Source #

(FromYaml a1, FromYaml a2, FromYaml a3, FromYaml a4, FromYaml a5, FromYaml a6, FromYaml a7, FromYaml a8, FromYaml a9) => FromYaml (a1, a2, a3, a4, a5, a6, a7, a8, a9) Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (a1, a2, a3, a4, a5, a6, a7, a8, a9) Source #

parseYamlList :: Node -> Parser [(a1, a2, a3, a4, a5, a6, a7, a8, a9)] Source #

parseYamlField :: Node -> Node -> Parser (a1, a2, a3, a4, a5, a6, a7, a8, a9) Source #

(FromYaml a1, FromYaml a2, FromYaml a3, FromYaml a4, FromYaml a5, FromYaml a6, FromYaml a7, FromYaml a8, FromYaml a9, FromYaml a10) => FromYaml (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

parseYaml :: Node -> Parser (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) Source #

parseYamlList :: Node -> Parser [(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)] Source #

parseYamlField :: Node -> Node -> Parser (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) Source #

Parser

data Parser a Source #

A parser of nodes. Its errors point to the node that the parser works on, unless failAt names another one.

The parser has no Alternative instance. To try another parser after a failure, use orElse. To reject a value, fail with a message that says why:

port <- parseYaml n
unless (port > 0 && port < 65536) $ fail "the port must be from 1 to 65535"

The applicative operators collect the errors of both parts: <*>, *>, <*, liftA2, and the functions that use them, e.g. traverse, mapM on a list and for_. This parser gives the errors of the unknown keys and of all fields together:

rejectUnknownKeys ["name", "paths"] o
  *> (Config <$> parseField o "name" <*> parseField o "paths")

>>= and >> stop at the first error. A statement of a do block also stops, e.g. the check of the port above. The functions that use >> also stop, e.g. mapM_ and forM_.

The choice between them changes only the errors, never the result. With ApplicativeDo, GHC turns the independent statements of a do block that ends with pure into <*>. Then they collect errors.

Instances

Instances details
Applicative Parser Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

pure :: a -> Parser a

(<*>) :: Parser (a -> b) -> Parser a -> Parser b

liftA2 :: (a -> b -> c) -> Parser a -> Parser b -> Parser c

(*>) :: Parser a -> Parser b -> Parser b

(<*) :: Parser a -> Parser b -> Parser a

Functor Parser Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

fmap :: (a -> b) -> Parser a -> Parser b

(<$) :: a -> Parser b -> Parser a

Monad Parser Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

(>>=) :: Parser a -> (a -> Parser b) -> Parser b

(>>) :: Parser a -> Parser b -> Parser b

return :: a -> Parser a

MonadFail Parser Source # 
Instance details

Defined in Yamlet.Internal.FromYaml

Methods

fail :: String -> Parser a

runParser :: (Node -> Parser a) -> Node -> Either (NonEmpty (Offset, String)) a Source #

Run a parser on a node. Each error is the offset of the node that caused it and the message. The errors are in the order of the offsets, and equal errors come only once. A note on an error comes right after it, e.g. the first key of a duplicate key.

First, the function makes the checks of decodeDocument on the node, e.g. for duplicate keys. It also replaces each alias with the node that the alias refers to. If a check fails, the result has only the error of that check, with its notes.

parseNode :: (Node -> Parser a) -> Node -> Parser a Source #

Run a parser on a node, so that fail points to the node.

failAt :: Node -> String -> Parser a Source #

Fail with an error that points to the given node.

typeMismatch :: String -> Node -> Parser a Source #

Fail with an error that the node is not of the expected kind, e.g. typeMismatch "a list" n gives "expected a list, but got a string".

orElse :: Parser a -> Parser a -> Parser a infixl 3 Source #

Run the second parser if the first one fails. A port can be a number or a name:

>>> :{
newtype Port = Port (Either Integer T.Text)
  deriving stock (Show)
instance FromYaml Port where
  parseYaml n =
    Port <$> ((Left <$> withInt pure n) `orElse` (Right <$> withText pure n))
:}
>>> decodeText @Port "8080"
Right (Port (Left 8080))
>>> decodeText @Port "http"
Right (Port (Right "http"))

If both parsers fail, the result has only the errors of the second one:

>>> either printErrors print (decodeText @Port "[80]")
input.yaml:1:1: expected a string, but got a list
  |
1 | [80]
  | ^

Views

data View Source #

The value of a node with its tag resolved. The items and the entries of a collection stay nodes of the syntax tree. A tag that the schema does not know does not matter, e.g. !secret abc is a string.

Constructors

NullView 
BoolView !Bool 
IntView !Integer 
FloatView !FloatValue 
StringView !Text 
SequenceView ![Node] 
MappingView ![(Node, Node)] 
AliasView !Text

An alias, e.g. in a node from parseDocuments. runParser replaces the aliases, so a parser never sees one.

Instances

Instances details
Generic View Source # 
Instance details

Defined in Yamlet.Internal.View

Associated Types

type Rep View 
Instance details

Defined in Yamlet.Internal.View

type Rep View = D1 ('MetaData "View" "Yamlet.Internal.View" "yamlet-1.0.0.1-2nRkbEnNUrLFBALTocq2AS" 'False) (((C1 ('MetaCons "NullView" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "BoolView" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Bool))) :+: (C1 ('MetaCons "IntView" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Integer)) :+: C1 ('MetaCons "FloatView" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 FloatValue)))) :+: ((C1 ('MetaCons "StringView" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text)) :+: C1 ('MetaCons "SequenceView" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 [Node]))) :+: (C1 ('MetaCons "MappingView" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 [(Node, Node)])) :+: C1 ('MetaCons "AliasView" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text)))))

Methods

from :: View -> Rep View x

to :: Rep View x -> View

Show View Source # 
Instance details

Defined in Yamlet.Internal.View

Methods

showsPrec :: Int -> View -> ShowS

show :: View -> String

showList :: [View] -> ShowS

Eq View Source # 
Instance details

Defined in Yamlet.Internal.View

Methods

(==) :: View -> View -> Bool

(/=) :: View -> View -> Bool

type Rep View Source # 
Instance details

Defined in Yamlet.Internal.View

type Rep View = D1 ('MetaData "View" "Yamlet.Internal.View" "yamlet-1.0.0.1-2nRkbEnNUrLFBALTocq2AS" 'False) (((C1 ('MetaCons "NullView" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "BoolView" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Bool))) :+: (C1 ('MetaCons "IntView" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Integer)) :+: C1 ('MetaCons "FloatView" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 FloatValue)))) :+: ((C1 ('MetaCons "StringView" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text)) :+: C1 ('MetaCons "SequenceView" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 [Node]))) :+: (C1 ('MetaCons "MappingView" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 [(Node, Node)])) :+: C1 ('MetaCons "AliasView" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text)))))

view :: Node -> View Source #

The view of a node.

describeNode :: Node -> String Source #

The kind of a node in plain words, e.g. "a list".

>>> map describeNode <$> decodeText @[Node] "- [1, 2]\n- 3.5\n- ~\n- !!str 12\n"
Right ["a list","a floating-point number","null","a string"]

Scalars

withNull :: Parser a -> Node -> Parser a Source #

Run the parser if the node is null.

withBool :: (Bool -> Parser a) -> Node -> Parser a Source #

The value of a boolean.

withInt :: (Integer -> Parser a) -> Node -> Parser a Source #

The value of an integer.

withFloat :: (Double -> Parser a) -> Node -> Parser a Source #

The nearest double. An integer counts as a floating-point number too.

withScientific :: (Scientific -> Parser a) -> Node -> Parser a Source #

The exact value of a finite number. An integer counts too, and negative zero becomes 0.

A conversion to an exact type, e.g. with truncate, is safe for untrusted input. An integer has the digits of its text, and the decoder rejects a float whose exponent in scientific notation is beyond the range from -1000 to 1000, also in a node that a program built.

withText :: (Text -> Parser a) -> Node -> Parser a Source #

The text of a string. The text is a copy, so it does not keep the input alive. For a plain scalar that YAML reads as a number or a boolean, e.g. 3.10, the error suggests quotes.

oneOf :: [(Text, a)] -> Node -> Parser a Source #

The value that goes with the string in the list of pairs, e.g. for names that the program knows only at run time. An empty list rejects every value. The errors are the same as for the constructors of an enumeration. An unknown name gets the closest name or the list of names:

>>> :{
newtype Size = Size Int
  deriving stock (Show)
instance FromYaml Size where
  parseYaml = oneOf [("small", Size 1), ("large", Size 2)]
:}
>>> decodeText @Size "large"
Right (Size 2)
>>> either printErrors print (decodeText @Size "lage")
input.yaml:1:1: unknown value "lage", did you mean "large"?
  |
1 | lage
  | ^

Collections

withSequence :: ([Node] -> Parser a) -> Node -> Parser a Source #

The items of a sequence. As for withMapping, the comments of the sequence stay with it, not with its first item.

parseItems :: (Node -> Parser a) -> [Node] -> Parser [a] Source #

The values of the items, with the errors of all items, as with mapM. Unlike mapM, the stack does not grow with the number of items, because the errors and the values are in accumulators until the end. A decoder of a list is withSequence (parseItems parseYaml).

withMapping :: (Object -> Parser a) -> Node -> Parser a Source #

The entries of a mapping. As for withText, the tag of a string key does not matter, so two string keys with the same text are an error, e.g. a and !foo a.

The comments of the mapping stay with it, not with its first key, e.g. a comment at the top of a file. A record has no place for them.

data Object Source #

A mapping with fast access to the values of string keys.

objectNode :: Object -> Node Source #

The node of the mapping.

objectEntries :: Object -> [(Node, Node)] Source #

The entries of the mapping in the order of the input.

objectKeys :: Object -> [Text] Source #

The string keys of the mapping in the order of the input.

lookupKey :: Object -> Text -> Parser (Maybe Node) Source #

The value of a key, or Nothing if the key is missing. As for parseField, a key with the same text that is not a string, e.g. 404, is an error, so that its value does not go away.

parseField :: FromYaml a => Object -> Text -> Parser a Source #

The value of a key. It is an error if the key is missing.

parseFieldMaybe :: FromYaml a => Object -> Text -> Parser (Maybe a) Source #

The value of a key, or Nothing if the key is missing or its value is null.

parseFieldIfPresent :: FromYaml a => Object -> Text -> Parser (Maybe a) Source #

The value of a key, or Nothing if the key is missing. Unlike parseFieldMaybe, a null value goes to the parser of the value, e.g. Maybe a gives Just Nothing for a null value.

>>> :{
newtype Limit = Limit (Maybe (Maybe Int))
  deriving stock (Show)
instance FromYaml Limit where
  parseYaml = withMapping $ \o -> Limit <$> parseFieldIfPresent o "limit"
:}
>>> decodeText @Limit "limit: null\n"
Right (Limit (Just Nothing))
>>> decodeText @Limit "{}"
Right (Limit Nothing)

parseFieldDefault :: FromYaml a => Object -> Text -> a -> Parser a Source #

The value of a key, or the default if the key is missing or its value is null.

>>> :{
newtype Server = Server Int
  deriving stock (Show)
instance FromYaml Server where
  parseYaml = withMapping $ \o -> Server <$> parseFieldDefault o "port" 80
:}
>>> decodeText @Server "{}"
Right (Server 80)
>>> decodeText @Server "port: null\n"
Right (Server 80)
>>> decodeText @Server "port: 8080\n"
Right (Server 8080)

parseFieldWith :: (Node -> Parser a) -> Object -> Text -> Parser a Source #

Like parseField, with the given parser for the value, e.g. to check a value without a new type for it. The errors of the parser point to the value. The parser gets only the value, so it cannot keep the comments of the key, as a Commented field does with parseField.

>>> :{
newtype Port = Port Int
  deriving stock (Show)
instance FromYaml Port where
  parseYaml = withMapping $ \o -> Port <$> parseFieldWith number o "port"
    where
      number :: Node -> Parser Int
      number = withInt $ \i ->
        if i >= 1 && i <= 65535
          then pure (fromInteger i)
          else fail "expected a port from 1 to 65535"
:}
>>> decodeText @Port "port: 80\n"
Right (Port 80)
>>> either printErrors print (decodeText @Port "port: 70000\n")
input.yaml:1:7: port: expected a port from 1 to 65535
  |
1 | port: 70000
  |       ^

parseFieldMaybeWith :: (Node -> Parser a) -> Object -> Text -> Parser (Maybe a) Source #

Like parseFieldMaybe, with the given parser for the value, as in parseFieldWith. The result is Nothing if the key is missing or its value is null. The parser never gets a null value, so a missing key and a null value mean the same.

>>> :{
newtype Job = Job (Maybe Int)
  deriving stock (Show)
instance FromYaml Job where
  parseYaml = withMapping $ \o -> Job <$> parseFieldMaybeWith positive o "retries"
    where
      positive :: Node -> Parser Int
      positive = withInt $ \i ->
        if i > 0 then pure (fromInteger i) else fail "expected a positive number"
:}
>>> decodeText @Job "{}"
Right (Job Nothing)
>>> decodeText @Job "retries: null\n"
Right (Job Nothing)
>>> decodeText @Job "retries: 3\n"
Right (Job (Just 3))

To give a null value to the parser, use parseFieldIfPresentWith.

parseFieldIfPresentWith :: (Node -> Parser a) -> Object -> Text -> Parser (Maybe a) Source #

Like parseFieldIfPresent, with the given parser for the value, as in parseFieldWith. The result is Nothing only if the key is missing. A null value goes to the parser, so the parser can give it a meaning of its own. Here a missing key takes the default limit, and null means no limit:

>>> :{
data Limit = Unlimited | Limit Int
  deriving stock (Show)
newtype Job = Job (Maybe Limit)
  deriving stock (Show)
instance FromYaml Job where
  parseYaml = withMapping $ \o -> Job <$> parseFieldIfPresentWith limit o "limit"
    where
      limit :: Node -> Parser Limit
      limit n = case view n of
        NullView -> pure Unlimited
        _ -> withInt (pure . Limit . fromInteger) n
:}
>>> decodeText @Job "{}"
Right (Job Nothing)
>>> decodeText @Job "limit: null\n"
Right (Job (Just Unlimited))
>>> decodeText @Job "limit: 3\n"
Right (Job (Just (Limit 3)))

With parseFieldMaybeWith, the null value would give Nothing, the same as the missing key.

parseFieldDefaultWith :: (Node -> Parser a) -> Object -> Text -> a -> Parser a Source #

Like parseFieldDefault, with the given parser for the value, as in parseFieldWith. The parser never gets a null value.

>>> :{
newtype Job = Job Int
  deriving stock (Show)
instance FromYaml Job where
  parseYaml = withMapping $ \o -> Job <$> parseFieldDefaultWith positive o "retries" 1
    where
      positive :: Node -> Parser Int
      positive = withInt $ \i ->
        if i > 0 then pure (fromInteger i) else fail "expected a positive number"
:}
>>> decodeText @Job "{}"
Right (Job 1)
>>> decodeText @Job "retries: 3\n"
Right (Job 3)

rejectUnknownKeys :: [Text] -> Object -> Parser () Source #

Fail at each key that is not in the list. If a key in the list is close to an unknown key, e.g. "host" to "hots", its error suggests it. Otherwise the error lists the known keys. An empty list accepts only an empty mapping, e.g. for a value written as {}.

A key that is not a string, but has the text of a known key, e.g. true, is left to the lookup of that key, e.g. parseField or lookupKey, which reports it.