diff --git a/jest/tests-setup.ts b/jest/tests-setup.ts index d8d49d61..7aaa4af8 100644 --- a/jest/tests-setup.ts +++ b/jest/tests-setup.ts @@ -1,10 +1,14 @@ +// TODO: Should be able to remove this once dev dependencies are hoisted to the workspace +// tslint:disable:no-implicit-dependencies import 'core-js/es6/reflect'; import 'core-js/es7/reflect'; import 'zone.js'; -import 'zone.js/dist/proxy'; -import 'zone.js/dist/sync-test'; import 'zone.js/dist/async-test'; import 'zone.js/dist/fake-async-test'; +import 'zone.js/dist/proxy'; +import 'zone.js/dist/sync-test'; +// This must be loaded in after ZoneJS +// tslint:disable-next-line:ordered-imports import 'jest-zone-patch'; import { TestBed } from '@angular/core/testing'; diff --git a/package.json b/package.json index 24e5ada9..eb61db51 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "clean:workspace-deps": "rimraf node_modules", "clean:package-deps": "rimraf packages/*/node_modules", "clean:coverage": "rimraf coverage", - "lint": "npm-run-all -p lint:*", + "lint": "tslint -p tsconfig.json", "lint:packages": "lerna run lint", "lint:prettier": "prettier -l \"**/*.*(ts|js|css|scss|json|md)\"", "test": "jest --coverage", @@ -31,14 +31,17 @@ "@commitlint/config-conventional": "7.0.1", "@commitlint/prompt-cli": "7.0.0", "@types/jest": "23.1.6", + "codelyzer": "4.4.2", "husky": "0.14.3", "jest": "23.4.1", "jest-junit": "5.1.0", "jest-preset-angular": "5.2.3", + "jest-zone-patch": "0.0.8", "lerna": "2.11.0", "lint-staged": "7.2.0", "npm-run-all": "4.1.3", "prettier": "1.13.7", - "rimraf": "2.6.2" + "rimraf": "2.6.2", + "tslint": "5.11.0" } } diff --git a/packages/example-app/circle.yml b/packages/example-app/circle.yml deleted file mode 100644 index 74094de1..00000000 --- a/packages/example-app/circle.yml +++ /dev/null @@ -1,15 +0,0 @@ -machine: - node: - version: 6.9.5 - -dependencies: - # Circle CI's preinstalled yarn doesn't work with @angular/cli. Never versions - # of yarn do. - pre: - - curl -o- -L https://yarnpkg.com/install.sh | bash - override: - - yarn - -test: - override: - - yarn test diff --git a/packages/example-app/package.json b/packages/example-app/package.json index 0e49a12b..5bf9de96 100644 --- a/packages/example-app/package.json +++ b/packages/example-app/package.json @@ -37,10 +37,8 @@ "@angular/compiler-cli": "^4.1.0", "@types/node": "~6.0.71", "@types/redux-logger": "^3.0.0", - "codelyzer": "~3.0.1", "protractor": "~5.1.1", "ts-node": "~3.0.2", - "tslint": "~5.1.0", "typescript": "^2.4.1" } } diff --git a/packages/example-app/src/app/animals/animal-list/component.spec.ts b/packages/example-app/src/app/animals/animal-list/component.spec.ts index e5cf28be..f0d7a71a 100644 --- a/packages/example-app/src/app/animals/animal-list/component.spec.ts +++ b/packages/example-app/src/app/animals/animal-list/component.spec.ts @@ -1,9 +1,9 @@ import { Component, Input } from '@angular/core'; -import { TestBed, async } from '@angular/core/testing'; +import { async, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { AnimalListComponent } from './component'; import { CoreModule } from '../../core/module'; import { AnimalType } from '../model'; +import { AnimalListComponent } from './component'; @Component({ selector: 'zoo-animal', template: '' }) class MockAnimalComponent { @@ -19,7 +19,7 @@ xdescribe('AnimalListComponent', () => { }).compileComponents(); })); - it(`should have as title 'Welcome to the Zoo'`, async(() => { + it("should have as title 'Welcome to the Zoo'", async(() => { const fixture = TestBed.createComponent(AnimalListComponent); const animalList = fixture.debugElement.componentInstance; diff --git a/packages/example-app/src/app/animals/animal-list/component.ts b/packages/example-app/src/app/animals/animal-list/component.ts index 98a11ea7..2f4487ed 100644 --- a/packages/example-app/src/app/animals/animal-list/component.ts +++ b/packages/example-app/src/app/animals/animal-list/component.ts @@ -1,6 +1,6 @@ -import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { Observable } from 'rxjs/Observable'; -import { IAnimal } from '../model'; +import { Animal } from '../model'; @Component({ selector: 'zoo-animal-list', @@ -11,14 +11,14 @@ import { IAnimal } from '../model'; export class AnimalListComponent { @Input() animalsName: string; @Input() animalType: string; - @Input() animals: Observable<IAnimal[]>; + @Input() animals: Observable<Animal[]>; @Input() loading: Observable<boolean>; @Input() error: Observable<any>; // Since we're observing an array of items, we need to set up a 'trackBy' // parameter so Angular doesn't tear down and rebuild the list's DOM every // time there's an update. - getKey(_, animal: IAnimal) { + getKey(_, animal: Animal) { return animal.id; } } diff --git a/packages/example-app/src/app/animals/animal/component.spec.ts b/packages/example-app/src/app/animals/animal/component.spec.ts index 21626611..932c9676 100644 --- a/packages/example-app/src/app/animals/animal/component.spec.ts +++ b/packages/example-app/src/app/animals/animal/component.spec.ts @@ -1,11 +1,11 @@ -import { async, TestBed } from '@angular/core/testing'; import { - NgReduxTestingModule, MockNgRedux, + NgReduxTestingModule, } from '@angular-redux/store/testing'; -import { AnimalComponent } from './component'; -import { CoreModule } from '../../core/module'; +import { async, TestBed } from '@angular/core/testing'; import 'rxjs/add/operator/toArray'; +import { CoreModule } from '../../core/module'; +import { AnimalComponent } from './component'; xdescribe('AnimalComponent', () => { let fixture; diff --git a/packages/example-app/src/app/animals/animal/component.ts b/packages/example-app/src/app/animals/animal/component.ts index f2e89bb2..930cc6f1 100644 --- a/packages/example-app/src/app/animals/animal/component.ts +++ b/packages/example-app/src/app/animals/animal/component.ts @@ -1,11 +1,11 @@ -import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; import { dispatch, select, select$, WithSubStore } from '@angular-redux/store'; +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { Observable } from 'rxjs/Observable'; +import { Animal } from '../model'; import { animalComponentReducer } from './reducers'; -import { IAnimal } from '../model'; -export const toSubTotal = (obs$: Observable<IAnimal>): Observable<number> => +export const toSubTotal = (obs$: Observable<Animal>): Observable<number> => obs$.map(s => s.ticketPrice * s.tickets); /** diff --git a/packages/example-app/src/app/animals/animal/reducers.ts b/packages/example-app/src/app/animals/animal/reducers.ts index 770d288e..64e2ada8 100644 --- a/packages/example-app/src/app/animals/animal/reducers.ts +++ b/packages/example-app/src/app/animals/animal/reducers.ts @@ -1,4 +1,4 @@ -import { Reducer, Action } from 'redux'; +import { Action, Reducer } from 'redux'; import { AnimalComponent } from './component'; export const ticketsReducer: Reducer<number> = ( diff --git a/packages/example-app/src/app/animals/api/actions.ts b/packages/example-app/src/app/animals/api/actions.ts index 5d98d50e..5dbc1d69 100644 --- a/packages/example-app/src/app/animals/api/actions.ts +++ b/packages/example-app/src/app/animals/api/actions.ts @@ -1,10 +1,10 @@ -import { Injectable } from '@angular/core'; import { dispatch } from '@angular-redux/store'; +import { Injectable } from '@angular/core'; import { FluxStandardAction } from 'flux-standard-action'; -import { IAnimal, AnimalType } from '../model'; +import { Animal, AnimalType } from '../model'; // Flux-standard-action gives us stronger typing of our actions. -type Payload = IAnimal[]; +type Payload = Animal[]; interface MetaData { animalType: AnimalType; } diff --git a/packages/example-app/src/app/animals/api/epics.ts b/packages/example-app/src/app/animals/api/epics.ts index 837582a0..d1035997 100644 --- a/packages/example-app/src/app/animals/api/epics.ts +++ b/packages/example-app/src/app/animals/api/epics.ts @@ -1,19 +1,19 @@ import { Injectable } from '@angular/core'; -import { Epic, createEpicMiddleware } from 'redux-observable'; -import { of } from 'rxjs/observable/of'; +import { createEpicMiddleware, Epic } from 'redux-observable'; import 'rxjs/add/operator/catch'; -import 'rxjs/add/operator/map'; import 'rxjs/add/operator/do'; +import 'rxjs/add/operator/map'; import 'rxjs/add/operator/startWith'; +import { of } from 'rxjs/observable/of'; -import { IAppState } from '../../store/model'; +import { AppState } from '../../store/model'; import { AnimalType } from '../model'; import { AnimalAPIAction, AnimalAPIActions } from './actions'; import { AnimalAPIService } from './service'; const animalsNotAlreadyFetched = ( animalType: AnimalType, - state: IAppState, + state: AppState, ): boolean => !( state[animalType] && @@ -32,13 +32,13 @@ export class AnimalAPIEpics { private actions: AnimalAPIActions, ) {} - public createEpic(animalType: AnimalType) { + createEpic(animalType: AnimalType) { return createEpicMiddleware(this.createLoadAnimalEpic(animalType)); } private createLoadAnimalEpic( animalType: AnimalType, - ): Epic<AnimalAPIAction, IAppState> { + ): Epic<AnimalAPIAction, AppState> { return (action$, store) => action$ .ofType(AnimalAPIActions.LOAD_ANIMALS) diff --git a/packages/example-app/src/app/animals/api/reducer.ts b/packages/example-app/src/app/animals/api/reducer.ts index c6a08237..3ea3b249 100644 --- a/packages/example-app/src/app/animals/api/reducer.ts +++ b/packages/example-app/src/app/animals/api/reducer.ts @@ -1,9 +1,9 @@ -import { AnimalAPIAction, AnimalAPIActions } from './actions'; -import { IAnimalList, AnimalType } from '../model'; import { indexBy, prop } from 'ramda'; import { Action } from 'redux'; +import { AnimalList, AnimalType } from '../model'; +import { AnimalAPIAction, AnimalAPIActions } from './actions'; -const INITIAL_STATE: IAnimalList = { +const INITIAL_STATE: AnimalList = { items: {}, loading: false, error: null, @@ -13,9 +13,9 @@ const INITIAL_STATE: IAnimalList = { // that only responds to actions for that particular animal type. export function createAnimalAPIReducer(animalType: AnimalType) { return function animalReducer( - state: IAnimalList = INITIAL_STATE, + state: AnimalList = INITIAL_STATE, a: Action, - ): IAnimalList { + ): AnimalList { const action = a as AnimalAPIAction; if (!action.meta || action.meta.animalType !== animalType) { return state; diff --git a/packages/example-app/src/app/animals/api/service.ts b/packages/example-app/src/app/animals/api/service.ts index 8c66fe95..8ff199fc 100644 --- a/packages/example-app/src/app/animals/api/service.ts +++ b/packages/example-app/src/app/animals/api/service.ts @@ -1,10 +1,10 @@ import { Injectable } from '@angular/core'; import { Http } from '@angular/http'; -import { Observable } from 'rxjs/Observable'; -import 'rxjs/add/operator/map'; import 'rxjs/add/observable/of'; +import 'rxjs/add/operator/map'; +import { Observable } from 'rxjs/Observable'; -import { ANIMAL_TYPES, AnimalType, IAnimal, fromServer } from '../model'; +import { Animal, ANIMAL_TYPES, AnimalType, fromServer } from '../model'; // A fake API on the internets. const URLS = { @@ -16,7 +16,7 @@ const URLS = { export class AnimalAPIService { constructor(private http: Http) {} - getAll = (animalType: AnimalType): Observable<IAnimal[]> => + getAll = (animalType: AnimalType): Observable<Animal[]> => this.http .get(URLS[animalType]) .map(resp => resp.json()) diff --git a/packages/example-app/src/app/animals/model.ts b/packages/example-app/src/app/animals/model.ts index a6336388..523afd25 100644 --- a/packages/example-app/src/app/animals/model.ts +++ b/packages/example-app/src/app/animals/model.ts @@ -6,7 +6,7 @@ export const ANIMAL_TYPES = { // TODO: is there a way to improve this? export type AnimalType = string; -export interface IAnimal { +export interface Animal { id: string; animalType: AnimalType; name: string; @@ -14,13 +14,13 @@ export interface IAnimal { tickets: number; } -export interface IAnimalList { +export interface AnimalList { items: {}; loading: boolean; error: any; } -export const fromServer = (record: any): IAnimal => ({ +export const fromServer = (record: any): Animal => ({ id: record.name.toLowerCase(), animalType: record.animalType, name: record.name, diff --git a/packages/example-app/src/app/animals/module.ts b/packages/example-app/src/app/animals/module.ts index 996877f7..712857dd 100644 --- a/packages/example-app/src/app/animals/module.ts +++ b/packages/example-app/src/app/animals/module.ts @@ -1,12 +1,12 @@ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { CoreModule } from '../core/module'; +import { StoreModule } from '../store/module'; import { AnimalListComponent } from './animal-list/component'; import { AnimalAPIActions } from './api/actions'; import { AnimalAPIEpics } from './api/epics'; import { AnimalAPIService } from './api/service'; -import { StoreModule } from '../store/module'; import { AnimalComponent } from './animal/component'; diff --git a/packages/example-app/src/app/component.html b/packages/example-app/src/app/component.html index 3d8c9e84..14d981f5 100644 --- a/packages/example-app/src/app/component.html +++ b/packages/example-app/src/app/component.html @@ -1,5 +1,5 @@ <h1> - {{title}} + {{ title }} </h1> <nav> <a routerLink="/elephants" routerLinkActive="active">Elephants</a> diff --git a/packages/example-app/src/app/component.spec.ts b/packages/example-app/src/app/component.spec.ts index 5b109930..bfd3fab4 100644 --- a/packages/example-app/src/app/component.spec.ts +++ b/packages/example-app/src/app/component.spec.ts @@ -1,4 +1,4 @@ -import { TestBed, async } from '@angular/core/testing'; +import { async, TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { AppComponent } from './component'; @@ -10,7 +10,7 @@ xdescribe('AppComponent', () => { }).compileComponents(); })); - it(`should have as title 'Welcome to the Zoo'`, async(() => { + it("should have as title 'Welcome to the Zoo'", async(() => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; expect(app.title).toEqual('Welcome to the Zoo'); diff --git a/packages/example-app/src/app/component.ts b/packages/example-app/src/app/component.ts index 78cc7237..47b55922 100644 --- a/packages/example-app/src/app/component.ts +++ b/packages/example-app/src/app/component.ts @@ -1,4 +1,4 @@ -import { Component, ChangeDetectionStrategy } from '@angular/core'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; @Component({ selector: 'zoo-root', diff --git a/packages/example-app/src/app/core/counter/component.ts b/packages/example-app/src/app/core/counter/component.ts index 795b96df..c70fb655 100644 --- a/packages/example-app/src/app/core/counter/component.ts +++ b/packages/example-app/src/app/core/counter/component.ts @@ -1,9 +1,9 @@ import { + ChangeDetectionStrategy, Component, + EventEmitter, Input, Output, - ChangeDetectionStrategy, - EventEmitter, } from '@angular/core'; @Component({ diff --git a/packages/example-app/src/app/core/error-well/component.ts b/packages/example-app/src/app/core/error-well/component.ts index 13b5827e..08092308 100644 --- a/packages/example-app/src/app/core/error-well/component.ts +++ b/packages/example-app/src/app/core/error-well/component.ts @@ -1,4 +1,4 @@ -import { Input, Component, ChangeDetectionStrategy } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { Observable } from 'rxjs/Observable'; @Component({ diff --git a/packages/example-app/src/app/core/module.ts b/packages/example-app/src/app/core/module.ts index c7f597ab..4befd66f 100644 --- a/packages/example-app/src/app/core/module.ts +++ b/packages/example-app/src/app/core/module.ts @@ -1,9 +1,9 @@ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; -import { SpinnerComponent } from './spinner/component'; -import { ErrorWellComponent } from './error-well/component'; import { CounterComponent } from './counter/component'; +import { ErrorWellComponent } from './error-well/component'; +import { SpinnerComponent } from './spinner/component'; @NgModule({ declarations: [SpinnerComponent, ErrorWellComponent, CounterComponent], diff --git a/packages/example-app/src/app/elephants/module.ts b/packages/example-app/src/app/elephants/module.ts index 3822efc0..f1018f72 100644 --- a/packages/example-app/src/app/elephants/module.ts +++ b/packages/example-app/src/app/elephants/module.ts @@ -1,10 +1,10 @@ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; -import { ElephantPageComponent } from './page'; import { AnimalModule } from '../animals/module'; import { CoreModule } from '../core/module'; import { StoreModule } from '../store/module'; +import { ElephantPageComponent } from './page'; @NgModule({ declarations: [ElephantPageComponent], diff --git a/packages/example-app/src/app/elephants/page.spec.ts b/packages/example-app/src/app/elephants/page.spec.ts index 26fb1283..1ccac2bc 100644 --- a/packages/example-app/src/app/elephants/page.spec.ts +++ b/packages/example-app/src/app/elephants/page.spec.ts @@ -1,19 +1,19 @@ -import { TestBed } from '@angular/core/testing'; import { - NgReduxTestingModule, MockNgRedux, + NgReduxTestingModule, } from '@angular-redux/store/testing'; +import { TestBed } from '@angular/core/testing'; import { Component, Input } from '@angular/core'; -import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/of'; -import 'rxjs/add/operator/toArray'; import 'rxjs/add/operator/do'; +import 'rxjs/add/operator/toArray'; +import { Observable } from 'rxjs/Observable'; -import { ElephantPageComponent } from './page'; import { AnimalAPIActions } from '../animals/api/actions'; import { ANIMAL_TYPES } from '../animals/model'; +import { ElephantPageComponent } from './page'; @Component({ selector: 'zoo-animal-list', diff --git a/packages/example-app/src/app/elephants/page.ts b/packages/example-app/src/app/elephants/page.ts index 86912434..badfcc64 100644 --- a/packages/example-app/src/app/elephants/page.ts +++ b/packages/example-app/src/app/elephants/page.ts @@ -1,10 +1,10 @@ -import { Component, ChangeDetectionStrategy } from '@angular/core'; import { select, select$ } from '@angular-redux/store'; -import { pipe, values, sortBy, prop } from 'ramda'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { pipe, prop, sortBy, values } from 'ramda'; import { Observable } from 'rxjs/Observable'; import { AnimalAPIActions } from '../animals/api/actions'; -import { ANIMAL_TYPES, IAnimal } from '../animals/model'; +import { Animal, ANIMAL_TYPES } from '../animals/model'; export const sortAnimals = (animalDictionary$: Observable<{}>) => animalDictionary$.map( @@ -21,7 +21,7 @@ export const sortAnimals = (animalDictionary$: Observable<{}>) => export class ElephantPageComponent { // Get elephant-related data out of the Redux store as observables. @select$(['elephant', 'items'], sortAnimals) - readonly animals$: Observable<IAnimal[]>; + readonly animals$: Observable<Animal[]>; @select(['elephant', 'loading']) readonly loading$: Observable<boolean>; diff --git a/packages/example-app/src/app/feedback/module.ts b/packages/example-app/src/app/feedback/module.ts index ae6c1096..28ac21bb 100644 --- a/packages/example-app/src/app/feedback/module.ts +++ b/packages/example-app/src/app/feedback/module.ts @@ -1,9 +1,9 @@ +import { NgReduxFormModule } from '@angular-redux/form'; +import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { CommonModule } from '@angular/common'; -import { NgReduxFormModule } from '@angular-redux/form'; -import { FeedbackFormComponent } from './page'; import { StoreModule } from '../store/module'; +import { FeedbackFormComponent } from './page'; @NgModule({ declarations: [FeedbackFormComponent], diff --git a/packages/example-app/src/app/feedback/page.spec.ts b/packages/example-app/src/app/feedback/page.spec.ts index bdb307bc..de8e4cd3 100644 --- a/packages/example-app/src/app/feedback/page.spec.ts +++ b/packages/example-app/src/app/feedback/page.spec.ts @@ -1,12 +1,12 @@ -import { TestBed } from '@angular/core/testing'; import { - NgReduxTestingModule, MockNgRedux, + NgReduxTestingModule, } from '@angular-redux/store/testing'; +import { TestBed } from '@angular/core/testing'; import 'rxjs/add/observable/of'; -import 'rxjs/add/operator/toArray'; import 'rxjs/add/operator/do'; +import 'rxjs/add/operator/toArray'; import { FeedbackFormComponent } from './page'; diff --git a/packages/example-app/src/app/feedback/page.ts b/packages/example-app/src/app/feedback/page.ts index 6c182c0f..4422206b 100644 --- a/packages/example-app/src/app/feedback/page.ts +++ b/packages/example-app/src/app/feedback/page.ts @@ -1,5 +1,5 @@ -import { Component, ChangeDetectionStrategy } from '@angular/core'; import { select$ } from '@angular-redux/store'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; import { Observable } from 'rxjs/Observable'; const MAX_COMMENT_CHARS = 300; diff --git a/packages/example-app/src/app/lions/module.ts b/packages/example-app/src/app/lions/module.ts index f95686fc..4dd48305 100644 --- a/packages/example-app/src/app/lions/module.ts +++ b/packages/example-app/src/app/lions/module.ts @@ -1,10 +1,10 @@ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; -import { LionPageComponent } from './page'; import { AnimalModule } from '../animals/module'; import { CoreModule } from '../core/module'; import { StoreModule } from '../store/module'; +import { LionPageComponent } from './page'; @NgModule({ declarations: [LionPageComponent], diff --git a/packages/example-app/src/app/lions/page.spec.ts b/packages/example-app/src/app/lions/page.spec.ts index d42bd855..47104d40 100644 --- a/packages/example-app/src/app/lions/page.spec.ts +++ b/packages/example-app/src/app/lions/page.spec.ts @@ -1,20 +1,20 @@ -import { TestBed, async } from '@angular/core/testing'; import { - NgReduxTestingModule, MockNgRedux, + NgReduxTestingModule, } from '@angular-redux/store/testing'; +import { async, TestBed } from '@angular/core/testing'; -import { Component, Input } from '@angular/core'; import { NgRedux } from '@angular-redux/store'; +import { Component, Input } from '@angular/core'; -import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/of'; -import 'rxjs/add/operator/toArray'; import 'rxjs/add/operator/do'; +import 'rxjs/add/operator/toArray'; +import { Observable } from 'rxjs/Observable'; -import { LionPageComponent } from './page'; import { AnimalAPIActions } from '../animals/api/actions'; import { ANIMAL_TYPES } from '../animals/model'; +import { LionPageComponent } from './page'; @Component({ selector: 'zoo-animal-list', diff --git a/packages/example-app/src/app/lions/page.ts b/packages/example-app/src/app/lions/page.ts index 599f6042..4fe1c485 100644 --- a/packages/example-app/src/app/lions/page.ts +++ b/packages/example-app/src/app/lions/page.ts @@ -1,10 +1,10 @@ -import { Component, ChangeDetectionStrategy } from '@angular/core'; import { select, select$ } from '@angular-redux/store'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { pipe, prop, sortBy, values } from 'ramda'; import { Observable } from 'rxjs/Observable'; -import { pipe, values, sortBy, prop } from 'ramda'; import { AnimalAPIActions } from '../animals/api/actions'; -import { ANIMAL_TYPES, IAnimal } from '../animals/model'; +import { Animal, ANIMAL_TYPES } from '../animals/model'; export const sortAnimals = (animalDictionary$: Observable<{}>) => animalDictionary$.map( @@ -21,7 +21,7 @@ export const sortAnimals = (animalDictionary$: Observable<{}>) => export class LionPageComponent { // Get lion-related data out of the Redux store as observables. @select$(['lion', 'items'], sortAnimals) - readonly animals$: Observable<IAnimal[]>; + readonly animals$: Observable<Animal[]>; @select(['lion', 'loading']) readonly loading$: Observable<boolean>; diff --git a/packages/example-app/src/app/module.ts b/packages/example-app/src/app/module.ts index ee96cc5f..ccd9444c 100644 --- a/packages/example-app/src/app/module.ts +++ b/packages/example-app/src/app/module.ts @@ -1,21 +1,21 @@ -import { BrowserModule } from '@angular/platform-browser'; +import { NgReduxRouterModule } from '@angular-redux/router'; +import { NgReduxModule } from '@angular-redux/store'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { RouterModule } from '@angular/router'; import { HttpModule } from '@angular/http'; -import { NgReduxModule } from '@angular-redux/store'; -import { NgReduxRouterModule } from '@angular-redux/router'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; // This app's ngModules -import { StoreModule } from './store/module'; import { AnimalModule } from './animals/module'; import { ElephantModule } from './elephants/module'; -import { LionModule } from './lions/module'; import { FeedbackModule } from './feedback/module'; +import { LionModule } from './lions/module'; +import { StoreModule } from './store/module'; // Top-level app component constructs. -import { appRoutes } from './routes'; import { AppComponent } from './component'; +import { appRoutes } from './routes'; @NgModule({ declarations: [AppComponent], diff --git a/packages/example-app/src/app/routes.ts b/packages/example-app/src/app/routes.ts index 8649863b..c58a5f39 100644 --- a/packages/example-app/src/app/routes.ts +++ b/packages/example-app/src/app/routes.ts @@ -1,6 +1,6 @@ import { ElephantPageComponent } from './elephants/page'; -import { LionPageComponent } from './lions/page'; import { FeedbackFormComponent } from './feedback/page'; +import { LionPageComponent } from './lions/page'; export const appRoutes = [ { path: '', redirectTo: '/elephants', pathMatch: 'full' }, diff --git a/packages/example-app/src/app/store/epics.ts b/packages/example-app/src/app/store/epics.ts index 4e5b4604..c58333af 100644 --- a/packages/example-app/src/app/store/epics.ts +++ b/packages/example-app/src/app/store/epics.ts @@ -1,13 +1,13 @@ import { Injectable } from '@angular/core'; -import { ANIMAL_TYPES } from '../animals/model'; import { AnimalAPIEpics } from '../animals/api/epics'; +import { ANIMAL_TYPES } from '../animals/model'; @Injectable() export class RootEpics { constructor(private animalEpics: AnimalAPIEpics) {} - public createEpics() { + createEpics() { return [ this.animalEpics.createEpic(ANIMAL_TYPES.ELEPHANT), this.animalEpics.createEpic(ANIMAL_TYPES.LION), diff --git a/packages/example-app/src/app/store/model.ts b/packages/example-app/src/app/store/model.ts index b5e37855..275961b8 100644 --- a/packages/example-app/src/app/store/model.ts +++ b/packages/example-app/src/app/store/model.ts @@ -1,7 +1,7 @@ -import { IAnimalList } from '../animals/model'; +import { AnimalList } from '../animals/model'; -export interface IAppState { - [animalType: string]: IAnimalList; +export interface AppState { + [animalType: string]: AnimalList; routes?: any; feedback?: any; } diff --git a/packages/example-app/src/app/store/module.spec.ts b/packages/example-app/src/app/store/module.spec.ts index 46fd3b25..df5b5035 100644 --- a/packages/example-app/src/app/store/module.spec.ts +++ b/packages/example-app/src/app/store/module.spec.ts @@ -1,16 +1,16 @@ -import { NgRedux, DevToolsExtension } from '@angular-redux/store'; +import { DevToolsExtension, NgRedux } from '@angular-redux/store'; import { - NgReduxTestingModule, MockNgRedux, + NgReduxTestingModule, } from '@angular-redux/store/testing'; -import { TestBed, async, getTestBed } from '@angular/core/testing'; -import { StoreModule } from './module'; +import { async, getTestBed, TestBed } from '@angular/core/testing'; import { RootEpics } from './epics'; +import { StoreModule } from './module'; xdescribe('Store Module', () => { let mockNgRedux: NgRedux<any>; let devTools: DevToolsExtension; - let mockEpics: RootEpics; + let mockEpics: Partial<RootEpics>; beforeEach(async(() => { TestBed.configureTestingModule({ @@ -24,7 +24,7 @@ xdescribe('Store Module', () => { createEpics() { return []; }, - } as RootEpics; + }; devTools = testbed.get(DevToolsExtension); mockNgRedux = MockNgRedux.getInstance(); diff --git a/packages/example-app/src/app/store/module.ts b/packages/example-app/src/app/store/module.ts index 16ac23d8..7e7d5849 100644 --- a/packages/example-app/src/app/store/module.ts +++ b/packages/example-app/src/app/store/module.ts @@ -4,21 +4,21 @@ import { NgModule } from '@angular/core'; // @angular-redux/form and @angular-redux/router are optional // extensions that sync form and route location state between // our store and Angular. +import { provideReduxForms } from '@angular-redux/form'; +import { NgReduxRouter, NgReduxRouterModule } from '@angular-redux/router'; import { - NgReduxModule, - NgRedux, DevToolsExtension, + NgRedux, + NgReduxModule, } from '@angular-redux/store'; -import { NgReduxRouterModule, NgReduxRouter } from '@angular-redux/router'; -import { provideReduxForms } from '@angular-redux/form'; // Redux ecosystem stuff. import { createLogger } from 'redux-logger'; // The top-level reducers and epics that make up our app's logic. -import { IAppState } from './model'; -import { rootReducer } from './reducers'; import { RootEpics } from './epics'; +import { AppState } from './model'; +import { rootReducer } from './reducers'; @NgModule({ imports: [NgReduxModule, NgReduxRouterModule], @@ -26,7 +26,7 @@ import { RootEpics } from './epics'; }) export class StoreModule { constructor( - public store: NgRedux<IAppState>, + public store: NgRedux<AppState>, devTools: DevToolsExtension, ngReduxRouter: NgReduxRouter, rootEpics: RootEpics, diff --git a/packages/example-app/src/app/store/reducers.ts b/packages/example-app/src/app/store/reducers.ts index 14aae186..199f5651 100644 --- a/packages/example-app/src/app/store/reducers.ts +++ b/packages/example-app/src/app/store/reducers.ts @@ -1,6 +1,6 @@ -import { combineReducers } from 'redux'; import { composeReducers, defaultFormReducer } from '@angular-redux/form'; import { routerReducer } from '@angular-redux/router'; +import { combineReducers } from 'redux'; import { createAnimalAPIReducer } from '../animals/api/reducer'; import { ANIMAL_TYPES } from '../animals/model'; diff --git a/packages/example-app/src/polyfills.ts b/packages/example-app/src/polyfills.ts index 0257e963..90921a21 100644 --- a/packages/example-app/src/polyfills.ts +++ b/packages/example-app/src/polyfills.ts @@ -18,7 +18,9 @@ * BROWSER POLYFILLS */ -/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +/** + * IE9, IE10 and IE11 requires all of the following polyfills. + */ // import 'core-js/es6/symbol'; // import 'core-js/es6/object'; // import 'core-js/es6/function'; @@ -39,11 +41,15 @@ /** IE10 and IE11 requires the following to support `@angular/animation`. */ // import 'web-animations-js'; // Run `npm install --save web-animations-js`. -/** Evergreen browsers require these. **/ +/** + * Evergreen browsers require these. + */ import 'core-js/es6/reflect'; import 'core-js/es7/reflect'; -/** ALL Firefox browsers require the following to support `@angular/animation`. **/ +/** + * ALL Firefox browsers require the following to support `@angular/animation`. + */ // import 'web-animations-js'; // Run `npm install --save web-animations-js`. /*************************************************************************************************** diff --git a/packages/example-app/src/test.ts b/packages/example-app/src/test.ts deleted file mode 100644 index 0c45c2ef..00000000 --- a/packages/example-app/src/test.ts +++ /dev/null @@ -1,32 +0,0 @@ -// This file is required by karma.conf.js and loads recursively all the .spec and framework files - -import 'zone.js/dist/long-stack-trace-zone'; -import 'zone.js/dist/proxy.js'; -import 'zone.js/dist/sync-test'; -import 'zone.js/dist/jasmine-patch'; -import 'zone.js/dist/async-test'; -import 'zone.js/dist/fake-async-test'; -import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting, -} from '@angular/platform-browser-dynamic/testing'; - -// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. -declare const __karma__: any; -declare const require: any; - -// Prevent Karma from running prematurely. -__karma__.loaded = function() {}; - -// First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - BrowserDynamicTestingModule, - platformBrowserDynamicTesting(), -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); -// Finally, start Karma to run the tests. -__karma__.start(); diff --git a/packages/example-app/tslint.json b/packages/example-app/tslint.json deleted file mode 100644 index 0bd85cab..00000000 --- a/packages/example-app/tslint.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "rulesDirectory": ["node_modules/codelyzer"], - "rules": { - "callable-types": true, - "class-name": true, - "comment-format": [true, "check-space"], - "curly": true, - "eofline": true, - "forin": true, - "import-blacklist": [true, "rxjs"], - "import-spacing": true, - "indent": [true, "spaces"], - "interface-over-type-literal": true, - "label-position": true, - "max-line-length": [true, 140], - "member-access": false, - "member-ordering": [ - true, - "static-before-instance", - "variables-before-functions" - ], - "no-arg": true, - "no-bitwise": true, - "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], - "no-construct": true, - "no-debugger": true, - "no-duplicate-variable": true, - "no-empty": false, - "no-empty-interface": true, - "no-eval": true, - "no-inferrable-types": [true, "ignore-params"], - "no-shadowed-variable": true, - "no-string-literal": false, - "no-string-throw": true, - "no-switch-case-fall-through": true, - "no-trailing-whitespace": true, - "no-unused-expression": true, - "no-use-before-declare": true, - "no-var-keyword": true, - "object-literal-sort-keys": false, - "one-line": [ - true, - "check-open-brace", - "check-catch", - "check-else", - "check-whitespace" - ], - "prefer-const": true, - "quotemark": [true, "single"], - "radix": true, - "semicolon": ["always"], - "triple-equals": [true, "allow-null-check"], - "typedef-whitespace": [ - true, - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - } - ], - "typeof-compare": true, - "unified-signatures": true, - "variable-name": false, - "whitespace": [ - true, - "check-branch", - "check-decl", - "check-operator", - "check-separator", - "check-type" - ], - - "directive-selector": [true, "attribute", "zoo", "camelCase"], - "component-selector": [true, "element", "zoo", "kebab-case"], - "use-input-property-decorator": true, - "use-output-property-decorator": true, - "use-host-property-decorator": true, - "no-input-rename": true, - "no-output-rename": true, - "use-life-cycle-interface": true, - "use-pipe-transform-interface": true, - "component-class-suffix": true, - "directive-class-suffix": true, - "no-access-missing-member": true, - "templates-use-public": true, - "invoke-injectable": true - } -} diff --git a/packages/form/source/compose-reducers.spec.ts b/packages/form/source/compose-reducers.spec.ts index 081569e6..6a016bb7 100644 --- a/packages/form/source/compose-reducers.spec.ts +++ b/packages/form/source/compose-reducers.spec.ts @@ -68,7 +68,7 @@ xdescribe('composeReducers', () => { expect(Set.isSet(state)).toEqual(true); const plain = state.toJS(); - expect(plain).not.toBeNull; + expect(plain).not.toBeNull(); expect(plain).toEqual([3, 2, 1, 4, 6, 5]); }); diff --git a/packages/form/source/compose-reducers.ts b/packages/form/source/compose-reducers.ts index b24cd522..62b18225 100644 --- a/packages/form/source/compose-reducers.ts +++ b/packages/form/source/compose-reducers.ts @@ -1,4 +1,4 @@ -import { Reducer, AnyAction } from 'redux'; +import { AnyAction, Reducer } from 'redux'; export const composeReducers = <State>( ...reducers: Reducer<State, AnyAction>[] diff --git a/packages/form/source/configure.ts b/packages/form/source/configure.ts index fdbd7cca..7b52a19c 100644 --- a/packages/form/source/configure.ts +++ b/packages/form/source/configure.ts @@ -8,13 +8,15 @@ import { AbstractStore, FormStore } from './form-store'; export const provideReduxForms = <T>(store: Store<T> | any) => { const abstractStore = wrap(store); - return [{ provide: FormStore, useValue: new FormStore(<any>abstractStore) }]; + return [ + { provide: FormStore, useValue: new FormStore(abstractStore as any) }, + ]; }; const wrap = <T>(store: Store<T> | any): AbstractStore<T> => { const dispatch = (action: Action) => store.dispatch(action); - const getState = () => <T>store.getState(); + const getState = () => store.getState() as T; const subscribe = (fn: (state: T) => void) => store.subscribe(() => fn(store.getState())); diff --git a/packages/form/source/connect-array/connect-array-template.ts b/packages/form/source/connect-array/connect-array-template.ts new file mode 100644 index 00000000..743eb051 --- /dev/null +++ b/packages/form/source/connect-array/connect-array-template.ts @@ -0,0 +1,3 @@ +export class ConnectArrayTemplate { + constructor(public $implicit: any, public index: number, public item: any) {} +} diff --git a/packages/form/source/connect-array/connect-array.module.ts b/packages/form/source/connect-array/connect-array.module.ts index bd263909..d28777fa 100644 --- a/packages/form/source/connect-array/connect-array.module.ts +++ b/packages/form/source/connect-array/connect-array.module.ts @@ -1,8 +1,8 @@ import { NgModule } from '@angular/core'; -import { ConnectArray } from './connect-array'; +import { ConnectArrayDirective } from './connect-array'; -const declarations = [ConnectArray]; +const declarations = [ConnectArrayDirective]; @NgModule({ declarations: [...declarations], diff --git a/packages/form/source/connect-array/connect-array.ts b/packages/form/source/connect-array/connect-array.ts index 7c33db9c..b6ebf48e 100644 --- a/packages/form/source/connect-array/connect-array.ts +++ b/packages/form/source/connect-array/connect-array.ts @@ -1,50 +1,50 @@ import { + Directive, + EmbeddedViewRef, forwardRef, Host, + Inject, Input, - SkipSelf, + OnDestroy, + OnInit, + Optional, Self, - Inject, + SkipSelf, TemplateRef, ViewContainerRef, - Directive, - Optional, - EmbeddedViewRef, - OnInit, } from '@angular/core'; import { AbstractControl, + AsyncValidatorFn, + ControlContainer, FormArray, FormControl, FormGroup, FormGroupDirective, + NG_ASYNC_VALIDATORS, + NG_VALIDATORS, NgModelGroup, - ControlContainer, + ValidatorFn, + Validators, } from '@angular/forms'; - -import { AsyncValidatorFn, ValidatorFn, Validators } from '@angular/forms'; -import { NG_ASYNC_VALIDATORS, NG_VALIDATORS } from '@angular/forms'; import { Unsubscribe } from 'redux'; import { ConnectBase } from '../connect'; import { FormStore } from '../form-store'; -import { State } from '../state'; import { controlPath } from '../shims'; - -export class ConnectArrayTemplate { - constructor(public $implicit: any, public index: number, public item: any) {} -} +import { State } from '../state'; +import { ConnectArrayTemplate } from './connect-array-template'; @Directive({ selector: '[connectArray]', providers: [ { provide: ControlContainer, - useExisting: forwardRef(() => ConnectArray), + useExisting: forwardRef(() => ConnectArrayDirective), }, ], }) -export class ConnectArray extends ControlContainer implements OnInit { +export class ConnectArrayDirective extends ControlContainer implements OnInit, OnDestroy { private stateSubscription: Unsubscribe; private array = new FormArray([]); @@ -86,7 +86,7 @@ export class ConnectArray extends ControlContainer implements OnInit { } ngOnInit() { - this.formDirective.addControl(<any>this); + this.formDirective.addControl(this as any); } get name(): string { @@ -98,10 +98,10 @@ export class ConnectArray extends ControlContainer implements OnInit { } get formDirective(): FormGroupDirective { - return <FormGroupDirective>this.parent.formDirective; + return this.parent.formDirective as FormGroupDirective; } - get path(): Array<string> { + get path(): string[] { return this.key ? controlPath(this.key, this.parent) : []; } @@ -113,7 +113,9 @@ export class ConnectArray extends ControlContainer implements OnInit { return Validators.composeAsync(this.rawAsyncValidators); } - updateValueAndValidity() {} + updateValueAndValidity() { + // stub? + } ngOnDestroy() { this.viewContainerRef.clear(); @@ -135,15 +137,15 @@ export class ConnectArray extends ControlContainer implements OnInit { let index = 0; for (const value of iterable) { - var viewRef = + const viewRef = this.viewContainerRef.length > index - ? <EmbeddedViewRef<ConnectArrayTemplate>>( - this.viewContainerRef.get(index) - ) + ? (this.viewContainerRef.get(index) as EmbeddedViewRef< + ConnectArrayTemplate + >) : null; if (viewRef == null) { - const viewRef = this.viewContainerRef.createEmbeddedView< + const embeddedViewRef = this.viewContainerRef.createEmbeddedView< ConnectArrayTemplate >( this.templateRef, @@ -151,11 +153,11 @@ export class ConnectArray extends ControlContainer implements OnInit { index, ); - this.patchDescendantControls(viewRef); + this.patchDescendantControls(embeddedViewRef); this.array.insert( index, - this.transform(this.array, viewRef.context.item), + this.transform(this.array, embeddedViewRef.context.item), ); } else { Object.assign( @@ -173,8 +175,8 @@ export class ConnectArray extends ControlContainer implements OnInit { } private registerInternals(array: any) { - array.registerControl = () => {}; - array.registerOnChange = () => {}; + array.registerControl = () => undefined; + array.registerOnChange = () => undefined; Object.defineProperties(this, { _rawValidators: { @@ -197,7 +199,7 @@ export class ConnectArray extends ControlContainer implements OnInit { value: this, }, _checkParentType: { - value: () => {}, + value: () => undefined, }, }); }); @@ -262,11 +264,11 @@ export class ConnectArray extends ControlContainer implements OnInit { }; if (Array.isArray(reference)) { - return iterate(<Array<any>>reference); + return iterate(reference as any[]); } else if (reference instanceof Set) { - return iterate(<Set<any>>reference); + return iterate(reference as Set<any>); } else if (reference instanceof Map) { - return associate(<Map<string, any>>reference); + return associate(reference as Map<string, any>); } else if (reference instanceof Object) { return associate(reference); } else { diff --git a/packages/form/source/connect-array/index.ts b/packages/form/source/connect-array/index.ts index 21f4af52..af948345 100644 --- a/packages/form/source/connect-array/index.ts +++ b/packages/form/source/connect-array/index.ts @@ -1,2 +1,3 @@ export * from './connect-array.module'; export * from './connect-array'; +export * from './connect-array-template'; diff --git a/packages/form/source/connect/connect-base.ts b/packages/form/source/connect/connect-base.ts index 153a7d53..12b56ce6 100644 --- a/packages/form/source/connect/connect-base.ts +++ b/packages/form/source/connect/connect-base.ts @@ -1,10 +1,10 @@ -import { Input } from '@angular/core'; +import { AfterContentInit, Input, OnDestroy } from '@angular/core'; import { AbstractControl, + FormArray, FormControl, FormGroup, - FormArray, NgControl, } from '@angular/forms'; @@ -18,19 +18,12 @@ import { FormStore } from '../form-store'; import { State } from '../state'; export interface ControlPair { - path: Array<string>; + path: string[]; control: AbstractControl; } -export class ConnectBase { - @Input('connect') connect?: () => (string | number) | Array<string | number>; - private stateSubscription?: Unsubscribe; - - private formSubscription?: Subscription; - protected store?: FormStore; - protected form: any; - - public get path(): Array<string> { +export class ConnectBase implements OnDestroy, AfterContentInit { + get path(): string[] { const path = typeof this.connect === 'function' ? this.connect() : this.connect; @@ -40,10 +33,10 @@ export class ConnectBase { return []; } if (Array.isArray(path)) { - return <Array<string>>path; + return path as string[]; } case 'string': - return (<string>path).split(/\./g); + return (path as string).split(/\./g); default: // fallthrough above (no break) throw new Error( @@ -51,6 +44,12 @@ export class ConnectBase { ); } } + @Input() connect?: () => (string | number) | (string | number)[]; + protected store?: FormStore; + protected form: any; + private stateSubscription?: Unsubscribe; + + private formSubscription?: Subscription; ngOnDestroy() { if (this.formSubscription) { @@ -71,22 +70,19 @@ export class ConnectBase { } Promise.resolve().then(() => { - this.formSubscription = (<any>this.form.valueChanges) + this.formSubscription = (this.form.valueChanges as any) .pipe(debounceTime(0)) .subscribe((values: any) => this.publish(values)); }); }); } - private descendants( - path: Array<string>, - formElement: any, - ): Array<ControlPair> { + private descendants(path: string[], formElement: any): ControlPair[] { const pairs = new Array<ControlPair>(); if (formElement instanceof FormArray) { formElement.controls.forEach((c, index) => { - for (const d of this.descendants((<any>path).concat([index]), c)) { + for (const d of this.descendants((path as any).concat([index]), c)) { pairs.push(d); } }); @@ -101,7 +97,7 @@ export class ConnectBase { formElement instanceof NgControl || formElement instanceof FormControl ) { - return [{ path: path, control: <any>formElement }]; + return [{ path, control: formElement as any }]; } else { throw new Error( `Unknown type of form element: ${formElement.constructor.name}`, @@ -115,12 +111,8 @@ export class ConnectBase { } private resetState() { - var formElement; - if (this.form.control === undefined) { - formElement = this.form; - } else { - formElement = this.form.control; - } + const formElement = + this.form.control === undefined ? this.form : this.form.control; const children = this.descendants([], formElement); diff --git a/packages/form/source/connect/connect-reactive.ts b/packages/form/source/connect/connect-reactive.ts index a986b26c..63ecc08f 100644 --- a/packages/form/source/connect/connect-reactive.ts +++ b/packages/form/source/connect/connect-reactive.ts @@ -6,8 +6,8 @@ import { ConnectBase } from './connect-base'; // For reactive forms (without implicit NgForm) @Directive({ selector: 'form[connect][formGroup]' }) -export class ReactiveConnect extends ConnectBase { - @Input('formGroup') form: any; +export class ReactiveConnectDirective extends ConnectBase { + @Input() formGroup: any; constructor(protected store: FormStore) { super(); diff --git a/packages/form/source/connect/connect.module.ts b/packages/form/source/connect/connect.module.ts index 165cd156..30aecaf4 100644 --- a/packages/form/source/connect/connect.module.ts +++ b/packages/form/source/connect/connect.module.ts @@ -1,9 +1,9 @@ import { NgModule } from '@angular/core'; -import { Connect } from './connect'; -import { ReactiveConnect } from './connect-reactive'; +import { ConnectDirective } from './connect'; +import { ReactiveConnectDirective } from './connect-reactive'; -const declarations = [Connect, ReactiveConnect]; +const declarations = [ConnectDirective, ReactiveConnectDirective]; @NgModule({ declarations: [...declarations], diff --git a/packages/form/source/connect/connect.spec.ts b/packages/form/source/connect/connect.spec.ts index 2f1542b3..b4a8deb8 100644 --- a/packages/form/source/connect/connect.spec.ts +++ b/packages/form/source/connect/connect.spec.ts @@ -115,7 +115,7 @@ // export class UpdateTextComponent {} describe('connect directive', () => { - it('should have a fake test for now until we can fix them...', () => {}); + it('should have a fake test for now until we can fix them...', () => undefined); // let store: Store<AppState>; // beforeEach(done => { diff --git a/packages/form/source/connect/connect.ts b/packages/form/source/connect/connect.ts index 69da4f66..09f84547 100644 --- a/packages/form/source/connect/connect.ts +++ b/packages/form/source/connect/connect.ts @@ -7,7 +7,7 @@ import { ConnectBase } from './connect-base'; // For template forms (with implicit NgForm) @Directive({ selector: 'form[connect]:not([formGroup])' }) -export class Connect extends ConnectBase { +export class ConnectDirective extends ConnectBase { constructor(protected store: FormStore, protected form: NgForm) { super(); } diff --git a/packages/form/source/module.ts b/packages/form/source/module.ts index af687989..e6aae22b 100644 --- a/packages/form/source/module.ts +++ b/packages/form/source/module.ts @@ -1,6 +1,6 @@ +import { NgRedux } from '@angular-redux/store'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { NgRedux } from '@angular-redux/store'; import { NgReduxFormConnectModule } from './connect'; import { NgReduxFormConnectArrayModule } from './connect-array'; diff --git a/packages/form/source/shims.ts b/packages/form/source/shims.ts index eac49453..5e0dc6e3 100644 --- a/packages/form/source/shims.ts +++ b/packages/form/source/shims.ts @@ -1,10 +1,10 @@ import { + CheckboxControlValueAccessor, ControlContainer, ControlValueAccessor, - CheckboxControlValueAccessor, + RadioControlValueAccessor, SelectControlValueAccessor, SelectMultipleControlValueAccessor, - RadioControlValueAccessor, } from '@angular/forms'; export function controlPath(name: string, parent: ControlContainer): string[] { diff --git a/packages/form/source/state.ts b/packages/form/source/state.ts index b431da0c..1233d149 100644 --- a/packages/form/source/state.ts +++ b/packages/form/source/state.ts @@ -13,24 +13,22 @@ export interface Operations<T> { update(key: number | string | null, value: T): any; } -export interface TraverseCallback { - ( - parent: any, - key: number | string, - remainingPath: string[], - value?: any, - ): any; -} +export type TraverseCallback = ( + parent: any, + key: number | string, + remainingPath: string[], + value?: any, +) => any; export abstract class State { - static traverse<State>(state: State, path: string[], fn?: TraverseCallback) { + static traverse<StateType>(state: StateType, path: string[], fn?: TraverseCallback) { let deepValue = state; for (const k of path) { const parent = deepValue; if (Iterable.isIterable(deepValue)) { - const m = <ImmutableMap<string, any>>(<any>deepValue); + const m = (deepValue as any) as ImmutableMap<string, any>; if (typeof m.get === 'function') { deepValue = m.get(k); } else { @@ -39,7 +37,7 @@ export abstract class State { ); } } else if (deepValue instanceof Map) { - deepValue = (<Map<string, any>>(<any>deepValue)).get(k); + deepValue = ((deepValue as any) as Map<string, any>).get(k); } else { deepValue = (deepValue as any)[k]; } @@ -69,11 +67,11 @@ export abstract class State { return deepValue; } - static get<State>(state: State, path: string[]): any { + static get<StateType>(state: StateType, path: string[]): any { return State.traverse(state, path); } - static assign<State>(state: State, path: string[], value?: any) { + static assign<StateType>(state: StateType, path: string[], value?: any) { const operations = State.inspect(state); if (path.length === 0) { @@ -104,16 +102,16 @@ export abstract class State { : innerOperations.merge(null, value), ); } else { - const getProbableType = (key: string | number) => { + const getProbableType = (stateKey: string | number) => { // NOTE(cbond): If your code gets here, you might not be using the library /// correctly. If you are assigning into a path in your state, try to /// ensure that there is a path to traverse, even if everything is just /// empty objects and arrays. If we have to guess the type of the containers /// and then create them ourselves, we may not get the types right. Use /// the Redux `initial state' construct to resolve this issue if you like. - return typeof key === 'number' + return typeof stateKey === 'number' ? new Array() - : Array.isArray(key) + : Array.isArray(stateKey) ? ImmutableMap() : new Object(); }; @@ -133,6 +131,7 @@ export abstract class State { static inspect<K>(object: K): Operations<K> { const metaOperations = ( + // TODO: Write proper type declarations for following Function types update: Function, merge: Function, clone?: Function, @@ -141,7 +140,7 @@ export abstract class State { /// Clone the object (shallow) clone: typeof clone === 'function' - ? () => clone(<any>object) as any + ? () => clone(object as any) as any : () => object, /// Update a specific key inside of the container object @@ -211,25 +210,25 @@ export abstract class State { if (key != null) { return parent.set(key, value); } else { - const m = new Map(<any>value); + const m = new Map(value as any); parent.clear(); - m.forEach((value, index) => parent.set(index, value)); + m.forEach((mapValue, index) => parent.set(index, mapValue)); return parent; } }, // Merge (parent: Map<string, any>, _: any, value: K) => { - const m = new Map<string, any>(<any>value); - m.forEach((value, key) => parent.set(key, value)); + const m = new Map<string, any>(value as any); + m.forEach((mapValue, key) => parent.set(key, mapValue)); return parent; }, // Clone () => object instanceof WeakMap - ? new WeakMap<Object, any>(<any>object) - : new Map<string, any>(<any>object), + ? new WeakMap<object, any>(object as any) + : new Map<string, any>(object as any), ); } else if (object instanceof WeakSet || object instanceof Set) { return metaOperations( @@ -238,8 +237,8 @@ export abstract class State { if (key != null) { return parent.set(key, value); } else { - const s = new Set(<any>value); - s.forEach((value, index) => parent.set(index, value)); + const s = new Set(value as any); + s.forEach((setValue, index) => parent.set(index, setValue)); s.clear(); return parent; } @@ -256,8 +255,8 @@ export abstract class State { // Clone () => object instanceof WeakSet - ? new WeakSet<any>(<any>object) - : new Set<any>(<any>object), + ? new WeakSet<any>(object as any) + : new Set<any>(object as any), ); } else if (object instanceof Date) { throw new FormException( @@ -279,9 +278,9 @@ export abstract class State { return metaOperations( (parent: any, key: any, value: K) => { if (key != null) { - return Object.assign(parent, { [key]: value }); + return { ...parent, [key]: value }; } - return Object.assign(parent, value); + return { ...parent, ...value as any }; }, (parent: any, _: any, value: K) => { for (const k of Object.keys(value)) { @@ -289,7 +288,7 @@ export abstract class State { } return parent; }, - () => Object.assign({}, object), + () => ({ ...object as any }), ); default: break; diff --git a/packages/router/.travis.yml b/packages/router/.travis.yml deleted file mode 100644 index 0563be43..00000000 --- a/packages/router/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: node_js -node_js: - - "6" -install: - npm i -script: - npm run build diff --git a/packages/router/src/index.ts b/packages/router/src/index.ts index 7e945478..cbb602ae 100644 --- a/packages/router/src/index.ts +++ b/packages/router/src/index.ts @@ -1,8 +1,7 @@ -import { ModuleWithProviders } from '@angular/core'; -import { NgModule } from '@angular/core'; -import { NgReduxRouter } from './router'; -import { RouterAction, routerReducer } from './reducer'; +import { ModuleWithProviders, NgModule } from '@angular/core'; import { UPDATE_LOCATION } from './actions'; +import { RouterAction, routerReducer } from './reducer'; +import { NgReduxRouter } from './router'; @NgModule() export class NgReduxRouterModule { diff --git a/packages/router/src/router.ts b/packages/router/src/router.ts index 56bf844a..f600cf92 100644 --- a/packages/router/src/router.ts +++ b/packages/router/src/router.ts @@ -1,25 +1,22 @@ -import { map, filter, distinctUntilChanged } from 'rxjs/operators'; -import { Injectable, ApplicationRef } from '@angular/core'; +import { NgRedux } from '@angular-redux/store'; import { Location } from '@angular/common'; +import { ApplicationRef, Injectable } from '@angular/core'; import { - Router, - NavigationEnd, - NavigationCancel, DefaultUrlSerializer, + NavigationCancel, + NavigationEnd, + Router, } from '@angular/router'; -import { NgRedux } from '@angular-redux/store'; import { Observable, Subscription } from 'rxjs'; +import { distinctUntilChanged, filter, map } from 'rxjs/operators'; import { UPDATE_LOCATION } from './actions'; -import { RouterAction, DefaultRouterState } from './reducer'; +import { DefaultRouterState, RouterAction } from './reducer'; @Injectable() export class NgReduxRouter { private initialized = false; private currentLocation?: string; private initialLocation?: string; - - private selectLocationFromState: (state: any) => string = state => - state.router; private urlState?: Observable<string>; private urlStateSubscription?: Subscription; @@ -66,7 +63,7 @@ export class NgReduxRouter { */ initialize( selectLocationFromState: (state: any) => string = state => state.router, - urlState$: Observable<string> | undefined = undefined, + urlState$?: Observable<string> | undefined, ) { if (this.initialized) { throw new Error( @@ -83,6 +80,9 @@ export class NgReduxRouter { this.initialized = true; } + private selectLocationFromState: (state: any) => string = state => + state.router; + private getDefaultUrlStateObservable() { return this.router.events.pipe( filter(event => event instanceof NavigationEnd), @@ -112,13 +112,13 @@ export class NgReduxRouter { // Fetch initial location from store and make sure // we dont dispath an event if the current url equals // the initial url. - let locationFromStore = this.getLocationFromStore(); + const locationFromStore = this.getLocationFromStore(); if (locationFromStore === this.currentLocation) { return; } } - this.ngRedux.dispatch(<RouterAction>{ + this.ngRedux.dispatch({ type: UPDATE_LOCATION, payload: location, }); @@ -136,7 +136,7 @@ export class NgReduxRouter { return; } - let locationInStore = this.getLocationFromStore(true); + const locationInStore = this.getLocationFromStore(true); if (this.currentLocation === locationInStore) { // Dont change router location if its equal to the one in the store. return; diff --git a/packages/store/circle.yml b/packages/store/circle.yml deleted file mode 100644 index 30ca0da8..00000000 --- a/packages/store/circle.yml +++ /dev/null @@ -1,19 +0,0 @@ -machine: - environment: - PATH: "${PATH}:${HOME}/${CIRCLE_PROJECT_REPONAME}/node_modules/.bin" - node: - version: 8.9.1 - -dependencies: - override: - - yarn - cache_directories: - - ~/.cache/yarn - -test: - override: - - yarn ci - -general: - artifacts: - - "./coverage" diff --git a/packages/store/package.json b/packages/store/package.json index 247270c2..25c8a3b4 100644 --- a/packages/store/package.json +++ b/packages/store/package.json @@ -52,9 +52,8 @@ "build": "npm run build:src && npm run build:testing", "build:src": "ngc -p tsconfig.build.json", "build:testing": "ngc -p tsconfig.testing.json", - "lint": "tslint 'src/**/*.ts'", - "prepublish": "npm run lint && npm run build && npm test", - "ci": "npm run lint && npm run build && npm test", + "prepublish": "npm run build && npm test", + "ci": "npm run build && npm test", "predoc": "rimraf docs", "doc": "typedoc --out docs --excludeExternals --excludePrivate --excludeNotExported -theme minimal --sourcefile-url-prefix \"https://github.com/angular-redux/store/blob/master/src/\" --name @angular-redux/store --mode file --module commonjs --tsconfig tsconfig.docs.json src" }, @@ -79,9 +78,6 @@ "rimraf": "2.6.2", "rxjs": "6.2.1", "symbol-observable": "1.2.0", - "ts-node": "6.2.0", - "tsconfig-paths": "3.4.2", - "tslint": "5.10.0", "typedoc": "0.11.1", "typedoc-plugin-sourcefile-url": "1.0.3", "typescript": "2.7.2", diff --git a/packages/store/src/components/dev-tools.ts b/packages/store/src/components/dev-tools.ts index e44e30f9..021244d6 100644 --- a/packages/store/src/components/dev-tools.ts +++ b/packages/store/src/components/dev-tools.ts @@ -1,6 +1,7 @@ -import { Injectable, ApplicationRef } from '@angular/core'; +import { ApplicationRef, Injectable, NgZone } from '@angular/core'; +import { Unsubscribe } from 'redux'; import { NgRedux } from './ng-redux'; -import { NgZone } from '@angular/core'; + declare const window: any; const environment: any = typeof window !== 'undefined' ? window : {}; @@ -21,8 +22,8 @@ export class DevToolsExtension { * format as described here: * [zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md] */ - enhancer = (options?: Object) => { - let subscription: Function; + enhancer = (options?: object) => { + let subscription: Unsubscribe; if (!this.isEnabled()) { return null; } diff --git a/packages/store/src/components/fractal-reducer-map.ts b/packages/store/src/components/fractal-reducer-map.ts index 16a2e386..af324537 100644 --- a/packages/store/src/components/fractal-reducer-map.ts +++ b/packages/store/src/components/fractal-reducer-map.ts @@ -1,7 +1,7 @@ import { AnyAction, Reducer } from 'redux'; -import { PathSelector } from './selectors'; -import { setIn } from '../utils/set-in'; import { getIn } from '../utils/get-in'; +import { setIn } from '../utils/set-in'; +import { PathSelector } from './selectors'; let reducerMap: { [id: string]: Reducer<any, AnyAction> } = {}; diff --git a/packages/store/src/components/ng-redux.ts b/packages/store/src/components/ng-redux.ts index 0f6f99da..48d6b29d 100644 --- a/packages/store/src/components/ng-redux.ts +++ b/packages/store/src/components/ng-redux.ts @@ -1,15 +1,15 @@ import { AnyAction, - Reducer, Dispatch, - Unsubscribe, Middleware, + Reducer, Store, StoreEnhancer, + Unsubscribe, } from 'redux'; import { Observable } from 'rxjs'; import { ObservableStore } from './observable-store'; -import { Selector, PathSelector, Comparator } from './selectors'; +import { Comparator, PathSelector, Selector } from './selectors'; /** * This is the public interface of @angular-redux/store. It wraps the global diff --git a/packages/store/src/components/observable-store.ts b/packages/store/src/components/observable-store.ts index 25f98503..1f5d342c 100644 --- a/packages/store/src/components/observable-store.ts +++ b/packages/store/src/components/observable-store.ts @@ -1,6 +1,6 @@ -import { Store, Reducer, AnyAction } from 'redux'; +import { AnyAction, Reducer, Store } from 'redux'; import { Observable } from 'rxjs'; -import { Selector, PathSelector, Comparator } from './selectors'; +import { Comparator, PathSelector, Selector } from './selectors'; /** * This interface represents the glue that connects the diff --git a/packages/store/src/components/root-store.spec.ts b/packages/store/src/components/root-store.spec.ts index 6f83b27e..e8b86ddd 100644 --- a/packages/store/src/components/root-store.spec.ts +++ b/packages/store/src/components/root-store.spec.ts @@ -1,12 +1,12 @@ import { NgZone } from '@angular/core'; -import { createStore, Reducer, Action, AnyAction, Store } from 'redux'; +import { Action, AnyAction, createStore, Reducer, Store } from 'redux'; import { Observable } from 'rxjs'; import { combineLatest, filter } from 'rxjs/operators'; +import { select } from '../decorators/select'; import { NgRedux } from './ng-redux'; import { RootStore } from './root-store'; -import { select } from '../decorators/select'; class MockNgZone extends NgZone { run<T>(fn: (...args: any[]) => T): T { @@ -17,16 +17,16 @@ class MockNgZone extends NgZone { type PayloadAction = Action & { payload?: string | number }; describe('NgRedux Observable Store', () => { - interface IAppState { + interface AppState { foo: string; bar: string; baz: number; } - let defaultState: IAppState; - let rootReducer: Reducer<IAppState, AnyAction>; - let store: Store<IAppState>; - let ngRedux: NgRedux<IAppState>; + let defaultState: AppState; + let rootReducer: Reducer<AppState, AnyAction>; + let store: Store<AppState>; + let ngRedux: NgRedux<AppState>; const mockNgZone = new MockNgZone({ enableLongStackTrace: false }) as NgZone; beforeEach(() => { @@ -39,18 +39,18 @@ describe('NgRedux Observable Store', () => { rootReducer = (state = defaultState, action: PayloadAction) => { switch (action.type) { case 'UPDATE_FOO': - return Object.assign({}, state, { foo: action.payload }); + return { ...state, foo: action.payload }; case 'UPDATE_BAZ': - return Object.assign({}, state, { baz: action.payload }); + return { ...state, baz: action.payload }; case 'UPDATE_BAR': - return Object.assign({}, state, { bar: action.payload }); + return { ...state, bar: action.payload }; default: return state; } }; store = createStore(rootReducer); - ngRedux = new RootStore<IAppState>(mockNgZone); + ngRedux = new RootStore<AppState>(mockNgZone); ngRedux.configureStore(rootReducer, defaultState); }); @@ -63,7 +63,7 @@ describe('NgRedux Observable Store', () => { }); it('should get the initial state', done => - ngRedux.select<any>().subscribe((state: IAppState) => { + ngRedux.select<any>().subscribe((state: AppState) => { expect(state.foo).toEqual('bar'); expect(state.baz).toEqual(-1); done(); @@ -137,16 +137,16 @@ describe('NgRedux Observable Store', () => { expect(spy.calls.count()).toEqual(3); }); - it(`should accept a custom compare function`, () => { - interface IRecord { + it('should accept a custom compare function', () => { + interface Record { data?: string; } - let fooData: IRecord = {}; + let fooData: Record = {}; const spy = jasmine .createSpy('spy') - .and.callFake((data: IRecord) => (fooData = data)); - const cmp = (a: IRecord, b: IRecord) => a.data === b.data; + .and.callFake((data: Record) => (fooData = data)); + const cmp = (a: Record, b: Record) => a.data === b.data; ngRedux .select(state => ({ data: `${state.foo}-${state.baz}` }), cmp) @@ -168,10 +168,10 @@ describe('NgRedux Observable Store', () => { expect(spy.calls.count()).toEqual(3); }); - it(`should only call provided select function if state changed`, () => { + it('should only call provided select function if state changed', () => { const selectSpy = jasmine .createSpy('selectSpy') - .and.callFake((state: IAppState) => state.foo); + .and.callFake((state: AppState) => state.foo); ngRedux.select().subscribe(selectSpy); @@ -193,18 +193,19 @@ describe('NgRedux Observable Store', () => { }); it('should wait until store is configured before emitting values', () => { + // tslint:disable-next-line:max-classes-per-file class SomeService { foo: string; bar: string; baz: number; - constructor(_ngRedux: NgRedux<any>) { - _ngRedux.select(n => n.foo).subscribe(foo => (this.foo = foo)); - _ngRedux.select(n => n.bar).subscribe(bar => (this.bar = bar)); - _ngRedux.select(n => n.baz).subscribe(baz => (this.baz = baz)); + constructor(stateStore: NgRedux<any>) { + stateStore.select(n => n.foo).subscribe(foo => (this.foo = foo)); + stateStore.select(n => n.bar).subscribe(bar => (this.bar = bar)); + stateStore.select(n => n.baz).subscribe(baz => (this.baz = baz)); } } - ngRedux = new RootStore<IAppState>(mockNgZone); + ngRedux = new RootStore<AppState>(mockNgZone); const someService = new SomeService(ngRedux); ngRedux.configureStore(rootReducer, defaultState); @@ -214,13 +215,14 @@ describe('NgRedux Observable Store', () => { }); it('should have select decorators work before store is configured', done => { + // tslint:disable-next-line:max-classes-per-file class SomeService { @select() foo$: Observable<string>; @select() bar$: Observable<string>; @select() baz$: Observable<number>; } - ngRedux = new RootStore<IAppState>(mockNgZone); + ngRedux = new RootStore<AppState>(mockNgZone); const someService = new SomeService(); someService.foo$ @@ -237,14 +239,14 @@ describe('NgRedux Observable Store', () => { }); describe('Chained actions in subscriptions', () => { - interface IAppState { + interface AppState { keyword: string; keywordLength: number; } - let defaultState: IAppState; - let rootReducer: Reducer<IAppState, AnyAction>; - let ngRedux: NgRedux<IAppState>; + let defaultState: AppState; + let rootReducer: Reducer<AppState, AnyAction>; + let ngRedux: NgRedux<AppState>; const mockNgZone = new MockNgZone({ enableLongStackTrace: false }) as NgZone; const doSearch = (word: string) => @@ -261,20 +263,20 @@ describe('Chained actions in subscriptions', () => { rootReducer = (state = defaultState, action: PayloadAction) => { switch (action.type) { case 'SEARCH': - return Object.assign({}, state, { keyword: action.payload }); + return { ...state, keyword: action.payload }; case 'SEARCH_RESULT': - return Object.assign({}, state, { keywordLength: action.payload }); + return { ...state, keywordLength: action.payload }; default: return state; } }; - ngRedux = new RootStore<IAppState>(mockNgZone); + ngRedux = new RootStore<AppState>(mockNgZone); ngRedux.configureStore(rootReducer, defaultState); }); describe('dispatching an action in a keyword$ before length$ happens', () => { - it(`length sub should be called twice`, () => { + it('length sub should be called twice', () => { const keyword$ = ngRedux.select(n => n.keyword); let keyword = ''; let length = 0; @@ -305,7 +307,7 @@ describe('Chained actions in subscriptions', () => { lenSub.unsubscribe(); }); - it(`second sub should get most current state value`, () => { + it('second sub should get most current state value', () => { const keyword$ = ngRedux.select(n => n.keyword); let keyword = ''; let length = 0; @@ -337,7 +339,7 @@ describe('Chained actions in subscriptions', () => { }); describe('dispatching an action in a keyword$ after length$ happens', () => { - it(`length sub should be called twice`, () => { + it('length sub should be called twice', () => { const keyword$ = ngRedux.select(n => n.keyword); let keyword = ''; let length = 0; @@ -367,7 +369,7 @@ describe('Chained actions in subscriptions', () => { lenSub.unsubscribe(); }); - it(`first sub should get most current state value`, () => { + it('first sub should get most current state value', () => { const keyword$ = ngRedux.select(n => n.keyword); let keyword = ''; let length = 0; diff --git a/packages/store/src/components/root-store.ts b/packages/store/src/components/root-store.ts index f364be35..313621a7 100644 --- a/packages/store/src/components/root-store.ts +++ b/packages/store/src/components/root-store.ts @@ -1,41 +1,41 @@ import { - Store, AnyAction, - Reducer, - Middleware, - StoreEnhancer, - Unsubscribe, - createStore, applyMiddleware, compose, + createStore, Dispatch, + Middleware, + Reducer, + Store, + StoreEnhancer, + Unsubscribe, } from 'redux'; import { NgZone } from '@angular/core'; import { BehaviorSubject, Observable, Observer } from 'rxjs'; import { distinctUntilChanged, filter, map, switchMap } from 'rxjs/operators'; +import { assert } from '../utils/assert'; +import { enableFractalReducers } from './fractal-reducer-map'; import { NgRedux } from './ng-redux'; +import { ObservableStore } from './observable-store'; import { - Selector, - PathSelector, Comparator, + PathSelector, resolveToFunctionSelector, + Selector, } from './selectors'; -import { assert } from '../utils/assert'; import { SubStore } from './sub-store'; -import { enableFractalReducers } from './fractal-reducer-map'; -import { ObservableStore } from './observable-store'; /** @hidden */ export class RootStore<RootState> extends NgRedux<RootState> { - private _store: Store<RootState> | undefined = undefined; - private _store$: BehaviorSubject<RootState>; + private store: Store<RootState> | undefined = undefined; + private store$: BehaviorSubject<RootState>; constructor(private ngZone: NgZone) { super(); NgRedux.instance = this; - this._store$ = new BehaviorSubject<RootState | undefined>(undefined).pipe( + this.store$ = new BehaviorSubject<RootState | undefined>(undefined).pipe( filter(n => n !== undefined), switchMap(observableStore => observableStore as any), // TODO: fix this? needing to explicitly cast this is wrong @@ -48,7 +48,7 @@ export class RootStore<RootState> extends NgRedux<RootState> { middleware: Middleware[] = [], enhancers: StoreEnhancer<RootState>[] = [], ): void => { - assert(!this._store, 'Store already configured!'); + assert(!this.store, 'Store already configured!'); // Variable-arity compose in typescript FTW. this.setStore( @@ -59,31 +59,31 @@ export class RootStore<RootState> extends NgRedux<RootState> { }; provideStore = (store: Store<RootState>) => { - assert(!this._store, 'Store already configured!'); + assert(!this.store, 'Store already configured!'); this.setStore(store); }; - getState = (): RootState => this._store!.getState(); + getState = (): RootState => this.store!.getState(); subscribe = (listener: () => void): Unsubscribe => - this._store!.subscribe(listener); + this.store!.subscribe(listener); replaceReducer = (nextReducer: Reducer<RootState, AnyAction>): void => { - this._store!.replaceReducer(nextReducer); + this.store!.replaceReducer(nextReducer); }; dispatch: Dispatch<AnyAction> = <A extends AnyAction>(action: A): A => { assert( - !!this._store, + !!this.store, 'Dispatch failed: did you forget to configure your store? ' + 'https://github.com/angular-redux/@angular-redux/core/blob/master/' + 'README.md#quick-start', ); if (!NgZone.isInAngularZone()) { - return this.ngZone.run(() => this._store!.dispatch(action)); + return this.ngZone.run(() => this.store!.dispatch(action)); } else { - return this._store!.dispatch(action); + return this.store!.dispatch(action); } }; @@ -91,7 +91,7 @@ export class RootStore<RootState> extends NgRedux<RootState> { selector?: Selector<RootState, SelectedType>, comparator?: Comparator, ): Observable<SelectedType> => - this._store$.pipe( + this.store$.pipe( distinctUntilChanged(), map(resolveToFunctionSelector(selector)), distinctUntilChanged(comparator), @@ -104,9 +104,9 @@ export class RootStore<RootState> extends NgRedux<RootState> { new SubStore<SubState>(this, basePath, localReducer); private setStore(store: Store<RootState>) { - this._store = store; + this.store = store; const storeServable = this.storeToObservable(store); - this._store$.next(storeServable as any); + this.store$.next(storeServable as any); } private storeToObservable = ( diff --git a/packages/store/src/components/selectors.ts b/packages/store/src/components/selectors.ts index bbada81e..fe0bd4f5 100644 --- a/packages/store/src/components/selectors.ts +++ b/packages/store/src/components/selectors.ts @@ -1,5 +1,5 @@ -import { getIn } from '../utils/get-in'; import { Observable } from 'rxjs'; +import { getIn } from '../utils/get-in'; /** * Custom equality checker that can be used with `.select` and `@select`. diff --git a/packages/store/src/components/sub-store.spec.ts b/packages/store/src/components/sub-store.spec.ts index 74f112b4..9dbcac3a 100644 --- a/packages/store/src/components/sub-store.spec.ts +++ b/packages/store/src/components/sub-store.spec.ts @@ -1,9 +1,9 @@ import { NgZone } from '@angular/core'; import { Action, AnyAction } from 'redux'; -import { RootStore } from './root-store'; +import { take, toArray } from 'rxjs/operators'; import { NgRedux } from './ng-redux'; import { ObservableStore } from './observable-store'; -import { take, toArray } from 'rxjs/operators'; +import { RootStore } from './root-store'; class MockNgZone extends NgZone { run<T>(fn: (...args: any[]) => T): T { @@ -11,15 +11,15 @@ class MockNgZone extends NgZone { } } -interface ISubState { +interface SubState { wat: { quux: number; }; } -interface IAppState { +interface AppState { foo: { - bar: ISubState; + bar: SubState; }; } @@ -27,11 +27,11 @@ describe('Substore', () => { const defaultReducer = (state: any, _: Action) => state; const basePath = ['foo', 'bar']; - let ngRedux: NgRedux<IAppState>; - let subStore: ObservableStore<ISubState>; + let ngRedux: NgRedux<AppState>; + let subStore: ObservableStore<SubState>; beforeEach(() => { - ngRedux = new RootStore<IAppState>(new MockNgZone({ + ngRedux = new RootStore<AppState>(new MockNgZone({ enableLongStackTrace: false, }) as NgZone); ngRedux.configureStore(defaultReducer, { @@ -40,7 +40,7 @@ describe('Substore', () => { }, }); - subStore = ngRedux.configureSubStore<ISubState>(basePath, defaultReducer); + subStore = ngRedux.configureSubStore<SubState>(basePath, defaultReducer); }); it('adds a key to actions it dispatches', () => @@ -56,7 +56,7 @@ describe('Substore', () => { subStore.select('wat').subscribe(wat => expect(wat).toEqual({ quux: 3 })); }); - it(`handles property selection on a base path that doesn't exist yet`, () => { + it("handles property selection on a base path that doesn't exist yet", () => { const nonExistentSubStore = ngRedux.configureSubStore( ['sure', 'whatever'], (state: any, action: any) => ({ ...state, value: action.newValue }), @@ -74,7 +74,7 @@ describe('Substore', () => { }); }); - it(`handles path selection on a base path that doesn't exist yet`, () => { + it("handles path selection on a base path that doesn't exist yet", () => { const nonExistentSubStore = ngRedux.configureSubStore( ['sure', 'whatever'], (state: any, action: any) => ({ ...state, value: action.newValue }), @@ -92,7 +92,7 @@ describe('Substore', () => { }); }); - it(`handles function selection on a base path that doesn't exist yet`, () => { + it("handles function selection on a base path that doesn't exist yet", () => { const nonExistentSubStore = ngRedux.configureSubStore( ['sure', 'whatever'], (state: any, action: any) => ({ ...state, value: action.newValue }), diff --git a/packages/store/src/components/sub-store.ts b/packages/store/src/components/sub-store.ts index 0b29db49..fc030ac2 100644 --- a/packages/store/src/components/sub-store.ts +++ b/packages/store/src/components/sub-store.ts @@ -3,18 +3,18 @@ import { Observable } from 'rxjs'; import { distinctUntilChanged, map } from 'rxjs/operators'; import { getIn } from '../utils/get-in'; -import { - PathSelector, - Selector, - Comparator, - resolveToFunctionSelector, -} from './selectors'; -import { NgRedux } from './ng-redux'; -import { ObservableStore } from './observable-store'; import { registerFractalReducer, replaceLocalReducer, } from './fractal-reducer-map'; +import { NgRedux } from './ng-redux'; +import { ObservableStore } from './observable-store'; +import { + Comparator, + PathSelector, + resolveToFunctionSelector, + Selector, +} from './selectors'; /** @hidden */ export class SubStore<State> implements ObservableStore<State> { @@ -27,11 +27,10 @@ export class SubStore<State> implements ObservableStore<State> { } dispatch: Dispatch<AnyAction> = action => - this.rootStore.dispatch( - Object.assign({}, action, { - '@angular-redux::fractalkey': JSON.stringify(this.basePath), - }), - ); + this.rootStore.dispatch({ + ...action as any, + '@angular-redux::fractalkey': JSON.stringify(this.basePath), + }); getState = (): State => getIn(this.rootStore.getState(), this.basePath); diff --git a/packages/store/src/decorators/dispatch.spec.ts b/packages/store/src/decorators/dispatch.spec.ts index 6f59ca0b..2a9ca7c0 100644 --- a/packages/store/src/decorators/dispatch.spec.ts +++ b/packages/store/src/decorators/dispatch.spec.ts @@ -1,5 +1,5 @@ -import { Reducer, Action, AnyAction } from 'redux'; import { NgZone } from '@angular/core'; +import { Action, AnyAction, Reducer } from 'redux'; import { NgRedux } from '../components/ng-redux'; import { ObservableStore } from '../components/observable-store'; import { RootStore } from '../components/root-store'; @@ -12,18 +12,18 @@ class MockNgZone extends NgZone { } } -interface IAppState { +interface AppState { value: string; instanceProperty?: string; } -type PayloadAction = Action & { payload?: IAppState }; +type PayloadAction = Action & { payload?: AppState }; describe('@dispatch', () => { let ngRedux; const mockNgZone = new MockNgZone({ enableLongStackTrace: false }) as NgZone; - let defaultState: IAppState; - let rootReducer: Reducer<IAppState, AnyAction>; + let defaultState: AppState; + let rootReducer: Reducer<AppState, AnyAction>; beforeEach(() => { defaultState = { @@ -36,7 +36,7 @@ describe('@dispatch', () => { case 'TEST': const { value = null, instanceProperty = null } = action.payload || {}; - return Object.assign({}, state, { value, instanceProperty }); + return { ...state, value, instanceProperty }; case 'CONDITIONAL_DISPATCH_TEST': return { ...state, ...action.payload }; default: @@ -50,6 +50,7 @@ describe('@dispatch', () => { }); describe('on the RootStore', () => { + // tslint:disable-next-line:max-classes-per-file class TestClass { instanceProperty = 'test'; @@ -122,7 +123,7 @@ describe('@dispatch', () => { }); it('should call dispatch with result of function normally', () => { - const result = <PayloadAction>instance.conditionalDispatchMethod(true); + const result = instance.conditionalDispatchMethod(true) as PayloadAction; expect(result.type).toBe('CONDITIONAL_DISPATCH_TEST'); expect(result.payload && result.payload.value).toBe( 'Conditional Dispatch Action', @@ -190,6 +191,8 @@ describe('@dispatch', () => { describe('On a substore', () => { const localReducer = (state: any, _: Action) => state; + + // tslint:disable-next-line:max-classes-per-file @WithSubStore({ basePathMethodName: 'getBasePath', localReducer, diff --git a/packages/store/src/decorators/dispatch.ts b/packages/store/src/decorators/dispatch.ts index 5d5ef757..e26169df 100644 --- a/packages/store/src/decorators/dispatch.ts +++ b/packages/store/src/decorators/dispatch.ts @@ -9,11 +9,11 @@ import { getBaseStore } from './helpers'; */ export function dispatch(): PropertyDecorator { return function decorate( - target: Object, + target: object, key: string | symbol | number, descriptor?: PropertyDescriptor, ): PropertyDescriptor { - let originalMethod: Function; + let originalMethod: () => void; const wrapped = function(this: any, ...args: any[]) { const result = originalMethod.apply(this, args); diff --git a/packages/store/src/decorators/helpers.ts b/packages/store/src/decorators/helpers.ts index d8cc1c41..69f79c64 100644 --- a/packages/store/src/decorators/helpers.ts +++ b/packages/store/src/decorators/helpers.ts @@ -1,13 +1,13 @@ -import { Reducer, AnyAction } from 'redux'; +import { AnyAction, Reducer } from 'redux'; +import { distinctUntilChanged } from 'rxjs/operators'; import { NgRedux } from '../components/ng-redux'; import { ObservableStore } from '../components/observable-store'; import { - Selector, - PathSelector, Comparator, + PathSelector, + Selector, Transformer, } from '../components/selectors'; -import { distinctUntilChanged } from 'rxjs/operators'; /** * Used with the `@WithSubStore` class decorator to define a SubStore (AKA a @@ -16,7 +16,7 @@ import { distinctUntilChanged } from 'rxjs/operators'; * For more info on substores, see * https://github.com/angular-redux/store/blob/master/articles/fractal-store.md */ -export interface IFractalStoreOptions { +export interface FractalStoreOptions { /** * The name of an instance method that will define the * base path for the subStore. This method is expected to return an array @@ -59,13 +59,13 @@ const INSTANCE_SELECTIONS_KEY = */ const INSTANCE_BASE_PATH_KEY = '@angular-redux::substore::instance::basepath'; -const getClassOptions = (decoratedInstance: any): IFractalStoreOptions => +const getClassOptions = (decoratedInstance: any): FractalStoreOptions => decoratedInstance.constructor[OPTIONS_KEY]; /** @hidden */ export const setClassOptions = ( decoratedClassConstructor: any, - options: IFractalStoreOptions, + options: FractalStoreOptions, ): void => { decoratedClassConstructor[OPTIONS_KEY] = options; }; diff --git a/packages/store/src/decorators/select.spec.ts b/packages/store/src/decorators/select.spec.ts index e94dbe4f..10e46ec5 100644 --- a/packages/store/src/decorators/select.spec.ts +++ b/packages/store/src/decorators/select.spec.ts @@ -1,3 +1,5 @@ +// tslint:disable:max-classes-per-file + import { NgZone } from '@angular/core'; import { Action } from 'redux'; @@ -8,7 +10,7 @@ import { NgRedux } from '../components/ng-redux'; import { RootStore } from '../components/root-store'; import { select, select$ } from './select'; -interface IAppState { +interface AppState { foo: string; baz: number; } @@ -20,23 +22,22 @@ class MockNgZone { } describe('Select decorators', () => { - let ngRedux: NgRedux<IAppState>; + let ngRedux: NgRedux<AppState>; const mockNgZone = (new MockNgZone() as any) as NgZone; const defaultState = { foo: 'bar', baz: -1 }; const rootReducer = (state = defaultState, action: PayloadAction) => - action.payload ? Object.assign({}, state, { baz: action.payload }) : state; + action.payload ? { ...state, baz: action.payload } : state; beforeEach(() => { - ngRedux = new RootStore<IAppState>(mockNgZone); + ngRedux = new RootStore<AppState>(mockNgZone); NgRedux.instance = ngRedux; ngRedux.configureStore(rootReducer, defaultState); }); describe('@select', () => { describe('when passed no arguments', () => { - // tslint:disable-next-line:max-line-length it('binds to a store property that matches the name of the class property', done => { class MockClass { @select() baz: Observable<number>; @@ -56,7 +57,6 @@ describe('Select decorators', () => { ngRedux.dispatch({ type: 'nvm', payload: 1 }); }); - // tslint:disable-next-line:max-line-length it('binds by name ignoring any $ characters in the class property name', done => { class MockClass { @select() baz$: Observable<number>; @@ -78,7 +78,6 @@ describe('Select decorators', () => { }); describe('when passed a string', () => { - // tslint:disable-next-line:max-line-length it('binds to the store property whose name matches the string value', done => { class MockClass { @select('baz') obs$: Observable<number>; @@ -101,7 +100,7 @@ describe('Select decorators', () => { describe('when passed a function', () => { it('attempts to use that function as the selector function', done => { - const selector = (state: IAppState) => state.baz * 2; + const selector = (state: AppState) => state.baz * 2; class MockClass { @select(selector) obs$: Observable<number>; } diff --git a/packages/store/src/decorators/select.ts b/packages/store/src/decorators/select.ts index 485b1405..364815cb 100644 --- a/packages/store/src/decorators/select.ts +++ b/packages/store/src/decorators/select.ts @@ -1,4 +1,4 @@ -import { Selector, Comparator, Transformer } from '../components/selectors'; +import { Comparator, Selector, Transformer } from '../components/selectors'; import { getInstanceSelection } from './helpers'; /** diff --git a/packages/store/src/decorators/with-sub-store.spec.ts b/packages/store/src/decorators/with-sub-store.spec.ts index 2b480b14..aa5b9af1 100644 --- a/packages/store/src/decorators/with-sub-store.spec.ts +++ b/packages/store/src/decorators/with-sub-store.spec.ts @@ -1,16 +1,17 @@ -import { NgZone, Component, Injectable } from '@angular/core'; -import { Action } from 'redux'; +// tslint:disable:max-classes-per-file +import { Component, Injectable, NgZone } from '@angular/core'; +import { Action } from 'redux'; import { Observable } from 'rxjs'; import { map, take, toArray } from 'rxjs/operators'; -import { WithSubStore } from './with-sub-store'; -import { select, select$ } from './select'; -import { dispatch } from './dispatch'; -import { PathSelector } from '../components/selectors'; -import { ObservableStore } from '../components/observable-store'; import { NgRedux } from '../components/ng-redux'; +import { ObservableStore } from '../components/observable-store'; import { RootStore } from '../components/root-store'; +import { PathSelector } from '../components/selectors'; +import { dispatch } from './dispatch'; +import { select, select$ } from './select'; +import { WithSubStore } from './with-sub-store'; class MockNgZone extends NgZone { run<T>(fn: (...args: any[]) => T): T { @@ -134,7 +135,7 @@ describe('@WithSubStore', () => { @WithSubStore({ basePathMethodName, localReducer: iDontExistYetReducer }) class TestClass { @select('nonexistentkey') obs$: Observable<string>; - getSubStorePath = (): PathSelector => ['I', `don't`, 'exist', 'yet']; + getSubStorePath = (): PathSelector => ['I', "don't", 'exist', 'yet']; @dispatch() makeItExist = (newValue: string) => ({ type: 'nvm', newValue }); } @@ -145,9 +146,7 @@ describe('@WithSubStore', () => { take(2), toArray(), ) - .subscribe((v: Array<any>) => - expect(v).toEqual([undefined, 'now I exist']), - ); + .subscribe((v: any[]) => expect(v).toEqual([undefined, 'now I exist'])); testInstance.makeItExist('now I exist'); }); }); @@ -224,24 +223,24 @@ describe('@WithSubStore', () => { it('@Component', () => { @Component({ template: '<p>Wat</p>' }) @WithSubStore({ basePathMethodName, localReducer }) - class TestClass { + class TestComponent { @select() foo$: Observable<string>; getSubStorePath = (): PathSelector => ['a', 'b']; } - const testInstance = new TestClass(); + const testInstance = new TestComponent(); testInstance.foo$.pipe(take(1)).subscribe(v => expect(v).toEqual('Foo!')); }); it('@Component the other way round', () => { @WithSubStore({ basePathMethodName, localReducer }) @Component({ template: '<p>Wat</p>' }) - class TestClass { + class TestComponent { @select() foo$: Observable<string>; getSubStorePath = (): PathSelector => ['a', 'b']; } - const testInstance = new TestClass(); + const testInstance = new TestComponent(); testInstance.foo$.pipe(take(1)).subscribe(v => expect(v).toEqual('Foo!')); }); @@ -271,7 +270,6 @@ describe('@WithSubStore', () => { }); describe('with inheritance', () => { - // tslint:disable-next-line:max-line-length it('lets you select in a super class against a path from the sub class', () => { @WithSubStore({ basePathMethodName, localReducer }) class SuperClass { @@ -286,7 +284,6 @@ describe('@WithSubStore', () => { testInstance.foo$.pipe(take(1)).subscribe(v => expect(v).toEqual('Foo!')); }); - // tslint:disable-next-line:max-line-length it('lets you select in a sub class against a path from the super class', () => { @WithSubStore({ basePathMethodName, localReducer }) class SuperClass { diff --git a/packages/store/src/decorators/with-sub-store.ts b/packages/store/src/decorators/with-sub-store.ts index a7b54588..c39fd6d2 100644 --- a/packages/store/src/decorators/with-sub-store.ts +++ b/packages/store/src/decorators/with-sub-store.ts @@ -1,4 +1,4 @@ -import { IFractalStoreOptions, setClassOptions } from './helpers'; +import { FractalStoreOptions, setClassOptions } from './helpers'; /** * Modifies the behaviour of any `@select`, `@select$`, or `@dispatch` @@ -11,7 +11,7 @@ import { IFractalStoreOptions, setClassOptions } from './helpers'; export function WithSubStore({ basePathMethodName, localReducer, -}: IFractalStoreOptions): ClassDecorator { +}: FractalStoreOptions): ClassDecorator { return function decorate(constructor: Function): void { setClassOptions(constructor, { basePathMethodName, diff --git a/packages/store/src/index.ts b/packages/store/src/index.ts index 84c25cc9..cff39a77 100644 --- a/packages/store/src/index.ts +++ b/packages/store/src/index.ts @@ -1,24 +1,23 @@ +import { DevToolsExtension } from './components/dev-tools'; +import { enableFractalReducers } from './components/fractal-reducer-map'; import { NgRedux } from './components/ng-redux'; +import { ObservableStore } from './components/observable-store'; import { - Selector, + Comparator, + FunctionSelector, PathSelector, PropertySelector, - FunctionSelector, - Comparator, + Selector, Transformer, } from './components/selectors'; -import { ObservableStore } from './components/observable-store'; -import { DevToolsExtension } from './components/dev-tools'; -import { enableFractalReducers } from './components/fractal-reducer-map'; -import { select, select$ } from './decorators/select'; import { dispatch } from './decorators/dispatch'; +import { select, select$ } from './decorators/select'; import { WithSubStore } from './decorators/with-sub-store'; import { NgReduxModule } from './ng-redux.module'; // Warning: don't do this: // export * from './foo' // ... because it breaks rollup. See -// tslint:disable-next-line:max-line-length // https://github.com/rollup/rollup/wiki/Troubleshooting#name-is-not-exported-by-module export { NgRedux, diff --git a/packages/store/src/ng-redux.module.ts b/packages/store/src/ng-redux.module.ts index cdf07ef2..0f871185 100644 --- a/packages/store/src/ng-redux.module.ts +++ b/packages/store/src/ng-redux.module.ts @@ -1,7 +1,7 @@ import { NgModule, NgZone } from '@angular/core'; +import { DevToolsExtension } from './components/dev-tools'; import { NgRedux } from './components/ng-redux'; import { RootStore } from './components/root-store'; -import { DevToolsExtension } from './components/dev-tools'; /** @hidden */ export function _ngReduxFactory(ngZone: NgZone) { diff --git a/packages/store/src/utils/set-in.ts b/packages/store/src/utils/set-in.ts index dfcc3e18..fb7976a3 100644 --- a/packages/store/src/utils/set-in.ts +++ b/packages/store/src/utils/set-in.ts @@ -9,7 +9,7 @@ export const setIn = ( obj: any, [firstElem, ...restElems]: (string | number)[], value: any, -): Object => +): object => 'function' === typeof (obj[firstElem] || {}).setIn ? { ...obj, diff --git a/packages/store/testing/dev-tools.mock.ts b/packages/store/testing/dev-tools.mock.ts index 5376daab..dcb24ec2 100644 --- a/packages/store/testing/dev-tools.mock.ts +++ b/packages/store/testing/dev-tools.mock.ts @@ -1,5 +1,7 @@ -import { Injectable } from '@angular/core'; +// TODO: See if this linting rule can be enabled with new build process (ng-packagr) +// tslint:disable:no-implicit-dependencies import { DevToolsExtension } from '@angular-redux/store'; +import { Injectable } from '@angular/core'; @Injectable() export class MockDevToolsExtension extends DevToolsExtension {} diff --git a/packages/store/testing/index.ts b/packages/store/testing/index.ts index 4bf3cf84..68729499 100644 --- a/packages/store/testing/index.ts +++ b/packages/store/testing/index.ts @@ -1,5 +1,5 @@ -import { NgReduxTestingModule } from './ng-redux-testing.module'; import { MockDevToolsExtension } from './dev-tools.mock'; +import { NgReduxTestingModule } from './ng-redux-testing.module'; import { MockNgRedux } from './ng-redux.mock'; import { MockObservableStore } from './observable-store.mock'; diff --git a/packages/store/testing/ng-redux-testing.module.ts b/packages/store/testing/ng-redux-testing.module.ts index de359716..7bf87fdf 100644 --- a/packages/store/testing/ng-redux-testing.module.ts +++ b/packages/store/testing/ng-redux-testing.module.ts @@ -1,7 +1,9 @@ +// TODO: See if this linting rule can be enabled with new build process (ng-packagr) +// tslint:disable:no-implicit-dependencies +import { DevToolsExtension, NgRedux } from '@angular-redux/store'; import { NgModule } from '@angular/core'; -import { NgRedux, DevToolsExtension } from '@angular-redux/store'; -import { MockNgRedux } from './ng-redux.mock'; import { MockDevToolsExtension } from './dev-tools.mock'; +import { MockNgRedux } from './ng-redux.mock'; // Needs to be initialized early so @select's use the mocked version too. const mockNgRedux = MockNgRedux.getInstance(); diff --git a/packages/store/testing/ng-redux.mock.spec.ts b/packages/store/testing/ng-redux.mock.spec.ts index 9f1e599c..4c8a5975 100644 --- a/packages/store/testing/ng-redux.mock.spec.ts +++ b/packages/store/testing/ng-redux.mock.spec.ts @@ -24,7 +24,7 @@ // } describe('NgReduxMock', () => { - it('should have a fake test for now until we can fix them...', () => {}); + it('should have a fake test for now until we can fix them...', () => undefined); // beforeEach(() => { // TestBed.configureTestingModule({ // declarations: [TestComponent], diff --git a/packages/store/testing/ng-redux.mock.ts b/packages/store/testing/ng-redux.mock.ts index 4e091df8..8f4715c5 100644 --- a/packages/store/testing/ng-redux.mock.ts +++ b/packages/store/testing/ng-redux.mock.ts @@ -1,20 +1,22 @@ +// TODO: See if this linting rule can be enabled with new build process (ng-packagr) +// tslint:disable:no-implicit-dependencies +// tslint:disable:member-ordering import { - NgRedux, - Selector, Comparator, + NgRedux, PathSelector, + Selector, } from '@angular-redux/store'; import { AnyAction, - Reducer, Dispatch, Middleware, + Reducer, Store, StoreEnhancer, } from 'redux'; import { Observable, Subject } from 'rxjs'; import { MockObservableStore } from './observable-store.mock'; -// tslint:disable:member-ordering /** * Convenience mock to make it easier to control selector * behaviour in unit tests. @@ -23,8 +25,6 @@ export class MockNgRedux<T = {}> extends NgRedux<T> { /** @deprecated Use MockNgRedux.getInstance() instead. */ static mockInstance?: MockNgRedux<any> = undefined; - private mockRootStore = new MockObservableStore<any>(); - /** * Returns a subject that's connected to any observable returned by the * given selector. You can use this subject to pump values into your @@ -64,7 +64,7 @@ export class MockNgRedux<T = {}> extends NgRedux<T> { */ static reset(): void { MockNgRedux.getInstance().mockRootStore.reset(); - NgRedux.instance = MockNgRedux.mockInstance; + NgRedux.instance = MockNgRedux.mockInstance as any; } /** @@ -75,31 +75,31 @@ export class MockNgRedux<T = {}> extends NgRedux<T> { MockNgRedux.mockInstance = MockNgRedux.mockInstance || new MockNgRedux(); return MockNgRedux.mockInstance; } + // + private mockRootStore = new MockObservableStore<any>(); - provideStore = (_: Store<any>): void => {}; - configureStore = ( - _: Reducer<any, AnyAction>, - __: any, - ___?: Middleware[], - ____?: StoreEnhancer<any>[], - ): void => {}; - - configureSubStore = this.mockRootStore.configureSubStore; - + configureSubStore = this.mockRootStore.configureSubStore as any; + dispatch = this.mockRootStore.dispatch as Dispatch<any>; + getState = this.mockRootStore.getState as any; + subscribe = this.mockRootStore.subscribe; + replaceReducer = this.mockRootStore.replaceReducer; select: <SelectedType>( selector?: Selector<T, SelectedType>, comparator?: Comparator, ) => Observable<SelectedType> = this.mockRootStore.select; - dispatch = this.mockRootStore.dispatch as Dispatch<any>; - getState = this.mockRootStore.getState; - subscribe = this.mockRootStore.subscribe; - replaceReducer = this.mockRootStore.replaceReducer; - /** @hidden */ - private constructor() { + constructor() { super(); // This hooks the mock up to @select. - NgRedux.instance = this; + NgRedux.instance = this as any; } + + provideStore = (_: Store<any>): void => undefined; + configureStore = ( + _: Reducer<any, AnyAction>, + __: any, + ___?: Middleware[], + ____?: StoreEnhancer<any>[], + ): void => undefined; } diff --git a/packages/store/testing/observable-store.mock.ts b/packages/store/testing/observable-store.mock.ts index cc2fbfdb..987276e4 100644 --- a/packages/store/testing/observable-store.mock.ts +++ b/packages/store/testing/observable-store.mock.ts @@ -1,11 +1,12 @@ +// TODO: See if this linting rule can be enabled with new build process (ng-packagr) +// tslint:disable:no-implicit-dependencies import { - Selector, Comparator, - ObservableStore, PathSelector, + Selector, } from '@angular-redux/store'; -import { AnyAction, Reducer, Dispatch } from 'redux'; -import { Observable, Subject, ReplaySubject } from 'rxjs'; +import { AnyAction, Dispatch, Reducer } from 'redux'; +import { Observable, ReplaySubject, Subject } from 'rxjs'; import { distinctUntilChanged } from 'rxjs/operators'; /** @hidden */ @@ -25,7 +26,7 @@ export interface SubStoreStubMap { } /** @hidden */ -export class MockObservableStore<State> implements ObservableStore<any> { +export class MockObservableStore<State> { selections: SelectorStubMap = {}; subStores: SubStoreStubMap = {}; @@ -43,7 +44,7 @@ export class MockObservableStore<State> implements ObservableStore<any> { dispatch: Dispatch<AnyAction> = action => action; replaceReducer = () => null; - getState = () => ({} as State); + getState = () => ({}); subscribe = () => () => null; select = <SelectedState>( diff --git a/packages/store/tests.js b/packages/store/tests.js deleted file mode 100644 index 0b7f4000..00000000 --- a/packages/store/tests.js +++ /dev/null @@ -1,40 +0,0 @@ -require('core-js/es7/reflect'); -require('zone.js/dist/zone-node.js'); -require('zone.js/dist/long-stack-trace-zone.js'); -require('zone.js/dist/proxy.js'); -require('zone.js/dist/sync-test.js'); -require('zone.js/dist/async-test.js'); -require('zone.js/dist/fake-async-test.js'); - -require('ts-node/register'); - -const Jasmine = require('jasmine'); -const runner = new Jasmine(); -global.jasmine = runner.jasmine; - -require('zone.js/dist/jasmine-patch.js'); - -// Stuff in the `testing` folder needs to import stuff from @angular-redux instead of '../src' -// or bad things happen when users of this package try to use MockNgRedux etc. This bit of code -// gets the unit test process to alias `import '@angular-redux/store'` to `import `../src` during -// our unit test execution. -const tsconfigPaths = require('tsconfig-paths'); -tsconfigPaths.register({ - baseUrl: '.', - paths: { '@angular-redux/store': [''] }, -}); - -const { getTestBed } = require('@angular/core/testing'); -const { - ServerTestingModule, - platformServerTesting, -} = require('@angular/platform-server/testing'); - -getTestBed().initTestEnvironment(ServerTestingModule, platformServerTesting()); - -runner.loadConfig({ - spec_dir: '.', - spec_files: ['**/*.spec.ts'], -}); - -runner.execute(); diff --git a/packages/store/tslint.json b/packages/store/tslint.json deleted file mode 100644 index 1c04a338..00000000 --- a/packages/store/tslint.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "rules": { - "callable-types": true, - "class-name": true, - "comment-format": [true, "check-space"], - "curly": true, - "eofline": true, - "forin": true, - "indent": [true, "spaces"], - "label-position": true, - "member-access": false, - "member-ordering": { - "options": { - "order": "statics-first" - } - }, - "no-arg": true, - "no-bitwise": true, - "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], - "no-construct": true, - "no-debugger": true, - "no-duplicate-variable": true, - "no-empty": false, - "no-eval": true, - "no-inferrable-types": [true, "ignore-params"], - "no-shadowed-variable": true, - "no-string-literal": false, - "no-string-throw": true, - "no-switch-case-fall-through": true, - "no-trailing-whitespace": true, - "no-unused-expression": true, - "no-var-keyword": true, - "object-literal-sort-keys": false, - "one-line": [ - true, - "check-open-brace", - "check-catch", - "check-else", - "check-whitespace" - ], - "prefer-const": true, - "quotemark": [true, "single"], - "radix": true, - "semicolon": [true, "always", "ignore-bound-class-methods"], - "triple-equals": [true, "allow-null-check"], - "typedef-whitespace": [ - true, - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - } - ], - "typeof-compare": false, - "unified-signatures": true, - "variable-name": false, - "whitespace": [ - true, - "check-branch", - "check-decl", - "check-operator", - "check-separator", - "check-type" - ] - } -} diff --git a/tslint.json b/tslint.json new file mode 100644 index 00000000..2aea0e43 --- /dev/null +++ b/tslint.json @@ -0,0 +1,72 @@ +{ + "extends": "tslint:latest", + "rulesDirectory": ["node_modules/codelyzer"], + "rules": { + // Codelyzer + "banana-in-box": true, + "contextual-life-cycle": true, + "decorator-not-allowed": true, + "pipe-impure": true, + "templates-no-negated-async": true, + "trackBy-function": true, + "i18n": false, + "no-attribute-parameter-decorator": true, + "no-forward-ref": false, + "no-input-rename": true, + "no-output-named-after-standard-event": true, + "no-output-on-prefix": true, + "no-output-rename": true, + "no-unused-css": false, + "use-life-cycle-interface": true, + "use-pipe-decorator": true, + "use-pipe-transform-interface": true, + "use-view-encapsulation": true, + "angular-whitespace": [ + true, + "check-interpolation", + "check-pipe", + "check-semicolon" + ], + "component-class-suffix": true, + "component-selector": ["element", "rdx", "kebab-case"], + "directive-class-suffix": true, + "directive-selector": ["attribute", "rdx", "camelCase"], + "import-destructuring-spacing": true, + "pipe-naming": ["camelCase", "rdx"], + "use-host-property-decorator": true, + "use-input-property-decorator": true, + "use-output-property-decorator": true, + + // Preset Overrides + "quotemark": [true, "single", "avoid-escape", "avoid-template"], + "object-literal-sort-keys": false, + "member-access": [true, "no-public"], + "arrow-parens": false, + "array-type": [true, "array"], + "semicolon": false, + "trailing-comma": false, + "interface-name": [true, "never-prefix"], + "no-console": [true, "log", "debug", "info", "time", "timeEnd", "trace"], + "object-literal-key-quotes": [true, "as-needed"], + "ban-types": [ + true, + ["Object", "Avoid using the `Object` type. Did you mean `object`?"], + ["Boolean", "Avoid using the `Boolean` type. Did you mean `boolean`?"], + ["Number", "Avoid using the `Number` type. Did you mean `number`?"], + ["String", "Avoid using the `String` type. Did you mean `string`?"], + ["Symbol", "Avoid using the `Symbol` type. Did you mean `symbol`?"] + ], + "no-submodule-imports": [ + true, + "core-js", + "zone.js", + "rxjs", + "@angular/core/testing", + "@angular/router/testing", + "@angular/platform-browser-dynamic/testing", + "@angular/platform-browser/animations", + "@angular-redux/store/testing" + ], + "no-implicit-dependencies": [true, "dev"] + } +} diff --git a/yarn.lock b/yarn.lock index b9e2d23c..6063ede5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1564,7 +1564,7 @@ bser@^2.0.0: dependencies: node-int64 "^0.4.0" -buffer-from@^1.0.0, buffer-from@^1.1.0: +buffer-from@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" @@ -1911,16 +1911,16 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" -codelyzer@~3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/codelyzer/-/codelyzer-3.0.1.tgz#ba66b7b2aa564fe9f45d6004b4003ad2cf116828" +codelyzer@4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/codelyzer/-/codelyzer-4.4.2.tgz#af11fed6ddf9362ed5b174495467fb7315306fb1" dependencies: app-root-path "^2.0.1" css-selector-tokenizer "^0.7.0" cssauron "^1.4.0" semver-dsl "^1.0.1" - source-map "^0.5.6" - sprintf-js "^1.0.3" + source-map "^0.5.7" + sprintf-js "^1.1.1" collection-visit@^1.0.0: version "1.0.0" @@ -1939,10 +1939,6 @@ color-name@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" -colors@^1.1.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.0.tgz#5f20c9fef6945cb1134260aab33bfbdc8295e04e" - columnify@^1.5.4: version "1.5.4" resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" @@ -2533,10 +2529,6 @@ deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" -deepmerge@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.1.1.tgz#e862b4e45ea0555072bf51e7fd0d9845170ae768" - default-require-extensions@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" @@ -3335,12 +3327,6 @@ find-up@^2.0.0, find-up@^2.1.0: dependencies: locate-path "^2.0.0" -findup-sync@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.3.0.tgz#37930aa5d816b777c03445e1966cc6790a4c0b16" - dependencies: - glob "~5.0.0" - flush-write-stream@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" @@ -3643,16 +3629,6 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2, gl once "^1.3.0" path-is-absolute "^1.0.0" -glob@~5.0.0: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - global-dirs@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" @@ -4954,7 +4930,7 @@ jest-worker@^23.2.0: dependencies: merge-stream "^1.0.1" -jest-zone-patch@^0.0.8: +jest-zone-patch@0.0.8, jest-zone-patch@^0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/jest-zone-patch/-/jest-zone-patch-0.0.8.tgz#90fa3b5b60e95ad3e624dd2c3eb59bb1dcabd371" @@ -7803,7 +7779,7 @@ split@^1.0.0: dependencies: through "2" -sprintf-js@^1.0.3: +sprintf-js@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c" @@ -7991,7 +7967,7 @@ strip-indent@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" -strip-json-comments@^2.0.0, strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: +strip-json-comments@^2.0.0, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -8279,19 +8255,6 @@ ts-jest@^22.4.4: source-map-support "^0.5.5" yargs "^11.0.0" -ts-node@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-6.2.0.tgz#65a0ae2acce319ea4fd7ac8d7c9f1f90c5da6baf" - dependencies: - arrify "^1.0.0" - buffer-from "^1.1.0" - diff "^3.1.0" - make-error "^1.1.1" - minimist "^1.2.0" - mkdirp "^0.5.1" - source-map-support "^0.5.6" - yn "^2.0.0" - ts-node@~3.0.2: version "3.0.6" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-3.0.6.tgz#55127ff790c7eebf6ba68c1e6dde94b09aaa21e0" @@ -8307,15 +8270,6 @@ ts-node@~3.0.2: v8flags "^2.0.11" yn "^2.0.0" -tsconfig-paths@3.4.2: - version "3.4.2" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.4.2.tgz#4640bffaeee3fc0ab986607edae203859156a8c3" - dependencies: - deepmerge "^2.0.1" - minimist "^1.2.0" - strip-bom "^3.0.0" - strip-json-comments "^2.0.1" - tsconfig@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-6.0.0.tgz#6b0e8376003d7af1864f8df8f89dd0059ffcd032" @@ -8345,9 +8299,9 @@ tslib@^1.7.1, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" -tslint@5.10.0: - version "5.10.0" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.10.0.tgz#11e26bccb88afa02dd0d9956cae3d4540b5f54c3" +tslint@5.11.0: + version "5.11.0" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.11.0.tgz#98f30c02eae3cde7006201e4c33cb08b48581eed" dependencies: babel-code-frame "^6.22.0" builtin-modules "^1.1.1" @@ -8360,29 +8314,11 @@ tslint@5.10.0: resolve "^1.3.2" semver "^5.3.0" tslib "^1.8.0" - tsutils "^2.12.1" - -tslint@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.1.0.tgz#51a47baeeb58956fcd617bd2cf00e2ef0eea2ed9" - dependencies: - babel-code-frame "^6.22.0" - colors "^1.1.2" - diff "^3.2.0" - findup-sync "~0.3.0" - glob "^7.1.1" - optimist "~0.6.0" - resolve "^1.3.2" - semver "^5.3.0" - tsutils "^1.4.0" - -tsutils@^1.4.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-1.9.1.tgz#b9f9ab44e55af9681831d5f28d0aeeaf5c750cb0" + tsutils "^2.27.2" -tsutils@^2.12.1: - version "2.27.2" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.27.2.tgz#60ba88a23d6f785ec4b89c6e8179cac9b431f1c7" +tsutils@^2.27.2: + version "2.29.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" dependencies: tslib "^1.8.1"