1 {-# LANGUAGE DerivingStrategies #-}
2 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
3 {-# LANGUAGE OverloadedStrings #-}
5 module Text.Edifact.Inspect
9 import Text.Edifact.Types
11 import Control.Monad.Reader (Reader, ask, local, runReader)
12 import Data.Maybe (catMaybes)
13 import Data.String (IsString)
14 import Data.Text (Text)
19 type Rendering = Reader Indent
21 indent :: Rendering a -> Rendering a
24 getIndentation :: Rendering Int
27 inspect :: Value -> Text
28 inspect = renderInspection . valueRenderer
30 renderInspection :: Rendering a -> a
31 renderInspection r = runReader r 0
33 valueRenderer :: Value -> Rendering Text
34 valueRenderer (Simple _ primitive) = primitiveRenderer primitive
35 valueRenderer (Composite _ values) = sformat inBrackets . commaSeparated . catMaybes <$> traverse positionRenderer values
36 valueRenderer (Segment code values) = indentedPrefix fSegmentCode code " " . spaceSeparated . catMaybes =<< traverse positionRenderer values
37 valueRenderer (Group code values) = indentedPrefix fGroupCode code "\n" . lineSeparated =<< indent (traverse silentPositionRenderer values)
38 valueRenderer (Message code values) = indentedPrefix fMessageCode code "\n" . lineSeparated =<< indent (traverse silentPositionRenderer values)
40 inBrackets :: Format r (Text -> r)
41 inBrackets = "[" % stext % "]"
43 indentedPrefix :: Format (String -> Text -> Text) (code -> String -> Text -> Text) -> code -> String -> Text -> Rendering Text
44 indentedPrefix codeFormatter code sep t = do
46 let prefix = replicate (i * 2) ' '
47 pure (sformat (string % codeFormatter % string % stext) prefix code sep t)
49 fMessageCode :: Format r (MessageCode -> r)
50 fMessageCode = mapf getMessageCode ("message " % string)
52 fGroupCode :: Format r (GroupCode -> r)
53 fGroupCode = mapf getGroupCode ("Segment Group - " % string)
55 fSegmentCode :: Format r (SegmentCode -> r)
56 fSegmentCode = mapf getSegmentCode string
58 positionRenderer :: (Position, Maybe Value) -> Rendering (Maybe Text)
59 positionRenderer (pos, value) = fmap (flip (sformat (stext % fPosition)) pos) <$> traverse valueRenderer value
61 silentPositionRenderer :: (Position, [Value]) -> Rendering Text
62 silentPositionRenderer (_, value) = lineSeparated <$> traverse valueRenderer value
64 fPosition :: Format r (Position -> r)
65 fPosition = mapf getPosition ("@" % string)
67 primitiveRenderer :: Primitive -> Rendering Text
68 primitiveRenderer (String t) = pure (sformat ("\"" % stext % "\"") t)
69 primitiveRenderer (Number s) = pure (sformat shown s)
71 newtype CommaSeparated = CommaSeparated { getCommaSeparated :: Text } deriving newtype (IsString, Eq)
73 instance Semigroup CommaSeparated where
76 t1 <> t2 = CommaSeparated (getCommaSeparated t1 <> "," <> getCommaSeparated t2)
78 instance Monoid CommaSeparated where
81 commaSeparated :: Foldable f => f Text -> Text
82 commaSeparated = getCommaSeparated . foldMap CommaSeparated
84 newtype SpaceSeparated = SpaceSeparated { getSpaceSeparated :: Text } deriving newtype (IsString, Eq)
86 instance Semigroup SpaceSeparated where
89 t1 <> t2 = SpaceSeparated (getSpaceSeparated t1 <> " " <> getSpaceSeparated t2)
91 instance Monoid SpaceSeparated where
94 spaceSeparated :: Foldable f => f Text -> Text
95 spaceSeparated = getSpaceSeparated . foldMap SpaceSeparated
97 newtype LineSeparated = LineSeparated { getLineSeparated :: Text } deriving newtype (IsString, Eq)
99 instance Semigroup LineSeparated where
102 t1 <> t2 = LineSeparated (getLineSeparated t1 <> "\n" <> getLineSeparated t2)
104 instance Monoid LineSeparated where
107 lineSeparated :: Foldable f => f Text -> Text
108 lineSeparated = getLineSeparated . foldMap LineSeparated