Commit 12727c72 authored by Vitali Stupin's avatar Vitali Stupin

Migrating to eslint

parent f9259960
{
"root": true,
"ignorePatterns": [
"projects/**/*"
],
"overrides": [
{
"files": [
"*.ts"
],
"parserOptions": {
"project": [
"tsconfig.json"
],
"createDefaultProgram": true
},
"extends": [
"plugin:@angular-eslint/ng-cli-compat",
"plugin:@angular-eslint/ng-cli-compat--formatting-add-on",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@typescript-eslint/explicit-member-accessibility": [
"off",
{
"accessibility": "explicit"
}
],
"arrow-parens": [
"off",
"always"
],
"import/order": "off"
}
},
{
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended"
],
"rules": {}
}
]
}
......@@ -93,42 +93,11 @@
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"builder": "@angular-eslint/builder:lint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"xtss-catalogue-e2e": {
"root": "e2e/",
"projectType": "application",
"prefix": "",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "xtss-catalogue:serve"
},
"configurations": {
"production": {
"devServerTarget": "xtss-catalogue:serve:production"
}
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**"
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
}
......@@ -136,4 +105,4 @@
}
},
"defaultProject": "xtss-catalogue"
}
\ No newline at end of file
}
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./src/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.e2e.json')
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};
\ No newline at end of file
import { AppPage } from './app.po';
import { browser, logging } from 'protractor';
describe('workspace-project App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getTitleText()).toEqual('Welcome to xtss-catalogue!');
});
afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
expect(logs).not.toContain(jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry));
});
});
import { browser, by, element } from 'protractor';
export class AppPage {
navigateTo() {
return browser.get(browser.baseUrl) as Promise<any>;
}
getTitleText() {
return element(by.css('app-root h1')).getText() as Promise<string>;
}
}
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}
\ No newline at end of file
This diff is collapsed.
......@@ -9,7 +9,6 @@
"test-headless": "ng test --watch=false --browsers=ChromiumHeadless",
"test-docker": "ng test --watch=false --browsers=ChromiumDocker",
"lint": "ng lint",
"e2e": "ng e2e",
"sonar": "sonar-scanner"
},
"private": true,
......@@ -32,13 +31,23 @@
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.1100.2",
"@angular-eslint/builder": "0.8.0-beta.1",
"@angular-eslint/eslint-plugin": "0.8.0-beta.1",
"@angular-eslint/eslint-plugin-template": "0.8.0-beta.1",
"@angular-eslint/template-parser": "0.8.0-beta.1",
"@angular/cli": "~11.0.2",
"@angular/compiler-cli": "^11.0.2",
"@angular/language-service": "^11.0.2",
"@types/jasmine": "~3.6.0",
"@types/jasminewd2": "^2.0.8",
"@types/node": "^12.11.1",
"@typescript-eslint/eslint-plugin": "4.3.0",
"@typescript-eslint/parser": "4.3.0",
"codelyzer": "^6.0.0",
"eslint": "^7.6.0",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-jsdoc": "30.7.6",
"eslint-plugin-prefer-arrow": "1.2.2",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~5.0.0",
"karma": "~5.0.0",
......@@ -49,7 +58,6 @@
"protractor": "~7.0.0",
"sonar-scanner": "^3.1.0",
"ts-node": "~7.0.0",
"tslint": "~6.1.0",
"typescript": "~4.0.5"
}
}
// We mock configuration file that has different naming convention
/* eslint-disable @typescript-eslint/naming-convention */
import { Injectable } from '@angular/core';
import { AppConfig } from './app.config';
......
......@@ -15,12 +15,14 @@ describe('AppConfig', () => {
});
it('should load configuration', async () => {
// eslint-disable-next-line @typescript-eslint/naming-convention
httpClientSpy.get.and.returnValue(of({TEST: 'OK'}));
await config.load();
expect(httpClientSpy.get).toHaveBeenCalledWith('./assets/config.json');
});
it('getConfig should work', async () => {
// eslint-disable-next-line @typescript-eslint/naming-convention
httpClientSpy.get.and.returnValue(of({TEST: 'OK'}));
await config.load();
expect(config.getConfig('TEST')).toBe('OK');
......
......@@ -33,7 +33,8 @@ import { MessagesComponent } from './messages/messages.component';
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
// Providing path as a workaround for ngx-translate bug with --base-href option
useFactory: (http: HttpClient) => new TranslateHttpLoader(http, './assets/i18n/'),
deps: [HttpClient]
}
})
......@@ -45,8 +46,3 @@ import { MessagesComponent } from './messages/messages.component';
bootstrap: [AppComponent]
})
export class AppModule { }
export function HttpLoaderFactory(http: HttpClient) {
// Providing path as a workaround for ngx-translate bug with --base-href option
return new TranslateHttpLoader(http, './assets/i18n/');
}
......@@ -7,7 +7,7 @@ import { SubsystemsService } from '../../subsystems.service';
})
export class SearchComponent implements OnInit {
limit: string;
limits: object;
limits: Map<string, number>;
nonEmpty: boolean;
filter: string;
......
......@@ -13,6 +13,8 @@ import { SearchComponent } from './search/search.component';
templateUrl: './subsystem-list.component.html'
})
export class SubsystemListComponent implements OnInit, AfterViewInit, OnDestroy {
@ViewChild(SearchComponent, { static: true }) search;
message: string;
scrollSubject: BehaviorSubject<any> = new BehaviorSubject(null);
routerScrollSubscription: Subscription;
......@@ -23,8 +25,6 @@ export class SubsystemListComponent implements OnInit, AfterViewInit, OnDestroy
instanceVersions: BehaviorSubject<InstanceVersion[]>;
instanceVersion: string;
@ViewChild(SearchComponent, { static: true }) search;
constructor(
private subsystemsService: SubsystemsService,
private route: ActivatedRoute,
......
......@@ -15,6 +15,7 @@ export class SubsystemComponent implements OnInit, AfterViewInit, OnDestroy {
message = '';
// Contains instance from route.params (for displaying warning)
paramsInstance = '';
subsystemSubject: BehaviorSubject<Subsystem> = new BehaviorSubject(null);
private scrollSubject: BehaviorSubject<any> = new BehaviorSubject(null);
private routerScrollSubscription: Subscription;
private routeSubscription: Subscription;
......@@ -22,7 +23,6 @@ export class SubsystemComponent implements OnInit, AfterViewInit, OnDestroy {
private scrollSubjectSubscription: Subscription;
private subsystemsSubscription: Subscription;
private instanceVersion: string;
subsystemSubject: BehaviorSubject<Subsystem> = new BehaviorSubject(null);
constructor(
private subsystemsService: SubsystemsService,
......@@ -40,12 +40,6 @@ export class SubsystemComponent implements OnInit, AfterViewInit, OnDestroy {
});
}
private getSubsystem(subsystems: Subsystem[], name: string): Subsystem {
return subsystems.find((element) => {
return element.fullSubsystemName === name;
});
}
getInstance(): string {
return this.subsystemsService.getInstance();
}
......@@ -126,4 +120,8 @@ export class SubsystemComponent implements OnInit, AfterViewInit, OnDestroy {
this.subsystemsSubscription.unsubscribe();
}
}
private getSubsystem(subsystems: Subsystem[], name: string): Subsystem {
return subsystems.find((element) => element.fullSubsystemName === name);
}
}
......@@ -12,19 +12,18 @@ import { InstanceVersion } from './instance-version';
providedIn: 'root'
})
export class SubsystemsService {
subsystemsSubject: BehaviorSubject<Subsystem[]> = new BehaviorSubject([]);
filteredSubsystemsSubject: BehaviorSubject<Subsystem[]> = new BehaviorSubject([]);
instanceVersionsSubject: BehaviorSubject<InstanceVersion[]> = new BehaviorSubject([]);
warnings: EventEmitter<string> = new EventEmitter();
private apiUrlBase = '';
private limit: number = this.config.getConfig('DEFAULT_LIMIT');
private nonEmpty = false;
private filter = '';
private instance = '';
private instanceVersion = '';
subsystemsSubject: BehaviorSubject<Subsystem[]> = new BehaviorSubject([]);
filteredSubsystemsSubject: BehaviorSubject<Subsystem[]> = new BehaviorSubject([]);
instanceVersionsSubject: BehaviorSubject<InstanceVersion[]> = new BehaviorSubject([]);
private updateFilter = new Subject<string>();
warnings: EventEmitter<string> = new EventEmitter();
constructor(
private http: HttpClient,
private config: AppConfig
......@@ -38,92 +37,6 @@ export class SubsystemsService {
});
}
private filteredSubsystems(): Subsystem[] {
const filtered: Subsystem[] = [];
let limit: number = this.limit;
for (let subsystem of this.subsystemsSubject.value) {
if (this.nonEmpty && !subsystem.methods.length && !subsystem.services.length) {
// Filtering out empty subsystems
continue;
}
if (
this.filter !== ''
&& !subsystem.methods.length
&& !subsystem.services.length
) {
// Subsystem without methods and services
if (subsystem.fullSubsystemName.toLowerCase().indexOf(this.filter.toLowerCase()) < 0) {
// Subsystem name does not match the filter
continue;
}
} else if (this.filter !== '') {
// Subsystem with methods and/or services
const filteredMethods: Method[] = [];
for (const method of subsystem.methods) {
if (method.fullMethodName.toLowerCase().indexOf(this.filter.toLowerCase()) >= 0) {
filteredMethods.push(method);
}
}
const filteredServices: Service[] = [];
for (const service of subsystem.services) {
if (service.fullServiceName.toLowerCase().indexOf(this.filter.toLowerCase()) >= 0) {
filteredServices.push(service);
}
}
if (!filteredMethods.length && !filteredServices.length) {
// No matching method and/or services names found
continue;
}
// Copy object to avoid overwriting methods array in subsystem object
subsystem = Object.assign(Object.create(subsystem), subsystem);
// Leaving only matcing methods and services
subsystem.methods = filteredMethods;
subsystem.services = filteredServices;
}
filtered.push(subsystem);
limit -= 1;
if (limit === 0) {
break;
}
}
return filtered;
}
private setFullNames(subsystems: Subsystem[]): Subsystem[] {
for (const subsystem of subsystems) {
subsystem.fullSubsystemName = subsystem.xRoadInstance
+ '/' + subsystem.memberClass
+ '/' + subsystem.memberCode
+ '/' + subsystem.subsystemCode;
for (const method of subsystem.methods) {
method.fullMethodName = subsystem.fullSubsystemName
+ '/' + method.serviceCode
+ '/' + method.serviceVersion;
}
if (!subsystem.servicesStatus) {
// Fix missing data in previous versions
subsystem.servicesStatus = 'ERROR';
}
if (!subsystem.services) {
// Fix missing data in previous versions
subsystem.services = [];
}
for (const service of subsystem.services) {
service.fullServiceName = subsystem.fullSubsystemName
+ '/' + service.serviceCode;
}
}
return subsystems;
}
private emitWarning(msg: string) {
this.warnings.emit(msg);
}
private updateFiltered() {
this.filteredSubsystemsSubject.next(this.filteredSubsystems());
}
getDefaultInstance(): string {
return Object.keys(this.config.getConfig('INSTANCES'))[0];
}
......@@ -161,10 +74,8 @@ export class SubsystemsService {
this.instanceVersionsSubject.next([]);
this.http.get<InstanceVersion[]>(this.apiUrlBase + this.config.getConfig('API_HISTORY'))
.pipe(
catchError(() => {
// Let the app keep running by returning an empty result.
return of([]);
})
// Let the app keep running by returning an empty result.
catchError(() => of([]))
).subscribe(history => {
const versions: InstanceVersion[] = [];
for (const version of history) {
......@@ -205,7 +116,7 @@ export class SubsystemsService {
return this.limit.toString();
}
getLimits(): object {
getLimits(): Map<string, number> {
return this.config.getConfig('LIMITS');
}
......@@ -253,4 +164,90 @@ export class SubsystemsService {
getInstanceVersion(): string {
return this.instanceVersion;
}
private filteredSubsystems(): Subsystem[] {
const filtered: Subsystem[] = [];
let limit: number = this.limit;
for (let subsystem of this.subsystemsSubject.value) {
if (this.nonEmpty && !subsystem.methods.length && !subsystem.services.length) {
// Filtering out empty subsystems
continue;
}
if (
this.filter !== ''
&& !subsystem.methods.length
&& !subsystem.services.length
) {
// Subsystem without methods and services
if (subsystem.fullSubsystemName.toLowerCase().indexOf(this.filter.toLowerCase()) < 0) {
// Subsystem name does not match the filter
continue;
}
} else if (this.filter !== '') {
// Subsystem with methods and/or services
const filteredMethods: Method[] = [];
for (const method of subsystem.methods) {
if (method.fullMethodName.toLowerCase().indexOf(this.filter.toLowerCase()) >= 0) {
filteredMethods.push(method);
}
}
const filteredServices: Service[] = [];
for (const service of subsystem.services) {
if (service.fullServiceName.toLowerCase().indexOf(this.filter.toLowerCase()) >= 0) {
filteredServices.push(service);
}
}
if (!filteredMethods.length && !filteredServices.length) {
// No matching method and/or services names found
continue;
}
// Copy object to avoid overwriting methods array in subsystem object
subsystem = Object.assign(Object.create(subsystem), subsystem);
// Leaving only matcing methods and services
subsystem.methods = filteredMethods;
subsystem.services = filteredServices;
}
filtered.push(subsystem);
limit -= 1;
if (limit === 0) {
break;
}
}
return filtered;
}
private setFullNames(subsystems: Subsystem[]): Subsystem[] {
for (const subsystem of subsystems) {
subsystem.fullSubsystemName = subsystem.xRoadInstance
+ '/' + subsystem.memberClass
+ '/' + subsystem.memberCode
+ '/' + subsystem.subsystemCode;
for (const method of subsystem.methods) {
method.fullMethodName = subsystem.fullSubsystemName
+ '/' + method.serviceCode
+ '/' + method.serviceVersion;
}
if (!subsystem.servicesStatus) {
// Fix missing data in previous versions
subsystem.servicesStatus = 'ERROR';
}
if (!subsystem.services) {
// Fix missing data in previous versions
subsystem.services = [];
}
for (const service of subsystem.services) {
service.fullServiceName = subsystem.fullSubsystemName
+ '/' + service.serviceCode;
}
}
return subsystems;
}
private emitWarning(msg: string) {
this.warnings.emit(msg);
}
private updateFiltered() {
this.filteredSubsystemsSubject.next(this.filteredSubsystems());
}
}
{
"extends": "../tslint.json",
"rules": {
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
]
}
}
{
"extends": "tslint:recommended",
"rulesDirectory": [
"codelyzer"
],
"rules": {
"align": {
"options": [
"parameters",
"statements"
]
},
"array-type": false,
"arrow-parens": false,
"arrow-return-shorthand": true,
"deprecation": {
"severity": "warn"
},
"curly": true,
"import-blacklist": [
true,
"rxjs/Rx"
],
"interface-name": false,
"eofline": true,
"max-classes-per-file": false,
"import-spacing": true,
"indent": {
"options": [
"spaces"
]
},
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-consecutive-blank-lines": false,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-empty": false,
"no-inferrable-types": [