Skip to content

Commit c5ef1dd

Browse files
Merge pull request Official support of Draft 2019-09 #78 (part of #67)
* feat: support $anchor keyword as $ref target * doc: claim (partial) support of draft 2019-09
2 parents 28e91a3 + 30539e7 commit c5ef1dd

File tree

4 files changed

+44
-14
lines changed

4 files changed

+44
-14
lines changed

CHANGELOG.MD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
### Added
99
- Draft 2019-09: support `$defs` as alternative to `definitions` keyword
1010
- Draft 2019-09: include other keywords alongside `$ref`
11+
- Draft 2019-09: support `$anchor` keyword as `$ref` target
12+
- Draft 2019-09: explicitly document unsupported keywords
1113
- introduce `hideSingleRootItem` prop for displaying only a single schema's properties
1214

1315
## [4.1.0] - 2019-11-26

README.md

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ npm i react-jsonschema-inspector
3232

3333
| Prop | Description |
3434
| --- | --- |
35-
| `schemas` (required) | Object: keys will be displayed in the root column, the values are expected to be independent JSON Schema definitions (compatible to Draft 4, 6 or 7) |
36-
| `referenceSchemas` | Array of objects: the entries are expected to be JSON Schema definitions with an absolute URI as `$id`/`id` (compatible to Draft 4, 6 or 7). These schemas will not be shown on the root column, but are used to resolve URI `$ref`-erences in any of the displayed `schemas` or in another entry of the `referenceSchemas` |
35+
| `schemas` (required) | Object: keys will be displayed in the root column, the values are expected to be independent JSON Schema definitions (compatible to Draft 4, 6, 7 or 2019-09) |
36+
| `referenceSchemas` | Array of objects: the entries are expected to be JSON Schema definitions with an absolute URI as `$id`/`id` (compatible to Draft 4, 6, 7 or 2019-09). These schemas will not be shown on the root column, but are used to resolve URI `$ref`-erences in any of the displayed `schemas` or in another entry of the `referenceSchemas` |
3737
| `hideSingleRootItem` | Boolean: flag indicating whether the properties of the single entry in the given `schemas` properties should be listed in the root column – in case of multiple entries in `schemas` this is being ignored |
3838
| `defaultSelectedItems` | Array of strings: each referring to the name of the selected item in the respective column (i.e. the first entry in this array should match one key in the `schemas` object) |
3939
| `onSelect` | Function: call-back being invoked after the selection changed. Receives two parameters: (1) the selection - as per the `defaultSelectedItems`, (2) an object containing the "columnData" - the full render information for all visible columns |
@@ -83,31 +83,41 @@ As output, the respective helper functions either return a single value or – i
8383

8484
## Compatibility
8585

86-
This component is compatible with JSON Schema Draft 7.
87-
It is also backwards-compatible with Drafts 4 and 6.
86+
This component supports JSON Schema Draft 2019-09.
87+
It is also backwards-compatible with Drafts 4, 6 and 7.
88+
89+
Please refer to the more detailed listing below regarding particular keywords.
8890

8991
### Structural Properties
9092

