@@ -0,0 +1,187 @@
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"
29+ Name "elm-lang" "core"
32+toString :: Name -> String
34+ user name ++ "/" ++ project name
37+toUrl :: Name -> String
39+ user name ++ "/" ++ project name
42+toFilePath :: Name -> FilePath
44+ user name </> project name
47+fromString :: String -> Maybe Name
49+ case break (=='/') string of
50+ ( user@(_:_), '/' : project@(_:_) )
51+ | all (/='/') project -> Just (Name user project)
55+fromString' :: (MonadError String m) => String -> m Name
57+ Maybe.maybe (throwError $ errorMsg string) return (fromString string)
60+instance Binary Name where
61+ get = Name <$> get <*> get
62+ put (Name user project) =
67+instance FromJSON Name where
68+ parseJSON (String text) =
69+ let string = T.unpack text in
70+ Maybe.maybe (fail $ errorMsg string) return (fromString string)
72+ parseJSON _ = fail "Project name must be a string."
75+instance ToJSON Name where
77+ toJSON (toString name)
80+errorMsg :: String -> String
83+ [ "Dependency file has an invalid name: " ++ string
84+ , "Must have format USER/PROJECT and match a public github project."
90+data Version = Version
98+initialVersion :: Version
102+dummyVersion :: Version
107+bumpPatch :: Version -> Version
108+bumpPatch (Version major minor patch) =
109+ Version major minor (patch + 1)
111+bumpMinor :: Version -> Version
112+bumpMinor (Version major minor _patch) =
113+ Version major (minor + 1) 0
115+bumpMajor :: Version -> Version
116+bumpMajor (Version major _minor _patch) =
117+ Version (major + 1) 0 0
122+filterLatest :: (Ord a) => (Version -> a) -> [Version] -> [Version]
123+filterLatest characteristic versions =
124+ map last (List.groupBy ((==) `on` characteristic) (List.sort versions))
127+majorAndMinor :: Version -> (Int,Int)
128+majorAndMinor (Version major minor _patch) =
134+versionToString :: Version -> String
135+versionToString (Version major minor patch) =
136+ show major ++ "." ++ show minor ++ "." ++ show patch
139+versionFromString :: String -> Maybe Version
140+versionFromString string =
141+ case splitNumbers string of
142+ Just [major, minor, patch] ->
143+ Just (Version major minor patch)
146+ splitNumbers :: String -> Maybe [Int]
148+ case span isDigit ns of
153+ Just [ read numbers ]
155+ (numbers, '.':rest) ->
156+ (read numbers :) <$> splitNumbers rest
161+instance Binary Version where
162+ get = Version <$> get <*> get <*> get
163+ put (Version major minor patch) =
169+instance FromJSON Version where
170+ parseJSON (String text) =
171+ let string = T.unpack text in
172+ case versionFromString string of
176+ [ "Dependency file has an invalid version number: " ++ string
177+ , "Must have format MAJOR.MINOR.PATCH (e.g. 0.1.2)"
181+ fail "Version number must be stored as a string."
184+instance ToJSON Version where
186+ toJSON (versionToString version)