1{-# LANGUAGE OverloadedStrings #-}
7 , moduleChangeMagnitude
15import Control.Monad (zipWithM)
16import Data.Function (on)
17import qualified Data.List as List
18import qualified Data.Map as Map
19import qualified Data.Name as Name
20import qualified Data.Set as Set
21import qualified Data.Utf8 as Utf8
23import qualified Deps.Website as Website
24import qualified Elm.Compiler.Type as Type
25import qualified Elm.Docs as Docs
26import qualified Elm.Magnitude as M
27import qualified Elm.ModuleName as ModuleName
28import qualified Elm.Package as Pkg
29import qualified Elm.Version as V
32import qualified Json.Decode as D
33import qualified Reporting.Exit as Exit
43 { _modules_added :: [ModuleName.Raw]
44 , _modules_changed :: Map.Map ModuleName.Raw ModuleChanges
45 , _modules_removed :: [ModuleName.Raw]
51 { _unions :: Changes Name.Name Docs.Union
52 , _aliases :: Changes Name.Name Docs.Alias
53 , _values :: Changes Name.Name Docs.Value
54 , _binops :: Changes Name.Name Docs.Binop
60 { _added :: Map.Map k v
61 , _changed :: Map.Map k (v,v)
62 , _removed :: Map.Map k v
66getChanges :: (Ord k) => (v -> v -> Bool) -> Map.Map k v -> Map.Map k v -> Changes k v
67getChanges isEquivalent old new =
69 overlap = Map.intersectionWith (,) old new
70 changed = Map.filter (not . uncurry isEquivalent) overlap
72 Changes (Map.difference new old) changed (Map.difference old new)
79diff :: Docs.Documentation -> Docs.Documentation -> PackageChanges
82 filterOutPatches chngs =
83 Map.filter (\chng -> moduleChangeMagnitude chng /= M.PATCH) chngs
85 (Changes added changed removed) =
86 getChanges (\_ _ -> False) oldDocs newDocs
90 (filterOutPatches (Map.map diffModule changed))
95diffModule :: (Docs.Module, Docs.Module) -> ModuleChanges
96diffModule (Docs.Module _ _ u1 a1 v1 b1, Docs.Module _ _ u2 a2 v2 b2) =
98 (getChanges isEquivalentUnion u1 u2)
99 (getChanges isEquivalentAlias a1 a2)
100 (getChanges isEquivalentValue v1 v2)
101 (getChanges isEquivalentBinop b1 b2)
108isEquivalentUnion :: Docs.Union -> Docs.Union -> Bool
109isEquivalentUnion (Docs.Union oldComment oldVars oldCtors) (Docs.Union newComment newVars newCtors) =
110 length oldCtors == length newCtors
111 && and (zipWith (==) (map fst oldCtors) (map fst newCtors))
112 && and (Map.elems (Map.intersectionWith equiv (Map.fromList oldCtors) (Map.fromList newCtors)))
114 equiv :: [Type.Type] -> [Type.Type] -> Bool
115 equiv oldTypes newTypes =
120 (map (Docs.Alias oldComment oldVars) oldTypes)
121 (map (Docs.Alias newComment newVars) newTypes)
123 length oldTypes == length newTypes
127isEquivalentAlias :: Docs.Alias -> Docs.Alias -> Bool
128isEquivalentAlias (Docs.Alias _ oldVars oldType) (Docs.Alias _ newVars newType) =
129 case diffType oldType newType of
134 length oldVars == length newVars
135 && isEquivalentRenaming (zip oldVars newVars ++ renamings)
138isEquivalentValue :: Docs.Value -> Docs.Value -> Bool
139isEquivalentValue (Docs.Value c1 t1) (Docs.Value c2 t2) =
140 isEquivalentAlias (Docs.Alias c1 [] t1) (Docs.Alias c2 [] t2)
143isEquivalentBinop :: Docs.Binop -> Docs.Binop -> Bool
144isEquivalentBinop (Docs.Binop c1 t1 a1 p1) (Docs.Binop c2 t2 a2 p2) =
145 isEquivalentAlias (Docs.Alias c1 [] t1) (Docs.Alias c2 [] t2)
154diffType :: Type.Type -> Type.Type -> Maybe [(Name.Name,Name.Name)]
155diffType oldType newType =
156 case (oldType, newType) of
157 (Type.Var oldName, Type.Var newName) ->
158 Just [(oldName, newName)]
160 (Type.Lambda a b, Type.Lambda a' b') ->
165 (Type.Type oldName oldArgs, Type.Type newName newArgs) ->
166 if not (isSameName oldName newName) || length oldArgs /= length newArgs then
169 concat <$> zipWithM diffType oldArgs newArgs
171 (Type.Record fields maybeExt, Type.Record fields' maybeExt') ->
172 case (maybeExt, maybeExt') of
179 (Nothing, Nothing) ->
180 diffFields fields fields'
182 (Just oldExt, Just newExt) ->
183 (:) (oldExt, newExt) <$> diffFields fields fields'
185 (Type.Unit, Type.Unit) ->
188 (Type.Tuple a b cs, Type.Tuple x y zs) ->
189 if length cs /= length zs then
192 do aVars <- diffType a x
193 bVars <- diffType b y
194 cVars <- concat <$> zipWithM diffType cs zs
195 return (aVars ++ bVars ++ cVars)
201-- handle very old docs that do not use qualified names
202isSameName :: Name.Name -> Name.Name -> Bool
203isSameName oldFullName newFullName =
206 reverse (Utf8.split 0x2E {-.-} (Name.toUtf8 name))
208 case ( dedot oldFullName, dedot newFullName ) of
209 (oldName:[], newName:_) ->
212 (oldName:_, newName:[]) ->
216 oldFullName == newFullName
219diffFields :: [(Name.Name, Type.Type)] -> [(Name.Name, Type.Type)] -> Maybe [(Name.Name,Name.Name)]
220diffFields oldRawFields newRawFields =
222 sort = List.sortBy (compare `on` fst)
223 oldFields = sort oldRawFields
224 newFields = sort newRawFields
226 if length oldRawFields /= length newRawFields then
229 else if or (zipWith ((/=) `on` fst) oldFields newFields) then
233 concat <$> zipWithM (diffType `on` snd) oldFields newFields
240isEquivalentRenaming :: [(Name.Name,Name.Name)] -> Bool
241isEquivalentRenaming varPairs =
244 Map.toList (foldr insert Map.empty varPairs)
246 insert (old,new) dict =
247 Map.insertWith (++) old [new] dict
255 if all (new ==) rest then
261 length list == Set.size (Set.fromList list)
263 case mapM verify renamings of
267 Just verifiedRenamings ->
268 all compatibleVars verifiedRenamings
270 allUnique (map snd verifiedRenamings)
273compatibleVars :: (Name.Name, Name.Name) -> Bool
274compatibleVars (old, new) =
275 case (categorizeVar old, categorizeVar new) of
276 (CompAppend, CompAppend) -> True
277 (Comparable, Comparable) -> True
278 (Appendable, Appendable) -> True
279 (Number , Number ) -> True
280 (Number , Comparable) -> True
295categorizeVar :: Name.Name -> TypeVarCategory
297 | Name.isCompappendType name = CompAppend
298 | Name.isComparableType name = Comparable
299 | Name.isAppendableType name = Appendable
300 | Name.isNumberType name = Number
308bump :: PackageChanges -> V.Version -> V.Version
309bump changes version =
310 case toMagnitude changes of
321toMagnitude :: PackageChanges -> M.Magnitude
322toMagnitude (PackageChanges added changed removed) =
324 addMag = if null added then M.PATCH else M.MINOR
325 removeMag = if null removed then M.PATCH else M.MAJOR
326 changeMags = map moduleChangeMagnitude (Map.elems changed)
328 maximum (addMag : removeMag : changeMags)
331moduleChangeMagnitude :: ModuleChanges -> M.Magnitude
332moduleChangeMagnitude (ModuleChanges unions aliases values binops) =
334 [ changeMagnitude unions
335 , changeMagnitude aliases
336 , changeMagnitude values
337 , changeMagnitude binops
341changeMagnitude :: Changes k v -> M.Magnitude
342changeMagnitude (Changes added changed removed) =
343 if Map.size removed > 0 || Map.size changed > 0 then
346 else if Map.size added > 0 then
357getDocs :: Stuff.PackageCache -> Http.Manager -> Pkg.Name -> V.Version -> IO (Either Exit.DocsProblem Docs.Documentation)
358getDocs cache manager name version =
359 do let path = Stuff.metadata cache name version "docs.json"
360 exists <- File.exists path
363 do result <- D.fromFile Docs.decoder path
370 return $ Left Exit.DP_Cache
372 do let url = Website.metadata name version "docs.json"
373 Http.post manager url [] Exit.DP_Http $ \body ->
374 case D.fromByteString Docs.decoder body of
376 do File.writeUtf8 path body
380 return $ Left Exit.DP_Data
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