diff --git a/README.md b/README.md index 19ff3cd..5b4706d 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,13 @@ The package defines these formats: - _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). diff --git a/src/formats.ts b/src/formats.ts index 15a7dd2..e5761a1 100644 --- a/src/formats.ts +++ b/src/formats.ts @@ -21,6 +21,13 @@ export type FormatName = | "json-pointer" | "json-pointer-uri-fragment" | "relative-json-pointer" + | "byte" + | "int32" + | "int64" + | "float" + | "double" + | "password" + | "binary" export type DefinedFormats = { [key in FormatName]: Format @@ -62,6 +69,21 @@ export const fullFormats: DefinedFormats = { "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: /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/gm, + // 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 = { @@ -169,6 +191,22 @@ function uri(str: string): boolean { return NOT_URI_FRAGMENT.test(str) && URI.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 diff --git a/tests/extras/format.json b/tests/extras/format.json index 95784c9..2be835c 100644 --- a/tests/extras/format.json +++ b/tests/extras/format.json @@ -728,5 +728,142 @@ "valid": true } ] + }, + { + "description": "validation of Byte", + "schema": {"format": "byte"}, + "tests": [ + { + "description": "'hello world' encoded in base64", + "data": "aGVsbG8gd29ybGQ=", + "valid": true + }, + { + "description": "multiline base64", + "data": "VGhpcyBpcyBhIGJhc2U2NCBtdWx0aWxpbmUgc3RyaW5nIHRoYXQgc3BhbnMgbW9yZSB0aGFuIDc2\nIGNoYXJhY3RlcnMgdG8gdGVzdCBtdWx0aWxpbmUgY2FwYWJpbGl0aWVzCg==", + "valid": true + }, + { + "description": "Invalid base64", + "data": "aGVsbG8gd29ybG=", + "valid": false + } + ] + }, + { + "description": "validation of int32", + "schema": {"type": "number", "format": "int32"}, + "tests": [ + { + "description": "256 is ok", + "data": 256, + "valid": true + }, + { + "description": "256.1 fails", + "data": 256.1, + "valid": false + }, + { + "description": "-(2**31) is ok", + "data": -2147483648, + "valid": true + }, + { + "description": "-(2**31) - 1 fails", + "data": -2147483649, + "valid": false + }, + { + "description": "(2**31)-1 is ok", + "data": 2147483647, + "valid": true + }, + { + "description": "2**31 fails", + "data": 2147483648, + "valid": false + }, + { + "description": "non-numeric fails", + "data": "x", + "valid": false + } + ] + }, + { + "description": "validation of int64", + "schema": {"type": "number", "format": "int64"}, + "tests": [ + { + "description": "256 is ok", + "data": 256, + "valid": true + }, + { + "description": "float fails", + "data": 256.1, + "valid": false + }, + { + "description": "non-numeric fails", + "data": "x", + "valid": false + } + ] + }, + { + "description": "validation of float", + "schema": {"type": "number", "format": "float"}, + "tests": [ + { + "description": "256.1 is ok", + "data": 256.1, + "valid": true + }, + { + "description": "non-numeric fails", + "data": "x", + "valid": false + } + ] + }, + { + "description": "validation of double", + "schema": {"type": "number", "format": "double"}, + "tests": [ + { + "description": "256.1 is ok", + "data": 256.1, + "valid": true + }, + { + "description": "non-numeric fails", + "data": "x", + "valid": false + } + ] + }, + { + "description": "validation of password", + "schema": {"format": "password"}, + "tests": [ + { + "description": "'password string' is ok", + "data": "password string", + "valid": true + } + ] + }, + { + "description": "validation of binary", + "schema": {"format": "binary"}, + "tests": [ + { + "description": "'binary string' is ok", + "data": "binary string", + "valid": true + } + ] } ]