Initial commit: notification-elements-demo app

Interactive Angular 19 demo for @sda/notification-elements-ui with
6 sections: Bell & Feed, Notification Center, Inbox, Comments &
Threads, Mention Input, and Full-Featured layout. Includes mock
data, dark mode toggle, and real-time event log.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Giuliano Silvestro
2026-02-13 21:49:19 +10:00
commit 5d0c9ec7eb
36473 changed files with 3778146 additions and 0 deletions

20
node_modules/schema-utils/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,20 @@
Copyright JS Foundation and other contributors
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.

317
node_modules/schema-utils/README.md generated vendored Normal file
View File

@@ -0,0 +1,317 @@
<div align="center">
<a href="http://json-schema.org">
<img width="160" height="160"
src="https://raw.githubusercontent.com/webpack-contrib/schema-utils/main/.github/assets/logo.png">
</a>
<a href="https://github.com/webpack/webpack">
<img width="200" height="200"
src="https://webpack.js.org/assets/icon-square-big.svg">
</a>
</div>
[![npm][npm]][npm-url]
[![node][node]][node-url]
[![tests][tests]][tests-url]
[![coverage][cover]][cover-url]
[![GitHub Discussions][discussion]][discussion-url]
[![size][size]][size-url]
# schema-utils
Package for validate options in loaders and plugins.
## Getting Started
To begin, you'll need to install `schema-utils`:
```console
npm install schema-utils
```
## API
**schema.json**
```json
{
"type": "object",
"properties": {
"option": {
"type": "boolean"
}
},
"additionalProperties": false
}
```
```js
import schema from "./path/to/schema.json";
import { validate } from "schema-utils";
const options = { option: true };
const configuration = { name: "Loader Name/Plugin Name/Name" };
validate(schema, options, configuration);
```
### `schema`
Type: `String`
JSON schema.
Simple example of schema:
```json
{
"type": "object",
"properties": {
"name": {
"description": "This is description of option.",
"type": "string"
}
},
"additionalProperties": false
}
```
### `options`
Type: `Object`
Object with options.
```js
import schema from "./path/to/schema.json";
import { validate } from "schema-utils";
const options = { foo: "bar" };
validate(schema, { name: 123 }, { name: "MyPlugin" });
```
### `configuration`
Allow to configure validator.
There is an alternative method to configure the `name` and`baseDataPath` options via the `title` property in the schema.
For example:
```json
{
"title": "My Loader options",
"type": "object",
"properties": {
"name": {
"description": "This is description of option.",
"type": "string"
}
},
"additionalProperties": false
}
```
The last word used for the `baseDataPath` option, other words used for the `name` option.
Based on the example above the `name` option equals `My Loader`, the `baseDataPath` option equals `options`.
#### `name`
Type: `Object`
Default: `"Object"`
Allow to setup name in validation errors.
```js
import schema from "./path/to/schema.json";
import { validate } from "schema-utils";
const options = { foo: "bar" };
validate(schema, options, { name: "MyPlugin" });
```
```shell
Invalid configuration object. MyPlugin has been initialised using a configuration object that does not match the API schema.
- configuration.optionName should be a integer.
```
#### `baseDataPath`
Type: `String`
Default: `"configuration"`
Allow to setup base data path in validation errors.
```js
import schema from "./path/to/schema.json";
import { validate } from "schema-utils";
const options = { foo: "bar" };
validate(schema, options, { name: "MyPlugin", baseDataPath: "options" });
```
```shell
Invalid options object. MyPlugin has been initialised using an options object that does not match the API schema.
- options.optionName should be a integer.
```
#### `postFormatter`
Type: `Function`
Default: `undefined`
Allow to reformat errors.
```js
import schema from "./path/to/schema.json";
import { validate } from "schema-utils";
const options = { foo: "bar" };
validate(schema, options, {
name: "MyPlugin",
postFormatter: (formattedError, error) => {
if (error.keyword === "type") {
return `${formattedError}\nAdditional Information.`;
}
return formattedError;
},
});
```
```shell
Invalid options object. MyPlugin has been initialized using an options object that does not match the API schema.
- options.optionName should be a integer.
Additional Information.
```
## Examples
**schema.json**
```json
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"test": {
"anyOf": [
{ "type": "array" },
{ "type": "string" },
{ "instanceof": "RegExp" }
]
},
"transform": {
"instanceof": "Function"
},
"sourceMap": {
"type": "boolean"
}
},
"additionalProperties": false
}
```
### `Loader`
```js
import { getOptions } from "loader-utils";
import { validate } from "schema-utils";
import schema from "path/to/schema.json";
function loader(src, map) {
const options = getOptions(this);
validate(schema, options, {
name: "Loader Name",
baseDataPath: "options",
});
// Code...
}
export default loader;
```
### `Plugin`
```js
import { validate } from "schema-utils";
import schema from "path/to/schema.json";
class Plugin {
constructor(options) {
validate(schema, options, {
name: "Plugin Name",
baseDataPath: "options",
});
this.options = options;
}
apply(compiler) {
// Code...
}
}
export default Plugin;
```
### Allow to disable and enable validation (the `validate` function do nothing)
This can be useful when you don't want to do validation for `production` builds.
```js
import { disableValidation, enableValidation, validate } from "schema-utils";
// Disable validation
disableValidation();
// Do nothing
validate(schema, options);
// Enable validation
enableValidation();
// Will throw an error if schema is not valid
validate(schema, options);
// Allow to undestand do you need validation or not
const need = needValidate();
console.log(need);
```
Also you can enable/disable validation using the `process.env.SKIP_VALIDATION` env variable.
Supported values (case insensitive):
- `yes`/`y`/`true`/`1`/`on`
- `no`/`n`/`false`/`0`/`off`
## Contributing
Please take a moment to read our contributing guidelines if you haven't yet done so.
[CONTRIBUTING](./.github/CONTRIBUTING.md)
## License
[MIT](./LICENSE)
[npm]: https://img.shields.io/npm/v/schema-utils.svg
[npm-url]: https://npmjs.com/package/schema-utils
[node]: https://img.shields.io/node/v/schema-utils.svg
[node-url]: https://nodejs.org
[tests]: https://github.com/webpack/schema-utils/workflows/schema-utils/badge.svg
[tests-url]: https://github.com/webpack/schema-utils/actions
[cover]: https://codecov.io/gh/webpack/schema-utils/branch/main/graph/badge.svg
[cover-url]: https://codecov.io/gh/webpack/schema-utils
[discussion]: https://img.shields.io/github/discussions/webpack/webpack
[discussion-url]: https://github.com/webpack/webpack/discussions
[size]: https://packagephobia.com/badge?p=schema-utils
[size-url]: https://packagephobia.com/result?p=schema-utils

View File

@@ -0,0 +1,74 @@
export default ValidationError;
export type JSONSchema6 = import("json-schema").JSONSchema6;
export type JSONSchema7 = import("json-schema").JSONSchema7;
export type Schema = import("./validate").Schema;
export type ValidationErrorConfiguration =
import("./validate").ValidationErrorConfiguration;
export type PostFormatter = import("./validate").PostFormatter;
export type SchemaUtilErrorObject = import("./validate").SchemaUtilErrorObject;
declare class ValidationError extends Error {
/**
* @param {Array<SchemaUtilErrorObject>} errors array of error objects
* @param {Schema} schema schema
* @param {ValidationErrorConfiguration} configuration configuration
*/
constructor(
errors: Array<SchemaUtilErrorObject>,
schema: Schema,
configuration?: ValidationErrorConfiguration,
);
/** @type {Array<SchemaUtilErrorObject>} */
errors: Array<SchemaUtilErrorObject>;
/** @type {Schema} */
schema: Schema;
/** @type {string} */
headerName: string;
/** @type {string} */
baseDataPath: string;
/** @type {PostFormatter | null} */
postFormatter: PostFormatter | null;
/**
* @param {string} path path
* @returns {Schema} schema
*/
getSchemaPart(path: string): Schema;
/**
* @param {Schema} schema schema
* @param {boolean} logic logic
* @param {Array<object>} prevSchemas prev schemas
* @returns {string} formatted schema
*/
formatSchema(
schema: Schema,
logic?: boolean,
prevSchemas?: Array<object>,
): string;
/**
* @param {Schema=} schemaPart schema part
* @param {(boolean | Array<string>)=} additionalPath additional path
* @param {boolean=} needDot true when need dot
* @param {boolean=} logic logic
* @returns {string} schema part text
*/
getSchemaPartText(
schemaPart?: Schema | undefined,
additionalPath?: (boolean | Array<string>) | undefined,
needDot?: boolean | undefined,
logic?: boolean | undefined,
): string;
/**
* @param {Schema=} schemaPart schema part
* @returns {string} schema part description
*/
getSchemaPartDescription(schemaPart?: Schema | undefined): string;
/**
* @param {SchemaUtilErrorObject} error error object
* @returns {string} formatted error object
*/
formatValidationError(error: SchemaUtilErrorObject): string;
/**
* @param {Array<SchemaUtilErrorObject>} errors errors
* @returns {string} formatted errors
*/
formatValidationErrors(errors: Array<SchemaUtilErrorObject>): string;
}

19
node_modules/schema-utils/declarations/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,19 @@
export type Schema = import("./validate").Schema;
export type JSONSchema4 = import("./validate").JSONSchema4;
export type JSONSchema6 = import("./validate").JSONSchema6;
export type JSONSchema7 = import("./validate").JSONSchema7;
export type ExtendedSchema = import("./validate").ExtendedSchema;
export type ValidationErrorConfiguration =
import("./validate").ValidationErrorConfiguration;
import { validate } from "./validate";
import { ValidationError } from "./validate";
import { enableValidation } from "./validate";
import { disableValidation } from "./validate";
import { needValidate } from "./validate";
export {
validate,
ValidationError,
enableValidation,
disableValidation,
needValidate,
};

View File

@@ -0,0 +1,10 @@
export default addAbsolutePathKeyword;
export type Ajv = import("ajv").default;
export type SchemaValidateFunction = import("ajv").SchemaValidateFunction;
export type AnySchemaObject = import("ajv").AnySchemaObject;
export type SchemaUtilErrorObject = import("../validate").SchemaUtilErrorObject;
/**
* @param {Ajv} ajv ajv
* @returns {Ajv} configured ajv
*/
declare function addAbsolutePathKeyword(ajv: Ajv): Ajv;

View File