9193
| Property | Support | Description |
9294
| --- | --- |--- |
93-
| `$schema` | - | *ignored* (assumed to be compatible to JSON Schema Draft 4, 6 or 7) |
94-
| `$id` | Yes | allowed as sub-schema reference in `$ref` (as per Draft 6 and 7), but not displayed; *ignored* if specified anywhere but in the root schema or inside an entry in `definitions` |
95-
| `id` | Yes | allowed as sub-schema reference in `$ref` (as per Draft 4), but not displayed; *ignored* if specified anywhere but in the root schema or inside an entry in `definitions` or if `$id` is present |
96-
| `$ref` | Yes | used to look-up re-usable sub-schemas transparently (i.e. not displayed), supporting:<ul><li>`#` or the root `$id`/`id` value as root schema references,</li><li>`#/definitions/<name-of-definition>` or the respective `$id`/`id` value from within the `definitions` for sub-schemas,</li><li>absolute URIs are supported as long as those separate schemas are provided via the `referenceSchemas` prop (and their respective root `$id`/`id` matches the given `$ref`)</li><li>absolute URIs ending with `#/definitions/<name-of-definition>` are also supported via the `referenceSchemas` prop</li></ul> |
95+
| `$schema` | - | *ignored* (assumed to be compatible to JSON Schema Draft 4, 6, 7 or 2019-09) |
96+
| `$vocabulary` | - | *ignored* |
97+
| `$id` | Yes | allowed as sub-schema reference in `$ref` (as per Draft 6 upwards), but not displayed; *ignored* if specified anywhere but in the root schema or inside an entry in `$defs`/`definitions` |
98+
| `id` | Yes | allowed as sub-schema reference in `$ref` (as per Draft 4), but not displayed; *ignored* if specified anywhere but in the root schema or inside an entry in `$defs`/`definitions` or if `$id` is present |
99+
| `$anchor` | Yes | allowed as sub-schema reference in `$ref` (as per Draft 2019-09) when preceded by `#`, but not displayed; *ignored* if specified anywhere but in the root schema or inside an entry in `$defs`/`definitions` |
100+
| `$ref` | Yes | used to look-up re-usable sub-schemas transparently (i.e. not displayed), supporting:<ul><li>`#` or the root `$id`/`id` value as root schema references,</li><li>`#/$defs/<name-of-definition>`/`#/definitions/<name-of-definition>` or the respective `$id`/`id` value from within the `$defs`/`definitions` for sub-schemas,</li><li>absolute URIs are supported as long as those separate schemas are provided via the `referenceSchemas` prop (and their respective root `$id`/`id` matches the given `$ref`)</li><li>absolute URIs ending with `#/$defs/<name-of-definition>`/`#/definitions/<name-of-definition>` or `#<anchor>` are also supported via the `referenceSchemas` prop</li></ul> |
101+
| `$recursiveAnchor` | - | *ignored* |
102+
| `$recursiveRef` | - | *ignored* |
97103
| `$defs`| Yes | used to provide re-usable sub-schemas that are being referenced via `$ref` (only in the respective root schemas) (as per Draft 2019-09) |
98104
| `definitions`| Yes | used to provide re-usable sub-schemas that are being referenced via `$ref` (only in the respective root schemas) (as per Draft 4, 6 or 7) |
99105
| `properties`| Yes | used to populate the whole structure to be traversed |
100106
| `required` | Yes | used to add empty `properties` to structure if they are not also mentioned in `properties` directly |
101107
| `additionalProperties` | - | *ignored* |
102108
| `patternProperties` | - | *ignored* |
109+
| `propertyNames` | - | *ignored* |
110+
| `unevaluatedProperties` | - | *ignored* |
103111
| `items`| Partially | used to look-up `properties` of single kind of items in an array; however if `items` is an array of multiple sub-schemas they are being *ignored* |
104112
| `additionalItems`| Yes | used to look-up `properties` of kind of items in an array if `items` is not present or defined as an array (which is not supported itself), otherwise `additionalItems` are being *ignored* |
113+
| `unevaluatedItems` | - | *ignored* |
105114
| `allOf` | Yes | used to combine sub-schemas transparently |
106115
| `anyOf` | Yes | used to combine sub-schemas |
107116
| `oneOf` | Yes | used to combine sub-schemas |
108117
| `not` | - | *ignored* |
109118
| `contains` | - | *ignored* |
110119
| `dependencies` | - | *ignored* |
120+
| `dependentSchemas` | - | *ignored* |
111121
| `if` | - | *ignored* |
112122
| `then` | - | *ignored* |
113123
| `else` | - | *ignored* |
@@ -129,14 +139,16 @@ It is also backwards-compatible with Drafts 4 and 6.
129139
| `format` | Yes | without further explanations |
130140
| `multipleOf` | Yes | |
131141
| `minimum` | Yes | |
132-
| `exclusiveMinimum` | Yes | supported both as `number` per Draft 6 and 7 and `boolean` per Draft 4 |
142+
| `exclusiveMinimum` | Yes | supported both as `number` per Draft 6 upwards and `boolean` per Draft 4 |
133143
| `maximum` | Yes | |
134-
| `exclusiveMaximum` | Yes | supported both as `number` per Draft 6 and 7 and `boolean` per Draft 4 |
144+
| `exclusiveMaximum` | Yes | supported both as `number` per Draft 6 upwards and `boolean` per Draft 4 |
135145
| `required` | Yes | not on the individual items per default |
146+
| `dependentRequired` | - | *ignored* |
136147
| `minItems` | Yes | |
137148
| `maxItems` | Yes | |
138149
| `uniqueItems` | Yes | |
139-
| `propertyNames` | - | *ignored* |
150+
| `minContains` | - | *ignored* |
151+
| `maxContains` | - | *ignored* |
140152
| `minProperties` | - | *ignored* |
141153
| `maxProperties` | - | *ignored* |
142154

