fast-json-stringify 3.1.0 → 4.1.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 +3 -3
- package/.github/workflows/ci.yml +3 -33
- package/README.md +37 -13
- package/ajv.js +37 -0
- package/benchmark/bench-cmp-branch.js +114 -0
- package/{bench.js → benchmark/bench-cmp-lib.js} +4 -4
- package/benchmark/bench-thread.js +21 -0
- package/benchmark/bench.js +251 -0
- package/example.js +0 -3
- package/index.d.ts +4 -0
- package/index.js +402 -691
- package/package.json +11 -5
- package/serializer.js +168 -0
- package/test/additionalProperties.test.js +23 -19
- package/test/allof.test.js +56 -0
- package/test/anyof.test.js +88 -9
- package/test/array.test.js +110 -23
- package/test/basic.test.js +8 -8
- package/test/date.test.js +62 -35
- package/test/debug-mode.test.js +1 -1
- package/test/fixtures/.keep +0 -0
- package/test/if-then-else.test.js +2 -2
- package/test/nestedObjects.test.js +31 -0
- package/test/nullable.test.js +343 -15
- package/test/oneof.test.js +9 -22
- package/test/patternProperties.test.js +17 -6
- package/test/recursion.test.js +65 -0
- package/test/required.test.js +1 -1
- package/test/sanitize3.test.js +9 -11
- package/test/standalone-mode.test.js +38 -0
- package/test/typesArray.test.js +40 -3
|
@@ -21,13 +21,13 @@ jobs:
|
|
|
21
21
|
matrix:
|
|
22
22
|
node-version: [12, 14, 16]
|
|
23
23
|
steps:
|
|
24
|
-
- uses: actions/checkout@
|
|
24
|
+
- uses: actions/checkout@v3
|
|
25
25
|
with:
|
|
26
26
|
persist-credentials: false
|
|
27
27
|
ref: ${{github.event.pull_request.head.sha}}
|
|
28
28
|
repository: ${{github.event.pull_request.head.repo.full_name}}
|
|
29
29
|
|
|
30
|
-
- uses: actions/setup-node@
|
|
30
|
+
- uses: actions/setup-node@v3
|
|
31
31
|
with:
|
|
32
32
|
node-version: ${{ matrix.node-version }}
|
|
33
33
|
|
|
@@ -46,7 +46,7 @@ jobs:
|
|
|
46
46
|
echo "::set-output name=BENCH_RESULT${{matrix.node-version}}::$content"
|
|
47
47
|
|
|
48
48
|
# main benchmark
|
|
49
|
-
- uses: actions/checkout@
|
|
49
|
+
- uses: actions/checkout@v3
|
|
50
50
|
with:
|
|
51
51
|
ref: 'master'
|
|
52
52
|
|
package/.github/workflows/ci.yml
CHANGED
|
@@ -12,36 +12,6 @@ on:
|
|
|
12
12
|
|
|
13
13
|
jobs:
|
|
14
14
|
test:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
node-version: [14, 16, 17]
|
|
19
|
-
os: [macos-latest, ubuntu-latest, windows-latest]
|
|
20
|
-
|
|
21
|
-
steps:
|
|
22
|
-
- uses: actions/checkout@v2
|
|
23
|
-
|
|
24
|
-
- name: Use Node.js
|
|
25
|
-
uses: actions/setup-node@v2
|
|
26
|
-
with:
|
|
27
|
-
node-version: ${{ matrix.node-version }}
|
|
28
|
-
|
|
29
|
-
- name: Install Dependencies
|
|
30
|
-
run: |
|
|
31
|
-
npm install --ignore-scripts
|
|
32
|
-
|
|
33
|
-
- name: Run Tests
|
|
34
|
-
run: |
|
|
35
|
-
npm test
|
|
36
|
-
|
|
37
|
-
automerge:
|
|
38
|
-
needs: test
|
|
39
|
-
runs-on: ubuntu-latest
|
|
40
|
-
permissions:
|
|
41
|
-
pull-requests: write
|
|
42
|
-
contents: write
|
|
43
|
-
steps:
|
|
44
|
-
- uses: fastify/github-action-merge-dependabot@v3
|
|
45
|
-
with:
|
|
46
|
-
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
47
|
-
target: minor
|
|
15
|
+
uses: fastify/workflows/.github/workflows/plugins-ci.yml@v3
|
|
16
|
+
with:
|
|
17
|
+
auto-merge-exclude: 'chalk'
|
package/README.md
CHANGED
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
[](https://www.npmjs.com/package/fast-json-stringify)
|
|
5
|
-
[](https://snyk.io/test/github/fastify/fast-json-stringify)
|
|
6
5
|
[](https://standardjs.com/)
|
|
7
6
|
[](https://www.npmjs.com/package/fast-json-stringify)
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
__fast-json-stringify__ is significantly faster than `JSON.stringify()` for small payloads.
|
|
11
|
-
Its performance advantage shrinks as your payload grows.
|
|
9
|
+
__fast-json-stringify__ is significantly faster than `JSON.stringify()` for small payloads.
|
|
10
|
+
Its performance advantage shrinks as your payload grows.
|
|
12
11
|
It pairs well with [__flatstr__](https://www.npmjs.com/package/flatstr), which triggers a V8 optimization that improves performance when eventually converting the string to a `Buffer`.
|
|
13
12
|
|
|
14
13
|
|
|
@@ -63,6 +62,8 @@ compile-json-stringify date format x 1,086,187 ops/sec ±0.16% (99 runs sampled)
|
|
|
63
62
|
- <a href="#nullable">`Nullable`</a>
|
|
64
63
|
- <a href="#largearrays">`Large Arrays`</a>
|
|
65
64
|
- <a href="#security">`Security Notice`</a>
|
|
65
|
+
- <a href="#debug">`Debug Mode`</a>
|
|
66
|
+
- <a href="#standalone">`Standalone Mode`</a>
|
|
66
67
|
- <a href="#acknowledgements">`Acknowledgements`</a>
|
|
67
68
|
- <a href="#license">`License`</a>
|
|
68
69
|
|
|
@@ -160,18 +161,17 @@ And nested ones, too.
|
|
|
160
161
|
|
|
161
162
|
**Note**: In the case of string formatted Date and not Date Object, there will be no manipulation on it. It should be properly formatted.
|
|
162
163
|
|
|
163
|
-
Example with a
|
|
164
|
+
Example with a Date object:
|
|
164
165
|
|
|
165
166
|
```javascript
|
|
166
|
-
const moment = require('moment')
|
|
167
|
-
|
|
168
167
|
const stringify = fastJson({
|
|
169
168
|
title: 'Example Schema with string date-time field',
|
|
170
169
|
type: 'string',
|
|
171
170
|
format: 'date-time'
|
|
172
171
|
})
|
|
173
172
|
|
|
174
|
-
|
|
173
|
+
const date = new Date()
|
|
174
|
+
console.log(stringify(date)) // '"YYYY-MM-DDTHH:mm:ss.sssZ"'
|
|
175
175
|
```
|
|
176
176
|
|
|
177
177
|
|
|
@@ -287,7 +287,7 @@ console.log(stringify(obj)) // '{"matchfoo":"42","otherfoo":"str","matchnum":3,"
|
|
|
287
287
|
If *additionalProperties* is not present or is set to `false`, every property that is not explicitly listed in the *properties* and *patternProperties* objects,will be ignored, as described in <a href="#missingFields">Missing fields</a>.
|
|
288
288
|
Missing fields are ignored to avoid having to rewrite objects before serializing. However, other schema rules would throw in similar situations.
|
|
289
289
|
If *additionalProperties* is set to `true`, it will be used by `JSON.stringify` to stringify the additional properties. If you want to achieve maximum performance, we strongly encourage you to use a fixed schema where possible.
|
|
290
|
-
The additional properties will always be
|
|
290
|
+
The additional properties will always be serialized at the end of the object.
|
|
291
291
|
Example:
|
|
292
292
|
```javascript
|
|
293
293
|
const stringify = fastJson({
|
|
@@ -665,13 +665,37 @@ const debugCompiled = fastJson({
|
|
|
665
665
|
type: 'string'
|
|
666
666
|
}
|
|
667
667
|
}
|
|
668
|
-
}, {
|
|
668
|
+
}, { mode: 'debug' })
|
|
669
|
+
|
|
670
|
+
console.log(debugCompiled) // it is a object contain code, ajv instance
|
|
671
|
+
const rawString = debugCompiled.code // it is the generated code
|
|
672
|
+
console.log(rawString)
|
|
673
|
+
|
|
674
|
+
const stringify = fastJson.restore(debugCompiled) // use the generated string to get back the `stringify` function
|
|
675
|
+
console.log(stringify({ firstName: 'Foo', surname: 'bar' })) // '{"firstName":"Foo"}'
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
<a name="standalone"></a>
|
|
679
|
+
### Standalone Mode
|
|
669
680
|
|
|
670
|
-
|
|
671
|
-
|
|
681
|
+
The standalone mode is used to compile the code that can be directly run by `node`
|
|
682
|
+
itself. You need to install `fast-json-stringify`, `ajv`, `fast-uri` and `ajv-formats`
|
|
683
|
+
in order to let the standalone code works.
|
|
684
|
+
|
|
685
|
+
```js
|
|
686
|
+
const fs = require('fs')
|
|
687
|
+
const code = fastJson({
|
|
688
|
+
title: 'default string',
|
|
689
|
+
type: 'object',
|
|
690
|
+
properties: {
|
|
691
|
+
firstName: {
|
|
692
|
+
type: 'string'
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}, { mode: 'standalone' })
|
|
672
696
|
|
|
673
|
-
|
|
674
|
-
const stringify =
|
|
697
|
+
fs.writeFileSync('stringify.js', code)
|
|
698
|
+
const stringify = require('stringify.js')
|
|
675
699
|
console.log(stringify({ firstName: 'Foo', surname: 'bar' })) // '{"firstName":"Foo"}'
|
|
676
700
|
```
|
|
677
701
|
|
package/ajv.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const Ajv = require('ajv')
|
|
4
|
+
const fastUri = require('fast-uri')
|
|
5
|
+
const ajvFormats = require('ajv-formats')
|
|
6
|
+
|
|
7
|
+
module.exports = buildAjv
|
|
8
|
+
|
|
9
|
+
function buildAjv (options) {
|
|
10
|
+
const ajvInstance = new Ajv({ ...options, strictSchema: false, uriResolver: fastUri })
|
|
11
|
+
ajvFormats(ajvInstance)
|
|
12
|
+
|
|
13
|
+
const validateDateTimeFormat = ajvFormats.get('date-time').validate
|
|
14
|
+
const validateDateFormat = ajvFormats.get('date').validate
|
|
15
|
+
const validateTimeFormat = ajvFormats.get('time').validate
|
|
16
|
+
|
|
17
|
+
ajvInstance.addKeyword({
|
|
18
|
+
keyword: 'fjs_date_type',
|
|
19
|
+
validate: (schema, date) => {
|
|
20
|
+
if (date instanceof Date) {
|
|
21
|
+
return true
|
|
22
|
+
}
|
|
23
|
+
if (schema === 'date-time') {
|
|
24
|
+
return validateDateTimeFormat(date)
|
|
25
|
+
}
|
|
26
|
+
if (schema === 'date') {
|
|
27
|
+
return validateDateFormat(date)
|
|
28
|
+
}
|
|
29
|
+
if (schema === 'time') {
|
|
30
|
+
return validateTimeFormat(date)
|
|
31
|
+
}
|
|
32
|
+
return false
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
return ajvInstance
|
|
37
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { spawn } = require('child_process')
|
|
4
|
+
|
|
5
|
+
const chalk = require('chalk')
|
|
6
|
+
const inquirer = require('inquirer')
|
|
7
|
+
const simpleGit = require('simple-git')
|
|
8
|
+
|
|
9
|
+
const git = simpleGit(process.cwd())
|
|
10
|
+
|
|
11
|
+
const COMMAND = 'npm run bench'
|
|
12
|
+
const DEFAULT_BRANCH = 'master'
|
|
13
|
+
const PERCENT_THRESHOLD = 5
|
|
14
|
+
|
|
15
|
+
async function selectBranchName (message, branches) {
|
|
16
|
+
const result = await inquirer.prompt([{
|
|
17
|
+
type: 'list',
|
|
18
|
+
name: 'branch',
|
|
19
|
+
choices: branches,
|
|
20
|
+
loop: false,
|
|
21
|
+
pageSize: 20,
|
|
22
|
+
message
|
|
23
|
+
}])
|
|
24
|
+
return result.branch
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function executeCommandOnBranch (command, branch) {
|
|
28
|
+
console.log(chalk.grey(`Checking out "${branch}"`))
|
|
29
|
+
await git.checkout(branch)
|
|
30
|
+
|
|
31
|
+
console.log(chalk.grey(`Execute "${command}"`))
|
|
32
|
+
const childProcess = spawn(command, { stdio: 'pipe', shell: true })
|
|
33
|
+
|
|
34
|
+
let result = ''
|
|
35
|
+
childProcess.stdout.on('data', (data) => {
|
|
36
|
+
process.stdout.write(data.toString())
|
|
37
|
+
result += data.toString()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
await new Promise(resolve => childProcess.on('close', resolve))
|
|
41
|
+
|
|
42
|
+
console.log()
|
|
43
|
+
|
|
44
|
+
return parseBenchmarksStdout(result)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function parseBenchmarksStdout (text) {
|
|
48
|
+
const results = []
|
|
49
|
+
|
|
50
|
+
const lines = text.split('\n')
|
|
51
|
+
for (const line of lines) {
|
|
52
|
+
const match = /^(.+?)(\.*) x (.+) ops\/sec .*$/.exec(line)
|
|
53
|
+
if (match !== null) {
|
|
54
|
+
results.push({
|
|
55
|
+
name: match[1],
|
|
56
|
+
alignedName: match[1] + match[2],
|
|
57
|
+
result: parseInt(match[3].split(',').join(''))
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return results
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function compareResults (featureBranch, mainBranch) {
|
|
66
|
+
for (const { name, alignedName, result: mainBranchResult } of mainBranch) {
|
|
67
|
+
const featureBranchBenchmark = featureBranch.find(result => result.name === name)
|
|
68
|
+
if (featureBranchBenchmark) {
|
|
69
|
+
const featureBranchResult = featureBranchBenchmark.result
|
|
70
|
+
const percent = (featureBranchResult - mainBranchResult) * 100 / mainBranchResult
|
|
71
|
+
const roundedPercent = Math.round(percent * 100) / 100
|
|
72
|
+
|
|
73
|
+
const percentString = roundedPercent > 0 ? `+${roundedPercent}%` : `${roundedPercent}%`
|
|
74
|
+
const message = alignedName + percentString.padStart(7, '.')
|
|
75
|
+
|
|
76
|
+
if (roundedPercent > PERCENT_THRESHOLD) {
|
|
77
|
+
console.log(chalk.green(message))
|
|
78
|
+
} else if (roundedPercent < -PERCENT_THRESHOLD) {
|
|
79
|
+
console.log(chalk.red(message))
|
|
80
|
+
} else {
|
|
81
|
+
console.log(message)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
(async function () {
|
|
88
|
+
const branches = await git.branch()
|
|
89
|
+
const currentBranch = branches.branches[branches.current]
|
|
90
|
+
|
|
91
|
+
let featureBranch = null
|
|
92
|
+
let mainBranch = null
|
|
93
|
+
|
|
94
|
+
if (process.argv[2] === '--ci') {
|
|
95
|
+
featureBranch = currentBranch.name
|
|
96
|
+
mainBranch = DEFAULT_BRANCH
|
|
97
|
+
} else {
|
|
98
|
+
featureBranch = await selectBranchName('Select the branch you want to compare (feature branch):', branches.all)
|
|
99
|
+
mainBranch = await selectBranchName('Select the branch you want to compare with (main branch):', branches.all)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
const featureBranchResult = await executeCommandOnBranch(COMMAND, featureBranch)
|
|
104
|
+
const mainBranchResult = await executeCommandOnBranch(COMMAND, mainBranch)
|
|
105
|
+
compareResults(featureBranchResult, mainBranchResult)
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error('Switch to origin branch due to an error', error.message)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
await git.checkout(currentBranch.commit)
|
|
111
|
+
await git.checkout(currentBranch.name)
|
|
112
|
+
|
|
113
|
+
console.log(chalk.gray(`Back to ${currentBranch.name} ${currentBranch.commit}`))
|
|
114
|
+
})()
|
|
@@ -5,7 +5,7 @@ const suite = new benchmark.Suite()
|
|
|
5
5
|
|
|
6
6
|
const STR_LEN = 1e4
|
|
7
7
|
const LARGE_ARRAY_SIZE = 2e4
|
|
8
|
-
const
|
|
8
|
+
const MULTI_ARRAY_LENGTH = 1e3
|
|
9
9
|
|
|
10
10
|
const schema = {
|
|
11
11
|
title: 'Example Schema',
|
|
@@ -93,7 +93,7 @@ const obj = {
|
|
|
93
93
|
|
|
94
94
|
const date = new Date()
|
|
95
95
|
|
|
96
|
-
const multiArray = new Array(
|
|
96
|
+
const multiArray = new Array(MULTI_ARRAY_LENGTH)
|
|
97
97
|
const largeArray = new Array(LARGE_ARRAY_SIZE)
|
|
98
98
|
|
|
99
99
|
const CJS = require('compile-json-stringify')
|
|
@@ -102,7 +102,7 @@ const CJSStringifyArray = CJS(arraySchemaCJS)
|
|
|
102
102
|
const CJSStringifyDate = CJS(dateFormatSchemaCJS)
|
|
103
103
|
const CJSStringifyString = CJS({ type: 'string' })
|
|
104
104
|
|
|
105
|
-
const FJS = require('
|
|
105
|
+
const FJS = require('..')
|
|
106
106
|
const stringify = FJS(schema)
|
|
107
107
|
const stringifyArrayDefault = FJS(arraySchema)
|
|
108
108
|
const stringifyArrayJSONStringify = FJS(arraySchema, {
|
|
@@ -158,7 +158,7 @@ for (let i = STR_LEN; i < LARGE_ARRAY_SIZE; ++i) {
|
|
|
158
158
|
|
|
159
159
|
Number(str)
|
|
160
160
|
|
|
161
|
-
for (let i = 0; i <
|
|
161
|
+
for (let i = 0; i < MULTI_ARRAY_LENGTH; i++) {
|
|
162
162
|
multiArray[i] = obj
|
|
163
163
|
}
|
|
164
164
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { workerData: benchmark, parentPort } = require('worker_threads')
|
|
4
|
+
|
|
5
|
+
const Benchmark = require('benchmark')
|
|
6
|
+
Benchmark.options.minSamples = 500
|
|
7
|
+
|
|
8
|
+
const suite = Benchmark.Suite()
|
|
9
|
+
|
|
10
|
+
const FJS = require('..')
|
|
11
|
+
const stringify = FJS(benchmark.schema)
|
|
12
|
+
|
|
13
|
+
suite
|
|
14
|
+
.add(benchmark.name, () => {
|
|
15
|
+
stringify(benchmark.input)
|
|
16
|
+
})
|
|
17
|
+
.on('cycle', (event) => {
|
|
18
|
+
parentPort.postMessage(String(event.target))
|
|
19
|
+
})
|
|
20
|
+
.on('complete', () => {})
|
|
21
|
+
.run()
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const path = require('path')
|
|
4
|
+
const { Worker } = require('worker_threads')
|
|
5
|
+
|
|
6
|
+
const BENCH_THREAD_PATH = path.join(__dirname, 'bench-thread.js')
|
|
7
|
+
|
|
8
|
+
const LONG_STRING_LENGTH = 1e4
|
|
9
|
+
const SHORT_ARRAY_SIZE = 1e3
|
|
10
|
+
|
|
11
|
+
const shortArrayOfNumbers = new Array(SHORT_ARRAY_SIZE)
|
|
12
|
+
const shortArrayOfIntegers = new Array(SHORT_ARRAY_SIZE)
|
|
13
|
+
const shortArrayOfShortStrings = new Array(SHORT_ARRAY_SIZE)
|
|
14
|
+
const shortArrayOfLongStrings = new Array(SHORT_ARRAY_SIZE)
|
|
15
|
+
const shortArrayOfMultiObject = new Array(SHORT_ARRAY_SIZE)
|
|
16
|
+
|
|
17
|
+
function getRandomInt (max) {
|
|
18
|
+
return Math.floor(Math.random() * max)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let longString = ''
|
|
22
|
+
for (let i = 0; i < LONG_STRING_LENGTH; i++) {
|
|
23
|
+
longString += i
|
|
24
|
+
if (i % 100 === 0) {
|
|
25
|
+
longString += '"'
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
for (let i = 0; i < SHORT_ARRAY_SIZE; i++) {
|
|
30
|
+
shortArrayOfNumbers[i] = getRandomInt(1000)
|
|
31
|
+
shortArrayOfIntegers[i] = getRandomInt(1000)
|
|
32
|
+
shortArrayOfShortStrings[i] = 'hello world'
|
|
33
|
+
shortArrayOfLongStrings[i] = longString
|
|
34
|
+
shortArrayOfMultiObject[i] = { s: 'hello world', n: 42, b: true }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const benchmarks = [
|
|
38
|
+
{
|
|
39
|
+
name: 'short string',
|
|
40
|
+
schema: {
|
|
41
|
+
type: 'string'
|
|
42
|
+
},
|
|
43
|
+
input: 'hello world'
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'long string',
|
|
47
|
+
schema: {
|
|
48
|
+
type: 'string'
|
|
49
|
+
},
|
|
50
|
+
input: longString
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'number',
|
|
54
|
+
schema: {
|
|
55
|
+
type: 'number'
|
|
56
|
+
},
|
|
57
|
+
input: 42
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'integer',
|
|
61
|
+
schema: {
|
|
62
|
+
type: 'integer'
|
|
63
|
+
},
|
|
64
|
+
input: 42
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'formatted date-time',
|
|
68
|
+
schema: {
|
|
69
|
+
type: 'string',
|
|
70
|
+
format: 'date-time'
|
|
71
|
+
},
|
|
72
|
+
input: new Date()
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'formatted date',
|
|
76
|
+
schema: {
|
|
77
|
+
type: 'string',
|
|
78
|
+
format: 'date'
|
|
79
|
+
},
|
|
80
|
+
input: new Date()
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: 'formatted time',
|
|
84
|
+
schema: {
|
|
85
|
+
type: 'string',
|
|
86
|
+
format: 'time'
|
|
87
|
+
},
|
|
88
|
+
input: new Date()
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'short array of numbers',
|
|
92
|
+
schema: {
|
|
93
|
+
type: 'array',
|
|
94
|
+
items: { type: 'number' }
|
|
95
|
+
},
|
|
96
|
+
input: shortArrayOfNumbers
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'short array of integers',
|
|
100
|
+
schema: {
|
|
101
|
+
type: 'array',
|
|
102
|
+
items: { type: 'integer' }
|
|
103
|
+
},
|
|
104
|
+
input: shortArrayOfIntegers
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: 'short array of short strings',
|
|
108
|
+
schema: {
|
|
109
|
+
type: 'array',
|
|
110
|
+
items: { type: 'string' }
|
|
111
|
+
},
|
|
112
|
+
input: shortArrayOfShortStrings
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: 'short array of long strings',
|
|
116
|
+
schema: {
|
|
117
|
+
type: 'array',
|
|
118
|
+
items: { type: 'string' }
|
|
119
|
+
},
|
|
120
|
+
input: shortArrayOfShortStrings
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: 'short array of objects with properties of different types',
|
|
124
|
+
schema: {
|
|
125
|
+
type: 'array',
|
|
126
|
+
items: {
|
|
127
|
+
type: 'object',
|
|
128
|
+
properties: {
|
|
129
|
+
s: { type: 'string' },
|
|
130
|
+
n: { type: 'number' },
|
|
131
|
+
b: { type: 'boolean' }
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
input: shortArrayOfMultiObject
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: 'object with number property',
|
|
139
|
+
schema: {
|
|
140
|
+
type: 'object',
|
|
141
|
+
properties: {
|
|
142
|
+
a: { type: 'number' }
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
input: { a: 42 }
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: 'object with integer property',
|
|
149
|
+
schema: {
|
|
150
|
+
type: 'object',
|
|
151
|
+
properties: {
|
|
152
|
+
a: { type: 'integer' }
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
input: { a: 42 }
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: 'object with short string property',
|
|
159
|
+
schema: {
|
|
160
|
+
type: 'object',
|
|
161
|
+
properties: {
|
|
162
|
+
a: { type: 'string' }
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
input: { a: 'hello world' }
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: 'object with long string property',
|
|
169
|
+
schema: {
|
|
170
|
+
type: 'object',
|
|
171
|
+
properties: {
|
|
172
|
+
a: { type: 'string' }
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
input: { a: longString }
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: 'object with properties of different types',
|
|
179
|
+
schema: {
|
|
180
|
+
type: 'object',
|
|
181
|
+
properties: {
|
|
182
|
+
s1: { type: 'string' },
|
|
183
|
+
n1: { type: 'number' },
|
|
184
|
+
b1: { type: 'boolean' },
|
|
185
|
+
s2: { type: 'string' },
|
|
186
|
+
n2: { type: 'number' },
|
|
187
|
+
b2: { type: 'boolean' },
|
|
188
|
+
s3: { type: 'string' },
|
|
189
|
+
n3: { type: 'number' },
|
|
190
|
+
b3: { type: 'boolean' },
|
|
191
|
+
s4: { type: 'string' },
|
|
192
|
+
n4: { type: 'number' },
|
|
193
|
+
b4: { type: 'boolean' },
|
|
194
|
+
s5: { type: 'string' },
|
|
195
|
+
n5: { type: 'number' },
|
|
196
|
+
b5: { type: 'boolean' }
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
input: {
|
|
200
|
+
s1: 'hello world',
|
|
201
|
+
n1: 42,
|
|
202
|
+
b1: true,
|
|
203
|
+
s2: 'hello world',
|
|
204
|
+
n2: 42,
|
|
205
|
+
b2: true,
|
|
206
|
+
s3: 'hello world',
|
|
207
|
+
n3: 42,
|
|
208
|
+
b3: true,
|
|
209
|
+
s4: 'hello world',
|
|
210
|
+
n4: 42,
|
|
211
|
+
b4: true,
|
|
212
|
+
s5: 'hello world',
|
|
213
|
+
n5: 42,
|
|
214
|
+
b5: true
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
]
|
|
218
|
+
|
|
219
|
+
async function runBenchmark (benchmark) {
|
|
220
|
+
const worker = new Worker(BENCH_THREAD_PATH, { workerData: benchmark })
|
|
221
|
+
|
|
222
|
+
return new Promise((resolve, reject) => {
|
|
223
|
+
let result = null
|
|
224
|
+
worker.on('error', reject)
|
|
225
|
+
worker.on('message', (benchResult) => {
|
|
226
|
+
result = benchResult
|
|
227
|
+
})
|
|
228
|
+
worker.on('exit', (code) => {
|
|
229
|
+
if (code === 0) {
|
|
230
|
+
resolve(result)
|
|
231
|
+
} else {
|
|
232
|
+
reject(new Error(`Worker stopped with exit code ${code}`))
|
|
233
|
+
}
|
|
234
|
+
})
|
|
235
|
+
})
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async function runBenchmarks () {
|
|
239
|
+
let maxNameLength = 0
|
|
240
|
+
for (const benchmark of benchmarks) {
|
|
241
|
+
maxNameLength = Math.max(benchmark.name.length, maxNameLength)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
for (const benchmark of benchmarks) {
|
|
245
|
+
benchmark.name = benchmark.name.padEnd(maxNameLength, '.')
|
|
246
|
+
const resultMessage = await runBenchmark(benchmark)
|
|
247
|
+
console.log(resultMessage)
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
runBenchmarks()
|
package/example.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const moment = require('moment')
|
|
2
1
|
const fastJson = require('.')
|
|
3
2
|
const stringify = fastJson({
|
|
4
3
|
title: 'Example Schema',
|
|
@@ -67,12 +66,10 @@ console.log(stringify({
|
|
|
67
66
|
lastName: 'Collina',
|
|
68
67
|
age: 32,
|
|
69
68
|
now: new Date(),
|
|
70
|
-
birthdate: moment(),
|
|
71
69
|
reg: /"([^"]|\\")*"/,
|
|
72
70
|
foo: 'hello',
|
|
73
71
|
numfoo: 42,
|
|
74
72
|
test: 42,
|
|
75
|
-
date: moment(),
|
|
76
73
|
strtest: '23',
|
|
77
74
|
arr: [{ str: 'stark' }, { str: 'lannister' }],
|
|
78
75
|
obj: { bool: true },
|