fast-json-stringify 5.2.0 → 5.4.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/.github/workflows/ci.yml +1 -0
- package/.taprc +7 -1
- package/{build-schema-validator.js → build/build-schema-validator.js} +1 -1
- package/{example.js → examples/example.js} +1 -1
- package/{server.js → examples/server.js} +1 -1
- package/index.d.ts +9 -8
- package/index.js +316 -375
- package/lib/location.js +55 -0
- package/{ref-resolver.js → lib/ref-resolver.js} +0 -0
- package/{schema-validator.js → lib/schema-validator.js} +0 -0
- package/{serializer.js → lib/serializer.js} +0 -36
- package/{standalone.js → lib/standalone.js} +12 -11
- package/{validator.js → lib/validator.js} +0 -0
- package/package.json +10 -6
- package/test/allof.test.js +45 -0
- package/test/anyof.test.js +20 -0
- package/test/array.test.js +43 -0
- package/test/date.test.js +19 -0
- package/test/debug-mode.test.js +18 -5
- package/test/if-then-else.test.js +50 -0
- package/test/ref.test.js +24 -0
- package/test/types/schema-inference.test-d.ts +48 -0
package/lib/location.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
class Location {
|
|
4
|
+
constructor (schema, schemaId, jsonPointer = '#', isValidated = false) {
|
|
5
|
+
this.schema = schema
|
|
6
|
+
this.schemaId = schemaId
|
|
7
|
+
this.jsonPointer = jsonPointer
|
|
8
|
+
this.isValidated = isValidated
|
|
9
|
+
this.mergedSchemaId = null
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
getPropertyLocation (propertyName) {
|
|
13
|
+
const propertyLocation = new Location(
|
|
14
|
+
this.schema[propertyName],
|
|
15
|
+
this.schemaId,
|
|
16
|
+
this.jsonPointer + '/' + propertyName,
|
|
17
|
+
this.isValidated
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
if (this.mergedSchemaId !== null) {
|
|
21
|
+
propertyLocation.addMergedSchema(
|
|
22
|
+
this.schema[propertyName],
|
|
23
|
+
this.mergedSchemaId,
|
|
24
|
+
this.jsonPointer + '/' + propertyName
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return propertyLocation
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Use this method to get current schema location.
|
|
32
|
+
// Use it when you need to create reference to the current location.
|
|
33
|
+
getSchemaId () {
|
|
34
|
+
return this.mergedSchemaId || this.schemaId
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Use this method to get original schema id for resolving user schema $refs
|
|
38
|
+
// Don't join it with a JSON pointer to get the current location.
|
|
39
|
+
getOriginSchemaId () {
|
|
40
|
+
return this.schemaId
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
getSchemaRef () {
|
|
44
|
+
const schemaId = this.getSchemaId()
|
|
45
|
+
return schemaId + this.jsonPointer
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
addMergedSchema (mergedSchema, schemaId, jsonPointer = '#') {
|
|
49
|
+
this.schema = mergedSchema
|
|
50
|
+
this.mergedSchemaId = schemaId
|
|
51
|
+
this.jsonPointer = jsonPointer
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = Location
|
|
File without changes
|
|
File without changes
|
|
@@ -18,14 +18,6 @@ module.exports = class Serializer {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
asAny (i) {
|
|
22
|
-
return JSON.stringify(i)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
asNull () {
|
|
26
|
-
return 'null'
|
|
27
|
-
}
|
|
28
|
-
|
|
29
21
|
asInteger (i) {
|
|
30
22
|
if (typeof i === 'bigint') {
|
|
31
23
|
return i.toString()
|
|
@@ -42,10 +34,6 @@ module.exports = class Serializer {
|
|
|
42
34
|
}
|
|
43
35
|
}
|
|
44
36
|
|
|
45
|
-
asIntegerNullable (i) {
|
|
46
|
-
return i === null ? 'null' : this.asInteger(i)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
37
|
asNumber (i) {
|
|
50
38
|
const num = Number(i)
|
|
51
39
|
if (Number.isNaN(num)) {
|
|
@@ -57,18 +45,10 @@ module.exports = class Serializer {
|
|
|
57
45
|
}
|
|
58
46
|
}
|
|
59
47
|
|
|
60
|
-
asNumberNullable (i) {
|
|
61
|
-
return i === null ? 'null' : this.asNumber(i)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
48
|
asBoolean (bool) {
|
|
65
49
|
return bool && 'true' || 'false' // eslint-disable-line
|
|
66
50
|
}
|
|
67
51
|
|
|
68
|
-
asBooleanNullable (bool) {
|
|
69
|
-
return bool === null ? 'null' : this.asBoolean(bool)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
52
|
asDateTime (date) {
|
|
73
53
|
if (date === null) return '""'
|
|
74
54
|
if (date instanceof Date) {
|
|
@@ -80,10 +60,6 @@ module.exports = class Serializer {
|
|
|
80
60
|
throw new Error(`The value "${date}" cannot be converted to a date-time.`)
|
|
81
61
|
}
|
|
82
62
|
|
|
83
|
-
asDateTimeNullable (date) {
|
|
84
|
-
return date === null ? 'null' : this.asDateTime(date)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
63
|
asDate (date) {
|
|
88
64
|
if (date === null) return '""'
|
|
89
65
|
if (date instanceof Date) {
|
|
@@ -95,10 +71,6 @@ module.exports = class Serializer {
|
|
|
95
71
|
throw new Error(`The value "${date}" cannot be converted to a date.`)
|
|
96
72
|
}
|
|
97
73
|
|
|
98
|
-
asDateNullable (date) {
|
|
99
|
-
return date === null ? 'null' : this.asDate(date)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
74
|
asTime (date) {
|
|
103
75
|
if (date === null) return '""'
|
|
104
76
|
if (date instanceof Date) {
|
|
@@ -110,10 +82,6 @@ module.exports = class Serializer {
|
|
|
110
82
|
throw new Error(`The value "${date}" cannot be converted to a time.`)
|
|
111
83
|
}
|
|
112
84
|
|
|
113
|
-
asTimeNullable (date) {
|
|
114
|
-
return date === null ? 'null' : this.asTime(date)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
85
|
asString (str) {
|
|
118
86
|
const quotes = '"'
|
|
119
87
|
if (str instanceof Date) {
|
|
@@ -133,10 +101,6 @@ module.exports = class Serializer {
|
|
|
133
101
|
}
|
|
134
102
|
}
|
|
135
103
|
|
|
136
|
-
asStringNullable (str) {
|
|
137
|
-
return str === null ? 'null' : this.asString(str)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
104
|
// magically escape strings for json
|
|
141
105
|
// relying on their charCodeAt
|
|
142
106
|
// everything below 32 needs JSON.stringify()
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
3
|
|
|
4
|
-
function buildStandaloneCode (options, validator, contextFunctionCode) {
|
|
4
|
+
function buildStandaloneCode (options, validator, isValidatorUsed, contextFunctionCode) {
|
|
5
5
|
const serializerCode = fs.readFileSync(path.join(__dirname, 'serializer.js')).toString()
|
|
6
6
|
let buildAjvCode = ''
|
|
7
|
-
let defaultAjvSchema = ''
|
|
8
|
-
const defaultMeta = validator.ajv.defaultMeta()
|
|
9
|
-
if (typeof defaultMeta === 'string') {
|
|
10
|
-
defaultAjvSchema = defaultMeta
|
|
11
|
-
} else {
|
|
12
|
-
defaultAjvSchema = defaultMeta.$id || defaultMeta.id
|
|
13
|
-
}
|
|
14
|
-
const shouldUseAjv = contextFunctionCode.indexOf('validator') !== -1
|
|
15
|
-
// we need to export the custom json schema
|
|
16
7
|
let ajvSchemasCode = ''
|
|
17
|
-
|
|
8
|
+
|
|
9
|
+
if (isValidatorUsed) {
|
|
10
|
+
let defaultAjvSchema = ''
|
|
11
|
+
// we need to export the custom json schema
|
|
12
|
+
const defaultMeta = validator.ajv.defaultMeta()
|
|
13
|
+
if (typeof defaultMeta === 'string') {
|
|
14
|
+
defaultAjvSchema = defaultMeta
|
|
15
|
+
} else {
|
|
16
|
+
defaultAjvSchema = defaultMeta.$id || defaultMeta.id
|
|
17
|
+
}
|
|
18
|
+
|
|
18
19
|
ajvSchemasCode += `const validator = new Validator(${JSON.stringify(options.ajv || {})})\n`
|
|
19
20
|
for (const [id, schema] of Object.entries(validator.ajv.schemas)) {
|
|
20
21
|
// should skip ajv default schema
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-json-stringify",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.4.0",
|
|
4
4
|
"description": "Stringify your JSON at max speed",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
"bench:cmp": "node ./benchmark/bench-cmp-branch.js",
|
|
10
10
|
"bench:cmp:ci": "node ./benchmark/bench-cmp-branch.js --ci",
|
|
11
11
|
"benchmark": "node ./benchmark/bench-cmp-lib.js",
|
|
12
|
+
"lint": "standard",
|
|
12
13
|
"lint:fix": "standard --fix",
|
|
13
|
-
"test:
|
|
14
|
-
"test:typescript": "tsc --project ./test/types/tsconfig.json",
|
|
14
|
+
"test:typescript": "tsc --project ./test/types/tsconfig.json && tsd",
|
|
15
15
|
"test:unit": "tap -J test/*.test.js test/**/*.test.js",
|
|
16
|
-
"test": "npm run test:
|
|
16
|
+
"test": "npm run test:unit && npm run test:typescript"
|
|
17
17
|
},
|
|
18
|
-
"precommit": "test",
|
|
18
|
+
"precommit": ["lint", "test"],
|
|
19
19
|
"repository": {
|
|
20
20
|
"type": "git",
|
|
21
21
|
"url": "git+https://github.com/fastify/fast-json-stringify.git"
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"simple-git": "^3.7.1",
|
|
46
46
|
"standard": "^17.0.0",
|
|
47
47
|
"tap": "^16.0.1",
|
|
48
|
+
"tsd": "^0.24.1",
|
|
48
49
|
"typescript": "^4.0.2",
|
|
49
50
|
"webpack": "^5.40.0"
|
|
50
51
|
},
|
|
@@ -61,5 +62,8 @@
|
|
|
61
62
|
"schema-validator.js"
|
|
62
63
|
]
|
|
63
64
|
},
|
|
64
|
-
"runkitExampleFilename": "example.js"
|
|
65
|
+
"runkitExampleFilename": "./examples/example.js",
|
|
66
|
+
"tsd": {
|
|
67
|
+
"directory": "test/types"
|
|
68
|
+
}
|
|
65
69
|
}
|
package/test/allof.test.js
CHANGED
|
@@ -437,3 +437,48 @@ test('object with external $refs in allOf', (t) => {
|
|
|
437
437
|
})
|
|
438
438
|
t.equal(value, '{"id1":1,"id2":2}')
|
|
439
439
|
})
|
|
440
|
+
|
|
441
|
+
test('allof with local anchor reference', (t) => {
|
|
442
|
+
t.plan(1)
|
|
443
|
+
|
|
444
|
+
const externalSchemas = {
|
|
445
|
+
Test: {
|
|
446
|
+
$id: 'Test',
|
|
447
|
+
definitions: {
|
|
448
|
+
Problem: {
|
|
449
|
+
type: 'object',
|
|
450
|
+
properties: {
|
|
451
|
+
type: {
|
|
452
|
+
type: 'string'
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
ValidationFragment: {
|
|
457
|
+
type: 'string'
|
|
458
|
+
},
|
|
459
|
+
ValidationErrorProblem: {
|
|
460
|
+
type: 'object',
|
|
461
|
+
allOf: [
|
|
462
|
+
{
|
|
463
|
+
$ref: '#/definitions/Problem'
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
type: 'object',
|
|
467
|
+
properties: {
|
|
468
|
+
validation: {
|
|
469
|
+
$ref: '#/definitions/ValidationFragment'
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
]
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const schema = { $ref: 'Test#/definitions/ValidationErrorProblem' }
|
|
480
|
+
const stringify = build(schema, { schema: externalSchemas })
|
|
481
|
+
const data = { type: 'foo', validation: 'bar' }
|
|
482
|
+
|
|
483
|
+
t.equal(stringify(data), JSON.stringify(data))
|
|
484
|
+
})
|
package/test/anyof.test.js
CHANGED
|
@@ -596,3 +596,23 @@ test('anyOf object with invalid field date of type string with format or null',
|
|
|
596
596
|
const withOneOfStringify = build(withOneOfSchema)
|
|
597
597
|
t.throws(() => withOneOfStringify({ prop: toStringify }))
|
|
598
598
|
})
|
|
599
|
+
|
|
600
|
+
test('anyOf with a nested external schema', (t) => {
|
|
601
|
+
t.plan(1)
|
|
602
|
+
|
|
603
|
+
const externalSchemas = {
|
|
604
|
+
schema1: {
|
|
605
|
+
definitions: {
|
|
606
|
+
def1: {
|
|
607
|
+
$id: 'external',
|
|
608
|
+
type: 'string'
|
|
609
|
+
}
|
|
610
|
+
},
|
|
611
|
+
type: 'number'
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
const schema = { anyOf: [{ $ref: 'external' }] }
|
|
615
|
+
|
|
616
|
+
const stringify = build(schema, { schema: externalSchemas })
|
|
617
|
+
t.equal(stringify('foo'), '"foo"')
|
|
618
|
+
})
|
package/test/array.test.js
CHANGED
|
@@ -4,6 +4,24 @@ const test = require('tap').test
|
|
|
4
4
|
const validator = require('is-my-json-valid')
|
|
5
5
|
const build = require('..')
|
|
6
6
|
|
|
7
|
+
test('error on invalid largeArrayMechanism', (t) => {
|
|
8
|
+
t.plan(1)
|
|
9
|
+
|
|
10
|
+
t.throws(() => build({
|
|
11
|
+
title: 'large array of null values with default mechanism',
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
ids: {
|
|
15
|
+
type: 'array',
|
|
16
|
+
items: { type: 'null' }
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}, {
|
|
20
|
+
largeArraySize: 2e4,
|
|
21
|
+
largeArrayMechanism: 'invalid'
|
|
22
|
+
}), Error('Unsupported large array mechanism invalid'))
|
|
23
|
+
})
|
|
24
|
+
|
|
7
25
|
function buildTest (schema, toStringify, options) {
|
|
8
26
|
test(`render a ${schema.title} as JSON`, (t) => {
|
|
9
27
|
t.plan(3)
|
|
@@ -327,6 +345,31 @@ test('object array with anyOf and symbol', (t) => {
|
|
|
327
345
|
t.equal(value, '[{"name":"name-0","option":"Foo"},{"name":"name-1","option":"Bar"}]')
|
|
328
346
|
})
|
|
329
347
|
|
|
348
|
+
test('different arrays with same item schemas', (t) => {
|
|
349
|
+
t.plan(1)
|
|
350
|
+
|
|
351
|
+
const schema = {
|
|
352
|
+
type: 'object',
|
|
353
|
+
properties: {
|
|
354
|
+
array1: {
|
|
355
|
+
type: 'array',
|
|
356
|
+
items: [{ type: 'string' }],
|
|
357
|
+
additionalItems: false
|
|
358
|
+
},
|
|
359
|
+
array2: {
|
|
360
|
+
type: 'array',
|
|
361
|
+
items: { $ref: '#/properties/array1/items' },
|
|
362
|
+
additionalItems: true
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const stringify = build(schema)
|
|
368
|
+
const data = { array1: ['bar'], array2: ['foo', 'bar'] }
|
|
369
|
+
|
|
370
|
+
t.equal(stringify(data), '{"array1":["bar"],"array2":["foo","bar"]}')
|
|
371
|
+
})
|
|
372
|
+
|
|
330
373
|
const largeArray = new Array(2e4).fill({ a: 'test', b: 1 })
|
|
331
374
|
buildTest({
|
|
332
375
|
title: 'large array with default mechanism',
|
package/test/date.test.js
CHANGED
|
@@ -525,3 +525,22 @@ test('nullable date', (t) => {
|
|
|
525
525
|
|
|
526
526
|
t.same(result, `"${DateTime.fromJSDate(data).toISODate()}"`)
|
|
527
527
|
})
|
|
528
|
+
|
|
529
|
+
test('non-date format should not affect data serialization (issue #491)', (t) => {
|
|
530
|
+
t.plan(1)
|
|
531
|
+
|
|
532
|
+
const schema = {
|
|
533
|
+
type: 'object',
|
|
534
|
+
properties: {
|
|
535
|
+
hello: {
|
|
536
|
+
type: 'string',
|
|
537
|
+
format: 'int64',
|
|
538
|
+
pattern: '^[0-9]*$'
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
const stringify = build(schema)
|
|
544
|
+
const data = { hello: 123n }
|
|
545
|
+
t.equal(stringify(data), '{"hello":"123"}')
|
|
546
|
+
})
|
package/test/debug-mode.test.js
CHANGED
|
@@ -4,7 +4,8 @@ const test = require('tap').test
|
|
|
4
4
|
const fjs = require('..')
|
|
5
5
|
|
|
6
6
|
const Ajv = require('ajv').default
|
|
7
|
-
const Validator = require('../validator')
|
|
7
|
+
const Validator = require('../lib/validator')
|
|
8
|
+
const Serializer = require('../lib/serializer')
|
|
8
9
|
|
|
9
10
|
function build (opts) {
|
|
10
11
|
return fjs({
|
|
@@ -20,17 +21,18 @@ function build (opts) {
|
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
test('activate debug mode', t => {
|
|
23
|
-
t.plan(
|
|
24
|
+
t.plan(5)
|
|
24
25
|
const debugMode = build({ debugMode: true })
|
|
25
26
|
|
|
26
27
|
t.type(debugMode, 'object')
|
|
27
28
|
t.ok(debugMode.ajv instanceof Ajv)
|
|
28
29
|
t.ok(debugMode.validator instanceof Validator)
|
|
30
|
+
t.ok(debugMode.serializer instanceof Serializer)
|
|
29
31
|
t.type(debugMode.code, 'string')
|
|
30
32
|
})
|
|
31
33
|
|
|
32
34
|
test('activate debug mode truthy', t => {
|
|
33
|
-
t.plan(
|
|
35
|
+
t.plan(5)
|
|
34
36
|
|
|
35
37
|
const debugMode = build({ debugMode: 'yes' })
|
|
36
38
|
|
|
@@ -38,15 +40,17 @@ test('activate debug mode truthy', t => {
|
|
|
38
40
|
t.type(debugMode.code, 'string')
|
|
39
41
|
t.ok(debugMode.ajv instanceof Ajv)
|
|
40
42
|
t.ok(debugMode.validator instanceof Validator)
|
|
43
|
+
t.ok(debugMode.serializer instanceof Serializer)
|
|
41
44
|
})
|
|
42
45
|
|
|
43
46
|
test('to string auto-consistent', t => {
|
|
44
|
-
t.plan(
|
|
47
|
+
t.plan(6)
|
|
45
48
|
const debugMode = build({ debugMode: 1 })
|
|
46
49
|
|
|
47
50
|
t.type(debugMode, 'object')
|
|
48
51
|
t.type(debugMode.code, 'string')
|
|
49
52
|
t.ok(debugMode.ajv instanceof Ajv)
|
|
53
|
+
t.ok(debugMode.serializer instanceof Serializer)
|
|
50
54
|
t.ok(debugMode.validator instanceof Validator)
|
|
51
55
|
|
|
52
56
|
const compiled = fjs.restore(debugMode)
|
|
@@ -55,7 +59,7 @@ test('to string auto-consistent', t => {
|
|
|
55
59
|
})
|
|
56
60
|
|
|
57
61
|
test('to string auto-consistent with ajv', t => {
|
|
58
|
-
t.plan(
|
|
62
|
+
t.plan(6)
|
|
59
63
|
|
|
60
64
|
const debugMode = fjs({
|
|
61
65
|
title: 'object with multiple types field',
|
|
@@ -75,6 +79,7 @@ test('to string auto-consistent with ajv', t => {
|
|
|
75
79
|
t.type(debugMode.code, 'string')
|
|
76
80
|
t.ok(debugMode.ajv instanceof Ajv)
|
|
77
81
|
t.ok(debugMode.validator instanceof Validator)
|
|
82
|
+
t.ok(debugMode.serializer instanceof Serializer)
|
|
78
83
|
|
|
79
84
|
const compiled = fjs.restore(debugMode)
|
|
80
85
|
const tobe = JSON.stringify({ str: 'Foo' })
|
|
@@ -106,3 +111,11 @@ test('to string auto-consistent with ajv-formats', t => {
|
|
|
106
111
|
t.same(compiled({ str: 'foo@bar.com' }), tobe)
|
|
107
112
|
t.throws(() => compiled({ str: 'foo' }))
|
|
108
113
|
})
|
|
114
|
+
|
|
115
|
+
test('debug should restore the same serializer instance', t => {
|
|
116
|
+
t.plan(1)
|
|
117
|
+
|
|
118
|
+
const debugMode = fjs({ type: 'integer' }, { debugMode: 1, rounding: 'ceil' })
|
|
119
|
+
const compiled = fjs.restore(debugMode)
|
|
120
|
+
t.same(compiled(3.95), 4)
|
|
121
|
+
})
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const t = require('tap')
|
|
4
|
+
const { DateTime } = require('luxon')
|
|
4
5
|
const build = require('..')
|
|
5
6
|
|
|
6
7
|
const schema = {
|
|
@@ -368,3 +369,52 @@ t.test('nested if/then', t => {
|
|
|
368
369
|
JSON.stringify({ a: 'A', bar: 'bar', bar1: 'bar1' })
|
|
369
370
|
)
|
|
370
371
|
})
|
|
372
|
+
|
|
373
|
+
t.test('if/else with string format', (t) => {
|
|
374
|
+
t.plan(2)
|
|
375
|
+
|
|
376
|
+
const schema = {
|
|
377
|
+
if: { type: 'string' },
|
|
378
|
+
then: { type: 'string', format: 'date' },
|
|
379
|
+
else: { const: 'Invalid' }
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const stringify = build(schema)
|
|
383
|
+
|
|
384
|
+
const date = new Date()
|
|
385
|
+
|
|
386
|
+
t.equal(stringify(date), `"${DateTime.fromJSDate(date).toISODate()}"`)
|
|
387
|
+
t.equal(stringify('Invalid'), '"Invalid"')
|
|
388
|
+
})
|
|
389
|
+
|
|
390
|
+
t.test('if/else with const integers', (t) => {
|
|
391
|
+
t.plan(2)
|
|
392
|
+
|
|
393
|
+
const schema = {
|
|
394
|
+
type: 'number',
|
|
395
|
+
if: { type: 'number', minimum: 42 },
|
|
396
|
+
then: { const: 66 },
|
|
397
|
+
else: { const: 33 }
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const stringify = build(schema)
|
|
401
|
+
|
|
402
|
+
t.equal(stringify(100.32), '66')
|
|
403
|
+
t.equal(stringify(10.12), '33')
|
|
404
|
+
})
|
|
405
|
+
|
|
406
|
+
t.test('if/else with array', (t) => {
|
|
407
|
+
t.plan(2)
|
|
408
|
+
|
|
409
|
+
const schema = {
|
|
410
|
+
type: 'array',
|
|
411
|
+
if: { type: 'array', maxItems: 1 },
|
|
412
|
+
then: { items: { type: 'string' } },
|
|
413
|
+
else: { items: { type: 'number' } }
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const stringify = build(schema)
|
|
417
|
+
|
|
418
|
+
t.equal(stringify(['1']), JSON.stringify(['1']))
|
|
419
|
+
t.equal(stringify(['1', '2']), JSON.stringify([1, 2]))
|
|
420
|
+
})
|
package/test/ref.test.js
CHANGED
|
@@ -1981,3 +1981,27 @@ test('nested schema should overwrite anchor scope', (t) => {
|
|
|
1981
1981
|
t.equal(output, JSON.stringify(data))
|
|
1982
1982
|
t.throws(() => build({ $ref: 'root#anchor' }, { schema: externalSchema }))
|
|
1983
1983
|
})
|
|
1984
|
+
|
|
1985
|
+
test('object property reference with default value', (t) => {
|
|
1986
|
+
t.plan(1)
|
|
1987
|
+
|
|
1988
|
+
const schema = {
|
|
1989
|
+
definitions: {
|
|
1990
|
+
prop: {
|
|
1991
|
+
type: 'string',
|
|
1992
|
+
default: 'foo'
|
|
1993
|
+
}
|
|
1994
|
+
},
|
|
1995
|
+
type: 'object',
|
|
1996
|
+
properties: {
|
|
1997
|
+
prop: {
|
|
1998
|
+
$ref: '#/definitions/prop'
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
const stringify = build(schema)
|
|
2004
|
+
const output = stringify({})
|
|
2005
|
+
|
|
2006
|
+
t.equal(output, '{"prop":"foo"}')
|
|
2007
|
+
})
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { expectError } from "tsd";
|
|
2
|
+
import build from "../..";
|
|
3
|
+
|
|
4
|
+
// With inference
|
|
5
|
+
interface Schema {
|
|
6
|
+
id: string;
|
|
7
|
+
a?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const stringify3 = build({
|
|
11
|
+
type: "object",
|
|
12
|
+
properties: { a: { type: "string" } },
|
|
13
|
+
});
|
|
14
|
+
stringify3<Schema>({ id: "123" });
|
|
15
|
+
stringify3<Schema>({ a: 123, id: "123" });
|
|
16
|
+
expectError(stringify3<Schema>({ anotherOne: "bar" }));
|
|
17
|
+
expectError(stringify3<Schema>({ a: "bar" }));
|
|
18
|
+
|
|
19
|
+
// Without inference
|
|
20
|
+
const stringify4 = build({
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: { a: { type: "string" } },
|
|
23
|
+
});
|
|
24
|
+
stringify4({ id: "123" });
|
|
25
|
+
stringify4({ a: 123, id: "123" });
|
|
26
|
+
stringify4({ anotherOne: "bar" });
|
|
27
|
+
stringify4({ a: "bar" });
|
|
28
|
+
|
|
29
|
+
// Without inference - string type
|
|
30
|
+
const stringify5 = build({
|
|
31
|
+
type: "string",
|
|
32
|
+
});
|
|
33
|
+
stringify5("foo");
|
|
34
|
+
expectError(stringify5({ id: "123" }));
|
|
35
|
+
|
|
36
|
+
// Without inference - null type
|
|
37
|
+
const stringify6 = build({
|
|
38
|
+
type: "null",
|
|
39
|
+
});
|
|
40
|
+
stringify6(null);
|
|
41
|
+
expectError(stringify6("a string"));
|
|
42
|
+
|
|
43
|
+
// Without inference - boolean type
|
|
44
|
+
const stringify7 = build({
|
|
45
|
+
type: "boolean",
|
|
46
|
+
});
|
|
47
|
+
stringify7(true);
|
|
48
|
+
expectError(stringify7("a string"));
|