src/model/JsonSchema.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,22 @@ export class RefScope {
9999
// any alias provided within definitions will only be available as short-hand in this schema
100100
this.internalRefs.set(subAlias, subSchema);
101101
}
102+
// from JSON Schema Draft 2019-09: "$anchor" for plain text references (that should no longer be provided via $id)
103+
const anchor = definition.$anchor;
104+
if (anchor) {
105+
// any alias provided within definitions will only be available as short-hand in this schema
106+
this.internalRefs.set(`#${anchor}`, subSchema);
107+
}
102108
// can always reference schema in definitions by its path, starting from the empty fragment
103109
this.internalRefs.set(`#/${definitionsKeyword}/${key}`, subSchema);
104110
if (externalRefBase) {
105111
// the convention was fulfilled and the top-level schema defined an absolute URI as its "$id"
106112
// this allows referencing a schema in definitions by its path, starting from that URI
107113
this.externalRefs.set(`${externalRefBase}/${definitionsKeyword}/${key}`, subSchema);
114+
if (anchor) {
115+
// from JSON Schema Draft 2019-09: "$anchor" can also be used in combination with base URI
116+
this.externalRefs.set(`${externalRefBase}${anchor}`, subSchema);
117+
}
108118
}
109119
}
110120
});

test/model/JsonSchema.test.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,26 +149,32 @@ describe("constructed correctly()", () => {
149149
it("ignores $id/id values on $defs in external references", () => {
150150
const subSchemaA = { $id: "A-$id-value" };
151151
const subSchemaB = { id: "B-id-value" };
152+
const subSchemaC = { $anchor: "C-anchor-value" };
152153
const schema = {
153154
$id: "http://valid-uri.com/$id#",
154155
$defs: {
155156
A: subSchemaA,
156-
B: subSchemaB
157+
B: subSchemaB,
158+
C: subSchemaC
157159
}
158160
};
159161
const { scope } = new JsonSchema(schema, {});
160-
expect(scope.internalRefs.size).toBe(5);
162+
expect(scope.internalRefs.size).toBe(7);
161163
expect(scope.internalRefs.get("#").schema).toEqual(schema);
162164
expect(scope.internalRefs.get("#/$defs/A").schema).toEqual(subSchemaA);
163165
expect(scope.internalRefs.get("#/$defs/B").schema).toEqual(subSchemaB);
166+
expect(scope.internalRefs.get("#/$defs/C").schema).toEqual(subSchemaC);
164167
expect(scope.internalRefs.get("A-$id-value").schema).toEqual(subSchemaA);
165168
expect(scope.internalRefs.get("B-id-value").schema).toEqual(subSchemaB);
169+
expect(scope.internalRefs.get("#C-anchor-value").schema).toEqual(subSchemaC);
166170

167-
expect(scope.externalRefs.size).toBe(4);
171+
expect(scope.externalRefs.size).toBe(6);
168172
expect(scope.externalRefs.get("http://valid-uri.com/$id").schema).toEqual(schema);
169173
expect(scope.externalRefs.get("http://valid-uri.com/$id#").schema).toEqual(schema);
170174
expect(scope.externalRefs.get("http://valid-uri.com/$id#/$defs/A").schema).toEqual(subSchemaA);
171175
expect(scope.externalRefs.get("http://valid-uri.com/$id#/$defs/B").schema).toEqual(subSchemaB);
176+
expect(scope.externalRefs.get("http://valid-uri.com/$id#/$defs/C").schema).toEqual(subSchemaC);
177+
expect(scope.externalRefs.get("http://valid-uri.com/$id#C-anchor-value").schema).toEqual(subSchemaC);
172178
});
173179
});
174180
describe("RefScope.findSchemaInThisScope()", () => {

0 commit comments

Comments
 (0)