fast-json-stringify 2.7.7 → 2.7.11

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.
@@ -0,0 +1,111 @@
1
+ name: Benchmark
2
+
3
+ on:
4
+ pull_request_target:
5
+ types: [labeled]
6
+
7
+ jobs:
8
+ benchmark:
9
+ if: ${{ github.event.label.name == 'benchmark' }}
10
+ runs-on: ubuntu-latest
11
+ outputs:
12
+ PR-BENCH-12: ${{ steps.benchmark-pr.outputs.BENCH_RESULT12 }}
13
+ PR-BENCH-14: ${{ steps.benchmark-pr.outputs.BENCH_RESULT14 }}
14
+ PR-BENCH-16: ${{ steps.benchmark-pr.outputs.BENCH_RESULT16 }}
15
+ MAIN-BENCH-12: ${{ steps.benchmark-main.outputs.BENCH_RESULT12 }}
16
+ MAIN-BENCH-14: ${{ steps.benchmark-main.outputs.BENCH_RESULT14 }}
17
+ MAIN-BENCH-16: ${{ steps.benchmark-main.outputs.BENCH_RESULT16 }}
18
+ strategy:
19
+ matrix:
20
+ node-version: [12, 14, 16]
21
+ steps:
22
+ - uses: actions/checkout@v2
23
+ with:
24
+ ref: ${{github.event.pull_request.head.ref}}
25
+ repository: ${{github.event.pull_request.head.repo.full_name}}
26
+
27
+ - uses: actions/setup-node@v2
28
+ with:
29
+ node-version: ${{ matrix.node-version }}
30
+
31
+ - name: Install
32
+ run: |
33
+ npm install --ignore-scripts
34
+
35
+ - name: Run benchmark
36
+ id: benchmark-pr
37
+ run: |
38
+ npm run --silent benchmark > ./bench-result
39
+ content=$(cat ./bench-result)
40
+ content="${content//'%'/'%25'}"
41
+ content="${content//$'\n'/'%0A'}"
42
+ content="${content//$'\r'/'%0D'}"
43
+ echo "::set-output name=BENCH_RESULT${{matrix.node-version}}::$content"
44
+
45
+ # main benchmark
46
+ - uses: actions/checkout@v2
47
+ with:
48
+ ref: 'master'
49
+
50
+ - name: Install
51
+ run: |
52
+ npm install --ignore-scripts
53
+
54
+ - name: Run benchmark
55
+ id: benchmark-master
56
+ run: |
57
+ npm run --silent benchmark > ./bench-result
58
+ content=$(cat ./bench-result)
59
+ content="${content//'%'/'%25'}"
60
+ content="${content//$'\n'/'%0A'}"
61
+ content="${content//$'\r'/'%0D'}"
62
+ echo "::set-output name=BENCH_RESULT${{matrix.node-version}}::$content"
63
+
64
+ output-benchmark:
65
+ needs: [benchmark]
66
+ runs-on: ubuntu-latest
67
+ steps:
68
+ - name: Comment PR
69
+ uses: thollander/actions-comment-pull-request@v1
70
+ with:
71
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
72
+ message: |
73
+ **Node**: 12
74
+ **PR**:
75
+ ```
76
+ ${{ needs.benchmark.outputs.PR-BENCH-12 }}
77
+ ```
78
+ **MAIN**:
79
+ ```
80
+ ${{ needs.benchmark.outputs.MAIN-BENCH-12 }}
81
+ ```
82
+
83
+ ---
84
+
85
+ **Node**: 14
86
+ **PR**:
87
+ ```
88
+ ${{ needs.benchmark.outputs.PR-BENCH-14 }}
89
+ ```
90
+ **MAIN**:
91
+ ```
92
+ ${{ needs.benchmark.outputs.MAIN-BENCH-14 }}
93
+ ```
94
+
95
+ ---
96
+
97
+ **Node**: 16
98
+ **PR**:
99
+ ```
100
+ ${{ needs.benchmark.outputs.PR-BENCH-16 }}
101
+ ```
102
+ **MAIN**:
103
+ ```
104
+ ${{ needs.benchmark.outputs.MAIN-BENCH-16 }}
105
+ ```
106
+
107
+ - uses: actions-ecosystem/action-remove-labels@v1
108
+ with:
109
+ labels: |
110
+ benchmark
111
+ github_token: ${{ secrets.GITHUB_TOKEN }}
@@ -22,7 +22,7 @@ jobs:
22
22
  - uses: actions/checkout@v2.3.4
