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
16import qualified BackgroundWriter as BW
18import Deps.Diff (PackageChanges(..), ModuleChanges(..), Changes(..))
19import qualified Deps.Diff as DD
20import qualified Deps.Registry as Registry
21import qualified Elm.Compiler.Type as Type
22import qualified Elm.Details as Details
23import qualified Elm.Docs as Docs
24import qualified Elm.Magnitude as M
25import qualified Elm.Outline as Outline
26import qualified Elm.Package as Pkg
27import qualified Elm.Version as V
29import qualified Reporting
30import Reporting.Doc ((<>), (<+>))
31import qualified Reporting.Doc as D
32import qualified Reporting.Exit as Exit
33import qualified Reporting.Exit.Help as Help
34import qualified Reporting.Render.Type.Localizer as L
35import qualified Reporting.Task as Task
45 | CodeVsExactly V.Version
46 | LocalInquiry V.Version V.Version
47 | GlobalInquiry Pkg.Name V.Version V.Version
50run :: Args -> () -> IO ()
52 Reporting.attempt Exit.diffToReport $
64 { _maybeRoot :: Maybe FilePath
65 , _cache :: Stuff.PackageCache
66 , _manager :: Http.Manager
67 , _registry :: Registry.Registry
73 do maybeRoot <- Task.io $ Stuff.findRoot
74 cache <- Task.io $ Stuff.getPackageCache
75 manager <- Task.io $ Http.getManager
76 registry <- Task.eio Exit.DiffMustHaveLatestRegistry $ Registry.latest manager cache
77 return (Env maybeRoot cache manager registry)
88diff :: Env -> Args -> Task ()
89diff env@(Env _ _ _ registry) args =
91 GlobalInquiry name v1 v2 ->
92 case Registry.getVersions' name registry of
94 do oldDocs <- getDocs env name vsns (min v1 v2)
95 newDocs <- getDocs env name vsns (max v1 v2)
96 writeDiff oldDocs newDocs
99 Task.throw $ Exit.DiffUnknownPackage name suggestions
101 LocalInquiry v1 v2 ->
102 do (name, vsns) <- readOutline env
103 oldDocs <- getDocs env name vsns (min v1 v2)
104 newDocs <- getDocs env name vsns (max v1 v2)
105 writeDiff oldDocs newDocs
108 do (name, vsns) <- readOutline env
109 oldDocs <- getLatestDocs env name vsns
110 newDocs <- generateDocs env
111 writeDiff oldDocs newDocs
113 CodeVsExactly version ->
114 do (name, vsns) <- readOutline env
115 oldDocs <- getDocs env name vsns version
116 newDocs <- generateDocs env
117 writeDiff oldDocs newDocs
124getDocs :: Env -> Pkg.Name -> Registry.KnownVersions -> V.Version -> Task Docs.Documentation
125getDocs (Env _ cache manager _) name (Registry.KnownVersions latest previous) version =
126 if latest == version || elem version previous
127 then Task.eio (Exit.DiffDocsProblem version) $ DD.getDocs cache manager name version
128 else Task.throw $ Exit.DiffUnknownVersion name version (latest:previous)
131getLatestDocs :: Env -> Pkg.Name -> Registry.KnownVersions -> Task Docs.Documentation
132getLatestDocs (Env _ cache manager _) name (Registry.KnownVersions latest _) =
133 Task.eio (Exit.DiffDocsProblem latest) $ DD.getDocs cache manager name latest
140readOutline :: Env -> Task (Pkg.Name, Registry.KnownVersions)
141readOutline (Env maybeRoot _ _ registry) =
144 Task.throw $ Exit.DiffNoOutline
147 do result <- Task.io $ Outline.read root
150 Task.throw $ Exit.DiffBadOutline err
155 Task.throw $ Exit.DiffApplication
157 Outline.Pkg (Outline.PkgOutline pkg _ _ _ _ _ _ _) ->
158 case Registry.getVersions pkg registry of
159 Just vsns -> return (pkg, vsns)
160 Nothing -> Task.throw Exit.DiffUnpublished
167generateDocs :: Env -> Task Docs.Documentation
168generateDocs (Env maybeRoot _ _ _) =
171 Task.throw $ Exit.DiffNoOutline
175 Task.eio Exit.DiffBadDetails $ BW.withScope $ \scope ->
176 Details.load Reporting.silent scope root
178 case Details._outline details of
179 Details.ValidApp _ ->
180 Task.throw $ Exit.DiffApplication
182 Details.ValidPkg _ exposed _ ->
185 Task.throw $ Exit.DiffNoExposed
188 Task.eio Exit.DiffBadBuild $
189 Build.fromExposed Reporting.silent root details Build.KeepDocs (NE.List e es)
196writeDiff :: Docs.Documentation -> Docs.Documentation -> Task ()
197writeDiff oldDocs newDocs =
199 changes = DD.diff oldDocs newDocs
200 localizer = L.fromNames (Map.union oldDocs newDocs)
202 Task.io $ Help.toStdout $ toDoc localizer changes <> "\n"
209toDoc :: L.Localizer -> PackageChanges -> D.Doc
210toDoc localizer changes@(PackageChanges added changed removed) =
211 if null added && Map.null changed && null removed then
212 "No API changes detected, so this is a" <+> D.green "PATCH" <+> "change."
216 D.fromChars (M.toChars (DD.toMagnitude changes))
219 "This is a" <+> D.green magDoc <+> "change."
222 if null added then [] else
223 [ Chunk "ADDED MODULES" M.MINOR $
224 D.vcat $ map D.fromName added
228 if null removed then [] else
229 [ Chunk "REMOVED MODULES" M.MAJOR $
230 D.vcat $ map D.fromName removed
234 addedChunk ++ removedChunk ++ map (changesToChunk localizer) (Map.toList changed)
236 D.vcat (header : "" : map chunkToDoc chunks)
242 , _magnitude :: M.Magnitude
247chunkToDoc :: Chunk -> D.Doc
248chunkToDoc (Chunk title magnitude details) =
251 "----" <+> D.fromChars title <+> "-" <+> D.fromChars (M.toChars magnitude) <+> "----"
262changesToChunk :: L.Localizer -> (Name.Name, ModuleChanges) -> Chunk
263changesToChunk localizer (name, changes@(ModuleChanges unions aliases values binops)) =
266 DD.moduleChangeMagnitude changes
268 (unionAdd, unionChange, unionRemove) =
269 changesToDocTriple (unionToDoc localizer) unions
271 (aliasAdd, aliasChange, aliasRemove) =
272 changesToDocTriple (aliasToDoc localizer) aliases
274 (valueAdd, valueChange, valueRemove) =
275 changesToDocTriple (valueToDoc localizer) values
277 (binopAdd, binopChange, binopRemove) =
278 changesToDocTriple (binopToDoc localizer) binops
280 Chunk (Name.toChars name) magnitude $
281 D.vcat $ List.intersperse "" $ Maybe.catMaybes $
282 [ changesToDoc "Added" unionAdd aliasAdd valueAdd binopAdd
283 , changesToDoc "Removed" unionRemove aliasRemove valueRemove binopRemove
284 , changesToDoc "Changed" unionChange aliasChange valueChange binopChange
288changesToDocTriple :: (k -> v -> D.Doc) -> Changes k v -> ([D.Doc], [D.Doc], [D.Doc])
289changesToDocTriple entryToDoc (Changes added changed removed) =
291 indented (name, value) =
292 D.indent 4 (entryToDoc name value)
294 diffed (name, (oldValue, newValue)) =
296 [ " - " <> entryToDoc name oldValue
297 , " + " <> entryToDoc name newValue
301 ( map indented (Map.toList added)
302 , map diffed (Map.toList changed)
303 , map indented (Map.toList removed)
307changesToDoc :: String -> [D.Doc] -> [D.Doc] -> [D.Doc] -> [D.Doc] -> Maybe D.Doc
308changesToDoc categoryName unions aliases values binops =
309 if null unions && null aliases && null values && null binops then
314 D.fromChars categoryName <> ":" : unions ++ aliases ++ binops ++ values
317unionToDoc :: L.Localizer -> Name.Name -> Docs.Union -> D.Doc
318unionToDoc localizer name (Docs.Union _ tvars ctors) =
321 "type" <+> D.fromName name <+> D.hsep (map D.fromName tvars)
323 ctorDoc (ctor, tipes) =
324 typeDoc localizer (Type.Type ctor tipes)
326 D.hang 4 (D.sep (setup : zipWith (<+>) ("=" : repeat "|") (map ctorDoc ctors)))
329aliasToDoc :: L.Localizer -> Name.Name -> Docs.Alias -> D.Doc
330aliasToDoc localizer name (Docs.Alias _ tvars tipe) =
333 "type" <+> "alias" <+> D.hsep (map D.fromName (name:tvars)) <+> "="
335 D.hang 4 (D.sep [ declaration, typeDoc localizer tipe ])
338valueToDoc :: L.Localizer -> Name.Name -> Docs.Value -> D.Doc
339valueToDoc localizer name (Docs.Value _ tipe) =
340 D.hang 4 $ D.sep [ D.fromName name <+> ":", typeDoc localizer tipe ]
343binopToDoc :: L.Localizer -> Name.Name -> Docs.Binop -> D.Doc
344binopToDoc localizer name (Docs.Binop _ tipe associativity (Docs.Precedence n)) =
345 "(" <> D.fromName name <> ")" <+> ":" <+> typeDoc localizer tipe <> D.black details
348 " (" <> D.fromName assoc <> "/" <> D.fromInt n <> ")"
351 case associativity of
354 Docs.Right -> "right"
357typeDoc :: L.Localizer -> Type.Type -> D.Doc
358typeDoc localizer tipe =
359 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