From 80315abc3b3ad1e29086f10451937006b7ac510a Mon Sep 17 00:00:00 2001 From: Jeremy Danyow Date: Fri, 14 Oct 2016 06:01:56 -0400 Subject: [PATCH] feat(package): add tslint related to #357 --- .vscode/extensions.json | 5 + .vscode/settings.json | 3 +- .vscode/tasks.json | 10 -- package.json | 3 + src/aurelia-validation.ts | 20 +-- src/implementation/rule.ts | 12 +- src/implementation/rules.ts | 12 +- src/implementation/standard-validator.ts | 115 ++++++++-------- src/implementation/validation-messages.ts | 14 +- src/implementation/validation-parser.ts | 82 ++++++------ src/implementation/validation-rules.ts | 139 +++++++++++--------- src/property-info.ts | 8 +- src/validate-binding-behavior-base.ts | 45 ++++--- src/validate-binding-behavior.ts | 38 +++--- src/validate-trigger.ts | 18 +-- src/validation-controller-factory.ts | 14 +- src/validation-controller.ts | 84 ++++++------ src/validation-error.ts | 12 +- src/validation-errors-custom-attribute.ts | 34 ++--- src/validation-renderer-custom-attribute.ts | 10 +- src/validator.ts | 10 +- test/basic.ts | 27 ++-- test/main.ts | 29 ++-- test/null-object.ts | 10 +- test/resources/index.ts | 2 +- test/resources/nullable-object-form.ts | 18 ++- test/resources/number-value.ts | 36 ++--- test/resources/registration-form.ts | 24 ++-- test/resources/trigger-form.ts | 30 ++--- test/shared.ts | 8 +- test/validate-binding-behavior.ts | 8 +- test/validation-controller-factory.ts | 2 +- test/validation-parser.ts | 10 +- test/validator.ts | 20 +-- tslint.json | 14 ++ 35 files changed, 494 insertions(+), 432 deletions(-) create mode 100644 .vscode/extensions.json delete mode 100644 .vscode/tasks.json create mode 100644 tslint.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..b3e36c85 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "eg2.tslint" + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index c20d8966..6f262cac 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "typescript.tsdk": "node_modules/typescript/lib" + "typescript.tsdk": "node_modules/typescript/lib", + "editor.formatOnSave": false } diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 6022c231..00000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "0.1.0", - "command": "tsc", - "isShellCommand": true, - "args": ["-p", ".", "--outFile", "dist/amd/aurelia-validation.js"], - "showOutput": "silent", - "problemMatcher": "$tsc" -} diff --git a/package.json b/package.json index e7432b7f..cdc1d6c4 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,8 @@ "url": "https://github.com/aurelia/validation" }, "scripts": { + "lint": "cross-env ./node_modules/.bin/tslint --project tsconfig.json", + "pretest": "cross-env npm run lint", "test": "cross-env ./node_modules/.bin/tsc && cross-env ./node_modules/karma/bin/karma start --single-run", "test-watch": "concurrently \"./node_modules/.bin/tsc --watch\" \"./node_modules/karma/bin/karma start\"", "prebuild:compile": "rimraf 'dist/**'", @@ -80,6 +82,7 @@ "requirejs": "^2.2.0", "requirejs-text": "^2.0.12", "rimraf": "^2.5.4", + "tslint": "^3.15.1", "typedoc": "^0.5.0", "typescript": "^2.0.0" }, diff --git a/src/aurelia-validation.ts b/src/aurelia-validation.ts index d37b3ab4..f15292bb 100644 --- a/src/aurelia-validation.ts +++ b/src/aurelia-validation.ts @@ -19,29 +19,29 @@ export * from './implementation/validation-rules'; // Configuration -import {Container} from 'aurelia-dependency-injection'; -import {Validator} from './validator'; -import {StandardValidator} from './implementation/standard-validator'; -import {ValidationParser} from './implementation/validation-parser'; -import {ValidationRules} from './implementation/validation-rules'; +import { Container } from 'aurelia-dependency-injection'; +import { Validator } from './validator'; +import { StandardValidator } from './implementation/standard-validator'; +import { ValidationParser } from './implementation/validation-parser'; +import { ValidationRules } from './implementation/validation-rules'; /** * Aurelia Validation Configuration API */ export class AureliaValidationConfiguration { - private validatorType: { new(...args: any[]): Validator } = StandardValidator; + private validatorType: { new (...args: any[]): Validator } = StandardValidator; /** * Use a custom Validator implementation. */ - customValidator(type: { new(...args: any[]): Validator }) { - this.validatorType = type; + public customValidator(type: { new (...args: any[]): Validator }) { + this.validatorType = type; } /** * Applies the configuration. */ - apply(container: Container) { + public apply(container: Container) { const validator = container.get(this.validatorType); container.registerInstance(Validator, validator); } @@ -52,7 +52,7 @@ export class AureliaValidationConfiguration { */ export function configure( frameworkConfig: { container: Container, globalResources: (...resources: string[]) => any }, - callback?: (config: AureliaValidationConfiguration) => void + callback?: (config: AureliaValidationConfiguration) => void ) { // the fluent rule definition API needs the parser to translate messages // to interpolation expressions. diff --git a/src/implementation/rule.ts b/src/implementation/rule.ts index 391797b9..05651c1e 100644 --- a/src/implementation/rule.ts +++ b/src/implementation/rule.ts @@ -1,4 +1,4 @@ -import {Expression} from 'aurelia-binding'; +import { Expression } from 'aurelia-binding'; /** * Information related to a property that is the subject of validation. @@ -7,12 +7,12 @@ export interface RuleProperty { /** * The property name. null indicates the rule targets the object itself. */ - name: string|null; + name: string | null; /** * The displayName of the property (or object). */ - displayName: string|null; + displayName: string | null; } /** @@ -20,11 +20,11 @@ export interface RuleProperty { */ export interface Rule { property: RuleProperty; - condition: (value: TValue, object?: TObject) => boolean|Promise; + condition: (value: TValue, object?: TObject) => boolean | Promise; config: Object; - when: { (object: TObject): boolean }|null; + when: { (object: TObject): boolean } | null; messageKey: string; - message: Expression|null; + message: Expression | null; sequence: number; tag?: string; } diff --git a/src/implementation/rules.ts b/src/implementation/rules.ts index 44a6508d..c1908b75 100644 --- a/src/implementation/rules.ts +++ b/src/implementation/rules.ts @@ -1,4 +1,4 @@ -import {Rule} from './rule'; +import { Rule } from './rule'; /** * Sets, unsets and retrieves rules on an object or constructor function. @@ -7,12 +7,12 @@ export class Rules { /** * The name of the property that stores the rules. */ - static key = '__rules__'; + private static key = '__rules__'; /** * Applies the rules to a target. */ - static set(target: any, rules: Rule[][]): void { + public static set(target: any, rules: Rule[][]): void { if (target instanceof Function) { target = target.prototype; } @@ -25,17 +25,17 @@ export class Rules { /** * Removes rules from a target. */ - static unset(target: any): void { + public static unset(target: any): void { if (target instanceof Function) { target = target.prototype; - } + } target[Rules.key] = null; } /** * Retrieves the target's rules. */ - static get(target: any): Rule[][]|null { + public static get(target: any): Rule[][] | null { return target[Rules.key] || null; } } diff --git a/src/implementation/standard-validator.ts b/src/implementation/standard-validator.ts index 902b9020..18906848 100644 --- a/src/implementation/standard-validator.ts +++ b/src/implementation/standard-validator.ts @@ -1,17 +1,17 @@ -import {Expression, LookupFunctions} from 'aurelia-binding'; -import {ViewResources} from 'aurelia-templating'; -import {Validator} from '../validator'; -import {ValidationError} from '../validation-error'; -import {Rule} from './rule'; -import {Rules} from './rules'; -import {ValidationMessageProvider} from './validation-messages'; +import { Expression, LookupFunctions } from 'aurelia-binding'; +import { ViewResources } from 'aurelia-templating'; +import { Validator } from '../validator'; +import { ValidationError } from '../validation-error'; +import { Rule } from './rule'; +import { Rules } from './rules'; +import { ValidationMessageProvider } from './validation-messages'; /** * Validates. * Responsible for validating objects and properties. */ export class StandardValidator extends Validator { - static inject = [ValidationMessageProvider, ViewResources]; + public static inject = [ValidationMessageProvider, ViewResources]; private messageProvider: ValidationMessageProvider; private lookupFunctions: LookupFunctions; @@ -24,6 +24,42 @@ export class StandardValidator extends Validator { 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) + */ + public validateProperty(object: any, propertyName: string, rules?: any): Promise { + 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) + */ + public validateObject(object: any, rules?: any): Promise { + 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. + */ + public ruleExists(rules: Rule[][], rule: Rule): boolean { + let i = rules.length; + while (i--) { + if (rules[i].indexOf(rule) !== -1) { + return true; + } + } + return false; + } + private getMessage(rule: Rule, object: any, value: any): string { const expression: Expression = rule.message || this.messageProvider.getMessage(rule.messageKey); let { name: propertyName, displayName } = rule.property; @@ -36,25 +72,28 @@ export class StandardValidator extends Validator { $value: value, $object: object, $config: rule.config, - $getDisplayName: this.getDisplayName + $getDisplayName: this.getDisplayName }; return expression.evaluate( { bindingContext: object, overrideContext }, this.lookupFunctions); } - private validateRuleSequence(object: any, propertyName: string|null, ruleSequence: Rule[][], sequence: number): Promise { + private validateRuleSequence( + object: any, propertyName: string | null, + ruleSequence: Rule[][], sequence: number + ): Promise { // are we validating all properties or a single property? const validateAllProperties = propertyName === null || propertyName === undefined; - + const rules = ruleSequence[sequence]; const errors: ValidationError[] = []; - + // validate each rule. const promises: Promise[] = []; for (let i = 0; i < rules.length; i++) { const rule = rules[i]; - + // is the rule related to the property we're validating. if (!validateAllProperties && rule.property.name !== propertyName) { continue; @@ -75,10 +114,10 @@ export class StandardValidator extends Validator { if (!isValid) { const message = this.getMessage(rule, object, value); errors.push(new ValidationError(rule, message, object, rule.property.name)); - } + } })); } - + return Promise.all(promises) .then(() => { sequence++; @@ -86,10 +125,14 @@ export class StandardValidator extends Validator { return this.validateRuleSequence(object, propertyName, ruleSequence, sequence); } return errors; - }); + }); } - private validate(object: any, propertyName: string|null, rules: Rule[][]|null): Promise { + private validate( + object: any, + propertyName: string | null, + rules: Rule[][] | null + ): Promise { // rules specified? if (!rules) { // no. attempt to locate the rules. @@ -100,43 +143,7 @@ export class StandardValidator extends Validator { if (!rules) { return Promise.resolve([]); } - - return this.validateRuleSequence(object, propertyName, rules, 0); - } - - /** - * 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, rules?: any): Promise { - 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: any, rules?: any): Promise { - 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[][], rule: Rule): boolean { - let i = rules.length; - while (i--) { - if (rules[i].indexOf(rule) !== -1) { - return true; - } - } - return false; + return this.validateRuleSequence(object, propertyName, rules, 0); } } diff --git a/src/implementation/validation-messages.ts b/src/implementation/validation-messages.ts index 8ee339f2..71da4d40 100644 --- a/src/implementation/validation-messages.ts +++ b/src/implementation/validation-messages.ts @@ -1,5 +1,5 @@ -import {Expression} from 'aurelia-binding'; -import {ValidationParser} from './validation-parser'; +import { Expression } from 'aurelia-binding'; +import { ValidationParser } from './validation-parser'; export interface ValidationMessages { [key: string]: string; @@ -21,21 +21,21 @@ export const validationMessages: ValidationMessages = { 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'}.`, equals: `\${$displayName} must be \${$config.expectedValue}.`, -} +}; /** * Retrieves validation messages and property display names. */ export class ValidationMessageProvider { - static inject = [ValidationParser]; + public static inject = [ValidationParser]; - constructor(private parser: ValidationParser) {} + constructor(private parser: ValidationParser) { } /** * Returns a message binding expression that corresponds to the key. * @param key The message key. */ - getMessage(key: string): Expression { + public getMessage(key: string): Expression { let message: string; if (key in validationMessages) { message = validationMessages[key]; @@ -51,7 +51,7 @@ export class ValidationMessageProvider { * Override this with your own custom logic. * @param propertyName The property name. */ - getDisplayName(propertyName: string): string { + public getDisplayName(propertyName: string): string { // split on upper-case letters. const words = propertyName.split(/(?=[A-Z])/).join(' '); // capitalize first letter. diff --git a/src/implementation/validation-parser.ts b/src/implementation/validation-parser.ts index 2080ca90..a24b04fe 100644 --- a/src/implementation/validation-parser.ts +++ b/src/implementation/validation-parser.ts @@ -10,9 +10,9 @@ import { CallMember, Unparser } from 'aurelia-binding'; -import {BindingLanguage} from 'aurelia-templating'; -import {RuleProperty} from './rule'; -import {isString} from './util'; +import { BindingLanguage } from 'aurelia-templating'; +import { RuleProperty } from './rule'; +import { isString } from './util'; import * as LogManager from 'aurelia-logging'; @@ -21,34 +21,21 @@ export interface PropertyAccessor { } export class ValidationParser { - static inject = [Parser, BindingLanguage]; + public static inject = [Parser, BindingLanguage]; private emptyStringExpression = new LiteralString(''); private nullExpression = new LiteralPrimitive(null); private undefinedExpression = new LiteralPrimitive(undefined); private cache: { [message: string]: Expression } = {}; - constructor(private parser: Parser, private bindinqLanguage: BindingLanguage) {} + constructor(private parser: Parser, private bindinqLanguage: BindingLanguage) { } - private coalesce(part: Expression): Expression { - // 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', []) - ); - } - - parseMessage(message: string): Expression { + public parseMessage(message: string): Expression { if (this.cache[message] !== undefined) { return this.cache[message]; } - const parts: (Expression|string)[]|null = (this.bindinqLanguage).parseInterpolation(null, message); + const parts: (Expression | string)[] | null = (this.bindinqLanguage).parseInterpolation(null, message); if (parts === null) { return new LiteralString(message); } @@ -64,31 +51,21 @@ export class ValidationParser { ) ); } - + MessageExpressionValidator.validate(expression, message); - + this.cache[message] = expression; - - return expression; - } - private getAccessorExpression(fn: string): Expression { - const classic = /^function\s*\([$_\w\d]+\)\s*\{\s*(?:"use strict";)?\s*return\s+[$_\w\d]+\.([$_\w\d]+)\s*;?\s*\}$/; - 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 this.parser.parse(match[1]); + return expression; } - parseProperty(property: string|PropertyAccessor): RuleProperty { + public parseProperty(property: string | PropertyAccessor): RuleProperty { if (isString(property)) { - return { name: property, displayName: null }; - } - const accessor = this.getAccessorExpression(property.toString()); + return { name: property, displayName: null }; + } + const accessor = this.getAccessorExpression(property.toString()); if (accessor instanceof AccessScope - || accessor instanceof AccessMember && accessor.object instanceof AccessScope) { + || accessor instanceof AccessMember && accessor.object instanceof AccessScope) { return { name: accessor.name, displayName: null @@ -96,10 +73,33 @@ export class ValidationParser { } throw new Error(`Invalid subject: "${accessor}"`); } + + private coalesce(part: Expression): Expression { + // 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', []) + ); + } + + private getAccessorExpression(fn: string): Expression { + const classic = /^function\s*\([$_\w\d]+\)\s*\{\s*(?:"use strict";)?\s*return\s+[$_\w\d]+\.([$_\w\d]+)\s*;?\s*\}$/; + 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 this.parser.parse(match[1]); + } } export class MessageExpressionValidator extends Unparser { - static validate(expression: Expression, originalMessage: string) { + public static validate(expression: Expression, originalMessage: string) { const visitor = new MessageExpressionValidator(originalMessage); expression.accept(visitor); } @@ -108,13 +108,15 @@ export class MessageExpressionValidator extends Unparser { super([]); } - visitAccessScope(access: AccessScope) { + public visitAccessScope(access: AccessScope) { 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:max-line-length */ .warn(`Did you mean to use "$${access.name}" instead of "${access.name}" in this validation message template: "${this.originalMessage}"?`); + /* tslint:enable:max-line-length */ } } } diff --git a/src/implementation/validation-rules.ts b/src/implementation/validation-rules.ts index d0a99784..cde9d987 100644 --- a/src/implementation/validation-rules.ts +++ b/src/implementation/validation-rules.ts @@ -1,8 +1,8 @@ -import {Rule, RuleProperty} from './rule'; -import {ValidationParser, PropertyAccessor} from './validation-parser'; -import {isString} from './util'; -import {Rules} from './rules'; -import {validationMessages} from './validation-messages'; +import { Rule, RuleProperty } from './rule'; +import { ValidationParser, PropertyAccessor } from './validation-parser'; +import { isString } from './util'; +import { Rules } from './rules'; +import { validationMessages } from './validation-messages'; /** * Part of the fluent rule API. Enables customizing property rules. @@ -12,7 +12,7 @@ export class FluentRuleCustomizer { constructor( property: RuleProperty, - condition: (value: TValue, object?: TObject) => boolean|Promise, + condition: (value: TValue, object?: TObject) => boolean | Promise, config: Object = {}, private fluentEnsure: FluentEnsure, private fluentRules: FluentRules, @@ -35,7 +35,7 @@ export class FluentRuleCustomizer { * been validated successfully. Use to postpone validation of costly * rules until less expensive rules pass validation. */ - then() { + public then() { this.fluentEnsure._sequence++; return this; } @@ -43,7 +43,7 @@ export class FluentRuleCustomizer { /** * Specifies the key to use when looking up the rule's validation message. */ - withMessageKey(key: string) { + public withMessageKey(key: string) { this.rule.messageKey = key; this.rule.message = null; return this; @@ -52,7 +52,7 @@ export class FluentRuleCustomizer { /** * Specifies rule's validation message. */ - withMessage(message: string) { + public withMessage(message: string) { this.rule.messageKey = 'custom'; this.rule.message = this.parser.parseMessage(message); return this; @@ -63,7 +63,7 @@ export class FluentRuleCustomizer { * @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) { + public when(condition: (object: TObject) => boolean) { this.rule.when = condition; return this; } @@ -72,7 +72,7 @@ export class FluentRuleCustomizer { * Tags the rule instance, enabling the rule to be found easily * using ValidationRules.taggedRules(rules, tag) */ - tag(tag: string) { + public tag(tag: string) { this.rule.tag = tag; return this; } @@ -83,29 +83,29 @@ export class FluentRuleCustomizer { * 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; }) { + public ensure(subject: string | { (model: TObject): TValue2; }) { return this.fluentEnsure.ensure(subject); } /** * Targets an object with validation rules. */ - ensureObject() { + public ensureObject() { return this.fluentEnsure.ensureObject(); } /** * Rules that have been defined using the fluent API. */ - get rules() { + public 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: any) { + public on(target: any) { return this.fluentEnsure.on(target); } @@ -117,7 +117,7 @@ export class FluentRuleCustomizer { * 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) { + public satisfies(condition: (value: TValue, object?: TObject) => boolean | Promise, config?: Object) { return this.fluentRules.satisfies(condition, config); } @@ -126,7 +126,7 @@ export class FluentRuleCustomizer { * @param name The name of the custom or standard rule. * @param args The rule's arguments. */ - satisfiesRule(name: string, ...args: any[]) { + public satisfiesRule(name: string, ...args: any[]) { return this.fluentRules.satisfiesRule(name, ...args); } @@ -134,7 +134,7 @@ export class FluentRuleCustomizer { * Applies the "required" rule to the property. * The value cannot be null, undefined or whitespace. */ - required() { + public required() { return this.fluentRules.required(); } @@ -143,7 +143,7 @@ export class FluentRuleCustomizer { * Value must match the specified regular expression. * null, undefined and empty-string values are considered valid. */ - matches(regex: RegExp) { + public matches(regex: RegExp) { return this.fluentRules.matches(regex); } @@ -151,7 +151,7 @@ export class FluentRuleCustomizer { * Applies the "email" rule to the property. * null, undefined and empty-string values are considered valid. */ - email() { + public email() { return this.fluentRules.email(); } @@ -159,7 +159,7 @@ export class FluentRuleCustomizer { * Applies the "minLength" STRING validation rule to the property. * null, undefined and empty-string values are considered valid. */ - minLength(length: number) { + public minLength(length: number) { return this.fluentRules.minLength(length); } @@ -167,7 +167,7 @@ export class FluentRuleCustomizer { * Applies the "maxLength" STRING validation rule to the property. * null, undefined and empty-string values are considered valid. */ - maxLength(length: number) { + public maxLength(length: number) { return this.fluentRules.maxLength(length); } @@ -175,7 +175,7 @@ export class FluentRuleCustomizer { * Applies the "minItems" ARRAY validation rule to the property. * null and undefined values are considered valid. */ - minItems(count: number) { + public minItems(count: number) { return this.fluentRules.minItems(count); } @@ -183,7 +183,7 @@ export class FluentRuleCustomizer { * Applies the "maxItems" ARRAY validation rule to the property. * null and undefined values are considered valid. */ - maxItems(count: number) { + public maxItems(count: number) { return this.fluentRules.maxItems(count); } @@ -191,7 +191,7 @@ export class FluentRuleCustomizer { * Applies the "equals" validation rule to the property. * null, undefined and empty-string values are considered valid. */ - equals(expectedValue: TValue) { + public equals(expectedValue: TValue) { return this.fluentRules.equals(expectedValue); } } @@ -200,9 +200,9 @@ export class FluentRuleCustomizer { * Part of the fluent rule API. Enables applying rules to properties and objects. */ export class FluentRules { - static customRules: { + public static customRules: { [name: string]: { - condition: (value: any, object?: any, ...fluentArgs: any[]) => boolean|Promise; + condition: (value: any, object?: any, ...fluentArgs: any[]) => boolean | Promise; argsToConfig?: (...args: any[]) => any; } } = {}; @@ -211,12 +211,12 @@ export class FluentRules { private fluentEnsure: FluentEnsure, private parser: ValidationParser, private property: RuleProperty - ) {} + ) { } /** * Sets the display name of the ensured property. */ - displayName(name: string) { + public displayName(name: string) { this.property.displayName = name; return this; } @@ -227,8 +227,9 @@ export class FluentRules { * 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) { - return new FluentRuleCustomizer(this.property, condition, config, this.fluentEnsure, this, this.parser); + public satisfies(condition: (value: TValue, object?: TObject) => boolean | Promise, config?: Object) { + return new FluentRuleCustomizer( + this.property, condition, config, this.fluentEnsure, this, this.parser); } /** @@ -236,7 +237,7 @@ export class FluentRules { * @param name The name of the custom or standard rule. * @param args The rule's arguments. */ - satisfiesRule(name: string, ...args: any[]) { + public satisfiesRule(name: string, ...args: any[]) { let rule = FluentRules.customRules[name]; if (!rule) { // standard rule? @@ -255,9 +256,9 @@ export class FluentRules { * Applies the "required" rule to the property. * The value cannot be null, undefined or whitespace. */ - required() { + public required() { return this.satisfies( - value => + value => value !== null && value !== undefined && !(isString(value) && !/\S/.test(value)) @@ -269,8 +270,9 @@ export class FluentRules { * Value must match the specified regular expression. * null, undefined and empty-string values are considered valid. */ - matches(regex: RegExp) { - return this.satisfies(value => value === null || value === undefined || (value).length === 0 || regex.test(value)) + public matches(regex: RegExp) { + return this.satisfies( + value => value === null || value === undefined || (value).length === 0 || regex.test(value)) .withMessageKey('matches'); } @@ -278,9 +280,11 @@ export class FluentRules { * Applies the "email" rule to the property. * null, undefined and empty-string values are considered valid. */ - email() { + public 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'); } @@ -288,8 +292,10 @@ export class FluentRules { * Applies the "minLength" STRING validation rule to the property. * null, undefined and empty-string values are considered valid. */ - minLength(length: number) { - return this.satisfies((value: any) => value === null || value === undefined || value.length === 0 || value.length >= length, { length }) + public minLength(length: number) { + return this.satisfies( + (value: any) => value === null || value === undefined || value.length === 0 || value.length >= length, + { length }) .withMessageKey('minLength'); } @@ -297,8 +303,10 @@ export class FluentRules { * Applies the "maxLength" STRING validation rule to the property. * null, undefined and empty-string values are considered valid. */ - maxLength(length: number) { - return this.satisfies((value: any) => value === null || value === undefined || value.length === 0 || value.length <= length, { length }) + public maxLength(length: number) { + return this.satisfies( + (value: any) => value === null || value === undefined || value.length === 0 || value.length <= length, + { length }) .withMessageKey('maxLength'); } @@ -306,7 +314,7 @@ export class FluentRules { * Applies the "minItems" ARRAY validation rule to the property. * null and undefined values are considered valid. */ - minItems(count: number) { + public minItems(count: number) { return this.satisfies((value: any) => value === null || value === undefined || value.length >= count, { count }) .withMessageKey('minItems'); } @@ -315,7 +323,7 @@ export class FluentRules { * Applies the "maxItems" ARRAY validation rule to the property. * null and undefined values are considered valid. */ - maxItems(count: number) { + public maxItems(count: number) { return this.satisfies((value: any) => value === null || value === undefined || value.length <= count, { count }) .withMessageKey('maxItems'); } @@ -324,8 +332,10 @@ export class FluentRules { * Applies the "equals" validation rule to the property. * null and undefined values are considered valid. */ - equals(expectedValue: TValue) { - return this.satisfies(value => value === null || value === undefined || value === '' || value === expectedValue, { expectedValue }) + public equals(expectedValue: TValue) { + return this.satisfies( + value => value === null || value === undefined || value === '' || value === expectedValue, + { expectedValue }) .withMessageKey('equals'); } } @@ -339,15 +349,18 @@ export class FluentEnsure { */ public rules: Rule[][] = []; + /* tslint:disable */ public _sequence = 0; + /* tslint:enable */ - constructor(private parser: ValidationParser) {} + constructor(private parser: ValidationParser) { } /** * Target a property with validation rules. - * @param property The property to target. Can be the property name or a property accessor function. + * @param property The property to target. Can be the property name or a property accessor + * function. */ - ensure(property: string|PropertyAccessor) { + public ensure(property: string | PropertyAccessor) { this.assertInitialized(); return new FluentRules(this, this.parser, this.parser.parseProperty(property)); } @@ -355,16 +368,17 @@ export class FluentEnsure { /** * Targets an object with validation rules. */ - ensureObject() { + public ensureObject() { this.assertInitialized(); - return new FluentRules(this, this.parser, { name: null, displayName: null }) + return new FluentRules( + this, this.parser, { name: null, displayName: null }); } /** * Applies the rules to a class or object, making them discoverable by the StandardValidator. * @param target A class or object. */ - on(target: any) { + public on(target: any) { Rules.set(target, this.rules); return this; } @@ -372,7 +386,7 @@ export class FluentEnsure { /** * Adds a rule definition to the sequenced ruleset. */ - _addRule(rule: Rule) { + public _addRule(rule: Rule) { while (this.rules.length < rule.sequence + 1) { this.rules.push([]); } @@ -393,7 +407,7 @@ export class FluentEnsure { export class ValidationRules { private static parser: ValidationParser; - static initialize(parser: ValidationParser) { + public static initialize(parser: ValidationParser) { ValidationRules.parser = parser; } @@ -401,14 +415,14 @@ export class ValidationRules { * 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|PropertyAccessor) { + public static ensure(property: string | PropertyAccessor) { return new FluentEnsure(ValidationRules.parser).ensure(property); } /** * Targets an object with validation rules. */ - static ensureObject() { + public static ensureObject() { return new FluentEnsure(ValidationRules.parser).ensureObject(); } @@ -417,24 +431,25 @@ export class ValidationRules { * @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. + * @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( + public static customRule( name: string, - condition: (value: any, object?: any, ...args: any[]) => boolean|Promise, + condition: (value: any, object?: any, ...args: any[]) => boolean | Promise, message: string, argsToConfig?: (...args: any[]) => any ) { 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: Rule[][], tag: string): Rule[][] { + public static taggedRules(rules: Rule[][], tag: string): Rule[][] { return rules.map(x => x.filter(r => r.tag === tag)); } @@ -442,7 +457,7 @@ export class ValidationRules { * Removes the rules from a class or object. * @param target A class or object. */ - static off(target: any): void { + public static off(target: any): void { Rules.unset(target); } } diff --git a/src/property-info.ts b/src/property-info.ts index 815e1537..15fb07bc 100644 --- a/src/property-info.ts +++ b/src/property-info.ts @@ -7,12 +7,14 @@ import { ValueConverter } from 'aurelia-binding'; -function getObject(expression: Expression, objectExpression: Expression, source: any): null|undefined|Object { +function getObject(expression: Expression, objectExpression: Expression, source: any): null | undefined | Object { let value = objectExpression.evaluate(source, null); if (value === null || value === undefined || value instanceof Object) { return value; } + /* tslint:disable */ throw new Error(`The '${objectExpression}' part of '${expression}' evaluates to ${value} instead of an object, null or undefined.`); + /* tslint:enable */ } /** @@ -20,13 +22,13 @@ function getObject(expression: Expression, objectExpression: Expression, source: * @param expression The expression * @param source The scope */ -export function getPropertyInfo(expression: Expression, source: any): { object: Object; propertyName: string; }|null { +export function getPropertyInfo(expression: Expression, source: any): { object: Object; propertyName: string; } | null { const originalExpression = expression; while (expression instanceof BindingBehavior || expression instanceof ValueConverter) { expression = expression.expression; } - let object: null|undefined|Object; + let object: null | undefined | Object; let propertyName: string; if (expression instanceof AccessScope) { object = source.bindingContext; diff --git a/src/validate-binding-behavior-base.ts b/src/validate-binding-behavior-base.ts index fa97df02..5cd0fe0d 100644 --- a/src/validate-binding-behavior-base.ts +++ b/src/validate-binding-behavior-base.ts @@ -1,24 +1,24 @@ -import {Optional} from 'aurelia-dependency-injection'; -import {DOM} from 'aurelia-pal'; -import {TaskQueue} from 'aurelia-task-queue'; -import {ValidationController} from './validation-controller'; -import {validateTrigger} from './validate-trigger'; +import { Optional } from 'aurelia-dependency-injection'; +import { DOM } from 'aurelia-pal'; +import { TaskQueue } from 'aurelia-task-queue'; +import { ValidationController } from './validation-controller'; +import { validateTrigger } from './validate-trigger'; /** * Binding behavior. Indicates the bound property should be validated. */ export abstract class ValidateBindingBehaviorBase { - constructor(private taskQueue: TaskQueue) {} + constructor(private taskQueue: TaskQueue) { } protected abstract getValidateTrigger(controller: ValidationController): number; /** - * 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. - */ - getTarget(binding: any, view: any) { + * 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. + */ + public getTarget(binding: any, view: any) { const target = binding.target; // DOM element if (target instanceof Element) { @@ -38,7 +38,7 @@ export abstract class ValidateBindingBehaviorBase { throw new Error(`Unable to locate target element for "${binding.sourceExpression}".`); } - bind(binding: any, source: any, rulesOrController?: ValidationController|any, rules?: any) { + public bind(binding: any, source: any, rulesOrController?: ValidationController | any, rules?: any) { // identify the target element. const target = this.getTarget(binding, source); @@ -49,7 +49,7 @@ export abstract class ValidateBindingBehaviorBase { } else { controller = source.container.get(Optional.of(ValidationController)); rules = rulesOrController; - } + } if (controller === null) { throw new Error(`A ValidationController has not been registered.`); } @@ -57,16 +57,21 @@ export abstract class ValidateBindingBehaviorBase { controller.registerBinding(binding, target, rules); binding.validationController = controller; const trigger = this.getValidateTrigger(controller); - + /* tslint:disable:no-bitwise */ if (trigger & validateTrigger.change) { + /* tslint:enable:no-bitwise */ binding.standardUpdateSource = binding.updateSource; - binding.updateSource = function(value: any) { + /* tslint:disable:only-arrow-functions */ + binding.updateSource = function (value: any) { + /* tslint:enable:only-arrow-functions */ this.standardUpdateSource(value); this.validationController.validateBinding(this); }; } - + + /* tslint:disable:no-bitwise */ if (trigger & validateTrigger.blur) { + /* tslint:enable:no-bitwise */ binding.validateBlurHandler = () => { this.taskQueue.queueMicroTask(() => controller.validateBinding(binding)); }; @@ -76,14 +81,16 @@ export abstract class ValidateBindingBehaviorBase { if (trigger !== validateTrigger.manual) { binding.standardUpdateTarget = binding.updateTarget; - binding.updateTarget = function(value: any) { + /* tslint:disable:only-arrow-functions */ + binding.updateTarget = function (value: any) { + /* tslint:enable:only-arrow-functions */ this.standardUpdateTarget(value); this.validationController.resetBinding(this); }; } } - unbind(binding: any) { + public unbind(binding: any) { // reset the binding to it's original state. if (binding.standardUpdateSource) { binding.updateSource = binding.standardUpdateSource; diff --git a/src/validate-binding-behavior.ts b/src/validate-binding-behavior.ts index a4edddee..6ac5ecf4 100644 --- a/src/validate-binding-behavior.ts +++ b/src/validate-binding-behavior.ts @@ -1,17 +1,17 @@ -import {TaskQueue} from 'aurelia-task-queue'; -import {ValidationController} from './validation-controller'; -import {validateTrigger} from './validate-trigger'; -import {ValidateBindingBehaviorBase} from './validate-binding-behavior-base'; +import { TaskQueue } from 'aurelia-task-queue'; +import { ValidationController } from './validation-controller'; +import { validateTrigger } from './validate-trigger'; +import { ValidateBindingBehaviorBase } from './validate-binding-behavior-base'; /** * Binding behavior. Indicates the bound property should be validated * when the validate trigger specified by the associated controller's * validateTrigger property occurs. */ -export class ValidateBindingBehavior extends ValidateBindingBehaviorBase { - static inject = [TaskQueue]; +export class ValidateBindingBehavior extends ValidateBindingBehaviorBase { + public static inject = [TaskQueue]; - getValidateTrigger(controller: ValidationController) { + public getValidateTrigger(controller: ValidationController) { return controller.validateTrigger; } } @@ -21,10 +21,10 @@ export class ValidateBindingBehavior extends ValidateBindingBehaviorBase { * manually, by calling controller.validate(). No automatic validation * triggered by data-entry or blur will occur. */ -export class ValidateManuallyBindingBehavior extends ValidateBindingBehaviorBase { - static inject = [TaskQueue]; +export class ValidateManuallyBindingBehavior extends ValidateBindingBehaviorBase { + public static inject = [TaskQueue]; - getValidateTrigger() { + public getValidateTrigger() { return validateTrigger.manual; } } @@ -33,10 +33,10 @@ export class ValidateManuallyBindingBehavior extends ValidateBindingBehaviorBase * Binding behavior. Indicates the bound property should be validated * when the associated element blurs. */ -export class ValidateOnBlurBindingBehavior extends ValidateBindingBehaviorBase { - static inject = [TaskQueue]; +export class ValidateOnBlurBindingBehavior extends ValidateBindingBehaviorBase { + public static inject = [TaskQueue]; - getValidateTrigger() { + public getValidateTrigger() { return validateTrigger.blur; } } @@ -46,10 +46,10 @@ export class ValidateOnBlurBindingBehavior extends ValidateBindingBehaviorBase { * when the associated element is changed by the user, causing a change * to the model. */ -export class ValidateOnChangeBindingBehavior extends ValidateBindingBehaviorBase { - static inject = [TaskQueue]; +export class ValidateOnChangeBindingBehavior extends ValidateBindingBehaviorBase { + public static inject = [TaskQueue]; - getValidateTrigger() { + public getValidateTrigger() { return validateTrigger.change; } } @@ -59,10 +59,10 @@ export class ValidateOnChangeBindingBehavior extends ValidateBindingBehaviorBase * when the associated element blurs or is changed by the user, causing * a change to the model. */ -export class ValidateOnChangeOrBlurBindingBehavior extends ValidateBindingBehaviorBase { - static inject = [TaskQueue]; +export class ValidateOnChangeOrBlurBindingBehavior extends ValidateBindingBehaviorBase { + public static inject = [TaskQueue]; - getValidateTrigger() { + public getValidateTrigger() { return validateTrigger.changeOrBlur; } } diff --git a/src/validate-trigger.ts b/src/validate-trigger.ts index 6eeac02d..1fb0e25a 100644 --- a/src/validate-trigger.ts +++ b/src/validate-trigger.ts @@ -1,21 +1,21 @@ /** -* Validation triggers. -*/ + * Validation triggers. + */ export const validateTrigger = { /** - * Manual validation. Use the controller's `validate()` and `reset()` methods - * to validate all bindings. - */ + * 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. - */ + * 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. - */ + * Validate the binding when it updates the model due to a change in the view. + */ change: 2, /** diff --git a/src/validation-controller-factory.ts b/src/validation-controller-factory.ts index 5774eab6..eb554bf9 100644 --- a/src/validation-controller-factory.ts +++ b/src/validation-controller-factory.ts @@ -1,21 +1,21 @@ -import {Container} from 'aurelia-dependency-injection'; -import {ValidationController} from './validation-controller'; -import {Validator} from './validator'; +import { Container } from 'aurelia-dependency-injection'; +import { ValidationController } from './validation-controller'; +import { Validator } from './validator'; /** * Creates ValidationController instances. */ export class ValidationControllerFactory { - static get(container: Container) { + public static get(container: Container) { return new ValidationControllerFactory(container); } - constructor(private container: Container) {} + constructor(private container: Container) { } /** * Creates a new controller instance. */ - create(validator?: Validator) { + public create(validator?: Validator) { if (!validator) { validator = this.container.get(Validator); } @@ -26,7 +26,7 @@ export class ValidationControllerFactory { * 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) { + public createForCurrentScope(validator?: Validator) { const controller = this.create(validator); this.container.registerInstance(ValidationController, controller); return controller; diff --git a/src/validation-controller.ts b/src/validation-controller.ts index a64f6b59..faf1eb5a 100644 --- a/src/validation-controller.ts +++ b/src/validation-controller.ts @@ -1,9 +1,9 @@ -import {Binding, Expression} from 'aurelia-binding'; -import {Validator} from './validator'; -import {validateTrigger} from './validate-trigger'; -import {getPropertyInfo} from './property-info'; -import {ValidationRenderer, RenderInstruction} from './validation-renderer'; -import {ValidationError} from './validation-error'; +import { Binding, Expression } from 'aurelia-binding'; +import { Validator } from './validator'; +import { validateTrigger } from './validate-trigger'; +import { getPropertyInfo } from './property-info'; +import { ValidationRenderer, RenderInstruction } from './validation-renderer'; +import { ValidationError } from './validation-error'; /** * Information related to an "& validate" decorated binding. @@ -22,7 +22,7 @@ interface BindingInfo { /** * The object and property associated with the binding. */ - propertyInfo: { object: any; propertyName: string; }|null; + propertyInfo: { object: any; propertyName: string; } | null; } export interface ValidateInstruction { @@ -48,7 +48,7 @@ export interface ValidateInstruction { * Exposes the current list of validation errors for binding purposes. */ export class ValidationController { - static inject = [Validator]; + public static inject = [Validator]; // Registered bindings (via the validate binding behavior) private bindings = new Map(); @@ -80,14 +80,14 @@ export class ValidationController { // Promise that resolves when validation has completed. private finishValidating = Promise.resolve(); - constructor(private validator: Validator) {} + constructor(private validator: Validator) { } /** * 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 { + public addObject(object: any, rules?: any): void { this.objects.set(object, rules); } @@ -95,7 +95,7 @@ export class ValidationController { * Removes an object from the set of objects that should be validated when validate is called. * @param object The object. */ - removeObject(object: any): void { + public removeObject(object: any): void { this.objects.delete(object); this.processErrorDelta( 'reset', @@ -106,7 +106,7 @@ export class ValidationController { /** * Adds and renders a ValidationError. */ - addError(message: string, object: any, propertyName?: string): ValidationError { + public addError(message: string, object: any, propertyName?: string): ValidationError { const error = new ValidationError({}, message, object, propertyName); this.processErrorDelta('validate', [], [error]); return error; @@ -115,7 +115,7 @@ export class ValidationController { /** * Removes and unrenders a ValidationError. */ - removeError(error: ValidationError) { + public removeError(error: ValidationError) { if (this.errors.indexOf(error) !== -1) { this.processErrorDelta('reset', [error], []); } @@ -125,7 +125,7 @@ export class ValidationController { * Adds a renderer. * @param renderer The renderer. */ - addRenderer(renderer: ValidationRenderer) { + public addRenderer(renderer: ValidationRenderer) { this.renderers.push(renderer); renderer.render({ kind: 'validate', @@ -138,7 +138,7 @@ export class ValidationController { * Removes a renderer. * @param renderer The renderer. */ - removeRenderer(renderer: ValidationRenderer) { + public removeRenderer(renderer: ValidationRenderer) { this.renderers.splice(this.renderers.indexOf(renderer), 1); renderer.render({ kind: 'reset', @@ -153,7 +153,7 @@ export class ValidationController { * @param target The DOM element. * @param rules (optional) rules associated with the binding. Validator implementation specific. */ - registerBinding(binding: Binding, target: Element, rules?: any) { + public registerBinding(binding: Binding, target: Element, rules?: any) { this.bindings.set(binding, { target, rules, propertyInfo: null }); } @@ -161,7 +161,7 @@ export class ValidationController { * Unregisters a binding with the controller. * @param binding The binding instance. */ - unregisterBinding(binding: Binding) { + public unregisterBinding(binding: Binding) { this.resetBinding(binding); this.bindings.delete(binding); } @@ -173,13 +173,13 @@ export class ValidationController { private getInstructionPredicate(instruction?: ValidateInstruction): (error: ValidationError) => boolean { if (instruction) { const { object, propertyName, rules } = instruction; - let predicate: (error: ValidationError) => boolean; + let predicate: (error: ValidationError) => boolean; if (instruction.propertyName) { predicate = x => x.object === object && x.propertyName === propertyName; } else { predicate = x => x.object === object; } - if (rules) { + if (rules) { return x => predicate(x) && this.validator.ruleExists(rules, x.rule); } return predicate; @@ -190,15 +190,16 @@ export class ValidationController { /** * Validates and renders errors. - * @param instruction Optional. Instructions on what to validate. If undefined, all objects and bindings will be validated. + * @param instruction Optional. Instructions on what to validate. If undefined, all + * objects and bindings will be validated. */ - validate(instruction?: ValidateInstruction): Promise { + public validate(instruction?: ValidateInstruction): Promise { // Get a function that will process the validation instruction. let execute: () => Promise; if (instruction) { let { object, propertyName, rules } = instruction; // if rules were not specified, check the object map. - rules = rules || this.objects.get(object); + rules = rules || this.objects.get(object); // property specified? if (instruction.propertyName === undefined) { // validate the specified object. @@ -219,7 +220,7 @@ export class ValidationController { if (!propertyInfo || this.objects.has(propertyInfo.object)) { continue; } - promises.push(this.validator.validateProperty(propertyInfo.object, propertyInfo.propertyName, rules)); + promises.push(this.validator.validateProperty(propertyInfo.object, propertyInfo.propertyName, rules)); } return Promise.all(promises).then(errorSets => errorSets.reduce((a, b) => a.concat(b), [])); }; @@ -230,13 +231,13 @@ export class ValidationController { let result = this.finishValidating .then(execute) .then(newErrors => { - const predicate = this.getInstructionPredicate(instruction); + const predicate = this.getInstructionPredicate(instruction); const oldErrors = this.errors.filter(predicate); this.processErrorDelta('validate', oldErrors, newErrors); if (result === this.finishValidating) { this.validating = false; } - return newErrors; + return newErrors; }) .catch(error => { // recover, to enable subsequent calls to validate() @@ -245,7 +246,7 @@ export class ValidationController { return Promise.reject(error); }); - + this.finishValidating = result; return result; @@ -255,10 +256,10 @@ export class ValidationController { * Resets any rendered errors (unrenders). * @param instruction Optional. Instructions on what to reset. If unspecified all rendered errors will be unrendered. */ - reset(instruction?: ValidateInstruction) { - const predicate = this.getInstructionPredicate(instruction); + public reset(instruction?: ValidateInstruction) { + const predicate = this.getInstructionPredicate(instruction); const oldErrors = this.errors.filter(predicate); - this.processErrorDelta('reset', oldErrors, []); + this.processErrorDelta('reset', oldErrors, []); } /** @@ -275,7 +276,7 @@ export class ValidationController { return elements; } - private processErrorDelta(kind: 'validate'|'reset', oldErrors: ValidationError[], newErrors: ValidationError[]) { + private processErrorDelta(kind: 'validate' | 'reset', oldErrors: ValidationError[], newErrors: ValidationError[]) { // prepare the instruction. const instruction: RenderInstruction = { kind, @@ -290,7 +291,7 @@ export class ValidationController { for (let oldError of oldErrors) { // get the elements associated with the old error. const elements = this.elements.get(oldError); - + // remove the old error from the element map. this.elements.delete(oldError); @@ -298,18 +299,19 @@ export class ValidationController { instruction.unrender.push({ error: oldError, elements }); // determine if there's a corresponding new error for the old error we are unrendering. - const newErrorIndex = newErrors.findIndex(x => x.rule === oldError.rule && x.object === oldError.object && x.propertyName === oldError.propertyName); + const newErrorIndex = newErrors.findIndex( + x => x.rule === oldError.rule && x.object === oldError.object && x.propertyName === oldError.propertyName); if (newErrorIndex === -1) { // no corresponding new error... simple remove. this.errors.splice(this.errors.indexOf(oldError), 1); } else { // there is a corresponding new error... const newError = newErrors.splice(newErrorIndex, 1)[0]; - + // get the elements that are associated with the new error. const elements = this.getAssociatedElements(newError); this.elements.set(newError, elements); - + // create a render instruction for the new error. instruction.render.push({ error: newError, elements }); @@ -334,9 +336,9 @@ export class ValidationController { } /** - * Validates the property associated with a binding. - */ - validateBinding(binding: Binding) { + * Validates the property associated with a binding. + */ + public validateBinding(binding: Binding) { if (!binding.isBound) { return; } @@ -349,15 +351,15 @@ export class ValidationController { } if (!propertyInfo) { return; - } + } const { object, propertyName } = propertyInfo; this.validate({ object, propertyName, rules }); } /** - * Resets the errors for a property associated with a binding. - */ - resetBinding(binding: Binding) { + * Resets the errors for a property associated with a binding. + */ + public resetBinding(binding: Binding) { const registeredBinding = this.bindings.get(binding); let propertyInfo = getPropertyInfo(binding.sourceExpression, (binding).source); if (!propertyInfo && registeredBinding) { diff --git a/src/validation-error.ts b/src/validation-error.ts index df144896..82132c5a 100644 --- a/src/validation-error.ts +++ b/src/validation-error.ts @@ -3,7 +3,7 @@ */ export class ValidationError { private static nextId = 0; - + /** * A number that uniquely identifies the error instance. */ @@ -17,14 +17,14 @@ export class ValidationError { */ constructor( public rule: any, - public message: string, - public object: any, - public propertyName: string|null = null + public message: string, + public object: any, + public propertyName: string | null = null ) { - this.id = ValidationError.nextId++; + this.id = ValidationError.nextId++; } - toString() { + public toString() { return this.message; } } diff --git a/src/validation-errors-custom-attribute.ts b/src/validation-errors-custom-attribute.ts index 6ee90092..8318a425 100644 --- a/src/validation-errors-custom-attribute.ts +++ b/src/validation-errors-custom-attribute.ts @@ -1,9 +1,9 @@ -import {bindingMode} from 'aurelia-binding'; -import {Lazy} from 'aurelia-dependency-injection'; -import {customAttribute} from 'aurelia-templating'; -import {ValidationController} from './validation-controller'; -import {ValidationError} from './validation-error'; -import {ValidationRenderer, RenderInstruction} from './validation-renderer'; +import { bindingMode } from 'aurelia-binding'; +import { Lazy } from 'aurelia-dependency-injection'; +import { customAttribute } from 'aurelia-templating'; +import { ValidationController } from './validation-controller'; +import { ValidationError } from './validation-error'; +import { ValidationRenderer, RenderInstruction } from './validation-renderer'; export interface RenderedError { error: ValidationError; @@ -12,28 +12,30 @@ export interface RenderedError { @customAttribute('validation-errors', bindingMode.twoWay) export class ValidationErrorsCustomAttribute implements ValidationRenderer { - static inject = [Element, Lazy.of(ValidationController)]; + public static inject = [Element, Lazy.of(ValidationController)]; - value: RenderedError[]; - errors: RenderedError[] = []; + public value: RenderedError[]; + public errors: RenderedError[] = []; constructor(private boundaryElement: Element, private controllerAccessor: { (): ValidationController; }) { } - sort() { + public sort() { this.errors.sort((a, b) => { if (a.targets[0] === b.targets[0]) { return 0; } + /* tslint:disable:no-bitwise */ return a.targets[0].compareDocumentPosition(b.targets[0]) & 2 ? 1 : -1; + /* tslint:enable:no-bitwise */ }); } - interestingElements(elements: Element[]): Element[] { + public interestingElements(elements: Element[]): Element[] { return elements.filter(e => this.boundaryElement.contains(e)); } - render(instruction: RenderInstruction) { + public render(instruction: RenderInstruction) { for (let { error } of instruction.unrender) { const index = this.errors.findIndex(x => x.error === error); if (index !== -1) { @@ -44,20 +46,20 @@ export class ValidationErrorsCustomAttribute implements ValidationRenderer { for (let { error, elements } of instruction.render) { const targets = this.interestingElements(elements); if (targets.length) { - this.errors.push({ error: error, targets }); - } + this.errors.push({ error, targets }); + } } this.sort(); this.value = this.errors; } - bind() { + public bind() { this.controllerAccessor().addRenderer(this); this.value = this.errors; } - unbind() { + public unbind() { this.controllerAccessor().removeRenderer(this); } } diff --git a/src/validation-renderer-custom-attribute.ts b/src/validation-renderer-custom-attribute.ts index df000bd5..ce04a2fc 100644 --- a/src/validation-renderer-custom-attribute.ts +++ b/src/validation-renderer-custom-attribute.ts @@ -1,5 +1,5 @@ -import {ValidationController} from './validation-controller'; -import {ValidationRenderer} from './validation-renderer'; +import { ValidationController } from './validation-controller'; +import { ValidationRenderer } from './validation-renderer'; export class ValidationRendererCustomAttribute { private container: any; @@ -7,17 +7,17 @@ export class ValidationRendererCustomAttribute { private value: string; private renderer: ValidationRenderer; - created(view: any) { + public created(view: any) { this.container = view.container; } - bind() { + public bind() { this.controller = this.container.get(ValidationController); this.renderer = this.container.get(this.value); this.controller.addRenderer(this.renderer); } - unbind() { + public unbind() { this.controller.removeRenderer(this.renderer); this.controller = null; this.renderer = null; diff --git a/src/validator.ts b/src/validator.ts index 98e9cf35..4c79f13c 100644 --- a/src/validator.ts +++ b/src/validator.ts @@ -1,4 +1,4 @@ -import {ValidationError} from './validation-error'; +import { ValidationError } from './validation-error'; /** * Validates. @@ -12,20 +12,20 @@ export abstract class Validator { * @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; - + public 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; + public 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; + public abstract ruleExists(rules: any, rule: any): boolean; } diff --git a/test/basic.ts b/test/basic.ts index d74679c4..4849e5fd 100644 --- a/test/basic.ts +++ b/test/basic.ts @@ -1,8 +1,8 @@ -import {StageComponent, ComponentTester} from 'aurelia-testing'; -import {bootstrap} from 'aurelia-bootstrapper'; -import {RegistrationForm} from './resources/registration-form'; -import {validateTrigger} from '../src/aurelia-validation'; -import {configure, blur, change} from './shared'; +import { StageComponent, ComponentTester } from 'aurelia-testing'; +import { bootstrap } from 'aurelia-bootstrapper'; +import { RegistrationForm } from './resources/registration-form'; +import { validateTrigger } from '../src/aurelia-validation'; +import { configure, blur, change } from './shared'; describe('end to end', () => { it('basic scenarios', (done: () => void) => { @@ -12,9 +12,12 @@ describe('end to end', () => { .boundTo({}); component.bootstrap(configure); - let firstName: HTMLInputElement, lastName: HTMLInputElement, - number1: HTMLInputElement, number2: HTMLInputElement, - password: HTMLInputElement, confirmPassword: HTMLInputElement; + let firstName: HTMLInputElement; + let lastName: HTMLInputElement; + let number1: HTMLInputElement; + let number2: HTMLInputElement; + let password: HTMLInputElement; + let confirmPassword: HTMLInputElement; let viewModel: RegistrationForm; @@ -24,7 +27,7 @@ describe('end to end', () => { // grab some references. .then(() => { viewModel = component.viewModel; - viewModel.controller.addRenderer(renderer); + viewModel.controller.addRenderer(renderer); firstName = component.element.querySelector('#firstName'); lastName = component.element.querySelector('#lastName'); number1 = component.element.querySelector('#number1'); @@ -79,12 +82,12 @@ describe('end to end', () => { // this should reset the errors for the number2 field. .then(() => viewModel.number2 = 2) // confirm the error was reset. - .then(() => expect(viewModel.controller.errors.length).toBe(1)) + .then(() => expect(viewModel.controller.errors.length).toBe(1)) // change the numbers back to invalid values. .then(() => { viewModel.number1 = 0; viewModel.number2 = 0; - }) + }) // hide the form and change the validateTrigger. .then(() => { @@ -98,7 +101,7 @@ describe('end to end', () => { // change the firstName field- this should trigger validation. .then(() => change(firstName, 'test')) // confirm there's no error. - .then(() => expect(viewModel.controller.errors.length).toBe(0)) + .then(() => expect(viewModel.controller.errors.length).toBe(0)) // change the firstName field- this should trigger validation. .then(() => change(firstName, '')) // confirm there's an error. diff --git a/test/main.ts b/test/main.ts index 27401d26..6a35b395 100644 --- a/test/main.ts +++ b/test/main.ts @@ -1,22 +1,22 @@ -var allTestFiles: string[] = [] -var TEST_REGEXP = /^\/base\/dist\/test\/test\/[^\/]+\.js$/i +let allTestFiles: string[] = []; +let TEST_REGEXP = /^\/base\/dist\/test\/test\/[^\/]+\.js$/i; -declare var require: any; +declare let require: any; interface Window { __karma__: any; } // Get a list of all the test files to include -Object.keys(window.__karma__.files).forEach(function (file) { +Object.keys(window.__karma__.files).forEach(file => { if (TEST_REGEXP.test(file) && file !== '/base/dist/test/test/main.js') { // Normalize paths to RequireJS module names. // If you require sub-dependencies of test files to be loaded as-is (requiring file extension) // then do not normalize the paths - var normalizedTestModule = file.replace(/^\/base\/|\.js$/g, '') - allTestFiles.push(normalizedTestModule) + let normalizedTestModule = file.replace(/^\/base\/|\.js$/g, ''); + allTestFiles.push(normalizedTestModule); } -}) +}); let started = false; @@ -35,8 +35,8 @@ require.config({ pal.initialize(); require(allTestFiles, () => window.__karma__.start()); }, - paths: { + /* tslint:disable:max-line-length */ 'aurelia-binding': '/base/node_modules/aurelia-binding/dist/amd/aurelia-binding', 'aurelia-bootstrapper': '/base/node_modules/aurelia-bootstrapper/dist/amd/aurelia-bootstrapper', 'aurelia-dependency-injection': '/base/node_modules/aurelia-dependency-injection/dist/amd/aurelia-dependency-injection', @@ -58,28 +58,31 @@ require.config({ 'aurelia-task-queue': '/base/node_modules/aurelia-task-queue/dist/amd/aurelia-task-queue', 'aurelia-templating': '/base/node_modules/aurelia-templating/dist/amd/aurelia-templating', 'aurelia-templating-binding': '/base/node_modules/aurelia-templating-binding/dist/amd/aurelia-templating-binding', + /* tslint:enable:max-line-length */ + /* tslint:disable */ 'text': '/base/node_modules/requirejs-text/text', + /* tslint:enable */ }, packages: [ { name: 'aurelia-templating-router', location: '/base/node_modules/aurelia-templating-router/dist/amd', - main : 'aurelia-templating-router' + main: 'aurelia-templating-router' }, { name: 'aurelia-templating-resources', location: '/base/node_modules/aurelia-templating-resources/dist/amd', - main : 'aurelia-templating-resources' + main: 'aurelia-templating-resources' }, { name: 'aurelia-testing', location: '/base/node_modules/aurelia-testing/dist/amd', - main : 'aurelia-testing' + main: 'aurelia-testing' }, { name: 'dist/test/src/aurelia-validation', location: '/base/dist/test/src', - main : 'aurelia-validation' + main: 'aurelia-validation' } ] -}) +}); diff --git a/test/null-object.ts b/test/null-object.ts index 1e280750..bd129997 100644 --- a/test/null-object.ts +++ b/test/null-object.ts @@ -1,7 +1,7 @@ -import {StageComponent, ComponentTester} from 'aurelia-testing'; -import {bootstrap} from 'aurelia-bootstrapper'; -import {NullableObjectForm} from './resources/nullable-object-form'; -import {configure, blur, change} from './shared'; +import { StageComponent, ComponentTester } from 'aurelia-testing'; +import { bootstrap } from 'aurelia-bootstrapper'; +import { NullableObjectForm } from './resources/nullable-object-form'; +import { configure, blur, change } from './shared'; describe('ValidationController', () => { it('handles bindings with null objects', (done: () => void) => { @@ -41,7 +41,7 @@ describe('ValidationController', () => { return new Promise(resolve => setTimeout(resolve, 500)); }) .then(() => expect(viewModel.controller.errors.length).toBe(0)) - + // cleanup and finish. .then(() => component.dispose()) .then(done); diff --git a/test/resources/index.ts b/test/resources/index.ts index 385105c1..725406b9 100644 --- a/test/resources/index.ts +++ b/test/resources/index.ts @@ -1,4 +1,4 @@ -import {FrameworkConfiguration} from 'aurelia-framework'; +import { FrameworkConfiguration } from 'aurelia-framework'; export function configure(config: FrameworkConfiguration) { config.globalResources([ diff --git a/test/resources/nullable-object-form.ts b/test/resources/nullable-object-form.ts index 6fd0d88d..7ddb0e4c 100644 --- a/test/resources/nullable-object-form.ts +++ b/test/resources/nullable-object-form.ts @@ -1,5 +1,5 @@ -import {inject, NewInstance} from 'aurelia-dependency-injection'; -import {inlineView} from 'aurelia-templating'; +import { inject, NewInstance } from 'aurelia-dependency-injection'; +import { inlineView } from 'aurelia-templating'; import { ValidationRules, ValidationController @@ -13,19 +13,23 @@ import { `) @inject(NewInstance.of(ValidationController)) export class NullableObjectForm { - input: HTMLInputElement; - - _obj: any = { prop: '' }; + public input: HTMLInputElement; + + /* tslint:disable */ + public _obj: any = { prop: '' }; + /* tslint:enable */ get obj() { return this._obj; } set obj(value) { // setter is required due to https://github.com/aurelia/binding/issues/205 + /* tslint:disable:no-console */ console.log(value); + /* tslint:enable:no-console */ } - rules = ValidationRules.ensure('prop').required().rules; + public rules = ValidationRules.ensure('prop').required().rules; - constructor(public controller: ValidationController) {} + constructor(public controller: ValidationController) { } } diff --git a/test/resources/number-value.ts b/test/resources/number-value.ts index b4c8bc75..5ac83fe5 100644 --- a/test/resources/number-value.ts +++ b/test/resources/number-value.ts @@ -1,28 +1,30 @@ -import {DOM} from 'aurelia-pal'; -import {inject} from 'aurelia-dependency-injection' -import {customAttribute, customElement, bindable, inlineView} from 'aurelia-templating'; -import {bindingMode} from 'aurelia-binding'; +import { DOM } from 'aurelia-pal'; +import { inject } from 'aurelia-dependency-injection'; +import { customAttribute, customElement, bindable, inlineView } from 'aurelia-templating'; +import { bindingMode } from 'aurelia-binding'; export abstract class NumberBase { - public abstract value: number|null; + public abstract value: number | null; + /* tslint:disable */ protected _input: HTMLInputElement; + /* tslint:enable */ - constructor(protected input: HTMLInputElement) {} + constructor(protected input: HTMLInputElement) { } - valueChanged(newValue: number|null) { + public valueChanged(newValue: number | null) { this.input.value = newValue === null ? '' : newValue.toString(10); } - inputValueChanged = () => { - this.value = this.input.value === '' ? null : parseInt(this.input.value); + public inputValueChanged = () => { + this.value = this.input.value === '' ? null : parseInt(this.input.value, 10); }; - bind() { + public bind() { this._input = this.input; this._input.addEventListener('change', this.inputValueChanged); } - unbind() { + public unbind() { this._input.removeEventListener('change', this.inputValueChanged); this._input = null; } @@ -31,30 +33,30 @@ export abstract class NumberBase { @customAttribute('number-value', bindingMode.twoWay) @inject(Element) export class NumberValueCustomAttribute extends NumberBase { - public value: number|null; + public value: number | null; } @customElement('number-input') @inject(Element) @inlineView(``) export class NumberInputCustomElement extends NumberBase { - @bindable({ defaultBindingMode: bindingMode.twoWay }) value: number|null; + @bindable({ defaultBindingMode: bindingMode.twoWay }) public value: number | null; constructor(private element: Element) { super(null); (this.element).focus = () => this.input.focus(); } - inputBlurred = () => { + public inputBlurred = () => { this.element.dispatchEvent(DOM.createCustomEvent('blur', {})); }; - bind() { + public bind() { super.bind(); - this._input.addEventListener('blur', this.inputBlurred); + this._input.addEventListener('blur', this.inputBlurred); } - unbind() { + public unbind() { this._input.removeEventListener('blur', this.inputBlurred); super.unbind(); } diff --git a/test/resources/registration-form.ts b/test/resources/registration-form.ts index 045ce8c4..f6c5d967 100644 --- a/test/resources/registration-form.ts +++ b/test/resources/registration-form.ts @@ -1,5 +1,5 @@ -import {inject} from 'aurelia-dependency-injection'; -import {inlineView} from 'aurelia-templating'; +import { inject } from 'aurelia-dependency-injection'; +import { inlineView } from 'aurelia-templating'; import { ValidationRules, ValidationControllerFactory, @@ -20,15 +20,15 @@ import { `) @inject(ValidationControllerFactory) export class RegistrationForm { - firstName = ''; - lastName = ''; - email = ''; - number1 = 0; - number2 = 0; - password = ''; - confirmPassword = ''; - controller: ValidationController; - showForm = true; + public firstName = ''; + public lastName = ''; + public email = ''; + public number1 = 0; + public number2 = 0; + public password = ''; + public confirmPassword = ''; + public controller: ValidationController; + public showForm = true; constructor(controllerFactory: ValidationControllerFactory) { this.controller = controllerFactory.createForCurrentScope(); @@ -37,7 +37,7 @@ export class RegistrationForm { ValidationRules.customRule( 'matchesProperty', - (value, obj, otherPropertyName) => + (value, obj, otherPropertyName) => value === null || value === undefined || value === '' diff --git a/test/resources/trigger-form.ts b/test/resources/trigger-form.ts index acc147e4..65d7e847 100644 --- a/test/resources/trigger-form.ts +++ b/test/resources/trigger-form.ts @@ -1,5 +1,5 @@ -import {inject, NewInstance} from 'aurelia-dependency-injection'; -import {inlineView} from 'aurelia-templating'; +import { inject, NewInstance } from 'aurelia-dependency-injection'; +import { inlineView } from 'aurelia-templating'; import { ValidationRules, ValidationController @@ -17,20 +17,20 @@ import { `) @inject(NewInstance.of(ValidationController)) export class TriggerForm { - standardInput: HTMLInputElement; - blurInput: HTMLInputElement; - changeInput: HTMLInputElement; - changeOrBlurInput: HTMLInputElement; - manualInput: HTMLInputElement; - - standardProp = ''; - blurProp = ''; - changeProp = ''; - changeOrBlurProp = ''; - manualProp = ''; - showForm = true; + public standardInput: HTMLInputElement; + public blurInput: HTMLInputElement; + public changeInput: HTMLInputElement; + public changeOrBlurInput: HTMLInputElement; + public manualInput: HTMLInputElement; - constructor(public controller: ValidationController) {} + public standardProp = ''; + public blurProp = ''; + public changeProp = ''; + public changeOrBlurProp = ''; + public manualProp = ''; + public showForm = true; + + constructor(public controller: ValidationController) { } } ValidationRules diff --git a/test/shared.ts b/test/shared.ts index a750a3c6..76639f47 100644 --- a/test/shared.ts +++ b/test/shared.ts @@ -1,10 +1,10 @@ -import {Aurelia} from 'aurelia-framework'; -import {DOM} from 'aurelia-pal'; +import { Aurelia } from 'aurelia-framework'; +import { DOM } from 'aurelia-pal'; export function configure(aurelia: Aurelia) { aurelia.use .standardConfiguration() - //.developmentLogging() + // .developmentLogging() .plugin('dist/test/src/aurelia-validation') .feature('./dist/test/test/resources'); } @@ -16,6 +16,6 @@ export function blur(element: Element): Promise { export function change(element: HTMLInputElement, value: string): Promise { element.value = value; - element.dispatchEvent(DOM.createCustomEvent('change', { bubbles: true })); + element.dispatchEvent(DOM.createCustomEvent('change', { bubbles: true })); return new Promise(setTimeout); } diff --git a/test/validate-binding-behavior.ts b/test/validate-binding-behavior.ts index a5cc957a..a40f319a 100644 --- a/test/validate-binding-behavior.ts +++ b/test/validate-binding-behavior.ts @@ -1,7 +1,7 @@ -import {StageComponent, ComponentTester} from 'aurelia-testing'; -import {bootstrap} from 'aurelia-bootstrapper'; -import {TriggerForm} from './resources/trigger-form'; -import {configure, blur, change} from './shared'; +import { StageComponent, ComponentTester } from 'aurelia-testing'; +import { bootstrap } from 'aurelia-bootstrapper'; +import { TriggerForm } from './resources/trigger-form'; +import { configure, blur, change } from './shared'; describe('ValidateBindingBehavior', () => { it('sets validateTrigger', (done: () => void) => { diff --git a/test/validation-controller-factory.ts b/test/validation-controller-factory.ts index 7b69af08..0c6ca977 100644 --- a/test/validation-controller-factory.ts +++ b/test/validation-controller-factory.ts @@ -1,4 +1,4 @@ -import {Container, Optional} from 'aurelia-dependency-injection'; +import { Container, Optional } from 'aurelia-dependency-injection'; import { ValidationControllerFactory, ValidationController, diff --git a/test/validation-parser.ts b/test/validation-parser.ts index 67e36f7a..b6f0b37f 100644 --- a/test/validation-parser.ts +++ b/test/validation-parser.ts @@ -1,8 +1,8 @@ -import {Expression, AccessScope} from 'aurelia-binding'; -import {Container} from 'aurelia-dependency-injection'; -import {BindingLanguage} from 'aurelia-templating' -import {TemplatingBindingLanguage} from 'aurelia-templating-binding'; -import {ValidationParser} from '../src/aurelia-validation'; +import { Expression, AccessScope } from 'aurelia-binding'; +import { Container } from 'aurelia-dependency-injection'; +import { BindingLanguage } from 'aurelia-templating'; +import { TemplatingBindingLanguage } from 'aurelia-templating-binding'; +import { ValidationParser } from '../src/aurelia-validation'; describe('Validator', () => { let parser: ValidationParser; diff --git a/test/validator.ts b/test/validator.ts index e9510616..2b2b9e7c 100644 --- a/test/validator.ts +++ b/test/validator.ts @@ -1,6 +1,6 @@ -import {Container} from 'aurelia-dependency-injection'; -import {BindingLanguage} from 'aurelia-templating' -import {TemplatingBindingLanguage} from 'aurelia-templating-binding'; +import { Container } from 'aurelia-dependency-injection'; +import { BindingLanguage } from 'aurelia-templating'; +import { TemplatingBindingLanguage } from 'aurelia-templating-binding'; import { StandardValidator, ValidationRules, @@ -16,10 +16,10 @@ describe('Validator', () => { container.registerInstance(BindingLanguage, container.get(TemplatingBindingLanguage)); const parser = container.get(ValidationParser); ValidationRules.initialize(parser); - validator = container.get(StandardValidator); + validator = container.get(StandardValidator); }); - it('validates email', (done: () => void) => { + it('validates email', (done: () => void) => { let obj = { prop: 'foo@bar.com' }; let rules = ValidationRules.ensure('prop').email().rules; validator.validateProperty(obj, 'prop', rules) @@ -27,7 +27,7 @@ describe('Validator', () => { .then(() => { obj = { prop: 'foo' }; rules = ValidationRules.ensure('prop').email().rules; - return validator.validateProperty(obj, 'prop', rules); + return validator.validateProperty(obj, 'prop', rules); }) .then(errors => { const expected = [new ValidationError(rules[0][0], 'Prop is not a valid email.', obj, 'prop')]; @@ -43,7 +43,7 @@ describe('Validator', () => { .then(done); }); - it('validates equals', (done: () => void) => { + it('validates equals', (done: () => void) => { let obj = { prop: 'test' }; let rules = ValidationRules.ensure('prop').equals('test').rules; validator.validateProperty(obj, 'prop', rules) @@ -51,7 +51,7 @@ describe('Validator', () => { .then(() => { obj = { prop: 'foo' }; rules = ValidationRules.ensure('prop').equals('test').rules; - return validator.validateProperty(obj, 'prop', rules); + return validator.validateProperty(obj, 'prop', rules); }) .then(errors => { const expected = [new ValidationError(rules[0][0], 'Prop must be test.', obj, 'prop')]; @@ -67,11 +67,11 @@ describe('Validator', () => { .then(done); }); - it('bails', (done: () => void) => { + it('bails', (done: () => void) => { let obj = { prop: 'invalid email' }; let spy = jasmine.createSpy().and.returnValue(true); let rules = ValidationRules.ensure('prop').email().then().satisfies(spy).rules; - validator.validateProperty(obj, 'prop', rules) + validator.validateProperty(obj, 'prop', rules) .then(errors => { const expected = [new ValidationError(rules[0][0], 'Prop is not a valid email.', obj, 'prop')]; expected[0].id = errors[0].id; diff --git a/tslint.json b/tslint.json new file mode 100644 index 00000000..0ca7c835 --- /dev/null +++ b/tslint.json @@ -0,0 +1,14 @@ +{ + "extends": "tslint:latest", + "rules": { + "quotemark": [true, "single"], + "object-literal-sort-keys": false, + "ordered-imports": [false], + "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-module", "check-separator", "check-type"], + "interface-name": [true, "never-prefix"], + "no-shadowed-variable": false, + "no-string-literal": false, + "trailing-comma": false, + "member-ordering": ["fields-first"] + } +}