23
23
 
24
24
  - name: Use Node.js
25
- uses: actions/setup-node@v2.1.5
25
+ uses: actions/setup-node@v2.4.0
26
26
  with:
27
27
  node-version: ${{ matrix.node-version }}
28
28
 
@@ -38,6 +38,6 @@ jobs:
38
38
  needs: test
39
39
  runs-on: ubuntu-latest
40
40
  steps:
41
- - uses: fastify/github-action-merge-dependabot@v2.1.1
41
+ - uses: fastify/github-action-merge-dependabot@v2.5.0
42
42
  with:
43
43
  github-token: ${{ secrets.GITHUB_TOKEN }}
package/README.md CHANGED
@@ -12,22 +12,25 @@ __fast-json-stringify__ is significantly faster than `JSON.stringify()` for smal
12
12
  ##### Benchmarks
13
13
 
14
14
  - Machine: `EX41S-SSD, Intel Core i7, 4Ghz, 64GB RAM, 4C/8T, SSD`.
15
- - Node.js `v12.16.2`
15
+ - Node.js `v16.9.1`
16
16
 
17
17
  ```
18
- FJS creation x 59,805 ops/sec ±0.23% (91 runs sampled)
18
+ FJS creation x 6,040 ops/sec ±1.17% (91 runs sampled)
19
19
 
20
- JSON.stringify array x 5,330 ops/sec ±0.54% (97 runs sampled)
21
- fast-json-stringify array x 6,995 ops/sec ±0.24% (94 runs sampled)
20
+ JSON.stringify array x 5,519 ops/sec ±0.08% (99 runs sampled)
21
+ fast-json-stringify array x 7,143 ops/sec ±0.14% (97 runs sampled)
22
22
 
23
- JSON.stringify long string x 15,108 ops/sec ±0.13% (100 runs sampled)
24
- fast-json-stringify long string x 15,089 ops/sec ±0.15% (98 runs sampled)
23
+ JSON.stringify long string x 16,438 ops/sec ±0.32% (98 runs sampled)
24
+ fast-json-stringify long string x 16,457 ops/sec ±0.09% (97 runs sampled)
25
25
 
26
- JSON.stringify short string x 13,214,696 ops/sec ±0.19% (97 runs sampled)
27
- fast-json-stringify short string x 33,378,500 ops/sec ±0.27% (95 runs sampled)
26
+ JSON.stringify short string x 12,061,258 ops/sec ±0.32% (97 runs sampled)
27
+ fast-json-stringify short string x 35,531,071 ops/sec ±0.17% (94 runs sampled)
28
28
 
29
- JSON.stringify obj x 3,172,653 ops/sec ±0.15% (98 runs sampled)
30
- fast-json-stringify obj x 13,537,123 ops/sec ±0.19% (95 runs sampled)
29
+ JSON.stringify obj x 3,079,746 ops/sec ±0.09% (95 runs sampled)
30
+ fast-json-stringify obj x 7,721,569 ops/sec ±0.12% (98 runs sampled)
31
+
32
+ JSON stringify date x 1,149,786 ops/sec ±0.10% (99 runs sampled)
33
+ fast-json-stringify date format x 1,674,498 ops/sec ±0.12% (99 runs sampled)
31
34
  ```
32
35
 
33
36
  #### Table of contents:
package/bench.js CHANGED
@@ -50,22 +50,38 @@ const arraySchemaCJS = {
50
50
  items: schemaCJS
51
51
  }
52
52
 
53
+ const dateFormatSchema = {
54
+ description: 'Date of birth',
55
+ type: 'string',
56
+ format: 'date'
57
+ }
58
+
59
+ const dateFormatSchemaCJS = {
60
+ description: 'Date of birth',
61
+ type: 'string',
62
+ format: 'date'
63
+ }
64
+
53
65
  const obj = {
54
66
  firstName: 'Matteo',
55
67
  lastName: 'Collina',
56
68
  age: 32
57
69
  }
58
70
 
71
+ const date = new Date()
72
+
59
73
  const multiArray = []
60
74
 
61
75
  const CJS = require('compile-json-stringify')
62
76
  const CJSStringify = CJS(schemaCJS)
63
77
  const CJSStringifyArray = CJS(arraySchemaCJS)
78
+ const CJSStringifyDate = CJS(dateFormatSchemaCJS)
64
79
  const CJSStringifyString = CJS({ type: 'string' })
