aboutsummaryrefslogtreecommitdiffhomepage
path: root/core/src/Text/Edifact/Inspect.hs
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/Text/Edifact/Inspect.hs')
-rw-r--r--core/src/Text/Edifact/Inspect.hs108
1 files changed, 108 insertions, 0 deletions
diff --git a/core/src/Text/Edifact/Inspect.hs b/core/src/Text/Edifact/Inspect.hs
new file mode 100644
index 0000000..fb3755a
--- /dev/null
+++ b/core/src/Text/Edifact/Inspect.hs
@@ -0,0 +1,108 @@
1{-# LANGUAGE DerivingStrategies #-}
2{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3{-# LANGUAGE OverloadedStrings #-}
4
5module Text.Edifact.Inspect
6 ( inspect
7 ) where
8
9import Text.Edifact.Types
10
11import Control.Monad.Reader (Reader, ask, local, runReader)
12import Data.Maybe (catMaybes)
13import Data.String (IsString)
14import Data.Text (Text)
15import Formatting
16
17type Indent = Int
18
19type Rendering = Reader Indent
20
21indent :: Rendering a -> Rendering a
22indent = local (+1)
23
24getIndentation :: Rendering Int
25getIndentation = ask
26
27inspect :: Value -> Text
28inspect = renderInspection . valueRenderer
29
30renderInspection :: Rendering a -> a
31renderInspection r = runReader r 0
32
33valueRenderer :: Value -> Rendering Text
34valueRenderer (Simple _ primitive) = primitiveRenderer primitive
35valueRenderer (Composite _ values) = sformat inBrackets . commaSeparated . catMaybes <$> traverse positionRenderer values
36valueRenderer (Segment code values) = indentedPrefix fSegmentCode code " " . spaceSeparated . catMaybes =<< traverse positionRenderer values
37valueRenderer (Group code values) = indentedPrefix fGroupCode code "\n" . lineSeparated =<< indent (traverse silentPositionRenderer values)
38valueRenderer (Message code values) = indentedPrefix fMessageCode code "\n" . lineSeparated =<< indent (traverse silentPositionRenderer values)
39
40inBrackets :: Format r (Text -> r)
41inBrackets = "[" % stext % "]"
42
43indentedPrefix :: Format (String -> Text -> Text) (code -> String -> Text -> Text) -> code -> String -> Text -> Rendering Text
44indentedPrefix codeFormatter code sep t = do
45 i <- getIndentation
46 let prefix = replicate (i * 2) ' '
47 pure (sformat (string % codeFormatter % string % stext) prefix code sep t)
48
49fMessageCode :: Format r (MessageCode -> r)
50fMessageCode = mapf getMessageCode ("message " % string)
51
52fGroupCode :: Format r (GroupCode -> r)
53fGroupCode = mapf getGroupCode ("Segment Group - " % string)
54
55fSegmentCode :: Format r (SegmentCode -> r)
56fSegmentCode = mapf getSegmentCode string
57
58positionRenderer :: (Position, Maybe Value) -> Rendering (Maybe Text)
59positionRenderer (pos, value) = fmap (flip (sformat (stext % fPosition)) pos) <$> traverse valueRenderer value
60
61silentPositionRenderer :: (Position, [Value]) -> Rendering Text
62silentPositionRenderer (_, value) = lineSeparated <$> traverse valueRenderer value
63
64fPosition :: Format r (Position -> r)
65fPosition = mapf getPosition ("@" % string)
66
67primitiveRenderer :: Primitive -> Rendering Text
68primitiveRenderer (String t) = pure (sformat ("\"" % stext % "\"") t)
69primitiveRenderer (Number s) = pure (sformat shown s)
70
71newtype CommaSeparated = CommaSeparated { getCommaSeparated :: Text } deriving newtype (IsString, Eq)
72
73instance Semigroup CommaSeparated where
74 t1 <> "" = t1
75 "" <> t2 = t2
76 t1 <> t2 = CommaSeparated (getCommaSeparated t1 <> "," <> getCommaSeparated t2)
77
78instance Monoid CommaSeparated where
79 mempty = ""
80
81commaSeparated :: Foldable f => f Text -> Text
82commaSeparated = getCommaSeparated . foldMap CommaSeparated
83
84newtype SpaceSeparated = SpaceSeparated { getSpaceSeparated :: Text } deriving newtype (IsString, Eq)
85
86instance Semigroup SpaceSeparated where
87 t1 <> "" = t1
88 "" <> t2 = t2
89 t1 <> t2 = SpaceSeparated (getSpaceSeparated t1 <> " " <> getSpaceSeparated t2)
90
91instance Monoid SpaceSeparated where
92 mempty = ""
93
94spaceSeparated :: Foldable f => f Text -> Text
95spaceSeparated = getSpaceSeparated . foldMap SpaceSeparated
96
97newtype LineSeparated = LineSeparated { getLineSeparated :: Text } deriving newtype (IsString, Eq)
98
99instance Semigroup LineSeparated where
100 t1 <> "" = t1
101 "" <> t2 = t2
102 t1 <> t2 = LineSeparated (getLineSeparated t1 <> "\n" <> getLineSeparated t2)
103
104instance Monoid LineSeparated where
105 mempty = ""
106
107lineSeparated :: Foldable f => f Text -> Text
108lineSeparated = getLineSeparated . foldMap LineSeparated