on master help sign in
Merge pull request #1 from elm-lang/master
fc1c4d4Christian Widera
Elm.cabal+4−4
@@ -1,5 +1,5 @@
1Name: Elm
1Name: Elm
2−Version: 0.11
2+Version: 0.12
3Synopsis: The Elm language module.
3Synopsis: The Elm language module.
4Description: Elm aims to make client-side web-development more pleasant.
4Description: Elm aims to make client-side web-development more pleasant.
5 It is a statically/strongly typed, functional reactive
5 It is a statically/strongly typed, functional reactive
@@ -14,13 +14,13 @@ License-file: LICENSE
14
14
15Author: Evan Czaplicki
15Author: Evan Czaplicki
16Maintainer: info@elm-lang.org
16Maintainer: info@elm-lang.org
17−Copyright: Copyright: (c) 2011-2013 Evan Czaplicki
17+Copyright: Copyright: (c) 2011-2014 Evan Czaplicki
18
18
19Category: Compiler, Language
19Category: Compiler, Language
20
20
21Build-type: Custom
21Build-type: Custom
22
22
23−Extra-source-files: changelog.txt
23+Extra-source-files: changelog.md
24Data-dir: data
24Data-dir: data
25Data-files: elm-runtime.js interfaces.data docs.json
25Data-files: elm-runtime.js interfaces.data docs.json
26Cabal-version: >=1.9
26Cabal-version: >=1.9
@@ -251,7 +251,7 @@ Test-Suite test-elm
251 Elm,
251 Elm,
252 test-framework,
252 test-framework,
253 test-framework-hunit,
253 test-framework-hunit,
254− test-framework-quickcheck2,
254+ test-framework-quickcheck2 >= 0.3,
255 HUnit,
255 HUnit,
256 pretty,
256 pretty,
257 QuickCheck >= 2 && < 3,
257 QuickCheck >= 2 && < 3,
LICENSE+1−1
@@ -1,4 +1,4 @@
1−Copyright (c) 2012-2013, Evan Czaplicki
1+Copyright (c) 2012-2014, Evan Czaplicki
2
2
3All rights reserved.
3All rights reserved.
4
4
README.md+3−3
@@ -1,10 +1,10 @@
1Learn about the Elm programming language at [elm-lang.org](http://elm-lang.org/).
1Learn about the Elm programming language at [elm-lang.org](http://elm-lang.org/).
2
2
3−[![Build Status](https://travis-ci.org/evancz/Elm.png)](https://travis-ci.org/evancz/Elm)
3+[![Build Status](https://travis-ci.org/elm-lang/Elm.png)](https://travis-ci.org/elm-lang/Elm)
4
4
5## Install
5## Install
6
6
7−**Arch Linux** &mdash; follow [these directions](https://github.com/evancz/Elm/wiki/Installing-Elm#arch-linux) and then
7+**Arch Linux** &mdash; follow [these directions](https://github.com/elm-lang/Elm/wiki/Installing-Elm#arch-linux) and then
8jump to the [My First Project](#my-first-project) section.
8jump to the [My First Project](#my-first-project) section.
9<br/>
9<br/>
10**OS X 10.9 or XCode 5** &mdash; follow
10**OS X 10.9 or XCode 5** &mdash; follow
@@ -51,7 +51,7 @@ The `elm` package provides
51working with Elm in Haskell. This can be useful for creating tooling
51working with Elm in Haskell. This can be useful for creating tooling
52for Elm, and has been useful for projects like
52for Elm, and has been useful for projects like
53[the website](http://elm-lang.org/) and
53[the website](http://elm-lang.org/) and
54−[`elm-get`](https://github.com/evancz/elm-get). Email the list if you
54+[`elm-get`](https://github.com/elm-lang/elm-get). Email the list if you
55want to rely on these functions!
55want to rely on these functions!
56
56
57If you are stuck, email
57If you are stuck, email
changelog.txt → changelog.mdrenamed+17−4
@@ -1,9 +1,22 @@
1
1
2−## next
2+## 0.13
3
3
4−Breaking Changes:
4+#### Breaking Changes:
5
5
6+ * Revamp Json library, simpler with better names
7+ * Revamp JavaScript.Experimental library to have slightly better names
8+ * Remove JavaScript library which was made redundant by ports
9+
10+## Improvements:
11+
12+ * Json.Value can flow through ports, so you can bring in values even
13+ if they don't conform to a consistent type.
14+
15+## 0.12
16+
17+#### Breaking Changes:
18+
6− * Overhaul Graphics.Input library (inspired by @seliopou and Jeff Smits)
19+ * Overhaul Graphics.Input library (inspired by Spiros Eliopoulos and Jeff Smitts)
7 * Overhaul Text library to accomodate new Graphics.Input.Field
20 * Overhaul Text library to accomodate new Graphics.Input.Field
8 library and make the API more consistent overall
21 library and make the API more consistent overall
9 * Overhaul Regex library (inspired by Attila Gazso)
22 * Overhaul Regex library (inspired by Attila Gazso)
@@ -13,7 +26,7 @@ Breaking Changes:
13 * Revise the semantics of keepWhen and dropWhen to only update when
26 * Revise the semantics of keepWhen and dropWhen to only update when
14 the filtered signal changes (thanks Max New and Janis Voigtländer)
27 the filtered signal changes (thanks Max New and Janis Voigtländer)
15
28
16−Improvements:
29+#### Improvements:
17
30
18 * Add Graphics.Input.Field for customizable text fields
31 * Add Graphics.Input.Field for customizable text fields
19 * Add Trampoline library (thanks to @maxsnew and @timthelion)
32 * Add Trampoline library (thanks to @maxsnew and @timthelion)
compiler/Build/Flags.hs+1−1
@@ -41,4 +41,4 @@ flags = Flags
41 } &= help "Compile Elm programs to HTML, CSS, and JavaScript."
41 } &= help "Compile Elm programs to HTML, CSS, and JavaScript."
42 &= helpArg [explicit, name "help", name "h"]
42 &= helpArg [explicit, name "help", name "h"]
43 &= versionArg [explicit, name "version", name "v", summary (show Version.elmVersion)]
43 &= versionArg [explicit, name "version", name "v", summary (show Version.elmVersion)]
44− &= summary ("The Elm Compiler " ++ show Version.elmVersion ++ ", (c) Evan Czaplicki 2011-2013")
44+ &= summary ("The Elm Compiler " ++ show Version.elmVersion ++ ", (c) Evan Czaplicki 2011-2014")
compiler/Generate/JavaScript.hs+9−7
@@ -39,7 +39,6 @@ internalImports name =
39 , include "_U" "_N.Utils"
39 , include "_U" "_N.Utils"
40 , include "_L" "_N.List"
40 , include "_L" "_N.List"
41 , include "_E" "_N.Error"
41 , include "_E" "_N.Error"
42− , include "_J" "_N.JavaScript"
43 , varDecl "$moduleName" (string name)
42 , varDecl "$moduleName" (string name)
44 ]
43 ]
45
44
@@ -55,7 +54,7 @@ literal lit =
55expression :: Expr -> State Int (Expression ())
54expression :: Expr -> State Int (Expression ())
56expression (A region expr) =
55expression (A region expr) =
57 case expr of
56 case expr of
58− Var (V.Raw x) -> return $ ref x
57+ Var (V.Raw x) -> return $ obj x
59 Literal lit -> return $ literal lit
58 Literal lit -> return $ literal lit
60
59
61 Range lo hi ->
60 Range lo hi ->
@@ -87,10 +86,9 @@ expression (A region expr) =
87 do fields' <- forM fields $ \(f,e) -> do
86 do fields' <- forM fields $ \(f,e) -> do
88 (,) f <$> expression e
87 (,) f <$> expression e
89 let fieldMap = List.foldl' combine Map.empty fields'
88 let fieldMap = List.foldl' combine Map.empty fields'
90− return $ ObjectLit () $ (PropId () (var "_"), hidden fieldMap) : visible fieldMap
89+ return $ ObjectLit () $ (prop "_", hidden fieldMap) : visible fieldMap
91 where
90 where
92 combine r (k,v) = Map.insertWith (++) k [v] r
91 combine r (k,v) = Map.insertWith (++) k [v] r
93− prop = PropId () . var
94 hidden fs = ObjectLit () . map (prop *** ArrayLit ()) .
92 hidden fs = ObjectLit () . map (prop *** ArrayLit ()) .
95 Map.toList . Map.filter (not . null) $ Map.map tail fs
93 Map.toList . Map.filter (not . null) $ Map.map tail fs
96 visible fs = map (first prop) . Map.toList $ Map.map head fs
94 visible fs = map (first prop) . Map.toList $ Map.map head fs
@@ -164,7 +162,7 @@ expression (A region expr) =
164
162
165 ExplicitList es ->
163 ExplicitList es ->
166 do es' <- mapM expression es
164 do es' <- mapM expression es
167− return $ obj "_J.toList" <| ArrayLit () es'
165+ return $ obj "_L.fromArray" <| ArrayLit () es'
168
166
169 Data name es ->
167 Data name es ->
170 do es' <- mapM expression es
168 do es' <- mapM expression es
@@ -243,7 +241,11 @@ match region mtch =
243 isLiteral p = case p of
241 isLiteral p = case p of
244 Case.Clause (Right _) _ _ -> True
242 Case.Clause (Right _) _ _ -> True
245 _ -> False
243 _ -> False
244+
245+ access name
246− access name = if any isLiteral clauses then ref name else dotSep [name,"ctor"]
246+ | any isLiteral clauses = obj name
247+ | otherwise = dotSep (split name ++ ["ctor"])
248+
247 format isChars e
249 format isChars e
248 | or isChars = InfixExpr () OpAdd e (string "")
250 | or isChars = InfixExpr () OpAdd e (string "")
249 | otherwise = e
251 | otherwise = e
@@ -307,7 +309,7 @@ generate unsafeModule =
307 jsExports = assign ("_elm" : names modul ++ ["values"]) (ObjectLit () exs)
309 jsExports = assign ("_elm" : names modul ++ ["values"]) (ObjectLit () exs)
308 where
310 where
309 exs = map entry . filter (not . Help.isOp) $ "_op" : exports modul
311 exs = map entry . filter (not . Help.isOp) $ "_op" : exports modul
310− entry x = (PropId () (var x), ref x)
312+ entry x = (prop x, ref x)
311
313
312 assign path expr =
314 assign path expr =
313 case path of
315 case path of
compiler/Generate/JavaScript/Ports.hs+14−15
@@ -35,17 +35,17 @@ inc tipe x =
35 case tipe of
35 case tipe of
36 Lambda _ _ -> error "functions should not be allowed through input ports"
36 Lambda _ _ -> error "functions should not be allowed through input ports"
37 Var _ -> error "type variables should not be allowed through input ports"
37 Var _ -> error "type variables should not be allowed through input ports"
38+
39+ Data "Json.Value" [] ->
40+ obj "Native.Json.fromJS" <| x
41+
38 Data ctor []
42 Data ctor []
39− | ctor == "Int" -> elm JSNumber
43+ | ctor == "Int" -> from JSNumber
40− | ctor == "Float" -> elm JSNumber
44+ | ctor == "Float" -> from JSNumber
41− | ctor == "Bool" -> elm JSBoolean
45+ | ctor == "Bool" -> from JSBoolean
42− | ctor == "String" -> elm JSString
46+ | ctor == "String" -> from JSString
43− | ctor == "JavaScript.JSNumber" -> js JSNumber
44− | ctor == "JavaScript.JSBool" -> js JSBoolean
45− | ctor == "JavaScript.JSString" -> js JSString
46 where
47 where
47− elm checks = check x checks (obj ("_J.to" ++ ctor) <| x)
48− js checks = check x checks x
48+ from checks = check x checks x
49
49
50 Data ctor [t]
50 Data ctor [t]
51 | ctor == "Maybe.Maybe" ->
51 | ctor == "Maybe.Maybe" ->
@@ -54,7 +54,7 @@ inc tipe x =
54 (obj "Maybe.Just" <| inc t x)
54 (obj "Maybe.Just" <| inc t x)
55
55
56 | ctor == "_List" ->
56 | ctor == "_List" ->
57− check x JSArray (obj "_J.toList" <| array)
57+ check x JSArray (obj "_L.fromArray" <| array)
58 where
58 where
59 array = DotRef () x (var "map") <| incoming t
59 array = DotRef () x (var "map") <| incoming t
60
60
@@ -104,10 +104,9 @@ out tipe x =
104
104
105 Var _ -> error "type variables should not be allowed through input ports"
105 Var _ -> error "type variables should not be allowed through input ports"
106 Data ctor []
106 Data ctor []
107− | ctor `elem` ["Int","Float","Bool","String"] -> obj ("_J.from" ++ ctor) <| x
107+ | ctor `elem` ["Int","Float","Bool","String"] -> x
108− | ctor `elem` jsPrims -> x
108+ | ctor == "Json.Value" ->
109− where
109+ obj "Native.Json.toJS" <| x
110− jsPrims = map ("JavaScript.JS"++) ["Number","Bool","String"]
111
110
112 Data ctor [t]
111 Data ctor [t]
113 | ctor == "Maybe.Maybe" ->
112 | ctor == "Maybe.Maybe" ->
@@ -116,7 +115,7 @@ out tipe x =
116 (out t (DotRef () x (var "_0")))
115 (out t (DotRef () x (var "_0")))
117
116
118 | ctor == "_List" ->
117 | ctor == "_List" ->
119− DotRef () (obj "_J.fromList" <| x) (var "map") <| outgoing t
118+ DotRef () (obj "_L.toArray" <| x) (var "map") <| outgoing t
120
119
121 Data ctor ts
120 Data ctor ts
122 | Help.isTuple ctor ->
121 | Help.isTuple ctor ->
compiler/Metadata/Prelude.hs+3−1
@@ -25,7 +25,9 @@ prelude = string ++ text ++ map (\n -> (n, Hiding [])) modules
25 text = map ((,) "Text") [ As "Text", Hiding ["link", "color", "height"] ]
25 text = map ((,) "Text") [ As "Text", Hiding ["link", "color", "height"] ]
26 string = map ((,) "String") [ As "String", Importing ["show"] ]
26 string = map ((,) "String") [ As "String", Importing ["show"] ]
27 modules = [ "Basics", "Signal", "List", "Maybe", "Time", "Color"
27 modules = [ "Basics", "Signal", "List", "Maybe", "Time", "Color"
28− , "Graphics.Element", "Graphics.Collage", "Native.Ports" ]
28+ , "Graphics.Element", "Graphics.Collage"
29+ , "Native.Ports", "Native.Json"
30+ ]
29
31
30interfaces :: Bool -> IO Interfaces
32interfaces :: Bool -> IO Interfaces
31interfaces noPrelude =
33interfaces noPrelude =
compiler/Parse/Helpers.hs+5−3
@@ -79,9 +79,11 @@ innerVarChar :: IParser Char
79innerVarChar = alphaNum <|> char '_' <|> char '\'' <?> ""
79innerVarChar = alphaNum <|> char '_' <|> char '\'' <?> ""
80
80
81makeVar :: IParser Char -> IParser String
81makeVar :: IParser Char -> IParser String
82+makeVar p = do
82−makeVar p = do v <- (:) <$> p <*> many innerVarChar
83+ v <- (:) <$> p <*> many innerVarChar
83− guard (v `notElem` reserveds)
84+ if v `elem` reserveds
85+ then fail $ "unexpected keyword '" ++ v ++ "', variables cannot be keywords"
84− return v
86+ else return v
85
87
86reserved :: String -> IParser String
88reserved :: String -> IParser String
87reserved word =
89reserved word =
compiler/Type/ExtraChecks.hs+10−14
@@ -8,7 +8,6 @@ module Type.ExtraChecks (mainType, occurs, portTypes) where
8
8
9import Control.Applicative ((<$>),(<*>))
9import Control.Applicative ((<$>),(<*>))
10import Control.Monad.State
10import Control.Monad.State
11−import qualified Data.List as List
12import qualified Data.Map as Map
11import qualified Data.Map as Map
13import qualified Data.Traversable as Traverse
12import qualified Data.Traversable as Traverse
14import qualified Data.UnionFind.IO as UF
13import qualified Data.UnionFind.IO as UF
@@ -56,9 +55,15 @@ portTypes rules expr =
56 isValid isTopLevel seenFunc seenSignal direction name tipe =
55 isValid isTopLevel seenFunc seenSignal direction name tipe =
57 case tipe of
56 case tipe of
58 ST.Data ctor ts
57 ST.Data ctor ts
59− | isJs ctor || isElm ctor -> mapM_ valid ts
58+ | validConstructor -> mapM_ valid ts
60 | ctor == "Signal.Signal" -> handleSignal ts
59 | ctor == "Signal.Signal" -> handleSignal ts
61 | otherwise -> err' True "an unsupported type"
60 | otherwise -> err' True "an unsupported type"
61+ where
62+ primitives =
63+ ["Int","Float","String","Bool","Maybe.Maybe","_List","Json.Value"]
64+
65+ validConstructor =
66+ ctor `elem` primitives || Help.isTuple ctor
62
67
63 ST.Var _ -> err "free type variables"
68 ST.Var _ -> err "free type variables"
64
69
@@ -80,14 +85,6 @@ portTypes rules expr =
80 isValid' = isValid False
85 isValid' = isValid False
81 valid = isValid' seenFunc seenSignal direction name
86 valid = isValid' seenFunc seenSignal direction name
82
87
83− isJs ctor =
84− List.isPrefixOf "JavaScript." ctor
85− && length (filter (=='.') ctor) == 1
86−
87− isElm ctor =
88− ctor `elem` ["Int","Float","String","Bool","Maybe.Maybe","_List"]
89− || Help.isTuple ctor
90−
91 handleSignal ts
88 handleSignal ts
92 | seenFunc = err "functions that involve signals"
89 | seenFunc = err "functions that involve signals"
93 | seenSignal = err "signals-of-signals"
90 | seenSignal = err "signals-of-signals"
@@ -104,10 +101,9 @@ portTypes rules expr =
104 , " through port '", name, "' is invalid." ]
101 , " through port '", name, "' is invalid." ]
105 , txt [ "It contains ", kind, ":\n" ]
102 , txt [ "It contains ", kind, ":\n" ]
106 , (P.nest 4 . SPP.pretty $ Alias.realias rules tipe) <> P.text "\n"
103 , (P.nest 4 . SPP.pretty $ Alias.realias rules tipe) <> P.text "\n"
107− , txt [ "Acceptable values for ", dir "incoming" "outgoing"
104+ , txt [ "Acceptable values for ", dir "incoming" "outgoing", " ports include:" ]
108− , " ports include JavaScript values and" ]
109− , txt [ "the following Elm values: Ints, Floats, Bools, Strings, Maybes," ]
105+ , txt [ " Ints, Floats, Bools, Strings, Maybes, Lists, Tuples," ]
110− , txt [ "Lists, Tuples, ", dir "" "first-order functions, ", "and concrete records." ]
106+ , txt [ " Json.Values, ", dir "" "first-order functions, ", "and concrete records." ]
111 ] ++ if couldBeAlias then aliasWarning else []
107 ] ++ if couldBeAlias then aliasWarning else []
112
108
113 aliasWarning =
109 aliasWarning =
libraries/Basics.elm+27
@@ -39,6 +39,9 @@ which happen to be radians.
39# Polar Coordinates
39# Polar Coordinates
40@docs toPolar, fromPolar
40@docs toPolar, fromPolar
41
41
42+# Floating Point Checks
43+@docs isNaN, isInfinite
44+
42# Tuples
45# Tuples
43@docs fst, snd
46@docs fst, snd
44
47
@@ -271,6 +274,30 @@ ceiling = Native.Basics.ceiling
271toFloat : Int -> Float
274toFloat : Int -> Float
272toFloat = Native.Basics.toFloat
275toFloat = Native.Basics.toFloat
273
276
277+{- | Determines whether a float is an undefined or unrepresentable number.
278+NaN stands for *not a number* and it is [a standardized part of floating point
279+numbers](http://en.wikipedia.org/wiki/NaN).
280+
281+ isNaN (0/0) == True
282+ isNaN (sqrt -1) == True
283+ isNaN (1/0) == False -- infinity is a number
284+ isNaN 1 == False
285+-}
286+isNaN : Float -> Bool
287+isNaN = Native.Basics.isNaN
288+
289+{- | Determines whether a float is positive or negative infinity.
290+
291+ isInfinite (0/0) == False
292+ isInfinite (sqrt -1) == False
293+ isInfinite (1/0) == True
294+ isInfinite 1 == False
295+
296+Notice that NaN is not infinite! For float `n` to be finite implies that
297+`not (isInfinite n || isNaN n)` evaluates to `True`.
298+-}
299+isInfinite : Float -> Bool
300+isInfinite = Native.Basics.isInfinite
274
301
275-- Function Helpers
302-- Function Helpers
276
303
libraries/Char.elm+2−2
@@ -52,8 +52,8 @@ toLocaleLower = Native.Char.toLocaleLower
52
52
53type KeyCode = Int
53type KeyCode = Int
54
54
55−{-| Convert to unicode. Used with the [`Keyboard`](/docs/Keyboard.elm)
55+{-| Convert to unicode. Used with the `Keyboard` library, which expects the
56−library, which expects the input to be uppercase. -}
56+input to be uppercase. -}
57toCode : Char -> KeyCode
57toCode : Char -> KeyCode
58toCode = Native.Char.toCode
58toCode = Native.Char.toCode
59
59
libraries/Debug.elm+2
@@ -1,6 +1,8 @@
1module Debug where
1module Debug where
2{-| This library is for investigating bugs or performance problems. It should
2{-| This library is for investigating bugs or performance problems. It should
3*not* be used in production code.
3*not* be used in production code.
4+
5+@docs log
4-}
6-}
5
7
6import Native.Debug
8import Native.Debug
libraries/Graphics/Collage.elm−1
@@ -38,7 +38,6 @@ import Native.Graphics.Collage
38import Graphics.Element (Element)
38import Graphics.Element (Element)
39import Color (Color, black, Gradient)
39import Color (Color, black, Gradient)
40import Maybe (Maybe)
40import Maybe (Maybe)
41−import JavaScript (JSString)
42
41
43type Form = {
42type Form = {
44 theta : Float,
43 theta : Float,
libraries/Graphics/Element.elm+10−13
@@ -39,8 +39,6 @@ If you need more precision, you can create custom positions.
39
39
40import Basics (..)
40import Basics (..)
41import Native.Utils
41import Native.Utils
42−import JavaScript as JS
43−import JavaScript (JSString)
44import List as List
42import List as List
45import Color (..)
43import Color (..)
46import Maybe (Maybe, Just, Nothing)
44import Maybe (Maybe, Just, Nothing)
@@ -51,8 +49,8 @@ type Properties = {
51 height : Int,
49 height : Int,
52 opacity : Float,
50 opacity : Float,
53 color : Maybe Color,
51 color : Maybe Color,
54− href : JSString,
52+ href : String,
55− tag : JSString,
53+ tag : String,
56 hover : (),
54 hover : (),
57 click : ()
55 click : ()
58 }
56 }
@@ -120,21 +118,20 @@ with a link like this: `/facts-about-animals.elm#all-about-badgers`
120-}
118-}
121tag : String -> Element -> Element
119tag : String -> Element -> Element
122tag name e = let p = e.props in
120tag name e = let p = e.props in
123− { element=e.element, props={p | tag <- JS.fromString name} }
121+ { element=e.element, props={p | tag <- name} }
124
122
125{-| Create an `Element` that is a hyper-link. -}
123{-| Create an `Element` that is a hyper-link. -}
126link : String -> Element -> Element
124link : String -> Element -> Element
127link href e = let p = e.props in
125link href e = let p = e.props in
128− { element=e.element, props={p | href <- JS.fromString href} }
126+ { element=e.element, props={p | href <- href} }
129
127
130−emptyStr = JS.fromString ""
131newElement w h e =
128newElement w h e =
132− { props = Properties (Native.Utils.guid ()) w h 1 Nothing emptyStr emptyStr () ()
129+ { props = Properties (Native.Utils.guid ()) w h 1 Nothing "" "" () ()
133 , element = e
130 , element = e
134 }
131 }
135
132
136data ElementPrim
133data ElementPrim
137− = Image ImageStyle Int Int JSString
134+ = Image ImageStyle Int Int String
138 | Container Position Element
135 | Container Position Element
139 | Flow Direction [Element]
136 | Flow Direction [Element]
140 | Spacer
137 | Spacer
@@ -145,13 +142,13 @@ data ImageStyle = Plain | Fitted | Cropped (Int,Int) | Tiled
145
142
146{-| Create an image given a width, height, and image source. -}
143{-| Create an image given a width, height, and image source. -}
147image : Int -> Int -> String -> Element
144image : Int -> Int -> String -> Element
148−image w h src = newElement w h (Image Plain w h (JS.fromString src))
145+image w h src = newElement w h (Image Plain w h src)
149
146
150{-| Create a fitted image given a width, height, and image source.
147{-| Create a fitted image given a width, height, and image source.
151This will crop the picture to best fill the given dimensions.
148This will crop the picture to best fill the given dimensions.
152-}
149-}
153fittedImage : Int -> Int -> String -> Element
150fittedImage : Int -> Int -> String -> Element
154−fittedImage w h src = newElement w h (Image Fitted w h (JS.fromString src))
151+fittedImage w h src = newElement w h (Image Fitted w h src)
155
152
156{-| Create a cropped image. Take a rectangle out of the picture starting
153{-| Create a cropped image. Take a rectangle out of the picture starting
157at the given top left coordinate. If you have a 140-by-140 image,
154at the given top left coordinate. If you have a 140-by-140 image,
@@ -161,11 +158,11 @@ the following will cut a 100-by-100 square out of the middle of it.
161-}
158-}
162croppedImage : (Int,Int) -> Int -> Int -> String -> Element
159croppedImage : (Int,Int) -> Int -> Int -> String -> Element
163croppedImage pos w h src =
160croppedImage pos w h src =
164− newElement w h (Image (Cropped pos) w h (JS.fromString src))
161+ newElement w h (Image (Cropped pos) w h src)
165
162
166tiledImage : Int -> Int -> String -> Element
163tiledImage : Int -> Int -> String -> Element
167tiledImage w h src =
164tiledImage w h src =
168− newElement w h (Image Tiled w h (JS.fromString src))
165+ newElement w h (Image Tiled w h src)
169
166
170data Three = P | Z | N
167data Three = P | Z | N
171data Pos = Absolute Int | Relative Float
168data Pos = Absolute Int | Relative Float
libraries/Http.elm+2−4
@@ -1,8 +1,6 @@
1module Http where
1module Http where
2−
3−{-| A library for asynchronous HTTP requests. See the
2+{-| A library for asynchronous HTTP requests. See the `WebSocket`
4−[WebSocket](http://elm-lang.org/docs/WebSocket.elm) library if
5−you have very strict latency requirements.
3+library if you have very strict latency requirements.
6
4
7# Sending Requests
5# Sending Requests
8@docs send, sendGet
6@docs send, sendGet
libraries/JavaScript.elmdeleted−74
@@ -1,74 +0,0 @@
1−
2−module JavaScript where
3−
4−{-|This library does basic conversions between Elm and JS values. This allows
5−the internal data structures of Elm to change and improve with no impact on JS
6−integration.
7−
8−It is intended to be imported as `import JavaScript as JS`. That way functions
9−like `JS.toInt` convert JavaScript *to* Elm integers and functions like
10−`JS.fromString` gets JavaScript *from* Elm strings.
11−
12−# Javascript to Elm
13−@docs toString, toInt, toFloat, toBool, toList
14−
15−# JavaScript from Elm
16−@docs fromString, fromInt, fromFloat, fromBool, fromList
17−-}
18−{-
19−# DOM Nodes and Elements
20−@docs toElement, fromElement
21−-}
22−
23−import Native.JavaScript
24−
25−data JSNumber = JSNumber
26−data JSBool = JSBool
27−data JSString = JSString
28−data JSArray a = JSArray a
29−data JSDomNode = JSDomNode
30−data JSObject = JSObject
31−
32−{-| Requires that the input array be uniform (all members have the same type) -}
33−toList : JSArray a -> [a]
34−toList = Native.JavaScript.toList
35−
36−toInt : JSNumber -> Int
37−toInt = Native.JavaScript.toInt
38−
39−toFloat : JSNumber -> Float
40−toFloat = Native.JavaScript.toFloat
41−
42−toBool : JSBool -> Bool
43−toBool = Native.JavaScript.toBool
44−
45−toString : JSString -> String
46−toString = Native.JavaScript.toString
47−
48−
49−{-| Produces a uniform JavaScript array with all members of the same type. -}
50−fromList : [a] -> JSArray a
51−fromList = Native.JavaScript.fromList
52−
53−fromInt : Int -> JSNumber
54−fromInt = Native.JavaScript.fromInt
55−
56−fromFloat : Float -> JSNumber
57−fromFloat = Native.JavaScript.fromFloat
58−
59−fromBool : Bool -> JSBool
60−fromBool = Native.JavaScript.fromBool
61−
62−fromString : String -> JSString
63−fromString = Native.JavaScript.fromString
64−
65−{-
66−{-| Turn an `Element` into a DOM node. -}
67−fromElement : Element -> JSDomNode
68−fromElement = Native.JavaScript.fromElement
69−
70−{-| Turn a DOM node into an `Element`. You can resize the node
71−using the normal `width` and `height` functions. -}
72−toElement : Int -> Int -> JSDomNode -> Element
73−toElement = Native.JavaScript.toElement
74−-}
libraries/JavaScript/Experimental.elm+30−16
@@ -8,34 +8,48 @@ improve as we find its key failings.
8@docs toRecord, fromRecord
8@docs toRecord, fromRecord
9-}
9-}
10
10
11−import JavaScript (JSObject)
12import Native.JavaScript
11import Native.JavaScript
12+import Json
13+
14+data RawObject = RawObject
13
15
14{-| Turn arbitrary JavaScript objects into Elm records.
16{-| Turn arbitrary JavaScript objects into Elm records.
15Arrays are converted into lists, nested objects are allowed.
17Arrays are converted into lists, nested objects are allowed.
16No `null` values or non-homogeneous arrays.
18No `null` values or non-homogeneous arrays.
17
19
18− -- OK objects
20+ -- OK objects
19− { student:"Steve", scores:[83,94,99,72] }
21+ { student:"Steve", scores:[83,94,99,72] }
20− { errorLevel:10, critical:true }
22+ { errorLevel:10, critical:true }
21
23
22− -- BAD objects
24+ -- BAD objects
23− { answer:null }
25+ { answer:null }
24− { info:[true,42,'what'] }
26+ { info:[true,42,'what'] }
25-}
27-}
26−toRecord : JSObject -> a
28+toRecord : RawObject -> a
27toRecord = Native.JavaScript.toRecord
29toRecord = Native.JavaScript.toRecord
28
30
29{-| Turn arbitrary Elm records into JavaScript objects.
31{-| Turn arbitrary Elm records into JavaScript objects.
30Lists become arrays, nested records are allowed. No ADTs.
32Lists become arrays, nested records are allowed. No ADTs.
31
33
32− -- OK records
34+ -- OK records
33− { student="Steve", scores=[83,94,99,72] }
35+ { student="Steve", scores=[83,94,99,72] }
34− { errorLevel=10, critical=True }
36+ { errorLevel=10, critical=True }
37+
38+ -- BAD records
39+ { answer = Nothing }
40+ { result = Left "An error occurred" }
41+-}
42+fromRecord : a -> RawObject
43+fromRecord = Native.JavaScript.fromRecord
44+
45+{-| Turn a raw JavaScript object into a `Json.Value` as described in the
46+`Json` library.
47+-}
48+toJson : RawObject -> Json.Value
49+toJson = Native.Json.fromJS
35
50
36− -- BAD records
51+{-| Turn a `Json.Value` (as described in the `Json` library) into a raw
37− { answer = Nothing }
52+JavaScript object.
38− { result = Left "An error occurred" }
39-}
53-}
40−fromRecord : a -> JSObject
54+fromJson : Json.Value -> RawObject
41−fromRecord = Native.JavaScript.fromRecord
55+fromJson = Native.Json.toJS
libraries/Json.elm+25−110
@@ -3,132 +3,47 @@ module Json where
3
3
4{-| Library for working with [JSON](https://en.wikipedia.org/wiki/JSON) values.
4{-| Library for working with [JSON](https://en.wikipedia.org/wiki/JSON) values.
5
5
6−# Json Values
7−@docs JsonValue
8−
9−# Strings
10−@docs fromString, toString
6+@docs Value, fromString, toString
11−
12−# JS Strings
13−@docs fromJSString, toJSString
14−
15−# JS Objects
16−@docs fromJSObject, toJSObject
17
7
18-}
8-}
19
9
20−import Basics (..)
21import Dict
10import Dict
22import Maybe (Maybe)
11import Maybe (Maybe)
23−import JavaScript as JS
24import Native.Json
12import Native.Json
25−import JavaScript (JSObject, JSString)
26
13
27−{-| This datatype can represent all valid values that can be held in a JSON
14+{-| This datatype can represent all valid JSON values. A `Value` can be sent
28−object. In Elm, a proper JSON object is represented as a (Dict String JsonValue)
15+through ports, and the runtime will do a conversion like this:
29−which is a mapping from strings to Json Values. -}
16+
30−data JsonValue
17+ [2,'abc',null] == Array [Number 2, String "abc", Null]
18+
19+JSON is an intentional subset of JavaScript values which excludes functions.
20+This ensures that impure functions cannot sneak into Elm through ports.
21+-}
22+data Value
31 = String String
23 = String String
32 | Number Float
24 | Number Float
33 | Boolean Bool
25 | Boolean Bool
34 | Null
26 | Null
35− | Array [JsonValue]
27+ | Array [Value]
36− | Object (Dict.Dict String JsonValue)
28+ | Object (Dict.Dict String Value)
37−
38
29
39−-- String Converters
40
30
41−{-| Convert a `JsonValue` into a prettified string.
31+{-| Convert a `Value` into a prettified string.
42The first argument is a separator token (e.g. \" \", \"\\n\", etc.) that will
32The first argument is a separator token (e.g. \" \", \"\\n\", etc.) that will
43−be used for indentation in the prettified string version of the JSON. -}
33+be used for indentation in the prettified string version of the JSON.
44−toString : String -> JsonValue -> String
45−toString sep v = JS.toString (Native.Json.toJSString sep v)
46
34
47−{-| Convert a proper JSON object into a JavaScript string.
35+ toString "" Null == "null"
48−Note that the type JSString seen here is not the same as the type constructor
36+ toString "" (Number 4.0) == "4.0"
49−JsonString used elsewhere in this module. -}
37+-}
50−toJSString : String -> JsonValue -> JSString
38+toString : String -> Value -> String
51−toJSString = Native.Json.toJSString
39+toString sep value = Native.Json.toString sep value
52
40
53{-| Parse a string representation of a proper JSON object into
41{-| Parse a string representation of a proper JSON object into
54−its Elm representation. -}
42+its Elm representation.
55−fromString : String -> Maybe JsonValue
56−fromString s = Native.Json.fromJSString (JS.fromString s)
57−
58−{-| Parse a JavaScript string representation of a proper JSON object into
59−its Elm representation. -}
60−fromJSString : JSString -> Maybe JsonValue
61−fromJSString = Native.Json.fromJSString
62−
63−{-| Convert a JS object into a `JsonValue`. -}
64−fromJSObject : JSObject -> JsonValue
65−fromJSObject = Native.Json.fromJSObject
66
43
67−{-| Convert a `JsonValue` into a `JSObject`. Paired with the
44+ fromString "null" == Just Null
68−[`JavaScript.Experimental` library](/docs/JavaScript/Experimental.elm),
45+ fromString "[true,3]" == Just (Array [Boolean True, Number 3])
69−This lets you convert strings into Elm records:
46+ fromString "{'abc':4}" == Just (Object (Dict.fromList [("abc", Number 4)]))
70−
71− import JavaScript.Experimental as JS
72−
73− stringToRecord str =
74− case fromString str of
75− Just jsonValue -> Just (JS.toRecord (toJSObject jsonValue))
76− Nothing -> Nothing
77-}
47-}
78−toJSObject : JsonValue -> JSObject
48+fromString : String -> Maybe Value
79−toJSObject = Native.Json.toJSObject
49+fromString str = Native.Json.fromString str
80−
81− {-- Extract Elm values from Json values
82−
83− string : JsonValue -> String
84− string v = case v of { String s -> s ; _ -> "" }
85−
86− number : JsonValue -> Float
87− number v = case v of { Number n -> n ; _ -> 0 }
88−
89− boolean : JsonValue -> Bool
90− boolean v = case v of { Boolean b -> b ; _ -> False }
91−
92− array : JsonValue -> [JsonValue]
93− array v = case v of { Array a -> a ; _ -> [] }
94−
95− object : JsonValue -> Dict String JsonValue
96− object v = case v of { Object o -> o ; _ -> Dict.empty }
97−
98−
99− -- Extract Elm values from dictionaries of Json values
100−
101− {-| Find a value in a Json Object using the passed get function. If the key is
102− not found, this returns the given default/base value. -}
103− find get base =
104− let f key dict =
105− case Dict.lookup key dict of
106− Nothing -> base
107− Just v -> get v
108− in f
109−
110− {-| Find a string value in an Elm Json object. If the key is not found or the
111− value found is not a string, this returns the empty string. -}
112− findString : String -> Object -> String
113− findString = find string ""
114−
115− {-| Find a number value in an Elm Json object. If the key is not found or the
116− value found is not a number, this returns 0 -}
117− findNumber : String -> Object -> Float
118− findNumber = find number 0
119−
120− {-| Find a boolean value in an Elm Json object. If the key is not found or the
121− value found is not a boolean, this returns the False. -}
122− findBoolean : String -> Object -> Bool
123− findBoolean = find boolean False
124−
125− {-| Find an array value in an Elm Json object. If the key is not found or the
126− value found is not an array, this returns an empty list. -}
127− findArray : String -> Object -> [JsonValue]
128− findArray = find array []
129−
130− {-| Find an object value in an Elm Json object. If the key is not found or the
131− value found is not an object, this returns an empty object. -}
132− findObject : String -> Object -> Object
133− findObject = find object Dict.empty
134− --}
libraries/Keyboard.elm+2−4
@@ -1,5 +1,4 @@
1module Keyboard where
1module Keyboard where
2−
3{-| Library for working with keyboard input.
2{-| Library for working with keyboard input.
4
3
5# Representing Keys
4# Representing Keys
@@ -20,9 +19,8 @@ import Signal (Signal)
20import Native.Keyboard
19import Native.Keyboard
21
20
22{-| Type alias to make it clearer what integers are supposed to represent
21{-| Type alias to make it clearer what integers are supposed to represent
23−in this library. Use [`Char.toCode`](docs/Char.elm#toCode) and
22+in this library. Use `Char.toCode` and `Char.fromCode` to convert key codes
24−[`Char.fromCode`](/docs/Char.elm#fromCode) to convert key codes to characters.
25−Use the uppercase character with `toCode`.
23+to characters. Use the uppercase character with `toCode`.
26-}
24-}
27type KeyCode = Int
25type KeyCode = Int
28
26
libraries/Native/Basics.js+3
@@ -19,6 +19,7 @@ Elm.Native.Basics.make = function(elm) {
19 return Utils.cmp(n,lo) < 0 ? lo : Utils.cmp(n,hi) > 0 ? hi : n; }
19 return Utils.cmp(n,lo) < 0 ? lo : Utils.cmp(n,hi) > 0 ? hi : n; }
20 function xor(a,b) { return a !== b; }
20 function xor(a,b) { return a !== b; }
21 function not(b) { return !b; }
21 function not(b) { return !b; }
22+ function isInfinite(n) { return n === Infinity || n === -Infinity }
22
23
23 function truncate(n) { return n|0; }
24 function truncate(n) { return n|0; }
24
25
@@ -53,6 +54,8 @@ Elm.Native.Basics.make = function(elm) {
53 floor:Math.floor,
54 floor:Math.floor,
54 round:Math.round,
55 round:Math.round,
55 toFloat:function(x) { return x; },
56 toFloat:function(x) { return x; },
57+ isNaN:isNaN,
58+ isInfinite:isInfinite
56 };
59 };
57
60
58 return elm.Native.Basics.values = basics;
61 return elm.Native.Basics.values = basics;
libraries/Native/Date.js+1−2
@@ -4,12 +4,11 @@ Elm.Native.Date.make = function(elm) {
4 elm.Native.Date = elm.Native.Date || {};
4 elm.Native.Date = elm.Native.Date || {};
5 if (elm.Native.Date.values) return elm.Native.Date.values;
5 if (elm.Native.Date.values) return elm.Native.Date.values;
6
6
7− var JS = Elm.JavaScript.make(elm);
8 var Maybe = Elm.Maybe.make(elm);
7 var Maybe = Elm.Maybe.make(elm);
9
8
10 function dateNow() { return new window.Date; }
9 function dateNow() { return new window.Date; }
11 function readDate(str) {
10 function readDate(str) {
12− var d = new window.Date(JS.fromString(str));
11+ var d = new window.Date(str);
13 if (isNaN(d.getTime())) return Maybe.Nothing;
12 if (isNaN(d.getTime())) return Maybe.Nothing;
14 return Maybe.Just(d);
13 return Maybe.Just(d);
15 }
14 }
libraries/Native/JavaScript.js+59−91
@@ -1,100 +1,68 @@
1Elm.Native.JavaScript = {};
1Elm.Native.JavaScript = {};
2Elm.Native.JavaScript.make = function(elm) {
2Elm.Native.JavaScript.make = function(elm) {
3− elm.Native = elm.Native || {};
3+ elm.Native = elm.Native || {};
4− elm.Native.JavaScript = elm.Native.JavaScript || {};
4+ elm.Native.JavaScript = elm.Native.JavaScript || {};
5− if (elm.Native.JavaScript.values) return elm.Native.JavaScript.values;
5+ if (elm.Native.JavaScript.values) return elm.Native.JavaScript.values;
6
6
7− var List = Elm.Native.List.make(elm);
7+ var List = Elm.Native.List.make(elm);
8− var Render = ElmRuntime.use(ElmRuntime.Render.Element);
8+ var Render = ElmRuntime.use(ElmRuntime.Render.Element);
9
9
10− function fromJS(v) {
10+ function fromJS(v) {
11− var type = typeof v;
11+ var type = typeof v;
12− if (type === 'number' ) return v;
12+ if (type === 'number' ) return v;
13− if (type === 'boolean') return v;
13+ if (type === 'boolean') return v;
14− if (type === 'string' ) return v;
14+ if (type === 'string' ) return v;
15− if (v instanceof Array) {
15+ if (v instanceof Array) {
16− var arr = [];
16+ var arr = [];
17− var len = v.length;
17+ var len = v.length;
18− for (var i = 0; i < len; ++i) {
18+ for (var i = 0; i < len; ++i) {
19− var x = fromJS(v[i]);
19+ var x = fromJS(v[i]);
20− if (x !== null) arr.push(x);
20+ if (x !== null) arr.push(x);
21− }
21+ }
22− return List.fromArray(arr);
22+ return List.fromArray(arr);
23− }
23+ }
24− if (type === 'object') {
24+ if (type === 'object') {
25− var rec = { _:{} };
25+ var rec = { _:{} };
26− for (var f in v) {
26+ for (var f in v) {
27− var x = fromJS(v[f]);
27+ var x = fromJS(v[f]);
28− if (x !== null) rec[f] = x;
28+ if (x !== null) rec[f] = x;
29− }
29+ }
30− return rec;
30+ return rec;
31− }
31+ }
32− return null;
32+ return null;
33− }
33+ }
34
34
35− function toJS(v) {
35+ function toJS(v) {
36− var type = typeof v;
36+ var type = typeof v;
37− if (type === 'number' || type === 'boolean' || type === 'string') return v;
37+ if (type === 'number' || type === 'boolean' || type === 'string') return v;
38− if (type === 'object' && '_' in v) {
38+ if (type === 'object' && '_' in v) {
39− var obj = {};
39+ var obj = {};
40− for (var k in v) {
40+ for (var k in v) {
41− var x = toJS(v[k]);
41+ var x = toJS(v[k]);
42− if (x !== null) obj[k] = x;
42+ if (x !== null) obj[k] = x;
43− }
43+ }
44− return obj;
44+ return obj;
45− }
45+ }
46− if (type === 'object' && (v.ctor === '::' || v.ctor === '[]')) {
46+ if (type === 'object' && (v.ctor === '::' || v.ctor === '[]')) {
47− var array = List.toArray(v);
47+ var array = List.toArray(v);
48− for (var i = array.length; i--; ) {
48+ for (var i = array.length; i--; ) {
49− array[i] = toJS(array[i]);
49+ array[i] = toJS(array[i]);
50− }
50+ }
51− return array;
51+ return array;
52− }
52+ }
53− return null;
53+ return null;
54− }
54+ }
55
55
56− function fromRecord(r) {
56+ function fromRecord(r) {
57− if (typeof r === 'object' && '_' in r) {
57+ if (typeof r === 'object' && '_' in r) {
58− return toJS(r);
58+ return toJS(r);
59− }
59+ }
60− throw new Error("'fromRecord' must be called on a record.");
60+ throw new Error("'fromRecord' must be called on a record.");
61− }
61+ }
62
62
63− function id(n) { return n; }
64−
65− function toElement(w,h,domNode) {
66− return A3( newElement, w, h, {
67− ctor: 'Custom',
68− type: 'DomNode',
69− render: function(node) { return node; },
70− update: function(node,oldNode,newNode) {
71− if (node === newNode) return;
72− node.parentNode.replaceChild(newNode, node);
73− },
74− model: domNode
75− });
76− }
77−
78− function fromElement(element) {
79− return Render.render(element);
80− }
81−
82− return elm.Native.JavaScript.values = {
63+ return elm.Native.JavaScript.values = {
83− toInt : function(n) { return n|0; },
84− toFloat : function(n) { return +n; },
85− toBool : id,
86− toString : id,
87− toList : List.fromArray,
88− fromString : id,
89− fromList : List.toArray,
90− fromInt : id,
91− fromFloat : id,
92− fromBool : id,
93−
94− toElement : toElement,
95− fromElement : fromElement,
96− toRecord : fromJS,
64+ toRecord : fromJS,
97− fromRecord : fromRecord
65+ fromRecord : fromRecord
98− };
66+ };
99
67
100};
68};
libraries/Native/Json.js+71−58
@@ -1,72 +1,85 @@
1Elm.Native.Json = {};
1Elm.Native.Json = {};
2Elm.Native.Json.make = function(elm) {
2Elm.Native.Json.make = function(elm) {
3
3
4− elm.Native = elm.Native || {};
4+ elm.Native = elm.Native || {};
5− elm.Native.Json = elm.Native.Json || {};
5+ elm.Native.Json = elm.Native.Json || {};
6− if (elm.Native.Json.values) return elm.Native.Json.values;
6+ if (elm.Native.Json.values) return elm.Native.Json.values;
7
7
8− var Maybe = Elm.Maybe.make(elm);
8+ var Maybe = Elm.Maybe.make(elm);
9− var Dict = Elm.Dict.make(elm);
9+ var Dict = Elm.Dict.make(elm);
10− var List = Elm.List.make(elm);
10+ var List = Elm.Native.List.make(elm);
11− var JS = Elm.JavaScript.make(elm);
12− var Utils = Elm.Native.Utils.make(elm);
11+ var Utils = Elm.Native.Utils.make(elm);
13
12
14− function fromValue(v) {
13+ function toJS(v) {
15− switch (v.ctor) {
14+ switch (v.ctor) {
16− case 'Null' : return null;
15+ case 'Null' : return null;
17− case 'String' : return JS.fromString(v._0);
16+ case 'String' : return v._0;
17+ case 'Number' : return v._0;
18+ case 'Boolean': return v._0;
18− case 'Object' :
19+ case 'Object' :
19− var obj = {};
20+ var obj = {};
20− var array = JS.fromList(Dict.toList(v._0));
21+ var array = List.toArray(Dict.toList(v._0));
21− for (var i = array.length; i--; ) {
22+ for (var i = array.length; i--; ) {
22− obj[JS.fromString(array[i]._0)] = fromValue(array[i]._1);
23+ var entry = array[i];
24+ obj[entry._0] = toJS(entry._1);
23− }
25+ }
24− return obj;
26+ return obj;
25− case 'Array' :
27+ case 'Array' :
26− var array = JS.fromList(v._0);
28+ var array = List.toArray(v._0);
27− for (var i = array.length; i--; ) {
29+ for (var i = array.length; i--; ) {
28− array[i] = fromValue(array[i]);
30+ array[i] = toJS(array[i]);
29− }
31+ }
30− return array;
32+ return array;
31− default :
33+ }
32− return v._0;
33 }
34 }
34− }
35
35
36− function toPrettyJSString(sep, obj) {
36+ function toString(sep, value) {
37− return JSON.stringify(fromValue(obj), null, JS.fromString(sep));
37+ return JSON.stringify(toJS(value), null, sep);
38− }
38+ }
39
39
40− function toValue(v) {
40+ function fromJS(v) {
41− switch (typeof v) {
41+ switch (typeof v) {
42− case 'string' : return { ctor:"String", _0: JS.toString(v) };
42+ case 'string' : return { ctor:"String" , _0: v };
43− case 'number' : return { ctor:"Number", _0: JS.toFloat(v) };
43+ case 'number' : return { ctor:"Number" , _0: v };
44− case 'boolean': return { ctor:"Boolean" , _0: JS.toBool(v) };
44+ case 'boolean': return { ctor:"Boolean", _0: v };
45− case 'object' :
45+ case 'object' :
46− if (v === null) return { ctor:"Null" };
46+ if (v === null) return { ctor:"Null" };
47− if (v instanceof Array) {
47+ if (v instanceof Array) {
48+ var array = new Array(v.length);
48− for (var i = v.length; i--; ) { v[i] = toValue(v[i]); }
49+ for (var i = v.length; i--; ) {
50+ array[i] = fromJS(v[i]);
51+ }
52+ return {
49− return { ctor:"Array", _0: JS.toList(v) };
53+ ctor:"Array",
54+ _0: List.fromArray(array)
55+ };
50− }
56+ }
51− var array = [];
57+ var array = [];
58+ for (var key in v) {
59+ var value = fromJS(v[key]);
52− for (var k in v) array.push(Utils.Tuple2(JS.toString(k), toValue(v[k])));
60+ array.push(Utils.Tuple2(key, value));
61+ }
62+ var list = List.fromArray(array);
63+ return {
64+ ctor:"Object",
53− return { ctor:"Object", _0: Dict.fromList(JS.toList(array)) };
65+ _0: Dict.fromList(list)
66+ };
67+ }
54 }
68 }
55− }
56
69
57− function fromJSString(str) {
70+ function fromString(str) {
58− try {
71+ try {
59− return Maybe.Just(toValue(JSON.parse(str)));
72+ return Maybe.Just(fromJS(JSON.parse(str)));
60− } catch (e) {
73+ } catch (e) {
61− return Maybe.Nothing;
74+ return Maybe.Nothing;
75+ }
62 }
76 }
63− }
64
77
65− return elm.Native.Json.values = {
78+ return elm.Native.Json.values = {
66− toJSString : F2(toPrettyJSString),
79+ toString : F2(toString),
67− fromJSString : fromJSString,
80+ fromString : fromString,
68− toJSObject : fromValue,
81+ fromJS : fromJS,
69− fromJSObject : toValue
82+ toJS : toJS,
70− };
83+ };
71
84
72};
85};
libraries/Native/Regex.js+14−14
@@ -6,8 +6,8 @@ Elm.Native.Regex.make = function(elm) {
6 if ('values' in Elm.Native.Regex)
6 if ('values' in Elm.Native.Regex)
7 return elm.Native.Regex.values = Elm.Native.Regex.values;
7 return elm.Native.Regex.values = Elm.Native.Regex.values;
8
8
9+ var List = Elm.Native.List.make(elm);
9 var Maybe = Elm.Maybe.make(elm);
10 var Maybe = Elm.Maybe.make(elm);
10− var JS = Elm.JavaScript.make(elm);
11
11
12 function escape(str) {
12 function escape(str) {
13 return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
13 return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
@@ -20,14 +20,14 @@ Elm.Native.Regex.make = function(elm) {
20 }
20 }
21
21
22 function contains(re, string) {
22 function contains(re, string) {
23− return re.test(JS.fromString(string));
23+ return string.match(re) !== null;
24 }
24 }
25
25
26 function find(n, re, str) {
26 function find(n, re, str) {
27 n = n.ctor === "All" ? Infinity : n._0;
27 n = n.ctor === "All" ? Infinity : n._0;
28 var out = [];
28 var out = [];
29 var number = 0;
29 var number = 0;
30− var string = JS.fromString(str);
30+ var string = str;
31 var result;
31 var result;
32 while (number++ < n && (result = re.exec(string))) {
32 while (number++ < n && (result = re.exec(string))) {
33 var i = result.length - 1;
33 var i = result.length - 1;
@@ -36,17 +36,17 @@ Elm.Native.Regex.make = function(elm) {
36 var submatch = result[i];
36 var submatch = result[i];
37 subs[--i] = submatch === undefined
37 subs[--i] = submatch === undefined
38 ? Maybe.Nothing
38 ? Maybe.Nothing
39− : Maybe.Just(JS.toString(submatch));
39+ : Maybe.Just(submatch);
40 }
40 }
41 out.push({
41 out.push({
42 _:{},
42 _:{},
43− match: JS.toString(result[0]),
43+ match: result[0],
44− submatches: JS.toList(subs),
44+ submatches: List.fromArray(subs),
45 index: result.index,
45 index: result.index,
46 number: number,
46 number: number,
47 });
47 });
48 }
48 }
49− return JS.toList(out);
49+ return List.fromArray(out);
50 }
50 }
51
51
52 function replace(n, re, replacer, string) {
52 function replace(n, re, replacer, string) {
@@ -60,24 +60,24 @@ Elm.Native.Regex.make = function(elm) {
60 var submatch = arguments[i];
60 var submatch = arguments[i];
61 submatches[--i] = submatch === undefined
61 submatches[--i] = submatch === undefined
62 ? Maybe.Nothing
62 ? Maybe.Nothing
63− : Maybe.Just(JS.toString(submatch));
63+ : Maybe.Just(submatch);
64 }
64 }
65− return JS.fromString(replacer({
65+ return replacer({
66 _:{},
66 _:{},
67 match:match,
67 match:match,
68− submatches:JS.toList(submatches),
68+ submatches:List.fromArray(submatches),
69 index:arguments[i-1],
69 index:arguments[i-1],
70 number:count
70 number:count
71− }));
71+ });
72 }
72 }
73 return string.replace(re, jsReplacer);
73 return string.replace(re, jsReplacer);
74 }
74 }
75
75
76 function split(n, re, str) {
76 function split(n, re, str) {
77 if (n === Infinity) {
77 if (n === Infinity) {
78− return JS.toList(JS.fromString(string).split(re));
78+ return List.fromArray(string.split(re));
79 }
79 }
80− var string = JS.fromString(str);
80+ var string = str;
81 var result;
81 var result;
82 var out = [];
82 var out = [];
83 var start = re.lastIndex;
83 var start = re.lastIndex;
@@ -87,7 +87,7 @@ Elm.Native.Regex.make = function(elm) {
87 start = re.lastIndex;
87 start = re.lastIndex;
88 }
88 }
89 out.push(string.slice(start));
89 out.push(string.slice(start));
90− return JS.toList(out);
90+ return List.fromArray(out);
91 }
91 }
92
92
93 return Elm.Native.Regex.values = {
93 return Elm.Native.Regex.values = {
libraries/Native/Signal/Http.js+6−7
@@ -5,7 +5,6 @@ Elm.Native.Http.make = function(elm) {
5 elm.Native.Http = elm.Native.Http || {};
5 elm.Native.Http = elm.Native.Http || {};
6 if (elm.Native.Http.values) return elm.Native.Http.values;
6 if (elm.Native.Http.values) return elm.Native.Http.values;
7
7
8− var JS = Elm.JavaScript.make(elm);
9 var List = Elm.List.make(elm);
8 var List = Elm.List.make(elm);
10 var Signal = Elm.Signal.make(elm);
9 var Signal = Elm.Signal.make(elm);
11
10
@@ -38,17 +37,17 @@ Elm.Native.Http.make = function(elm) {
38 request.onreadystatechange = function(e) {
37 request.onreadystatechange = function(e) {
39 if (request.readyState === 4) {
38 if (request.readyState === 4) {
40 response.value = (request.status >= 200 && request.status < 300 ?
39 response.value = (request.status >= 200 && request.status < 300 ?
41− { ctor:'Success', _0:JS.toString(request.responseText) } :
40+ { ctor:'Success', _0:request.responseText } :
42− { ctor:'Failure', _0:request.status, _1:JS.toString(request.statusText) });
41+ { ctor:'Failure', _0:request.status, _1:request.statusText });
43 setTimeout(function() { updateQueue(queue,responses); }, 0);
42 setTimeout(function() { updateQueue(queue,responses); }, 0);
44 }
43 }
45 };
44 };
46− request.open(JS.fromString(req.verb), JS.fromString(req.url), true);
45+ request.open(req.verb, req.url, true);
47 function setHeader(pair) {
46 function setHeader(pair) {
48− request.setRequestHeader( JS.fromString(pair._0), JS.fromString(pair._1) );
47+ request.setRequestHeader( pair._0, pair._1 );
49 }
48 }
50− List.map(setHeader)(req.headers);
49+ A2( List.map, setHeader, req.headers );
51− request.send(JS.fromString(req.body));
50+ request.send(req.body);
52 }
51 }
53
52
54 function send(requests) {
53 function send(requests) {
libraries/Native/Signal/Touch.js+3−3
@@ -6,7 +6,7 @@ Elm.Native.Touch.make = function(elm) {
6 if (elm.Native.Touch.values) return elm.Native.Touch.values;
6 if (elm.Native.Touch.values) return elm.Native.Touch.values;
7
7
8 var Signal = Elm.Signal.make(elm);
8 var Signal = Elm.Signal.make(elm);
9− var JS = Elm.JavaScript.make(elm);
9+ var List = Elm.Native.List.make(elm);
10 var Utils = Elm.Native.Utils.make(elm);
10 var Utils = Elm.Native.Utils.make(elm);
11
11
12 function Dict() {
12 function Dict() {
@@ -136,7 +136,7 @@ Elm.Native.Touch.make = function(elm) {
136 return sig;
136 return sig;
137 }
137 }
138
138
139− var touches = dependency(JS.toList);
139+ var touches = dependency(List.fromArray);
140
140
141 var taps = function() {
141 var taps = function() {
142 var sig = dependency(function(_) { return tap; });
142 var sig = dependency(function(_) { return tap; });
@@ -149,4 +149,4 @@ Elm.Native.Touch.make = function(elm) {
149
149
150 return elm.Native.Touch.values = { touches: touches, taps: taps };
150 return elm.Native.Touch.values = { touches: touches, taps: taps };
151
151
152−};
152+};
libraries/Native/Signal/WebSocket.js+3−5
@@ -6,12 +6,11 @@ Elm.Native.WebSocket.make = function(elm) {
6 if (elm.Native.WebSocket.values) return elm.Native.WebSocket.values;
6 if (elm.Native.WebSocket.values) return elm.Native.WebSocket.values;
7
7
8 var Signal = Elm.Signal.make(elm);
8 var Signal = Elm.Signal.make(elm);
9− var JS = Elm.JavaScript.make(elm);
10 var List = Elm.Native.List.make(elm);
9 var List = Elm.Native.List.make(elm);
11
10
12 function open(url, outgoing) {
11 function open(url, outgoing) {
13 var incoming = Signal.constant(List.Nil);
12 var incoming = Signal.constant(List.Nil);
14− var ws = new WebSocket(JS.fromString(url));
13+ var ws = new WebSocket(url);
15
14
16 var pending = [];
15 var pending = [];
17 var ready = false;
16 var ready = false;
@@ -22,12 +21,11 @@ Elm.Native.WebSocket.make = function(elm) {
22 ready = true;
21 ready = true;
23 };
22 };
24 ws.onmessage = function(event) {
23 ws.onmessage = function(event) {
25− elm.notify(incoming.id, JS.toString(event.data));
24+ elm.notify(incoming.id, event.data);
26 };
25 };
27
26
28 function send(msg) {
27 function send(msg) {
29− var s = JS.fromString(msg);
30− ready ? ws.send(s) : pending.push(s);
28+ ready ? ws.send(msg) : pending.push(msg);
31 }
29 }
32
30
33 function take1(x,y) { return x }
31 function take1(x,y) { return x }
libraries/Native/String.js+9−9
@@ -8,7 +8,7 @@ Elm.Native.String.make = function(elm) {
8
8
9 var Char = Elm.Char.make(elm);
9 var Char = Elm.Char.make(elm);
10 var Maybe = Elm.Maybe.make(elm);
10 var Maybe = Elm.Maybe.make(elm);
11− var JS = Elm.JavaScript.make(elm);
11+ var List = Elm.Native.List.make(elm);
12 var Utils = Elm.Native.Utils.make(elm);
12 var Utils = Elm.Native.Utils.make(elm);
13
13
14 function isEmpty(str) {
14 function isEmpty(str) {
@@ -26,7 +26,7 @@ Elm.Native.String.make = function(elm) {
26 return a + b;
26 return a + b;
27 }
27 }
28 function concat(strs) {
28 function concat(strs) {
29− return JS.fromList(strs).join('');
29+ return List.toArray(strs).join('');
30 }
30 }
31 function length(str) {
31 function length(str) {
32 return str.length;
32 return str.length;
@@ -59,10 +59,10 @@ Elm.Native.String.make = function(elm) {
59 }
59 }
60
60
61 function split(sep, str) {
61 function split(sep, str) {
62− return JS.toList(str.split(sep));
62+ return List.fromArray(str.split(sep));
63 }
63 }
64 function join(sep, strs) {
64 function join(sep, strs) {
65− return JS.fromList(strs).join(sep);
65+ return List.toArray(strs).join(sep);
66 }
66 }
67 function repeat(n, str) {
67 function repeat(n, str) {
68 var result = '';
68 var result = '';
@@ -111,10 +111,10 @@ Elm.Native.String.make = function(elm) {
111 }
111 }
112
112
113 function words(str) {
113 function words(str) {
114− return JS.toList(str.split(/\s+/g));
114+ return List.fromArray(str.split(/\s+/g));
115 }
115 }
116 function lines(str) {
116 function lines(str) {
117− return JS.toList(str.split(/\r\n|\r|\n/g));
117+ return List.fromArray(str.split(/\r\n|\r|\n/g));
118 }
118 }
119
119
120 function toUpper(str) {
120 function toUpper(str) {
@@ -155,7 +155,7 @@ Elm.Native.String.make = function(elm) {
155 is.push(i);
155 is.push(i);
156 i = i + subLen;
156 i = i + subLen;
157 }
157 }
158− return JS.toList(is);
158+ return List.fromArray(is);
159 }
159 }
160
160
161 function toInt(s) {
161 function toInt(s) {
@@ -193,10 +193,10 @@ Elm.Native.String.make = function(elm) {
193 }
193 }
194
194
195 function toList(str) {
195 function toList(str) {
196− return JS.toList(str.split('').map(Utils.chr));
196+ return List.fromArray(str.split('').map(Utils.chr));
197 }
197 }
198 function fromList(chars) {
198 function fromList(chars) {
199− return JS.fromList(chars).join('');
199+ return List.toArray(chars).join('');
200 }
200 }
201
201
202 return Elm.Native.String.values = {
202 return Elm.Native.String.values = {
libraries/Signal.elm+1−1
@@ -10,7 +10,7 @@ past-dependence.
10
10
11Some useful functions for working with time (e.g. setting FPS) and combining
11Some useful functions for working with time (e.g. setting FPS) and combining
12signals and time (e.g. delaying updates, getting timestamps) can be found in
12signals and time (e.g. delaying updates, getting timestamps) can be found in
13−the [`Time`](/docs/Signal/Time.elm) library.
13+the `Time` library.
14
14
15# Combine
15# Combine
16@docs constant, lift, lift2, merge, merges, combine
16@docs constant, lift, lift2, merge, merges, combine
libraries/String.elm+6−6
@@ -174,18 +174,18 @@ pad = Native.String.pad
174
174
175{-| Pad a string on the left until it has a given length.
175{-| Pad a string on the left until it has a given length.
176
176
177− pad 5 '.' "1" == "....1"
177+ padLeft 5 '.' "1" == "....1"
178− pad 5 '.' "11" == "...11"
178+ padLeft 5 '.' "11" == "...11"
179− pad 5 '.' "121" == "..121"
179+ padLeft 5 '.' "121" == "..121"
180-}
180-}
181padLeft : Int -> Char -> String -> String
181padLeft : Int -> Char -> String -> String
182padLeft = Native.String.padLeft
182padLeft = Native.String.padLeft
183
183
184{-| Pad a string on the right until it has a given length.
184{-| Pad a string on the right until it has a given length.
185
185
186− pad 5 '.' "1" == "1...."
186+ padRight 5 '.' "1" == "1...."
187− pad 5 '.' "11" == "11..."
187+ padRight 5 '.' "11" == "11..."
188− pad 5 '.' "121" == "121.."
188+ padRight 5 '.' "121" == "121.."
189-}
189-}
190padRight : Int -> Char -> String -> String
190padRight : Int -> Char -> String -> String
191padRight = Native.String.padRight
191padRight = Native.String.padRight
libraries/Text.elm−1
@@ -35,7 +35,6 @@ import String
35import Color (Color, black)
35import Color (Color, black)
36import Graphics.Element (Element, Three, Pos, ElementPrim, Properties)
36import Graphics.Element (Element, Three, Pos, ElementPrim, Properties)
37import Maybe (Maybe, Nothing)
37import Maybe (Maybe, Nothing)
38−import JavaScript (JSString)
39import Native.Show
38import Native.Show
40import Native.Text
39import Native.Text
41
40
libraries/elm_dependencies.json+4−4
@@ -1,9 +1,9 @@
1−{ "version": "0.11"
1+{ "version": "0.12"
2, "summary": "Elm's standard libraries"
2, "summary": "Elm's standard libraries"
3−, "description": "The full set of standard libraries for Elm. This library is pegged to the version number of the compiler, so if you are using Elm 0.11, you should be using version 0.11 of the standard libraries."
3+, "description": "The full set of standard libraries for Elm. This library is pegged to the version number of the compiler, so if you are using Elm 0.12, you should be using version 0.12 of the standard libraries."
4, "license": "BSD3"
4, "license": "BSD3"
5, "repository": "http://github.com/evancz/Elm.git"
5, "repository": "http://github.com/evancz/Elm.git"
6−, "elm-version": "0.11"
6+, "elm-version": "0.12"
7, "dependencies": {}
7, "dependencies": {}
8, "exposed-modules":
8, "exposed-modules":
9 [ "Basics"
9 [ "Basics"
@@ -17,8 +17,8 @@
17 , "Graphics.Element"
17 , "Graphics.Element"
18 , "Graphics.Collage"
18 , "Graphics.Collage"
19 , "Graphics.Input"
19 , "Graphics.Input"
20+ , "Graphics.Input.Field"
20 , "Http"
21 , "Http"
21− , "JavaScript"
22 , "JavaScript.Experimental"
22 , "JavaScript.Experimental"
23 , "Json"
23 , "Json"
24 , "Keyboard"
24 , "Keyboard"
runtime/Render/Element.js+58−30
@@ -34,35 +34,59 @@ function setProps(elem, e) {
34 e.appendChild(a);
34 e.appendChild(a);
35 }
35 }
36 if (props.hover.ctor !== '_Tuple0') {
36 if (props.hover.ctor !== '_Tuple0') {
37− e.style.pointerEvents = 'auto';
38− e.elm_hover_handler = props.hover;
37+ addHover(e, props.hover);
39− e.elm_hover_count = 0;
40− e.addEventListener('mouseover', function() {
41− if (e.elm_hover_count++ > 0) return;
42− var handler = e.elm_hover_handler;
43− if (handler !== null) {
44− handler(true);
45− }
46− });
47− e.addEventListener('mouseout', function(evt) {
48− if (e.contains(evt.toElement || evt.relatedTarget)) return;
49− e.elm_hover_count = 0;
50− var handler = e.elm_hover_handler;
51− if (handler !== null) {
52− handler(false);
53− }
54− });
55 }
38 }
56 if (props.click.ctor !== '_Tuple0') {
39 if (props.click.ctor !== '_Tuple0') {
57− e.style.pointerEvents = 'auto';
58− e.elm_click_handler = props.click;
40+ addClick(e, props.click);
59− e.addEventListener('click', function() {
60− e.elm_click_handler(Tuple0);
61− });
62 }
41 }
63 return e;
42 return e;
64}
43}
65
44
45+function addClick(e, handler) {
46+ e.style.pointerEvents = 'auto';
47+ e.elm_click_handler = handler;
48+ function trigger() {
49+ e.elm_click_handler(Utils.Tuple0);
50+ }
51+ e.elm_click_trigger = trigger;
52+ e.addEventListener('click', trigger);
53+}
54+
55+function removeClick(e, handler) {
56+ if (e.elm_click_trigger) {
57+ e.removeEventListener('click', e.elm_click_trigger);
58+ }
59+}
60+
61+function addHover(e, handler) {
62+ e.style.pointerEvents = 'auto';
63+ e.elm_hover_handler = handler;
64+ e.elm_hover_count = 0;
65+
66+ function over() {
67+ if (e.elm_hover_count++ > 0) return;
68+ e.elm_hover_handler(true);
69+ }
70+ function out(evt) {
71+ if (e.contains(evt.toElement || evt.relatedTarget)) return;
72+ e.elm_hover_count = 0;
73+ e.elm_hover_handler(false);
74+ }
75+ e.elm_hover_over = over;
76+ e.elm_hover_out = out;
77+ e.addEventListener('mouseover', over);
78+ e.addEventListener('mouseout', out);
79+}
80+
81+function removeHover(e) {
82+ if (e.elm_hover_over) {
83+ e.removeEventListener('mouseover', e.elm_hover_over);
84+ }
85+ if (e.elm_hover_out) {
86+ e.removeEventListener('mouseout', e.elm_hover_out);
87+ }
88+}
89+
66function image(props, img) {
90function image(props, img) {
67 switch (img._0.ctor) {
91 switch (img._0.ctor) {
68 case 'Plain': return plainImage(img._3);
92 case 'Plain': return plainImage(img._3);
@@ -331,7 +355,7 @@ function updateProps(node, curr, next) {
331 if (height !== currP.height) {
355 if (height !== currP.height) {
332 e.style.height = (height|0) + 'px';
356 e.style.height = (height|0) + 'px';
333 }
357 }
334− if (props.opacity !== 1 && props.opacity !== currP.opacity) {
358+ if (props.opacity !== currP.opacity) {
335 e.style.opacity = props.opacity;
359 e.style.opacity = props.opacity;
336 }
360 }
337 var nextColor = (props.color.ctor === 'Just' ?
361 var nextColor = (props.color.ctor === 'Just' ?
@@ -358,17 +382,21 @@ function updateProps(node, curr, next) {
358 }
382 }
359
383
360 // update hover handlers
384 // update hover handlers
361− if (props.hover.ctor !== '_Tuple0') {
385+ if (props.hover.ctor === '_Tuple0') {
362− e.elm_hover_handler = props.hover;
386+ removeHover(e);
363 } else if (e.elm_hover_handler) {
387 } else if (e.elm_hover_handler) {
364− e.elm_hover_handler = null;
388+ e.elm_hover_handler = props.hover;
389+ } else {
390+ addHover(e, props.hover);
365 }
391 }
366
392
367 // update click handlers
393 // update click handlers
368− if (props.click.ctor !== '_Tuple0') {
394+ if (props.click.ctor === '_Tuple0') {
369− e.elm_click_handler = props.click;
395+ removeClick(e);
370 } else if (e.elm_click_handler) {
396 } else if (e.elm_click_handler) {
371− e.elm_click_handler = null;
397+ e.elm_click_handler = props.click;
398+ } else {
399+ addClick(e, props.click);
372 }
400 }
373}
401}
374
402
server/LICENSE+1−1
@@ -1,4 +1,4 @@
1−Copyright (c)2012-2013, Evan Czaplicki
1+Copyright (c)2012-2014, Evan Czaplicki
2
2
3All rights reserved.
3All rights reserved.
4
4
server/Server.hs+112−99
@@ -1,114 +1,127 @@
1+{-# OPTIONS_GHC -Wall #-}
2+{-# LANGUAGE OverloadedStrings, DeriveDataTypeable #-}
1module Main where
3module Main where
2
4
3−import Control.Monad (msum,guard,when)
5+import Control.Applicative ((<$>),(<|>))
6+import Control.Monad (guard)
4import Control.Monad.Trans (MonadIO(liftIO))
7import Control.Monad.Trans (MonadIO(liftIO))
5−import Data.List (isPrefixOf, isSuffixOf, (\\))
8+import qualified Data.ByteString as BS
6−import Data.Version (showVersion)
9+import qualified Data.ByteString.Char8 as BSC
7−import Happstack.Server
10+import qualified Data.HashMap.Strict as Map
8−import Happstack.Server.Compression
11+import qualified Data.Version as Version
12+import System.Console.CmdArgs
9import System.Directory
13import System.Directory
10−import System.Environment
11import System.Exit
14import System.Exit
12import System.FilePath
15import System.FilePath
13import System.Process
16import System.Process
14−import GHC.IO.Handle
17+import System.IO (hGetContents, Handle)
18+
19+import Paths_elm_server (version)
15−import qualified Elm.Internal.Paths as ElmPaths
20+import qualified Elm.Internal.Paths as Elm
16−import Paths_elm_server
21+import Snap.Core
17−
22+import Snap.Http.Server
18−runtime = "/elm-runtime.js"
23+import Snap.Util.FileServe
19−
24+
20−serve :: Int -> String -> IO ()
25+data Flags = Flags
21−serve portNumber libLoc = do
26+ { port :: Int
27+ , runtime :: Maybe FilePath
28+ } deriving (Data,Typeable,Show,Eq)
29+
30+flags :: Flags
31+flags = Flags
32+ { port = 8000 &= help "set the port of the server"
33+ , runtime = Nothing &= typFile
34+ &= help "Specify a custom location for Elm's runtime system."
35+ } &= help "Quickly reload Elm projects in your browser. Just refresh to recompile.\n\
36+ \It serves static files and freshly recompiled Elm files."
37+ &= helpArg [explicit, name "help", name "h"]
38+ &= versionArg [ explicit, name "version", name "v"
39+ , summary (Version.showVersion version)
40+ ]
41+ &= summary ("Elm Server " ++ Version.showVersion version ++
42+ ", (c) Evan Czaplicki 2011-2014")
43+
44+
45+config :: Config Snap a
46+config = setAccessLog ConfigNoLog (setErrorLog ConfigNoLog defaultConfig)
47+
48+-- | Set up the server.
49+main :: IO ()
50+main = do
51+ cargs <- cmdArgs flags
22− putStrLn $ "Elm Server " ++ showVersion version ++
52+ putStrLn $ "Elm Server " ++ Version.showVersion version ++
23− ": running at <http://localhost:" ++ show portNumber ++ ">"
24− putStrLn "Just refresh a page to recompile it!"
53+ ": Just refresh a page to recompile it!"
25− simpleHTTP httpConf $ do
54+ httpServe (setPort (port cargs) config) $
26− _ <- compressedResponseFilter
55+ serveRuntime (maybe Elm.runtime id (runtime cargs))
27− msum [ uriRest serveElm
56+ <|> serveElm
28− , uriRest (serveLib libLoc)
57+ <|> serveDirectoryWith directoryConfig "."
29− , serveDirectory EnableBrowsing [] "."
58+
30− ]
59+directoryConfig :: MonadSnap m => DirectoryConfig m
31− where httpConf = nullConf { port = portNumber }
60+directoryConfig =
32−
61+ fancyDirectoryConfig
33−pageTitle :: String -> String
62+ { indexGenerator = defaultIndexGenerator defaultMimeTypes indexStyle
34−pageTitle = dropExtension . takeBaseName
63+ , mimeTypes = Map.insert ".elm" "text/html" defaultMimeTypes
35−
64+ }
36−serveElm :: FilePath -> ServerPartT IO Response
65+
66+indexStyle :: BS.ByteString
67+indexStyle =
68+ "body { margin:0; font-family:sans-serif; background:rgb(245,245,245);\
69+ \ font-family: calibri, verdana, helvetica, arial; }\
70+ \div.header { padding: 40px 50px; font-size: 24px; }\
71+ \div.content { padding: 0 40px }\
72+ \div.footer { display:none; }\
73+ \table { width:100%; border-collapse:collapse; }\
74+ \td { padding: 6px 10px; }\
75+ \tr:nth-child(odd) { background:rgb(216,221,225); }\
76+ \td { font-family:monospace }\
77+ \th { background:rgb(90,99,120); color:white; text-align:left;\
78+ \ padding:10px; font-weight:normal; }"
79+
80+runtimeName :: String
81+runtimeName = "elm-runtime.js"
82+
83+serveRuntime :: FilePath -> Snap ()
84+serveRuntime runtimePath =
85+ do file <- BSC.unpack . rqPathInfo <$> getRequest
86+ guard (file == runtimeName)
87+ serveFileAs "application/javascript" runtimePath
88+
37−serveElm fp =
89+serveElm :: Snap ()
90+serveElm =
91+ do file <- BSC.unpack . rqPathInfo <$> getRequest
38− do fileExists <- liftIO $ doesFileExist file
92+ exists <- liftIO $ doesFileExist file
39− guard (fileExists && takeExtension fp == ".elm")
93+ guard (exists && takeExtension file == ".elm")
40− onSuccess compile serve
94+ onSuccess (compile file) (serve file)
41 where
95 where
42− file = tail fp
96+ compile file =
97+ let elmArgs = [ "--make", "--runtime=" ++ runtimeName, file ]
98+ in createProcess $ (proc "elm" elmArgs) { std_out = CreatePipe }
43
99
44− compile = liftIO $ createProcess $ (proc "elm" args) { std_out = CreatePipe }
100+ serve file =
45− where args = [ "--make", "--runtime=" ++ runtime, file ]
101+ serveFileAs "text/html; charset=UTF-8" ("build" </> replaceExtension file "html")
46
102
47− serve = serveFile (asContentType "text/html")
103+failure :: String -> Snap ()
48− ("build" </> replaceExtension file "html")
104+failure msg =
105+ do modifyResponse $ setResponseStatus 404 "Not found"
106+ writeBS $ BSC.pack msg
49
107
108+onSuccess :: IO (t, Maybe Handle, t1, ProcessHandle) -> Snap () -> Snap ()
50−onSuccess action success = do
109+onSuccess action success =
51− (_, stdout, _, handle) <- action
110+ do (_, stdout, _, handle) <- liftIO action
52− exitCode <- liftIO $ waitForProcess handle
111+ exitCode <- liftIO $ waitForProcess handle
53− case (exitCode, stdout) of
112+ case (exitCode, stdout) of
54− (ExitFailure 127, _) ->
113+ (ExitFailure 127, _) ->
55− badRequest $ toResponse "Error: elm binary not found in your path."
114+ failure "Error: elm compiler not found in your path."
56− (ExitFailure _, Just out) ->
57− do str <- liftIO $ hGetContents out
58− badRequest $ toResponse str
59− (ExitFailure _, Nothing) ->
60− badRequest $ toResponse "See command line for error message."
61− (ExitSuccess, _) -> success
62
115
116+ (ExitFailure _, Just out) ->
117+ failure =<< liftIO (hGetContents out)
63
118
64−serveLib :: FilePath -> String -> ServerPartT IO Response
119+ (ExitFailure _, Nothing) ->
65−serveLib libLoc fp = do
120+ failure "See command line for error message."
66− guard (fp == runtime)
67− serveFile (asContentType "application/javascript") libLoc
68
121
69−main :: IO ()
122+ (ExitSuccess, _) -> success
70−main = getArgs >>= parse
71−
72−parse :: [String] -> IO ()
73−parse ("--help":_) = putStrLn usage
74−parse ("--version":_) = putStrLn ("The Elm Server " ++ showVersion version)
75−parse args =
76− if null remainingArgs then
77− serve portNumber elmRuntime
78− else
79− putStrLn usageMini
80
123
81− where
124+{--
82− runtimeArg = filter (isPrefixOf "--runtime-location=") args
125+pageTitle :: String -> String
83− portArg = filter (isPrefixOf "--port=") args
126+pageTitle = dropExtension . takeBaseName
84− remainingArgs = (args \\ runtimeArg) \\ portArg
127+--}
85−
86− argValue arg = tail $ dropWhile (/= '=') (head arg)
87− portNumber = if null portArg then 8000 else read (argValue portArg) :: Int
88− elmRuntime = if null runtimeArg then
89− ElmPaths.runtime
90− else
91− argValue runtimeArg
92−
93−usageMini :: String
94−usageMini =
95− "Usage: elm-server [OPTIONS]\n\
96− \Try `elm-server --help' for more information."
97−
98−usage :: String
99−usage =
100− "Usage: elm-server [OPTIONS]\n\
101− \Compiles and serves .elm files from the current directory.\n\
102− \Example: elm-server\n\
103− \\n\
104− \Server configuration:\n\
105− \ --port set the port to listen on (default: 8000)\n\
106− \\n\
107− \Resource Locations:\n\
108− \ --runtime-location set the location of the Elm runtime\n\
109− \\n\
110− \Compiler Information:\n\
111− \ --version print the version information and exit\n\
112− \ --help display this help and exit\n\
113− \\n\
114− \Elm home page: <http://elm-lang.org>"
server/elm-server.cabal+14−13
@@ -1,7 +1,9 @@
1Name: elm-server
1Name: elm-server
2−Version: 0.10.1
2+Version: 0.11
3−Synopsis: The Elm language server.
3+Synopsis: Server for developing Elm projects
4−Description: This package provides a standalone, Happstack-based Elm server.
4+Description: Provides a standalone Snap server that serves static files.
5+ For Elm files, it recompiles them and serves them as HTML,
6+ so you can just refresh to see the new version.
5
7
6Homepage: http://elm-lang.org
8Homepage: http://elm-lang.org
7
9
@@ -10,7 +12,7 @@ License-file: LICENSE
10
12
11Author: Evan Czaplicki
13Author: Evan Czaplicki
12Maintainer: info@elm-lang.org
14Maintainer: info@elm-lang.org
13−Copyright: Copyright: (c) 2011-2013 Evan Czaplicki
15+Copyright: Copyright: (c) 2011-2014 Evan Czaplicki
14
16
15Category: Compiler, Language
17Category: Compiler, Language
16
18
@@ -26,15 +28,14 @@ source-repository head
26Executable elm-server
28Executable elm-server
27 Main-is: Server.hs
29 Main-is: Server.hs
28 Build-depends: base >=4.2 && <5,
30 Build-depends: base >=4.2 && <5,
31+ bytestring,
32+ cmdargs,
29 containers >= 0.3,
33 containers >= 0.3,
30 directory,
34 directory,
31− transformers >= 0.2,
32− mtl >= 2,
33− parsec >= 3.1.1,
34− blaze-html >= 0.5.1,
35− HTTP >= 4000,
36− happstack-server,
37− deepseq,
38 filepath,
35 filepath,
39− Elm >= 0.10.1,
36+ Elm >= 0.11,
37+ snap-core,
38+ snap-server,
39+ mtl,
40− process
40+ process,
41+ unordered-containers