diff --git a/dist/amd/aurelia-validation.js b/dist/amd/aurelia-validation.js new file mode 100644 index 00000000..8440d9ca --- /dev/null +++ b/dist/amd/aurelia-validation.js @@ -0,0 +1,1883 @@ +define('aurelia-validation', ['exports', 'aurelia-pal', 'aurelia-binding', 'aurelia-dependency-injection', 'aurelia-task-queue', 'aurelia-templating', 'aurelia-logging'], function (exports, aureliaPal, aureliaBinding, aureliaDependencyInjection, aureliaTaskQueue, aureliaTemplating, LogManager) { 'use strict'; + + /** + * Gets the DOM element associated with the data-binding. Most of the time it's + * the binding.target but sometimes binding.target is an aurelia custom element, + * or custom attribute which is a javascript "class" instance, so we need to use + * the controller's container to retrieve the actual DOM element. + */ + function getTargetDOMElement(binding, view) { + var target = binding.target; + // DOM element + if (target instanceof Element) { + return target; + } + // custom element or custom attribute + // tslint:disable-next-line:prefer-const + for (var i = 0, ii = view.controllers.length; i < ii; i++) { + var controller = view.controllers[i]; + if (controller.viewModel === target) { + var element = controller.container.get(aureliaPal.DOM.Element); + if (element) { + return element; + } + throw new Error("Unable to locate target element for \"" + binding.sourceExpression + "\"."); + } + } + throw new Error("Unable to locate target element for \"" + binding.sourceExpression + "\"."); + } + + function getObject(expression, objectExpression, source) { + var value = objectExpression.evaluate(source, null); + if (value === null || value === undefined || value instanceof Object) { + return value; + } + // tslint:disable-next-line:max-line-length + throw new Error("The '" + objectExpression + "' part of '" + expression + "' evaluates to " + value + " instead of an object, null or undefined."); + } + /** + * Retrieves the object and property name for the specified expression. + * @param expression The expression + * @param source The scope + */ + function getPropertyInfo(expression, source) { + var originalExpression = expression; + while (expression instanceof aureliaBinding.BindingBehavior || expression instanceof aureliaBinding.ValueConverter) { + expression = expression.expression; + } + var object; + var propertyName; + if (expression instanceof aureliaBinding.AccessScope) { + object = aureliaBinding.getContextFor(expression.name, source, expression.ancestor); + propertyName = expression.name; + } + else if (expression instanceof aureliaBinding.AccessMember) { + object = getObject(originalExpression, expression.object, source); + propertyName = expression.name; + } + else if (expression instanceof aureliaBinding.AccessKeyed) { + object = getObject(originalExpression, expression.object, source); + propertyName = expression.key.evaluate(source); + } + else { + throw new Error("Expression '" + originalExpression + "' is not compatible with the validate binding-behavior."); + } + if (object === null || object === undefined) { + return null; + } + return { object: object, propertyName: propertyName }; + } + + function isString(value) { + return Object.prototype.toString.call(value) === '[object String]'; + } + function isNumber(value) { + return Object.prototype.toString.call(value) === '[object Number]'; + } + + var PropertyAccessorParser = /** @class */ (function () { + function PropertyAccessorParser(parser) { + this.parser = parser; + } + PropertyAccessorParser.prototype.parse = function (property) { + if (isString(property) || isNumber(property)) { + return property; + } + var accessorText = getAccessorExpression(property.toString()); + var accessor = this.parser.parse(accessorText); + if (accessor instanceof aureliaBinding.AccessScope + || accessor instanceof aureliaBinding.AccessMember && accessor.object instanceof aureliaBinding.AccessScope) { + return accessor.name; + } + throw new Error("Invalid property expression: \"" + accessor + "\""); + }; + PropertyAccessorParser.inject = [aureliaBinding.Parser]; + return PropertyAccessorParser; + }()); + function getAccessorExpression(fn) { + /* tslint:disable:max-line-length */ + var classic = /^function\s*\([$_\w\d]+\)\s*\{(?:\s*"use strict";)?\s*(?:[$_\w\d.['"\]+;]+)?\s*return\s+[$_\w\d]+\.([$_\w\d]+)\s*;?\s*\}$/; + /* tslint:enable:max-line-length */ + var arrow = /^\(?[$_\w\d]+\)?\s*=>\s*[$_\w\d]+\.([$_\w\d]+)$/; + var match = classic.exec(fn) || arrow.exec(fn); + if (match === null) { + throw new Error("Unable to parse accessor function:\n" + fn); + } + return match[1]; + } + + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use + this file except in compliance with the License. You may obtain a copy of the + License at http://www.apache.org/licenses/LICENSE-2.0 + + THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED + WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, + MERCHANTABLITY OR NON-INFRINGEMENT. + + See the Apache Version 2.0 License for specific language governing permissions + and limitations under the License. + ***************************************************************************** */ + /* global Reflect, Promise */ + + var extendStatics = function(d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + + function __extends(d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + } + + function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; + } + + /** + * Validation triggers. + */ + (function (validateTrigger) { + /** + * Manual validation. Use the controller's `validate()` and `reset()` methods + * to validate all bindings. + */ + validateTrigger[validateTrigger["manual"] = 0] = "manual"; + /** + * Validate the binding when the binding's target element fires a DOM "blur" event. + */ + validateTrigger[validateTrigger["blur"] = 1] = "blur"; + /** + * Validate the binding when it updates the model due to a change in the view. + */ + validateTrigger[validateTrigger["change"] = 2] = "change"; + /** + * Validate the binding when the binding's target element fires a DOM "blur" event and + * when it updates the model due to a change in the view. + */ + validateTrigger[validateTrigger["changeOrBlur"] = 3] = "changeOrBlur"; + })(exports.validateTrigger || (exports.validateTrigger = {})); + + /** + * Validates objects and properties. + */ + var Validator = /** @class */ (function () { + function Validator() { + } + return Validator; + }()); + + /** + * The result of validating an individual validation rule. + */ + var ValidateResult = /** @class */ (function () { + /** + * @param rule The rule associated with the result. Validator implementation specific. + * @param object The object that was validated. + * @param propertyName The name of the property that was validated. + * @param error The error, if the result is a validation error. + */ + function ValidateResult(rule, object, propertyName, valid, message) { + if (message === void 0) { message = null; } + this.rule = rule; + this.object = object; + this.propertyName = propertyName; + this.valid = valid; + this.message = message; + this.id = ValidateResult.nextId++; + } + ValidateResult.prototype.toString = function () { + return this.valid ? 'Valid.' : this.message; + }; + ValidateResult.nextId = 0; + return ValidateResult; + }()); + + var ValidateEvent = /** @class */ (function () { + function ValidateEvent( + /** + * The type of validate event. Either "validate" or "reset". + */ + type, + /** + * The controller's current array of errors. For an array containing both + * failed rules and passed rules, use the "results" property. + */ + errors, + /** + * The controller's current array of validate results. This + * includes both passed rules and failed rules. For an array of only failed rules, + * use the "errors" property. + */ + results, + /** + * The instruction passed to the "validate" or "reset" event. Will be null when + * the controller's validate/reset method was called with no instruction argument. + */ + instruction, + /** + * In events with type === "validate", this property will contain the result + * of validating the instruction (see "instruction" property). Use the controllerValidateResult + * to access the validate results specific to the call to "validate" + * (as opposed to using the "results" and "errors" properties to access the controller's entire + * set of results/errors). + */ + controllerValidateResult) { + this.type = type; + this.errors = errors; + this.results = results; + this.instruction = instruction; + this.controllerValidateResult = controllerValidateResult; + } + return ValidateEvent; + }()); + + /** + * Orchestrates validation. + * Manages a set of bindings, renderers and objects. + * Exposes the current list of validation results for binding purposes. + */ + var ValidationController = /** @class */ (function () { + function ValidationController(validator, propertyParser) { + this.validator = validator; + this.propertyParser = propertyParser; + // Registered bindings (via the validate binding behavior) + this.bindings = new Map(); + // Renderers that have been added to the controller instance. + this.renderers = []; + /** + * Validation results that have been rendered by the controller. + */ + this.results = []; + /** + * Validation errors that have been rendered by the controller. + */ + this.errors = []; + /** + * Whether the controller is currently validating. + */ + this.validating = false; + // Elements related to validation results that have been rendered. + this.elements = new Map(); + // Objects that have been added to the controller instance (entity-style validation). + this.objects = new Map(); + /** + * The trigger that will invoke automatic validation of a property used in a binding. + */ + this.validateTrigger = exports.validateTrigger.blur; + // Promise that resolves when validation has completed. + this.finishValidating = Promise.resolve(); + this.eventCallbacks = []; + } + /** + * Subscribe to controller validate and reset events. These events occur when the + * controller's "validate"" and "reset" methods are called. + * @param callback The callback to be invoked when the controller validates or resets. + */ + ValidationController.prototype.subscribe = function (callback) { + var _this = this; + this.eventCallbacks.push(callback); + return { + dispose: function () { + var index = _this.eventCallbacks.indexOf(callback); + if (index === -1) { + return; + } + _this.eventCallbacks.splice(index, 1); + } + }; + }; + /** + * Adds an object to the set of objects that should be validated when validate is called. + * @param object The object. + * @param rules Optional. The rules. If rules aren't supplied the Validator implementation will lookup the rules. + */ + ValidationController.prototype.addObject = function (object, rules) { + this.objects.set(object, rules); + }; + /** + * Removes an object from the set of objects that should be validated when validate is called. + * @param object The object. + */ + ValidationController.prototype.removeObject = function (object) { + this.objects.delete(object); + this.processResultDelta('reset', this.results.filter(function (result) { return result.object === object; }), []); + }; + /** + * Adds and renders an error. + */ + ValidationController.prototype.addError = function (message, object, propertyName) { + if (propertyName === void 0) { propertyName = null; } + var resolvedPropertyName; + if (propertyName === null) { + resolvedPropertyName = propertyName; + } + else { + resolvedPropertyName = this.propertyParser.parse(propertyName); + } + var result = new ValidateResult({ __manuallyAdded__: true }, object, resolvedPropertyName, false, message); + this.processResultDelta('validate', [], [result]); + return result; + }; + /** + * Removes and unrenders an error. + */ + ValidationController.prototype.removeError = function (result) { + if (this.results.indexOf(result) !== -1) { + this.processResultDelta('reset', [result], []); + } + }; + /** + * Adds a renderer. + * @param renderer The renderer. + */ + ValidationController.prototype.addRenderer = function (renderer) { + var _this = this; + this.renderers.push(renderer); + renderer.render({ + kind: 'validate', + render: this.results.map(function (result) { return ({ result: result, elements: _this.elements.get(result) }); }), + unrender: [] + }); + }; + /** + * Removes a renderer. + * @param renderer The renderer. + */ + ValidationController.prototype.removeRenderer = function (renderer) { + var _this = this; + this.renderers.splice(this.renderers.indexOf(renderer), 1); + renderer.render({ + kind: 'reset', + render: [], + unrender: this.results.map(function (result) { return ({ result: result, elements: _this.elements.get(result) }); }) + }); + }; + /** + * Registers a binding with the controller. + * @param binding The binding instance. + * @param target The DOM element. + * @param rules (optional) rules associated with the binding. Validator implementation specific. + */ + ValidationController.prototype.registerBinding = function (binding, target, rules) { + this.bindings.set(binding, { target: target, rules: rules, propertyInfo: null }); + }; + /** + * Unregisters a binding with the controller. + * @param binding The binding instance. + */ + ValidationController.prototype.unregisterBinding = function (binding) { + this.resetBinding(binding); + this.bindings.delete(binding); + }; + /** + * Interprets the instruction and returns a predicate that will identify + * relevant results in the list of rendered validation results. + */ + ValidationController.prototype.getInstructionPredicate = function (instruction) { + var _this = this; + if (instruction) { + var object_1 = instruction.object, propertyName_1 = instruction.propertyName, rules_1 = instruction.rules; + var predicate_1; + if (instruction.propertyName) { + predicate_1 = function (x) { return x.object === object_1 && x.propertyName === propertyName_1; }; + } + else { + predicate_1 = function (x) { return x.object === object_1; }; + } + if (rules_1) { + return function (x) { return predicate_1(x) && _this.validator.ruleExists(rules_1, x.rule); }; + } + return predicate_1; + } + else { + return function () { return true; }; + } + }; + /** + * Validates and renders results. + * @param instruction Optional. Instructions on what to validate. If undefined, all + * objects and bindings will be validated. + */ + ValidationController.prototype.validate = function (instruction) { + var _this = this; + // Get a function that will process the validation instruction. + var execute; + if (instruction) { + // tslint:disable-next-line:prefer-const + var object_2 = instruction.object, propertyName_2 = instruction.propertyName, rules_2 = instruction.rules; + // if rules were not specified, check the object map. + rules_2 = rules_2 || this.objects.get(object_2); + // property specified? + if (instruction.propertyName === undefined) { + // validate the specified object. + execute = function () { return _this.validator.validateObject(object_2, rules_2); }; + } + else { + // validate the specified property. + execute = function () { return _this.validator.validateProperty(object_2, propertyName_2, rules_2); }; + } + } + else { + // validate all objects and bindings. + execute = function () { + var promises = []; + for (var _i = 0, _a = Array.from(_this.objects); _i < _a.length; _i++) { + var _b = _a[_i], object = _b[0], rules = _b[1]; + promises.push(_this.validator.validateObject(object, rules)); + } + for (var _c = 0, _d = Array.from(_this.bindings); _c < _d.length; _c++) { + var _e = _d[_c], binding = _e[0], rules = _e[1].rules; + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (!propertyInfo || _this.objects.has(propertyInfo.object)) { + continue; + } + promises.push(_this.validator.validateProperty(propertyInfo.object, propertyInfo.propertyName, rules)); + } + return Promise.all(promises).then(function (resultSets) { return resultSets.reduce(function (a, b) { return a.concat(b); }, []); }); + }; + } + // Wait for any existing validation to finish, execute the instruction, render the results. + this.validating = true; + var returnPromise = this.finishValidating + .then(execute) + .then(function (newResults) { + var predicate = _this.getInstructionPredicate(instruction); + var oldResults = _this.results.filter(predicate); + _this.processResultDelta('validate', oldResults, newResults); + if (returnPromise === _this.finishValidating) { + _this.validating = false; + } + var result = { + instruction: instruction, + valid: newResults.find(function (x) { return !x.valid; }) === undefined, + results: newResults + }; + _this.invokeCallbacks(instruction, result); + return result; + }) + .catch(function (exception) { + // recover, to enable subsequent calls to validate() + _this.validating = false; + _this.finishValidating = Promise.resolve(); + return Promise.reject(exception); + }); + this.finishValidating = returnPromise; + return returnPromise; + }; + /** + * Resets any rendered validation results (unrenders). + * @param instruction Optional. Instructions on what to reset. If unspecified all rendered results + * will be unrendered. + */ + ValidationController.prototype.reset = function (instruction) { + var predicate = this.getInstructionPredicate(instruction); + var oldResults = this.results.filter(predicate); + this.processResultDelta('reset', oldResults, []); + this.invokeCallbacks(instruction, null); + }; + /** + * Gets the elements associated with an object and propertyName (if any). + */ + ValidationController.prototype.getAssociatedElements = function (_a) { + var object = _a.object, propertyName = _a.propertyName; + var elements = []; + for (var _i = 0, _b = Array.from(this.bindings); _i < _b.length; _i++) { + var _c = _b[_i], binding = _c[0], target = _c[1].target; + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (propertyInfo && propertyInfo.object === object && propertyInfo.propertyName === propertyName) { + elements.push(target); + } + } + return elements; + }; + ValidationController.prototype.processResultDelta = function (kind, oldResults, newResults) { + // prepare the instruction. + var instruction = { + kind: kind, + render: [], + unrender: [] + }; + // create a shallow copy of newResults so we can mutate it without causing side-effects. + newResults = newResults.slice(0); + var _loop_1 = function (oldResult) { + // get the elements associated with the old result. + var elements = this_1.elements.get(oldResult); + // remove the old result from the element map. + this_1.elements.delete(oldResult); + // create the unrender instruction. + instruction.unrender.push({ result: oldResult, elements: elements }); + // determine if there's a corresponding new result for the old result we are unrendering. + var newResultIndex = newResults.findIndex(function (x) { return x.rule === oldResult.rule && x.object === oldResult.object && x.propertyName === oldResult.propertyName; }); + if (newResultIndex === -1) { + // no corresponding new result... simple remove. + this_1.results.splice(this_1.results.indexOf(oldResult), 1); + if (!oldResult.valid) { + this_1.errors.splice(this_1.errors.indexOf(oldResult), 1); + } + } + else { + // there is a corresponding new result... + var newResult = newResults.splice(newResultIndex, 1)[0]; + // get the elements that are associated with the new result. + var elements_1 = this_1.getAssociatedElements(newResult); + this_1.elements.set(newResult, elements_1); + // create a render instruction for the new result. + instruction.render.push({ result: newResult, elements: elements_1 }); + // do an in-place replacement of the old result with the new result. + // this ensures any repeats bound to this.results will not thrash. + this_1.results.splice(this_1.results.indexOf(oldResult), 1, newResult); + if (!oldResult.valid && newResult.valid) { + this_1.errors.splice(this_1.errors.indexOf(oldResult), 1); + } + else if (!oldResult.valid && !newResult.valid) { + this_1.errors.splice(this_1.errors.indexOf(oldResult), 1, newResult); + } + else if (!newResult.valid) { + this_1.errors.push(newResult); + } + } + }; + var this_1 = this; + // create unrender instructions from the old results. + for (var _i = 0, oldResults_1 = oldResults; _i < oldResults_1.length; _i++) { + var oldResult = oldResults_1[_i]; + _loop_1(oldResult); + } + // create render instructions from the remaining new results. + for (var _a = 0, newResults_1 = newResults; _a < newResults_1.length; _a++) { + var result = newResults_1[_a]; + var elements = this.getAssociatedElements(result); + instruction.render.push({ result: result, elements: elements }); + this.elements.set(result, elements); + this.results.push(result); + if (!result.valid) { + this.errors.push(result); + } + } + // render. + for (var _b = 0, _c = this.renderers; _b < _c.length; _b++) { + var renderer = _c[_b]; + renderer.render(instruction); + } + }; + /** + * Validates the property associated with a binding. + */ + ValidationController.prototype.validateBinding = function (binding) { + if (!binding.isBound) { + return; + } + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + var rules; + var registeredBinding = this.bindings.get(binding); + if (registeredBinding) { + rules = registeredBinding.rules; + registeredBinding.propertyInfo = propertyInfo; + } + if (!propertyInfo) { + return; + } + var object = propertyInfo.object, propertyName = propertyInfo.propertyName; + this.validate({ object: object, propertyName: propertyName, rules: rules }); + }; + /** + * Resets the results for a property associated with a binding. + */ + ValidationController.prototype.resetBinding = function (binding) { + var registeredBinding = this.bindings.get(binding); + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (!propertyInfo && registeredBinding) { + propertyInfo = registeredBinding.propertyInfo; + } + if (registeredBinding) { + registeredBinding.propertyInfo = null; + } + if (!propertyInfo) { + return; + } + var object = propertyInfo.object, propertyName = propertyInfo.propertyName; + this.reset({ object: object, propertyName: propertyName }); + }; + /** + * Changes the controller's validateTrigger. + * @param newTrigger The new validateTrigger + */ + ValidationController.prototype.changeTrigger = function (newTrigger) { + this.validateTrigger = newTrigger; + var bindings = Array.from(this.bindings.keys()); + for (var _i = 0, bindings_1 = bindings; _i < bindings_1.length; _i++) { + var binding = bindings_1[_i]; + var source = binding.source; + binding.unbind(); + binding.bind(source); + } + }; + /** + * Revalidates the controller's current set of errors. + */ + ValidationController.prototype.revalidateErrors = function () { + for (var _i = 0, _a = this.errors; _i < _a.length; _i++) { + var _b = _a[_i], object = _b.object, propertyName = _b.propertyName, rule = _b.rule; + if (rule.__manuallyAdded__) { + continue; + } + var rules = [[rule]]; + this.validate({ object: object, propertyName: propertyName, rules: rules }); + } + }; + ValidationController.prototype.invokeCallbacks = function (instruction, result) { + if (this.eventCallbacks.length === 0) { + return; + } + var event = new ValidateEvent(result ? 'validate' : 'reset', this.errors, this.results, instruction || null, result); + for (var i = 0; i < this.eventCallbacks.length; i++) { + this.eventCallbacks[i](event); + } + }; + ValidationController.inject = [Validator, PropertyAccessorParser]; + return ValidationController; + }()); + + /** + * Binding behavior. Indicates the bound property should be validated. + */ + var ValidateBindingBehaviorBase = /** @class */ (function () { + function ValidateBindingBehaviorBase(taskQueue) { + this.taskQueue = taskQueue; + } + ValidateBindingBehaviorBase.prototype.bind = function (binding, source, rulesOrController, rules) { + var _this = this; + // identify the target element. + var target = getTargetDOMElement(binding, source); + // locate the controller. + var controller; + if (rulesOrController instanceof ValidationController) { + controller = rulesOrController; + } + else { + controller = source.container.get(aureliaDependencyInjection.Optional.of(ValidationController)); + rules = rulesOrController; + } + if (controller === null) { + throw new Error("A ValidationController has not been registered."); + } + controller.registerBinding(binding, target, rules); + binding.validationController = controller; + var trigger = this.getValidateTrigger(controller); + // tslint:disable-next-line:no-bitwise + if (trigger & exports.validateTrigger.change) { + binding.vbbUpdateSource = binding.updateSource; + // tslint:disable-next-line:only-arrow-functions + // tslint:disable-next-line:space-before-function-paren + binding.updateSource = function (value) { + this.vbbUpdateSource(value); + this.validationController.validateBinding(this); + }; + } + // tslint:disable-next-line:no-bitwise + if (trigger & exports.validateTrigger.blur) { + binding.validateBlurHandler = function () { + _this.taskQueue.queueMicroTask(function () { return controller.validateBinding(binding); }); + }; + binding.validateTarget = target; + target.addEventListener('blur', binding.validateBlurHandler); + } + if (trigger !== exports.validateTrigger.manual) { + binding.standardUpdateTarget = binding.updateTarget; + // tslint:disable-next-line:only-arrow-functions + // tslint:disable-next-line:space-before-function-paren + binding.updateTarget = function (value) { + this.standardUpdateTarget(value); + this.validationController.resetBinding(this); + }; + } + }; + ValidateBindingBehaviorBase.prototype.unbind = function (binding) { + // reset the binding to it's original state. + if (binding.vbbUpdateSource) { + binding.updateSource = binding.vbbUpdateSource; + binding.vbbUpdateSource = null; + } + if (binding.standardUpdateTarget) { + binding.updateTarget = binding.standardUpdateTarget; + binding.standardUpdateTarget = null; + } + if (binding.validateBlurHandler) { + binding.validateTarget.removeEventListener('blur', binding.validateBlurHandler); + binding.validateBlurHandler = null; + binding.validateTarget = null; + } + binding.validationController.unregisterBinding(binding); + binding.validationController = null; + }; + return ValidateBindingBehaviorBase; + }()); + + /** + * Binding behavior. Indicates the bound property should be validated + * when the validate trigger specified by the associated controller's + * validateTrigger property occurs. + */ + var ValidateBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateBindingBehavior, _super); + function ValidateBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateBindingBehavior.prototype.getValidateTrigger = function (controller) { + return controller.validateTrigger; + }; + ValidateBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + ValidateBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validate') + ], ValidateBindingBehavior); + return ValidateBindingBehavior; + }(ValidateBindingBehaviorBase)); + /** + * Binding behavior. Indicates the bound property will be validated + * manually, by calling controller.validate(). No automatic validation + * triggered by data-entry or blur will occur. + */ + var ValidateManuallyBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateManuallyBindingBehavior, _super); + function ValidateManuallyBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateManuallyBindingBehavior.prototype.getValidateTrigger = function () { + return exports.validateTrigger.manual; + }; + ValidateManuallyBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + ValidateManuallyBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validateManually') + ], ValidateManuallyBindingBehavior); + return ValidateManuallyBindingBehavior; + }(ValidateBindingBehaviorBase)); + /** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs. + */ + var ValidateOnBlurBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateOnBlurBindingBehavior, _super); + function ValidateOnBlurBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateOnBlurBindingBehavior.prototype.getValidateTrigger = function () { + return exports.validateTrigger.blur; + }; + ValidateOnBlurBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + ValidateOnBlurBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validateOnBlur') + ], ValidateOnBlurBindingBehavior); + return ValidateOnBlurBindingBehavior; + }(ValidateBindingBehaviorBase)); + /** + * Binding behavior. Indicates the bound property should be validated + * when the associated element is changed by the user, causing a change + * to the model. + */ + var ValidateOnChangeBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateOnChangeBindingBehavior, _super); + function ValidateOnChangeBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateOnChangeBindingBehavior.prototype.getValidateTrigger = function () { + return exports.validateTrigger.change; + }; + ValidateOnChangeBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + ValidateOnChangeBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validateOnChange') + ], ValidateOnChangeBindingBehavior); + return ValidateOnChangeBindingBehavior; + }(ValidateBindingBehaviorBase)); + /** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs or is changed by the user, causing + * a change to the model. + */ + var ValidateOnChangeOrBlurBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateOnChangeOrBlurBindingBehavior, _super); + function ValidateOnChangeOrBlurBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateOnChangeOrBlurBindingBehavior.prototype.getValidateTrigger = function () { + return exports.validateTrigger.changeOrBlur; + }; + ValidateOnChangeOrBlurBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + ValidateOnChangeOrBlurBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validateOnChangeOrBlur') + ], ValidateOnChangeOrBlurBindingBehavior); + return ValidateOnChangeOrBlurBindingBehavior; + }(ValidateBindingBehaviorBase)); + + /** + * Creates ValidationController instances. + */ + var ValidationControllerFactory = /** @class */ (function () { + function ValidationControllerFactory(container) { + this.container = container; + } + ValidationControllerFactory.get = function (container) { + return new ValidationControllerFactory(container); + }; + /** + * Creates a new controller instance. + */ + ValidationControllerFactory.prototype.create = function (validator) { + if (!validator) { + validator = this.container.get(Validator); + } + var propertyParser = this.container.get(PropertyAccessorParser); + return new ValidationController(validator, propertyParser); + }; + /** + * Creates a new controller and registers it in the current element's container so that it's + * available to the validate binding behavior and renderers. + */ + ValidationControllerFactory.prototype.createForCurrentScope = function (validator) { + var controller = this.create(validator); + this.container.registerInstance(ValidationController, controller); + return controller; + }; + return ValidationControllerFactory; + }()); + ValidationControllerFactory['protocol:aurelia:resolver'] = true; + + var ValidationErrorsCustomAttribute = /** @class */ (function () { + function ValidationErrorsCustomAttribute(boundaryElement, controllerAccessor) { + this.boundaryElement = boundaryElement; + this.controllerAccessor = controllerAccessor; + this.controller = null; + this.errors = []; + this.errorsInternal = []; + } + ValidationErrorsCustomAttribute.inject = function () { + return [aureliaPal.DOM.Element, aureliaDependencyInjection.Lazy.of(ValidationController)]; + }; + ValidationErrorsCustomAttribute.prototype.sort = function () { + this.errorsInternal.sort(function (a, b) { + if (a.targets[0] === b.targets[0]) { + return 0; + } + // tslint:disable-next-line:no-bitwise + return a.targets[0].compareDocumentPosition(b.targets[0]) & 2 ? 1 : -1; + }); + }; + ValidationErrorsCustomAttribute.prototype.interestingElements = function (elements) { + var _this = this; + return elements.filter(function (e) { return _this.boundaryElement.contains(e); }); + }; + ValidationErrorsCustomAttribute.prototype.render = function (instruction) { + var _loop_1 = function (result) { + var index = this_1.errorsInternal.findIndex(function (x) { return x.error === result; }); + if (index !== -1) { + this_1.errorsInternal.splice(index, 1); + } + }; + var this_1 = this; + for (var _i = 0, _a = instruction.unrender; _i < _a.length; _i++) { + var result = _a[_i].result; + _loop_1(result); + } + for (var _b = 0, _c = instruction.render; _b < _c.length; _b++) { + var _d = _c[_b], result = _d.result, elements = _d.elements; + if (result.valid) { + continue; + } + var targets = this.interestingElements(elements); + if (targets.length) { + this.errorsInternal.push({ error: result, targets: targets }); + } + } + this.sort(); + this.errors = this.errorsInternal; + }; + ValidationErrorsCustomAttribute.prototype.bind = function () { + if (!this.controller) { + this.controller = this.controllerAccessor(); + } + // this will call render() with the side-effect of updating this.errors + this.controller.addRenderer(this); + }; + ValidationErrorsCustomAttribute.prototype.unbind = function () { + if (this.controller) { + this.controller.removeRenderer(this); + } + }; + __decorate([ + aureliaTemplating.bindable({ defaultBindingMode: aureliaBinding.bindingMode.oneWay }) + ], ValidationErrorsCustomAttribute.prototype, "controller", void 0); + __decorate([ + aureliaTemplating.bindable({ primaryProperty: true, defaultBindingMode: aureliaBinding.bindingMode.twoWay }) + ], ValidationErrorsCustomAttribute.prototype, "errors", void 0); + ValidationErrorsCustomAttribute = __decorate([ + aureliaTemplating.customAttribute('validation-errors') + ], ValidationErrorsCustomAttribute); + return ValidationErrorsCustomAttribute; + }()); + + var ValidationRendererCustomAttribute = /** @class */ (function () { + function ValidationRendererCustomAttribute() { + } + ValidationRendererCustomAttribute.prototype.created = function (view) { + this.container = view.container; + }; + ValidationRendererCustomAttribute.prototype.bind = function () { + this.controller = this.container.get(ValidationController); + this.renderer = this.container.get(this.value); + this.controller.addRenderer(this.renderer); + }; + ValidationRendererCustomAttribute.prototype.unbind = function () { + this.controller.removeRenderer(this.renderer); + this.controller = null; + this.renderer = null; + }; + ValidationRendererCustomAttribute = __decorate([ + aureliaTemplating.customAttribute('validation-renderer') + ], ValidationRendererCustomAttribute); + return ValidationRendererCustomAttribute; + }()); + + /** + * Sets, unsets and retrieves rules on an object or constructor function. + */ + var Rules = /** @class */ (function () { + function Rules() { + } + /** + * Applies the rules to a target. + */ + Rules.set = function (target, rules) { + if (target instanceof Function) { + target = target.prototype; + } + Object.defineProperty(target, Rules.key, { enumerable: false, configurable: false, writable: true, value: rules }); + }; + /** + * Removes rules from a target. + */ + Rules.unset = function (target) { + if (target instanceof Function) { + target = target.prototype; + } + target[Rules.key] = null; + }; + /** + * Retrieves the target's rules. + */ + Rules.get = function (target) { + return target[Rules.key] || null; + }; + /** + * The name of the property that stores the rules. + */ + Rules.key = '__rules__'; + return Rules; + }()); + + // tslint:disable:no-empty + var ExpressionVisitor = /** @class */ (function () { + function ExpressionVisitor() { + } + ExpressionVisitor.prototype.visitChain = function (chain) { + this.visitArgs(chain.expressions); + }; + ExpressionVisitor.prototype.visitBindingBehavior = function (behavior) { + behavior.expression.accept(this); + this.visitArgs(behavior.args); + }; + ExpressionVisitor.prototype.visitValueConverter = function (converter) { + converter.expression.accept(this); + this.visitArgs(converter.args); + }; + ExpressionVisitor.prototype.visitAssign = function (assign) { + assign.target.accept(this); + assign.value.accept(this); + }; + ExpressionVisitor.prototype.visitConditional = function (conditional) { + conditional.condition.accept(this); + conditional.yes.accept(this); + conditional.no.accept(this); + }; + ExpressionVisitor.prototype.visitAccessThis = function (access) { + access.ancestor = access.ancestor; + }; + ExpressionVisitor.prototype.visitAccessScope = function (access) { + access.name = access.name; + }; + ExpressionVisitor.prototype.visitAccessMember = function (access) { + access.object.accept(this); + }; + ExpressionVisitor.prototype.visitAccessKeyed = function (access) { + access.object.accept(this); + access.key.accept(this); + }; + ExpressionVisitor.prototype.visitCallScope = function (call) { + this.visitArgs(call.args); + }; + ExpressionVisitor.prototype.visitCallFunction = function (call) { + call.func.accept(this); + this.visitArgs(call.args); + }; + ExpressionVisitor.prototype.visitCallMember = function (call) { + call.object.accept(this); + this.visitArgs(call.args); + }; + ExpressionVisitor.prototype.visitPrefix = function (prefix) { + prefix.expression.accept(this); + }; + ExpressionVisitor.prototype.visitBinary = function (binary) { + binary.left.accept(this); + binary.right.accept(this); + }; + ExpressionVisitor.prototype.visitLiteralPrimitive = function (literal) { + literal.value = literal.value; + }; + ExpressionVisitor.prototype.visitLiteralArray = function (literal) { + this.visitArgs(literal.elements); + }; + ExpressionVisitor.prototype.visitLiteralObject = function (literal) { + this.visitArgs(literal.values); + }; + ExpressionVisitor.prototype.visitLiteralString = function (literal) { + literal.value = literal.value; + }; + ExpressionVisitor.prototype.visitArgs = function (args) { + for (var i = 0; i < args.length; i++) { + args[i].accept(this); + } + }; + return ExpressionVisitor; + }()); + + var ValidationMessageParser = /** @class */ (function () { + function ValidationMessageParser(bindinqLanguage) { + this.bindinqLanguage = bindinqLanguage; + this.emptyStringExpression = new aureliaBinding.LiteralString(''); + this.nullExpression = new aureliaBinding.LiteralPrimitive(null); + this.undefinedExpression = new aureliaBinding.LiteralPrimitive(undefined); + this.cache = {}; + } + ValidationMessageParser.prototype.parse = function (message) { + if (this.cache[message] !== undefined) { + return this.cache[message]; + } + var parts = this.bindinqLanguage.parseInterpolation(null, message); + if (parts === null) { + return new aureliaBinding.LiteralString(message); + } + var expression = new aureliaBinding.LiteralString(parts[0]); + for (var i = 1; i < parts.length; i += 2) { + expression = new aureliaBinding.Binary('+', expression, new aureliaBinding.Binary('+', this.coalesce(parts[i]), new aureliaBinding.LiteralString(parts[i + 1]))); + } + MessageExpressionValidator.validate(expression, message); + this.cache[message] = expression; + return expression; + }; + ValidationMessageParser.prototype.coalesce = function (part) { + // part === null || part === undefined ? '' : part + return new aureliaBinding.Conditional(new aureliaBinding.Binary('||', new aureliaBinding.Binary('===', part, this.nullExpression), new aureliaBinding.Binary('===', part, this.undefinedExpression)), this.emptyStringExpression, new aureliaBinding.CallMember(part, 'toString', [])); + }; + ValidationMessageParser.inject = [aureliaTemplating.BindingLanguage]; + return ValidationMessageParser; + }()); + var MessageExpressionValidator = /** @class */ (function (_super) { + __extends(MessageExpressionValidator, _super); + function MessageExpressionValidator(originalMessage) { + var _this = _super.call(this) || this; + _this.originalMessage = originalMessage; + return _this; + } + MessageExpressionValidator.validate = function (expression, originalMessage) { + var visitor = new MessageExpressionValidator(originalMessage); + expression.accept(visitor); + }; + MessageExpressionValidator.prototype.visitAccessScope = function (access) { + if (access.ancestor !== 0) { + throw new Error('$parent is not permitted in validation message expressions.'); + } + if (['displayName', 'propertyName', 'value', 'object', 'config', 'getDisplayName'].indexOf(access.name) !== -1) { + LogManager.getLogger('aurelia-validation') + // tslint:disable-next-line:max-line-length + .warn("Did you mean to use \"$" + access.name + "\" instead of \"" + access.name + "\" in this validation message template: \"" + this.originalMessage + "\"?"); + } + }; + return MessageExpressionValidator; + }(ExpressionVisitor)); + + /** + * Dictionary of validation messages. [messageKey]: messageExpression + */ + var validationMessages = { + /** + * The default validation message. Used with rules that have no standard message. + */ + default: "${$displayName} is invalid.", + required: "${$displayName} is required.", + matches: "${$displayName} is not correctly formatted.", + email: "${$displayName} is not a valid email.", + minLength: "${$displayName} must be at least ${$config.length} character${$config.length === 1 ? '' : 's'}.", + maxLength: "${$displayName} cannot be longer than ${$config.length} character${$config.length === 1 ? '' : 's'}.", + minItems: "${$displayName} must contain at least ${$config.count} item${$config.count === 1 ? '' : 's'}.", + maxItems: "${$displayName} cannot contain more than ${$config.count} item${$config.count === 1 ? '' : 's'}.", + min: "${$displayName} must be at least ${$config.constraint}.", + max: "${$displayName} must be at most ${$config.constraint}.", + range: "${$displayName} must be between or equal to ${$config.min} and ${$config.max}.", + between: "${$displayName} must be between but not equal to ${$config.min} and ${$config.max}.", + equals: "${$displayName} must be ${$config.expectedValue}.", + }; + /** + * Retrieves validation messages and property display names. + */ + var ValidationMessageProvider = /** @class */ (function () { + function ValidationMessageProvider(parser) { + this.parser = parser; + } + /** + * Returns a message binding expression that corresponds to the key. + * @param key The message key. + */ + ValidationMessageProvider.prototype.getMessage = function (key) { + var message; + if (key in validationMessages) { + message = validationMessages[key]; + } + else { + message = validationMessages['default']; + } + return this.parser.parse(message); + }; + /** + * Formulates a property display name using the property name and the configured + * displayName (if provided). + * Override this with your own custom logic. + * @param propertyName The property name. + */ + ValidationMessageProvider.prototype.getDisplayName = function (propertyName, displayName) { + if (displayName !== null && displayName !== undefined) { + return (displayName instanceof Function) ? displayName() : displayName; + } + // split on upper-case letters. + var words = propertyName.toString().split(/(?=[A-Z])/).join(' '); + // capitalize first letter. + return words.charAt(0).toUpperCase() + words.slice(1); + }; + ValidationMessageProvider.inject = [ValidationMessageParser]; + return ValidationMessageProvider; + }()); + + /** + * Validates. + * Responsible for validating objects and properties. + */ + var StandardValidator = /** @class */ (function (_super) { + __extends(StandardValidator, _super); + function StandardValidator(messageProvider, resources) { + var _this = _super.call(this) || this; + _this.messageProvider = messageProvider; + _this.lookupFunctions = resources.lookupFunctions; + _this.getDisplayName = messageProvider.getDisplayName.bind(messageProvider); + return _this; + } + /** + * Validates the specified property. + * @param object The object to validate. + * @param propertyName The name of the property to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + StandardValidator.prototype.validateProperty = function (object, propertyName, rules) { + return this.validate(object, propertyName, rules || null); + }; + /** + * Validates all rules for specified object and it's properties. + * @param object The object to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + StandardValidator.prototype.validateObject = function (object, rules) { + return this.validate(object, null, rules || null); + }; + /** + * Determines whether a rule exists in a set of rules. + * @param rules The rules to search. + * @parem rule The rule to find. + */ + StandardValidator.prototype.ruleExists = function (rules, rule) { + var i = rules.length; + while (i--) { + if (rules[i].indexOf(rule) !== -1) { + return true; + } + } + return false; + }; + StandardValidator.prototype.getMessage = function (rule, object, value) { + var expression = rule.message || this.messageProvider.getMessage(rule.messageKey); + // tslint:disable-next-line:prefer-const + var _a = rule.property, propertyName = _a.name, displayName = _a.displayName; + if (propertyName !== null) { + displayName = this.messageProvider.getDisplayName(propertyName, displayName); + } + var overrideContext = { + $displayName: displayName, + $propertyName: propertyName, + $value: value, + $object: object, + $config: rule.config, + // returns the name of a given property, given just the property name (irrespective of the property's displayName) + // split on capital letters, first letter ensured to be capitalized + $getDisplayName: this.getDisplayName + }; + return expression.evaluate({ bindingContext: object, overrideContext: overrideContext }, this.lookupFunctions); + }; + StandardValidator.prototype.validateRuleSequence = function (object, propertyName, ruleSequence, sequence, results) { + var _this = this; + // are we validating all properties or a single property? + var validateAllProperties = propertyName === null || propertyName === undefined; + var rules = ruleSequence[sequence]; + var allValid = true; + // validate each rule. + var promises = []; + var _loop_1 = function (i) { + var rule = rules[i]; + // is the rule related to the property we're validating. + // tslint:disable-next-line:triple-equals | Use loose equality for property keys + if (!validateAllProperties && rule.property.name != propertyName) { + return "continue"; + } + // is this a conditional rule? is the condition met? + if (rule.when && !rule.when(object)) { + return "continue"; + } + // validate. + var value = rule.property.name === null ? object : object[rule.property.name]; + var promiseOrBoolean = rule.condition(value, object); + if (!(promiseOrBoolean instanceof Promise)) { + promiseOrBoolean = Promise.resolve(promiseOrBoolean); + } + promises.push(promiseOrBoolean.then(function (valid) { + var message = valid ? null : _this.getMessage(rule, object, value); + results.push(new ValidateResult(rule, object, rule.property.name, valid, message)); + allValid = allValid && valid; + return valid; + })); + }; + for (var i = 0; i < rules.length; i++) { + _loop_1(i); + } + return Promise.all(promises) + .then(function () { + sequence++; + if (allValid && sequence < ruleSequence.length) { + return _this.validateRuleSequence(object, propertyName, ruleSequence, sequence, results); + } + return results; + }); + }; + StandardValidator.prototype.validate = function (object, propertyName, rules) { + // rules specified? + if (!rules) { + // no. attempt to locate the rules. + rules = Rules.get(object); + } + // any rules? + if (!rules || rules.length === 0) { + return Promise.resolve([]); + } + return this.validateRuleSequence(object, propertyName, rules, 0, []); + }; + StandardValidator.inject = [ValidationMessageProvider, aureliaTemplating.ViewResources]; + return StandardValidator; + }(Validator)); + + /** + * Part of the fluent rule API. Enables customizing property rules. + */ + var FluentRuleCustomizer = /** @class */ (function () { + function FluentRuleCustomizer(property, condition, config, fluentEnsure, fluentRules, parsers) { + if (config === void 0) { config = {}; } + this.fluentEnsure = fluentEnsure; + this.fluentRules = fluentRules; + this.parsers = parsers; + this.rule = { + property: property, + condition: condition, + config: config, + when: null, + messageKey: 'default', + message: null, + sequence: fluentRules.sequence + }; + this.fluentEnsure._addRule(this.rule); + } + /** + * Validate subsequent rules after previously declared rules have + * been validated successfully. Use to postpone validation of costly + * rules until less expensive rules pass validation. + */ + FluentRuleCustomizer.prototype.then = function () { + this.fluentRules.sequence++; + return this; + }; + /** + * Specifies the key to use when looking up the rule's validation message. + */ + FluentRuleCustomizer.prototype.withMessageKey = function (key) { + this.rule.messageKey = key; + this.rule.message = null; + return this; + }; + /** + * Specifies rule's validation message. + */ + FluentRuleCustomizer.prototype.withMessage = function (message) { + this.rule.messageKey = 'custom'; + this.rule.message = this.parsers.message.parse(message); + return this; + }; + /** + * Specifies a condition that must be met before attempting to validate the rule. + * @param condition A function that accepts the object as a parameter and returns true + * or false whether the rule should be evaluated. + */ + FluentRuleCustomizer.prototype.when = function (condition) { + this.rule.when = condition; + return this; + }; + /** + * Tags the rule instance, enabling the rule to be found easily + * using ValidationRules.taggedRules(rules, tag) + */ + FluentRuleCustomizer.prototype.tag = function (tag) { + this.rule.tag = tag; + return this; + }; + ///// FluentEnsure APIs ///// + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + FluentRuleCustomizer.prototype.ensure = function (subject) { + return this.fluentEnsure.ensure(subject); + }; + /** + * Targets an object with validation rules. + */ + FluentRuleCustomizer.prototype.ensureObject = function () { + return this.fluentEnsure.ensureObject(); + }; + Object.defineProperty(FluentRuleCustomizer.prototype, "rules", { + /** + * Rules that have been defined using the fluent API. + */ + get: function () { + return this.fluentEnsure.rules; + }, + enumerable: true, + configurable: true + }); + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + FluentRuleCustomizer.prototype.on = function (target) { + return this.fluentEnsure.on(target); + }; + ///////// FluentRules APIs ///////// + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + FluentRuleCustomizer.prototype.satisfies = function (condition, config) { + return this.fluentRules.satisfies(condition, config); + }; + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + FluentRuleCustomizer.prototype.satisfiesRule = function (name) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + var _a; + return (_a = this.fluentRules).satisfiesRule.apply(_a, [name].concat(args)); + }; + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + FluentRuleCustomizer.prototype.required = function () { + return this.fluentRules.required(); + }; + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.matches = function (regex) { + return this.fluentRules.matches(regex); + }; + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.email = function () { + return this.fluentRules.email(); + }; + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.minLength = function (length) { + return this.fluentRules.minLength(length); + }; + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.maxLength = function (length) { + return this.fluentRules.maxLength(length); + }; + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.minItems = function (count) { + return this.fluentRules.minItems(count); + }; + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.maxItems = function (count) { + return this.fluentRules.maxItems(count); + }; + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.min = function (value) { + return this.fluentRules.min(value); + }; + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.max = function (value) { + return this.fluentRules.max(value); + }; + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.range = function (min, max) { + return this.fluentRules.range(min, max); + }; + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.between = function (min, max) { + return this.fluentRules.between(min, max); + }; + /** + * Applies the "equals" validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.equals = function (expectedValue) { + return this.fluentRules.equals(expectedValue); + }; + return FluentRuleCustomizer; + }()); + /** + * Part of the fluent rule API. Enables applying rules to properties and objects. + */ + var FluentRules = /** @class */ (function () { + function FluentRules(fluentEnsure, parsers, property) { + this.fluentEnsure = fluentEnsure; + this.parsers = parsers; + this.property = property; + /** + * Current rule sequence number. Used to postpone evaluation of rules until rules + * with lower sequence number have successfully validated. The "then" fluent API method + * manages this property, there's usually no need to set it directly. + */ + this.sequence = 0; + } + /** + * Sets the display name of the ensured property. + */ + FluentRules.prototype.displayName = function (name) { + this.property.displayName = name; + return this; + }; + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + FluentRules.prototype.satisfies = function (condition, config) { + return new FluentRuleCustomizer(this.property, condition, config, this.fluentEnsure, this, this.parsers); + }; + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + FluentRules.prototype.satisfiesRule = function (name) { + var _this = this; + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + var rule = FluentRules.customRules[name]; + if (!rule) { + // standard rule? + rule = this[name]; + if (rule instanceof Function) { + return rule.call.apply(rule, [this].concat(args)); + } + throw new Error("Rule with name \"" + name + "\" does not exist."); + } + var config = rule.argsToConfig ? rule.argsToConfig.apply(rule, args) : undefined; + return this.satisfies(function (value, obj) { + var _a; + return (_a = rule.condition).call.apply(_a, [_this, value, obj].concat(args)); + }, config) + .withMessageKey(name); + }; + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + FluentRules.prototype.required = function () { + return this.satisfies(function (value) { + return value !== null + && value !== undefined + && !(isString(value) && !/\S/.test(value)); + }).withMessageKey('required'); + }; + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.matches = function (regex) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length === 0 || regex.test(value); }) + .withMessageKey('matches'); + }; + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.email = function () { + // regex from https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address + /* tslint:disable:max-line-length */ + return this.matches(/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/) + /* tslint:enable:max-line-length */ + .withMessageKey('email'); + }; + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.minLength = function (length) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length === 0 || value.length >= length; }, { length: length }) + .withMessageKey('minLength'); + }; + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.maxLength = function (length) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length === 0 || value.length <= length; }, { length: length }) + .withMessageKey('maxLength'); + }; + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRules.prototype.minItems = function (count) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length >= count; }, { count: count }) + .withMessageKey('minItems'); + }; + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRules.prototype.maxItems = function (count) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length <= count; }, { count: count }) + .withMessageKey('maxItems'); + }; + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRules.prototype.min = function (constraint) { + return this.satisfies(function (value) { return value === null || value === undefined || value >= constraint; }, { constraint: constraint }) + .withMessageKey('min'); + }; + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRules.prototype.max = function (constraint) { + return this.satisfies(function (value) { return value === null || value === undefined || value <= constraint; }, { constraint: constraint }) + .withMessageKey('max'); + }; + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRules.prototype.range = function (min, max) { + return this.satisfies(function (value) { return value === null || value === undefined || (value >= min && value <= max); }, { min: min, max: max }) + .withMessageKey('range'); + }; + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRules.prototype.between = function (min, max) { + return this.satisfies(function (value) { return value === null || value === undefined || (value > min && value < max); }, { min: min, max: max }) + .withMessageKey('between'); + }; + /** + * Applies the "equals" validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRules.prototype.equals = function (expectedValue) { + return this.satisfies(function (value) { return value === null || value === undefined || value === '' || value === expectedValue; }, { expectedValue: expectedValue }) + .withMessageKey('equals'); + }; + FluentRules.customRules = {}; + return FluentRules; + }()); + /** + * Part of the fluent rule API. Enables targeting properties and objects with rules. + */ + var FluentEnsure = /** @class */ (function () { + function FluentEnsure(parsers) { + this.parsers = parsers; + /** + * Rules that have been defined using the fluent API. + */ + this.rules = []; + } + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor + * function. + */ + FluentEnsure.prototype.ensure = function (property) { + this.assertInitialized(); + var name = this.parsers.property.parse(property); + var fluentRules = new FluentRules(this, this.parsers, { name: name, displayName: null }); + return this.mergeRules(fluentRules, name); + }; + /** + * Targets an object with validation rules. + */ + FluentEnsure.prototype.ensureObject = function () { + this.assertInitialized(); + var fluentRules = new FluentRules(this, this.parsers, { name: null, displayName: null }); + return this.mergeRules(fluentRules, null); + }; + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + FluentEnsure.prototype.on = function (target) { + Rules.set(target, this.rules); + return this; + }; + /** + * Adds a rule definition to the sequenced ruleset. + * @internal + */ + FluentEnsure.prototype._addRule = function (rule) { + while (this.rules.length < rule.sequence + 1) { + this.rules.push([]); + } + this.rules[rule.sequence].push(rule); + }; + FluentEnsure.prototype.assertInitialized = function () { + if (this.parsers) { + return; + } + throw new Error("Did you forget to add \".plugin('aurelia-validation')\" to your main.js?"); + }; + FluentEnsure.prototype.mergeRules = function (fluentRules, propertyName) { + // tslint:disable-next-line:triple-equals | Use loose equality for property keys + var existingRules = this.rules.find(function (r) { return r.length > 0 && r[0].property.name == propertyName; }); + if (existingRules) { + var rule = existingRules[existingRules.length - 1]; + fluentRules.sequence = rule.sequence; + if (rule.property.displayName !== null) { + fluentRules = fluentRules.displayName(rule.property.displayName); + } + } + return fluentRules; + }; + return FluentEnsure; + }()); + /** + * Fluent rule definition API. + */ + var ValidationRules = /** @class */ (function () { + function ValidationRules() { + } + ValidationRules.initialize = function (messageParser, propertyParser) { + this.parsers = { + message: messageParser, + property: propertyParser + }; + }; + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + ValidationRules.ensure = function (property) { + return new FluentEnsure(ValidationRules.parsers).ensure(property); + }; + /** + * Targets an object with validation rules. + */ + ValidationRules.ensureObject = function () { + return new FluentEnsure(ValidationRules.parsers).ensureObject(); + }; + /** + * Defines a custom rule. + * @param name The name of the custom rule. Also serves as the message key. + * @param condition The rule function. + * @param message The message expression + * @param argsToConfig A function that maps the rule's arguments to a "config" + * object that can be used when evaluating the message expression. + */ + ValidationRules.customRule = function (name, condition, message, argsToConfig) { + validationMessages[name] = message; + FluentRules.customRules[name] = { condition: condition, argsToConfig: argsToConfig }; + }; + /** + * Returns rules with the matching tag. + * @param rules The rules to search. + * @param tag The tag to search for. + */ + ValidationRules.taggedRules = function (rules, tag) { + return rules.map(function (x) { return x.filter(function (r) { return r.tag === tag; }); }); + }; + /** + * Returns rules that have no tag. + * @param rules The rules to search. + */ + ValidationRules.untaggedRules = function (rules) { + return rules.map(function (x) { return x.filter(function (r) { return r.tag === undefined; }); }); + }; + /** + * Removes the rules from a class or object. + * @param target A class or object. + */ + ValidationRules.off = function (target) { + Rules.unset(target); + }; + return ValidationRules; + }()); + + // Exports + /** + * Aurelia Validation Configuration API + */ + var AureliaValidationConfiguration = /** @class */ (function () { + function AureliaValidationConfiguration() { + this.validatorType = StandardValidator; + } + /** + * Use a custom Validator implementation. + */ + AureliaValidationConfiguration.prototype.customValidator = function (type) { + this.validatorType = type; + }; + /** + * Applies the configuration. + */ + AureliaValidationConfiguration.prototype.apply = function (container) { + var validator = container.get(this.validatorType); + container.registerInstance(Validator, validator); + }; + return AureliaValidationConfiguration; + }()); + /** + * Configures the plugin. + */ + function configure( + // tslint:disable-next-line:ban-types + frameworkConfig, callback) { + // the fluent rule definition API needs the parser to translate messages + // to interpolation expressions. + var messageParser = frameworkConfig.container.get(ValidationMessageParser); + var propertyParser = frameworkConfig.container.get(PropertyAccessorParser); + ValidationRules.initialize(messageParser, propertyParser); + // configure... + var config = new AureliaValidationConfiguration(); + if (callback instanceof Function) { + callback(config); + } + config.apply(frameworkConfig.container); + // globalize the behaviors. + if (frameworkConfig.globalResources) { + frameworkConfig.globalResources(ValidateBindingBehavior, ValidateManuallyBindingBehavior, ValidateOnBlurBindingBehavior, ValidateOnChangeBindingBehavior, ValidateOnChangeOrBlurBindingBehavior, ValidationErrorsCustomAttribute, ValidationRendererCustomAttribute); + } + } + + exports.AureliaValidationConfiguration = AureliaValidationConfiguration; + exports.configure = configure; + exports.getTargetDOMElement = getTargetDOMElement; + exports.getPropertyInfo = getPropertyInfo; + exports.PropertyAccessorParser = PropertyAccessorParser; + exports.getAccessorExpression = getAccessorExpression; + exports.ValidateBindingBehavior = ValidateBindingBehavior; + exports.ValidateManuallyBindingBehavior = ValidateManuallyBindingBehavior; + exports.ValidateOnBlurBindingBehavior = ValidateOnBlurBindingBehavior; + exports.ValidateOnChangeBindingBehavior = ValidateOnChangeBindingBehavior; + exports.ValidateOnChangeOrBlurBindingBehavior = ValidateOnChangeOrBlurBindingBehavior; + exports.ValidateEvent = ValidateEvent; + exports.ValidateResult = ValidateResult; + exports.ValidationController = ValidationController; + exports.ValidationControllerFactory = ValidationControllerFactory; + exports.ValidationErrorsCustomAttribute = ValidationErrorsCustomAttribute; + exports.ValidationRendererCustomAttribute = ValidationRendererCustomAttribute; + exports.Validator = Validator; + exports.Rules = Rules; + exports.StandardValidator = StandardValidator; + exports.validationMessages = validationMessages; + exports.ValidationMessageProvider = ValidationMessageProvider; + exports.ValidationMessageParser = ValidationMessageParser; + exports.MessageExpressionValidator = MessageExpressionValidator; + exports.FluentRuleCustomizer = FluentRuleCustomizer; + exports.FluentRules = FluentRules; + exports.FluentEnsure = FluentEnsure; + exports.ValidationRules = ValidationRules; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}); diff --git a/dist/aurelia-validation.d.ts b/dist/aurelia-validation.d.ts new file mode 100644 index 00000000..c3e4d796 --- /dev/null +++ b/dist/aurelia-validation.d.ts @@ -0,0 +1,944 @@ +import { AccessKeyed, AccessMember, AccessScope, Binary, Binding, BindingBehavior, CallMember, Conditional, Expression, Parser, Scope, ValueConverter } from 'aurelia-binding'; +import { Container, Lazy } from 'aurelia-dependency-injection'; +import { TaskQueue } from 'aurelia-task-queue'; +import { BindingLanguage, ViewResources } from 'aurelia-templating'; + +/** + * The result of validating an individual validation rule. + */ +export declare class ValidateResult { + rule: any; + object: any; + propertyName: string | number | null; + valid: boolean; + message: string | null; + private static nextId; + /** + * A number that uniquely identifies the result instance. + */ + id: number; + /** + * @param rule The rule associated with the result. Validator implementation specific. + * @param object The object that was validated. + * @param propertyName The name of the property that was validated. + * @param error The error, if the result is a validation error. + */ + constructor(rule: any, object: any, propertyName: string | number | null, valid: boolean, message?: string | null); + toString(): string | null; +} +/** + * Instructions for the validation controller's validate method. + */ +export interface ValidateInstruction { + /** + * The object to validate. + */ + object: any; + /** + * The property to validate. Optional. + */ + propertyName?: any; + /** + * The rules to validate. Optional. + */ + rules?: any; +} +/** + * The result of a call to the validation controller's validate method. + */ +export interface ControllerValidateResult { + /** + * Whether validation passed. + */ + valid: boolean; + /** + * The validation result of every rule that was evaluated. + */ + results: ValidateResult[]; + /** + * The instruction passed to the controller's validate method. + */ + instruction?: ValidateInstruction; +} +/** + * Gets the DOM element associated with the data-binding. Most of the time it's + * the binding.target but sometimes binding.target is an aurelia custom element, + * or custom attribute which is a javascript "class" instance, so we need to use + * the controller's container to retrieve the actual DOM element. + */ +export declare function getTargetDOMElement(binding: any, view: any): Element; +/** + * Retrieves the object and property name for the specified expression. + * @param expression The expression + * @param source The scope + */ +export declare function getPropertyInfo(expression: Expression, source: Scope): { + object: object; + propertyName: string; +} | null; +export declare type PropertyAccessor = (object: TObject) => TValue; +export declare class PropertyAccessorParser { + private parser; + static inject: (typeof Parser)[]; + constructor(parser: Parser); + parse(property: string | number | PropertyAccessor): string | number; +} +export declare function getAccessorExpression(fn: string): string; +/** + * Validates objects and properties. + */ +export declare abstract class Validator { + /** + * Validates the specified property. + * @param object The object to validate. + * @param propertyName The name of the property to validate. + * @param rules Optional. If unspecified, the implementation should lookup the rules for the + * specified object. This may not be possible for all implementations of this interface. + */ + abstract validateProperty(object: any, propertyName: string, rules?: any): Promise; + /** + * Validates all rules for specified object and it's properties. + * @param object The object to validate. + * @param rules Optional. If unspecified, the implementation should lookup the rules for the + * specified object. This may not be possible for all implementations of this interface. + */ + abstract validateObject(object: any, rules?: any): Promise; + /** + * Determines whether a rule exists in a set of rules. + * @param rules The rules to search. + * @parem rule The rule to find. + */ + abstract ruleExists(rules: any, rule: any): boolean; +} +/** + * Validation triggers. + */ +export declare enum validateTrigger { + /** + * Manual validation. Use the controller's `validate()` and `reset()` methods + * to validate all bindings. + */ + manual = 0, + /** + * Validate the binding when the binding's target element fires a DOM "blur" event. + */ + blur = 1, + /** + * Validate the binding when it updates the model due to a change in the view. + */ + change = 2, + /** + * Validate the binding when the binding's target element fires a DOM "blur" event and + * when it updates the model due to a change in the view. + */ + changeOrBlur = 3 +} +/** + * A result to render (or unrender) and the associated elements (if any) + */ +export interface ResultInstruction { + /** + * The validation result. + */ + result: ValidateResult; + /** + * The associated elements (if any). + */ + elements: Element[]; +} +/** + * Defines which validation results to render and which validation results to unrender. + */ +export interface RenderInstruction { + /** + * The "kind" of render instruction. Either 'validate' or 'reset'. + */ + kind: 'validate' | 'reset'; + /** + * The results to render. + */ + render: ResultInstruction[]; + /** + * The results to unrender. + */ + unrender: ResultInstruction[]; +} +/** + * Renders validation results. + */ +export interface ValidationRenderer { + /** + * Render the validation results. + * @param instruction The render instruction. Defines which results to render and which + * results to unrender. + */ + render(instruction: RenderInstruction): void; +} +export declare class ValidateEvent { + /** + * The type of validate event. Either "validate" or "reset". + */ + readonly type: 'validate' | 'reset'; + /** + * The controller's current array of errors. For an array containing both + * failed rules and passed rules, use the "results" property. + */ + readonly errors: ValidateResult[]; + /** + * The controller's current array of validate results. This + * includes both passed rules and failed rules. For an array of only failed rules, + * use the "errors" property. + */ + readonly results: ValidateResult[]; + /** + * The instruction passed to the "validate" or "reset" event. Will be null when + * the controller's validate/reset method was called with no instruction argument. + */ + readonly instruction: ValidateInstruction | null; + /** + * In events with type === "validate", this property will contain the result + * of validating the instruction (see "instruction" property). Use the controllerValidateResult + * to access the validate results specific to the call to "validate" + * (as opposed to using the "results" and "errors" properties to access the controller's entire + * set of results/errors). + */ + readonly controllerValidateResult: ControllerValidateResult | null; + constructor( + /** + * The type of validate event. Either "validate" or "reset". + */ + type: 'validate' | 'reset', + /** + * The controller's current array of errors. For an array containing both + * failed rules and passed rules, use the "results" property. + */ + errors: ValidateResult[], + /** + * The controller's current array of validate results. This + * includes both passed rules and failed rules. For an array of only failed rules, + * use the "errors" property. + */ + results: ValidateResult[], + /** + * The instruction passed to the "validate" or "reset" event. Will be null when + * the controller's validate/reset method was called with no instruction argument. + */ + instruction: ValidateInstruction | null, + /** + * In events with type === "validate", this property will contain the result + * of validating the instruction (see "instruction" property). Use the controllerValidateResult + * to access the validate results specific to the call to "validate" + * (as opposed to using the "results" and "errors" properties to access the controller's entire + * set of results/errors). + */ + controllerValidateResult: ControllerValidateResult | null); +} +/** + * Orchestrates validation. + * Manages a set of bindings, renderers and objects. + * Exposes the current list of validation results for binding purposes. + */ +export declare class ValidationController { + private validator; + private propertyParser; + static inject: (typeof PropertyAccessorParser | typeof Validator)[]; + private bindings; + private renderers; + /** + * Validation results that have been rendered by the controller. + */ + private results; + /** + * Validation errors that have been rendered by the controller. + */ + errors: ValidateResult[]; + /** + * Whether the controller is currently validating. + */ + validating: boolean; + private elements; + private objects; + /** + * The trigger that will invoke automatic validation of a property used in a binding. + */ + validateTrigger: validateTrigger; + private finishValidating; + private eventCallbacks; + constructor(validator: Validator, propertyParser: PropertyAccessorParser); + /** + * Subscribe to controller validate and reset events. These events occur when the + * controller's "validate"" and "reset" methods are called. + * @param callback The callback to be invoked when the controller validates or resets. + */ + subscribe(callback: (event: ValidateEvent) => void): { + dispose: () => void; + }; + /** + * Adds an object to the set of objects that should be validated when validate is called. + * @param object The object. + * @param rules Optional. The rules. If rules aren't supplied the Validator implementation will lookup the rules. + */ + addObject(object: any, rules?: any): void; + /** + * Removes an object from the set of objects that should be validated when validate is called. + * @param object The object. + */ + removeObject(object: any): void; + /** + * Adds and renders an error. + */ + addError(message: string, object: TObject, propertyName?: string | PropertyAccessor | null): ValidateResult; + /** + * Removes and unrenders an error. + */ + removeError(result: ValidateResult): void; + /** + * Adds a renderer. + * @param renderer The renderer. + */ + addRenderer(renderer: ValidationRenderer): void; + /** + * Removes a renderer. + * @param renderer The renderer. + */ + removeRenderer(renderer: ValidationRenderer): void; + /** + * Registers a binding with the controller. + * @param binding The binding instance. + * @param target The DOM element. + * @param rules (optional) rules associated with the binding. Validator implementation specific. + */ + registerBinding(binding: Binding, target: Element, rules?: any): void; + /** + * Unregisters a binding with the controller. + * @param binding The binding instance. + */ + unregisterBinding(binding: Binding): void; + /** + * Interprets the instruction and returns a predicate that will identify + * relevant results in the list of rendered validation results. + */ + private getInstructionPredicate; + /** + * Validates and renders results. + * @param instruction Optional. Instructions on what to validate. If undefined, all + * objects and bindings will be validated. + */ + validate(instruction?: ValidateInstruction): Promise; + /** + * Resets any rendered validation results (unrenders). + * @param instruction Optional. Instructions on what to reset. If unspecified all rendered results + * will be unrendered. + */ + reset(instruction?: ValidateInstruction): void; + /** + * Gets the elements associated with an object and propertyName (if any). + */ + private getAssociatedElements; + private processResultDelta; + /** + * Validates the property associated with a binding. + */ + validateBinding(binding: Binding): void; + /** + * Resets the results for a property associated with a binding. + */ + resetBinding(binding: Binding): void; + /** + * Changes the controller's validateTrigger. + * @param newTrigger The new validateTrigger + */ + changeTrigger(newTrigger: validateTrigger): void; + /** + * Revalidates the controller's current set of errors. + */ + revalidateErrors(): void; + private invokeCallbacks; +} +declare abstract class ValidateBindingBehaviorBase { + private taskQueue; + constructor(taskQueue: TaskQueue); + protected abstract getValidateTrigger(controller: ValidationController): validateTrigger; + bind(binding: any, source: any, rulesOrController?: ValidationController | any, rules?: any): void; + unbind(binding: any): void; +} +/** + * Binding behavior. Indicates the bound property should be validated + * when the validate trigger specified by the associated controller's + * validateTrigger property occurs. + */ +export declare class ValidateBindingBehavior extends ValidateBindingBehaviorBase { + static inject: (typeof TaskQueue)[]; + getValidateTrigger(controller: ValidationController): validateTrigger; +} +/** + * Binding behavior. Indicates the bound property will be validated + * manually, by calling controller.validate(). No automatic validation + * triggered by data-entry or blur will occur. + */ +export declare class ValidateManuallyBindingBehavior extends ValidateBindingBehaviorBase { + static inject: (typeof TaskQueue)[]; + getValidateTrigger(): validateTrigger; +} +/** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs. + */ +export declare class ValidateOnBlurBindingBehavior extends ValidateBindingBehaviorBase { + static inject: (typeof TaskQueue)[]; + getValidateTrigger(): validateTrigger; +} +/** + * Binding behavior. Indicates the bound property should be validated + * when the associated element is changed by the user, causing a change + * to the model. + */ +export declare class ValidateOnChangeBindingBehavior extends ValidateBindingBehaviorBase { + static inject: (typeof TaskQueue)[]; + getValidateTrigger(): validateTrigger; +} +/** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs or is changed by the user, causing + * a change to the model. + */ +export declare class ValidateOnChangeOrBlurBindingBehavior extends ValidateBindingBehaviorBase { + static inject: (typeof TaskQueue)[]; + getValidateTrigger(): validateTrigger; +} +/** + * Creates ValidationController instances. + */ +export declare class ValidationControllerFactory { + private container; + static get(container: Container): ValidationControllerFactory; + constructor(container: Container); + /** + * Creates a new controller instance. + */ + create(validator?: Validator): ValidationController; + /** + * Creates a new controller and registers it in the current element's container so that it's + * available to the validate binding behavior and renderers. + */ + createForCurrentScope(validator?: Validator): ValidationController; +} +export interface RenderedError { + error: ValidateResult; + targets: Element[]; +} +export declare class ValidationErrorsCustomAttribute implements ValidationRenderer { + private boundaryElement; + private controllerAccessor; + static inject(): ({ + new (): Element; + prototype: Element; + } | Lazy)[]; + controller: ValidationController | null; + errors: RenderedError[]; + private errorsInternal; + constructor(boundaryElement: Element, controllerAccessor: () => ValidationController); + sort(): void; + interestingElements(elements: Element[]): Element[]; + render(instruction: RenderInstruction): void; + bind(): void; + unbind(): void; +} +export declare class ValidationRendererCustomAttribute { + private container; + private controller; + private value; + private renderer; + created(view: any): void; + bind(): void; + unbind(): void; +} +export declare type ValidationDisplayNameAccessor = () => string; +/** + * Information related to a property that is the subject of validation. + */ +export interface RuleProperty { + /** + * The property name. null indicates the rule targets the object itself. + */ + name: string | number | null; + /** + * The displayName of the property (or object). + */ + displayName: string | ValidationDisplayNameAccessor | null; +} +/** + * A rule definition. Associations a rule with a property or object. + */ +export interface Rule { + property: RuleProperty; + condition: (value: TValue, object?: TObject) => boolean | Promise; + config: object; + when: ((object: TObject) => boolean) | null; + messageKey: string; + message: Expression | null; + sequence: number; + tag?: string; +} +/** + * Sets, unsets and retrieves rules on an object or constructor function. + */ +export declare class Rules { + /** + * The name of the property that stores the rules. + */ + private static key; + /** + * Applies the rules to a target. + */ + static set(target: any, rules: Rule[][]): void; + /** + * Removes rules from a target. + */ + static unset(target: any): void; + /** + * Retrieves the target's rules. + */ + static get(target: any): Rule[][] | null; +} +export declare type Chain = any; +export declare type Assign = any; +export declare type AccessThis = any; +export declare type AccessScope = any; +export declare type CallScope = any; +export declare type CallFunction = any; +export declare type PrefixNot = any; +export declare type LiteralPrimitive = any; +export declare type LiteralArray = any; +export declare type LiteralObject = any; +export declare type LiteralString = any; +declare class ExpressionVisitor { + visitChain(chain: Chain): void; + visitBindingBehavior(behavior: BindingBehavior): void; + visitValueConverter(converter: ValueConverter): void; + visitAssign(assign: Assign): void; + visitConditional(conditional: Conditional): void; + visitAccessThis(access: AccessThis): void; + visitAccessScope(access: AccessScope): void; + visitAccessMember(access: AccessMember): void; + visitAccessKeyed(access: AccessKeyed): void; + visitCallScope(call: CallScope): void; + visitCallFunction(call: CallFunction): void; + visitCallMember(call: CallMember): void; + visitPrefix(prefix: PrefixNot): void; + visitBinary(binary: Binary): void; + visitLiteralPrimitive(literal: LiteralPrimitive): void; + visitLiteralArray(literal: LiteralArray): void; + visitLiteralObject(literal: LiteralObject): void; + visitLiteralString(literal: LiteralString): void; + private visitArgs; +} +export declare class ValidationMessageParser { + private bindinqLanguage; + static inject: (typeof BindingLanguage)[]; + private emptyStringExpression; + private nullExpression; + private undefinedExpression; + private cache; + constructor(bindinqLanguage: BindingLanguage); + parse(message: string): Expression; + private coalesce; +} +export declare class MessageExpressionValidator extends ExpressionVisitor { + private originalMessage; + static validate(expression: Expression, originalMessage: string): void; + constructor(originalMessage: string); + visitAccessScope(access: AccessScope): void; +} +export interface ValidationMessages { + [key: string]: string; +} +/** + * Dictionary of validation messages. [messageKey]: messageExpression + */ +export declare const validationMessages: ValidationMessages; +/** + * Retrieves validation messages and property display names. + */ +export declare class ValidationMessageProvider { + parser: ValidationMessageParser; + static inject: (typeof ValidationMessageParser)[]; + constructor(parser: ValidationMessageParser); + /** + * Returns a message binding expression that corresponds to the key. + * @param key The message key. + */ + getMessage(key: string): Expression; + /** + * Formulates a property display name using the property name and the configured + * displayName (if provided). + * Override this with your own custom logic. + * @param propertyName The property name. + */ + getDisplayName(propertyName: string | number, displayName?: string | null | (() => string)): string; +} +/** + * Validates. + * Responsible for validating objects and properties. + */ +export declare class StandardValidator extends Validator { + static inject: (typeof ViewResources | typeof ValidationMessageProvider)[]; + private messageProvider; + private lookupFunctions; + private getDisplayName; + constructor(messageProvider: ValidationMessageProvider, resources: ViewResources); + /** + * Validates the specified property. + * @param object The object to validate. + * @param propertyName The name of the property to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + validateProperty(object: any, propertyName: string | number, rules?: any): Promise; + /** + * Validates all rules for specified object and it's properties. + * @param object The object to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + validateObject(object: any, rules?: any): Promise; + /** + * Determines whether a rule exists in a set of rules. + * @param rules The rules to search. + * @parem rule The rule to find. + */ + ruleExists(rules: Rule[][], rule: Rule): boolean; + private getMessage; + private validateRuleSequence; + private validate; +} +/** + * Part of the fluent rule API. Enables customizing property rules. + */ +export declare class FluentRuleCustomizer { + private fluentEnsure; + private fluentRules; + private parsers; + private rule; + constructor(property: RuleProperty, condition: (value: TValue, object?: TObject) => boolean | Promise, config: object | undefined, fluentEnsure: FluentEnsure, fluentRules: FluentRules, parsers: Parsers); + /** + * Validate subsequent rules after previously declared rules have + * been validated successfully. Use to postpone validation of costly + * rules until less expensive rules pass validation. + */ + then(): this; + /** + * Specifies the key to use when looking up the rule's validation message. + */ + withMessageKey(key: string): this; + /** + * Specifies rule's validation message. + */ + withMessage(message: string): this; + /** + * Specifies a condition that must be met before attempting to validate the rule. + * @param condition A function that accepts the object as a parameter and returns true + * or false whether the rule should be evaluated. + */ + when(condition: (object: TObject) => boolean): this; + /** + * Tags the rule instance, enabling the rule to be found easily + * using ValidationRules.taggedRules(rules, tag) + */ + tag(tag: string): this; + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + ensure(subject: string | ((model: TObject) => TValue2)): FluentRules; + /** + * Targets an object with validation rules. + */ + ensureObject(): FluentRules; + /** + * Rules that have been defined using the fluent API. + */ + readonly rules: Rule[][]; + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + on(target: any): FluentEnsure; + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + satisfies(condition: (value: TValue, object: TObject) => boolean | Promise, config?: object): FluentRuleCustomizer; + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + satisfiesRule(name: string, ...args: any[]): FluentRuleCustomizer; + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + required(): FluentRuleCustomizer; + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + matches(regex: RegExp): FluentRuleCustomizer; + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + email(): FluentRuleCustomizer; + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + minLength(length: number): FluentRuleCustomizer; + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + maxLength(length: number): FluentRuleCustomizer; + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + minItems(count: number): FluentRuleCustomizer; + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + maxItems(count: number): FluentRuleCustomizer; + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + min(value: number): FluentRuleCustomizer; + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + max(value: number): FluentRuleCustomizer; + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + range(min: number, max: number): FluentRuleCustomizer; + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + between(min: number, max: number): FluentRuleCustomizer; + /** + * Applies the "equals" validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + equals(expectedValue: TValue): FluentRuleCustomizer; +} +/** + * Part of the fluent rule API. Enables applying rules to properties and objects. + */ +export declare class FluentRules { + private fluentEnsure; + private parsers; + private property; + static customRules: { + [name: string]: { + condition: (value: any, object?: any, ...fluentArgs: any[]) => boolean | Promise; + argsToConfig?: (...args: any[]) => any; + }; + }; + /** + * Current rule sequence number. Used to postpone evaluation of rules until rules + * with lower sequence number have successfully validated. The "then" fluent API method + * manages this property, there's usually no need to set it directly. + */ + sequence: number; + constructor(fluentEnsure: FluentEnsure, parsers: Parsers, property: RuleProperty); + /** + * Sets the display name of the ensured property. + */ + displayName(name: string | ValidationDisplayNameAccessor | null): this; + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + satisfies(condition: (value: TValue, object?: TObject) => boolean | Promise, config?: object): FluentRuleCustomizer; + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + satisfiesRule(name: string, ...args: any[]): FluentRuleCustomizer; + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + required(): FluentRuleCustomizer; + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + matches(regex: RegExp): FluentRuleCustomizer; + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + email(): FluentRuleCustomizer; + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + minLength(length: number): FluentRuleCustomizer; + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + maxLength(length: number): FluentRuleCustomizer; + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + minItems(count: number): FluentRuleCustomizer; + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + maxItems(count: number): FluentRuleCustomizer; + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + min(constraint: number): FluentRuleCustomizer; + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + max(constraint: number): FluentRuleCustomizer; + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + range(min: number, max: number): FluentRuleCustomizer; + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + between(min: number, max: number): FluentRuleCustomizer; + /** + * Applies the "equals" validation rule to the property. + * null and undefined values are considered valid. + */ + equals(expectedValue: TValue): FluentRuleCustomizer; +} +/** + * Part of the fluent rule API. Enables targeting properties and objects with rules. + */ +export declare class FluentEnsure { + private parsers; + /** + * Rules that have been defined using the fluent API. + */ + rules: Rule[][]; + constructor(parsers: Parsers); + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor + * function. + */ + ensure(property: string | number | PropertyAccessor): FluentRules; + /** + * Targets an object with validation rules. + */ + ensureObject(): FluentRules; + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + on(target: any): this; + private assertInitialized; + private mergeRules; +} +/** + * Fluent rule definition API. + */ +export declare class ValidationRules { + private static parsers; + static initialize(messageParser: ValidationMessageParser, propertyParser: PropertyAccessorParser): void; + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + static ensure(property: string | number | PropertyAccessor): FluentRules; + /** + * Targets an object with validation rules. + */ + static ensureObject(): FluentRules; + /** + * Defines a custom rule. + * @param name The name of the custom rule. Also serves as the message key. + * @param condition The rule function. + * @param message The message expression + * @param argsToConfig A function that maps the rule's arguments to a "config" + * object that can be used when evaluating the message expression. + */ + static customRule(name: string, condition: (value: any, object?: any, ...args: any[]) => boolean | Promise, message: string, argsToConfig?: (...args: any[]) => any): void; + /** + * Returns rules with the matching tag. + * @param rules The rules to search. + * @param tag The tag to search for. + */ + static taggedRules(rules: Rule[][], tag: string): Rule[][]; + /** + * Returns rules that have no tag. + * @param rules The rules to search. + */ + static untaggedRules(rules: Rule[][]): Rule[][]; + /** + * Removes the rules from a class or object. + * @param target A class or object. + */ + static off(target: any): void; +} +export interface Parsers { + message: ValidationMessageParser; + property: PropertyAccessorParser; +} +/** + * Aurelia Validation Configuration API + */ +export declare class AureliaValidationConfiguration { + private validatorType; + /** + * Use a custom Validator implementation. + */ + customValidator(type: { + new (...args: any[]): Validator; + }): void; + /** + * Applies the configuration. + */ + apply(container: Container): void; +} +/** + * Configures the plugin. + */ +export declare function configure(frameworkConfig: { + container: Container; + globalResources?: (...resources: any[]) => any; +}, callback?: (config: AureliaValidationConfiguration) => void): void; \ No newline at end of file diff --git a/dist/commonjs/aurelia-validation.js b/dist/commonjs/aurelia-validation.js new file mode 100644 index 00000000..49e45b31 --- /dev/null +++ b/dist/commonjs/aurelia-validation.js @@ -0,0 +1,1888 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var aureliaPal = require('aurelia-pal'); +var aureliaBinding = require('aurelia-binding'); +var aureliaDependencyInjection = require('aurelia-dependency-injection'); +var aureliaTaskQueue = require('aurelia-task-queue'); +var aureliaTemplating = require('aurelia-templating'); +var LogManager = require('aurelia-logging'); + +/** + * Gets the DOM element associated with the data-binding. Most of the time it's + * the binding.target but sometimes binding.target is an aurelia custom element, + * or custom attribute which is a javascript "class" instance, so we need to use + * the controller's container to retrieve the actual DOM element. + */ +function getTargetDOMElement(binding, view) { + var target = binding.target; + // DOM element + if (target instanceof Element) { + return target; + } + // custom element or custom attribute + // tslint:disable-next-line:prefer-const + for (var i = 0, ii = view.controllers.length; i < ii; i++) { + var controller = view.controllers[i]; + if (controller.viewModel === target) { + var element = controller.container.get(aureliaPal.DOM.Element); + if (element) { + return element; + } + throw new Error("Unable to locate target element for \"" + binding.sourceExpression + "\"."); + } + } + throw new Error("Unable to locate target element for \"" + binding.sourceExpression + "\"."); +} + +function getObject(expression, objectExpression, source) { + var value = objectExpression.evaluate(source, null); + if (value === null || value === undefined || value instanceof Object) { + return value; + } + // tslint:disable-next-line:max-line-length + throw new Error("The '" + objectExpression + "' part of '" + expression + "' evaluates to " + value + " instead of an object, null or undefined."); +} +/** + * Retrieves the object and property name for the specified expression. + * @param expression The expression + * @param source The scope + */ +function getPropertyInfo(expression, source) { + var originalExpression = expression; + while (expression instanceof aureliaBinding.BindingBehavior || expression instanceof aureliaBinding.ValueConverter) { + expression = expression.expression; + } + var object; + var propertyName; + if (expression instanceof aureliaBinding.AccessScope) { + object = aureliaBinding.getContextFor(expression.name, source, expression.ancestor); + propertyName = expression.name; + } + else if (expression instanceof aureliaBinding.AccessMember) { + object = getObject(originalExpression, expression.object, source); + propertyName = expression.name; + } + else if (expression instanceof aureliaBinding.AccessKeyed) { + object = getObject(originalExpression, expression.object, source); + propertyName = expression.key.evaluate(source); + } + else { + throw new Error("Expression '" + originalExpression + "' is not compatible with the validate binding-behavior."); + } + if (object === null || object === undefined) { + return null; + } + return { object: object, propertyName: propertyName }; +} + +function isString(value) { + return Object.prototype.toString.call(value) === '[object String]'; +} +function isNumber(value) { + return Object.prototype.toString.call(value) === '[object Number]'; +} + +var PropertyAccessorParser = /** @class */ (function () { + function PropertyAccessorParser(parser) { + this.parser = parser; + } + PropertyAccessorParser.prototype.parse = function (property) { + if (isString(property) || isNumber(property)) { + return property; + } + var accessorText = getAccessorExpression(property.toString()); + var accessor = this.parser.parse(accessorText); + if (accessor instanceof aureliaBinding.AccessScope + || accessor instanceof aureliaBinding.AccessMember && accessor.object instanceof aureliaBinding.AccessScope) { + return accessor.name; + } + throw new Error("Invalid property expression: \"" + accessor + "\""); + }; + PropertyAccessorParser.inject = [aureliaBinding.Parser]; + return PropertyAccessorParser; +}()); +function getAccessorExpression(fn) { + /* tslint:disable:max-line-length */ + var classic = /^function\s*\([$_\w\d]+\)\s*\{(?:\s*"use strict";)?\s*(?:[$_\w\d.['"\]+;]+)?\s*return\s+[$_\w\d]+\.([$_\w\d]+)\s*;?\s*\}$/; + /* tslint:enable:max-line-length */ + var arrow = /^\(?[$_\w\d]+\)?\s*=>\s*[$_\w\d]+\.([$_\w\d]+)$/; + var match = classic.exec(fn) || arrow.exec(fn); + if (match === null) { + throw new Error("Unable to parse accessor function:\n" + fn); + } + return match[1]; +} + +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ +/* global Reflect, Promise */ + +var extendStatics = function(d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); +}; + +function __extends(d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +} + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +} + +/** + * Validation triggers. + */ +(function (validateTrigger) { + /** + * Manual validation. Use the controller's `validate()` and `reset()` methods + * to validate all bindings. + */ + validateTrigger[validateTrigger["manual"] = 0] = "manual"; + /** + * Validate the binding when the binding's target element fires a DOM "blur" event. + */ + validateTrigger[validateTrigger["blur"] = 1] = "blur"; + /** + * Validate the binding when it updates the model due to a change in the view. + */ + validateTrigger[validateTrigger["change"] = 2] = "change"; + /** + * Validate the binding when the binding's target element fires a DOM "blur" event and + * when it updates the model due to a change in the view. + */ + validateTrigger[validateTrigger["changeOrBlur"] = 3] = "changeOrBlur"; +})(exports.validateTrigger || (exports.validateTrigger = {})); + +/** + * Validates objects and properties. + */ +var Validator = /** @class */ (function () { + function Validator() { + } + return Validator; +}()); + +/** + * The result of validating an individual validation rule. + */ +var ValidateResult = /** @class */ (function () { + /** + * @param rule The rule associated with the result. Validator implementation specific. + * @param object The object that was validated. + * @param propertyName The name of the property that was validated. + * @param error The error, if the result is a validation error. + */ + function ValidateResult(rule, object, propertyName, valid, message) { + if (message === void 0) { message = null; } + this.rule = rule; + this.object = object; + this.propertyName = propertyName; + this.valid = valid; + this.message = message; + this.id = ValidateResult.nextId++; + } + ValidateResult.prototype.toString = function () { + return this.valid ? 'Valid.' : this.message; + }; + ValidateResult.nextId = 0; + return ValidateResult; +}()); + +var ValidateEvent = /** @class */ (function () { + function ValidateEvent( + /** + * The type of validate event. Either "validate" or "reset". + */ + type, + /** + * The controller's current array of errors. For an array containing both + * failed rules and passed rules, use the "results" property. + */ + errors, + /** + * The controller's current array of validate results. This + * includes both passed rules and failed rules. For an array of only failed rules, + * use the "errors" property. + */ + results, + /** + * The instruction passed to the "validate" or "reset" event. Will be null when + * the controller's validate/reset method was called with no instruction argument. + */ + instruction, + /** + * In events with type === "validate", this property will contain the result + * of validating the instruction (see "instruction" property). Use the controllerValidateResult + * to access the validate results specific to the call to "validate" + * (as opposed to using the "results" and "errors" properties to access the controller's entire + * set of results/errors). + */ + controllerValidateResult) { + this.type = type; + this.errors = errors; + this.results = results; + this.instruction = instruction; + this.controllerValidateResult = controllerValidateResult; + } + return ValidateEvent; +}()); + +/** + * Orchestrates validation. + * Manages a set of bindings, renderers and objects. + * Exposes the current list of validation results for binding purposes. + */ +var ValidationController = /** @class */ (function () { + function ValidationController(validator, propertyParser) { + this.validator = validator; + this.propertyParser = propertyParser; + // Registered bindings (via the validate binding behavior) + this.bindings = new Map(); + // Renderers that have been added to the controller instance. + this.renderers = []; + /** + * Validation results that have been rendered by the controller. + */ + this.results = []; + /** + * Validation errors that have been rendered by the controller. + */ + this.errors = []; + /** + * Whether the controller is currently validating. + */ + this.validating = false; + // Elements related to validation results that have been rendered. + this.elements = new Map(); + // Objects that have been added to the controller instance (entity-style validation). + this.objects = new Map(); + /** + * The trigger that will invoke automatic validation of a property used in a binding. + */ + this.validateTrigger = exports.validateTrigger.blur; + // Promise that resolves when validation has completed. + this.finishValidating = Promise.resolve(); + this.eventCallbacks = []; + } + /** + * Subscribe to controller validate and reset events. These events occur when the + * controller's "validate"" and "reset" methods are called. + * @param callback The callback to be invoked when the controller validates or resets. + */ + ValidationController.prototype.subscribe = function (callback) { + var _this = this; + this.eventCallbacks.push(callback); + return { + dispose: function () { + var index = _this.eventCallbacks.indexOf(callback); + if (index === -1) { + return; + } + _this.eventCallbacks.splice(index, 1); + } + }; + }; + /** + * Adds an object to the set of objects that should be validated when validate is called. + * @param object The object. + * @param rules Optional. The rules. If rules aren't supplied the Validator implementation will lookup the rules. + */ + ValidationController.prototype.addObject = function (object, rules) { + this.objects.set(object, rules); + }; + /** + * Removes an object from the set of objects that should be validated when validate is called. + * @param object The object. + */ + ValidationController.prototype.removeObject = function (object) { + this.objects.delete(object); + this.processResultDelta('reset', this.results.filter(function (result) { return result.object === object; }), []); + }; + /** + * Adds and renders an error. + */ + ValidationController.prototype.addError = function (message, object, propertyName) { + if (propertyName === void 0) { propertyName = null; } + var resolvedPropertyName; + if (propertyName === null) { + resolvedPropertyName = propertyName; + } + else { + resolvedPropertyName = this.propertyParser.parse(propertyName); + } + var result = new ValidateResult({ __manuallyAdded__: true }, object, resolvedPropertyName, false, message); + this.processResultDelta('validate', [], [result]); + return result; + }; + /** + * Removes and unrenders an error. + */ + ValidationController.prototype.removeError = function (result) { + if (this.results.indexOf(result) !== -1) { + this.processResultDelta('reset', [result], []); + } + }; + /** + * Adds a renderer. + * @param renderer The renderer. + */ + ValidationController.prototype.addRenderer = function (renderer) { + var _this = this; + this.renderers.push(renderer); + renderer.render({ + kind: 'validate', + render: this.results.map(function (result) { return ({ result: result, elements: _this.elements.get(result) }); }), + unrender: [] + }); + }; + /** + * Removes a renderer. + * @param renderer The renderer. + */ + ValidationController.prototype.removeRenderer = function (renderer) { + var _this = this; + this.renderers.splice(this.renderers.indexOf(renderer), 1); + renderer.render({ + kind: 'reset', + render: [], + unrender: this.results.map(function (result) { return ({ result: result, elements: _this.elements.get(result) }); }) + }); + }; + /** + * Registers a binding with the controller. + * @param binding The binding instance. + * @param target The DOM element. + * @param rules (optional) rules associated with the binding. Validator implementation specific. + */ + ValidationController.prototype.registerBinding = function (binding, target, rules) { + this.bindings.set(binding, { target: target, rules: rules, propertyInfo: null }); + }; + /** + * Unregisters a binding with the controller. + * @param binding The binding instance. + */ + ValidationController.prototype.unregisterBinding = function (binding) { + this.resetBinding(binding); + this.bindings.delete(binding); + }; + /** + * Interprets the instruction and returns a predicate that will identify + * relevant results in the list of rendered validation results. + */ + ValidationController.prototype.getInstructionPredicate = function (instruction) { + var _this = this; + if (instruction) { + var object_1 = instruction.object, propertyName_1 = instruction.propertyName, rules_1 = instruction.rules; + var predicate_1; + if (instruction.propertyName) { + predicate_1 = function (x) { return x.object === object_1 && x.propertyName === propertyName_1; }; + } + else { + predicate_1 = function (x) { return x.object === object_1; }; + } + if (rules_1) { + return function (x) { return predicate_1(x) && _this.validator.ruleExists(rules_1, x.rule); }; + } + return predicate_1; + } + else { + return function () { return true; }; + } + }; + /** + * Validates and renders results. + * @param instruction Optional. Instructions on what to validate. If undefined, all + * objects and bindings will be validated. + */ + ValidationController.prototype.validate = function (instruction) { + var _this = this; + // Get a function that will process the validation instruction. + var execute; + if (instruction) { + // tslint:disable-next-line:prefer-const + var object_2 = instruction.object, propertyName_2 = instruction.propertyName, rules_2 = instruction.rules; + // if rules were not specified, check the object map. + rules_2 = rules_2 || this.objects.get(object_2); + // property specified? + if (instruction.propertyName === undefined) { + // validate the specified object. + execute = function () { return _this.validator.validateObject(object_2, rules_2); }; + } + else { + // validate the specified property. + execute = function () { return _this.validator.validateProperty(object_2, propertyName_2, rules_2); }; + } + } + else { + // validate all objects and bindings. + execute = function () { + var promises = []; + for (var _i = 0, _a = Array.from(_this.objects); _i < _a.length; _i++) { + var _b = _a[_i], object = _b[0], rules = _b[1]; + promises.push(_this.validator.validateObject(object, rules)); + } + for (var _c = 0, _d = Array.from(_this.bindings); _c < _d.length; _c++) { + var _e = _d[_c], binding = _e[0], rules = _e[1].rules; + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (!propertyInfo || _this.objects.has(propertyInfo.object)) { + continue; + } + promises.push(_this.validator.validateProperty(propertyInfo.object, propertyInfo.propertyName, rules)); + } + return Promise.all(promises).then(function (resultSets) { return resultSets.reduce(function (a, b) { return a.concat(b); }, []); }); + }; + } + // Wait for any existing validation to finish, execute the instruction, render the results. + this.validating = true; + var returnPromise = this.finishValidating + .then(execute) + .then(function (newResults) { + var predicate = _this.getInstructionPredicate(instruction); + var oldResults = _this.results.filter(predicate); + _this.processResultDelta('validate', oldResults, newResults); + if (returnPromise === _this.finishValidating) { + _this.validating = false; + } + var result = { + instruction: instruction, + valid: newResults.find(function (x) { return !x.valid; }) === undefined, + results: newResults + }; + _this.invokeCallbacks(instruction, result); + return result; + }) + .catch(function (exception) { + // recover, to enable subsequent calls to validate() + _this.validating = false; + _this.finishValidating = Promise.resolve(); + return Promise.reject(exception); + }); + this.finishValidating = returnPromise; + return returnPromise; + }; + /** + * Resets any rendered validation results (unrenders). + * @param instruction Optional. Instructions on what to reset. If unspecified all rendered results + * will be unrendered. + */ + ValidationController.prototype.reset = function (instruction) { + var predicate = this.getInstructionPredicate(instruction); + var oldResults = this.results.filter(predicate); + this.processResultDelta('reset', oldResults, []); + this.invokeCallbacks(instruction, null); + }; + /** + * Gets the elements associated with an object and propertyName (if any). + */ + ValidationController.prototype.getAssociatedElements = function (_a) { + var object = _a.object, propertyName = _a.propertyName; + var elements = []; + for (var _i = 0, _b = Array.from(this.bindings); _i < _b.length; _i++) { + var _c = _b[_i], binding = _c[0], target = _c[1].target; + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (propertyInfo && propertyInfo.object === object && propertyInfo.propertyName === propertyName) { + elements.push(target); + } + } + return elements; + }; + ValidationController.prototype.processResultDelta = function (kind, oldResults, newResults) { + // prepare the instruction. + var instruction = { + kind: kind, + render: [], + unrender: [] + }; + // create a shallow copy of newResults so we can mutate it without causing side-effects. + newResults = newResults.slice(0); + var _loop_1 = function (oldResult) { + // get the elements associated with the old result. + var elements = this_1.elements.get(oldResult); + // remove the old result from the element map. + this_1.elements.delete(oldResult); + // create the unrender instruction. + instruction.unrender.push({ result: oldResult, elements: elements }); + // determine if there's a corresponding new result for the old result we are unrendering. + var newResultIndex = newResults.findIndex(function (x) { return x.rule === oldResult.rule && x.object === oldResult.object && x.propertyName === oldResult.propertyName; }); + if (newResultIndex === -1) { + // no corresponding new result... simple remove. + this_1.results.splice(this_1.results.indexOf(oldResult), 1); + if (!oldResult.valid) { + this_1.errors.splice(this_1.errors.indexOf(oldResult), 1); + } + } + else { + // there is a corresponding new result... + var newResult = newResults.splice(newResultIndex, 1)[0]; + // get the elements that are associated with the new result. + var elements_1 = this_1.getAssociatedElements(newResult); + this_1.elements.set(newResult, elements_1); + // create a render instruction for the new result. + instruction.render.push({ result: newResult, elements: elements_1 }); + // do an in-place replacement of the old result with the new result. + // this ensures any repeats bound to this.results will not thrash. + this_1.results.splice(this_1.results.indexOf(oldResult), 1, newResult); + if (!oldResult.valid && newResult.valid) { + this_1.errors.splice(this_1.errors.indexOf(oldResult), 1); + } + else if (!oldResult.valid && !newResult.valid) { + this_1.errors.splice(this_1.errors.indexOf(oldResult), 1, newResult); + } + else if (!newResult.valid) { + this_1.errors.push(newResult); + } + } + }; + var this_1 = this; + // create unrender instructions from the old results. + for (var _i = 0, oldResults_1 = oldResults; _i < oldResults_1.length; _i++) { + var oldResult = oldResults_1[_i]; + _loop_1(oldResult); + } + // create render instructions from the remaining new results. + for (var _a = 0, newResults_1 = newResults; _a < newResults_1.length; _a++) { + var result = newResults_1[_a]; + var elements = this.getAssociatedElements(result); + instruction.render.push({ result: result, elements: elements }); + this.elements.set(result, elements); + this.results.push(result); + if (!result.valid) { + this.errors.push(result); + } + } + // render. + for (var _b = 0, _c = this.renderers; _b < _c.length; _b++) { + var renderer = _c[_b]; + renderer.render(instruction); + } + }; + /** + * Validates the property associated with a binding. + */ + ValidationController.prototype.validateBinding = function (binding) { + if (!binding.isBound) { + return; + } + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + var rules; + var registeredBinding = this.bindings.get(binding); + if (registeredBinding) { + rules = registeredBinding.rules; + registeredBinding.propertyInfo = propertyInfo; + } + if (!propertyInfo) { + return; + } + var object = propertyInfo.object, propertyName = propertyInfo.propertyName; + this.validate({ object: object, propertyName: propertyName, rules: rules }); + }; + /** + * Resets the results for a property associated with a binding. + */ + ValidationController.prototype.resetBinding = function (binding) { + var registeredBinding = this.bindings.get(binding); + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (!propertyInfo && registeredBinding) { + propertyInfo = registeredBinding.propertyInfo; + } + if (registeredBinding) { + registeredBinding.propertyInfo = null; + } + if (!propertyInfo) { + return; + } + var object = propertyInfo.object, propertyName = propertyInfo.propertyName; + this.reset({ object: object, propertyName: propertyName }); + }; + /** + * Changes the controller's validateTrigger. + * @param newTrigger The new validateTrigger + */ + ValidationController.prototype.changeTrigger = function (newTrigger) { + this.validateTrigger = newTrigger; + var bindings = Array.from(this.bindings.keys()); + for (var _i = 0, bindings_1 = bindings; _i < bindings_1.length; _i++) { + var binding = bindings_1[_i]; + var source = binding.source; + binding.unbind(); + binding.bind(source); + } + }; + /** + * Revalidates the controller's current set of errors. + */ + ValidationController.prototype.revalidateErrors = function () { + for (var _i = 0, _a = this.errors; _i < _a.length; _i++) { + var _b = _a[_i], object = _b.object, propertyName = _b.propertyName, rule = _b.rule; + if (rule.__manuallyAdded__) { + continue; + } + var rules = [[rule]]; + this.validate({ object: object, propertyName: propertyName, rules: rules }); + } + }; + ValidationController.prototype.invokeCallbacks = function (instruction, result) { + if (this.eventCallbacks.length === 0) { + return; + } + var event = new ValidateEvent(result ? 'validate' : 'reset', this.errors, this.results, instruction || null, result); + for (var i = 0; i < this.eventCallbacks.length; i++) { + this.eventCallbacks[i](event); + } + }; + ValidationController.inject = [Validator, PropertyAccessorParser]; + return ValidationController; +}()); + +/** + * Binding behavior. Indicates the bound property should be validated. + */ +var ValidateBindingBehaviorBase = /** @class */ (function () { + function ValidateBindingBehaviorBase(taskQueue) { + this.taskQueue = taskQueue; + } + ValidateBindingBehaviorBase.prototype.bind = function (binding, source, rulesOrController, rules) { + var _this = this; + // identify the target element. + var target = getTargetDOMElement(binding, source); + // locate the controller. + var controller; + if (rulesOrController instanceof ValidationController) { + controller = rulesOrController; + } + else { + controller = source.container.get(aureliaDependencyInjection.Optional.of(ValidationController)); + rules = rulesOrController; + } + if (controller === null) { + throw new Error("A ValidationController has not been registered."); + } + controller.registerBinding(binding, target, rules); + binding.validationController = controller; + var trigger = this.getValidateTrigger(controller); + // tslint:disable-next-line:no-bitwise + if (trigger & exports.validateTrigger.change) { + binding.vbbUpdateSource = binding.updateSource; + // tslint:disable-next-line:only-arrow-functions + // tslint:disable-next-line:space-before-function-paren + binding.updateSource = function (value) { + this.vbbUpdateSource(value); + this.validationController.validateBinding(this); + }; + } + // tslint:disable-next-line:no-bitwise + if (trigger & exports.validateTrigger.blur) { + binding.validateBlurHandler = function () { + _this.taskQueue.queueMicroTask(function () { return controller.validateBinding(binding); }); + }; + binding.validateTarget = target; + target.addEventListener('blur', binding.validateBlurHandler); + } + if (trigger !== exports.validateTrigger.manual) { + binding.standardUpdateTarget = binding.updateTarget; + // tslint:disable-next-line:only-arrow-functions + // tslint:disable-next-line:space-before-function-paren + binding.updateTarget = function (value) { + this.standardUpdateTarget(value); + this.validationController.resetBinding(this); + }; + } + }; + ValidateBindingBehaviorBase.prototype.unbind = function (binding) { + // reset the binding to it's original state. + if (binding.vbbUpdateSource) { + binding.updateSource = binding.vbbUpdateSource; + binding.vbbUpdateSource = null; + } + if (binding.standardUpdateTarget) { + binding.updateTarget = binding.standardUpdateTarget; + binding.standardUpdateTarget = null; + } + if (binding.validateBlurHandler) { + binding.validateTarget.removeEventListener('blur', binding.validateBlurHandler); + binding.validateBlurHandler = null; + binding.validateTarget = null; + } + binding.validationController.unregisterBinding(binding); + binding.validationController = null; + }; + return ValidateBindingBehaviorBase; +}()); + +/** + * Binding behavior. Indicates the bound property should be validated + * when the validate trigger specified by the associated controller's + * validateTrigger property occurs. + */ +var ValidateBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateBindingBehavior, _super); + function ValidateBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateBindingBehavior.prototype.getValidateTrigger = function (controller) { + return controller.validateTrigger; + }; + ValidateBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + ValidateBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validate') + ], ValidateBindingBehavior); + return ValidateBindingBehavior; +}(ValidateBindingBehaviorBase)); +/** + * Binding behavior. Indicates the bound property will be validated + * manually, by calling controller.validate(). No automatic validation + * triggered by data-entry or blur will occur. + */ +var ValidateManuallyBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateManuallyBindingBehavior, _super); + function ValidateManuallyBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateManuallyBindingBehavior.prototype.getValidateTrigger = function () { + return exports.validateTrigger.manual; + }; + ValidateManuallyBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + ValidateManuallyBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validateManually') + ], ValidateManuallyBindingBehavior); + return ValidateManuallyBindingBehavior; +}(ValidateBindingBehaviorBase)); +/** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs. + */ +var ValidateOnBlurBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateOnBlurBindingBehavior, _super); + function ValidateOnBlurBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateOnBlurBindingBehavior.prototype.getValidateTrigger = function () { + return exports.validateTrigger.blur; + }; + ValidateOnBlurBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + ValidateOnBlurBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validateOnBlur') + ], ValidateOnBlurBindingBehavior); + return ValidateOnBlurBindingBehavior; +}(ValidateBindingBehaviorBase)); +/** + * Binding behavior. Indicates the bound property should be validated + * when the associated element is changed by the user, causing a change + * to the model. + */ +var ValidateOnChangeBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateOnChangeBindingBehavior, _super); + function ValidateOnChangeBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateOnChangeBindingBehavior.prototype.getValidateTrigger = function () { + return exports.validateTrigger.change; + }; + ValidateOnChangeBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + ValidateOnChangeBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validateOnChange') + ], ValidateOnChangeBindingBehavior); + return ValidateOnChangeBindingBehavior; +}(ValidateBindingBehaviorBase)); +/** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs or is changed by the user, causing + * a change to the model. + */ +var ValidateOnChangeOrBlurBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateOnChangeOrBlurBindingBehavior, _super); + function ValidateOnChangeOrBlurBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateOnChangeOrBlurBindingBehavior.prototype.getValidateTrigger = function () { + return exports.validateTrigger.changeOrBlur; + }; + ValidateOnChangeOrBlurBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + ValidateOnChangeOrBlurBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validateOnChangeOrBlur') + ], ValidateOnChangeOrBlurBindingBehavior); + return ValidateOnChangeOrBlurBindingBehavior; +}(ValidateBindingBehaviorBase)); + +/** + * Creates ValidationController instances. + */ +var ValidationControllerFactory = /** @class */ (function () { + function ValidationControllerFactory(container) { + this.container = container; + } + ValidationControllerFactory.get = function (container) { + return new ValidationControllerFactory(container); + }; + /** + * Creates a new controller instance. + */ + ValidationControllerFactory.prototype.create = function (validator) { + if (!validator) { + validator = this.container.get(Validator); + } + var propertyParser = this.container.get(PropertyAccessorParser); + return new ValidationController(validator, propertyParser); + }; + /** + * Creates a new controller and registers it in the current element's container so that it's + * available to the validate binding behavior and renderers. + */ + ValidationControllerFactory.prototype.createForCurrentScope = function (validator) { + var controller = this.create(validator); + this.container.registerInstance(ValidationController, controller); + return controller; + }; + return ValidationControllerFactory; +}()); +ValidationControllerFactory['protocol:aurelia:resolver'] = true; + +var ValidationErrorsCustomAttribute = /** @class */ (function () { + function ValidationErrorsCustomAttribute(boundaryElement, controllerAccessor) { + this.boundaryElement = boundaryElement; + this.controllerAccessor = controllerAccessor; + this.controller = null; + this.errors = []; + this.errorsInternal = []; + } + ValidationErrorsCustomAttribute.inject = function () { + return [aureliaPal.DOM.Element, aureliaDependencyInjection.Lazy.of(ValidationController)]; + }; + ValidationErrorsCustomAttribute.prototype.sort = function () { + this.errorsInternal.sort(function (a, b) { + if (a.targets[0] === b.targets[0]) { + return 0; + } + // tslint:disable-next-line:no-bitwise + return a.targets[0].compareDocumentPosition(b.targets[0]) & 2 ? 1 : -1; + }); + }; + ValidationErrorsCustomAttribute.prototype.interestingElements = function (elements) { + var _this = this; + return elements.filter(function (e) { return _this.boundaryElement.contains(e); }); + }; + ValidationErrorsCustomAttribute.prototype.render = function (instruction) { + var _loop_1 = function (result) { + var index = this_1.errorsInternal.findIndex(function (x) { return x.error === result; }); + if (index !== -1) { + this_1.errorsInternal.splice(index, 1); + } + }; + var this_1 = this; + for (var _i = 0, _a = instruction.unrender; _i < _a.length; _i++) { + var result = _a[_i].result; + _loop_1(result); + } + for (var _b = 0, _c = instruction.render; _b < _c.length; _b++) { + var _d = _c[_b], result = _d.result, elements = _d.elements; + if (result.valid) { + continue; + } + var targets = this.interestingElements(elements); + if (targets.length) { + this.errorsInternal.push({ error: result, targets: targets }); + } + } + this.sort(); + this.errors = this.errorsInternal; + }; + ValidationErrorsCustomAttribute.prototype.bind = function () { + if (!this.controller) { + this.controller = this.controllerAccessor(); + } + // this will call render() with the side-effect of updating this.errors + this.controller.addRenderer(this); + }; + ValidationErrorsCustomAttribute.prototype.unbind = function () { + if (this.controller) { + this.controller.removeRenderer(this); + } + }; + __decorate([ + aureliaTemplating.bindable({ defaultBindingMode: aureliaBinding.bindingMode.oneWay }) + ], ValidationErrorsCustomAttribute.prototype, "controller", void 0); + __decorate([ + aureliaTemplating.bindable({ primaryProperty: true, defaultBindingMode: aureliaBinding.bindingMode.twoWay }) + ], ValidationErrorsCustomAttribute.prototype, "errors", void 0); + ValidationErrorsCustomAttribute = __decorate([ + aureliaTemplating.customAttribute('validation-errors') + ], ValidationErrorsCustomAttribute); + return ValidationErrorsCustomAttribute; +}()); + +var ValidationRendererCustomAttribute = /** @class */ (function () { + function ValidationRendererCustomAttribute() { + } + ValidationRendererCustomAttribute.prototype.created = function (view) { + this.container = view.container; + }; + ValidationRendererCustomAttribute.prototype.bind = function () { + this.controller = this.container.get(ValidationController); + this.renderer = this.container.get(this.value); + this.controller.addRenderer(this.renderer); + }; + ValidationRendererCustomAttribute.prototype.unbind = function () { + this.controller.removeRenderer(this.renderer); + this.controller = null; + this.renderer = null; + }; + ValidationRendererCustomAttribute = __decorate([ + aureliaTemplating.customAttribute('validation-renderer') + ], ValidationRendererCustomAttribute); + return ValidationRendererCustomAttribute; +}()); + +/** + * Sets, unsets and retrieves rules on an object or constructor function. + */ +var Rules = /** @class */ (function () { + function Rules() { + } + /** + * Applies the rules to a target. + */ + Rules.set = function (target, rules) { + if (target instanceof Function) { + target = target.prototype; + } + Object.defineProperty(target, Rules.key, { enumerable: false, configurable: false, writable: true, value: rules }); + }; + /** + * Removes rules from a target. + */ + Rules.unset = function (target) { + if (target instanceof Function) { + target = target.prototype; + } + target[Rules.key] = null; + }; + /** + * Retrieves the target's rules. + */ + Rules.get = function (target) { + return target[Rules.key] || null; + }; + /** + * The name of the property that stores the rules. + */ + Rules.key = '__rules__'; + return Rules; +}()); + +// tslint:disable:no-empty +var ExpressionVisitor = /** @class */ (function () { + function ExpressionVisitor() { + } + ExpressionVisitor.prototype.visitChain = function (chain) { + this.visitArgs(chain.expressions); + }; + ExpressionVisitor.prototype.visitBindingBehavior = function (behavior) { + behavior.expression.accept(this); + this.visitArgs(behavior.args); + }; + ExpressionVisitor.prototype.visitValueConverter = function (converter) { + converter.expression.accept(this); + this.visitArgs(converter.args); + }; + ExpressionVisitor.prototype.visitAssign = function (assign) { + assign.target.accept(this); + assign.value.accept(this); + }; + ExpressionVisitor.prototype.visitConditional = function (conditional) { + conditional.condition.accept(this); + conditional.yes.accept(this); + conditional.no.accept(this); + }; + ExpressionVisitor.prototype.visitAccessThis = function (access) { + access.ancestor = access.ancestor; + }; + ExpressionVisitor.prototype.visitAccessScope = function (access) { + access.name = access.name; + }; + ExpressionVisitor.prototype.visitAccessMember = function (access) { + access.object.accept(this); + }; + ExpressionVisitor.prototype.visitAccessKeyed = function (access) { + access.object.accept(this); + access.key.accept(this); + }; + ExpressionVisitor.prototype.visitCallScope = function (call) { + this.visitArgs(call.args); + }; + ExpressionVisitor.prototype.visitCallFunction = function (call) { + call.func.accept(this); + this.visitArgs(call.args); + }; + ExpressionVisitor.prototype.visitCallMember = function (call) { + call.object.accept(this); + this.visitArgs(call.args); + }; + ExpressionVisitor.prototype.visitPrefix = function (prefix) { + prefix.expression.accept(this); + }; + ExpressionVisitor.prototype.visitBinary = function (binary) { + binary.left.accept(this); + binary.right.accept(this); + }; + ExpressionVisitor.prototype.visitLiteralPrimitive = function (literal) { + literal.value = literal.value; + }; + ExpressionVisitor.prototype.visitLiteralArray = function (literal) { + this.visitArgs(literal.elements); + }; + ExpressionVisitor.prototype.visitLiteralObject = function (literal) { + this.visitArgs(literal.values); + }; + ExpressionVisitor.prototype.visitLiteralString = function (literal) { + literal.value = literal.value; + }; + ExpressionVisitor.prototype.visitArgs = function (args) { + for (var i = 0; i < args.length; i++) { + args[i].accept(this); + } + }; + return ExpressionVisitor; +}()); + +var ValidationMessageParser = /** @class */ (function () { + function ValidationMessageParser(bindinqLanguage) { + this.bindinqLanguage = bindinqLanguage; + this.emptyStringExpression = new aureliaBinding.LiteralString(''); + this.nullExpression = new aureliaBinding.LiteralPrimitive(null); + this.undefinedExpression = new aureliaBinding.LiteralPrimitive(undefined); + this.cache = {}; + } + ValidationMessageParser.prototype.parse = function (message) { + if (this.cache[message] !== undefined) { + return this.cache[message]; + } + var parts = this.bindinqLanguage.parseInterpolation(null, message); + if (parts === null) { + return new aureliaBinding.LiteralString(message); + } + var expression = new aureliaBinding.LiteralString(parts[0]); + for (var i = 1; i < parts.length; i += 2) { + expression = new aureliaBinding.Binary('+', expression, new aureliaBinding.Binary('+', this.coalesce(parts[i]), new aureliaBinding.LiteralString(parts[i + 1]))); + } + MessageExpressionValidator.validate(expression, message); + this.cache[message] = expression; + return expression; + }; + ValidationMessageParser.prototype.coalesce = function (part) { + // part === null || part === undefined ? '' : part + return new aureliaBinding.Conditional(new aureliaBinding.Binary('||', new aureliaBinding.Binary('===', part, this.nullExpression), new aureliaBinding.Binary('===', part, this.undefinedExpression)), this.emptyStringExpression, new aureliaBinding.CallMember(part, 'toString', [])); + }; + ValidationMessageParser.inject = [aureliaTemplating.BindingLanguage]; + return ValidationMessageParser; +}()); +var MessageExpressionValidator = /** @class */ (function (_super) { + __extends(MessageExpressionValidator, _super); + function MessageExpressionValidator(originalMessage) { + var _this = _super.call(this) || this; + _this.originalMessage = originalMessage; + return _this; + } + MessageExpressionValidator.validate = function (expression, originalMessage) { + var visitor = new MessageExpressionValidator(originalMessage); + expression.accept(visitor); + }; + MessageExpressionValidator.prototype.visitAccessScope = function (access) { + if (access.ancestor !== 0) { + throw new Error('$parent is not permitted in validation message expressions.'); + } + if (['displayName', 'propertyName', 'value', 'object', 'config', 'getDisplayName'].indexOf(access.name) !== -1) { + LogManager.getLogger('aurelia-validation') + // tslint:disable-next-line:max-line-length + .warn("Did you mean to use \"$" + access.name + "\" instead of \"" + access.name + "\" in this validation message template: \"" + this.originalMessage + "\"?"); + } + }; + return MessageExpressionValidator; +}(ExpressionVisitor)); + +/** + * Dictionary of validation messages. [messageKey]: messageExpression + */ +var validationMessages = { + /** + * The default validation message. Used with rules that have no standard message. + */ + default: "${$displayName} is invalid.", + required: "${$displayName} is required.", + matches: "${$displayName} is not correctly formatted.", + email: "${$displayName} is not a valid email.", + minLength: "${$displayName} must be at least ${$config.length} character${$config.length === 1 ? '' : 's'}.", + maxLength: "${$displayName} cannot be longer than ${$config.length} character${$config.length === 1 ? '' : 's'}.", + minItems: "${$displayName} must contain at least ${$config.count} item${$config.count === 1 ? '' : 's'}.", + maxItems: "${$displayName} cannot contain more than ${$config.count} item${$config.count === 1 ? '' : 's'}.", + min: "${$displayName} must be at least ${$config.constraint}.", + max: "${$displayName} must be at most ${$config.constraint}.", + range: "${$displayName} must be between or equal to ${$config.min} and ${$config.max}.", + between: "${$displayName} must be between but not equal to ${$config.min} and ${$config.max}.", + equals: "${$displayName} must be ${$config.expectedValue}.", +}; +/** + * Retrieves validation messages and property display names. + */ +var ValidationMessageProvider = /** @class */ (function () { + function ValidationMessageProvider(parser) { + this.parser = parser; + } + /** + * Returns a message binding expression that corresponds to the key. + * @param key The message key. + */ + ValidationMessageProvider.prototype.getMessage = function (key) { + var message; + if (key in validationMessages) { + message = validationMessages[key]; + } + else { + message = validationMessages['default']; + } + return this.parser.parse(message); + }; + /** + * Formulates a property display name using the property name and the configured + * displayName (if provided). + * Override this with your own custom logic. + * @param propertyName The property name. + */ + ValidationMessageProvider.prototype.getDisplayName = function (propertyName, displayName) { + if (displayName !== null && displayName !== undefined) { + return (displayName instanceof Function) ? displayName() : displayName; + } + // split on upper-case letters. + var words = propertyName.toString().split(/(?=[A-Z])/).join(' '); + // capitalize first letter. + return words.charAt(0).toUpperCase() + words.slice(1); + }; + ValidationMessageProvider.inject = [ValidationMessageParser]; + return ValidationMessageProvider; +}()); + +/** + * Validates. + * Responsible for validating objects and properties. + */ +var StandardValidator = /** @class */ (function (_super) { + __extends(StandardValidator, _super); + function StandardValidator(messageProvider, resources) { + var _this = _super.call(this) || this; + _this.messageProvider = messageProvider; + _this.lookupFunctions = resources.lookupFunctions; + _this.getDisplayName = messageProvider.getDisplayName.bind(messageProvider); + return _this; + } + /** + * Validates the specified property. + * @param object The object to validate. + * @param propertyName The name of the property to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + StandardValidator.prototype.validateProperty = function (object, propertyName, rules) { + return this.validate(object, propertyName, rules || null); + }; + /** + * Validates all rules for specified object and it's properties. + * @param object The object to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + StandardValidator.prototype.validateObject = function (object, rules) { + return this.validate(object, null, rules || null); + }; + /** + * Determines whether a rule exists in a set of rules. + * @param rules The rules to search. + * @parem rule The rule to find. + */ + StandardValidator.prototype.ruleExists = function (rules, rule) { + var i = rules.length; + while (i--) { + if (rules[i].indexOf(rule) !== -1) { + return true; + } + } + return false; + }; + StandardValidator.prototype.getMessage = function (rule, object, value) { + var expression = rule.message || this.messageProvider.getMessage(rule.messageKey); + // tslint:disable-next-line:prefer-const + var _a = rule.property, propertyName = _a.name, displayName = _a.displayName; + if (propertyName !== null) { + displayName = this.messageProvider.getDisplayName(propertyName, displayName); + } + var overrideContext = { + $displayName: displayName, + $propertyName: propertyName, + $value: value, + $object: object, + $config: rule.config, + // returns the name of a given property, given just the property name (irrespective of the property's displayName) + // split on capital letters, first letter ensured to be capitalized + $getDisplayName: this.getDisplayName + }; + return expression.evaluate({ bindingContext: object, overrideContext: overrideContext }, this.lookupFunctions); + }; + StandardValidator.prototype.validateRuleSequence = function (object, propertyName, ruleSequence, sequence, results) { + var _this = this; + // are we validating all properties or a single property? + var validateAllProperties = propertyName === null || propertyName === undefined; + var rules = ruleSequence[sequence]; + var allValid = true; + // validate each rule. + var promises = []; + var _loop_1 = function (i) { + var rule = rules[i]; + // is the rule related to the property we're validating. + // tslint:disable-next-line:triple-equals | Use loose equality for property keys + if (!validateAllProperties && rule.property.name != propertyName) { + return "continue"; + } + // is this a conditional rule? is the condition met? + if (rule.when && !rule.when(object)) { + return "continue"; + } + // validate. + var value = rule.property.name === null ? object : object[rule.property.name]; + var promiseOrBoolean = rule.condition(value, object); + if (!(promiseOrBoolean instanceof Promise)) { + promiseOrBoolean = Promise.resolve(promiseOrBoolean); + } + promises.push(promiseOrBoolean.then(function (valid) { + var message = valid ? null : _this.getMessage(rule, object, value); + results.push(new ValidateResult(rule, object, rule.property.name, valid, message)); + allValid = allValid && valid; + return valid; + })); + }; + for (var i = 0; i < rules.length; i++) { + _loop_1(i); + } + return Promise.all(promises) + .then(function () { + sequence++; + if (allValid && sequence < ruleSequence.length) { + return _this.validateRuleSequence(object, propertyName, ruleSequence, sequence, results); + } + return results; + }); + }; + StandardValidator.prototype.validate = function (object, propertyName, rules) { + // rules specified? + if (!rules) { + // no. attempt to locate the rules. + rules = Rules.get(object); + } + // any rules? + if (!rules || rules.length === 0) { + return Promise.resolve([]); + } + return this.validateRuleSequence(object, propertyName, rules, 0, []); + }; + StandardValidator.inject = [ValidationMessageProvider, aureliaTemplating.ViewResources]; + return StandardValidator; +}(Validator)); + +/** + * Part of the fluent rule API. Enables customizing property rules. + */ +var FluentRuleCustomizer = /** @class */ (function () { + function FluentRuleCustomizer(property, condition, config, fluentEnsure, fluentRules, parsers) { + if (config === void 0) { config = {}; } + this.fluentEnsure = fluentEnsure; + this.fluentRules = fluentRules; + this.parsers = parsers; + this.rule = { + property: property, + condition: condition, + config: config, + when: null, + messageKey: 'default', + message: null, + sequence: fluentRules.sequence + }; + this.fluentEnsure._addRule(this.rule); + } + /** + * Validate subsequent rules after previously declared rules have + * been validated successfully. Use to postpone validation of costly + * rules until less expensive rules pass validation. + */ + FluentRuleCustomizer.prototype.then = function () { + this.fluentRules.sequence++; + return this; + }; + /** + * Specifies the key to use when looking up the rule's validation message. + */ + FluentRuleCustomizer.prototype.withMessageKey = function (key) { + this.rule.messageKey = key; + this.rule.message = null; + return this; + }; + /** + * Specifies rule's validation message. + */ + FluentRuleCustomizer.prototype.withMessage = function (message) { + this.rule.messageKey = 'custom'; + this.rule.message = this.parsers.message.parse(message); + return this; + }; + /** + * Specifies a condition that must be met before attempting to validate the rule. + * @param condition A function that accepts the object as a parameter and returns true + * or false whether the rule should be evaluated. + */ + FluentRuleCustomizer.prototype.when = function (condition) { + this.rule.when = condition; + return this; + }; + /** + * Tags the rule instance, enabling the rule to be found easily + * using ValidationRules.taggedRules(rules, tag) + */ + FluentRuleCustomizer.prototype.tag = function (tag) { + this.rule.tag = tag; + return this; + }; + ///// FluentEnsure APIs ///// + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + FluentRuleCustomizer.prototype.ensure = function (subject) { + return this.fluentEnsure.ensure(subject); + }; + /** + * Targets an object with validation rules. + */ + FluentRuleCustomizer.prototype.ensureObject = function () { + return this.fluentEnsure.ensureObject(); + }; + Object.defineProperty(FluentRuleCustomizer.prototype, "rules", { + /** + * Rules that have been defined using the fluent API. + */ + get: function () { + return this.fluentEnsure.rules; + }, + enumerable: true, + configurable: true + }); + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + FluentRuleCustomizer.prototype.on = function (target) { + return this.fluentEnsure.on(target); + }; + ///////// FluentRules APIs ///////// + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + FluentRuleCustomizer.prototype.satisfies = function (condition, config) { + return this.fluentRules.satisfies(condition, config); + }; + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + FluentRuleCustomizer.prototype.satisfiesRule = function (name) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + var _a; + return (_a = this.fluentRules).satisfiesRule.apply(_a, [name].concat(args)); + }; + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + FluentRuleCustomizer.prototype.required = function () { + return this.fluentRules.required(); + }; + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.matches = function (regex) { + return this.fluentRules.matches(regex); + }; + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.email = function () { + return this.fluentRules.email(); + }; + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.minLength = function (length) { + return this.fluentRules.minLength(length); + }; + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.maxLength = function (length) { + return this.fluentRules.maxLength(length); + }; + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.minItems = function (count) { + return this.fluentRules.minItems(count); + }; + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.maxItems = function (count) { + return this.fluentRules.maxItems(count); + }; + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.min = function (value) { + return this.fluentRules.min(value); + }; + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.max = function (value) { + return this.fluentRules.max(value); + }; + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.range = function (min, max) { + return this.fluentRules.range(min, max); + }; + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.between = function (min, max) { + return this.fluentRules.between(min, max); + }; + /** + * Applies the "equals" validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.equals = function (expectedValue) { + return this.fluentRules.equals(expectedValue); + }; + return FluentRuleCustomizer; +}()); +/** + * Part of the fluent rule API. Enables applying rules to properties and objects. + */ +var FluentRules = /** @class */ (function () { + function FluentRules(fluentEnsure, parsers, property) { + this.fluentEnsure = fluentEnsure; + this.parsers = parsers; + this.property = property; + /** + * Current rule sequence number. Used to postpone evaluation of rules until rules + * with lower sequence number have successfully validated. The "then" fluent API method + * manages this property, there's usually no need to set it directly. + */ + this.sequence = 0; + } + /** + * Sets the display name of the ensured property. + */ + FluentRules.prototype.displayName = function (name) { + this.property.displayName = name; + return this; + }; + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + FluentRules.prototype.satisfies = function (condition, config) { + return new FluentRuleCustomizer(this.property, condition, config, this.fluentEnsure, this, this.parsers); + }; + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + FluentRules.prototype.satisfiesRule = function (name) { + var _this = this; + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + var rule = FluentRules.customRules[name]; + if (!rule) { + // standard rule? + rule = this[name]; + if (rule instanceof Function) { + return rule.call.apply(rule, [this].concat(args)); + } + throw new Error("Rule with name \"" + name + "\" does not exist."); + } + var config = rule.argsToConfig ? rule.argsToConfig.apply(rule, args) : undefined; + return this.satisfies(function (value, obj) { + var _a; + return (_a = rule.condition).call.apply(_a, [_this, value, obj].concat(args)); + }, config) + .withMessageKey(name); + }; + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + FluentRules.prototype.required = function () { + return this.satisfies(function (value) { + return value !== null + && value !== undefined + && !(isString(value) && !/\S/.test(value)); + }).withMessageKey('required'); + }; + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.matches = function (regex) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length === 0 || regex.test(value); }) + .withMessageKey('matches'); + }; + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.email = function () { + // regex from https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address + /* tslint:disable:max-line-length */ + return this.matches(/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/) + /* tslint:enable:max-line-length */ + .withMessageKey('email'); + }; + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.minLength = function (length) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length === 0 || value.length >= length; }, { length: length }) + .withMessageKey('minLength'); + }; + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.maxLength = function (length) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length === 0 || value.length <= length; }, { length: length }) + .withMessageKey('maxLength'); + }; + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRules.prototype.minItems = function (count) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length >= count; }, { count: count }) + .withMessageKey('minItems'); + }; + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRules.prototype.maxItems = function (count) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length <= count; }, { count: count }) + .withMessageKey('maxItems'); + }; + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRules.prototype.min = function (constraint) { + return this.satisfies(function (value) { return value === null || value === undefined || value >= constraint; }, { constraint: constraint }) + .withMessageKey('min'); + }; + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRules.prototype.max = function (constraint) { + return this.satisfies(function (value) { return value === null || value === undefined || value <= constraint; }, { constraint: constraint }) + .withMessageKey('max'); + }; + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRules.prototype.range = function (min, max) { + return this.satisfies(function (value) { return value === null || value === undefined || (value >= min && value <= max); }, { min: min, max: max }) + .withMessageKey('range'); + }; + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRules.prototype.between = function (min, max) { + return this.satisfies(function (value) { return value === null || value === undefined || (value > min && value < max); }, { min: min, max: max }) + .withMessageKey('between'); + }; + /** + * Applies the "equals" validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRules.prototype.equals = function (expectedValue) { + return this.satisfies(function (value) { return value === null || value === undefined || value === '' || value === expectedValue; }, { expectedValue: expectedValue }) + .withMessageKey('equals'); + }; + FluentRules.customRules = {}; + return FluentRules; +}()); +/** + * Part of the fluent rule API. Enables targeting properties and objects with rules. + */ +var FluentEnsure = /** @class */ (function () { + function FluentEnsure(parsers) { + this.parsers = parsers; + /** + * Rules that have been defined using the fluent API. + */ + this.rules = []; + } + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor + * function. + */ + FluentEnsure.prototype.ensure = function (property) { + this.assertInitialized(); + var name = this.parsers.property.parse(property); + var fluentRules = new FluentRules(this, this.parsers, { name: name, displayName: null }); + return this.mergeRules(fluentRules, name); + }; + /** + * Targets an object with validation rules. + */ + FluentEnsure.prototype.ensureObject = function () { + this.assertInitialized(); + var fluentRules = new FluentRules(this, this.parsers, { name: null, displayName: null }); + return this.mergeRules(fluentRules, null); + }; + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + FluentEnsure.prototype.on = function (target) { + Rules.set(target, this.rules); + return this; + }; + /** + * Adds a rule definition to the sequenced ruleset. + * @internal + */ + FluentEnsure.prototype._addRule = function (rule) { + while (this.rules.length < rule.sequence + 1) { + this.rules.push([]); + } + this.rules[rule.sequence].push(rule); + }; + FluentEnsure.prototype.assertInitialized = function () { + if (this.parsers) { + return; + } + throw new Error("Did you forget to add \".plugin('aurelia-validation')\" to your main.js?"); + }; + FluentEnsure.prototype.mergeRules = function (fluentRules, propertyName) { + // tslint:disable-next-line:triple-equals | Use loose equality for property keys + var existingRules = this.rules.find(function (r) { return r.length > 0 && r[0].property.name == propertyName; }); + if (existingRules) { + var rule = existingRules[existingRules.length - 1]; + fluentRules.sequence = rule.sequence; + if (rule.property.displayName !== null) { + fluentRules = fluentRules.displayName(rule.property.displayName); + } + } + return fluentRules; + }; + return FluentEnsure; +}()); +/** + * Fluent rule definition API. + */ +var ValidationRules = /** @class */ (function () { + function ValidationRules() { + } + ValidationRules.initialize = function (messageParser, propertyParser) { + this.parsers = { + message: messageParser, + property: propertyParser + }; + }; + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + ValidationRules.ensure = function (property) { + return new FluentEnsure(ValidationRules.parsers).ensure(property); + }; + /** + * Targets an object with validation rules. + */ + ValidationRules.ensureObject = function () { + return new FluentEnsure(ValidationRules.parsers).ensureObject(); + }; + /** + * Defines a custom rule. + * @param name The name of the custom rule. Also serves as the message key. + * @param condition The rule function. + * @param message The message expression + * @param argsToConfig A function that maps the rule's arguments to a "config" + * object that can be used when evaluating the message expression. + */ + ValidationRules.customRule = function (name, condition, message, argsToConfig) { + validationMessages[name] = message; + FluentRules.customRules[name] = { condition: condition, argsToConfig: argsToConfig }; + }; + /** + * Returns rules with the matching tag. + * @param rules The rules to search. + * @param tag The tag to search for. + */ + ValidationRules.taggedRules = function (rules, tag) { + return rules.map(function (x) { return x.filter(function (r) { return r.tag === tag; }); }); + }; + /** + * Returns rules that have no tag. + * @param rules The rules to search. + */ + ValidationRules.untaggedRules = function (rules) { + return rules.map(function (x) { return x.filter(function (r) { return r.tag === undefined; }); }); + }; + /** + * Removes the rules from a class or object. + * @param target A class or object. + */ + ValidationRules.off = function (target) { + Rules.unset(target); + }; + return ValidationRules; +}()); + +// Exports +/** + * Aurelia Validation Configuration API + */ +var AureliaValidationConfiguration = /** @class */ (function () { + function AureliaValidationConfiguration() { + this.validatorType = StandardValidator; + } + /** + * Use a custom Validator implementation. + */ + AureliaValidationConfiguration.prototype.customValidator = function (type) { + this.validatorType = type; + }; + /** + * Applies the configuration. + */ + AureliaValidationConfiguration.prototype.apply = function (container) { + var validator = container.get(this.validatorType); + container.registerInstance(Validator, validator); + }; + return AureliaValidationConfiguration; +}()); +/** + * Configures the plugin. + */ +function configure( +// tslint:disable-next-line:ban-types +frameworkConfig, callback) { + // the fluent rule definition API needs the parser to translate messages + // to interpolation expressions. + var messageParser = frameworkConfig.container.get(ValidationMessageParser); + var propertyParser = frameworkConfig.container.get(PropertyAccessorParser); + ValidationRules.initialize(messageParser, propertyParser); + // configure... + var config = new AureliaValidationConfiguration(); + if (callback instanceof Function) { + callback(config); + } + config.apply(frameworkConfig.container); + // globalize the behaviors. + if (frameworkConfig.globalResources) { + frameworkConfig.globalResources(ValidateBindingBehavior, ValidateManuallyBindingBehavior, ValidateOnBlurBindingBehavior, ValidateOnChangeBindingBehavior, ValidateOnChangeOrBlurBindingBehavior, ValidationErrorsCustomAttribute, ValidationRendererCustomAttribute); + } +} + +exports.AureliaValidationConfiguration = AureliaValidationConfiguration; +exports.configure = configure; +exports.getTargetDOMElement = getTargetDOMElement; +exports.getPropertyInfo = getPropertyInfo; +exports.PropertyAccessorParser = PropertyAccessorParser; +exports.getAccessorExpression = getAccessorExpression; +exports.ValidateBindingBehavior = ValidateBindingBehavior; +exports.ValidateManuallyBindingBehavior = ValidateManuallyBindingBehavior; +exports.ValidateOnBlurBindingBehavior = ValidateOnBlurBindingBehavior; +exports.ValidateOnChangeBindingBehavior = ValidateOnChangeBindingBehavior; +exports.ValidateOnChangeOrBlurBindingBehavior = ValidateOnChangeOrBlurBindingBehavior; +exports.ValidateEvent = ValidateEvent; +exports.ValidateResult = ValidateResult; +exports.ValidationController = ValidationController; +exports.ValidationControllerFactory = ValidationControllerFactory; +exports.ValidationErrorsCustomAttribute = ValidationErrorsCustomAttribute; +exports.ValidationRendererCustomAttribute = ValidationRendererCustomAttribute; +exports.Validator = Validator; +exports.Rules = Rules; +exports.StandardValidator = StandardValidator; +exports.validationMessages = validationMessages; +exports.ValidationMessageProvider = ValidationMessageProvider; +exports.ValidationMessageParser = ValidationMessageParser; +exports.MessageExpressionValidator = MessageExpressionValidator; +exports.FluentRuleCustomizer = FluentRuleCustomizer; +exports.FluentRules = FluentRules; +exports.FluentEnsure = FluentEnsure; +exports.ValidationRules = ValidationRules; diff --git a/dist/es2015/aurelia-validation.js b/dist/es2015/aurelia-validation.js new file mode 100644 index 00000000..7a46b442 --- /dev/null +++ b/dist/es2015/aurelia-validation.js @@ -0,0 +1,1733 @@ +import { DOM } from 'aurelia-pal'; +import { AccessMember, AccessScope, AccessKeyed, BindingBehavior, ValueConverter, getContextFor, Parser, bindingBehavior, bindingMode, LiteralString, Binary, Conditional, LiteralPrimitive, CallMember } from 'aurelia-binding'; +import { Optional, Lazy } from 'aurelia-dependency-injection'; +import { TaskQueue } from 'aurelia-task-queue'; +import { customAttribute, bindable, BindingLanguage, ViewResources } from 'aurelia-templating'; +import { getLogger } from 'aurelia-logging'; + +/** + * Gets the DOM element associated with the data-binding. Most of the time it's + * the binding.target but sometimes binding.target is an aurelia custom element, + * or custom attribute which is a javascript "class" instance, so we need to use + * the controller's container to retrieve the actual DOM element. + */ +function getTargetDOMElement(binding, view) { + const target = binding.target; + // DOM element + if (target instanceof Element) { + return target; + } + // custom element or custom attribute + // tslint:disable-next-line:prefer-const + for (let i = 0, ii = view.controllers.length; i < ii; i++) { + const controller = view.controllers[i]; + if (controller.viewModel === target) { + const element = controller.container.get(DOM.Element); + if (element) { + return element; + } + throw new Error(`Unable to locate target element for "${binding.sourceExpression}".`); + } + } + throw new Error(`Unable to locate target element for "${binding.sourceExpression}".`); +} + +function getObject(expression, objectExpression, source) { + const value = objectExpression.evaluate(source, null); + if (value === null || value === undefined || value instanceof Object) { + return value; + } + // tslint:disable-next-line:max-line-length + throw new Error(`The '${objectExpression}' part of '${expression}' evaluates to ${value} instead of an object, null or undefined.`); +} +/** + * Retrieves the object and property name for the specified expression. + * @param expression The expression + * @param source The scope + */ +function getPropertyInfo(expression, source) { + const originalExpression = expression; + while (expression instanceof BindingBehavior || expression instanceof ValueConverter) { + expression = expression.expression; + } + let object; + let propertyName; + if (expression instanceof AccessScope) { + object = getContextFor(expression.name, source, expression.ancestor); + propertyName = expression.name; + } + else if (expression instanceof AccessMember) { + object = getObject(originalExpression, expression.object, source); + propertyName = expression.name; + } + else if (expression instanceof AccessKeyed) { + object = getObject(originalExpression, expression.object, source); + propertyName = expression.key.evaluate(source); + } + else { + throw new Error(`Expression '${originalExpression}' is not compatible with the validate binding-behavior.`); + } + if (object === null || object === undefined) { + return null; + } + return { object, propertyName }; +} + +function isString(value) { + return Object.prototype.toString.call(value) === '[object String]'; +} +function isNumber(value) { + return Object.prototype.toString.call(value) === '[object Number]'; +} + +class PropertyAccessorParser { + constructor(parser) { + this.parser = parser; + } + parse(property) { + if (isString(property) || isNumber(property)) { + return property; + } + const accessorText = getAccessorExpression(property.toString()); + const accessor = this.parser.parse(accessorText); + if (accessor instanceof AccessScope + || accessor instanceof AccessMember && accessor.object instanceof AccessScope) { + return accessor.name; + } + throw new Error(`Invalid property expression: "${accessor}"`); + } +} +PropertyAccessorParser.inject = [Parser]; +function getAccessorExpression(fn) { + /* tslint:disable:max-line-length */ + const classic = /^function\s*\([$_\w\d]+\)\s*\{(?:\s*"use strict";)?\s*(?:[$_\w\d.['"\]+;]+)?\s*return\s+[$_\w\d]+\.([$_\w\d]+)\s*;?\s*\}$/; + /* tslint:enable:max-line-length */ + const arrow = /^\(?[$_\w\d]+\)?\s*=>\s*[$_\w\d]+\.([$_\w\d]+)$/; + const match = classic.exec(fn) || arrow.exec(fn); + if (match === null) { + throw new Error(`Unable to parse accessor function:\n${fn}`); + } + return match[1]; +} + +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +} + +/** + * Validation triggers. + */ +var validateTrigger; +(function (validateTrigger) { + /** + * Manual validation. Use the controller's `validate()` and `reset()` methods + * to validate all bindings. + */ + validateTrigger[validateTrigger["manual"] = 0] = "manual"; + /** + * Validate the binding when the binding's target element fires a DOM "blur" event. + */ + validateTrigger[validateTrigger["blur"] = 1] = "blur"; + /** + * Validate the binding when it updates the model due to a change in the view. + */ + validateTrigger[validateTrigger["change"] = 2] = "change"; + /** + * Validate the binding when the binding's target element fires a DOM "blur" event and + * when it updates the model due to a change in the view. + */ + validateTrigger[validateTrigger["changeOrBlur"] = 3] = "changeOrBlur"; +})(validateTrigger || (validateTrigger = {})); + +/** + * Validates objects and properties. + */ +class Validator { +} + +/** + * The result of validating an individual validation rule. + */ +class ValidateResult { + /** + * @param rule The rule associated with the result. Validator implementation specific. + * @param object The object that was validated. + * @param propertyName The name of the property that was validated. + * @param error The error, if the result is a validation error. + */ + constructor(rule, object, propertyName, valid, message = null) { + this.rule = rule; + this.object = object; + this.propertyName = propertyName; + this.valid = valid; + this.message = message; + this.id = ValidateResult.nextId++; + } + toString() { + return this.valid ? 'Valid.' : this.message; + } +} +ValidateResult.nextId = 0; + +class ValidateEvent { + constructor( + /** + * The type of validate event. Either "validate" or "reset". + */ + type, + /** + * The controller's current array of errors. For an array containing both + * failed rules and passed rules, use the "results" property. + */ + errors, + /** + * The controller's current array of validate results. This + * includes both passed rules and failed rules. For an array of only failed rules, + * use the "errors" property. + */ + results, + /** + * The instruction passed to the "validate" or "reset" event. Will be null when + * the controller's validate/reset method was called with no instruction argument. + */ + instruction, + /** + * In events with type === "validate", this property will contain the result + * of validating the instruction (see "instruction" property). Use the controllerValidateResult + * to access the validate results specific to the call to "validate" + * (as opposed to using the "results" and "errors" properties to access the controller's entire + * set of results/errors). + */ + controllerValidateResult) { + this.type = type; + this.errors = errors; + this.results = results; + this.instruction = instruction; + this.controllerValidateResult = controllerValidateResult; + } +} + +/** + * Orchestrates validation. + * Manages a set of bindings, renderers and objects. + * Exposes the current list of validation results for binding purposes. + */ +class ValidationController { + constructor(validator, propertyParser) { + this.validator = validator; + this.propertyParser = propertyParser; + // Registered bindings (via the validate binding behavior) + this.bindings = new Map(); + // Renderers that have been added to the controller instance. + this.renderers = []; + /** + * Validation results that have been rendered by the controller. + */ + this.results = []; + /** + * Validation errors that have been rendered by the controller. + */ + this.errors = []; + /** + * Whether the controller is currently validating. + */ + this.validating = false; + // Elements related to validation results that have been rendered. + this.elements = new Map(); + // Objects that have been added to the controller instance (entity-style validation). + this.objects = new Map(); + /** + * The trigger that will invoke automatic validation of a property used in a binding. + */ + this.validateTrigger = validateTrigger.blur; + // Promise that resolves when validation has completed. + this.finishValidating = Promise.resolve(); + this.eventCallbacks = []; + } + /** + * Subscribe to controller validate and reset events. These events occur when the + * controller's "validate"" and "reset" methods are called. + * @param callback The callback to be invoked when the controller validates or resets. + */ + subscribe(callback) { + this.eventCallbacks.push(callback); + return { + dispose: () => { + const index = this.eventCallbacks.indexOf(callback); + if (index === -1) { + return; + } + this.eventCallbacks.splice(index, 1); + } + }; + } + /** + * Adds an object to the set of objects that should be validated when validate is called. + * @param object The object. + * @param rules Optional. The rules. If rules aren't supplied the Validator implementation will lookup the rules. + */ + addObject(object, rules) { + this.objects.set(object, rules); + } + /** + * Removes an object from the set of objects that should be validated when validate is called. + * @param object The object. + */ + removeObject(object) { + this.objects.delete(object); + this.processResultDelta('reset', this.results.filter(result => result.object === object), []); + } + /** + * Adds and renders an error. + */ + addError(message, object, propertyName = null) { + let resolvedPropertyName; + if (propertyName === null) { + resolvedPropertyName = propertyName; + } + else { + resolvedPropertyName = this.propertyParser.parse(propertyName); + } + const result = new ValidateResult({ __manuallyAdded__: true }, object, resolvedPropertyName, false, message); + this.processResultDelta('validate', [], [result]); + return result; + } + /** + * Removes and unrenders an error. + */ + removeError(result) { + if (this.results.indexOf(result) !== -1) { + this.processResultDelta('reset', [result], []); + } + } + /** + * Adds a renderer. + * @param renderer The renderer. + */ + addRenderer(renderer) { + this.renderers.push(renderer); + renderer.render({ + kind: 'validate', + render: this.results.map(result => ({ result, elements: this.elements.get(result) })), + unrender: [] + }); + } + /** + * Removes a renderer. + * @param renderer The renderer. + */ + removeRenderer(renderer) { + this.renderers.splice(this.renderers.indexOf(renderer), 1); + renderer.render({ + kind: 'reset', + render: [], + unrender: this.results.map(result => ({ result, elements: this.elements.get(result) })) + }); + } + /** + * Registers a binding with the controller. + * @param binding The binding instance. + * @param target The DOM element. + * @param rules (optional) rules associated with the binding. Validator implementation specific. + */ + registerBinding(binding, target, rules) { + this.bindings.set(binding, { target, rules, propertyInfo: null }); + } + /** + * Unregisters a binding with the controller. + * @param binding The binding instance. + */ + unregisterBinding(binding) { + this.resetBinding(binding); + this.bindings.delete(binding); + } + /** + * Interprets the instruction and returns a predicate that will identify + * relevant results in the list of rendered validation results. + */ + getInstructionPredicate(instruction) { + if (instruction) { + const { object, propertyName, rules } = instruction; + let predicate; + if (instruction.propertyName) { + predicate = x => x.object === object && x.propertyName === propertyName; + } + else { + predicate = x => x.object === object; + } + if (rules) { + return x => predicate(x) && this.validator.ruleExists(rules, x.rule); + } + return predicate; + } + else { + return () => true; + } + } + /** + * Validates and renders results. + * @param instruction Optional. Instructions on what to validate. If undefined, all + * objects and bindings will be validated. + */ + validate(instruction) { + // Get a function that will process the validation instruction. + let execute; + if (instruction) { + // tslint:disable-next-line:prefer-const + let { object, propertyName, rules } = instruction; + // if rules were not specified, check the object map. + rules = rules || this.objects.get(object); + // property specified? + if (instruction.propertyName === undefined) { + // validate the specified object. + execute = () => this.validator.validateObject(object, rules); + } + else { + // validate the specified property. + execute = () => this.validator.validateProperty(object, propertyName, rules); + } + } + else { + // validate all objects and bindings. + execute = () => { + const promises = []; + for (const [object, rules] of Array.from(this.objects)) { + promises.push(this.validator.validateObject(object, rules)); + } + for (const [binding, { rules }] of Array.from(this.bindings)) { + const propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (!propertyInfo || this.objects.has(propertyInfo.object)) { + continue; + } + promises.push(this.validator.validateProperty(propertyInfo.object, propertyInfo.propertyName, rules)); + } + return Promise.all(promises).then(resultSets => resultSets.reduce((a, b) => a.concat(b), [])); + }; + } + // Wait for any existing validation to finish, execute the instruction, render the results. + this.validating = true; + const returnPromise = this.finishValidating + .then(execute) + .then((newResults) => { + const predicate = this.getInstructionPredicate(instruction); + const oldResults = this.results.filter(predicate); + this.processResultDelta('validate', oldResults, newResults); + if (returnPromise === this.finishValidating) { + this.validating = false; + } + const result = { + instruction, + valid: newResults.find(x => !x.valid) === undefined, + results: newResults + }; + this.invokeCallbacks(instruction, result); + return result; + }) + .catch(exception => { + // recover, to enable subsequent calls to validate() + this.validating = false; + this.finishValidating = Promise.resolve(); + return Promise.reject(exception); + }); + this.finishValidating = returnPromise; + return returnPromise; + } + /** + * Resets any rendered validation results (unrenders). + * @param instruction Optional. Instructions on what to reset. If unspecified all rendered results + * will be unrendered. + */ + reset(instruction) { + const predicate = this.getInstructionPredicate(instruction); + const oldResults = this.results.filter(predicate); + this.processResultDelta('reset', oldResults, []); + this.invokeCallbacks(instruction, null); + } + /** + * Gets the elements associated with an object and propertyName (if any). + */ + getAssociatedElements({ object, propertyName }) { + const elements = []; + for (const [binding, { target }] of Array.from(this.bindings)) { + const propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (propertyInfo && propertyInfo.object === object && propertyInfo.propertyName === propertyName) { + elements.push(target); + } + } + return elements; + } + processResultDelta(kind, oldResults, newResults) { + // prepare the instruction. + const instruction = { + kind, + render: [], + unrender: [] + }; + // create a shallow copy of newResults so we can mutate it without causing side-effects. + newResults = newResults.slice(0); + // create unrender instructions from the old results. + for (const oldResult of oldResults) { + // get the elements associated with the old result. + const elements = this.elements.get(oldResult); + // remove the old result from the element map. + this.elements.delete(oldResult); + // create the unrender instruction. + instruction.unrender.push({ result: oldResult, elements }); + // determine if there's a corresponding new result for the old result we are unrendering. + const newResultIndex = newResults.findIndex(x => x.rule === oldResult.rule && x.object === oldResult.object && x.propertyName === oldResult.propertyName); + if (newResultIndex === -1) { + // no corresponding new result... simple remove. + this.results.splice(this.results.indexOf(oldResult), 1); + if (!oldResult.valid) { + this.errors.splice(this.errors.indexOf(oldResult), 1); + } + } + else { + // there is a corresponding new result... + const newResult = newResults.splice(newResultIndex, 1)[0]; + // get the elements that are associated with the new result. + const elements = this.getAssociatedElements(newResult); + this.elements.set(newResult, elements); + // create a render instruction for the new result. + instruction.render.push({ result: newResult, elements }); + // do an in-place replacement of the old result with the new result. + // this ensures any repeats bound to this.results will not thrash. + this.results.splice(this.results.indexOf(oldResult), 1, newResult); + if (!oldResult.valid && newResult.valid) { + this.errors.splice(this.errors.indexOf(oldResult), 1); + } + else if (!oldResult.valid && !newResult.valid) { + this.errors.splice(this.errors.indexOf(oldResult), 1, newResult); + } + else if (!newResult.valid) { + this.errors.push(newResult); + } + } + } + // create render instructions from the remaining new results. + for (const result of newResults) { + const elements = this.getAssociatedElements(result); + instruction.render.push({ result, elements }); + this.elements.set(result, elements); + this.results.push(result); + if (!result.valid) { + this.errors.push(result); + } + } + // render. + for (const renderer of this.renderers) { + renderer.render(instruction); + } + } + /** + * Validates the property associated with a binding. + */ + validateBinding(binding) { + if (!binding.isBound) { + return; + } + const propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + let rules; + const registeredBinding = this.bindings.get(binding); + if (registeredBinding) { + rules = registeredBinding.rules; + registeredBinding.propertyInfo = propertyInfo; + } + if (!propertyInfo) { + return; + } + const { object, propertyName } = propertyInfo; + this.validate({ object, propertyName, rules }); + } + /** + * Resets the results for a property associated with a binding. + */ + resetBinding(binding) { + const registeredBinding = this.bindings.get(binding); + let propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (!propertyInfo && registeredBinding) { + propertyInfo = registeredBinding.propertyInfo; + } + if (registeredBinding) { + registeredBinding.propertyInfo = null; + } + if (!propertyInfo) { + return; + } + const { object, propertyName } = propertyInfo; + this.reset({ object, propertyName }); + } + /** + * Changes the controller's validateTrigger. + * @param newTrigger The new validateTrigger + */ + changeTrigger(newTrigger) { + this.validateTrigger = newTrigger; + const bindings = Array.from(this.bindings.keys()); + for (const binding of bindings) { + const source = binding.source; + binding.unbind(); + binding.bind(source); + } + } + /** + * Revalidates the controller's current set of errors. + */ + revalidateErrors() { + for (const { object, propertyName, rule } of this.errors) { + if (rule.__manuallyAdded__) { + continue; + } + const rules = [[rule]]; + this.validate({ object, propertyName, rules }); + } + } + invokeCallbacks(instruction, result) { + if (this.eventCallbacks.length === 0) { + return; + } + const event = new ValidateEvent(result ? 'validate' : 'reset', this.errors, this.results, instruction || null, result); + for (let i = 0; i < this.eventCallbacks.length; i++) { + this.eventCallbacks[i](event); + } + } +} +ValidationController.inject = [Validator, PropertyAccessorParser]; + +/** + * Binding behavior. Indicates the bound property should be validated. + */ +class ValidateBindingBehaviorBase { + constructor(taskQueue) { + this.taskQueue = taskQueue; + } + bind(binding, source, rulesOrController, rules) { + // identify the target element. + const target = getTargetDOMElement(binding, source); + // locate the controller. + let controller; + if (rulesOrController instanceof ValidationController) { + controller = rulesOrController; + } + else { + controller = source.container.get(Optional.of(ValidationController)); + rules = rulesOrController; + } + if (controller === null) { + throw new Error(`A ValidationController has not been registered.`); + } + controller.registerBinding(binding, target, rules); + binding.validationController = controller; + const trigger = this.getValidateTrigger(controller); + // tslint:disable-next-line:no-bitwise + if (trigger & validateTrigger.change) { + binding.vbbUpdateSource = binding.updateSource; + // tslint:disable-next-line:only-arrow-functions + // tslint:disable-next-line:space-before-function-paren + binding.updateSource = function (value) { + this.vbbUpdateSource(value); + this.validationController.validateBinding(this); + }; + } + // tslint:disable-next-line:no-bitwise + if (trigger & validateTrigger.blur) { + binding.validateBlurHandler = () => { + this.taskQueue.queueMicroTask(() => controller.validateBinding(binding)); + }; + binding.validateTarget = target; + target.addEventListener('blur', binding.validateBlurHandler); + } + if (trigger !== validateTrigger.manual) { + binding.standardUpdateTarget = binding.updateTarget; + // tslint:disable-next-line:only-arrow-functions + // tslint:disable-next-line:space-before-function-paren + binding.updateTarget = function (value) { + this.standardUpdateTarget(value); + this.validationController.resetBinding(this); + }; + } + } + unbind(binding) { + // reset the binding to it's original state. + if (binding.vbbUpdateSource) { + binding.updateSource = binding.vbbUpdateSource; + binding.vbbUpdateSource = null; + } + if (binding.standardUpdateTarget) { + binding.updateTarget = binding.standardUpdateTarget; + binding.standardUpdateTarget = null; + } + if (binding.validateBlurHandler) { + binding.validateTarget.removeEventListener('blur', binding.validateBlurHandler); + binding.validateBlurHandler = null; + binding.validateTarget = null; + } + binding.validationController.unregisterBinding(binding); + binding.validationController = null; + } +} + +/** + * Binding behavior. Indicates the bound property should be validated + * when the validate trigger specified by the associated controller's + * validateTrigger property occurs. + */ +let ValidateBindingBehavior = class ValidateBindingBehavior extends ValidateBindingBehaviorBase { + getValidateTrigger(controller) { + return controller.validateTrigger; + } +}; +ValidateBindingBehavior.inject = [TaskQueue]; +ValidateBindingBehavior = __decorate([ + bindingBehavior('validate') +], ValidateBindingBehavior); +/** + * Binding behavior. Indicates the bound property will be validated + * manually, by calling controller.validate(). No automatic validation + * triggered by data-entry or blur will occur. + */ +let ValidateManuallyBindingBehavior = class ValidateManuallyBindingBehavior extends ValidateBindingBehaviorBase { + getValidateTrigger() { + return validateTrigger.manual; + } +}; +ValidateManuallyBindingBehavior.inject = [TaskQueue]; +ValidateManuallyBindingBehavior = __decorate([ + bindingBehavior('validateManually') +], ValidateManuallyBindingBehavior); +/** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs. + */ +let ValidateOnBlurBindingBehavior = class ValidateOnBlurBindingBehavior extends ValidateBindingBehaviorBase { + getValidateTrigger() { + return validateTrigger.blur; + } +}; +ValidateOnBlurBindingBehavior.inject = [TaskQueue]; +ValidateOnBlurBindingBehavior = __decorate([ + bindingBehavior('validateOnBlur') +], ValidateOnBlurBindingBehavior); +/** + * Binding behavior. Indicates the bound property should be validated + * when the associated element is changed by the user, causing a change + * to the model. + */ +let ValidateOnChangeBindingBehavior = class ValidateOnChangeBindingBehavior extends ValidateBindingBehaviorBase { + getValidateTrigger() { + return validateTrigger.change; + } +}; +ValidateOnChangeBindingBehavior.inject = [TaskQueue]; +ValidateOnChangeBindingBehavior = __decorate([ + bindingBehavior('validateOnChange') +], ValidateOnChangeBindingBehavior); +/** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs or is changed by the user, causing + * a change to the model. + */ +let ValidateOnChangeOrBlurBindingBehavior = class ValidateOnChangeOrBlurBindingBehavior extends ValidateBindingBehaviorBase { + getValidateTrigger() { + return validateTrigger.changeOrBlur; + } +}; +ValidateOnChangeOrBlurBindingBehavior.inject = [TaskQueue]; +ValidateOnChangeOrBlurBindingBehavior = __decorate([ + bindingBehavior('validateOnChangeOrBlur') +], ValidateOnChangeOrBlurBindingBehavior); + +/** + * Creates ValidationController instances. + */ +class ValidationControllerFactory { + constructor(container) { + this.container = container; + } + static get(container) { + return new ValidationControllerFactory(container); + } + /** + * Creates a new controller instance. + */ + create(validator) { + if (!validator) { + validator = this.container.get(Validator); + } + const propertyParser = this.container.get(PropertyAccessorParser); + return new ValidationController(validator, propertyParser); + } + /** + * Creates a new controller and registers it in the current element's container so that it's + * available to the validate binding behavior and renderers. + */ + createForCurrentScope(validator) { + const controller = this.create(validator); + this.container.registerInstance(ValidationController, controller); + return controller; + } +} +ValidationControllerFactory['protocol:aurelia:resolver'] = true; + +let ValidationErrorsCustomAttribute = class ValidationErrorsCustomAttribute { + constructor(boundaryElement, controllerAccessor) { + this.boundaryElement = boundaryElement; + this.controllerAccessor = controllerAccessor; + this.controller = null; + this.errors = []; + this.errorsInternal = []; + } + static inject() { + return [DOM.Element, Lazy.of(ValidationController)]; + } + sort() { + this.errorsInternal.sort((a, b) => { + if (a.targets[0] === b.targets[0]) { + return 0; + } + // tslint:disable-next-line:no-bitwise + return a.targets[0].compareDocumentPosition(b.targets[0]) & 2 ? 1 : -1; + }); + } + interestingElements(elements) { + return elements.filter(e => this.boundaryElement.contains(e)); + } + render(instruction) { + for (const { result } of instruction.unrender) { + const index = this.errorsInternal.findIndex(x => x.error === result); + if (index !== -1) { + this.errorsInternal.splice(index, 1); + } + } + for (const { result, elements } of instruction.render) { + if (result.valid) { + continue; + } + const targets = this.interestingElements(elements); + if (targets.length) { + this.errorsInternal.push({ error: result, targets }); + } + } + this.sort(); + this.errors = this.errorsInternal; + } + bind() { + if (!this.controller) { + this.controller = this.controllerAccessor(); + } + // this will call render() with the side-effect of updating this.errors + this.controller.addRenderer(this); + } + unbind() { + if (this.controller) { + this.controller.removeRenderer(this); + } + } +}; +__decorate([ + bindable({ defaultBindingMode: bindingMode.oneWay }) +], ValidationErrorsCustomAttribute.prototype, "controller", void 0); +__decorate([ + bindable({ primaryProperty: true, defaultBindingMode: bindingMode.twoWay }) +], ValidationErrorsCustomAttribute.prototype, "errors", void 0); +ValidationErrorsCustomAttribute = __decorate([ + customAttribute('validation-errors') +], ValidationErrorsCustomAttribute); + +let ValidationRendererCustomAttribute = class ValidationRendererCustomAttribute { + created(view) { + this.container = view.container; + } + bind() { + this.controller = this.container.get(ValidationController); + this.renderer = this.container.get(this.value); + this.controller.addRenderer(this.renderer); + } + unbind() { + this.controller.removeRenderer(this.renderer); + this.controller = null; + this.renderer = null; + } +}; +ValidationRendererCustomAttribute = __decorate([ + customAttribute('validation-renderer') +], ValidationRendererCustomAttribute); + +/** + * Sets, unsets and retrieves rules on an object or constructor function. + */ +class Rules { + /** + * Applies the rules to a target. + */ + static set(target, rules) { + if (target instanceof Function) { + target = target.prototype; + } + Object.defineProperty(target, Rules.key, { enumerable: false, configurable: false, writable: true, value: rules }); + } + /** + * Removes rules from a target. + */ + static unset(target) { + if (target instanceof Function) { + target = target.prototype; + } + target[Rules.key] = null; + } + /** + * Retrieves the target's rules. + */ + static get(target) { + return target[Rules.key] || null; + } +} +/** + * The name of the property that stores the rules. + */ +Rules.key = '__rules__'; + +// tslint:disable:no-empty +class ExpressionVisitor { + visitChain(chain) { + this.visitArgs(chain.expressions); + } + visitBindingBehavior(behavior) { + behavior.expression.accept(this); + this.visitArgs(behavior.args); + } + visitValueConverter(converter) { + converter.expression.accept(this); + this.visitArgs(converter.args); + } + visitAssign(assign) { + assign.target.accept(this); + assign.value.accept(this); + } + visitConditional(conditional) { + conditional.condition.accept(this); + conditional.yes.accept(this); + conditional.no.accept(this); + } + visitAccessThis(access) { + access.ancestor = access.ancestor; + } + visitAccessScope(access) { + access.name = access.name; + } + visitAccessMember(access) { + access.object.accept(this); + } + visitAccessKeyed(access) { + access.object.accept(this); + access.key.accept(this); + } + visitCallScope(call) { + this.visitArgs(call.args); + } + visitCallFunction(call) { + call.func.accept(this); + this.visitArgs(call.args); + } + visitCallMember(call) { + call.object.accept(this); + this.visitArgs(call.args); + } + visitPrefix(prefix) { + prefix.expression.accept(this); + } + visitBinary(binary) { + binary.left.accept(this); + binary.right.accept(this); + } + visitLiteralPrimitive(literal) { + literal.value = literal.value; + } + visitLiteralArray(literal) { + this.visitArgs(literal.elements); + } + visitLiteralObject(literal) { + this.visitArgs(literal.values); + } + visitLiteralString(literal) { + literal.value = literal.value; + } + visitArgs(args) { + for (let i = 0; i < args.length; i++) { + args[i].accept(this); + } + } +} + +class ValidationMessageParser { + constructor(bindinqLanguage) { + this.bindinqLanguage = bindinqLanguage; + this.emptyStringExpression = new LiteralString(''); + this.nullExpression = new LiteralPrimitive(null); + this.undefinedExpression = new LiteralPrimitive(undefined); + this.cache = {}; + } + parse(message) { + if (this.cache[message] !== undefined) { + return this.cache[message]; + } + const parts = this.bindinqLanguage.parseInterpolation(null, message); + if (parts === null) { + return new LiteralString(message); + } + let expression = new LiteralString(parts[0]); + for (let i = 1; i < parts.length; i += 2) { + expression = new Binary('+', expression, new Binary('+', this.coalesce(parts[i]), new LiteralString(parts[i + 1]))); + } + MessageExpressionValidator.validate(expression, message); + this.cache[message] = expression; + return expression; + } + coalesce(part) { + // part === null || part === undefined ? '' : part + return new Conditional(new Binary('||', new Binary('===', part, this.nullExpression), new Binary('===', part, this.undefinedExpression)), this.emptyStringExpression, new CallMember(part, 'toString', [])); + } +} +ValidationMessageParser.inject = [BindingLanguage]; +class MessageExpressionValidator extends ExpressionVisitor { + constructor(originalMessage) { + super(); + this.originalMessage = originalMessage; + } + static validate(expression, originalMessage) { + const visitor = new MessageExpressionValidator(originalMessage); + expression.accept(visitor); + } + visitAccessScope(access) { + if (access.ancestor !== 0) { + throw new Error('$parent is not permitted in validation message expressions.'); + } + if (['displayName', 'propertyName', 'value', 'object', 'config', 'getDisplayName'].indexOf(access.name) !== -1) { + getLogger('aurelia-validation') + // tslint:disable-next-line:max-line-length + .warn(`Did you mean to use "$${access.name}" instead of "${access.name}" in this validation message template: "${this.originalMessage}"?`); + } + } +} + +/** + * Dictionary of validation messages. [messageKey]: messageExpression + */ +const validationMessages = { + /** + * The default validation message. Used with rules that have no standard message. + */ + default: `\${$displayName} is invalid.`, + required: `\${$displayName} is required.`, + matches: `\${$displayName} is not correctly formatted.`, + email: `\${$displayName} is not a valid email.`, + minLength: `\${$displayName} must be at least \${$config.length} character\${$config.length === 1 ? '' : 's'}.`, + maxLength: `\${$displayName} cannot be longer than \${$config.length} character\${$config.length === 1 ? '' : 's'}.`, + minItems: `\${$displayName} must contain at least \${$config.count} item\${$config.count === 1 ? '' : 's'}.`, + maxItems: `\${$displayName} cannot contain more than \${$config.count} item\${$config.count === 1 ? '' : 's'}.`, + min: `\${$displayName} must be at least \${$config.constraint}.`, + max: `\${$displayName} must be at most \${$config.constraint}.`, + range: `\${$displayName} must be between or equal to \${$config.min} and \${$config.max}.`, + between: `\${$displayName} must be between but not equal to \${$config.min} and \${$config.max}.`, + equals: `\${$displayName} must be \${$config.expectedValue}.`, +}; +/** + * Retrieves validation messages and property display names. + */ +class ValidationMessageProvider { + constructor(parser) { + this.parser = parser; + } + /** + * Returns a message binding expression that corresponds to the key. + * @param key The message key. + */ + getMessage(key) { + let message; + if (key in validationMessages) { + message = validationMessages[key]; + } + else { + message = validationMessages['default']; + } + return this.parser.parse(message); + } + /** + * Formulates a property display name using the property name and the configured + * displayName (if provided). + * Override this with your own custom logic. + * @param propertyName The property name. + */ + getDisplayName(propertyName, displayName) { + if (displayName !== null && displayName !== undefined) { + return (displayName instanceof Function) ? displayName() : displayName; + } + // split on upper-case letters. + const words = propertyName.toString().split(/(?=[A-Z])/).join(' '); + // capitalize first letter. + return words.charAt(0).toUpperCase() + words.slice(1); + } +} +ValidationMessageProvider.inject = [ValidationMessageParser]; + +/** + * Validates. + * Responsible for validating objects and properties. + */ +class StandardValidator extends Validator { + constructor(messageProvider, resources) { + super(); + this.messageProvider = messageProvider; + this.lookupFunctions = resources.lookupFunctions; + this.getDisplayName = messageProvider.getDisplayName.bind(messageProvider); + } + /** + * Validates the specified property. + * @param object The object to validate. + * @param propertyName The name of the property to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + validateProperty(object, propertyName, rules) { + return this.validate(object, propertyName, rules || null); + } + /** + * Validates all rules for specified object and it's properties. + * @param object The object to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + validateObject(object, rules) { + return this.validate(object, null, rules || null); + } + /** + * Determines whether a rule exists in a set of rules. + * @param rules The rules to search. + * @parem rule The rule to find. + */ + ruleExists(rules, rule) { + let i = rules.length; + while (i--) { + if (rules[i].indexOf(rule) !== -1) { + return true; + } + } + return false; + } + getMessage(rule, object, value) { + const expression = rule.message || this.messageProvider.getMessage(rule.messageKey); + // tslint:disable-next-line:prefer-const + let { name: propertyName, displayName } = rule.property; + if (propertyName !== null) { + displayName = this.messageProvider.getDisplayName(propertyName, displayName); + } + const overrideContext = { + $displayName: displayName, + $propertyName: propertyName, + $value: value, + $object: object, + $config: rule.config, + // returns the name of a given property, given just the property name (irrespective of the property's displayName) + // split on capital letters, first letter ensured to be capitalized + $getDisplayName: this.getDisplayName + }; + return expression.evaluate({ bindingContext: object, overrideContext }, this.lookupFunctions); + } + validateRuleSequence(object, propertyName, ruleSequence, sequence, results) { + // are we validating all properties or a single property? + const validateAllProperties = propertyName === null || propertyName === undefined; + const rules = ruleSequence[sequence]; + let allValid = true; + // validate each rule. + const promises = []; + for (let i = 0; i < rules.length; i++) { + const rule = rules[i]; + // is the rule related to the property we're validating. + // tslint:disable-next-line:triple-equals | Use loose equality for property keys + if (!validateAllProperties && rule.property.name != propertyName) { + continue; + } + // is this a conditional rule? is the condition met? + if (rule.when && !rule.when(object)) { + continue; + } + // validate. + const value = rule.property.name === null ? object : object[rule.property.name]; + let promiseOrBoolean = rule.condition(value, object); + if (!(promiseOrBoolean instanceof Promise)) { + promiseOrBoolean = Promise.resolve(promiseOrBoolean); + } + promises.push(promiseOrBoolean.then(valid => { + const message = valid ? null : this.getMessage(rule, object, value); + results.push(new ValidateResult(rule, object, rule.property.name, valid, message)); + allValid = allValid && valid; + return valid; + })); + } + return Promise.all(promises) + .then(() => { + sequence++; + if (allValid && sequence < ruleSequence.length) { + return this.validateRuleSequence(object, propertyName, ruleSequence, sequence, results); + } + return results; + }); + } + validate(object, propertyName, rules) { + // rules specified? + if (!rules) { + // no. attempt to locate the rules. + rules = Rules.get(object); + } + // any rules? + if (!rules || rules.length === 0) { + return Promise.resolve([]); + } + return this.validateRuleSequence(object, propertyName, rules, 0, []); + } +} +StandardValidator.inject = [ValidationMessageProvider, ViewResources]; + +/** + * Part of the fluent rule API. Enables customizing property rules. + */ +class FluentRuleCustomizer { + constructor(property, condition, config = {}, fluentEnsure, fluentRules, parsers) { + this.fluentEnsure = fluentEnsure; + this.fluentRules = fluentRules; + this.parsers = parsers; + this.rule = { + property, + condition, + config, + when: null, + messageKey: 'default', + message: null, + sequence: fluentRules.sequence + }; + this.fluentEnsure._addRule(this.rule); + } + /** + * Validate subsequent rules after previously declared rules have + * been validated successfully. Use to postpone validation of costly + * rules until less expensive rules pass validation. + */ + then() { + this.fluentRules.sequence++; + return this; + } + /** + * Specifies the key to use when looking up the rule's validation message. + */ + withMessageKey(key) { + this.rule.messageKey = key; + this.rule.message = null; + return this; + } + /** + * Specifies rule's validation message. + */ + withMessage(message) { + this.rule.messageKey = 'custom'; + this.rule.message = this.parsers.message.parse(message); + return this; + } + /** + * Specifies a condition that must be met before attempting to validate the rule. + * @param condition A function that accepts the object as a parameter and returns true + * or false whether the rule should be evaluated. + */ + when(condition) { + this.rule.when = condition; + return this; + } + /** + * Tags the rule instance, enabling the rule to be found easily + * using ValidationRules.taggedRules(rules, tag) + */ + tag(tag) { + this.rule.tag = tag; + return this; + } + ///// FluentEnsure APIs ///// + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + ensure(subject) { + return this.fluentEnsure.ensure(subject); + } + /** + * Targets an object with validation rules. + */ + ensureObject() { + return this.fluentEnsure.ensureObject(); + } + /** + * Rules that have been defined using the fluent API. + */ + get rules() { + return this.fluentEnsure.rules; + } + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + on(target) { + return this.fluentEnsure.on(target); + } + ///////// FluentRules APIs ///////// + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + satisfies(condition, config) { + return this.fluentRules.satisfies(condition, config); + } + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + satisfiesRule(name, ...args) { + return this.fluentRules.satisfiesRule(name, ...args); + } + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + required() { + return this.fluentRules.required(); + } + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + matches(regex) { + return this.fluentRules.matches(regex); + } + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + email() { + return this.fluentRules.email(); + } + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + minLength(length) { + return this.fluentRules.minLength(length); + } + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + maxLength(length) { + return this.fluentRules.maxLength(length); + } + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + minItems(count) { + return this.fluentRules.minItems(count); + } + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + maxItems(count) { + return this.fluentRules.maxItems(count); + } + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + min(value) { + return this.fluentRules.min(value); + } + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + max(value) { + return this.fluentRules.max(value); + } + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + range(min, max) { + return this.fluentRules.range(min, max); + } + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + between(min, max) { + return this.fluentRules.between(min, max); + } + /** + * Applies the "equals" validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + equals(expectedValue) { + return this.fluentRules.equals(expectedValue); + } +} +/** + * Part of the fluent rule API. Enables applying rules to properties and objects. + */ +class FluentRules { + constructor(fluentEnsure, parsers, property) { + this.fluentEnsure = fluentEnsure; + this.parsers = parsers; + this.property = property; + /** + * Current rule sequence number. Used to postpone evaluation of rules until rules + * with lower sequence number have successfully validated. The "then" fluent API method + * manages this property, there's usually no need to set it directly. + */ + this.sequence = 0; + } + /** + * Sets the display name of the ensured property. + */ + displayName(name) { + this.property.displayName = name; + return this; + } + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + satisfies(condition, config) { + return new FluentRuleCustomizer(this.property, condition, config, this.fluentEnsure, this, this.parsers); + } + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + satisfiesRule(name, ...args) { + let rule = FluentRules.customRules[name]; + if (!rule) { + // standard rule? + rule = this[name]; + if (rule instanceof Function) { + return rule.call(this, ...args); + } + throw new Error(`Rule with name "${name}" does not exist.`); + } + const config = rule.argsToConfig ? rule.argsToConfig(...args) : undefined; + return this.satisfies((value, obj) => rule.condition.call(this, value, obj, ...args), config) + .withMessageKey(name); + } + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + required() { + return this.satisfies(value => value !== null + && value !== undefined + && !(isString(value) && !/\S/.test(value))).withMessageKey('required'); + } + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + matches(regex) { + return this.satisfies(value => value === null || value === undefined || value.length === 0 || regex.test(value)) + .withMessageKey('matches'); + } + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + email() { + // regex from https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address + /* tslint:disable:max-line-length */ + return this.matches(/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/) + /* tslint:enable:max-line-length */ + .withMessageKey('email'); + } + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + minLength(length) { + return this.satisfies((value) => value === null || value === undefined || value.length === 0 || value.length >= length, { length }) + .withMessageKey('minLength'); + } + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + maxLength(length) { + return this.satisfies((value) => value === null || value === undefined || value.length === 0 || value.length <= length, { length }) + .withMessageKey('maxLength'); + } + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + minItems(count) { + return this.satisfies((value) => value === null || value === undefined || value.length >= count, { count }) + .withMessageKey('minItems'); + } + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + maxItems(count) { + return this.satisfies((value) => value === null || value === undefined || value.length <= count, { count }) + .withMessageKey('maxItems'); + } + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + min(constraint) { + return this.satisfies((value) => value === null || value === undefined || value >= constraint, { constraint }) + .withMessageKey('min'); + } + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + max(constraint) { + return this.satisfies((value) => value === null || value === undefined || value <= constraint, { constraint }) + .withMessageKey('max'); + } + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + range(min, max) { + return this.satisfies((value) => value === null || value === undefined || (value >= min && value <= max), { min, max }) + .withMessageKey('range'); + } + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + between(min, max) { + return this.satisfies((value) => value === null || value === undefined || (value > min && value < max), { min, max }) + .withMessageKey('between'); + } + /** + * Applies the "equals" validation rule to the property. + * null and undefined values are considered valid. + */ + equals(expectedValue) { + return this.satisfies(value => value === null || value === undefined || value === '' || value === expectedValue, { expectedValue }) + .withMessageKey('equals'); + } +} +FluentRules.customRules = {}; +/** + * Part of the fluent rule API. Enables targeting properties and objects with rules. + */ +class FluentEnsure { + constructor(parsers) { + this.parsers = parsers; + /** + * Rules that have been defined using the fluent API. + */ + this.rules = []; + } + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor + * function. + */ + ensure(property) { + this.assertInitialized(); + const name = this.parsers.property.parse(property); + const fluentRules = new FluentRules(this, this.parsers, { name, displayName: null }); + return this.mergeRules(fluentRules, name); + } + /** + * Targets an object with validation rules. + */ + ensureObject() { + this.assertInitialized(); + const fluentRules = new FluentRules(this, this.parsers, { name: null, displayName: null }); + return this.mergeRules(fluentRules, null); + } + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + on(target) { + Rules.set(target, this.rules); + return this; + } + /** + * Adds a rule definition to the sequenced ruleset. + * @internal + */ + _addRule(rule) { + while (this.rules.length < rule.sequence + 1) { + this.rules.push([]); + } + this.rules[rule.sequence].push(rule); + } + assertInitialized() { + if (this.parsers) { + return; + } + throw new Error(`Did you forget to add ".plugin('aurelia-validation')" to your main.js?`); + } + mergeRules(fluentRules, propertyName) { + // tslint:disable-next-line:triple-equals | Use loose equality for property keys + const existingRules = this.rules.find(r => r.length > 0 && r[0].property.name == propertyName); + if (existingRules) { + const rule = existingRules[existingRules.length - 1]; + fluentRules.sequence = rule.sequence; + if (rule.property.displayName !== null) { + fluentRules = fluentRules.displayName(rule.property.displayName); + } + } + return fluentRules; + } +} +/** + * Fluent rule definition API. + */ +class ValidationRules { + static initialize(messageParser, propertyParser) { + this.parsers = { + message: messageParser, + property: propertyParser + }; + } + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + static ensure(property) { + return new FluentEnsure(ValidationRules.parsers).ensure(property); + } + /** + * Targets an object with validation rules. + */ + static ensureObject() { + return new FluentEnsure(ValidationRules.parsers).ensureObject(); + } + /** + * Defines a custom rule. + * @param name The name of the custom rule. Also serves as the message key. + * @param condition The rule function. + * @param message The message expression + * @param argsToConfig A function that maps the rule's arguments to a "config" + * object that can be used when evaluating the message expression. + */ + static customRule(name, condition, message, argsToConfig) { + validationMessages[name] = message; + FluentRules.customRules[name] = { condition, argsToConfig }; + } + /** + * Returns rules with the matching tag. + * @param rules The rules to search. + * @param tag The tag to search for. + */ + static taggedRules(rules, tag) { + return rules.map(x => x.filter(r => r.tag === tag)); + } + /** + * Returns rules that have no tag. + * @param rules The rules to search. + */ + static untaggedRules(rules) { + return rules.map(x => x.filter(r => r.tag === undefined)); + } + /** + * Removes the rules from a class or object. + * @param target A class or object. + */ + static off(target) { + Rules.unset(target); + } +} + +// Exports +/** + * Aurelia Validation Configuration API + */ +class AureliaValidationConfiguration { + constructor() { + this.validatorType = StandardValidator; + } + /** + * Use a custom Validator implementation. + */ + customValidator(type) { + this.validatorType = type; + } + /** + * Applies the configuration. + */ + apply(container) { + const validator = container.get(this.validatorType); + container.registerInstance(Validator, validator); + } +} +/** + * Configures the plugin. + */ +function configure( +// tslint:disable-next-line:ban-types +frameworkConfig, callback) { + // the fluent rule definition API needs the parser to translate messages + // to interpolation expressions. + const messageParser = frameworkConfig.container.get(ValidationMessageParser); + const propertyParser = frameworkConfig.container.get(PropertyAccessorParser); + ValidationRules.initialize(messageParser, propertyParser); + // configure... + const config = new AureliaValidationConfiguration(); + if (callback instanceof Function) { + callback(config); + } + config.apply(frameworkConfig.container); + // globalize the behaviors. + if (frameworkConfig.globalResources) { + frameworkConfig.globalResources(ValidateBindingBehavior, ValidateManuallyBindingBehavior, ValidateOnBlurBindingBehavior, ValidateOnChangeBindingBehavior, ValidateOnChangeOrBlurBindingBehavior, ValidationErrorsCustomAttribute, ValidationRendererCustomAttribute); + } +} + +export { AureliaValidationConfiguration, configure, getTargetDOMElement, getPropertyInfo, PropertyAccessorParser, getAccessorExpression, ValidateBindingBehavior, ValidateManuallyBindingBehavior, ValidateOnBlurBindingBehavior, ValidateOnChangeBindingBehavior, ValidateOnChangeOrBlurBindingBehavior, ValidateEvent, ValidateResult, validateTrigger, ValidationController, ValidationControllerFactory, ValidationErrorsCustomAttribute, ValidationRendererCustomAttribute, Validator, Rules, StandardValidator, validationMessages, ValidationMessageProvider, ValidationMessageParser, MessageExpressionValidator, FluentRuleCustomizer, FluentRules, FluentEnsure, ValidationRules }; diff --git a/dist/es2017/aurelia-validation.js b/dist/es2017/aurelia-validation.js new file mode 100644 index 00000000..7a46b442 --- /dev/null +++ b/dist/es2017/aurelia-validation.js @@ -0,0 +1,1733 @@ +import { DOM } from 'aurelia-pal'; +import { AccessMember, AccessScope, AccessKeyed, BindingBehavior, ValueConverter, getContextFor, Parser, bindingBehavior, bindingMode, LiteralString, Binary, Conditional, LiteralPrimitive, CallMember } from 'aurelia-binding'; +import { Optional, Lazy } from 'aurelia-dependency-injection'; +import { TaskQueue } from 'aurelia-task-queue'; +import { customAttribute, bindable, BindingLanguage, ViewResources } from 'aurelia-templating'; +import { getLogger } from 'aurelia-logging'; + +/** + * Gets the DOM element associated with the data-binding. Most of the time it's + * the binding.target but sometimes binding.target is an aurelia custom element, + * or custom attribute which is a javascript "class" instance, so we need to use + * the controller's container to retrieve the actual DOM element. + */ +function getTargetDOMElement(binding, view) { + const target = binding.target; + // DOM element + if (target instanceof Element) { + return target; + } + // custom element or custom attribute + // tslint:disable-next-line:prefer-const + for (let i = 0, ii = view.controllers.length; i < ii; i++) { + const controller = view.controllers[i]; + if (controller.viewModel === target) { + const element = controller.container.get(DOM.Element); + if (element) { + return element; + } + throw new Error(`Unable to locate target element for "${binding.sourceExpression}".`); + } + } + throw new Error(`Unable to locate target element for "${binding.sourceExpression}".`); +} + +function getObject(expression, objectExpression, source) { + const value = objectExpression.evaluate(source, null); + if (value === null || value === undefined || value instanceof Object) { + return value; + } + // tslint:disable-next-line:max-line-length + throw new Error(`The '${objectExpression}' part of '${expression}' evaluates to ${value} instead of an object, null or undefined.`); +} +/** + * Retrieves the object and property name for the specified expression. + * @param expression The expression + * @param source The scope + */ +function getPropertyInfo(expression, source) { + const originalExpression = expression; + while (expression instanceof BindingBehavior || expression instanceof ValueConverter) { + expression = expression.expression; + } + let object; + let propertyName; + if (expression instanceof AccessScope) { + object = getContextFor(expression.name, source, expression.ancestor); + propertyName = expression.name; + } + else if (expression instanceof AccessMember) { + object = getObject(originalExpression, expression.object, source); + propertyName = expression.name; + } + else if (expression instanceof AccessKeyed) { + object = getObject(originalExpression, expression.object, source); + propertyName = expression.key.evaluate(source); + } + else { + throw new Error(`Expression '${originalExpression}' is not compatible with the validate binding-behavior.`); + } + if (object === null || object === undefined) { + return null; + } + return { object, propertyName }; +} + +function isString(value) { + return Object.prototype.toString.call(value) === '[object String]'; +} +function isNumber(value) { + return Object.prototype.toString.call(value) === '[object Number]'; +} + +class PropertyAccessorParser { + constructor(parser) { + this.parser = parser; + } + parse(property) { + if (isString(property) || isNumber(property)) { + return property; + } + const accessorText = getAccessorExpression(property.toString()); + const accessor = this.parser.parse(accessorText); + if (accessor instanceof AccessScope + || accessor instanceof AccessMember && accessor.object instanceof AccessScope) { + return accessor.name; + } + throw new Error(`Invalid property expression: "${accessor}"`); + } +} +PropertyAccessorParser.inject = [Parser]; +function getAccessorExpression(fn) { + /* tslint:disable:max-line-length */ + const classic = /^function\s*\([$_\w\d]+\)\s*\{(?:\s*"use strict";)?\s*(?:[$_\w\d.['"\]+;]+)?\s*return\s+[$_\w\d]+\.([$_\w\d]+)\s*;?\s*\}$/; + /* tslint:enable:max-line-length */ + const arrow = /^\(?[$_\w\d]+\)?\s*=>\s*[$_\w\d]+\.([$_\w\d]+)$/; + const match = classic.exec(fn) || arrow.exec(fn); + if (match === null) { + throw new Error(`Unable to parse accessor function:\n${fn}`); + } + return match[1]; +} + +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +} + +/** + * Validation triggers. + */ +var validateTrigger; +(function (validateTrigger) { + /** + * Manual validation. Use the controller's `validate()` and `reset()` methods + * to validate all bindings. + */ + validateTrigger[validateTrigger["manual"] = 0] = "manual"; + /** + * Validate the binding when the binding's target element fires a DOM "blur" event. + */ + validateTrigger[validateTrigger["blur"] = 1] = "blur"; + /** + * Validate the binding when it updates the model due to a change in the view. + */ + validateTrigger[validateTrigger["change"] = 2] = "change"; + /** + * Validate the binding when the binding's target element fires a DOM "blur" event and + * when it updates the model due to a change in the view. + */ + validateTrigger[validateTrigger["changeOrBlur"] = 3] = "changeOrBlur"; +})(validateTrigger || (validateTrigger = {})); + +/** + * Validates objects and properties. + */ +class Validator { +} + +/** + * The result of validating an individual validation rule. + */ +class ValidateResult { + /** + * @param rule The rule associated with the result. Validator implementation specific. + * @param object The object that was validated. + * @param propertyName The name of the property that was validated. + * @param error The error, if the result is a validation error. + */ + constructor(rule, object, propertyName, valid, message = null) { + this.rule = rule; + this.object = object; + this.propertyName = propertyName; + this.valid = valid; + this.message = message; + this.id = ValidateResult.nextId++; + } + toString() { + return this.valid ? 'Valid.' : this.message; + } +} +ValidateResult.nextId = 0; + +class ValidateEvent { + constructor( + /** + * The type of validate event. Either "validate" or "reset". + */ + type, + /** + * The controller's current array of errors. For an array containing both + * failed rules and passed rules, use the "results" property. + */ + errors, + /** + * The controller's current array of validate results. This + * includes both passed rules and failed rules. For an array of only failed rules, + * use the "errors" property. + */ + results, + /** + * The instruction passed to the "validate" or "reset" event. Will be null when + * the controller's validate/reset method was called with no instruction argument. + */ + instruction, + /** + * In events with type === "validate", this property will contain the result + * of validating the instruction (see "instruction" property). Use the controllerValidateResult + * to access the validate results specific to the call to "validate" + * (as opposed to using the "results" and "errors" properties to access the controller's entire + * set of results/errors). + */ + controllerValidateResult) { + this.type = type; + this.errors = errors; + this.results = results; + this.instruction = instruction; + this.controllerValidateResult = controllerValidateResult; + } +} + +/** + * Orchestrates validation. + * Manages a set of bindings, renderers and objects. + * Exposes the current list of validation results for binding purposes. + */ +class ValidationController { + constructor(validator, propertyParser) { + this.validator = validator; + this.propertyParser = propertyParser; + // Registered bindings (via the validate binding behavior) + this.bindings = new Map(); + // Renderers that have been added to the controller instance. + this.renderers = []; + /** + * Validation results that have been rendered by the controller. + */ + this.results = []; + /** + * Validation errors that have been rendered by the controller. + */ + this.errors = []; + /** + * Whether the controller is currently validating. + */ + this.validating = false; + // Elements related to validation results that have been rendered. + this.elements = new Map(); + // Objects that have been added to the controller instance (entity-style validation). + this.objects = new Map(); + /** + * The trigger that will invoke automatic validation of a property used in a binding. + */ + this.validateTrigger = validateTrigger.blur; + // Promise that resolves when validation has completed. + this.finishValidating = Promise.resolve(); + this.eventCallbacks = []; + } + /** + * Subscribe to controller validate and reset events. These events occur when the + * controller's "validate"" and "reset" methods are called. + * @param callback The callback to be invoked when the controller validates or resets. + */ + subscribe(callback) { + this.eventCallbacks.push(callback); + return { + dispose: () => { + const index = this.eventCallbacks.indexOf(callback); + if (index === -1) { + return; + } + this.eventCallbacks.splice(index, 1); + } + }; + } + /** + * Adds an object to the set of objects that should be validated when validate is called. + * @param object The object. + * @param rules Optional. The rules. If rules aren't supplied the Validator implementation will lookup the rules. + */ + addObject(object, rules) { + this.objects.set(object, rules); + } + /** + * Removes an object from the set of objects that should be validated when validate is called. + * @param object The object. + */ + removeObject(object) { + this.objects.delete(object); + this.processResultDelta('reset', this.results.filter(result => result.object === object), []); + } + /** + * Adds and renders an error. + */ + addError(message, object, propertyName = null) { + let resolvedPropertyName; + if (propertyName === null) { + resolvedPropertyName = propertyName; + } + else { + resolvedPropertyName = this.propertyParser.parse(propertyName); + } + const result = new ValidateResult({ __manuallyAdded__: true }, object, resolvedPropertyName, false, message); + this.processResultDelta('validate', [], [result]); + return result; + } + /** + * Removes and unrenders an error. + */ + removeError(result) { + if (this.results.indexOf(result) !== -1) { + this.processResultDelta('reset', [result], []); + } + } + /** + * Adds a renderer. + * @param renderer The renderer. + */ + addRenderer(renderer) { + this.renderers.push(renderer); + renderer.render({ + kind: 'validate', + render: this.results.map(result => ({ result, elements: this.elements.get(result) })), + unrender: [] + }); + } + /** + * Removes a renderer. + * @param renderer The renderer. + */ + removeRenderer(renderer) { + this.renderers.splice(this.renderers.indexOf(renderer), 1); + renderer.render({ + kind: 'reset', + render: [], + unrender: this.results.map(result => ({ result, elements: this.elements.get(result) })) + }); + } + /** + * Registers a binding with the controller. + * @param binding The binding instance. + * @param target The DOM element. + * @param rules (optional) rules associated with the binding. Validator implementation specific. + */ + registerBinding(binding, target, rules) { + this.bindings.set(binding, { target, rules, propertyInfo: null }); + } + /** + * Unregisters a binding with the controller. + * @param binding The binding instance. + */ + unregisterBinding(binding) { + this.resetBinding(binding); + this.bindings.delete(binding); + } + /** + * Interprets the instruction and returns a predicate that will identify + * relevant results in the list of rendered validation results. + */ + getInstructionPredicate(instruction) { + if (instruction) { + const { object, propertyName, rules } = instruction; + let predicate; + if (instruction.propertyName) { + predicate = x => x.object === object && x.propertyName === propertyName; + } + else { + predicate = x => x.object === object; + } + if (rules) { + return x => predicate(x) && this.validator.ruleExists(rules, x.rule); + } + return predicate; + } + else { + return () => true; + } + } + /** + * Validates and renders results. + * @param instruction Optional. Instructions on what to validate. If undefined, all + * objects and bindings will be validated. + */ + validate(instruction) { + // Get a function that will process the validation instruction. + let execute; + if (instruction) { + // tslint:disable-next-line:prefer-const + let { object, propertyName, rules } = instruction; + // if rules were not specified, check the object map. + rules = rules || this.objects.get(object); + // property specified? + if (instruction.propertyName === undefined) { + // validate the specified object. + execute = () => this.validator.validateObject(object, rules); + } + else { + // validate the specified property. + execute = () => this.validator.validateProperty(object, propertyName, rules); + } + } + else { + // validate all objects and bindings. + execute = () => { + const promises = []; + for (const [object, rules] of Array.from(this.objects)) { + promises.push(this.validator.validateObject(object, rules)); + } + for (const [binding, { rules }] of Array.from(this.bindings)) { + const propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (!propertyInfo || this.objects.has(propertyInfo.object)) { + continue; + } + promises.push(this.validator.validateProperty(propertyInfo.object, propertyInfo.propertyName, rules)); + } + return Promise.all(promises).then(resultSets => resultSets.reduce((a, b) => a.concat(b), [])); + }; + } + // Wait for any existing validation to finish, execute the instruction, render the results. + this.validating = true; + const returnPromise = this.finishValidating + .then(execute) + .then((newResults) => { + const predicate = this.getInstructionPredicate(instruction); + const oldResults = this.results.filter(predicate); + this.processResultDelta('validate', oldResults, newResults); + if (returnPromise === this.finishValidating) { + this.validating = false; + } + const result = { + instruction, + valid: newResults.find(x => !x.valid) === undefined, + results: newResults + }; + this.invokeCallbacks(instruction, result); + return result; + }) + .catch(exception => { + // recover, to enable subsequent calls to validate() + this.validating = false; + this.finishValidating = Promise.resolve(); + return Promise.reject(exception); + }); + this.finishValidating = returnPromise; + return returnPromise; + } + /** + * Resets any rendered validation results (unrenders). + * @param instruction Optional. Instructions on what to reset. If unspecified all rendered results + * will be unrendered. + */ + reset(instruction) { + const predicate = this.getInstructionPredicate(instruction); + const oldResults = this.results.filter(predicate); + this.processResultDelta('reset', oldResults, []); + this.invokeCallbacks(instruction, null); + } + /** + * Gets the elements associated with an object and propertyName (if any). + */ + getAssociatedElements({ object, propertyName }) { + const elements = []; + for (const [binding, { target }] of Array.from(this.bindings)) { + const propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (propertyInfo && propertyInfo.object === object && propertyInfo.propertyName === propertyName) { + elements.push(target); + } + } + return elements; + } + processResultDelta(kind, oldResults, newResults) { + // prepare the instruction. + const instruction = { + kind, + render: [], + unrender: [] + }; + // create a shallow copy of newResults so we can mutate it without causing side-effects. + newResults = newResults.slice(0); + // create unrender instructions from the old results. + for (const oldResult of oldResults) { + // get the elements associated with the old result. + const elements = this.elements.get(oldResult); + // remove the old result from the element map. + this.elements.delete(oldResult); + // create the unrender instruction. + instruction.unrender.push({ result: oldResult, elements }); + // determine if there's a corresponding new result for the old result we are unrendering. + const newResultIndex = newResults.findIndex(x => x.rule === oldResult.rule && x.object === oldResult.object && x.propertyName === oldResult.propertyName); + if (newResultIndex === -1) { + // no corresponding new result... simple remove. + this.results.splice(this.results.indexOf(oldResult), 1); + if (!oldResult.valid) { + this.errors.splice(this.errors.indexOf(oldResult), 1); + } + } + else { + // there is a corresponding new result... + const newResult = newResults.splice(newResultIndex, 1)[0]; + // get the elements that are associated with the new result. + const elements = this.getAssociatedElements(newResult); + this.elements.set(newResult, elements); + // create a render instruction for the new result. + instruction.render.push({ result: newResult, elements }); + // do an in-place replacement of the old result with the new result. + // this ensures any repeats bound to this.results will not thrash. + this.results.splice(this.results.indexOf(oldResult), 1, newResult); + if (!oldResult.valid && newResult.valid) { + this.errors.splice(this.errors.indexOf(oldResult), 1); + } + else if (!oldResult.valid && !newResult.valid) { + this.errors.splice(this.errors.indexOf(oldResult), 1, newResult); + } + else if (!newResult.valid) { + this.errors.push(newResult); + } + } + } + // create render instructions from the remaining new results. + for (const result of newResults) { + const elements = this.getAssociatedElements(result); + instruction.render.push({ result, elements }); + this.elements.set(result, elements); + this.results.push(result); + if (!result.valid) { + this.errors.push(result); + } + } + // render. + for (const renderer of this.renderers) { + renderer.render(instruction); + } + } + /** + * Validates the property associated with a binding. + */ + validateBinding(binding) { + if (!binding.isBound) { + return; + } + const propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + let rules; + const registeredBinding = this.bindings.get(binding); + if (registeredBinding) { + rules = registeredBinding.rules; + registeredBinding.propertyInfo = propertyInfo; + } + if (!propertyInfo) { + return; + } + const { object, propertyName } = propertyInfo; + this.validate({ object, propertyName, rules }); + } + /** + * Resets the results for a property associated with a binding. + */ + resetBinding(binding) { + const registeredBinding = this.bindings.get(binding); + let propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (!propertyInfo && registeredBinding) { + propertyInfo = registeredBinding.propertyInfo; + } + if (registeredBinding) { + registeredBinding.propertyInfo = null; + } + if (!propertyInfo) { + return; + } + const { object, propertyName } = propertyInfo; + this.reset({ object, propertyName }); + } + /** + * Changes the controller's validateTrigger. + * @param newTrigger The new validateTrigger + */ + changeTrigger(newTrigger) { + this.validateTrigger = newTrigger; + const bindings = Array.from(this.bindings.keys()); + for (const binding of bindings) { + const source = binding.source; + binding.unbind(); + binding.bind(source); + } + } + /** + * Revalidates the controller's current set of errors. + */ + revalidateErrors() { + for (const { object, propertyName, rule } of this.errors) { + if (rule.__manuallyAdded__) { + continue; + } + const rules = [[rule]]; + this.validate({ object, propertyName, rules }); + } + } + invokeCallbacks(instruction, result) { + if (this.eventCallbacks.length === 0) { + return; + } + const event = new ValidateEvent(result ? 'validate' : 'reset', this.errors, this.results, instruction || null, result); + for (let i = 0; i < this.eventCallbacks.length; i++) { + this.eventCallbacks[i](event); + } + } +} +ValidationController.inject = [Validator, PropertyAccessorParser]; + +/** + * Binding behavior. Indicates the bound property should be validated. + */ +class ValidateBindingBehaviorBase { + constructor(taskQueue) { + this.taskQueue = taskQueue; + } + bind(binding, source, rulesOrController, rules) { + // identify the target element. + const target = getTargetDOMElement(binding, source); + // locate the controller. + let controller; + if (rulesOrController instanceof ValidationController) { + controller = rulesOrController; + } + else { + controller = source.container.get(Optional.of(ValidationController)); + rules = rulesOrController; + } + if (controller === null) { + throw new Error(`A ValidationController has not been registered.`); + } + controller.registerBinding(binding, target, rules); + binding.validationController = controller; + const trigger = this.getValidateTrigger(controller); + // tslint:disable-next-line:no-bitwise + if (trigger & validateTrigger.change) { + binding.vbbUpdateSource = binding.updateSource; + // tslint:disable-next-line:only-arrow-functions + // tslint:disable-next-line:space-before-function-paren + binding.updateSource = function (value) { + this.vbbUpdateSource(value); + this.validationController.validateBinding(this); + }; + } + // tslint:disable-next-line:no-bitwise + if (trigger & validateTrigger.blur) { + binding.validateBlurHandler = () => { + this.taskQueue.queueMicroTask(() => controller.validateBinding(binding)); + }; + binding.validateTarget = target; + target.addEventListener('blur', binding.validateBlurHandler); + } + if (trigger !== validateTrigger.manual) { + binding.standardUpdateTarget = binding.updateTarget; + // tslint:disable-next-line:only-arrow-functions + // tslint:disable-next-line:space-before-function-paren + binding.updateTarget = function (value) { + this.standardUpdateTarget(value); + this.validationController.resetBinding(this); + }; + } + } + unbind(binding) { + // reset the binding to it's original state. + if (binding.vbbUpdateSource) { + binding.updateSource = binding.vbbUpdateSource; + binding.vbbUpdateSource = null; + } + if (binding.standardUpdateTarget) { + binding.updateTarget = binding.standardUpdateTarget; + binding.standardUpdateTarget = null; + } + if (binding.validateBlurHandler) { + binding.validateTarget.removeEventListener('blur', binding.validateBlurHandler); + binding.validateBlurHandler = null; + binding.validateTarget = null; + } + binding.validationController.unregisterBinding(binding); + binding.validationController = null; + } +} + +/** + * Binding behavior. Indicates the bound property should be validated + * when the validate trigger specified by the associated controller's + * validateTrigger property occurs. + */ +let ValidateBindingBehavior = class ValidateBindingBehavior extends ValidateBindingBehaviorBase { + getValidateTrigger(controller) { + return controller.validateTrigger; + } +}; +ValidateBindingBehavior.inject = [TaskQueue]; +ValidateBindingBehavior = __decorate([ + bindingBehavior('validate') +], ValidateBindingBehavior); +/** + * Binding behavior. Indicates the bound property will be validated + * manually, by calling controller.validate(). No automatic validation + * triggered by data-entry or blur will occur. + */ +let ValidateManuallyBindingBehavior = class ValidateManuallyBindingBehavior extends ValidateBindingBehaviorBase { + getValidateTrigger() { + return validateTrigger.manual; + } +}; +ValidateManuallyBindingBehavior.inject = [TaskQueue]; +ValidateManuallyBindingBehavior = __decorate([ + bindingBehavior('validateManually') +], ValidateManuallyBindingBehavior); +/** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs. + */ +let ValidateOnBlurBindingBehavior = class ValidateOnBlurBindingBehavior extends ValidateBindingBehaviorBase { + getValidateTrigger() { + return validateTrigger.blur; + } +}; +ValidateOnBlurBindingBehavior.inject = [TaskQueue]; +ValidateOnBlurBindingBehavior = __decorate([ + bindingBehavior('validateOnBlur') +], ValidateOnBlurBindingBehavior); +/** + * Binding behavior. Indicates the bound property should be validated + * when the associated element is changed by the user, causing a change + * to the model. + */ +let ValidateOnChangeBindingBehavior = class ValidateOnChangeBindingBehavior extends ValidateBindingBehaviorBase { + getValidateTrigger() { + return validateTrigger.change; + } +}; +ValidateOnChangeBindingBehavior.inject = [TaskQueue]; +ValidateOnChangeBindingBehavior = __decorate([ + bindingBehavior('validateOnChange') +], ValidateOnChangeBindingBehavior); +/** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs or is changed by the user, causing + * a change to the model. + */ +let ValidateOnChangeOrBlurBindingBehavior = class ValidateOnChangeOrBlurBindingBehavior extends ValidateBindingBehaviorBase { + getValidateTrigger() { + return validateTrigger.changeOrBlur; + } +}; +ValidateOnChangeOrBlurBindingBehavior.inject = [TaskQueue]; +ValidateOnChangeOrBlurBindingBehavior = __decorate([ + bindingBehavior('validateOnChangeOrBlur') +], ValidateOnChangeOrBlurBindingBehavior); + +/** + * Creates ValidationController instances. + */ +class ValidationControllerFactory { + constructor(container) { + this.container = container; + } + static get(container) { + return new ValidationControllerFactory(container); + } + /** + * Creates a new controller instance. + */ + create(validator) { + if (!validator) { + validator = this.container.get(Validator); + } + const propertyParser = this.container.get(PropertyAccessorParser); + return new ValidationController(validator, propertyParser); + } + /** + * Creates a new controller and registers it in the current element's container so that it's + * available to the validate binding behavior and renderers. + */ + createForCurrentScope(validator) { + const controller = this.create(validator); + this.container.registerInstance(ValidationController, controller); + return controller; + } +} +ValidationControllerFactory['protocol:aurelia:resolver'] = true; + +let ValidationErrorsCustomAttribute = class ValidationErrorsCustomAttribute { + constructor(boundaryElement, controllerAccessor) { + this.boundaryElement = boundaryElement; + this.controllerAccessor = controllerAccessor; + this.controller = null; + this.errors = []; + this.errorsInternal = []; + } + static inject() { + return [DOM.Element, Lazy.of(ValidationController)]; + } + sort() { + this.errorsInternal.sort((a, b) => { + if (a.targets[0] === b.targets[0]) { + return 0; + } + // tslint:disable-next-line:no-bitwise + return a.targets[0].compareDocumentPosition(b.targets[0]) & 2 ? 1 : -1; + }); + } + interestingElements(elements) { + return elements.filter(e => this.boundaryElement.contains(e)); + } + render(instruction) { + for (const { result } of instruction.unrender) { + const index = this.errorsInternal.findIndex(x => x.error === result); + if (index !== -1) { + this.errorsInternal.splice(index, 1); + } + } + for (const { result, elements } of instruction.render) { + if (result.valid) { + continue; + } + const targets = this.interestingElements(elements); + if (targets.length) { + this.errorsInternal.push({ error: result, targets }); + } + } + this.sort(); + this.errors = this.errorsInternal; + } + bind() { + if (!this.controller) { + this.controller = this.controllerAccessor(); + } + // this will call render() with the side-effect of updating this.errors + this.controller.addRenderer(this); + } + unbind() { + if (this.controller) { + this.controller.removeRenderer(this); + } + } +}; +__decorate([ + bindable({ defaultBindingMode: bindingMode.oneWay }) +], ValidationErrorsCustomAttribute.prototype, "controller", void 0); +__decorate([ + bindable({ primaryProperty: true, defaultBindingMode: bindingMode.twoWay }) +], ValidationErrorsCustomAttribute.prototype, "errors", void 0); +ValidationErrorsCustomAttribute = __decorate([ + customAttribute('validation-errors') +], ValidationErrorsCustomAttribute); + +let ValidationRendererCustomAttribute = class ValidationRendererCustomAttribute { + created(view) { + this.container = view.container; + } + bind() { + this.controller = this.container.get(ValidationController); + this.renderer = this.container.get(this.value); + this.controller.addRenderer(this.renderer); + } + unbind() { + this.controller.removeRenderer(this.renderer); + this.controller = null; + this.renderer = null; + } +}; +ValidationRendererCustomAttribute = __decorate([ + customAttribute('validation-renderer') +], ValidationRendererCustomAttribute); + +/** + * Sets, unsets and retrieves rules on an object or constructor function. + */ +class Rules { + /** + * Applies the rules to a target. + */ + static set(target, rules) { + if (target instanceof Function) { + target = target.prototype; + } + Object.defineProperty(target, Rules.key, { enumerable: false, configurable: false, writable: true, value: rules }); + } + /** + * Removes rules from a target. + */ + static unset(target) { + if (target instanceof Function) { + target = target.prototype; + } + target[Rules.key] = null; + } + /** + * Retrieves the target's rules. + */ + static get(target) { + return target[Rules.key] || null; + } +} +/** + * The name of the property that stores the rules. + */ +Rules.key = '__rules__'; + +// tslint:disable:no-empty +class ExpressionVisitor { + visitChain(chain) { + this.visitArgs(chain.expressions); + } + visitBindingBehavior(behavior) { + behavior.expression.accept(this); + this.visitArgs(behavior.args); + } + visitValueConverter(converter) { + converter.expression.accept(this); + this.visitArgs(converter.args); + } + visitAssign(assign) { + assign.target.accept(this); + assign.value.accept(this); + } + visitConditional(conditional) { + conditional.condition.accept(this); + conditional.yes.accept(this); + conditional.no.accept(this); + } + visitAccessThis(access) { + access.ancestor = access.ancestor; + } + visitAccessScope(access) { + access.name = access.name; + } + visitAccessMember(access) { + access.object.accept(this); + } + visitAccessKeyed(access) { + access.object.accept(this); + access.key.accept(this); + } + visitCallScope(call) { + this.visitArgs(call.args); + } + visitCallFunction(call) { + call.func.accept(this); + this.visitArgs(call.args); + } + visitCallMember(call) { + call.object.accept(this); + this.visitArgs(call.args); + } + visitPrefix(prefix) { + prefix.expression.accept(this); + } + visitBinary(binary) { + binary.left.accept(this); + binary.right.accept(this); + } + visitLiteralPrimitive(literal) { + literal.value = literal.value; + } + visitLiteralArray(literal) { + this.visitArgs(literal.elements); + } + visitLiteralObject(literal) { + this.visitArgs(literal.values); + } + visitLiteralString(literal) { + literal.value = literal.value; + } + visitArgs(args) { + for (let i = 0; i < args.length; i++) { + args[i].accept(this); + } + } +} + +class ValidationMessageParser { + constructor(bindinqLanguage) { + this.bindinqLanguage = bindinqLanguage; + this.emptyStringExpression = new LiteralString(''); + this.nullExpression = new LiteralPrimitive(null); + this.undefinedExpression = new LiteralPrimitive(undefined); + this.cache = {}; + } + parse(message) { + if (this.cache[message] !== undefined) { + return this.cache[message]; + } + const parts = this.bindinqLanguage.parseInterpolation(null, message); + if (parts === null) { + return new LiteralString(message); + } + let expression = new LiteralString(parts[0]); + for (let i = 1; i < parts.length; i += 2) { + expression = new Binary('+', expression, new Binary('+', this.coalesce(parts[i]), new LiteralString(parts[i + 1]))); + } + MessageExpressionValidator.validate(expression, message); + this.cache[message] = expression; + return expression; + } + coalesce(part) { + // part === null || part === undefined ? '' : part + return new Conditional(new Binary('||', new Binary('===', part, this.nullExpression), new Binary('===', part, this.undefinedExpression)), this.emptyStringExpression, new CallMember(part, 'toString', [])); + } +} +ValidationMessageParser.inject = [BindingLanguage]; +class MessageExpressionValidator extends ExpressionVisitor { + constructor(originalMessage) { + super(); + this.originalMessage = originalMessage; + } + static validate(expression, originalMessage) { + const visitor = new MessageExpressionValidator(originalMessage); + expression.accept(visitor); + } + visitAccessScope(access) { + if (access.ancestor !== 0) { + throw new Error('$parent is not permitted in validation message expressions.'); + } + if (['displayName', 'propertyName', 'value', 'object', 'config', 'getDisplayName'].indexOf(access.name) !== -1) { + getLogger('aurelia-validation') + // tslint:disable-next-line:max-line-length + .warn(`Did you mean to use "$${access.name}" instead of "${access.name}" in this validation message template: "${this.originalMessage}"?`); + } + } +} + +/** + * Dictionary of validation messages. [messageKey]: messageExpression + */ +const validationMessages = { + /** + * The default validation message. Used with rules that have no standard message. + */ + default: `\${$displayName} is invalid.`, + required: `\${$displayName} is required.`, + matches: `\${$displayName} is not correctly formatted.`, + email: `\${$displayName} is not a valid email.`, + minLength: `\${$displayName} must be at least \${$config.length} character\${$config.length === 1 ? '' : 's'}.`, + maxLength: `\${$displayName} cannot be longer than \${$config.length} character\${$config.length === 1 ? '' : 's'}.`, + minItems: `\${$displayName} must contain at least \${$config.count} item\${$config.count === 1 ? '' : 's'}.`, + maxItems: `\${$displayName} cannot contain more than \${$config.count} item\${$config.count === 1 ? '' : 's'}.`, + min: `\${$displayName} must be at least \${$config.constraint}.`, + max: `\${$displayName} must be at most \${$config.constraint}.`, + range: `\${$displayName} must be between or equal to \${$config.min} and \${$config.max}.`, + between: `\${$displayName} must be between but not equal to \${$config.min} and \${$config.max}.`, + equals: `\${$displayName} must be \${$config.expectedValue}.`, +}; +/** + * Retrieves validation messages and property display names. + */ +class ValidationMessageProvider { + constructor(parser) { + this.parser = parser; + } + /** + * Returns a message binding expression that corresponds to the key. + * @param key The message key. + */ + getMessage(key) { + let message; + if (key in validationMessages) { + message = validationMessages[key]; + } + else { + message = validationMessages['default']; + } + return this.parser.parse(message); + } + /** + * Formulates a property display name using the property name and the configured + * displayName (if provided). + * Override this with your own custom logic. + * @param propertyName The property name. + */ + getDisplayName(propertyName, displayName) { + if (displayName !== null && displayName !== undefined) { + return (displayName instanceof Function) ? displayName() : displayName; + } + // split on upper-case letters. + const words = propertyName.toString().split(/(?=[A-Z])/).join(' '); + // capitalize first letter. + return words.charAt(0).toUpperCase() + words.slice(1); + } +} +ValidationMessageProvider.inject = [ValidationMessageParser]; + +/** + * Validates. + * Responsible for validating objects and properties. + */ +class StandardValidator extends Validator { + constructor(messageProvider, resources) { + super(); + this.messageProvider = messageProvider; + this.lookupFunctions = resources.lookupFunctions; + this.getDisplayName = messageProvider.getDisplayName.bind(messageProvider); + } + /** + * Validates the specified property. + * @param object The object to validate. + * @param propertyName The name of the property to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + validateProperty(object, propertyName, rules) { + return this.validate(object, propertyName, rules || null); + } + /** + * Validates all rules for specified object and it's properties. + * @param object The object to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + validateObject(object, rules) { + return this.validate(object, null, rules || null); + } + /** + * Determines whether a rule exists in a set of rules. + * @param rules The rules to search. + * @parem rule The rule to find. + */ + ruleExists(rules, rule) { + let i = rules.length; + while (i--) { + if (rules[i].indexOf(rule) !== -1) { + return true; + } + } + return false; + } + getMessage(rule, object, value) { + const expression = rule.message || this.messageProvider.getMessage(rule.messageKey); + // tslint:disable-next-line:prefer-const + let { name: propertyName, displayName } = rule.property; + if (propertyName !== null) { + displayName = this.messageProvider.getDisplayName(propertyName, displayName); + } + const overrideContext = { + $displayName: displayName, + $propertyName: propertyName, + $value: value, + $object: object, + $config: rule.config, + // returns the name of a given property, given just the property name (irrespective of the property's displayName) + // split on capital letters, first letter ensured to be capitalized + $getDisplayName: this.getDisplayName + }; + return expression.evaluate({ bindingContext: object, overrideContext }, this.lookupFunctions); + } + validateRuleSequence(object, propertyName, ruleSequence, sequence, results) { + // are we validating all properties or a single property? + const validateAllProperties = propertyName === null || propertyName === undefined; + const rules = ruleSequence[sequence]; + let allValid = true; + // validate each rule. + const promises = []; + for (let i = 0; i < rules.length; i++) { + const rule = rules[i]; + // is the rule related to the property we're validating. + // tslint:disable-next-line:triple-equals | Use loose equality for property keys + if (!validateAllProperties && rule.property.name != propertyName) { + continue; + } + // is this a conditional rule? is the condition met? + if (rule.when && !rule.when(object)) { + continue; + } + // validate. + const value = rule.property.name === null ? object : object[rule.property.name]; + let promiseOrBoolean = rule.condition(value, object); + if (!(promiseOrBoolean instanceof Promise)) { + promiseOrBoolean = Promise.resolve(promiseOrBoolean); + } + promises.push(promiseOrBoolean.then(valid => { + const message = valid ? null : this.getMessage(rule, object, value); + results.push(new ValidateResult(rule, object, rule.property.name, valid, message)); + allValid = allValid && valid; + return valid; + })); + } + return Promise.all(promises) + .then(() => { + sequence++; + if (allValid && sequence < ruleSequence.length) { + return this.validateRuleSequence(object, propertyName, ruleSequence, sequence, results); + } + return results; + }); + } + validate(object, propertyName, rules) { + // rules specified? + if (!rules) { + // no. attempt to locate the rules. + rules = Rules.get(object); + } + // any rules? + if (!rules || rules.length === 0) { + return Promise.resolve([]); + } + return this.validateRuleSequence(object, propertyName, rules, 0, []); + } +} +StandardValidator.inject = [ValidationMessageProvider, ViewResources]; + +/** + * Part of the fluent rule API. Enables customizing property rules. + */ +class FluentRuleCustomizer { + constructor(property, condition, config = {}, fluentEnsure, fluentRules, parsers) { + this.fluentEnsure = fluentEnsure; + this.fluentRules = fluentRules; + this.parsers = parsers; + this.rule = { + property, + condition, + config, + when: null, + messageKey: 'default', + message: null, + sequence: fluentRules.sequence + }; + this.fluentEnsure._addRule(this.rule); + } + /** + * Validate subsequent rules after previously declared rules have + * been validated successfully. Use to postpone validation of costly + * rules until less expensive rules pass validation. + */ + then() { + this.fluentRules.sequence++; + return this; + } + /** + * Specifies the key to use when looking up the rule's validation message. + */ + withMessageKey(key) { + this.rule.messageKey = key; + this.rule.message = null; + return this; + } + /** + * Specifies rule's validation message. + */ + withMessage(message) { + this.rule.messageKey = 'custom'; + this.rule.message = this.parsers.message.parse(message); + return this; + } + /** + * Specifies a condition that must be met before attempting to validate the rule. + * @param condition A function that accepts the object as a parameter and returns true + * or false whether the rule should be evaluated. + */ + when(condition) { + this.rule.when = condition; + return this; + } + /** + * Tags the rule instance, enabling the rule to be found easily + * using ValidationRules.taggedRules(rules, tag) + */ + tag(tag) { + this.rule.tag = tag; + return this; + } + ///// FluentEnsure APIs ///// + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + ensure(subject) { + return this.fluentEnsure.ensure(subject); + } + /** + * Targets an object with validation rules. + */ + ensureObject() { + return this.fluentEnsure.ensureObject(); + } + /** + * Rules that have been defined using the fluent API. + */ + get rules() { + return this.fluentEnsure.rules; + } + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + on(target) { + return this.fluentEnsure.on(target); + } + ///////// FluentRules APIs ///////// + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + satisfies(condition, config) { + return this.fluentRules.satisfies(condition, config); + } + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + satisfiesRule(name, ...args) { + return this.fluentRules.satisfiesRule(name, ...args); + } + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + required() { + return this.fluentRules.required(); + } + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + matches(regex) { + return this.fluentRules.matches(regex); + } + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + email() { + return this.fluentRules.email(); + } + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + minLength(length) { + return this.fluentRules.minLength(length); + } + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + maxLength(length) { + return this.fluentRules.maxLength(length); + } + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + minItems(count) { + return this.fluentRules.minItems(count); + } + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + maxItems(count) { + return this.fluentRules.maxItems(count); + } + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + min(value) { + return this.fluentRules.min(value); + } + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + max(value) { + return this.fluentRules.max(value); + } + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + range(min, max) { + return this.fluentRules.range(min, max); + } + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + between(min, max) { + return this.fluentRules.between(min, max); + } + /** + * Applies the "equals" validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + equals(expectedValue) { + return this.fluentRules.equals(expectedValue); + } +} +/** + * Part of the fluent rule API. Enables applying rules to properties and objects. + */ +class FluentRules { + constructor(fluentEnsure, parsers, property) { + this.fluentEnsure = fluentEnsure; + this.parsers = parsers; + this.property = property; + /** + * Current rule sequence number. Used to postpone evaluation of rules until rules + * with lower sequence number have successfully validated. The "then" fluent API method + * manages this property, there's usually no need to set it directly. + */ + this.sequence = 0; + } + /** + * Sets the display name of the ensured property. + */ + displayName(name) { + this.property.displayName = name; + return this; + } + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + satisfies(condition, config) { + return new FluentRuleCustomizer(this.property, condition, config, this.fluentEnsure, this, this.parsers); + } + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + satisfiesRule(name, ...args) { + let rule = FluentRules.customRules[name]; + if (!rule) { + // standard rule? + rule = this[name]; + if (rule instanceof Function) { + return rule.call(this, ...args); + } + throw new Error(`Rule with name "${name}" does not exist.`); + } + const config = rule.argsToConfig ? rule.argsToConfig(...args) : undefined; + return this.satisfies((value, obj) => rule.condition.call(this, value, obj, ...args), config) + .withMessageKey(name); + } + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + required() { + return this.satisfies(value => value !== null + && value !== undefined + && !(isString(value) && !/\S/.test(value))).withMessageKey('required'); + } + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + matches(regex) { + return this.satisfies(value => value === null || value === undefined || value.length === 0 || regex.test(value)) + .withMessageKey('matches'); + } + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + email() { + // regex from https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address + /* tslint:disable:max-line-length */ + return this.matches(/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/) + /* tslint:enable:max-line-length */ + .withMessageKey('email'); + } + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + minLength(length) { + return this.satisfies((value) => value === null || value === undefined || value.length === 0 || value.length >= length, { length }) + .withMessageKey('minLength'); + } + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + maxLength(length) { + return this.satisfies((value) => value === null || value === undefined || value.length === 0 || value.length <= length, { length }) + .withMessageKey('maxLength'); + } + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + minItems(count) { + return this.satisfies((value) => value === null || value === undefined || value.length >= count, { count }) + .withMessageKey('minItems'); + } + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + maxItems(count) { + return this.satisfies((value) => value === null || value === undefined || value.length <= count, { count }) + .withMessageKey('maxItems'); + } + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + min(constraint) { + return this.satisfies((value) => value === null || value === undefined || value >= constraint, { constraint }) + .withMessageKey('min'); + } + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + max(constraint) { + return this.satisfies((value) => value === null || value === undefined || value <= constraint, { constraint }) + .withMessageKey('max'); + } + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + range(min, max) { + return this.satisfies((value) => value === null || value === undefined || (value >= min && value <= max), { min, max }) + .withMessageKey('range'); + } + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + between(min, max) { + return this.satisfies((value) => value === null || value === undefined || (value > min && value < max), { min, max }) + .withMessageKey('between'); + } + /** + * Applies the "equals" validation rule to the property. + * null and undefined values are considered valid. + */ + equals(expectedValue) { + return this.satisfies(value => value === null || value === undefined || value === '' || value === expectedValue, { expectedValue }) + .withMessageKey('equals'); + } +} +FluentRules.customRules = {}; +/** + * Part of the fluent rule API. Enables targeting properties and objects with rules. + */ +class FluentEnsure { + constructor(parsers) { + this.parsers = parsers; + /** + * Rules that have been defined using the fluent API. + */ + this.rules = []; + } + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor + * function. + */ + ensure(property) { + this.assertInitialized(); + const name = this.parsers.property.parse(property); + const fluentRules = new FluentRules(this, this.parsers, { name, displayName: null }); + return this.mergeRules(fluentRules, name); + } + /** + * Targets an object with validation rules. + */ + ensureObject() { + this.assertInitialized(); + const fluentRules = new FluentRules(this, this.parsers, { name: null, displayName: null }); + return this.mergeRules(fluentRules, null); + } + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + on(target) { + Rules.set(target, this.rules); + return this; + } + /** + * Adds a rule definition to the sequenced ruleset. + * @internal + */ + _addRule(rule) { + while (this.rules.length < rule.sequence + 1) { + this.rules.push([]); + } + this.rules[rule.sequence].push(rule); + } + assertInitialized() { + if (this.parsers) { + return; + } + throw new Error(`Did you forget to add ".plugin('aurelia-validation')" to your main.js?`); + } + mergeRules(fluentRules, propertyName) { + // tslint:disable-next-line:triple-equals | Use loose equality for property keys + const existingRules = this.rules.find(r => r.length > 0 && r[0].property.name == propertyName); + if (existingRules) { + const rule = existingRules[existingRules.length - 1]; + fluentRules.sequence = rule.sequence; + if (rule.property.displayName !== null) { + fluentRules = fluentRules.displayName(rule.property.displayName); + } + } + return fluentRules; + } +} +/** + * Fluent rule definition API. + */ +class ValidationRules { + static initialize(messageParser, propertyParser) { + this.parsers = { + message: messageParser, + property: propertyParser + }; + } + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + static ensure(property) { + return new FluentEnsure(ValidationRules.parsers).ensure(property); + } + /** + * Targets an object with validation rules. + */ + static ensureObject() { + return new FluentEnsure(ValidationRules.parsers).ensureObject(); + } + /** + * Defines a custom rule. + * @param name The name of the custom rule. Also serves as the message key. + * @param condition The rule function. + * @param message The message expression + * @param argsToConfig A function that maps the rule's arguments to a "config" + * object that can be used when evaluating the message expression. + */ + static customRule(name, condition, message, argsToConfig) { + validationMessages[name] = message; + FluentRules.customRules[name] = { condition, argsToConfig }; + } + /** + * Returns rules with the matching tag. + * @param rules The rules to search. + * @param tag The tag to search for. + */ + static taggedRules(rules, tag) { + return rules.map(x => x.filter(r => r.tag === tag)); + } + /** + * Returns rules that have no tag. + * @param rules The rules to search. + */ + static untaggedRules(rules) { + return rules.map(x => x.filter(r => r.tag === undefined)); + } + /** + * Removes the rules from a class or object. + * @param target A class or object. + */ + static off(target) { + Rules.unset(target); + } +} + +// Exports +/** + * Aurelia Validation Configuration API + */ +class AureliaValidationConfiguration { + constructor() { + this.validatorType = StandardValidator; + } + /** + * Use a custom Validator implementation. + */ + customValidator(type) { + this.validatorType = type; + } + /** + * Applies the configuration. + */ + apply(container) { + const validator = container.get(this.validatorType); + container.registerInstance(Validator, validator); + } +} +/** + * Configures the plugin. + */ +function configure( +// tslint:disable-next-line:ban-types +frameworkConfig, callback) { + // the fluent rule definition API needs the parser to translate messages + // to interpolation expressions. + const messageParser = frameworkConfig.container.get(ValidationMessageParser); + const propertyParser = frameworkConfig.container.get(PropertyAccessorParser); + ValidationRules.initialize(messageParser, propertyParser); + // configure... + const config = new AureliaValidationConfiguration(); + if (callback instanceof Function) { + callback(config); + } + config.apply(frameworkConfig.container); + // globalize the behaviors. + if (frameworkConfig.globalResources) { + frameworkConfig.globalResources(ValidateBindingBehavior, ValidateManuallyBindingBehavior, ValidateOnBlurBindingBehavior, ValidateOnChangeBindingBehavior, ValidateOnChangeOrBlurBindingBehavior, ValidationErrorsCustomAttribute, ValidationRendererCustomAttribute); + } +} + +export { AureliaValidationConfiguration, configure, getTargetDOMElement, getPropertyInfo, PropertyAccessorParser, getAccessorExpression, ValidateBindingBehavior, ValidateManuallyBindingBehavior, ValidateOnBlurBindingBehavior, ValidateOnChangeBindingBehavior, ValidateOnChangeOrBlurBindingBehavior, ValidateEvent, ValidateResult, validateTrigger, ValidationController, ValidationControllerFactory, ValidationErrorsCustomAttribute, ValidationRendererCustomAttribute, Validator, Rules, StandardValidator, validationMessages, ValidationMessageProvider, ValidationMessageParser, MessageExpressionValidator, FluentRuleCustomizer, FluentRules, FluentEnsure, ValidationRules }; diff --git a/dist/native-modules/aurelia-validation.js b/dist/native-modules/aurelia-validation.js new file mode 100644 index 00000000..8d9316da --- /dev/null +++ b/dist/native-modules/aurelia-validation.js @@ -0,0 +1,1858 @@ +import { DOM } from 'aurelia-pal'; +import { AccessMember, AccessScope, AccessKeyed, BindingBehavior, ValueConverter, getContextFor, Parser, bindingBehavior, bindingMode, LiteralString, Binary, Conditional, LiteralPrimitive, CallMember } from 'aurelia-binding'; +import { Optional, Lazy } from 'aurelia-dependency-injection'; +import { TaskQueue } from 'aurelia-task-queue'; +import { customAttribute, bindable, BindingLanguage, ViewResources } from 'aurelia-templating'; +import { getLogger } from 'aurelia-logging'; + +/** + * Gets the DOM element associated with the data-binding. Most of the time it's + * the binding.target but sometimes binding.target is an aurelia custom element, + * or custom attribute which is a javascript "class" instance, so we need to use + * the controller's container to retrieve the actual DOM element. + */ +function getTargetDOMElement(binding, view) { + var target = binding.target; + // DOM element + if (target instanceof Element) { + return target; + } + // custom element or custom attribute + // tslint:disable-next-line:prefer-const + for (var i = 0, ii = view.controllers.length; i < ii; i++) { + var controller = view.controllers[i]; + if (controller.viewModel === target) { + var element = controller.container.get(DOM.Element); + if (element) { + return element; + } + throw new Error("Unable to locate target element for \"" + binding.sourceExpression + "\"."); + } + } + throw new Error("Unable to locate target element for \"" + binding.sourceExpression + "\"."); +} + +function getObject(expression, objectExpression, source) { + var value = objectExpression.evaluate(source, null); + if (value === null || value === undefined || value instanceof Object) { + return value; + } + // tslint:disable-next-line:max-line-length + throw new Error("The '" + objectExpression + "' part of '" + expression + "' evaluates to " + value + " instead of an object, null or undefined."); +} +/** + * Retrieves the object and property name for the specified expression. + * @param expression The expression + * @param source The scope + */ +function getPropertyInfo(expression, source) { + var originalExpression = expression; + while (expression instanceof BindingBehavior || expression instanceof ValueConverter) { + expression = expression.expression; + } + var object; + var propertyName; + if (expression instanceof AccessScope) { + object = getContextFor(expression.name, source, expression.ancestor); + propertyName = expression.name; + } + else if (expression instanceof AccessMember) { + object = getObject(originalExpression, expression.object, source); + propertyName = expression.name; + } + else if (expression instanceof AccessKeyed) { + object = getObject(originalExpression, expression.object, source); + propertyName = expression.key.evaluate(source); + } + else { + throw new Error("Expression '" + originalExpression + "' is not compatible with the validate binding-behavior."); + } + if (object === null || object === undefined) { + return null; + } + return { object: object, propertyName: propertyName }; +} + +function isString(value) { + return Object.prototype.toString.call(value) === '[object String]'; +} +function isNumber(value) { + return Object.prototype.toString.call(value) === '[object Number]'; +} + +var PropertyAccessorParser = /** @class */ (function () { + function PropertyAccessorParser(parser) { + this.parser = parser; + } + PropertyAccessorParser.prototype.parse = function (property) { + if (isString(property) || isNumber(property)) { + return property; + } + var accessorText = getAccessorExpression(property.toString()); + var accessor = this.parser.parse(accessorText); + if (accessor instanceof AccessScope + || accessor instanceof AccessMember && accessor.object instanceof AccessScope) { + return accessor.name; + } + throw new Error("Invalid property expression: \"" + accessor + "\""); + }; + PropertyAccessorParser.inject = [Parser]; + return PropertyAccessorParser; +}()); +function getAccessorExpression(fn) { + /* tslint:disable:max-line-length */ + var classic = /^function\s*\([$_\w\d]+\)\s*\{(?:\s*"use strict";)?\s*(?:[$_\w\d.['"\]+;]+)?\s*return\s+[$_\w\d]+\.([$_\w\d]+)\s*;?\s*\}$/; + /* tslint:enable:max-line-length */ + var arrow = /^\(?[$_\w\d]+\)?\s*=>\s*[$_\w\d]+\.([$_\w\d]+)$/; + var match = classic.exec(fn) || arrow.exec(fn); + if (match === null) { + throw new Error("Unable to parse accessor function:\n" + fn); + } + return match[1]; +} + +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ +/* global Reflect, Promise */ + +var extendStatics = function(d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); +}; + +function __extends(d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +} + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +} + +/** + * Validation triggers. + */ +var validateTrigger; +(function (validateTrigger) { + /** + * Manual validation. Use the controller's `validate()` and `reset()` methods + * to validate all bindings. + */ + validateTrigger[validateTrigger["manual"] = 0] = "manual"; + /** + * Validate the binding when the binding's target element fires a DOM "blur" event. + */ + validateTrigger[validateTrigger["blur"] = 1] = "blur"; + /** + * Validate the binding when it updates the model due to a change in the view. + */ + validateTrigger[validateTrigger["change"] = 2] = "change"; + /** + * Validate the binding when the binding's target element fires a DOM "blur" event and + * when it updates the model due to a change in the view. + */ + validateTrigger[validateTrigger["changeOrBlur"] = 3] = "changeOrBlur"; +})(validateTrigger || (validateTrigger = {})); + +/** + * Validates objects and properties. + */ +var Validator = /** @class */ (function () { + function Validator() { + } + return Validator; +}()); + +/** + * The result of validating an individual validation rule. + */ +var ValidateResult = /** @class */ (function () { + /** + * @param rule The rule associated with the result. Validator implementation specific. + * @param object The object that was validated. + * @param propertyName The name of the property that was validated. + * @param error The error, if the result is a validation error. + */ + function ValidateResult(rule, object, propertyName, valid, message) { + if (message === void 0) { message = null; } + this.rule = rule; + this.object = object; + this.propertyName = propertyName; + this.valid = valid; + this.message = message; + this.id = ValidateResult.nextId++; + } + ValidateResult.prototype.toString = function () { + return this.valid ? 'Valid.' : this.message; + }; + ValidateResult.nextId = 0; + return ValidateResult; +}()); + +var ValidateEvent = /** @class */ (function () { + function ValidateEvent( + /** + * The type of validate event. Either "validate" or "reset". + */ + type, + /** + * The controller's current array of errors. For an array containing both + * failed rules and passed rules, use the "results" property. + */ + errors, + /** + * The controller's current array of validate results. This + * includes both passed rules and failed rules. For an array of only failed rules, + * use the "errors" property. + */ + results, + /** + * The instruction passed to the "validate" or "reset" event. Will be null when + * the controller's validate/reset method was called with no instruction argument. + */ + instruction, + /** + * In events with type === "validate", this property will contain the result + * of validating the instruction (see "instruction" property). Use the controllerValidateResult + * to access the validate results specific to the call to "validate" + * (as opposed to using the "results" and "errors" properties to access the controller's entire + * set of results/errors). + */ + controllerValidateResult) { + this.type = type; + this.errors = errors; + this.results = results; + this.instruction = instruction; + this.controllerValidateResult = controllerValidateResult; + } + return ValidateEvent; +}()); + +/** + * Orchestrates validation. + * Manages a set of bindings, renderers and objects. + * Exposes the current list of validation results for binding purposes. + */ +var ValidationController = /** @class */ (function () { + function ValidationController(validator, propertyParser) { + this.validator = validator; + this.propertyParser = propertyParser; + // Registered bindings (via the validate binding behavior) + this.bindings = new Map(); + // Renderers that have been added to the controller instance. + this.renderers = []; + /** + * Validation results that have been rendered by the controller. + */ + this.results = []; + /** + * Validation errors that have been rendered by the controller. + */ + this.errors = []; + /** + * Whether the controller is currently validating. + */ + this.validating = false; + // Elements related to validation results that have been rendered. + this.elements = new Map(); + // Objects that have been added to the controller instance (entity-style validation). + this.objects = new Map(); + /** + * The trigger that will invoke automatic validation of a property used in a binding. + */ + this.validateTrigger = validateTrigger.blur; + // Promise that resolves when validation has completed. + this.finishValidating = Promise.resolve(); + this.eventCallbacks = []; + } + /** + * Subscribe to controller validate and reset events. These events occur when the + * controller's "validate"" and "reset" methods are called. + * @param callback The callback to be invoked when the controller validates or resets. + */ + ValidationController.prototype.subscribe = function (callback) { + var _this = this; + this.eventCallbacks.push(callback); + return { + dispose: function () { + var index = _this.eventCallbacks.indexOf(callback); + if (index === -1) { + return; + } + _this.eventCallbacks.splice(index, 1); + } + }; + }; + /** + * Adds an object to the set of objects that should be validated when validate is called. + * @param object The object. + * @param rules Optional. The rules. If rules aren't supplied the Validator implementation will lookup the rules. + */ + ValidationController.prototype.addObject = function (object, rules) { + this.objects.set(object, rules); + }; + /** + * Removes an object from the set of objects that should be validated when validate is called. + * @param object The object. + */ + ValidationController.prototype.removeObject = function (object) { + this.objects.delete(object); + this.processResultDelta('reset', this.results.filter(function (result) { return result.object === object; }), []); + }; + /** + * Adds and renders an error. + */ + ValidationController.prototype.addError = function (message, object, propertyName) { + if (propertyName === void 0) { propertyName = null; } + var resolvedPropertyName; + if (propertyName === null) { + resolvedPropertyName = propertyName; + } + else { + resolvedPropertyName = this.propertyParser.parse(propertyName); + } + var result = new ValidateResult({ __manuallyAdded__: true }, object, resolvedPropertyName, false, message); + this.processResultDelta('validate', [], [result]); + return result; + }; + /** + * Removes and unrenders an error. + */ + ValidationController.prototype.removeError = function (result) { + if (this.results.indexOf(result) !== -1) { + this.processResultDelta('reset', [result], []); + } + }; + /** + * Adds a renderer. + * @param renderer The renderer. + */ + ValidationController.prototype.addRenderer = function (renderer) { + var _this = this; + this.renderers.push(renderer); + renderer.render({ + kind: 'validate', + render: this.results.map(function (result) { return ({ result: result, elements: _this.elements.get(result) }); }), + unrender: [] + }); + }; + /** + * Removes a renderer. + * @param renderer The renderer. + */ + ValidationController.prototype.removeRenderer = function (renderer) { + var _this = this; + this.renderers.splice(this.renderers.indexOf(renderer), 1); + renderer.render({ + kind: 'reset', + render: [], + unrender: this.results.map(function (result) { return ({ result: result, elements: _this.elements.get(result) }); }) + }); + }; + /** + * Registers a binding with the controller. + * @param binding The binding instance. + * @param target The DOM element. + * @param rules (optional) rules associated with the binding. Validator implementation specific. + */ + ValidationController.prototype.registerBinding = function (binding, target, rules) { + this.bindings.set(binding, { target: target, rules: rules, propertyInfo: null }); + }; + /** + * Unregisters a binding with the controller. + * @param binding The binding instance. + */ + ValidationController.prototype.unregisterBinding = function (binding) { + this.resetBinding(binding); + this.bindings.delete(binding); + }; + /** + * Interprets the instruction and returns a predicate that will identify + * relevant results in the list of rendered validation results. + */ + ValidationController.prototype.getInstructionPredicate = function (instruction) { + var _this = this; + if (instruction) { + var object_1 = instruction.object, propertyName_1 = instruction.propertyName, rules_1 = instruction.rules; + var predicate_1; + if (instruction.propertyName) { + predicate_1 = function (x) { return x.object === object_1 && x.propertyName === propertyName_1; }; + } + else { + predicate_1 = function (x) { return x.object === object_1; }; + } + if (rules_1) { + return function (x) { return predicate_1(x) && _this.validator.ruleExists(rules_1, x.rule); }; + } + return predicate_1; + } + else { + return function () { return true; }; + } + }; + /** + * Validates and renders results. + * @param instruction Optional. Instructions on what to validate. If undefined, all + * objects and bindings will be validated. + */ + ValidationController.prototype.validate = function (instruction) { + var _this = this; + // Get a function that will process the validation instruction. + var execute; + if (instruction) { + // tslint:disable-next-line:prefer-const + var object_2 = instruction.object, propertyName_2 = instruction.propertyName, rules_2 = instruction.rules; + // if rules were not specified, check the object map. + rules_2 = rules_2 || this.objects.get(object_2); + // property specified? + if (instruction.propertyName === undefined) { + // validate the specified object. + execute = function () { return _this.validator.validateObject(object_2, rules_2); }; + } + else { + // validate the specified property. + execute = function () { return _this.validator.validateProperty(object_2, propertyName_2, rules_2); }; + } + } + else { + // validate all objects and bindings. + execute = function () { + var promises = []; + for (var _i = 0, _a = Array.from(_this.objects); _i < _a.length; _i++) { + var _b = _a[_i], object = _b[0], rules = _b[1]; + promises.push(_this.validator.validateObject(object, rules)); + } + for (var _c = 0, _d = Array.from(_this.bindings); _c < _d.length; _c++) { + var _e = _d[_c], binding = _e[0], rules = _e[1].rules; + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (!propertyInfo || _this.objects.has(propertyInfo.object)) { + continue; + } + promises.push(_this.validator.validateProperty(propertyInfo.object, propertyInfo.propertyName, rules)); + } + return Promise.all(promises).then(function (resultSets) { return resultSets.reduce(function (a, b) { return a.concat(b); }, []); }); + }; + } + // Wait for any existing validation to finish, execute the instruction, render the results. + this.validating = true; + var returnPromise = this.finishValidating + .then(execute) + .then(function (newResults) { + var predicate = _this.getInstructionPredicate(instruction); + var oldResults = _this.results.filter(predicate); + _this.processResultDelta('validate', oldResults, newResults); + if (returnPromise === _this.finishValidating) { + _this.validating = false; + } + var result = { + instruction: instruction, + valid: newResults.find(function (x) { return !x.valid; }) === undefined, + results: newResults + }; + _this.invokeCallbacks(instruction, result); + return result; + }) + .catch(function (exception) { + // recover, to enable subsequent calls to validate() + _this.validating = false; + _this.finishValidating = Promise.resolve(); + return Promise.reject(exception); + }); + this.finishValidating = returnPromise; + return returnPromise; + }; + /** + * Resets any rendered validation results (unrenders). + * @param instruction Optional. Instructions on what to reset. If unspecified all rendered results + * will be unrendered. + */ + ValidationController.prototype.reset = function (instruction) { + var predicate = this.getInstructionPredicate(instruction); + var oldResults = this.results.filter(predicate); + this.processResultDelta('reset', oldResults, []); + this.invokeCallbacks(instruction, null); + }; + /** + * Gets the elements associated with an object and propertyName (if any). + */ + ValidationController.prototype.getAssociatedElements = function (_a) { + var object = _a.object, propertyName = _a.propertyName; + var elements = []; + for (var _i = 0, _b = Array.from(this.bindings); _i < _b.length; _i++) { + var _c = _b[_i], binding = _c[0], target = _c[1].target; + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (propertyInfo && propertyInfo.object === object && propertyInfo.propertyName === propertyName) { + elements.push(target); + } + } + return elements; + }; + ValidationController.prototype.processResultDelta = function (kind, oldResults, newResults) { + // prepare the instruction. + var instruction = { + kind: kind, + render: [], + unrender: [] + }; + // create a shallow copy of newResults so we can mutate it without causing side-effects. + newResults = newResults.slice(0); + var _loop_1 = function (oldResult) { + // get the elements associated with the old result. + var elements = this_1.elements.get(oldResult); + // remove the old result from the element map. + this_1.elements.delete(oldResult); + // create the unrender instruction. + instruction.unrender.push({ result: oldResult, elements: elements }); + // determine if there's a corresponding new result for the old result we are unrendering. + var newResultIndex = newResults.findIndex(function (x) { return x.rule === oldResult.rule && x.object === oldResult.object && x.propertyName === oldResult.propertyName; }); + if (newResultIndex === -1) { + // no corresponding new result... simple remove. + this_1.results.splice(this_1.results.indexOf(oldResult), 1); + if (!oldResult.valid) { + this_1.errors.splice(this_1.errors.indexOf(oldResult), 1); + } + } + else { + // there is a corresponding new result... + var newResult = newResults.splice(newResultIndex, 1)[0]; + // get the elements that are associated with the new result. + var elements_1 = this_1.getAssociatedElements(newResult); + this_1.elements.set(newResult, elements_1); + // create a render instruction for the new result. + instruction.render.push({ result: newResult, elements: elements_1 }); + // do an in-place replacement of the old result with the new result. + // this ensures any repeats bound to this.results will not thrash. + this_1.results.splice(this_1.results.indexOf(oldResult), 1, newResult); + if (!oldResult.valid && newResult.valid) { + this_1.errors.splice(this_1.errors.indexOf(oldResult), 1); + } + else if (!oldResult.valid && !newResult.valid) { + this_1.errors.splice(this_1.errors.indexOf(oldResult), 1, newResult); + } + else if (!newResult.valid) { + this_1.errors.push(newResult); + } + } + }; + var this_1 = this; + // create unrender instructions from the old results. + for (var _i = 0, oldResults_1 = oldResults; _i < oldResults_1.length; _i++) { + var oldResult = oldResults_1[_i]; + _loop_1(oldResult); + } + // create render instructions from the remaining new results. + for (var _a = 0, newResults_1 = newResults; _a < newResults_1.length; _a++) { + var result = newResults_1[_a]; + var elements = this.getAssociatedElements(result); + instruction.render.push({ result: result, elements: elements }); + this.elements.set(result, elements); + this.results.push(result); + if (!result.valid) { + this.errors.push(result); + } + } + // render. + for (var _b = 0, _c = this.renderers; _b < _c.length; _b++) { + var renderer = _c[_b]; + renderer.render(instruction); + } + }; + /** + * Validates the property associated with a binding. + */ + ValidationController.prototype.validateBinding = function (binding) { + if (!binding.isBound) { + return; + } + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + var rules; + var registeredBinding = this.bindings.get(binding); + if (registeredBinding) { + rules = registeredBinding.rules; + registeredBinding.propertyInfo = propertyInfo; + } + if (!propertyInfo) { + return; + } + var object = propertyInfo.object, propertyName = propertyInfo.propertyName; + this.validate({ object: object, propertyName: propertyName, rules: rules }); + }; + /** + * Resets the results for a property associated with a binding. + */ + ValidationController.prototype.resetBinding = function (binding) { + var registeredBinding = this.bindings.get(binding); + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (!propertyInfo && registeredBinding) { + propertyInfo = registeredBinding.propertyInfo; + } + if (registeredBinding) { + registeredBinding.propertyInfo = null; + } + if (!propertyInfo) { + return; + } + var object = propertyInfo.object, propertyName = propertyInfo.propertyName; + this.reset({ object: object, propertyName: propertyName }); + }; + /** + * Changes the controller's validateTrigger. + * @param newTrigger The new validateTrigger + */ + ValidationController.prototype.changeTrigger = function (newTrigger) { + this.validateTrigger = newTrigger; + var bindings = Array.from(this.bindings.keys()); + for (var _i = 0, bindings_1 = bindings; _i < bindings_1.length; _i++) { + var binding = bindings_1[_i]; + var source = binding.source; + binding.unbind(); + binding.bind(source); + } + }; + /** + * Revalidates the controller's current set of errors. + */ + ValidationController.prototype.revalidateErrors = function () { + for (var _i = 0, _a = this.errors; _i < _a.length; _i++) { + var _b = _a[_i], object = _b.object, propertyName = _b.propertyName, rule = _b.rule; + if (rule.__manuallyAdded__) { + continue; + } + var rules = [[rule]]; + this.validate({ object: object, propertyName: propertyName, rules: rules }); + } + }; + ValidationController.prototype.invokeCallbacks = function (instruction, result) { + if (this.eventCallbacks.length === 0) { + return; + } + var event = new ValidateEvent(result ? 'validate' : 'reset', this.errors, this.results, instruction || null, result); + for (var i = 0; i < this.eventCallbacks.length; i++) { + this.eventCallbacks[i](event); + } + }; + ValidationController.inject = [Validator, PropertyAccessorParser]; + return ValidationController; +}()); + +/** + * Binding behavior. Indicates the bound property should be validated. + */ +var ValidateBindingBehaviorBase = /** @class */ (function () { + function ValidateBindingBehaviorBase(taskQueue) { + this.taskQueue = taskQueue; + } + ValidateBindingBehaviorBase.prototype.bind = function (binding, source, rulesOrController, rules) { + var _this = this; + // identify the target element. + var target = getTargetDOMElement(binding, source); + // locate the controller. + var controller; + if (rulesOrController instanceof ValidationController) { + controller = rulesOrController; + } + else { + controller = source.container.get(Optional.of(ValidationController)); + rules = rulesOrController; + } + if (controller === null) { + throw new Error("A ValidationController has not been registered."); + } + controller.registerBinding(binding, target, rules); + binding.validationController = controller; + var trigger = this.getValidateTrigger(controller); + // tslint:disable-next-line:no-bitwise + if (trigger & validateTrigger.change) { + binding.vbbUpdateSource = binding.updateSource; + // tslint:disable-next-line:only-arrow-functions + // tslint:disable-next-line:space-before-function-paren + binding.updateSource = function (value) { + this.vbbUpdateSource(value); + this.validationController.validateBinding(this); + }; + } + // tslint:disable-next-line:no-bitwise + if (trigger & validateTrigger.blur) { + binding.validateBlurHandler = function () { + _this.taskQueue.queueMicroTask(function () { return controller.validateBinding(binding); }); + }; + binding.validateTarget = target; + target.addEventListener('blur', binding.validateBlurHandler); + } + if (trigger !== validateTrigger.manual) { + binding.standardUpdateTarget = binding.updateTarget; + // tslint:disable-next-line:only-arrow-functions + // tslint:disable-next-line:space-before-function-paren + binding.updateTarget = function (value) { + this.standardUpdateTarget(value); + this.validationController.resetBinding(this); + }; + } + }; + ValidateBindingBehaviorBase.prototype.unbind = function (binding) { + // reset the binding to it's original state. + if (binding.vbbUpdateSource) { + binding.updateSource = binding.vbbUpdateSource; + binding.vbbUpdateSource = null; + } + if (binding.standardUpdateTarget) { + binding.updateTarget = binding.standardUpdateTarget; + binding.standardUpdateTarget = null; + } + if (binding.validateBlurHandler) { + binding.validateTarget.removeEventListener('blur', binding.validateBlurHandler); + binding.validateBlurHandler = null; + binding.validateTarget = null; + } + binding.validationController.unregisterBinding(binding); + binding.validationController = null; + }; + return ValidateBindingBehaviorBase; +}()); + +/** + * Binding behavior. Indicates the bound property should be validated + * when the validate trigger specified by the associated controller's + * validateTrigger property occurs. + */ +var ValidateBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateBindingBehavior, _super); + function ValidateBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateBindingBehavior.prototype.getValidateTrigger = function (controller) { + return controller.validateTrigger; + }; + ValidateBindingBehavior.inject = [TaskQueue]; + ValidateBindingBehavior = __decorate([ + bindingBehavior('validate') + ], ValidateBindingBehavior); + return ValidateBindingBehavior; +}(ValidateBindingBehaviorBase)); +/** + * Binding behavior. Indicates the bound property will be validated + * manually, by calling controller.validate(). No automatic validation + * triggered by data-entry or blur will occur. + */ +var ValidateManuallyBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateManuallyBindingBehavior, _super); + function ValidateManuallyBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateManuallyBindingBehavior.prototype.getValidateTrigger = function () { + return validateTrigger.manual; + }; + ValidateManuallyBindingBehavior.inject = [TaskQueue]; + ValidateManuallyBindingBehavior = __decorate([ + bindingBehavior('validateManually') + ], ValidateManuallyBindingBehavior); + return ValidateManuallyBindingBehavior; +}(ValidateBindingBehaviorBase)); +/** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs. + */ +var ValidateOnBlurBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateOnBlurBindingBehavior, _super); + function ValidateOnBlurBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateOnBlurBindingBehavior.prototype.getValidateTrigger = function () { + return validateTrigger.blur; + }; + ValidateOnBlurBindingBehavior.inject = [TaskQueue]; + ValidateOnBlurBindingBehavior = __decorate([ + bindingBehavior('validateOnBlur') + ], ValidateOnBlurBindingBehavior); + return ValidateOnBlurBindingBehavior; +}(ValidateBindingBehaviorBase)); +/** + * Binding behavior. Indicates the bound property should be validated + * when the associated element is changed by the user, causing a change + * to the model. + */ +var ValidateOnChangeBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateOnChangeBindingBehavior, _super); + function ValidateOnChangeBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateOnChangeBindingBehavior.prototype.getValidateTrigger = function () { + return validateTrigger.change; + }; + ValidateOnChangeBindingBehavior.inject = [TaskQueue]; + ValidateOnChangeBindingBehavior = __decorate([ + bindingBehavior('validateOnChange') + ], ValidateOnChangeBindingBehavior); + return ValidateOnChangeBindingBehavior; +}(ValidateBindingBehaviorBase)); +/** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs or is changed by the user, causing + * a change to the model. + */ +var ValidateOnChangeOrBlurBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateOnChangeOrBlurBindingBehavior, _super); + function ValidateOnChangeOrBlurBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateOnChangeOrBlurBindingBehavior.prototype.getValidateTrigger = function () { + return validateTrigger.changeOrBlur; + }; + ValidateOnChangeOrBlurBindingBehavior.inject = [TaskQueue]; + ValidateOnChangeOrBlurBindingBehavior = __decorate([ + bindingBehavior('validateOnChangeOrBlur') + ], ValidateOnChangeOrBlurBindingBehavior); + return ValidateOnChangeOrBlurBindingBehavior; +}(ValidateBindingBehaviorBase)); + +/** + * Creates ValidationController instances. + */ +var ValidationControllerFactory = /** @class */ (function () { + function ValidationControllerFactory(container) { + this.container = container; + } + ValidationControllerFactory.get = function (container) { + return new ValidationControllerFactory(container); + }; + /** + * Creates a new controller instance. + */ + ValidationControllerFactory.prototype.create = function (validator) { + if (!validator) { + validator = this.container.get(Validator); + } + var propertyParser = this.container.get(PropertyAccessorParser); + return new ValidationController(validator, propertyParser); + }; + /** + * Creates a new controller and registers it in the current element's container so that it's + * available to the validate binding behavior and renderers. + */ + ValidationControllerFactory.prototype.createForCurrentScope = function (validator) { + var controller = this.create(validator); + this.container.registerInstance(ValidationController, controller); + return controller; + }; + return ValidationControllerFactory; +}()); +ValidationControllerFactory['protocol:aurelia:resolver'] = true; + +var ValidationErrorsCustomAttribute = /** @class */ (function () { + function ValidationErrorsCustomAttribute(boundaryElement, controllerAccessor) { + this.boundaryElement = boundaryElement; + this.controllerAccessor = controllerAccessor; + this.controller = null; + this.errors = []; + this.errorsInternal = []; + } + ValidationErrorsCustomAttribute.inject = function () { + return [DOM.Element, Lazy.of(ValidationController)]; + }; + ValidationErrorsCustomAttribute.prototype.sort = function () { + this.errorsInternal.sort(function (a, b) { + if (a.targets[0] === b.targets[0]) { + return 0; + } + // tslint:disable-next-line:no-bitwise + return a.targets[0].compareDocumentPosition(b.targets[0]) & 2 ? 1 : -1; + }); + }; + ValidationErrorsCustomAttribute.prototype.interestingElements = function (elements) { + var _this = this; + return elements.filter(function (e) { return _this.boundaryElement.contains(e); }); + }; + ValidationErrorsCustomAttribute.prototype.render = function (instruction) { + var _loop_1 = function (result) { + var index = this_1.errorsInternal.findIndex(function (x) { return x.error === result; }); + if (index !== -1) { + this_1.errorsInternal.splice(index, 1); + } + }; + var this_1 = this; + for (var _i = 0, _a = instruction.unrender; _i < _a.length; _i++) { + var result = _a[_i].result; + _loop_1(result); + } + for (var _b = 0, _c = instruction.render; _b < _c.length; _b++) { + var _d = _c[_b], result = _d.result, elements = _d.elements; + if (result.valid) { + continue; + } + var targets = this.interestingElements(elements); + if (targets.length) { + this.errorsInternal.push({ error: result, targets: targets }); + } + } + this.sort(); + this.errors = this.errorsInternal; + }; + ValidationErrorsCustomAttribute.prototype.bind = function () { + if (!this.controller) { + this.controller = this.controllerAccessor(); + } + // this will call render() with the side-effect of updating this.errors + this.controller.addRenderer(this); + }; + ValidationErrorsCustomAttribute.prototype.unbind = function () { + if (this.controller) { + this.controller.removeRenderer(this); + } + }; + __decorate([ + bindable({ defaultBindingMode: bindingMode.oneWay }) + ], ValidationErrorsCustomAttribute.prototype, "controller", void 0); + __decorate([ + bindable({ primaryProperty: true, defaultBindingMode: bindingMode.twoWay }) + ], ValidationErrorsCustomAttribute.prototype, "errors", void 0); + ValidationErrorsCustomAttribute = __decorate([ + customAttribute('validation-errors') + ], ValidationErrorsCustomAttribute); + return ValidationErrorsCustomAttribute; +}()); + +var ValidationRendererCustomAttribute = /** @class */ (function () { + function ValidationRendererCustomAttribute() { + } + ValidationRendererCustomAttribute.prototype.created = function (view) { + this.container = view.container; + }; + ValidationRendererCustomAttribute.prototype.bind = function () { + this.controller = this.container.get(ValidationController); + this.renderer = this.container.get(this.value); + this.controller.addRenderer(this.renderer); + }; + ValidationRendererCustomAttribute.prototype.unbind = function () { + this.controller.removeRenderer(this.renderer); + this.controller = null; + this.renderer = null; + }; + ValidationRendererCustomAttribute = __decorate([ + customAttribute('validation-renderer') + ], ValidationRendererCustomAttribute); + return ValidationRendererCustomAttribute; +}()); + +/** + * Sets, unsets and retrieves rules on an object or constructor function. + */ +var Rules = /** @class */ (function () { + function Rules() { + } + /** + * Applies the rules to a target. + */ + Rules.set = function (target, rules) { + if (target instanceof Function) { + target = target.prototype; + } + Object.defineProperty(target, Rules.key, { enumerable: false, configurable: false, writable: true, value: rules }); + }; + /** + * Removes rules from a target. + */ + Rules.unset = function (target) { + if (target instanceof Function) { + target = target.prototype; + } + target[Rules.key] = null; + }; + /** + * Retrieves the target's rules. + */ + Rules.get = function (target) { + return target[Rules.key] || null; + }; + /** + * The name of the property that stores the rules. + */ + Rules.key = '__rules__'; + return Rules; +}()); + +// tslint:disable:no-empty +var ExpressionVisitor = /** @class */ (function () { + function ExpressionVisitor() { + } + ExpressionVisitor.prototype.visitChain = function (chain) { + this.visitArgs(chain.expressions); + }; + ExpressionVisitor.prototype.visitBindingBehavior = function (behavior) { + behavior.expression.accept(this); + this.visitArgs(behavior.args); + }; + ExpressionVisitor.prototype.visitValueConverter = function (converter) { + converter.expression.accept(this); + this.visitArgs(converter.args); + }; + ExpressionVisitor.prototype.visitAssign = function (assign) { + assign.target.accept(this); + assign.value.accept(this); + }; + ExpressionVisitor.prototype.visitConditional = function (conditional) { + conditional.condition.accept(this); + conditional.yes.accept(this); + conditional.no.accept(this); + }; + ExpressionVisitor.prototype.visitAccessThis = function (access) { + access.ancestor = access.ancestor; + }; + ExpressionVisitor.prototype.visitAccessScope = function (access) { + access.name = access.name; + }; + ExpressionVisitor.prototype.visitAccessMember = function (access) { + access.object.accept(this); + }; + ExpressionVisitor.prototype.visitAccessKeyed = function (access) { + access.object.accept(this); + access.key.accept(this); + }; + ExpressionVisitor.prototype.visitCallScope = function (call) { + this.visitArgs(call.args); + }; + ExpressionVisitor.prototype.visitCallFunction = function (call) { + call.func.accept(this); + this.visitArgs(call.args); + }; + ExpressionVisitor.prototype.visitCallMember = function (call) { + call.object.accept(this); + this.visitArgs(call.args); + }; + ExpressionVisitor.prototype.visitPrefix = function (prefix) { + prefix.expression.accept(this); + }; + ExpressionVisitor.prototype.visitBinary = function (binary) { + binary.left.accept(this); + binary.right.accept(this); + }; + ExpressionVisitor.prototype.visitLiteralPrimitive = function (literal) { + literal.value = literal.value; + }; + ExpressionVisitor.prototype.visitLiteralArray = function (literal) { + this.visitArgs(literal.elements); + }; + ExpressionVisitor.prototype.visitLiteralObject = function (literal) { + this.visitArgs(literal.values); + }; + ExpressionVisitor.prototype.visitLiteralString = function (literal) { + literal.value = literal.value; + }; + ExpressionVisitor.prototype.visitArgs = function (args) { + for (var i = 0; i < args.length; i++) { + args[i].accept(this); + } + }; + return ExpressionVisitor; +}()); + +var ValidationMessageParser = /** @class */ (function () { + function ValidationMessageParser(bindinqLanguage) { + this.bindinqLanguage = bindinqLanguage; + this.emptyStringExpression = new LiteralString(''); + this.nullExpression = new LiteralPrimitive(null); + this.undefinedExpression = new LiteralPrimitive(undefined); + this.cache = {}; + } + ValidationMessageParser.prototype.parse = function (message) { + if (this.cache[message] !== undefined) { + return this.cache[message]; + } + var parts = this.bindinqLanguage.parseInterpolation(null, message); + if (parts === null) { + return new LiteralString(message); + } + var expression = new LiteralString(parts[0]); + for (var i = 1; i < parts.length; i += 2) { + expression = new Binary('+', expression, new Binary('+', this.coalesce(parts[i]), new LiteralString(parts[i + 1]))); + } + MessageExpressionValidator.validate(expression, message); + this.cache[message] = expression; + return expression; + }; + ValidationMessageParser.prototype.coalesce = function (part) { + // part === null || part === undefined ? '' : part + return new Conditional(new Binary('||', new Binary('===', part, this.nullExpression), new Binary('===', part, this.undefinedExpression)), this.emptyStringExpression, new CallMember(part, 'toString', [])); + }; + ValidationMessageParser.inject = [BindingLanguage]; + return ValidationMessageParser; +}()); +var MessageExpressionValidator = /** @class */ (function (_super) { + __extends(MessageExpressionValidator, _super); + function MessageExpressionValidator(originalMessage) { + var _this = _super.call(this) || this; + _this.originalMessage = originalMessage; + return _this; + } + MessageExpressionValidator.validate = function (expression, originalMessage) { + var visitor = new MessageExpressionValidator(originalMessage); + expression.accept(visitor); + }; + MessageExpressionValidator.prototype.visitAccessScope = function (access) { + if (access.ancestor !== 0) { + throw new Error('$parent is not permitted in validation message expressions.'); + } + if (['displayName', 'propertyName', 'value', 'object', 'config', 'getDisplayName'].indexOf(access.name) !== -1) { + getLogger('aurelia-validation') + // tslint:disable-next-line:max-line-length + .warn("Did you mean to use \"$" + access.name + "\" instead of \"" + access.name + "\" in this validation message template: \"" + this.originalMessage + "\"?"); + } + }; + return MessageExpressionValidator; +}(ExpressionVisitor)); + +/** + * Dictionary of validation messages. [messageKey]: messageExpression + */ +var validationMessages = { + /** + * The default validation message. Used with rules that have no standard message. + */ + default: "${$displayName} is invalid.", + required: "${$displayName} is required.", + matches: "${$displayName} is not correctly formatted.", + email: "${$displayName} is not a valid email.", + minLength: "${$displayName} must be at least ${$config.length} character${$config.length === 1 ? '' : 's'}.", + maxLength: "${$displayName} cannot be longer than ${$config.length} character${$config.length === 1 ? '' : 's'}.", + minItems: "${$displayName} must contain at least ${$config.count} item${$config.count === 1 ? '' : 's'}.", + maxItems: "${$displayName} cannot contain more than ${$config.count} item${$config.count === 1 ? '' : 's'}.", + min: "${$displayName} must be at least ${$config.constraint}.", + max: "${$displayName} must be at most ${$config.constraint}.", + range: "${$displayName} must be between or equal to ${$config.min} and ${$config.max}.", + between: "${$displayName} must be between but not equal to ${$config.min} and ${$config.max}.", + equals: "${$displayName} must be ${$config.expectedValue}.", +}; +/** + * Retrieves validation messages and property display names. + */ +var ValidationMessageProvider = /** @class */ (function () { + function ValidationMessageProvider(parser) { + this.parser = parser; + } + /** + * Returns a message binding expression that corresponds to the key. + * @param key The message key. + */ + ValidationMessageProvider.prototype.getMessage = function (key) { + var message; + if (key in validationMessages) { + message = validationMessages[key]; + } + else { + message = validationMessages['default']; + } + return this.parser.parse(message); + }; + /** + * Formulates a property display name using the property name and the configured + * displayName (if provided). + * Override this with your own custom logic. + * @param propertyName The property name. + */ + ValidationMessageProvider.prototype.getDisplayName = function (propertyName, displayName) { + if (displayName !== null && displayName !== undefined) { + return (displayName instanceof Function) ? displayName() : displayName; + } + // split on upper-case letters. + var words = propertyName.toString().split(/(?=[A-Z])/).join(' '); + // capitalize first letter. + return words.charAt(0).toUpperCase() + words.slice(1); + }; + ValidationMessageProvider.inject = [ValidationMessageParser]; + return ValidationMessageProvider; +}()); + +/** + * Validates. + * Responsible for validating objects and properties. + */ +var StandardValidator = /** @class */ (function (_super) { + __extends(StandardValidator, _super); + function StandardValidator(messageProvider, resources) { + var _this = _super.call(this) || this; + _this.messageProvider = messageProvider; + _this.lookupFunctions = resources.lookupFunctions; + _this.getDisplayName = messageProvider.getDisplayName.bind(messageProvider); + return _this; + } + /** + * Validates the specified property. + * @param object The object to validate. + * @param propertyName The name of the property to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + StandardValidator.prototype.validateProperty = function (object, propertyName, rules) { + return this.validate(object, propertyName, rules || null); + }; + /** + * Validates all rules for specified object and it's properties. + * @param object The object to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + StandardValidator.prototype.validateObject = function (object, rules) { + return this.validate(object, null, rules || null); + }; + /** + * Determines whether a rule exists in a set of rules. + * @param rules The rules to search. + * @parem rule The rule to find. + */ + StandardValidator.prototype.ruleExists = function (rules, rule) { + var i = rules.length; + while (i--) { + if (rules[i].indexOf(rule) !== -1) { + return true; + } + } + return false; + }; + StandardValidator.prototype.getMessage = function (rule, object, value) { + var expression = rule.message || this.messageProvider.getMessage(rule.messageKey); + // tslint:disable-next-line:prefer-const + var _a = rule.property, propertyName = _a.name, displayName = _a.displayName; + if (propertyName !== null) { + displayName = this.messageProvider.getDisplayName(propertyName, displayName); + } + var overrideContext = { + $displayName: displayName, + $propertyName: propertyName, + $value: value, + $object: object, + $config: rule.config, + // returns the name of a given property, given just the property name (irrespective of the property's displayName) + // split on capital letters, first letter ensured to be capitalized + $getDisplayName: this.getDisplayName + }; + return expression.evaluate({ bindingContext: object, overrideContext: overrideContext }, this.lookupFunctions); + }; + StandardValidator.prototype.validateRuleSequence = function (object, propertyName, ruleSequence, sequence, results) { + var _this = this; + // are we validating all properties or a single property? + var validateAllProperties = propertyName === null || propertyName === undefined; + var rules = ruleSequence[sequence]; + var allValid = true; + // validate each rule. + var promises = []; + var _loop_1 = function (i) { + var rule = rules[i]; + // is the rule related to the property we're validating. + // tslint:disable-next-line:triple-equals | Use loose equality for property keys + if (!validateAllProperties && rule.property.name != propertyName) { + return "continue"; + } + // is this a conditional rule? is the condition met? + if (rule.when && !rule.when(object)) { + return "continue"; + } + // validate. + var value = rule.property.name === null ? object : object[rule.property.name]; + var promiseOrBoolean = rule.condition(value, object); + if (!(promiseOrBoolean instanceof Promise)) { + promiseOrBoolean = Promise.resolve(promiseOrBoolean); + } + promises.push(promiseOrBoolean.then(function (valid) { + var message = valid ? null : _this.getMessage(rule, object, value); + results.push(new ValidateResult(rule, object, rule.property.name, valid, message)); + allValid = allValid && valid; + return valid; + })); + }; + for (var i = 0; i < rules.length; i++) { + _loop_1(i); + } + return Promise.all(promises) + .then(function () { + sequence++; + if (allValid && sequence < ruleSequence.length) { + return _this.validateRuleSequence(object, propertyName, ruleSequence, sequence, results); + } + return results; + }); + }; + StandardValidator.prototype.validate = function (object, propertyName, rules) { + // rules specified? + if (!rules) { + // no. attempt to locate the rules. + rules = Rules.get(object); + } + // any rules? + if (!rules || rules.length === 0) { + return Promise.resolve([]); + } + return this.validateRuleSequence(object, propertyName, rules, 0, []); + }; + StandardValidator.inject = [ValidationMessageProvider, ViewResources]; + return StandardValidator; +}(Validator)); + +/** + * Part of the fluent rule API. Enables customizing property rules. + */ +var FluentRuleCustomizer = /** @class */ (function () { + function FluentRuleCustomizer(property, condition, config, fluentEnsure, fluentRules, parsers) { + if (config === void 0) { config = {}; } + this.fluentEnsure = fluentEnsure; + this.fluentRules = fluentRules; + this.parsers = parsers; + this.rule = { + property: property, + condition: condition, + config: config, + when: null, + messageKey: 'default', + message: null, + sequence: fluentRules.sequence + }; + this.fluentEnsure._addRule(this.rule); + } + /** + * Validate subsequent rules after previously declared rules have + * been validated successfully. Use to postpone validation of costly + * rules until less expensive rules pass validation. + */ + FluentRuleCustomizer.prototype.then = function () { + this.fluentRules.sequence++; + return this; + }; + /** + * Specifies the key to use when looking up the rule's validation message. + */ + FluentRuleCustomizer.prototype.withMessageKey = function (key) { + this.rule.messageKey = key; + this.rule.message = null; + return this; + }; + /** + * Specifies rule's validation message. + */ + FluentRuleCustomizer.prototype.withMessage = function (message) { + this.rule.messageKey = 'custom'; + this.rule.message = this.parsers.message.parse(message); + return this; + }; + /** + * Specifies a condition that must be met before attempting to validate the rule. + * @param condition A function that accepts the object as a parameter and returns true + * or false whether the rule should be evaluated. + */ + FluentRuleCustomizer.prototype.when = function (condition) { + this.rule.when = condition; + return this; + }; + /** + * Tags the rule instance, enabling the rule to be found easily + * using ValidationRules.taggedRules(rules, tag) + */ + FluentRuleCustomizer.prototype.tag = function (tag) { + this.rule.tag = tag; + return this; + }; + ///// FluentEnsure APIs ///// + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + FluentRuleCustomizer.prototype.ensure = function (subject) { + return this.fluentEnsure.ensure(subject); + }; + /** + * Targets an object with validation rules. + */ + FluentRuleCustomizer.prototype.ensureObject = function () { + return this.fluentEnsure.ensureObject(); + }; + Object.defineProperty(FluentRuleCustomizer.prototype, "rules", { + /** + * Rules that have been defined using the fluent API. + */ + get: function () { + return this.fluentEnsure.rules; + }, + enumerable: true, + configurable: true + }); + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + FluentRuleCustomizer.prototype.on = function (target) { + return this.fluentEnsure.on(target); + }; + ///////// FluentRules APIs ///////// + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + FluentRuleCustomizer.prototype.satisfies = function (condition, config) { + return this.fluentRules.satisfies(condition, config); + }; + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + FluentRuleCustomizer.prototype.satisfiesRule = function (name) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + var _a; + return (_a = this.fluentRules).satisfiesRule.apply(_a, [name].concat(args)); + }; + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + FluentRuleCustomizer.prototype.required = function () { + return this.fluentRules.required(); + }; + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.matches = function (regex) { + return this.fluentRules.matches(regex); + }; + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.email = function () { + return this.fluentRules.email(); + }; + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.minLength = function (length) { + return this.fluentRules.minLength(length); + }; + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.maxLength = function (length) { + return this.fluentRules.maxLength(length); + }; + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.minItems = function (count) { + return this.fluentRules.minItems(count); + }; + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.maxItems = function (count) { + return this.fluentRules.maxItems(count); + }; + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.min = function (value) { + return this.fluentRules.min(value); + }; + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.max = function (value) { + return this.fluentRules.max(value); + }; + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.range = function (min, max) { + return this.fluentRules.range(min, max); + }; + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.between = function (min, max) { + return this.fluentRules.between(min, max); + }; + /** + * Applies the "equals" validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.equals = function (expectedValue) { + return this.fluentRules.equals(expectedValue); + }; + return FluentRuleCustomizer; +}()); +/** + * Part of the fluent rule API. Enables applying rules to properties and objects. + */ +var FluentRules = /** @class */ (function () { + function FluentRules(fluentEnsure, parsers, property) { + this.fluentEnsure = fluentEnsure; + this.parsers = parsers; + this.property = property; + /** + * Current rule sequence number. Used to postpone evaluation of rules until rules + * with lower sequence number have successfully validated. The "then" fluent API method + * manages this property, there's usually no need to set it directly. + */ + this.sequence = 0; + } + /** + * Sets the display name of the ensured property. + */ + FluentRules.prototype.displayName = function (name) { + this.property.displayName = name; + return this; + }; + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + FluentRules.prototype.satisfies = function (condition, config) { + return new FluentRuleCustomizer(this.property, condition, config, this.fluentEnsure, this, this.parsers); + }; + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + FluentRules.prototype.satisfiesRule = function (name) { + var _this = this; + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + var rule = FluentRules.customRules[name]; + if (!rule) { + // standard rule? + rule = this[name]; + if (rule instanceof Function) { + return rule.call.apply(rule, [this].concat(args)); + } + throw new Error("Rule with name \"" + name + "\" does not exist."); + } + var config = rule.argsToConfig ? rule.argsToConfig.apply(rule, args) : undefined; + return this.satisfies(function (value, obj) { + var _a; + return (_a = rule.condition).call.apply(_a, [_this, value, obj].concat(args)); + }, config) + .withMessageKey(name); + }; + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + FluentRules.prototype.required = function () { + return this.satisfies(function (value) { + return value !== null + && value !== undefined + && !(isString(value) && !/\S/.test(value)); + }).withMessageKey('required'); + }; + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.matches = function (regex) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length === 0 || regex.test(value); }) + .withMessageKey('matches'); + }; + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.email = function () { + // regex from https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address + /* tslint:disable:max-line-length */ + return this.matches(/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/) + /* tslint:enable:max-line-length */ + .withMessageKey('email'); + }; + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.minLength = function (length) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length === 0 || value.length >= length; }, { length: length }) + .withMessageKey('minLength'); + }; + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.maxLength = function (length) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length === 0 || value.length <= length; }, { length: length }) + .withMessageKey('maxLength'); + }; + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRules.prototype.minItems = function (count) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length >= count; }, { count: count }) + .withMessageKey('minItems'); + }; + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRules.prototype.maxItems = function (count) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length <= count; }, { count: count }) + .withMessageKey('maxItems'); + }; + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRules.prototype.min = function (constraint) { + return this.satisfies(function (value) { return value === null || value === undefined || value >= constraint; }, { constraint: constraint }) + .withMessageKey('min'); + }; + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRules.prototype.max = function (constraint) { + return this.satisfies(function (value) { return value === null || value === undefined || value <= constraint; }, { constraint: constraint }) + .withMessageKey('max'); + }; + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRules.prototype.range = function (min, max) { + return this.satisfies(function (value) { return value === null || value === undefined || (value >= min && value <= max); }, { min: min, max: max }) + .withMessageKey('range'); + }; + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRules.prototype.between = function (min, max) { + return this.satisfies(function (value) { return value === null || value === undefined || (value > min && value < max); }, { min: min, max: max }) + .withMessageKey('between'); + }; + /** + * Applies the "equals" validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRules.prototype.equals = function (expectedValue) { + return this.satisfies(function (value) { return value === null || value === undefined || value === '' || value === expectedValue; }, { expectedValue: expectedValue }) + .withMessageKey('equals'); + }; + FluentRules.customRules = {}; + return FluentRules; +}()); +/** + * Part of the fluent rule API. Enables targeting properties and objects with rules. + */ +var FluentEnsure = /** @class */ (function () { + function FluentEnsure(parsers) { + this.parsers = parsers; + /** + * Rules that have been defined using the fluent API. + */ + this.rules = []; + } + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor + * function. + */ + FluentEnsure.prototype.ensure = function (property) { + this.assertInitialized(); + var name = this.parsers.property.parse(property); + var fluentRules = new FluentRules(this, this.parsers, { name: name, displayName: null }); + return this.mergeRules(fluentRules, name); + }; + /** + * Targets an object with validation rules. + */ + FluentEnsure.prototype.ensureObject = function () { + this.assertInitialized(); + var fluentRules = new FluentRules(this, this.parsers, { name: null, displayName: null }); + return this.mergeRules(fluentRules, null); + }; + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + FluentEnsure.prototype.on = function (target) { + Rules.set(target, this.rules); + return this; + }; + /** + * Adds a rule definition to the sequenced ruleset. + * @internal + */ + FluentEnsure.prototype._addRule = function (rule) { + while (this.rules.length < rule.sequence + 1) { + this.rules.push([]); + } + this.rules[rule.sequence].push(rule); + }; + FluentEnsure.prototype.assertInitialized = function () { + if (this.parsers) { + return; + } + throw new Error("Did you forget to add \".plugin('aurelia-validation')\" to your main.js?"); + }; + FluentEnsure.prototype.mergeRules = function (fluentRules, propertyName) { + // tslint:disable-next-line:triple-equals | Use loose equality for property keys + var existingRules = this.rules.find(function (r) { return r.length > 0 && r[0].property.name == propertyName; }); + if (existingRules) { + var rule = existingRules[existingRules.length - 1]; + fluentRules.sequence = rule.sequence; + if (rule.property.displayName !== null) { + fluentRules = fluentRules.displayName(rule.property.displayName); + } + } + return fluentRules; + }; + return FluentEnsure; +}()); +/** + * Fluent rule definition API. + */ +var ValidationRules = /** @class */ (function () { + function ValidationRules() { + } + ValidationRules.initialize = function (messageParser, propertyParser) { + this.parsers = { + message: messageParser, + property: propertyParser + }; + }; + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + ValidationRules.ensure = function (property) { + return new FluentEnsure(ValidationRules.parsers).ensure(property); + }; + /** + * Targets an object with validation rules. + */ + ValidationRules.ensureObject = function () { + return new FluentEnsure(ValidationRules.parsers).ensureObject(); + }; + /** + * Defines a custom rule. + * @param name The name of the custom rule. Also serves as the message key. + * @param condition The rule function. + * @param message The message expression + * @param argsToConfig A function that maps the rule's arguments to a "config" + * object that can be used when evaluating the message expression. + */ + ValidationRules.customRule = function (name, condition, message, argsToConfig) { + validationMessages[name] = message; + FluentRules.customRules[name] = { condition: condition, argsToConfig: argsToConfig }; + }; + /** + * Returns rules with the matching tag. + * @param rules The rules to search. + * @param tag The tag to search for. + */ + ValidationRules.taggedRules = function (rules, tag) { + return rules.map(function (x) { return x.filter(function (r) { return r.tag === tag; }); }); + }; + /** + * Returns rules that have no tag. + * @param rules The rules to search. + */ + ValidationRules.untaggedRules = function (rules) { + return rules.map(function (x) { return x.filter(function (r) { return r.tag === undefined; }); }); + }; + /** + * Removes the rules from a class or object. + * @param target A class or object. + */ + ValidationRules.off = function (target) { + Rules.unset(target); + }; + return ValidationRules; +}()); + +// Exports +/** + * Aurelia Validation Configuration API + */ +var AureliaValidationConfiguration = /** @class */ (function () { + function AureliaValidationConfiguration() { + this.validatorType = StandardValidator; + } + /** + * Use a custom Validator implementation. + */ + AureliaValidationConfiguration.prototype.customValidator = function (type) { + this.validatorType = type; + }; + /** + * Applies the configuration. + */ + AureliaValidationConfiguration.prototype.apply = function (container) { + var validator = container.get(this.validatorType); + container.registerInstance(Validator, validator); + }; + return AureliaValidationConfiguration; +}()); +/** + * Configures the plugin. + */ +function configure( +// tslint:disable-next-line:ban-types +frameworkConfig, callback) { + // the fluent rule definition API needs the parser to translate messages + // to interpolation expressions. + var messageParser = frameworkConfig.container.get(ValidationMessageParser); + var propertyParser = frameworkConfig.container.get(PropertyAccessorParser); + ValidationRules.initialize(messageParser, propertyParser); + // configure... + var config = new AureliaValidationConfiguration(); + if (callback instanceof Function) { + callback(config); + } + config.apply(frameworkConfig.container); + // globalize the behaviors. + if (frameworkConfig.globalResources) { + frameworkConfig.globalResources(ValidateBindingBehavior, ValidateManuallyBindingBehavior, ValidateOnBlurBindingBehavior, ValidateOnChangeBindingBehavior, ValidateOnChangeOrBlurBindingBehavior, ValidationErrorsCustomAttribute, ValidationRendererCustomAttribute); + } +} + +export { AureliaValidationConfiguration, configure, getTargetDOMElement, getPropertyInfo, PropertyAccessorParser, getAccessorExpression, ValidateBindingBehavior, ValidateManuallyBindingBehavior, ValidateOnBlurBindingBehavior, ValidateOnChangeBindingBehavior, ValidateOnChangeOrBlurBindingBehavior, ValidateEvent, ValidateResult, validateTrigger, ValidationController, ValidationControllerFactory, ValidationErrorsCustomAttribute, ValidationRendererCustomAttribute, Validator, Rules, StandardValidator, validationMessages, ValidationMessageProvider, ValidationMessageParser, MessageExpressionValidator, FluentRuleCustomizer, FluentRules, FluentEnsure, ValidationRules }; diff --git a/dist/system/aurelia-validation.js b/dist/system/aurelia-validation.js new file mode 100644 index 00000000..a48f59df --- /dev/null +++ b/dist/system/aurelia-validation.js @@ -0,0 +1,1897 @@ +System.register(['aurelia-pal', 'aurelia-binding', 'aurelia-dependency-injection', 'aurelia-task-queue', 'aurelia-templating', 'aurelia-logging'], function (exports, module) { + 'use strict'; + var DOM, AccessMember, AccessScope, AccessKeyed, BindingBehavior, ValueConverter, getContextFor, Parser, bindingBehavior, bindingMode, LiteralString, Binary, Conditional, LiteralPrimitive, CallMember, Optional, Lazy, TaskQueue, customAttribute, bindable, BindingLanguage, ViewResources, getLogger; + return { + setters: [function (module) { + DOM = module.DOM; + }, function (module) { + AccessMember = module.AccessMember; + AccessScope = module.AccessScope; + AccessKeyed = module.AccessKeyed; + BindingBehavior = module.BindingBehavior; + ValueConverter = module.ValueConverter; + getContextFor = module.getContextFor; + Parser = module.Parser; + bindingBehavior = module.bindingBehavior; + bindingMode = module.bindingMode; + LiteralString = module.LiteralString; + Binary = module.Binary; + Conditional = module.Conditional; + LiteralPrimitive = module.LiteralPrimitive; + CallMember = module.CallMember; + }, function (module) { + Optional = module.Optional; + Lazy = module.Lazy; + }, function (module) { + TaskQueue = module.TaskQueue; + }, function (module) { + customAttribute = module.customAttribute; + bindable = module.bindable; + BindingLanguage = module.BindingLanguage; + ViewResources = module.ViewResources; + }, function (module) { + getLogger = module.getLogger; + }], + execute: function () { + + exports({ + configure: configure, + getTargetDOMElement: getTargetDOMElement, + getPropertyInfo: getPropertyInfo, + getAccessorExpression: getAccessorExpression, + validateTrigger: void 0 + }); + + /** + * Gets the DOM element associated with the data-binding. Most of the time it's + * the binding.target but sometimes binding.target is an aurelia custom element, + * or custom attribute which is a javascript "class" instance, so we need to use + * the controller's container to retrieve the actual DOM element. + */ + function getTargetDOMElement(binding, view) { + var target = binding.target; + // DOM element + if (target instanceof Element) { + return target; + } + // custom element or custom attribute + // tslint:disable-next-line:prefer-const + for (var i = 0, ii = view.controllers.length; i < ii; i++) { + var controller = view.controllers[i]; + if (controller.viewModel === target) { + var element = controller.container.get(DOM.Element); + if (element) { + return element; + } + throw new Error("Unable to locate target element for \"" + binding.sourceExpression + "\"."); + } + } + throw new Error("Unable to locate target element for \"" + binding.sourceExpression + "\"."); + } + + function getObject(expression, objectExpression, source) { + var value = objectExpression.evaluate(source, null); + if (value === null || value === undefined || value instanceof Object) { + return value; + } + // tslint:disable-next-line:max-line-length + throw new Error("The '" + objectExpression + "' part of '" + expression + "' evaluates to " + value + " instead of an object, null or undefined."); + } + /** + * Retrieves the object and property name for the specified expression. + * @param expression The expression + * @param source The scope + */ + function getPropertyInfo(expression, source) { + var originalExpression = expression; + while (expression instanceof BindingBehavior || expression instanceof ValueConverter) { + expression = expression.expression; + } + var object; + var propertyName; + if (expression instanceof AccessScope) { + object = getContextFor(expression.name, source, expression.ancestor); + propertyName = expression.name; + } + else if (expression instanceof AccessMember) { + object = getObject(originalExpression, expression.object, source); + propertyName = expression.name; + } + else if (expression instanceof AccessKeyed) { + object = getObject(originalExpression, expression.object, source); + propertyName = expression.key.evaluate(source); + } + else { + throw new Error("Expression '" + originalExpression + "' is not compatible with the validate binding-behavior."); + } + if (object === null || object === undefined) { + return null; + } + return { object: object, propertyName: propertyName }; + } + + function isString(value) { + return Object.prototype.toString.call(value) === '[object String]'; + } + function isNumber(value) { + return Object.prototype.toString.call(value) === '[object Number]'; + } + + var PropertyAccessorParser = exports('PropertyAccessorParser', /** @class */ (function () { + function PropertyAccessorParser(parser) { + this.parser = parser; + } + PropertyAccessorParser.prototype.parse = function (property) { + if (isString(property) || isNumber(property)) { + return property; + } + var accessorText = getAccessorExpression(property.toString()); + var accessor = this.parser.parse(accessorText); + if (accessor instanceof AccessScope + || accessor instanceof AccessMember && accessor.object instanceof AccessScope) { + return accessor.name; + } + throw new Error("Invalid property expression: \"" + accessor + "\""); + }; + PropertyAccessorParser.inject = [Parser]; + return PropertyAccessorParser; + }())); + function getAccessorExpression(fn) { + /* tslint:disable:max-line-length */ + var classic = /^function\s*\([$_\w\d]+\)\s*\{(?:\s*"use strict";)?\s*(?:[$_\w\d.['"\]+;]+)?\s*return\s+[$_\w\d]+\.([$_\w\d]+)\s*;?\s*\}$/; + /* tslint:enable:max-line-length */ + var arrow = /^\(?[$_\w\d]+\)?\s*=>\s*[$_\w\d]+\.([$_\w\d]+)$/; + var match = classic.exec(fn) || arrow.exec(fn); + if (match === null) { + throw new Error("Unable to parse accessor function:\n" + fn); + } + return match[1]; + } + + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use + this file except in compliance with the License. You may obtain a copy of the + License at http://www.apache.org/licenses/LICENSE-2.0 + + THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED + WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, + MERCHANTABLITY OR NON-INFRINGEMENT. + + See the Apache Version 2.0 License for specific language governing permissions + and limitations under the License. + ***************************************************************************** */ + /* global Reflect, Promise */ + + var extendStatics = function(d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + + function __extends(d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + } + + function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; + } + + /** + * Validation triggers. + */ + var validateTrigger; + (function (validateTrigger) { + /** + * Manual validation. Use the controller's `validate()` and `reset()` methods + * to validate all bindings. + */ + validateTrigger[validateTrigger["manual"] = 0] = "manual"; + /** + * Validate the binding when the binding's target element fires a DOM "blur" event. + */ + validateTrigger[validateTrigger["blur"] = 1] = "blur"; + /** + * Validate the binding when it updates the model due to a change in the view. + */ + validateTrigger[validateTrigger["change"] = 2] = "change"; + /** + * Validate the binding when the binding's target element fires a DOM "blur" event and + * when it updates the model due to a change in the view. + */ + validateTrigger[validateTrigger["changeOrBlur"] = 3] = "changeOrBlur"; + })(validateTrigger || (validateTrigger = exports('validateTrigger', {}))); + + /** + * Validates objects and properties. + */ + var Validator = exports('Validator', /** @class */ (function () { + function Validator() { + } + return Validator; + }())); + + /** + * The result of validating an individual validation rule. + */ + var ValidateResult = exports('ValidateResult', /** @class */ (function () { + /** + * @param rule The rule associated with the result. Validator implementation specific. + * @param object The object that was validated. + * @param propertyName The name of the property that was validated. + * @param error The error, if the result is a validation error. + */ + function ValidateResult(rule, object, propertyName, valid, message) { + if (message === void 0) { message = null; } + this.rule = rule; + this.object = object; + this.propertyName = propertyName; + this.valid = valid; + this.message = message; + this.id = ValidateResult.nextId++; + } + ValidateResult.prototype.toString = function () { + return this.valid ? 'Valid.' : this.message; + }; + ValidateResult.nextId = 0; + return ValidateResult; + }())); + + var ValidateEvent = exports('ValidateEvent', /** @class */ (function () { + function ValidateEvent( + /** + * The type of validate event. Either "validate" or "reset". + */ + type, + /** + * The controller's current array of errors. For an array containing both + * failed rules and passed rules, use the "results" property. + */ + errors, + /** + * The controller's current array of validate results. This + * includes both passed rules and failed rules. For an array of only failed rules, + * use the "errors" property. + */ + results, + /** + * The instruction passed to the "validate" or "reset" event. Will be null when + * the controller's validate/reset method was called with no instruction argument. + */ + instruction, + /** + * In events with type === "validate", this property will contain the result + * of validating the instruction (see "instruction" property). Use the controllerValidateResult + * to access the validate results specific to the call to "validate" + * (as opposed to using the "results" and "errors" properties to access the controller's entire + * set of results/errors). + */ + controllerValidateResult) { + this.type = type; + this.errors = errors; + this.results = results; + this.instruction = instruction; + this.controllerValidateResult = controllerValidateResult; + } + return ValidateEvent; + }())); + + /** + * Orchestrates validation. + * Manages a set of bindings, renderers and objects. + * Exposes the current list of validation results for binding purposes. + */ + var ValidationController = exports('ValidationController', /** @class */ (function () { + function ValidationController(validator, propertyParser) { + this.validator = validator; + this.propertyParser = propertyParser; + // Registered bindings (via the validate binding behavior) + this.bindings = new Map(); + // Renderers that have been added to the controller instance. + this.renderers = []; + /** + * Validation results that have been rendered by the controller. + */ + this.results = []; + /** + * Validation errors that have been rendered by the controller. + */ + this.errors = []; + /** + * Whether the controller is currently validating. + */ + this.validating = false; + // Elements related to validation results that have been rendered. + this.elements = new Map(); + // Objects that have been added to the controller instance (entity-style validation). + this.objects = new Map(); + /** + * The trigger that will invoke automatic validation of a property used in a binding. + */ + this.validateTrigger = validateTrigger.blur; + // Promise that resolves when validation has completed. + this.finishValidating = Promise.resolve(); + this.eventCallbacks = []; + } + /** + * Subscribe to controller validate and reset events. These events occur when the + * controller's "validate"" and "reset" methods are called. + * @param callback The callback to be invoked when the controller validates or resets. + */ + ValidationController.prototype.subscribe = function (callback) { + var _this = this; + this.eventCallbacks.push(callback); + return { + dispose: function () { + var index = _this.eventCallbacks.indexOf(callback); + if (index === -1) { + return; + } + _this.eventCallbacks.splice(index, 1); + } + }; + }; + /** + * Adds an object to the set of objects that should be validated when validate is called. + * @param object The object. + * @param rules Optional. The rules. If rules aren't supplied the Validator implementation will lookup the rules. + */ + ValidationController.prototype.addObject = function (object, rules) { + this.objects.set(object, rules); + }; + /** + * Removes an object from the set of objects that should be validated when validate is called. + * @param object The object. + */ + ValidationController.prototype.removeObject = function (object) { + this.objects.delete(object); + this.processResultDelta('reset', this.results.filter(function (result) { return result.object === object; }), []); + }; + /** + * Adds and renders an error. + */ + ValidationController.prototype.addError = function (message, object, propertyName) { + if (propertyName === void 0) { propertyName = null; } + var resolvedPropertyName; + if (propertyName === null) { + resolvedPropertyName = propertyName; + } + else { + resolvedPropertyName = this.propertyParser.parse(propertyName); + } + var result = new ValidateResult({ __manuallyAdded__: true }, object, resolvedPropertyName, false, message); + this.processResultDelta('validate', [], [result]); + return result; + }; + /** + * Removes and unrenders an error. + */ + ValidationController.prototype.removeError = function (result) { + if (this.results.indexOf(result) !== -1) { + this.processResultDelta('reset', [result], []); + } + }; + /** + * Adds a renderer. + * @param renderer The renderer. + */ + ValidationController.prototype.addRenderer = function (renderer) { + var _this = this; + this.renderers.push(renderer); + renderer.render({ + kind: 'validate', + render: this.results.map(function (result) { return ({ result: result, elements: _this.elements.get(result) }); }), + unrender: [] + }); + }; + /** + * Removes a renderer. + * @param renderer The renderer. + */ + ValidationController.prototype.removeRenderer = function (renderer) { + var _this = this; + this.renderers.splice(this.renderers.indexOf(renderer), 1); + renderer.render({ + kind: 'reset', + render: [], + unrender: this.results.map(function (result) { return ({ result: result, elements: _this.elements.get(result) }); }) + }); + }; + /** + * Registers a binding with the controller. + * @param binding The binding instance. + * @param target The DOM element. + * @param rules (optional) rules associated with the binding. Validator implementation specific. + */ + ValidationController.prototype.registerBinding = function (binding, target, rules) { + this.bindings.set(binding, { target: target, rules: rules, propertyInfo: null }); + }; + /** + * Unregisters a binding with the controller. + * @param binding The binding instance. + */ + ValidationController.prototype.unregisterBinding = function (binding) { + this.resetBinding(binding); + this.bindings.delete(binding); + }; + /** + * Interprets the instruction and returns a predicate that will identify + * relevant results in the list of rendered validation results. + */ + ValidationController.prototype.getInstructionPredicate = function (instruction) { + var _this = this; + if (instruction) { + var object_1 = instruction.object, propertyName_1 = instruction.propertyName, rules_1 = instruction.rules; + var predicate_1; + if (instruction.propertyName) { + predicate_1 = function (x) { return x.object === object_1 && x.propertyName === propertyName_1; }; + } + else { + predicate_1 = function (x) { return x.object === object_1; }; + } + if (rules_1) { + return function (x) { return predicate_1(x) && _this.validator.ruleExists(rules_1, x.rule); }; + } + return predicate_1; + } + else { + return function () { return true; }; + } + }; + /** + * Validates and renders results. + * @param instruction Optional. Instructions on what to validate. If undefined, all + * objects and bindings will be validated. + */ + ValidationController.prototype.validate = function (instruction) { + var _this = this; + // Get a function that will process the validation instruction. + var execute; + if (instruction) { + // tslint:disable-next-line:prefer-const + var object_2 = instruction.object, propertyName_2 = instruction.propertyName, rules_2 = instruction.rules; + // if rules were not specified, check the object map. + rules_2 = rules_2 || this.objects.get(object_2); + // property specified? + if (instruction.propertyName === undefined) { + // validate the specified object. + execute = function () { return _this.validator.validateObject(object_2, rules_2); }; + } + else { + // validate the specified property. + execute = function () { return _this.validator.validateProperty(object_2, propertyName_2, rules_2); }; + } + } + else { + // validate all objects and bindings. + execute = function () { + var promises = []; + for (var _i = 0, _a = Array.from(_this.objects); _i < _a.length; _i++) { + var _b = _a[_i], object = _b[0], rules = _b[1]; + promises.push(_this.validator.validateObject(object, rules)); + } + for (var _c = 0, _d = Array.from(_this.bindings); _c < _d.length; _c++) { + var _e = _d[_c], binding = _e[0], rules = _e[1].rules; + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (!propertyInfo || _this.objects.has(propertyInfo.object)) { + continue; + } + promises.push(_this.validator.validateProperty(propertyInfo.object, propertyInfo.propertyName, rules)); + } + return Promise.all(promises).then(function (resultSets) { return resultSets.reduce(function (a, b) { return a.concat(b); }, []); }); + }; + } + // Wait for any existing validation to finish, execute the instruction, render the results. + this.validating = true; + var returnPromise = this.finishValidating + .then(execute) + .then(function (newResults) { + var predicate = _this.getInstructionPredicate(instruction); + var oldResults = _this.results.filter(predicate); + _this.processResultDelta('validate', oldResults, newResults); + if (returnPromise === _this.finishValidating) { + _this.validating = false; + } + var result = { + instruction: instruction, + valid: newResults.find(function (x) { return !x.valid; }) === undefined, + results: newResults + }; + _this.invokeCallbacks(instruction, result); + return result; + }) + .catch(function (exception) { + // recover, to enable subsequent calls to validate() + _this.validating = false; + _this.finishValidating = Promise.resolve(); + return Promise.reject(exception); + }); + this.finishValidating = returnPromise; + return returnPromise; + }; + /** + * Resets any rendered validation results (unrenders). + * @param instruction Optional. Instructions on what to reset. If unspecified all rendered results + * will be unrendered. + */ + ValidationController.prototype.reset = function (instruction) { + var predicate = this.getInstructionPredicate(instruction); + var oldResults = this.results.filter(predicate); + this.processResultDelta('reset', oldResults, []); + this.invokeCallbacks(instruction, null); + }; + /** + * Gets the elements associated with an object and propertyName (if any). + */ + ValidationController.prototype.getAssociatedElements = function (_a) { + var object = _a.object, propertyName = _a.propertyName; + var elements = []; + for (var _i = 0, _b = Array.from(this.bindings); _i < _b.length; _i++) { + var _c = _b[_i], binding = _c[0], target = _c[1].target; + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (propertyInfo && propertyInfo.object === object && propertyInfo.propertyName === propertyName) { + elements.push(target); + } + } + return elements; + }; + ValidationController.prototype.processResultDelta = function (kind, oldResults, newResults) { + // prepare the instruction. + var instruction = { + kind: kind, + render: [], + unrender: [] + }; + // create a shallow copy of newResults so we can mutate it without causing side-effects. + newResults = newResults.slice(0); + var _loop_1 = function (oldResult) { + // get the elements associated with the old result. + var elements = this_1.elements.get(oldResult); + // remove the old result from the element map. + this_1.elements.delete(oldResult); + // create the unrender instruction. + instruction.unrender.push({ result: oldResult, elements: elements }); + // determine if there's a corresponding new result for the old result we are unrendering. + var newResultIndex = newResults.findIndex(function (x) { return x.rule === oldResult.rule && x.object === oldResult.object && x.propertyName === oldResult.propertyName; }); + if (newResultIndex === -1) { + // no corresponding new result... simple remove. + this_1.results.splice(this_1.results.indexOf(oldResult), 1); + if (!oldResult.valid) { + this_1.errors.splice(this_1.errors.indexOf(oldResult), 1); + } + } + else { + // there is a corresponding new result... + var newResult = newResults.splice(newResultIndex, 1)[0]; + // get the elements that are associated with the new result. + var elements_1 = this_1.getAssociatedElements(newResult); + this_1.elements.set(newResult, elements_1); + // create a render instruction for the new result. + instruction.render.push({ result: newResult, elements: elements_1 }); + // do an in-place replacement of the old result with the new result. + // this ensures any repeats bound to this.results will not thrash. + this_1.results.splice(this_1.results.indexOf(oldResult), 1, newResult); + if (!oldResult.valid && newResult.valid) { + this_1.errors.splice(this_1.errors.indexOf(oldResult), 1); + } + else if (!oldResult.valid && !newResult.valid) { + this_1.errors.splice(this_1.errors.indexOf(oldResult), 1, newResult); + } + else if (!newResult.valid) { + this_1.errors.push(newResult); + } + } + }; + var this_1 = this; + // create unrender instructions from the old results. + for (var _i = 0, oldResults_1 = oldResults; _i < oldResults_1.length; _i++) { + var oldResult = oldResults_1[_i]; + _loop_1(oldResult); + } + // create render instructions from the remaining new results. + for (var _a = 0, newResults_1 = newResults; _a < newResults_1.length; _a++) { + var result = newResults_1[_a]; + var elements = this.getAssociatedElements(result); + instruction.render.push({ result: result, elements: elements }); + this.elements.set(result, elements); + this.results.push(result); + if (!result.valid) { + this.errors.push(result); + } + } + // render. + for (var _b = 0, _c = this.renderers; _b < _c.length; _b++) { + var renderer = _c[_b]; + renderer.render(instruction); + } + }; + /** + * Validates the property associated with a binding. + */ + ValidationController.prototype.validateBinding = function (binding) { + if (!binding.isBound) { + return; + } + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + var rules; + var registeredBinding = this.bindings.get(binding); + if (registeredBinding) { + rules = registeredBinding.rules; + registeredBinding.propertyInfo = propertyInfo; + } + if (!propertyInfo) { + return; + } + var object = propertyInfo.object, propertyName = propertyInfo.propertyName; + this.validate({ object: object, propertyName: propertyName, rules: rules }); + }; + /** + * Resets the results for a property associated with a binding. + */ + ValidationController.prototype.resetBinding = function (binding) { + var registeredBinding = this.bindings.get(binding); + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (!propertyInfo && registeredBinding) { + propertyInfo = registeredBinding.propertyInfo; + } + if (registeredBinding) { + registeredBinding.propertyInfo = null; + } + if (!propertyInfo) { + return; + } + var object = propertyInfo.object, propertyName = propertyInfo.propertyName; + this.reset({ object: object, propertyName: propertyName }); + }; + /** + * Changes the controller's validateTrigger. + * @param newTrigger The new validateTrigger + */ + ValidationController.prototype.changeTrigger = function (newTrigger) { + this.validateTrigger = newTrigger; + var bindings = Array.from(this.bindings.keys()); + for (var _i = 0, bindings_1 = bindings; _i < bindings_1.length; _i++) { + var binding = bindings_1[_i]; + var source = binding.source; + binding.unbind(); + binding.bind(source); + } + }; + /** + * Revalidates the controller's current set of errors. + */ + ValidationController.prototype.revalidateErrors = function () { + for (var _i = 0, _a = this.errors; _i < _a.length; _i++) { + var _b = _a[_i], object = _b.object, propertyName = _b.propertyName, rule = _b.rule; + if (rule.__manuallyAdded__) { + continue; + } + var rules = [[rule]]; + this.validate({ object: object, propertyName: propertyName, rules: rules }); + } + }; + ValidationController.prototype.invokeCallbacks = function (instruction, result) { + if (this.eventCallbacks.length === 0) { + return; + } + var event = new ValidateEvent(result ? 'validate' : 'reset', this.errors, this.results, instruction || null, result); + for (var i = 0; i < this.eventCallbacks.length; i++) { + this.eventCallbacks[i](event); + } + }; + ValidationController.inject = [Validator, PropertyAccessorParser]; + return ValidationController; + }())); + + /** + * Binding behavior. Indicates the bound property should be validated. + */ + var ValidateBindingBehaviorBase = /** @class */ (function () { + function ValidateBindingBehaviorBase(taskQueue) { + this.taskQueue = taskQueue; + } + ValidateBindingBehaviorBase.prototype.bind = function (binding, source, rulesOrController, rules) { + var _this = this; + // identify the target element. + var target = getTargetDOMElement(binding, source); + // locate the controller. + var controller; + if (rulesOrController instanceof ValidationController) { + controller = rulesOrController; + } + else { + controller = source.container.get(Optional.of(ValidationController)); + rules = rulesOrController; + } + if (controller === null) { + throw new Error("A ValidationController has not been registered."); + } + controller.registerBinding(binding, target, rules); + binding.validationController = controller; + var trigger = this.getValidateTrigger(controller); + // tslint:disable-next-line:no-bitwise + if (trigger & validateTrigger.change) { + binding.vbbUpdateSource = binding.updateSource; + // tslint:disable-next-line:only-arrow-functions + // tslint:disable-next-line:space-before-function-paren + binding.updateSource = function (value) { + this.vbbUpdateSource(value); + this.validationController.validateBinding(this); + }; + } + // tslint:disable-next-line:no-bitwise + if (trigger & validateTrigger.blur) { + binding.validateBlurHandler = function () { + _this.taskQueue.queueMicroTask(function () { return controller.validateBinding(binding); }); + }; + binding.validateTarget = target; + target.addEventListener('blur', binding.validateBlurHandler); + } + if (trigger !== validateTrigger.manual) { + binding.standardUpdateTarget = binding.updateTarget; + // tslint:disable-next-line:only-arrow-functions + // tslint:disable-next-line:space-before-function-paren + binding.updateTarget = function (value) { + this.standardUpdateTarget(value); + this.validationController.resetBinding(this); + }; + } + }; + ValidateBindingBehaviorBase.prototype.unbind = function (binding) { + // reset the binding to it's original state. + if (binding.vbbUpdateSource) { + binding.updateSource = binding.vbbUpdateSource; + binding.vbbUpdateSource = null; + } + if (binding.standardUpdateTarget) { + binding.updateTarget = binding.standardUpdateTarget; + binding.standardUpdateTarget = null; + } + if (binding.validateBlurHandler) { + binding.validateTarget.removeEventListener('blur', binding.validateBlurHandler); + binding.validateBlurHandler = null; + binding.validateTarget = null; + } + binding.validationController.unregisterBinding(binding); + binding.validationController = null; + }; + return ValidateBindingBehaviorBase; + }()); + + /** + * Binding behavior. Indicates the bound property should be validated + * when the validate trigger specified by the associated controller's + * validateTrigger property occurs. + */ + var ValidateBindingBehavior = exports('ValidateBindingBehavior', /** @class */ (function (_super) { + __extends(ValidateBindingBehavior, _super); + function ValidateBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateBindingBehavior.prototype.getValidateTrigger = function (controller) { + return controller.validateTrigger; + }; + ValidateBindingBehavior.inject = [TaskQueue]; + ValidateBindingBehavior = __decorate([ + bindingBehavior('validate') + ], ValidateBindingBehavior); + return ValidateBindingBehavior; + }(ValidateBindingBehaviorBase))); + /** + * Binding behavior. Indicates the bound property will be validated + * manually, by calling controller.validate(). No automatic validation + * triggered by data-entry or blur will occur. + */ + var ValidateManuallyBindingBehavior = exports('ValidateManuallyBindingBehavior', /** @class */ (function (_super) { + __extends(ValidateManuallyBindingBehavior, _super); + function ValidateManuallyBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateManuallyBindingBehavior.prototype.getValidateTrigger = function () { + return validateTrigger.manual; + }; + ValidateManuallyBindingBehavior.inject = [TaskQueue]; + ValidateManuallyBindingBehavior = __decorate([ + bindingBehavior('validateManually') + ], ValidateManuallyBindingBehavior); + return ValidateManuallyBindingBehavior; + }(ValidateBindingBehaviorBase))); + /** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs. + */ + var ValidateOnBlurBindingBehavior = exports('ValidateOnBlurBindingBehavior', /** @class */ (function (_super) { + __extends(ValidateOnBlurBindingBehavior, _super); + function ValidateOnBlurBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateOnBlurBindingBehavior.prototype.getValidateTrigger = function () { + return validateTrigger.blur; + }; + ValidateOnBlurBindingBehavior.inject = [TaskQueue]; + ValidateOnBlurBindingBehavior = __decorate([ + bindingBehavior('validateOnBlur') + ], ValidateOnBlurBindingBehavior); + return ValidateOnBlurBindingBehavior; + }(ValidateBindingBehaviorBase))); + /** + * Binding behavior. Indicates the bound property should be validated + * when the associated element is changed by the user, causing a change + * to the model. + */ + var ValidateOnChangeBindingBehavior = exports('ValidateOnChangeBindingBehavior', /** @class */ (function (_super) { + __extends(ValidateOnChangeBindingBehavior, _super); + function ValidateOnChangeBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateOnChangeBindingBehavior.prototype.getValidateTrigger = function () { + return validateTrigger.change; + }; + ValidateOnChangeBindingBehavior.inject = [TaskQueue]; + ValidateOnChangeBindingBehavior = __decorate([ + bindingBehavior('validateOnChange') + ], ValidateOnChangeBindingBehavior); + return ValidateOnChangeBindingBehavior; + }(ValidateBindingBehaviorBase))); + /** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs or is changed by the user, causing + * a change to the model. + */ + var ValidateOnChangeOrBlurBindingBehavior = exports('ValidateOnChangeOrBlurBindingBehavior', /** @class */ (function (_super) { + __extends(ValidateOnChangeOrBlurBindingBehavior, _super); + function ValidateOnChangeOrBlurBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateOnChangeOrBlurBindingBehavior.prototype.getValidateTrigger = function () { + return validateTrigger.changeOrBlur; + }; + ValidateOnChangeOrBlurBindingBehavior.inject = [TaskQueue]; + ValidateOnChangeOrBlurBindingBehavior = __decorate([ + bindingBehavior('validateOnChangeOrBlur') + ], ValidateOnChangeOrBlurBindingBehavior); + return ValidateOnChangeOrBlurBindingBehavior; + }(ValidateBindingBehaviorBase))); + + /** + * Creates ValidationController instances. + */ + var ValidationControllerFactory = exports('ValidationControllerFactory', /** @class */ (function () { + function ValidationControllerFactory(container) { + this.container = container; + } + ValidationControllerFactory.get = function (container) { + return new ValidationControllerFactory(container); + }; + /** + * Creates a new controller instance. + */ + ValidationControllerFactory.prototype.create = function (validator) { + if (!validator) { + validator = this.container.get(Validator); + } + var propertyParser = this.container.get(PropertyAccessorParser); + return new ValidationController(validator, propertyParser); + }; + /** + * Creates a new controller and registers it in the current element's container so that it's + * available to the validate binding behavior and renderers. + */ + ValidationControllerFactory.prototype.createForCurrentScope = function (validator) { + var controller = this.create(validator); + this.container.registerInstance(ValidationController, controller); + return controller; + }; + return ValidationControllerFactory; + }())); + ValidationControllerFactory['protocol:aurelia:resolver'] = true; + + var ValidationErrorsCustomAttribute = exports('ValidationErrorsCustomAttribute', /** @class */ (function () { + function ValidationErrorsCustomAttribute(boundaryElement, controllerAccessor) { + this.boundaryElement = boundaryElement; + this.controllerAccessor = controllerAccessor; + this.controller = null; + this.errors = []; + this.errorsInternal = []; + } + ValidationErrorsCustomAttribute.inject = function () { + return [DOM.Element, Lazy.of(ValidationController)]; + }; + ValidationErrorsCustomAttribute.prototype.sort = function () { + this.errorsInternal.sort(function (a, b) { + if (a.targets[0] === b.targets[0]) { + return 0; + } + // tslint:disable-next-line:no-bitwise + return a.targets[0].compareDocumentPosition(b.targets[0]) & 2 ? 1 : -1; + }); + }; + ValidationErrorsCustomAttribute.prototype.interestingElements = function (elements) { + var _this = this; + return elements.filter(function (e) { return _this.boundaryElement.contains(e); }); + }; + ValidationErrorsCustomAttribute.prototype.render = function (instruction) { + var _loop_1 = function (result) { + var index = this_1.errorsInternal.findIndex(function (x) { return x.error === result; }); + if (index !== -1) { + this_1.errorsInternal.splice(index, 1); + } + }; + var this_1 = this; + for (var _i = 0, _a = instruction.unrender; _i < _a.length; _i++) { + var result = _a[_i].result; + _loop_1(result); + } + for (var _b = 0, _c = instruction.render; _b < _c.length; _b++) { + var _d = _c[_b], result = _d.result, elements = _d.elements; + if (result.valid) { + continue; + } + var targets = this.interestingElements(elements); + if (targets.length) { + this.errorsInternal.push({ error: result, targets: targets }); + } + } + this.sort(); + this.errors = this.errorsInternal; + }; + ValidationErrorsCustomAttribute.prototype.bind = function () { + if (!this.controller) { + this.controller = this.controllerAccessor(); + } + // this will call render() with the side-effect of updating this.errors + this.controller.addRenderer(this); + }; + ValidationErrorsCustomAttribute.prototype.unbind = function () { + if (this.controller) { + this.controller.removeRenderer(this); + } + }; + __decorate([ + bindable({ defaultBindingMode: bindingMode.oneWay }) + ], ValidationErrorsCustomAttribute.prototype, "controller", void 0); + __decorate([ + bindable({ primaryProperty: true, defaultBindingMode: bindingMode.twoWay }) + ], ValidationErrorsCustomAttribute.prototype, "errors", void 0); + ValidationErrorsCustomAttribute = __decorate([ + customAttribute('validation-errors') + ], ValidationErrorsCustomAttribute); + return ValidationErrorsCustomAttribute; + }())); + + var ValidationRendererCustomAttribute = exports('ValidationRendererCustomAttribute', /** @class */ (function () { + function ValidationRendererCustomAttribute() { + } + ValidationRendererCustomAttribute.prototype.created = function (view) { + this.container = view.container; + }; + ValidationRendererCustomAttribute.prototype.bind = function () { + this.controller = this.container.get(ValidationController); + this.renderer = this.container.get(this.value); + this.controller.addRenderer(this.renderer); + }; + ValidationRendererCustomAttribute.prototype.unbind = function () { + this.controller.removeRenderer(this.renderer); + this.controller = null; + this.renderer = null; + }; + ValidationRendererCustomAttribute = __decorate([ + customAttribute('validation-renderer') + ], ValidationRendererCustomAttribute); + return ValidationRendererCustomAttribute; + }())); + + /** + * Sets, unsets and retrieves rules on an object or constructor function. + */ + var Rules = exports('Rules', /** @class */ (function () { + function Rules() { + } + /** + * Applies the rules to a target. + */ + Rules.set = function (target, rules) { + if (target instanceof Function) { + target = target.prototype; + } + Object.defineProperty(target, Rules.key, { enumerable: false, configurable: false, writable: true, value: rules }); + }; + /** + * Removes rules from a target. + */ + Rules.unset = function (target) { + if (target instanceof Function) { + target = target.prototype; + } + target[Rules.key] = null; + }; + /** + * Retrieves the target's rules. + */ + Rules.get = function (target) { + return target[Rules.key] || null; + }; + /** + * The name of the property that stores the rules. + */ + Rules.key = '__rules__'; + return Rules; + }())); + + // tslint:disable:no-empty + var ExpressionVisitor = /** @class */ (function () { + function ExpressionVisitor() { + } + ExpressionVisitor.prototype.visitChain = function (chain) { + this.visitArgs(chain.expressions); + }; + ExpressionVisitor.prototype.visitBindingBehavior = function (behavior) { + behavior.expression.accept(this); + this.visitArgs(behavior.args); + }; + ExpressionVisitor.prototype.visitValueConverter = function (converter) { + converter.expression.accept(this); + this.visitArgs(converter.args); + }; + ExpressionVisitor.prototype.visitAssign = function (assign) { + assign.target.accept(this); + assign.value.accept(this); + }; + ExpressionVisitor.prototype.visitConditional = function (conditional) { + conditional.condition.accept(this); + conditional.yes.accept(this); + conditional.no.accept(this); + }; + ExpressionVisitor.prototype.visitAccessThis = function (access) { + access.ancestor = access.ancestor; + }; + ExpressionVisitor.prototype.visitAccessScope = function (access) { + access.name = access.name; + }; + ExpressionVisitor.prototype.visitAccessMember = function (access) { + access.object.accept(this); + }; + ExpressionVisitor.prototype.visitAccessKeyed = function (access) { + access.object.accept(this); + access.key.accept(this); + }; + ExpressionVisitor.prototype.visitCallScope = function (call) { + this.visitArgs(call.args); + }; + ExpressionVisitor.prototype.visitCallFunction = function (call) { + call.func.accept(this); + this.visitArgs(call.args); + }; + ExpressionVisitor.prototype.visitCallMember = function (call) { + call.object.accept(this); + this.visitArgs(call.args); + }; + ExpressionVisitor.prototype.visitPrefix = function (prefix) { + prefix.expression.accept(this); + }; + ExpressionVisitor.prototype.visitBinary = function (binary) { + binary.left.accept(this); + binary.right.accept(this); + }; + ExpressionVisitor.prototype.visitLiteralPrimitive = function (literal) { + literal.value = literal.value; + }; + ExpressionVisitor.prototype.visitLiteralArray = function (literal) { + this.visitArgs(literal.elements); + }; + ExpressionVisitor.prototype.visitLiteralObject = function (literal) { + this.visitArgs(literal.values); + }; + ExpressionVisitor.prototype.visitLiteralString = function (literal) { + literal.value = literal.value; + }; + ExpressionVisitor.prototype.visitArgs = function (args) { + for (var i = 0; i < args.length; i++) { + args[i].accept(this); + } + }; + return ExpressionVisitor; + }()); + + var ValidationMessageParser = exports('ValidationMessageParser', /** @class */ (function () { + function ValidationMessageParser(bindinqLanguage) { + this.bindinqLanguage = bindinqLanguage; + this.emptyStringExpression = new LiteralString(''); + this.nullExpression = new LiteralPrimitive(null); + this.undefinedExpression = new LiteralPrimitive(undefined); + this.cache = {}; + } + ValidationMessageParser.prototype.parse = function (message) { + if (this.cache[message] !== undefined) { + return this.cache[message]; + } + var parts = this.bindinqLanguage.parseInterpolation(null, message); + if (parts === null) { + return new LiteralString(message); + } + var expression = new LiteralString(parts[0]); + for (var i = 1; i < parts.length; i += 2) { + expression = new Binary('+', expression, new Binary('+', this.coalesce(parts[i]), new LiteralString(parts[i + 1]))); + } + MessageExpressionValidator.validate(expression, message); + this.cache[message] = expression; + return expression; + }; + ValidationMessageParser.prototype.coalesce = function (part) { + // part === null || part === undefined ? '' : part + return new Conditional(new Binary('||', new Binary('===', part, this.nullExpression), new Binary('===', part, this.undefinedExpression)), this.emptyStringExpression, new CallMember(part, 'toString', [])); + }; + ValidationMessageParser.inject = [BindingLanguage]; + return ValidationMessageParser; + }())); + var MessageExpressionValidator = exports('MessageExpressionValidator', /** @class */ (function (_super) { + __extends(MessageExpressionValidator, _super); + function MessageExpressionValidator(originalMessage) { + var _this = _super.call(this) || this; + _this.originalMessage = originalMessage; + return _this; + } + MessageExpressionValidator.validate = function (expression, originalMessage) { + var visitor = new MessageExpressionValidator(originalMessage); + expression.accept(visitor); + }; + MessageExpressionValidator.prototype.visitAccessScope = function (access) { + if (access.ancestor !== 0) { + throw new Error('$parent is not permitted in validation message expressions.'); + } + if (['displayName', 'propertyName', 'value', 'object', 'config', 'getDisplayName'].indexOf(access.name) !== -1) { + getLogger('aurelia-validation') + // tslint:disable-next-line:max-line-length + .warn("Did you mean to use \"$" + access.name + "\" instead of \"" + access.name + "\" in this validation message template: \"" + this.originalMessage + "\"?"); + } + }; + return MessageExpressionValidator; + }(ExpressionVisitor))); + + /** + * Dictionary of validation messages. [messageKey]: messageExpression + */ + var validationMessages = exports('validationMessages', { + /** + * The default validation message. Used with rules that have no standard message. + */ + default: "${$displayName} is invalid.", + required: "${$displayName} is required.", + matches: "${$displayName} is not correctly formatted.", + email: "${$displayName} is not a valid email.", + minLength: "${$displayName} must be at least ${$config.length} character${$config.length === 1 ? '' : 's'}.", + maxLength: "${$displayName} cannot be longer than ${$config.length} character${$config.length === 1 ? '' : 's'}.", + minItems: "${$displayName} must contain at least ${$config.count} item${$config.count === 1 ? '' : 's'}.", + maxItems: "${$displayName} cannot contain more than ${$config.count} item${$config.count === 1 ? '' : 's'}.", + min: "${$displayName} must be at least ${$config.constraint}.", + max: "${$displayName} must be at most ${$config.constraint}.", + range: "${$displayName} must be between or equal to ${$config.min} and ${$config.max}.", + between: "${$displayName} must be between but not equal to ${$config.min} and ${$config.max}.", + equals: "${$displayName} must be ${$config.expectedValue}.", + }); + /** + * Retrieves validation messages and property display names. + */ + var ValidationMessageProvider = exports('ValidationMessageProvider', /** @class */ (function () { + function ValidationMessageProvider(parser) { + this.parser = parser; + } + /** + * Returns a message binding expression that corresponds to the key. + * @param key The message key. + */ + ValidationMessageProvider.prototype.getMessage = function (key) { + var message; + if (key in validationMessages) { + message = validationMessages[key]; + } + else { + message = validationMessages['default']; + } + return this.parser.parse(message); + }; + /** + * Formulates a property display name using the property name and the configured + * displayName (if provided). + * Override this with your own custom logic. + * @param propertyName The property name. + */ + ValidationMessageProvider.prototype.getDisplayName = function (propertyName, displayName) { + if (displayName !== null && displayName !== undefined) { + return (displayName instanceof Function) ? displayName() : displayName; + } + // split on upper-case letters. + var words = propertyName.toString().split(/(?=[A-Z])/).join(' '); + // capitalize first letter. + return words.charAt(0).toUpperCase() + words.slice(1); + }; + ValidationMessageProvider.inject = [ValidationMessageParser]; + return ValidationMessageProvider; + }())); + + /** + * Validates. + * Responsible for validating objects and properties. + */ + var StandardValidator = exports('StandardValidator', /** @class */ (function (_super) { + __extends(StandardValidator, _super); + function StandardValidator(messageProvider, resources) { + var _this = _super.call(this) || this; + _this.messageProvider = messageProvider; + _this.lookupFunctions = resources.lookupFunctions; + _this.getDisplayName = messageProvider.getDisplayName.bind(messageProvider); + return _this; + } + /** + * Validates the specified property. + * @param object The object to validate. + * @param propertyName The name of the property to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + StandardValidator.prototype.validateProperty = function (object, propertyName, rules) { + return this.validate(object, propertyName, rules || null); + }; + /** + * Validates all rules for specified object and it's properties. + * @param object The object to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + StandardValidator.prototype.validateObject = function (object, rules) { + return this.validate(object, null, rules || null); + }; + /** + * Determines whether a rule exists in a set of rules. + * @param rules The rules to search. + * @parem rule The rule to find. + */ + StandardValidator.prototype.ruleExists = function (rules, rule) { + var i = rules.length; + while (i--) { + if (rules[i].indexOf(rule) !== -1) { + return true; + } + } + return false; + }; + StandardValidator.prototype.getMessage = function (rule, object, value) { + var expression = rule.message || this.messageProvider.getMessage(rule.messageKey); + // tslint:disable-next-line:prefer-const + var _a = rule.property, propertyName = _a.name, displayName = _a.displayName; + if (propertyName !== null) { + displayName = this.messageProvider.getDisplayName(propertyName, displayName); + } + var overrideContext = { + $displayName: displayName, + $propertyName: propertyName, + $value: value, + $object: object, + $config: rule.config, + // returns the name of a given property, given just the property name (irrespective of the property's displayName) + // split on capital letters, first letter ensured to be capitalized + $getDisplayName: this.getDisplayName + }; + return expression.evaluate({ bindingContext: object, overrideContext: overrideContext }, this.lookupFunctions); + }; + StandardValidator.prototype.validateRuleSequence = function (object, propertyName, ruleSequence, sequence, results) { + var _this = this; + // are we validating all properties or a single property? + var validateAllProperties = propertyName === null || propertyName === undefined; + var rules = ruleSequence[sequence]; + var allValid = true; + // validate each rule. + var promises = []; + var _loop_1 = function (i) { + var rule = rules[i]; + // is the rule related to the property we're validating. + // tslint:disable-next-line:triple-equals | Use loose equality for property keys + if (!validateAllProperties && rule.property.name != propertyName) { + return "continue"; + } + // is this a conditional rule? is the condition met? + if (rule.when && !rule.when(object)) { + return "continue"; + } + // validate. + var value = rule.property.name === null ? object : object[rule.property.name]; + var promiseOrBoolean = rule.condition(value, object); + if (!(promiseOrBoolean instanceof Promise)) { + promiseOrBoolean = Promise.resolve(promiseOrBoolean); + } + promises.push(promiseOrBoolean.then(function (valid) { + var message = valid ? null : _this.getMessage(rule, object, value); + results.push(new ValidateResult(rule, object, rule.property.name, valid, message)); + allValid = allValid && valid; + return valid; + })); + }; + for (var i = 0; i < rules.length; i++) { + _loop_1(i); + } + return Promise.all(promises) + .then(function () { + sequence++; + if (allValid && sequence < ruleSequence.length) { + return _this.validateRuleSequence(object, propertyName, ruleSequence, sequence, results); + } + return results; + }); + }; + StandardValidator.prototype.validate = function (object, propertyName, rules) { + // rules specified? + if (!rules) { + // no. attempt to locate the rules. + rules = Rules.get(object); + } + // any rules? + if (!rules || rules.length === 0) { + return Promise.resolve([]); + } + return this.validateRuleSequence(object, propertyName, rules, 0, []); + }; + StandardValidator.inject = [ValidationMessageProvider, ViewResources]; + return StandardValidator; + }(Validator))); + + /** + * Part of the fluent rule API. Enables customizing property rules. + */ + var FluentRuleCustomizer = exports('FluentRuleCustomizer', /** @class */ (function () { + function FluentRuleCustomizer(property, condition, config, fluentEnsure, fluentRules, parsers) { + if (config === void 0) { config = {}; } + this.fluentEnsure = fluentEnsure; + this.fluentRules = fluentRules; + this.parsers = parsers; + this.rule = { + property: property, + condition: condition, + config: config, + when: null, + messageKey: 'default', + message: null, + sequence: fluentRules.sequence + }; + this.fluentEnsure._addRule(this.rule); + } + /** + * Validate subsequent rules after previously declared rules have + * been validated successfully. Use to postpone validation of costly + * rules until less expensive rules pass validation. + */ + FluentRuleCustomizer.prototype.then = function () { + this.fluentRules.sequence++; + return this; + }; + /** + * Specifies the key to use when looking up the rule's validation message. + */ + FluentRuleCustomizer.prototype.withMessageKey = function (key) { + this.rule.messageKey = key; + this.rule.message = null; + return this; + }; + /** + * Specifies rule's validation message. + */ + FluentRuleCustomizer.prototype.withMessage = function (message) { + this.rule.messageKey = 'custom'; + this.rule.message = this.parsers.message.parse(message); + return this; + }; + /** + * Specifies a condition that must be met before attempting to validate the rule. + * @param condition A function that accepts the object as a parameter and returns true + * or false whether the rule should be evaluated. + */ + FluentRuleCustomizer.prototype.when = function (condition) { + this.rule.when = condition; + return this; + }; + /** + * Tags the rule instance, enabling the rule to be found easily + * using ValidationRules.taggedRules(rules, tag) + */ + FluentRuleCustomizer.prototype.tag = function (tag) { + this.rule.tag = tag; + return this; + }; + ///// FluentEnsure APIs ///// + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + FluentRuleCustomizer.prototype.ensure = function (subject) { + return this.fluentEnsure.ensure(subject); + }; + /** + * Targets an object with validation rules. + */ + FluentRuleCustomizer.prototype.ensureObject = function () { + return this.fluentEnsure.ensureObject(); + }; + Object.defineProperty(FluentRuleCustomizer.prototype, "rules", { + /** + * Rules that have been defined using the fluent API. + */ + get: function () { + return this.fluentEnsure.rules; + }, + enumerable: true, + configurable: true + }); + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + FluentRuleCustomizer.prototype.on = function (target) { + return this.fluentEnsure.on(target); + }; + ///////// FluentRules APIs ///////// + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + FluentRuleCustomizer.prototype.satisfies = function (condition, config) { + return this.fluentRules.satisfies(condition, config); + }; + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + FluentRuleCustomizer.prototype.satisfiesRule = function (name) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + var _a; + return (_a = this.fluentRules).satisfiesRule.apply(_a, [name].concat(args)); + }; + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + FluentRuleCustomizer.prototype.required = function () { + return this.fluentRules.required(); + }; + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.matches = function (regex) { + return this.fluentRules.matches(regex); + }; + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.email = function () { + return this.fluentRules.email(); + }; + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.minLength = function (length) { + return this.fluentRules.minLength(length); + }; + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.maxLength = function (length) { + return this.fluentRules.maxLength(length); + }; + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.minItems = function (count) { + return this.fluentRules.minItems(count); + }; + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.maxItems = function (count) { + return this.fluentRules.maxItems(count); + }; + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.min = function (value) { + return this.fluentRules.min(value); + }; + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.max = function (value) { + return this.fluentRules.max(value); + }; + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.range = function (min, max) { + return this.fluentRules.range(min, max); + }; + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.between = function (min, max) { + return this.fluentRules.between(min, max); + }; + /** + * Applies the "equals" validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.equals = function (expectedValue) { + return this.fluentRules.equals(expectedValue); + }; + return FluentRuleCustomizer; + }())); + /** + * Part of the fluent rule API. Enables applying rules to properties and objects. + */ + var FluentRules = exports('FluentRules', /** @class */ (function () { + function FluentRules(fluentEnsure, parsers, property) { + this.fluentEnsure = fluentEnsure; + this.parsers = parsers; + this.property = property; + /** + * Current rule sequence number. Used to postpone evaluation of rules until rules + * with lower sequence number have successfully validated. The "then" fluent API method + * manages this property, there's usually no need to set it directly. + */ + this.sequence = 0; + } + /** + * Sets the display name of the ensured property. + */ + FluentRules.prototype.displayName = function (name) { + this.property.displayName = name; + return this; + }; + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + FluentRules.prototype.satisfies = function (condition, config) { + return new FluentRuleCustomizer(this.property, condition, config, this.fluentEnsure, this, this.parsers); + }; + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + FluentRules.prototype.satisfiesRule = function (name) { + var _this = this; + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + var rule = FluentRules.customRules[name]; + if (!rule) { + // standard rule? + rule = this[name]; + if (rule instanceof Function) { + return rule.call.apply(rule, [this].concat(args)); + } + throw new Error("Rule with name \"" + name + "\" does not exist."); + } + var config = rule.argsToConfig ? rule.argsToConfig.apply(rule, args) : undefined; + return this.satisfies(function (value, obj) { + var _a; + return (_a = rule.condition).call.apply(_a, [_this, value, obj].concat(args)); + }, config) + .withMessageKey(name); + }; + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + FluentRules.prototype.required = function () { + return this.satisfies(function (value) { + return value !== null + && value !== undefined + && !(isString(value) && !/\S/.test(value)); + }).withMessageKey('required'); + }; + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.matches = function (regex) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length === 0 || regex.test(value); }) + .withMessageKey('matches'); + }; + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.email = function () { + // regex from https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address + /* tslint:disable:max-line-length */ + return this.matches(/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/) + /* tslint:enable:max-line-length */ + .withMessageKey('email'); + }; + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.minLength = function (length) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length === 0 || value.length >= length; }, { length: length }) + .withMessageKey('minLength'); + }; + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.maxLength = function (length) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length === 0 || value.length <= length; }, { length: length }) + .withMessageKey('maxLength'); + }; + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRules.prototype.minItems = function (count) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length >= count; }, { count: count }) + .withMessageKey('minItems'); + }; + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRules.prototype.maxItems = function (count) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length <= count; }, { count: count }) + .withMessageKey('maxItems'); + }; + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRules.prototype.min = function (constraint) { + return this.satisfies(function (value) { return value === null || value === undefined || value >= constraint; }, { constraint: constraint }) + .withMessageKey('min'); + }; + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRules.prototype.max = function (constraint) { + return this.satisfies(function (value) { return value === null || value === undefined || value <= constraint; }, { constraint: constraint }) + .withMessageKey('max'); + }; + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRules.prototype.range = function (min, max) { + return this.satisfies(function (value) { return value === null || value === undefined || (value >= min && value <= max); }, { min: min, max: max }) + .withMessageKey('range'); + }; + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRules.prototype.between = function (min, max) { + return this.satisfies(function (value) { return value === null || value === undefined || (value > min && value < max); }, { min: min, max: max }) + .withMessageKey('between'); + }; + /** + * Applies the "equals" validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRules.prototype.equals = function (expectedValue) { + return this.satisfies(function (value) { return value === null || value === undefined || value === '' || value === expectedValue; }, { expectedValue: expectedValue }) + .withMessageKey('equals'); + }; + FluentRules.customRules = {}; + return FluentRules; + }())); + /** + * Part of the fluent rule API. Enables targeting properties and objects with rules. + */ + var FluentEnsure = exports('FluentEnsure', /** @class */ (function () { + function FluentEnsure(parsers) { + this.parsers = parsers; + /** + * Rules that have been defined using the fluent API. + */ + this.rules = []; + } + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor + * function. + */ + FluentEnsure.prototype.ensure = function (property) { + this.assertInitialized(); + var name = this.parsers.property.parse(property); + var fluentRules = new FluentRules(this, this.parsers, { name: name, displayName: null }); + return this.mergeRules(fluentRules, name); + }; + /** + * Targets an object with validation rules. + */ + FluentEnsure.prototype.ensureObject = function () { + this.assertInitialized(); + var fluentRules = new FluentRules(this, this.parsers, { name: null, displayName: null }); + return this.mergeRules(fluentRules, null); + }; + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + FluentEnsure.prototype.on = function (target) { + Rules.set(target, this.rules); + return this; + }; + /** + * Adds a rule definition to the sequenced ruleset. + * @internal + */ + FluentEnsure.prototype._addRule = function (rule) { + while (this.rules.length < rule.sequence + 1) { + this.rules.push([]); + } + this.rules[rule.sequence].push(rule); + }; + FluentEnsure.prototype.assertInitialized = function () { + if (this.parsers) { + return; + } + throw new Error("Did you forget to add \".plugin('aurelia-validation')\" to your main.js?"); + }; + FluentEnsure.prototype.mergeRules = function (fluentRules, propertyName) { + // tslint:disable-next-line:triple-equals | Use loose equality for property keys + var existingRules = this.rules.find(function (r) { return r.length > 0 && r[0].property.name == propertyName; }); + if (existingRules) { + var rule = existingRules[existingRules.length - 1]; + fluentRules.sequence = rule.sequence; + if (rule.property.displayName !== null) { + fluentRules = fluentRules.displayName(rule.property.displayName); + } + } + return fluentRules; + }; + return FluentEnsure; + }())); + /** + * Fluent rule definition API. + */ + var ValidationRules = exports('ValidationRules', /** @class */ (function () { + function ValidationRules() { + } + ValidationRules.initialize = function (messageParser, propertyParser) { + this.parsers = { + message: messageParser, + property: propertyParser + }; + }; + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + ValidationRules.ensure = function (property) { + return new FluentEnsure(ValidationRules.parsers).ensure(property); + }; + /** + * Targets an object with validation rules. + */ + ValidationRules.ensureObject = function () { + return new FluentEnsure(ValidationRules.parsers).ensureObject(); + }; + /** + * Defines a custom rule. + * @param name The name of the custom rule. Also serves as the message key. + * @param condition The rule function. + * @param message The message expression + * @param argsToConfig A function that maps the rule's arguments to a "config" + * object that can be used when evaluating the message expression. + */ + ValidationRules.customRule = function (name, condition, message, argsToConfig) { + validationMessages[name] = message; + FluentRules.customRules[name] = { condition: condition, argsToConfig: argsToConfig }; + }; + /** + * Returns rules with the matching tag. + * @param rules The rules to search. + * @param tag The tag to search for. + */ + ValidationRules.taggedRules = function (rules, tag) { + return rules.map(function (x) { return x.filter(function (r) { return r.tag === tag; }); }); + }; + /** + * Returns rules that have no tag. + * @param rules The rules to search. + */ + ValidationRules.untaggedRules = function (rules) { + return rules.map(function (x) { return x.filter(function (r) { return r.tag === undefined; }); }); + }; + /** + * Removes the rules from a class or object. + * @param target A class or object. + */ + ValidationRules.off = function (target) { + Rules.unset(target); + }; + return ValidationRules; + }())); + + // Exports + /** + * Aurelia Validation Configuration API + */ + var AureliaValidationConfiguration = exports('AureliaValidationConfiguration', /** @class */ (function () { + function AureliaValidationConfiguration() { + this.validatorType = StandardValidator; + } + /** + * Use a custom Validator implementation. + */ + AureliaValidationConfiguration.prototype.customValidator = function (type) { + this.validatorType = type; + }; + /** + * Applies the configuration. + */ + AureliaValidationConfiguration.prototype.apply = function (container) { + var validator = container.get(this.validatorType); + container.registerInstance(Validator, validator); + }; + return AureliaValidationConfiguration; + }())); + /** + * Configures the plugin. + */ + function configure( + // tslint:disable-next-line:ban-types + frameworkConfig, callback) { + // the fluent rule definition API needs the parser to translate messages + // to interpolation expressions. + var messageParser = frameworkConfig.container.get(ValidationMessageParser); + var propertyParser = frameworkConfig.container.get(PropertyAccessorParser); + ValidationRules.initialize(messageParser, propertyParser); + // configure... + var config = new AureliaValidationConfiguration(); + if (callback instanceof Function) { + callback(config); + } + config.apply(frameworkConfig.container); + // globalize the behaviors. + if (frameworkConfig.globalResources) { + frameworkConfig.globalResources(ValidateBindingBehavior, ValidateManuallyBindingBehavior, ValidateOnBlurBindingBehavior, ValidateOnChangeBindingBehavior, ValidateOnChangeOrBlurBindingBehavior, ValidationErrorsCustomAttribute, ValidationRendererCustomAttribute); + } + } + + } + }; +}); diff --git a/dist/umd-es2015/aurelia-validation.js b/dist/umd-es2015/aurelia-validation.js new file mode 100644 index 00000000..49165a19 --- /dev/null +++ b/dist/umd-es2015/aurelia-validation.js @@ -0,0 +1,1755 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('aurelia-pal'), require('aurelia-binding'), require('aurelia-dependency-injection'), require('aurelia-task-queue'), require('aurelia-templating'), require('aurelia-logging')) : + typeof define === 'function' && define.amd ? define(['exports', 'aurelia-pal', 'aurelia-binding', 'aurelia-dependency-injection', 'aurelia-task-queue', 'aurelia-templating', 'aurelia-logging'], factory) : + (factory((global.au = global.au || {}, global.au.validation = {}),global.au,global.au,global.au,global.au,global.au,global.au.LogManager)); +}(this, (function (exports,aureliaPal,aureliaBinding,aureliaDependencyInjection,aureliaTaskQueue,aureliaTemplating,LogManager) { 'use strict'; + + /** + * Gets the DOM element associated with the data-binding. Most of the time it's + * the binding.target but sometimes binding.target is an aurelia custom element, + * or custom attribute which is a javascript "class" instance, so we need to use + * the controller's container to retrieve the actual DOM element. + */ + function getTargetDOMElement(binding, view) { + const target = binding.target; + // DOM element + if (target instanceof Element) { + return target; + } + // custom element or custom attribute + // tslint:disable-next-line:prefer-const + for (let i = 0, ii = view.controllers.length; i < ii; i++) { + const controller = view.controllers[i]; + if (controller.viewModel === target) { + const element = controller.container.get(aureliaPal.DOM.Element); + if (element) { + return element; + } + throw new Error(`Unable to locate target element for "${binding.sourceExpression}".`); + } + } + throw new Error(`Unable to locate target element for "${binding.sourceExpression}".`); + } + + function getObject(expression, objectExpression, source) { + const value = objectExpression.evaluate(source, null); + if (value === null || value === undefined || value instanceof Object) { + return value; + } + // tslint:disable-next-line:max-line-length + throw new Error(`The '${objectExpression}' part of '${expression}' evaluates to ${value} instead of an object, null or undefined.`); + } + /** + * Retrieves the object and property name for the specified expression. + * @param expression The expression + * @param source The scope + */ + function getPropertyInfo(expression, source) { + const originalExpression = expression; + while (expression instanceof aureliaBinding.BindingBehavior || expression instanceof aureliaBinding.ValueConverter) { + expression = expression.expression; + } + let object; + let propertyName; + if (expression instanceof aureliaBinding.AccessScope) { + object = aureliaBinding.getContextFor(expression.name, source, expression.ancestor); + propertyName = expression.name; + } + else if (expression instanceof aureliaBinding.AccessMember) { + object = getObject(originalExpression, expression.object, source); + propertyName = expression.name; + } + else if (expression instanceof aureliaBinding.AccessKeyed) { + object = getObject(originalExpression, expression.object, source); + propertyName = expression.key.evaluate(source); + } + else { + throw new Error(`Expression '${originalExpression}' is not compatible with the validate binding-behavior.`); + } + if (object === null || object === undefined) { + return null; + } + return { object, propertyName }; + } + + function isString(value) { + return Object.prototype.toString.call(value) === '[object String]'; + } + function isNumber(value) { + return Object.prototype.toString.call(value) === '[object Number]'; + } + + class PropertyAccessorParser { + constructor(parser) { + this.parser = parser; + } + parse(property) { + if (isString(property) || isNumber(property)) { + return property; + } + const accessorText = getAccessorExpression(property.toString()); + const accessor = this.parser.parse(accessorText); + if (accessor instanceof aureliaBinding.AccessScope + || accessor instanceof aureliaBinding.AccessMember && accessor.object instanceof aureliaBinding.AccessScope) { + return accessor.name; + } + throw new Error(`Invalid property expression: "${accessor}"`); + } + } + PropertyAccessorParser.inject = [aureliaBinding.Parser]; + function getAccessorExpression(fn) { + /* tslint:disable:max-line-length */ + const classic = /^function\s*\([$_\w\d]+\)\s*\{(?:\s*"use strict";)?\s*(?:[$_\w\d.['"\]+;]+)?\s*return\s+[$_\w\d]+\.([$_\w\d]+)\s*;?\s*\}$/; + /* tslint:enable:max-line-length */ + const arrow = /^\(?[$_\w\d]+\)?\s*=>\s*[$_\w\d]+\.([$_\w\d]+)$/; + const match = classic.exec(fn) || arrow.exec(fn); + if (match === null) { + throw new Error(`Unable to parse accessor function:\n${fn}`); + } + return match[1]; + } + + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use + this file except in compliance with the License. You may obtain a copy of the + License at http://www.apache.org/licenses/LICENSE-2.0 + + THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED + WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, + MERCHANTABLITY OR NON-INFRINGEMENT. + + See the Apache Version 2.0 License for specific language governing permissions + and limitations under the License. + ***************************************************************************** */ + + function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; + } + + /** + * Validation triggers. + */ + (function (validateTrigger) { + /** + * Manual validation. Use the controller's `validate()` and `reset()` methods + * to validate all bindings. + */ + validateTrigger[validateTrigger["manual"] = 0] = "manual"; + /** + * Validate the binding when the binding's target element fires a DOM "blur" event. + */ + validateTrigger[validateTrigger["blur"] = 1] = "blur"; + /** + * Validate the binding when it updates the model due to a change in the view. + */ + validateTrigger[validateTrigger["change"] = 2] = "change"; + /** + * Validate the binding when the binding's target element fires a DOM "blur" event and + * when it updates the model due to a change in the view. + */ + validateTrigger[validateTrigger["changeOrBlur"] = 3] = "changeOrBlur"; + })(exports.validateTrigger || (exports.validateTrigger = {})); + + /** + * Validates objects and properties. + */ + class Validator { + } + + /** + * The result of validating an individual validation rule. + */ + class ValidateResult { + /** + * @param rule The rule associated with the result. Validator implementation specific. + * @param object The object that was validated. + * @param propertyName The name of the property that was validated. + * @param error The error, if the result is a validation error. + */ + constructor(rule, object, propertyName, valid, message = null) { + this.rule = rule; + this.object = object; + this.propertyName = propertyName; + this.valid = valid; + this.message = message; + this.id = ValidateResult.nextId++; + } + toString() { + return this.valid ? 'Valid.' : this.message; + } + } + ValidateResult.nextId = 0; + + class ValidateEvent { + constructor( + /** + * The type of validate event. Either "validate" or "reset". + */ + type, + /** + * The controller's current array of errors. For an array containing both + * failed rules and passed rules, use the "results" property. + */ + errors, + /** + * The controller's current array of validate results. This + * includes both passed rules and failed rules. For an array of only failed rules, + * use the "errors" property. + */ + results, + /** + * The instruction passed to the "validate" or "reset" event. Will be null when + * the controller's validate/reset method was called with no instruction argument. + */ + instruction, + /** + * In events with type === "validate", this property will contain the result + * of validating the instruction (see "instruction" property). Use the controllerValidateResult + * to access the validate results specific to the call to "validate" + * (as opposed to using the "results" and "errors" properties to access the controller's entire + * set of results/errors). + */ + controllerValidateResult) { + this.type = type; + this.errors = errors; + this.results = results; + this.instruction = instruction; + this.controllerValidateResult = controllerValidateResult; + } + } + + /** + * Orchestrates validation. + * Manages a set of bindings, renderers and objects. + * Exposes the current list of validation results for binding purposes. + */ + class ValidationController { + constructor(validator, propertyParser) { + this.validator = validator; + this.propertyParser = propertyParser; + // Registered bindings (via the validate binding behavior) + this.bindings = new Map(); + // Renderers that have been added to the controller instance. + this.renderers = []; + /** + * Validation results that have been rendered by the controller. + */ + this.results = []; + /** + * Validation errors that have been rendered by the controller. + */ + this.errors = []; + /** + * Whether the controller is currently validating. + */ + this.validating = false; + // Elements related to validation results that have been rendered. + this.elements = new Map(); + // Objects that have been added to the controller instance (entity-style validation). + this.objects = new Map(); + /** + * The trigger that will invoke automatic validation of a property used in a binding. + */ + this.validateTrigger = exports.validateTrigger.blur; + // Promise that resolves when validation has completed. + this.finishValidating = Promise.resolve(); + this.eventCallbacks = []; + } + /** + * Subscribe to controller validate and reset events. These events occur when the + * controller's "validate"" and "reset" methods are called. + * @param callback The callback to be invoked when the controller validates or resets. + */ + subscribe(callback) { + this.eventCallbacks.push(callback); + return { + dispose: () => { + const index = this.eventCallbacks.indexOf(callback); + if (index === -1) { + return; + } + this.eventCallbacks.splice(index, 1); + } + }; + } + /** + * Adds an object to the set of objects that should be validated when validate is called. + * @param object The object. + * @param rules Optional. The rules. If rules aren't supplied the Validator implementation will lookup the rules. + */ + addObject(object, rules) { + this.objects.set(object, rules); + } + /** + * Removes an object from the set of objects that should be validated when validate is called. + * @param object The object. + */ + removeObject(object) { + this.objects.delete(object); + this.processResultDelta('reset', this.results.filter(result => result.object === object), []); + } + /** + * Adds and renders an error. + */ + addError(message, object, propertyName = null) { + let resolvedPropertyName; + if (propertyName === null) { + resolvedPropertyName = propertyName; + } + else { + resolvedPropertyName = this.propertyParser.parse(propertyName); + } + const result = new ValidateResult({ __manuallyAdded__: true }, object, resolvedPropertyName, false, message); + this.processResultDelta('validate', [], [result]); + return result; + } + /** + * Removes and unrenders an error. + */ + removeError(result) { + if (this.results.indexOf(result) !== -1) { + this.processResultDelta('reset', [result], []); + } + } + /** + * Adds a renderer. + * @param renderer The renderer. + */ + addRenderer(renderer) { + this.renderers.push(renderer); + renderer.render({ + kind: 'validate', + render: this.results.map(result => ({ result, elements: this.elements.get(result) })), + unrender: [] + }); + } + /** + * Removes a renderer. + * @param renderer The renderer. + */ + removeRenderer(renderer) { + this.renderers.splice(this.renderers.indexOf(renderer), 1); + renderer.render({ + kind: 'reset', + render: [], + unrender: this.results.map(result => ({ result, elements: this.elements.get(result) })) + }); + } + /** + * Registers a binding with the controller. + * @param binding The binding instance. + * @param target The DOM element. + * @param rules (optional) rules associated with the binding. Validator implementation specific. + */ + registerBinding(binding, target, rules) { + this.bindings.set(binding, { target, rules, propertyInfo: null }); + } + /** + * Unregisters a binding with the controller. + * @param binding The binding instance. + */ + unregisterBinding(binding) { + this.resetBinding(binding); + this.bindings.delete(binding); + } + /** + * Interprets the instruction and returns a predicate that will identify + * relevant results in the list of rendered validation results. + */ + getInstructionPredicate(instruction) { + if (instruction) { + const { object, propertyName, rules } = instruction; + let predicate; + if (instruction.propertyName) { + predicate = x => x.object === object && x.propertyName === propertyName; + } + else { + predicate = x => x.object === object; + } + if (rules) { + return x => predicate(x) && this.validator.ruleExists(rules, x.rule); + } + return predicate; + } + else { + return () => true; + } + } + /** + * Validates and renders results. + * @param instruction Optional. Instructions on what to validate. If undefined, all + * objects and bindings will be validated. + */ + validate(instruction) { + // Get a function that will process the validation instruction. + let execute; + if (instruction) { + // tslint:disable-next-line:prefer-const + let { object, propertyName, rules } = instruction; + // if rules were not specified, check the object map. + rules = rules || this.objects.get(object); + // property specified? + if (instruction.propertyName === undefined) { + // validate the specified object. + execute = () => this.validator.validateObject(object, rules); + } + else { + // validate the specified property. + execute = () => this.validator.validateProperty(object, propertyName, rules); + } + } + else { + // validate all objects and bindings. + execute = () => { + const promises = []; + for (const [object, rules] of Array.from(this.objects)) { + promises.push(this.validator.validateObject(object, rules)); + } + for (const [binding, { rules }] of Array.from(this.bindings)) { + const propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (!propertyInfo || this.objects.has(propertyInfo.object)) { + continue; + } + promises.push(this.validator.validateProperty(propertyInfo.object, propertyInfo.propertyName, rules)); + } + return Promise.all(promises).then(resultSets => resultSets.reduce((a, b) => a.concat(b), [])); + }; + } + // Wait for any existing validation to finish, execute the instruction, render the results. + this.validating = true; + const returnPromise = this.finishValidating + .then(execute) + .then((newResults) => { + const predicate = this.getInstructionPredicate(instruction); + const oldResults = this.results.filter(predicate); + this.processResultDelta('validate', oldResults, newResults); + if (returnPromise === this.finishValidating) { + this.validating = false; + } + const result = { + instruction, + valid: newResults.find(x => !x.valid) === undefined, + results: newResults + }; + this.invokeCallbacks(instruction, result); + return result; + }) + .catch(exception => { + // recover, to enable subsequent calls to validate() + this.validating = false; + this.finishValidating = Promise.resolve(); + return Promise.reject(exception); + }); + this.finishValidating = returnPromise; + return returnPromise; + } + /** + * Resets any rendered validation results (unrenders). + * @param instruction Optional. Instructions on what to reset. If unspecified all rendered results + * will be unrendered. + */ + reset(instruction) { + const predicate = this.getInstructionPredicate(instruction); + const oldResults = this.results.filter(predicate); + this.processResultDelta('reset', oldResults, []); + this.invokeCallbacks(instruction, null); + } + /** + * Gets the elements associated with an object and propertyName (if any). + */ + getAssociatedElements({ object, propertyName }) { + const elements = []; + for (const [binding, { target }] of Array.from(this.bindings)) { + const propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (propertyInfo && propertyInfo.object === object && propertyInfo.propertyName === propertyName) { + elements.push(target); + } + } + return elements; + } + processResultDelta(kind, oldResults, newResults) { + // prepare the instruction. + const instruction = { + kind, + render: [], + unrender: [] + }; + // create a shallow copy of newResults so we can mutate it without causing side-effects. + newResults = newResults.slice(0); + // create unrender instructions from the old results. + for (const oldResult of oldResults) { + // get the elements associated with the old result. + const elements = this.elements.get(oldResult); + // remove the old result from the element map. + this.elements.delete(oldResult); + // create the unrender instruction. + instruction.unrender.push({ result: oldResult, elements }); + // determine if there's a corresponding new result for the old result we are unrendering. + const newResultIndex = newResults.findIndex(x => x.rule === oldResult.rule && x.object === oldResult.object && x.propertyName === oldResult.propertyName); + if (newResultIndex === -1) { + // no corresponding new result... simple remove. + this.results.splice(this.results.indexOf(oldResult), 1); + if (!oldResult.valid) { + this.errors.splice(this.errors.indexOf(oldResult), 1); + } + } + else { + // there is a corresponding new result... + const newResult = newResults.splice(newResultIndex, 1)[0]; + // get the elements that are associated with the new result. + const elements = this.getAssociatedElements(newResult); + this.elements.set(newResult, elements); + // create a render instruction for the new result. + instruction.render.push({ result: newResult, elements }); + // do an in-place replacement of the old result with the new result. + // this ensures any repeats bound to this.results will not thrash. + this.results.splice(this.results.indexOf(oldResult), 1, newResult); + if (!oldResult.valid && newResult.valid) { + this.errors.splice(this.errors.indexOf(oldResult), 1); + } + else if (!oldResult.valid && !newResult.valid) { + this.errors.splice(this.errors.indexOf(oldResult), 1, newResult); + } + else if (!newResult.valid) { + this.errors.push(newResult); + } + } + } + // create render instructions from the remaining new results. + for (const result of newResults) { + const elements = this.getAssociatedElements(result); + instruction.render.push({ result, elements }); + this.elements.set(result, elements); + this.results.push(result); + if (!result.valid) { + this.errors.push(result); + } + } + // render. + for (const renderer of this.renderers) { + renderer.render(instruction); + } + } + /** + * Validates the property associated with a binding. + */ + validateBinding(binding) { + if (!binding.isBound) { + return; + } + const propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + let rules; + const registeredBinding = this.bindings.get(binding); + if (registeredBinding) { + rules = registeredBinding.rules; + registeredBinding.propertyInfo = propertyInfo; + } + if (!propertyInfo) { + return; + } + const { object, propertyName } = propertyInfo; + this.validate({ object, propertyName, rules }); + } + /** + * Resets the results for a property associated with a binding. + */ + resetBinding(binding) { + const registeredBinding = this.bindings.get(binding); + let propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (!propertyInfo && registeredBinding) { + propertyInfo = registeredBinding.propertyInfo; + } + if (registeredBinding) { + registeredBinding.propertyInfo = null; + } + if (!propertyInfo) { + return; + } + const { object, propertyName } = propertyInfo; + this.reset({ object, propertyName }); + } + /** + * Changes the controller's validateTrigger. + * @param newTrigger The new validateTrigger + */ + changeTrigger(newTrigger) { + this.validateTrigger = newTrigger; + const bindings = Array.from(this.bindings.keys()); + for (const binding of bindings) { + const source = binding.source; + binding.unbind(); + binding.bind(source); + } + } + /** + * Revalidates the controller's current set of errors. + */ + revalidateErrors() { + for (const { object, propertyName, rule } of this.errors) { + if (rule.__manuallyAdded__) { + continue; + } + const rules = [[rule]]; + this.validate({ object, propertyName, rules }); + } + } + invokeCallbacks(instruction, result) { + if (this.eventCallbacks.length === 0) { + return; + } + const event = new ValidateEvent(result ? 'validate' : 'reset', this.errors, this.results, instruction || null, result); + for (let i = 0; i < this.eventCallbacks.length; i++) { + this.eventCallbacks[i](event); + } + } + } + ValidationController.inject = [Validator, PropertyAccessorParser]; + + /** + * Binding behavior. Indicates the bound property should be validated. + */ + class ValidateBindingBehaviorBase { + constructor(taskQueue) { + this.taskQueue = taskQueue; + } + bind(binding, source, rulesOrController, rules) { + // identify the target element. + const target = getTargetDOMElement(binding, source); + // locate the controller. + let controller; + if (rulesOrController instanceof ValidationController) { + controller = rulesOrController; + } + else { + controller = source.container.get(aureliaDependencyInjection.Optional.of(ValidationController)); + rules = rulesOrController; + } + if (controller === null) { + throw new Error(`A ValidationController has not been registered.`); + } + controller.registerBinding(binding, target, rules); + binding.validationController = controller; + const trigger = this.getValidateTrigger(controller); + // tslint:disable-next-line:no-bitwise + if (trigger & exports.validateTrigger.change) { + binding.vbbUpdateSource = binding.updateSource; + // tslint:disable-next-line:only-arrow-functions + // tslint:disable-next-line:space-before-function-paren + binding.updateSource = function (value) { + this.vbbUpdateSource(value); + this.validationController.validateBinding(this); + }; + } + // tslint:disable-next-line:no-bitwise + if (trigger & exports.validateTrigger.blur) { + binding.validateBlurHandler = () => { + this.taskQueue.queueMicroTask(() => controller.validateBinding(binding)); + }; + binding.validateTarget = target; + target.addEventListener('blur', binding.validateBlurHandler); + } + if (trigger !== exports.validateTrigger.manual) { + binding.standardUpdateTarget = binding.updateTarget; + // tslint:disable-next-line:only-arrow-functions + // tslint:disable-next-line:space-before-function-paren + binding.updateTarget = function (value) { + this.standardUpdateTarget(value); + this.validationController.resetBinding(this); + }; + } + } + unbind(binding) { + // reset the binding to it's original state. + if (binding.vbbUpdateSource) { + binding.updateSource = binding.vbbUpdateSource; + binding.vbbUpdateSource = null; + } + if (binding.standardUpdateTarget) { + binding.updateTarget = binding.standardUpdateTarget; + binding.standardUpdateTarget = null; + } + if (binding.validateBlurHandler) { + binding.validateTarget.removeEventListener('blur', binding.validateBlurHandler); + binding.validateBlurHandler = null; + binding.validateTarget = null; + } + binding.validationController.unregisterBinding(binding); + binding.validationController = null; + } + } + + /** + * Binding behavior. Indicates the bound property should be validated + * when the validate trigger specified by the associated controller's + * validateTrigger property occurs. + */ + exports.ValidateBindingBehavior = class ValidateBindingBehavior extends ValidateBindingBehaviorBase { + getValidateTrigger(controller) { + return controller.validateTrigger; + } + }; + exports.ValidateBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + exports.ValidateBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validate') + ], exports.ValidateBindingBehavior); + /** + * Binding behavior. Indicates the bound property will be validated + * manually, by calling controller.validate(). No automatic validation + * triggered by data-entry or blur will occur. + */ + exports.ValidateManuallyBindingBehavior = class ValidateManuallyBindingBehavior extends ValidateBindingBehaviorBase { + getValidateTrigger() { + return exports.validateTrigger.manual; + } + }; + exports.ValidateManuallyBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + exports.ValidateManuallyBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validateManually') + ], exports.ValidateManuallyBindingBehavior); + /** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs. + */ + exports.ValidateOnBlurBindingBehavior = class ValidateOnBlurBindingBehavior extends ValidateBindingBehaviorBase { + getValidateTrigger() { + return exports.validateTrigger.blur; + } + }; + exports.ValidateOnBlurBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + exports.ValidateOnBlurBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validateOnBlur') + ], exports.ValidateOnBlurBindingBehavior); + /** + * Binding behavior. Indicates the bound property should be validated + * when the associated element is changed by the user, causing a change + * to the model. + */ + exports.ValidateOnChangeBindingBehavior = class ValidateOnChangeBindingBehavior extends ValidateBindingBehaviorBase { + getValidateTrigger() { + return exports.validateTrigger.change; + } + }; + exports.ValidateOnChangeBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + exports.ValidateOnChangeBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validateOnChange') + ], exports.ValidateOnChangeBindingBehavior); + /** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs or is changed by the user, causing + * a change to the model. + */ + exports.ValidateOnChangeOrBlurBindingBehavior = class ValidateOnChangeOrBlurBindingBehavior extends ValidateBindingBehaviorBase { + getValidateTrigger() { + return exports.validateTrigger.changeOrBlur; + } + }; + exports.ValidateOnChangeOrBlurBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + exports.ValidateOnChangeOrBlurBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validateOnChangeOrBlur') + ], exports.ValidateOnChangeOrBlurBindingBehavior); + + /** + * Creates ValidationController instances. + */ + class ValidationControllerFactory { + constructor(container) { + this.container = container; + } + static get(container) { + return new ValidationControllerFactory(container); + } + /** + * Creates a new controller instance. + */ + create(validator) { + if (!validator) { + validator = this.container.get(Validator); + } + const propertyParser = this.container.get(PropertyAccessorParser); + return new ValidationController(validator, propertyParser); + } + /** + * Creates a new controller and registers it in the current element's container so that it's + * available to the validate binding behavior and renderers. + */ + createForCurrentScope(validator) { + const controller = this.create(validator); + this.container.registerInstance(ValidationController, controller); + return controller; + } + } + ValidationControllerFactory['protocol:aurelia:resolver'] = true; + + exports.ValidationErrorsCustomAttribute = class ValidationErrorsCustomAttribute { + constructor(boundaryElement, controllerAccessor) { + this.boundaryElement = boundaryElement; + this.controllerAccessor = controllerAccessor; + this.controller = null; + this.errors = []; + this.errorsInternal = []; + } + static inject() { + return [aureliaPal.DOM.Element, aureliaDependencyInjection.Lazy.of(ValidationController)]; + } + sort() { + this.errorsInternal.sort((a, b) => { + if (a.targets[0] === b.targets[0]) { + return 0; + } + // tslint:disable-next-line:no-bitwise + return a.targets[0].compareDocumentPosition(b.targets[0]) & 2 ? 1 : -1; + }); + } + interestingElements(elements) { + return elements.filter(e => this.boundaryElement.contains(e)); + } + render(instruction) { + for (const { result } of instruction.unrender) { + const index = this.errorsInternal.findIndex(x => x.error === result); + if (index !== -1) { + this.errorsInternal.splice(index, 1); + } + } + for (const { result, elements } of instruction.render) { + if (result.valid) { + continue; + } + const targets = this.interestingElements(elements); + if (targets.length) { + this.errorsInternal.push({ error: result, targets }); + } + } + this.sort(); + this.errors = this.errorsInternal; + } + bind() { + if (!this.controller) { + this.controller = this.controllerAccessor(); + } + // this will call render() with the side-effect of updating this.errors + this.controller.addRenderer(this); + } + unbind() { + if (this.controller) { + this.controller.removeRenderer(this); + } + } + }; + __decorate([ + aureliaTemplating.bindable({ defaultBindingMode: aureliaBinding.bindingMode.oneWay }) + ], exports.ValidationErrorsCustomAttribute.prototype, "controller", void 0); + __decorate([ + aureliaTemplating.bindable({ primaryProperty: true, defaultBindingMode: aureliaBinding.bindingMode.twoWay }) + ], exports.ValidationErrorsCustomAttribute.prototype, "errors", void 0); + exports.ValidationErrorsCustomAttribute = __decorate([ + aureliaTemplating.customAttribute('validation-errors') + ], exports.ValidationErrorsCustomAttribute); + + exports.ValidationRendererCustomAttribute = class ValidationRendererCustomAttribute { + created(view) { + this.container = view.container; + } + bind() { + this.controller = this.container.get(ValidationController); + this.renderer = this.container.get(this.value); + this.controller.addRenderer(this.renderer); + } + unbind() { + this.controller.removeRenderer(this.renderer); + this.controller = null; + this.renderer = null; + } + }; + exports.ValidationRendererCustomAttribute = __decorate([ + aureliaTemplating.customAttribute('validation-renderer') + ], exports.ValidationRendererCustomAttribute); + + /** + * Sets, unsets and retrieves rules on an object or constructor function. + */ + class Rules { + /** + * Applies the rules to a target. + */ + static set(target, rules) { + if (target instanceof Function) { + target = target.prototype; + } + Object.defineProperty(target, Rules.key, { enumerable: false, configurable: false, writable: true, value: rules }); + } + /** + * Removes rules from a target. + */ + static unset(target) { + if (target instanceof Function) { + target = target.prototype; + } + target[Rules.key] = null; + } + /** + * Retrieves the target's rules. + */ + static get(target) { + return target[Rules.key] || null; + } + } + /** + * The name of the property that stores the rules. + */ + Rules.key = '__rules__'; + + // tslint:disable:no-empty + class ExpressionVisitor { + visitChain(chain) { + this.visitArgs(chain.expressions); + } + visitBindingBehavior(behavior) { + behavior.expression.accept(this); + this.visitArgs(behavior.args); + } + visitValueConverter(converter) { + converter.expression.accept(this); + this.visitArgs(converter.args); + } + visitAssign(assign) { + assign.target.accept(this); + assign.value.accept(this); + } + visitConditional(conditional) { + conditional.condition.accept(this); + conditional.yes.accept(this); + conditional.no.accept(this); + } + visitAccessThis(access) { + access.ancestor = access.ancestor; + } + visitAccessScope(access) { + access.name = access.name; + } + visitAccessMember(access) { + access.object.accept(this); + } + visitAccessKeyed(access) { + access.object.accept(this); + access.key.accept(this); + } + visitCallScope(call) { + this.visitArgs(call.args); + } + visitCallFunction(call) { + call.func.accept(this); + this.visitArgs(call.args); + } + visitCallMember(call) { + call.object.accept(this); + this.visitArgs(call.args); + } + visitPrefix(prefix) { + prefix.expression.accept(this); + } + visitBinary(binary) { + binary.left.accept(this); + binary.right.accept(this); + } + visitLiteralPrimitive(literal) { + literal.value = literal.value; + } + visitLiteralArray(literal) { + this.visitArgs(literal.elements); + } + visitLiteralObject(literal) { + this.visitArgs(literal.values); + } + visitLiteralString(literal) { + literal.value = literal.value; + } + visitArgs(args) { + for (let i = 0; i < args.length; i++) { + args[i].accept(this); + } + } + } + + class ValidationMessageParser { + constructor(bindinqLanguage) { + this.bindinqLanguage = bindinqLanguage; + this.emptyStringExpression = new aureliaBinding.LiteralString(''); + this.nullExpression = new aureliaBinding.LiteralPrimitive(null); + this.undefinedExpression = new aureliaBinding.LiteralPrimitive(undefined); + this.cache = {}; + } + parse(message) { + if (this.cache[message] !== undefined) { + return this.cache[message]; + } + const parts = this.bindinqLanguage.parseInterpolation(null, message); + if (parts === null) { + return new aureliaBinding.LiteralString(message); + } + let expression = new aureliaBinding.LiteralString(parts[0]); + for (let i = 1; i < parts.length; i += 2) { + expression = new aureliaBinding.Binary('+', expression, new aureliaBinding.Binary('+', this.coalesce(parts[i]), new aureliaBinding.LiteralString(parts[i + 1]))); + } + MessageExpressionValidator.validate(expression, message); + this.cache[message] = expression; + return expression; + } + coalesce(part) { + // part === null || part === undefined ? '' : part + return new aureliaBinding.Conditional(new aureliaBinding.Binary('||', new aureliaBinding.Binary('===', part, this.nullExpression), new aureliaBinding.Binary('===', part, this.undefinedExpression)), this.emptyStringExpression, new aureliaBinding.CallMember(part, 'toString', [])); + } + } + ValidationMessageParser.inject = [aureliaTemplating.BindingLanguage]; + class MessageExpressionValidator extends ExpressionVisitor { + constructor(originalMessage) { + super(); + this.originalMessage = originalMessage; + } + static validate(expression, originalMessage) { + const visitor = new MessageExpressionValidator(originalMessage); + expression.accept(visitor); + } + visitAccessScope(access) { + if (access.ancestor !== 0) { + throw new Error('$parent is not permitted in validation message expressions.'); + } + if (['displayName', 'propertyName', 'value', 'object', 'config', 'getDisplayName'].indexOf(access.name) !== -1) { + LogManager.getLogger('aurelia-validation') + // tslint:disable-next-line:max-line-length + .warn(`Did you mean to use "$${access.name}" instead of "${access.name}" in this validation message template: "${this.originalMessage}"?`); + } + } + } + + /** + * Dictionary of validation messages. [messageKey]: messageExpression + */ + const validationMessages = { + /** + * The default validation message. Used with rules that have no standard message. + */ + default: `\${$displayName} is invalid.`, + required: `\${$displayName} is required.`, + matches: `\${$displayName} is not correctly formatted.`, + email: `\${$displayName} is not a valid email.`, + minLength: `\${$displayName} must be at least \${$config.length} character\${$config.length === 1 ? '' : 's'}.`, + maxLength: `\${$displayName} cannot be longer than \${$config.length} character\${$config.length === 1 ? '' : 's'}.`, + minItems: `\${$displayName} must contain at least \${$config.count} item\${$config.count === 1 ? '' : 's'}.`, + maxItems: `\${$displayName} cannot contain more than \${$config.count} item\${$config.count === 1 ? '' : 's'}.`, + min: `\${$displayName} must be at least \${$config.constraint}.`, + max: `\${$displayName} must be at most \${$config.constraint}.`, + range: `\${$displayName} must be between or equal to \${$config.min} and \${$config.max}.`, + between: `\${$displayName} must be between but not equal to \${$config.min} and \${$config.max}.`, + equals: `\${$displayName} must be \${$config.expectedValue}.`, + }; + /** + * Retrieves validation messages and property display names. + */ + class ValidationMessageProvider { + constructor(parser) { + this.parser = parser; + } + /** + * Returns a message binding expression that corresponds to the key. + * @param key The message key. + */ + getMessage(key) { + let message; + if (key in validationMessages) { + message = validationMessages[key]; + } + else { + message = validationMessages['default']; + } + return this.parser.parse(message); + } + /** + * Formulates a property display name using the property name and the configured + * displayName (if provided). + * Override this with your own custom logic. + * @param propertyName The property name. + */ + getDisplayName(propertyName, displayName) { + if (displayName !== null && displayName !== undefined) { + return (displayName instanceof Function) ? displayName() : displayName; + } + // split on upper-case letters. + const words = propertyName.toString().split(/(?=[A-Z])/).join(' '); + // capitalize first letter. + return words.charAt(0).toUpperCase() + words.slice(1); + } + } + ValidationMessageProvider.inject = [ValidationMessageParser]; + + /** + * Validates. + * Responsible for validating objects and properties. + */ + class StandardValidator extends Validator { + constructor(messageProvider, resources) { + super(); + this.messageProvider = messageProvider; + this.lookupFunctions = resources.lookupFunctions; + this.getDisplayName = messageProvider.getDisplayName.bind(messageProvider); + } + /** + * Validates the specified property. + * @param object The object to validate. + * @param propertyName The name of the property to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + validateProperty(object, propertyName, rules) { + return this.validate(object, propertyName, rules || null); + } + /** + * Validates all rules for specified object and it's properties. + * @param object The object to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + validateObject(object, rules) { + return this.validate(object, null, rules || null); + } + /** + * Determines whether a rule exists in a set of rules. + * @param rules The rules to search. + * @parem rule The rule to find. + */ + ruleExists(rules, rule) { + let i = rules.length; + while (i--) { + if (rules[i].indexOf(rule) !== -1) { + return true; + } + } + return false; + } + getMessage(rule, object, value) { + const expression = rule.message || this.messageProvider.getMessage(rule.messageKey); + // tslint:disable-next-line:prefer-const + let { name: propertyName, displayName } = rule.property; + if (propertyName !== null) { + displayName = this.messageProvider.getDisplayName(propertyName, displayName); + } + const overrideContext = { + $displayName: displayName, + $propertyName: propertyName, + $value: value, + $object: object, + $config: rule.config, + // returns the name of a given property, given just the property name (irrespective of the property's displayName) + // split on capital letters, first letter ensured to be capitalized + $getDisplayName: this.getDisplayName + }; + return expression.evaluate({ bindingContext: object, overrideContext }, this.lookupFunctions); + } + validateRuleSequence(object, propertyName, ruleSequence, sequence, results) { + // are we validating all properties or a single property? + const validateAllProperties = propertyName === null || propertyName === undefined; + const rules = ruleSequence[sequence]; + let allValid = true; + // validate each rule. + const promises = []; + for (let i = 0; i < rules.length; i++) { + const rule = rules[i]; + // is the rule related to the property we're validating. + // tslint:disable-next-line:triple-equals | Use loose equality for property keys + if (!validateAllProperties && rule.property.name != propertyName) { + continue; + } + // is this a conditional rule? is the condition met? + if (rule.when && !rule.when(object)) { + continue; + } + // validate. + const value = rule.property.name === null ? object : object[rule.property.name]; + let promiseOrBoolean = rule.condition(value, object); + if (!(promiseOrBoolean instanceof Promise)) { + promiseOrBoolean = Promise.resolve(promiseOrBoolean); + } + promises.push(promiseOrBoolean.then(valid => { + const message = valid ? null : this.getMessage(rule, object, value); + results.push(new ValidateResult(rule, object, rule.property.name, valid, message)); + allValid = allValid && valid; + return valid; + })); + } + return Promise.all(promises) + .then(() => { + sequence++; + if (allValid && sequence < ruleSequence.length) { + return this.validateRuleSequence(object, propertyName, ruleSequence, sequence, results); + } + return results; + }); + } + validate(object, propertyName, rules) { + // rules specified? + if (!rules) { + // no. attempt to locate the rules. + rules = Rules.get(object); + } + // any rules? + if (!rules || rules.length === 0) { + return Promise.resolve([]); + } + return this.validateRuleSequence(object, propertyName, rules, 0, []); + } + } + StandardValidator.inject = [ValidationMessageProvider, aureliaTemplating.ViewResources]; + + /** + * Part of the fluent rule API. Enables customizing property rules. + */ + class FluentRuleCustomizer { + constructor(property, condition, config = {}, fluentEnsure, fluentRules, parsers) { + this.fluentEnsure = fluentEnsure; + this.fluentRules = fluentRules; + this.parsers = parsers; + this.rule = { + property, + condition, + config, + when: null, + messageKey: 'default', + message: null, + sequence: fluentRules.sequence + }; + this.fluentEnsure._addRule(this.rule); + } + /** + * Validate subsequent rules after previously declared rules have + * been validated successfully. Use to postpone validation of costly + * rules until less expensive rules pass validation. + */ + then() { + this.fluentRules.sequence++; + return this; + } + /** + * Specifies the key to use when looking up the rule's validation message. + */ + withMessageKey(key) { + this.rule.messageKey = key; + this.rule.message = null; + return this; + } + /** + * Specifies rule's validation message. + */ + withMessage(message) { + this.rule.messageKey = 'custom'; + this.rule.message = this.parsers.message.parse(message); + return this; + } + /** + * Specifies a condition that must be met before attempting to validate the rule. + * @param condition A function that accepts the object as a parameter and returns true + * or false whether the rule should be evaluated. + */ + when(condition) { + this.rule.when = condition; + return this; + } + /** + * Tags the rule instance, enabling the rule to be found easily + * using ValidationRules.taggedRules(rules, tag) + */ + tag(tag) { + this.rule.tag = tag; + return this; + } + ///// FluentEnsure APIs ///// + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + ensure(subject) { + return this.fluentEnsure.ensure(subject); + } + /** + * Targets an object with validation rules. + */ + ensureObject() { + return this.fluentEnsure.ensureObject(); + } + /** + * Rules that have been defined using the fluent API. + */ + get rules() { + return this.fluentEnsure.rules; + } + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + on(target) { + return this.fluentEnsure.on(target); + } + ///////// FluentRules APIs ///////// + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + satisfies(condition, config) { + return this.fluentRules.satisfies(condition, config); + } + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + satisfiesRule(name, ...args) { + return this.fluentRules.satisfiesRule(name, ...args); + } + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + required() { + return this.fluentRules.required(); + } + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + matches(regex) { + return this.fluentRules.matches(regex); + } + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + email() { + return this.fluentRules.email(); + } + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + minLength(length) { + return this.fluentRules.minLength(length); + } + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + maxLength(length) { + return this.fluentRules.maxLength(length); + } + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + minItems(count) { + return this.fluentRules.minItems(count); + } + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + maxItems(count) { + return this.fluentRules.maxItems(count); + } + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + min(value) { + return this.fluentRules.min(value); + } + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + max(value) { + return this.fluentRules.max(value); + } + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + range(min, max) { + return this.fluentRules.range(min, max); + } + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + between(min, max) { + return this.fluentRules.between(min, max); + } + /** + * Applies the "equals" validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + equals(expectedValue) { + return this.fluentRules.equals(expectedValue); + } + } + /** + * Part of the fluent rule API. Enables applying rules to properties and objects. + */ + class FluentRules { + constructor(fluentEnsure, parsers, property) { + this.fluentEnsure = fluentEnsure; + this.parsers = parsers; + this.property = property; + /** + * Current rule sequence number. Used to postpone evaluation of rules until rules + * with lower sequence number have successfully validated. The "then" fluent API method + * manages this property, there's usually no need to set it directly. + */ + this.sequence = 0; + } + /** + * Sets the display name of the ensured property. + */ + displayName(name) { + this.property.displayName = name; + return this; + } + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + satisfies(condition, config) { + return new FluentRuleCustomizer(this.property, condition, config, this.fluentEnsure, this, this.parsers); + } + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + satisfiesRule(name, ...args) { + let rule = FluentRules.customRules[name]; + if (!rule) { + // standard rule? + rule = this[name]; + if (rule instanceof Function) { + return rule.call(this, ...args); + } + throw new Error(`Rule with name "${name}" does not exist.`); + } + const config = rule.argsToConfig ? rule.argsToConfig(...args) : undefined; + return this.satisfies((value, obj) => rule.condition.call(this, value, obj, ...args), config) + .withMessageKey(name); + } + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + required() { + return this.satisfies(value => value !== null + && value !== undefined + && !(isString(value) && !/\S/.test(value))).withMessageKey('required'); + } + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + matches(regex) { + return this.satisfies(value => value === null || value === undefined || value.length === 0 || regex.test(value)) + .withMessageKey('matches'); + } + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + email() { + // regex from https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address + /* tslint:disable:max-line-length */ + return this.matches(/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/) + /* tslint:enable:max-line-length */ + .withMessageKey('email'); + } + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + minLength(length) { + return this.satisfies((value) => value === null || value === undefined || value.length === 0 || value.length >= length, { length }) + .withMessageKey('minLength'); + } + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + maxLength(length) { + return this.satisfies((value) => value === null || value === undefined || value.length === 0 || value.length <= length, { length }) + .withMessageKey('maxLength'); + } + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + minItems(count) { + return this.satisfies((value) => value === null || value === undefined || value.length >= count, { count }) + .withMessageKey('minItems'); + } + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + maxItems(count) { + return this.satisfies((value) => value === null || value === undefined || value.length <= count, { count }) + .withMessageKey('maxItems'); + } + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + min(constraint) { + return this.satisfies((value) => value === null || value === undefined || value >= constraint, { constraint }) + .withMessageKey('min'); + } + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + max(constraint) { + return this.satisfies((value) => value === null || value === undefined || value <= constraint, { constraint }) + .withMessageKey('max'); + } + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + range(min, max) { + return this.satisfies((value) => value === null || value === undefined || (value >= min && value <= max), { min, max }) + .withMessageKey('range'); + } + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + between(min, max) { + return this.satisfies((value) => value === null || value === undefined || (value > min && value < max), { min, max }) + .withMessageKey('between'); + } + /** + * Applies the "equals" validation rule to the property. + * null and undefined values are considered valid. + */ + equals(expectedValue) { + return this.satisfies(value => value === null || value === undefined || value === '' || value === expectedValue, { expectedValue }) + .withMessageKey('equals'); + } + } + FluentRules.customRules = {}; + /** + * Part of the fluent rule API. Enables targeting properties and objects with rules. + */ + class FluentEnsure { + constructor(parsers) { + this.parsers = parsers; + /** + * Rules that have been defined using the fluent API. + */ + this.rules = []; + } + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor + * function. + */ + ensure(property) { + this.assertInitialized(); + const name = this.parsers.property.parse(property); + const fluentRules = new FluentRules(this, this.parsers, { name, displayName: null }); + return this.mergeRules(fluentRules, name); + } + /** + * Targets an object with validation rules. + */ + ensureObject() { + this.assertInitialized(); + const fluentRules = new FluentRules(this, this.parsers, { name: null, displayName: null }); + return this.mergeRules(fluentRules, null); + } + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + on(target) { + Rules.set(target, this.rules); + return this; + } + /** + * Adds a rule definition to the sequenced ruleset. + * @internal + */ + _addRule(rule) { + while (this.rules.length < rule.sequence + 1) { + this.rules.push([]); + } + this.rules[rule.sequence].push(rule); + } + assertInitialized() { + if (this.parsers) { + return; + } + throw new Error(`Did you forget to add ".plugin('aurelia-validation')" to your main.js?`); + } + mergeRules(fluentRules, propertyName) { + // tslint:disable-next-line:triple-equals | Use loose equality for property keys + const existingRules = this.rules.find(r => r.length > 0 && r[0].property.name == propertyName); + if (existingRules) { + const rule = existingRules[existingRules.length - 1]; + fluentRules.sequence = rule.sequence; + if (rule.property.displayName !== null) { + fluentRules = fluentRules.displayName(rule.property.displayName); + } + } + return fluentRules; + } + } + /** + * Fluent rule definition API. + */ + class ValidationRules { + static initialize(messageParser, propertyParser) { + this.parsers = { + message: messageParser, + property: propertyParser + }; + } + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + static ensure(property) { + return new FluentEnsure(ValidationRules.parsers).ensure(property); + } + /** + * Targets an object with validation rules. + */ + static ensureObject() { + return new FluentEnsure(ValidationRules.parsers).ensureObject(); + } + /** + * Defines a custom rule. + * @param name The name of the custom rule. Also serves as the message key. + * @param condition The rule function. + * @param message The message expression + * @param argsToConfig A function that maps the rule's arguments to a "config" + * object that can be used when evaluating the message expression. + */ + static customRule(name, condition, message, argsToConfig) { + validationMessages[name] = message; + FluentRules.customRules[name] = { condition, argsToConfig }; + } + /** + * Returns rules with the matching tag. + * @param rules The rules to search. + * @param tag The tag to search for. + */ + static taggedRules(rules, tag) { + return rules.map(x => x.filter(r => r.tag === tag)); + } + /** + * Returns rules that have no tag. + * @param rules The rules to search. + */ + static untaggedRules(rules) { + return rules.map(x => x.filter(r => r.tag === undefined)); + } + /** + * Removes the rules from a class or object. + * @param target A class or object. + */ + static off(target) { + Rules.unset(target); + } + } + + // Exports + /** + * Aurelia Validation Configuration API + */ + class AureliaValidationConfiguration { + constructor() { + this.validatorType = StandardValidator; + } + /** + * Use a custom Validator implementation. + */ + customValidator(type) { + this.validatorType = type; + } + /** + * Applies the configuration. + */ + apply(container) { + const validator = container.get(this.validatorType); + container.registerInstance(Validator, validator); + } + } + /** + * Configures the plugin. + */ + function configure( + // tslint:disable-next-line:ban-types + frameworkConfig, callback) { + // the fluent rule definition API needs the parser to translate messages + // to interpolation expressions. + const messageParser = frameworkConfig.container.get(ValidationMessageParser); + const propertyParser = frameworkConfig.container.get(PropertyAccessorParser); + ValidationRules.initialize(messageParser, propertyParser); + // configure... + const config = new AureliaValidationConfiguration(); + if (callback instanceof Function) { + callback(config); + } + config.apply(frameworkConfig.container); + // globalize the behaviors. + if (frameworkConfig.globalResources) { + frameworkConfig.globalResources(exports.ValidateBindingBehavior, exports.ValidateManuallyBindingBehavior, exports.ValidateOnBlurBindingBehavior, exports.ValidateOnChangeBindingBehavior, exports.ValidateOnChangeOrBlurBindingBehavior, exports.ValidationErrorsCustomAttribute, exports.ValidationRendererCustomAttribute); + } + } + + exports.AureliaValidationConfiguration = AureliaValidationConfiguration; + exports.configure = configure; + exports.getTargetDOMElement = getTargetDOMElement; + exports.getPropertyInfo = getPropertyInfo; + exports.PropertyAccessorParser = PropertyAccessorParser; + exports.getAccessorExpression = getAccessorExpression; + exports.ValidateEvent = ValidateEvent; + exports.ValidateResult = ValidateResult; + exports.ValidationController = ValidationController; + exports.ValidationControllerFactory = ValidationControllerFactory; + exports.Validator = Validator; + exports.Rules = Rules; + exports.StandardValidator = StandardValidator; + exports.validationMessages = validationMessages; + exports.ValidationMessageProvider = ValidationMessageProvider; + exports.ValidationMessageParser = ValidationMessageParser; + exports.MessageExpressionValidator = MessageExpressionValidator; + exports.FluentRuleCustomizer = FluentRuleCustomizer; + exports.FluentRules = FluentRules; + exports.FluentEnsure = FluentEnsure; + exports.ValidationRules = ValidationRules; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); diff --git a/dist/umd/aurelia-validation.js b/dist/umd/aurelia-validation.js new file mode 100644 index 00000000..c251878a --- /dev/null +++ b/dist/umd/aurelia-validation.js @@ -0,0 +1,1887 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('aurelia-pal'), require('aurelia-binding'), require('aurelia-dependency-injection'), require('aurelia-task-queue'), require('aurelia-templating'), require('aurelia-logging')) : + typeof define === 'function' && define.amd ? define(['exports', 'aurelia-pal', 'aurelia-binding', 'aurelia-dependency-injection', 'aurelia-task-queue', 'aurelia-templating', 'aurelia-logging'], factory) : + (factory((global.au = global.au || {}, global.au.validation = {}),global.au,global.au,global.au,global.au,global.au,global.au.LogManager)); +}(this, (function (exports,aureliaPal,aureliaBinding,aureliaDependencyInjection,aureliaTaskQueue,aureliaTemplating,LogManager) { 'use strict'; + + /** + * Gets the DOM element associated with the data-binding. Most of the time it's + * the binding.target but sometimes binding.target is an aurelia custom element, + * or custom attribute which is a javascript "class" instance, so we need to use + * the controller's container to retrieve the actual DOM element. + */ + function getTargetDOMElement(binding, view) { + var target = binding.target; + // DOM element + if (target instanceof Element) { + return target; + } + // custom element or custom attribute + // tslint:disable-next-line:prefer-const + for (var i = 0, ii = view.controllers.length; i < ii; i++) { + var controller = view.controllers[i]; + if (controller.viewModel === target) { + var element = controller.container.get(aureliaPal.DOM.Element); + if (element) { + return element; + } + throw new Error("Unable to locate target element for \"" + binding.sourceExpression + "\"."); + } + } + throw new Error("Unable to locate target element for \"" + binding.sourceExpression + "\"."); + } + + function getObject(expression, objectExpression, source) { + var value = objectExpression.evaluate(source, null); + if (value === null || value === undefined || value instanceof Object) { + return value; + } + // tslint:disable-next-line:max-line-length + throw new Error("The '" + objectExpression + "' part of '" + expression + "' evaluates to " + value + " instead of an object, null or undefined."); + } + /** + * Retrieves the object and property name for the specified expression. + * @param expression The expression + * @param source The scope + */ + function getPropertyInfo(expression, source) { + var originalExpression = expression; + while (expression instanceof aureliaBinding.BindingBehavior || expression instanceof aureliaBinding.ValueConverter) { + expression = expression.expression; + } + var object; + var propertyName; + if (expression instanceof aureliaBinding.AccessScope) { + object = aureliaBinding.getContextFor(expression.name, source, expression.ancestor); + propertyName = expression.name; + } + else if (expression instanceof aureliaBinding.AccessMember) { + object = getObject(originalExpression, expression.object, source); + propertyName = expression.name; + } + else if (expression instanceof aureliaBinding.AccessKeyed) { + object = getObject(originalExpression, expression.object, source); + propertyName = expression.key.evaluate(source); + } + else { + throw new Error("Expression '" + originalExpression + "' is not compatible with the validate binding-behavior."); + } + if (object === null || object === undefined) { + return null; + } + return { object: object, propertyName: propertyName }; + } + + function isString(value) { + return Object.prototype.toString.call(value) === '[object String]'; + } + function isNumber(value) { + return Object.prototype.toString.call(value) === '[object Number]'; + } + + var PropertyAccessorParser = /** @class */ (function () { + function PropertyAccessorParser(parser) { + this.parser = parser; + } + PropertyAccessorParser.prototype.parse = function (property) { + if (isString(property) || isNumber(property)) { + return property; + } + var accessorText = getAccessorExpression(property.toString()); + var accessor = this.parser.parse(accessorText); + if (accessor instanceof aureliaBinding.AccessScope + || accessor instanceof aureliaBinding.AccessMember && accessor.object instanceof aureliaBinding.AccessScope) { + return accessor.name; + } + throw new Error("Invalid property expression: \"" + accessor + "\""); + }; + PropertyAccessorParser.inject = [aureliaBinding.Parser]; + return PropertyAccessorParser; + }()); + function getAccessorExpression(fn) { + /* tslint:disable:max-line-length */ + var classic = /^function\s*\([$_\w\d]+\)\s*\{(?:\s*"use strict";)?\s*(?:[$_\w\d.['"\]+;]+)?\s*return\s+[$_\w\d]+\.([$_\w\d]+)\s*;?\s*\}$/; + /* tslint:enable:max-line-length */ + var arrow = /^\(?[$_\w\d]+\)?\s*=>\s*[$_\w\d]+\.([$_\w\d]+)$/; + var match = classic.exec(fn) || arrow.exec(fn); + if (match === null) { + throw new Error("Unable to parse accessor function:\n" + fn); + } + return match[1]; + } + + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use + this file except in compliance with the License. You may obtain a copy of the + License at http://www.apache.org/licenses/LICENSE-2.0 + + THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED + WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, + MERCHANTABLITY OR NON-INFRINGEMENT. + + See the Apache Version 2.0 License for specific language governing permissions + and limitations under the License. + ***************************************************************************** */ + /* global Reflect, Promise */ + + var extendStatics = function(d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + + function __extends(d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + } + + function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; + } + + /** + * Validation triggers. + */ + (function (validateTrigger) { + /** + * Manual validation. Use the controller's `validate()` and `reset()` methods + * to validate all bindings. + */ + validateTrigger[validateTrigger["manual"] = 0] = "manual"; + /** + * Validate the binding when the binding's target element fires a DOM "blur" event. + */ + validateTrigger[validateTrigger["blur"] = 1] = "blur"; + /** + * Validate the binding when it updates the model due to a change in the view. + */ + validateTrigger[validateTrigger["change"] = 2] = "change"; + /** + * Validate the binding when the binding's target element fires a DOM "blur" event and + * when it updates the model due to a change in the view. + */ + validateTrigger[validateTrigger["changeOrBlur"] = 3] = "changeOrBlur"; + })(exports.validateTrigger || (exports.validateTrigger = {})); + + /** + * Validates objects and properties. + */ + var Validator = /** @class */ (function () { + function Validator() { + } + return Validator; + }()); + + /** + * The result of validating an individual validation rule. + */ + var ValidateResult = /** @class */ (function () { + /** + * @param rule The rule associated with the result. Validator implementation specific. + * @param object The object that was validated. + * @param propertyName The name of the property that was validated. + * @param error The error, if the result is a validation error. + */ + function ValidateResult(rule, object, propertyName, valid, message) { + if (message === void 0) { message = null; } + this.rule = rule; + this.object = object; + this.propertyName = propertyName; + this.valid = valid; + this.message = message; + this.id = ValidateResult.nextId++; + } + ValidateResult.prototype.toString = function () { + return this.valid ? 'Valid.' : this.message; + }; + ValidateResult.nextId = 0; + return ValidateResult; + }()); + + var ValidateEvent = /** @class */ (function () { + function ValidateEvent( + /** + * The type of validate event. Either "validate" or "reset". + */ + type, + /** + * The controller's current array of errors. For an array containing both + * failed rules and passed rules, use the "results" property. + */ + errors, + /** + * The controller's current array of validate results. This + * includes both passed rules and failed rules. For an array of only failed rules, + * use the "errors" property. + */ + results, + /** + * The instruction passed to the "validate" or "reset" event. Will be null when + * the controller's validate/reset method was called with no instruction argument. + */ + instruction, + /** + * In events with type === "validate", this property will contain the result + * of validating the instruction (see "instruction" property). Use the controllerValidateResult + * to access the validate results specific to the call to "validate" + * (as opposed to using the "results" and "errors" properties to access the controller's entire + * set of results/errors). + */ + controllerValidateResult) { + this.type = type; + this.errors = errors; + this.results = results; + this.instruction = instruction; + this.controllerValidateResult = controllerValidateResult; + } + return ValidateEvent; + }()); + + /** + * Orchestrates validation. + * Manages a set of bindings, renderers and objects. + * Exposes the current list of validation results for binding purposes. + */ + var ValidationController = /** @class */ (function () { + function ValidationController(validator, propertyParser) { + this.validator = validator; + this.propertyParser = propertyParser; + // Registered bindings (via the validate binding behavior) + this.bindings = new Map(); + // Renderers that have been added to the controller instance. + this.renderers = []; + /** + * Validation results that have been rendered by the controller. + */ + this.results = []; + /** + * Validation errors that have been rendered by the controller. + */ + this.errors = []; + /** + * Whether the controller is currently validating. + */ + this.validating = false; + // Elements related to validation results that have been rendered. + this.elements = new Map(); + // Objects that have been added to the controller instance (entity-style validation). + this.objects = new Map(); + /** + * The trigger that will invoke automatic validation of a property used in a binding. + */ + this.validateTrigger = exports.validateTrigger.blur; + // Promise that resolves when validation has completed. + this.finishValidating = Promise.resolve(); + this.eventCallbacks = []; + } + /** + * Subscribe to controller validate and reset events. These events occur when the + * controller's "validate"" and "reset" methods are called. + * @param callback The callback to be invoked when the controller validates or resets. + */ + ValidationController.prototype.subscribe = function (callback) { + var _this = this; + this.eventCallbacks.push(callback); + return { + dispose: function () { + var index = _this.eventCallbacks.indexOf(callback); + if (index === -1) { + return; + } + _this.eventCallbacks.splice(index, 1); + } + }; + }; + /** + * Adds an object to the set of objects that should be validated when validate is called. + * @param object The object. + * @param rules Optional. The rules. If rules aren't supplied the Validator implementation will lookup the rules. + */ + ValidationController.prototype.addObject = function (object, rules) { + this.objects.set(object, rules); + }; + /** + * Removes an object from the set of objects that should be validated when validate is called. + * @param object The object. + */ + ValidationController.prototype.removeObject = function (object) { + this.objects.delete(object); + this.processResultDelta('reset', this.results.filter(function (result) { return result.object === object; }), []); + }; + /** + * Adds and renders an error. + */ + ValidationController.prototype.addError = function (message, object, propertyName) { + if (propertyName === void 0) { propertyName = null; } + var resolvedPropertyName; + if (propertyName === null) { + resolvedPropertyName = propertyName; + } + else { + resolvedPropertyName = this.propertyParser.parse(propertyName); + } + var result = new ValidateResult({ __manuallyAdded__: true }, object, resolvedPropertyName, false, message); + this.processResultDelta('validate', [], [result]); + return result; + }; + /** + * Removes and unrenders an error. + */ + ValidationController.prototype.removeError = function (result) { + if (this.results.indexOf(result) !== -1) { + this.processResultDelta('reset', [result], []); + } + }; + /** + * Adds a renderer. + * @param renderer The renderer. + */ + ValidationController.prototype.addRenderer = function (renderer) { + var _this = this; + this.renderers.push(renderer); + renderer.render({ + kind: 'validate', + render: this.results.map(function (result) { return ({ result: result, elements: _this.elements.get(result) }); }), + unrender: [] + }); + }; + /** + * Removes a renderer. + * @param renderer The renderer. + */ + ValidationController.prototype.removeRenderer = function (renderer) { + var _this = this; + this.renderers.splice(this.renderers.indexOf(renderer), 1); + renderer.render({ + kind: 'reset', + render: [], + unrender: this.results.map(function (result) { return ({ result: result, elements: _this.elements.get(result) }); }) + }); + }; + /** + * Registers a binding with the controller. + * @param binding The binding instance. + * @param target The DOM element. + * @param rules (optional) rules associated with the binding. Validator implementation specific. + */ + ValidationController.prototype.registerBinding = function (binding, target, rules) { + this.bindings.set(binding, { target: target, rules: rules, propertyInfo: null }); + }; + /** + * Unregisters a binding with the controller. + * @param binding The binding instance. + */ + ValidationController.prototype.unregisterBinding = function (binding) { + this.resetBinding(binding); + this.bindings.delete(binding); + }; + /** + * Interprets the instruction and returns a predicate that will identify + * relevant results in the list of rendered validation results. + */ + ValidationController.prototype.getInstructionPredicate = function (instruction) { + var _this = this; + if (instruction) { + var object_1 = instruction.object, propertyName_1 = instruction.propertyName, rules_1 = instruction.rules; + var predicate_1; + if (instruction.propertyName) { + predicate_1 = function (x) { return x.object === object_1 && x.propertyName === propertyName_1; }; + } + else { + predicate_1 = function (x) { return x.object === object_1; }; + } + if (rules_1) { + return function (x) { return predicate_1(x) && _this.validator.ruleExists(rules_1, x.rule); }; + } + return predicate_1; + } + else { + return function () { return true; }; + } + }; + /** + * Validates and renders results. + * @param instruction Optional. Instructions on what to validate. If undefined, all + * objects and bindings will be validated. + */ + ValidationController.prototype.validate = function (instruction) { + var _this = this; + // Get a function that will process the validation instruction. + var execute; + if (instruction) { + // tslint:disable-next-line:prefer-const + var object_2 = instruction.object, propertyName_2 = instruction.propertyName, rules_2 = instruction.rules; + // if rules were not specified, check the object map. + rules_2 = rules_2 || this.objects.get(object_2); + // property specified? + if (instruction.propertyName === undefined) { + // validate the specified object. + execute = function () { return _this.validator.validateObject(object_2, rules_2); }; + } + else { + // validate the specified property. + execute = function () { return _this.validator.validateProperty(object_2, propertyName_2, rules_2); }; + } + } + else { + // validate all objects and bindings. + execute = function () { + var promises = []; + for (var _i = 0, _a = Array.from(_this.objects); _i < _a.length; _i++) { + var _b = _a[_i], object = _b[0], rules = _b[1]; + promises.push(_this.validator.validateObject(object, rules)); + } + for (var _c = 0, _d = Array.from(_this.bindings); _c < _d.length; _c++) { + var _e = _d[_c], binding = _e[0], rules = _e[1].rules; + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (!propertyInfo || _this.objects.has(propertyInfo.object)) { + continue; + } + promises.push(_this.validator.validateProperty(propertyInfo.object, propertyInfo.propertyName, rules)); + } + return Promise.all(promises).then(function (resultSets) { return resultSets.reduce(function (a, b) { return a.concat(b); }, []); }); + }; + } + // Wait for any existing validation to finish, execute the instruction, render the results. + this.validating = true; + var returnPromise = this.finishValidating + .then(execute) + .then(function (newResults) { + var predicate = _this.getInstructionPredicate(instruction); + var oldResults = _this.results.filter(predicate); + _this.processResultDelta('validate', oldResults, newResults); + if (returnPromise === _this.finishValidating) { + _this.validating = false; + } + var result = { + instruction: instruction, + valid: newResults.find(function (x) { return !x.valid; }) === undefined, + results: newResults + }; + _this.invokeCallbacks(instruction, result); + return result; + }) + .catch(function (exception) { + // recover, to enable subsequent calls to validate() + _this.validating = false; + _this.finishValidating = Promise.resolve(); + return Promise.reject(exception); + }); + this.finishValidating = returnPromise; + return returnPromise; + }; + /** + * Resets any rendered validation results (unrenders). + * @param instruction Optional. Instructions on what to reset. If unspecified all rendered results + * will be unrendered. + */ + ValidationController.prototype.reset = function (instruction) { + var predicate = this.getInstructionPredicate(instruction); + var oldResults = this.results.filter(predicate); + this.processResultDelta('reset', oldResults, []); + this.invokeCallbacks(instruction, null); + }; + /** + * Gets the elements associated with an object and propertyName (if any). + */ + ValidationController.prototype.getAssociatedElements = function (_a) { + var object = _a.object, propertyName = _a.propertyName; + var elements = []; + for (var _i = 0, _b = Array.from(this.bindings); _i < _b.length; _i++) { + var _c = _b[_i], binding = _c[0], target = _c[1].target; + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (propertyInfo && propertyInfo.object === object && propertyInfo.propertyName === propertyName) { + elements.push(target); + } + } + return elements; + }; + ValidationController.prototype.processResultDelta = function (kind, oldResults, newResults) { + // prepare the instruction. + var instruction = { + kind: kind, + render: [], + unrender: [] + }; + // create a shallow copy of newResults so we can mutate it without causing side-effects. + newResults = newResults.slice(0); + var _loop_1 = function (oldResult) { + // get the elements associated with the old result. + var elements = this_1.elements.get(oldResult); + // remove the old result from the element map. + this_1.elements.delete(oldResult); + // create the unrender instruction. + instruction.unrender.push({ result: oldResult, elements: elements }); + // determine if there's a corresponding new result for the old result we are unrendering. + var newResultIndex = newResults.findIndex(function (x) { return x.rule === oldResult.rule && x.object === oldResult.object && x.propertyName === oldResult.propertyName; }); + if (newResultIndex === -1) { + // no corresponding new result... simple remove. + this_1.results.splice(this_1.results.indexOf(oldResult), 1); + if (!oldResult.valid) { + this_1.errors.splice(this_1.errors.indexOf(oldResult), 1); + } + } + else { + // there is a corresponding new result... + var newResult = newResults.splice(newResultIndex, 1)[0]; + // get the elements that are associated with the new result. + var elements_1 = this_1.getAssociatedElements(newResult); + this_1.elements.set(newResult, elements_1); + // create a render instruction for the new result. + instruction.render.push({ result: newResult, elements: elements_1 }); + // do an in-place replacement of the old result with the new result. + // this ensures any repeats bound to this.results will not thrash. + this_1.results.splice(this_1.results.indexOf(oldResult), 1, newResult); + if (!oldResult.valid && newResult.valid) { + this_1.errors.splice(this_1.errors.indexOf(oldResult), 1); + } + else if (!oldResult.valid && !newResult.valid) { + this_1.errors.splice(this_1.errors.indexOf(oldResult), 1, newResult); + } + else if (!newResult.valid) { + this_1.errors.push(newResult); + } + } + }; + var this_1 = this; + // create unrender instructions from the old results. + for (var _i = 0, oldResults_1 = oldResults; _i < oldResults_1.length; _i++) { + var oldResult = oldResults_1[_i]; + _loop_1(oldResult); + } + // create render instructions from the remaining new results. + for (var _a = 0, newResults_1 = newResults; _a < newResults_1.length; _a++) { + var result = newResults_1[_a]; + var elements = this.getAssociatedElements(result); + instruction.render.push({ result: result, elements: elements }); + this.elements.set(result, elements); + this.results.push(result); + if (!result.valid) { + this.errors.push(result); + } + } + // render. + for (var _b = 0, _c = this.renderers; _b < _c.length; _b++) { + var renderer = _c[_b]; + renderer.render(instruction); + } + }; + /** + * Validates the property associated with a binding. + */ + ValidationController.prototype.validateBinding = function (binding) { + if (!binding.isBound) { + return; + } + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + var rules; + var registeredBinding = this.bindings.get(binding); + if (registeredBinding) { + rules = registeredBinding.rules; + registeredBinding.propertyInfo = propertyInfo; + } + if (!propertyInfo) { + return; + } + var object = propertyInfo.object, propertyName = propertyInfo.propertyName; + this.validate({ object: object, propertyName: propertyName, rules: rules }); + }; + /** + * Resets the results for a property associated with a binding. + */ + ValidationController.prototype.resetBinding = function (binding) { + var registeredBinding = this.bindings.get(binding); + var propertyInfo = getPropertyInfo(binding.sourceExpression, binding.source); + if (!propertyInfo && registeredBinding) { + propertyInfo = registeredBinding.propertyInfo; + } + if (registeredBinding) { + registeredBinding.propertyInfo = null; + } + if (!propertyInfo) { + return; + } + var object = propertyInfo.object, propertyName = propertyInfo.propertyName; + this.reset({ object: object, propertyName: propertyName }); + }; + /** + * Changes the controller's validateTrigger. + * @param newTrigger The new validateTrigger + */ + ValidationController.prototype.changeTrigger = function (newTrigger) { + this.validateTrigger = newTrigger; + var bindings = Array.from(this.bindings.keys()); + for (var _i = 0, bindings_1 = bindings; _i < bindings_1.length; _i++) { + var binding = bindings_1[_i]; + var source = binding.source; + binding.unbind(); + binding.bind(source); + } + }; + /** + * Revalidates the controller's current set of errors. + */ + ValidationController.prototype.revalidateErrors = function () { + for (var _i = 0, _a = this.errors; _i < _a.length; _i++) { + var _b = _a[_i], object = _b.object, propertyName = _b.propertyName, rule = _b.rule; + if (rule.__manuallyAdded__) { + continue; + } + var rules = [[rule]]; + this.validate({ object: object, propertyName: propertyName, rules: rules }); + } + }; + ValidationController.prototype.invokeCallbacks = function (instruction, result) { + if (this.eventCallbacks.length === 0) { + return; + } + var event = new ValidateEvent(result ? 'validate' : 'reset', this.errors, this.results, instruction || null, result); + for (var i = 0; i < this.eventCallbacks.length; i++) { + this.eventCallbacks[i](event); + } + }; + ValidationController.inject = [Validator, PropertyAccessorParser]; + return ValidationController; + }()); + + /** + * Binding behavior. Indicates the bound property should be validated. + */ + var ValidateBindingBehaviorBase = /** @class */ (function () { + function ValidateBindingBehaviorBase(taskQueue) { + this.taskQueue = taskQueue; + } + ValidateBindingBehaviorBase.prototype.bind = function (binding, source, rulesOrController, rules) { + var _this = this; + // identify the target element. + var target = getTargetDOMElement(binding, source); + // locate the controller. + var controller; + if (rulesOrController instanceof ValidationController) { + controller = rulesOrController; + } + else { + controller = source.container.get(aureliaDependencyInjection.Optional.of(ValidationController)); + rules = rulesOrController; + } + if (controller === null) { + throw new Error("A ValidationController has not been registered."); + } + controller.registerBinding(binding, target, rules); + binding.validationController = controller; + var trigger = this.getValidateTrigger(controller); + // tslint:disable-next-line:no-bitwise + if (trigger & exports.validateTrigger.change) { + binding.vbbUpdateSource = binding.updateSource; + // tslint:disable-next-line:only-arrow-functions + // tslint:disable-next-line:space-before-function-paren + binding.updateSource = function (value) { + this.vbbUpdateSource(value); + this.validationController.validateBinding(this); + }; + } + // tslint:disable-next-line:no-bitwise + if (trigger & exports.validateTrigger.blur) { + binding.validateBlurHandler = function () { + _this.taskQueue.queueMicroTask(function () { return controller.validateBinding(binding); }); + }; + binding.validateTarget = target; + target.addEventListener('blur', binding.validateBlurHandler); + } + if (trigger !== exports.validateTrigger.manual) { + binding.standardUpdateTarget = binding.updateTarget; + // tslint:disable-next-line:only-arrow-functions + // tslint:disable-next-line:space-before-function-paren + binding.updateTarget = function (value) { + this.standardUpdateTarget(value); + this.validationController.resetBinding(this); + }; + } + }; + ValidateBindingBehaviorBase.prototype.unbind = function (binding) { + // reset the binding to it's original state. + if (binding.vbbUpdateSource) { + binding.updateSource = binding.vbbUpdateSource; + binding.vbbUpdateSource = null; + } + if (binding.standardUpdateTarget) { + binding.updateTarget = binding.standardUpdateTarget; + binding.standardUpdateTarget = null; + } + if (binding.validateBlurHandler) { + binding.validateTarget.removeEventListener('blur', binding.validateBlurHandler); + binding.validateBlurHandler = null; + binding.validateTarget = null; + } + binding.validationController.unregisterBinding(binding); + binding.validationController = null; + }; + return ValidateBindingBehaviorBase; + }()); + + /** + * Binding behavior. Indicates the bound property should be validated + * when the validate trigger specified by the associated controller's + * validateTrigger property occurs. + */ + var ValidateBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateBindingBehavior, _super); + function ValidateBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateBindingBehavior.prototype.getValidateTrigger = function (controller) { + return controller.validateTrigger; + }; + ValidateBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + ValidateBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validate') + ], ValidateBindingBehavior); + return ValidateBindingBehavior; + }(ValidateBindingBehaviorBase)); + /** + * Binding behavior. Indicates the bound property will be validated + * manually, by calling controller.validate(). No automatic validation + * triggered by data-entry or blur will occur. + */ + var ValidateManuallyBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateManuallyBindingBehavior, _super); + function ValidateManuallyBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateManuallyBindingBehavior.prototype.getValidateTrigger = function () { + return exports.validateTrigger.manual; + }; + ValidateManuallyBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + ValidateManuallyBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validateManually') + ], ValidateManuallyBindingBehavior); + return ValidateManuallyBindingBehavior; + }(ValidateBindingBehaviorBase)); + /** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs. + */ + var ValidateOnBlurBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateOnBlurBindingBehavior, _super); + function ValidateOnBlurBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateOnBlurBindingBehavior.prototype.getValidateTrigger = function () { + return exports.validateTrigger.blur; + }; + ValidateOnBlurBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + ValidateOnBlurBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validateOnBlur') + ], ValidateOnBlurBindingBehavior); + return ValidateOnBlurBindingBehavior; + }(ValidateBindingBehaviorBase)); + /** + * Binding behavior. Indicates the bound property should be validated + * when the associated element is changed by the user, causing a change + * to the model. + */ + var ValidateOnChangeBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateOnChangeBindingBehavior, _super); + function ValidateOnChangeBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateOnChangeBindingBehavior.prototype.getValidateTrigger = function () { + return exports.validateTrigger.change; + }; + ValidateOnChangeBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + ValidateOnChangeBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validateOnChange') + ], ValidateOnChangeBindingBehavior); + return ValidateOnChangeBindingBehavior; + }(ValidateBindingBehaviorBase)); + /** + * Binding behavior. Indicates the bound property should be validated + * when the associated element blurs or is changed by the user, causing + * a change to the model. + */ + var ValidateOnChangeOrBlurBindingBehavior = /** @class */ (function (_super) { + __extends(ValidateOnChangeOrBlurBindingBehavior, _super); + function ValidateOnChangeOrBlurBindingBehavior() { + return _super !== null && _super.apply(this, arguments) || this; + } + ValidateOnChangeOrBlurBindingBehavior.prototype.getValidateTrigger = function () { + return exports.validateTrigger.changeOrBlur; + }; + ValidateOnChangeOrBlurBindingBehavior.inject = [aureliaTaskQueue.TaskQueue]; + ValidateOnChangeOrBlurBindingBehavior = __decorate([ + aureliaBinding.bindingBehavior('validateOnChangeOrBlur') + ], ValidateOnChangeOrBlurBindingBehavior); + return ValidateOnChangeOrBlurBindingBehavior; + }(ValidateBindingBehaviorBase)); + + /** + * Creates ValidationController instances. + */ + var ValidationControllerFactory = /** @class */ (function () { + function ValidationControllerFactory(container) { + this.container = container; + } + ValidationControllerFactory.get = function (container) { + return new ValidationControllerFactory(container); + }; + /** + * Creates a new controller instance. + */ + ValidationControllerFactory.prototype.create = function (validator) { + if (!validator) { + validator = this.container.get(Validator); + } + var propertyParser = this.container.get(PropertyAccessorParser); + return new ValidationController(validator, propertyParser); + }; + /** + * Creates a new controller and registers it in the current element's container so that it's + * available to the validate binding behavior and renderers. + */ + ValidationControllerFactory.prototype.createForCurrentScope = function (validator) { + var controller = this.create(validator); + this.container.registerInstance(ValidationController, controller); + return controller; + }; + return ValidationControllerFactory; + }()); + ValidationControllerFactory['protocol:aurelia:resolver'] = true; + + var ValidationErrorsCustomAttribute = /** @class */ (function () { + function ValidationErrorsCustomAttribute(boundaryElement, controllerAccessor) { + this.boundaryElement = boundaryElement; + this.controllerAccessor = controllerAccessor; + this.controller = null; + this.errors = []; + this.errorsInternal = []; + } + ValidationErrorsCustomAttribute.inject = function () { + return [aureliaPal.DOM.Element, aureliaDependencyInjection.Lazy.of(ValidationController)]; + }; + ValidationErrorsCustomAttribute.prototype.sort = function () { + this.errorsInternal.sort(function (a, b) { + if (a.targets[0] === b.targets[0]) { + return 0; + } + // tslint:disable-next-line:no-bitwise + return a.targets[0].compareDocumentPosition(b.targets[0]) & 2 ? 1 : -1; + }); + }; + ValidationErrorsCustomAttribute.prototype.interestingElements = function (elements) { + var _this = this; + return elements.filter(function (e) { return _this.boundaryElement.contains(e); }); + }; + ValidationErrorsCustomAttribute.prototype.render = function (instruction) { + var _loop_1 = function (result) { + var index = this_1.errorsInternal.findIndex(function (x) { return x.error === result; }); + if (index !== -1) { + this_1.errorsInternal.splice(index, 1); + } + }; + var this_1 = this; + for (var _i = 0, _a = instruction.unrender; _i < _a.length; _i++) { + var result = _a[_i].result; + _loop_1(result); + } + for (var _b = 0, _c = instruction.render; _b < _c.length; _b++) { + var _d = _c[_b], result = _d.result, elements = _d.elements; + if (result.valid) { + continue; + } + var targets = this.interestingElements(elements); + if (targets.length) { + this.errorsInternal.push({ error: result, targets: targets }); + } + } + this.sort(); + this.errors = this.errorsInternal; + }; + ValidationErrorsCustomAttribute.prototype.bind = function () { + if (!this.controller) { + this.controller = this.controllerAccessor(); + } + // this will call render() with the side-effect of updating this.errors + this.controller.addRenderer(this); + }; + ValidationErrorsCustomAttribute.prototype.unbind = function () { + if (this.controller) { + this.controller.removeRenderer(this); + } + }; + __decorate([ + aureliaTemplating.bindable({ defaultBindingMode: aureliaBinding.bindingMode.oneWay }) + ], ValidationErrorsCustomAttribute.prototype, "controller", void 0); + __decorate([ + aureliaTemplating.bindable({ primaryProperty: true, defaultBindingMode: aureliaBinding.bindingMode.twoWay }) + ], ValidationErrorsCustomAttribute.prototype, "errors", void 0); + ValidationErrorsCustomAttribute = __decorate([ + aureliaTemplating.customAttribute('validation-errors') + ], ValidationErrorsCustomAttribute); + return ValidationErrorsCustomAttribute; + }()); + + var ValidationRendererCustomAttribute = /** @class */ (function () { + function ValidationRendererCustomAttribute() { + } + ValidationRendererCustomAttribute.prototype.created = function (view) { + this.container = view.container; + }; + ValidationRendererCustomAttribute.prototype.bind = function () { + this.controller = this.container.get(ValidationController); + this.renderer = this.container.get(this.value); + this.controller.addRenderer(this.renderer); + }; + ValidationRendererCustomAttribute.prototype.unbind = function () { + this.controller.removeRenderer(this.renderer); + this.controller = null; + this.renderer = null; + }; + ValidationRendererCustomAttribute = __decorate([ + aureliaTemplating.customAttribute('validation-renderer') + ], ValidationRendererCustomAttribute); + return ValidationRendererCustomAttribute; + }()); + + /** + * Sets, unsets and retrieves rules on an object or constructor function. + */ + var Rules = /** @class */ (function () { + function Rules() { + } + /** + * Applies the rules to a target. + */ + Rules.set = function (target, rules) { + if (target instanceof Function) { + target = target.prototype; + } + Object.defineProperty(target, Rules.key, { enumerable: false, configurable: false, writable: true, value: rules }); + }; + /** + * Removes rules from a target. + */ + Rules.unset = function (target) { + if (target instanceof Function) { + target = target.prototype; + } + target[Rules.key] = null; + }; + /** + * Retrieves the target's rules. + */ + Rules.get = function (target) { + return target[Rules.key] || null; + }; + /** + * The name of the property that stores the rules. + */ + Rules.key = '__rules__'; + return Rules; + }()); + + // tslint:disable:no-empty + var ExpressionVisitor = /** @class */ (function () { + function ExpressionVisitor() { + } + ExpressionVisitor.prototype.visitChain = function (chain) { + this.visitArgs(chain.expressions); + }; + ExpressionVisitor.prototype.visitBindingBehavior = function (behavior) { + behavior.expression.accept(this); + this.visitArgs(behavior.args); + }; + ExpressionVisitor.prototype.visitValueConverter = function (converter) { + converter.expression.accept(this); + this.visitArgs(converter.args); + }; + ExpressionVisitor.prototype.visitAssign = function (assign) { + assign.target.accept(this); + assign.value.accept(this); + }; + ExpressionVisitor.prototype.visitConditional = function (conditional) { + conditional.condition.accept(this); + conditional.yes.accept(this); + conditional.no.accept(this); + }; + ExpressionVisitor.prototype.visitAccessThis = function (access) { + access.ancestor = access.ancestor; + }; + ExpressionVisitor.prototype.visitAccessScope = function (access) { + access.name = access.name; + }; + ExpressionVisitor.prototype.visitAccessMember = function (access) { + access.object.accept(this); + }; + ExpressionVisitor.prototype.visitAccessKeyed = function (access) { + access.object.accept(this); + access.key.accept(this); + }; + ExpressionVisitor.prototype.visitCallScope = function (call) { + this.visitArgs(call.args); + }; + ExpressionVisitor.prototype.visitCallFunction = function (call) { + call.func.accept(this); + this.visitArgs(call.args); + }; + ExpressionVisitor.prototype.visitCallMember = function (call) { + call.object.accept(this); + this.visitArgs(call.args); + }; + ExpressionVisitor.prototype.visitPrefix = function (prefix) { + prefix.expression.accept(this); + }; + ExpressionVisitor.prototype.visitBinary = function (binary) { + binary.left.accept(this); + binary.right.accept(this); + }; + ExpressionVisitor.prototype.visitLiteralPrimitive = function (literal) { + literal.value = literal.value; + }; + ExpressionVisitor.prototype.visitLiteralArray = function (literal) { + this.visitArgs(literal.elements); + }; + ExpressionVisitor.prototype.visitLiteralObject = function (literal) { + this.visitArgs(literal.values); + }; + ExpressionVisitor.prototype.visitLiteralString = function (literal) { + literal.value = literal.value; + }; + ExpressionVisitor.prototype.visitArgs = function (args) { + for (var i = 0; i < args.length; i++) { + args[i].accept(this); + } + }; + return ExpressionVisitor; + }()); + + var ValidationMessageParser = /** @class */ (function () { + function ValidationMessageParser(bindinqLanguage) { + this.bindinqLanguage = bindinqLanguage; + this.emptyStringExpression = new aureliaBinding.LiteralString(''); + this.nullExpression = new aureliaBinding.LiteralPrimitive(null); + this.undefinedExpression = new aureliaBinding.LiteralPrimitive(undefined); + this.cache = {}; + } + ValidationMessageParser.prototype.parse = function (message) { + if (this.cache[message] !== undefined) { + return this.cache[message]; + } + var parts = this.bindinqLanguage.parseInterpolation(null, message); + if (parts === null) { + return new aureliaBinding.LiteralString(message); + } + var expression = new aureliaBinding.LiteralString(parts[0]); + for (var i = 1; i < parts.length; i += 2) { + expression = new aureliaBinding.Binary('+', expression, new aureliaBinding.Binary('+', this.coalesce(parts[i]), new aureliaBinding.LiteralString(parts[i + 1]))); + } + MessageExpressionValidator.validate(expression, message); + this.cache[message] = expression; + return expression; + }; + ValidationMessageParser.prototype.coalesce = function (part) { + // part === null || part === undefined ? '' : part + return new aureliaBinding.Conditional(new aureliaBinding.Binary('||', new aureliaBinding.Binary('===', part, this.nullExpression), new aureliaBinding.Binary('===', part, this.undefinedExpression)), this.emptyStringExpression, new aureliaBinding.CallMember(part, 'toString', [])); + }; + ValidationMessageParser.inject = [aureliaTemplating.BindingLanguage]; + return ValidationMessageParser; + }()); + var MessageExpressionValidator = /** @class */ (function (_super) { + __extends(MessageExpressionValidator, _super); + function MessageExpressionValidator(originalMessage) { + var _this = _super.call(this) || this; + _this.originalMessage = originalMessage; + return _this; + } + MessageExpressionValidator.validate = function (expression, originalMessage) { + var visitor = new MessageExpressionValidator(originalMessage); + expression.accept(visitor); + }; + MessageExpressionValidator.prototype.visitAccessScope = function (access) { + if (access.ancestor !== 0) { + throw new Error('$parent is not permitted in validation message expressions.'); + } + if (['displayName', 'propertyName', 'value', 'object', 'config', 'getDisplayName'].indexOf(access.name) !== -1) { + LogManager.getLogger('aurelia-validation') + // tslint:disable-next-line:max-line-length + .warn("Did you mean to use \"$" + access.name + "\" instead of \"" + access.name + "\" in this validation message template: \"" + this.originalMessage + "\"?"); + } + }; + return MessageExpressionValidator; + }(ExpressionVisitor)); + + /** + * Dictionary of validation messages. [messageKey]: messageExpression + */ + var validationMessages = { + /** + * The default validation message. Used with rules that have no standard message. + */ + default: "${$displayName} is invalid.", + required: "${$displayName} is required.", + matches: "${$displayName} is not correctly formatted.", + email: "${$displayName} is not a valid email.", + minLength: "${$displayName} must be at least ${$config.length} character${$config.length === 1 ? '' : 's'}.", + maxLength: "${$displayName} cannot be longer than ${$config.length} character${$config.length === 1 ? '' : 's'}.", + minItems: "${$displayName} must contain at least ${$config.count} item${$config.count === 1 ? '' : 's'}.", + maxItems: "${$displayName} cannot contain more than ${$config.count} item${$config.count === 1 ? '' : 's'}.", + min: "${$displayName} must be at least ${$config.constraint}.", + max: "${$displayName} must be at most ${$config.constraint}.", + range: "${$displayName} must be between or equal to ${$config.min} and ${$config.max}.", + between: "${$displayName} must be between but not equal to ${$config.min} and ${$config.max}.", + equals: "${$displayName} must be ${$config.expectedValue}.", + }; + /** + * Retrieves validation messages and property display names. + */ + var ValidationMessageProvider = /** @class */ (function () { + function ValidationMessageProvider(parser) { + this.parser = parser; + } + /** + * Returns a message binding expression that corresponds to the key. + * @param key The message key. + */ + ValidationMessageProvider.prototype.getMessage = function (key) { + var message; + if (key in validationMessages) { + message = validationMessages[key]; + } + else { + message = validationMessages['default']; + } + return this.parser.parse(message); + }; + /** + * Formulates a property display name using the property name and the configured + * displayName (if provided). + * Override this with your own custom logic. + * @param propertyName The property name. + */ + ValidationMessageProvider.prototype.getDisplayName = function (propertyName, displayName) { + if (displayName !== null && displayName !== undefined) { + return (displayName instanceof Function) ? displayName() : displayName; + } + // split on upper-case letters. + var words = propertyName.toString().split(/(?=[A-Z])/).join(' '); + // capitalize first letter. + return words.charAt(0).toUpperCase() + words.slice(1); + }; + ValidationMessageProvider.inject = [ValidationMessageParser]; + return ValidationMessageProvider; + }()); + + /** + * Validates. + * Responsible for validating objects and properties. + */ + var StandardValidator = /** @class */ (function (_super) { + __extends(StandardValidator, _super); + function StandardValidator(messageProvider, resources) { + var _this = _super.call(this) || this; + _this.messageProvider = messageProvider; + _this.lookupFunctions = resources.lookupFunctions; + _this.getDisplayName = messageProvider.getDisplayName.bind(messageProvider); + return _this; + } + /** + * Validates the specified property. + * @param object The object to validate. + * @param propertyName The name of the property to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + StandardValidator.prototype.validateProperty = function (object, propertyName, rules) { + return this.validate(object, propertyName, rules || null); + }; + /** + * Validates all rules for specified object and it's properties. + * @param object The object to validate. + * @param rules Optional. If unspecified, the rules will be looked up using the metadata + * for the object created by ValidationRules....on(class/object) + */ + StandardValidator.prototype.validateObject = function (object, rules) { + return this.validate(object, null, rules || null); + }; + /** + * Determines whether a rule exists in a set of rules. + * @param rules The rules to search. + * @parem rule The rule to find. + */ + StandardValidator.prototype.ruleExists = function (rules, rule) { + var i = rules.length; + while (i--) { + if (rules[i].indexOf(rule) !== -1) { + return true; + } + } + return false; + }; + StandardValidator.prototype.getMessage = function (rule, object, value) { + var expression = rule.message || this.messageProvider.getMessage(rule.messageKey); + // tslint:disable-next-line:prefer-const + var _a = rule.property, propertyName = _a.name, displayName = _a.displayName; + if (propertyName !== null) { + displayName = this.messageProvider.getDisplayName(propertyName, displayName); + } + var overrideContext = { + $displayName: displayName, + $propertyName: propertyName, + $value: value, + $object: object, + $config: rule.config, + // returns the name of a given property, given just the property name (irrespective of the property's displayName) + // split on capital letters, first letter ensured to be capitalized + $getDisplayName: this.getDisplayName + }; + return expression.evaluate({ bindingContext: object, overrideContext: overrideContext }, this.lookupFunctions); + }; + StandardValidator.prototype.validateRuleSequence = function (object, propertyName, ruleSequence, sequence, results) { + var _this = this; + // are we validating all properties or a single property? + var validateAllProperties = propertyName === null || propertyName === undefined; + var rules = ruleSequence[sequence]; + var allValid = true; + // validate each rule. + var promises = []; + var _loop_1 = function (i) { + var rule = rules[i]; + // is the rule related to the property we're validating. + // tslint:disable-next-line:triple-equals | Use loose equality for property keys + if (!validateAllProperties && rule.property.name != propertyName) { + return "continue"; + } + // is this a conditional rule? is the condition met? + if (rule.when && !rule.when(object)) { + return "continue"; + } + // validate. + var value = rule.property.name === null ? object : object[rule.property.name]; + var promiseOrBoolean = rule.condition(value, object); + if (!(promiseOrBoolean instanceof Promise)) { + promiseOrBoolean = Promise.resolve(promiseOrBoolean); + } + promises.push(promiseOrBoolean.then(function (valid) { + var message = valid ? null : _this.getMessage(rule, object, value); + results.push(new ValidateResult(rule, object, rule.property.name, valid, message)); + allValid = allValid && valid; + return valid; + })); + }; + for (var i = 0; i < rules.length; i++) { + _loop_1(i); + } + return Promise.all(promises) + .then(function () { + sequence++; + if (allValid && sequence < ruleSequence.length) { + return _this.validateRuleSequence(object, propertyName, ruleSequence, sequence, results); + } + return results; + }); + }; + StandardValidator.prototype.validate = function (object, propertyName, rules) { + // rules specified? + if (!rules) { + // no. attempt to locate the rules. + rules = Rules.get(object); + } + // any rules? + if (!rules || rules.length === 0) { + return Promise.resolve([]); + } + return this.validateRuleSequence(object, propertyName, rules, 0, []); + }; + StandardValidator.inject = [ValidationMessageProvider, aureliaTemplating.ViewResources]; + return StandardValidator; + }(Validator)); + + /** + * Part of the fluent rule API. Enables customizing property rules. + */ + var FluentRuleCustomizer = /** @class */ (function () { + function FluentRuleCustomizer(property, condition, config, fluentEnsure, fluentRules, parsers) { + if (config === void 0) { config = {}; } + this.fluentEnsure = fluentEnsure; + this.fluentRules = fluentRules; + this.parsers = parsers; + this.rule = { + property: property, + condition: condition, + config: config, + when: null, + messageKey: 'default', + message: null, + sequence: fluentRules.sequence + }; + this.fluentEnsure._addRule(this.rule); + } + /** + * Validate subsequent rules after previously declared rules have + * been validated successfully. Use to postpone validation of costly + * rules until less expensive rules pass validation. + */ + FluentRuleCustomizer.prototype.then = function () { + this.fluentRules.sequence++; + return this; + }; + /** + * Specifies the key to use when looking up the rule's validation message. + */ + FluentRuleCustomizer.prototype.withMessageKey = function (key) { + this.rule.messageKey = key; + this.rule.message = null; + return this; + }; + /** + * Specifies rule's validation message. + */ + FluentRuleCustomizer.prototype.withMessage = function (message) { + this.rule.messageKey = 'custom'; + this.rule.message = this.parsers.message.parse(message); + return this; + }; + /** + * Specifies a condition that must be met before attempting to validate the rule. + * @param condition A function that accepts the object as a parameter and returns true + * or false whether the rule should be evaluated. + */ + FluentRuleCustomizer.prototype.when = function (condition) { + this.rule.when = condition; + return this; + }; + /** + * Tags the rule instance, enabling the rule to be found easily + * using ValidationRules.taggedRules(rules, tag) + */ + FluentRuleCustomizer.prototype.tag = function (tag) { + this.rule.tag = tag; + return this; + }; + ///// FluentEnsure APIs ///// + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + FluentRuleCustomizer.prototype.ensure = function (subject) { + return this.fluentEnsure.ensure(subject); + }; + /** + * Targets an object with validation rules. + */ + FluentRuleCustomizer.prototype.ensureObject = function () { + return this.fluentEnsure.ensureObject(); + }; + Object.defineProperty(FluentRuleCustomizer.prototype, "rules", { + /** + * Rules that have been defined using the fluent API. + */ + get: function () { + return this.fluentEnsure.rules; + }, + enumerable: true, + configurable: true + }); + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + FluentRuleCustomizer.prototype.on = function (target) { + return this.fluentEnsure.on(target); + }; + ///////// FluentRules APIs ///////// + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + FluentRuleCustomizer.prototype.satisfies = function (condition, config) { + return this.fluentRules.satisfies(condition, config); + }; + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + FluentRuleCustomizer.prototype.satisfiesRule = function (name) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + var _a; + return (_a = this.fluentRules).satisfiesRule.apply(_a, [name].concat(args)); + }; + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + FluentRuleCustomizer.prototype.required = function () { + return this.fluentRules.required(); + }; + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.matches = function (regex) { + return this.fluentRules.matches(regex); + }; + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.email = function () { + return this.fluentRules.email(); + }; + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.minLength = function (length) { + return this.fluentRules.minLength(length); + }; + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.maxLength = function (length) { + return this.fluentRules.maxLength(length); + }; + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.minItems = function (count) { + return this.fluentRules.minItems(count); + }; + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.maxItems = function (count) { + return this.fluentRules.maxItems(count); + }; + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.min = function (value) { + return this.fluentRules.min(value); + }; + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.max = function (value) { + return this.fluentRules.max(value); + }; + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.range = function (min, max) { + return this.fluentRules.range(min, max); + }; + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRuleCustomizer.prototype.between = function (min, max) { + return this.fluentRules.between(min, max); + }; + /** + * Applies the "equals" validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRuleCustomizer.prototype.equals = function (expectedValue) { + return this.fluentRules.equals(expectedValue); + }; + return FluentRuleCustomizer; + }()); + /** + * Part of the fluent rule API. Enables applying rules to properties and objects. + */ + var FluentRules = /** @class */ (function () { + function FluentRules(fluentEnsure, parsers, property) { + this.fluentEnsure = fluentEnsure; + this.parsers = parsers; + this.property = property; + /** + * Current rule sequence number. Used to postpone evaluation of rules until rules + * with lower sequence number have successfully validated. The "then" fluent API method + * manages this property, there's usually no need to set it directly. + */ + this.sequence = 0; + } + /** + * Sets the display name of the ensured property. + */ + FluentRules.prototype.displayName = function (name) { + this.property.displayName = name; + return this; + }; + /** + * Applies an ad-hoc rule function to the ensured property or object. + * @param condition The function to validate the rule. + * Will be called with two arguments, the property value and the object. + * Should return a boolean or a Promise that resolves to a boolean. + */ + FluentRules.prototype.satisfies = function (condition, config) { + return new FluentRuleCustomizer(this.property, condition, config, this.fluentEnsure, this, this.parsers); + }; + /** + * Applies a rule by name. + * @param name The name of the custom or standard rule. + * @param args The rule's arguments. + */ + FluentRules.prototype.satisfiesRule = function (name) { + var _this = this; + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + var rule = FluentRules.customRules[name]; + if (!rule) { + // standard rule? + rule = this[name]; + if (rule instanceof Function) { + return rule.call.apply(rule, [this].concat(args)); + } + throw new Error("Rule with name \"" + name + "\" does not exist."); + } + var config = rule.argsToConfig ? rule.argsToConfig.apply(rule, args) : undefined; + return this.satisfies(function (value, obj) { + var _a; + return (_a = rule.condition).call.apply(_a, [_this, value, obj].concat(args)); + }, config) + .withMessageKey(name); + }; + /** + * Applies the "required" rule to the property. + * The value cannot be null, undefined or whitespace. + */ + FluentRules.prototype.required = function () { + return this.satisfies(function (value) { + return value !== null + && value !== undefined + && !(isString(value) && !/\S/.test(value)); + }).withMessageKey('required'); + }; + /** + * Applies the "matches" rule to the property. + * Value must match the specified regular expression. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.matches = function (regex) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length === 0 || regex.test(value); }) + .withMessageKey('matches'); + }; + /** + * Applies the "email" rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.email = function () { + // regex from https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address + /* tslint:disable:max-line-length */ + return this.matches(/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/) + /* tslint:enable:max-line-length */ + .withMessageKey('email'); + }; + /** + * Applies the "minLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.minLength = function (length) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length === 0 || value.length >= length; }, { length: length }) + .withMessageKey('minLength'); + }; + /** + * Applies the "maxLength" STRING validation rule to the property. + * null, undefined and empty-string values are considered valid. + */ + FluentRules.prototype.maxLength = function (length) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length === 0 || value.length <= length; }, { length: length }) + .withMessageKey('maxLength'); + }; + /** + * Applies the "minItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRules.prototype.minItems = function (count) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length >= count; }, { count: count }) + .withMessageKey('minItems'); + }; + /** + * Applies the "maxItems" ARRAY validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRules.prototype.maxItems = function (count) { + return this.satisfies(function (value) { return value === null || value === undefined || value.length <= count; }, { count: count }) + .withMessageKey('maxItems'); + }; + /** + * Applies the "min" NUMBER validation rule to the property. + * Value must be greater than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRules.prototype.min = function (constraint) { + return this.satisfies(function (value) { return value === null || value === undefined || value >= constraint; }, { constraint: constraint }) + .withMessageKey('min'); + }; + /** + * Applies the "max" NUMBER validation rule to the property. + * Value must be less than or equal to the specified constraint. + * null and undefined values are considered valid. + */ + FluentRules.prototype.max = function (constraint) { + return this.satisfies(function (value) { return value === null || value === undefined || value <= constraint; }, { constraint: constraint }) + .withMessageKey('max'); + }; + /** + * Applies the "range" NUMBER validation rule to the property. + * Value must be between or equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRules.prototype.range = function (min, max) { + return this.satisfies(function (value) { return value === null || value === undefined || (value >= min && value <= max); }, { min: min, max: max }) + .withMessageKey('range'); + }; + /** + * Applies the "between" NUMBER validation rule to the property. + * Value must be between but not equal to the specified min and max. + * null and undefined values are considered valid. + */ + FluentRules.prototype.between = function (min, max) { + return this.satisfies(function (value) { return value === null || value === undefined || (value > min && value < max); }, { min: min, max: max }) + .withMessageKey('between'); + }; + /** + * Applies the "equals" validation rule to the property. + * null and undefined values are considered valid. + */ + FluentRules.prototype.equals = function (expectedValue) { + return this.satisfies(function (value) { return value === null || value === undefined || value === '' || value === expectedValue; }, { expectedValue: expectedValue }) + .withMessageKey('equals'); + }; + FluentRules.customRules = {}; + return FluentRules; + }()); + /** + * Part of the fluent rule API. Enables targeting properties and objects with rules. + */ + var FluentEnsure = /** @class */ (function () { + function FluentEnsure(parsers) { + this.parsers = parsers; + /** + * Rules that have been defined using the fluent API. + */ + this.rules = []; + } + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor + * function. + */ + FluentEnsure.prototype.ensure = function (property) { + this.assertInitialized(); + var name = this.parsers.property.parse(property); + var fluentRules = new FluentRules(this, this.parsers, { name: name, displayName: null }); + return this.mergeRules(fluentRules, name); + }; + /** + * Targets an object with validation rules. + */ + FluentEnsure.prototype.ensureObject = function () { + this.assertInitialized(); + var fluentRules = new FluentRules(this, this.parsers, { name: null, displayName: null }); + return this.mergeRules(fluentRules, null); + }; + /** + * Applies the rules to a class or object, making them discoverable by the StandardValidator. + * @param target A class or object. + */ + FluentEnsure.prototype.on = function (target) { + Rules.set(target, this.rules); + return this; + }; + /** + * Adds a rule definition to the sequenced ruleset. + * @internal + */ + FluentEnsure.prototype._addRule = function (rule) { + while (this.rules.length < rule.sequence + 1) { + this.rules.push([]); + } + this.rules[rule.sequence].push(rule); + }; + FluentEnsure.prototype.assertInitialized = function () { + if (this.parsers) { + return; + } + throw new Error("Did you forget to add \".plugin('aurelia-validation')\" to your main.js?"); + }; + FluentEnsure.prototype.mergeRules = function (fluentRules, propertyName) { + // tslint:disable-next-line:triple-equals | Use loose equality for property keys + var existingRules = this.rules.find(function (r) { return r.length > 0 && r[0].property.name == propertyName; }); + if (existingRules) { + var rule = existingRules[existingRules.length - 1]; + fluentRules.sequence = rule.sequence; + if (rule.property.displayName !== null) { + fluentRules = fluentRules.displayName(rule.property.displayName); + } + } + return fluentRules; + }; + return FluentEnsure; + }()); + /** + * Fluent rule definition API. + */ + var ValidationRules = /** @class */ (function () { + function ValidationRules() { + } + ValidationRules.initialize = function (messageParser, propertyParser) { + this.parsers = { + message: messageParser, + property: propertyParser + }; + }; + /** + * Target a property with validation rules. + * @param property The property to target. Can be the property name or a property accessor function. + */ + ValidationRules.ensure = function (property) { + return new FluentEnsure(ValidationRules.parsers).ensure(property); + }; + /** + * Targets an object with validation rules. + */ + ValidationRules.ensureObject = function () { + return new FluentEnsure(ValidationRules.parsers).ensureObject(); + }; + /** + * Defines a custom rule. + * @param name The name of the custom rule. Also serves as the message key. + * @param condition The rule function. + * @param message The message expression + * @param argsToConfig A function that maps the rule's arguments to a "config" + * object that can be used when evaluating the message expression. + */ + ValidationRules.customRule = function (name, condition, message, argsToConfig) { + validationMessages[name] = message; + FluentRules.customRules[name] = { condition: condition, argsToConfig: argsToConfig }; + }; + /** + * Returns rules with the matching tag. + * @param rules The rules to search. + * @param tag The tag to search for. + */ + ValidationRules.taggedRules = function (rules, tag) { + return rules.map(function (x) { return x.filter(function (r) { return r.tag === tag; }); }); + }; + /** + * Returns rules that have no tag. + * @param rules The rules to search. + */ + ValidationRules.untaggedRules = function (rules) { + return rules.map(function (x) { return x.filter(function (r) { return r.tag === undefined; }); }); + }; + /** + * Removes the rules from a class or object. + * @param target A class or object. + */ + ValidationRules.off = function (target) { + Rules.unset(target); + }; + return ValidationRules; + }()); + + // Exports + /** + * Aurelia Validation Configuration API + */ + var AureliaValidationConfiguration = /** @class */ (function () { + function AureliaValidationConfiguration() { + this.validatorType = StandardValidator; + } + /** + * Use a custom Validator implementation. + */ + AureliaValidationConfiguration.prototype.customValidator = function (type) { + this.validatorType = type; + }; + /** + * Applies the configuration. + */ + AureliaValidationConfiguration.prototype.apply = function (container) { + var validator = container.get(this.validatorType); + container.registerInstance(Validator, validator); + }; + return AureliaValidationConfiguration; + }()); + /** + * Configures the plugin. + */ + function configure( + // tslint:disable-next-line:ban-types + frameworkConfig, callback) { + // the fluent rule definition API needs the parser to translate messages + // to interpolation expressions. + var messageParser = frameworkConfig.container.get(ValidationMessageParser); + var propertyParser = frameworkConfig.container.get(PropertyAccessorParser); + ValidationRules.initialize(messageParser, propertyParser); + // configure... + var config = new AureliaValidationConfiguration(); + if (callback instanceof Function) { + callback(config); + } + config.apply(frameworkConfig.container); + // globalize the behaviors. + if (frameworkConfig.globalResources) { + frameworkConfig.globalResources(ValidateBindingBehavior, ValidateManuallyBindingBehavior, ValidateOnBlurBindingBehavior, ValidateOnChangeBindingBehavior, ValidateOnChangeOrBlurBindingBehavior, ValidationErrorsCustomAttribute, ValidationRendererCustomAttribute); + } + } + + exports.AureliaValidationConfiguration = AureliaValidationConfiguration; + exports.configure = configure; + exports.getTargetDOMElement = getTargetDOMElement; + exports.getPropertyInfo = getPropertyInfo; + exports.PropertyAccessorParser = PropertyAccessorParser; + exports.getAccessorExpression = getAccessorExpression; + exports.ValidateBindingBehavior = ValidateBindingBehavior; + exports.ValidateManuallyBindingBehavior = ValidateManuallyBindingBehavior; + exports.ValidateOnBlurBindingBehavior = ValidateOnBlurBindingBehavior; + exports.ValidateOnChangeBindingBehavior = ValidateOnChangeBindingBehavior; + exports.ValidateOnChangeOrBlurBindingBehavior = ValidateOnChangeOrBlurBindingBehavior; + exports.ValidateEvent = ValidateEvent; + exports.ValidateResult = ValidateResult; + exports.ValidationController = ValidationController; + exports.ValidationControllerFactory = ValidationControllerFactory; + exports.ValidationErrorsCustomAttribute = ValidationErrorsCustomAttribute; + exports.ValidationRendererCustomAttribute = ValidationRendererCustomAttribute; + exports.Validator = Validator; + exports.Rules = Rules; + exports.StandardValidator = StandardValidator; + exports.validationMessages = validationMessages; + exports.ValidationMessageProvider = ValidationMessageProvider; + exports.ValidationMessageParser = ValidationMessageParser; + exports.MessageExpressionValidator = MessageExpressionValidator; + exports.FluentRuleCustomizer = FluentRuleCustomizer; + exports.FluentRules = FluentRules; + exports.FluentEnsure = FluentEnsure; + exports.ValidationRules = ValidationRules; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); diff --git a/doc/api.json b/doc/api.json index b15aae52..079e8c28 100644 --- a/doc/api.json +++ b/doc/api.json @@ -1 +1 @@ -{"name":"aurelia-validation","children":[{"id":52,"name":"validateTrigger","kind":4,"kindString":"Enumeration","flags":{"isExported":true},"comment":{"shortText":"Validation triggers."},"children":[{"id":54,"name":"blur","kind":16,"kindString":"Enumeration member","flags":{"isExported":true},"comment":{"shortText":"Validate the binding when the binding's target element fires a DOM \"blur\" event."},"sources":[{"fileName":"aurelia-validation.d.ts","line":136,"character":12}],"defaultValue":"1"},{"id":55,"name":"change","kind":16,"kindString":"Enumeration member","flags":{"isExported":true},"comment":{"shortText":"Validate the binding when it updates the model due to a change in the view."},"sources":[{"fileName":"aurelia-validation.d.ts","line":140,"character":14}],"defaultValue":"2"},{"id":56,"name":"changeOrBlur","kind":16,"kindString":"Enumeration member","flags":{"isExported":true},"comment":{"shortText":"Validate the binding when the binding's target element fires a DOM \"blur\" event and\nwhen it updates the model due to a change in the view."},"sources":[{"fileName":"aurelia-validation.d.ts","line":145,"character":20}],"defaultValue":"3"},{"id":53,"name":"manual","kind":16,"kindString":"Enumeration member","flags":{"isExported":true},"comment":{"shortText":"Manual validation. Use the controller's `validate()` and `reset()` methods\nto validate all bindings."},"sources":[{"fileName":"aurelia-validation.d.ts","line":132,"character":14}],"defaultValue":"0"}],"groups":[{"title":"Enumeration members","kind":16,"children":[54,55,56,53]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":127,"character":31}]},{"id":732,"name":"AureliaValidationConfiguration","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Aurelia Validation Configuration API"},"children":[{"id":733,"name":"validatorType","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":959,"character":29}],"type":{"type":"intrinsic","name":"any"}},{"id":741,"name":"apply","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":742,"name":"apply","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the configuration."},"parameters":[{"id":743,"name":"container","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Container"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":969,"character":13}]},{"id":734,"name":"customValidator","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":735,"name":"customValidator","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Use a custom Validator implementation."},"parameters":[{"id":736,"name":"type","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reflection","declaration":{"id":737,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"children":[{"id":738,"name":"constructor","kind":512,"kindString":"Constructor","flags":{},"signatures":[{"id":739,"name":"new __type","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":740,"name":"args","kind":32768,"kindString":"Parameter","flags":{"isRest":true},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}}],"type":{"type":"reference","name":"Validator","id":38}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":963,"character":31}]}],"groups":[{"title":"Constructors","kind":512,"children":[738]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":963,"character":29}]}}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":963,"character":23}]}],"groups":[{"title":"Properties","kind":1024,"children":[733]},{"title":"Methods","kind":2048,"children":[741,734]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":958,"character":47}]},{"id":350,"name":"ExpressionVisitor","kind":128,"kindString":"Class","flags":{"isExported":true},"children":[{"id":405,"name":"visitArgs","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":579,"character":25}],"type":{"type":"intrinsic","name":"any"}},{"id":375,"name":"visitAccessKeyed","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":376,"name":"visitAccessKeyed","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":377,"name":"access","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AccessKeyed"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":569,"character":24}]},{"id":372,"name":"visitAccessMember","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":373,"name":"visitAccessMember","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":374,"name":"access","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AccessMember"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":568,"character":25}]},{"id":369,"name":"visitAccessScope","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":370,"name":"visitAccessScope","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":371,"name":"access","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AccessScope"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":567,"character":24}]},{"id":366,"name":"visitAccessThis","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":367,"name":"visitAccessThis","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":368,"name":"access","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AccessThis","id":775}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":566,"character":23}]},{"id":360,"name":"visitAssign","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":361,"name":"visitAssign","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":362,"name":"assign","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Assign","id":774}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":564,"character":19}]},{"id":390,"name":"visitBinary","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":391,"name":"visitBinary","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":392,"name":"binary","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Binary"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":574,"character":19}]},{"id":354,"name":"visitBindingBehavior","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":355,"name":"visitBindingBehavior","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":356,"name":"behavior","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"BindingBehavior"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":562,"character":28}]},{"id":381,"name":"visitCallFunction","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":382,"name":"visitCallFunction","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":383,"name":"call","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"CallFunction","id":778}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":571,"character":25}]},{"id":384,"name":"visitCallMember","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":385,"name":"visitCallMember","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":386,"name":"call","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"CallMember"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":572,"character":23}]},{"id":378,"name":"visitCallScope","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":379,"name":"visitCallScope","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":380,"name":"call","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"CallScope","id":777}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":570,"character":22}]},{"id":351,"name":"visitChain","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":352,"name":"visitChain","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":353,"name":"chain","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Chain","id":773}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":561,"character":18}]},{"id":363,"name":"visitConditional","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":364,"name":"visitConditional","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":365,"name":"conditional","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Conditional"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":565,"character":24}]},{"id":396,"name":"visitLiteralArray","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":397,"name":"visitLiteralArray","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":398,"name":"literal","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"LiteralArray","id":781}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":576,"character":25}]},{"id":399,"name":"visitLiteralObject","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":400,"name":"visitLiteralObject","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":401,"name":"literal","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"LiteralObject","id":782}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":577,"character":26}]},{"id":393,"name":"visitLiteralPrimitive","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":394,"name":"visitLiteralPrimitive","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":395,"name":"literal","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"LiteralPrimitive","id":780}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":575,"character":29}]},{"id":402,"name":"visitLiteralString","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":403,"name":"visitLiteralString","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":404,"name":"literal","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"LiteralString","id":783}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":578,"character":26}]},{"id":387,"name":"visitPrefix","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":388,"name":"visitPrefix","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":389,"name":"prefix","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"PrefixNot","id":779}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":573,"character":19}]},{"id":357,"name":"visitValueConverter","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":358,"name":"visitValueConverter","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":359,"name":"converter","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValueConverter"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":563,"character":27}]}],"groups":[{"title":"Properties","kind":1024,"children":[405]},{"title":"Methods","kind":2048,"children":[375,372,369,366,360,390,354,381,384,378,351,363,396,399,393,402,387,357]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":560,"character":34}],"extendedBy":[{"type":"reference","name":"MessageExpressionValidator","id":420}]},{"id":673,"name":"FluentEnsure","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Part of the fluent rule API. Enables targeting properties and objects with rules."},"typeParameter":[{"id":674,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}}],"children":[{"id":677,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":678,"name":"new FluentEnsure","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":679,"name":"parsers","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Parsers","id":729}}],"type":{"type":"reference","name":"FluentEnsure","id":673}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":867,"character":38}]},{"id":689,"name":"assertInitialized","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":884,"character":33}],"type":{"type":"intrinsic","name":"any"}},{"id":690,"name":"mergeRules","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":885,"character":26}],"type":{"type":"intrinsic","name":"any"}},{"id":675,"name":"parsers","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":863,"character":23}],"type":{"type":"intrinsic","name":"any"}},{"id":676,"name":"rules","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"Rules that have been defined using the fluent API."},"sources":[{"fileName":"aurelia-validation.d.ts","line":867,"character":13}],"type":{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"any"}]}}}},{"id":680,"name":"ensure","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":681,"name":"ensure","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Target a property with validation rules."},"typeParameter":[{"id":682,"name":"TValue","kind":131072,"kindString":"Type parameter","flags":{}}],"parameters":[{"id":683,"name":"property","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The property to target. Can be the property name or a property accessor\nfunction.\n"},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"},{"type":"reference","name":"PropertyAccessor","id":761,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}]}}],"type":{"type":"reference","name":"FluentRules","id":609,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"any"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":874,"character":14}]},{"id":684,"name":"ensureObject","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":685,"name":"ensureObject","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Targets an object with validation rules."},"type":{"type":"reference","name":"FluentRules","id":609,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"any"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":878,"character":20}]},{"id":686,"name":"on","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":687,"name":"on","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the rules to a class or object, making them discoverable by the StandardValidator."},"parameters":[{"id":688,"name":"target","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"A class or object.\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"this"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":883,"character":10}]}],"groups":[{"title":"Constructors","kind":512,"children":[677]},{"title":"Properties","kind":1024,"children":[689,690,675,676]},{"title":"Methods","kind":2048,"children":[680,684,686]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":862,"character":29}]},{"id":526,"name":"FluentRuleCustomizer","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Part of the fluent rule API. Enables customizing property rules."},"typeParameter":[{"id":527,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}},{"id":528,"name":"TValue","kind":131072,"kindString":"Type parameter","flags":{}}],"children":[{"id":533,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":534,"name":"new FluentRuleCustomizer","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":535,"name":"property","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"RuleProperty","id":317}},{"id":536,"name":"condition","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reflection","declaration":{"id":537,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":538,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":539,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TValue"}},{"id":540,"name":"object","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"reference","name":"TObject","id":527}}],"type":{"type":"union","types":[{"type":"intrinsic","name":"boolean"},{"type":"reference","name":"Promise","typeArguments":[{"type":"intrinsic","name":"boolean"}]}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":681,"character":54}]}}},{"id":541,"name":"config","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"union","types":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"undefined"}]}},{"id":542,"name":"fluentEnsure","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"FluentEnsure","id":673,"typeArguments":[{"type":"typeParameter","name":"TObject"}]}},{"id":543,"name":"fluentRules","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"FluentRules","id":609,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}},{"id":544,"name":"parsers","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Parsers","id":729}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":680,"character":21}]},{"id":529,"name":"fluentEnsure","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":677,"character":28}],"type":{"type":"intrinsic","name":"any"}},{"id":530,"name":"fluentRules","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":678,"character":27}],"type":{"type":"intrinsic","name":"any"}},{"id":531,"name":"parsers","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":679,"character":23}],"type":{"type":"intrinsic","name":"any"}},{"id":532,"name":"rule","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":680,"character":20}],"type":{"type":"intrinsic","name":"any"}},{"id":571,"name":"rules","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"Rules that have been defined using the fluent API."},"sources":[{"fileName":"aurelia-validation.d.ts","line":719,"character":22}],"type":{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"any"}]}}}},{"id":592,"name":"email","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":593,"name":"email","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"email\" rule to the property.\nnull, undefined and empty-string values are considered valid."},"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":753,"character":13}]},{"id":562,"name":"ensure","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":563,"name":"ensure","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Target a property with validation rules."},"typeParameter":[{"id":564,"name":"TValue2","kind":131072,"kindString":"Type parameter","flags":{}}],"parameters":[{"id":565,"name":"subject","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"reflection","declaration":{"id":566,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":567,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":568,"name":"model","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TObject"}}],"type":{"type":"typeParameter","name":"TValue2"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":711,"character":41}]}}]}}],"type":{"type":"reference","name":"FluentRules","id":609,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"any"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":711,"character":14}]},{"id":569,"name":"ensureObject","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":570,"name":"ensureObject","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Targets an object with validation rules."},"type":{"type":"reference","name":"FluentRules","id":609,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"any"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":715,"character":20}]},{"id":606,"name":"equals","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":607,"name":"equals","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"equals\" validation rule to the property.\nnull, undefined and empty-string values are considered valid."},"parameters":[{"id":608,"name":"expectedValue","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TValue"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":778,"character":14}]},{"id":589,"name":"matches","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":590,"name":"matches","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"matches\" rule to the property.\nValue must match the specified regular expression.\nnull, undefined and empty-string values are considered valid."},"parameters":[{"id":591,"name":"regex","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"RegExp"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":748,"character":15}]},{"id":603,"name":"maxItems","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":604,"name":"maxItems","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"maxItems\" ARRAY validation rule to the property.\nnull and undefined values are considered valid."},"parameters":[{"id":605,"name":"count","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":773,"character":16}]},{"id":597,"name":"maxLength","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":598,"name":"maxLength","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"maxLength\" STRING validation rule to the property.\nnull, undefined and empty-string values are considered valid."},"parameters":[{"id":599,"name":"length","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":763,"character":17}]},{"id":600,"name":"minItems","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":601,"name":"minItems","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"minItems\" ARRAY validation rule to the property.\nnull and undefined values are considered valid."},"parameters":[{"id":602,"name":"count","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":768,"character":16}]},{"id":594,"name":"minLength","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":595,"name":"minLength","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"minLength\" STRING validation rule to the property.\nnull, undefined and empty-string values are considered valid."},"parameters":[{"id":596,"name":"length","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":758,"character":17}]},{"id":572,"name":"on","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":573,"name":"on","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the rules to a class or object, making them discoverable by the StandardValidator."},"parameters":[{"id":574,"name":"target","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"A class or object.\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"reference","name":"FluentEnsure","id":673,"typeArguments":[{"type":"typeParameter","name":"TObject"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":724,"character":10}]},{"id":587,"name":"required","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":588,"name":"required","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"required\" rule to the property.\nThe value cannot be null, undefined or whitespace."},"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":742,"character":16}]},{"id":575,"name":"satisfies","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":576,"name":"satisfies","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies an ad-hoc rule function to the ensured property or object."},"parameters":[{"id":577,"name":"condition","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The function to validate the rule.\nWill be called with two arguments, the property value and the object.\nShould return a boolean or a Promise that resolves to a boolean.\n"},"type":{"type":"reflection","declaration":{"id":578,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":579,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":580,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TValue"}},{"id":581,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TObject"}}],"type":{"type":"union","types":[{"type":"intrinsic","name":"boolean"},{"type":"reference","name":"Promise","typeArguments":[{"type":"intrinsic","name":"boolean"}]}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":731,"character":28}]}}},{"id":582,"name":"config","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"intrinsic","name":"undefined"},{"type":"intrinsic","name":"object"}]}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":731,"character":17}]},{"id":583,"name":"satisfiesRule","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":584,"name":"satisfiesRule","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies a rule by name."},"parameters":[{"id":585,"name":"name","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The name of the custom or standard rule."},"type":{"type":"intrinsic","name":"string"}},{"id":586,"name":"args","kind":32768,"kindString":"Parameter","flags":{"isRest":true},"comment":{"text":"The rule's arguments.\n"},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":737,"character":21}]},{"id":559,"name":"tag","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":560,"name":"tag","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Tags the rule instance, enabling the rule to be found easily\nusing ValidationRules.taggedRules(rules, tag)"},"parameters":[{"id":561,"name":"tag","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"this"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":706,"character":11}]},{"id":545,"name":"then","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":546,"name":"then","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Validate subsequent rules after previously declared rules have\nbeen validated successfully. Use to postpone validation of costly\nrules until less expensive rules pass validation."},"type":{"type":"intrinsic","name":"this"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":687,"character":12}]},{"id":553,"name":"when","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":554,"name":"when","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Specifies a condition that must be met before attempting to validate the rule."},"parameters":[{"id":555,"name":"condition","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"A function that accepts the object as a parameter and returns true\nor false whether the rule should be evaluated.\n"},"type":{"type":"reflection","declaration":{"id":556,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":557,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":558,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TObject"}}],"type":{"type":"intrinsic","name":"boolean"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":701,"character":23}]}}}],"type":{"type":"intrinsic","name":"this"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":701,"character":12}]},{"id":550,"name":"withMessage","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":551,"name":"withMessage","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Specifies rule's validation message."},"parameters":[{"id":552,"name":"message","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"this"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":695,"character":19}]},{"id":547,"name":"withMessageKey","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":548,"name":"withMessageKey","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Specifies the key to use when looking up the rule's validation message."},"parameters":[{"id":549,"name":"key","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"this"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":691,"character":22}]}],"groups":[{"title":"Constructors","kind":512,"children":[533]},{"title":"Properties","kind":1024,"children":[529,530,531,532,571]},{"title":"Methods","kind":2048,"children":[592,562,569,606,589,603,597,600,594,572,587,575,583,559,545,553,550,547]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":676,"character":37}]},{"id":609,"name":"FluentRules","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Part of the fluent rule API. Enables applying rules to properties and objects."},"typeParameter":[{"id":610,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}},{"id":611,"name":"TValue","kind":131072,"kindString":"Type parameter","flags":{}}],"children":[{"id":631,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":632,"name":"new FluentRules","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":633,"name":"fluentEnsure","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"FluentEnsure","id":673,"typeArguments":[{"type":"typeParameter","name":"TObject"}]}},{"id":634,"name":"parsers","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Parsers","id":729}},{"id":635,"name":"property","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"RuleProperty","id":317}}],"type":{"type":"reference","name":"FluentRules","id":609}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":798,"character":25}]},{"id":612,"name":"fluentEnsure","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":784,"character":28}],"type":{"type":"intrinsic","name":"any"}},{"id":613,"name":"parsers","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":785,"character":23}],"type":{"type":"intrinsic","name":"any"}},{"id":614,"name":"property","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":786,"character":24}],"type":{"type":"intrinsic","name":"any"}},{"id":630,"name":"sequence","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"Current rule sequence number. Used to postpone evaluation of rules until rules\nwith lower sequence number have successfully validated. The \"then\" fluent API method\nmanages this property, there's usually no need to set it directly."},"sources":[{"fileName":"aurelia-validation.d.ts","line":798,"character":16}],"type":{"type":"intrinsic","name":"number"}},{"id":615,"name":"customRules","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":787,"character":26}],"type":{"type":"reflection","declaration":{"id":616,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"indexSignature":{"id":617,"name":"__index","kind":8192,"kindString":"Index signature","flags":{},"parameters":[{"id":618,"name":"name","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reflection","declaration":{"id":619,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"children":[{"id":626,"name":"argsToConfig","kind":32,"kindString":"Variable","flags":{"isOptional":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":790,"character":28}],"type":{"type":"union","types":[{"type":"intrinsic","name":"undefined"},{"type":"reflection","declaration":{"id":627,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":628,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":629,"name":"args","kind":32768,"kindString":"Parameter","flags":{"isRest":true},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}}],"type":{"type":"intrinsic","name":"any"}}]}}]}},{"id":620,"name":"condition","kind":32,"kindString":"Variable","flags":{},"sources":[{"fileName":"aurelia-validation.d.ts","line":789,"character":25}],"type":{"type":"reflection","declaration":{"id":621,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":622,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":623,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":624,"name":"object","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"intrinsic","name":"any"}},{"id":625,"name":"fluentArgs","kind":32768,"kindString":"Parameter","flags":{"isRest":true},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}}],"type":{"type":"union","types":[{"type":"intrinsic","name":"boolean"},{"type":"reference","name":"Promise","typeArguments":[{"type":"intrinsic","name":"boolean"}]}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":789,"character":26}]}}}],"groups":[{"title":"Variables","kind":32,"children":[626,620]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":788,"character":27}]}}},"sources":[{"fileName":"aurelia-validation.d.ts","line":787,"character":27}]}}},{"id":636,"name":"displayName","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":637,"name":"displayName","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Sets the display name of the ensured property."},"parameters":[{"id":638,"name":"name","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"reference","name":"ValidationDisplayNameAccessor","id":770},{"type":"intrinsic","name":"null"}]}}],"type":{"type":"intrinsic","name":"this"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":803,"character":19}]},{"id":656,"name":"email","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":657,"name":"email","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"email\" rule to the property.\nnull, undefined and empty-string values are considered valid."},"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":832,"character":13}]},{"id":670,"name":"equals","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":671,"name":"equals","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"equals\" validation rule to the property.\nnull and undefined values are considered valid."},"parameters":[{"id":672,"name":"expectedValue","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TValue"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":857,"character":14}]},{"id":653,"name":"matches","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":654,"name":"matches","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"matches\" rule to the property.\nValue must match the specified regular expression.\nnull, undefined and empty-string values are considered valid."},"parameters":[{"id":655,"name":"regex","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"RegExp"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":827,"character":15}]},{"id":667,"name":"maxItems","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":668,"name":"maxItems","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"maxItems\" ARRAY validation rule to the property.\nnull and undefined values are considered valid."},"parameters":[{"id":669,"name":"count","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":852,"character":16}]},{"id":661,"name":"maxLength","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":662,"name":"maxLength","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"maxLength\" STRING validation rule to the property.\nnull, undefined and empty-string values are considered valid."},"parameters":[{"id":663,"name":"length","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":842,"character":17}]},{"id":664,"name":"minItems","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":665,"name":"minItems","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"minItems\" ARRAY validation rule to the property.\nnull and undefined values are considered valid."},"parameters":[{"id":666,"name":"count","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":847,"character":16}]},{"id":658,"name":"minLength","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":659,"name":"minLength","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"minLength\" STRING validation rule to the property.\nnull, undefined and empty-string values are considered valid."},"parameters":[{"id":660,"name":"length","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":837,"character":17}]},{"id":651,"name":"required","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":652,"name":"required","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"required\" rule to the property.\nThe value cannot be null, undefined or whitespace."},"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":821,"character":16}]},{"id":639,"name":"satisfies","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":640,"name":"satisfies","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies an ad-hoc rule function to the ensured property or object."},"parameters":[{"id":641,"name":"condition","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The function to validate the rule.\nWill be called with two arguments, the property value and the object.\nShould return a boolean or a Promise that resolves to a boolean.\n"},"type":{"type":"reflection","declaration":{"id":642,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":643,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":644,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TValue"}},{"id":645,"name":"object","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"reference","name":"TObject","id":610}}],"type":{"type":"union","types":[{"type":"intrinsic","name":"boolean"},{"type":"reference","name":"Promise","typeArguments":[{"type":"intrinsic","name":"boolean"}]}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":810,"character":28}]}}},{"id":646,"name":"config","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"intrinsic","name":"undefined"},{"type":"intrinsic","name":"object"}]}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":810,"character":17}]},{"id":647,"name":"satisfiesRule","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":648,"name":"satisfiesRule","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies a rule by name."},"parameters":[{"id":649,"name":"name","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The name of the custom or standard rule."},"type":{"type":"intrinsic","name":"string"}},{"id":650,"name":"args","kind":32768,"kindString":"Parameter","flags":{"isRest":true},"comment":{"text":"The rule's arguments.\n"},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":816,"character":21}]}],"groups":[{"title":"Constructors","kind":512,"children":[631]},{"title":"Properties","kind":1024,"children":[612,613,614,630,615]},{"title":"Methods","kind":2048,"children":[636,656,670,653,667,661,664,658,651,639,647]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":783,"character":28}]},{"id":420,"name":"MessageExpressionValidator","kind":128,"kindString":"Class","flags":{"isExported":true},"children":[{"id":426,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":427,"name":"new MessageExpressionValidator","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":428,"name":"originalMessage","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"MessageExpressionValidator","id":420}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":597,"character":79}]},{"id":421,"name":"originalMessage","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":596,"character":31}],"type":{"type":"intrinsic","name":"any"}},{"id":453,"name":"visitAccessKeyed","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":454,"name":"visitAccessKeyed","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":455,"name":"access","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AccessKeyed"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitAccessKeyed","id":375}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":569,"character":24}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitAccessKeyed","id":375}},{"id":450,"name":"visitAccessMember","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":451,"name":"visitAccessMember","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":452,"name":"access","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AccessMember"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitAccessMember","id":372}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":568,"character":25}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitAccessMember","id":372}},{"id":429,"name":"visitAccessScope","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":430,"name":"visitAccessScope","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":431,"name":"access","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AccessScope"}}],"type":{"type":"intrinsic","name":"void"},"overwrites":{"type":"reference","name":"ExpressionVisitor.visitAccessScope","id":369}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":599,"character":24}],"overwrites":{"type":"reference","name":"ExpressionVisitor.visitAccessScope","id":369}},{"id":447,"name":"visitAccessThis","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":448,"name":"visitAccessThis","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":449,"name":"access","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AccessThis","id":775}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitAccessThis","id":366}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":566,"character":23}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitAccessThis","id":366}},{"id":441,"name":"visitAssign","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":442,"name":"visitAssign","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":443,"name":"assign","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Assign","id":774}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitAssign","id":360}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":564,"character":19}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitAssign","id":360}},{"id":468,"name":"visitBinary","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":469,"name":"visitBinary","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":470,"name":"binary","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Binary"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitBinary","id":390}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":574,"character":19}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitBinary","id":390}},{"id":435,"name":"visitBindingBehavior","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":436,"name":"visitBindingBehavior","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":437,"name":"behavior","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"BindingBehavior"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitBindingBehavior","id":354}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":562,"character":28}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitBindingBehavior","id":354}},{"id":459,"name":"visitCallFunction","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":460,"name":"visitCallFunction","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":461,"name":"call","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"CallFunction","id":778}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitCallFunction","id":381}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":571,"character":25}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitCallFunction","id":381}},{"id":462,"name":"visitCallMember","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":463,"name":"visitCallMember","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":464,"name":"call","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"CallMember"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitCallMember","id":384}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":572,"character":23}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitCallMember","id":384}},{"id":456,"name":"visitCallScope","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":457,"name":"visitCallScope","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":458,"name":"call","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"CallScope","id":777}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitCallScope","id":378}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":570,"character":22}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitCallScope","id":378}},{"id":432,"name":"visitChain","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":433,"name":"visitChain","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":434,"name":"chain","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Chain","id":773}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitChain","id":351}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":561,"character":18}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitChain","id":351}},{"id":444,"name":"visitConditional","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":445,"name":"visitConditional","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":446,"name":"conditional","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Conditional"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitConditional","id":363}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":565,"character":24}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitConditional","id":363}},{"id":474,"name":"visitLiteralArray","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":475,"name":"visitLiteralArray","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":476,"name":"literal","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"LiteralArray","id":781}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitLiteralArray","id":396}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":576,"character":25}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitLiteralArray","id":396}},{"id":477,"name":"visitLiteralObject","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":478,"name":"visitLiteralObject","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":479,"name":"literal","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"LiteralObject","id":782}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitLiteralObject","id":399}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":577,"character":26}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitLiteralObject","id":399}},{"id":471,"name":"visitLiteralPrimitive","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":472,"name":"visitLiteralPrimitive","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":473,"name":"literal","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"LiteralPrimitive","id":780}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitLiteralPrimitive","id":393}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":575,"character":29}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitLiteralPrimitive","id":393}},{"id":480,"name":"visitLiteralString","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":481,"name":"visitLiteralString","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":482,"name":"literal","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"LiteralString","id":783}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitLiteralString","id":402}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":578,"character":26}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitLiteralString","id":402}},{"id":465,"name":"visitPrefix","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":466,"name":"visitPrefix","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":467,"name":"prefix","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"PrefixNot","id":779}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitPrefix","id":387}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":573,"character":19}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitPrefix","id":387}},{"id":438,"name":"visitValueConverter","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":439,"name":"visitValueConverter","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":440,"name":"converter","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValueConverter"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitValueConverter","id":357}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":563,"character":27}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitValueConverter","id":357}},{"id":422,"name":"validate","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":423,"name":"validate","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":424,"name":"expression","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Expression"}},{"id":425,"name":"originalMessage","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":597,"character":23}]}],"groups":[{"title":"Constructors","kind":512,"children":[426]},{"title":"Properties","kind":1024,"children":[421]},{"title":"Methods","kind":2048,"children":[453,450,429,447,441,468,435,459,462,456,432,444,474,477,471,480,465,438,422]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":595,"character":43}],"extendedTypes":[{"type":"reference","name":"ExpressionVisitor","id":350}]},{"id":27,"name":"PropertyAccessorParser","kind":128,"kindString":"Class","flags":{"isExported":true},"children":[{"id":30,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":31,"name":"new PropertyAccessorParser","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":32,"name":"parser","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Parser"}}],"type":{"type":"reference","name":"PropertyAccessorParser","id":27}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":91,"character":41}]},{"id":28,"name":"parser","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":90,"character":22}],"type":{"type":"intrinsic","name":"any"}},{"id":29,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":91,"character":21}],"type":{"type":"array","elementType":{"type":"reference","name":"Parser"}}},{"id":33,"name":"parse","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":34,"name":"parse","kind":4096,"kindString":"Call signature","flags":{},"typeParameter":[{"id":35,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}},{"id":36,"name":"TValue","kind":131072,"kindString":"Type parameter","flags":{}}],"parameters":[{"id":37,"name":"property","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"},{"type":"reference","name":"PropertyAccessor","id":761,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}]}}],"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":93,"character":13}]}],"groups":[{"title":"Constructors","kind":512,"children":[30]},{"title":"Properties","kind":1024,"children":[28,29]},{"title":"Methods","kind":2048,"children":[33]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":89,"character":39}]},{"id":338,"name":"Rules","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Sets, unsets and retrieves rules on an object or constructor function."},"children":[{"id":339,"name":"key","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isPrivate":true,"isExported":true},"comment":{"shortText":"The name of the property that stores the rules."},"sources":[{"fileName":"aurelia-validation.d.ts","line":534,"character":26}],"type":{"type":"intrinsic","name":"any"}},{"id":347,"name":"get","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":348,"name":"get","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Retrieves the target's rules."},"parameters":[{"id":349,"name":"target","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"union","types":[{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"any"}]}}},{"type":"intrinsic","name":"null"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":546,"character":18}]},{"id":340,"name":"set","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":341,"name":"set","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the rules to a target."},"parameters":[{"id":342,"name":"target","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":343,"name":"rules","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"any"}]}}}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":538,"character":18}]},{"id":344,"name":"unset","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":345,"name":"unset","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Removes rules from a target."},"parameters":[{"id":346,"name":"target","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":542,"character":20}]}],"groups":[{"title":"Properties","kind":1024,"children":[339]},{"title":"Methods","kind":2048,"children":[347,340,344]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":530,"character":22}]},{"id":501,"name":"StandardValidator","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Validates.\nResponsible for validating objects and properties."},"children":[{"id":506,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":507,"name":"new StandardValidator","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":508,"name":"messageProvider","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValidationMessageProvider","id":486}},{"id":509,"name":"resources","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ViewResources"}}],"type":{"type":"reference","name":"StandardValidator","id":501}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":643,"character":31}]},{"id":505,"name":"getDisplayName","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":643,"character":30}],"type":{"type":"intrinsic","name":"any"}},{"id":523,"name":"getMessage","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":666,"character":26}],"type":{"type":"intrinsic","name":"any"}},{"id":504,"name":"lookupFunctions","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":642,"character":31}],"type":{"type":"intrinsic","name":"any"}},{"id":503,"name":"messageProvider","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":641,"character":31}],"type":{"type":"intrinsic","name":"any"}},{"id":525,"name":"validate","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":668,"character":24}],"type":{"type":"intrinsic","name":"any"}},{"id":524,"name":"validateRuleSequence","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":667,"character":36}],"type":{"type":"intrinsic","name":"any"}},{"id":502,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":640,"character":21}],"type":{"type":"array","elementType":{"type":"union","types":[{"type":"reference","name":"ViewResources"},{"type":"reference","name":"ValidationMessageProvider","id":486}]}}},{"id":519,"name":"ruleExists","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":520,"name":"ruleExists","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Determines whether a rule exists in a set of rules.","tags":[{"tag":"parem","text":"rule The rule to find.\n"}]},"parameters":[{"id":521,"name":"rules","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The rules to search."},"type":{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"any"}]}}}},{"id":522,"name":"rule","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"any"}]}}],"type":{"type":"intrinsic","name":"boolean"},"overwrites":{"type":"reference","name":"Validator.ruleExists","id":48}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":665,"character":18}],"overwrites":{"type":"reference","name":"Validator.ruleExists","id":48}},{"id":515,"name":"validateObject","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":516,"name":"validateObject","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Validates all rules for specified object and it's properties."},"parameters":[{"id":517,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The object to validate."},"type":{"type":"intrinsic","name":"any"}},{"id":518,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"Optional. If unspecified, the rules will be looked up using the metadata\nfor the object created by ValidationRules....on(class/object)\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"reference","name":"Promise","typeArguments":[{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}]},"overwrites":{"type":"reference","name":"Validator.validateObject","id":44}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":659,"character":22}],"overwrites":{"type":"reference","name":"Validator.validateObject","id":44}},{"id":510,"name":"validateProperty","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":511,"name":"validateProperty","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Validates the specified property."},"parameters":[{"id":512,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The object to validate."},"type":{"type":"intrinsic","name":"any"}},{"id":513,"name":"propertyName","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The name of the property to validate."},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"}]}},{"id":514,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"Optional. If unspecified, the rules will be looked up using the metadata\nfor the object created by ValidationRules....on(class/object)\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"reference","name":"Promise","typeArguments":[{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}]},"overwrites":{"type":"reference","name":"Validator.validateProperty","id":39}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":652,"character":24}],"overwrites":{"type":"reference","name":"Validator.validateProperty","id":39}}],"groups":[{"title":"Constructors","kind":512,"children":[506]},{"title":"Properties","kind":1024,"children":[505,523,504,503,525,524,502]},{"title":"Methods","kind":2048,"children":[519,515,510]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":639,"character":34}],"extendedTypes":[{"type":"reference","name":"Validator","id":38}]},{"id":177,"name":"ValidateBindingBehavior","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Binding behavior. Indicates the bound property should be validated\nwhen the validate trigger specified by the associated controller's\nvalidateTrigger property occurs."},"children":[{"id":182,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":183,"name":"new ValidateBindingBehavior","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":184,"name":"taskQueue","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"TaskQueue"}}],"type":{"type":"reference","name":"ValidateBindingBehavior","id":177},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":389,"character":26}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}},{"id":178,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":405,"character":21}],"type":{"type":"array","elementType":{"type":"reference","name":"TaskQueue"}}},{"id":185,"name":"bind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":186,"name":"bind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":187,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":188,"name":"source","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":189,"name":"rulesOrController","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"reference","name":"ValidationController","id":81},{"type":"intrinsic","name":"any"}]}},{"id":190,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":392,"character":12}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}},{"id":179,"name":"getValidateTrigger","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":180,"name":"getValidateTrigger","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":181,"name":"controller","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValidationController","id":81}}],"type":{"type":"reference","name":"validateTrigger","id":52},"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":406,"character":26}],"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}},{"id":191,"name":"unbind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":192,"name":"unbind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":193,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":393,"character":14}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"groups":[{"title":"Constructors","kind":512,"children":[182]},{"title":"Properties","kind":1024,"children":[178]},{"title":"Methods","kind":2048,"children":[185,179,191]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":404,"character":40}],"extendedTypes":[{"type":"reference","name":"ValidateBindingBehaviorBase","id":160}]},{"id":160,"name":"ValidateBindingBehaviorBase","kind":128,"kindString":"Class","flags":{"isExported":true,"isAbstract":true},"comment":{"shortText":"Binding behavior. Indicates the bound property should be validated."},"children":[{"id":162,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":163,"name":"new ValidateBindingBehaviorBase","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":164,"name":"taskQueue","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"TaskQueue"}}],"type":{"type":"reference","name":"ValidateBindingBehaviorBase","id":160}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":389,"character":26}]},{"id":161,"name":"taskQueue","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":389,"character":25}],"type":{"type":"intrinsic","name":"any"}},{"id":168,"name":"bind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":169,"name":"bind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":170,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":171,"name":"source","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":172,"name":"rulesOrController","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"reference","name":"ValidationController","id":81},{"type":"intrinsic","name":"any"}]}},{"id":173,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":392,"character":12}]},{"id":165,"name":"getValidateTrigger","kind":2048,"kindString":"Method","flags":{"isExported":true,"isProtected":true,"isAbstract":true},"signatures":[{"id":166,"name":"getValidateTrigger","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":167,"name":"controller","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValidationController","id":81}}],"type":{"type":"reference","name":"validateTrigger","id":52}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":391,"character":45}]},{"id":174,"name":"unbind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":175,"name":"unbind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":176,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":393,"character":14}]}],"groups":[{"title":"Constructors","kind":512,"children":[162]},{"title":"Properties","kind":1024,"children":[161]},{"title":"Methods","kind":2048,"children":[168,165,174]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":388,"character":53}],"extendedBy":[{"type":"reference","name":"ValidateBindingBehavior","id":177},{"type":"reference","name":"ValidateManuallyBindingBehavior","id":194},{"type":"reference","name":"ValidateOnBlurBindingBehavior","id":210},{"type":"reference","name":"ValidateOnChangeBindingBehavior","id":226},{"type":"reference","name":"ValidateOnChangeOrBlurBindingBehavior","id":242}]},{"id":68,"name":"ValidateEvent","kind":128,"kindString":"Class","flags":{"isExported":true},"children":[{"id":74,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":75,"name":"new ValidateEvent","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":76,"name":"type","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"union","types":[{"type":"stringLiteral","value":"validate"},{"type":"stringLiteral","value":"reset"}]}},{"id":77,"name":"errors","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}},{"id":78,"name":"results","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}},{"id":79,"name":"instruction","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"union","types":[{"type":"reference","name":"ValidateInstruction","id":19},{"type":"intrinsic","name":"null"}]}},{"id":80,"name":"controllerValidateResult","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"union","types":[{"type":"reference","name":"ControllerValidateResult","id":23},{"type":"intrinsic","name":"null"}]}}],"type":{"type":"reference","name":"ValidateEvent","id":68}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":220,"character":75}]},{"id":73,"name":"controllerValidateResult","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"In events with type === \"validate\", this property will contain the result\nof validating the instruction (see \"instruction\" property). Use the controllerValidateResult\nto access the validate results specific to the call to \"validate\"\n(as opposed to using the \"results\" and \"errors\" properties to access the controller's entire\nset of results/errors)."},"sources":[{"fileName":"aurelia-validation.d.ts","line":220,"character":41}],"type":{"type":"union","types":[{"type":"reference","name":"ControllerValidateResult","id":23},{"type":"intrinsic","name":"null"}]}},{"id":70,"name":"errors","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The controller's current array of errors. For an array containing both\nfailed rules and passed rules, use the \"results\" property."},"sources":[{"fileName":"aurelia-validation.d.ts","line":201,"character":23}],"type":{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}},{"id":72,"name":"instruction","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The instruction passed to the \"validate\" or \"reset\" event. Will be null when\nthe controller's validate/reset method was called with no instruction argument."},"sources":[{"fileName":"aurelia-validation.d.ts","line":212,"character":28}],"type":{"type":"union","types":[{"type":"reference","name":"ValidateInstruction","id":19},{"type":"intrinsic","name":"null"}]}},{"id":71,"name":"results","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The controller's current array of validate results. This\nincludes both passed rules and failed rules. For an array of only failed rules,\nuse the \"errors\" property."},"sources":[{"fileName":"aurelia-validation.d.ts","line":207,"character":24}],"type":{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}},{"id":69,"name":"type","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The type of validate event. Either \"validate\" or \"reset\"."},"sources":[{"fileName":"aurelia-validation.d.ts","line":196,"character":21}],"type":{"type":"union","types":[{"type":"stringLiteral","value":"validate"},{"type":"stringLiteral","value":"reset"}]}}],"groups":[{"title":"Constructors","kind":512,"children":[74]},{"title":"Properties","kind":1024,"children":[73,70,72,71,69]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":192,"character":30}]},{"id":194,"name":"ValidateManuallyBindingBehavior","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Binding behavior. Indicates the bound property will be validated\nmanually, by calling controller.validate(). No automatic validation\ntriggered by data-entry or blur will occur."},"children":[{"id":198,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":199,"name":"new ValidateManuallyBindingBehavior","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":200,"name":"taskQueue","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"TaskQueue"}}],"type":{"type":"reference","name":"ValidateManuallyBindingBehavior","id":194},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":389,"character":26}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}},{"id":195,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":414,"character":21}],"type":{"type":"array","elementType":{"type":"reference","name":"TaskQueue"}}},{"id":201,"name":"bind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":202,"name":"bind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":203,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":204,"name":"source","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":205,"name":"rulesOrController","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"reference","name":"ValidationController","id":81},{"type":"intrinsic","name":"any"}]}},{"id":206,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":392,"character":12}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}},{"id":196,"name":"getValidateTrigger","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":197,"name":"getValidateTrigger","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"reference","name":"validateTrigger","id":52},"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":415,"character":26}],"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}},{"id":207,"name":"unbind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":208,"name":"unbind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":209,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":393,"character":14}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"groups":[{"title":"Constructors","kind":512,"children":[198]},{"title":"Properties","kind":1024,"children":[195]},{"title":"Methods","kind":2048,"children":[201,196,207]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":413,"character":48}],"extendedTypes":[{"type":"reference","name":"ValidateBindingBehaviorBase","id":160}]},{"id":210,"name":"ValidateOnBlurBindingBehavior","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Binding behavior. Indicates the bound property should be validated\nwhen the associated element blurs."},"children":[{"id":214,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":215,"name":"new ValidateOnBlurBindingBehavior","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":216,"name":"taskQueue","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"TaskQueue"}}],"type":{"type":"reference","name":"ValidateOnBlurBindingBehavior","id":210},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":389,"character":26}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}},{"id":211,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":422,"character":21}],"type":{"type":"array","elementType":{"type":"reference","name":"TaskQueue"}}},{"id":217,"name":"bind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":218,"name":"bind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":219,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":220,"name":"source","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":221,"name":"rulesOrController","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"reference","name":"ValidationController","id":81},{"type":"intrinsic","name":"any"}]}},{"id":222,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":392,"character":12}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}},{"id":212,"name":"getValidateTrigger","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":213,"name":"getValidateTrigger","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"reference","name":"validateTrigger","id":52},"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":423,"character":26}],"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}},{"id":223,"name":"unbind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":224,"name":"unbind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":225,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":393,"character":14}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"groups":[{"title":"Constructors","kind":512,"children":[214]},{"title":"Properties","kind":1024,"children":[211]},{"title":"Methods","kind":2048,"children":[217,212,223]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":421,"character":46}],"extendedTypes":[{"type":"reference","name":"ValidateBindingBehaviorBase","id":160}]},{"id":226,"name":"ValidateOnChangeBindingBehavior","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Binding behavior. Indicates the bound property should be validated\nwhen the associated element is changed by the user, causing a change\nto the model."},"children":[{"id":230,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":231,"name":"new ValidateOnChangeBindingBehavior","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":232,"name":"taskQueue","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"TaskQueue"}}],"type":{"type":"reference","name":"ValidateOnChangeBindingBehavior","id":226},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":389,"character":26}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}},{"id":227,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":431,"character":21}],"type":{"type":"array","elementType":{"type":"reference","name":"TaskQueue"}}},{"id":233,"name":"bind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":234,"name":"bind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":235,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":236,"name":"source","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":237,"name":"rulesOrController","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"reference","name":"ValidationController","id":81},{"type":"intrinsic","name":"any"}]}},{"id":238,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":392,"character":12}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}},{"id":228,"name":"getValidateTrigger","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":229,"name":"getValidateTrigger","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"reference","name":"validateTrigger","id":52},"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":432,"character":26}],"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}},{"id":239,"name":"unbind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":240,"name":"unbind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":241,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":393,"character":14}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"groups":[{"title":"Constructors","kind":512,"children":[230]},{"title":"Properties","kind":1024,"children":[227]},{"title":"Methods","kind":2048,"children":[233,228,239]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":430,"character":48}],"extendedTypes":[{"type":"reference","name":"ValidateBindingBehaviorBase","id":160}]},{"id":242,"name":"ValidateOnChangeOrBlurBindingBehavior","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Binding behavior. Indicates the bound property should be validated\nwhen the associated element blurs or is changed by the user, causing\na change to the model."},"children":[{"id":246,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":247,"name":"new ValidateOnChangeOrBlurBindingBehavior","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":248,"name":"taskQueue","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"TaskQueue"}}],"type":{"type":"reference","name":"ValidateOnChangeOrBlurBindingBehavior","id":242},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":389,"character":26}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}},{"id":243,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":440,"character":21}],"type":{"type":"array","elementType":{"type":"reference","name":"TaskQueue"}}},{"id":249,"name":"bind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":250,"name":"bind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":251,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":252,"name":"source","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":253,"name":"rulesOrController","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"reference","name":"ValidationController","id":81},{"type":"intrinsic","name":"any"}]}},{"id":254,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":392,"character":12}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}},{"id":244,"name":"getValidateTrigger","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":245,"name":"getValidateTrigger","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"reference","name":"validateTrigger","id":52},"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":441,"character":26}],"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}},{"id":255,"name":"unbind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":256,"name":"unbind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":257,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":393,"character":14}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"groups":[{"title":"Constructors","kind":512,"children":[246]},{"title":"Properties","kind":1024,"children":[243]},{"title":"Methods","kind":2048,"children":[249,244,255]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":439,"character":54}],"extendedTypes":[{"type":"reference","name":"ValidateBindingBehaviorBase","id":160}]},{"id":2,"name":"ValidateResult","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"The result of validating an individual validation rule."},"children":[{"id":10,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"comment":{},"signatures":[{"id":11,"name":"new ValidateResult","kind":16384,"kindString":"Constructor signature","flags":{},"comment":{},"parameters":[{"id":12,"name":"rule","kind":32768,"kindString":"Parameter","flags":{},"comment":{"shortText":"The rule associated with the result. Validator implementation specific."},"type":{"type":"intrinsic","name":"any"}},{"id":13,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"comment":{"shortText":"The object that was validated."},"type":{"type":"intrinsic","name":"any"}},{"id":14,"name":"propertyName","kind":32768,"kindString":"Parameter","flags":{},"comment":{"shortText":"The name of the property that was validated."},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"},{"type":"intrinsic","name":"null"}]}},{"id":15,"name":"valid","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"boolean"}},{"id":16,"name":"message","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"null"}]}}],"type":{"type":"reference","name":"ValidateResult","id":2}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":19,"character":19}]},{"id":9,"name":"id","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"A number that uniquely identifies the result instance."},"sources":[{"fileName":"aurelia-validation.d.ts","line":19,"character":10}],"type":{"type":"intrinsic","name":"number"}},{"id":7,"name":"message","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":14,"character":15}],"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"null"}]}},{"id":4,"name":"object","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":11,"character":14}],"type":{"type":"intrinsic","name":"any"}},{"id":5,"name":"propertyName","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":12,"character":20}],"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"},{"type":"intrinsic","name":"null"}]}},{"id":3,"name":"rule","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":10,"character":12}],"type":{"type":"intrinsic","name":"any"}},{"id":6,"name":"valid","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":13,"character":13}],"type":{"type":"intrinsic","name":"boolean"}},{"id":8,"name":"nextId","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":15,"character":29}],"type":{"type":"intrinsic","name":"any"}},{"id":17,"name":"toString","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":18,"name":"toString","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"null"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":27,"character":16}]}],"groups":[{"title":"Constructors","kind":512,"children":[10]},{"title":"Properties","kind":1024,"children":[9,7,4,5,3,6,8]},{"title":"Methods","kind":2048,"children":[17]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":9,"character":31}]},{"id":81,"name":"ValidationController","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Orchestrates validation.\nManages a set of bindings, renderers and objects.\nExposes the current list of validation results for binding purposes."},"children":[{"id":95,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":96,"name":"new ValidationController","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":97,"name":"validator","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Validator","id":38}},{"id":98,"name":"propertyParser","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"PropertyAccessorParser","id":27}}],"type":{"type":"reference","name":"ValidationController","id":81}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":290,"character":31}]},{"id":85,"name":"bindings","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":269,"character":24}],"type":{"type":"intrinsic","name":"any"}},{"id":90,"name":"elements","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":283,"character":24}],"type":{"type":"intrinsic","name":"any"}},{"id":88,"name":"errors","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"Validation errors that have been rendered by the controller."},"sources":[{"fileName":"aurelia-validation.d.ts","line":278,"character":14}],"type":{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}},{"id":94,"name":"eventCallbacks","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":290,"character":30}],"type":{"type":"intrinsic","name":"any"}},{"id":93,"name":"finishValidating","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":289,"character":32}],"type":{"type":"intrinsic","name":"any"}},{"id":146,"name":"getAssociatedElements","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"comment":{"shortText":"Gets the elements associated with an object and propertyName (if any)."},"sources":[{"fileName":"aurelia-validation.d.ts","line":361,"character":37}],"type":{"type":"intrinsic","name":"any"}},{"id":139,"name":"getInstructionPredicate","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"comment":{"shortText":"Interprets the instruction and returns a predicate that will identify\nrelevant results in the list of rendered validation results."},"sources":[{"fileName":"aurelia-validation.d.ts","line":345,"character":39}],"type":{"type":"intrinsic","name":"any"}},{"id":159,"name":"invokeCallbacks","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":380,"character":31}],"type":{"type":"intrinsic","name":"any"}},{"id":91,"name":"objects","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":284,"character":23}],"type":{"type":"intrinsic","name":"any"}},{"id":147,"name":"processResultDelta","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":362,"character":34}],"type":{"type":"intrinsic","name":"any"}},{"id":83,"name":"propertyParser","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":267,"character":30}],"type":{"type":"intrinsic","name":"any"}},{"id":86,"name":"renderers","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":270,"character":25}],"type":{"type":"intrinsic","name":"any"}},{"id":87,"name":"results","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"comment":{"shortText":"Validation results that have been rendered by the controller."},"sources":[{"fileName":"aurelia-validation.d.ts","line":274,"character":23}],"type":{"type":"intrinsic","name":"any"}},{"id":92,"name":"validateTrigger","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The trigger that will invoke automatic validation of a property used in a binding."},"sources":[{"fileName":"aurelia-validation.d.ts","line":288,"character":23}],"type":{"type":"reference","name":"validateTrigger","id":52}},{"id":89,"name":"validating","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":" Whether the controller is currently validating."},"sources":[{"fileName":"aurelia-validation.d.ts","line":282,"character":18}],"type":{"type":"intrinsic","name":"boolean"}},{"id":82,"name":"validator","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":266,"character":25}],"type":{"type":"intrinsic","name":"any"}},{"id":84,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":268,"character":21}],"type":{"type":"array","elementType":{"type":"union","types":[{"type":"reference","name":"PropertyAccessorParser","id":27},{"type":"reference","name":"Validator","id":38}]}}},{"id":116,"name":"addError","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":117,"name":"addError","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Adds and renders an error."},"typeParameter":[{"id":118,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}}],"parameters":[{"id":119,"name":"message","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}},{"id":120,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TObject"}},{"id":121,"name":"propertyName","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"reference","name":"PropertyAccessor","id":761,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"string"}]},{"type":"intrinsic","name":"null"}]}}],"type":{"type":"reference","name":"ValidateResult","id":2}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":314,"character":16}]},{"id":109,"name":"addObject","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":110,"name":"addObject","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Adds an object to the set of objects that should be validated when validate is called."},"parameters":[{"id":111,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The object."},"type":{"type":"intrinsic","name":"any"}},{"id":112,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"Optional. The rules. If rules aren't supplied the Validator implementation will lookup the rules.\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":305,"character":17}]},{"id":125,"name":"addRenderer","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":126,"name":"addRenderer","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Adds a renderer."},"parameters":[{"id":127,"name":"renderer","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The renderer.\n"},"type":{"type":"reference","name":"ValidationRenderer","id":64}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":323,"character":19}]},{"id":154,"name":"changeTrigger","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":155,"name":"changeTrigger","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Changes the controller's validateTrigger."},"parameters":[{"id":156,"name":"newTrigger","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The new validateTrigger\n"},"type":{"type":"reference","name":"validateTrigger","id":52}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":375,"character":21}]},{"id":131,"name":"registerBinding","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":132,"name":"registerBinding","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Registers a binding with the controller."},"parameters":[{"id":133,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The binding instance."},"type":{"type":"reference","name":"Binding"}},{"id":134,"name":"target","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The DOM element."},"type":{"type":"reference","name":"Element"}},{"id":135,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"(optional) rules associated with the binding. Validator implementation specific.\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":335,"character":23}]},{"id":122,"name":"removeError","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":123,"name":"removeError","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Removes and unrenders an error."},"parameters":[{"id":124,"name":"result","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValidateResult","id":2}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":318,"character":19}]},{"id":113,"name":"removeObject","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":114,"name":"removeObject","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Removes an object from the set of objects that should be validated when validate is called."},"parameters":[{"id":115,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The object.\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":310,"character":20}]},{"id":128,"name":"removeRenderer","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":129,"name":"removeRenderer","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Removes a renderer."},"parameters":[{"id":130,"name":"renderer","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The renderer.\n"},"type":{"type":"reference","name":"ValidationRenderer","id":64}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":328,"character":22}]},{"id":143,"name":"reset","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":144,"name":"reset","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Resets any rendered validation results (unrenders)."},"parameters":[{"id":145,"name":"instruction","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"Optional. Instructions on what to reset. If unspecified all rendered results\nwill be unrendered.\n"},"type":{"type":"reference","name":"ValidateInstruction","id":19}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":357,"character":13}]},{"id":151,"name":"resetBinding","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":152,"name":"resetBinding","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Resets the results for a property associated with a binding."},"parameters":[{"id":153,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Binding"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":370,"character":20}]},{"id":157,"name":"revalidateErrors","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":158,"name":"revalidateErrors","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Revalidates the controller's current set of errors."},"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":379,"character":24}]},{"id":99,"name":"subscribe","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":100,"name":"subscribe","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Subscribe to controller validate and reset events. These events occur when the\ncontroller's \"validate\"\" and \"reset\" methods are called."},"parameters":[{"id":101,"name":"callback","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The callback to be invoked when the controller validates or resets.\n"},"type":{"type":"reflection","declaration":{"id":102,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":103,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":104,"name":"event","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValidateEvent","id":68}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":297,"character":27}]}}}],"type":{"type":"reflection","declaration":{"id":105,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"children":[{"id":106,"name":"dispose","kind":32,"kindString":"Variable","flags":{},"sources":[{"fileName":"aurelia-validation.d.ts","line":298,"character":19}],"type":{"type":"reflection","declaration":{"id":107,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":108,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":298,"character":20}]}}}],"groups":[{"title":"Variables","kind":32,"children":[106]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":297,"character":60}]}}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":297,"character":17}]},{"id":136,"name":"unregisterBinding","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":137,"name":"unregisterBinding","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Unregisters a binding with the controller."},"parameters":[{"id":138,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The binding instance.\n"},"type":{"type":"reference","name":"Binding"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":340,"character":25}]},{"id":140,"name":"validate","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":141,"name":"validate","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Validates and renders results."},"parameters":[{"id":142,"name":"instruction","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"Optional. Instructions on what to validate. If undefined, all\nobjects and bindings will be validated.\n"},"type":{"type":"reference","name":"ValidateInstruction","id":19}}],"type":{"type":"reference","name":"Promise","typeArguments":[{"type":"reference","name":"ControllerValidateResult","id":23}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":351,"character":16}]},{"id":148,"name":"validateBinding","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":149,"name":"validateBinding","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Validates the property associated with a binding."},"parameters":[{"id":150,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Binding"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":366,"character":23}]}],"groups":[{"title":"Constructors","kind":512,"children":[95]},{"title":"Properties","kind":1024,"children":[85,90,88,94,93,146,139,159,91,147,83,86,87,92,89,82,84]},{"title":"Methods","kind":2048,"children":[116,109,125,154,131,122,113,128,143,151,157,99,136,140,148]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":265,"character":37}]},{"id":258,"name":"ValidationControllerFactory","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Creates ValidationController instances."},"children":[{"id":263,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":264,"name":"new ValidationControllerFactory","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":265,"name":"container","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Container"}}],"type":{"type":"reference","name":"ValidationControllerFactory","id":258}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":451,"character":70}]},{"id":259,"name":"container","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":450,"character":25}],"type":{"type":"intrinsic","name":"any"}},{"id":266,"name":"create","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":267,"name":"create","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Creates a new controller instance."},"parameters":[{"id":268,"name":"validator","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"reference","name":"Validator","id":38}}],"type":{"type":"reference","name":"ValidationController","id":81}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":456,"character":14}]},{"id":269,"name":"createForCurrentScope","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":270,"name":"createForCurrentScope","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Creates a new controller and registers it in the current element's container so that it's\navailable to the validate binding behavior and renderers."},"parameters":[{"id":271,"name":"validator","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"reference","name":"Validator","id":38}}],"type":{"type":"reference","name":"ValidationController","id":81}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":461,"character":29}]},{"id":260,"name":"get","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":261,"name":"get","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":262,"name":"container","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Container"}}],"type":{"type":"reference","name":"ValidationControllerFactory","id":258}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":451,"character":18}]}],"groups":[{"title":"Constructors","kind":512,"children":[263]},{"title":"Properties","kind":1024,"children":[259]},{"title":"Methods","kind":2048,"children":[266,269,260]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":449,"character":44}]},{"id":275,"name":"ValidationErrorsCustomAttribute","kind":128,"kindString":"Class","flags":{"isExported":true},"children":[{"id":287,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":288,"name":"new ValidationErrorsCustomAttribute","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":289,"name":"boundaryElement","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Element"}},{"id":290,"name":"controllerAccessor","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reflection","declaration":{"id":291,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":292,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"reference","name":"ValidationController","id":81}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":481,"character":65}]}}}],"type":{"type":"reference","name":"ValidationErrorsCustomAttribute","id":275}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":480,"character":31}]},{"id":276,"name":"boundaryElement","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":472,"character":31}],"type":{"type":"intrinsic","name":"any"}},{"id":284,"name":"controller","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":478,"character":18}],"type":{"type":"union","types":[{"type":"reference","name":"ValidationController","id":81},{"type":"intrinsic","name":"null"}]}},{"id":277,"name":"controllerAccessor","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":473,"character":34}],"type":{"type":"intrinsic","name":"any"}},{"id":285,"name":"errors","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":479,"character":14}],"type":{"type":"array","elementType":{"type":"reference","name":"RenderedError","id":272}}},{"id":286,"name":"errorsInternal","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":480,"character":30}],"type":{"type":"intrinsic","name":"any"}},{"id":301,"name":"bind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":302,"name":"bind","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":485,"character":12}]},{"id":295,"name":"interestingElements","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":296,"name":"interestingElements","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":297,"name":"elements","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"array","elementType":{"type":"reference","name":"Element"}}}],"type":{"type":"array","elementType":{"type":"reference","name":"Element"}}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":483,"character":27}]},{"id":298,"name":"render","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":299,"name":"render","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":300,"name":"instruction","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"RenderInstruction","id":60}}],"type":{"type":"intrinsic","name":"void"},"implementationOf":{"type":"reference","name":"ValidationRenderer.render","id":66}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":484,"character":14}],"implementationOf":{"type":"reference","name":"ValidationRenderer.render","id":65}},{"id":293,"name":"sort","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":294,"name":"sort","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":482,"character":12}]},{"id":303,"name":"unbind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":304,"name":"unbind","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":486,"character":14}]},{"id":278,"name":"inject","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":279,"name":"inject","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"array","elementType":{"type":"union","types":[{"type":"reflection","declaration":{"id":280,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"children":[{"id":281,"name":"constructor","kind":512,"kindString":"Constructor","flags":{},"signatures":[{"id":282,"name":"new __type","kind":16384,"kindString":"Constructor signature","flags":{},"type":{"type":"reference","name":"Element"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":474,"character":27}]},{"id":283,"name":"prototype","kind":32,"kindString":"Variable","flags":{},"sources":[{"fileName":"aurelia-validation.d.ts","line":476,"character":21}],"type":{"type":"reference","name":"Element"}}],"groups":[{"title":"Constructors","kind":512,"children":[281]},{"title":"Variables","kind":32,"children":[283]}]}},{"type":"reference","name":"Lazy"}]}}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":474,"character":21}]}],"groups":[{"title":"Constructors","kind":512,"children":[287]},{"title":"Properties","kind":1024,"children":[276,284,277,285,286]},{"title":"Methods","kind":2048,"children":[301,295,298,293,303,278]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":471,"character":48}],"implementedTypes":[{"type":"reference","name":"ValidationRenderer","id":64}]},{"id":406,"name":"ValidationMessageParser","kind":128,"kindString":"Class","flags":{"isExported":true},"children":[{"id":413,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":414,"name":"new ValidationMessageParser","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":415,"name":"bindinqLanguage","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"BindingLanguage"}}],"type":{"type":"reference","name":"ValidationMessageParser","id":406}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":590,"character":22}]},{"id":407,"name":"bindinqLanguage","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":585,"character":31}],"type":{"type":"intrinsic","name":"any"}},{"id":412,"name":"cache","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":590,"character":21}],"type":{"type":"intrinsic","name":"any"}},{"id":419,"name":"coalesce","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":593,"character":24}],"type":{"type":"intrinsic","name":"any"}},{"id":409,"name":"emptyStringExpression","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":587,"character":37}],"type":{"type":"intrinsic","name":"any"}},{"id":410,"name":"nullExpression","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":588,"character":30}],"type":{"type":"intrinsic","name":"any"}},{"id":411,"name":"undefinedExpression","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":589,"character":35}],"type":{"type":"intrinsic","name":"any"}},{"id":408,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":586,"character":21}],"type":{"type":"array","elementType":{"type":"reference","name":"BindingLanguage"}}},{"id":416,"name":"parse","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":417,"name":"parse","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":418,"name":"message","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"Expression"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":592,"character":13}]}],"groups":[{"title":"Constructors","kind":512,"children":[413]},{"title":"Properties","kind":1024,"children":[407,412,419,409,410,411,408]},{"title":"Methods","kind":2048,"children":[416]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":584,"character":40}]},{"id":486,"name":"ValidationMessageProvider","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Retrieves validation messages and property display names."},"children":[{"id":489,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":490,"name":"new ValidationMessageProvider","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":491,"name":"parser","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValidationMessageParser","id":406}}],"type":{"type":"reference","name":"ValidationMessageProvider","id":486}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":615,"character":58}]},{"id":487,"name":"parser","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":614,"character":14}],"type":{"type":"reference","name":"ValidationMessageParser","id":406}},{"id":488,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":615,"character":21}],"type":{"type":"array","elementType":{"type":"reference","name":"ValidationMessageParser","id":406}}},{"id":495,"name":"getDisplayName","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":496,"name":"getDisplayName","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Formulates a property display name using the property name and the configured\ndisplayName (if provided).\nOverride this with your own custom logic."},"parameters":[{"id":497,"name":"propertyName","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The property name.\n"},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"}]}},{"id":498,"name":"displayName","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"null"},{"type":"reflection","declaration":{"id":499,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":500,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"intrinsic","name":"string"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":628,"character":83}]}}]}}],"type":{"type":"intrinsic","name":"string"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":628,"character":22}]},{"id":492,"name":"getMessage","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":493,"name":"getMessage","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Returns a message binding expression that corresponds to the key."},"parameters":[{"id":494,"name":"key","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The message key.\n"},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"Expression"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":621,"character":18}]}],"groups":[{"title":"Constructors","kind":512,"children":[489]},{"title":"Properties","kind":1024,"children":[487,488]},{"title":"Methods","kind":2048,"children":[495,492]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":613,"character":42}]},{"id":305,"name":"ValidationRendererCustomAttribute","kind":128,"kindString":"Class","flags":{"isExported":true},"children":[{"id":306,"name":"container","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":490,"character":25}],"type":{"type":"intrinsic","name":"any"}},{"id":307,"name":"controller","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":491,"character":26}],"type":{"type":"intrinsic","name":"any"}},{"id":309,"name":"renderer","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":493,"character":24}],"type":{"type":"intrinsic","name":"any"}},{"id":308,"name":"value","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":492,"character":21}],"type":{"type":"intrinsic","name":"any"}},{"id":313,"name":"bind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":314,"name":"bind","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":495,"character":12}]},{"id":310,"name":"created","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":311,"name":"created","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":312,"name":"view","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":494,"character":15}]},{"id":315,"name":"unbind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":316,"name":"unbind","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":496,"character":14}]}],"groups":[{"title":"Properties","kind":1024,"children":[306,307,309,308]},{"title":"Methods","kind":2048,"children":[313,310,315]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":489,"character":50}]},{"id":691,"name":"ValidationRules","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Fluent rule definition API."},"children":[{"id":692,"name":"parsers","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":891,"character":30}],"type":{"type":"intrinsic","name":"any"}},{"id":705,"name":"customRule","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":706,"name":"customRule","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Defines a custom rule."},"parameters":[{"id":707,"name":"name","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The name of the custom rule. Also serves as the message key."},"type":{"type":"intrinsic","name":"string"}},{"id":708,"name":"condition","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The rule function."},"type":{"type":"reflection","declaration":{"id":709,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":710,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":711,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":712,"name":"object","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"intrinsic","name":"any"}},{"id":713,"name":"args","kind":32768,"kindString":"Parameter","flags":{"isRest":true},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}}],"type":{"type":"union","types":[{"type":"intrinsic","name":"boolean"},{"type":"reference","name":"Promise","typeArguments":[{"type":"intrinsic","name":"boolean"}]}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":910,"character":50}]}}},{"id":714,"name":"message","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The message expression"},"type":{"type":"intrinsic","name":"string"}},{"id":715,"name":"argsToConfig","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"A function that maps the rule's arguments to a \"config\"\nobject that can be used when evaluating the message expression.\n"},"type":{"type":"union","types":[{"type":"intrinsic","name":"undefined"},{"type":"reflection","declaration":{"id":716,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":717,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":718,"name":"args","kind":32768,"kindString":"Parameter","flags":{"isRest":true},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}}],"type":{"type":"intrinsic","name":"any"}}]}}]}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":910,"character":25}]},{"id":697,"name":"ensure","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":698,"name":"ensure","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Target a property with validation rules."},"typeParameter":[{"id":699,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}},{"id":700,"name":"TValue","kind":131072,"kindString":"Type parameter","flags":{}}],"parameters":[{"id":701,"name":"property","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The property to target. Can be the property name or a property accessor function.\n"},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"},{"type":"reference","name":"PropertyAccessor","id":761,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}]}}],"type":{"type":"reference","name":"FluentRules","id":609,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"any"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":897,"character":21}]},{"id":702,"name":"ensureObject","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":703,"name":"ensureObject","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Targets an object with validation rules."},"typeParameter":[{"id":704,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}}],"type":{"type":"reference","name":"FluentRules","id":609,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"any"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":901,"character":27}]},{"id":693,"name":"initialize","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":694,"name":"initialize","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":695,"name":"messageParser","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValidationMessageParser","id":406}},{"id":696,"name":"propertyParser","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"PropertyAccessorParser","id":27}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":892,"character":25}]},{"id":726,"name":"off","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":727,"name":"off","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Removes the rules from a class or object."},"parameters":[{"id":728,"name":"target","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"A class or object.\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":926,"character":18}]},{"id":719,"name":"taggedRules","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":720,"name":"taggedRules","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Returns rules with the matching tag."},"parameters":[{"id":721,"name":"rules","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The rules to search."},"type":{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"any"}]}}}},{"id":722,"name":"tag","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The tag to search for.\n"},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"any"}]}}}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":916,"character":26}]},{"id":723,"name":"untaggedRules","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":724,"name":"untaggedRules","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Returns rules that have no tag."},"parameters":[{"id":725,"name":"rules","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The rules to search.\n"},"type":{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"any"}]}}}}],"type":{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"any"}]}}}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":921,"character":28}]}],"groups":[{"title":"Properties","kind":1024,"children":[692]},{"title":"Methods","kind":2048,"children":[705,697,702,693,726,719,723]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":890,"character":32}]},{"id":38,"name":"Validator","kind":128,"kindString":"Class","flags":{"isExported":true,"isAbstract":true},"comment":{"shortText":"Validates objects and properties."},"children":[{"id":48,"name":"ruleExists","kind":2048,"kindString":"Method","flags":{"isExported":true,"isAbstract":true},"signatures":[{"id":49,"name":"ruleExists","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Determines whether a rule exists in a set of rules.","tags":[{"tag":"parem","text":"rule The rule to find.\n"}]},"parameters":[{"id":50,"name":"rules","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The rules to search."},"type":{"type":"intrinsic","name":"any"}},{"id":51,"name":"rule","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"boolean"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":121,"character":27}]},{"id":44,"name":"validateObject","kind":2048,"kindString":"Method","flags":{"isExported":true,"isAbstract":true},"signatures":[{"id":45,"name":"validateObject","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Validates all rules for specified object and it's properties."},"parameters":[{"id":46,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The object to validate."},"type":{"type":"intrinsic","name":"any"}},{"id":47,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"Optional. If unspecified, the implementation should lookup the rules for the\nspecified object. This may not be possible for all implementations of this interface.\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"reference","name":"Promise","typeArguments":[{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":115,"character":31}]},{"id":39,"name":"validateProperty","kind":2048,"kindString":"Method","flags":{"isExported":true,"isAbstract":true},"signatures":[{"id":40,"name":"validateProperty","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Validates the specified property."},"parameters":[{"id":41,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The object to validate."},"type":{"type":"intrinsic","name":"any"}},{"id":42,"name":"propertyName","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The name of the property to validate."},"type":{"type":"intrinsic","name":"string"}},{"id":43,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"Optional. If unspecified, the implementation should lookup the rules for the\nspecified object. This may not be possible for all implementations of this interface.\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"reference","name":"Promise","typeArguments":[{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":108,"character":33}]}],"groups":[{"title":"Methods","kind":2048,"children":[48,44,39]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":100,"character":35}],"extendedBy":[{"type":"reference","name":"StandardValidator","id":501}]},{"id":23,"name":"ControllerValidateResult","kind":256,"kindString":"Interface","flags":{"isExported":true},"comment":{"shortText":"The result of a call to the validation controller's validate method."},"children":[{"id":26,"name":"instruction","kind":1024,"kindString":"Property","flags":{"isExported":true,"isOptional":true},"comment":{"shortText":"The instruction passed to the controller's validate method."},"sources":[{"fileName":"aurelia-validation.d.ts","line":64,"character":19}],"type":{"type":"reference","name":"ValidateInstruction","id":19}},{"id":25,"name":"results","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The validation result of every rule that was evaluated."},"sources":[{"fileName":"aurelia-validation.d.ts","line":60,"character":15}],"type":{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}},{"id":24,"name":"valid","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"Whether validation passed."},"sources":[{"fileName":"aurelia-validation.d.ts","line":56,"character":13}],"type":{"type":"intrinsic","name":"boolean"}}],"groups":[{"title":"Properties","kind":1024,"children":[26,25,24]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":52,"character":45}]},{"id":729,"name":"Parsers","kind":256,"kindString":"Interface","flags":{"isExported":true},"children":[{"id":730,"name":"message","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":929,"character":15}],"type":{"type":"reference","name":"ValidationMessageParser","id":406}},{"id":731,"name":"property","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":930,"character":16}],"type":{"type":"reference","name":"PropertyAccessorParser","id":27}}],"groups":[{"title":"Properties","kind":1024,"children":[730,731]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":928,"character":28}]},{"id":60,"name":"RenderInstruction","kind":256,"kindString":"Interface","flags":{"isExported":true},"comment":{"shortText":"Defines which validation results to render and which validation results to unrender."},"children":[{"id":61,"name":"kind","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The \"kind\" of render instruction. Either 'validate' or 'reset'."},"sources":[{"fileName":"aurelia-validation.d.ts","line":168,"character":12}],"type":{"type":"union","types":[{"type":"stringLiteral","value":"validate"},{"type":"stringLiteral","value":"reset"}]}},{"id":62,"name":"render","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The results to render."},"sources":[{"fileName":"aurelia-validation.d.ts","line":172,"character":14}],"type":{"type":"array","elementType":{"type":"reference","name":"ResultInstruction","id":57}}},{"id":63,"name":"unrender","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The results to unrender."},"sources":[{"fileName":"aurelia-validation.d.ts","line":176,"character":16}],"type":{"type":"array","elementType":{"type":"reference","name":"ResultInstruction","id":57}}}],"groups":[{"title":"Properties","kind":1024,"children":[61,62,63]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":164,"character":38}]},{"id":272,"name":"RenderedError","kind":256,"kindString":"Interface","flags":{"isExported":true},"children":[{"id":273,"name":"error","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":468,"character":13}],"type":{"type":"reference","name":"ValidateResult","id":2}},{"id":274,"name":"targets","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":469,"character":15}],"type":{"type":"array","elementType":{"type":"reference","name":"Element"}}}],"groups":[{"title":"Properties","kind":1024,"children":[273,274]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":467,"character":34}]},{"id":57,"name":"ResultInstruction","kind":256,"kindString":"Interface","flags":{"isExported":true},"comment":{"shortText":"A result to render (or unrender) and the associated elements (if any)"},"children":[{"id":59,"name":"elements","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The associated elements (if any)."},"sources":[{"fileName":"aurelia-validation.d.ts","line":159,"character":16}],"type":{"type":"array","elementType":{"type":"reference","name":"Element"}}},{"id":58,"name":"result","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The validation result."},"sources":[{"fileName":"aurelia-validation.d.ts","line":155,"character":14}],"type":{"type":"reference","name":"ValidateResult","id":2}}],"groups":[{"title":"Properties","kind":1024,"children":[59,58]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":151,"character":38}]},{"id":320,"name":"Rule","kind":256,"kindString":"Interface","flags":{"isExported":true},"comment":{"shortText":"A rule definition. Associations a rule with a property or object."},"typeParameter":[{"id":321,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}},{"id":322,"name":"TValue","kind":131072,"kindString":"Type parameter","flags":{}}],"children":[{"id":324,"name":"condition","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":518,"character":17}],"type":{"type":"reflection","declaration":{"id":325,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":326,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":327,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TValue"}},{"id":328,"name":"object","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"reference","name":"TObject","id":321}}],"type":{"type":"union","types":[{"type":"intrinsic","name":"boolean"},{"type":"reference","name":"Promise","typeArguments":[{"type":"intrinsic","name":"boolean"}]}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":518,"character":18}]}}},{"id":329,"name":"config","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":519,"character":14}],"type":{"type":"intrinsic","name":"object"}},{"id":335,"name":"message","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":522,"character":15}],"type":{"type":"union","types":[{"type":"reference","name":"Expression"},{"type":"intrinsic","name":"null"}]}},{"id":334,"name":"messageKey","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":521,"character":18}],"type":{"type":"intrinsic","name":"string"}},{"id":323,"name":"property","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":517,"character":16}],"type":{"type":"reference","name":"RuleProperty","id":317}},{"id":336,"name":"sequence","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":523,"character":16}],"type":{"type":"intrinsic","name":"number"}},{"id":337,"name":"tag","kind":1024,"kindString":"Property","flags":{"isExported":true,"isOptional":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":524,"character":11}],"type":{"type":"union","types":[{"type":"intrinsic","name":"undefined"},{"type":"intrinsic","name":"string"}]}},{"id":330,"name":"when","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":520,"character":12}],"type":{"type":"union","types":[{"type":"reflection","declaration":{"id":331,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":332,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":333,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TObject"}}],"type":{"type":"intrinsic","name":"boolean"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":520,"character":13}]}},{"type":"intrinsic","name":"null"}]}}],"groups":[{"title":"Properties","kind":1024,"children":[324,329,335,334,323,336,337,330]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":516,"character":25}]},{"id":317,"name":"RuleProperty","kind":256,"kindString":"Interface","flags":{"isExported":true},"comment":{"shortText":"Information related to a property that is the subject of validation."},"children":[{"id":319,"name":"displayName","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The displayName of the property (or object)."},"sources":[{"fileName":"aurelia-validation.d.ts","line":511,"character":19}],"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"reference","name":"ValidationDisplayNameAccessor","id":770},{"type":"intrinsic","name":"null"}]}},{"id":318,"name":"name","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The property name. null indicates the rule targets the object itself."},"sources":[{"fileName":"aurelia-validation.d.ts","line":507,"character":12}],"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"},{"type":"intrinsic","name":"null"}]}}],"groups":[{"title":"Properties","kind":1024,"children":[319,318]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":503,"character":33}]},{"id":19,"name":"ValidateInstruction","kind":256,"kindString":"Interface","flags":{"isExported":true},"comment":{"shortText":"Instructions for the validation controller's validate method."},"children":[{"id":20,"name":"object","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The object to validate."},"sources":[{"fileName":"aurelia-validation.d.ts","line":37,"character":14}],"type":{"type":"intrinsic","name":"any"}},{"id":21,"name":"propertyName","kind":1024,"kindString":"Property","flags":{"isExported":true,"isOptional":true},"comment":{"shortText":"The property to validate. Optional."},"sources":[{"fileName":"aurelia-validation.d.ts","line":41,"character":20}],"type":{"type":"intrinsic","name":"any"}},{"id":22,"name":"rules","kind":1024,"kindString":"Property","flags":{"isExported":true,"isOptional":true},"comment":{"shortText":"The rules to validate. Optional."},"sources":[{"fileName":"aurelia-validation.d.ts","line":45,"character":13}],"type":{"type":"intrinsic","name":"any"}}],"groups":[{"title":"Properties","kind":1024,"children":[20,21,22]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":33,"character":40}]},{"id":483,"name":"ValidationMessages","kind":256,"kindString":"Interface","flags":{"isExported":true},"indexSignature":{"id":484,"name":"__index","kind":8192,"kindString":"Index signature","flags":{},"parameters":[{"id":485,"name":"key","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"string"}},"sources":[{"fileName":"aurelia-validation.d.ts","line":603,"character":39}]},{"id":64,"name":"ValidationRenderer","kind":256,"kindString":"Interface","flags":{"isExported":true},"comment":{"shortText":"Renders validation results."},"children":[{"id":65,"name":"render","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":66,"name":"render","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Render the validation results."},"parameters":[{"id":67,"name":"instruction","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The render instruction. Defines which results to render and which\nresults to unrender.\n"},"type":{"type":"reference","name":"RenderInstruction","id":60}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":187,"character":14}]}],"groups":[{"title":"Methods","kind":2048,"children":[65]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":181,"character":39}],"implementedBy":[{"type":"reference","name":"ValidationErrorsCustomAttribute","id":275}]},{"id":776,"name":"AccessScope","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":552,"character":27}],"type":{"type":"intrinsic","name":"any"}},{"id":775,"name":"AccessThis","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":551,"character":26}],"type":{"type":"intrinsic","name":"any"}},{"id":774,"name":"Assign","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":550,"character":22}],"type":{"type":"intrinsic","name":"any"}},{"id":778,"name":"CallFunction","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":554,"character":28}],"type":{"type":"intrinsic","name":"any"}},{"id":777,"name":"CallScope","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":553,"character":25}],"type":{"type":"intrinsic","name":"any"}},{"id":773,"name":"Chain","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":549,"character":21}],"type":{"type":"intrinsic","name":"any"}},{"id":781,"name":"LiteralArray","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":557,"character":28}],"type":{"type":"intrinsic","name":"any"}},{"id":782,"name":"LiteralObject","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":558,"character":29}],"type":{"type":"intrinsic","name":"any"}},{"id":780,"name":"LiteralPrimitive","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":556,"character":32}],"type":{"type":"intrinsic","name":"any"}},{"id":783,"name":"LiteralString","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":559,"character":29}],"type":{"type":"intrinsic","name":"any"}},{"id":779,"name":"PrefixNot","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":555,"character":25}],"type":{"type":"intrinsic","name":"any"}},{"id":761,"name":"PropertyAccessor","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"typeParameter":[{"id":762,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}},{"id":763,"name":"TValue","kind":131072,"kindString":"Type parameter","flags":{}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":88,"character":32}],"type":{"type":"reflection","declaration":{"id":764,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":765,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":766,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TObject"}}],"type":{"type":"typeParameter","name":"TValue"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":88,"character":51}]}}},{"id":770,"name":"ValidationDisplayNameAccessor","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":499,"character":45}],"type":{"type":"reflection","declaration":{"id":771,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":772,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"intrinsic","name":"string"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":499,"character":47}]}}},{"id":784,"name":"validationMessages","kind":32,"kindString":"Variable","flags":{"isExported":true,"isConst":true},"comment":{"shortText":"Dictionary of validation messages. [messageKey]: messageExpression"},"sources":[{"fileName":"aurelia-validation.d.ts","line":609,"character":35}],"type":{"type":"reference","name":"ValidationMessages","id":483}},{"id":785,"name":"configure","kind":64,"kindString":"Function","flags":{"isExported":true},"signatures":[{"id":786,"name":"configure","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Configures the plugin."},"parameters":[{"id":787,"name":"frameworkConfig","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reflection","declaration":{"id":788,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"children":[{"id":789,"name":"container","kind":32,"kindString":"Variable","flags":{},"sources":[{"fileName":"aurelia-validation.d.ts","line":975,"character":17}],"type":{"type":"reference","name":"Container"}},{"id":790,"name":"globalResources","kind":32,"kindString":"Variable","flags":{"isOptional":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":976,"character":23}],"type":{"type":"union","types":[{"type":"intrinsic","name":"undefined"},{"type":"reflection","declaration":{"id":791,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":792,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":793,"name":"resources","kind":32768,"kindString":"Parameter","flags":{"isRest":true},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}}],"type":{"type":"intrinsic","name":"any"}}]}}]}}],"groups":[{"title":"Variables","kind":32,"children":[789,790]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":974,"character":46}]}}},{"id":794,"name":"callback","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"intrinsic","name":"undefined"},{"type":"reflection","declaration":{"id":795,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":796,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":797,"name":"config","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AureliaValidationConfiguration","id":732}}],"type":{"type":"intrinsic","name":"void"}}]}}]}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":974,"character":29}]},{"id":767,"name":"getAccessorExpression","kind":64,"kindString":"Function","flags":{"isExported":true},"signatures":[{"id":768,"name":"getAccessorExpression","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":769,"name":"fn","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"string"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":95,"character":41}]},{"id":748,"name":"getPropertyInfo","kind":64,"kindString":"Function","flags":{"isExported":true},"signatures":[{"id":749,"name":"getPropertyInfo","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Retrieves the object and property name for the specified expression."},"parameters":[{"id":750,"name":"expression","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The expression"},"type":{"type":"reference","name":"Expression"}},{"id":751,"name":"source","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The scope\n"},"type":{"type":"reference","name":"Scope"}}],"type":{"type":"union","types":[{"type":"reflection","declaration":{"id":752,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"children":[{"id":753,"name":"object","kind":32,"kindString":"Variable","flags":{},"sources":[{"fileName":"aurelia-validation.d.ts","line":81,"character":14}],"type":{"type":"intrinsic","name":"object"}},{"id":754,"name":"propertyName","kind":32,"kindString":"Variable","flags":{},"sources":[{"fileName":"aurelia-validation.d.ts","line":82,"character":20}],"type":{"type":"intrinsic","name":"string"}}],"groups":[{"title":"Variables","kind":32,"children":[753,754]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":80,"character":75}]}},{"type":"intrinsic","name":"null"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":80,"character":35}]},{"id":744,"name":"getTargetDOMElement","kind":64,"kindString":"Function","flags":{"isExported":true},"signatures":[{"id":745,"name":"getTargetDOMElement","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Gets the DOM element associated with the data-binding. Most of the time it's\nthe binding.target but sometimes binding.target is an aurelia custom element,\nor custom attribute which is a javascript \"class\" instance, so we need to use\nthe controller's container to retrieve the actual DOM element."},"parameters":[{"id":746,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":747,"name":"view","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"reference","name":"Element"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":73,"character":39}]},{"id":758,"name":"isNumber","kind":64,"kindString":"Function","flags":{"isExported":true},"signatures":[{"id":759,"name":"isNumber","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":760,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"boolean"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":86,"character":28}]},{"id":755,"name":"isString","kind":64,"kindString":"Function","flags":{"isExported":true},"signatures":[{"id":756,"name":"isString","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":757,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"boolean"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":85,"character":28}]}],"groups":[{"title":"Enumerations","kind":4,"children":[52]},{"title":"Classes","kind":128,"children":[732,350,673,526,609,420,27,338,501,177,160,68,194,210,226,242,2,81,258,275,406,486,305,691,38]},{"title":"Interfaces","kind":256,"children":[23,729,60,272,57,320,317,19,483,64]},{"title":"Type aliases","kind":4194304,"children":[776,775,774,778,777,773,781,782,780,783,779,761,770]},{"title":"Variables","kind":32,"children":[784]},{"title":"Functions","kind":64,"children":[785,767,748,744,758,755]}]} +{"name":"aurelia-validation","children":[{"id":52,"name":"validateTrigger","kind":4,"kindString":"Enumeration","flags":{"isExported":true},"comment":{"shortText":"Validation triggers."},"children":[{"id":54,"name":"blur","kind":16,"kindString":"Enumeration member","flags":{"isExported":true},"comment":{"shortText":"Validate the binding when the binding's target element fires a DOM \"blur\" event."},"sources":[{"fileName":"aurelia-validation.d.ts","line":136,"character":12}],"defaultValue":"1"},{"id":55,"name":"change","kind":16,"kindString":"Enumeration member","flags":{"isExported":true},"comment":{"shortText":"Validate the binding when it updates the model due to a change in the view."},"sources":[{"fileName":"aurelia-validation.d.ts","line":140,"character":14}],"defaultValue":"2"},{"id":56,"name":"changeOrBlur","kind":16,"kindString":"Enumeration member","flags":{"isExported":true},"comment":{"shortText":"Validate the binding when the binding's target element fires a DOM \"blur\" event and\nwhen it updates the model due to a change in the view."},"sources":[{"fileName":"aurelia-validation.d.ts","line":145,"character":20}],"defaultValue":"3"},{"id":53,"name":"manual","kind":16,"kindString":"Enumeration member","flags":{"isExported":true},"comment":{"shortText":"Manual validation. Use the controller's `validate()` and `reset()` methods\nto validate all bindings."},"sources":[{"fileName":"aurelia-validation.d.ts","line":132,"character":14}],"defaultValue":"0"}],"groups":[{"title":"Enumeration members","kind":16,"children":[54,55,56,53]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":127,"character":31}]},{"id":760,"name":"AureliaValidationConfiguration","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Aurelia Validation Configuration API"},"children":[{"id":761,"name":"validatorType","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":1007,"character":29}],"type":{"type":"intrinsic","name":"any"}},{"id":769,"name":"apply","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":770,"name":"apply","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the configuration."},"parameters":[{"id":771,"name":"container","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Container"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":1017,"character":13}]},{"id":762,"name":"customValidator","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":763,"name":"customValidator","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Use a custom Validator implementation."},"parameters":[{"id":764,"name":"type","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reflection","declaration":{"id":765,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"children":[{"id":766,"name":"constructor","kind":512,"kindString":"Constructor","flags":{},"signatures":[{"id":767,"name":"new __type","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":768,"name":"args","kind":32768,"kindString":"Parameter","flags":{"isRest":true},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}}],"type":{"type":"reference","name":"Validator","id":38}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":1011,"character":31}]}],"groups":[{"title":"Constructors","kind":512,"children":[766]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":1011,"character":29}]}}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":1011,"character":23}]}],"groups":[{"title":"Properties","kind":1024,"children":[761]},{"title":"Methods","kind":2048,"children":[769,762]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":1006,"character":47}]},{"id":350,"name":"ExpressionVisitor","kind":128,"kindString":"Class","flags":{"isExported":true},"children":[{"id":405,"name":"visitArgs","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":579,"character":25}],"type":{"type":"intrinsic","name":"any"}},{"id":375,"name":"visitAccessKeyed","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":376,"name":"visitAccessKeyed","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":377,"name":"access","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AccessKeyed"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":569,"character":24}]},{"id":372,"name":"visitAccessMember","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":373,"name":"visitAccessMember","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":374,"name":"access","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AccessMember"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":568,"character":25}]},{"id":369,"name":"visitAccessScope","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":370,"name":"visitAccessScope","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":371,"name":"access","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AccessScope"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":567,"character":24}]},{"id":366,"name":"visitAccessThis","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":367,"name":"visitAccessThis","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":368,"name":"access","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AccessThis","id":803}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":566,"character":23}]},{"id":360,"name":"visitAssign","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":361,"name":"visitAssign","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":362,"name":"assign","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Assign","id":802}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":564,"character":19}]},{"id":390,"name":"visitBinary","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":391,"name":"visitBinary","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":392,"name":"binary","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Binary"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":574,"character":19}]},{"id":354,"name":"visitBindingBehavior","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":355,"name":"visitBindingBehavior","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":356,"name":"behavior","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"BindingBehavior"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":562,"character":28}]},{"id":381,"name":"visitCallFunction","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":382,"name":"visitCallFunction","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":383,"name":"call","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"CallFunction","id":806}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":571,"character":25}]},{"id":384,"name":"visitCallMember","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":385,"name":"visitCallMember","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":386,"name":"call","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"CallMember"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":572,"character":23}]},{"id":378,"name":"visitCallScope","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":379,"name":"visitCallScope","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":380,"name":"call","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"CallScope","id":805}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":570,"character":22}]},{"id":351,"name":"visitChain","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":352,"name":"visitChain","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":353,"name":"chain","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Chain","id":801}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":561,"character":18}]},{"id":363,"name":"visitConditional","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":364,"name":"visitConditional","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":365,"name":"conditional","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Conditional"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":565,"character":24}]},{"id":396,"name":"visitLiteralArray","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":397,"name":"visitLiteralArray","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":398,"name":"literal","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"LiteralArray","id":809}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":576,"character":25}]},{"id":399,"name":"visitLiteralObject","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":400,"name":"visitLiteralObject","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":401,"name":"literal","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"LiteralObject","id":810}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":577,"character":26}]},{"id":393,"name":"visitLiteralPrimitive","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":394,"name":"visitLiteralPrimitive","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":395,"name":"literal","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"LiteralPrimitive","id":808}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":575,"character":29}]},{"id":402,"name":"visitLiteralString","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":403,"name":"visitLiteralString","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":404,"name":"literal","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"LiteralString","id":811}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":578,"character":26}]},{"id":387,"name":"visitPrefix","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":388,"name":"visitPrefix","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":389,"name":"prefix","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"PrefixNot","id":807}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":573,"character":19}]},{"id":357,"name":"visitValueConverter","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":358,"name":"visitValueConverter","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":359,"name":"converter","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValueConverter"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":563,"character":27}]}],"groups":[{"title":"Properties","kind":1024,"children":[405]},{"title":"Methods","kind":2048,"children":[375,372,369,366,360,390,354,381,384,378,351,363,396,399,393,402,387,357]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":560,"character":34}],"extendedBy":[{"type":"reference","name":"MessageExpressionValidator","id":420}]},{"id":701,"name":"FluentEnsure","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Part of the fluent rule API. Enables targeting properties and objects with rules."},"typeParameter":[{"id":702,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}}],"children":[{"id":705,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":706,"name":"new FluentEnsure","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":707,"name":"parsers","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Parsers","id":757}}],"type":{"type":"reference","name":"FluentEnsure","id":701}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":915,"character":38}]},{"id":717,"name":"assertInitialized","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":932,"character":33}],"type":{"type":"intrinsic","name":"any"}},{"id":718,"name":"mergeRules","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":933,"character":26}],"type":{"type":"intrinsic","name":"any"}},{"id":703,"name":"parsers","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":911,"character":23}],"type":{"type":"intrinsic","name":"any"}},{"id":704,"name":"rules","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"Rules that have been defined using the fluent API."},"sources":[{"fileName":"aurelia-validation.d.ts","line":915,"character":13}],"type":{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"any"}]}}}},{"id":708,"name":"ensure","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":709,"name":"ensure","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Target a property with validation rules."},"typeParameter":[{"id":710,"name":"TValue","kind":131072,"kindString":"Type parameter","flags":{}}],"parameters":[{"id":711,"name":"property","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The property to target. Can be the property name or a property accessor\nfunction.\n"},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"},{"type":"reference","name":"PropertyAccessor","id":789,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}]}}],"type":{"type":"reference","name":"FluentRules","id":623,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"any"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":922,"character":14}]},{"id":712,"name":"ensureObject","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":713,"name":"ensureObject","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Targets an object with validation rules."},"type":{"type":"reference","name":"FluentRules","id":623,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"any"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":926,"character":20}]},{"id":714,"name":"on","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":715,"name":"on","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the rules to a class or object, making them discoverable by the StandardValidator."},"parameters":[{"id":716,"name":"target","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"A class or object.\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"this"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":931,"character":10}]}],"groups":[{"title":"Constructors","kind":512,"children":[705]},{"title":"Properties","kind":1024,"children":[717,718,703,704]},{"title":"Methods","kind":2048,"children":[708,712,714]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":910,"character":29}]},{"id":526,"name":"FluentRuleCustomizer","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Part of the fluent rule API. Enables customizing property rules."},"typeParameter":[{"id":527,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}},{"id":528,"name":"TValue","kind":131072,"kindString":"Type parameter","flags":{}}],"children":[{"id":533,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":534,"name":"new FluentRuleCustomizer","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":535,"name":"property","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"RuleProperty","id":317}},{"id":536,"name":"condition","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reflection","declaration":{"id":537,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":538,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":539,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TValue"}},{"id":540,"name":"object","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"reference","name":"TObject","id":527}}],"type":{"type":"union","types":[{"type":"intrinsic","name":"boolean"},{"type":"reference","name":"Promise","typeArguments":[{"type":"intrinsic","name":"boolean"}]}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":681,"character":54}]}}},{"id":541,"name":"config","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"union","types":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"undefined"}]}},{"id":542,"name":"fluentEnsure","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"FluentEnsure","id":701,"typeArguments":[{"type":"typeParameter","name":"TObject"}]}},{"id":543,"name":"fluentRules","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"FluentRules","id":623,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}},{"id":544,"name":"parsers","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Parsers","id":757}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":680,"character":21}]},{"id":529,"name":"fluentEnsure","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":677,"character":28}],"type":{"type":"intrinsic","name":"any"}},{"id":530,"name":"fluentRules","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":678,"character":27}],"type":{"type":"intrinsic","name":"any"}},{"id":531,"name":"parsers","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":679,"character":23}],"type":{"type":"intrinsic","name":"any"}},{"id":532,"name":"rule","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":680,"character":20}],"type":{"type":"intrinsic","name":"any"}},{"id":571,"name":"rules","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"Rules that have been defined using the fluent API."},"sources":[{"fileName":"aurelia-validation.d.ts","line":719,"character":22}],"type":{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"any"}]}}}},{"id":616,"name":"between","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":617,"name":"between","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"between\" NUMBER validation rule to the property.\nValue must be between but not equal to the specified min and max.\nnull and undefined values are considered valid."},"parameters":[{"id":618,"name":"min","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}},{"id":619,"name":"max","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":797,"character":15}]},{"id":592,"name":"email","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":593,"name":"email","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"email\" rule to the property.\nnull, undefined and empty-string values are considered valid."},"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":753,"character":13}]},{"id":562,"name":"ensure","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":563,"name":"ensure","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Target a property with validation rules."},"typeParameter":[{"id":564,"name":"TValue2","kind":131072,"kindString":"Type parameter","flags":{}}],"parameters":[{"id":565,"name":"subject","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"reflection","declaration":{"id":566,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":567,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":568,"name":"model","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TObject"}}],"type":{"type":"typeParameter","name":"TValue2"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":711,"character":41}]}}]}}],"type":{"type":"reference","name":"FluentRules","id":623,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"any"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":711,"character":14}]},{"id":569,"name":"ensureObject","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":570,"name":"ensureObject","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Targets an object with validation rules."},"type":{"type":"reference","name":"FluentRules","id":623,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"any"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":715,"character":20}]},{"id":620,"name":"equals","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":621,"name":"equals","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"equals\" validation rule to the property.\nnull, undefined and empty-string values are considered valid."},"parameters":[{"id":622,"name":"expectedValue","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TValue"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":802,"character":14}]},{"id":589,"name":"matches","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":590,"name":"matches","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"matches\" rule to the property.\nValue must match the specified regular expression.\nnull, undefined and empty-string values are considered valid."},"parameters":[{"id":591,"name":"regex","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"RegExp"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":748,"character":15}]},{"id":609,"name":"max","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":610,"name":"max","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"max\" NUMBER validation rule to the property.\nValue must be less than or equal to the specified constraint.\nnull and undefined values are considered valid."},"parameters":[{"id":611,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":785,"character":11}]},{"id":603,"name":"maxItems","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":604,"name":"maxItems","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"maxItems\" ARRAY validation rule to the property.\nnull and undefined values are considered valid."},"parameters":[{"id":605,"name":"count","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":773,"character":16}]},{"id":597,"name":"maxLength","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":598,"name":"maxLength","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"maxLength\" STRING validation rule to the property.\nnull, undefined and empty-string values are considered valid."},"parameters":[{"id":599,"name":"length","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":763,"character":17}]},{"id":606,"name":"min","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":607,"name":"min","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"min\" NUMBER validation rule to the property.\nValue must be greater than or equal to the specified constraint.\nnull and undefined values are considered valid."},"parameters":[{"id":608,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":779,"character":11}]},{"id":600,"name":"minItems","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":601,"name":"minItems","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"minItems\" ARRAY validation rule to the property.\nnull and undefined values are considered valid."},"parameters":[{"id":602,"name":"count","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":768,"character":16}]},{"id":594,"name":"minLength","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":595,"name":"minLength","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"minLength\" STRING validation rule to the property.\nnull, undefined and empty-string values are considered valid."},"parameters":[{"id":596,"name":"length","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":758,"character":17}]},{"id":572,"name":"on","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":573,"name":"on","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the rules to a class or object, making them discoverable by the StandardValidator."},"parameters":[{"id":574,"name":"target","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"A class or object.\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"reference","name":"FluentEnsure","id":701,"typeArguments":[{"type":"typeParameter","name":"TObject"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":724,"character":10}]},{"id":612,"name":"range","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":613,"name":"range","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"range\" NUMBER validation rule to the property.\nValue must be between or equal to the specified min and max.\nnull and undefined values are considered valid."},"parameters":[{"id":614,"name":"min","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}},{"id":615,"name":"max","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":791,"character":13}]},{"id":587,"name":"required","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":588,"name":"required","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"required\" rule to the property.\nThe value cannot be null, undefined or whitespace."},"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":742,"character":16}]},{"id":575,"name":"satisfies","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":576,"name":"satisfies","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies an ad-hoc rule function to the ensured property or object."},"parameters":[{"id":577,"name":"condition","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The function to validate the rule.\nWill be called with two arguments, the property value and the object.\nShould return a boolean or a Promise that resolves to a boolean.\n"},"type":{"type":"reflection","declaration":{"id":578,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":579,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":580,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TValue"}},{"id":581,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TObject"}}],"type":{"type":"union","types":[{"type":"intrinsic","name":"boolean"},{"type":"reference","name":"Promise","typeArguments":[{"type":"intrinsic","name":"boolean"}]}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":731,"character":28}]}}},{"id":582,"name":"config","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"intrinsic","name":"undefined"},{"type":"intrinsic","name":"object"}]}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":731,"character":17}]},{"id":583,"name":"satisfiesRule","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":584,"name":"satisfiesRule","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies a rule by name."},"parameters":[{"id":585,"name":"name","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The name of the custom or standard rule."},"type":{"type":"intrinsic","name":"string"}},{"id":586,"name":"args","kind":32768,"kindString":"Parameter","flags":{"isRest":true},"comment":{"text":"The rule's arguments.\n"},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":737,"character":21}]},{"id":559,"name":"tag","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":560,"name":"tag","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Tags the rule instance, enabling the rule to be found easily\nusing ValidationRules.taggedRules(rules, tag)"},"parameters":[{"id":561,"name":"tag","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"this"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":706,"character":11}]},{"id":545,"name":"then","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":546,"name":"then","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Validate subsequent rules after previously declared rules have\nbeen validated successfully. Use to postpone validation of costly\nrules until less expensive rules pass validation."},"type":{"type":"intrinsic","name":"this"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":687,"character":12}]},{"id":553,"name":"when","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":554,"name":"when","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Specifies a condition that must be met before attempting to validate the rule."},"parameters":[{"id":555,"name":"condition","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"A function that accepts the object as a parameter and returns true\nor false whether the rule should be evaluated.\n"},"type":{"type":"reflection","declaration":{"id":556,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":557,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":558,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TObject"}}],"type":{"type":"intrinsic","name":"boolean"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":701,"character":23}]}}}],"type":{"type":"intrinsic","name":"this"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":701,"character":12}]},{"id":550,"name":"withMessage","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":551,"name":"withMessage","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Specifies rule's validation message."},"parameters":[{"id":552,"name":"message","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"this"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":695,"character":19}]},{"id":547,"name":"withMessageKey","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":548,"name":"withMessageKey","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Specifies the key to use when looking up the rule's validation message."},"parameters":[{"id":549,"name":"key","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"this"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":691,"character":22}]}],"groups":[{"title":"Constructors","kind":512,"children":[533]},{"title":"Properties","kind":1024,"children":[529,530,531,532,571]},{"title":"Methods","kind":2048,"children":[616,592,562,569,620,589,609,603,597,606,600,594,572,612,587,575,583,559,545,553,550,547]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":676,"character":37}]},{"id":623,"name":"FluentRules","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Part of the fluent rule API. Enables applying rules to properties and objects."},"typeParameter":[{"id":624,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}},{"id":625,"name":"TValue","kind":131072,"kindString":"Type parameter","flags":{}}],"children":[{"id":645,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":646,"name":"new FluentRules","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":647,"name":"fluentEnsure","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"FluentEnsure","id":701,"typeArguments":[{"type":"typeParameter","name":"TObject"}]}},{"id":648,"name":"parsers","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Parsers","id":757}},{"id":649,"name":"property","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"RuleProperty","id":317}}],"type":{"type":"reference","name":"FluentRules","id":623}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":822,"character":25}]},{"id":626,"name":"fluentEnsure","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":808,"character":28}],"type":{"type":"intrinsic","name":"any"}},{"id":627,"name":"parsers","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":809,"character":23}],"type":{"type":"intrinsic","name":"any"}},{"id":628,"name":"property","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":810,"character":24}],"type":{"type":"intrinsic","name":"any"}},{"id":644,"name":"sequence","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"Current rule sequence number. Used to postpone evaluation of rules until rules\nwith lower sequence number have successfully validated. The \"then\" fluent API method\nmanages this property, there's usually no need to set it directly."},"sources":[{"fileName":"aurelia-validation.d.ts","line":822,"character":16}],"type":{"type":"intrinsic","name":"number"}},{"id":629,"name":"customRules","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":811,"character":26}],"type":{"type":"reflection","declaration":{"id":630,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"indexSignature":{"id":631,"name":"__index","kind":8192,"kindString":"Index signature","flags":{},"parameters":[{"id":632,"name":"name","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reflection","declaration":{"id":633,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"children":[{"id":640,"name":"argsToConfig","kind":32,"kindString":"Variable","flags":{"isOptional":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":814,"character":28}],"type":{"type":"union","types":[{"type":"intrinsic","name":"undefined"},{"type":"reflection","declaration":{"id":641,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":642,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":643,"name":"args","kind":32768,"kindString":"Parameter","flags":{"isRest":true},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}}],"type":{"type":"intrinsic","name":"any"}}]}}]}},{"id":634,"name":"condition","kind":32,"kindString":"Variable","flags":{},"sources":[{"fileName":"aurelia-validation.d.ts","line":813,"character":25}],"type":{"type":"reflection","declaration":{"id":635,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":636,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":637,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":638,"name":"object","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"intrinsic","name":"any"}},{"id":639,"name":"fluentArgs","kind":32768,"kindString":"Parameter","flags":{"isRest":true},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}}],"type":{"type":"union","types":[{"type":"intrinsic","name":"boolean"},{"type":"reference","name":"Promise","typeArguments":[{"type":"intrinsic","name":"boolean"}]}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":813,"character":26}]}}}],"groups":[{"title":"Variables","kind":32,"children":[640,634]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":812,"character":27}]}}},"sources":[{"fileName":"aurelia-validation.d.ts","line":811,"character":27}]}}},{"id":694,"name":"between","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":695,"name":"between","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"between\" NUMBER validation rule to the property.\nValue must be between but not equal to the specified min and max.\nnull and undefined values are considered valid."},"parameters":[{"id":696,"name":"min","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}},{"id":697,"name":"max","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":900,"character":15}]},{"id":650,"name":"displayName","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":651,"name":"displayName","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Sets the display name of the ensured property."},"parameters":[{"id":652,"name":"name","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"reference","name":"ValidationDisplayNameAccessor","id":798},{"type":"intrinsic","name":"null"}]}}],"type":{"type":"intrinsic","name":"this"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":827,"character":19}]},{"id":670,"name":"email","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":671,"name":"email","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"email\" rule to the property.\nnull, undefined and empty-string values are considered valid."},"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":856,"character":13}]},{"id":698,"name":"equals","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":699,"name":"equals","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"equals\" validation rule to the property.\nnull and undefined values are considered valid."},"parameters":[{"id":700,"name":"expectedValue","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TValue"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":905,"character":14}]},{"id":667,"name":"matches","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":668,"name":"matches","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"matches\" rule to the property.\nValue must match the specified regular expression.\nnull, undefined and empty-string values are considered valid."},"parameters":[{"id":669,"name":"regex","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"RegExp"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":851,"character":15}]},{"id":687,"name":"max","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":688,"name":"max","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"max\" NUMBER validation rule to the property.\nValue must be less than or equal to the specified constraint.\nnull and undefined values are considered valid."},"parameters":[{"id":689,"name":"constraint","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":888,"character":11}]},{"id":681,"name":"maxItems","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":682,"name":"maxItems","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"maxItems\" ARRAY validation rule to the property.\nnull and undefined values are considered valid."},"parameters":[{"id":683,"name":"count","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":876,"character":16}]},{"id":675,"name":"maxLength","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":676,"name":"maxLength","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"maxLength\" STRING validation rule to the property.\nnull, undefined and empty-string values are considered valid."},"parameters":[{"id":677,"name":"length","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":866,"character":17}]},{"id":684,"name":"min","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":685,"name":"min","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"min\" NUMBER validation rule to the property.\nValue must be greater than or equal to the specified constraint.\nnull and undefined values are considered valid."},"parameters":[{"id":686,"name":"constraint","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":882,"character":11}]},{"id":678,"name":"minItems","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":679,"name":"minItems","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"minItems\" ARRAY validation rule to the property.\nnull and undefined values are considered valid."},"parameters":[{"id":680,"name":"count","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":871,"character":16}]},{"id":672,"name":"minLength","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":673,"name":"minLength","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"minLength\" STRING validation rule to the property.\nnull, undefined and empty-string values are considered valid."},"parameters":[{"id":674,"name":"length","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":861,"character":17}]},{"id":690,"name":"range","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":691,"name":"range","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"range\" NUMBER validation rule to the property.\nValue must be between or equal to the specified min and max.\nnull and undefined values are considered valid."},"parameters":[{"id":692,"name":"min","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}},{"id":693,"name":"max","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":894,"character":13}]},{"id":665,"name":"required","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":666,"name":"required","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the \"required\" rule to the property.\nThe value cannot be null, undefined or whitespace."},"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":845,"character":16}]},{"id":653,"name":"satisfies","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":654,"name":"satisfies","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies an ad-hoc rule function to the ensured property or object."},"parameters":[{"id":655,"name":"condition","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The function to validate the rule.\nWill be called with two arguments, the property value and the object.\nShould return a boolean or a Promise that resolves to a boolean.\n"},"type":{"type":"reflection","declaration":{"id":656,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":657,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":658,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TValue"}},{"id":659,"name":"object","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"reference","name":"TObject","id":624}}],"type":{"type":"union","types":[{"type":"intrinsic","name":"boolean"},{"type":"reference","name":"Promise","typeArguments":[{"type":"intrinsic","name":"boolean"}]}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":834,"character":28}]}}},{"id":660,"name":"config","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"intrinsic","name":"undefined"},{"type":"intrinsic","name":"object"}]}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":834,"character":17}]},{"id":661,"name":"satisfiesRule","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":662,"name":"satisfiesRule","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies a rule by name."},"parameters":[{"id":663,"name":"name","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The name of the custom or standard rule."},"type":{"type":"intrinsic","name":"string"}},{"id":664,"name":"args","kind":32768,"kindString":"Parameter","flags":{"isRest":true},"comment":{"text":"The rule's arguments.\n"},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}}],"type":{"type":"reference","name":"FluentRuleCustomizer","id":526,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":840,"character":21}]}],"groups":[{"title":"Constructors","kind":512,"children":[645]},{"title":"Properties","kind":1024,"children":[626,627,628,644,629]},{"title":"Methods","kind":2048,"children":[694,650,670,698,667,687,681,675,684,678,672,690,665,653,661]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":807,"character":28}]},{"id":420,"name":"MessageExpressionValidator","kind":128,"kindString":"Class","flags":{"isExported":true},"children":[{"id":426,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":427,"name":"new MessageExpressionValidator","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":428,"name":"originalMessage","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"MessageExpressionValidator","id":420}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":597,"character":79}]},{"id":421,"name":"originalMessage","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":596,"character":31}],"type":{"type":"intrinsic","name":"any"}},{"id":453,"name":"visitAccessKeyed","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":454,"name":"visitAccessKeyed","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":455,"name":"access","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AccessKeyed"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitAccessKeyed","id":375}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":569,"character":24}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitAccessKeyed","id":375}},{"id":450,"name":"visitAccessMember","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":451,"name":"visitAccessMember","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":452,"name":"access","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AccessMember"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitAccessMember","id":372}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":568,"character":25}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitAccessMember","id":372}},{"id":429,"name":"visitAccessScope","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":430,"name":"visitAccessScope","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":431,"name":"access","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AccessScope"}}],"type":{"type":"intrinsic","name":"void"},"overwrites":{"type":"reference","name":"ExpressionVisitor.visitAccessScope","id":369}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":599,"character":24}],"overwrites":{"type":"reference","name":"ExpressionVisitor.visitAccessScope","id":369}},{"id":447,"name":"visitAccessThis","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":448,"name":"visitAccessThis","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":449,"name":"access","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AccessThis","id":803}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitAccessThis","id":366}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":566,"character":23}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitAccessThis","id":366}},{"id":441,"name":"visitAssign","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":442,"name":"visitAssign","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":443,"name":"assign","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Assign","id":802}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitAssign","id":360}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":564,"character":19}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitAssign","id":360}},{"id":468,"name":"visitBinary","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":469,"name":"visitBinary","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":470,"name":"binary","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Binary"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitBinary","id":390}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":574,"character":19}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitBinary","id":390}},{"id":435,"name":"visitBindingBehavior","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":436,"name":"visitBindingBehavior","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":437,"name":"behavior","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"BindingBehavior"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitBindingBehavior","id":354}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":562,"character":28}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitBindingBehavior","id":354}},{"id":459,"name":"visitCallFunction","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":460,"name":"visitCallFunction","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":461,"name":"call","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"CallFunction","id":806}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitCallFunction","id":381}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":571,"character":25}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitCallFunction","id":381}},{"id":462,"name":"visitCallMember","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":463,"name":"visitCallMember","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":464,"name":"call","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"CallMember"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitCallMember","id":384}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":572,"character":23}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitCallMember","id":384}},{"id":456,"name":"visitCallScope","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":457,"name":"visitCallScope","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":458,"name":"call","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"CallScope","id":805}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitCallScope","id":378}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":570,"character":22}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitCallScope","id":378}},{"id":432,"name":"visitChain","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":433,"name":"visitChain","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":434,"name":"chain","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Chain","id":801}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitChain","id":351}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":561,"character":18}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitChain","id":351}},{"id":444,"name":"visitConditional","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":445,"name":"visitConditional","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":446,"name":"conditional","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Conditional"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitConditional","id":363}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":565,"character":24}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitConditional","id":363}},{"id":474,"name":"visitLiteralArray","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":475,"name":"visitLiteralArray","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":476,"name":"literal","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"LiteralArray","id":809}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitLiteralArray","id":396}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":576,"character":25}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitLiteralArray","id":396}},{"id":477,"name":"visitLiteralObject","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":478,"name":"visitLiteralObject","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":479,"name":"literal","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"LiteralObject","id":810}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitLiteralObject","id":399}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":577,"character":26}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitLiteralObject","id":399}},{"id":471,"name":"visitLiteralPrimitive","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":472,"name":"visitLiteralPrimitive","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":473,"name":"literal","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"LiteralPrimitive","id":808}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitLiteralPrimitive","id":393}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":575,"character":29}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitLiteralPrimitive","id":393}},{"id":480,"name":"visitLiteralString","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":481,"name":"visitLiteralString","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":482,"name":"literal","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"LiteralString","id":811}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitLiteralString","id":402}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":578,"character":26}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitLiteralString","id":402}},{"id":465,"name":"visitPrefix","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":466,"name":"visitPrefix","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":467,"name":"prefix","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"PrefixNot","id":807}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitPrefix","id":387}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":573,"character":19}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitPrefix","id":387}},{"id":438,"name":"visitValueConverter","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":439,"name":"visitValueConverter","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":440,"name":"converter","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValueConverter"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitValueConverter","id":357}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":563,"character":27}],"inheritedFrom":{"type":"reference","name":"ExpressionVisitor.visitValueConverter","id":357}},{"id":422,"name":"validate","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":423,"name":"validate","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":424,"name":"expression","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Expression"}},{"id":425,"name":"originalMessage","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":597,"character":23}]}],"groups":[{"title":"Constructors","kind":512,"children":[426]},{"title":"Properties","kind":1024,"children":[421]},{"title":"Methods","kind":2048,"children":[453,450,429,447,441,468,435,459,462,456,432,444,474,477,471,480,465,438,422]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":595,"character":43}],"extendedTypes":[{"type":"reference","name":"ExpressionVisitor","id":350}]},{"id":27,"name":"PropertyAccessorParser","kind":128,"kindString":"Class","flags":{"isExported":true},"children":[{"id":30,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":31,"name":"new PropertyAccessorParser","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":32,"name":"parser","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Parser"}}],"type":{"type":"reference","name":"PropertyAccessorParser","id":27}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":91,"character":41}]},{"id":28,"name":"parser","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":90,"character":22}],"type":{"type":"intrinsic","name":"any"}},{"id":29,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":91,"character":21}],"type":{"type":"array","elementType":{"type":"reference","name":"Parser"}}},{"id":33,"name":"parse","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":34,"name":"parse","kind":4096,"kindString":"Call signature","flags":{},"typeParameter":[{"id":35,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}},{"id":36,"name":"TValue","kind":131072,"kindString":"Type parameter","flags":{}}],"parameters":[{"id":37,"name":"property","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"},{"type":"reference","name":"PropertyAccessor","id":789,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}]}}],"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":93,"character":13}]}],"groups":[{"title":"Constructors","kind":512,"children":[30]},{"title":"Properties","kind":1024,"children":[28,29]},{"title":"Methods","kind":2048,"children":[33]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":89,"character":39}]},{"id":338,"name":"Rules","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Sets, unsets and retrieves rules on an object or constructor function."},"children":[{"id":339,"name":"key","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isPrivate":true,"isExported":true},"comment":{"shortText":"The name of the property that stores the rules."},"sources":[{"fileName":"aurelia-validation.d.ts","line":534,"character":26}],"type":{"type":"intrinsic","name":"any"}},{"id":347,"name":"get","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":348,"name":"get","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Retrieves the target's rules."},"parameters":[{"id":349,"name":"target","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"union","types":[{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"any"}]}}},{"type":"intrinsic","name":"null"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":546,"character":18}]},{"id":340,"name":"set","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":341,"name":"set","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Applies the rules to a target."},"parameters":[{"id":342,"name":"target","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":343,"name":"rules","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"any"}]}}}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":538,"character":18}]},{"id":344,"name":"unset","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":345,"name":"unset","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Removes rules from a target."},"parameters":[{"id":346,"name":"target","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":542,"character":20}]}],"groups":[{"title":"Properties","kind":1024,"children":[339]},{"title":"Methods","kind":2048,"children":[347,340,344]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":530,"character":22}]},{"id":501,"name":"StandardValidator","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Validates.\nResponsible for validating objects and properties."},"children":[{"id":506,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":507,"name":"new StandardValidator","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":508,"name":"messageProvider","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValidationMessageProvider","id":486}},{"id":509,"name":"resources","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ViewResources"}}],"type":{"type":"reference","name":"StandardValidator","id":501}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":643,"character":31}]},{"id":505,"name":"getDisplayName","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":643,"character":30}],"type":{"type":"intrinsic","name":"any"}},{"id":523,"name":"getMessage","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":666,"character":26}],"type":{"type":"intrinsic","name":"any"}},{"id":504,"name":"lookupFunctions","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":642,"character":31}],"type":{"type":"intrinsic","name":"any"}},{"id":503,"name":"messageProvider","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":641,"character":31}],"type":{"type":"intrinsic","name":"any"}},{"id":525,"name":"validate","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":668,"character":24}],"type":{"type":"intrinsic","name":"any"}},{"id":524,"name":"validateRuleSequence","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":667,"character":36}],"type":{"type":"intrinsic","name":"any"}},{"id":502,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":640,"character":21}],"type":{"type":"array","elementType":{"type":"union","types":[{"type":"reference","name":"ViewResources"},{"type":"reference","name":"ValidationMessageProvider","id":486}]}}},{"id":519,"name":"ruleExists","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":520,"name":"ruleExists","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Determines whether a rule exists in a set of rules.","tags":[{"tag":"parem","text":"rule The rule to find.\n"}]},"parameters":[{"id":521,"name":"rules","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The rules to search."},"type":{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"any"}]}}}},{"id":522,"name":"rule","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"any"}]}}],"type":{"type":"intrinsic","name":"boolean"},"overwrites":{"type":"reference","name":"Validator.ruleExists","id":48}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":665,"character":18}],"overwrites":{"type":"reference","name":"Validator.ruleExists","id":48}},{"id":515,"name":"validateObject","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":516,"name":"validateObject","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Validates all rules for specified object and it's properties."},"parameters":[{"id":517,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The object to validate."},"type":{"type":"intrinsic","name":"any"}},{"id":518,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"Optional. If unspecified, the rules will be looked up using the metadata\nfor the object created by ValidationRules....on(class/object)\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"reference","name":"Promise","typeArguments":[{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}]},"overwrites":{"type":"reference","name":"Validator.validateObject","id":44}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":659,"character":22}],"overwrites":{"type":"reference","name":"Validator.validateObject","id":44}},{"id":510,"name":"validateProperty","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":511,"name":"validateProperty","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Validates the specified property."},"parameters":[{"id":512,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The object to validate."},"type":{"type":"intrinsic","name":"any"}},{"id":513,"name":"propertyName","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The name of the property to validate."},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"}]}},{"id":514,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"Optional. If unspecified, the rules will be looked up using the metadata\nfor the object created by ValidationRules....on(class/object)\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"reference","name":"Promise","typeArguments":[{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}]},"overwrites":{"type":"reference","name":"Validator.validateProperty","id":39}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":652,"character":24}],"overwrites":{"type":"reference","name":"Validator.validateProperty","id":39}}],"groups":[{"title":"Constructors","kind":512,"children":[506]},{"title":"Properties","kind":1024,"children":[505,523,504,503,525,524,502]},{"title":"Methods","kind":2048,"children":[519,515,510]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":639,"character":34}],"extendedTypes":[{"type":"reference","name":"Validator","id":38}]},{"id":177,"name":"ValidateBindingBehavior","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Binding behavior. Indicates the bound property should be validated\nwhen the validate trigger specified by the associated controller's\nvalidateTrigger property occurs."},"children":[{"id":182,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":183,"name":"new ValidateBindingBehavior","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":184,"name":"taskQueue","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"TaskQueue"}}],"type":{"type":"reference","name":"ValidateBindingBehavior","id":177},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":389,"character":26}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}},{"id":178,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":405,"character":21}],"type":{"type":"array","elementType":{"type":"reference","name":"TaskQueue"}}},{"id":185,"name":"bind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":186,"name":"bind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":187,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":188,"name":"source","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":189,"name":"rulesOrController","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"reference","name":"ValidationController","id":81},{"type":"intrinsic","name":"any"}]}},{"id":190,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":392,"character":12}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}},{"id":179,"name":"getValidateTrigger","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":180,"name":"getValidateTrigger","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":181,"name":"controller","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValidationController","id":81}}],"type":{"type":"reference","name":"validateTrigger","id":52},"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":406,"character":26}],"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}},{"id":191,"name":"unbind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":192,"name":"unbind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":193,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":393,"character":14}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"groups":[{"title":"Constructors","kind":512,"children":[182]},{"title":"Properties","kind":1024,"children":[178]},{"title":"Methods","kind":2048,"children":[185,179,191]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":404,"character":40}],"extendedTypes":[{"type":"reference","name":"ValidateBindingBehaviorBase","id":160}]},{"id":160,"name":"ValidateBindingBehaviorBase","kind":128,"kindString":"Class","flags":{"isExported":true,"isAbstract":true},"comment":{"shortText":"Binding behavior. Indicates the bound property should be validated."},"children":[{"id":162,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":163,"name":"new ValidateBindingBehaviorBase","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":164,"name":"taskQueue","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"TaskQueue"}}],"type":{"type":"reference","name":"ValidateBindingBehaviorBase","id":160}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":389,"character":26}]},{"id":161,"name":"taskQueue","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":389,"character":25}],"type":{"type":"intrinsic","name":"any"}},{"id":168,"name":"bind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":169,"name":"bind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":170,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":171,"name":"source","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":172,"name":"rulesOrController","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"reference","name":"ValidationController","id":81},{"type":"intrinsic","name":"any"}]}},{"id":173,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":392,"character":12}]},{"id":165,"name":"getValidateTrigger","kind":2048,"kindString":"Method","flags":{"isExported":true,"isProtected":true,"isAbstract":true},"signatures":[{"id":166,"name":"getValidateTrigger","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":167,"name":"controller","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValidationController","id":81}}],"type":{"type":"reference","name":"validateTrigger","id":52}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":391,"character":45}]},{"id":174,"name":"unbind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":175,"name":"unbind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":176,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":393,"character":14}]}],"groups":[{"title":"Constructors","kind":512,"children":[162]},{"title":"Properties","kind":1024,"children":[161]},{"title":"Methods","kind":2048,"children":[168,165,174]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":388,"character":53}],"extendedBy":[{"type":"reference","name":"ValidateBindingBehavior","id":177},{"type":"reference","name":"ValidateManuallyBindingBehavior","id":194},{"type":"reference","name":"ValidateOnBlurBindingBehavior","id":210},{"type":"reference","name":"ValidateOnChangeBindingBehavior","id":226},{"type":"reference","name":"ValidateOnChangeOrBlurBindingBehavior","id":242}]},{"id":68,"name":"ValidateEvent","kind":128,"kindString":"Class","flags":{"isExported":true},"children":[{"id":74,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":75,"name":"new ValidateEvent","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":76,"name":"type","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"union","types":[{"type":"stringLiteral","value":"validate"},{"type":"stringLiteral","value":"reset"}]}},{"id":77,"name":"errors","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}},{"id":78,"name":"results","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}},{"id":79,"name":"instruction","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"union","types":[{"type":"reference","name":"ValidateInstruction","id":19},{"type":"intrinsic","name":"null"}]}},{"id":80,"name":"controllerValidateResult","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"union","types":[{"type":"reference","name":"ControllerValidateResult","id":23},{"type":"intrinsic","name":"null"}]}}],"type":{"type":"reference","name":"ValidateEvent","id":68}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":220,"character":75}]},{"id":73,"name":"controllerValidateResult","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"In events with type === \"validate\", this property will contain the result\nof validating the instruction (see \"instruction\" property). Use the controllerValidateResult\nto access the validate results specific to the call to \"validate\"\n(as opposed to using the \"results\" and \"errors\" properties to access the controller's entire\nset of results/errors)."},"sources":[{"fileName":"aurelia-validation.d.ts","line":220,"character":41}],"type":{"type":"union","types":[{"type":"reference","name":"ControllerValidateResult","id":23},{"type":"intrinsic","name":"null"}]}},{"id":70,"name":"errors","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The controller's current array of errors. For an array containing both\nfailed rules and passed rules, use the \"results\" property."},"sources":[{"fileName":"aurelia-validation.d.ts","line":201,"character":23}],"type":{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}},{"id":72,"name":"instruction","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The instruction passed to the \"validate\" or \"reset\" event. Will be null when\nthe controller's validate/reset method was called with no instruction argument."},"sources":[{"fileName":"aurelia-validation.d.ts","line":212,"character":28}],"type":{"type":"union","types":[{"type":"reference","name":"ValidateInstruction","id":19},{"type":"intrinsic","name":"null"}]}},{"id":71,"name":"results","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The controller's current array of validate results. This\nincludes both passed rules and failed rules. For an array of only failed rules,\nuse the \"errors\" property."},"sources":[{"fileName":"aurelia-validation.d.ts","line":207,"character":24}],"type":{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}},{"id":69,"name":"type","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The type of validate event. Either \"validate\" or \"reset\"."},"sources":[{"fileName":"aurelia-validation.d.ts","line":196,"character":21}],"type":{"type":"union","types":[{"type":"stringLiteral","value":"validate"},{"type":"stringLiteral","value":"reset"}]}}],"groups":[{"title":"Constructors","kind":512,"children":[74]},{"title":"Properties","kind":1024,"children":[73,70,72,71,69]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":192,"character":30}]},{"id":194,"name":"ValidateManuallyBindingBehavior","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Binding behavior. Indicates the bound property will be validated\nmanually, by calling controller.validate(). No automatic validation\ntriggered by data-entry or blur will occur."},"children":[{"id":198,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":199,"name":"new ValidateManuallyBindingBehavior","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":200,"name":"taskQueue","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"TaskQueue"}}],"type":{"type":"reference","name":"ValidateManuallyBindingBehavior","id":194},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":389,"character":26}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}},{"id":195,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":414,"character":21}],"type":{"type":"array","elementType":{"type":"reference","name":"TaskQueue"}}},{"id":201,"name":"bind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":202,"name":"bind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":203,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":204,"name":"source","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":205,"name":"rulesOrController","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"reference","name":"ValidationController","id":81},{"type":"intrinsic","name":"any"}]}},{"id":206,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":392,"character":12}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}},{"id":196,"name":"getValidateTrigger","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":197,"name":"getValidateTrigger","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"reference","name":"validateTrigger","id":52},"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":415,"character":26}],"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}},{"id":207,"name":"unbind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":208,"name":"unbind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":209,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":393,"character":14}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"groups":[{"title":"Constructors","kind":512,"children":[198]},{"title":"Properties","kind":1024,"children":[195]},{"title":"Methods","kind":2048,"children":[201,196,207]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":413,"character":48}],"extendedTypes":[{"type":"reference","name":"ValidateBindingBehaviorBase","id":160}]},{"id":210,"name":"ValidateOnBlurBindingBehavior","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Binding behavior. Indicates the bound property should be validated\nwhen the associated element blurs."},"children":[{"id":214,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":215,"name":"new ValidateOnBlurBindingBehavior","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":216,"name":"taskQueue","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"TaskQueue"}}],"type":{"type":"reference","name":"ValidateOnBlurBindingBehavior","id":210},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":389,"character":26}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}},{"id":211,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":422,"character":21}],"type":{"type":"array","elementType":{"type":"reference","name":"TaskQueue"}}},{"id":217,"name":"bind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":218,"name":"bind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":219,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":220,"name":"source","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":221,"name":"rulesOrController","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"reference","name":"ValidationController","id":81},{"type":"intrinsic","name":"any"}]}},{"id":222,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":392,"character":12}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}},{"id":212,"name":"getValidateTrigger","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":213,"name":"getValidateTrigger","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"reference","name":"validateTrigger","id":52},"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":423,"character":26}],"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}},{"id":223,"name":"unbind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":224,"name":"unbind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":225,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":393,"character":14}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"groups":[{"title":"Constructors","kind":512,"children":[214]},{"title":"Properties","kind":1024,"children":[211]},{"title":"Methods","kind":2048,"children":[217,212,223]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":421,"character":46}],"extendedTypes":[{"type":"reference","name":"ValidateBindingBehaviorBase","id":160}]},{"id":226,"name":"ValidateOnChangeBindingBehavior","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Binding behavior. Indicates the bound property should be validated\nwhen the associated element is changed by the user, causing a change\nto the model."},"children":[{"id":230,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":231,"name":"new ValidateOnChangeBindingBehavior","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":232,"name":"taskQueue","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"TaskQueue"}}],"type":{"type":"reference","name":"ValidateOnChangeBindingBehavior","id":226},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":389,"character":26}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}},{"id":227,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":431,"character":21}],"type":{"type":"array","elementType":{"type":"reference","name":"TaskQueue"}}},{"id":233,"name":"bind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":234,"name":"bind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":235,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":236,"name":"source","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":237,"name":"rulesOrController","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"reference","name":"ValidationController","id":81},{"type":"intrinsic","name":"any"}]}},{"id":238,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":392,"character":12}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}},{"id":228,"name":"getValidateTrigger","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":229,"name":"getValidateTrigger","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"reference","name":"validateTrigger","id":52},"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":432,"character":26}],"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}},{"id":239,"name":"unbind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":240,"name":"unbind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":241,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":393,"character":14}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"groups":[{"title":"Constructors","kind":512,"children":[230]},{"title":"Properties","kind":1024,"children":[227]},{"title":"Methods","kind":2048,"children":[233,228,239]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":430,"character":48}],"extendedTypes":[{"type":"reference","name":"ValidateBindingBehaviorBase","id":160}]},{"id":242,"name":"ValidateOnChangeOrBlurBindingBehavior","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Binding behavior. Indicates the bound property should be validated\nwhen the associated element blurs or is changed by the user, causing\na change to the model."},"children":[{"id":246,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":247,"name":"new ValidateOnChangeOrBlurBindingBehavior","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":248,"name":"taskQueue","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"TaskQueue"}}],"type":{"type":"reference","name":"ValidateOnChangeOrBlurBindingBehavior","id":242},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":389,"character":26}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.__constructor","id":162}},{"id":243,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":440,"character":21}],"type":{"type":"array","elementType":{"type":"reference","name":"TaskQueue"}}},{"id":249,"name":"bind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":250,"name":"bind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":251,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":252,"name":"source","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":253,"name":"rulesOrController","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"reference","name":"ValidationController","id":81},{"type":"intrinsic","name":"any"}]}},{"id":254,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":392,"character":12}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.bind","id":168}},{"id":244,"name":"getValidateTrigger","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":245,"name":"getValidateTrigger","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"reference","name":"validateTrigger","id":52},"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":441,"character":26}],"overwrites":{"type":"reference","name":"ValidateBindingBehaviorBase.getValidateTrigger","id":165}},{"id":255,"name":"unbind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":256,"name":"unbind","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":257,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"},"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":393,"character":14}],"inheritedFrom":{"type":"reference","name":"ValidateBindingBehaviorBase.unbind","id":174}}],"groups":[{"title":"Constructors","kind":512,"children":[246]},{"title":"Properties","kind":1024,"children":[243]},{"title":"Methods","kind":2048,"children":[249,244,255]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":439,"character":54}],"extendedTypes":[{"type":"reference","name":"ValidateBindingBehaviorBase","id":160}]},{"id":2,"name":"ValidateResult","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"The result of validating an individual validation rule."},"children":[{"id":10,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"comment":{},"signatures":[{"id":11,"name":"new ValidateResult","kind":16384,"kindString":"Constructor signature","flags":{},"comment":{},"parameters":[{"id":12,"name":"rule","kind":32768,"kindString":"Parameter","flags":{},"comment":{"shortText":"The rule associated with the result. Validator implementation specific."},"type":{"type":"intrinsic","name":"any"}},{"id":13,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"comment":{"shortText":"The object that was validated."},"type":{"type":"intrinsic","name":"any"}},{"id":14,"name":"propertyName","kind":32768,"kindString":"Parameter","flags":{},"comment":{"shortText":"The name of the property that was validated."},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"},{"type":"intrinsic","name":"null"}]}},{"id":15,"name":"valid","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"boolean"}},{"id":16,"name":"message","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"null"}]}}],"type":{"type":"reference","name":"ValidateResult","id":2}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":19,"character":19}]},{"id":9,"name":"id","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"A number that uniquely identifies the result instance."},"sources":[{"fileName":"aurelia-validation.d.ts","line":19,"character":10}],"type":{"type":"intrinsic","name":"number"}},{"id":7,"name":"message","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":14,"character":15}],"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"null"}]}},{"id":4,"name":"object","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":11,"character":14}],"type":{"type":"intrinsic","name":"any"}},{"id":5,"name":"propertyName","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":12,"character":20}],"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"},{"type":"intrinsic","name":"null"}]}},{"id":3,"name":"rule","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":10,"character":12}],"type":{"type":"intrinsic","name":"any"}},{"id":6,"name":"valid","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":13,"character":13}],"type":{"type":"intrinsic","name":"boolean"}},{"id":8,"name":"nextId","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":15,"character":29}],"type":{"type":"intrinsic","name":"any"}},{"id":17,"name":"toString","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":18,"name":"toString","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"null"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":27,"character":16}]}],"groups":[{"title":"Constructors","kind":512,"children":[10]},{"title":"Properties","kind":1024,"children":[9,7,4,5,3,6,8]},{"title":"Methods","kind":2048,"children":[17]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":9,"character":31}]},{"id":81,"name":"ValidationController","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Orchestrates validation.\nManages a set of bindings, renderers and objects.\nExposes the current list of validation results for binding purposes."},"children":[{"id":95,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":96,"name":"new ValidationController","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":97,"name":"validator","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Validator","id":38}},{"id":98,"name":"propertyParser","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"PropertyAccessorParser","id":27}}],"type":{"type":"reference","name":"ValidationController","id":81}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":290,"character":31}]},{"id":85,"name":"bindings","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":269,"character":24}],"type":{"type":"intrinsic","name":"any"}},{"id":90,"name":"elements","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":283,"character":24}],"type":{"type":"intrinsic","name":"any"}},{"id":88,"name":"errors","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"Validation errors that have been rendered by the controller."},"sources":[{"fileName":"aurelia-validation.d.ts","line":278,"character":14}],"type":{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}},{"id":94,"name":"eventCallbacks","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":290,"character":30}],"type":{"type":"intrinsic","name":"any"}},{"id":93,"name":"finishValidating","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":289,"character":32}],"type":{"type":"intrinsic","name":"any"}},{"id":146,"name":"getAssociatedElements","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"comment":{"shortText":"Gets the elements associated with an object and propertyName (if any)."},"sources":[{"fileName":"aurelia-validation.d.ts","line":361,"character":37}],"type":{"type":"intrinsic","name":"any"}},{"id":139,"name":"getInstructionPredicate","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"comment":{"shortText":"Interprets the instruction and returns a predicate that will identify\nrelevant results in the list of rendered validation results."},"sources":[{"fileName":"aurelia-validation.d.ts","line":345,"character":39}],"type":{"type":"intrinsic","name":"any"}},{"id":159,"name":"invokeCallbacks","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":380,"character":31}],"type":{"type":"intrinsic","name":"any"}},{"id":91,"name":"objects","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":284,"character":23}],"type":{"type":"intrinsic","name":"any"}},{"id":147,"name":"processResultDelta","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":362,"character":34}],"type":{"type":"intrinsic","name":"any"}},{"id":83,"name":"propertyParser","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":267,"character":30}],"type":{"type":"intrinsic","name":"any"}},{"id":86,"name":"renderers","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":270,"character":25}],"type":{"type":"intrinsic","name":"any"}},{"id":87,"name":"results","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"comment":{"shortText":"Validation results that have been rendered by the controller."},"sources":[{"fileName":"aurelia-validation.d.ts","line":274,"character":23}],"type":{"type":"intrinsic","name":"any"}},{"id":92,"name":"validateTrigger","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The trigger that will invoke automatic validation of a property used in a binding."},"sources":[{"fileName":"aurelia-validation.d.ts","line":288,"character":23}],"type":{"type":"reference","name":"validateTrigger","id":52}},{"id":89,"name":"validating","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":" Whether the controller is currently validating."},"sources":[{"fileName":"aurelia-validation.d.ts","line":282,"character":18}],"type":{"type":"intrinsic","name":"boolean"}},{"id":82,"name":"validator","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":266,"character":25}],"type":{"type":"intrinsic","name":"any"}},{"id":84,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":268,"character":21}],"type":{"type":"array","elementType":{"type":"union","types":[{"type":"reference","name":"PropertyAccessorParser","id":27},{"type":"reference","name":"Validator","id":38}]}}},{"id":116,"name":"addError","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":117,"name":"addError","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Adds and renders an error."},"typeParameter":[{"id":118,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}}],"parameters":[{"id":119,"name":"message","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}},{"id":120,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TObject"}},{"id":121,"name":"propertyName","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"reference","name":"PropertyAccessor","id":789,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"string"}]},{"type":"intrinsic","name":"null"}]}}],"type":{"type":"reference","name":"ValidateResult","id":2}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":314,"character":16}]},{"id":109,"name":"addObject","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":110,"name":"addObject","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Adds an object to the set of objects that should be validated when validate is called."},"parameters":[{"id":111,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The object."},"type":{"type":"intrinsic","name":"any"}},{"id":112,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"Optional. The rules. If rules aren't supplied the Validator implementation will lookup the rules.\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":305,"character":17}]},{"id":125,"name":"addRenderer","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":126,"name":"addRenderer","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Adds a renderer."},"parameters":[{"id":127,"name":"renderer","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The renderer.\n"},"type":{"type":"reference","name":"ValidationRenderer","id":64}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":323,"character":19}]},{"id":154,"name":"changeTrigger","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":155,"name":"changeTrigger","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Changes the controller's validateTrigger."},"parameters":[{"id":156,"name":"newTrigger","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The new validateTrigger\n"},"type":{"type":"reference","name":"validateTrigger","id":52}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":375,"character":21}]},{"id":131,"name":"registerBinding","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":132,"name":"registerBinding","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Registers a binding with the controller."},"parameters":[{"id":133,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The binding instance."},"type":{"type":"reference","name":"Binding"}},{"id":134,"name":"target","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The DOM element."},"type":{"type":"reference","name":"Element"}},{"id":135,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"(optional) rules associated with the binding. Validator implementation specific.\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":335,"character":23}]},{"id":122,"name":"removeError","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":123,"name":"removeError","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Removes and unrenders an error."},"parameters":[{"id":124,"name":"result","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValidateResult","id":2}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":318,"character":19}]},{"id":113,"name":"removeObject","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":114,"name":"removeObject","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Removes an object from the set of objects that should be validated when validate is called."},"parameters":[{"id":115,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The object.\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":310,"character":20}]},{"id":128,"name":"removeRenderer","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":129,"name":"removeRenderer","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Removes a renderer."},"parameters":[{"id":130,"name":"renderer","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The renderer.\n"},"type":{"type":"reference","name":"ValidationRenderer","id":64}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":328,"character":22}]},{"id":143,"name":"reset","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":144,"name":"reset","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Resets any rendered validation results (unrenders)."},"parameters":[{"id":145,"name":"instruction","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"Optional. Instructions on what to reset. If unspecified all rendered results\nwill be unrendered.\n"},"type":{"type":"reference","name":"ValidateInstruction","id":19}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":357,"character":13}]},{"id":151,"name":"resetBinding","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":152,"name":"resetBinding","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Resets the results for a property associated with a binding."},"parameters":[{"id":153,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Binding"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":370,"character":20}]},{"id":157,"name":"revalidateErrors","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":158,"name":"revalidateErrors","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Revalidates the controller's current set of errors."},"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":379,"character":24}]},{"id":99,"name":"subscribe","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":100,"name":"subscribe","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Subscribe to controller validate and reset events. These events occur when the\ncontroller's \"validate\"\" and \"reset\" methods are called."},"parameters":[{"id":101,"name":"callback","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The callback to be invoked when the controller validates or resets.\n"},"type":{"type":"reflection","declaration":{"id":102,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":103,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":104,"name":"event","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValidateEvent","id":68}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":297,"character":27}]}}}],"type":{"type":"reflection","declaration":{"id":105,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"children":[{"id":106,"name":"dispose","kind":32,"kindString":"Variable","flags":{},"sources":[{"fileName":"aurelia-validation.d.ts","line":298,"character":19}],"type":{"type":"reflection","declaration":{"id":107,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":108,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":298,"character":20}]}}}],"groups":[{"title":"Variables","kind":32,"children":[106]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":297,"character":60}]}}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":297,"character":17}]},{"id":136,"name":"unregisterBinding","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":137,"name":"unregisterBinding","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Unregisters a binding with the controller."},"parameters":[{"id":138,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The binding instance.\n"},"type":{"type":"reference","name":"Binding"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":340,"character":25}]},{"id":140,"name":"validate","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":141,"name":"validate","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Validates and renders results."},"parameters":[{"id":142,"name":"instruction","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"Optional. Instructions on what to validate. If undefined, all\nobjects and bindings will be validated.\n"},"type":{"type":"reference","name":"ValidateInstruction","id":19}}],"type":{"type":"reference","name":"Promise","typeArguments":[{"type":"reference","name":"ControllerValidateResult","id":23}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":351,"character":16}]},{"id":148,"name":"validateBinding","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":149,"name":"validateBinding","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Validates the property associated with a binding."},"parameters":[{"id":150,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Binding"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":366,"character":23}]}],"groups":[{"title":"Constructors","kind":512,"children":[95]},{"title":"Properties","kind":1024,"children":[85,90,88,94,93,146,139,159,91,147,83,86,87,92,89,82,84]},{"title":"Methods","kind":2048,"children":[116,109,125,154,131,122,113,128,143,151,157,99,136,140,148]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":265,"character":37}]},{"id":258,"name":"ValidationControllerFactory","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Creates ValidationController instances."},"children":[{"id":263,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":264,"name":"new ValidationControllerFactory","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":265,"name":"container","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Container"}}],"type":{"type":"reference","name":"ValidationControllerFactory","id":258}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":451,"character":70}]},{"id":259,"name":"container","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":450,"character":25}],"type":{"type":"intrinsic","name":"any"}},{"id":266,"name":"create","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":267,"name":"create","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Creates a new controller instance."},"parameters":[{"id":268,"name":"validator","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"reference","name":"Validator","id":38}}],"type":{"type":"reference","name":"ValidationController","id":81}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":456,"character":14}]},{"id":269,"name":"createForCurrentScope","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":270,"name":"createForCurrentScope","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Creates a new controller and registers it in the current element's container so that it's\navailable to the validate binding behavior and renderers."},"parameters":[{"id":271,"name":"validator","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"reference","name":"Validator","id":38}}],"type":{"type":"reference","name":"ValidationController","id":81}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":461,"character":29}]},{"id":260,"name":"get","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":261,"name":"get","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":262,"name":"container","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Container"}}],"type":{"type":"reference","name":"ValidationControllerFactory","id":258}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":451,"character":18}]}],"groups":[{"title":"Constructors","kind":512,"children":[263]},{"title":"Properties","kind":1024,"children":[259]},{"title":"Methods","kind":2048,"children":[266,269,260]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":449,"character":44}]},{"id":275,"name":"ValidationErrorsCustomAttribute","kind":128,"kindString":"Class","flags":{"isExported":true},"children":[{"id":287,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":288,"name":"new ValidationErrorsCustomAttribute","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":289,"name":"boundaryElement","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"Element"}},{"id":290,"name":"controllerAccessor","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reflection","declaration":{"id":291,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":292,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"reference","name":"ValidationController","id":81}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":481,"character":65}]}}}],"type":{"type":"reference","name":"ValidationErrorsCustomAttribute","id":275}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":480,"character":31}]},{"id":276,"name":"boundaryElement","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":472,"character":31}],"type":{"type":"intrinsic","name":"any"}},{"id":284,"name":"controller","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":478,"character":18}],"type":{"type":"union","types":[{"type":"reference","name":"ValidationController","id":81},{"type":"intrinsic","name":"null"}]}},{"id":277,"name":"controllerAccessor","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":473,"character":34}],"type":{"type":"intrinsic","name":"any"}},{"id":285,"name":"errors","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":479,"character":14}],"type":{"type":"array","elementType":{"type":"reference","name":"RenderedError","id":272}}},{"id":286,"name":"errorsInternal","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":480,"character":30}],"type":{"type":"intrinsic","name":"any"}},{"id":301,"name":"bind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":302,"name":"bind","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":485,"character":12}]},{"id":295,"name":"interestingElements","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":296,"name":"interestingElements","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":297,"name":"elements","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"array","elementType":{"type":"reference","name":"Element"}}}],"type":{"type":"array","elementType":{"type":"reference","name":"Element"}}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":483,"character":27}]},{"id":298,"name":"render","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":299,"name":"render","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":300,"name":"instruction","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"RenderInstruction","id":60}}],"type":{"type":"intrinsic","name":"void"},"implementationOf":{"type":"reference","name":"ValidationRenderer.render","id":66}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":484,"character":14}],"implementationOf":{"type":"reference","name":"ValidationRenderer.render","id":65}},{"id":293,"name":"sort","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":294,"name":"sort","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":482,"character":12}]},{"id":303,"name":"unbind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":304,"name":"unbind","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":486,"character":14}]},{"id":278,"name":"inject","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":279,"name":"inject","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"array","elementType":{"type":"union","types":[{"type":"reflection","declaration":{"id":280,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"children":[{"id":281,"name":"constructor","kind":512,"kindString":"Constructor","flags":{},"signatures":[{"id":282,"name":"new __type","kind":16384,"kindString":"Constructor signature","flags":{},"type":{"type":"reference","name":"Element"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":474,"character":27}]},{"id":283,"name":"prototype","kind":32,"kindString":"Variable","flags":{},"sources":[{"fileName":"aurelia-validation.d.ts","line":476,"character":21}],"type":{"type":"reference","name":"Element"}}],"groups":[{"title":"Constructors","kind":512,"children":[281]},{"title":"Variables","kind":32,"children":[283]}]}},{"type":"reference","name":"Lazy"}]}}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":474,"character":21}]}],"groups":[{"title":"Constructors","kind":512,"children":[287]},{"title":"Properties","kind":1024,"children":[276,284,277,285,286]},{"title":"Methods","kind":2048,"children":[301,295,298,293,303,278]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":471,"character":48}],"implementedTypes":[{"type":"reference","name":"ValidationRenderer","id":64}]},{"id":406,"name":"ValidationMessageParser","kind":128,"kindString":"Class","flags":{"isExported":true},"children":[{"id":413,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":414,"name":"new ValidationMessageParser","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":415,"name":"bindinqLanguage","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"BindingLanguage"}}],"type":{"type":"reference","name":"ValidationMessageParser","id":406}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":590,"character":22}]},{"id":407,"name":"bindinqLanguage","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":585,"character":31}],"type":{"type":"intrinsic","name":"any"}},{"id":412,"name":"cache","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":590,"character":21}],"type":{"type":"intrinsic","name":"any"}},{"id":419,"name":"coalesce","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":593,"character":24}],"type":{"type":"intrinsic","name":"any"}},{"id":409,"name":"emptyStringExpression","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":587,"character":37}],"type":{"type":"intrinsic","name":"any"}},{"id":410,"name":"nullExpression","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":588,"character":30}],"type":{"type":"intrinsic","name":"any"}},{"id":411,"name":"undefinedExpression","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":589,"character":35}],"type":{"type":"intrinsic","name":"any"}},{"id":408,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":586,"character":21}],"type":{"type":"array","elementType":{"type":"reference","name":"BindingLanguage"}}},{"id":416,"name":"parse","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":417,"name":"parse","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":418,"name":"message","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"Expression"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":592,"character":13}]}],"groups":[{"title":"Constructors","kind":512,"children":[413]},{"title":"Properties","kind":1024,"children":[407,412,419,409,410,411,408]},{"title":"Methods","kind":2048,"children":[416]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":584,"character":40}]},{"id":486,"name":"ValidationMessageProvider","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Retrieves validation messages and property display names."},"children":[{"id":489,"name":"constructor","kind":512,"kindString":"Constructor","flags":{"isExported":true},"signatures":[{"id":490,"name":"new ValidationMessageProvider","kind":16384,"kindString":"Constructor signature","flags":{},"parameters":[{"id":491,"name":"parser","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValidationMessageParser","id":406}}],"type":{"type":"reference","name":"ValidationMessageProvider","id":486}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":615,"character":58}]},{"id":487,"name":"parser","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":614,"character":14}],"type":{"type":"reference","name":"ValidationMessageParser","id":406}},{"id":488,"name":"inject","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":615,"character":21}],"type":{"type":"array","elementType":{"type":"reference","name":"ValidationMessageParser","id":406}}},{"id":495,"name":"getDisplayName","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":496,"name":"getDisplayName","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Formulates a property display name using the property name and the configured\ndisplayName (if provided).\nOverride this with your own custom logic."},"parameters":[{"id":497,"name":"propertyName","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The property name.\n"},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"}]}},{"id":498,"name":"displayName","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"null"},{"type":"reflection","declaration":{"id":499,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":500,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"intrinsic","name":"string"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":628,"character":83}]}}]}}],"type":{"type":"intrinsic","name":"string"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":628,"character":22}]},{"id":492,"name":"getMessage","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":493,"name":"getMessage","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Returns a message binding expression that corresponds to the key."},"parameters":[{"id":494,"name":"key","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The message key.\n"},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"Expression"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":621,"character":18}]}],"groups":[{"title":"Constructors","kind":512,"children":[489]},{"title":"Properties","kind":1024,"children":[487,488]},{"title":"Methods","kind":2048,"children":[495,492]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":613,"character":42}]},{"id":305,"name":"ValidationRendererCustomAttribute","kind":128,"kindString":"Class","flags":{"isExported":true},"children":[{"id":306,"name":"container","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":490,"character":25}],"type":{"type":"intrinsic","name":"any"}},{"id":307,"name":"controller","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":491,"character":26}],"type":{"type":"intrinsic","name":"any"}},{"id":309,"name":"renderer","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":493,"character":24}],"type":{"type":"intrinsic","name":"any"}},{"id":308,"name":"value","kind":1024,"kindString":"Property","flags":{"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":492,"character":21}],"type":{"type":"intrinsic","name":"any"}},{"id":313,"name":"bind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":314,"name":"bind","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":495,"character":12}]},{"id":310,"name":"created","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":311,"name":"created","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":312,"name":"view","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":494,"character":15}]},{"id":315,"name":"unbind","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":316,"name":"unbind","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":496,"character":14}]}],"groups":[{"title":"Properties","kind":1024,"children":[306,307,309,308]},{"title":"Methods","kind":2048,"children":[313,310,315]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":489,"character":50}]},{"id":719,"name":"ValidationRules","kind":128,"kindString":"Class","flags":{"isExported":true},"comment":{"shortText":"Fluent rule definition API."},"children":[{"id":720,"name":"parsers","kind":1024,"kindString":"Property","flags":{"isStatic":true,"isPrivate":true,"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":939,"character":30}],"type":{"type":"intrinsic","name":"any"}},{"id":733,"name":"customRule","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":734,"name":"customRule","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Defines a custom rule."},"parameters":[{"id":735,"name":"name","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The name of the custom rule. Also serves as the message key."},"type":{"type":"intrinsic","name":"string"}},{"id":736,"name":"condition","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The rule function."},"type":{"type":"reflection","declaration":{"id":737,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":738,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":739,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":740,"name":"object","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"intrinsic","name":"any"}},{"id":741,"name":"args","kind":32768,"kindString":"Parameter","flags":{"isRest":true},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}}],"type":{"type":"union","types":[{"type":"intrinsic","name":"boolean"},{"type":"reference","name":"Promise","typeArguments":[{"type":"intrinsic","name":"boolean"}]}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":958,"character":50}]}}},{"id":742,"name":"message","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The message expression"},"type":{"type":"intrinsic","name":"string"}},{"id":743,"name":"argsToConfig","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"A function that maps the rule's arguments to a \"config\"\nobject that can be used when evaluating the message expression.\n"},"type":{"type":"union","types":[{"type":"intrinsic","name":"undefined"},{"type":"reflection","declaration":{"id":744,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":745,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":746,"name":"args","kind":32768,"kindString":"Parameter","flags":{"isRest":true},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}}],"type":{"type":"intrinsic","name":"any"}}]}}]}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":958,"character":25}]},{"id":725,"name":"ensure","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":726,"name":"ensure","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Target a property with validation rules."},"typeParameter":[{"id":727,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}},{"id":728,"name":"TValue","kind":131072,"kindString":"Type parameter","flags":{}}],"parameters":[{"id":729,"name":"property","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The property to target. Can be the property name or a property accessor function.\n"},"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"},{"type":"reference","name":"PropertyAccessor","id":789,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"typeParameter","name":"TValue"}]}]}}],"type":{"type":"reference","name":"FluentRules","id":623,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"any"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":945,"character":21}]},{"id":730,"name":"ensureObject","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":731,"name":"ensureObject","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Targets an object with validation rules."},"typeParameter":[{"id":732,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}}],"type":{"type":"reference","name":"FluentRules","id":623,"typeArguments":[{"type":"typeParameter","name":"TObject"},{"type":"intrinsic","name":"any"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":949,"character":27}]},{"id":721,"name":"initialize","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":722,"name":"initialize","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":723,"name":"messageParser","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"ValidationMessageParser","id":406}},{"id":724,"name":"propertyParser","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"PropertyAccessorParser","id":27}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":940,"character":25}]},{"id":754,"name":"off","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":755,"name":"off","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Removes the rules from a class or object."},"parameters":[{"id":756,"name":"target","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"A class or object.\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":974,"character":18}]},{"id":747,"name":"taggedRules","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":748,"name":"taggedRules","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Returns rules with the matching tag."},"parameters":[{"id":749,"name":"rules","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The rules to search."},"type":{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"any"}]}}}},{"id":750,"name":"tag","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The tag to search for.\n"},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"any"}]}}}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":964,"character":26}]},{"id":751,"name":"untaggedRules","kind":2048,"kindString":"Method","flags":{"isStatic":true,"isExported":true},"signatures":[{"id":752,"name":"untaggedRules","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Returns rules that have no tag."},"parameters":[{"id":753,"name":"rules","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The rules to search.\n"},"type":{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"any"}]}}}}],"type":{"type":"array","elementType":{"type":"array","elementType":{"type":"reference","name":"Rule","id":320,"typeArguments":[{"type":"intrinsic","name":"any"},{"type":"intrinsic","name":"any"}]}}}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":969,"character":28}]}],"groups":[{"title":"Properties","kind":1024,"children":[720]},{"title":"Methods","kind":2048,"children":[733,725,730,721,754,747,751]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":938,"character":32}]},{"id":38,"name":"Validator","kind":128,"kindString":"Class","flags":{"isExported":true,"isAbstract":true},"comment":{"shortText":"Validates objects and properties."},"children":[{"id":48,"name":"ruleExists","kind":2048,"kindString":"Method","flags":{"isExported":true,"isAbstract":true},"signatures":[{"id":49,"name":"ruleExists","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Determines whether a rule exists in a set of rules.","tags":[{"tag":"parem","text":"rule The rule to find.\n"}]},"parameters":[{"id":50,"name":"rules","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The rules to search."},"type":{"type":"intrinsic","name":"any"}},{"id":51,"name":"rule","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"boolean"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":121,"character":27}]},{"id":44,"name":"validateObject","kind":2048,"kindString":"Method","flags":{"isExported":true,"isAbstract":true},"signatures":[{"id":45,"name":"validateObject","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Validates all rules for specified object and it's properties."},"parameters":[{"id":46,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The object to validate."},"type":{"type":"intrinsic","name":"any"}},{"id":47,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"Optional. If unspecified, the implementation should lookup the rules for the\nspecified object. This may not be possible for all implementations of this interface.\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"reference","name":"Promise","typeArguments":[{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":115,"character":31}]},{"id":39,"name":"validateProperty","kind":2048,"kindString":"Method","flags":{"isExported":true,"isAbstract":true},"signatures":[{"id":40,"name":"validateProperty","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Validates the specified property."},"parameters":[{"id":41,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The object to validate."},"type":{"type":"intrinsic","name":"any"}},{"id":42,"name":"propertyName","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The name of the property to validate."},"type":{"type":"intrinsic","name":"string"}},{"id":43,"name":"rules","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"comment":{"text":"Optional. If unspecified, the implementation should lookup the rules for the\nspecified object. This may not be possible for all implementations of this interface.\n"},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"reference","name":"Promise","typeArguments":[{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":108,"character":33}]}],"groups":[{"title":"Methods","kind":2048,"children":[48,44,39]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":100,"character":35}],"extendedBy":[{"type":"reference","name":"StandardValidator","id":501}]},{"id":23,"name":"ControllerValidateResult","kind":256,"kindString":"Interface","flags":{"isExported":true},"comment":{"shortText":"The result of a call to the validation controller's validate method."},"children":[{"id":26,"name":"instruction","kind":1024,"kindString":"Property","flags":{"isExported":true,"isOptional":true},"comment":{"shortText":"The instruction passed to the controller's validate method."},"sources":[{"fileName":"aurelia-validation.d.ts","line":64,"character":19}],"type":{"type":"reference","name":"ValidateInstruction","id":19}},{"id":25,"name":"results","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The validation result of every rule that was evaluated."},"sources":[{"fileName":"aurelia-validation.d.ts","line":60,"character":15}],"type":{"type":"array","elementType":{"type":"reference","name":"ValidateResult","id":2}}},{"id":24,"name":"valid","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"Whether validation passed."},"sources":[{"fileName":"aurelia-validation.d.ts","line":56,"character":13}],"type":{"type":"intrinsic","name":"boolean"}}],"groups":[{"title":"Properties","kind":1024,"children":[26,25,24]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":52,"character":45}]},{"id":757,"name":"Parsers","kind":256,"kindString":"Interface","flags":{"isExported":true},"children":[{"id":758,"name":"message","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":977,"character":15}],"type":{"type":"reference","name":"ValidationMessageParser","id":406}},{"id":759,"name":"property","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":978,"character":16}],"type":{"type":"reference","name":"PropertyAccessorParser","id":27}}],"groups":[{"title":"Properties","kind":1024,"children":[758,759]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":976,"character":28}]},{"id":60,"name":"RenderInstruction","kind":256,"kindString":"Interface","flags":{"isExported":true},"comment":{"shortText":"Defines which validation results to render and which validation results to unrender."},"children":[{"id":61,"name":"kind","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The \"kind\" of render instruction. Either 'validate' or 'reset'."},"sources":[{"fileName":"aurelia-validation.d.ts","line":168,"character":12}],"type":{"type":"union","types":[{"type":"stringLiteral","value":"validate"},{"type":"stringLiteral","value":"reset"}]}},{"id":62,"name":"render","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The results to render."},"sources":[{"fileName":"aurelia-validation.d.ts","line":172,"character":14}],"type":{"type":"array","elementType":{"type":"reference","name":"ResultInstruction","id":57}}},{"id":63,"name":"unrender","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The results to unrender."},"sources":[{"fileName":"aurelia-validation.d.ts","line":176,"character":16}],"type":{"type":"array","elementType":{"type":"reference","name":"ResultInstruction","id":57}}}],"groups":[{"title":"Properties","kind":1024,"children":[61,62,63]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":164,"character":38}]},{"id":272,"name":"RenderedError","kind":256,"kindString":"Interface","flags":{"isExported":true},"children":[{"id":273,"name":"error","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":468,"character":13}],"type":{"type":"reference","name":"ValidateResult","id":2}},{"id":274,"name":"targets","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":469,"character":15}],"type":{"type":"array","elementType":{"type":"reference","name":"Element"}}}],"groups":[{"title":"Properties","kind":1024,"children":[273,274]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":467,"character":34}]},{"id":57,"name":"ResultInstruction","kind":256,"kindString":"Interface","flags":{"isExported":true},"comment":{"shortText":"A result to render (or unrender) and the associated elements (if any)"},"children":[{"id":59,"name":"elements","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The associated elements (if any)."},"sources":[{"fileName":"aurelia-validation.d.ts","line":159,"character":16}],"type":{"type":"array","elementType":{"type":"reference","name":"Element"}}},{"id":58,"name":"result","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The validation result."},"sources":[{"fileName":"aurelia-validation.d.ts","line":155,"character":14}],"type":{"type":"reference","name":"ValidateResult","id":2}}],"groups":[{"title":"Properties","kind":1024,"children":[59,58]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":151,"character":38}]},{"id":320,"name":"Rule","kind":256,"kindString":"Interface","flags":{"isExported":true},"comment":{"shortText":"A rule definition. Associations a rule with a property or object."},"typeParameter":[{"id":321,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}},{"id":322,"name":"TValue","kind":131072,"kindString":"Type parameter","flags":{}}],"children":[{"id":324,"name":"condition","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":518,"character":17}],"type":{"type":"reflection","declaration":{"id":325,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":326,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":327,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TValue"}},{"id":328,"name":"object","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"reference","name":"TObject","id":321}}],"type":{"type":"union","types":[{"type":"intrinsic","name":"boolean"},{"type":"reference","name":"Promise","typeArguments":[{"type":"intrinsic","name":"boolean"}]}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":518,"character":18}]}}},{"id":329,"name":"config","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":519,"character":14}],"type":{"type":"intrinsic","name":"object"}},{"id":335,"name":"message","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":522,"character":15}],"type":{"type":"union","types":[{"type":"reference","name":"Expression"},{"type":"intrinsic","name":"null"}]}},{"id":334,"name":"messageKey","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":521,"character":18}],"type":{"type":"intrinsic","name":"string"}},{"id":323,"name":"property","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":517,"character":16}],"type":{"type":"reference","name":"RuleProperty","id":317}},{"id":336,"name":"sequence","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":523,"character":16}],"type":{"type":"intrinsic","name":"number"}},{"id":337,"name":"tag","kind":1024,"kindString":"Property","flags":{"isExported":true,"isOptional":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":524,"character":11}],"type":{"type":"union","types":[{"type":"intrinsic","name":"undefined"},{"type":"intrinsic","name":"string"}]}},{"id":330,"name":"when","kind":1024,"kindString":"Property","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":520,"character":12}],"type":{"type":"union","types":[{"type":"reflection","declaration":{"id":331,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":332,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":333,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TObject"}}],"type":{"type":"intrinsic","name":"boolean"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":520,"character":13}]}},{"type":"intrinsic","name":"null"}]}}],"groups":[{"title":"Properties","kind":1024,"children":[324,329,335,334,323,336,337,330]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":516,"character":25}]},{"id":317,"name":"RuleProperty","kind":256,"kindString":"Interface","flags":{"isExported":true},"comment":{"shortText":"Information related to a property that is the subject of validation."},"children":[{"id":319,"name":"displayName","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The displayName of the property (or object)."},"sources":[{"fileName":"aurelia-validation.d.ts","line":511,"character":19}],"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"reference","name":"ValidationDisplayNameAccessor","id":798},{"type":"intrinsic","name":"null"}]}},{"id":318,"name":"name","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The property name. null indicates the rule targets the object itself."},"sources":[{"fileName":"aurelia-validation.d.ts","line":507,"character":12}],"type":{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"intrinsic","name":"number"},{"type":"intrinsic","name":"null"}]}}],"groups":[{"title":"Properties","kind":1024,"children":[319,318]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":503,"character":33}]},{"id":19,"name":"ValidateInstruction","kind":256,"kindString":"Interface","flags":{"isExported":true},"comment":{"shortText":"Instructions for the validation controller's validate method."},"children":[{"id":20,"name":"object","kind":1024,"kindString":"Property","flags":{"isExported":true},"comment":{"shortText":"The object to validate."},"sources":[{"fileName":"aurelia-validation.d.ts","line":37,"character":14}],"type":{"type":"intrinsic","name":"any"}},{"id":21,"name":"propertyName","kind":1024,"kindString":"Property","flags":{"isExported":true,"isOptional":true},"comment":{"shortText":"The property to validate. Optional."},"sources":[{"fileName":"aurelia-validation.d.ts","line":41,"character":20}],"type":{"type":"intrinsic","name":"any"}},{"id":22,"name":"rules","kind":1024,"kindString":"Property","flags":{"isExported":true,"isOptional":true},"comment":{"shortText":"The rules to validate. Optional."},"sources":[{"fileName":"aurelia-validation.d.ts","line":45,"character":13}],"type":{"type":"intrinsic","name":"any"}}],"groups":[{"title":"Properties","kind":1024,"children":[20,21,22]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":33,"character":40}]},{"id":483,"name":"ValidationMessages","kind":256,"kindString":"Interface","flags":{"isExported":true},"indexSignature":{"id":484,"name":"__index","kind":8192,"kindString":"Index signature","flags":{},"parameters":[{"id":485,"name":"key","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"string"}},"sources":[{"fileName":"aurelia-validation.d.ts","line":603,"character":39}]},{"id":64,"name":"ValidationRenderer","kind":256,"kindString":"Interface","flags":{"isExported":true},"comment":{"shortText":"Renders validation results."},"children":[{"id":65,"name":"render","kind":2048,"kindString":"Method","flags":{"isExported":true},"signatures":[{"id":66,"name":"render","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Render the validation results."},"parameters":[{"id":67,"name":"instruction","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The render instruction. Defines which results to render and which\nresults to unrender.\n"},"type":{"type":"reference","name":"RenderInstruction","id":60}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":187,"character":14}]}],"groups":[{"title":"Methods","kind":2048,"children":[65]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":181,"character":39}],"implementedBy":[{"type":"reference","name":"ValidationErrorsCustomAttribute","id":275}]},{"id":804,"name":"AccessScope","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":552,"character":27}],"type":{"type":"intrinsic","name":"any"}},{"id":803,"name":"AccessThis","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":551,"character":26}],"type":{"type":"intrinsic","name":"any"}},{"id":802,"name":"Assign","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":550,"character":22}],"type":{"type":"intrinsic","name":"any"}},{"id":806,"name":"CallFunction","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":554,"character":28}],"type":{"type":"intrinsic","name":"any"}},{"id":805,"name":"CallScope","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":553,"character":25}],"type":{"type":"intrinsic","name":"any"}},{"id":801,"name":"Chain","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":549,"character":21}],"type":{"type":"intrinsic","name":"any"}},{"id":809,"name":"LiteralArray","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":557,"character":28}],"type":{"type":"intrinsic","name":"any"}},{"id":810,"name":"LiteralObject","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":558,"character":29}],"type":{"type":"intrinsic","name":"any"}},{"id":808,"name":"LiteralPrimitive","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":556,"character":32}],"type":{"type":"intrinsic","name":"any"}},{"id":811,"name":"LiteralString","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":559,"character":29}],"type":{"type":"intrinsic","name":"any"}},{"id":807,"name":"PrefixNot","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":555,"character":25}],"type":{"type":"intrinsic","name":"any"}},{"id":789,"name":"PropertyAccessor","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"typeParameter":[{"id":790,"name":"TObject","kind":131072,"kindString":"Type parameter","flags":{}},{"id":791,"name":"TValue","kind":131072,"kindString":"Type parameter","flags":{}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":88,"character":32}],"type":{"type":"reflection","declaration":{"id":792,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":793,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":794,"name":"object","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"typeParameter","name":"TObject"}}],"type":{"type":"typeParameter","name":"TValue"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":88,"character":51}]}}},{"id":798,"name":"ValidationDisplayNameAccessor","kind":4194304,"kindString":"Type alias","flags":{"isExported":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":499,"character":45}],"type":{"type":"reflection","declaration":{"id":799,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":800,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"type":{"type":"intrinsic","name":"string"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":499,"character":47}]}}},{"id":812,"name":"validationMessages","kind":32,"kindString":"Variable","flags":{"isExported":true,"isConst":true},"comment":{"shortText":"Dictionary of validation messages. [messageKey]: messageExpression"},"sources":[{"fileName":"aurelia-validation.d.ts","line":609,"character":35}],"type":{"type":"reference","name":"ValidationMessages","id":483}},{"id":813,"name":"configure","kind":64,"kindString":"Function","flags":{"isExported":true},"signatures":[{"id":814,"name":"configure","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Configures the plugin."},"parameters":[{"id":815,"name":"frameworkConfig","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reflection","declaration":{"id":816,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"children":[{"id":817,"name":"container","kind":32,"kindString":"Variable","flags":{},"sources":[{"fileName":"aurelia-validation.d.ts","line":1023,"character":17}],"type":{"type":"reference","name":"Container"}},{"id":818,"name":"globalResources","kind":32,"kindString":"Variable","flags":{"isOptional":true},"sources":[{"fileName":"aurelia-validation.d.ts","line":1024,"character":23}],"type":{"type":"union","types":[{"type":"intrinsic","name":"undefined"},{"type":"reflection","declaration":{"id":819,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":820,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":821,"name":"resources","kind":32768,"kindString":"Parameter","flags":{"isRest":true},"type":{"type":"array","elementType":{"type":"intrinsic","name":"any"}}}],"type":{"type":"intrinsic","name":"any"}}]}}]}}],"groups":[{"title":"Variables","kind":32,"children":[817,818]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":1022,"character":46}]}}},{"id":822,"name":"callback","kind":32768,"kindString":"Parameter","flags":{"isOptional":true},"type":{"type":"union","types":[{"type":"intrinsic","name":"undefined"},{"type":"reflection","declaration":{"id":823,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"signatures":[{"id":824,"name":"__call","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":825,"name":"config","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"reference","name":"AureliaValidationConfiguration","id":760}}],"type":{"type":"intrinsic","name":"void"}}]}}]}}],"type":{"type":"intrinsic","name":"void"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":1022,"character":29}]},{"id":795,"name":"getAccessorExpression","kind":64,"kindString":"Function","flags":{"isExported":true},"signatures":[{"id":796,"name":"getAccessorExpression","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":797,"name":"fn","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"string"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":95,"character":41}]},{"id":776,"name":"getPropertyInfo","kind":64,"kindString":"Function","flags":{"isExported":true},"signatures":[{"id":777,"name":"getPropertyInfo","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Retrieves the object and property name for the specified expression."},"parameters":[{"id":778,"name":"expression","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The expression"},"type":{"type":"reference","name":"Expression"}},{"id":779,"name":"source","kind":32768,"kindString":"Parameter","flags":{},"comment":{"text":"The scope\n"},"type":{"type":"reference","name":"Scope"}}],"type":{"type":"union","types":[{"type":"reflection","declaration":{"id":780,"name":"__type","kind":65536,"kindString":"Type literal","flags":{},"children":[{"id":781,"name":"object","kind":32,"kindString":"Variable","flags":{},"sources":[{"fileName":"aurelia-validation.d.ts","line":81,"character":14}],"type":{"type":"intrinsic","name":"object"}},{"id":782,"name":"propertyName","kind":32,"kindString":"Variable","flags":{},"sources":[{"fileName":"aurelia-validation.d.ts","line":82,"character":20}],"type":{"type":"intrinsic","name":"string"}}],"groups":[{"title":"Variables","kind":32,"children":[781,782]}],"sources":[{"fileName":"aurelia-validation.d.ts","line":80,"character":75}]}},{"type":"intrinsic","name":"null"}]}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":80,"character":35}]},{"id":772,"name":"getTargetDOMElement","kind":64,"kindString":"Function","flags":{"isExported":true},"signatures":[{"id":773,"name":"getTargetDOMElement","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Gets the DOM element associated with the data-binding. Most of the time it's\nthe binding.target but sometimes binding.target is an aurelia custom element,\nor custom attribute which is a javascript \"class\" instance, so we need to use\nthe controller's container to retrieve the actual DOM element."},"parameters":[{"id":774,"name":"binding","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}},{"id":775,"name":"view","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"reference","name":"Element"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":73,"character":39}]},{"id":786,"name":"isNumber","kind":64,"kindString":"Function","flags":{"isExported":true},"signatures":[{"id":787,"name":"isNumber","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":788,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"boolean"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":86,"character":28}]},{"id":783,"name":"isString","kind":64,"kindString":"Function","flags":{"isExported":true},"signatures":[{"id":784,"name":"isString","kind":4096,"kindString":"Call signature","flags":{},"parameters":[{"id":785,"name":"value","kind":32768,"kindString":"Parameter","flags":{},"type":{"type":"intrinsic","name":"any"}}],"type":{"type":"intrinsic","name":"boolean"}}],"sources":[{"fileName":"aurelia-validation.d.ts","line":85,"character":28}]}],"groups":[{"title":"Enumerations","kind":4,"children":[52]},{"title":"Classes","kind":128,"children":[760,350,701,526,623,420,27,338,501,177,160,68,194,210,226,242,2,81,258,275,406,486,305,719,38]},{"title":"Interfaces","kind":256,"children":[23,757,60,272,57,320,317,19,483,64]},{"title":"Type aliases","kind":4194304,"children":[804,803,802,806,805,801,809,810,808,811,807,789,798]},{"title":"Variables","kind":32,"children":[812]},{"title":"Functions","kind":64,"children":[813,795,776,772,786,783]}]}