planning
All checks were successful
Publish To Prod / deploy_and_publish (push) Successful in 35s

This commit is contained in:
2024-10-14 09:15:30 +02:00
parent bcba00a730
commit 6e64e138e2
21059 changed files with 2317811 additions and 1 deletions

21
node_modules/ajv-errors/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Evgeny Poberezkin
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.

341
node_modules/ajv-errors/README.md generated vendored Normal file
View File

@@ -0,0 +1,341 @@
# ajv-errors
Custom error messages in JSON-Schema for Ajv validator
[![build](https://github.com/ajv-validator/ajv-errors/workflows/build/badge.svg)](https://github.com/ajv-validator/ajv-errors/actions?query=workflow%3Abuild)
[![npm](https://img.shields.io/npm/v/ajv-errors.svg)](https://www.npmjs.com/package/ajv-errors)
[![coverage](https://coveralls.io/repos/github/ajv-validator/ajv-errors/badge.svg?branch=master)](https://coveralls.io/github/ajv-validator/ajv-errors?branch=master)
[![gitter](https://img.shields.io/gitter/room/ajv-validator/ajv.svg)](https://gitter.im/ajv-validator/ajv)
**Please note**
ajv-errors v3 supports [ajv v8](https://github.com/ajv-validator/ajv).
If you are using ajv v6, you should use [ajv-errors v1](https://github.com/ajv-validator/ajv-errors/tree/v1)
## Contents
- [Install](#install)
- [Usage](#usage)
- [Single message](#single-message)
- [Messages for keywords](#messages-for-keywords)
- [Messages for properties and items](#messages-for-properties-and-items)
- [Default message](#default-message)
- [Templates](#templates)
- [Options](#options)
- [Supporters, Enterprise support, Security contact](#supporters)
- [License](#license)
## Install
```
npm install ajv-errors
```
## Usage
Add the keyword `errorMessages` to Ajv instance:
```javascript
const Ajv = require("ajv").default
const ajv = new Ajv({allErrors: true})
// Ajv option allErrors is required
require("ajv-errors")(ajv /*, {singleError: true} */)
```
See [Options](#options) below.
### Single message
Replace all errors in the current schema and subschemas with a single message:
```javascript
const schema = {
type: "object",
required: ["foo"],
properties: {
foo: {type: "integer"},
},
additionalProperties: false,
errorMessage: "should be an object with an integer property foo only",
}
const validate = ajv.compile(schema)
console.log(validate({foo: "a", bar: 2})) // false
console.log(validate.errors) // processed errors
```
Processed errors:
```json5
[
{
keyword: "errorMessage",
message: "should be an object with an integer property foo only",
// ...
params: {
errors: [
{keyword: "additionalProperties", instancePath: "" /* , ... */},
{keyword: "type", instancePath: ".foo" /* , ... */},
],
},
},
]
```
### Messages for keywords
Replace errors for certain keywords in the current schema only:
```javascript
const schema = {
type: "object",
required: ["foo"],
properties: {
foo: {type: "integer"},
},
additionalProperties: false,
errorMessage: {
type: "should be an object", // will not replace internal "type" error for the property "foo"
required: "should have property foo",
additionalProperties: "should not have properties other than foo",
},
}
const validate = ajv.compile(schema)
console.log(validate({foo: "a", bar: 2})) // false
console.log(validate.errors) // processed errors
```
Processed errors:
```json5
[
{
// original error
keyword: type,
instancePath: "/foo",
// ...
message: "should be integer",
},
{
// generated error
keyword: "errorMessage",
message: "should not have properties other than foo",
// ...
params: {
errors: [{keyword: "additionalProperties" /* , ... */}],
},
},
]
```
For keywords "required" and "dependencies" it is possible to specify different messages for different properties:
```javascript
const schema = {
type: "object",
required: ["foo", "bar"],
properties: {
foo: {type: "integer"},
bar: {type: "string"},
},
errorMessage: {
type: "should be an object", // will not replace internal "type" error for the property "foo"
required: {
foo: 'should have an integer property "foo"',
bar: 'should have a string property "bar"',
},
},
}
```
### Messages for properties and items
Replace errors for properties / items (and deeper), regardless where in schema they were created:
```javascript
const schema = {
type: "object",
required: ["foo", "bar"],
allOf: [
{
properties: {
foo: {type: "integer", minimum: 2},
bar: {type: "string", minLength: 2},
},
additionalProperties: false,
},
],
errorMessage: {
properties: {
foo: "data.foo should be integer >= 2",
bar: "data.bar should be string with length >= 2",
},
},
}
const validate = ajv.compile(schema)
console.log(validate({foo: 1, bar: "a"})) // false
console.log(validate.errors) // processed errors
```
Processed errors:
```json5
[
{
keyword: "errorMessage",
message: "data.foo should be integer >= 2",
instancePath: "/foo",
// ...
params: {
errors: [{keyword: "minimum" /* , ... */}],
},
},
{
keyword: "errorMessage",
message: "data.bar should be string with length >= 2",
instancePath: "/bar",
// ...
params: {
errors: [{keyword: "minLength" /* , ... */}],
},
},
]
```
### Default message
When the value of keyword `errorMessage` is an object you can specify a message that will be used if any error appears that is not specified by keywords/properties/items using `_` property:
```javascript
const schema = {
type: "object",
required: ["foo", "bar"],
allOf: [
{
properties: {
foo: {type: "integer", minimum: 2},
bar: {type: "string", minLength: 2},
},
additionalProperties: false,
},
],
errorMessage: {
type: "data should be an object",
properties: {
foo: "data.foo should be integer >= 2",
bar: "data.bar should be string with length >= 2",
},
_: 'data should have properties "foo" and "bar" only',
},
}
const validate = ajv.compile(schema)
console.log(validate({})) // false
console.log(validate.errors) // processed errors
```
Processed errors:
```json5
[
{
keyword: "errorMessage",
message: 'data should be an object with properties "foo" and "bar" only',
instancePath: "",
// ...
params: {
errors: [{keyword: "required" /* , ... */}, {keyword: "required" /* , ... */}],
},
},
]
```
The message in property `_` of `errorMessage` replaces the same errors that would have been replaced if `errorMessage` were a string.
## Templates
Custom error messages used in `errorMessage` keyword can be templates using [JSON-pointers](https://tools.ietf.org/html/rfc6901) or [relative JSON-pointers](http://tools.ietf.org/html/draft-luff-relative-json-pointer-00) to data being validated, in which case the value will be interpolated. Also see [examples](https://gist.github.com/geraintluff/5911303) of relative JSON-pointers.
The syntax to interpolate a value is `${<pointer>}`.
The values used in messages will be JSON-stringified:
- to differentiate between `false` and `"false"`, etc.
- to support structured values.
Example:
```javascript
const schema = {
type: "object",
properties: {
size: {
type: "number",
minimum: 4,
},
},
errorMessage: {
properties: {
size: "size should be a number bigger or equal to 4, current value is ${/size}",
},
},
}
```
#### Using property names in error messages
Property names can be used in error messages with the relative JSON-pointer (e.g. `0#`).
Example:
```javascript
const schema = {
type: "object",
properties: {
size: {
type: "number",
},
},
additionalProperties: {
not: true,
errorMessage: extra property is ${0#}
}
}
```
## Options
Defaults:
```json5
{
keepErrors: false,
singleError: false,
}
```
- _keepErrors_: keep original errors. Default is to remove matched errors (they will still be available in `params.errors` property of generated error). If an error was matched and included in the error generated by `errorMessage` keyword it will have property `emUsed: true`.
- _singleError_: create one error for all keywords used in `errorMessage` keyword (error messages defined for properties and items are not merged because they have different instancePaths). Multiple error messages are concatenated. Option values:
- `false` (default): create multiple errors, one for each message
- `true`: create single error, messages are concatenated using `"; "`
- non-empty string: this string is used as a separator to concatenate messages
## Supporters
[Roger Kepler](https://www.linkedin.com/in/rogerkepler/)
## Enterprise support
ajv-errors package is a part of [Tidelift enterprise subscription](https://tidelift.com/subscription/pkg/npm-ajv-errors?utm_source=npm-ajv-errors&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) - it provides a centralised commercial support to open-source software users, in addition to the support provided by software maintainers.
## Security contact
To report a security vulnerability, please use the
[Tidelift security contact](https://tidelift.com/security).
Tidelift will coordinate the fix and disclosure. Please do NOT report security vulnerability via GitHub issues.
## License
[MIT](https://github.com/epoberezkin/ajv-errors/blob/master/LICENSE)

7
node_modules/ajv-errors/dist/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,7 @@
import type { Plugin } from "ajv";
export interface ErrorMessageOptions {
keepErrors?: boolean;
singleError?: boolean | string;
}
declare const ajvErrors: Plugin<ErrorMessageOptions>;
export default ajvErrors;

275
node_modules/ajv-errors/dist/index.js generated vendored Normal file
View File

@@ -0,0 +1,275 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const ajv_1 = require("ajv");
const codegen_1 = require("ajv/dist/compile/codegen");
const code_1 = require("ajv/dist/compile/codegen/code");
const validate_1 = require("ajv/dist/compile/validate");
const errors_1 = require("ajv/dist/compile/errors");
const names_1 = require("ajv/dist/compile/names");
const keyword = "errorMessage";
const used = new ajv_1.Name("emUsed");
const KEYWORD_PROPERTY_PARAMS = {
required: "missingProperty",
dependencies: "property",
dependentRequired: "property",
};
const INTERPOLATION = /\$\{[^}]+\}/;
const INTERPOLATION_REPLACE = /\$\{([^}]+)\}/g;
const EMPTY_STR = /^""\s*\+\s*|\s*\+\s*""$/g;
function errorMessage(options) {
return {
keyword,
schemaType: ["string", "object"],
post: true,
code(cxt) {
const { gen, data, schema, schemaValue, it } = cxt;
if (it.createErrors === false)
return;
const sch = schema;
const instancePath = codegen_1.strConcat(names_1.default.instancePath, it.errorPath);
gen.if(ajv_1._ `${names_1.default.errors} > 0`, () => {
if (typeof sch == "object") {
const [kwdPropErrors, kwdErrors] = keywordErrorsConfig(sch);
if (kwdErrors)
processKeywordErrors(kwdErrors);
if (kwdPropErrors)
processKeywordPropErrors(kwdPropErrors);
processChildErrors(childErrorsConfig(sch));
}
const schMessage = typeof sch == "string" ? sch : sch._;
if (schMessage)
processAllErrors(schMessage);
if (!options.keepErrors)
removeUsedErrors();
});
function childErrorsConfig({ properties, items }) {
const errors = {};
if (properties) {
errors.props = {};
for (const p in properties)
errors.props[p] = [];
}
if (items) {
errors.items = {};
for (let i = 0; i < items.length; i++)
errors.items[i] = [];
}
return errors;
}
function keywordErrorsConfig(emSchema) {
let propErrors;
let errors;
for (const k in emSchema) {
if (k === "properties" || k === "items")
continue;
const kwdSch = emSchema[k];
if (typeof kwdSch == "object") {
propErrors || (propErrors = {});
const errMap = (propErrors[k] = {});
for (const p in kwdSch)
errMap[p] = [];
}
else {
errors || (errors = {});
errors[k] = [];
}
}
return [propErrors, errors];
}
function processKeywordErrors(kwdErrors) {
const kwdErrs = gen.const("emErrors", ajv_1.stringify(kwdErrors));
const templates = gen.const("templates", getTemplatesCode(kwdErrors, schema));
gen.forOf("err", names_1.default.vErrors, (err) => gen.if(matchKeywordError(err, kwdErrs), () => gen.code(ajv_1._ `${kwdErrs}[${err}.keyword].push(${err})`).assign(ajv_1._ `${err}.${used}`, true)));
const { singleError } = options;
if (singleError) {
const message = gen.let("message", ajv_1._ `""`);
const paramsErrors = gen.let("paramsErrors", ajv_1._ `[]`);
loopErrors((key) => {
gen.if(message, () => gen.code(ajv_1._ `${message} += ${typeof singleError == "string" ? singleError : ";"}`));
gen.code(ajv_1._ `${message} += ${errMessage(key)}`);
gen.assign(paramsErrors, ajv_1._ `${paramsErrors}.concat(${kwdErrs}[${key}])`);
});
errors_1.reportError(cxt, { message, params: ajv_1._ `{errors: ${paramsErrors}}` });
}
else {
loopErrors((key) => errors_1.reportError(cxt, {
message: errMessage(key),
params: ajv_1._ `{errors: ${kwdErrs}[${key}]}`,
}));
}
function loopErrors(body) {
gen.forIn("key", kwdErrs, (key) => gen.if(ajv_1._ `${kwdErrs}[${key}].length`, () => body(key)));
}
function errMessage(key) {
return ajv_1._ `${key} in ${templates} ? ${templates}[${key}]() : ${schemaValue}[${key}]`;
}
}
function processKeywordPropErrors(kwdPropErrors) {
const kwdErrs = gen.const("emErrors", ajv_1.stringify(kwdPropErrors));
const templatesCode = [];
for (const k in kwdPropErrors) {
templatesCode.push([
k,
getTemplatesCode(kwdPropErrors[k], schema[k]),
]);
}
const templates = gen.const("templates", gen.object(...templatesCode));
const kwdPropParams = gen.scopeValue("obj", {
ref: KEYWORD_PROPERTY_PARAMS,
code: ajv_1.stringify(KEYWORD_PROPERTY_PARAMS),
});
const propParam = gen.let("emPropParams");
const paramsErrors = gen.let("emParamsErrors");
gen.forOf("err", names_1.default.vErrors, (err) => gen.if(matchKeywordError(err, kwdErrs), () => {
gen.assign(propParam, ajv_1._ `${kwdPropParams}[${err}.keyword]`);
gen.assign(paramsErrors, ajv_1._ `${kwdErrs}[${err}.keyword][${err}.params[${propParam}]]`);
gen.if(paramsErrors, () => gen.code(ajv_1._ `${paramsErrors}.push(${err})`).assign(ajv_1._ `${err}.${used}`, true));
}));
gen.forIn("key", kwdErrs, (key) => gen.forIn("keyProp", ajv_1._ `${kwdErrs}[${key}]`, (keyProp) => {
gen.assign(paramsErrors, ajv_1._ `${kwdErrs}[${key}][${keyProp}]`);
gen.if(ajv_1._ `${paramsErrors}.length`, () => {
const tmpl = gen.const("tmpl", ajv_1._ `${templates}[${key}] && ${templates}[${key}][${keyProp}]`);
errors_1.reportError(cxt, {
message: ajv_1._ `${tmpl} ? ${tmpl}() : ${schemaValue}[${key}][${keyProp}]`,
params: ajv_1._ `{errors: ${paramsErrors}}`,
});
});
}));
}
function processChildErrors(childErrors) {
const { props, items } = childErrors;
if (!props && !items)
return;
const isObj = ajv_1._ `typeof ${data} == "object"`;
const isArr = ajv_1._ `Array.isArray(${data})`;
const childErrs = gen.let("emErrors");
let childKwd;
let childProp;
const templates = gen.let("templates");
if (props && items) {
childKwd = gen.let("emChildKwd");
gen.if(isObj);
gen.if(isArr, () => {
init(items, schema.items);
gen.assign(childKwd, ajv_1.str `items`);
}, () => {
init(props, schema.properties);
gen.assign(childKwd, ajv_1.str `properties`);
});
childProp = ajv_1._ `[${childKwd}]`;
}
else if (items) {
gen.if(isArr);
init(items, schema.items);
childProp = ajv_1._ `.items`;
}
else if (props) {
gen.if(codegen_1.and(isObj, codegen_1.not(isArr)));
init(props, schema.properties);
childProp = ajv_1._ `.properties`;
}
gen.forOf("err", names_1.default.vErrors, (err) => ifMatchesChildError(err, childErrs, (child) => gen.code(ajv_1._ `${childErrs}[${child}].push(${err})`).assign(ajv_1._ `${err}.${used}`, true)));
gen.forIn("key", childErrs, (key) => gen.if(ajv_1._ `${childErrs}[${key}].length`, () => {
errors_1.reportError(cxt, {
message: ajv_1._ `${key} in ${templates} ? ${templates}[${key}]() : ${schemaValue}${childProp}[${key}]`,
params: ajv_1._ `{errors: ${childErrs}[${key}]}`,
});
gen.assign(ajv_1._ `${names_1.default.vErrors}[${names_1.default.errors}-1].instancePath`, ajv_1._ `${instancePath} + "/" + ${key}.replace(/~/g, "~0").replace(/\\//g, "~1")`);
}));
gen.endIf();
function init(children, msgs) {
gen.assign(childErrs, ajv_1.stringify(children));
gen.assign(templates, getTemplatesCode(children, msgs));
}
}
function processAllErrors(schMessage) {
const errs = gen.const("emErrs", ajv_1._ `[]`);
gen.forOf("err", names_1.default.vErrors, (err) => gen.if(matchAnyError(err), () => gen.code(ajv_1._ `${errs}.push(${err})`).assign(ajv_1._ `${err}.${used}`, true)));
gen.if(ajv_1._ `${errs}.length`, () => errors_1.reportError(cxt, {
message: templateExpr(schMessage),
params: ajv_1._ `{errors: ${errs}}`,
}));
}
function removeUsedErrors() {
const errs = gen.const("emErrs", ajv_1._ `[]`);
gen.forOf("err", names_1.default.vErrors, (err) => gen.if(ajv_1._ `!${err}.${used}`, () => gen.code(ajv_1._ `${errs}.push(${err})`)));
gen.assign(names_1.default.vErrors, errs).assign(names_1.default.errors, ajv_1._ `${errs}.length`);
}
function matchKeywordError(err, kwdErrs) {
return codegen_1.and(ajv_1._ `${err}.keyword !== ${keyword}`, ajv_1._ `!${err}.${used}`, ajv_1._ `${err}.instancePath === ${instancePath}`, ajv_1._ `${err}.keyword in ${kwdErrs}`,
// TODO match the end of the string?
ajv_1._ `${err}.schemaPath.indexOf(${it.errSchemaPath}) === 0`, ajv_1._ `/^\\/[^\\/]*$/.test(${err}.schemaPath.slice(${it.errSchemaPath.length}))`);
}
function ifMatchesChildError(err, childErrs, thenBody) {
gen.if(codegen_1.and(ajv_1._ `${err}.keyword !== ${keyword}`, ajv_1._ `!${err}.${used}`, ajv_1._ `${err}.instancePath.indexOf(${instancePath}) === 0`), () => {
const childRegex = gen.scopeValue("pattern", {
ref: /^\/([^/]*)(?:\/|$)/,
code: ajv_1._ `new RegExp("^\\\/([^/]*)(?:\\\/|$)")`,
});
const matches = gen.const("emMatches", ajv_1._ `${childRegex}.exec(${err}.instancePath.slice(${instancePath}.length))`);
const child = gen.const("emChild", ajv_1._ `${matches} && ${matches}[1].replace(/~1/g, "/").replace(/~0/g, "~")`);
gen.if(ajv_1._ `${child} !== undefined && ${child} in ${childErrs}`, () => thenBody(child));
});
}
function matchAnyError(err) {
return codegen_1.and(ajv_1._ `${err}.keyword !== ${keyword}`, ajv_1._ `!${err}.${used}`, codegen_1.or(ajv_1._ `${err}.instancePath === ${instancePath}`, codegen_1.and(ajv_1._ `${err}.instancePath.indexOf(${instancePath}) === 0`, ajv_1._ `${err}.instancePath[${instancePath}.length] === "/"`)), ajv_1._ `${err}.schemaPath.indexOf(${it.errSchemaPath}) === 0`, ajv_1._ `${err}.schemaPath[${it.errSchemaPath}.length] === "/"`);
}
function getTemplatesCode(keys, msgs) {
const templatesCode = [];
for (const k in keys) {
const msg = msgs[k];
if (INTERPOLATION.test(msg))
templatesCode.push([k, templateFunc(msg)]);
}
return gen.object(...templatesCode);
}
function templateExpr(msg) {
if (!INTERPOLATION.test(msg))
return ajv_1.stringify(msg);
return new code_1._Code(code_1.safeStringify(msg)
.replace(INTERPOLATION_REPLACE, (_s, ptr) => `" + JSON.stringify(${validate_1.getData(ptr, it)}) + "`)
.replace(EMPTY_STR, ""));
}
function templateFunc(msg) {
return ajv_1._ `function(){return ${templateExpr(msg)}}`;
}
},
metaSchema: {
anyOf: [
{ type: "string" },
{
type: "object",
properties: {
properties: { $ref: "#/$defs/stringMap" },
items: { $ref: "#/$defs/stringList" },
required: { $ref: "#/$defs/stringOrMap" },
dependencies: { $ref: "#/$defs/stringOrMap" },
},
additionalProperties: { type: "string" },
},
],
$defs: {
stringMap: {
type: "object",
additionalProperties: { type: "string" },
},
stringOrMap: {
anyOf: [{ type: "string" }, { $ref: "#/$defs/stringMap" }],
},
stringList: { type: "array", items: { type: "string" } },
},
},
};
}
const ajvErrors = (ajv, options = {}) => {
if (!ajv.opts.allErrors)
throw new Error("ajv-errors: Ajv option allErrors must be true");
if (ajv.opts.jsPropertySyntax) {
throw new Error("ajv-errors: ajv option jsPropertySyntax is not supported");
}
return ajv.addKeyword(errorMessage(options));
};
exports.default = ajvErrors;
module.exports = ajvErrors;
module.exports.default = ajvErrors;
//# sourceMappingURL=index.js.map

1
node_modules/ajv-errors/dist/index.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

66
node_modules/ajv-errors/package.json generated vendored Normal file
View File

@@ -0,0 +1,66 @@
{
"name": "ajv-errors",
"version": "3.0.0",
"description": "Custom error messages in JSON Schemas for Ajv validator",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"src",
"dist"
],
"scripts": {
"build": "rm -rf dist && tsc",
"eslint": "eslint \"src/**/*.*s\" \"spec/**/*.*s\"",
"prettier:write": "prettier --write \"./**/*.{json,ts,js}\"",
"prettier:check": "prettier --list-different \"./**/*.{json,ts,js}\"",
"test-spec": "jest \"spec/*.ts\"",
"test-cov": "jest \"spec/*.ts\" --coverage",
"test": "npm run prettier:check && npm run eslint && npm run build && npm run test-cov",
"prepublish": "npm run build"
},
"repository": {
"type": "git",
"url": "git+https://github.com/epoberezkin/ajv-errors.git"
},
"keywords": [
"ajv",
"json-schema",
"validator",
"error",
"messages"
],
"author": "",
"license": "MIT",
"bugs": {
"url": "https://github.com/epoberezkin/ajv-errors/issues"
},
"homepage": "https://github.com/epoberezkin/ajv-errors#readme",
"peerDependencies": {
"ajv": "^8.0.1"
},
"devDependencies": {
"@ajv-validator/config": "^0.3.0",
"@types/jest": "^26.0.15",
"@types/node": "^14.14.7",
"@typescript-eslint/eslint-plugin": "^4.7.0",
"@typescript-eslint/parser": "^4.7.0",
"ajv": "^8.0.1",
"eslint": "^7.2.0",
"eslint-config-prettier": "^7.0.0",
"husky": "^5.1.3",
"jest": "^26.6.3",
"lint-staged": "^10.5.1",
"prettier": "^2.1.2",
"ts-jest": "^26.4.4",
"typescript": "^4.0.5"
},
"prettier": "@ajv-validator/config/prettierrc.json",
"husky": {
"hooks": {
"pre-commit": "lint-staged && npm test"
}
},
"lint-staged": {
"*.{json,yaml,js,ts}": "prettier --write"
}
}

394
node_modules/ajv-errors/src/index.ts generated vendored Normal file
View File

@@ -0,0 +1,394 @@
import type {Plugin, CodeKeywordDefinition, KeywordCxt, ErrorObject, Code} from "ajv"
import Ajv, {_, str, stringify, Name} from "ajv"
import {and, or, not, strConcat} from "ajv/dist/compile/codegen"
import {safeStringify, _Code} from "ajv/dist/compile/codegen/code"
import {getData} from "ajv/dist/compile/validate"
import {reportError} from "ajv/dist/compile/errors"
import N from "ajv/dist/compile/names"
type ErrorsMap<T extends string | number> = {[P in T]?: ErrorObject[]}
type StringMap = {[P in string]?: string}
type ErrorMessageSchema = {
properties?: StringMap
items?: string[]
required?: string | StringMap
dependencies?: string | StringMap
_?: string
} & {[K in string]?: string | StringMap}
interface ChildErrors {
props?: ErrorsMap<string>
items?: ErrorsMap<number>
}
const keyword = "errorMessage"
const used: Name = new Name("emUsed")
const KEYWORD_PROPERTY_PARAMS = {
required: "missingProperty",
dependencies: "property",
dependentRequired: "property",
}
export interface ErrorMessageOptions {
keepErrors?: boolean
singleError?: boolean | string
}
const INTERPOLATION = /\$\{[^}]+\}/
const INTERPOLATION_REPLACE = /\$\{([^}]+)\}/g
const EMPTY_STR = /^""\s*\+\s*|\s*\+\s*""$/g
function errorMessage(options: ErrorMessageOptions): CodeKeywordDefinition {
return {
keyword,
schemaType: ["string", "object"],
post: true,
code(cxt: KeywordCxt) {
const {gen, data, schema, schemaValue, it} = cxt
if (it.createErrors === false) return
const sch: ErrorMessageSchema | string = schema
const instancePath = strConcat(N.instancePath, it.errorPath)
gen.if(_`${N.errors} > 0`, () => {
if (typeof sch == "object") {
const [kwdPropErrors, kwdErrors] = keywordErrorsConfig(sch)
if (kwdErrors) processKeywordErrors(kwdErrors)
if (kwdPropErrors) processKeywordPropErrors(kwdPropErrors)
processChildErrors(childErrorsConfig(sch))
}
const schMessage = typeof sch == "string" ? sch : sch._
if (schMessage) processAllErrors(schMessage)
if (!options.keepErrors) removeUsedErrors()
})
function childErrorsConfig({properties, items}: ErrorMessageSchema): ChildErrors {
const errors: ChildErrors = {}
if (properties) {
errors.props = {}
for (const p in properties) errors.props[p] = []
}
if (items) {
errors.items = {}
for (let i = 0; i < items.length; i++) errors.items[i] = []
}
return errors
}
function keywordErrorsConfig(
emSchema: ErrorMessageSchema
): [{[K in string]?: ErrorsMap<string>} | undefined, ErrorsMap<string> | undefined] {
let propErrors: {[K in string]?: ErrorsMap<string>} | undefined
let errors: ErrorsMap<string> | undefined
for (const k in emSchema) {
if (k === "properties" || k === "items") continue
const kwdSch = emSchema[k]
if (typeof kwdSch == "object") {
propErrors ||= {}
const errMap: ErrorsMap<string> = (propErrors[k] = {})
for (const p in kwdSch) errMap[p] = []
} else {
errors ||= {}
errors[k] = []
}
}
return [propErrors, errors]
}
function processKeywordErrors(kwdErrors: ErrorsMap<string>): void {
const kwdErrs = gen.const("emErrors", stringify(kwdErrors))
const templates = gen.const("templates", getTemplatesCode(kwdErrors, schema))
gen.forOf("err", N.vErrors, (err) =>
gen.if(matchKeywordError(err, kwdErrs), () =>
gen.code(_`${kwdErrs}[${err}.keyword].push(${err})`).assign(_`${err}.${used}`, true)
)
)
const {singleError} = options
if (singleError) {
const message = gen.let("message", _`""`)
const paramsErrors = gen.let("paramsErrors", _`[]`)
loopErrors((key) => {
gen.if(message, () =>
gen.code(_`${message} += ${typeof singleError == "string" ? singleError : ";"}`)
)
gen.code(_`${message} += ${errMessage(key)}`)
gen.assign(paramsErrors, _`${paramsErrors}.concat(${kwdErrs}[${key}])`)
})
reportError(cxt, {message, params: _`{errors: ${paramsErrors}}`})
} else {
loopErrors((key) =>
reportError(cxt, {
message: errMessage(key),
params: _`{errors: ${kwdErrs}[${key}]}`,
})
)
}
function loopErrors(body: (key: Name) => void): void {
gen.forIn("key", kwdErrs, (key) => gen.if(_`${kwdErrs}[${key}].length`, () => body(key)))
}
function errMessage(key: Name): Code {
return _`${key} in ${templates} ? ${templates}[${key}]() : ${schemaValue}[${key}]`
}
}
function processKeywordPropErrors(kwdPropErrors: {[K in string]?: ErrorsMap<string>}): void {
const kwdErrs = gen.const("emErrors", stringify(kwdPropErrors))
const templatesCode: [string, Code][] = []
for (const k in kwdPropErrors) {
templatesCode.push([
k,
getTemplatesCode(kwdPropErrors[k] as ErrorsMap<string>, schema[k]),
])
}
const templates = gen.const("templates", gen.object(...templatesCode))
const kwdPropParams = gen.scopeValue("obj", {
ref: KEYWORD_PROPERTY_PARAMS,
code: stringify(KEYWORD_PROPERTY_PARAMS),
})
const propParam = gen.let("emPropParams")
const paramsErrors = gen.let("emParamsErrors")
gen.forOf("err", N.vErrors, (err) =>
gen.if(matchKeywordError(err, kwdErrs), () => {
gen.assign(propParam, _`${kwdPropParams}[${err}.keyword]`)
gen.assign(paramsErrors, _`${kwdErrs}[${err}.keyword][${err}.params[${propParam}]]`)
gen.if(paramsErrors, () =>
gen.code(_`${paramsErrors}.push(${err})`).assign(_`${err}.${used}`, true)
)
})
)
gen.forIn("key", kwdErrs, (key) =>
gen.forIn("keyProp", _`${kwdErrs}[${key}]`, (keyProp) => {
gen.assign(paramsErrors, _`${kwdErrs}[${key}][${keyProp}]`)
gen.if(_`${paramsErrors}.length`, () => {
const tmpl = gen.const(
"tmpl",
_`${templates}[${key}] && ${templates}[${key}][${keyProp}]`
)
reportError(cxt, {
message: _`${tmpl} ? ${tmpl}() : ${schemaValue}[${key}][${keyProp}]`,
params: _`{errors: ${paramsErrors}}`,
})
})
})
)
}
function processChildErrors(childErrors: ChildErrors): void {
const {props, items} = childErrors
if (!props && !items) return
const isObj = _`typeof ${data} == "object"`
const isArr = _`Array.isArray(${data})`
const childErrs = gen.let("emErrors")
let childKwd: Name
let childProp: Code
const templates = gen.let("templates")
if (props && items) {
childKwd = gen.let("emChildKwd")
gen.if(isObj)
gen.if(
isArr,
() => {
init(items, schema.items)
gen.assign(childKwd, str`items`)
},
() => {
init(props, schema.properties)
gen.assign(childKwd, str`properties`)
}
)
childProp = _`[${childKwd}]`
} else if (items) {
gen.if(isArr)
init(items, schema.items)
childProp = _`.items`
} else if (props) {
gen.if(and(isObj, not(isArr)))
init(props, schema.properties)
childProp = _`.properties`
}
gen.forOf("err", N.vErrors, (err) =>
ifMatchesChildError(err, childErrs, (child) =>
gen.code(_`${childErrs}[${child}].push(${err})`).assign(_`${err}.${used}`, true)
)
)
gen.forIn("key", childErrs, (key) =>
gen.if(_`${childErrs}[${key}].length`, () => {
reportError(cxt, {
message: _`${key} in ${templates} ? ${templates}[${key}]() : ${schemaValue}${childProp}[${key}]`,
params: _`{errors: ${childErrs}[${key}]}`,
})
gen.assign(
_`${N.vErrors}[${N.errors}-1].instancePath`,
_`${instancePath} + "/" + ${key}.replace(/~/g, "~0").replace(/\\//g, "~1")`
)
})
)
gen.endIf()
function init<T extends string | number>(
children: ErrorsMap<T>,
msgs: {[K in string]?: string}
): void {
gen.assign(childErrs, stringify(children))
gen.assign(templates, getTemplatesCode(children, msgs))
}
}
function processAllErrors(schMessage: string): void {
const errs = gen.const("emErrs", _`[]`)
gen.forOf("err", N.vErrors, (err) =>
gen.if(matchAnyError(err), () =>
gen.code(_`${errs}.push(${err})`).assign(_`${err}.${used}`, true)
)
)
gen.if(_`${errs}.length`, () =>
reportError(cxt, {
message: templateExpr(schMessage),
params: _`{errors: ${errs}}`,
})
)
}
function removeUsedErrors(): void {
const errs = gen.const("emErrs", _`[]`)
gen.forOf("err", N.vErrors, (err) =>
gen.if(_`!${err}.${used}`, () => gen.code(_`${errs}.push(${err})`))
)
gen.assign(N.vErrors, errs).assign(N.errors, _`${errs}.length`)
}
function matchKeywordError(err: Name, kwdErrs: Name): Code {
return and(
_`${err}.keyword !== ${keyword}`,
_`!${err}.${used}`,
_`${err}.instancePath === ${instancePath}`,
_`${err}.keyword in ${kwdErrs}`,
// TODO match the end of the string?
_`${err}.schemaPath.indexOf(${it.errSchemaPath}) === 0`,
_`/^\\/[^\\/]*$/.test(${err}.schemaPath.slice(${it.errSchemaPath.length}))`
)
}
function ifMatchesChildError(
err: Name,
childErrs: Name,
thenBody: (child: Name) => void
): void {
gen.if(
and(
_`${err}.keyword !== ${keyword}`,
_`!${err}.${used}`,
_`${err}.instancePath.indexOf(${instancePath}) === 0`
),
() => {
const childRegex = gen.scopeValue("pattern", {
ref: /^\/([^/]*)(?:\/|$)/,
code: _`new RegExp("^\\\/([^/]*)(?:\\\/|$)")`,
})
const matches = gen.const(
"emMatches",
_`${childRegex}.exec(${err}.instancePath.slice(${instancePath}.length))`
)
const child = gen.const(
"emChild",
_`${matches} && ${matches}[1].replace(/~1/g, "/").replace(/~0/g, "~")`
)
gen.if(_`${child} !== undefined && ${child} in ${childErrs}`, () => thenBody(child))
}
)
}
function matchAnyError(err: Name): Code {
return and(
_`${err}.keyword !== ${keyword}`,
_`!${err}.${used}`,
or(
_`${err}.instancePath === ${instancePath}`,
and(
_`${err}.instancePath.indexOf(${instancePath}) === 0`,
_`${err}.instancePath[${instancePath}.length] === "/"`
)
),
_`${err}.schemaPath.indexOf(${it.errSchemaPath}) === 0`,
_`${err}.schemaPath[${it.errSchemaPath}.length] === "/"`
)
}
function getTemplatesCode(keys: Record<string, any>, msgs: {[K in string]?: string}): Code {
const templatesCode: [string, Code][] = []
for (const k in keys) {
const msg = msgs[k] as string
if (INTERPOLATION.test(msg)) templatesCode.push([k, templateFunc(msg)])
}
return gen.object(...templatesCode)
}
function templateExpr(msg: string): Code {
if (!INTERPOLATION.test(msg)) return stringify(msg)
return new _Code(
safeStringify(msg)
.replace(
INTERPOLATION_REPLACE,
(_s, ptr) => `" + JSON.stringify(${getData(ptr, it)}) + "`
)
.replace(EMPTY_STR, "")
)
}
function templateFunc(msg: string): Code {
return _`function(){return ${templateExpr(msg)}}`
}
},
metaSchema: {
anyOf: [
{type: "string"},
{
type: "object",
properties: {
properties: {$ref: "#/$defs/stringMap"},
items: {$ref: "#/$defs/stringList"},
required: {$ref: "#/$defs/stringOrMap"},
dependencies: {$ref: "#/$defs/stringOrMap"},
},
additionalProperties: {type: "string"},
},
],
$defs: {
stringMap: {
type: "object",
additionalProperties: {type: "string"},
},
stringOrMap: {
anyOf: [{type: "string"}, {$ref: "#/$defs/stringMap"}],
},
stringList: {type: "array", items: {type: "string"}},
},
},
}
}
const ajvErrors: Plugin<ErrorMessageOptions> = (
ajv: Ajv,
options: ErrorMessageOptions = {}
): Ajv => {
if (!ajv.opts.allErrors) throw new Error("ajv-errors: Ajv option allErrors must be true")
if (ajv.opts.jsPropertySyntax) {
throw new Error("ajv-errors: ajv option jsPropertySyntax is not supported")
}
return ajv.addKeyword(errorMessage(options))
}
export default ajvErrors
module.exports = ajvErrors
module.exports.default = ajvErrors