fast-json-stringify 5.0.6 → 5.3.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/benchmark.yml +12 -12
- package/.github/workflows/ci.yml +2 -0
- package/benchmark/bench.js +54 -0
- 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 +232 -270
- package/lib/ref-resolver.js +84 -0
- package/{schema-validator.js → lib/schema-validator.js} +0 -0
- package/{serializer.js → lib/serializer.js} +19 -46
- package/{standalone.js → lib/standalone.js} +8 -8
- package/lib/validator.js +75 -0
- package/package.json +11 -6
- package/test/array.test.js +25 -0
- package/test/basic.test.js +13 -0
- package/test/const.test.js +235 -8
- package/test/date.test.js +119 -4
- package/test/debug-mode.test.js +23 -4
- package/test/nullable.test.js +97 -0
- package/test/ref.test.js +28 -0
- package/test/types/schema-inference.test-d.ts +48 -0
- package/test/typesArray.test.js +29 -0
- package/ajv.js +0 -37
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const deepEqual = require('fast-deep-equal')
|
|
4
|
+
|
|
5
|
+
class RefResolver {
|
|
6
|
+
constructor () {
|
|
7
|
+
this.schemas = {}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
addSchema (schema, schemaId) {
|
|
11
|
+
if (schema.$id !== undefined && schema.$id.charAt(0) !== '#') {
|
|
12
|
+
schemaId = schema.$id
|
|
13
|
+
}
|
|
14
|
+
if (this.getSchema(schemaId) === undefined) {
|
|
15
|
+
this.insertSchemaBySchemaId(schema, schemaId)
|
|
16
|
+
this.insertSchemaSubschemas(schema, schemaId)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
getSchema (schemaId, jsonPointer = '#') {
|
|
21
|
+
const schema = this.schemas[schemaId]
|
|
22
|
+
if (schema === undefined) {
|
|
23
|
+
return undefined
|
|
24
|
+
}
|
|
25
|
+
if (schema.anchors[jsonPointer] !== undefined) {
|
|
26
|
+
return schema.anchors[jsonPointer]
|
|
27
|
+
}
|
|
28
|
+
return getDataByJSONPointer(schema.schema, jsonPointer)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
insertSchemaBySchemaId (schema, schemaId) {
|
|
32
|
+
if (
|
|
33
|
+
this.schemas[schemaId] !== undefined &&
|
|
34
|
+
!deepEqual(schema, this.schemas[schemaId].schema)
|
|
35
|
+
) {
|
|
36
|
+
throw new Error(`There is already another schema with id ${schemaId}`)
|
|
37
|
+
}
|
|
38
|
+
this.schemas[schemaId] = { schema, anchors: {} }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
insertSchemaByAnchor (schema, schemaId, anchor) {
|
|
42
|
+
const { anchors } = this.schemas[schemaId]
|
|
43
|
+
if (
|
|
44
|
+
anchors[anchor] !== undefined &&
|
|
45
|
+
!deepEqual(schema, anchors[anchor])
|
|
46
|
+
) {
|
|
47
|
+
throw new Error(`There is already another schema with id ${schemaId}#${anchor}`)
|
|
48
|
+
}
|
|
49
|
+
anchors[anchor] = schema
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
insertSchemaSubschemas (schema, rootSchemaId) {
|
|
53
|
+
const schemaId = schema.$id
|
|
54
|
+
if (schemaId !== undefined && typeof schemaId === 'string') {
|
|
55
|
+
if (schemaId.charAt(0) === '#') {
|
|
56
|
+
this.insertSchemaByAnchor(schema, rootSchemaId, schemaId)
|
|
57
|
+
} else {
|
|
58
|
+
this.insertSchemaBySchemaId(schema, schemaId)
|
|
59
|
+
rootSchemaId = schemaId
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
for (const key in schema) {
|
|
64
|
+
if (typeof schema[key] === 'object' && schema[key] !== null) {
|
|
65
|
+
this.insertSchemaSubschemas(schema[key], rootSchemaId)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function getDataByJSONPointer (data, jsonPointer) {
|
|
72
|
+
const parts = jsonPointer.split('/')
|
|
73
|
+
let current = data
|
|
74
|
+
for (const part of parts) {
|
|
75
|
+
if (part === '' || part === '#') continue
|
|
76
|
+
if (typeof current !== 'object' || current === null) {
|
|
77
|
+
return undefined
|
|
78
|
+
}
|
|
79
|
+
current = current[part]
|
|
80
|
+
}
|
|
81
|
+
return current
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports = RefResolver
|
|
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,52 +45,41 @@ 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
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
asDatetime (date) {
|
|
73
|
-
const quotes = '"'
|
|
52
|
+
asDateTime (date) {
|
|
53
|
+
if (date === null) return '""'
|
|
74
54
|
if (date instanceof Date) {
|
|
75
|
-
return
|
|
55
|
+
return '"' + date.toISOString() + '"'
|
|
76
56
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return date === null ? 'null' : this.asDatetime(date)
|
|
57
|
+
if (typeof date === 'string') {
|
|
58
|
+
return '"' + date + '"'
|
|
59
|
+
}
|
|
60
|
+
throw new Error(`The value "${date}" cannot be converted to a date-time.`)
|
|
82
61
|
}
|
|
83
62
|
|
|
84
63
|
asDate (date) {
|
|
85
|
-
|
|
64
|
+
if (date === null) return '""'
|
|
86
65
|
if (date instanceof Date) {
|
|
87
|
-
return
|
|
66
|
+
return '"' + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(0, 10) + '"'
|
|
88
67
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return date === null ? 'null' : this.asDate(date)
|
|
68
|
+
if (typeof date === 'string') {
|
|
69
|
+
return '"' + date + '"'
|
|
70
|
+
}
|
|
71
|
+
throw new Error(`The value "${date}" cannot be converted to a date.`)
|
|
94
72
|
}
|
|
95
73
|
|
|
96
74
|
asTime (date) {
|
|
97
|
-
|
|
75
|
+
if (date === null) return '""'
|
|
98
76
|
if (date instanceof Date) {
|
|
99
|
-
return
|
|
77
|
+
return '"' + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(11, 19) + '"'
|
|
100
78
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return date === null ? 'null' : this.asTime(date)
|
|
79
|
+
if (typeof date === 'string') {
|
|
80
|
+
return '"' + date + '"'
|
|
81
|
+
}
|
|
82
|
+
throw new Error(`The value "${date}" cannot be converted to a time.`)
|
|
106
83
|
}
|
|
107
84
|
|
|
108
85
|
asString (str) {
|
|
@@ -124,10 +101,6 @@ module.exports = class Serializer {
|
|
|
124
101
|
}
|
|
125
102
|
}
|
|
126
103
|
|
|
127
|
-
asStringNullable (str) {
|
|
128
|
-
return str === null ? 'null' : this.asString(str)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
104
|
// magically escape strings for json
|
|
132
105
|
// relying on their charCodeAt
|
|
133
106
|
// everything below 32 needs JSON.stringify()
|
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
3
|
|
|
4
|
-
function buildStandaloneCode (options,
|
|
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 =
|
|
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('
|
|
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
|
|
19
|
-
for (const [id, schema] of Object.entries(
|
|
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, '
|
|
25
|
-
buildAjvCode = buildAjvCode.replace("'use strict'", '').replace('module.exports =
|
|
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'
|
package/lib/validator.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const Ajv = require('ajv')
|
|
4
|
+
const fastUri = require('fast-uri')
|
|
5
|
+
const ajvFormats = require('ajv-formats')
|
|
6
|
+
const clone = require('rfdc')({ proto: true })
|
|
7
|
+
|
|
8
|
+
class Validator {
|
|
9
|
+
constructor (ajvOptions) {
|
|
10
|
+
this.ajv = new Ajv({
|
|
11
|
+
...ajvOptions,
|
|
12
|
+
strictSchema: false,
|
|
13
|
+
validateSchema: false,
|
|
14
|
+
allowUnionTypes: true,
|
|
15
|
+
uriResolver: fastUri
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
ajvFormats(this.ajv)
|
|
19
|
+
|
|
20
|
+
this.ajv.addKeyword({
|
|
21
|
+
keyword: 'fjs_type',
|
|
22
|
+
type: 'object',
|
|
23
|
+
errors: false,
|
|
24
|
+
validate: (type, date) => {
|
|
25
|
+
return date instanceof Date
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
addSchema (schema, schemaName) {
|
|
31
|
+
let schemaKey = schema.$id || schemaName
|
|
32
|
+
if (schema.$id !== undefined && schema.$id[0] === '#') {
|
|
33
|
+
schemaKey = schemaName + schema.$id // relative URI
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (
|
|
37
|
+
this.ajv.refs[schemaKey] === undefined &&
|
|
38
|
+
this.ajv.schemas[schemaKey] === undefined
|
|
39
|
+
) {
|
|
40
|
+
const ajvSchema = clone(schema)
|
|
41
|
+
this.convertSchemaToAjvFormat(ajvSchema)
|
|
42
|
+
this.ajv.addSchema(ajvSchema, schemaKey)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
validate (schemaRef, data) {
|
|
47
|
+
return this.ajv.validate(schemaRef, data)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Ajv does not support js date format. In order to properly validate objects containing a date,
|
|
51
|
+
// it needs to replace all occurrences of the string date format with a custom keyword fjs_type.
|
|
52
|
+
// (see https://github.com/fastify/fast-json-stringify/pull/441)
|
|
53
|
+
convertSchemaToAjvFormat (schema) {
|
|
54
|
+
if (schema === null) return
|
|
55
|
+
|
|
56
|
+
if (schema.type === 'string') {
|
|
57
|
+
schema.fjs_type = 'string'
|
|
58
|
+
schema.type = ['string', 'object']
|
|
59
|
+
} else if (
|
|
60
|
+
Array.isArray(schema.type) &&
|
|
61
|
+
schema.type.includes('string') &&
|
|
62
|
+
!schema.type.includes('object')
|
|
63
|
+
) {
|
|
64
|
+
schema.fjs_type = 'string'
|
|
65
|
+
schema.type.push('object')
|
|
66
|
+
}
|
|
67
|
+
for (const property in schema) {
|
|
68
|
+
if (typeof schema[property] === 'object') {
|
|
69
|
+
this.convertSchemaToAjvFormat(schema[property])
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = Validator
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-json-stringify",
|
|
3
|
-
"version": "5.0
|
|
3
|
+
"version": "5.3.0",
|
|
4
4
|
"description": "Stringify your JSON at max speed",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"benchmark": "node ./benchmark/bench-cmp-lib.js",
|
|
12
12
|
"lint:fix": "standard --fix",
|
|
13
13
|
"test:lint": "standard",
|
|
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
16
|
"test": "npm run test:lint && npm run test:unit && npm run test:typescript"
|
|
17
17
|
},
|
|
@@ -33,25 +33,27 @@
|
|
|
33
33
|
},
|
|
34
34
|
"homepage": "https://github.com/fastify/fast-json-stringify#readme",
|
|
35
35
|
"devDependencies": {
|
|
36
|
+
"@fastify/pre-commit": "^2.0.2",
|
|
36
37
|
"@sinclair/typebox": "^0.24.9",
|
|
37
38
|
"benchmark": "^2.1.4",
|
|
38
39
|
"cli-select": "^1.1.2",
|
|
39
40
|
"compile-json-stringify": "^0.1.2",
|
|
40
41
|
"is-my-json-valid": "^2.20.0",
|
|
41
|
-
"luxon": "^
|
|
42
|
-
"pre-commit": "^1.2.2",
|
|
42
|
+
"luxon": "^3.0.1",
|
|
43
43
|
"proxyquire": "^2.1.3",
|
|
44
44
|
"semver": "^7.1.0",
|
|
45
45
|
"simple-git": "^3.7.1",
|
|
46
46
|
"standard": "^17.0.0",
|
|
47
47
|
"tap": "^16.0.1",
|
|
48
|
+
"tsd": "^0.22.0",
|
|
48
49
|
"typescript": "^4.0.2",
|
|
49
50
|
"webpack": "^5.40.0"
|
|
50
51
|
},
|
|
51
52
|
"dependencies": {
|
|
53
|
+
"@fastify/deepmerge": "^1.0.0",
|
|
52
54
|
"ajv": "^8.10.0",
|
|
53
55
|
"ajv-formats": "^2.1.1",
|
|
54
|
-
"
|
|
56
|
+
"fast-deep-equal": "^3.1.3",
|
|
55
57
|
"fast-uri": "^2.1.0",
|
|
56
58
|
"rfdc": "^1.2.0"
|
|
57
59
|
},
|
|
@@ -60,5 +62,8 @@
|
|
|
60
62
|
"schema-validator.js"
|
|
61
63
|
]
|
|
62
64
|
},
|
|
63
|
-
"runkitExampleFilename": "example.js"
|
|
65
|
+
"runkitExampleFilename": "./examples/example.js",
|
|
66
|
+
"tsd": {
|
|
67
|
+
"directory": "test/types"
|
|
68
|
+
}
|
|
64
69
|
}
|
package/test/array.test.js
CHANGED
|
@@ -327,6 +327,31 @@ test('object array with anyOf and symbol', (t) => {
|
|
|
327
327
|
t.equal(value, '[{"name":"name-0","option":"Foo"},{"name":"name-1","option":"Bar"}]')
|
|
328
328
|
})
|
|
329
329
|
|
|
330
|
+
test('different arrays with same item schemas', (t) => {
|
|
331
|
+
t.plan(1)
|
|
332
|
+
|
|
333
|
+
const schema = {
|
|
334
|
+
type: 'object',
|
|
335
|
+
properties: {
|
|
336
|
+
array1: {
|
|
337
|
+
type: 'array',
|
|
338
|
+
items: [{ type: 'string' }],
|
|
339
|
+
additionalItems: false
|
|
340
|
+
},
|
|
341
|
+
array2: {
|
|
342
|
+
type: 'array',
|
|
343
|
+
items: { $ref: '#/properties/array1/items' },
|
|
344
|
+
additionalItems: true
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const stringify = build(schema)
|
|
350
|
+
const data = { array1: ['bar'], array2: ['foo', 'bar'] }
|
|
351
|
+
|
|
352
|
+
t.equal(stringify(data), '{"array1":["bar"],"array2":["foo","bar"]}')
|
|
353
|
+
})
|
|
354
|
+
|
|
330
355
|
const largeArray = new Array(2e4).fill({ a: 'test', b: 1 })
|
|
331
356
|
buildTest({
|
|
332
357
|
title: 'large array with default mechanism',
|
package/test/basic.test.js
CHANGED
|
@@ -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
|
+
})
|
package/test/const.test.js
CHANGED
|
@@ -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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
})
|