1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
10import qualified Data.List as List
11import qualified Data.Map as Map
12import qualified Data.Maybe as Maybe
13import qualified Data.Name as Name
14import qualified Data.NonEmptyList as NE
17import Deps.Diff (PackageChanges(..), ModuleChanges(..), Changes(..))
18import qualified Deps.Diff as DD
19import qualified Deps.Registry as Registry
20import qualified Elm.Compiler.Type as Type
21import qualified Elm.Details as Details
22import qualified Elm.Docs as Docs
23import qualified Elm.Magnitude as M
24import qualified Elm.Outline as Outline
25import qualified Elm.Package as Pkg
26import qualified Elm.Version as V
28import qualified Reporting
29import Reporting.Doc ((<>), (<+>))
30import qualified Reporting.Doc as D
31import qualified Reporting.Exit as Exit
32import qualified Reporting.Exit.Help as Help
33import qualified Reporting.Render.Type.Localizer as L
34import qualified Reporting.Task as Task
44 | CodeVsExactly V.Version
45 | LocalInquiry V.Version V.Version
46 | GlobalInquiry Pkg.Name V.Version V.Version
49run :: Args -> () -> IO ()
51 Reporting.attempt Exit.diffToReport $
63 { _maybeRoot :: Maybe FilePath
64 , _cache :: Stuff.PackageCache
65 , _manager :: Http.Manager
66 , _registry :: Registry.Registry
72 do maybeRoot <- Task.io $ Stuff.findRoot
73 cache <- Task.io $ Stuff.getPackageCache
74 manager <- Task.io $ Http.getManager
75 registry <- Task.eio Exit.DiffMustHaveLatestRegistry $ Registry.latest manager cache
76 return (Env maybeRoot cache manager registry)
87diff :: Env -> Args -> Task ()
88diff env@(Env _ _ _ registry) args =
90 GlobalInquiry name v1 v2 ->
91 case Registry.getVersions' name registry of
93 do oldDocs <- getDocs env name vsns (min v1 v2)
94 newDocs <- getDocs env name vsns (max v1 v2)
95 writeDiff oldDocs newDocs
98 Task.throw $ Exit.DiffUnknownPackage name suggestions
100 LocalInquiry v1 v2 ->
101 do (name, vsns) <- readOutline env
102 oldDocs <- getDocs env name vsns (min v1 v2)
103 newDocs <- getDocs env name vsns (max v1 v2)
104 writeDiff oldDocs newDocs
107 do (name, vsns) <- readOutline env
108 oldDocs <- getLatestDocs env name vsns
109 newDocs <- generateDocs env
110 writeDiff oldDocs newDocs
112 CodeVsExactly version ->
113 do (name, vsns) <- readOutline env
114 oldDocs <- getDocs env name vsns version
115 newDocs <- generateDocs env
116 writeDiff oldDocs newDocs
123getDocs :: Env -> Pkg.Name -> Registry.KnownVersions -> V.Version -> Task Docs.Documentation
124getDocs (Env _ cache manager _) name (Registry.KnownVersions latest previous) version =
125 if latest == version || elem version previous
126 then Task.eio (Exit.DiffDocsProblem version) $ DD.getDocs cache manager name version
127 else Task.throw $ Exit.DiffUnknownVersion name version (latest:previous)
130getLatestDocs :: Env -> Pkg.Name -> Registry.KnownVersions -> Task Docs.Documentation
131getLatestDocs (Env _ cache manager _) name (Registry.KnownVersions latest _) =
132 Task.eio (Exit.DiffDocsProblem latest) $ DD.getDocs cache manager name latest
139readOutline :: Env -> Task (Pkg.Name, Registry.KnownVersions)
140readOutline (Env maybeRoot _ _ registry) =
143 Task.throw $ Exit.DiffNoOutline
146 do result <- Task.io $ Outline.read root
149 Task.throw $ Exit.DiffBadOutline err
154 Task.throw $ Exit.DiffApplication
156 Outline.Pkg (Outline.PkgOutline pkg _ _ _ _ _ _ _) ->
157 case Registry.getVersions pkg registry of
158 Just vsns -> return (pkg, vsns)
159 Nothing -> Task.throw Exit.DiffUnpublished
166generateDocs :: Env -> Task Docs.Documentation
167generateDocs (Env maybeRoot _ _ _) =
170 Task.throw $ Exit.DiffNoOutline
174 Task.eio Exit.DiffBadDetails $
175 Details.load Reporting.silent root
177 case Details._outline details of
178 Details.ValidApp _ ->
179 Task.throw $ Exit.DiffApplication
181 Details.ValidPkg _ exposed ->
184 Task.throw $ Exit.DiffNoExposed
187 Task.eio Exit.DiffBadBuild $
188 Build.fromExposed Reporting.silent root details Build.KeepDocs (NE.List e es)
195writeDiff :: Docs.Documentation -> Docs.Documentation -> Task ()
196writeDiff oldDocs newDocs =
198 changes = DD.diff oldDocs newDocs
199 localizer = L.fromNames (Map.union oldDocs newDocs)
201 Task.io $ Help.toStdout $ toDoc localizer changes <> "\n"
208toDoc :: L.Localizer -> PackageChanges -> D.Doc
209toDoc localizer changes@(PackageChanges added changed removed) =
210 if null added && Map.null changed && null removed then
211 "No API changes detected, so this is a" <+> D.green "PATCH" <+> "change."
215 D.fromChars (M.toChars (DD.toMagnitude changes))
218 "This is a" <+> D.green magDoc <+> "change."
221 if null added then [] else
222 [ Chunk "ADDED MODULES" M.MINOR $
223 D.vcat $ map D.fromName added
227 if null removed then [] else
228 [ Chunk "REMOVED MODULES" M.MAJOR $
229 D.vcat $ map D.fromName removed
233 addedChunk ++ removedChunk ++ map (changesToChunk localizer) (Map.toList changed)
235 D.vcat (header : "" : map chunkToDoc chunks)
241 , _magnitude :: M.Magnitude
246chunkToDoc :: Chunk -> D.Doc
247chunkToDoc (Chunk title magnitude details) =
250 "----" <+> D.fromChars title <+> "-" <+> D.fromChars (M.toChars magnitude) <+> "----"
261changesToChunk :: L.Localizer -> (Name.Name, ModuleChanges) -> Chunk
262changesToChunk localizer (name, changes@(ModuleChanges unions aliases values binops)) =
265 DD.moduleChangeMagnitude changes
267 (unionAdd, unionChange, unionRemove) =
268 changesToDocTriple (unionToDoc localizer) unions
270 (aliasAdd, aliasChange, aliasRemove) =
271 changesToDocTriple (aliasToDoc localizer) aliases
273 (valueAdd, valueChange, valueRemove) =
274 changesToDocTriple (valueToDoc localizer) values
276 (binopAdd, binopChange, binopRemove) =
277 changesToDocTriple (binopToDoc localizer) binops
279 Chunk (Name.toChars name) magnitude $
280 D.vcat $ List.intersperse "" $ Maybe.catMaybes $
281 [ changesToDoc "Added" unionAdd aliasAdd valueAdd binopAdd
282 , changesToDoc "Removed" unionRemove aliasRemove valueRemove binopRemove
283 , changesToDoc "Changed" unionChange aliasChange valueChange binopChange
287changesToDocTriple :: (k -> v -> D.Doc) -> Changes k v -> ([D.Doc], [D.Doc], [D.Doc])
288changesToDocTriple entryToDoc (Changes added changed removed) =
290 indented (name, value) =
291 D.indent 4 (entryToDoc name value)
293 diffed (name, (oldValue, newValue)) =
295 [ " - " <> entryToDoc name oldValue
296 , " + " <> entryToDoc name newValue
300 ( map indented (Map.toList added)
301 , map diffed (Map.toList changed)
302 , map indented (Map.toList removed)
306changesToDoc :: String -> [D.Doc] -> [D.Doc] -> [D.Doc] -> [D.Doc] -> Maybe D.Doc
307changesToDoc categoryName unions aliases values binops =
308 if null unions && null aliases && null values && null binops then
313 D.fromChars categoryName <> ":" : unions ++ aliases ++ binops ++ values
316unionToDoc :: L.Localizer -> Name.Name -> Docs.Union -> D.Doc
317unionToDoc localizer name (Docs.Union _ tvars ctors) =
320 "type" <+> D.fromName name <+> D.hsep (map D.fromName tvars)
322 ctorDoc (ctor, tipes) =
323 typeDoc localizer (Type.Type ctor tipes)
325 D.hang 4 (D.sep (setup : zipWith (<+>) ("=" : repeat "|") (map ctorDoc ctors)))
328aliasToDoc :: L.Localizer -> Name.Name -> Docs.Alias -> D.Doc
329aliasToDoc localizer name (Docs.Alias _ tvars tipe) =
332 "type" <+> "alias" <+> D.hsep (map D.fromName (name:tvars)) <+> "="
334 D.hang 4 (D.sep [ declaration, typeDoc localizer tipe ])
337valueToDoc :: L.Localizer -> Name.Name -> Docs.Value -> D.Doc
338valueToDoc localizer name (Docs.Value _ tipe) =
339 D.hang 4 $ D.sep [ D.fromName name <+> ":", typeDoc localizer tipe ]
342binopToDoc :: L.Localizer -> Name.Name -> Docs.Binop -> D.Doc
343binopToDoc localizer name (Docs.Binop _ tipe associativity (Docs.Precedence n)) =
344 "(" <> D.fromName name <> ")" <+> ":" <+> typeDoc localizer tipe <> D.black details
347 " (" <> D.fromName assoc <> "/" <> D.fromInt n <> ")"
350 case associativity of
353 Docs.Right -> "right"
356typeDoc :: L.Localizer -> Type.Type -> D.Doc
357typeDoc localizer tipe =
358 Type.toDoc localizer Type.None tipe
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list