@@ -0,0 +1,14 @@
export default addLimitKeyword;
export type Ajv = import("ajv").default;
export type Code = import("ajv").Code;
export type Name = import("ajv").Name;
export type KeywordErrorDefinition = import("ajv").KeywordErrorDefinition;
/** @typedef {import("ajv").default} Ajv */
/** @typedef {import("ajv").Code} Code */
/** @typedef {import("ajv").Name} Name */
/** @typedef {import("ajv").KeywordErrorDefinition} KeywordErrorDefinition */
/**
* @param {Ajv} ajv ajv
* @returns {Ajv} ajv with limit keyword
*/
declare function addLimitKeyword(ajv: Ajv): Ajv;

View File

@@ -0,0 +1,14 @@
export default addUndefinedAsNullKeyword;
export type Ajv = import("ajv").default;
export type SchemaValidateFunction = import("ajv").SchemaValidateFunction;
export type AnySchemaObject = import("ajv").AnySchemaObject;
export type ValidateFunction = import("ajv").ValidateFunction;
/** @typedef {import("ajv").default} Ajv */
/** @typedef {import("ajv").SchemaValidateFunction} SchemaValidateFunction */
/** @typedef {import("ajv").AnySchemaObject} AnySchemaObject */
/** @typedef {import("ajv").ValidateFunction} ValidateFunction */
/**
* @param {Ajv} ajv ajv
* @returns {Ajv} configured ajv
*/
declare function addUndefinedAsNullKeyword(ajv: Ajv): Ajv;

79
node_modules/schema-utils/declarations/util/Range.d.ts generated vendored Normal file
View File

@@ -0,0 +1,79 @@
export = Range;
/**
* @typedef {[number, boolean]} RangeValue
*/
/**
* @callback RangeValueCallback
* @param {RangeValue} rangeValue
* @returns {boolean}
*/
declare class Range {
/**
* @param {"left" | "right"} side side
* @param {boolean} exclusive exclusive
* @returns {">" | ">=" | "<" | "<="} operator
*/
static getOperator(
side: "left" | "right",
exclusive: boolean,
): ">" | ">=" | "<" | "<=";
/**
* @param {number} value value
* @param {boolean} logic is not logic applied
* @param {boolean} exclusive is range exclusive
* @returns {string} formatted right
*/
static formatRight(value: number, logic: boolean, exclusive: boolean): string;
/**
* @param {number} value value
* @param {boolean} logic is not logic applied
* @param {boolean} exclusive is range exclusive
* @returns {string} formatted left
*/
static formatLeft(value: number, logic: boolean, exclusive: boolean): string;
/**
* @param {number} start left side value
* @param {number} end right side value
* @param {boolean} startExclusive is range exclusive from left side
* @param {boolean} endExclusive is range exclusive from right side
* @param {boolean} logic is not logic applied
* @returns {string} formatted range
*/
static formatRange(
start: number,
end: number,
startExclusive: boolean,
endExclusive: boolean,
logic: boolean,
): string;
/**
* @param {Array<RangeValue>} values values
* @param {boolean} logic is not logic applied
* @returns {RangeValue} computed value and it's exclusive flag
*/
static getRangeValue(values: Array<RangeValue>, logic: boolean): RangeValue;
/** @type {Array<RangeValue>} */
_left: Array<RangeValue>;
/** @type {Array<RangeValue>} */
_right: Array<RangeValue>;
/**
* @param {number} value value
* @param {boolean=} exclusive true when exclusive, otherwise false
*/
left(value: number, exclusive?: boolean | undefined): void;
/**
* @param {number} value value
* @param {boolean=} exclusive true when exclusive, otherwise false
*/
right(value: number, exclusive?: boolean | undefined): void;
/**
* @param {boolean} logic is not logic applied
* @returns {string} "smart" range string representation
*/
format(logic?: boolean): string;
}
declare namespace Range {
export { RangeValue, RangeValueCallback };
}
type RangeValue = [number, boolean];
type RangeValueCallback = (rangeValue: RangeValue) => boolean;

View File

@@ -0,0 +1,3 @@
export function stringHints(schema: Schema, logic: boolean): string[];
export function numberHints(schema: Schema, logic: boolean): string[];
export type Schema = import("../validate").Schema;

View File

@@ -0,0 +1,12 @@
export default memoize;
export type FunctionReturning<T> = () => T;
/**
* @template T
* @typedef {() => T} FunctionReturning
*/
/**
* @template T
* @param {FunctionReturning<T>} fn memorized function
* @returns {FunctionReturning<T>} new function
*/
declare function memoize<T>(fn: FunctionReturning<T>): FunctionReturning<T>;

77
node_modules/schema-utils/declarations/validate.d.ts generated vendored Normal file
View File

@@ -0,0 +1,77 @@
export { default as ValidationError } from "./ValidationError";
export type JSONSchema4 = import("json-schema").JSONSchema4;
export type JSONSchema6 = import("json-schema").JSONSchema6;
export type JSONSchema7 = import("json-schema").JSONSchema7;
export type ErrorObject = import("ajv").ErrorObject;
export type ExtendedSchema = {
/**
* format minimum
*/
formatMinimum?: (string | number) | undefined;
/**
* format maximum
*/
formatMaximum?: (string | number) | undefined;
/**
* format exclusive minimum
*/
formatExclusiveMinimum?: (string | boolean) | undefined;
/**
* format exclusive maximum
*/
formatExclusiveMaximum?: (string | boolean) | undefined;
/**
* link
*/
link?: string | undefined;
/**
* undefined will be resolved as null
*/
undefinedAsNull?: boolean | undefined;
};
export type Extend = ExtendedSchema;
export type Schema = (JSONSchema4 | JSONSchema6 | JSONSchema7) & ExtendedSchema;
export type SchemaUtilErrorObject = ErrorObject & {
children?: Array<ErrorObject>;
};
export type PostFormatter = (
formattedError: string,
error: SchemaUtilErrorObject,
) => string;
export type ValidationErrorConfiguration = {
/**
* name
*/
name?: string | undefined;
/**
* base data path
*/
baseDataPath?: string | undefined;
/**
* post formatter
*/
postFormatter?: PostFormatter | undefined;
};
/**
* @param {Schema} schema schema
* @param {Array<object> | object} options options
* @param {ValidationErrorConfiguration=} configuration configuration
* @returns {void}
*/
export function validate(
schema: Schema,
options: Array<object> | object,
configuration?: ValidationErrorConfiguration | undefined,
): void;
/**
* @returns {void}
*/
export function enableValidation(): void;
/**
* @returns {void}
*/
export function disableValidation(): void;
/**
* @returns {boolean} true when need validate, otherwise false
*/
export function needValidate(): boolean;

1061
node_modules/schema-utils/dist/ValidationError.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

23
node_modules/schema-utils/dist/index.js generated vendored Normal file
View File

@@ -0,0 +1,23 @@
"use strict";
/** @typedef {import("./validate").Schema} Schema */
/** @typedef {import("./validate").JSONSchema4} JSONSchema4 */
/** @typedef {import("./validate").JSONSchema6} JSONSchema6 */
/** @typedef {import("./validate").JSONSchema7} JSONSchema7 */
/** @typedef {import("./validate").ExtendedSchema} ExtendedSchema */
/** @typedef {import("./validate").ValidationErrorConfiguration} ValidationErrorConfiguration */
const {
validate,
ValidationError,
enableValidation,
disableValidation,
needValidate
} = require("./validate");
module.exports = {
validate,
ValidationError,
enableValidation,
disableValidation,
needValidate
};

View File

@@ -0,0 +1,83 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/** @typedef {import("ajv").default} Ajv */
/** @typedef {import("ajv").SchemaValidateFunction} SchemaValidateFunction */
/** @typedef {import("ajv").AnySchemaObject} AnySchemaObject */
/** @typedef {import("../validate").SchemaUtilErrorObject} SchemaUtilErrorObject */
/**
* @param {string} message message
* @param {object} schema schema
* @param {string} data data
* @returns {SchemaUtilErrorObject} error object
*/
function errorMessage(message, schema, data) {
return {
dataPath: undefined,
// @ts-expect-error
schemaPath: undefined,
keyword: "absolutePath",
params: {
absolutePath: data
},
message,
parentSchema: schema
};
}
/**
* @param {boolean} shouldBeAbsolute true when should be absolute path, otherwise false
* @param {object} schema schema
* @param {string} data data
* @returns {SchemaUtilErrorObject} error object
*/
function getErrorFor(shouldBeAbsolute, schema, data) {
const message = shouldBeAbsolute ? `The provided value ${JSON.stringify(data)} is not an absolute path!` : `A relative path is expected. However, the provided value ${JSON.stringify(data)} is an absolute path!`;
return errorMessage(message, schema, data);
}
/**
* @param {Ajv} ajv ajv
* @returns {Ajv} configured ajv
*/
function addAbsolutePathKeyword(ajv) {
ajv.addKeyword({
keyword: "absolutePath",
type: "string",
errors: true,
/**
* @param {boolean} schema schema
* @param {AnySchemaObject} parentSchema parent schema
* @returns {SchemaValidateFunction} validate function
*/
compile(schema, parentSchema) {
/** @type {SchemaValidateFunction} */
const callback = data => {
let passes = true;
const isExclamationMarkPresent = data.includes("!");
if (isExclamationMarkPresent) {
callback.errors = [errorMessage(`The provided value ${JSON.stringify(data)} contains exclamation mark (!) which is not allowed because it's reserved for loader syntax.`, parentSchema, data)];
passes = false;
}
// ?:[A-Za-z]:\\ - Windows absolute path
// \\\\ - Windows network absolute path
// \/ - Unix-like OS absolute path
const isCorrectAbsolutePath = schema === /^(?:[A-Za-z]:(\\|\/)|\\\\|\/)/.test(data);
if (!isCorrectAbsolutePath) {
callback.errors = [getErrorFor(schema, parentSchema, data)];
passes = false;
}
return passes;
};
callback.errors = [];
return callback;
}
});
return ajv;
}
var _default = exports.default = addAbsolutePathKeyword;

167
node_modules/schema-utils/dist/keywords/limit.js generated vendored Normal file
View File

