diff --git a/.gitignore b/.gitignore index e5806885e9f..383713b0349 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ node_modules typings /dist +/transpiled /xmloutput test-results.xml npm-debug.log diff --git a/app/scripts/modules/core/application/application.model.ts b/app/scripts/modules/core/application/application.model.ts index 1f0c2ed5174..fe3b9104616 100644 --- a/app/scripts/modules/core/application/application.model.ts +++ b/app/scripts/modules/core/application/application.model.ts @@ -1,11 +1,9 @@ -import {ApplicationDataSource} from "./service/applicationDataSource"; +import {ApplicationDataSource} from './service/applicationDataSource'; import {Subject} from 'rxjs'; export class Application { - [k:string]: any; - - constructor(private applicationName: string, private scheduler: any, private $q: ng.IQService, private $log: ng.ILogService) {} + [k: string]: any; /** * A collection of all available data sources for the given application @@ -61,6 +59,12 @@ export class Application { */ public notFound: boolean = false; + private refreshStream: Subject = new Subject(); + + private refreshFailureStream: Subject = new Subject(); + + constructor(private applicationName: string, private scheduler: any, private $q: ng.IQService, private $log: ng.ILogService) {} + /** * Returns a data source based on its key. Data sources can be accessed on the application directly via the key, * e.g. application.serverGroups, but this is the preferred access method, as it allows type inference @@ -122,10 +126,6 @@ export class Application { }); } - private refreshStream: Subject = new Subject(); - - private refreshFailureStream: Subject = new Subject(); - private applicationLoadError(err: Error): void { this.$log.error(err, 'Failed to load application, will retry on next scheduler execution.'); this.refreshFailureStream.next(err); @@ -151,7 +151,7 @@ export class Application { let results = new Map(); let sources = this.dataSources.filter(d => d[field] !== undefined); let providers = sources.map(ds => ds.data.map(d => d[ds.providerField])).filter(p => p.length > 0); - let allProviders: any; //typescript made me do it this way + let allProviders: any; // typescript made me do it this way allProviders = _.union(...providers); allProviders.forEach((provider: string) => { let vals = sources @@ -167,7 +167,6 @@ export class Application { private setDefaults(): void { this.defaultCredentials = this.extractProviderDefault('credentialsField'); - this.defaultRegions = this.extractProviderDefault('regionField') + this.defaultRegions = this.extractProviderDefault('regionField'); } - } diff --git a/app/scripts/modules/core/application/service/applicationDataSource.registry.ts b/app/scripts/modules/core/application/service/applicationDataSource.registry.ts index 86c2955df30..b92aee448bf 100644 --- a/app/scripts/modules/core/application/service/applicationDataSource.registry.ts +++ b/app/scripts/modules/core/application/service/applicationDataSource.registry.ts @@ -2,7 +2,7 @@ import * as _ from 'lodash'; import {module} from 'angular'; -import {DataSourceConfig} from './applicationDataSource.ts' +import {DataSourceConfig} from './applicationDataSource.ts'; export class ApplicationDataSourceRegistry { diff --git a/app/scripts/modules/core/application/service/applicationDataSource.ts b/app/scripts/modules/core/application/service/applicationDataSource.ts index 57e553cf957..8bed51076a1 100644 --- a/app/scripts/modules/core/application/service/applicationDataSource.ts +++ b/app/scripts/modules/core/application/service/applicationDataSource.ts @@ -3,10 +3,6 @@ import {Application} from '../application.model.ts'; export class DataSourceConfig { - constructor(config:any) { - Object.assign(this, config); - } - /** * unique value for this data source; the data source will be available on the Application directly via this key, * e.g. if the key is "serverGroups", you can access the data source via application.serverGroups @@ -117,24 +113,13 @@ export class DataSourceConfig { * to the field name that represents the provider on each data item. */ public providerField: string; -} - -export class ApplicationDataSource { - constructor(config: DataSourceConfig, private application: Application, private $q?: ng.IQService, private $log?: ng.ILogService, private $filter?: any) { + constructor(config: any) { Object.assign(this, config); - if (!config.sref && config.visible !== false) { - this.sref = '.insight.' + config.key; - } - - if (!config.label && this.$filter) { - this.label = this.$filter('robotToHuman')(config.key); - } - - if (!config.activeState) { - this.activeState = '**' + this.sref + '.**'; - } } +} + +export class ApplicationDataSource { /** * Index Signature @@ -259,6 +244,10 @@ export class ApplicationDataSource { */ public loader: {(any: any): ng.IPromise}; + private refreshStream: Subject = new Subject(); + + private refreshFailureStream: Subject = new Subject(); + /** * Called when a method mutates some item in the data source's data, e.g. when a running execution is updated * independent of the execution data source's refresh cycle @@ -267,6 +256,21 @@ export class ApplicationDataSource { this.refreshStream.next(null); } + constructor(config: DataSourceConfig, private application: Application, private $q?: ng.IQService, private $log?: ng.ILogService, private $filter?: any) { + Object.assign(this, config); + if (!config.sref && config.visible !== false) { + this.sref = '.insight.' + config.key; + } + + if (!config.label && this.$filter) { + this.label = this.$filter('robotToHuman')(config.key); + } + + if (!config.activeState) { + this.activeState = '**' + this.sref + '.**'; + } + } + /** * A method that allows another method to be called the next time the data source refreshes * @@ -397,9 +401,4 @@ export class ApplicationDataSource { } } } - - private refreshStream: Subject = new Subject(); - - private refreshFailureStream: Subject = new Subject(); - } diff --git a/app/scripts/modules/core/chaosMonkey/chaosMonkeyExceptions.component.ts b/app/scripts/modules/core/chaosMonkey/chaosMonkeyExceptions.component.ts index 22c3c932d1e..27c2520c735 100644 --- a/app/scripts/modules/core/chaosMonkey/chaosMonkeyExceptions.component.ts +++ b/app/scripts/modules/core/chaosMonkey/chaosMonkeyExceptions.component.ts @@ -6,13 +6,13 @@ export class ChaosMonkeyExceptionsController { static get $inject() { return ['accountService', '$q']; } - public constructor(private accountService: any, private $q: ng.IQService) {} - public accounts: any[] = []; public regionsByAccount: any; public config: any; public configChanged: () => void; + public constructor(private accountService: any, private $q: ng.IQService) {} + public addException(): void { this.config.exceptions = this.config.exceptions || []; this.config.exceptions.push({}); @@ -21,7 +21,7 @@ export class ChaosMonkeyExceptionsController { public removeException(index): void { this.config.exceptions.splice(index, 1); - this.configChanged() + this.configChanged(); }; public $onInit(): void { diff --git a/app/scripts/modules/core/chaosMonkey/chaosMonkeyNewApplicationConfig.component.ts b/app/scripts/modules/core/chaosMonkey/chaosMonkeyNewApplicationConfig.component.ts index cad8ef29a70..641bb7b034b 100644 --- a/app/scripts/modules/core/chaosMonkey/chaosMonkeyNewApplicationConfig.component.ts +++ b/app/scripts/modules/core/chaosMonkey/chaosMonkeyNewApplicationConfig.component.ts @@ -12,7 +12,7 @@ export class ChaosMonkeyNewApplicationConfigController { if (this.enabled) { this.applicationConfig.chaosMonkey = { enabled: this.enabled - } + }; } } } diff --git a/app/scripts/modules/core/delivery/executionBuild/buildDisplayName.filter.ts b/app/scripts/modules/core/delivery/executionBuild/buildDisplayName.filter.ts index 29e8bfc29d5..0c1fe170d38 100644 --- a/app/scripts/modules/core/delivery/executionBuild/buildDisplayName.filter.ts +++ b/app/scripts/modules/core/delivery/executionBuild/buildDisplayName.filter.ts @@ -1,8 +1,6 @@ -'use strict'; - import { module } from 'angular'; -import { BuildInfo } from '../../domain' +import { BuildInfo } from '../../domain'; const MODULE_NAME = 'spinnaker.core.delivery.buildDisplayName.filter'; @@ -11,12 +9,12 @@ export function buildDisplayName() { if (!input) { return ''; } - var formattedInput = ''; - if( input.fullDisplayName !== undefined ) { + let formattedInput = ''; + if (input.fullDisplayName !== undefined) { formattedInput = input.fullDisplayName.split('#' + input.number).pop(); } return formattedInput; - }; + }; } module(MODULE_NAME, []) diff --git a/app/scripts/modules/core/delivery/status/executionUser.filter.ts b/app/scripts/modules/core/delivery/status/executionUser.filter.ts index 2cc765b1f3e..04075aa14af 100644 --- a/app/scripts/modules/core/delivery/status/executionUser.filter.ts +++ b/app/scripts/modules/core/delivery/status/executionUser.filter.ts @@ -1,7 +1,7 @@ import { has } from 'lodash'; import { module } from 'angular'; -import { Execution } from '../../domain' +import { Execution } from '../../domain'; export function executionUserFilter() { return function (input: Execution): string { @@ -14,11 +14,11 @@ export function executionUserFilter() { } return user; }; -}; +} const MODULE_NAME = 'spinnaker.core.delivery.executionUser.filter'; module(MODULE_NAME, []) .filter('executionUser', executionUserFilter); -export default MODULE_NAME +export default MODULE_NAME; diff --git a/app/scripts/modules/core/domain/health.ts b/app/scripts/modules/core/domain/health.ts index 26d8d886948..16e09bbdabc 100644 --- a/app/scripts/modules/core/domain/health.ts +++ b/app/scripts/modules/core/domain/health.ts @@ -1,5 +1,4 @@ - -import { LoadBalancer } from "./loadBalancer"; +import { LoadBalancer } from './loadBalancer'; export class Health { type: string; diff --git a/app/scripts/modules/core/domain/loadBalancer.ts b/app/scripts/modules/core/domain/loadBalancer.ts index 99c349b10d9..d7b8880a722 100644 --- a/app/scripts/modules/core/domain/loadBalancer.ts +++ b/app/scripts/modules/core/domain/loadBalancer.ts @@ -1,6 +1,5 @@ import { InstanceCounts } from './instanceCounts'; - export class LoadBalancer { constructor( @@ -10,8 +9,7 @@ export class LoadBalancer { public region?: string, public account?: string, public serverGroups?: any[], - public healthState?:string, + public healthState?: string, public instanceCounts?: InstanceCounts, ) { } - } diff --git a/app/scripts/modules/core/loadBalancer/loadBalancersTag.component.ts b/app/scripts/modules/core/loadBalancer/loadBalancersTag.component.ts index a716fd66fde..06866ded29f 100644 --- a/app/scripts/modules/core/loadBalancer/loadBalancersTag.component.ts +++ b/app/scripts/modules/core/loadBalancer/loadBalancersTag.component.ts @@ -1,10 +1,10 @@ -import { Application } from '../application/application.model.ts'; +import { Application } from '../application/application.model'; import { LoadBalancer, ServerGroup, Health } from '../domain'; -import {InstanceCounts} from "../domain/instanceCounts"; +import {InstanceCounts} from '../domain/instanceCounts'; export class LoadBalancersTagController implements ng.IComponentController { @@ -21,7 +21,7 @@ export class LoadBalancersTagController implements ng.IComponentController { .find((lb: LoadBalancer): boolean => { return lb.name === lbName && lb.account === serverGroup.account - && lb.region === serverGroup.region + && lb.region === serverGroup.region; }); return this.buildLoadBalancer(match); @@ -35,7 +35,7 @@ export class LoadBalancersTagController implements ng.IComponentController { } let loadBalancer: LoadBalancer = new LoadBalancer(match.name, match.vpcId); - loadBalancer.instanceCounts = {up:0, down: 0, succeeded: 0, failed: 0, unknown: 0}; + loadBalancer.instanceCounts = {up: 0, down: 0, succeeded: 0, failed: 0, unknown: 0}; this.serverGroup.instances.forEach(instance => { let lbHealth: Health = instance.health.find(h => h.type === 'LoadBalancer'); diff --git a/app/scripts/modules/core/pipeline/config/stages/deploy/clusterName.filter.ts b/app/scripts/modules/core/pipeline/config/stages/deploy/clusterName.filter.ts index e153c0c8797..0cee307f778 100644 --- a/app/scripts/modules/core/pipeline/config/stages/deploy/clusterName.filter.ts +++ b/app/scripts/modules/core/pipeline/config/stages/deploy/clusterName.filter.ts @@ -1,6 +1,5 @@ - import { module } from 'angular'; -import { StageContext } from '../../../../domain/stageContext.ts' +import { StageContext } from '../../../../domain/stageContext'; const MODULE_NAME = 'spinnaker.core.pipeline.clusterName.filter'; @@ -12,9 +11,9 @@ export function clusterNameFilter(namingService: any): any { } return namingService.getClusterName(input.application, input.stack, input.freeFormDetails); }; -}; +} module(MODULE_NAME, []) .filter('clusterName', clusterNameFilter); -export default MODULE_NAME +export default MODULE_NAME; diff --git a/app/scripts/modules/core/presentation/anyFieldFilter/anyField.filter.ts b/app/scripts/modules/core/presentation/anyFieldFilter/anyField.filter.ts index 6cc53c230ac..d899af9eae6 100644 --- a/app/scripts/modules/core/presentation/anyFieldFilter/anyField.filter.ts +++ b/app/scripts/modules/core/presentation/anyFieldFilter/anyField.filter.ts @@ -1,8 +1,6 @@ /** * From angular-ui-select demo: http://plnkr.co/edit/juqoNOt1z1Gb349XabQ2 */ -'use strict'; - /** * AngularJS default filter with the following expression: * "person in people | filter: {name: $select.search, age: $select.search}" @@ -12,7 +10,7 @@ import { module } from 'angular'; -const MODULE_NAME ='spinnaker.core.presentation.anyFieldFilter'; +const MODULE_NAME = 'spinnaker.core.presentation.anyFieldFilter'; export function anyFieldFilter() { return function(items: any, props: any): any[] { @@ -20,10 +18,10 @@ export function anyFieldFilter() { if (angular.isArray(items)) { items.forEach(function (item) { - let itemMatches: boolean = false; + let itemMatches = false; let keys: any[] = Object.keys(props); - for (var i = 0; i < keys.length; i++) { + for (let i = 0; i < keys.length; i++) { let prop: any = keys[i]; let text: string = (props)[prop].toLowerCase(); if (item[prop] && item[prop].toString().toLowerCase().indexOf(text) !== -1) { @@ -42,7 +40,7 @@ export function anyFieldFilter() { } return out; - } + }; } module(MODULE_NAME, []) diff --git a/app/scripts/modules/core/task/displayableTasks.filter.ts b/app/scripts/modules/core/task/displayableTasks.filter.ts index 9e4395c157e..ab925e97fe8 100644 --- a/app/scripts/modules/core/task/displayableTasks.filter.ts +++ b/app/scripts/modules/core/task/displayableTasks.filter.ts @@ -1,11 +1,9 @@ -'use strict'; - import { module } from 'angular'; -import { TaskStep } from '../domain/taskStep.ts' +import { TaskStep } from '../domain/taskStep'; export function displayableTaskFilter() { - var blacklist = [ + let blacklist = [ 'stageStart', 'stageEnd' ]; return function (input: TaskStep[]) { @@ -15,7 +13,7 @@ export function displayableTaskFilter() { }); } }; -}; +} const MODULE_NAME = 'spinnaker.pipelines.stages.core.displayableTasks.filter'; diff --git a/app/scripts/modules/google/serverGroup/configure/wizard/loadBalancingPolicy/loadBalancingPolicySelector.component.ts b/app/scripts/modules/google/serverGroup/configure/wizard/loadBalancingPolicy/loadBalancingPolicySelector.component.ts index 8f922b5f93a..f136844d4c8 100644 --- a/app/scripts/modules/google/serverGroup/configure/wizard/loadBalancingPolicy/loadBalancingPolicySelector.component.ts +++ b/app/scripts/modules/google/serverGroup/configure/wizard/loadBalancingPolicy/loadBalancingPolicySelector.component.ts @@ -11,7 +11,7 @@ class GceLoadBalancingPolicySelectorController implements ng.IComponentControlle _.set(this, propertyName, viewValue / 100); }; - public setView (propertyName:string , modelValue: number): void { + public setView (propertyName: string , modelValue: number): void { this[propertyName] = this.decimalToPercent(modelValue); }; diff --git a/karma.conf.js b/karma.conf.js index 2c276a3ac1b..adba39bc76e 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -18,7 +18,6 @@ module.exports = function(config) { './node_modules/jquery/dist/jquery.js', './node_modules/angular/angular.js', './node_modules/angular-mocks/angular-mocks.js', - //'app/**/*.spec.js', 'settings.js', 'test/test_index.js' ], diff --git a/package.json b/package.json index b19fd4b1849..98ace4537df 100644 --- a/package.json +++ b/package.json @@ -106,6 +106,8 @@ "protractor": "^2.2.0", "style-loader": "^0.12.3", "ts-loader": "^0.8.2", + "tslint": "^3.15.1", + "tslint-loader": "^2.1.5", "typescript": "^2.0.2", "typings": "^1.3.3", "url-loader": "^0.5.6", diff --git a/tslint.json b/tslint.json new file mode 100644 index 00000000000..67ab4e64b1c --- /dev/null +++ b/tslint.json @@ -0,0 +1,132 @@ +{ + "rulesDirectory": [ + "node_modules/codelyzer" + ], + "rules": { + "class-name": true, + "comment-format": [ + true, + "check-space" + ], + "curly": true, + "eofline": true, + "forin": true, + "indent": [ + true, + "spaces" + ], + "label-position": true, + "label-undefined": true, + "max-line-length": false, + "member-access": false, + "member-ordering": [ + true, + "static-before-instance", + "variables-before-functions" + ], + "no-arg": true, + "no-bitwise": true, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-construct": true, + "no-debugger": true, + "no-duplicate-key": true, + "no-duplicate-variable": true, + "no-empty": false, + "no-eval": true, + "no-inferrable-types": true, + "no-shadowed-variable": true, + "no-string-literal": false, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-unused-variable": true, + "no-unreachable": true, + "no-use-before-declare": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [ + true, + "check-open-brace", + "check-whitespace" + ], + "quotemark": [ + true, + "single" + ], + "radix": true, + "semicolon": [ + "always" + ], + "triple-equals": [ + true, + "allow-null-check" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "variable-name": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ], + "directive-selector-name": [ + true, + "camelCase" + ], + "component-selector-name": [ + true, + "kebab-case" + ], + "directive-selector-type": [ + true, + "attribute" + ], + "component-selector-type": [ + true, + "element" + ], + "directive-selector-prefix": [ + true, + "deck" + ], + "component-selector-prefix": [ + true, + "deck" + ], + "use-input-property-decorator": true, + "use-output-property-decorator": true, + "use-host-property-decorator": true, + "no-attribute-parameter-decorator": true, + "no-input-rename": true, + "no-output-rename": true, + "no-forward-ref": true, + "use-life-cycle-interface": true, + "use-pipe-transform-interface": true, + "pipe-naming": [ + true, + "camelCase", + "deck" + ], + "component-class-suffix": true, + "directive-class-suffix": true, + "import-destructuring-spacing": false + } +} diff --git a/webpack.config.js b/webpack.config.js index bc3891f0cbe..b5a43fa792b 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -3,7 +3,7 @@ var HtmlWebpackPlugin = require('html-webpack-plugin'); var CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin'); var HappyPack = require('happypack'); -var happyThreadPool = HappyPack.ThreadPool({ size: 6 }); +var happyThreadPool = HappyPack.ThreadPool({size: 6}); var path = require('path'); var nodeModulePath = path.join(__dirname, 'node_modules'); @@ -23,6 +23,12 @@ module.exports = { filename: '[name].js', }, module: { + preLoaders: [ + { + test: /\.ts$/, + loader: "tslint" + } + ], loaders: [ { test: /jquery\.js$/, @@ -76,7 +82,7 @@ module.exports = { }), new HappyPack({ id: 'js', - loaders: [ 'ng-annotate!angular!babel!envify!eslint' ], + loaders: ['ng-annotate!angular!babel!envify!eslint'], threadPool: happyThreadPool, cacheContext: { env: process.env, @@ -84,12 +90,12 @@ module.exports = { }), new HappyPack({ id: 'html', - loaders: [ 'ngtemplate?relativeTo=' + (path.resolve(__dirname)) + '/!html' ], + loaders: ['ngtemplate?relativeTo=' + (path.resolve(__dirname)) + '/!html'], threadPool: happyThreadPool, }), new HappyPack({ id: 'less', - loaders: [ 'style!css!less' ], + loaders: ['style!css!less'], threadPool: happyThreadPool, }), ],