fatsify核心功能示例测试!!!
This commit is contained in:
2
node_modules/fast-json-stringify/.gitattributes
generated
vendored
Normal file
2
node_modules/fast-json-stringify/.gitattributes
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Set default behavior to automatically convert line endings
|
||||
* text=auto eol=lf
|
||||
13
node_modules/fast-json-stringify/.github/dependabot.yml
generated
vendored
Normal file
13
node_modules/fast-json-stringify/.github/dependabot.yml
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 10
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 10
|
||||
21
node_modules/fast-json-stringify/.github/stale.yml
generated
vendored
Normal file
21
node_modules/fast-json-stringify/.github/stale.yml
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 15
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- "discussion"
|
||||
- "feature request"
|
||||
- "bug"
|
||||
- "help wanted"
|
||||
- "plugin suggestion"
|
||||
- "good first issue"
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
85
node_modules/fast-json-stringify/.github/workflows/benchmark.yml
generated
vendored
Normal file
85
node_modules/fast-json-stringify/.github/workflows/benchmark.yml
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
name: Benchmark PR
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
benchmark:
|
||||
if: ${{ github.event.label.name == 'benchmark' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
outputs:
|
||||
PR-BENCH: ${{ steps.benchmark-pr.outputs.BENCH_RESULT }}
|
||||
MASTER-BENCH: ${{ steps.benchmark-master.outputs.BENCH_RESULT }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{github.event.pull_request.head.sha}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
npm install --ignore-scripts
|
||||
|
||||
- name: Run benchmark
|
||||
id: benchmark-pr
|
||||
run: |
|
||||
npm run --silent bench > ./bench-result
|
||||
content=$(cat ./bench-result)
|
||||
content="${content//'%'/'%25'}"
|
||||
content="${content//$'\n'/'%0A'}"
|
||||
content="${content//$'\r'/'%0D'}"
|
||||
echo "::set-output name=BENCH_RESULT::$content"
|
||||
|
||||
# master benchmark
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: 'master'
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
npm install --ignore-scripts
|
||||
|
||||
- name: Run benchmark
|
||||
id: benchmark-master
|
||||
run: |
|
||||
npm run --silent bench > ./bench-result
|
||||
content=$(cat ./bench-result)
|
||||
content="${content//'%'/'%25'}"
|
||||
content="${content//$'\n'/'%0A'}"
|
||||
content="${content//$'\r'/'%0D'}"
|
||||
echo "::set-output name=BENCH_RESULT::$content"
|
||||
|
||||
output-benchmark:
|
||||
if: "always()"
|
||||
needs: [benchmark]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Comment PR
|
||||
uses: thollander/actions-comment-pull-request@v3
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
message: |
|
||||
**PR**:
|
||||
```
|
||||
${{ needs.benchmark.outputs.PR-BENCH }}
|
||||
```
|
||||
**MASTER**:
|
||||
```
|
||||
${{ needs.benchmark.outputs.MASTER-BENCH }}
|
||||
```
|
||||
|
||||
- uses: actions-ecosystem/action-remove-labels@v1
|
||||
with:
|
||||
labels: |
|
||||
benchmark
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
23
node_modules/fast-json-stringify/.github/workflows/ci.yml
generated
vendored
Normal file
23
node_modules/fast-json-stringify/.github/workflows/ci.yml
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
- next
|
||||
- 'v*'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
uses: fastify/workflows/.github/workflows/plugins-ci.yml@v5
|
||||
with:
|
||||
license-check: true
|
||||
lint: true
|
||||
21
node_modules/fast-json-stringify/LICENSE
generated
vendored
Normal file
21
node_modules/fast-json-stringify/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2018 Matteo Collina
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
739
node_modules/fast-json-stringify/README.md
generated
vendored
Normal file
739
node_modules/fast-json-stringify/README.md
generated
vendored
Normal file
@@ -0,0 +1,739 @@
|
||||
# fast-json-stringify
|
||||
|
||||
[](https://github.com/fastify/fast-json-stringify/actions/workflows/ci.yml)
|
||||
[](https://www.npmjs.com/package/fast-json-stringify)
|
||||
[](https://github.com/neostandard/neostandard)
|
||||
[](https://www.npmjs.com/package/fast-json-stringify)
|
||||
|
||||
|
||||
__fast-json-stringify__ is significantly faster than `JSON.stringify()` for small payloads.
|
||||
Its performance advantage shrinks as your payload grows.
|
||||
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`.
|
||||
|
||||
|
||||
### How it works
|
||||
|
||||
fast-json-stringify requires a [JSON Schema Draft 7](https://json-schema.org/specification-links.html#draft-7) input to generate a fast `stringify` function.
|
||||
|
||||
##### Benchmarks
|
||||
|
||||
- Machine: `EX41S-SSD, Intel Core i7, 4Ghz, 64GB RAM, 4C/8T, SSD`.
|
||||
- Node.js `v18.12.1`
|
||||
|
||||
```
|
||||
FJS creation x 4,129 ops/sec ±0.82% (92 runs sampled)
|
||||
CJS creation x 184,196 ops/sec ±0.12% (97 runs sampled)
|
||||
AJV Serialize creation x 61,130,591 ops/sec ±0.40% (92 runs sampled)
|
||||
JSON.stringify array x 5,057 ops/sec ±0.10% (100 runs sampled)
|
||||
fast-json-stringify array default x 6,243 ops/sec ±0.14% (98 runs sampled)
|
||||
fast-json-stringify array json-stringify x 6,261 ops/sec ±0.30% (99 runs sampled)
|
||||
compile-json-stringify array x 6,842 ops/sec ±0.18% (96 runs sampled)
|
||||
AJV Serialize array x 6,964 ops/sec ±0.11% (95 runs sampled)
|
||||
JSON.stringify large array x 248 ops/sec ±0.07% (90 runs sampled)
|
||||
fast-json-stringify large array default x 99.96 ops/sec ±0.22% (74 runs sampled)
|
||||
fast-json-stringify large array json-stringify x 248 ops/sec ±0.07% (90 runs sampled)
|
||||
compile-json-stringify large array x 317 ops/sec ±0.09% (89 runs sampled)
|
||||
AJV Serialize large array x 111 ops/sec ±0.07% (33 runs sampled)
|
||||
JSON.stringify long string x 16,002 ops/sec ±0.09% (98 runs sampled)
|
||||
fast-json-stringify long string x 15,979 ops/sec ±0.09% (96 runs sampled)
|
||||
compile-json-stringify long string x 15,952 ops/sec ±0.31% (97 runs sampled)
|
||||
AJV Serialize long string x 21,416 ops/sec ±0.08% (98 runs sampled)
|
||||
JSON.stringify short string x 12,944,272 ops/sec ±0.09% (96 runs sampled)
|
||||
fast-json-stringify short string x 30,585,790 ops/sec ±0.27% (97 runs sampled)
|
||||
compile-json-stringify short string x 30,656,406 ops/sec ±0.12% (96 runs sampled)
|
||||
AJV Serialize short string x 30,406,785 ops/sec ±0.37% (96 runs sampled)
|
||||
JSON.stringify obj x 3,153,043 ops/sec ±0.33% (99 runs sampled)
|
||||
fast-json-stringify obj x 6,866,434 ops/sec ±0.11% (100 runs sampled)
|
||||
compile-json-stringify obj x 15,886,723 ops/sec ±0.15% (98 runs sampled)
|
||||
AJV Serialize obj x 8,969,043 ops/sec ±0.36% (97 runs sampled)
|
||||
JSON stringify date x 1,126,547 ops/sec ±0.09% (97 runs sampled)
|
||||
fast-json-stringify date format x 1,836,188 ops/sec ±0.12% (99 runs sampled)
|
||||
compile-json-stringify date format x 1,125,735 ops/sec ±0.19% (98 runs sampled)
|
||||
```
|
||||
|
||||
#### Table of contents:
|
||||
- <a href="#example">`Example`</a>
|
||||
- <a href="#options">`Options`</a>
|
||||
- <a href="#api">`API`</a>
|
||||
- <a href="#fastJsonStringify">`fastJsonStringify`</a>
|
||||
- <a href="#specific">`Specific use cases`</a>
|
||||
- <a href="#required">`Required`</a>
|
||||
- <a href="#missingFields">`Missing fields`</a>
|
||||
- <a href="#patternProperties">`Pattern Properties`</a>
|
||||
- <a href="#additionalProperties">`Additional Properties`</a>
|
||||
- <a href="#AnyOf-and-OneOf">`AnyOf` and `OneOf`</a>
|
||||
- <a href="#ref">`Reuse - $ref`</a>
|
||||
- <a href="#long">`Long integers`</a>
|
||||
- <a href="#integer">`Integers`</a>
|
||||
- <a href="#nullable">`Nullable`</a>
|
||||
- <a href="#largearrays">`Large Arrays`</a>
|
||||
- <a href="#security">`Security Notice`</a>
|
||||
- <a href="#debug">`Debug Mode`</a>
|
||||
- <a href="#standalone">`Standalone Mode`</a>
|
||||
- <a href="#acknowledgments">`Acknowledgments`</a>
|
||||
- <a href="#license">`License`</a>
|
||||
|
||||
|
||||
<a name="example"></a>
|
||||
Try it out on RunKit: <a href="https://runkit.com/npm/fast-json-stringify">https://runkit.com/npm/fast-json-stringify</a>
|
||||
## Example
|
||||
|
||||
```js
|
||||
const fastJson = require('fast-json-stringify')
|
||||
const stringify = fastJson({
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: 'string'
|
||||
},
|
||||
age: {
|
||||
description: 'Age in years',
|
||||
type: 'integer'
|
||||
},
|
||||
reg: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
console.log(stringify({
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32,
|
||||
reg: /"([^"]|\\")*"/
|
||||
}))
|
||||
```
|
||||
|
||||
<a name="options"></a>
|
||||
## Options
|
||||
|
||||
Optionally, you may provide to `fast-json-stringify` an option object as the second parameter:
|
||||
|
||||
```js
|
||||
const fastJson = require('fast-json-stringify')
|
||||
const stringify = fastJson(mySchema, {
|
||||
schema: { ... },
|
||||
ajv: { ... },
|
||||
rounding: 'ceil'
|
||||
})
|
||||
```
|
||||
|
||||
- `schema`: external schemas references by $ref property. [More details](#ref)
|
||||
- `ajv`: [ajv v8 instance's settings](https://ajv.js.org/options.html) for those properties that require `ajv`. [More details](#anyof)
|
||||
- `rounding`: setup how the `integer` types will be rounded when not integers. [More details](#integer)
|
||||
- `largeArrayMechanism`: set the mechanism that should be used to handle large
|
||||
(by default `20000` or more items) arrays. [More details](#largearrays)
|
||||
|
||||
|
||||
<a name="api"></a>
|
||||
## API
|
||||
<a name="fastJsonStringify"></a>
|
||||
### fastJsonStringify(schema)
|
||||
|
||||
Build a `stringify()` function based on [jsonschema draft 7 spec](https://json-schema.org/specification-links.html#draft-7).
|
||||
|
||||
Supported types:
|
||||
|
||||
* `'string'`
|
||||
* `'integer'`
|
||||
* `'number'`
|
||||
* `'array'`
|
||||
* `'object'`
|
||||
* `'boolean'`
|
||||
* `'null'`
|
||||
|
||||
And nested ones, too.
|
||||
|
||||
<a name="specific"></a>
|
||||
#### Specific use cases
|
||||
|
||||
| Instance | Serialized as |
|
||||
| -------- | ---------------------------- |
|
||||
| `Date` | `string` via `toISOString()` |
|
||||
| `RegExp` | `string` |
|
||||
| `BigInt` | `integer` via `toString` |
|
||||
|
||||
[JSON Schema built-in formats](https://json-schema.org/understanding-json-schema/reference/string.html#built-in-formats) for dates are supported and will be serialized as:
|
||||
|
||||
| Format | Serialized format example |
|
||||
| ----------- | -------------------------- |
|
||||
| `date-time` | `2020-04-03T09:11:08.615Z` |
|
||||
| `date` | `2020-04-03` |
|
||||
| `time` | `09:11:08` |
|
||||
|
||||
**Note**: In the case of a string formatted Date and not Date Object, there will be no manipulation on it. It should be properly formatted.
|
||||
|
||||
Example with a Date object:
|
||||
|
||||
```javascript
|
||||
const stringify = fastJson({
|
||||
title: 'Example Schema with string date-time field',
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
})
|
||||
|
||||
const date = new Date()
|
||||
console.log(stringify(date)) // '"YYYY-MM-DDTHH:mm:ss.sssZ"'
|
||||
```
|
||||
|
||||
|
||||
<a name="required"></a>
|
||||
#### Required
|
||||
You can set specific fields of an object as required in your schema by adding the field name inside the `required` array in your schema.
|
||||
Example:
|
||||
```javascript
|
||||
const schema = {
|
||||
title: 'Example Schema with required field',
|
||||
type: 'object',
|
||||
properties: {
|
||||
nickname: {
|
||||
type: 'string'
|
||||
},
|
||||
mail: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
required: ['mail']
|
||||
}
|
||||
```
|
||||
If the object to stringify is missing the required field(s), `fast-json-stringify` will throw an error.
|
||||
|
||||
<a name="missingFields"></a>
|
||||
#### Missing fields
|
||||
If a field *is present* in the schema (and is not required) but it *is not present* in the object to stringify, `fast-json-stringify` will not write it in the final string.
|
||||
Example:
|
||||
```javascript
|
||||
const stringify = fastJson({
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
nickname: {
|
||||
type: 'string'
|
||||
},
|
||||
mail: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = {
|
||||
mail: 'mail@example.com'
|
||||
}
|
||||
|
||||
console.log(stringify(obj)) // '{"mail":"mail@example.com"}'
|
||||
```
|
||||
|
||||
<a name="defaults"></a>
|
||||
#### Defaults
|
||||
`fast-json-stringify` supports `default` jsonschema key in order to serialize a value
|
||||
if it is `undefined` or not present.
|
||||
|
||||
Example:
|
||||
```javascript
|
||||
const stringify = fastJson({
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
nickname: {
|
||||
type: 'string',
|
||||
default: 'the default string'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
console.log(stringify({})) // '{"nickname":"the default string"}'
|
||||
console.log(stringify({nickname: 'my-nickname'})) // '{"nickname":"my-nickname"}'
|
||||
```
|
||||
|
||||
<a name="patternProperties"></a>
|
||||
#### Pattern properties
|
||||
`fast-json-stringify` supports pattern properties as defined by JSON schema.
|
||||
*patternProperties* must be an object, where the key is a valid regex and the value is an object, declared in this way: `{ type: 'type' }`.
|
||||
*patternProperties* will work only for the properties that are not explicitly listed in the properties object.
|
||||
Example:
|
||||
```javascript
|
||||
const stringify = fastJson({
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
nickname: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
patternProperties: {
|
||||
'num': {
|
||||
type: 'number'
|
||||
},
|
||||
'.*foo$': {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = {
|
||||
nickname: 'nick',
|
||||
matchfoo: 42,
|
||||
otherfoo: 'str',
|
||||
matchnum: 3
|
||||
}
|
||||
|
||||
console.log(stringify(obj)) // '{"matchfoo":"42","otherfoo":"str","matchnum":3,"nickname":"nick"}'
|
||||
```
|
||||
|
||||
<a name="additionalProperties"></a>
|
||||
#### Additional properties
|
||||
`fast-json-stringify` supports additional properties as defined by JSON schema.
|
||||
*additionalProperties* must be an object or a boolean, declared in this way: `{ type: 'type' }`.
|
||||
*additionalProperties* will work only for the properties that are not explicitly listed in the *properties* and *patternProperties* objects.
|
||||
|
||||
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>.
|
||||
Missing fields are ignored to avoid having to rewrite objects before serializing. However, other schema rules would throw in similar situations.
|
||||
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.
|
||||
The additional properties will always be serialized at the end of the object.
|
||||
Example:
|
||||
```javascript
|
||||
const stringify = fastJson({
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
nickname: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
patternProperties: {
|
||||
'num': {
|
||||
type: 'number'
|
||||
},
|
||||
'.*foo$': {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
additionalProperties: {
|
||||
type: 'string'
|
||||
}
|
||||
})
|
||||
|
||||
const obj = {
|
||||
nickname: 'nick',
|
||||
matchfoo: 42,
|
||||
otherfoo: 'str',
|
||||
matchnum: 3,
|
||||
nomatchstr: 'valar morghulis',
|
||||
nomatchint: 313
|
||||
}
|
||||
|
||||
console.log(stringify(obj)) // '{"nickname":"nick","matchfoo":"42","otherfoo":"str","matchnum":3,"nomatchstr":"valar morghulis",nomatchint:"313"}'
|
||||
```
|
||||
|
||||
#### AnyOf and OneOf
|
||||
|
||||
`fast-json-stringify` supports the **anyOf** and **oneOf** keywords as defined by JSON schema. Both must be an array of valid JSON schemas. The different schemas will be tested in the specified order. The more schemas `stringify` has to try before finding a match, the slower it will be.
|
||||
|
||||
*anyOf* and *oneOf* use [ajv](https://www.npmjs.com/package/ajv) as a JSON schema validator to find the schema that matches the data. This has an impact on performance—only use it as a last resort.
|
||||
|
||||
Example:
|
||||
```javascript
|
||||
const stringify = fastJson({
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
'undecidedType': {
|
||||
'anyOf': [{
|
||||
type: 'string'
|
||||
}, {
|
||||
type: 'boolean'
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
When specifying object JSON schemas for *anyOf*, add *required* validation keyword to match only the objects with the properties you want.
|
||||
|
||||
Example:
|
||||
```javascript
|
||||
const stringify = fastJson({
|
||||
title: 'Example Schema',
|
||||
type: 'array',
|
||||
items: {
|
||||
anyOf: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
savedId: { type: 'string' }
|
||||
},
|
||||
// without "required" validation any object will match
|
||||
required: ['savedId']
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
error: { type: 'string' }
|
||||
},
|
||||
required: ['error']
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
<a name="if-then-else"></a>
|
||||
#### If/then/else
|
||||
`fast-json-stringify` supports `if/then/else` jsonschema feature. See [ajv documentation](https://ajv.js.org/keywords.html#ifthenelse).
|
||||
|
||||
Example:
|
||||
```javascript
|
||||
const stringify = fastJson({
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
},
|
||||
'if': {
|
||||
'properties': {
|
||||
'kind': { 'type': 'string', 'enum': ['foobar'] }
|
||||
}
|
||||
},
|
||||
'then': {
|
||||
'properties': {
|
||||
'kind': { 'type': 'string', 'enum': ['foobar'] },
|
||||
'foo': { 'type': 'string' },
|
||||
'bar': { 'type': 'number' }
|
||||
}
|
||||
},
|
||||
'else': {
|
||||
'properties': {
|
||||
'kind': { 'type': 'string', 'enum': ['greeting'] },
|
||||
'hi': { 'type': 'string' },
|
||||
'hello': { 'type': 'number' }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
console.log(stringify({
|
||||
kind: 'greeting',
|
||||
foo: 'FOO',
|
||||
bar: 42,
|
||||
hi: 'HI',
|
||||
hello: 45
|
||||
})) // {"kind":"greeting","hi":"HI","hello":45}
|
||||
console.log(stringify({
|
||||
kind: 'foobar',
|
||||
foo: 'FOO',
|
||||
bar: 42,
|
||||
hi: 'HI',
|
||||
hello: 45
|
||||
})) // {"kind":"foobar","foo":"FOO","bar":42}
|
||||
```
|
||||
|
||||
**NB** Do not declare the properties twice or you will print them twice!
|
||||
|
||||
<a name="ref"></a>
|
||||
#### Reuse - $ref
|
||||
If you want to reuse a definition of a value, you can use the property `$ref`.
|
||||
The value of `$ref` must be a string in [JSON Pointer](https://tools.ietf.org/html/rfc6901) format.
|
||||
Example:
|
||||
```javascript
|
||||
const schema = {
|
||||
title: 'Example Schema',
|
||||
definitions: {
|
||||
num: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
int: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
},
|
||||
str: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
type: 'object',
|
||||
properties: {
|
||||
nickname: {
|
||||
$ref: '#/definitions/str'
|
||||
}
|
||||
},
|
||||
patternProperties: {
|
||||
'num': {
|
||||
$ref: '#/definitions/num'
|
||||
}
|
||||
},
|
||||
additionalProperties: {
|
||||
$ref: '#/definitions/def'
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = fastJson(schema)
|
||||
```
|
||||
If you need to use an external definition, you can pass it as an option to `fast-json-stringify`.
|
||||
Example:
|
||||
```javascript
|
||||
const schema = {
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
nickname: {
|
||||
$ref: 'strings#/definitions/str'
|
||||
}
|
||||
},
|
||||
patternProperties: {
|
||||
'num': {
|
||||
$ref: 'numbers#/definitions/num'
|
||||
}
|
||||
},
|
||||
additionalProperties: {
|
||||
$ref: 'strings#/definitions/def'
|
||||
}
|
||||
}
|
||||
|
||||
const externalSchema = {
|
||||
numbers: {
|
||||
definitions: {
|
||||
num: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
int: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
strings: require('./string-def.json')
|
||||
}
|
||||
|
||||
const stringify = fastJson(schema, { schema: externalSchema })
|
||||
```
|
||||
External definitions can also reference each other.
|
||||
Example:
|
||||
```javascript
|
||||
const schema = {
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
$ref: 'strings#/definitions/foo'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const externalSchema = {
|
||||
strings: {
|
||||
definitions: {
|
||||
foo: {
|
||||
$ref: 'things#/definitions/foo'
|
||||
}
|
||||
}
|
||||
},
|
||||
things: {
|
||||
definitions: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = fastJson(schema, { schema: externalSchema })
|
||||
```
|
||||
|
||||
<a name="long"></a>
|
||||
#### Long integers
|
||||
By default, the library will handle automatically [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt).
|
||||
|
||||
<a name="integer"></a>
|
||||
#### Integers
|
||||
The `type: integer` property will be truncated if a floating point is provided.
|
||||
You can customize this behavior with the `rounding` option that will accept [`round`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round), [`ceil`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/ceil), [`floor`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor), or [`trunc`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc). Default is `trunc`:
|
||||
|
||||
```js
|
||||
const stringify = fastJson(schema, { rounding: 'ceil' })
|
||||
```
|
||||
|
||||
|
||||
<a name="nullable"></a>
|
||||
#### Nullable
|
||||
|
||||
According to the [Open API 3.0 specification](https://swagger.io/docs/specification/data-models/data-types/#null), a value that can be null must be declared `nullable`.
|
||||
|
||||
##### Nullable object
|
||||
```javascript
|
||||
const stringify = fastJson({
|
||||
'title': 'Nullable schema',
|
||||
'type': 'object',
|
||||
'nullable': true,
|
||||
'properties': {
|
||||
'product': {
|
||||
'nullable': true,
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'name': {
|
||||
'type': 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
console.log(stringify({product: {name: "hello"}})) // "{"product":{"name":"hello"}}"
|
||||
console.log(stringify({product: null})) // "{"product":null}"
|
||||
console.log(stringify(null)) // null
|
||||
```
|
||||
|
||||
Otherwise, instead of raising an error, null values will be coerced as follows:
|
||||
|
||||
- `integer` -> `0`
|
||||
- `number` -> `0`
|
||||
- `string` -> `""`
|
||||
- `boolean` -> `false`
|
||||
- `object` -> `{}`
|
||||
- `array` -> `[]`
|
||||
|
||||
<a name="largearrays"></a>
|
||||
#### Large Arrays
|
||||
|
||||
Large arrays are, for the scope of this document, defined as arrays containing,
|
||||
by default, `20000` elements or more. That value can be adjusted via the option
|
||||
parameter `largeArraySize`.
|
||||
|
||||
At some point the overhead caused by the default mechanism used by
|
||||
`fast-json-stringify` to handle arrays starts increasing exponentially, leading
|
||||
to slow overall executions.
|
||||
|
||||
##### Settings
|
||||
|
||||
In order to improve that the user can set the `largeArrayMechanism` and
|
||||
`largeArraySize` options.
|
||||
|
||||
`largeArrayMechanism`'s default value is `default`. Valid values for it are:
|
||||
|
||||
- `default` - This option is a compromise between performance and feature set by
|
||||
still providing the expected functionality out of this lib but giving up some
|
||||
possible performance gain. With this option set, **large arrays** would be
|
||||
stringified by joining their stringified elements using `Array.join` instead of
|
||||
string concatenation for better performance
|
||||
- `json-stringify` - This option will remove support for schema validation
|
||||
within **large arrays** completely. By doing so the overhead previously
|
||||
mentioned is nulled, greatly improving execution time. Mind there's no change
|
||||
in behavior for arrays not considered _large_
|
||||
|
||||
`largeArraySize`'s default value is `20000`. Valid values for it are
|
||||
integer-like values, such as:
|
||||
|
||||
- `20000`
|
||||
- `2e4`
|
||||
- `'20000'`
|
||||
- `'2e4'` - _note this will be converted to `2`, not `20000`_
|
||||
- `1.5` - _note this will be converted to `1`_
|
||||
|
||||
<a name="unsafe"></a>
|
||||
#### Unsafe string
|
||||
By default, the library escapes all strings. With the 'unsafe' format, the string isn't escaped. This has a potentially dangerous security issue. You can use it only if you are sure that your data doesn't need escaping. The advantage is a significant performance improvement.
|
||||
|
||||
Example:
|
||||
```javascript
|
||||
const stringify = fastJson({
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
'code': {
|
||||
type: 'string',
|
||||
format 'unsafe'
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
##### Benchmarks
|
||||
|
||||
For reference, here are some benchmarks for comparison over the three
|
||||
mechanisms. Benchmarks were conducted on an old machine.
|
||||
|
||||
- Machine: `ST1000LM024 HN-M 1TB HDD, Intel Core i7-3610QM @ 2.3GHz, 12GB RAM, 4C/8T`.
|
||||
- Node.js `v16.13.1`
|
||||
|
||||
```
|
||||
JSON.stringify large array x 157 ops/sec ±0.73% (86 runs sampled)
|
||||
fast-json-stringify large array default x 48.72 ops/sec ±4.92% (48 runs sampled)
|
||||
fast-json-stringify large array json-stringify x 157 ops/sec ±0.76% (86 runs sampled)
|
||||
compile-json-stringify large array x 175 ops/sec ±4.47% (79 runs sampled)
|
||||
AJV Serialize large array x 58.76 ops/sec ±4.59% (60 runs sampled)
|
||||
```
|
||||
|
||||
<a name="security"></a>
|
||||
## Security notice
|
||||
|
||||
Treat the schema definition as application code, it
|
||||
is not safe to use user-provided schemas.
|
||||
|
||||
To achieve low cost and high performance redaction `fast-json-stringify`
|
||||
creates and compiles a function (using the `Function` constructor) on initialization.
|
||||
While the `schema` is currently validated for any developer errors,
|
||||
there is no guarantee that supplying user-generated schema could not
|
||||
expose your application to remote attacks.
|
||||
|
||||
Users are responsible for sending trusted data. `fast-json-stringify` guarantees that you will get
|
||||
a valid output only if your input matches the schema or can be coerced to the schema. If your input
|
||||
doesn't match the schema, you will get undefined behavior.
|
||||
|
||||
<a name="debug"></a>
|
||||
### Debug Mode
|
||||
|
||||
The debug mode can be activated during your development to understand what is going on when things do not
|
||||
work as you expect.
|
||||
|
||||
```js
|
||||
const debugCompiled = fastJson({
|
||||
title: 'default string',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}, { mode: 'debug' })
|
||||
|
||||
console.log(debugCompiled) // it is a object contain code, ajv instance
|
||||
const rawString = debugCompiled.code // it is the generated code
|
||||
console.log(rawString)
|
||||
|
||||
const stringify = fastJson.restore(debugCompiled) // use the generated string to get back the `stringify` function
|
||||
console.log(stringify({ firstName: 'Foo', surname: 'bar' })) // '{"firstName":"Foo"}'
|
||||
```
|
||||
|
||||
<a name="standalone"></a>
|
||||
### Standalone Mode
|
||||
|
||||
The standalone mode is used to compile the code that can be directly run by `node`
|
||||
itself. You need to have `fast-json-stringify` installed for the standalone code to work.
|
||||
|
||||
```js
|
||||
const fs = require('fs')
|
||||
const code = fastJson({
|
||||
title: 'default string',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}, { mode: 'standalone' })
|
||||
|
||||
fs.writeFileSync('stringify.js', code)
|
||||
const stringify = require('stringify.js')
|
||||
console.log(stringify({ firstName: 'Foo', surname: 'bar' })) // '{"firstName":"Foo"}'
|
||||
```
|
||||
|
||||
<a name="acknowledgments"></a>
|
||||
## Acknowledgments
|
||||
|
||||
This project was kindly sponsored by [nearForm](https://nearform.com).
|
||||
|
||||
<a name="license"></a>
|
||||
## License
|
||||
|
||||
Licensed under [MIT](./LICENSE).
|
||||
116
node_modules/fast-json-stringify/benchmark/bench-cmp-branch.js
generated
vendored
Normal file
116
node_modules/fast-json-stringify/benchmark/bench-cmp-branch.js
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
'use strict'
|
||||
|
||||
const { spawn } = require('child_process')
|
||||
|
||||
const cliSelect = require('cli-select')
|
||||
const simpleGit = require('simple-git')
|
||||
|
||||
const git = simpleGit(process.cwd())
|
||||
|
||||
const COMMAND = 'npm run bench'
|
||||
const DEFAULT_BRANCH = 'master'
|
||||
const PERCENT_THRESHOLD = 5
|
||||
const greyColor = '\x1b[30m'
|
||||
const redColor = '\x1b[31m'
|
||||
const greenColor = '\x1b[32m'
|
||||
const resetColor = '\x1b[0m'
|
||||
|
||||
async function selectBranchName (message, branches) {
|
||||
console.log(message)
|
||||
const result = await cliSelect({
|
||||
type: 'list',
|
||||
name: 'branch',
|
||||
values: branches
|
||||
})
|
||||
console.log(result.value)
|
||||
return result.value
|
||||
}
|
||||
|
||||
async function executeCommandOnBranch (command, branch) {
|
||||
console.log(`${greyColor}Checking out "${branch}"${resetColor}`)
|
||||
await git.checkout(branch)
|
||||
|
||||
console.log(`${greyColor}Execute "${command}"${resetColor}`)
|
||||
const childProcess = spawn(command, { stdio: 'pipe', shell: true })
|
||||
|
||||
let result = ''
|
||||
childProcess.stdout.on('data', (data) => {
|
||||
process.stdout.write(data.toString())
|
||||
result += data.toString()
|
||||
})
|
||||
|
||||
await new Promise(resolve => childProcess.on('close', resolve))
|
||||
|
||||
console.log()
|
||||
|
||||
return parseBenchmarksStdout(result)
|
||||
}
|
||||
|
||||
function parseBenchmarksStdout (text) {
|
||||
const results = []
|
||||
|
||||
const lines = text.split('\n')
|
||||
for (const line of lines) {
|
||||
const match = /^(.+?)(\.*) x (.+) ops\/sec .*$/.exec(line)
|
||||
if (match !== null) {
|
||||
results.push({
|
||||
name: match[1],
|
||||
alignedName: match[1] + match[2],
|
||||
result: parseInt(match[3].split(',').join(''))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
function compareResults (featureBranch, mainBranch) {
|
||||
for (const { name, alignedName, result: mainBranchResult } of mainBranch) {
|
||||
const featureBranchBenchmark = featureBranch.find(result => result.name === name)
|
||||
if (featureBranchBenchmark) {
|
||||
const featureBranchResult = featureBranchBenchmark.result
|
||||
const percent = (featureBranchResult - mainBranchResult) * 100 / mainBranchResult
|
||||
const roundedPercent = Math.round(percent * 100) / 100
|
||||
|
||||
const percentString = roundedPercent > 0 ? `+${roundedPercent}%` : `${roundedPercent}%`
|
||||
const message = alignedName + percentString.padStart(7, '.')
|
||||
|
||||
if (roundedPercent > PERCENT_THRESHOLD) {
|
||||
console.log(`${greenColor}${message}${resetColor}`)
|
||||
} else if (roundedPercent < -PERCENT_THRESHOLD) {
|
||||
console.log(`${redColor}${message}${resetColor}`)
|
||||
} else {
|
||||
console.log(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(async function () {
|
||||
const branches = await git.branch()
|
||||
const currentBranch = branches.branches[branches.current]
|
||||
|
||||
let featureBranch = null
|
||||
let mainBranch = null
|
||||
|
||||
if (process.argv[2] === '--ci') {
|
||||
featureBranch = currentBranch.name
|
||||
mainBranch = DEFAULT_BRANCH
|
||||
} else {
|
||||
featureBranch = await selectBranchName('Select the branch you want to compare (feature branch):', branches.all)
|
||||
mainBranch = await selectBranchName('Select the branch you want to compare with (main branch):', branches.all)
|
||||
}
|
||||
|
||||
try {
|
||||
const featureBranchResult = await executeCommandOnBranch(COMMAND, featureBranch)
|
||||
const mainBranchResult = await executeCommandOnBranch(COMMAND, mainBranch)
|
||||
compareResults(featureBranchResult, mainBranchResult)
|
||||
} catch (error) {
|
||||
console.error('Switch to origin branch due to an error', error.message)
|
||||
}
|
||||
|
||||
await git.checkout(currentBranch.commit)
|
||||
await git.checkout(currentBranch.name)
|
||||
|
||||
console.log(`${greyColor}Back to ${currentBranch.name} ${currentBranch.commit}${resetColor}`)
|
||||
})()
|
||||
280
node_modules/fast-json-stringify/benchmark/bench-cmp-lib.js
generated
vendored
Normal file
280
node_modules/fast-json-stringify/benchmark/bench-cmp-lib.js
generated
vendored
Normal file
@@ -0,0 +1,280 @@
|
||||
'use strict'
|
||||
|
||||
const benchmark = require('benchmark')
|
||||
const suite = new benchmark.Suite()
|
||||
|
||||
const STR_LEN = 1e4
|
||||
const LARGE_ARRAY_SIZE = 2e4
|
||||
const MULTI_ARRAY_LENGTH = 1e3
|
||||
|
||||
const schema = {
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: ['string', 'null']
|
||||
},
|
||||
age: {
|
||||
description: 'Age in years',
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
const schemaCJS = {
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: ['string', 'null']
|
||||
},
|
||||
age: {
|
||||
description: 'Age in years',
|
||||
type: 'number',
|
||||
minimum: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schemaAJVJTD = {
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: 'string',
|
||||
nullable: true
|
||||
},
|
||||
age: {
|
||||
type: 'uint8'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const arraySchema = {
|
||||
title: 'array schema',
|
||||
type: 'array',
|
||||
items: schema
|
||||
}
|
||||
|
||||
const arraySchemaCJS = {
|
||||
title: 'array schema',
|
||||
type: 'array',
|
||||
items: schemaCJS
|
||||
}
|
||||
|
||||
const arraySchemaAJVJTD = {
|
||||
elements: schemaAJVJTD
|
||||
}
|
||||
|
||||
const dateFormatSchema = {
|
||||
description: 'Date of birth',
|
||||
type: 'string',
|
||||
format: 'date'
|
||||
}
|
||||
|
||||
const dateFormatSchemaCJS = {
|
||||
description: 'Date of birth',
|
||||
type: 'string',
|
||||
format: 'date'
|
||||
}
|
||||
|
||||
const obj = {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32
|
||||
}
|
||||
|
||||
const date = new Date()
|
||||
|
||||
const multiArray = new Array(MULTI_ARRAY_LENGTH)
|
||||
const largeArray = new Array(LARGE_ARRAY_SIZE)
|
||||
|
||||
const CJS = require('compile-json-stringify')
|
||||
const CJSStringify = CJS(schemaCJS)
|
||||
const CJSStringifyArray = CJS(arraySchemaCJS)
|
||||
const CJSStringifyDate = CJS(dateFormatSchemaCJS)
|
||||
const CJSStringifyString = CJS({ type: 'string' })
|
||||
|
||||
const FJS = require('..')
|
||||
const stringify = FJS(schema)
|
||||
const stringifyArrayDefault = FJS(arraySchema)
|
||||
const stringifyArrayJSONStringify = FJS(arraySchema, {
|
||||
largeArrayMechanism: 'json-stringify'
|
||||
})
|
||||
const stringifyDate = FJS(dateFormatSchema)
|
||||
const stringifyString = FJS({ type: 'string' })
|
||||
let str = ''
|
||||
|
||||
const Ajv = require('ajv/dist/jtd')
|
||||
const ajv = new Ajv()
|
||||
const ajvSerialize = ajv.compileSerializer(schemaAJVJTD)
|
||||
const ajvSerializeArray = ajv.compileSerializer(arraySchemaAJVJTD)
|
||||
const ajvSerializeString = ajv.compileSerializer({ type: 'string' })
|
||||
|
||||
const getRandomString = (length) => {
|
||||
if (!Number.isInteger(length)) {
|
||||
throw new Error('Expected integer length')
|
||||
}
|
||||
|
||||
const validCharacters = 'abcdefghijklmnopqrstuvwxyz'
|
||||
const nValidCharacters = 26
|
||||
|
||||
let result = ''
|
||||
for (let i = 0; i < length; ++i) {
|
||||
result += validCharacters[Math.floor(Math.random() * nValidCharacters)]
|
||||
}
|
||||
|
||||
return result[0].toUpperCase() + result.slice(1)
|
||||
}
|
||||
|
||||
for (let i = 0; i < STR_LEN; i++) {
|
||||
largeArray[i] = {
|
||||
firstName: getRandomString(8),
|
||||
lastName: getRandomString(6),
|
||||
age: Math.ceil(Math.random() * 99)
|
||||
}
|
||||
|
||||
str += i
|
||||
if (i % 100 === 0) {
|
||||
str += '"'
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = STR_LEN; i < LARGE_ARRAY_SIZE; ++i) {
|
||||
largeArray[i] = {
|
||||
firstName: getRandomString(10),
|
||||
lastName: getRandomString(4),
|
||||
age: Math.ceil(Math.random() * 99)
|
||||
}
|
||||
}
|
||||
|
||||
Number(str)
|
||||
|
||||
for (let i = 0; i < MULTI_ARRAY_LENGTH; i++) {
|
||||
multiArray[i] = obj
|
||||
}
|
||||
|
||||
suite.add('FJS creation', function () {
|
||||
FJS(schema)
|
||||
})
|
||||
suite.add('CJS creation', function () {
|
||||
CJS(schemaCJS)
|
||||
})
|
||||
suite.add('AJV Serialize creation', function () {
|
||||
ajv.compileSerializer(schemaAJVJTD)
|
||||
})
|
||||
|
||||
suite.add('JSON.stringify array', function () {
|
||||
JSON.stringify(multiArray)
|
||||
})
|
||||
|
||||
suite.add('fast-json-stringify array default', function () {
|
||||
stringifyArrayDefault(multiArray)
|
||||
})
|
||||
|
||||
suite.add('fast-json-stringify array json-stringify', function () {
|
||||
stringifyArrayJSONStringify(multiArray)
|
||||
})
|
||||
|
||||
suite.add('compile-json-stringify array', function () {
|
||||
CJSStringifyArray(multiArray)
|
||||
})
|
||||
|
||||
suite.add('AJV Serialize array', function () {
|
||||
ajvSerializeArray(multiArray)
|
||||
})
|
||||
|
||||
suite.add('JSON.stringify large array', function () {
|
||||
JSON.stringify(largeArray)
|
||||
})
|
||||
|
||||
suite.add('fast-json-stringify large array default', function () {
|
||||
stringifyArrayDefault(largeArray)
|
||||
})
|
||||
|
||||
suite.add('fast-json-stringify large array json-stringify', function () {
|
||||
stringifyArrayJSONStringify(largeArray)
|
||||
})
|
||||
|
||||
suite.add('compile-json-stringify large array', function () {
|
||||
CJSStringifyArray(largeArray)
|
||||
})
|
||||
|
||||
suite.add('AJV Serialize large array', function () {
|
||||
ajvSerializeArray(largeArray)
|
||||
})
|
||||
|
||||
suite.add('JSON.stringify long string', function () {
|
||||
JSON.stringify(str)
|
||||
})
|
||||
|
||||
suite.add('fast-json-stringify long string', function () {
|
||||
stringifyString(str)
|
||||
})
|
||||
|
||||
suite.add('compile-json-stringify long string', function () {
|
||||
CJSStringifyString(str)
|
||||
})
|
||||
|
||||
suite.add('AJV Serialize long string', function () {
|
||||
ajvSerializeString(str)
|
||||
})
|
||||
|
||||
suite.add('JSON.stringify short string', function () {
|
||||
JSON.stringify('hello world')
|
||||
})
|
||||
|
||||
suite.add('fast-json-stringify short string', function () {
|
||||
stringifyString('hello world')
|
||||
})
|
||||
|
||||
suite.add('compile-json-stringify short string', function () {
|
||||
CJSStringifyString('hello world')
|
||||
})
|
||||
|
||||
suite.add('AJV Serialize short string', function () {
|
||||
ajvSerializeString('hello world')
|
||||
})
|
||||
|
||||
suite.add('JSON.stringify obj', function () {
|
||||
JSON.stringify(obj)
|
||||
})
|
||||
|
||||
suite.add('fast-json-stringify obj', function () {
|
||||
stringify(obj)
|
||||
})
|
||||
|
||||
suite.add('compile-json-stringify obj', function () {
|
||||
CJSStringify(obj)
|
||||
})
|
||||
|
||||
suite.add('AJV Serialize obj', function () {
|
||||
ajvSerialize(obj)
|
||||
})
|
||||
|
||||
suite.add('JSON stringify date', function () {
|
||||
JSON.stringify(date)
|
||||
})
|
||||
|
||||
suite.add('fast-json-stringify date format', function () {
|
||||
stringifyDate(date)
|
||||
})
|
||||
|
||||
suite.add('compile-json-stringify date format', function () {
|
||||
CJSStringifyDate(date)
|
||||
})
|
||||
|
||||
suite.on('cycle', cycle)
|
||||
|
||||
suite.run()
|
||||
|
||||
function cycle (e) {
|
||||
console.log(e.target.toString())
|
||||
}
|
||||
21
node_modules/fast-json-stringify/benchmark/bench-thread.js
generated
vendored
Normal file
21
node_modules/fast-json-stringify/benchmark/bench-thread.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
'use strict'
|
||||
|
||||
const { workerData: benchmark, parentPort } = require('worker_threads')
|
||||
|
||||
const Benchmark = require('benchmark')
|
||||
Benchmark.options.minSamples = 100
|
||||
|
||||
const suite = Benchmark.Suite()
|
||||
|
||||
const FJS = require('..')
|
||||
const stringify = FJS(benchmark.schema)
|
||||
|
||||
suite
|
||||
.add(benchmark.name, () => {
|
||||
stringify(benchmark.input)
|
||||
})
|
||||
.on('cycle', (event) => {
|
||||
parentPort.postMessage(String(event.target))
|
||||
})
|
||||
.on('complete', () => {})
|
||||
.run()
|
||||
391
node_modules/fast-json-stringify/benchmark/bench.js
generated
vendored
Normal file
391
node_modules/fast-json-stringify/benchmark/bench.js
generated
vendored
Normal file
@@ -0,0 +1,391 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const { Worker } = require('worker_threads')
|
||||
|
||||
const BENCH_THREAD_PATH = path.join(__dirname, 'bench-thread.js')
|
||||
|
||||
const LONG_STRING_LENGTH = 1e4
|
||||
const SHORT_ARRAY_SIZE = 1e3
|
||||
|
||||
const shortArrayOfNumbers = new Array(SHORT_ARRAY_SIZE)
|
||||
const shortArrayOfIntegers = new Array(SHORT_ARRAY_SIZE)
|
||||
const shortArrayOfShortStrings = new Array(SHORT_ARRAY_SIZE)
|
||||
const shortArrayOfLongStrings = new Array(SHORT_ARRAY_SIZE)
|
||||
const shortArrayOfMultiObject = new Array(SHORT_ARRAY_SIZE)
|
||||
|
||||
function getRandomInt (max) {
|
||||
return Math.floor(Math.random() * max)
|
||||
}
|
||||
|
||||
let longSimpleString = ''
|
||||
for (let i = 0; i < LONG_STRING_LENGTH; i++) {
|
||||
longSimpleString += i
|
||||
}
|
||||
|
||||
let longString = ''
|
||||
for (let i = 0; i < LONG_STRING_LENGTH; i++) {
|
||||
longString += i
|
||||
if (i % 100 === 0) {
|
||||
longString += '"'
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < SHORT_ARRAY_SIZE; i++) {
|
||||
shortArrayOfNumbers[i] = getRandomInt(1000)
|
||||
shortArrayOfIntegers[i] = getRandomInt(1000)
|
||||
shortArrayOfShortStrings[i] = 'hello world'
|
||||
shortArrayOfLongStrings[i] = longString
|
||||
shortArrayOfMultiObject[i] = { s: 'hello world', n: 42, b: true }
|
||||
}
|
||||
|
||||
const benchmarks = [
|
||||
{
|
||||
name: 'short string',
|
||||
schema: {
|
||||
type: 'string'
|
||||
},
|
||||
input: 'hello world'
|
||||
},
|
||||
{
|
||||
name: 'unsafe short string',
|
||||
schema: {
|
||||
type: 'string',
|
||||
format: 'unsafe'
|
||||
},
|
||||
input: 'hello world'
|
||||
},
|
||||
{
|
||||
name: 'short string with double quote',
|
||||
schema: {
|
||||
type: 'string'
|
||||
},
|
||||
input: 'hello " world'
|
||||
},
|
||||
{
|
||||
name: 'long string without double quotes',
|
||||
schema: {
|
||||
type: 'string'
|
||||
},
|
||||
input: longSimpleString
|
||||
},
|
||||
{
|
||||
name: 'unsafe long string without double quotes',
|
||||
schema: {
|
||||
type: 'string',
|
||||
format: 'unsafe'
|
||||
},
|
||||
input: longSimpleString
|
||||
},
|
||||
{
|
||||
name: 'long string',
|
||||
schema: {
|
||||
type: 'string'
|
||||
},
|
||||
input: longString
|
||||
},
|
||||
{
|
||||
name: 'unsafe long string',
|
||||
schema: {
|
||||
type: 'string',
|
||||
format: 'unsafe'
|
||||
},
|
||||
input: longString
|
||||
},
|
||||
{
|
||||
name: 'number',
|
||||
schema: {
|
||||
type: 'number'
|
||||
},
|
||||
input: 42
|
||||
},
|
||||
{
|
||||
name: 'integer',
|
||||
schema: {
|
||||
type: 'integer'
|
||||
},
|
||||
input: 42
|
||||
},
|
||||
{
|
||||
name: 'formatted date-time',
|
||||
schema: {
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
},
|
||||
input: new Date()
|
||||
},
|
||||
{
|
||||
name: 'formatted date',
|
||||
schema: {
|
||||
type: 'string',
|
||||
format: 'date'
|
||||
},
|
||||
input: new Date()
|
||||
},
|
||||
{
|
||||
name: 'formatted time',
|
||||
schema: {
|
||||
type: 'string',
|
||||
format: 'time'
|
||||
},
|
||||
input: new Date()
|
||||
},
|
||||
{
|
||||
name: 'short array of numbers',
|
||||
schema: {
|
||||
type: 'array',
|
||||
items: { type: 'number' }
|
||||
},
|
||||
input: shortArrayOfNumbers
|
||||
},
|
||||
{
|
||||
name: 'short array of integers',
|
||||
schema: {
|
||||
type: 'array',
|
||||
items: { type: 'integer' }
|
||||
},
|
||||
input: shortArrayOfIntegers
|
||||
},
|
||||
{
|
||||
name: 'short array of short strings',
|
||||
schema: {
|
||||
type: 'array',
|
||||
items: { type: 'string' }
|
||||
},
|
||||
input: shortArrayOfShortStrings
|
||||
},
|
||||
{
|
||||
name: 'short array of long strings',
|
||||
schema: {
|
||||
type: 'array',
|
||||
items: { type: 'string' }
|
||||
},
|
||||
input: shortArrayOfShortStrings
|
||||
},
|
||||
{
|
||||
name: 'short array of objects with properties of different types',
|
||||
schema: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
s: { type: 'string' },
|
||||
n: { type: 'number' },
|
||||
b: { type: 'boolean' }
|
||||
}
|
||||
}
|
||||
},
|
||||
input: shortArrayOfMultiObject
|
||||
},
|
||||
{
|
||||
name: 'object with number property',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: { type: 'number' }
|
||||
}
|
||||
},
|
||||
input: { a: 42 }
|
||||
},
|
||||
{
|
||||
name: 'object with integer property',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: { type: 'integer' }
|
||||
}
|
||||
},
|
||||
input: { a: 42 }
|
||||
},
|
||||
{
|
||||
name: 'object with short string property',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: { type: 'string' }
|
||||
}
|
||||
},
|
||||
input: { a: 'hello world' }
|
||||
},
|
||||
{
|
||||
name: 'object with long string property',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: { type: 'string' }
|
||||
}
|
||||
},
|
||||
input: { a: longString }
|
||||
},
|
||||
{
|
||||
name: 'object with properties of different types',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
s1: { type: 'string' },
|
||||
n1: { type: 'number' },
|
||||
b1: { type: 'boolean' },
|
||||
s2: { type: 'string' },
|
||||
n2: { type: 'number' },
|
||||
b2: { type: 'boolean' },
|
||||
s3: { type: 'string' },
|
||||
n3: { type: 'number' },
|
||||
b3: { type: 'boolean' },
|
||||
s4: { type: 'string' },
|
||||
n4: { type: 'number' },
|
||||
b4: { type: 'boolean' },
|
||||
s5: { type: 'string' },
|
||||
n5: { type: 'number' },
|
||||
b5: { type: 'boolean' }
|
||||
}
|
||||
},
|
||||
input: {
|
||||
s1: 'hello world',
|
||||
n1: 42,
|
||||
b1: true,
|
||||
s2: 'hello world',
|
||||
n2: 42,
|
||||
b2: true,
|
||||
s3: 'hello world',
|
||||
n3: 42,
|
||||
b3: true,
|
||||
s4: 'hello world',
|
||||
n4: 42,
|
||||
b4: true,
|
||||
s5: 'hello world',
|
||||
n5: 42,
|
||||
b5: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'simple object',
|
||||
schema: {
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: ['string', 'null']
|
||||
},
|
||||
age: {
|
||||
description: 'Age in years',
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
input: { firstName: 'Max', lastName: 'Power', age: 22 }
|
||||
},
|
||||
{
|
||||
name: 'simple object with required fields',
|
||||
schema: {
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: ['string', 'null']
|
||||
},
|
||||
age: {
|
||||
description: 'Age in years',
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
}
|
||||
},
|
||||
required: ['firstName', 'lastName', 'age']
|
||||
},
|
||||
input: { firstName: 'Max', lastName: 'Power', age: 22 }
|
||||
},
|
||||
{
|
||||
name: 'object with const string property',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: { const: 'const string' }
|
||||
}
|
||||
},
|
||||
input: { a: 'const string' }
|
||||
},
|
||||
{
|
||||
name: 'object with const number property',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: { const: 1 }
|
||||
}
|
||||
},
|
||||
input: { a: 1 }
|
||||
},
|
||||
{
|
||||
name: 'object with const bool property',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: { const: true }
|
||||
}
|
||||
},
|
||||
input: { a: true }
|
||||
},
|
||||
{
|
||||
name: 'object with const object property',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { const: { bar: 'baz' } }
|
||||
}
|
||||
},
|
||||
input: {
|
||||
foo: { bar: 'baz' }
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'object with const null property',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { const: null }
|
||||
}
|
||||
},
|
||||
input: {
|
||||
foo: null
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
async function runBenchmark (benchmark) {
|
||||
const worker = new Worker(BENCH_THREAD_PATH, { workerData: benchmark })
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let result = null
|
||||
worker.on('error', reject)
|
||||
worker.on('message', (benchResult) => {
|
||||
result = benchResult
|
||||
})
|
||||
worker.on('exit', (code) => {
|
||||
if (code === 0) {
|
||||
resolve(result)
|
||||
} else {
|
||||
reject(new Error(`Worker stopped with exit code ${code}`))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function runBenchmarks () {
|
||||
let maxNameLength = 0
|
||||
for (const benchmark of benchmarks) {
|
||||
maxNameLength = Math.max(benchmark.name.length, maxNameLength)
|
||||
}
|
||||
|
||||
for (const benchmark of benchmarks) {
|
||||
benchmark.name = benchmark.name.padEnd(maxNameLength, '.')
|
||||
const resultMessage = await runBenchmark(benchmark)
|
||||
console.log(resultMessage)
|
||||
}
|
||||
}
|
||||
|
||||
runBenchmarks()
|
||||
26
node_modules/fast-json-stringify/build/build-schema-validator.js
generated
vendored
Normal file
26
node_modules/fast-json-stringify/build/build-schema-validator.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
'use strict'
|
||||
|
||||
const Ajv = require('ajv')
|
||||
const standaloneCode = require('ajv/dist/standalone').default
|
||||
const ajvFormats = require('ajv-formats')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const ajv = new Ajv({
|
||||
addUsedSchema: false,
|
||||
allowUnionTypes: true,
|
||||
code: {
|
||||
source: true,
|
||||
lines: true,
|
||||
optimize: 3
|
||||
}
|
||||
})
|
||||
ajvFormats(ajv)
|
||||
|
||||
const schema = require('ajv/lib/refs/json-schema-draft-07.json')
|
||||
const validate = ajv.compile(schema)
|
||||
const validationCode = standaloneCode(ajv, validate)
|
||||
|
||||
const moduleCode = `/* CODE GENERATED BY '${path.basename(__filename)}' DO NOT EDIT! */\n${validationCode}`
|
||||
|
||||
fs.writeFileSync(path.join(__dirname, '../lib/schema-validator.js'), moduleCode)
|
||||
9
node_modules/fast-json-stringify/eslint.config.js
generated
vendored
Normal file
9
node_modules/fast-json-stringify/eslint.config.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = require('neostandard')({
|
||||
ignores: [
|
||||
...require('neostandard').resolveIgnoresFromGitignore(),
|
||||
'lib/schema-validator.js'
|
||||
],
|
||||
ts: true
|
||||
})
|
||||
81
node_modules/fast-json-stringify/examples/example.js
generated
vendored
Normal file
81
node_modules/fast-json-stringify/examples/example.js
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
'use strict'
|
||||
|
||||
const fastJson = require('..')
|
||||
const stringify = fastJson({
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: 'string'
|
||||
},
|
||||
age: {
|
||||
description: 'Age in years',
|
||||
type: 'integer'
|
||||
},
|
||||
now: {
|
||||
type: 'string'
|
||||
},
|
||||
birthdate: {
|
||||
type: ['string'],
|
||||
format: 'date-time'
|
||||
},
|
||||
reg: {
|
||||
type: 'string'
|
||||
},
|
||||
obj: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
bool: {
|
||||
type: 'boolean'
|
||||
}
|
||||
}
|
||||
},
|
||||
arr: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ['now'],
|
||||
patternProperties: {
|
||||
'.*foo$': {
|
||||
type: 'string'
|
||||
},
|
||||
test: {
|
||||
type: 'number'
|
||||
},
|
||||
date: {
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
}
|
||||
},
|
||||
additionalProperties: {
|
||||
type: 'string'
|
||||
}
|
||||
})
|
||||
|
||||
console.log(stringify({
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32,
|
||||
now: new Date(),
|
||||
reg: /"([^"]|\\")*"/,
|
||||
foo: 'hello',
|
||||
numfoo: 42,
|
||||
test: 42,
|
||||
strtest: '23',
|
||||
arr: [{ str: 'stark' }, { str: 'lannister' }],
|
||||
obj: { bool: true },
|
||||
notmatch: 'valar morghulis',
|
||||
notmatchobj: { a: true },
|
||||
notmatchnum: 42
|
||||
}))
|
||||
42
node_modules/fast-json-stringify/examples/server.js
generated
vendored
Normal file
42
node_modules/fast-json-stringify/examples/server.js
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
'use strict'
|
||||
|
||||
const http = require('http')
|
||||
|
||||
const stringify = require('fast-json-stringify')({
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'string'
|
||||
},
|
||||
data: {
|
||||
type: 'number'
|
||||
},
|
||||
nested: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
more: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const server = http.createServer(handle)
|
||||
|
||||
function handle (req, res) {
|
||||
const data = {
|
||||
hello: 'world',
|
||||
data: 42,
|
||||
nested: {
|
||||
more: 'data'
|
||||
}
|
||||
}
|
||||
if (req.url === '/JSON') {
|
||||
res.end(JSON.stringify(data))
|
||||
} else {
|
||||
res.end(stringify(data))
|
||||
}
|
||||
}
|
||||
|
||||
server.listen(3000)
|
||||
1028
node_modules/fast-json-stringify/index.js
generated
vendored
Normal file
1028
node_modules/fast-json-stringify/index.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
24
node_modules/fast-json-stringify/lib/location.js
generated
vendored
Normal file
24
node_modules/fast-json-stringify/lib/location.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
'use strict'
|
||||
|
||||
class Location {
|
||||
constructor (schema, schemaId, jsonPointer = '#') {
|
||||
this.schema = schema
|
||||
this.schemaId = schemaId
|
||||
this.jsonPointer = jsonPointer
|
||||
}
|
||||
|
||||
getPropertyLocation (propertyName) {
|
||||
const propertyLocation = new Location(
|
||||
this.schema[propertyName],
|
||||
this.schemaId,
|
||||
this.jsonPointer + '/' + propertyName
|
||||
)
|
||||
return propertyLocation
|
||||
}
|
||||
|
||||
getSchemaRef () {
|
||||
return this.schemaId + this.jsonPointer
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Location
|
||||
9
node_modules/fast-json-stringify/lib/merge-schemas.js
generated
vendored
Normal file
9
node_modules/fast-json-stringify/lib/merge-schemas.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
'use strict'
|
||||
|
||||
const { mergeSchemas: _mergeSchemas } = require('@fastify/merge-json-schemas')
|
||||
|
||||
function mergeSchemas (schemas) {
|
||||
return _mergeSchemas(schemas, { onConflict: 'skip' })
|
||||
}
|
||||
|
||||
module.exports = mergeSchemas
|
||||
1134
node_modules/fast-json-stringify/lib/schema-validator.js
generated
vendored
Normal file
1134
node_modules/fast-json-stringify/lib/schema-validator.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
139
node_modules/fast-json-stringify/lib/serializer.js
generated
vendored
Normal file
139
node_modules/fast-json-stringify/lib/serializer.js
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
'use strict'
|
||||
|
||||
// eslint-disable-next-line
|
||||
const STR_ESCAPE = /[\u0000-\u001f\u0022\u005c\ud800-\udfff]/
|
||||
|
||||
module.exports = class Serializer {
|
||||
constructor (options) {
|
||||
switch (options && options.rounding) {
|
||||
case 'floor':
|
||||
this.parseInteger = Math.floor
|
||||
break
|
||||
case 'ceil':
|
||||
this.parseInteger = Math.ceil
|
||||
break
|
||||
case 'round':
|
||||
this.parseInteger = Math.round
|
||||
break
|
||||
case 'trunc':
|
||||
default:
|
||||
this.parseInteger = Math.trunc
|
||||
break
|
||||
}
|
||||
this._options = options
|
||||
}
|
||||
|
||||
asInteger (i) {
|
||||
if (Number.isInteger(i)) {
|
||||
return '' + i
|
||||
} else if (typeof i === 'bigint') {
|
||||
return i.toString()
|
||||
}
|
||||
/* eslint no-undef: "off" */
|
||||
const integer = this.parseInteger(i)
|
||||
// check if number is Infinity or NaN
|
||||
// eslint-disable-next-line no-self-compare
|
||||
if (integer === Infinity || integer === -Infinity || integer !== integer) {
|
||||
throw new Error(`The value "${i}" cannot be converted to an integer.`)
|
||||
}
|
||||
return '' + integer
|
||||
}
|
||||
|
||||
asNumber (i) {
|
||||
// fast cast to number
|
||||
const num = Number(i)
|
||||
// check if number is NaN
|
||||
// eslint-disable-next-line no-self-compare
|
||||
if (num !== num) {
|
||||
throw new Error(`The value "${i}" cannot be converted to a number.`)
|
||||
} else if (num === Infinity || num === -Infinity) {
|
||||
return 'null'
|
||||
} else {
|
||||
return '' + num
|
||||
}
|
||||
}
|
||||
|
||||
asBoolean (bool) {
|
||||
return bool && 'true' || 'false' // eslint-disable-line
|
||||
}
|
||||
|
||||
asDateTime (date) {
|
||||
if (date === null) return '""'
|
||||
if (date instanceof Date) {
|
||||
return '"' + date.toISOString() + '"'
|
||||
}
|
||||
if (typeof date === 'string') {
|
||||
return '"' + date + '"'
|
||||
}
|
||||
throw new Error(`The value "${date}" cannot be converted to a date-time.`)
|
||||
}
|
||||
|
||||
asDate (date) {
|
||||
if (date === null) return '""'
|
||||
if (date instanceof Date) {
|
||||
return '"' + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(0, 10) + '"'
|
||||
}
|
||||
if (typeof date === 'string') {
|
||||
return '"' + date + '"'
|
||||
}
|
||||
throw new Error(`The value "${date}" cannot be converted to a date.`)
|
||||
}
|
||||
|
||||
asTime (date) {
|
||||
if (date === null) return '""'
|
||||
if (date instanceof Date) {
|
||||
return '"' + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(11, 19) + '"'
|
||||
}
|
||||
if (typeof date === 'string') {
|
||||
return '"' + date + '"'
|
||||
}
|
||||
throw new Error(`The value "${date}" cannot be converted to a time.`)
|
||||
}
|
||||
|
||||
asString (str) {
|
||||
const len = str.length
|
||||
if (len < 42) {
|
||||
// magically escape strings for json
|
||||
// relying on their charCodeAt
|
||||
// everything below 32 needs JSON.stringify()
|
||||
// every string that contain surrogate needs JSON.stringify()
|
||||
// 34 and 92 happens all the time, so we
|
||||
// have a fast case for them
|
||||
let result = ''
|
||||
let last = -1
|
||||
let point = 255
|
||||
for (let i = 0; i < len; i++) {
|
||||
point = str.charCodeAt(i)
|
||||
if (
|
||||
point === 0x22 || // '"'
|
||||
point === 0x5c // '\'
|
||||
) {
|
||||
last === -1 && (last = 0)
|
||||
result += str.slice(last, i) + '\\'
|
||||
last = i
|
||||
} else if (point < 32 || (point >= 0xD800 && point <= 0xDFFF)) {
|
||||
// The current character is non-printable characters or a surrogate.
|
||||
return JSON.stringify(str)
|
||||
}
|
||||
}
|
||||
return (last === -1 && ('"' + str + '"')) || ('"' + result + str.slice(last) + '"')
|
||||
} else if (len < 5000 && STR_ESCAPE.test(str) === false) {
|
||||
// Only use the regular expression for shorter input. The overhead is otherwise too much.
|
||||
return '"' + str + '"'
|
||||
} else {
|
||||
return JSON.stringify(str)
|
||||
}
|
||||
}
|
||||
|
||||
asUnsafeString (str) {
|
||||
return '"' + str + '"'
|
||||
}
|
||||
|
||||
getState () {
|
||||
return this._options
|
||||
}
|
||||
|
||||
static restoreFromState (state) {
|
||||
return new Serializer(state)
|
||||
}
|
||||
}
|
||||
34
node_modules/fast-json-stringify/lib/standalone.js
generated
vendored
Normal file
34
node_modules/fast-json-stringify/lib/standalone.js
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
'use strict'
|
||||
|
||||
function buildStandaloneCode (contextFunc, context, serializer, validator) {
|
||||
let ajvDependencyCode = ''
|
||||
if (context.validatorSchemasIds.size > 0) {
|
||||
ajvDependencyCode += 'const Validator = require(\'fast-json-stringify/lib/validator\')\n'
|
||||
ajvDependencyCode += `const validatorState = ${JSON.stringify(validator.getState())}\n`
|
||||
ajvDependencyCode += 'const validator = Validator.restoreFromState(validatorState)\n'
|
||||
} else {
|
||||
ajvDependencyCode += 'const validator = null\n'
|
||||
}
|
||||
|
||||
// Don't need to keep external schemas once compiled
|
||||
// validatorState will hold external schemas if it needs them
|
||||
const { schema, ...serializerState } = serializer.getState()
|
||||
|
||||
return `
|
||||
'use strict'
|
||||
|
||||
const Serializer = require('fast-json-stringify/lib/serializer')
|
||||
const serializerState = ${JSON.stringify(serializerState)}
|
||||
const serializer = Serializer.restoreFromState(serializerState)
|
||||
|
||||
${ajvDependencyCode}
|
||||
|
||||
module.exports = ${contextFunc.toString()}(validator, serializer)`
|
||||
}
|
||||
|
||||
module.exports = buildStandaloneCode
|
||||
|
||||
module.exports.dependencies = {
|
||||
Serializer: require('./serializer'),
|
||||
Validator: require('./validator')
|
||||
}
|
||||
94
node_modules/fast-json-stringify/lib/validator.js
generated
vendored
Normal file
94
node_modules/fast-json-stringify/lib/validator.js
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
'use strict'
|
||||
|
||||
const Ajv = require('ajv')
|
||||
const fastUri = require('fast-uri')
|
||||
const ajvFormats = require('ajv-formats')
|
||||
const clone = require('rfdc')({ proto: true })
|
||||
|
||||
class Validator {
|
||||
constructor (ajvOptions) {
|
||||
this.ajv = new Ajv({
|
||||
...ajvOptions,
|
||||
strictSchema: false,
|
||||
validateSchema: false,
|
||||
allowUnionTypes: true,
|
||||
uriResolver: fastUri
|
||||
})
|
||||
|
||||
ajvFormats(this.ajv)
|
||||
|
||||
this.ajv.addKeyword({
|
||||
keyword: 'fjs_type',
|
||||
type: 'object',
|
||||
errors: false,
|
||||
validate: (_type, date) => {
|
||||
return date instanceof Date
|
||||
}
|
||||
})
|
||||
|
||||
this._ajvSchemas = {}
|
||||
this._ajvOptions = ajvOptions || {}
|
||||
}
|
||||
|
||||
addSchema (schema, schemaName) {
|
||||
let schemaKey = schema.$id || schemaName
|
||||
if (schema.$id !== undefined && schema.$id[0] === '#') {
|
||||
schemaKey = schemaName + schema.$id // relative URI
|
||||
}
|
||||
|
||||
if (
|
||||
this.ajv.refs[schemaKey] === undefined &&
|
||||
this.ajv.schemas[schemaKey] === undefined
|
||||
) {
|
||||
const ajvSchema = clone(schema)
|
||||
this.convertSchemaToAjvFormat(ajvSchema)
|
||||
this.ajv.addSchema(ajvSchema, schemaKey)
|
||||
this._ajvSchemas[schemaKey] = schema
|
||||
}
|
||||
}
|
||||
|
||||
validate (schemaRef, data) {
|
||||
return this.ajv.validate(schemaRef, data)
|
||||
}
|
||||
|
||||
// Ajv does not support js date format. In order to properly validate objects containing a date,
|
||||
// it needs to replace all occurrences of the string date format with a custom keyword fjs_type.
|
||||
// (see https://github.com/fastify/fast-json-stringify/pull/441)
|
||||
convertSchemaToAjvFormat (schema) {
|
||||
if (schema === null) return
|
||||
|
||||
if (schema.type === 'string') {
|
||||
schema.fjs_type = 'string'
|
||||
schema.type = ['string', 'object']
|
||||
} else if (
|
||||
Array.isArray(schema.type) &&
|
||||
schema.type.includes('string') &&
|
||||
!schema.type.includes('object')
|
||||
) {
|
||||
schema.fjs_type = 'string'
|
||||
schema.type.push('object')
|
||||
}
|
||||
for (const property in schema) {
|
||||
if (typeof schema[property] === 'object') {
|
||||
this.convertSchemaToAjvFormat(schema[property])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getState () {
|
||||
return {
|
||||
ajvOptions: this._ajvOptions,
|
||||
ajvSchemas: this._ajvSchemas
|
||||
}
|
||||
}
|
||||
|
||||
static restoreFromState (state) {
|
||||
const validator = new Validator(state.ajvOptions)
|
||||
for (const [id, ajvSchema] of Object.entries(state.ajvSchemas)) {
|
||||
validator.ajv.addSchema(ajvSchema, id)
|
||||
}
|
||||
return validator
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Validator
|
||||
92
node_modules/fast-json-stringify/package.json
generated
vendored
Normal file
92
node_modules/fast-json-stringify/package.json
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
{
|
||||
"name": "fast-json-stringify",
|
||||
"version": "6.0.1",
|
||||
"description": "Stringify your JSON at max speed",
|
||||
"main": "index.js",
|
||||
"type": "commonjs",
|
||||
"types": "types/index.d.ts",
|
||||
"scripts": {
|
||||
"bench": "node ./benchmark/bench.js",
|
||||
"bench:cmp": "node ./benchmark/bench-cmp-branch.js",
|
||||
"bench:cmp:ci": "node ./benchmark/bench-cmp-branch.js --ci",
|
||||
"benchmark": "node ./benchmark/bench-cmp-lib.js",
|
||||
"lint": "eslint",
|
||||
"lint:fix": "eslint --fix",
|
||||
"test:typescript": "tsd",
|
||||
"test:unit": "c8 node --test",
|
||||
"test": "npm run test:unit && npm run test:typescript"
|
||||
},
|
||||
"precommit": [
|
||||
"lint",
|
||||
"test"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/fastify/fast-json-stringify.git"
|
||||
},
|
||||
"keywords": [
|
||||
"json",
|
||||
"stringify",
|
||||
"schema",
|
||||
"fast"
|
||||
],
|
||||
"author": "Matteo Collina <hello@matteocollina.com>",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Tomas Della Vedova",
|
||||
"url": "http://delved.org"
|
||||
},
|
||||
{
|
||||
"name": "Aras Abbasi",
|
||||
"email": "aras.abbasi@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Manuel Spigolon",
|
||||
"email": "behemoth89@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Frazer Smith",
|
||||
"email": "frazer.dev@icloud.com",
|
||||
"url": "https://github.com/fdawgs"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/fastify/fast-json-stringify/issues"
|
||||
},
|
||||
"homepage": "https://github.com/fastify/fast-json-stringify#readme",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fastify"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fastify"
|
||||
}
|
||||
],
|
||||
"devDependencies": {
|
||||
"@fastify/pre-commit": "^2.1.0",
|
||||
"@sinclair/typebox": "^0.34.3",
|
||||
"benchmark": "^2.1.4",
|
||||
"c8": "^10.1.2",
|
||||
"cli-select": "^1.1.2",
|
||||
"compile-json-stringify": "^0.1.2",
|
||||
"eslint": "^9.17.0",
|
||||
"fast-json-stringify": ".",
|
||||
"is-my-json-valid": "^2.20.6",
|
||||
"neostandard": "^0.12.0",
|
||||
"simple-git": "^3.23.0",
|
||||
"tsd": "^0.31.0",
|
||||
"webpack": "^5.90.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fastify/merge-json-schemas": "^0.2.0",
|
||||
"ajv": "^8.12.0",
|
||||
"ajv-formats": "^3.0.1",
|
||||
"fast-uri": "^3.0.0",
|
||||
"json-schema-ref-resolver": "^2.0.0",
|
||||
"rfdc": "^1.2.0"
|
||||
},
|
||||
"runkitExampleFilename": "./examples/example.js"
|
||||
}
|
||||
332
node_modules/fast-json-stringify/test/additionalProperties.test.js
generated
vendored
Normal file
332
node_modules/fast-json-stringify/test/additionalProperties.test.js
generated
vendored
Normal file
@@ -0,0 +1,332 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('additionalProperties', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'additionalProperties',
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
additionalProperties: {
|
||||
type: 'string'
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { str: 'test', foo: 42, ofoo: true, foof: 'string', objfoo: { a: true } }
|
||||
t.assert.equal(stringify(obj), '{"str":"test","foo":"42","ofoo":"true","foof":"string","objfoo":"[object Object]"}')
|
||||
})
|
||||
|
||||
test('additionalProperties should not change properties', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'patternProperties should not change properties',
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
additionalProperties: {
|
||||
type: 'number'
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { foo: '42', ofoo: 42 }
|
||||
t.assert.equal(stringify(obj), '{"foo":"42","ofoo":42}')
|
||||
})
|
||||
|
||||
test('additionalProperties should not change properties and patternProperties', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'patternProperties should not change properties',
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
patternProperties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
additionalProperties: {
|
||||
type: 'number'
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { foo: '42', ofoo: 42, test: '42' }
|
||||
t.assert.equal(stringify(obj), '{"foo":"42","ofoo":"42","test":42}')
|
||||
})
|
||||
|
||||
test('additionalProperties set to true, use of fast-safe-stringify', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'check string coerce',
|
||||
type: 'object',
|
||||
properties: {},
|
||||
additionalProperties: true
|
||||
})
|
||||
|
||||
const obj = { foo: true, ofoo: 42, arrfoo: ['array', 'test'], objfoo: { a: 'world' } }
|
||||
t.assert.equal(stringify(obj), '{"foo":true,"ofoo":42,"arrfoo":["array","test"],"objfoo":{"a":"world"}}')
|
||||
})
|
||||
|
||||
test('additionalProperties - string coerce', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'check string coerce',
|
||||
type: 'object',
|
||||
properties: {},
|
||||
additionalProperties: {
|
||||
type: 'string'
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { foo: true, ofoo: 42, arrfoo: ['array', 'test'], objfoo: { a: 'world' } }
|
||||
t.assert.equal(stringify(obj), '{"foo":"true","ofoo":"42","arrfoo":"array,test","objfoo":"[object Object]"}')
|
||||
})
|
||||
|
||||
test('additionalProperties - number skip', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'check number coerce',
|
||||
type: 'object',
|
||||
properties: {},
|
||||
additionalProperties: {
|
||||
type: 'number'
|
||||
}
|
||||
})
|
||||
|
||||
// const obj = { foo: true, ofoo: '42', xfoo: 'string', arrfoo: [1, 2], objfoo: { num: 42 } }
|
||||
const obj = { foo: true, ofoo: '42' }
|
||||
t.assert.equal(stringify(obj), '{"foo":1,"ofoo":42}')
|
||||
})
|
||||
|
||||
test('additionalProperties - boolean coerce', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'check boolean coerce',
|
||||
type: 'object',
|
||||
properties: {},
|
||||
additionalProperties: {
|
||||
type: 'boolean'
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { foo: 'true', ofoo: 0, arrfoo: [1, 2], objfoo: { a: true } }
|
||||
t.assert.equal(stringify(obj), '{"foo":true,"ofoo":false,"arrfoo":true,"objfoo":true}')
|
||||
})
|
||||
|
||||
test('additionalProperties - object coerce', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'check object coerce',
|
||||
type: 'object',
|
||||
properties: {},
|
||||
additionalProperties: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
answer: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { objfoo: { answer: 42 } }
|
||||
t.assert.equal(stringify(obj), '{"objfoo":{"answer":42}}')
|
||||
})
|
||||
|
||||
test('additionalProperties - array coerce', (t) => {
|
||||
t.plan(2)
|
||||
const stringify = build({
|
||||
title: 'check array coerce',
|
||||
type: 'object',
|
||||
properties: {},
|
||||
additionalProperties: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const coercibleValues = { arrfoo: [1, 2] }
|
||||
t.assert.equal(stringify(coercibleValues), '{"arrfoo":["1","2"]}')
|
||||
|
||||
const incoercibleValues = { foo: 'true', ofoo: 0, objfoo: { tyrion: 'lannister' } }
|
||||
t.assert.throws(() => stringify(incoercibleValues))
|
||||
})
|
||||
|
||||
test('additionalProperties with empty schema', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
type: 'object',
|
||||
additionalProperties: {}
|
||||
})
|
||||
|
||||
const obj = { a: 1, b: true, c: null }
|
||||
t.assert.equal(stringify(obj), '{"a":1,"b":true,"c":null}')
|
||||
})
|
||||
|
||||
test('additionalProperties with nested empty schema', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: { type: 'object', additionalProperties: {} }
|
||||
},
|
||||
required: ['data']
|
||||
})
|
||||
|
||||
const obj = { data: { a: 1, b: true, c: null } }
|
||||
t.assert.equal(stringify(obj), '{"data":{"a":1,"b":true,"c":null}}')
|
||||
})
|
||||
|
||||
test('nested additionalProperties', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'additionalProperties',
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
ap: {
|
||||
type: 'object',
|
||||
additionalProperties: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = [{ ap: { value: 'string' } }]
|
||||
t.assert.equal(stringify(obj), '[{"ap":{"value":"string"}}]')
|
||||
})
|
||||
|
||||
test('very nested additionalProperties', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'additionalProperties',
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
ap: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
nested: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
moarNested: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
finally: {
|
||||
type: 'object',
|
||||
additionalProperties: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = [{ ap: { nested: { moarNested: { finally: { value: 'str' } } } } }]
|
||||
t.assert.equal(stringify(obj), '[{"ap":{"nested":{"moarNested":{"finally":{"value":"str"}}}}}]')
|
||||
})
|
||||
|
||||
test('nested additionalProperties set to true', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'nested additionalProperties=true',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ap: {
|
||||
type: 'object',
|
||||
additionalProperties: true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { ap: { value: 'string', someNumber: 42 } }
|
||||
t.assert.equal(stringify(obj), '{"ap":{"value":"string","someNumber":42}}')
|
||||
})
|
||||
|
||||
test('field passed to fastSafeStringify as undefined should be removed', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'nested additionalProperties=true',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ap: {
|
||||
type: 'object',
|
||||
additionalProperties: true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { ap: { value: 'string', someNumber: undefined } }
|
||||
t.assert.equal(stringify(obj), '{"ap":{"value":"string"}}')
|
||||
})
|
||||
|
||||
test('property without type but with enum, will acts as additionalProperties', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'automatic additionalProperties',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ap: {
|
||||
enum: ['foobar', 42, ['foo', 'bar'], {}]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { ap: { additional: 'field' } }
|
||||
t.assert.equal(stringify(obj), '{"ap":{"additional":"field"}}')
|
||||
})
|
||||
|
||||
test('property without type but with enum, will acts as additionalProperties without overwriting', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'automatic additionalProperties',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ap: {
|
||||
additionalProperties: false,
|
||||
enum: ['foobar', 42, ['foo', 'bar'], {}]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { ap: { additional: 'field' } }
|
||||
t.assert.equal(stringify(obj), '{"ap":{}}')
|
||||
})
|
||||
|
||||
test('function and symbol references are not serialized as undefined', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'additionalProperties',
|
||||
type: 'object',
|
||||
additionalProperties: true,
|
||||
properties: {
|
||||
str: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { str: 'x', test: 'test', meth: () => 'x', sym: Symbol('x') }
|
||||
t.assert.equal(stringify(obj), '{"str":"x","test":"test"}')
|
||||
})
|
||||
751
node_modules/fast-json-stringify/test/allof.test.js
generated
vendored
Normal file
751
node_modules/fast-json-stringify/test/allof.test.js
generated
vendored
Normal file
@@ -0,0 +1,751 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
process.env.TZ = 'UTC'
|
||||
|
||||
test('allOf: combine type and format ', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
allOf: [
|
||||
{ type: 'string' },
|
||||
{ format: 'time' }
|
||||
]
|
||||
}
|
||||
const stringify = build(schema)
|
||||
const date = new Date(1674263005800)
|
||||
const value = stringify(date)
|
||||
t.assert.equal(value, '"01:03:25"')
|
||||
})
|
||||
|
||||
test('allOf: combine additional properties ', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
allOf: [
|
||||
{ type: 'object' },
|
||||
{
|
||||
type: 'object',
|
||||
additionalProperties: { type: 'boolean' }
|
||||
}
|
||||
]
|
||||
}
|
||||
const stringify = build(schema)
|
||||
const data = { property: true }
|
||||
const value = stringify(data)
|
||||
t.assert.equal(value, JSON.stringify(data))
|
||||
})
|
||||
|
||||
test('allOf: combine pattern properties', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
allOf: [
|
||||
{ type: 'object' },
|
||||
{
|
||||
type: 'object',
|
||||
patternProperties: {
|
||||
foo: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
const stringify = build(schema)
|
||||
const data = { foo: 42 }
|
||||
const value = stringify(data)
|
||||
t.assert.equal(value, JSON.stringify(data))
|
||||
})
|
||||
|
||||
test('object with allOf and multiple schema on the allOf', (t) => {
|
||||
t.plan(4)
|
||||
|
||||
const schema = {
|
||||
title: 'object with allOf and multiple schema on the allOf',
|
||||
type: 'object',
|
||||
allOf: [
|
||||
{
|
||||
type: 'object',
|
||||
required: [
|
||||
'name'
|
||||
],
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string'
|
||||
},
|
||||
tag: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
required: [
|
||||
'id'
|
||||
],
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
try {
|
||||
stringify({
|
||||
id: 1
|
||||
})
|
||||
} catch (e) {
|
||||
t.assert.equal(e.message, '"name" is required!')
|
||||
}
|
||||
|
||||
try {
|
||||
stringify({
|
||||
name: 'string'
|
||||
})
|
||||
} catch (e) {
|
||||
t.assert.equal(e.message, '"id" is required!')
|
||||
}
|
||||
|
||||
t.assert.equal(stringify({
|
||||
id: 1,
|
||||
name: 'string'
|
||||
}), '{"name":"string","id":1}')
|
||||
|
||||
t.assert.equal(stringify({
|
||||
id: 1,
|
||||
name: 'string',
|
||||
tag: 'otherString'
|
||||
}), '{"name":"string","id":1,"tag":"otherString"}')
|
||||
})
|
||||
|
||||
test('object with allOf and one schema on the allOf', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'object with allOf and one schema on the allOf',
|
||||
type: 'object',
|
||||
allOf: [
|
||||
{
|
||||
required: [
|
||||
'id'
|
||||
],
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
const value = stringify({
|
||||
id: 1
|
||||
})
|
||||
t.assert.equal(value, '{"id":1}')
|
||||
})
|
||||
|
||||
test('object with allOf and no schema on the allOf', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'object with allOf and no schema on the allOf',
|
||||
type: 'object',
|
||||
allOf: []
|
||||
}
|
||||
|
||||
try {
|
||||
build(schema)
|
||||
t.fail()
|
||||
} catch (e) {
|
||||
t.assert.equal(e.message, 'schema is invalid: data/allOf must NOT have fewer than 1 items')
|
||||
}
|
||||
})
|
||||
|
||||
test('object with nested allOfs', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'object with nested allOfs',
|
||||
type: 'object',
|
||||
allOf: [
|
||||
{
|
||||
required: [
|
||||
'id1'
|
||||
],
|
||||
type: 'object',
|
||||
properties: {
|
||||
id1: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
allOf: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
id2: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
id3: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const value = stringify({
|
||||
id1: 1,
|
||||
id2: 2,
|
||||
id3: 3,
|
||||
id4: 4 // extra prop shouldn't be in result
|
||||
})
|
||||
t.assert.equal(value, '{"id1":1,"id2":2,"id3":3}')
|
||||
})
|
||||
|
||||
test('object with anyOf nested inside allOf', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'object with anyOf nested inside allOf',
|
||||
type: 'object',
|
||||
allOf: [
|
||||
{
|
||||
required: ['id1', 'obj'],
|
||||
type: 'object',
|
||||
properties: {
|
||||
id1: {
|
||||
type: 'integer'
|
||||
},
|
||||
obj: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
nested: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
anyOf: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
id2: { type: 'string' }
|
||||
},
|
||||
required: ['id2']
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
id3: {
|
||||
type: 'integer'
|
||||
},
|
||||
nestedObj: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
nested: { type: 'string' }
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ['id3']
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
id4: { type: 'integer' }
|
||||
},
|
||||
required: ['id4']
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const value = stringify({
|
||||
id1: 1,
|
||||
id3: 3,
|
||||
id4: 4, // extra prop shouldn't be in result
|
||||
obj: { nested: 'yes' },
|
||||
nestedObj: { nested: 'yes' }
|
||||
})
|
||||
t.assert.equal(value, '{"id1":1,"obj":{"nested":"yes"},"id3":3,"nestedObj":{"nested":"yes"}}')
|
||||
})
|
||||
|
||||
test('object with $ref in allOf', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'object with $ref in allOf',
|
||||
type: 'object',
|
||||
definitions: {
|
||||
id1: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id1: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
allOf: [
|
||||
{
|
||||
$ref: '#/definitions/id1'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const value = stringify({
|
||||
id1: 1,
|
||||
id2: 2 // extra prop shouldn't be in result
|
||||
})
|
||||
t.assert.equal(value, '{"id1":1}')
|
||||
})
|
||||
|
||||
test('object with $ref and other object in allOf', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'object with $ref in allOf',
|
||||
type: 'object',
|
||||
definitions: {
|
||||
id1: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id1: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
allOf: [
|
||||
{
|
||||
$ref: '#/definitions/id1'
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
id2: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const value = stringify({
|
||||
id1: 1,
|
||||
id2: 2,
|
||||
id3: 3 // extra prop shouldn't be in result
|
||||
})
|
||||
t.assert.equal(value, '{"id1":1,"id2":2}')
|
||||
})
|
||||
|
||||
test('object with multiple $refs in allOf', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'object with $ref in allOf',
|
||||
type: 'object',
|
||||
definitions: {
|
||||
id1: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id1: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
},
|
||||
id2: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id2: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
allOf: [
|
||||
{
|
||||
$ref: '#/definitions/id1'
|
||||
},
|
||||
{
|
||||
$ref: '#/definitions/id2'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const value = stringify({
|
||||
id1: 1,
|
||||
id2: 2,
|
||||
id3: 3 // extra prop shouldn't be in result
|
||||
})
|
||||
t.assert.equal(value, '{"id1":1,"id2":2}')
|
||||
})
|
||||
|
||||
test('allOf with nested allOf in $ref', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'allOf with nested allOf in $ref',
|
||||
type: 'object',
|
||||
definitions: {
|
||||
group: {
|
||||
type: 'object',
|
||||
allOf: [{
|
||||
properties: {
|
||||
id2: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}, {
|
||||
properties: {
|
||||
id3: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
allOf: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
id1: {
|
||||
type: 'integer'
|
||||
}
|
||||
},
|
||||
required: [
|
||||
'id1'
|
||||
]
|
||||
},
|
||||
{
|
||||
$ref: '#/definitions/group'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const value = stringify({
|
||||
id1: 1,
|
||||
id2: 2,
|
||||
id3: 3,
|
||||
id4: 4 // extra prop shouldn't be in result
|
||||
})
|
||||
t.assert.equal(value, '{"id1":1,"id2":2,"id3":3}')
|
||||
})
|
||||
|
||||
test('object with external $refs in allOf', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const externalSchema = {
|
||||
first: {
|
||||
definitions: {
|
||||
id1: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id1: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
second: {
|
||||
definitions: {
|
||||
id2: {
|
||||
$id: '#id2',
|
||||
type: 'object',
|
||||
properties: {
|
||||
id2: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
title: 'object with $ref in allOf',
|
||||
type: 'object',
|
||||
allOf: [
|
||||
{
|
||||
$ref: 'first#/definitions/id1'
|
||||
},
|
||||
{
|
||||
$ref: 'second#/definitions/id2'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const stringify = build(schema, { schema: externalSchema })
|
||||
const value = stringify({
|
||||
id1: 1,
|
||||
id2: 2,
|
||||
id3: 3 // extra prop shouldn't be in result
|
||||
})
|
||||
t.assert.equal(value, '{"id1":1,"id2":2}')
|
||||
})
|
||||
|
||||
test('allof with local anchor reference', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const externalSchemas = {
|
||||
Test: {
|
||||
$id: 'Test',
|
||||
definitions: {
|
||||
Problem: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
type: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
ValidationFragment: {
|
||||
type: 'string'
|
||||
},
|
||||
ValidationErrorProblem: {
|
||||
type: 'object',
|
||||
allOf: [
|
||||
{
|
||||
$ref: '#/definitions/Problem'
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
validation: {
|
||||
$ref: '#/definitions/ValidationFragment'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema = { $ref: 'Test#/definitions/ValidationErrorProblem' }
|
||||
const stringify = build(schema, { schema: externalSchemas })
|
||||
const data = { type: 'foo', validation: 'bar' }
|
||||
|
||||
t.assert.equal(stringify(data), JSON.stringify(data))
|
||||
})
|
||||
|
||||
test('allOf: multiple nested $ref properties', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const externalSchema1 = {
|
||||
$id: 'externalSchema1',
|
||||
oneOf: [
|
||||
{ $ref: '#/definitions/id1' }
|
||||
],
|
||||
definitions: {
|
||||
id1: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id1: {
|
||||
type: 'integer'
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const externalSchema2 = {
|
||||
$id: 'externalSchema2',
|
||||
oneOf: [
|
||||
{ $ref: '#/definitions/id2' }
|
||||
],
|
||||
definitions: {
|
||||
id2: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id2: {
|
||||
type: 'integer'
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
anyOf: [
|
||||
{ $ref: 'externalSchema1' },
|
||||
{ $ref: 'externalSchema2' }
|
||||
]
|
||||
}
|
||||
|
||||
const stringify = build(schema, { schema: [externalSchema1, externalSchema2] })
|
||||
|
||||
t.assert.equal(stringify({ id1: 1 }), JSON.stringify({ id1: 1 }))
|
||||
t.assert.equal(stringify({ id2: 2 }), JSON.stringify({ id2: 2 }))
|
||||
})
|
||||
|
||||
test('allOf: throw Error if types mismatch ', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
allOf: [
|
||||
{ type: 'string' },
|
||||
{ type: 'number' }
|
||||
]
|
||||
}
|
||||
t.assert.throws(() => {
|
||||
build(schema)
|
||||
}, {
|
||||
message: 'Failed to merge "type" keyword schemas.',
|
||||
schemas: [['string'], ['number']]
|
||||
})
|
||||
})
|
||||
|
||||
test('allOf: throw Error if format mismatch ', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
allOf: [
|
||||
{ format: 'date' },
|
||||
{ format: 'time' }
|
||||
]
|
||||
}
|
||||
t.assert.throws(() => {
|
||||
build(schema)
|
||||
}, {
|
||||
message: 'Failed to merge "format" keyword schemas.'
|
||||
// schemas: ['date', 'time']
|
||||
})
|
||||
})
|
||||
|
||||
test('recursive nested allOfs', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
additionalProperties: false,
|
||||
allOf: [{ $ref: '#' }]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const data = { foo: {} }
|
||||
const stringify = build(schema)
|
||||
t.assert.equal(stringify(data), JSON.stringify(data))
|
||||
})
|
||||
|
||||
test('recursive nested allOfs', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
additionalProperties: false,
|
||||
allOf: [{ allOf: [{ $ref: '#' }] }]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const data = { foo: {} }
|
||||
const stringify = build(schema)
|
||||
t.assert.equal(stringify(data), JSON.stringify(data))
|
||||
})
|
||||
|
||||
test('external recursive allOfs', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const externalSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
properties: {
|
||||
bar: { type: 'string' }
|
||||
},
|
||||
allOf: [{ $ref: '#' }]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: { $ref: 'externalSchema#/properties/foo' },
|
||||
b: { $ref: 'externalSchema#/properties/foo' }
|
||||
}
|
||||
}
|
||||
|
||||
const data = {
|
||||
a: {
|
||||
foo: {},
|
||||
bar: '42',
|
||||
baz: 42
|
||||
},
|
||||
b: {
|
||||
foo: {},
|
||||
bar: '42',
|
||||
baz: 42
|
||||
}
|
||||
}
|
||||
const stringify = build(schema, { schema: { externalSchema } })
|
||||
t.assert.equal(stringify(data), '{"a":{"bar":"42","foo":{}},"b":{"bar":"42","foo":{}}}')
|
||||
})
|
||||
|
||||
test('do not crash with $ref prop', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'object with $ref',
|
||||
type: 'object',
|
||||
properties: {
|
||||
outside: {
|
||||
$ref: '#/$defs/outside'
|
||||
}
|
||||
},
|
||||
$defs: {
|
||||
inside: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
$ref: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
outside: {
|
||||
allOf: [{
|
||||
$ref: '#/$defs/inside'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
const value = stringify({
|
||||
outside: {
|
||||
$ref: 'true'
|
||||
}
|
||||
})
|
||||
t.assert.equal(value, '{"outside":{"$ref":"true"}}')
|
||||
})
|
||||
231
node_modules/fast-json-stringify/test/any.test.js
generated
vendored
Normal file
231
node_modules/fast-json-stringify/test/any.test.js
generated
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('object with nested random property', (t) => {
|
||||
t.plan(4)
|
||||
|
||||
const schema = {
|
||||
title: 'empty schema to allow any object',
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'number' },
|
||||
name: {}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({
|
||||
id: 1, name: 'string'
|
||||
}), '{"id":1,"name":"string"}')
|
||||
|
||||
t.assert.equal(stringify({
|
||||
id: 1, name: { first: 'name', last: 'last' }
|
||||
}), '{"id":1,"name":{"first":"name","last":"last"}}')
|
||||
|
||||
t.assert.equal(stringify({
|
||||
id: 1, name: null
|
||||
}), '{"id":1,"name":null}')
|
||||
|
||||
t.assert.equal(stringify({
|
||||
id: 1, name: ['first', 'last']
|
||||
}), '{"id":1,"name":["first","last"]}')
|
||||
})
|
||||
|
||||
// reference: https://github.com/fastify/fast-json-stringify/issues/259
|
||||
test('object with empty schema with $id: undefined set', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'empty schema to allow any object with $id: undefined set',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { $id: undefined }
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
t.assert.equal(stringify({
|
||||
name: 'string'
|
||||
}), '{"name":"string"}')
|
||||
})
|
||||
|
||||
test('array with random items', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'empty schema to allow any object',
|
||||
type: 'array',
|
||||
items: {}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
const value = stringify([1, 'string', null])
|
||||
t.assert.equal(value, '[1,"string",null]')
|
||||
})
|
||||
|
||||
test('empty schema', (t) => {
|
||||
t.plan(7)
|
||||
|
||||
const schema = { }
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify(null), 'null')
|
||||
t.assert.equal(stringify(1), '1')
|
||||
t.assert.equal(stringify(true), 'true')
|
||||
t.assert.equal(stringify('hello'), '"hello"')
|
||||
t.assert.equal(stringify({}), '{}')
|
||||
t.assert.equal(stringify({ x: 10 }), '{"x":10}')
|
||||
t.assert.equal(stringify([true, 1, 'hello']), '[true,1,"hello"]')
|
||||
})
|
||||
|
||||
test('empty schema on nested object', (t) => {
|
||||
t.plan(7)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
x: {}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({ x: null }), '{"x":null}')
|
||||
t.assert.equal(stringify({ x: 1 }), '{"x":1}')
|
||||
t.assert.equal(stringify({ x: true }), '{"x":true}')
|
||||
t.assert.equal(stringify({ x: 'hello' }), '{"x":"hello"}')
|
||||
t.assert.equal(stringify({ x: {} }), '{"x":{}}')
|
||||
t.assert.equal(stringify({ x: { x: 10 } }), '{"x":{"x":10}}')
|
||||
t.assert.equal(stringify({ x: [true, 1, 'hello'] }), '{"x":[true,1,"hello"]}')
|
||||
})
|
||||
|
||||
test('empty schema on array', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
type: 'array',
|
||||
items: {}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify([1, true, 'hello', [], { x: 1 }]), '[1,true,"hello",[],{"x":1}]')
|
||||
})
|
||||
|
||||
test('empty schema on anyOf', (t) => {
|
||||
t.plan(4)
|
||||
|
||||
// any on Foo codepath.
|
||||
const schema = {
|
||||
anyOf: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: {
|
||||
type: 'string',
|
||||
enum: ['Foo']
|
||||
},
|
||||
value: {}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: {
|
||||
type: 'string',
|
||||
enum: ['Bar']
|
||||
},
|
||||
value: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({ kind: 'Bar', value: 1 }), '{"kind":"Bar","value":1}')
|
||||
t.assert.equal(stringify({ kind: 'Foo', value: 1 }), '{"kind":"Foo","value":1}')
|
||||
t.assert.equal(stringify({ kind: 'Foo', value: true }), '{"kind":"Foo","value":true}')
|
||||
t.assert.equal(stringify({ kind: 'Foo', value: 'hello' }), '{"kind":"Foo","value":"hello"}')
|
||||
})
|
||||
|
||||
test('should throw a TypeError with the path to the key of the invalid value /1', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
// any on Foo codepath.
|
||||
const schema = {
|
||||
anyOf: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: {
|
||||
type: 'string',
|
||||
enum: ['Foo']
|
||||
},
|
||||
value: {}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: {
|
||||
type: 'string',
|
||||
enum: ['Bar']
|
||||
},
|
||||
value: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.throws(() => stringify({ kind: 'Baz', value: 1 }), new TypeError('The value of \'#\' does not match schema definition.'))
|
||||
})
|
||||
|
||||
test('should throw a TypeError with the path to the key of the invalid value /2', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
// any on Foo codepath.
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: {
|
||||
anyOf: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: {
|
||||
type: 'string',
|
||||
enum: ['Foo']
|
||||
},
|
||||
value: {}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: {
|
||||
type: 'string',
|
||||
enum: ['Bar']
|
||||
},
|
||||
value: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.throws(() => stringify({ data: { kind: 'Baz', value: 1 } }), new TypeError('The value of \'#/properties/data\' does not match schema definition.'))
|
||||
})
|
||||
792
node_modules/fast-json-stringify/test/anyof.test.js
generated
vendored
Normal file
792
node_modules/fast-json-stringify/test/anyof.test.js
generated
vendored
Normal file
@@ -0,0 +1,792 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
process.env.TZ = 'UTC'
|
||||
|
||||
test('object with multiple types field', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'object with multiple types field',
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
anyOf: [{
|
||||
type: 'string'
|
||||
}, {
|
||||
type: 'boolean'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({
|
||||
str: 'string'
|
||||
}), '{"str":"string"}')
|
||||
|
||||
t.assert.equal(stringify({
|
||||
str: true
|
||||
}), '{"str":true}')
|
||||
})
|
||||
|
||||
test('object with field of type object or null', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'object with field of type object or null',
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop: {
|
||||
anyOf: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}, {
|
||||
type: 'null'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({
|
||||
prop: null
|
||||
}), '{"prop":null}')
|
||||
|
||||
t.assert.equal(stringify({
|
||||
prop: {
|
||||
str: 'string'
|
||||
}
|
||||
}), '{"prop":{"str":"string"}}')
|
||||
})
|
||||
|
||||
test('object with field of type object or array', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'object with field of type object or array',
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop: {
|
||||
anyOf: [{
|
||||
type: 'object',
|
||||
properties: {},
|
||||
additionalProperties: true
|
||||
}, {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({
|
||||
prop: {
|
||||
str: 'string'
|
||||
}
|
||||
}), '{"prop":{"str":"string"}}')
|
||||
|
||||
t.assert.equal(stringify({
|
||||
prop: ['string']
|
||||
}), '{"prop":["string"]}')
|
||||
})
|
||||
|
||||
test('object with field of type string and coercion disable ', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'object with field of type string',
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
anyOf: [{
|
||||
type: 'string'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
t.assert.throws(() => stringify({ str: 1 }))
|
||||
})
|
||||
|
||||
test('object with field of type string and coercion enable ', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'object with field of type string',
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
anyOf: [{
|
||||
type: 'string'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const options = {
|
||||
ajv: {
|
||||
coerceTypes: true
|
||||
}
|
||||
}
|
||||
const stringify = build(schema, options)
|
||||
|
||||
const value = stringify({
|
||||
str: 1
|
||||
})
|
||||
t.assert.equal(value, '{"str":"1"}')
|
||||
})
|
||||
|
||||
test('object with field with type union of multiple objects', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'object with anyOf property value containing objects',
|
||||
type: 'object',
|
||||
properties: {
|
||||
anyOfSchema: {
|
||||
anyOf: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
baz: { type: 'number' }
|
||||
},
|
||||
required: ['baz']
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
bar: { type: 'string' }
|
||||
},
|
||||
required: ['bar']
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
required: ['anyOfSchema']
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({ anyOfSchema: { baz: 5 } }), '{"anyOfSchema":{"baz":5}}')
|
||||
|
||||
t.assert.equal(stringify({ anyOfSchema: { bar: 'foo' } }), '{"anyOfSchema":{"bar":"foo"}}')
|
||||
})
|
||||
|
||||
test('null value in schema', (t) => {
|
||||
t.plan(0)
|
||||
|
||||
const schema = {
|
||||
title: 'schema with null child',
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
enum: [null]
|
||||
}
|
||||
|
||||
build(schema)
|
||||
})
|
||||
|
||||
test('symbol value in schema', (t) => {
|
||||
t.plan(4)
|
||||
|
||||
const ObjectKind = Symbol('LiteralKind')
|
||||
const UnionKind = Symbol('UnionKind')
|
||||
const LiteralKind = Symbol('LiteralKind')
|
||||
|
||||
const schema = {
|
||||
kind: ObjectKind,
|
||||
type: 'object',
|
||||
properties: {
|
||||
value: {
|
||||
kind: UnionKind,
|
||||
anyOf: [
|
||||
{ kind: LiteralKind, type: 'string', enum: ['foo'] },
|
||||
{ kind: LiteralKind, type: 'string', enum: ['bar'] },
|
||||
{ kind: LiteralKind, type: 'string', enum: ['baz'] }
|
||||
]
|
||||
}
|
||||
},
|
||||
required: ['value']
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
t.assert.equal(stringify({ value: 'foo' }), '{"value":"foo"}')
|
||||
t.assert.equal(stringify({ value: 'bar' }), '{"value":"bar"}')
|
||||
t.assert.equal(stringify({ value: 'baz' }), '{"value":"baz"}')
|
||||
t.assert.throws(() => stringify({ value: 'qux' }))
|
||||
})
|
||||
|
||||
test('anyOf and $ref together', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
cs: {
|
||||
anyOf: [
|
||||
{
|
||||
$ref: '#/definitions/Option'
|
||||
},
|
||||
{
|
||||
type: 'boolean'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
definitions: {
|
||||
Option: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({ cs: 'franco' }), '{"cs":"franco"}')
|
||||
|
||||
t.assert.equal(stringify({ cs: true }), '{"cs":true}')
|
||||
})
|
||||
|
||||
test('anyOf and $ref: 2 levels are fine', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
cs: {
|
||||
anyOf: [
|
||||
{
|
||||
$ref: '#/definitions/Option'
|
||||
},
|
||||
{
|
||||
type: 'boolean'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
definitions: {
|
||||
Option: {
|
||||
anyOf: [
|
||||
{
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
type: 'boolean'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const value = stringify({ cs: 3 })
|
||||
t.assert.equal(value, '{"cs":3}')
|
||||
})
|
||||
|
||||
test('anyOf and $ref: multiple levels should throw at build.', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
cs: {
|
||||
anyOf: [
|
||||
{
|
||||
$ref: '#/definitions/Option'
|
||||
},
|
||||
{
|
||||
type: 'boolean'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
definitions: {
|
||||
Option: {
|
||||
anyOf: [
|
||||
{
|
||||
$ref: '#/definitions/Option2'
|
||||
},
|
||||
{
|
||||
type: 'string'
|
||||
}
|
||||
]
|
||||
},
|
||||
Option2: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({ cs: 3 }), '{"cs":3}')
|
||||
t.assert.equal(stringify({ cs: true }), '{"cs":true}')
|
||||
t.assert.equal(stringify({ cs: 'pippo' }), '{"cs":"pippo"}')
|
||||
})
|
||||
|
||||
test('anyOf and $ref - multiple external $ref', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const externalSchema = {
|
||||
external: {
|
||||
definitions: {
|
||||
def: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop: { anyOf: [{ $ref: 'external2#/definitions/other' }] }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
external2: {
|
||||
definitions: {
|
||||
internal: {
|
||||
type: 'string'
|
||||
},
|
||||
other: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop2: { $ref: '#/definitions/internal' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
title: 'object with $ref',
|
||||
type: 'object',
|
||||
properties: {
|
||||
obj: {
|
||||
$ref: 'external#/definitions/def'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const object = {
|
||||
obj: {
|
||||
prop: {
|
||||
prop2: 'test'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema, { schema: externalSchema })
|
||||
const output = stringify(object)
|
||||
|
||||
t.assert.doesNotThrow(() => JSON.parse(output))
|
||||
t.assert.equal(output, '{"obj":{"prop":{"prop2":"test"}}}')
|
||||
})
|
||||
|
||||
test('anyOf looks for all of the array items', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'type array that may have any of declared items',
|
||||
type: 'array',
|
||||
items: {
|
||||
anyOf: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
savedId: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
required: ['savedId']
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
error: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
required: ['error']
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
const value = stringify([{ savedId: 'great' }, { error: 'oops' }])
|
||||
t.assert.equal(value, '[{"savedId":"great"},{"error":"oops"}]')
|
||||
})
|
||||
|
||||
test('anyOf with enum with more than 100 entries', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'type array that may have any of declared items',
|
||||
type: 'array',
|
||||
items: {
|
||||
anyOf: [
|
||||
{
|
||||
type: 'string',
|
||||
enum: ['EUR', 'USD', ...(new Set([...new Array(200)].map(() => Math.random().toString(36).substr(2, 3)))).values()]
|
||||
},
|
||||
{ type: 'null' }
|
||||
]
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
const value = stringify(['EUR', 'USD', null])
|
||||
t.assert.equal(value, '["EUR","USD",null]')
|
||||
})
|
||||
|
||||
test('anyOf object with field date-time of type string with format or null', (t) => {
|
||||
t.plan(1)
|
||||
const toStringify = new Date()
|
||||
const withOneOfSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop: {
|
||||
anyOf: [{
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
}, {
|
||||
type: 'null'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const withOneOfStringify = build(withOneOfSchema)
|
||||
|
||||
t.assert.equal(withOneOfStringify({
|
||||
prop: toStringify
|
||||
}), `{"prop":"${toStringify.toISOString()}"}`)
|
||||
})
|
||||
|
||||
test('anyOf object with nested field date-time of type string with format or null', (t) => {
|
||||
t.plan(1)
|
||||
const withOneOfSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop: {
|
||||
anyOf: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
nestedProp: {
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const withOneOfStringify = build(withOneOfSchema)
|
||||
|
||||
const data = {
|
||||
prop: { nestedProp: new Date() }
|
||||
}
|
||||
|
||||
t.assert.equal(withOneOfStringify(data), JSON.stringify(data))
|
||||
})
|
||||
|
||||
test('anyOf object with nested field date of type string with format or null', (t) => {
|
||||
t.plan(1)
|
||||
const withOneOfSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop: {
|
||||
anyOf: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
nestedProp: {
|
||||
type: 'string',
|
||||
format: 'date'
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const withOneOfStringify = build(withOneOfSchema)
|
||||
|
||||
const data = {
|
||||
prop: { nestedProp: new Date(1674263005800) }
|
||||
}
|
||||
|
||||
t.assert.equal(withOneOfStringify(data), '{"prop":{"nestedProp":"2023-01-21"}}')
|
||||
})
|
||||
|
||||
test('anyOf object with nested field time of type string with format or null', (t) => {
|
||||
t.plan(1)
|
||||
const withOneOfSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop: {
|
||||
anyOf: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
nestedProp: {
|
||||
type: 'string',
|
||||
format: 'time'
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const withOneOfStringify = build(withOneOfSchema)
|
||||
|
||||
const data = {
|
||||
prop: { nestedProp: new Date(1674263005800) }
|
||||
}
|
||||
t.assert.equal(withOneOfStringify(data), '{"prop":{"nestedProp":"01:03:25"}}')
|
||||
})
|
||||
|
||||
test('anyOf object with field date of type string with format or null', (t) => {
|
||||
t.plan(1)
|
||||
const toStringify = '2011-01-01'
|
||||
const withOneOfSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop: {
|
||||
anyOf: [{
|
||||
type: 'string',
|
||||
format: 'date'
|
||||
}, {
|
||||
type: 'null'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const withOneOfStringify = build(withOneOfSchema)
|
||||
t.assert.equal(withOneOfStringify({
|
||||
prop: toStringify
|
||||
}), '{"prop":"2011-01-01"}')
|
||||
})
|
||||
|
||||
test('anyOf object with invalid field date of type string with format or null', (t) => {
|
||||
t.plan(1)
|
||||
const toStringify = 'foo bar'
|
||||
const withOneOfSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop: {
|
||||
anyOf: [{
|
||||
type: 'string',
|
||||
format: 'date'
|
||||
}, {
|
||||
type: 'null'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const withOneOfStringify = build(withOneOfSchema)
|
||||
t.assert.throws(() => withOneOfStringify({ prop: toStringify }))
|
||||
})
|
||||
|
||||
test('anyOf with a nested external schema', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const externalSchemas = {
|
||||
schema1: {
|
||||
definitions: {
|
||||
def1: {
|
||||
$id: 'external',
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
const schema = { anyOf: [{ $ref: 'external' }] }
|
||||
|
||||
const stringify = build(schema, { schema: externalSchemas })
|
||||
t.assert.equal(stringify('foo'), '"foo"')
|
||||
})
|
||||
|
||||
test('object with ref and validated properties', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const externalSchemas = {
|
||||
RefSchema: {
|
||||
$id: 'RefSchema',
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
$id: 'root',
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
anyOf: [
|
||||
{ type: 'string' },
|
||||
{ type: 'number' }
|
||||
]
|
||||
},
|
||||
reference: { $ref: 'RefSchema' }
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema, { schema: externalSchemas })
|
||||
t.assert.equal(stringify({ id: 1, reference: 'hi' }), '{"id":1,"reference":"hi"}')
|
||||
})
|
||||
|
||||
test('anyOf required props', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop1: { type: 'string' },
|
||||
prop2: { type: 'string' },
|
||||
prop3: { type: 'string' }
|
||||
},
|
||||
required: ['prop1'],
|
||||
anyOf: [{ required: ['prop2'] }, { required: ['prop3'] }]
|
||||
}
|
||||
const stringify = build(schema)
|
||||
t.assert.equal(stringify({ prop1: 'test', prop2: 'test2' }), '{"prop1":"test","prop2":"test2"}')
|
||||
t.assert.equal(stringify({ prop1: 'test', prop3: 'test3' }), '{"prop1":"test","prop3":"test3"}')
|
||||
t.assert.equal(stringify({ prop1: 'test', prop2: 'test2', prop3: 'test3' }), '{"prop1":"test","prop2":"test2","prop3":"test3"}')
|
||||
})
|
||||
|
||||
test('anyOf required props', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop1: { type: 'string' }
|
||||
},
|
||||
anyOf: [
|
||||
{
|
||||
properties: {
|
||||
prop2: { type: 'string' }
|
||||
}
|
||||
},
|
||||
{
|
||||
properties: {
|
||||
prop3: { type: 'string' }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
const stringify = build(schema)
|
||||
t.assert.equal(stringify({ prop1: 'test1' }), '{"prop1":"test1"}')
|
||||
t.assert.equal(stringify({ prop2: 'test2' }), '{"prop2":"test2"}')
|
||||
t.assert.equal(stringify({ prop1: 'test1', prop2: 'test2' }), '{"prop1":"test1","prop2":"test2"}')
|
||||
})
|
||||
|
||||
test('recursive nested anyOfs', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
additionalProperties: false,
|
||||
anyOf: [{ $ref: '#' }]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const data = { foo: {} }
|
||||
const stringify = build(schema)
|
||||
t.assert.equal(stringify(data), JSON.stringify(data))
|
||||
})
|
||||
|
||||
test('recursive nested anyOfs', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
additionalProperties: false,
|
||||
anyOf: [{ anyOf: [{ $ref: '#' }] }]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const data = { foo: {} }
|
||||
const stringify = build(schema)
|
||||
t.assert.equal(stringify(data), JSON.stringify(data))
|
||||
})
|
||||
|
||||
test('external recursive anyOfs', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const externalSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
properties: {
|
||||
bar: { type: 'string' }
|
||||
},
|
||||
anyOf: [{ $ref: '#' }]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: { $ref: 'externalSchema#/properties/foo' },
|
||||
b: { $ref: 'externalSchema#/properties/foo' }
|
||||
}
|
||||
}
|
||||
|
||||
const data = {
|
||||
a: {
|
||||
foo: {},
|
||||
bar: '42',
|
||||
baz: 42
|
||||
},
|
||||
b: {
|
||||
foo: {},
|
||||
bar: '42',
|
||||
baz: 42
|
||||
}
|
||||
}
|
||||
const stringify = build(schema, { schema: { externalSchema } })
|
||||
t.assert.equal(stringify(data), '{"a":{"bar":"42","foo":{}},"b":{"bar":"42","foo":{}}}')
|
||||
})
|
||||
|
||||
test('should build merged schemas twice', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
enums: {
|
||||
type: 'string',
|
||||
anyOf: [
|
||||
{ type: 'string', const: 'FOO' },
|
||||
{ type: 'string', const: 'BAR' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const stringify = build(schema)
|
||||
t.assert.equal(stringify({ enums: 'FOO' }), '{"enums":"FOO"}')
|
||||
}
|
||||
|
||||
{
|
||||
const stringify = build(schema)
|
||||
t.assert.equal(stringify({ enums: 'BAR' }), '{"enums":"BAR"}')
|
||||
}
|
||||
})
|
||||
638
node_modules/fast-json-stringify/test/array.test.js
generated
vendored
Normal file
638
node_modules/fast-json-stringify/test/array.test.js
generated
vendored
Normal file
@@ -0,0 +1,638 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const validator = require('is-my-json-valid')
|
||||
const build = require('..')
|
||||
const Ajv = require('ajv')
|
||||
|
||||
test('error on invalid largeArrayMechanism', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
t.assert.throws(() => build({
|
||||
title: 'large array of null values with default mechanism',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: { type: 'null' }
|
||||
}
|
||||
}
|
||||
}, {
|
||||
largeArraySize: 2e4,
|
||||
largeArrayMechanism: 'invalid'
|
||||
}), Error('Unsupported large array mechanism invalid'))
|
||||
})
|
||||
|
||||
function buildTest (schema, toStringify, options) {
|
||||
test(`render a ${schema.title} as JSON`, (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema, options)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.deepStrictEqual(JSON.parse(output), JSON.parse(JSON.stringify(toStringify)))
|
||||
t.assert.equal(output, JSON.stringify(toStringify))
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
}
|
||||
|
||||
buildTest({
|
||||
title: 'dates tuple',
|
||||
type: 'object',
|
||||
properties: {
|
||||
dates: {
|
||||
type: 'array',
|
||||
minItems: 2,
|
||||
maxItems: 2,
|
||||
items: [
|
||||
{
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}, {
|
||||
dates: [new Date(1), new Date(2)]
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'string array',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
ids: ['test']
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'number array',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
ids: [1]
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'mixed array',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: [
|
||||
{
|
||||
type: 'null'
|
||||
},
|
||||
{
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
type: 'integer'
|
||||
},
|
||||
{
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
type: 'boolean'
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}, {
|
||||
ids: [null, 'test', 1, 1.1, true, { a: 'test' }, ['test']]
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'repeated types',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: [
|
||||
{
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
type: 'number'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}, { ids: [1, 2] })
|
||||
|
||||
buildTest({
|
||||
title: 'pattern properties array',
|
||||
type: 'object',
|
||||
properties: {
|
||||
args: {
|
||||
type: 'array',
|
||||
items: [
|
||||
{
|
||||
type: 'object',
|
||||
patternProperties: {
|
||||
'.*': {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
patternProperties: {
|
||||
'.*': {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}, { args: [{ a: 'test' }, { b: 1 }] })
|
||||
|
||||
buildTest({
|
||||
title: 'array with weird key',
|
||||
type: 'object',
|
||||
properties: {
|
||||
'@data': {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
'@data': ['test']
|
||||
})
|
||||
|
||||
test('invalid items throw', (t) => {
|
||||
t.plan(1)
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
args: {
|
||||
type: 'array',
|
||||
items: [
|
||||
{
|
||||
type: 'object',
|
||||
patternProperties: {
|
||||
'.*': {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
t.assert.throws(() => stringify({ args: ['invalid'] }))
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'item types in array default to any',
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'array'
|
||||
}
|
||||
}
|
||||
}, {
|
||||
foo: [1, 'string', {}, null]
|
||||
})
|
||||
|
||||
test('array items is a list of schema and additionalItems is true, just the described item is validated', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'array',
|
||||
items: [
|
||||
{
|
||||
type: 'string'
|
||||
}
|
||||
],
|
||||
additionalItems: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const result = stringify({
|
||||
foo: [
|
||||
'foo',
|
||||
'bar',
|
||||
1
|
||||
]
|
||||
})
|
||||
|
||||
t.assert.equal(result, '{"foo":["foo","bar",1]}')
|
||||
})
|
||||
|
||||
test('array items is a list of schema and additionalItems is true, just the described item is validated', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'array',
|
||||
items: [
|
||||
{
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
type: 'number'
|
||||
}
|
||||
],
|
||||
additionalItems: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const result = stringify({
|
||||
foo: ['foo']
|
||||
})
|
||||
|
||||
t.assert.equal(result, '{"foo":["foo"]}')
|
||||
})
|
||||
|
||||
test('array items is a list of schema and additionalItems is false /1', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'array',
|
||||
items: [
|
||||
{ type: 'string' }
|
||||
],
|
||||
additionalItems: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
t.assert.throws(() => stringify({ foo: ['foo', 'bar'] }), new Error('Item at 1 does not match schema definition.'))
|
||||
})
|
||||
|
||||
test('array items is a list of schema and additionalItems is false /2', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'array',
|
||||
items: [
|
||||
{ type: 'string' },
|
||||
{ type: 'string' }
|
||||
],
|
||||
additionalItems: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.throws(() => stringify({ foo: [1, 'bar'] }), new Error('Item at 0 does not match schema definition.'))
|
||||
t.assert.throws(() => stringify({ foo: ['foo', 1] }), new Error('Item at 1 does not match schema definition.'))
|
||||
t.assert.throws(() => stringify({ foo: ['foo', 'bar', 'baz'] }), new Error('Item at 2 does not match schema definition.'))
|
||||
})
|
||||
|
||||
test('array items is a schema and additionalItems is false', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
additionalItems: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
// ajv ignores additionalItems if items is not an Array
|
||||
const ajv = new Ajv({ allErrors: true, strict: false })
|
||||
|
||||
const validate = ajv.compile(schema)
|
||||
t.assert.equal(stringify({ foo: ['foo', 'bar'] }), '{"foo":["foo","bar"]}')
|
||||
t.assert.equal(validate({ foo: ['foo', 'bar'] }), true)
|
||||
})
|
||||
|
||||
// https://github.com/fastify/fast-json-stringify/issues/279
|
||||
test('object array with anyOf and symbol', (t) => {
|
||||
t.plan(1)
|
||||
const ArrayKind = Symbol('ArrayKind')
|
||||
const ObjectKind = Symbol('LiteralKind')
|
||||
const UnionKind = Symbol('UnionKind')
|
||||
const LiteralKind = Symbol('LiteralKind')
|
||||
const StringKind = Symbol('StringKind')
|
||||
|
||||
const schema = {
|
||||
kind: ArrayKind,
|
||||
type: 'array',
|
||||
items: {
|
||||
kind: ObjectKind,
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
kind: StringKind,
|
||||
type: 'string'
|
||||
},
|
||||
option: {
|
||||
kind: UnionKind,
|
||||
anyOf: [
|
||||
{
|
||||
kind: LiteralKind,
|
||||
type: 'string',
|
||||
enum: ['Foo']
|
||||
},
|
||||
{
|
||||
kind: LiteralKind,
|
||||
type: 'string',
|
||||
enum: ['Bar']
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
required: ['name', 'option']
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
const value = stringify([
|
||||
{ name: 'name-0', option: 'Foo' },
|
||||
{ name: 'name-1', option: 'Bar' }
|
||||
])
|
||||
t.assert.equal(value, '[{"name":"name-0","option":"Foo"},{"name":"name-1","option":"Bar"}]')
|
||||
})
|
||||
|
||||
test('different arrays with same item schemas', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
array1: {
|
||||
type: 'array',
|
||||
items: [{ type: 'string' }],
|
||||
additionalItems: false
|
||||
},
|
||||
array2: {
|
||||
type: 'array',
|
||||
items: { $ref: '#/properties/array1/items' },
|
||||
additionalItems: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const data = { array1: ['bar'], array2: ['foo', 'bar'] }
|
||||
|
||||
t.assert.equal(stringify(data), '{"array1":["bar"],"array2":["foo","bar"]}')
|
||||
})
|
||||
|
||||
const largeArray = new Array(2e4).fill({ a: 'test', b: 1 })
|
||||
buildTest({
|
||||
title: 'large array with default mechanism',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: { type: 'string' },
|
||||
b: { type: 'number' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
ids: largeArray
|
||||
}, {
|
||||
largeArraySize: 2e4,
|
||||
largeArrayMechanism: 'default'
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'large array of objects with json-stringify mechanism',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: { type: 'string' },
|
||||
b: { type: 'number' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
ids: largeArray
|
||||
}, {
|
||||
largeArrayMechanism: 'json-stringify'
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'large array of strings with default mechanism',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}, {
|
||||
ids: new Array(2e4).fill('string')
|
||||
}, {
|
||||
largeArraySize: 2e4,
|
||||
largeArrayMechanism: 'default'
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'large array of numbers with default mechanism',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: { type: 'number' }
|
||||
}
|
||||
}
|
||||
}, {
|
||||
ids: new Array(2e4).fill(42)
|
||||
}, {
|
||||
largeArraySize: 2e4,
|
||||
largeArrayMechanism: 'default'
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'large array of integers with default mechanism',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: { type: 'integer' }
|
||||
}
|
||||
}
|
||||
}, {
|
||||
ids: new Array(2e4).fill(42)
|
||||
}, {
|
||||
largeArraySize: 2e4,
|
||||
largeArrayMechanism: 'default'
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'large array of booleans with default mechanism',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: { type: 'boolean' }
|
||||
}
|
||||
}
|
||||
}, {
|
||||
ids: new Array(2e4).fill(true)
|
||||
}, {
|
||||
largeArraySize: 2e4,
|
||||
largeArrayMechanism: 'default'
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'large array of null values with default mechanism',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: { type: 'null' }
|
||||
}
|
||||
}
|
||||
}, {
|
||||
ids: new Array(2e4).fill(null)
|
||||
}, {
|
||||
largeArraySize: 2e4,
|
||||
largeArrayMechanism: 'default'
|
||||
})
|
||||
|
||||
test('error on invalid value for largeArraySize /1', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
t.assert.throws(() => build({
|
||||
title: 'large array of null values with default mechanism',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: { type: 'null' }
|
||||
}
|
||||
}
|
||||
}, {
|
||||
largeArraySize: 'invalid'
|
||||
}), Error('Unsupported large array size. Expected integer-like, got string with value invalid'))
|
||||
})
|
||||
|
||||
test('error on invalid value for largeArraySize /2', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
t.assert.throws(() => build({
|
||||
title: 'large array of null values with default mechanism',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: { type: 'null' }
|
||||
}
|
||||
}
|
||||
}, {
|
||||
largeArraySize: Infinity
|
||||
}), Error('Unsupported large array size. Expected integer-like, got number with value Infinity'))
|
||||
})
|
||||
|
||||
test('error on invalid value for largeArraySize /3', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
t.assert.throws(() => build({
|
||||
title: 'large array of null values with default mechanism',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: { type: 'null' }
|
||||
}
|
||||
}
|
||||
}, {
|
||||
largeArraySize: [200]
|
||||
}), Error('Unsupported large array size. Expected integer-like, got object with value 200'))
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'large array of integers with largeArraySize is bigint',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: { type: 'integer' }
|
||||
}
|
||||
}
|
||||
}, {
|
||||
ids: new Array(2e4).fill(42)
|
||||
}, {
|
||||
largeArraySize: 20000n,
|
||||
largeArrayMechanism: 'default'
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'large array of integers with largeArraySize is valid string',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: { type: 'integer' }
|
||||
}
|
||||
}
|
||||
}, {
|
||||
ids: new Array(1e4).fill(42)
|
||||
}, {
|
||||
largeArraySize: '10000',
|
||||
largeArrayMechanism: 'default'
|
||||
})
|
||||
13
node_modules/fast-json-stringify/test/asNumber.test.js
generated
vendored
Normal file
13
node_modules/fast-json-stringify/test/asNumber.test.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
|
||||
test('asNumber should convert BigInt', (t) => {
|
||||
t.plan(1)
|
||||
const Serializer = require('../lib/serializer')
|
||||
const serializer = new Serializer()
|
||||
|
||||
const number = serializer.asNumber(11753021440n)
|
||||
|
||||
t.assert.equal(number, '11753021440')
|
||||
})
|
||||
400
node_modules/fast-json-stringify/test/basic.test.js
generated
vendored
Normal file
400
node_modules/fast-json-stringify/test/basic.test.js
generated
vendored
Normal file
@@ -0,0 +1,400 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const validator = require('is-my-json-valid')
|
||||
const build = require('..')
|
||||
|
||||
function buildTest (schema, toStringify) {
|
||||
test(`render a ${schema.title} as JSON`, (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.deepStrictEqual(JSON.parse(output), toStringify)
|
||||
t.assert.equal(output, JSON.stringify(toStringify))
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
}
|
||||
|
||||
buildTest({
|
||||
title: 'string',
|
||||
type: 'string',
|
||||
format: 'unsafe'
|
||||
}, 'hello world')
|
||||
|
||||
buildTest({
|
||||
title: 'basic',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: 'string'
|
||||
},
|
||||
age: {
|
||||
description: 'Age in years',
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
},
|
||||
magic: {
|
||||
type: 'number'
|
||||
}
|
||||
},
|
||||
required: ['firstName', 'lastName']
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32,
|
||||
magic: 42.42
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'string',
|
||||
type: 'string'
|
||||
}, 'hello world')
|
||||
|
||||
buildTest({
|
||||
title: 'string',
|
||||
type: 'string'
|
||||
}, 'hello\nworld')
|
||||
|
||||
buildTest({
|
||||
title: 'string with quotes',
|
||||
type: 'string'
|
||||
}, 'hello """" world')
|
||||
|
||||
buildTest({
|
||||
title: 'boolean true',
|
||||
type: 'boolean'
|
||||
}, true)
|
||||
|
||||
buildTest({
|
||||
title: 'boolean false',
|
||||
type: 'boolean'
|
||||
}, false)
|
||||
|
||||
buildTest({
|
||||
title: 'an integer',
|
||||
type: 'integer'
|
||||
}, 42)
|
||||
|
||||
buildTest({
|
||||
title: 'a number',
|
||||
type: 'number'
|
||||
}, 42.42)
|
||||
|
||||
buildTest({
|
||||
title: 'deep',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: 'string'
|
||||
},
|
||||
more: {
|
||||
description: 'more properties',
|
||||
type: 'object',
|
||||
properties: {
|
||||
something: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
more: {
|
||||
something: 'else'
|
||||
}
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'null',
|
||||
type: 'null'
|
||||
}, null)
|
||||
|
||||
buildTest({
|
||||
title: 'deep object with weird keys',
|
||||
type: 'object',
|
||||
properties: {
|
||||
'@version': {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}, {
|
||||
'@version': 1
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'deep object with weird keys of type object',
|
||||
type: 'object',
|
||||
properties: {
|
||||
'@data': {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
'@data': {
|
||||
id: 'string'
|
||||
}
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'deep object with spaces in key',
|
||||
type: 'object',
|
||||
properties: {
|
||||
'spaces in key': {
|
||||
type: 'object',
|
||||
properties: {
|
||||
something: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
'spaces in key': {
|
||||
something: 1
|
||||
}
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'with null',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'null'
|
||||
}
|
||||
}
|
||||
}, {
|
||||
firstName: null
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'array with objects',
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [{
|
||||
name: 'Matteo'
|
||||
}, {
|
||||
name: 'Dave'
|
||||
}])
|
||||
|
||||
buildTest({
|
||||
title: 'array with strings',
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
}, [
|
||||
'Matteo',
|
||||
'Dave'
|
||||
])
|
||||
|
||||
buildTest({
|
||||
title: 'array with numbers',
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'number'
|
||||
}
|
||||
}, [
|
||||
42.42,
|
||||
24
|
||||
])
|
||||
|
||||
buildTest({
|
||||
title: 'array with integers',
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'number'
|
||||
}
|
||||
}, [
|
||||
42,
|
||||
24
|
||||
])
|
||||
|
||||
buildTest({
|
||||
title: 'nested array with objects',
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
data: [{
|
||||
name: 'Matteo'
|
||||
}, {
|
||||
name: 'Dave'
|
||||
}]
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'object with boolean',
|
||||
type: 'object',
|
||||
properties: {
|
||||
readonly: {
|
||||
type: 'boolean'
|
||||
}
|
||||
}
|
||||
}, {
|
||||
readonly: true
|
||||
})
|
||||
|
||||
test('throw an error or coerce numbers and integers that are not numbers', (t) => {
|
||||
const stringify = build({
|
||||
title: 'basic',
|
||||
type: 'object',
|
||||
properties: {
|
||||
age: {
|
||||
type: 'number'
|
||||
},
|
||||
distance: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.assert.throws(() => {
|
||||
stringify({ age: 'hello ', distance: 'long' })
|
||||
}, { message: 'The value "hello " cannot be converted to a number.' })
|
||||
|
||||
const result = stringify({
|
||||
age: '42',
|
||||
distance: true
|
||||
})
|
||||
|
||||
t.assert.deepStrictEqual(JSON.parse(result), { age: 42, distance: 1 })
|
||||
})
|
||||
|
||||
test('Should throw on invalid schema', t => {
|
||||
t.plan(1)
|
||||
t.assert.throws(() => {
|
||||
build({
|
||||
type: 'Dinosaur',
|
||||
properties: {
|
||||
claws: { type: 'sharp' }
|
||||
}
|
||||
})
|
||||
}, { message: 'schema is invalid: data/properties/claws/type must be equal to one of the allowed values' })
|
||||
})
|
||||
|
||||
test('additionalProperties - throw on unknown type', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
t.assert.throws(() => {
|
||||
build({
|
||||
title: 'check array coerce',
|
||||
type: 'object',
|
||||
properties: {},
|
||||
additionalProperties: {
|
||||
type: 'strangetype'
|
||||
}
|
||||
})
|
||||
t.fail('should be an invalid schema')
|
||||
}, { message: 'schema is invalid: data/additionalProperties/type must be equal to one of the allowed values' })
|
||||
})
|
||||
|
||||
test('patternProperties - throw on unknown type', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
t.assert.throws(() => {
|
||||
build({
|
||||
title: 'check array coerce',
|
||||
type: 'object',
|
||||
properties: {},
|
||||
patternProperties: {
|
||||
foo: {
|
||||
type: 'strangetype'
|
||||
}
|
||||
}
|
||||
})
|
||||
}, { message: 'schema is invalid: data/patternProperties/foo/type must be equal to one of the allowed values' })
|
||||
})
|
||||
|
||||
test('render a double quote as JSON /1', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'string'
|
||||
}
|
||||
const toStringify = '" double quote'
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.equal(output, JSON.stringify(toStringify))
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('render a double quote as JSON /2', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'string'
|
||||
}
|
||||
const toStringify = 'double quote " 2'
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.equal(output, JSON.stringify(toStringify))
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('render a long string', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'string'
|
||||
}
|
||||
const toStringify = 'the Ultimate Question of Life, the Universe, and Everything.'
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.equal(output, JSON.stringify(toStringify))
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('returns JSON.stringify if schema type is boolean', t => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
type: 'array',
|
||||
items: true
|
||||
}
|
||||
|
||||
const array = [1, true, 'test']
|
||||
const stringify = build(schema)
|
||||
t.assert.equal(stringify(array), JSON.stringify(array))
|
||||
})
|
||||
76
node_modules/fast-json-stringify/test/bigint.test.js
generated
vendored
Normal file
76
node_modules/fast-json-stringify/test/bigint.test.js
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
|
||||
const build = require('..')
|
||||
|
||||
test('render a bigint as JSON', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'bigint',
|
||||
type: 'integer'
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const output = stringify(1615n)
|
||||
|
||||
t.assert.equal(output, '1615')
|
||||
})
|
||||
|
||||
test('render an object with a bigint as JSON', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'object with bigint',
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
id: 1615n
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"id":1615}')
|
||||
})
|
||||
|
||||
test('render an array with a bigint as JSON', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'array with bigint',
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const output = stringify([1615n])
|
||||
|
||||
t.assert.equal(output, '[1615]')
|
||||
})
|
||||
|
||||
test('render an object with an additionalProperty of type bigint as JSON', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'object with bigint',
|
||||
type: 'object',
|
||||
additionalProperties: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
num: 1615n
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"num":1615}')
|
||||
})
|
||||
47
node_modules/fast-json-stringify/test/clean-cache.test.js
generated
vendored
Normal file
47
node_modules/fast-json-stringify/test/clean-cache.test.js
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('Should clean the cache', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
$id: 'test',
|
||||
type: 'string'
|
||||
}
|
||||
|
||||
t.assert.doesNotThrow(() => {
|
||||
build(schema)
|
||||
build(schema)
|
||||
})
|
||||
})
|
||||
|
||||
test('Should clean the cache with external schemas', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
$id: 'test',
|
||||
definitions: {
|
||||
def: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
type: 'object',
|
||||
properties: {
|
||||
obj: {
|
||||
$ref: '#/definitions/def'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t.assert.doesNotThrow(() => {
|
||||
build(schema)
|
||||
build(schema)
|
||||
})
|
||||
})
|
||||
314
node_modules/fast-json-stringify/test/const.test.js
generated
vendored
Normal file
314
node_modules/fast-json-stringify/test/const.test.js
generated
vendored
Normal file
@@ -0,0 +1,314 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const validator = require('is-my-json-valid')
|
||||
const build = require('..')
|
||||
|
||||
test('schema with const string', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { const: 'bar' }
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
foo: 'bar'
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"foo":"bar"}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('schema with const string and different input', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { const: 'bar' }
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
foo: 'baz'
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"foo":"bar"}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('schema with const string and different type input', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { const: 'bar' }
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
foo: 1
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"foo":"bar"}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('schema with const string and no input', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { const: 'bar' }
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({})
|
||||
|
||||
t.assert.equal(output, '{}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('schema with const string that contains \'', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { const: "'bar'" }
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
foo: "'bar'"
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"foo":"\'bar\'"}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('schema with const number', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { const: 1 }
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
foo: 1
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"foo":1}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('schema with const number and different input', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { const: 1 }
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
foo: 2
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"foo":1}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('schema with const bool', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { const: true }
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
foo: true
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"foo":true}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('schema with const number', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { const: 1 }
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
foo: 1
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"foo":1}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('schema with const null', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { const: null }
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
foo: null
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"foo":null}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('schema with const array', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { const: [1, 2, 3] }
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
foo: [1, 2, 3]
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"foo":[1,2,3]}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('schema with const object', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { const: { bar: 'baz' } }
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
foo: { bar: 'baz' }
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"foo":{"bar":"baz"}}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('schema with const and null as type', (t) => {
|
||||
t.plan(4)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: ['string', 'null'], const: 'baz' }
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
foo: null
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"foo":null}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
|
||||
const output2 = stringify({ foo: 'baz' })
|
||||
t.assert.equal(output2, '{"foo":"baz"}')
|
||||
t.assert.ok(validate(JSON.parse(output2)), 'valid schema')
|
||||
})
|
||||
|
||||
test('schema with const as nullable', (t) => {
|
||||
t.plan(4)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { nullable: true, const: 'baz' }
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
foo: null
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"foo":null}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
|
||||
const output2 = stringify({
|
||||
foo: 'baz'
|
||||
})
|
||||
t.assert.equal(output2, '{"foo":"baz"}')
|
||||
t.assert.ok(validate(JSON.parse(output2)), 'valid schema')
|
||||
})
|
||||
|
||||
test('schema with const and invalid object', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { const: { foo: 'bar' } }
|
||||
},
|
||||
required: ['foo']
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const result = stringify({
|
||||
foo: { foo: 'baz' }
|
||||
})
|
||||
|
||||
t.assert.equal(result, '{"foo":{"foo":"bar"}}')
|
||||
t.assert.ok(validate(JSON.parse(result)), 'valid schema')
|
||||
})
|
||||
639
node_modules/fast-json-stringify/test/date.test.js
generated
vendored
Normal file
639
node_modules/fast-json-stringify/test/date.test.js
generated
vendored
Normal file
@@ -0,0 +1,639 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const validator = require('is-my-json-valid')
|
||||
const build = require('..')
|
||||
|
||||
process.env.TZ = 'UTC'
|
||||
|
||||
test('render a date in a string as JSON', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'a date in a string',
|
||||
type: 'string'
|
||||
}
|
||||
const toStringify = new Date(1674263005800)
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.equal(output, JSON.stringify(toStringify))
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('render a date in a string when format is date-format as ISOString', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'a date in a string',
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
}
|
||||
const toStringify = new Date(1674263005800)
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.equal(output, JSON.stringify(toStringify))
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('render a nullable date in a string when format is date-format as ISOString', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'a date in a string',
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
nullable: true
|
||||
}
|
||||
const toStringify = new Date(1674263005800)
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.equal(output, JSON.stringify(toStringify))
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('render a date in a string when format is date as YYYY-MM-DD', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'a date in a string',
|
||||
type: 'string',
|
||||
format: 'date'
|
||||
}
|
||||
const toStringify = new Date(1674263005800)
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.equal(output, '"2023-01-21"')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('render a nullable date in a string when format is date as YYYY-MM-DD', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'a date in a string',
|
||||
type: 'string',
|
||||
format: 'date',
|
||||
nullable: true
|
||||
}
|
||||
const toStringify = new Date(1674263005800)
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.equal(output, '"2023-01-21"')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('verify padding for rendered date in a string when format is date', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'a date in a string',
|
||||
type: 'string',
|
||||
format: 'date'
|
||||
}
|
||||
const toStringify = new Date(2020, 0, 1, 0, 0, 0, 0)
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.equal(output, '"2020-01-01"')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('render a date in a string when format is time as kk:mm:ss', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const schema = {
|
||||
title: 'a date in a string',
|
||||
type: 'string',
|
||||
format: 'time'
|
||||
}
|
||||
const toStringify = new Date(1674263005800)
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
validate(JSON.parse(output))
|
||||
t.assert.equal(validate.errors, null)
|
||||
|
||||
t.assert.equal(output, '"01:03:25"')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('render a nullable date in a string when format is time as kk:mm:ss', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const schema = {
|
||||
title: 'a date in a string',
|
||||
type: 'string',
|
||||
format: 'time',
|
||||
nullable: true
|
||||
}
|
||||
const toStringify = new Date(1674263005800)
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
validate(JSON.parse(output))
|
||||
t.assert.equal(validate.errors, null)
|
||||
|
||||
t.assert.equal(output, '"01:03:25"')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('render a midnight time', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const schema = {
|
||||
title: 'a date in a string',
|
||||
type: 'string',
|
||||
format: 'time'
|
||||
}
|
||||
const midnight = new Date(new Date(1674263005800).setHours(24))
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(midnight)
|
||||
|
||||
validate(JSON.parse(output))
|
||||
t.assert.equal(validate.errors, null)
|
||||
|
||||
t.assert.equal(output, '"00:03:25"')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('verify padding for rendered date in a string when format is time', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const schema = {
|
||||
title: 'a date in a string',
|
||||
type: 'string',
|
||||
format: 'time'
|
||||
}
|
||||
const toStringify = new Date(2020, 0, 1, 1, 1, 1, 1)
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
validate(JSON.parse(output))
|
||||
t.assert.equal(validate.errors, null)
|
||||
|
||||
t.assert.equal(output, '"01:01:01"')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('render a nested object in a string when type is date-format as ISOString', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'an object in a string',
|
||||
type: 'object',
|
||||
properties: {
|
||||
date: {
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
}
|
||||
}
|
||||
}
|
||||
const toStringify = { date: new Date(1674263005800) }
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.equal(output, JSON.stringify(toStringify))
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('serializing null value', async t => {
|
||||
const input = { updatedAt: null }
|
||||
|
||||
function createSchema (properties) {
|
||||
return {
|
||||
title: 'an object in a string',
|
||||
type: 'object',
|
||||
properties
|
||||
}
|
||||
}
|
||||
|
||||
function serialize (schema, input) {
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(input)
|
||||
|
||||
return {
|
||||
validate,
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
t.plan(3)
|
||||
|
||||
await t.test('type::string', async t => {
|
||||
t.plan(3)
|
||||
|
||||
await t.test('format::date-time', t => {
|
||||
t.plan(2)
|
||||
|
||||
const prop = {
|
||||
updatedAt: {
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
output,
|
||||
validate
|
||||
} = serialize(createSchema(prop), input)
|
||||
|
||||
t.assert.equal(output, '{"updatedAt":""}')
|
||||
t.assert.equal(validate(JSON.parse(output)), false, 'an empty string is not a date-time format')
|
||||
})
|
||||
|
||||
await t.test('format::date', t => {
|
||||
t.plan(2)
|
||||
|
||||
const prop = {
|
||||
updatedAt: {
|
||||
type: 'string',
|
||||
format: 'date'
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
output,
|
||||
validate
|
||||
} = serialize(createSchema(prop), input)
|
||||
|
||||
t.assert.equal(output, '{"updatedAt":""}')
|
||||
t.assert.equal(validate(JSON.parse(output)), false, 'an empty string is not a date format')
|
||||
})
|
||||
|
||||
await t.test('format::time', t => {
|
||||
t.plan(2)
|
||||
|
||||
const prop = {
|
||||
updatedAt: {
|
||||
type: 'string',
|
||||
format: 'time'
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
output,
|
||||
validate
|
||||
} = serialize(createSchema(prop), input)
|
||||
|
||||
t.assert.equal(output, '{"updatedAt":""}')
|
||||
t.assert.equal(validate(JSON.parse(output)), false, 'an empty string is not a time format')
|
||||
})
|
||||
})
|
||||
|
||||
await t.test('type::array', async t => {
|
||||
t.plan(6)
|
||||
|
||||
await t.test('format::date-time', t => {
|
||||
t.plan(2)
|
||||
|
||||
const prop = {
|
||||
updatedAt: {
|
||||
type: ['string'],
|
||||
format: 'date-time'
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
output,
|
||||
validate
|
||||
} = serialize(createSchema(prop), input)
|
||||
|
||||
t.assert.equal(output, '{"updatedAt":""}')
|
||||
t.assert.equal(validate(JSON.parse(output)), false, 'an empty string is not a date-time format')
|
||||
})
|
||||
|
||||
await t.test('format::date', t => {
|
||||
t.plan(2)
|
||||
|
||||
const prop = {
|
||||
updatedAt: {
|
||||
type: ['string'],
|
||||
format: 'date'
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
output,
|
||||
validate
|
||||
} = serialize(createSchema(prop), input)
|
||||
|
||||
t.assert.equal(output, '{"updatedAt":""}')
|
||||
t.assert.equal(validate(JSON.parse(output)), false, 'an empty string is not a date format')
|
||||
})
|
||||
|
||||
await t.test('format::date', t => {
|
||||
t.plan(2)
|
||||
|
||||
const prop = {
|
||||
updatedAt: {
|
||||
type: ['string'],
|
||||
format: 'date'
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
output,
|
||||
validate
|
||||
} = serialize(createSchema(prop), input)
|
||||
|
||||
t.assert.equal(output, '{"updatedAt":""}')
|
||||
t.assert.equal(validate(JSON.parse(output)), false, 'an empty string is not a date format')
|
||||
})
|
||||
|
||||
await t.test('format::time, Date object', t => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
updatedAt: {
|
||||
type: ['string', 'number'],
|
||||
format: 'time'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const date = new Date(1674263005800)
|
||||
const input = { updatedAt: date }
|
||||
const { output } = serialize(schema, input)
|
||||
|
||||
t.assert.equal(output, JSON.stringify({ updatedAt: '01:03:25' }))
|
||||
})
|
||||
|
||||
await t.test('format::time, Date object', t => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
oneOf: [
|
||||
{
|
||||
type: ['string', 'number'],
|
||||
format: 'time'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const date = new Date(1674263005800)
|
||||
const { output } = serialize(schema, date)
|
||||
|
||||
t.assert.equal(output, '"01:03:25"')
|
||||
})
|
||||
|
||||
await t.test('format::time, Date object', t => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
oneOf: [
|
||||
{
|
||||
type: ['string', 'number'],
|
||||
format: 'time'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const { output } = serialize(schema, 42)
|
||||
|
||||
t.assert.equal(output, JSON.stringify(42))
|
||||
})
|
||||
})
|
||||
|
||||
await t.test('type::array::nullable', async t => {
|
||||
t.plan(3)
|
||||
|
||||
await t.test('format::date-time', t => {
|
||||
t.plan(2)
|
||||
|
||||
const prop = {
|
||||
updatedAt: {
|
||||
type: ['string', 'null'],
|
||||
format: 'date-time'
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
output,
|
||||
validate
|
||||
} = serialize(createSchema(prop), input)
|
||||
|
||||
t.assert.equal(output, '{"updatedAt":null}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
await t.test('format::date', t => {
|
||||
t.plan(2)
|
||||
|
||||
const prop = {
|
||||
updatedAt: {
|
||||
type: ['string', 'null'],
|
||||
format: 'date'
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
output,
|
||||
validate
|
||||
} = serialize(createSchema(prop), input)
|
||||
|
||||
t.assert.equal(output, '{"updatedAt":null}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
await t.test('format::time', t => {
|
||||
t.plan(2)
|
||||
|
||||
const prop = {
|
||||
updatedAt: {
|
||||
type: ['string', 'null'],
|
||||
format: 'time'
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
output,
|
||||
validate
|
||||
} = serialize(createSchema(prop), input)
|
||||
|
||||
t.assert.equal(output, '{"updatedAt":null}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Validate Date object as string type', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
oneOf: [
|
||||
{ type: 'string' }
|
||||
]
|
||||
}
|
||||
const toStringify = new Date(1674263005800)
|
||||
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.equal(output, JSON.stringify(toStringify))
|
||||
})
|
||||
|
||||
test('nullable date', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
anyOf: [
|
||||
{
|
||||
format: 'date',
|
||||
type: 'string',
|
||||
nullable: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
const data = new Date(1674263005800)
|
||||
const result = stringify(data)
|
||||
|
||||
t.assert.equal(result, '"2023-01-21"')
|
||||
})
|
||||
|
||||
test('non-date format should not affect data serialization (issue #491)', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'string',
|
||||
format: 'int64',
|
||||
pattern: '^[0-9]*$'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const data = { hello: 123n }
|
||||
t.assert.equal(stringify(data), '{"hello":"123"}')
|
||||
})
|
||||
|
||||
test('should serialize also an invalid string value, even if it is not a valid date', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'a date in a string',
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
nullable: true
|
||||
}
|
||||
const toStringify = 'invalid'
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.equal(output, JSON.stringify(toStringify))
|
||||
t.assert.equal(validate(JSON.parse(output)), false, 'valid schema')
|
||||
})
|
||||
|
||||
test('should throw an error if value can not be transformed to date-time', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'a date in a string',
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
nullable: true
|
||||
}
|
||||
const toStringify = true
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.throws(() => stringify(toStringify), new Error('The value "true" cannot be converted to a date-time.'))
|
||||
t.assert.equal(validate(toStringify), false)
|
||||
})
|
||||
|
||||
test('should throw an error if value can not be transformed to date', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'a date in a string',
|
||||
type: 'string',
|
||||
format: 'date',
|
||||
nullable: true
|
||||
}
|
||||
const toStringify = true
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.throws(() => stringify(toStringify), new Error('The value "true" cannot be converted to a date.'))
|
||||
t.assert.equal(validate(toStringify), false)
|
||||
})
|
||||
|
||||
test('should throw an error if value can not be transformed to time', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'a time in a string',
|
||||
type: 'string',
|
||||
format: 'time',
|
||||
nullable: true
|
||||
}
|
||||
const toStringify = true
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.throws(() => stringify(toStringify), new Error('The value "true" cannot be converted to a time.'))
|
||||
t.assert.equal(validate(toStringify), false)
|
||||
})
|
||||
|
||||
test('should serialize also an invalid string value, even if it is not a valid time', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'a time in a string',
|
||||
type: 'string',
|
||||
format: 'time',
|
||||
nullable: true
|
||||
}
|
||||
const toStringify = 'invalid'
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.equal(output, JSON.stringify(toStringify))
|
||||
t.assert.equal(validate(JSON.parse(output)), false, 'valid schema')
|
||||
})
|
||||
121
node_modules/fast-json-stringify/test/debug-mode.test.js
generated
vendored
Normal file
121
node_modules/fast-json-stringify/test/debug-mode.test.js
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const fjs = require('..')
|
||||
|
||||
const Ajv = require('ajv').default
|
||||
const Validator = require('../lib/validator')
|
||||
const Serializer = require('../lib/serializer')
|
||||
|
||||
function build (opts) {
|
||||
return fjs({
|
||||
title: 'default string',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
required: ['firstName']
|
||||
}, opts)
|
||||
}
|
||||
|
||||
test('activate debug mode', t => {
|
||||
t.plan(5)
|
||||
const debugMode = build({ debugMode: true })
|
||||
|
||||
t.assert.ok(typeof debugMode === 'object')
|
||||
t.assert.ok(debugMode.ajv instanceof Ajv)
|
||||
t.assert.ok(debugMode.validator instanceof Validator)
|
||||
t.assert.ok(debugMode.serializer instanceof Serializer)
|
||||
t.assert.ok(typeof debugMode.code === 'string')
|
||||
})
|
||||
|
||||
test('activate debug mode truthy', t => {
|
||||
t.plan(5)
|
||||
|
||||
const debugMode = build({ debugMode: 'yes' })
|
||||
|
||||
t.assert.ok(typeof debugMode === 'object')
|
||||
t.assert.ok(typeof debugMode.code === 'string')
|
||||
t.assert.ok(debugMode.ajv instanceof Ajv)
|
||||
t.assert.ok(debugMode.validator instanceof Validator)
|
||||
t.assert.ok(debugMode.serializer instanceof Serializer)
|
||||
})
|
||||
|
||||
test('to string auto-consistent', t => {
|
||||
t.plan(6)
|
||||
const debugMode = build({ debugMode: 1 })
|
||||
|
||||
t.assert.ok(typeof debugMode === 'object')
|
||||
t.assert.ok(typeof debugMode.code === 'string')
|
||||
t.assert.ok(debugMode.ajv instanceof Ajv)
|
||||
t.assert.ok(debugMode.serializer instanceof Serializer)
|
||||
t.assert.ok(debugMode.validator instanceof Validator)
|
||||
|
||||
const compiled = fjs.restore(debugMode)
|
||||
const tobe = JSON.stringify({ firstName: 'Foo' })
|
||||
t.assert.equal(compiled({ firstName: 'Foo', surname: 'bar' }), tobe, 'surname evicted')
|
||||
})
|
||||
|
||||
test('to string auto-consistent with ajv', t => {
|
||||
t.plan(6)
|
||||
|
||||
const debugMode = fjs({
|
||||
title: 'object with multiple types field',
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
anyOf: [{
|
||||
type: 'string'
|
||||
}, {
|
||||
type: 'boolean'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}, { debugMode: 1 })
|
||||
|
||||
t.assert.ok(typeof debugMode === 'object')
|
||||
t.assert.ok(typeof debugMode.code === 'string')
|
||||
t.assert.ok(debugMode.ajv instanceof Ajv)
|
||||
t.assert.ok(debugMode.validator instanceof Validator)
|
||||
t.assert.ok(debugMode.serializer instanceof Serializer)
|
||||
|
||||
const compiled = fjs.restore(debugMode)
|
||||
const tobe = JSON.stringify({ str: 'Foo' })
|
||||
t.assert.equal(compiled({ str: 'Foo', void: 'me' }), tobe)
|
||||
})
|
||||
|
||||
test('to string auto-consistent with ajv-formats', t => {
|
||||
t.plan(3)
|
||||
|
||||
const debugMode = fjs({
|
||||
title: 'object with multiple types field and format keyword',
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
anyOf: [{
|
||||
type: 'string',
|
||||
format: 'email'
|
||||
}, {
|
||||
type: 'boolean'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}, { debugMode: 1 })
|
||||
|
||||
t.assert.ok(typeof debugMode === 'object')
|
||||
|
||||
const compiled = fjs.restore(debugMode)
|
||||
const tobe = JSON.stringify({ str: 'foo@bar.com' })
|
||||
t.assert.equal(compiled({ str: 'foo@bar.com' }), tobe)
|
||||
t.assert.throws(() => compiled({ str: 'foo' }))
|
||||
})
|
||||
|
||||
test('debug should restore the same serializer instance', t => {
|
||||
t.plan(1)
|
||||
|
||||
const debugMode = fjs({ type: 'integer' }, { debugMode: 1, rounding: 'ceil' })
|
||||
const compiled = fjs.restore(debugMode)
|
||||
t.assert.equal(compiled(3.95), 4)
|
||||
})
|
||||
376
node_modules/fast-json-stringify/test/defaults.test.js
generated
vendored
Normal file
376
node_modules/fast-json-stringify/test/defaults.test.js
generated
vendored
Normal file
@@ -0,0 +1,376 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
function buildTest (schema, toStringify, expected) {
|
||||
test(`render a ${schema.title} with default as JSON`, (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.equal(output, JSON.stringify(expected))
|
||||
})
|
||||
}
|
||||
|
||||
buildTest({
|
||||
title: 'default string',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: 'string',
|
||||
default: 'Collina'
|
||||
},
|
||||
age: {
|
||||
description: 'Age in years',
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
},
|
||||
magic: {
|
||||
type: 'number'
|
||||
}
|
||||
},
|
||||
required: ['firstName', 'lastName']
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
magic: 42,
|
||||
age: 32
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32,
|
||||
magic: 42
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'default string with value',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: 'string',
|
||||
default: 'Collina'
|
||||
},
|
||||
age: {
|
||||
description: 'Age in years',
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
},
|
||||
magic: {
|
||||
type: 'number'
|
||||
}
|
||||
},
|
||||
required: ['firstName', 'lastName']
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'collina',
|
||||
magic: 42,
|
||||
age: 32
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'collina',
|
||||
age: 32,
|
||||
magic: 42
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'default number',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: 'string'
|
||||
},
|
||||
age: {
|
||||
description: 'Age in years',
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
},
|
||||
magic: {
|
||||
type: 'number',
|
||||
default: 42
|
||||
}
|
||||
},
|
||||
required: ['firstName', 'lastName']
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32,
|
||||
magic: 42
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'default number with value',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: 'string'
|
||||
},
|
||||
age: {
|
||||
description: 'Age in years',
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
},
|
||||
magic: {
|
||||
type: 'number',
|
||||
default: 42
|
||||
}
|
||||
},
|
||||
required: ['firstName', 'lastName']
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32,
|
||||
magic: 66
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32,
|
||||
magic: 66
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'default object',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: 'string'
|
||||
},
|
||||
age: {
|
||||
description: 'Age in years',
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
},
|
||||
otherProps: {
|
||||
type: 'object',
|
||||
default: { foo: 'bar' }
|
||||
}
|
||||
},
|
||||
required: ['firstName', 'lastName']
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32,
|
||||
otherProps: { foo: 'bar' }
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'default object with value',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: 'string'
|
||||
},
|
||||
age: {
|
||||
description: 'Age in years',
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
},
|
||||
otherProps: {
|
||||
type: 'object',
|
||||
additionalProperties: true,
|
||||
default: { foo: 'bar' }
|
||||
}
|
||||
},
|
||||
required: ['firstName', 'lastName']
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32,
|
||||
otherProps: { hello: 'world' }
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32,
|
||||
otherProps: { hello: 'world' }
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'default array',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: 'string'
|
||||
},
|
||||
age: {
|
||||
description: 'Age in years',
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
},
|
||||
otherProps: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
default: ['FOO']
|
||||
}
|
||||
},
|
||||
required: ['firstName', 'lastName']
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32,
|
||||
otherProps: ['FOO']
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'default array with value',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: 'string'
|
||||
},
|
||||
age: {
|
||||
description: 'Age in years',
|
||||
type: 'integer',
|
||||
minimum: 0
|
||||
},
|
||||
otherProps: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
default: ['FOO']
|
||||
}
|
||||
},
|
||||
required: ['firstName', 'lastName']
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32,
|
||||
otherProps: ['BAR']
|
||||
}, {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32,
|
||||
otherProps: ['BAR']
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'default deeper value',
|
||||
type: 'object',
|
||||
properties: {
|
||||
level1: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
level2: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
level3: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
level4: {
|
||||
type: 'object',
|
||||
default: { foo: 'bar' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
level1: { level2: { level3: { } } }
|
||||
}, {
|
||||
level1: { level2: { level3: { level4: { foo: 'bar' } } } }
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'default deeper value with value',
|
||||
type: 'object',
|
||||
properties: {
|
||||
level1: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
level2: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
level3: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
level4: {
|
||||
type: 'object',
|
||||
default: { foo: 'bar' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
level1: { level2: { level3: { level4: { } } } }
|
||||
}, {
|
||||
level1: { level2: { level3: { level4: { } } } }
|
||||
})
|
||||
|
||||
buildTest({
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string',
|
||||
default: 'foo'
|
||||
},
|
||||
dev: {
|
||||
type: 'boolean',
|
||||
default: false
|
||||
}
|
||||
},
|
||||
required: [
|
||||
'name', 'dev'
|
||||
]
|
||||
}, {}, { name: 'foo', dev: false })
|
||||
|
||||
buildTest({
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string',
|
||||
default: 'foo'
|
||||
},
|
||||
dev: {
|
||||
type: 'boolean'
|
||||
},
|
||||
job: {
|
||||
type: 'string',
|
||||
default: 'awesome'
|
||||
}
|
||||
},
|
||||
required: [
|
||||
'name', 'dev'
|
||||
]
|
||||
}, { dev: true }, { name: 'foo', dev: true, job: 'awesome' })
|
||||
37
node_modules/fast-json-stringify/test/enum.test.js
generated
vendored
Normal file
37
node_modules/fast-json-stringify/test/enum.test.js
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('use enum without type', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
order: {
|
||||
type: 'string',
|
||||
enum: ['asc', 'desc']
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { order: 'asc' }
|
||||
t.assert.equal('{"order":"asc"}', stringify(obj))
|
||||
})
|
||||
|
||||
test('use enum without type', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
order: {
|
||||
enum: ['asc', 'desc']
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { order: 'asc' }
|
||||
t.assert.equal('{"order":"asc"}', stringify(obj))
|
||||
})
|
||||
25
node_modules/fast-json-stringify/test/fix-604.test.js
generated
vendored
Normal file
25
node_modules/fast-json-stringify/test/fix-604.test.js
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const fjs = require('..')
|
||||
|
||||
test('fix-604', t => {
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
fullName: { type: 'string' },
|
||||
phone: { type: 'number' }
|
||||
}
|
||||
}
|
||||
|
||||
const input = {
|
||||
fullName: 'Jone',
|
||||
phone: 'phone'
|
||||
}
|
||||
|
||||
const render = fjs(schema)
|
||||
|
||||
t.assert.throws(() => {
|
||||
render(input)
|
||||
}, { message: 'The value "phone" cannot be converted to a number.' })
|
||||
})
|
||||
0
node_modules/fast-json-stringify/test/fixtures/.keep
generated
vendored
Normal file
0
node_modules/fast-json-stringify/test/fixtures/.keep
generated
vendored
Normal file
468
node_modules/fast-json-stringify/test/if-then-else.test.js
generated
vendored
Normal file
468
node_modules/fast-json-stringify/test/if-then-else.test.js
generated
vendored
Normal file
@@ -0,0 +1,468 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
process.env.TZ = 'UTC'
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
},
|
||||
if: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['foobar'] }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['foobar'] },
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'number' },
|
||||
list: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
value: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
else: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['greeting'] },
|
||||
hi: { type: 'string' },
|
||||
hello: { type: 'number' },
|
||||
list: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
value: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const nestedIfSchema = {
|
||||
type: 'object',
|
||||
properties: { },
|
||||
if: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['foobar', 'greeting'] }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
if: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['foobar'] }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['foobar'] },
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'number' },
|
||||
list: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
value: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
else: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['greeting'] },
|
||||
hi: { type: 'string' },
|
||||
hello: { type: 'number' }
|
||||
}
|
||||
}
|
||||
},
|
||||
else: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['alphabet'] },
|
||||
a: { type: 'string' },
|
||||
b: { type: 'number' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const nestedElseSchema = {
|
||||
type: 'object',
|
||||
properties: { },
|
||||
if: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['foobar'] }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['foobar'] },
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'number' },
|
||||
list: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
value: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
else: {
|
||||
if: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['greeting'] }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['greeting'] },
|
||||
hi: { type: 'string' },
|
||||
hello: { type: 'number' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['alphabet'] },
|
||||
a: { type: 'string' },
|
||||
b: { type: 'number' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const nestedDeepElseSchema = {
|
||||
type: 'object',
|
||||
additionalProperties: schema
|
||||
}
|
||||
|
||||
const noElseSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
},
|
||||
if: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['foobar'] }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['foobar'] },
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'number' },
|
||||
list: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
value: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const fooBarInput = {
|
||||
kind: 'foobar',
|
||||
foo: 'FOO',
|
||||
list: [{
|
||||
name: 'name',
|
||||
value: 'foo'
|
||||
}],
|
||||
bar: 42,
|
||||
hi: 'HI',
|
||||
hello: 45,
|
||||
a: 'A',
|
||||
b: 35
|
||||
}
|
||||
const greetingInput = {
|
||||
kind: 'greeting',
|
||||
foo: 'FOO',
|
||||
bar: 42,
|
||||
hi: 'HI',
|
||||
hello: 45,
|
||||
a: 'A',
|
||||
b: 35
|
||||
}
|
||||
const alphabetInput = {
|
||||
kind: 'alphabet',
|
||||
foo: 'FOO',
|
||||
bar: 42,
|
||||
hi: 'HI',
|
||||
hello: 45,
|
||||
a: 'A',
|
||||
b: 35
|
||||
}
|
||||
const deepFoobarInput = {
|
||||
foobar: fooBarInput
|
||||
}
|
||||
const foobarOutput = JSON.stringify({
|
||||
kind: 'foobar',
|
||||
foo: 'FOO',
|
||||
bar: 42,
|
||||
list: [{
|
||||
name: 'name',
|
||||
value: 'foo'
|
||||
}]
|
||||
})
|
||||
const greetingOutput = JSON.stringify({
|
||||
kind: 'greeting',
|
||||
hi: 'HI',
|
||||
hello: 45
|
||||
})
|
||||
const alphabetOutput = JSON.stringify({
|
||||
kind: 'alphabet',
|
||||
a: 'A',
|
||||
b: 35
|
||||
})
|
||||
const deepFoobarOutput = JSON.stringify({
|
||||
foobar: JSON.parse(foobarOutput)
|
||||
})
|
||||
const noElseGreetingOutput = JSON.stringify({})
|
||||
|
||||
test('if-then-else', async t => {
|
||||
const tests = [
|
||||
{
|
||||
name: 'foobar',
|
||||
schema,
|
||||
input: fooBarInput,
|
||||
expected: foobarOutput
|
||||
},
|
||||
{
|
||||
name: 'greeting',
|
||||
schema,
|
||||
input: greetingInput,
|
||||
expected: greetingOutput
|
||||
},
|
||||
{
|
||||
name: 'if nested - then then',
|
||||
schema: nestedIfSchema,
|
||||
input: fooBarInput,
|
||||
expected: foobarOutput
|
||||
},
|
||||
{
|
||||
name: 'if nested - then else',
|
||||
schema: nestedIfSchema,
|
||||
input: greetingInput,
|
||||
expected: greetingOutput
|
||||
},
|
||||
{
|
||||
name: 'if nested - else',
|
||||
schema: nestedIfSchema,
|
||||
input: alphabetInput,
|
||||
expected: alphabetOutput
|
||||
},
|
||||
{
|
||||
name: 'else nested - then',
|
||||
schema: nestedElseSchema,
|
||||
input: fooBarInput,
|
||||
expected: foobarOutput
|
||||
},
|
||||
{
|
||||
name: 'else nested - else then',
|
||||
schema: nestedElseSchema,
|
||||
input: greetingInput,
|
||||
expected: greetingOutput
|
||||
},
|
||||
{
|
||||
name: 'else nested - else else',
|
||||
schema: nestedElseSchema,
|
||||
input: alphabetInput,
|
||||
expected: alphabetOutput
|
||||
},
|
||||
{
|
||||
name: 'deep then - else',
|
||||
schema: nestedDeepElseSchema,
|
||||
input: deepFoobarInput,
|
||||
expected: deepFoobarOutput
|
||||
},
|
||||
{
|
||||
name: 'no else',
|
||||
schema: noElseSchema,
|
||||
input: greetingInput,
|
||||
expected: noElseGreetingOutput
|
||||
}
|
||||
]
|
||||
|
||||
for (const { name, schema, input, expected } of tests) {
|
||||
await t.test(name + ' - normal', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build(JSON.parse(JSON.stringify(schema)), { ajv: { strictTypes: false } })
|
||||
const serialized = stringify(input)
|
||||
t.assert.equal(serialized, expected)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('nested if/then', t => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: { a: { type: 'string' } },
|
||||
if: {
|
||||
type: 'object',
|
||||
properties: { foo: { type: 'string' } }
|
||||
},
|
||||
then: {
|
||||
properties: { bar: { type: 'string' } },
|
||||
if: {
|
||||
type: 'object',
|
||||
properties: { foo1: { type: 'string' } }
|
||||
},
|
||||
then: {
|
||||
properties: { bar1: { type: 'string' } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(
|
||||
stringify({ a: 'A', foo: 'foo', bar: 'bar' }),
|
||||
JSON.stringify({ a: 'A', bar: 'bar' })
|
||||
)
|
||||
|
||||
t.assert.equal(
|
||||
stringify({ a: 'A', foo: 'foo', bar: 'bar', foo1: 'foo1', bar1: 'bar1' }),
|
||||
JSON.stringify({ a: 'A', bar: 'bar', bar1: 'bar1' })
|
||||
)
|
||||
})
|
||||
|
||||
test('if/else with string format', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
if: { type: 'string' },
|
||||
then: { type: 'string', format: 'date' },
|
||||
else: { const: 'Invalid' }
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
const date = new Date(1674263005800)
|
||||
|
||||
t.assert.equal(stringify(date), '"2023-01-21"')
|
||||
t.assert.equal(stringify('Invalid'), '"Invalid"')
|
||||
})
|
||||
|
||||
test('if/else with const integers', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'number',
|
||||
if: { type: 'number', minimum: 42 },
|
||||
then: { const: 66 },
|
||||
else: { const: 33 }
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify(100.32), '66')
|
||||
t.assert.equal(stringify(10.12), '33')
|
||||
})
|
||||
|
||||
test('if/else with array', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'array',
|
||||
if: { type: 'array', maxItems: 1 },
|
||||
then: { items: { type: 'string' } },
|
||||
else: { items: { type: 'number' } }
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify(['1']), JSON.stringify(['1']))
|
||||
t.assert.equal(stringify(['1', '2']), JSON.stringify([1, 2]))
|
||||
})
|
||||
|
||||
test('external recursive if/then/else', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const externalSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
base: { type: 'string' },
|
||||
self: { $ref: 'externalSchema#' }
|
||||
},
|
||||
if: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string', const: '41' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
bar: { type: 'string', const: '42' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
baz: { type: 'string', const: '43' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: { $ref: 'externalSchema#/properties/self' },
|
||||
b: { $ref: 'externalSchema#/properties/self' }
|
||||
}
|
||||
}
|
||||
|
||||
const data = {
|
||||
a: {
|
||||
base: 'a',
|
||||
foo: '41',
|
||||
bar: '42',
|
||||
baz: '43',
|
||||
ignore: 'ignored'
|
||||
},
|
||||
b: {
|
||||
base: 'b',
|
||||
foo: 'not-41',
|
||||
bar: '42',
|
||||
baz: '43',
|
||||
ignore: 'ignored'
|
||||
}
|
||||
}
|
||||
const stringify = build(schema, { schema: { externalSchema } })
|
||||
t.assert.equal(stringify(data), '{"a":{"base":"a","bar":"42"},"b":{"base":"b","baz":"43"}}')
|
||||
})
|
||||
92
node_modules/fast-json-stringify/test/inferType.test.js
generated
vendored
Normal file
92
node_modules/fast-json-stringify/test/inferType.test.js
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const validator = require('is-my-json-valid')
|
||||
const build = require('..')
|
||||
|
||||
function buildTest (schema, toStringify) {
|
||||
test(`render a ${schema.title} as JSON`, (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(toStringify)
|
||||
|
||||
t.assert.deepStrictEqual(JSON.parse(output), toStringify)
|
||||
t.assert.equal(output, JSON.stringify(toStringify))
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
}
|
||||
|
||||
buildTest({
|
||||
title: 'infer type object by keyword',
|
||||
// 'type': 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}, {
|
||||
name: 'foo'
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'infer type of nested object by keyword',
|
||||
// 'type': 'object',
|
||||
properties: {
|
||||
more: {
|
||||
description: 'more properties',
|
||||
// 'type': 'object',
|
||||
properties: {
|
||||
something: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
more: {
|
||||
something: 'else'
|
||||
}
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'infer type array by keyword',
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
// 'type': 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
ids: ['test']
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'infer type string by keyword',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
// 'type': 'string',
|
||||
maxLength: 3
|
||||
}
|
||||
}
|
||||
}, {
|
||||
name: 'foo'
|
||||
})
|
||||
|
||||
buildTest({
|
||||
title: 'infer type number by keyword',
|
||||
type: 'object',
|
||||
properties: {
|
||||
age: {
|
||||
// 'type': 'number',
|
||||
maximum: 18
|
||||
}
|
||||
}
|
||||
}, {
|
||||
age: 18
|
||||
})
|
||||
55
node_modules/fast-json-stringify/test/infinity.test.js
generated
vendored
Normal file
55
node_modules/fast-json-stringify/test/infinity.test.js
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('Finite numbers', t => {
|
||||
const values = [-5, 0, -0, 1.33, 99, 100.0,
|
||||
Math.E, Number.EPSILON,
|
||||
Number.MAX_SAFE_INTEGER, Number.MAX_VALUE,
|
||||
Number.MIN_SAFE_INTEGER, Number.MIN_VALUE]
|
||||
|
||||
t.plan(values.length)
|
||||
|
||||
const schema = {
|
||||
type: 'number'
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
values.forEach(v => t.assert.equal(stringify(v), JSON.stringify(v)))
|
||||
})
|
||||
|
||||
test('Infinite integers', t => {
|
||||
const values = [Infinity, -Infinity]
|
||||
|
||||
t.plan(values.length)
|
||||
|
||||
const schema = {
|
||||
type: 'integer'
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
values.forEach(v => {
|
||||
try {
|
||||
stringify(v)
|
||||
} catch (err) {
|
||||
t.assert.equal(err.message, `The value "${v}" cannot be converted to an integer.`)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('Infinite numbers', t => {
|
||||
const values = [Infinity, -Infinity]
|
||||
|
||||
t.plan(values.length)
|
||||
|
||||
const schema = {
|
||||
type: 'number'
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
values.forEach(v => t.assert.equal(stringify(v), JSON.stringify(v)))
|
||||
})
|
||||
194
node_modules/fast-json-stringify/test/integer.test.js
generated
vendored
Normal file
194
node_modules/fast-json-stringify/test/integer.test.js
generated
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
|
||||
const validator = require('is-my-json-valid')
|
||||
const build = require('..')
|
||||
const ROUNDING_TYPES = ['ceil', 'floor', 'round']
|
||||
|
||||
test('render an integer as JSON', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'integer',
|
||||
type: 'integer'
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify(1615)
|
||||
|
||||
t.assert.equal(output, '1615')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('render a float as an integer', (t) => {
|
||||
t.plan(2)
|
||||
try {
|
||||
build({
|
||||
title: 'float as integer',
|
||||
type: 'integer'
|
||||
}, { rounding: 'foobar' })
|
||||
} catch (error) {
|
||||
t.assert.ok(error)
|
||||
t.assert.equal(error.message, 'Unsupported integer rounding method foobar')
|
||||
}
|
||||
})
|
||||
|
||||
test('throws on NaN', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'integer',
|
||||
type: 'integer'
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
t.assert.throws(() => stringify(NaN), new Error('The value "NaN" cannot be converted to an integer.'))
|
||||
})
|
||||
|
||||
test('render a float as an integer', (t) => {
|
||||
const cases = [
|
||||
{ input: Math.PI, output: '3' },
|
||||
{ input: 5.0, output: '5' },
|
||||
{ input: null, output: '0' },
|
||||
{ input: 0, output: '0' },
|
||||
{ input: 0.0, output: '0' },
|
||||
{ input: 42, output: '42' },
|
||||
{ input: 1.99999, output: '1' },
|
||||
{ input: -45.05, output: '-45' },
|
||||
{ input: 3333333333333333, output: '3333333333333333' },
|
||||
{ input: Math.PI, output: '3', rounding: 'trunc' },
|
||||
{ input: 5.0, output: '5', rounding: 'trunc' },
|
||||
{ input: null, output: '0', rounding: 'trunc' },
|
||||
{ input: 0, output: '0', rounding: 'trunc' },
|
||||
{ input: 0.0, output: '0', rounding: 'trunc' },
|
||||
{ input: 42, output: '42', rounding: 'trunc' },
|
||||
{ input: 1.99999, output: '1', rounding: 'trunc' },
|
||||
{ input: -45.05, output: '-45', rounding: 'trunc' },
|
||||
{ input: 0.95, output: '1', rounding: 'ceil' },
|
||||
{ input: 0.2, output: '1', rounding: 'ceil' },
|
||||
{ input: 45.95, output: '45', rounding: 'floor' },
|
||||
{ input: -45.05, output: '-46', rounding: 'floor' },
|
||||
{ input: 45.44, output: '45', rounding: 'round' },
|
||||
{ input: 45.95, output: '46', rounding: 'round' }
|
||||
]
|
||||
|
||||
t.plan(cases.length * 2)
|
||||
cases.forEach(checkInteger)
|
||||
|
||||
function checkInteger ({ input, output, rounding }) {
|
||||
const schema = {
|
||||
title: 'float as integer',
|
||||
type: 'integer'
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema, { rounding })
|
||||
const str = stringify(input)
|
||||
|
||||
t.assert.equal(str, output)
|
||||
t.assert.ok(validate(JSON.parse(str)), 'valid schema')
|
||||
}
|
||||
})
|
||||
|
||||
test('render an object with an integer as JSON', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'object with integer',
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
id: 1615
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"id":1615}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('render an array with an integer as JSON', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'array with integer',
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify([1615])
|
||||
|
||||
t.assert.equal(output, '[1615]')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('render an object with an additionalProperty of type integer as JSON', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'object with integer',
|
||||
type: 'object',
|
||||
additionalProperties: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({
|
||||
num: 1615
|
||||
})
|
||||
|
||||
t.assert.equal(output, '{"num":1615}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('should round integer object parameter', t => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = { type: 'object', properties: { magic: { type: 'integer' } } }
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema, { rounding: 'ceil' })
|
||||
const output = stringify({ magic: 4.2 })
|
||||
|
||||
t.assert.equal(output, '{"magic":5}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('should not stringify a property if it does not exist', t => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = { title: 'Example Schema', type: 'object', properties: { age: { type: 'integer' } } }
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify({})
|
||||
|
||||
t.assert.equal(output, '{}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
ROUNDING_TYPES.forEach((rounding) => {
|
||||
test(`should not stringify a property if it does not exist (rounding: ${rounding})`, t => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = { type: 'object', properties: { magic: { type: 'integer' } } }
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema, { rounding })
|
||||
const output = stringify({})
|
||||
|
||||
t.assert.equal(output, '{}')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
})
|
||||
18
node_modules/fast-json-stringify/test/invalidSchema.test.js
generated
vendored
Normal file
18
node_modules/fast-json-stringify/test/invalidSchema.test.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
// Covers issue #139
|
||||
test('Should throw on invalid schema', t => {
|
||||
t.plan(1)
|
||||
t.assert.throws(() => {
|
||||
build({}, {
|
||||
schema: {
|
||||
invalid: {
|
||||
type: 'Dinosaur'
|
||||
}
|
||||
}
|
||||
})
|
||||
}, { message: /^"invalid" schema is invalid:.*/ })
|
||||
})
|
||||
57
node_modules/fast-json-stringify/test/issue-479.test.js
generated
vendored
Normal file
57
node_modules/fast-json-stringify/test/issue-479.test.js
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('should validate anyOf after allOf merge', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
$id: 'schema',
|
||||
type: 'object',
|
||||
allOf: [
|
||||
{
|
||||
$id: 'base',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
required: [
|
||||
'name'
|
||||
]
|
||||
},
|
||||
{
|
||||
$id: 'inner_schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
union: {
|
||||
$id: '#id',
|
||||
anyOf: [
|
||||
{
|
||||
|
||||
$id: 'guid',
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
|
||||
$id: 'email',
|
||||
type: 'string'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
required: [
|
||||
'union'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(
|
||||
stringify({ name: 'foo', union: 'a8f1cc50-5530-5c62-9109-5ba9589a6ae1' }),
|
||||
'{"name":"foo","union":"a8f1cc50-5530-5c62-9109-5ba9589a6ae1"}')
|
||||
})
|
||||
10
node_modules/fast-json-stringify/test/json-schema-test-suite/README.md
generated
vendored
Normal file
10
node_modules/fast-json-stringify/test/json-schema-test-suite/README.md
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# JSON-Schema-Test-Suite
|
||||
|
||||
You can find all test cases [here](https://github.com/json-schema-org/JSON-Schema-Test-Suite).
|
||||
It contains a set of JSON objects that implementors of JSON Schema validation libraries can use to test their validators.
|
||||
|
||||
# How to add another test case?
|
||||
|
||||
1. Navigate to [JSON-Schema-Test-Suite](https://github.com/json-schema-org/JSON-Schema-Test-Suite/tree/master/tests)
|
||||
2. Choose a draft `draft4`, `draft6` or `draft7`
|
||||
3. Copy & paste the `test-case.json` to the project and add a test like in the `draft4.test.js`
|
||||
12
node_modules/fast-json-stringify/test/json-schema-test-suite/draft4.test.js
generated
vendored
Normal file
12
node_modules/fast-json-stringify/test/json-schema-test-suite/draft4.test.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const { counTests, runTests } = require('./util')
|
||||
|
||||
const requiredTestSuite = require('./draft4/required.json')
|
||||
|
||||
test('required', async (t) => {
|
||||
const skippedTests = ['ignores arrays', 'ignores strings', 'ignores other non-objects']
|
||||
t.plan(counTests(requiredTestSuite, skippedTests))
|
||||
await runTests(t, requiredTestSuite, skippedTests)
|
||||
})
|
||||
54
node_modules/fast-json-stringify/test/json-schema-test-suite/draft4/required.json
generated
vendored
Normal file
54
node_modules/fast-json-stringify/test/json-schema-test-suite/draft4/required.json
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
[
|
||||
{
|
||||
"description": "required validation",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {},
|
||||
"bar": {}
|
||||
},
|
||||
"required": ["foo"]
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "present required property is valid",
|
||||
"data": {"foo": 1},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "non-present required property is invalid",
|
||||
"data": {"bar": 1},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores arrays",
|
||||
"data": [],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "ignores strings",
|
||||
"data": "",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "ignores other non-objects",
|
||||
"data": 12,
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "required default validation",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {}
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "not required by default",
|
||||
"data": {},
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
12
node_modules/fast-json-stringify/test/json-schema-test-suite/draft6.test.js
generated
vendored
Normal file
12
node_modules/fast-json-stringify/test/json-schema-test-suite/draft6.test.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const { counTests, runTests } = require('./util')
|
||||
|
||||
const requiredTestSuite = require('./draft6/required.json')
|
||||
|
||||
test('required', async (t) => {
|
||||
const skippedTests = ['ignores arrays', 'ignores strings', 'ignores other non-objects']
|
||||
t.plan(counTests(requiredTestSuite, skippedTests))
|
||||
await runTests(t, requiredTestSuite, skippedTests)
|
||||
})
|
||||
70
node_modules/fast-json-stringify/test/json-schema-test-suite/draft6/required.json
generated
vendored
Normal file
70
node_modules/fast-json-stringify/test/json-schema-test-suite/draft6/required.json
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
[
|
||||
{
|
||||
"description": "required validation",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {},
|
||||
"bar": {}
|
||||
},
|
||||
"required": ["foo"]
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "present required property is valid",
|
||||
"data": {"foo": 1},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "non-present required property is invalid",
|
||||
"data": {"bar": 1},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores arrays",
|
||||
"data": [],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "ignores strings",
|
||||
"data": "",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "ignores other non-objects",
|
||||
"data": 12,
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "required default validation",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {}
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "not required by default",
|
||||
"data": {},
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "required with empty array",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {}
|
||||
},
|
||||
"required": []
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "property not required",
|
||||
"data": {},
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
12
node_modules/fast-json-stringify/test/json-schema-test-suite/draft7.test.js
generated
vendored
Normal file
12
node_modules/fast-json-stringify/test/json-schema-test-suite/draft7.test.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const { counTests, runTests } = require('./util')
|
||||
|
||||
const requiredTestSuite = require('./draft7/required.json')
|
||||
|
||||
test('required', async (t) => {
|
||||
const skippedTests = ['ignores arrays', 'ignores strings', 'ignores other non-objects']
|
||||
t.plan(counTests(requiredTestSuite, skippedTests))
|
||||
await runTests(t, requiredTestSuite, skippedTests)
|
||||
})
|
||||
70
node_modules/fast-json-stringify/test/json-schema-test-suite/draft7/required.json
generated
vendored
Normal file
70
node_modules/fast-json-stringify/test/json-schema-test-suite/draft7/required.json
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
[
|
||||
{
|
||||
"description": "required validation",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {},
|
||||
"bar": {}
|
||||
},
|
||||
"required": ["foo"]
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "present required property is valid",
|
||||
"data": {"foo": 1},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "non-present required property is invalid",
|
||||
"data": {"bar": 1},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores arrays",
|
||||
"data": [],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "ignores strings",
|
||||
"data": "",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "ignores other non-objects",
|
||||
"data": 12,
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "required default validation",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {}
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "not required by default",
|
||||
"data": {},
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "required with empty array",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {}
|
||||
},
|
||||
"required": []
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "property not required",
|
||||
"data": {},
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
31
node_modules/fast-json-stringify/test/json-schema-test-suite/util.js
generated
vendored
Normal file
31
node_modules/fast-json-stringify/test/json-schema-test-suite/util.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
'use strict'
|
||||
|
||||
const build = require('../..')
|
||||
|
||||
async function runTests (t, testsuite, skippedTests) {
|
||||
for (const scenario of testsuite) {
|
||||
const stringify = build(scenario.schema)
|
||||
for (const test of scenario.tests) {
|
||||
if (skippedTests.indexOf(test.description) !== -1) {
|
||||
console.log(`skip ${test.description}`)
|
||||
continue
|
||||
}
|
||||
|
||||
await t.test(test.description, (t) => {
|
||||
t.plan(1)
|
||||
try {
|
||||
const output = stringify(test.data)
|
||||
t.assert.equal(output, JSON.stringify(test.data), 'compare payloads')
|
||||
} catch (err) {
|
||||
t.assert.ok(test.valid === false, 'payload should be valid: ' + err.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function counTests (ts, skippedTests) {
|
||||
return ts.reduce((a, b) => a + b.tests.length, 0) - skippedTests.length
|
||||
}
|
||||
|
||||
module.exports = { runTests, counTests }
|
||||
88
node_modules/fast-json-stringify/test/missing-values.test.js
generated
vendored
Normal file
88
node_modules/fast-json-stringify/test/missing-values.test.js
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('missing values', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const stringify = build({
|
||||
title: 'object with missing values',
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
type: 'string'
|
||||
},
|
||||
num: {
|
||||
type: 'number'
|
||||
},
|
||||
val: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.assert.equal('{"val":"value"}', stringify({ val: 'value' }))
|
||||
t.assert.equal('{"str":"string","val":"value"}', stringify({ str: 'string', val: 'value' }))
|
||||
t.assert.equal('{"str":"string","num":42,"val":"value"}', stringify({ str: 'string', num: 42, val: 'value' }))
|
||||
})
|
||||
|
||||
test('handle null when value should be string', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build({
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.assert.equal('{"str":""}', stringify({ str: null }))
|
||||
})
|
||||
|
||||
test('handle null when value should be integer', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build({
|
||||
type: 'object',
|
||||
properties: {
|
||||
int: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.assert.equal('{"int":0}', stringify({ int: null }))
|
||||
})
|
||||
|
||||
test('handle null when value should be number', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build({
|
||||
type: 'object',
|
||||
properties: {
|
||||
num: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.assert.equal('{"num":0}', stringify({ num: null }))
|
||||
})
|
||||
|
||||
test('handle null when value should be boolean', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build({
|
||||
type: 'object',
|
||||
properties: {
|
||||
bool: {
|
||||
type: 'boolean'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.assert.equal('{"bool":false}', stringify({ bool: null }))
|
||||
})
|
||||
19
node_modules/fast-json-stringify/test/multi-type-serializer.test.js
generated
vendored
Normal file
19
node_modules/fast-json-stringify/test/multi-type-serializer.test.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('should throw a TypeError with the path to the key of the invalid value', (t) => {
|
||||
t.plan(1)
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
num: {
|
||||
type: ['number']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
t.assert.throws(() => stringify({ num: { bla: 123 } }), new TypeError('The value of \'#/properties/num\' does not match schema definition.'))
|
||||
})
|
||||
63
node_modules/fast-json-stringify/test/nestedObjects.test.js
generated
vendored
Normal file
63
node_modules/fast-json-stringify/test/nestedObjects.test.js
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('nested objects with same properties', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'nested objects with same properties',
|
||||
type: 'object',
|
||||
properties: {
|
||||
stringProperty: {
|
||||
type: 'string'
|
||||
},
|
||||
objectProperty: {
|
||||
type: 'object',
|
||||
additionalProperties: true
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
const value = stringify({
|
||||
stringProperty: 'string1',
|
||||
objectProperty: {
|
||||
stringProperty: 'string2',
|
||||
numberProperty: 42
|
||||
}
|
||||
})
|
||||
t.assert.equal(value, '{"stringProperty":"string1","objectProperty":{"stringProperty":"string2","numberProperty":42}}')
|
||||
})
|
||||
|
||||
test('names collision', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'nested objects with same properties',
|
||||
type: 'object',
|
||||
properties: {
|
||||
test: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: { type: 'string' }
|
||||
}
|
||||
},
|
||||
tes: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
b: { type: 'string' },
|
||||
t: { type: 'object' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
const data = {
|
||||
test: { a: 'a' },
|
||||
tes: { b: 'b', t: {} }
|
||||
}
|
||||
|
||||
t.assert.equal(stringify(data), JSON.stringify(data))
|
||||
})
|
||||
543
node_modules/fast-json-stringify/test/nullable.test.js
generated
vendored
Normal file
543
node_modules/fast-json-stringify/test/nullable.test.js
generated
vendored
Normal file
@@ -0,0 +1,543 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
|
||||
const build = require('..')
|
||||
|
||||
const nullable = true
|
||||
|
||||
const complexObject = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
nullableString: { type: 'string', nullable },
|
||||
nullableNumber: { type: 'number', nullable },
|
||||
nullableInteger: { type: 'integer', nullable },
|
||||
nullableBoolean: { type: 'boolean', nullable },
|
||||
nullableNull: { type: 'null', nullable },
|
||||
nullableArray: {
|
||||
type: 'array',
|
||||
nullable: true,
|
||||
items: {}
|
||||
},
|
||||
nullableObject: { type: 'object', nullable: true },
|
||||
objectWithNullableProps: {
|
||||
type: 'object',
|
||||
nullable: false,
|
||||
additionalProperties: true,
|
||||
properties: {
|
||||
nullableString: { type: 'string', nullable },
|
||||
nullableNumber: { type: 'number', nullable },
|
||||
nullableInteger: { type: 'integer', nullable },
|
||||
nullableBoolean: { type: 'boolean', nullable },
|
||||
nullableNull: { type: 'null', nullable },
|
||||
nullableArray: {
|
||||
type: 'array',
|
||||
nullable: true,
|
||||
items: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
arrayWithNullableItems: {
|
||||
type: 'array',
|
||||
nullable: true,
|
||||
items: { type: ['integer', 'string'], nullable: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const complexData = {
|
||||
nullableString: null,
|
||||
nullableNumber: null,
|
||||
nullableInteger: null,
|
||||
nullableBoolean: null,
|
||||
nullableNull: null,
|
||||
nullableArray: null,
|
||||
nullableObject: null,
|
||||
objectWithNullableProps: {
|
||||
additionalProp: null,
|
||||
nullableString: null,
|
||||
nullableNumber: null,
|
||||
nullableInteger: null,
|
||||
nullableBoolean: null,
|
||||
nullableNull: null,
|
||||
nullableArray: null
|
||||
},
|
||||
arrayWithNullableItems: [1, 2, null]
|
||||
}
|
||||
|
||||
const complexExpectedResult = {
|
||||
nullableString: null,
|
||||
nullableNumber: null,
|
||||
nullableInteger: null,
|
||||
nullableBoolean: null,
|
||||
nullableNull: null,
|
||||
nullableArray: null,
|
||||
nullableObject: null,
|
||||
objectWithNullableProps: {
|
||||
additionalProp: null,
|
||||
nullableString: null,
|
||||
nullableNumber: null,
|
||||
nullableInteger: null,
|
||||
nullableBoolean: null,
|
||||
nullableNull: null,
|
||||
nullableArray: null
|
||||
},
|
||||
arrayWithNullableItems: [1, 2, null]
|
||||
}
|
||||
|
||||
const testSet = {
|
||||
nullableString: [{ type: 'string', nullable }, null, null],
|
||||
nullableNumber: [{ type: 'number', nullable }, null, null],
|
||||
nullableInteger: [{ type: 'integer', nullable }, null, null],
|
||||
nullableBoolean: [{ type: 'boolean', nullable }, null, null],
|
||||
nullableNull: [{ type: 'null', nullable }, null, null],
|
||||
nullableArray: [{
|
||||
type: 'array',
|
||||
nullable: true,
|
||||
items: {}
|
||||
}, null, null],
|
||||
nullableObject: [{ type: 'object', nullable: true }, null, null],
|
||||
complexObject: [complexObject, complexData, complexExpectedResult, { ajv: { allowUnionTypes: true } }]
|
||||
}
|
||||
|
||||
Object.keys(testSet).forEach(key => {
|
||||
test(`handle nullable:true in ${key} correctly`, (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const [
|
||||
schema,
|
||||
data,
|
||||
expected,
|
||||
extraOptions
|
||||
] = testSet[key]
|
||||
|
||||
const stringifier = build(schema, extraOptions)
|
||||
const result = stringifier(data)
|
||||
t.assert.deepStrictEqual(JSON.parse(result), expected)
|
||||
})
|
||||
})
|
||||
|
||||
test('handle nullable number correctly', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'number',
|
||||
nullable: true
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
const data = null
|
||||
const result = stringify(data)
|
||||
|
||||
t.assert.equal(result, JSON.stringify(data))
|
||||
t.assert.equal(JSON.parse(result), data)
|
||||
})
|
||||
|
||||
test('handle nullable integer correctly', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'integer',
|
||||
nullable: true
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
const data = null
|
||||
const result = stringify(data)
|
||||
|
||||
t.assert.equal(result, JSON.stringify(data))
|
||||
t.assert.equal(JSON.parse(result), data)
|
||||
})
|
||||
|
||||
test('handle nullable boolean correctly', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'boolean',
|
||||
nullable: true
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
const data = null
|
||||
const result = stringify(data)
|
||||
|
||||
t.assert.equal(result, JSON.stringify(data))
|
||||
t.assert.equal(JSON.parse(result), data)
|
||||
})
|
||||
|
||||
test('handle nullable string correctly', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'string',
|
||||
nullable: true
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
const data = null
|
||||
const result = stringify(data)
|
||||
|
||||
t.assert.equal(result, JSON.stringify(data))
|
||||
t.assert.equal(JSON.parse(result), data)
|
||||
})
|
||||
|
||||
test('handle nullable date-time correctly', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
nullable: true
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
const data = null
|
||||
const result = stringify(data)
|
||||
|
||||
t.assert.equal(result, JSON.stringify(data))
|
||||
t.assert.equal(JSON.parse(result), data)
|
||||
})
|
||||
|
||||
test('handle nullable date correctly', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'string',
|
||||
format: 'date',
|
||||
nullable: true
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
const data = null
|
||||
const result = stringify(data)
|
||||
|
||||
t.assert.equal(result, JSON.stringify(data))
|
||||
t.assert.equal(JSON.parse(result), data)
|
||||
})
|
||||
|
||||
test('handle nullable time correctly', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'string',
|
||||
format: 'time',
|
||||
nullable: true
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
const data = null
|
||||
const result = stringify(data)
|
||||
|
||||
t.assert.equal(result, JSON.stringify(data))
|
||||
t.assert.equal(JSON.parse(result), data)
|
||||
})
|
||||
|
||||
test('large array of nullable strings with default mechanism', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
nullable: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const options = {
|
||||
largeArraySize: 2e4,
|
||||
largeArrayMechanism: 'default'
|
||||
}
|
||||
|
||||
const stringify = build(schema, options)
|
||||
|
||||
const data = { ids: new Array(2e4).fill(null) }
|
||||
const result = stringify(data)
|
||||
|
||||
t.assert.equal(result, JSON.stringify(data))
|
||||
t.assert.deepStrictEqual(JSON.parse(result), data)
|
||||
})
|
||||
|
||||
test('large array of nullable date-time strings with default mechanism', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
nullable: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const options = {
|
||||
largeArraySize: 2e4,
|
||||
largeArrayMechanism: 'default'
|
||||
}
|
||||
|
||||
const stringify = build(schema, options)
|
||||
|
||||
const data = { ids: new Array(2e4).fill(null) }
|
||||
const result = stringify(data)
|
||||
|
||||
t.assert.equal(result, JSON.stringify(data))
|
||||
t.assert.deepStrictEqual(JSON.parse(result), data)
|
||||
})
|
||||
|
||||
test('large array of nullable date-time strings with default mechanism', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
format: 'date',
|
||||
nullable: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const options = {
|
||||
largeArraySize: 2e4,
|
||||
largeArrayMechanism: 'default'
|
||||
}
|
||||
|
||||
const stringify = build(schema, options)
|
||||
|
||||
const data = { ids: new Array(2e4).fill(null) }
|
||||
const result = stringify(data)
|
||||
|
||||
t.assert.equal(result, JSON.stringify(data))
|
||||
t.assert.deepStrictEqual(JSON.parse(result), data)
|
||||
})
|
||||
|
||||
test('large array of nullable date-time strings with default mechanism', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
format: 'time',
|
||||
nullable: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const options = {
|
||||
largeArraySize: 2e4,
|
||||
largeArrayMechanism: 'default'
|
||||
}
|
||||
|
||||
const stringify = build(schema, options)
|
||||
|
||||
const data = { ids: new Array(2e4).fill(null) }
|
||||
const result = stringify(data)
|
||||
|
||||
t.assert.equal(result, JSON.stringify(data))
|
||||
t.assert.deepStrictEqual(JSON.parse(result), data)
|
||||
})
|
||||
|
||||
test('large array of nullable numbers with default mechanism', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'number',
|
||||
nullable: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const options = {
|
||||
largeArraySize: 2e4,
|
||||
largeArrayMechanism: 'default'
|
||||
}
|
||||
|
||||
const stringify = build(schema, options)
|
||||
|
||||
const data = { ids: new Array(2e4).fill(null) }
|
||||
const result = stringify(data)
|
||||
|
||||
t.assert.equal(result, JSON.stringify(data))
|
||||
t.assert.deepStrictEqual(JSON.parse(result), data)
|
||||
})
|
||||
|
||||
test('large array of nullable integers with default mechanism', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'integer',
|
||||
nullable: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const options = {
|
||||
largeArraySize: 2e4,
|
||||
largeArrayMechanism: 'default'
|
||||
}
|
||||
|
||||
const stringify = build(schema, options)
|
||||
|
||||
const data = { ids: new Array(2e4).fill(null) }
|
||||
const result = stringify(data)
|
||||
|
||||
t.assert.equal(result, JSON.stringify(data))
|
||||
t.assert.deepStrictEqual(JSON.parse(result), data)
|
||||
})
|
||||
|
||||
test('large array of nullable booleans with default mechanism', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
ids: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'boolean',
|
||||
nullable: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const options = {
|
||||
largeArraySize: 2e4,
|
||||
largeArrayMechanism: 'default'
|
||||
}
|
||||
|
||||
const stringify = build(schema, options)
|
||||
|
||||
const data = { ids: new Array(2e4).fill(null) }
|
||||
const result = stringify(data)
|
||||
|
||||
t.assert.equal(result, JSON.stringify(data))
|
||||
t.assert.deepStrictEqual(JSON.parse(result), data)
|
||||
})
|
||||
|
||||
test('nullable type in the schema', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: ['object', 'null'],
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
const data = { foo: 'bar' }
|
||||
|
||||
t.assert.equal(stringify(data), JSON.stringify(data))
|
||||
t.assert.equal(stringify(null), JSON.stringify(null))
|
||||
})
|
||||
|
||||
test('throw an error if the value doesn\'t match the type', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
required: ['data'],
|
||||
properties: {
|
||||
data: {
|
||||
type: 'array',
|
||||
minItems: 1,
|
||||
items: {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
type: 'number'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
const validData = { data: [1, 'testing'] }
|
||||
t.assert.equal(stringify(validData), JSON.stringify(validData))
|
||||
|
||||
const invalidData = { data: [false, 'testing'] }
|
||||
t.assert.throws(() => stringify(invalidData))
|
||||
})
|
||||
|
||||
test('nullable value in oneOf', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'integer', minimum: 1 }
|
||||
},
|
||||
additionalProperties: false,
|
||||
required: ['id']
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
job: { type: 'string', nullable: true }
|
||||
},
|
||||
additionalProperties: false,
|
||||
required: ['job']
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
required: ['data'],
|
||||
additionalProperties: false
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
const data = { data: [{ job: null }] }
|
||||
t.assert.equal(stringify(data), JSON.stringify(data))
|
||||
})
|
||||
490
node_modules/fast-json-stringify/test/oneof.test.js
generated
vendored
Normal file
490
node_modules/fast-json-stringify/test/oneof.test.js
generated
vendored
Normal file
@@ -0,0 +1,490 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('object with multiple types field', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'object with multiple types field',
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
oneOf: [{
|
||||
type: 'string'
|
||||
}, {
|
||||
type: 'boolean'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({ str: 'string' }), '{"str":"string"}')
|
||||
t.assert.equal(stringify({ str: true }), '{"str":true}')
|
||||
})
|
||||
|
||||
test('object with field of type object or null', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'object with field of type object or null',
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop: {
|
||||
oneOf: [{
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}, {
|
||||
type: 'null'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({ prop: null }), '{"prop":null}')
|
||||
|
||||
t.assert.equal(stringify({
|
||||
prop: {
|
||||
str: 'string', remove: 'this'
|
||||
}
|
||||
}), '{"prop":{"str":"string"}}')
|
||||
})
|
||||
|
||||
test('object with field of type object or array', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'object with field of type object or array',
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop: {
|
||||
oneOf: [{
|
||||
type: 'object',
|
||||
properties: {},
|
||||
additionalProperties: true
|
||||
}, {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({
|
||||
prop: { str: 'string' }
|
||||
}), '{"prop":{"str":"string"}}')
|
||||
|
||||
t.assert.equal(stringify({
|
||||
prop: ['string']
|
||||
}), '{"prop":["string"]}')
|
||||
})
|
||||
|
||||
test('object with field of type string and coercion disable ', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'object with field of type string',
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
oneOf: [{
|
||||
type: 'string'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
t.assert.throws(() => stringify({ str: 1 }))
|
||||
})
|
||||
|
||||
test('object with field of type string and coercion enable ', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'object with field of type string',
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
oneOf: [{
|
||||
type: 'string'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const options = {
|
||||
ajv: {
|
||||
coerceTypes: true
|
||||
}
|
||||
}
|
||||
const stringify = build(schema, options)
|
||||
|
||||
const value = stringify({
|
||||
str: 1
|
||||
})
|
||||
t.assert.equal(value, '{"str":"1"}')
|
||||
})
|
||||
|
||||
test('object with field with type union of multiple objects', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'object with oneOf property value containing objects',
|
||||
type: 'object',
|
||||
properties: {
|
||||
oneOfSchema: {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
baz: { type: 'number' }
|
||||
},
|
||||
required: ['baz']
|
||||
},
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
bar: { type: 'string' }
|
||||
},
|
||||
required: ['bar']
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
required: ['oneOfSchema']
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({ oneOfSchema: { baz: 5 } }), '{"oneOfSchema":{"baz":5}}')
|
||||
|
||||
t.assert.equal(stringify({ oneOfSchema: { bar: 'foo' } }), '{"oneOfSchema":{"bar":"foo"}}')
|
||||
})
|
||||
|
||||
test('null value in schema', (t) => {
|
||||
t.plan(0)
|
||||
|
||||
const schema = {
|
||||
title: 'schema with null child',
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
enum: [null]
|
||||
}
|
||||
|
||||
build(schema)
|
||||
})
|
||||
|
||||
test('oneOf and $ref together', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
cs: {
|
||||
oneOf: [
|
||||
{
|
||||
$ref: '#/definitions/Option'
|
||||
},
|
||||
{
|
||||
type: 'boolean'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
definitions: {
|
||||
Option: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({ cs: 'franco' }), '{"cs":"franco"}')
|
||||
|
||||
t.assert.equal(stringify({ cs: true }), '{"cs":true}')
|
||||
})
|
||||
|
||||
test('oneOf and $ref: 2 levels are fine', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
cs: {
|
||||
oneOf: [
|
||||
{
|
||||
$ref: '#/definitions/Option'
|
||||
},
|
||||
{
|
||||
type: 'boolean'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
definitions: {
|
||||
Option: {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
type: 'boolean'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const value = stringify({
|
||||
cs: 3
|
||||
})
|
||||
t.assert.equal(value, '{"cs":3}')
|
||||
})
|
||||
|
||||
test('oneOf and $ref: multiple levels should throw at build.', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
cs: {
|
||||
oneOf: [
|
||||
{
|
||||
$ref: '#/definitions/Option'
|
||||
},
|
||||
{
|
||||
type: 'boolean'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
definitions: {
|
||||
Option: {
|
||||
oneOf: [
|
||||
{
|
||||
$ref: '#/definitions/Option2'
|
||||
},
|
||||
{
|
||||
type: 'string'
|
||||
}
|
||||
]
|
||||
},
|
||||
Option2: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({ cs: 3 }), '{"cs":3}')
|
||||
t.assert.equal(stringify({ cs: true }), '{"cs":true}')
|
||||
t.assert.equal(stringify({ cs: 'pippo' }), '{"cs":"pippo"}')
|
||||
})
|
||||
|
||||
test('oneOf and $ref - multiple external $ref', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const externalSchema = {
|
||||
external: {
|
||||
definitions: {
|
||||
def: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop: { oneOf: [{ $ref: 'external2#/definitions/other' }] }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
external2: {
|
||||
definitions: {
|
||||
internal: {
|
||||
type: 'string'
|
||||
},
|
||||
other: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop2: { $ref: '#/definitions/internal' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
title: 'object with $ref',
|
||||
type: 'object',
|
||||
properties: {
|
||||
obj: {
|
||||
$ref: 'external#/definitions/def'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const object = {
|
||||
obj: {
|
||||
prop: {
|
||||
prop2: 'test'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema, { schema: externalSchema })
|
||||
const output = stringify(object)
|
||||
|
||||
t.assert.doesNotThrow(() => JSON.parse(output))
|
||||
t.assert.equal(output, '{"obj":{"prop":{"prop2":"test"}}}')
|
||||
})
|
||||
|
||||
test('oneOf with enum with more than 100 entries', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'type array that may have one of declared items',
|
||||
type: 'array',
|
||||
items: {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'string',
|
||||
enum: ['EUR', 'USD', ...(new Set([...new Array(200)].map(() => Math.random().toString(36).substr(2, 3)))).values()]
|
||||
},
|
||||
{ type: 'null' }
|
||||
]
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
const value = stringify(['EUR', 'USD', null])
|
||||
t.assert.equal(value, '["EUR","USD",null]')
|
||||
})
|
||||
|
||||
test('oneOf object with field of type string with format or null', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const toStringify = new Date()
|
||||
|
||||
const withOneOfSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
prop: {
|
||||
oneOf: [{
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
}, {
|
||||
type: 'null'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const withOneOfStringify = build(withOneOfSchema)
|
||||
|
||||
t.assert.equal(withOneOfStringify({
|
||||
prop: toStringify
|
||||
}), `{"prop":"${toStringify.toISOString()}"}`)
|
||||
})
|
||||
|
||||
test('one array item match oneOf types', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
required: ['data'],
|
||||
properties: {
|
||||
data: {
|
||||
type: 'array',
|
||||
minItems: 1,
|
||||
items: {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
type: 'number'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({ data: ['foo'] }), '{"data":["foo"]}')
|
||||
t.assert.equal(stringify({ data: [1] }), '{"data":[1]}')
|
||||
t.assert.throws(() => stringify({ data: [false, 'foo'] }))
|
||||
})
|
||||
|
||||
test('some array items match oneOf types', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
required: ['data'],
|
||||
properties: {
|
||||
data: {
|
||||
type: 'array',
|
||||
minItems: 1,
|
||||
items: {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
type: 'number'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({ data: ['foo', 5] }), '{"data":["foo",5]}')
|
||||
t.assert.throws(() => stringify({ data: [false, 'foo', true, 5] }))
|
||||
})
|
||||
|
||||
test('all array items does not match oneOf types', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
required: ['data'],
|
||||
properties: {
|
||||
data: {
|
||||
type: 'array',
|
||||
minItems: 1,
|
||||
items: {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
type: 'number'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.throws(() => stringify({ data: [null, false, true, undefined, [], {}] }))
|
||||
})
|
||||
168
node_modules/fast-json-stringify/test/patternProperties.test.js
generated
vendored
Normal file
168
node_modules/fast-json-stringify/test/patternProperties.test.js
generated
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('patternProperties', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'patternProperties',
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
patternProperties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { str: 'test', foo: 42, ofoo: true, foof: 'string', objfoo: { a: true }, notMe: false }
|
||||
t.assert.equal(stringify(obj), '{"str":"test","foo":"42","ofoo":"true","foof":"string","objfoo":"[object Object]"}')
|
||||
})
|
||||
|
||||
test('patternProperties should not change properties', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'patternProperties should not change properties',
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
patternProperties: {
|
||||
foo: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { foo: '42', ofoo: 42 }
|
||||
t.assert.equal(stringify(obj), '{"foo":"42","ofoo":42}')
|
||||
})
|
||||
|
||||
test('patternProperties - string coerce', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'check string coerce',
|
||||
type: 'object',
|
||||
properties: {},
|
||||
patternProperties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { foo: true, ofoo: 42, arrfoo: ['array', 'test'], objfoo: { a: 'world' } }
|
||||
t.assert.equal(stringify(obj), '{"foo":"true","ofoo":"42","arrfoo":"array,test","objfoo":"[object Object]"}')
|
||||
})
|
||||
|
||||
test('patternProperties - number coerce', (t) => {
|
||||
t.plan(2)
|
||||
const stringify = build({
|
||||
title: 'check number coerce',
|
||||
type: 'object',
|
||||
properties: {},
|
||||
patternProperties: {
|
||||
foo: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const coercibleValues = { foo: true, ofoo: '42' }
|
||||
t.assert.equal(stringify(coercibleValues), '{"foo":1,"ofoo":42}')
|
||||
|
||||
const incoercibleValues = { xfoo: 'string', arrfoo: [1, 2], objfoo: { num: 42 } }
|
||||
try {
|
||||
stringify(incoercibleValues)
|
||||
t.fail('should throw an error')
|
||||
} catch (err) {
|
||||
t.assert.ok(err)
|
||||
}
|
||||
})
|
||||
|
||||
test('patternProperties - boolean coerce', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'check boolean coerce',
|
||||
type: 'object',
|
||||
properties: {},
|
||||
patternProperties: {
|
||||
foo: {
|
||||
type: 'boolean'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { foo: 'true', ofoo: 0, arrfoo: [1, 2], objfoo: { a: true } }
|
||||
t.assert.equal(stringify(obj), '{"foo":true,"ofoo":false,"arrfoo":true,"objfoo":true}')
|
||||
})
|
||||
|
||||
test('patternProperties - object coerce', (t) => {
|
||||
t.plan(1)
|
||||
const stringify = build({
|
||||
title: 'check object coerce',
|
||||
type: 'object',
|
||||
properties: {},
|
||||
patternProperties: {
|
||||
foo: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
answer: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { objfoo: { answer: 42 } }
|
||||
t.assert.equal(stringify(obj), '{"objfoo":{"answer":42}}')
|
||||
})
|
||||
|
||||
test('patternProperties - array coerce', (t) => {
|
||||
t.plan(2)
|
||||
const stringify = build({
|
||||
title: 'check array coerce',
|
||||
type: 'object',
|
||||
properties: {},
|
||||
patternProperties: {
|
||||
foo: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const coercibleValues = { arrfoo: [1, 2] }
|
||||
t.assert.equal(stringify(coercibleValues), '{"arrfoo":["1","2"]}')
|
||||
|
||||
const incoercibleValues = { foo: 'true', ofoo: 0, objfoo: { tyrion: 'lannister' } }
|
||||
t.assert.throws(() => stringify(incoercibleValues))
|
||||
})
|
||||
|
||||
test('patternProperties - fail on invalid regex, handled by ajv', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
t.assert.throws(() => build({
|
||||
title: 'check array coerce',
|
||||
type: 'object',
|
||||
properties: {},
|
||||
patternProperties: {
|
||||
'foo/\\': {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}), new Error('schema is invalid: data/patternProperties must match format "regex"'))
|
||||
})
|
||||
245
node_modules/fast-json-stringify/test/recursion.test.js
generated
vendored
Normal file
245
node_modules/fast-json-stringify/test/recursion.test.js
generated
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('can stringify recursive directory tree (issue #181)', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
definitions: {
|
||||
directory: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
subDirectories: {
|
||||
type: 'array',
|
||||
items: { $ref: '#/definitions/directory' },
|
||||
default: []
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
type: 'array',
|
||||
items: { $ref: '#/definitions/directory' }
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify([
|
||||
{ name: 'directory 1', subDirectories: [] },
|
||||
{
|
||||
name: 'directory 2',
|
||||
subDirectories: [
|
||||
{ name: 'directory 2.1', subDirectories: [] },
|
||||
{ name: 'directory 2.2', subDirectories: [] }
|
||||
]
|
||||
}
|
||||
]), '[{"name":"directory 1","subDirectories":[]},{"name":"directory 2","subDirectories":[{"name":"directory 2.1","subDirectories":[]},{"name":"directory 2.2","subDirectories":[]}]}]')
|
||||
})
|
||||
|
||||
test('can stringify when recursion in external schema', t => {
|
||||
t.plan(1)
|
||||
|
||||
const referenceSchema = {
|
||||
$id: 'person',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
children: {
|
||||
type: 'array',
|
||||
items: { $ref: '#' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
$id: 'mainSchema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
people: {
|
||||
$ref: 'person'
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema, {
|
||||
schema: {
|
||||
[referenceSchema.$id]: referenceSchema
|
||||
}
|
||||
})
|
||||
|
||||
const value = stringify({ people: { name: 'Elizabeth', children: [{ name: 'Charles' }] } })
|
||||
t.assert.equal(value, '{"people":{"name":"Elizabeth","children":[{"name":"Charles"}]}}')
|
||||
})
|
||||
|
||||
test('use proper serialize function', t => {
|
||||
t.plan(1)
|
||||
|
||||
const personSchema = {
|
||||
$id: 'person',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
children: {
|
||||
type: 'array',
|
||||
items: { $ref: '#' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const directorySchema = {
|
||||
$id: 'directory',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
subDirectories: {
|
||||
type: 'array',
|
||||
items: { $ref: '#' },
|
||||
default: []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
$id: 'mainSchema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
people: { $ref: 'person' },
|
||||
directory: { $ref: 'directory' }
|
||||
}
|
||||
}
|
||||
const stringify = build(schema, {
|
||||
schema: {
|
||||
[personSchema.$id]: personSchema,
|
||||
[directorySchema.$id]: directorySchema
|
||||
}
|
||||
})
|
||||
|
||||
const value = stringify({
|
||||
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' }, { name: 'directory 1.2.2' }]
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
t.assert.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":[]}]}]}}')
|
||||
})
|
||||
|
||||
test('can stringify recursive references in object types (issue #365)', t => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
definitions: {
|
||||
parentCategory: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
parent: {
|
||||
$ref: '#/definitions/parentCategory'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
properties: {
|
||||
category: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
parent: {
|
||||
$ref: '#/definitions/parentCategory'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const data = {
|
||||
category: {
|
||||
parent: {
|
||||
parent: {
|
||||
parent: {
|
||||
parent: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const value = stringify(data)
|
||||
t.assert.equal(value, '{"category":{"parent":{"parent":{"parent":{"parent":{}}}}}}')
|
||||
})
|
||||
|
||||
test('can stringify recursive inline $id references (issue #410)', t => {
|
||||
t.plan(1)
|
||||
const schema = {
|
||||
$id: 'Node',
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string'
|
||||
},
|
||||
nodes: {
|
||||
type: 'array',
|
||||
items: {
|
||||
$ref: 'Node'
|
||||
}
|
||||
}
|
||||
},
|
||||
required: [
|
||||
'id',
|
||||
'nodes'
|
||||
]
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const data = {
|
||||
id: '0',
|
||||
nodes: [
|
||||
{
|
||||
id: '1',
|
||||
nodes: [{
|
||||
id: '2',
|
||||
nodes: [
|
||||
{ id: '3', nodes: [] },
|
||||
{ id: '4', nodes: [] },
|
||||
{ id: '5', nodes: [] }
|
||||
]
|
||||
}]
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
nodes: [{
|
||||
id: '7',
|
||||
nodes: [
|
||||
{ id: '8', nodes: [] },
|
||||
{ id: '9', nodes: [] },
|
||||
{ id: '10', nodes: [] }
|
||||
]
|
||||
}]
|
||||
},
|
||||
{
|
||||
id: '11',
|
||||
nodes: [{
|
||||
id: '12',
|
||||
nodes: [
|
||||
{ id: '13', nodes: [] },
|
||||
{ id: '14', nodes: [] },
|
||||
{ id: '15', nodes: [] }
|
||||
]
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
const value = stringify(data)
|
||||
t.assert.equal(value, '{"id":"0","nodes":[{"id":"1","nodes":[{"id":"2","nodes":[{"id":"3","nodes":[]},{"id":"4","nodes":[]},{"id":"5","nodes":[]}]}]},{"id":"6","nodes":[{"id":"7","nodes":[{"id":"8","nodes":[]},{"id":"9","nodes":[]},{"id":"10","nodes":[]}]}]},{"id":"11","nodes":[{"id":"12","nodes":[{"id":"13","nodes":[]},{"id":"14","nodes":[]},{"id":"15","nodes":[]}]}]}]}')
|
||||
})
|
||||
12
node_modules/fast-json-stringify/test/ref.json
generated
vendored
Normal file
12
node_modules/fast-json-stringify/test/ref.json
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"definitions": {
|
||||
"def": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"str": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2046
node_modules/fast-json-stringify/test/ref.test.js
generated
vendored
Normal file
2046
node_modules/fast-json-stringify/test/ref.test.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
32
node_modules/fast-json-stringify/test/regex.test.js
generated
vendored
Normal file
32
node_modules/fast-json-stringify/test/regex.test.js
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const validator = require('is-my-json-valid')
|
||||
const build = require('..')
|
||||
|
||||
test('object with RexExp', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const schema = {
|
||||
title: 'object with RegExp',
|
||||
type: 'object',
|
||||
properties: {
|
||||
reg: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const obj = {
|
||||
reg: /"([^"]|\\")*"/
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const validate = validator(schema)
|
||||
const output = stringify(obj)
|
||||
|
||||
t.assert.doesNotThrow(() => JSON.parse(output))
|
||||
|
||||
t.assert.equal(obj.reg.source, new RegExp(JSON.parse(output).reg).source)
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
204
node_modules/fast-json-stringify/test/required.test.js
generated
vendored
Normal file
204
node_modules/fast-json-stringify/test/required.test.js
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('object with required field', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'object with required field',
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
type: 'string'
|
||||
},
|
||||
num: {
|
||||
type: 'integer'
|
||||
}
|
||||
},
|
||||
required: ['str']
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.doesNotThrow(() => {
|
||||
stringify({
|
||||
str: 'string'
|
||||
})
|
||||
})
|
||||
|
||||
t.assert.throws(() => {
|
||||
stringify({
|
||||
num: 42
|
||||
})
|
||||
}, { message: '"str" is required!' })
|
||||
})
|
||||
|
||||
test('object with required field not in properties schema', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'object with required field',
|
||||
type: 'object',
|
||||
properties: {
|
||||
num: {
|
||||
type: 'integer'
|
||||
}
|
||||
},
|
||||
required: ['str']
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.throws(() => {
|
||||
stringify({})
|
||||
}, { message: '"str" is required!' })
|
||||
|
||||
t.assert.throws(() => {
|
||||
stringify({
|
||||
num: 42
|
||||
})
|
||||
}, { message: '"str" is required!' })
|
||||
})
|
||||
|
||||
test('object with required field not in properties schema with additional properties true', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'object with required field',
|
||||
type: 'object',
|
||||
properties: {
|
||||
num: {
|
||||
type: 'integer'
|
||||
}
|
||||
},
|
||||
additionalProperties: true,
|
||||
required: ['str']
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.throws(() => {
|
||||
stringify({})
|
||||
}, { message: '"str" is required!' })
|
||||
|
||||
t.assert.throws(() => {
|
||||
stringify({
|
||||
num: 42
|
||||
})
|
||||
}, { message: '"str" is required!' })
|
||||
})
|
||||
|
||||
test('object with multiple required field not in properties schema', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const schema = {
|
||||
title: 'object with required field',
|
||||
type: 'object',
|
||||
properties: {
|
||||
num: {
|
||||
type: 'integer'
|
||||
}
|
||||
},
|
||||
additionalProperties: true,
|
||||
required: ['num', 'key1', 'key2']
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.throws(() => {
|
||||
stringify({})
|
||||
}, { message: '"key1" is required!' })
|
||||
|
||||
t.assert.throws(() => {
|
||||
stringify({
|
||||
key1: 42,
|
||||
key2: 42
|
||||
})
|
||||
}, { message: '"num" is required!' })
|
||||
|
||||
t.assert.throws(() => {
|
||||
stringify({
|
||||
num: 42,
|
||||
key1: 'some'
|
||||
})
|
||||
}, { message: '"key2" is required!' })
|
||||
})
|
||||
|
||||
test('object with required bool', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'object with required field',
|
||||
type: 'object',
|
||||
properties: {
|
||||
num: {
|
||||
type: 'integer'
|
||||
}
|
||||
},
|
||||
additionalProperties: true,
|
||||
required: ['bool']
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.throws(() => {
|
||||
stringify({})
|
||||
}, { message: '"bool" is required!' })
|
||||
|
||||
t.assert.doesNotThrow(() => {
|
||||
stringify({
|
||||
bool: false
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('required nullable', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'object with required field',
|
||||
type: 'object',
|
||||
properties: {
|
||||
num: {
|
||||
type: ['integer']
|
||||
}
|
||||
},
|
||||
additionalProperties: true,
|
||||
required: ['null']
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.doesNotThrow(() => {
|
||||
stringify({
|
||||
null: null
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('required numbers', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'object with required field',
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
type: 'string'
|
||||
},
|
||||
num: {
|
||||
type: 'integer'
|
||||
}
|
||||
},
|
||||
required: ['num']
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.doesNotThrow(() => {
|
||||
stringify({
|
||||
num: 42
|
||||
})
|
||||
})
|
||||
|
||||
t.assert.throws(() => {
|
||||
stringify({
|
||||
num: 'aaa'
|
||||
})
|
||||
}, { message: 'The value "aaa" cannot be converted to an integer.' })
|
||||
})
|
||||
50
node_modules/fast-json-stringify/test/requiresAjv.test.js
generated
vendored
Normal file
50
node_modules/fast-json-stringify/test/requiresAjv.test.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('nested ref requires ajv', async t => {
|
||||
t.test('nested ref requires ajv', async t => {
|
||||
const schemaA = {
|
||||
$id: 'urn:schema:a',
|
||||
definitions: {
|
||||
foo: { anyOf: [{ type: 'string' }, { type: 'null' }] }
|
||||
}
|
||||
}
|
||||
|
||||
const schemaB = {
|
||||
$id: 'urn:schema:b',
|
||||
type: 'object',
|
||||
properties: {
|
||||
results: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
bar: {
|
||||
type: 'array',
|
||||
items: { $ref: 'urn:schema:a#/definitions/foo' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schemaB, {
|
||||
schema: {
|
||||
[schemaA.$id]: schemaA
|
||||
}
|
||||
})
|
||||
const result = stringify({
|
||||
results: {
|
||||
items: {
|
||||
bar: ['baz']
|
||||
}
|
||||
}
|
||||
})
|
||||
t.assert.equal(result, '{"results":{"items":{"bar":["baz"]}}}')
|
||||
})
|
||||
})
|
||||
141
node_modules/fast-json-stringify/test/sanitize.test.js
generated
vendored
Normal file
141
node_modules/fast-json-stringify/test/sanitize.test.js
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
const stringify = build({
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
},
|
||||
lastName: {
|
||||
type: 'string'
|
||||
},
|
||||
age: {
|
||||
description: 'Age in years"',
|
||||
type: 'integer'
|
||||
},
|
||||
[(() => "phra'&& process.exit(1) ||'phra")()]: {},
|
||||
now: {
|
||||
type: 'string'
|
||||
},
|
||||
reg: {
|
||||
type: 'string',
|
||||
default: 'a\'&& process.exit(1) ||\''
|
||||
},
|
||||
obj: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
bool: {
|
||||
type: 'boolean'
|
||||
}
|
||||
}
|
||||
},
|
||||
'"\'w00t': {
|
||||
type: 'string',
|
||||
default: '"\'w00t'
|
||||
},
|
||||
arr: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
'phra\' && process.exit(1)//': {
|
||||
type: 'number'
|
||||
},
|
||||
str: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ['now'],
|
||||
patternProperties: {
|
||||
'.*foo$': {
|
||||
type: 'string'
|
||||
},
|
||||
test: {
|
||||
type: 'number'
|
||||
},
|
||||
'phra\'/ && process.exit(1) && /\'': {
|
||||
type: 'number'
|
||||
},
|
||||
'"\'w00t.*////': {
|
||||
type: 'number'
|
||||
}
|
||||
},
|
||||
additionalProperties: {
|
||||
type: 'string'
|
||||
}
|
||||
})
|
||||
|
||||
const obj = {
|
||||
firstName: 'Matteo',
|
||||
lastName: 'Collina',
|
||||
age: 32,
|
||||
now: new Date(),
|
||||
foo: 'hello"',
|
||||
bar: "world'",
|
||||
'fuzz"': 42,
|
||||
"me'": 42,
|
||||
numfoo: 42,
|
||||
test: 42,
|
||||
strtest: '23',
|
||||
arr: [{ 'phra\' && process.exit(1)//': 42 }],
|
||||
obj: { bool: true },
|
||||
notmatch: 'valar morghulis',
|
||||
notmatchobj: { a: true },
|
||||
notmatchnum: 42
|
||||
}
|
||||
|
||||
test('sanitize', t => {
|
||||
const json = stringify(obj)
|
||||
t.assert.doesNotThrow(() => JSON.parse(json))
|
||||
|
||||
const stringify2 = build({
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
patternProperties: {
|
||||
'"\'w00t.*////': {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.assert.deepStrictEqual(JSON.parse(stringify2({
|
||||
'"\'phra////': 42,
|
||||
asd: 42
|
||||
})), {
|
||||
})
|
||||
|
||||
const stringify3 = build({
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
"\"phra\\'&&(console.log(42))//||'phra": {}
|
||||
}
|
||||
})
|
||||
|
||||
// this verifies the escaping
|
||||
JSON.parse(stringify3({
|
||||
'"phra\'&&(console.log(42))//||\'phra': 42
|
||||
}))
|
||||
|
||||
const stringify4 = build({
|
||||
title: 'Example Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
'"\\\\\\\\\'w00t': {
|
||||
type: 'string',
|
||||
default: '"\'w00t'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.assert.deepStrictEqual(JSON.parse(stringify4({})), {
|
||||
'"\\\\\\\\\'w00t': '"\'w00t'
|
||||
})
|
||||
})
|
||||
18
node_modules/fast-json-stringify/test/sanitize2.test.js
generated
vendored
Normal file
18
node_modules/fast-json-stringify/test/sanitize2.test.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('sanitize 2', t => {
|
||||
const payload = '(throw "pwoned")'
|
||||
|
||||
const stringify = build({
|
||||
properties: {
|
||||
[`*///\\\\\\']);${payload};{/*`]: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.assert.doesNotThrow(() => stringify({}))
|
||||
})
|
||||
17
node_modules/fast-json-stringify/test/sanitize3.test.js
generated
vendored
Normal file
17
node_modules/fast-json-stringify/test/sanitize3.test.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('sanitize 3', t => {
|
||||
t.assert.throws(() => {
|
||||
build({
|
||||
$defs: {
|
||||
type: 'foooo"bar'
|
||||
},
|
||||
patternProperties: {
|
||||
x: { $ref: '#/$defs' }
|
||||
}
|
||||
})
|
||||
}, { message: 'foooo"bar unsupported' })
|
||||
})
|
||||
16
node_modules/fast-json-stringify/test/sanitize4.test.js
generated
vendored
Normal file
16
node_modules/fast-json-stringify/test/sanitize4.test.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('sanitize 4', t => {
|
||||
const payload = '(throw "pwoned")'
|
||||
|
||||
const stringify = build({
|
||||
required: [`"];${payload}//`]
|
||||
})
|
||||
|
||||
t.assert.throws(() => {
|
||||
stringify({})
|
||||
}, { message: '""];(throw "pwoned")//" is required!' })
|
||||
})
|
||||
16
node_modules/fast-json-stringify/test/sanitize5.test.js
generated
vendored
Normal file
16
node_modules/fast-json-stringify/test/sanitize5.test.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('sanitize 5', t => {
|
||||
const payload = '(throw "pwoned")'
|
||||
|
||||
t.assert.throws(() => {
|
||||
build({
|
||||
patternProperties: {
|
||||
'*': { type: `*/${payload}){//` }
|
||||
}
|
||||
})
|
||||
}, { message: 'schema is invalid: data/patternProperties must match format "regex"' })
|
||||
})
|
||||
22
node_modules/fast-json-stringify/test/sanitize6.test.js
generated
vendored
Normal file
22
node_modules/fast-json-stringify/test/sanitize6.test.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('sanitize 6', t => {
|
||||
const payload = '(throw "pwoned")'
|
||||
|
||||
const stringify = build({
|
||||
type: 'object',
|
||||
properties: {
|
||||
'/*': { type: 'object' },
|
||||
x: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: { type: 'string', default: `*/}${payload};{//` }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
t.assert.doesNotThrow(() => { stringify({}) })
|
||||
})
|
||||
68
node_modules/fast-json-stringify/test/sanitize7.test.js
generated
vendored
Normal file
68
node_modules/fast-json-stringify/test/sanitize7.test.js
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('required property containing single quote, contains property', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build({
|
||||
type: 'object',
|
||||
properties: {
|
||||
'\'': { type: 'string' }
|
||||
},
|
||||
required: [
|
||||
'\''
|
||||
]
|
||||
})
|
||||
|
||||
t.assert.throws(() => stringify({}), new Error('"\'" is required!'))
|
||||
})
|
||||
|
||||
test('required property containing double quote, contains property', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build({
|
||||
type: 'object',
|
||||
properties: {
|
||||
'"': { type: 'string' }
|
||||
},
|
||||
required: [
|
||||
'"'
|
||||
]
|
||||
})
|
||||
|
||||
t.assert.throws(() => stringify({}), new Error('""" is required!'))
|
||||
})
|
||||
|
||||
test('required property containing single quote, does not contain property', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build({
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: { type: 'string' }
|
||||
},
|
||||
required: [
|
||||
'\''
|
||||
]
|
||||
})
|
||||
|
||||
t.assert.throws(() => stringify({}), new Error('"\'" is required!'))
|
||||
})
|
||||
|
||||
test('required property containing double quote, does not contain property', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build({
|
||||
type: 'object',
|
||||
properties: {
|
||||
a: { type: 'string' }
|
||||
},
|
||||
required: [
|
||||
'"'
|
||||
]
|
||||
})
|
||||
|
||||
t.assert.throws(() => stringify({}), new Error('""" is required!'))
|
||||
})
|
||||
196
node_modules/fast-json-stringify/test/side-effect.test.js
generated
vendored
Normal file
196
node_modules/fast-json-stringify/test/side-effect.test.js
generated
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const clone = require('rfdc/default')
|
||||
const build = require('..')
|
||||
|
||||
test('oneOf with $ref should not change the input schema', t => {
|
||||
t.plan(2)
|
||||
|
||||
const referenceSchema = {
|
||||
$id: 'externalId',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' }
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
$id: 'mainSchema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
people: {
|
||||
oneOf: [{ $ref: 'externalId' }]
|
||||
}
|
||||
}
|
||||
}
|
||||
const clonedSchema = clone(schema)
|
||||
const stringify = build(schema, {
|
||||
schema: {
|
||||
[referenceSchema.$id]: referenceSchema
|
||||
}
|
||||
})
|
||||
|
||||
const value = stringify({ people: { name: 'hello', foo: 'bar' } })
|
||||
t.assert.equal(value, '{"people":{"name":"hello"}}')
|
||||
t.assert.deepStrictEqual(schema, clonedSchema)
|
||||
})
|
||||
|
||||
test('oneOf and anyOf with $ref should not change the input schema', t => {
|
||||
t.plan(3)
|
||||
|
||||
const referenceSchema = {
|
||||
$id: 'externalSchema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' }
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
$id: 'rootSchema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
people: {
|
||||
oneOf: [{ $ref: 'externalSchema' }]
|
||||
},
|
||||
love: {
|
||||
anyOf: [
|
||||
{ $ref: '#/definitions/foo' },
|
||||
{ type: 'boolean' }
|
||||
]
|
||||
}
|
||||
},
|
||||
definitions: {
|
||||
foo: { type: 'string' }
|
||||
}
|
||||
}
|
||||
const clonedSchema = clone(schema)
|
||||
const stringify = build(schema, {
|
||||
schema: {
|
||||
[referenceSchema.$id]: referenceSchema
|
||||
}
|
||||
})
|
||||
|
||||
const valueAny1 = stringify({ people: { name: 'hello', foo: 'bar' }, love: 'music' })
|
||||
const valueAny2 = stringify({ people: { name: 'hello', foo: 'bar' }, love: true })
|
||||
|
||||
t.assert.equal(valueAny1, '{"people":{"name":"hello"},"love":"music"}')
|
||||
t.assert.equal(valueAny2, '{"people":{"name":"hello"},"love":true}')
|
||||
t.assert.deepStrictEqual(schema, clonedSchema)
|
||||
})
|
||||
|
||||
test('multiple $ref tree', t => {
|
||||
t.plan(2)
|
||||
|
||||
const referenceDeepSchema = {
|
||||
$id: 'deepId',
|
||||
type: 'number'
|
||||
}
|
||||
|
||||
const referenceSchema = {
|
||||
$id: 'externalId',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { $ref: '#/definitions/foo' },
|
||||
age: { $ref: 'deepId' }
|
||||
},
|
||||
definitions: {
|
||||
foo: { type: 'string' }
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
$id: 'mainSchema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
people: {
|
||||
oneOf: [{ $ref: 'externalId' }]
|
||||
}
|
||||
}
|
||||
}
|
||||
const clonedSchema = clone(schema)
|
||||
const stringify = build(schema, {
|
||||
schema: {
|
||||
[referenceDeepSchema.$id]: referenceDeepSchema,
|
||||
[referenceSchema.$id]: referenceSchema
|
||||
}
|
||||
})
|
||||
|
||||
const value = stringify({ people: { name: 'hello', foo: 'bar', age: 42 } })
|
||||
t.assert.equal(value, '{"people":{"name":"hello","age":42}}')
|
||||
t.assert.deepStrictEqual(schema, clonedSchema)
|
||||
})
|
||||
|
||||
test('must not mutate items $ref', t => {
|
||||
t.plan(2)
|
||||
|
||||
const referenceSchema = {
|
||||
$id: 'ShowSchema',
|
||||
$schema: 'http://json-schema.org/draft-07/schema#',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
$id: 'ListSchema',
|
||||
$schema: 'http://json-schema.org/draft-07/schema#',
|
||||
type: 'array',
|
||||
items: {
|
||||
$ref: 'ShowSchema#'
|
||||
}
|
||||
}
|
||||
const clonedSchema = clone(schema)
|
||||
const stringify = build(schema, {
|
||||
schema: {
|
||||
[referenceSchema.$id]: referenceSchema
|
||||
}
|
||||
})
|
||||
|
||||
const value = stringify([{ name: 'foo' }])
|
||||
t.assert.equal(value, '[{"name":"foo"}]')
|
||||
t.assert.deepStrictEqual(schema, clonedSchema)
|
||||
})
|
||||
|
||||
test('must not mutate items referred by $ref', t => {
|
||||
t.plan(2)
|
||||
|
||||
const firstSchema = {
|
||||
$id: 'example1',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const reusedSchema = {
|
||||
$id: 'example2',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
oneOf: [
|
||||
{
|
||||
$ref: 'example1'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const clonedSchema = clone(firstSchema)
|
||||
const stringify = build(reusedSchema, {
|
||||
schema: {
|
||||
[firstSchema.$id]: firstSchema
|
||||
}
|
||||
})
|
||||
|
||||
const value = stringify({ name: { name: 'foo' } })
|
||||
t.assert.equal(value, '{"name":{"name":"foo"}}')
|
||||
t.assert.deepStrictEqual(firstSchema, clonedSchema)
|
||||
})
|
||||
219
node_modules/fast-json-stringify/test/standalone-mode.test.js
generated
vendored
Normal file
219
node_modules/fast-json-stringify/test/standalone-mode.test.js
generated
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
'use strict'
|
||||
|
||||
const { test, after } = require('node:test')
|
||||
const fjs = require('..')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
function build (opts, schema) {
|
||||
return fjs(schema || {
|
||||
title: 'default string',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
required: ['firstName']
|
||||
}, opts)
|
||||
}
|
||||
|
||||
const tmpDir = 'test/fixtures'
|
||||
|
||||
test('activate standalone mode', async (t) => {
|
||||
t.plan(3)
|
||||
|
||||
after(async () => {
|
||||
await fs.promises.rm(destination, { force: true })
|
||||
})
|
||||
|
||||
const code = build({ mode: 'standalone' })
|
||||
t.assert.ok(typeof code === 'string')
|
||||
t.assert.equal(code.indexOf('ajv'), -1)
|
||||
|
||||
const destination = path.resolve(tmpDir, 'standalone.js')
|
||||
|
||||
await fs.promises.writeFile(destination, code)
|
||||
const standalone = require(destination)
|
||||
t.assert.equal(standalone({ firstName: 'Foo', surname: 'bar' }), JSON.stringify({ firstName: 'Foo' }), 'surname evicted')
|
||||
})
|
||||
|
||||
test('test ajv schema', async (t) => {
|
||||
t.plan(3)
|
||||
|
||||
after(async () => {
|
||||
await fs.promises.rm(destination, { force: true })
|
||||
})
|
||||
|
||||
const code = build({ mode: 'standalone' }, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
},
|
||||
if: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['foobar'] }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['foobar'] },
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'number' },
|
||||
list: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
value: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
else: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kind: { type: 'string', enum: ['greeting'] },
|
||||
hi: { type: 'string' },
|
||||
hello: { type: 'number' },
|
||||
list: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
value: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
t.assert.ok(typeof code === 'string')
|
||||
t.assert.equal(code.indexOf('ajv') > 0, true)
|
||||
|
||||
const destination = path.resolve(tmpDir, 'standalone2.js')
|
||||
|
||||
await fs.promises.writeFile(destination, code)
|
||||
const standalone = require(destination)
|
||||
t.assert.equal(standalone({
|
||||
kind: 'foobar',
|
||||
foo: 'FOO',
|
||||
list: [{
|
||||
name: 'name',
|
||||
value: 'foo'
|
||||
}],
|
||||
bar: 42,
|
||||
hi: 'HI',
|
||||
hello: 45,
|
||||
a: 'A',
|
||||
b: 35
|
||||
}), JSON.stringify({
|
||||
kind: 'foobar',
|
||||
foo: 'FOO',
|
||||
bar: 42,
|
||||
list: [{
|
||||
name: 'name',
|
||||
value: 'foo'
|
||||
}]
|
||||
}))
|
||||
})
|
||||
|
||||
test('no need to keep external schemas once compiled', async (t) => {
|
||||
t.plan(1)
|
||||
|
||||
after(async () => {
|
||||
await fs.promises.rm(destination, { force: true })
|
||||
})
|
||||
|
||||
const externalSchema = {
|
||||
first: {
|
||||
definitions: {
|
||||
id1: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id1: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const code = fjs({
|
||||
$ref: 'first#/definitions/id1'
|
||||
}, {
|
||||
mode: 'standalone',
|
||||
schema: externalSchema
|
||||
})
|
||||
|
||||
const destination = path.resolve(tmpDir, 'standalone3.js')
|
||||
|
||||
await fs.promises.writeFile(destination, code)
|
||||
const standalone = require(destination)
|
||||
|
||||
t.assert.equal(standalone({ id1: 5 }), JSON.stringify({ id1: 5 }), 'serialization works with external schemas')
|
||||
})
|
||||
|
||||
test('no need to keep external schemas once compiled - with oneOf validator', async (t) => {
|
||||
t.plan(2)
|
||||
|
||||
after(async () => {
|
||||
await fs.promises.rm(destination, { force: true })
|
||||
})
|
||||
|
||||
const externalSchema = {
|
||||
ext: {
|
||||
definitions: {
|
||||
oBaz: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
baz: { type: 'number' }
|
||||
},
|
||||
required: ['baz']
|
||||
},
|
||||
oBar: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
bar: { type: 'string' }
|
||||
},
|
||||
required: ['bar']
|
||||
},
|
||||
other: {
|
||||
type: 'string',
|
||||
const: 'other'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
title: 'object with oneOf property value containing refs to external schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
oneOfSchema: {
|
||||
oneOf: [
|
||||
{ $ref: 'ext#/definitions/oBaz' },
|
||||
{ $ref: 'ext#/definitions/oBar' }
|
||||
]
|
||||
}
|
||||
},
|
||||
required: ['oneOfSchema']
|
||||
}
|
||||
|
||||
const code = fjs(schema, {
|
||||
mode: 'standalone',
|
||||
schema: externalSchema
|
||||
})
|
||||
|
||||
const destination = path.resolve(tmpDir, 'standalone-oneOf-ref.js')
|
||||
|
||||
await fs.promises.writeFile(destination, code)
|
||||
const stringify = require(destination)
|
||||
|
||||
t.assert.equal(stringify({ oneOfSchema: { baz: 5 } }), '{"oneOfSchema":{"baz":5}}')
|
||||
t.assert.equal(stringify({ oneOfSchema: { bar: 'foo' } }), '{"oneOfSchema":{"bar":"foo"}}')
|
||||
})
|
||||
84
node_modules/fast-json-stringify/test/string.test.js
generated
vendored
Normal file
84
node_modules/fast-json-stringify/test/string.test.js
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
|
||||
const build = require('..')
|
||||
|
||||
test('serialize short string', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'string'
|
||||
}
|
||||
|
||||
const input = 'abcd'
|
||||
const stringify = build(schema)
|
||||
const output = stringify(input)
|
||||
|
||||
t.assert.equal(output, '"abcd"')
|
||||
t.assert.equal(JSON.parse(output), input)
|
||||
})
|
||||
|
||||
test('serialize short string', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'string'
|
||||
}
|
||||
|
||||
const input = '\x00'
|
||||
const stringify = build(schema)
|
||||
const output = stringify(input)
|
||||
|
||||
t.assert.equal(output, '"\\u0000"')
|
||||
t.assert.equal(JSON.parse(output), input)
|
||||
})
|
||||
|
||||
test('serialize long string', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'string'
|
||||
}
|
||||
|
||||
const input = new Array(2e4).fill('\x00').join('')
|
||||
const stringify = build(schema)
|
||||
const output = stringify(input)
|
||||
|
||||
t.assert.equal(output, `"${new Array(2e4).fill('\\u0000').join('')}"`)
|
||||
t.assert.equal(JSON.parse(output), input)
|
||||
})
|
||||
|
||||
test('unsafe string', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'string',
|
||||
format: 'unsafe'
|
||||
}
|
||||
|
||||
const input = 'abcd'
|
||||
const stringify = build(schema)
|
||||
const output = stringify(input)
|
||||
|
||||
t.assert.equal(output, `"${input}"`)
|
||||
t.assert.equal(JSON.parse(output), input)
|
||||
})
|
||||
|
||||
test('unsafe unescaped string', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'string',
|
||||
format: 'unsafe'
|
||||
}
|
||||
|
||||
const input = 'abcd "abcd"'
|
||||
const stringify = build(schema)
|
||||
const output = stringify(input)
|
||||
|
||||
t.assert.equal(output, `"${input}"`)
|
||||
t.assert.throws(function () {
|
||||
JSON.parse(output)
|
||||
})
|
||||
})
|
||||
67
node_modules/fast-json-stringify/test/surrogate.test.js
generated
vendored
Normal file
67
node_modules/fast-json-stringify/test/surrogate.test.js
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const validator = require('is-my-json-valid')
|
||||
const build = require('..')
|
||||
|
||||
test('render a string with surrogate pairs as JSON:test 1', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'surrogate',
|
||||
type: 'string'
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify('𝌆')
|
||||
|
||||
t.assert.equal(output, '"𝌆"')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('render a string with surrogate pairs as JSON: test 2', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'long',
|
||||
type: 'string'
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify('\uD834\uDF06')
|
||||
|
||||
t.assert.equal(output, '"𝌆"')
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('render a string with Unpaired surrogate code as JSON', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'surrogate',
|
||||
type: 'string'
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify('\uDF06\uD834')
|
||||
t.assert.equal(output, JSON.stringify('\uDF06\uD834'))
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
|
||||
test('render a string with lone surrogate code as JSON', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'surrogate',
|
||||
type: 'string'
|
||||
}
|
||||
|
||||
const validate = validator(schema)
|
||||
const stringify = build(schema)
|
||||
const output = stringify('\uDEAD')
|
||||
t.assert.equal(output, JSON.stringify('\uDEAD'))
|
||||
t.assert.ok(validate(JSON.parse(output)), 'valid schema')
|
||||
})
|
||||
203
node_modules/fast-json-stringify/test/toJSON.test.js
generated
vendored
Normal file
203
node_modules/fast-json-stringify/test/toJSON.test.js
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('use toJSON method on object types', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build({
|
||||
title: 'simple object',
|
||||
type: 'object',
|
||||
properties: {
|
||||
productName: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
})
|
||||
const object = {
|
||||
product: { name: 'cola' },
|
||||
toJSON: function () {
|
||||
return { productName: this.product.name }
|
||||
}
|
||||
}
|
||||
|
||||
t.assert.equal('{"productName":"cola"}', stringify(object))
|
||||
})
|
||||
|
||||
test('use toJSON method on nested object types', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build({
|
||||
title: 'simple array',
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
productName: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
const array = [
|
||||
{
|
||||
product: { name: 'cola' },
|
||||
toJSON: function () {
|
||||
return { productName: this.product.name }
|
||||
}
|
||||
},
|
||||
{
|
||||
product: { name: 'sprite' },
|
||||
toJSON: function () {
|
||||
return { productName: this.product.name }
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
t.assert.equal('[{"productName":"cola"},{"productName":"sprite"}]', stringify(array))
|
||||
})
|
||||
|
||||
test('not use toJSON if does not exist', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build({
|
||||
title: 'simple object',
|
||||
type: 'object',
|
||||
properties: {
|
||||
product: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
const object = {
|
||||
product: { name: 'cola' }
|
||||
}
|
||||
|
||||
t.assert.equal('{"product":{"name":"cola"}}', stringify(object))
|
||||
})
|
||||
|
||||
test('not fail on null object declared nullable', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build({
|
||||
title: 'simple object',
|
||||
type: 'object',
|
||||
nullable: true,
|
||||
properties: {
|
||||
product: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
t.assert.equal('null', stringify(null))
|
||||
})
|
||||
|
||||
test('not fail on null sub-object declared nullable', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build({
|
||||
title: 'simple object',
|
||||
type: 'object',
|
||||
properties: {
|
||||
product: {
|
||||
nullable: true,
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
const object = {
|
||||
product: null
|
||||
}
|
||||
t.assert.equal('{"product":null}', stringify(object))
|
||||
})
|
||||
|
||||
test('on non nullable null sub-object it should coerce to {}', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build({
|
||||
title: 'simple object',
|
||||
type: 'object',
|
||||
properties: {
|
||||
product: {
|
||||
nullable: false,
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
const object = {
|
||||
product: null
|
||||
}
|
||||
|
||||
const result = stringify(object)
|
||||
t.assert.equal(result, JSON.stringify({ product: {} }))
|
||||
})
|
||||
|
||||
test('on non nullable null object it should coerce to {}', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build({
|
||||
title: 'simple object',
|
||||
nullable: false,
|
||||
type: 'object',
|
||||
properties: {
|
||||
product: {
|
||||
nullable: false,
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const result = stringify(null)
|
||||
t.assert.equal(result, '{}')
|
||||
})
|
||||
|
||||
test('on non-nullable null object it should skip rendering, skipping required fields checks', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const stringify = build({
|
||||
title: 'simple object',
|
||||
nullable: false,
|
||||
type: 'object',
|
||||
properties: {
|
||||
product: {
|
||||
nullable: false,
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ['product']
|
||||
})
|
||||
|
||||
const result = stringify(null)
|
||||
t.assert.equal(result, '{}')
|
||||
})
|
||||
36
node_modules/fast-json-stringify/test/typebox.test.js
generated
vendored
Normal file
36
node_modules/fast-json-stringify/test/typebox.test.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('nested object in pattern properties for typebox', (t) => {
|
||||
const { Type } = require('@sinclair/typebox')
|
||||
|
||||
t.plan(1)
|
||||
|
||||
const nestedSchema = Type.Object({
|
||||
nestedKey1: Type.String()
|
||||
})
|
||||
|
||||
const RootSchema = Type.Object({
|
||||
key1: Type.Record(Type.String(), nestedSchema),
|
||||
key2: Type.Record(Type.String(), nestedSchema)
|
||||
})
|
||||
|
||||
const schema = RootSchema
|
||||
const stringify = build(schema)
|
||||
|
||||
const value = stringify({
|
||||
key1: {
|
||||
nestedKey: {
|
||||
nestedKey1: 'value1'
|
||||
}
|
||||
},
|
||||
key2: {
|
||||
nestedKey: {
|
||||
nestedKey1: 'value2'
|
||||
}
|
||||
}
|
||||
})
|
||||
t.assert.equal(value, '{"key1":{"nestedKey":{"nestedKey1":"value1"}},"key2":{"nestedKey":{"nestedKey1":"value2"}}}')
|
||||
})
|
||||
550
node_modules/fast-json-stringify/test/typesArray.test.js
generated
vendored
Normal file
550
node_modules/fast-json-stringify/test/typesArray.test.js
generated
vendored
Normal file
@@ -0,0 +1,550 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('possibly nullable integer primitive alternative', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'simple object with multi-type nullable primitive',
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: {
|
||||
type: ['integer']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema, { ajv: { allowUnionTypes: true } })
|
||||
|
||||
const value = stringify({
|
||||
data: 4
|
||||
})
|
||||
t.assert.equal(value, '{"data":4}')
|
||||
})
|
||||
|
||||
test('possibly nullable number primitive alternative', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'simple object with multi-type nullable primitive',
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: {
|
||||
type: ['number']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
const value = stringify({
|
||||
data: 4
|
||||
})
|
||||
t.assert.equal(value, '{"data":4}')
|
||||
})
|
||||
|
||||
test('possibly nullable integer primitive alternative with null value', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'simple object with multi-type nullable primitive',
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: {
|
||||
type: ['integer']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
const value = stringify({
|
||||
data: null
|
||||
})
|
||||
t.assert.equal(value, '{"data":0}')
|
||||
})
|
||||
|
||||
test('possibly nullable number primitive alternative with null value', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'simple object with multi-type nullable primitive',
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: {
|
||||
type: ['number']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
const value = stringify({
|
||||
data: null
|
||||
})
|
||||
t.assert.equal(value, '{"data":0}')
|
||||
})
|
||||
|
||||
test('possibly nullable number primitive alternative with null value', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'simple object with multi-type nullable primitive',
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: {
|
||||
type: ['boolean']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
const value = stringify({
|
||||
data: null
|
||||
})
|
||||
t.assert.equal(value, '{"data":false}')
|
||||
})
|
||||
|
||||
test('nullable integer primitive', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'simple object with nullable primitive',
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: {
|
||||
type: ['integer', 'null']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
const value = stringify({
|
||||
data: 4
|
||||
})
|
||||
t.assert.equal(value, '{"data":4}')
|
||||
})
|
||||
|
||||
test('nullable number primitive', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'simple object with nullable primitive',
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: {
|
||||
type: ['number', 'null']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
const value = stringify({
|
||||
data: 4
|
||||
})
|
||||
t.assert.equal(value, '{"data":4}')
|
||||
})
|
||||
|
||||
test('nullable primitive with null value', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'simple object with nullable primitive',
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: {
|
||||
type: ['integer', 'null']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
const value = stringify({
|
||||
data: null
|
||||
})
|
||||
t.assert.equal(value, '{"data":null}')
|
||||
})
|
||||
|
||||
test('nullable number primitive with null value', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'simple object with nullable primitive',
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: {
|
||||
type: ['number', 'null']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
const value = stringify({
|
||||
data: null
|
||||
})
|
||||
t.assert.equal(value, '{"data":null}')
|
||||
})
|
||||
|
||||
test('possibly null object with multi-type property', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const schema = {
|
||||
title: 'simple object with multi-type property',
|
||||
type: 'object',
|
||||
properties: {
|
||||
objectOrNull: {
|
||||
type: ['object', 'null'],
|
||||
properties: {
|
||||
stringOrNumber: {
|
||||
type: ['string', 'number']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.equal(stringify({
|
||||
objectOrNull: {
|
||||
stringOrNumber: 'string'
|
||||
}
|
||||
}), '{"objectOrNull":{"stringOrNumber":"string"}}')
|
||||
|
||||
t.assert.equal(stringify({
|
||||
objectOrNull: {
|
||||
stringOrNumber: 42
|
||||
}
|
||||
}), '{"objectOrNull":{"stringOrNumber":42}}')
|
||||
|
||||
t.assert.equal(stringify({
|
||||
objectOrNull: null
|
||||
}), '{"objectOrNull":null}')
|
||||
})
|
||||
|
||||
test('object with possibly null array of multiple types', (t) => {
|
||||
t.plan(5)
|
||||
|
||||
const schema = {
|
||||
title: 'object with array of multiple types',
|
||||
type: 'object',
|
||||
properties: {
|
||||
arrayOfStringsAndNumbers: {
|
||||
type: ['array', 'null'],
|
||||
items: {
|
||||
type: ['string', 'number', 'null']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
try {
|
||||
const value = stringify({
|
||||
arrayOfStringsAndNumbers: null
|
||||
})
|
||||
t.assert.equal(value, '{"arrayOfStringsAndNumbers":null}')
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
t.fail()
|
||||
}
|
||||
|
||||
try {
|
||||
const value = stringify({
|
||||
arrayOfStringsAndNumbers: ['string1', 'string2']
|
||||
})
|
||||
t.assert.equal(value, '{"arrayOfStringsAndNumbers":["string1","string2"]}')
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
t.fail()
|
||||
}
|
||||
|
||||
t.assert.equal(stringify({
|
||||
arrayOfStringsAndNumbers: [42, 7]
|
||||
}), '{"arrayOfStringsAndNumbers":[42,7]}')
|
||||
|
||||
t.assert.equal(stringify({
|
||||
arrayOfStringsAndNumbers: ['string1', 42, 7, 'string2']
|
||||
}), '{"arrayOfStringsAndNumbers":["string1",42,7,"string2"]}')
|
||||
|
||||
t.assert.equal(stringify({
|
||||
arrayOfStringsAndNumbers: ['string1', null, 42, 7, 'string2', null]
|
||||
}), '{"arrayOfStringsAndNumbers":["string1",null,42,7,"string2",null]}')
|
||||
})
|
||||
|
||||
test('object with tuple of multiple types', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
title: 'object with array of multiple types',
|
||||
type: 'object',
|
||||
properties: {
|
||||
fixedTupleOfStringsAndNumbers: {
|
||||
type: 'array',
|
||||
items: [
|
||||
{
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
type: ['string', 'number']
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
|
||||
try {
|
||||
const value = stringify({
|
||||
fixedTupleOfStringsAndNumbers: ['string1', 42, 7]
|
||||
})
|
||||
t.assert.equal(value, '{"fixedTupleOfStringsAndNumbers":["string1",42,7]}')
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
t.fail()
|
||||
}
|
||||
|
||||
try {
|
||||
const value = stringify({
|
||||
fixedTupleOfStringsAndNumbers: ['string1', 42, 'string2']
|
||||
})
|
||||
t.assert.equal(value, '{"fixedTupleOfStringsAndNumbers":["string1",42,"string2"]}')
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('object with anyOf and multiple types', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const schema = {
|
||||
title: 'object with anyOf and multiple types',
|
||||
type: 'object',
|
||||
properties: {
|
||||
objectOrBoolean: {
|
||||
anyOf: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
stringOrNumber: {
|
||||
type: ['string', 'number']
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'boolean'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
const stringify = build(schema, { ajv: { allowUnionTypes: true } })
|
||||
|
||||
try {
|
||||
const value = stringify({
|
||||
objectOrBoolean: { stringOrNumber: 'string' }
|
||||
})
|
||||
t.assert.equal(value, '{"objectOrBoolean":{"stringOrNumber":"string"}}')
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
t.fail()
|
||||
}
|
||||
|
||||
t.assert.equal(stringify({
|
||||
objectOrBoolean: { stringOrNumber: 42 }
|
||||
}), '{"objectOrBoolean":{"stringOrNumber":42}}')
|
||||
|
||||
t.assert.equal(stringify({
|
||||
objectOrBoolean: true
|
||||
}), '{"objectOrBoolean":true}')
|
||||
})
|
||||
|
||||
test('string type array can handle dates', (t) => {
|
||||
t.plan(1)
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
date: { type: ['string'] },
|
||||
dateObject: { type: ['string'], format: 'date-time' }
|
||||
}
|
||||
}
|
||||
const stringify = build(schema)
|
||||
const value = stringify({
|
||||
date: new Date('2018-04-20T07:52:31.017Z'),
|
||||
dateObject: new Date('2018-04-21T07:52:31.017Z')
|
||||
})
|
||||
t.assert.equal(value, '{"date":"2018-04-20T07:52:31.017Z","dateObject":"2018-04-21T07:52:31.017Z"}')
|
||||
})
|
||||
|
||||
test('object that is simultaneously a string and a json', (t) => {
|
||||
t.plan(2)
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
simultaneously: {
|
||||
type: ['string', 'object'],
|
||||
properties: {
|
||||
foo: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const likeObjectId = {
|
||||
toString () { return 'hello' }
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const valueStr = stringify({ simultaneously: likeObjectId })
|
||||
t.assert.equal(valueStr, '{"simultaneously":"hello"}')
|
||||
|
||||
const valueObj = stringify({ simultaneously: { foo: likeObjectId } })
|
||||
t.assert.equal(valueObj, '{"simultaneously":{"foo":"hello"}}')
|
||||
})
|
||||
|
||||
test('object that is simultaneously a string and a json switched', (t) => {
|
||||
t.plan(2)
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
simultaneously: {
|
||||
type: ['object', 'string'],
|
||||
properties: {
|
||||
foo: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const likeObjectId = {
|
||||
toString () { return 'hello' }
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const valueStr = stringify({ simultaneously: likeObjectId })
|
||||
t.assert.equal(valueStr, '{"simultaneously":{}}')
|
||||
|
||||
const valueObj = stringify({ simultaneously: { foo: likeObjectId } })
|
||||
t.assert.equal(valueObj, '{"simultaneously":{"foo":"hello"}}')
|
||||
})
|
||||
|
||||
test('class instance that is simultaneously a string and a json', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
simultaneously: {
|
||||
type: ['string', 'object'],
|
||||
properties: {
|
||||
foo: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Test {
|
||||
toString () { return 'hello' }
|
||||
}
|
||||
|
||||
const likeObjectId = new Test()
|
||||
|
||||
const stringify = build(schema)
|
||||
const valueStr = stringify({ simultaneously: likeObjectId })
|
||||
t.assert.equal(valueStr, '{"simultaneously":"hello"}')
|
||||
|
||||
const valueObj = stringify({ simultaneously: { foo: likeObjectId } })
|
||||
t.assert.equal(valueObj, '{"simultaneously":{"foo":"hello"}}')
|
||||
})
|
||||
|
||||
test('should not throw an error when type is array and object is null, it should instead coerce to []', (t) => {
|
||||
t.plan(1)
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
arr: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
const result = stringify({ arr: null })
|
||||
t.assert.equal(result, JSON.stringify({ arr: [] }))
|
||||
})
|
||||
|
||||
test('should throw an error when type is array and object is not an array', (t) => {
|
||||
t.plan(1)
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
arr: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
t.assert.throws(() => stringify({ arr: { foo: 'hello' } }), new TypeError('The value of \'#/properties/arr\' does not match schema definition.'))
|
||||
})
|
||||
|
||||
test('should throw an error when type is array and object is not an array with external schema', (t) => {
|
||||
t.plan(1)
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
arr: {
|
||||
$ref: 'arrayOfNumbers#/definitions/arr'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const externalSchema = {
|
||||
arrayOfNumbers: {
|
||||
definitions: {
|
||||
arr: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema, { schema: externalSchema })
|
||||
t.assert.throws(() => stringify({ arr: { foo: 'hello' } }), new TypeError('The value of \'arrayOfNumbers#/definitions/arr\' does not match schema definition.'))
|
||||
})
|
||||
|
||||
test('throw an error if none of types matches', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'simple object with multi-type nullable primitive',
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: {
|
||||
type: ['number', 'boolean']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
t.assert.throws(() => stringify({ data: 'string' }), 'The value "string" does not match schema definition.')
|
||||
})
|
||||
27
node_modules/fast-json-stringify/test/unknownFormats.test.js
generated
vendored
Normal file
27
node_modules/fast-json-stringify/test/unknownFormats.test.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const build = require('..')
|
||||
|
||||
test('object with custom format field', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const schema = {
|
||||
title: 'object with custom format field',
|
||||
type: 'object',
|
||||
properties: {
|
||||
str: {
|
||||
type: 'string',
|
||||
format: 'test-format'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stringify = build(schema)
|
||||
|
||||
t.assert.doesNotThrow(() => {
|
||||
stringify({
|
||||
str: 'string'
|
||||
})
|
||||
})
|
||||
})
|
||||
50
node_modules/fast-json-stringify/test/webpack.test.js
generated
vendored
Normal file
50
node_modules/fast-json-stringify/test/webpack.test.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const webpack = require('webpack')
|
||||
const path = require('path')
|
||||
|
||||
test('the library should work with webpack', async (t) => {
|
||||
t.plan(1)
|
||||
const targetdir = path.resolve(__dirname, '..', '.cache')
|
||||
const targetname = path.join(targetdir, 'webpacktest.js')
|
||||
const wopts = {
|
||||
entry: path.resolve(__dirname, '..', 'index.js'),
|
||||
mode: 'production',
|
||||
target: 'node',
|
||||
output: {
|
||||
path: targetdir,
|
||||
filename: 'webpacktest.js',
|
||||
library: {
|
||||
name: 'fastJsonStringify',
|
||||
type: 'umd'
|
||||
}
|
||||
}
|
||||
}
|
||||
await new Promise((resolve, reject) => {
|
||||
webpack(wopts, (err, stats) => {
|
||||
if (err) { reject(err) } else { resolve(stats) };
|
||||
})
|
||||
})
|
||||
const build = require(targetname)
|
||||
const stringify = build({
|
||||
title: 'webpack should not rename code to be executed',
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
},
|
||||
bar: {
|
||||
type: 'boolean'
|
||||
}
|
||||
},
|
||||
patternProperties: {
|
||||
foo: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const obj = { foo: '42', bar: true }
|
||||
t.assert.equal(stringify(obj), '{"foo":"42","bar":true}')
|
||||
})
|
||||
231
node_modules/fast-json-stringify/types/index.d.ts
generated
vendored
Normal file
231
node_modules/fast-json-stringify/types/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
import Ajv, { Options as AjvOptions } from 'ajv'
|
||||
|
||||
type Build = typeof build
|
||||
|
||||
declare namespace build {
|
||||
interface BaseSchema {
|
||||
/**
|
||||
* Schema id
|
||||
*/
|
||||
$id?: string
|
||||
/**
|
||||
* Schema title
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* Schema description
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* A comment to be added to the schema
|
||||
*/
|
||||
$comment?: string;
|
||||
/**
|
||||
* Default value to be assigned when no value is given in the document
|
||||
*/
|
||||
default?: any;
|
||||
/**
|
||||
* A list of example values that match this schema
|
||||
*/
|
||||
examples?: any[];
|
||||
/**
|
||||
* Additional schema definition to reference from within the schema
|
||||
*/
|
||||
definitions?: Record<string, Schema>
|
||||
/**
|
||||
* A set of schemas of which at least one must match
|
||||
*/
|
||||
anyOf?: Partial<Schema>[];
|
||||
/**
|
||||
* A set of schemas which must all match
|
||||
*/
|
||||
allOf?: Partial<Schema>[];
|
||||
/**
|
||||
* A conditional schema to check, controls schemas defined in `then` and `else`
|
||||
*/
|
||||
if?: Partial<Schema>;
|
||||
/**
|
||||
* A schema to apply if the conditional schema from `if` passes
|
||||
*/
|
||||
then?: Partial<Schema>;
|
||||
/**
|
||||
* A schema to apply if the conditional schema from `if` fails
|
||||
*/
|
||||
else?: Partial<Schema>;
|
||||
/**
|
||||
* Open API 3.0 spec states that any value that can be null must be declared `nullable`
|
||||
* @default false
|
||||
*/
|
||||
nullable?: boolean;
|
||||
}
|
||||
|
||||
export interface RefSchema {
|
||||
/**
|
||||
* A json-pointer to a schema to use as a reference
|
||||
*/
|
||||
$ref: string;
|
||||
}
|
||||
|
||||
export interface AnySchema extends BaseSchema {
|
||||
}
|
||||
|
||||
export interface StringSchema extends BaseSchema {
|
||||
type: 'string';
|
||||
format?: string;
|
||||
}
|
||||
|
||||
export interface IntegerSchema extends BaseSchema {
|
||||
type: 'integer';
|
||||
}
|
||||
|
||||
export interface NumberSchema extends BaseSchema {
|
||||
type: 'number';
|
||||
}
|
||||
|
||||
export interface NullSchema extends BaseSchema {
|
||||
type: 'null';
|
||||
}
|
||||
|
||||
export interface BooleanSchema extends BaseSchema {
|
||||
type: 'boolean';
|
||||
}
|
||||
|
||||
export interface ArraySchema extends BaseSchema {
|
||||
type: 'array';
|
||||
/**
|
||||
* The schema for the items in the array
|
||||
*/
|
||||
items: Schema | {}
|
||||
}
|
||||
|
||||
export interface TupleSchema extends BaseSchema {
|
||||
type: 'array';
|
||||
/**
|
||||
* The schemas for the items in the tuple
|
||||
*/
|
||||
items: Schema[];
|
||||
}
|
||||
|
||||
type ObjectProperties = Record<string, Partial<Schema>> & {
|
||||
anyOf?: ObjectProperties[];
|
||||
allOf?: ObjectProperties[];
|
||||
if?: ObjectProperties;
|
||||
then?: ObjectProperties;
|
||||
else?: ObjectProperties;
|
||||
}
|
||||
|
||||
export interface ObjectSchema extends BaseSchema {
|
||||
type: 'object';
|
||||
/**
|
||||
* Describe the properties of the object
|
||||
*/
|
||||
properties?: ObjectProperties;
|
||||
/**
|
||||
* The required properties of the object
|
||||
*/
|
||||
required?: string[];
|
||||
/**
|
||||
* Describe properties that have keys following a given pattern
|
||||
*/
|
||||
patternProperties?: ObjectProperties;
|
||||
/**
|
||||
* Specifies whether additional properties on the object are allowed, and optionally what schema they should
|
||||
* adhere to
|
||||
* @default false
|
||||
*/
|
||||
additionalProperties?: Schema | boolean;
|
||||
}
|
||||
|
||||
export type Schema =
|
||||
| RefSchema
|
||||
| StringSchema
|
||||
| IntegerSchema
|
||||
| NumberSchema
|
||||
| NullSchema
|
||||
| BooleanSchema
|
||||
| ArraySchema
|
||||
| TupleSchema
|
||||
| ObjectSchema
|
||||
|
||||
export interface Options {
|
||||
/**
|
||||
* Optionally add an external definition to reference from your schema
|
||||
*/
|
||||
schema?: Record<string, Schema>
|
||||
/**
|
||||
* Configure Ajv, which is used to evaluate conditional schemas and combined (anyOf) schemas
|
||||
*/
|
||||
ajv?: AjvOptions
|
||||
/**
|
||||
* Optionally configure how the integer will be rounded
|
||||
*
|
||||
* @default 'trunc'
|
||||
*/
|
||||
rounding?: 'ceil' | 'floor' | 'round' | 'trunc'
|
||||
/**
|
||||
* @deprecated
|
||||
* Enable debug mode. Please use `mode: "debug"` instead
|
||||
*/
|
||||
debugMode?: boolean
|
||||
/**
|
||||
* Running mode of fast-json-stringify
|
||||
*/
|
||||
mode?: 'debug' | 'standalone'
|
||||
|
||||
/**
|
||||
* Large arrays are defined as arrays containing, by default, `20000`
|
||||
* elements or more. That value can be adjusted via the option parameter
|
||||
* `largeArraySize`.
|
||||
*
|
||||
* @default 20000
|
||||
*/
|
||||
largeArraySize?: number | string | BigInt
|
||||
|
||||
/**
|
||||
* Specify the function on how large Arrays should be stringified.
|
||||
*
|
||||
* @default 'default'
|
||||
*/
|
||||
largeArrayMechanism?: 'default' | 'json-stringify'
|
||||
}
|
||||
|
||||
export const validLargeArrayMechanisms: string[]
|
||||
export function restore (value: <TDoc extends object = object>(doc: TDoc) => string): ReturnType<Build>
|
||||
|
||||
export const build: Build
|
||||
export { build as default }
|
||||
}
|
||||
|
||||
interface DebugOption extends build.Options {
|
||||
mode: 'debug'
|
||||
}
|
||||
|
||||
interface DeprecateDebugOption extends build.Options {
|
||||
debugMode: true
|
||||
}
|
||||
|
||||
interface StandaloneOption extends build.Options {
|
||||
mode: 'standalone'
|
||||
}
|
||||
|
||||
type StringCoercible = string | Date | RegExp
|
||||
type IntegerCoercible = number | BigInt
|
||||
|
||||
/**
|
||||
* Build a stringify function using a schema of the documents that should be stringified
|
||||
* @param schema The schema used to stringify values
|
||||
* @param options The options to use (optional)
|
||||
*/
|
||||
declare function build (schema: build.AnySchema, options: DebugOption): { code: string, ajv: Ajv }
|
||||
declare function build (schema: build.AnySchema, options: DeprecateDebugOption): { code: string, ajv: Ajv }
|
||||
declare function build (schema: build.AnySchema, options: StandaloneOption): string
|
||||
declare function build (schema: build.AnySchema, options?: build.Options): <TDoc = any>(doc: TDoc) => any
|
||||
declare function build (schema: build.StringSchema, options?: build.Options): <TDoc extends StringCoercible = StringCoercible>(doc: TDoc) => string
|
||||
declare function build (schema: build.IntegerSchema | build.NumberSchema, options?: build.Options): <TDoc extends IntegerCoercible = IntegerCoercible>(doc: TDoc) => string
|
||||
declare function build (schema: build.NullSchema, options?: build.Options): <TDoc extends null = null>(doc: TDoc) => 'null'
|
||||
declare function build (schema: build.BooleanSchema, options?: build.Options): <TDoc extends boolean = boolean>(doc: TDoc) => string
|
||||
declare function build (schema: build.ArraySchema | build.TupleSchema, options?: build.Options): <TDoc extends any[]= any[]>(doc: TDoc) => string
|
||||
declare function build (schema: build.ObjectSchema, options?: build.Options): <TDoc extends object = object>(doc: TDoc) => string
|
||||
declare function build (schema: build.Schema, options?: build.Options): <TDoc = object | any[] | string | number | boolean | null> (doc: TDoc) => string
|
||||
|
||||
export = build
|
||||
259
node_modules/fast-json-stringify/types/index.test-d.ts
generated
vendored
Normal file
259
node_modules/fast-json-stringify/types/index.test-d.ts
generated
vendored
Normal file
@@ -0,0 +1,259 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Test using this disabled, see https://github.com/fastify/fast-json-stringify/pull/683
|
||||
import Ajv from 'ajv'
|
||||
import build, { restore, Schema, validLargeArrayMechanisms } from '..'
|
||||
import { expectError, expectType } from 'tsd'
|
||||
|
||||
// Number schemas
|
||||
build({
|
||||
type: 'number'
|
||||
})(25)
|
||||
build({
|
||||
type: 'integer'
|
||||
})(-5)
|
||||
build({
|
||||
type: 'integer'
|
||||
})(5n)
|
||||
|
||||
build({
|
||||
type: 'number'
|
||||
}, { rounding: 'ceil' })
|
||||
build({
|
||||
type: 'number'
|
||||
}, { rounding: 'floor' })
|
||||
build({
|
||||
type: 'number'
|
||||
}, { rounding: 'round' })
|
||||
build({
|
||||
type: 'number'
|
||||
}, { rounding: 'trunc' })
|
||||
expectError(build({
|
||||
type: 'number'
|
||||
}, { rounding: 'invalid' }))
|
||||
|
||||
// String schema
|
||||
build({
|
||||
type: 'string'
|
||||
})('foobar')
|
||||
|
||||
// Boolean schema
|
||||
build({
|
||||
type: 'boolean'
|
||||
})(true)
|
||||
|
||||
// Null schema
|
||||
build({
|
||||
type: 'null'
|
||||
})(null)
|
||||
|
||||
// Array schemas
|
||||
build({
|
||||
type: 'array',
|
||||
items: { type: 'number' }
|
||||
})([25])
|
||||
build({
|
||||
type: 'array',
|
||||
items: [{ type: 'string' }, { type: 'integer' }]
|
||||
})(['hello', 42])
|
||||
|
||||
// Object schemas
|
||||
build({
|
||||
type: 'object'
|
||||
})({})
|
||||
build({
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'integer' }
|
||||
},
|
||||
required: ['foo'],
|
||||
patternProperties: {
|
||||
'baz*': { type: 'null' }
|
||||
},
|
||||
additionalProperties: {
|
||||
type: 'boolean'
|
||||
}
|
||||
})({ foo: 'bar' })
|
||||
build({
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'integer' }
|
||||
},
|
||||
required: ['foo'],
|
||||
patternProperties: {
|
||||
'baz*': { type: 'null' }
|
||||
},
|
||||
additionalProperties: {
|
||||
type: 'boolean'
|
||||
}
|
||||
}, { rounding: 'floor' })({ foo: 'bar' })
|
||||
|
||||
// Reference schemas
|
||||
build({
|
||||
title: 'Example Schema',
|
||||
definitions: {
|
||||
num: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
int: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
},
|
||||
str: {
|
||||
type: 'string'
|
||||
},
|
||||
def: {
|
||||
type: 'null'
|
||||
}
|
||||
},
|
||||
type: 'object',
|
||||
properties: {
|
||||
nickname: {
|
||||
$ref: '#/definitions/str'
|
||||
}
|
||||
},
|
||||
patternProperties: {
|
||||
num: {
|
||||
$ref: '#/definitions/num'
|
||||
}
|
||||
},
|
||||
additionalProperties: {
|
||||
$ref: '#/definitions/def'
|
||||
}
|
||||
})({ nickname: '', num: { int: 5 }, other: null })
|
||||
|
||||
// Conditional/Combined schemas
|
||||
build({
|
||||
title: 'Conditional/Combined Schema',
|
||||
type: 'object',
|
||||
properties: {
|
||||
something: {
|
||||
anyOf: [
|
||||
{ type: 'string' },
|
||||
{ type: 'boolean' }
|
||||
]
|
||||
}
|
||||
},
|
||||
if: {
|
||||
properties: {
|
||||
something: { type: 'string' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
somethingElse: { type: 'number' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
somethingElse: { type: 'null' }
|
||||
}
|
||||
}
|
||||
})({ something: 'a string', somethingElse: 42 })
|
||||
|
||||
// String schema with format
|
||||
|
||||
build({
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
})(new Date())
|
||||
|
||||
/*
|
||||
This overload doesn't work yet -
|
||||
TypeScript chooses the generic for the schema
|
||||
before it chooses the overload for the options
|
||||
parameter.
|
||||
let str: string, ajv: Ajv
|
||||
str = build({
|
||||
type: 'number'
|
||||
}, { debugMode: true }).code
|
||||
ajv = build({
|
||||
type: 'number'
|
||||
}, { debugMode: true }).ajv
|
||||
str = build({
|
||||
type: 'number'
|
||||
}, { mode: 'debug' }).code
|
||||
ajv = build({
|
||||
type: 'number'
|
||||
}, { mode: 'debug' }).ajv
|
||||
str = build({
|
||||
type: 'number'
|
||||
}, { mode: 'standalone' })
|
||||
*/
|
||||
|
||||
const debugCompiled = build({
|
||||
title: 'default string',
|
||||
type: 'object',
|
||||
properties: {
|
||||
firstName: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}, { mode: 'debug' })
|
||||
expectType<ReturnType<typeof build>>(build.restore(debugCompiled))
|
||||
expectType<ReturnType<typeof build>>(restore(debugCompiled))
|
||||
|
||||
expectType<string[]>(build.validLargeArrayMechanisms)
|
||||
expectType<string[]>(validLargeArrayMechanisms)
|
||||
|
||||
/**
|
||||
* Schema inference
|
||||
*/
|
||||
|
||||
// With inference
|
||||
interface InferenceSchema {
|
||||
id: string;
|
||||
a?: number;
|
||||
}
|
||||
|
||||
const stringify3 = build({
|
||||
type: 'object',
|
||||
properties: { a: { type: 'string' } },
|
||||
})
|
||||
stringify3<InferenceSchema>({ id: '123' })
|
||||
stringify3<InferenceSchema>({ a: 123, id: '123' })
|
||||
expectError(stringify3<InferenceSchema>({ anotherOne: 'bar' }))
|
||||
expectError(stringify3<Schema>({ a: 'bar' }))
|
||||
|
||||
// Without inference
|
||||
const stringify4 = build({
|
||||
type: 'object',
|
||||
properties: { a: { type: 'string' } },
|
||||
})
|
||||
stringify4({ id: '123' })
|
||||
stringify4({ a: 123, id: '123' })
|
||||
stringify4({ anotherOne: 'bar' })
|
||||
stringify4({ a: 'bar' })
|
||||
|
||||
// Without inference - string type
|
||||
const stringify5 = build({
|
||||
type: 'string',
|
||||
})
|
||||
stringify5('foo')
|
||||
expectError(stringify5({ id: '123' }))
|
||||
|
||||
// Without inference - null type
|
||||
const stringify6 = build({
|
||||
type: 'null',
|
||||
})
|
||||
stringify6(null)
|
||||
expectError(stringify6('a string'))
|
||||
|
||||
// Without inference - boolean type
|
||||
const stringify7 = build({
|
||||
type: 'boolean',
|
||||
})
|
||||
stringify7(true)
|
||||
expectError(stringify7('a string'))
|
||||
|
||||
// largeArrayMechanism
|
||||
|
||||
build({}, { largeArrayMechanism: 'json-stringify' })
|
||||
build({}, { largeArrayMechanism: 'default' })
|
||||
expectError(build({} as Schema, { largeArrayMechanism: 'invalid' }))
|
||||
|
||||
build({}, { largeArraySize: 2000 })
|
||||
build({}, { largeArraySize: '2e4' })
|
||||
build({}, { largeArraySize: 2n })
|
||||
expectError(build({} as Schema, { largeArraySize: ['asdf'] }))
|
||||
Reference in New Issue
Block a user