@@ -0,0 +1,182 @@
1+{-# LANGUAGE FlexibleContexts #-}
2+module Elm.Package where
4+import Control.Applicative ((<$>), (<*>))
5+import Control.Monad.Error.Class (MonadError, throwError)
8+import qualified Data.List as List
9+import qualified Data.Text as T
10+import qualified Data.Maybe as Maybe
11+import System.FilePath ((</>))
12+import Data.Char (isDigit)
13+import Data.Function (on)
24+ Name "USER" "PROJECT"
27+toString :: Name -> String
29+ user name ++ "/" ++ project name
32+toUrl :: Name -> String
34+ user name ++ "/" ++ project name
37+toFilePath :: Name -> FilePath
39+ user name </> project name
42+fromString :: String -> Maybe Name
44+ case break (=='/') string of
45+ ( user@(_:_), '/' : project@(_:_) )
46+ | all (/='/') project -> Just (Name user project)
50+fromString' :: (MonadError String m) => String -> m Name
52+ Maybe.maybe (throwError $ errorMsg string) return (fromString string)
55+instance Binary Name where
56+ get = Name <$> get <*> get
57+ put (Name user project) =
62+instance FromJSON Name where
63+ parseJSON (String text) =
64+ let string = T.unpack text in
65+ Maybe.maybe (fail $ errorMsg string) return (fromString string)
67+ parseJSON _ = fail "Project name must be a string."
70+instance ToJSON Name where
72+ toJSON (toString name)
75+errorMsg :: String -> String
78+ [ "Dependency file has an invalid name: " ++ string
79+ , "Must have format USER/PROJECT and match a public github project."
85+data Version = Version
93+initialVersion :: Version
97+dummyVersion :: Version
102+bumpPatch :: Version -> Version
103+bumpPatch (Version major minor patch) =
104+ Version major minor (patch + 1)
106+bumpMinor :: Version -> Version
107+bumpMinor (Version major minor _patch) =
108+ Version major (minor + 1) 0
110+bumpMajor :: Version -> Version
111+bumpMajor (Version major _minor _patch) =
112+ Version (major + 1) 0 0
117+filterLatest :: (Ord a) => (Version -> a) -> [Version] -> [Version]
118+filterLatest characteristic versions =
119+ map last (List.groupBy ((==) `on` characteristic) (List.sort versions))
122+majorAndMinor :: Version -> (Int,Int)
123+majorAndMinor (Version major minor _patch) =
129+versionToString :: Version -> String
130+versionToString (Version major minor patch) =
131+ show major ++ "." ++ show minor ++ "." ++ show patch
134+versionFromString :: String -> Maybe Version
135+versionFromString string =
136+ case splitNumbers string of
137+ Just [major, minor, patch] ->
138+ Just (Version major minor patch)
141+ splitNumbers :: String -> Maybe [Int]
143+ case span isDigit ns of
148+ Just [ read numbers ]
150+ (numbers, '.':rest) ->
151+ (read numbers :) <$> splitNumbers rest
156+instance Binary Version where
157+ get = Version <$> get <*> get <*> get
158+ put (Version major minor patch) =
164+instance FromJSON Version where
165+ parseJSON (String text) =
166+ let string = T.unpack text in
167+ case versionFromString string of
171+ [ "Dependency file has an invalid version number: " ++ string
172+ , "Must have format MAJOR.MINOR.PATCH (e.g. 0.1.2)"
176+ fail "Version number must be stored as a string."
179+instance ToJSON Version where
181+ toJSON (versionToString version)