diff --git a/.gitignore b/.gitignore index 7050558..332b6cf 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /bower_components/ /node_modules/ /output/ +package-lock.json diff --git a/LICENSE b/LICENSE index 58b0299..311379c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,20 +1,26 @@ -The MIT License (MIT) +Copyright 2018 PureScript -Copyright (c) 2014 PureScript +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/bower.json b/bower.json index 4a2a46b..60d8a13 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,6 @@ { "name": "purescript-foreign", "homepage": "https://github.com/purescript/purescript-foreign", - "description": "PureScript library for dealing with foreign data (JSON and JavaScript objects)", "authors": [ "Gary Burgess ", "Phil Freeman " @@ -10,7 +9,7 @@ "type": "git", "url": "git://github.com/purescript/purescript-foreign.git" }, - "license": "MIT", + "license": "BSD-3-Clause", "ignore": [ "**/.*", "bower_components", @@ -21,16 +20,17 @@ "package.json" ], "dependencies": { - "purescript-arrays": "^4.0.0", - "purescript-either": "^3.0.0", - "purescript-foldable-traversable": "^3.0.0", - "purescript-functions": "^3.0.0", - "purescript-integers": "^3.0.0", - "purescript-lists": "^4.0.0", - "purescript-strings": "^3.0.0", - "purescript-transformers": "^3.0.0" + "purescript-either": "^4.0.0", + "purescript-functions": "^4.0.0", + "purescript-identity": "^4.0.0", + "purescript-integers": "^4.0.0", + "purescript-lists": "^5.0.0", + "purescript-maybe": "^4.0.0", + "purescript-prelude": "^4.0.0", + "purescript-strings": "^4.0.0", + "purescript-transformers": "^4.0.0" }, "devDependencies": { - "purescript-console": "^3.0.0" + "purescript-console": "^4.0.0" } } diff --git a/examples/Applicative.purs b/examples/Applicative.purs index ed082b9..9f9f5c3 100755 --- a/examples/Applicative.purs +++ b/examples/Applicative.purs @@ -2,14 +2,12 @@ module Example.Applicative where import Prelude -import Control.Monad.Eff (Eff) -import Control.Monad.Eff.Console (CONSOLE, logShow) import Control.Monad.Except (runExcept) - -import Data.Foreign (F, Foreign, readNumber) -import Data.Foreign.Index ((!)) - +import Effect (Effect) +import Effect.Console (logShow) import Example.Util.Value (foreignValue) +import Foreign (F, Foreign, readNumber) +import Foreign.Index ((!)) data Point = Point Number Number Number @@ -23,7 +21,7 @@ readPoint value = do <*> (value ! "y" >>= readNumber) <*> (value ! "z" >>= readNumber) -main :: Eff (console :: CONSOLE) Unit +main :: Effect Unit main = logShow $ runExcept $ readPoint =<< foreignValue """{ "x": 1, "y": 2, "z": 3 }""" diff --git a/examples/Arrays.purs b/examples/Arrays.purs index 25bb108..86efd36 100644 --- a/examples/Arrays.purs +++ b/examples/Arrays.purs @@ -2,16 +2,14 @@ module Example.Arrays where import Prelude -import Control.Monad.Eff (Eff) -import Control.Monad.Eff.Console (CONSOLE, logShow) import Control.Monad.Except (runExcept) - -import Data.Foreign (readArray, readNumber, readString) import Data.Traversable (traverse) - +import Effect (Effect) +import Effect.Console (logShow) import Example.Util.Value (foreignValue) +import Foreign (readArray, readNumber, readString) -main :: Eff (console :: CONSOLE) Unit +main :: Effect Unit main = do logShow $ runExcept $ traverse readString =<< readArray =<< foreignValue """["hello", "world"]""" diff --git a/examples/Complex.purs b/examples/Complex.purs index 4093181..0a96a4d 100755 --- a/examples/Complex.purs +++ b/examples/Complex.purs @@ -2,32 +2,21 @@ module Example.Complex where import Prelude -import Control.Monad.Eff (Eff) -import Control.Monad.Eff.Console (CONSOLE, logShow) import Control.Monad.Except (runExcept) - -import Data.Foreign (F, Foreign, readArray, readBoolean, readNumber, readString, readNullOrUndefined) -import Data.Foreign.Index ((!)) -import Data.Traversable (traverse) import Data.Maybe (Maybe) - +import Data.Traversable (traverse) +import Effect (Effect) +import Effect.Console (logShow) import Example.Util.Value (foreignValue) +import Foreign (F, Foreign, readArray, readBoolean, readNumber, readString, readNullOrUndefined) +import Foreign.Index ((!)) -newtype SomeObject = - SomeObject - { foo :: String - , bar :: Boolean - , baz :: Number - , list :: Array ListItem - } - -instance showSomeObject :: Show SomeObject where - show (SomeObject o) = - "(SomeObject { foo: " <> show o.foo <> - ", bar: " <> show o.bar <> - ", baz: " <> show o.baz <> - ", list: " <> show o.list <> - "})" +type SomeObject = + { foo :: String + , bar :: Boolean + , baz :: Number + , list :: Array ListItem + } readSomeObject :: Foreign -> F SomeObject readSomeObject value = do @@ -35,30 +24,22 @@ readSomeObject value = do bar <- value ! "bar" >>= readBoolean baz <- value ! "baz" >>= readNumber list <- value ! "list" >>= readArray >>= traverse readListItem - pure $ SomeObject { foo, bar, baz, list } - -newtype ListItem = - ListItem - { x :: Number - , y :: Number - , z :: Maybe Number - } + pure { foo, bar, baz, list } -instance showListItem :: Show ListItem where - show (ListItem o) = - "(ListItem { x: " <> show o.x <> - ", y: " <> show o.y <> - ", z: " <> show o.z <> - " })" +type ListItem = + { x :: Number + , y :: Number + , z :: Maybe Number + } readListItem :: Foreign -> F ListItem readListItem value = do x <- value ! "x" >>= readNumber y <- value ! "y" >>= readNumber z <- value ! "z" >>= readNullOrUndefined >>= traverse readNumber - pure $ ListItem { x, y, z } + pure { x, y, z } -main :: Eff (console :: CONSOLE) Unit +main :: Effect Unit main = do let json = """{"foo":"hello","bar":true,"baz":1,"list":[{"x":1,"y":2},{"x":3,"y":4,"z":999}]}""" logShow $ runExcept $ readSomeObject =<< foreignValue json diff --git a/examples/MaybeNullable.purs b/examples/MaybeNullable.purs index d9bd790..1831663 100755 --- a/examples/MaybeNullable.purs +++ b/examples/MaybeNullable.purs @@ -2,18 +2,18 @@ module Example.MaybeNullable where import Prelude -import Control.Monad.Eff (Eff) -import Control.Monad.Eff.Console (CONSOLE, logShow) +import Effect (Effect) +import Effect.Console (logShow) import Control.Monad.Except (runExcept) -import Data.Foreign (readBoolean, readNull) +import Foreign (readBoolean, readNull) import Data.Traversable (traverse) import Example.Util.Value (foreignValue) -- Parsing values that are allowed to null or undefined is possible by -- using Maybe types. -main :: Eff (console :: CONSOLE) Unit +main :: Effect Unit main = do logShow $ runExcept $ traverse readBoolean =<< readNull =<< foreignValue "null" diff --git a/examples/Nested.purs b/examples/Nested.purs index 3a04216..bbcb3e4 100755 --- a/examples/Nested.purs +++ b/examples/Nested.purs @@ -2,14 +2,12 @@ module Example.Nested where import Prelude -import Control.Monad.Eff (Eff) -import Control.Monad.Eff.Console (CONSOLE, logShow) import Control.Monad.Except (runExcept) - -import Data.Foreign (F, Foreign, readNumber, readString) -import Data.Foreign.Index ((!)) - +import Effect (Effect) +import Effect.Console (logShow) import Example.Util.Value (foreignValue) +import Foreign (F, Foreign, readNumber, readString) +import Foreign.Index ((!)) data Foo = Foo Bar Baz @@ -32,7 +30,7 @@ readFoo value = do n <- value ! "foo" ! "baz" >>= readNumber pure $ Foo (Bar s) (Baz n) -main :: Eff (console :: CONSOLE) Unit +main :: Effect Unit main = logShow $ runExcept $ readFoo =<< foreignValue """{ "foo": { "bar": "bar", "baz": 1 } }""" diff --git a/examples/Objects.purs b/examples/Objects.purs index 0fa094e..3a9893b 100755 --- a/examples/Objects.purs +++ b/examples/Objects.purs @@ -2,28 +2,22 @@ module Example.Objects where import Prelude -import Control.Monad.Eff (Eff) -import Control.Monad.Eff.Console (CONSOLE, logShow) import Control.Monad.Except (runExcept) - -import Data.Foreign (F, Foreign, readNumber) -import Data.Foreign.Index ((!)) - +import Effect (Effect) +import Effect.Console (logShow) import Example.Util.Value (foreignValue) +import Foreign (F, Foreign, readNumber) +import Foreign.Index ((!)) -newtype Point = Point { x :: Number, y :: Number } - -instance showPoint :: Show Point where - show (Point { x, y }) = - "(Point { x: " <> show x <> ", y: " <> show y <> " })" +type Point = { x :: Number, y :: Number } readPoint :: Foreign -> F Point readPoint value = do x <- value ! "x" >>= readNumber y <- value ! "y" >>= readNumber - pure $ Point { x, y } + pure { x, y } -main :: Eff (console :: CONSOLE) Unit +main :: Effect Unit main = do logShow $ runExcept $ readPoint =<< foreignValue """{ "x": 1, "y": 2 }""" diff --git a/examples/ParseErrors.purs b/examples/ParseErrors.purs index a3418c9..52faf30 100755 --- a/examples/ParseErrors.purs +++ b/examples/ParseErrors.purs @@ -2,15 +2,13 @@ module Example.ParseErrors where import Prelude -import Control.Monad.Eff (Eff) -import Control.Monad.Eff.Console (CONSOLE, logShow) import Control.Monad.Except (runExcept) - -import Data.Foreign (F, Foreign, readArray, readBoolean, readNumber, readString) -import Data.Foreign.Index ((!)) import Data.Traversable (traverse) - +import Effect (Effect) +import Effect.Console (logShow) import Example.Util.Value (foreignValue) +import Foreign (F, Foreign, readArray, readBoolean, readNumber, readString) +import Foreign.Index ((!)) newtype Point = Point { x :: Number, y :: Number } @@ -23,7 +21,7 @@ readPoint value = do y <- value ! "y" >>= readNumber pure $ Point { x: x, y: y } -main :: Eff (console :: CONSOLE) Unit +main :: Effect Unit main = do -- When trying to parse invalid JSON we catch an exception from diff --git a/examples/SimpleTypes.purs b/examples/SimpleTypes.purs index 97233d7..e3ba48c 100644 --- a/examples/SimpleTypes.purs +++ b/examples/SimpleTypes.purs @@ -2,17 +2,15 @@ module Example.SimpleTypes where import Prelude -import Control.Monad.Eff (Eff) -import Control.Monad.Eff.Console (CONSOLE, logShow) import Control.Monad.Except (runExcept) - -import Data.Foreign (readString, readNumber, readBoolean) - +import Effect (Effect) +import Effect.Console (logShow) import Example.Util.Value (foreignValue) +import Foreign (readString, readNumber, readBoolean) -- Parsing of the simple JSON String, Number and Boolean types is provided -- out of the box. -main :: Eff (console :: CONSOLE) Unit +main :: Effect Unit main = do logShow $ runExcept $ readString =<< foreignValue "\"a JSON string\"" diff --git a/examples/Union.purs b/examples/Union.purs index ff9a56b..06504da 100755 --- a/examples/Union.purs +++ b/examples/Union.purs @@ -2,14 +2,12 @@ module Example.Union where import Prelude -import Control.Monad.Eff (Eff) -import Control.Monad.Eff.Console (CONSOLE, logShow) import Control.Monad.Except (runExcept) - -import Data.Foreign (F, Foreign, readBoolean, readString) -import Data.Foreign.Index ((!)) - +import Effect (Effect) +import Effect.Console (logShow) import Example.Util.Value (foreignValue) +import Foreign (F, Foreign, readBoolean, readString) +import Foreign.Index ((!)) data StringList = Nil | Cons String StringList @@ -28,7 +26,7 @@ readStringList value = <$> (value ! "head" >>= readString) <*> (value ! "tail" >>= readStringList) -main :: Eff (console :: CONSOLE) Unit +main :: Effect Unit main = do logShow $ runExcept $ diff --git a/examples/Util/Value.purs b/examples/Util/Value.purs index bc6516e..50f7b8f 100644 --- a/examples/Util/Value.purs +++ b/examples/Util/Value.purs @@ -4,9 +4,9 @@ import Prelude import Data.Function.Uncurried (Fn3, runFn3) -import Data.Foreign (F, Foreign, ForeignError(..), fail) +import Foreign (F, Foreign, ForeignError(..), fail) foreign import foreignValueImpl :: forall r. Fn3 (String -> r) (Foreign -> r) String r foreignValue :: String -> F Foreign -foreignValue json = runFn3 foreignValueImpl (fail <<< JSONError) pure json +foreignValue json = runFn3 foreignValueImpl (fail <<< ForeignError) pure json diff --git a/package.json b/package.json index e499ea4..f517f7c 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,9 @@ "test": "pulp build -I examples -- --censor-lib --strict" }, "devDependencies": { - "eslint": "^3.17.1", - "pulp": "^10.0.4", - "purescript-psa": "^0.5.0-rc.1", - "rimraf": "^2.6.1" + "eslint": "^4.19.1", + "pulp": "^12.2.0", + "purescript-psa": "^0.6.0", + "rimraf": "^2.6.2" } } diff --git a/src/Data/Foreign.js b/src/Foreign.js similarity index 92% rename from src/Data/Foreign.js rename to src/Foreign.js index e511096..cb96c82 100644 --- a/src/Data/Foreign.js +++ b/src/Foreign.js @@ -1,6 +1,6 @@ "use strict"; -exports.toForeign = function (value) { +exports.unsafeToForeign = function (value) { return value; }; diff --git a/src/Data/Foreign.purs b/src/Foreign.purs similarity index 90% rename from src/Data/Foreign.purs rename to src/Foreign.purs index a7ea0df..2752c6e 100644 --- a/src/Data/Foreign.purs +++ b/src/Foreign.purs @@ -1,13 +1,13 @@ -- | This module defines types and functions for working with _foreign_ -- | data. -module Data.Foreign +module Foreign ( Foreign , ForeignError(..) , MultipleErrors(..) , F , renderForeignError - , toForeign + , unsafeToForeign , unsafeFromForeign , unsafeReadTagged , typeOf @@ -36,7 +36,7 @@ import Data.Int as Int import Data.List.NonEmpty (NonEmptyList) import Data.List.NonEmpty as NEL import Data.Maybe (Maybe(..), maybe) -import Data.String (toChar) +import Data.String.CodeUnits (toChar) -- | A type for _foreign data_. -- | @@ -56,7 +56,6 @@ data ForeignError | TypeMismatch String String | ErrorAtIndex Int ForeignError | ErrorAtProperty String ForeignError - | JSONError String derive instance eqForeignError :: Eq ForeignError derive instance ordForeignError :: Ord ForeignError @@ -65,7 +64,6 @@ instance showForeignError :: Show ForeignError where show (ForeignError msg) = "(ForeignError " <> show msg <> ")" show (ErrorAtIndex i e) = "(ErrorAtIndex " <> show i <> " " <> show e <> ")" show (ErrorAtProperty prop e) = "(ErrorAtProperty " <> show prop <> " " <> show e <> ")" - show (JSONError s) = "(JSONError " <> show s <> ")" show (TypeMismatch exps act) = "(TypeMismatch " <> show exps <> " " <> show act <> ")" -- | A type for accumulating multiple `ForeignError`s. @@ -73,9 +71,8 @@ type MultipleErrors = NonEmptyList ForeignError renderForeignError :: ForeignError -> String renderForeignError (ForeignError msg) = msg -renderForeignError (ErrorAtIndex i e) = "Error at array index " <> show i <> ": " <> show e -renderForeignError (ErrorAtProperty prop e) = "Error at property " <> show prop <> ": " <> show e -renderForeignError (JSONError s) = "JSON error: " <> s +renderForeignError (ErrorAtIndex i e) = "Error at array index " <> show i <> ": " <> renderForeignError e +renderForeignError (ErrorAtProperty prop e) = "Error at property " <> show prop <> ": " <> renderForeignError e renderForeignError (TypeMismatch exp act) = "Type mismatch: expected " <> exp <> ", found " <> act -- | An error monad, used in this library to encode possible failures when @@ -86,7 +83,12 @@ renderForeignError (TypeMismatch exp act) = "Type mismatch: expected " <> exp <> type F = Except MultipleErrors -- | Coerce any value to the a `Foreign` value. -foreign import toForeign :: forall a. a -> Foreign +-- | +-- | This is considered unsafe as it's only intended to be used on primitive +-- | JavaScript types, rather than PureScript types. Exporting PureScript values +-- | via the FFI can be dangerous as they can be mutated by code outside the +-- | PureScript program, resulting in difficult to diagnose problems elsewhere. +foreign import unsafeToForeign :: forall a. a -> Foreign -- | Unsafely coerce a `Foreign` value. foreign import unsafeFromForeign :: forall a. Foreign -> a diff --git a/src/Data/Foreign/Index.js b/src/Foreign/Index.js similarity index 100% rename from src/Data/Foreign/Index.js rename to src/Foreign/Index.js diff --git a/src/Data/Foreign/Index.purs b/src/Foreign/Index.purs similarity index 95% rename from src/Data/Foreign/Index.purs rename to src/Foreign/Index.purs index 71afb61..405e72f 100644 --- a/src/Data/Foreign/Index.purs +++ b/src/Foreign/Index.purs @@ -1,7 +1,7 @@ -- | This module defines a type class for types which act like -- | _property indices_. -module Data.Foreign.Index +module Foreign.Index ( class Index , class Indexable , readProp @@ -17,7 +17,7 @@ import Prelude import Control.Monad.Except.Trans (ExceptT) -import Data.Foreign (Foreign, F, ForeignError(..), typeOf, isUndefined, isNull, fail) +import Foreign (Foreign, F, ForeignError(..), typeOf, isUndefined, isNull, fail) import Data.Function.Uncurried (Fn2, runFn2, Fn4, runFn4) import Data.Identity (Identity) import Data.List.NonEmpty (NonEmptyList) diff --git a/src/Data/Foreign/Keys.js b/src/Foreign/Keys.js similarity index 100% rename from src/Data/Foreign/Keys.js rename to src/Foreign/Keys.js diff --git a/src/Data/Foreign/Keys.purs b/src/Foreign/Keys.purs similarity index 82% rename from src/Data/Foreign/Keys.purs rename to src/Foreign/Keys.purs index 4bb9967..c600be1 100644 --- a/src/Data/Foreign/Keys.purs +++ b/src/Foreign/Keys.purs @@ -1,13 +1,13 @@ -- | This module provides functions for working with object properties -- | of Javascript objects. -module Data.Foreign.Keys +module Foreign.Keys ( keys ) where import Prelude -import Data.Foreign (F, Foreign, ForeignError(..), typeOf, isUndefined, isNull, fail) +import Foreign (F, Foreign, ForeignError(..), typeOf, isUndefined, isNull, fail) foreign import unsafeKeys :: Foreign -> Array String