@@ -0,0 +1,167 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/** @typedef {import("ajv").default} Ajv */
/** @typedef {import("ajv").Code} Code */
/** @typedef {import("ajv").Name} Name */
/** @typedef {import("ajv").KeywordErrorDefinition} KeywordErrorDefinition */
/**
* @param {Ajv} ajv ajv
* @returns {Ajv} ajv with limit keyword
*/
function addLimitKeyword(ajv) {
const {
_,
str,
KeywordCxt,
nil,
Name
} = require("ajv");
/**
* @param {Code | Name} nameOrCode name or code
* @returns {Code | Name} name or code
*/
function par(nameOrCode) {
return nameOrCode instanceof Name ? nameOrCode : _`(${nameOrCode})`;
}
/**
* @param {Code} op op
* @returns {(xValue: Code, yValue: Code) => Code} code
*/
function mappend(op) {
return (xValue, yValue) => xValue === nil ? yValue : yValue === nil ? xValue : _`${par(xValue)} ${op} ${par(yValue)}`;
}
const orCode = mappend(_`||`);
// boolean OR (||) expression with the passed arguments
/**
* @param {...Code} args args
* @returns {Code} code
*/
function or(...args) {
return args.reduce(orCode);
}
/**
* @param {string | number} key key
* @returns {Code} property
*/
function getProperty(key) {
return _`[${key}]`;
}
const keywords = {
formatMaximum: {
okStr: "<=",
ok: _`<=`,
fail: _`>`
},
formatMinimum: {
okStr: ">=",
ok: _`>=`,
fail: _`<`
},
formatExclusiveMaximum: {
okStr: "<",
ok: _`<`,
fail: _`>=`
},
formatExclusiveMinimum: {
okStr: ">",
ok: _`>`,
fail: _`<=`
}
};
/** @type {KeywordErrorDefinition} */
const error = {
message: ({
keyword,
schemaCode
}) => str`should be ${keywords[(/** @type {keyof typeof keywords} */keyword)].okStr} ${schemaCode}`,
params: ({
keyword,
schemaCode
}) => _`{comparison: ${keywords[(/** @type {keyof typeof keywords} */keyword)].okStr}, limit: ${schemaCode}}`
};
for (const keyword of Object.keys(keywords)) {
ajv.addKeyword({
keyword,
type: "string",
schemaType: keyword.startsWith("formatExclusive") ? ["string", "boolean"] : ["string", "number"],
$data: true,
error,
code(cxt) {
const {
gen,
data,
schemaCode,
keyword,
it
} = cxt;
const {
opts,
self
} = it;
if (!opts.validateFormats) return;
const fCxt = new KeywordCxt(it,
// eslint-disable-next-line jsdoc/no-restricted-syntax
/** @type {any} */
self.RULES.all.format.definition, "format");
/**
* @param {Name} fmt fmt
* @returns {Code} code
*/
function compareCode(fmt) {
return _`${fmt}.compare(${data}, ${schemaCode}) ${keywords[(/** @type {keyof typeof keywords} */keyword)].fail} 0`;
}
/**
* @returns {void}
*/
function validate$DataFormat() {
const fmts = gen.scopeValue("formats", {
ref: self.formats,
code: opts.code.formats
});
const fmt = gen.const("fmt", _`${fmts}[${fCxt.schemaCode}]`);
cxt.fail$data(or(_`typeof ${fmt} != "object"`, _`${fmt} instanceof RegExp`, _`typeof ${fmt}.compare != "function"`, compareCode(fmt)));
}
/**
* @returns {void}
*/
function validateFormat() {
const format = fCxt.schema;
const fmtDef = self.formats[format];
if (!fmtDef || fmtDef === true) {
return;
}
if (typeof fmtDef !== "object" || fmtDef instanceof RegExp || typeof fmtDef.compare !== "function") {
throw new Error(`"${keyword}": format "${format}" does not define "compare" function`);
}
const fmt = gen.scopeValue("formats", {
key: format,
ref: fmtDef,
code: opts.code.formats ? _`${opts.code.formats}${getProperty(format)}` : undefined
});
cxt.fail$data(compareCode(fmt));
}
if (fCxt.$data) {
validate$DataFormat();
} else {
validateFormat();
}
},
dependencies: ["format"]
});
}
return ajv;
}
var _default = exports.default = addLimitKeyword;

View File

@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/** @typedef {import("ajv").default} Ajv */
/** @typedef {import("ajv").SchemaValidateFunction} SchemaValidateFunction */
/** @typedef {import("ajv").AnySchemaObject} AnySchemaObject */
/** @typedef {import("ajv").ValidateFunction} ValidateFunction */
/**
* @param {Ajv} ajv ajv
* @returns {Ajv} configured ajv
*/
function addUndefinedAsNullKeyword(ajv) {
ajv.addKeyword({
keyword: "undefinedAsNull",
before: "enum",
modifying: true,
/** @type {SchemaValidateFunction} */
validate(kwVal, data, metadata, dataCxt) {
if (kwVal && dataCxt && metadata && typeof metadata.enum !== "undefined") {
const idx = dataCxt.parentDataProperty;
if (typeof dataCxt.parentData[idx] === "undefined") {
dataCxt.parentData[dataCxt.parentDataProperty] = null;
}
}
return true;
}
});
return ajv;
}
var _default = exports.default = addUndefinedAsNullKeyword;

143
node_modules/schema-utils/dist/util/Range.js generated vendored Normal file
View File

@@ -0,0 +1,143 @@
"use strict";
/**
* @typedef {[number, boolean]} RangeValue
*/
/**
* @callback RangeValueCallback
* @param {RangeValue} rangeValue
* @returns {boolean}
*/
class Range {
/**
* @param {"left" | "right"} side side
* @param {boolean} exclusive exclusive
* @returns {">" | ">=" | "<" | "<="} operator
*/
static getOperator(side, exclusive) {
if (side === "left") {
return exclusive ? ">" : ">=";
}
return exclusive ? "<" : "<=";
}
/**
* @param {number} value value
* @param {boolean} logic is not logic applied
* @param {boolean} exclusive is range exclusive
* @returns {string} formatted right
*/
static formatRight(value, logic, exclusive) {
if (logic === false) {
return Range.formatLeft(value, !logic, !exclusive);
}
return `should be ${Range.getOperator("right", exclusive)} ${value}`;
}
/**
* @param {number} value value
* @param {boolean} logic is not logic applied
* @param {boolean} exclusive is range exclusive
* @returns {string} formatted left
*/
static formatLeft(value, logic, exclusive) {
if (logic === false) {
return Range.formatRight(value, !logic, !exclusive);
}
return `should be ${Range.getOperator("left", exclusive)} ${value}`;
}
/**
* @param {number} start left side value
* @param {number} end right side value
* @param {boolean} startExclusive is range exclusive from left side
* @param {boolean} endExclusive is range exclusive from right side
* @param {boolean} logic is not logic applied
* @returns {string} formatted range
*/
static formatRange(start, end, startExclusive, endExclusive, logic) {
let result = "should be";
result += ` ${Range.getOperator(logic ? "left" : "right", logic ? startExclusive : !startExclusive)} ${start} `;
result += logic ? "and" : "or";
result += ` ${Range.getOperator(logic ? "right" : "left", logic ? endExclusive : !endExclusive)} ${end}`;
return result;
}
/**
* @param {Array<RangeValue>} values values
* @param {boolean} logic is not logic applied
* @returns {RangeValue} computed value and it's exclusive flag
*/
static getRangeValue(values, logic) {
let minMax = logic ? Infinity : -Infinity;
let j = -1;
const predicate = logic ? /** @type {RangeValueCallback} */
([value]) => value <= minMax : /** @type {RangeValueCallback} */
([value]) => value >= minMax;
for (let i = 0; i < values.length; i++) {
if (predicate(values[i])) {
[minMax] = values[i];
j = i;
}
}
if (j > -1) {
return values[j];
}
return [Infinity, true];
}
constructor() {
/** @type {Array<RangeValue>} */
this._left = [];
/** @type {Array<RangeValue>} */
this._right = [];
}
/**
* @param {number} value value
* @param {boolean=} exclusive true when exclusive, otherwise false
*/
left(value, exclusive = false) {
this._left.push([value, exclusive]);
}
/**
* @param {number} value value
* @param {boolean=} exclusive true when exclusive, otherwise false
*/
right(value, exclusive = false) {
this._right.push([value, exclusive]);
}
/**
* @param {boolean} logic is not logic applied
* @returns {string} "smart" range string representation
*/
format(logic = true) {
const [start, leftExclusive] = Range.getRangeValue(this._left, logic);
const [end, rightExclusive] = Range.getRangeValue(this._right, !logic);
if (!Number.isFinite(start) && !Number.isFinite(end)) {
return "";
}
const realStart = leftExclusive ? start + 1 : start;
const realEnd = rightExclusive ? end - 1 : end;
// e.g. 5 < x < 7, 5 < x <= 6, 6 <= x <= 6
if (realStart === realEnd) {
return `should be ${logic ? "" : "!"}= ${realStart}`;
}
// e.g. 4 < x < ∞
if (Number.isFinite(start) && !Number.isFinite(end)) {
return Range.formatLeft(start, logic, leftExclusive);
}
// e.g. ∞ < x < 4
if (!Number.isFinite(start) && Number.isFinite(end)) {
return Range.formatRight(end, logic, rightExclusive);
}
return Range.formatRange(start, end, leftExclusive, rightExclusive, logic);
}
}
module.exports = Range;

85
node_modules/schema-utils/dist/util/hints.js generated vendored Normal file
View File

@@ -0,0 +1,85 @@
"use strict";
const Range = require("./Range");
/** @typedef {import("../validate").Schema} Schema */
/**
* @param {Schema} schema schema
* @param {boolean} logic logic
* @returns {string[]} array of hints
*/
module.exports.stringHints = function stringHints(schema, logic) {
const hints = [];
let type = "string";
const currentSchema = {
...schema
};
if (!logic) {
const tmpLength = currentSchema.minLength;
const tmpFormat = currentSchema.formatMinimum;
currentSchema.minLength = currentSchema.maxLength;
currentSchema.maxLength = tmpLength;
currentSchema.formatMinimum = currentSchema.formatMaximum;
currentSchema.formatMaximum = tmpFormat;
}
if (typeof currentSchema.minLength === "number") {
if (currentSchema.minLength === 1) {
type = "non-empty string";
} else {
const length = Math.max(currentSchema.minLength - 1, 0);
hints.push(`should be longer than ${length} character${length > 1 ? "s" : ""}`);
}
}
if (typeof currentSchema.maxLength === "number") {
if (currentSchema.maxLength === 0) {
type = "empty string";
} else {
const length = currentSchema.maxLength + 1;
hints.push(`should be shorter than ${length} character${length > 1 ? "s" : ""}`);
}
}
if (currentSchema.pattern) {
hints.push(`should${logic ? "" : " not"} match pattern ${JSON.stringify(currentSchema.pattern)}`);
}
if (currentSchema.format) {
hints.push(`should${logic ? "" : " not"} match format ${JSON.stringify(currentSchema.format)}`);
}
if (currentSchema.formatMinimum) {
hints.push(`should be ${currentSchema.formatExclusiveMinimum ? ">" : ">="} ${JSON.stringify(currentSchema.formatMinimum)}`);
}
if (currentSchema.formatMaximum) {
hints.push(`should be ${currentSchema.formatExclusiveMaximum ? "<" : "<="} ${JSON.stringify(currentSchema.formatMaximum)}`);
}
return [type, ...hints];
};
/**
* @param {Schema} schema schema
* @param {boolean} logic logic
* @returns {string[]} array of hints
*/
module.exports.numberHints = function numberHints(schema, logic) {
const hints = [schema.type === "integer" ? "integer" : "number"];
const range = new Range();
if (typeof schema.minimum === "number") {
range.left(schema.minimum);
}
if (typeof schema.exclusiveMinimum === "number") {
range.left(schema.exclusiveMinimum, true);
}
if (typeof schema.maximum === "number") {
range.right(schema.maximum);
}
if (typeof schema.exclusiveMaximum === "number") {
range.right(schema.exclusiveMaximum, true);
}
const rangeFormat = range.format(logic);
if (rangeFormat) {
hints.push(rangeFormat);
}
if (typeof schema.multipleOf === "number") {
hints.push(`should${logic ? "" : " not"} be multiple of ${schema.multipleOf}`);
}
return hints;
};

