@@ -1,6 +1,18 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3−module Elm.Package where
3+module Elm.Package
6+ , dummyName, core, virtualDom, html
7+ , toString, toText, toUrl, toFilePath
10+ , initialVersion, dummyVersion
11+ , bumpPatch, bumpMinor, bumpMajor
12+ , filterLatest, majorAndMinor
13+ , versionToString, versionFromText
5import Data.Aeson
17import Data.Aeson
6import Data.Binary
18import Data.Binary
@@ -9,6 +21,7 @@ import Data.Function (on)
9import qualified Data.List as List
21import qualified Data.List as List
10import Data.Monoid ((<>))
22import Data.Monoid ((<>))
11import qualified Data.Text as Text
23import qualified Data.Text as Text
24+import qualified Data.Text.Read as Text
12import Data.Text (Text)
25import Data.Text (Text)
13import System.FilePath ((</>))
26import System.FilePath ((</>))
@@ -17,7 +30,8 @@ import System.FilePath ((</>))
17-- PACKGE NAMES
30-- PACKGE NAMES
20−data Name = Name
33+data Name =
21 { _user :: Text
35 { _user :: Text
22 , _project :: Text
36 , _project :: Text
@@ -67,68 +81,32 @@ toFilePath (Name user project) =
67 Text.unpack user </> Text.unpack project
81 Text.unpack user </> Text.unpack project
70−fromString :: String -> Either String Name
84+fromText :: Text -> Either String Name
71−fromString string =
85+fromText text =
72− case break (=='/') string of
86+ case Text.splitOn "/" text of
73− ( user, '/' : project ) ->
87+ [ user, project ] | not (Text.null user || Text.null project) ->
74− if null user then
88+ Name user <$> validateProjectName project
75− Left "You did not provide a user name (user/project)"
77− else if null project then
90+ _ ->
78− Left "You did not provide a project name (user/project)"
91+ Left "A valid project name looks like `user/project`"
80− else if all (/='/') project then
81− Name (Text.pack user) <$> validateProjectName project
83− else
94+validateProjectName :: Text -> Either String Text
84− Left "Expecting only one slash, separating the user and project name (user/project)"
95+validateProjectName text =
96+ if Text.isInfixOf "--" text then
97+ Left "There is a double dash -- in your package name. It must be a single dash."
86− _ ->
99+ else if Text.isInfixOf "_" text then
87− Left "There should be a slash separating the user and project name (user/project)"
90−whitelistedUppercaseName :: String -> Bool
91−whitelistedUppercaseName name =
92− -- These packages were uploaded to package.elm-lang.org before version 0.16,
93− -- when uppercase letters were disallowed in package names.
94− -- They should be considered deprecated and removed from this list once users
95− -- migrate to using the lowercase versions of the names.
99− , "elm-MultiDimArray"
106− , "Elm-Align-Distribute"
107− , "Elm-Format-String"
109− , "Elm-Random-Sampling"
116−validateProjectName :: String -> Either String Text
117−validateProjectName str =
118− if elem ('-','-') (zip str (tail str)) then
119− Left "There is a double dash -- in your package name. It must be a single dash."
121− else if elem '_' str then
122− Left "Underscores are not allowed in package names."
100+ Left "Underscores are not allowed in package names."
124− else if any Char.isUpper str && not (whitelistedUppercaseName str) then
102+ else if Text.any Char.isUpper text then
125− Left "Upper case characters are not allowed in package names."
103+ Left "Upper case characters are not allowed in package names."
127− else if not (Char.isLetter (head str)) then
105+ else if not (Char.isLetter (Text.head text)) then
128− Left "Package names must start with a letter."
106+ Left "Package names must start with a letter."
131− Right (Text.pack str)
109+ Right text
134instance Binary Name where
112instance Binary Name where
@@ -140,15 +118,14 @@ instance Binary Name where
141instance FromJSON Name where
119instance FromJSON Name where
142 parseJSON (String text) =
120 parseJSON (String text) =
143− let
121+ case fromText text of
144− string = Text.unpack text
146− case fromString string of
147− Left msg ->
122+ Left msg ->
148− fail ("Ran into an invalid package name: " ++ string ++ "\n\n" ++ msg)
124+ "Ran into an invalid package name: "
125+ ++ Text.unpack text ++ "\n\n" ++ msg
150− Right name ->
127+ Right name ->
151− return name
128+ return name
153 parseJSON _ =
130 parseJSON _ =
154 fail "Project name must be a string."
131 fail "Project name must be a string."
@@ -161,7 +138,8 @@ instance ToJSON Name where
162-- PACKAGE VERSIONS
139-- PACKAGE VERSIONS
164−data Version = Version
141+data Version =
165 { _major :: Int
143 { _major :: Int
166 , _minor :: Int
144 , _minor :: Int
167 , _patch :: Int
145 , _patch :: Int
@@ -210,53 +188,52 @@ versionToString (Version major minor patch) =
210 show major ++ "." ++ show minor ++ "." ++ show patch
188 show major ++ "." ++ show minor ++ "." ++ show patch
213−versionFromString :: String -> Either String Version
191+versionFromText :: Text -> Either String Version
214−versionFromString string =
192+versionFromText text =
215− case splitNumbers string of
193+ let
216− Just [major, minor, patch] ->
194+ chunks =
217− Right (Version major minor patch)
195+ Text.splitOn "." text
219− Left "Must have format MAJOR.MINOR.PATCH (e.g. 1.0.2)"
221− splitNumbers :: String -> Maybe [Int]
223− case span Char.isDigit ns of
227− (numbers, []) ->
197+ toNumber txt =
198+ case Text.decimal txt of
228− Just [ read numbers ]
200+ Just n
230− (numbers, '.':rest) ->
202+ _ ->
231− (read numbers :) <$> splitNumbers rest
203+ Nothing
205+ case traverse toNumber chunks of
206+ Just [major, minor, patch] ->
207+ Right (Version major minor patch)
234− Nothing
210+ Left "Must have format MAJOR.MINOR.PATCH (e.g. 1.0.2)"
237instance Binary Version where
213instance Binary Version where
238− get = Version <$> get <*> get <*> get
215+ Version <$> get <*> get <*> get
239− put (Version major minor patch) =
217+ put (Version major minor patch) =
245−instance FromJSON Version where
246− parseJSON (String text) =
247− let string = Text.unpack text in
248− case versionFromString string of
223+instance FromJSON Version where
224+ parseJSON (String text) =
225+ case versionFromText text of
252− Left problem ->
229+ Left problem ->
253− fail $ unlines
230+ fail $ unlines $
254− [ "Ran into an invalid version number: " ++ string
231+ [ "Ran into an invalid version number: " ++ Text.unpack text
255− , problem
232+ , problem
258− parseJSON _ =
235+ parseJSON _ =
259− fail "Version number must be stored as a string."
236+ fail "Version number must be stored as a string."
262instance ToJSON Version where
239instance ToJSON Version where