@@ -1,27 +1,25 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3−module Elm.Project.Json
3+module Elm.Outline
4− ( Project(..)
4+ ( Outline(..)
5− , AppInfo(..)
5+ , AppOutline(..)
6− , PkgInfo(..)
6+ , PkgOutline(..)
7 , Exposed(..)
7 , Exposed(..)
8− , defaultSummary
8+ , read
13− , pkgDecoder
12+ , defaultSummary
15 , isPlatformPackage
13 , isPlatformPackage
17 , getExposed
15 , getExposed
23import Prelude hiding (read)
20import Prelude hiding (read)
24−import Control.Monad.Trans (liftIO)
21+import Control.Monad (filterM, liftM)
22+import Data.Binary (Binary, get, put, getWord8, putWord8)
25import Data.Foldable (traverse_)
23import Data.Foldable (traverse_)
26import qualified Data.Map as Map
24import qualified Data.Map as Map
27import qualified Data.Utf8 as Utf8
25import qualified Data.Utf8 as Utf8
@@ -37,39 +35,30 @@ import qualified Json.Decode as D
37import qualified Json.Encode as E
35import qualified Json.Encode as E
38import qualified Reporting.Exit as Exit
36import qualified Reporting.Exit as Exit
39import qualified Reporting.Exit.Assets as E
37import qualified Reporting.Exit.Assets as E
40−import qualified Reporting.Task as Task
53−-- APPLICATION
44+data Outline
56−data AppInfo =
49+data AppOutline =
57− AppInfo
50+ AppOutline
58 { _app_elm_version :: V.Version
51 { _app_elm_version :: V.Version
59 , _app_source_dirs :: [FilePath]
52 , _app_source_dirs :: [FilePath]
60 , _app_deps_direct :: Map.Map Pkg.Name V.Version
53 , _app_deps_direct :: Map.Map Pkg.Name V.Version
61− , _app_deps_trans :: Map.Map Pkg.Name V.Version
54+ , _app_deps_indirect :: Map.Map Pkg.Name V.Version
62 , _app_test_direct :: Map.Map Pkg.Name V.Version
55 , _app_test_direct :: Map.Map Pkg.Name V.Version
63− , _app_test_trans :: Map.Map Pkg.Name V.Version
56+ , _app_test_indirect :: Map.Map Pkg.Name V.Version
68−-- PACKAGE
61+ PkgOutline
73 { _pkg_name :: Pkg.Name
62 { _pkg_name :: Pkg.Name
74 , _pkg_summary :: Utf8.String
63 , _pkg_summary :: Utf8.String
75 , _pkg_license :: Licenses.License
64 , _pkg_license :: Licenses.License
@@ -99,76 +88,54 @@ defaultSummary =
102−isPlatformPackage :: Project -> Bool
91+isPlatformPackage :: Outline -> Bool
103−isPlatformPackage project =
92+isPlatformPackage outline =
104− case project of
93+ case outline of
108− Pkg info ->
97+ Pkg pkgOutline ->
109− let
98+ let author = Pkg._author (_pkg_name pkgOutline) in
110− (Pkg.Name author _) =
113 author == "elm" || author == "elm-explorations"
99 author == "elm" || author == "elm-explorations"
116−getName :: Project -> Pkg.Name
102+getName :: Outline -> Pkg.Name
117−getName project =
103+getName outline =
118− case project of
104+ case outline of
120 Pkg.dummyName
106 Pkg.dummyName
126−getExposed :: PkgInfo -> [ModuleName.Raw]
128− case _pkg_exposed info of
129− ExposedList modules ->
132− ExposedDict chunks ->
133− concatMap snd chunks
136−check :: Project -> Task.Task ()
139− Pkg (PkgInfo name _ _ _ _ deps _ _) ->
108+ Pkg (PkgOutline name _ _ _ _ _ _ _) ->
140− if name == Pkg.core || Map.member Pkg.core deps
109+ name
142− else throwBadJson E.NoPkgCore
144− App (AppInfo _ _ direct indirect _ _) ->
145− if Map.member Pkg.core direct then
147− if Map.member Pkg.json direct || Map.member Pkg.json indirect
112+getExposed :: PkgOutline -> [ModuleName.Raw]
148− then return ()
113+getExposed (PkgOutline _ _ _ _ exposed _ _ _) =
149− else throwBadJson E.NoAppJson
114+ case exposed of
115+ ExposedList names ->
151− else
118+ ExposedDict sections ->
152− throwBadJson E.NoAppCore
119+ concatMap snd sections
159−write :: FilePath -> Project -> IO ()
126+write :: FilePath -> Outline -> IO ()
160−write root project =
127+write root outline =
161− E.write (root </> "elm.json") (encode project)
128+ E.write (root </> "elm.json") (encode outline)
165-- JSON ENCODE
132-- JSON ENCODE
168−encode :: Project -> E.Value
135+encode :: Outline -> E.Value
169−encode project =
136+encode outline =
170− case project of
137+ case outline of
171− App (AppInfo elm srcDirs depsDirect depsTrans testDirect testTrans) ->
138+ App (AppOutline elm srcDirs depsDirect depsTrans testDirect testTrans) ->
173 [ "type" ==> E.string "application"
140 [ "type" ==> E.string "application"
174 , "source-directories" ==> E.list (E.string . Utf8.fromChars) srcDirs
141 , "source-directories" ==> E.list (E.string . Utf8.fromChars) srcDirs
@@ -185,10 +152,10 @@ encode project =
188− Pkg (PkgInfo name summary license version exposed deps tests elm) ->
155+ Pkg (PkgOutline name summary license version exposed deps tests elm) ->
190 [ "type" ==> E.string "package"
157 [ "type" ==> E.string "package"
191− , "name" ==> E.string (Pkg.toString name)
158+ , "name" ==> Pkg.encode name
192 , "summary" ==> E.string summary
159 , "summary" ==> E.string summary
193 , "license" ==> Licenses.encode license
160 , "license" ==> Licenses.encode license
194 , "version" ==> V.encode version
161 , "version" ==> V.encode version
@@ -228,34 +195,28 @@ encodeDeps encodeValue deps =
228-- PARSE AND VERIFY
195-- PARSE AND VERIFY
231−read :: FilePath -> Task.Task Project
198+read :: FilePath -> IO (Either Exit.OutlineProblem Outline)
232−read path =
199+read root =
233− do result <- liftIO $ D.fromFile decoder path
200+ do result <- D.fromFile decoder (root </> "elm.json")
234 case result of
201 case result of
240− App (AppInfo _ srcDirs _ _ _ _) ->
241− do mapM_ doesDirectoryExist srcDirs
244 Left err ->
202 Left err ->
245− throwBadJson (error "TODO bad json" err)
203+ return $ Left (Exit.BadOutlineStructure err)
208+ return $ Right outline
248−throwBadJson :: E.ElmJsonProblem -> Task.Task a
210+ App (AppOutline _ srcDirs _ _ _ _) ->
249−throwBadJson problem =
211+ do badDirs <- filterM (isBadSrcDir root) srcDirs
250− Task.throw (Exit.Assets (E.BadElmJson problem))
212+ case badDirs of
213+ [] -> return $ Right outline
214+ d:ds -> return $ Left (Exit.BadOutlineSrcDirs d ds)
253−doesDirectoryExist :: FilePath -> Task.Task ()
217+isBadSrcDir :: FilePath -> FilePath -> IO Bool
254−doesDirectoryExist dir =
218+isBadSrcDir root dir =
255− do exists <- liftIO $ Dir.doesDirectoryExist dir
219+ not <$> Dir.doesDirectoryExist (root </> dir)
258− else throwBadJson (E.BadSrcDir dir)
@@ -266,7 +227,7 @@ type Decoder a =
266 D.Decoder E.BadElmJsonContent a
227 D.Decoder E.BadElmJsonContent a
269−decoder :: Decoder Project
230+decoder :: Decoder Outline
271 do tipe <- D.field "type" D.string
232 do tipe <- D.field "type" D.string
272 case tipe of
233 case tipe of
@@ -280,9 +241,9 @@ decoder =
280 D.failure (E.BadType other)
241 D.failure (E.BadType other)
283−appDecoder :: Decoder AppInfo
244+appDecoder :: Decoder AppOutline
284appDecoder =
245appDecoder =
285− AppInfo
246+ AppOutline
286 <$> D.field "elm-version" versionDecoder
247 <$> D.field "elm-version" versionDecoder
287 <*> D.field "source-directories" (D.list dirDecoder)
248 <*> D.field "source-directories" (D.list dirDecoder)
288 <*> D.field "dependencies" (D.field "direct" (depsDecoder versionDecoder))
249 <*> D.field "dependencies" (D.field "direct" (depsDecoder versionDecoder))
@@ -291,12 +252,12 @@ appDecoder =
291 <*> D.field "test-dependencies" (D.field "indirect" (depsDecoder versionDecoder))
252 <*> D.field "test-dependencies" (D.field "indirect" (depsDecoder versionDecoder))
294−pkgDecoder :: Decoder PkgInfo
255+pkgDecoder :: Decoder PkgOutline
295pkgDecoder =
256pkgDecoder =
296− PkgInfo
257+ PkgOutline
297− <$> D.field "name" pkgNameDecoder
258+ <$> D.field "name" (D.mapError E.BadPkgName Pkg.decoder)
298 <*> D.field "summary" summaryDecoder
259 <*> D.field "summary" summaryDecoder
299− <*> D.field "license" licenseDecoder
260+ <*> D.field "license" (Licenses.decoder E.BadLicense)
300 <*> D.field "version" versionDecoder
261 <*> D.field "version" versionDecoder
301 <*> D.field "exposed-modules" exposedDecoder
262 <*> D.field "exposed-modules" exposedDecoder
302 <*> D.field "dependencies" (depsDecoder constraintDecoder)
263 <*> D.field "dependencies" (depsDecoder constraintDecoder)
@@ -308,11 +269,6 @@ pkgDecoder =
308-- JSON DECODE HELPERS
269-- JSON DECODE HELPERS
311−pkgNameDecoder :: Decoder Pkg.Name
313− D.mapError E.BadPkgName Pkg.decoder
316summaryDecoder :: Decoder Utf8.String
272summaryDecoder :: Decoder Utf8.String
317summaryDecoder =
273summaryDecoder =
318 do summary <- D.string
274 do summary <- D.string
@@ -321,11 +277,6 @@ summaryDecoder =
321 else D.failure E.BadSummaryTooLong
277 else D.failure E.BadSummaryTooLong
324−licenseDecoder :: Decoder Licenses.License
326− Licenses.decoder E.BadLicense
329versionDecoder :: Decoder V.Version
280versionDecoder :: Decoder V.Version
330versionDecoder =
281versionDecoder =
331 D.mapError E.BadVersion V.decoder
282 D.mapError E.BadVersion V.decoder
@@ -379,7 +330,68 @@ moduleDecoder =
380checkHeader :: Utf8.String -> Decoder ()
331checkHeader :: Utf8.String -> Decoder ()
381checkHeader header =
332checkHeader header =
382− if Utf8.size header < 20 then
333+ if Utf8.size header < 20
383− return ()
334+ then return ()
385− D.failure (E.BadModuleHeaderTooLong header)
335+ else D.failure (E.BadModuleHeaderTooLong header)
342+instance Binary Outline where
345+ App a -> putWord8 0 >> put a
346+ Pkg a -> putWord8 1 >> put a
353+ _ -> error "binary encoding of Outline was corrupted"
356+instance Binary AppOutline where
357+ put (AppOutline a b c d e f) =
358+ put a >> put b >> put c >> put d >> put e >> put f
367+ return (AppOutline a b c d e f)
370+instance Binary PkgOutline where
371+ put (PkgOutline a b c d e f g h) =
372+ put a >> put b >> put c >> put d >> put e >> put f >> put g >> put h
383+ return (PkgOutline a b c d e f g h)
386+instance Binary Exposed where
389+ ExposedList a -> putWord8 0 >> put a
390+ ExposedDict a -> putWord8 1 >> put a
395+ 0 -> liftM ExposedList get
396+ 1 -> liftM ExposedDict get
397+ _ -> error "binary encoding of ProjectDeps was corrupted"