-
Notifications
You must be signed in to change notification settings - Fork 113
/
Copy pathMoveDocs.hs
303 lines (224 loc) · 7.17 KB
/
MoveDocs.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE OverloadedStrings #-}
module MoveDocs
( move
)
where
import Control.Monad
import Control.Monad.Trans (liftIO)
import Data.Aeson ((.:), (.:?))
import qualified Data.Aeson as Json
import qualified Data.Aeson.Types as Json
import qualified Data.ByteString.Lazy as BS
import qualified Data.Char as Char
import qualified Data.List as List
import qualified Data.Map as Map
import qualified Data.Maybe as Maybe
import qualified Data.Set as Set
import qualified Data.Text as Text
import System.FilePath ((</>))
import qualified Crawl
import qualified Elm.Compiler.Module as Module
import qualified Elm.Compiler.Type as Type
import qualified Elm.Docs as Docs
import qualified Elm.Name as N
import qualified Elm.Package as Pkg
import qualified Task
import qualified Json.Encode as Encode
-- MOVE
move :: Pkg.Name -> Pkg.Version -> Task.Transaction ()
move pkg version =
do bits <- liftIO $ BS.readFile (Crawl.oldDir pkg version </> "documentation.json")
case Json.eitherDecode bits of
Left problem ->
Task.bail $ "Problem parsing documentation.json:\n" ++ problem
Right oldDocs ->
let
newDocs = List.map updateDocs oldDocs
in
liftIO $
Encode.write (Crawl.newDir pkg version </> "docs.json") $
Encode.list Docs.encode newDocs
updateDocs :: OldDocs -> Docs.Module
updateDocs (OldDocs (Txt moduleName) (Txt comment) aliases types values) =
Docs.Module
{ Docs._name = N.fromText moduleName
, Docs._comment = comment
, Docs._unions = Map.fromList (map toUnionPair types)
, Docs._aliases = Map.fromList (map toAliasPair aliases)
, Docs._values = Map.fromList (Maybe.mapMaybe toValuePair values)
, Docs._binops = Map.fromList (Maybe.mapMaybe toBinopPair values)
}
toUnionPair :: Union -> (N.Name, Docs.Union)
toUnionPair (Union (Txt name) (Txt comment) args cases) =
( N.fromText name, Docs.Union comment args cases )
toAliasPair :: Alias -> (N.Name, Docs.Alias)
toAliasPair (Alias (Txt name) (Txt comment) args tipe) =
( N.fromText name, Docs.Alias comment args tipe )
toValuePair :: Value -> Maybe (N.Name, Docs.Value)
toValuePair (Value (Txt name) (Txt comment) tipe _) =
if Text.any isSymbol name then
Nothing
else
Just (N.fromText name, Docs.Value comment tipe)
toBinopPair :: Value -> Maybe (N.Name, Docs.Binop)
toBinopPair (Value (Txt name) (Txt comment) tipe fix) =
if Text.any isSymbol name then
Just
( N.fromText name
, case fix of
Nothing ->
Docs.Binop comment tipe Docs.Left (Docs.Precedence 9)
Just (assoc, prec) ->
Docs.Binop comment tipe assoc prec
)
else
Nothing
isSymbol :: Char -> Bool
isSymbol char =
Char.isSymbol char || Set.member char symbols
symbols :: Set.Set Char
symbols =
Set.fromList "+-/*=.$<>:&|^?%#@~!"
-- OLD DOCS
newtype Txt =
Txt Text.Text
data OldDocs =
OldDocs
{ _moduleName :: Txt
, _comment :: Txt
, _aliases :: [Alias]
, _types :: [Union]
, _values :: [Value]
}
data Alias =
Alias
{ _aliasName :: Txt
, _aliasComment :: Txt
, _aliasArgs :: [N.Name]
, _aliasType :: Type.Type
}
data Union =
Union
{ _unionName :: Txt
, _unionComment :: Txt
, _unionArgs :: [N.Name]
, _unionCases :: [(N.Name, [Type.Type])]
}
data Value =
Value
{ _valueName :: Txt
, _valueComment :: Txt
, _valueType :: Type.Type
, _valueFix :: Maybe (Docs.Associativity, Docs.Precedence)
}
-- JSON for OLD DOCS
instance Json.FromJSON OldDocs where
parseJSON (Json.Object obj) =
OldDocs
<$> obj .: "name"
<*> obj .: "comment"
<*> obj .: "aliases"
<*> obj .: "types"
<*> obj .: "values"
parseJSON value =
fail $ "Cannot decode OldDocs from: " ++ show (Json.encode value)
instance Json.FromJSON Alias where
parseJSON (Json.Object obj) =
Alias
<$> obj .: "name"
<*> obj .: "comment"
<*> obj .: "args"
<*> obj .: "type"
parseJSON value =
fail $ "Cannot decode Alias from: " ++ show (Json.encode value)
instance Json.FromJSON Union where
parseJSON (Json.Object obj) =
Union
<$> obj .: "name"
<*> obj .: "comment"
<*> obj .: "args"
<*> obj .: "cases"
parseJSON value =
fail $ "Cannot decode Union from: " ++ show (Json.encode value)
instance Json.FromJSON Value where
parseJSON (Json.Object obj) =
Value
<$> obj .: "name"
<*> obj .: "comment"
<*> obj .: "type"
<*> (liftM2 (,) <$> obj .:? "associativity" <*> obj .:? "precedence")
parseJSON value =
fail $ "Cannot decode Value from: " ++ show (Json.encode value)
instance Json.FromJSON Docs.Associativity where
parseJSON value =
case value of
Json.String "left" -> return Docs.Left
Json.String "non" -> return Docs.Non
Json.String "right" -> return Docs.Right
_ -> fail $ "Unknown precedence: " ++ show (Json.encode value)
instance Json.FromJSON Docs.Precedence where
parseJSON value =
Docs.Precedence <$> Json.parseJSON value
instance Json.FromJSON Txt where
parseJSON (Json.String txt) =
return $ Txt $
Text.replace "\\u003c" "<" (Text.replace "\\u003e" ">" txt)
parseJSON _ =
fail "Need a STRING here."
instance Json.FromJSON N.Name where
parseJSON (Json.String txt) =
return $ N.fromText txt
parseJSON _ =
fail "Need a STRING here."
-- JSON for TYPES
instance Json.FromJSON Type.Type where
parseJSON value =
let
failure =
fail $
"Trying to decode a type string, but could not handle this value:\n"
++ show (Json.encode value)
in
case value of
Json.String text ->
maybe failure return (Type.fromText (Text.replace "\\u003e" ">" text))
Json.Object obj ->
fromObject obj
_ ->
failure
fromObject :: Json.Object -> Json.Parser Type.Type
fromObject obj =
do tag <- obj .: "tag"
case (tag :: String) of
"lambda" ->
Type.Lambda
<$> obj .: "in"
<*> obj .: "out"
"var" ->
Type.Var
<$> obj .: "name"
"type" ->
do name <- obj .: "name"
return $
if name == "_Tuple0" then Type.Unit else Type.Type name []
"app" ->
do func <- obj .: "func"
args <- obj .: "args"
case func of
Type.Type name [] ->
case args of
(a:b:cs) | N.startsWith "_Tuple" name ->
return $ Type.Tuple a b cs
_ ->
return $ Type.Type name args
Type.Unit | null args ->
return Type.Unit
_ ->
fail $ "Error on " ++ show (Json.encode obj)
"record" ->
Type.Record
<$> obj .: "fields"
<*> obj .: "extension"
_ ->
fail $ "Error when decoding type with tag: " ++ tag