From 7664dd1be4ce77f3f1593c7f4196b30e862e8365 Mon Sep 17 00:00:00 2001 From: Christoph Linder Date: Thu, 13 Sep 2018 02:53:33 +0200 Subject: [PATCH 01/12] Smaller bundle - kickoff --- package.json | 2 +- .../CustomTextLength.ts | 4 +- sample/sample4-custom-validator/Post.ts | 5 +- .../sample6-custom-decorator/IsLongerThan.ts | 4 +- src/decorator/Equals.ts | 25 +++ src/decorator/IsBoolean.ts | 28 +++ src/decorator/IsEmpty.ts | 25 +++ src/decorator/IsIn.ts | 30 +++ src/decorator/IsNotEmpty.ts | 25 +++ src/decorator/IsNotIn.ts | 30 +++ src/decorator/IsPhoneNumber.ts | 45 ++++ src/decorator/NotEquals.ts | 25 +++ src/decorator/Validate.ts | 24 ++ src/decorator/ValidateBy.ts | 31 +++ src/decorator/ValidationFunction.ts | 9 + src/decorator/ValidatorConstraint.ts | 20 ++ src/decorator/decorators.ts | 206 ++---------------- src/index.ts | 8 + src/metadata/ValidationMetadataArgs.ts | 2 +- src/types.d.ts | 3 +- .../ValidationSchemaToMetadataTransformer.ts | 2 +- src/validation/ValidationTypes.ts | 32 +-- src/validation/Validator.ts | 85 -------- .../functional/conditional-validation.spec.ts | 4 +- test/functional/custom-decorators.spec.ts | 2 +- test/functional/sync-validation.ts | 4 +- test/functional/validation-error.spec.ts | 3 +- ...alidation-functions-and-decorators.spec.ts | 53 +++-- test/functional/validator-options.spec.ts | 2 +- 29 files changed, 395 insertions(+), 343 deletions(-) create mode 100644 src/decorator/Equals.ts create mode 100644 src/decorator/IsBoolean.ts create mode 100644 src/decorator/IsEmpty.ts create mode 100644 src/decorator/IsIn.ts create mode 100644 src/decorator/IsNotEmpty.ts create mode 100644 src/decorator/IsNotIn.ts create mode 100644 src/decorator/IsPhoneNumber.ts create mode 100644 src/decorator/NotEquals.ts create mode 100644 src/decorator/Validate.ts create mode 100644 src/decorator/ValidateBy.ts create mode 100644 src/decorator/ValidationFunction.ts create mode 100644 src/decorator/ValidatorConstraint.ts diff --git a/package.json b/package.json index 04ee8178d0..b012f00edd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "class-validator", "private": true, - "version": "0.9.1", + "version": "0.9.1-rc1", "description": "Class-based validation with Typescript / ES6 / ES5 using decorators or validation schemas. Supports both node.js and browser", "license": "MIT", "readmeFilename": "README.md", diff --git a/sample/sample4-custom-validator/CustomTextLength.ts b/sample/sample4-custom-validator/CustomTextLength.ts index 04e3746e83..51969e9021 100644 --- a/sample/sample4-custom-validator/CustomTextLength.ts +++ b/sample/sample4-custom-validator/CustomTextLength.ts @@ -1,5 +1,5 @@ import {ValidatorConstraintInterface} from "../../src/validation/ValidatorConstraintInterface"; -import {ValidatorConstraint} from "../../src/decorator/decorators"; +import {ValidatorConstraint} from "../../src/decorator/ValidatorConstraint"; @ValidatorConstraint() export class CustomTextLength implements ValidatorConstraintInterface { @@ -8,4 +8,4 @@ export class CustomTextLength implements ValidatorConstraintInterface { return text.length > 1 && text.length < 10; } -} \ No newline at end of file +} diff --git a/sample/sample4-custom-validator/Post.ts b/sample/sample4-custom-validator/Post.ts index 6a4d226c0a..f4d372c253 100644 --- a/sample/sample4-custom-validator/Post.ts +++ b/sample/sample4-custom-validator/Post.ts @@ -1,6 +1,5 @@ -import {Contains, IsInt, MinLength, MaxLength, IsEmail, IsFQDN, IsDate, IsNotEmpty, ArrayNotEmpty, ArrayMinSize, ArrayMaxSize} from "../../src/decorator/decorators"; -import {Validate} from "../../src/decorator/decorators"; import {CustomTextLength} from "./CustomTextLength"; +import {Validate} from "../../src/decorator/Validate"; export class Post { @@ -9,4 +8,4 @@ export class Post { }) title: string; -} \ No newline at end of file +} diff --git a/sample/sample6-custom-decorator/IsLongerThan.ts b/sample/sample6-custom-decorator/IsLongerThan.ts index 90bde6e092..73108dada8 100644 --- a/sample/sample6-custom-decorator/IsLongerThan.ts +++ b/sample/sample6-custom-decorator/IsLongerThan.ts @@ -1,7 +1,7 @@ import {registerDecorator} from "../../src/index"; import {ValidationOptions} from "../../src/decorator/ValidationOptions"; import {ValidatorConstraintInterface} from "../../src/validation/ValidatorConstraintInterface"; -import {ValidatorConstraint} from "../../src/decorator/decorators"; +import {ValidatorConstraint} from "../../src/decorator/ValidatorConstraint"; import {ValidationArguments} from "../../src/validation/ValidationArguments"; export function IsLongerThan(property: string, validationOptions?: ValidationOptions) { @@ -27,4 +27,4 @@ export class IsLongerThanConstraint implements ValidatorConstraintInterface { value.length > relatedValue.length; } -} \ No newline at end of file +} diff --git a/src/decorator/Equals.ts b/src/decorator/Equals.ts new file mode 100644 index 0000000000..d87e997520 --- /dev/null +++ b/src/decorator/Equals.ts @@ -0,0 +1,25 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +/** + * Checks if value matches ("===") the comparison. + */ +export function equals(value: any, comparison: any): boolean { + return value === comparison; +} + +/** + * Checks if the value match ("===") the comparison. + */ +export function Equals(comparison: any, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "equals", + validate: (value, args) => equals(value, args.constraints[0]), + constraints: [comparison], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be equal to $constraint1", validationOptions), + + }, + validationOptions + ); +} + diff --git a/src/decorator/IsBoolean.ts b/src/decorator/IsBoolean.ts new file mode 100644 index 0000000000..fb5c0b35a1 --- /dev/null +++ b/src/decorator/IsBoolean.ts @@ -0,0 +1,28 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; +import {getFromContainer, MetadataStorage, ValidationTypes} from ".."; +import {ValidationMetadata} from "../metadata/ValidationMetadata"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import {equals} from "./Equals"; + +/** + * Checks if a given value is a real boolean. + */ +export function isBoolean(value: any): boolean { + return value instanceof Boolean || typeof value === "boolean"; +} + + +/** + * Checks if a value is a boolean. + */ +export function IsBoolean(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isBoolean", + validate: (value, args) => isBoolean(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a boolean value", validationOptions), + + }, + validationOptions + ); +} diff --git a/src/decorator/IsEmpty.ts b/src/decorator/IsEmpty.ts new file mode 100644 index 0000000000..c78f289e76 --- /dev/null +++ b/src/decorator/IsEmpty.ts @@ -0,0 +1,25 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; +import {getFromContainer, MetadataStorage, ValidationTypes} from ".."; +import {ValidationMetadata} from "../metadata/ValidationMetadata"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import {equals} from "./Equals"; + +/** + * Checks if given value is empty (=== '', === null, === undefined). + */ +export function isEmpty(value: any): boolean { + return value === "" || value === null || value === undefined; +} + +/** + * Checks if given value is empty (=== '', === null, === undefined). + */ +export function IsEmpty(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isEmpty", + validate: (value, args) => isEmpty(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be empty", validationOptions), + + }, validationOptions); +} diff --git a/src/decorator/IsIn.ts b/src/decorator/IsIn.ts new file mode 100644 index 0000000000..f9e67533a3 --- /dev/null +++ b/src/decorator/IsIn.ts @@ -0,0 +1,30 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; +import {getFromContainer, MetadataStorage, ValidationTypes} from ".."; +import {ValidationMetadata} from "../metadata/ValidationMetadata"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import {equals} from "./Equals"; + +/** + * Checks if given value is in a array of allowed values. + */ +export function isIn(value: any, possibleValues: any[]): boolean { + return !(possibleValues instanceof Array) || possibleValues.some(possibleValue => possibleValue === value); +} + +/** + * Checks if value is in a array of allowed values. + */ +export function IsIn(values: any[], validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isIn", + constraints: [values], + validate: (value, args) => isIn(value, args.constraints[0]), + defaultMessage: buildMessage( + (eachPrefix) => eachPrefix + "$property must be one of the following values: $constraint1", + validationOptions), + + }, + validationOptions + ); +} diff --git a/src/decorator/IsNotEmpty.ts b/src/decorator/IsNotEmpty.ts new file mode 100644 index 0000000000..f15899df18 --- /dev/null +++ b/src/decorator/IsNotEmpty.ts @@ -0,0 +1,25 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; +import {getFromContainer, MetadataStorage, ValidationTypes} from ".."; +import {ValidationMetadata} from "../metadata/ValidationMetadata"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import {isEmpty} from "./IsEmpty"; + +/** + * Checks if given value is not empty (!== '', !== null, !== undefined). + */ +export function isNotEmpty(value: any): boolean { + return value !== "" && value !== null && value !== undefined; +} + +/** + * Checks if given value is not empty (!== '', !== null, !== undefined). + */ +export function IsNotEmpty(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isNotEmpty", + validate: (value, args) => isNotEmpty(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property should not be empty", validationOptions), + + }, validationOptions); +} diff --git a/src/decorator/IsNotIn.ts b/src/decorator/IsNotIn.ts new file mode 100644 index 0000000000..d4caa99fc4 --- /dev/null +++ b/src/decorator/IsNotIn.ts @@ -0,0 +1,30 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; +import {getFromContainer, MetadataStorage, ValidationTypes} from ".."; +import {ValidationMetadata} from "../metadata/ValidationMetadata"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import {equals} from "./Equals"; + +/** + * Checks if given value not in a array of allowed values. + */ +export function isNotIn(value: any, possibleValues: any[]): boolean { + return !(possibleValues instanceof Array) || !possibleValues.some(possibleValue => possibleValue === value); +} + +/** + * Checks if value is not in a array of disallowed values. + */ +export function IsNotIn(values: any[], validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isNotIn", + validate: (value, args) => isNotIn(value, args.constraints[0]), + constraints: [values], + defaultMessage: buildMessage( + (eachPrefix) => eachPrefix + "$property should not be one of the following values: $constraint1", + validationOptions), + + }, + validationOptions + ); +} diff --git a/src/decorator/IsPhoneNumber.ts b/src/decorator/IsPhoneNumber.ts new file mode 100644 index 0000000000..527efc4f97 --- /dev/null +++ b/src/decorator/IsPhoneNumber.ts @@ -0,0 +1,45 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +import * as libphonenumber from "google-libphonenumber"; + +const phoneUtil = libphonenumber.PhoneNumberUtil.getInstance(); + +/** + * Checks if the string is a valid phone number. + * @param value the potential phone number string to test + * @param {string} region 2 characters uppercase country code (e.g. DE, US, CH). + * If users must enter the intl. prefix (e.g. +41), then you may pass "ZZ" or null as region. + * See [google-libphonenumber, metadata.js:countryCodeToRegionCodeMap on github]{@link https://github.com/ruimarinho/google-libphonenumber/blob/1e46138878cff479aafe2ce62175c6c49cb58720/src/metadata.js#L33} + */ +export function isPhoneNumber(value: string, region: string | null): boolean { + try { + const phoneNum = phoneUtil.parseAndKeepRawInput(value, region); + const result = phoneUtil.isValidNumber(phoneNum); + return result; + } catch (error) { + // logging? + return false; + } +} + + +/** + * Checks if the string is a valid phone number. + * @param region 2 characters uppercase country code (e.g. DE, US, CH). + * If users must enter the intl. prefix (e.g. +41), then you may pass "ZZ" or null as region. + * See [google-libphonenumber, metadata.js:countryCodeToRegionCodeMap on github]{@link https://github.com/ruimarinho/google-libphonenumber/blob/1e46138878cff479aafe2ce62175c6c49cb58720/src/metadata.js#L33} + */ +export function IsPhoneNumber(region: string | null, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isPhoneNumber", + constraints: [region], + validate: (value, args) => isPhoneNumber(value, args.constraints[0]), + defaultMessage: buildMessage( + (eachPrefix) => eachPrefix + "$property must be a valid phone number", + validationOptions), + + }, + validationOptions + ); +} diff --git a/src/decorator/NotEquals.ts b/src/decorator/NotEquals.ts new file mode 100644 index 0000000000..7a71431cbe --- /dev/null +++ b/src/decorator/NotEquals.ts @@ -0,0 +1,25 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; +import {getFromContainer, MetadataStorage, ValidationTypes} from ".."; +import {ValidationMetadata} from "../metadata/ValidationMetadata"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +/** + * Checks if value does not match ("!==") the comparison. + */ +export function notEquals(value: any, comparison: any): boolean { + return value !== comparison; +} + +/** + * Checks if the value does not match ("!==") the comparison. + */ +export function NotEquals(comparison: any, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "notEquals", + constraints: [comparison], + validate: (value, args) => notEquals(value, args.constraints[0]), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property should not be equal to $constraint1", validationOptions) + }, + validationOptions); +} diff --git a/src/decorator/Validate.ts b/src/decorator/Validate.ts new file mode 100644 index 0000000000..0f82b43140 --- /dev/null +++ b/src/decorator/Validate.ts @@ -0,0 +1,24 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; +import {getFromContainer, MetadataStorage, ValidationTypes} from ".."; +import {ValidationMetadata} from "../metadata/ValidationMetadata"; + +/** + * Performs validation based on the given custom validation class. + * Validation class must be decorated with ValidatorConstraint decorator. + */ +export function Validate(constraintClass: Function, validationOptions?: ValidationOptions): Function; +export function Validate(constraintClass: Function, constraints?: any[], validationOptions?: ValidationOptions): Function; +export function Validate(constraintClass: Function, constraintsOrValidationOptions?: any[] | ValidationOptions, maybeValidationOptions?: ValidationOptions): Function { + return function (object: Object, propertyName: string) { + const args: ValidationMetadataArgs = { + type: ValidationTypes.CUSTOM_VALIDATION, + target: object.constructor, + propertyName: propertyName, + constraintCls: constraintClass, + constraints: constraintsOrValidationOptions instanceof Array ? constraintsOrValidationOptions as any[] : undefined, + validationOptions: !(constraintsOrValidationOptions instanceof Array) ? constraintsOrValidationOptions as ValidationOptions : maybeValidationOptions + }; + getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); + }; +} diff --git a/src/decorator/ValidateBy.ts b/src/decorator/ValidateBy.ts new file mode 100644 index 0000000000..d910f80475 --- /dev/null +++ b/src/decorator/ValidateBy.ts @@ -0,0 +1,31 @@ +// ------------------------------------------------------------------------- +import {ValidationFunction} from "./ValidationFunction"; +import {ValidationOptions} from "./ValidationOptions"; +import {registerDecorator} from "../register-decorator"; +import {ValidationArguments, ValidatorConstraintInterface} from ".."; + +export function buildMessage(impl: (eachPrefix: string) => string, validationOptions?: ValidationOptions): + (validationArguments?: ValidationArguments) => string { + return () => { + const eachPrefix = validationOptions && validationOptions.each + ? "each value in " + : ""; + return impl(eachPrefix); + }; +} + +export function ValidateBy(validator: ValidationFunction, validationOptions?: ValidationOptions) { + return function (object: Object, propertyName: string) { + registerDecorator({ + name: validator.name, + target: object.constructor, + propertyName: propertyName, + options: validationOptions, + constraints: validator.constraints, + validator: { + validate: validator.validate, + defaultMessage: validator.defaultMessage + } + }); + }; +} diff --git a/src/decorator/ValidationFunction.ts b/src/decorator/ValidationFunction.ts new file mode 100644 index 0000000000..2898e04f1f --- /dev/null +++ b/src/decorator/ValidationFunction.ts @@ -0,0 +1,9 @@ +import {ValidationArguments} from "../index"; + +export interface ValidationFunction { + name: string; + constraints?: any[]; + validate: (value: any, validationArguments?: ValidationArguments) => Promise|boolean; + defaultMessage: (validationArguments?: ValidationArguments) => string; + async?: boolean; +} diff --git a/src/decorator/ValidatorConstraint.ts b/src/decorator/ValidatorConstraint.ts new file mode 100644 index 0000000000..e0cea83ed5 --- /dev/null +++ b/src/decorator/ValidatorConstraint.ts @@ -0,0 +1,20 @@ +import {ConstraintMetadata} from "../metadata/ConstraintMetadata"; +import {getFromContainer} from "../container"; +import {MetadataStorage} from ".."; + +/** + * Registers custom validator class. + */ +export function ValidatorConstraint(options?: { name?: string, async?: boolean }) { + return function (target: Function) { + const isAsync = options && options.async ? true : false; + let name = options && options.name ? options.name : ""; + if (!name) { + name = (target as any).name; + if (!name) // generate name if it was not given + name = name.replace(/\.?([A-Z]+)/g, (x, y) => "_" + y.toLowerCase()).replace(/^_/, ""); + } + const metadata = new ConstraintMetadata(target, name, isAsync); + getFromContainer(MetadataStorage).addConstraintMetadata(metadata); + }; +} diff --git a/src/decorator/decorators.ts b/src/decorator/decorators.ts index 370bc7cd18..20a9442cd1 100644 --- a/src/decorator/decorators.ts +++ b/src/decorator/decorators.ts @@ -1,53 +1,19 @@ import {ValidationTypes} from "../validation/ValidationTypes"; -import {IsNumberOptions} from "../validation/ValidationTypeOptions"; +import { + IsCurrencyOptions, + IsEmailOptions, + IsFQDNOptions, + IsNumberOptions, + IsURLOptions +} from "../validation/ValidationTypeOptions"; import {ValidationOptions} from "./ValidationOptions"; import {ValidationMetadata} from "../metadata/ValidationMetadata"; import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; -import {ConstraintMetadata} from "../metadata/ConstraintMetadata"; import {getFromContainer} from "../container"; import {MetadataStorage} from "../metadata/MetadataStorage"; // ------------------------------------------------------------------------- // System -// ------------------------------------------------------------------------- - -/** - * Registers custom validator class. - */ -export function ValidatorConstraint(options?: { name?: string, async?: boolean }) { - return function(target: Function) { - const isAsync = options && options.async ? true : false; - let name = options && options.name ? options.name : ""; - if (!name) { - name = (target as any).name; - if (!name) // generate name if it was not given - name = name.replace(/\.?([A-Z]+)/g, (x, y) => "_" + y.toLowerCase()).replace(/^_/, ""); - } - const metadata = new ConstraintMetadata(target, name, isAsync); - getFromContainer(MetadataStorage).addConstraintMetadata(metadata); - }; -} - -/** - * Performs validation based on the given custom validation class. - * Validation class must be decorated with ValidatorConstraint decorator. - */ -export function Validate(constraintClass: Function, validationOptions?: ValidationOptions): Function; -export function Validate(constraintClass: Function, constraints?: any[], validationOptions?: ValidationOptions): Function; -export function Validate(constraintClass: Function, constraintsOrValidationOptions?: any[]|ValidationOptions, maybeValidationOptions?: ValidationOptions): Function { - return function(object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.CUSTOM_VALIDATION, - target: object.constructor, - propertyName: propertyName, - constraintCls: constraintClass, - constraints: constraintsOrValidationOptions instanceof Array ? constraintsOrValidationOptions as any[] : undefined, - validationOptions: !(constraintsOrValidationOptions instanceof Array) ? constraintsOrValidationOptions as ValidationOptions : maybeValidationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - /** * Objects / object arrays marked with this decorator will also be validated. */ @@ -67,63 +33,11 @@ export function ValidateNested(validationOptions?: ValidationOptions) { * If object has both allowed and not allowed properties a validation error will be thrown. */ export function Allow(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.WHITELIST, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - - -/** - * Objects / object arrays marked with this decorator will also be validated. - */ -export function ValidateIf(condition: (object: any, value: any) => boolean, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.CONDITIONAL_VALIDATION, - target: object.constructor, - propertyName: propertyName, - constraints: [condition], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -// ------------------------------------------------------------------------- -// Common checkers -// ------------------------------------------------------------------------- - -/** - * Checks if given value is defined (!== undefined, !== null). - */ -export function IsDefined(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_DEFINED, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the value match ("===") the comparison. - */ -export function Equals(comparison: any, validationOptions?: ValidationOptions) { return function (object: Object, propertyName: string) { const args: ValidationMetadataArgs = { - type: ValidationTypes.EQUALS, + type: ValidationTypes.WHITELIST, target: object.constructor, propertyName: propertyName, - constraints: [comparison], validationOptions: validationOptions }; getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); @@ -131,61 +45,15 @@ export function Equals(comparison: any, validationOptions?: ValidationOptions) { } /** - * Checks if the value does not match ("!==") the comparison. - */ -export function NotEquals(comparison: any, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.NOT_EQUALS, - target: object.constructor, - propertyName: propertyName, - constraints: [comparison], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if given value is empty (=== '', === null, === undefined). - */ -export function IsEmpty(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_EMPTY, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if given value is not empty (!== '', !== null, !== undefined). - */ -export function IsNotEmpty(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_NOT_EMPTY, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if value is in a array of allowed values. + * Objects / object arrays marked with this decorator will also be validated. */ -export function IsIn(values: any[], validationOptions?: ValidationOptions) { +export function ValidateIf(condition: (object: any, value: any) => boolean, validationOptions?: ValidationOptions) { return function (object: Object, propertyName: string) { const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_IN, + type: ValidationTypes.CONDITIONAL_VALIDATION, target: object.constructor, propertyName: propertyName, - constraints: [values], + constraints: [condition], validationOptions: validationOptions }; getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); @@ -193,15 +61,14 @@ export function IsIn(values: any[], validationOptions?: ValidationOptions) { } /** - * Checks if value is not in a array of disallowed values. + * Checks if given value is defined (!== undefined, !== null). */ -export function IsNotIn(values: any[], validationOptions?: ValidationOptions) { +export function IsDefined(validationOptions?: ValidationOptions) { return function (object: Object, propertyName: string) { const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_NOT_IN, + type: ValidationTypes.IS_DEFINED, target: object.constructor, propertyName: propertyName, - constraints: [values], validationOptions: validationOptions }; getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); @@ -230,21 +97,6 @@ export function IsOptional(validationOptions?: ValidationOptions) { // Type checkers // ------------------------------------------------------------------------- -/** - * Checks if a value is a boolean. - */ -export function IsBoolean(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_BOOLEAN, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - /** * Checks if a value is a date. */ @@ -399,6 +251,7 @@ export function IsNegative(validationOptions?: ValidationOptions) { getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); }; } + /** * Checks if the given number is greater than or equal to given number. */ @@ -754,7 +607,7 @@ export function IsHexadecimal(validationOptions?: ValidationOptions) { /** * Checks if the string is an IP (version 4 or 6). */ -export function IsIP(version?: "4"|"6", validationOptions?: ValidationOptions) { +export function IsIP(version?: "4" | "6", validationOptions?: ValidationOptions) { return function (object: Object, propertyName: string) { const args: ValidationMetadataArgs = { type: ValidationTypes.IS_IP, @@ -770,7 +623,7 @@ export function IsIP(version?: "4"|"6", validationOptions?: ValidationOptions) { /** * Checks if the string is an ISBN (version 10 or 13). */ -export function IsISBN(version?: "10"|"13", validationOptions?: ValidationOptions) { +export function IsISBN(version?: "10" | "13", validationOptions?: ValidationOptions) { return function (object: Object, propertyName: string) { const args: ValidationMetadataArgs = { type: ValidationTypes.IS_ISBN, @@ -860,25 +713,6 @@ export function IsMobilePhone(locale: string, validationOptions?: ValidationOpti }; } -/** - * Checks if the string is a valid phone number. - * @param {string} region 2 characters uppercase country code (e.g. DE, US, CH). - * If users must enter the intl. prefix (e.g. +41), then you may pass "ZZ" or null as region. - * See [google-libphonenumber, metadata.js:countryCodeToRegionCodeMap on github]{@link https://github.com/ruimarinho/google-libphonenumber/blob/1e46138878cff479aafe2ce62175c6c49cb58720/src/metadata.js#L33} - */ -export function IsPhoneNumber(region: string, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_PHONE_NUMBER, - target: object.constructor, - propertyName: propertyName, - constraints: [region], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - /** * Checks if the string is a valid hex-encoded representation of a MongoDB ObjectId. */ @@ -943,7 +777,7 @@ export function IsUrl(options?: ValidatorJS.IsURLOptions, validationOptions?: Va /** * Checks if the string is a UUID (version 3, 4 or 5). */ -export function IsUUID(version?: "3"|"4"|"5", validationOptions?: ValidationOptions) { +export function IsUUID(version?: "3" | "4" | "5", validationOptions?: ValidationOptions) { return function (object: Object, propertyName: string) { const args: ValidationMetadataArgs = { type: ValidationTypes.IS_UUID, @@ -1024,7 +858,7 @@ export function MaxLength(max: number, validationOptions?: ValidationOptions) { */ export function Matches(pattern: RegExp, validationOptions?: ValidationOptions): Function; export function Matches(pattern: RegExp, modifiers?: string, validationOptions?: ValidationOptions): Function; -export function Matches(pattern: RegExp, modifiersOrAnnotationOptions?: string|ValidationOptions, validationOptions?: ValidationOptions): Function { +export function Matches(pattern: RegExp, modifiersOrAnnotationOptions?: string | ValidationOptions, validationOptions?: ValidationOptions): Function { let modifiers: string; if (modifiersOrAnnotationOptions && modifiersOrAnnotationOptions instanceof Object && !validationOptions) { validationOptions = modifiersOrAnnotationOptions as ValidationOptions; diff --git a/src/index.ts b/src/index.ts index 07001fc2a1..ac5b35d2e1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -108,3 +108,11 @@ export function validateSync(schemaNameOrObject: Object|string, export function registerSchema(schema: ValidationSchema): void { getFromContainer(MetadataStorage).addValidationSchema(schema); } +export {Equals} from "./decorator/Equals"; +export {NotEquals} from "./decorator/NotEquals"; +export {IsEmpty} from "./decorator/IsEmpty"; +export {IsNotEmpty} from "./decorator/IsNotEmpty"; +export {IsIn} from "./decorator/IsIn"; +export {IsNotIn} from "./decorator/IsNotIn"; +export {IsPhoneNumber} from "./decorator/IsPhoneNumber"; +export {IsBoolean} from "./decorator/IsBoolean"; diff --git a/src/metadata/ValidationMetadataArgs.ts b/src/metadata/ValidationMetadataArgs.ts index 8dcdb904ba..131efdd620 100644 --- a/src/metadata/ValidationMetadataArgs.ts +++ b/src/metadata/ValidationMetadataArgs.ts @@ -39,4 +39,4 @@ export interface ValidationMetadataArgs { * Extra options specific to validation type. */ validationTypeOptions?: any; -} \ No newline at end of file +} diff --git a/src/types.d.ts b/src/types.d.ts index 67607af4eb..879048a75a 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -1,3 +1,4 @@ declare var window: any; -declare module "ansicolor"; \ No newline at end of file +declare module "ansicolor"; +declare module "google-libphonenumber"; diff --git a/src/validation-schema/ValidationSchemaToMetadataTransformer.ts b/src/validation-schema/ValidationSchemaToMetadataTransformer.ts index fcc9eed5ef..6a3b6b277a 100644 --- a/src/validation-schema/ValidationSchemaToMetadataTransformer.ts +++ b/src/validation-schema/ValidationSchemaToMetadataTransformer.ts @@ -36,4 +36,4 @@ export class ValidationSchemaToMetadataTransformer { return metadatas; } -} \ No newline at end of file +} diff --git a/src/validation/ValidationTypes.ts b/src/validation/ValidationTypes.ts index eb128cdfe9..89ec56182b 100644 --- a/src/validation/ValidationTypes.ts +++ b/src/validation/ValidationTypes.ts @@ -10,18 +10,10 @@ export class ValidationTypes { static NESTED_VALIDATION = "nestedValidation"; static CONDITIONAL_VALIDATION = "conditionalValidation"; static WHITELIST = "whitelistValidation"; - - /* common checkers */ + // FIXME: delete static IS_DEFINED = "isDefined"; - static EQUALS = "equals"; - static NOT_EQUALS = "notEquals"; - static IS_EMPTY = "isEmpty"; - static IS_NOT_EMPTY = "isNotEmpty"; - static IS_IN = "isIn"; - static IS_NOT_IN = "isNotIn"; /* type checkers */ - static IS_BOOLEAN = "isBoolean"; static IS_DATE = "isDate"; static IS_NUMBER = "isNumber"; static IS_STRING = "isString"; @@ -69,7 +61,6 @@ export class ValidationTypes { static IS_JSON = "isJson"; static IS_LOWERCASE = "isLowercase"; static IS_MOBILE_PHONE = "isMobilePhone"; - static IS_PHONE_NUMBER = "isPhoneNumber"; static IS_MONGO_ID = "isMongoId"; static IS_MULTIBYTE = "isMultibyte"; static IS_SURROGATE_PAIR = "isSurrogatePair"; @@ -112,25 +103,10 @@ export class ValidationTypes { /* system chceck */ case this.NESTED_VALIDATION: return eachPrefix + "nested property $property must be either object or array"; - /* common checkers */ case this.IS_DEFINED: return eachPrefix + "$property should not be null or undefined"; - case this.EQUALS: - return eachPrefix + "$property must be equal to $constraint1"; - case this.NOT_EQUALS: - return eachPrefix + "$property should not be equal to $constraint1"; - case this.IS_EMPTY: - return eachPrefix + "$property must be empty"; - case this.IS_NOT_EMPTY: - return eachPrefix + "$property should not be empty"; - case this.IS_IN: - return eachPrefix + "$property must be one of the following values: $constraint1"; - case this.IS_NOT_IN: - return eachPrefix + "$property should not be one of the following values: $constraint1"; /* type checkers */ - case this.IS_BOOLEAN: - return eachPrefix + "$property must be a boolean value"; case this.IS_DATE: return eachPrefix + "$property must be a Date instance"; case this.IS_NUMBER: @@ -217,8 +193,6 @@ export class ValidationTypes { return eachPrefix + "$property must be a lowercase string"; case this.IS_MOBILE_PHONE: return eachPrefix + "$property must be a phone number"; - case this.IS_PHONE_NUMBER: - return eachPrefix + "$property must be a valid phone number"; case this.IS_MONGO_ID: return eachPrefix + "$property must be a mongodb id"; case this.IS_MULTIBYTE: @@ -271,9 +245,9 @@ export class ValidationTypes { return eachPrefix + `${this.IS_INSTANCE} decorator expects and object as value, but got falsy value.`; } }; + default: + return ""; } - - return ""; } } diff --git a/src/validation/Validator.ts b/src/validation/Validator.ts index ff8ca18482..7ab820cdca 100644 --- a/src/validation/Validator.ts +++ b/src/validation/Validator.ts @@ -16,9 +16,6 @@ export class Validator { // ------------------------------------------------------------------------- private validatorJs = require("validator"); - private libPhoneNumber = { - phoneUtil: require("google-libphonenumber").PhoneNumberUtil.getInstance(), - }; /** * Performs validation of the given object based on decorators or validation schema. @@ -112,22 +109,8 @@ export class Validator { /* common checkers */ case ValidationTypes.IS_DEFINED: return this.isDefined(value); - case ValidationTypes.EQUALS: - return this.equals(value, metadata.constraints[0]); - case ValidationTypes.NOT_EQUALS: - return this.notEquals(value, metadata.constraints[0]); - case ValidationTypes.IS_EMPTY: - return this.isEmpty(value); - case ValidationTypes.IS_NOT_EMPTY: - return this.isNotEmpty(value); - case ValidationTypes.IS_IN: - return this.isIn(value, metadata.constraints[0]); - case ValidationTypes.IS_NOT_IN: - return this.isNotIn(value, metadata.constraints[0]); /* type checkers */ - case ValidationTypes.IS_BOOLEAN: - return this.isBoolean(value); case ValidationTypes.IS_DATE: return this.isDate(value); case ValidationTypes.IS_STRING: @@ -214,8 +197,6 @@ export class Validator { return this.isLowercase(value); case ValidationTypes.IS_MOBILE_PHONE: return this.isMobilePhone(value, metadata.constraints[0]); - case ValidationTypes.IS_PHONE_NUMBER: - return this.isPhoneNumber(value, metadata.constraints[0]); case ValidationTypes.IS_MONGO_ID: return this.isMongoId(value); case ValidationTypes.IS_MULTIBYTE: @@ -270,59 +251,10 @@ export class Validator { return value !== undefined && value !== null; } - /** - * Checks if value matches ("===") the comparison. - */ - equals(value: any, comparison: any): boolean { - return value === comparison; - } - - /** - * Checks if value does not match ("!==") the comparison. - */ - notEquals(value: any, comparison: any): boolean { - return value !== comparison; - } - - /** - * Checks if given value is empty (=== '', === null, === undefined). - */ - isEmpty(value: any): boolean { - return value === "" || value === null || value === undefined; - } - - /** - * Checks if given value is not empty (!== '', !== null, !== undefined). - */ - isNotEmpty(value: any): boolean { - return value !== "" && value !== null && value !== undefined; - } - - /** - * Checks if given value is in a array of allowed values. - */ - isIn(value: any, possibleValues: any[]): boolean { - return !(possibleValues instanceof Array) || possibleValues.some(possibleValue => possibleValue === value); - } - - /** - * Checks if given value not in a array of allowed values. - */ - isNotIn(value: any, possibleValues: any[]): boolean { - return !(possibleValues instanceof Array) || !possibleValues.some(possibleValue => possibleValue === value); - } - // ------------------------------------------------------------------------- // Validation Methods: type checkers // ------------------------------------------------------------------------- - /** - * Checks if a given value is a real boolean. - */ - isBoolean(value: any): boolean { - return value instanceof Boolean || typeof value === "boolean"; - } - /** * Checks if a given value is a real date. */ @@ -651,23 +583,6 @@ export class Validator { return typeof value === "string" && this.validatorJs.isMobilePhone(value, locale); } - /** - * Checks if the string is a valid phone number. - * @param value the potential phone number string to test - * @param {string} region 2 characters uppercase country code (e.g. DE, US, CH). - * If users must enter the intl. prefix (e.g. +41), then you may pass "ZZ" or null as region. - * See [google-libphonenumber, metadata.js:countryCodeToRegionCodeMap on github]{@link https://github.com/ruimarinho/google-libphonenumber/blob/1e46138878cff479aafe2ce62175c6c49cb58720/src/metadata.js#L33} - */ - isPhoneNumber(value: string, region: string): boolean { - try { - const phoneNum = this.libPhoneNumber.phoneUtil.parseAndKeepRawInput(value, region); - return this.libPhoneNumber.phoneUtil.isValidNumber(phoneNum); - } catch (error) { - // logging? - return false; - } - } - /** * Checks if the string is a valid hex-encoded representation of a MongoDB ObjectId. * If given value is not a string, then it returns false. diff --git a/test/functional/conditional-validation.spec.ts b/test/functional/conditional-validation.spec.ts index 92e8a32af2..5690881ba1 100644 --- a/test/functional/conditional-validation.spec.ts +++ b/test/functional/conditional-validation.spec.ts @@ -1,10 +1,12 @@ import "es6-shim"; -import {IsNotEmpty, ValidateIf, IsOptional, Equals} from "../../src/decorator/decorators"; +import {ValidateIf, IsOptional} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; import {ValidatorOptions} from "../../src/validation/ValidatorOptions"; import {expect, should, use } from "chai"; import * as chaiAsPromised from "chai-as-promised"; +import {Equals} from "../../src/decorator/Equals"; +import {IsNotEmpty} from "../../src/decorator/IsNotEmpty"; should(); use(chaiAsPromised); diff --git a/test/functional/custom-decorators.spec.ts b/test/functional/custom-decorators.spec.ts index 6bcdc77d98..754ab84e31 100644 --- a/test/functional/custom-decorators.spec.ts +++ b/test/functional/custom-decorators.spec.ts @@ -3,7 +3,7 @@ import {Validator} from "../../src/validation/Validator"; import {ValidationArguments} from "../../src/validation/ValidationArguments"; import {registerDecorator} from "../../src/register-decorator"; import {ValidationOptions} from "../../src/decorator/ValidationOptions"; -import {ValidatorConstraint} from "../../src/decorator/decorators"; +import {ValidatorConstraint} from "../../src/decorator/ValidatorConstraint"; import {ValidatorConstraintInterface} from "../../src/validation/ValidatorConstraintInterface"; import {should, use } from "chai"; diff --git a/test/functional/sync-validation.ts b/test/functional/sync-validation.ts index 925d53d01e..7c4470fc13 100644 --- a/test/functional/sync-validation.ts +++ b/test/functional/sync-validation.ts @@ -3,7 +3,9 @@ import {Validator} from "../../src/validation/Validator"; import {ValidationArguments} from "../../src/validation/ValidationArguments"; import {registerDecorator} from "../../src/register-decorator"; import {ValidationOptions} from "../../src/decorator/ValidationOptions"; -import {ValidatorConstraint, Validate, IsNotEmpty} from "../../src/decorator/decorators"; +import {IsNotEmpty} from "../../src/decorator/IsNotEmpty"; +import {Validate} from "../../src/decorator/Validate"; +import {ValidatorConstraint} from "../../src/decorator/ValidatorConstraint"; import {ValidatorConstraintInterface} from "../../src/validation/ValidatorConstraintInterface"; import {should, use } from "chai"; diff --git a/test/functional/validation-error.spec.ts b/test/functional/validation-error.spec.ts index ab4520cb42..3b0111a99f 100644 --- a/test/functional/validation-error.spec.ts +++ b/test/functional/validation-error.spec.ts @@ -1,11 +1,12 @@ import "es6-shim"; -import { IsNotEmpty, IsString, IsUrl, IsOptional, ValidateNested, MinLength } from "../../src/decorator/decorators"; +import { IsString, IsUrl, IsOptional, ValidateNested, MinLength } from "../../src/decorator/decorators"; import { Validator } from "../../src/validation/Validator"; import { expect } from "chai"; import {should, use } from "chai"; import * as chaiAsPromised from "chai-as-promised"; +import {IsNotEmpty} from "../../src/decorator/IsNotEmpty"; should(); use(chaiAsPromised); diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts index 1d06a71d81..5dd6ad6724 100644 --- a/test/functional/validation-functions-and-decorators.spec.ts +++ b/test/functional/validation-functions-and-decorators.spec.ts @@ -5,14 +5,12 @@ import { IsPositive, IsNegative, Contains, - Equals, MinDate, MaxDate, IsAlpha, IsAlphanumeric, IsAscii, IsBase64, - IsBoolean, IsByteLength, IsCreditCard, IsCurrency, @@ -29,7 +27,6 @@ import { IsIP, IsISBN, IsISO8601, - IsIn, IsInt, IsJSON, Length, @@ -46,15 +43,11 @@ import { MaxLength, Min, Max, - IsNotEmpty, IsMilitaryTime, ArrayNotEmpty, ArrayMinSize, ArrayMaxSize, - NotEquals, - IsEmpty, IsDefined, - IsNotIn, IsNumber, IsString, NotContains, @@ -63,15 +56,21 @@ import { ArrayUnique, IsArray, IsDateString, - IsInstance, - IsPhoneNumber -} from "../../src/decorator/decorators"; + IsInstance} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; import {ValidatorOptions} from "../../src/validation/ValidatorOptions"; import {should, use } from "chai"; import * as chaiAsPromised from "chai-as-promised"; +import {equals, Equals} from "../../src/decorator/Equals"; +import {notEquals, NotEquals} from "../../src/decorator/NotEquals"; +import {IsEmpty, isEmpty} from "../../src/decorator/IsEmpty"; +import {isNotEmpty, IsNotEmpty} from "../../src/decorator/IsNotEmpty"; +import {IsIn, isIn} from "../../src/decorator/IsIn"; +import {IsNotIn, isNotIn} from "../../src/decorator/IsNotIn"; +import {IsPhoneNumber} from "../../src/decorator/IsPhoneNumber"; +import {IsBoolean, isBoolean} from "../../src/decorator/IsBoolean"; should(); use(chaiAsPromised); @@ -197,11 +196,11 @@ describe("Equals", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.equals(value, constraint).should.be.true); + validValues.forEach(value => equals(value, constraint).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.equals(value, constraint).should.be.false); + invalidValues.forEach(value => equals(value, constraint).should.be.false); }); it("should return error object with proper data", function(done) { @@ -232,11 +231,11 @@ describe("NotEquals", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.notEquals(value, constraint).should.be.true); + validValues.forEach(value => notEquals(value, constraint).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.notEquals(value, constraint).should.be.false); + invalidValues.forEach(value => notEquals(value, constraint).should.be.false); }); it("should return error object with proper data", function(done) { @@ -266,11 +265,11 @@ describe("IsEmpty", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isEmpty(value).should.be.true); + validValues.forEach(value => isEmpty(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isEmpty(value).should.be.false); + invalidValues.forEach(value => isEmpty(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -300,11 +299,11 @@ describe("IsNotEmpty", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isNotEmpty(value).should.be.true); + validValues.forEach(value => isNotEmpty(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isNotEmpty(value).should.be.false); + invalidValues.forEach(value => isNotEmpty(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -335,11 +334,11 @@ describe("IsIn", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isIn(value, constraint).should.be.true); + validValues.forEach(value => isIn(value, constraint).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isIn(value, constraint).should.be.false); + invalidValues.forEach(value => isIn(value, constraint).should.be.false); }); it("should return error object with proper data", function(done) { @@ -370,11 +369,11 @@ describe("IsNotIn", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isNotIn(value, constraint).should.be.true); + validValues.forEach(value => isNotIn(value, constraint).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isNotIn(value, constraint).should.be.false); + invalidValues.forEach(value => isNotIn(value, constraint).should.be.false); }); it("should return error object with proper data", function(done) { @@ -408,11 +407,11 @@ describe("IsBoolean", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isBoolean(value).should.be.true); + validValues.forEach(value => isBoolean(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isBoolean(value).should.be.false); + invalidValues.forEach(value => isBoolean(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -2851,8 +2850,8 @@ describe("IsMilitaryTime", function() { }); -describe("isPhoneNumber", function() { - describe("with region", function() { +describe.only("isPhoneNumber", function() { + describe.only("with region", function() { const validValues = [ "0311111111", "031 633 60 01", "079 4 666 666", "075 416 20 30", "+41 311111111", "+41 31 633 60 01", "+41 79 4 666 666", "+41 75 416 20 30", @@ -2866,7 +2865,7 @@ describe("isPhoneNumber", function() { someProperty: string; } - it("should not fail if validator.validate said that its valid", function(done) { + it.only("should not fail if validator.validate said that its valid", function(done) { checkValidValues(new MyClass(), validValues, done); }); diff --git a/test/functional/validator-options.spec.ts b/test/functional/validator-options.spec.ts index 6cd6303609..52dabbf07a 100644 --- a/test/functional/validator-options.spec.ts +++ b/test/functional/validator-options.spec.ts @@ -1,5 +1,5 @@ import "es6-shim"; -import {IsNotEmpty} from "../../src/decorator/decorators"; +import {IsNotEmpty} from "../../src/decorator/IsNotEmpty"; import {Validator} from "../../src/validation/Validator"; import {expect} from "chai"; From f63fe69039d40d9b6a63d67448b2088421b946b3 Mon Sep 17 00:00:00 2001 From: Christoph Linder Date: Fri, 12 Oct 2018 01:28:51 +0200 Subject: [PATCH 02/12] Smaller bundle - minor fix for preliminary unit test --- test/functional/validation-functions-and-decorators.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts index 5dd6ad6724..9e43288eb2 100644 --- a/test/functional/validation-functions-and-decorators.spec.ts +++ b/test/functional/validation-functions-and-decorators.spec.ts @@ -2850,8 +2850,8 @@ describe("IsMilitaryTime", function() { }); -describe.only("isPhoneNumber", function() { - describe.only("with region", function() { +describe("isPhoneNumber", function() { + describe("with region", function() { const validValues = [ "0311111111", "031 633 60 01", "079 4 666 666", "075 416 20 30", "+41 311111111", "+41 31 633 60 01", "+41 79 4 666 666", "+41 75 416 20 30", @@ -2865,7 +2865,7 @@ describe.only("isPhoneNumber", function() { someProperty: string; } - it.only("should not fail if validator.validate said that its valid", function(done) { + it("should not fail if validator.validate said that its valid", function(done) { checkValidValues(new MyClass(), validValues, done); }); From 7df6a609e58b45c8bb806d289bf013f1213f23de Mon Sep 17 00:00:00 2001 From: Christoph Linder Date: Thu, 18 Oct 2018 00:52:40 +0200 Subject: [PATCH 03/12] Smaller bundle - next bunch of migrations... --- package-lock.json | 5 +- package.json | 1 + sample/sample1-simple-validation/Post.ts | 5 +- sample/sample2-using-groups/Post.ts | 6 +- sample/sample3-nested-objects/Post.ts | 4 +- sample/sample3-nested-objects/Tag.ts | 4 +- sample/sample7-inheritance-support/Post.ts | 5 +- src/decorator/IsArray.ts | 23 ++ src/decorator/IsBoolean.ts | 5 +- src/decorator/IsDate.ts | 22 ++ src/decorator/IsDateString.ts | 21 ++ src/decorator/IsDivisibleBy.ts | 27 ++ src/decorator/IsEnum.ts | 25 ++ src/decorator/IsInt.ts | 22 ++ src/decorator/IsNegative.ts | 22 ++ src/decorator/IsNumber.ts | 39 +++ src/decorator/IsPositive.ts | 22 ++ src/decorator/IsString.ts | 22 ++ src/decorator/Max.ts | 23 ++ src/decorator/MaxDate.ts | 23 ++ src/decorator/Min.ts | 23 ++ src/decorator/MinDate.ts | 23 ++ src/decorator/decorators.ts | 234 +----------------- src/validation/ValidationTypeOptions.ts | 2 +- src/validation/ValidationTypes.ts | 54 ---- src/validation/Validator.ts | 160 +----------- test/functional/validation-error.spec.ts | 4 +- ...alidation-functions-and-decorators.spec.ts | 88 +++---- test/functional/whitelist-validation.spec.ts | 3 +- 29 files changed, 412 insertions(+), 505 deletions(-) create mode 100644 src/decorator/IsArray.ts create mode 100644 src/decorator/IsDate.ts create mode 100644 src/decorator/IsDateString.ts create mode 100644 src/decorator/IsDivisibleBy.ts create mode 100644 src/decorator/IsEnum.ts create mode 100644 src/decorator/IsInt.ts create mode 100644 src/decorator/IsNegative.ts create mode 100644 src/decorator/IsNumber.ts create mode 100644 src/decorator/IsPositive.ts create mode 100644 src/decorator/IsString.ts create mode 100644 src/decorator/Max.ts create mode 100644 src/decorator/MaxDate.ts create mode 100644 src/decorator/Min.ts create mode 100644 src/decorator/MinDate.ts diff --git a/package-lock.json b/package-lock.json index 12d4e658b6..2315a795ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "class-validator", - "version": "0.9.1", + "version": "1.0.0-rc1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -162,7 +162,8 @@ "@types/validator": { "version": "9.4.2", "resolved": "https://registry.npmjs.org/@types/validator/-/validator-9.4.2.tgz", - "integrity": "sha512-v6H2QH+oXVdLKp9keOJi5LQSt6X5/XIOtK1YmbCzvkAT2kHW9WyQkixit9w1UgJpBGrDCqqCZlQ+Qucpmsf8hA==" + "integrity": "sha512-v6H2QH+oXVdLKp9keOJi5LQSt6X5/XIOtK1YmbCzvkAT2kHW9WyQkixit9w1UgJpBGrDCqqCZlQ+Qucpmsf8hA==", + "dev": true }, "@types/vinyl": { "version": "2.0.2", diff --git a/package.json b/package.json index b012f00edd..acab62ecf2 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@types/mocha": "^5.2.5", "@types/node": "^10.5.2", "@types/sinon": "^5.0.1", + "@types/validator": "^9.4.2", "chai": "^4.1.2", "chai-as-promised": "^7.1.1", "codecov": "^3.0.4", diff --git a/sample/sample1-simple-validation/Post.ts b/sample/sample1-simple-validation/Post.ts index 8a3e2c6f6a..e97c77ebac 100644 --- a/sample/sample1-simple-validation/Post.ts +++ b/sample/sample1-simple-validation/Post.ts @@ -1,4 +1,7 @@ -import {Contains, IsInt, MinLength, MaxLength, IsEmail, IsFQDN, IsDate, ArrayNotEmpty, ArrayMinSize, ArrayMaxSize, IsEnum} from "../../src/decorator/decorators"; +import {Contains, MinLength, MaxLength, IsEmail, IsFQDN, ArrayNotEmpty, ArrayMinSize, ArrayMaxSize} from "../../src/decorator/decorators"; +import {IsDate} from "../../src/decorator/IsDate"; +import {IsInt} from "../../src/decorator/IsInt"; +import {IsEnum} from "../../src/decorator/IsEnum"; export enum PostType { Public, diff --git a/sample/sample2-using-groups/Post.ts b/sample/sample2-using-groups/Post.ts index 4ae81ce862..d6d0e05e97 100644 --- a/sample/sample2-using-groups/Post.ts +++ b/sample/sample2-using-groups/Post.ts @@ -1,4 +1,6 @@ -import {Contains, IsInt, Length, IsEmail, IsFQDN, IsDate} from "../../src/decorator/decorators"; +import {Contains, Length, IsEmail, IsFQDN} from "../../src/decorator/decorators"; +import {IsDate} from "../../src/decorator/IsDate"; +import {IsInt} from "../../src/decorator/IsInt"; export class Post { @@ -35,4 +37,4 @@ export class Post { @IsDate() createDate: Date; -} \ No newline at end of file +} diff --git a/sample/sample3-nested-objects/Post.ts b/sample/sample3-nested-objects/Post.ts index 85e794be87..ddbbc3b8f0 100644 --- a/sample/sample3-nested-objects/Post.ts +++ b/sample/sample3-nested-objects/Post.ts @@ -1,4 +1,4 @@ -import {Contains, IsInt, Length, IsEmail, IsFQDN, IsDate, ValidateNested} from "../../src/decorator/decorators"; +import {Length, ValidateNested} from "../../src/decorator/decorators"; import {Tag} from "./Tag"; export class Post { @@ -11,4 +11,4 @@ export class Post { @ValidateNested() tags: Tag[]; -} \ No newline at end of file +} diff --git a/sample/sample3-nested-objects/Tag.ts b/sample/sample3-nested-objects/Tag.ts index c547f90ec3..7075f51e8d 100644 --- a/sample/sample3-nested-objects/Tag.ts +++ b/sample/sample3-nested-objects/Tag.ts @@ -1,4 +1,4 @@ -import {Contains, IsInt, Length, IsEmail, IsFQDN, IsDate} from "../../src/decorator/decorators"; +import {Length} from "../../src/decorator/decorators"; export class Tag { @@ -7,4 +7,4 @@ export class Tag { }) name: string; -} \ No newline at end of file +} diff --git a/sample/sample7-inheritance-support/Post.ts b/sample/sample7-inheritance-support/Post.ts index 6d3a6d2325..87722161fc 100644 --- a/sample/sample7-inheritance-support/Post.ts +++ b/sample/sample7-inheritance-support/Post.ts @@ -1,5 +1,6 @@ -import {Contains, IsInt, MinLength, MaxLength} from "../../src/decorator/decorators"; +import {Contains, MinLength, MaxLength} from "../../src/decorator/decorators"; import {BaseContent} from "./BaseContent"; +import {IsInt} from "../../src/decorator/IsInt"; export class Post extends BaseContent { @@ -13,4 +14,4 @@ export class Post extends BaseContent { @IsInt() rating: number; -} \ No newline at end of file +} diff --git a/src/decorator/IsArray.ts b/src/decorator/IsArray.ts new file mode 100644 index 0000000000..a99a23b210 --- /dev/null +++ b/src/decorator/IsArray.ts @@ -0,0 +1,23 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + + +/** + * Checks if a given value is an array + */ +export function isArray(value: any): boolean { + return value instanceof Array; +} + +/** + * Checks if a value is an array. + */ +export function IsArray(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isArray", + validate: (value) => isArray(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be an array", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsBoolean.ts b/src/decorator/IsBoolean.ts index fb5c0b35a1..2c9339f044 100644 --- a/src/decorator/IsBoolean.ts +++ b/src/decorator/IsBoolean.ts @@ -19,9 +19,8 @@ export function isBoolean(value: any): boolean { export function IsBoolean(validationOptions?: ValidationOptions) { return ValidateBy({ name: "isBoolean", - validate: (value, args) => isBoolean(value), - defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a boolean value", validationOptions), - + validate: (value) => isBoolean(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a boolean value", validationOptions) }, validationOptions ); diff --git a/src/decorator/IsDate.ts b/src/decorator/IsDate.ts new file mode 100644 index 0000000000..5625807b83 --- /dev/null +++ b/src/decorator/IsDate.ts @@ -0,0 +1,22 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +/** + * Checks if a given value is a real date. + */ +export function isDate(value: any): boolean { + return value instanceof Date && !isNaN(value.getTime()); +} + +/** + * Checks if a value is a date. + */ +export function IsDate(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isDate", + validate: (value) => isDate(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a Date instance", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsDateString.ts b/src/decorator/IsDateString.ts new file mode 100644 index 0000000000..070796d6e6 --- /dev/null +++ b/src/decorator/IsDateString.ts @@ -0,0 +1,21 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import {isString} from "./IsString"; + +/** + * Checks if a given value is a ISOString date. + */ +export function isDateString(value: any): boolean { + const regex = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z|\+[0-2]\d(?:\:[0-5]\d)?)?/g; + return isString(value) && regex.test(value); +} + +export function IsDateString(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isDateString", + validate: (value) => isDateString(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a ISOString", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsDivisibleBy.ts b/src/decorator/IsDivisibleBy.ts new file mode 100644 index 0000000000..298cb1830c --- /dev/null +++ b/src/decorator/IsDivisibleBy.ts @@ -0,0 +1,27 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +import * as validatorIsDivisibleBy from "validator/lib/isDivisibleBy"; + +/** + * Checks if value is a number that's divisible by another. + */ +export function isDivisibleBy(value: number, num: number): boolean { + return typeof value === "number" && + typeof num === "number" && + validatorIsDivisibleBy(String(value), num); +} + +/** + * Checks if the value is a number that's divisible by another. + */ +export function IsDivisibleBy(num: number, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isDivisibleBy", + validate: (value, args) => isDivisibleBy(value, args.constraints[0]), + constraints: [num], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be divisible by $constraint1", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsEnum.ts b/src/decorator/IsEnum.ts new file mode 100644 index 0000000000..94a96ebc8b --- /dev/null +++ b/src/decorator/IsEnum.ts @@ -0,0 +1,25 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +/** + * Checks if a given value is an enum + */ +export function isEnum(value: any, entity: any): boolean { + const enumValues = Object.keys(entity) + .map(k => entity[k]); + return enumValues.indexOf(value) >= 0; +} + +/** + * Checks if a value is a number enum. + */ +export function IsEnum(entity: Object, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isEnum", + validate: (value, args) => isEnum(value, args.constraints[0]), + constraints: [entity], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a valid enum value", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsInt.ts b/src/decorator/IsInt.ts new file mode 100644 index 0000000000..a1ee84fd8a --- /dev/null +++ b/src/decorator/IsInt.ts @@ -0,0 +1,22 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +/** + * Checks if value is an integer. + */ +export function isInt(val: number): boolean { + return Number.isInteger(val); +} + +/** + * Checks if the value is an integer number. + */ +export function IsInt(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isInt", + validate: (value) => isInt(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be an integer number", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsNegative.ts b/src/decorator/IsNegative.ts new file mode 100644 index 0000000000..af48457e51 --- /dev/null +++ b/src/decorator/IsNegative.ts @@ -0,0 +1,22 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +/** + * Checks if the value is a negative number. + */ +export function isNegative(value: number): boolean { + return typeof value === "number" && value < 0; +} + +/** + * Checks if the value is a negative number. + */ +export function IsNegative(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isNegative", + validate: (value) => isNegative(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a negative number", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsNumber.ts b/src/decorator/IsNumber.ts new file mode 100644 index 0000000000..6782483658 --- /dev/null +++ b/src/decorator/IsNumber.ts @@ -0,0 +1,39 @@ +import {ValidationOptions} from ".."; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +/** + * Options to be passed to IsNumber decorator. + */ +export interface IsNumberOptions { + allowNaN?: boolean; + allowInfinity?: boolean; +} + +/** + * Checks if a given value is a number. + */ +export function isNumber(value: any, options: IsNumberOptions = {}): boolean { + if (value === Infinity || value === -Infinity) { + return options.allowInfinity; + } + + if (Number.isNaN(value)) { + return options.allowNaN; + } + + return Number.isFinite(value); +} + +/** + * Checks if a value is a number. + */ +export function IsNumber(options: IsNumberOptions = {}, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isNumber", + validate: (value, args) => isNumber(value, args.constraints[0]), + constraints: [options], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a number", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsPositive.ts b/src/decorator/IsPositive.ts new file mode 100644 index 0000000000..8b70167350 --- /dev/null +++ b/src/decorator/IsPositive.ts @@ -0,0 +1,22 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +/** + * Checks if the value is a positive number. + */ +export function isPositive(value: number): boolean { + return typeof value === "number" && value > 0; +} + +/** + * Checks if the value is a positive number. + */ +export function IsPositive(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isPositive", + validate: (value) => isPositive(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a positive number", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsString.ts b/src/decorator/IsString.ts new file mode 100644 index 0000000000..0c562e3898 --- /dev/null +++ b/src/decorator/IsString.ts @@ -0,0 +1,22 @@ +import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "./ValidationOptions"; + +/** + * Checks if a given value is a real string. + */ +export function isString(value: any): boolean { + return value instanceof String || typeof value === "string"; +} + +/** + * Checks if a value is a string. + */ +export function IsString(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isString", + validate: (value) => isString(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a string", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/Max.ts b/src/decorator/Max.ts new file mode 100644 index 0000000000..995918a5d6 --- /dev/null +++ b/src/decorator/Max.ts @@ -0,0 +1,23 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +/** + * Checks if the first number is less than or equal to the second/reference. + */ +export function max(num: number, reference: number): boolean { + return typeof num === "number" && typeof reference === "number" && num <= reference; +} + +/** + * Checks if the given number is less than or equal to the reference number. + */ +export function Max(reference: number, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "max", + validate: (value, args) => max(value, args.constraints[0]), + constraints: [reference], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must not be greater than $constraint1", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/MaxDate.ts b/src/decorator/MaxDate.ts new file mode 100644 index 0000000000..3e70f7210b --- /dev/null +++ b/src/decorator/MaxDate.ts @@ -0,0 +1,23 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +/** + * Checks if the value is a date that's before the specified date. + */ +export function maxDate(date: Date, maxDate: Date): boolean { + return date && date.getTime() <= maxDate.getTime(); +} + +/** + * Checks if the value is a date that's before the specified date. + */ +export function MaxDate(date: Date, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "maxDate", + validate: (value, args) => maxDate(value, args.constraints[0]), + constraints: [date], + defaultMessage: buildMessage((eachPrefix) => "maximal allowed date for " + eachPrefix + "$property is $constraint1", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/Min.ts b/src/decorator/Min.ts new file mode 100644 index 0000000000..6b288117dd --- /dev/null +++ b/src/decorator/Min.ts @@ -0,0 +1,23 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +/** + * Checks if the first number is greater than or equal to the second/reference. + */ +export function min(num: number, reference: number): boolean { + return typeof num === "number" && typeof reference === "number" && num >= reference; +} + +/** + * Checks if the given number is greater than or equal to reference number. + */ +export function Min(reference: number, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "min", + validate: (value, args) => min(value, args.constraints[0]), + constraints: [reference], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must not be less than $constraint1", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/MinDate.ts b/src/decorator/MinDate.ts new file mode 100644 index 0000000000..f071ff9766 --- /dev/null +++ b/src/decorator/MinDate.ts @@ -0,0 +1,23 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +/** + * Checks if the value is a date that's after the specified date. + */ +export function minDate(date: Date, minDate: Date): boolean { + return date && date.getTime() >= minDate.getTime(); +} + +/** + * Checks if the value is a date that's after the specified date. + */ +export function MinDate(date: Date, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "minDate", + validate: (value, args) => minDate(value, args.constraints[0]), + constraints: [date], + defaultMessage: buildMessage((eachPrefix) => "minimal allowed date for " + eachPrefix + "$property is $constraint1", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/decorators.ts b/src/decorator/decorators.ts index 20a9442cd1..3fd75eb243 100644 --- a/src/decorator/decorators.ts +++ b/src/decorator/decorators.ts @@ -1,16 +1,15 @@ -import {ValidationTypes} from "../validation/ValidationTypes"; +import {ValidationTypes} from ".."; import { IsCurrencyOptions, IsEmailOptions, IsFQDNOptions, - IsNumberOptions, IsURLOptions -} from "../validation/ValidationTypeOptions"; +} from ".."; import {ValidationOptions} from "./ValidationOptions"; import {ValidationMetadata} from "../metadata/ValidationMetadata"; import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; import {getFromContainer} from "../container"; -import {MetadataStorage} from "../metadata/MetadataStorage"; +import {MetadataStorage} from ".."; // ------------------------------------------------------------------------- // System @@ -93,233 +92,6 @@ export function IsOptional(validationOptions?: ValidationOptions) { }; } -// ------------------------------------------------------------------------- -// Type checkers -// ------------------------------------------------------------------------- - -/** - * Checks if a value is a date. - */ -export function IsDate(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_DATE, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if a value is a number. - */ -export function IsNumber(options: IsNumberOptions = {}, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_NUMBER, - target: object.constructor, - propertyName: propertyName, - constraints: [options], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the value is an integer number. - */ -export function IsInt(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_INT, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if a value is a string. - */ -export function IsString(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_STRING, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -export function IsDateString(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_DATE_STRING, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if a value is an array. - */ -export function IsArray(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_ARRAY, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if a value is a number enum. - */ -export function IsEnum(entity: Object, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_ENUM, - target: object.constructor, - propertyName: propertyName, - constraints: [entity], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - - -// ------------------------------------------------------------------------- -// Number checkers -// ------------------------------------------------------------------------- - -/** - * Checks if the value is a number that's divisible by another. - */ -export function IsDivisibleBy(num: number, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_DIVISIBLE_BY, - target: object.constructor, - propertyName: propertyName, - constraints: [num], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the value is a positive number. - */ -export function IsPositive(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_POSITIVE, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the value is a negative number. - */ -export function IsNegative(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_NEGATIVE, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the given number is greater than or equal to given number. - */ -export function Min(min: number, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.MIN, - target: object.constructor, - propertyName: propertyName, - constraints: [min], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the given number is less than or equal to given number. - */ -export function Max(max: number, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.MAX, - target: object.constructor, - propertyName: propertyName, - constraints: [max], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -// ------------------------------------------------------------------------- -// Date checkers -// ------------------------------------------------------------------------- - -/** - * Checks if the value is a date that's after the specified date. - */ -export function MinDate(date: Date, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.MIN_DATE, - target: object.constructor, - propertyName: propertyName, - constraints: [date], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the value is a date that's before the specified date. - */ -export function MaxDate(date: Date, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.MAX_DATE, - target: object.constructor, - propertyName: propertyName, - constraints: [date], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - // ------------------------------------------------------------------------- // String-as-types checkers // ------------------------------------------------------------------------- diff --git a/src/validation/ValidationTypeOptions.ts b/src/validation/ValidationTypeOptions.ts index fe91f7a91d..361dbc82a3 100644 --- a/src/validation/ValidationTypeOptions.ts +++ b/src/validation/ValidationTypeOptions.ts @@ -4,4 +4,4 @@ export interface IsNumberOptions { allowNaN?: boolean; allowInfinity?: boolean; -} \ No newline at end of file +} diff --git a/src/validation/ValidationTypes.ts b/src/validation/ValidationTypes.ts index 89ec56182b..f875c2f4be 100644 --- a/src/validation/ValidationTypes.ts +++ b/src/validation/ValidationTypes.ts @@ -13,26 +13,6 @@ export class ValidationTypes { // FIXME: delete static IS_DEFINED = "isDefined"; - /* type checkers */ - static IS_DATE = "isDate"; - static IS_NUMBER = "isNumber"; - static IS_STRING = "isString"; - static IS_DATE_STRING = "isDateString"; - static IS_ARRAY = "isArray"; - static IS_INT = "isInt"; - static IS_ENUM = "isEnum"; - - /* number checkers */ - static IS_DIVISIBLE_BY = "isDivisibleBy"; - static IS_POSITIVE = "isPositive"; - static IS_NEGATIVE = "isNegative"; - static MIN = "min"; - static MAX = "max"; - - /* date checkers */ - static MIN_DATE = "minDate"; - static MAX_DATE = "maxDate"; - /* string-as-type checkers */ static IS_BOOLEAN_STRING = "isBooleanString"; static IS_NUMBER_STRING = "isNumberString"; @@ -106,40 +86,6 @@ export class ValidationTypes { case this.IS_DEFINED: return eachPrefix + "$property should not be null or undefined"; - /* type checkers */ - case this.IS_DATE: - return eachPrefix + "$property must be a Date instance"; - case this.IS_NUMBER: - return eachPrefix + "$property must be a number"; - case this.IS_INT: - return eachPrefix + "$property must be an integer number"; - case this.IS_STRING: - return eachPrefix + "$property must be a string"; - case this.IS_DATE_STRING: - return eachPrefix + "$property must be a ISOString"; - case this.IS_ARRAY: - return eachPrefix + "$property must be an array"; - case this.IS_ENUM: - return eachPrefix + "$property must be a valid enum value"; - - /* number checkers */ - case this.IS_DIVISIBLE_BY: - return eachPrefix + "$property must be divisible by $constraint1"; - case this.IS_POSITIVE: - return eachPrefix + "$property must be a positive number"; - case this.IS_NEGATIVE: - return eachPrefix + "$property must be a negative number"; - case this.MIN: - return eachPrefix + "$property must not be less than $constraint1"; - case this.MAX: - return eachPrefix + "$property must not be greater than $constraint1"; - - /* date checkers */ - case this.MIN_DATE: - return "minimal allowed date for " + eachPrefix + "$property is $constraint1"; - case this.MAX_DATE: - return "maximal allowed date for " + eachPrefix + "$property is $constraint1"; - /* string-as-type checkers */ case this.IS_BOOLEAN_STRING: return eachPrefix + "$property must be a boolean string"; diff --git a/src/validation/Validator.ts b/src/validation/Validator.ts index 7ab820cdca..1236bf37f5 100644 --- a/src/validation/Validator.ts +++ b/src/validation/Validator.ts @@ -4,7 +4,7 @@ import {ValidationError} from "./ValidationError"; import {IsNumberOptions} from "./ValidationTypeOptions"; import {ValidatorOptions} from "./ValidatorOptions"; import {ValidationExecutor} from "./ValidationExecutor"; -import {ValidationOptions} from "../decorator/ValidationOptions"; +import {ValidationOptions} from ".."; /** * Validator performs validation of the given object based on its metadata. @@ -15,6 +15,7 @@ export class Validator { // Private Properties // ------------------------------------------------------------------------- + // FIXME: other goal of modularization: remove this!!!! private validatorJs = require("validator"); /** @@ -110,40 +111,6 @@ export class Validator { case ValidationTypes.IS_DEFINED: return this.isDefined(value); - /* type checkers */ - case ValidationTypes.IS_DATE: - return this.isDate(value); - case ValidationTypes.IS_STRING: - return this.isString(value); - case ValidationTypes.IS_DATE_STRING: - return this.isDateString(value); - case ValidationTypes.IS_ARRAY: - return this.isArray(value); - case ValidationTypes.IS_NUMBER: - return this.isNumber(value, metadata.constraints[0]); - case ValidationTypes.IS_INT: - return this.isInt(value); - case ValidationTypes.IS_ENUM: - return this.isEnum(value, metadata.constraints[0]); - - /* number checkers */ - case ValidationTypes.IS_DIVISIBLE_BY: - return this.isDivisibleBy(value, metadata.constraints[0]); - case ValidationTypes.IS_POSITIVE: - return this.isPositive(value); - case ValidationTypes.IS_NEGATIVE: - return this.isNegative(value); - case ValidationTypes.MIN: - return this.min(value, metadata.constraints[0]); - case ValidationTypes.MAX: - return this.max(value, metadata.constraints[0]); - - /* date checkers */ - case ValidationTypes.MIN_DATE: - return this.minDate(value, metadata.constraints[0]); - case ValidationTypes.MAX_DATE: - return this.maxDate(value, metadata.constraints[0]); - /* string-as-type checkers */ case ValidationTypes.IS_BOOLEAN_STRING: return this.isBooleanString(value); @@ -251,129 +218,6 @@ export class Validator { return value !== undefined && value !== null; } - // ------------------------------------------------------------------------- - // Validation Methods: type checkers - // ------------------------------------------------------------------------- - - /** - * Checks if a given value is a real date. - */ - isDate(value: any): boolean { - return value instanceof Date && !isNaN(value.getTime()); - } - - /** - * Checks if a given value is a real string. - */ - isString(value: any): boolean { - return value instanceof String || typeof value === "string"; - } - - /** - * Checks if a given value is a ISOString date. - */ - isDateString(value: any): boolean { - const regex = /^\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z|\+[0-2]\d(?:\:[0-5]\d)?)?$/g; - return this.isString(value) && regex.test(value); - } - - /** - * Checks if a given value is an array - */ - isArray(value: any): boolean { - return value instanceof Array; - } - - /** - * Checks if a given value is an enum - */ - isEnum(value: any, entity: any): boolean { - const enumValues = Object.keys(entity) - .map(k => entity[k]); - return enumValues.indexOf(value) >= 0; - } - - /** - * Checks if a given value is a number. - */ - isNumber(value: any, options: IsNumberOptions = {}): boolean { - if (value === Infinity || value === -Infinity) { - return options.allowInfinity; - } - - if (Number.isNaN(value)) { - return options.allowNaN; - } - - return Number.isFinite(value); - } - - /** - * Checks if value is an integer. - */ - isInt(val: number): boolean { - return Number.isInteger(val); - } - - // ------------------------------------------------------------------------- - // Validation Methods: number checkers - // ------------------------------------------------------------------------- - - /** - * Checks if value is a number that's divisible by another. - */ - isDivisibleBy(value: number, num: number): boolean { - return typeof value === "number" && - typeof num === "number" && - this.validatorJs.isDivisibleBy(String(value), num); - } - - /** - * Checks if the value is a positive number. - */ - isPositive(value: number): boolean { - return typeof value === "number" && value > 0; - } - - /** - * Checks if the value is a negative number. - */ - isNegative(value: number): boolean { - return typeof value === "number" && value < 0; - } - - /** - * Checks if the first number is greater than or equal to the second. - */ - min(num: number, min: number): boolean { - return typeof num === "number" && typeof min === "number" && num >= min; - } - - /** - * Checks if the first number is less than or equal to the second. - */ - max(num: number, max: number): boolean { - return typeof num === "number" && typeof max === "number" && num <= max; - } - - // ------------------------------------------------------------------------- - // Validation Methods: date checkers - // ------------------------------------------------------------------------- - - /** - * Checks if the value is a date that's after the specified date. - */ - minDate(date: Date, minDate: Date): boolean { - return date && date.getTime() >= minDate.getTime(); - } - - /** - * Checks if the value is a date that's before the specified date. - */ - maxDate(date: Date, maxDate: Date): boolean { - return date && date.getTime() <= maxDate.getTime(); - } - // ------------------------------------------------------------------------- // Validation Methods: string-as-type checkers // ------------------------------------------------------------------------- diff --git a/test/functional/validation-error.spec.ts b/test/functional/validation-error.spec.ts index 3b0111a99f..ceec232588 100644 --- a/test/functional/validation-error.spec.ts +++ b/test/functional/validation-error.spec.ts @@ -1,12 +1,12 @@ import "es6-shim"; -import { IsString, IsUrl, IsOptional, ValidateNested, MinLength } from "../../src/decorator/decorators"; +import { IsUrl, IsOptional, ValidateNested, MinLength } from "../../src/decorator/decorators"; import { Validator } from "../../src/validation/Validator"; import { expect } from "chai"; import {should, use } from "chai"; import * as chaiAsPromised from "chai-as-promised"; -import {IsNotEmpty} from "../../src/decorator/IsNotEmpty"; +import {IsString} from "../../src/decorator/IsString"; should(); use(chaiAsPromised); diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts index 9e43288eb2..f2597f2118 100644 --- a/test/functional/validation-functions-and-decorators.spec.ts +++ b/test/functional/validation-functions-and-decorators.spec.ts @@ -2,11 +2,7 @@ import "es6-shim"; import {expect} from "chai"; import { IsBooleanString, - IsPositive, - IsNegative, Contains, - MinDate, - MaxDate, IsAlpha, IsAlphanumeric, IsAscii, @@ -14,10 +10,7 @@ import { IsByteLength, IsCreditCard, IsCurrency, - IsDate, - IsDivisibleBy, IsEmail, - IsEnum, IsFQDN, IsFullWidth, IsHalfWidth, @@ -27,7 +20,6 @@ import { IsIP, IsISBN, IsISO8601, - IsInt, IsJSON, Length, IsLowercase, @@ -41,21 +33,15 @@ import { Matches, MinLength, MaxLength, - Min, - Max, IsMilitaryTime, ArrayNotEmpty, ArrayMinSize, ArrayMaxSize, IsDefined, - IsNumber, - IsString, NotContains, ArrayContains, ArrayNotContains, ArrayUnique, - IsArray, - IsDateString, IsInstance} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; import {ValidatorOptions} from "../../src/validation/ValidatorOptions"; @@ -71,6 +57,20 @@ import {IsIn, isIn} from "../../src/decorator/IsIn"; import {IsNotIn, isNotIn} from "../../src/decorator/IsNotIn"; import {IsPhoneNumber} from "../../src/decorator/IsPhoneNumber"; import {IsBoolean, isBoolean} from "../../src/decorator/IsBoolean"; +import {IsDate, isDate} from "../../src/decorator/IsDate"; +import {IsNumber, isNumber} from "../../src/decorator/IsNumber"; +import {IsInt, isInt} from "../../src/decorator/IsInt"; +import {IsString, isString} from "../../src/decorator/IsString"; +import {IsDateString, isDateString} from "../../src/decorator/IsDateString"; +import {IsArray, isArray} from "../../src/decorator/IsArray"; +import {isEnum, IsEnum} from "../../src/decorator/IsEnum"; +import {IsDivisibleBy, isDivisibleBy} from "../../src/decorator/IsDivisibleBy"; +import {IsPositive, isPositive} from "../../src/decorator/IsPositive"; +import {isNegative, IsNegative} from "../../src/decorator/IsNegative"; +import {Min, min} from "../../src/decorator/Min"; +import {Max, max} from "../../src/decorator/Max"; +import {minDate, MinDate} from "../../src/decorator/MinDate"; +import {maxDate, MaxDate} from "../../src/decorator/MaxDate"; should(); use(chaiAsPromised); @@ -441,11 +441,11 @@ describe("IsDate", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isDate(value).should.be.true); + validValues.forEach(value => isDate(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isDate(value).should.be.false); + invalidValues.forEach(value => isDate(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -501,11 +501,11 @@ describe("IsNumber", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isNumber(value).should.be.true); + validValues.forEach(value => isNumber(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isNumber(value).should.be.false); + invalidValues.forEach(value => isNumber(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -545,11 +545,11 @@ describe("IsInt", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isInt(value).should.be.true); + validValues.forEach(value => isInt(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isInt(value as any).should.be.false); + invalidValues.forEach(value => isInt(value as any).should.be.false); }); it("should return error object with proper data", function(done) { @@ -586,11 +586,11 @@ describe("IsString", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isString(value).should.be.true); + validValues.forEach(value => isString(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isString(value as any).should.be.false); + invalidValues.forEach(value => isString(value as any).should.be.false); }); it("should return error object with proper data", function(done) { @@ -637,11 +637,11 @@ describe("IsDateString", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => expect(validator.isDateString(value)).be.true); + validValues.forEach(value => expect(isDateString(value)).be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => expect(validator.isDateString(value as any)).be.false); + invalidValues.forEach(value => expect(isDateString(value as any)).be.false); }); it("should return error object with proper data", function(done) { @@ -679,11 +679,11 @@ describe("IsArray", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isArray(value).should.be.true); + validValues.forEach(value => isArray(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isArray(value as any).should.be.false); + invalidValues.forEach(value => isArray(value as any).should.be.false); }); it("should return error object with proper data", function(done) { @@ -746,19 +746,19 @@ describe("IsEnum", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isEnum(value, MyEnum).should.be.true); + validValues.forEach(value => isEnum(value, MyEnum).should.be.true); }); it("should not fail if method in validator said that its valid (string enum)", function() { - validStringValues.forEach(value => validator.isEnum(value, MyStringEnum).should.be.true); + validStringValues.forEach(value => isEnum(value, MyStringEnum).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isEnum(value, MyEnum).should.be.false); + invalidValues.forEach(value => isEnum(value, MyEnum).should.be.false); }); it("should fail if method in validator said that its invalid (string enum)", function() { - invalidValues.forEach(value => validator.isEnum(value, MyStringEnum).should.be.false); + invalidValues.forEach(value => isEnum(value, MyStringEnum).should.be.false); }); it("should return error object with proper data", function(done) { @@ -800,11 +800,11 @@ describe("IsDivisibleBy", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isDivisibleBy(value, constraint).should.be.true); + validValues.forEach(value => isDivisibleBy(value, constraint).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isDivisibleBy(value as any, constraint).should.be.false); + invalidValues.forEach(value => isDivisibleBy(value as any, constraint).should.be.false); }); it("should return error object with proper data", function(done) { @@ -856,11 +856,11 @@ describe("IsPositive", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isPositive(value).should.be.true); + validValues.forEach(value => isPositive(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isPositive(value as any).should.be.false); + invalidValues.forEach(value => isPositive(value as any).should.be.false); }); it("should return error object with proper data", function(done) { @@ -913,11 +913,11 @@ describe("IsNegative", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isNegative(value).should.be.true); + validValues.forEach(value => isNegative(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isNegative(value as any).should.be.false); + invalidValues.forEach(value => isNegative(value as any).should.be.false); }); it("should return error object with proper data", function(done) { @@ -948,11 +948,11 @@ describe("Min", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.min(value, constraint).should.be.true); + validValues.forEach(value => min(value, constraint).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.min(value, constraint).should.be.false); + invalidValues.forEach(value => min(value, constraint).should.be.false); }); it("should return error object with proper data", function(done) { @@ -983,11 +983,11 @@ describe("Max", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.max(value, constraint).should.be.true); + validValues.forEach(value => max(value, constraint).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.max(value, constraint).should.be.false); + invalidValues.forEach(value => max(value, constraint).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1022,11 +1022,11 @@ describe("MinDate", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.minDate(value, constraint).should.be.true); + validValues.forEach(value => minDate(value, constraint).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.minDate(value, constraint).should.be.false); + invalidValues.forEach(value => minDate(value, constraint).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1057,11 +1057,11 @@ describe("MaxDate", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.maxDate(value, constraint).should.be.true); + validValues.forEach(value => maxDate(value, constraint).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.maxDate(value, constraint).should.be.false); + invalidValues.forEach(value => maxDate(value, constraint).should.be.false); }); it("should return error object with proper data", function(done) { diff --git a/test/functional/whitelist-validation.spec.ts b/test/functional/whitelist-validation.spec.ts index 3750ee3d55..e7ac667802 100644 --- a/test/functional/whitelist-validation.spec.ts +++ b/test/functional/whitelist-validation.spec.ts @@ -1,5 +1,5 @@ import "es6-shim"; -import {Allow, IsDefined, Min, ValidateNested} from "../../src/decorator/decorators"; +import {Allow, IsDefined} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; import {expect} from "chai"; import {ValidationTypes} from "../../src/validation/ValidationTypes"; @@ -7,6 +7,7 @@ import {ValidationTypes} from "../../src/validation/ValidationTypes"; import {should, use } from "chai"; import * as chaiAsPromised from "chai-as-promised"; +import {Min} from "../../src/decorator/Min"; should(); use(chaiAsPromised); From c734897a64303a1d6f4e66fcc4ec9d0223b3c2e0 Mon Sep 17 00:00:00 2001 From: Christoph Linder Date: Thu, 18 Oct 2018 01:29:01 +0200 Subject: [PATCH 04/12] Smaller bundle - remove global exports/fix imports --- .../CustomTextLength.ts | 2 +- .../sample6-custom-decorator/IsLongerThan.ts | 2 +- .../IsUserAlreadyExist.ts | 4 +-- src/decorator/IsBoolean.ts | 4 --- src/decorator/IsEmpty.ts | 4 --- src/decorator/IsIn.ts | 4 --- src/decorator/IsNotEmpty.ts | 4 --- src/decorator/IsNotIn.ts | 4 --- src/decorator/IsNumber.ts | 2 +- src/decorator/NotEquals.ts | 3 -- src/decorator/Validate.ts | 4 ++- src/decorator/ValidateBy.ts | 4 +-- src/decorator/ValidationFunction.ts | 2 +- src/decorator/ValidatorConstraint.ts | 2 +- src/decorator/decorators.ts | 6 ++-- src/index.ts | 35 ++++++++----------- src/validation/Validator.ts | 2 +- .../ValidatorConstraintInterface.ts | 2 +- test/functional/validation-options.spec.ts | 6 ++-- 19 files changed, 33 insertions(+), 63 deletions(-) diff --git a/sample/sample4-custom-validator/CustomTextLength.ts b/sample/sample4-custom-validator/CustomTextLength.ts index 51969e9021..b34140a0c2 100644 --- a/sample/sample4-custom-validator/CustomTextLength.ts +++ b/sample/sample4-custom-validator/CustomTextLength.ts @@ -1,5 +1,5 @@ -import {ValidatorConstraintInterface} from "../../src/validation/ValidatorConstraintInterface"; import {ValidatorConstraint} from "../../src/decorator/ValidatorConstraint"; +import {ValidatorConstraintInterface} from "../../src/validation/ValidatorConstraintInterface"; @ValidatorConstraint() export class CustomTextLength implements ValidatorConstraintInterface { diff --git a/sample/sample6-custom-decorator/IsLongerThan.ts b/sample/sample6-custom-decorator/IsLongerThan.ts index 73108dada8..22465c35b6 100644 --- a/sample/sample6-custom-decorator/IsLongerThan.ts +++ b/sample/sample6-custom-decorator/IsLongerThan.ts @@ -1,8 +1,8 @@ -import {registerDecorator} from "../../src/index"; import {ValidationOptions} from "../../src/decorator/ValidationOptions"; import {ValidatorConstraintInterface} from "../../src/validation/ValidatorConstraintInterface"; import {ValidatorConstraint} from "../../src/decorator/ValidatorConstraint"; import {ValidationArguments} from "../../src/validation/ValidationArguments"; +import {registerDecorator} from "../../src/register-decorator"; export function IsLongerThan(property: string, validationOptions?: ValidationOptions) { return function (object: Object, propertyName: string) { diff --git a/sample/sample6-custom-decorator/IsUserAlreadyExist.ts b/sample/sample6-custom-decorator/IsUserAlreadyExist.ts index 49474e9c61..e73380d819 100644 --- a/sample/sample6-custom-decorator/IsUserAlreadyExist.ts +++ b/sample/sample6-custom-decorator/IsUserAlreadyExist.ts @@ -1,6 +1,6 @@ -import {registerDecorator} from "../../src/index"; import {ValidationOptions} from "../../src/decorator/ValidationOptions"; import {ValidationArguments} from "../../src/validation/ValidationArguments"; +import {registerDecorator} from "../../src/register-decorator"; export function IsUserAlreadyExist(validationOptions?: ValidationOptions) { return function (object: Object, propertyName: string) { @@ -23,4 +23,4 @@ export function IsUserAlreadyExist(validationOptions?: ValidationOptions) { } }); }; -} \ No newline at end of file +} diff --git a/src/decorator/IsBoolean.ts b/src/decorator/IsBoolean.ts index 2c9339f044..5aad0d081c 100644 --- a/src/decorator/IsBoolean.ts +++ b/src/decorator/IsBoolean.ts @@ -1,9 +1,5 @@ import {ValidationOptions} from "./ValidationOptions"; -import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; -import {getFromContainer, MetadataStorage, ValidationTypes} from ".."; -import {ValidationMetadata} from "../metadata/ValidationMetadata"; import {buildMessage, ValidateBy} from "./ValidateBy"; -import {equals} from "./Equals"; /** * Checks if a given value is a real boolean. diff --git a/src/decorator/IsEmpty.ts b/src/decorator/IsEmpty.ts index c78f289e76..8de37125a4 100644 --- a/src/decorator/IsEmpty.ts +++ b/src/decorator/IsEmpty.ts @@ -1,9 +1,5 @@ import {ValidationOptions} from "./ValidationOptions"; -import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; -import {getFromContainer, MetadataStorage, ValidationTypes} from ".."; -import {ValidationMetadata} from "../metadata/ValidationMetadata"; import {buildMessage, ValidateBy} from "./ValidateBy"; -import {equals} from "./Equals"; /** * Checks if given value is empty (=== '', === null, === undefined). diff --git a/src/decorator/IsIn.ts b/src/decorator/IsIn.ts index f9e67533a3..d50785ce94 100644 --- a/src/decorator/IsIn.ts +++ b/src/decorator/IsIn.ts @@ -1,9 +1,5 @@ import {ValidationOptions} from "./ValidationOptions"; -import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; -import {getFromContainer, MetadataStorage, ValidationTypes} from ".."; -import {ValidationMetadata} from "../metadata/ValidationMetadata"; import {buildMessage, ValidateBy} from "./ValidateBy"; -import {equals} from "./Equals"; /** * Checks if given value is in a array of allowed values. diff --git a/src/decorator/IsNotEmpty.ts b/src/decorator/IsNotEmpty.ts index f15899df18..201ffd0511 100644 --- a/src/decorator/IsNotEmpty.ts +++ b/src/decorator/IsNotEmpty.ts @@ -1,9 +1,5 @@ import {ValidationOptions} from "./ValidationOptions"; -import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; -import {getFromContainer, MetadataStorage, ValidationTypes} from ".."; -import {ValidationMetadata} from "../metadata/ValidationMetadata"; import {buildMessage, ValidateBy} from "./ValidateBy"; -import {isEmpty} from "./IsEmpty"; /** * Checks if given value is not empty (!== '', !== null, !== undefined). diff --git a/src/decorator/IsNotIn.ts b/src/decorator/IsNotIn.ts index d4caa99fc4..c27ccdad31 100644 --- a/src/decorator/IsNotIn.ts +++ b/src/decorator/IsNotIn.ts @@ -1,9 +1,5 @@ import {ValidationOptions} from "./ValidationOptions"; -import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; -import {getFromContainer, MetadataStorage, ValidationTypes} from ".."; -import {ValidationMetadata} from "../metadata/ValidationMetadata"; import {buildMessage, ValidateBy} from "./ValidateBy"; -import {equals} from "./Equals"; /** * Checks if given value not in a array of allowed values. diff --git a/src/decorator/IsNumber.ts b/src/decorator/IsNumber.ts index 6782483658..c5de9a3f6e 100644 --- a/src/decorator/IsNumber.ts +++ b/src/decorator/IsNumber.ts @@ -1,4 +1,4 @@ -import {ValidationOptions} from ".."; +import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; /** diff --git a/src/decorator/NotEquals.ts b/src/decorator/NotEquals.ts index 7a71431cbe..dc7151feb4 100644 --- a/src/decorator/NotEquals.ts +++ b/src/decorator/NotEquals.ts @@ -1,7 +1,4 @@ import {ValidationOptions} from "./ValidationOptions"; -import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; -import {getFromContainer, MetadataStorage, ValidationTypes} from ".."; -import {ValidationMetadata} from "../metadata/ValidationMetadata"; import {buildMessage, ValidateBy} from "./ValidateBy"; /** diff --git a/src/decorator/Validate.ts b/src/decorator/Validate.ts index 0f82b43140..b58c9806c0 100644 --- a/src/decorator/Validate.ts +++ b/src/decorator/Validate.ts @@ -1,7 +1,9 @@ import {ValidationOptions} from "./ValidationOptions"; import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; -import {getFromContainer, MetadataStorage, ValidationTypes} from ".."; import {ValidationMetadata} from "../metadata/ValidationMetadata"; +import {MetadataStorage} from "../metadata/MetadataStorage"; +import {ValidationTypes} from "../validation/ValidationTypes"; +import {getFromContainer} from "../container"; /** * Performs validation based on the given custom validation class. diff --git a/src/decorator/ValidateBy.ts b/src/decorator/ValidateBy.ts index d910f80475..c19cf4d815 100644 --- a/src/decorator/ValidateBy.ts +++ b/src/decorator/ValidateBy.ts @@ -1,8 +1,8 @@ -// ------------------------------------------------------------------------- import {ValidationFunction} from "./ValidationFunction"; import {ValidationOptions} from "./ValidationOptions"; import {registerDecorator} from "../register-decorator"; -import {ValidationArguments, ValidatorConstraintInterface} from ".."; +import {ValidationArguments} from "../validation/ValidationArguments"; +import {ValidatorConstraintInterface} from "../validation/ValidatorConstraintInterface"; export function buildMessage(impl: (eachPrefix: string) => string, validationOptions?: ValidationOptions): (validationArguments?: ValidationArguments) => string { diff --git a/src/decorator/ValidationFunction.ts b/src/decorator/ValidationFunction.ts index 2898e04f1f..4e6495dac8 100644 --- a/src/decorator/ValidationFunction.ts +++ b/src/decorator/ValidationFunction.ts @@ -1,4 +1,4 @@ -import {ValidationArguments} from "../index"; +import {ValidationArguments} from "../validation/ValidationArguments"; export interface ValidationFunction { name: string; diff --git a/src/decorator/ValidatorConstraint.ts b/src/decorator/ValidatorConstraint.ts index e0cea83ed5..035767b094 100644 --- a/src/decorator/ValidatorConstraint.ts +++ b/src/decorator/ValidatorConstraint.ts @@ -1,6 +1,6 @@ import {ConstraintMetadata} from "../metadata/ConstraintMetadata"; import {getFromContainer} from "../container"; -import {MetadataStorage} from ".."; +import {MetadataStorage} from "../metadata/MetadataStorage"; /** * Registers custom validator class. diff --git a/src/decorator/decorators.ts b/src/decorator/decorators.ts index 3fd75eb243..69f95cf2e3 100644 --- a/src/decorator/decorators.ts +++ b/src/decorator/decorators.ts @@ -1,15 +1,15 @@ -import {ValidationTypes} from ".."; +import {ValidationTypes} from "../validation/ValidationTypes"; import { IsCurrencyOptions, IsEmailOptions, IsFQDNOptions, IsURLOptions -} from ".."; +} from "../validation/ValidationTypeOptions"; import {ValidationOptions} from "./ValidationOptions"; import {ValidationMetadata} from "../metadata/ValidationMetadata"; import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; import {getFromContainer} from "../container"; -import {MetadataStorage} from ".."; +import {MetadataStorage} from "../metadata/MetadataStorage"; // ------------------------------------------------------------------------- // System diff --git a/src/index.ts b/src/index.ts index ac5b35d2e1..d3ec4a10a0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,19 +9,20 @@ import {getFromContainer} from "./container"; // Export everything api users needs // ------------------------------------------------------------------------- -export * from "./container"; -export * from "./decorator/decorators"; -export * from "./decorator/ValidationOptions"; -export * from "./validation/ValidatorConstraintInterface"; -export * from "./validation/ValidationError"; -export * from "./validation/ValidationTypeOptions"; -export * from "./validation/ValidatorOptions"; -export * from "./validation/ValidationArguments"; -export * from "./validation/ValidationTypes"; -export * from "./validation/Validator"; -export * from "./validation-schema/ValidationSchema"; -export * from "./register-decorator"; -export * from "./metadata/MetadataStorage"; +// export * from "./container"; +// export * from "./decorator/decorators"; +// export * from "./decorator/ValidationOptions"; +// export * from "./validation/ValidatorConstraintInterface"; +// export * from "./validation/ValidationError"; +// export * from "./validation/ValidationTypeOptions"; +// export * from "./validation/ValidatorOptions"; +// export * from "./validation/ValidationArguments"; +// export * from "./validation/ValidationTypes"; +// export * from "./validation/Validator"; +// export * from "./validation-schema/ValidationSchema"; +// export * from "./register-decorator"; +// export * from "./metadata/MetadataStorage"; +// FIXME: re-add exports above and all decorators here? // ------------------------------------------------------------------------- // Shortcut methods for api users @@ -108,11 +109,3 @@ export function validateSync(schemaNameOrObject: Object|string, export function registerSchema(schema: ValidationSchema): void { getFromContainer(MetadataStorage).addValidationSchema(schema); } -export {Equals} from "./decorator/Equals"; -export {NotEquals} from "./decorator/NotEquals"; -export {IsEmpty} from "./decorator/IsEmpty"; -export {IsNotEmpty} from "./decorator/IsNotEmpty"; -export {IsIn} from "./decorator/IsIn"; -export {IsNotIn} from "./decorator/IsNotIn"; -export {IsPhoneNumber} from "./decorator/IsPhoneNumber"; -export {IsBoolean} from "./decorator/IsBoolean"; diff --git a/src/validation/Validator.ts b/src/validation/Validator.ts index 1236bf37f5..ef03737f4d 100644 --- a/src/validation/Validator.ts +++ b/src/validation/Validator.ts @@ -4,7 +4,7 @@ import {ValidationError} from "./ValidationError"; import {IsNumberOptions} from "./ValidationTypeOptions"; import {ValidatorOptions} from "./ValidatorOptions"; import {ValidationExecutor} from "./ValidationExecutor"; -import {ValidationOptions} from ".."; +import {ValidationOptions} from "../decorator/ValidationOptions"; /** * Validator performs validation of the given object based on its metadata. diff --git a/src/validation/ValidatorConstraintInterface.ts b/src/validation/ValidatorConstraintInterface.ts index 5d485bd0df..b526a9608c 100644 --- a/src/validation/ValidatorConstraintInterface.ts +++ b/src/validation/ValidatorConstraintInterface.ts @@ -14,4 +14,4 @@ export interface ValidatorConstraintInterface { */ defaultMessage?(validationArguments?: ValidationArguments): string; -} \ No newline at end of file +} diff --git a/test/functional/validation-options.spec.ts b/test/functional/validation-options.spec.ts index 77eb07faee..34303d8f1d 100644 --- a/test/functional/validation-options.spec.ts +++ b/test/functional/validation-options.spec.ts @@ -1,10 +1,8 @@ import "es6-shim"; import {Contains, Matches, MinLength, ValidateNested} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; -import {ValidationError} from "../../src"; - -import {should, use } from "chai"; - +import {ValidationError} from "../../src/validation/ValidationError"; +import {should, use} from "chai"; import * as chaiAsPromised from "chai-as-promised"; should(); From 246893067af3a53057efb2b515cdc78eb760282d Mon Sep 17 00:00:00 2001 From: Christoph Linder Date: Thu, 18 Oct 2018 01:35:22 +0200 Subject: [PATCH 05/12] API breaking changes require major version bump => version 1.0.0-rc --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index acab62ecf2..b53271c22b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "class-validator", "private": true, - "version": "0.9.1-rc1", + "version": "1.0.0-rc", "description": "Class-based validation with Typescript / ES6 / ES5 using decorators or validation schemas. Supports both node.js and browser", "license": "MIT", "readmeFilename": "README.md", From 1320d29df003adb85d3ba006f33d773e7c1d3861 Mon Sep 17 00:00:00 2001 From: Christoph Linder Date: Tue, 13 Nov 2018 00:26:34 +0100 Subject: [PATCH 06/12] Smaller bundle - rebase onto origin/master, fix conflicts --- package.json | 1 - src/decorator/IsDateString.ts | 2 +- src/decorator/decorators.ts | 6 ------ 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/package.json b/package.json index b53271c22b..203a64db0c 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,6 @@ "typescript-validator" ], "dependencies": { - "@types/validator": "9.4.2", "google-libphonenumber": "^3.1.6", "validator": "10.4.0" }, diff --git a/src/decorator/IsDateString.ts b/src/decorator/IsDateString.ts index 070796d6e6..fd420b6225 100644 --- a/src/decorator/IsDateString.ts +++ b/src/decorator/IsDateString.ts @@ -6,7 +6,7 @@ import {isString} from "./IsString"; * Checks if a given value is a ISOString date. */ export function isDateString(value: any): boolean { - const regex = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z|\+[0-2]\d(?:\:[0-5]\d)?)?/g; + const regex = /^\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z|\+[0-2]\d(?:\:[0-5]\d)?)?$/g; return isString(value) && regex.test(value); } diff --git a/src/decorator/decorators.ts b/src/decorator/decorators.ts index 69f95cf2e3..fa1591c907 100644 --- a/src/decorator/decorators.ts +++ b/src/decorator/decorators.ts @@ -1,10 +1,4 @@ import {ValidationTypes} from "../validation/ValidationTypes"; -import { - IsCurrencyOptions, - IsEmailOptions, - IsFQDNOptions, - IsURLOptions -} from "../validation/ValidationTypeOptions"; import {ValidationOptions} from "./ValidationOptions"; import {ValidationMetadata} from "../metadata/ValidationMetadata"; import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; From 390786353650bc84db24c0cefc67e7c4bf1ad161 Mon Sep 17 00:00:00 2001 From: Christoph Linder Date: Tue, 13 Nov 2018 02:57:58 +0100 Subject: [PATCH 07/12] Smaller bundle - next bunch of migrations... --- sample/sample1-simple-validation/Post.ts | 3 +- sample/sample2-using-groups/Post.ts | 3 +- sample/sample7-inheritance-support/Post.ts | 3 +- src/decorator/Contains.ts | 25 +++++ src/decorator/IsBooleanString.ts | 24 +++++ src/decorator/IsNumberString.ts | 24 +++++ src/decorator/decorators.ts | 49 ---------- src/validation/ValidationTypes.ts | 15 +-- src/validation/Validator.ts | 35 ------- test/functional/custom-decorators.spec.ts | 96 ++++++++++++------- test/functional/inherited-validation.spec.ts | 5 +- test/functional/nested-validation.spec.ts | 4 +- test/functional/reject-validation.spec.ts | 2 +- ...alidation-functions-and-decorators.spec.ts | 18 ++-- test/functional/validation-options.spec.ts | 3 +- 15 files changed, 158 insertions(+), 151 deletions(-) create mode 100644 src/decorator/Contains.ts create mode 100644 src/decorator/IsBooleanString.ts create mode 100644 src/decorator/IsNumberString.ts diff --git a/sample/sample1-simple-validation/Post.ts b/sample/sample1-simple-validation/Post.ts index e97c77ebac..6608748665 100644 --- a/sample/sample1-simple-validation/Post.ts +++ b/sample/sample1-simple-validation/Post.ts @@ -1,7 +1,8 @@ -import {Contains, MinLength, MaxLength, IsEmail, IsFQDN, ArrayNotEmpty, ArrayMinSize, ArrayMaxSize} from "../../src/decorator/decorators"; +import {MinLength, MaxLength, IsEmail, IsFQDN, ArrayNotEmpty, ArrayMinSize, ArrayMaxSize} from "../../src/decorator/decorators"; import {IsDate} from "../../src/decorator/IsDate"; import {IsInt} from "../../src/decorator/IsInt"; import {IsEnum} from "../../src/decorator/IsEnum"; +import {Contains} from "../../src/decorator/Contains"; export enum PostType { Public, diff --git a/sample/sample2-using-groups/Post.ts b/sample/sample2-using-groups/Post.ts index d6d0e05e97..dcc3bd2571 100644 --- a/sample/sample2-using-groups/Post.ts +++ b/sample/sample2-using-groups/Post.ts @@ -1,6 +1,7 @@ -import {Contains, Length, IsEmail, IsFQDN} from "../../src/decorator/decorators"; +import {Length, IsEmail, IsFQDN} from "../../src/decorator/decorators"; import {IsDate} from "../../src/decorator/IsDate"; import {IsInt} from "../../src/decorator/IsInt"; +import {Contains} from "../../src/decorator/Contains"; export class Post { diff --git a/sample/sample7-inheritance-support/Post.ts b/sample/sample7-inheritance-support/Post.ts index 87722161fc..9961c96bb1 100644 --- a/sample/sample7-inheritance-support/Post.ts +++ b/sample/sample7-inheritance-support/Post.ts @@ -1,6 +1,7 @@ -import {Contains, MinLength, MaxLength} from "../../src/decorator/decorators"; +import {MinLength, MaxLength} from "../../src/decorator/decorators"; import {BaseContent} from "./BaseContent"; import {IsInt} from "../../src/decorator/IsInt"; +import {Contains} from "../../src/decorator/Contains"; export class Post extends BaseContent { diff --git a/src/decorator/Contains.ts b/src/decorator/Contains.ts new file mode 100644 index 0000000000..f15e9f19f9 --- /dev/null +++ b/src/decorator/Contains.ts @@ -0,0 +1,25 @@ +import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "./ValidationOptions"; +import validatorJsContains = require("validator/lib/contains"); + +/** + * Checks if the string contains the seed. + * If given value is not a string, then it returns false. + */ +export function contains(value: string, seed: string): boolean { + return typeof value === "string" && validatorJsContains(value, seed); +} + +/** + * Checks if the string contains the seed. + */ +export function Contains(seed: string, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "contains", + validate: (value, args) => contains(value, args.constraints[0]), + constraints: [seed], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain a $constraint1 string", validationOptions), + }, + validationOptions + ); +} diff --git a/src/decorator/IsBooleanString.ts b/src/decorator/IsBooleanString.ts new file mode 100644 index 0000000000..6fc4b4c50e --- /dev/null +++ b/src/decorator/IsBooleanString.ts @@ -0,0 +1,24 @@ +import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "./ValidationOptions"; +import validatorJsIsBoolean = require("validator/lib/isBoolean"); + +/** + * Checks if a string is a boolean. + * If given value is not a string, then it returns false. + */ +export function isBooleanString(value: string): boolean { + return typeof value === "string" && validatorJsIsBoolean(value); +} + +/** + * Checks if a string is a boolean. + */ +export function IsBooleanString(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isBooleanString", + validate: (value) => isBooleanString(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + eachPrefix + "$property must be a boolean string", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsNumberString.ts b/src/decorator/IsNumberString.ts new file mode 100644 index 0000000000..722aae97cd --- /dev/null +++ b/src/decorator/IsNumberString.ts @@ -0,0 +1,24 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsNumeric = require("validator/lib/isNumeric"); + +/** + * Checks if the string is numeric. + * If given value is not a string, then it returns false. + */ +export function isNumberString(value: string, options?: ValidatorJS.IsNumericOptions): boolean { + return typeof value === "string" && validatorJsIsNumeric(value, options); +} + +/** + * Checks if the string is a number. + */ +export function IsNumberString(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isNumberString", + validate: (value) => isNumberString(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a number string", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/decorators.ts b/src/decorator/decorators.ts index fa1591c907..01d1c39f2c 100644 --- a/src/decorator/decorators.ts +++ b/src/decorator/decorators.ts @@ -86,59 +86,10 @@ export function IsOptional(validationOptions?: ValidationOptions) { }; } -// ------------------------------------------------------------------------- -// String-as-types checkers -// ------------------------------------------------------------------------- - -/** - * Checks if a string is a boolean. - */ -export function IsBooleanString(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_BOOLEAN_STRING, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is a number. - */ -export function IsNumberString(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_NUMBER_STRING, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - // ------------------------------------------------------------------------- // String checkers // ------------------------------------------------------------------------- -/** - * Checks if the string contains the seed. - */ -export function Contains(seed: string, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.CONTAINS, - target: object.constructor, - propertyName: propertyName, - constraints: [seed], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} /** * Checks if the string does not contain the seed. diff --git a/src/validation/ValidationTypes.ts b/src/validation/ValidationTypes.ts index f875c2f4be..78d85f88f0 100644 --- a/src/validation/ValidationTypes.ts +++ b/src/validation/ValidationTypes.ts @@ -10,15 +10,10 @@ export class ValidationTypes { static NESTED_VALIDATION = "nestedValidation"; static CONDITIONAL_VALIDATION = "conditionalValidation"; static WHITELIST = "whitelistValidation"; - // FIXME: delete + // FIXME: delete? static IS_DEFINED = "isDefined"; - /* string-as-type checkers */ - static IS_BOOLEAN_STRING = "isBooleanString"; - static IS_NUMBER_STRING = "isNumberString"; - /* string checkers */ - static CONTAINS = "contains"; static NOT_CONTAINS = "notContains"; static IS_ALPHA = "isAlpha"; static IS_ALPHANUMERIC = "isAlphanumeric"; @@ -86,15 +81,7 @@ export class ValidationTypes { case this.IS_DEFINED: return eachPrefix + "$property should not be null or undefined"; - /* string-as-type checkers */ - case this.IS_BOOLEAN_STRING: - return eachPrefix + "$property must be a boolean string"; - case this.IS_NUMBER_STRING: - return eachPrefix + "$property must be a number string"; - /* string checkers */ - case this.CONTAINS: - return eachPrefix + "$property must contain a $constraint1 string"; case this.NOT_CONTAINS: return eachPrefix + "$property should not contain a $constraint1 string"; case this.IS_ALPHA: diff --git a/src/validation/Validator.ts b/src/validation/Validator.ts index ef03737f4d..830e8b1477 100644 --- a/src/validation/Validator.ts +++ b/src/validation/Validator.ts @@ -111,15 +111,7 @@ export class Validator { case ValidationTypes.IS_DEFINED: return this.isDefined(value); - /* string-as-type checkers */ - case ValidationTypes.IS_BOOLEAN_STRING: - return this.isBooleanString(value); - case ValidationTypes.IS_NUMBER_STRING: - return this.isNumberString(value); - /* string checkers */ - case ValidationTypes.CONTAINS: - return this.contains(value, metadata.constraints[0]); case ValidationTypes.NOT_CONTAINS: return this.notContains(value, metadata.constraints[0]); case ValidationTypes.IS_ALPHA: @@ -218,37 +210,10 @@ export class Validator { return value !== undefined && value !== null; } - // ------------------------------------------------------------------------- - // Validation Methods: string-as-type checkers - // ------------------------------------------------------------------------- - - /** - * Checks if a string is a boolean. - * If given value is not a string, then it returns false. - */ - isBooleanString(value: string): boolean { - return typeof value === "string" && this.validatorJs.isBoolean(value); - } - - /** - * Checks if the string is numeric. - * If given value is not a string, then it returns false. - */ - isNumberString(value: string, options?: ValidatorJS.IsNumericOptions): boolean { - return typeof value === "string" && this.validatorJs.isNumeric(value, options); - } - // ------------------------------------------------------------------------- // Validation Methods: string checkers // ------------------------------------------------------------------------- - /** - * Checks if the string contains the seed. - * If given value is not a string, then it returns false. - */ - contains(value: string, seed: string): boolean { - return typeof value === "string" && this.validatorJs.contains(value, seed); - } /** * Checks if the string does not contain the seed. diff --git a/test/functional/custom-decorators.spec.ts b/test/functional/custom-decorators.spec.ts index 754ab84e31..55a166d14f 100644 --- a/test/functional/custom-decorators.spec.ts +++ b/test/functional/custom-decorators.spec.ts @@ -6,11 +6,11 @@ import {ValidationOptions} from "../../src/decorator/ValidationOptions"; import {ValidatorConstraint} from "../../src/decorator/ValidatorConstraint"; import {ValidatorConstraintInterface} from "../../src/validation/ValidatorConstraintInterface"; -import {should, use } from "chai"; +import {should as chaiShould, use} from "chai"; import * as chaiAsPromised from "chai-as-promised"; -should(); +const should = chaiShould(); use(chaiAsPromised); // ------------------------------------------------------------------------- @@ -23,9 +23,9 @@ const validator = new Validator(); // Specifications: common decorators // ------------------------------------------------------------------------- -describe("custom decorators", function() { +describe("custom decorators", function () { - describe("decorator with inline validation", function() { + describe("decorator with inline validation", function () { function IsLongerThan(property: string, validationOptions?: ValidationOptions) { return function (object: Object, propertyName: string) { @@ -41,7 +41,7 @@ describe("custom decorators", function() { const relatedValue = (args.object as any)[relatedPropertyName]; if (relatedValue === undefined || relatedValue === null) return true; - + return typeof value === "string" && typeof relatedValue === "string" && value.length > relatedValue.length; @@ -50,17 +50,17 @@ describe("custom decorators", function() { }); }; } - + class MyClass { @IsLongerThan("lastName", { message: "$property must be longer then $constraint1. Given value: $value" }) firstName: string; - + lastName: string; } - it("if firstName is not empty and lastLame is empty then it should succeed", function() { + it("if firstName is not empty and lastLame is empty then it should succeed", function () { const model = new MyClass(); model.firstName = "hell no world"; return validator.validate(model).then(errors => { @@ -68,29 +68,29 @@ describe("custom decorators", function() { }); }); - it("if firstName is empty and lastLame is not empty then it should fail", function() { + it("if firstName is empty and lastLame is not empty then it should fail", function () { const model = new MyClass(); model.firstName = ""; model.lastName = "Kim"; return validator.validate(model).then(errors => { errors.length.should.be.equal(1); - errors[0].constraints.should.be.eql({ isLongerThan: "firstName must be longer then lastName. Given value: " }); + errors[0].constraints.should.be.eql({isLongerThan: "firstName must be longer then lastName. Given value: "}); }); }); - it("if firstName is shorter then lastLame then it should fail", function() { + it("if firstName is shorter then lastLame then it should fail", function () { const model = new MyClass(); model.firstName = "Li"; model.lastName = "Kim"; return validator.validate(model).then(errors => { errors.length.should.be.equal(1); - errors[0].constraints.should.be.eql({ isLongerThan: "firstName must be longer then lastName. Given value: Li" }); + errors[0].constraints.should.be.eql({isLongerThan: "firstName must be longer then lastName. Given value: Li"}); }); }); - + }); - - describe("decorator with default message", function() { + + describe("decorator with default message", function () { function IsLonger(property: string, validationOptions?: ValidationOptions) { return function (object: Object, propertyName: string) { @@ -106,7 +106,7 @@ describe("custom decorators", function() { const relatedValue = (args.object as any)[relatedPropertyName]; if (relatedValue === undefined || relatedValue === null) return true; - + return typeof value === "string" && typeof relatedValue === "string" && value.length > relatedValue.length; @@ -118,15 +118,15 @@ describe("custom decorators", function() { }); }; } - + class SecondClass { @IsLonger("lastName") firstName: string; - + lastName: string; } - it("if firstName is not empty and lastLame is empty then it should succeed", function() { + it("if firstName is not empty and lastLame is empty then it should succeed", function () { const model = new SecondClass(); model.firstName = "hell no world"; return validator.validate(model).then(errors => { @@ -134,31 +134,31 @@ describe("custom decorators", function() { }); }); - it("if firstName is empty and lastLame is not empty then it should fail", function() { + it("if firstName is empty and lastLame is not empty then it should fail", function () { const model = new SecondClass(); model.firstName = ""; model.lastName = "Kim"; return validator.validate(model).then(errors => { errors.length.should.be.equal(1); - errors[0].constraints.should.be.eql({ isLonger: "firstName must be longer then lastName" }); + errors[0].constraints.should.be.eql({isLonger: "firstName must be longer then lastName"}); }); }); - it("if firstName is shorter then lastLame then it should fail", function() { + it("if firstName is shorter then lastLame then it should fail", function () { const model = new SecondClass(); model.firstName = "Li"; model.lastName = "Kim"; return validator.validate(model).then(errors => { errors.length.should.be.equal(1); - errors[0].constraints.should.be.eql({ isLonger: "firstName must be longer then lastName" }); + errors[0].constraints.should.be.eql({isLonger: "firstName must be longer then lastName"}); }); }); - + }); - describe("decorator with separate validation constraint class", function() { + describe("decorator with separate validation constraint class", function () { - @ValidatorConstraint({ name: "isShortenThan" }) + @ValidatorConstraint({name: "isShortenThan"}) class IsShortenThanConstraint implements ValidatorConstraintInterface { validate(value: any, args: ValidationArguments) { @@ -166,10 +166,10 @@ describe("custom decorators", function() { const relatedValue = (args.object as any)[relatedPropertyName]; if (value === null || value === undefined) return true; - - return typeof value === "string" && - typeof relatedValue === "string" && - value.length < relatedValue.length; + + return typeof value === "string" && + typeof relatedValue === "string" && + value.length < relatedValue.length; } } @@ -195,7 +195,7 @@ describe("custom decorators", function() { lastName: string; } - it("if firstName is not empty and lastLame is empty then it should succeed", function() { + it("if firstName is not empty and lastLame is empty then it should succeed", function () { const model = new MyClass(); model.firstName = "hell no world"; return validator.validate(model).then(errors => { @@ -203,26 +203,52 @@ describe("custom decorators", function() { }); }); - it("if firstName is empty and lastLame is not empty then it should fail", function() { + it("if firstName is empty and lastLame is not empty then it should fail", function () { const model = new MyClass(); model.firstName = ""; model.lastName = "Kim"; return validator.validate(model).then(errors => { errors.length.should.be.equal(1); - errors[0].constraints.should.be.eql({ isShortenThan: "lastName must be shorter then firstName. Given value: Kim" }); + errors[0].constraints.should.be.eql({isShortenThan: "lastName must be shorter then firstName. Given value: Kim"}); + should.not.exist(errors[0].contexts); }); }); - it("if firstName is shorter then lastLame then it should fail", function() { + it("if firstName is shorter then lastLame then it should fail", function () { const model = new MyClass(); model.firstName = "Li"; model.lastName = "Kim"; return validator.validate(model).then(errors => { errors.length.should.be.equal(1); - errors[0].constraints.should.be.eql({ isShortenThan: "lastName must be shorter then firstName. Given value: Kim" }); + errors[0].constraints.should.be.eql({isShortenThan: "lastName must be shorter then firstName. Given value: Kim"}); + should.not.exist(errors[0].contexts); }); }); + describe("with context", () => { + class MyClass { + firstName: string; + + @IsShortenThan("firstName", { + message: "$property must be shorter then $constraint1. Given value: $value", + context: {foo: "bar"} + }) + lastName: string; + } + + it("if firstName is shorter then lastLame then error should contain context", function () { + const model = new MyClass(); + model.firstName = "Li"; + model.lastName = "Kim"; + return validator.validate(model).then(errors => { + errors.length.should.be.equal(1); + errors[0].constraints.should.be.eql({isShortenThan: "lastName must be shorter then firstName. Given value: Kim"}); + errors[0].contexts["isShortenThan"].should.be.eql({foo: "bar"}); + }); + }); + + }); + }); }); diff --git a/test/functional/inherited-validation.spec.ts b/test/functional/inherited-validation.spec.ts index 23494b5c71..27f97b36b9 100644 --- a/test/functional/inherited-validation.spec.ts +++ b/test/functional/inherited-validation.spec.ts @@ -1,10 +1,11 @@ import "es6-shim"; -import {Contains, MinLength} from "../../src/decorator/decorators"; +import {MinLength} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; import {should, use } from "chai"; import * as chaiAsPromised from "chai-as-promised"; +import {Contains} from "../../src/decorator/Contains"; should(); use(chaiAsPromised); @@ -53,4 +54,4 @@ describe("inherited validation", function() { }); }); -}); \ No newline at end of file +}); diff --git a/test/functional/nested-validation.spec.ts b/test/functional/nested-validation.spec.ts index 40b551e6e4..2f4d661c31 100644 --- a/test/functional/nested-validation.spec.ts +++ b/test/functional/nested-validation.spec.ts @@ -1,13 +1,13 @@ import "es6-shim"; -import {Contains, IsDefined, MinLength, ValidateNested} from "../../src/decorator/decorators"; +import {IsDefined, MinLength, ValidateNested} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; import {expect} from "chai"; -import {inspect} from "util"; import {ValidationTypes} from "../../src/validation/ValidationTypes"; import {should, use } from "chai"; import * as chaiAsPromised from "chai-as-promised"; +import {Contains} from "../../src/decorator/Contains"; should(); use(chaiAsPromised); diff --git a/test/functional/reject-validation.spec.ts b/test/functional/reject-validation.spec.ts index b3d35a5a5d..c2432fd414 100644 --- a/test/functional/reject-validation.spec.ts +++ b/test/functional/reject-validation.spec.ts @@ -1,13 +1,13 @@ import "es6-shim"; import { ValidationError } from "./../../src/validation/ValidationError"; -import { Contains, MinLength } from "../../src/decorator/decorators"; import { Validator } from "../../src/validation/Validator"; import { expect } from "chai"; import {should, use } from "chai"; import * as chaiAsPromised from "chai-as-promised"; +import {Contains} from "../../src/decorator/Contains"; should(); use(chaiAsPromised); diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts index f2597f2118..9188a7c8a3 100644 --- a/test/functional/validation-functions-and-decorators.spec.ts +++ b/test/functional/validation-functions-and-decorators.spec.ts @@ -1,8 +1,6 @@ import "es6-shim"; import {expect} from "chai"; import { - IsBooleanString, - Contains, IsAlpha, IsAlphanumeric, IsAscii, @@ -25,7 +23,6 @@ import { IsLowercase, IsMongoId, IsMultibyte, - IsNumberString, IsSurrogatePair, IsUrl, IsUUID, @@ -71,6 +68,9 @@ import {Min, min} from "../../src/decorator/Min"; import {Max, max} from "../../src/decorator/Max"; import {minDate, MinDate} from "../../src/decorator/MinDate"; import {maxDate, MaxDate} from "../../src/decorator/MaxDate"; +import {isBooleanString, IsBooleanString} from "../../src/decorator/IsBooleanString"; +import {IsNumberString, isNumberString} from "../../src/decorator/IsNumberString"; +import {Contains, contains} from "../../src/decorator/Contains"; should(); use(chaiAsPromised); @@ -1104,11 +1104,11 @@ describe("IsBooleanString", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isBooleanString(value).should.be.true); + validValues.forEach(value => isBooleanString(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isBooleanString(value).should.be.false); + invalidValues.forEach(value => isBooleanString(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1149,11 +1149,11 @@ describe("IsNumberString", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isNumberString(value).should.be.true); + validValues.forEach(value => isNumberString(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isNumberString(value).should.be.false); + invalidValues.forEach(value => isNumberString(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1188,11 +1188,11 @@ describe("Contains", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.contains(value, constraint).should.be.true); + validValues.forEach(value => contains(value, constraint).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.contains(value, constraint).should.be.false); + invalidValues.forEach(value => contains(value, constraint).should.be.false); }); it("should return error object with proper data", function(done) { diff --git a/test/functional/validation-options.spec.ts b/test/functional/validation-options.spec.ts index 34303d8f1d..93f6512657 100644 --- a/test/functional/validation-options.spec.ts +++ b/test/functional/validation-options.spec.ts @@ -1,9 +1,10 @@ import "es6-shim"; -import {Contains, Matches, MinLength, ValidateNested} from "../../src/decorator/decorators"; +import {Matches, MinLength, ValidateNested} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; import {ValidationError} from "../../src/validation/ValidationError"; import {should, use} from "chai"; import * as chaiAsPromised from "chai-as-promised"; +import {Contains} from "../../src/decorator/Contains"; should(); use(chaiAsPromised); From 86079d8d2f7c37ce8d12f93243fdf59a3e2a8ce0 Mon Sep 17 00:00:00 2001 From: Christoph Linder Date: Tue, 13 Nov 2018 02:58:21 +0100 Subject: [PATCH 08/12] fix "context" for custom validators --- src/metadata/ValidationMetadataArgs.ts | 6 ++++++ src/register-decorator.ts | 12 ++++++++++-- src/validation/ValidationExecutor.ts | 24 +++++++++++++++++------- src/validation/ValidatorOptions.ts | 7 ++++++- 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/metadata/ValidationMetadataArgs.ts b/src/metadata/ValidationMetadataArgs.ts index 131efdd620..0278944349 100644 --- a/src/metadata/ValidationMetadataArgs.ts +++ b/src/metadata/ValidationMetadataArgs.ts @@ -39,4 +39,10 @@ export interface ValidationMetadataArgs { * Extra options specific to validation type. */ validationTypeOptions?: any; + + /** + * A transient set of data passed through to the validation result for response mapping + */ + context?: any; + } diff --git a/src/register-decorator.ts b/src/register-decorator.ts index cdf6ca38ff..c7a9186039 100644 --- a/src/register-decorator.ts +++ b/src/register-decorator.ts @@ -51,11 +51,18 @@ export interface ValidationDecoratorOptions { */ export function registerDecorator(options: ValidationDecoratorOptions): void { + let name; let constraintCls: Function; if (options.validator instanceof Function) { constraintCls = options.validator as Function; + const constraintClasses = getFromContainer(MetadataStorage).getTargetValidatorConstraints(options.validator); + if (constraintClasses.length !== 1) { + throw `More than one implementation of ValidatorConstraintInterface found for validator on: ${options.target}:${options.propertyName}`; + } + name = options.name || constraintClasses[0].name; } else { const validator = options.validator as ValidatorConstraintInterface; + name = options.name; constraintCls = class CustomConstraint implements ValidatorConstraintInterface { validate(value: any, validationArguments?: ValidationArguments): Promise|boolean { return validator.validate(value, validationArguments); @@ -73,12 +80,13 @@ export function registerDecorator(options: ValidationDecoratorOptions): void { } const validationMetadataArgs: ValidationMetadataArgs = { - type: ValidationTypes.CUSTOM_VALIDATION, + type: name || ValidationTypes.CUSTOM_VALIDATION, target: options.target, propertyName: options.propertyName, validationOptions: options.options, constraintCls: constraintCls, - constraints: options.constraints + constraints: options.constraints, + context: (options.options || {}).context }; getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(validationMetadataArgs)); } diff --git a/src/validation/ValidationExecutor.ts b/src/validation/ValidationExecutor.ts index 4c4248acfc..77bad4f488 100644 --- a/src/validation/ValidationExecutor.ts +++ b/src/validation/ValidationExecutor.ts @@ -43,7 +43,7 @@ export class ValidationExecutor { /** * If there is no metadata registered it means possibly the dependencies are not flatterned and * more than one instance is used. - * + * * TODO: This needs proper handling, forcing to use the same container or some other proper solution. */ if (!this.metadataStorage.hasValidationMetaData) { @@ -60,29 +60,39 @@ export class ValidationExecutor { if (!this.validatorOptions || !this.validatorOptions.validationError || this.validatorOptions.validationError.target === undefined || - this.validatorOptions.validationError.target === true) + this.validatorOptions.validationError.target === true) { validationError.target = object; + } validationError.value = undefined; validationError.property = undefined; validationError.children = []; - validationError.constraints = { unknownValue: "an unknown value was passed to the validate function" }; + validationError.constraints = {unknownValue: "an unknown value was passed to the validate function"}; validationErrors.push(validationError); return; } - if (this.validatorOptions && this.validatorOptions.whitelist) + if (this.validatorOptions && this.validatorOptions.whitelist) { this.whitelist(object, groupedMetadatas, validationErrors); + } + + const PREDEFINED_VALIDATION_TYPES = [ + ValidationTypes.NESTED_VALIDATION, + ValidationTypes.CONDITIONAL_VALIDATION, + ValidationTypes.WHITELIST, + ValidationTypes.IS_DEFINED + ]; // General validation Object.keys(groupedMetadatas).forEach(propertyName => { + const value = (object as any)[propertyName]; const definedMetadatas = groupedMetadatas[propertyName].filter(metadata => metadata.type === ValidationTypes.IS_DEFINED); const metadatas = groupedMetadatas[propertyName].filter( - metadata => metadata.type !== ValidationTypes.IS_DEFINED && metadata.type !== ValidationTypes.WHITELIST); - const customValidationMetadatas = metadatas.filter(metadata => metadata.type === ValidationTypes.CUSTOM_VALIDATION); + metadata => metadata.type !== ValidationTypes.IS_DEFINED && metadata.type !== ValidationTypes.WHITELIST); + const customValidationMetadatas = metadatas.filter(metadata => PREDEFINED_VALIDATION_TYPES.indexOf(metadata.type) === -1); const nestedValidationMetadatas = metadatas.filter(metadata => metadata.type === ValidationTypes.NESTED_VALIDATION); const conditionalValidationMetadatas = metadatas.filter(metadata => metadata.type === ValidationTypes.CONDITIONAL_VALIDATION); @@ -128,7 +138,7 @@ export class ValidationExecutor { notAllowedProperties.forEach(property => { validationErrors.push({ target: object, property, value: (object as any)[property], children: undefined, - constraints: { [ValidationTypes.WHITELIST]: `property ${property} should not exist` } + constraints: {[ValidationTypes.WHITELIST]: `property ${property} should not exist`} }); }); diff --git a/src/validation/ValidatorOptions.ts b/src/validation/ValidatorOptions.ts index 67cc143038..ed2b8ccd3e 100644 --- a/src/validation/ValidatorOptions.ts +++ b/src/validation/ValidatorOptions.ts @@ -53,4 +53,9 @@ export interface ValidatorOptions { */ forbidUnknownValues?: boolean; -} \ No newline at end of file + /** + * A transient set of data passed through to the validation result for response mapping + */ + context?: any; + +} From 61130a5dd632b592a339aa86edf3baf23ad3e5ac Mon Sep 17 00:00:00 2001 From: Christoph Linder Date: Sat, 17 Nov 2018 01:13:08 +0100 Subject: [PATCH 09/12] Smaller bundle - next bunch of migrations... --- package-lock.json | 1828 ++++++++--------- package.json | 2 +- sample/sample1-simple-validation/Post.ts | 4 +- sample/sample2-using-groups/Post.ts | 4 +- .../BaseContent.ts | 4 +- src/decorator/IsAlpha.ts | 26 + src/decorator/IsAlphanumeric.ts | 25 + src/decorator/IsAscii.ts | 24 + src/decorator/IsBase64.ts | 26 + src/decorator/IsByteLength.ts | 27 + src/decorator/IsCreditCard.ts | 25 + src/decorator/IsCurrency.ts | 26 + src/decorator/IsEmail.ts | 25 + src/decorator/IsFQDN.ts | 25 + src/decorator/IsFullWidth.ts | 27 + src/decorator/IsHalfWidth.ts | 26 + src/decorator/IsHexColor.ts | 25 + src/decorator/IsHexadecimal.ts | 25 + src/decorator/IsIP.ts | 28 + src/decorator/IsISBN.ts | 28 + src/decorator/IsISIN.ts | 25 + src/decorator/IsVariableWidth.ts | 25 + src/decorator/NotContains.ts | 27 + src/decorator/decorators.ts | 277 --- src/validation/ValidationTypes.ts | 54 - src/validation/Validator.ts | 179 -- ...alidation-functions-and-decorators.spec.ts | 171 +- 27 files changed, 1504 insertions(+), 1484 deletions(-) create mode 100644 src/decorator/IsAlpha.ts create mode 100644 src/decorator/IsAlphanumeric.ts create mode 100644 src/decorator/IsAscii.ts create mode 100644 src/decorator/IsBase64.ts create mode 100644 src/decorator/IsByteLength.ts create mode 100644 src/decorator/IsCreditCard.ts create mode 100644 src/decorator/IsCurrency.ts create mode 100644 src/decorator/IsEmail.ts create mode 100644 src/decorator/IsFQDN.ts create mode 100644 src/decorator/IsFullWidth.ts create mode 100644 src/decorator/IsHalfWidth.ts create mode 100644 src/decorator/IsHexColor.ts create mode 100644 src/decorator/IsHexadecimal.ts create mode 100644 src/decorator/IsIP.ts create mode 100644 src/decorator/IsISBN.ts create mode 100644 src/decorator/IsISIN.ts create mode 100644 src/decorator/IsVariableWidth.ts create mode 100644 src/decorator/NotContains.ts diff --git a/package-lock.json b/package-lock.json index 2315a795ae..ce069473cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "class-validator", - "version": "1.0.0-rc1", + "version": "1.0.0-rc", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -10,11 +10,11 @@ "integrity": "sha512-ciiioYMLdo16ShmfHBXJBOFm3xPC4AuwO4xeRpFeHz7WK9PYsWCmigagG2XyzZpubK4a3qNKoUBDhbzHfa50LQ==", "dev": true, "requires": { - "acorn": "5.7.1", - "css": "2.2.3", - "normalize-path": "2.1.1", - "source-map": "0.6.1", - "through2": "2.0.3" + "acorn": "^5.0.3", + "css": "^2.2.1", + "normalize-path": "^2.1.1", + "source-map": "^0.6.0", + "through2": "^2.0.3" }, "dependencies": { "source-map": { @@ -31,8 +31,8 @@ "integrity": "sha1-iQrnxdjId/bThIYCFazp1+yUW9o=", "dev": true, "requires": { - "normalize-path": "2.1.1", - "through2": "2.0.3" + "normalize-path": "^2.0.1", + "through2": "^2.0.3" } }, "@sinonjs/formatio": { @@ -62,7 +62,7 @@ "integrity": "sha512-MFiW54UOSt+f2bRw8J7LgQeIvE/9b4oGvwU7XW30S9QGAiHGnU/fmiOprsyMkdmH2rl8xSPc0/yrQw8juXU6bQ==", "dev": true, "requires": { - "@types/chai": "4.1.4" + "@types/chai": "*" } }, "@types/chokidar": { @@ -71,8 +71,8 @@ "integrity": "sha512-PDkSRY7KltW3M60hSBlerxI8SFPXsO3AL/aRVsO4Kh9IHRW74Ih75gUuTd/aE4LSSFqypb10UIX3QzOJwBQMGQ==", "dev": true, "requires": { - "@types/events": "1.2.0", - "@types/node": "10.5.2" + "@types/events": "*", + "@types/node": "*" } }, "@types/events": { @@ -93,9 +93,9 @@ "integrity": "sha512-wc+VveszMLyMWFvXLkloixT4n0harUIVZjnpzztaZ0nKLuul7Z32iMt2fUFGAaZ4y1XWjFRMtCI5ewvyh4aIeg==", "dev": true, "requires": { - "@types/events": "1.2.0", - "@types/minimatch": "3.0.3", - "@types/node": "10.5.2" + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" } }, "@types/glob-stream": { @@ -104,8 +104,8 @@ "integrity": "sha512-RHv6ZQjcTncXo3thYZrsbAVwoy4vSKosSWhuhuQxLOTv74OJuFQxXkmUuZCr3q9uNBEVCvIzmZL/FeRNbHZGUg==", "dev": true, "requires": { - "@types/glob": "5.0.35", - "@types/node": "10.5.2" + "@types/glob": "*", + "@types/node": "*" } }, "@types/gulp": { @@ -114,9 +114,9 @@ "integrity": "sha512-nx1QjPTiRpvLfYsZ7MBu7bT6Cm7tAXyLbY0xbdx2IEMxCK2v2urIhJMQZHW0iV1TskM71Xl6p2uRRuWDbk+/7g==", "dev": true, "requires": { - "@types/chokidar": "1.7.5", - "@types/undertaker": "1.2.0", - "@types/vinyl-fs": "2.4.8" + "@types/chokidar": "*", + "@types/undertaker": "*", + "@types/vinyl-fs": "*" } }, "@types/minimatch": { @@ -149,8 +149,8 @@ "integrity": "sha512-bx/5nZCGkasXs6qaA3B6SVDjBZqdyk04UO12e0uEPSzjt5H8jEJw0DKe7O7IM0hM2bVHRh70pmOH7PEHqXwzOw==", "dev": true, "requires": { - "@types/events": "1.2.0", - "@types/undertaker-registry": "1.0.1" + "@types/events": "*", + "@types/undertaker-registry": "*" } }, "@types/undertaker-registry": { @@ -160,9 +160,9 @@ "dev": true }, "@types/validator": { - "version": "9.4.2", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-9.4.2.tgz", - "integrity": "sha512-v6H2QH+oXVdLKp9keOJi5LQSt6X5/XIOtK1YmbCzvkAT2kHW9WyQkixit9w1UgJpBGrDCqqCZlQ+Qucpmsf8hA==", + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-9.4.3.tgz", + "integrity": "sha512-D4zRrAs2pTg5cva6+hJ6GrQlb/UX5NxNtk/da3Gw27enoLvbRMTTloZ1w6CCqc+kHyZvT3DsyWQZ8baTGgSg0g==", "dev": true }, "@types/vinyl": { @@ -171,7 +171,7 @@ "integrity": "sha512-2iYpNuOl98SrLPBZfEN9Mh2JCJ2EI9HU35SfgBEb51DcmaHkhp8cKMblYeBqMQiwXMgAD3W60DbQ4i/UdLiXhw==", "dev": true, "requires": { - "@types/node": "10.5.2" + "@types/node": "*" } }, "@types/vinyl-fs": { @@ -180,9 +180,9 @@ "integrity": "sha512-yE2pN9OOrxJVeO7IZLHAHrh5R4Q0osbn5WQRuQU6GdXoK7dNFrMK3K7YhATkzf3z0yQBkol3+gafs7Rp0s7dDg==", "dev": true, "requires": { - "@types/glob-stream": "6.1.0", - "@types/node": "10.5.2", - "@types/vinyl": "2.0.2" + "@types/glob-stream": "*", + "@types/node": "*", + "@types/vinyl": "*" } }, "abbrev": { @@ -203,10 +203,10 @@ "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "align-text": { @@ -215,9 +215,9 @@ "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, "requires": { - "kind-of": "3.2.2", - "longest": "1.0.1", - "repeat-string": "1.6.1" + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" }, "dependencies": { "kind-of": { @@ -226,7 +226,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -243,7 +243,7 @@ "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", "dev": true, "requires": { - "ansi-wrap": "0.1.0" + "ansi-wrap": "^0.1.0" } }, "ansi-cyan": { @@ -297,7 +297,7 @@ "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", "dev": true, "requires": { - "buffer-equal": "1.0.0" + "buffer-equal": "^1.0.0" } }, "archy": { @@ -312,7 +312,7 @@ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" } }, "argv": { @@ -363,7 +363,7 @@ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "1.0.3" + "array-uniq": "^1.0.1" } }, "array-uniq": { @@ -444,9 +444,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" } }, "balanced-match": { @@ -461,13 +461,13 @@ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { - "cache-base": "1.0.1", - "class-utils": "0.3.6", - "component-emitter": "1.2.1", - "define-property": "1.0.0", - "isobject": "3.0.1", - "mixin-deep": "1.3.1", - "pascalcase": "0.1.1" + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" }, "dependencies": { "define-property": { @@ -476,7 +476,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -485,7 +485,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -494,7 +494,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -503,9 +503,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -517,7 +517,7 @@ "dev": true, "optional": true, "requires": { - "tweetnacl": "0.14.5" + "tweetnacl": "^0.14.3" } }, "beeper": { @@ -538,7 +538,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -548,16 +548,16 @@ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "arr-flatten": "1.1.0", - "array-unique": "0.3.2", - "extend-shallow": "2.0.1", - "fill-range": "4.0.0", - "isobject": "3.0.1", - "repeat-element": "1.1.2", - "snapdragon": "0.8.2", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.2" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -566,7 +566,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -601,15 +601,15 @@ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { - "collection-visit": "1.0.0", - "component-emitter": "1.2.1", - "get-value": "2.0.6", - "has-value": "1.0.0", - "isobject": "3.0.1", - "set-value": "2.0.0", - "to-object-path": "0.3.0", - "union-value": "1.0.0", - "unset-value": "1.0.0" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" } }, "camelcase": { @@ -632,8 +632,8 @@ "dev": true, "optional": true, "requires": { - "align-text": "0.1.4", - "lazy-cache": "1.0.4" + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" } }, "chai": { @@ -642,12 +642,12 @@ "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", "dev": true, "requires": { - "assertion-error": "1.1.0", - "check-error": "1.0.2", - "deep-eql": "3.0.1", - "get-func-name": "2.0.0", - "pathval": "1.1.0", - "type-detect": "4.0.8" + "assertion-error": "^1.0.1", + "check-error": "^1.0.1", + "deep-eql": "^3.0.0", + "get-func-name": "^2.0.0", + "pathval": "^1.0.0", + "type-detect": "^4.0.0" } }, "chai-as-promised": { @@ -656,7 +656,7 @@ "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", "dev": true, "requires": { - "check-error": "1.0.2" + "check-error": "^1.0.2" } }, "chalk": { @@ -665,11 +665,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "check-error": { @@ -684,10 +684,10 @@ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { - "arr-union": "3.1.0", - "define-property": "0.2.5", - "isobject": "3.0.1", - "static-extend": "0.1.2" + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" }, "dependencies": { "define-property": { @@ -696,7 +696,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -708,8 +708,8 @@ "dev": true, "optional": true, "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", + "center-align": "^0.1.1", + "right-align": "^0.1.1", "wordwrap": "0.0.2" }, "dependencies": { @@ -746,9 +746,9 @@ "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==", "dev": true, "requires": { - "inherits": "2.0.3", - "process-nextick-args": "2.0.0", - "readable-stream": "2.3.6" + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" }, "dependencies": { "isarray": { @@ -763,13 +763,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -778,7 +778,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -795,10 +795,10 @@ "integrity": "sha512-KJyzHdg9B8U9LxXa7hS6jnEW5b1cNckLYc2YpnJ1nEFiOW+/iSzDHp+5MYEIQd9fN3/tC6WmGZmYiwxzkuGp/A==", "dev": true, "requires": { - "argv": "0.0.2", - "ignore-walk": "3.0.1", - "request": "2.87.0", - "urlgrey": "0.4.4" + "argv": "^0.0.2", + "ignore-walk": "^3.0.1", + "request": "^2.87.0", + "urlgrey": "^0.4.4" } }, "collection-visit": { @@ -807,8 +807,8 @@ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "map-visit": "1.0.0", - "object-visit": "1.0.1" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" } }, "color-convert": { @@ -838,7 +838,7 @@ "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "dev": true, "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "commander": { @@ -883,11 +883,11 @@ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { - "nice-try": "1.0.4", - "path-key": "2.0.1", - "semver": "5.5.0", - "shebang-command": "1.2.0", - "which": "1.3.1" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" }, "dependencies": { "semver": { @@ -904,10 +904,10 @@ "integrity": "sha512-0W171WccAjQGGTKLhw4m2nnl0zPHUlTO/I8td4XzJgIB8Hg3ZZx71qT4G4eX8OVsSiaAKiUMy73E3nsbPlg2DQ==", "dev": true, "requires": { - "inherits": "2.0.3", - "source-map": "0.1.43", - "source-map-resolve": "0.5.2", - "urix": "0.1.0" + "inherits": "^2.0.1", + "source-map": "^0.1.38", + "source-map-resolve": "^0.5.1", + "urix": "^0.1.0" }, "dependencies": { "source-map": { @@ -916,7 +916,7 @@ "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", "dev": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } } } @@ -927,7 +927,7 @@ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { - "es5-ext": "0.10.45" + "es5-ext": "^0.10.9" } }, "dargs": { @@ -942,7 +942,7 @@ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "dateformat": { @@ -966,9 +966,9 @@ "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==", "dev": true, "requires": { - "debug": "3.1.0", - "memoizee": "0.4.12", - "object-assign": "4.1.1" + "debug": "3.X", + "memoizee": "0.4.X", + "object-assign": "4.X" }, "dependencies": { "debug": { @@ -1001,7 +1001,7 @@ "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", "dev": true, "requires": { - "type-detect": "4.0.8" + "type-detect": "^4.0.0" } }, "deep-is": { @@ -1016,7 +1016,7 @@ "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", "dev": true, "requires": { - "clone": "1.0.4" + "clone": "^1.0.2" } }, "define-properties": { @@ -1025,8 +1025,8 @@ "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", "dev": true, "requires": { - "foreach": "2.0.5", - "object-keys": "1.0.12" + "foreach": "^2.0.5", + "object-keys": "^1.0.8" } }, "define-property": { @@ -1035,8 +1035,8 @@ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { - "is-descriptor": "1.0.2", - "isobject": "3.0.1" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "dependencies": { "is-accessor-descriptor": { @@ -1045,7 +1045,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -1054,7 +1054,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -1063,9 +1063,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -1076,12 +1076,12 @@ "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", "dev": true, "requires": { - "globby": "6.1.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.1", - "p-map": "1.2.0", - "pify": "3.0.0", - "rimraf": "2.6.2" + "globby": "^6.1.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "p-map": "^1.1.1", + "pify": "^3.0.0", + "rimraf": "^2.2.8" } }, "delayed-stream": { @@ -1120,7 +1120,7 @@ "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", "dev": true, "requires": { - "readable-stream": "1.1.14" + "readable-stream": "~1.1.9" } }, "duplexify": { @@ -1129,10 +1129,10 @@ "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", "dev": true, "requires": { - "end-of-stream": "1.4.1", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "stream-shift": "1.0.0" + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" }, "dependencies": { "end-of-stream": { @@ -1141,7 +1141,7 @@ "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, "requires": { - "once": "1.4.0" + "once": "^1.4.0" } }, "isarray": { @@ -1156,13 +1156,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -1171,7 +1171,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -1183,7 +1183,7 @@ "dev": true, "optional": true, "requires": { - "jsbn": "0.1.1" + "jsbn": "~0.1.0" } }, "editions": { @@ -1198,7 +1198,7 @@ "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", "dev": true, "requires": { - "once": "1.3.3" + "once": "~1.3.0" }, "dependencies": { "once": { @@ -1207,7 +1207,7 @@ "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } } } @@ -1218,9 +1218,9 @@ "integrity": "sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ==", "dev": true, "requires": { - "es6-iterator": "2.0.3", - "es6-symbol": "3.1.1", - "next-tick": "1.0.0" + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.1", + "next-tick": "1" } }, "es6-iterator": { @@ -1229,9 +1229,9 @@ "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.45", - "es6-symbol": "3.1.1" + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" } }, "es6-shim": { @@ -1246,8 +1246,8 @@ "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.45" + "d": "1", + "es5-ext": "~0.10.14" } }, "es6-weak-map": { @@ -1256,10 +1256,10 @@ "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.45", - "es6-iterator": "2.0.3", - "es6-symbol": "3.1.1" + "d": "1", + "es5-ext": "^0.10.14", + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" } }, "escape-string-regexp": { @@ -1274,11 +1274,11 @@ "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", "dev": true, "requires": { - "esprima": "2.7.3", - "estraverse": "1.9.3", - "esutils": "2.0.2", - "optionator": "0.8.2", - "source-map": "0.2.0" + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" }, "dependencies": { "source-map": { @@ -1288,7 +1288,7 @@ "dev": true, "optional": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } } } @@ -1317,8 +1317,8 @@ "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.45" + "d": "1", + "es5-ext": "~0.10.14" } }, "execa": { @@ -1327,13 +1327,13 @@ "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", "dev": true, "requires": { - "cross-spawn": "6.0.5", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^6.0.0", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, "expand-brackets": { @@ -1342,13 +1342,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -1357,7 +1357,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -1366,7 +1366,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -1377,7 +1377,7 @@ "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", "dev": true, "requires": { - "homedir-polyfill": "1.0.1" + "homedir-polyfill": "^1.0.1" } }, "extend": { @@ -1392,8 +1392,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -1402,7 +1402,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -1413,14 +1413,14 @@ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { - "array-unique": "0.3.2", - "define-property": "1.0.0", - "expand-brackets": "2.1.4", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -1429,7 +1429,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "extend-shallow": { @@ -1438,7 +1438,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "is-accessor-descriptor": { @@ -1447,7 +1447,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -1456,7 +1456,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -1465,9 +1465,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -1484,9 +1484,9 @@ "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=", "dev": true, "requires": { - "ansi-gray": "0.1.1", - "color-support": "1.1.3", - "time-stamp": "1.1.0" + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "time-stamp": "^1.0.0" } }, "fast-deep-equal": { @@ -1513,10 +1513,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "repeat-string": "1.6.1", - "to-regex-range": "2.1.1" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" }, "dependencies": { "extend-shallow": { @@ -1525,7 +1525,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -1542,10 +1542,10 @@ "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", "dev": true, "requires": { - "detect-file": "1.0.0", - "is-glob": "3.1.0", - "micromatch": "3.1.10", - "resolve-dir": "1.0.1" + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" } }, "fined": { @@ -1554,11 +1554,11 @@ "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=", "dev": true, "requires": { - "expand-tilde": "2.0.2", - "is-plain-object": "2.0.4", - "object.defaults": "1.1.0", - "object.pick": "1.3.0", - "parse-filepath": "1.0.2" + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" } }, "first-chunk-stream": { @@ -1579,8 +1579,8 @@ "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", "dev": true, "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.6" + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" }, "dependencies": { "isarray": { @@ -1595,13 +1595,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -1610,7 +1610,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -1627,7 +1627,7 @@ "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", "dev": true, "requires": { - "for-in": "1.0.2" + "for-in": "^1.0.1" } }, "foreach": { @@ -1648,9 +1648,9 @@ "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "dev": true, "requires": { - "asynckit": "0.4.0", + "asynckit": "^0.4.0", "combined-stream": "1.0.6", - "mime-types": "2.1.19" + "mime-types": "^2.1.12" } }, "fragment-cache": { @@ -1659,7 +1659,7 @@ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "map-cache": "0.2.2" + "map-cache": "^0.2.2" } }, "fs-mkdirp-stream": { @@ -1668,8 +1668,8 @@ "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "through2": "2.0.3" + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" }, "dependencies": { "graceful-fs": { @@ -1698,7 +1698,7 @@ "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", "dev": true, "requires": { - "globule": "0.1.0" + "globule": "~0.1.0" } }, "get-func-name": { @@ -1725,7 +1725,7 @@ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "dev": true, "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "glob": { @@ -1734,12 +1734,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "glob-parent": { @@ -1748,8 +1748,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "3.1.0", - "path-dirname": "1.0.2" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" } }, "glob-stream": { @@ -1758,12 +1758,12 @@ "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", "dev": true, "requires": { - "glob": "4.5.3", - "glob2base": "0.0.12", - "minimatch": "2.0.10", - "ordered-read-streams": "0.1.0", - "through2": "0.6.5", - "unique-stream": "1.0.0" + "glob": "^4.3.1", + "glob2base": "^0.0.12", + "minimatch": "^2.0.1", + "ordered-read-streams": "^0.1.0", + "through2": "^0.6.1", + "unique-stream": "^1.0.0" }, "dependencies": { "glob": { @@ -1772,10 +1772,10 @@ "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", "dev": true, "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "2.0.10", - "once": "1.4.0" + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^2.0.1", + "once": "^1.3.0" } }, "minimatch": { @@ -1784,19 +1784,19 @@ "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.0.0" } }, "readable-stream": { "version": "1.0.34", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } }, "through2": { @@ -1805,8 +1805,8 @@ "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { - "readable-stream": "1.0.34", - "xtend": "4.0.1" + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" } } } @@ -1817,7 +1817,7 @@ "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", "dev": true, "requires": { - "gaze": "0.5.2" + "gaze": "^0.5.1" } }, "glob2base": { @@ -1826,7 +1826,7 @@ "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", "dev": true, "requires": { - "find-index": "0.1.1" + "find-index": "^0.1.1" } }, "global-modules": { @@ -1835,9 +1835,9 @@ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "dev": true, "requires": { - "global-prefix": "1.0.2", - "is-windows": "1.0.2", - "resolve-dir": "1.0.1" + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" } }, "global-prefix": { @@ -1846,11 +1846,11 @@ "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", "dev": true, "requires": { - "expand-tilde": "2.0.2", - "homedir-polyfill": "1.0.1", - "ini": "1.3.5", - "is-windows": "1.0.2", - "which": "1.3.1" + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" } }, "globby": { @@ -1859,11 +1859,11 @@ "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "dev": true, "requires": { - "array-union": "1.0.2", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" }, "dependencies": { "pify": { @@ -1880,9 +1880,9 @@ "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", "dev": true, "requires": { - "glob": "3.1.21", - "lodash": "1.0.2", - "minimatch": "0.2.14" + "glob": "~3.1.21", + "lodash": "~1.0.1", + "minimatch": "~0.2.11" }, "dependencies": { "glob": { @@ -1891,9 +1891,9 @@ "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", "dev": true, "requires": { - "graceful-fs": "1.2.3", - "inherits": "1.0.2", - "minimatch": "0.2.14" + "graceful-fs": "~1.2.0", + "inherits": "1", + "minimatch": "~0.2.11" } }, "graceful-fs": { @@ -1914,8 +1914,8 @@ "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", "dev": true, "requires": { - "lru-cache": "2.7.3", - "sigmund": "1.0.1" + "lru-cache": "2", + "sigmund": "~1.0.0" } } } @@ -1926,7 +1926,7 @@ "integrity": "sha512-ynYqXLoluBKf9XGR1gA59yEJisIL7YHEH4xr3ZziHB5/yl4qWfaK8Js9jGe6gBGCSCKVqiyO30WnRZADvemUNw==", "dev": true, "requires": { - "sparkles": "1.0.1" + "sparkles": "^1.0.0" } }, "google-libphonenumber": { @@ -1940,7 +1940,7 @@ "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", "dev": true, "requires": { - "natives": "1.1.4" + "natives": "^1.1.0" } }, "growl": { @@ -1951,23 +1951,23 @@ }, "gulp": { "version": "3.9.1", - "resolved": "http://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=", "dev": true, "requires": { - "archy": "1.0.0", - "chalk": "1.1.3", - "deprecated": "0.0.1", - "gulp-util": "3.0.8", - "interpret": "1.1.0", - "liftoff": "2.5.0", - "minimist": "1.2.0", - "orchestrator": "0.3.8", - "pretty-hrtime": "1.0.3", - "semver": "4.3.6", - "tildify": "1.2.0", - "v8flags": "2.1.1", - "vinyl-fs": "0.3.14" + "archy": "^1.0.0", + "chalk": "^1.0.0", + "deprecated": "^0.0.1", + "gulp-util": "^3.0.0", + "interpret": "^1.0.0", + "liftoff": "^2.1.0", + "minimist": "^1.1.0", + "orchestrator": "^0.3.0", + "pretty-hrtime": "^1.0.0", + "semver": "^4.1.0", + "tildify": "^1.0.0", + "v8flags": "^2.0.2", + "vinyl-fs": "^0.3.0" } }, "gulp-istanbul": { @@ -1976,12 +1976,12 @@ "integrity": "sha512-uMLSdqPDnBAV/B9rNyOgVMgrVC1tPbe+5GH6P13UOyxbRDT/w4sKYHWftPMA8j9om+NFvfeRlqpDXL2fixFWNA==", "dev": true, "requires": { - "istanbul": "0.4.5", - "istanbul-threshold-checker": "0.2.1", - "lodash": "4.17.10", - "plugin-error": "0.1.2", - "through2": "2.0.3", - "vinyl-sourcemaps-apply": "0.2.1" + "istanbul": "^0.4.0", + "istanbul-threshold-checker": "^0.2.1", + "lodash": "^4.0.0", + "plugin-error": "^0.1.2", + "through2": "^2.0.0", + "vinyl-sourcemaps-apply": "^0.2.1" }, "dependencies": { "lodash": { @@ -1998,13 +1998,13 @@ "integrity": "sha512-FfBldW5ttnDpKf4Sg6/BLOOKCCbr5mbixDGK1t02/8oSrTCwNhgN/mdszG3cuQuYNzuouUdw4EH/mlYtgUscPg==", "dev": true, "requires": { - "dargs": "5.1.0", - "execa": "0.10.0", - "mocha": "5.2.0", - "npm-run-path": "2.0.2", - "plugin-error": "1.0.1", - "supports-color": "5.4.0", - "through2": "2.0.3" + "dargs": "^5.1.0", + "execa": "^0.10.0", + "mocha": "^5.2.0", + "npm-run-path": "^2.0.2", + "plugin-error": "^1.0.1", + "supports-color": "^5.4.0", + "through2": "^2.0.3" }, "dependencies": { "has-flag": { @@ -2019,10 +2019,10 @@ "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", "dev": true, "requires": { - "ansi-colors": "1.1.0", - "arr-diff": "4.0.0", - "arr-union": "3.1.0", - "extend-shallow": "3.0.2" + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" } }, "supports-color": { @@ -2031,7 +2031,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -2043,8 +2043,8 @@ "dev": true, "requires": { "istextorbinary": "2.2.1", - "readable-stream": "2.3.6", - "replacestream": "4.0.3" + "readable-stream": "^2.0.1", + "replacestream": "^4.0.0" }, "dependencies": { "isarray": { @@ -2059,13 +2059,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -2074,7 +2074,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -2085,13 +2085,13 @@ "integrity": "sha512-f3m1WcS0o2B72/PGj1Jbv9zYR9rynBh/EQJv64n01xQUo7j7anols0eww9GG/WtDTzGVQLrupVDYkifRFnj5Zg==", "dev": true, "requires": { - "async": "2.6.1", - "chalk": "2.4.1", - "fancy-log": "1.3.2", - "lodash": "4.17.10", - "lodash.template": "4.4.0", - "plugin-error": "0.1.2", - "through2": "2.0.3" + "async": "^2.1.5", + "chalk": "^2.3.0", + "fancy-log": "^1.3.2", + "lodash": "^4.17.4", + "lodash.template": "^4.4.0", + "plugin-error": "^0.1.2", + "through2": "^2.0.3" }, "dependencies": { "ansi-styles": { @@ -2100,7 +2100,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "1.9.2" + "color-convert": "^1.9.0" } }, "async": { @@ -2109,7 +2109,7 @@ "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", "dev": true, "requires": { - "lodash": "4.17.10" + "lodash": "^4.17.10" } }, "chalk": { @@ -2118,9 +2118,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "has-flag": { @@ -2141,8 +2141,8 @@ "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=", "dev": true, "requires": { - "lodash._reinterpolate": "3.0.0", - "lodash.templatesettings": "4.1.0" + "lodash._reinterpolate": "~3.0.0", + "lodash.templatesettings": "^4.0.0" } }, "lodash.templatesettings": { @@ -2151,7 +2151,7 @@ "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=", "dev": true, "requires": { - "lodash._reinterpolate": "3.0.0" + "lodash._reinterpolate": "~3.0.0" } }, "supports-color": { @@ -2160,7 +2160,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -2171,17 +2171,17 @@ "integrity": "sha1-y7IAhFCxvM5s0jv5gze+dRv24wo=", "dev": true, "requires": { - "@gulp-sourcemaps/identity-map": "1.0.2", - "@gulp-sourcemaps/map-sources": "1.0.0", - "acorn": "5.7.1", - "convert-source-map": "1.5.1", - "css": "2.2.3", - "debug-fabulous": "1.1.0", - "detect-newline": "2.1.0", - "graceful-fs": "4.1.11", - "source-map": "0.6.1", - "strip-bom-string": "1.0.0", - "through2": "2.0.3" + "@gulp-sourcemaps/identity-map": "1.X", + "@gulp-sourcemaps/map-sources": "1.X", + "acorn": "5.X", + "convert-source-map": "1.X", + "css": "2.X", + "debug-fabulous": "1.X", + "detect-newline": "2.X", + "graceful-fs": "4.X", + "source-map": "~0.6.0", + "strip-bom-string": "1.X", + "through2": "2.X" }, "dependencies": { "graceful-fs": { @@ -2207,9 +2207,9 @@ "@types/fancy-log": "1.3.0", "chalk": "2.3.1", "fancy-log": "1.3.2", - "map-stream": "0.0.7", + "map-stream": "~0.0.7", "plugin-error": "1.0.1", - "through": "2.3.8" + "through": "~2.3.8" }, "dependencies": { "ansi-styles": { @@ -2218,7 +2218,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "1.9.2" + "color-convert": "^1.9.0" } }, "chalk": { @@ -2227,9 +2227,9 @@ "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" + "ansi-styles": "^3.2.0", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.2.0" } }, "has-flag": { @@ -2244,10 +2244,10 @@ "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", "dev": true, "requires": { - "ansi-colors": "1.1.0", - "arr-diff": "4.0.0", - "arr-union": "3.1.0", - "extend-shallow": "3.0.2" + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" } }, "supports-color": { @@ -2256,7 +2256,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -2267,12 +2267,12 @@ "integrity": "sha512-6iSBjqBXAUqRsLUh/9XtlOnSzpPMbLrr5rqGj4UPLtGpDwFHW/fVTuRgv6LAWiKesLIUDDM0ourxvcpu2trecQ==", "dev": true, "requires": { - "ansi-colors": "2.0.3", - "plugin-error": "1.0.1", - "source-map": "0.7.3", - "through2": "2.0.3", - "vinyl": "2.2.0", - "vinyl-fs": "3.0.3" + "ansi-colors": "^2.0.2", + "plugin-error": "^1.0.1", + "source-map": "^0.7.3", + "through2": "^2.0.3", + "vinyl": "^2.1.0", + "vinyl-fs": "^3.0.3" }, "dependencies": { "ansi-colors": { @@ -2299,16 +2299,16 @@ "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", "dev": true, "requires": { - "extend": "3.0.1", - "glob": "7.1.2", - "glob-parent": "3.1.0", - "is-negated-glob": "1.0.0", - "ordered-read-streams": "1.0.1", - "pumpify": "1.5.1", - "readable-stream": "2.3.6", - "remove-trailing-separator": "1.1.0", - "to-absolute-glob": "2.0.2", - "unique-stream": "2.2.1" + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" } }, "graceful-fs": { @@ -2329,7 +2329,7 @@ "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", "dev": true, "requires": { - "readable-stream": "2.3.6" + "readable-stream": "^2.0.1" } }, "plugin-error": { @@ -2338,10 +2338,10 @@ "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", "dev": true, "requires": { - "ansi-colors": "1.1.0", - "arr-diff": "4.0.0", - "arr-union": "3.1.0", - "extend-shallow": "3.0.2" + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" }, "dependencies": { "ansi-colors": { @@ -2350,7 +2350,7 @@ "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", "dev": true, "requires": { - "ansi-wrap": "0.1.0" + "ansi-wrap": "^0.1.0" } } } @@ -2361,13 +2361,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "replace-ext": { @@ -2388,7 +2388,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } }, "unique-stream": { @@ -2397,8 +2397,8 @@ "integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=", "dev": true, "requires": { - "json-stable-stringify": "1.0.1", - "through2-filter": "2.0.0" + "json-stable-stringify": "^1.0.0", + "through2-filter": "^2.0.0" } }, "vinyl": { @@ -2407,12 +2407,12 @@ "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", "dev": true, "requires": { - "clone": "2.1.1", - "clone-buffer": "1.0.0", - "clone-stats": "1.0.0", - "cloneable-readable": "1.1.2", - "remove-trailing-separator": "1.1.0", - "replace-ext": "1.0.0" + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" } }, "vinyl-fs": { @@ -2421,23 +2421,23 @@ "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", "dev": true, "requires": { - "fs-mkdirp-stream": "1.0.0", - "glob-stream": "6.1.0", - "graceful-fs": "4.1.11", - "is-valid-glob": "1.0.0", - "lazystream": "1.0.0", - "lead": "1.0.0", - "object.assign": "4.1.0", - "pumpify": "1.5.1", - "readable-stream": "2.3.6", - "remove-bom-buffer": "3.0.0", - "remove-bom-stream": "1.2.0", - "resolve-options": "1.1.0", - "through2": "2.0.3", - "to-through": "2.0.0", - "value-or-function": "3.0.0", - "vinyl": "2.2.0", - "vinyl-sourcemap": "1.1.0" + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" } } } @@ -2448,24 +2448,24 @@ "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", "dev": true, "requires": { - "array-differ": "1.0.0", - "array-uniq": "1.0.3", - "beeper": "1.1.1", - "chalk": "1.1.3", - "dateformat": "2.2.0", - "fancy-log": "1.3.2", - "gulplog": "1.0.0", - "has-gulplog": "0.1.0", - "lodash._reescape": "3.0.0", - "lodash._reevaluate": "3.0.0", - "lodash._reinterpolate": "3.0.0", - "lodash.template": "3.6.2", - "minimist": "1.2.0", - "multipipe": "0.1.2", - "object-assign": "3.0.0", + "array-differ": "^1.0.0", + "array-uniq": "^1.0.2", + "beeper": "^1.0.0", + "chalk": "^1.0.0", + "dateformat": "^2.0.0", + "fancy-log": "^1.1.0", + "gulplog": "^1.0.0", + "has-gulplog": "^0.1.0", + "lodash._reescape": "^3.0.0", + "lodash._reevaluate": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.template": "^3.0.0", + "minimist": "^1.1.0", + "multipipe": "^0.1.2", + "object-assign": "^3.0.0", "replace-ext": "0.0.1", - "through2": "2.0.3", - "vinyl": "0.5.3" + "through2": "^2.0.0", + "vinyl": "^0.5.0" }, "dependencies": { "object-assign": { @@ -2482,9 +2482,9 @@ "integrity": "sha1-0m9cOdw5nhHEWpCHh8hkkLwx6FA=", "dev": true, "requires": { - "gulp": "3.9.1", - "merge2": "0.3.7", - "run-sequence": "1.2.2" + "gulp": "^3.9.0", + "merge2": "^0.3.6", + "run-sequence": "^1.1.5" } }, "gulplog": { @@ -2493,7 +2493,7 @@ "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", "dev": true, "requires": { - "glogg": "1.0.1" + "glogg": "^1.0.0" } }, "handlebars": { @@ -2502,10 +2502,10 @@ "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", "dev": true, "requires": { - "async": "1.5.2", - "optimist": "0.6.1", - "source-map": "0.4.4", - "uglify-js": "2.8.29" + "async": "^1.4.0", + "optimist": "^0.6.1", + "source-map": "^0.4.4", + "uglify-js": "^2.6" }, "dependencies": { "source-map": { @@ -2514,7 +2514,7 @@ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } } } @@ -2531,8 +2531,8 @@ "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "dev": true, "requires": { - "ajv": "5.5.2", - "har-schema": "2.0.0" + "ajv": "^5.1.0", + "har-schema": "^2.0.0" } }, "has-ansi": { @@ -2541,7 +2541,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "has-flag": { @@ -2556,7 +2556,7 @@ "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", "dev": true, "requires": { - "sparkles": "1.0.1" + "sparkles": "^1.0.0" } }, "has-symbols": { @@ -2571,9 +2571,9 @@ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "1.0.0", - "isobject": "3.0.1" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" } }, "has-values": { @@ -2582,8 +2582,8 @@ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { "kind-of": { @@ -2592,7 +2592,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2609,7 +2609,7 @@ "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", "dev": true, "requires": { - "parse-passwd": "1.0.0" + "parse-passwd": "^1.0.0" } }, "http-signature": { @@ -2618,9 +2618,9 @@ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "dev": true, "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.14.2" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "ignore-walk": { @@ -2629,7 +2629,7 @@ "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "requires": { - "minimatch": "3.0.4" + "minimatch": "^3.0.4" } }, "inflight": { @@ -2638,8 +2638,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -2666,8 +2666,8 @@ "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", "dev": true, "requires": { - "is-relative": "1.0.0", - "is-windows": "1.0.2" + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" } }, "is-accessor-descriptor": { @@ -2676,7 +2676,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -2685,7 +2685,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2702,7 +2702,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -2711,7 +2711,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2722,9 +2722,9 @@ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "dependencies": { "kind-of": { @@ -2753,7 +2753,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.0" } }, "is-negated-glob": { @@ -2768,7 +2768,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -2777,7 +2777,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2794,7 +2794,7 @@ "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "dev": true, "requires": { - "is-path-inside": "1.0.1" + "is-path-inside": "^1.0.0" } }, "is-path-inside": { @@ -2803,7 +2803,7 @@ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.1" } }, "is-plain-object": { @@ -2812,7 +2812,7 @@ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "is-promise": { @@ -2827,7 +2827,7 @@ "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, "requires": { - "is-unc-path": "1.0.0" + "is-unc-path": "^1.0.0" } }, "is-stream": { @@ -2848,7 +2848,7 @@ "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, "requires": { - "unc-path-regex": "0.1.2" + "unc-path-regex": "^0.1.2" } }, "is-utf8": { @@ -2899,20 +2899,20 @@ "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", "dev": true, "requires": { - "abbrev": "1.0.9", - "async": "1.5.2", - "escodegen": "1.8.1", - "esprima": "2.7.3", - "glob": "5.0.15", - "handlebars": "4.0.11", - "js-yaml": "3.12.0", - "mkdirp": "0.5.1", - "nopt": "3.0.6", - "once": "1.4.0", - "resolve": "1.1.7", - "supports-color": "3.2.3", - "which": "1.3.1", - "wordwrap": "1.0.0" + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" }, "dependencies": { "glob": { @@ -2921,11 +2921,11 @@ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", "dev": true, "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "resolve": { @@ -2940,7 +2940,7 @@ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, "requires": { - "has-flag": "1.0.0" + "has-flag": "^1.0.0" } } } @@ -2951,8 +2951,8 @@ "integrity": "sha1-xdyU6PLMXNP/0zVFL4S1U8QkgzE=", "dev": true, "requires": { - "istanbul": "0.4.5", - "lodash": "4.17.10" + "istanbul": "~0.4.5", + "lodash": "~4.17.2" }, "dependencies": { "lodash": { @@ -2969,9 +2969,9 @@ "integrity": "sha512-TS+hoFl8Z5FAFMK38nhBkdLt44CclNRgDHWeMgsV8ko3nDlr/9UI2Sf839sW7enijf8oKsZYXRvM8g0it9Zmcw==", "dev": true, "requires": { - "binaryextensions": "2.1.1", - "editions": "1.3.4", - "textextensions": "2.2.0" + "binaryextensions": "2", + "editions": "^1.3.3", + "textextensions": "2" } }, "js-tokens": { @@ -2986,8 +2986,8 @@ "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", "dev": true, "requires": { - "argparse": "1.0.10", - "esprima": "4.0.1" + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, "dependencies": { "esprima": { @@ -3023,7 +3023,7 @@ "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "dev": true, "requires": { - "jsonify": "0.0.0" + "jsonify": "~0.0.0" } }, "json-stringify-safe": { @@ -3075,7 +3075,7 @@ "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", "dev": true, "requires": { - "readable-stream": "2.3.6" + "readable-stream": "^2.0.5" }, "dependencies": { "isarray": { @@ -3090,13 +3090,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -3105,7 +3105,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -3116,7 +3116,7 @@ "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", "dev": true, "requires": { - "flush-write-stream": "1.0.3" + "flush-write-stream": "^1.0.2" } }, "levn": { @@ -3125,8 +3125,8 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" } }, "liftoff": { @@ -3135,19 +3135,19 @@ "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", "dev": true, "requires": { - "extend": "3.0.1", - "findup-sync": "2.0.0", - "fined": "1.1.0", - "flagged-respawn": "1.0.0", - "is-plain-object": "2.0.4", - "object.map": "1.0.1", - "rechoir": "0.6.2", - "resolve": "1.8.1" + "extend": "^3.0.0", + "findup-sync": "^2.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" } }, "lodash": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", "dev": true }, @@ -3211,7 +3211,7 @@ "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", "dev": true, "requires": { - "lodash._root": "3.0.1" + "lodash._root": "^3.0.0" } }, "lodash.get": { @@ -3238,9 +3238,9 @@ "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", "dev": true, "requires": { - "lodash._getnative": "3.9.1", - "lodash.isarguments": "3.1.0", - "lodash.isarray": "3.0.4" + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" } }, "lodash.restparam": { @@ -3255,15 +3255,15 @@ "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", "dev": true, "requires": { - "lodash._basecopy": "3.0.1", - "lodash._basetostring": "3.0.1", - "lodash._basevalues": "3.0.0", - "lodash._isiterateecall": "3.0.9", - "lodash._reinterpolate": "3.0.0", - "lodash.escape": "3.2.0", - "lodash.keys": "3.1.2", - "lodash.restparam": "3.6.1", - "lodash.templatesettings": "3.1.1" + "lodash._basecopy": "^3.0.0", + "lodash._basetostring": "^3.0.0", + "lodash._basevalues": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0", + "lodash.keys": "^3.0.0", + "lodash.restparam": "^3.0.0", + "lodash.templatesettings": "^3.0.0" } }, "lodash.templatesettings": { @@ -3272,8 +3272,8 @@ "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", "dev": true, "requires": { - "lodash._reinterpolate": "3.0.0", - "lodash.escape": "3.2.0" + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0" } }, "log-symbols": { @@ -3282,7 +3282,7 @@ "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", "dev": true, "requires": { - "chalk": "1.1.3" + "chalk": "^1.0.0" } }, "lolex": { @@ -3309,7 +3309,7 @@ "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", "dev": true, "requires": { - "es5-ext": "0.10.45" + "es5-ext": "~0.10.2" } }, "make-error": { @@ -3324,7 +3324,7 @@ "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.2" } }, "map-cache": { @@ -3345,7 +3345,7 @@ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "object-visit": "1.0.1" + "object-visit": "^1.0.0" } }, "memoizee": { @@ -3354,14 +3354,14 @@ "integrity": "sha512-sprBu6nwxBWBvBOh5v2jcsGqiGLlL2xr2dLub3vR8dnE8YB17omwtm/0NSHl8jjNbcsJd5GMWJAnTSVe/O0Wfg==", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.45", - "es6-weak-map": "2.0.2", - "event-emitter": "0.3.5", - "is-promise": "2.1.0", - "lru-queue": "0.1.0", - "next-tick": "1.0.0", - "timers-ext": "0.1.5" + "d": "1", + "es5-ext": "^0.10.30", + "es6-weak-map": "^2.0.2", + "event-emitter": "^0.3.5", + "is-promise": "^2.1", + "lru-queue": "0.1", + "next-tick": "1", + "timers-ext": "^0.1.2" } }, "merge2": { @@ -3376,19 +3376,19 @@ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "extglob": "2.0.4", - "fragment-cache": "0.2.1", - "kind-of": "6.0.2", - "nanomatch": "1.2.13", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" } }, "mime-db": { @@ -3403,7 +3403,7 @@ "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", "dev": true, "requires": { - "mime-db": "1.35.0" + "mime-db": "~1.35.0" } }, "minimatch": { @@ -3412,7 +3412,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -3427,8 +3427,8 @@ "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", "dev": true, "requires": { - "for-in": "1.0.2", - "is-extendable": "1.0.1" + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -3437,7 +3437,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -3499,7 +3499,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -3525,17 +3525,17 @@ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "fragment-cache": "0.2.1", - "is-windows": "1.0.2", - "kind-of": "6.0.2", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" } }, "natives": { @@ -3562,11 +3562,11 @@ "integrity": "sha512-BxH/DxoQYYdhKgVAfqVy4pzXRZELHOIewzoesxpjYvpU+7YOalQhGNPf7wAx8pLrTNPrHRDlLOkAl8UI0ZpXjw==", "dev": true, "requires": { - "@sinonjs/formatio": "2.0.0", - "just-extend": "1.1.27", - "lolex": "2.7.1", - "path-to-regexp": "1.7.0", - "text-encoding": "0.6.4" + "@sinonjs/formatio": "^2.0.0", + "just-extend": "^1.1.27", + "lolex": "^2.3.2", + "path-to-regexp": "^1.7.0", + "text-encoding": "^0.6.4" } }, "nopt": { @@ -3575,7 +3575,7 @@ "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "dev": true, "requires": { - "abbrev": "1.0.9" + "abbrev": "1" } }, "normalize-path": { @@ -3584,7 +3584,7 @@ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "requires": { - "remove-trailing-separator": "1.1.0" + "remove-trailing-separator": "^1.0.1" } }, "now-and-later": { @@ -3593,7 +3593,7 @@ "integrity": "sha1-vGHLtFbXnLMiB85HygUTb/Ln1u4=", "dev": true, "requires": { - "once": "1.4.0" + "once": "^1.3.2" } }, "npm-run-path": { @@ -3602,7 +3602,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "oauth-sign": { @@ -3623,9 +3623,9 @@ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { - "copy-descriptor": "0.1.1", - "define-property": "0.2.5", - "kind-of": "3.2.2" + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" }, "dependencies": { "define-property": { @@ -3634,7 +3634,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "kind-of": { @@ -3643,7 +3643,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -3660,7 +3660,7 @@ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.0" } }, "object.assign": { @@ -3669,10 +3669,10 @@ "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "dev": true, "requires": { - "define-properties": "1.1.2", - "function-bind": "1.1.1", - "has-symbols": "1.0.0", - "object-keys": "1.0.12" + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" } }, "object.defaults": { @@ -3681,10 +3681,10 @@ "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", "dev": true, "requires": { - "array-each": "1.0.1", - "array-slice": "1.1.0", - "for-own": "1.0.0", - "isobject": "3.0.1" + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" } }, "object.map": { @@ -3693,8 +3693,8 @@ "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", "dev": true, "requires": { - "for-own": "1.0.0", - "make-iterator": "1.0.1" + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" } }, "object.pick": { @@ -3703,7 +3703,7 @@ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "once": { @@ -3712,7 +3712,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "optimist": { @@ -3721,8 +3721,8 @@ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { - "minimist": "0.0.10", - "wordwrap": "0.0.3" + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" }, "dependencies": { "minimist": { @@ -3745,12 +3745,12 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" } }, "orchestrator": { @@ -3759,9 +3759,9 @@ "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", "dev": true, "requires": { - "end-of-stream": "0.1.5", - "sequencify": "0.0.7", - "stream-consume": "0.1.1" + "end-of-stream": "~0.1.5", + "sequencify": "~0.0.7", + "stream-consume": "~0.1.0" } }, "ordered-read-streams": { @@ -3794,9 +3794,9 @@ "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", "dev": true, "requires": { - "is-absolute": "1.0.0", - "map-cache": "0.2.2", - "path-root": "0.1.1" + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" } }, "parse-passwd": { @@ -3847,7 +3847,7 @@ "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", "dev": true, "requires": { - "path-root-regex": "0.1.2" + "path-root-regex": "^0.1.0" } }, "path-root-regex": { @@ -3895,7 +3895,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "plugin-error": { @@ -3904,11 +3904,11 @@ "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", "dev": true, "requires": { - "ansi-cyan": "0.1.1", - "ansi-red": "0.1.1", - "arr-diff": "1.1.0", - "arr-union": "2.1.0", - "extend-shallow": "1.1.4" + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" }, "dependencies": { "arr-diff": { @@ -3917,8 +3917,8 @@ "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", "dev": true, "requires": { - "arr-flatten": "1.1.0", - "array-slice": "0.2.3" + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" } }, "arr-union": { @@ -3939,7 +3939,7 @@ "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", "dev": true, "requires": { - "kind-of": "1.1.0" + "kind-of": "^1.1.0" } }, "kind-of": { @@ -3964,7 +3964,7 @@ }, "pretty-hrtime": { "version": "1.0.3", - "resolved": "http://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, @@ -3980,8 +3980,8 @@ "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "dev": true, "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" }, "dependencies": { "end-of-stream": { @@ -3990,7 +3990,7 @@ "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, "requires": { - "once": "1.4.0" + "once": "^1.4.0" } } } @@ -4001,9 +4001,9 @@ "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "dev": true, "requires": { - "duplexify": "3.6.0", - "inherits": "2.0.3", - "pump": "2.0.1" + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" } }, "punycode": { @@ -4024,10 +4024,10 @@ "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } }, "rechoir": { @@ -4036,7 +4036,7 @@ "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", "dev": true, "requires": { - "resolve": "1.8.1" + "resolve": "^1.1.6" } }, "regex-not": { @@ -4045,8 +4045,8 @@ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { - "extend-shallow": "3.0.2", - "safe-regex": "1.1.0" + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" } }, "remap-istanbul": { @@ -4055,11 +4055,11 @@ "integrity": "sha512-Itv3XvYjD6G+9xDzAeFohx4GUwbFjfqFt0UXlC826jHR18E49fEiEGqZUxUASwMq4z7wwUv2H9/XF2d6qj0iaQ==", "dev": true, "requires": { - "amdefine": "1.0.1", + "amdefine": "^1.0.0", "istanbul": "0.4.5", - "minimatch": "3.0.4", - "plugin-error": "0.1.2", - "source-map": "0.6.1", + "minimatch": "^3.0.3", + "plugin-error": "^0.1.2", + "source-map": "^0.6.1", "through2": "2.0.1" }, "dependencies": { @@ -4081,12 +4081,12 @@ "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" } }, "source-map": { @@ -4101,8 +4101,8 @@ "integrity": "sha1-OE51MU1J8y3hLuu4E2uOtrXVnak=", "dev": true, "requires": { - "readable-stream": "2.0.6", - "xtend": "4.0.1" + "readable-stream": "~2.0.0", + "xtend": "~4.0.0" } } } @@ -4113,8 +4113,8 @@ "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", "dev": true, "requires": { - "is-buffer": "1.1.6", - "is-utf8": "0.2.1" + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" } }, "remove-bom-stream": { @@ -4123,9 +4123,9 @@ "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", "dev": true, "requires": { - "remove-bom-buffer": "3.0.0", - "safe-buffer": "5.1.2", - "through2": "2.0.3" + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" } }, "remove-trailing-separator": { @@ -4158,9 +4158,9 @@ "integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==", "dev": true, "requires": { - "escape-string-regexp": "1.0.5", - "object-assign": "4.1.1", - "readable-stream": "2.3.6" + "escape-string-regexp": "^1.0.3", + "object-assign": "^4.0.1", + "readable-stream": "^2.0.2" }, "dependencies": { "isarray": { @@ -4175,13 +4175,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -4190,7 +4190,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -4201,26 +4201,26 @@ "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", "dev": true, "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.7.0", - "caseless": "0.12.0", - "combined-stream": "1.0.6", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.3.2", - "har-validator": "5.0.3", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.19", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.2", - "safe-buffer": "5.1.2", - "tough-cookie": "2.3.4", - "tunnel-agent": "0.6.0", - "uuid": "3.3.2" + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" } }, "resolve": { @@ -4229,7 +4229,7 @@ "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", "dev": true, "requires": { - "path-parse": "1.0.5" + "path-parse": "^1.0.5" } }, "resolve-dir": { @@ -4238,8 +4238,8 @@ "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", "dev": true, "requires": { - "expand-tilde": "2.0.2", - "global-modules": "1.0.0" + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" } }, "resolve-options": { @@ -4248,7 +4248,7 @@ "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", "dev": true, "requires": { - "value-or-function": "3.0.0" + "value-or-function": "^3.0.0" } }, "resolve-url": { @@ -4270,7 +4270,7 @@ "dev": true, "optional": true, "requires": { - "align-text": "0.1.4" + "align-text": "^0.1.1" } }, "rimraf": { @@ -4279,7 +4279,7 @@ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } }, "run-sequence": { @@ -4288,8 +4288,8 @@ "integrity": "sha1-UJWgvr6YczsBQL0I3YDsAw3azes=", "dev": true, "requires": { - "chalk": "1.1.3", - "gulp-util": "3.0.8" + "chalk": "*", + "gulp-util": "*" } }, "safe-buffer": { @@ -4300,11 +4300,11 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { - "ret": "0.1.15" + "ret": "~0.1.10" } }, "safer-buffer": { @@ -4321,7 +4321,7 @@ }, "semver": { "version": "4.3.6", - "resolved": "http://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", "dev": true }, @@ -4337,10 +4337,10 @@ "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "split-string": "3.1.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -4349,7 +4349,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -4360,7 +4360,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -4387,14 +4387,14 @@ "integrity": "sha512-yeTza8xIZZdiXntCHJAzKll/sSYE+DuJOS8hiSapzaLqdW8eCNVVC9je9SZYYTkPm2bLts9x6UYxwuMAVVrM6Q==", "dev": true, "requires": { - "@sinonjs/formatio": "2.0.0", - "@sinonjs/samsam": "2.0.0", - "diff": "3.5.0", - "lodash.get": "4.4.2", - "lolex": "2.7.1", - "nise": "1.4.2", - "supports-color": "5.4.0", - "type-detect": "4.0.8" + "@sinonjs/formatio": "^2.0.0", + "@sinonjs/samsam": "^2.0.0", + "diff": "^3.5.0", + "lodash.get": "^4.4.2", + "lolex": "^2.4.2", + "nise": "^1.3.3", + "supports-color": "^5.4.0", + "type-detect": "^4.0.8" }, "dependencies": { "has-flag": { @@ -4409,7 +4409,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -4426,14 +4426,14 @@ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { - "base": "0.11.2", - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "map-cache": "0.2.2", - "source-map": "0.5.7", - "source-map-resolve": "0.5.2", - "use": "3.1.1" + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" }, "dependencies": { "define-property": { @@ -4442,7 +4442,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -4451,7 +4451,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -4462,9 +4462,9 @@ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { - "define-property": "1.0.0", - "isobject": "3.0.1", - "snapdragon-util": "3.0.1" + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" }, "dependencies": { "define-property": { @@ -4473,7 +4473,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -4482,7 +4482,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -4491,7 +4491,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -4500,9 +4500,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -4513,7 +4513,7 @@ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.2.0" }, "dependencies": { "kind-of": { @@ -4522,7 +4522,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -4539,11 +4539,11 @@ "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", "dev": true, "requires": { - "atob": "2.1.1", - "decode-uri-component": "0.2.0", - "resolve-url": "0.2.1", - "source-map-url": "0.4.0", - "urix": "0.1.0" + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" } }, "source-map-support": { @@ -4552,8 +4552,8 @@ "integrity": "sha512-N4KXEz7jcKqPf2b2vZF11lQIz9W5ZMuUcIOGj243lduidkf2fjkVKJS9vNxVWn3u/uxX38AcE8U9nnH9FPcq+g==", "dev": true, "requires": { - "buffer-from": "1.1.0", - "source-map": "0.6.1" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" }, "dependencies": { "source-map": { @@ -4582,7 +4582,7 @@ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { - "extend-shallow": "3.0.2" + "extend-shallow": "^3.0.0" } }, "sprintf-js": { @@ -4597,15 +4597,15 @@ "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", "dev": true, "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.2", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "safer-buffer": "2.1.2", - "tweetnacl": "0.14.5" + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" } }, "static-extend": { @@ -4614,8 +4614,8 @@ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { - "define-property": "0.2.5", - "object-copy": "0.1.0" + "define-property": "^0.2.5", + "object-copy": "^0.1.0" }, "dependencies": { "define-property": { @@ -4624,7 +4624,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -4653,7 +4653,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-bom": { @@ -4662,8 +4662,8 @@ "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", "dev": true, "requires": { - "first-chunk-stream": "1.0.0", - "is-utf8": "0.2.1" + "first-chunk-stream": "^1.0.0", + "is-utf8": "^0.2.0" } }, "strip-bom-string": { @@ -4714,8 +4714,8 @@ "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "dev": true, "requires": { - "readable-stream": "2.3.6", - "xtend": "4.0.1" + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" }, "dependencies": { "isarray": { @@ -4730,13 +4730,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -4745,7 +4745,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -4756,8 +4756,8 @@ "integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=", "dev": true, "requires": { - "through2": "2.0.3", - "xtend": "4.0.1" + "through2": "~2.0.0", + "xtend": "~4.0.0" } }, "tildify": { @@ -4766,7 +4766,7 @@ "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", "dev": true, "requires": { - "os-homedir": "1.0.2" + "os-homedir": "^1.0.0" } }, "time-stamp": { @@ -4781,8 +4781,8 @@ "integrity": "sha512-tsEStd7kmACHENhsUPaxb8Jf8/+GZZxyNFQbZD07HQOyooOa6At1rQqjffgvg7n+dxscQa9cjjMdWhJtsP2sxg==", "dev": true, "requires": { - "es5-ext": "0.10.45", - "next-tick": "1.0.0" + "es5-ext": "~0.10.14", + "next-tick": "1" } }, "to-absolute-glob": { @@ -4791,8 +4791,8 @@ "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", "dev": true, "requires": { - "is-absolute": "1.0.0", - "is-negated-glob": "1.0.0" + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" } }, "to-object-path": { @@ -4801,7 +4801,7 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -4810,7 +4810,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -4821,10 +4821,10 @@ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "regex-not": "1.0.2", - "safe-regex": "1.1.0" + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" } }, "to-regex-range": { @@ -4833,8 +4833,8 @@ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "is-number": "3.0.0", - "repeat-string": "1.6.1" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } }, "to-through": { @@ -4843,7 +4843,7 @@ "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", "dev": true, "requires": { - "through2": "2.0.3" + "through2": "^2.0.3" } }, "tough-cookie": { @@ -4852,7 +4852,7 @@ "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", "dev": true, "requires": { - "punycode": "1.4.1" + "punycode": "^1.4.1" } }, "ts-node": { @@ -4861,14 +4861,14 @@ "integrity": "sha512-klJsfswHP0FuOLsvBZ/zzCfUvakOSSxds78mVeK7I+qP76YWtxf16hEZsp3U+b0kIo82R5UatGFeblYMqabb2Q==", "dev": true, "requires": { - "arrify": "1.0.1", - "buffer-from": "1.1.0", - "diff": "3.5.0", - "make-error": "1.3.4", - "minimist": "1.2.0", - "mkdirp": "0.5.1", - "source-map-support": "0.5.6", - "yn": "2.0.0" + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" } }, "tslib": { @@ -4883,18 +4883,18 @@ "integrity": "sha1-mPMMAurjzecAYgHkwzywi0hYHu0=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "builtin-modules": "1.1.1", - "chalk": "2.4.1", - "commander": "2.15.1", - "diff": "3.5.0", - "glob": "7.1.2", - "js-yaml": "3.12.0", - "minimatch": "3.0.4", - "resolve": "1.8.1", - "semver": "5.5.0", - "tslib": "1.9.3", - "tsutils": "2.28.0" + "babel-code-frame": "^6.22.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.7.0", + "minimatch": "^3.0.4", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.27.2" }, "dependencies": { "ansi-styles": { @@ -4903,7 +4903,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "1.9.2" + "color-convert": "^1.9.0" } }, "chalk": { @@ -4912,9 +4912,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "has-flag": { @@ -4935,7 +4935,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -4946,11 +4946,11 @@ "integrity": "sha1-jNo8OMnKtU57It989CuO8RXc2V8=", "dev": true, "requires": { - "chalk": "1.1.3", - "lodash": "3.10.1", - "log-symbols": "1.0.2", - "text-table": "0.2.0", - "tslint": "2.5.1" + "chalk": "^1.1.1", + "lodash": "^3.10.1", + "log-symbols": "^1.0.2", + "text-table": "^0.2.0", + "tslint": "^2.5.0" }, "dependencies": { "findup-sync": { @@ -4959,7 +4959,7 @@ "integrity": "sha1-4KkKRQB1xJRm7lE3MgV1FLgeh4w=", "dev": true, "requires": { - "glob": "4.3.5" + "glob": "~4.3.0" } }, "glob": { @@ -4968,10 +4968,10 @@ "integrity": "sha1-gPuwjKVA8jiszl0R0em8QedRc9M=", "dev": true, "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "2.0.10", - "once": "1.4.0" + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^2.0.1", + "once": "^1.3.0" } }, "lodash": { @@ -4986,7 +4986,7 @@ "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.0.0" } }, "tslint": { @@ -4995,9 +4995,9 @@ "integrity": "sha1-veTJnpfNXRxvuzAz9kt9iX/UGpI=", "dev": true, "requires": { - "findup-sync": "0.2.1", - "optimist": "0.6.1", - "underscore.string": "3.1.1" + "findup-sync": "~0.2.1", + "optimist": "~0.6.0", + "underscore.string": "~3.1.1" } } } @@ -5008,7 +5008,7 @@ "integrity": "sha512-bh5nAtW0tuhvOJnx1GLRn5ScraRLICGyJV5wJhtRWOLsxW70Kk5tZtpK3O/hW6LDnqKS9mlUMPZj9fEMJ0gxqA==", "dev": true, "requires": { - "tslib": "1.9.3" + "tslib": "^1.8.1" } }, "tunnel-agent": { @@ -5017,7 +5017,7 @@ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { @@ -5033,7 +5033,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "1.1.2" + "prelude-ls": "~1.1.2" } }, "type-detect": { @@ -5055,9 +5055,9 @@ "dev": true, "optional": true, "requires": { - "source-map": "0.5.7", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" } }, "uglify-to-browserify": { @@ -5085,10 +5085,10 @@ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", "dev": true, "requires": { - "arr-union": "3.1.0", - "get-value": "2.0.6", - "is-extendable": "0.1.1", - "set-value": "0.4.3" + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" }, "dependencies": { "extend-shallow": { @@ -5097,7 +5097,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "set-value": { @@ -5106,10 +5106,10 @@ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "to-object-path": "0.3.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" } } } @@ -5126,8 +5126,8 @@ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "has-value": "0.3.1", - "isobject": "3.0.1" + "has-value": "^0.3.1", + "isobject": "^3.0.0" }, "dependencies": { "has-value": { @@ -5136,9 +5136,9 @@ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "0.1.4", - "isobject": "2.1.0" + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" }, "dependencies": { "isobject": { @@ -5208,7 +5208,7 @@ "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", "dev": true, "requires": { - "user-home": "1.1.1" + "user-home": "^1.1.1" } }, "validator": { @@ -5228,9 +5228,9 @@ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "dev": true, "requires": { - "assert-plus": "1.0.0", + "assert-plus": "^1.0.0", "core-util-is": "1.0.2", - "extsprintf": "1.3.0" + "extsprintf": "^1.2.0" } }, "vinyl": { @@ -5239,8 +5239,8 @@ "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", "dev": true, "requires": { - "clone": "1.0.4", - "clone-stats": "0.0.1", + "clone": "^1.0.0", + "clone-stats": "^0.0.1", "replace-ext": "0.0.1" } }, @@ -5250,14 +5250,14 @@ "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", "dev": true, "requires": { - "defaults": "1.0.3", - "glob-stream": "3.1.18", - "glob-watcher": "0.0.6", - "graceful-fs": "3.0.11", - "mkdirp": "0.5.1", - "strip-bom": "1.0.0", - "through2": "0.6.5", - "vinyl": "0.4.6" + "defaults": "^1.0.0", + "glob-stream": "^3.1.5", + "glob-watcher": "^0.0.6", + "graceful-fs": "^3.0.0", + "mkdirp": "^0.5.0", + "strip-bom": "^1.0.0", + "through2": "^0.6.1", + "vinyl": "^0.4.0" }, "dependencies": { "clone": { @@ -5268,14 +5268,14 @@ }, "readable-stream": { "version": "1.0.34", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } }, "through2": { @@ -5284,8 +5284,8 @@ "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { - "readable-stream": "1.0.34", - "xtend": "4.0.1" + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" } }, "vinyl": { @@ -5294,8 +5294,8 @@ "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", "dev": true, "requires": { - "clone": "0.2.0", - "clone-stats": "0.0.1" + "clone": "^0.2.0", + "clone-stats": "^0.0.1" } } } @@ -5306,13 +5306,13 @@ "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", "dev": true, "requires": { - "append-buffer": "1.0.2", - "convert-source-map": "1.5.1", - "graceful-fs": "4.1.11", - "normalize-path": "2.1.1", - "now-and-later": "2.0.0", - "remove-bom-buffer": "3.0.0", - "vinyl": "2.2.0" + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" }, "dependencies": { "clone": { @@ -5345,12 +5345,12 @@ "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", "dev": true, "requires": { - "clone": "2.1.1", - "clone-buffer": "1.0.0", - "clone-stats": "1.0.0", - "cloneable-readable": "1.1.2", - "remove-trailing-separator": "1.1.0", - "replace-ext": "1.0.0" + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" } } } @@ -5361,7 +5361,7 @@ "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", "dev": true, "requires": { - "source-map": "0.5.7" + "source-map": "^0.5.1" } }, "which": { @@ -5370,7 +5370,7 @@ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "window-size": { @@ -5405,9 +5405,9 @@ "dev": true, "optional": true, "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", "window-size": "0.1.0" } }, diff --git a/package.json b/package.json index 203a64db0c..8584319a60 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@types/mocha": "^5.2.5", "@types/node": "^10.5.2", "@types/sinon": "^5.0.1", - "@types/validator": "^9.4.2", + "@types/validator": "^9.4.3", "chai": "^4.1.2", "chai-as-promised": "^7.1.1", "codecov": "^3.0.4", diff --git a/sample/sample1-simple-validation/Post.ts b/sample/sample1-simple-validation/Post.ts index 6608748665..6c0a1c8fa2 100644 --- a/sample/sample1-simple-validation/Post.ts +++ b/sample/sample1-simple-validation/Post.ts @@ -1,8 +1,10 @@ -import {MinLength, MaxLength, IsEmail, IsFQDN, ArrayNotEmpty, ArrayMinSize, ArrayMaxSize} from "../../src/decorator/decorators"; +import {MinLength, MaxLength, ArrayNotEmpty, ArrayMinSize, ArrayMaxSize} from "../../src/decorator/decorators"; import {IsDate} from "../../src/decorator/IsDate"; import {IsInt} from "../../src/decorator/IsInt"; import {IsEnum} from "../../src/decorator/IsEnum"; import {Contains} from "../../src/decorator/Contains"; +import {IsEmail} from "../../src/decorator/IsEmail"; +import {IsFQDN} from "../../src/decorator/IsFQDN"; export enum PostType { Public, diff --git a/sample/sample2-using-groups/Post.ts b/sample/sample2-using-groups/Post.ts index dcc3bd2571..432613850a 100644 --- a/sample/sample2-using-groups/Post.ts +++ b/sample/sample2-using-groups/Post.ts @@ -1,7 +1,9 @@ -import {Length, IsEmail, IsFQDN} from "../../src/decorator/decorators"; +import {Length} from "../../src/decorator/decorators"; import {IsDate} from "../../src/decorator/IsDate"; import {IsInt} from "../../src/decorator/IsInt"; import {Contains} from "../../src/decorator/Contains"; +import {IsEmail} from "../../src/decorator/IsEmail"; +import {IsFQDN} from "../../src/decorator/IsFQDN"; export class Post { diff --git a/sample/sample7-inheritance-support/BaseContent.ts b/sample/sample7-inheritance-support/BaseContent.ts index e6b0171fbd..297fef3981 100644 --- a/sample/sample7-inheritance-support/BaseContent.ts +++ b/sample/sample7-inheritance-support/BaseContent.ts @@ -1,8 +1,8 @@ -import {IsEmail} from "../../src/decorator/decorators"; +import {IsEmail} from "../../src/decorator/IsEmail"; export class BaseContent { @IsEmail() email: string; -} \ No newline at end of file +} diff --git a/src/decorator/IsAlpha.ts b/src/decorator/IsAlpha.ts new file mode 100644 index 0000000000..0d120738f0 --- /dev/null +++ b/src/decorator/IsAlpha.ts @@ -0,0 +1,26 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsAlpha = require("validator/lib/isAlpha"); + +/** + * Checks if the string contains only letters (a-zA-Z). + * If given value is not a string, then it returns false. + */ +export function isAlpha(value: string): boolean { + return typeof value === "string" && validatorJsIsAlpha(value); +} + + +/** + * Checks if the string contains only letters (a-zA-Z). + */ +export function IsAlpha(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isAlpha", + validate: (value) => isAlpha(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain only letters (a-zA-Z)", validationOptions) + }, + validationOptions + ); +} + diff --git a/src/decorator/IsAlphanumeric.ts b/src/decorator/IsAlphanumeric.ts new file mode 100644 index 0000000000..f8f73b82df --- /dev/null +++ b/src/decorator/IsAlphanumeric.ts @@ -0,0 +1,25 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsAlphanumeric = require("validator/lib/isAlphanumeric"); + +/** + * Checks if the string contains only letters and numbers. + * If given value is not a string, then it returns false. + */ +export function isAlphanumeric(value: string): boolean { + return typeof value === "string" && validatorJsIsAlphanumeric(value); +} + + +/** + * Checks if the string contains only letters and numbers. + */ +export function IsAlphanumeric(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isAlphanumeric", + validate: (value) => isAlphanumeric(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain only letters and numbers", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsAscii.ts b/src/decorator/IsAscii.ts new file mode 100644 index 0000000000..f23beea36e --- /dev/null +++ b/src/decorator/IsAscii.ts @@ -0,0 +1,24 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsAscii = require("validator/lib/isAscii"); + +/** + * Checks if the string contains ASCII chars only. + * If given value is not a string, then it returns false. + */ +export function isAscii(value: string): boolean { + return typeof value === "string" && validatorJsIsAscii(value); +} + +/** + * Checks if the string contains ASCII chars only. + */ +export function IsAscii(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isAscii", + validate: (value) => isAscii(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain only ASCII characters", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsBase64.ts b/src/decorator/IsBase64.ts new file mode 100644 index 0000000000..268e46d83e --- /dev/null +++ b/src/decorator/IsBase64.ts @@ -0,0 +1,26 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsBase64 = require("validator/lib/isBase64"); + + +/** + * Checks if a string is base64 encoded. + * If given value is not a string, then it returns false. + */ +export function isBase64(value: string): boolean { + return typeof value === "string" && validatorJsIsBase64(value); +} + + +/** + * Checks if a string is base64 encoded. + */ +export function IsBase64(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isBase64", + validate: (value) => isBase64(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be base64 encoded", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsByteLength.ts b/src/decorator/IsByteLength.ts new file mode 100644 index 0000000000..3efe4723f3 --- /dev/null +++ b/src/decorator/IsByteLength.ts @@ -0,0 +1,27 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsByteLength = require("validator/lib/isByteLength"); + + +/** + * Checks if the string's length (in bytes) falls in a range. + * If given value is not a string, then it returns false. + */ +export function isByteLength(value: string, min: number, max?: number): boolean { + return typeof value === "string" && validatorJsIsByteLength(value, min, max); +} + + +/** + * Checks if the string's length (in bytes) falls in a range. + */ +export function IsByteLength(min: number, max?: number, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isByteLength", + validate: (value, args) => isByteLength(value, args.constraints[0], args.constraints[1]), + constraints: [min, max], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property's byte length must fall into ($constraint1, $constraint2) range", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsCreditCard.ts b/src/decorator/IsCreditCard.ts new file mode 100644 index 0000000000..557ec63aea --- /dev/null +++ b/src/decorator/IsCreditCard.ts @@ -0,0 +1,25 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsCreditCard = require("validator/lib/isCreditCard"); + +/** + * Checks if the string is a credit card. + * If given value is not a string, then it returns false. + */ +export function isCreditCard(value: string): boolean { + return typeof value === "string" && validatorJsIsCreditCard(value); +} + + +/** + * Checks if the string is a credit card. + */ +export function IsCreditCard(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isCreditCard", + validate: (value) => isCreditCard(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a credit card", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsCurrency.ts b/src/decorator/IsCurrency.ts new file mode 100644 index 0000000000..fc7bcb8e14 --- /dev/null +++ b/src/decorator/IsCurrency.ts @@ -0,0 +1,26 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsCurrency = require("validator/lib/isCurrency"); + + +/** + * Checks if the string is a valid currency amount. + * If given value is not a string, then it returns false. + */ +export function isCurrency(value: string, options?: ValidatorJS.IsCurrencyOptions): boolean { + return typeof value === "string" && validatorJsIsCurrency(value, options); +} + +/** + * Checks if the string is a valid currency amount. + */ +export function IsCurrency(options?: ValidatorJS.IsCurrencyOptions, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isCurrency", + validate: (value, args) => isCurrency(value, args.constraints[0]), + constraints: [options], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a currency", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsEmail.ts b/src/decorator/IsEmail.ts new file mode 100644 index 0000000000..12d04ac61a --- /dev/null +++ b/src/decorator/IsEmail.ts @@ -0,0 +1,25 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsEmail = require("validator/lib/isEmail"); + +/** + * Checks if the string is an email. + * If given value is not a string, then it returns false. + */ +export function isEmail(value: string, options?: ValidatorJS.IsEmailOptions): boolean { + return typeof value === "string" && validatorJsIsEmail(value, options); +} + +/** + * Checks if the string is an email. + */ +export function IsEmail(options?: ValidatorJS.IsEmailOptions, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isEmail", + validate: (value, args) => isEmail(value, args.constraints[0]), + constraints: [options], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be an email", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsFQDN.ts b/src/decorator/IsFQDN.ts new file mode 100644 index 0000000000..735ee5a232 --- /dev/null +++ b/src/decorator/IsFQDN.ts @@ -0,0 +1,25 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsFQDN = require("validator/lib/isFQDN"); + +/** + * Checks if the string is a fully qualified domain name (e.g. domain.com). + * If given value is not a string, then it returns false. + */ +export function isFQDN(value: string, options?: ValidatorJS.IsFQDNOptions): boolean { + return typeof value === "string" && validatorJsIsFQDN(value, options); +} + +/** + * Checks if the string is a fully qualified domain name (e.g. domain.com). + */ +export function IsFQDN(options?: ValidatorJS.IsFQDNOptions, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isFqdn", + validate: (value, args) => isFQDN(value, args.constraints[0]), + constraints: [options], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a valid domain name", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsFullWidth.ts b/src/decorator/IsFullWidth.ts new file mode 100644 index 0000000000..9563fe91dd --- /dev/null +++ b/src/decorator/IsFullWidth.ts @@ -0,0 +1,27 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +// strange module export :( +const validatorJsIsFullWidth: (value: any) => boolean = require("validator/lib/isFullWidth").default; + +/** + * Checks if the string contains any full-width chars. + * If given value is not a string, then it returns false. + */ +export function isFullWidth(value: string): boolean { + return typeof value === "string" && validatorJsIsFullWidth(value); +} + + +/** + * Checks if the string contains any full-width chars. + */ +export function IsFullWidth(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isFullWidth", + validate: (value) => isFullWidth(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain a full-width characters", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsHalfWidth.ts b/src/decorator/IsHalfWidth.ts new file mode 100644 index 0000000000..0bba26e377 --- /dev/null +++ b/src/decorator/IsHalfWidth.ts @@ -0,0 +1,26 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +// strange module export :( +const validatorJsIsHalfWidth: (value: any) => boolean = require("validator/lib/isHalfWidth").default; + +/** + * Checks if the string contains any half-width chars. + * If given value is not a string, then it returns false. + */ +export function isHalfWidth(value: string): boolean { + return typeof value === "string" && validatorJsIsHalfWidth(value); +} + +/** + * Checks if the string contains any half-width chars. + */ +export function IsHalfWidth(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isHalfWidth", + validate: (value) => isHalfWidth(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain a half-width characters", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsHexColor.ts b/src/decorator/IsHexColor.ts new file mode 100644 index 0000000000..b840104140 --- /dev/null +++ b/src/decorator/IsHexColor.ts @@ -0,0 +1,25 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsHexColor = require("validator/lib/isHexColor"); + + +/** + * Checks if the string is a hexadecimal color. + * If given value is not a string, then it returns false. + */ +export function isHexColor(value: string): boolean { + return typeof value === "string" && validatorJsIsHexColor(value); +} + +/** + * Checks if the string is a hexadecimal color. + */ +export function IsHexColor(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isHexColor", + validate: (value) => isHexColor(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a hexadecimal color", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsHexadecimal.ts b/src/decorator/IsHexadecimal.ts new file mode 100644 index 0000000000..70862f5faa --- /dev/null +++ b/src/decorator/IsHexadecimal.ts @@ -0,0 +1,25 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsHexadecimal = require("validator/lib/isHexadecimal"); + + +/** + * Checks if the string is a hexadecimal number. + * If given value is not a string, then it returns false. + */ +export function isHexadecimal(value: string): boolean { + return typeof value === "string" && validatorJsIsHexadecimal(value); +} + +/** + * Checks if the string is a hexadecimal number. + */ +export function IsHexadecimal(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isHexadecimal", + validate: (value) => isHexadecimal(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a hexadecimal number", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsIP.ts b/src/decorator/IsIP.ts new file mode 100644 index 0000000000..658a50dc36 --- /dev/null +++ b/src/decorator/IsIP.ts @@ -0,0 +1,28 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsIP = require("validator/lib/isIP"); + + +/** + * Checks if the string is an IP (version 4 or 6). + * If given value is not a string, then it returns false. + */ +export function isIP(value: string, version?: "4" | "6"): boolean { + // typings for isIP are wrong: JS actually accepts strings and numbers + const versionNr = version ? Number(version) : undefined; + return typeof value === "string" && validatorJsIsIP(value, versionNr); +} + +/** + * Checks if the string is an IP (version 4 or 6). + */ +export function IsIP(version?: "4" | "6", validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isIp", + validate: (value, args) => isIP(value, args.constraints[0]), + constraints: [version], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be an ip address", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsISBN.ts b/src/decorator/IsISBN.ts new file mode 100644 index 0000000000..2cf034f03c --- /dev/null +++ b/src/decorator/IsISBN.ts @@ -0,0 +1,28 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsISBN = require("validator/lib/isISBN"); + + +/** + * Checks if the string is an ISBN (version 10 or 13). + * If given value is not a string, then it returns false. + */ +export function isISBN(value: string, version?: "10" | "13"): boolean { + // typings are wrong: JS actually allows string or number + const versionNr = version ? Number(version) : undefined; + return typeof value === "string" && validatorJsIsISBN(value, versionNr); +} + +/** + * Checks if the string is an ISBN (version 10 or 13). + */ +export function IsISBN(version?: "10" | "13", validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isIsbn", + validate: (value, args) => isISBN(value, args.constraints[0]), + constraints: [version], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be an ISBN", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsISIN.ts b/src/decorator/IsISIN.ts new file mode 100644 index 0000000000..f20ffbe13e --- /dev/null +++ b/src/decorator/IsISIN.ts @@ -0,0 +1,25 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsISIN = require("validator/lib/isISIN"); + + +/** + * Checks if the string is an ISIN (stock/security identifier). + * If given value is not a string, then it returns false. + */ +export function isISIN(value: string): boolean { + return typeof value === "string" && validatorJsIsISIN(value); +} + +/** + * Checks if the string is an ISIN (stock/security identifier). + */ +export function IsISIN(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isIsin", + validate: (value) => isISIN(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be an ISIN (stock/security identifier)", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsVariableWidth.ts b/src/decorator/IsVariableWidth.ts new file mode 100644 index 0000000000..f7ab55931a --- /dev/null +++ b/src/decorator/IsVariableWidth.ts @@ -0,0 +1,25 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; + +import validatorJsIsVariableWidth = require("validator/lib/isVariableWidth"); + +/** + * Checks if the string contains variable-width chars. + * If given value is not a string, then it returns false. + */ +export function isVariableWidth(value: string): boolean { + return typeof value === "string" && validatorJsIsVariableWidth(value); +} + +/** + * Checks if the string contains a mixture of full and half-width chars. + */ +export function IsVariableWidth(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "isVariableWidth", + validate: (value) => isVariableWidth(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain a full-width and half-width characters", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/NotContains.ts b/src/decorator/NotContains.ts new file mode 100644 index 0000000000..52b0c464a0 --- /dev/null +++ b/src/decorator/NotContains.ts @@ -0,0 +1,27 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import {contains} from "./Contains"; + + +/** + * Checks if the string does not contain the seed. + * If given value is not a string, then it returns false. + */ +export function notContains(value: string, seed: string): boolean { + return typeof value === "string" && !contains(value, seed); +} + + +/** + * Checks if the string does not contain the seed. + */ +export function NotContains(seed: string, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: "notContains", + validate: (value, args) => notContains(value, args.constraints[0]), + constraints: [seed], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property should not contain a $constraint1 string", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/decorators.ts b/src/decorator/decorators.ts index 01d1c39f2c..0b681de9f9 100644 --- a/src/decorator/decorators.ts +++ b/src/decorator/decorators.ts @@ -91,283 +91,6 @@ export function IsOptional(validationOptions?: ValidationOptions) { // ------------------------------------------------------------------------- -/** - * Checks if the string does not contain the seed. - */ -export function NotContains(seed: string, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.NOT_CONTAINS, - target: object.constructor, - propertyName: propertyName, - constraints: [seed], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string contains only letters (a-zA-Z). - */ -export function IsAlpha(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_ALPHA, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string contains only letters and numbers. - */ -export function IsAlphanumeric(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_ALPHANUMERIC, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string contains ASCII chars only. - */ -export function IsAscii(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_ASCII, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if a string is base64 encoded. - */ -export function IsBase64(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_BASE64, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string's length (in bytes) falls in a range. - */ -export function IsByteLength(min: number, max?: number, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_BYTE_LENGTH, - target: object.constructor, - propertyName: propertyName, - constraints: [min, max], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is a credit card. - */ -export function IsCreditCard(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_CREDIT_CARD, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is a valid currency amount. - */ -export function IsCurrency(options?: ValidatorJS.IsCurrencyOptions, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_CURRENCY, - target: object.constructor, - propertyName: propertyName, - constraints: [options], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is an email. - */ -export function IsEmail(options?: ValidatorJS.IsEmailOptions, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_EMAIL, - target: object.constructor, - propertyName: propertyName, - constraints: [options], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is a fully qualified domain name (e.g. domain.com). - */ -export function IsFQDN(options?: ValidatorJS.IsFQDNOptions, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_FQDN, - target: object.constructor, - propertyName: propertyName, - constraints: [options], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string contains any full-width chars. - */ -export function IsFullWidth(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_FULL_WIDTH, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string contains any half-width chars. - */ -export function IsHalfWidth(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_HALF_WIDTH, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string contains a mixture of full and half-width chars. - */ -export function IsVariableWidth(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_VARIABLE_WIDTH, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is a hexadecimal color. - */ -export function IsHexColor(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_HEX_COLOR, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is a hexadecimal number. - */ -export function IsHexadecimal(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_HEXADECIMAL, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is an IP (version 4 or 6). - */ -export function IsIP(version?: "4" | "6", validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_IP, - target: object.constructor, - propertyName: propertyName, - constraints: [version], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is an ISBN (version 10 or 13). - */ -export function IsISBN(version?: "10" | "13", validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_ISBN, - target: object.constructor, - propertyName: propertyName, - constraints: [version], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is an ISIN (stock/security identifier). - */ -export function IsISIN(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_ISIN, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - /** * Checks if the string is a valid ISO 8601 date. */ diff --git a/src/validation/ValidationTypes.ts b/src/validation/ValidationTypes.ts index 78d85f88f0..135cd50881 100644 --- a/src/validation/ValidationTypes.ts +++ b/src/validation/ValidationTypes.ts @@ -14,24 +14,6 @@ export class ValidationTypes { static IS_DEFINED = "isDefined"; /* string checkers */ - static NOT_CONTAINS = "notContains"; - static IS_ALPHA = "isAlpha"; - static IS_ALPHANUMERIC = "isAlphanumeric"; - static IS_ASCII = "isAscii"; - static IS_BASE64 = "isBase64"; - static IS_BYTE_LENGTH = "isByteLength"; - static IS_CREDIT_CARD = "isCreditCard"; - static IS_CURRENCY = "isCurrency"; - static IS_EMAIL = "isEmail"; - static IS_FQDN = "isFqdn"; - static IS_FULL_WIDTH = "isFullWidth"; - static IS_HALF_WIDTH = "isHalfWidth"; - static IS_VARIABLE_WIDTH = "isVariableWidth"; - static IS_HEX_COLOR = "isHexColor"; - static IS_HEXADECIMAL = "isHexadecimal"; - static IS_IP = "isIp"; - static IS_ISBN = "isIsbn"; - static IS_ISIN = "isIsin"; static IS_ISO8601 = "isIso8601"; static IS_JSON = "isJson"; static IS_LOWERCASE = "isLowercase"; @@ -82,42 +64,6 @@ export class ValidationTypes { return eachPrefix + "$property should not be null or undefined"; /* string checkers */ - case this.NOT_CONTAINS: - return eachPrefix + "$property should not contain a $constraint1 string"; - case this.IS_ALPHA: - return eachPrefix + "$property must contain only letters (a-zA-Z)"; - case this.IS_ALPHANUMERIC: - return eachPrefix + "$property must contain only letters and numbers"; - case this.IS_ASCII: - return eachPrefix + "$property must contain only ASCII characters"; - case this.IS_BASE64: - return eachPrefix + "$property must be base64 encoded"; - case this.IS_BYTE_LENGTH: - return eachPrefix + "$property's byte length must fall into ($constraint1, $constraint2) range"; - case this.IS_CREDIT_CARD: - return eachPrefix + "$property must be a credit card"; - case this.IS_CURRENCY: - return eachPrefix + "$property must be a currency"; - case this.IS_EMAIL: - return eachPrefix + "$property must be an email"; - case this.IS_FQDN: - return eachPrefix + "$property must be a valid domain name"; - case this.IS_FULL_WIDTH: - return eachPrefix + "$property must contain a full-width characters"; - case this.IS_HALF_WIDTH: - return eachPrefix + "$property must contain a half-width characters"; - case this.IS_VARIABLE_WIDTH: - return eachPrefix + "$property must contain a full-width and half-width characters"; - case this.IS_HEX_COLOR: - return eachPrefix + "$property must be a hexadecimal color"; - case this.IS_HEXADECIMAL: - return eachPrefix + "$property must be a hexadecimal number"; - case this.IS_IP: - return eachPrefix + "$property must be an ip address"; - case this.IS_ISBN: - return eachPrefix + "$property must be an ISBN"; - case this.IS_ISIN: - return eachPrefix + "$property must be an ISIN (stock/security identifier)"; case this.IS_ISO8601: return eachPrefix + "$property must be a valid ISO 8601 date string"; case this.IS_JSON: diff --git a/src/validation/Validator.ts b/src/validation/Validator.ts index 830e8b1477..a587caf09d 100644 --- a/src/validation/Validator.ts +++ b/src/validation/Validator.ts @@ -112,42 +112,6 @@ export class Validator { return this.isDefined(value); /* string checkers */ - case ValidationTypes.NOT_CONTAINS: - return this.notContains(value, metadata.constraints[0]); - case ValidationTypes.IS_ALPHA: - return this.isAlpha(value); - case ValidationTypes.IS_ALPHANUMERIC: - return this.isAlphanumeric(value); - case ValidationTypes.IS_ASCII: - return this.isAscii(value); - case ValidationTypes.IS_BASE64: - return this.isBase64(value); - case ValidationTypes.IS_BYTE_LENGTH: - return this.isByteLength(value, metadata.constraints[0], metadata.constraints[1]); - case ValidationTypes.IS_CREDIT_CARD: - return this.isCreditCard(value); - case ValidationTypes.IS_CURRENCY: - return this.isCurrency(value, metadata.constraints[0]); - case ValidationTypes.IS_EMAIL: - return this.isEmail(value, metadata.constraints[0]); - case ValidationTypes.IS_FQDN: - return this.isFQDN(value, metadata.constraints[0]); - case ValidationTypes.IS_FULL_WIDTH: - return this.isFullWidth(value); - case ValidationTypes.IS_HALF_WIDTH: - return this.isHalfWidth(value); - case ValidationTypes.IS_VARIABLE_WIDTH: - return this.isVariableWidth(value); - case ValidationTypes.IS_HEX_COLOR: - return this.isHexColor(value); - case ValidationTypes.IS_HEXADECIMAL: - return this.isHexadecimal(value); - case ValidationTypes.IS_IP: - return this.isIP(value, metadata.constraints[0]); - case ValidationTypes.IS_ISBN: - return this.isISBN(value, metadata.constraints[0]); - case ValidationTypes.IS_ISIN: - return this.isISIN(value); case ValidationTypes.IS_ISO8601: return this.isISO8601(value); case ValidationTypes.IS_JSON: @@ -215,149 +179,6 @@ export class Validator { // ------------------------------------------------------------------------- - /** - * Checks if the string does not contain the seed. - * If given value is not a string, then it returns false. - */ - notContains(value: string, seed: string): boolean { - return typeof value === "string" && !this.validatorJs.contains(value, seed); - } - - /** - * Checks if the string contains only letters (a-zA-Z). - * If given value is not a string, then it returns false. - */ - isAlpha(value: string): boolean { - return typeof value === "string" && this.validatorJs.isAlpha(value); - } - - /** - * Checks if the string contains only letters and numbers. - * If given value is not a string, then it returns false. - */ - isAlphanumeric(value: string): boolean { - return typeof value === "string" && this.validatorJs.isAlphanumeric(value); - } - - /** - * Checks if the string contains ASCII chars only. - * If given value is not a string, then it returns false. - */ - isAscii(value: string): boolean { - return typeof value === "string" && this.validatorJs.isAscii(value); - } - - /** - * Checks if a string is base64 encoded. - * If given value is not a string, then it returns false. - */ - isBase64(value: string): boolean { - return typeof value === "string" && this.validatorJs.isBase64(value); - } - - /** - * Checks if the string's length (in bytes) falls in a range. - * If given value is not a string, then it returns false. - */ - isByteLength(value: string, min: number, max?: number): boolean { - return typeof value === "string" && this.validatorJs.isByteLength(value, min, max); - } - - /** - * Checks if the string is a credit card. - * If given value is not a string, then it returns false. - */ - isCreditCard(value: string): boolean { - return typeof value === "string" && this.validatorJs.isCreditCard(value); - } - - /** - * Checks if the string is a valid currency amount. - * If given value is not a string, then it returns false. - */ - isCurrency(value: string, options?: ValidatorJS.IsCurrencyOptions): boolean { - return typeof value === "string" && this.validatorJs.isCurrency(value, options); - } - - /** - * Checks if the string is an email. - * If given value is not a string, then it returns false. - */ - isEmail(value: string, options?: ValidatorJS.IsEmailOptions): boolean { - return typeof value === "string" && this.validatorJs.isEmail(value, options); - } - - /** - * Checks if the string is a fully qualified domain name (e.g. domain.com). - * If given value is not a string, then it returns false. - */ - isFQDN(value: string, options?: ValidatorJS.IsFQDNOptions): boolean { - return typeof value === "string" && this.validatorJs.isFQDN(value, options); - } - - /** - * Checks if the string contains any full-width chars. - * If given value is not a string, then it returns false. - */ - isFullWidth(value: string): boolean { - return typeof value === "string" && this.validatorJs.isFullWidth(value); - } - - /** - * Checks if the string contains any half-width chars. - * If given value is not a string, then it returns false. - */ - isHalfWidth(value: string): boolean { - return typeof value === "string" && this.validatorJs.isHalfWidth(value); - } - - /** - * Checks if the string contains variable-width chars. - * If given value is not a string, then it returns false. - */ - isVariableWidth(value: string): boolean { - return typeof value === "string" && this.validatorJs.isVariableWidth(value); - } - - /** - * Checks if the string is a hexadecimal color. - * If given value is not a string, then it returns false. - */ - isHexColor(value: string): boolean { - return typeof value === "string" && this.validatorJs.isHexColor(value); - } - - /** - * Checks if the string is a hexadecimal number. - * If given value is not a string, then it returns false. - */ - isHexadecimal(value: string): boolean { - return typeof value === "string" && this.validatorJs.isHexadecimal(value); - } - - /** - * Checks if the string is an IP (version 4 or 6). - * If given value is not a string, then it returns false. - */ - isIP(value: string, version?: "4"|"6"): boolean { - return typeof value === "string" && this.validatorJs.isIP(value, version); - } - - /** - * Checks if the string is an ISBN (version 10 or 13). - * If given value is not a string, then it returns false. - */ - isISBN(value: string, version?: "10"|"13"): boolean { - return typeof value === "string" && this.validatorJs.isISBN(value, version); - } - - /** - * Checks if the string is an ISIN (stock/security identifier). - * If given value is not a string, then it returns false. - */ - isISIN(value: string): boolean { - return typeof value === "string" && this.validatorJs.isISIN(value); - } /** * Checks if the string is a valid ISO 8601 date. diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts index 9188a7c8a3..a1ccb0a024 100644 --- a/test/functional/validation-functions-and-decorators.spec.ts +++ b/test/functional/validation-functions-and-decorators.spec.ts @@ -1,22 +1,6 @@ import "es6-shim"; import {expect} from "chai"; import { - IsAlpha, - IsAlphanumeric, - IsAscii, - IsBase64, - IsByteLength, - IsCreditCard, - IsCurrency, - IsEmail, - IsFQDN, - IsFullWidth, - IsHalfWidth, - IsVariableWidth, - IsHexColor, - IsHexadecimal, - IsIP, - IsISBN, IsISO8601, IsJSON, Length, @@ -35,11 +19,11 @@ import { ArrayMinSize, ArrayMaxSize, IsDefined, - NotContains, ArrayContains, ArrayNotContains, ArrayUnique, - IsInstance} from "../../src/decorator/decorators"; + IsInstance +} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; import {ValidatorOptions} from "../../src/validation/ValidatorOptions"; @@ -71,6 +55,24 @@ import {maxDate, MaxDate} from "../../src/decorator/MaxDate"; import {isBooleanString, IsBooleanString} from "../../src/decorator/IsBooleanString"; import {IsNumberString, isNumberString} from "../../src/decorator/IsNumberString"; import {Contains, contains} from "../../src/decorator/Contains"; +import {NotContains, notContains} from "../../src/decorator/NotContains"; +import {IsAlpha, isAlpha} from "../../src/decorator/IsAlpha"; +import {isAlphanumeric, IsAlphanumeric} from "../../src/decorator/IsAlphanumeric"; +import {IsAscii, isAscii} from "../../src/decorator/IsAscii"; +import {IsBase64, isBase64} from "../../src/decorator/IsBase64"; +import {IsByteLength, isByteLength} from "../../src/decorator/IsByteLength"; +import {IsCreditCard, isCreditCard} from "../../src/decorator/IsCreditCard"; +import {IsCurrency, isCurrency} from "../../src/decorator/IsCurrency"; +import {IsEmail, isEmail} from "../../src/decorator/IsEmail"; +import {isFQDN, IsFQDN} from "../../src/decorator/IsFQDN"; +import {isFullWidth, IsFullWidth} from "../../src/decorator/IsFullWidth"; +import {isHalfWidth, IsHalfWidth} from "../../src/decorator/IsHalfWidth"; +import {IsVariableWidth, isVariableWidth} from "../../src/decorator/IsVariableWidth"; +import {isHexColor, IsHexColor} from "../../src/decorator/IsHexColor"; +import {isHexadecimal, IsHexadecimal} from "../../src/decorator/IsHexadecimal"; +import {isIP, IsIP} from "../../src/decorator/IsIP"; +import {isISBN, IsISBN} from "../../src/decorator/IsISBN"; +import {isISIN, IsISIN} from "../../src/decorator/IsISIN"; should(); use(chaiAsPromised); @@ -1223,11 +1225,11 @@ describe("NotContains", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.notContains(value, constraint).should.be.true); + validValues.forEach(value => notContains(value, constraint).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.notContains(value, constraint).should.be.false); + invalidValues.forEach(value => notContains(value, constraint).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1258,11 +1260,11 @@ describe("IsAlpha", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isAlpha(value).should.be.true); + validValues.forEach(value => isAlpha(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isAlpha(value).should.be.false); + invalidValues.forEach(value => isAlpha(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1293,11 +1295,11 @@ describe("IsAlphanumeric", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isAlphanumeric(value).should.be.true); + validValues.forEach(value => isAlphanumeric(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isAlphanumeric(value).should.be.false); + invalidValues.forEach(value => isAlphanumeric(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1328,11 +1330,11 @@ describe("IsAscii", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isAscii(value).should.be.true); + validValues.forEach(value => isAscii(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isAscii(value).should.be.false); + invalidValues.forEach(value => isAscii(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1363,11 +1365,11 @@ describe("IsBase64", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isBase64(value).should.be.true); + validValues.forEach(value => isBase64(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isBase64(value).should.be.false); + invalidValues.forEach(value => isBase64(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1399,11 +1401,11 @@ describe("IsByteLength", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isByteLength(value, constraint1, constraint2).should.be.true); + validValues.forEach(value => isByteLength(value, constraint1, constraint2).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isByteLength(value, constraint1, constraint2).should.be.false); + invalidValues.forEach(value => isByteLength(value, constraint1, constraint2).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1440,11 +1442,11 @@ describe("IsCreditCard", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isCreditCard(value).should.be.true); + validValues.forEach(value => isCreditCard(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isCreditCard(value).should.be.false); + invalidValues.forEach(value => isCreditCard(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1518,11 +1520,11 @@ describe("IsCurrency", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isCurrency(value).should.be.true); + validValues.forEach(value => isCurrency(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isCurrency(value).should.be.false); + invalidValues.forEach(value => isCurrency(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1578,13 +1580,13 @@ describe("IsEmail", function() { it("should not fail if method in validator said that its valid", function() { validValues.forEach(value => { - console.log(value, validator.isEmail(value)); - return validator.isEmail(value).should.be.true; + console.log(value, isEmail(value)); + return isEmail(value).should.be.true; }); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isEmail(value).should.be.false); + invalidValues.forEach(value => isEmail(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1631,11 +1633,11 @@ describe("IsFQDN", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isFQDN(value).should.be.true); + validValues.forEach(value => isFQDN(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isFQDN(value).should.be.false); + invalidValues.forEach(value => isFQDN(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1675,11 +1677,11 @@ describe("IsFullWidth", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isFullWidth(value).should.be.true); + validValues.forEach(value => isFullWidth(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isFullWidth(value).should.be.false); + invalidValues.forEach(value => isFullWidth(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1718,11 +1720,11 @@ describe("IsHalfWidth", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isHalfWidth(value).should.be.true); + validValues.forEach(value => isHalfWidth(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isHalfWidth(value).should.be.false); + invalidValues.forEach(value => isHalfWidth(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1766,11 +1768,11 @@ describe("IsVariableWidth", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isVariableWidth(value).should.be.true); + validValues.forEach(value => isVariableWidth(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isVariableWidth(value).should.be.false); + invalidValues.forEach(value => isVariableWidth(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1811,11 +1813,11 @@ describe("IsHexColor", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isHexColor(value).should.be.true); + validValues.forEach(value => isHexColor(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isHexColor(value).should.be.false); + invalidValues.forEach(value => isHexColor(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1854,11 +1856,11 @@ describe("IsHexadecimal", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isHexadecimal(value).should.be.true); + validValues.forEach(value => isHexadecimal(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isHexadecimal(value).should.be.false); + invalidValues.forEach(value => isHexadecimal(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1925,11 +1927,11 @@ describe("IsIP", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isIP(value).should.be.true); + validValues.forEach(value => isIP(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isIP(value).should.be.false); + invalidValues.forEach(value => isIP(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -1938,6 +1940,12 @@ describe("IsIP", function() { checkReturnedError(new MyClass(), invalidValues, validationType, message, done); }); + it("should heed the version param", function() { + isIP("123.123.123.123", "4").should.be.true; + isIP("123.123.123.123", "6").should.be.false; + isIP("::1", "4").should.be.false; + isIP("::1", "6").should.be.true; + }); }); describe("IsISBN version 10", function() { @@ -1969,11 +1977,11 @@ describe("IsISBN version 10", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isISBN(value, "10").should.be.true); + validValues.forEach(value => isISBN(value, "10").should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isISBN(value, "10").should.be.false); + invalidValues.forEach(value => isISBN(value, "10").should.be.false); }); it("should return error object with proper data", function(done) { @@ -1982,6 +1990,11 @@ describe("IsISBN version 10", function() { checkReturnedError(new MyClass(), invalidValues, validationType, message, done); }); + it("should heed the version param", function() { + isISBN("99921-58-10-7", "10").should.be.true; + isISBN("978-3-16-148410-0", "10").should.be.false; + }); + }); describe("IsISBN version 13", function() { @@ -2011,11 +2024,11 @@ describe("IsISBN version 13", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isISBN(value, "13").should.be.true); + validValues.forEach(value => isISBN(value, "13").should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isISBN(value, "13").should.be.false); + invalidValues.forEach(value => isISBN(value, "13").should.be.false); }); it("should return error object with proper data", function(done) { @@ -2024,8 +2037,56 @@ describe("IsISBN version 13", function() { checkReturnedError(new MyClass(), invalidValues, validationType, message, done); }); + it("should heed the version param", function() { + isISBN("978-3-16-148410-0", "13").should.be.true; + isISBN("99921-58-10-7", "13").should.be.false; + }); + }); +describe("IsISIN", function() { + + const validValues = [ + "US5949181045", "US38259P5089", "US0378331005" + , "BMG491BT1088", "IE00B4BNMY34", "US0231351067" + , "US64110L1061", "US30303M1027", "CH0031240127" + ]; + const invalidValues = [ + null, undefined, "9783836221190", "978-3-8362-2119-0", "978 3 8362 2119 0" + , "3836221195", "3-8362-2119-5", "3 8362 2119 5" + , "01234567890ab", "foo", "" + ]; + + class MyClass { + @IsISIN() + someProperty: string; + } + + it("should not fail if validator.validate said that its valid", function(done) { + checkValidValues(new MyClass(), validValues, done); + }); + + it("should fail if validator.validate said that its invalid", function(done) { + checkInvalidValues(new MyClass(), invalidValues, done); + }); + + it("should not fail if method in validator said that its valid", function() { + validValues.forEach(value => isISIN(value).should.be.true); + }); + + it("should fail if method in validator said that its invalid", function() { + invalidValues.forEach(value => isISIN(value).should.be.false); + }); + + it("should return error object with proper data", function(done) { + const validationType = "isIsin"; + const message = "someProperty must be an ISIN (stock/security identifier)"; + checkReturnedError(new MyClass(), invalidValues, validationType, message, done); + }); + +}); + + describe("IsISO8601", function() { const validValues = [ From b8ee2b64b2d08c1322736ae7bae944df84a184c0 Mon Sep 17 00:00:00 2001 From: Christoph Linder Date: Sat, 17 Nov 2018 01:22:07 +0100 Subject: [PATCH 10/12] Smaller bundle - undo accidental dependency downgrades --- package-lock.json | 1828 ++++++++++++++++++++++----------------------- package.json | 4 +- 2 files changed, 916 insertions(+), 916 deletions(-) diff --git a/package-lock.json b/package-lock.json index ce069473cd..2315a795ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "class-validator", - "version": "1.0.0-rc", + "version": "1.0.0-rc1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -10,11 +10,11 @@ "integrity": "sha512-ciiioYMLdo16ShmfHBXJBOFm3xPC4AuwO4xeRpFeHz7WK9PYsWCmigagG2XyzZpubK4a3qNKoUBDhbzHfa50LQ==", "dev": true, "requires": { - "acorn": "^5.0.3", - "css": "^2.2.1", - "normalize-path": "^2.1.1", - "source-map": "^0.6.0", - "through2": "^2.0.3" + "acorn": "5.7.1", + "css": "2.2.3", + "normalize-path": "2.1.1", + "source-map": "0.6.1", + "through2": "2.0.3" }, "dependencies": { "source-map": { @@ -31,8 +31,8 @@ "integrity": "sha1-iQrnxdjId/bThIYCFazp1+yUW9o=", "dev": true, "requires": { - "normalize-path": "^2.0.1", - "through2": "^2.0.3" + "normalize-path": "2.1.1", + "through2": "2.0.3" } }, "@sinonjs/formatio": { @@ -62,7 +62,7 @@ "integrity": "sha512-MFiW54UOSt+f2bRw8J7LgQeIvE/9b4oGvwU7XW30S9QGAiHGnU/fmiOprsyMkdmH2rl8xSPc0/yrQw8juXU6bQ==", "dev": true, "requires": { - "@types/chai": "*" + "@types/chai": "4.1.4" } }, "@types/chokidar": { @@ -71,8 +71,8 @@ "integrity": "sha512-PDkSRY7KltW3M60hSBlerxI8SFPXsO3AL/aRVsO4Kh9IHRW74Ih75gUuTd/aE4LSSFqypb10UIX3QzOJwBQMGQ==", "dev": true, "requires": { - "@types/events": "*", - "@types/node": "*" + "@types/events": "1.2.0", + "@types/node": "10.5.2" } }, "@types/events": { @@ -93,9 +93,9 @@ "integrity": "sha512-wc+VveszMLyMWFvXLkloixT4n0harUIVZjnpzztaZ0nKLuul7Z32iMt2fUFGAaZ4y1XWjFRMtCI5ewvyh4aIeg==", "dev": true, "requires": { - "@types/events": "*", - "@types/minimatch": "*", - "@types/node": "*" + "@types/events": "1.2.0", + "@types/minimatch": "3.0.3", + "@types/node": "10.5.2" } }, "@types/glob-stream": { @@ -104,8 +104,8 @@ "integrity": "sha512-RHv6ZQjcTncXo3thYZrsbAVwoy4vSKosSWhuhuQxLOTv74OJuFQxXkmUuZCr3q9uNBEVCvIzmZL/FeRNbHZGUg==", "dev": true, "requires": { - "@types/glob": "*", - "@types/node": "*" + "@types/glob": "5.0.35", + "@types/node": "10.5.2" } }, "@types/gulp": { @@ -114,9 +114,9 @@ "integrity": "sha512-nx1QjPTiRpvLfYsZ7MBu7bT6Cm7tAXyLbY0xbdx2IEMxCK2v2urIhJMQZHW0iV1TskM71Xl6p2uRRuWDbk+/7g==", "dev": true, "requires": { - "@types/chokidar": "*", - "@types/undertaker": "*", - "@types/vinyl-fs": "*" + "@types/chokidar": "1.7.5", + "@types/undertaker": "1.2.0", + "@types/vinyl-fs": "2.4.8" } }, "@types/minimatch": { @@ -149,8 +149,8 @@ "integrity": "sha512-bx/5nZCGkasXs6qaA3B6SVDjBZqdyk04UO12e0uEPSzjt5H8jEJw0DKe7O7IM0hM2bVHRh70pmOH7PEHqXwzOw==", "dev": true, "requires": { - "@types/events": "*", - "@types/undertaker-registry": "*" + "@types/events": "1.2.0", + "@types/undertaker-registry": "1.0.1" } }, "@types/undertaker-registry": { @@ -160,9 +160,9 @@ "dev": true }, "@types/validator": { - "version": "9.4.3", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-9.4.3.tgz", - "integrity": "sha512-D4zRrAs2pTg5cva6+hJ6GrQlb/UX5NxNtk/da3Gw27enoLvbRMTTloZ1w6CCqc+kHyZvT3DsyWQZ8baTGgSg0g==", + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-9.4.2.tgz", + "integrity": "sha512-v6H2QH+oXVdLKp9keOJi5LQSt6X5/XIOtK1YmbCzvkAT2kHW9WyQkixit9w1UgJpBGrDCqqCZlQ+Qucpmsf8hA==", "dev": true }, "@types/vinyl": { @@ -171,7 +171,7 @@ "integrity": "sha512-2iYpNuOl98SrLPBZfEN9Mh2JCJ2EI9HU35SfgBEb51DcmaHkhp8cKMblYeBqMQiwXMgAD3W60DbQ4i/UdLiXhw==", "dev": true, "requires": { - "@types/node": "*" + "@types/node": "10.5.2" } }, "@types/vinyl-fs": { @@ -180,9 +180,9 @@ "integrity": "sha512-yE2pN9OOrxJVeO7IZLHAHrh5R4Q0osbn5WQRuQU6GdXoK7dNFrMK3K7YhATkzf3z0yQBkol3+gafs7Rp0s7dDg==", "dev": true, "requires": { - "@types/glob-stream": "*", - "@types/node": "*", - "@types/vinyl": "*" + "@types/glob-stream": "6.1.0", + "@types/node": "10.5.2", + "@types/vinyl": "2.0.2" } }, "abbrev": { @@ -203,10 +203,10 @@ "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" } }, "align-text": { @@ -215,9 +215,9 @@ "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" }, "dependencies": { "kind-of": { @@ -226,7 +226,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -243,7 +243,7 @@ "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", "dev": true, "requires": { - "ansi-wrap": "^0.1.0" + "ansi-wrap": "0.1.0" } }, "ansi-cyan": { @@ -297,7 +297,7 @@ "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", "dev": true, "requires": { - "buffer-equal": "^1.0.0" + "buffer-equal": "1.0.0" } }, "archy": { @@ -312,7 +312,7 @@ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "sprintf-js": "~1.0.2" + "sprintf-js": "1.0.3" } }, "argv": { @@ -363,7 +363,7 @@ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "^1.0.1" + "array-uniq": "1.0.3" } }, "array-uniq": { @@ -444,9 +444,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" } }, "balanced-match": { @@ -461,13 +461,13 @@ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "cache-base": "1.0.1", + "class-utils": "0.3.6", + "component-emitter": "1.2.1", + "define-property": "1.0.0", + "isobject": "3.0.1", + "mixin-deep": "1.3.1", + "pascalcase": "0.1.1" }, "dependencies": { "define-property": { @@ -476,7 +476,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { @@ -485,7 +485,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -494,7 +494,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -503,9 +503,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -517,7 +517,7 @@ "dev": true, "optional": true, "requires": { - "tweetnacl": "^0.14.3" + "tweetnacl": "0.14.5" } }, "beeper": { @@ -538,7 +538,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -548,16 +548,16 @@ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.2", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -566,7 +566,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -601,15 +601,15 @@ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "collection-visit": "1.0.0", + "component-emitter": "1.2.1", + "get-value": "2.0.6", + "has-value": "1.0.0", + "isobject": "3.0.1", + "set-value": "2.0.0", + "to-object-path": "0.3.0", + "union-value": "1.0.0", + "unset-value": "1.0.0" } }, "camelcase": { @@ -632,8 +632,8 @@ "dev": true, "optional": true, "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" + "align-text": "0.1.4", + "lazy-cache": "1.0.4" } }, "chai": { @@ -642,12 +642,12 @@ "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", "dev": true, "requires": { - "assertion-error": "^1.0.1", - "check-error": "^1.0.1", - "deep-eql": "^3.0.0", - "get-func-name": "^2.0.0", - "pathval": "^1.0.0", - "type-detect": "^4.0.0" + "assertion-error": "1.1.0", + "check-error": "1.0.2", + "deep-eql": "3.0.1", + "get-func-name": "2.0.0", + "pathval": "1.1.0", + "type-detect": "4.0.8" } }, "chai-as-promised": { @@ -656,7 +656,7 @@ "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", "dev": true, "requires": { - "check-error": "^1.0.2" + "check-error": "1.0.2" } }, "chalk": { @@ -665,11 +665,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" } }, "check-error": { @@ -684,10 +684,10 @@ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "arr-union": "3.1.0", + "define-property": "0.2.5", + "isobject": "3.0.1", + "static-extend": "0.1.2" }, "dependencies": { "define-property": { @@ -696,7 +696,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -708,8 +708,8 @@ "dev": true, "optional": true, "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", + "center-align": "0.1.3", + "right-align": "0.1.3", "wordwrap": "0.0.2" }, "dependencies": { @@ -746,9 +746,9 @@ "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==", "dev": true, "requires": { - "inherits": "^2.0.1", - "process-nextick-args": "^2.0.0", - "readable-stream": "^2.3.5" + "inherits": "2.0.3", + "process-nextick-args": "2.0.0", + "readable-stream": "2.3.6" }, "dependencies": { "isarray": { @@ -763,13 +763,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -778,7 +778,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -795,10 +795,10 @@ "integrity": "sha512-KJyzHdg9B8U9LxXa7hS6jnEW5b1cNckLYc2YpnJ1nEFiOW+/iSzDHp+5MYEIQd9fN3/tC6WmGZmYiwxzkuGp/A==", "dev": true, "requires": { - "argv": "^0.0.2", - "ignore-walk": "^3.0.1", - "request": "^2.87.0", - "urlgrey": "^0.4.4" + "argv": "0.0.2", + "ignore-walk": "3.0.1", + "request": "2.87.0", + "urlgrey": "0.4.4" } }, "collection-visit": { @@ -807,8 +807,8 @@ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "map-visit": "1.0.0", + "object-visit": "1.0.1" } }, "color-convert": { @@ -838,7 +838,7 @@ "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "dev": true, "requires": { - "delayed-stream": "~1.0.0" + "delayed-stream": "1.0.0" } }, "commander": { @@ -883,11 +883,11 @@ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "nice-try": "1.0.4", + "path-key": "2.0.1", + "semver": "5.5.0", + "shebang-command": "1.2.0", + "which": "1.3.1" }, "dependencies": { "semver": { @@ -904,10 +904,10 @@ "integrity": "sha512-0W171WccAjQGGTKLhw4m2nnl0zPHUlTO/I8td4XzJgIB8Hg3ZZx71qT4G4eX8OVsSiaAKiUMy73E3nsbPlg2DQ==", "dev": true, "requires": { - "inherits": "^2.0.1", - "source-map": "^0.1.38", - "source-map-resolve": "^0.5.1", - "urix": "^0.1.0" + "inherits": "2.0.3", + "source-map": "0.1.43", + "source-map-resolve": "0.5.2", + "urix": "0.1.0" }, "dependencies": { "source-map": { @@ -916,7 +916,7 @@ "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", "dev": true, "requires": { - "amdefine": ">=0.0.4" + "amdefine": "1.0.1" } } } @@ -927,7 +927,7 @@ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { - "es5-ext": "^0.10.9" + "es5-ext": "0.10.45" } }, "dargs": { @@ -942,7 +942,7 @@ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, "requires": { - "assert-plus": "^1.0.0" + "assert-plus": "1.0.0" } }, "dateformat": { @@ -966,9 +966,9 @@ "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==", "dev": true, "requires": { - "debug": "3.X", - "memoizee": "0.4.X", - "object-assign": "4.X" + "debug": "3.1.0", + "memoizee": "0.4.12", + "object-assign": "4.1.1" }, "dependencies": { "debug": { @@ -1001,7 +1001,7 @@ "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", "dev": true, "requires": { - "type-detect": "^4.0.0" + "type-detect": "4.0.8" } }, "deep-is": { @@ -1016,7 +1016,7 @@ "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", "dev": true, "requires": { - "clone": "^1.0.2" + "clone": "1.0.4" } }, "define-properties": { @@ -1025,8 +1025,8 @@ "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", "dev": true, "requires": { - "foreach": "^2.0.5", - "object-keys": "^1.0.8" + "foreach": "2.0.5", + "object-keys": "1.0.12" } }, "define-property": { @@ -1035,8 +1035,8 @@ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "is-descriptor": "1.0.2", + "isobject": "3.0.1" }, "dependencies": { "is-accessor-descriptor": { @@ -1045,7 +1045,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -1054,7 +1054,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -1063,9 +1063,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -1076,12 +1076,12 @@ "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", "dev": true, "requires": { - "globby": "^6.1.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "p-map": "^1.1.1", - "pify": "^3.0.0", - "rimraf": "^2.2.8" + "globby": "6.1.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "p-map": "1.2.0", + "pify": "3.0.0", + "rimraf": "2.6.2" } }, "delayed-stream": { @@ -1120,7 +1120,7 @@ "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", "dev": true, "requires": { - "readable-stream": "~1.1.9" + "readable-stream": "1.1.14" } }, "duplexify": { @@ -1129,10 +1129,10 @@ "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", "dev": true, "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" + "end-of-stream": "1.4.1", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "stream-shift": "1.0.0" }, "dependencies": { "end-of-stream": { @@ -1141,7 +1141,7 @@ "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, "requires": { - "once": "^1.4.0" + "once": "1.4.0" } }, "isarray": { @@ -1156,13 +1156,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -1171,7 +1171,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -1183,7 +1183,7 @@ "dev": true, "optional": true, "requires": { - "jsbn": "~0.1.0" + "jsbn": "0.1.1" } }, "editions": { @@ -1198,7 +1198,7 @@ "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", "dev": true, "requires": { - "once": "~1.3.0" + "once": "1.3.3" }, "dependencies": { "once": { @@ -1207,7 +1207,7 @@ "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", "dev": true, "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } } } @@ -1218,9 +1218,9 @@ "integrity": "sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ==", "dev": true, "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.1", - "next-tick": "1" + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1", + "next-tick": "1.0.0" } }, "es6-iterator": { @@ -1229,9 +1229,9 @@ "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", "dev": true, "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" + "d": "1.0.0", + "es5-ext": "0.10.45", + "es6-symbol": "3.1.1" } }, "es6-shim": { @@ -1246,8 +1246,8 @@ "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", "dev": true, "requires": { - "d": "1", - "es5-ext": "~0.10.14" + "d": "1.0.0", + "es5-ext": "0.10.45" } }, "es6-weak-map": { @@ -1256,10 +1256,10 @@ "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", "dev": true, "requires": { - "d": "1", - "es5-ext": "^0.10.14", - "es6-iterator": "^2.0.1", - "es6-symbol": "^3.1.1" + "d": "1.0.0", + "es5-ext": "0.10.45", + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1" } }, "escape-string-regexp": { @@ -1274,11 +1274,11 @@ "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", "dev": true, "requires": { - "esprima": "^2.7.1", - "estraverse": "^1.9.1", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.2.0" + "esprima": "2.7.3", + "estraverse": "1.9.3", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.2.0" }, "dependencies": { "source-map": { @@ -1288,7 +1288,7 @@ "dev": true, "optional": true, "requires": { - "amdefine": ">=0.0.4" + "amdefine": "1.0.1" } } } @@ -1317,8 +1317,8 @@ "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", "dev": true, "requires": { - "d": "1", - "es5-ext": "~0.10.14" + "d": "1.0.0", + "es5-ext": "0.10.45" } }, "execa": { @@ -1327,13 +1327,13 @@ "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", "dev": true, "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "6.0.5", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" } }, "expand-brackets": { @@ -1342,13 +1342,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -1357,7 +1357,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -1366,7 +1366,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -1377,7 +1377,7 @@ "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", "dev": true, "requires": { - "homedir-polyfill": "^1.0.1" + "homedir-polyfill": "1.0.1" } }, "extend": { @@ -1392,8 +1392,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -1402,7 +1402,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -1413,14 +1413,14 @@ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -1429,7 +1429,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "extend-shallow": { @@ -1438,7 +1438,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "is-accessor-descriptor": { @@ -1447,7 +1447,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -1456,7 +1456,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -1465,9 +1465,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -1484,9 +1484,9 @@ "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=", "dev": true, "requires": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "time-stamp": "^1.0.0" + "ansi-gray": "0.1.1", + "color-support": "1.1.3", + "time-stamp": "1.1.0" } }, "fast-deep-equal": { @@ -1513,10 +1513,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" }, "dependencies": { "extend-shallow": { @@ -1525,7 +1525,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -1542,10 +1542,10 @@ "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", "dev": true, "requires": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" + "detect-file": "1.0.0", + "is-glob": "3.1.0", + "micromatch": "3.1.10", + "resolve-dir": "1.0.1" } }, "fined": { @@ -1554,11 +1554,11 @@ "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=", "dev": true, "requires": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" + "expand-tilde": "2.0.2", + "is-plain-object": "2.0.4", + "object.defaults": "1.1.0", + "object.pick": "1.3.0", + "parse-filepath": "1.0.2" } }, "first-chunk-stream": { @@ -1579,8 +1579,8 @@ "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", "dev": true, "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.4" + "inherits": "2.0.3", + "readable-stream": "2.3.6" }, "dependencies": { "isarray": { @@ -1595,13 +1595,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -1610,7 +1610,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -1627,7 +1627,7 @@ "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", "dev": true, "requires": { - "for-in": "^1.0.1" + "for-in": "1.0.2" } }, "foreach": { @@ -1648,9 +1648,9 @@ "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "dev": true, "requires": { - "asynckit": "^0.4.0", + "asynckit": "0.4.0", "combined-stream": "1.0.6", - "mime-types": "^2.1.12" + "mime-types": "2.1.19" } }, "fragment-cache": { @@ -1659,7 +1659,7 @@ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "map-cache": "^0.2.2" + "map-cache": "0.2.2" } }, "fs-mkdirp-stream": { @@ -1668,8 +1668,8 @@ "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", "dev": true, "requires": { - "graceful-fs": "^4.1.11", - "through2": "^2.0.3" + "graceful-fs": "4.1.11", + "through2": "2.0.3" }, "dependencies": { "graceful-fs": { @@ -1698,7 +1698,7 @@ "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", "dev": true, "requires": { - "globule": "~0.1.0" + "globule": "0.1.0" } }, "get-func-name": { @@ -1725,7 +1725,7 @@ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "dev": true, "requires": { - "assert-plus": "^1.0.0" + "assert-plus": "1.0.0" } }, "glob": { @@ -1734,12 +1734,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "glob-parent": { @@ -1748,8 +1748,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "is-glob": "3.1.0", + "path-dirname": "1.0.2" } }, "glob-stream": { @@ -1758,12 +1758,12 @@ "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", "dev": true, "requires": { - "glob": "^4.3.1", - "glob2base": "^0.0.12", - "minimatch": "^2.0.1", - "ordered-read-streams": "^0.1.0", - "through2": "^0.6.1", - "unique-stream": "^1.0.0" + "glob": "4.5.3", + "glob2base": "0.0.12", + "minimatch": "2.0.10", + "ordered-read-streams": "0.1.0", + "through2": "0.6.5", + "unique-stream": "1.0.0" }, "dependencies": { "glob": { @@ -1772,10 +1772,10 @@ "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", "dev": true, "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^2.0.1", - "once": "^1.3.0" + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "2.0.10", + "once": "1.4.0" } }, "minimatch": { @@ -1784,19 +1784,19 @@ "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", "dev": true, "requires": { - "brace-expansion": "^1.0.0" + "brace-expansion": "1.1.11" } }, "readable-stream": { "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", + "core-util-is": "1.0.2", + "inherits": "2.0.3", "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "string_decoder": "0.10.31" } }, "through2": { @@ -1805,8 +1805,8 @@ "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" + "readable-stream": "1.0.34", + "xtend": "4.0.1" } } } @@ -1817,7 +1817,7 @@ "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", "dev": true, "requires": { - "gaze": "^0.5.1" + "gaze": "0.5.2" } }, "glob2base": { @@ -1826,7 +1826,7 @@ "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", "dev": true, "requires": { - "find-index": "^0.1.1" + "find-index": "0.1.1" } }, "global-modules": { @@ -1835,9 +1835,9 @@ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "dev": true, "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" + "global-prefix": "1.0.2", + "is-windows": "1.0.2", + "resolve-dir": "1.0.1" } }, "global-prefix": { @@ -1846,11 +1846,11 @@ "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", "dev": true, "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" + "expand-tilde": "2.0.2", + "homedir-polyfill": "1.0.1", + "ini": "1.3.5", + "is-windows": "1.0.2", + "which": "1.3.1" } }, "globby": { @@ -1859,11 +1859,11 @@ "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "dev": true, "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" }, "dependencies": { "pify": { @@ -1880,9 +1880,9 @@ "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", "dev": true, "requires": { - "glob": "~3.1.21", - "lodash": "~1.0.1", - "minimatch": "~0.2.11" + "glob": "3.1.21", + "lodash": "1.0.2", + "minimatch": "0.2.14" }, "dependencies": { "glob": { @@ -1891,9 +1891,9 @@ "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", "dev": true, "requires": { - "graceful-fs": "~1.2.0", - "inherits": "1", - "minimatch": "~0.2.11" + "graceful-fs": "1.2.3", + "inherits": "1.0.2", + "minimatch": "0.2.14" } }, "graceful-fs": { @@ -1914,8 +1914,8 @@ "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", "dev": true, "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" + "lru-cache": "2.7.3", + "sigmund": "1.0.1" } } } @@ -1926,7 +1926,7 @@ "integrity": "sha512-ynYqXLoluBKf9XGR1gA59yEJisIL7YHEH4xr3ZziHB5/yl4qWfaK8Js9jGe6gBGCSCKVqiyO30WnRZADvemUNw==", "dev": true, "requires": { - "sparkles": "^1.0.0" + "sparkles": "1.0.1" } }, "google-libphonenumber": { @@ -1940,7 +1940,7 @@ "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", "dev": true, "requires": { - "natives": "^1.1.0" + "natives": "1.1.4" } }, "growl": { @@ -1951,23 +1951,23 @@ }, "gulp": { "version": "3.9.1", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", + "resolved": "http://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=", "dev": true, "requires": { - "archy": "^1.0.0", - "chalk": "^1.0.0", - "deprecated": "^0.0.1", - "gulp-util": "^3.0.0", - "interpret": "^1.0.0", - "liftoff": "^2.1.0", - "minimist": "^1.1.0", - "orchestrator": "^0.3.0", - "pretty-hrtime": "^1.0.0", - "semver": "^4.1.0", - "tildify": "^1.0.0", - "v8flags": "^2.0.2", - "vinyl-fs": "^0.3.0" + "archy": "1.0.0", + "chalk": "1.1.3", + "deprecated": "0.0.1", + "gulp-util": "3.0.8", + "interpret": "1.1.0", + "liftoff": "2.5.0", + "minimist": "1.2.0", + "orchestrator": "0.3.8", + "pretty-hrtime": "1.0.3", + "semver": "4.3.6", + "tildify": "1.2.0", + "v8flags": "2.1.1", + "vinyl-fs": "0.3.14" } }, "gulp-istanbul": { @@ -1976,12 +1976,12 @@ "integrity": "sha512-uMLSdqPDnBAV/B9rNyOgVMgrVC1tPbe+5GH6P13UOyxbRDT/w4sKYHWftPMA8j9om+NFvfeRlqpDXL2fixFWNA==", "dev": true, "requires": { - "istanbul": "^0.4.0", - "istanbul-threshold-checker": "^0.2.1", - "lodash": "^4.0.0", - "plugin-error": "^0.1.2", - "through2": "^2.0.0", - "vinyl-sourcemaps-apply": "^0.2.1" + "istanbul": "0.4.5", + "istanbul-threshold-checker": "0.2.1", + "lodash": "4.17.10", + "plugin-error": "0.1.2", + "through2": "2.0.3", + "vinyl-sourcemaps-apply": "0.2.1" }, "dependencies": { "lodash": { @@ -1998,13 +1998,13 @@ "integrity": "sha512-FfBldW5ttnDpKf4Sg6/BLOOKCCbr5mbixDGK1t02/8oSrTCwNhgN/mdszG3cuQuYNzuouUdw4EH/mlYtgUscPg==", "dev": true, "requires": { - "dargs": "^5.1.0", - "execa": "^0.10.0", - "mocha": "^5.2.0", - "npm-run-path": "^2.0.2", - "plugin-error": "^1.0.1", - "supports-color": "^5.4.0", - "through2": "^2.0.3" + "dargs": "5.1.0", + "execa": "0.10.0", + "mocha": "5.2.0", + "npm-run-path": "2.0.2", + "plugin-error": "1.0.1", + "supports-color": "5.4.0", + "through2": "2.0.3" }, "dependencies": { "has-flag": { @@ -2019,10 +2019,10 @@ "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", "dev": true, "requires": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" + "ansi-colors": "1.1.0", + "arr-diff": "4.0.0", + "arr-union": "3.1.0", + "extend-shallow": "3.0.2" } }, "supports-color": { @@ -2031,7 +2031,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -2043,8 +2043,8 @@ "dev": true, "requires": { "istextorbinary": "2.2.1", - "readable-stream": "^2.0.1", - "replacestream": "^4.0.0" + "readable-stream": "2.3.6", + "replacestream": "4.0.3" }, "dependencies": { "isarray": { @@ -2059,13 +2059,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -2074,7 +2074,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -2085,13 +2085,13 @@ "integrity": "sha512-f3m1WcS0o2B72/PGj1Jbv9zYR9rynBh/EQJv64n01xQUo7j7anols0eww9GG/WtDTzGVQLrupVDYkifRFnj5Zg==", "dev": true, "requires": { - "async": "^2.1.5", - "chalk": "^2.3.0", - "fancy-log": "^1.3.2", - "lodash": "^4.17.4", - "lodash.template": "^4.4.0", - "plugin-error": "^0.1.2", - "through2": "^2.0.3" + "async": "2.6.1", + "chalk": "2.4.1", + "fancy-log": "1.3.2", + "lodash": "4.17.10", + "lodash.template": "4.4.0", + "plugin-error": "0.1.2", + "through2": "2.0.3" }, "dependencies": { "ansi-styles": { @@ -2100,7 +2100,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.2" } }, "async": { @@ -2109,7 +2109,7 @@ "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", "dev": true, "requires": { - "lodash": "^4.17.10" + "lodash": "4.17.10" } }, "chalk": { @@ -2118,9 +2118,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" } }, "has-flag": { @@ -2141,8 +2141,8 @@ "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=", "dev": true, "requires": { - "lodash._reinterpolate": "~3.0.0", - "lodash.templatesettings": "^4.0.0" + "lodash._reinterpolate": "3.0.0", + "lodash.templatesettings": "4.1.0" } }, "lodash.templatesettings": { @@ -2151,7 +2151,7 @@ "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=", "dev": true, "requires": { - "lodash._reinterpolate": "~3.0.0" + "lodash._reinterpolate": "3.0.0" } }, "supports-color": { @@ -2160,7 +2160,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -2171,17 +2171,17 @@ "integrity": "sha1-y7IAhFCxvM5s0jv5gze+dRv24wo=", "dev": true, "requires": { - "@gulp-sourcemaps/identity-map": "1.X", - "@gulp-sourcemaps/map-sources": "1.X", - "acorn": "5.X", - "convert-source-map": "1.X", - "css": "2.X", - "debug-fabulous": "1.X", - "detect-newline": "2.X", - "graceful-fs": "4.X", - "source-map": "~0.6.0", - "strip-bom-string": "1.X", - "through2": "2.X" + "@gulp-sourcemaps/identity-map": "1.0.2", + "@gulp-sourcemaps/map-sources": "1.0.0", + "acorn": "5.7.1", + "convert-source-map": "1.5.1", + "css": "2.2.3", + "debug-fabulous": "1.1.0", + "detect-newline": "2.1.0", + "graceful-fs": "4.1.11", + "source-map": "0.6.1", + "strip-bom-string": "1.0.0", + "through2": "2.0.3" }, "dependencies": { "graceful-fs": { @@ -2207,9 +2207,9 @@ "@types/fancy-log": "1.3.0", "chalk": "2.3.1", "fancy-log": "1.3.2", - "map-stream": "~0.0.7", + "map-stream": "0.0.7", "plugin-error": "1.0.1", - "through": "~2.3.8" + "through": "2.3.8" }, "dependencies": { "ansi-styles": { @@ -2218,7 +2218,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.2" } }, "chalk": { @@ -2227,9 +2227,9 @@ "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.2.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" } }, "has-flag": { @@ -2244,10 +2244,10 @@ "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", "dev": true, "requires": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" + "ansi-colors": "1.1.0", + "arr-diff": "4.0.0", + "arr-union": "3.1.0", + "extend-shallow": "3.0.2" } }, "supports-color": { @@ -2256,7 +2256,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -2267,12 +2267,12 @@ "integrity": "sha512-6iSBjqBXAUqRsLUh/9XtlOnSzpPMbLrr5rqGj4UPLtGpDwFHW/fVTuRgv6LAWiKesLIUDDM0ourxvcpu2trecQ==", "dev": true, "requires": { - "ansi-colors": "^2.0.2", - "plugin-error": "^1.0.1", - "source-map": "^0.7.3", - "through2": "^2.0.3", - "vinyl": "^2.1.0", - "vinyl-fs": "^3.0.3" + "ansi-colors": "2.0.3", + "plugin-error": "1.0.1", + "source-map": "0.7.3", + "through2": "2.0.3", + "vinyl": "2.2.0", + "vinyl-fs": "3.0.3" }, "dependencies": { "ansi-colors": { @@ -2299,16 +2299,16 @@ "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", "dev": true, "requires": { - "extend": "^3.0.0", - "glob": "^7.1.1", - "glob-parent": "^3.1.0", - "is-negated-glob": "^1.0.0", - "ordered-read-streams": "^1.0.0", - "pumpify": "^1.3.5", - "readable-stream": "^2.1.5", - "remove-trailing-separator": "^1.0.1", - "to-absolute-glob": "^2.0.0", - "unique-stream": "^2.0.2" + "extend": "3.0.1", + "glob": "7.1.2", + "glob-parent": "3.1.0", + "is-negated-glob": "1.0.0", + "ordered-read-streams": "1.0.1", + "pumpify": "1.5.1", + "readable-stream": "2.3.6", + "remove-trailing-separator": "1.1.0", + "to-absolute-glob": "2.0.2", + "unique-stream": "2.2.1" } }, "graceful-fs": { @@ -2329,7 +2329,7 @@ "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", "dev": true, "requires": { - "readable-stream": "^2.0.1" + "readable-stream": "2.3.6" } }, "plugin-error": { @@ -2338,10 +2338,10 @@ "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", "dev": true, "requires": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" + "ansi-colors": "1.1.0", + "arr-diff": "4.0.0", + "arr-union": "3.1.0", + "extend-shallow": "3.0.2" }, "dependencies": { "ansi-colors": { @@ -2350,7 +2350,7 @@ "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", "dev": true, "requires": { - "ansi-wrap": "^0.1.0" + "ansi-wrap": "0.1.0" } } } @@ -2361,13 +2361,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "replace-ext": { @@ -2388,7 +2388,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } }, "unique-stream": { @@ -2397,8 +2397,8 @@ "integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=", "dev": true, "requires": { - "json-stable-stringify": "^1.0.0", - "through2-filter": "^2.0.0" + "json-stable-stringify": "1.0.1", + "through2-filter": "2.0.0" } }, "vinyl": { @@ -2407,12 +2407,12 @@ "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", "dev": true, "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" + "clone": "2.1.1", + "clone-buffer": "1.0.0", + "clone-stats": "1.0.0", + "cloneable-readable": "1.1.2", + "remove-trailing-separator": "1.1.0", + "replace-ext": "1.0.0" } }, "vinyl-fs": { @@ -2421,23 +2421,23 @@ "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", "dev": true, "requires": { - "fs-mkdirp-stream": "^1.0.0", - "glob-stream": "^6.1.0", - "graceful-fs": "^4.0.0", - "is-valid-glob": "^1.0.0", - "lazystream": "^1.0.0", - "lead": "^1.0.0", - "object.assign": "^4.0.4", - "pumpify": "^1.3.5", - "readable-stream": "^2.3.3", - "remove-bom-buffer": "^3.0.0", - "remove-bom-stream": "^1.2.0", - "resolve-options": "^1.1.0", - "through2": "^2.0.0", - "to-through": "^2.0.0", - "value-or-function": "^3.0.0", - "vinyl": "^2.0.0", - "vinyl-sourcemap": "^1.1.0" + "fs-mkdirp-stream": "1.0.0", + "glob-stream": "6.1.0", + "graceful-fs": "4.1.11", + "is-valid-glob": "1.0.0", + "lazystream": "1.0.0", + "lead": "1.0.0", + "object.assign": "4.1.0", + "pumpify": "1.5.1", + "readable-stream": "2.3.6", + "remove-bom-buffer": "3.0.0", + "remove-bom-stream": "1.2.0", + "resolve-options": "1.1.0", + "through2": "2.0.3", + "to-through": "2.0.0", + "value-or-function": "3.0.0", + "vinyl": "2.2.0", + "vinyl-sourcemap": "1.1.0" } } } @@ -2448,24 +2448,24 @@ "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", "dev": true, "requires": { - "array-differ": "^1.0.0", - "array-uniq": "^1.0.2", - "beeper": "^1.0.0", - "chalk": "^1.0.0", - "dateformat": "^2.0.0", - "fancy-log": "^1.1.0", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.0.0", - "minimist": "^1.1.0", - "multipipe": "^0.1.2", - "object-assign": "^3.0.0", + "array-differ": "1.0.0", + "array-uniq": "1.0.3", + "beeper": "1.1.1", + "chalk": "1.1.3", + "dateformat": "2.2.0", + "fancy-log": "1.3.2", + "gulplog": "1.0.0", + "has-gulplog": "0.1.0", + "lodash._reescape": "3.0.0", + "lodash._reevaluate": "3.0.0", + "lodash._reinterpolate": "3.0.0", + "lodash.template": "3.6.2", + "minimist": "1.2.0", + "multipipe": "0.1.2", + "object-assign": "3.0.0", "replace-ext": "0.0.1", - "through2": "^2.0.0", - "vinyl": "^0.5.0" + "through2": "2.0.3", + "vinyl": "0.5.3" }, "dependencies": { "object-assign": { @@ -2482,9 +2482,9 @@ "integrity": "sha1-0m9cOdw5nhHEWpCHh8hkkLwx6FA=", "dev": true, "requires": { - "gulp": "^3.9.0", - "merge2": "^0.3.6", - "run-sequence": "^1.1.5" + "gulp": "3.9.1", + "merge2": "0.3.7", + "run-sequence": "1.2.2" } }, "gulplog": { @@ -2493,7 +2493,7 @@ "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", "dev": true, "requires": { - "glogg": "^1.0.0" + "glogg": "1.0.1" } }, "handlebars": { @@ -2502,10 +2502,10 @@ "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", "dev": true, "requires": { - "async": "^1.4.0", - "optimist": "^0.6.1", - "source-map": "^0.4.4", - "uglify-js": "^2.6" + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" }, "dependencies": { "source-map": { @@ -2514,7 +2514,7 @@ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { - "amdefine": ">=0.0.4" + "amdefine": "1.0.1" } } } @@ -2531,8 +2531,8 @@ "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "dev": true, "requires": { - "ajv": "^5.1.0", - "har-schema": "^2.0.0" + "ajv": "5.5.2", + "har-schema": "2.0.0" } }, "has-ansi": { @@ -2541,7 +2541,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "has-flag": { @@ -2556,7 +2556,7 @@ "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", "dev": true, "requires": { - "sparkles": "^1.0.0" + "sparkles": "1.0.1" } }, "has-symbols": { @@ -2571,9 +2571,9 @@ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "get-value": "2.0.6", + "has-values": "1.0.0", + "isobject": "3.0.1" } }, "has-values": { @@ -2582,8 +2582,8 @@ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" + "is-number": "3.0.0", + "kind-of": "4.0.0" }, "dependencies": { "kind-of": { @@ -2592,7 +2592,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -2609,7 +2609,7 @@ "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", "dev": true, "requires": { - "parse-passwd": "^1.0.0" + "parse-passwd": "1.0.0" } }, "http-signature": { @@ -2618,9 +2618,9 @@ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "dev": true, "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.14.2" } }, "ignore-walk": { @@ -2629,7 +2629,7 @@ "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "requires": { - "minimatch": "^3.0.4" + "minimatch": "3.0.4" } }, "inflight": { @@ -2638,8 +2638,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -2666,8 +2666,8 @@ "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", "dev": true, "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" + "is-relative": "1.0.0", + "is-windows": "1.0.2" } }, "is-accessor-descriptor": { @@ -2676,7 +2676,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -2685,7 +2685,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -2702,7 +2702,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -2711,7 +2711,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -2722,9 +2722,9 @@ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" }, "dependencies": { "kind-of": { @@ -2753,7 +2753,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "^2.1.0" + "is-extglob": "2.1.1" } }, "is-negated-glob": { @@ -2768,7 +2768,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -2777,7 +2777,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -2794,7 +2794,7 @@ "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "dev": true, "requires": { - "is-path-inside": "^1.0.0" + "is-path-inside": "1.0.1" } }, "is-path-inside": { @@ -2803,7 +2803,7 @@ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { - "path-is-inside": "^1.0.1" + "path-is-inside": "1.0.2" } }, "is-plain-object": { @@ -2812,7 +2812,7 @@ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" } }, "is-promise": { @@ -2827,7 +2827,7 @@ "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, "requires": { - "is-unc-path": "^1.0.0" + "is-unc-path": "1.0.0" } }, "is-stream": { @@ -2848,7 +2848,7 @@ "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, "requires": { - "unc-path-regex": "^0.1.2" + "unc-path-regex": "0.1.2" } }, "is-utf8": { @@ -2899,20 +2899,20 @@ "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", "dev": true, "requires": { - "abbrev": "1.0.x", - "async": "1.x", - "escodegen": "1.8.x", - "esprima": "2.7.x", - "glob": "^5.0.15", - "handlebars": "^4.0.1", - "js-yaml": "3.x", - "mkdirp": "0.5.x", - "nopt": "3.x", - "once": "1.x", - "resolve": "1.1.x", - "supports-color": "^3.1.0", - "which": "^1.1.1", - "wordwrap": "^1.0.0" + "abbrev": "1.0.9", + "async": "1.5.2", + "escodegen": "1.8.1", + "esprima": "2.7.3", + "glob": "5.0.15", + "handlebars": "4.0.11", + "js-yaml": "3.12.0", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "once": "1.4.0", + "resolve": "1.1.7", + "supports-color": "3.2.3", + "which": "1.3.1", + "wordwrap": "1.0.0" }, "dependencies": { "glob": { @@ -2921,11 +2921,11 @@ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", "dev": true, "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "resolve": { @@ -2940,7 +2940,7 @@ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, "requires": { - "has-flag": "^1.0.0" + "has-flag": "1.0.0" } } } @@ -2951,8 +2951,8 @@ "integrity": "sha1-xdyU6PLMXNP/0zVFL4S1U8QkgzE=", "dev": true, "requires": { - "istanbul": "~0.4.5", - "lodash": "~4.17.2" + "istanbul": "0.4.5", + "lodash": "4.17.10" }, "dependencies": { "lodash": { @@ -2969,9 +2969,9 @@ "integrity": "sha512-TS+hoFl8Z5FAFMK38nhBkdLt44CclNRgDHWeMgsV8ko3nDlr/9UI2Sf839sW7enijf8oKsZYXRvM8g0it9Zmcw==", "dev": true, "requires": { - "binaryextensions": "2", - "editions": "^1.3.3", - "textextensions": "2" + "binaryextensions": "2.1.1", + "editions": "1.3.4", + "textextensions": "2.2.0" } }, "js-tokens": { @@ -2986,8 +2986,8 @@ "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "1.0.10", + "esprima": "4.0.1" }, "dependencies": { "esprima": { @@ -3023,7 +3023,7 @@ "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "dev": true, "requires": { - "jsonify": "~0.0.0" + "jsonify": "0.0.0" } }, "json-stringify-safe": { @@ -3075,7 +3075,7 @@ "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", "dev": true, "requires": { - "readable-stream": "^2.0.5" + "readable-stream": "2.3.6" }, "dependencies": { "isarray": { @@ -3090,13 +3090,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -3105,7 +3105,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -3116,7 +3116,7 @@ "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", "dev": true, "requires": { - "flush-write-stream": "^1.0.2" + "flush-write-stream": "1.0.3" } }, "levn": { @@ -3125,8 +3125,8 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "prelude-ls": "1.1.2", + "type-check": "0.3.2" } }, "liftoff": { @@ -3135,19 +3135,19 @@ "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", "dev": true, "requires": { - "extend": "^3.0.0", - "findup-sync": "^2.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" + "extend": "3.0.1", + "findup-sync": "2.0.0", + "fined": "1.1.0", + "flagged-respawn": "1.0.0", + "is-plain-object": "2.0.4", + "object.map": "1.0.1", + "rechoir": "0.6.2", + "resolve": "1.8.1" } }, "lodash": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", "dev": true }, @@ -3211,7 +3211,7 @@ "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", "dev": true, "requires": { - "lodash._root": "^3.0.0" + "lodash._root": "3.0.1" } }, "lodash.get": { @@ -3238,9 +3238,9 @@ "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", "dev": true, "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" } }, "lodash.restparam": { @@ -3255,15 +3255,15 @@ "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", "dev": true, "requires": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" + "lodash._basecopy": "3.0.1", + "lodash._basetostring": "3.0.1", + "lodash._basevalues": "3.0.0", + "lodash._isiterateecall": "3.0.9", + "lodash._reinterpolate": "3.0.0", + "lodash.escape": "3.2.0", + "lodash.keys": "3.1.2", + "lodash.restparam": "3.6.1", + "lodash.templatesettings": "3.1.1" } }, "lodash.templatesettings": { @@ -3272,8 +3272,8 @@ "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", "dev": true, "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" + "lodash._reinterpolate": "3.0.0", + "lodash.escape": "3.2.0" } }, "log-symbols": { @@ -3282,7 +3282,7 @@ "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", "dev": true, "requires": { - "chalk": "^1.0.0" + "chalk": "1.1.3" } }, "lolex": { @@ -3309,7 +3309,7 @@ "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", "dev": true, "requires": { - "es5-ext": "~0.10.2" + "es5-ext": "0.10.45" } }, "make-error": { @@ -3324,7 +3324,7 @@ "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", "dev": true, "requires": { - "kind-of": "^6.0.2" + "kind-of": "6.0.2" } }, "map-cache": { @@ -3345,7 +3345,7 @@ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "object-visit": "^1.0.0" + "object-visit": "1.0.1" } }, "memoizee": { @@ -3354,14 +3354,14 @@ "integrity": "sha512-sprBu6nwxBWBvBOh5v2jcsGqiGLlL2xr2dLub3vR8dnE8YB17omwtm/0NSHl8jjNbcsJd5GMWJAnTSVe/O0Wfg==", "dev": true, "requires": { - "d": "1", - "es5-ext": "^0.10.30", - "es6-weak-map": "^2.0.2", - "event-emitter": "^0.3.5", - "is-promise": "^2.1", - "lru-queue": "0.1", - "next-tick": "1", - "timers-ext": "^0.1.2" + "d": "1.0.0", + "es5-ext": "0.10.45", + "es6-weak-map": "2.0.2", + "event-emitter": "0.3.5", + "is-promise": "2.1.0", + "lru-queue": "0.1.0", + "next-tick": "1.0.0", + "timers-ext": "0.1.5" } }, "merge2": { @@ -3376,19 +3376,19 @@ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.13", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "mime-db": { @@ -3403,7 +3403,7 @@ "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", "dev": true, "requires": { - "mime-db": "~1.35.0" + "mime-db": "1.35.0" } }, "minimatch": { @@ -3412,7 +3412,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { @@ -3427,8 +3427,8 @@ "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", "dev": true, "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" + "for-in": "1.0.2", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -3437,7 +3437,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -3499,7 +3499,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -3525,17 +3525,17 @@ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "fragment-cache": "0.2.1", + "is-windows": "1.0.2", + "kind-of": "6.0.2", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "natives": { @@ -3562,11 +3562,11 @@ "integrity": "sha512-BxH/DxoQYYdhKgVAfqVy4pzXRZELHOIewzoesxpjYvpU+7YOalQhGNPf7wAx8pLrTNPrHRDlLOkAl8UI0ZpXjw==", "dev": true, "requires": { - "@sinonjs/formatio": "^2.0.0", - "just-extend": "^1.1.27", - "lolex": "^2.3.2", - "path-to-regexp": "^1.7.0", - "text-encoding": "^0.6.4" + "@sinonjs/formatio": "2.0.0", + "just-extend": "1.1.27", + "lolex": "2.7.1", + "path-to-regexp": "1.7.0", + "text-encoding": "0.6.4" } }, "nopt": { @@ -3575,7 +3575,7 @@ "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "dev": true, "requires": { - "abbrev": "1" + "abbrev": "1.0.9" } }, "normalize-path": { @@ -3584,7 +3584,7 @@ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "requires": { - "remove-trailing-separator": "^1.0.1" + "remove-trailing-separator": "1.1.0" } }, "now-and-later": { @@ -3593,7 +3593,7 @@ "integrity": "sha1-vGHLtFbXnLMiB85HygUTb/Ln1u4=", "dev": true, "requires": { - "once": "^1.3.2" + "once": "1.4.0" } }, "npm-run-path": { @@ -3602,7 +3602,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "^2.0.0" + "path-key": "2.0.1" } }, "oauth-sign": { @@ -3623,9 +3623,9 @@ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "copy-descriptor": "0.1.1", + "define-property": "0.2.5", + "kind-of": "3.2.2" }, "dependencies": { "define-property": { @@ -3634,7 +3634,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "kind-of": { @@ -3643,7 +3643,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -3660,7 +3660,7 @@ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { - "isobject": "^3.0.0" + "isobject": "3.0.1" } }, "object.assign": { @@ -3669,10 +3669,10 @@ "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "define-properties": "1.1.2", + "function-bind": "1.1.1", + "has-symbols": "1.0.0", + "object-keys": "1.0.12" } }, "object.defaults": { @@ -3681,10 +3681,10 @@ "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", "dev": true, "requires": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" + "array-each": "1.0.1", + "array-slice": "1.1.0", + "for-own": "1.0.0", + "isobject": "3.0.1" } }, "object.map": { @@ -3693,8 +3693,8 @@ "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", "dev": true, "requires": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" + "for-own": "1.0.0", + "make-iterator": "1.0.1" } }, "object.pick": { @@ -3703,7 +3703,7 @@ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" } }, "once": { @@ -3712,7 +3712,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "optimist": { @@ -3721,8 +3721,8 @@ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" + "minimist": "0.0.10", + "wordwrap": "0.0.3" }, "dependencies": { "minimist": { @@ -3745,12 +3745,12 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" } }, "orchestrator": { @@ -3759,9 +3759,9 @@ "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", "dev": true, "requires": { - "end-of-stream": "~0.1.5", - "sequencify": "~0.0.7", - "stream-consume": "~0.1.0" + "end-of-stream": "0.1.5", + "sequencify": "0.0.7", + "stream-consume": "0.1.1" } }, "ordered-read-streams": { @@ -3794,9 +3794,9 @@ "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", "dev": true, "requires": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" + "is-absolute": "1.0.0", + "map-cache": "0.2.2", + "path-root": "0.1.1" } }, "parse-passwd": { @@ -3847,7 +3847,7 @@ "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", "dev": true, "requires": { - "path-root-regex": "^0.1.0" + "path-root-regex": "0.1.2" } }, "path-root-regex": { @@ -3895,7 +3895,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "^2.0.0" + "pinkie": "2.0.4" } }, "plugin-error": { @@ -3904,11 +3904,11 @@ "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", "dev": true, "requires": { - "ansi-cyan": "^0.1.1", - "ansi-red": "^0.1.1", - "arr-diff": "^1.0.1", - "arr-union": "^2.0.1", - "extend-shallow": "^1.1.2" + "ansi-cyan": "0.1.1", + "ansi-red": "0.1.1", + "arr-diff": "1.1.0", + "arr-union": "2.1.0", + "extend-shallow": "1.1.4" }, "dependencies": { "arr-diff": { @@ -3917,8 +3917,8 @@ "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", "dev": true, "requires": { - "arr-flatten": "^1.0.1", - "array-slice": "^0.2.3" + "arr-flatten": "1.1.0", + "array-slice": "0.2.3" } }, "arr-union": { @@ -3939,7 +3939,7 @@ "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", "dev": true, "requires": { - "kind-of": "^1.1.0" + "kind-of": "1.1.0" } }, "kind-of": { @@ -3964,7 +3964,7 @@ }, "pretty-hrtime": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "resolved": "http://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, @@ -3980,8 +3980,8 @@ "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "end-of-stream": "1.4.1", + "once": "1.4.0" }, "dependencies": { "end-of-stream": { @@ -3990,7 +3990,7 @@ "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, "requires": { - "once": "^1.4.0" + "once": "1.4.0" } } } @@ -4001,9 +4001,9 @@ "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "dev": true, "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" + "duplexify": "3.6.0", + "inherits": "2.0.3", + "pump": "2.0.1" } }, "punycode": { @@ -4024,10 +4024,10 @@ "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", + "core-util-is": "1.0.2", + "inherits": "2.0.3", "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "string_decoder": "0.10.31" } }, "rechoir": { @@ -4036,7 +4036,7 @@ "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", "dev": true, "requires": { - "resolve": "^1.1.6" + "resolve": "1.8.1" } }, "regex-not": { @@ -4045,8 +4045,8 @@ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "extend-shallow": "3.0.2", + "safe-regex": "1.1.0" } }, "remap-istanbul": { @@ -4055,11 +4055,11 @@ "integrity": "sha512-Itv3XvYjD6G+9xDzAeFohx4GUwbFjfqFt0UXlC826jHR18E49fEiEGqZUxUASwMq4z7wwUv2H9/XF2d6qj0iaQ==", "dev": true, "requires": { - "amdefine": "^1.0.0", + "amdefine": "1.0.1", "istanbul": "0.4.5", - "minimatch": "^3.0.3", - "plugin-error": "^0.1.2", - "source-map": "^0.6.1", + "minimatch": "3.0.4", + "plugin-error": "0.1.2", + "source-map": "0.6.1", "through2": "2.0.1" }, "dependencies": { @@ -4081,12 +4081,12 @@ "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" } }, "source-map": { @@ -4101,8 +4101,8 @@ "integrity": "sha1-OE51MU1J8y3hLuu4E2uOtrXVnak=", "dev": true, "requires": { - "readable-stream": "~2.0.0", - "xtend": "~4.0.0" + "readable-stream": "2.0.6", + "xtend": "4.0.1" } } } @@ -4113,8 +4113,8 @@ "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", "dev": true, "requires": { - "is-buffer": "^1.1.5", - "is-utf8": "^0.2.1" + "is-buffer": "1.1.6", + "is-utf8": "0.2.1" } }, "remove-bom-stream": { @@ -4123,9 +4123,9 @@ "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", "dev": true, "requires": { - "remove-bom-buffer": "^3.0.0", - "safe-buffer": "^5.1.0", - "through2": "^2.0.3" + "remove-bom-buffer": "3.0.0", + "safe-buffer": "5.1.2", + "through2": "2.0.3" } }, "remove-trailing-separator": { @@ -4158,9 +4158,9 @@ "integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==", "dev": true, "requires": { - "escape-string-regexp": "^1.0.3", - "object-assign": "^4.0.1", - "readable-stream": "^2.0.2" + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1", + "readable-stream": "2.3.6" }, "dependencies": { "isarray": { @@ -4175,13 +4175,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -4190,7 +4190,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -4201,26 +4201,26 @@ "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", "dev": true, "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", - "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", - "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "tough-cookie": "~2.3.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" + "aws-sign2": "0.7.0", + "aws4": "1.7.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.19", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.2", + "safe-buffer": "5.1.2", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.3.2" } }, "resolve": { @@ -4229,7 +4229,7 @@ "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", "dev": true, "requires": { - "path-parse": "^1.0.5" + "path-parse": "1.0.5" } }, "resolve-dir": { @@ -4238,8 +4238,8 @@ "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", "dev": true, "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" + "expand-tilde": "2.0.2", + "global-modules": "1.0.0" } }, "resolve-options": { @@ -4248,7 +4248,7 @@ "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", "dev": true, "requires": { - "value-or-function": "^3.0.0" + "value-or-function": "3.0.0" } }, "resolve-url": { @@ -4270,7 +4270,7 @@ "dev": true, "optional": true, "requires": { - "align-text": "^0.1.1" + "align-text": "0.1.4" } }, "rimraf": { @@ -4279,7 +4279,7 @@ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "7.1.2" } }, "run-sequence": { @@ -4288,8 +4288,8 @@ "integrity": "sha1-UJWgvr6YczsBQL0I3YDsAw3azes=", "dev": true, "requires": { - "chalk": "*", - "gulp-util": "*" + "chalk": "1.1.3", + "gulp-util": "3.0.8" } }, "safe-buffer": { @@ -4300,11 +4300,11 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { - "ret": "~0.1.10" + "ret": "0.1.15" } }, "safer-buffer": { @@ -4321,7 +4321,7 @@ }, "semver": { "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "resolved": "http://registry.npmjs.org/semver/-/semver-4.3.6.tgz", "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", "dev": true }, @@ -4337,10 +4337,10 @@ "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "split-string": "3.1.0" }, "dependencies": { "extend-shallow": { @@ -4349,7 +4349,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -4360,7 +4360,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "1.0.0" } }, "shebang-regex": { @@ -4387,14 +4387,14 @@ "integrity": "sha512-yeTza8xIZZdiXntCHJAzKll/sSYE+DuJOS8hiSapzaLqdW8eCNVVC9je9SZYYTkPm2bLts9x6UYxwuMAVVrM6Q==", "dev": true, "requires": { - "@sinonjs/formatio": "^2.0.0", - "@sinonjs/samsam": "^2.0.0", - "diff": "^3.5.0", - "lodash.get": "^4.4.2", - "lolex": "^2.4.2", - "nise": "^1.3.3", - "supports-color": "^5.4.0", - "type-detect": "^4.0.8" + "@sinonjs/formatio": "2.0.0", + "@sinonjs/samsam": "2.0.0", + "diff": "3.5.0", + "lodash.get": "4.4.2", + "lolex": "2.7.1", + "nise": "1.4.2", + "supports-color": "5.4.0", + "type-detect": "4.0.8" }, "dependencies": { "has-flag": { @@ -4409,7 +4409,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -4426,14 +4426,14 @@ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" + "base": "0.11.2", + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "map-cache": "0.2.2", + "source-map": "0.5.7", + "source-map-resolve": "0.5.2", + "use": "3.1.1" }, "dependencies": { "define-property": { @@ -4442,7 +4442,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -4451,7 +4451,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -4462,9 +4462,9 @@ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" + "define-property": "1.0.0", + "isobject": "3.0.1", + "snapdragon-util": "3.0.1" }, "dependencies": { "define-property": { @@ -4473,7 +4473,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { @@ -4482,7 +4482,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -4491,7 +4491,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -4500,9 +4500,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -4513,7 +4513,7 @@ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { - "kind-of": "^3.2.0" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -4522,7 +4522,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -4539,11 +4539,11 @@ "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", "dev": true, "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "atob": "2.1.1", + "decode-uri-component": "0.2.0", + "resolve-url": "0.2.1", + "source-map-url": "0.4.0", + "urix": "0.1.0" } }, "source-map-support": { @@ -4552,8 +4552,8 @@ "integrity": "sha512-N4KXEz7jcKqPf2b2vZF11lQIz9W5ZMuUcIOGj243lduidkf2fjkVKJS9vNxVWn3u/uxX38AcE8U9nnH9FPcq+g==", "dev": true, "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "buffer-from": "1.1.0", + "source-map": "0.6.1" }, "dependencies": { "source-map": { @@ -4582,7 +4582,7 @@ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { - "extend-shallow": "^3.0.0" + "extend-shallow": "3.0.2" } }, "sprintf-js": { @@ -4597,15 +4597,15 @@ "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", "dev": true, "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.2", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "safer-buffer": "2.1.2", + "tweetnacl": "0.14.5" } }, "static-extend": { @@ -4614,8 +4614,8 @@ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "define-property": "0.2.5", + "object-copy": "0.1.0" }, "dependencies": { "define-property": { @@ -4624,7 +4624,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -4653,7 +4653,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "strip-bom": { @@ -4662,8 +4662,8 @@ "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", "dev": true, "requires": { - "first-chunk-stream": "^1.0.0", - "is-utf8": "^0.2.0" + "first-chunk-stream": "1.0.0", + "is-utf8": "0.2.1" } }, "strip-bom-string": { @@ -4714,8 +4714,8 @@ "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "dev": true, "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" + "readable-stream": "2.3.6", + "xtend": "4.0.1" }, "dependencies": { "isarray": { @@ -4730,13 +4730,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -4745,7 +4745,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -4756,8 +4756,8 @@ "integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=", "dev": true, "requires": { - "through2": "~2.0.0", - "xtend": "~4.0.0" + "through2": "2.0.3", + "xtend": "4.0.1" } }, "tildify": { @@ -4766,7 +4766,7 @@ "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", "dev": true, "requires": { - "os-homedir": "^1.0.0" + "os-homedir": "1.0.2" } }, "time-stamp": { @@ -4781,8 +4781,8 @@ "integrity": "sha512-tsEStd7kmACHENhsUPaxb8Jf8/+GZZxyNFQbZD07HQOyooOa6At1rQqjffgvg7n+dxscQa9cjjMdWhJtsP2sxg==", "dev": true, "requires": { - "es5-ext": "~0.10.14", - "next-tick": "1" + "es5-ext": "0.10.45", + "next-tick": "1.0.0" } }, "to-absolute-glob": { @@ -4791,8 +4791,8 @@ "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", "dev": true, "requires": { - "is-absolute": "^1.0.0", - "is-negated-glob": "^1.0.0" + "is-absolute": "1.0.0", + "is-negated-glob": "1.0.0" } }, "to-object-path": { @@ -4801,7 +4801,7 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -4810,7 +4810,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -4821,10 +4821,10 @@ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "regex-not": "1.0.2", + "safe-regex": "1.1.0" } }, "to-regex-range": { @@ -4833,8 +4833,8 @@ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "3.0.0", + "repeat-string": "1.6.1" } }, "to-through": { @@ -4843,7 +4843,7 @@ "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", "dev": true, "requires": { - "through2": "^2.0.3" + "through2": "2.0.3" } }, "tough-cookie": { @@ -4852,7 +4852,7 @@ "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", "dev": true, "requires": { - "punycode": "^1.4.1" + "punycode": "1.4.1" } }, "ts-node": { @@ -4861,14 +4861,14 @@ "integrity": "sha512-klJsfswHP0FuOLsvBZ/zzCfUvakOSSxds78mVeK7I+qP76YWtxf16hEZsp3U+b0kIo82R5UatGFeblYMqabb2Q==", "dev": true, "requires": { - "arrify": "^1.0.0", - "buffer-from": "^1.1.0", - "diff": "^3.1.0", - "make-error": "^1.1.1", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "source-map-support": "^0.5.6", - "yn": "^2.0.0" + "arrify": "1.0.1", + "buffer-from": "1.1.0", + "diff": "3.5.0", + "make-error": "1.3.4", + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "source-map-support": "0.5.6", + "yn": "2.0.0" } }, "tslib": { @@ -4883,18 +4883,18 @@ "integrity": "sha1-mPMMAurjzecAYgHkwzywi0hYHu0=", "dev": true, "requires": { - "babel-code-frame": "^6.22.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^3.2.0", - "glob": "^7.1.1", - "js-yaml": "^3.7.0", - "minimatch": "^3.0.4", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.27.2" + "babel-code-frame": "6.26.0", + "builtin-modules": "1.1.1", + "chalk": "2.4.1", + "commander": "2.15.1", + "diff": "3.5.0", + "glob": "7.1.2", + "js-yaml": "3.12.0", + "minimatch": "3.0.4", + "resolve": "1.8.1", + "semver": "5.5.0", + "tslib": "1.9.3", + "tsutils": "2.28.0" }, "dependencies": { "ansi-styles": { @@ -4903,7 +4903,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.2" } }, "chalk": { @@ -4912,9 +4912,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" } }, "has-flag": { @@ -4935,7 +4935,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -4946,11 +4946,11 @@ "integrity": "sha1-jNo8OMnKtU57It989CuO8RXc2V8=", "dev": true, "requires": { - "chalk": "^1.1.1", - "lodash": "^3.10.1", - "log-symbols": "^1.0.2", - "text-table": "^0.2.0", - "tslint": "^2.5.0" + "chalk": "1.1.3", + "lodash": "3.10.1", + "log-symbols": "1.0.2", + "text-table": "0.2.0", + "tslint": "2.5.1" }, "dependencies": { "findup-sync": { @@ -4959,7 +4959,7 @@ "integrity": "sha1-4KkKRQB1xJRm7lE3MgV1FLgeh4w=", "dev": true, "requires": { - "glob": "~4.3.0" + "glob": "4.3.5" } }, "glob": { @@ -4968,10 +4968,10 @@ "integrity": "sha1-gPuwjKVA8jiszl0R0em8QedRc9M=", "dev": true, "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^2.0.1", - "once": "^1.3.0" + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "2.0.10", + "once": "1.4.0" } }, "lodash": { @@ -4986,7 +4986,7 @@ "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", "dev": true, "requires": { - "brace-expansion": "^1.0.0" + "brace-expansion": "1.1.11" } }, "tslint": { @@ -4995,9 +4995,9 @@ "integrity": "sha1-veTJnpfNXRxvuzAz9kt9iX/UGpI=", "dev": true, "requires": { - "findup-sync": "~0.2.1", - "optimist": "~0.6.0", - "underscore.string": "~3.1.1" + "findup-sync": "0.2.1", + "optimist": "0.6.1", + "underscore.string": "3.1.1" } } } @@ -5008,7 +5008,7 @@ "integrity": "sha512-bh5nAtW0tuhvOJnx1GLRn5ScraRLICGyJV5wJhtRWOLsxW70Kk5tZtpK3O/hW6LDnqKS9mlUMPZj9fEMJ0gxqA==", "dev": true, "requires": { - "tslib": "^1.8.1" + "tslib": "1.9.3" } }, "tunnel-agent": { @@ -5017,7 +5017,7 @@ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "dev": true, "requires": { - "safe-buffer": "^5.0.1" + "safe-buffer": "5.1.2" } }, "tweetnacl": { @@ -5033,7 +5033,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "~1.1.2" + "prelude-ls": "1.1.2" } }, "type-detect": { @@ -5055,9 +5055,9 @@ "dev": true, "optional": true, "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" } }, "uglify-to-browserify": { @@ -5085,10 +5085,10 @@ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", "dev": true, "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" + "arr-union": "3.1.0", + "get-value": "2.0.6", + "is-extendable": "0.1.1", + "set-value": "0.4.3" }, "dependencies": { "extend-shallow": { @@ -5097,7 +5097,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "set-value": { @@ -5106,10 +5106,10 @@ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "to-object-path": "0.3.0" } } } @@ -5126,8 +5126,8 @@ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" + "has-value": "0.3.1", + "isobject": "3.0.1" }, "dependencies": { "has-value": { @@ -5136,9 +5136,9 @@ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" + "get-value": "2.0.6", + "has-values": "0.1.4", + "isobject": "2.1.0" }, "dependencies": { "isobject": { @@ -5208,7 +5208,7 @@ "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", "dev": true, "requires": { - "user-home": "^1.1.1" + "user-home": "1.1.1" } }, "validator": { @@ -5228,9 +5228,9 @@ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "dev": true, "requires": { - "assert-plus": "^1.0.0", + "assert-plus": "1.0.0", "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "extsprintf": "1.3.0" } }, "vinyl": { @@ -5239,8 +5239,8 @@ "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", "dev": true, "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", + "clone": "1.0.4", + "clone-stats": "0.0.1", "replace-ext": "0.0.1" } }, @@ -5250,14 +5250,14 @@ "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", "dev": true, "requires": { - "defaults": "^1.0.0", - "glob-stream": "^3.1.5", - "glob-watcher": "^0.0.6", - "graceful-fs": "^3.0.0", - "mkdirp": "^0.5.0", - "strip-bom": "^1.0.0", - "through2": "^0.6.1", - "vinyl": "^0.4.0" + "defaults": "1.0.3", + "glob-stream": "3.1.18", + "glob-watcher": "0.0.6", + "graceful-fs": "3.0.11", + "mkdirp": "0.5.1", + "strip-bom": "1.0.0", + "through2": "0.6.5", + "vinyl": "0.4.6" }, "dependencies": { "clone": { @@ -5268,14 +5268,14 @@ }, "readable-stream": { "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", + "core-util-is": "1.0.2", + "inherits": "2.0.3", "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "string_decoder": "0.10.31" } }, "through2": { @@ -5284,8 +5284,8 @@ "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" + "readable-stream": "1.0.34", + "xtend": "4.0.1" } }, "vinyl": { @@ -5294,8 +5294,8 @@ "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", "dev": true, "requires": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" + "clone": "0.2.0", + "clone-stats": "0.0.1" } } } @@ -5306,13 +5306,13 @@ "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", "dev": true, "requires": { - "append-buffer": "^1.0.2", - "convert-source-map": "^1.5.0", - "graceful-fs": "^4.1.6", - "normalize-path": "^2.1.1", - "now-and-later": "^2.0.0", - "remove-bom-buffer": "^3.0.0", - "vinyl": "^2.0.0" + "append-buffer": "1.0.2", + "convert-source-map": "1.5.1", + "graceful-fs": "4.1.11", + "normalize-path": "2.1.1", + "now-and-later": "2.0.0", + "remove-bom-buffer": "3.0.0", + "vinyl": "2.2.0" }, "dependencies": { "clone": { @@ -5345,12 +5345,12 @@ "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", "dev": true, "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" + "clone": "2.1.1", + "clone-buffer": "1.0.0", + "clone-stats": "1.0.0", + "cloneable-readable": "1.1.2", + "remove-trailing-separator": "1.1.0", + "replace-ext": "1.0.0" } } } @@ -5361,7 +5361,7 @@ "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", "dev": true, "requires": { - "source-map": "^0.5.1" + "source-map": "0.5.7" } }, "which": { @@ -5370,7 +5370,7 @@ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { - "isexe": "^2.0.0" + "isexe": "2.0.0" } }, "window-size": { @@ -5405,9 +5405,9 @@ "dev": true, "optional": true, "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", "window-size": "0.1.0" } }, diff --git a/package.json b/package.json index 8584319a60..caa9b332a9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "class-validator", "private": true, - "version": "1.0.0-rc", + "version": "1.0.0-rc1", "description": "Class-based validation with Typescript / ES6 / ES5 using decorators or validation schemas. Supports both node.js and browser", "license": "MIT", "readmeFilename": "README.md", @@ -33,7 +33,7 @@ "@types/mocha": "^5.2.5", "@types/node": "^10.5.2", "@types/sinon": "^5.0.1", - "@types/validator": "^9.4.3", + "@types/validator": "^9.4.2", "chai": "^4.1.2", "chai-as-promised": "^7.1.1", "codecov": "^3.0.4", From 44e6227cba617adda71c8939ec8a7cfa42a4f6f9 Mon Sep 17 00:00:00 2001 From: Christoph Linder Date: Tue, 20 Nov 2018 01:12:37 +0100 Subject: [PATCH 11/12] Smaller bundle - next bunch of migrations... --- sample/sample1-simple-validation/Post.ts | 4 +- sample/sample2-using-groups/Post.ts | 2 +- sample/sample3-nested-objects/Post.ts | 3 +- sample/sample3-nested-objects/Tag.ts | 2 +- sample/sample7-inheritance-support/Post.ts | 3 +- src/decorator/Contains.ts | 5 +- src/decorator/Equals.ts | 4 +- src/decorator/IsAlpha.ts | 4 +- src/decorator/IsAlphanumeric.ts | 5 +- src/decorator/IsArray.ts | 3 +- src/decorator/IsAscii.ts | 4 +- src/decorator/IsBase64.ts | 4 +- src/decorator/IsBoolean.ts | 5 +- src/decorator/IsBooleanString.ts | 4 +- src/decorator/IsByteLength.ts | 3 +- src/decorator/IsCreditCard.ts | 4 +- src/decorator/IsCurrency.ts | 3 +- src/decorator/IsDate.ts | 4 +- src/decorator/IsDateString.ts | 4 +- src/decorator/IsDivisibleBy.ts | 5 +- src/decorator/IsEmail.ts | 4 +- src/decorator/IsEmpty.ts | 4 +- src/decorator/IsEnum.ts | 4 +- src/decorator/IsFQDN.ts | 4 +- src/decorator/IsFullWidth.ts | 6 +- src/decorator/IsHalfWidth.ts | 5 +- src/decorator/IsHexColor.ts | 3 +- src/decorator/IsHexadecimal.ts | 3 +- src/decorator/IsIP.ts | 3 +- src/decorator/IsISBN.ts | 3 +- src/decorator/IsISIN.ts | 3 +- src/decorator/IsISO8601.ts | 28 ++ src/decorator/IsIn.ts | 4 +- src/decorator/IsInt.ts | 4 +- src/decorator/IsJSON.ts | 26 ++ src/decorator/IsLowercase.ts | 26 ++ src/decorator/IsMilitaryTime.ts | 27 ++ src/decorator/IsMobilePhone.ts | 29 ++ src/decorator/IsMongoId.ts | 26 ++ src/decorator/IsMultibyte.ts | 27 ++ src/decorator/IsNegative.ts | 4 +- src/decorator/IsNotEmpty.ts | 4 +- src/decorator/IsNotIn.ts | 4 +- src/decorator/IsNumber.ts | 4 +- src/decorator/IsNumberString.ts | 4 +- src/decorator/IsPhoneNumber.ts | 6 +- src/decorator/IsPositive.ts | 4 +- src/decorator/IsString.ts | 4 +- src/decorator/IsSurrogatePair.ts | 27 ++ src/decorator/IsUUID.ts | 27 ++ src/decorator/IsUppercase.ts | 27 ++ src/decorator/IsUrl.ts | 27 ++ src/decorator/IsVariableWidth.ts | 5 +- src/decorator/Length.ts | 36 +++ src/decorator/Matches.ts | 35 +++ src/decorator/Max.ts | 4 +- src/decorator/MaxDate.ts | 4 +- src/decorator/MaxLength.ts | 27 ++ src/decorator/Min.ts | 4 +- src/decorator/MinDate.ts | 4 +- src/decorator/MinLength.ts | 27 ++ src/decorator/NotContains.ts | 4 +- src/decorator/NotEquals.ts | 4 +- src/decorator/ValidateBy.ts | 10 +- src/decorator/decorators.ts | 247 ------------------ src/validation/ValidationTypes.ts | 56 ---- src/validation/Validator.ts | 155 +---------- test/functional/inherited-validation.spec.ts | 2 +- test/functional/nested-validation.spec.ts | 3 +- test/functional/validation-error.spec.ts | 4 +- ...alidation-functions-and-decorators.spec.ts | 150 +++++++---- test/functional/validation-options.spec.ts | 4 +- 72 files changed, 669 insertions(+), 572 deletions(-) create mode 100644 src/decorator/IsISO8601.ts create mode 100644 src/decorator/IsJSON.ts create mode 100644 src/decorator/IsLowercase.ts create mode 100644 src/decorator/IsMilitaryTime.ts create mode 100644 src/decorator/IsMobilePhone.ts create mode 100644 src/decorator/IsMongoId.ts create mode 100644 src/decorator/IsMultibyte.ts create mode 100644 src/decorator/IsSurrogatePair.ts create mode 100644 src/decorator/IsUUID.ts create mode 100644 src/decorator/IsUppercase.ts create mode 100644 src/decorator/IsUrl.ts create mode 100644 src/decorator/Length.ts create mode 100644 src/decorator/Matches.ts create mode 100644 src/decorator/MaxLength.ts create mode 100644 src/decorator/MinLength.ts diff --git a/sample/sample1-simple-validation/Post.ts b/sample/sample1-simple-validation/Post.ts index 6c0a1c8fa2..30859a3601 100644 --- a/sample/sample1-simple-validation/Post.ts +++ b/sample/sample1-simple-validation/Post.ts @@ -1,10 +1,12 @@ -import {MinLength, MaxLength, ArrayNotEmpty, ArrayMinSize, ArrayMaxSize} from "../../src/decorator/decorators"; +import {ArrayNotEmpty, ArrayMinSize, ArrayMaxSize} from "../../src/decorator/decorators"; import {IsDate} from "../../src/decorator/IsDate"; import {IsInt} from "../../src/decorator/IsInt"; import {IsEnum} from "../../src/decorator/IsEnum"; import {Contains} from "../../src/decorator/Contains"; import {IsEmail} from "../../src/decorator/IsEmail"; import {IsFQDN} from "../../src/decorator/IsFQDN"; +import {MinLength} from "../../src/decorator/MinLength"; +import {MaxLength} from "../../src/decorator/MaxLength"; export enum PostType { Public, diff --git a/sample/sample2-using-groups/Post.ts b/sample/sample2-using-groups/Post.ts index 432613850a..1d6b30ad3a 100644 --- a/sample/sample2-using-groups/Post.ts +++ b/sample/sample2-using-groups/Post.ts @@ -1,9 +1,9 @@ -import {Length} from "../../src/decorator/decorators"; import {IsDate} from "../../src/decorator/IsDate"; import {IsInt} from "../../src/decorator/IsInt"; import {Contains} from "../../src/decorator/Contains"; import {IsEmail} from "../../src/decorator/IsEmail"; import {IsFQDN} from "../../src/decorator/IsFQDN"; +import {Length} from "../../src/decorator/Length"; export class Post { diff --git a/sample/sample3-nested-objects/Post.ts b/sample/sample3-nested-objects/Post.ts index ddbbc3b8f0..d1161e187f 100644 --- a/sample/sample3-nested-objects/Post.ts +++ b/sample/sample3-nested-objects/Post.ts @@ -1,5 +1,6 @@ -import {Length, ValidateNested} from "../../src/decorator/decorators"; +import {ValidateNested} from "../../src/decorator/decorators"; import {Tag} from "./Tag"; +import {Length} from "../../src/decorator/Length"; export class Post { diff --git a/sample/sample3-nested-objects/Tag.ts b/sample/sample3-nested-objects/Tag.ts index 7075f51e8d..cea904d5ba 100644 --- a/sample/sample3-nested-objects/Tag.ts +++ b/sample/sample3-nested-objects/Tag.ts @@ -1,4 +1,4 @@ -import {Length} from "../../src/decorator/decorators"; +import {Length} from "../../src/decorator/Length"; export class Tag { diff --git a/sample/sample7-inheritance-support/Post.ts b/sample/sample7-inheritance-support/Post.ts index 9961c96bb1..89e0f533d6 100644 --- a/sample/sample7-inheritance-support/Post.ts +++ b/sample/sample7-inheritance-support/Post.ts @@ -1,7 +1,8 @@ -import {MinLength, MaxLength} from "../../src/decorator/decorators"; import {BaseContent} from "./BaseContent"; import {IsInt} from "../../src/decorator/IsInt"; import {Contains} from "../../src/decorator/Contains"; +import {MinLength} from "../../src/decorator/MinLength"; +import {MaxLength} from "../../src/decorator/MaxLength"; export class Post extends BaseContent { diff --git a/src/decorator/Contains.ts b/src/decorator/Contains.ts index f15e9f19f9..f3d2143f7b 100644 --- a/src/decorator/Contains.ts +++ b/src/decorator/Contains.ts @@ -2,6 +2,8 @@ import {buildMessage, ValidateBy} from "./ValidateBy"; import {ValidationOptions} from "./ValidationOptions"; import validatorJsContains = require("validator/lib/contains"); +export const CONTAINS = "contains"; + /** * Checks if the string contains the seed. * If given value is not a string, then it returns false. @@ -14,8 +16,9 @@ export function contains(value: string, seed: string): boolean { * Checks if the string contains the seed. */ export function Contains(seed: string, validationOptions?: ValidationOptions) { + return ValidateBy({ - name: "contains", + name: CONTAINS, validate: (value, args) => contains(value, args.constraints[0]), constraints: [seed], defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain a $constraint1 string", validationOptions), diff --git a/src/decorator/Equals.ts b/src/decorator/Equals.ts index d87e997520..b73dd26ad0 100644 --- a/src/decorator/Equals.ts +++ b/src/decorator/Equals.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const EQUALS = "equals"; + /** * Checks if value matches ("===") the comparison. */ @@ -13,7 +15,7 @@ export function equals(value: any, comparison: any): boolean { */ export function Equals(comparison: any, validationOptions?: ValidationOptions) { return ValidateBy({ - name: "equals", + name: EQUALS, validate: (value, args) => equals(value, args.constraints[0]), constraints: [comparison], defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be equal to $constraint1", validationOptions), diff --git a/src/decorator/IsAlpha.ts b/src/decorator/IsAlpha.ts index 0d120738f0..0e73f53c93 100644 --- a/src/decorator/IsAlpha.ts +++ b/src/decorator/IsAlpha.ts @@ -2,6 +2,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import validatorJsIsAlpha = require("validator/lib/isAlpha"); +export const IS_ALPHA = "isAlpha"; + /** * Checks if the string contains only letters (a-zA-Z). * If given value is not a string, then it returns false. @@ -16,7 +18,7 @@ export function isAlpha(value: string): boolean { */ export function IsAlpha(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isAlpha", + name: IS_ALPHA, validate: (value) => isAlpha(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain only letters (a-zA-Z)", validationOptions) }, diff --git a/src/decorator/IsAlphanumeric.ts b/src/decorator/IsAlphanumeric.ts index f8f73b82df..323c676e02 100644 --- a/src/decorator/IsAlphanumeric.ts +++ b/src/decorator/IsAlphanumeric.ts @@ -2,6 +2,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import validatorJsIsAlphanumeric = require("validator/lib/isAlphanumeric"); +export const IS_ALPHANUMERIC = "isAlphanumeric"; + /** * Checks if the string contains only letters and numbers. * If given value is not a string, then it returns false. @@ -10,13 +12,12 @@ export function isAlphanumeric(value: string): boolean { return typeof value === "string" && validatorJsIsAlphanumeric(value); } - /** * Checks if the string contains only letters and numbers. */ export function IsAlphanumeric(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isAlphanumeric", + name: IS_ALPHANUMERIC, validate: (value) => isAlphanumeric(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain only letters and numbers", validationOptions) }, diff --git a/src/decorator/IsArray.ts b/src/decorator/IsArray.ts index a99a23b210..35906f8d43 100644 --- a/src/decorator/IsArray.ts +++ b/src/decorator/IsArray.ts @@ -1,6 +1,7 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const IS_ARRAY = "isArray"; /** * Checks if a given value is an array @@ -14,7 +15,7 @@ export function isArray(value: any): boolean { */ export function IsArray(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isArray", + name: IS_ARRAY, validate: (value) => isArray(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be an array", validationOptions) }, diff --git a/src/decorator/IsAscii.ts b/src/decorator/IsAscii.ts index f23beea36e..a50b93d72e 100644 --- a/src/decorator/IsAscii.ts +++ b/src/decorator/IsAscii.ts @@ -2,6 +2,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import validatorJsIsAscii = require("validator/lib/isAscii"); +export const IS_ASCII = "isAscii"; + /** * Checks if the string contains ASCII chars only. * If given value is not a string, then it returns false. @@ -15,7 +17,7 @@ export function isAscii(value: string): boolean { */ export function IsAscii(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isAscii", + name: IS_ASCII, validate: (value) => isAscii(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain only ASCII characters", validationOptions) }, diff --git a/src/decorator/IsBase64.ts b/src/decorator/IsBase64.ts index 268e46d83e..bfe5804a8b 100644 --- a/src/decorator/IsBase64.ts +++ b/src/decorator/IsBase64.ts @@ -2,6 +2,7 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import validatorJsIsBase64 = require("validator/lib/isBase64"); +export const IS_BASE64 = "isBase64"; /** * Checks if a string is base64 encoded. @@ -11,13 +12,12 @@ export function isBase64(value: string): boolean { return typeof value === "string" && validatorJsIsBase64(value); } - /** * Checks if a string is base64 encoded. */ export function IsBase64(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isBase64", + name: IS_BASE64, validate: (value) => isBase64(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be base64 encoded", validationOptions) }, diff --git a/src/decorator/IsBoolean.ts b/src/decorator/IsBoolean.ts index 5aad0d081c..f1e0f6e3ef 100644 --- a/src/decorator/IsBoolean.ts +++ b/src/decorator/IsBoolean.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const IS_BOOLEAN = "isBoolean"; + /** * Checks if a given value is a real boolean. */ @@ -8,13 +10,12 @@ export function isBoolean(value: any): boolean { return value instanceof Boolean || typeof value === "boolean"; } - /** * Checks if a value is a boolean. */ export function IsBoolean(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isBoolean", + name: IS_BOOLEAN, validate: (value) => isBoolean(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a boolean value", validationOptions) }, diff --git a/src/decorator/IsBooleanString.ts b/src/decorator/IsBooleanString.ts index 6fc4b4c50e..004e0cb3b9 100644 --- a/src/decorator/IsBooleanString.ts +++ b/src/decorator/IsBooleanString.ts @@ -2,6 +2,8 @@ import {buildMessage, ValidateBy} from "./ValidateBy"; import {ValidationOptions} from "./ValidationOptions"; import validatorJsIsBoolean = require("validator/lib/isBoolean"); +export const IS_BOOLEAN_STRING = "isBooleanString"; + /** * Checks if a string is a boolean. * If given value is not a string, then it returns false. @@ -15,7 +17,7 @@ export function isBooleanString(value: string): boolean { */ export function IsBooleanString(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isBooleanString", + name: IS_BOOLEAN_STRING, validate: (value) => isBooleanString(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + eachPrefix + "$property must be a boolean string", validationOptions) }, diff --git a/src/decorator/IsByteLength.ts b/src/decorator/IsByteLength.ts index 3efe4723f3..1ada2953a6 100644 --- a/src/decorator/IsByteLength.ts +++ b/src/decorator/IsByteLength.ts @@ -2,6 +2,7 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import validatorJsIsByteLength = require("validator/lib/isByteLength"); +export const IS_BYTE_LENGTH = "isByteLength"; /** * Checks if the string's length (in bytes) falls in a range. @@ -17,7 +18,7 @@ export function isByteLength(value: string, min: number, max?: number): boolean */ export function IsByteLength(min: number, max?: number, validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isByteLength", + name: IS_BYTE_LENGTH, validate: (value, args) => isByteLength(value, args.constraints[0], args.constraints[1]), constraints: [min, max], defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property's byte length must fall into ($constraint1, $constraint2) range", validationOptions) diff --git a/src/decorator/IsCreditCard.ts b/src/decorator/IsCreditCard.ts index 557ec63aea..d79f2d54fc 100644 --- a/src/decorator/IsCreditCard.ts +++ b/src/decorator/IsCreditCard.ts @@ -2,6 +2,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import validatorJsIsCreditCard = require("validator/lib/isCreditCard"); +export const IS_CREDIT_CARD = "isCreditCard"; + /** * Checks if the string is a credit card. * If given value is not a string, then it returns false. @@ -16,7 +18,7 @@ export function isCreditCard(value: string): boolean { */ export function IsCreditCard(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isCreditCard", + name: IS_CREDIT_CARD, validate: (value) => isCreditCard(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a credit card", validationOptions) }, diff --git a/src/decorator/IsCurrency.ts b/src/decorator/IsCurrency.ts index fc7bcb8e14..7b066d0df0 100644 --- a/src/decorator/IsCurrency.ts +++ b/src/decorator/IsCurrency.ts @@ -2,6 +2,7 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import validatorJsIsCurrency = require("validator/lib/isCurrency"); +export const IS_CURRENCY = "isCurrency"; /** * Checks if the string is a valid currency amount. @@ -16,7 +17,7 @@ export function isCurrency(value: string, options?: ValidatorJS.IsCurrencyOption */ export function IsCurrency(options?: ValidatorJS.IsCurrencyOptions, validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isCurrency", + name: IS_CURRENCY, validate: (value, args) => isCurrency(value, args.constraints[0]), constraints: [options], defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a currency", validationOptions) diff --git a/src/decorator/IsDate.ts b/src/decorator/IsDate.ts index 5625807b83..4d5f0f60f3 100644 --- a/src/decorator/IsDate.ts +++ b/src/decorator/IsDate.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const IS_DATE = "isDate"; + /** * Checks if a given value is a real date. */ @@ -13,7 +15,7 @@ export function isDate(value: any): boolean { */ export function IsDate(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isDate", + name: IS_DATE, validate: (value) => isDate(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a Date instance", validationOptions) }, diff --git a/src/decorator/IsDateString.ts b/src/decorator/IsDateString.ts index fd420b6225..e011508143 100644 --- a/src/decorator/IsDateString.ts +++ b/src/decorator/IsDateString.ts @@ -2,6 +2,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import {isString} from "./IsString"; +export const IS_DATE_STRING = "isDateString"; + /** * Checks if a given value is a ISOString date. */ @@ -12,7 +14,7 @@ export function isDateString(value: any): boolean { export function IsDateString(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isDateString", + name: IS_DATE_STRING, validate: (value) => isDateString(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a ISOString", validationOptions) }, diff --git a/src/decorator/IsDivisibleBy.ts b/src/decorator/IsDivisibleBy.ts index 298cb1830c..c8060d74cb 100644 --- a/src/decorator/IsDivisibleBy.ts +++ b/src/decorator/IsDivisibleBy.ts @@ -1,8 +1,9 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; - import * as validatorIsDivisibleBy from "validator/lib/isDivisibleBy"; +export const IS_DIVISIBLE_BY = "isDivisibleBy"; + /** * Checks if value is a number that's divisible by another. */ @@ -17,7 +18,7 @@ export function isDivisibleBy(value: number, num: number): boolean { */ export function IsDivisibleBy(num: number, validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isDivisibleBy", + name: IS_DIVISIBLE_BY, validate: (value, args) => isDivisibleBy(value, args.constraints[0]), constraints: [num], defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be divisible by $constraint1", validationOptions) diff --git a/src/decorator/IsEmail.ts b/src/decorator/IsEmail.ts index 12d04ac61a..eb1bf1f4ff 100644 --- a/src/decorator/IsEmail.ts +++ b/src/decorator/IsEmail.ts @@ -2,6 +2,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import validatorJsIsEmail = require("validator/lib/isEmail"); +export const IS_EMAIL = "isEmail"; + /** * Checks if the string is an email. * If given value is not a string, then it returns false. @@ -15,7 +17,7 @@ export function isEmail(value: string, options?: ValidatorJS.IsEmailOptions): bo */ export function IsEmail(options?: ValidatorJS.IsEmailOptions, validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isEmail", + name: IS_EMAIL, validate: (value, args) => isEmail(value, args.constraints[0]), constraints: [options], defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be an email", validationOptions) diff --git a/src/decorator/IsEmpty.ts b/src/decorator/IsEmpty.ts index 8de37125a4..a7de31dc26 100644 --- a/src/decorator/IsEmpty.ts +++ b/src/decorator/IsEmpty.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const IS_EMPTY = "isEmpty"; + /** * Checks if given value is empty (=== '', === null, === undefined). */ @@ -13,7 +15,7 @@ export function isEmpty(value: any): boolean { */ export function IsEmpty(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isEmpty", + name: IS_EMPTY, validate: (value, args) => isEmpty(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be empty", validationOptions), diff --git a/src/decorator/IsEnum.ts b/src/decorator/IsEnum.ts index 94a96ebc8b..1607f12c54 100644 --- a/src/decorator/IsEnum.ts +++ b/src/decorator/IsEnum.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const IS_ENUM = "isEnum"; + /** * Checks if a given value is an enum */ @@ -15,7 +17,7 @@ export function isEnum(value: any, entity: any): boolean { */ export function IsEnum(entity: Object, validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isEnum", + name: IS_ENUM, validate: (value, args) => isEnum(value, args.constraints[0]), constraints: [entity], defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a valid enum value", validationOptions) diff --git a/src/decorator/IsFQDN.ts b/src/decorator/IsFQDN.ts index 735ee5a232..8bc8d6d00d 100644 --- a/src/decorator/IsFQDN.ts +++ b/src/decorator/IsFQDN.ts @@ -2,6 +2,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import validatorJsIsFQDN = require("validator/lib/isFQDN"); +export const IS_FQDN = "isFqdn"; + /** * Checks if the string is a fully qualified domain name (e.g. domain.com). * If given value is not a string, then it returns false. @@ -15,7 +17,7 @@ export function isFQDN(value: string, options?: ValidatorJS.IsFQDNOptions): bool */ export function IsFQDN(options?: ValidatorJS.IsFQDNOptions, validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isFqdn", + name: IS_FQDN, validate: (value, args) => isFQDN(value, args.constraints[0]), constraints: [options], defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a valid domain name", validationOptions) diff --git a/src/decorator/IsFullWidth.ts b/src/decorator/IsFullWidth.ts index 9563fe91dd..70a9493f89 100644 --- a/src/decorator/IsFullWidth.ts +++ b/src/decorator/IsFullWidth.ts @@ -1,9 +1,10 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; - // strange module export :( const validatorJsIsFullWidth: (value: any) => boolean = require("validator/lib/isFullWidth").default; +export const IS_FULL_WIDTH = "isFullWidth"; + /** * Checks if the string contains any full-width chars. * If given value is not a string, then it returns false. @@ -12,13 +13,12 @@ export function isFullWidth(value: string): boolean { return typeof value === "string" && validatorJsIsFullWidth(value); } - /** * Checks if the string contains any full-width chars. */ export function IsFullWidth(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isFullWidth", + name: IS_FULL_WIDTH, validate: (value) => isFullWidth(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain a full-width characters", validationOptions) }, diff --git a/src/decorator/IsHalfWidth.ts b/src/decorator/IsHalfWidth.ts index 0bba26e377..da0f61fe59 100644 --- a/src/decorator/IsHalfWidth.ts +++ b/src/decorator/IsHalfWidth.ts @@ -1,9 +1,10 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; - // strange module export :( const validatorJsIsHalfWidth: (value: any) => boolean = require("validator/lib/isHalfWidth").default; +export const IS_HALF_WIDTH = "isHalfWidth"; + /** * Checks if the string contains any half-width chars. * If given value is not a string, then it returns false. @@ -17,7 +18,7 @@ export function isHalfWidth(value: string): boolean { */ export function IsHalfWidth(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isHalfWidth", + name: IS_HALF_WIDTH, validate: (value) => isHalfWidth(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain a half-width characters", validationOptions) }, diff --git a/src/decorator/IsHexColor.ts b/src/decorator/IsHexColor.ts index b840104140..29eefb2616 100644 --- a/src/decorator/IsHexColor.ts +++ b/src/decorator/IsHexColor.ts @@ -2,6 +2,7 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import validatorJsIsHexColor = require("validator/lib/isHexColor"); +export const IS_HEX_COLOR = "isHexColor"; /** * Checks if the string is a hexadecimal color. @@ -16,7 +17,7 @@ export function isHexColor(value: string): boolean { */ export function IsHexColor(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isHexColor", + name: IS_HEX_COLOR, validate: (value) => isHexColor(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a hexadecimal color", validationOptions) }, diff --git a/src/decorator/IsHexadecimal.ts b/src/decorator/IsHexadecimal.ts index 70862f5faa..b5be8ccc55 100644 --- a/src/decorator/IsHexadecimal.ts +++ b/src/decorator/IsHexadecimal.ts @@ -2,6 +2,7 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import validatorJsIsHexadecimal = require("validator/lib/isHexadecimal"); +export const IS_HEXADECIMAL = "isHexadecimal"; /** * Checks if the string is a hexadecimal number. @@ -16,7 +17,7 @@ export function isHexadecimal(value: string): boolean { */ export function IsHexadecimal(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isHexadecimal", + name: IS_HEXADECIMAL, validate: (value) => isHexadecimal(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a hexadecimal number", validationOptions) }, diff --git a/src/decorator/IsIP.ts b/src/decorator/IsIP.ts index 658a50dc36..f2f2bc01bd 100644 --- a/src/decorator/IsIP.ts +++ b/src/decorator/IsIP.ts @@ -2,6 +2,7 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import validatorJsIsIP = require("validator/lib/isIP"); +export const IS_IP = "isIp"; /** * Checks if the string is an IP (version 4 or 6). @@ -18,7 +19,7 @@ export function isIP(value: string, version?: "4" | "6"): boolean { */ export function IsIP(version?: "4" | "6", validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isIp", + name: IS_IP, validate: (value, args) => isIP(value, args.constraints[0]), constraints: [version], defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be an ip address", validationOptions) diff --git a/src/decorator/IsISBN.ts b/src/decorator/IsISBN.ts index 2cf034f03c..b9aa9ac222 100644 --- a/src/decorator/IsISBN.ts +++ b/src/decorator/IsISBN.ts @@ -2,6 +2,7 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import validatorJsIsISBN = require("validator/lib/isISBN"); +export const IS_ISBN = "isIsbn"; /** * Checks if the string is an ISBN (version 10 or 13). @@ -18,7 +19,7 @@ export function isISBN(value: string, version?: "10" | "13"): boolean { */ export function IsISBN(version?: "10" | "13", validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isIsbn", + name: IS_ISBN, validate: (value, args) => isISBN(value, args.constraints[0]), constraints: [version], defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be an ISBN", validationOptions) diff --git a/src/decorator/IsISIN.ts b/src/decorator/IsISIN.ts index f20ffbe13e..7ff7ec2105 100644 --- a/src/decorator/IsISIN.ts +++ b/src/decorator/IsISIN.ts @@ -2,6 +2,7 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import validatorJsIsISIN = require("validator/lib/isISIN"); +export const IS_ISIN = "isIsin"; /** * Checks if the string is an ISIN (stock/security identifier). @@ -16,7 +17,7 @@ export function isISIN(value: string): boolean { */ export function IsISIN(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isIsin", + name: IS_ISIN, validate: (value) => isISIN(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be an ISIN (stock/security identifier)", validationOptions) }, diff --git a/src/decorator/IsISO8601.ts b/src/decorator/IsISO8601.ts new file mode 100644 index 0000000000..d4223135e7 --- /dev/null +++ b/src/decorator/IsISO8601.ts @@ -0,0 +1,28 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsISO8601 = require("validator/lib/isISO8601"); + +export const IS_ISO8601 = "isIso8601"; + + +/** + * Checks if the string is a valid ISO 8601 date. + * If given value is not a string, then it returns false. + */ +export function isISO8601(value: string): boolean { + return typeof value === "string" && validatorJsIsISO8601(value); +} + + +/** + * Checks if the string is a valid ISO 8601 date. + */ +export function IsISO8601(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: IS_ISO8601, + validate: (value) => isISO8601(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a valid ISO 8601 date string", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsIn.ts b/src/decorator/IsIn.ts index d50785ce94..5e1b2b3c97 100644 --- a/src/decorator/IsIn.ts +++ b/src/decorator/IsIn.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const IS_IN = "isIn"; + /** * Checks if given value is in a array of allowed values. */ @@ -13,7 +15,7 @@ export function isIn(value: any, possibleValues: any[]): boolean { */ export function IsIn(values: any[], validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isIn", + name: IS_IN, constraints: [values], validate: (value, args) => isIn(value, args.constraints[0]), defaultMessage: buildMessage( diff --git a/src/decorator/IsInt.ts b/src/decorator/IsInt.ts index a1ee84fd8a..67c9ea1664 100644 --- a/src/decorator/IsInt.ts +++ b/src/decorator/IsInt.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const IS_INT = "isInt"; + /** * Checks if value is an integer. */ @@ -13,7 +15,7 @@ export function isInt(val: number): boolean { */ export function IsInt(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isInt", + name: IS_INT, validate: (value) => isInt(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be an integer number", validationOptions) }, diff --git a/src/decorator/IsJSON.ts b/src/decorator/IsJSON.ts new file mode 100644 index 0000000000..553bb109fa --- /dev/null +++ b/src/decorator/IsJSON.ts @@ -0,0 +1,26 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsJSON = require("validator/lib/isJSON"); + +export const IS_JSON = "isJson"; + +/** + * Checks if the string is valid JSON (note: uses JSON.parse). + * If given value is not a string, then it returns false. + */ +export function isJSON(value: string): boolean { + return typeof value === "string" && validatorJsIsJSON(value); +} + +/** + * Checks if the string is valid JSON (note: uses JSON.parse). + */ +export function IsJSON(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: IS_JSON, + validate: (value) => isJSON(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a json string", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsLowercase.ts b/src/decorator/IsLowercase.ts new file mode 100644 index 0000000000..a3d655fafc --- /dev/null +++ b/src/decorator/IsLowercase.ts @@ -0,0 +1,26 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsLowercase = require("validator/lib/isLowercase"); + +export const IS_LOWERCASE = "isLowercase"; + +/** + * Checks if the string is lowercase. + * If given value is not a string, then it returns false. + */ +export function isLowercase(value: string): boolean { + return typeof value === "string" && validatorJsIsLowercase(value); +} + +/** + * Checks if the string is lowercase. + */ +export function IsLowercase(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: IS_LOWERCASE, + validate: (value) => isLowercase(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a lowercase string", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsMilitaryTime.ts b/src/decorator/IsMilitaryTime.ts new file mode 100644 index 0000000000..3206dcf189 --- /dev/null +++ b/src/decorator/IsMilitaryTime.ts @@ -0,0 +1,27 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import {matches} from "./Matches"; + +export const IS_MILITARY_TIME = "isMilitaryTime"; + +/** + * Checks if the string represents a time without a given timezone in the format HH:MM (military) + * If the given value does not match the pattern HH:MM, then it returns false. + */ +export function isMilitaryTime(value: string): boolean { + return matches(value, /^([01]\d|2[0-3]):?([0-5]\d)$/); +} + + +/** + * Checks if the string correctly represents a time in the format HH:MM + */ +export function IsMilitaryTime(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: IS_MILITARY_TIME, + validate: (value) => isMilitaryTime(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a military time", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsMobilePhone.ts b/src/decorator/IsMobilePhone.ts new file mode 100644 index 0000000000..0193523474 --- /dev/null +++ b/src/decorator/IsMobilePhone.ts @@ -0,0 +1,29 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsMobilePhone = require("validator/lib/isMobilePhone"); + +export const IS_MOBILE_PHONE = "isMobilePhone"; + +/** + * Checks if the string is a mobile phone number. See ValidatorJS for a list of supported locales! + * If given value is not a string, then it returns false. + */ +export function isMobilePhone(value: string, locale: ValidatorJS.MobilePhoneLocale | ValidatorJS.MobilePhoneLocale[] | "any"): boolean { + // typings are wrong: current ValidatorJS.isMobilePhone supports both one locale and an array of locales! + return typeof value === "string" && validatorJsIsMobilePhone(value, locale as any); +} + +/** + * Checks if the string is a mobile phone number. See ValidatorJS for a list of supported locales! + */ +export function IsMobilePhone(locale: ValidatorJS.MobilePhoneLocale | ValidatorJS.MobilePhoneLocale[] | any, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: IS_MOBILE_PHONE, + validate: (value, args) => isMobilePhone(value, args.constraints[0]), + constraints: [locale], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a phone number", validationOptions) + }, + validationOptions + ); +} + diff --git a/src/decorator/IsMongoId.ts b/src/decorator/IsMongoId.ts new file mode 100644 index 0000000000..83554de2dc --- /dev/null +++ b/src/decorator/IsMongoId.ts @@ -0,0 +1,26 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsMongoId = require("validator/lib/isMongoId"); + +export const IS_MONGO_ID = "isMongoId"; + +/** + * Checks if the string is a valid hex-encoded representation of a MongoDB ObjectId. + * If given value is not a string, then it returns false. + */ +export function isMongoId(value: string): boolean { + return typeof value === "string" && validatorJsIsMongoId(value); +} + +/** + * Checks if the string is a valid hex-encoded representation of a MongoDB ObjectId. + */ +export function IsMongoId(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: IS_MONGO_ID, + validate: (value) => isMongoId(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a mongodb id", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsMultibyte.ts b/src/decorator/IsMultibyte.ts new file mode 100644 index 0000000000..f015513e09 --- /dev/null +++ b/src/decorator/IsMultibyte.ts @@ -0,0 +1,27 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsMultibyte = require("validator/lib/isMultibyte"); + +export const IS_MULTIBYTE = "isMultibyte"; + +/** + * Checks if the string contains one or more multibyte chars. + * If given value is not a string, then it returns false. + */ +export function isMultibyte(value: string): boolean { + return typeof value === "string" && validatorJsIsMultibyte(value); +} + + +/** + * Checks if the string contains one or more multibyte chars. + */ +export function IsMultibyte(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: IS_MULTIBYTE, + validate: (value) => isMultibyte(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain one or more multibyte chars", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsNegative.ts b/src/decorator/IsNegative.ts index af48457e51..ff6efc7813 100644 --- a/src/decorator/IsNegative.ts +++ b/src/decorator/IsNegative.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const IS_NEGATIVE = "isNegative"; + /** * Checks if the value is a negative number. */ @@ -13,7 +15,7 @@ export function isNegative(value: number): boolean { */ export function IsNegative(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isNegative", + name: IS_NEGATIVE, validate: (value) => isNegative(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a negative number", validationOptions) }, diff --git a/src/decorator/IsNotEmpty.ts b/src/decorator/IsNotEmpty.ts index 201ffd0511..e46c78646d 100644 --- a/src/decorator/IsNotEmpty.ts +++ b/src/decorator/IsNotEmpty.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const IS_NOT_EMPTY = "isNotEmpty"; + /** * Checks if given value is not empty (!== '', !== null, !== undefined). */ @@ -13,7 +15,7 @@ export function isNotEmpty(value: any): boolean { */ export function IsNotEmpty(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isNotEmpty", + name: IS_NOT_EMPTY, validate: (value, args) => isNotEmpty(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property should not be empty", validationOptions), diff --git a/src/decorator/IsNotIn.ts b/src/decorator/IsNotIn.ts index c27ccdad31..9b24e7fb73 100644 --- a/src/decorator/IsNotIn.ts +++ b/src/decorator/IsNotIn.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const IS_NOT_IN = "isNotIn"; + /** * Checks if given value not in a array of allowed values. */ @@ -13,7 +15,7 @@ export function isNotIn(value: any, possibleValues: any[]): boolean { */ export function IsNotIn(values: any[], validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isNotIn", + name: IS_NOT_IN, validate: (value, args) => isNotIn(value, args.constraints[0]), constraints: [values], defaultMessage: buildMessage( diff --git a/src/decorator/IsNumber.ts b/src/decorator/IsNumber.ts index c5de9a3f6e..faef169f83 100644 --- a/src/decorator/IsNumber.ts +++ b/src/decorator/IsNumber.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const IS_NUMBER = "isNumber"; + /** * Options to be passed to IsNumber decorator. */ @@ -29,7 +31,7 @@ export function isNumber(value: any, options: IsNumberOptions = {}): boolean { */ export function IsNumber(options: IsNumberOptions = {}, validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isNumber", + name: IS_NUMBER, validate: (value, args) => isNumber(value, args.constraints[0]), constraints: [options], defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a number", validationOptions) diff --git a/src/decorator/IsNumberString.ts b/src/decorator/IsNumberString.ts index 722aae97cd..80388d2aae 100644 --- a/src/decorator/IsNumberString.ts +++ b/src/decorator/IsNumberString.ts @@ -2,6 +2,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import validatorJsIsNumeric = require("validator/lib/isNumeric"); +export const IS_NUMBER_STRING = "isNumberString"; + /** * Checks if the string is numeric. * If given value is not a string, then it returns false. @@ -15,7 +17,7 @@ export function isNumberString(value: string, options?: ValidatorJS.IsNumericOpt */ export function IsNumberString(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isNumberString", + name: IS_NUMBER_STRING, validate: (value) => isNumberString(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a number string", validationOptions) }, diff --git a/src/decorator/IsPhoneNumber.ts b/src/decorator/IsPhoneNumber.ts index 527efc4f97..ba0d1db8d1 100644 --- a/src/decorator/IsPhoneNumber.ts +++ b/src/decorator/IsPhoneNumber.ts @@ -1,10 +1,11 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; - import * as libphonenumber from "google-libphonenumber"; const phoneUtil = libphonenumber.PhoneNumberUtil.getInstance(); +export const IS_PHONE_NUMBER = "isPhoneNumber"; + /** * Checks if the string is a valid phone number. * @param value the potential phone number string to test @@ -23,7 +24,6 @@ export function isPhoneNumber(value: string, region: string | null): boolean { } } - /** * Checks if the string is a valid phone number. * @param region 2 characters uppercase country code (e.g. DE, US, CH). @@ -32,7 +32,7 @@ export function isPhoneNumber(value: string, region: string | null): boolean { */ export function IsPhoneNumber(region: string | null, validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isPhoneNumber", + name: IS_PHONE_NUMBER, constraints: [region], validate: (value, args) => isPhoneNumber(value, args.constraints[0]), defaultMessage: buildMessage( diff --git a/src/decorator/IsPositive.ts b/src/decorator/IsPositive.ts index 8b70167350..34ad17b9b8 100644 --- a/src/decorator/IsPositive.ts +++ b/src/decorator/IsPositive.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const IS_POSITIVE = "isPositive"; + /** * Checks if the value is a positive number. */ @@ -13,7 +15,7 @@ export function isPositive(value: number): boolean { */ export function IsPositive(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isPositive", + name: IS_POSITIVE, validate: (value) => isPositive(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a positive number", validationOptions) }, diff --git a/src/decorator/IsString.ts b/src/decorator/IsString.ts index 0c562e3898..bd110064ea 100644 --- a/src/decorator/IsString.ts +++ b/src/decorator/IsString.ts @@ -1,6 +1,8 @@ import {buildMessage, ValidateBy} from "./ValidateBy"; import {ValidationOptions} from "./ValidationOptions"; +export const IS_STRING = "isString"; + /** * Checks if a given value is a real string. */ @@ -13,7 +15,7 @@ export function isString(value: any): boolean { */ export function IsString(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isString", + name: IS_STRING, validate: (value) => isString(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be a string", validationOptions) }, diff --git a/src/decorator/IsSurrogatePair.ts b/src/decorator/IsSurrogatePair.ts new file mode 100644 index 0000000000..b8c968e009 --- /dev/null +++ b/src/decorator/IsSurrogatePair.ts @@ -0,0 +1,27 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsSurrogatePair = require("validator/lib/isSurrogatePair"); + +export const IS_SURROGATE_PAIR = "isSurrogatePair"; + +/** + * Checks if the string contains any surrogate pairs chars. + * If given value is not a string, then it returns false. + */ +export function isSurrogatePair(value: string): boolean { + return typeof value === "string" && validatorJsIsSurrogatePair(value); +} + + +/** + * Checks if the string contains any surrogate pairs chars. + */ +export function IsSurrogatePair(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: IS_SURROGATE_PAIR, + validate: (value) => isSurrogatePair(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain any surrogate pairs chars", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsUUID.ts b/src/decorator/IsUUID.ts new file mode 100644 index 0000000000..7a26a5d404 --- /dev/null +++ b/src/decorator/IsUUID.ts @@ -0,0 +1,27 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsUUID = require("validator/lib/isUUID"); + +export const IS_UUID = "isUuid"; + +/** + * Checks if the string is a UUID (version 3, 4 or 5). + * If given value is not a string, then it returns false. + */ +export function isUUID(value: string, version?: 3|4|5|"3"|"4"|"5"|"all"): boolean { + return typeof value === "string" && validatorJsIsUUID(value, version); +} + +/** + * Checks if the string is a UUID (version 3, 4 or 5). + */ +export function IsUUID(version?: 3|4|5|"3"|"4"|"5"|"all", validationOptions?: ValidationOptions) { + return ValidateBy({ + name: IS_UUID, + validate: (value, args) => isUUID(value, args.constraints[0]), + constraints: [version], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be an UUID", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsUppercase.ts b/src/decorator/IsUppercase.ts new file mode 100644 index 0000000000..e03be8a538 --- /dev/null +++ b/src/decorator/IsUppercase.ts @@ -0,0 +1,27 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsUppercase = require("validator/lib/isUppercase"); + +export const IS_UPPERCASE = "isUppercase"; + +/** + * Checks if the string is uppercase. + * If given value is not a string, then it returns false. + */ +export function isUppercase(value: string): boolean { + return typeof value === "string" && validatorJsIsUppercase(value); +} + + +/** + * Checks if the string is uppercase. + */ +export function IsUppercase(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: IS_UPPERCASE, + validate: (value) => isUppercase(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be uppercase", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsUrl.ts b/src/decorator/IsUrl.ts new file mode 100644 index 0000000000..f6377e95a6 --- /dev/null +++ b/src/decorator/IsUrl.ts @@ -0,0 +1,27 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsURL = require("validator/lib/isURL"); + +export const IS_URL = "isUrl"; + +/** + * Checks if the string is an url. + * If given value is not a string, then it returns false. + */ +export function isURL(value: string, options?: ValidatorJS.IsURLOptions): boolean { + return typeof value === "string" && validatorJsIsURL(value, options); +} + +/** + * Checks if the string is an url. + */ +export function IsUrl(options?: ValidatorJS.IsURLOptions, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: IS_URL, + validate: (value, args) => isURL(value, args.constraints[0]), + constraints: [options], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be an URL address", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsVariableWidth.ts b/src/decorator/IsVariableWidth.ts index f7ab55931a..6dafb80c43 100644 --- a/src/decorator/IsVariableWidth.ts +++ b/src/decorator/IsVariableWidth.ts @@ -1,8 +1,9 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; - import validatorJsIsVariableWidth = require("validator/lib/isVariableWidth"); +export const IS_VARIABLE_WIDTH = "isVariableWidth"; + /** * Checks if the string contains variable-width chars. * If given value is not a string, then it returns false. @@ -16,7 +17,7 @@ export function isVariableWidth(value: string): boolean { */ export function IsVariableWidth(validationOptions?: ValidationOptions) { return ValidateBy({ - name: "isVariableWidth", + name: IS_VARIABLE_WIDTH, validate: (value) => isVariableWidth(value), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain a full-width and half-width characters", validationOptions) }, diff --git a/src/decorator/Length.ts b/src/decorator/Length.ts new file mode 100644 index 0000000000..bf2ff46ffa --- /dev/null +++ b/src/decorator/Length.ts @@ -0,0 +1,36 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsIsLength = require("validator/lib/isLength"); + +export const LENGTH = "length"; + +/** + * Checks if the string's length falls in a range. Note: this function takes into account surrogate pairs. + * If given value is not a string, then it returns false. + */ +export function length(value: string, min: number, max?: number): boolean { + return typeof value === "string" && validatorJsIsLength(value, min, max); +} + +/** + * Checks if the string's length falls in a range. Note: this function takes into account surrogate pairs. + */ +export function Length(min: number, max?: number, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: LENGTH, + validate: (value, args) => length(value, args.constraints[0], args.constraints[1]), + constraints: [min, max], + defaultMessage: buildMessage((eachPrefix, args) => { + const isMinLength = args.constraints[0] !== null && args.constraints[0] !== undefined; + const isMaxLength = args.constraints[1] !== null && args.constraints[1] !== undefined; + if (isMinLength && (!args.value || args.value.length < args.constraints[0])) { + return eachPrefix + "$property must be longer than or equal to $constraint1 characters"; + } else if (isMaxLength && (args.value.length > args.constraints[1])) { + return eachPrefix + "$property must be shorter than or equal to $constraint2 characters"; + } + return eachPrefix + "$property must be longer than or equal to $constraint1 and shorter than or equal to $constraint2 characters"; + }, validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/Matches.ts b/src/decorator/Matches.ts new file mode 100644 index 0000000000..d9395938c1 --- /dev/null +++ b/src/decorator/Matches.ts @@ -0,0 +1,35 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import validatorJsMatches = require("validator/lib/matches"); + +export const MATCHES = "matches"; + +/** + * Checks if string matches the pattern. Either matches('foo', /foo/i) or matches('foo', 'foo', 'i'). + * If given value is not a string, then it returns false. + */ +export function matches(value: string, pattern: RegExp, modifiers?: string): boolean { + return typeof value === "string" && validatorJsMatches(value, pattern, modifiers); +} + +/** + * Checks if string matches the pattern. Either matches('foo', /foo/i) or matches('foo', 'foo', 'i'). + */ +export function Matches(pattern: RegExp, validationOptions?: ValidationOptions): Function; +export function Matches(pattern: RegExp, modifiers?: string, validationOptions?: ValidationOptions): Function; +export function Matches(pattern: RegExp, modifiersOrAnnotationOptions?: string | ValidationOptions, validationOptions?: ValidationOptions): Function { + let modifiers: string; + if (modifiersOrAnnotationOptions && modifiersOrAnnotationOptions instanceof Object && !validationOptions) { + validationOptions = modifiersOrAnnotationOptions as ValidationOptions; + } else { + modifiers = modifiersOrAnnotationOptions as string; + } + return ValidateBy({ + name: MATCHES, + validate: (value, args) => matches(value, args.constraints[0]), + constraints: [pattern, modifiers], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must match $constraint1 regular expression", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/Max.ts b/src/decorator/Max.ts index 995918a5d6..83a201abf3 100644 --- a/src/decorator/Max.ts +++ b/src/decorator/Max.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const MAX = "max"; + /** * Checks if the first number is less than or equal to the second/reference. */ @@ -13,7 +15,7 @@ export function max(num: number, reference: number): boolean { */ export function Max(reference: number, validationOptions?: ValidationOptions) { return ValidateBy({ - name: "max", + name: MAX, validate: (value, args) => max(value, args.constraints[0]), constraints: [reference], defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must not be greater than $constraint1", validationOptions) diff --git a/src/decorator/MaxDate.ts b/src/decorator/MaxDate.ts index 3e70f7210b..9c82e0f683 100644 --- a/src/decorator/MaxDate.ts +++ b/src/decorator/MaxDate.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const MAX_DATE = "maxDate"; + /** * Checks if the value is a date that's before the specified date. */ @@ -13,7 +15,7 @@ export function maxDate(date: Date, maxDate: Date): boolean { */ export function MaxDate(date: Date, validationOptions?: ValidationOptions) { return ValidateBy({ - name: "maxDate", + name: MAX_DATE, validate: (value, args) => maxDate(value, args.constraints[0]), constraints: [date], defaultMessage: buildMessage((eachPrefix) => "maximal allowed date for " + eachPrefix + "$property is $constraint1", validationOptions) diff --git a/src/decorator/MaxLength.ts b/src/decorator/MaxLength.ts new file mode 100644 index 0000000000..f4ad3d6714 --- /dev/null +++ b/src/decorator/MaxLength.ts @@ -0,0 +1,27 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import {length} from "./Length"; + +export const MAX_LENGTH = "maxLength"; + +/** + * Checks if the string's length is not more than given number. Note: this function takes into account surrogate pairs. + * If given value is not a string, then it returns false. + */ +export function maxLength(value: string, max: number) { + return typeof value === "string" && length(value, 0, max); +} + +/** + * Checks if the string's length is not more than given number. Note: this function takes into account surrogate pairs. + */ +export function MaxLength(max: number, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: MAX_LENGTH, + validate: (value, args) => maxLength(value, args.constraints[0]), + constraints: [max], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be shorter than or equal to $constraint1 characters", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/Min.ts b/src/decorator/Min.ts index 6b288117dd..b43c8c3217 100644 --- a/src/decorator/Min.ts +++ b/src/decorator/Min.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const MIN = "min"; + /** * Checks if the first number is greater than or equal to the second/reference. */ @@ -13,7 +15,7 @@ export function min(num: number, reference: number): boolean { */ export function Min(reference: number, validationOptions?: ValidationOptions) { return ValidateBy({ - name: "min", + name: MIN, validate: (value, args) => min(value, args.constraints[0]), constraints: [reference], defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must not be less than $constraint1", validationOptions) diff --git a/src/decorator/MinDate.ts b/src/decorator/MinDate.ts index f071ff9766..eff65f9190 100644 --- a/src/decorator/MinDate.ts +++ b/src/decorator/MinDate.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const MIN_DATE = "minDate"; + /** * Checks if the value is a date that's after the specified date. */ @@ -13,7 +15,7 @@ export function minDate(date: Date, minDate: Date): boolean { */ export function MinDate(date: Date, validationOptions?: ValidationOptions) { return ValidateBy({ - name: "minDate", + name: MIN_DATE, validate: (value, args) => minDate(value, args.constraints[0]), constraints: [date], defaultMessage: buildMessage((eachPrefix) => "minimal allowed date for " + eachPrefix + "$property is $constraint1", validationOptions) diff --git a/src/decorator/MinLength.ts b/src/decorator/MinLength.ts new file mode 100644 index 0000000000..2a80a6edd1 --- /dev/null +++ b/src/decorator/MinLength.ts @@ -0,0 +1,27 @@ +import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "./ValidateBy"; +import {length} from "./Length"; + +export const MIN_LENGTH = "minLength"; + +/** + * Checks if the string's length is not less than given number. Note: this function takes into account surrogate pairs. + * If given value is not a string, then it returns false. + */ +export function minLength(value: string, min: number) { + return typeof value === "string" && length(value, min); +} + +/** + * Checks if the string's length is not less than given number. Note: this function takes into account surrogate pairs. + */ +export function MinLength(min: number, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: MIN_LENGTH, + validate: (value, args) => minLength(value, args.constraints[0]), + constraints: [min], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must be longer than or equal to $constraint1 characters", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/NotContains.ts b/src/decorator/NotContains.ts index 52b0c464a0..687e912d3d 100644 --- a/src/decorator/NotContains.ts +++ b/src/decorator/NotContains.ts @@ -2,6 +2,7 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; import {contains} from "./Contains"; +export const NOT_CONTAINS = "notContains"; /** * Checks if the string does not contain the seed. @@ -11,13 +12,12 @@ export function notContains(value: string, seed: string): boolean { return typeof value === "string" && !contains(value, seed); } - /** * Checks if the string does not contain the seed. */ export function NotContains(seed: string, validationOptions?: ValidationOptions) { return ValidateBy({ - name: "notContains", + name: NOT_CONTAINS, validate: (value, args) => notContains(value, args.constraints[0]), constraints: [seed], defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property should not contain a $constraint1 string", validationOptions) diff --git a/src/decorator/NotEquals.ts b/src/decorator/NotEquals.ts index dc7151feb4..424ceabc94 100644 --- a/src/decorator/NotEquals.ts +++ b/src/decorator/NotEquals.ts @@ -1,6 +1,8 @@ import {ValidationOptions} from "./ValidationOptions"; import {buildMessage, ValidateBy} from "./ValidateBy"; +export const NOT_EQUALS = "notEquals"; + /** * Checks if value does not match ("!==") the comparison. */ @@ -13,7 +15,7 @@ export function notEquals(value: any, comparison: any): boolean { */ export function NotEquals(comparison: any, validationOptions?: ValidationOptions) { return ValidateBy({ - name: "notEquals", + name: NOT_EQUALS, constraints: [comparison], validate: (value, args) => notEquals(value, args.constraints[0]), defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property should not be equal to $constraint1", validationOptions) diff --git a/src/decorator/ValidateBy.ts b/src/decorator/ValidateBy.ts index c19cf4d815..72c5e96a98 100644 --- a/src/decorator/ValidateBy.ts +++ b/src/decorator/ValidateBy.ts @@ -4,13 +4,15 @@ import {registerDecorator} from "../register-decorator"; import {ValidationArguments} from "../validation/ValidationArguments"; import {ValidatorConstraintInterface} from "../validation/ValidatorConstraintInterface"; -export function buildMessage(impl: (eachPrefix: string) => string, validationOptions?: ValidationOptions): - (validationArguments?: ValidationArguments) => string { - return () => { +export function buildMessage( + impl: (eachPrefix: string, args?: ValidationArguments) => string, + validationOptions?: ValidationOptions) + : (validationArguments?: ValidationArguments) => string { + return (validationArguments?: ValidationArguments) => { const eachPrefix = validationOptions && validationOptions.each ? "each value in " : ""; - return impl(eachPrefix); + return impl(eachPrefix, validationArguments); }; } diff --git a/src/decorator/decorators.ts b/src/decorator/decorators.ts index 0b681de9f9..2e5260a700 100644 --- a/src/decorator/decorators.ts +++ b/src/decorator/decorators.ts @@ -86,253 +86,6 @@ export function IsOptional(validationOptions?: ValidationOptions) { }; } -// ------------------------------------------------------------------------- -// String checkers -// ------------------------------------------------------------------------- - - -/** - * Checks if the string is a valid ISO 8601 date. - */ -export function IsISO8601(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_ISO8601, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is valid JSON (note: uses JSON.parse). - */ -export function IsJSON(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_JSON, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is lowercase. - */ -export function IsLowercase(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_LOWERCASE, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is a mobile phone number (locale is one of ['zh-CN', 'zh-TW', 'en-ZA', 'en-AU', 'en-HK', - * 'pt-PT', 'fr-FR', 'el-GR', 'en-GB', 'en-US', 'en-ZM', 'ru-RU', 'nb-NO', 'nn-NO', 'vi-VN', 'en-NZ']). - */ -export function IsMobilePhone(locale: string, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_MOBILE_PHONE, - target: object.constructor, - propertyName: propertyName, - constraints: [locale], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is a valid hex-encoded representation of a MongoDB ObjectId. - */ -export function IsMongoId(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_MONGO_ID, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string contains one or more multibyte chars. - */ -export function IsMultibyte(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_MULTIBYTE, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string contains any surrogate pairs chars. - */ -export function IsSurrogatePair(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_SURROGATE_PAIR, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is an url. - */ -export function IsUrl(options?: ValidatorJS.IsURLOptions, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_URL, - target: object.constructor, - propertyName: propertyName, - constraints: [options], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is a UUID (version 3, 4 or 5). - */ -export function IsUUID(version?: "3" | "4" | "5", validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_UUID, - target: object.constructor, - propertyName: propertyName, - constraints: [version], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string is uppercase. - */ -export function IsUppercase(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_UPPERCASE, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string's length falls in a range. Note: this function takes into account surrogate pairs. - */ -export function Length(min: number, max?: number, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.LENGTH, - target: object.constructor, - propertyName: propertyName, - constraints: [min, max], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string's length is not less than given number. Note: this function takes into account surrogate pairs. - */ -export function MinLength(min: number, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.MIN_LENGTH, - target: object.constructor, - propertyName: propertyName, - constraints: [min], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string's length is not more than given number. Note: this function takes into account surrogate pairs. - */ -export function MaxLength(max: number, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.MAX_LENGTH, - target: object.constructor, - propertyName: propertyName, - constraints: [max], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if string matches the pattern. Either matches('foo', /foo/i) or matches('foo', 'foo', 'i'). - */ -export function Matches(pattern: RegExp, validationOptions?: ValidationOptions): Function; -export function Matches(pattern: RegExp, modifiers?: string, validationOptions?: ValidationOptions): Function; -export function Matches(pattern: RegExp, modifiersOrAnnotationOptions?: string | ValidationOptions, validationOptions?: ValidationOptions): Function { - let modifiers: string; - if (modifiersOrAnnotationOptions && modifiersOrAnnotationOptions instanceof Object && !validationOptions) { - validationOptions = modifiersOrAnnotationOptions as ValidationOptions; - } else { - modifiers = modifiersOrAnnotationOptions as string; - } - - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.MATCHES, - target: object.constructor, - propertyName: propertyName, - constraints: [pattern, modifiers], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if the string correctly represents a time in the format HH:MM - */ -export function IsMilitaryTime(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_MILITARY_TIME, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - // ------------------------------------------------------------------------- // Array checkers // ------------------------------------------------------------------------- diff --git a/src/validation/ValidationTypes.ts b/src/validation/ValidationTypes.ts index 135cd50881..7b242badab 100644 --- a/src/validation/ValidationTypes.ts +++ b/src/validation/ValidationTypes.ts @@ -13,23 +13,6 @@ export class ValidationTypes { // FIXME: delete? static IS_DEFINED = "isDefined"; - /* string checkers */ - static IS_ISO8601 = "isIso8601"; - static IS_JSON = "isJson"; - static IS_LOWERCASE = "isLowercase"; - static IS_MOBILE_PHONE = "isMobilePhone"; - static IS_MONGO_ID = "isMongoId"; - static IS_MULTIBYTE = "isMultibyte"; - static IS_SURROGATE_PAIR = "isSurrogatePair"; - static IS_URL = "isUrl"; - static IS_UUID = "isUuid"; - static LENGTH = "length"; - static IS_UPPERCASE = "isUppercase"; - static MIN_LENGTH = "minLength"; - static MAX_LENGTH = "maxLength"; - static MATCHES = "matches"; - static IS_MILITARY_TIME = "isMilitaryTime"; - /* array checkers */ static ARRAY_CONTAINS = "arrayContains"; static ARRAY_NOT_CONTAINS = "arrayNotContains"; @@ -63,45 +46,6 @@ export class ValidationTypes { case this.IS_DEFINED: return eachPrefix + "$property should not be null or undefined"; - /* string checkers */ - case this.IS_ISO8601: - return eachPrefix + "$property must be a valid ISO 8601 date string"; - case this.IS_JSON: - return eachPrefix + "$property must be a json string"; - case this.IS_LOWERCASE: - return eachPrefix + "$property must be a lowercase string"; - case this.IS_MOBILE_PHONE: - return eachPrefix + "$property must be a phone number"; - case this.IS_MONGO_ID: - return eachPrefix + "$property must be a mongodb id"; - case this.IS_MULTIBYTE: - return eachPrefix + "$property must contain one or more multibyte chars"; - case this.IS_SURROGATE_PAIR: - return eachPrefix + "$property must contain any surrogate pairs chars"; - case this.IS_URL: - return eachPrefix + "$property must be an URL address"; - case this.IS_UUID: - return eachPrefix + "$property must be an UUID"; - case this.IS_UPPERCASE: - return eachPrefix + "$property must be uppercase"; - case this.LENGTH: - return (args: ValidationArguments) => { - const isMinLength = args.constraints[0] !== null && args.constraints[0] !== undefined; - const isMaxLength = args.constraints[1] !== null && args.constraints[1] !== undefined; - if (isMinLength && (!args.value || args.value.length < args.constraints[0])) { - return eachPrefix + "$property must be longer than or equal to $constraint1 characters"; - } else if (isMaxLength && (args.value.length > args.constraints[1])) { - return eachPrefix + "$property must be shorter than or equal to $constraint2 characters"; - } - return eachPrefix + "$property must be longer than or equal to $constraint1 and shorter than or equal to $constraint2 characters"; - }; - case this.MIN_LENGTH: - return eachPrefix + "$property must be longer than or equal to $constraint1 characters"; - case this.MAX_LENGTH: - return eachPrefix + "$property must be shorter than or equal to $constraint1 characters"; - case this.MATCHES: - return eachPrefix + "$property must match $constraint1 regular expression"; - /* array checkers */ case this.ARRAY_CONTAINS: return eachPrefix + "$property must contain $constraint1 values"; diff --git a/src/validation/Validator.ts b/src/validation/Validator.ts index a587caf09d..5e5fb3a0dc 100644 --- a/src/validation/Validator.ts +++ b/src/validation/Validator.ts @@ -5,6 +5,8 @@ import {IsNumberOptions} from "./ValidationTypeOptions"; import {ValidatorOptions} from "./ValidatorOptions"; import {ValidationExecutor} from "./ValidationExecutor"; import {ValidationOptions} from "../decorator/ValidationOptions"; +import {length} from "../decorator/Length"; +import {matches} from "../decorator/Matches"; /** * Validator performs validation of the given object based on its metadata. @@ -111,38 +113,6 @@ export class Validator { case ValidationTypes.IS_DEFINED: return this.isDefined(value); - /* string checkers */ - case ValidationTypes.IS_ISO8601: - return this.isISO8601(value); - case ValidationTypes.IS_JSON: - return this.isJSON(value); - case ValidationTypes.IS_LOWERCASE: - return this.isLowercase(value); - case ValidationTypes.IS_MOBILE_PHONE: - return this.isMobilePhone(value, metadata.constraints[0]); - case ValidationTypes.IS_MONGO_ID: - return this.isMongoId(value); - case ValidationTypes.IS_MULTIBYTE: - return this.isMultibyte(value); - case ValidationTypes.IS_SURROGATE_PAIR: - return this.isSurrogatePair(value); - case ValidationTypes.IS_URL: - return this.isURL(value, metadata.constraints[0]); - case ValidationTypes.IS_UUID: - return this.isUUID(value, metadata.constraints[0]); - case ValidationTypes.IS_UPPERCASE: - return this.isUppercase(value); - case ValidationTypes.LENGTH: - return this.length(value, metadata.constraints[0], metadata.constraints[1]); - case ValidationTypes.MIN_LENGTH: - return this.minLength(value, metadata.constraints[0]); - case ValidationTypes.MAX_LENGTH: - return this.maxLength(value, metadata.constraints[0]); - case ValidationTypes.MATCHES: - return this.matches(value, metadata.constraints[0], metadata.constraints[1]); - case ValidationTypes.IS_MILITARY_TIME: - return this.isMilitaryTime(value); - /* array checkers */ case ValidationTypes.ARRAY_CONTAINS: return this.arrayContains(value, metadata.constraints[0]); @@ -180,127 +150,6 @@ export class Validator { - /** - * Checks if the string is a valid ISO 8601 date. - * If given value is not a string, then it returns false. - */ - isISO8601(value: string): boolean { - return typeof value === "string" && this.validatorJs.isISO8601(value); - } - - /** - * Checks if the string is valid JSON (note: uses JSON.parse). - * If given value is not a string, then it returns false. - */ - isJSON(value: string): boolean { - return typeof value === "string" && this.validatorJs.isJSON(value); - } - - /** - * Checks if the string is lowercase. - * If given value is not a string, then it returns false. - */ - isLowercase(value: string): boolean { - return typeof value === "string" && this.validatorJs.isLowercase(value); - } - - /** - * Checks if the string is a mobile phone number (locale is one of ['zh-CN', 'zh-TW', 'en-ZA', 'en-AU', 'en-HK', - * 'pt-PT', 'fr-FR', 'el-GR', 'en-GB', 'en-US', 'en-ZM', 'ru-RU', 'nb-NO', 'nn-NO', 'vi-VN', 'en-NZ']). - * If given value is not a string, then it returns false. - */ - isMobilePhone(value: string, locale: ValidatorJS.MobilePhoneLocale): boolean { - return typeof value === "string" && this.validatorJs.isMobilePhone(value, locale); - } - - /** - * Checks if the string is a valid hex-encoded representation of a MongoDB ObjectId. - * If given value is not a string, then it returns false. - */ - isMongoId(value: string): boolean { - return typeof value === "string" && this.validatorJs.isMongoId(value); - } - - /** - * Checks if the string contains one or more multibyte chars. - * If given value is not a string, then it returns false. - */ - isMultibyte(value: string): boolean { - return typeof value === "string" && this.validatorJs.isMultibyte(value); - } - - /** - * Checks if the string contains any surrogate pairs chars. - * If given value is not a string, then it returns false. - */ - isSurrogatePair(value: string): boolean { - return typeof value === "string" && this.validatorJs.isSurrogatePair(value); - } - - /** - * Checks if the string is an url. - * If given value is not a string, then it returns false. - */ - isURL(value: string, options?: ValidatorJS.IsURLOptions): boolean { - return typeof value === "string" && this.validatorJs.isURL(value, options); - } - - /** - * Checks if the string is a UUID (version 3, 4 or 5). - * If given value is not a string, then it returns false. - */ - isUUID(value: string, version?: "3"|"4"|"5"): boolean { - return typeof value === "string" && this.validatorJs.isUUID(value, version); - } - - /** - * Checks if the string is uppercase. - * If given value is not a string, then it returns false. - */ - isUppercase(value: string): boolean { - return typeof value === "string" && this.validatorJs.isUppercase(value); - } - - /** - * Checks if the string's length falls in a range. Note: this function takes into account surrogate pairs. - * If given value is not a string, then it returns false. - */ - length(value: string, min: number, max?: number): boolean { - return typeof value === "string" && this.validatorJs.isLength(value, min, max); - } - - /** - * Checks if the string's length is not less than given number. Note: this function takes into account surrogate pairs. - * If given value is not a string, then it returns false. - */ - minLength(value: string, min: number) { - return typeof value === "string" && this.length(value, min); - } - - /** - * Checks if the string's length is not more than given number. Note: this function takes into account surrogate pairs. - * If given value is not a string, then it returns false. - */ - maxLength(value: string, max: number) { - return typeof value === "string" && this.length(value, 0, max); - } - - /** - * Checks if string matches the pattern. Either matches('foo', /foo/i) or matches('foo', 'foo', 'i'). - * If given value is not a string, then it returns false. - */ - matches(value: string, pattern: RegExp, modifiers?: string): boolean { - return typeof value === "string" && this.validatorJs.matches(value, pattern, modifiers); - } - - /** - * Checks if the string represents a time without a given timezone in the format HH:MM (military) - * If the given value does not match the pattern HH:MM, then it returns false. - */ - isMilitaryTime(value: string): boolean { - return this.matches(value, /^([01]\d|2[0-3]):?([0-5]\d)$/); - } - // ------------------------------------------------------------------------- // Validation Methods: array checkers // ------------------------------------------------------------------------- diff --git a/test/functional/inherited-validation.spec.ts b/test/functional/inherited-validation.spec.ts index 27f97b36b9..7dfe62a83f 100644 --- a/test/functional/inherited-validation.spec.ts +++ b/test/functional/inherited-validation.spec.ts @@ -1,11 +1,11 @@ import "es6-shim"; -import {MinLength} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; import {should, use } from "chai"; import * as chaiAsPromised from "chai-as-promised"; import {Contains} from "../../src/decorator/Contains"; +import {MinLength} from "../../src/decorator/MinLength"; should(); use(chaiAsPromised); diff --git a/test/functional/nested-validation.spec.ts b/test/functional/nested-validation.spec.ts index 2f4d661c31..46df9c8ffb 100644 --- a/test/functional/nested-validation.spec.ts +++ b/test/functional/nested-validation.spec.ts @@ -1,5 +1,5 @@ import "es6-shim"; -import {IsDefined, MinLength, ValidateNested} from "../../src/decorator/decorators"; +import {IsDefined, ValidateNested} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; import {expect} from "chai"; import {ValidationTypes} from "../../src/validation/ValidationTypes"; @@ -8,6 +8,7 @@ import {should, use } from "chai"; import * as chaiAsPromised from "chai-as-promised"; import {Contains} from "../../src/decorator/Contains"; +import {MinLength} from "../../src/decorator/MinLength"; should(); use(chaiAsPromised); diff --git a/test/functional/validation-error.spec.ts b/test/functional/validation-error.spec.ts index ceec232588..d9bacf1afc 100644 --- a/test/functional/validation-error.spec.ts +++ b/test/functional/validation-error.spec.ts @@ -1,5 +1,5 @@ import "es6-shim"; -import { IsUrl, IsOptional, ValidateNested, MinLength } from "../../src/decorator/decorators"; +import { IsOptional, ValidateNested} from "../../src/decorator/decorators"; import { Validator } from "../../src/validation/Validator"; import { expect } from "chai"; @@ -7,6 +7,8 @@ import {should, use } from "chai"; import * as chaiAsPromised from "chai-as-promised"; import {IsString} from "../../src/decorator/IsString"; +import {IsUrl} from "../../src/decorator/IsUrl"; +import {MinLength} from "../../src/decorator/MinLength"; should(); use(chaiAsPromised); diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts index a1ccb0a024..dbfabd36e7 100644 --- a/test/functional/validation-functions-and-decorators.spec.ts +++ b/test/functional/validation-functions-and-decorators.spec.ts @@ -1,20 +1,6 @@ import "es6-shim"; import {expect} from "chai"; import { - IsISO8601, - IsJSON, - Length, - IsLowercase, - IsMongoId, - IsMultibyte, - IsSurrogatePair, - IsUrl, - IsUUID, - IsUppercase, - Matches, - MinLength, - MaxLength, - IsMilitaryTime, ArrayNotEmpty, ArrayMinSize, ArrayMaxSize, @@ -73,6 +59,21 @@ import {isHexadecimal, IsHexadecimal} from "../../src/decorator/IsHexadecimal"; import {isIP, IsIP} from "../../src/decorator/IsIP"; import {isISBN, IsISBN} from "../../src/decorator/IsISBN"; import {isISIN, IsISIN} from "../../src/decorator/IsISIN"; +import {IsISO8601, isISO8601} from "../../src/decorator/IsISO8601"; +import {IsJSON, isJSON} from "../../src/decorator/IsJSON"; +import {isLowercase, IsLowercase} from "../../src/decorator/IsLowercase"; +import {IsMobilePhone} from "../../src/decorator/IsMobilePhone"; +import {isMongoId, IsMongoId} from "../../src/decorator/IsMongoId"; +import {IsMultibyte, isMultibyte} from "../../src/decorator/IsMultibyte"; +import {isSurrogatePair, IsSurrogatePair} from "../../src/decorator/IsSurrogatePair"; +import {IsUrl, isURL} from "../../src/decorator/IsUrl"; +import {IsUUID, isUUID} from "../../src/decorator/IsUUID"; +import {IsUppercase, isUppercase} from "../../src/decorator/IsUppercase"; +import {length, Length} from "../../src/decorator/Length"; +import {MinLength, minLength} from "../../src/decorator/MinLength"; +import {maxLength, MaxLength} from "../../src/decorator/MaxLength"; +import {Matches, matches} from "../../src/decorator/Matches"; +import {IsMilitaryTime} from "../../src/decorator/IsMilitaryTime"; should(); use(chaiAsPromised); @@ -98,7 +99,7 @@ export function checkInvalidValues(object: { someProperty: any }, values: any[], object.someProperty = value; return validator .validate(object, validatorOptions) - .then(errors => errors.length.should.be.equal(1)); + .then(errors => errors.length.should.be.equal(1, `no errors (unexpectedly) on value: ${value}`)); }); Promise.all(promises).then(() => done(), err => done(err)); } @@ -2173,11 +2174,11 @@ describe("IsISO8601", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isISO8601(value).should.be.true); + validValues.forEach(value => isISO8601(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isISO8601(value).should.be.false); + invalidValues.forEach(value => isISO8601(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -2207,11 +2208,11 @@ describe("IsJSON", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isJSON(value).should.be.true); + validValues.forEach(value => isJSON(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isJSON(value).should.be.false); + invalidValues.forEach(value => isJSON(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -2251,11 +2252,11 @@ describe("IsLowercase", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isLowercase(value).should.be.true); + validValues.forEach(value => isLowercase(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isLowercase(value).should.be.false); + invalidValues.forEach(value => isLowercase(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -2294,11 +2295,11 @@ describe("IsMongoId", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isMongoId(value).should.be.true); + validValues.forEach(value => isMongoId(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isMongoId(value).should.be.false); + invalidValues.forEach(value => isMongoId(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -2341,11 +2342,11 @@ describe("IsMultibyte", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isMultibyte(value).should.be.true); + validValues.forEach(value => isMultibyte(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isMultibyte(value).should.be.false); + invalidValues.forEach(value => isMultibyte(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -2385,11 +2386,11 @@ describe("IsSurrogatePair", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isSurrogatePair(value).should.be.true); + validValues.forEach(value => isSurrogatePair(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isSurrogatePair(value).should.be.false); + invalidValues.forEach(value => isSurrogatePair(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -2484,19 +2485,19 @@ describe("IsUrl", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isURL(value).should.be.true); + validValues.forEach(value => isURL(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isURL(value).should.be.false); + invalidValues.forEach(value => isURL(value).should.be.false); }); it("should fail on localhost without require_tld option", function () { - validator.isURL("http://localhost:3000/").should.be.false; + isURL("http://localhost:3000/").should.be.false; }); it("should pass on localhost with require_tld option", function () { - validator.isURL("http://localhost:3000/", { require_tld: false }).should.be.true; + isURL("http://localhost:3000/", { require_tld: false }).should.be.true; }); it("should return error object with proper data", function(done) { @@ -2540,11 +2541,11 @@ describe("IsUUID", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isUUID(value).should.be.true); + validValues.forEach(value => isUUID(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isUUID(value).should.be.false); + invalidValues.forEach(value => isUUID(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -2585,11 +2586,11 @@ describe("IsUUID v3", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isUUID(value, "3").should.be.true); + validValues.forEach(value => isUUID(value, "3").should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isUUID(value, "3").should.be.false); + invalidValues.forEach(value => isUUID(value, "3").should.be.false); }); it("should return error object with proper data", function(done) { @@ -2633,11 +2634,11 @@ describe("IsUUID v4", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isUUID(value, "4").should.be.true); + validValues.forEach(value => isUUID(value, "4").should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isUUID(value, "4").should.be.false); + invalidValues.forEach(value => isUUID(value, "4").should.be.false); }); it("should return error object with proper data", function(done) { @@ -2681,11 +2682,11 @@ describe("IsUUID v5", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isUUID(value, "5").should.be.true); + validValues.forEach(value => isUUID(value, "5").should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isUUID(value, "5").should.be.false); + invalidValues.forEach(value => isUUID(value, "5").should.be.false); }); it("should return error object with proper data", function(done) { @@ -2725,11 +2726,11 @@ describe("IsUppercase", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isUppercase(value).should.be.true); + validValues.forEach(value => isUppercase(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isUppercase(value).should.be.false); + invalidValues.forEach(value => isUppercase(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -2761,11 +2762,11 @@ describe("Length", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.length(value, constraint1, constraint2).should.be.true); + validValues.forEach(value => length(value, constraint1, constraint2).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.length(value, constraint1, constraint2).should.be.false); + invalidValues.forEach(value => length(value, constraint1, constraint2).should.be.false); }); it("should return error object with proper data", function(done) { @@ -2802,11 +2803,11 @@ describe("MinLength", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.minLength(value, constraint1).should.be.true); + validValues.forEach(value => minLength(value, constraint1).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.minLength(value, constraint1).should.be.false); + invalidValues.forEach(value => minLength(value, constraint1).should.be.false); }); it("should return error object with proper data", function(done) { @@ -2837,11 +2838,11 @@ describe("MaxLength", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.maxLength(value, constraint1).should.be.true); + validValues.forEach(value => maxLength(value, constraint1).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.maxLength(value, constraint1).should.be.false); + invalidValues.forEach(value => maxLength(value, constraint1).should.be.false); }); it("should return error object with proper data", function(done) { @@ -2872,11 +2873,11 @@ describe("Matches", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.matches(value, constraint).should.be.true); + validValues.forEach(value => matches(value, constraint).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.matches(value, constraint).should.be.false); + invalidValues.forEach(value => matches(value, constraint).should.be.false); }); it("should return error object with proper data", function(done) { @@ -2911,6 +2912,57 @@ describe("IsMilitaryTime", function() { }); +describe("isMobilePhone", function() { + describe("with region", function() { + const validValues = [ + "01517551023", "0151 755 10 23", + "+491517551023", "+49 151 755 10 23", + "+49 (0) 1517551023", "+49 151 755 10 23", + ]; + const invalidValues = [undefined, null, "asdf", "1"]; + + class MyClass { + @IsMobilePhone("de-DE") + someProperty: string; + } + + it("should not fail if validator.validate said that its valid", function(done) { + checkValidValues(new MyClass(), validValues, done); + }); + + it("should fail if validator.validate said that its invalid", function(done) { + checkInvalidValues(new MyClass(), invalidValues, done); + }); + }); + + describe("no region", function() { + const validValues = [ + "+491517551023", "+49 151 755 10 23", + "+49 (0) 1517551023", "+49 151 755 10 23" + ]; + const invalidValues = [ + // most numbers are valid in any of the supported locales.. + // so choosing failing fixtures is hard. + "12345678901234567894654321", + undefined, null, "asdf", "1" + ]; + + class MyClass { + @IsMobilePhone("any") + someProperty: string; + } + + it("should not fail if validator.validate said that its valid", function(done) { + checkValidValues(new MyClass(), validValues, done); + }); + + it("should fail if validator.validate said that its invalid", function(done) { + checkInvalidValues(new MyClass(), invalidValues, done); + }); + }); +}); + + describe("isPhoneNumber", function() { describe("with region", function() { const validValues = [ diff --git a/test/functional/validation-options.spec.ts b/test/functional/validation-options.spec.ts index 93f6512657..ea662829ee 100644 --- a/test/functional/validation-options.spec.ts +++ b/test/functional/validation-options.spec.ts @@ -1,10 +1,12 @@ import "es6-shim"; -import {Matches, MinLength, ValidateNested} from "../../src/decorator/decorators"; +import {ValidateNested} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; import {ValidationError} from "../../src/validation/ValidationError"; import {should, use} from "chai"; import * as chaiAsPromised from "chai-as-promised"; import {Contains} from "../../src/decorator/Contains"; +import {MinLength} from "../../src/decorator/MinLength"; +import {Matches} from "../../src/decorator/Matches"; should(); use(chaiAsPromised); From dec640d01c74aa9f32117040517adb0770b07da6 Mon Sep 17 00:00:00 2001 From: Christoph Linder Date: Wed, 21 Nov 2018 01:04:24 +0100 Subject: [PATCH 12/12] Smaller bundle - last bunch of migrations, removed now unused defaultValidations/validateValueByMetadata --- README.md | 1953 +++++++++-------- sample/sample1-simple-validation/Post.ts | 20 +- sample/sample2-using-groups/Post.ts | 12 +- sample/sample3-nested-objects/Post.ts | 4 +- sample/sample3-nested-objects/Tag.ts | 2 +- .../BaseContent.ts | 2 +- sample/sample7-inheritance-support/Post.ts | 8 +- src/decorator/array/ArrayContains.ts | 30 + src/decorator/array/ArrayMaxSize.ts | 30 + src/decorator/array/ArrayMinSize.ts | 30 + src/decorator/array/ArrayNotContains.ts | 30 + src/decorator/array/ArrayNotEmpty.ts | 29 + src/decorator/array/ArrayUnique.ts | 30 + src/decorator/{ => common}/Equals.ts | 4 +- src/decorator/{ => common}/IsEmpty.ts | 4 +- src/decorator/{ => common}/IsIn.ts | 4 +- src/decorator/{ => common}/IsNotEmpty.ts | 4 +- src/decorator/{ => common}/IsNotIn.ts | 4 +- src/decorator/{ => common}/NotEquals.ts | 4 +- src/decorator/{ => date}/MaxDate.ts | 4 +- src/decorator/{ => date}/MinDate.ts | 4 +- src/decorator/decorators.ts | 201 -- src/decorator/{ => number}/IsDivisibleBy.ts | 4 +- src/decorator/{ => number}/IsNegative.ts | 4 +- src/decorator/{ => number}/IsPositive.ts | 4 +- src/decorator/{ => number}/Max.ts | 4 +- src/decorator/{ => number}/Min.ts | 4 +- .../{ => string-as-type}/IsBooleanString.ts | 4 +- .../{ => string-as-type}/IsDateString.ts | 6 +- .../{ => string-as-type}/IsNumberString.ts | 4 +- src/decorator/{ => string}/Contains.ts | 4 +- src/decorator/{ => string}/IsAlpha.ts | 4 +- src/decorator/{ => string}/IsAlphanumeric.ts | 4 +- src/decorator/{ => string}/IsAscii.ts | 4 +- src/decorator/{ => string}/IsBase64.ts | 4 +- src/decorator/{ => string}/IsByteLength.ts | 4 +- src/decorator/{ => string}/IsCreditCard.ts | 4 +- src/decorator/{ => string}/IsCurrency.ts | 4 +- src/decorator/{ => string}/IsEmail.ts | 4 +- src/decorator/{ => string}/IsFQDN.ts | 4 +- src/decorator/{ => string}/IsFullWidth.ts | 4 +- src/decorator/{ => string}/IsHalfWidth.ts | 4 +- src/decorator/{ => string}/IsHexColor.ts | 4 +- src/decorator/{ => string}/IsHexadecimal.ts | 4 +- src/decorator/{ => string}/IsIP.ts | 4 +- src/decorator/{ => string}/IsISBN.ts | 4 +- src/decorator/{ => string}/IsISIN.ts | 4 +- src/decorator/{ => string}/IsISO8601.ts | 4 +- src/decorator/{ => string}/IsJSON.ts | 4 +- src/decorator/{ => string}/IsLowercase.ts | 4 +- src/decorator/{ => string}/IsMilitaryTime.ts | 4 +- src/decorator/{ => string}/IsMobilePhone.ts | 4 +- src/decorator/{ => string}/IsMongoId.ts | 4 +- src/decorator/{ => string}/IsMultibyte.ts | 4 +- src/decorator/{ => string}/IsPhoneNumber.ts | 4 +- src/decorator/{ => string}/IsSurrogatePair.ts | 4 +- src/decorator/{ => string}/IsUUID.ts | 4 +- src/decorator/{ => string}/IsUppercase.ts | 4 +- src/decorator/{ => string}/IsUrl.ts | 4 +- src/decorator/{ => string}/IsVariableWidth.ts | 4 +- src/decorator/{ => string}/Length.ts | 4 +- src/decorator/{ => string}/Matches.ts | 4 +- src/decorator/{ => string}/MaxLength.ts | 4 +- src/decorator/{ => string}/MinLength.ts | 4 +- src/decorator/{ => string}/NotContains.ts | 4 +- src/decorator/system/Allow.ts | 22 + src/decorator/system/IsDefined.ts | 27 + src/decorator/system/IsOptional.ts | 24 + src/decorator/system/ValidateIf.ts | 22 + src/decorator/system/ValidateNested.ts | 25 + src/decorator/{ => typechecker}/IsArray.ts | 4 +- src/decorator/{ => typechecker}/IsBoolean.ts | 4 +- src/decorator/{ => typechecker}/IsDate.ts | 4 +- src/decorator/{ => typechecker}/IsEnum.ts | 4 +- src/decorator/typechecker/IsInstance.ts | 33 + src/decorator/{ => typechecker}/IsInt.ts | 4 +- src/decorator/{ => typechecker}/IsNumber.ts | 4 +- src/decorator/{ => typechecker}/IsString.ts | 4 +- .../ValidationSchemaToMetadataTransformer.ts | 4 - src/validation/ValidationExecutor.ts | 38 +- src/validation/ValidationTypes.ts | 63 - src/validation/Validator.ts | 149 +- .../functional/conditional-validation.spec.ts | 24 +- test/functional/inherited-validation.spec.ts | 4 +- test/functional/nested-validation.spec.ts | 7 +- test/functional/reject-validation.spec.ts | 2 +- test/functional/sync-validation.ts | 2 +- test/functional/validation-error.spec.ts | 128 +- ...alidation-functions-and-decorators.spec.ts | 166 +- test/functional/validation-options.spec.ts | 8 +- test/functional/validator-options.spec.ts | 2 +- test/functional/whitelist-validation.spec.ts | 5 +- 92 files changed, 1657 insertions(+), 1713 deletions(-) create mode 100644 src/decorator/array/ArrayContains.ts create mode 100644 src/decorator/array/ArrayMaxSize.ts create mode 100644 src/decorator/array/ArrayMinSize.ts create mode 100644 src/decorator/array/ArrayNotContains.ts create mode 100644 src/decorator/array/ArrayNotEmpty.ts create mode 100644 src/decorator/array/ArrayUnique.ts rename src/decorator/{ => common}/Equals.ts (85%) rename src/decorator/{ => common}/IsEmpty.ts (84%) rename src/decorator/{ => common}/IsIn.ts (87%) rename src/decorator/{ => common}/IsNotEmpty.ts (85%) rename src/decorator/{ => common}/IsNotIn.ts (88%) rename src/decorator/{ => common}/NotEquals.ts (86%) rename src/decorator/{ => date}/MaxDate.ts (86%) rename src/decorator/{ => date}/MinDate.ts (86%) delete mode 100644 src/decorator/decorators.ts rename src/decorator/{ => number}/IsDivisibleBy.ts (88%) rename src/decorator/{ => number}/IsNegative.ts (84%) rename src/decorator/{ => number}/IsPositive.ts (84%) rename src/decorator/{ => number}/Max.ts (87%) rename src/decorator/{ => number}/Min.ts (87%) rename src/decorator/{ => string-as-type}/IsBooleanString.ts (87%) rename src/decorator/{ => string-as-type}/IsDateString.ts (80%) rename src/decorator/{ => string-as-type}/IsNumberString.ts (87%) rename src/decorator/{ => string}/Contains.ts (88%) rename src/decorator/{ => string}/IsAlpha.ts (87%) rename src/decorator/{ => string}/IsAlphanumeric.ts (88%) rename src/decorator/{ => string}/IsAscii.ts (86%) rename src/decorator/{ => string}/IsBase64.ts (86%) rename src/decorator/{ => string}/IsByteLength.ts (89%) rename src/decorator/{ => string}/IsCreditCard.ts (87%) rename src/decorator/{ => string}/IsCurrency.ts (89%) rename src/decorator/{ => string}/IsEmail.ts (88%) rename src/decorator/{ => string}/IsFQDN.ts (89%) rename src/decorator/{ => string}/IsFullWidth.ts (88%) rename src/decorator/{ => string}/IsHalfWidth.ts (88%) rename src/decorator/{ => string}/IsHexColor.ts (87%) rename src/decorator/{ => string}/IsHexadecimal.ts (87%) rename src/decorator/{ => string}/IsIP.ts (89%) rename src/decorator/{ => string}/IsISBN.ts (89%) rename src/decorator/{ => string}/IsISIN.ts (87%) rename src/decorator/{ => string}/IsISO8601.ts (87%) rename src/decorator/{ => string}/IsJSON.ts (86%) rename src/decorator/{ => string}/IsLowercase.ts (86%) rename src/decorator/{ => string}/IsMilitaryTime.ts (88%) rename src/decorator/{ => string}/IsMobilePhone.ts (91%) rename src/decorator/{ => string}/IsMongoId.ts (87%) rename src/decorator/{ => string}/IsMultibyte.ts (87%) rename src/decorator/{ => string}/IsPhoneNumber.ts (94%) rename src/decorator/{ => string}/IsSurrogatePair.ts (88%) rename src/decorator/{ => string}/IsUUID.ts (88%) rename src/decorator/{ => string}/IsUppercase.ts (86%) rename src/decorator/{ => string}/IsUrl.ts (88%) rename src/decorator/{ => string}/IsVariableWidth.ts (88%) rename src/decorator/{ => string}/Length.ts (93%) rename src/decorator/{ => string}/Matches.ts (93%) rename src/decorator/{ => string}/MaxLength.ts (89%) rename src/decorator/{ => string}/MinLength.ts (89%) rename src/decorator/{ => string}/NotContains.ts (88%) create mode 100644 src/decorator/system/Allow.ts create mode 100644 src/decorator/system/IsDefined.ts create mode 100644 src/decorator/system/IsOptional.ts create mode 100644 src/decorator/system/ValidateIf.ts create mode 100644 src/decorator/system/ValidateNested.ts rename src/decorator/{ => typechecker}/IsArray.ts (82%) rename src/decorator/{ => typechecker}/IsBoolean.ts (84%) rename src/decorator/{ => typechecker}/IsDate.ts (83%) rename src/decorator/{ => typechecker}/IsEnum.ts (86%) create mode 100644 src/decorator/typechecker/IsInstance.ts rename src/decorator/{ => typechecker}/IsInt.ts (82%) rename src/decorator/{ => typechecker}/IsNumber.ts (89%) rename src/decorator/{ => typechecker}/IsString.ts (83%) diff --git a/README.md b/README.md index f9a33bf30c..11446b8ea8 100644 --- a/README.md +++ b/README.md @@ -1,960 +1,993 @@ -# class-validator - -[![Build Status](https://travis-ci.org/typestack/class-validator.svg?branch=master)](https://travis-ci.org/typestack/class-validator) -[![npm version](https://badge.fury.io/js/class-validator.svg)](https://badge.fury.io/js/class-validator) -[![install size](https://packagephobia.now.sh/badge?p=class-validator)](https://packagephobia.now.sh/result?p=class-validator) -[![Join the chat at https://gitter.im/typestack/class-validator](https://badges.gitter.im/typestack/class-validator.svg)](https://gitter.im/typestack/class-validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -Allows use of decorator and non-decorator based validation. -Internally uses [validator.js][1] to perform validation. -Class-validator works on both browser and node.js platforms. - -## Table of Contents - - * [Installation](#installation) - - [Old versions of node.js/browser](#old-versions-of-nodejsbrowser) - - [Using in browser](#using-in-browser) - * [Usage](#usage) - + [Validation errors](#validation-errors) - + [Validation messages](#validation-messages) - + [Validating arrays](#validating-arrays) - + [Validating nested objects](#validating-nested-objects) - + [Inheriting Validation decorators](#inheriting-validation-decorators) - + [Conditional validation](#conditional-validation) - + [Whitelisting](#whitelisting) - + [Passing context to decorators](#passing-context-to-decorators) - + [Skipping missing properties](#skipping-missing-properties) - + [Validation groups](#validation-groups) - + [Custom validation classes](#custom-validation-classes) - + [Custom validation decorators](#custom-validation-decorators) - + [Using service container](#using-service-container) - + [Synchronous validation](#synchronous-validation) - + [Manual validation](#manual-validation) - + [Validation decorators](#validation-decorators) - + [Defining validation schema without decorators](#defining-validation-schema-without-decorators) - + [Validating plain objects](#validating-plain-objects) - * [Samples](#samples) - * [Extensions](#extensions) - * [Release notes](#release-notes) - -## Installation - -``` -npm install class-validator --save -``` - -> Note: Please use at least npm@6 when using class-validator as from npm@6 the dependency tree is flatterned what is good for us. - -## Usage - -Create your class and put some validation decorators on the properties you want to validate: - -```typescript -import {validate, Contains, IsInt, Length, IsEmail, IsFQDN, IsDate, Min, Max} from "class-validator"; - -export class Post { - - @Length(10, 20) - title: string; - - @Contains("hello") - text: string; - - @IsInt() - @Min(0) - @Max(10) - rating: number; - - @IsEmail() - email: string; - - @IsFQDN() - site: string; - - @IsDate() - createDate: Date; - -} - -let post = new Post(); -post.title = "Hello"; // should not pass -post.text = "this is a great post about hell world"; // should not pass -post.rating = 11; // should not pass -post.email = "google.com"; // should not pass -post.site = "googlecom"; // should not pass - -validate(post).then(errors => { // errors is an array of validation errors - if (errors.length > 0) { - console.log("validation failed. errors: ", errors); - } else { - console.log("validation succeed"); - } -}); -``` - -### Passing options - -The `validate` function optionally expects a `ValidatorOptions` object as a second parameter. - -```ts -export interface ValidatorOptions { - - skipMissingProperties?: boolean; - whitelist?: boolean; - forbidNonWhitelisted?: boolean; - groups?: string[]; - dismissDefaultMessages?: boolean; - validationError?: { - target?: boolean; - value?: boolean; - }; - - forbidUnknownValues?: boolean; -} -``` - -> It's highly advised to enable on `forbidUnknownValues` what prevent unknown objects to pass validation. - -## Validation errors - -`validate` method returns you an array of `ValidationError` objects. Each `ValidationError` is: - -```typescript -{ - target: Object; // Object that was validated. - property: string; // Object's property that haven't pass validation. - value: any; // Value that haven't pass a validation. - constraints?: { // Constraints that failed validation with error messages. - [type: string]: string; - }; - children?: ValidationError[]; // Contains all nested validation errors of the property -} -``` - -In our case, when we validated a Post object, we have such array of ValidationErrors: - -```typescript -[{ - target: /* post object */, - property: "title", - value: "Hello", - constraints: { - length: "$property must be longer than or equal to 10 characters" - } -}, { - target: /* post object */, - property: "text", - value: "this is a great post about hell world", - constraints: { - contains: "text must contain a hello string" - } -}, -// and other errors -] -``` - -If you don't want a `target` to be exposed in validation errors, there is a special option when you use validator: - -```typescript -validator.validate(post, { validationError: { target: false } }); -``` - -This is especially useful when you send errors back over http, and you most probably don't want to expose -the whole target object. - -## Validation messages - -You can specify validation message in the decorator options and that message will be returned in `ValidationError` -returned by `validate` method in the case that validation for this field fails. - -```typescript -import {MinLength, MaxLength} from "class-validator"; - -export class Post { - - @MinLength(10, { - message: "Title is too short" - }) - @MaxLength(50, { - message: "Title is too long" - }) - title: string; -} -``` - -There are few special tokens you can use in your messages: -* `$value` - the value that is being validated -* `$property` - name of the object's property being validated -* `$target` - name of the object's class being validated -* `$constraint1`, `$constraint2`, ... `$constraintN` - constraints defined by specific validation type - -Example of usage: - -```typescript -import {MinLength, MaxLength} from "class-validator"; - -export class Post { - - @MinLength(10, { // here, $constraint1 will be replaced with "10", and $value with actual supplied value - message: "Title is too short. Minimal length is $constraint1 characters, but actual is $value" - }) - @MaxLength(50, { // here, $constraint1 will be replaced with "50", and $value with actual supplied value - message: "Title is too long. Maximal length is $constraint1 characters, but actual is $value" - }) - title: string; -} -``` - -Also you can provide a function, that returns a message. This way allows to create more granular messages: - -```typescript -import {MinLength, MaxLength, ValidationArguments} from "class-validator"; - -export class Post { - - @MinLength(10, { - message: (args: ValidationArguments) => { - if (args.value.length === 1) { - return "Too short, minimum length is 1 character"; - } else { - return "Too short, minimum length is " + args.constraints[0] + " characters"; - } - } - }) - title: string; -} -``` - -Message function accepts `ValidationArguments` which contains following information: -* `value` - the value that is being validated -* `constraints` - array of constraints defined by specific validation type -* `targetName` - name of the object's class being validated -* `object` - object that is being validated -* `property` - name of the object's property being validated - -## Validating arrays - -If your field is an array and you want to perform validation of each item in the array you must specify a -special `each: true` decorator option: - -```typescript -import {MinLength, MaxLength} from "class-validator"; - -export class Post { - - @MaxLength(20, { - each: true - }) - tags: string[]; -} -``` - -This will validate each item in `post.tags` array. - -## Validating nested objects - -If your object contains nested objects and you want the validator to perform their validation too, then you need to -use the `@ValidateNested()` decorator: - -```typescript -import {ValidateNested} from "class-validator"; - -export class Post { - - @ValidateNested() - user: User; - -} -``` - -## Inheriting Validation decorators - -When you define a subclass which extends from another one, the subclass will automatically inherit the parent's decorators. If a property is redefined in the descendant class decorators will be applied on it both from that and the base class. - -```typescript -import {validate} from "class-validator"; - -class BaseContent { - - @IsEmail() - email: string; - - @IsString() - password: string; -} - -class User extends BaseContent { - - @MinLength(10) - @MaxLength(20) - name: string; - - @Contains("hello") - welcome: string; - - @MinLength(20) - password: string; / -} - -let user = new User(); - -user.email = "invalid email"; // inherited property -user.password = "too short" // password wil be validated not only against IsString, but against MinLength as well -user.name = "not valid"; -user.welcome = "helo"; - -validate(user).then(errors => { - // ... -}); // it will return errors for email, title and text properties - -``` - -## Conditional validation - -The conditional validation decorator (`@ValidateIf`) can be used to ignore the validators on a property when the provided condition function returns false. The condition function takes the object being validated and must return a `boolean`. - -```typescript -import {ValidateIf, IsNotEmpty} from "class-validator"; - -export class Post { - otherProperty:string; - - @ValidateIf(o => o.otherProperty === "value") - @IsNotEmpty() - example:string; -} -``` - -In the example above, the validation rules applied to `example` won't be run unless the object's `otherProperty` is `"value"`. - -Note that when the condition is false all validation decorators are ignored, including `isDefined`. - -## Whitelisting - -Even if your object is an instance of a validation class it can contain additional properties that are not defined. -If you do not want to have such properties on your object, pass special flag to `validate` method: - -```typescript -import {validate} from "class-validator"; -// ... -validate(post, { whitelist: true }); -``` - -This will strip all properties that don't have any decorators. If no other decorator is suitable for your property, -you can use @Allow decorator: - -```typescript -import {validate, Allow, Min} from "class-validator"; - -export class Post { - - @Allow() - title: string; - - @Min(0) - views: number; - - nonWhitelistedProperty: number; -} - -let post = new Post(); -post.title = 'Hello world!'; -post.views = 420; - -post.nonWhitelistedProperty = 69; -(post as any).anotherNonWhitelistedProperty = "something"; - -validate(post).then(errors => { - // post.nonWhitelistedProperty is not defined - // (post as any).anotherNonWhitelistedProperty is not defined - ... -}); -```` - -If you would rather to have an error thrown when any non-whitelisted properties are present, pass another flag to -`validate` method: - -```typescript -import {validate} from "class-validator"; -// ... -validate(post, { whitelist: true, forbidNonWhitelisted: true }); -``` - -## Passing context to decorators - -It's possible to pass a custom object to decorators which will be accessible on the `ValidationError` instance of the property if validation failed. - -```ts -import { validate } from 'class-validator'; - -class MyClass { - @MinLength(32, { - message: "EIC code must be at least 32 charatcers", - context: { - errorCode: 1003, - developerNote: "The validated string must contain 32 or more characters." - } - }) - eicCode: string; -} - -const model = new MyClass(); - -validate(model).then(errors => { - //errors[0].contexts['minLength'].errorCode === 1003 -}); -``` - -## Skipping missing properties - -Sometimes you may want to skip validation of the properties that does not exist in the validating object. This is -usually desirable when you want to update some parts of the object, and want to validate only updated parts, -but skip everything else, e.g. skip missing properties. -In such situations you will need to pass a special flag to `validate` method: - -```typescript -import {validate} from "class-validator"; -// ... -validate(post, { skipMissingProperties: true }); -``` - -When skipping missing properties, sometimes you want not to skip all missing properties, some of them maybe required -for you, even if skipMissingProperties is set to true. For such cases you should use `@IsDefined()` decorator. -`@IsDefined()` is the only decorator that ignores `skipMissingProperties` option. - -## Validation groups - -In different situations you may want to use different validation schemas of the same object. - In such cases you can use validation groups. - -```typescript -import {validate, Min, Length} from "class-validator"; - -export class User { - - @Min(12, { - groups: ["registration"] - }) - age: number; - - @Length(2, 20, { - groups: ["registration", "admin"] - }) - name: string; -} - -let user = new User(); -user.age = 10; -user.name = "Alex"; - -validate(user, { - groups: ["registration"] -}); // this will not pass validation - -validate(user, { - groups: ["admin"] -}); // this will pass validation - -validate(user, { - groups: ["registration", "admin"] -}); // this will not pass validation - -validate(user, { - groups: undefined // the default -}); // this will not pass validation since all properties get validated regardless of their groups - -validate(user, { - groups: [] -}); // this will not pass validation, (equivalent to 'groups: undefined', see above) -``` - -There is also a special flag `always: true` in validation options that you can use. This flag says that this validation -must be applied always no matter which group is used. - -## Custom validation classes - -If you have custom validation logic you can create a *Constraint class*: - -1. First create a file, lets say `CustomTextLength.ts`, and define a new class: - - ```typescript - import {ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments} from "class-validator"; - - @ValidatorConstraint({ name: "customText", async: false }) - export class CustomTextLength implements ValidatorConstraintInterface { - - validate(text: string, args: ValidationArguments) { - return text.length > 1 && text.length < 10; // for async validations you must return a Promise here - } - - defaultMessage(args: ValidationArguments) { // here you can provide default error message if validation failed - return "Text ($value) is too short or too long!"; - } - - } - ``` - - We marked our class with `@ValidatorConstraint` decorator. - You can also supply a validation constraint name - this name will be used as "error type" in ValidationError. - If you will not supply a constraint name - it will be auto-generated. - - Our class must implement `ValidatorConstraintInterface` interface and its `validate` method, - which defines validation logic. If validation succeeds, method returns true, otherwise false. - Custom validator can be asynchronous, if you want to perform validation after some asynchronous - operations, simply return a promise with boolean inside in `validate` method. - - Also we defined optional method `defaultMessage` which defines a default error message, - in the case that the decorator's implementation doesn't set an error message. - - -2. Then you can use your new validation constraint in your class: - - ```typescript - import {Validate} from "class-validator"; - import {CustomTextLength} from "./CustomTextLength"; - - export class Post { - - @Validate(CustomTextLength, { - message: "Title is too short or long!" - }) - title: string; - - } - ``` - - Here we set our newly created `CustomTextLength` validation constraint for `Post.title`. - -3. And use validator as usual: - - ```typescript - import {validate} from "class-validator"; - - validate(post).then(errors => { - // ... - }); - ``` - -You can also pass constraints to your validator, like this: - -```typescript -import {Validate} from "class-validator"; -import {CustomTextLength} from "./CustomTextLength"; - -export class Post { - - @Validate(CustomTextLength, [3, 20], { - message: "Wrong post title" - }) - title: string; - -} -``` - -And use them from `validationArguments` object: - -```typescript -import {ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface} from "class-validator"; - -@ValidatorConstraint() -export class CustomTextLength implements ValidatorConstraintInterface { - - validate(text: string, validationArguments: ValidationArguments) { - return text.length > validationArguments.constraints[0] && text.length < validationArguments.constraints[1]; - } - -} -``` - -## Custom validation decorators - -You can also create a custom decorators. Its the most elegant way of using a custom validations. -Lets create a decorator called `@IsLongerThan`: - -1. Create a decorator itself: - - ```typescript - import {registerDecorator, ValidationOptions, ValidationArguments} from "class-validator"; - - export function IsLongerThan(property: string, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - registerDecorator({ - name: "isLongerThan", - target: object.constructor, - propertyName: propertyName, - constraints: [property], - options: validationOptions, - validator: { - validate(value: any, args: ValidationArguments) { - const [relatedPropertyName] = args.constraints; - const relatedValue = (args.object as any)[relatedPropertyName]; - return typeof value === "string" && - typeof relatedValue === "string" && - value.length > relatedValue.length; // you can return a Promise here as well, if you want to make async validation - } - } - }); - }; - } - ``` - -2. Put it to use: - - ```typescript - import {IsLongerThan} from "./IsLongerThan"; - - export class Post { - - title: string; - - @IsLongerThan("title", { - /* you can also use additional validation options, like "groups" in your custom validation decorators. "each" is not supported */ - message: "Text must be longer than the title" - }) - text: string; - - } - ``` - -In your custom decorators you can also use `ValidationConstraint`. -Lets create another custom validation decorator called `IsUserAlreadyExist`: - -1. Create a ValidationConstraint and decorator: - - ```typescript - import {registerDecorator, ValidationOptions, ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments} from "class-validator"; - - @ValidatorConstraint({ async: true }) - export class IsUserAlreadyExistConstraint implements ValidatorConstraintInterface { - - validate(userName: any, args: ValidationArguments) { - return UserRepository.findOneByName(userName).then(user => { - if (user) return false; - return true; - }); - } - - } - - export function IsUserAlreadyExist(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - registerDecorator({ - target: object.constructor, - propertyName: propertyName, - options: validationOptions, - constraints: [], - validator: IsUserAlreadyExistConstraint - }); - }; - } - ``` - - note that we marked our constraint that it will by async by adding `{ async: true }` in validation options. - -2. And put it to use: - - ```typescript - import {IsUserAlreadyExist} from "./IsUserAlreadyExist"; - - export class User { - - @IsUserAlreadyExist({ - message: "User $value already exists. Choose another name." - }) - name: string; - - } - ``` - -## Using service container - -Validator supports service container in the case if want to inject dependencies into your custom validator constraint -classes. Here is example how to integrate it with [typedi][2]: - -```typescript -import {Container} from "typedi"; -import {useContainer, Validator} from "class-validator"; - -// do this somewhere in the global application level: -useContainer(Container); -let validator = Container.get(Validator); - -// now everywhere you can inject Validator class which will go from the container -// also you can inject classes using constructor injection into your custom ValidatorConstraint-s -``` - -## Synchronous validation - -If you want to perform a simple non async validation you can use `validateSync` method instead of regular `validate` - method. It has the same arguments as `validate` method. But note, this method **ignores** all async validations - you have. - -## Manual validation - -There are several method exist in the Validator that allows to perform non-decorator based validation: - -```typescript -import {Validator} from "class-validator"; - -// Validation methods -const validator = new Validator(); - -// common validation methods -validator.isDefined(value); // Checks if value is defined ("!==undefined"). -validator.equals(value, comparison); // Checks if value matches ("===") the comparison. -validator.notEquals(value, comparison); // Checks if value does not match ("!==") the comparison. -validator.isEmpty(value); // Checks if given value is empty (=== '', === null, === undefined). -validator.isNotEmpty(value); // Checks if given value is not empty (!== '', !== null, !== undefined). -validator.isIn(value, possibleValues); // Checks if given value is in a array of allowed values. -validator.isNotIn(value, possibleValues); // Checks if given value not in a array of allowed values. - -// type validation methods -validator.isBoolean(value); // Checks if a given value is a real boolean. -validator.isDate(value); // Checks if a given value is a real date. -validator.isString(value); // Checks if a given value is a real string. -validator.isArray(value); // Checks if a given value is an array. -validator.isNumber(value, options); // Checks if a given value is a real number. -validator.isInt(value); // Checks if value is an integer. -validator.isEnum(value, entity); // Checks if value is valid for a certain enum entity. - -// number validation methods -validator.isDivisibleBy(value, num); // Checks if value is a number that's divisible by another. -validator.isPositive(value); // Checks if the value is a positive number. -validator.isNegative(value); // Checks if the value is a negative number. -validator.min(num, min); // Checks if the first number is greater than or equal to the second. -validator.max(num, max); // Checks if the first number is less than or equal to the second. - -// date validation methods -validator.minDate(date, minDate); // Checks if the value is a date that's after the specified date. -validator.maxDate(date, minDate); // Checks if the value is a date that's before the specified date. - -// string-type validation methods -validator.isBooleanString(str); // Checks if a string is a boolean. -validator.isNumberString(str); // Checks if the string is numeric. - -// string validation methods -validator.contains(str, seed); // Checks if the string contains the seed. -validator.notContains(str, seed); // Checks if the string does not contain the seed. -validator.isAlpha(str); // Checks if the string contains only letters (a-zA-Z). -validator.isAlphanumeric(str); // Checks if the string contains only letters and numbers. -validator.isAscii(str); // Checks if the string contains ASCII chars only. -validator.isBase64(str); // Checks if a string is base64 encoded. -validator.isByteLength(str, min, max); // Checks if the string's length (in bytes) falls in a range. -validator.isCreditCard(str); // Checks if the string is a credit card. -validator.isCurrency(str, options); // Checks if the string is a valid currency amount. -validator.isEmail(str, options); // Checks if the string is an email. -validator.isFQDN(str, options); // Checks if the string is a fully qualified domain name (e.g. domain.com). -validator.isFullWidth(str); // Checks if the string contains any full-width chars. -validator.isHalfWidth(str); // Checks if the string contains any half-width chars. -validator.isVariableWidth(str); // Checks if the string contains variable-width chars. -validator.isHexColor(str); // Checks if the string is a hexadecimal color. -validator.isHexadecimal(str); // Checks if the string is a hexadecimal number. -validator.isIP(str, version); // Checks if the string is an IP (version 4 or 6). -validator.isISBN(str, version); // Checks if the string is an ISBN (version 10 or 13). -validator.isISIN(str); // Checks if the string is an ISIN (stock/security identifier). -validator.isISO8601(str); // Checks if the string is a valid ISO 8601 date. -validator.isJSON(str); // Checks if the string is valid JSON (note: uses JSON.parse). -validator.isLowercase(str); // Checks if the string is lowercase. -validator.isMobilePhone(str, locale); // Checks if the string is a mobile phone number. -validator.isPhoneNumber(str, region); // Checks if the string is a valid phone number. -validator.isMongoId(str); // Checks if the string is a valid hex-encoded representation of a MongoDB ObjectId. -validator.isMultibyte(str); // Checks if the string contains one or more multibyte chars. -validator.isSurrogatePair(str); // Checks if the string contains any surrogate pairs chars. -validator.isURL(str, options); // Checks if the string is an url. -validator.isUUID(str, version); // Checks if the string is a UUID (version 3, 4 or 5). -validator.isUppercase(str); // Checks if the string is uppercase. -validator.length(str, min, max); // Checks if the string's length falls in a range. -validator.minLength(str, min); // Checks if the string's length is not less than given number. -validator.maxLength(str, max); // Checks if the string's length is not more than given number. -validator.matches(str, pattern, modifiers); // Checks if string matches the pattern. Either matches('foo', /foo/i) or matches('foo', 'foo', 'i'). -validator.isMilitaryTime(str); // Checks if the string is a valid representation of military time in the format HH:MM. - -// array validation methods -validator.arrayContains(array, values); // Checks if array contains all values from the given array of values. -validator.arrayNotContains(array, values); // Checks if array does not contain any of the given values. -validator.arrayNotEmpty(array); // Checks if given array is not empty. -validator.arrayMinSize(array, min); // Checks if array's length is at least `min` number. -validator.arrayMaxSize(array, max); // Checks if array's length is as most `max` number. -validator.arrayUnique(array); // Checks if all array's values are unique. Comparison for objects is reference-based. - -// object validation methods -validator.isInstance(value, target); // Checks value is an instance of the target. -``` - -## Validation decorators - -| Decorator | Description | -|-------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------| -| **Common validation decorators** | -| `@IsDefined(value: any)` | Checks if value is defined (!== undefined, !== null). This is the only decorator that ignores skipMissingProperties option. | -| `@IsOptional()` | Checks if given value is empty (=== null, === undefined) and if so, ignores all the validators on the property. | -| `@Equals(comparison: any)` | Checks if value equals ("===") comparison. | -| `@NotEquals(comparison: any)` | Checks if value not equal ("!==") comparison. | -| `@IsEmpty()` | Checks if given value is empty (=== '', === null, === undefined). | -| `@IsNotEmpty()` | Checks if given value is not empty (!== '', !== null, !== undefined). | -| `@IsIn(values: any[])` | Checks if value is in a array of allowed values. | -| `@IsNotIn(values: any[])` | Checks if value is not in a array of disallowed values. | -| **Type validation decorators** | -| `@IsBoolean()` | Checks if a value is a boolean. | -| `@IsDate()` | Checks if the value is a date. | -| `@IsString()` | Checks if the string is a string. | -| `@IsNumber(options: IsNumberOptions)` | Checks if the value is a number. | -| `@IsInt()` | Checks if the value is an integer number. | -| `@IsArray()` | Checks if the value is an array | -| `@IsEnum(entity: object)` | Checks if the value is an valid enum | -| **Number validation decorators** | -| `@IsDivisibleBy(num: number)` | Checks if the value is a number that's divisible by another. | -| `@IsPositive()` | Checks if the value is a positive number. | -| `@IsNegative()` | Checks if the value is a negative number. | -| `@Min(min: number)` | Checks if the given number is greater than or equal to given number. | -| `@Max(max: number)` | Checks if the given number is less than or equal to given number. | -| **Date validation decorators** | -| `@MinDate(date: Date)` | Checks if the value is a date that's after the specified date. | -| `@MaxDate(date: Date)` | Checks if the value is a date that's before the specified date. | | -| **String-type validation decorators** | -| `@IsBooleanString()` | Checks if a string is a boolean (e.g. is "true" or "false"). | -| `@IsDateString()` | Checks if a string is a complete representation of a date (e.g. "2017-06-07T14:34:08.700Z", "2017-06-07T14:34:08.700 or "2017-06-07T14:34:08+04:00"). | -| `@IsNumberString()` | Checks if a string is a number. | -| **String validation decorators** | -| `@Contains(seed: string)` | Checks if the string contains the seed. | -| `@NotContains(seed: string)` | Checks if the string not contains the seed. | -| `@IsAlpha()` | Checks if the string contains only letters (a-zA-Z). | -| `@IsAlphanumeric()` | Checks if the string contains only letters and numbers. | -| `@IsAscii()` | Checks if the string contains ASCII chars only. | -| `@IsBase64()` | Checks if a string is base64 encoded. | -| `@IsByteLength(min: number, max?: number)` | Checks if the string's length (in bytes) falls in a range. | -| `@IsCreditCard()` | Checks if the string is a credit card. | -| `@IsCurrency(options?: IsCurrencyOptions)` | Checks if the string is a valid currency amount. | -| `@IsEmail(options?: IsEmailOptions)` | Checks if the string is an email. | -| `@IsFQDN(options?: IsFQDNOptions)` | Checks if the string is a fully qualified domain name (e.g. domain.com). | -| `@IsFullWidth()` | Checks if the string contains any full-width chars. | -| `@IsHalfWidth()` | Checks if the string contains any half-width chars. | -| `@IsVariableWidth()` | Checks if the string contains a mixture of full and half-width chars. | -| `@IsHexColor()` | Checks if the string is a hexadecimal color. | -| `@IsHexadecimal()` | Checks if the string is a hexadecimal number. | -| `@IsIP(version?: "4"\|"6")` | Checks if the string is an IP (version 4 or 6). | -| `@IsISBN(version?: "10"\|"13")` | Checks if the string is an ISBN (version 10 or 13). | -| `@IsISIN()` | Checks if the string is an ISIN (stock/security identifier). | -| `@IsISO8601()` | Checks if the string is a valid ISO 8601 date. | -| `@IsJSON()` | Checks if the string is valid JSON. | -| `@IsLowercase()` | Checks if the string is lowercase. | -| `@IsMobilePhone(locale: string)` | Checks if the string is a mobile phone number. | -| `@IsPhoneNumber(region: string)` | Checks if the string is a valid phone number. "region" accepts 2 characters uppercase country code (e.g. DE, US, CH).If users must enter the intl. prefix (e.g. +41), then you may pass "ZZ" or null as region. See [google-libphonenumber, metadata.js:countryCodeToRegionCodeMap on github](https://github.com/ruimarinho/google-libphonenumber/blob/1e46138878cff479aafe2ce62175c6c49cb58720/src/metadata.js#L33) | -| `@IsMongoId()` | Checks if the string is a valid hex-encoded representation of a MongoDB ObjectId. | -| `@IsMultibyte()` | Checks if the string contains one or more multibyte chars. | -| `@IsNumberString()` | Checks if the string is numeric. | -| `@IsSurrogatePair()` | Checks if the string contains any surrogate pairs chars. | -| `@IsUrl(options?: IsURLOptions)` | Checks if the string is an url. | -| `@IsUUID(version?: "3"\|"4"\|"5")` | Checks if the string is a UUID (version 3, 4 or 5). | -| `@IsUppercase()` | Checks if the string is uppercase. | -| `@Length(min: number, max?: number)` | Checks if the string's length falls in a range. | -| `@MinLength(min: number)` | Checks if the string's length is not less than given number. | -| `@MaxLength(max: number)` | Checks if the string's length is not more than given number. | -| `@Matches(pattern: RegExp, modifiers?: string)` | Checks if string matches the pattern. Either matches('foo', /foo/i) or matches('foo', 'foo', 'i'). -| `@IsMilitaryTime()` | Checks if the string is a valid representation of military time in the format HH:MM. | -| **Array validation decorators** | -| `@ArrayContains(values: any[])` | Checks if array contains all values from the given array of values. | -| `@ArrayNotContains(values: any[])` | Checks if array does not contain any of the given values. | -| `@ArrayNotEmpty()` | Checks if given array is not empty. | -| `@ArrayMinSize(min: number)` | Checks if array's length is as minimal this number. | -| `@ArrayMaxSize(max: number)` | Checks if array's length is as maximal this number. | -| `@ArrayUnique()` | Checks if all array's values are unique. Comparison for objects is reference-based. | -| **Object validation decorators** | -| `@IsInstance(value: any)` | Checks if the property is an instance of the passed value. | - **Other decorators** | -| `@Allow()` | Prevent stripping off the property when no other constraint is specified for it. | - -## Defining validation schema without decorators - -You can define your validation schemas without decorators: - -* you can define it in the separate object -* you can define it in the `.json` file - -This feature maybe useful in the cases if: - -* are using es5/es6 and don't have decorators available -* you don't have a classes, and instead using interfaces -* you don't want to use model at all -* you want to have a validation schema separate of your model -* you want beautiful json-schema based validation models -* you simply hate decorators - -Here is an example of using it: - -1. Create a schema object: - - ```typescript - import {ValidationSchema} from "class-validator"; - export let UserValidationSchema: ValidationSchema = { // using interface here is not required, its just for type-safety - name: "myUserSchema", // this is required, and must be unique - properties: { - firstName: [{ - type: "minLength", // validation type. All validation types are listed in ValidationTypes class. - constraints: [2] - }, { - type: "maxLength", - constraints: [20] - }], - lastName: [{ - type: "minLength", - constraints: [2] - }, { - type: "maxLength", - constraints: [20] - }], - email: [{ - type: "isEmail" - }] - } - }; - ``` - - Same schema can be provided in `.json` file, depend on your wish. - -2. Register your schema: - - ```typescript - import {registerSchema} from "class-validator"; - import {UserValidationSchema} from "./UserValidationSchema"; - registerSchema(schema); // if schema is in .json file, then you can simply do registerSchema(require("path-to-schema.json")); - ``` - - Better to put this code in a global place, maybe when you bootstrap your application, for example in `app.ts`. - -3. Validate your object using validation schema: - - ```typescript - import {validate} from "class-validator"; - const user = { firstName: "Johny", secondName: "Cage", email: "johny@cage.com" }; - validate("myUserSchema", user).then(errors => { - if (errors.length > 0) { - console.log("Validation failed: ", errors); - } else { - console.log("Validation succeed."); - } - }); - ``` - - That's it. Here `"myUserSchema"` is the name of our validation schema. - `validate` method will perform validation based on this schema - -## Validating plain objects -Due to nature of the decorators, the validated object has to be instantiated using `new Class()` syntax. If you have your class defined using class-validator decorators and you want to validate plain JS object (literal object or returned by JSON.parse), you need to transform it to the class instance (e.g. using [class-transformer](https://github.com/pleerock/class-transformer)) or just use the [class-transformer-validator](https://github.com/19majkel94/class-transformer-validator) extension which can do that for you. - -## Samples - -Take a look on samples in [./sample](https://github.com/pleerock/class-validator/tree/master/sample) for more examples of -usages. - -## Extensions -There are several extensions that simplify class-validator integration with other modules: -- [class-validator integration](https://github.com/19majkel94/class-transformer-validator) with [class-transformer](https://github.com/pleerock/class-transformer) - -## Release notes - -See information about breaking changes and release notes [here][3]. - -[1]: https://github.com/chriso/validator.js -[2]: https://github.com/pleerock/typedi -[3]: CHANGELOG.md +# class-validator + +[![Build Status](https://travis-ci.org/typestack/class-validator.svg?branch=master)](https://travis-ci.org/typestack/class-validator) +[![npm version](https://badge.fury.io/js/class-validator.svg)](https://badge.fury.io/js/class-validator) +[![install size](https://packagephobia.now.sh/badge?p=class-validator)](https://packagephobia.now.sh/result?p=class-validator) +[![Join the chat at https://gitter.im/typestack/class-validator](https://badges.gitter.im/typestack/class-validator.svg)](https://gitter.im/typestack/class-validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +Allows use of decorator and non-decorator based validation. +Internally uses [validator.js][1] to perform validation. +Class-validator works on both browser and node.js platforms. + +## Table of Contents + + * [Installation](#installation) + - [Old versions of node.js/browser](#old-versions-of-nodejsbrowser) + - [Using in browser](#using-in-browser) + * [Usage](#usage) + + [Validation errors](#validation-errors) + + [Validation messages](#validation-messages) + + [Validating arrays](#validating-arrays) + + [Validating nested objects](#validating-nested-objects) + + [Inheriting Validation decorators](#inheriting-validation-decorators) + + [Conditional validation](#conditional-validation) + + [Whitelisting](#whitelisting) + + [Passing context to decorators](#passing-context-to-decorators) + + [Skipping missing properties](#skipping-missing-properties) + + [Validation groups](#validation-groups) + + [Custom validation classes](#custom-validation-classes) + + [Custom validation decorators](#custom-validation-decorators) + + [Using service container](#using-service-container) + + [Synchronous validation](#synchronous-validation) + + [Manual validation](#manual-validation) + + [Validation decorators](#validation-decorators) + + [Defining validation schema without decorators](#defining-validation-schema-without-decorators) + + [Validating plain objects](#validating-plain-objects) + * [Samples](#samples) + * [Extensions](#extensions) + * [Release notes](#release-notes) + +## Installation + +``` +npm install class-validator --save +``` + +> Note: Please use at least npm@6 when using class-validator as from npm@6 the dependency tree is flatterned what is good for us. + +## Usage + +Create your class and put some validation decorators on the properties you want to validate: + +```typescript +import {validate} from "class-validator"; +import {Length} from "class-validator/decorator/string/Length"; +import {Contains} from "class-validator/decorator/string/Contains"; +import {IsInt} from "class-validator/decorator/typechecker/IsInt"; +import {Min} from "class-validator/decorator/number/Min"; +import {Max} from "class-validator/decorator/number/Max"; +import {IsEmail} from "class-validator/decorator/string/IsEmail"; +import {IsFQDN} from "class-validator/decorator/string/IsFQDN"; +import {IsDate} from "class-validator/decorator/typechecker/IsDate"; + +export class Post { + + @Length(10, 20) + title: string; + + @Contains("hello") + text: string; + + @IsInt() + @Min(0) + @Max(10) + rating: number; + + @IsEmail() + email: string; + + @IsFQDN() + site: string; + + @IsDate() + createDate: Date; + +} + +let post = new Post(); +post.title = "Hello"; // should not pass +post.text = "this is a great post about hell world"; // should not pass +post.rating = 11; // should not pass +post.email = "google.com"; // should not pass +post.site = "googlecom"; // should not pass + +validate(post).then(errors => { // errors is an array of validation errors + if (errors.length > 0) { + console.log("validation failed. errors: ", errors); + } else { + console.log("validation succeed"); + } +}); +``` + +### Passing options + +The `validate` function optionally expects a `ValidatorOptions` object as a second parameter. + +```ts +export interface ValidatorOptions { + + skipMissingProperties?: boolean; + whitelist?: boolean; + forbidNonWhitelisted?: boolean; + groups?: string[]; + dismissDefaultMessages?: boolean; + validationError?: { + target?: boolean; + value?: boolean; + }; + + forbidUnknownValues?: boolean; +} +``` + +> It's highly advised to enable on `forbidUnknownValues` what prevent unknown objects to pass validation. + +## Validation errors + +`validate` method returns you an array of `ValidationError` objects. Each `ValidationError` is: + +```typescript +{ + target: Object; // Object that was validated. + property: string; // Object's property that haven't pass validation. + value: any; // Value that haven't pass a validation. + constraints?: { // Constraints that failed validation with error messages. + [type: string]: string; + }; + children?: ValidationError[]; // Contains all nested validation errors of the property +} +``` + +In our case, when we validated a Post object, we have such array of ValidationErrors: + +```typescript +[{ + target: /* post object */, + property: "title", + value: "Hello", + constraints: { + length: "$property must be longer than or equal to 10 characters" + } +}, { + target: /* post object */, + property: "text", + value: "this is a great post about hell world", + constraints: { + contains: "text must contain a hello string" + } +}, +// and other errors +] +``` + +If you don't want a `target` to be exposed in validation errors, there is a special option when you use validator: + +```typescript +validator.validate(post, { validationError: { target: false } }); +``` + +This is especially useful when you send errors back over http, and you most probably don't want to expose +the whole target object. + +## Validation messages + +You can specify validation message in the decorator options and that message will be returned in `ValidationError` +returned by `validate` method in the case that validation for this field fails. + +```typescript +import {MaxLength} from "class-validator/decorator/string/MaxLength"; +import {MinLength} from "class-validator/decorator/string/MinLength"; + +export class Post { + + @MinLength(10, { + message: "Title is too short" + }) + @MaxLength(50, { + message: "Title is too long" + }) + title: string; +} +``` + +There are few special tokens you can use in your messages: +* `$value` - the value that is being validated +* `$property` - name of the object's property being validated +* `$target` - name of the object's class being validated +* `$constraint1`, `$constraint2`, ... `$constraintN` - constraints defined by specific validation type + +Example of usage: + +```typescript +import {MaxLength} from "class-validator/decorator/string/MaxLength"; +import {MinLength} from "class-validator/decorator/string/MinLength"; + +export class Post { + + @MinLength(10, { // here, $constraint1 will be replaced with "10", and $value with actual supplied value + message: "Title is too short. Minimal length is $constraint1 characters, but actual is $value" + }) + @MaxLength(50, { // here, $constraint1 will be replaced with "50", and $value with actual supplied value + message: "Title is too long. Maximal length is $constraint1 characters, but actual is $value" + }) + title: string; +} +``` + +Also you can provide a function, that returns a message. This way allows to create more granular messages: + +```typescript +import {MaxLength} from "class-validator/decorator/string/MaxLength"; +import {MinLength} from "class-validator/decorator/string/MinLength"; +import {ValidationArguments} from "class-validator/validation/ValidationArguments"; + +export class Post { + + @MinLength(10, { + message: (args: ValidationArguments) => { + if (args.value.length === 1) { + return "Too short, minimum length is 1 character"; + } else { + return "Too short, minimum length is " + args.constraints[0] + " characters"; + } + } + }) + title: string; +} +``` + +Message function accepts `ValidationArguments` which contains following information: +* `value` - the value that is being validated +* `constraints` - array of constraints defined by specific validation type +* `targetName` - name of the object's class being validated +* `object` - object that is being validated +* `property` - name of the object's property being validated + +## Validating arrays + +If your field is an array and you want to perform validation of each item in the array you must specify a +special `each: true` decorator option: + +```typescript +import {MaxLength} from "class-validator/decorator/string/MaxLength"; +import {MinLength} from "class-validator/decorator/string/MinLength"; + +export class Post { + + @MaxLength(20, { + each: true + }) + tags: string[]; +} +``` + +This will validate each item in `post.tags` array. + +## Validating nested objects + +If your object contains nested objects and you want the validator to perform their validation too, then you need to +use the `@ValidateNested()` decorator: + +```typescript +import {ValidateNested} from "class-validator/decorator/system/ValidateNested"; + +export class Post { + + @ValidateNested() + user: User; + +} +``` + +## Inheriting Validation decorators + +When you define a subclass which extends from another one, the subclass will automatically inherit the parent's decorators. If a property is redefined in the descendant class decorators will be applied on it both from that and the base class. + +```typescript +import {validate} from "class-validator"; + +class BaseContent { + + @IsEmail() + email: string; + + @IsString() + password: string; +} + +class User extends BaseContent { + + @MinLength(10) + @MaxLength(20) + name: string; + + @Contains("hello") + welcome: string; + + @MinLength(20) + password: string; / +} + +let user = new User(); + +user.email = "invalid email"; // inherited property +user.password = "too short" // password wil be validated not only against IsString, but against MinLength as well +user.name = "not valid"; +user.welcome = "helo"; + +validate(user).then(errors => { + // ... +}); // it will return errors for email, title and text properties + +``` + +## Conditional validation + +The conditional validation decorator (`@ValidateIf`) can be used to ignore the validators on a property when the provided condition function returns false. The condition function takes the object being validated and must return a `boolean`. + +```typescript +import {ValidateIf} from "class-validator/decorator/system/ValidateIf"; +import {IsNotEmpty} from "class-validator/decorator/common/IsNotEmpty"; + +export class Post { + otherProperty:string; + + @ValidateIf(o => o.otherProperty === "value") + @IsNotEmpty() + example:string; +} +``` + +In the example above, the validation rules applied to `example` won't be run unless the object's `otherProperty` is `"value"`. + +Note that when the condition is false all validation decorators are ignored, including `isDefined`. + +## Whitelisting + +Even if your object is an instance of a validation class it can contain additional properties that are not defined. +If you do not want to have such properties on your object, pass special flag to `validate` method: + +```typescript +import {validate} from "class-validator"; +// ... +validate(post, { whitelist: true }); +``` + +This will strip all properties that don't have any decorators. If no other decorator is suitable for your property, +you can use @Allow decorator: + +```typescript +import {Allow} from "class-validator/decorator/system/Allow"; +import {Min} from "class-validator/decorator/number/Min"; +import {validate} from "class-validator"; + +export class Post { + + @Allow() + title: string; + + @Min(0) + views: number; + + nonWhitelistedProperty: number; +} + +let post = new Post(); +post.title = 'Hello world!'; +post.views = 420; + +post.nonWhitelistedProperty = 69; +(post as any).anotherNonWhitelistedProperty = "something"; + +validate(post).then(errors => { + // post.nonWhitelistedProperty is not defined + // (post as any).anotherNonWhitelistedProperty is not defined + ... +}); +```` + +If you would rather to have an error thrown when any non-whitelisted properties are present, pass another flag to +`validate` method: + +```typescript +import {validate} from "class-validator"; +// ... +validate(post, { whitelist: true, forbidNonWhitelisted: true }); +``` + +## Passing context to decorators + +It's possible to pass a custom object to decorators which will be accessible on the `ValidationError` instance of the property if validation failed. + +```ts +import { validate } from 'class-validator'; + +class MyClass { + @MinLength(32, { + message: "EIC code must be at least 32 charatcers", + context: { + errorCode: 1003, + developerNote: "The validated string must contain 32 or more characters." + } + }) + eicCode: string; +} + +const model = new MyClass(); + +validate(model).then(errors => { + //errors[0].contexts['minLength'].errorCode === 1003 +}); +``` + +## Skipping missing properties + +Sometimes you may want to skip validation of the properties that does not exist in the validating object. This is +usually desirable when you want to update some parts of the object, and want to validate only updated parts, +but skip everything else, e.g. skip missing properties. +In such situations you will need to pass a special flag to `validate` method: + +```typescript +import {validate} from "class-validator"; +// ... +validate(post, { skipMissingProperties: true }); +``` + +When skipping missing properties, sometimes you want not to skip all missing properties, some of them maybe required +for you, even if skipMissingProperties is set to true. For such cases you should use `@IsDefined()` decorator. +`@IsDefined()` is the only decorator that ignores `skipMissingProperties` option. + +## Validation groups + +In different situations you may want to use different validation schemas of the same object. + In such cases you can use validation groups. + +```typescript +import {validate} from "class-validator"; +import {Length} from "class-validator/decorator/string/Length"; +import {Min} from "class-validator/decorator/number/Min"; + +export class User { + + @Min(12, { + groups: ["registration"] + }) + age: number; + + @Length(2, 20, { + groups: ["registration", "admin"] + }) + name: string; +} + +let user = new User(); +user.age = 10; +user.name = "Alex"; + +validate(user, { + groups: ["registration"] +}); // this will not pass validation + +validate(user, { + groups: ["admin"] +}); // this will pass validation + +validate(user, { + groups: ["registration", "admin"] +}); // this will not pass validation + +validate(user, { + groups: undefined // the default +}); // this will not pass validation since all properties get validated regardless of their groups + +validate(user, { + groups: [] +}); // this will not pass validation, (equivalent to 'groups: undefined', see above) +``` + +There is also a special flag `always: true` in validation options that you can use. This flag says that this validation +must be applied always no matter which group is used. + +## Custom validation classes + +If you have custom validation logic you can create a *Constraint class*: + +1. First create a file, lets say `CustomTextLength.ts`, and define a new class: + + ```typescript + import {ValidatorConstraintInterface} from "class-validator/validation/ValidatorConstraintInterface"; + import {ValidationArguments} from "class-validator/validation/ValidationArguments"; + import {ValidatorConstraint} from "class-validator/decorator/ValidatorConstraint"; + + @ValidatorConstraint({ name: "customText", async: false }) + export class CustomTextLength implements ValidatorConstraintInterface { + + validate(text: string, args: ValidationArguments) { + return text.length > 1 && text.length < 10; // for async validations you must return a Promise here + } + + defaultMessage(args: ValidationArguments) { // here you can provide default error message if validation failed + return "Text ($value) is too short or too long!"; + } + + } + ``` + + We marked our class with `@ValidatorConstraint` decorator. + You can also supply a validation constraint name - this name will be used as "error type" in ValidationError. + If you will not supply a constraint name - it will be auto-generated. + + Our class must implement `ValidatorConstraintInterface` interface and its `validate` method, + which defines validation logic. If validation succeeds, method returns true, otherwise false. + Custom validator can be asynchronous, if you want to perform validation after some asynchronous + operations, simply return a promise with boolean inside in `validate` method. + + Also we defined optional method `defaultMessage` which defines a default error message, + in the case that the decorator's implementation doesn't set an error message. + + +2. Then you can use your new validation constraint in your class: + + ```typescript + import {Validate} from "class-validator"; + import {CustomTextLength} from "./CustomTextLength"; + + export class Post { + + @Validate(CustomTextLength, { + message: "Title is too short or long!" + }) + title: string; + + } + ``` + + Here we set our newly created `CustomTextLength` validation constraint for `Post.title`. + +3. And use validator as usual: + + ```typescript + import {validate} from "class-validator"; + + validate(post).then(errors => { + // ... + }); + ``` + +You can also pass constraints to your validator, like this: + +```typescript +import {Validate} from "class-validator"; +import {CustomTextLength} from "./CustomTextLength"; + +export class Post { + + @Validate(CustomTextLength, [3, 20], { + message: "Wrong post title" + }) + title: string; + +} +``` + +And use them from `validationArguments` object: + +```typescript +import {ValidatorConstraintInterface} from "class-validator/validation/ValidatorConstraintInterface"; +import {ValidationArguments} from "class-validator/validation/ValidationArguments"; +import {ValidatorConstraint} from "class-validator/decorator/ValidatorConstraint"; + +@ValidatorConstraint() +export class CustomTextLength implements ValidatorConstraintInterface { + + validate(text: string, validationArguments: ValidationArguments) { + return text.length > validationArguments.constraints[0] && text.length < validationArguments.constraints[1]; + } + +} +``` + +## Custom validation decorators + +You can also create a custom decorators. Its the most elegant way of using a custom validations. +Lets create a decorator called `@IsLongerThan`: + +1. Create a decorator itself: + + ```typescript + import {registerDecorator} from "class-validator/register-decorator"; + import {ValidationOptions} from "class-validator/decorator/ValidationOptions"; + import {ValidationArguments} from "class-validator/validation/ValidationArguments"; + + export function IsLongerThan(property: string, validationOptions?: ValidationOptions) { + return function (object: Object, propertyName: string) { + registerDecorator({ + name: "isLongerThan", + target: object.constructor, + propertyName: propertyName, + constraints: [property], + options: validationOptions, + validator: { + validate(value: any, args: ValidationArguments) { + const [relatedPropertyName] = args.constraints; + const relatedValue = (args.object as any)[relatedPropertyName]; + return typeof value === "string" && + typeof relatedValue === "string" && + value.length > relatedValue.length; // you can return a Promise here as well, if you want to make async validation + } + } + }); + }; + } + ``` + +2. Put it to use: + + ```typescript + import {IsLongerThan} from "./IsLongerThan"; + + export class Post { + + title: string; + + @IsLongerThan("title", { + /* you can also use additional validation options, like "groups" in your custom validation decorators. "each" is not supported */ + message: "Text must be longer than the title" + }) + text: string; + + } + ``` + +In your custom decorators you can also use `ValidationConstraint`. +Lets create another custom validation decorator called `IsUserAlreadyExist`: + +1. Create a ValidationConstraint and decorator: + + ```typescript + import {registerDecorator} from "class-validator/register-decorator"; + import {ValidationOptions} from "class-validator/decorator/ValidationOptions"; + import {ValidatorConstraint} from "class-validator/decorator/ValidatorConstraint"; + import {ValidatorConstraintInterface} from "class-validator/validation/ValidatorConstraintInterface"; + import {ValidationArguments} from "class-validator/validation/ValidationArguments"; + + @ValidatorConstraint({ async: true }) + export class IsUserAlreadyExistConstraint implements ValidatorConstraintInterface { + + validate(userName: any, args: ValidationArguments) { + return UserRepository.findOneByName(userName).then(user => { + if (user) return false; + return true; + }); + } + + } + + export function IsUserAlreadyExist(validationOptions?: ValidationOptions) { + return function (object: Object, propertyName: string) { + registerDecorator({ + target: object.constructor, + propertyName: propertyName, + options: validationOptions, + constraints: [], + validator: IsUserAlreadyExistConstraint + }); + }; + } + ``` + + note that we marked our constraint that it will by async by adding `{ async: true }` in validation options. + +2. And put it to use: + + ```typescript + import {IsUserAlreadyExist} from "./IsUserAlreadyExist"; + + export class User { + + @IsUserAlreadyExist({ + message: "User $value already exists. Choose another name." + }) + name: string; + + } + ``` + +## Using service container + +Validator supports service container in the case if want to inject dependencies into your custom validator constraint +classes. Here is example how to integrate it with [typedi][2]: + +```typescript +import {Container} from "typedi"; +import {useContainer} from "class-validator/container"; +import {Validator} from "class-validator/validation/Validator"; + +// do this somewhere in the global application level: +useContainer(Container); +let validator = Container.get(Validator); + +// now everywhere you can inject Validator class which will go from the container +// also you can inject classes using constructor injection into your custom ValidatorConstraint-s +``` + +## Synchronous validation + +If you want to perform a simple non async validation you can use `validateSync` method instead of regular `validate` + method. It has the same arguments as `validate` method. But note, this method **ignores** all async validations + you have. + +## Manual validation + +There are several method exist in the Validator that allows to perform non-decorator based validation that is +compatible to the respective decorator. + +Each method is exported from the same module as the decorator. + +```typescript + +// common validation methods +// import {fooValidation} from "class-validator/decorator/common/FooValidation"; +isDefined(value); // Checks if value is defined ("!==undefined"). +equals(value, comparison); // Checks if value matches ("===") the comparison. +notEquals(value, comparison); // Checks if value does not match ("!==") the comparison. +isEmpty(value); // Checks if given value is empty (=== '', === null, === undefined). +isNotEmpty(value); // Checks if given value is not empty (!== '', !== null, !== undefined). +isIn(value, possibleValues); // Checks if given value is in a array of allowed values. +isNotIn(value, possibleValues); // Checks if given value not in a array of allowed values. + +// type validation methods +// import {fooValidation} from "class-validator/decorator/typechecker/FooValidation"; +isBoolean(value); // Checks if a given value is a real boolean. +isDate(value); // Checks if a given value is a real date. +isString(value); // Checks if a given value is a real string. +isArray(value); // Checks if a given value is an array. +isNumber(value, options); // Checks if a given value is a real number. +isInt(value); // Checks if value is an integer. +isEnum(value, entity); // Checks if value is valid for a certain enum entity. +isInstance(value, target); // Checks value is an instance of the target. + +// number validation methods +// import {fooValidation} from "class-validator/decorator/number/FooValidation"; +isDivisibleBy(value, num); // Checks if value is a number that's divisible by another. +isPositive(value); // Checks if the value is a positive number. +isNegative(value); // Checks if the value is a negative number. +min(num, min); // Checks if the first number is greater than or equal to the second. +max(num, max); // Checks if the first number is less than or equal to the second. + +// date validation methods +// import {fooValidation} from "class-validator/decorator/date/FooValidation"; +minDate(date, minDate); // Checks if the value is a date that's after the specified date. +maxDate(date, minDate); // Checks if the value is a date that's before the specified date. + +// string-type validation methods +// import {fooValidation} from "class-validator/decorator/string-as-type/FooValidation"; +isBooleanString(str); // Checks if a string is a boolean. +isNumberString(str); // Checks if the string is numeric. + +// string validation methods +// import {fooValidation} from "class-validator/decorator/string/FooValidation"; +contains(str, seed); // Checks if the string contains the seed. +notContains(str, seed); // Checks if the string does not contain the seed. +isAlpha(str); // Checks if the string contains only letters (a-zA-Z). +isAlphanumeric(str); // Checks if the string contains only letters and numbers. +isAscii(str); // Checks if the string contains ASCII chars only. +isBase64(str); // Checks if a string is base64 encoded. +isByteLength(str, min, max); // Checks if the string's length (in bytes) falls in a range. +isCreditCard(str); // Checks if the string is a credit card. +isCurrency(str, options); // Checks if the string is a valid currency amount. +isEmail(str, options); // Checks if the string is an email. +isFQDN(str, options); // Checks if the string is a fully qualified domain name (e.g. domain.com). +isFullWidth(str); // Checks if the string contains any full-width chars. +isHalfWidth(str); // Checks if the string contains any half-width chars. +isVariableWidth(str); // Checks if the string contains variable-width chars. +isHexColor(str); // Checks if the string is a hexadecimal color. +isHexadecimal(str); // Checks if the string is a hexadecimal number. +isIP(str, version); // Checks if the string is an IP (version 4 or 6). +isISBN(str, version); // Checks if the string is an ISBN (version 10 or 13). +isISIN(str); // Checks if the string is an ISIN (stock/security identifier). +isISO8601(str); // Checks if the string is a valid ISO 8601 date. +isJSON(str); // Checks if the string is valid JSON (note: uses JSON.parse). +isLowercase(str); // Checks if the string is lowercase. +isMobilePhone(str, locale); // Checks if the string is a mobile phone number. +isPhoneNumber(str, region); // Checks if the string is a valid phone number. +isMongoId(str); // Checks if the string is a valid hex-encoded representation of a MongoDB ObjectId. +isMultibyte(str); // Checks if the string contains one or more multibyte chars. +isSurrogatePair(str); // Checks if the string contains any surrogate pairs chars. +isURL(str, options); // Checks if the string is an url. +isUUID(str, version); // Checks if the string is a UUID (version 3, 4 or 5). +isUppercase(str); // Checks if the string is uppercase. +length(str, min, max); // Checks if the string's length falls in a range. +minLength(str, min); // Checks if the string's length is not less than given number. +maxLength(str, max); // Checks if the string's length is not more than given number. +matches(str, pattern, modifiers); // Checks if string matches the pattern. Either matches('foo', /foo/i) or matches('foo', 'foo', 'i'). +isMilitaryTime(str); // Checks if the string is a valid representation of military time in the format HH:MM. + +// array validation methods +// import {fooValidation} from "class-validator/decorator/array/FooValidation"; +arrayContains(array, values); // Checks if array contains all values from the given array of values. +arrayNotContains(array, values); // Checks if array does not contain any of the given values. +arrayNotEmpty(array); // Checks if given array is not empty. +arrayMinSize(array, min); // Checks if array's length is at least `min` number. +arrayMaxSize(array, max); // Checks if array's length is as most `max` number. +arrayUnique(array); // Checks if all array's values are unique. Comparison for objects is reference-based. +``` + +## Validation decorators + +| Decorator | Description | +|-------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------| +| **Common validation decorators** | +| `@IsDefined(value: any)` | Checks if value is defined (!== undefined, !== null). This is the only decorator that ignores skipMissingProperties option. | +| `@IsOptional()` | Checks if given value is empty (=== null, === undefined) and if so, ignores all the validators on the property. | +| `@Equals(comparison: any)` | Checks if value equals ("===") comparison. | +| `@NotEquals(comparison: any)` | Checks if value not equal ("!==") comparison. | +| `@IsEmpty()` | Checks if given value is empty (=== '', === null, === undefined). | +| `@IsNotEmpty()` | Checks if given value is not empty (!== '', !== null, !== undefined). | +| `@IsIn(values: any[])` | Checks if value is in a array of allowed values. | +| `@IsNotIn(values: any[])` | Checks if value is not in a array of disallowed values. | +| **Type validation decorators** | +| `@IsBoolean()` | Checks if a value is a boolean. | +| `@IsDate()` | Checks if the value is a date. | +| `@IsString()` | Checks if the string is a string. | +| `@IsNumber(options: IsNumberOptions)` | Checks if the value is a number. | +| `@IsInt()` | Checks if the value is an integer number. | +| `@IsArray()` | Checks if the value is an array | +| `@IsEnum(entity: object)` | Checks if the value is an valid enum | +| **Number validation decorators** | +| `@IsDivisibleBy(num: number)` | Checks if the value is a number that's divisible by another. | +| `@IsPositive()` | Checks if the value is a positive number. | +| `@IsNegative()` | Checks if the value is a negative number. | +| `@Min(min: number)` | Checks if the given number is greater than or equal to given number. | +| `@Max(max: number)` | Checks if the given number is less than or equal to given number. | +| **Date validation decorators** | +| `@MinDate(date: Date)` | Checks if the value is a date that's after the specified date. | +| `@MaxDate(date: Date)` | Checks if the value is a date that's before the specified date. | | +| **String-type validation decorators** | +| `@IsBooleanString()` | Checks if a string is a boolean (e.g. is "true" or "false"). | +| `@IsDateString()` | Checks if a string is a complete representation of a date (e.g. "2017-06-07T14:34:08.700Z", "2017-06-07T14:34:08.700 or "2017-06-07T14:34:08+04:00"). | +| `@IsNumberString()` | Checks if a string is a number. | +| **String validation decorators** | +| `@Contains(seed: string)` | Checks if the string contains the seed. | +| `@NotContains(seed: string)` | Checks if the string not contains the seed. | +| `@IsAlpha()` | Checks if the string contains only letters (a-zA-Z). | +| `@IsAlphanumeric()` | Checks if the string contains only letters and numbers. | +| `@IsAscii()` | Checks if the string contains ASCII chars only. | +| `@IsBase64()` | Checks if a string is base64 encoded. | +| `@IsByteLength(min: number, max?: number)` | Checks if the string's length (in bytes) falls in a range. | +| `@IsCreditCard()` | Checks if the string is a credit card. | +| `@IsCurrency(options?: IsCurrencyOptions)` | Checks if the string is a valid currency amount. | +| `@IsEmail(options?: IsEmailOptions)` | Checks if the string is an email. | +| `@IsFQDN(options?: IsFQDNOptions)` | Checks if the string is a fully qualified domain name (e.g. domain.com). | +| `@IsFullWidth()` | Checks if the string contains any full-width chars. | +| `@IsHalfWidth()` | Checks if the string contains any half-width chars. | +| `@IsVariableWidth()` | Checks if the string contains a mixture of full and half-width chars. | +| `@IsHexColor()` | Checks if the string is a hexadecimal color. | +| `@IsHexadecimal()` | Checks if the string is a hexadecimal number. | +| `@IsIP(version?: "4"\|"6")` | Checks if the string is an IP (version 4 or 6). | +| `@IsISBN(version?: "10"\|"13")` | Checks if the string is an ISBN (version 10 or 13). | +| `@IsISIN()` | Checks if the string is an ISIN (stock/security identifier). | +| `@IsISO8601()` | Checks if the string is a valid ISO 8601 date. | +| `@IsJSON()` | Checks if the string is valid JSON. | +| `@IsLowercase()` | Checks if the string is lowercase. | +| `@IsMobilePhone(locale: string)` | Checks if the string is a mobile phone number. | +| `@IsPhoneNumber(region: string)` | Checks if the string is a valid phone number. "region" accepts 2 characters uppercase country code (e.g. DE, US, CH).If users must enter the intl. prefix (e.g. +41), then you may pass "ZZ" or null as region. See [google-libphonenumber, metadata.js:countryCodeToRegionCodeMap on github](https://github.com/ruimarinho/google-libphonenumber/blob/1e46138878cff479aafe2ce62175c6c49cb58720/src/metadata.js#L33) | +| `@IsMongoId()` | Checks if the string is a valid hex-encoded representation of a MongoDB ObjectId. | +| `@IsMultibyte()` | Checks if the string contains one or more multibyte chars. | +| `@IsNumberString()` | Checks if the string is numeric. | +| `@IsSurrogatePair()` | Checks if the string contains any surrogate pairs chars. | +| `@IsUrl(options?: IsURLOptions)` | Checks if the string is an url. | +| `@IsUUID(version?: "3"\|"4"\|"5")` | Checks if the string is a UUID (version 3, 4 or 5). | +| `@IsUppercase()` | Checks if the string is uppercase. | +| `@Length(min: number, max?: number)` | Checks if the string's length falls in a range. | +| `@MinLength(min: number)` | Checks if the string's length is not less than given number. | +| `@MaxLength(max: number)` | Checks if the string's length is not more than given number. | +| `@Matches(pattern: RegExp, modifiers?: string)` | Checks if string matches the pattern. Either matches('foo', /foo/i) or matches('foo', 'foo', 'i'). +| `@IsMilitaryTime()` | Checks if the string is a valid representation of military time in the format HH:MM. | +| **Array validation decorators** | +| `@ArrayContains(values: any[])` | Checks if array contains all values from the given array of values. | +| `@ArrayNotContains(values: any[])` | Checks if array does not contain any of the given values. | +| `@ArrayNotEmpty()` | Checks if given array is not empty. | +| `@ArrayMinSize(min: number)` | Checks if array's length is as minimal this number. | +| `@ArrayMaxSize(max: number)` | Checks if array's length is as maximal this number. | +| `@ArrayUnique()` | Checks if all array's values are unique. Comparison for objects is reference-based. | +| **Object validation decorators** | +| `@IsInstance(value: any)` | Checks if the property is an instance of the passed value. | + **Other decorators** | +| `@Allow()` | Prevent stripping off the property when no other constraint is specified for it. | + +## Defining validation schema without decorators + +You can define your validation schemas without decorators: + +* you can define it in the separate object +* you can define it in the `.json` file + +This feature maybe useful in the cases if: + +* are using es5/es6 and don't have decorators available +* you don't have a classes, and instead using interfaces +* you don't want to use model at all +* you want to have a validation schema separate of your model +* you want beautiful json-schema based validation models +* you simply hate decorators + +Here is an example of using it: + +1. Create a schema object: + + ```typescript + import {ValidationSchema} from "class-validator/validation-schema/ValidationSchema"; + export let UserValidationSchema: ValidationSchema = { // using interface here is not required, its just for type-safety + name: "myUserSchema", // this is required, and must be unique + properties: { + firstName: [{ + type: "minLength", // validation type. All validation types are listed in ValidationTypes class. + constraints: [2] + }, { + type: "maxLength", + constraints: [20] + }], + lastName: [{ + type: "minLength", + constraints: [2] + }, { + type: "maxLength", + constraints: [20] + }], + email: [{ + type: "isEmail" + }] + } + }; + ``` + + Same schema can be provided in `.json` file, depend on your wish. + +2. Register your schema: + + ```typescript + import {registerSchema} from "class-validator"; + import {UserValidationSchema} from "./UserValidationSchema"; + registerSchema(schema); // if schema is in .json file, then you can simply do registerSchema(require("path-to-schema.json")); + ``` + + Better to put this code in a global place, maybe when you bootstrap your application, for example in `app.ts`. + +3. Validate your object using validation schema: + + ```typescript + import {validate} from "class-validator"; + const user = { firstName: "Johny", secondName: "Cage", email: "johny@cage.com" }; + validate("myUserSchema", user).then(errors => { + if (errors.length > 0) { + console.log("Validation failed: ", errors); + } else { + console.log("Validation succeed."); + } + }); + ``` + + That's it. Here `"myUserSchema"` is the name of our validation schema. + `validate` method will perform validation based on this schema + +## Validating plain objects +Due to nature of the decorators, the validated object has to be instantiated using `new Class()` syntax. If you have your class defined using class-validator decorators and you want to validate plain JS object (literal object or returned by JSON.parse), you need to transform it to the class instance (e.g. using [class-transformer](https://github.com/pleerock/class-transformer)) or just use the [class-transformer-validator](https://github.com/19majkel94/class-transformer-validator) extension which can do that for you. + +## Samples + +Take a look on samples in [./sample](https://github.com/pleerock/class-validator/tree/master/sample) for more examples of +usages. + +## Extensions +There are several extensions that simplify class-validator integration with other modules: +- [class-validator integration](https://github.com/19majkel94/class-transformer-validator) with [class-transformer](https://github.com/pleerock/class-transformer) + +## Release notes + +See information about breaking changes and release notes [here][3]. + +[1]: https://github.com/chriso/validator.js +[2]: https://github.com/pleerock/typedi +[3]: CHANGELOG.md diff --git a/sample/sample1-simple-validation/Post.ts b/sample/sample1-simple-validation/Post.ts index 30859a3601..a8619cccb3 100644 --- a/sample/sample1-simple-validation/Post.ts +++ b/sample/sample1-simple-validation/Post.ts @@ -1,12 +1,14 @@ -import {ArrayNotEmpty, ArrayMinSize, ArrayMaxSize} from "../../src/decorator/decorators"; -import {IsDate} from "../../src/decorator/IsDate"; -import {IsInt} from "../../src/decorator/IsInt"; -import {IsEnum} from "../../src/decorator/IsEnum"; -import {Contains} from "../../src/decorator/Contains"; -import {IsEmail} from "../../src/decorator/IsEmail"; -import {IsFQDN} from "../../src/decorator/IsFQDN"; -import {MinLength} from "../../src/decorator/MinLength"; -import {MaxLength} from "../../src/decorator/MaxLength"; +import {IsDate} from "../../src/decorator/typechecker/IsDate"; +import {IsInt} from "../../src/decorator/typechecker/IsInt"; +import {IsEnum} from "../../src/decorator/typechecker/IsEnum"; +import {Contains} from "../../src/decorator/string/Contains"; +import {IsEmail} from "../../src/decorator/string/IsEmail"; +import {IsFQDN} from "../../src/decorator/string/IsFQDN"; +import {MinLength} from "../../src/decorator/string/MinLength"; +import {MaxLength} from "../../src/decorator/string/MaxLength"; +import {ArrayNotEmpty} from "../../src/decorator/array/ArrayNotEmpty"; +import {ArrayMinSize} from "../../src/decorator/array/ArrayMinSize"; +import {ArrayMaxSize} from "../../src/decorator/array/ArrayMaxSize"; export enum PostType { Public, diff --git a/sample/sample2-using-groups/Post.ts b/sample/sample2-using-groups/Post.ts index 1d6b30ad3a..ddd1dd6931 100644 --- a/sample/sample2-using-groups/Post.ts +++ b/sample/sample2-using-groups/Post.ts @@ -1,9 +1,9 @@ -import {IsDate} from "../../src/decorator/IsDate"; -import {IsInt} from "../../src/decorator/IsInt"; -import {Contains} from "../../src/decorator/Contains"; -import {IsEmail} from "../../src/decorator/IsEmail"; -import {IsFQDN} from "../../src/decorator/IsFQDN"; -import {Length} from "../../src/decorator/Length"; +import {IsDate} from "../../src/decorator/typechecker/IsDate"; +import {IsInt} from "../../src/decorator/typechecker/IsInt"; +import {Contains} from "../../src/decorator/string/Contains"; +import {IsEmail} from "../../src/decorator/string/IsEmail"; +import {IsFQDN} from "../../src/decorator/string/IsFQDN"; +import {Length} from "../../src/decorator/string/Length"; export class Post { diff --git a/sample/sample3-nested-objects/Post.ts b/sample/sample3-nested-objects/Post.ts index d1161e187f..4a74897bdd 100644 --- a/sample/sample3-nested-objects/Post.ts +++ b/sample/sample3-nested-objects/Post.ts @@ -1,6 +1,6 @@ -import {ValidateNested} from "../../src/decorator/decorators"; import {Tag} from "./Tag"; -import {Length} from "../../src/decorator/Length"; +import {Length} from "../../src/decorator/string/Length"; +import {ValidateNested} from "../../src/decorator/system/ValidateNested"; export class Post { diff --git a/sample/sample3-nested-objects/Tag.ts b/sample/sample3-nested-objects/Tag.ts index cea904d5ba..bb7cf6ea37 100644 --- a/sample/sample3-nested-objects/Tag.ts +++ b/sample/sample3-nested-objects/Tag.ts @@ -1,4 +1,4 @@ -import {Length} from "../../src/decorator/Length"; +import {Length} from "../../src/decorator/string/Length"; export class Tag { diff --git a/sample/sample7-inheritance-support/BaseContent.ts b/sample/sample7-inheritance-support/BaseContent.ts index 297fef3981..02db1bdf76 100644 --- a/sample/sample7-inheritance-support/BaseContent.ts +++ b/sample/sample7-inheritance-support/BaseContent.ts @@ -1,4 +1,4 @@ -import {IsEmail} from "../../src/decorator/IsEmail"; +import {IsEmail} from "../../src/decorator/string/IsEmail"; export class BaseContent { diff --git a/sample/sample7-inheritance-support/Post.ts b/sample/sample7-inheritance-support/Post.ts index 89e0f533d6..bcb9981be0 100644 --- a/sample/sample7-inheritance-support/Post.ts +++ b/sample/sample7-inheritance-support/Post.ts @@ -1,8 +1,8 @@ import {BaseContent} from "./BaseContent"; -import {IsInt} from "../../src/decorator/IsInt"; -import {Contains} from "../../src/decorator/Contains"; -import {MinLength} from "../../src/decorator/MinLength"; -import {MaxLength} from "../../src/decorator/MaxLength"; +import {IsInt} from "../../src/decorator/typechecker/IsInt"; +import {Contains} from "../../src/decorator/string/Contains"; +import {MinLength} from "../../src/decorator/string/MinLength"; +import {MaxLength} from "../../src/decorator/string/MaxLength"; export class Post extends BaseContent { diff --git a/src/decorator/array/ArrayContains.ts b/src/decorator/array/ArrayContains.ts new file mode 100644 index 0000000000..13f9e1e4b2 --- /dev/null +++ b/src/decorator/array/ArrayContains.ts @@ -0,0 +1,30 @@ +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; + +export const ARRAY_CONTAINS = "arrayContains"; + +/** + * Checks if array contains all values from the given array of values. + * If null or undefined is given then this function returns false. + */ +export function arrayContains(array: any[], values: any[]) { + if (!(array instanceof Array)) { + return false; + } + + return !array || values.every(value => array.indexOf(value) !== -1); +} + +/** + * Checks if array contains all values from the given array of values. + */ +export function ArrayContains(values: any[], validationOptions?: ValidationOptions) { + return ValidateBy({ + name: ARRAY_CONTAINS, + validate: (value, args) => arrayContains(value, args.constraints[0]), + constraints: [values], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain $constraint1 values", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/array/ArrayMaxSize.ts b/src/decorator/array/ArrayMaxSize.ts new file mode 100644 index 0000000000..94c95f100a --- /dev/null +++ b/src/decorator/array/ArrayMaxSize.ts @@ -0,0 +1,30 @@ +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; + +export const ARRAY_MAX_SIZE = "arrayMaxSize"; + +/** + * Checks if array's length is as maximal this number. + * If null or undefined is given then this function returns false. + */ +export function arrayMaxSize(array: any[], max: number) { + if (!(array instanceof Array)) { + return false; + } + + return array instanceof Array && array.length <= max; +} + +/** + * Checks if array's length is as maximal this number. + */ +export function ArrayMaxSize(max: number, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: ARRAY_MAX_SIZE, + validate: (value, args) => arrayMaxSize(value, args.constraints[0]), + constraints: [max], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain not more than $constraint1 elements", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/array/ArrayMinSize.ts b/src/decorator/array/ArrayMinSize.ts new file mode 100644 index 0000000000..5d9579e6d2 --- /dev/null +++ b/src/decorator/array/ArrayMinSize.ts @@ -0,0 +1,30 @@ +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; + +export const ARRAY_MIN_SIZE = "arrayMinSize"; + +/** + * Checks if array's length is as minimal this number. + * If null or undefined is given then this function returns false. + */ +export function arrayMinSize(array: any[], min: number) { + if (!(array instanceof Array)) { + return false; + } + + return array instanceof Array && array.length >= min; +} + +/** + * Checks if array's length is as minimal this number. + */ +export function ArrayMinSize(min: number, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: ARRAY_MIN_SIZE, + validate: (value, args) => arrayMinSize(value, args.constraints[0]), + constraints: [min], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property must contain at least $constraint1 elements", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/array/ArrayNotContains.ts b/src/decorator/array/ArrayNotContains.ts new file mode 100644 index 0000000000..afd99559ff --- /dev/null +++ b/src/decorator/array/ArrayNotContains.ts @@ -0,0 +1,30 @@ +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; + +export const ARRAY_NOT_CONTAINS = "arrayNotContains"; + +/** + * Checks if array does not contain any of the given values. + * If null or undefined is given then this function returns false. + */ +export function arrayNotContains(array: any[], values: any[]) { + if (!(array instanceof Array)) { + return false; + } + + return !array || values.every(value => array.indexOf(value) === -1); +} + +/** + * Checks if array does not contain any of the given values. + */ +export function ArrayNotContains(values: any[], validationOptions?: ValidationOptions) { + return ValidateBy({ + name: ARRAY_NOT_CONTAINS, + validate: (value, args) => arrayNotContains(value, args.constraints[0]), + constraints: [values], + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property should not contain $constraint1 values", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/array/ArrayNotEmpty.ts b/src/decorator/array/ArrayNotEmpty.ts new file mode 100644 index 0000000000..d61949d5dc --- /dev/null +++ b/src/decorator/array/ArrayNotEmpty.ts @@ -0,0 +1,29 @@ +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; + +export const ARRAY_NOT_EMPTY = "arrayNotEmpty"; + +/** + * Checks if given array is not empty. + * If null or undefined is given then this function returns false. + */ +export function arrayNotEmpty(array: any[]) { + if (!(array instanceof Array)) { + return false; + } + + return array instanceof Array && array.length > 0; +} + +/** + * Checks if given array is not empty. + */ +export function ArrayNotEmpty(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: ARRAY_NOT_EMPTY, + validate: (value) => arrayNotEmpty(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property should not be empty", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/array/ArrayUnique.ts b/src/decorator/array/ArrayUnique.ts new file mode 100644 index 0000000000..6cc940a1e4 --- /dev/null +++ b/src/decorator/array/ArrayUnique.ts @@ -0,0 +1,30 @@ +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; + +export const ARRAY_UNIQUE = "arrayUnique"; + +/** + * Checks if all array's values are unique. Comparison for objects is reference-based. + * If null or undefined is given then this function returns false. + */ +export function arrayUnique(array: any[]) { + if (!(array instanceof Array)) { + return false; + } + + const uniqueItems = array.filter((a, b, c) => c.indexOf(a) === b); + return array.length === uniqueItems.length; +} + +/** + * Checks if all array's values are unique. Comparison for objects is reference-based. + */ +export function ArrayUnique(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: ARRAY_UNIQUE, + validate: (value) => arrayUnique(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "All $property's elements must be unique", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/Equals.ts b/src/decorator/common/Equals.ts similarity index 85% rename from src/decorator/Equals.ts rename to src/decorator/common/Equals.ts index b73dd26ad0..6fc40ee0ab 100644 --- a/src/decorator/Equals.ts +++ b/src/decorator/common/Equals.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const EQUALS = "equals"; diff --git a/src/decorator/IsEmpty.ts b/src/decorator/common/IsEmpty.ts similarity index 84% rename from src/decorator/IsEmpty.ts rename to src/decorator/common/IsEmpty.ts index a7de31dc26..088cce7ede 100644 --- a/src/decorator/IsEmpty.ts +++ b/src/decorator/common/IsEmpty.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const IS_EMPTY = "isEmpty"; diff --git a/src/decorator/IsIn.ts b/src/decorator/common/IsIn.ts similarity index 87% rename from src/decorator/IsIn.ts rename to src/decorator/common/IsIn.ts index 5e1b2b3c97..90f7e9fd2c 100644 --- a/src/decorator/IsIn.ts +++ b/src/decorator/common/IsIn.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const IS_IN = "isIn"; diff --git a/src/decorator/IsNotEmpty.ts b/src/decorator/common/IsNotEmpty.ts similarity index 85% rename from src/decorator/IsNotEmpty.ts rename to src/decorator/common/IsNotEmpty.ts index e46c78646d..41896d67b8 100644 --- a/src/decorator/IsNotEmpty.ts +++ b/src/decorator/common/IsNotEmpty.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const IS_NOT_EMPTY = "isNotEmpty"; diff --git a/src/decorator/IsNotIn.ts b/src/decorator/common/IsNotIn.ts similarity index 88% rename from src/decorator/IsNotIn.ts rename to src/decorator/common/IsNotIn.ts index 9b24e7fb73..063acff930 100644 --- a/src/decorator/IsNotIn.ts +++ b/src/decorator/common/IsNotIn.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const IS_NOT_IN = "isNotIn"; diff --git a/src/decorator/NotEquals.ts b/src/decorator/common/NotEquals.ts similarity index 86% rename from src/decorator/NotEquals.ts rename to src/decorator/common/NotEquals.ts index 424ceabc94..b02c4bdfca 100644 --- a/src/decorator/NotEquals.ts +++ b/src/decorator/common/NotEquals.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const NOT_EQUALS = "notEquals"; diff --git a/src/decorator/MaxDate.ts b/src/decorator/date/MaxDate.ts similarity index 86% rename from src/decorator/MaxDate.ts rename to src/decorator/date/MaxDate.ts index 9c82e0f683..79a552ecba 100644 --- a/src/decorator/MaxDate.ts +++ b/src/decorator/date/MaxDate.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const MAX_DATE = "maxDate"; diff --git a/src/decorator/MinDate.ts b/src/decorator/date/MinDate.ts similarity index 86% rename from src/decorator/MinDate.ts rename to src/decorator/date/MinDate.ts index eff65f9190..d9803fb5b7 100644 --- a/src/decorator/MinDate.ts +++ b/src/decorator/date/MinDate.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const MIN_DATE = "minDate"; diff --git a/src/decorator/decorators.ts b/src/decorator/decorators.ts deleted file mode 100644 index 2e5260a700..0000000000 --- a/src/decorator/decorators.ts +++ /dev/null @@ -1,201 +0,0 @@ -import {ValidationTypes} from "../validation/ValidationTypes"; -import {ValidationOptions} from "./ValidationOptions"; -import {ValidationMetadata} from "../metadata/ValidationMetadata"; -import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; -import {getFromContainer} from "../container"; -import {MetadataStorage} from "../metadata/MetadataStorage"; - -// ------------------------------------------------------------------------- -// System -/** - * Objects / object arrays marked with this decorator will also be validated. - */ -export function ValidateNested(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.NESTED_VALIDATION, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * If object has both allowed and not allowed properties a validation error will be thrown. - */ -export function Allow(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.WHITELIST, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Objects / object arrays marked with this decorator will also be validated. - */ -export function ValidateIf(condition: (object: any, value: any) => boolean, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.CONDITIONAL_VALIDATION, - target: object.constructor, - propertyName: propertyName, - constraints: [condition], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if given value is defined (!== undefined, !== null). - */ -export function IsDefined(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_DEFINED, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if value is missing and if so, ignores all validators. - */ -export function IsOptional(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.CONDITIONAL_VALIDATION, - target: object.constructor, - propertyName: propertyName, - constraints: [(object: any, value: any) => { - return object[propertyName] !== null && object[propertyName] !== undefined; - }], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -// ------------------------------------------------------------------------- -// Array checkers -// ------------------------------------------------------------------------- - -/** - * Checks if array contains all values from the given array of values. - */ -export function ArrayContains(values: any[], validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.ARRAY_CONTAINS, - target: object.constructor, - propertyName: propertyName, - constraints: [values], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if array does not contain any of the given values. - */ -export function ArrayNotContains(values: any[], validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.ARRAY_NOT_CONTAINS, - target: object.constructor, - propertyName: propertyName, - constraints: [values], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if given array is not empty. - */ -export function ArrayNotEmpty(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.ARRAY_NOT_EMPTY, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if array's length is as minimal this number. - */ -export function ArrayMinSize(min: number, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.ARRAY_MIN_SIZE, - target: object.constructor, - propertyName: propertyName, - constraints: [min], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if array's length is as maximal this number. - */ -export function ArrayMaxSize(max: number, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.ARRAY_MAX_SIZE, - target: object.constructor, - propertyName: propertyName, - constraints: [max], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if all array's values are unique. Comparison for objects is reference-based. - */ -export function ArrayUnique(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.ARRAY_UNIQUE, - target: object.constructor, - propertyName: propertyName, - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} - -/** - * Checks if all array's values are unique. Comparison for objects is reference-based. - */ -export function IsInstance(targetType: new (...args: any[]) => any, validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { - const args: ValidationMetadataArgs = { - type: ValidationTypes.IS_INSTANCE, - target: object.constructor, - propertyName: propertyName, - constraints: [targetType], - validationOptions: validationOptions - }; - getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); - }; -} diff --git a/src/decorator/IsDivisibleBy.ts b/src/decorator/number/IsDivisibleBy.ts similarity index 88% rename from src/decorator/IsDivisibleBy.ts rename to src/decorator/number/IsDivisibleBy.ts index c8060d74cb..1cd41a439e 100644 --- a/src/decorator/IsDivisibleBy.ts +++ b/src/decorator/number/IsDivisibleBy.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import * as validatorIsDivisibleBy from "validator/lib/isDivisibleBy"; export const IS_DIVISIBLE_BY = "isDivisibleBy"; diff --git a/src/decorator/IsNegative.ts b/src/decorator/number/IsNegative.ts similarity index 84% rename from src/decorator/IsNegative.ts rename to src/decorator/number/IsNegative.ts index ff6efc7813..f31ef20530 100644 --- a/src/decorator/IsNegative.ts +++ b/src/decorator/number/IsNegative.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const IS_NEGATIVE = "isNegative"; diff --git a/src/decorator/IsPositive.ts b/src/decorator/number/IsPositive.ts similarity index 84% rename from src/decorator/IsPositive.ts rename to src/decorator/number/IsPositive.ts index 34ad17b9b8..31ae1eeb48 100644 --- a/src/decorator/IsPositive.ts +++ b/src/decorator/number/IsPositive.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const IS_POSITIVE = "isPositive"; diff --git a/src/decorator/Max.ts b/src/decorator/number/Max.ts similarity index 87% rename from src/decorator/Max.ts rename to src/decorator/number/Max.ts index 83a201abf3..ff34bb6995 100644 --- a/src/decorator/Max.ts +++ b/src/decorator/number/Max.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const MAX = "max"; diff --git a/src/decorator/Min.ts b/src/decorator/number/Min.ts similarity index 87% rename from src/decorator/Min.ts rename to src/decorator/number/Min.ts index b43c8c3217..2fd38e1e20 100644 --- a/src/decorator/Min.ts +++ b/src/decorator/number/Min.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const MIN = "min"; diff --git a/src/decorator/IsBooleanString.ts b/src/decorator/string-as-type/IsBooleanString.ts similarity index 87% rename from src/decorator/IsBooleanString.ts rename to src/decorator/string-as-type/IsBooleanString.ts index 004e0cb3b9..07433be51a 100644 --- a/src/decorator/IsBooleanString.ts +++ b/src/decorator/string-as-type/IsBooleanString.ts @@ -1,5 +1,5 @@ -import {buildMessage, ValidateBy} from "./ValidateBy"; -import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; import validatorJsIsBoolean = require("validator/lib/isBoolean"); export const IS_BOOLEAN_STRING = "isBooleanString"; diff --git a/src/decorator/IsDateString.ts b/src/decorator/string-as-type/IsDateString.ts similarity index 80% rename from src/decorator/IsDateString.ts rename to src/decorator/string-as-type/IsDateString.ts index e011508143..d62dd53cbe 100644 --- a/src/decorator/IsDateString.ts +++ b/src/decorator/string-as-type/IsDateString.ts @@ -1,6 +1,6 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; -import {isString} from "./IsString"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; +import {isString} from "../typechecker/IsString"; export const IS_DATE_STRING = "isDateString"; diff --git a/src/decorator/IsNumberString.ts b/src/decorator/string-as-type/IsNumberString.ts similarity index 87% rename from src/decorator/IsNumberString.ts rename to src/decorator/string-as-type/IsNumberString.ts index 80388d2aae..eef8cbed36 100644 --- a/src/decorator/IsNumberString.ts +++ b/src/decorator/string-as-type/IsNumberString.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsNumeric = require("validator/lib/isNumeric"); export const IS_NUMBER_STRING = "isNumberString"; diff --git a/src/decorator/Contains.ts b/src/decorator/string/Contains.ts similarity index 88% rename from src/decorator/Contains.ts rename to src/decorator/string/Contains.ts index f3d2143f7b..ecb9483631 100644 --- a/src/decorator/Contains.ts +++ b/src/decorator/string/Contains.ts @@ -1,5 +1,5 @@ -import {buildMessage, ValidateBy} from "./ValidateBy"; -import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; import validatorJsContains = require("validator/lib/contains"); export const CONTAINS = "contains"; diff --git a/src/decorator/IsAlpha.ts b/src/decorator/string/IsAlpha.ts similarity index 87% rename from src/decorator/IsAlpha.ts rename to src/decorator/string/IsAlpha.ts index 0e73f53c93..6396a93cd6 100644 --- a/src/decorator/IsAlpha.ts +++ b/src/decorator/string/IsAlpha.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsAlpha = require("validator/lib/isAlpha"); export const IS_ALPHA = "isAlpha"; diff --git a/src/decorator/IsAlphanumeric.ts b/src/decorator/string/IsAlphanumeric.ts similarity index 88% rename from src/decorator/IsAlphanumeric.ts rename to src/decorator/string/IsAlphanumeric.ts index 323c676e02..ba31d5844c 100644 --- a/src/decorator/IsAlphanumeric.ts +++ b/src/decorator/string/IsAlphanumeric.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsAlphanumeric = require("validator/lib/isAlphanumeric"); export const IS_ALPHANUMERIC = "isAlphanumeric"; diff --git a/src/decorator/IsAscii.ts b/src/decorator/string/IsAscii.ts similarity index 86% rename from src/decorator/IsAscii.ts rename to src/decorator/string/IsAscii.ts index a50b93d72e..71f7c09ef5 100644 --- a/src/decorator/IsAscii.ts +++ b/src/decorator/string/IsAscii.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsAscii = require("validator/lib/isAscii"); export const IS_ASCII = "isAscii"; diff --git a/src/decorator/IsBase64.ts b/src/decorator/string/IsBase64.ts similarity index 86% rename from src/decorator/IsBase64.ts rename to src/decorator/string/IsBase64.ts index bfe5804a8b..c184295c9c 100644 --- a/src/decorator/IsBase64.ts +++ b/src/decorator/string/IsBase64.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsBase64 = require("validator/lib/isBase64"); export const IS_BASE64 = "isBase64"; diff --git a/src/decorator/IsByteLength.ts b/src/decorator/string/IsByteLength.ts similarity index 89% rename from src/decorator/IsByteLength.ts rename to src/decorator/string/IsByteLength.ts index 1ada2953a6..bacbd6b271 100644 --- a/src/decorator/IsByteLength.ts +++ b/src/decorator/string/IsByteLength.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsByteLength = require("validator/lib/isByteLength"); export const IS_BYTE_LENGTH = "isByteLength"; diff --git a/src/decorator/IsCreditCard.ts b/src/decorator/string/IsCreditCard.ts similarity index 87% rename from src/decorator/IsCreditCard.ts rename to src/decorator/string/IsCreditCard.ts index d79f2d54fc..69957722c9 100644 --- a/src/decorator/IsCreditCard.ts +++ b/src/decorator/string/IsCreditCard.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsCreditCard = require("validator/lib/isCreditCard"); export const IS_CREDIT_CARD = "isCreditCard"; diff --git a/src/decorator/IsCurrency.ts b/src/decorator/string/IsCurrency.ts similarity index 89% rename from src/decorator/IsCurrency.ts rename to src/decorator/string/IsCurrency.ts index 7b066d0df0..be0d3b570d 100644 --- a/src/decorator/IsCurrency.ts +++ b/src/decorator/string/IsCurrency.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsCurrency = require("validator/lib/isCurrency"); export const IS_CURRENCY = "isCurrency"; diff --git a/src/decorator/IsEmail.ts b/src/decorator/string/IsEmail.ts similarity index 88% rename from src/decorator/IsEmail.ts rename to src/decorator/string/IsEmail.ts index eb1bf1f4ff..470a547b7e 100644 --- a/src/decorator/IsEmail.ts +++ b/src/decorator/string/IsEmail.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsEmail = require("validator/lib/isEmail"); export const IS_EMAIL = "isEmail"; diff --git a/src/decorator/IsFQDN.ts b/src/decorator/string/IsFQDN.ts similarity index 89% rename from src/decorator/IsFQDN.ts rename to src/decorator/string/IsFQDN.ts index 8bc8d6d00d..0ae4b93d36 100644 --- a/src/decorator/IsFQDN.ts +++ b/src/decorator/string/IsFQDN.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsFQDN = require("validator/lib/isFQDN"); export const IS_FQDN = "isFqdn"; diff --git a/src/decorator/IsFullWidth.ts b/src/decorator/string/IsFullWidth.ts similarity index 88% rename from src/decorator/IsFullWidth.ts rename to src/decorator/string/IsFullWidth.ts index 70a9493f89..003127e96a 100644 --- a/src/decorator/IsFullWidth.ts +++ b/src/decorator/string/IsFullWidth.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; // strange module export :( const validatorJsIsFullWidth: (value: any) => boolean = require("validator/lib/isFullWidth").default; diff --git a/src/decorator/IsHalfWidth.ts b/src/decorator/string/IsHalfWidth.ts similarity index 88% rename from src/decorator/IsHalfWidth.ts rename to src/decorator/string/IsHalfWidth.ts index da0f61fe59..c4bc004d3b 100644 --- a/src/decorator/IsHalfWidth.ts +++ b/src/decorator/string/IsHalfWidth.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; // strange module export :( const validatorJsIsHalfWidth: (value: any) => boolean = require("validator/lib/isHalfWidth").default; diff --git a/src/decorator/IsHexColor.ts b/src/decorator/string/IsHexColor.ts similarity index 87% rename from src/decorator/IsHexColor.ts rename to src/decorator/string/IsHexColor.ts index 29eefb2616..64fc5a649b 100644 --- a/src/decorator/IsHexColor.ts +++ b/src/decorator/string/IsHexColor.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsHexColor = require("validator/lib/isHexColor"); export const IS_HEX_COLOR = "isHexColor"; diff --git a/src/decorator/IsHexadecimal.ts b/src/decorator/string/IsHexadecimal.ts similarity index 87% rename from src/decorator/IsHexadecimal.ts rename to src/decorator/string/IsHexadecimal.ts index b5be8ccc55..75780a62b7 100644 --- a/src/decorator/IsHexadecimal.ts +++ b/src/decorator/string/IsHexadecimal.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsHexadecimal = require("validator/lib/isHexadecimal"); export const IS_HEXADECIMAL = "isHexadecimal"; diff --git a/src/decorator/IsIP.ts b/src/decorator/string/IsIP.ts similarity index 89% rename from src/decorator/IsIP.ts rename to src/decorator/string/IsIP.ts index f2f2bc01bd..99e513c9c8 100644 --- a/src/decorator/IsIP.ts +++ b/src/decorator/string/IsIP.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsIP = require("validator/lib/isIP"); export const IS_IP = "isIp"; diff --git a/src/decorator/IsISBN.ts b/src/decorator/string/IsISBN.ts similarity index 89% rename from src/decorator/IsISBN.ts rename to src/decorator/string/IsISBN.ts index b9aa9ac222..5ccd322150 100644 --- a/src/decorator/IsISBN.ts +++ b/src/decorator/string/IsISBN.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsISBN = require("validator/lib/isISBN"); export const IS_ISBN = "isIsbn"; diff --git a/src/decorator/IsISIN.ts b/src/decorator/string/IsISIN.ts similarity index 87% rename from src/decorator/IsISIN.ts rename to src/decorator/string/IsISIN.ts index 7ff7ec2105..e9efa99df2 100644 --- a/src/decorator/IsISIN.ts +++ b/src/decorator/string/IsISIN.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsISIN = require("validator/lib/isISIN"); export const IS_ISIN = "isIsin"; diff --git a/src/decorator/IsISO8601.ts b/src/decorator/string/IsISO8601.ts similarity index 87% rename from src/decorator/IsISO8601.ts rename to src/decorator/string/IsISO8601.ts index d4223135e7..1a3b878c74 100644 --- a/src/decorator/IsISO8601.ts +++ b/src/decorator/string/IsISO8601.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsISO8601 = require("validator/lib/isISO8601"); export const IS_ISO8601 = "isIso8601"; diff --git a/src/decorator/IsJSON.ts b/src/decorator/string/IsJSON.ts similarity index 86% rename from src/decorator/IsJSON.ts rename to src/decorator/string/IsJSON.ts index 553bb109fa..878766ea37 100644 --- a/src/decorator/IsJSON.ts +++ b/src/decorator/string/IsJSON.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsJSON = require("validator/lib/isJSON"); export const IS_JSON = "isJson"; diff --git a/src/decorator/IsLowercase.ts b/src/decorator/string/IsLowercase.ts similarity index 86% rename from src/decorator/IsLowercase.ts rename to src/decorator/string/IsLowercase.ts index a3d655fafc..8164a84d42 100644 --- a/src/decorator/IsLowercase.ts +++ b/src/decorator/string/IsLowercase.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsLowercase = require("validator/lib/isLowercase"); export const IS_LOWERCASE = "isLowercase"; diff --git a/src/decorator/IsMilitaryTime.ts b/src/decorator/string/IsMilitaryTime.ts similarity index 88% rename from src/decorator/IsMilitaryTime.ts rename to src/decorator/string/IsMilitaryTime.ts index 3206dcf189..59fae5c590 100644 --- a/src/decorator/IsMilitaryTime.ts +++ b/src/decorator/string/IsMilitaryTime.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import {matches} from "./Matches"; export const IS_MILITARY_TIME = "isMilitaryTime"; diff --git a/src/decorator/IsMobilePhone.ts b/src/decorator/string/IsMobilePhone.ts similarity index 91% rename from src/decorator/IsMobilePhone.ts rename to src/decorator/string/IsMobilePhone.ts index 0193523474..385e258ec1 100644 --- a/src/decorator/IsMobilePhone.ts +++ b/src/decorator/string/IsMobilePhone.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsMobilePhone = require("validator/lib/isMobilePhone"); export const IS_MOBILE_PHONE = "isMobilePhone"; diff --git a/src/decorator/IsMongoId.ts b/src/decorator/string/IsMongoId.ts similarity index 87% rename from src/decorator/IsMongoId.ts rename to src/decorator/string/IsMongoId.ts index 83554de2dc..885e29b54f 100644 --- a/src/decorator/IsMongoId.ts +++ b/src/decorator/string/IsMongoId.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsMongoId = require("validator/lib/isMongoId"); export const IS_MONGO_ID = "isMongoId"; diff --git a/src/decorator/IsMultibyte.ts b/src/decorator/string/IsMultibyte.ts similarity index 87% rename from src/decorator/IsMultibyte.ts rename to src/decorator/string/IsMultibyte.ts index f015513e09..341d44d656 100644 --- a/src/decorator/IsMultibyte.ts +++ b/src/decorator/string/IsMultibyte.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsMultibyte = require("validator/lib/isMultibyte"); export const IS_MULTIBYTE = "isMultibyte"; diff --git a/src/decorator/IsPhoneNumber.ts b/src/decorator/string/IsPhoneNumber.ts similarity index 94% rename from src/decorator/IsPhoneNumber.ts rename to src/decorator/string/IsPhoneNumber.ts index ba0d1db8d1..bfc2876481 100644 --- a/src/decorator/IsPhoneNumber.ts +++ b/src/decorator/string/IsPhoneNumber.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import * as libphonenumber from "google-libphonenumber"; const phoneUtil = libphonenumber.PhoneNumberUtil.getInstance(); diff --git a/src/decorator/IsSurrogatePair.ts b/src/decorator/string/IsSurrogatePair.ts similarity index 88% rename from src/decorator/IsSurrogatePair.ts rename to src/decorator/string/IsSurrogatePair.ts index b8c968e009..854bd7a4de 100644 --- a/src/decorator/IsSurrogatePair.ts +++ b/src/decorator/string/IsSurrogatePair.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsSurrogatePair = require("validator/lib/isSurrogatePair"); export const IS_SURROGATE_PAIR = "isSurrogatePair"; diff --git a/src/decorator/IsUUID.ts b/src/decorator/string/IsUUID.ts similarity index 88% rename from src/decorator/IsUUID.ts rename to src/decorator/string/IsUUID.ts index 7a26a5d404..ff61f65ffe 100644 --- a/src/decorator/IsUUID.ts +++ b/src/decorator/string/IsUUID.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsUUID = require("validator/lib/isUUID"); export const IS_UUID = "isUuid"; diff --git a/src/decorator/IsUppercase.ts b/src/decorator/string/IsUppercase.ts similarity index 86% rename from src/decorator/IsUppercase.ts rename to src/decorator/string/IsUppercase.ts index e03be8a538..1cb83cb073 100644 --- a/src/decorator/IsUppercase.ts +++ b/src/decorator/string/IsUppercase.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsUppercase = require("validator/lib/isUppercase"); export const IS_UPPERCASE = "isUppercase"; diff --git a/src/decorator/IsUrl.ts b/src/decorator/string/IsUrl.ts similarity index 88% rename from src/decorator/IsUrl.ts rename to src/decorator/string/IsUrl.ts index f6377e95a6..26a4ac962f 100644 --- a/src/decorator/IsUrl.ts +++ b/src/decorator/string/IsUrl.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsURL = require("validator/lib/isURL"); export const IS_URL = "isUrl"; diff --git a/src/decorator/IsVariableWidth.ts b/src/decorator/string/IsVariableWidth.ts similarity index 88% rename from src/decorator/IsVariableWidth.ts rename to src/decorator/string/IsVariableWidth.ts index 6dafb80c43..7cee6a8f34 100644 --- a/src/decorator/IsVariableWidth.ts +++ b/src/decorator/string/IsVariableWidth.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsVariableWidth = require("validator/lib/isVariableWidth"); export const IS_VARIABLE_WIDTH = "isVariableWidth"; diff --git a/src/decorator/Length.ts b/src/decorator/string/Length.ts similarity index 93% rename from src/decorator/Length.ts rename to src/decorator/string/Length.ts index bf2ff46ffa..b0b2a840d4 100644 --- a/src/decorator/Length.ts +++ b/src/decorator/string/Length.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsIsLength = require("validator/lib/isLength"); export const LENGTH = "length"; diff --git a/src/decorator/Matches.ts b/src/decorator/string/Matches.ts similarity index 93% rename from src/decorator/Matches.ts rename to src/decorator/string/Matches.ts index d9395938c1..5d040effc0 100644 --- a/src/decorator/Matches.ts +++ b/src/decorator/string/Matches.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import validatorJsMatches = require("validator/lib/matches"); export const MATCHES = "matches"; diff --git a/src/decorator/MaxLength.ts b/src/decorator/string/MaxLength.ts similarity index 89% rename from src/decorator/MaxLength.ts rename to src/decorator/string/MaxLength.ts index f4ad3d6714..08455012be 100644 --- a/src/decorator/MaxLength.ts +++ b/src/decorator/string/MaxLength.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import {length} from "./Length"; export const MAX_LENGTH = "maxLength"; diff --git a/src/decorator/MinLength.ts b/src/decorator/string/MinLength.ts similarity index 89% rename from src/decorator/MinLength.ts rename to src/decorator/string/MinLength.ts index 2a80a6edd1..3a74b9ed65 100644 --- a/src/decorator/MinLength.ts +++ b/src/decorator/string/MinLength.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import {length} from "./Length"; export const MIN_LENGTH = "minLength"; diff --git a/src/decorator/NotContains.ts b/src/decorator/string/NotContains.ts similarity index 88% rename from src/decorator/NotContains.ts rename to src/decorator/string/NotContains.ts index 687e912d3d..2c1062b750 100644 --- a/src/decorator/NotContains.ts +++ b/src/decorator/string/NotContains.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; import {contains} from "./Contains"; export const NOT_CONTAINS = "notContains"; diff --git a/src/decorator/system/Allow.ts b/src/decorator/system/Allow.ts new file mode 100644 index 0000000000..1ffe231830 --- /dev/null +++ b/src/decorator/system/Allow.ts @@ -0,0 +1,22 @@ +import {ValidationOptions} from "../ValidationOptions"; +import {ValidationMetadataArgs} from "../../metadata/ValidationMetadataArgs"; +import {ValidationTypes} from "../../validation/ValidationTypes"; +import {getFromContainer} from "../../container"; +import {MetadataStorage} from "../../metadata/MetadataStorage"; +import {ValidationMetadata} from "../../metadata/ValidationMetadata"; + + +/** + * If object has both allowed and not allowed properties a validation error will be thrown. + */ +export function Allow(validationOptions?: ValidationOptions) { + return function (object: Object, propertyName: string) { + const args: ValidationMetadataArgs = { + type: ValidationTypes.WHITELIST, + target: object.constructor, + propertyName: propertyName, + validationOptions: validationOptions + }; + getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); + }; +} diff --git a/src/decorator/system/IsDefined.ts b/src/decorator/system/IsDefined.ts new file mode 100644 index 0000000000..0796b5d976 --- /dev/null +++ b/src/decorator/system/IsDefined.ts @@ -0,0 +1,27 @@ +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; +import {ValidationTypes} from "../../validation/ValidationTypes"; + +// isDefined is (yet) a special case +export const IS_DEFINED = ValidationTypes.IS_DEFINED; + +/** + * Checks if value is defined (!== undefined, !== null). + */ +export function isDefined(value: any): boolean { + return value !== undefined && value !== null; +} + + +/** + * Checks if given value is defined (!== undefined, !== null). + */ +export function IsDefined(validationOptions?: ValidationOptions) { + return ValidateBy({ + name: IS_DEFINED, + validate: (value) => isDefined(value), + defaultMessage: buildMessage((eachPrefix) => eachPrefix + "$property should not be null or undefined", validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/system/IsOptional.ts b/src/decorator/system/IsOptional.ts new file mode 100644 index 0000000000..84c2f539b7 --- /dev/null +++ b/src/decorator/system/IsOptional.ts @@ -0,0 +1,24 @@ +import {ValidationOptions} from "../ValidationOptions"; +import {ValidationMetadataArgs} from "../../metadata/ValidationMetadataArgs"; +import {ValidationTypes} from "../../validation/ValidationTypes"; +import {getFromContainer} from "../../container"; +import {MetadataStorage} from "../../metadata/MetadataStorage"; +import {ValidationMetadata} from "../../metadata/ValidationMetadata"; + +/** + * Checks if value is missing and if so, ignores all validators. + */ +export function IsOptional(validationOptions?: ValidationOptions) { + return function (object: Object, propertyName: string) { + const args: ValidationMetadataArgs = { + type: ValidationTypes.CONDITIONAL_VALIDATION, + target: object.constructor, + propertyName: propertyName, + constraints: [(object: any, value: any) => { + return object[propertyName] !== null && object[propertyName] !== undefined; + }], + validationOptions: validationOptions + }; + getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); + }; +} diff --git a/src/decorator/system/ValidateIf.ts b/src/decorator/system/ValidateIf.ts new file mode 100644 index 0000000000..c68b5e1545 --- /dev/null +++ b/src/decorator/system/ValidateIf.ts @@ -0,0 +1,22 @@ +import {ValidationOptions} from "../ValidationOptions"; +import {ValidationMetadataArgs} from "../../metadata/ValidationMetadataArgs"; +import {ValidationTypes} from "../../validation/ValidationTypes"; +import {getFromContainer} from "../../container"; +import {MetadataStorage} from "../../metadata/MetadataStorage"; +import {ValidationMetadata} from "../../metadata/ValidationMetadata"; + +/** + * Objects / object arrays marked with this decorator will also be validated. + */ +export function ValidateIf(condition: (object: any, value: any) => boolean, validationOptions?: ValidationOptions) { + return function (object: Object, propertyName: string) { + const args: ValidationMetadataArgs = { + type: ValidationTypes.CONDITIONAL_VALIDATION, + target: object.constructor, + propertyName: propertyName, + constraints: [condition], + validationOptions: validationOptions + }; + getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); + }; +} diff --git a/src/decorator/system/ValidateNested.ts b/src/decorator/system/ValidateNested.ts new file mode 100644 index 0000000000..3fd7d5dfba --- /dev/null +++ b/src/decorator/system/ValidateNested.ts @@ -0,0 +1,25 @@ +import {ValidationOptions} from "../ValidationOptions"; +import {ValidationMetadataArgs} from "../../metadata/ValidationMetadataArgs"; +import {ValidationTypes} from "../../validation/ValidationTypes"; +import {getFromContainer} from "../../container"; +import {MetadataStorage} from "../../metadata/MetadataStorage"; +import {ValidationMetadata} from "../../metadata/ValidationMetadata"; + +/** + * Objects / object arrays marked with this decorator will also be validated. + */ +export function ValidateNested(validationOptions?: ValidationOptions) { + const opts: ValidationOptions = {...validationOptions}; + const eachPrefix = opts.each ? "each value in " : ""; + opts.message = opts.message || eachPrefix + "nested property $property must be either object or array"; + + return function (object: Object, propertyName: string) { + const args: ValidationMetadataArgs = { + type: ValidationTypes.NESTED_VALIDATION, + target: object.constructor, + propertyName: propertyName, + validationOptions: opts, + }; + getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); + }; +} diff --git a/src/decorator/IsArray.ts b/src/decorator/typechecker/IsArray.ts similarity index 82% rename from src/decorator/IsArray.ts rename to src/decorator/typechecker/IsArray.ts index 35906f8d43..f6e1d1641b 100644 --- a/src/decorator/IsArray.ts +++ b/src/decorator/typechecker/IsArray.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const IS_ARRAY = "isArray"; diff --git a/src/decorator/IsBoolean.ts b/src/decorator/typechecker/IsBoolean.ts similarity index 84% rename from src/decorator/IsBoolean.ts rename to src/decorator/typechecker/IsBoolean.ts index f1e0f6e3ef..a0fd1e7a46 100644 --- a/src/decorator/IsBoolean.ts +++ b/src/decorator/typechecker/IsBoolean.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const IS_BOOLEAN = "isBoolean"; diff --git a/src/decorator/IsDate.ts b/src/decorator/typechecker/IsDate.ts similarity index 83% rename from src/decorator/IsDate.ts rename to src/decorator/typechecker/IsDate.ts index 4d5f0f60f3..8ff367f07e 100644 --- a/src/decorator/IsDate.ts +++ b/src/decorator/typechecker/IsDate.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const IS_DATE = "isDate"; diff --git a/src/decorator/IsEnum.ts b/src/decorator/typechecker/IsEnum.ts similarity index 86% rename from src/decorator/IsEnum.ts rename to src/decorator/typechecker/IsEnum.ts index 1607f12c54..5bf2ad26aa 100644 --- a/src/decorator/IsEnum.ts +++ b/src/decorator/typechecker/IsEnum.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const IS_ENUM = "isEnum"; diff --git a/src/decorator/typechecker/IsInstance.ts b/src/decorator/typechecker/IsInstance.ts new file mode 100644 index 0000000000..9adf7ff935 --- /dev/null +++ b/src/decorator/typechecker/IsInstance.ts @@ -0,0 +1,33 @@ +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; + +export const IS_INSTANCE = "isInstance"; + +/** + * Checks if the value is an instance of the specified object. + */ +export function isInstance(object: any, targetTypeConstructor: new (...args: any[]) => any) { + return targetTypeConstructor + && typeof targetTypeConstructor === "function" + && object instanceof targetTypeConstructor; +} + +/** + * Checks if all array's values are unique. Comparison for objects is reference-based. + */ +export function IsInstance(targetType: new (...args: any[]) => any, validationOptions?: ValidationOptions) { + return ValidateBy({ + name: IS_INSTANCE, + validate: (value, args) => isInstance(value, args.constraints[0]), + constraints: [targetType], + defaultMessage: buildMessage((eachPrefix, args) => { + if (args.constraints[0]) { + return eachPrefix + `$property must be an instance of ${args.constraints[0].name}`; + } else { + return eachPrefix + `${this.IS_INSTANCE} decorator expects and object as value, but got falsy value.`; + } + }, validationOptions) + }, + validationOptions + ); +} diff --git a/src/decorator/IsInt.ts b/src/decorator/typechecker/IsInt.ts similarity index 82% rename from src/decorator/IsInt.ts rename to src/decorator/typechecker/IsInt.ts index 67c9ea1664..25bbb06612 100644 --- a/src/decorator/IsInt.ts +++ b/src/decorator/typechecker/IsInt.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const IS_INT = "isInt"; diff --git a/src/decorator/IsNumber.ts b/src/decorator/typechecker/IsNumber.ts similarity index 89% rename from src/decorator/IsNumber.ts rename to src/decorator/typechecker/IsNumber.ts index faef169f83..0a68ff8cf5 100644 --- a/src/decorator/IsNumber.ts +++ b/src/decorator/typechecker/IsNumber.ts @@ -1,5 +1,5 @@ -import {ValidationOptions} from "./ValidationOptions"; -import {buildMessage, ValidateBy} from "./ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; export const IS_NUMBER = "isNumber"; diff --git a/src/decorator/IsString.ts b/src/decorator/typechecker/IsString.ts similarity index 83% rename from src/decorator/IsString.ts rename to src/decorator/typechecker/IsString.ts index bd110064ea..532c04c036 100644 --- a/src/decorator/IsString.ts +++ b/src/decorator/typechecker/IsString.ts @@ -1,5 +1,5 @@ -import {buildMessage, ValidateBy} from "./ValidateBy"; -import {ValidationOptions} from "./ValidationOptions"; +import {buildMessage, ValidateBy} from "../ValidateBy"; +import {ValidationOptions} from "../ValidationOptions"; export const IS_STRING = "isString"; diff --git a/src/validation-schema/ValidationSchemaToMetadataTransformer.ts b/src/validation-schema/ValidationSchemaToMetadataTransformer.ts index 6a3b6b277a..ad4063efcc 100644 --- a/src/validation-schema/ValidationSchemaToMetadataTransformer.ts +++ b/src/validation-schema/ValidationSchemaToMetadataTransformer.ts @@ -2,7 +2,6 @@ import {ValidationSchema} from "./ValidationSchema"; import {ValidationMetadata} from "../metadata/ValidationMetadata"; import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs"; import {ValidationOptions} from "../decorator/ValidationOptions"; -import {ValidationTypes} from "../validation/ValidationTypes"; /** * Used to transform validation schemas to validation metadatas. @@ -13,9 +12,6 @@ export class ValidationSchemaToMetadataTransformer { const metadatas: ValidationMetadata[] = []; Object.keys(schema.properties).forEach(property => { schema.properties[property].forEach(validation => { - if (!ValidationTypes.isValid(validation.type)) - throw new Error(`Validation schema ${schema.name}#${property} as incorrect type ${validation.type}`); - const validationOptions: ValidationOptions = { message: validation.message, groups: validation.groups, diff --git a/src/validation/ValidationExecutor.ts b/src/validation/ValidationExecutor.ts index 77bad4f488..741fcc9676 100644 --- a/src/validation/ValidationExecutor.ts +++ b/src/validation/ValidationExecutor.ts @@ -105,14 +105,13 @@ export class ValidationExecutor { } // handle IS_DEFINED validation type the special way - it should work no matter skipMissingProperties is set or not - this.defaultValidations(object, value, definedMetadatas, validationError.constraints); + this.runValidations(object, value, definedMetadatas, validationError.constraints); if ((value === null || value === undefined) && this.validatorOptions && this.validatorOptions.skipMissingProperties === true) { return; } - this.defaultValidations(object, value, metadatas, validationError.constraints); - this.customValidations(object, value, customValidationMetadatas, validationError.constraints); + this.runValidations(object, value, customValidationMetadatas, validationError.constraints); this.nestedValidations(value, nestedValidationMetadatas, validationError.children); this.mapContexts(object, value, metadatas, validationError); @@ -203,28 +202,7 @@ export class ValidationExecutor { .reduce((resultA, resultB) => resultA && resultB, true); } - private defaultValidations(object: Object, - value: any, - metadatas: ValidationMetadata[], - errorMap: { [key: string]: string }) { - return metadatas - .filter(metadata => { - if (metadata.each) { - if (value instanceof Array) { - return !value.every((subValue: any) => this.validator.validateValueByMetadata(subValue, metadata)); - } - - } else { - return !this.validator.validateValueByMetadata(value, metadata); - } - }) - .forEach(metadata => { - const [key, message] = this.createValidationError(object, value, metadata); - errorMap[key] = message; - }); - } - - private customValidations(object: Object, + private runValidations(object: Object, value: any, metadatas: ValidationMetadata[], errorMap: { [key: string]: string }) { @@ -233,8 +211,9 @@ export class ValidationExecutor { getFromContainer(MetadataStorage) .getTargetValidatorConstraints(metadata.constraintCls) .forEach(customConstraintMetadata => { - if (customConstraintMetadata.async && this.ignoreAsyncValidations) + if (customConstraintMetadata.async && this.ignoreAsyncValidations) { return; + } const validationArguments: ValidationArguments = { targetName: object.constructor ? (object.constructor as any).name : undefined, @@ -269,7 +248,9 @@ export class ValidationExecutor { } metadatas.forEach(metadata => { - if (metadata.type !== ValidationTypes.NESTED_VALIDATION) return; + if (metadata.type !== ValidationTypes.NESTED_VALIDATION) { + return; + } const targetSchema = typeof metadata.target === "string" ? metadata.target as string : undefined; if (value instanceof Array) { @@ -340,8 +321,7 @@ export class ValidationExecutor { message = customValidatorMetadata.instance.defaultMessage(validationArguments); } - if (!message) - message = ValidationTypes.getMessage(type, metadata.each); + message = message || ""; } const messageString = ValidationUtils.replaceMessageSpecialTokens(message, validationArguments); diff --git a/src/validation/ValidationTypes.ts b/src/validation/ValidationTypes.ts index 7b242badab..6f5f98b996 100644 --- a/src/validation/ValidationTypes.ts +++ b/src/validation/ValidationTypes.ts @@ -1,5 +1,3 @@ -import {ValidationArguments} from "./ValidationArguments"; - /** * Validation types. */ @@ -10,67 +8,6 @@ export class ValidationTypes { static NESTED_VALIDATION = "nestedValidation"; static CONDITIONAL_VALIDATION = "conditionalValidation"; static WHITELIST = "whitelistValidation"; - // FIXME: delete? static IS_DEFINED = "isDefined"; - /* array checkers */ - static ARRAY_CONTAINS = "arrayContains"; - static ARRAY_NOT_CONTAINS = "arrayNotContains"; - static ARRAY_NOT_EMPTY = "arrayNotEmpty"; - static ARRAY_MIN_SIZE = "arrayMinSize"; - static ARRAY_MAX_SIZE = "arrayMaxSize"; - static ARRAY_UNIQUE = "arrayUnique"; - - /* object chekers */ - static IS_INSTANCE = "isInstance"; - - /** - * Checks if validation type is valid. - */ - static isValid(type: string) { - return type !== "isValid" && - type !== "getMessage" && - Object.keys(this).map(key => (this as any)[key]).indexOf(type) !== -1; - } - - /** - * Gets default validation error message for the given validation type. - */ - static getMessage(type: string, isEach: boolean): string|((args: ValidationArguments) => string) { - const eachPrefix = isEach ? "each value in " : ""; - switch (type) { - - /* system chceck */ - case this.NESTED_VALIDATION: - return eachPrefix + "nested property $property must be either object or array"; - case this.IS_DEFINED: - return eachPrefix + "$property should not be null or undefined"; - - /* array checkers */ - case this.ARRAY_CONTAINS: - return eachPrefix + "$property must contain $constraint1 values"; - case this.ARRAY_NOT_CONTAINS: - return eachPrefix + "$property should not contain $constraint1 values"; - case this.ARRAY_NOT_EMPTY: - return eachPrefix + "$property should not be empty"; - case this.ARRAY_MIN_SIZE: - return eachPrefix + "$property must contain at least $constraint1 elements"; - case this.ARRAY_MAX_SIZE: - return eachPrefix + "$property must contain not more than $constraint1 elements"; - case this.ARRAY_UNIQUE: - return eachPrefix + "All $property's elements must be unique"; - - case this.IS_INSTANCE: - return (args: ValidationArguments) => { - if (args.constraints[0]) { - return eachPrefix + `$property must be an instance of ${args.constraints[0].name}`; - } else { - return eachPrefix + `${this.IS_INSTANCE} decorator expects and object as value, but got falsy value.`; - } - }; - default: - return ""; - } - } - } diff --git a/src/validation/Validator.ts b/src/validation/Validator.ts index 5e5fb3a0dc..0322db1346 100644 --- a/src/validation/Validator.ts +++ b/src/validation/Validator.ts @@ -1,30 +1,18 @@ -import {ValidationMetadata} from "../metadata/ValidationMetadata"; -import {ValidationTypes} from "./ValidationTypes"; import {ValidationError} from "./ValidationError"; -import {IsNumberOptions} from "./ValidationTypeOptions"; import {ValidatorOptions} from "./ValidatorOptions"; import {ValidationExecutor} from "./ValidationExecutor"; import {ValidationOptions} from "../decorator/ValidationOptions"; -import {length} from "../decorator/Length"; -import {matches} from "../decorator/Matches"; /** * Validator performs validation of the given object based on its metadata. */ export class Validator { - // ------------------------------------------------------------------------- - // Private Properties - // ------------------------------------------------------------------------- - - // FIXME: other goal of modularization: remove this!!!! - private validatorJs = require("validator"); - /** * Performs validation of the given object based on decorators or validation schema. * Common method for `validateOrReject` and `validate` methods. */ - private coreValidate(objectOrSchemaName: Object|string, objectOrValidationOptions: Object|ValidationOptions, maybeValidatorOptions?: ValidatorOptions): Promise { + private coreValidate(objectOrSchemaName: Object | string, objectOrValidationOptions: Object | ValidationOptions, maybeValidatorOptions?: ValidatorOptions): Promise { const object = typeof objectOrSchemaName === "string" ? objectOrValidationOptions as Object : objectOrSchemaName as Object; const options = typeof objectOrSchemaName === "string" ? maybeValidatorOptions : objectOrValidationOptions as ValidationOptions; const schema = typeof objectOrSchemaName === "string" ? objectOrSchemaName as string : undefined; @@ -55,7 +43,7 @@ export class Validator { /** * Performs validation of the given object based on decorators or validation schema. */ - validate(objectOrSchemaName: Object|string, objectOrValidationOptions: Object|ValidationOptions, maybeValidatorOptions?: ValidatorOptions): Promise { + validate(objectOrSchemaName: Object | string, objectOrValidationOptions: Object | ValidationOptions, maybeValidatorOptions?: ValidatorOptions): Promise { return this.coreValidate(objectOrSchemaName, objectOrValidationOptions, maybeValidatorOptions); } @@ -72,10 +60,12 @@ export class Validator { /** * Performs validation of the given object based on decorators or validation schema and reject on error. */ - async validateOrReject(objectOrSchemaName: Object|string, objectOrValidationOptions: Object|ValidationOptions, maybeValidatorOptions?: ValidatorOptions): Promise { + async validateOrReject(objectOrSchemaName: Object | string, objectOrValidationOptions: Object | ValidationOptions, maybeValidatorOptions?: ValidatorOptions): Promise { const errors = await this.coreValidate(objectOrSchemaName, objectOrValidationOptions, maybeValidatorOptions); - if (errors.length) + if (errors.length) { return Promise.reject(errors); + } + // FIXME: else??? } /** @@ -92,7 +82,7 @@ export class Validator { /** * Performs validation of the given object based on decorators or validation schema. */ - validateSync(objectOrSchemaName: Object|string, objectOrValidationOptions: Object|ValidationOptions, maybeValidatorOptions?: ValidatorOptions): ValidationError[] { + validateSync(objectOrSchemaName: Object | string, objectOrValidationOptions: Object | ValidationOptions, maybeValidatorOptions?: ValidatorOptions): ValidationError[] { const object = typeof objectOrSchemaName === "string" ? objectOrValidationOptions as Object : objectOrSchemaName as Object; const options = typeof objectOrSchemaName === "string" ? maybeValidatorOptions : objectOrValidationOptions as ValidationOptions; const schema = typeof objectOrSchemaName === "string" ? objectOrSchemaName as string : undefined; @@ -104,130 +94,5 @@ export class Validator { return executor.stripEmptyErrors(validationErrors); } - /** - * Performs validation of the given object based on the given ValidationMetadata object. - */ - validateValueByMetadata(value: any, metadata: ValidationMetadata): boolean { - switch (metadata.type) { - /* common checkers */ - case ValidationTypes.IS_DEFINED: - return this.isDefined(value); - - /* array checkers */ - case ValidationTypes.ARRAY_CONTAINS: - return this.arrayContains(value, metadata.constraints[0]); - case ValidationTypes.ARRAY_NOT_CONTAINS: - return this.arrayNotContains(value, metadata.constraints[0]); - case ValidationTypes.ARRAY_NOT_EMPTY: - return this.arrayNotEmpty(value); - case ValidationTypes.ARRAY_MIN_SIZE: - return this.arrayMinSize(value, metadata.constraints[0]); - case ValidationTypes.ARRAY_MAX_SIZE: - return this.arrayMaxSize(value, metadata.constraints[0]); - case ValidationTypes.ARRAY_UNIQUE: - return this.arrayUnique(value); - - case ValidationTypes.IS_INSTANCE: - return this.isInstance(value, metadata.constraints[0]); - } - return true; - } - - // ------------------------------------------------------------------------- - // Validation Methods: common checkers - // ------------------------------------------------------------------------- - - /** - * Checks if value is defined (!== undefined, !== null). - */ - isDefined(value: any): boolean { - return value !== undefined && value !== null; - } - - // ------------------------------------------------------------------------- - // Validation Methods: string checkers - // ------------------------------------------------------------------------- - - - - // ------------------------------------------------------------------------- - // Validation Methods: array checkers - // ------------------------------------------------------------------------- - - /** - * Checks if array contains all values from the given array of values. - * If null or undefined is given then this function returns false. - */ - arrayContains(array: any[], values: any[]) { - if (!(array instanceof Array)) - return false; - - return !array || values.every(value => array.indexOf(value) !== -1); - } - - /** - * Checks if array does not contain any of the given values. - * If null or undefined is given then this function returns false. - */ - arrayNotContains(array: any[], values: any[]) { - if (!(array instanceof Array)) - return false; - - return !array || values.every(value => array.indexOf(value) === -1); - } - - /** - * Checks if given array is not empty. - * If null or undefined is given then this function returns false. - */ - arrayNotEmpty(array: any[]) { - if (!(array instanceof Array)) - return false; - - return array instanceof Array && array.length > 0; - } - - /** - * Checks if array's length is as minimal this number. - * If null or undefined is given then this function returns false. - */ - arrayMinSize(array: any[], min: number) { - if (!(array instanceof Array)) - return false; - - return array instanceof Array && array.length >= min; - } - - /** - * Checks if array's length is as maximal this number. - * If null or undefined is given then this function returns false. - */ - arrayMaxSize(array: any[], max: number) { - if (!(array instanceof Array)) - return false; - - return array instanceof Array && array.length <= max; - } - - /** - * Checks if all array's values are unique. Comparison for objects is reference-based. - * If null or undefined is given then this function returns false. - */ - arrayUnique(array: any[]) { - if (!(array instanceof Array)) - return false; - - const uniqueItems = array.filter((a, b, c) => c.indexOf(a) === b); - return array.length === uniqueItems.length; - } - - /** - * Checks if the value is an instance of the specified object. - */ - isInstance(object: any, targetTypeConstructor: new (...args: any[]) => any) { - return targetTypeConstructor - && typeof targetTypeConstructor === "function" - && object instanceof targetTypeConstructor; - } } diff --git a/test/functional/conditional-validation.spec.ts b/test/functional/conditional-validation.spec.ts index 5690881ba1..492650c6d6 100644 --- a/test/functional/conditional-validation.spec.ts +++ b/test/functional/conditional-validation.spec.ts @@ -1,12 +1,12 @@ import "es6-shim"; -import {ValidateIf, IsOptional} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; -import {ValidatorOptions} from "../../src/validation/ValidatorOptions"; -import {expect, should, use } from "chai"; +import {expect, should, use} from "chai"; import * as chaiAsPromised from "chai-as-promised"; -import {Equals} from "../../src/decorator/Equals"; -import {IsNotEmpty} from "../../src/decorator/IsNotEmpty"; +import {Equals} from "../../src/decorator/common/Equals"; +import {IsNotEmpty} from "../../src/decorator/common/IsNotEmpty"; +import {ValidateIf} from "../../src/decorator/system/ValidateIf"; +import {IsOptional} from "../../src/decorator/system/IsOptional"; should(); use(chaiAsPromised); @@ -21,8 +21,8 @@ const validator = new Validator(); // Specifications: common decorators // ------------------------------------------------------------------------- -describe("conditional validation", function() { - it("shouldn't validate a property when the condition is false", function() { +describe("conditional validation", function () { + it("shouldn't validate a property when the condition is false", function () { class MyClass { @ValidateIf(o => false) @IsNotEmpty() @@ -35,7 +35,7 @@ describe("conditional validation", function() { }); }); - it("should validate a property when the condition is true", function() { + it("should validate a property when the condition is true", function () { class MyClass { @ValidateIf(o => true) @IsNotEmpty() @@ -47,12 +47,12 @@ describe("conditional validation", function() { errors.length.should.be.equal(1); errors[0].target.should.be.equal(model); errors[0].property.should.be.equal("title"); - errors[0].constraints.should.be.eql({ isNotEmpty: "title should not be empty" }); + errors[0].constraints.should.be.eql({isNotEmpty: "title should not be empty"}); errors[0].value.should.be.equal(""); }); }); - it("should pass the object being validated to the condition function", function() { + it("should pass the object being validated to the condition function", function () { class MyClass { @ValidateIf(o => { expect(o).to.be.instanceOf(MyClass); @@ -81,7 +81,7 @@ describe("conditional validation", function() { errors.length.should.be.equal(1); errors[0].target.should.be.equal(model); errors[0].property.should.be.equal("title"); - errors[0].constraints.should.be.eql({ equals: "title must be equal to test" }); + errors[0].constraints.should.be.eql({equals: "title must be equal to test"}); errors[0].value.should.be.equal(""); }); }); @@ -98,7 +98,7 @@ describe("conditional validation", function() { errors.length.should.be.equal(1); errors[0].target.should.be.equal(model); errors[0].property.should.be.equal("title"); - errors[0].constraints.should.be.eql({ equals: "title must be equal to test" }); + errors[0].constraints.should.be.eql({equals: "title must be equal to test"}); errors[0].value.should.be.equal("bad_value"); }); }); diff --git a/test/functional/inherited-validation.spec.ts b/test/functional/inherited-validation.spec.ts index 7dfe62a83f..94dc75fe91 100644 --- a/test/functional/inherited-validation.spec.ts +++ b/test/functional/inherited-validation.spec.ts @@ -4,8 +4,8 @@ import {Validator} from "../../src/validation/Validator"; import {should, use } from "chai"; import * as chaiAsPromised from "chai-as-promised"; -import {Contains} from "../../src/decorator/Contains"; -import {MinLength} from "../../src/decorator/MinLength"; +import {Contains} from "../../src/decorator/string/Contains"; +import {MinLength} from "../../src/decorator/string/MinLength"; should(); use(chaiAsPromised); diff --git a/test/functional/nested-validation.spec.ts b/test/functional/nested-validation.spec.ts index 46df9c8ffb..fe6c5d23af 100644 --- a/test/functional/nested-validation.spec.ts +++ b/test/functional/nested-validation.spec.ts @@ -1,5 +1,4 @@ import "es6-shim"; -import {IsDefined, ValidateNested} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; import {expect} from "chai"; import {ValidationTypes} from "../../src/validation/ValidationTypes"; @@ -7,8 +6,10 @@ import {ValidationTypes} from "../../src/validation/ValidationTypes"; import {should, use } from "chai"; import * as chaiAsPromised from "chai-as-promised"; -import {Contains} from "../../src/decorator/Contains"; -import {MinLength} from "../../src/decorator/MinLength"; +import {Contains} from "../../src/decorator/string/Contains"; +import {MinLength} from "../../src/decorator/string/MinLength"; +import {IsDefined} from "../../src/decorator/system/IsDefined"; +import {ValidateNested} from "../../src/decorator/system/ValidateNested"; should(); use(chaiAsPromised); diff --git a/test/functional/reject-validation.spec.ts b/test/functional/reject-validation.spec.ts index c2432fd414..3210b36106 100644 --- a/test/functional/reject-validation.spec.ts +++ b/test/functional/reject-validation.spec.ts @@ -7,7 +7,7 @@ import { expect } from "chai"; import {should, use } from "chai"; import * as chaiAsPromised from "chai-as-promised"; -import {Contains} from "../../src/decorator/Contains"; +import {Contains} from "../../src/decorator/string/Contains"; should(); use(chaiAsPromised); diff --git a/test/functional/sync-validation.ts b/test/functional/sync-validation.ts index 7c4470fc13..f57dd91bd2 100644 --- a/test/functional/sync-validation.ts +++ b/test/functional/sync-validation.ts @@ -3,7 +3,7 @@ import {Validator} from "../../src/validation/Validator"; import {ValidationArguments} from "../../src/validation/ValidationArguments"; import {registerDecorator} from "../../src/register-decorator"; import {ValidationOptions} from "../../src/decorator/ValidationOptions"; -import {IsNotEmpty} from "../../src/decorator/IsNotEmpty"; +import {IsNotEmpty} from "../../src/decorator/common/IsNotEmpty"; import {Validate} from "../../src/decorator/Validate"; import {ValidatorConstraint} from "../../src/decorator/ValidatorConstraint"; import {ValidatorConstraintInterface} from "../../src/validation/ValidatorConstraintInterface"; diff --git a/test/functional/validation-error.spec.ts b/test/functional/validation-error.spec.ts index d9bacf1afc..cf74c44529 100644 --- a/test/functional/validation-error.spec.ts +++ b/test/functional/validation-error.spec.ts @@ -1,14 +1,13 @@ import "es6-shim"; -import { IsOptional, ValidateNested} from "../../src/decorator/decorators"; -import { Validator } from "../../src/validation/Validator"; -import { expect } from "chai"; - -import {should, use } from "chai"; +import {Validator} from "../../src/validation/Validator"; +import {should, use} from "chai"; import * as chaiAsPromised from "chai-as-promised"; -import {IsString} from "../../src/decorator/IsString"; -import {IsUrl} from "../../src/decorator/IsUrl"; -import {MinLength} from "../../src/decorator/MinLength"; +import {IsString} from "../../src/decorator/typechecker/IsString"; +import {IsUrl} from "../../src/decorator/string/IsUrl"; +import {MinLength} from "../../src/decorator/string/MinLength"; +import {IsOptional} from "../../src/decorator/system/IsOptional"; +import {ValidateNested} from "../../src/decorator/system/ValidateNested"; should(); use(chaiAsPromised); @@ -26,61 +25,62 @@ const validator = new Validator(); * - testing arrays * - testing color codes? */ -describe("ValidationError", function () { - it("should correctly log error message without ANSI escape codes", async function () { - class NestedClass { - - @IsString() - public name: string; - - @IsUrl() - public url: string; - - @IsOptional() - @ValidateNested() - public insideNested: NestedClass; - - constructor(url: string, name: any, insideNested?: NestedClass) { - this.url = url; - this.name = name; - this.insideNested = insideNested; - } - - } - class RootClass { - @IsString() - @MinLength(15) - public title: string; - - @ValidateNested() - public nestedObj: NestedClass; - - @ValidateNested({ each: true }) - public nestedArr: NestedClass[]; - - constructor() { - this.title = (5 as any); - this.nestedObj = new NestedClass("invalid-url", 5, new NestedClass("invalid-url", 5)); - this.nestedArr = [new NestedClass("invalid-url", 5), new NestedClass("invalid-url", 5)]; - } - } - - const validationErrors = await validator.validate(new RootClass()); - - validationErrors[0].toString().should.be.equal("An instance of RootClass has failed the validation:\n" + - " - property title has failed the following constraints: minLength, isString \n"); - - validationErrors[1].toString().should.be.equal("An instance of RootClass has failed the validation:\n" + - " - property nestedObj.name has failed the following constraints: isString \n" + - " - property nestedObj.url has failed the following constraints: isUrl \n" + - " - property nestedObj.insideNested.name has failed the following constraints: isString \n" + - " - property nestedObj.insideNested.url has failed the following constraints: isUrl \n"); - - validationErrors[2].toString().should.be.equal("An instance of RootClass has failed the validation:\n" + - " - property nestedArr[0].name has failed the following constraints: isString \n" + - " - property nestedArr[0].url has failed the following constraints: isUrl \n" + - " - property nestedArr[1].name has failed the following constraints: isString \n" + - " - property nestedArr[1].url has failed the following constraints: isUrl \n"); - }); +describe("ValidationError", function () { + it("should correctly log error message without ANSI escape codes", async function () { + class NestedClass { + + @IsString() + public name: string; + + @IsUrl() + public url: string; + + @IsOptional() + @ValidateNested() + public insideNested: NestedClass; + + constructor(url: string, name: any, insideNested?: NestedClass) { + this.url = url; + this.name = name; + this.insideNested = insideNested; + } + + } + + class RootClass { + @IsString() + @MinLength(15) + public title: string; + + @ValidateNested() + public nestedObj: NestedClass; + + @ValidateNested({each: true}) + public nestedArr: NestedClass[]; + + constructor() { + this.title = (5 as any); + this.nestedObj = new NestedClass("invalid-url", 5, new NestedClass("invalid-url", 5)); + this.nestedArr = [new NestedClass("invalid-url", 5), new NestedClass("invalid-url", 5)]; + } + } + + const validationErrors = await validator.validate(new RootClass()); + + validationErrors[0].toString().should.be.equal("An instance of RootClass has failed the validation:\n" + + " - property title has failed the following constraints: minLength, isString \n"); + + validationErrors[1].toString().should.be.equal("An instance of RootClass has failed the validation:\n" + + " - property nestedObj.name has failed the following constraints: isString \n" + + " - property nestedObj.url has failed the following constraints: isUrl \n" + + " - property nestedObj.insideNested.name has failed the following constraints: isString \n" + + " - property nestedObj.insideNested.url has failed the following constraints: isUrl \n"); + + validationErrors[2].toString().should.be.equal("An instance of RootClass has failed the validation:\n" + + " - property nestedArr[0].name has failed the following constraints: isString \n" + + " - property nestedArr[0].url has failed the following constraints: isUrl \n" + + " - property nestedArr[1].name has failed the following constraints: isString \n" + + " - property nestedArr[1].url has failed the following constraints: isUrl \n"); + }); }); diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts index dbfabd36e7..f92b214252 100644 --- a/test/functional/validation-functions-and-decorators.spec.ts +++ b/test/functional/validation-functions-and-decorators.spec.ts @@ -1,79 +1,77 @@ import "es6-shim"; import {expect} from "chai"; -import { - ArrayNotEmpty, - ArrayMinSize, - ArrayMaxSize, - IsDefined, - ArrayContains, - ArrayNotContains, - ArrayUnique, - IsInstance -} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; import {ValidatorOptions} from "../../src/validation/ValidatorOptions"; import {should, use } from "chai"; import * as chaiAsPromised from "chai-as-promised"; -import {equals, Equals} from "../../src/decorator/Equals"; -import {notEquals, NotEquals} from "../../src/decorator/NotEquals"; -import {IsEmpty, isEmpty} from "../../src/decorator/IsEmpty"; -import {isNotEmpty, IsNotEmpty} from "../../src/decorator/IsNotEmpty"; -import {IsIn, isIn} from "../../src/decorator/IsIn"; -import {IsNotIn, isNotIn} from "../../src/decorator/IsNotIn"; -import {IsPhoneNumber} from "../../src/decorator/IsPhoneNumber"; -import {IsBoolean, isBoolean} from "../../src/decorator/IsBoolean"; -import {IsDate, isDate} from "../../src/decorator/IsDate"; -import {IsNumber, isNumber} from "../../src/decorator/IsNumber"; -import {IsInt, isInt} from "../../src/decorator/IsInt"; -import {IsString, isString} from "../../src/decorator/IsString"; -import {IsDateString, isDateString} from "../../src/decorator/IsDateString"; -import {IsArray, isArray} from "../../src/decorator/IsArray"; -import {isEnum, IsEnum} from "../../src/decorator/IsEnum"; -import {IsDivisibleBy, isDivisibleBy} from "../../src/decorator/IsDivisibleBy"; -import {IsPositive, isPositive} from "../../src/decorator/IsPositive"; -import {isNegative, IsNegative} from "../../src/decorator/IsNegative"; -import {Min, min} from "../../src/decorator/Min"; -import {Max, max} from "../../src/decorator/Max"; -import {minDate, MinDate} from "../../src/decorator/MinDate"; -import {maxDate, MaxDate} from "../../src/decorator/MaxDate"; -import {isBooleanString, IsBooleanString} from "../../src/decorator/IsBooleanString"; -import {IsNumberString, isNumberString} from "../../src/decorator/IsNumberString"; -import {Contains, contains} from "../../src/decorator/Contains"; -import {NotContains, notContains} from "../../src/decorator/NotContains"; -import {IsAlpha, isAlpha} from "../../src/decorator/IsAlpha"; -import {isAlphanumeric, IsAlphanumeric} from "../../src/decorator/IsAlphanumeric"; -import {IsAscii, isAscii} from "../../src/decorator/IsAscii"; -import {IsBase64, isBase64} from "../../src/decorator/IsBase64"; -import {IsByteLength, isByteLength} from "../../src/decorator/IsByteLength"; -import {IsCreditCard, isCreditCard} from "../../src/decorator/IsCreditCard"; -import {IsCurrency, isCurrency} from "../../src/decorator/IsCurrency"; -import {IsEmail, isEmail} from "../../src/decorator/IsEmail"; -import {isFQDN, IsFQDN} from "../../src/decorator/IsFQDN"; -import {isFullWidth, IsFullWidth} from "../../src/decorator/IsFullWidth"; -import {isHalfWidth, IsHalfWidth} from "../../src/decorator/IsHalfWidth"; -import {IsVariableWidth, isVariableWidth} from "../../src/decorator/IsVariableWidth"; -import {isHexColor, IsHexColor} from "../../src/decorator/IsHexColor"; -import {isHexadecimal, IsHexadecimal} from "../../src/decorator/IsHexadecimal"; -import {isIP, IsIP} from "../../src/decorator/IsIP"; -import {isISBN, IsISBN} from "../../src/decorator/IsISBN"; -import {isISIN, IsISIN} from "../../src/decorator/IsISIN"; -import {IsISO8601, isISO8601} from "../../src/decorator/IsISO8601"; -import {IsJSON, isJSON} from "../../src/decorator/IsJSON"; -import {isLowercase, IsLowercase} from "../../src/decorator/IsLowercase"; -import {IsMobilePhone} from "../../src/decorator/IsMobilePhone"; -import {isMongoId, IsMongoId} from "../../src/decorator/IsMongoId"; -import {IsMultibyte, isMultibyte} from "../../src/decorator/IsMultibyte"; -import {isSurrogatePair, IsSurrogatePair} from "../../src/decorator/IsSurrogatePair"; -import {IsUrl, isURL} from "../../src/decorator/IsUrl"; -import {IsUUID, isUUID} from "../../src/decorator/IsUUID"; -import {IsUppercase, isUppercase} from "../../src/decorator/IsUppercase"; -import {length, Length} from "../../src/decorator/Length"; -import {MinLength, minLength} from "../../src/decorator/MinLength"; -import {maxLength, MaxLength} from "../../src/decorator/MaxLength"; -import {Matches, matches} from "../../src/decorator/Matches"; -import {IsMilitaryTime} from "../../src/decorator/IsMilitaryTime"; +import {equals, Equals} from "../../src/decorator/common/Equals"; +import {notEquals, NotEquals} from "../../src/decorator/common/NotEquals"; +import {IsEmpty, isEmpty} from "../../src/decorator/common/IsEmpty"; +import {isNotEmpty, IsNotEmpty} from "../../src/decorator/common/IsNotEmpty"; +import {IsIn, isIn} from "../../src/decorator/common/IsIn"; +import {IsNotIn, isNotIn} from "../../src/decorator/common/IsNotIn"; +import {IsPhoneNumber} from "../../src/decorator/string/IsPhoneNumber"; +import {IsBoolean, isBoolean} from "../../src/decorator/typechecker/IsBoolean"; +import {IsDate, isDate} from "../../src/decorator/typechecker/IsDate"; +import {IsNumber, isNumber} from "../../src/decorator/typechecker/IsNumber"; +import {IsInt, isInt} from "../../src/decorator/typechecker/IsInt"; +import {IsString, isString} from "../../src/decorator/typechecker/IsString"; +import {IsDateString, isDateString} from "../../src/decorator/string-as-type/IsDateString"; +import {IsArray, isArray} from "../../src/decorator/typechecker/IsArray"; +import {isEnum, IsEnum} from "../../src/decorator/typechecker/IsEnum"; +import {IsDivisibleBy, isDivisibleBy} from "../../src/decorator/number/IsDivisibleBy"; +import {IsPositive, isPositive} from "../../src/decorator/number/IsPositive"; +import {isNegative, IsNegative} from "../../src/decorator/number/IsNegative"; +import {Min, min} from "../../src/decorator/number/Min"; +import {Max, max} from "../../src/decorator/number/Max"; +import {minDate, MinDate} from "../../src/decorator/date/MinDate"; +import {maxDate, MaxDate} from "../../src/decorator/date/MaxDate"; +import {isBooleanString, IsBooleanString} from "../../src/decorator/string-as-type/IsBooleanString"; +import {IsNumberString, isNumberString} from "../../src/decorator/string-as-type/IsNumberString"; +import {Contains, contains} from "../../src/decorator/string/Contains"; +import {NotContains, notContains} from "../../src/decorator/string/NotContains"; +import {IsAlpha, isAlpha} from "../../src/decorator/string/IsAlpha"; +import {isAlphanumeric, IsAlphanumeric} from "../../src/decorator/string/IsAlphanumeric"; +import {IsAscii, isAscii} from "../../src/decorator/string/IsAscii"; +import {IsBase64, isBase64} from "../../src/decorator/string/IsBase64"; +import {IsByteLength, isByteLength} from "../../src/decorator/string/IsByteLength"; +import {IsCreditCard, isCreditCard} from "../../src/decorator/string/IsCreditCard"; +import {IsCurrency, isCurrency} from "../../src/decorator/string/IsCurrency"; +import {IsEmail, isEmail} from "../../src/decorator/string/IsEmail"; +import {isFQDN, IsFQDN} from "../../src/decorator/string/IsFQDN"; +import {isFullWidth, IsFullWidth} from "../../src/decorator/string/IsFullWidth"; +import {isHalfWidth, IsHalfWidth} from "../../src/decorator/string/IsHalfWidth"; +import {IsVariableWidth, isVariableWidth} from "../../src/decorator/string/IsVariableWidth"; +import {isHexColor, IsHexColor} from "../../src/decorator/string/IsHexColor"; +import {isHexadecimal, IsHexadecimal} from "../../src/decorator/string/IsHexadecimal"; +import {isIP, IsIP} from "../../src/decorator/string/IsIP"; +import {isISBN, IsISBN} from "../../src/decorator/string/IsISBN"; +import {isISIN, IsISIN} from "../../src/decorator/string/IsISIN"; +import {IsISO8601, isISO8601} from "../../src/decorator/string/IsISO8601"; +import {IsJSON, isJSON} from "../../src/decorator/string/IsJSON"; +import {isLowercase, IsLowercase} from "../../src/decorator/string/IsLowercase"; +import {IsMobilePhone} from "../../src/decorator/string/IsMobilePhone"; +import {isMongoId, IsMongoId} from "../../src/decorator/string/IsMongoId"; +import {IsMultibyte, isMultibyte} from "../../src/decorator/string/IsMultibyte"; +import {isSurrogatePair, IsSurrogatePair} from "../../src/decorator/string/IsSurrogatePair"; +import {IsUrl, isURL} from "../../src/decorator/string/IsUrl"; +import {IsUUID, isUUID} from "../../src/decorator/string/IsUUID"; +import {IsUppercase, isUppercase} from "../../src/decorator/string/IsUppercase"; +import {length, Length} from "../../src/decorator/string/Length"; +import {MinLength, minLength} from "../../src/decorator/string/MinLength"; +import {maxLength, MaxLength} from "../../src/decorator/string/MaxLength"; +import {Matches, matches} from "../../src/decorator/string/Matches"; +import {IsMilitaryTime} from "../../src/decorator/string/IsMilitaryTime"; +import {ArrayContains, arrayContains} from "../../src/decorator/array/ArrayContains"; +import {ArrayNotContains, arrayNotContains} from "../../src/decorator/array/ArrayNotContains"; +import {arrayNotEmpty, ArrayNotEmpty} from "../../src/decorator/array/ArrayNotEmpty"; +import {arrayMinSize, ArrayMinSize} from "../../src/decorator/array/ArrayMinSize"; +import {ArrayMaxSize, arrayMaxSize} from "../../src/decorator/array/ArrayMaxSize"; +import {ArrayUnique, arrayUnique} from "../../src/decorator/array/ArrayUnique"; +import {IsInstance, isInstance} from "../../src/decorator/typechecker/IsInstance"; +import {isDefined, IsDefined} from "../../src/decorator/system/IsDefined"; should(); use(chaiAsPromised); @@ -164,11 +162,11 @@ describe("IsDefined", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isDefined(value).should.be.true); + validValues.forEach(value => isDefined(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isDefined(value).should.be.false); + invalidValues.forEach(value => isDefined(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -3038,11 +3036,11 @@ describe("ArrayContains", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.arrayContains(value, constraint).should.be.true); + validValues.forEach(value => arrayContains(value, constraint).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.arrayContains(value, constraint).should.be.false); + invalidValues.forEach(value => arrayContains(value, constraint).should.be.false); }); it("should return error object with proper data", function(done) { @@ -3073,11 +3071,11 @@ describe("ArrayNotContains", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.arrayNotContains(value, constraint).should.be.true); + validValues.forEach(value => arrayNotContains(value, constraint).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.arrayNotContains(value, constraint).should.be.false); + invalidValues.forEach(value => arrayNotContains(value, constraint).should.be.false); }); it("should return error object with proper data", function(done) { @@ -3107,11 +3105,11 @@ describe("ArrayNotEmpty", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.arrayNotEmpty(value).should.be.true); + validValues.forEach(value => arrayNotEmpty(value).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.arrayNotEmpty(value).should.be.false); + invalidValues.forEach(value => arrayNotEmpty(value).should.be.false); }); it("should return error object with proper data", function(done) { @@ -3142,11 +3140,11 @@ describe("ArrayMinSize", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.arrayMinSize(value, constraint).should.be.true); + validValues.forEach(value => arrayMinSize(value, constraint).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.arrayMinSize(value, constraint).should.be.false); + invalidValues.forEach(value => arrayMinSize(value, constraint).should.be.false); }); it("should return error object with proper data", function(done) { @@ -3177,11 +3175,11 @@ describe("ArrayMaxSize", function() { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.arrayMaxSize(value, constraint).should.be.true); + validValues.forEach(value => arrayMaxSize(value, constraint).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.arrayMaxSize(value, constraint).should.be.false); + invalidValues.forEach(value => arrayMaxSize(value, constraint).should.be.false); }); it("should return error object with proper data", function(done) { @@ -3211,11 +3209,11 @@ describe("ArrayUnique", function () { }); it("should not fail if method in validator said that its valid", function () { - validValues.forEach(value => validator.arrayUnique(value).should.be.true); + validValues.forEach(value => arrayUnique(value).should.be.true); }); it("should fail if method in validator said that its invalid", function () { - invalidValues.forEach(value => validator.arrayUnique(value).should.be.false); + invalidValues.forEach(value => arrayUnique(value).should.be.false); }); it("should return error object with proper data", function (done) { @@ -3248,11 +3246,11 @@ describe("isInstance", function () { }); it("should not fail if method in validator said that its valid", function() { - validValues.forEach(value => validator.isInstance(value, MySubClass).should.be.true); + validValues.forEach(value => isInstance(value, MySubClass).should.be.true); }); it("should fail if method in validator said that its invalid", function() { - invalidValues.forEach(value => validator.isInstance(value, MySubClass).should.be.false); + invalidValues.forEach(value => isInstance(value, MySubClass).should.be.false); }); it("should return error object with proper data", function(done) { diff --git a/test/functional/validation-options.spec.ts b/test/functional/validation-options.spec.ts index ea662829ee..b1dbb15452 100644 --- a/test/functional/validation-options.spec.ts +++ b/test/functional/validation-options.spec.ts @@ -1,12 +1,12 @@ import "es6-shim"; -import {ValidateNested} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; import {ValidationError} from "../../src/validation/ValidationError"; import {should, use} from "chai"; import * as chaiAsPromised from "chai-as-promised"; -import {Contains} from "../../src/decorator/Contains"; -import {MinLength} from "../../src/decorator/MinLength"; -import {Matches} from "../../src/decorator/Matches"; +import {Contains} from "../../src/decorator/string/Contains"; +import {MinLength} from "../../src/decorator/string/MinLength"; +import {Matches} from "../../src/decorator/string/Matches"; +import {ValidateNested} from "../../src/decorator/system/ValidateNested"; should(); use(chaiAsPromised); diff --git a/test/functional/validator-options.spec.ts b/test/functional/validator-options.spec.ts index 52dabbf07a..174c7eb7e6 100644 --- a/test/functional/validator-options.spec.ts +++ b/test/functional/validator-options.spec.ts @@ -1,5 +1,5 @@ import "es6-shim"; -import {IsNotEmpty} from "../../src/decorator/IsNotEmpty"; +import {IsNotEmpty} from "../../src/decorator/common/IsNotEmpty"; import {Validator} from "../../src/validation/Validator"; import {expect} from "chai"; diff --git a/test/functional/whitelist-validation.spec.ts b/test/functional/whitelist-validation.spec.ts index e7ac667802..56ee9fddf4 100644 --- a/test/functional/whitelist-validation.spec.ts +++ b/test/functional/whitelist-validation.spec.ts @@ -1,5 +1,4 @@ import "es6-shim"; -import {Allow, IsDefined} from "../../src/decorator/decorators"; import {Validator} from "../../src/validation/Validator"; import {expect} from "chai"; import {ValidationTypes} from "../../src/validation/ValidationTypes"; @@ -7,7 +6,9 @@ import {ValidationTypes} from "../../src/validation/ValidationTypes"; import {should, use } from "chai"; import * as chaiAsPromised from "chai-as-promised"; -import {Min} from "../../src/decorator/Min"; +import {Min} from "../../src/decorator/number/Min"; +import {IsDefined} from "../../src/decorator/system/IsDefined"; +import {Allow} from "../../src/decorator/system/Allow"; should(); use(chaiAsPromised);