fast-json-stringify 5.11.1 → 5.13.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/README.md +18 -0
- package/benchmark/bench.js +24 -0
- package/index.js +284 -239
- package/lib/location.js +1 -30
- package/lib/merge-schemas.js +9 -0
- package/lib/serializer.js +8 -20
- package/package.json +3 -3
- package/test/allof.test.js +134 -17
- package/test/anyof.test.js +148 -0
- package/test/basic.test.js +6 -0
- package/test/if-then-else.test.js +58 -9
- package/test/required.test.js +4 -3
- package/test/string.test.js +34 -0
- package/types/index.d.ts +5 -2
- package/types/index.test-d.ts +79 -57
package/lib/location.js
CHANGED
|
@@ -5,7 +5,6 @@ class Location {
|
|
|
5
5
|
this.schema = schema
|
|
6
6
|
this.schemaId = schemaId
|
|
7
7
|
this.jsonPointer = jsonPointer
|
|
8
|
-
this.mergedSchemaId = null
|
|
9
8
|
}
|
|
10
9
|
|
|
11
10
|
getPropertyLocation (propertyName) {
|
|
@@ -14,39 +13,11 @@ class Location {
|
|
|
14
13
|
this.schemaId,
|
|
15
14
|
this.jsonPointer + '/' + propertyName
|
|
16
15
|
)
|
|
17
|
-
|
|
18
|
-
if (this.mergedSchemaId !== null) {
|
|
19
|
-
propertyLocation.addMergedSchema(
|
|
20
|
-
this.schema[propertyName],
|
|
21
|
-
this.mergedSchemaId,
|
|
22
|
-
this.jsonPointer + '/' + propertyName
|
|
23
|
-
)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
16
|
return propertyLocation
|
|
27
17
|
}
|
|
28
18
|
|
|
29
|
-
// Use this method to get current schema location.
|
|
30
|
-
// Use it when you need to create reference to the current location.
|
|
31
|
-
getSchemaId () {
|
|
32
|
-
return this.mergedSchemaId || this.schemaId
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Use this method to get original schema id for resolving user schema $refs
|
|
36
|
-
// Don't join it with a JSON pointer to get the current location.
|
|
37
|
-
getOriginSchemaId () {
|
|
38
|
-
return this.schemaId
|
|
39
|
-
}
|
|
40
|
-
|
|
41
19
|
getSchemaRef () {
|
|
42
|
-
|
|
43
|
-
return schemaId + this.jsonPointer
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
addMergedSchema (mergedSchema, schemaId, jsonPointer = '#') {
|
|
47
|
-
this.schema = mergedSchema
|
|
48
|
-
this.mergedSchemaId = schemaId
|
|
49
|
-
this.jsonPointer = jsonPointer
|
|
20
|
+
return this.schemaId + this.jsonPointer
|
|
50
21
|
}
|
|
51
22
|
}
|
|
52
23
|
|
package/lib/serializer.js
CHANGED
|
@@ -99,29 +99,20 @@ module.exports = class Serializer {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
asString (str) {
|
|
102
|
-
if (typeof str !== 'string') {
|
|
103
|
-
if (str === null) {
|
|
104
|
-
return '""'
|
|
105
|
-
}
|
|
106
|
-
if (str instanceof Date) {
|
|
107
|
-
return '"' + str.toISOString() + '"'
|
|
108
|
-
}
|
|
109
|
-
if (str instanceof RegExp) {
|
|
110
|
-
str = str.source
|
|
111
|
-
} else {
|
|
112
|
-
str = str.toString()
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
102
|
if (str.length < 42) {
|
|
117
103
|
return this.asStringSmall(str)
|
|
118
|
-
} else if (STR_ESCAPE.test(str) === false) {
|
|
104
|
+
} else if (str.length < 5000 && STR_ESCAPE.test(str) === false) {
|
|
105
|
+
// Only use the regular expression for shorter input. The overhead is otherwise too much.
|
|
119
106
|
return '"' + str + '"'
|
|
120
107
|
} else {
|
|
121
108
|
return JSON.stringify(str)
|
|
122
109
|
}
|
|
123
110
|
}
|
|
124
111
|
|
|
112
|
+
asUnsafeString (str) {
|
|
113
|
+
return '"' + str + '"'
|
|
114
|
+
}
|
|
115
|
+
|
|
125
116
|
// magically escape strings for json
|
|
126
117
|
// relying on their charCodeAt
|
|
127
118
|
// everything below 32 needs JSON.stringify()
|
|
@@ -137,11 +128,8 @@ module.exports = class Serializer {
|
|
|
137
128
|
// eslint-disable-next-line
|
|
138
129
|
for (var i = 0; i < len; i++) {
|
|
139
130
|
point = str.charCodeAt(i)
|
|
140
|
-
if (point < 32) {
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
if (point >= 0xD800 && point <= 0xDFFF) {
|
|
144
|
-
// The current character is a surrogate.
|
|
131
|
+
if (point < 32 || (point >= 0xD800 && point <= 0xDFFF)) {
|
|
132
|
+
// The current character is non-printable characters or a surrogate.
|
|
145
133
|
return JSON.stringify(str)
|
|
146
134
|
}
|
|
147
135
|
if (
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-json-stringify",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.13.0",
|
|
4
4
|
"description": "Stringify your JSON at max speed",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -51,13 +51,13 @@
|
|
|
51
51
|
"fast-json-stringify": "."
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@fastify/deepmerge": "^1.0.0",
|
|
55
54
|
"ajv": "^8.10.0",
|
|
56
55
|
"ajv-formats": "^2.1.1",
|
|
57
56
|
"fast-deep-equal": "^3.1.3",
|
|
58
57
|
"fast-uri": "^2.1.0",
|
|
59
58
|
"rfdc": "^1.2.0",
|
|
60
|
-
"json-schema-ref-resolver": "^1.0.1"
|
|
59
|
+
"json-schema-ref-resolver": "^1.0.1",
|
|
60
|
+
"@fastify/merge-json-schemas": "^0.1.0"
|
|
61
61
|
},
|
|
62
62
|
"standard": {
|
|
63
63
|
"ignore": [
|
package/test/allof.test.js
CHANGED
|
@@ -121,7 +121,7 @@ test('object with allOf and multiple schema on the allOf', (t) => {
|
|
|
121
121
|
id: 1,
|
|
122
122
|
name: 'string',
|
|
123
123
|
tag: 'otherString'
|
|
124
|
-
}), '{"name":"string","tag":"otherString"
|
|
124
|
+
}), '{"name":"string","id":1,"tag":"otherString"}')
|
|
125
125
|
})
|
|
126
126
|
|
|
127
127
|
test('object with allOf and one schema on the allOf', (t) => {
|
|
@@ -553,8 +553,60 @@ test('allof with local anchor reference', (t) => {
|
|
|
553
553
|
t.equal(stringify(data), JSON.stringify(data))
|
|
554
554
|
})
|
|
555
555
|
|
|
556
|
+
test('allOf: multiple nested $ref properties', (t) => {
|
|
557
|
+
t.plan(2)
|
|
558
|
+
|
|
559
|
+
const externalSchema1 = {
|
|
560
|
+
$id: 'externalSchema1',
|
|
561
|
+
oneOf: [
|
|
562
|
+
{ $ref: '#/definitions/id1' }
|
|
563
|
+
],
|
|
564
|
+
definitions: {
|
|
565
|
+
id1: {
|
|
566
|
+
type: 'object',
|
|
567
|
+
properties: {
|
|
568
|
+
id1: {
|
|
569
|
+
type: 'integer'
|
|
570
|
+
}
|
|
571
|
+
},
|
|
572
|
+
additionalProperties: false
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
const externalSchema2 = {
|
|
578
|
+
$id: 'externalSchema2',
|
|
579
|
+
oneOf: [
|
|
580
|
+
{ $ref: '#/definitions/id2' }
|
|
581
|
+
],
|
|
582
|
+
definitions: {
|
|
583
|
+
id2: {
|
|
584
|
+
type: 'object',
|
|
585
|
+
properties: {
|
|
586
|
+
id2: {
|
|
587
|
+
type: 'integer'
|
|
588
|
+
}
|
|
589
|
+
},
|
|
590
|
+
additionalProperties: false
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
const schema = {
|
|
596
|
+
anyOf: [
|
|
597
|
+
{ $ref: 'externalSchema1' },
|
|
598
|
+
{ $ref: 'externalSchema2' }
|
|
599
|
+
]
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
const stringify = build(schema, { schema: [externalSchema1, externalSchema2] })
|
|
603
|
+
|
|
604
|
+
t.equal(stringify({ id1: 1 }), JSON.stringify({ id1: 1 }))
|
|
605
|
+
t.equal(stringify({ id2: 2 }), JSON.stringify({ id2: 2 }))
|
|
606
|
+
})
|
|
607
|
+
|
|
556
608
|
test('allOf: throw Error if types mismatch ', (t) => {
|
|
557
|
-
t.plan(
|
|
609
|
+
t.plan(3)
|
|
558
610
|
|
|
559
611
|
const schema = {
|
|
560
612
|
allOf: [
|
|
@@ -562,11 +614,18 @@ test('allOf: throw Error if types mismatch ', (t) => {
|
|
|
562
614
|
{ type: 'number' }
|
|
563
615
|
]
|
|
564
616
|
}
|
|
565
|
-
|
|
617
|
+
try {
|
|
618
|
+
build(schema)
|
|
619
|
+
t.fail('should throw the MergeError')
|
|
620
|
+
} catch (error) {
|
|
621
|
+
t.ok(error instanceof Error)
|
|
622
|
+
t.equal(error.message, 'Failed to merge "type" keyword schemas.')
|
|
623
|
+
t.same(error.schemas, [['string'], ['number']])
|
|
624
|
+
}
|
|
566
625
|
})
|
|
567
626
|
|
|
568
627
|
test('allOf: throw Error if format mismatch ', (t) => {
|
|
569
|
-
t.plan(
|
|
628
|
+
t.plan(3)
|
|
570
629
|
|
|
571
630
|
const schema = {
|
|
572
631
|
allOf: [
|
|
@@ -574,29 +633,87 @@ test('allOf: throw Error if format mismatch ', (t) => {
|
|
|
574
633
|
{ format: 'time' }
|
|
575
634
|
]
|
|
576
635
|
}
|
|
577
|
-
|
|
636
|
+
try {
|
|
637
|
+
build(schema)
|
|
638
|
+
t.fail('should throw the MergeError')
|
|
639
|
+
} catch (error) {
|
|
640
|
+
t.ok(error instanceof Error)
|
|
641
|
+
t.equal(error.message, 'Failed to merge "format" keyword schemas.')
|
|
642
|
+
t.same(error.schemas, ['date', 'time'])
|
|
643
|
+
}
|
|
578
644
|
})
|
|
579
645
|
|
|
580
|
-
test('
|
|
646
|
+
test('recursive nested allOfs', (t) => {
|
|
581
647
|
t.plan(1)
|
|
582
648
|
|
|
583
649
|
const schema = {
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
650
|
+
type: 'object',
|
|
651
|
+
properties: {
|
|
652
|
+
foo: {
|
|
653
|
+
additionalProperties: false,
|
|
654
|
+
allOf: [{ $ref: '#' }]
|
|
655
|
+
}
|
|
656
|
+
}
|
|
588
657
|
}
|
|
589
|
-
|
|
658
|
+
|
|
659
|
+
const data = { foo: {} }
|
|
660
|
+
const stringify = build(schema)
|
|
661
|
+
t.equal(stringify(data), JSON.stringify(data))
|
|
590
662
|
})
|
|
591
663
|
|
|
592
|
-
test('
|
|
664
|
+
test('recursive nested allOfs', (t) => {
|
|
593
665
|
t.plan(1)
|
|
594
666
|
|
|
595
667
|
const schema = {
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
668
|
+
type: 'object',
|
|
669
|
+
properties: {
|
|
670
|
+
foo: {
|
|
671
|
+
additionalProperties: false,
|
|
672
|
+
allOf: [{ allOf: [{ $ref: '#' }] }]
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
const data = { foo: {} }
|
|
678
|
+
const stringify = build(schema)
|
|
679
|
+
t.equal(stringify(data), JSON.stringify(data))
|
|
680
|
+
})
|
|
681
|
+
|
|
682
|
+
test('external recursive allOfs', (t) => {
|
|
683
|
+
t.plan(1)
|
|
684
|
+
|
|
685
|
+
const externalSchema = {
|
|
686
|
+
type: 'object',
|
|
687
|
+
properties: {
|
|
688
|
+
foo: {
|
|
689
|
+
properties: {
|
|
690
|
+
bar: { type: 'string' }
|
|
691
|
+
},
|
|
692
|
+
allOf: [{ $ref: '#' }]
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
const schema = {
|
|
698
|
+
type: 'object',
|
|
699
|
+
properties: {
|
|
700
|
+
a: { $ref: 'externalSchema#/properties/foo' },
|
|
701
|
+
b: { $ref: 'externalSchema#/properties/foo' }
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
const data = {
|
|
706
|
+
a: {
|
|
707
|
+
foo: {},
|
|
708
|
+
bar: '42',
|
|
709
|
+
baz: 42
|
|
710
|
+
},
|
|
711
|
+
b: {
|
|
712
|
+
foo: {},
|
|
713
|
+
bar: '42',
|
|
714
|
+
baz: 42
|
|
715
|
+
}
|
|
600
716
|
}
|
|
601
|
-
|
|
717
|
+
const stringify = build(schema, { schema: { externalSchema } })
|
|
718
|
+
t.equal(stringify(data), '{"a":{"bar":"42","foo":{}},"b":{"bar":"42","foo":{}}}')
|
|
602
719
|
})
|
package/test/anyof.test.js
CHANGED
|
@@ -644,3 +644,151 @@ test('object with ref and validated properties', (t) => {
|
|
|
644
644
|
const stringify = build(schema, { schema: externalSchemas })
|
|
645
645
|
t.equal(stringify({ id: 1, reference: 'hi' }), '{"id":1,"reference":"hi"}')
|
|
646
646
|
})
|
|
647
|
+
|
|
648
|
+
test('anyOf required props', (t) => {
|
|
649
|
+
t.plan(3)
|
|
650
|
+
|
|
651
|
+
const schema = {
|
|
652
|
+
type: 'object',
|
|
653
|
+
properties: {
|
|
654
|
+
prop1: { type: 'string' },
|
|
655
|
+
prop2: { type: 'string' },
|
|
656
|
+
prop3: { type: 'string' }
|
|
657
|
+
},
|
|
658
|
+
required: ['prop1'],
|
|
659
|
+
anyOf: [{ required: ['prop2'] }, { required: ['prop3'] }]
|
|
660
|
+
}
|
|
661
|
+
const stringify = build(schema)
|
|
662
|
+
t.equal(stringify({ prop1: 'test', prop2: 'test2' }), '{"prop1":"test","prop2":"test2"}')
|
|
663
|
+
t.equal(stringify({ prop1: 'test', prop3: 'test3' }), '{"prop1":"test","prop3":"test3"}')
|
|
664
|
+
t.equal(stringify({ prop1: 'test', prop2: 'test2', prop3: 'test3' }), '{"prop1":"test","prop2":"test2","prop3":"test3"}')
|
|
665
|
+
})
|
|
666
|
+
|
|
667
|
+
test('anyOf required props', (t) => {
|
|
668
|
+
t.plan(3)
|
|
669
|
+
|
|
670
|
+
const schema = {
|
|
671
|
+
type: 'object',
|
|
672
|
+
properties: {
|
|
673
|
+
prop1: { type: 'string' }
|
|
674
|
+
},
|
|
675
|
+
anyOf: [
|
|
676
|
+
{
|
|
677
|
+
properties: {
|
|
678
|
+
prop2: { type: 'string' }
|
|
679
|
+
}
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
properties: {
|
|
683
|
+
prop3: { type: 'string' }
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
]
|
|
687
|
+
}
|
|
688
|
+
const stringify = build(schema)
|
|
689
|
+
t.equal(stringify({ prop1: 'test1' }), '{"prop1":"test1"}')
|
|
690
|
+
t.equal(stringify({ prop2: 'test2' }), '{"prop2":"test2"}')
|
|
691
|
+
t.equal(stringify({ prop1: 'test1', prop2: 'test2' }), '{"prop1":"test1","prop2":"test2"}')
|
|
692
|
+
})
|
|
693
|
+
|
|
694
|
+
test('recursive nested anyOfs', (t) => {
|
|
695
|
+
t.plan(1)
|
|
696
|
+
|
|
697
|
+
const schema = {
|
|
698
|
+
type: 'object',
|
|
699
|
+
properties: {
|
|
700
|
+
foo: {
|
|
701
|
+
additionalProperties: false,
|
|
702
|
+
anyOf: [{ $ref: '#' }]
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
const data = { foo: {} }
|
|
708
|
+
const stringify = build(schema)
|
|
709
|
+
t.equal(stringify(data), JSON.stringify(data))
|
|
710
|
+
})
|
|
711
|
+
|
|
712
|
+
test('recursive nested anyOfs', (t) => {
|
|
713
|
+
t.plan(1)
|
|
714
|
+
|
|
715
|
+
const schema = {
|
|
716
|
+
type: 'object',
|
|
717
|
+
properties: {
|
|
718
|
+
foo: {
|
|
719
|
+
additionalProperties: false,
|
|
720
|
+
anyOf: [{ anyOf: [{ $ref: '#' }] }]
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
const data = { foo: {} }
|
|
726
|
+
const stringify = build(schema)
|
|
727
|
+
t.equal(stringify(data), JSON.stringify(data))
|
|
728
|
+
})
|
|
729
|
+
|
|
730
|
+
test('external recursive anyOfs', (t) => {
|
|
731
|
+
t.plan(1)
|
|
732
|
+
|
|
733
|
+
const externalSchema = {
|
|
734
|
+
type: 'object',
|
|
735
|
+
properties: {
|
|
736
|
+
foo: {
|
|
737
|
+
properties: {
|
|
738
|
+
bar: { type: 'string' }
|
|
739
|
+
},
|
|
740
|
+
anyOf: [{ $ref: '#' }]
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
const schema = {
|
|
746
|
+
type: 'object',
|
|
747
|
+
properties: {
|
|
748
|
+
a: { $ref: 'externalSchema#/properties/foo' },
|
|
749
|
+
b: { $ref: 'externalSchema#/properties/foo' }
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
const data = {
|
|
754
|
+
a: {
|
|
755
|
+
foo: {},
|
|
756
|
+
bar: '42',
|
|
757
|
+
baz: 42
|
|
758
|
+
},
|
|
759
|
+
b: {
|
|
760
|
+
foo: {},
|
|
761
|
+
bar: '42',
|
|
762
|
+
baz: 42
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
const stringify = build(schema, { schema: { externalSchema } })
|
|
766
|
+
t.equal(stringify(data), '{"a":{"bar":"42","foo":{}},"b":{"bar":"42","foo":{}}}')
|
|
767
|
+
})
|
|
768
|
+
|
|
769
|
+
test('should build merged schemas twice', (t) => {
|
|
770
|
+
t.plan(2)
|
|
771
|
+
|
|
772
|
+
const schema = {
|
|
773
|
+
type: 'object',
|
|
774
|
+
properties: {
|
|
775
|
+
enums: {
|
|
776
|
+
type: 'string',
|
|
777
|
+
anyOf: [
|
|
778
|
+
{ type: 'string', const: 'FOO' },
|
|
779
|
+
{ type: 'string', const: 'BAR' }
|
|
780
|
+
]
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
{
|
|
786
|
+
const stringify = build(schema)
|
|
787
|
+
t.equal(stringify({ enums: 'FOO' }), '{"enums":"FOO"}')
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
{
|
|
791
|
+
const stringify = build(schema)
|
|
792
|
+
t.equal(stringify({ enums: 'BAR' }), '{"enums":"BAR"}')
|
|
793
|
+
}
|
|
794
|
+
})
|
package/test/basic.test.js
CHANGED
|
@@ -249,15 +249,7 @@ const alphabetOutput = JSON.stringify({
|
|
|
249
249
|
const deepFoobarOutput = JSON.stringify({
|
|
250
250
|
foobar: JSON.parse(foobarOutput)
|
|
251
251
|
})
|
|
252
|
-
const noElseGreetingOutput = JSON.stringify({
|
|
253
|
-
kind: 'greeting',
|
|
254
|
-
foo: 'FOO',
|
|
255
|
-
bar: 42,
|
|
256
|
-
hi: 'HI',
|
|
257
|
-
hello: 45,
|
|
258
|
-
a: 'A',
|
|
259
|
-
b: 35
|
|
260
|
-
})
|
|
252
|
+
const noElseGreetingOutput = JSON.stringify({})
|
|
261
253
|
|
|
262
254
|
t.test('if-then-else', t => {
|
|
263
255
|
const tests = [
|
|
@@ -419,3 +411,60 @@ t.test('if/else with array', (t) => {
|
|
|
419
411
|
t.equal(stringify(['1']), JSON.stringify(['1']))
|
|
420
412
|
t.equal(stringify(['1', '2']), JSON.stringify([1, 2]))
|
|
421
413
|
})
|
|
414
|
+
|
|
415
|
+
t.test('external recursive if/then/else', (t) => {
|
|
416
|
+
t.plan(1)
|
|
417
|
+
|
|
418
|
+
const externalSchema = {
|
|
419
|
+
type: 'object',
|
|
420
|
+
properties: {
|
|
421
|
+
base: { type: 'string' },
|
|
422
|
+
self: { $ref: 'externalSchema#' }
|
|
423
|
+
},
|
|
424
|
+
if: {
|
|
425
|
+
type: 'object',
|
|
426
|
+
properties: {
|
|
427
|
+
foo: { type: 'string', const: '41' }
|
|
428
|
+
}
|
|
429
|
+
},
|
|
430
|
+
then: {
|
|
431
|
+
type: 'object',
|
|
432
|
+
properties: {
|
|
433
|
+
bar: { type: 'string', const: '42' }
|
|
434
|
+
}
|
|
435
|
+
},
|
|
436
|
+
else: {
|
|
437
|
+
type: 'object',
|
|
438
|
+
properties: {
|
|
439
|
+
baz: { type: 'string', const: '43' }
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const schema = {
|
|
445
|
+
type: 'object',
|
|
446
|
+
properties: {
|
|
447
|
+
a: { $ref: 'externalSchema#/properties/self' },
|
|
448
|
+
b: { $ref: 'externalSchema#/properties/self' }
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const data = {
|
|
453
|
+
a: {
|
|
454
|
+
base: 'a',
|
|
455
|
+
foo: '41',
|
|
456
|
+
bar: '42',
|
|
457
|
+
baz: '43',
|
|
458
|
+
ignore: 'ignored'
|
|
459
|
+
},
|
|
460
|
+
b: {
|
|
461
|
+
base: 'b',
|
|
462
|
+
foo: 'not-41',
|
|
463
|
+
bar: '42',
|
|
464
|
+
baz: '43',
|
|
465
|
+
ignore: 'ignored'
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
const stringify = build(schema, { schema: { externalSchema } })
|
|
469
|
+
t.equal(stringify(data), '{"a":{"base":"a","bar":"42"},"b":{"base":"b","baz":"43"}}')
|
|
470
|
+
})
|
package/test/required.test.js
CHANGED
|
@@ -126,17 +126,18 @@ test('object with multiple required field not in properties schema', (t) => {
|
|
|
126
126
|
stringify({})
|
|
127
127
|
t.fail()
|
|
128
128
|
} catch (e) {
|
|
129
|
-
t.equal(e.message, '"
|
|
129
|
+
t.equal(e.message, '"key1" is required!')
|
|
130
130
|
t.pass()
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
try {
|
|
134
134
|
stringify({
|
|
135
|
-
|
|
135
|
+
key1: 42,
|
|
136
|
+
key2: 42
|
|
136
137
|
})
|
|
137
138
|
t.fail()
|
|
138
139
|
} catch (e) {
|
|
139
|
-
t.equal(e.message, '"
|
|
140
|
+
t.equal(e.message, '"num" is required!')
|
|
140
141
|
t.pass()
|
|
141
142
|
}
|
|
142
143
|
|
package/test/string.test.js
CHANGED
|
@@ -48,3 +48,37 @@ test('serialize long string', (t) => {
|
|
|
48
48
|
t.equal(output, `"${new Array(2e4).fill('\\u0000').join('')}"`)
|
|
49
49
|
t.equal(JSON.parse(output), input)
|
|
50
50
|
})
|
|
51
|
+
|
|
52
|
+
test('unsafe string', (t) => {
|
|
53
|
+
t.plan(2)
|
|
54
|
+
|
|
55
|
+
const schema = {
|
|
56
|
+
type: 'string',
|
|
57
|
+
format: 'unsafe'
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const input = 'abcd'
|
|
61
|
+
const stringify = build(schema)
|
|
62
|
+
const output = stringify(input)
|
|
63
|
+
|
|
64
|
+
t.equal(output, `"${input}"`)
|
|
65
|
+
t.equal(JSON.parse(output), input)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('unsafe unescaped string', (t) => {
|
|
69
|
+
t.plan(2)
|
|
70
|
+
|
|
71
|
+
const schema = {
|
|
72
|
+
type: 'string',
|
|
73
|
+
format: 'unsafe'
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const input = 'abcd "abcd"'
|
|
77
|
+
const stringify = build(schema)
|
|
78
|
+
const output = stringify(input)
|
|
79
|
+
|
|
80
|
+
t.equal(output, `"${input}"`)
|
|
81
|
+
t.throws(function () {
|
|
82
|
+
JSON.parse(output)
|
|
83
|
+
})
|
|
84
|
+
})
|
package/types/index.d.ts
CHANGED
|
@@ -208,6 +208,9 @@ interface StandaloneOption extends build.Options {
|
|
|
208
208
|
mode: 'standalone'
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
type StringCoercible = string | Date | RegExp;
|
|
212
|
+
type IntegerCoercible = number | BigInt;
|
|
213
|
+
|
|
211
214
|
/**
|
|
212
215
|
* Build a stringify function using a schema of the documents that should be stringified
|
|
213
216
|
* @param schema The schema used to stringify values
|
|
@@ -217,8 +220,8 @@ declare function build(schema: build.AnySchema, options: DebugOption): { code: s
|
|
|
217
220
|
declare function build(schema: build.AnySchema, options: DeprecateDebugOption): { code: string, ajv: Ajv };
|
|
218
221
|
declare function build(schema: build.AnySchema, options: StandaloneOption): string;
|
|
219
222
|
declare function build(schema: build.AnySchema, options?: build.Options): <TDoc = any>(doc: TDoc) => any;
|
|
220
|
-
declare function build(schema: build.StringSchema, options?: build.Options): <TDoc extends
|
|
221
|
-
declare function build(schema: build.IntegerSchema | build.NumberSchema, options?: build.Options): <TDoc extends
|
|
223
|
+
declare function build(schema: build.StringSchema, options?: build.Options): <TDoc extends StringCoercible = StringCoercible>(doc: TDoc) => string;
|
|
224
|
+
declare function build(schema: build.IntegerSchema | build.NumberSchema, options?: build.Options): <TDoc extends IntegerCoercible = IntegerCoercible>(doc: TDoc) => string;
|
|
222
225
|
declare function build(schema: build.NullSchema, options?: build.Options): <TDoc extends null = null>(doc: TDoc) => "null";
|
|
223
226
|
declare function build(schema: build.BooleanSchema, options?: build.Options): <TDoc extends boolean = boolean>(doc: TDoc) => string;
|
|
224
227
|
declare function build(schema: build.ArraySchema | build.TupleSchema, options?: build.Options): <TDoc extends any[]= any[]>(doc: TDoc) => string;
|