Skip to content

Commit 16a1bd4

Browse files
committed
fix(objectschema)!: omit id from schema returned by without + only
the methods without and only return new schema objects with the same id that was found on the original. In terms of schema reuse, this creates two different schemas with the same id which is technically invalid. Additionally, it was not possible to set the id property on an object schema that had properties defined. This problem originates from the setattribute function which will always set the attribute on the schema properties if they are defined. In the case of the object schema, this is almost always the case. This changes the id function on the object schema to always generate a new schema with the id set on the object schema rather than its properties BREAKING CHANGE: ObjectSchema.id() will always set the id on the root object BREAKING CHANGE: ObjectSchema.without() will omit id from the return schema BREAKING CHANGE: ObjectSchema.only() will omit id from the return schema
1 parent f62a218 commit 16a1bd4

File tree

4 files changed

+64
-16
lines changed

4 files changed

+64
-16
lines changed

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v12.14.0
1+
v14.19.0

docs/API.md

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,12 @@ it can be handy to arbitrary modify the schema injecting a fragment</p>
225225
<dt><a href="#ObjectSchema">ObjectSchema([options])</a> ⇒ <code><a href="#StringSchema">StringSchema</a></code></dt>
226226
<dd><p>Represents a ObjectSchema.</p>
227227
</dd>
228+
<dt><a href="#id">id(id)</a></dt>
229+
<dd><p>It defines a URI for the schema, and the base URI that other URI references within the schema are resolved against.
230+
Calling <code>id</code> on an ObjectSchema will alway set the id on the root of the object rather than in its &quot;properties&quot;, which
231+
differs from other schema types.</p>
232+
<p><a href="https://tools.ietf.org/html/draft-handrews-json-schema-01#section-8.2">reference</a></p>
233+
</dd>
228234
<dt><a href="#additionalProperties">additionalProperties(value)</a> ⇒ <code>FluentSchema</code></dt>
229235
<dd><p>This keyword determines how child instances validate for objects, and does not directly validate the immediate instance itself.
230236
Validation with &quot;additionalProperties&quot; applies only to the child values of instance names that do not match any names in &quot;properties&quot;,
@@ -276,10 +282,12 @@ Note the property name that the schema is testing will always be a string.</p>
276282
<p><a href="https://tools.ietf.org/id/draft-handrews-json-schema-validation-01.html#rfc.section.6.5.4">reference</a></p>
277283
</dd>
278284
<dt><a href="#only">only(properties)</a> ⇒ <code><a href="#ObjectSchema">ObjectSchema</a></code></dt>
279-
<dd><p>Returns an object schema with only a subset of keys provided</p>
285+
<dd><p>Returns an object schema with only a subset of keys provided. If called on an ObjectSchema with an
286+
<code>$id</code>, it will be removed and the return value will be considered a new schema.</p>
280287
</dd>
281288
<dt><a href="#without">without(properties)</a> ⇒ <code><a href="#ObjectSchema">ObjectSchema</a></code></dt>
282-
<dd><p>Returns an object schema without a subset of keys provided</p>
289+
<dd><p>Returns an object schema without a subset of keys provided. If called on an ObjectSchema with an
290+
<code>$id</code>, it will be removed and the return value will be considered a new schema.</p>
283291
</dd>
284292
<dt><a href="#definition">definition(name, props)</a> ⇒ <code>FluentSchema</code></dt>
285293
<dd><p>The &quot;definitions&quot; keywords provides a standardized location for schema authors to inline re-usable JSON Schemas into a more general schema.
@@ -951,6 +959,21 @@ Represents a ObjectSchema.
951959
| [options.schema] | [<code>StringSchema</code>](#StringSchema) | | Default schema |
952960
| [options.generateIds] | [<code>boolean</code>](#boolean) | <code>false</code> | generate the id automatically e.g. #properties.foo |
953961

962+
<a name="id"></a>
963+
964+
## id(id)
965+
It defines a URI for the schema, and the base URI that other URI references within the schema are resolved against.
966+
Calling `id` on an ObjectSchema will alway set the id on the root of the object rather than in its "properties", which
967+
differs from other schema types.
968+
969+
[reference](https://tools.ietf.org/html/draft-handrews-json-schema-01#section-8.2)
970+
971+
**Kind**: global function
972+
973+
| Param | Type | Description |
974+
| --- | --- | --- |
975+
| id | [<code>string</code>](#string) | an #id |
976+
954977
<a name="additionalProperties"></a>
955978

956979
## additionalProperties(value) ⇒ <code>FluentSchema</code>
@@ -1086,7 +1109,8 @@ The value of "properties" MUST be an object. Each value of this object MUST be a
10861109
<a name="only"></a>
10871110

10881111
## only(properties) ⇒ [<code>ObjectSchema</code>](#ObjectSchema)
1089-
Returns an object schema with only a subset of keys provided
1112+
Returns an object schema with only a subset of keys provided. If called on an ObjectSchema with an
1113+
`$id`, it will be removed and the return value will be considered a new schema.
10901114

10911115
**Kind**: global function
10921116

@@ -1097,7 +1121,8 @@ Returns an object schema with only a subset of keys provided
10971121
<a name="without"></a>
10981122

10991123
## without(properties) ⇒ [<code>ObjectSchema</code>](#ObjectSchema)
1100-
Returns an object schema without a subset of keys provided
1124+
Returns an object schema without a subset of keys provided. If called on an ObjectSchema with an
1125+
`$id`, it will be removed and the return value will be considered a new schema.
11011126

11021127
**Kind**: global function
11031128

src/ObjectSchema.js

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,21 @@ const ObjectSchema = ({ schema = initialState, ...options } = {}) => {
3636
return {
3737
...BaseSchema({ ...options, schema }),
3838

39+
/**
40+
* It defines a URI for the schema, and the base URI that other URI references within the schema are resolved against.
41+
* Calling `id` on an ObjectSchema will alway set the id on the root of the object rather than in its "properties", which
42+
* differs from other schema types.
43+
*
44+
* {@link https://tools.ietf.org/html/draft-handrews-json-schema-01#section-8.2|reference}
45+
* @param {string} id - an #id
46+
**/
47+
id: id => {
48+
if (!id)
49+
throw new FluentSchemaError(
50+
`id should not be an empty fragment <#> or an empty string <> (e.g. #myId)`
51+
)
52+
return options.factory({ schema: { ...schema, $id: id }, ...options })
53+
},
3954
/**
4055
* This keyword determines how child instances validate for objects, and does not directly validate the immediate instance itself.
4156
* Validation with "additionalProperties" applies only to the child values of instance names that do not match any names in "properties",
@@ -335,15 +350,16 @@ const ObjectSchema = ({ schema = initialState, ...options } = {}) => {
335350
},
336351

337352
/**
338-
* Returns an object schema with only a subset of keys provided
353+
* Returns an object schema with only a subset of keys provided. If called on an ObjectSchema with an
354+
* `$id`, it will be removed and the return value will be considered a new schema.
339355
*
340356
* @param properties a list of properties you want to keep
341357
* @returns {ObjectSchema}
342358
*/
343359
only: properties => {
344360
return ObjectSchema({
345361
schema: {
346-
...schema,
362+
...omit(schema, ['$id', 'properties']),
347363
properties: schema.properties.filter(({ name }) => properties.includes(name)),
348364
required: schema.required.filter(p => properties.includes(p))
349365
},
@@ -352,15 +368,16 @@ const ObjectSchema = ({ schema = initialState, ...options } = {}) => {
352368
},
353369

354370
/**
355-
* Returns an object schema without a subset of keys provided
371+
* Returns an object schema without a subset of keys provided. If called on an ObjectSchema with an
372+
* `$id`, it will be removed and the return value will be considered a new schema.
356373
*
357374
* @param properties a list of properties you dont want to keep
358375
* @returns {ObjectSchema}
359376
*/
360377
without: properties => {
361378
return ObjectSchema({
362379
schema: {
363-
...schema,
380+
...omit(schema, ['$id', 'properties']),
364381
properties: schema.properties.filter(({ name }) => !properties.includes(name)),
365382
required: schema.required.filter(p => !properties.includes(p))
366383
},

src/ObjectSchema.test.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@ describe('ObjectSchema', () => {
9393
type: 'object'
9494
})
9595
})
96+
it('invalid', () => {
97+
expect(() => {
98+
ObjectSchema().id('')
99+
}).toThrowError(
100+
new S.FluentSchemaError(
101+
'id should not be an empty fragment <#> or an empty string <> (e.g. #myId)'
102+
)
103+
)
104+
})
96105
})
97106
})
98107

@@ -213,14 +222,15 @@ describe('ObjectSchema', () => {
213222
describe('id', () => {
214223
it('valid', () => {
215224
const id = 'myId'
216-
const prop = 'prop'
217225
expect(
218226
ObjectSchema()
219227
.prop('prop')
220228
.id(id)
221-
.valueOf().properties[prop]
229+
.valueOf()
222230
).toEqual({
223-
$id: id
231+
$id: id,
232+
properties: {'prop': {}},
233+
type: 'object'
224234
})
225235
})
226236

@@ -915,7 +925,6 @@ describe('ObjectSchema', () => {
915925

916926
expect(only.valueOf()).toEqual({
917927
$schema: 'http://json-schema.org/draft-07/schema#',
918-
$id: 'base',
919928
title: 'base',
920929
properties: {
921930
foo: {
@@ -939,7 +948,6 @@ describe('ObjectSchema', () => {
939948

940949
expect(only.valueOf()).toEqual({
941950
$schema: 'http://json-schema.org/draft-07/schema#',
942-
$id: 'base',
943951
title: 'base',
944952
properties: {
945953
foo: {
@@ -974,7 +982,6 @@ describe('ObjectSchema', () => {
974982

975983
expect(without.valueOf()).toEqual({
976984
$schema: 'http://json-schema.org/draft-07/schema#',
977-
$id: 'base',
978985
title: 'base',
979986
properties: {
980987
bar: {
@@ -1001,7 +1008,6 @@ describe('ObjectSchema', () => {
10011008

10021009
expect(without.valueOf()).toEqual({
10031010
$schema: 'http://json-schema.org/draft-07/schema#',
1004-
$id: 'base',
10051011
title: 'base',
10061012
properties: {
10071013
baz: {

0 commit comments

Comments
 (0)