1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
9 , moduleChangeMagnitude
17import Control.Monad (zipWithM)
18import Data.Function (on)
19import qualified Data.List as List
20import qualified Data.Map as Map
21import qualified Data.Set as Set
22import qualified Data.Text as Text
24import qualified Elm.Compiler.Module as Module
25import qualified Elm.Compiler.Type as Type
26import qualified Elm.Docs as Docs
27import qualified Elm.Name as N
28import qualified Elm.Package as Pkg
37 { _modules_added :: [Module.Raw]
38 , _modules_changed :: Map.Map Module.Raw ModuleChanges
39 , _modules_removed :: [Module.Raw]
45 { _unions :: Changes N.Name Docs.Union
46 , _aliases :: Changes N.Name Docs.Alias
47 , _values :: Changes N.Name Docs.Value
48 , _binops :: Changes N.Name Docs.Binop
54 { _added :: Map.Map k v
55 , _changed :: Map.Map k (v,v)
56 , _removed :: Map.Map k v
60getChanges :: (Ord k) => (v -> v -> Bool) -> Map.Map k v -> Map.Map k v -> Changes k v
61getChanges isEquivalent old new =
63 overlap = Map.intersectionWith (,) old new
64 changed = Map.filter (not . uncurry isEquivalent) overlap
66 Changes (Map.difference new old) changed (Map.difference old new)
73diff :: Docs.Documentation -> Docs.Documentation -> PackageChanges
76 filterOutPatches chngs =
77 Map.filter (\chng -> moduleChangeMagnitude chng /= PATCH) chngs
79 (Changes added changed removed) =
80 getChanges (\_ _ -> False) oldDocs newDocs
84 (filterOutPatches (Map.map diffModule changed))
89diffModule :: (Docs.Module, Docs.Module) -> ModuleChanges
90diffModule (Docs.Module _ _ u1 a1 v1 b1, Docs.Module _ _ u2 a2 v2 b2) =
92 (getChanges isEquivalentUnion u1 u2)
93 (getChanges isEquivalentAlias a1 a2)
94 (getChanges isEquivalentValue v1 v2)
95 (getChanges isEquivalentBinop b1 b2)
102isEquivalentUnion :: Docs.Union -> Docs.Union -> Bool
103isEquivalentUnion (Docs.Union oldComment oldVars oldCtors) (Docs.Union newComment newVars newCtors) =
104 length oldCtors == length newCtors
105 && and (zipWith (==) (map fst oldCtors) (map fst newCtors))
106 && and (Map.elems (Map.intersectionWith equiv (Map.fromList oldCtors) (Map.fromList newCtors)))
108 equiv :: [Type.Type] -> [Type.Type] -> Bool
109 equiv oldTypes newTypes =
114 (map (Docs.Alias oldComment oldVars) oldTypes)
115 (map (Docs.Alias newComment newVars) newTypes)
117 length oldTypes == length newTypes
121isEquivalentAlias :: Docs.Alias -> Docs.Alias -> Bool
122isEquivalentAlias (Docs.Alias _ oldVars oldType) (Docs.Alias _ newVars newType) =
123 case diffType oldType newType of
128 length oldVars == length newVars
129 && isEquivalentRenaming (zip oldVars newVars ++ renamings)
132isEquivalentValue :: Docs.Value -> Docs.Value -> Bool
133isEquivalentValue (Docs.Value c1 t1) (Docs.Value c2 t2) =
134 isEquivalentAlias (Docs.Alias c1 [] t1) (Docs.Alias c2 [] t2)
137isEquivalentBinop :: Docs.Binop -> Docs.Binop -> Bool
138isEquivalentBinop (Docs.Binop c1 t1 a1 p1) (Docs.Binop c2 t2 a2 p2) =
139 isEquivalentAlias (Docs.Alias c1 [] t1) (Docs.Alias c2 [] t2)
148diffType :: Type.Type -> Type.Type -> Maybe [(N.Name,N.Name)]
149diffType oldType newType =
150 case (oldType, newType) of
151 (Type.Var oldName, Type.Var newName) ->
152 Just [(oldName, newName)]
154 (Type.Lambda a b, Type.Lambda a' b') ->
159 (Type.Type oldName oldArgs, Type.Type newName newArgs) ->
160 if not (isSameName oldName newName) || length oldArgs /= length newArgs then
163 concat <$> zipWithM diffType oldArgs newArgs
165 (Type.Record fields maybeExt, Type.Record fields' maybeExt') ->
166 case (maybeExt, maybeExt') of
173 (Nothing, Nothing) ->
174 diffFields fields fields'
176 (Just oldExt, Just newExt) ->
177 (:) (oldExt, newExt) <$> diffFields fields fields'
179 (Type.Unit, Type.Unit) ->
182 (Type.Tuple a b cs, Type.Tuple x y zs) ->
183 if length cs /= length zs then
186 do aVars <- diffType a x
187 bVars <- diffType b y
188 cVars <- concat <$> zipWithM diffType cs zs
189 return (aVars ++ bVars ++ cVars)
195-- handle very old docs that do not use qualified names
196isSameName :: N.Name -> N.Name -> Bool
197isSameName oldFullName newFullName =
200 reverse (Text.splitOn "." (N.toText name))
202 case ( dedot oldFullName, dedot newFullName ) of
203 (oldName:[], newName:_) ->
206 (oldName:_, newName:[]) ->
210 oldFullName == newFullName
213diffFields :: [(N.Name, Type.Type)] -> [(N.Name, Type.Type)] -> Maybe [(N.Name,N.Name)]
214diffFields oldRawFields newRawFields =
216 sort = List.sortBy (compare `on` fst)
217 oldFields = sort oldRawFields
218 newFields = sort newRawFields
220 if length oldRawFields /= length newRawFields then
223 else if or (zipWith ((/=) `on` fst) oldFields newFields) then
227 concat <$> zipWithM (diffType `on` snd) oldFields newFields
234isEquivalentRenaming :: [(N.Name,N.Name)] -> Bool
235isEquivalentRenaming varPairs =
238 Map.toList (foldr insert Map.empty varPairs)
240 insert (old,new) dict =
241 Map.insertWith (++) old [new] dict
249 if all (new ==) rest then
255 length list == Set.size (Set.fromList list)
257 case mapM verify renamings of
261 Just verifiedRenamings ->
262 all compatibleVars verifiedRenamings
264 allUnique (map snd verifiedRenamings)
267compatibleVars :: (N.Name, N.Name) -> Bool
268compatibleVars (old, new) =
269 case (categorizeVar old, categorizeVar new) of
270 (CompAppend, CompAppend) -> True
271 (Comparable, Comparable) -> True
272 (Appendable, Appendable) -> True
273 (Number , Number ) -> True
274 (Number , Comparable) -> True
289categorizeVar :: N.Name -> TypeVarCategory
291 | N.startsWith "compappend" name = CompAppend
292 | N.startsWith "comparable" name = Comparable
293 | N.startsWith "appendable" name = Appendable
294 | N.startsWith "number" name = Number
309magnitudeToString :: Magnitude -> String
310magnitudeToString magnitude =
322bump :: PackageChanges -> Pkg.Version -> Pkg.Version
323bump changes version =
324 case toMagnitude changes of
326 Pkg.bumpPatch version
329 Pkg.bumpMinor version
332 Pkg.bumpMajor version
335toMagnitude :: PackageChanges -> Magnitude
336toMagnitude (PackageChanges added changed removed) =
338 addMag = if null added then PATCH else MINOR
339 removeMag = if null removed then PATCH else MAJOR
340 changeMags = map moduleChangeMagnitude (Map.elems changed)
342 maximum (addMag : removeMag : changeMags)
345moduleChangeMagnitude :: ModuleChanges -> Magnitude
346moduleChangeMagnitude (ModuleChanges unions aliases values binops) =
348 [ changeMagnitude unions
349 , changeMagnitude aliases
350 , changeMagnitude values
351 , changeMagnitude binops
355changeMagnitude :: Changes k v -> Magnitude
356changeMagnitude (Changes added changed removed) =
357 if Map.size removed > 0 || Map.size changed > 0 then
360 else if Map.size added > 0 then
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