├── .gitignore ├── .vscode ├── settings.json └── tasks.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── app ├── app.component.css ├── app.component.ts ├── app.module.ts ├── customers │ ├── customer.component.html │ ├── customer.component.ts │ └── customer.ts ├── main.ts └── shared │ └── generic-validator.ts ├── favicon.ico ├── index.html ├── package.json ├── systemjs.config.js ├── tsconfig.json └── tslint.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated files 2 | **/app/**/*.js 3 | **/app/**/*.map 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | 15 | # Directory for instrumented libs generated by jscoverage/JSCover 16 | lib-cov 17 | 18 | # Coverage directory used by tools like istanbul 19 | coverage 20 | 21 | # nyc test coverage 22 | .nyc_output 23 | 24 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 25 | .grunt 26 | 27 | # node-waf configuration 28 | .lock-wscript 29 | 30 | # Compiled binary addons (http://nodejs.org/api/addons.html) 31 | build/Release 32 | 33 | # Dependency directories 34 | node_modules 35 | jspm_packages 36 | 37 | # Optional npm cache directory 38 | .npm 39 | 40 | # Optional REPL history 41 | .node_repl_history 42 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "**/.git": true, 5 | "**/.DS_Store": true, 6 | "**/app/**/*.js": true, 7 | "**/*.map": true 8 | }, 9 | // Controls auto save of dirty files. Accepted values: "off", "afterDelay", "onFocusChange". If set to "afterDelay" you can configure the delay in "files.autoSaveDelay". 10 | "files.autoSave": "afterDelay" 11 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${fileBasename}: the current opened file's basename 5 | // ${fileDirname}: the current opened file's dirname 6 | // ${fileExtname}: the current opened file's extension 7 | // ${cwd}: the current working directory of the spawned process 8 | 9 | // A task runner that calls the Typescript compiler (tsc) and 10 | // Compiles a HelloWorld.ts program 11 | { 12 | "version": "0.1.0", 13 | 14 | // The command is tsc. Assumes that tsc has been installed using npm install -g typescript 15 | "command": "tsc", 16 | 17 | // The command is a shell script 18 | "isShellCommand": true, 19 | 20 | // Show the output window only if unrecognized errors occur. 21 | "showOutput": "silent", 22 | 23 | // args is the HelloWorld program to compile. 24 | "args": [ ], 25 | 26 | // use the standard tsc problem matcher to find compile problems 27 | // in the output. 28 | "problemMatcher": "$tsc" 29 | } 30 | 31 | // A task runner that calls the Typescript compiler (tsc) and 32 | // compiles based on a tsconfig.json file that is present in 33 | // the root of the folder open in VSCode 34 | /* 35 | { 36 | "version": "0.1.0", 37 | 38 | // The command is tsc. Assumes that tsc has been installed using npm install -g typescript 39 | "command": "tsc", 40 | 41 | // The command is a shell script 42 | "isShellCommand": true, 43 | 44 | // Show the output window only if unrecognized errors occur. 45 | "showOutput": "silent", 46 | 47 | // Tell the tsc compiler to use the tsconfig.json from the open folder. 48 | "args": ["-p", "."], 49 | 50 | // use the standard tsc problem matcher to find compile problems 51 | // in the output. 52 | "problemMatcher": "$tsc" 53 | } 54 | */ 55 | 56 | // A task runner configuration for gulp. Gulp provides a less task 57 | // which compiles less to css. 58 | /* 59 | { 60 | "version": "0.1.0", 61 | "command": "gulp", 62 | "isShellCommand": true, 63 | "tasks": [ 64 | { 65 | "taskName": "less", 66 | // Make this the default build command. 67 | "isBuildCommand": true, 68 | // Show the output window only if unrecognized errors occur. 69 | "showOutput": "silent", 70 | // Use the standard less compilation problem matcher. 71 | "problemMatcher": "$lessCompile" 72 | } 73 | ] 74 | } 75 | */ 76 | 77 | // Uncomment the following section to use jake to build a workspace 78 | // cloned from https://github.com/Microsoft/TypeScript.git 79 | /* 80 | { 81 | "version": "0.1.0", 82 | // Task runner is jake 83 | "command": "jake", 84 | // Need to be executed in shell / cmd 85 | "isShellCommand": true, 86 | "showOutput": "silent", 87 | "tasks": [ 88 | { 89 | // TS build command is local. 90 | "taskName": "local", 91 | // Make this the default build command. 92 | "isBuildCommand": true, 93 | // Show the output window only if unrecognized errors occur. 94 | "showOutput": "silent", 95 | // Use the redefined Typescript output problem matcher. 96 | "problemMatcher": [ 97 | "$tsc" 98 | ] 99 | } 100 | ] 101 | } 102 | */ 103 | 104 | // Uncomment the section below to use msbuild and generate problems 105 | // for csc, cpp, tsc and vb. The configuration assumes that msbuild 106 | // is available on the path and a solution file exists in the 107 | // workspace folder root. 108 | /* 109 | { 110 | "version": "0.1.0", 111 | "command": "msbuild", 112 | "args": [ 113 | // Ask msbuild to generate full paths for file names. 114 | "/property:GenerateFullPaths=true" 115 | ], 116 | "taskSelector": "/t:", 117 | "showOutput": "silent", 118 | "tasks": [ 119 | { 120 | "taskName": "build", 121 | // Show the output window only if unrecognized errors occur. 122 | "showOutput": "silent", 123 | // Use the standard MS compiler pattern to detect errors, warnings 124 | // and infos in the output. 125 | "problemMatcher": "$msCompile" 126 | } 127 | ] 128 | } 129 | */ 130 | 131 | // Uncomment the following section to use msbuild which compiles Typescript 132 | // and less files. 133 | /* 134 | { 135 | "version": "0.1.0", 136 | "command": "msbuild", 137 | "args": [ 138 | // Ask msbuild to generate full paths for file names. 139 | "/property:GenerateFullPaths=true" 140 | ], 141 | "taskSelector": "/t:", 142 | "showOutput": "silent", 143 | "tasks": [ 144 | { 145 | "taskName": "build", 146 | // Show the output window only if unrecognized errors occur. 147 | "showOutput": "silent", 148 | // Use the standard MS compiler pattern to detect errors, warnings 149 | // and infos in the output. 150 | "problemMatcher": [ 151 | "$msCompile", 152 | "$lessCompile" 153 | ] 154 | } 155 | ] 156 | } 157 | */ 158 | // A task runner example that defines a problemMatcher inline instead of using 159 | // a predefined one. 160 | /* 161 | { 162 | "version": "0.1.0", 163 | "command": "tsc", 164 | "isShellCommand": true, 165 | "args": ["HelloWorld.ts"], 166 | "showOutput": "silent", 167 | "problemMatcher": { 168 | // The problem is owned by the typescript language service. Ensure that the problems 169 | // are merged with problems produced by Visual Studio's language service. 170 | "owner": "typescript", 171 | // The file name for reported problems is relative to the current working directory. 172 | "fileLocation": ["relative", "${cwd}"], 173 | // The actual pattern to match problems in the output. 174 | "pattern": { 175 | // The regular expression. Matches HelloWorld.ts(2,10): error TS2339: Property 'logg' does not exist on type 'Console'. 176 | "regexp": "^([^\\s].*)\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$", 177 | // The match group that denotes the file containing the problem. 178 | "file": 1, 179 | // The match group that denotes the problem location. 180 | "location": 2, 181 | // The match group that denotes the problem's severity. Can be omitted. 182 | "severity": 3, 183 | // The match group that denotes the problem code. Can be omitted. 184 | "code": 4, 185 | // The match group that denotes the problem's message. 186 | "message": 5 187 | } 188 | } 189 | } 190 | */ -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # (2016-11-01) 2 | 3 | ### Changes 4 | * Add ViewChildren to access the blur event so required field validation messages can appear on blur. 5 | Thanks to Brandon Roberts who provided this technique. 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Deborah Kurata 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-generic-validator 2 | Defines a generic validator for Angular 2 Reactive Forms 3 | 4 | The generic validator resides in shared/generic-validator.ts. 5 | The customer component is provided as an example usage of the generic validator. 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/app.component.css: -------------------------------------------------------------------------------- 1 | li { 2 | font-size: large; 3 | } 4 | 5 | div.panel-heading { 6 | font-size: x-large; 7 | } 8 | -------------------------------------------------------------------------------- /app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'my-app', 5 | template: ` 6 |
7 | 8 |
9 | ` 10 | }) 11 | export class AppComponent { } 12 | -------------------------------------------------------------------------------- /app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { ReactiveFormsModule } from '@angular/forms'; 4 | 5 | import { AppComponent } from './app.component'; 6 | import { CustomerComponent } from './customers/customer.component'; 7 | 8 | @NgModule({ 9 | imports: [ 10 | BrowserModule, 11 | ReactiveFormsModule 12 | ], 13 | declarations: [ 14 | AppComponent, 15 | CustomerComponent 16 | ], 17 | bootstrap: [AppComponent] 18 | }) 19 | export class AppModule { } 20 | -------------------------------------------------------------------------------- /app/customers/customer.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | Sign Up! 4 |
5 | 6 |
7 |
11 |
12 |
14 | 16 | 17 |
18 | 23 | 24 | {{ displayMessage.firstName }} 25 | 26 |
27 |
28 | 29 |
31 | 33 | 34 |
35 | 40 | 41 | {{ displayMessage.lastName }} 42 | 43 |
44 |
45 | 46 |
49 |
51 | 53 | 54 |
55 | 60 | 61 | {{ displayMessage.email }} 62 | 63 |
64 |
65 | 66 |
70 | 72 | 73 |
74 | 79 | 82 | 83 | Please confirm your email address. 84 | 85 | 86 |
87 |
88 |
89 |
90 | 91 | 92 | The email address does not match the confirmation. 93 | 94 | 95 |
96 |
97 |
98 | 99 |
101 | 103 | 104 |
105 | 110 | 111 | 112 | Please enter your phone number. 113 | 114 | 115 |
116 |
117 | 118 |
119 | 120 |
121 | 126 | 131 |
132 |
133 | 134 |
135 |
136 | 137 | 142 | 143 |
144 |
145 |
146 |
147 |
148 |
-------------------------------------------------------------------------------- /app/customers/customer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, AfterViewInit, ViewChildren, ElementRef } from '@angular/core'; 2 | import { FormGroup, FormBuilder, Validators, AbstractControl, FormControlName } from '@angular/forms'; 3 | 4 | import 'rxjs/add/operator/debounceTime'; 5 | import 'rxjs/add/observable/fromEvent'; 6 | import 'rxjs/add/observable/merge'; 7 | import { Observable } from 'rxjs/Observable'; 8 | 9 | import { Customer } from './customer'; 10 | import { GenericValidator } from '../shared/generic-validator'; 11 | 12 | function emailMatcher(c: AbstractControl) { 13 | let emailControl = c.get('email'); 14 | let confirmControl = c.get('confirmEmail'); 15 | 16 | if (emailControl.pristine || confirmControl.pristine) { 17 | return null; 18 | } 19 | 20 | if (emailControl.value === confirmControl.value) { 21 | return null; 22 | } 23 | return { 'match': true }; 24 | } 25 | 26 | @Component({ 27 | selector: 'my-signup', 28 | templateUrl: './app/customers/customer.component.html' 29 | }) 30 | export class CustomerComponent implements OnInit, AfterViewInit { 31 | @ViewChildren(FormControlName, { read: ElementRef }) formControls: ElementRef[]; 32 | 33 | customerForm: FormGroup; 34 | customer: Customer = new Customer(); 35 | displayMessage: { [key: string]: string } = {}; 36 | genericValidator: GenericValidator; 37 | 38 | private validationMessages: { [key: string]: { [key: string]: string } } = { 39 | firstName: { 40 | required: 'Please enter your first name.', 41 | minlength: 'The first name must be longer than 3 characters.' 42 | }, 43 | lastName: { 44 | required: 'Please enter your last name.', 45 | maxlength: 'The last name must be less than 50 characters.', 46 | }, 47 | email: { 48 | required: 'Please enter your email address.', 49 | pattern: 'Please enter a valid email address.' 50 | } 51 | }; 52 | 53 | constructor(private fb: FormBuilder) { 54 | // Create an instance of the generic validator 55 | this.genericValidator = new GenericValidator(this.validationMessages); 56 | } 57 | 58 | ngOnInit(): void { 59 | this.customerForm = this.fb.group({ 60 | firstName: [null, [Validators.required, Validators.minLength(3)]], 61 | lastName: [null, [Validators.required, Validators.maxLength(50)]], 62 | emailGroup: this.fb.group({ 63 | email: [null, [Validators.required, Validators.pattern('[a-z0-9._%+-]+@[a-z0-9.-]+')]], 64 | confirmEmail: [null, Validators.required] 65 | }, { validator: emailMatcher }), 66 | phone: null, 67 | notification: 'email' 68 | }); 69 | 70 | this.customerForm.get('notification').valueChanges.subscribe(value => { 71 | this.setNotification(value); 72 | }); 73 | } 74 | 75 | ngAfterViewInit() { 76 | let controlBlurs: Observable[] = this.formControls 77 | .map((formControl: ElementRef) => Observable.fromEvent(formControl.nativeElement, 'blur')); 78 | 79 | Observable.merge(this.customerForm.valueChanges, ...controlBlurs).debounceTime(1000).subscribe(value => { 80 | this.displayMessage = this.genericValidator.processMessages(this.customerForm); 81 | }); 82 | } 83 | 84 | save(): void { 85 | console.log('Saved: ' + JSON.stringify(this.customerForm.value)); 86 | } 87 | 88 | setNotification(notifyVia: string): void { 89 | let phoneControl = this.customerForm.get('phone'); 90 | if (notifyVia === 'text') { 91 | phoneControl.setValidators(Validators.required); 92 | } else { 93 | phoneControl.clearValidators(); 94 | } 95 | phoneControl.updateValueAndValidity(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/customers/customer.ts: -------------------------------------------------------------------------------- 1 | export class Customer { 2 | 3 | constructor(public firstName = '', 4 | public lastName = '', 5 | public email = '', 6 | public phone = '', 7 | public notification = 'email') {} 8 | } 9 | -------------------------------------------------------------------------------- /app/main.ts: -------------------------------------------------------------------------------- 1 | // main entry point 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | import { AppModule } from './app.module'; 4 | 5 | platformBrowserDynamic().bootstrapModule(AppModule); 6 | -------------------------------------------------------------------------------- /app/shared/generic-validator.ts: -------------------------------------------------------------------------------- 1 | import { FormGroup } from '@angular/forms'; 2 | 3 | // Generic validator for Reactive forms 4 | // Implemented as a class, not a service, so it can retain state for multiple forms. 5 | export class GenericValidator { 6 | 7 | // Provide the set of valid validation messages 8 | // Stucture: 9 | // controlName1: { 10 | // validationRuleName1: 'Validation Message.', 11 | // validationRuleName2: 'Validation Message.' 12 | // }, 13 | // controlName2: { 14 | // validationRuleName1: 'Validation Message.', 15 | // validationRuleName2: 'Validation Message.' 16 | // } 17 | constructor(private validationMessages: { [key: string]: { [key: string]: string } }) { 18 | 19 | } 20 | 21 | // Processes each control within a FormGroup 22 | // And returns a set of validation messages to display 23 | // Structure 24 | // controlName1: 'Validation Message.', 25 | // controlName2: 'Validation Message.' 26 | processMessages(container: FormGroup): { [key: string]: string } { 27 | let messages = {}; 28 | for (let controlKey in container.controls) { 29 | if (container.controls.hasOwnProperty(controlKey)) { 30 | let c = container.controls[controlKey]; 31 | // If it is a FormGroup, process its child controls. 32 | if (c instanceof FormGroup) { 33 | let childMessages = this.processMessages(c); 34 | Object.assign(messages, childMessages); 35 | } else { 36 | // Only validate if there are validation messages for the control 37 | if (this.validationMessages[controlKey]) { 38 | messages[controlKey] = ''; 39 | if ((c.dirty || c.touched) && 40 | c.errors) { 41 | for (let messageKey in c.errors) { 42 | if (c.errors.hasOwnProperty(messageKey) && 43 | this.validationMessages[controlKey][messageKey]) { 44 | messages[controlKey] += this.validationMessages[controlKey][messageKey]; 45 | } 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } 52 | return messages; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeborahK/angular-generic-validator/bd6e8db5e889e7f3e047c2d8245e49e675e51741/favicon.ico -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Angular 2: Reactive Forms 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 25 | 26 | 27 | Loading ... 28 | 29 | 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "product-management", 3 | "version": "1.0.0", 4 | "author": "Deborah Kurata", 5 | "description": "Package for the Acme Product Management sample application", 6 | "scripts": { 7 | "start": "tsc && concurrently \"tsc -w\" \"lite-server\" ", 8 | "tsc": "tsc", 9 | "tsc:w": "tsc -w", 10 | "lint": "tslint ./app/**/*.ts -t verbose", 11 | "lite": "lite-server" 12 | }, 13 | "license": "ISC", 14 | "dependencies": { 15 | "@angular/common": "~2.1.1", 16 | "@angular/compiler": "~2.1.1", 17 | "@angular/core": "~2.1.1", 18 | "@angular/forms": "~2.1.1", 19 | "@angular/http": "~2.1.1", 20 | "@angular/platform-browser": "~2.1.1", 21 | "@angular/platform-browser-dynamic": "~2.1.1", 22 | "@angular/router": "~3.1.1", 23 | 24 | "core-js": "^2.4.1", 25 | "reflect-metadata": "^0.1.8", 26 | "rxjs": "5.0.0-beta.12", 27 | "systemjs": "0.19.39", 28 | "zone.js": "^0.6.26", 29 | 30 | "bootstrap": "^3.3.7" 31 | }, 32 | "devDependencies": { 33 | "concurrently": "^3.1.0", 34 | "lite-server": "^2.2.2", 35 | "tslint": "^3.15.1", 36 | "typescript": "^2.0.3", 37 | 38 | "@types/core-js": "^0.9.34", 39 | "@types/node": "^6.0.45" 40 | }, 41 | "repository": {} 42 | } -------------------------------------------------------------------------------- /systemjs.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * System configuration for Angular 2 samples 3 | * Adjust as necessary for your application needs. 4 | */ 5 | (function (global) { 6 | System.config({ 7 | paths: { 8 | // paths serve as alias 9 | 'npm:': 'node_modules/' 10 | }, 11 | // map tells the System loader where to look for things 12 | map: { 13 | // our app is within the app folder 14 | app: 'app', 15 | 16 | // angular bundles 17 | '@angular/core': 'npm:@angular/core/bundles/core.umd.js', 18 | '@angular/common': 'npm:@angular/common/bundles/common.umd.js', 19 | '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', 20 | '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', 21 | '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', 22 | '@angular/http': 'npm:@angular/http/bundles/http.umd.js', 23 | '@angular/router': 'npm:@angular/router/bundles/router.umd.js', 24 | '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', 25 | 26 | // other libraries 27 | 'rxjs': 'npm:rxjs' 28 | }, 29 | // packages tells the System loader how to load when no filename and/or no extension 30 | packages: { 31 | app: { 32 | main: './main.js', 33 | defaultExtension: 'js' 34 | }, 35 | rxjs: { 36 | defaultExtension: 'js' 37 | } 38 | } 39 | }); 40 | })(this); -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "removeComments": false, 10 | "noImplicitAny": true, 11 | "suppressImplicitAnyIndexErrors": true, 12 | "typeRoots": [ 13 | "./node_modules/@types/" 14 | ] 15 | }, 16 | "exclude": [ 17 | "node_modules/*" 18 | ] 19 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "class-name": true, 4 | "comment-format": [ 5 | true, 6 | "check-space" 7 | ], 8 | "curly": true, 9 | "eofline": true, 10 | "forin": true, 11 | "indent": [ 12 | true, 13 | "spaces" 14 | ], 15 | "label-position": true, 16 | "label-undefined": true, 17 | "max-line-length": [ 18 | true, 19 | 140 20 | ], 21 | "member-access": false, 22 | "member-ordering": [ 23 | true, 24 | "static-before-instance", 25 | "variables-before-functions" 26 | ], 27 | "no-arg": true, 28 | "no-bitwise": true, 29 | "no-console": [ 30 | true, 31 | "debug", 32 | "info", 33 | "time", 34 | "timeEnd", 35 | "trace" 36 | ], 37 | "no-construct": true, 38 | "no-debugger": true, 39 | "no-duplicate-key": true, 40 | "no-duplicate-variable": true, 41 | "no-empty": false, 42 | "no-eval": true, 43 | "no-inferrable-types": true, 44 | "no-shadowed-variable": true, 45 | "no-string-literal": false, 46 | "no-switch-case-fall-through": true, 47 | "no-trailing-whitespace": true, 48 | "no-unused-expression": true, 49 | "no-unused-variable": true, 50 | "no-unreachable": true, 51 | "no-use-before-declare": true, 52 | "no-var-keyword": true, 53 | "object-literal-sort-keys": false, 54 | "one-line": [ 55 | true, 56 | "check-open-brace", 57 | "check-catch", 58 | "check-else", 59 | "check-whitespace" 60 | ], 61 | "quotemark": [ 62 | true, 63 | "single" 64 | ], 65 | "radix": true, 66 | "semicolon": [ 67 | "always" 68 | ], 69 | "triple-equals": [ 70 | true, 71 | "allow-null-check" 72 | ], 73 | "typedef-whitespace": [ 74 | true, 75 | { 76 | "call-signature": "nospace", 77 | "index-signature": "nospace", 78 | "parameter": "nospace", 79 | "property-declaration": "nospace", 80 | "variable-declaration": "nospace" 81 | } 82 | ], 83 | "variable-name": false, 84 | "whitespace": [ 85 | true, 86 | "check-branch", 87 | "check-decl", 88 | "check-operator", 89 | "check-separator", 90 | "check-type" 91 | ] 92 | } 93 | } --------------------------------------------------------------------------------