34
node_modules/schema-utils/dist/util/memorize.js generated vendored Normal file
View File

@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* @template T
* @typedef {() => T} FunctionReturning
*/
/**
* @template T
* @param {FunctionReturning<T>} fn memorized function
* @returns {FunctionReturning<T>} new function
*/
const memoize = fn => {
let cache = false;
/** @type {T} */
let result;
return () => {
if (cache) {
return result;
}
result = fn();
cache = true;
// Allow to clean up memory for fn
// and all dependent resources
/** @type {FunctionReturning<T> | undefined} */
fn = undefined;
return result;
};
};
var _default = exports.default = memoize;

215
node_modules/schema-utils/dist/validate.js generated vendored Normal file
View File

@@ -0,0 +1,215 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "ValidationError", {
enumerable: true,
get: function () {
return _ValidationError.default;
}
});
exports.disableValidation = disableValidation;
exports.enableValidation = enableValidation;
exports.needValidate = needValidate;
exports.validate = validate;
var _ValidationError = _interopRequireDefault(require("./ValidationError"));
var _memorize = _interopRequireDefault(require("./util/memorize"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const getAjv = (0, _memorize.default)(() => {
// Use CommonJS require for ajv libs so TypeScript consumers aren't locked into esModuleInterop (see #110).
const Ajv = require("ajv").default;
const ajvKeywords = require("ajv-keywords").default;
const addFormats = require("ajv-formats").default;
/**
* @type {Ajv}
*/
const ajv = new Ajv({
strict: false,
allErrors: true,
verbose: true,
$data: true
});
ajvKeywords(ajv, ["instanceof", "patternRequired"]);
// TODO set `{ keywords: true }` for the next major release and remove `keywords/limit.js`
addFormats(ajv, {
keywords: false
});
// Custom keywords
const addAbsolutePathKeyword = require("./keywords/absolutePath").default;
addAbsolutePathKeyword(ajv);
const addLimitKeyword = require("./keywords/limit").default;
addLimitKeyword(ajv);
const addUndefinedAsNullKeyword = require("./keywords/undefinedAsNull").default;
addUndefinedAsNullKeyword(ajv);
return ajv;
});
/** @typedef {import("json-schema").JSONSchema4} JSONSchema4 */
/** @typedef {import("json-schema").JSONSchema6} JSONSchema6 */
/** @typedef {import("json-schema").JSONSchema7} JSONSchema7 */
/** @typedef {import("ajv").ErrorObject} ErrorObject */
/**
* @typedef {object} ExtendedSchema
* @property {(string | number)=} formatMinimum format minimum
* @property {(string | number)=} formatMaximum format maximum
* @property {(string | boolean)=} formatExclusiveMinimum format exclusive minimum
* @property {(string | boolean)=} formatExclusiveMaximum format exclusive maximum
* @property {string=} link link
* @property {boolean=} undefinedAsNull undefined will be resolved as null
*/
// TODO remove me in the next major release
/** @typedef {ExtendedSchema} Extend */
/** @typedef {(JSONSchema4 | JSONSchema6 | JSONSchema7) & ExtendedSchema} Schema */
/** @typedef {ErrorObject & { children?: Array<ErrorObject> }} SchemaUtilErrorObject */
/**
* @callback PostFormatter
* @param {string} formattedError
* @param {SchemaUtilErrorObject} error
* @returns {string}
*/
/**
* @typedef {object} ValidationErrorConfiguration
* @property {string=} name name
* @property {string=} baseDataPath base data path
* @property {PostFormatter=} postFormatter post formatter
*/
/**
* @param {SchemaUtilErrorObject} error error
* @param {number} idx idx
* @returns {SchemaUtilErrorObject} error object with idx
*/
function applyPrefix(error, idx) {
error.instancePath = `[${idx}]${error.instancePath}`;
if (error.children) {
for (const err of error.children) applyPrefix(err, idx);
}
return error;
}
let skipValidation = false;
// We use `process.env.SKIP_VALIDATION` because you can have multiple `schema-utils` with different version,
// so we want to disable it globally, `process.env` doesn't supported by browsers, so we have the local `skipValidation` variables
// Enable validation
/**
* @returns {void}
*/
function enableValidation() {
skipValidation = false;
// Disable validation for any versions
if (process && process.env) {
process.env.SKIP_VALIDATION = "n";
}
}
// Disable validation
/**
* @returns {void}
*/
function disableValidation() {
skipValidation = true;
if (process && process.env) {
process.env.SKIP_VALIDATION = "y";
}
}
// Check if we need to confirm
/**
* @returns {boolean} true when need validate, otherwise false
*/
function needValidate() {
if (skipValidation) {
return false;
}
if (process && process.env && process.env.SKIP_VALIDATION) {
const value = process.env.SKIP_VALIDATION.trim();
if (/^(?:y|yes|true|1|on)$/i.test(value)) {
return false;
}
if (/^(?:n|no|false|0|off)$/i.test(value)) {
return true;
}
}
return true;
}
/**
* @param {Array<ErrorObject>} errors array of error objects
* @returns {Array<SchemaUtilErrorObject>} filtered array of objects
*/
function filterErrors(errors) {
/** @type {Array<SchemaUtilErrorObject>} */
let newErrors = [];
for (const error of (/** @type {Array<SchemaUtilErrorObject>} */errors)) {
const {
instancePath
} = error;
/** @type {Array<SchemaUtilErrorObject>} */
let children = [];
newErrors = newErrors.filter(oldError => {
if (oldError.instancePath.includes(instancePath)) {
if (oldError.children) {
children = [...children, ...oldError.children];
}
oldError.children = undefined;
children.push(oldError);
return false;
}
return true;
});
if (children.length) {
error.children = children;
}
newErrors.push(error);
}
return newErrors;
}
/**
* @param {Schema} schema schema
* @param {Array<object> | object} options options
* @returns {Array<SchemaUtilErrorObject>} array of error objects
*/
function validateObject(schema, options) {
// Not need to cache, because `ajv@8` has built-in cache
const compiledSchema = getAjv().compile(schema);
const valid = compiledSchema(options);
if (valid) return [];
return compiledSchema.errors ? filterErrors(compiledSchema.errors) : [];
}
/**
* @param {Schema} schema schema
* @param {Array<object> | object} options options
* @param {ValidationErrorConfiguration=} configuration configuration
* @returns {void}
*/
function validate(schema, options, configuration) {
if (!needValidate()) {
return;
}
let errors = [];
if (Array.isArray(options)) {
for (let i = 0; i <= options.length - 1; i++) {
errors.push(...validateObject(schema, options[i]).map(err => applyPrefix(err, i)));
}
} else {
errors = validateObject(schema, options);
}
if (errors.length > 0) {
throw new _ValidationError.default(errors, schema, configuration);
}
}

View File

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

View File

@@ -0,0 +1,123 @@
# ajv-formats
JSON Schema formats for Ajv
[![Build Status](https://travis-ci.org/ajv-validator/ajv-formats.svg?branch=master)](https://travis-ci.org/ajv-validator/ajv-formats)
[![npm](https://img.shields.io/npm/v/ajv-formats.svg)](https://www.npmjs.com/package/ajv-formats)
[![Gitter](https://img.shields.io/gitter/room/ajv-validator/ajv.svg)](https://gitter.im/ajv-validator/ajv)
[![GitHub Sponsors](https://img.shields.io/badge/$-sponsors-brightgreen)](https://github.com/sponsors/epoberezkin)
## Usage
```javascript
// ESM/TypeScript import
import Ajv from "ajv"
import addFormats from "ajv-formats"
// Node.js require:
const Ajv = require("ajv")
const addFormats = require("ajv-formats")
const ajv = new Ajv()
addFormats(ajv)
```
## Formats
The package defines these formats:
- _date_: full-date according to [RFC3339](http://tools.ietf.org/html/rfc3339#section-5.6).
- _time_: time with optional time-zone.
- _date-time_: date-time from the same source (time-zone is mandatory).
- _duration_: duration from [RFC3339](https://tools.ietf.org/html/rfc3339#appendix-A)
- _uri_: full URI.
- _uri-reference_: URI reference, including full and relative URIs.
- _uri-template_: URI template according to [RFC6570](https://tools.ietf.org/html/rfc6570)
- _url_ (deprecated): [URL record](https://url.spec.whatwg.org/#concept-url).
- _email_: email address.
- _hostname_: host name according to [RFC1034](http://tools.ietf.org/html/rfc1034#section-3.5).
- _ipv4_: IP address v4.
- _ipv6_: IP address v6.
- _regex_: tests whether a string is a valid regular expression by passing it to RegExp constructor.
- _uuid_: Universally Unique IDentifier according to [RFC4122](http://tools.ietf.org/html/rfc4122).
- _json-pointer_: JSON-pointer according to [RFC6901](https://tools.ietf.org/html/rfc6901).
- _relative-json-pointer_: relative JSON-pointer according to [this draft](http://tools.ietf.org/html/draft-luff-relative-json-pointer-00).
- _byte_: base64 encoded data according to the [openApi 3.0.0 specification](https://spec.openapis.org/oas/v3.0.0#data-types)
- _int32_: signed 32 bits integer according to the [openApi 3.0.0 specification](https://spec.openapis.org/oas/v3.0.0#data-types)
- _int64_: signed 64 bits according to the [openApi 3.0.0 specification](https://spec.openapis.org/oas/v3.0.0#data-types)
- _float_: float according to the [openApi 3.0.0 specification](https://spec.openapis.org/oas/v3.0.0#data-types)
- _double_: double according to the [openApi 3.0.0 specification](https://spec.openapis.org/oas/v3.0.0#data-types)
- _password_: password string according to the [openApi 3.0.0 specification](https://spec.openapis.org/oas/v3.0.0#data-types)
- _binary_: binary string according to the [openApi 3.0.0 specification](https://spec.openapis.org/oas/v3.0.0#data-types)
See regular expressions used for format validation and the sources that were used in [formats.ts](https://github.com/ajv-validator/ajv-formats/blob/master/src/formats.ts).
**Please note**: JSON Schema draft-07 also defines formats `iri`, `iri-reference`, `idn-hostname` and `idn-email` for URLs, hostnames and emails with international characters. These formats are available in [ajv-formats-draft2019](https://github.com/luzlab/ajv-formats-draft2019) plugin.
## Keywords to compare values: `formatMaximum` / `formatMinimum` and `formatExclusiveMaximum` / `formatExclusiveMinimum`
These keywords allow to define minimum/maximum constraints when the format keyword defines ordering (`compare` function in format definition).
These keywords are added to ajv instance when ajv-formats is used without options or with option `keywords: true`.
These keywords apply only to strings. If the data is not a string, the validation succeeds.
The value of keywords `formatMaximum`/`formatMinimum` and `formatExclusiveMaximum`/`formatExclusiveMinimum` should be a string or [\$data reference](https://github.com/ajv-validator/ajv/blob/master/docs/validation.md#data-reference). This value is the maximum (minimum) allowed value for the data to be valid as determined by `format` keyword. If `format` keyword is not present schema compilation will throw exception.
When these keyword are added, they also add comparison functions to formats `"date"`, `"time"` and `"date-time"`. User-defined formats also can have comparison functions. See [addFormat](https://github.com/ajv-validator/ajv/blob/master/docs/api.md#api-addformat) method.
```javascript
require("ajv-formats")(ajv)
const schema = {
type: "string",
format: "date",
formatMinimum: "2016-02-06",
formatExclusiveMaximum: "2016-12-27",
}
const validDataList = ["2016-02-06", "2016-12-26"]
const invalidDataList = ["2016-02-05", "2016-12-27", "abc"]
```
## Options
Options can be passed via the second parameter. Options value can be
1. The list of format names that will be added to ajv instance:
```javascript
addFormats(ajv, ["date", "time"])
```
**Please note**: when ajv encounters an undefined format it throws exception (unless ajv instance was configured with `strict: false` option). To allow specific undefined formats they have to be passed to ajv instance via `formats` option with `true` value:
```javascript
const ajv = new Ajv((formats: {date: true, time: true})) // to ignore "date" and "time" formats in schemas.
```
2. Format validation mode (default is `"full"`) with optional list of format names and `keywords` option to add additional format comparison keywords:
```javascript
addFormats(ajv, {mode: "fast"})
```
or
```javascript
addFormats(ajv, {mode: "fast", formats: ["date", "time"], keywords: true})
```
In `"fast"` mode the following formats are simplified: `"date"`, `"time"`, `"date-time"`, `"uri"`, `"uri-reference"`, `"email"`. For example `"date"`, `"time"` and `"date-time"` do not validate ranges in `"fast"` mode, only string structure, and other formats have simplified regular expressions.
## Tests
```bash
npm install
git submodule update --init
npm test
```
## License
[MIT](https://github.com/ajv-validator/ajv-formats/blob/master/LICENSE)

View File

@@ -0,0 +1,9 @@
import type { Format } from "ajv";
export declare type FormatMode = "fast" | "full";
export declare type FormatName = "date" | "time" | "date-time" | "duration" | "uri" | "uri-reference" | "uri-template" | "url" | "email" | "hostname" | "ipv4" | "ipv6" | "regex" | "uuid" | "json-pointer" | "json-pointer-uri-fragment" | "relative-json-pointer" | "byte" | "int32" | "int64" | "float" | "double" | "password" | "binary";
export declare type DefinedFormats = {
[key in FormatName]: Format;
};
export declare const fullFormats: DefinedFormats;
export declare const fastFormats: DefinedFormats;
export declare const formatNames: FormatName[];

View File

@@ -0,0 +1,173 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatNames = exports.fastFormats = exports.fullFormats = void 0;
function fmtDef(validate, compare) {
return { validate, compare };
}
exports.fullFormats = {
// date: http://tools.ietf.org/html/rfc3339#section-5.6
date: fmtDef(date, compareDate),
// date-time: http://tools.ietf.org/html/rfc3339#section-5.6
time: fmtDef(time, compareTime),
"date-time": fmtDef(date_time, compareDateTime),
// duration: https://tools.ietf.org/html/rfc3339#appendix-A
duration: /^P(?!$)((\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?|(\d+W)?)$/,
uri,
"uri-reference": /^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'"()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i,
// uri-template: https://tools.ietf.org/html/rfc6570
"uri-template": /^(?:(?:[^\x00-\x20"'<>%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i,
// For the source: https://gist.github.com/dperini/729294
// For test cases: https://mathiasbynens.be/demo/url-regex
url: /^(?:https?|ftp):\/\/(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u{00a1}-\u{ffff}]+-)*[a-z0-9\u{00a1}-\u{ffff}]+)(?:\.(?:[a-z0-9\u{00a1}-\u{ffff}]+-)*[a-z0-9\u{00a1}-\u{ffff}]+)*(?:\.(?:[a-z\u{00a1}-\u{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iu,
email: /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i,
hostname: /^(?=.{1,253}\.?$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*\.?$/i,
// optimized https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9780596802837/ch07s16.html
ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/,
ipv6: /^((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))$/i,
regex,
// uuid: http://tools.ietf.org/html/rfc4122
uuid: /^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i,
// JSON-pointer: https://tools.ietf.org/html/rfc6901
// uri fragment: https://tools.ietf.org/html/rfc3986#appendix-A
"json-pointer": /^(?:\/(?:[^~/]|~0|~1)*)*$/,
"json-pointer-uri-fragment": /^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i,
// relative JSON-pointer: http://tools.ietf.org/html/draft-luff-relative-json-pointer-00
"relative-json-pointer": /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/,
// the following formats are used by the openapi specification: https://spec.openapis.org/oas/v3.0.0#data-types
// byte: https://github.com/miguelmota/is-base64
byte,
// signed 32 bit integer
int32: { type: "number", validate: validateInt32 },
// signed 64 bit integer
int64: { type: "number", validate: validateInt64 },
// C-type float
float: { type: "number", validate: validateNumber },
// C-type double
double: { type: "number", validate: validateNumber },
// hint to the UI to hide input strings
password: true,
// unchecked string payload
binary: true,
};
exports.fastFormats = {
...exports.fullFormats,
date: fmtDef(/^\d\d\d\d-[0-1]\d-[0-3]\d$/, compareDate),
time: fmtDef(/^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)?$/i, compareTime),
"date-time": fmtDef(/^\d\d\d\d-[0-1]\d-[0-3]\d[t\s](?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)$/i, compareDateTime),
// uri: https://github.com/mafintosh/is-my-json-valid/blob/master/formats.js
uri: /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/)?[^\s]*$/i,
"uri-reference": /^(?:(?:[a-z][a-z0-9+\-.]*:)?\/?\/)?(?:[^\\\s#][^\s#]*)?(?:#[^\\\s]*)?$/i,
// email (sources from jsen validator):
// http://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address#answer-8829363
// http://www.w3.org/TR/html5/forms.html#valid-e-mail-address (search for 'wilful violation')
email: /^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i,
};
exports.formatNames = Object.keys(exports.fullFormats);
function isLeapYear(year) {
// https://tools.ietf.org/html/rfc3339#appendix-C
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
}
const DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
const DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
function date(str) {
// full-date from http://tools.ietf.org/html/rfc3339#section-5.6
const matches = DATE.exec(str);
if (!matches)
return false;
const year = +matches[1];
const month = +matches[2];
const day = +matches[3];
return (month >= 1 &&
month <= 12 &&
day >= 1 &&
day <= (month === 2 && isLeapYear(year) ? 29 : DAYS[month]));
}
function compareDate(d1, d2) {
if (!(d1 && d2))
return undefined;
if (d1 > d2)
return 1;
if (d1 < d2)
return -1;
return 0;
}
const TIME = /^(\d\d):(\d\d):(\d\d)(\.\d+)?(z|[+-]\d\d(?::?\d\d)?)?$/i;
function time(str, withTimeZone) {
const matches = TIME.exec(str);
if (!matches)
return false;
const hour = +matches[1];
const minute = +matches[2];
const second = +matches[3];
const timeZone = matches[5];
return (((hour <= 23 && minute <= 59 && second <= 59) ||
(hour === 23 && minute === 59 && second === 60)) &&
(!withTimeZone || timeZone !== ""));
}
function compareTime(t1, t2) {
if (!(t1 && t2))
return undefined;
const a1 = TIME.exec(t1);
const a2 = TIME.exec(t2);
if (!(a1 && a2))
return undefined;
t1 = a1[1] + a1[2] + a1[3] + (a1[4] || "");
t2 = a2[1] + a2[2] + a2[3] + (a2[4] || "");
if (t1 > t2)
return 1;
if (t1 < t2)
return -1;
return 0;
}
const DATE_TIME_SEPARATOR = /t|\s/i;
function date_time(str) {
// http://tools.ietf.org/html/rfc3339#section-5.6
const dateTime = str.split(DATE_TIME_SEPARATOR);
return dateTime.length === 2 && date(dateTime[0]) && time(dateTime[1], true);
}
function compareDateTime(dt1, dt2) {
if (!(dt1 && dt2))
return undefined;
const [d1, t1] = dt1.split(DATE_TIME_SEPARATOR);
const [d2, t2] = dt2.split(DATE_TIME_SEPARATOR);
const res = compareDate(d1, d2);
if (res === undefined)
return undefined;
return res || compareTime(t1, t2);
}
const NOT_URI_FRAGMENT = /\/|:/;
const URI = /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i;
function uri(str) {
// http://jmrware.com/articles/2009/uri_regexp/URI_regex.html + optional protocol + required "."
return NOT_URI_FRAGMENT.test(str) && URI.test(str);
}
const BYTE = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/gm;
function byte(str) {
BYTE.lastIndex = 0;
return BYTE.test(str);
}
const MIN_INT32 = -(2 ** 31);
const MAX_INT32 = 2 ** 31 - 1;
function validateInt32(value) {
return Number.isInteger(value) && value <= MAX_INT32 && value >= MIN_INT32;
}
function validateInt64(value) {
// JSON and javascript max Int is 2**53, so any int that passes isInteger is valid for Int64
return Number.isInteger(value);
}
function validateNumber() {
return true;
}
const Z_ANCHOR = /[^\\]\\Z/;
function regex(str) {
if (Z_ANCHOR.test(str))
return false;
try {
new RegExp(str);
return true;
}
catch (e) {
return false;
}
}
//# sourceMappingURL=formats.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,15 @@
import { FormatMode, FormatName } from "./formats";
import type { Plugin, Format } from "ajv";
export { FormatMode, FormatName } from "./formats";
export { LimitFormatError } from "./limit";
export interface FormatOptions {
mode?: FormatMode;
formats?: FormatName[];
keywords?: boolean;
}
export declare type FormatsPluginOptions = FormatName[] | FormatOptions;
export interface FormatsPlugin extends Plugin<FormatsPluginOptions> {
get: (format: FormatName, mode?: FormatMode) => Format;
}
declare const formatsPlugin: FormatsPlugin;
export default formatsPlugin;

View File

@@ -0,0 +1,37 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const formats_1 = require("./formats");
const limit_1 = require("./limit");
const codegen_1 = require("ajv/dist/compile/codegen");
const fullName = new codegen_1.Name("fullFormats");
const fastName = new codegen_1.Name("fastFormats");
const formatsPlugin = (ajv, opts = { keywords: true }) => {
if (Array.isArray(opts)) {
addFormats(ajv, opts, formats_1.fullFormats, fullName);
return ajv;
}
const [formats, exportName] = opts.mode === "fast" ? [formats_1.fastFormats, fastName] : [formats_1.fullFormats, fullName];
const list = opts.formats || formats_1.formatNames;
addFormats(ajv, list, formats, exportName);
if (opts.keywords)
limit_1.default(ajv);
return ajv;
};
formatsPlugin.get = (name, mode = "full") => {
const formats = mode === "fast" ? formats_1.fastFormats : formats_1.fullFormats;
const f = formats[name];
if (!f)
throw new Error(`Unknown format "${name}"`);
return f;
};
function addFormats(ajv, list, fs, exportName) {
var _a;
var _b;
(_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : (_b.formats = codegen_1._ `require("ajv-formats/dist/formats").${exportName}`);
for (const f of list)
ajv.addFormat(f, fs[f]);
}
module.exports = exports = formatsPlugin;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = formatsPlugin;
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,uCAOkB;AAClB,mCAAiC;AAGjC,sDAAgD;AAgBhD,MAAM,QAAQ,GAAG,IAAI,cAAI,CAAC,aAAa,CAAC,CAAA;AACxC,MAAM,QAAQ,GAAG,IAAI,cAAI,CAAC,aAAa,CAAC,CAAA;AAExC,MAAM,aAAa,GAAkB,CACnC,GAAQ,EACR,OAA6B,EAAC,QAAQ,EAAE,IAAI,EAAC,EACxC,EAAE;IACP,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;QACvB,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,qBAAW,EAAE,QAAQ,CAAC,CAAA;QAC5C,OAAO,GAAG,CAAA;KACX;IACD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GACzB,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,qBAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,qBAAW,EAAE,QAAQ,CAAC,CAAA;IAC1E,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,IAAI,qBAAW,CAAA;IACxC,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAA;IAC1C,IAAI,IAAI,CAAC,QAAQ;QAAE,eAAW,CAAC,GAAG,CAAC,CAAA;IACnC,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA;AAED,aAAa,CAAC,GAAG,GAAG,CAAC,IAAgB,EAAE,OAAmB,MAAM,EAAU,EAAE;IAC1E,MAAM,OAAO,GAAG,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,qBAAW,CAAC,CAAC,CAAC,qBAAW,CAAA;IAC3D,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvB,IAAI,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,GAAG,CAAC,CAAA;IACnD,OAAO,CAAC,CAAA;AACV,CAAC,CAAA;AAED,SAAS,UAAU,CAAC,GAAQ,EAAE,IAAkB,EAAE,EAAkB,EAAE,UAAgB;;;IACpF,YAAA,GAAG,CAAC,IAAI,CAAC,IAAI,EAAC,OAAO,uCAAP,OAAO,GAAK,WAAC,CAAA,uCAAuC,UAAU,EAAE,EAAA;IAC9E,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;AAC/C,CAAC;AAED,MAAM,CAAC,OAAO,GAAG,OAAO,GAAG,aAAa,CAAA;AACxC,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,EAAC,KAAK,EAAE,IAAI,EAAC,CAAC,CAAA;AAE3D,kBAAe,aAAa,CAAA"}

View File

@@ -0,0 +1,10 @@
import type { Plugin, CodeKeywordDefinition, ErrorObject } from "ajv";
declare type Kwd = "formatMaximum" | "formatMinimum" | "formatExclusiveMaximum" | "formatExclusiveMinimum";
declare type Comparison = "<=" | ">=" | "<" | ">";
export declare type LimitFormatError = ErrorObject<Kwd, {
limit: string;
comparison: Comparison;
}>;
export declare const formatLimitDefinition: CodeKeywordDefinition;
declare const formatLimitPlugin: Plugin<undefined>;
export default formatLimitPlugin;

View File

@@ -0,0 +1,69 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatLimitDefinition = void 0;
const ajv_1 = require("ajv");
const codegen_1 = require("ajv/dist/compile/codegen");
const ops = codegen_1.operators;
const KWDs = {
formatMaximum: { okStr: "<=", ok: ops.LTE, fail: ops.GT },
formatMinimum: { okStr: ">=", ok: ops.GTE, fail: ops.LT },
formatExclusiveMaximum: { okStr: "<", ok: ops.LT, fail: ops.GTE },
formatExclusiveMinimum: { okStr: ">", ok: ops.GT, fail: ops.LTE },
};
const error = {
message: ({ keyword, schemaCode }) => codegen_1.str `should be ${KWDs[keyword].okStr} ${schemaCode}`,
params: ({ keyword, schemaCode }) => codegen_1._ `{comparison: ${KWDs[keyword].okStr}, limit: ${schemaCode}}`,
};
exports.formatLimitDefinition = {
keyword: Object.keys(KWDs),
type: "string",
schemaType: "string",
$data: true,
error,
code(cxt) {
const { gen, data, schemaCode, keyword, it } = cxt;
const { opts, self } = it;
if (!opts.validateFormats)
return;
const fCxt = new ajv_1.KeywordCxt(it, self.RULES.all.format.definition, "format");
if (fCxt.$data)
validate$DataFormat();
else
validateFormat();
function validate$DataFormat() {
const fmts = gen.scopeValue("formats", {
ref: self.formats,
code: opts.code.formats,
});
const fmt = gen.const("fmt", codegen_1._ `${fmts}[${fCxt.schemaCode}]`);
cxt.fail$data(codegen_1.or(codegen_1._ `typeof ${fmt} != "object"`, codegen_1._ `${fmt} instanceof RegExp`, codegen_1._ `typeof ${fmt}.compare != "function"`, compareCode(fmt)));
}
function validateFormat() {
const format = fCxt.schema;
const fmtDef = self.formats[format];
if (!fmtDef || fmtDef === true)
return;
if (typeof fmtDef != "object" ||
fmtDef instanceof RegExp ||
typeof fmtDef.compare != "function") {
throw new Error(`"${keyword}": format "${format}" does not define "compare" function`);
}
const fmt = gen.scopeValue("formats", {
key: format,
ref: fmtDef,
code: opts.code.formats ? codegen_1._ `${opts.code.formats}${codegen_1.getProperty(format)}` : undefined,
});
cxt.fail$data(compareCode(fmt));
}
function compareCode(fmt) {
return codegen_1._ `${fmt}.compare(${data}, ${schemaCode}) ${KWDs[keyword].fail} 0`;
}
},
dependencies: ["format"],
};
const formatLimitPlugin = (ajv) => {
ajv.addKeyword(exports.formatLimitDefinition);
return ajv;
};
exports.default = formatLimitPlugin;
//# sourceMappingURL=limit.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"limit.js","sourceRoot":"","sources":["../src/limit.ts"],"names":[],"mappings":";;;AAWA,6BAA8B;AAC9B,sDAA2E;AAM3E,MAAM,GAAG,GAAG,mBAAS,CAAA;AAErB,MAAM,IAAI,GAA4D;IACpE,aAAa,EAAE,EAAC,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,EAAC;IACvD,aAAa,EAAE,EAAC,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,EAAC;IACvD,sBAAsB,EAAE,EAAC,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,GAAG,EAAC;IAC/D,sBAAsB,EAAE,EAAC,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,GAAG,EAAC;CAChE,CAAA;AAID,MAAM,KAAK,GAA2B;IACpC,OAAO,EAAE,CAAC,EAAC,OAAO,EAAE,UAAU,EAAC,EAAE,EAAE,CAAC,aAAG,CAAA,aAAa,IAAI,CAAC,OAAc,CAAC,CAAC,KAAK,IAAI,UAAU,EAAE;IAC9F,MAAM,EAAE,CAAC,EAAC,OAAO,EAAE,UAAU,EAAC,EAAE,EAAE,CAChC,WAAC,CAAA,gBAAgB,IAAI,CAAC,OAAc,CAAC,CAAC,KAAK,YAAY,UAAU,GAAG;CACvE,CAAA;AAEY,QAAA,qBAAqB,GAA0B;IAC1D,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;IAC1B,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE,QAAQ;IACpB,KAAK,EAAE,IAAI;IACX,KAAK;IACL,IAAI,CAAC,GAAG;QACN,MAAM,EAAC,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,EAAC,GAAG,GAAG,CAAA;QAChD,MAAM,EAAC,IAAI,EAAE,IAAI,EAAC,GAAG,EAAE,CAAA;QACvB,IAAI,CAAC,IAAI,CAAC,eAAe;YAAE,OAAM;QAEjC,MAAM,IAAI,GAAG,IAAI,gBAAU,CAAC,EAAE,EAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAe,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;QACrF,IAAI,IAAI,CAAC,KAAK;YAAE,mBAAmB,EAAE,CAAA;;YAChC,cAAc,EAAE,CAAA;QAErB,SAAS,mBAAmB;YAC1B,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,CAAC,SAAS,EAAE;gBACrC,GAAG,EAAE,IAAI,CAAC,OAAO;gBACjB,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO;aACxB,CAAC,CAAA;YACF,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,WAAC,CAAA,GAAG,IAAI,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC,CAAA;YAC5D,GAAG,CAAC,SAAS,CACX,YAAE,CACA,WAAC,CAAA,UAAU,GAAG,cAAc,EAC5B,WAAC,CAAA,GAAG,GAAG,oBAAoB,EAC3B,WAAC,CAAA,UAAU,GAAG,wBAAwB,EACtC,WAAW,CAAC,GAAG,CAAC,CACjB,CACF,CAAA;QACH,CAAC;QAED,SAAS,cAAc;YACrB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAgB,CAAA;YACpC,MAAM,MAAM,GAA4B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;YAC5D,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,IAAI;gBAAE,OAAM;YACtC,IACE,OAAO,MAAM,IAAI,QAAQ;gBACzB,MAAM,YAAY,MAAM;gBACxB,OAAO,MAAM,CAAC,OAAO,IAAI,UAAU,EACnC;gBACA,MAAM,IAAI,KAAK,CAAC,IAAI,OAAO,cAAc,MAAM,sCAAsC,CAAC,CAAA;aACvF;YACD,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,SAAS,EAAE;gBACpC,GAAG,EAAE,MAAM;gBACX,GAAG,EAAE,MAAM;gBACX,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,WAAC,CAAA,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,qBAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;aACpF,CAAC,CAAA;YAEF,GAAG,CAAC,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAA;QACjC,CAAC;QAED,SAAS,WAAW,CAAC,GAAS;YAC5B,OAAO,WAAC,CAAA,GAAG,GAAG,YAAY,IAAI,KAAK,UAAU,KAAK,IAAI,CAAC,OAAc,CAAC,CAAC,IAAI,IAAI,CAAA;QACjF,CAAC;IACH,CAAC;IACD,YAAY,EAAE,CAAC,QAAQ,CAAC;CACzB,CAAA;AAED,MAAM,iBAAiB,GAAsB,CAAC,GAAQ,EAAO,EAAE;IAC7D,GAAG,CAAC,UAAU,CAAC,6BAAqB,CAAC,CAAA;IACrC,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA;AAED,kBAAe,iBAAiB,CAAA"}

View File

@@ -0,0 +1,74 @@
{
"name": "ajv-formats",
"version": "2.1.1",
"description": "Format validation for Ajv v7+",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"src/",
"dist/"
],
"scripts": {
"build": "tsc",
"prettier:write": "prettier --write \"./**/*.{md,json,yaml,js,ts}\"",
"prettier:check": "prettier --list-different \"./**/*.{md,json,yaml,js,ts}\"",
"eslint": "eslint --ext .ts ./src/**/*",
"test-spec": "jest",
"test-cov": "jest --coverage",
"test": "npm run prettier:check && npm run build && npm run eslint && npm run test-cov",
"ci-test": "npm run test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ajv-validator/ajv-formats.git"
},
"keywords": [
"Ajv",
"JSON-Schema",
"format",
"validation"
],
"author": "Evgeny Poberezkin",
"license": "MIT",
"bugs": {
"url": "https://github.com/ajv-validator/ajv-formats/issues"
},
"homepage": "https://github.com/ajv-validator/ajv-formats#readme",
"dependencies": {
"ajv": "^8.0.0"
},
"peerDependencies": {
"ajv": "^8.0.0"
},
"peerDependenciesMeta": {
"ajv": {
"optional": true
}
},
"devDependencies": {
"@ajv-validator/config": "^0.3.0",
"@types/jest": "^26.0.5",
"@types/node": "^14.10.1",
"@typescript-eslint/eslint-plugin": "^3.7.0",
"@typescript-eslint/parser": "^3.7.0",
"ajv": "^8.0.0",
"eslint": "^7.5.0",
"eslint-config-prettier": "^6.11.0",
"husky": "^4.2.5",
"jest": "^26.1.0",
"json-schema-test": "^2.0.0",
"lint-staged": "^10.2.11",
"prettier": "^2.3.2",
"ts-jest": "^26.1.3",
"typescript": "^4.0.0"
},
"prettier": "@ajv-validator/config/prettierrc.json",
"husky": {
"hooks": {
"pre-commit": "lint-staged && npm test"
}
},
"lint-staged": {
"*.{md,json,yaml,js,ts}": "prettier --write"
}
}

View File

@@ -0,0 +1,232 @@
import type {Format, FormatDefinition} from "ajv"
import type {FormatValidator, FormatCompare} from "ajv/dist/types"
export type FormatMode = "fast" | "full"
export type FormatName =
| "date"
| "time"
| "date-time"
| "duration"
| "uri"
| "uri-reference"
| "uri-template"
| "url"
| "email"
| "hostname"
| "ipv4"
| "ipv6"
| "regex"
| "uuid"
| "json-pointer"
| "json-pointer-uri-fragment"
| "relative-json-pointer"
| "byte"
| "int32"
| "int64"
| "float"
| "double"
| "password"
| "binary"
export type DefinedFormats = {
[key in FormatName]: Format
}
function fmtDef(
validate: RegExp | FormatValidator<string>,
compare: FormatCompare<string>
): FormatDefinition<string> {
return {validate, compare}
}
export const fullFormats: DefinedFormats = {
// date: http://tools.ietf.org/html/rfc3339#section-5.6
date: fmtDef(date, compareDate),
// date-time: http://tools.ietf.org/html/rfc3339#section-5.6
time: fmtDef(time, compareTime),
"date-time": fmtDef(date_time, compareDateTime),
// duration: https://tools.ietf.org/html/rfc3339#appendix-A
duration: /^P(?!$)((\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?|(\d+W)?)$/,
uri,
"uri-reference":
/^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'"()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i,
// uri-template: https://tools.ietf.org/html/rfc6570
"uri-template":
/^(?:(?:[^\x00-\x20"'<>%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i,
// For the source: https://gist.github.com/dperini/729294
// For test cases: https://mathiasbynens.be/demo/url-regex
url: /^(?:https?|ftp):\/\/(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u{00a1}-\u{ffff}]+-)*[a-z0-9\u{00a1}-\u{ffff}]+)(?:\.(?:[a-z0-9\u{00a1}-\u{ffff}]+-)*[a-z0-9\u{00a1}-\u{ffff}]+)*(?:\.(?:[a-z\u{00a1}-\u{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iu,
email:
/^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i,
hostname:
/^(?=.{1,253}\.?$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*\.?$/i,
// optimized https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9780596802837/ch07s16.html
ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/,
ipv6: /^((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))$/i,
regex,
// uuid: http://tools.ietf.org/html/rfc4122
uuid: /^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i,
// JSON-pointer: https://tools.ietf.org/html/rfc6901
// uri fragment: https://tools.ietf.org/html/rfc3986#appendix-A
"json-pointer": /^(?:\/(?:[^~/]|~0|~1)*)*$/,
"json-pointer-uri-fragment": /^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i,
// relative JSON-pointer: http://tools.ietf.org/html/draft-luff-relative-json-pointer-00
"relative-json-pointer": /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/,
// the following formats are used by the openapi specification: https://spec.openapis.org/oas/v3.0.0#data-types
// byte: https://github.com/miguelmota/is-base64
byte,
// signed 32 bit integer
int32: {type: "number", validate: validateInt32},
// signed 64 bit integer
int64: {type: "number", validate: validateInt64},
// C-type float
float: {type: "number", validate: validateNumber},
// C-type double
double: {type: "number", validate: validateNumber},
// hint to the UI to hide input strings
password: true,
// unchecked string payload
binary: true,
}
export const fastFormats: DefinedFormats = {
...fullFormats,
date: fmtDef(/^\d\d\d\d-[0-1]\d-[0-3]\d$/, compareDate),
time: fmtDef(
/^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)?$/i,
compareTime
),
"date-time": fmtDef(
/^\d\d\d\d-[0-1]\d-[0-3]\d[t\s](?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)$/i,
compareDateTime
),
// uri: https://github.com/mafintosh/is-my-json-valid/blob/master/formats.js
uri: /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/)?[^\s]*$/i,
"uri-reference": /^(?:(?:[a-z][a-z0-9+\-.]*:)?\/?\/)?(?:[^\\\s#][^\s#]*)?(?:#[^\\\s]*)?$/i,
// email (sources from jsen validator):
// http://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address#answer-8829363
// http://www.w3.org/TR/html5/forms.html#valid-e-mail-address (search for 'wilful violation')
email:
/^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i,
}
export const formatNames = Object.keys(fullFormats) as FormatName[]
function isLeapYear(year: number): boolean {
// https://tools.ietf.org/html/rfc3339#appendix-C
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)
}
const DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/
const DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
function date(str: string): boolean {
// full-date from http://tools.ietf.org/html/rfc3339#section-5.6
const matches: string[] | null = DATE.exec(str)
if (!matches) return false
const year: number = +matches[1]
const month: number = +matches[2]
const day: number = +matches[3]
return (
month >= 1 &&
month <= 12 &&
day >= 1 &&
day <= (month === 2 && isLeapYear(year) ? 29 : DAYS[month])
)
}
function compareDate(d1: string, d2: string): number | undefined {
if (!(d1 && d2)) return undefined
if (d1 > d2) return 1
if (d1 < d2) return -1
return 0
}
const TIME = /^(\d\d):(\d\d):(\d\d)(\.\d+)?(z|[+-]\d\d(?::?\d\d)?)?$/i
function time(str: string, withTimeZone?: boolean): boolean {
const matches: string[] | null = TIME.exec(str)
if (!matches) return false
const hour: number = +matches[1]
const minute: number = +matches[2]
const second: number = +matches[3]
const timeZone: string = matches[5]
return (
((hour <= 23 && minute <= 59 && second <= 59) ||
(hour === 23 && minute === 59 && second === 60)) &&
(!withTimeZone || timeZone !== "")
)
}
function compareTime(t1: string, t2: string): number | undefined {
if (!(t1 && t2)) return undefined
const a1 = TIME.exec(t1)
const a2 = TIME.exec(t2)
if (!(a1 && a2)) return undefined
t1 = a1[1] + a1[2] + a1[3] + (a1[4] || "")
t2 = a2[1] + a2[2] + a2[3] + (a2[4] || "")
if (t1 > t2) return 1
if (t1 < t2) return -1
return 0
}
const DATE_TIME_SEPARATOR = /t|\s/i
function date_time(str: string): boolean {
// http://tools.ietf.org/html/rfc3339#section-5.6
const dateTime: string[] = str.split(DATE_TIME_SEPARATOR)
return dateTime.length === 2 && date(dateTime[0]) && time(dateTime[1], true)
}
function compareDateTime(dt1: string, dt2: string): number | undefined {
if (!(dt1 && dt2)) return undefined
const [d1, t1] = dt1.split(DATE_TIME_SEPARATOR)
const [d2, t2] = dt2.split(DATE_TIME_SEPARATOR)
const res = compareDate(d1, d2)
if (res === undefined) return undefined
return res || compareTime(t1, t2)
}
const NOT_URI_FRAGMENT = /\/|:/
const URI =
/^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i
function uri(str: string): boolean {
// http://jmrware.com/articles/2009/uri_regexp/URI_regex.html + optional protocol + required "."
return NOT_URI_FRAGMENT.test(str) && URI.test(str)
}
const BYTE = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/gm
function byte(str: string): boolean {
BYTE.lastIndex = 0
return BYTE.test(str)
}
const MIN_INT32 = -(2 ** 31)
const MAX_INT32 = 2 ** 31 - 1
function validateInt32(value: number): boolean {
return Number.isInteger(value) && value <= MAX_INT32 && value >= MIN_INT32
}
function validateInt64(value: number): boolean {
// JSON and javascript max Int is 2**53, so any int that passes isInteger is valid for Int64
return Number.isInteger(value)
}
function validateNumber(): boolean {
return true
}
const Z_ANCHOR = /[^\\]\\Z/
function regex(str: string): boolean {
if (Z_ANCHOR.test(str)) return false
try {
new RegExp(str)
return true
} catch (e) {
return false
}
}

View File

@@ -0,0 +1,62 @@
import {
DefinedFormats,
FormatMode,
FormatName,
formatNames,
fastFormats,
fullFormats,
} from "./formats"
import formatLimit from "./limit"
import type Ajv from "ajv"
import type {Plugin, Format} from "ajv"
import {_, Name} from "ajv/dist/compile/codegen"
export {FormatMode, FormatName} from "./formats"
export {LimitFormatError} from "./limit"
export interface FormatOptions {
mode?: FormatMode
formats?: FormatName[]
keywords?: boolean
}
export type FormatsPluginOptions = FormatName[] | FormatOptions
export interface FormatsPlugin extends Plugin<FormatsPluginOptions> {
get: (format: FormatName, mode?: FormatMode) => Format
}
const fullName = new Name("fullFormats")
const fastName = new Name("fastFormats")
const formatsPlugin: FormatsPlugin = (
ajv: Ajv,
opts: FormatsPluginOptions = {keywords: true}
): Ajv => {
if (Array.isArray(opts)) {
addFormats(ajv, opts, fullFormats, fullName)
return ajv
}
const [formats, exportName] =
opts.mode === "fast" ? [fastFormats, fastName] : [fullFormats, fullName]
const list = opts.formats || formatNames
addFormats(ajv, list, formats, exportName)
if (opts.keywords) formatLimit(ajv)
return ajv
}
formatsPlugin.get = (name: FormatName, mode: FormatMode = "full"): Format => {
const formats = mode === "fast" ? fastFormats : fullFormats
const f = formats[name]
if (!f) throw new Error(`Unknown format "${name}"`)
return f
}
function addFormats(ajv: Ajv, list: FormatName[], fs: DefinedFormats, exportName: Name): void {
ajv.opts.code.formats ??= _`require("ajv-formats/dist/formats").${exportName}`
for (const f of list) ajv.addFormat(f, fs[f])
}
module.exports = exports = formatsPlugin
Object.defineProperty(exports, "__esModule", {value: true})
export default formatsPlugin

View File

@@ -0,0 +1,99 @@
import type Ajv from "ajv"
import type {
Plugin,
CodeKeywordDefinition,
KeywordErrorDefinition,
Code,
Name,
ErrorObject,
} from "ajv"
import type {AddedFormat} from "ajv/dist/types"
import type {Rule} from "ajv/dist/compile/rules"
import {KeywordCxt} from "ajv"
import {_, str, or, getProperty, operators} from "ajv/dist/compile/codegen"
type Kwd = "formatMaximum" | "formatMinimum" | "formatExclusiveMaximum" | "formatExclusiveMinimum"
type Comparison = "<=" | ">=" | "<" | ">"
const ops = operators
const KWDs: {[K in Kwd]: {okStr: Comparison; ok: Code; fail: Code}} = {
formatMaximum: {okStr: "<=", ok: ops.LTE, fail: ops.GT},
formatMinimum: {okStr: ">=", ok: ops.GTE, fail: ops.LT},
formatExclusiveMaximum: {okStr: "<", ok: ops.LT, fail: ops.GTE},
formatExclusiveMinimum: {okStr: ">", ok: ops.GT, fail: ops.LTE},
}
export type LimitFormatError = ErrorObject<Kwd, {limit: string; comparison: Comparison}>
const error: KeywordErrorDefinition = {
message: ({keyword, schemaCode}) => str`should be ${KWDs[keyword as Kwd].okStr} ${schemaCode}`,
params: ({keyword, schemaCode}) =>
_`{comparison: ${KWDs[keyword as Kwd].okStr}, limit: ${schemaCode}}`,
}
export const formatLimitDefinition: CodeKeywordDefinition = {
keyword: Object.keys(KWDs),
type: "string",
schemaType: "string",
$data: true,
error,
code(cxt) {
const {gen, data, schemaCode, keyword, it} = cxt
const {opts, self} = it
if (!opts.validateFormats) return
const fCxt = new KeywordCxt(it, (self.RULES.all.format as Rule).definition, "format")
if (fCxt.$data) validate$DataFormat()
else validateFormat()
function validate$DataFormat(): void {
const fmts = gen.scopeValue("formats", {
ref: self.formats,
code: opts.code.formats,
})
const fmt = gen.const("fmt", _`${fmts}[${fCxt.schemaCode}]`)
cxt.fail$data(
or(
_`typeof ${fmt} != "object"`,
_`${fmt} instanceof RegExp`,
_`typeof ${fmt}.compare != "function"`,
compareCode(fmt)
)
)
}
function validateFormat(): void {
const format = fCxt.schema as string
const fmtDef: AddedFormat | undefined = self.formats[format]
if (!fmtDef || fmtDef === true) return
if (
typeof fmtDef != "object" ||
fmtDef instanceof RegExp ||
typeof fmtDef.compare != "function"
) {
throw new Error(`"${keyword}": format "${format}" does not define "compare" function`)
}
const fmt = gen.scopeValue("formats", {
key: format,
ref: fmtDef,
code: opts.code.formats ? _`${opts.code.formats}${getProperty(format)}` : undefined,
})
cxt.fail$data(compareCode(fmt))
}
function compareCode(fmt: Name): Code {
return _`${fmt}.compare(${data}, ${schemaCode}) ${KWDs[keyword as Kwd].fail} 0`
}
},
dependencies: ["format"],
}
const formatLimitPlugin: Plugin<undefined> = (ajv: Ajv): Ajv => {
ajv.addKeyword(formatLimitDefinition)
return ajv
}
export default formatLimitPlugin

89
node_modules/schema-utils/package.json generated vendored Normal file
View File

@@ -0,0 +1,89 @@
{
"name": "schema-utils",
"version": "4.3.3",
"description": "webpack Validation Utils",
"license": "MIT",
"repository": "webpack/schema-utils",
"author": "webpack Contrib (https://github.com/webpack-contrib)",
"homepage": "https://github.com/webpack/schema-utils",
"bugs": "https://github.com/webpack/schema-utils/issues",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"main": "dist/index.js",
"types": "declarations/index.d.ts",
"engines": {
"node": ">= 10.13.0"
},
"scripts": {
"start": "npm run build -- -w",
"clean": "del-cli dist declarations",
"prebuild": "npm run clean",
"build:types": "tsc --declaration --emitDeclarationOnly --outDir declarations && prettier \"declarations/**/*.ts\" --write",
"build:code": "babel src -d dist --copy-files",
"build": "npm-run-all -p \"build:**\"",
"commitlint": "commitlint --from=main",
"security": "npm audit --production",
"fmt:check": "prettier \"{**/*,*}.{js,json,md,yml,css,ts}\" --list-different",
"lint:code": "eslint --cache .",
"lint:types": "tsc --pretty --noEmit",
"lint": "npm-run-all lint:code lint:types fmt:check",
"fmt": "npm run fmt:check -- --write",
"fix:js": "npm run lint:code -- --fix",
"fix": "npm-run-all fix:js fmt",
"test:only": "jest",
"test:watch": "npm run test:only -- --watch",
"test:coverage": "npm run test:only -- --collectCoverageFrom=\"src/**/*.js\" --coverage",
"pretest": "npm run lint",
"test": "npm run test:coverage",
"prepare": "npm run build && husky install",
"release": "standard-version"
},
"files": [
"dist",
"declarations"
],
"dependencies": {
"@types/json-schema": "^7.0.9",
"ajv": "^8.9.0",
"ajv-formats": "^2.1.1",
"ajv-keywords": "^5.1.0"
},
"devDependencies": {
"@eslint/js": "^9.28.0",
"@eslint/markdown": "^6.5.0",
"@babel/cli": "^7.17.0",
"@babel/core": "^7.17.0",
"@babel/preset-env": "^7.16.11",
"@commitlint/cli": "^17.6.1",
"@commitlint/config-conventional": "^16.0.0",
"@types/node": "^22.15.19",
"@stylistic/eslint-plugin": "^4.4.1",
"babel-jest": "^27.4.6",
"del": "^6.0.0",
"del-cli": "^4.0.1",
"globals": "^16.2.0",
"eslint": "^9.28.0",
"eslint-config-webpack": "^4.0.2",
"eslint-config-prettier": "^10.1.5",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jest": "^28.12.0",
"eslint-plugin-jsdoc": "^50.7.1",
"eslint-plugin-n": "^17.19.0",
"eslint-plugin-prettier": "^5.4.1",
"eslint-plugin-unicorn": "^59.0.1",
"husky": "^7.0.4",
"jest": "^27.4.7",
"lint-staged": "^16.0.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.5.3",
"prettier-2": "npm:prettier@^2",
"standard-version": "^9.3.2",
"typescript": "^5.8.3",
"webpack": "^5.99.8"
},
"keywords": [
"webpack"
]
}