on master help sign in
Merge pull request #1 from elm-lang/master

Update.

commitfc1c4d4ddc70e8440c5f804c793072853dd0bd72 authorChristian Widera <xash@posteo.de> dateMon 31 Mar 2014, 15:57 (13 years ago) parent154187c5cdb8f3
37 files changed+532−621
Elm.cabal+4−4 LICENSE+1−1 README.md+3−3 changelog.txt → changelog.md+17−4 compiler/Build/Flags.hs+1−1 compiler/Generate/JavaScript.hs+9−7 compiler/Generate/JavaScript/Ports.hs+14−15 compiler/Metadata/Prelude.hs+3−1 compiler/Parse/Helpers.hs+5−3 compiler/Type/ExtraChecks.hs+10−14 libraries/Basics.elm+27 libraries/Char.elm+2−2 libraries/Debug.elm+2 libraries/Graphics/Collage.elm−1 libraries/Graphics/Element.elm+10−13 libraries/Http.elm+2−4 libraries/JavaScript.elm−74 libraries/JavaScript/Experimental.elm+30−16 libraries/Json.elm+25−110 libraries/Keyboard.elm+2−4 libraries/Native/Basics.js+3 libraries/Native/Date.js+1−2 libraries/Native/JavaScript.js+59−91 libraries/Native/Json.js+71−58 libraries/Native/Regex.js+14−14 libraries/Native/Signal/Http.js+6−7 libraries/Native/Signal/Touch.js+3−3 libraries/Native/Signal/WebSocket.js+3−5 libraries/Native/String.js+9−9 libraries/Signal.elm+1−1 libraries/String.elm+6−6 libraries/Text.elm−1 libraries/elm_dependencies.json+4−4 runtime/Render/Element.js+58−30 server/LICENSE+1−1 server/Server.hs+112−99 server/elm-server.cabal+14−13
Elm.cabal+4−4
@@ -1,5 +1,5 @@
11Name: Elm
2−Version: 0.11
2+Version: 0.12
33Synopsis: The Elm language module.
44Description: Elm aims to make client-side web-development more pleasant.
55 It is a statically/strongly typed, functional reactive
@@ -14,13 +14,13 @@ License-file: LICENSE
1414
1515Author: Evan Czaplicki
1616Maintainer: info@elm-lang.org
17−Copyright: Copyright: (c) 2011-2013 Evan Czaplicki
17+Copyright: Copyright: (c) 2011-2014 Evan Czaplicki
1818
1919Category: Compiler, Language
2020
2121Build-type: Custom
2222
23−Extra-source-files: changelog.txt
23+Extra-source-files: changelog.md
2424Data-dir: data
2525Data-files: elm-runtime.js interfaces.data docs.json
2626Cabal-version: >=1.9
@@ -251,7 +251,7 @@ Test-Suite test-elm
251251 Elm,
252252 test-framework,
253253 test-framework-hunit,
254− test-framework-quickcheck2,
254+ test-framework-quickcheck2 >= 0.3,
255255 HUnit,
256256 pretty,
257257 QuickCheck >= 2 && < 3,
LICENSE+1−1
@@ -1,4 +1,4 @@
1−Copyright (c) 2012-2013, Evan Czaplicki
1+Copyright (c) 2012-2014, Evan Czaplicki
22
33All rights reserved.
44
README.md+3−3
@@ -1,10 +1,10 @@
11Learn about the Elm programming language at [elm-lang.org](http://elm-lang.org/).
22
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)
44
55## Install
66
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
88jump to the [My First Project](#my-first-project) section.
99<br/>
1010**OS X 10.9 or XCode 5** &mdash; follow
@@ -51,7 +51,7 @@ The `elm` package provides
5151working with Elm in Haskell. This can be useful for creating tooling
5252for Elm, and has been useful for projects like
5353[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
5555want to rely on these functions!
5656
5757If you are stuck, email
changelog.txt → changelog.mdrenamed+17−4
@@ -1,9 +1,22 @@
11
2−## next
2+## 0.13
33
4−Breaking Changes:
4+#### Breaking Changes:
55
6− * Overhaul Graphics.Input library (inspired by @seliopou and Jeff Smits)
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+
19+ * Overhaul Graphics.Input library (inspired by Spiros Eliopoulos and Jeff Smitts)
720 * Overhaul Text library to accomodate new Graphics.Input.Field
821 library and make the API more consistent overall
922 * Overhaul Regex library (inspired by Attila Gazso)
@@ -13,7 +26,7 @@ Breaking Changes:
1326 * Revise the semantics of keepWhen and dropWhen to only update when
1427 the filtered signal changes (thanks Max New and Janis Voigtländer)
1528
16−Improvements:
29+#### Improvements:
1730
1831 * Add Graphics.Input.Field for customizable text fields
1932 * Add Trampoline library (thanks to @maxsnew and @timthelion)
compiler/Build/Flags.hs+1−1
@@ -41,4 +41,4 @@ flags = Flags
4141 } &= help "Compile Elm programs to HTML, CSS, and JavaScript."
4242 &= helpArg [explicit, name "help", name "h"]
4343 &= 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 =
3939 , include "_U" "_N.Utils"
4040 , include "_L" "_N.List"
4141 , include "_E" "_N.Error"
42− , include "_J" "_N.JavaScript"
4342 , varDecl "$moduleName" (string name)
4443 ]
4544
@@ -55,7 +54,7 @@ literal lit =
5554expression :: Expr -> State Int (Expression ())
5655expression (A region expr) =
5756 case expr of
58− Var (V.Raw x) -> return $ ref x
57+ Var (V.Raw x) -> return $ obj x
5958 Literal lit -> return $ literal lit
6059
6160 Range lo hi ->
@@ -87,10 +86,9 @@ expression (A region expr) =
8786 do fields' <- forM fields $ \(f,e) -> do
8887 (,) f <$> expression e
8988 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
9190 where
9291 combine r (k,v) = Map.insertWith (++) k [v] r
93− prop = PropId () . var
9492 hidden fs = ObjectLit () . map (prop *** ArrayLit ()) .
9593 Map.toList . Map.filter (not . null) $ Map.map tail fs
9694 visible fs = map (first prop) . Map.toList $ Map.map head fs
@@ -164,7 +162,7 @@ expression (A region expr) =
164162
165163 ExplicitList es ->
166164 do es' <- mapM expression es
167− return $ obj "_J.toList" <| ArrayLit () es'
165+ return $ obj "_L.fromArray" <| ArrayLit () es'
168166
169167 Data name es ->
170168 do es' <- mapM expression es
@@ -243,7 +241,11 @@ match region mtch =
243241 isLiteral p = case p of
244242 Case.Clause (Right _) _ _ -> True
245243 _ -> False
246− access name = if any isLiteral clauses then ref name else dotSep [name,"ctor"]
244+
245+ access name
246+ | any isLiteral clauses = obj name
247+ | otherwise = dotSep (split name ++ ["ctor"])
248+
247249 format isChars e
248250 | or isChars = InfixExpr () OpAdd e (string "")
249251 | otherwise = e
@@ -307,7 +309,7 @@ generate unsafeModule =
307309 jsExports = assign ("_elm" : names modul ++ ["values"]) (ObjectLit () exs)
308310 where
309311 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)
311313
312314 assign path expr =
313315 case path of
compiler/Generate/JavaScript/Ports.hs+14−15
@@ -35,17 +35,17 @@ inc tipe x =
3535 case tipe of
3636 Lambda _ _ -> error "functions should not be allowed through input ports"
3737 Var _ -> error "type variables should not be allowed through input ports"
38+
39+ Data "Json.Value" [] ->
40+ obj "Native.Json.fromJS" <| x
41+
3842 Data ctor []
39− | ctor == "Int" -> elm JSNumber
40− | ctor == "Float" -> elm JSNumber
41− | ctor == "Bool" -> elm JSBoolean
42− | ctor == "String" -> elm JSString
43− | ctor == "JavaScript.JSNumber" -> js JSNumber
44− | ctor == "JavaScript.JSBool" -> js JSBoolean
45− | ctor == "JavaScript.JSString" -> js JSString
43+ | ctor == "Int" -> from JSNumber
44+ | ctor == "Float" -> from JSNumber
45+ | ctor == "Bool" -> from JSBoolean
46+ | ctor == "String" -> from JSString
4647 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
4949
5050 Data ctor [t]
5151 | ctor == "Maybe.Maybe" ->
@@ -54,7 +54,7 @@ inc tipe x =
5454 (obj "Maybe.Just" <| inc t x)
5555
5656 | ctor == "_List" ->
57− check x JSArray (obj "_J.toList" <| array)
57+ check x JSArray (obj "_L.fromArray" <| array)
5858 where
5959 array = DotRef () x (var "map") <| incoming t
6060
@@ -104,10 +104,9 @@ out tipe x =
104104
105105 Var _ -> error "type variables should not be allowed through input ports"
106106 Data ctor []
107− | ctor `elem` ["Int","Float","Bool","String"] -> obj ("_J.from" ++ ctor) <| x
108− | ctor `elem` jsPrims -> x
109− where
110− jsPrims = map ("JavaScript.JS"++) ["Number","Bool","String"]
107+ | ctor `elem` ["Int","Float","Bool","String"] -> x
108+ | ctor == "Json.Value" ->
109+ obj "Native.Json.toJS" <| x
111110
112111 Data ctor [t]
113112 | ctor == "Maybe.Maybe" ->
@@ -116,7 +115,7 @@ out tipe x =
116115 (out t (DotRef () x (var "_0")))
117116
118117 | ctor == "_List" ->
119− DotRef () (obj "_J.fromList" <| x) (var "map") <| outgoing t
118+ DotRef () (obj "_L.toArray" <| x) (var "map") <| outgoing t
120119
121120 Data ctor ts
122121 | Help.isTuple ctor ->
compiler/Metadata/Prelude.hs+3−1
@@ -25,7 +25,9 @@ prelude = string ++ text ++ map (\n -> (n, Hiding [])) modules
2525 text = map ((,) "Text") [ As "Text", Hiding ["link", "color", "height"] ]
2626 string = map ((,) "String") [ As "String", Importing ["show"] ]
2727 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+ ]
2931
3032interfaces :: Bool -> IO Interfaces
3133interfaces noPrelude =
compiler/Parse/Helpers.hs+5−3
@@ -79,9 +79,11 @@ innerVarChar :: IParser Char
7979innerVarChar = alphaNum <|> char '_' <|> char '\'' <?> ""
8080
8181makeVar :: IParser Char -> IParser String
82−makeVar p = do v <- (:) <$> p <*> many innerVarChar
83− guard (v `notElem` reserveds)
84− return v
82+makeVar p = do
83+ v <- (:) <$> p <*> many innerVarChar
84+ if v `elem` reserveds
85+ then fail $ "unexpected keyword '" ++ v ++ "', variables cannot be keywords"
86+ else return v
8587
8688reserved :: String -> IParser String
8789reserved word =
compiler/Type/ExtraChecks.hs+10−14
@@ -8,7 +8,6 @@ module Type.ExtraChecks (mainType, occurs, portTypes) where
88
99import Control.Applicative ((<$>),(<*>))
1010import Control.Monad.State
11−import qualified Data.List as List
1211import qualified Data.Map as Map
1312import qualified Data.Traversable as Traverse
1413import qualified Data.UnionFind.IO as UF
@@ -56,9 +55,15 @@ portTypes rules expr =
5655 isValid isTopLevel seenFunc seenSignal direction name tipe =
5756 case tipe of
5857 ST.Data ctor ts
59− | isJs ctor || isElm ctor -> mapM_ valid ts
58+ | validConstructor -> mapM_ valid ts
6059 | ctor == "Signal.Signal" -> handleSignal ts
6160 | 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
6267
6368 ST.Var _ -> err "free type variables"
6469
@@ -80,14 +85,6 @@ portTypes rules expr =
8085 isValid' = isValid False
8186 valid = isValid' seenFunc seenSignal direction name
8287
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−
9188 handleSignal ts
9289 | seenFunc = err "functions that involve signals"
9390 | seenSignal = err "signals-of-signals"
@@ -104,10 +101,9 @@ portTypes rules expr =
104101 , " through port '", name, "' is invalid." ]
105102 , txt [ "It contains ", kind, ":\n" ]
106103 , (P.nest 4 . SPP.pretty $ Alias.realias rules tipe) <> P.text "\n"
107− , txt [ "Acceptable values for ", dir "incoming" "outgoing"
108− , " ports include JavaScript values and" ]
109− , txt [ "the following Elm values: Ints, Floats, Bools, Strings, Maybes," ]
110− , txt [ "Lists, Tuples, ", dir "" "first-order functions, ", "and concrete records." ]
104+ , txt [ "Acceptable values for ", dir "incoming" "outgoing", " ports include:" ]
105+ , txt [ " Ints, Floats, Bools, Strings, Maybes, Lists, Tuples," ]
106+ , txt [ " Json.Values, ", dir "" "first-order functions, ", "and concrete records." ]
111107 ] ++ if couldBeAlias then aliasWarning else []
112108
113109 aliasWarning =
libraries/Basics.elm+27
@@ -39,6 +39,9 @@ which happen to be radians.
3939# Polar Coordinates
4040@docs toPolar, fromPolar
4141
42+# Floating Point Checks
43+@docs isNaN, isInfinite
44+
4245# Tuples
4346@docs fst, snd
4447
@@ -271,6 +274,30 @@ ceiling = Native.Basics.ceiling
271274toFloat : Int -> Float
272275toFloat = Native.Basics.toFloat
273276
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
274301
275302-- Function Helpers
276303
libraries/Char.elm+2−2
@@ -52,8 +52,8 @@ toLocaleLower = Native.Char.toLocaleLower
5252
5353type KeyCode = Int
5454
55−{-| Convert to unicode. Used with the [`Keyboard`](/docs/Keyboard.elm)
56−library, which expects the input to be uppercase. -}
55+{-| Convert to unicode. Used with the `Keyboard` library, which expects the
56+input to be uppercase. -}
5757toCode : Char -> KeyCode
5858toCode = Native.Char.toCode
5959
libraries/Debug.elm+2
@@ -1,6 +1,8 @@
11module Debug where
22{-| This library is for investigating bugs or performance problems. It should
33*not* be used in production code.
4+
5+@docs log
46-}
57
68import Native.Debug
libraries/Graphics/Collage.elm−1
@@ -38,7 +38,6 @@ import Native.Graphics.Collage
3838import Graphics.Element (Element)
3939import Color (Color, black, Gradient)
4040import Maybe (Maybe)
41−import JavaScript (JSString)
4241
4342type Form = {
4443 theta : Float,
libraries/Graphics/Element.elm+10−13
@@ -39,8 +39,6 @@ If you need more precision, you can create custom positions.
3939
4040import Basics (..)
4141import Native.Utils
42−import JavaScript as JS
43−import JavaScript (JSString)
4442import List as List
4543import Color (..)
4644import Maybe (Maybe, Just, Nothing)
@@ -51,8 +49,8 @@ type Properties = {
5149 height : Int,
5250 opacity : Float,
5351 color : Maybe Color,
54− href : JSString,
55− tag : JSString,
52+ href : String,
53+ tag : String,
5654 hover : (),
5755 click : ()
5856 }
@@ -120,21 +118,20 @@ with a link like this: `/facts-about-animals.elm#all-about-badgers`
120118-}
121119tag : String -> Element -> Element
122120tag 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} }
124122
125123{-| Create an `Element` that is a hyper-link. -}
126124link : String -> Element -> Element
127125link 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} }
129127
130−emptyStr = JS.fromString ""
131128newElement 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 "" "" () ()
133130 , element = e
134131 }
135132
136133data ElementPrim
137− = Image ImageStyle Int Int JSString
134+ = Image ImageStyle Int Int String
138135 | Container Position Element
139136 | Flow Direction [Element]
140137 | Spacer
@@ -145,13 +142,13 @@ data ImageStyle = Plain | Fitted | Cropped (Int,Int) | Tiled
145142
146143{-| Create an image given a width, height, and image source. -}
147144image : 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)
149146
150147{-| Create a fitted image given a width, height, and image source.
151148This will crop the picture to best fill the given dimensions.
152149-}
153150fittedImage : 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)
155152
156153{-| Create a cropped image. Take a rectangle out of the picture starting
157154at 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.
161158-}
162159croppedImage : (Int,Int) -> Int -> Int -> String -> Element
163160croppedImage 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)
165162
166163tiledImage : Int -> Int -> String -> Element
167164tiledImage w h src =
168− newElement w h (Image Tiled w h (JS.fromString src))
165+ newElement w h (Image Tiled w h src)
169166
170167data Three = P | Z | N
171168data Pos = Absolute Int | Relative Float
libraries/Http.elm+2−4
@@ -1,8 +1,6 @@
11module Http where
2−
3−{-| A library for asynchronous HTTP requests. See the
4−[WebSocket](http://elm-lang.org/docs/WebSocket.elm) library if
5−you have very strict latency requirements.
2+{-| A library for asynchronous HTTP requests. See the `WebSocket`
3+library if you have very strict latency requirements.
64
75# Sending Requests
86@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.
88@docs toRecord, fromRecord
99-}
1010
11−import JavaScript (JSObject)
1211import Native.JavaScript
12+import Json
13+
14+data RawObject = RawObject
1315
1416{-| Turn arbitrary JavaScript objects into Elm records.
1517Arrays are converted into lists, nested objects are allowed.
1618No `null` values or non-homogeneous arrays.
1719
18− -- OK objects
19− { student:"Steve", scores:[83,94,99,72] }
20− { errorLevel:10, critical:true }
20+ -- OK objects
21+ { student:"Steve", scores:[83,94,99,72] }
22+ { errorLevel:10, critical:true }
2123
22− -- BAD objects
23− { answer:null }
24− { info:[true,42,'what'] }
24+ -- BAD objects
25+ { answer:null }
26+ { info:[true,42,'what'] }
2527-}
26−toRecord : JSObject -> a
28+toRecord : RawObject -> a
2729toRecord = Native.JavaScript.toRecord
2830
2931{-| Turn arbitrary Elm records into JavaScript objects.
3032Lists become arrays, nested records are allowed. No ADTs.
3133
32− -- OK records
33− { student="Steve", scores=[83,94,99,72] }
34− { errorLevel=10, critical=True }
34+ -- OK records
35+ { student="Steve", scores=[83,94,99,72] }
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
3550
36− -- BAD records
37− { answer = Nothing }
38− { result = Left "An error occurred" }
51+{-| Turn a `Json.Value` (as described in the `Json` library) into a raw
52+JavaScript object.
3953-}
40−fromRecord : a -> JSObject
41−fromRecord = Native.JavaScript.fromRecord
54+fromJson : Json.Value -> RawObject
55+fromJson = Native.Json.toJS
libraries/Json.elm+25−110
@@ -3,132 +3,47 @@ module Json where
33
44{-| Library for working with [JSON](https://en.wikipedia.org/wiki/JSON) values.
55
6−# Json Values
7−@docs JsonValue
8−
9−# Strings
10−@docs fromString, toString
11−
12−# JS Strings
13−@docs fromJSString, toJSString
14−
15−# JS Objects
16−@docs fromJSObject, toJSObject
6+@docs Value, fromString, toString
177
188-}
199
20−import Basics (..)
2110import Dict
2211import Maybe (Maybe)
23−import JavaScript as JS
2412import Native.Json
25−import JavaScript (JSObject, JSString)
2613
27−{-| This datatype can represent all valid values that can be held in a JSON
28−object. In Elm, a proper JSON object is represented as a (Dict String JsonValue)
29−which is a mapping from strings to Json Values. -}
30−data JsonValue
14+{-| This datatype can represent all valid JSON values. A `Value` can be sent
15+through ports, and the runtime will do a conversion like this:
16+
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
3123 = String String
3224 | Number Float
3325 | Boolean Bool
3426 | Null
35− | Array [JsonValue]
36− | Object (Dict.Dict String JsonValue)
37−
27+ | Array [Value]
28+ | Object (Dict.Dict String Value)
3829
39−-- String Converters
4030
41−{-| Convert a `JsonValue` into a prettified string.
31+{-| Convert a `Value` into a prettified string.
4232The 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. -}
44−toString : String -> JsonValue -> String
45−toString sep v = JS.toString (Native.Json.toJSString sep v)
33+be used for indentation in the prettified string version of the JSON.
4634
47−{-| Convert a proper JSON object into a JavaScript string.
48−Note that the type JSString seen here is not the same as the type constructor
49−JsonString used elsewhere in this module. -}
50−toJSString : String -> JsonValue -> JSString
51−toJSString = Native.Json.toJSString
35+ toString "" Null == "null"
36+ toString "" (Number 4.0) == "4.0"
37+-}
38+toString : String -> Value -> String
39+toString sep value = Native.Json.toString sep value
5240
5341{-| Parse a string representation of a proper JSON object into
54−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
42+its Elm representation.
6643
67−{-| Convert a `JsonValue` into a `JSObject`. Paired with the
68−[`JavaScript.Experimental` library](/docs/JavaScript/Experimental.elm),
69−This lets you convert strings into Elm records:
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
44+ fromString "null" == Just Null
45+ fromString "[true,3]" == Just (Array [Boolean True, Number 3])
46+ fromString "{'abc':4}" == Just (Object (Dict.fromList [("abc", Number 4)]))
7747-}
78−toJSObject : JsonValue -> JSObject
79−toJSObject = Native.Json.toJSObject
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− --}
48+fromString : String -> Maybe Value
49+fromString str = Native.Json.fromString str
libraries/Keyboard.elm+2−4
@@ -1,5 +1,4 @@
11module Keyboard where
2−
32{-| Library for working with keyboard input.
43
54# Representing Keys
@@ -20,9 +19,8 @@ import Signal (Signal)
2019import Native.Keyboard
2120
2221{-| Type alias to make it clearer what integers are supposed to represent
23−in this library. Use [`Char.toCode`](docs/Char.elm#toCode) and
24−[`Char.fromCode`](/docs/Char.elm#fromCode) to convert key codes to characters.
25−Use the uppercase character with `toCode`.
22+in this library. Use `Char.toCode` and `Char.fromCode` to convert key codes
23+to characters. Use the uppercase character with `toCode`.
2624-}
2725type KeyCode = Int
2826
libraries/Native/Basics.js+3
@@ -19,6 +19,7 @@ Elm.Native.Basics.make = function(elm) {
1919 return Utils.cmp(n,lo) < 0 ? lo : Utils.cmp(n,hi) > 0 ? hi : n; }
2020 function xor(a,b) { return a !== b; }
2121 function not(b) { return !b; }
22+ function isInfinite(n) { return n === Infinity || n === -Infinity }
2223
2324 function truncate(n) { return n|0; }
2425
@@ -53,6 +54,8 @@ Elm.Native.Basics.make = function(elm) {
5354 floor:Math.floor,
5455 round:Math.round,
5556 toFloat:function(x) { return x; },
57+ isNaN:isNaN,
58+ isInfinite:isInfinite
5659 };
5760
5861 return elm.Native.Basics.values = basics;
libraries/Native/Date.js+1−2
@@ -4,12 +4,11 @@ Elm.Native.Date.make = function(elm) {
44 elm.Native.Date = elm.Native.Date || {};
55 if (elm.Native.Date.values) return elm.Native.Date.values;
66
7− var JS = Elm.JavaScript.make(elm);
87 var Maybe = Elm.Maybe.make(elm);
98
109 function dateNow() { return new window.Date; }
1110 function readDate(str) {
12− var d = new window.Date(JS.fromString(str));
11+ var d = new window.Date(str);
1312 if (isNaN(d.getTime())) return Maybe.Nothing;
1413 return Maybe.Just(d);
1514 }
libraries/Native/JavaScript.js+59−91
@@ -1,100 +1,68 @@
11Elm.Native.JavaScript = {};
22Elm.Native.JavaScript.make = function(elm) {
3− elm.Native = elm.Native || {};
4− elm.Native.JavaScript = elm.Native.JavaScript || {};
5− if (elm.Native.JavaScript.values) return elm.Native.JavaScript.values;
3+ elm.Native = elm.Native || {};
4+ elm.Native.JavaScript = elm.Native.JavaScript || {};
5+ if (elm.Native.JavaScript.values) return elm.Native.JavaScript.values;
66
7− var List = Elm.Native.List.make(elm);
8− var Render = ElmRuntime.use(ElmRuntime.Render.Element);
7+ var List = Elm.Native.List.make(elm);
8+ var Render = ElmRuntime.use(ElmRuntime.Render.Element);
99
10− function fromJS(v) {
11− var type = typeof v;
12− if (type === 'number' ) return v;
13− if (type === 'boolean') return v;
14− if (type === 'string' ) return v;
15− if (v instanceof Array) {
16− var arr = [];
17− var len = v.length;
18− for (var i = 0; i < len; ++i) {
19− var x = fromJS(v[i]);
20− if (x !== null) arr.push(x);
21− }
22− return List.fromArray(arr);
23− }
24− if (type === 'object') {
25− var rec = { _:{} };
26− for (var f in v) {
27− var x = fromJS(v[f]);
28− if (x !== null) rec[f] = x;
29− }
30− return rec;
31− }
32− return null;
33− }
10+ function fromJS(v) {
11+ var type = typeof v;
12+ if (type === 'number' ) return v;
13+ if (type === 'boolean') return v;
14+ if (type === 'string' ) return v;
15+ if (v instanceof Array) {
16+ var arr = [];
17+ var len = v.length;
18+ for (var i = 0; i < len; ++i) {
19+ var x = fromJS(v[i]);
20+ if (x !== null) arr.push(x);
21+ }
22+ return List.fromArray(arr);
23+ }
24+ if (type === 'object') {
25+ var rec = { _:{} };
26+ for (var f in v) {
27+ var x = fromJS(v[f]);
28+ if (x !== null) rec[f] = x;
29+ }
30+ return rec;
31+ }
32+ return null;
33+ }
3434
35− function toJS(v) {
36− var type = typeof v;
37− if (type === 'number' || type === 'boolean' || type === 'string') return v;
38− if (type === 'object' && '_' in v) {
39− var obj = {};
40− for (var k in v) {
41− var x = toJS(v[k]);
42− if (x !== null) obj[k] = x;
43− }
44− return obj;
45− }
46− if (type === 'object' && (v.ctor === '::' || v.ctor === '[]')) {
47− var array = List.toArray(v);
48− for (var i = array.length; i--; ) {
49− array[i] = toJS(array[i]);
50− }
51− return array;
52− }
53− return null;
54− }
35+ function toJS(v) {
36+ var type = typeof v;
37+ if (type === 'number' || type === 'boolean' || type === 'string') return v;
38+ if (type === 'object' && '_' in v) {
39+ var obj = {};
40+ for (var k in v) {
41+ var x = toJS(v[k]);
42+ if (x !== null) obj[k] = x;
43+ }
44+ return obj;
45+ }
46+ if (type === 'object' && (v.ctor === '::' || v.ctor === '[]')) {
47+ var array = List.toArray(v);
48+ for (var i = array.length; i--; ) {
49+ array[i] = toJS(array[i]);
50+ }
51+ return array;
52+ }
53+ return null;
54+ }
5555
56− function fromRecord(r) {
57− if (typeof r === 'object' && '_' in r) {
58− return toJS(r);
59− }
60− throw new Error("'fromRecord' must be called on a record.");
61− }
56+ function fromRecord(r) {
57+ if (typeof r === 'object' && '_' in r) {
58+ return toJS(r);
59+ }
60+ throw new Error("'fromRecord' must be called on a record.");
61+ }
6262
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 = {
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,
97− fromRecord : fromRecord
98− };
63+ return elm.Native.JavaScript.values = {
64+ toRecord : fromJS,
65+ fromRecord : fromRecord
66+ };
9967
10068};
libraries/Native/Json.js+71−58
@@ -1,72 +1,85 @@
11Elm.Native.Json = {};
22Elm.Native.Json.make = function(elm) {
33
4− elm.Native = elm.Native || {};
5− elm.Native.Json = elm.Native.Json || {};
6− if (elm.Native.Json.values) return elm.Native.Json.values;
4+ elm.Native = elm.Native || {};
5+ elm.Native.Json = elm.Native.Json || {};
6+ if (elm.Native.Json.values) return elm.Native.Json.values;
77
8− var Maybe = Elm.Maybe.make(elm);
9− var Dict = Elm.Dict.make(elm);
10− var List = Elm.List.make(elm);
11− var JS = Elm.JavaScript.make(elm);
12− var Utils = Elm.Native.Utils.make(elm);
8+ var Maybe = Elm.Maybe.make(elm);
9+ var Dict = Elm.Dict.make(elm);
10+ var List = Elm.Native.List.make(elm);
11+ var Utils = Elm.Native.Utils.make(elm);
1312
14− function fromValue(v) {
15− switch (v.ctor) {
16− case 'Null' : return null;
17− case 'String' : return JS.fromString(v._0);
18− case 'Object' :
19− var obj = {};
20− var array = JS.fromList(Dict.toList(v._0));
21− for (var i = array.length; i--; ) {
22− obj[JS.fromString(array[i]._0)] = fromValue(array[i]._1);
23− }
24− return obj;
25− case 'Array' :
26− var array = JS.fromList(v._0);
27− for (var i = array.length; i--; ) {
28− array[i] = fromValue(array[i]);
29− }
30− return array;
31− default :
32− return v._0;
13+ function toJS(v) {
14+ switch (v.ctor) {
15+ case 'Null' : return null;
16+ case 'String' : return v._0;
17+ case 'Number' : return v._0;
18+ case 'Boolean': return v._0;
19+ case 'Object' :
20+ var obj = {};
21+ var array = List.toArray(Dict.toList(v._0));
22+ for (var i = array.length; i--; ) {
23+ var entry = array[i];
24+ obj[entry._0] = toJS(entry._1);
25+ }
26+ return obj;
27+ case 'Array' :
28+ var array = List.toArray(v._0);
29+ for (var i = array.length; i--; ) {
30+ array[i] = toJS(array[i]);
31+ }
32+ return array;
33+ }
3334 }
34− }
3535
36− function toPrettyJSString(sep, obj) {
37− return JSON.stringify(fromValue(obj), null, JS.fromString(sep));
38− }
36+ function toString(sep, value) {
37+ return JSON.stringify(toJS(value), null, sep);
38+ }
3939
40− function toValue(v) {
41− switch (typeof v) {
42− case 'string' : return { ctor:"String", _0: JS.toString(v) };
43− case 'number' : return { ctor:"Number", _0: JS.toFloat(v) };
44− case 'boolean': return { ctor:"Boolean" , _0: JS.toBool(v) };
45− case 'object' :
46− if (v === null) return { ctor:"Null" };
47− if (v instanceof Array) {
48− for (var i = v.length; i--; ) { v[i] = toValue(v[i]); }
49− return { ctor:"Array", _0: JS.toList(v) };
50− }
51− var array = [];
52− for (var k in v) array.push(Utils.Tuple2(JS.toString(k), toValue(v[k])));
53− return { ctor:"Object", _0: Dict.fromList(JS.toList(array)) };
40+ function fromJS(v) {
41+ switch (typeof v) {
42+ case 'string' : return { ctor:"String" , _0: v };
43+ case 'number' : return { ctor:"Number" , _0: v };
44+ case 'boolean': return { ctor:"Boolean", _0: v };
45+ case 'object' :
46+ if (v === null) return { ctor:"Null" };
47+ if (v instanceof Array) {
48+ var array = new Array(v.length);
49+ for (var i = v.length; i--; ) {
50+ array[i] = fromJS(v[i]);
51+ }
52+ return {
53+ ctor:"Array",
54+ _0: List.fromArray(array)
55+ };
56+ }
57+ var array = [];
58+ for (var key in v) {
59+ var value = fromJS(v[key]);
60+ array.push(Utils.Tuple2(key, value));
61+ }
62+ var list = List.fromArray(array);
63+ return {
64+ ctor:"Object",
65+ _0: Dict.fromList(list)
66+ };
67+ }
5468 }
55− }
5669
57− function fromJSString(str) {
58− try {
59− return Maybe.Just(toValue(JSON.parse(str)));
60− } catch (e) {
61− return Maybe.Nothing;
70+ function fromString(str) {
71+ try {
72+ return Maybe.Just(fromJS(JSON.parse(str)));
73+ } catch (e) {
74+ return Maybe.Nothing;
75+ }
6276 }
63− }
6477
65− return elm.Native.Json.values = {
66− toJSString : F2(toPrettyJSString),
67− fromJSString : fromJSString,
68− toJSObject : fromValue,
69− fromJSObject : toValue
70− };
78+ return elm.Native.Json.values = {
79+ toString : F2(toString),
80+ fromString : fromString,
81+ fromJS : fromJS,
82+ toJS : toJS,
83+ };
7184
7285};
libraries/Native/Regex.js+14−14
@@ -6,8 +6,8 @@ Elm.Native.Regex.make = function(elm) {
66 if ('values' in Elm.Native.Regex)
77 return elm.Native.Regex.values = Elm.Native.Regex.values;
88
9+ var List = Elm.Native.List.make(elm);
910 var Maybe = Elm.Maybe.make(elm);
10− var JS = Elm.JavaScript.make(elm);
1111
1212 function escape(str) {
1313 return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
@@ -20,14 +20,14 @@ Elm.Native.Regex.make = function(elm) {
2020 }
2121
2222 function contains(re, string) {
23− return re.test(JS.fromString(string));
23+ return string.match(re) !== null;
2424 }
2525
2626 function find(n, re, str) {
2727 n = n.ctor === "All" ? Infinity : n._0;
2828 var out = [];
2929 var number = 0;
30− var string = JS.fromString(str);
30+ var string = str;
3131 var result;
3232 while (number++ < n && (result = re.exec(string))) {
3333 var i = result.length - 1;
@@ -36,17 +36,17 @@ Elm.Native.Regex.make = function(elm) {
3636 var submatch = result[i];
3737 subs[--i] = submatch === undefined
3838 ? Maybe.Nothing
39− : Maybe.Just(JS.toString(submatch));
39+ : Maybe.Just(submatch);
4040 }
4141 out.push({
4242 _:{},
43− match: JS.toString(result[0]),
44− submatches: JS.toList(subs),
43+ match: result[0],
44+ submatches: List.fromArray(subs),
4545 index: result.index,
4646 number: number,
4747 });
4848 }
49− return JS.toList(out);
49+ return List.fromArray(out);
5050 }
5151
5252 function replace(n, re, replacer, string) {
@@ -60,24 +60,24 @@ Elm.Native.Regex.make = function(elm) {
6060 var submatch = arguments[i];
6161 submatches[--i] = submatch === undefined
6262 ? Maybe.Nothing
63− : Maybe.Just(JS.toString(submatch));
63+ : Maybe.Just(submatch);
6464 }
65− return JS.fromString(replacer({
65+ return replacer({
6666 _:{},
6767 match:match,
68− submatches:JS.toList(submatches),
68+ submatches:List.fromArray(submatches),
6969 index:arguments[i-1],
7070 number:count
71− }));
71+ });
7272 }
7373 return string.replace(re, jsReplacer);
7474 }
7575
7676 function split(n, re, str) {
7777 if (n === Infinity) {
78− return JS.toList(JS.fromString(string).split(re));
78+ return List.fromArray(string.split(re));
7979 }
80− var string = JS.fromString(str);
80+ var string = str;
8181 var result;
8282 var out = [];
8383 var start = re.lastIndex;
@@ -87,7 +87,7 @@ Elm.Native.Regex.make = function(elm) {
8787 start = re.lastIndex;
8888 }
8989 out.push(string.slice(start));
90− return JS.toList(out);
90+ return List.fromArray(out);
9191 }
9292
9393 return Elm.Native.Regex.values = {
libraries/Native/Signal/Http.js+6−7
@@ -5,7 +5,6 @@ Elm.Native.Http.make = function(elm) {
55 elm.Native.Http = elm.Native.Http || {};
66 if (elm.Native.Http.values) return elm.Native.Http.values;
77
8− var JS = Elm.JavaScript.make(elm);
98 var List = Elm.List.make(elm);
109 var Signal = Elm.Signal.make(elm);
1110
@@ -38,17 +37,17 @@ Elm.Native.Http.make = function(elm) {
3837 request.onreadystatechange = function(e) {
3938 if (request.readyState === 4) {
4039 response.value = (request.status >= 200 && request.status < 300 ?
41− { ctor:'Success', _0:JS.toString(request.responseText) } :
42− { ctor:'Failure', _0:request.status, _1:JS.toString(request.statusText) });
40+ { ctor:'Success', _0:request.responseText } :
41+ { ctor:'Failure', _0:request.status, _1:request.statusText });
4342 setTimeout(function() { updateQueue(queue,responses); }, 0);
4443 }
4544 };
46− request.open(JS.fromString(req.verb), JS.fromString(req.url), true);
45+ request.open(req.verb, req.url, true);
4746 function setHeader(pair) {
48− request.setRequestHeader( JS.fromString(pair._0), JS.fromString(pair._1) );
47+ request.setRequestHeader( pair._0, pair._1 );
4948 }
50− List.map(setHeader)(req.headers);
51− request.send(JS.fromString(req.body));
49+ A2( List.map, setHeader, req.headers );
50+ request.send(req.body);
5251 }
5352
5453 function send(requests) {
libraries/Native/Signal/Touch.js+3−3
@@ -6,7 +6,7 @@ Elm.Native.Touch.make = function(elm) {
66 if (elm.Native.Touch.values) return elm.Native.Touch.values;
77
88 var Signal = Elm.Signal.make(elm);
9− var JS = Elm.JavaScript.make(elm);
9+ var List = Elm.Native.List.make(elm);
1010 var Utils = Elm.Native.Utils.make(elm);
1111
1212 function Dict() {
@@ -136,7 +136,7 @@ Elm.Native.Touch.make = function(elm) {
136136 return sig;
137137 }
138138
139− var touches = dependency(JS.toList);
139+ var touches = dependency(List.fromArray);
140140
141141 var taps = function() {
142142 var sig = dependency(function(_) { return tap; });
@@ -149,4 +149,4 @@ Elm.Native.Touch.make = function(elm) {
149149
150150 return elm.Native.Touch.values = { touches: touches, taps: taps };
151151
152−};
152+};
libraries/Native/Signal/WebSocket.js+3−5
@@ -6,12 +6,11 @@ Elm.Native.WebSocket.make = function(elm) {
66 if (elm.Native.WebSocket.values) return elm.Native.WebSocket.values;
77
88 var Signal = Elm.Signal.make(elm);
9− var JS = Elm.JavaScript.make(elm);
109 var List = Elm.Native.List.make(elm);
1110
1211 function open(url, outgoing) {
1312 var incoming = Signal.constant(List.Nil);
14− var ws = new WebSocket(JS.fromString(url));
13+ var ws = new WebSocket(url);
1514
1615 var pending = [];
1716 var ready = false;
@@ -22,12 +21,11 @@ Elm.Native.WebSocket.make = function(elm) {
2221 ready = true;
2322 };
2423 ws.onmessage = function(event) {
25− elm.notify(incoming.id, JS.toString(event.data));
24+ elm.notify(incoming.id, event.data);
2625 };
2726
2827 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);
3129 }
3230
3331 function take1(x,y) { return x }
libraries/Native/String.js+9−9
@@ -8,7 +8,7 @@ Elm.Native.String.make = function(elm) {
88
99 var Char = Elm.Char.make(elm);
1010 var Maybe = Elm.Maybe.make(elm);
11− var JS = Elm.JavaScript.make(elm);
11+ var List = Elm.Native.List.make(elm);
1212 var Utils = Elm.Native.Utils.make(elm);
1313
1414 function isEmpty(str) {
@@ -26,7 +26,7 @@ Elm.Native.String.make = function(elm) {
2626 return a + b;
2727 }
2828 function concat(strs) {
29− return JS.fromList(strs).join('');
29+ return List.toArray(strs).join('');
3030 }
3131 function length(str) {
3232 return str.length;
@@ -59,10 +59,10 @@ Elm.Native.String.make = function(elm) {
5959 }
6060
6161 function split(sep, str) {
62− return JS.toList(str.split(sep));
62+ return List.fromArray(str.split(sep));
6363 }
6464 function join(sep, strs) {
65− return JS.fromList(strs).join(sep);
65+ return List.toArray(strs).join(sep);
6666 }
6767 function repeat(n, str) {
6868 var result = '';
@@ -111,10 +111,10 @@ Elm.Native.String.make = function(elm) {
111111 }
112112
113113 function words(str) {
114− return JS.toList(str.split(/\s+/g));
114+ return List.fromArray(str.split(/\s+/g));
115115 }
116116 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));
118118 }
119119
120120 function toUpper(str) {
@@ -155,7 +155,7 @@ Elm.Native.String.make = function(elm) {
155155 is.push(i);
156156 i = i + subLen;
157157 }
158− return JS.toList(is);
158+ return List.fromArray(is);
159159 }
160160
161161 function toInt(s) {
@@ -193,10 +193,10 @@ Elm.Native.String.make = function(elm) {
193193 }
194194
195195 function toList(str) {
196− return JS.toList(str.split('').map(Utils.chr));
196+ return List.fromArray(str.split('').map(Utils.chr));
197197 }
198198 function fromList(chars) {
199− return JS.fromList(chars).join('');
199+ return List.toArray(chars).join('');
200200 }
201201
202202 return Elm.Native.String.values = {
libraries/Signal.elm+1−1
@@ -10,7 +10,7 @@ past-dependence.
1010
1111Some useful functions for working with time (e.g. setting FPS) and combining
1212signals and time (e.g. delaying updates, getting timestamps) can be found in
13−the [`Time`](/docs/Signal/Time.elm) library.
13+the `Time` library.
1414
1515# Combine
1616@docs constant, lift, lift2, merge, merges, combine
libraries/String.elm+6−6
@@ -174,18 +174,18 @@ pad = Native.String.pad
174174
175175{-| Pad a string on the left until it has a given length.
176176
177− pad 5 '.' "1" == "....1"
178− pad 5 '.' "11" == "...11"
179− pad 5 '.' "121" == "..121"
177+ padLeft 5 '.' "1" == "....1"
178+ padLeft 5 '.' "11" == "...11"
179+ padLeft 5 '.' "121" == "..121"
180180-}
181181padLeft : Int -> Char -> String -> String
182182padLeft = Native.String.padLeft
183183
184184{-| Pad a string on the right until it has a given length.
185185
186− pad 5 '.' "1" == "1...."
187− pad 5 '.' "11" == "11..."
188− pad 5 '.' "121" == "121.."
186+ padRight 5 '.' "1" == "1...."
187+ padRight 5 '.' "11" == "11..."
188+ padRight 5 '.' "121" == "121.."
189189-}
190190padRight : Int -> Char -> String -> String
191191padRight = Native.String.padRight
libraries/Text.elm−1
@@ -35,7 +35,6 @@ import String
3535import Color (Color, black)
3636import Graphics.Element (Element, Three, Pos, ElementPrim, Properties)
3737import Maybe (Maybe, Nothing)
38−import JavaScript (JSString)
3938import Native.Show
4039import Native.Text
4140
libraries/elm_dependencies.json+4−4
@@ -1,9 +1,9 @@
1−{ "version": "0.11"
1+{ "version": "0.12"
22, "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."
44, "license": "BSD3"
55, "repository": "http://github.com/evancz/Elm.git"
6−, "elm-version": "0.11"
6+, "elm-version": "0.12"
77, "dependencies": {}
88, "exposed-modules":
99 [ "Basics"
@@ -17,8 +17,8 @@
1717 , "Graphics.Element"
1818 , "Graphics.Collage"
1919 , "Graphics.Input"
20+ , "Graphics.Input.Field"
2021 , "Http"
21− , "JavaScript"
2222 , "JavaScript.Experimental"
2323 , "Json"
2424 , "Keyboard"
runtime/Render/Element.js+58−30
@@ -34,35 +34,59 @@ function setProps(elem, e) {
3434 e.appendChild(a);
3535 }
3636 if (props.hover.ctor !== '_Tuple0') {
37− e.style.pointerEvents = 'auto';
38− e.elm_hover_handler = 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− });
37+ addHover(e, props.hover);
5538 }
5639 if (props.click.ctor !== '_Tuple0') {
57− e.style.pointerEvents = 'auto';
58− e.elm_click_handler = props.click;
59− e.addEventListener('click', function() {
60− e.elm_click_handler(Tuple0);
61− });
40+ addClick(e, props.click);
6241 }
6342 return e;
6443}
6544
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+
6690function image(props, img) {
6791 switch (img._0.ctor) {
6892 case 'Plain': return plainImage(img._3);
@@ -331,7 +355,7 @@ function updateProps(node, curr, next) {
331355 if (height !== currP.height) {
332356 e.style.height = (height|0) + 'px';
333357 }
334− if (props.opacity !== 1 && props.opacity !== currP.opacity) {
358+ if (props.opacity !== currP.opacity) {
335359 e.style.opacity = props.opacity;
336360 }
337361 var nextColor = (props.color.ctor === 'Just' ?
@@ -358,17 +382,21 @@ function updateProps(node, curr, next) {
358382 }
359383
360384 // update hover handlers
361− if (props.hover.ctor !== '_Tuple0') {
362− e.elm_hover_handler = props.hover;
385+ if (props.hover.ctor === '_Tuple0') {
386+ removeHover(e);
363387 } 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);
365391 }
366392
367393 // update click handlers
368− if (props.click.ctor !== '_Tuple0') {
369− e.elm_click_handler = props.click;
394+ if (props.click.ctor === '_Tuple0') {
395+ removeClick(e);
370396 } 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);
372400 }
373401}
374402
server/LICENSE+1−1
@@ -1,4 +1,4 @@
1−Copyright (c)2012-2013, Evan Czaplicki
1+Copyright (c)2012-2014, Evan Czaplicki
22
33All rights reserved.
44
server/Server.hs+112−99
@@ -1,114 +1,127 @@
1+{-# OPTIONS_GHC -Wall #-}
2+{-# LANGUAGE OverloadedStrings, DeriveDataTypeable #-}
13module Main where
24
3−import Control.Monad (msum,guard,when)
5+import Control.Applicative ((<$>),(<|>))
6+import Control.Monad (guard)
47import Control.Monad.Trans (MonadIO(liftIO))
5−import Data.List (isPrefixOf, isSuffixOf, (\\))
6−import Data.Version (showVersion)
7−import Happstack.Server
8−import Happstack.Server.Compression
8+import qualified Data.ByteString as BS
9+import qualified Data.ByteString.Char8 as BSC
10+import qualified Data.HashMap.Strict as Map
11+import qualified Data.Version as Version
12+import System.Console.CmdArgs
913import System.Directory
10−import System.Environment
1114import System.Exit
1215import System.FilePath
1316import System.Process
14−import GHC.IO.Handle
15−import qualified Elm.Internal.Paths as ElmPaths
16−import Paths_elm_server
17−
18−runtime = "/elm-runtime.js"
19−
20−serve :: Int -> String -> IO ()
21−serve portNumber libLoc = do
22− putStrLn $ "Elm Server " ++ showVersion version ++
23− ": running at <http://localhost:" ++ show portNumber ++ ">"
24− putStrLn "Just refresh a page to recompile it!"
25− simpleHTTP httpConf $ do
26− _ <- compressedResponseFilter
27− msum [ uriRest serveElm
28− , uriRest (serveLib libLoc)
29− , serveDirectory EnableBrowsing [] "."
30− ]
31− where httpConf = nullConf { port = portNumber }
32−
33−pageTitle :: String -> String
34−pageTitle = dropExtension . takeBaseName
35−
36−serveElm :: FilePath -> ServerPartT IO Response
37−serveElm fp =
38− do fileExists <- liftIO $ doesFileExist file
39− guard (fileExists && takeExtension fp == ".elm")
40− onSuccess compile serve
17+import System.IO (hGetContents, Handle)
18+
19+import Paths_elm_server (version)
20+import qualified Elm.Internal.Paths as Elm
21+import Snap.Core
22+import Snap.Http.Server
23+import Snap.Util.FileServe
24+
25+data Flags = Flags
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
52+ putStrLn $ "Elm Server " ++ Version.showVersion version ++
53+ ": Just refresh a page to recompile it!"
54+ httpServe (setPort (port cargs) config) $
55+ serveRuntime (maybe Elm.runtime id (runtime cargs))
56+ <|> serveElm
57+ <|> serveDirectoryWith directoryConfig "."
58+
59+directoryConfig :: MonadSnap m => DirectoryConfig m
60+directoryConfig =
61+ fancyDirectoryConfig
62+ { indexGenerator = defaultIndexGenerator defaultMimeTypes indexStyle
63+ , mimeTypes = Map.insert ".elm" "text/html" defaultMimeTypes
64+ }
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+
89+serveElm :: Snap ()
90+serveElm =
91+ do file <- BSC.unpack . rqPathInfo <$> getRequest
92+ exists <- liftIO $ doesFileExist file
93+ guard (exists && takeExtension file == ".elm")
94+ onSuccess (compile file) (serve file)
4195 where
42− file = tail fp
96+ compile file =
97+ let elmArgs = [ "--make", "--runtime=" ++ runtimeName, file ]
98+ in createProcess $ (proc "elm" elmArgs) { std_out = CreatePipe }
4399
44− compile = liftIO $ createProcess $ (proc "elm" args) { std_out = CreatePipe }
45− where args = [ "--make", "--runtime=" ++ runtime, file ]
100+ serve file =
101+ serveFileAs "text/html; charset=UTF-8" ("build" </> replaceExtension file "html")
46102
47− serve = serveFile (asContentType "text/html")
48− ("build" </> replaceExtension file "html")
103+failure :: String -> Snap ()
104+failure msg =
105+ do modifyResponse $ setResponseStatus 404 "Not found"
106+ writeBS $ BSC.pack msg
49107
50−onSuccess action success = do
51− (_, stdout, _, handle) <- action
52− exitCode <- liftIO $ waitForProcess handle
53− case (exitCode, stdout) of
54− (ExitFailure 127, _) ->
55− badRequest $ toResponse "Error: elm binary 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
108+onSuccess :: IO (t, Maybe Handle, t1, ProcessHandle) -> Snap () -> Snap ()
109+onSuccess action success =
110+ do (_, stdout, _, handle) <- liftIO action
111+ exitCode <- liftIO $ waitForProcess handle
112+ case (exitCode, stdout) of
113+ (ExitFailure 127, _) ->
114+ failure "Error: elm compiler not found in your path."
62115
116+ (ExitFailure _, Just out) ->
117+ failure =<< liftIO (hGetContents out)
63118
64−serveLib :: FilePath -> String -> ServerPartT IO Response
65−serveLib libLoc fp = do
66− guard (fp == runtime)
67− serveFile (asContentType "application/javascript") libLoc
119+ (ExitFailure _, Nothing) ->
120+ failure "See command line for error message."
68121
69−main :: IO ()
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
122+ (ExitSuccess, _) -> success
80123
81− where
82− runtimeArg = filter (isPrefixOf "--runtime-location=") args
83− portArg = filter (isPrefixOf "--port=") args
84− remainingArgs = (args \\ runtimeArg) \\ portArg
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>"
124+{--
125+pageTitle :: String -> String
126+pageTitle = dropExtension . takeBaseName
127+--}
server/elm-server.cabal+14−13
@@ -1,7 +1,9 @@
11Name: elm-server
2−Version: 0.10.1
3−Synopsis: The Elm language server.
4−Description: This package provides a standalone, Happstack-based Elm server.
2+Version: 0.11
3+Synopsis: Server for developing Elm projects
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.
57
68Homepage: http://elm-lang.org
79
@@ -10,7 +12,7 @@ License-file: LICENSE
1012
1113Author: Evan Czaplicki
1214Maintainer: info@elm-lang.org
13−Copyright: Copyright: (c) 2011-2013 Evan Czaplicki
15+Copyright: Copyright: (c) 2011-2014 Evan Czaplicki
1416
1517Category: Compiler, Language
1618
@@ -26,15 +28,14 @@ source-repository head
2628Executable elm-server
2729 Main-is: Server.hs
2830 Build-depends: base >=4.2 && <5,
31+ bytestring,
32+ cmdargs,
2933 containers >= 0.3,
3034 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,
3835 filepath,
39− Elm >= 0.10.1,
40− process
36+ Elm >= 0.11,
37+ snap-core,
38+ snap-server,
39+ mtl,
40+ process,
41+ unordered-containers