diff --git a/README.md b/README.md index ff1f1460..01e309b5 100644 --- a/README.md +++ b/README.md @@ -590,6 +590,8 @@ Otherwise, instead of raising an error, null values will be coerced as follows: - `number` -> `0` - `string` -> `""` - `boolean` -> `false` +- `object` -> `{}` +- `array` -> `[]` #### Large Arrays diff --git a/index.js b/index.js index ea435369..20dd386b 100644 --- a/index.js +++ b/index.js @@ -560,10 +560,13 @@ function buildObject (context, location) { let functionCode = ` ` + const nullable = schema.nullable === true functionCode += ` // ${schemaRef} function ${functionName} (input) { const obj = ${toJSON('input')} + ${!nullable ? 'if (obj === null) return \'{}\'' : ''} + ${buildInnerObject(context, location)} } ` @@ -601,7 +604,9 @@ function buildArray (context, location) { // ${schemaRef} ` + const nullable = schema.nullable === true functionCode += ` + ${!nullable ? 'if (obj === null) return \'[]\'' : ''} if (!Array.isArray(obj)) { throw new TypeError(\`The value of '${schemaRef}' does not match schema definition.\`) } diff --git a/test/toJSON.test.js b/test/toJSON.test.js index 04ac2975..67429550 100644 --- a/test/toJSON.test.js +++ b/test/toJSON.test.js @@ -127,7 +127,7 @@ test('not fail on null sub-object declared nullable', (t) => { t.equal('{"product":null}', stringify(object)) }) -test('throw an error on non nullable null sub-object', (t) => { +test('on non nullable null sub-object it should coerce to {}', (t) => { t.plan(1) const stringify = build({ @@ -148,10 +148,12 @@ test('throw an error on non nullable null sub-object', (t) => { const object = { product: null } - t.throws(() => { stringify(object) }) + + const result = stringify(object) + t.equal(result, JSON.stringify({ product: {} })) }) -test('throw an error on non nullable null object', (t) => { +test('on non nullable null object it should coerce to {}', (t) => { t.plan(1) const stringify = build({ @@ -170,5 +172,32 @@ test('throw an error on non nullable null object', (t) => { } } }) - t.throws(() => { stringify(null) }) + + const result = stringify(null) + t.equal(result, '{}') +}) + +test('on non-nullable null object it should skip rendering, skipping required fields checks', (t) => { + t.plan(1) + + const stringify = build({ + title: 'simple object', + nullable: false, + type: 'object', + properties: { + product: { + nullable: false, + type: 'object', + properties: { + name: { + type: 'string' + } + } + } + }, + required: ['product'] + }) + + const result = stringify(null) + t.equal(result, '{}') }) diff --git a/test/typesArray.test.js b/test/typesArray.test.js index cac9b09e..920eb8e8 100644 --- a/test/typesArray.test.js +++ b/test/typesArray.test.js @@ -467,7 +467,7 @@ test('class instance that is simultaneously a string and a json', (t) => { t.equal(valueObj, '{"simultaneously":{"foo":"hello"}}') }) -test('should throw an error when type is array and object is null', (t) => { +test('should not throw an error when type is array and object is null, it should instead coerce to []', (t) => { t.plan(1) const schema = { type: 'object', @@ -482,7 +482,8 @@ test('should throw an error when type is array and object is null', (t) => { } const stringify = build(schema) - t.throws(() => stringify({ arr: null }), new TypeError('The value of \'#/properties/arr\' does not match schema definition.')) + const result = stringify({ arr: null }) + t.equal(result, JSON.stringify({ arr: [] })) }) test('should throw an error when type is array and object is not an array', (t) => {