65
80
 
66
81
  const FJS = require('.')
67
82
  const stringify = FJS(schema)
68
83
  const stringifyArray = FJS(arraySchema)
84
+ const stringifyDate = FJS(dateFormatSchema)
69
85
  const stringifyString = FJS({ type: 'string' })
70
86
  let str = ''
71
87
 
@@ -138,6 +154,18 @@ suite.add('compile-json-stringify obj', function () {
138
154
  CJSStringify(obj)
139
155
  })
140
156
 
157
+ suite.add('JSON stringify date', function () {
158
+ JSON.stringify(date)
159
+ })
160
+
161
+ suite.add('fast-json-stringify date format', function () {
162
+ stringifyDate(date)
163
+ })
164
+
165
+ suite.add('compile-json-stringify date format', function () {
166
+ CJSStringifyDate(date)
167
+ })
168
+
141
169
  suite.on('cycle', cycle)
142
170
 
143
171
  suite.run()
package/index.d.ts CHANGED
@@ -64,6 +64,7 @@ declare namespace build {
64
64
 
65
65
  export interface StringSchema extends BaseSchema {
66
66
  type: "string";
67
+ format?: string;
67
68
  }
68
69
 
69
70
  export interface IntegerSchema extends BaseSchema {
package/index.js CHANGED
@@ -47,7 +47,10 @@ function mergeLocation (source, dest) {
47
47
  }
48
48
  }
49
49
 
50
+ const referenceSerializersMap = new Map()
51
+
50
52
  function build (schema, options) {
53
+ referenceSerializersMap.clear()
51
54
  options = options || {}
52
55
  isValidSchema(schema)
53
56
  if (options.schema) {
@@ -144,6 +147,8 @@ function build (schema, options) {
144
147
  return dependenciesName
145
148
  }
146
149
 
150
+ referenceSerializersMap.clear()
151
+
147
152
  return (Function.apply(null, dependenciesName).apply(null, dependencies))
148
153
  }
149
154
 
@@ -285,10 +290,7 @@ function $asDatetime (date, skipQuotes) {
285
290
  function $asDate (date, skipQuotes) {
286
291
  const quotes = skipQuotes === true ? '' : '"'
287
292
  if (date instanceof Date) {
288
- const year = new Intl.DateTimeFormat('en', { year: 'numeric' }).format(date)
289
- const month = new Intl.DateTimeFormat('en', { month: '2-digit' }).format(date)
290
- const day = new Intl.DateTimeFormat('en', { day: '2-digit' }).format(date)
291
- return quotes + year + '-' + month + '-' + day + quotes
293
+ return quotes + new Date(date.getTime() - (date.getTimezoneOffset() * 60000 )).toISOString().slice(0, 10) + quotes
292
294
  } else if (date && typeof date.format === 'function') {
293
295
  return quotes + date.format('YYYY-MM-DD') + quotes
294
296
  } else {
@@ -959,9 +961,6 @@ function buildArray (location, code, name, key = null) {
959
961
  }
960
962
  `
961
963
  }
962
- code += `
963
- var json = '['
964
- `
965
964
  const laterCode = ''
966
965
 
967
966
  // default to any items type
@@ -975,8 +974,18 @@ function buildArray (location, code, name, key = null) {
975
974
  schema = location.schema
976
975
  schema[fjsCloned] = true
977
976
  }
977
+
978
978
  location = refFinder(schema.items.$ref, location)
979
979
  schema.items = location.schema
980
+
981
+ if (referenceSerializersMap.has(schema.items)) {
982
+ code += `
983
+ return ${referenceSerializersMap.get(schema.items)}(obj)
984
+ }
985
+ `
986
+ return code
987
+ }
988
+ referenceSerializersMap.set(schema.items, name)
980
989
  }
981
990
 
982
991
  let result = { code: '', laterCode: '' }
@@ -1023,15 +1032,17 @@ function buildArray (location, code, name, key = null) {
1023
1032
 
1024
1033
  code += `
1025
1034
  var l = obj.length
1026
- var w = l - 1
1035
+ var jsonOutput= ''
1027
1036
  for (var i = 0; i < l; i++) {
1028
- if (i > 0) {
1029
- json += ','
1030
- }
1037
+ var json = ''
1031
1038
  ${result.code}
1039
+ jsonOutput += json
1040
+
1041
+ if (json.length > 0 && i < l - 1) {
1042
+ jsonOutput += ','
1043
+ }
1032
1044
  }
1033
- json += ']'
1034
- return json
1045
+ return \`[\${jsonOutput}]\`
1035
1046
  }
1036
1047
  ${result.laterCode}
1037
1048
  `
@@ -1214,9 +1225,12 @@ function nested (laterCode, name, key, location, subKey, isArray) {
1214
1225
  `
1215
1226
  laterCode = nestedResult.laterCode
1216
1227
  })
1217
- code += `
1218
- else json+= null
1219
- `
1228
+
1229
+ if (!isArray) {
1230
+ code += `
1231
+ else json+= null
1232
+ `
1233
+ }
1220
1234
  } else if (isEmpty(schema)) {
1221
1235
  code += `
1222
1236
  json += JSON.stringify(obj${accessor})
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fast-json-stringify",
3
- "version": "2.7.7",
3
+ "version": "2.7.11",
4
4
  "description": "Stringify your JSON at max speed",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -401,3 +401,105 @@ test('oneOf object with field of type string with format or null', (t) => {
401
401
  prop: toStringify
402
402
  }), `{"prop":"${toStringify.toISOString()}"}`)
403
403
  })
404
+
405
+ test('one array item match oneOf types', (t) => {
406
+ t.plan(1)
407
+
408
+ const schema = {
409
+ type: 'object',
410
+ additionalProperties: false,
411
+ required: ['data'],
412
+ properties: {
413
+ data: {
414
+ type: 'array',
415
+ minItems: 1,
416
+ items: {
417
+ oneOf: [
418
+ {
419
+ type: 'string'
420
+ },
421
+ {
422
+ type: 'number'
423
+ }
424
+ ]
425
+ }
426
+ }
427
+ }
428
+ }
429
+
430
+ const stringify = build(schema)
431
+
432
+ const responseWithMappedType = stringify({
433
+ data: [false, 'foo']
434
+ })
435
+
436
+ t.equal('{"data":["foo"]}', responseWithMappedType)
437
+ })
438
+
439
+ test('some array items match oneOf types', (t) => {
440
+ t.plan(1)
441
+
442
+ const schema = {
443
+ type: 'object',
444
+ additionalProperties: false,
445
+ required: ['data'],
446
+ properties: {
447
+ data: {
448
+ type: 'array',
449
+ minItems: 1,
450
+ items: {
451
+ oneOf: [
452
+ {
453
+ type: 'string'
454
+ },
455
+ {
456
+ type: 'number'
457
+ }
458
+ ]
459
+ }
460
+ }
461
+ }
462
+ }
463
+
464
+ const stringify = build(schema)
465
+
466
+ const responseWithMappedTypes = stringify({
467
+ data: [false, 'foo', true, 5]
468
+ })
469
+
470
+ t.equal('{"data":["foo",5]}', responseWithMappedTypes)
471
+ })
472
+
473
+ test('all array items does not match oneOf types', (t) => {
474
+ t.plan(1)
475
+
476
+ const schema = {
477
+ type: 'object',
478
+ additionalProperties: false,
479
+ required: ['data'],
480
+ properties: {
481
+ data: {
482
+ type: 'array',
483
+ minItems: 1,
484
+ items: {
485
+ oneOf: [
486
+ {
487
+ type: 'string'
488
+ },
489
+ {
490
+ type: 'number'
491
+ }
492
+ ]
493
+ }
494
+ }
495
+ }
496
+ }
497
+
498
+ const stringify = build(schema)
499
+
500
+ const emptyResponse = stringify({
501
+ data: [null, false, true, undefined, [], {}]
502
+ })
503
+
504
+ t.equal('{"data":[]}', emptyResponse)
505
+ })
@@ -0,0 +1,137 @@
1
+ 'use strict'
2
+
3
+ const test = require('tap').test
4
+ const build = require('..')
5
+
6
+ test('can stringify recursive directory tree (issue #181)', (t) => {
7
+ t.plan(1)
8
+
9
+ const schema = {
10
+ definitions: {
11
+ directory: {
12
+ type: 'object',
13
+ properties: {
14
+ name: { type: 'string' },
15
+ subDirectories: {
16
+ type: 'array',
17
+ items: { $ref: '#/definitions/directory' },
18
+ default: []
19
+ }
20
+ }
21
+ }
22
+ },
23
+ type: 'array',
24
+ items: { $ref: '#/definitions/directory' }
25
+ }
26
+ const stringify = build(schema)
27
+
28
+ t.equal(stringify([
29
+ { name: 'directory 1', subDirectories: [] },
30
+ {
31
+ name: 'directory 2',
32
+ subDirectories: [
33
+ { name: 'directory 2.1', subDirectories: [] },
34
+ { name: 'directory 2.2', subDirectories: [] }
35
+ ]
36
+ }
37
+ ]), '[{"name":"directory 1","subDirectories":[]},{"name":"directory 2","subDirectories":[{"name":"directory 2.1","subDirectories":[]},{"name":"directory 2.2","subDirectories":[]}]}]')
38
+ })
39
+
40
+ test('can stringify when recursion in external schema', t => {
41
+ t.plan(1)
42
+
43
+ const referenceSchema = {
44
+ $id: 'person',
45
+ type: 'object',
46
+ properties: {
47
+ name: { type: 'string' },
48
+ children: {
49
+ type: 'array',
50
+ items: { $ref: '#' }
51
+ }
52
+ }
53
+ }
54
+
55
+ const schema = {
56
+ $id: 'mainSchema',
57
+ type: 'object',
58
+ properties: {
59
+ people: {
60
+ $ref: 'person'
61
+ }
62
+ }
63
+ }
64
+ const stringify = build(schema, {
65
+ schema: {
66
+ [referenceSchema.$id]: referenceSchema
67
+ }
68
+ })
69
+
70
+ const value = stringify({ people: { name: 'Elizabeth', children: [{ name: 'Charles' }] } })
71
+ t.equal(value, '{"people":{"name":"Elizabeth","children":[{"name":"Charles"}]}}')
72
+ })
73
+
74
+ test('use proper serialize function', t => {
75
+ t.plan(1)
76
+
77
+ const personSchema = {
78
+ $id: 'person',
79
+ type: 'object',
80
+ properties: {
81
+ name: { type: 'string' },
82
+ children: {
83
+ type: 'array',
84
+ items: { $ref: '#' }
85
+ }
86
+ }
87
+ }
88
+
89
+ const directorySchema = {
90
+ $id: 'directory',
91
+ type: 'object',
92
+ properties: {
93
+ name: { type: 'string' },
94
+ subDirectories: {
95
+ type: 'array',
96
+ items: { $ref: '#' },
97
+ default: []
98
+ }
99
+ }
100
+ }
101
+
102
+ const schema = {
103
+ $id: 'mainSchema',
104
+ type: 'object',
105
+ properties: {
106
+ people: { $ref: 'person' },
107
+ directory: { $ref: 'directory' }
108
+ }
109
+ }
110
+ const stringify = build(schema, {
111
+ schema: {
112
+ [personSchema.$id]: personSchema,
113
+ [directorySchema.$id]: directorySchema
114
+ }
115
+ })
116
+
117
+ const value = stringify({
118
+ people: {
119
+ name: 'Elizabeth',
120
+ children: [{
121
+ name: 'Charles',
122
+ children: [{ name: 'William', children: [{ name: 'George' }, { name: 'Charlotte' }] }, { name: 'Harry' }]
123
+ }]
124
+ },
125
+ directory: {
126
+ name: 'directory 1',
127
+ subDirectories: [
128
+ { name: 'directory 1.1', subDirectories: [] },
129
+ {
130
+ name: 'directory 1.2',
131
+ subDirectories: [{ name: 'directory 1.2.1' }, { name: 'directory 1.2.2' }]
132
+ }
133
+ ]
134
+ }
135
+ })
136
+ t.equal(value, '{"people":{"name":"Elizabeth","children":[{"name":"Charles","children":[{"name":"William","children":[{"name":"George"},{"name":"Charlotte"}]},{"name":"Harry"}]}]},"directory":{"name":"directory 1","subDirectories":[{"name":"directory 1.1","subDirectories":[]},{"name":"directory 1.2","subDirectories":[{"name":"directory 1.2.1","subDirectories":[]},{"name":"directory 1.2.2","subDirectories":[]}]}]}}')
137
+ })
@@ -135,3 +135,11 @@ const schema11: Schema = {
135
135
  }
136
136
 
137
137
  build(schema11)({ something: 'a string', somethingElse: 42 })
138
+
139
+ // String schema with format
140
+ const schema12: Schema = {
141
+ type: 'string',
142
+ format: 'date-time'
143
+ }
144
+
145
+ build(schema12)(new Date())