@hyperjump/json-schema 1.6.5 → 1.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,134 @@
1
+ # Bundler Tests
2
+
3
+ The testing strategy used by this Test Suite is based on the concept that it
4
+ should be indistinguishable whether the user evaluated the schema using the
5
+ bundle or using individually loaded schemas. Test Runners should validate each
6
+ Test twice, once with all schemas loaded individually and again using just the
7
+ bundle. The Test passes if both evaluations produce identical output.
8
+
9
+ The accuracy of this testing approach is dependent on how detailed the output
10
+ is. It's recommended that Test Runner use a validator implementation that
11
+ supports the
12
+ ["verbose"](https://json-schema.org/draft/2020-12/json-schema-core#name-verbose)
13
+ official output format or something similarly detailed that can be used for
14
+ comparison.
15
+
16
+ ## Supported Dialects
17
+
18
+ Although the topic of bundling didn't appear in the spec until 2020-12, the
19
+ process described is applicable since `id` (now `$id`) was introduced in
20
+ draft-03. Test Cases in this Test Suite are designed to be compatible with as
21
+ many releases of JSON Schema as possible. They do not include a `$schema`
22
+ keyword so that implementations can run the same Test Suite for each dialect
23
+ they support. The Test Runner should define what dialect it's using to run the
24
+ Test Suite.
25
+
26
+ Since this Test Suite can be used for a variety of dialects, there are a couple
27
+ of options that can be used by Test Runners to filter out Test Cases that don't
28
+ apply to the dialect under test.
29
+
30
+ ## Test Case Components
31
+
32
+ ### description
33
+
34
+ A short description of what behavior the Test Case is covering.
35
+
36
+ ### compatibility
37
+
38
+ The `compatibility` option allows you to set which dialects the Test Case is
39
+ compatible with. Test Runners can use this value to filter out Test Cases that
40
+ don't apply the to dialect currently under test. Dialects are indicated by the
41
+ number corresponding to their release. Date-based releases use just the year.
42
+
43
+ If this option isn't present, it means the Test Case is compatible with draft-03
44
+ and above.
45
+
46
+ If this option is present with a number, the number indicates the minimum
47
+ release the Test Case is compatible with. This example indicates that the Test
48
+ Case is compatible with draft-07 and up.
49
+
50
+ **Example**: `"compatibility": "7"`
51
+
52
+ You can use a `<=` operator to indicate that the Test Case is compatible with
53
+ releases less then or equal to the given release. This example indicates that
54
+ the Test Case is compatible with 2019-09 and under.
55
+
56
+ **Example**: `"compatibility": "<=2019"`
57
+
58
+ You can use comma-separated values to indicate multiple constraints if needed.
59
+ This example indicates that the Test Case is compatible with releases between
60
+ draft-06 and 2019-09.
61
+
62
+ **Example**: `"compatibility": "6,<=2019"`
63
+
64
+ For convenience, you can use the `=` operator to indicate a Test Case is only
65
+ compatible with a single release. This example indicates that the Test Case is
66
+ compatible only with 2020-12.
67
+
68
+ **Example**: `"compatibility": "=2020"`
69
+
70
+ ### requiredDialects
71
+
72
+ Since 2020-12, it's been allowed to have bundles that include schemas using
73
+ dialects different from the parent schema. In order to test this, it's necessary
74
+ to have an external schema that declares a dialect with `$schema`. The
75
+ `requiredDialects` option can be included to tell the Test Runner which dialects
76
+ are required to run the Test Case other than the dialect under test. This option
77
+ is an array of numbers corresponding to release numbers. Date-based releases use
78
+ just the year.
79
+
80
+ **Example**: `"requiredDialects": [2019]`
81
+
82
+ ### schema
83
+
84
+ The schema that will serve as the entry point of the bundle. This schema
85
+ shouldn't include `$schema` or `id`/`$id` because Test Cases should be designed
86
+ to work with as many releases as possible.
87
+
88
+ ### externalSchemas
89
+
90
+ `externalSchemas` is where you define the schemas that the schema in `schema`
91
+ references and you expect to get embedded into the bundled schema. The value is
92
+ an object where the keys are retrieval URIs and values are schemas. Most
93
+ external schemas aren't self identifying (using `id`/`$id`) and rely solely on
94
+ the retrieval URI for identification. This is done to increase the number of
95
+ dialects that the test is compatible with. Because `id` changed to `$id` in
96
+ draft-06, if you use `$id`, the test becomes incompatible with draft-03/4 and in
97
+ most cases, that's not necessary.
98
+
99
+ ### tests
100
+
101
+ `tests` are a collection of Tests to run to verify the Test Case. Tests don't
102
+ include an expected pass/fail for the instance because we don't care if the
103
+ instance is valid or not, we care only whether the bundle produces the same
104
+ results as its unbundled equivalent.
105
+
106
+ Tests should be designed to expose potential differences between the bundled and
107
+ unbundled evaluations. You should have at least one Test that's expected to pass
108
+ to ensure that annotations are equivalent and at least one Test that's expected
109
+ to fail to ensure errors are equivalent.
110
+
111
+ ## Fixtures
112
+
113
+ Often we don't care what's in the externally referenced schemas and end up using
114
+ the same simple and generic schemas in a lot of tests. In order to reduce
115
+ duplication, there are a couple of generic schemas defined that test runners
116
+ should load in addition to `externalSchemas` for each Test Case.
117
+
118
+ Fixtures are expected to be simple, compatible with all dialects, and not
119
+ critical to understanding what is being tested. Anything that doesn't meet those
120
+ criteria is better off declared in `externalSchemas`.
121
+
122
+ ## Directory Structure
123
+
124
+ * tests - A directory containing the full Test Suite.
125
+ * tests.json - A Test Suite covering functionality in the latest spec release.
126
+ * legacy-tests.json - A Test Suite covering functionality that was removed in
127
+ a previous release. This is mostly adaptations of Test Cases that use `$id`
128
+ or `$defs` to cover the same functionality for older releases that use `id`
129
+ or `definitions`. Test Cases involving other removed keywords such as
130
+ `dependencies` and `recursiveRef` can be found here as well.
131
+ * fixtures - A collection of simple and reusable schemas
132
+ * string.schema.json
133
+ * number.schema.json
134
+ * ... etc
@@ -0,0 +1,57 @@
1
+ [
2
+ {
3
+ "description": "Use relative paths for files",
4
+ "schema": "main.schema.json",
5
+ "externalSchemas": [],
6
+ "bundledSchema": {
7
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
8
+
9
+ "type": "object",
10
+ "properties": {
11
+ "foo": { "$ref": "string.schema.json" }
12
+ },
13
+
14
+ "$defs": {
15
+ "string.schema.json": {
16
+ "$id": "string.schema.json",
17
+
18
+ "type": "string"
19
+ }
20
+ }
21
+ }
22
+ },
23
+ {
24
+ "description": "Allow mix of http and file if main is file",
25
+ "schema": "mixed-schemes.schema.json",
26
+ "externalSchemas": [
27
+ {
28
+ "$id": "https://bundler.hyperjump.io/number",
29
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
30
+
31
+ "type": "number"
32
+ }
33
+ ],
34
+ "bundledSchema": {
35
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
36
+
37
+ "type": "object",
38
+ "properties": {
39
+ "foo": { "$ref": "string.schema.json" },
40
+ "bar": { "$ref": "https://bundler.hyperjump.io/number" }
41
+ },
42
+
43
+ "$defs": {
44
+ "string.schema.json": {
45
+ "$id": "string.schema.json",
46
+
47
+ "type": "string"
48
+ },
49
+ "https://bundler.hyperjump.io/number": {
50
+ "$id": "https://bundler.hyperjump.io/number",
51
+
52
+ "type": "number"
53
+ }
54
+ }
55
+ }
56
+ }
57
+ ]
@@ -1,3 +1,4 @@
1
+ import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";
1
2
  import jsonStringify from "fastest-stable-stringify";
2
3
  import * as Schema from "../schema.js";
3
4
  import * as Instance from "../instance.js";
@@ -5,7 +6,13 @@ import * as Instance from "../instance.js";
5
6
 
6
7
  const id = "https://json-schema.org/keyword/enum";
7
8
 
8
- const compile = (schema) => Schema.value(schema).map(jsonStringify);
9
+ const compile = (schema) => pipe(
10
+ Schema.iter(schema),
11
+ asyncMap(Schema.value),
12
+ asyncMap(jsonStringify),
13
+ asyncCollectArray
14
+ );
15
+
9
16
  const interpret = (enum_, instance) => enum_.some((enumValue) => jsonStringify(Instance.value(instance)) === enumValue);
10
17
 
11
18
  export default { id, compile, interpret };
package/lib/schema.js CHANGED
@@ -259,6 +259,7 @@ export const toSchema = (schemaDoc, options = {}) => {
259
259
  const idToken = getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/id")
260
260
  || getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/draft-04/id");
261
261
  const anchorToken = getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/anchor");
262
+ const legacyAnchorToken = getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/draft-04/id");
262
263
  const dynamicAnchorToken = getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/dynamicAnchor");
263
264
  const legacyDynamicAnchorToken = getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/draft-2020-12/dynamicAnchor");
264
265
  const recursiveAnchorToken = getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/recursiveAnchor");
@@ -284,7 +285,14 @@ export const toSchema = (schemaDoc, options = {}) => {
284
285
  }
285
286
  } else {
286
287
  if (pointer in anchors) {
287
- value = { [anchorToken]: anchors[pointer], ...value };
288
+ if (anchorToken) {
289
+ value = { [anchorToken]: anchors[pointer], ...value };
290
+ }
291
+
292
+ // Legacy anchor
293
+ if (legacyAnchorToken) {
294
+ value = { [legacyAnchorToken]: `#${anchors[pointer]}`, ...value };
295
+ }
288
296
  }
289
297
  if (pointer in dynamicAnchors) {
290
298
  if (dynamicAnchorToken) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperjump/json-schema",
3
- "version": "1.6.5",
3
+ "version": "1.6.6",
4
4
  "description": "A JSON Schema validator with support for custom keywords, vocabularies, and dialects",
5
5
  "type": "module",
6
6
  "main": "./stable/index.js",