fast-json-stringify 5.0.5 → 5.2.0

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.
package/standalone.js CHANGED
@@ -1,28 +1,28 @@
1
1
  const fs = require('fs')
2
2
  const path = require('path')
3
3
 
4
- function buildStandaloneCode (options, ajvInstance, contextFunctionCode) {
4
+ function buildStandaloneCode (options, validator, contextFunctionCode) {
5
5
  const serializerCode = fs.readFileSync(path.join(__dirname, 'serializer.js')).toString()
6
6
  let buildAjvCode = ''
7
7
  let defaultAjvSchema = ''
8
- const defaultMeta = ajvInstance.defaultMeta()
8
+ const defaultMeta = validator.ajv.defaultMeta()
9
9
  if (typeof defaultMeta === 'string') {
10
10
  defaultAjvSchema = defaultMeta
11
11
  } else {
12
12
  defaultAjvSchema = defaultMeta.$id || defaultMeta.id
13
13
  }
14
- const shouldUseAjv = contextFunctionCode.indexOf('ajv') !== -1
14
+ const shouldUseAjv = contextFunctionCode.indexOf('validator') !== -1
15
15
  // we need to export the custom json schema
16
16
  let ajvSchemasCode = ''
17
17
  if (shouldUseAjv) {
18
- ajvSchemasCode += `const ajv = buildAjv(${JSON.stringify(options.ajv || {})})\n`
19
- for (const [id, schema] of Object.entries(ajvInstance.schemas)) {
18
+ ajvSchemasCode += `const validator = new Validator(${JSON.stringify(options.ajv || {})})\n`
19
+ for (const [id, schema] of Object.entries(validator.ajv.schemas)) {
20
20
  // should skip ajv default schema
21
21
  if (id === defaultAjvSchema) continue
22
- ajvSchemasCode += `ajv.addSchema(${JSON.stringify(schema.schema)}, "${id}")\n`
22
+ ajvSchemasCode += `validator.ajv.addSchema(${JSON.stringify(schema.schema)}, "${id}")\n`
23
23
  }
24
- buildAjvCode = fs.readFileSync(path.join(__dirname, 'ajv.js')).toString()
25
- buildAjvCode = buildAjvCode.replace("'use strict'", '').replace('module.exports = buildAjv', '')
24
+ buildAjvCode = fs.readFileSync(path.join(__dirname, 'validator.js')).toString()
25
+ buildAjvCode = buildAjvCode.replace("'use strict'", '').replace('module.exports = SchemaValidator', '')
26
26
  }
27
27
  return `
28
28
  'use strict'
@@ -359,3 +359,16 @@ test('render a single quote as JSON', (t) => {
359
359
  t.equal(output, JSON.stringify(toStringify))
360
360
  t.ok(validate(JSON.parse(output)), 'valid schema')
361
361
  })
362
+
363
+ test('returns JSON.stringify if schema type is boolean', t => {
364
+ t.plan(1)
365
+
366
+ const schema = {
367
+ type: 'array',
368
+ items: true
369
+ }
370
+
371
+ const array = [1, true, 'test']
372
+ const stringify = build(schema)
373
+ t.equal(stringify(array), JSON.stringify(array))
374
+ })
@@ -24,6 +24,184 @@ test('schema with const string', (t) => {
24
24
  t.ok(validate(JSON.parse(output)), 'valid schema')
25
25
  })
26
26
 
27
+ test('schema with const string and different input', (t) => {
28
+ t.plan(2)
29
+
30
+ const schema = {
31
+ type: 'object',
32
+ properties: {
33
+ foo: { const: 'bar' }
34
+ }
35
+ }
36
+
37
+ const validate = validator(schema)
38
+ const stringify = build(schema)
39
+ const output = stringify({
40
+ foo: 'baz'
41
+ })
42
+
43
+ t.equal(output, '{"foo":"bar"}')
44
+ t.ok(validate(JSON.parse(output)), 'valid schema')
45
+ })
46
+
47
+ test('schema with const string and different type input', (t) => {
48
+ t.plan(2)
49
+
50
+ const schema = {
51
+ type: 'object',
52
+ properties: {
53
+ foo: { const: 'bar' }
54
+ }
55
+ }
56
+
57
+ const validate = validator(schema)
58
+ const stringify = build(schema)
59
+ const output = stringify({
60
+ foo: 1
61
+ })
62
+
63
+ t.equal(output, '{"foo":"bar"}')
64
+ t.ok(validate(JSON.parse(output)), 'valid schema')
65
+ })
66
+
67
+ test('schema with const string and no input', (t) => {
68
+ t.plan(2)
69
+
70
+ const schema = {
71
+ type: 'object',
72
+ properties: {
73
+ foo: { const: 'bar' }
74
+ }
75
+ }
76
+
77
+ const validate = validator(schema)
78
+ const stringify = build(schema)
79
+ const output = stringify({})
80
+
81
+ t.equal(output, '{}')
82
+ t.ok(validate(JSON.parse(output)), 'valid schema')
83
+ })
84
+
85
+ test('schema with const number', (t) => {
86
+ t.plan(2)
87
+
88
+ const schema = {
89
+ type: 'object',
90
+ properties: {
91
+ foo: { const: 1 }
92
+ }
93
+ }
94
+
95
+ const validate = validator(schema)
96
+ const stringify = build(schema)
97
+ const output = stringify({
98
+ foo: 1
99
+ })
100
+
101
+ t.equal(output, '{"foo":1}')
102
+ t.ok(validate(JSON.parse(output)), 'valid schema')
103
+ })
104
+
105
+ test('schema with const number and different input', (t) => {
106
+ t.plan(2)
107
+
108
+ const schema = {
109
+ type: 'object',
110
+ properties: {
111
+ foo: { const: 1 }
112
+ }
113
+ }
114
+
115
+ const validate = validator(schema)
116
+ const stringify = build(schema)
117
+ const output = stringify({
118
+ foo: 2
119
+ })
120
+
121
+ t.equal(output, '{"foo":1}')
122
+ t.ok(validate(JSON.parse(output)), 'valid schema')
123
+ })
124
+
125
+ test('schema with const bool', (t) => {
126
+ t.plan(2)
127
+
128
+ const schema = {
129
+ type: 'object',
130
+ properties: {
131
+ foo: { const: true }
132
+ }
133
+ }
134
+
135
+ const validate = validator(schema)
136
+ const stringify = build(schema)
137
+ const output = stringify({
138
+ foo: true
139
+ })
140
+
141
+ t.equal(output, '{"foo":true}')
142
+ t.ok(validate(JSON.parse(output)), 'valid schema')
143
+ })
144
+
145
+ test('schema with const number', (t) => {
146
+ t.plan(2)
147
+
148
+ const schema = {
149
+ type: 'object',
150
+ properties: {
151
+ foo: { const: 1 }
152
+ }
153
+ }
154
+
155
+ const validate = validator(schema)
156
+ const stringify = build(schema)
157
+ const output = stringify({
158
+ foo: 1
159
+ })
160
+
161
+ t.equal(output, '{"foo":1}')
162
+ t.ok(validate(JSON.parse(output)), 'valid schema')
163
+ })
164
+
165
+ test('schema with const null', (t) => {
166
+ t.plan(2)
167
+
168
+ const schema = {
169
+ type: 'object',
170
+ properties: {
171
+ foo: { const: null }
172
+ }
173
+ }
174
+
175
+ const validate = validator(schema)
176
+ const stringify = build(schema)
177
+ const output = stringify({
178
+ foo: null
179
+ })
180
+
181
+ t.equal(output, '{"foo":null}')
182
+ t.ok(validate(JSON.parse(output)), 'valid schema')
183
+ })
184
+
185
+ test('schema with const array', (t) => {
186
+ t.plan(2)
187
+
188
+ const schema = {
189
+ type: 'object',
190
+ properties: {
191
+ foo: { const: [1, 2, 3] }
192
+ }
193
+ }
194
+
195
+ const validate = validator(schema)
196
+ const stringify = build(schema)
197
+ const output = stringify({
198
+ foo: [1, 2, 3]
199
+ })
200
+
201
+ t.equal(output, '{"foo":[1,2,3]}')
202
+ t.ok(validate(JSON.parse(output)), 'valid schema')
203
+ })
204
+
27
205
  test('schema with const object', (t) => {
28
206
  t.plan(2)
29
207
 
@@ -44,6 +222,56 @@ test('schema with const object', (t) => {
44
222
  t.ok(validate(JSON.parse(output)), 'valid schema')
45
223
  })
46
224
 
225
+ test('schema with const and null as type', (t) => {
226
+ t.plan(4)
227
+
228
+ const schema = {
229
+ type: 'object',
230
+ properties: {
231
+ foo: { type: ['string', 'null'], const: 'baz' }
232
+ }
233
+ }
234
+
235
+ const validate = validator(schema)
236
+ const stringify = build(schema)
237
+ const output = stringify({
238
+ foo: null
239
+ })
240
+
241
+ t.equal(output, '{"foo":null}')
242
+ t.ok(validate(JSON.parse(output)), 'valid schema')
243
+
244
+ const output2 = stringify({ foo: 'baz' })
245
+ t.equal(output2, '{"foo":"baz"}')
246
+ t.ok(validate(JSON.parse(output2)), 'valid schema')
247
+ })
248
+
249
+ test('schema with const as nullable', (t) => {
250
+ t.plan(4)
251
+
252
+ const schema = {
253
+ type: 'object',
254
+ properties: {
255
+ foo: { nullable: true, const: 'baz' }
256
+ }
257
+ }
258
+
259
+ const validate = validator(schema)
260
+ const stringify = build(schema)
261
+ const output = stringify({
262
+ foo: null
263
+ })
264
+
265
+ t.equal(output, '{"foo":null}')
266
+ t.ok(validate(JSON.parse(output)), 'valid schema')
267
+
268
+ const output2 = stringify({
269
+ foo: 'baz'
270
+ })
271
+ t.equal(output2, '{"foo":"baz"}')
272
+ t.ok(validate(JSON.parse(output2)), 'valid schema')
273
+ })
274
+
47
275
  test('schema with const and invalid object', (t) => {
48
276
  t.plan(2)
49
277
 
@@ -55,13 +283,12 @@ test('schema with const and invalid object', (t) => {
55
283
  required: ['foo']
56
284
  }
57
285
 
286
+ const validate = validator(schema)
58
287
  const stringify = build(schema)
59
- try {
60
- stringify({
61
- foo: { foo: 'baz' }
62
- })
63
- } catch (err) {
64
- t.match(err.message, /^Item .* does not match schema definition/, 'Given object has invalid const value')
65
- t.ok(err)
66
- }
288
+ const result = stringify({
289
+ foo: { foo: 'baz' }
290
+ })
291
+
292
+ t.equal(result, '{"foo":{"foo":"bar"}}')
293
+ t.ok(validate(JSON.parse(result)), 'valid schema')
67
294
  })
package/test/date.test.js CHANGED
@@ -308,7 +308,7 @@ test('serializing null value', t => {
308
308
  })
309
309
 
310
310
  t.test('type::array', t => {
311
- t.plan(3)
311
+ t.plan(6)
312
312
 
313
313
  t.test('format::date-time', t => {
314
314
  t.plan(2)
@@ -348,13 +348,13 @@ test('serializing null value', t => {
348
348
  t.notOk(validate(JSON.parse(output)), 'an empty string is not a date format')
349
349
  })
350
350
 
351
- t.test('format::time', t => {
351
+ t.test('format::date', t => {
352
352
  t.plan(2)
353
353
 
354
354
  const prop = {
355
355
  updatedAt: {
356
356
  type: ['string'],
357
- format: 'time'
357
+ format: 'date'
358
358
  }
359
359
  }
360
360
 
@@ -364,7 +364,66 @@ test('serializing null value', t => {
364
364
  } = serialize(createSchema(prop), input)
365
365
 
366
366
  t.equal(output, '{"updatedAt":""}')
367
- t.notOk(validate(JSON.parse(output)), 'an empty string is not a time format')
367
+ t.notOk(validate(JSON.parse(output)), 'an empty string is not a date format')
368
+ })
369
+
370
+ t.test('format::time, Date object', t => {
371
+ t.plan(1)
372
+
373
+ const schema = {
374
+ oneOf: [
375
+ {
376
+ type: 'object',
377
+ properties: {
378
+ updatedAt: {
379
+ type: ['string', 'number'],
380
+ format: 'time'
381
+ }
382
+ }
383
+ }
384
+ ]
385
+ }
386
+
387
+ const date = new Date()
388
+ const input = { updatedAt: date }
389
+ const { output } = serialize(schema, input)
390
+
391
+ t.equal(output, JSON.stringify({ updatedAt: DateTime.fromJSDate(date).toFormat('HH:mm:ss') }))
392
+ })
393
+
394
+ t.test('format::time, Date object', t => {
395
+ t.plan(1)
396
+
397
+ const schema = {
398
+ oneOf: [
399
+ {
400
+ type: ['string', 'number'],
401
+ format: 'time'
402
+ }
403
+ ]
404
+ }
405
+
406
+ const date = new Date()
407
+ const { output } = serialize(schema, date)
408
+
409
+ t.equal(output, `"${DateTime.fromJSDate(date).toFormat('HH:mm:ss')}"`)
410
+ })
411
+
412
+ t.test('format::time, Date object', t => {
413
+ t.plan(1)
414
+
415
+ const schema = {
416
+ oneOf: [
417
+ {
418
+ type: ['string', 'number'],
419
+ format: 'time'
420
+ }
421
+ ]
422
+ }
423
+
424
+ const { output } = serialize(schema, 42)
425
+
426
+ t.equal(output, JSON.stringify(42))
368
427
  })
369
428
  })
370
429
 
@@ -429,3 +488,40 @@ test('serializing null value', t => {
429
488
  })
430
489
  })
431
490
  })
491
+
492
+ test('Validate Date object as string type', (t) => {
493
+ t.plan(1)
494
+
495
+ const schema = {
496
+ oneOf: [
497
+ { type: 'string' }
498
+ ]
499
+ }
500
+ const toStringify = new Date()
501
+
502
+ const stringify = build(schema)
503
+ const output = stringify(toStringify)
504
+
505
+ t.equal(output, JSON.stringify(toStringify))
506
+ })
507
+
508
+ test('nullable date', (t) => {
509
+ t.plan(1)
510
+
511
+ const schema = {
512
+ anyOf: [
513
+ {
514
+ format: 'date',
515
+ type: 'string',
516
+ nullable: true
517
+ }
518
+ ]
519
+ }
520
+
521
+ const stringify = build(schema)
522
+
523
+ const data = new Date()
524
+ const result = stringify(data)
525
+
526
+ t.same(result, `"${DateTime.fromJSDate(data).toISODate()}"`)
527
+ })
@@ -2,7 +2,9 @@
2
2
 
3
3
  const test = require('tap').test
4
4
  const fjs = require('..')
5
+
5
6
  const Ajv = require('ajv').default
7
+ const Validator = require('../validator')
6
8
 
7
9
  function build (opts) {
8
10
  return fjs({
@@ -18,31 +20,34 @@ function build (opts) {
18
20
  }
19
21
 
20
22
  test('activate debug mode', t => {
21
- t.plan(3)
23
+ t.plan(4)
22
24
  const debugMode = build({ debugMode: true })
23
25
 
24
26
  t.type(debugMode, 'object')
25
27
  t.ok(debugMode.ajv instanceof Ajv)
28
+ t.ok(debugMode.validator instanceof Validator)
26
29
  t.type(debugMode.code, 'string')
27
30
  })
28
31
 
29
32
  test('activate debug mode truthy', t => {
30
- t.plan(3)
33
+ t.plan(4)
31
34
 
32
35
  const debugMode = build({ debugMode: 'yes' })
33
36
 
34
37
  t.type(debugMode, 'object')
35
38
  t.type(debugMode.code, 'string')
36
39
  t.ok(debugMode.ajv instanceof Ajv)
40
+ t.ok(debugMode.validator instanceof Validator)
37
41
  })
38
42
 
39
43
  test('to string auto-consistent', t => {
40
- t.plan(4)
44
+ t.plan(5)
41
45
  const debugMode = build({ debugMode: 1 })
42
46
 
43
47
  t.type(debugMode, 'object')
44
48
  t.type(debugMode.code, 'string')
45
49
  t.ok(debugMode.ajv instanceof Ajv)
50
+ t.ok(debugMode.validator instanceof Validator)
46
51
 
47
52
  const compiled = fjs.restore(debugMode)
48
53
  const tobe = JSON.stringify({ firstName: 'Foo' })
@@ -50,7 +55,7 @@ test('to string auto-consistent', t => {
50
55
  })
51
56
 
52
57
  test('to string auto-consistent with ajv', t => {
53
- t.plan(4)
58
+ t.plan(5)
54
59
 
55
60
  const debugMode = fjs({
56
61
  title: 'object with multiple types field',
@@ -69,6 +74,7 @@ test('to string auto-consistent with ajv', t => {
69
74
  t.type(debugMode, 'object')
70
75
  t.type(debugMode.code, 'string')
71
76
  t.ok(debugMode.ajv instanceof Ajv)
77
+ t.ok(debugMode.validator instanceof Validator)
72
78
 
73
79
  const compiled = fjs.restore(debugMode)
74
80
  const tobe = JSON.stringify({ str: 'Foo' })
@@ -444,3 +444,100 @@ test('large array of nullable booleans with default mechanism', (t) => {
444
444
  t.same(result, JSON.stringify(data))
445
445
  t.same(JSON.parse(result), data)
446
446
  })
447
+
448
+ test('nullable type in the schema', (t) => {
449
+ t.plan(2)
450
+
451
+ const schema = {
452
+ type: ['object', 'null'],
453
+ properties: {
454
+ foo: {
455
+ type: 'string'
456
+ }
457
+ }
458
+ }
459
+
460
+ const stringify = build(schema)
461
+
462
+ const data = { foo: 'bar' }
463
+
464
+ t.same(stringify(data), JSON.stringify(data))
465
+ t.same(stringify(null), JSON.stringify(null))
466
+ })
467
+
468
+ test('throw an error if the value doesn\'t match the type', (t) => {
469
+ t.plan(2)
470
+
471
+ const schema = {
472
+ type: 'object',
473
+ additionalProperties: false,
474
+ required: ['data'],
475
+ properties: {
476
+ data: {
477
+ type: 'array',
478
+ minItems: 1,
479
+ items: {
480
+ oneOf: [
481
+ {
482
+ type: 'string'
483
+ },
484
+ {
485
+ type: 'number'
486
+ }
487
+ ]
488
+ }
489
+ }
490
+ }
491
+ }
492
+
493
+ const stringify = build(schema)
494
+
495
+ const validData = { data: [1, 'testing'] }
496
+ t.equal(stringify(validData), JSON.stringify(validData))
497
+
498
+ const invalidData = { data: [false, 'testing'] }
499
+ t.throws(() => stringify(invalidData))
500
+ })
501
+
502
+ test('nullable value in oneOf', (t) => {
503
+ t.plan(1)
504
+
505
+ const schema = {
506
+ type: 'object',
507
+ properties: {
508
+ data: {
509
+ oneOf: [
510
+ {
511
+ type: 'array',
512
+ items: {
513
+ type: 'object',
514
+ properties: {
515
+ id: { type: 'integer', minimum: 1 }
516
+ },
517
+ additionalProperties: false,
518
+ required: ['id']
519
+ }
520
+ },
521
+ {
522
+ type: 'array',
523
+ items: {
524
+ type: 'object',
525
+ properties: {
526
+ job: { type: 'string', nullable: true }
527
+ },
528
+ additionalProperties: false,
529
+ required: ['job']
530
+ }
531
+ }
532
+ ]
533
+ }
534
+ },
535
+ required: ['data'],
536
+ additionalProperties: false
537
+ }
538
+
539
+ const stringify = build(schema)
540
+
541
+ const data = { data: [{ job: null }] }
542
+ t.equal(stringify(data), JSON.stringify(data))
543
+ })
package/test/ref.test.js CHANGED
@@ -1926,3 +1926,58 @@ test('anyOf inside allOf', (t) => {
1926
1926
 
1927
1927
  t.equal(output, JSON.stringify(object))
1928
1928
  })
1929
+
1930
+ test('should resolve absolute $refs', (t) => {
1931
+ t.plan(1)
1932
+
1933
+ const externalSchema = {
1934
+ FooSchema: {
1935
+ $id: 'FooSchema',
1936
+ type: 'object',
1937
+ properties: {
1938
+ type: {
1939
+ anyOf: [
1940
+ { type: 'string', const: 'bar' },
1941
+ { type: 'string', const: 'baz' }
1942
+ ]
1943
+ }
1944
+ }
1945
+ }
1946
+ }
1947
+
1948
+ const schema = { $ref: 'FooSchema' }
1949
+
1950
+ const object = { type: 'bar' }
1951
+ const stringify = build(schema, { schema: externalSchema })
1952
+ const output = stringify(object)
1953
+
1954
+ t.equal(output, JSON.stringify(object))
1955
+ })
1956
+
1957
+ test('nested schema should overwrite anchor scope', (t) => {
1958
+ t.plan(2)
1959
+
1960
+ const externalSchema = {
1961
+ root: {
1962
+ $id: 'root',
1963
+ definitions: {
1964
+ subschema: {
1965
+ $id: 'subschema',
1966
+ definitions: {
1967
+ anchorSchema: {
1968
+ $id: '#anchor',
1969
+ type: 'string'
1970
+ }
1971
+ }
1972
+ }
1973
+ }
1974
+ }
1975
+ }
1976
+
1977
+ const data = 'test'
1978
+ const stringify = build({ $ref: 'subschema#anchor' }, { schema: externalSchema })
1979
+ const output = stringify(data)
1980
+
1981
+ t.equal(output, JSON.stringify(data))
1982
+ t.throws(() => build({ $ref: 'root#anchor' }, { schema: externalSchema }))
1983
+ })
@@ -438,6 +438,35 @@ test('object that is simultaneously a string and a json switched', (t) => {
438
438
  t.equal(valueObj, '{"simultaneously":{"foo":"hello"}}')
439
439
  })
440
440
 
441
+ test('class instance that is simultaneously a string and a json', (t) => {
442
+ t.plan(2)
443
+
444
+ const schema = {
445
+ type: 'object',
446
+ properties: {
447
+ simultaneously: {
448
+ type: ['string', 'object'],
449
+ properties: {
450
+ foo: { type: 'string' }
451
+ }
452
+ }
453
+ }
454
+ }
455
+
456
+ class Test {
457
+ toString () { return 'hello' }
458
+ }
459
+
460
+ const likeObjectId = new Test()
461
+
462
+ const stringify = build(schema)
463
+ const valueStr = stringify({ simultaneously: likeObjectId })
464
+ t.equal(valueStr, '{"simultaneously":"hello"}')
465
+
466
+ const valueObj = stringify({ simultaneously: { foo: likeObjectId } })
467
+ t.equal(valueObj, '{"simultaneously":{"foo":"hello"}}')
468
+ })
469
+
441
470
  test('should throw an error when type is array and object is null', (t) => {
442
471
  t.plan(1)
443
472
  const schema = {