Skip to content

Commit c9febf5

Browse files
authored
Merge pull request #4 from purescript/updates
Various updates
2 parents b06c9d5 + cffa6e6 commit c9febf5

File tree

9 files changed

+136
-38
lines changed

9 files changed

+136
-38
lines changed

.tidyrc.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
{
2+
"importSort": "ide",
3+
"importWrap": "source",
24
"indent": 2,
35
"operatorsFile": null,
46
"ribbon": 1,

src/JSON.purs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ import Prelude
2727

2828
import Data.Either (Either(..))
2929
import Data.Function.Uncurried (runFn2, runFn3, runFn7)
30-
import Data.Maybe (Maybe(..))
3130
import Data.Int as Int
32-
import JSON.Internal (JArray, JObject, JSON) as Exports
31+
import Data.Maybe (Maybe(..))
3332
import JSON.Internal (JArray, JObject, JSON)
33+
import JSON.Internal (JArray, JObject, JSON) as Exports
3434
import JSON.Internal as Internal
3535

3636
-- | Attempts to parse a string as a JSON value. If parsing fails, an error message detailing the
@@ -122,7 +122,7 @@ toNumber :: JSON -> Maybe Number
122122
toNumber json = runFn7 Internal._case fail fail Just fail fail fail json
123123

124124
-- | Converts a `JSON` `Number` into an `Int`.
125-
-- |
125+
-- |
126126
-- | This is provided for convenience only.
127127
toInt :: JSON -> Maybe Int
128128
toInt = toNumber >=> Int.fromNumber

src/JSON/Array.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const singleton = (x) => [x];

src/JSON/Array.purs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
module JSON.Array
22
( fromFoldable
3-
, empty
43
, singleton
54
, index
65
, toUnfoldable
@@ -9,26 +8,22 @@ module JSON.Array
98

109
import Data.Array as Array
1110
import Data.Foldable (class Foldable)
12-
import Data.Maybe (Maybe)
11+
import Data.Function.Uncurried (runFn4)
12+
import Data.Maybe (Maybe(..))
1313
import Data.Unfoldable (class Unfoldable)
14-
import JSON.Internal (JArray, JSON, toArray, fromArray)
15-
import JSON.Internal (JArray, toArray, fromArray) as Exports
14+
import JSON.Internal (JArray, JSON, _index, fromArray, toArray)
15+
import JSON.Internal (JArray, empty, fromArray, length, toArray) as Exports
1616

1717
-- | Creates a `JArray` from a `Foldable` source of `JSON`.
1818
fromFoldable :: forall f. Foldable f => f JSON -> JArray
1919
fromFoldable js = fromArray (Array.fromFoldable js)
2020

21-
-- | An empty `JArray`.
22-
empty :: JArray
23-
empty = fromArray []
24-
2521
-- | Creates a `JArray` with a single entry.
26-
singleton :: JSON -> JArray
27-
singleton j = fromArray [ j ]
22+
foreign import singleton :: JSON -> JArray
2823

2924
-- | Attempts to read a value from the specified index of a `JArray`.
30-
index :: JArray -> Int -> Maybe JSON
31-
index js = Array.index (toArray js)
25+
index :: Int -> JArray -> Maybe JSON
26+
index ix arr = runFn4 _index Nothing Just ix arr
3227

3328
-- | Unfolds a `JArray` into `JSON` items
3429
toUnfoldable :: forall f. Unfoldable f => JArray -> f JSON

src/JSON/Internal.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,12 @@ export const _entries = (tuple, obj) =>
4848

4949
export const _lookup = (nothing, just, key, obj) =>
5050
hasOwnProperty.call(obj, key) ? just(obj[key]) : nothing;
51+
52+
export const empty = [];
53+
54+
export const length = (arr) => arr.length;
55+
56+
export const _index = (nothing, just, ix, arr) =>
57+
ix >= 0 && ix < arr.length ? just(arr[ix]) : nothing;
58+
59+
export const _append = (xs, ys) => xs.concat(ys);

src/JSON/Internal.purs

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ module JSON.Internal where
22

33
import Prelude
44

5-
import Data.Either (Either)
65
import Data.Function.Uncurried (Fn2, Fn3, Fn4, Fn7, runFn2, runFn7)
7-
import Data.Maybe (Maybe)
86
import Data.Tuple (Tuple(..))
97

108
-- | A type that represents all varieties of JSON value.
@@ -54,17 +52,22 @@ foreign import toArray :: JArray -> Array JSON
5452
-- | Converts an `Array` of `JSON` values into a `JArray`.
5553
foreign import fromArray :: Array JSON -> JArray
5654

55+
-- | An empty `JArray`.
56+
foreign import empty :: JArray
57+
5758
instance Eq JArray where
58-
eq x y = eq (toArray x) (toArray y)
59+
eq xs ys
60+
| length xs == length ys = eq (toArray xs) (toArray ys)
61+
| otherwise = false
5962

6063
instance Ord JArray where
6164
compare x y = compare (toArray x) (toArray y)
6265

6366
instance Semigroup JArray where
64-
append x y = fromArray (append (toArray x) (toArray y))
67+
append xs ys = runFn2 _append xs ys
6568

6669
instance Monoid JArray where
67-
mempty = fromArray []
70+
mempty = empty
6871

6972
-- | A type that represents JSON objects. Similar to the JSON type, this is not a PureScript type,
7073
-- | but represents the underlying representation for JSON objects.
@@ -77,11 +80,12 @@ instance Ord JObject where
7780
compare x y = compare (runFn2 _entries Tuple x) (runFn2 _entries Tuple y)
7881

7982
foreign import _parse
80-
:: Fn3
81-
(forall a b. a -> Either a b)
82-
(forall a b. b -> Either a b)
83+
:: forall f
84+
. Fn3
85+
(forall a b. a -> f a b)
86+
(forall a b. b -> f a b)
8387
String
84-
(Either String JSON)
88+
(f String JSON)
8589

8690
foreign import _fromNumberWithDefault :: Fn2 Int Number JSON
8791

@@ -102,18 +106,37 @@ foreign import _insert :: Fn3 String JSON JObject JObject
102106
foreign import _delete :: Fn2 String JObject JObject
103107

104108
foreign import _fromEntries
105-
:: Fn3
106-
(forall x y. Tuple x y -> x)
107-
(forall x y. Tuple x y -> y)
108-
(Prim.Array (Tuple String JSON))
109+
:: forall f
110+
. Fn3
111+
(forall x y. f x y -> x)
112+
(forall x y. f x y -> y)
113+
(Prim.Array (f String JSON))
109114
JObject
110115

111116
foreign import _entries :: forall c. Fn2 (String -> JSON -> c) JObject (Prim.Array c)
112117

113118
foreign import _lookup
114-
:: Fn4
115-
(forall a. Maybe a)
116-
(forall a. a -> Maybe a)
119+
:: forall f
120+
. Fn4
121+
(forall a. f a)
122+
(forall a. a -> f a)
117123
String
118124
JObject
119-
(Maybe JSON)
125+
(f JSON)
126+
127+
foreign import _index
128+
:: forall f
129+
. Fn4
130+
(forall a. f a)
131+
(forall a. a -> f a)
132+
Int
133+
JArray
134+
(f JSON)
135+
136+
foreign import length :: JArray -> Int
137+
138+
foreign import _append
139+
:: Fn2
140+
JArray
141+
JArray
142+
JArray

src/JSON/Object.purs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import Data.Function.Uncurried (runFn2, runFn3, runFn4)
2121
import Data.Maybe (Maybe(..))
2222
import Data.Tuple (Tuple(..), fst, snd)
2323
import Data.Unfoldable (class Unfoldable)
24-
import JSON.Internal (JSON, JObject, _delete, _entries, _fromEntries, _insert, _lookup)
2524
import JSON.Internal (JObject) as Exports
25+
import JSON.Internal (JObject, JSON, _delete, _entries, _fromEntries, _insert, _lookup)
2626

2727
-- | Creates an `JObject` from an array of key/value pairs.
2828
fromEntries :: Array (Tuple String JSON) -> JObject

src/JSON/Path.purs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
module JSON.Path where
2+
3+
import Prelude
4+
5+
import Data.Maybe (Maybe(..))
6+
import JSON (JSON)
7+
import JSON as JSON
8+
import JSON.Array as JArray
9+
import JSON.Object as JObject
10+
11+
data Path
12+
= Top
13+
| AtKey String Path
14+
| AtIndex Int Path
15+
16+
derive instance Eq Path
17+
derive instance Ord Path
18+
19+
instance Show Path where
20+
show = case _ of
21+
Top -> "Top"
22+
AtKey key rest -> "(AtKey " <> show key <> " " <> show rest <> ")"
23+
AtIndex ix rest -> "(AtIndex " <> show ix <> " " <> show rest <> ")"
24+
25+
get :: Path -> JSON -> Maybe JSON
26+
get path json =
27+
case path of
28+
Top -> Just json
29+
AtKey key rest -> JObject.lookup key =<< JSON.toJObject =<< get rest json
30+
AtIndex ix rest -> JArray.index ix =<< JSON.toJArray =<< get rest json
31+
32+
print :: Path -> String
33+
print path = "$" <> go path ""
34+
where
35+
go :: Path -> String -> String
36+
go p acc = case p of
37+
Top -> acc
38+
AtKey k rest -> go rest ("." <> k <> acc)
39+
AtIndex ix rest -> go rest ("[" <> show ix <> "]" <> acc)

test/Main.purs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ module Test.Main where
22

33
import Prelude
44

5+
import Data.Maybe (Maybe(..))
56
import Data.Tuple (Tuple(..))
67
import Effect (Effect)
78
import Effect.Console (log)
89
import JSON as J
910
import JSON.Array as JA
1011
import JSON.Object as JO
11-
import Test.Assert (assertTrue)
12+
import JSON.Path as Path
13+
import Test.Assert (assertEqual, assertTrue)
1214

1315
main :: Effect Unit
1416
main = do
@@ -25,10 +27,37 @@ main = do
2527

2628
log "Check array comparisons"
2729
assertTrue $ J.fromJArray (JA.fromArray []) == J.fromJArray (JA.fromArray [])
28-
assertTrue $ J.fromJArray (JA.fromArray [J.fromInt 1]) == J.fromJArray (JA.fromArray [J.fromInt 1])
29-
assertTrue $ J.fromJArray (JA.fromArray [J.fromInt 1]) < J.fromJArray (JA.fromArray [J.fromInt 2])
30+
assertTrue $ J.fromJArray (JA.fromArray [ J.fromInt 1 ]) == J.fromJArray (JA.fromArray [ J.fromInt 1 ])
31+
assertTrue $ J.fromJArray (JA.fromArray [ J.fromInt 1 ]) < J.fromJArray (JA.fromArray [ J.fromInt 2 ])
3032

3133
log "Check object comparisons"
3234
assertTrue $ JO.empty == JO.empty
33-
assertTrue $ J.fromJObject (JO.fromEntries [Tuple "a" (J.fromInt 1)]) == J.fromJObject (JO.fromEntries [Tuple "a" (J.fromInt 1)])
34-
assertTrue $ J.fromJObject (JO.fromEntries [Tuple "a" (J.fromInt 1)]) < J.fromJObject (JO.fromEntries [Tuple "a" (J.fromInt 2)])
35+
assertTrue $ J.fromJObject (JO.fromEntries [ Tuple "a" (J.fromInt 1) ]) == J.fromJObject (JO.fromEntries [ Tuple "a" (J.fromInt 1) ])
36+
assertTrue $ J.fromJObject (JO.fromEntries [ Tuple "a" (J.fromInt 1) ]) < J.fromJObject (JO.fromEntries [ Tuple "a" (J.fromInt 2) ])
37+
38+
log "Check array index"
39+
assertTrue $ JA.index (-1) (JA.fromArray (J.fromInt <$> [ 0, 2, 4 ])) == Nothing
40+
assertTrue $ JA.index 0 (JA.fromArray (J.fromInt <$> [ 0, 2, 4 ])) == Just (J.fromInt 0)
41+
assertTrue $ JA.index 1 (JA.fromArray (J.fromInt <$> [ 0, 2, 4 ])) == Just (J.fromInt 2)
42+
assertTrue $ JA.index 2 (JA.fromArray (J.fromInt <$> [ 0, 2, 4 ])) == Just (J.fromInt 4)
43+
assertTrue $ JA.index 3 (JA.fromArray (J.fromInt <$> [ 0, 2, 4 ])) == Nothing
44+
45+
log "Check array concat"
46+
assertTrue $ JA.fromArray (J.fromInt <$> [ 1, 2 ]) <> JA.fromArray (J.fromInt <$> [ 2, 3 ]) == JA.fromArray (J.fromInt <$> [ 1, 2, 2, 3 ])
47+
48+
log "Check path printing"
49+
assertEqual
50+
{ expected: "$.data[0].field"
51+
, actual: Path.print (Path.AtKey "field" (Path.AtIndex 0 (Path.AtKey "data" Path.Top)))
52+
}
53+
54+
log "Check path get"
55+
assertTrue $ Path.get Path.Top (J.fromString "hello") == Just (J.fromString "hello")
56+
assertTrue $ Path.get Path.Top (J.fromJArray (JA.fromArray [ J.fromInt 42 ])) == Just (J.fromJArray (JA.fromArray [ J.fromInt 42 ]))
57+
assertTrue $ Path.get (Path.AtIndex 0 Path.Top) (J.fromJArray (JA.fromArray [ J.fromInt 42, J.fromString "X", J.fromBoolean true ])) == Just (J.fromInt 42)
58+
assertTrue $ Path.get (Path.AtIndex 1 Path.Top) (J.fromJArray (JA.fromArray [ J.fromInt 42, J.fromString "X", J.fromBoolean true ])) == Just (J.fromString "X")
59+
assertTrue $ Path.get (Path.AtIndex 5 Path.Top) (J.fromJArray (JA.fromArray [ J.fromInt 42, J.fromString "X", J.fromBoolean true ])) == Nothing
60+
assertTrue $ Path.get (Path.AtKey "a" Path.Top) (J.fromJObject (JO.fromEntries [ Tuple "a" (J.fromInt 1), Tuple "x" (J.fromBoolean false) ])) == Just (J.fromInt 1)
61+
assertTrue $ Path.get (Path.AtKey "x" Path.Top) (J.fromJObject (JO.fromEntries [ Tuple "a" (J.fromInt 1), Tuple "x" (J.fromBoolean false) ])) == Just (J.fromBoolean false)
62+
assertTrue $ Path.get (Path.AtKey "z" Path.Top) (J.fromJObject (JO.fromEntries [ Tuple "a" (J.fromInt 1), Tuple "x" (J.fromBoolean false) ])) == Nothing
63+
assertTrue $ Path.get (Path.AtKey "x" (Path.AtIndex 1 Path.Top)) (J.fromJArray (JA.fromArray [ J.fromString "skip", (J.fromJObject (JO.fromEntries [ Tuple "a" (J.fromInt 1), Tuple "x" (J.fromBoolean false) ])) ])) == Just (J.fromBoolean false)

0 commit comments

Comments
 (0)