Skip to content

Commit 915867b

Browse files
mum-never-proudmcollinaEomm
authored
serializing null value crash fix (#219)
Co-authored-by: Matteo Collina <[email protected]> Co-authored-by: Manuel Spigolon <[email protected]>
1 parent 1241c5d commit 915867b

File tree

2 files changed

+213
-4
lines changed

2 files changed

+213
-4
lines changed

index.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ function $asBooleanNullable (bool) {
279279
function $asDatetime (date) {
280280
if (date instanceof Date) {
281281
return '"' + date.toISOString() + '"'
282-
} else if (typeof date.toISOString === 'function') {
282+
} else if (date && typeof date.toISOString === 'function') {
283283
return '"' + date.toISOString() + '"'
284284
} else {
285285
return $asString(date)
@@ -292,7 +292,7 @@ function $asDate (date) {
292292
var month = new Intl.DateTimeFormat('en', { month: '2-digit' }).format(date)
293293
var day = new Intl.DateTimeFormat('en', { day: '2-digit' }).format(date)
294294
return '"' + year + '-' + month + '-' + day + '"'
295-
} else if (typeof date.format === 'function') {
295+
} else if (date && typeof date.format === 'function') {
296296
return '"' + date.format('YYYY-MM-DD') + '"'
297297
} else {
298298
return $asString(date)
@@ -305,7 +305,7 @@ function $asTime (date) {
305305
var minute = new Intl.DateTimeFormat('en', { minute: 'numeric' }).format(date)
306306
var second = new Intl.DateTimeFormat('en', { second: 'numeric' }).format(date)
307307
return '"' + $pad2Zeros(hour) + ':' + $pad2Zeros(minute) + ':' + $pad2Zeros(second) + '"'
308-
} else if (typeof date.format === 'function') {
308+
} else if (date && typeof date.format === 'function') {
309309
return '"' + date.format('HH:mm:ss') + '"'
310310
} else {
311311
return $asString(date)
@@ -1077,9 +1077,10 @@ function nested (laterCode, name, key, schema, externalSchema, fullSchema, subKe
10771077
sortedTypes.forEach((type, index) => {
10781078
var tempSchema = Object.assign({}, schema, { type })
10791079
var nestedResult = nested(laterCode, name, key, tempSchema, externalSchema, fullSchema, subKey)
1080+
10801081
if (type === 'string') {
10811082
code += `
1082-
${index === 0 ? 'if' : 'else if'}(typeof obj${accessor} === "${type}" || obj${accessor} instanceof Date || typeof obj${accessor}.toISOString === "function" || obj${accessor} instanceof RegExp)
1083+
${index === 0 ? 'if' : 'else if'}(obj${accessor} === null || typeof obj${accessor} === "${type}" || obj${accessor} instanceof Date || typeof obj${accessor}.toISOString === "function" || obj${accessor} instanceof RegExp)
10831084
${nestedResult.code}
10841085
`
10851086
} else if (type === 'null') {

test/date.test.js

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,211 @@ test('render a nested object in a string when type is date-format as ISOString',
194194
t.equal(output, JSON.stringify(toStringify))
195195
t.ok(validate(JSON.parse(output)), 'valid schema')
196196
})
197+
198+
test('serializing null value', t => {
199+
const input = { updatedAt: null }
200+
201+
function createSchema (properties) {
202+
return {
203+
title: 'an object in a string',
204+
type: 'object',
205+
properties
206+
}
207+
}
208+
209+
function serialize (schema, input) {
210+
const validate = validator(schema)
211+
const stringify = build(schema)
212+
const output = stringify(input)
213+
214+
return {
215+
validate,
216+
output
217+
}
218+
}
219+
220+
t.plan(3)
221+
222+
t.test('type::string', t => {
223+
t.plan(3)
224+
225+
t.test('format::date-time', t => {
226+
t.plan(2)
227+
228+
const prop = {
229+
updatedAt: {
230+
type: 'string',
231+
format: 'date-time'
232+
}
233+
}
234+
235+
const {
236+
output,
237+
validate
238+
} = serialize(createSchema(prop), input)
239+
240+
t.equal(output, '{"updatedAt":""}')
241+
t.notOk(validate(JSON.parse(output)), 'an empty string is not a date-time format')
242+
})
243+
244+
t.test('format::date', t => {
245+
t.plan(2)
246+
247+
const prop = {
248+
updatedAt: {
249+
type: 'string',
250+
format: 'date'
251+
}
252+
}
253+
254+
const {
255+
output,
256+
validate
257+
} = serialize(createSchema(prop), input)
258+
259+
t.equal(output, '{"updatedAt":""}')
260+
t.notOk(validate(JSON.parse(output)), 'an empty string is not a date format')
261+
})
262+
263+
t.test('format::time', t => {
264+
t.plan(2)
265+
266+
const prop = {
267+
updatedAt: {
268+
type: 'string',
269+
format: 'time'
270+
}
271+
}
272+
273+
const {
274+
output,
275+
validate
276+
} = serialize(createSchema(prop), input)
277+
278+
t.equal(output, '{"updatedAt":""}')
279+
t.notOk(validate(JSON.parse(output)), 'an empty string is not a time format')
280+
})
281+
})
282+
283+
t.test('type::array', t => {
284+
t.plan(3)
285+
286+
t.test('format::date-time', t => {
287+
t.plan(2)
288+
289+
const prop = {
290+
updatedAt: {
291+
type: ['string'],
292+
format: 'date-time'
293+
}
294+
}
295+
296+
const {
297+
output,
298+
validate
299+
} = serialize(createSchema(prop), input)
300+
301+
t.equal(output, '{"updatedAt":""}')
302+
t.notOk(validate(JSON.parse(output)), 'an empty string is not a date-time format')
303+
})
304+
305+
t.test('format::date', t => {
306+
t.plan(2)
307+
308+
const prop = {
309+
updatedAt: {
310+
type: ['string'],
311+
format: 'date'
312+
}
313+
}
314+
315+
const {
316+
output,
317+
validate
318+
} = serialize(createSchema(prop), input)
319+
320+
t.equal(output, '{"updatedAt":""}')
321+
t.notOk(validate(JSON.parse(output)), 'an empty string is not a date format')
322+
})
323+
324+
t.test('format::time', t => {
325+
t.plan(2)
326+
327+
const prop = {
328+
updatedAt: {
329+
type: ['string'],
330+
format: 'time'
331+
}
332+
}
333+
334+
const {
335+
output,
336+
validate
337+
} = serialize(createSchema(prop), input)
338+
339+
t.equal(output, '{"updatedAt":""}')
340+
t.notOk(validate(JSON.parse(output)), 'an empty string is not a time format')
341+
})
342+
})
343+
344+
t.test('type::array::nullable', t => {
345+
t.plan(3)
346+
347+
t.test('format::date-time', t => {
348+
t.plan(2)
349+
350+
const prop = {
351+
updatedAt: {
352+
type: ['string', 'null'],
353+
format: 'date-time'
354+
}
355+
}
356+
357+
const {
358+
output,
359+
validate
360+
} = serialize(createSchema(prop), input)
361+
362+
t.equal(output, '{"updatedAt":null}')
363+
t.ok(validate(JSON.parse(output)), 'valid schema')
364+
})
365+
366+
t.test('format::date', t => {
367+
t.plan(2)
368+
369+
const prop = {
370+
updatedAt: {
371+
type: ['string', 'null'],
372+
format: 'date'
373+
}
374+
}
375+
376+
const {
377+
output,
378+
validate
379+
} = serialize(createSchema(prop), input)
380+
381+
t.equal(output, '{"updatedAt":null}')
382+
t.ok(validate(JSON.parse(output)), 'valid schema')
383+
})
384+
385+
t.test('format::time', t => {
386+
t.plan(2)
387+
388+
const prop = {
389+
updatedAt: {
390+
type: ['string', 'null'],
391+
format: 'time'
392+
}
393+
}
394+
395+
const {
396+
output,
397+
validate
398+
} = serialize(createSchema(prop), input)
399+
400+
t.equal(output, '{"updatedAt":null}')
401+
t.ok(validate(JSON.parse(output)), 'valid schema')
402+
})
403+
})
404+
})

0 commit comments

Comments
 (0)