From b282af35ad4b0bb8d90e517f4b9ff03c22234090 Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Wed, 7 Sep 2022 15:07:04 +0200 Subject: Copy-edit specification --- src/lib/Codec/Pesto/Lint.lhs | 104 ++++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 51 deletions(-) (limited to 'src/lib/Codec/Pesto/Lint.lhs') diff --git a/src/lib/Codec/Pesto/Lint.lhs b/src/lib/Codec/Pesto/Lint.lhs index 58f9ab0..3ecdfa1 100644 --- a/src/lib/Codec/Pesto/Lint.lhs +++ b/src/lib/Codec/Pesto/Lint.lhs @@ -25,11 +25,11 @@ Linting Not every graph generated in the previous section is a useful recipe. Some instruction sequences just do not make sense. The tests in this section can detect those. Failing any of them does not render a stream of instructions or -graph invalid. They just does not describe a *useful* recipe. Thus -implementations must not generate or export such documents. However they should +graph invalid. They just do not describe a *useful* recipe. Thus +implementations must not generate or export such documents. However, they should accept input that fails any of the tests and warn the user about the failure. -Additionally this section provides guidance on how to use the instructions +Additionally, this section provides guidance on how to use the instructions provided by the Pesto language properly. Graph properties @@ -37,9 +37,9 @@ Graph properties .. _resultsused: -The graph must have exactly one root node (i.e. a node with incoming edges +The graph must have exactly one root node (i.e., a node with incoming edges only). This also requires all results and alternatives to be referenced -somewhere. Directives are either consumed when parsing, generating a graph and +somewhere. Directives are either consumed when parsing, generating a graph, and linting. Otherwise they are dangling as well. Unknown instructions are always dangling. @@ -54,15 +54,15 @@ Empty recipes or circular references have no root node: > testConnectivity = [ > cmpLint "" [LintResult NoRootNode [], LintResult NoMetadata []] > , cmpLint "*foobar >foobar" -> [LintResult NoRootNode [], LintResult CircularLoop [0, 1], LintResult NoMetadata []] +> [LintResult NoRootNode [], LintResult CircularLoop [0, 1], LintResult NoMetadata []] > , cmpLint "+foobar" -> [LintResult NonResultRootNode [0], LintResult NoMetadata []] +> [LintResult NonResultRootNode [0], LintResult NoMetadata []] Directives and unknown instructions are dangling and thus root nodes. > , cmpLint "invalid %invalid +foo >bar" > [LintResult MoreThanOneRootNode [0,1,3], LintResult NoMetadata []] -> ] +> ] Metadata ++++++++ @@ -75,11 +75,11 @@ title (object) of the recipe. > Just $ (i, ("title", MetaStr title)) > :(i, ("yield", MetaQty q)) > :foldl f [] (incomingNodes nodes edges i) -> _ -> Nothing +> _ -> Nothing > where Additional key-value metadata for the whole recipe can be added as annotations -to the root node. If multiple annotations with the same key exist the key maps +to the root node. If multiple annotations with the same key exist, the key maps to a list of those values. Annotations that are unparseable key-value pairs are added as recipe description instead. @@ -103,8 +103,8 @@ colon char. A value may be empty. > checkKey xs (_, (k, _)) | isKeyKnown k = xs > checkKey xs (i, _) = LintResult UnknownMetadataKey [i]:xs -Valid metadata keys are listed below. Additionally applications may add keys by -prefixing them with “x-myapp-”, thus an application called “basil” adding +Valid metadata keys are listed below. Additionally, applications may add keys by +prefixing them with “x-myapp-”. Thus an application called “basil” adding “some-key” would use the full key “x-basil-some-key”. > isKeyKnown k = k `elem` knownKeys || "x-" `isPrefixOf` k @@ -115,7 +115,7 @@ The following metadata keys are permitted: The title, description and yield are implicit. -> "title" +> "title" > , "description" > , "yield" @@ -137,11 +137,11 @@ An image can be a relative file reference or URI For instance a german language recipe for one person would look like this: > testMetadata = [ -> cmpLintMeta "+foo >1 ml foobar (language: de) (x-app-key: value)" -> [] -> (Just [(1, ("title", MetaStr "foobar")) -> , (1, ("yield", MetaQty (Quantity (Exact (AmountRatio (1%1))) "ml" "foobar"))) -> , (2, ("language", MetaStr "de")) +> cmpLintMeta "+foo >1 _ foobar (language: de) (x-app-key: value)" +> [] +> (Just [(1, ("title", MetaStr "foobar")) +> , (1, ("yield", MetaQty (Quantity (Exact (AmountRatio (1%1))) "" "foobar"))) +> , (2, ("language", MetaStr "de")) > , (3, ("x-app-key", MetaStr "value"))]) Unparseable annotations or unknown keys are linting errors: @@ -149,7 +149,7 @@ Unparseable annotations or unknown keys are linting errors: > , cmpLintMeta "+foo >foobar (unknown-key: value)" > [LintResult UnknownMetadataKey [2]] > (Just [(1, ("title", MetaStr "foobar")) -> , (1, ("yield", MetaQty (strQuantity "foobar"))) +> , (1, ("yield", MetaQty (strQuantity "foobar"))) > , (2, ("unknown-key", MetaStr "value"))]) Root node annotations not containing a parseable key-value pair are assigned @@ -169,7 +169,7 @@ the key “description”. Time is a tool ++++++++++++++ -By definition time is a tool and not an ingredient. +By definition, time is a tool and not an ingredient. > timeUnits = ["s", "min", "h", "d"] > @@ -179,7 +179,7 @@ By definition time is a tool and not an ingredient. > timeIsATool nodes _ = foldl f [] nodes > where > f xs (nodeid, Ingredient q) | isTime q = LintResult TimeIsATool [nodeid]:xs -> f xs _ = xs +> f xs _ = xs > testLintQuantity = [ > cmpLint "+10 min >foo" [LintResult TimeIsATool [0]] @@ -189,9 +189,9 @@ By definition time is a tool and not an ingredient. > , cmpLint "&10 min [bar] >foo" [] > ] -Only actions can be annotated with a time. It can be used to indicate how long -a certain action is *expected* to take (i.e. peeling potatoes takes two -minutes) or how long the action is supposed to be executed (i.e. cook five +Only actions can be annotated like this. It can be used to indicate how long +a particular action is *expected* to take (i.e., peeling potatoes takes two +minutes) or how long the action is supposed to be executed (i.e. cook for five minutes). More time annotations improve the software’s scheduling capabilities. > timeAnnotatesAction nodes edges = foldl f [] nodes @@ -201,7 +201,7 @@ minutes). More time annotations improve the software’s scheduling capabilities > toNodelist = (!!) nodes . snd > allActions = all (isAction . snd . toNodelist) -For example “cook 10 minutes” can be expressed with +For example, “cook 10 minutes” can be expressed with: > testTimeAnnotatesAction = [ > cmpLint "&10 min [cook] >soup" [] @@ -216,10 +216,10 @@ For example “cook 10 minutes” can be expressed with Well-known units ++++++++++++++++ -Units can be an arbitrary strings, but implementations should recognize the -common metric units g (gram), l (litre) and m (metre). One of these prefixes -may be used with each of them: m (milli-), c (centi-), d (dezi-) and k (kilo-). -Additionally time in s (second), min (minute), h (hour), d (day) should be +Units can be arbitrary strings, but implementations should recognize the +standard metric units g (gram), l (liter), and m (meter). One of these prefixes +may be used with each of them: m (milli-), c (centi-), d (dezi-), and k (kilo-). +Additionally, time in s (second), min (minute), h (hour), and d (day) should be accepted. > wellKnownUnit nodes _ = foldl f [] nodes @@ -232,7 +232,7 @@ accepted. > extractQty _ = Nothing > f xs (nodeid, instr) | fromMaybe False (extractQty instr >>= (return . not . known)) = > LintResult UnitNotWellKnown [nodeid]:xs -> f xs _ = xs +> f xs _ = xs > known (Quantity _ unit _) = unit `elem` knownUnits > knownUnits = [ > "" @@ -241,9 +241,9 @@ accepted. > , "cm", "dm", "m" > ] ++ timeUnits -Usage of imperial units (inch, pound, …) as well as non-standard -units like “teaspoon”, “cup” or similar is discouraged because -the former is used by just three countries in the world right now and +Usage of imperial units (inch, pound, …), non-standard +units like “teaspoon,” “cup,” or similar is discouraged because +the former is used by just three countries in the world right now, and the latter is language- and country-dependent. The implementation may provide the user with a conversion utility. @@ -268,14 +268,14 @@ The unit is case-sensitive, thus References ++++++++++ -All references must be resolved. An `earlier check <#resultsused>`_ makes sure +All references must be resolved. An `earlier check <#resultsused>`_ ensures all results and alternatives are referenced at some point. > referencesResolved nodes edges = foldl f [] nodes > where > f xs (nodeid, Reference _) | null (incomingEdges edges nodeid) = > LintResult UndefinedReference [nodeid]:xs -> f xs _ = xs +> f xs _ = xs > testLintRefs = [ > cmpLint "*foobar >foobar >barbaz" [LintResult CircularLoop [0, 1]] @@ -283,8 +283,8 @@ all results and alternatives are referenced at some point. > ] Results and alternatives must not have duplicate names, so collect -their lower-case object names into map and flag those, which reference -multiple nodes. +their lower-case object names into a ``Map`` and flag those which +reference multiple nodes. > uniqueNames nodes _ = M.foldl f [] nameMap > where @@ -312,7 +312,7 @@ only occur at the beginning of a recipe. > where > f xs (nodeid, Result _) | null (incomingEdges edges nodeid) = > LintResult TooFewChildren [nodeid]:xs -> f xs _ = xs +> f xs _ = xs > testLintResultNonempty = [ > cmpLint ">bar *bar >baz" [LintResult TooFewChildren [0]] @@ -325,9 +325,9 @@ make the alternative pointless. > twoAlternatives nodes edges = foldl f [] nodes > where -> f xs (nodeid, Alternative _) | length (incomingEdges edges nodeid) < 2 = +> f xs (nodeid, Alternative _) | length (incomingEdges edges nodeid) < 2 = > LintResult TooFewChildren [nodeid]:xs -> f xs _ = xs +> f xs _ = xs > testLintTwoAlternatives = [ > cmpLint "+A |foo *foo >bar" [LintResult TooFewChildren [1]] @@ -335,9 +335,11 @@ make the alternative pointless. > , cmpLint "+A &B |foo *foo >bar" [] > ] -References cannot loop, because, well, you cannot cook something and +.. _reject-loops: + +References cannot loop because, well, you cannot cook something and use an ingredient you have not made yet. It is possible to branch out -and merge again though if an ingredient is split into multiple parts +and merge again if an ingredient is split into multiple parts and added to different outputs. > circularLoops nodes edges = map (LintResult CircularLoop) circles @@ -376,11 +378,11 @@ This limitation is not enforced for ranges containing strings. > rangeFromLargerThanTo nodes _ = foldl f [] nodes > where -> f xs (nodeid, Ingredient q) | not $ rangeOk q = +> f xs (nodeid, Ingredient q) | not $ rangeOk q = > LintResult RangeFromLargerThanTo [nodeid]:xs -> f xs (nodeid, Reference q) | not $ rangeOk q = +> f xs (nodeid, Reference q) | not $ rangeOk q = > LintResult RangeFromLargerThanTo [nodeid]:xs -> f xs _ = xs +> f xs _ = xs > rangeOk (Quantity (Range (AmountRatio a) (AmountRatio b)) _ _) = a < b > rangeOk _ = True @@ -404,9 +406,9 @@ Appendix > | DuplicateReferenceName > | CircularLoop > | TooFewChildren -> | TimeIsATool +> | TimeIsATool > | TimeAnnotatesAction -> | UnitNotWellKnown +> | UnitNotWellKnown > | InvalidNode > | RangeFromLargerThanTo > | NoMetadata @@ -419,11 +421,11 @@ Every lint test checks a single aspect of the graph. > lintTests = [ > rootIsResult -> , referencesResolved +> , referencesResolved > , uniqueNames > , circularLoops -> , resultNonempty -> , twoAlternatives +> , resultNonempty +> , twoAlternatives > , timeIsATool > , timeAnnotatesAction > , wellKnownUnit @@ -432,7 +434,7 @@ Every lint test checks a single aspect of the graph. > ] > withGraph doc f = f nodes edges -> where +> where > (Right op) = (head . extract . snd . unzip) <$> parse ("%pesto " ++ doc) > nodes = zip [firstNodeId..] op > edges = toGraph nodes ++ resolveReferences nodes -- cgit v1.2.3