Skip to content

Commit 7f4e6de

Browse files
committed
Introduce JArray, rename Object to JObject.
1 parent b2b19cf commit 7f4e6de

File tree

10 files changed

+172
-95
lines changed

10 files changed

+172
-95
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
[![Build status](https://github.com/purescript/purescript-json/workflows/CI/badge.svg?branch=master)](https://github.com/purescript/purescript-json/actions?query=workflow%3ACI+branch%3Amaster)
44

5-
Standard types for JSON and JSON objects, and basic operations for working with them.
5+
Standard types and basic operations for working with JSON.
66

77
For efficiency and performance reasons this library provides an interface for working with JSON without using PureScript ADTs, and instead operates on the underlying representation.
88

99
## Differences from Argonaut
1010

11-
This library is similar to the traditionally used `argonaut-core` library, but has been implemented with an eye to making it backend agnostic. As such, it does not use `Foreign.Object` as the representation for JSON objects, and instead provides its own type.
11+
This library is similar to the traditionally used `argonaut-core` library, but has been implemented with an eye to making it backend agnostic. As such, it does not use `Foreign.Object` as the representation for JSON objects, does not use `Array JSON`, and instead provides its own `JObject` and `JArray` types.

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
"private": true,
33
"scripts": {
44
"clean": "rimraf output && rimraf .pulp-cache",
5-
"build": "eslint src && purs-tidy check --config-require src/**/*.purs && pulp build -- --censor-lib --strict"
5+
"build": "eslint src && purs-tidy check --config-require src/**/*.purs && pulp build -- --censor-lib --strict",
6+
"test": "pulp test"
67
},
78
"devDependencies": {
8-
"eslint": "^8.25.0",
9+
"eslint": "^8.40.0",
910
"pulp": "^16.0.2",
1011
"purescript-psa": "^0.8.2",
11-
"purs-tidy": "^0.9.2",
12-
"rimraf": "^3.0.2"
12+
"purs-tidy": "^0.9.3",
13+
"rimraf": "^5.0.0"
1314
}
1415
}

src/JSON.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ export const fromInt = coerce;
88

99
export const fromString = coerce;
1010

11-
export const fromArray = coerce;
11+
export const fromJArray = coerce;
1212

13-
export const fromObject = coerce;
13+
export const fromJObject = coerce;
1414

1515
export const print = (j) => JSON.stringify(j);
1616

src/JSON.purs

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,65 +2,69 @@ module JSON
22
( parse
33
, null
44
, fromBoolean
5-
, fromNumberWithDefault
65
, fromNumber
6+
, fromNumberWithDefault
77
, fromInt
88
, fromString
99
, fromArray
10-
, fromObject
10+
, fromJArray
11+
, fromJObject
1112
, case_
1213
, toNull
1314
, toBoolean
1415
, toNumber
1516
, toString
1617
, toArray
17-
, toObject
18+
, toJArray
19+
, toJObject
1820
, print
1921
, printIndented
20-
, module Internal
22+
, module Exports
2123
) where
2224

2325
import Prelude
2426

2527
import Data.Either (Either(..))
2628
import Data.Function.Uncurried (runFn2, runFn3, runFn7)
2729
import Data.Maybe (Maybe(..))
28-
import JSON.Internal (JSON) as Internal
29-
import JSON.Internal (JSON, Object, _case, _fromNumberWithDefault, _parse)
30+
import JSON.Internal (JArray, JObject, JSON) as Exports
31+
import JSON.Internal (JArray, JObject, JSON)
32+
import JSON.Internal as Internal
3033

3134
-- | Attempts to parse a string as a JSON value. If parsing fails, an error message detailing the
3235
-- | cause may be returned in the `Left` of the result.
3336
parse :: String -> Either String JSON
34-
parse j = runFn3 _parse Left Right j
37+
parse j = runFn3 Internal._parse Left Right j
3538

3639
-- | The JSON `null` value.
3740
null :: JSON
3841
null = _null
3942

43+
-- | The JSON `null` value.
4044
foreign import _null :: JSON
4145

42-
-- | Creates a `JSON` value from a `Boolean`.
46+
-- | Converts a `Boolean` into `JSON`.
4347
foreign import fromBoolean :: Boolean -> JSON
4448

45-
-- | Creates a `JSON` value from a `Number`, using a fallback `Int` value for cases where the
46-
-- | PureScript number value is not valid for JSON.
47-
fromNumberWithDefault :: Int -> Number -> JSON
48-
fromNumberWithDefault fallback n = runFn2 _fromNumberWithDefault fallback n
49-
50-
-- | Creates a `JSON` value from a `Number`.
49+
-- | Converts a `Number` into `JSON`.
5150
-- |
5251
-- | The PureScript `Number` type admits infinities and a `NaN` value which are not allowed in JSON,
5352
-- | so when encountered, this function will treat those values as 0.
5453
fromNumber :: Number -> JSON
55-
fromNumber n = runFn2 _fromNumberWithDefault 0 n
54+
fromNumber n = runFn2 Internal._fromNumberWithDefault 0 n
5655

57-
-- | Creates a `JSON` value from an `Int`.
56+
-- | Creates a `Number` into `JSON`, using a fallback `Int` value for cases where the
57+
-- | PureScript number value is not valid for JSON (`NaN`, `infinity`).
58+
fromNumberWithDefault :: Int -> Number -> JSON
59+
fromNumberWithDefault fallback n = runFn2 Internal._fromNumberWithDefault fallback n
60+
61+
-- | Converts an `Int` into `JSON`.
5862
-- |
5963
-- | There is no corresponding `toInt` as JSON doesn't have a concept of integers - this is provided
6064
-- | as a convenience to avoid having to convert `Int` to `Number` before creating a `JSON` value.
6165
foreign import fromInt :: Int -> JSON
6266

63-
-- | Creates a `JSON` value from a `String`.
67+
-- | Converts a `String` into `JSON`.
6468
-- |
6569
-- | **Note**: this does not parse a string as a JSON value, it takes a PureScript string and
6670
-- | produces the corresponding `JSON` value for that string, similar to the other functions like
@@ -70,59 +74,69 @@ foreign import fromInt :: Int -> JSON
7074
-- | [`parse`](#v:parse).
7175
foreign import fromString :: String -> JSON
7276

73-
-- | Creates a `JSON` value from an array of `JSON` values.
74-
foreign import fromArray :: Array JSON -> JSON
77+
-- | Converts a `JArray` into `JSON`.
78+
foreign import fromJArray :: JArray -> JSON
79+
80+
-- | Converts an array of `JSON` values into `JSON`.
81+
fromArray :: Array JSON -> JSON
82+
fromArray js = fromJArray (Internal.fromArray js)
7583

76-
-- | Creates a `JSON` value from an `Object`.
77-
foreign import fromObject :: Object -> JSON
84+
-- | Converts a `JObject` into `JSON`.
85+
foreign import fromJObject :: JObject -> JSON
7886

7987
-- | Performs case analysis on a JSON value.
8088
-- |
8189
-- | As the `JSON` type is not a PureScript sum type, pattern matching cannot be used to
8290
-- | discriminate between the potential varieties of value. This function provides an equivalent
8391
-- | mechanism by accepting functions that deal with each variety, similar to an exaustive `case`
8492
-- | statement.
93+
-- |
94+
-- | The `Unit` case is for `null` values.
8595
case_
8696
:: forall a
8797
. (Unit -> a)
8898
-> (Boolean -> a)
8999
-> (Number -> a)
90100
-> (String -> a)
91-
-> (Array JSON -> a)
92-
-> (Object -> a)
101+
-> (JArray -> a)
102+
-> (JObject -> a)
93103
-> JSON
94104
-> a
95-
case_ a b c d e f json = runFn7 _case a b c d e f json
105+
case_ a b c d e f json = runFn7 Internal._case a b c d e f json
96106

97107
fail :: forall a b. a -> Maybe b
98108
fail _ = Nothing
99109

100110
-- | Converts a `JSON` value to `Null` if the `JSON` is `null`.
101111
toNull :: JSON -> Maybe Unit
102-
toNull json = runFn7 _case Just fail fail fail fail fail json
112+
toNull json = runFn7 Internal._case Just fail fail fail fail fail json
103113

104114
-- | Converts a `JSON` value to `Boolean` if the `JSON` is a boolean.
105115
toBoolean :: JSON -> Maybe Boolean
106-
toBoolean json = runFn7 _case fail Just fail fail fail fail json
116+
toBoolean json = runFn7 Internal._case fail Just fail fail fail fail json
107117

108118
-- | Converts a `JSON` value to `Number` if the `JSON` is a number.
109119
toNumber :: JSON -> Maybe Number
110-
toNumber json = runFn7 _case fail fail Just fail fail fail json
120+
toNumber json = runFn7 Internal._case fail fail Just fail fail fail json
111121

112122
-- | Converts a `JSON` value to `String` if the `JSON` is a string.
113123
toString :: JSON -> Maybe String
114-
toString json = runFn7 _case fail fail fail Just fail fail json
124+
toString json = runFn7 Internal._case fail fail fail Just fail fail json
125+
126+
-- | Converts a `JSON` value to `JArray` if the `JSON` is an array.
127+
toJArray :: JSON -> Maybe JArray
128+
toJArray json = runFn7 Internal._case fail fail fail fail Just fail json
115129

116130
-- | Converts a `JSON` value to `Array JSON` if the `JSON` is an array.
117131
toArray :: JSON -> Maybe (Array JSON)
118-
toArray json = runFn7 _case fail fail fail fail Just fail json
132+
toArray json = Internal.toArray <$> toJArray json
119133

120134
-- | Converts a `JSON` value to `Object` if the `JSON` is an object.
121-
toObject :: JSON -> Maybe Object
122-
toObject json = runFn7 _case fail fail fail fail fail Just json
135+
toJObject :: JSON -> Maybe JObject
136+
toJObject json = runFn7 Internal._case fail fail fail fail fail Just json
123137

124138
-- | Prints a JSON value as a compact (single line) string.
125139
foreign import print :: JSON -> String
126140

127-
-- | Prints a JSON value as a "pretty" string,
141+
-- | Prints a JSON value as a "pretty" string with newlines and indentation.
128142
foreign import printIndented :: JSON -> String

src/JSON/Array.purs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module JSON.Array
2+
( fromFoldable
3+
, empty
4+
, singleton
5+
, index
6+
, toUnfoldable
7+
, module Exports
8+
) where
9+
10+
import Data.Array as Array
11+
import Data.Foldable (class Foldable)
12+
import Data.Maybe (Maybe)
13+
import Data.Unfoldable (class Unfoldable)
14+
import JSON.Internal (JArray, JSON, toArray, fromArray)
15+
import JSON.Internal (JArray, toArray, fromArray) as Exports
16+
17+
-- | Creates a `JArray` from a `Foldable` source of `JSON`.
18+
fromFoldable :: forall f. Foldable f => f JSON -> JArray
19+
fromFoldable js = fromArray (Array.fromFoldable js)
20+
21+
-- | An empty `JArray`.
22+
empty :: JArray
23+
empty = fromArray []
24+
25+
-- | Creates a `JArray` with a single entry.
26+
singleton :: JSON -> JArray
27+
singleton j = fromArray [ j ]
28+
29+
-- | 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)
32+
33+
-- | Unfolds a `JArray` into `JSON` items
34+
toUnfoldable :: forall f. Unfoldable f => JArray -> f JSON
35+
toUnfoldable js = Array.toUnfoldable (toArray js)

src/JSON/Gen.purs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import Data.NonEmpty ((:|))
1010
import Data.String.Gen (genUnicodeString)
1111
import Data.Tuple (Tuple(..))
1212
import JSON as J
13-
import JSON.Object as Object
13+
import JSON.Array as JArray
14+
import JSON.Object as JObject
1415

1516
-- | A generator for random `JSON` values of any variety.
1617
genJSON :: forall m. MonadGen m => MonadRec m => Lazy (m J.JSON) => m J.JSON
@@ -23,15 +24,15 @@ genJSON = Gen.resize (min 5) $ Gen.sized genJSON'
2324

2425
-- | A generator for JSON arrays containing items based on the passed generator.
2526
genArrayOf :: forall m. MonadGen m => MonadRec m => m J.JSON -> m J.JSON
26-
genArrayOf inner = J.fromArray <$> Gen.unfoldable inner
27+
genArrayOf inner = J.fromJArray <<< JArray.fromArray <$> Gen.unfoldable inner
2728

2829
-- | A generator for JSON arrays containing random items.
2930
genArray :: forall m. MonadGen m => MonadRec m => Lazy (m J.JSON) => m J.JSON
3031
genArray = genArrayOf (defer \_ -> genJSON)
3132

3233
-- | A generator for JSON objects containing entries based on the passed generator.
3334
genObjectOf :: forall m. MonadGen m => MonadRec m => m (Tuple String J.JSON) -> m J.JSON
34-
genObjectOf inner = J.fromObject <<< Object.fromEntries <$> (Gen.unfoldable inner)
35+
genObjectOf inner = J.fromJObject <<< JObject.fromEntries <$> (Gen.unfoldable inner)
3536

3637
-- | A generator for JSON objects containing random entries.
3738
genObject :: forall m. MonadGen m => MonadRec m => Lazy (m J.JSON) => m J.JSON

src/JSON/Internal.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ export const _case = (isNull, isBool, isNum, isStr, isArr, isObj, j) => {
2222
return isObj(j);
2323
};
2424

25+
export const toArray = (js) => js;
26+
export const fromArray = (js) => js;
27+
2528
export const _fromEntries = (fst, snd, entries) => {
2629
const result = {};
2730
for (var i = 0; i < entries.length; i++) {

src/JSON/Internal.purs

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,36 @@ _lt _ = LT
4444
_gt :: forall a. a -> Ordering
4545
_gt _ = GT
4646

47+
-- | A type that represents JSON arrays. Similar to the JSON type, this is not a PureScript type,
48+
-- | but represents the underlying representation for JSON arrays.
49+
foreign import data JArray :: Type
50+
51+
-- | Converts a `JArray` into an `Array` of `JSON` values
52+
foreign import toArray :: JArray -> Array JSON
53+
54+
-- | Converts an `Array` of `JSON` values into a `JArray`.
55+
foreign import fromArray :: Array JSON -> JArray
56+
57+
instance Eq JArray where
58+
eq x y = eq (toArray x) (toArray y)
59+
60+
instance Ord JArray where
61+
compare x y = compare (toArray x) (toArray y)
62+
63+
instance Semigroup JArray where
64+
append x y = fromArray (append (toArray x) (toArray y))
65+
66+
instance Monoid JArray where
67+
mempty = fromArray []
68+
4769
-- | A type that represents JSON objects. Similar to the JSON type, this is not a PureScript type,
4870
-- | but represents the underlying representation for JSON objects.
49-
foreign import data Object :: Type
71+
foreign import data JObject :: Type
5072

51-
instance Eq Object where
73+
instance Eq JObject where
5274
eq x y = eq (runFn2 _entries Tuple x) (runFn2 _entries Tuple y)
5375

54-
instance Ord Object where
76+
instance Ord JObject where
5577
compare x y = compare (runFn2 _entries Tuple x) (runFn2 _entries Tuple y)
5678

5779
foreign import _parse
@@ -70,28 +92,28 @@ foreign import _case
7092
(Boolean -> a)
7193
(Number -> a)
7294
(String -> a)
73-
(Array JSON -> a)
74-
(Object -> a)
95+
(JArray -> a)
96+
(JObject -> a)
7597
JSON
7698
a
7799

78-
foreign import _insert :: Fn3 String JSON Object Object
100+
foreign import _insert :: Fn3 String JSON JObject JObject
79101

80-
foreign import _delete :: Fn2 String Object Object
102+
foreign import _delete :: Fn2 String JObject JObject
81103

82104
foreign import _fromEntries
83105
:: Fn3
84106
(forall x y. Tuple x y -> x)
85107
(forall x y. Tuple x y -> y)
86-
(Array (Tuple String JSON))
87-
Object
108+
(Prim.Array (Tuple String JSON))
109+
JObject
88110

89-
foreign import _entries :: forall c. Fn2 (String -> JSON -> c) Object (Array c)
111+
foreign import _entries :: forall c. Fn2 (String -> JSON -> c) JObject (Prim.Array c)
90112

91113
foreign import _lookup
92114
:: Fn4
93115
(forall a. Maybe a)
94116
(forall a. a -> Maybe a)
95117
String
96-
Object
118+
JObject
97119
(Maybe JSON)

0 commit comments

Comments
 (0)