git.iko.soy/typeable/hjsonschema
on master help sign in
34 files changed+300−320
since splitsnapshots
unifiedsplit
.travis.yml+22−9 README.md+8−50 changelog.md+33−1 examples/AlternateSchema.hs+13−18 examples/Simple.hs+4−5 examples/TwoStep.hs+3−4 hjsonschema.cabal+25−30 logo.jpg run-stack-haddock−1 shell.nix+5−5 src/Import.hs+7−8 src/JSONSchema/Draft4.hs+12−15 src/JSONSchema/Draft4/Failure.hs+1−2 src/JSONSchema/Draft4/Schema.hs+6−7 src/JSONSchema/Draft4/Spec.hs+9−13 src/JSONSchema/Fetch.hs+16−15 src/JSONSchema/Types.hs−1 src/JSONSchema/Validator/Draft4.hs+7−8 src/JSONSchema/Validator/Draft4/Any.hs+50−29 src/JSONSchema/Validator/Draft4/Array.hs+7−6 src/JSONSchema/Validator/Draft4/Number.hs+1−2 src/JSONSchema/Validator/Draft4/Object.hs+5−9 src/JSONSchema/Validator/Draft4/Object/Properties.hs+5−6 src/JSONSchema/Validator/Draft4/String.hs+2−3 src/JSONSchema/Validator/Reference.hs+7−7 src/JSONSchema/Validator/Types.hs−1 src/JSONSchema/Validator/Utils.hs+11−17 stack.yaml+2 test/Local.hs+7−10 test/Local/Failure.hs+3−4 test/Local/Reference.hs−1 test/Local/Validation.hs+5−6 test/Remote.hs+6−7 test/Shared.hs+18−20
.travis.yml+22−9
@@ -26,18 +26,19 @@ before_cache:
2626
2727matrix:
2828 include:
29− - compiler: "ghc-7.8.4"
29+ - compiler: "ghc-8.0.2"
3030 # env: TEST=--disable-tests BENCH=--disable-benchmarks
31− addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-7.8.4], sources: [hvr-ghc]}}
32− - compiler: "ghc-7.10.2"
31+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.0.2], sources: [hvr-ghc]}}
32+ - compiler: "ghc-8.2.2"
3333 # env: TEST=--disable-tests BENCH=--disable-benchmarks
34− addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-7.10.2], sources: [hvr-ghc]}}
35− - compiler: "ghc-8.0.1"
34+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.2.2], sources: [hvr-ghc]}}
35+ - compiler: "ghc-8.4.1"
3636 # env: TEST=--disable-tests BENCH=--disable-benchmarks
37− addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.0.1], sources: [hvr-ghc]}}
37+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.4.1], sources: [hvr-ghc]}}
3838
3939before_install:
4040 - HC=${CC}
41+ - HCPKG=${HC/ghc/ghc-pkg}
4142 - unset CC
4243 - PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$PATH
4344 - PKGNAME='hjsonschema'
@@ -47,8 +48,10 @@ install:
4748 - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
4849 - BENCH=${BENCH---enable-benchmarks}
4950 - TEST=${TEST---enable-tests}
51+ - HADDOCK=${HADDOCK-true}
52+ - INSTALLED=${INSTALLED-true}
5053 - travis_retry cabal update -v
51− - sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
54+ - sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
5255 - rm -fv cabal.project.local
5356 - "echo 'packages: .' > cabal.project"
5457 - rm -f cabal.project.freeze
@@ -59,7 +62,7 @@ install:
5962# any command which exits with a non-zero exit code causes the build to fail.
6063script:
6164 - if [ -f configure.ac ]; then autoreconf -i; fi
62− - rm -rf dist/
65+ - rm -rf .ghc.environment.* dist/
6366 - cabal sdist # test that a source-distribution can be generated
6467 - cd dist/
6568 - SRCTAR=(${PKGNAME}-*.tar.gz)
@@ -75,8 +78,18 @@ script:
7578 # this builds all libraries and executables (including tests/benchmarks)
7679 # - rm -rf ./dist-newstyle
7780
78− # build & run tests
81+ # Build with installed constraints for packages in global-db
82+ - if $INSTALLED; then
83+ echo cabal new-build -w ${HC} --disable-tests --disable-benchmarks $(${HCPKG} list --global --simple-output --names-only | sed 's/\([a-zA-Z0-9-]\{1,\}\) */--constraint="\1 installed" /g') all | sh;
84+ else echo "Not building with installed constraints"; fi
85+
86+ # build & run tests, build benchmarks
7987 - cabal new-build -w ${HC} ${TEST} ${BENCH} all
8088 - if [ "x$TEST" = "x--enable-tests" ]; then cabal new-test -w ${HC} ${TEST} all; fi
8189
90+ # haddock
91+ - rm -rf ./dist-newstyle
92+ - if $HADDOCK; then cabal new-haddock -w ${HC} --disable-tests --disable-benchmarks all; else echo "Skipping haddock generation";fi
93+
94+# REGENDATA ["hjsonschema.cabal"]
8295# EOF
README.md+8−50
@@ -1,67 +1,25 @@
1−![hjsonschema logo](./logo.jpg)
1+# DEPRECATION NOTICE
22
3−A Haskell implementation of the most commonly used [JSON Schema](http://json-schema.org/) specification ([Draft 4](https://github.com/json-schema-org/json-schema-spec/wiki/Specification-Links#draft-4)).
3+`hjsonschema` was an attempt to build a very modular JSON Schema library. Validators have [a concrete type](src/JSONSchema/Validator/Types.hs) and can be mixed and matched into new [Specs](src/JSONSchema/Types.hs).
44
5−[Hackage](https://hackage.haskell.org/package/hjsonschema) / [GitHub](https://github.com/seagreen/hjsonschema) / [Travis CI](https://travis-ci.org/seagreen/hjsonschema)
6−
7−# Notes
5+However this flexibility came at the price of complicating the code. I don't think it was the right tradeoff, especially since situations where you'd want to change what validators make up a `Spec` at runtime seem rare.
86
9−+ As of 2017 [json-schema-org](https://github.com/json-schema-org/json-schema-spec) has begun releasing new drafts of the standard. Once this work stabilizes `hjsonschema` will add coverage for the latest draft.
7+Also, there are many parts of JSON Schema that `hjsonschema` doesn't implement properly (as you can see from the issue tracker). I'm hoping that a new JSON Schema library will come along that handles these correctly. In the meantime I'm happy to merge working fixes into here.
108
11−+ Requires [pcre](http://www.pcre.org/) (`pkgs.pcre` in Nixpkgs).
9+# Links
1210
13−+ Schemas with circular references can cause infinite loops. hjsonschema does loop detection but it may not be solid yet -- please open an issue if you find a situation where it fails.
11+[Hackage](https://hackage.haskell.org/package/hjsonschema) / [GitHub](https://github.com/seagreen/hjsonschema) / [Travis CI](https://travis-ci.org/seagreen/hjsonschema)
1412
1513# Example
1614
1715See [here](https://github.com/seagreen/hjsonschema/blob/master/examples/Simple.hs).
1816
19−# Tests
20−
21−Run all tests:
22−
23−`stack test`
24−
25−Run only local tests:
26−
27−`stack test hjsonschema:local`
28−
29−Run remote tests (makes GETs to json-schema.org, also temporarily starts an HTTP server on port 1234):
30−
31−`stack test hjsonschema:remote`
32−
33−# Details
34−
35−## Goals
36−
37−+ Be a correct and fast implementation of the spec.
17+# System dependencies
3818
39−+ Be a useful reference for implementers in other languages. Haskell's high level nature, expressive type system and referential transparency suit this purpose well.
40−
41−## Good Parts
42−
43−+ Passes all the required tests in the [language agnostic test suite](https://github.com/json-schema/JSON-Schema-Test-Suite). NOTE: due to an issue with the test suite this isn't true at the moment, see [#175](https://github.com/json-schema-org/JSON-Schema-Test-Suite/issues/175).
44−
45−+ Very modular, which should make it easy to support future versions of the specification.
46−
47−## Bad Parts
48−
49−+ Uses the [pcre-heavy](https://hackage.haskell.org/package/pcre-heavy) regular expression library for the "pattern" validator. It should use a library based on the ECMA 262 regex dialect, which the [spec](http://json-schema.org/latest/json-schema-validation.html#anchor33) requires.
50−
51−+ Currently doesn't support the optional `"format"` validators.
19++ Requires [pcre](http://www.pcre.org/) (`pkgs.pcre` in Nixpkgs).
5220
5321## Vendoring
5422
5523+ `JSON-Schema-Test-Suite` is vendored from commit # c1b12bf699f29a04b4286711c6e3bbfba66f21e5 [here](https://github.com/json-schema-org/JSON-Schema-Test-Suite).
5624
5725+ `src/draft4.json` is from commit # c1b12bf699f29a04b4286711c6e3bbfba66f21e5 [here](https://github.com/json-schema/json-schema). The [root ref in remote ref](./JSON-Schema-Test-Suite/tests/draft4/refRemote.json) test has been modified to fix [#175](https://github.com/json-schema-org/JSON-Schema-Test-Suite/issues/175).
58−
59−+ `.travis.yml` was created with `make_travis_yml_2.hs` commit # ea6c7d177a97bfbfb2fdc4deba943d60d2aff199.
60−
61−## Credits
62−
63−[TJ Weigel](http://tjweigel.com/) created the logo.
64−
65−[Tim Baumann](https://github.com/timjb) wrote [aeson-schema](https://hackage.haskell.org/package/aeson-schema), on which hjsonschema's test code and its implementation of `SchemaGraph` were based.
66−
67−[Julian Berman](https://github.com/Julian) maintains the fantastic [language agnostic test suite](https://github.com/json-schema/JSON-Schema-Test-Suite).
changelog.md+33−1
@@ -1,4 +1,36 @@
1−# 1.6.0
1+# 1.8.0
2+
3++ Add GHC 8.4 support (thanks @4e6 !).
4++ Drop GHC 7.10 support.
5++ Fix JSON Pointer resolution error.
6+
7+# 1.8.0
8+
9++ Allow HTTPS references (thanks @creichert!).
10++ Use `safe-exceptions` to eliminate the risk of catching asynchronous exceptions.
11+
12+# 1.7.2
13+
14++ Remove upper bounds.
15+
16+# 1.7.1
17+
18++ Bump http-types.
19+
20+# 1.7.0
21+
22++ Test with GHC 8.2. Drop GHC 7.8.
23++ Rework `allUniqueValues` related utility functions.
24+
25+# 1.6.3
26+
27++ Bump hjsonpointer and QuickCheck.
28+
29+# 1.6.2
30+
31++ Bump aeson.
32+
33+# 1.6.1
234
335+ Fix Haddocks.
436
examples/AlternateSchema.hs+13−18
@@ -5,28 +5,23 @@
55-- to copy this module instead of the 'JSONSchema.Draft4'. While it's
66-- less convenient to write schemas in Haskell without a record type, you
77-- can get the implementation finished with far fewer lines of code.
8−
98module AlternateSchema where
109
1110import Protolude
1211
13−import Data.Aeson (FromJSON(..), Value(..),
14− decodeStrict)
15−import qualified Data.Aeson as AE
16−import qualified Data.HashMap.Strict as HM
17−import Data.Maybe (fromMaybe)
18−import Data.Profunctor (Profunctor (..))
19−
20−import JSONSchema.Draft4 (ValidatorFailure(..),
21− metaSchemaBytes)
22−import JSONSchema.Fetch (SchemaWithURI(..),
23− URISchemaMap(..))
24−import qualified JSONSchema.Fetch as FE
25−import JSONSchema.Types (Schema(..), Spec(..))
26−import qualified JSONSchema.Types as JT
27−import qualified JSONSchema.Validator.Draft4 as D4
28−import JSONSchema.Validator.Reference (BaseURI(..),
29− Scope(..),
12+import Data.Aeson (FromJSON(..), Value(..), decodeStrict)
13+import qualified Data.Aeson as AE
14+import qualified Data.HashMap.Strict as HM
15+import Data.Maybe (fromMaybe)
16+import Data.Profunctor (Profunctor(..))
17+
18+import JSONSchema.Draft4 (ValidatorFailure(..), metaSchemaBytes)
19+import JSONSchema.Fetch (SchemaWithURI(..), URISchemaMap(..))
20+import qualified JSONSchema.Fetch as FE
21+import JSONSchema.Types (Schema(..), Spec(..))
22+import qualified JSONSchema.Types as JT
23+import qualified JSONSchema.Validator.Draft4 as D4
24+import JSONSchema.Validator.Reference (BaseURI(..), Scope(..),
3025 updateResolutionScope)
3126
3227--------------------------------------------------
examples/Simple.hs+4−5
@@ -1,14 +1,13 @@
1−
21module Simple where
32
43import Protolude
54
6−import Data.Aeson (Value(..), decodeStrict, toJSON)
7−import qualified Data.ByteString as BS
5+import Data.Aeson (Value(..), decodeStrict, toJSON)
6+import qualified Data.ByteString as BS
87import qualified Data.List.NonEmpty as NE
9−import Data.Maybe (fromMaybe)
8+import Data.Maybe (fromMaybe)
109
11−import qualified JSONSchema.Draft4 as D4
10+import qualified JSONSchema.Draft4 as D4
1211
1312badData :: Value
1413badData = toJSON [True, True]
examples/TwoStep.hs+3−4
@@ -10,15 +10,14 @@
1010-- 'fetchHTTPAndValidate' which fetched references over HTTP (though it
1111-- didn't matter because the last schema didn't actually have any).
1212-- This time we need to get them from the filesystem.
13−
1413module TwoStep where
1514
1615import Protolude
1716
18−import Data.Aeson (Value (..), toJSON)
19−import qualified Data.List.NonEmpty as NE
17+import Data.Aeson (Value(..), toJSON)
18+import qualified Data.List.NonEmpty as NE
2019
21−import qualified JSONSchema.Draft4 as D4
20+import qualified JSONSchema.Draft4 as D4
2221import qualified JSONSchema.Validator.Draft4 as VAL
2322
2423schema :: D4.Schema
hjsonschema.cabal+25−30
@@ -1,5 +1,5 @@
11name: hjsonschema
2−version: 1.6.1
2+version: 1.9.0
33synopsis: JSON Schema library
44homepage: https://github.com/seagreen/hjsonschema
55license: MIT
@@ -9,7 +9,8 @@ maintainer: ian@housejeffries.com
99category: Data
1010build-type: Simple
1111cabal-version: >=1.10
12−tested-with: GHC == 7.8.4, GHC == 7.10.2, GHC == 8.0.1
12+-- Rerun multi-ghc-travis (executable make-travis-yml-2) after changing:
13+Tested-With: GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.1
1314extra-source-files:
1415 changelog.md
1516 JSON-Schema-Test-Suite/remotes/*.json
@@ -33,7 +34,6 @@ library
3334 NoImplicitPrelude
3435 OverloadedStrings
3536 ScopedTypeVariables
36− TupleSections
3737 if impl(ghc >= 8)
3838 default-extensions: StrictData
3939 ghc-options:
@@ -58,27 +58,28 @@ library
5858 JSONSchema.Validator.Draft4.Object.Properties
5959 , Import
6060 build-depends:
61− base >= 4.7 && < 4.10
61+ base >= 4.7 && < 5
6262 -- 0.11 is for `.:!`:
63− , aeson >= 0.11 && < 1.2
64− , bytestring >= 0.10 && < 0.11
65− , containers >= 0.5 && < 0.6
66− , file-embed >= 0.0.8 && < 0.1
67− , filepath >= 1.3 && < 1.5
68− , hashable >= 1.2 && < 1.3
69− , hjsonpointer >= 1.1 && < 1.2
63+ , aeson >= 0.11
64+ , bytestring >= 0.10
65+ , containers >= 0.5
66+ , file-embed >= 0.0.8
67+ , filepath >= 1.3
68+ , hashable >= 1.2
69+ , hjsonpointer >= 1.1
7070 -- 0.4.30 is for parseUrlThrow:
71− , http-client >= 0.4.30 && < 0.6
72− , http-types >= 0.8 && < 0.10
73− , pcre-heavy >= 1.0 && < 1.1
74− , profunctors >= 5.0 && < 5.3
75− , protolude >= 0.1.10 && < 1.2
76− , QuickCheck >= 2.8 && < 2.10
77− , scientific >= 0.3 && < 0.4
78− , semigroups >= 0.18 && < 0.19
79− , unordered-containers >= 0.2 && < 0.3
80− , text >= 1.1 && < 1.3
81− , vector >= 0.10 && < 1.0
71+ , http-client >= 0.4.30
72+ , http-client-tls >= 0.3
73+ , http-types >= 0.8
74+ , pcre-heavy >= 1.0
75+ , profunctors >= 5.0
76+ , protolude >= 0.1.10
77+ , QuickCheck >= 2.8
78+ , safe-exceptions >= 0.1.6
79+ , scientific >= 0.3
80+ , unordered-containers >= 0.2
81+ , text >= 1.1
82+ , vector >= 0.10
8283
8384test-suite local
8485 hs-source-dirs:
@@ -113,15 +114,14 @@ test-suite local
113114 , hjsonschema
114115 , profunctors
115116 , protolude
116− , semigroups
117117 , text
118118 , QuickCheck
119119 , unordered-containers
120120 , vector
121121
122122 -- directory-1.2.5 required for `listDirectory`:
123− , directory >= 1.2.5 && < 2.0
124− , hspec >= 2.2 && < 3.0
123+ , directory >= 1.2.5
124+ , hspec >= 2.2
125125
126126test-suite remote
127127 hs-source-dirs:
@@ -152,7 +152,6 @@ test-suite remote
152152 , hjsonschema
153153 , profunctors
154154 , protolude
155− , semigroups
156155 , text
157156 , unordered-containers
158157 , vector
@@ -161,7 +160,3 @@ test-suite remote
161160 , hspec
162161 , wai-app-static
163162 , warp
164−
165−source-repository head
166− type: git
167− location: git://github.com/seagreen/hjsonschema.git
logo.jpgdeleted

Binary file not shown.

run-stack-haddockdeleted−1
@@ -1 +0,0 @@
1−../stack-haddock-upload/stack-haddock-upload hjsonschema # 1.2.0.1
shell.nix+5−5
@@ -1,15 +1,15 @@
1+{ghc}:
12with (import <nixpkgs> {});
23
34haskell.lib.buildStackProject {
45 name = "none";
56 inherit ghc;
67 buildInputs = [
7− pkgconfig
8− zlib
9−
108 pcre
119
12− # for `git:` references in stack.yml:
13− git
10+ git # for `git:` references in stack.yml.
11+ ncurses # for intero
12+ pkgconfig
13+ zlib
1414 ];
1515}
src/Import.hs+7−8
@@ -1,17 +1,16 @@
11
22module Import (module Export, fromJSONEither) where
33
4−import Protolude as Export
4+import Protolude as Export
55
6−import Data.Aeson as Export
6+import Data.Aeson as Export
77import Data.HashMap.Strict as Export (HashMap)
8−import Data.List as Export (length, null) -- for older GHCs
9−import Data.List.NonEmpty as Export (NonEmpty)
10−import Data.Vector as Export (Vector)
11−import Test.QuickCheck as Export hiding ((.&.), Failure,
12− Result, Success)
8+import Data.List.NonEmpty as Export (NonEmpty)
9+import Data.Vector as Export (Vector)
10+import Test.QuickCheck as Export hiding (Failure, Result, Success,
11+ (.&.))
1312
14−import qualified Data.Text as T
13+import qualified Data.Text as T
1514
1615fromJSONEither :: FromJSON a => Value -> Either Text a
1716fromJSONEither a =
src/JSONSchema/Draft4.hs+12−15
@@ -37,22 +37,19 @@ module JSONSchema.Draft4
3737
3838import Import
3939
40−import qualified Data.ByteString as BS
41−import Data.FileEmbed (embedFile,
42− makeRelativeToProject)
43−import qualified Data.HashMap.Strict as HM
44−import qualified Data.List.NonEmpty as NE
45−import Data.Maybe (fromMaybe)
46−
47−import JSONSchema.Draft4.Failure (Invalid(..),
48− SchemaInvalid(..),
40+import qualified Data.ByteString as BS
41+import Data.FileEmbed (embedFile, makeRelativeToProject)
42+import qualified Data.HashMap.Strict as HM
43+import qualified Data.List.NonEmpty as NE
44+import Data.Maybe (fromMaybe)
45+
46+import JSONSchema.Draft4.Failure (Invalid(..), SchemaInvalid(..),
4947 ValidatorFailure(..))
50−import JSONSchema.Draft4.Schema (Schema)
51−import qualified JSONSchema.Draft4.Schema as SC
52−import qualified JSONSchema.Draft4.Spec as Spec
53−import JSONSchema.Fetch (SchemaWithURI(..),
54− URISchemaMap(..))
55−import qualified JSONSchema.Fetch as FE
48+import JSONSchema.Draft4.Schema (Schema)
49+import qualified JSONSchema.Draft4.Schema as SC
50+import qualified JSONSchema.Draft4.Spec as Spec
51+import JSONSchema.Fetch (SchemaWithURI(..), URISchemaMap(..))
52+import qualified JSONSchema.Fetch as FE
5653
5754data HTTPValidationFailure
5855 = HVRequest FE.HTTPFailure
src/JSONSchema/Draft4/Failure.hs+1−2
@@ -1,9 +1,8 @@
1−
21module JSONSchema.Draft4.Failure where
32
43import Import
54
6−import JSONSchema.Draft4.Schema (Schema)
5+import JSONSchema.Draft4.Schema (Schema)
76import qualified JSONSchema.Validator.Draft4 as VAL
87
98-- | Used to report an entire instance being invalidated, as opposed
src/JSONSchema/Draft4/Schema.hs+6−7
@@ -1,14 +1,13 @@
1−
21module JSONSchema.Draft4.Schema where
32
4−import Import hiding (mapMaybe)
3+import Import hiding (mapMaybe)
54
6−import qualified Data.HashMap.Strict as HM
7−import Data.List.NonEmpty (NonEmpty)
8−import Data.Maybe (fromJust, isJust)
5+import qualified Data.HashMap.Strict as HM
6+import Data.List.NonEmpty (NonEmpty)
7+import Data.Maybe (fromJust, isJust)
98import Data.Scientific
10−import qualified Data.Set as Set
11−import qualified Data.Text as T
9+import qualified Data.Set as Set
10+import qualified Data.Text as T
1211
1312import qualified JSONSchema.Validator.Draft4 as D4
1413import JSONSchema.Validator.Utils
src/JSONSchema/Draft4/Spec.hs+9−13
@@ -1,22 +1,18 @@
1−
21module JSONSchema.Draft4.Spec where
32
43import Import
54
6−import Data.Maybe (fromMaybe)
7−import Data.Profunctor (Profunctor(..))
5+import Data.Maybe (fromMaybe)
6+import Data.Profunctor (Profunctor(..))
87
98import JSONSchema.Draft4.Failure
10−import JSONSchema.Draft4.Schema (Schema(..),
11− emptySchema)
12−import JSONSchema.Fetch (SchemaWithURI(..),
13− URISchemaMap(..))
14−import qualified JSONSchema.Fetch as FE
15−import JSONSchema.Types (Spec(..))
16−import qualified JSONSchema.Types as JT
9+import JSONSchema.Draft4.Schema (Schema(..), emptySchema)
10+import JSONSchema.Fetch (SchemaWithURI(..), URISchemaMap(..))
11+import qualified JSONSchema.Fetch as FE
12+import JSONSchema.Types (Spec(..))
13+import qualified JSONSchema.Types as JT
1714import JSONSchema.Validator.Draft4
18−import JSONSchema.Validator.Reference (BaseURI(..),
19− Scope(..),
15+import JSONSchema.Validator.Reference (BaseURI(..), Scope(..),
2016 updateResolutionScope)
2117
2218-- | An implementation of 'JT.embedded'.
@@ -43,7 +39,7 @@ specValidate schemaMap sw =
4339 (_schemaId (_swSchema sw))
4440 }
4541
46−validateSubschema
42+validateSubschema
4743 :: URISchemaMap Schema
4844 -> VisitedSchemas
4945 -> Scope Schema
src/JSONSchema/Fetch.hs+16−15
@@ -1,18 +1,18 @@
1−
21module JSONSchema.Fetch where
32
43import Import
54
6−import Control.Exception (IOException, catch)
7−import Control.Monad (foldM)
8−import qualified Data.ByteString as BS
9−import qualified Data.ByteString.Lazy as LBS
10−import qualified Data.HashMap.Strict as HM
11−import qualified Data.Text as T
12−import qualified Network.HTTP.Client as NC
13−
14−import JSONSchema.Validator.Reference (BaseURI(..),
15− resolveReference,
5+import qualified Control.Exception.Safe as Safe
6+import Control.Monad (foldM)
7+import qualified Data.ByteString as BS
8+import qualified Data.ByteString.Lazy as LBS
9+import qualified Data.HashMap.Strict as HM
10+import qualified Data.Semigroup as S
11+import qualified Data.Text as T
12+import qualified Network.HTTP.Client as NC
13+import qualified Network.HTTP.Client.TLS as NCTLS
14+
15+import JSONSchema.Validator.Reference (BaseURI(..), resolveReference,
1616 updateResolutionScope)
1717
1818--------------------------------------------------
@@ -30,7 +30,7 @@ data FetchInfo schema = FetchInfo
3030-- | Keys are URIs (without URI fragments).
3131newtype URISchemaMap schema
3232 = URISchemaMap { _unURISchemaMap :: HashMap Text schema }
33− deriving (Eq, Show, Monoid)
33+ deriving (Eq, Show, S.Semigroup, Monoid)
3434
3535-- | A top-level schema along with its location.
3636data SchemaWithURI schema = SchemaWithURI
@@ -61,9 +61,9 @@ referencesViaHTTP'
6161 -> SchemaWithURI schema
6262 -> IO (Either HTTPFailure (URISchemaMap schema))
6363referencesViaHTTP' info sw = do
64− manager <- NC.newManager NC.defaultManagerSettings
64+ manager <- NC.newManager NCTLS.tlsManagerSettings
6565 let f = referencesMethodAgnostic (getURL manager) info sw
66− catch (first HTTPParseFailure <$> f) handler
66+ Safe.catch (first HTTPParseFailure <$> f) handler
6767 where
6868 getURL :: NC.Manager -> Text -> IO BS.ByteString
6969 getURL man url = do
@@ -89,7 +89,8 @@ referencesViaFilesystem'
8989 => FetchInfo schema
9090 -> SchemaWithURI schema
9191 -> IO (Either FilesystemFailure (URISchemaMap schema))
92−referencesViaFilesystem' info sw = catch (first FSParseFailure <$> f) handler
92+referencesViaFilesystem' info sw =
93+ Safe.catch (first FSParseFailure <$> f) handler
9394 where
9495 f :: IO (Either Text (URISchemaMap schema))
9596 f = referencesMethodAgnostic (BS.readFile . T.unpack) info sw
src/JSONSchema/Types.hs−1
@@ -1,4 +1,3 @@
1−
21module JSONSchema.Types where
32
43import Import
src/JSONSchema/Validator/Draft4.hs+7−8
@@ -2,7 +2,6 @@
22--
33-- This is frankly a lot of busywork. It can perhaps be moved into the
44-- validator modules themselves once we're sure this is the right design.
5−
65module JSONSchema.Validator.Draft4
76 ( module JSONSchema.Validator.Draft4
87 , module Export
@@ -10,16 +9,16 @@ module JSONSchema.Validator.Draft4
109
1110import Import
1211
13−import qualified Data.HashMap.Strict as HM
14−import qualified Data.List.NonEmpty as NE
12+import qualified Data.HashMap.Strict as HM
13+import qualified Data.List.NonEmpty as NE
1514
16−import JSONSchema.Validator.Draft4.Any as Export
17−import JSONSchema.Validator.Draft4.Array as Export
15+import JSONSchema.Validator.Draft4.Any as Export
16+import JSONSchema.Validator.Draft4.Array as Export
1817import JSONSchema.Validator.Draft4.Number as Export
1918import JSONSchema.Validator.Draft4.Object as Export
2019import JSONSchema.Validator.Draft4.String as Export
21−import JSONSchema.Validator.Reference (BaseURI(..), Scope(..))
22−import JSONSchema.Validator.Types (Validator(..))
20+import JSONSchema.Validator.Reference (BaseURI(..), Scope(..))
21+import JSONSchema.Validator.Types (Validator(..))
2322
2423-- | For internal use.
2524--
@@ -148,7 +147,7 @@ propertiesRelatedValidator f =
148147 <> HM.elems (fromMaybe mempty (_propPattern a))
149148 <> case _propAdditional a of
150149 Just (AdditionalPropertiesObject b) -> [b]
151− _ -> mempty
150+ _ -> mempty
152151 ))
153152 (\a b -> case fromJSONEither b of
154153 Left _ -> mempty
src/JSONSchema/Validator/Draft4/Any.hs+50−29
@@ -1,25 +1,24 @@
1−
21module JSONSchema.Validator.Draft4.Any where
32
4−import Import hiding ((<>))
3+import Import hiding ((<>))
54
6−import Data.Aeson.TH (constructorTagModifier)
7−import Data.Char (toLower)
8−import Data.List.NonEmpty (NonEmpty((:|)))
9−import qualified Data.List.NonEmpty as NE
10−import qualified Data.Scientific as SCI
5+import Data.Aeson.TH (constructorTagModifier)
6+import Data.Char (toLower)
7+import qualified Data.HashMap.Strict as HM
8+import Data.List.NonEmpty (NonEmpty((:|)))
9+import qualified Data.List.NonEmpty as NE
10+import qualified Data.Scientific as SCI
1111import Data.Semigroup
12−import Data.Set (Set)
13−import qualified Data.Set as Set
14−import Data.Text.Encoding.Error (UnicodeException)
15−import qualified JSONPointer as JP
16−import Network.HTTP.Types.URI (urlDecode)
17−
18−import qualified JSONSchema.Validator.Utils as UT
19−import JSONSchema.Validator.Reference (BaseURI(..),
20− Scope(..),
12+import Data.Set (Set)
13+import qualified Data.Set as Set
14+import Data.Text.Encoding.Error (UnicodeException)
15+import qualified JSONPointer as JP
16+import Network.HTTP.Types.URI (urlDecode)
17+
18+import JSONSchema.Validator.Reference (BaseURI(..), Scope(..),
2119 URIAndFragment,
2220 resolveReference)
21+import qualified JSONSchema.Validator.Utils as UT
2322
2423--------------------------------------------------
2524-- * $ref
@@ -135,7 +134,7 @@ data JSONPointerError
135134 deriving (Eq, Show)
136135
137136resolveFragment
138− :: forall schema. (FromJSON schema, ToJSON schema)
137+ :: (FromJSON schema, ToJSON schema)
139138 => (BaseURI -> schema -> BaseURI)
140139 -> Scope schema
141140 -> Text
@@ -160,17 +159,40 @@ resolveFragment updateScope scope fragment = do
160159 -- as property keys that aren't meant to change scope?
161160 -- Perhaps this should be added to the language agnostic
162161 -- test suite as well.
162+ --
163+ -- In the meantime 'newBaseURIFromFragment' drops all keys
164+ -- from JSON objects except "id", which at least prevents
165+ -- SubschemaDecodingError in a situation where one of the
166+ -- values we step through isn't a valid schema.
163167 go :: (Value, BaseURI)
164168 -> JP.Token
165169 -> Either JSONPointerError (Value, BaseURI)
166− go (lastVal, uri) tok = do
170+ go (lastVal, baseURI) tok = do
167171 v <- first ResolutionError (JP.resolveToken tok lastVal)
168− case v of
169− Array _ -> pure (v, uri)
170− _ -> do
171− -- PERFORMANCE: Avoid deserializing subschemas.
172− schema <- first SubschemaDecodingError (fromJSONEither v)
173− pure (v, updateScope uri schema)
172+ newBase <- newBaseURIFromFragment updateScope baseURI v
173+ Right (v, newBase)
174+
175+-- | Update the 'BaseURI' (the store of the current "id" value)
176+-- after resolving one token of a JSON Pointer and stepping into
177+-- a new 'Value'.
178+newBaseURIFromFragment
179+ :: FromJSON schema
180+ => (BaseURI -> schema -> BaseURI)
181+ -> BaseURI
182+ -> Value
183+ -> Either JSONPointerError BaseURI
184+newBaseURIFromFragment updateScope baseURI v =
185+ case v of
186+ Object hm -> do
187+ let hmWithOnlyId = case HM.lookup idKey hm of
188+ Nothing -> mempty
189+ Just idVal -> HM.singleton idKey idVal
190+ schema <- first SubschemaDecodingError (fromJSONEither (Object hmWithOnlyId))
191+ Right (updateScope baseURI schema)
192+ _ -> Right baseURI
193+ where
194+ idKey :: Text
195+ idKey = "id"
174196
175197--------------------------------------------------
176198-- * enum
@@ -216,9 +238,9 @@ data EnumInvalid
216238
217239enumVal :: EnumValidator -> Value -> Maybe EnumInvalid
218240enumVal a@(EnumValidator vs) x
219− | not (UT.allUniqueValues' vs) = Nothing
220− | x `elem` vs = Nothing
221− | otherwise = Just $ EnumInvalid a x
241+ | not (UT.allUniqueValues vs) = Nothing
242+ | x `elem` vs = Nothing
243+ | otherwise = Just $ EnumInvalid a x
222244
223245--------------------------------------------------
224246-- * type
@@ -377,8 +399,7 @@ anyOfVal
377399 -> Value
378400 -> Maybe (AnyOfInvalid err)
379401anyOfVal f (AnyOf subSchemas) x
380− -- Replace with @null@ once we drop GHC 7.8:
381− | any (((==) 0 . length) . snd) perhapsFailures = Nothing
402+ | any (null . snd) perhapsFailures = Nothing
382403 | otherwise = AnyOfInvalid <$> NE.nonEmpty failures
383404 where
384405 perhapsFailures :: [(JP.Index, [err])]
src/JSONSchema/Validator/Draft4/Array.hs+7−6
@@ -1,11 +1,10 @@
1−
21module JSONSchema.Validator.Draft4.Array where
32
43import Import
54
6−import qualified Data.List.NonEmpty as NE
7−import qualified Data.Vector as V
8−import qualified JSONPointer as JP
5+import qualified Data.List.NonEmpty as NE
6+import qualified Data.Vector as V
7+import qualified JSONPointer as JP
98
109import JSONSchema.Validator.Utils (allUniqueValues)
1110
@@ -174,7 +173,8 @@ itemsVal f a xs =
174173 :: schema
175174 -> (JP.Index, Value)
176175 -> Maybe (JP.Index, NonEmpty err)
177− validateElem schema (index,x) = (index,) <$> NE.nonEmpty (f schema x)
176+ validateElem schema (index,x) =
177+ (\v -> (index, v)) <$> NE.nonEmpty (f schema x)
178178
179179--------------------------------------------------
180180-- * additionalItems
@@ -219,6 +219,7 @@ additionalItemsVal _ (AdditionalBool False) xs =
219219 AdditionalItemsBoolInvalid <$> NE.nonEmpty xs
220220additionalItemsVal f (AdditionalObject subSchema) xs =
221221 let res = mapMaybe
222− (\(index,x) -> (index,) <$> NE.nonEmpty (f subSchema x))
222+ (\(index,x) -> (\v -> (index, v))
223+ <$> NE.nonEmpty (f subSchema x))
223224 xs
224225 in AdditionalItemsObjectInvalid <$> NE.nonEmpty res
src/JSONSchema/Validator/Draft4/Number.hs+1−2
@@ -1,9 +1,8 @@
1−
21module JSONSchema.Validator.Draft4.Number where
32
43import Import
54
6−import Data.Fixed (mod')
5+import Data.Fixed (mod')
76import Data.Scientific (Scientific)
87
98--------------------------------------------------
src/JSONSchema/Validator/Draft4/Object.hs+5−9
@@ -1,4 +1,3 @@
1−
21module JSONSchema.Validator.Draft4.Object
32 ( module JSONSchema.Validator.Draft4.Object
43 , module JSONSchema.Validator.Draft4.Object.Properties
@@ -6,11 +5,11 @@ module JSONSchema.Validator.Draft4.Object
65
76import Import
87
9−import qualified Data.HashMap.Strict as HM
10−import qualified Data.List.NonEmpty as NE
11−import Data.Set (Set)
12−import qualified Data.Set as Set
13−import qualified Data.Text as T
8+import qualified Data.HashMap.Strict as HM
9+import qualified Data.List.NonEmpty as NE
10+import Data.Set (Set)
11+import qualified Data.Set as Set
12+import qualified Data.Text as T
1413
1514import JSONSchema.Validator.Draft4.Object.Properties
1615import JSONSchema.Validator.Utils
@@ -96,9 +95,6 @@ data RequiredInvalid
9695
9796requiredVal :: Required -> HashMap Text Value -> Maybe RequiredInvalid
9897requiredVal r@(Required ts) x
99− -- NOTE: When we no longer need to support GHCs before 7.10
100− -- we can use null from Prelude throughout the library
101− -- instead of specialized versions.
10298 | Set.null ts = Nothing
10399 | Set.null leftovers = Nothing
104100 | otherwise = Just (RequiredInvalid r leftovers x)
src/JSONSchema/Validator/Draft4/Object/Properties.hs+5−6
@@ -1,13 +1,12 @@
1−
21module JSONSchema.Validator.Draft4.Object.Properties where
32
43import Import
54
6−import qualified Data.Hashable as HA
7−import qualified Data.HashMap.Strict as HM
8−import qualified Data.List.NonEmpty as NE
9−import Data.Text.Encoding (encodeUtf8)
10−import qualified JSONPointer as JP
5+import qualified Data.Hashable as HA
6+import qualified Data.HashMap.Strict as HM
7+import qualified Data.List.NonEmpty as NE
8+import Data.Text.Encoding (encodeUtf8)
9+import qualified JSONPointer as JP
1110import qualified Text.Regex.PCRE.Heavy as RE
1211
1312data PropertiesRelated schema = PropertiesRelated
src/JSONSchema/Validator/Draft4/String.hs+2−3
@@ -1,10 +1,9 @@
1−
21module JSONSchema.Validator.Draft4.String where
32
43import Import
54
6−import qualified Data.Text as T
7−import Data.Text.Encoding (encodeUtf8)
5+import qualified Data.Text as T
6+import Data.Text.Encoding (encodeUtf8)
87import qualified Text.Regex.PCRE.Heavy as RE
98
109--------------------------------------------------
src/JSONSchema/Validator/Reference.hs+7−7
@@ -3,15 +3,14 @@
33--
44-- And is extended for JSON Schema here:
55-- <http://json-schema.org/latest/json-schema-core.html#anchor26>
6−
76module JSONSchema.Validator.Reference where
87
98import Import
109
11−import qualified Data.Text as T
12−import System.FilePath ((</>), dropFileName)
10+import qualified Data.Text as T
11+import System.FilePath (dropFileName, (</>))
1312
14−data Scope schema = Scope
13+data Scope schema = Scope
1514 { _topLevelDocument :: schema
1615 , _documentURI :: Maybe Text
1716 , _currentBaseURI :: BaseURI
@@ -25,9 +24,10 @@ newtype BaseURI
2524type URIAndFragment = (Maybe Text, Maybe Text)
2625
2726updateResolutionScope :: BaseURI -> Maybe Text -> BaseURI
28−updateResolutionScope base idKeyword
29− | Just t <- idKeyword = BaseURI . fst . baseAndFragment $ resolveScopeAgainst base t
30− | otherwise = base
27+updateResolutionScope base idKeyword =
28+ case idKeyword of
29+ Just t -> BaseURI . fst . baseAndFragment $ resolveScopeAgainst base t
30+ Nothing -> base
3131
3232resolveReference :: BaseURI -> Text -> URIAndFragment
3333resolveReference base t = baseAndFragment (resolveScopeAgainst base t)
src/JSONSchema/Validator/Types.hs−1
@@ -1,4 +1,3 @@
1−
21module JSONSchema.Validator.Types where
32
43import Import
src/JSONSchema/Validator/Utils.hs+11−17
@@ -1,16 +1,15 @@
1−
21module JSONSchema.Validator.Utils where
32
43import Import
54
6−import Control.Monad (fail)
5+import Control.Monad (fail)
76import qualified Data.HashMap.Strict as HM
8−import qualified Data.List.NonEmpty as NE
9−import Data.Scientific (Scientific, fromFloatDigits)
10−import Data.Set (Set)
11−import qualified Data.Set as S
12−import qualified Data.Text as T
13−import qualified Data.Vector as V
7+import qualified Data.List.NonEmpty as NE
8+import Data.Scientific (Scientific, fromFloatDigits)
9+import Data.Set (Set)
10+import qualified Data.Set as S
11+import qualified Data.Text as T
12+import qualified Data.Vector as V
1413
1514--------------------------------------------------
1615-- * QuickCheck
@@ -83,16 +82,11 @@ instance Arbitrary a => Arbitrary (NonEmpty' a) where
8382-- * allUniqueValues
8483--------------------------------------------------
8584
86−allUniqueValues :: Vector Value -> Bool
87−allUniqueValues = allUnique . fmap OrdValue . V.toList
88−
89−-- NOTE: When we no longer support GHC 7.8 we can generalize
90−-- allUnique to work on any Foldable and remove this function.
91−allUniqueValues' :: NonEmpty Value -> Bool
92−allUniqueValues' = allUnique . fmap OrdValue . NE.toList
85+allUniqueValues :: (Foldable f, Functor f) => f Value -> Bool
86+allUniqueValues = allUnique . fmap OrdValue
9387
94−allUnique :: (Ord a) => [a] -> Bool
95−allUnique xs = S.size (S.fromList xs) == length xs
88+allUnique :: (Foldable f, Ord a) => f a -> Bool
89+allUnique xs = S.size (S.fromList (toList xs)) == length xs
9690
9791-- | OrdValue's Ord instance needs benchmarking, but it allows us to
9892-- use our 'allUnique' function instead of O(n^2) nub, so it's probably
stack.yamlnew file+2
@@ -0,0 +1,2 @@
1+resolver: lts-10.8
2+pvp-bounds: upper-revision
test/Local.hs+7−10
@@ -1,19 +1,18 @@
1−
21module Main where
32
43import Protolude
54
65import Data.Aeson
76import qualified Data.List.NonEmpty as NE
8−import qualified System.Timeout as TO
7+import qualified System.Timeout as TO
98import Test.Hspec
10−import Test.QuickCheck (property)
9+import Test.QuickCheck (property)
1110
12−import qualified JSONSchema.Draft4 as D4
13−import qualified JSONSchema.Types as JT
11+import qualified JSONSchema.Draft4 as D4
12+import qualified JSONSchema.Types as JT
1413import qualified Local.Failure
15−import qualified Local.Validation
1614import qualified Local.Reference
15+import qualified Local.Validation
1716import Shared
1817
1918-- Examples
@@ -33,12 +32,10 @@ main = do
3332 -- Language agnostic tests
3433 ts <- readSchemaTests
3534 dir
36− (\a -> not (isHTTPTest a || skipOptional a))
35+ (\a -> not (isHTTPTest a || skipTest a))
3736
3837 -- Custom supplements to the language agnostic tests
39− supplementTs <- readSchemaTests
40− supplementDir
41− (\a -> not (isHTTPTest a || skipOptional a))
38+ supplementTs <- readSchemaTests supplementDir (not . isHTTPTest)
4239
4340 hspec $ do
4441 describe "Examples" exampleTests
test/Local/Failure.hs+3−4
@@ -1,15 +1,14 @@
1−
21module Local.Failure where
32
43import Protolude
54
65import Data.Aeson
6+import qualified Data.Vector as V
7+import qualified JSONPointer as JP
78import Test.Hspec
8−import qualified Data.Vector as V
9−import qualified JSONPointer as JP
109
1110import JSONSchema.Draft4
12−import qualified JSONSchema.Draft4.Spec as Spec
11+import qualified JSONSchema.Draft4.Spec as Spec
1312import qualified JSONSchema.Validator.Draft4 as VAL
1413
1514spec :: Spec
test/Local/Reference.hs−1
@@ -1,4 +1,3 @@
1−
21module Local.Reference where
32
43import Protolude
test/Local/Validation.hs+5−6
@@ -1,17 +1,16 @@
1−
21module Local.Validation where
32
4−import Protolude hiding (msg)
3+import Protolude
54
65import Data.Aeson
7−import qualified Data.Aeson as AE
6+import qualified Data.Aeson as AE
87import qualified Data.HashMap.Strict as HM
9−import Data.String (String)
8+import Data.String (String)
109import Test.Hspec
1110
11+import qualified AlternateSchema as AS
1212import JSONSchema.Draft4
13−import qualified JSONSchema.Types as JT
14−import qualified AlternateSchema as AS
13+import qualified JSONSchema.Types as JT
1514
1615spec :: Spec
1716spec = do
test/Remote.hs+6−7
@@ -1,17 +1,16 @@
1−
21module Main where
32
43import Protolude
54
6−import Control.Concurrent.Async (withAsync)
7−import qualified Data.List.NonEmpty as NE
5+import Control.Concurrent.Async (withAsync)
6+import qualified Data.List.NonEmpty as NE
87import Network.Wai.Application.Static (defaultFileServerSettings,
98 staticApp)
10−import Network.Wai.Handler.Warp (run)
9+import qualified Network.Wai.Handler.Warp as Warp
1110import Test.Hspec
1211
13−import qualified JSONSchema.Draft4 as D4
14−import qualified JSONSchema.Types as JT
12+import qualified JSONSchema.Draft4 as D4
13+import qualified JSONSchema.Types as JT
1514import Shared
1615
1716-- Examples
@@ -52,7 +51,7 @@ main = withAsync serve $ \_ -> do
5251 assertResult sc failures
5352
5453serve :: IO ()
55−serve = run 1234
54+serve = Warp.run 1234
5655 . staticApp
5756 . defaultFileServerSettings
5857 $ "JSON-Schema-Test-Suite/remotes"
test/Shared.hs+18−20
@@ -1,19 +1,29 @@
1−
21module Shared where
32
43import Protolude
54
6−import Control.Monad (fail)
5+import Control.Monad (fail)
76import Data.Aeson
8−import Data.Aeson.TH (fieldLabelModifier)
9−import qualified Data.ByteString as BS
10−import Data.Char (toLower)
11−import Data.List (stripPrefix, unlines)
12−import qualified Data.Text as T
7+import Data.Aeson.TH (fieldLabelModifier)
8+import qualified Data.ByteString as BS
9+import Data.Char (toLower)
10+import Data.List (stripPrefix, unlines)
11+import qualified Data.Text as T
1312import qualified System.Directory as SD
14−import System.FilePath ((</>))
13+import System.FilePath ((</>))
1514import Test.Hspec
1615
16+skipTest :: FilePath -> Bool
17+skipTest file = (file == "optional/format.json") -- Optional
18+ || (file == "optional/zeroTerminatedFloats.json")
19+ || (file == "optional/ecmascript-regex.json")
20+
21+
22+isHTTPTest :: FilePath -> Bool
23+isHTTPTest file = (file == "definitions.json")
24+ || (file == "ref.json")
25+ || (file == "refRemote.json")
26+
1727-- Recursively return the contents of a directory
1828-- (or return itself if given a file as an argument).
1929--
@@ -37,18 +47,6 @@ listFilesFullPath path = do
3747 fs <- fmap (path </>) <$> SD.listDirectory path
3848 concat <$> traverse listFilesFullPath fs
3949
40−isHTTPTest :: FilePath -> Bool
41−isHTTPTest file = (file == "definitions.json")
42− || (file == "ref.json")
43− || (file == "refRemote.json")
44−
45−-- | We may never support the @"format"@ keywords
46−-- and are currently failing the others listed here.
47−skipOptional :: FilePath -> Bool
48−skipOptional file = (file == "optional/format.json")
49− || (file == "optional/zeroTerminatedFloats.json")
50− || (file == "optional/ecmascript-regex.json")
51−
5250data SchemaTest = SchemaTest
5351 { _stDescription :: Text
5452 , _stSchema :: Value