我的node项目首次提交!!!
This commit is contained in:
2
node_modules/@fastify/ajv-compiler/.gitattributes
generated
vendored
Normal file
2
node_modules/@fastify/ajv-compiler/.gitattributes
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Set default behavior to automatically convert line endings
|
||||
* text=auto eol=lf
|
||||
21
node_modules/@fastify/ajv-compiler/.github/.stale.yml
generated
vendored
Normal file
21
node_modules/@fastify/ajv-compiler/.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
|
||||
13
node_modules/@fastify/ajv-compiler/.github/dependabot.yml
generated
vendored
Normal file
13
node_modules/@fastify/ajv-compiler/.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: "weekly"
|
||||
open-pull-requests-limit: 10
|
||||
8
node_modules/@fastify/ajv-compiler/.github/tests_checker.yml
generated
vendored
Normal file
8
node_modules/@fastify/ajv-compiler/.github/tests_checker.yml
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
comment: |
|
||||
Hello! Thank you for contributing!
|
||||
It appears that you have changed the code, but the tests that verify your change are missing. Could you please add them?
|
||||
fileExtensions:
|
||||
- '.ts'
|
||||
- '.js'
|
||||
|
||||
testDir: 'test'
|
||||
26
node_modules/@fastify/ajv-compiler/.github/workflows/ci.yml
generated
vendored
Normal file
26
node_modules/@fastify/ajv-compiler/.github/workflows/ci.yml
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
- next
|
||||
- 'v*'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
|
||||
env:
|
||||
TZ: 'UTC'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
uses: fastify/workflows/.github/workflows/plugins-ci.yml@v5
|
||||
with:
|
||||
lint: true
|
||||
license-check: true
|
||||
2
node_modules/@fastify/ajv-compiler/.taprc
generated
vendored
Normal file
2
node_modules/@fastify/ajv-compiler/.taprc
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
files:
|
||||
- test/**/*.test.js
|
||||
24
node_modules/@fastify/ajv-compiler/LICENSE
generated
vendored
Normal file
24
node_modules/@fastify/ajv-compiler/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) The Fastify Team
|
||||
|
||||
The Fastify team members are listed at https://github.com/fastify/fastify#team
|
||||
and in the README file.
|
||||
|
||||
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.
|
||||
237
node_modules/@fastify/ajv-compiler/README.md
generated
vendored
Normal file
237
node_modules/@fastify/ajv-compiler/README.md
generated
vendored
Normal file
@@ -0,0 +1,237 @@
|
||||
# @fastify/ajv-compiler
|
||||
|
||||
[](https://github.com/fastify/ajv-compiler/actions/workflows/ci.yml)
|
||||
[](https://www.npmjs.com/package/@fastify/ajv-compiler)
|
||||
[](https://github.com/neostandard/neostandard)
|
||||
|
||||
This module manages the [`ajv`](https://www.npmjs.com/package/ajv) instances for the Fastify framework.
|
||||
It isolates the `ajv` dependency so that the AJV version is not tightly coupled to the Fastify version.
|
||||
This allows the user to decide which version of AJV to use in their Fastify-based application.
|
||||
|
||||
|
||||
## Versions
|
||||
|
||||
| `@fastify/ajv-compiler` | `ajv` | Default in `fastify` |
|
||||
|------------------------:|------:|---------------------:|
|
||||
| v4.x | v8.x | ^5.x |
|
||||
| v3.x | v8.x | ^4.x |
|
||||
| v2.x | v8.x | - |
|
||||
| v1.x | v6.x | ^3.14 |
|
||||
|
||||
### AJV Configuration
|
||||
|
||||
The Fastify's default [`ajv` options](https://github.com/ajv-validator/ajv/tree/v6#options) are:
|
||||
|
||||
```js
|
||||
{
|
||||
coerceTypes: 'array',
|
||||
useDefaults: true,
|
||||
removeAdditional: true,
|
||||
uriResolver: require('fast-uri'),
|
||||
addUsedSchema: false,
|
||||
// Explicitly set allErrors to `false`.
|
||||
// When set to `true`, a DoS attack is possible.
|
||||
allErrors: false
|
||||
}
|
||||
```
|
||||
|
||||
Moreover, the [`ajv-formats`](https://www.npmjs.com/package/ajv-formats) module is included by default.
|
||||
If you need to customize it, check the _usage_ section below.
|
||||
|
||||
To customize the `ajv` options, see how in the [Fastify documentation](https://fastify.dev/docs/latest/Reference/Server/#ajv).
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
This module is already used as default by Fastify.
|
||||
If you need to provide your server instance with a different version, refer to [the Fastify docs](https://fastify.dev/docs/latest/Reference/Server/#schemacontroller).
|
||||
|
||||
### Customize the `ajv-formats` plugin
|
||||
|
||||
The `format` keyword is not part of the official `ajv` module since v7. To use it, you need to install the `ajv-formats` module and this module
|
||||
does it for you with the default configuration.
|
||||
|
||||
If you need to configure the `ajv-formats` plugin you can do it using the standard Fastify configuration:
|
||||
|
||||
```js
|
||||
const app = fastify({
|
||||
ajv: {
|
||||
plugins: [[require('ajv-formats'), { mode: 'fast' }]]
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
In this way, your setup will have precedence over the `@fastify/ajv-compiler` default configuration.
|
||||
|
||||
### Customize the `ajv` instance
|
||||
|
||||
If you need to customize the `ajv` instance and take full control of its configuration, you can do it by
|
||||
using the `onCreate` option in the Fastify configuration that accepts a synchronous function that receives the `ajv` instance:
|
||||
|
||||
```js
|
||||
const app = fastify({
|
||||
ajv: {
|
||||
onCreate: (ajv) => {
|
||||
// Modify the ajv instance as you need.
|
||||
ajv.addFormat('myFormat', (data) => typeof data === 'string')
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Fastify with JTD
|
||||
|
||||
The [JSON Type Definition](https://jsontypedef.com/) feature is supported by AJV v8.x and you can benefit from it in your Fastify application.
|
||||
|
||||
With Fastify v3.20.x and higher, you can use the `@fastify/ajv-compiler` module to load JSON Type Definitions like so:
|
||||
|
||||
```js
|
||||
const factory = require('@fastify/ajv-compiler')()
|
||||
|
||||
const app = fastify({
|
||||
jsonShorthand: false,
|
||||
ajv: {
|
||||
customOptions: { }, // additional JTD options
|
||||
mode: 'JTD'
|
||||
},
|
||||
schemaController: {
|
||||
compilersFactory: {
|
||||
buildValidator: factory
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The default AJV JTD options are the same as [Fastify's default options](#AJV-Configuration).
|
||||
|
||||
#### Fastify with JTD and serialization
|
||||
|
||||
You can use JTD Schemas to serialize your response object too:
|
||||
|
||||
```js
|
||||
const factoryValidator = require('@fastify/ajv-compiler')()
|
||||
const factorySerializer = require('@fastify/ajv-compiler')({ jtdSerializer: true })
|
||||
|
||||
const app = fastify({
|
||||
jsonShorthand: false,
|
||||
ajv: {
|
||||
customOptions: { }, // additional JTD options
|
||||
mode: 'JTD'
|
||||
},
|
||||
schemaController: {
|
||||
compilersFactory: {
|
||||
buildValidator: factoryValidator,
|
||||
buildSerializer: factorySerializer
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
### AJV Standalone
|
||||
|
||||
AJV v8 introduced a [standalone feature](https://ajv.js.org/standalone.html) that lets you pre-compile your schemas and use them in your application for a faster startup.
|
||||
|
||||
To use this feature, you must be aware of the following:
|
||||
|
||||
1. You must generate and save the application's compiled schemas.
|
||||
2. Read the compiled schemas from the file and provide them back to your Fastify application.
|
||||
|
||||
|
||||
#### Generate and save the compiled schemas
|
||||
|
||||
Fastify helps you to generate the validation schemas functions and it is your choice to save them where you want.
|
||||
To accomplish this, you must use a new compiler: `StandaloneValidator`.
|
||||
|
||||
You must provide 2 parameters to this compiler:
|
||||
|
||||
- `readMode: false`: a boolean to indicate that you want to generate the schemas functions string.
|
||||
- `storeFunction`" a sync function that must store the source code of the schemas functions. You may provide an async function too, but you must manage errors.
|
||||
|
||||
When `readMode: false`, **the compiler is meant to be used in development ONLY**.
|
||||
|
||||
|
||||
```js
|
||||
const { StandaloneValidator } = require('@fastify/ajv-compiler')
|
||||
const factory = StandaloneValidator({
|
||||
readMode: false,
|
||||
storeFunction (routeOpts, schemaValidationCode) {
|
||||
// routeOpts is like: { schema, method, url, httpPart }
|
||||
// schemaValidationCode is a string source code that is the compiled schema function
|
||||
const fileName = generateFileName(routeOpts)
|
||||
fs.writeFileSync(path.join(__dirname, fileName), schemaValidationCode)
|
||||
}
|
||||
})
|
||||
|
||||
const app = fastify({
|
||||
jsonShorthand: false,
|
||||
schemaController: {
|
||||
compilersFactory: {
|
||||
buildValidator: factory
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// ... add all your routes with schemas ...
|
||||
|
||||
app.ready().then(() => {
|
||||
// at this stage all your schemas are compiled and stored in the file system
|
||||
// now it is important to turn off the readMode
|
||||
})
|
||||
```
|
||||
|
||||
#### Read the compiled schemas functions
|
||||
|
||||
At this stage, you should have a file for every route's schema.
|
||||
To use them, you must use the `StandaloneValidator` with the parameters:
|
||||
|
||||
- `readMode: true`: a boolean to indicate that you want to read and use the schemas functions string.
|
||||
- `restoreFunction`" a sync function that must return a function to validate the route.
|
||||
|
||||
Important keep away before you continue reading the documentation:
|
||||
|
||||
- when you use the `readMode: true`, the application schemas are not compiled (they are ignored). So, if you change your schemas, you must recompile them!
|
||||
- as you can see, you must relate the route's schema to the file name using the `routeOpts` object. You may use the `routeOpts.schema.$id` field to do so, it is up to you to define a unique schema identifier.
|
||||
|
||||
```js
|
||||
const { StandaloneValidator } = require('@fastify/ajv-compiler')
|
||||
const factory = StandaloneValidator({
|
||||
readMode: true,
|
||||
restoreFunction (routeOpts) {
|
||||
// routeOpts is like: { schema, method, url, httpPart }
|
||||
const fileName = generateFileName(routeOpts)
|
||||
return require(path.join(__dirname, fileName))
|
||||
}
|
||||
})
|
||||
|
||||
const app = fastify({
|
||||
jsonShorthand: false,
|
||||
schemaController: {
|
||||
compilersFactory: {
|
||||
buildValidator: factory
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// ... add all your routes with schemas as before...
|
||||
|
||||
app.listen({ port: 3000 })
|
||||
```
|
||||
|
||||
### How it works
|
||||
|
||||
This module provides a factory function to produce [Validator Compilers](https://fastify.dev/docs/latest/Reference/Server/#validatorcompiler) functions.
|
||||
|
||||
The Fastify factory function is just one per server instance and it is called for every encapsulated context created by the application through the `fastify.register()` call.
|
||||
|
||||
Every Validator Compiler produced has a dedicated AJV instance, so this factory will try to produce as less as possible AJV instances to reduce the memory footprint and the startup time.
|
||||
|
||||
The variables involved to choose if a Validator Compiler can be reused are:
|
||||
|
||||
- the AJV configuration: it is [one per server](https://fastify.dev/docs/latest/Reference/Server/#ajv)
|
||||
- the external JSON schemas: once a new schema is added to a fastify's context, calling `fastify.addSchema()`, it will cause a new AJV initialization
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Licensed under [MIT](./LICENSE).
|
||||
37
node_modules/@fastify/ajv-compiler/benchmark/small-object.mjs
generated
vendored
Normal file
37
node_modules/@fastify/ajv-compiler/benchmark/small-object.mjs
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
import cronometro from 'cronometro'
|
||||
|
||||
import fjs from 'fast-json-stringify'
|
||||
import AjvCompiler from '../index.js'
|
||||
|
||||
const fjsSerialize = buildFJSSerializerFunction({
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { type: 'string' },
|
||||
name: { type: 'string' }
|
||||
}
|
||||
})
|
||||
const ajvSerialize = buildAJVSerializerFunction({
|
||||
properties: {
|
||||
hello: { type: 'string' },
|
||||
name: { type: 'string' }
|
||||
}
|
||||
})
|
||||
|
||||
await cronometro({
|
||||
'fast-json-stringify': function () {
|
||||
fjsSerialize({ hello: 'Ciao', name: 'Manuel' })
|
||||
},
|
||||
'ajv serializer': function () {
|
||||
ajvSerialize({ hello: 'Ciao', name: 'Manuel' })
|
||||
}
|
||||
})
|
||||
|
||||
function buildFJSSerializerFunction (schema) {
|
||||
return fjs(schema)
|
||||
}
|
||||
|
||||
function buildAJVSerializerFunction (schema) {
|
||||
const factory = AjvCompiler({ jtdSerializer: true })
|
||||
const compiler = factory({}, { customOptions: {} })
|
||||
return compiler({ schema })
|
||||
}
|
||||
6
node_modules/@fastify/ajv-compiler/eslint.config.js
generated
vendored
Normal file
6
node_modules/@fastify/ajv-compiler/eslint.config.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = require('neostandard')({
|
||||
ignores: require('neostandard').resolveIgnoresFromGitignore(),
|
||||
ts: true
|
||||
})
|
||||
53
node_modules/@fastify/ajv-compiler/index.js
generated
vendored
Normal file
53
node_modules/@fastify/ajv-compiler/index.js
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
'use strict'
|
||||
|
||||
const AjvReference = Symbol.for('fastify.ajv-compiler.reference')
|
||||
const ValidatorCompiler = require('./lib/validator-compiler')
|
||||
const SerializerCompiler = require('./lib/serializer-compiler')
|
||||
|
||||
function AjvCompiler (opts) {
|
||||
const validatorPool = new Map()
|
||||
const serializerPool = new Map()
|
||||
|
||||
if (opts && opts.jtdSerializer === true) {
|
||||
return function buildSerializerFromPool (externalSchemas, serializerOpts) {
|
||||
const uniqueAjvKey = getPoolKey({}, serializerOpts)
|
||||
if (serializerPool.has(uniqueAjvKey)) {
|
||||
return serializerPool.get(uniqueAjvKey)
|
||||
}
|
||||
|
||||
const compiler = new SerializerCompiler(externalSchemas, serializerOpts)
|
||||
const ret = compiler.buildSerializerFunction.bind(compiler)
|
||||
serializerPool.set(uniqueAjvKey, ret)
|
||||
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
return function buildCompilerFromPool (externalSchemas, options) {
|
||||
const uniqueAjvKey = getPoolKey(externalSchemas, options.customOptions)
|
||||
if (validatorPool.has(uniqueAjvKey)) {
|
||||
return validatorPool.get(uniqueAjvKey)
|
||||
}
|
||||
|
||||
const compiler = new ValidatorCompiler(externalSchemas, options)
|
||||
const ret = compiler.buildValidatorFunction.bind(compiler)
|
||||
validatorPool.set(uniqueAjvKey, ret)
|
||||
|
||||
if (options.customOptions.code !== undefined) {
|
||||
ret[AjvReference] = compiler
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
function getPoolKey (externalSchemas, options) {
|
||||
const externals = JSON.stringify(externalSchemas)
|
||||
const ajvConfig = JSON.stringify(options)
|
||||
return `${externals}${ajvConfig}`
|
||||
}
|
||||
module.exports = AjvCompiler
|
||||
module.exports.default = AjvCompiler
|
||||
module.exports.AjvCompiler = AjvCompiler
|
||||
module.exports.AjvReference = AjvReference
|
||||
module.exports.StandaloneValidator = require('./standalone')
|
||||
14
node_modules/@fastify/ajv-compiler/lib/default-ajv-options.js
generated
vendored
Normal file
14
node_modules/@fastify/ajv-compiler/lib/default-ajv-options.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict'
|
||||
|
||||
const fastUri = require('fast-uri')
|
||||
|
||||
module.exports = Object.freeze({
|
||||
coerceTypes: 'array',
|
||||
useDefaults: true,
|
||||
removeAdditional: true,
|
||||
uriResolver: fastUri,
|
||||
addUsedSchema: false,
|
||||
// Explicitly set allErrors to `false`.
|
||||
// When set to `true`, a DoS attack is possible.
|
||||
allErrors: false
|
||||
})
|
||||
27
node_modules/@fastify/ajv-compiler/lib/serializer-compiler.js
generated
vendored
Normal file
27
node_modules/@fastify/ajv-compiler/lib/serializer-compiler.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
'use strict'
|
||||
|
||||
const AjvJTD = require('ajv/dist/jtd')
|
||||
|
||||
const defaultAjvOptions = require('./default-ajv-options')
|
||||
|
||||
class SerializerCompiler {
|
||||
constructor (_externalSchemas, options) {
|
||||
this.ajv = new AjvJTD(Object.assign({}, defaultAjvOptions, options))
|
||||
|
||||
/**
|
||||
* https://ajv.js.org/json-type-definition.html#ref-form
|
||||
* Unlike JSON Schema, JTD does not allow to reference:
|
||||
* - any schema fragment other than root level definitions member
|
||||
* - root of the schema - there is another way to define a self-recursive schema (see Example 2)
|
||||
* - another schema file (but you can still combine schemas from multiple files using JavaScript).
|
||||
*
|
||||
* So we ignore the externalSchemas parameter.
|
||||
*/
|
||||
}
|
||||
|
||||
buildSerializerFunction ({ schema/*, method, url, httpStatus */ }) {
|
||||
return this.ajv.compileSerializer(schema)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SerializerCompiler
|
||||
58
node_modules/@fastify/ajv-compiler/lib/validator-compiler.js
generated
vendored
Normal file
58
node_modules/@fastify/ajv-compiler/lib/validator-compiler.js
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
'use strict'
|
||||
|
||||
const Ajv = require('ajv').default
|
||||
const AjvJTD = require('ajv/dist/jtd')
|
||||
|
||||
const defaultAjvOptions = require('./default-ajv-options')
|
||||
|
||||
class ValidatorCompiler {
|
||||
constructor (externalSchemas, options) {
|
||||
// This instance of Ajv is private
|
||||
// it should not be customized or used
|
||||
if (options.mode === 'JTD') {
|
||||
this.ajv = new AjvJTD(Object.assign({}, defaultAjvOptions, options.customOptions))
|
||||
} else {
|
||||
this.ajv = new Ajv(Object.assign({}, defaultAjvOptions, options.customOptions))
|
||||
}
|
||||
|
||||
let addFormatPlugin = true
|
||||
if (options.plugins && options.plugins.length > 0) {
|
||||
for (const plugin of options.plugins) {
|
||||
if (Array.isArray(plugin)) {
|
||||
addFormatPlugin = addFormatPlugin && plugin[0].name !== 'formatsPlugin'
|
||||
plugin[0](this.ajv, plugin[1])
|
||||
} else {
|
||||
addFormatPlugin = addFormatPlugin && plugin.name !== 'formatsPlugin'
|
||||
plugin(this.ajv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addFormatPlugin) {
|
||||
require('ajv-formats')(this.ajv)
|
||||
}
|
||||
|
||||
options.onCreate?.(this.ajv)
|
||||
|
||||
const sourceSchemas = Object.values(externalSchemas)
|
||||
for (const extSchema of sourceSchemas) {
|
||||
this.ajv.addSchema(extSchema)
|
||||
}
|
||||
}
|
||||
|
||||
buildValidatorFunction ({ schema/*, method, url, httpPart */ }) {
|
||||
// Ajv does not support compiling two schemas with the same
|
||||
// id inside the same instance. Therefore if we have already
|
||||
// compiled the schema with the given id, we just return it.
|
||||
if (schema.$id) {
|
||||
const stored = this.ajv.getSchema(schema.$id)
|
||||
if (stored) {
|
||||
return stored
|
||||
}
|
||||
}
|
||||
|
||||
return this.ajv.compile(schema)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ValidatorCompiler
|
||||
84
node_modules/@fastify/ajv-compiler/package.json
generated
vendored
Normal file
84
node_modules/@fastify/ajv-compiler/package.json
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"name": "@fastify/ajv-compiler",
|
||||
"version": "4.0.2",
|
||||
"description": "Build and manage the AJV instances for the fastify framework",
|
||||
"main": "index.js",
|
||||
"type": "commonjs",
|
||||
"types": "types/index.d.ts",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint",
|
||||
"lint:fix": "eslint --fix",
|
||||
"unit": "tap",
|
||||
"test": "npm run unit && npm run test:typescript",
|
||||
"test:typescript": "tsd",
|
||||
"ajv:compile": "ajv compile -s test/source.json -o test/validate_schema.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/fastify/ajv-compiler.git"
|
||||
},
|
||||
"keywords": [
|
||||
"ajv",
|
||||
"validator",
|
||||
"schema",
|
||||
"compiler",
|
||||
"fastify"
|
||||
],
|
||||
"author": "Manuel Spigolon <behemoth89@gmail.com> (https://github.com/Eomm)",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Matteo Collina",
|
||||
"email": "hello@matteocollina.com"
|
||||
},
|
||||
{
|
||||
"name": "Aras Abbasi",
|
||||
"email": "aras.abbasi@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "James Sumners",
|
||||
"url": "https://james.sumners.info"
|
||||
},
|
||||
{
|
||||
"name": "Frazer Smith",
|
||||
"email": "frazer.dev@icloud.com",
|
||||
"url": "https://github.com/fdawgs"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/fastify/ajv-compiler/issues"
|
||||
},
|
||||
"homepage": "https://github.com/fastify/ajv-compiler#readme",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fastify"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fastify"
|
||||
}
|
||||
],
|
||||
"devDependencies": {
|
||||
"ajv-cli": "^5.0.0",
|
||||
"ajv-errors": "^3.0.0",
|
||||
"ajv-i18n": "^4.2.0",
|
||||
"ajv-merge-patch": "^5.0.1",
|
||||
"cronometro": "^4.0.0",
|
||||
"eslint": "^9.17.0",
|
||||
"fastify": "^5.0.0",
|
||||
"neostandard": "^0.12.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"tap": "^19.0.0",
|
||||
"tsd": "^0.31.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": "^8.12.0",
|
||||
"ajv-formats": "^3.0.1",
|
||||
"fast-uri": "^3.0.0"
|
||||
}
|
||||
}
|
||||
44
node_modules/@fastify/ajv-compiler/standalone.js
generated
vendored
Normal file
44
node_modules/@fastify/ajv-compiler/standalone.js
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
'use strict'
|
||||
|
||||
const ValidatorSelector = require('./index')
|
||||
const standaloneCode = require('ajv/dist/standalone').default
|
||||
|
||||
function StandaloneValidator (options = { readMode: true }) {
|
||||
if (options.readMode === true && !options.restoreFunction) {
|
||||
throw new Error('You must provide a restoreFunction options when readMode ON')
|
||||
}
|
||||
|
||||
if (options.readMode !== true && !options.storeFunction) {
|
||||
throw new Error('You must provide a storeFunction options when readMode OFF')
|
||||
}
|
||||
|
||||
if (options.readMode === true) {
|
||||
// READ MODE: it behalf only in the restore function provided by the user
|
||||
return function wrapper () {
|
||||
return function (opts) {
|
||||
return options.restoreFunction(opts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WRITE MODE: it behalf on the default ValidatorSelector, wrapping the API to run the Ajv Standalone code generation
|
||||
const factory = ValidatorSelector()
|
||||
return function wrapper (externalSchemas, ajvOptions = {}) {
|
||||
if (!ajvOptions.customOptions || !ajvOptions.customOptions.code) {
|
||||
// to generate the validation source code, these options are mandatory
|
||||
ajvOptions.customOptions = Object.assign({}, ajvOptions.customOptions, { code: { source: true } })
|
||||
}
|
||||
|
||||
const compiler = factory(externalSchemas, ajvOptions)
|
||||
return function (opts) { // { schema/*, method, url, httpPart */ }
|
||||
const validationFunc = compiler(opts)
|
||||
|
||||
const schemaValidationCode = standaloneCode(compiler[ValidatorSelector.AjvReference].ajv, validationFunc)
|
||||
options.storeFunction(opts, schemaValidationCode)
|
||||
|
||||
return validationFunc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = StandaloneValidator
|
||||
0
node_modules/@fastify/ajv-compiler/test/.gitkeep
generated
vendored
Normal file
0
node_modules/@fastify/ajv-compiler/test/.gitkeep
generated
vendored
Normal file
59
node_modules/@fastify/ajv-compiler/test/duplicated-id-compile.test.js
generated
vendored
Normal file
59
node_modules/@fastify/ajv-compiler/test/duplicated-id-compile.test.js
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const AjvCompiler = require('../index')
|
||||
|
||||
const postSchema = Object.freeze({
|
||||
$schema: 'http://json-schema.org/draft-07/schema#',
|
||||
type: 'object',
|
||||
$id: 'http://mydomain.com/user',
|
||||
title: 'User schema',
|
||||
description: 'Contains all user fields',
|
||||
properties: {
|
||||
username: { type: 'string', minLength: 4 },
|
||||
firstName: { type: 'string', minLength: 1 },
|
||||
lastName: { type: 'string', minLength: 1 },
|
||||
email: { type: 'string' },
|
||||
password: { type: 'string', minLength: 6 },
|
||||
bio: { type: 'string' }
|
||||
},
|
||||
required: ['username', 'firstName', 'lastName', 'email', 'bio', 'password']
|
||||
})
|
||||
|
||||
const patchSchema = Object.freeze({
|
||||
$schema: 'http://json-schema.org/draft-07/schema#',
|
||||
type: 'object',
|
||||
$id: 'http://mydomain.com/user',
|
||||
title: 'User schema',
|
||||
description: 'Contains all user fields',
|
||||
properties: {
|
||||
firstName: { type: 'string', minLength: 1 },
|
||||
lastName: { type: 'string', minLength: 1 },
|
||||
bio: { type: 'string' }
|
||||
}
|
||||
})
|
||||
|
||||
const fastifyAjvOptionsDefault = Object.freeze({
|
||||
customOptions: {}
|
||||
})
|
||||
|
||||
t.test('must not store schema on compile', t => {
|
||||
t.plan(4)
|
||||
const factory = AjvCompiler()
|
||||
const compiler = factory({}, fastifyAjvOptionsDefault)
|
||||
const postFn = compiler({ schema: postSchema })
|
||||
const patchFn = compiler({ schema: patchSchema })
|
||||
|
||||
const resultForPost = postFn({})
|
||||
t.equal(resultForPost, false)
|
||||
t.has(postFn.errors, [
|
||||
{
|
||||
keyword: 'required',
|
||||
message: "must have required property 'username'"
|
||||
}
|
||||
])
|
||||
|
||||
const resultForPatch = patchFn({})
|
||||
t.ok(resultForPatch)
|
||||
t.notOk(patchFn.errors)
|
||||
})
|
||||
307
node_modules/@fastify/ajv-compiler/test/index.test.js
generated
vendored
Normal file
307
node_modules/@fastify/ajv-compiler/test/index.test.js
generated
vendored
Normal file
@@ -0,0 +1,307 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const fastify = require('fastify')
|
||||
const AjvCompiler = require('../index')
|
||||
|
||||
const sym = Symbol.for('fastify.ajv-compiler.reference')
|
||||
|
||||
const sampleSchema = Object.freeze({
|
||||
$id: 'example1',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' }
|
||||
}
|
||||
})
|
||||
|
||||
const externalSchemas1 = Object.freeze({})
|
||||
const externalSchemas2 = Object.freeze({
|
||||
foo: {
|
||||
$id: 'foo',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const fastifyAjvOptionsDefault = Object.freeze({
|
||||
customOptions: {}
|
||||
})
|
||||
|
||||
const fastifyJtdDefault = Object.freeze({
|
||||
customOptions: { },
|
||||
mode: 'JTD'
|
||||
})
|
||||
|
||||
const fastifyAjvOptionsCustom = Object.freeze({
|
||||
customOptions: {
|
||||
allErrors: true,
|
||||
removeAdditional: false
|
||||
},
|
||||
plugins: [
|
||||
require('ajv-formats'),
|
||||
[require('ajv-errors'), { singleError: false }]
|
||||
]
|
||||
})
|
||||
|
||||
t.test('basic usage', t => {
|
||||
t.plan(1)
|
||||
const factory = AjvCompiler()
|
||||
const compiler = factory(externalSchemas1, fastifyAjvOptionsDefault)
|
||||
const validatorFunc = compiler({ schema: sampleSchema })
|
||||
const result = validatorFunc({ name: 'hello' })
|
||||
t.equal(result, true)
|
||||
})
|
||||
|
||||
t.test('array coercion', t => {
|
||||
t.plan(2)
|
||||
const factory = AjvCompiler()
|
||||
const compiler = factory(externalSchemas1, fastifyAjvOptionsDefault)
|
||||
|
||||
const arraySchema = {
|
||||
$id: 'example1',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'array', items: { type: 'string' } }
|
||||
}
|
||||
}
|
||||
|
||||
const validatorFunc = compiler({ schema: arraySchema })
|
||||
|
||||
const inputObj = { name: 'hello' }
|
||||
t.equal(validatorFunc(inputObj), true)
|
||||
t.same(inputObj, { name: ['hello'] }, 'the name property should be coerced to an array')
|
||||
})
|
||||
|
||||
t.test('nullable default', t => {
|
||||
t.plan(2)
|
||||
const factory = AjvCompiler()
|
||||
const compiler = factory({}, fastifyAjvOptionsDefault)
|
||||
const validatorFunc = compiler({
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
nullable: { type: 'string', nullable: true },
|
||||
notNullable: { type: 'string' }
|
||||
}
|
||||
}
|
||||
})
|
||||
const input = { nullable: null, notNullable: null }
|
||||
const result = validatorFunc(input)
|
||||
t.equal(result, true)
|
||||
t.same(input, { nullable: null, notNullable: '' }, 'the notNullable field has been coerced')
|
||||
})
|
||||
|
||||
t.test('plugin loading', t => {
|
||||
t.plan(3)
|
||||
const factory = AjvCompiler()
|
||||
const compiler = factory(externalSchemas1, fastifyAjvOptionsCustom)
|
||||
const validatorFunc = compiler({
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
q: {
|
||||
type: 'string',
|
||||
format: 'date',
|
||||
formatMinimum: '2016-02-06',
|
||||
formatExclusiveMaximum: '2016-12-27'
|
||||
}
|
||||
},
|
||||
required: ['q'],
|
||||
errorMessage: 'hello world'
|
||||
}
|
||||
})
|
||||
const result = validatorFunc({ q: '2016-10-02' })
|
||||
t.equal(result, true)
|
||||
|
||||
const resultFail = validatorFunc({})
|
||||
t.equal(resultFail, false)
|
||||
t.equal(validatorFunc.errors[0].message, 'hello world')
|
||||
})
|
||||
|
||||
t.test('optimization - cache ajv instance', t => {
|
||||
t.plan(5)
|
||||
const factory = AjvCompiler()
|
||||
const compiler1 = factory(externalSchemas1, fastifyAjvOptionsDefault)
|
||||
const compiler2 = factory(externalSchemas1, fastifyAjvOptionsDefault)
|
||||
t.equal(compiler1, compiler2, 'same instance')
|
||||
t.same(compiler1, compiler2, 'same instance')
|
||||
|
||||
const compiler3 = factory(externalSchemas2, fastifyAjvOptionsDefault)
|
||||
t.not(compiler3, compiler1, 'new ajv instance when externa schema change')
|
||||
|
||||
const compiler4 = factory(externalSchemas1, fastifyAjvOptionsCustom)
|
||||
t.not(compiler4, compiler1, 'new ajv instance when externa schema change')
|
||||
t.not(compiler4, compiler3, 'new ajv instance when externa schema change')
|
||||
})
|
||||
|
||||
t.test('the onCreate callback can enhance the ajv instance', t => {
|
||||
t.plan(2)
|
||||
const factory = AjvCompiler()
|
||||
|
||||
const fastifyAjvCustomOptionsFormats = Object.freeze({
|
||||
onCreate (ajv) {
|
||||
for (const [formatName, format] of Object.entries(this.customOptions.formats)) {
|
||||
ajv.addFormat(formatName, format)
|
||||
}
|
||||
},
|
||||
customOptions: {
|
||||
formats: {
|
||||
date: /foo/
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const compiler1 = factory(externalSchemas1, fastifyAjvCustomOptionsFormats)
|
||||
const validatorFunc = compiler1({
|
||||
schema: {
|
||||
type: 'string',
|
||||
format: 'date'
|
||||
}
|
||||
})
|
||||
const result = validatorFunc('foo')
|
||||
t.equal(result, true)
|
||||
|
||||
const resultFail = validatorFunc('2016-10-02')
|
||||
t.equal(resultFail, false)
|
||||
})
|
||||
|
||||
// https://github.com/fastify/fastify/pull/2969
|
||||
t.test('compile same $id when in external schema', t => {
|
||||
t.plan(3)
|
||||
const factory = AjvCompiler()
|
||||
|
||||
const base = {
|
||||
$id: 'urn:schema:base',
|
||||
definitions: {
|
||||
hello: { type: 'string' }
|
||||
},
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { $ref: '#/definitions/hello' }
|
||||
}
|
||||
}
|
||||
|
||||
const refSchema = {
|
||||
$id: 'urn:schema:ref',
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { $ref: 'urn:schema:base#/definitions/hello' }
|
||||
}
|
||||
}
|
||||
|
||||
const compiler = factory({
|
||||
[base.$id]: base,
|
||||
[refSchema.$id]: refSchema
|
||||
|
||||
}, fastifyAjvOptionsDefault)
|
||||
|
||||
t.notOk(compiler[sym], 'the ajv reference do not exists if code is not activated')
|
||||
|
||||
const validatorFunc1 = compiler({
|
||||
schema: {
|
||||
$id: 'urn:schema:ref'
|
||||
}
|
||||
})
|
||||
|
||||
const validatorFunc2 = compiler({
|
||||
schema: {
|
||||
$id: 'urn:schema:ref'
|
||||
}
|
||||
})
|
||||
|
||||
t.pass('the compile does not fail if the schema compiled is already in the external schemas')
|
||||
t.equal(validatorFunc1, validatorFunc2, 'the returned function is the same')
|
||||
})
|
||||
|
||||
t.test('JTD MODE', t => {
|
||||
t.plan(2)
|
||||
|
||||
t.test('compile jtd schema', t => {
|
||||
t.plan(4)
|
||||
const factory = AjvCompiler()
|
||||
|
||||
const jtdSchema = {
|
||||
discriminator: 'version',
|
||||
mapping: {
|
||||
1: {
|
||||
properties: {
|
||||
foo: { type: 'uint8' }
|
||||
}
|
||||
},
|
||||
2: {
|
||||
properties: {
|
||||
foo: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const compiler = factory({}, fastifyJtdDefault)
|
||||
const validatorFunc = compiler({ schema: jtdSchema })
|
||||
t.pass('generated validation function for JTD SCHEMA')
|
||||
|
||||
const result = validatorFunc({
|
||||
version: '2',
|
||||
foo: []
|
||||
})
|
||||
t.notOk(result, 'failed validation')
|
||||
t.type(validatorFunc.errors, 'Array')
|
||||
|
||||
const success = validatorFunc({
|
||||
version: '1',
|
||||
foo: 42
|
||||
})
|
||||
t.ok(success)
|
||||
})
|
||||
|
||||
t.test('fastify integration', async t => {
|
||||
const factory = AjvCompiler()
|
||||
|
||||
const app = fastify({
|
||||
jsonShorthand: false,
|
||||
ajv: {
|
||||
customOptions: { },
|
||||
mode: 'JTD'
|
||||
},
|
||||
schemaController: {
|
||||
compilersFactory: {
|
||||
buildValidator: factory
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
app.post('/', {
|
||||
schema: {
|
||||
body: {
|
||||
discriminator: 'version',
|
||||
mapping: {
|
||||
1: {
|
||||
properties: {
|
||||
foo: { type: 'uint8' }
|
||||
}
|
||||
},
|
||||
2: {
|
||||
properties: {
|
||||
foo: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, () => {})
|
||||
|
||||
const res = await app.inject({
|
||||
url: '/',
|
||||
method: 'POST',
|
||||
payload: {
|
||||
version: '1',
|
||||
foo: 'this is not a number'
|
||||
}
|
||||
})
|
||||
|
||||
t.equal(res.statusCode, 400)
|
||||
t.equal(res.json().message, 'body/foo must be uint8')
|
||||
})
|
||||
})
|
||||
264
node_modules/@fastify/ajv-compiler/test/plugins.test.js
generated
vendored
Normal file
264
node_modules/@fastify/ajv-compiler/test/plugins.test.js
generated
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const fastify = require('fastify')
|
||||
const AjvCompiler = require('../index')
|
||||
|
||||
const ajvFormats = require('ajv-formats')
|
||||
const ajvErrors = require('ajv-errors')
|
||||
const localize = require('ajv-i18n')
|
||||
|
||||
t.test('Format Baseline test', async (t) => {
|
||||
const app = buildApplication({
|
||||
customOptions: {
|
||||
validateFormats: false
|
||||
}
|
||||
})
|
||||
|
||||
const res = await app.inject({
|
||||
url: '/hello',
|
||||
headers: {
|
||||
'x-foo': 'hello',
|
||||
'x-date': 'not a date',
|
||||
'x-email': 'not an email'
|
||||
},
|
||||
query: {
|
||||
foo: 'hello',
|
||||
date: 'not a date',
|
||||
email: 'not an email'
|
||||
}
|
||||
})
|
||||
t.equal(res.statusCode, 200, 'format validation does not apply as configured')
|
||||
t.equal(res.payload, 'hello')
|
||||
})
|
||||
|
||||
t.test('Custom Format plugin loading test', (t) => {
|
||||
t.plan(6)
|
||||
const app = buildApplication({
|
||||
customOptions: {
|
||||
validateFormats: true
|
||||
},
|
||||
plugins: [[ajvFormats, { mode: 'fast' }]]
|
||||
})
|
||||
|
||||
app.inject('/hello', (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 400, 'format validation applies')
|
||||
})
|
||||
|
||||
app.inject('/2ad0612c-7578-4b18-9a6f-579863f40e0b', (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 400, 'format validation applies')
|
||||
})
|
||||
|
||||
app.inject({
|
||||
url: '/2ad0612c-7578-4b18-9a6f-579863f40e0b',
|
||||
headers: {
|
||||
'x-foo': 'hello',
|
||||
'x-date': new Date().toISOString(),
|
||||
'x-email': 'foo@bar.baz'
|
||||
},
|
||||
query: {
|
||||
foo: 'hello',
|
||||
date: new Date().toISOString(),
|
||||
email: 'foo@bar.baz'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
t.test('Format plugin set by default test', (t) => {
|
||||
t.plan(6)
|
||||
const app = buildApplication({})
|
||||
|
||||
app.inject('/hello', (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 400, 'format validation applies')
|
||||
})
|
||||
|
||||
app.inject('/2ad0612c-7578-4b18-9a6f-579863f40e0b', (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 400, 'format validation applies')
|
||||
})
|
||||
|
||||
app.inject({
|
||||
url: '/2ad0612c-7578-4b18-9a6f-579863f40e0b',
|
||||
headers: {
|
||||
'x-foo': 'hello',
|
||||
'x-date': new Date().toISOString(),
|
||||
'x-email': 'foo@bar.baz'
|
||||
},
|
||||
query: {
|
||||
foo: 'hello',
|
||||
date: new Date().toISOString(),
|
||||
email: 'foo@bar.baz'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
t.test('Custom error messages', (t) => {
|
||||
t.plan(9)
|
||||
|
||||
const app = buildApplication({
|
||||
customOptions: {
|
||||
removeAdditional: false,
|
||||
allErrors: true
|
||||
},
|
||||
plugins: [ajvFormats, ajvErrors]
|
||||
})
|
||||
|
||||
const errorMessage = {
|
||||
required: 'custom miss',
|
||||
type: 'custom type', // will not replace internal "type" error for the property "foo"
|
||||
_: 'custom type', // this prop will do it
|
||||
additionalProperties: 'custom too many params'
|
||||
}
|
||||
|
||||
app.post('/', {
|
||||
handler: () => { t.fail('dont call me') },
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['foo'],
|
||||
properties: {
|
||||
foo: { type: 'integer' }
|
||||
},
|
||||
additionalProperties: false,
|
||||
errorMessage
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
app.inject({
|
||||
url: '/',
|
||||
method: 'post',
|
||||
payload: {}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 400)
|
||||
t.match(res.json().message, errorMessage.required)
|
||||
})
|
||||
|
||||
app.inject({
|
||||
url: '/',
|
||||
method: 'post',
|
||||
payload: { foo: 'not a number' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 400)
|
||||
t.match(res.json().message, errorMessage.type)
|
||||
})
|
||||
|
||||
app.inject({
|
||||
url: '/',
|
||||
method: 'post',
|
||||
payload: { foo: 3, bar: 'ops' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 400)
|
||||
t.match(res.json().message, errorMessage.additionalProperties)
|
||||
})
|
||||
})
|
||||
|
||||
t.test('Custom i18n error messages', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const app = buildApplication({
|
||||
customOptions: {
|
||||
allErrors: true,
|
||||
messages: false
|
||||
},
|
||||
plugins: [ajvFormats]
|
||||
})
|
||||
|
||||
app.post('/', {
|
||||
handler: () => { t.fail('dont call me') },
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['foo'],
|
||||
properties: {
|
||||
foo: { type: 'integer' }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
app.setErrorHandler((error, request, reply) => {
|
||||
t.pass('Error handler executed')
|
||||
if (error.validation) {
|
||||
localize.ru(error.validation)
|
||||
reply.status(400).send(error.validation)
|
||||
return
|
||||
}
|
||||
t.fail('not other errors')
|
||||
})
|
||||
|
||||
app.inject({
|
||||
method: 'POST',
|
||||
url: '/',
|
||||
payload: {
|
||||
foo: 'string'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.json()[0].message, 'должно быть integer')
|
||||
})
|
||||
})
|
||||
|
||||
function buildApplication (ajvOptions) {
|
||||
const factory = AjvCompiler()
|
||||
|
||||
const app = fastify({
|
||||
ajv: ajvOptions,
|
||||
schemaController: {
|
||||
compilersFactory: {
|
||||
buildValidator: factory
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
app.get('/:id', {
|
||||
schema: {
|
||||
headers: {
|
||||
type: 'object',
|
||||
required: [
|
||||
'x-foo',
|
||||
'x-date',
|
||||
'x-email'
|
||||
],
|
||||
properties: {
|
||||
'x-foo': { type: 'string' },
|
||||
'x-date': { type: 'string', format: 'date-time' },
|
||||
'x-email': { type: 'string', format: 'email' }
|
||||
}
|
||||
},
|
||||
query: {
|
||||
type: 'object',
|
||||
required: [
|
||||
'foo',
|
||||
'date',
|
||||
'email'
|
||||
],
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
date: { type: 'string', format: 'date-time' },
|
||||
email: { type: 'string', format: 'email' }
|
||||
}
|
||||
},
|
||||
params: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', format: 'uuid' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}, async () => 'hello')
|
||||
|
||||
return app
|
||||
}
|
||||
279
node_modules/@fastify/ajv-compiler/test/serialization.test.js
generated
vendored
Normal file
279
node_modules/@fastify/ajv-compiler/test/serialization.test.js
generated
vendored
Normal file
@@ -0,0 +1,279 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const fastify = require('fastify')
|
||||
const AjvCompiler = require('../index')
|
||||
|
||||
const jtdSchema = {
|
||||
discriminator: 'version',
|
||||
mapping: {
|
||||
1: {
|
||||
properties: {
|
||||
foo: { type: 'uint8' }
|
||||
}
|
||||
},
|
||||
2: {
|
||||
properties: {
|
||||
foo: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const externalSchemas1 = Object.freeze({})
|
||||
const externalSchemas2 = Object.freeze({
|
||||
foo: {
|
||||
definitions: {
|
||||
coordinates: {
|
||||
properties: {
|
||||
lat: { type: 'float32' },
|
||||
lng: { type: 'float32' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const fastifyAjvOptionsDefault = Object.freeze({
|
||||
customOptions: {}
|
||||
})
|
||||
|
||||
t.test('basic serializer usage', t => {
|
||||
t.plan(4)
|
||||
const factory = AjvCompiler({ jtdSerializer: true })
|
||||
const compiler = factory(externalSchemas1, fastifyAjvOptionsDefault)
|
||||
const serializeFunc = compiler({ schema: jtdSchema })
|
||||
t.equal(serializeFunc({ version: '1', foo: 42 }), '{"version":"1","foo":42}')
|
||||
t.equal(serializeFunc({ version: '2', foo: 'hello' }), '{"version":"2","foo":"hello"}')
|
||||
t.equal(serializeFunc({ version: '3', foo: 'hello' }), '{"version":"3"}')
|
||||
t.equal(serializeFunc({ version: '2', foo: ['not', 1, { string: 'string' }] }), '{"version":"2","foo":"not,1,[object Object]"}')
|
||||
})
|
||||
|
||||
t.test('external schemas are ignored', t => {
|
||||
t.plan(1)
|
||||
const factory = AjvCompiler({ jtdSerializer: true })
|
||||
const compiler = factory(externalSchemas2, fastifyAjvOptionsDefault)
|
||||
const serializeFunc = compiler({
|
||||
schema: {
|
||||
definitions: {
|
||||
coordinates: {
|
||||
properties: {
|
||||
lat: { type: 'float32' },
|
||||
lng: { type: 'float32' }
|
||||
}
|
||||
}
|
||||
},
|
||||
properties: {
|
||||
userLoc: { ref: 'coordinates' },
|
||||
serverLoc: { ref: 'coordinates' }
|
||||
}
|
||||
}
|
||||
})
|
||||
t.equal(serializeFunc(
|
||||
{ userLoc: { lat: 50, lng: -90 }, serverLoc: { lat: -15, lng: 50 } }),
|
||||
'{"userLoc":{"lat":50,"lng":-90},"serverLoc":{"lat":-15,"lng":50}}'
|
||||
)
|
||||
})
|
||||
|
||||
t.test('fastify integration within JTD serializer', async t => {
|
||||
const factoryValidator = AjvCompiler()
|
||||
const factorySerializer = AjvCompiler({ jtdSerializer: true })
|
||||
|
||||
const app = fastify({
|
||||
jsonShorthand: false,
|
||||
ajv: {
|
||||
customOptions: { },
|
||||
mode: 'JTD'
|
||||
},
|
||||
schemaController: {
|
||||
compilersFactory: {
|
||||
buildValidator: factoryValidator,
|
||||
buildSerializer: factorySerializer
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
app.post('/', {
|
||||
schema: {
|
||||
body: jtdSchema,
|
||||
response: {
|
||||
200: {
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
createdAt: { type: 'timestamp' },
|
||||
karma: { type: 'int32' },
|
||||
isAdmin: { type: 'boolean' }
|
||||
}
|
||||
},
|
||||
400: jtdSchema
|
||||
}
|
||||
}
|
||||
}, async () => {
|
||||
return {
|
||||
id: '123',
|
||||
createdAt: new Date('1999-01-31T23:00:00.000Z'),
|
||||
karma: 42,
|
||||
isAdmin: true,
|
||||
remove: 'me'
|
||||
}
|
||||
})
|
||||
|
||||
{
|
||||
const res = await app.inject({
|
||||
url: '/',
|
||||
method: 'POST',
|
||||
payload: {
|
||||
version: '1',
|
||||
foo: 'not a number'
|
||||
}
|
||||
})
|
||||
|
||||
t.equal(res.statusCode, 400)
|
||||
t.same(res.json(), { version: 'undefined' })
|
||||
}
|
||||
|
||||
{
|
||||
const res = await app.inject({
|
||||
url: '/',
|
||||
method: 'POST',
|
||||
payload: {
|
||||
version: '1',
|
||||
foo: 32
|
||||
}
|
||||
})
|
||||
|
||||
t.equal(res.statusCode, 200)
|
||||
t.same(res.json(), {
|
||||
id: '123',
|
||||
createdAt: '1999-01-31T23:00:00.000Z',
|
||||
karma: 42,
|
||||
isAdmin: true
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.test('fastify integration and cached serializer', async t => {
|
||||
const factoryValidator = AjvCompiler()
|
||||
const factorySerializer = AjvCompiler({ jtdSerializer: true })
|
||||
|
||||
const app = fastify({
|
||||
jsonShorthand: false,
|
||||
ajv: {
|
||||
customOptions: { },
|
||||
mode: 'JTD'
|
||||
},
|
||||
schemaController: {
|
||||
compilersFactory: {
|
||||
buildValidator: factoryValidator,
|
||||
buildSerializer: factorySerializer
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
app.register(async function plugin (app, opts) {
|
||||
app.post('/', {
|
||||
schema: {
|
||||
body: jtdSchema,
|
||||
response: {
|
||||
200: {
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
createdAt: { type: 'timestamp' },
|
||||
karma: { type: 'int32' },
|
||||
isAdmin: { type: 'boolean' }
|
||||
}
|
||||
},
|
||||
400: jtdSchema
|
||||
}
|
||||
}
|
||||
}, async () => {
|
||||
return {
|
||||
id: '123',
|
||||
createdAt: new Date('1999-01-31T23:00:00.000Z'),
|
||||
karma: 42,
|
||||
isAdmin: true,
|
||||
remove: 'me'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
app.register(async function plugin (app, opts) {
|
||||
app.post('/two', {
|
||||
schema: {
|
||||
body: jtdSchema,
|
||||
response: {
|
||||
400: jtdSchema
|
||||
}
|
||||
}
|
||||
}, () => {})
|
||||
})
|
||||
|
||||
{
|
||||
const res = await app.inject({
|
||||
url: '/',
|
||||
method: 'POST',
|
||||
payload: {
|
||||
version: '1',
|
||||
foo: 'not a number'
|
||||
}
|
||||
})
|
||||
|
||||
t.equal(res.statusCode, 400)
|
||||
t.same(res.json(), { version: 'undefined' })
|
||||
}
|
||||
|
||||
{
|
||||
const res = await app.inject({
|
||||
url: '/',
|
||||
method: 'POST',
|
||||
payload: {
|
||||
version: '1',
|
||||
foo: 32
|
||||
}
|
||||
})
|
||||
|
||||
t.equal(res.statusCode, 200)
|
||||
t.same(res.json(), {
|
||||
id: '123',
|
||||
createdAt: '1999-01-31T23:00:00.000Z',
|
||||
karma: 42,
|
||||
isAdmin: true
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.test('fastify integration within JTD serializer and custom options', async t => {
|
||||
const factorySerializer = AjvCompiler({ jtdSerializer: true })
|
||||
|
||||
const app = fastify({
|
||||
jsonShorthand: false,
|
||||
serializerOpts: {
|
||||
allErrors: true,
|
||||
logger: 'wrong-value'
|
||||
},
|
||||
schemaController: {
|
||||
compilersFactory: {
|
||||
buildSerializer: factorySerializer
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
app.post('/', {
|
||||
schema: {
|
||||
response: {
|
||||
200: {
|
||||
properties: {
|
||||
test: { type: 'boolean' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, async () => { })
|
||||
|
||||
try {
|
||||
await app.ready()
|
||||
t.fail('should throw')
|
||||
} catch (error) {
|
||||
t.equal(error.message, 'logger must implement log, warn and error methods', 'the wrong setting is forwarded to ajv/jtd')
|
||||
}
|
||||
})
|
||||
203
node_modules/@fastify/ajv-compiler/test/standalone.test.js
generated
vendored
Normal file
203
node_modules/@fastify/ajv-compiler/test/standalone.test.js
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
'use strict'
|
||||
|
||||
const fs = require('node:fs')
|
||||
const path = require('node:path')
|
||||
const t = require('tap')
|
||||
const fastify = require('fastify')
|
||||
const sanitize = require('sanitize-filename')
|
||||
|
||||
const { StandaloneValidator: AjvStandaloneValidator } = require('../')
|
||||
|
||||
function generateFileName (routeOpts) {
|
||||
return `/ajv-generated-${sanitize(routeOpts.schema.$id)}-${routeOpts.method}-${routeOpts.httpPart}-${sanitize(routeOpts.url)}.js`
|
||||
}
|
||||
|
||||
const generatedFileNames = []
|
||||
|
||||
t.test('standalone', t => {
|
||||
t.plan(4)
|
||||
|
||||
t.teardown(async () => {
|
||||
for (const fileName of generatedFileNames) {
|
||||
await fs.promises.unlink(path.join(__dirname, fileName))
|
||||
}
|
||||
})
|
||||
|
||||
t.test('errors', t => {
|
||||
t.plan(2)
|
||||
t.throws(() => {
|
||||
AjvStandaloneValidator()
|
||||
}, 'missing restoreFunction')
|
||||
t.throws(() => {
|
||||
AjvStandaloneValidator({ readMode: false })
|
||||
}, 'missing storeFunction')
|
||||
})
|
||||
|
||||
t.test('generate standalone code', t => {
|
||||
t.plan(5)
|
||||
|
||||
const base = {
|
||||
$id: 'urn:schema:base',
|
||||
definitions: {
|
||||
hello: { type: 'string' }
|
||||
},
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { $ref: '#/definitions/hello' }
|
||||
}
|
||||
}
|
||||
|
||||
const refSchema = {
|
||||
$id: 'urn:schema:ref',
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { $ref: 'urn:schema:base#/definitions/hello' }
|
||||
}
|
||||
}
|
||||
|
||||
const endpointSchema = {
|
||||
schema: {
|
||||
$id: 'urn:schema:endpoint',
|
||||
$ref: 'urn:schema:ref'
|
||||
}
|
||||
}
|
||||
|
||||
const schemaMap = {
|
||||
[base.$id]: base,
|
||||
[refSchema.$id]: refSchema
|
||||
}
|
||||
|
||||
const factory = AjvStandaloneValidator({
|
||||
readMode: false,
|
||||
storeFunction (routeOpts, schemaValidationCode) {
|
||||
t.same(routeOpts, endpointSchema)
|
||||
t.type(schemaValidationCode, 'string')
|
||||
fs.writeFileSync(path.join(__dirname, '/ajv-generated.js'), schemaValidationCode)
|
||||
generatedFileNames.push('/ajv-generated.js')
|
||||
t.pass('stored the validation function')
|
||||
}
|
||||
})
|
||||
|
||||
const compiler = factory(schemaMap)
|
||||
compiler(endpointSchema)
|
||||
t.pass('compiled the endpoint schema')
|
||||
|
||||
t.test('usage standalone code', t => {
|
||||
t.plan(3)
|
||||
const standaloneValidate = require('./ajv-generated')
|
||||
|
||||
const valid = standaloneValidate({ hello: 'world' })
|
||||
t.ok(valid)
|
||||
|
||||
const invalid = standaloneValidate({ hello: [] })
|
||||
t.notOk(invalid)
|
||||
|
||||
t.ok(standaloneValidate)
|
||||
})
|
||||
})
|
||||
|
||||
t.test('fastify integration - writeMode', async t => {
|
||||
t.plan(6)
|
||||
|
||||
const factory = AjvStandaloneValidator({
|
||||
readMode: false,
|
||||
storeFunction (routeOpts, schemaValidationCode) {
|
||||
const fileName = generateFileName(routeOpts)
|
||||
t.ok(routeOpts)
|
||||
fs.writeFileSync(path.join(__dirname, fileName), schemaValidationCode)
|
||||
t.pass('stored the validation function')
|
||||
generatedFileNames.push(fileName)
|
||||
},
|
||||
restoreFunction () {
|
||||
t.fail('write mode ON')
|
||||
}
|
||||
})
|
||||
|
||||
const app = buildApp(factory)
|
||||
await app.ready()
|
||||
})
|
||||
|
||||
t.test('fastify integration - readMode', async t => {
|
||||
t.plan(6)
|
||||
|
||||
const factory = AjvStandaloneValidator({
|
||||
readMode: true,
|
||||
storeFunction () {
|
||||
t.fail('read mode ON')
|
||||
},
|
||||
restoreFunction (routeOpts) {
|
||||
t.pass('restore the validation function')
|
||||
const fileName = generateFileName(routeOpts)
|
||||
return require(path.join(__dirname, fileName))
|
||||
}
|
||||
})
|
||||
|
||||
const app = buildApp(factory)
|
||||
await app.ready()
|
||||
|
||||
let res = await app.inject({
|
||||
url: '/foo',
|
||||
method: 'POST',
|
||||
payload: { hello: [] }
|
||||
})
|
||||
t.equal(res.statusCode, 400)
|
||||
|
||||
res = await app.inject({
|
||||
url: '/bar?lang=invalid',
|
||||
method: 'GET'
|
||||
})
|
||||
t.equal(res.statusCode, 400)
|
||||
|
||||
res = await app.inject({
|
||||
url: '/bar?lang=it',
|
||||
method: 'GET'
|
||||
})
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
|
||||
function buildApp (factory) {
|
||||
const app = fastify({
|
||||
jsonShorthand: false,
|
||||
schemaController: {
|
||||
compilersFactory: {
|
||||
buildValidator: factory
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
app.addSchema({
|
||||
$id: 'urn:schema:foo',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
id: { type: 'integer' }
|
||||
}
|
||||
})
|
||||
|
||||
app.post('/foo', {
|
||||
schema: {
|
||||
body: {
|
||||
$id: 'urn:schema:body',
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { $ref: 'urn:schema:foo#/properties/name' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}, () => { return 'ok' })
|
||||
|
||||
app.get('/bar', {
|
||||
schema: {
|
||||
query: {
|
||||
$id: 'urn:schema:query',
|
||||
type: 'object',
|
||||
properties: {
|
||||
lang: { type: 'string', enum: ['it', 'en'] }
|
||||
}
|
||||
}
|
||||
}
|
||||
}, () => { return 'ok' })
|
||||
|
||||
return app
|
||||
}
|
||||
})
|
||||
72
node_modules/@fastify/ajv-compiler/types/index.d.ts
generated
vendored
Normal file
72
node_modules/@fastify/ajv-compiler/types/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
import _ajv, { AnySchema, Options as AjvOptions, ValidateFunction } from 'ajv'
|
||||
import AjvJTD, { JTDOptions } from 'ajv/dist/jtd'
|
||||
import type { Options, ErrorObject } from 'ajv'
|
||||
import { AnyValidateFunction } from 'ajv/dist/core'
|
||||
|
||||
type Ajv = _ajv
|
||||
type AjvSerializerGenerator = typeof AjvCompiler
|
||||
|
||||
type AjvJTDCompile = AjvJTD['compileSerializer']
|
||||
type AjvCompile = (schema: AnySchema, _meta?: boolean) => AnyValidateFunction
|
||||
|
||||
declare function buildCompilerFromPool (externalSchemas: { [key: string]: AnySchema | AnySchema[] }, options?: { mode: 'JTD'; customOptions?: JTDOptions; onCreate?: (ajvInstance: Ajv) => void }): AjvCompile
|
||||
declare function buildCompilerFromPool (externalSchemas: { [key: string]: AnySchema | AnySchema[] }, options?: { mode?: never; customOptions?: AjvOptions; onCreate?: (ajvInstance: Ajv) => void }): AjvCompile
|
||||
|
||||
declare function buildSerializerFromPool (externalSchemas: any, serializerOpts?: { mode?: never; } & JTDOptions): AjvJTDCompile
|
||||
|
||||
declare function AjvCompiler (opts: { jtdSerializer: true }): AjvCompiler.BuildSerializerFromPool
|
||||
declare function AjvCompiler (opts?: { jtdSerializer?: false }): AjvCompiler.BuildCompilerFromPool
|
||||
|
||||
declare function StandaloneValidator (options: AjvCompiler.StandaloneOptions): AjvCompiler.BuildCompilerFromPool
|
||||
|
||||
declare namespace AjvCompiler {
|
||||
export type { Options, ErrorObject }
|
||||
export { Ajv }
|
||||
|
||||
export type BuildSerializerFromPool = typeof buildSerializerFromPool
|
||||
|
||||
export type BuildCompilerFromPool = typeof buildCompilerFromPool
|
||||
|
||||
export const AjvReference: Symbol
|
||||
|
||||
export enum HttpParts {
|
||||
Body = 'body',
|
||||
Headers = 'headers',
|
||||
Params = 'params',
|
||||
Query = 'querystring',
|
||||
}
|
||||
|
||||
export type RouteDefinition = {
|
||||
method: string,
|
||||
url: string,
|
||||
httpPart: HttpParts,
|
||||
schema?: unknown,
|
||||
}
|
||||
|
||||
export type StandaloneRestoreFunction = (opts: RouteDefinition) => ValidateFunction
|
||||
|
||||
export type StandaloneStoreFunction = (opts: RouteDefinition, schemaValidationCode: string) => void
|
||||
|
||||
export type StandaloneOptionsReadModeOn = {
|
||||
readMode: true;
|
||||
restoreFunction?: StandaloneRestoreFunction
|
||||
}
|
||||
|
||||
export type StandaloneOptionsReadModeOff = {
|
||||
readMode?: false | undefined;
|
||||
storeFunction?: StandaloneStoreFunction;
|
||||
}
|
||||
|
||||
export type StandaloneOptions = StandaloneOptionsReadModeOn | StandaloneOptionsReadModeOff
|
||||
|
||||
export type ValidatorFactory = BuildCompilerFromPool | BuildSerializerFromPool
|
||||
|
||||
export type ValidatorCompiler = ReturnType<ValidatorFactory>
|
||||
|
||||
export { StandaloneValidator }
|
||||
|
||||
export const AjvCompiler: AjvSerializerGenerator
|
||||
export { AjvCompiler as default }
|
||||
}
|
||||
|
||||
export = AjvCompiler
|
||||
226
node_modules/@fastify/ajv-compiler/types/index.test-d.ts
generated
vendored
Normal file
226
node_modules/@fastify/ajv-compiler/types/index.test-d.ts
generated
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
import { AnySchemaObject, ValidateFunction } from 'ajv'
|
||||
import { AnyValidateFunction } from 'ajv/dist/core'
|
||||
import { expectAssignable, expectType } from 'tsd'
|
||||
import AjvCompiler, { AjvReference, ValidatorFactory, StandaloneValidator, RouteDefinition, ErrorObject, BuildCompilerFromPool, BuildSerializerFromPool, ValidatorCompiler } from '..'
|
||||
|
||||
{
|
||||
const compiler = AjvCompiler({})
|
||||
expectType<BuildCompilerFromPool>(compiler)
|
||||
}
|
||||
{
|
||||
const compiler = AjvCompiler()
|
||||
expectType<BuildCompilerFromPool>(compiler)
|
||||
}
|
||||
{
|
||||
const compiler = AjvCompiler({ jtdSerializer: false })
|
||||
expectType<BuildCompilerFromPool>(compiler)
|
||||
}
|
||||
|
||||
{
|
||||
const factory = AjvCompiler({ jtdSerializer: false })
|
||||
expectType<BuildCompilerFromPool>(factory)
|
||||
factory({}, {
|
||||
onCreate (ajv) {
|
||||
expectType<import('ajv').default>(ajv)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
const compiler = AjvCompiler({ jtdSerializer: true })
|
||||
expectType<BuildSerializerFromPool>(compiler)
|
||||
}
|
||||
const reader = StandaloneValidator({
|
||||
readMode: true,
|
||||
restoreFunction: (route: RouteDefinition) => {
|
||||
expectAssignable<RouteDefinition>(route)
|
||||
return {} as ValidateFunction
|
||||
},
|
||||
})
|
||||
expectAssignable<ValidatorFactory>(reader)
|
||||
|
||||
const writer = StandaloneValidator({
|
||||
readMode: false,
|
||||
storeFunction: (route: RouteDefinition, code: string) => {
|
||||
expectAssignable<RouteDefinition>(route)
|
||||
expectAssignable<string>(code)
|
||||
},
|
||||
})
|
||||
expectAssignable<ValidatorFactory>(writer)
|
||||
|
||||
expectType<unknown>(({} as ErrorObject).data)
|
||||
expectType<string>(({} as ErrorObject).instancePath)
|
||||
expectType<string>(({} as ErrorObject).keyword)
|
||||
expectType<string | undefined>(({} as ErrorObject).message)
|
||||
expectType<Record<string, any>>(({} as ErrorObject).params)
|
||||
expectType<AnySchemaObject | undefined>(({} as ErrorObject).parentSchema)
|
||||
expectType<string | undefined>(({} as ErrorObject).propertyName)
|
||||
expectType<unknown>(({} as ErrorObject).schema)
|
||||
expectType<string>(({} as ErrorObject).schemaPath)
|
||||
|
||||
expectType<Symbol>(AjvReference)
|
||||
|
||||
{
|
||||
const jtdSchema = {
|
||||
discriminator: 'version',
|
||||
mapping: {
|
||||
1: {
|
||||
properties: {
|
||||
foo: { type: 'uint8' }
|
||||
}
|
||||
},
|
||||
2: {
|
||||
properties: {
|
||||
foo: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const externalSchemas1 = {
|
||||
foo: {
|
||||
definitions: {
|
||||
coordinates: {
|
||||
properties: {
|
||||
lat: { type: 'float32' },
|
||||
lng: { type: 'float32' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const factory = AjvCompiler({ jtdSerializer: true })
|
||||
expectType<BuildSerializerFromPool>(factory)
|
||||
const compiler = factory(externalSchemas1, {})
|
||||
expectAssignable<Function>(compiler)
|
||||
const serializeFunc = compiler({ schema: jtdSchema })
|
||||
expectType<(data: unknown) => string>(serializeFunc)
|
||||
expectType<string>(serializeFunc({ version: '1', foo: 42 }))
|
||||
}
|
||||
// JTD
|
||||
{
|
||||
const factory = AjvCompiler()
|
||||
expectType<BuildCompilerFromPool>(factory)
|
||||
|
||||
const jtdSchema = {
|
||||
discriminator: 'version',
|
||||
mapping: {
|
||||
1: {
|
||||
properties: {
|
||||
foo: { type: 'uint8' }
|
||||
}
|
||||
},
|
||||
2: {
|
||||
properties: {
|
||||
foo: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const compiler = factory({}, {
|
||||
customOptions: {},
|
||||
mode: 'JTD'
|
||||
})
|
||||
expectAssignable<ValidatorCompiler>(compiler)
|
||||
const validatorFunc = compiler({ schema: jtdSchema })
|
||||
expectAssignable<ValidateFunction>(validatorFunc)
|
||||
|
||||
expectType<boolean | Promise<any>>(validatorFunc({
|
||||
version: '2',
|
||||
foo: []
|
||||
}))
|
||||
}
|
||||
|
||||
// generate standalone code
|
||||
{
|
||||
const base = {
|
||||
$id: 'urn:schema:base',
|
||||
definitions: {
|
||||
hello: { type: 'string' }
|
||||
},
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { $ref: '#/definitions/hello' }
|
||||
}
|
||||
}
|
||||
|
||||
const refSchema = {
|
||||
$id: 'urn:schema:ref',
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { $ref: 'urn:schema:base#/definitions/hello' }
|
||||
}
|
||||
}
|
||||
|
||||
const endpointSchema = {
|
||||
schema: {
|
||||
$id: 'urn:schema:endpoint',
|
||||
$ref: 'urn:schema:ref'
|
||||
}
|
||||
}
|
||||
|
||||
const schemaMap = {
|
||||
[base.$id]: base,
|
||||
[refSchema.$id]: refSchema
|
||||
}
|
||||
|
||||
const factory = StandaloneValidator({
|
||||
readMode: false,
|
||||
storeFunction (routeOpts, schemaValidationCode) {
|
||||
expectType<RouteDefinition>(routeOpts)
|
||||
expectType<string>(schemaValidationCode)
|
||||
}
|
||||
})
|
||||
expectAssignable<ValidatorFactory>(factory)
|
||||
|
||||
const compiler = factory(schemaMap)
|
||||
expectAssignable<ValidatorCompiler>(compiler)
|
||||
expectAssignable<Function>(compiler(endpointSchema))
|
||||
}
|
||||
|
||||
{
|
||||
const base = {
|
||||
$id: 'urn:schema:base',
|
||||
definitions: {
|
||||
hello: { type: 'string' }
|
||||
},
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { $ref: '#/definitions/hello' }
|
||||
}
|
||||
}
|
||||
|
||||
const refSchema = {
|
||||
$id: 'urn:schema:ref',
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { $ref: 'urn:schema:base#/definitions/hello' }
|
||||
}
|
||||
}
|
||||
|
||||
const endpointSchema = {
|
||||
schema: {
|
||||
$id: 'urn:schema:endpoint',
|
||||
$ref: 'urn:schema:ref'
|
||||
}
|
||||
}
|
||||
|
||||
const schemaMap = {
|
||||
[base.$id]: base,
|
||||
[refSchema.$id]: refSchema
|
||||
}
|
||||
const factory = StandaloneValidator({
|
||||
readMode: true,
|
||||
restoreFunction (routeOpts) {
|
||||
expectType<RouteDefinition>(routeOpts)
|
||||
return {} as ValidateFunction
|
||||
}
|
||||
})
|
||||
expectAssignable<ValidatorFactory>(factory)
|
||||
|
||||
const compiler = factory(schemaMap)
|
||||
expectAssignable<ValidatorCompiler>(compiler)
|
||||
expectType<AnyValidateFunction<any>>(compiler(endpointSchema))
|
||||
}
|
||||
Reference in New Issue
Block a user