First commit
This commit is contained in:
122
CLAUDE.md
Normal file
122
CLAUDE.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# QR-Invoice Service
|
||||
|
||||
Swiss QR-Bill PDF Generation Service für Schweizer Zahlscheine nach SIX-Spezifikation.
|
||||
|
||||
## Projektübersicht
|
||||
|
||||
Ein Node.js/TypeScript HTTP-Service, der JSON-Daten über einen Webhook empfängt und eine PDF mit Swiss QR-Zahlteil generiert.
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- **Runtime**: Node.js 18+
|
||||
- **Sprache**: TypeScript
|
||||
- **HTTP Framework**: Fastify 4
|
||||
- **PDF-Generierung**: swissqrbill + pdfkit
|
||||
- **Validierung**: Zod
|
||||
|
||||
## Projektstruktur
|
||||
|
||||
```
|
||||
src/
|
||||
├── index.ts # Entry Point, startet Server
|
||||
├── app.ts # Fastify App Konfiguration
|
||||
├── config/index.ts # Umgebungsvariablen (PORT, HOST, LOG_LEVEL)
|
||||
├── types/ # TypeScript Interfaces
|
||||
├── schemas/ # Zod Validierungsschemas
|
||||
├── services/ # Business Logic (QR-Bill Generierung)
|
||||
├── routes/ # API Endpoints
|
||||
└── errors/ # Error Handler
|
||||
```
|
||||
|
||||
## Wichtige Befehle
|
||||
|
||||
```bash
|
||||
npm run dev # Entwicklungsserver mit Hot-Reload (tsx watch)
|
||||
npm run build # TypeScript kompilieren nach dist/
|
||||
npm run start # Produktionsserver starten
|
||||
npm run typecheck # TypeScript Typprüfung
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Method | Path | Beschreibung |
|
||||
|--------|------|--------------|
|
||||
| POST | `/api/v1/invoice/qr-bill` | Generiert QR-Bill PDF |
|
||||
| GET | `/health` | Health Check |
|
||||
| GET | `/health/ready` | Readiness Probe |
|
||||
|
||||
## Request Format (POST /api/v1/invoice/qr-bill)
|
||||
|
||||
```json
|
||||
{
|
||||
"creditor": {
|
||||
"iban": "CH4431999123000889012",
|
||||
"address": {
|
||||
"name": "Firma AG",
|
||||
"street": "Strasse",
|
||||
"buildingNumber": "123",
|
||||
"postalCode": "8000",
|
||||
"city": "Zürich",
|
||||
"country": "CH"
|
||||
}
|
||||
},
|
||||
"amount": 1949.75,
|
||||
"currency": "CHF",
|
||||
"reference": {
|
||||
"type": "QRR",
|
||||
"value": "210000000003139471430009017"
|
||||
},
|
||||
"debtor": {
|
||||
"address": { ... }
|
||||
},
|
||||
"additionalInformation": {
|
||||
"message": "Rechnung Nr. 123"
|
||||
},
|
||||
"options": {
|
||||
"language": "de",
|
||||
"separate": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Validierungsregeln (SIX-Spezifikation)
|
||||
|
||||
- **QRR** (QR-Referenz): 27 Ziffern, Modulo 10 rekursiv, erfordert QR-IBAN (IID 30000-31999)
|
||||
- **SCOR** (Creditor Reference): ISO 11649, erfordert normale IBAN
|
||||
- **NON** (Ohne Referenz): Erfordert normale IBAN
|
||||
- **Strukturierte Adressen**: Pflicht seit November 2025
|
||||
- **Betrag**: 0.01 - 999'999'999.99, max. 2 Dezimalstellen
|
||||
- **Währung**: CHF oder EUR
|
||||
|
||||
## Umgebungsvariablen
|
||||
|
||||
| Variable | Default | Beschreibung |
|
||||
|----------|---------|--------------|
|
||||
| PORT | 3000 | Server Port |
|
||||
| HOST | 0.0.0.0 | Server Host |
|
||||
| LOG_LEVEL | info | Pino Log Level |
|
||||
|
||||
## Testen
|
||||
|
||||
```bash
|
||||
# Server starten
|
||||
npm run dev
|
||||
|
||||
# Test-Request senden
|
||||
curl -X POST http://localhost:3000/api/v1/invoice/qr-bill \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @test-request.json \
|
||||
-o output.pdf
|
||||
```
|
||||
|
||||
## Wichtige Dateien
|
||||
|
||||
- `src/schemas/qr-invoice.schema.ts` - Zod Schema mit Cross-Validation für IBAN/Referenz
|
||||
- `src/services/qr-bill.service.ts` - PDF-Generierung mit swissqrbill
|
||||
- `src/routes/invoice.routes.ts` - API Endpoint Implementation
|
||||
- `test-request.json` - Beispiel-Request für Tests
|
||||
|
||||
## Externe Ressourcen
|
||||
|
||||
- [SIX QR-Bill Spezifikation](https://www.six-group.com/dam/download/banking-services/standardization/qr-bill/ig-qr-bill-v2.3-en.pdf)
|
||||
- [swissqrbill Dokumentation](https://github.com/schoero/swissqrbill)
|
||||
1
node_modules/.bin/esbuild
generated
vendored
Symbolic link
1
node_modules/.bin/esbuild
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../esbuild/bin/esbuild
|
||||
1
node_modules/.bin/pino
generated
vendored
Symbolic link
1
node_modules/.bin/pino
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../pino/bin.js
|
||||
1
node_modules/.bin/semver
generated
vendored
Symbolic link
1
node_modules/.bin/semver
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../semver/bin/semver.js
|
||||
1
node_modules/.bin/tsc
generated
vendored
Symbolic link
1
node_modules/.bin/tsc
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../typescript/bin/tsc
|
||||
1
node_modules/.bin/tsserver
generated
vendored
Symbolic link
1
node_modules/.bin/tsserver
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../typescript/bin/tsserver
|
||||
1
node_modules/.bin/tsx
generated
vendored
Symbolic link
1
node_modules/.bin/tsx
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../tsx/dist/cli.mjs
|
||||
779
node_modules/.package-lock.json
generated
vendored
Normal file
779
node_modules/.package-lock.json
generated
vendored
Normal file
@@ -0,0 +1,779 @@
|
||||
{
|
||||
"name": "qr-invoice-service",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz",
|
||||
"integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@fastify/ajv-compiler": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.6.0.tgz",
|
||||
"integrity": "sha512-LwdXQJjmMD+GwLOkP7TVC68qa+pSSogeWWmznRJ/coyTcfe9qA05AHFSe1eZFwK6q+xVRpChnvFUkf1iYaSZsQ==",
|
||||
"dependencies": {
|
||||
"ajv": "^8.11.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"fast-uri": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fastify/error": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/error/-/error-3.4.1.tgz",
|
||||
"integrity": "sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ=="
|
||||
},
|
||||
"node_modules/@fastify/fast-json-stringify-compiler": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.3.0.tgz",
|
||||
"integrity": "sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==",
|
||||
"dependencies": {
|
||||
"fast-json-stringify": "^5.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fastify/merge-json-schemas": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.1.1.tgz",
|
||||
"integrity": "sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@pinojs/redact": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz",
|
||||
"integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg=="
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.18",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.18.tgz",
|
||||
"integrity": "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.19.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.3.tgz",
|
||||
"integrity": "sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/pdfkit": {
|
||||
"version": "0.17.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/pdfkit/-/pdfkit-0.17.4.tgz",
|
||||
"integrity": "sha512-odAmVuuguRxKh1X4pbMrJMp8ecwNqHRw6lweupvzK+wuyNmi6wzlUlGVZ9EqMvp3Bs2+L9Ty0sRlrvKL+gsQZg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/abstract-logging": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz",
|
||||
"integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-uri": "^3.0.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/ajv-formats": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
|
||||
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
|
||||
"dependencies": {
|
||||
"ajv": "^8.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ajv": "^8.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"ajv": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/ajv/node_modules/fast-uri": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
|
||||
"integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fastify"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fastify"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/atomic-sleep": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
|
||||
"integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/avvio": {
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/avvio/-/avvio-8.4.0.tgz",
|
||||
"integrity": "sha512-CDSwaxINFy59iNwhYnkvALBwZiTydGkOecZyPkqBpABYR1KqGEsET0VOOYDwtleZSUIdeY36DC2bSZ24CO1igA==",
|
||||
"dependencies": {
|
||||
"@fastify/error": "^3.3.0",
|
||||
"fastq": "^1.17.1"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/brotli": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz",
|
||||
"integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/clone": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
|
||||
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/crypto-js": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
|
||||
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
|
||||
},
|
||||
"node_modules/dfa": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz",
|
||||
"integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q=="
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz",
|
||||
"integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.27.2",
|
||||
"@esbuild/android-arm": "0.27.2",
|
||||
"@esbuild/android-arm64": "0.27.2",
|
||||
"@esbuild/android-x64": "0.27.2",
|
||||
"@esbuild/darwin-arm64": "0.27.2",
|
||||
"@esbuild/darwin-x64": "0.27.2",
|
||||
"@esbuild/freebsd-arm64": "0.27.2",
|
||||
"@esbuild/freebsd-x64": "0.27.2",
|
||||
"@esbuild/linux-arm": "0.27.2",
|
||||
"@esbuild/linux-arm64": "0.27.2",
|
||||
"@esbuild/linux-ia32": "0.27.2",
|
||||
"@esbuild/linux-loong64": "0.27.2",
|
||||
"@esbuild/linux-mips64el": "0.27.2",
|
||||
"@esbuild/linux-ppc64": "0.27.2",
|
||||
"@esbuild/linux-riscv64": "0.27.2",
|
||||
"@esbuild/linux-s390x": "0.27.2",
|
||||
"@esbuild/linux-x64": "0.27.2",
|
||||
"@esbuild/netbsd-arm64": "0.27.2",
|
||||
"@esbuild/netbsd-x64": "0.27.2",
|
||||
"@esbuild/openbsd-arm64": "0.27.2",
|
||||
"@esbuild/openbsd-x64": "0.27.2",
|
||||
"@esbuild/openharmony-arm64": "0.27.2",
|
||||
"@esbuild/sunos-x64": "0.27.2",
|
||||
"@esbuild/win32-arm64": "0.27.2",
|
||||
"@esbuild/win32-ia32": "0.27.2",
|
||||
"@esbuild/win32-x64": "0.27.2"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-content-type-parse": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz",
|
||||
"integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ=="
|
||||
},
|
||||
"node_modules/fast-decode-uri-component": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz",
|
||||
"integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"node_modules/fast-json-stringify": {
|
||||
"version": "5.16.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.16.1.tgz",
|
||||
"integrity": "sha512-KAdnLvy1yu/XrRtP+LJnxbBGrhN+xXu+gt3EUvZhYGKCr3lFHq/7UFJHHFgmJKoqlh6B40bZLEv7w46B0mqn1g==",
|
||||
"dependencies": {
|
||||
"@fastify/merge-json-schemas": "^0.1.0",
|
||||
"ajv": "^8.10.0",
|
||||
"ajv-formats": "^3.0.1",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-uri": "^2.1.0",
|
||||
"json-schema-ref-resolver": "^1.0.1",
|
||||
"rfdc": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-json-stringify/node_modules/ajv-formats": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
|
||||
"integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
|
||||
"dependencies": {
|
||||
"ajv": "^8.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ajv": "^8.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"ajv": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/fast-querystring": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz",
|
||||
"integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==",
|
||||
"dependencies": {
|
||||
"fast-decode-uri-component": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-uri": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.4.0.tgz",
|
||||
"integrity": "sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA=="
|
||||
},
|
||||
"node_modules/fastify": {
|
||||
"version": "4.29.1",
|
||||
"resolved": "https://registry.npmjs.org/fastify/-/fastify-4.29.1.tgz",
|
||||
"integrity": "sha512-m2kMNHIG92tSNWv+Z3UeTR9AWLLuo7KctC7mlFPtMEVrfjIhmQhkQnT9v15qA/BfVq3vvj134Y0jl9SBje3jXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fastify"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fastify"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@fastify/ajv-compiler": "^3.5.0",
|
||||
"@fastify/error": "^3.4.0",
|
||||
"@fastify/fast-json-stringify-compiler": "^4.3.0",
|
||||
"abstract-logging": "^2.0.1",
|
||||
"avvio": "^8.3.0",
|
||||
"fast-content-type-parse": "^1.1.0",
|
||||
"fast-json-stringify": "^5.8.0",
|
||||
"find-my-way": "^8.0.0",
|
||||
"light-my-request": "^5.11.0",
|
||||
"pino": "^9.0.0",
|
||||
"process-warning": "^3.0.0",
|
||||
"proxy-addr": "^2.0.7",
|
||||
"rfdc": "^1.3.0",
|
||||
"secure-json-parse": "^2.7.0",
|
||||
"semver": "^7.5.4",
|
||||
"toad-cache": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fastq": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
|
||||
"integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
|
||||
"dependencies": {
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/find-my-way": {
|
||||
"version": "8.2.2",
|
||||
"resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-8.2.2.tgz",
|
||||
"integrity": "sha512-Dobi7gcTEq8yszimcfp/R7+owiT4WncAJ7VTTgFH1jYJ5GaG1FbhjwDG820hptN0QDFvzVY3RfCzdInvGPGzjA==",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-querystring": "^1.0.0",
|
||||
"safe-regex2": "^3.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/fontkit": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz",
|
||||
"integrity": "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==",
|
||||
"dependencies": {
|
||||
"@swc/helpers": "^0.5.12",
|
||||
"brotli": "^1.3.2",
|
||||
"clone": "^2.1.2",
|
||||
"dfa": "^1.2.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"restructure": "^3.0.0",
|
||||
"tiny-inflate": "^1.0.3",
|
||||
"unicode-properties": "^1.4.0",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/get-tsconfig": {
|
||||
"version": "4.13.0",
|
||||
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz",
|
||||
"integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"resolve-pkg-maps": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/iban": {
|
||||
"version": "0.0.14",
|
||||
"resolved": "https://registry.npmjs.org/iban/-/iban-0.0.14.tgz",
|
||||
"integrity": "sha512-+rocNKk+Ga9m8Lr9fTMWd+87JnsBrucm0ZsIx5ROOarZlaDLmd+FKdbtvb0XyoBw9GAFOYG2GuLqoNB16d+p3w=="
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/jpeg-exif": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/jpeg-exif/-/jpeg-exif-1.1.4.tgz",
|
||||
"integrity": "sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ==",
|
||||
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."
|
||||
},
|
||||
"node_modules/json-schema-ref-resolver": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-1.0.1.tgz",
|
||||
"integrity": "sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||
},
|
||||
"node_modules/light-my-request": {
|
||||
"version": "5.14.0",
|
||||
"resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.14.0.tgz",
|
||||
"integrity": "sha512-aORPWntbpH5esaYpGOOmri0OHDOe3wC5M2MQxZ9dvMLZm6DnaAn0kJlcbU9hwsQgLzmZyReKwFwwPkR+nHu5kA==",
|
||||
"dependencies": {
|
||||
"cookie": "^0.7.0",
|
||||
"process-warning": "^3.0.0",
|
||||
"set-cookie-parser": "^2.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/linebreak": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz",
|
||||
"integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==",
|
||||
"dependencies": {
|
||||
"base64-js": "0.0.8",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/linebreak/node_modules/base64-js": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
|
||||
"integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/on-exit-leak-free": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz",
|
||||
"integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pako": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
|
||||
"integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="
|
||||
},
|
||||
"node_modules/pdfkit": {
|
||||
"version": "0.17.2",
|
||||
"resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.17.2.tgz",
|
||||
"integrity": "sha512-UnwF5fXy08f0dnp4jchFYAROKMNTaPqb/xgR8GtCzIcqoTnbOqtp3bwKvO4688oHI6vzEEs8Q6vqqEnC5IUELw==",
|
||||
"dependencies": {
|
||||
"crypto-js": "^4.2.0",
|
||||
"fontkit": "^2.0.4",
|
||||
"jpeg-exif": "^1.1.4",
|
||||
"linebreak": "^1.1.0",
|
||||
"png-js": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pino": {
|
||||
"version": "9.14.0",
|
||||
"resolved": "https://registry.npmjs.org/pino/-/pino-9.14.0.tgz",
|
||||
"integrity": "sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==",
|
||||
"dependencies": {
|
||||
"@pinojs/redact": "^0.4.0",
|
||||
"atomic-sleep": "^1.0.0",
|
||||
"on-exit-leak-free": "^2.1.0",
|
||||
"pino-abstract-transport": "^2.0.0",
|
||||
"pino-std-serializers": "^7.0.0",
|
||||
"process-warning": "^5.0.0",
|
||||
"quick-format-unescaped": "^4.0.3",
|
||||
"real-require": "^0.2.0",
|
||||
"safe-stable-stringify": "^2.3.1",
|
||||
"sonic-boom": "^4.0.1",
|
||||
"thread-stream": "^3.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"pino": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/pino-abstract-transport": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz",
|
||||
"integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==",
|
||||
"dependencies": {
|
||||
"split2": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pino-std-serializers": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz",
|
||||
"integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA=="
|
||||
},
|
||||
"node_modules/pino/node_modules/process-warning": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz",
|
||||
"integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fastify"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fastify"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/png-js": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz",
|
||||
"integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g=="
|
||||
},
|
||||
"node_modules/process-warning": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz",
|
||||
"integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ=="
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
|
||||
"dependencies": {
|
||||
"forwarded": "0.2.0",
|
||||
"ipaddr.js": "1.9.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/quick-format-unescaped": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
|
||||
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="
|
||||
},
|
||||
"node_modules/real-require": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz",
|
||||
"integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==",
|
||||
"engines": {
|
||||
"node": ">= 12.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/require-from-string": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-pkg-maps": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
|
||||
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/restructure": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.2.tgz",
|
||||
"integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw=="
|
||||
},
|
||||
"node_modules/ret": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/ret/-/ret-0.4.3.tgz",
|
||||
"integrity": "sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/reusify": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
|
||||
"integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
|
||||
"engines": {
|
||||
"iojs": ">=1.0.0",
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rfdc": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
|
||||
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="
|
||||
},
|
||||
"node_modules/safe-regex2": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-3.1.0.tgz",
|
||||
"integrity": "sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug==",
|
||||
"dependencies": {
|
||||
"ret": "~0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-stable-stringify": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
|
||||
"integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/secure-json-parse": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
|
||||
"integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.3",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
|
||||
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/set-cookie-parser": {
|
||||
"version": "2.7.2",
|
||||
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
|
||||
"integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="
|
||||
},
|
||||
"node_modules/sonic-boom": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz",
|
||||
"integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==",
|
||||
"dependencies": {
|
||||
"atomic-sleep": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/split2": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
|
||||
"integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
|
||||
"engines": {
|
||||
"node": ">= 10.x"
|
||||
}
|
||||
},
|
||||
"node_modules/svg-engine": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/svg-engine/-/svg-engine-0.3.0.tgz",
|
||||
"integrity": "sha512-s172jAcwfoCcvM/6DwNBvmWN3brztHGFENCR+RU3CBJKeBxPrRlTltVxX1Je5hst782QgP8PM6U37vUR/RhPng=="
|
||||
},
|
||||
"node_modules/swissqrbill": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/swissqrbill/-/swissqrbill-4.2.1.tgz",
|
||||
"integrity": "sha512-7HRXCHpt10nXlojzk0c1udDt4QK45v7MHflwW78eUPVvrTNH1c8F5wPRrrF+D2ChvDrXkEnvqSN3oXZ8td7zTw==",
|
||||
"dependencies": {
|
||||
"svg-engine": "^0.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"pdfkit": ">=0.13.0",
|
||||
"typescript": ">=4.7.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"pdfkit": {
|
||||
"optional": true
|
||||
},
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/thread-stream": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz",
|
||||
"integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==",
|
||||
"dependencies": {
|
||||
"real-require": "^0.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tiny-inflate": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
|
||||
"integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="
|
||||
},
|
||||
"node_modules/toad-cache": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz",
|
||||
"integrity": "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
|
||||
},
|
||||
"node_modules/tsx": {
|
||||
"version": "4.21.0",
|
||||
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz",
|
||||
"integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "~0.27.0",
|
||||
"get-tsconfig": "^4.7.5"
|
||||
},
|
||||
"bin": {
|
||||
"tsx": "dist/cli.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.3"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"devOptional": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/unicode-properties": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz",
|
||||
"integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.0",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unicode-trie": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
|
||||
"integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
|
||||
"dependencies": {
|
||||
"pako": "^0.2.5",
|
||||
"tiny-inflate": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.25.76",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
node_modules/@esbuild/linux-x64/README.md
generated
vendored
Normal file
3
node_modules/@esbuild/linux-x64/README.md
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# esbuild
|
||||
|
||||
This is the Linux 64-bit binary for esbuild, a JavaScript bundler and minifier. See https://github.com/evanw/esbuild for details.
|
||||
BIN
node_modules/@esbuild/linux-x64/bin/esbuild
generated
vendored
Executable file
BIN
node_modules/@esbuild/linux-x64/bin/esbuild
generated
vendored
Executable file
Binary file not shown.
20
node_modules/@esbuild/linux-x64/package.json
generated
vendored
Normal file
20
node_modules/@esbuild/linux-x64/package.json
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "@esbuild/linux-x64",
|
||||
"version": "0.27.2",
|
||||
"description": "The Linux 64-bit binary for esbuild, a JavaScript bundler.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/evanw/esbuild.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"preferUnplugged": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
]
|
||||
}
|
||||
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: Continuous Integration
|
||||
|
||||
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@v3
|
||||
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.
|
||||
236
node_modules/@fastify/ajv-compiler/README.md
generated
vendored
Normal file
236
node_modules/@fastify/ajv-compiler/README.md
generated
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
# @fastify/ajv-compiler
|
||||
|
||||
[](http://standardjs.com/)
|
||||
[](https://github.com/fastify/ajv-compiler/actions/workflows/ci.yml)
|
||||
|
||||
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` |
|
||||
|------------------------:|------:|---------------------:|
|
||||
| v1.x | v6.x | ^3.14 |
|
||||
| v2.x | v8.x | - |
|
||||
| v3.x | v8.x | ^4.x |
|
||||
|
||||
|
||||
### 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`'s options, see how in the [Fastify official docs](https://fastify.dev/docs/latest/Reference/Server/#ajv).
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
This module is already used as default by Fastify.
|
||||
If you need to provide to your server instance a different version, refer to [the official doc](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 precendence 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 syncronous 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 defaults AJV JTD options are the same as the [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 introduces the [standalone feature](https://ajv.js.org/standalone.html) that let you to 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 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 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 provide 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 inizialization
|
||||
|
||||
|
||||
## 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 })
|
||||
}
|
||||
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
|
||||
54
node_modules/@fastify/ajv-compiler/package.json
generated
vendored
Normal file
54
node_modules/@fastify/ajv-compiler/package.json
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"name": "@fastify/ajv-compiler",
|
||||
"version": "3.6.0",
|
||||
"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": "standard",
|
||||
"lint:fix": "standard --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)",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/fastify/ajv-compiler/issues"
|
||||
},
|
||||
"homepage": "https://github.com/fastify/ajv-compiler#readme",
|
||||
"devDependencies": {
|
||||
"ajv-cli": "^5.0.0",
|
||||
"ajv-errors": "^3.0.0",
|
||||
"ajv-i18n": "^4.0.1",
|
||||
"ajv-merge-patch": "^5.0.1",
|
||||
"cronometro": "^3.0.1",
|
||||
"fastify": "^4.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"standard": "^17.0.0",
|
||||
"tap": "^16.2.0",
|
||||
"tsd": "^0.31.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": "^8.11.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"fast-uri": "^2.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 { AnySchema, default as _ajv, Options as AjvOptions, ValidateFunction } from "ajv";
|
||||
import { default as 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 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 }
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
export = AjvCompiler
|
||||
227
node_modules/@fastify/ajv-compiler/types/index.test-d.ts
generated
vendored
Normal file
227
node_modules/@fastify/ajv-compiler/types/index.test-d.ts
generated
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
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))
|
||||
}
|
||||
2
node_modules/@fastify/error/.gitattributes
generated
vendored
Normal file
2
node_modules/@fastify/error/.gitattributes
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Set default behavior to automatically convert line endings
|
||||
* text=auto eol=lf
|
||||
13
node_modules/@fastify/error/.github/dependabot.yml
generated
vendored
Normal file
13
node_modules/@fastify/error/.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
|
||||
23
node_modules/@fastify/error/.github/workflows/ci.yml
generated
vendored
Normal file
23
node_modules/@fastify/error/.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@v3
|
||||
with:
|
||||
license-check: true
|
||||
lint: true
|
||||
2
node_modules/@fastify/error/.taprc
generated
vendored
Normal file
2
node_modules/@fastify/error/.taprc
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
files:
|
||||
- test/**/*.test.js
|
||||
21
node_modules/@fastify/error/LICENSE
generated
vendored
Normal file
21
node_modules/@fastify/error/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Fastify
|
||||
|
||||
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.
|
||||
62
node_modules/@fastify/error/README.md
generated
vendored
Normal file
62
node_modules/@fastify/error/README.md
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
# @fastify/error
|
||||
|
||||

|
||||
[](https://www.npmjs.com/package/@fastify/error)
|
||||
[](https://standardjs.com/)
|
||||
|
||||
A small utility, used by Fastify itself, for generating consistent error objects across your codebase and plugins.
|
||||
|
||||
### Install
|
||||
```
|
||||
npm i @fastify/error
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
The module exports a function that you can use for consistent error objects, it takes 4 parameters:
|
||||
|
||||
```
|
||||
createError(code, message [, statusCode [, Base]])
|
||||
```
|
||||
|
||||
- `code` (`string`, required) - The error code, you can access it later with `error.code`. For consistency, we recommend prefixing plugin error codes with `FST_`
|
||||
- `message` (`string`, required) - The error message. You can also use interpolated strings for formatting the message.
|
||||
- `statusCode` (`number`, optional) - The status code that Fastify will use if the error is sent via HTTP.
|
||||
- `Base` (`ErrorConstructor`, optional) - The base error object that will be used. (eg `TypeError`, `RangeError`)
|
||||
|
||||
```js
|
||||
const createError = require('@fastify/error')
|
||||
const CustomError = createError('ERROR_CODE', 'Hello')
|
||||
console.log(new CustomError()) // error.message => 'Hello'
|
||||
```
|
||||
|
||||
How to use an interpolated string:
|
||||
```js
|
||||
const createError = require('@fastify/error')
|
||||
const CustomError = createError('ERROR_CODE', 'Hello %s')
|
||||
console.log(new CustomError('world')) // error.message => 'Hello world'
|
||||
```
|
||||
|
||||
How to add cause:
|
||||
```js
|
||||
const createError = require('@fastify/error')
|
||||
const CustomError = createError('ERROR_CODE', 'Hello %s')
|
||||
console.log(new CustomError('world', {cause: new Error('cause')}))
|
||||
// error.message => 'Hello world'
|
||||
// error.cause => Error('cause')
|
||||
```
|
||||
|
||||
### TypeScript
|
||||
|
||||
It is possible to limit your error constructor with a generic type using TypeScript:
|
||||
|
||||
```ts
|
||||
const CustomError = createError<[string]>('ERROR_CODE', 'Hello %s')
|
||||
new CustomError('world')
|
||||
//@ts-expect-error
|
||||
new CustomError(1)
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Licensed under [MIT](./LICENSE).
|
||||
9
node_modules/@fastify/error/benchmarks/create.js
generated
vendored
Normal file
9
node_modules/@fastify/error/benchmarks/create.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
'use strict'
|
||||
|
||||
const benchmark = require('benchmark')
|
||||
const createError = require('..')
|
||||
|
||||
new benchmark.Suite()
|
||||
.add('create FastifyError', function () { createError('CODE', 'Not available') }, { minSamples: 100 })
|
||||
.on('cycle', function onCycle (event) { console.log(String(event.target)) })
|
||||
.run({ async: false })
|
||||
18
node_modules/@fastify/error/benchmarks/instantiate.js
generated
vendored
Normal file
18
node_modules/@fastify/error/benchmarks/instantiate.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
'use strict'
|
||||
|
||||
const benchmark = require('benchmark')
|
||||
const createError = require('..')
|
||||
|
||||
const FastifyError = createError('CODE', 'Not available')
|
||||
const FastifyError1 = createError('CODE', 'Not %s available')
|
||||
const FastifyError2 = createError('CODE', 'Not %s available %s')
|
||||
|
||||
const cause = new Error('cause')
|
||||
new benchmark.Suite()
|
||||
.add('instantiate Error', function () { new Error() }, { minSamples: 100 }) // eslint-disable-line no-new
|
||||
.add('instantiate FastifyError', function () { new FastifyError() }, { minSamples: 100 }) // eslint-disable-line no-new
|
||||
.add('instantiate FastifyError arg 1', function () { new FastifyError1('q') }, { minSamples: 100 }) // eslint-disable-line no-new
|
||||
.add('instantiate FastifyError arg 2', function () { new FastifyError2('qq', 'ss') }, { minSamples: 100 }) // eslint-disable-line no-new
|
||||
.add('instantiate FastifyError cause', function () { new FastifyError2({ cause }) }, { minSamples: 100 }) // eslint-disable-line no-new
|
||||
.on('cycle', function onCycle (event) { console.log(String(event.target)) })
|
||||
.run({ async: false })
|
||||
13
node_modules/@fastify/error/benchmarks/no-stack.js
generated
vendored
Normal file
13
node_modules/@fastify/error/benchmarks/no-stack.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict'
|
||||
|
||||
const benchmark = require('benchmark')
|
||||
const createError = require('..')
|
||||
|
||||
const FastifyError = createError('CODE', 'Not available')
|
||||
Error.stackTraceLimit = 0
|
||||
|
||||
new benchmark.Suite()
|
||||
.add('no-stack instantiate Error', function () { new Error() }, { minSamples: 100 }) // eslint-disable-line no-new
|
||||
.add('no-stack instantiate FastifyError', function () { new FastifyError() }, { minSamples: 100 }) // eslint-disable-line no-new
|
||||
.on('cycle', function onCycle (event) { console.log(String(event.target)) })
|
||||
.run({ async: false })
|
||||
11
node_modules/@fastify/error/benchmarks/toString.js
generated
vendored
Normal file
11
node_modules/@fastify/error/benchmarks/toString.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
'use strict'
|
||||
|
||||
const benchmark = require('benchmark')
|
||||
const createError = require('..')
|
||||
|
||||
const FastifyError = createError('CODE', 'Not available')
|
||||
|
||||
new benchmark.Suite()
|
||||
.add('FastifyError toString', function () { new FastifyError().toString() }, { minSamples: 100 })
|
||||
.on('cycle', function onCycle (event) { console.log(String(event.target)) })
|
||||
.run({ async: false })
|
||||
53
node_modules/@fastify/error/index.js
generated
vendored
Normal file
53
node_modules/@fastify/error/index.js
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
'use strict'
|
||||
|
||||
const { format } = require('node:util')
|
||||
|
||||
function toString () {
|
||||
return `${this.name} [${this.code}]: ${this.message}`
|
||||
}
|
||||
|
||||
function createError (code, message, statusCode = 500, Base = Error) {
|
||||
if (!code) throw new Error('Fastify error code must not be empty')
|
||||
if (!message) throw new Error('Fastify error message must not be empty')
|
||||
|
||||
code = code.toUpperCase()
|
||||
!statusCode && (statusCode = undefined)
|
||||
|
||||
function FastifyError (...args) {
|
||||
if (!new.target) {
|
||||
return new FastifyError(...args)
|
||||
}
|
||||
|
||||
this.code = code
|
||||
this.name = 'FastifyError'
|
||||
this.statusCode = statusCode
|
||||
|
||||
const lastElement = args.length - 1
|
||||
if (lastElement !== -1 && args[lastElement] && typeof args[lastElement] === 'object' && 'cause' in args[lastElement]) {
|
||||
this.cause = args.pop().cause
|
||||
}
|
||||
|
||||
this.message = format(message, ...args)
|
||||
|
||||
Error.stackTraceLimit !== 0 && Error.captureStackTrace(this, FastifyError)
|
||||
}
|
||||
|
||||
FastifyError.prototype = Object.create(Base.prototype, {
|
||||
constructor: {
|
||||
value: FastifyError,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true
|
||||
}
|
||||
})
|
||||
|
||||
FastifyError.prototype[Symbol.toStringTag] = 'Error'
|
||||
|
||||
FastifyError.prototype.toString = toString
|
||||
|
||||
return FastifyError
|
||||
}
|
||||
|
||||
module.exports = createError
|
||||
module.exports.default = createError
|
||||
module.exports.createError = createError
|
||||
45
node_modules/@fastify/error/package.json
generated
vendored
Normal file
45
node_modules/@fastify/error/package.json
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "@fastify/error",
|
||||
"version": "3.4.1",
|
||||
"description": "A small utility, used by Fastify itself, for generating consistent error objects across your codebase and plugins.",
|
||||
"main": "index.js",
|
||||
"type": "commonjs",
|
||||
"types": "types/index.d.ts",
|
||||
"scripts": {
|
||||
"lint": "standard",
|
||||
"lint:fix": "standard --fix",
|
||||
"test": "npm run test:unit && npm run test:typescript",
|
||||
"test:unit": "tap",
|
||||
"test:typescript": "tsd"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/fastify/fastify-error.git"
|
||||
},
|
||||
"keywords": [
|
||||
"fastify",
|
||||
"error",
|
||||
"utility",
|
||||
"plugin"
|
||||
],
|
||||
"author": "Tomas Della Vedova",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/fastify/fastify-error/issues"
|
||||
},
|
||||
"homepage": "https://github.com/fastify/fastify-error#readme",
|
||||
"devDependencies": {
|
||||
"benchmark": "^2.1.4",
|
||||
"standard": "^17.0.0",
|
||||
"tap": "^16.0.0",
|
||||
"tsd": "^0.29.0"
|
||||
},
|
||||
"tsd": {
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true
|
||||
}
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
184
node_modules/@fastify/error/test/index.test.js
generated
vendored
Normal file
184
node_modules/@fastify/error/test/index.test.js
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const createError = require('..')
|
||||
|
||||
test('Create error with zero parameter', t => {
|
||||
t.plan(6)
|
||||
|
||||
const NewError = createError('CODE', 'Not available')
|
||||
const err = new NewError()
|
||||
t.ok(err instanceof Error)
|
||||
t.equal(err.name, 'FastifyError')
|
||||
t.equal(err.message, 'Not available')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, 500)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('Create error with 1 parameter', t => {
|
||||
t.plan(6)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s')
|
||||
const err = new NewError('alice')
|
||||
t.ok(err instanceof Error)
|
||||
t.equal(err.name, 'FastifyError')
|
||||
t.equal(err.message, 'hey alice')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, 500)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('Create error with 1 parameter set to undefined', t => {
|
||||
t.plan(1)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s')
|
||||
const err = new NewError(undefined)
|
||||
t.equal(err.message, 'hey undefined')
|
||||
})
|
||||
|
||||
test('Create error with 2 parameters', (t) => {
|
||||
t.plan(6)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s, I like your %s')
|
||||
const err = new NewError('alice', 'attitude')
|
||||
t.ok(err instanceof Error)
|
||||
t.equal(err.name, 'FastifyError')
|
||||
t.equal(err.message, 'hey alice, I like your attitude')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, 500)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('Create error with 2 parameters set to undefined', t => {
|
||||
t.plan(1)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s, I like your %s')
|
||||
const err = new NewError(undefined, undefined)
|
||||
t.equal(err.message, 'hey undefined, I like your undefined')
|
||||
})
|
||||
|
||||
test('Create error with 3 parameters', t => {
|
||||
t.plan(6)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s, I like your %s %s')
|
||||
const err = new NewError('alice', 'attitude', 'see you')
|
||||
t.ok(err instanceof Error)
|
||||
t.equal(err.name, 'FastifyError')
|
||||
t.equal(err.message, 'hey alice, I like your attitude see you')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, 500)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('Create error with 3 parameters set to undefined', t => {
|
||||
t.plan(4)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s, I like your %s %s')
|
||||
const err = new NewError(undefined, undefined, undefined)
|
||||
t.equal(err.message, 'hey undefined, I like your undefined undefined')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, 500)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('Create error with 4 parameters set to undefined', t => {
|
||||
t.plan(4)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s, I like your %s %s and %s')
|
||||
const err = new NewError(undefined, undefined, undefined, undefined)
|
||||
t.equal(err.message, 'hey undefined, I like your undefined undefined and undefined')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, 500)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('Create error with no statusCode property', t => {
|
||||
t.plan(6)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s', 0)
|
||||
const err = new NewError('dude')
|
||||
t.ok(err instanceof Error)
|
||||
t.equal(err.name, 'FastifyError')
|
||||
t.equal(err.message, 'hey dude')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, undefined)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('Should throw when error code has no fastify code', t => {
|
||||
t.plan(1)
|
||||
|
||||
t.throws(() => createError(), new Error('Fastify error code must not be empty'))
|
||||
})
|
||||
|
||||
test('Should throw when error code has no message', t => {
|
||||
t.plan(1)
|
||||
|
||||
t.throws(() => createError('code'), new Error('Fastify error message must not be empty'))
|
||||
})
|
||||
|
||||
test('Create error with different base', t => {
|
||||
t.plan(7)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s', 500, TypeError)
|
||||
const err = new NewError('dude')
|
||||
t.ok(err instanceof Error)
|
||||
t.ok(err instanceof TypeError)
|
||||
t.equal(err.name, 'FastifyError')
|
||||
t.equal(err.message, 'hey dude')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, 500)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('FastifyError.toString returns code', t => {
|
||||
t.plan(1)
|
||||
|
||||
const NewError = createError('CODE', 'foo')
|
||||
const err = new NewError()
|
||||
t.equal(err.toString(), 'FastifyError [CODE]: foo')
|
||||
})
|
||||
|
||||
test('Create the error without the new keyword', t => {
|
||||
t.plan(6)
|
||||
|
||||
const NewError = createError('CODE', 'Not available')
|
||||
const err = NewError()
|
||||
t.ok(err instanceof Error)
|
||||
t.equal(err.name, 'FastifyError')
|
||||
t.equal(err.message, 'Not available')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, 500)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('Create an error with cause', t => {
|
||||
t.plan(2)
|
||||
const cause = new Error('HEY')
|
||||
const NewError = createError('CODE', 'Not available')
|
||||
const err = NewError({ cause })
|
||||
|
||||
t.ok(err instanceof Error)
|
||||
t.equal(err.cause, cause)
|
||||
})
|
||||
|
||||
test('Create an error with cause and message', t => {
|
||||
t.plan(2)
|
||||
const cause = new Error('HEY')
|
||||
const NewError = createError('CODE', 'Not available: %s')
|
||||
const err = NewError('foo', { cause })
|
||||
|
||||
t.ok(err instanceof Error)
|
||||
t.equal(err.cause, cause)
|
||||
})
|
||||
|
||||
test('Create an error with last argument null', t => {
|
||||
t.plan(2)
|
||||
const cause = new Error('HEY')
|
||||
const NewError = createError('CODE', 'Not available')
|
||||
const err = NewError({ cause }, null)
|
||||
|
||||
t.ok(err instanceof Error)
|
||||
t.notOk(err.cause)
|
||||
})
|
||||
44
node_modules/@fastify/error/types/index.d.ts
generated
vendored
Normal file
44
node_modules/@fastify/error/types/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
declare function createError<C extends string, SC extends number, Arg extends unknown[] = [any?, any?, any?]> (
|
||||
code: C,
|
||||
message: string,
|
||||
statusCode: SC,
|
||||
Base?: ErrorConstructor
|
||||
): createError.FastifyErrorConstructor<{ code: C, statusCode: SC }, Arg>
|
||||
|
||||
declare function createError<C extends string, Arg extends unknown[] = [any?, any?, any?]> (
|
||||
code: C,
|
||||
message: string,
|
||||
statusCode?: number,
|
||||
Base?: ErrorConstructor
|
||||
): createError.FastifyErrorConstructor<{ code: C }, Arg>
|
||||
|
||||
declare function createError<Arg extends unknown[] = [any?, any?, any?]> (
|
||||
code: string,
|
||||
message: string,
|
||||
statusCode?: number,
|
||||
Base?: ErrorConstructor
|
||||
): createError.FastifyErrorConstructor<{ code: string }, Arg>
|
||||
|
||||
type CreateError = typeof createError
|
||||
|
||||
declare namespace createError {
|
||||
export interface FastifyError extends Error {
|
||||
code: string
|
||||
name: string
|
||||
statusCode?: number
|
||||
}
|
||||
|
||||
export interface FastifyErrorConstructor<
|
||||
E extends { code: string, statusCode?: number } = { code: string, statusCode?: number },
|
||||
T extends unknown[] = [any?, any?, any?]
|
||||
> {
|
||||
new(...arg: T): FastifyError & E
|
||||
(...arg: T): FastifyError & E
|
||||
readonly prototype: FastifyError & E
|
||||
}
|
||||
|
||||
export const createError: CreateError
|
||||
export { createError as default }
|
||||
}
|
||||
|
||||
export = createError
|
||||
72
node_modules/@fastify/error/types/index.test-d.ts
generated
vendored
Normal file
72
node_modules/@fastify/error/types/index.test-d.ts
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
import createError, { FastifyError, FastifyErrorConstructor } from '..'
|
||||
import { expectType, expectError } from 'tsd'
|
||||
|
||||
const CustomError = createError('ERROR_CODE', 'message')
|
||||
expectType<FastifyErrorConstructor<{ code: 'ERROR_CODE' }>>(CustomError)
|
||||
const err = new CustomError()
|
||||
expectType<FastifyError & { code: 'ERROR_CODE' }>(err)
|
||||
expectType<'ERROR_CODE'>(err.code)
|
||||
expectType<string>(err.message)
|
||||
expectType<number | undefined>(err.statusCode)
|
||||
|
||||
const CustomTypedError = createError('OTHER_CODE', 'message', 400)
|
||||
expectType<FastifyErrorConstructor<{ code: 'OTHER_CODE', statusCode: 400 }>>(CustomTypedError)
|
||||
const typed = new CustomTypedError()
|
||||
expectType<FastifyError & { code: 'OTHER_CODE', statusCode: 400 }>(typed)
|
||||
expectType<'OTHER_CODE'>(typed.code)
|
||||
expectType<string>(typed.message)
|
||||
expectType<400>(typed.statusCode)
|
||||
|
||||
/* eslint-disable no-new */
|
||||
const CustomTypedArgError = createError<[string]>('OTHER_CODE', 'expect %s message', 400)
|
||||
CustomTypedArgError('a')
|
||||
expectError(CustomTypedArgError('a', 'b'))
|
||||
expectError(new CustomTypedArgError('a', 'b'))
|
||||
expectError(CustomTypedArgError(1))
|
||||
expectError(new CustomTypedArgError(1))
|
||||
|
||||
const CustomTypedArgError2 = createError<string, number, [string]>('OTHER_CODE', 'expect %s message', 400)
|
||||
CustomTypedArgError2('a')
|
||||
expectError(CustomTypedArgError2('a', 'b'))
|
||||
expectError(new CustomTypedArgError2('a', 'b'))
|
||||
expectError(CustomTypedArgError2(1))
|
||||
expectError(new CustomTypedArgError2(1))
|
||||
|
||||
const CustomTypedArgError3 = createError<string, number, [string, string]>('OTHER_CODE', 'expect %s message but got %s', 400)
|
||||
expectError(CustomTypedArgError3('a'))
|
||||
CustomTypedArgError3('a', 'b')
|
||||
new CustomTypedArgError3('a', 'b')
|
||||
expectError(CustomTypedArgError3(1))
|
||||
expectError(new CustomTypedArgError3(1))
|
||||
expectError(new CustomTypedArgError3(1, 2))
|
||||
expectError(new CustomTypedArgError3('1', 2))
|
||||
expectError(new CustomTypedArgError3(1, '2'))
|
||||
|
||||
const CustomTypedArgError4 = createError<string, number, [string, string]>('OTHER_CODE', 'expect %s message but got %s', 400)
|
||||
expectError(CustomTypedArgError4('a'))
|
||||
CustomTypedArgError4('a', 'b')
|
||||
new CustomTypedArgError4('a', 'b')
|
||||
expectError(CustomTypedArgError4(1))
|
||||
expectError(new CustomTypedArgError4(1))
|
||||
expectError(new CustomTypedArgError4(1, 2))
|
||||
expectError(new CustomTypedArgError4('1', 2))
|
||||
expectError(new CustomTypedArgError4(1, '2'))
|
||||
|
||||
const CustomTypedArgError5 = createError<[string, string, string, string]>('OTHER_CODE', 'expect %s message but got %s. Please contact %s by emailing to %s', 400)
|
||||
expectError(CustomTypedArgError5('a'))
|
||||
expectError(new CustomTypedArgError5('a', 'b'))
|
||||
expectError(new CustomTypedArgError5('a', 'b', 'c'))
|
||||
CustomTypedArgError5('a', 'b', 'c', 'd')
|
||||
expectError(new CustomTypedArgError5('a', 'b', 'c', 'd', 'e'))
|
||||
|
||||
const CustomTypedArgError6 = createError<string, number, [string, string, string, string]>('OTHER_CODE', 'expect %s message but got %s. Please contact %s by emailing to %s', 400)
|
||||
expectError(CustomTypedArgError6('a'))
|
||||
expectError(new CustomTypedArgError6('a', 'b'))
|
||||
expectError(new CustomTypedArgError6('a', 'b', 'c'))
|
||||
CustomTypedArgError6('a', 'b', 'c', 'd')
|
||||
expectError(new CustomTypedArgError6('a', 'b', 'c', 'd', 'e'))
|
||||
|
||||
|
||||
const CustomErrorWithErrorConstructor = createError('ERROR_CODE', 'message', 500, TypeError)
|
||||
expectType<FastifyErrorConstructor<{ code: 'ERROR_CODE', statusCode: 500 }>>(CustomErrorWithErrorConstructor)
|
||||
CustomErrorWithErrorConstructor({cause: new Error('Error')})
|
||||
1
node_modules/@fastify/fast-json-stringify-compiler/.eslintrc
generated
vendored
Normal file
1
node_modules/@fastify/fast-json-stringify-compiler/.eslintrc
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"extends": "standard"}
|
||||
13
node_modules/@fastify/fast-json-stringify-compiler/.github/dependabot.yml
generated
vendored
Normal file
13
node_modules/@fastify/fast-json-stringify-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
|
||||
18
node_modules/@fastify/fast-json-stringify-compiler/.github/workflows/ci.yml
generated
vendored
Normal file
18
node_modules/@fastify/fast-json-stringify-compiler/.github/workflows/ci.yml
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
uses: fastify/workflows/.github/workflows/plugins-ci.yml@v3
|
||||
with:
|
||||
license-check: true
|
||||
lint: true
|
||||
21
node_modules/@fastify/fast-json-stringify-compiler/LICENSE
generated
vendored
Normal file
21
node_modules/@fastify/fast-json-stringify-compiler/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Fastify
|
||||
|
||||
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.
|
||||
127
node_modules/@fastify/fast-json-stringify-compiler/README.md
generated
vendored
Normal file
127
node_modules/@fastify/fast-json-stringify-compiler/README.md
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
# @fastify/fast-json-stringify-compiler
|
||||
Build and manage the [`fast-json-stringify`](https://www.npmjs.com/package/fast-json-stringify) instances for the fastify framework.
|
||||
This package is responsible for compiling the application's `response` JSON schemas into optimized functions to speed up the response time.
|
||||
|
||||
[](http://standardjs.com/)
|
||||
[](https://github.com/fastify/fast-json-stringify-compiler/actions/workflows/ci.yml)
|
||||
|
||||
|
||||
## Versions
|
||||
|
||||
| `@fastify/fast-json-stringify-compiler` | `fast-json-stringify` | Supported `fastify` |
|
||||
|----------------------------------------:|----------------------:|--------------------:|
|
||||
| v1.x | v3.x | ^3.x |
|
||||
| v2.x | v3.x | ^4.x |
|
||||
| v3.x | v4.x | ^4.x |
|
||||
| v4.x | v5.x | ^4.x |
|
||||
|
||||
### fast-json-stringify Configuration
|
||||
|
||||
The `fast-json-stringify` configuration is the default one. You can check it the default settings in the [`fast-json-stringify` option](https://github.com/fastify/fast-json-stringify/#options) documentation.
|
||||
|
||||
You can also override the default configuration by passing the [`serializerOpts`](https://www.fastify.io/docs/latest/Reference/Server/#serializeropts) configuration to the Fastify instance.
|
||||
|
||||
## Usage
|
||||
|
||||
This module is already used as default by Fastify.
|
||||
If you need to provide to your server instance a different version, refer to [the official doc](https://www.fastify.io/docs/latest/Reference/Server/#schemacontroller).
|
||||
|
||||
### fast-json-stringify Standalone
|
||||
|
||||
`fast-json-stringify@v4.1.0` introduces the [standalone feature](https://github.com/fastify/fast-json-stringify#standalone) that let you to 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 serialization schemas functions and it is your choice to save them where you want.
|
||||
To accomplish this, you must use a new compiler: `@fastify/fast-json-stringify-compiler/standalone`.
|
||||
|
||||
You must provide 2 parameters to this compiler:
|
||||
|
||||
- `readMode: false`: a boolean to indicate that you want 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 { StandaloneSerializer } = require('@fastify/fast-json-stringify-compiler')
|
||||
|
||||
const factory = StandaloneSerializer({
|
||||
readMode: false,
|
||||
storeFunction (routeOpts, schemaSerializationCode) {
|
||||
// routeOpts is like: { schema, method, url, httpStatus }
|
||||
// schemaSerializationCode is a string source code that is the compiled schema function
|
||||
const fileName = generateFileName(routeOpts)
|
||||
fs.writeFileSync(path.join(__dirname, fileName), schemaSerializationCode)
|
||||
}
|
||||
})
|
||||
|
||||
const app = fastify({
|
||||
jsonShorthand: false,
|
||||
schemaController: {
|
||||
compilersFactory: {
|
||||
buildSerializer: 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 `@fastify/fast-json-stringify-compiler/standalone` with the parameters:
|
||||
|
||||
- `readMode: true`: a boolean to indicate that you want read and use the schemas functions string.
|
||||
- `restoreFunction`" a sync function that must return a function to serialize the route's payload.
|
||||
|
||||
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 { StandaloneSerializer } = require('@fastify/fast-json-stringify-compiler')
|
||||
|
||||
const factory = StandaloneSerializer({
|
||||
readMode: true,
|
||||
restoreFunction (routeOpts) {
|
||||
// routeOpts is like: { schema, method, url, httpStatus }
|
||||
const fileName = generateFileName(routeOpts)
|
||||
return require(path.join(__dirname, fileName))
|
||||
}
|
||||
})
|
||||
|
||||
const app = fastify({
|
||||
jsonShorthand: false,
|
||||
schemaController: {
|
||||
compilersFactory: {
|
||||
buildSerializer: factory
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// ... add all your routes with schemas as before...
|
||||
|
||||
app.listen({ port: 3000 })
|
||||
```
|
||||
|
||||
### How it works
|
||||
|
||||
This module provide a factory function to produce [Serializer Compilers](https://www.fastify.io/docs/latest/Reference/Server/#serializercompiler) functions.
|
||||
|
||||
## License
|
||||
|
||||
Licensed under [MIT](./LICENSE).
|
||||
23
node_modules/@fastify/fast-json-stringify-compiler/index.js
generated
vendored
Normal file
23
node_modules/@fastify/fast-json-stringify-compiler/index.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
'use strict'
|
||||
|
||||
const fastJsonStringify = require('fast-json-stringify')
|
||||
|
||||
function SerializerSelector () {
|
||||
return function buildSerializerFactory (externalSchemas, serializerOpts) {
|
||||
const fjsOpts = Object.assign({}, serializerOpts, { schema: externalSchemas })
|
||||
return responseSchemaCompiler.bind(null, fjsOpts)
|
||||
}
|
||||
}
|
||||
|
||||
function responseSchemaCompiler (fjsOpts, { schema /* method, url, httpStatus */ }) {
|
||||
if (fjsOpts.schema && schema.$id && fjsOpts.schema[schema.$id]) {
|
||||
fjsOpts.schema = { ...fjsOpts.schema }
|
||||
delete fjsOpts.schema[schema.$id]
|
||||
}
|
||||
return fastJsonStringify(schema, fjsOpts)
|
||||
}
|
||||
|
||||
module.exports = SerializerSelector
|
||||
module.exports.default = SerializerSelector
|
||||
module.exports.SerializerSelector = SerializerSelector
|
||||
module.exports.StandaloneSerializer = require('./standalone')
|
||||
40
node_modules/@fastify/fast-json-stringify-compiler/package.json
generated
vendored
Normal file
40
node_modules/@fastify/fast-json-stringify-compiler/package.json
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "@fastify/fast-json-stringify-compiler",
|
||||
"description": "Build and manage the fast-json-stringify instances for the fastify framework",
|
||||
"version": "4.3.0",
|
||||
"main": "index.js",
|
||||
"types": "types/index.d.ts",
|
||||
"scripts": {
|
||||
"lint": "standard",
|
||||
"lint:fix": "standard --fix",
|
||||
"unit": "tap test/**/*.test.js",
|
||||
"test": "npm run unit && npm run test:typescript",
|
||||
"test:typescript": "tsd"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/fastify/fast-json-stringify-compiler.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Manuel Spigolon <manuel.spigolon@nearform.com> (https://github.com/Eomm)",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/fastify/fast-json-stringify-compiler/issues"
|
||||
},
|
||||
"homepage": "https://github.com/fastify/fast-json-stringify-compiler#readme",
|
||||
"devDependencies": {
|
||||
"@fastify/pre-commit": "^2.0.2",
|
||||
"fastify": "^4.0.0",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"standard": "^17.0.0",
|
||||
"tap": "^16.0.0",
|
||||
"tsd": "^0.28.0"
|
||||
},
|
||||
"pre-commit": [
|
||||
"lint",
|
||||
"test"
|
||||
],
|
||||
"dependencies": {
|
||||
"fast-json-stringify": "^5.7.0"
|
||||
}
|
||||
}
|
||||
42
node_modules/@fastify/fast-json-stringify-compiler/standalone.js
generated
vendored
Normal file
42
node_modules/@fastify/fast-json-stringify-compiler/standalone.js
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
'use strict'
|
||||
|
||||
const SerializerSelector = require('./index')
|
||||
|
||||
function StandaloneSerializer (options = { readMode: true }) {
|
||||
if (options.readMode === true && typeof options.restoreFunction !== 'function') {
|
||||
throw new Error('You must provide a function for the restoreFunction-option when readMode ON')
|
||||
}
|
||||
|
||||
if (options.readMode !== true && typeof options.storeFunction !== 'function') {
|
||||
throw new Error('You must provide a function for the storeFunction-option 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 SerializerSelector, wrapping the API to run the Ajv Standalone code generation
|
||||
const factory = SerializerSelector()
|
||||
return function wrapper (externalSchemas, serializerOpts = {}) {
|
||||
// to generate the serialization source code, this option is mandatory
|
||||
serializerOpts.mode = 'standalone'
|
||||
|
||||
const compiler = factory(externalSchemas, serializerOpts)
|
||||
return function (opts) { // { schema/*, method, url, httpPart */ }
|
||||
const serializeFuncCode = compiler(opts)
|
||||
|
||||
options.storeFunction(opts, serializeFuncCode)
|
||||
|
||||
// eslint-disable-next-line no-new-func
|
||||
return new Function(serializeFuncCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = StandaloneSerializer
|
||||
module.exports.default = StandaloneSerializer
|
||||
26
node_modules/@fastify/fast-json-stringify-compiler/test/duplicate-schema.test.js
generated
vendored
Normal file
26
node_modules/@fastify/fast-json-stringify-compiler/test/duplicate-schema.test.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const FjsCompiler = require('../index')
|
||||
|
||||
t.test('Use input schema duplicate in the externalSchemas', async t => {
|
||||
t.plan(1)
|
||||
const externalSchemas = {
|
||||
schema1: {
|
||||
$id: 'schema1',
|
||||
type: 'number'
|
||||
},
|
||||
schema2: {
|
||||
$id: 'schema2',
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
|
||||
const factory = FjsCompiler()
|
||||
const compiler = factory(externalSchemas)
|
||||
|
||||
compiler({ schema: externalSchemas.schema1 })
|
||||
compiler({ schema: externalSchemas.schema2 })
|
||||
|
||||
t.pass()
|
||||
})
|
||||
78
node_modules/@fastify/fast-json-stringify-compiler/test/plugin.test.js
generated
vendored
Normal file
78
node_modules/@fastify/fast-json-stringify-compiler/test/plugin.test.js
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const fastify = require('fastify')
|
||||
const FjsCompiler = require('../index')
|
||||
|
||||
const echo = async (req, reply) => { return req.body }
|
||||
|
||||
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 fastifyFjsOptionsDefault = Object.freeze({})
|
||||
|
||||
t.test('basic usage', t => {
|
||||
t.plan(1)
|
||||
const factory = FjsCompiler()
|
||||
const compiler = factory(externalSchemas1, fastifyFjsOptionsDefault)
|
||||
const serializeFunc = compiler({ schema: sampleSchema })
|
||||
const result = serializeFunc({ name: 'hello' })
|
||||
t.equal(result, '{"name":"hello"}')
|
||||
})
|
||||
|
||||
t.test('fastify integration', async t => {
|
||||
const factory = FjsCompiler()
|
||||
|
||||
const app = fastify({
|
||||
serializerOpts: {
|
||||
rounding: 'ceil'
|
||||
},
|
||||
schemaController: {
|
||||
compilersFactory: {
|
||||
buildSerializer: factory
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
app.addSchema(externalSchemas2.foo)
|
||||
|
||||
app.post('/', {
|
||||
handler: echo,
|
||||
schema: {
|
||||
response: {
|
||||
200: {
|
||||
$ref: 'foo#'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const res = await app.inject({
|
||||
url: '/',
|
||||
method: 'POST',
|
||||
payload: {
|
||||
version: '1',
|
||||
foo: 'this is not a number',
|
||||
name: 'serialize me'
|
||||
}
|
||||
})
|
||||
|
||||
t.equal(res.statusCode, 200)
|
||||
t.same(res.json(), { name: 'serialize me' })
|
||||
})
|
||||
230
node_modules/@fastify/fast-json-stringify-compiler/test/standalone.test.js
generated
vendored
Normal file
230
node_modules/@fastify/fast-json-stringify-compiler/test/standalone.test.js
generated
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
'use strict'
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const t = require('tap')
|
||||
const fastify = require('fastify')
|
||||
const sanitize = require('sanitize-filename')
|
||||
|
||||
const { StandaloneSerializer: FjsStandaloneCompiler } = require('../')
|
||||
|
||||
const generatedFileNames = []
|
||||
|
||||
function generateFileName (routeOpts) {
|
||||
const fileName = `/fjs-generated-${sanitize(routeOpts.schema.$id)}-${routeOpts.method}-${routeOpts.httpPart}-${sanitize(routeOpts.url)}.js`
|
||||
generatedFileNames.push(fileName)
|
||||
return fileName
|
||||
}
|
||||
|
||||
t.test('standalone', t => {
|
||||
t.plan(5)
|
||||
|
||||
t.teardown(async () => {
|
||||
for (const fileName of generatedFileNames) {
|
||||
try {
|
||||
await fs.promises.unlink(path.join(__dirname, fileName))
|
||||
} catch (e) {}
|
||||
}
|
||||
})
|
||||
|
||||
t.test('errors', t => {
|
||||
t.plan(2)
|
||||
t.throws(() => {
|
||||
FjsStandaloneCompiler()
|
||||
}, 'missing restoreFunction')
|
||||
t.throws(() => {
|
||||
FjsStandaloneCompiler({ 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 = FjsStandaloneCompiler({
|
||||
readMode: false,
|
||||
storeFunction (routeOpts, schemaSerializerCode) {
|
||||
t.same(routeOpts, endpointSchema)
|
||||
t.type(schemaSerializerCode, 'string')
|
||||
fs.writeFileSync(path.join(__dirname, '/fjs-generated.js'), schemaSerializerCode)
|
||||
generatedFileNames.push('/fjs-generated.js')
|
||||
t.pass('stored the serializer function')
|
||||
}
|
||||
})
|
||||
|
||||
const compiler = factory(schemaMap)
|
||||
compiler(endpointSchema)
|
||||
t.pass('compiled the endpoint schema')
|
||||
|
||||
t.test('usage standalone code', t => {
|
||||
t.plan(3)
|
||||
const standaloneSerializer = require('./fjs-generated')
|
||||
t.ok(standaloneSerializer)
|
||||
|
||||
const valid = standaloneSerializer({ hello: 'world' })
|
||||
t.same(valid, JSON.stringify({ hello: 'world' }))
|
||||
|
||||
const invalid = standaloneSerializer({ hello: [] })
|
||||
t.same(invalid, '{"hello":""}')
|
||||
})
|
||||
})
|
||||
|
||||
t.test('fastify integration - writeMode', async t => {
|
||||
t.plan(4)
|
||||
|
||||
const factory = FjsStandaloneCompiler({
|
||||
readMode: false,
|
||||
storeFunction (routeOpts, schemaSerializationCode) {
|
||||
const fileName = generateFileName(routeOpts)
|
||||
t.ok(routeOpts)
|
||||
fs.writeFileSync(path.join(__dirname, fileName), schemaSerializationCode)
|
||||
t.pass(`stored the serializer function ${fileName}`)
|
||||
},
|
||||
restoreFunction () {
|
||||
t.fail('write mode ON')
|
||||
}
|
||||
})
|
||||
|
||||
const app = buildApp(factory)
|
||||
await app.ready()
|
||||
})
|
||||
|
||||
t.test('fastify integration - writeMode forces standalone', async t => {
|
||||
t.plan(4)
|
||||
|
||||
const factory = FjsStandaloneCompiler({
|
||||
readMode: false,
|
||||
storeFunction (routeOpts, schemaSerializationCode) {
|
||||
const fileName = generateFileName(routeOpts)
|
||||
t.ok(routeOpts)
|
||||
fs.writeFileSync(path.join(__dirname, fileName), schemaSerializationCode)
|
||||
t.pass(`stored the serializer function ${fileName}`)
|
||||
},
|
||||
restoreFunction () {
|
||||
t.fail('write mode ON')
|
||||
}
|
||||
})
|
||||
|
||||
const app = buildApp(factory, {
|
||||
mode: 'not-standalone',
|
||||
rounding: 'ceil'
|
||||
})
|
||||
|
||||
await app.ready()
|
||||
})
|
||||
|
||||
t.test('fastify integration - readMode', async t => {
|
||||
t.plan(6)
|
||||
|
||||
const factory = FjsStandaloneCompiler({
|
||||
readMode: true,
|
||||
storeFunction () {
|
||||
t.fail('read mode ON')
|
||||
},
|
||||
restoreFunction (routeOpts) {
|
||||
const fileName = generateFileName(routeOpts)
|
||||
t.pass(`restore the serializer function ${fileName}}`)
|
||||
return require(path.join(__dirname, fileName))
|
||||
}
|
||||
})
|
||||
|
||||
const app = buildApp(factory)
|
||||
await app.ready()
|
||||
|
||||
let res = await app.inject({
|
||||
url: '/foo',
|
||||
method: 'POST'
|
||||
})
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, JSON.stringify({ hello: 'world' }))
|
||||
|
||||
res = await app.inject({
|
||||
url: '/bar?lang=it',
|
||||
method: 'GET'
|
||||
})
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, JSON.stringify({ lang: 'en' }))
|
||||
})
|
||||
|
||||
function buildApp (factory, serializerOpts) {
|
||||
const app = fastify({
|
||||
exposeHeadRoutes: false,
|
||||
jsonShorthand: false,
|
||||
schemaController: {
|
||||
compilersFactory: {
|
||||
buildSerializer: factory
|
||||
}
|
||||
},
|
||||
serializerOpts
|
||||
})
|
||||
|
||||
app.addSchema({
|
||||
$id: 'urn:schema:foo',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
id: { type: 'integer' }
|
||||
}
|
||||
})
|
||||
|
||||
app.post('/foo', {
|
||||
schema: {
|
||||
response: {
|
||||
200: {
|
||||
$id: 'urn:schema:response',
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { $ref: 'urn:schema:foo#/properties/name' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, () => { return { hello: 'world' } })
|
||||
|
||||
app.get('/bar', {
|
||||
schema: {
|
||||
response: {
|
||||
200: {
|
||||
$id: 'urn:schema:response:bar',
|
||||
type: 'object',
|
||||
properties: {
|
||||
lang: { type: 'string', enum: ['it', 'en'] }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, () => { return { lang: 'en' } })
|
||||
|
||||
return app
|
||||
}
|
||||
})
|
||||
45
node_modules/@fastify/fast-json-stringify-compiler/types/index.d.ts
generated
vendored
Normal file
45
node_modules/@fastify/fast-json-stringify-compiler/types/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
import { Options } from 'fast-json-stringify'
|
||||
|
||||
type FastJsonStringifyFactory = () => SerializerSelector.SerializerFactory
|
||||
|
||||
declare namespace SerializerSelector {
|
||||
export type SerializerFactory = (
|
||||
externalSchemas?: unknown,
|
||||
options?: Options
|
||||
) => SerializerCompiler;
|
||||
|
||||
export type SerializerCompiler = (
|
||||
externalSchemas?: unknown,
|
||||
options?: Options
|
||||
) => Serializer;
|
||||
|
||||
export type Serializer = (doc: any) => string
|
||||
|
||||
export type RouteDefinition = {
|
||||
method: string;
|
||||
url: string;
|
||||
httpStatus: string;
|
||||
schema?: unknown;
|
||||
}
|
||||
|
||||
export type StandaloneOptions = StandaloneOptionsReadModeOn | StandaloneOptionsReadModeOff
|
||||
|
||||
export type StandaloneOptionsReadModeOn = {
|
||||
readMode: true;
|
||||
restoreFunction?(opts: RouteDefinition): Serializer;
|
||||
}
|
||||
|
||||
export type StandaloneOptionsReadModeOff = {
|
||||
readMode?: false | undefined;
|
||||
storeFunction?(opts: RouteDefinition, schemaSerializationCode: string): void;
|
||||
}
|
||||
|
||||
export type { Options }
|
||||
export const SerializerSelector: FastJsonStringifyFactory;
|
||||
export function StandaloneSerializer(options: StandaloneOptions): SerializerFactory;
|
||||
|
||||
export { SerializerSelector as default }
|
||||
}
|
||||
|
||||
declare function SerializerSelector(...params: Parameters<FastJsonStringifyFactory>): ReturnType<FastJsonStringifyFactory>
|
||||
export = SerializerSelector
|
||||
141
node_modules/@fastify/fast-json-stringify-compiler/types/index.test-d.ts
generated
vendored
Normal file
141
node_modules/@fastify/fast-json-stringify-compiler/types/index.test-d.ts
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
import { expectAssignable, expectError, expectType } from "tsd";
|
||||
import SerializerSelector, {
|
||||
RouteDefinition,
|
||||
Serializer,
|
||||
SerializerCompiler,
|
||||
SerializerFactory,
|
||||
SerializerSelector as SerializerSelectorNamed,
|
||||
StandaloneSerializer,
|
||||
} from "..";
|
||||
|
||||
/**
|
||||
* SerializerSelector
|
||||
*/
|
||||
|
||||
{
|
||||
const compiler = SerializerSelector();
|
||||
expectType<SerializerFactory>(compiler);
|
||||
}
|
||||
|
||||
{
|
||||
const compiler = SerializerSelectorNamed();
|
||||
expectType<SerializerFactory>(compiler);
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
const sampleSchema = {
|
||||
$id: 'example1',
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' }
|
||||
}
|
||||
}
|
||||
|
||||
const externalSchemas1 = {}
|
||||
|
||||
const factory = SerializerSelector()
|
||||
expectType<SerializerFactory>(factory);
|
||||
const compiler = factory(externalSchemas1, {})
|
||||
expectType<SerializerCompiler>(compiler);
|
||||
const serializeFunc = compiler({ schema: sampleSchema })
|
||||
expectType<Serializer>(serializeFunc);
|
||||
|
||||
expectType<string>(serializeFunc({ name: 'hello' }))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* StandaloneSerializer
|
||||
*/
|
||||
|
||||
const reader = StandaloneSerializer({
|
||||
readMode: true,
|
||||
restoreFunction: (route: RouteDefinition) => {
|
||||
expectAssignable<RouteDefinition>(route)
|
||||
return {} as Serializer
|
||||
},
|
||||
});
|
||||
expectType<SerializerFactory>(reader);
|
||||
|
||||
const writer = StandaloneSerializer({
|
||||
readMode: false,
|
||||
storeFunction: (route: RouteDefinition, code: string) => {
|
||||
expectAssignable<RouteDefinition>(route)
|
||||
expectAssignable<string>(code)
|
||||
},
|
||||
});
|
||||
expectType<SerializerFactory>(writer);
|
||||
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
expectError(StandaloneSerializer({
|
||||
readMode: true,
|
||||
storeFunction () { }
|
||||
}))
|
||||
expectError(StandaloneSerializer({
|
||||
readMode: false,
|
||||
restoreFunction () {}
|
||||
}))
|
||||
expectError(StandaloneSerializer({
|
||||
restoreFunction () {}
|
||||
}))
|
||||
|
||||
expectType<SerializerFactory>(StandaloneSerializer({
|
||||
storeFunction (routeOpts, schemaSerializerCode) {
|
||||
expectType<RouteDefinition>(routeOpts)
|
||||
expectType<string>(schemaSerializerCode)
|
||||
}
|
||||
}))
|
||||
|
||||
expectType<SerializerFactory>(StandaloneSerializer({
|
||||
readMode: true,
|
||||
restoreFunction (routeOpts) {
|
||||
expectType<RouteDefinition>(routeOpts)
|
||||
return {} as Serializer
|
||||
}
|
||||
}))
|
||||
|
||||
const factory = StandaloneSerializer({
|
||||
readMode: false,
|
||||
storeFunction (routeOpts, schemaSerializerCode) {
|
||||
expectType<RouteDefinition>(routeOpts)
|
||||
expectType<string>(schemaSerializerCode)
|
||||
}
|
||||
})
|
||||
expectType<SerializerFactory>(factory)
|
||||
|
||||
const compiler = factory(schemaMap)
|
||||
expectType<SerializerCompiler>(compiler)
|
||||
expectType<Serializer>(compiler(endpointSchema))
|
||||
}
|
||||
2
node_modules/@fastify/merge-json-schemas/.gitattributes
generated
vendored
Normal file
2
node_modules/@fastify/merge-json-schemas/.gitattributes
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Set default behavior to automatically convert line endings
|
||||
* text=auto eol=lf
|
||||
32
node_modules/@fastify/merge-json-schemas/.github/test.yml
generated
vendored
Normal file
32
node_modules/@fastify/merge-json-schemas/.github/test.yml
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Run Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18.x, 20.x]
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
npm install
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
npm run test
|
||||
21
node_modules/@fastify/merge-json-schemas/LICENSE
generated
vendored
Normal file
21
node_modules/@fastify/merge-json-schemas/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Fastify
|
||||
|
||||
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.
|
||||
115
node_modules/@fastify/merge-json-schemas/README.md
generated
vendored
Normal file
115
node_modules/@fastify/merge-json-schemas/README.md
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
# @fastify/merge-json-schema
|
||||
|
||||
__merge-json-schema__ is a javascript library that build a logical product (AND) for multiple [JSON schemas](https://json-schema.org/draft/2020-12/json-schema-core#name-introduction).
|
||||
|
||||
- [Installation](#installation)
|
||||
- [Usage](#usage)
|
||||
- [API](#api)
|
||||
- [mergeSchemas(schemas, options)](#mergeschemasschemas-options)
|
||||
- [resolvers](#resolvers)
|
||||
- [defaultResolver](#defaultresolver)
|
||||
- [License](#license)
|
||||
|
||||
<a name="installation"></a>
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @fastify/merge-json-schema
|
||||
```
|
||||
|
||||
<a name="usage"></a>
|
||||
|
||||
## Usage
|
||||
|
||||
```javascript
|
||||
const assert = require('node:assert')
|
||||
const { mergeSchemas } = require('merge-json-schema')
|
||||
|
||||
const schema1 = {
|
||||
$id: 'schema1',
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string', enum: ['foo1', 'foo2'] },
|
||||
bar: { type: 'string', minLength: 3 }
|
||||
}
|
||||
}
|
||||
|
||||
const schema2 = {
|
||||
$id: 'schema1',
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string', enum: ['foo1', 'foo3'] },
|
||||
bar: { type: 'string', minLength: 5 }
|
||||
},
|
||||
required: ['foo']
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2])
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
$id: 'schema1',
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string', enum: ['foo1'] },
|
||||
bar: { type: 'string', minLength: 5 }
|
||||
},
|
||||
required: ['foo']
|
||||
})
|
||||
```
|
||||
|
||||
<a name="api"></a>
|
||||
|
||||
## API
|
||||
|
||||
<a name="merge-schemas"></a>
|
||||
|
||||
#### mergeSchemas(schemas, options)
|
||||
|
||||
Builds a logical conjunction (AND) of multiple [JSON schemas](https://json-schema.org/draft/2020-12/json-schema-core#name-introduction).
|
||||
|
||||
- `schemas` __\<objects[]\>__ - list of JSON schemas to merge.
|
||||
- `options` __\<object\>__ - optional options.
|
||||
- `resolvers` __\<object\>__ - custom resolvers for JSON schema keywords. Each key is the name of a JSON schema keyword. Each value is a resolver function. See [keywordResolver](#keywordresolver-keyword-values-mergedschema-parentschemas-options).
|
||||
- `defaultResolver` __\<function\>__ - custom default resolver for JSON schema keywords. See [keywordResolver](#keywordresolver-keyword-values-mergedschema-parentschemas-options).
|
||||
- `onConflict` __\<string\>__ - action to take when a conflict is found. Used by the default `defaultResolver`. Default is `throw`. Possible values are:
|
||||
- `throw` - throws an error if found a multiple different schemas for the same keyword.
|
||||
- `ignore` - do nothing if found a multiple different schemas for the same keyword.
|
||||
- `first` - use the value of the first schema if found a multiple different schemas for the same keyword.
|
||||
|
||||
#### resolvers
|
||||
|
||||
A list of default resolvers that __merge-json-schema__ uses to merge JSON schemas. You can override the default resolvers by passing a list of custom resolvers in the `options` argument of `mergeSchemas`. See [keywordResolver](#keywordresolver-keyword-values-mergedschema-parentschemas-options).
|
||||
|
||||
#### defaultResolver
|
||||
|
||||
A default resolver that __merge-json-schema__ uses to merge JSON schemas. Default resolver is used when no custom resolver is defined for a JSON schema keyword. By default, the default resolver works as follows:
|
||||
|
||||
- If only one schema contains the keyword, the value of the keyword is used as the merged value.
|
||||
- If multiple schemas contain the exact same value for the keyword, the value of the keyword is used as the merged value.
|
||||
- If multiple schemas contain different values for the keyword, it throws an error.
|
||||
|
||||
#### keywordResolver (keyword, values, mergedSchema, parentSchemas, options)
|
||||
|
||||
__merge-json-schema__ uses a set of resolvers to merge JSON schemas. Each resolver is associated with a JSON schema keyword. The resolver is called when the keyword is found in the schemas to merge. The resolver is called with the following arguments:
|
||||
|
||||
- `keyword` __\<string\>__ - the name of the keyword to merge.
|
||||
- `values` __\<any[]\>__ - the values of the keyword to merge. The length of the array is equal to the number of schemas to merge. If a schema does not contain the keyword, the value is `undefined`.
|
||||
- `mergedSchema` __\<object\>__ - an instance of the merged schema.
|
||||
- `parentSchemas` __\<object[]\>__ - the list of parent schemas.
|
||||
- `options` __\<object\>__ - the options passed to `mergeSchemas`.
|
||||
|
||||
The resolver must set the merged value of the `keyword` in the `mergedSchema` object.
|
||||
|
||||
__Example:__ resolver for the `minNumber` keyword.
|
||||
|
||||
```javascript
|
||||
function minNumberResolver (keyword, values, mergedSchema) {
|
||||
mergedSchema[keyword] = Math.min(...values)
|
||||
}
|
||||
```
|
||||
|
||||
<a name="license"></a>
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
357
node_modules/@fastify/merge-json-schemas/index.js
generated
vendored
Normal file
357
node_modules/@fastify/merge-json-schemas/index.js
generated
vendored
Normal file
@@ -0,0 +1,357 @@
|
||||
'use strict'
|
||||
|
||||
const deepEqual = require('fast-deep-equal')
|
||||
const resolvers = require('./lib/resolvers')
|
||||
const errors = require('./lib/errors')
|
||||
|
||||
const keywordsResolvers = {
|
||||
$id: resolvers.skip,
|
||||
type: resolvers.hybridArraysIntersection,
|
||||
enum: resolvers.arraysIntersection,
|
||||
minLength: resolvers.maxNumber,
|
||||
maxLength: resolvers.minNumber,
|
||||
minimum: resolvers.maxNumber,
|
||||
maximum: resolvers.minNumber,
|
||||
multipleOf: resolvers.commonMultiple,
|
||||
exclusiveMinimum: resolvers.maxNumber,
|
||||
exclusiveMaximum: resolvers.minNumber,
|
||||
minItems: resolvers.maxNumber,
|
||||
maxItems: resolvers.minNumber,
|
||||
maxProperties: resolvers.minNumber,
|
||||
minProperties: resolvers.maxNumber,
|
||||
const: resolvers.allEqual,
|
||||
default: resolvers.allEqual,
|
||||
format: resolvers.allEqual,
|
||||
required: resolvers.arraysUnion,
|
||||
properties: mergeProperties,
|
||||
patternProperties: mergeObjects,
|
||||
additionalProperties: mergeSchemasResolver,
|
||||
items: mergeItems,
|
||||
additionalItems: mergeAdditionalItems,
|
||||
definitions: mergeObjects,
|
||||
$defs: mergeObjects,
|
||||
nullable: resolvers.booleanAnd,
|
||||
oneOf: mergeOneOf,
|
||||
anyOf: mergeOneOf,
|
||||
allOf: resolvers.arraysUnion,
|
||||
not: mergeSchemasResolver,
|
||||
if: mergeIfThenElseSchemas,
|
||||
then: resolvers.skip,
|
||||
else: resolvers.skip,
|
||||
dependencies: mergeDependencies,
|
||||
dependentRequired: mergeDependencies,
|
||||
dependentSchemas: mergeObjects,
|
||||
propertyNames: mergeSchemasResolver,
|
||||
uniqueItems: resolvers.booleanOr,
|
||||
contains: mergeSchemasResolver
|
||||
}
|
||||
|
||||
function mergeSchemasResolver (keyword, values, mergedSchema, schemas, options) {
|
||||
mergedSchema[keyword] = _mergeSchemas(values, options)
|
||||
}
|
||||
|
||||
function cartesianProduct (arrays) {
|
||||
let result = [[]]
|
||||
|
||||
for (const array of arrays) {
|
||||
const temp = []
|
||||
for (const x of result) {
|
||||
for (const y of array) {
|
||||
temp.push([...x, y])
|
||||
}
|
||||
}
|
||||
result = temp
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function mergeOneOf (keyword, values, mergedSchema, schemas, options) {
|
||||
if (values.length === 1) {
|
||||
mergedSchema[keyword] = values[0]
|
||||
return
|
||||
}
|
||||
|
||||
const product = cartesianProduct(values)
|
||||
const mergedOneOf = []
|
||||
for (const combination of product) {
|
||||
try {
|
||||
const mergedSchema = _mergeSchemas(combination, options)
|
||||
if (mergedSchema !== undefined) {
|
||||
mergedOneOf.push(mergedSchema)
|
||||
}
|
||||
} catch (error) {
|
||||
// If this combination is not valid, we can ignore it.
|
||||
if (error instanceof errors.MergeError) continue
|
||||
throw error
|
||||
}
|
||||
}
|
||||
mergedSchema[keyword] = mergedOneOf
|
||||
}
|
||||
|
||||
function getSchemaForItem (schema, index) {
|
||||
const { items, additionalItems } = schema
|
||||
|
||||
if (Array.isArray(items)) {
|
||||
if (index < items.length) {
|
||||
return items[index]
|
||||
}
|
||||
return additionalItems
|
||||
}
|
||||
|
||||
if (items !== undefined) {
|
||||
return items
|
||||
}
|
||||
|
||||
return additionalItems
|
||||
}
|
||||
|
||||
function mergeItems (keyword, values, mergedSchema, schemas, options) {
|
||||
let maxArrayItemsLength = 0
|
||||
for (const itemsSchema of values) {
|
||||
if (Array.isArray(itemsSchema)) {
|
||||
maxArrayItemsLength = Math.max(maxArrayItemsLength, itemsSchema.length)
|
||||
}
|
||||
}
|
||||
|
||||
if (maxArrayItemsLength === 0) {
|
||||
mergedSchema[keyword] = _mergeSchemas(values, options)
|
||||
return
|
||||
}
|
||||
|
||||
const mergedItemsSchemas = []
|
||||
for (let i = 0; i < maxArrayItemsLength; i++) {
|
||||
const indexItemSchemas = []
|
||||
for (const schema of schemas) {
|
||||
const itemSchema = getSchemaForItem(schema, i)
|
||||
if (itemSchema !== undefined) {
|
||||
indexItemSchemas.push(itemSchema)
|
||||
}
|
||||
}
|
||||
mergedItemsSchemas[i] = _mergeSchemas(indexItemSchemas, options)
|
||||
}
|
||||
mergedSchema[keyword] = mergedItemsSchemas
|
||||
}
|
||||
|
||||
function mergeAdditionalItems (keyword, values, mergedSchema, schemas, options) {
|
||||
let hasArrayItems = false
|
||||
for (const schema of schemas) {
|
||||
if (Array.isArray(schema.items)) {
|
||||
hasArrayItems = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasArrayItems) {
|
||||
mergedSchema[keyword] = _mergeSchemas(values, options)
|
||||
return
|
||||
}
|
||||
|
||||
const mergedAdditionalItemsSchemas = []
|
||||
for (const schema of schemas) {
|
||||
let additionalItemsSchema = schema.additionalItems
|
||||
if (
|
||||
additionalItemsSchema === undefined &&
|
||||
!Array.isArray(schema.items)
|
||||
) {
|
||||
additionalItemsSchema = schema.items
|
||||
}
|
||||
if (additionalItemsSchema !== undefined) {
|
||||
mergedAdditionalItemsSchemas.push(additionalItemsSchema)
|
||||
}
|
||||
}
|
||||
|
||||
mergedSchema[keyword] = _mergeSchemas(mergedAdditionalItemsSchemas, options)
|
||||
}
|
||||
|
||||
function getSchemaForProperty (schema, propertyName) {
|
||||
const { properties, patternProperties, additionalProperties } = schema
|
||||
|
||||
if (properties?.[propertyName] !== undefined) {
|
||||
return properties[propertyName]
|
||||
}
|
||||
|
||||
for (const pattern of Object.keys(patternProperties ?? {})) {
|
||||
const regexp = new RegExp(pattern)
|
||||
if (regexp.test(propertyName)) {
|
||||
return patternProperties[pattern]
|
||||
}
|
||||
}
|
||||
|
||||
return additionalProperties
|
||||
}
|
||||
|
||||
function mergeProperties (keyword, values, mergedSchema, schemas, options) {
|
||||
const foundProperties = {}
|
||||
for (const currentSchema of schemas) {
|
||||
const properties = currentSchema.properties ?? {}
|
||||
for (const propertyName of Object.keys(properties)) {
|
||||
if (foundProperties[propertyName] !== undefined) continue
|
||||
|
||||
const propertySchema = properties[propertyName]
|
||||
foundProperties[propertyName] = [propertySchema]
|
||||
|
||||
for (const anotherSchema of schemas) {
|
||||
if (currentSchema === anotherSchema) continue
|
||||
|
||||
const propertySchema = getSchemaForProperty(anotherSchema, propertyName)
|
||||
if (propertySchema !== undefined) {
|
||||
foundProperties[propertyName].push(propertySchema)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mergedProperties = {}
|
||||
for (const property of Object.keys(foundProperties)) {
|
||||
const propertySchemas = foundProperties[property]
|
||||
mergedProperties[property] = _mergeSchemas(propertySchemas, options)
|
||||
}
|
||||
mergedSchema[keyword] = mergedProperties
|
||||
}
|
||||
|
||||
function mergeObjects (keyword, values, mergedSchema, schemas, options) {
|
||||
const objectsProperties = {}
|
||||
|
||||
for (const properties of values) {
|
||||
for (const propertyName of Object.keys(properties)) {
|
||||
if (objectsProperties[propertyName] === undefined) {
|
||||
objectsProperties[propertyName] = []
|
||||
}
|
||||
objectsProperties[propertyName].push(properties[propertyName])
|
||||
}
|
||||
}
|
||||
|
||||
const mergedProperties = {}
|
||||
for (const propertyName of Object.keys(objectsProperties)) {
|
||||
const propertySchemas = objectsProperties[propertyName]
|
||||
const mergedPropertySchema = _mergeSchemas(propertySchemas, options)
|
||||
mergedProperties[propertyName] = mergedPropertySchema
|
||||
}
|
||||
|
||||
mergedSchema[keyword] = mergedProperties
|
||||
}
|
||||
|
||||
function mergeIfThenElseSchemas (keyword, values, mergedSchema, schemas, options) {
|
||||
for (let i = 0; i < schemas.length; i++) {
|
||||
const subSchema = {
|
||||
if: schemas[i].if,
|
||||
then: schemas[i].then,
|
||||
else: schemas[i].else
|
||||
}
|
||||
|
||||
if (subSchema.if === undefined) continue
|
||||
|
||||
if (mergedSchema.if === undefined) {
|
||||
mergedSchema.if = subSchema.if
|
||||
if (subSchema.then !== undefined) {
|
||||
mergedSchema.then = subSchema.then
|
||||
}
|
||||
if (subSchema.else !== undefined) {
|
||||
mergedSchema.else = subSchema.else
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if (mergedSchema.then !== undefined) {
|
||||
mergedSchema.then = _mergeSchemas([mergedSchema.then, subSchema], options)
|
||||
}
|
||||
if (mergedSchema.else !== undefined) {
|
||||
mergedSchema.else = _mergeSchemas([mergedSchema.else, subSchema], options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function mergeDependencies (keyword, values, mergedSchema) {
|
||||
const mergedDependencies = {}
|
||||
for (const dependencies of values) {
|
||||
for (const propertyName of Object.keys(dependencies)) {
|
||||
if (mergedDependencies[propertyName] === undefined) {
|
||||
mergedDependencies[propertyName] = []
|
||||
}
|
||||
const mergedPropertyDependencies = mergedDependencies[propertyName]
|
||||
for (const propertyDependency of dependencies[propertyName]) {
|
||||
if (!mergedPropertyDependencies.includes(propertyDependency)) {
|
||||
mergedPropertyDependencies.push(propertyDependency)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mergedSchema[keyword] = mergedDependencies
|
||||
}
|
||||
|
||||
function _mergeSchemas (schemas, options) {
|
||||
if (schemas.length === 0) return {}
|
||||
if (schemas.length === 1) return schemas[0]
|
||||
|
||||
const mergedSchema = {}
|
||||
const keywords = {}
|
||||
|
||||
let allSchemasAreTrue = true
|
||||
|
||||
for (const schema of schemas) {
|
||||
if (schema === false) return false
|
||||
if (schema === true) continue
|
||||
allSchemasAreTrue = false
|
||||
|
||||
for (const keyword of Object.keys(schema)) {
|
||||
if (keywords[keyword] === undefined) {
|
||||
keywords[keyword] = []
|
||||
}
|
||||
keywords[keyword].push(schema[keyword])
|
||||
}
|
||||
}
|
||||
|
||||
if (allSchemasAreTrue) return true
|
||||
|
||||
for (const keyword of Object.keys(keywords)) {
|
||||
const keywordValues = keywords[keyword]
|
||||
const resolver = options.resolvers[keyword] ?? options.defaultResolver
|
||||
resolver(keyword, keywordValues, mergedSchema, schemas, options)
|
||||
}
|
||||
|
||||
return mergedSchema
|
||||
}
|
||||
|
||||
function defaultResolver (keyword, values, mergedSchema, schemas, options) {
|
||||
const onConflict = options.onConflict ?? 'throw'
|
||||
|
||||
if (values.length === 1 || onConflict === 'first') {
|
||||
mergedSchema[keyword] = values[0]
|
||||
return
|
||||
}
|
||||
|
||||
let allValuesEqual = true
|
||||
for (let i = 1; i < values.length; i++) {
|
||||
if (!deepEqual(values[i], values[0])) {
|
||||
allValuesEqual = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (allValuesEqual) {
|
||||
mergedSchema[keyword] = values[0]
|
||||
return
|
||||
}
|
||||
|
||||
if (onConflict === 'throw') {
|
||||
throw new errors.ResolverNotFoundError(keyword, values)
|
||||
}
|
||||
if (onConflict === 'skip') {
|
||||
return
|
||||
}
|
||||
throw new errors.InvalidOnConflictOptionError(onConflict)
|
||||
}
|
||||
|
||||
function mergeSchemas (schemas, options = {}) {
|
||||
if (options.defaultResolver === undefined) {
|
||||
options.defaultResolver = defaultResolver
|
||||
}
|
||||
|
||||
options.resolvers = { ...keywordsResolvers, ...options.resolvers }
|
||||
|
||||
const mergedSchema = _mergeSchemas(schemas, options)
|
||||
return mergedSchema
|
||||
}
|
||||
|
||||
module.exports = { mergeSchemas, keywordsResolvers, defaultResolver, ...errors }
|
||||
36
node_modules/@fastify/merge-json-schemas/lib/errors.js
generated
vendored
Normal file
36
node_modules/@fastify/merge-json-schemas/lib/errors.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
'use strict'
|
||||
|
||||
class MergeError extends Error {
|
||||
constructor (keyword, schemas) {
|
||||
super()
|
||||
this.name = 'JsonSchemaMergeError'
|
||||
this.code = 'JSON_SCHEMA_MERGE_ERROR'
|
||||
this.message = `Failed to merge "${keyword}" keyword schemas.`
|
||||
this.schemas = schemas
|
||||
}
|
||||
}
|
||||
|
||||
class ResolverNotFoundError extends Error {
|
||||
constructor (keyword, schemas) {
|
||||
super()
|
||||
this.name = 'JsonSchemaMergeError'
|
||||
this.code = 'JSON_SCHEMA_MERGE_ERROR'
|
||||
this.message = `Resolver for "${keyword}" keyword not found.`
|
||||
this.schemas = schemas
|
||||
}
|
||||
}
|
||||
|
||||
class InvalidOnConflictOptionError extends Error {
|
||||
constructor (onConflict) {
|
||||
super()
|
||||
this.name = 'JsonSchemaMergeError'
|
||||
this.code = 'JSON_SCHEMA_MERGE_ERROR'
|
||||
this.message = `Invalid "onConflict" option: "${onConflict}".`
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
MergeError,
|
||||
ResolverNotFoundError,
|
||||
InvalidOnConflictOptionError
|
||||
}
|
||||
127
node_modules/@fastify/merge-json-schemas/lib/resolvers.js
generated
vendored
Normal file
127
node_modules/@fastify/merge-json-schemas/lib/resolvers.js
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
'use strict'
|
||||
|
||||
const deepEqual = require('fast-deep-equal')
|
||||
const { MergeError } = require('./errors')
|
||||
|
||||
function _arraysIntersection (arrays) {
|
||||
let intersection = arrays[0]
|
||||
for (let i = 1; i < arrays.length; i++) {
|
||||
intersection = intersection.filter(
|
||||
value => arrays[i].includes(value)
|
||||
)
|
||||
}
|
||||
return intersection
|
||||
}
|
||||
|
||||
function arraysIntersection (keyword, values, mergedSchema) {
|
||||
const intersection = _arraysIntersection(values)
|
||||
if (intersection.length === 0) {
|
||||
throw new MergeError(keyword, values)
|
||||
}
|
||||
mergedSchema[keyword] = intersection
|
||||
}
|
||||
|
||||
function hybridArraysIntersection (keyword, values, mergedSchema) {
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
if (!Array.isArray(values[i])) {
|
||||
values[i] = [values[i]]
|
||||
}
|
||||
}
|
||||
|
||||
const intersection = _arraysIntersection(values)
|
||||
if (intersection.length === 0) {
|
||||
throw new MergeError(keyword, values)
|
||||
}
|
||||
|
||||
if (intersection.length === 1) {
|
||||
mergedSchema[keyword] = intersection[0]
|
||||
} else {
|
||||
mergedSchema[keyword] = intersection
|
||||
}
|
||||
}
|
||||
|
||||
function arraysUnion (keyword, values, mergedSchema) {
|
||||
const union = []
|
||||
|
||||
for (const array of values) {
|
||||
for (const value of array) {
|
||||
if (!union.includes(value)) {
|
||||
union.push(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mergedSchema[keyword] = union
|
||||
}
|
||||
|
||||
function minNumber (keyword, values, mergedSchema) {
|
||||
mergedSchema[keyword] = Math.min(...values)
|
||||
}
|
||||
|
||||
function maxNumber (keyword, values, mergedSchema) {
|
||||
mergedSchema[keyword] = Math.max(...values)
|
||||
}
|
||||
|
||||
function commonMultiple (keyword, values, mergedSchema) {
|
||||
const gcd = (a, b) => (!b ? a : gcd(b, a % b))
|
||||
const lcm = (a, b) => (a * b) / gcd(a, b)
|
||||
|
||||
let scale = 1
|
||||
for (const value of values) {
|
||||
while (value * scale % 1 !== 0) {
|
||||
scale *= 10
|
||||
}
|
||||
}
|
||||
|
||||
let multiple = values[0] * scale
|
||||
for (const value of values) {
|
||||
multiple = lcm(multiple, value * scale)
|
||||
}
|
||||
|
||||
mergedSchema[keyword] = multiple / scale
|
||||
}
|
||||
|
||||
function allEqual (keyword, values, mergedSchema) {
|
||||
const firstValue = values[0]
|
||||
for (let i = 1; i < values.length; i++) {
|
||||
if (!deepEqual(values[i], firstValue)) {
|
||||
throw new MergeError(keyword, values)
|
||||
}
|
||||
}
|
||||
mergedSchema[keyword] = firstValue
|
||||
}
|
||||
|
||||
function skip () {}
|
||||
|
||||
function booleanAnd (keyword, values, mergedSchema) {
|
||||
for (const value of values) {
|
||||
if (value === false) {
|
||||
mergedSchema[keyword] = false
|
||||
return
|
||||
}
|
||||
}
|
||||
mergedSchema[keyword] = true
|
||||
}
|
||||
|
||||
function booleanOr (keyword, values, mergedSchema) {
|
||||
for (const value of values) {
|
||||
if (value === true) {
|
||||
mergedSchema[keyword] = true
|
||||
return
|
||||
}
|
||||
}
|
||||
mergedSchema[keyword] = false
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
arraysIntersection,
|
||||
hybridArraysIntersection,
|
||||
arraysUnion,
|
||||
minNumber,
|
||||
maxNumber,
|
||||
commonMultiple,
|
||||
allEqual,
|
||||
booleanAnd,
|
||||
booleanOr,
|
||||
skip
|
||||
}
|
||||
39
node_modules/@fastify/merge-json-schemas/package.json
generated
vendored
Normal file
39
node_modules/@fastify/merge-json-schemas/package.json
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "@fastify/merge-json-schemas",
|
||||
"version": "0.1.1",
|
||||
"description": "Builds a logical conjunction (AND) of multiple JSON schemas",
|
||||
"main": "index.js",
|
||||
"type": "commonjs",
|
||||
"types": "types/index.d.ts",
|
||||
"scripts": {
|
||||
"lint": "standard",
|
||||
"lint:fix": "standard --fix",
|
||||
"test:unit": "c8 --100 node --test",
|
||||
"test:types": "tsd",
|
||||
"test": "npm run lint && npm run test:unit && npm run test:types"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/fastify/merge-json-schemas.git"
|
||||
},
|
||||
"keywords": [
|
||||
"json",
|
||||
"schema",
|
||||
"merge",
|
||||
"allOf"
|
||||
],
|
||||
"author": "Ivan Tymoshenko <ivan@tymoshenko.me>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/fastify/merge-json-schemas/issues"
|
||||
},
|
||||
"homepage": "https://github.com/fastify/merge-json-schemas#readme",
|
||||
"devDependencies": {
|
||||
"c8": "^8.0.1",
|
||||
"standard": "^17.1.0",
|
||||
"tsd": "^0.30.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3"
|
||||
}
|
||||
}
|
||||
164
node_modules/@fastify/merge-json-schemas/test/additional-items.test.js
generated
vendored
Normal file
164
node_modules/@fastify/merge-json-schemas/test/additional-items.test.js
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and additionalItems = false keyword', () => {
|
||||
const schema1 = { type: 'array' }
|
||||
const schema2 = {
|
||||
type: 'array',
|
||||
additionalItems: false
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'array',
|
||||
additionalItems: false
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge two schemas with boolean additionalItems', () => {
|
||||
const schema1 = {
|
||||
type: 'array',
|
||||
additionalItems: true
|
||||
}
|
||||
const schema2 = {
|
||||
type: 'array',
|
||||
additionalItems: false
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'array',
|
||||
additionalItems: false
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge additionalItems schema with false value', () => {
|
||||
const schema1 = {
|
||||
type: 'array',
|
||||
additionalItems: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
const schema2 = {
|
||||
type: 'array',
|
||||
additionalItems: false
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'array',
|
||||
additionalItems: false
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge additionalItems schema with true value', () => {
|
||||
const schema1 = {
|
||||
type: 'array',
|
||||
additionalItems: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
const schema2 = {
|
||||
type: 'array',
|
||||
additionalItems: true
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'array',
|
||||
additionalItems: {
|
||||
type: 'string'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge two additionalItems schemas', () => {
|
||||
const schema1 = {
|
||||
type: 'array',
|
||||
additionalItems: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
const schema2 = {
|
||||
type: 'array',
|
||||
additionalItems: {
|
||||
type: 'string', minLength: 1
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'array',
|
||||
additionalItems: {
|
||||
type: 'string', minLength: 1
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge additionalItems with items array', () => {
|
||||
const schema1 = {
|
||||
type: 'array',
|
||||
items: [
|
||||
{ type: 'string', const: 'foo1' },
|
||||
{ type: 'string', const: 'foo2' },
|
||||
{ type: 'string', const: 'foo3' }
|
||||
]
|
||||
}
|
||||
const schema2 = {
|
||||
type: 'array',
|
||||
additionalItems: {
|
||||
type: 'string', minLength: 42
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'array',
|
||||
items: [
|
||||
{ type: 'string', const: 'foo1', minLength: 42 },
|
||||
{ type: 'string', const: 'foo2', minLength: 42 },
|
||||
{ type: 'string', const: 'foo3', minLength: 42 }
|
||||
],
|
||||
additionalItems: {
|
||||
type: 'string', minLength: 42
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge items array and additionalItems with items array', () => {
|
||||
const schema1 = {
|
||||
type: 'array',
|
||||
items: [
|
||||
{ type: 'string', const: 'foo1' },
|
||||
{ type: 'string', const: 'foo2' },
|
||||
{ type: 'string', const: 'foo3' }
|
||||
]
|
||||
}
|
||||
const schema2 = {
|
||||
type: 'array',
|
||||
items: [
|
||||
{ type: 'string', minLength: 1 },
|
||||
{ type: 'string', minLength: 2 }
|
||||
],
|
||||
additionalItems: {
|
||||
type: 'string', minLength: 3
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'array',
|
||||
items: [
|
||||
{ type: 'string', const: 'foo1', minLength: 1 },
|
||||
{ type: 'string', const: 'foo2', minLength: 2 },
|
||||
{ type: 'string', const: 'foo3', minLength: 3 }
|
||||
],
|
||||
additionalItems: {
|
||||
type: 'string', minLength: 3
|
||||
}
|
||||
})
|
||||
})
|
||||
129
node_modules/@fastify/merge-json-schemas/test/additional-properties.test.js
generated
vendored
Normal file
129
node_modules/@fastify/merge-json-schemas/test/additional-properties.test.js
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and additionalProperties=false keyword', () => {
|
||||
const schema1 = { type: 'object' }
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
additionalProperties: false
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
additionalProperties: false
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge two schemas with boolean additionalProperties', () => {
|
||||
const schema1 = {
|
||||
type: 'object',
|
||||
additionalProperties: true
|
||||
}
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
additionalProperties: false
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
additionalProperties: false
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge additionalProperties schema with false value', () => {
|
||||
const schema1 = {
|
||||
type: 'object',
|
||||
additionalProperties: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
additionalProperties: false
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
additionalProperties: false
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge additionalProperties schema with true value', () => {
|
||||
const schema1 = {
|
||||
type: 'object',
|
||||
additionalProperties: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
additionalProperties: true
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
additionalProperties: {
|
||||
type: 'string'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge two additionalProperties schemas', () => {
|
||||
const schema1 = {
|
||||
type: 'object',
|
||||
additionalProperties: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
additionalProperties: {
|
||||
type: 'string', minLength: 1
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
additionalProperties: {
|
||||
type: 'string', minLength: 1
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge two additionalProperties and properties schemas', () => {
|
||||
const schema1 = {
|
||||
type: 'object',
|
||||
additionalProperties: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: ['string', 'number'] }
|
||||
},
|
||||
additionalProperties: {
|
||||
type: 'string', minLength: 1
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' }
|
||||
},
|
||||
additionalProperties: {
|
||||
type: 'string', minLength: 1
|
||||
}
|
||||
})
|
||||
})
|
||||
43
node_modules/@fastify/merge-json-schemas/test/all-of.test.js
generated
vendored
Normal file
43
node_modules/@fastify/merge-json-schemas/test/all-of.test.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and allOf keyword', () => {
|
||||
const schema1 = {}
|
||||
const schema2 = {
|
||||
allOf: [
|
||||
{ type: 'string', const: 'foo' }
|
||||
]
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
allOf: [
|
||||
{ type: 'string', const: 'foo' }
|
||||
]
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge schemas with allOfs schemas', () => {
|
||||
const schema1 = {
|
||||
allOf: [
|
||||
{ type: 'number', minimum: 0 }
|
||||
]
|
||||
}
|
||||
const schema2 = {
|
||||
allOf: [
|
||||
{ type: 'string', const: 'foo' }
|
||||
]
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
allOf: [
|
||||
{ type: 'number', minimum: 0 },
|
||||
{ type: 'string', const: 'foo' }
|
||||
]
|
||||
})
|
||||
})
|
||||
81
node_modules/@fastify/merge-json-schemas/test/any-of.test.js
generated
vendored
Normal file
81
node_modules/@fastify/merge-json-schemas/test/any-of.test.js
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and anyOf keyword', () => {
|
||||
const schema1 = {}
|
||||
const schema2 = {
|
||||
anyOf: [
|
||||
{ type: 'string', const: 'foo' }
|
||||
]
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
anyOf: [
|
||||
{ type: 'string', const: 'foo' }
|
||||
]
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge two schemas with anyOfs schemas', () => {
|
||||
const schema1 = {
|
||||
anyOf: [
|
||||
{ type: 'string', enum: ['foo1', 'foo2', 'foo3'] },
|
||||
{ type: 'string', enum: ['foo3', 'foo4', 'foo5'] }
|
||||
]
|
||||
}
|
||||
const schema2 = {
|
||||
anyOf: [
|
||||
{ type: 'string', enum: ['foo2', 'foo3', 'foo4'] },
|
||||
{ type: 'string', enum: ['foo3', 'foo6', 'foo7'] }
|
||||
]
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
anyOf: [
|
||||
{ type: 'string', enum: ['foo2', 'foo3'] },
|
||||
{ type: 'string', enum: ['foo3'] },
|
||||
{ type: 'string', enum: ['foo3', 'foo4'] },
|
||||
{ type: 'string', enum: ['foo3'] }
|
||||
]
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge three schemas with anyOfs schemas', () => {
|
||||
const schema1 = {
|
||||
anyOf: [
|
||||
{ type: 'string', enum: ['foo1', 'foo2', 'foo3', 'foo4'] },
|
||||
{ type: 'string', enum: ['foo3', 'foo4', 'foo5', 'foo7'] }
|
||||
]
|
||||
}
|
||||
const schema2 = {
|
||||
anyOf: [
|
||||
{ type: 'string', enum: ['foo2', 'foo3', 'foo4', 'foo5'] },
|
||||
{ type: 'string', enum: ['foo3', 'foo6', 'foo7', 'foo8'] }
|
||||
]
|
||||
}
|
||||
|
||||
const schema3 = {
|
||||
anyOf: [
|
||||
{ type: 'string', enum: ['foo1', 'foo3', 'foo5', 'foo7'] },
|
||||
{ type: 'string', enum: ['foo2', 'foo4', 'foo6', 'foo8'] }
|
||||
]
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2, schema3], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
anyOf: [
|
||||
{ type: 'string', enum: ['foo3'] },
|
||||
{ type: 'string', enum: ['foo2', 'foo4'] },
|
||||
{ type: 'string', enum: ['foo3'] },
|
||||
{ type: 'string', enum: ['foo3', 'foo5'] },
|
||||
{ type: 'string', enum: ['foo4'] },
|
||||
{ type: 'string', enum: ['foo3', 'foo7'] }
|
||||
]
|
||||
})
|
||||
})
|
||||
58
node_modules/@fastify/merge-json-schemas/test/const.test.js
generated
vendored
Normal file
58
node_modules/@fastify/merge-json-schemas/test/const.test.js
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and string const keyword', () => {
|
||||
const schema1 = { type: 'string' }
|
||||
const schema2 = { type: 'string', const: 'foo' }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string', const: 'foo' })
|
||||
})
|
||||
|
||||
test('should merge equal string const keywords', () => {
|
||||
const schema1 = { type: 'string', const: 'foo' }
|
||||
const schema2 = { type: 'string', const: 'foo' }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string', const: 'foo' })
|
||||
})
|
||||
|
||||
test('should merge equal object const keywords', () => {
|
||||
const schema1 = { type: 'string', const: { foo: 'bar' } }
|
||||
const schema2 = { type: 'string', const: { foo: 'bar' } }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string', const: { foo: 'bar' } })
|
||||
})
|
||||
|
||||
test('should throw an error if const string values are different', () => {
|
||||
const schema1 = { type: 'string', const: 'foo' }
|
||||
const schema2 = { type: 'string', const: 'bar' }
|
||||
|
||||
assert.throws(() => {
|
||||
mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
}, {
|
||||
name: 'JsonSchemaMergeError',
|
||||
code: 'JSON_SCHEMA_MERGE_ERROR',
|
||||
message: 'Failed to merge "const" keyword schemas.',
|
||||
schemas: ['foo', 'bar']
|
||||
})
|
||||
})
|
||||
|
||||
test('should throw an error if const object values are different', () => {
|
||||
const schema1 = { type: 'object', const: { foo: 'bar' } }
|
||||
const schema2 = { type: 'object', const: { foo: 'baz' } }
|
||||
|
||||
assert.throws(() => {
|
||||
mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
}, {
|
||||
name: 'JsonSchemaMergeError',
|
||||
code: 'JSON_SCHEMA_MERGE_ERROR',
|
||||
message: 'Failed to merge "const" keyword schemas.',
|
||||
schemas: [{ foo: 'bar' }, { foo: 'baz' }]
|
||||
})
|
||||
})
|
||||
55
node_modules/@fastify/merge-json-schemas/test/contains.test.js
generated
vendored
Normal file
55
node_modules/@fastify/merge-json-schemas/test/contains.test.js
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and contains keyword', () => {
|
||||
const schema1 = {}
|
||||
const schema2 = {
|
||||
type: 'array',
|
||||
contains: {
|
||||
type: 'integer',
|
||||
minimum: 5
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'array',
|
||||
contains: {
|
||||
type: 'integer',
|
||||
minimum: 5
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge two contains keyword schemas', () => {
|
||||
const schema1 = {
|
||||
type: 'array',
|
||||
contains: {
|
||||
type: 'integer',
|
||||
minimum: 5,
|
||||
maximum: 14
|
||||
}
|
||||
}
|
||||
const schema2 = {
|
||||
type: 'array',
|
||||
contains: {
|
||||
type: 'integer',
|
||||
minimum: 9,
|
||||
maximum: 10
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'array',
|
||||
contains: {
|
||||
type: 'integer',
|
||||
minimum: 9,
|
||||
maximum: 10
|
||||
}
|
||||
})
|
||||
})
|
||||
50
node_modules/@fastify/merge-json-schemas/test/custom-resolvers.test.js
generated
vendored
Normal file
50
node_modules/@fastify/merge-json-schemas/test/custom-resolvers.test.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should use a custom resolver instead of default one', () => {
|
||||
const schema1 = { type: 'string' }
|
||||
const schema2 = { type: 'number' }
|
||||
|
||||
const mergedSchema = mergeSchemas(
|
||||
[schema1, schema2],
|
||||
{
|
||||
resolvers: {
|
||||
type: (keyword, values, mergedSchema, schemas) => {
|
||||
assert.strictEqual(keyword, 'type')
|
||||
assert.deepStrictEqual(values, ['string', 'number'])
|
||||
assert.deepStrictEqual(schemas, [schema1, schema2])
|
||||
|
||||
mergedSchema[keyword] = 'custom-type'
|
||||
}
|
||||
},
|
||||
defaultResolver
|
||||
}
|
||||
)
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'custom-type' })
|
||||
})
|
||||
|
||||
test('should use a custom resolver for unknown keyword', () => {
|
||||
const schema1 = { customKeyword: 'string' }
|
||||
const schema2 = { customKeyword: 'number' }
|
||||
|
||||
const mergedSchema = mergeSchemas(
|
||||
[schema1, schema2],
|
||||
{
|
||||
resolvers: {
|
||||
customKeyword: (keyword, values, mergedSchema, schemas) => {
|
||||
assert.strictEqual(keyword, 'customKeyword')
|
||||
assert.deepStrictEqual(values, ['string', 'number'])
|
||||
assert.deepStrictEqual(schemas, [schema1, schema2])
|
||||
|
||||
mergedSchema[keyword] = 'custom-type'
|
||||
}
|
||||
},
|
||||
defaultResolver
|
||||
}
|
||||
)
|
||||
assert.deepStrictEqual(mergedSchema, { customKeyword: 'custom-type' })
|
||||
})
|
||||
111
node_modules/@fastify/merge-json-schemas/test/default-resolver.test.js
generated
vendored
Normal file
111
node_modules/@fastify/merge-json-schemas/test/default-resolver.test.js
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
|
||||
test('should merge an unknown keyword with an empty schema', () => {
|
||||
const schema1 = {}
|
||||
const schema2 = { customKeyword: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2])
|
||||
assert.deepStrictEqual(mergedSchema, { customKeyword: 42 })
|
||||
})
|
||||
|
||||
test('should merge two equal unknown keywords', () => {
|
||||
const schema1 = { customKeyword: 42 }
|
||||
const schema2 = { customKeyword: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2])
|
||||
assert.deepStrictEqual(mergedSchema, { customKeyword: 42 })
|
||||
})
|
||||
|
||||
test('should merge two equal unknown object keywords', () => {
|
||||
const schema1 = { type: 'string', customKeyword: { foo: 'bar' } }
|
||||
const schema2 = { type: 'string', customKeyword: { foo: 'bar' } }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2])
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'string',
|
||||
customKeyword: { foo: 'bar' }
|
||||
})
|
||||
})
|
||||
|
||||
test('should use custom defaultResolver if passed', () => {
|
||||
const schema1 = { type: 'string', customKeyword: 42 }
|
||||
const schema2 = { type: 'string', customKeyword: 43 }
|
||||
|
||||
const mergedSchema = mergeSchemas(
|
||||
[schema1, schema2],
|
||||
{
|
||||
defaultResolver: (keyword, values, mergedSchema, schemas) => {
|
||||
assert.strictEqual(keyword, 'customKeyword')
|
||||
assert.deepStrictEqual(values, [42, 43])
|
||||
assert.deepStrictEqual(schemas, [schema1, schema2])
|
||||
|
||||
mergedSchema.customKeyword = 'custom-value-42'
|
||||
}
|
||||
}
|
||||
)
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'string',
|
||||
customKeyword: 'custom-value-42'
|
||||
})
|
||||
})
|
||||
|
||||
test('should trow an error when merging two different unknown keywords', () => {
|
||||
const schema1 = { customKeyword: 42 }
|
||||
const schema2 = { customKeyword: 43 }
|
||||
|
||||
assert.throws(() => {
|
||||
mergeSchemas([schema1, schema2])
|
||||
}, {
|
||||
name: 'JsonSchemaMergeError',
|
||||
code: 'JSON_SCHEMA_MERGE_ERROR',
|
||||
message: 'Resolver for "customKeyword" keyword not found.',
|
||||
schemas: [42, 43]
|
||||
})
|
||||
})
|
||||
|
||||
test('should trow an error when merging two different unknown keywords with onConflict = throw', () => {
|
||||
const schema1 = { customKeyword: 42 }
|
||||
const schema2 = { customKeyword: 43 }
|
||||
|
||||
assert.throws(() => {
|
||||
mergeSchemas([schema1, schema2], { onConflict: 'throw' })
|
||||
}, {
|
||||
name: 'JsonSchemaMergeError',
|
||||
code: 'JSON_SCHEMA_MERGE_ERROR',
|
||||
message: 'Resolver for "customKeyword" keyword not found.',
|
||||
schemas: [42, 43]
|
||||
})
|
||||
})
|
||||
|
||||
test('should skip the keyword schemas if onConflict = skip', () => {
|
||||
const schema1 = { customKeyword: 42 }
|
||||
const schema2 = { customKeyword: 43 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { onConflict: 'skip' })
|
||||
assert.deepStrictEqual(mergedSchema, {})
|
||||
})
|
||||
|
||||
test('should pick first schema if onConflict = first', () => {
|
||||
const schema1 = { customKeyword: 42 }
|
||||
const schema2 = { customKeyword: 43 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { onConflict: 'first' })
|
||||
assert.deepStrictEqual(mergedSchema, { customKeyword: 42 })
|
||||
})
|
||||
|
||||
test('should throw an error if pass wrong onConflict value', () => {
|
||||
const schema1 = { customKeyword: 42 }
|
||||
const schema2 = { customKeyword: 43 }
|
||||
|
||||
assert.throws(() => {
|
||||
mergeSchemas([schema1, schema2], { onConflict: 'foo' })
|
||||
}, {
|
||||
name: 'JsonSchemaMergeError',
|
||||
code: 'JSON_SCHEMA_MERGE_ERROR',
|
||||
message: 'Invalid "onConflict" option: "foo".'
|
||||
})
|
||||
})
|
||||
50
node_modules/@fastify/merge-json-schemas/test/default.test.js
generated
vendored
Normal file
50
node_modules/@fastify/merge-json-schemas/test/default.test.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and string default keyword', () => {
|
||||
const schema1 = { type: 'string' }
|
||||
const schema2 = { type: 'string', default: 'foo' }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string', default: 'foo' })
|
||||
})
|
||||
|
||||
test('should merge equal string default keywords', () => {
|
||||
const schema1 = { type: 'string', default: 'foo' }
|
||||
const schema2 = { type: 'string', default: 'foo' }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string', default: 'foo' })
|
||||
})
|
||||
|
||||
test('should throw an error if default string values are different', () => {
|
||||
const schema1 = { type: 'string', default: 'foo' }
|
||||
const schema2 = { type: 'string', default: 'bar' }
|
||||
|
||||
assert.throws(() => {
|
||||
mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
}, {
|
||||
name: 'JsonSchemaMergeError',
|
||||
code: 'JSON_SCHEMA_MERGE_ERROR',
|
||||
message: 'Failed to merge "default" keyword schemas.',
|
||||
schemas: ['foo', 'bar']
|
||||
})
|
||||
})
|
||||
|
||||
test('should throw an error if default object values are different', () => {
|
||||
const schema1 = { type: 'object', default: { foo: 'bar' } }
|
||||
const schema2 = { type: 'object', default: { foo: 'baz' } }
|
||||
|
||||
assert.throws(() => {
|
||||
mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
}, {
|
||||
name: 'JsonSchemaMergeError',
|
||||
code: 'JSON_SCHEMA_MERGE_ERROR',
|
||||
message: 'Failed to merge "default" keyword schemas.',
|
||||
schemas: [{ foo: 'bar' }, { foo: 'baz' }]
|
||||
})
|
||||
})
|
||||
46
node_modules/@fastify/merge-json-schemas/test/definitions.test.js
generated
vendored
Normal file
46
node_modules/@fastify/merge-json-schemas/test/definitions.test.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and definitions keyword', () => {
|
||||
const schema1 = {}
|
||||
const schema2 = {
|
||||
definitions: {
|
||||
foo: { type: 'string', const: 'foo' }
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
definitions: {
|
||||
foo: { type: 'string', const: 'foo' }
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge two definition schemas', () => {
|
||||
const schema1 = {
|
||||
definitions: {
|
||||
foo: { type: 'string', enum: ['foo', 'bar'] },
|
||||
bar: { type: 'string', enum: ['foo', 'bar'] }
|
||||
}
|
||||
}
|
||||
const schema2 = {
|
||||
definitions: {
|
||||
foo: { type: 'string', enum: ['foo'] },
|
||||
baz: { type: 'string' }
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
definitions: {
|
||||
foo: { type: 'string', enum: ['foo'] },
|
||||
bar: { type: 'string', enum: ['foo', 'bar'] },
|
||||
baz: { type: 'string' }
|
||||
}
|
||||
})
|
||||
})
|
||||
46
node_modules/@fastify/merge-json-schemas/test/defs.test.js
generated
vendored
Normal file
46
node_modules/@fastify/merge-json-schemas/test/defs.test.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and $defs keyword', () => {
|
||||
const schema1 = {}
|
||||
const schema2 = {
|
||||
$defs: {
|
||||
foo: { type: 'string', const: 'foo' }
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
$defs: {
|
||||
foo: { type: 'string', const: 'foo' }
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge two definition schemas', () => {
|
||||
const schema1 = {
|
||||
$defs: {
|
||||
foo: { type: 'string', enum: ['foo', 'bar'] },
|
||||
bar: { type: 'string', enum: ['foo', 'bar'] }
|
||||
}
|
||||
}
|
||||
const schema2 = {
|
||||
$defs: {
|
||||
foo: { type: 'string', enum: ['foo'] },
|
||||
baz: { type: 'string' }
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
$defs: {
|
||||
foo: { type: 'string', enum: ['foo'] },
|
||||
bar: { type: 'string', enum: ['foo', 'bar'] },
|
||||
baz: { type: 'string' }
|
||||
}
|
||||
})
|
||||
})
|
||||
75
node_modules/@fastify/merge-json-schemas/test/dependencies.test.js
generated
vendored
Normal file
75
node_modules/@fastify/merge-json-schemas/test/dependencies.test.js
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and dependencies keyword', () => {
|
||||
const schema1 = {}
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'string' }
|
||||
},
|
||||
dependencies: {
|
||||
foo: ['bar']
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'string' }
|
||||
},
|
||||
dependencies: {
|
||||
foo: ['bar']
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge two dependencies keyword schemas', () => {
|
||||
const schema1 = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'string' },
|
||||
que: { type: 'string' }
|
||||
},
|
||||
dependencies: {
|
||||
foo: ['bar', 'que'],
|
||||
bar: ['que']
|
||||
}
|
||||
}
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'string' },
|
||||
baz: { type: 'string' }
|
||||
},
|
||||
dependencies: {
|
||||
foo: ['baz'],
|
||||
baz: ['foo']
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'string' },
|
||||
que: { type: 'string' },
|
||||
baz: { type: 'string' }
|
||||
},
|
||||
dependencies: {
|
||||
foo: ['bar', 'que', 'baz'],
|
||||
bar: ['que'],
|
||||
baz: ['foo']
|
||||
}
|
||||
})
|
||||
})
|
||||
75
node_modules/@fastify/merge-json-schemas/test/dependent-required.test.js
generated
vendored
Normal file
75
node_modules/@fastify/merge-json-schemas/test/dependent-required.test.js
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and dependentRequired keyword', () => {
|
||||
const schema1 = {}
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'string' }
|
||||
},
|
||||
dependentRequired: {
|
||||
foo: ['bar']
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'string' }
|
||||
},
|
||||
dependentRequired: {
|
||||
foo: ['bar']
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge two dependentRequired keyword schemas', () => {
|
||||
const schema1 = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'string' },
|
||||
que: { type: 'string' }
|
||||
},
|
||||
dependentRequired: {
|
||||
foo: ['bar', 'que'],
|
||||
bar: ['que']
|
||||
}
|
||||
}
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'string' },
|
||||
baz: { type: 'string' }
|
||||
},
|
||||
dependentRequired: {
|
||||
foo: ['baz'],
|
||||
baz: ['foo']
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'string' },
|
||||
que: { type: 'string' },
|
||||
baz: { type: 'string' }
|
||||
},
|
||||
dependentRequired: {
|
||||
foo: ['bar', 'que', 'baz'],
|
||||
bar: ['que'],
|
||||
baz: ['foo']
|
||||
}
|
||||
})
|
||||
})
|
||||
76
node_modules/@fastify/merge-json-schemas/test/dependent-schemas.test.js
generated
vendored
Normal file
76
node_modules/@fastify/merge-json-schemas/test/dependent-schemas.test.js
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and dependentRequired keyword', () => {
|
||||
const schema1 = {}
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'string' }
|
||||
},
|
||||
dependentSchemas: {
|
||||
foo: { required: ['bar'] }
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'string' }
|
||||
},
|
||||
dependentSchemas: {
|
||||
foo: { required: ['bar'] }
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge two dependentRequired keyword schemas', () => {
|
||||
const schema1 = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'string' },
|
||||
que: { type: 'string' }
|
||||
},
|
||||
dependentSchemas: {
|
||||
foo: { required: ['bar', 'que'] },
|
||||
bar: { required: ['que'] }
|
||||
}
|
||||
}
|
||||
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'string' },
|
||||
baz: { type: 'string' }
|
||||
},
|
||||
dependentSchemas: {
|
||||
foo: { required: ['baz'] },
|
||||
baz: { required: ['foo'] }
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'string' },
|
||||
que: { type: 'string' },
|
||||
baz: { type: 'string' }
|
||||
},
|
||||
dependentSchemas: {
|
||||
foo: { required: ['bar', 'que', 'baz'] },
|
||||
bar: { required: ['que'] },
|
||||
baz: { required: ['foo'] }
|
||||
}
|
||||
})
|
||||
})
|
||||
44
node_modules/@fastify/merge-json-schemas/test/enum.test.js
generated
vendored
Normal file
44
node_modules/@fastify/merge-json-schemas/test/enum.test.js
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and string enum values', () => {
|
||||
const schema1 = { type: 'string' }
|
||||
const schema2 = { type: 'string', enum: ['foo', 'bar'] }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string', enum: ['foo', 'bar'] })
|
||||
})
|
||||
|
||||
test('should merge equal string enum values', () => {
|
||||
const schema1 = { type: 'string', enum: ['foo', 'bar'] }
|
||||
const schema2 = { type: 'string', enum: ['foo', 'bar'] }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string', enum: ['foo', 'bar'] })
|
||||
})
|
||||
|
||||
test('should merge different string enum values', () => {
|
||||
const schema1 = { type: 'string', enum: ['foo', 'bar'] }
|
||||
const schema2 = { type: 'string', enum: ['foo', 'baz'] }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string', enum: ['foo'] })
|
||||
})
|
||||
|
||||
test('should throw an error if can not merge enum values', () => {
|
||||
const schema1 = { type: 'string', enum: ['foo', 'bar'] }
|
||||
const schema2 = { type: 'string', enum: ['baz', 'qux'] }
|
||||
|
||||
assert.throws(() => {
|
||||
mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
}, {
|
||||
name: 'JsonSchemaMergeError',
|
||||
code: 'JSON_SCHEMA_MERGE_ERROR',
|
||||
message: 'Failed to merge "enum" keyword schemas.',
|
||||
schemas: [['foo', 'bar'], ['baz', 'qux']]
|
||||
})
|
||||
})
|
||||
30
node_modules/@fastify/merge-json-schemas/test/exclusive-maximum.test.js
generated
vendored
Normal file
30
node_modules/@fastify/merge-json-schemas/test/exclusive-maximum.test.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and exclusiveMaximum keyword', () => {
|
||||
const schema1 = { type: 'number' }
|
||||
const schema2 = { type: 'number', exclusiveMaximum: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'number', exclusiveMaximum: 42 })
|
||||
})
|
||||
|
||||
test('should merge equal exclusiveMaximum values', () => {
|
||||
const schema1 = { type: 'number', exclusiveMaximum: 42 }
|
||||
const schema2 = { type: 'number', exclusiveMaximum: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'number', exclusiveMaximum: 42 })
|
||||
})
|
||||
|
||||
test('should merge different exclusiveMaximum values', () => {
|
||||
const schema1 = { type: 'integer', exclusiveMaximum: 42 }
|
||||
const schema2 = { type: 'integer', exclusiveMaximum: 43 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'integer', exclusiveMaximum: 42 })
|
||||
})
|
||||
30
node_modules/@fastify/merge-json-schemas/test/exclusive-minimum.test.js
generated
vendored
Normal file
30
node_modules/@fastify/merge-json-schemas/test/exclusive-minimum.test.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and exclusiveMinimum keyword', () => {
|
||||
const schema1 = { type: 'number' }
|
||||
const schema2 = { type: 'number', exclusiveMinimum: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'number', exclusiveMinimum: 42 })
|
||||
})
|
||||
|
||||
test('should merge equal exclusiveMinimum values', () => {
|
||||
const schema1 = { type: 'number', exclusiveMinimum: 42 }
|
||||
const schema2 = { type: 'number', exclusiveMinimum: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'number', exclusiveMinimum: 42 })
|
||||
})
|
||||
|
||||
test('should merge different exclusiveMinimum values', () => {
|
||||
const schema1 = { type: 'integer', exclusiveMinimum: 42 }
|
||||
const schema2 = { type: 'integer', exclusiveMinimum: 43 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'integer', exclusiveMinimum: 43 })
|
||||
})
|
||||
36
node_modules/@fastify/merge-json-schemas/test/format.test.js
generated
vendored
Normal file
36
node_modules/@fastify/merge-json-schemas/test/format.test.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and string format keyword', () => {
|
||||
const schema1 = { type: 'string' }
|
||||
const schema2 = { type: 'string', format: 'date-time' }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string', format: 'date-time' })
|
||||
})
|
||||
|
||||
test('should merge equal string format keywords', () => {
|
||||
const schema1 = { type: 'string', format: 'date-time' }
|
||||
const schema2 = { type: 'string', format: 'date-time' }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string', format: 'date-time' })
|
||||
})
|
||||
|
||||
test('should throw an error if format keyword values are different', () => {
|
||||
const schema1 = { type: 'string', format: 'date-time' }
|
||||
const schema2 = { type: 'string', format: 'date' }
|
||||
|
||||
assert.throws(() => {
|
||||
mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
}, {
|
||||
name: 'JsonSchemaMergeError',
|
||||
code: 'JSON_SCHEMA_MERGE_ERROR',
|
||||
message: 'Failed to merge "format" keyword schemas.',
|
||||
schemas: ['date-time', 'date']
|
||||
})
|
||||
})
|
||||
22
node_modules/@fastify/merge-json-schemas/test/id.test.js
generated
vendored
Normal file
22
node_modules/@fastify/merge-json-schemas/test/id.test.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should skip $id keyword if they are equal', () => {
|
||||
const schema1 = { $id: 'foo', type: 'string' }
|
||||
const schema2 = { $id: 'foo', type: 'string' }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string' })
|
||||
})
|
||||
|
||||
test('should skip $id keyword if they are different', () => {
|
||||
const schema1 = { $id: 'foo', type: 'string' }
|
||||
const schema2 = { $id: 'bar', type: 'string' }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string' })
|
||||
})
|
||||
550
node_modules/@fastify/merge-json-schemas/test/if-then-else.test.js
generated
vendored
Normal file
550
node_modules/@fastify/merge-json-schemas/test/if-then-else.test.js
generated
vendored
Normal file
@@ -0,0 +1,550 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and if/then/else keywords', () => {
|
||||
const schema1 = {}
|
||||
const schema2 = {
|
||||
if: {
|
||||
type: 'string',
|
||||
const: 'foo'
|
||||
},
|
||||
then: {
|
||||
type: 'string',
|
||||
const: 'bar'
|
||||
},
|
||||
else: {
|
||||
type: 'string',
|
||||
const: 'baz'
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
if: {
|
||||
type: 'string',
|
||||
const: 'foo'
|
||||
},
|
||||
then: {
|
||||
type: 'string',
|
||||
const: 'bar'
|
||||
},
|
||||
else: {
|
||||
type: 'string',
|
||||
const: 'baz'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge if/then/else schema with an empty schema', () => {
|
||||
const schema1 = {
|
||||
if: {
|
||||
type: 'string',
|
||||
const: 'foo'
|
||||
},
|
||||
then: {
|
||||
type: 'string',
|
||||
const: 'bar'
|
||||
},
|
||||
else: {
|
||||
type: 'string',
|
||||
const: 'baz'
|
||||
}
|
||||
}
|
||||
const schema2 = {}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
if: {
|
||||
type: 'string',
|
||||
const: 'foo'
|
||||
},
|
||||
then: {
|
||||
type: 'string',
|
||||
const: 'bar'
|
||||
},
|
||||
else: {
|
||||
type: 'string',
|
||||
const: 'baz'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge two if/then/else schemas', () => {
|
||||
const schema1 = {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo1: { type: 'string', const: 'foo1' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar1: { type: 'string', const: 'bar1' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
baz1: { type: 'string', const: 'baz1' }
|
||||
}
|
||||
}
|
||||
}
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo2: { type: 'string', const: 'foo2' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar2: { type: 'string', const: 'bar2' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
baz2: { type: 'string', const: 'baz2' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo1: { type: 'string', const: 'foo1' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar1: { type: 'string', const: 'bar1' }
|
||||
},
|
||||
if: {
|
||||
properties: {
|
||||
foo2: { type: 'string', const: 'foo2' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar2: { type: 'string', const: 'bar2' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
baz2: { type: 'string', const: 'baz2' }
|
||||
}
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
baz1: { type: 'string', const: 'baz1' }
|
||||
},
|
||||
if: {
|
||||
properties: {
|
||||
foo2: { type: 'string', const: 'foo2' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar2: { type: 'string', const: 'bar2' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
baz2: { type: 'string', const: 'baz2' }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge three if/then/else schemas', () => {
|
||||
const schema1 = {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo1: { type: 'string', const: 'foo1' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar1: { type: 'string', const: 'bar1' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
baz1: { type: 'string', const: 'baz1' }
|
||||
}
|
||||
}
|
||||
}
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo2: { type: 'string', const: 'foo2' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar2: { type: 'string', const: 'bar2' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
baz2: { type: 'string', const: 'baz2' }
|
||||
}
|
||||
}
|
||||
}
|
||||
const schema3 = {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo3: { type: 'string', const: 'foo3' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar3: { type: 'string', const: 'bar3' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
baz3: { type: 'string', const: 'baz3' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2, schema3], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo1: { type: 'string', const: 'foo1' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar1: { type: 'string', const: 'bar1' }
|
||||
},
|
||||
if: {
|
||||
properties: {
|
||||
foo2: { type: 'string', const: 'foo2' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar2: { type: 'string', const: 'bar2' }
|
||||
},
|
||||
if: {
|
||||
properties: {
|
||||
foo3: { type: 'string', const: 'foo3' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar3: { type: 'string', const: 'bar3' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
baz3: { type: 'string', const: 'baz3' }
|
||||
}
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
baz2: { type: 'string', const: 'baz2' }
|
||||
},
|
||||
if: {
|
||||
properties: {
|
||||
foo3: { type: 'string', const: 'foo3' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar3: { type: 'string', const: 'bar3' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
baz3: { type: 'string', const: 'baz3' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
baz1: { type: 'string', const: 'baz1' }
|
||||
},
|
||||
if: {
|
||||
properties: {
|
||||
foo2: { type: 'string', const: 'foo2' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar2: { type: 'string', const: 'bar2' }
|
||||
},
|
||||
if: {
|
||||
properties: {
|
||||
foo3: { type: 'string', const: 'foo3' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar3: { type: 'string', const: 'bar3' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
baz3: { type: 'string', const: 'baz3' }
|
||||
}
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
baz2: { type: 'string', const: 'baz2' }
|
||||
},
|
||||
if: {
|
||||
properties: {
|
||||
foo3: { type: 'string', const: 'foo3' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar3: { type: 'string', const: 'bar3' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
baz3: { type: 'string', const: 'baz3' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should two if/then keyword schemas', () => {
|
||||
const schema1 = {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo1: { type: 'string', const: 'foo1' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar1: { type: 'string', const: 'bar1' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo2: { type: 'string', const: 'foo2' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar2: { type: 'string', const: 'bar2' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo1: { type: 'string', const: 'foo1' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar1: { type: 'string', const: 'bar1' }
|
||||
},
|
||||
if: {
|
||||
properties: {
|
||||
foo2: { type: 'string', const: 'foo2' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar2: { type: 'string', const: 'bar2' }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should two if/else keyword schemas', () => {
|
||||
const schema1 = {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo1: { type: 'string', const: 'foo1' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
bar1: { type: 'string', const: 'bar1' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo2: { type: 'string', const: 'foo2' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
bar2: { type: 'string', const: 'bar2' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo1: { type: 'string', const: 'foo1' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
bar1: { type: 'string', const: 'bar1' }
|
||||
},
|
||||
if: {
|
||||
properties: {
|
||||
foo2: { type: 'string', const: 'foo2' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
bar2: { type: 'string', const: 'bar2' }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should two if/then and if/else keyword schemas', () => {
|
||||
const schema1 = {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo1: { type: 'string', const: 'foo1' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar1: { type: 'string', const: 'bar1' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo2: { type: 'string', const: 'foo2' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
bar2: { type: 'string', const: 'bar2' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo1: { type: 'string', const: 'foo1' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar1: { type: 'string', const: 'bar1' }
|
||||
},
|
||||
if: {
|
||||
properties: {
|
||||
foo2: { type: 'string', const: 'foo2' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
bar2: { type: 'string', const: 'bar2' }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should two if/else and if/then keyword schemas', () => {
|
||||
const schema1 = {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo1: { type: 'string', const: 'foo1' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
bar1: { type: 'string', const: 'bar1' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema2 = {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo2: { type: 'string', const: 'foo2' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar2: { type: 'string', const: 'bar2' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'object',
|
||||
if: {
|
||||
properties: {
|
||||
foo1: { type: 'string', const: 'foo1' }
|
||||
}
|
||||
},
|
||||
else: {
|
||||
properties: {
|
||||
bar1: { type: 'string', const: 'bar1' }
|
||||
},
|
||||
if: {
|
||||
properties: {
|
||||
foo2: { type: 'string', const: 'foo2' }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
properties: {
|
||||
bar2: { type: 'string', const: 'bar2' }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
152
node_modules/@fastify/merge-json-schemas/test/items.test.js
generated
vendored
Normal file
152
node_modules/@fastify/merge-json-schemas/test/items.test.js
generated
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and items keyword', () => {
|
||||
const schema1 = { type: 'array' }
|
||||
const schema2 = {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' }
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge two equal item schemas', () => {
|
||||
const schema1 = {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema2 = {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' }
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge two different sets of item schemas', () => {
|
||||
const schema1 = {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'number' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema2 = {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
baz: { type: 'boolean' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
bar: { type: 'number' },
|
||||
baz: { type: 'boolean' }
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('should merge two different sets of item schemas with additionalItems', () => {
|
||||
const schema1 = {
|
||||
type: 'array',
|
||||
items: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string', const: 'foo' }
|
||||
}
|
||||
}
|
||||
],
|
||||
additionalItems: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
baz: { type: 'string', const: 'baz' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema2 = {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
baz: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {
|
||||
type: 'array',
|
||||
items: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string', const: 'foo' },
|
||||
baz: { type: 'string' }
|
||||
}
|
||||
}
|
||||
],
|
||||
additionalItems: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'string' },
|
||||
baz: { type: 'string', const: 'baz' }
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
30
node_modules/@fastify/merge-json-schemas/test/max-items.test.js
generated
vendored
Normal file
30
node_modules/@fastify/merge-json-schemas/test/max-items.test.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and maxItems keyword', () => {
|
||||
const schema1 = { type: 'array' }
|
||||
const schema2 = { type: 'array', maxItems: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'array', maxItems: 42 })
|
||||
})
|
||||
|
||||
test('should merge equal maxItems values', () => {
|
||||
const schema1 = { type: 'array', maxItems: 42 }
|
||||
const schema2 = { type: 'array', maxItems: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'array', maxItems: 42 })
|
||||
})
|
||||
|
||||
test('should merge different maxItems values', () => {
|
||||
const schema1 = { type: 'array', maxItems: 42 }
|
||||
const schema2 = { type: 'array', maxItems: 43 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'array', maxItems: 42 })
|
||||
})
|
||||
30
node_modules/@fastify/merge-json-schemas/test/max-length.test.js
generated
vendored
Normal file
30
node_modules/@fastify/merge-json-schemas/test/max-length.test.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and maxLength keyword', () => {
|
||||
const schema1 = { type: 'string' }
|
||||
const schema2 = { type: 'string', maxLength: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string', maxLength: 42 })
|
||||
})
|
||||
|
||||
test('should merge equal maxLength values', () => {
|
||||
const schema1 = { type: 'string', maxLength: 42 }
|
||||
const schema2 = { type: 'string', maxLength: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string', maxLength: 42 })
|
||||
})
|
||||
|
||||
test('should merge different maxLength values', () => {
|
||||
const schema1 = { type: 'string', maxLength: 42 }
|
||||
const schema2 = { type: 'string', maxLength: 43 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string', maxLength: 42 })
|
||||
})
|
||||
30
node_modules/@fastify/merge-json-schemas/test/max-properties.test.js
generated
vendored
Normal file
30
node_modules/@fastify/merge-json-schemas/test/max-properties.test.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and maxProperties keyword', () => {
|
||||
const schema1 = { type: 'object' }
|
||||
const schema2 = { type: 'object', maxProperties: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'object', maxProperties: 42 })
|
||||
})
|
||||
|
||||
test('should merge equal maxProperties values', () => {
|
||||
const schema1 = { type: 'object', maxProperties: 42 }
|
||||
const schema2 = { type: 'object', maxProperties: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'object', maxProperties: 42 })
|
||||
})
|
||||
|
||||
test('should merge different maxProperties values', () => {
|
||||
const schema1 = { type: 'object', maxProperties: 42 }
|
||||
const schema2 = { type: 'object', maxProperties: 43 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'object', maxProperties: 42 })
|
||||
})
|
||||
30
node_modules/@fastify/merge-json-schemas/test/maximum.test.js
generated
vendored
Normal file
30
node_modules/@fastify/merge-json-schemas/test/maximum.test.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and maximum keyword', () => {
|
||||
const schema1 = { type: 'number' }
|
||||
const schema2 = { type: 'number', maximum: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'number', maximum: 42 })
|
||||
})
|
||||
|
||||
test('should merge equal maximum values', () => {
|
||||
const schema1 = { type: 'number', maximum: 42 }
|
||||
const schema2 = { type: 'number', maximum: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'number', maximum: 42 })
|
||||
})
|
||||
|
||||
test('should merge different maximum values', () => {
|
||||
const schema1 = { type: 'integer', maximum: 42 }
|
||||
const schema2 = { type: 'integer', maximum: 43 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'integer', maximum: 42 })
|
||||
})
|
||||
29
node_modules/@fastify/merge-json-schemas/test/merge-schema.test.js
generated
vendored
Normal file
29
node_modules/@fastify/merge-json-schemas/test/merge-schema.test.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should return an empty schema if passing an empty array', () => {
|
||||
const mergedSchema = mergeSchemas([], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, {})
|
||||
})
|
||||
|
||||
test('should return true if passing all true values', () => {
|
||||
const mergedSchema = mergeSchemas([true, true, true], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, true)
|
||||
})
|
||||
|
||||
test('should return true if passing all false values', () => {
|
||||
const mergedSchema = mergeSchemas([false, false, false], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, false)
|
||||
})
|
||||
|
||||
test('should return true if passing at least one false schema', () => {
|
||||
const schema1 = { type: 'string' }
|
||||
const schema2 = { type: 'number' }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2, false], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, false)
|
||||
})
|
||||
30
node_modules/@fastify/merge-json-schemas/test/min-items.test.js
generated
vendored
Normal file
30
node_modules/@fastify/merge-json-schemas/test/min-items.test.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and minItems keyword', () => {
|
||||
const schema1 = { type: 'array' }
|
||||
const schema2 = { type: 'array', minItems: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'array', minItems: 42 })
|
||||
})
|
||||
|
||||
test('should merge equal minItems values', () => {
|
||||
const schema1 = { type: 'array', minItems: 42 }
|
||||
const schema2 = { type: 'array', minItems: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'array', minItems: 42 })
|
||||
})
|
||||
|
||||
test('should merge different minItems values', () => {
|
||||
const schema1 = { type: 'array', minItems: 42 }
|
||||
const schema2 = { type: 'array', minItems: 43 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'array', minItems: 43 })
|
||||
})
|
||||
30
node_modules/@fastify/merge-json-schemas/test/min-length.test.js
generated
vendored
Normal file
30
node_modules/@fastify/merge-json-schemas/test/min-length.test.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and minLength keyword', () => {
|
||||
const schema1 = { type: 'string' }
|
||||
const schema2 = { type: 'string', minLength: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string', minLength: 42 })
|
||||
})
|
||||
|
||||
test('should merge equal minLength values', () => {
|
||||
const schema1 = { type: 'string', minLength: 42 }
|
||||
const schema2 = { type: 'string', minLength: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string', minLength: 42 })
|
||||
})
|
||||
|
||||
test('should merge different minLength values', () => {
|
||||
const schema1 = { type: 'string', minLength: 42 }
|
||||
const schema2 = { type: 'string', minLength: 43 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'string', minLength: 43 })
|
||||
})
|
||||
30
node_modules/@fastify/merge-json-schemas/test/min-properties.test.js
generated
vendored
Normal file
30
node_modules/@fastify/merge-json-schemas/test/min-properties.test.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and minProperties keyword', () => {
|
||||
const schema1 = { type: 'object' }
|
||||
const schema2 = { type: 'object', minProperties: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'object', minProperties: 42 })
|
||||
})
|
||||
|
||||
test('should merge equal minItems values', () => {
|
||||
const schema1 = { type: 'object', minProperties: 42 }
|
||||
const schema2 = { type: 'object', minProperties: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'object', minProperties: 42 })
|
||||
})
|
||||
|
||||
test('should merge different minItems values', () => {
|
||||
const schema1 = { type: 'object', minProperties: 42 }
|
||||
const schema2 = { type: 'object', minProperties: 43 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'object', minProperties: 43 })
|
||||
})
|
||||
30
node_modules/@fastify/merge-json-schemas/test/minimum.test.js
generated
vendored
Normal file
30
node_modules/@fastify/merge-json-schemas/test/minimum.test.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict'
|
||||
|
||||
const assert = require('node:assert/strict')
|
||||
const { test } = require('node:test')
|
||||
const { mergeSchemas } = require('../index')
|
||||
const { defaultResolver } = require('./utils')
|
||||
|
||||
test('should merge empty schema and minimum keyword', () => {
|
||||
const schema1 = { type: 'number' }
|
||||
const schema2 = { type: 'number', minimum: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'number', minimum: 42 })
|
||||
})
|
||||
|
||||
test('should merge equal minimum values', () => {
|
||||
const schema1 = { type: 'number', minimum: 42 }
|
||||
const schema2 = { type: 'number', minimum: 42 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'number', minimum: 42 })
|
||||
})
|
||||
|
||||
test('should merge different minimum values', () => {
|
||||
const schema1 = { type: 'integer', minimum: 42 }
|
||||
const schema2 = { type: 'integer', minimum: 43 }
|
||||
|
||||
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
|
||||
assert.deepStrictEqual(mergedSchema, { type: 'integer', minimum: 43 })
|
||||
})
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user