aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Timeline/ClientApp/src/app/app.component.ts9
-rw-r--r--Timeline/ClientApp/src/app/test-utilities/activated-route.mock.ts66
-rw-r--r--Timeline/ClientApp/src/app/todo/todo-service/http-entities.ts11
-rw-r--r--Timeline/ClientApp/src/app/todo/todo-service/todo.service.spec.ts8
-rw-r--r--Timeline/ClientApp/src/app/todo/todo-service/todo.service.ts14
-rw-r--r--Timeline/ClientApp/src/app/user/entities.ts9
-rw-r--r--Timeline/ClientApp/src/app/user/internal-user-service/errors.ts25
-rw-r--r--Timeline/ClientApp/src/app/user/internal-user-service/http-entities.ts20
-rw-r--r--Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.mock.ts5
-rw-r--r--Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.spec.ts116
-rw-r--r--Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.ts96
-rw-r--r--Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.html7
-rw-r--r--Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.spec.ts86
-rw-r--r--Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.ts47
-rw-r--r--Timeline/ClientApp/src/app/user/user-info.ts4
-rw-r--r--Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.spec.ts40
-rw-r--r--Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.ts12
-rw-r--r--Timeline/ClientApp/src/app/user/user-login/user-login.component.spec.ts75
-rw-r--r--Timeline/ClientApp/src/app/user/user-login/user-login.component.ts25
-rw-r--r--Timeline/ClientApp/src/app/user/user-service/user.service.spec.ts114
-rw-r--r--Timeline/ClientApp/src/app/user/user-service/user.service.ts116
-rw-r--r--Timeline/ClientApp/src/app/user/user.module.ts11
-rw-r--r--Timeline/ClientApp/src/app/user/user.service.ts33
-rw-r--r--Timeline/ClientApp/src/app/utilities/debounce-click.directive.spec.ts (renamed from Timeline/ClientApp/src/app/utility/debounce-click.directive.spec.ts)0
-rw-r--r--Timeline/ClientApp/src/app/utilities/debounce-click.directive.ts (renamed from Timeline/ClientApp/src/app/utility/debounce-click.directive.ts)0
-rw-r--r--Timeline/ClientApp/src/app/utilities/utility.module.ts (renamed from Timeline/ClientApp/src/app/utility/utility.module.ts)0
-rw-r--r--Timeline/ClientApp/src/tsconfig.app.json4
-rw-r--r--Timeline/ClientApp/src/tsconfig.spec.json4
-rw-r--r--Timeline/ClientApp/yarn.lock472
29 files changed, 807 insertions, 622 deletions
diff --git a/Timeline/ClientApp/src/app/app.component.ts b/Timeline/ClientApp/src/app/app.component.ts
index 0e2a9799..ee02f833 100644
--- a/Timeline/ClientApp/src/app/app.component.ts
+++ b/Timeline/ClientApp/src/app/app.component.ts
@@ -1,6 +1,5 @@
import { Component } from '@angular/core';
-import { MatDialog } from '@angular/material';
-import { UserDialogComponent } from './user/user-dialog/user-dialog.component';
+import { UserService } from './user/user.service';
@Component({
selector: 'app-root',
@@ -9,11 +8,9 @@ import { UserDialogComponent } from './user/user-dialog/user-dialog.component';
})
export class AppComponent {
- constructor(private dialog: MatDialog) { }
+ constructor(private userService: UserService) { }
openUserDialog() {
- this.dialog.open(UserDialogComponent, {
- width: '300px'
- });
+ this.userService.openUserDialog();
}
}
diff --git a/Timeline/ClientApp/src/app/test-utilities/activated-route.mock.ts b/Timeline/ClientApp/src/app/test-utilities/activated-route.mock.ts
new file mode 100644
index 00000000..1743e615
--- /dev/null
+++ b/Timeline/ClientApp/src/app/test-utilities/activated-route.mock.ts
@@ -0,0 +1,66 @@
+import { ParamMap } from '@angular/router';
+
+import { Observable, BehaviorSubject } from 'rxjs';
+import { map } from 'rxjs/operators';
+
+export interface ParamMapCreator { [name: string]: string | string[]; }
+
+export class MockActivatedRouteSnapshot {
+
+ private paramMapInternal: ParamMap;
+
+ constructor({ mockParamMap }: { mockParamMap: ParamMapCreator } = { mockParamMap: {} }) {
+ this.paramMapInternal = {
+ keys: Object.keys(mockParamMap),
+ get(name: string): string | null {
+ const param = mockParamMap[name];
+ if (typeof param === 'string') {
+ return param;
+ } else if (param instanceof Array) {
+ if (param.length === 0) {
+ return null;
+ }
+ return param[0];
+ }
+ return null;
+ },
+ getAll(name: string): string[] {
+ const param = mockParamMap[name];
+ if (typeof param === 'string') {
+ return [param];
+ } else if (param instanceof Array) {
+ return param;
+ }
+ return [];
+ },
+ has(name: string): boolean {
+ return mockParamMap.hasOwnProperty(name);
+ }
+ };
+ }
+
+ get paramMap(): ParamMap {
+ return this.paramMapInternal;
+ }
+}
+
+export class MockActivatedRoute {
+
+ snapshot$ = new BehaviorSubject<MockActivatedRouteSnapshot>(new MockActivatedRouteSnapshot());
+
+ get paramMap(): Observable<ParamMap> {
+ return this.snapshot$.pipe(map(snapshot => snapshot.paramMap));
+ }
+
+ get snapshot(): MockActivatedRouteSnapshot {
+ return this.snapshot$.value;
+ }
+
+ pushSnapshot(snapshot: MockActivatedRouteSnapshot) {
+ this.snapshot$.next(snapshot);
+ }
+
+ pushSnapshotWithParamMap(mockParamMap: ParamMapCreator) {
+ this.pushSnapshot(new MockActivatedRouteSnapshot({mockParamMap}));
+ }
+}
diff --git a/Timeline/ClientApp/src/app/todo/todo-service/http-entities.ts b/Timeline/ClientApp/src/app/todo/todo-service/http-entities.ts
new file mode 100644
index 00000000..3971617c
--- /dev/null
+++ b/Timeline/ClientApp/src/app/todo/todo-service/http-entities.ts
@@ -0,0 +1,11 @@
+export const githubBaseUrl = 'https://api.github.com/repos/crupest/Timeline';
+
+export interface IssueResponseItem {
+ number: number;
+ title: string;
+ state: string;
+ html_url: string;
+ pull_request?: any;
+}
+
+export type IssueResponse = IssueResponseItem[];
diff --git a/Timeline/ClientApp/src/app/todo/todo-service/todo.service.spec.ts b/Timeline/ClientApp/src/app/todo/todo-service/todo.service.spec.ts
index b0b35f7b..679dc8b7 100644
--- a/Timeline/ClientApp/src/app/todo/todo-service/todo.service.spec.ts
+++ b/Timeline/ClientApp/src/app/todo/todo-service/todo.service.spec.ts
@@ -3,7 +3,8 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/
import { toArray } from 'rxjs/operators';
import { TodoItem } from '../todo-item';
-import { TodoService, IssueResponse } from './todo.service';
+import { TodoService } from './todo.service';
+import { IssueResponse, githubBaseUrl } from './http-entities';
describe('TodoService', () => {
@@ -19,8 +20,6 @@ describe('TodoService', () => {
it('should work well', () => {
const service: TodoService = TestBed.get(TodoService);
- const baseUrl = service.baseUrl;
-
const mockIssueList: IssueResponse = [{
number: 1,
title: 'Issue title 1',
@@ -47,7 +46,8 @@ describe('TodoService', () => {
const httpController: HttpTestingController = TestBed.get(HttpTestingController);
- httpController.expectOne(request => request.url === baseUrl + '/issues' && request.params.get('state') === 'all').flush(mockIssueList);
+ httpController.expectOne(request => request.url === githubBaseUrl + '/issues' &&
+ request.params.get('state') === 'all').flush(mockIssueList);
httpController.verify();
});
diff --git a/Timeline/ClientApp/src/app/todo/todo-service/todo.service.ts b/Timeline/ClientApp/src/app/todo/todo-service/todo.service.ts
index ed1f2cbe..df63636d 100644
--- a/Timeline/ClientApp/src/app/todo/todo-service/todo.service.ts
+++ b/Timeline/ClientApp/src/app/todo/todo-service/todo.service.ts
@@ -3,29 +3,19 @@ import { HttpClient } from '@angular/common/http';
import { Observable, from } from 'rxjs';
import { switchMap, map, filter } from 'rxjs/operators';
+import { IssueResponse, githubBaseUrl } from './http-entities';
import { TodoItem } from '../todo-item';
-export interface IssueResponseItem {
- number: number;
- title: string;
- state: string;
- html_url: string;
- pull_request?: any;
-}
-
-export type IssueResponse = IssueResponseItem[];
@Injectable({
providedIn: 'root'
})
export class TodoService {
- readonly baseUrl = 'https://api.github.com/repos/crupest/Timeline';
-
constructor(private client: HttpClient) { }
getWorkItemList(): Observable<TodoItem> {
- return this.client.get<IssueResponse>(`${this.baseUrl}/issues`, {
+ return this.client.get<IssueResponse>(`${githubBaseUrl}/issues`, {
params: {
state: 'all'
}
diff --git a/Timeline/ClientApp/src/app/user/entities.ts b/Timeline/ClientApp/src/app/user/entities.ts
new file mode 100644
index 00000000..6d432ec6
--- /dev/null
+++ b/Timeline/ClientApp/src/app/user/entities.ts
@@ -0,0 +1,9 @@
+export interface UserCredentials {
+ username: string;
+ password: string;
+}
+
+export interface UserInfo {
+ username: string;
+ roles: string[];
+}
diff --git a/Timeline/ClientApp/src/app/user/internal-user-service/errors.ts b/Timeline/ClientApp/src/app/user/internal-user-service/errors.ts
new file mode 100644
index 00000000..22e44dd6
--- /dev/null
+++ b/Timeline/ClientApp/src/app/user/internal-user-service/errors.ts
@@ -0,0 +1,25 @@
+export abstract class LoginError extends Error { }
+
+export class BadNetworkError extends LoginError {
+ constructor() {
+ super('Network is bad.');
+ }
+}
+
+export class AlreadyLoginError extends LoginError {
+ constructor() {
+ super('Internal logical error. There is already a token saved. Please call validateUserLoginState first.');
+ }
+}
+
+export class BadCredentialsError extends LoginError {
+ constructor() {
+ super('Username or password is wrong.');
+ }
+}
+
+export class UnknownError extends LoginError {
+ constructor(public internalError?: any) {
+ super('Sorry, unknown error occured!');
+ }
+}
diff --git a/Timeline/ClientApp/src/app/user/internal-user-service/http-entities.ts b/Timeline/ClientApp/src/app/user/internal-user-service/http-entities.ts
new file mode 100644
index 00000000..5664cf7c
--- /dev/null
+++ b/Timeline/ClientApp/src/app/user/internal-user-service/http-entities.ts
@@ -0,0 +1,20 @@
+import { UserCredentials, UserInfo } from '../entities';
+
+export const createTokenUrl = '/api/User/CreateToken';
+export const validateTokenUrl = '/api/User/ValidateToken';
+
+export type CreateTokenRequest = UserCredentials;
+
+export interface CreateTokenResponse {
+ token: string;
+ userInfo: UserInfo;
+}
+
+export interface ValidateTokenRequest {
+ token: string;
+}
+
+export interface ValidateTokenResponse {
+ isValid: boolean;
+ userInfo?: UserInfo;
+}
diff --git a/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.mock.ts b/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.mock.ts
new file mode 100644
index 00000000..f4a85262
--- /dev/null
+++ b/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.mock.ts
@@ -0,0 +1,5 @@
+import { InternalUserService } from './internal-user.service';
+
+export function createMockInternalUserService(): jasmine.SpyObj<InternalUserService> {
+ return jasmine.createSpyObj('InternalUserService', ['userRouteNavigate', 'refreshAndGetUserState', 'tryLogin']);
+}
diff --git a/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.spec.ts b/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.spec.ts
new file mode 100644
index 00000000..4db28768
--- /dev/null
+++ b/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.spec.ts
@@ -0,0 +1,116 @@
+import { TestBed } from '@angular/core/testing';
+import { HttpRequest } from '@angular/common/http';
+import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
+import { Router } from '@angular/router';
+
+import { UserInfo, UserCredentials } from '../entities';
+import {
+ createTokenUrl, validateTokenUrl, CreateTokenRequest,
+ CreateTokenResponse, ValidateTokenRequest, ValidateTokenResponse
+} from './http-entities';
+import { InternalUserService, UserLoginState } from './internal-user.service';
+
+describe('InternalUserService', () => {
+ const mockUserCredentials: UserCredentials = {
+ username: 'user',
+ password: 'user'
+ };
+
+ beforeEach(() => TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [{ provide: Router, useValue: null }]
+ }));
+
+ it('should be created', () => {
+ const service: InternalUserService = TestBed.get(InternalUserService);
+ expect(service).toBeTruthy();
+ });
+
+ it('should be nologin at first', () => {
+ const service: InternalUserService = TestBed.get(InternalUserService);
+ expect(service.currentUserInfo).toBe(null);
+ service.refreshAndGetUserState().subscribe(result => {
+ expect(result).toBe('nologin');
+ });
+ });
+
+ it('login should work well', () => {
+ const service: InternalUserService = TestBed.get(InternalUserService);
+
+ const mockUserInfo: UserInfo = {
+ username: 'user',
+ roles: ['user', 'other']
+ };
+
+ service.tryLogin(mockUserCredentials).subscribe(result => {
+ expect(result).toEqual(mockUserInfo);
+ });
+
+ const httpController = TestBed.get(HttpTestingController) as HttpTestingController;
+
+ httpController.expectOne((request: HttpRequest<CreateTokenRequest>) =>
+ request.url === createTokenUrl &&
+ request.body.username === 'user' &&
+ request.body.password === 'user').flush(<CreateTokenResponse>{
+ token: 'test-token',
+ userInfo: mockUserInfo
+ });
+
+ expect(service.currentUserInfo).toEqual(mockUserInfo);
+
+ httpController.verify();
+ });
+
+ describe('validateUserLoginState', () => {
+ let service: InternalUserService;
+ let httpController: HttpTestingController;
+
+ const mockUserInfo: UserInfo = {
+ username: 'user',
+ roles: ['user', 'other']
+ };
+
+ const mockToken = 'mock-token';
+
+ const tokenValidateRequestMatcher = (req: HttpRequest<ValidateTokenRequest>) => {
+ return req.url === validateTokenUrl && req.body.token === mockToken;
+ };
+
+ beforeEach(() => {
+ service = TestBed.get(InternalUserService);
+ httpController = TestBed.get(HttpTestingController);
+
+ service.tryLogin(mockUserCredentials).subscribe(); // subscribe to activate login
+
+ httpController.expectOne(createTokenUrl).flush(<CreateTokenResponse>{
+ token: mockToken,
+ userInfo: mockUserInfo
+ });
+ });
+
+ it('success should work well', () => {
+ service.refreshAndGetUserState().subscribe((result: UserLoginState) => {
+ expect(result).toEqual(<UserLoginState>'success');
+ });
+
+ httpController.expectOne(tokenValidateRequestMatcher).flush(<ValidateTokenResponse>{
+ isValid: true,
+ userInfo: mockUserInfo
+ });
+
+ httpController.verify();
+ });
+
+ it('invalid should work well', () => {
+ service.refreshAndGetUserState().subscribe((result: UserLoginState) => {
+ expect(result).toEqual(<UserLoginState>'invalidlogin');
+ });
+
+ httpController.expectOne(tokenValidateRequestMatcher).flush(<ValidateTokenResponse>{ isValid: false });
+
+ httpController.verify();
+ });
+ });
+
+ // TODO: test on error situations.
+});
diff --git a/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.ts b/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.ts
new file mode 100644
index 00000000..91a67e5b
--- /dev/null
+++ b/Timeline/ClientApp/src/app/user/internal-user-service/internal-user.service.ts
@@ -0,0 +1,96 @@
+import { Injectable } from '@angular/core';
+import { HttpClient, HttpErrorResponse } from '@angular/common/http';
+import { Router } from '@angular/router';
+
+import { Observable, of, throwError, BehaviorSubject } from 'rxjs';
+import { map, catchError, retry } from 'rxjs/operators';
+
+import { AlreadyLoginError, BadCredentialsError, BadNetworkError, UnknownError } from './errors';
+import {
+ createTokenUrl, validateTokenUrl, CreateTokenRequest,
+ CreateTokenResponse, ValidateTokenRequest, ValidateTokenResponse
+} from './http-entities';
+import { UserCredentials, UserInfo } from '../entities';
+
+
+export type UserLoginState = 'nologin' | 'invalidlogin' | 'success';
+
+/**
+ * This service is only used internal in user module.
+ */
+@Injectable({
+ providedIn: 'root'
+})
+export class InternalUserService {
+
+ private token: string;
+ private userInfoSubject = new BehaviorSubject<UserInfo | null>(null);
+
+ get currentUserInfo(): UserInfo | null {
+ return this.userInfoSubject.value;
+ }
+
+ get userInfo$(): Observable<UserInfo | null> {
+ return this.userInfoSubject;
+ }
+
+ constructor(private httpClient: HttpClient, private router: Router) { }
+
+ userRouteNavigate(commands: any[]) {
+ this.router.navigate([{
+ outlets: {
+ user: commands
+ }
+ }]);
+ }
+
+ refreshAndGetUserState(): Observable<UserLoginState> {
+ if (this.token === undefined || this.token === null) {
+ return of(<UserLoginState>'nologin');
+ }
+
+ return this.httpClient.post<ValidateTokenResponse>(validateTokenUrl, <ValidateTokenRequest>{ token: this.token }).pipe(
+ retry(3),
+ catchError(error => {
+ console.error('Failed to validate token.');
+ return throwError(error);
+ }),
+ map(result => {
+ if (result.isValid) {
+ this.userInfoSubject.next(result.userInfo);
+ return <UserLoginState>'success';
+ } else {
+ this.token = null;
+ this.userInfoSubject.next(null);
+ return <UserLoginState>'invalidlogin';
+ }
+ })
+ );
+ }
+
+ tryLogin(credentials: UserCredentials): Observable<UserInfo> {
+ if (this.token) {
+ return throwError(new AlreadyLoginError());
+ }
+
+ return this.httpClient.post<CreateTokenResponse>(createTokenUrl, <CreateTokenRequest>credentials).pipe(
+ catchError((error: HttpErrorResponse) => {
+ if (error.error instanceof ErrorEvent) {
+ console.error('An error occurred when login: ' + error.error.message);
+ return throwError(new BadNetworkError());
+ } else if (error.status === 400) {
+ console.error('An error occurred when login: wrong credentials.');
+ return throwError(new BadCredentialsError());
+ } else {
+ console.error('An unknown error occurred when login: ' + error);
+ return throwError(new UnknownError(error));
+ }
+ }),
+ map(result => {
+ this.token = result.token;
+ this.userInfoSubject.next(result.userInfo);
+ return result.userInfo;
+ })
+ );
+ }
+}
diff --git a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.html b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.html
index 50d6ba56..58dff0e4 100644
--- a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.html
+++ b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.html
@@ -1,5 +1,4 @@
-<div [ngSwitch]="state" class="container">
- <mat-progress-spinner *ngSwitchCase="'loading'" mode="indeterminate" diameter="50"></mat-progress-spinner>
- <app-user-login *ngSwitchCase="'login'" (login)="login($event)" [message]="loginMessage"></app-user-login>
- <app-user-login-success *ngSwitchCase="'success'" [userInfo]="userInfo" [displayLoginSuccessMessage]="displayLoginSuccessMessage"></app-user-login-success>
+<div class="container">
+ <mat-progress-spinner *ngIf="isLoading" mode="indeterminate" diameter="50"></mat-progress-spinner>
+ <router-outlet name="user"></router-outlet>
</div>
diff --git a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.spec.ts b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.spec.ts
index d24c0cd2..c56e1ed1 100644
--- a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.spec.ts
+++ b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.spec.ts
@@ -1,13 +1,13 @@
-import { Component, Output, EventEmitter } from '@angular/core';
+import { Component } from '@angular/core';
import { async, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
-import { of } from 'rxjs';
+import { Router, Event } from '@angular/router';
+import { of, Observable } from 'rxjs';
import { delay } from 'rxjs/operators';
-import { UserInfo } from '../user-info';
import { UserDialogComponent } from './user-dialog.component';
-import { UserService, UserLoginState } from '../user-service/user.service';
-import { LoginEvent } from '../user-login/user-login.component';
+import { createMockInternalUserService } from '../internal-user-service/internal-user.service.mock';
+import { InternalUserService, UserLoginState } from '../internal-user-service/internal-user.service';
@Component({
/* tslint:disable-next-line:component-selector*/
@@ -17,36 +17,30 @@ import { LoginEvent } from '../user-login/user-login.component';
class MatProgressSpinnerStubComponent { }
@Component({
- selector: 'app-user-login',
- /* tslint:disable-next-line:use-input-property-decorator*/
- inputs: ['message'],
+ /* tslint:disable-next-line:component-selector*/
+ selector: 'router-outlet',
template: ''
})
-class UserLoginStubComponent {
- @Output()
- login = new EventEmitter<LoginEvent>();
-}
+class RouterOutletStubComponent { }
-@Component({
- selector: 'app-user-login-success',
- /* tslint:disable-next-line:use-input-property-decorator*/
- inputs: ['userInfo', 'displayLoginSuccessMessage'],
- template: ''
-})
-class UserLoginSuccessStubComponent { }
describe('UserDialogComponent', () => {
let component: UserDialogComponent;
let fixture: ComponentFixture<UserDialogComponent>;
- let mockUserService: jasmine.SpyObj<UserService>;
+ let mockInternalUserService: jasmine.SpyObj<InternalUserService>;
+
beforeEach(async(() => {
- mockUserService = jasmine.createSpyObj('UserService', ['validateUserLoginState', 'tryLogin']);
+ mockInternalUserService = createMockInternalUserService();
TestBed.configureTestingModule({
- declarations: [UserDialogComponent, MatProgressSpinnerStubComponent,
- UserLoginStubComponent, UserLoginSuccessStubComponent],
- providers: [{ provide: UserService, useValue: mockUserService }]
+ declarations: [UserDialogComponent, MatProgressSpinnerStubComponent, RouterOutletStubComponent],
+ providers: [{ provide: InternalUserService, useValue: mockInternalUserService },
+ { // for the workaround
+ provide: Router, useValue: {
+ events: new Observable<Event>()
+ }
+ }]
})
.compileComponents();
}));
@@ -57,7 +51,7 @@ describe('UserDialogComponent', () => {
});
it('progress spinner should work well', fakeAsync(() => {
- mockUserService.validateUserLoginState.and.returnValue(of(<UserLoginState>{ state: 'nologin' }).pipe(delay(10)));
+ mockInternalUserService.refreshAndGetUserState.and.returnValue(of(<UserLoginState>'nologin').pipe(delay(10)));
fixture.detectChanges();
expect(fixture.debugElement.query(By.css('mat-progress-spinner'))).toBeTruthy();
tick(10);
@@ -66,49 +60,29 @@ describe('UserDialogComponent', () => {
}));
it('nologin should work well', () => {
- mockUserService.validateUserLoginState.and.returnValue(of(<UserLoginState>{ state: 'nologin' }));
+ mockInternalUserService.refreshAndGetUserState.and.returnValue(of(<UserLoginState>'nologin'));
fixture.detectChanges();
- expect(mockUserService.validateUserLoginState).toHaveBeenCalled();
- expect(fixture.debugElement.query(By.css('app-user-login'))).toBeTruthy();
- expect(fixture.debugElement.query(By.css('app-user-login-success'))).toBeFalsy();
+ expect(mockInternalUserService.refreshAndGetUserState).toHaveBeenCalled();
+ expect(mockInternalUserService.userRouteNavigate).toHaveBeenCalledWith(['login', { reason: 'nologin' }]);
});
- it('success should work well', () => {
- mockUserService.validateUserLoginState.and.returnValue(of(<UserLoginState>{ state: 'success', userInfo: {} }));
+ it('invalid login should work well', () => {
+ mockInternalUserService.refreshAndGetUserState.and.returnValue(of(<UserLoginState>'invalidlogin'));
fixture.detectChanges();
- expect(mockUserService.validateUserLoginState).toHaveBeenCalled();
- expect(fixture.debugElement.query(By.css('app-user-login'))).toBeFalsy();
- expect(fixture.debugElement.query(By.css('app-user-login-success'))).toBeTruthy();
+ expect(mockInternalUserService.refreshAndGetUserState).toHaveBeenCalled();
+ expect(mockInternalUserService.userRouteNavigate).toHaveBeenCalledWith(['login', { reason: 'invalidlogin' }]);
});
- it('login should work well', () => {
- mockUserService.validateUserLoginState.and.returnValue(of(<UserLoginState>{ state: 'nologin' }));
-
- fixture.detectChanges();
- expect(mockUserService.validateUserLoginState).toHaveBeenCalled();
- expect(fixture.debugElement.query(By.css('app-user-login'))).toBeTruthy();
- expect(fixture.debugElement.query(By.css('app-user-login-success'))).toBeFalsy();
-
- mockUserService.tryLogin.withArgs('user', 'user').and.returnValue(of(<UserInfo>{
- username: 'user',
- roles: ['user']
- }));
-
- (fixture.debugElement.query(By.css('app-user-login')).componentInstance as
- UserLoginStubComponent).login.emit(<LoginEvent>{
- username: 'user',
- password: 'user'
- });
+ it('success should work well', () => {
+ mockInternalUserService.refreshAndGetUserState.and.returnValue(of(<UserLoginState>'success'));
fixture.detectChanges();
- expect(mockUserService.tryLogin).toHaveBeenCalledWith('user', 'user');
-
- expect(fixture.debugElement.query(By.css('app-user-login'))).toBeFalsy();
- expect(fixture.debugElement.query(By.css('app-user-login-success'))).toBeTruthy();
+ expect(mockInternalUserService.refreshAndGetUserState).toHaveBeenCalled();
+ expect(mockInternalUserService.userRouteNavigate).toHaveBeenCalledWith(['success', { reason: 'already' }]);
});
});
diff --git a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.ts b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.ts
index 7511de16..498ffaa1 100644
--- a/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.ts
+++ b/Timeline/ClientApp/src/app/user/user-dialog/user-dialog.component.ts
@@ -1,43 +1,40 @@
-import { Component, OnInit } from '@angular/core';
-import { UserInfo } from '../user-info';
-import { UserService } from '../user-service/user.service';
-import { LoginEvent, LoginMessage } from '../user-login/user-login.component';
+import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
+import { InternalUserService } from '../internal-user-service/internal-user.service';
+import { RouterOutlet, Router, ActivationStart } from '@angular/router';
@Component({
selector: 'app-user-dialog',
templateUrl: './user-dialog.component.html',
styleUrls: ['./user-dialog.component.css']
})
-export class UserDialogComponent implements OnInit {
+export class UserDialogComponent implements OnInit, OnDestroy {
- constructor(private userService: UserService) { }
+ constructor(private userService: InternalUserService, private router: Router) { }
- state: 'loading' | 'login' | 'success' = 'loading';
+ @ViewChild(RouterOutlet) outlet: RouterOutlet;
- loginMessage: LoginMessage;
-
- displayLoginSuccessMessage = false;
- userInfo: UserInfo;
+ isLoading = true;
ngOnInit() {
- this.userService.validateUserLoginState().subscribe(result => {
- if (result.state === 'success') {
- this.userInfo = result.userInfo;
- this.state = 'success';
+ // this is a workaround for a bug. see https://github.com/angular/angular/issues/20694
+ this.router.events.subscribe(e => {
+ if (e instanceof ActivationStart && e.snapshot.outlet === 'user') {
+ this.outlet.deactivate();
+ }
+ });
+
+
+ this.userService.refreshAndGetUserState().subscribe(result => {
+ this.isLoading = false;
+ if (result === 'success') {
+ this.userService.userRouteNavigate(['success', { reason: 'already' }]);
} else {
- this.loginMessage = result.state;
- this.state = 'login';
+ this.userService.userRouteNavigate(['login', { reason: result }]);
}
});
}
- login(event: LoginEvent) {
- this.userService.tryLogin(event.username, event.password).subscribe(result => {
- this.userInfo = result;
- this.displayLoginSuccessMessage = true;
- this.state = 'success';
- }, (error: Error) => {
- this.loginMessage = error.message;
- });
+ ngOnDestroy() {
+ this.userService.userRouteNavigate(null);
}
}
diff --git a/Timeline/ClientApp/src/app/user/user-info.ts b/Timeline/ClientApp/src/app/user/user-info.ts
deleted file mode 100644
index 490b00ba..00000000
--- a/Timeline/ClientApp/src/app/user/user-info.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export interface UserInfo {
- username: string;
- roles: string[];
-}
diff --git a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.spec.ts b/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.spec.ts
index ba015ae6..1efbb5c7 100644
--- a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.spec.ts
+++ b/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.spec.ts
@@ -1,20 +1,39 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+import { ActivatedRoute } from '@angular/router';
+
+import { MockActivatedRoute } from 'src/app/test-utilities/activated-route.mock';
+import { createMockInternalUserService } from '../internal-user-service/internal-user.service.mock';
import { UserLoginSuccessComponent } from './user-login-success.component';
-import { By } from '@angular/platform-browser';
+import { InternalUserService } from '../internal-user-service/internal-user.service';
+
describe('UserLoginSuccessComponent', () => {
let component: UserLoginSuccessComponent;
let fixture: ComponentFixture<UserLoginSuccessComponent>;
+ let mockInternalUserService: jasmine.SpyObj<InternalUserService>;
+ let mockActivatedRoute: MockActivatedRoute;
+
const mockUserInfo = {
username: 'crupest',
roles: ['superman', 'coder']
};
beforeEach(async(() => {
+ mockInternalUserService = createMockInternalUserService();
+ mockActivatedRoute = new MockActivatedRoute();
+
+ // mock currentUserInfo property. because it only has a getter so cast it to any first.
+ (<any>mockInternalUserService).currentUserInfo = mockUserInfo;
+
TestBed.configureTestingModule({
- declarations: [UserLoginSuccessComponent]
+ declarations: [UserLoginSuccessComponent],
+ providers: [
+ { provide: InternalUserService, useValue: mockInternalUserService },
+ { provide: ActivatedRoute, useValue: mockActivatedRoute }
+ ]
})
.compileComponents();
}));
@@ -22,18 +41,29 @@ describe('UserLoginSuccessComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(UserLoginSuccessComponent);
component = fixture.componentInstance;
- component.userInfo = mockUserInfo;
- fixture.detectChanges();
});
it('should create', () => {
+ fixture.detectChanges();
expect(component).toBeTruthy();
});
- it('should work well', () => {
+ it('user info should work well', () => {
+ fixture.detectChanges();
+
+ expect((fixture.debugElement.query(By.css('p.login-success-message')))).toBeFalsy();
+
expect((fixture.debugElement.query(By.css('span.username')).nativeElement as HTMLSpanElement).textContent)
.toBe(mockUserInfo.username);
expect((fixture.debugElement.query(By.css('span.roles')).nativeElement as HTMLSpanElement).textContent)
.toBe(mockUserInfo.roles.join(', '));
});
+
+ it('login success message should display well', () => {
+ mockActivatedRoute.pushSnapshotWithParamMap({ reason: 'login' });
+
+ fixture.detectChanges();
+
+ expect((fixture.debugElement.query(By.css('p.login-success-message')))).toBeTruthy();
+ });
});
diff --git a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.ts b/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.ts
index 99de5970..48e331d6 100644
--- a/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.ts
+++ b/Timeline/ClientApp/src/app/user/user-login-success/user-login-success.component.ts
@@ -1,5 +1,8 @@
import { Component, OnInit, Input } from '@angular/core';
-import { UserInfo } from '../user-info';
+import { ActivatedRoute } from '@angular/router';
+
+import { UserInfo } from '../entities';
+import { InternalUserService } from '../internal-user-service/internal-user.service';
@Component({
selector: 'app-user-login-success',
@@ -8,15 +11,14 @@ import { UserInfo } from '../user-info';
})
export class UserLoginSuccessComponent implements OnInit {
- @Input()
displayLoginSuccessMessage = false;
- @Input()
userInfo: UserInfo;
- constructor() { }
+ constructor(private route: ActivatedRoute, private userService: InternalUserService) { }
ngOnInit() {
+ this.userInfo = this.userService.currentUserInfo;
+ this.displayLoginSuccessMessage = this.route.snapshot.paramMap.get('reason') === 'login';
}
-
}
diff --git a/Timeline/ClientApp/src/app/user/user-login/user-login.component.spec.ts b/Timeline/ClientApp/src/app/user/user-login/user-login.component.spec.ts
index acd13721..9c9ee1dc 100644
--- a/Timeline/ClientApp/src/app/user/user-login/user-login.component.spec.ts
+++ b/Timeline/ClientApp/src/app/user/user-login/user-login.component.spec.ts
@@ -1,17 +1,33 @@
import { NO_ERRORS_SCHEMA } from '@angular/core';
-import { async, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
+import { ActivatedRoute } from '@angular/router';
-import { UserLoginComponent, LoginEvent } from './user-login.component';
+import { of, throwError } from 'rxjs';
+
+import { createMockInternalUserService } from '../internal-user-service/internal-user.service.mock';
+import { MockActivatedRoute } from '../../test-utilities/activated-route.mock';
+import { UserLoginComponent } from './user-login.component';
+import { InternalUserService } from '../internal-user-service/internal-user.service';
+import { UserInfo } from '../entities';
describe('UserLoginComponent', () => {
let component: UserLoginComponent;
let fixture: ComponentFixture<UserLoginComponent>;
+ let mockInternalUserService: jasmine.SpyObj<InternalUserService>;
+ let mockActivatedRoute: MockActivatedRoute;
beforeEach(async(() => {
+ mockInternalUserService = createMockInternalUserService();
+ mockActivatedRoute = new MockActivatedRoute();
+
TestBed.configureTestingModule({
declarations: [UserLoginComponent],
+ providers: [
+ { provide: InternalUserService, useValue: mockInternalUserService },
+ { provide: ActivatedRoute, useValue: mockActivatedRoute }
+ ],
imports: [ReactiveFormsModule],
schemas: [NO_ERRORS_SCHEMA]
})
@@ -21,14 +37,16 @@ describe('UserLoginComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(UserLoginComponent);
component = fixture.componentInstance;
- fixture.detectChanges();
});
it('should create', () => {
+ fixture.detectChanges();
expect(component).toBeTruthy();
});
it('reactive form should work well', () => {
+ fixture.detectChanges();
+
const usernameInput = fixture.debugElement.query(By.css('input[type=text]')).nativeElement as HTMLInputElement;
const passwordInput = fixture.debugElement.query(By.css('input[type=password]')).nativeElement as HTMLInputElement;
@@ -45,16 +63,57 @@ describe('UserLoginComponent', () => {
});
});
- it('login event should work well', fakeAsync(() => {
- let userCredential: LoginEvent;
- component.login.subscribe((e: LoginEvent) => { userCredential = e; });
+ it('login should work well', () => {
fixture.detectChanges();
+
const mockValue = {
username: 'user',
password: 'user'
};
+
+ mockInternalUserService.tryLogin.withArgs(mockValue).and.returnValue(of(<UserInfo>{ username: 'user', roles: ['user'] }));
+
component.form.setValue(mockValue);
component.onLoginButtonClick();
- expect(userCredential).toEqual(mockValue);
- }));
+
+ expect(mockInternalUserService.tryLogin).toHaveBeenCalledWith(mockValue);
+ expect(mockInternalUserService.userRouteNavigate).toHaveBeenCalledWith(['success', { reason: 'login' }]);
+ });
+
+ describe('message display', () => {
+ it('nologin reason should display', () => {
+ mockActivatedRoute.pushSnapshotWithParamMap({ reason: 'nologin' });
+ fixture.detectChanges();
+ expect(component.message).toBe('nologin');
+ expect((fixture.debugElement.query(By.css('p.mat-body')).nativeElement as
+ HTMLParagraphElement).textContent).toBe('You haven\'t login.');
+ });
+
+ it('invalid login reason should display', () => {
+ mockActivatedRoute.pushSnapshotWithParamMap({ reason: 'invalidlogin' });
+ fixture.detectChanges();
+ expect(component.message).toBe('invalidlogin');
+ expect((fixture.debugElement.query(By.css('p.mat-body')).nativeElement as
+ HTMLParagraphElement).textContent).toBe('Your login is no longer valid.');
+ });
+
+ it('custom error message should display', () => {
+ const customMessage = 'custom message';
+
+ fixture.detectChanges();
+
+ const mockValue = {
+ username: 'user',
+ password: 'user'
+ };
+ mockInternalUserService.tryLogin.withArgs(mockValue).and.returnValue(throwError(new Error(customMessage)));
+ component.form.setValue(mockValue);
+ component.onLoginButtonClick();
+
+ fixture.detectChanges();
+ expect(component.message).toBe(customMessage);
+ expect((fixture.debugElement.query(By.css('p.mat-body')).nativeElement as
+ HTMLParagraphElement).textContent).toBe(customMessage);
+ });
+ });
});
diff --git a/Timeline/ClientApp/src/app/user/user-login/user-login.component.ts b/Timeline/ClientApp/src/app/user/user-login/user-login.component.ts
index da642cb8..79a788de 100644
--- a/Timeline/ClientApp/src/app/user/user-login/user-login.component.ts
+++ b/Timeline/ClientApp/src/app/user/user-login/user-login.component.ts
@@ -1,32 +1,35 @@
-import { Component, Output, OnInit, EventEmitter, Input } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
+import { ActivatedRoute } from '@angular/router';
+
+import { InternalUserService } from '../internal-user-service/internal-user.service';
export type LoginMessage = 'nologin' | 'invalidlogin' | string;
-export class LoginEvent {
- username: string;
- password: string;
-}
@Component({
selector: 'app-user-login',
templateUrl: './user-login.component.html',
styleUrls: ['./user-login.component.css']
})
-export class UserLoginComponent {
+export class UserLoginComponent implements OnInit {
- @Input()
- message: LoginMessage;
+ constructor(private route: ActivatedRoute, private userService: InternalUserService) { }
- @Output()
- login = new EventEmitter<LoginEvent>();
+ message: LoginMessage;
form = new FormGroup({
username: new FormControl(''),
password: new FormControl('')
});
+ ngOnInit() {
+ this.message = this.route.snapshot.paramMap.get('reason');
+ }
+
onLoginButtonClick() {
- this.login.emit(this.form.value);
+ this.userService.tryLogin(this.form.value).subscribe(_ => {
+ this.userService.userRouteNavigate(['success', { reason: 'login' }]);
+ }, (error: Error) => this.message = error.message);
}
}
diff --git a/Timeline/ClientApp/src/app/user/user-service/user.service.spec.ts b/Timeline/ClientApp/src/app/user/user-service/user.service.spec.ts
deleted file mode 100644
index 0095f031..00000000
--- a/Timeline/ClientApp/src/app/user/user-service/user.service.spec.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-import { TestBed } from '@angular/core/testing';
-import { HttpRequest } from '@angular/common/http';
-import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
-
-import { UserInfo } from '../user-info';
-import {
- UserService, UserCredentials, CreateTokenResult,
- UserLoginState, TokenValidationRequest, TokenValidationResult
-} from './user.service';
-
-describe('UserService', () => {
- const tokenCreateUrl = '/api/User/CreateToken';
-
- beforeEach(() => TestBed.configureTestingModule({
- imports: [HttpClientTestingModule]
- }));
-
- it('should be created', () => {
- const service: UserService = TestBed.get(UserService);
- expect(service).toBeTruthy();
- });
-
- it('should be nologin at first', () => {
- const service: UserService = TestBed.get(UserService);
- service.validateUserLoginState().subscribe(result => {
- expect(result.state).toBe('nologin');
- });
- });
-
- it('login should work well', () => {
- const service: UserService = TestBed.get(UserService);
-
- const mockUserInfo: UserInfo = {
- username: 'user',
- roles: ['user', 'other']
- };
-
- service.tryLogin('user', 'user').subscribe(result => {
- expect(result).toEqual(mockUserInfo);
- });
-
- const httpController = TestBed.get(HttpTestingController) as HttpTestingController;
-
- httpController.expectOne((request: HttpRequest<UserCredentials>) =>
- request.url === tokenCreateUrl &&
- request.body.username === 'user' &&
- request.body.password === 'user').flush(<CreateTokenResult>{
- token: 'test-token',
- userInfo: mockUserInfo
- });
-
- httpController.verify();
- });
-
- describe('validateUserLoginState', () => {
- let service: UserService;
- let httpController: HttpTestingController;
-
- const mockUserInfo: UserInfo = {
- username: 'user',
- roles: ['user', 'other']
- };
-
- const mockToken = 'mock-token';
-
- const tokenValidateRequestMatcher = (req: HttpRequest<TokenValidationRequest>) => {
- return req.url === '/api/User/ValidateToken' && req.body.token === mockToken;
- };
-
- beforeEach(() => {
- service = TestBed.get(UserService);
- httpController = TestBed.get(HttpTestingController);
-
- service.tryLogin('user', 'user').subscribe(); // subscribe to activate login
-
- httpController.expectOne(tokenCreateUrl).flush(<CreateTokenResult>{
- token: mockToken,
- userInfo: mockUserInfo
- });
- });
-
- it('success should work well', () => {
- service.validateUserLoginState().subscribe((result: UserLoginState) => {
- expect(result).toEqual(<UserLoginState>{
- state: 'success',
- userInfo: mockUserInfo
- });
- });
-
- httpController.expectOne(tokenValidateRequestMatcher).flush(<TokenValidationResult>{
- isValid: true,
- userInfo: mockUserInfo
- });
-
- httpController.verify();
- });
-
- it('invalid should work well', () => {
- service.validateUserLoginState().subscribe((result: UserLoginState) => {
- expect(result).toEqual(<UserLoginState>{
- state: 'invalidlogin'
- });
- });
-
- httpController.expectOne(tokenValidateRequestMatcher).flush(<TokenValidationResult>{
- isValid: false
- });
-
- httpController.verify();
- });
- });
-
- // TODO: test on error situations.
-});
diff --git a/Timeline/ClientApp/src/app/user/user-service/user.service.ts b/Timeline/ClientApp/src/app/user/user-service/user.service.ts
deleted file mode 100644
index 009e5292..00000000
--- a/Timeline/ClientApp/src/app/user/user-service/user.service.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-import { Injectable } from '@angular/core';
-import { HttpClient, HttpErrorResponse } from '@angular/common/http';
-import { Observable, of, throwError } from 'rxjs';
-import { map, catchError, retry } from 'rxjs/operators';
-
-import { UserInfo } from '../user-info';
-
-export interface UserCredentials {
- username: string;
- password: string;
-}
-
-export interface CreateTokenResult {
- token: string;
- userInfo: UserInfo;
-}
-
-export interface TokenValidationRequest {
- token: string;
-}
-
-export interface TokenValidationResult {
- isValid: boolean;
- userInfo?: UserInfo;
-}
-
-export interface UserLoginState {
- state: 'nologin' | 'invalidlogin' | 'success';
- userInfo?: UserInfo;
-}
-
-export class BadNetworkException extends Error {
- constructor() {
- super('Network is bad.');
- }
-}
-
-export class AlreadyLoginException extends Error {
- constructor() {
- super('There is already a token saved. Please call validateUserLoginState first.');
- }
-}
-
-export class BadCredentialsException extends Error {
- constructor() {
- super(`Username or password is wrong.`);
- }
-}
-
-@Injectable({
- providedIn: 'root'
-})
-export class UserService {
-
- private token: string;
- private userInfo: UserInfo;
-
- constructor(private httpClient: HttpClient) { }
-
- validateUserLoginState(): Observable<UserLoginState> {
- if (this.token === undefined || this.token === null) {
- return of(<UserLoginState>{ state: 'nologin' });
- }
-
- return this.httpClient.post<TokenValidationResult>('/api/User/ValidateToken', <TokenValidationRequest>{ token: this.token }).pipe(
- retry(3),
- catchError(error => {
- console.error('Failed to validate token.');
- return throwError(error);
- }),
- map(result => {
- if (result.isValid) {
- this.userInfo = result.userInfo;
- return <UserLoginState>{
- state: 'success',
- userInfo: result.userInfo
- };
- } else {
- this.token = null;
- this.userInfo = null;
- return <UserLoginState>{
- state: 'invalidlogin'
- };
- }
- })
- );
- }
-
- tryLogin(username: string, password: string): Observable<UserInfo> {
- if (this.token) {
- return throwError(new AlreadyLoginException());
- }
-
- return this.httpClient.post<CreateTokenResult>('/api/User/CreateToken', <UserCredentials>{
- username, password
- }).pipe(
- catchError((error: HttpErrorResponse) => {
- if (error.error instanceof ErrorEvent) {
- console.error('An error occurred when login: ' + error.error.message);
- return throwError(new BadNetworkException());
- } else if (error.status === 400) {
- console.error('An error occurred when login: wrong credentials.');
- return throwError(new BadCredentialsException());
- } else {
- console.error('An unknown error occurred when login: ' + error);
- return throwError(error);
- }
- }),
- map(result => {
- this.token = result.token;
- this.userInfo = result.userInfo;
- return result.userInfo;
- })
- );
- }
-}
diff --git a/Timeline/ClientApp/src/app/user/user.module.ts b/Timeline/ClientApp/src/app/user/user.module.ts
index 67de90a2..c399c9e0 100644
--- a/Timeline/ClientApp/src/app/user/user.module.ts
+++ b/Timeline/ClientApp/src/app/user/user.module.ts
@@ -10,15 +10,22 @@ import {
import { UserDialogComponent } from './user-dialog/user-dialog.component';
import { UserLoginComponent } from './user-login/user-login.component';
import { UserLoginSuccessComponent } from './user-login-success/user-login-success.component';
-import { UtilityModule } from '../utility/utility.module';
+import { UtilityModule } from '../utilities/utility.module';
+import { RouterModule } from '@angular/router';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
declarations: [UserDialogComponent, UserLoginComponent, UserLoginSuccessComponent],
imports: [
- CommonModule, HttpClientModule, ReactiveFormsModule,
+ RouterModule.forChild([
+ { path: 'login', component: UserLoginComponent, outlet: 'user' },
+ { path: 'success', component: UserLoginSuccessComponent, outlet: 'user' }
+ ]),
+ CommonModule, HttpClientModule, ReactiveFormsModule, BrowserAnimationsModule,
MatFormFieldModule, MatProgressSpinnerModule, MatDialogModule, MatInputModule, MatButtonModule,
UtilityModule
],
+ exports: [RouterModule],
entryComponents: [UserDialogComponent]
})
export class UserModule { }
diff --git a/Timeline/ClientApp/src/app/user/user.service.ts b/Timeline/ClientApp/src/app/user/user.service.ts
new file mode 100644
index 00000000..e876706c
--- /dev/null
+++ b/Timeline/ClientApp/src/app/user/user.service.ts
@@ -0,0 +1,33 @@
+import { Injectable } from '@angular/core';
+import { MatDialog } from '@angular/material';
+
+import { Observable } from 'rxjs';
+
+import { UserInfo } from './entities';
+import { InternalUserService } from './internal-user-service/internal-user.service';
+import { UserDialogComponent } from './user-dialog/user-dialog.component';
+
+
+/**
+ * This service provides public api of user module.
+ */
+@Injectable({
+ providedIn: 'root'
+})
+export class UserService {
+ constructor(private dialog: MatDialog, private internalService: InternalUserService) { }
+
+ get currentUserInfo(): UserInfo | null {
+ return this.internalService.currentUserInfo;
+ }
+
+ get userInfo$(): Observable<UserInfo | null> {
+ return this.internalService.userInfo$;
+ }
+
+ openUserDialog() {
+ this.dialog.open(UserDialogComponent, {
+ width: '300px'
+ });
+ }
+}
diff --git a/Timeline/ClientApp/src/app/utility/debounce-click.directive.spec.ts b/Timeline/ClientApp/src/app/utilities/debounce-click.directive.spec.ts
index 75710d0c..75710d0c 100644
--- a/Timeline/ClientApp/src/app/utility/debounce-click.directive.spec.ts
+++ b/Timeline/ClientApp/src/app/utilities/debounce-click.directive.spec.ts
diff --git a/Timeline/ClientApp/src/app/utility/debounce-click.directive.ts b/Timeline/ClientApp/src/app/utilities/debounce-click.directive.ts
index feb0404e..feb0404e 100644
--- a/Timeline/ClientApp/src/app/utility/debounce-click.directive.ts
+++ b/Timeline/ClientApp/src/app/utilities/debounce-click.directive.ts
diff --git a/Timeline/ClientApp/src/app/utility/utility.module.ts b/Timeline/ClientApp/src/app/utilities/utility.module.ts
index dd686bf7..dd686bf7 100644
--- a/Timeline/ClientApp/src/app/utility/utility.module.ts
+++ b/Timeline/ClientApp/src/app/utilities/utility.module.ts
diff --git a/Timeline/ClientApp/src/tsconfig.app.json b/Timeline/ClientApp/src/tsconfig.app.json
index 722c370d..13151ca4 100644
--- a/Timeline/ClientApp/src/tsconfig.app.json
+++ b/Timeline/ClientApp/src/tsconfig.app.json
@@ -7,6 +7,8 @@
},
"exclude": [
"src/test.ts",
- "**/*.spec.ts"
+ "**/*.spec.ts",
+ "**/*.mock.ts",
+ "**/*.test.ts"
]
}
diff --git a/Timeline/ClientApp/src/tsconfig.spec.json b/Timeline/ClientApp/src/tsconfig.spec.json
index 8f7cedec..6e4460f8 100644
--- a/Timeline/ClientApp/src/tsconfig.spec.json
+++ b/Timeline/ClientApp/src/tsconfig.spec.json
@@ -14,6 +14,8 @@
],
"include": [
"**/*.spec.ts",
- "**/*.d.ts"
+ "**/*.d.ts",
+ "**/*.mock.ts",
+ "**/*.test.ts"
]
}
diff --git a/Timeline/ClientApp/yarn.lock b/Timeline/ClientApp/yarn.lock
index fcb3c00f..cd6328eb 100644
--- a/Timeline/ClientApp/yarn.lock
+++ b/Timeline/ClientApp/yarn.lock
@@ -10,12 +10,12 @@
"@angular-devkit/core" "7.2.4"
rxjs "6.3.3"
-"@angular-devkit/architect@0.13.3":
- version "0.13.3"
- resolved "http://registry.npm.taobao.org/@angular-devkit/architect/download/@angular-devkit/architect-0.13.3.tgz#28813279c546cdcb709ad55038bb2051736de668"
- integrity sha1-KIEyecVGzctwmtVQOLsgUXNt5mg=
+"@angular-devkit/architect@0.13.5":
+ version "0.13.5"
+ resolved "http://registry.npm.taobao.org/@angular-devkit/architect/download/@angular-devkit/architect-0.13.5.tgz#ecd41e3bc37337b9b8884cebc761a367b06cb697"
+ integrity sha1-7NQeO8NzN7m4iEzrx2GjZ7Bstpc=
dependencies:
- "@angular-devkit/core" "7.3.3"
+ "@angular-devkit/core" "7.3.5"
rxjs "6.3.3"
"@angular-devkit/build-angular@^0.12.3":
@@ -102,10 +102,10 @@
rxjs "6.3.3"
source-map "0.7.3"
-"@angular-devkit/core@7.3.3":
- version "7.3.3"
- resolved "http://registry.npm.taobao.org/@angular-devkit/core/download/@angular-devkit/core-7.3.3.tgz#cd6d5a8eca25ef07b6394bc2b08133d90d08d39f"
- integrity sha1-zW1ajsol7we2OUvCsIEz2Q0I058=
+"@angular-devkit/core@7.3.5":
+ version "7.3.5"
+ resolved "http://registry.npm.taobao.org/@angular-devkit/core/download/@angular-devkit/core-7.3.5.tgz#2a59a913eab358e2385f52ba28132b81435e63b3"
+ integrity sha1-KlmpE+qzWOI4X1K6KBMrgUNeY7M=
dependencies:
ajv "6.9.1"
chokidar "2.0.4"
@@ -113,18 +113,18 @@
rxjs "6.3.3"
source-map "0.7.3"
-"@angular-devkit/schematics@7.3.3":
- version "7.3.3"
- resolved "http://registry.npm.taobao.org/@angular-devkit/schematics/download/@angular-devkit/schematics-7.3.3.tgz#80e9dc3197a3181f32edfb5c07e7ac016eace7d3"
- integrity sha1-gOncMZejGB8y7ftcB+esAW6s59M=
+"@angular-devkit/schematics@7.3.5":
+ version "7.3.5"
+ resolved "http://registry.npm.taobao.org/@angular-devkit/schematics/download/@angular-devkit/schematics-7.3.5.tgz#7b007f8a86dea76e93eef007d4fb6e7d8324b7bb"
+ integrity sha1-ewB/iobep26T7vAH1PtufYMkt7s=
dependencies:
- "@angular-devkit/core" "7.3.3"
+ "@angular-devkit/core" "7.3.5"
rxjs "6.3.3"
"@angular/animations@^7.2.4":
- version "7.2.6"
- resolved "http://registry.npm.taobao.org/@angular/animations/download/@angular/animations-7.2.6.tgz#5153d68da7f7dd08e26490f72f97679a93e78f34"
- integrity sha1-UVPWjaf33QjiZJD3L5dnmpPnjzQ=
+ version "7.2.8"
+ resolved "http://registry.npm.taobao.org/@angular/animations/download/@angular/animations-7.2.8.tgz#0285364c839c660a934ab0f753ec21424bfb292e"
+ integrity sha1-AoU2TIOcZgqTSrD3U+whQkv7KS4=
dependencies:
tslib "^1.9.0"
@@ -138,15 +138,15 @@
parse5 "^5.0.0"
"@angular/cli@^7.3.1":
- version "7.3.3"
- resolved "http://registry.npm.taobao.org/@angular/cli/download/@angular/cli-7.3.3.tgz#b357000385aa6c75b001cb9fa7982ef3ce02c423"
- integrity sha1-s1cAA4WqbHWwAcufp5gu884CxCM=
- dependencies:
- "@angular-devkit/architect" "0.13.3"
- "@angular-devkit/core" "7.3.3"
- "@angular-devkit/schematics" "7.3.3"
- "@schematics/angular" "7.3.3"
- "@schematics/update" "0.13.3"
+ version "7.3.5"
+ resolved "http://registry.npm.taobao.org/@angular/cli/download/@angular/cli-7.3.5.tgz#7aa0294410e0a9ae18b9e686803d9b0997d8c5fa"
+ integrity sha1-eqApRBDgqa4YueaGgD2bCZfYxfo=
+ dependencies:
+ "@angular-devkit/architect" "0.13.5"
+ "@angular-devkit/core" "7.3.5"
+ "@angular-devkit/schematics" "7.3.5"
+ "@schematics/angular" "7.3.5"
+ "@schematics/update" "0.13.5"
"@yarnpkg/lockfile" "1.1.0"
ini "1.3.5"
inquirer "6.2.1"
@@ -157,16 +157,16 @@
symbol-observable "1.2.0"
"@angular/common@^7.2.4":
- version "7.2.6"
- resolved "http://registry.npm.taobao.org/@angular/common/download/@angular/common-7.2.6.tgz#876aaf1f9021807b306faba39334b30917f4c3a8"
- integrity sha1-h2qvH5AhgHswb6ujkzSzCRf0w6g=
+ version "7.2.8"
+ resolved "http://registry.npm.taobao.org/@angular/common/download/@angular/common-7.2.8.tgz#660c816b6f08cd2919a6efb7465397e4ff14d265"
+ integrity sha1-ZgyBa28IzSkZpu+3RlOX5P8U0mU=
dependencies:
tslib "^1.9.0"
"@angular/compiler-cli@^7.2.4":
- version "7.2.6"
- resolved "http://registry.npm.taobao.org/@angular/compiler-cli/download/@angular/compiler-cli-7.2.6.tgz#50c4d2fed21292b40b7e14d20a2133312a09d2cd"
- integrity sha1-UMTS/tISkrQLfhTSCiEzMSoJ0s0=
+ version "7.2.8"
+ resolved "http://registry.npm.taobao.org/@angular/compiler-cli/download/@angular/compiler-cli-7.2.8.tgz#167d106ea002a580e1ed0651e9bcce87e4e14fb3"
+ integrity sha1-Fn0QbqACpYDh7QZR6bzOh+ThT7M=
dependencies:
canonical-path "1.0.0"
chokidar "^2.1.1"
@@ -181,37 +181,37 @@
yargs "9.0.1"
"@angular/compiler@^7.2.4":
- version "7.2.6"
- resolved "http://registry.npm.taobao.org/@angular/compiler/download/@angular/compiler-7.2.6.tgz#c1047f0be52d19f39239b0f3ff9a85caf759c855"
- integrity sha1-wQR/C+UtGfOSObDz/5qFyvdZyFU=
+ version "7.2.8"
+ resolved "http://registry.npm.taobao.org/@angular/compiler/download/@angular/compiler-7.2.8.tgz#9d9c1515e99914399e6915c1c90484b1d255560b"
+ integrity sha1-nZwVFemZFDmeaRXByQSEsdJVVgs=
dependencies:
tslib "^1.9.0"
"@angular/core@^7.2.4":
- version "7.2.6"
- resolved "http://registry.npm.taobao.org/@angular/core/download/@angular/core-7.2.6.tgz#0142bba2b08d6b49811e12d04cb50586f9c5a1f0"
- integrity sha1-AUK7orCNa0mBHhLQTLUFhvnFofA=
+ version "7.2.8"
+ resolved "http://registry.npm.taobao.org/@angular/core/download/@angular/core-7.2.8.tgz#6586d9b6c6321c80119b3f3e2bd0edbb32d0b649"
+ integrity sha1-ZYbZtsYyHIARmz8+K9DtuzLQtkk=
dependencies:
tslib "^1.9.0"
"@angular/forms@^7.2.4":
- version "7.2.6"
- resolved "http://registry.npm.taobao.org/@angular/forms/download/@angular/forms-7.2.6.tgz#4db5238a5aa462927be29c90bc60ce4585ed939f"
- integrity sha1-TbUjilqkYpJ74pyQvGDORYXtk58=
+ version "7.2.8"
+ resolved "http://registry.npm.taobao.org/@angular/forms/download/@angular/forms-7.2.8.tgz#adf194088495822d55dcf3e5bf69196dcf19465d"
+ integrity sha1-rfGUCISVgi1V3PPlv2kZbc8ZRl0=
dependencies:
tslib "^1.9.0"
"@angular/http@^7.2.4":
- version "7.2.6"
- resolved "http://registry.npm.taobao.org/@angular/http/download/@angular/http-7.2.6.tgz#13cdddb561bc54d98efa5279221707eca064f5ae"
- integrity sha1-E83dtWG8VNmO+lJ5IhcH7KBk9a4=
+ version "7.2.8"
+ resolved "http://registry.npm.taobao.org/@angular/http/download/@angular/http-7.2.8.tgz#bba2ca9c80d3475c4e3fb47427fdfd25f6969241"
+ integrity sha1-u6LKnIDTR1xOP7R0J/39JfaWkkE=
dependencies:
tslib "^1.9.0"
"@angular/language-service@^7.2.4":
- version "7.2.6"
- resolved "http://registry.npm.taobao.org/@angular/language-service/download/@angular/language-service-7.2.6.tgz#cc4fc6427667c57f3745de889d30bd751bb4c325"
- integrity sha1-zE/GQnZnxX83Rd6InTC9dRu0wyU=
+ version "7.2.8"
+ resolved "http://registry.npm.taobao.org/@angular/language-service/download/@angular/language-service-7.2.8.tgz#f08d50cd24c294441d8ebf0d4050c439f6ae86dc"
+ integrity sha1-8I1QzSTClEQdjr8NQFDEOfauhtw=
"@angular/material@^7.3.2":
version "7.3.3"
@@ -221,32 +221,32 @@
tslib "^1.7.1"
"@angular/platform-browser-dynamic@^7.2.4":
- version "7.2.6"
- resolved "http://registry.npm.taobao.org/@angular/platform-browser-dynamic/download/@angular/platform-browser-dynamic-7.2.6.tgz#3a1cc79b40a1ab487cf035ca679f21b406677c09"
- integrity sha1-OhzHm0Chq0h88DXKZ58htAZnfAk=
+ version "7.2.8"
+ resolved "http://registry.npm.taobao.org/@angular/platform-browser-dynamic/download/@angular/platform-browser-dynamic-7.2.8.tgz#e82768900cedfa75bf453263f931a9f90f7aaab2"
+ integrity sha1-6CdokAzt+nW/RTJj+TGp+Q96qrI=
dependencies:
tslib "^1.9.0"
"@angular/platform-browser@^7.2.4":
- version "7.2.6"
- resolved "http://registry.npm.taobao.org/@angular/platform-browser/download/@angular/platform-browser-7.2.6.tgz#7587dfc60c3af77943c0343658e770f706017f7a"
- integrity sha1-dYffxgw693lDwDQ2WOdw9wYBf3o=
+ version "7.2.8"
+ resolved "http://registry.npm.taobao.org/@angular/platform-browser/download/@angular/platform-browser-7.2.8.tgz#11096727b99bf3d7fd82a00a3a468b933c9713bd"
+ integrity sha1-EQlnJ7mb89f9gqAKOkaLkzyXE70=
dependencies:
tslib "^1.9.0"
"@angular/platform-server@^7.2.4":
- version "7.2.6"
- resolved "http://registry.npm.taobao.org/@angular/platform-server/download/@angular/platform-server-7.2.6.tgz#5fa02d8ae6723da234230292f61f33fb3e80a325"
- integrity sha1-X6AtiuZyPaI0IwKS9h8z+z6AoyU=
+ version "7.2.8"
+ resolved "http://registry.npm.taobao.org/@angular/platform-server/download/@angular/platform-server-7.2.8.tgz#b6a83bbe92613a689989524cbff5613d33bd06b1"
+ integrity sha1-tqg7vpJhOmiZiVJMv/VhPTO9BrE=
dependencies:
domino "^2.1.0"
tslib "^1.9.0"
xhr2 "^0.1.4"
"@angular/router@^7.2.4":
- version "7.2.6"
- resolved "http://registry.npm.taobao.org/@angular/router/download/@angular/router-7.2.6.tgz#d469384922ccc1c5d7e9d32d40e8855e67833149"
- integrity sha1-1Gk4SSLMwcXX6dMtQOiFXmeDMUk=
+ version "7.2.8"
+ resolved "http://registry.npm.taobao.org/@angular/router/download/@angular/router-7.2.8.tgz#3ae38abd95cf045f5abd988e039b5253c979a094"
+ integrity sha1-OuOKvZXPBF9avZiOA5tSU8l5oJQ=
dependencies:
tslib "^1.9.0"
@@ -257,12 +257,12 @@
dependencies:
"@babel/highlight" "^7.0.0"
-"@babel/generator@^7.0.0", "@babel/generator@^7.2.2":
- version "7.3.3"
- resolved "http://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.3.3.tgz#185962ade59a52e00ca2bdfcfd1d58e528d4e39e"
- integrity sha1-GFlireWaUuAMor38/R1Y5SjU454=
+"@babel/generator@^7.0.0", "@babel/generator@^7.3.4":
+ version "7.3.4"
+ resolved "http://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.3.4.tgz#9aa48c1989257877a9d971296e5b73bfe72e446e"
+ integrity sha1-mqSMGYkleHep2XEpbltzv+cuRG4=
dependencies:
- "@babel/types" "^7.3.3"
+ "@babel/types" "^7.3.4"
jsesc "^2.5.1"
lodash "^4.17.11"
source-map "^0.5.0"
@@ -300,10 +300,10 @@
esutils "^2.0.2"
js-tokens "^4.0.0"
-"@babel/parser@^7.0.0", "@babel/parser@^7.2.2", "@babel/parser@^7.2.3":
- version "7.3.3"
- resolved "http://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.3.3.tgz#092d450db02bdb6ccb1ca8ffd47d8774a91aef87"
- integrity sha1-CS1FDbAr22zLHKj/1H2HdKka74c=
+"@babel/parser@^7.0.0", "@babel/parser@^7.2.2", "@babel/parser@^7.3.4":
+ version "7.3.4"
+ resolved "http://registry.npm.taobao.org/@babel/parser/download/@babel/parser-7.3.4.tgz#a43357e4bbf4b92a437fb9e465c192848287f27c"
+ integrity sha1-pDNX5Lv0uSpDf7nkZcGShIKH8nw=
"@babel/template@^7.0.0", "@babel/template@^7.1.0":
version "7.2.2"
@@ -315,24 +315,24 @@
"@babel/types" "^7.2.2"
"@babel/traverse@^7.0.0":
- version "7.2.3"
- resolved "http://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.2.3.tgz#7ff50cefa9c7c0bd2d81231fdac122f3957748d8"
- integrity sha1-f/UM76nHwL0tgSMf2sEi85V3SNg=
+ version "7.3.4"
+ resolved "http://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.3.4.tgz#1330aab72234f8dea091b08c4f8b9d05c7119e06"
+ integrity sha1-EzCqtyI0+N6gkbCMT4udBccRngY=
dependencies:
"@babel/code-frame" "^7.0.0"
- "@babel/generator" "^7.2.2"
+ "@babel/generator" "^7.3.4"
"@babel/helper-function-name" "^7.1.0"
"@babel/helper-split-export-declaration" "^7.0.0"
- "@babel/parser" "^7.2.3"
- "@babel/types" "^7.2.2"
+ "@babel/parser" "^7.3.4"
+ "@babel/types" "^7.3.4"
debug "^4.1.0"
globals "^11.1.0"
- lodash "^4.17.10"
+ lodash "^4.17.11"
-"@babel/types@^7.0.0", "@babel/types@^7.2.2", "@babel/types@^7.3.3":
- version "7.3.3"
- resolved "http://registry.npm.taobao.org/@babel/types/download/@babel/types-7.3.3.tgz#6c44d1cdac2a7625b624216657d5bc6c107ab436"
- integrity sha1-bETRzawqdiW2JCFmV9W8bBB6tDY=
+"@babel/types@^7.0.0", "@babel/types@^7.2.2", "@babel/types@^7.3.4":
+ version "7.3.4"
+ resolved "http://registry.npm.taobao.org/@babel/types/download/@babel/types-7.3.4.tgz#bf482eaeaffb367a28abbf9357a94963235d90ed"
+ integrity sha1-v0gurq/7Nnooq7+TV6lJYyNdkO0=
dependencies:
esutils "^2.0.2"
lodash "^4.17.11"
@@ -350,26 +350,26 @@
webpack-sources "1.2.0"
"@nguniversal/module-map-ngfactory-loader@^7.1.0":
- version "7.1.0"
- resolved "http://registry.npm.taobao.org/@nguniversal/module-map-ngfactory-loader/download/@nguniversal/module-map-ngfactory-loader-7.1.0.tgz#70ea905c1b32c2edc484cb77aa7a3f3208069966"
- integrity sha1-cOqQXBsywu3EhMt3qno/MggGmWY=
+ version "7.1.1"
+ resolved "http://registry.npm.taobao.org/@nguniversal/module-map-ngfactory-loader/download/@nguniversal/module-map-ngfactory-loader-7.1.1.tgz#488a6f8c5890d44b7ad8468180919644a4d1a1ae"
+ integrity sha1-SIpvjFiQ1Et62EaBgJGWRKTRoa4=
-"@schematics/angular@7.3.3":
- version "7.3.3"
- resolved "http://registry.npm.taobao.org/@schematics/angular/download/@schematics/angular-7.3.3.tgz#aaa63331365bf67b1b908cc18cfc5d7097ec8377"
- integrity sha1-qqYzMTZb9nsbkIzBjPxdcJfsg3c=
+"@schematics/angular@7.3.5":
+ version "7.3.5"
+ resolved "http://registry.npm.taobao.org/@schematics/angular/download/@schematics/angular-7.3.5.tgz#7af1cd446b051b2be3fbe59cb4ba140ec06e2d87"
+ integrity sha1-evHNRGsFGyvj++WctLoUDsBuLYc=
dependencies:
- "@angular-devkit/core" "7.3.3"
- "@angular-devkit/schematics" "7.3.3"
+ "@angular-devkit/core" "7.3.5"
+ "@angular-devkit/schematics" "7.3.5"
typescript "3.2.4"
-"@schematics/update@0.13.3":
- version "0.13.3"
- resolved "http://registry.npm.taobao.org/@schematics/update/download/@schematics/update-0.13.3.tgz#7c325b1f723e538ed932b3e344a4a51ea123ffb7"
- integrity sha1-fDJbH3I+U47ZMrPjRKSlHqEj/7c=
+"@schematics/update@0.13.5":
+ version "0.13.5"
+ resolved "http://registry.npm.taobao.org/@schematics/update/download/@schematics/update-0.13.5.tgz#6019accecd2bca5efc931cc9832ecb234009ceb2"
+ integrity sha1-YBmszs0ryl78kxzJgy7LI0AJzrI=
dependencies:
- "@angular-devkit/core" "7.3.3"
- "@angular-devkit/schematics" "7.3.3"
+ "@angular-devkit/core" "7.3.5"
+ "@angular-devkit/schematics" "7.3.5"
"@yarnpkg/lockfile" "1.1.0"
ini "1.3.5"
pacote "9.4.0"
@@ -390,14 +390,14 @@
"@types/jasmine" "*"
"@types/node@*":
- version "11.9.4"
- resolved "http://registry.npm.taobao.org/@types/node/download/@types/node-11.9.4.tgz#ceb0048a546db453f6248f2d1d95e937a6f00a14"
- integrity sha1-zrAEilRttFP2JI8tHZXpN6bwChQ=
+ version "11.11.0"
+ resolved "http://registry.npm.taobao.org/@types/node/download/@types/node-11.11.0.tgz#070e9ce7c90e727aca0e0c14e470f9a93ffe9390"
+ integrity sha1-Bw6c58kOcnrKDgwU5HD5qT/+k5A=
"@types/node@^10.12.19":
- version "10.12.26"
- resolved "http://registry.npm.taobao.org/@types/node/download/@types/node-10.12.26.tgz#2dec19f1f7981c95cb54bab8f618ecb5dc983d0e"
- integrity sha1-LewZ8feYHJXLVLq49hjstdyYPQ4=
+ version "10.12.30"
+ resolved "http://registry.npm.taobao.org/@types/node/download/@types/node-10.12.30.tgz#4c2b4f0015f214f8158a347350481322b3b29b2f"
+ integrity sha1-TCtPABXyFPgVijRzUEgTIrOymy8=
"@types/q@^0.0.32":
version "0.0.32"
@@ -629,7 +629,7 @@ after@0.8.2:
resolved "http://registry.npm.taobao.org/after/download/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
-agent-base@4, agent-base@^4.1.0, agent-base@~4.2.0:
+agent-base@4, agent-base@^4.1.0, agent-base@~4.2.1:
version "4.2.1"
resolved "http://registry.npm.taobao.org/agent-base/download/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9"
integrity sha1-2J5ZmfeXh1Z0wH2H8mD8Qeg+jKk=
@@ -663,7 +663,7 @@ ajv@6.6.2:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
-ajv@6.9.1, ajv@^6.1.0, ajv@^6.5.5:
+ajv@6.9.1:
version "6.9.1"
resolved "http://registry.npm.taobao.org/ajv/download/ajv-6.9.1.tgz#a4d3683d74abc5670e75f0b16520f70a20ea8dc1"
integrity sha1-pNNoPXSrxWcOdfCxZSD3CiDqjcE=
@@ -683,15 +683,25 @@ ajv@^5.0.0:
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.3.0"
+ajv@^6.1.0, ajv@^6.5.5:
+ version "6.10.0"
+ resolved "http://registry.npm.taobao.org/ajv/download/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1"
+ integrity sha1-kNDVRDnaWHzX6EO/twRfUL0ivfE=
+ dependencies:
+ fast-deep-equal "^2.0.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
+
amdefine@>=0.0.4:
version "1.0.1"
resolved "http://registry.npm.taobao.org/amdefine/download/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=
ansi-colors@^3.0.0:
- version "3.2.3"
- resolved "http://registry.npm.taobao.org/ansi-colors/download/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813"
- integrity sha1-V9NbhoboUeLMBMQD8cACA5dqGBM=
+ version "3.2.4"
+ resolved "http://registry.npm.taobao.org/ansi-colors/download/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
+ integrity sha1-46PaS/uubIapwoViXeEkojQCb78=
ansi-escapes@^3.0.0:
version "3.2.0"
@@ -713,10 +723,10 @@ ansi-regex@^3.0.0:
resolved "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
-ansi-regex@^4.0.0:
- version "4.0.0"
- resolved "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9"
- integrity sha1-cN55Ht8CFATD/WFaqJEYrgQy5ak=
+ansi-regex@^4.1.0:
+ version "4.1.0"
+ resolved "http://registry.npm.taobao.org/ansi-regex/download/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
+ integrity sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=
ansi-styles@^2.2.1:
version "2.2.1"
@@ -800,11 +810,6 @@ array-flatten@^2.1.0:
resolved "http://registry.npm.taobao.org/array-flatten/download/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099"
integrity sha1-JO+AoowaiTYX4hSbDG0NeIKTsJk=
-array-slice@^0.2.3:
- version "0.2.3"
- resolved "http://registry.npm.taobao.org/array-slice/download/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5"
- integrity sha1-3Tz7gO15c6dRF82sabC5nshhhvU=
-
array-union@^1.0.1:
version "1.0.2"
resolved "http://registry.npm.taobao.org/array-union/download/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
@@ -817,11 +822,6 @@ array-uniq@^1.0.1:
resolved "http://registry.npm.taobao.org/array-uniq/download/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=
-array-unique@^0.2.1:
- version "0.2.1"
- resolved "http://registry.npm.taobao.org/array-unique/download/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
- integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=
-
array-unique@^0.3.2:
version "0.3.2"
resolved "http://registry.npm.taobao.org/array-unique/download/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
@@ -1157,13 +1157,6 @@ brace-expansion@^1.1.7:
balanced-match "^1.0.0"
concat-map "0.0.1"
-braces@^0.1.2:
- version "0.1.5"
- resolved "http://registry.npm.taobao.org/braces/download/braces-0.1.5.tgz#c085711085291d8b75fdd74eab0f8597280711e6"
- integrity sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=
- dependencies:
- expand-range "^0.1.0"
-
braces@^2.3.0, braces@^2.3.1, braces@^2.3.2:
version "2.3.2"
resolved "http://registry.npm.taobao.org/braces/download/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
@@ -1245,13 +1238,13 @@ browserify-zlib@^0.2.0:
pako "~1.0.5"
browserslist@^4.3.6:
- version "4.4.1"
- resolved "http://registry.npm.taobao.org/browserslist/download/browserslist-4.4.1.tgz#42e828954b6b29a7a53e352277be429478a69062"
- integrity sha1-QugolUtrKaelPjUid75ClHimkGI=
+ version "4.4.2"
+ resolved "http://registry.npm.taobao.org/browserslist/download/browserslist-4.4.2.tgz#6ea8a74d6464bb0bd549105f659b41197d8f0ba2"
+ integrity sha1-bqinTWRkuwvVSRBfZZtBGX2PC6I=
dependencies:
- caniuse-lite "^1.0.30000929"
- electron-to-chromium "^1.3.103"
- node-releases "^1.1.3"
+ caniuse-lite "^1.0.30000939"
+ electron-to-chromium "^1.3.113"
+ node-releases "^1.1.8"
browserstack@^1.5.1:
version "1.5.2"
@@ -1404,10 +1397,10 @@ camelcase@^4.1.0:
resolved "http://registry.npm.taobao.org/camelcase/download/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
-caniuse-lite@^1.0.30000921, caniuse-lite@^1.0.30000929:
- version "1.0.30000938"
- resolved "http://registry.npm.taobao.org/caniuse-lite/download/caniuse-lite-1.0.30000938.tgz#b64bf1427438df40183fce910fe24e34feda7a3f"
- integrity sha1-tkvxQnQ430AYP86RD+JONP7aej8=
+caniuse-lite@^1.0.30000921, caniuse-lite@^1.0.30000939:
+ version "1.0.30000942"
+ resolved "http://registry.npm.taobao.org/caniuse-lite/download/caniuse-lite-1.0.30000942.tgz#454139b28274bce70bfe1d50c30970df7430c6e4"
+ integrity sha1-RUE5soJ0vOcL/h1Qwwlw33QwxuQ=
canonical-path@1.0.0:
version "1.0.0"
@@ -1508,11 +1501,6 @@ circular-dependency-plugin@5.0.2:
resolved "http://registry.npm.taobao.org/circular-dependency-plugin/download/circular-dependency-plugin-5.0.2.tgz#da168c0b37e7b43563fb9f912c1c007c213389ef"
integrity sha1-2haMCzfntDVj+5+RLBwAfCEzie8=
-circular-json@^0.5.5:
- version "0.5.9"
- resolved "http://registry.npm.taobao.org/circular-json/download/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d"
- integrity sha1-kydjroj0996teg0JyKUaR0OlOx0=
-
class-utils@^0.3.5:
version "0.3.6"
resolved "http://registry.npm.taobao.org/class-utils/download/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
@@ -1627,13 +1615,6 @@ colors@^1.1.0:
resolved "http://registry.npm.taobao.org/colors/download/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d"
integrity sha1-OeAF1Uav4B4B+cTKj6UPaGoBIF0=
-combine-lists@^1.0.0:
- version "1.0.1"
- resolved "http://registry.npm.taobao.org/combine-lists/download/combine-lists-1.0.1.tgz#458c07e09e0d900fc28b70a3fec2dacd1d2cb7f6"
- integrity sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=
- dependencies:
- lodash "^4.5.0"
-
combined-stream@^1.0.6, combined-stream@~1.0.6:
version "1.0.7"
resolved "http://registry.npm.taobao.org/combined-stream/download/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828"
@@ -1947,10 +1928,10 @@ dashdash@^1.12.0:
dependencies:
assert-plus "^1.0.0"
-date-format@^1.2.0:
- version "1.2.0"
- resolved "http://registry.npm.taobao.org/date-format/download/date-format-1.2.0.tgz#615e828e233dd1ab9bb9ae0950e0ceccfa6ecad8"
- integrity sha1-YV6CjiM90aubua4JUODOzPpuytg=
+date-format@^2.0.0:
+ version "2.0.0"
+ resolved "http://registry.npm.taobao.org/date-format/download/date-format-2.0.0.tgz#7cf7b172f1ec564f0003b39ea302c5498fb98c8f"
+ integrity sha1-fPexcvHsVk8AA7OeowLFSY+5jI8=
date-now@^0.1.4:
version "0.1.4"
@@ -2205,9 +2186,9 @@ domain-task@^3.0.0:
isomorphic-fetch "^2.2.1"
domino@^2.1.0:
- version "2.1.2"
- resolved "http://registry.npm.taobao.org/domino/download/domino-2.1.2.tgz#70e8367839ee8ad8bde3aeb4857cf3d93bd98b85"
- integrity sha1-cOg2eDnuiti94660hXzz2TvZi4U=
+ version "2.1.3"
+ resolved "http://registry.npm.taobao.org/domino/download/domino-2.1.3.tgz#0ca1ad02cbd316ebe2e99e0ac9fb0010407d4601"
+ integrity sha1-DKGtAsvTFuvi6Z4KyfsAEEB9RgE=
duplexify@^3.4.2, duplexify@^3.6.0:
version "3.7.1"
@@ -2232,7 +2213,7 @@ ee-first@1.1.1:
resolved "http://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
-electron-to-chromium@^1.3.103:
+electron-to-chromium@^1.3.113:
version "1.3.113"
resolved "http://registry.npm.taobao.org/electron-to-chromium/download/electron-to-chromium-1.3.113.tgz#b1ccf619df7295aea17bc6951dc689632629e4a9"
integrity sha1-scz2Gd9yla6he8aVHcaJYyYp5Kk=
@@ -2382,9 +2363,9 @@ escodegen@1.8.x:
source-map "~0.2.0"
eslint-scope@^4.0.0:
- version "4.0.0"
- resolved "http://registry.npm.taobao.org/eslint-scope/download/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172"
- integrity sha1-UL8wcekzi83EMzF5Sgy1M/ATYXI=
+ version "4.0.2"
+ resolved "http://registry.npm.taobao.org/eslint-scope/download/eslint-scope-4.0.2.tgz#5f10cd6cabb1965bf479fa65745673439e21cb0e"
+ integrity sha1-XxDNbKuxllv0efpldFZzQ54hyw4=
dependencies:
esrecurse "^4.1.0"
estraverse "^4.1.1"
@@ -2495,15 +2476,6 @@ exit@^0.1.2:
resolved "http://registry.npm.taobao.org/exit/download/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=
-expand-braces@^0.1.1:
- version "0.1.2"
- resolved "http://registry.npm.taobao.org/expand-braces/download/expand-braces-0.1.2.tgz#488b1d1d2451cb3d3a6b192cfc030f44c5855fea"
- integrity sha1-SIsdHSRRyz06axks/AMPRMWFX+o=
- dependencies:
- array-slice "^0.2.3"
- array-unique "^0.2.1"
- braces "^0.1.2"
-
expand-brackets@^2.1.4:
version "2.1.4"
resolved "http://registry.npm.taobao.org/expand-brackets/download/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
@@ -2517,14 +2489,6 @@ expand-brackets@^2.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
-expand-range@^0.1.0:
- version "0.1.1"
- resolved "http://registry.npm.taobao.org/expand-range/download/expand-range-0.1.1.tgz#4cb8eda0993ca56fa4f41fc42f3cbb4ccadff044"
- integrity sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=
- dependencies:
- is-number "^0.1.1"
- repeat-string "^0.2.2"
-
express@^4.16.2:
version "4.16.4"
resolved "http://registry.npm.taobao.org/express/download/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e"
@@ -2840,6 +2804,15 @@ fs-access@^1.0.0:
dependencies:
null-check "^1.0.0"
+fs-extra@^7.0.0:
+ version "7.0.1"
+ resolved "http://registry.npm.taobao.org/fs-extra/download/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
+ integrity sha1-TxicRKoSO4lfcigE9V6iPq3DSOk=
+ dependencies:
+ graceful-fs "^4.1.2"
+ jsonfile "^4.0.0"
+ universalify "^0.1.0"
+
fs-minipass@^1.2.5:
version "1.2.5"
resolved "http://registry.npm.taobao.org/fs-minipass/download/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d"
@@ -3037,7 +3010,7 @@ globule@^1.0.0:
lodash "~4.17.10"
minimatch "~3.0.2"
-graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2:
+graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
version "4.1.15"
resolved "http://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
integrity sha1-/7cD4QZuig7qpMi4C6klPu77+wA=
@@ -3567,11 +3540,6 @@ is-glob@^4.0.0:
dependencies:
is-extglob "^2.1.1"
-is-number@^0.1.1:
- version "0.1.1"
- resolved "http://registry.npm.taobao.org/is-number/download/is-number-0.1.1.tgz#69a7af116963d47206ec9bd9b48a14216f1e3806"
- integrity sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=
-
is-number@^3.0.0:
version "3.0.0"
resolved "http://registry.npm.taobao.org/is-number/download/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
@@ -3848,9 +3816,9 @@ js-tokens@^3.0.2:
integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
js-yaml@3.x, js-yaml@^3.12.0, js-yaml@^3.7.0, js-yaml@^3.9.0:
- version "3.12.1"
- resolved "http://registry.npm.taobao.org/js-yaml/download/js-yaml-3.12.1.tgz#295c8632a18a23e054cf5c9d3cecafe678167600"
- integrity sha1-KVyGMqGKI+BUz1ydPOyv5ngWdgA=
+ version "3.12.2"
+ resolved "http://registry.npm.taobao.org/js-yaml/download/js-yaml-3.12.2.tgz#ef1d067c5a9d9cb65bd72f285b5d8105c77f14fc"
+ integrity sha1-7x0GfFqdnLZb1y8oW12BBcd/FPw=
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
@@ -3917,6 +3885,13 @@ json5@^1.0.1:
dependencies:
minimist "^1.2.0"
+jsonfile@^4.0.0:
+ version "4.0.0"
+ resolved "http://registry.npm.taobao.org/jsonfile/download/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
+ integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
+ optionalDependencies:
+ graceful-fs "^4.1.6"
+
jsonparse@^1.2.0:
version "1.3.1"
resolved "http://registry.npm.taobao.org/jsonparse/download/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
@@ -3986,27 +3961,26 @@ karma-source-map-support@1.3.0:
source-map-support "^0.5.5"
karma@^4.0.0:
- version "4.0.0"
- resolved "http://registry.npm.taobao.org/karma/download/karma-4.0.0.tgz#f28e38a2b66243fde3f98e12a8dcaa2c6ff8ca9c"
- integrity sha1-8o44orZiQ/3j+Y4SqNyqLG/4ypw=
+ version "4.0.1"
+ resolved "http://registry.npm.taobao.org/karma/download/karma-4.0.1.tgz#2581d6caa0d4cd28b65131561b47bad6d5478773"
+ integrity sha1-JYHWyqDUzSi2UTFWG0e61tVHh3M=
dependencies:
bluebird "^3.3.0"
body-parser "^1.16.1"
+ braces "^2.3.2"
chokidar "^2.0.3"
colors "^1.1.0"
- combine-lists "^1.0.0"
connect "^3.6.0"
core-js "^2.2.0"
di "^0.0.1"
dom-serialize "^2.2.0"
- expand-braces "^0.1.1"
flatted "^2.0.0"
glob "^7.1.1"
graceful-fs "^4.1.2"
http-proxy "^1.13.0"
isbinaryfile "^3.0.0"
- lodash "^4.17.5"
- log4js "^3.0.0"
+ lodash "^4.17.11"
+ log4js "^4.0.0"
mime "^2.3.1"
minimatch "^3.0.2"
optimist "^0.6.1"
@@ -4195,21 +4169,21 @@ lodash.tail@^4.1.1:
resolved "http://registry.npm.taobao.org/lodash.tail/download/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664"
integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=
-lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.5.0, lodash@~4.17.10:
+lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10:
version "4.17.11"
resolved "http://registry.npm.taobao.org/lodash/download/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
integrity sha1-s56mIp72B+zYniyN8SU2iRysm40=
-log4js@^3.0.0:
- version "3.0.6"
- resolved "http://registry.npm.taobao.org/log4js/download/log4js-3.0.6.tgz#e6caced94967eeeb9ce399f9f8682a4b2b28c8ff"
- integrity sha1-5srO2Uln7uuc45n5+GgqSysoyP8=
+log4js@^4.0.0:
+ version "4.0.2"
+ resolved "http://registry.npm.taobao.org/log4js/download/log4js-4.0.2.tgz#0c73e623ca4448669653eb0e9f629beacc7fbbe3"
+ integrity sha1-DHPmI8pESGaWU+sOn2Kb6sx/u+M=
dependencies:
- circular-json "^0.5.5"
- date-format "^1.2.0"
+ date-format "^2.0.0"
debug "^3.1.0"
+ flatted "^2.0.0"
rfdc "^1.1.2"
- streamroller "0.7.0"
+ streamroller "^1.0.1"
loglevel@^1.4.1:
version "1.6.1"
@@ -4711,10 +4685,10 @@ node-pre-gyp@^0.10.0:
semver "^5.3.0"
tar "^4"
-node-releases@^1.1.3:
- version "1.1.8"
- resolved "http://registry.npm.taobao.org/node-releases/download/node-releases-1.1.8.tgz#32a63fff63c5e51b7e0f540ac95947d220fc6862"
- integrity sha1-MqY//2PF5Rt+D1QKyVlH0iD8aGI=
+node-releases@^1.1.8:
+ version "1.1.10"
+ resolved "http://registry.npm.taobao.org/node-releases/download/node-releases-1.1.10.tgz#5dbeb6bc7f4e9c85b899e2e7adcc0635c9b2adf7"
+ integrity sha1-Xb62vH9OnIW4meLnrcwGNcmyrfc=
dependencies:
semver "^5.3.0"
@@ -5060,9 +5034,9 @@ p-limit@^1.0.0, p-limit@^1.1.0:
p-try "^1.0.0"
p-limit@^2.0.0:
- version "2.1.0"
- resolved "http://registry.npm.taobao.org/p-limit/download/p-limit-2.1.0.tgz#1d5a0d20fb12707c758a655f6bbc4386b5930d68"
- integrity sha1-HVoNIPsScHx1imVfa7xDhrWTDWg=
+ version "2.2.0"
+ resolved "http://registry.npm.taobao.org/p-limit/download/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2"
+ integrity sha1-QXyZQeYCepq8ulCS3SkE4lW1+8I=
dependencies:
p-try "^2.0.0"
@@ -5129,9 +5103,9 @@ pacote@9.4.0:
which "^1.3.1"
pako@~1.0.2, pako@~1.0.5:
- version "1.0.8"
- resolved "http://registry.npm.taobao.org/pako/download/pako-1.0.8.tgz#6844890aab9c635af868ad5fecc62e8acbba3ea4"
- integrity sha1-aESJCqucY1r4aK1f7MYuisu6PqQ=
+ version "1.0.10"
+ resolved "http://registry.npm.taobao.org/pako/download/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732"
+ integrity sha1-Qyi621CGpCaqkPVBl31JVdpclzI=
parallel-transform@^1.1.0:
version "1.1.0"
@@ -5658,7 +5632,7 @@ read-pkg@^2.0.0:
normalize-package-data "^2.3.2"
path-type "^2.0.0"
-"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
+"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
version "2.3.6"
resolved "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
integrity sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=
@@ -5672,9 +5646,9 @@ read-pkg@^2.0.0:
util-deprecate "~1.0.1"
readable-stream@^3.0.6:
- version "3.1.1"
- resolved "http://registry.npm.taobao.org/readable-stream/download/readable-stream-3.1.1.tgz#ed6bbc6c5ba58b090039ff18ce670515795aeb06"
- integrity sha1-7Wu8bFuliwkAOf8YzmcFFXla6wY=
+ version "3.2.0"
+ resolved "http://registry.npm.taobao.org/readable-stream/download/readable-stream-3.2.0.tgz#de17f229864c120a9f56945756e4f32c4045245d"
+ integrity sha1-3hfyKYZMEgqfVpRXVuTzLEBFJF0=
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
@@ -5758,11 +5732,6 @@ repeat-element@^1.1.2:
resolved "http://registry.npm.taobao.org/repeat-element/download/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
integrity sha1-eC4NglwMWjuzlzH4Tv7mt0Lmsc4=
-repeat-string@^0.2.2:
- version "0.2.2"
- resolved "http://registry.npm.taobao.org/repeat-string/download/repeat-string-0.2.2.tgz#c7a8d3236068362059a7e4651fc6884e8b1fb4ae"
- integrity sha1-x6jTI2BoNiBZp+RlH8aITosftK4=
-
repeat-string@^1.6.1:
version "1.6.1"
resolved "http://registry.npm.taobao.org/repeat-string/download/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
@@ -6292,17 +6261,17 @@ sockjs@0.3.19:
uuid "^3.0.1"
socks-proxy-agent@^4.0.0:
- version "4.0.1"
- resolved "http://registry.npm.taobao.org/socks-proxy-agent/download/socks-proxy-agent-4.0.1.tgz#5936bf8b707a993079c6f37db2091821bffa6473"
- integrity sha1-WTa/i3B6mTB5xvN9sgkYIb/6ZHM=
+ version "4.0.2"
+ resolved "http://registry.npm.taobao.org/socks-proxy-agent/download/socks-proxy-agent-4.0.2.tgz#3c8991f3145b2799e70e11bd5fbc8b1963116386"
+ integrity sha1-PImR8xRbJ5nnDhG9X7yLGWMRY4Y=
dependencies:
- agent-base "~4.2.0"
- socks "~2.2.0"
+ agent-base "~4.2.1"
+ socks "~2.3.2"
-socks@~2.2.0:
- version "2.2.3"
- resolved "http://registry.npm.taobao.org/socks/download/socks-2.2.3.tgz#7399ce11e19b2a997153c983a9ccb6306721f2dc"
- integrity sha1-c5nOEeGbKplxU8mDqcy2MGch8tw=
+socks@~2.3.2:
+ version "2.3.2"
+ resolved "http://registry.npm.taobao.org/socks/download/socks-2.3.2.tgz#ade388e9e6d87fdb11649c15746c578922a5883e"
+ integrity sha1-reOI6ebYf9sRZJwVdGxXiSKliD4=
dependencies:
ip "^1.1.5"
smart-buffer "4.0.2"
@@ -6581,15 +6550,16 @@ stream-shift@^1.0.0:
resolved "http://registry.npm.taobao.org/stream-shift/download/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952"
integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=
-streamroller@0.7.0:
- version "0.7.0"
- resolved "http://registry.npm.taobao.org/streamroller/download/streamroller-0.7.0.tgz#a1d1b7cf83d39afb0d63049a5acbf93493bdf64b"
- integrity sha1-odG3z4PTmvsNYwSaWsv5NJO99ks=
+streamroller@^1.0.1:
+ version "1.0.3"
+ resolved "http://registry.npm.taobao.org/streamroller/download/streamroller-1.0.3.tgz#cb51e7e382f799a9381a5d7490ce3053b325fba3"
+ integrity sha1-y1Hn44L3mak4Gl10kM4wU7Ml+6M=
dependencies:
- date-format "^1.2.0"
+ async "^2.6.1"
+ date-format "^2.0.0"
debug "^3.1.0"
- mkdirp "^0.5.1"
- readable-stream "^2.3.0"
+ fs-extra "^7.0.0"
+ lodash "^4.17.10"
string-width@^1.0.1, string-width@^1.0.2:
version "1.0.2"
@@ -6637,11 +6607,11 @@ strip-ansi@^4.0.0:
ansi-regex "^3.0.0"
strip-ansi@^5.0.0:
- version "5.0.0"
- resolved "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f"
- integrity sha1-949otdCGbCCyybjGG1KYUI3IdW8=
+ version "5.1.0"
+ resolved "http://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.1.0.tgz#55aaa54e33b4c0649a7338a43437b1887d153ec4"
+ integrity sha1-VaqlTjO0wGSaczikNDexiH0VPsQ=
dependencies:
- ansi-regex "^4.0.0"
+ ansi-regex "^4.1.0"
strip-bom@^2.0.0:
version "2.0.0"
@@ -6774,9 +6744,9 @@ terser-webpack-plugin@1.2.1:
worker-farm "^1.5.2"
terser-webpack-plugin@^1.1.0:
- version "1.2.2"
- resolved "http://registry.npm.taobao.org/terser-webpack-plugin/download/terser-webpack-plugin-1.2.2.tgz#9bff3a891ad614855a7dde0d707f7db5a927e3d9"
- integrity sha1-m/86iRrWFIVafd4NcH99takn49k=
+ version "1.2.3"
+ resolved "http://registry.npm.taobao.org/terser-webpack-plugin/download/terser-webpack-plugin-1.2.3.tgz#3f98bc902fac3e5d0de730869f50668561262ec8"
+ integrity sha1-P5i8kC+sPl0N5zCGn1BmhWEmLsg=
dependencies:
cacache "^11.0.2"
find-cache-dir "^2.0.0"
@@ -6930,9 +6900,9 @@ tslib@^1.7.1, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0:
integrity sha1-1+TdeSRdhUKMTX5IIqeZF5VMooY=
tslint@^5.12.1:
- version "5.12.1"
- resolved "http://registry.npm.taobao.org/tslint/download/tslint-5.12.1.tgz#8cec9d454cf8a1de9b0a26d7bdbad6de362e52c1"
- integrity sha1-jOydRUz4od6bCibXvbrW3jYuUsE=
+ version "5.13.1"
+ resolved "http://registry.npm.taobao.org/tslint/download/tslint-5.13.1.tgz#fbc0541c425647a33cd9108ce4fd4cd18d7904ed"
+ integrity sha1-+8BUHEJWR6M82RCM5P1M0Y15BO0=
dependencies:
babel-code-frame "^6.22.0"
builtin-modules "^1.1.1"
@@ -6942,6 +6912,7 @@ tslint@^5.12.1:
glob "^7.1.1"
js-yaml "^3.7.0"
minimatch "^3.0.4"
+ mkdirp "^0.5.1"
resolve "^1.3.2"
semver "^5.3.0"
tslib "^1.8.0"
@@ -7033,6 +7004,11 @@ unique-slug@^2.0.0:
dependencies:
imurmurhash "^0.1.4"
+universalify@^0.1.0:
+ version "0.1.2"
+ resolved "http://registry.npm.taobao.org/universalify/download/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
+ integrity sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY=
+
unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
resolved "http://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
@@ -7047,9 +7023,9 @@ unset-value@^1.0.0:
isobject "^3.0.0"
upath@^1.0.5, upath@^1.1.0:
- version "1.1.0"
- resolved "http://registry.npm.taobao.org/upath/download/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd"
- integrity sha1-NSVll+RqWB20eT0M5H+prr/J+r0=
+ version "1.1.1"
+ resolved "http://registry.npm.taobao.org/upath/download/upath-1.1.1.tgz#497f7c1090b0818f310bbfb06783586a68d28014"
+ integrity sha1-SX98EJCwgY8xC7+wZ4NYamjSgBQ=
uri-js@^4.2.2:
version "4.2.2"