diff --git a/build/builder.ts b/build/builder.ts index ffff38d86b..ed886b0d76 100644 --- a/build/builder.ts +++ b/build/builder.ts @@ -1,19 +1,18 @@ import * as tasks from './tasks'; import { createBuilder } from './util'; - export default createBuilder([ - [ 'Removing "./dist" Folder', tasks.removeDistFolder ], - [ 'Compiling packages with NGC', tasks.compilePackagesWithNgc ], - [ 'Bundling FESMs', tasks.bundleFesms ], - [ 'Down-leveling FESMs to ES5', tasks.downLevelFesmsToES5 ], - [ 'Creating UMD Bundles', tasks.createUmdBundles ], - [ 'Renaming package entry files', tasks.renamePackageEntryFiles ], - [ 'Cleaning TypeScript files', tasks.cleanTypeScriptFiles ], - [ 'Removing remaining sourcemap files', tasks.removeRemainingSourceMapFiles ], - [ 'Copying type definition files', tasks.copyTypeDefinitionFiles ], - [ 'Minifying UMD bundles', tasks.minifyUmdBundles ], - [ 'Copying documents', tasks.copyDocs ], - [ 'Copying package.json files', tasks.copyPackageJsonFiles ], - [ 'Removing "./dist/packages" Folder', tasks.removePackagesFolder ], + ['Removing "./dist" Folder', tasks.removeDistFolder], + ['Compiling packages with NGC', tasks.compilePackagesWithNgc], + ['Bundling FESMs', tasks.bundleFesms], + ['Down-leveling FESMs to ES5', tasks.downLevelFesmsToES5], + ['Creating UMD Bundles', tasks.createUmdBundles], + ['Renaming package entry files', tasks.renamePackageEntryFiles], + ['Cleaning TypeScript files', tasks.cleanTypeScriptFiles], + ['Removing remaining sourcemap files', tasks.removeRemainingSourceMapFiles], + ['Copying type definition files', tasks.copyTypeDefinitionFiles], + ['Minifying UMD bundles', tasks.minifyUmdBundles], + ['Copying documents', tasks.copyDocs], + ['Copying package.json files', tasks.copyPackageJsonFiles], + ['Removing "./dist/packages" Folder', tasks.removePackagesFolder], ]); diff --git a/build/config.ts b/build/config.ts index 6da01e9392..29e2da865b 100644 --- a/build/config.ts +++ b/build/config.ts @@ -1,6 +1,6 @@ export interface PackageDescription { - name: string, - hasTestingModule: boolean, + name: string; + hasTestingModule: boolean; } export interface Config { diff --git a/build/deploy-build.ts b/build/deploy-build.ts index f8f86ca571..55a1a09d25 100644 --- a/build/deploy-build.ts +++ b/build/deploy-build.ts @@ -2,14 +2,11 @@ import * as tasks from './tasks'; import { createBuilder } from './util'; import { packages } from './config'; - -const deploy = createBuilder([ - [ 'Deploy builds', tasks.publishToRepo ] -]); +const deploy = createBuilder([['Deploy builds', tasks.publishToRepo]]); deploy({ scope: '@ngrx', - packages + packages, }).catch(err => { console.error(err); process.exit(1); diff --git a/build/index.ts b/build/index.ts index 69ef6bb698..3c7342dc31 100644 --- a/build/index.ts +++ b/build/index.ts @@ -1,10 +1,9 @@ import build from './builder'; import { packages } from './config'; - build({ scope: '@ngrx', - packages + packages, }).catch(err => { console.error(err); process.exit(1); diff --git a/build/tasks.ts b/build/tasks.ts index c58fbcd516..98050171ce 100644 --- a/build/tasks.ts +++ b/build/tasks.ts @@ -1,20 +1,16 @@ import { Config } from './config'; import * as util from './util'; - /** * Cleans the top level dist folder. All npm-ready packages are created * in the dist folder. */ export async function removeDistFolder(config: Config) { - const args = [ - './dist' - ]; + const args = ['./dist']; return await util.exec('rimraf', args); } - /** * Uses the 'tsconfig-build.json' file in each package directory to produce * AOT and Closure compatible JavaScript @@ -31,9 +27,7 @@ export async function compilePackagesWithNgc(config: Config) { } async function _compilePackagesWithNgc(pkg: string) { - await util.exec('ngc', [ - `-p ./modules/${pkg}/tsconfig-build.json` - ]); + await util.exec('ngc', [`-p ./modules/${pkg}/tsconfig-build.json`]); const entryTypeDefinition = `export * from './${pkg}/index';`; const entryMetadata = `{"__symbolic":"module","version":3,"metadata":{},"exports":[{"from":"./${pkg}/index"}]}`; @@ -42,7 +36,6 @@ async function _compilePackagesWithNgc(pkg: string) { util.writeFile(`./dist/packages/${pkg}.metadata.json`, entryMetadata); } - /** * Uses Rollup to bundle the JavaScript into a single flat file called * a FESM (Flat Ecma Script Module) @@ -50,7 +43,7 @@ async function _compilePackagesWithNgc(pkg: string) { export async function bundleFesms(config: Config) { const pkgs = util.getAllPackages(config); - await mapPackages(pkgs, async (pkg) => { + await mapPackages(pkgs, async pkg => { const topLevelName = util.getTopLevelName(pkg); await util.exec('rollup', [ @@ -63,21 +56,15 @@ export async function bundleFesms(config: Config) { }); } - /** * Copies each FESM into a TS file then uses TypeScript to downlevel * the FESM into ES5 with ESM modules */ export async function downLevelFesmsToES5(config: Config) { const packages = util.getAllPackages(config); - const tscArgs = [ - '--target es5', - '--module es2015', - '--noLib', - '--sourceMap', - ]; - - await mapPackages(packages, async (pkg) => { + const tscArgs = ['--target es5', '--module es2015', '--noLib', '--sourceMap']; + + await mapPackages(packages, async pkg => { const topLevelName = util.getTopLevelName(pkg); const file = `./dist/${topLevelName}/${config.scope}/${pkg}.js`; @@ -85,7 +72,7 @@ export async function downLevelFesmsToES5(config: Config) { util.copy(file, target); - await util.ignoreErrors(util.exec('tsc', [ target, ...tscArgs ])); + await util.ignoreErrors(util.exec('tsc', [target, ...tscArgs])); await util.mapSources(target.replace('.ts', '.js')); await util.remove(target); }); @@ -93,26 +80,23 @@ export async function downLevelFesmsToES5(config: Config) { await util.removeRecursively(`./dist/**/*/${config.scope}/*.ts`); } - /** * Re-runs Rollup on the downleveled ES5 to produce a UMD bundle */ export async function createUmdBundles(config: Config) { - await mapPackages(util.getAllPackages(config), async (pkg) => { + await mapPackages(util.getAllPackages(config), async pkg => { const topLevelName = util.getTopLevelName(pkg); const destinationName = util.getDestinationName(pkg); - const rollupArgs = [ - `-c ./modules/${pkg}/rollup.config.js`, - `--sourcemap`, - ]; + const rollupArgs = [`-c ./modules/${pkg}/rollup.config.js`, `--sourcemap`]; await util.exec('rollup', rollupArgs); - await util.mapSources(`./dist/${topLevelName}/bundles/${destinationName}.umd.js`); + await util.mapSources( + `./dist/${topLevelName}/bundles/${destinationName}.umd.js` + ); }); } - /** * Removes any leftover TypeScript files from previous compilation steps, * leaving any type definition files in place @@ -127,13 +111,12 @@ export async function cleanTypeScriptFiles(config: Config) { } } - /** * Renames the index files in each package to the name * of the package. */ export async function renamePackageEntryFiles(config: Config) { - await mapPackages(util.getAllPackages(config), async (pkg) => { + await mapPackages(util.getAllPackages(config), async pkg => { const bottomLevelName = util.getBottomLevelName(pkg); const files = await util.getListOfFiles(`./dist/packages/${pkg}/index.**`); @@ -146,24 +129,26 @@ export async function renamePackageEntryFiles(config: Config) { }); } - /** * Removes any remaining source map files from running NGC */ export async function removeRemainingSourceMapFiles(config: Config) { const packages = util.getTopLevelPackages(config); - await util.removeRecursively(`./dist/packages/?(${packages.join('|')})/**/*.map`); + await util.removeRecursively( + `./dist/packages/?(${packages.join('|')})/**/*.map` + ); } - /** * Copies the type definition files and NGC metadata files to * the root of the distribution */ export async function copyTypeDefinitionFiles(config: Config) { const packages = util.getTopLevelPackages(config); - const files = await util.getListOfFiles(`./dist/packages/?(${packages.join('|')})/**/*`); + const files = await util.getListOfFiles( + `./dist/packages/?(${packages.join('|')})/**/*` + ); for (let file of files) { const target = file.replace('packages/', ''); @@ -173,19 +158,13 @@ export async function copyTypeDefinitionFiles(config: Config) { await util.removeRecursively(`./dist/packages/?(${packages.join('|')})`); } - /** * Creates minified copies of each UMD bundle */ export async function minifyUmdBundles(config: Config) { - const uglifyArgs = [ - '-c', - '-m', - '--screw-ie8', - '--comments', - ]; - - await mapPackages(util.getAllPackages(config), async (pkg) => { + const uglifyArgs = ['-c', '-m', '--screw-ie8', '--comments']; + + await mapPackages(util.getAllPackages(config), async pkg => { const topLevelName = util.getTopLevelName(pkg); const destinationName = util.getDestinationName(pkg); const file = `./dist/${topLevelName}/bundles/${destinationName}.umd.js`; @@ -196,12 +175,11 @@ export async function minifyUmdBundles(config: Config) { `-o ${out}`, `--source-map ${out}.map`, `--source-map-include-sources ${file}`, - `--in-source-map ${file}.map` + `--in-source-map ${file}.map`, ]); }); } - /** * Copies the README.md, LICENSE, and package.json files into * each package @@ -229,7 +207,6 @@ export async function copyPackageJsonFiles(config: Config) { } } - /** * Removes the packages folder */ @@ -237,7 +214,6 @@ export async function removePackagesFolder(config: Config) { await util.removeRecursively('./dist/packages'); } - /** * Deploy build artifacts to repos */ @@ -248,8 +224,12 @@ export async function publishToRepo(config: Config) { const REPO_DIR = `./tmp/${pkg}`; const SHA = await util.git([`rev-parse HEAD`]); const SHORT_SHA = await util.git([`rev-parse --short HEAD`]); - const COMMITTER_USER_NAME = await util.git([`--no-pager show -s --format='%cN' HEAD`]); - const COMMITTER_USER_EMAIL = await util.git([`--no-pager show -s --format='%cE' HEAD`]); + const COMMITTER_USER_NAME = await util.git([ + `--no-pager show -s --format='%cN' HEAD`, + ]); + const COMMITTER_USER_EMAIL = await util.git([ + `--no-pager show -s --format='%cE' HEAD`, + ]); await util.cmd('rm -rf', [`${REPO_DIR}`]); await util.cmd('mkdir ', [`-p ${REPO_DIR}`]); @@ -274,6 +254,9 @@ export async function publishToRepo(config: Config) { } } -export function mapPackages(packages: string[], mapFn: (pkg: string, i: number) => Promise) { +export function mapPackages( + packages: string[], + mapFn: (pkg: string, i: number) => Promise +) { return Promise.all(packages.map(mapFn)); } diff --git a/build/util.ts b/build/util.ts index ef5befa237..8efed0f41d 100644 --- a/build/util.ts +++ b/build/util.ts @@ -6,7 +6,6 @@ import * as path from 'path'; import * as rimraf from 'rimraf'; import { Config } from './config'; - export function copy(target: string, destination: string) { fsExtra.copySync(target, destination); } @@ -27,9 +26,12 @@ export function rmdir(target: string) { fs.rmdirSync(target); } -export function getListOfFiles(globPath: string, exclude?: string): Promise { +export function getListOfFiles( + globPath: string, + exclude?: string +): Promise { return new Promise((resolve, reject) => { - const options = exclude ? { ignore: exclude } : { }; + const options = exclude ? { ignore: exclude } : {}; glob(globPath, options, (error, matches) => { if (error) { @@ -46,15 +48,18 @@ export function removeRecursively(glob: string) { rimraf(glob, err => { if (err) { reject(err); - } - else { + } else { resolve(); } }); }); } -export function exec(command: string, args: string[], base: (command: string) => string = fromNpm): Promise { +export function exec( + command: string, + args: string[], + base: (command: string) => string = fromNpm +): Promise { return new Promise((resolve, reject) => { cp.exec(base(command) + ' ' + args.join(' '), (err, stdout, stderr) => { if (err) { @@ -78,8 +83,7 @@ export async function ignoreErrors(promise: Promise): Promise { try { const result = await promise; return result; - } - catch (err) { + } catch (err) { return null; } } @@ -95,7 +99,8 @@ export function getPackageFilePath(pkg: string, filename: string) { const sorcery = require('sorcery'); export function mapSources(file: string) { return new Promise((resolve, reject) => { - sorcery.load(file) + sorcery + .load(file) .then((chain: any) => { chain.write(); resolve(); @@ -121,17 +126,19 @@ async function runTask(name: string, taskFn: () => Promise) { } } -export function createBuilder(tasks: [ string, (config: Config) => Promise ][]) { - return async function (config: Config) { - for (let [ name, runner ] of tasks) { +export function createBuilder( + tasks: [string, (config: Config) => Promise][] +) { + return async function(config: Config) { + for (let [name, runner] of tasks) { await runTask(name, () => runner(config)); } }; } export function flatMap(list: K[], mapFn: (item: K) => J[]): J[] { - return list.reduce(function (newList, nextItem) { - return [ ...newList, ...mapFn(nextItem) ]; + return list.reduce(function(newList, nextItem) { + return [...newList, ...mapFn(nextItem)]; }, [] as J[]); } @@ -142,23 +149,20 @@ export function getTopLevelPackages(config: Config) { export function getTestingPackages(config: Config) { return flatMap(config.packages, ({ name, hasTestingModule }) => { if (hasTestingModule) { - return [ `${name}/testing` ]; + return [`${name}/testing`]; } - return [ ]; + return []; }); } export function getAllPackages(config: Config) { return flatMap(config.packages, packageDescription => { if (packageDescription.hasTestingModule) { - return [ - packageDescription.name, - `${packageDescription.name}/testing`, - ]; + return [packageDescription.name, `${packageDescription.name}/testing`]; } - return [ packageDescription.name ]; + return [packageDescription.name]; }); } diff --git a/example-app/app/app.module.ts b/example-app/app/app.module.ts index 9771df8525..0ee2f3a898 100644 --- a/example-app/app/app.module.ts +++ b/example-app/app/app.module.ts @@ -1,4 +1,4 @@ -import { NgModule, } from '@angular/core'; +import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @@ -38,7 +38,9 @@ import { environment } from '../environments/environment'; * based application. */ StoreModule.forRoot(reducers, { - reducerFactory: !environment.production ? developmentReducerFactory : undefined + reducerFactory: !environment.production + ? developmentReducerFactory + : undefined, }), /** @@ -75,7 +77,7 @@ import { environment } from '../environments/environment'; CoreModule.forRoot(), - AuthModule.forRoot() + AuthModule.forRoot(), ], bootstrap: [AppComponent], }) diff --git a/example-app/app/auth/actions/auth.ts b/example-app/app/auth/actions/auth.ts index f7141db531..999ab5fdb7 100644 --- a/example-app/app/auth/actions/auth.ts +++ b/example-app/app/auth/actions/auth.ts @@ -33,9 +33,9 @@ export class Logout implements Action { readonly type = LOGOUT; } -export type Actions - = Login +export type Actions = + | Login | LoginSuccess | LoginFailure | LoginRedirect - | Logout; \ No newline at end of file + | Logout; diff --git a/example-app/app/auth/auth.module.ts b/example-app/app/auth/auth.module.ts index e5d69d34a9..fe57a360d7 100644 --- a/example-app/app/auth/auth.module.ts +++ b/example-app/app/auth/auth.module.ts @@ -13,28 +13,18 @@ import { AuthGuard } from './services/auth-guard.service'; import { AuthEffects } from './effects/auth.effects'; import { reducers } from './reducers'; -export const COMPONENTS = [ - LoginPageComponent, - LoginFormComponent -]; +export const COMPONENTS = [LoginPageComponent, LoginFormComponent]; @NgModule({ - imports: [ - CommonModule, - ReactiveFormsModule, - MaterialModule, - ], + imports: [CommonModule, ReactiveFormsModule, MaterialModule], declarations: COMPONENTS, - exports: COMPONENTS + exports: COMPONENTS, }) export class AuthModule { static forRoot(): ModuleWithProviders { return { ngModule: RootAuthModule, - providers: [ - AuthService, - AuthGuard - ] + providers: [AuthService, AuthGuard], }; } } @@ -42,13 +32,9 @@ export class AuthModule { @NgModule({ imports: [ AuthModule, - RouterModule.forChild([ - { path: 'login', component: LoginPageComponent } - ]), + RouterModule.forChild([{ path: 'login', component: LoginPageComponent }]), StoreModule.forFeature('auth', reducers), - EffectsModule.forFeature([ - AuthEffects - ]), - ] + EffectsModule.forFeature([AuthEffects]), + ], }) -export class RootAuthModule {} \ No newline at end of file +export class RootAuthModule {} diff --git a/example-app/app/auth/components/login-form.component.ts b/example-app/app/auth/components/login-form.component.ts index 1bda7ce680..823f379da4 100644 --- a/example-app/app/auth/components/login-form.component.ts +++ b/example-app/app/auth/components/login-form.component.ts @@ -1,4 +1,11 @@ -import { Component, OnInit, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core'; +import { + Component, + OnInit, + Input, + Output, + EventEmitter, + ChangeDetectionStrategy, +} from '@angular/core'; import { FormGroup, FormControl } from '@angular/forms'; import { Authenticate } from '../models/user'; @@ -33,7 +40,8 @@ import { Authenticate } from '../models/user'; `, - styles: [` + styles: [ + ` :host { display: flex; justify-content: center; @@ -62,10 +70,12 @@ import { Authenticate } from '../models/user'; flex-direction: row; justify-content: flex-end; } - `] + `, + ], }) export class LoginFormComponent implements OnInit { - @Input() set pending(isPending: boolean) { + @Input() + set pending(isPending: boolean) { if (isPending) { this.form.disable(); } @@ -79,17 +89,16 @@ export class LoginFormComponent implements OnInit { form: FormGroup = new FormGroup({ username: new FormControl(''), - password: new FormControl('') + password: new FormControl(''), }); - constructor() { } + constructor() {} - ngOnInit() { - } + ngOnInit() {} submit() { if (this.form.valid) { - this.submitted.emit(this.form.value); + this.submitted.emit(this.form.value); } } } diff --git a/example-app/app/auth/containers/login-page.component.ts b/example-app/app/auth/containers/login-page.component.ts index c6d4d84009..03f94f2b53 100644 --- a/example-app/app/auth/containers/login-page.component.ts +++ b/example-app/app/auth/containers/login-page.component.ts @@ -13,16 +13,15 @@ import * as Auth from '../actions/auth'; [errorMessage]="error$ | async"> `, - styles: [] + styles: [], }) export class LoginPageComponent implements OnInit { pending$ = this.store.select(fromAuth.getLoginPagePending); error$ = this.store.select(fromAuth.getLoginPageError); - constructor(private store: Store) { } + constructor(private store: Store) {} - ngOnInit() { - } + ngOnInit() {} onSubmit($event: Authenticate) { this.store.dispatch(new Auth.Login($event)); diff --git a/example-app/app/auth/effects/auth.effects.ts b/example-app/app/auth/effects/auth.effects.ts index e17c637718..fa40ca0726 100644 --- a/example-app/app/auth/effects/auth.effects.ts +++ b/example-app/app/auth/effects/auth.effects.ts @@ -14,20 +14,24 @@ import * as Auth from '../actions/auth'; @Injectable() export class AuthEffects { @Effect() - login$ = this.actions$.ofType(Auth.LOGIN) + login$ = this.actions$ + .ofType(Auth.LOGIN) .map((action: Auth.Login) => action.payload) .exhaustMap(auth => - this.authService.login(auth) - .map(user => new Auth.LoginSuccess({user})) + this.authService + .login(auth) + .map(user => new Auth.LoginSuccess({ user })) .catch(error => of(new Auth.LoginFailure(error))) ); @Effect({ dispatch: false }) - loginSuccess$ = this.actions$.ofType(Auth.LOGIN_SUCCESS) + loginSuccess$ = this.actions$ + .ofType(Auth.LOGIN_SUCCESS) .do(() => this.router.navigate(['/'])); @Effect({ dispatch: false }) - loginRedirect$ = this.actions$.ofType(Auth.LOGIN_REDIRECT, Auth.LOGOUT) + loginRedirect$ = this.actions$ + .ofType(Auth.LOGIN_REDIRECT, Auth.LOGOUT) .do(authed => { this.router.navigate(['/login']); }); @@ -35,6 +39,6 @@ export class AuthEffects { constructor( private actions$: Actions, private authService: AuthService, - private router: Router, + private router: Router ) {} -} \ No newline at end of file +} diff --git a/example-app/app/auth/models/user.ts b/example-app/app/auth/models/user.ts index 134c08f174..5f73f1d5f4 100644 --- a/example-app/app/auth/models/user.ts +++ b/example-app/app/auth/models/user.ts @@ -5,4 +5,4 @@ export interface Authenticate { export interface User { name: string; -} \ No newline at end of file +} diff --git a/example-app/app/auth/reducers/auth.ts b/example-app/app/auth/reducers/auth.ts index 82f0c2a50d..57d9752198 100644 --- a/example-app/app/auth/reducers/auth.ts +++ b/example-app/app/auth/reducers/auth.ts @@ -4,11 +4,11 @@ import { User } from '../models/user'; export interface State { loggedIn: boolean; user: User | null; -}; +} export const initialState: State = { loggedIn: false, - user: null + user: null, }; export function reducer(state = initialState, action: auth.Actions): State { @@ -17,7 +17,7 @@ export function reducer(state = initialState, action: auth.Actions): State { return { ...state, loggedIn: true, - user: action.payload.user + user: action.payload.user, }; } @@ -27,9 +27,9 @@ export function reducer(state = initialState, action: auth.Actions): State { default: { return state; - }; + } } } export const getLoggedIn = (state: State) => state.loggedIn; -export const getUser = (state: State) => state.user; \ No newline at end of file +export const getUser = (state: State) => state.user; diff --git a/example-app/app/auth/reducers/index.ts b/example-app/app/auth/reducers/index.ts index 68dc1e6312..cd8bc9a46b 100644 --- a/example-app/app/auth/reducers/index.ts +++ b/example-app/app/auth/reducers/index.ts @@ -6,7 +6,7 @@ import * as fromLoginPage from './login-page'; export interface AuthState { status: fromAuth.State; loginPage: fromLoginPage.State; -}; +} export interface State extends fromRoot.State { auth: AuthState; @@ -14,15 +14,30 @@ export interface State extends fromRoot.State { export const reducers = { status: fromAuth.reducer, - loginPage: fromLoginPage.reducer + loginPage: fromLoginPage.reducer, }; export const selectAuthState = createFeatureSelector('auth'); -export const selectAuthStatusState = createSelector(selectAuthState, (state: AuthState) => state.status); -export const getLoggedIn = createSelector(selectAuthStatusState, fromAuth.getLoggedIn); +export const selectAuthStatusState = createSelector( + selectAuthState, + (state: AuthState) => state.status +); +export const getLoggedIn = createSelector( + selectAuthStatusState, + fromAuth.getLoggedIn +); export const getUser = createSelector(selectAuthStatusState, fromAuth.getUser); -export const selectLoginPageState = createSelector(selectAuthState, (state: AuthState) => state.loginPage); -export const getLoginPageError = createSelector(selectLoginPageState, fromLoginPage.getError); -export const getLoginPagePending = createSelector(selectLoginPageState, fromLoginPage.getPending); \ No newline at end of file +export const selectLoginPageState = createSelector( + selectAuthState, + (state: AuthState) => state.loginPage +); +export const getLoginPageError = createSelector( + selectLoginPageState, + fromLoginPage.getError +); +export const getLoginPagePending = createSelector( + selectLoginPageState, + fromLoginPage.getPending +); diff --git a/example-app/app/auth/reducers/login-page.ts b/example-app/app/auth/reducers/login-page.ts index f99de724a0..b631d70747 100644 --- a/example-app/app/auth/reducers/login-page.ts +++ b/example-app/app/auth/reducers/login-page.ts @@ -4,11 +4,11 @@ import { User } from '../models/user'; export interface State { error: string | null; pending: boolean; -}; +} export const initialState: State = { error: null, - pending: false + pending: false, }; export function reducer(state = initialState, action: auth.Actions): State { @@ -17,7 +17,7 @@ export function reducer(state = initialState, action: auth.Actions): State { return { ...state, error: null, - pending: true + pending: true, }; } @@ -25,7 +25,7 @@ export function reducer(state = initialState, action: auth.Actions): State { return { ...state, error: null, - pending: false + pending: false, }; } @@ -33,15 +33,15 @@ export function reducer(state = initialState, action: auth.Actions): State { return { ...state, error: action.payload, - pending: false + pending: false, }; } default: { return state; - }; + } } } export const getError = (state: State) => state.error; -export const getPending = (state: State) => state.pending; \ No newline at end of file +export const getPending = (state: State) => state.pending; diff --git a/example-app/app/auth/services/auth-guard.service.ts b/example-app/app/auth/services/auth-guard.service.ts index 46b0462c01..875e8174f3 100644 --- a/example-app/app/auth/services/auth-guard.service.ts +++ b/example-app/app/auth/services/auth-guard.service.ts @@ -7,24 +7,18 @@ import { Observable } from 'rxjs/Observable'; import * as Auth from '../actions/auth'; import * as fromAuth from '../reducers'; - @Injectable() export class AuthGuard implements CanActivate { - - constructor( - private store: Store, - ) {} + constructor(private store: Store) {} canActivate(): Observable { - return this.store.select(fromAuth.getLoggedIn) - .take(1) - .map(authed => { - if (!authed) { - this.store.dispatch(new Auth.LoginRedirect()); - return false; - } + return this.store.select(fromAuth.getLoggedIn).take(1).map(authed => { + if (!authed) { + this.store.dispatch(new Auth.LoginRedirect()); + return false; + } - return true; - }); + return true; + }); } } diff --git a/example-app/app/auth/services/auth.service.ts b/example-app/app/auth/services/auth.service.ts index db00ae0f02..0d6aeadcd4 100644 --- a/example-app/app/auth/services/auth.service.ts +++ b/example-app/app/auth/services/auth.service.ts @@ -5,8 +5,7 @@ import { User, Authenticate } from '../models/user'; @Injectable() export class AuthService { - - constructor() { } + constructor() {} login({ username, password }: Authenticate) { /** diff --git a/example-app/app/books/actions/book.ts b/example-app/app/books/actions/book.ts index e36f3d26ba..e13684906f 100644 --- a/example-app/app/books/actions/book.ts +++ b/example-app/app/books/actions/book.ts @@ -1,11 +1,10 @@ import { Action } from '@ngrx/store'; import { Book } from '../models/book'; -export const SEARCH = '[Book] Search'; -export const SEARCH_COMPLETE = '[Book] Search Complete'; -export const LOAD = '[Book] Load'; -export const SELECT = '[Book] Select'; - +export const SEARCH = '[Book] Search'; +export const SEARCH_COMPLETE = '[Book] Search Complete'; +export const LOAD = '[Book] Load'; +export const SELECT = '[Book] Select'; /** * Every action is comprised of at least a type and an optional @@ -17,33 +16,33 @@ export const SELECT = '[Book] Select'; export class SearchAction implements Action { readonly type = SEARCH; - constructor(public payload: string) { } + constructor(public payload: string) {} } export class SearchCompleteAction implements Action { readonly type = SEARCH_COMPLETE; - constructor(public payload: Book[]) { } + constructor(public payload: Book[]) {} } export class LoadAction implements Action { readonly type = LOAD; - constructor(public payload: Book) { } + constructor(public payload: Book) {} } export class SelectAction implements Action { readonly type = SELECT; - constructor(public payload: string) { } + constructor(public payload: string) {} } /** * Export a type alias of all actions in this action group * so that reducers can easily compose action types */ -export type Actions - = SearchAction +export type Actions = + | SearchAction | SearchCompleteAction | LoadAction | SelectAction; diff --git a/example-app/app/books/actions/collection.ts b/example-app/app/books/actions/collection.ts index cfefbedb02..4cd1c898ec 100644 --- a/example-app/app/books/actions/collection.ts +++ b/example-app/app/books/actions/collection.ts @@ -1,17 +1,15 @@ import { Action } from '@ngrx/store'; import { Book } from '../models/book'; - -export const ADD_BOOK = '[Collection] Add Book'; -export const ADD_BOOK_SUCCESS = '[Collection] Add Book Success'; -export const ADD_BOOK_FAIL = '[Collection] Add Book Fail'; -export const REMOVE_BOOK = '[Collection] Remove Book'; -export const REMOVE_BOOK_SUCCESS = '[Collection] Remove Book Success'; -export const REMOVE_BOOK_FAIL = '[Collection] Remove Book Fail'; -export const LOAD = '[Collection] Load'; -export const LOAD_SUCCESS = '[Collection] Load Success'; -export const LOAD_FAIL = '[Collection] Load Fail'; - +export const ADD_BOOK = '[Collection] Add Book'; +export const ADD_BOOK_SUCCESS = '[Collection] Add Book Success'; +export const ADD_BOOK_FAIL = '[Collection] Add Book Fail'; +export const REMOVE_BOOK = '[Collection] Remove Book'; +export const REMOVE_BOOK_SUCCESS = '[Collection] Remove Book Success'; +export const REMOVE_BOOK_FAIL = '[Collection] Remove Book Fail'; +export const LOAD = '[Collection] Load'; +export const LOAD_SUCCESS = '[Collection] Load Success'; +export const LOAD_FAIL = '[Collection] Load Fail'; /** * Add Book to Collection Actions @@ -19,35 +17,34 @@ export const LOAD_FAIL = '[Collection] Load Fail'; export class AddBookAction implements Action { readonly type = ADD_BOOK; - constructor(public payload: Book) { } + constructor(public payload: Book) {} } export class AddBookSuccessAction implements Action { readonly type = ADD_BOOK_SUCCESS; - constructor(public payload: Book) { } + constructor(public payload: Book) {} } export class AddBookFailAction implements Action { readonly type = ADD_BOOK_FAIL; - constructor(public payload: Book) { } + constructor(public payload: Book) {} } - /** * Remove Book from Collection Actions */ export class RemoveBookAction implements Action { readonly type = REMOVE_BOOK; - constructor(public payload: Book) { } + constructor(public payload: Book) {} } export class RemoveBookSuccessAction implements Action { readonly type = REMOVE_BOOK_SUCCESS; - constructor(public payload: Book) { } + constructor(public payload: Book) {} } export class RemoveBookFailAction implements Action { @@ -66,18 +63,17 @@ export class LoadAction implements Action { export class LoadSuccessAction implements Action { readonly type = LOAD_SUCCESS; - constructor(public payload: Book[]) { } + constructor(public payload: Book[]) {} } export class LoadFailAction implements Action { readonly type = LOAD_FAIL; - constructor(public payload: any) { } + constructor(public payload: any) {} } - -export type Actions - = AddBookAction +export type Actions = + | AddBookAction | AddBookSuccessAction | AddBookFailAction | RemoveBookAction diff --git a/example-app/app/books/books.module.ts b/example-app/app/books/books.module.ts index e9b215f269..bb6a1c0924 100644 --- a/example-app/app/books/books.module.ts +++ b/example-app/app/books/books.module.ts @@ -24,8 +24,12 @@ import { reducers } from './reducers'; ComponentsModule, RouterModule.forChild([ { path: 'find', component: FindBookPageComponent }, - { path: ':id', component: ViewBookPageComponent, canActivate: [ BookExistsGuard ] }, - { path: '', component: CollectionPageComponent }, + { + path: ':id', + component: ViewBookPageComponent, + canActivate: [BookExistsGuard], + }, + { path: '', component: CollectionPageComponent }, ]), /** @@ -44,10 +48,7 @@ import { reducers } from './reducers'; * All Effects will only be instantiated once regardless of * whether they are registered once or multiple times. */ - EffectsModule.forFeature([ - BookEffects, - CollectionEffects - ]), + EffectsModule.forFeature([BookEffects, CollectionEffects]), ], declarations: [ FindBookPageComponent, @@ -55,8 +56,6 @@ import { reducers } from './reducers'; SelectedBookPageComponent, CollectionPageComponent, ], - providers: [ - BookExistsGuard - ] + providers: [BookExistsGuard], }) -export class BooksModule {} \ No newline at end of file +export class BooksModule {} diff --git a/example-app/app/books/components/book-authors.ts b/example-app/app/books/components/book-authors.ts index 4ea734e349..acd881654f 100644 --- a/example-app/app/books/components/book-authors.ts +++ b/example-app/app/books/components/book-authors.ts @@ -2,7 +2,6 @@ import { Component, Input } from '@angular/core'; import { Book } from '../models/book'; - @Component({ selector: 'bc-book-authors', template: ` @@ -11,11 +10,13 @@ import { Book } from '../models/book'; {{ authors | bcAddCommas }} `, - styles: [` + styles: [ + ` h5 { margin-bottom: 5px; } - `] + `, + ], }) export class BookAuthorsComponent { @Input() book: Book; diff --git a/example-app/app/books/components/book-detail.ts b/example-app/app/books/components/book-detail.ts index f81cc03119..ddb683b6c4 100644 --- a/example-app/app/books/components/book-detail.ts +++ b/example-app/app/books/components/book-detail.ts @@ -1,7 +1,6 @@ import { Component, Input, Output, EventEmitter } from '@angular/core'; import { Book } from '../models/book'; - @Component({ selector: 'bc-book-detail', template: ` @@ -29,7 +28,8 @@ import { Book } from '../models/book'; `, - styles: [` + styles: [ + ` :host { display: flex; justify-content: center; @@ -56,7 +56,8 @@ import { Book } from '../models/book'; padding: 0 25px 25px; position: relative; } - `] + `, + ], }) export class BookDetailComponent { /** @@ -72,7 +73,6 @@ export class BookDetailComponent { @Output() add = new EventEmitter(); @Output() remove = new EventEmitter(); - /** * Tip: Utilize getters to keep templates clean */ @@ -93,7 +93,9 @@ export class BookDetailComponent { } get thumbnail() { - return this.book.volumeInfo.imageLinks - && this.book.volumeInfo.imageLinks.smallThumbnail; + return ( + this.book.volumeInfo.imageLinks && + this.book.volumeInfo.imageLinks.smallThumbnail + ); } } diff --git a/example-app/app/books/components/book-preview-list.ts b/example-app/app/books/components/book-preview-list.ts index 7cb4897963..bcfc70cf12 100644 --- a/example-app/app/books/components/book-preview-list.ts +++ b/example-app/app/books/components/book-preview-list.ts @@ -6,13 +6,15 @@ import { Book } from '../models/book'; template: ` `, - styles: [` + styles: [ + ` :host { display: flex; flex-wrap: wrap; justify-content: center; } - `] + `, + ], }) export class BookPreviewListComponent { @Input() books: Book[]; diff --git a/example-app/app/books/components/book-preview.ts b/example-app/app/books/components/book-preview.ts index d479c648d8..ec958e2ec0 100644 --- a/example-app/app/books/components/book-preview.ts +++ b/example-app/app/books/components/book-preview.ts @@ -1,7 +1,6 @@ import { Component, Input } from '@angular/core'; import { Book } from '../models/book'; - @Component({ selector: 'bc-book-preview', template: ` @@ -21,7 +20,8 @@ import { Book } from '../models/book'; `, - styles: [` + styles: [ + ` md-card { width: 400px; height: 300px; @@ -61,7 +61,8 @@ import { Book } from '../models/book'; md-card-footer { padding: 0 25px 25px; } - `] + `, + ], }) export class BookPreviewComponent { @Input() book: Book; diff --git a/example-app/app/books/components/book-search.ts b/example-app/app/books/components/book-search.ts index 8bf40cbb7d..151db7e669 100644 --- a/example-app/app/books/components/book-search.ts +++ b/example-app/app/books/components/book-search.ts @@ -3,7 +3,6 @@ import 'rxjs/add/operator/map'; import 'rxjs/add/operator/distinctUntilChanged'; import { Component, Output, Input, EventEmitter } from '@angular/core'; - @Component({ selector: 'bc-book-search', template: ` @@ -17,7 +16,8 @@ import { Component, Output, Input, EventEmitter } from '@angular/core'; `, - styles: [` + styles: [ + ` md-card-title, md-card-content { display: flex; @@ -44,7 +44,8 @@ import { Component, Output, Input, EventEmitter } from '@angular/core'; md-spinner.show { opacity: 1.0; } - `] + `, + ], }) export class BookSearchComponent { @Input() query = ''; diff --git a/example-app/app/books/components/index.ts b/example-app/app/books/components/index.ts index ef77c34ed9..1c4cf61459 100644 --- a/example-app/app/books/components/index.ts +++ b/example-app/app/books/components/index.ts @@ -12,7 +12,6 @@ import { BookSearchComponent } from './book-search'; import { PipesModule } from '../../shared/pipes'; - export const COMPONENTS = [ BookAuthorsComponent, BookDetailComponent, @@ -21,7 +20,6 @@ export const COMPONENTS = [ BookSearchComponent, ]; - @NgModule({ imports: [ CommonModule, @@ -31,6 +29,6 @@ export const COMPONENTS = [ PipesModule, ], declarations: COMPONENTS, - exports: COMPONENTS + exports: COMPONENTS, }) -export class ComponentsModule { } +export class ComponentsModule {} diff --git a/example-app/app/books/containers/collection-page.ts b/example-app/app/books/containers/collection-page.ts index c12cb14932..841566b7ea 100644 --- a/example-app/app/books/containers/collection-page.ts +++ b/example-app/app/books/containers/collection-page.ts @@ -6,7 +6,6 @@ import { Observable } from 'rxjs/Observable'; import * as fromBooks from '../reducers'; import { Book } from '../models/book'; - @Component({ selector: 'bc-collection-page', changeDetection: ChangeDetectionStrategy.OnPush, @@ -23,12 +22,14 @@ import { Book } from '../models/book'; * consider breaking them out into presentational * components. */ - styles: [` + styles: [ + ` md-card-title { display: flex; justify-content: center; } - `] + `, + ], }) export class CollectionPageComponent { books$: Observable; diff --git a/example-app/app/books/containers/find-book-page.ts b/example-app/app/books/containers/find-book-page.ts index 2dab6ae4c1..d24d01be03 100644 --- a/example-app/app/books/containers/find-book-page.ts +++ b/example-app/app/books/containers/find-book-page.ts @@ -7,14 +7,13 @@ import * as fromBooks from '../reducers'; import * as book from '../actions/book'; import { Book } from '../models/book'; - @Component({ selector: 'bc-find-book-page', changeDetection: ChangeDetectionStrategy.OnPush, template: ` - ` + `, }) export class FindBookPageComponent { searchQuery$: Observable; diff --git a/example-app/app/books/containers/selected-book-page.ts b/example-app/app/books/containers/selected-book-page.ts index 1073a4c2cf..d271ba1989 100644 --- a/example-app/app/books/containers/selected-book-page.ts +++ b/example-app/app/books/containers/selected-book-page.ts @@ -6,7 +6,6 @@ import * as fromBooks from '../reducers'; import * as collection from '../actions/collection'; import { Book } from '../models/book'; - @Component({ selector: 'bc-selected-book-page', changeDetection: ChangeDetectionStrategy.OnPush, @@ -17,7 +16,7 @@ import { Book } from '../models/book'; (add)="addToCollection($event)" (remove)="removeFromCollection($event)"> - ` + `, }) export class SelectedBookPageComponent { book$: Observable; @@ -25,7 +24,9 @@ export class SelectedBookPageComponent { constructor(private store: Store) { this.book$ = store.select(fromBooks.getSelectedBook); - this.isSelectedBookInCollection$ = store.select(fromBooks.isSelectedBookInCollection); + this.isSelectedBookInCollection$ = store.select( + fromBooks.isSelectedBookInCollection + ); } addToCollection(book: Book) { diff --git a/example-app/app/books/containers/view-book-page.ts b/example-app/app/books/containers/view-book-page.ts index eb86d717a8..6acd0a73b3 100644 --- a/example-app/app/books/containers/view-book-page.ts +++ b/example-app/app/books/containers/view-book-page.ts @@ -23,7 +23,7 @@ import * as book from '../actions/book'; changeDetection: ChangeDetectionStrategy.OnPush, template: ` - ` + `, }) export class ViewBookPageComponent implements OnDestroy { actionsSubscription: Subscription; diff --git a/example-app/app/books/effects/book.spec.ts b/example-app/app/books/effects/book.spec.ts index 2343e11716..2b41d23905 100644 --- a/example-app/app/books/effects/book.spec.ts +++ b/example-app/app/books/effects/book.spec.ts @@ -31,11 +31,14 @@ describe('BookEffects', () => { TestBed.configureTestingModule({ providers: [ BookEffects, - { provide: GoogleBooksService, useValue: jasmine.createSpyObj('GoogleBooksService', ['searchBooks']) }, + { + provide: GoogleBooksService, + useValue: jasmine.createSpyObj('GoogleBooksService', ['searchBooks']), + }, { provide: Actions, useFactory: getActions }, { provide: SEARCH_SCHEDULER, useFactory: getTestScheduler }, { provide: SEARCH_DEBOUNCE, useValue: 30 }, - ] + ], }); effects = TestBed.get(BookEffects); @@ -45,8 +48,8 @@ describe('BookEffects', () => { describe('search$', () => { it('should return a new book.SearchCompleteAction, with the books, on success, after the de-bounce', () => { - const book1 = {id: '111', volumeInfo: {}} as Book; - const book2 = {id: '222', volumeInfo: {}} as Book; + const book1 = { id: '111', volumeInfo: {} } as Book; + const book2 = { id: '222', volumeInfo: {} } as Book; const books = [book1, book2]; const action = new SearchAction('query'); const completion = new SearchCompleteAction(books); @@ -59,7 +62,7 @@ describe('BookEffects', () => { expect(effects.search$).toBeObservable(expected); }); - it('should return a new book.SearchCompleteAction, with an empty array, if the books service throws', (() => { + it('should return a new book.SearchCompleteAction, with an empty array, if the books service throws', () => { const action = new SearchAction('query'); const completion = new SearchCompleteAction([]); const error = 'Error!'; @@ -70,15 +73,18 @@ describe('BookEffects', () => { googleBooksService.searchBooks.and.returnValue(response); expect(effects.search$).toBeObservable(expected); - })); + }); - it(`should not do anything if the query is an empty string`, fakeAsync(() => { - const action = new SearchAction(''); + it( + `should not do anything if the query is an empty string`, + fakeAsync(() => { + const action = new SearchAction(''); - actions$.stream = hot('-a---', { a: action }); - const expected = cold('---'); + actions$.stream = hot('-a---', { a: action }); + const expected = cold('---'); - expect(effects.search$).toBeObservable(expected); - })); + expect(effects.search$).toBeObservable(expected); + }) + ); }); }); diff --git a/example-app/app/books/effects/book.ts b/example-app/app/books/effects/book.ts index 4c037a7d22..f660018d97 100644 --- a/example-app/app/books/effects/book.ts +++ b/example-app/app/books/effects/book.ts @@ -18,8 +18,9 @@ import * as book from '../actions/book'; import { Book } from '../models/book'; export const SEARCH_DEBOUNCE = new InjectionToken('Search Debounce'); -export const SEARCH_SCHEDULER = new InjectionToken('Search Scheduler'); - +export const SEARCH_SCHEDULER = new InjectionToken( + 'Search Scheduler' +); /** * Effects offer a way to isolate and easily test side-effects within your @@ -52,22 +53,26 @@ export class BookEffects { const nextSearch$ = this.actions$.ofType(book.SEARCH).skip(1); - return this.googleBooks.searchBooks(query) + return this.googleBooks + .searchBooks(query) .takeUntil(nextSearch$) .map((books: Book[]) => new book.SearchCompleteAction(books)) .catch(() => of(new book.SearchCompleteAction([]))); }); - constructor( - private actions$: Actions, - private googleBooks: GoogleBooksService, - @Optional() @Inject(SEARCH_DEBOUNCE) private debounce: number = 300, - - /** + constructor( + private actions$: Actions, + private googleBooks: GoogleBooksService, + @Optional() + @Inject(SEARCH_DEBOUNCE) + private debounce: number = 300, + /** * You inject an optional Scheduler that will be undefined * in normal application usage, but its injected here so that you can mock out * during testing using the RxJS TestScheduler for simulating passages of time. */ - @Optional() @Inject(SEARCH_SCHEDULER) private scheduler: Scheduler - ) { } + @Optional() + @Inject(SEARCH_SCHEDULER) + private scheduler: Scheduler + ) {} } diff --git a/example-app/app/books/effects/collection.spec.ts b/example-app/app/books/effects/collection.spec.ts index 783bd475f3..c397e9ec2e 100644 --- a/example-app/app/books/effects/collection.spec.ts +++ b/example-app/app/books/effects/collection.spec.ts @@ -28,16 +28,24 @@ describe('CollectionEffects', () => { let effects: CollectionEffects; let actions$: TestActions; - const book1 = {id: '111', volumeInfo: {}} as Book; - const book2 = {id: '222', volumeInfo: {}} as Book; + const book1 = { id: '111', volumeInfo: {} } as Book; + const book2 = { id: '222', volumeInfo: {} } as Book; beforeEach(() => { TestBed.configureTestingModule({ providers: [ CollectionEffects, - { provide: Database, useValue: jasmine.createSpyObj('database', ['open', 'query', 'insert', 'executeWrite']) }, + { + provide: Database, + useValue: jasmine.createSpyObj('database', [ + 'open', + 'query', + 'insert', + 'executeWrite', + ]), + }, { provide: Actions, useFactory: getActions }, - ] + ], }); db = TestBed.get(Database); @@ -45,7 +53,6 @@ describe('CollectionEffects', () => { actions$ = TestBed.get(Actions); }); - describe('openDB$', () => { it('should call db.open when initially subscribed to', () => { effects.openDB$.subscribe(); @@ -72,7 +79,7 @@ describe('CollectionEffects', () => { const completion = new collection.LoadFailAction(error); actions$.stream = hot('-a', { a: action }); - const response = cold('-#', { }, error); + const response = cold('-#', {}, error); const expected = cold('--c', { c: completion }); db.query.and.returnValue(response); @@ -100,7 +107,7 @@ describe('CollectionEffects', () => { const error = 'Error!'; actions$.stream = hot('-a', { a: action }); - const response = cold('-#', { }, error); + const response = cold('-#', {}, error); const expected = cold('--c', { c: completion }); db.insert.and.returnValue(response); @@ -118,7 +125,9 @@ describe('CollectionEffects', () => { db.executeWrite.and.returnValue(response); expect(effects.removeBookFromCollection$).toBeObservable(expected); - expect(db.executeWrite).toHaveBeenCalledWith('books', 'delete', [book1.id]); + expect(db.executeWrite).toHaveBeenCalledWith('books', 'delete', [ + book1.id, + ]); }); it('should return a collection.RemoveBookFailAction, with the book, when the db insert throws', () => { @@ -127,13 +136,15 @@ describe('CollectionEffects', () => { const error = 'Error!'; actions$.stream = hot('-a', { a: action }); - const response = cold('-#', { }, error); + const response = cold('-#', {}, error); const expected = cold('--c', { c: completion }); db.executeWrite.and.returnValue(response); expect(effects.removeBookFromCollection$).toBeObservable(expected); - expect(db.executeWrite).toHaveBeenCalledWith('books', 'delete', [book1.id]); + expect(db.executeWrite).toHaveBeenCalledWith('books', 'delete', [ + book1.id, + ]); }); }); }); -}); \ No newline at end of file +}); diff --git a/example-app/app/books/effects/collection.ts b/example-app/app/books/effects/collection.ts index baf9dfa69f..7182681c51 100644 --- a/example-app/app/books/effects/collection.ts +++ b/example-app/app/books/effects/collection.ts @@ -15,10 +15,8 @@ import { of } from 'rxjs/observable/of'; import * as collection from '../actions/collection'; import { Book } from '../models/book'; - @Injectable() export class CollectionEffects { - /** * This effect does not yield any actions back to the store. Set * `dispatch` to false to hint to @ngrx/effects that it should @@ -43,7 +41,8 @@ export class CollectionEffects { .ofType(collection.LOAD) .startWith(new collection.LoadAction()) .switchMap(() => - this.db.query('books') + this.db + .query('books') .toArray() .map((books: Book[]) => new collection.LoadSuccessAction(books)) .catch(error => of(new collection.LoadFailAction(error))) @@ -54,21 +53,22 @@ export class CollectionEffects { .ofType(collection.ADD_BOOK) .map((action: collection.AddBookAction) => action.payload) .mergeMap(book => - this.db.insert('books', [ book ]) + this.db + .insert('books', [book]) .map(() => new collection.AddBookSuccessAction(book)) .catch(() => of(new collection.AddBookFailAction(book))) ); - @Effect() removeBookFromCollection$: Observable = this.actions$ .ofType(collection.REMOVE_BOOK) .map((action: collection.RemoveBookAction) => action.payload) .mergeMap(book => - this.db.executeWrite('books', 'delete', [ book.id ]) + this.db + .executeWrite('books', 'delete', [book.id]) .map(() => new collection.RemoveBookSuccessAction(book)) .catch(() => of(new collection.RemoveBookFailAction(book))) ); - constructor(private actions$: Actions, private db: Database) { } + constructor(private actions$: Actions, private db: Database) {} } diff --git a/example-app/app/books/guards/book-exists.ts b/example-app/app/books/guards/book-exists.ts index b1982d63a5..1d5d5aebc0 100644 --- a/example-app/app/books/guards/book-exists.ts +++ b/example-app/app/books/guards/book-exists.ts @@ -15,7 +15,6 @@ import { GoogleBooksService } from '../../core/services/google-books'; import * as fromBooks from '../reducers'; import * as book from '../actions/book'; - /** * Guards are hooks into the route resolution process, providing an opportunity * to inform the router's navigation process whether the route should continue @@ -27,7 +26,7 @@ export class BookExistsGuard implements CanActivate { private store: Store, private googleBooks: GoogleBooksService, private router: Router - ) { } + ) {} /** * This method creates an observable that waits for the `loaded` property @@ -35,7 +34,8 @@ export class BookExistsGuard implements CanActivate { * has finished. */ waitForCollectionToLoad(): Observable { - return this.store.select(fromBooks.getCollectionLoaded) + return this.store + .select(fromBooks.getCollectionLoaded) .filter(loaded => loaded) .take(1); } @@ -45,7 +45,8 @@ export class BookExistsGuard implements CanActivate { * in the Store */ hasBookInStore(id: string): Observable { - return this.store.select(fromBooks.getBookEntities) + return this.store + .select(fromBooks.getBookEntities) .map(entities => !!entities[id]) .take(1); } @@ -55,7 +56,8 @@ export class BookExistsGuard implements CanActivate { * it in the store, returning `true` or `false` if it was found. */ hasBookInApi(id: string): Observable { - return this.googleBooks.retrieveBook(id) + return this.googleBooks + .retrieveBook(id) .map(bookEntity => new book.LoadAction(bookEntity)) .do((action: book.LoadAction) => this.store.dispatch(action)) .map(book => !!book) @@ -71,14 +73,13 @@ export class BookExistsGuard implements CanActivate { * API. */ hasBook(id: string): Observable { - return this.hasBookInStore(id) - .switchMap(inStore => { - if (inStore) { - return of(inStore); - } + return this.hasBookInStore(id).switchMap(inStore => { + if (inStore) { + return of(inStore); + } - return this.hasBookInApi(id); - }); + return this.hasBookInApi(id); + }); } /** @@ -95,7 +96,8 @@ export class BookExistsGuard implements CanActivate { * to the 404 page. */ canActivate(route: ActivatedRouteSnapshot): Observable { - return this.waitForCollectionToLoad() - .switchMap(() => this.hasBook(route.params['id'])); + return this.waitForCollectionToLoad().switchMap(() => + this.hasBook(route.params['id']) + ); } } diff --git a/example-app/app/books/reducers/book.spec.ts b/example-app/app/books/reducers/book.spec.ts index 6d96b1681d..f5e280fc4e 100644 --- a/example-app/app/books/reducers/book.spec.ts +++ b/example-app/app/books/reducers/book.spec.ts @@ -1,6 +1,10 @@ import { reducer } from './books'; import * as fromBooks from './books'; -import { SearchCompleteAction, LoadAction, SelectAction } from '../actions/book'; +import { + SearchCompleteAction, + LoadAction, + SelectAction, +} from '../actions/book'; import { Book } from '../models/book'; import { LoadSuccessAction } from '../actions/collection'; @@ -16,15 +20,15 @@ describe('BooksReducer', () => { describe('SEARCH_COMPLETE & LOAD_SUCCESS', () => { function noExistingBooks(action: any) { - const book1 = {id: '111'} as Book; - const book2 = {id: '222'} as Book; + const book1 = { id: '111' } as Book; + const book2 = { id: '222' } as Book; const createAction = new action([book1, book2]); const expectedResult = { ids: ['111', '222'], entities: { '111': book1, - '222': book2 + '222': book2, }, selectedBookId: null, }; @@ -34,19 +38,19 @@ describe('BooksReducer', () => { } function existingBooks(action: any) { - const book1 = {id: '111'} as Book; - const book2 = {id: '222'} as Book; + const book1 = { id: '111' } as Book; + const book2 = { id: '222' } as Book; const initialState = { ids: ['111', '222'], entities: { '111': book1, - '222': book2 + '222': book2, }, selectedBookId: null, } as any; // should not replace existing books - const differentBook2 = {id: '222', foo: 'bar'} as any; - const book3 = {id: '333'} as Book; + const differentBook2 = { id: '222', foo: 'bar' } as any; + const book3 = { id: '333' } as Book; const createAction = new action([book3, differentBook2]); const expectedResult = { @@ -54,7 +58,7 @@ describe('BooksReducer', () => { entities: { '111': book1, '222': book2, - '333': book3 + '333': book3, }, selectedBookId: null, }; @@ -76,15 +80,15 @@ describe('BooksReducer', () => { describe('LOAD', () => { it('should add a single book, if the book does not exist', () => { - const book = {id: '888'} as Book; + const book = { id: '888' } as Book; const action = new LoadAction(book); const expectedResult = { ids: ['888'], entities: { - '888': book + '888': book, }, - selectedBookId: null + selectedBookId: null, }; const result = reducer(fromBooks.initialState, action); @@ -95,10 +99,10 @@ describe('BooksReducer', () => { const initialState = { ids: ['999'], entities: { - '999': {id: '999'} - } + '999': { id: '999' }, + }, } as any; - const book = {id: '999', foo: 'baz'} as any; + const book = { id: '999', foo: 'baz' } as any; const action = new LoadAction(book); const result = reducer(initialState, action); @@ -116,15 +120,15 @@ describe('BooksReducer', () => { }); describe('Selections', () => { - const book1 = {id: '111'} as Book; - const book2 = {id: '222'} as Book; + const book1 = { id: '111' } as Book; + const book2 = { id: '222' } as Book; const state: fromBooks.State = { ids: ['111', '222'], entities: { '111': book1, '222': book2, }, - selectedBookId: '111' + selectedBookId: '111', }; describe('getEntities', () => { @@ -161,6 +165,5 @@ describe('BooksReducer', () => { expect(result).toEqual([book1, book2]); }); }); - }); }); diff --git a/example-app/app/books/reducers/books.ts b/example-app/app/books/reducers/books.ts index 0a92312d5f..b1a91c9fea 100644 --- a/example-app/app/books/reducers/books.ts +++ b/example-app/app/books/reducers/books.ts @@ -3,12 +3,11 @@ import { Book } from '../models/book'; import * as book from '../actions/book'; import * as collection from '../actions/collection'; - export interface State { ids: string[]; entities: { [id: string]: Book }; selectedBookId: string | null; -}; +} export const initialState: State = { ids: [], @@ -16,7 +15,10 @@ export const initialState: State = { selectedBookId: null, }; -export function reducer(state = initialState, action: book.Actions | collection.Actions): State { +export function reducer( + state = initialState, + action: book.Actions | collection.Actions +): State { switch (action.type) { case book.SEARCH_COMPLETE: case collection.LOAD_SUCCESS: { @@ -24,16 +26,19 @@ export function reducer(state = initialState, action: book.Actions | collection. const newBooks = books.filter(book => !state.entities[book.id]); const newBookIds = newBooks.map(book => book.id); - const newBookEntities = newBooks.reduce((entities: { [id: string]: Book }, book: Book) => { - return Object.assign(entities, { - [book.id]: book - }); - }, {}); + const newBookEntities = newBooks.reduce( + (entities: { [id: string]: Book }, book: Book) => { + return Object.assign(entities, { + [book.id]: book, + }); + }, + {} + ); return { - ids: [ ...state.ids, ...newBookIds ], + ids: [...state.ids, ...newBookIds], entities: Object.assign({}, state.entities, newBookEntities), - selectedBookId: state.selectedBookId + selectedBookId: state.selectedBookId, }; } @@ -45,11 +50,11 @@ export function reducer(state = initialState, action: book.Actions | collection. } return { - ids: [ ...state.ids, book.id ], + ids: [...state.ids, book.id], entities: Object.assign({}, state.entities, { - [book.id]: book + [book.id]: book, }), - selectedBookId: state.selectedBookId + selectedBookId: state.selectedBookId, }; } @@ -57,7 +62,7 @@ export function reducer(state = initialState, action: book.Actions | collection. return { ids: state.ids, entities: state.entities, - selectedBookId: action.payload + selectedBookId: action.payload, }; } @@ -82,9 +87,13 @@ export const getIds = (state: State) => state.ids; export const getSelectedId = (state: State) => state.selectedBookId; -export const getSelected = createSelector(getEntities, getSelectedId, (entities, selectedId) => { - return entities[selectedId]; -}); +export const getSelected = createSelector( + getEntities, + getSelectedId, + (entities, selectedId) => { + return entities[selectedId]; + } +); export const getAll = createSelector(getEntities, getIds, (entities, ids) => { return ids.map(id => entities[id]); diff --git a/example-app/app/books/reducers/collection.ts b/example-app/app/books/reducers/collection.ts index f8dae266af..f8f65f74b1 100644 --- a/example-app/app/books/reducers/collection.ts +++ b/example-app/app/books/reducers/collection.ts @@ -1,23 +1,25 @@ import * as collection from '../actions/collection'; - export interface State { loaded: boolean; loading: boolean; ids: string[]; -}; +} const initialState: State = { loaded: false, loading: false, - ids: [] + ids: [], }; -export function reducer(state = initialState, action: collection.Actions): State { +export function reducer( + state = initialState, + action: collection.Actions +): State { switch (action.type) { case collection.LOAD: { return Object.assign({}, state, { - loading: true + loading: true, }); } @@ -27,7 +29,7 @@ export function reducer(state = initialState, action: collection.Actions): State return { loaded: true, loading: false, - ids: books.map(book => book.id) + ids: books.map(book => book.id), }; } @@ -40,7 +42,7 @@ export function reducer(state = initialState, action: collection.Actions): State } return Object.assign({}, state, { - ids: [ ...state.ids, book.id ] + ids: [...state.ids, book.id], }); } @@ -49,7 +51,7 @@ export function reducer(state = initialState, action: collection.Actions): State const book = action.payload; return Object.assign({}, state, { - ids: state.ids.filter(id => id !== book.id) + ids: state.ids.filter(id => id !== book.id), }); } @@ -59,7 +61,6 @@ export function reducer(state = initialState, action: collection.Actions): State } } - export const getLoaded = (state: State) => state.loaded; export const getLoading = (state: State) => state.loading; diff --git a/example-app/app/books/reducers/index.ts b/example-app/app/books/reducers/index.ts index 621434cd7b..526062d84a 100644 --- a/example-app/app/books/reducers/index.ts +++ b/example-app/app/books/reducers/index.ts @@ -7,7 +7,7 @@ import { combineReducers, Action, ActionReducerFactory, - MemoizedSelector + MemoizedSelector, } from '@ngrx/store'; import * as fromSearch from './search'; import * as fromBooks from './books'; @@ -60,44 +60,91 @@ export const getBooksState = createFeatureSelector('books'); * only recompute when arguments change. The created selectors can also be composed * together to select different pieces of state. */ -export const getBookEntitiesState = createSelector(getBooksState, (state: BooksState) => state.books); -export const getBookEntities = createSelector(getBookEntitiesState, fromBooks.getEntities); -export const getBookIds = createSelector(getBookEntitiesState, fromBooks.getIds); -export const getSelectedBookId = createSelector(getBookEntitiesState, fromBooks.getSelectedId); -export const getSelectedBook = createSelector(getBookEntitiesState, fromBooks.getSelected); - +export const getBookEntitiesState = createSelector( + getBooksState, + (state: BooksState) => state.books +); +export const getBookEntities = createSelector( + getBookEntitiesState, + fromBooks.getEntities +); +export const getBookIds = createSelector( + getBookEntitiesState, + fromBooks.getIds +); +export const getSelectedBookId = createSelector( + getBookEntitiesState, + fromBooks.getSelectedId +); +export const getSelectedBook = createSelector( + getBookEntitiesState, + fromBooks.getSelected +); /** * Just like with the books selectors, we also have to compose the search * reducer's and collection reducer's selectors. */ -export const getSearchState = createSelector(getBooksState, (state: BooksState) => state.search); - -export const getSearchBookIds = createSelector(getSearchState, fromSearch.getIds); -export const getSearchQuery = createSelector(getSearchState, fromSearch.getQuery); -export const getSearchLoading = createSelector(getSearchState, fromSearch.getLoading); - +export const getSearchState = createSelector( + getBooksState, + (state: BooksState) => state.search +); + +export const getSearchBookIds = createSelector( + getSearchState, + fromSearch.getIds +); +export const getSearchQuery = createSelector( + getSearchState, + fromSearch.getQuery +); +export const getSearchLoading = createSelector( + getSearchState, + fromSearch.getLoading +); /** * Some selector functions create joins across parts of state. This selector * composes the search result IDs to return an array of books in the store. */ -export const getSearchResults = createSelector(getBookEntities, getSearchBookIds, (books, searchIds) => { - return searchIds.map(id => books[id]); -}); - - - -export const getCollectionState = createSelector(getBooksState, (state: BooksState) => state.collection); - -export const getCollectionLoaded = createSelector(getCollectionState, fromCollection.getLoaded); -export const getCollectionLoading = createSelector(getCollectionState, fromCollection.getLoading); -export const getCollectionBookIds = createSelector(getCollectionState, fromCollection.getIds); - -export const getBookCollection = createSelector(getBookEntities, getCollectionBookIds, (entities, ids) => { - return ids.map(id => entities[id]); -}); - -export const isSelectedBookInCollection = createSelector(getCollectionBookIds, getSelectedBookId, (ids, selected) => { - return ids.indexOf(selected) > -1; -}); \ No newline at end of file +export const getSearchResults = createSelector( + getBookEntities, + getSearchBookIds, + (books, searchIds) => { + return searchIds.map(id => books[id]); + } +); + +export const getCollectionState = createSelector( + getBooksState, + (state: BooksState) => state.collection +); + +export const getCollectionLoaded = createSelector( + getCollectionState, + fromCollection.getLoaded +); +export const getCollectionLoading = createSelector( + getCollectionState, + fromCollection.getLoading +); +export const getCollectionBookIds = createSelector( + getCollectionState, + fromCollection.getIds +); + +export const getBookCollection = createSelector( + getBookEntities, + getCollectionBookIds, + (entities, ids) => { + return ids.map(id => entities[id]); + } +); + +export const isSelectedBookInCollection = createSelector( + getCollectionBookIds, + getSelectedBookId, + (ids, selected) => { + return ids.indexOf(selected) > -1; + } +); diff --git a/example-app/app/books/reducers/search.ts b/example-app/app/books/reducers/search.ts index 21692b1701..3840bde324 100644 --- a/example-app/app/books/reducers/search.ts +++ b/example-app/app/books/reducers/search.ts @@ -1,16 +1,15 @@ import * as book from '../actions/book'; - export interface State { ids: string[]; loading: boolean; query: string; -}; +} const initialState: State = { ids: [], loading: false, - query: '' + query: '', }; export function reducer(state = initialState, action: book.Actions): State { @@ -22,13 +21,13 @@ export function reducer(state = initialState, action: book.Actions): State { return { ids: [], loading: false, - query + query, }; } return Object.assign({}, state, { query, - loading: true + loading: true, }); } @@ -38,7 +37,7 @@ export function reducer(state = initialState, action: book.Actions): State { return { ids: books.map(book => book.id), loading: false, - query: state.query + query: state.query, }; } @@ -48,7 +47,6 @@ export function reducer(state = initialState, action: book.Actions): State { } } - export const getIds = (state: State) => state.ids; export const getQuery = (state: State) => state.query; diff --git a/example-app/app/core/actions/layout.ts b/example-app/app/core/actions/layout.ts index 448de292d8..9dcc2aeaee 100644 --- a/example-app/app/core/actions/layout.ts +++ b/example-app/app/core/actions/layout.ts @@ -1,8 +1,7 @@ import { Action } from '@ngrx/store'; -export const OPEN_SIDENAV = '[Layout] Open Sidenav'; -export const CLOSE_SIDENAV = '[Layout] Close Sidenav'; - +export const OPEN_SIDENAV = '[Layout] Open Sidenav'; +export const CLOSE_SIDENAV = '[Layout] Close Sidenav'; export class OpenSidenavAction implements Action { readonly type = OPEN_SIDENAV; @@ -12,7 +11,4 @@ export class CloseSidenavAction implements Action { readonly type = CLOSE_SIDENAV; } - -export type Actions - = OpenSidenavAction - | CloseSidenavAction; +export type Actions = OpenSidenavAction | CloseSidenavAction; diff --git a/example-app/app/core/components/layout.ts b/example-app/app/core/components/layout.ts index 50a921bbcf..6a58959980 100644 --- a/example-app/app/core/components/layout.ts +++ b/example-app/app/core/components/layout.ts @@ -1,6 +1,5 @@ import { Component } from '@angular/core'; - @Component({ selector: 'bc-layout', template: ` @@ -10,7 +9,8 @@ import { Component } from '@angular/core'; `, - styles: [` + styles: [ + ` md-sidenav-container { background: rgba(0, 0, 0, 0.03); } @@ -19,6 +19,7 @@ import { Component } from '@angular/core'; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } - `] + `, + ], }) -export class LayoutComponent { } +export class LayoutComponent {} diff --git a/example-app/app/core/components/nav-item.ts b/example-app/app/core/components/nav-item.ts index 00209c1f29..148c910c11 100644 --- a/example-app/app/core/components/nav-item.ts +++ b/example-app/app/core/components/nav-item.ts @@ -1,6 +1,5 @@ import { Component, Input, Output, EventEmitter } from '@angular/core'; - @Component({ selector: 'bc-nav-item', template: ` @@ -10,11 +9,13 @@ import { Component, Input, Output, EventEmitter } from '@angular/core'; {{ hint }} `, - styles: [` + styles: [ + ` .secondary { color: rgba(0, 0, 0, 0.54); } - `] + `, + ], }) export class NavItemComponent { @Input() icon = ''; diff --git a/example-app/app/core/components/sidenav.ts b/example-app/app/core/components/sidenav.ts index 0fb4686ee0..e56fd18668 100644 --- a/example-app/app/core/components/sidenav.ts +++ b/example-app/app/core/components/sidenav.ts @@ -9,11 +9,13 @@ import { Component, Input } from '@angular/core'; `, - styles: [` + styles: [ + ` md-sidenav { width: 300px; } - `] + `, + ], }) export class SidenavComponent { @Input() open = false; diff --git a/example-app/app/core/components/toolbar.ts b/example-app/app/core/components/toolbar.ts index dfb3c066cb..6ed0d3c9ec 100644 --- a/example-app/app/core/components/toolbar.ts +++ b/example-app/app/core/components/toolbar.ts @@ -1,6 +1,5 @@ import { Component, Output, EventEmitter } from '@angular/core'; - @Component({ selector: 'bc-toolbar', template: ` @@ -10,7 +9,7 @@ import { Component, Output, EventEmitter } from '@angular/core'; - ` + `, }) export class ToolbarComponent { @Output() openMenu = new EventEmitter(); diff --git a/example-app/app/core/containers/app.ts b/example-app/app/core/containers/app.ts index 78a2cccb53..9643af4d60 100644 --- a/example-app/app/core/containers/app.ts +++ b/example-app/app/core/containers/app.ts @@ -8,7 +8,6 @@ import * as fromAuth from '../../auth/reducers'; import * as layout from '../actions/layout'; import * as Auth from '../../auth/actions/auth'; - @Component({ selector: 'bc-app', changeDetection: ChangeDetectionStrategy.OnPush, @@ -34,7 +33,7 @@ import * as Auth from '../../auth/actions/auth'; - ` + `, }) export class AppComponent { showSidenav$: Observable; diff --git a/example-app/app/core/containers/not-found-page.ts b/example-app/app/core/containers/not-found-page.ts index f1229361b4..4b569ac310 100644 --- a/example-app/app/core/containers/not-found-page.ts +++ b/example-app/app/core/containers/not-found-page.ts @@ -1,6 +1,5 @@ import { Component, ChangeDetectionStrategy } from '@angular/core'; - @Component({ selector: 'bc-not-found-page', changeDetection: ChangeDetectionStrategy.OnPush, @@ -15,10 +14,12 @@ import { Component, ChangeDetectionStrategy } from '@angular/core'; `, - styles: [` + styles: [ + ` :host { text-align: center; } - `] + `, + ], }) -export class NotFoundPageComponent { } +export class NotFoundPageComponent {} diff --git a/example-app/app/core/core.module.ts b/example-app/app/core/core.module.ts index 48e6016c15..5f0d863112 100644 --- a/example-app/app/core/core.module.ts +++ b/example-app/app/core/core.module.ts @@ -12,7 +12,6 @@ import { ToolbarComponent } from './components/toolbar'; import { GoogleBooksService } from './services/google-books'; - export const COMPONENTS = [ AppComponent, NotFoundPageComponent, @@ -22,21 +21,16 @@ export const COMPONENTS = [ ToolbarComponent, ]; - @NgModule({ - imports: [ - CommonModule, - RouterModule, - MaterialModule, - ], + imports: [CommonModule, RouterModule, MaterialModule], declarations: COMPONENTS, - exports: COMPONENTS + exports: COMPONENTS, }) export class CoreModule { static forRoot() { return { ngModule: CoreModule, - providers: [ GoogleBooksService ] - } + providers: [GoogleBooksService], + }; } } diff --git a/example-app/app/core/reducers/layout.ts b/example-app/app/core/reducers/layout.ts index 8085b8560d..1976452592 100644 --- a/example-app/app/core/reducers/layout.ts +++ b/example-app/app/core/reducers/layout.ts @@ -1,6 +1,5 @@ import * as layout from '../actions/layout'; - export interface State { showSidenav: boolean; } @@ -13,12 +12,12 @@ export function reducer(state = initialState, action: layout.Actions): State { switch (action.type) { case layout.CLOSE_SIDENAV: return { - showSidenav: false + showSidenav: false, }; case layout.OPEN_SIDENAV: return { - showSidenav: true + showSidenav: true, }; default: diff --git a/example-app/app/core/services/google-books.spec.ts b/example-app/app/core/services/google-books.spec.ts index f9218b723b..8f543b5286 100644 --- a/example-app/app/core/services/google-books.spec.ts +++ b/example-app/app/core/services/google-books.spec.ts @@ -10,9 +10,9 @@ describe('Service: GoogleBooks', () => { beforeEach(() => { TestBed.configureTestingModule({ providers: [ - { provide: Http, useValue: jasmine.createSpyObj('Http', ['get']) }, - GoogleBooksService - ] + { provide: Http, useValue: jasmine.createSpyObj('Http', ['get']) }, + GoogleBooksService, + ], }); service = TestBed.get(GoogleBooksService); @@ -20,23 +20,23 @@ describe('Service: GoogleBooks', () => { }); const data = { - 'title': 'Book Title', - 'author': 'John Smith', - 'volumeId': '12345' + title: 'Book Title', + author: 'John Smith', + volumeId: '12345', }; const books = { items: [ - {id: '12345', volumeInfo: {title: 'Title'}}, - {id: '67890', volumeInfo: {title: 'Another Title'}} - ] + { id: '12345', volumeInfo: { title: 'Title' } }, + { id: '67890', volumeInfo: { title: 'Another Title' } }, + ], }; const queryTitle = 'Book Title'; it('should call the search api and return the search results', () => { const httpResponse = { - json: () => books + json: () => books, }; const response = cold('-a|', { a: httpResponse }); @@ -44,12 +44,14 @@ describe('Service: GoogleBooks', () => { http.get.and.returnValue(response); expect(service.searchBooks(queryTitle)).toBeObservable(expected); - expect(http.get).toHaveBeenCalledWith(`https://www.googleapis.com/books/v1/volumes?q=${queryTitle}`); + expect(http.get).toHaveBeenCalledWith( + `https://www.googleapis.com/books/v1/volumes?q=${queryTitle}` + ); }); it('should retrieve the book from the volumeId', () => { const httpResponse = { - json: () => data + json: () => data, }; const response = cold('-a|', { a: httpResponse }); @@ -57,7 +59,8 @@ describe('Service: GoogleBooks', () => { http.get.and.returnValue(response); expect(service.retrieveBook(data.volumeId)).toBeObservable(expected); - expect(http.get).toHaveBeenCalledWith(`https://www.googleapis.com/books/v1/volumes/${data.volumeId}`); + expect(http.get).toHaveBeenCalledWith( + `https://www.googleapis.com/books/v1/volumes/${data.volumeId}` + ); }); - }); diff --git a/example-app/app/core/services/google-books.ts b/example-app/app/core/services/google-books.ts index 84fbbc13ce..30f1ac82f4 100644 --- a/example-app/app/core/services/google-books.ts +++ b/example-app/app/core/services/google-books.ts @@ -4,7 +4,6 @@ import { Http } from '@angular/http'; import { Observable } from 'rxjs/Observable'; import { Book } from 'app/books/models/book'; - @Injectable() export class GoogleBooksService { private API_PATH = 'https://www.googleapis.com/books/v1/volumes'; @@ -12,12 +11,12 @@ export class GoogleBooksService { constructor(private http: Http) {} searchBooks(queryTitle: string): Observable { - return this.http.get(`${this.API_PATH}?q=${queryTitle}`) + return this.http + .get(`${this.API_PATH}?q=${queryTitle}`) .map(res => res.json().items || []); } retrieveBook(volumeId: string): Observable { - return this.http.get(`${this.API_PATH}/${volumeId}`) - .map(res => res.json()); + return this.http.get(`${this.API_PATH}/${volumeId}`).map(res => res.json()); } } diff --git a/example-app/app/db.ts b/example-app/app/db.ts index 54fd9c6369..ec00705e52 100644 --- a/example-app/app/db.ts +++ b/example-app/app/db.ts @@ -1,6 +1,5 @@ import { DBSchema } from '@ngrx/db'; - /** * ngrx/db uses a simple schema config object to initialize stores in IndexedDB. */ @@ -10,7 +9,7 @@ export const schema: DBSchema = { stores: { books: { autoIncrement: true, - primaryKey: 'id' - } - } + primaryKey: 'id', + }, + }, }; diff --git a/example-app/app/reducers/index.ts b/example-app/app/reducers/index.ts index e2954a688a..6b0a7ae9d5 100644 --- a/example-app/app/reducers/index.ts +++ b/example-app/app/reducers/index.ts @@ -11,7 +11,6 @@ import { import * as fromRouter from '@ngrx/router-store'; import { environment } from '../../environments/environment'; - /** * Every reducer module's default export is the reducer function itself. In * addition, each module should export a type or interface that describes @@ -29,17 +28,15 @@ export interface State { layout: fromLayout.State; } - /** * Our state is composed of a map of action reducer functions. * These reducer functions are called with each dispatched action * and the current or initial state and return a new immutable state. */ export const reducers: ActionReducerMap = { - layout: fromLayout.reducer + layout: fromLayout.reducer, }; - // console.log all actions export function logger(reducer: ActionReducer) { return function(state: State, action: any) { @@ -47,7 +44,7 @@ export function logger(reducer: ActionReducer) { console.log('action', action); return reducer(state, action); - } + }; } /** @@ -72,11 +69,17 @@ export function logger(reducer: ActionReducer) { * By default, @ngrx/store uses combineReducers with the reducer map to compose the root meta-reducer. * To add more meta-reducers, provide a custom reducer factory. */ -export const developmentReducerFactory: ActionReducerFactory = compose(logger, combineReducers); +export const developmentReducerFactory: ActionReducerFactory< + State, + Action +> = compose(logger, combineReducers); /** * Layout Reducers */ export const getLayoutState = createFeatureSelector('layout'); -export const getShowSidenav = createSelector(getLayoutState, fromLayout.getShowSidenav); +export const getShowSidenav = createSelector( + getLayoutState, + fromLayout.getShowSidenav +); diff --git a/example-app/app/routes.ts b/example-app/app/routes.ts index 42782d1f08..f085e66ffc 100644 --- a/example-app/app/routes.ts +++ b/example-app/app/routes.ts @@ -4,6 +4,10 @@ import { NotFoundPageComponent } from './core/containers/not-found-page'; export const routes: Routes = [ { path: '', redirectTo: '/books', pathMatch: 'full' }, - { path: 'books', loadChildren: 'app/books/books.module#BooksModule', canActivate: [ AuthGuard ] }, - { path: '**', component: NotFoundPageComponent } + { + path: 'books', + loadChildren: 'app/books/books.module#BooksModule', + canActivate: [AuthGuard], + }, + { path: '**', component: NotFoundPageComponent }, ]; diff --git a/example-app/app/shared/pipes/add-commas.spec.ts b/example-app/app/shared/pipes/add-commas.spec.ts index 4b7a5c0f6e..ac58b97bfd 100644 --- a/example-app/app/shared/pipes/add-commas.spec.ts +++ b/example-app/app/shared/pipes/add-commas.spec.ts @@ -16,7 +16,9 @@ describe('Pipe: Add Commas', () => { }); it('should transform ["Kim", "Ryan", "Amanda"] to "Kim, Ryan, and Amanda"', () => { - expect(pipe.transform(['Kim', 'Ryan', 'Amanda'])).toEqual('Kim, Ryan, and Amanda'); + expect(pipe.transform(['Kim', 'Ryan', 'Amanda'])).toEqual( + 'Kim, Ryan, and Amanda' + ); }); it('transforms undefined to "Author Unknown"', () => { diff --git a/example-app/app/shared/pipes/add-commas.ts b/example-app/app/shared/pipes/add-commas.ts index 2d7bed8a4d..b64b4209c0 100644 --- a/example-app/app/shared/pipes/add-commas.ts +++ b/example-app/app/shared/pipes/add-commas.ts @@ -1,6 +1,5 @@ import { Pipe, PipeTransform } from '@angular/core'; - @Pipe({ name: 'bcAddCommas' }) export class AddCommasPipe implements PipeTransform { transform(authors: null | string[]) { diff --git a/example-app/app/shared/pipes/ellipsis.spec.ts b/example-app/app/shared/pipes/ellipsis.spec.ts index 021ac69891..e470d212f1 100644 --- a/example-app/app/shared/pipes/ellipsis.spec.ts +++ b/example-app/app/shared/pipes/ellipsis.spec.ts @@ -39,7 +39,7 @@ describe('Pipe: Ellipsis', () => { pipe = new EllipsisPipe(); }); - it('should return the string if it\'s length is less than 250', () => { + it("should return the string if it's length is less than 250", () => { expect(pipe.transform('string')).toEqual('string'); }); diff --git a/example-app/app/shared/pipes/ellipsis.ts b/example-app/app/shared/pipes/ellipsis.ts index 0284af7d24..17c17daf3c 100644 --- a/example-app/app/shared/pipes/ellipsis.ts +++ b/example-app/app/shared/pipes/ellipsis.ts @@ -1,10 +1,9 @@ import { Pipe, PipeTransform } from '@angular/core'; - @Pipe({ name: 'bcEllipsis' }) export class EllipsisPipe implements PipeTransform { transform(str: string, strLength: number = 250) { - const withoutHtml = str.replace(/(<([^>]+)>)/ig, ''); + const withoutHtml = str.replace(/(<([^>]+)>)/gi, ''); if (str.length >= strLength) { return `${withoutHtml.slice(0, strLength)}...`; diff --git a/example-app/app/shared/pipes/index.ts b/example-app/app/shared/pipes/index.ts index e11b8a9a7a..f9f2d6ef84 100644 --- a/example-app/app/shared/pipes/index.ts +++ b/example-app/app/shared/pipes/index.ts @@ -3,14 +3,10 @@ import { NgModule } from '@angular/core'; import { AddCommasPipe } from './add-commas'; import { EllipsisPipe } from './ellipsis'; - -export const PIPES = [ - AddCommasPipe, - EllipsisPipe, -]; +export const PIPES = [AddCommasPipe, EllipsisPipe]; @NgModule({ declarations: PIPES, - exports: PIPES + exports: PIPES, }) -export class PipesModule { } +export class PipesModule {} diff --git a/example-app/environments/environment.prod.ts b/example-app/environments/environment.prod.ts index 3612073bc3..c9669790be 100644 --- a/example-app/environments/environment.prod.ts +++ b/example-app/environments/environment.prod.ts @@ -1,3 +1,3 @@ export const environment = { - production: true + production: true, }; diff --git a/example-app/environments/environment.ts b/example-app/environments/environment.ts index 00313f1664..a7edcfab4d 100644 --- a/example-app/environments/environment.ts +++ b/example-app/environments/environment.ts @@ -4,5 +4,5 @@ // The list of which env maps to which file can be found in `angular-cli.json`. export const environment = { - production: false + production: false, }; diff --git a/example-app/test.ts b/example-app/test.ts index c8040e2792..87fd46437b 100644 --- a/example-app/test.ts +++ b/example-app/test.ts @@ -9,7 +9,7 @@ import 'zone.js/dist/fake-async-test'; import { getTestBed } from '@angular/core/testing'; import { BrowserDynamicTestingModule, - platformBrowserDynamicTesting + platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; // fixes typing errors in Atom editor @@ -20,7 +20,7 @@ declare var __karma__: any; declare var require: any; // Prevent Karma from running prematurely. -__karma__.loaded = function () {}; +__karma__.loaded = function() {}; // First, initialize the Angular testing environment. getTestBed().initTestEnvironment( diff --git a/modules/effects/spec/actions.spec.ts b/modules/effects/spec/actions.spec.ts index e17d6d8246..d1da8e5332 100644 --- a/modules/effects/spec/actions.spec.ts +++ b/modules/effects/spec/actions.spec.ts @@ -3,10 +3,14 @@ import 'rxjs/add/operator/toArray'; import 'rxjs/add/operator/map'; import 'rxjs/add/observable/of'; import { ReflectiveInjector } from '@angular/core'; -import { Action, StoreModule, ScannedActionsSubject, ActionsSubject } from '@ngrx/store'; +import { + Action, + StoreModule, + ScannedActionsSubject, + ActionsSubject, +} from '@ngrx/store'; import { Actions } from '../'; - describe('Actions', function() { let actions$: Actions; let dispatcher: ScannedActionsSubject; @@ -28,7 +32,7 @@ describe('Actions', function() { beforeEach(function() { const injector = ReflectiveInjector.resolveAndCreate([ StoreModule.forRoot(reducer).providers || [], - Actions + Actions, ]); actions$ = injector.get(Actions); @@ -40,36 +44,30 @@ describe('Actions', function() { { type: ADD }, { type: SUBTRACT }, { type: SUBTRACT }, - { type: SUBTRACT } + { type: SUBTRACT }, ]; - let iterations = [ - ...actions - ]; + let iterations = [...actions]; actions$.subscribe({ next(value) { let change = iterations.shift(); expect(value.type).toEqual(change!.type); - } + }, }); actions.forEach(action => dispatcher.next(action)); }); it('should let you filter out actions', function() { - const actions = [ ADD, ADD, SUBTRACT, ADD, SUBTRACT ]; + const actions = [ADD, ADD, SUBTRACT, ADD, SUBTRACT]; const expected = actions.filter(type => type === ADD); - actions$ - .ofType(ADD) - .map(update => update.type) - .toArray() - .subscribe({ - next(actual) { - expect(actual).toEqual(expected); - } - }); + actions$.ofType(ADD).map(update => update.type).toArray().subscribe({ + next(actual) { + expect(actual).toEqual(expected); + }, + }); actions.forEach(action => dispatcher.next({ type: action })); dispatcher.complete(); diff --git a/modules/effects/spec/effects_metadata.spec.ts b/modules/effects/spec/effects_metadata.spec.ts index 356288914b..223927a19f 100644 --- a/modules/effects/spec/effects_metadata.spec.ts +++ b/modules/effects/spec/effects_metadata.spec.ts @@ -1,4 +1,8 @@ -import { Effect, getSourceMetadata, getSourceForInstance } from '../src/effects_metadata'; +import { + Effect, + getSourceMetadata, + getSourceForInstance, +} from '../src/effects_metadata'; describe('Effect Metadata', () => { describe('getSourceMetadata', () => { @@ -6,7 +10,8 @@ describe('Effect Metadata', () => { class Fixture { @Effect() a: any; @Effect() b: any; - @Effect({ dispatch: false }) c: any; + @Effect({ dispatch: false }) + c: any; } const mock = new Fixture(); @@ -14,7 +19,7 @@ describe('Effect Metadata', () => { expect(getSourceMetadata(mock)).toEqual([ { propertyName: 'a', dispatch: true }, { propertyName: 'b', dispatch: true }, - { propertyName: 'c', dispatch: false } + { propertyName: 'c', dispatch: false }, ]); }); @@ -33,7 +38,7 @@ describe('Effect Metadata', () => { describe('getSourceProto', () => { it('should get the prototype for an instance of a source', () => { - class Fixture { } + class Fixture {} const instance = new Fixture(); const proto = getSourceForInstance(instance); diff --git a/modules/effects/spec/effects_resolver.spec.ts b/modules/effects/spec/effects_resolver.spec.ts index e69619fa54..da0592fd74 100644 --- a/modules/effects/spec/effects_resolver.spec.ts +++ b/modules/effects/spec/effects_resolver.spec.ts @@ -2,7 +2,4 @@ import 'rxjs/add/observable/of'; import { Observable } from 'rxjs/Observable'; import { Effect, mergeEffects } from '../'; - -describe('mergeEffects', () => { - -}); +describe('mergeEffects', () => {}); diff --git a/modules/effects/spec/ngc/ngc.spec.ts b/modules/effects/spec/ngc/ngc.spec.ts index 23c5f40287..5bbcf9bdbc 100644 --- a/modules/effects/spec/ngc/ngc.spec.ts +++ b/modules/effects/spec/ngc/ngc.spec.ts @@ -6,29 +6,25 @@ import { BrowserModule } from '@angular/platform-browser'; import { Store, StoreModule, combineReducers } from '../../../store'; import { EffectsModule, Effect, Actions } from '../../'; - @Injectable() export class NgcSpecFeatureEffects { - constructor(actions$: Actions) { } + constructor(actions$: Actions) {} @Effect() run$ = of({ type: 'NgcSpecFeatureAction' }); } @NgModule({ - imports: [ - EffectsModule.forFeature([ NgcSpecFeatureEffects ]), - ] + imports: [EffectsModule.forFeature([NgcSpecFeatureEffects])], }) -export class NgcSpecFeatureModule { } +export class NgcSpecFeatureModule {} @Injectable() export class NgcSpecRootEffects { - constructor(actions$: Actions) { } + constructor(actions$: Actions) {} @Effect() run$ = of({ type: 'NgcSpecRootAction' }); } - export interface AppState { count: number; } @@ -37,24 +33,18 @@ export interface AppState { selector: 'ngc-spec-component', template: `

Hello Effects

- ` + `, }) -export class NgcSpecComponent { - -} +export class NgcSpecComponent {} @NgModule({ imports: [ BrowserModule, - StoreModule.forRoot({ }), - EffectsModule.forRoot([ NgcSpecRootEffects ]), + StoreModule.forRoot({}), + EffectsModule.forRoot([NgcSpecRootEffects]), NgcSpecFeatureModule, ], - declarations: [ - NgcSpecComponent, - ], - bootstrap: [ - NgcSpecComponent, - ] + declarations: [NgcSpecComponent], + bootstrap: [NgcSpecComponent], }) export class NgcSpecModule {} diff --git a/modules/effects/src/actions.ts b/modules/effects/src/actions.ts index cf4b700669..f97b378270 100644 --- a/modules/effects/src/actions.ts +++ b/modules/effects/src/actions.ts @@ -23,7 +23,7 @@ export class Actions extends Observable { ofType(...allowedTypes: string[]): Actions { return filter.call(this, (action: Action) => - allowedTypes.some(type => type === action.type), + allowedTypes.some(type => type === action.type) ); } } diff --git a/modules/effects/src/effect_notification.ts b/modules/effects/src/effect_notification.ts index 7daf9410c1..0f2e758e72 100644 --- a/modules/effects/src/effect_notification.ts +++ b/modules/effects/src/effect_notification.ts @@ -11,12 +11,18 @@ export interface EffectNotification { notification: Notification; } -export function verifyOutput(output: EffectNotification, reporter: ErrorReporter) { +export function verifyOutput( + output: EffectNotification, + reporter: ErrorReporter +) { reportErrorThrown(output, reporter); reportInvalidActions(output, reporter); } -function reportErrorThrown(output: EffectNotification, reporter: ErrorReporter) { +function reportErrorThrown( + output: EffectNotification, + reporter: ErrorReporter +) { if (output.notification.kind === 'E') { const errorReason = `Effect ${getEffectName(output)} threw an error`; @@ -29,13 +35,18 @@ function reportErrorThrown(output: EffectNotification, reporter: ErrorReporter) } } -function reportInvalidActions(output: EffectNotification, reporter: ErrorReporter) { +function reportInvalidActions( + output: EffectNotification, + reporter: ErrorReporter +) { if (output.notification.kind === 'N') { const action = output.notification.value; const isInvalidAction = !isAction(action); if (isInvalidAction) { - const errorReason = `Effect ${getEffectName(output)} dispatched an invalid action`; + const errorReason = `Effect ${getEffectName( + output + )} dispatched an invalid action`; reporter.report(errorReason, { Source: output.sourceInstance, @@ -51,7 +62,11 @@ function isAction(action: any): action is Action { return action && action.type && typeof action.type === 'string'; } -function getEffectName({ propertyName, sourceInstance, sourceName }: EffectNotification) { +function getEffectName({ + propertyName, + sourceInstance, + sourceName, +}: EffectNotification) { const isMethod = typeof sourceInstance[propertyName] === 'function'; return `"${sourceName}.${propertyName}${isMethod ? '()' : ''}"`; diff --git a/modules/effects/src/effect_sources.ts b/modules/effects/src/effect_sources.ts index fae96f9647..3991bbb22e 100644 --- a/modules/effects/src/effect_sources.ts +++ b/modules/effects/src/effect_sources.ts @@ -15,9 +15,7 @@ import { ErrorReporter } from './error_reporter'; @Injectable() export class EffectSources extends Subject { - constructor( - private errorReporter: ErrorReporter, - ) { + constructor(private errorReporter: ErrorReporter) { super(); } @@ -39,9 +37,9 @@ export class EffectSources extends Subject { verifyOutput(output, this.errorReporter); return output.notification; - }, - ), - ), + } + ) + ) ); } } diff --git a/modules/effects/src/effects_feature_module.ts b/modules/effects/src/effects_feature_module.ts index 34a46b653a..80e947ef83 100644 --- a/modules/effects/src/effects_feature_module.ts +++ b/modules/effects/src/effects_feature_module.ts @@ -6,12 +6,12 @@ import { FEATURE_EFFECTS } from './tokens'; export class EffectsFeatureModule { constructor( private root: EffectsRootModule, - @Inject(FEATURE_EFFECTS) effectSourceGroups: any[][], + @Inject(FEATURE_EFFECTS) effectSourceGroups: any[][] ) { effectSourceGroups.forEach(group => group.forEach(effectSourceInstance => - root.addEffects(effectSourceInstance), - ), + root.addEffects(effectSourceInstance) + ) ); } } diff --git a/modules/effects/src/effects_metadata.ts b/modules/effects/src/effects_metadata.ts index 9016cca4eb..06380f8ec2 100644 --- a/modules/effects/src/effects_metadata.ts +++ b/modules/effects/src/effects_metadata.ts @@ -38,5 +38,5 @@ export function getSourceForInstance(instance: Object): any { export const getSourceMetadata = compose( getEffectMetadataEntries, - getSourceForInstance, + getSourceForInstance ); diff --git a/modules/effects/src/effects_resolver.ts b/modules/effects/src/effects_resolver.ts index 3ee6144d6d..bb8956a33a 100644 --- a/modules/effects/src/effects_resolver.ts +++ b/modules/effects/src/effects_resolver.ts @@ -10,17 +10,17 @@ import { getSourceMetadata, getSourceForInstance } from './effects_metadata'; import { isOnRunEffects } from './on_run_effects'; export function mergeEffects( - sourceInstance: any, + sourceInstance: any ): Observable { const sourceName = getSourceForInstance(sourceInstance).constructor.name; const observables: Observable[] = getSourceMetadata( - sourceInstance, + sourceInstance ).map(({ propertyName, dispatch }): Observable => { - const observable: Observable = typeof sourceInstance[propertyName] === - 'function' - ? sourceInstance[propertyName]() - : sourceInstance[propertyName]; + const observable: Observable = + typeof sourceInstance[propertyName] === 'function' + ? sourceInstance[propertyName]() + : sourceInstance[propertyName]; if (dispatch === false) { return ignoreElements.call(observable); @@ -36,7 +36,7 @@ export function mergeEffects( propertyName, sourceName, sourceInstance, - }), + }) ); }); diff --git a/modules/effects/src/effects_root_module.ts b/modules/effects/src/effects_root_module.ts index 1fdfe7eebf..62f4ddb959 100644 --- a/modules/effects/src/effects_root_module.ts +++ b/modules/effects/src/effects_root_module.ts @@ -8,7 +8,7 @@ export class EffectsRootModule { constructor( private sources: EffectSources, runner: EffectsRunner, - @Inject(ROOT_EFFECTS) rootEffects: any[], + @Inject(ROOT_EFFECTS) rootEffects: any[] ) { runner.start(); diff --git a/modules/effects/src/effects_runner.ts b/modules/effects/src/effects_runner.ts index 13c94d28b1..b7160cc227 100644 --- a/modules/effects/src/effects_runner.ts +++ b/modules/effects/src/effects_runner.ts @@ -9,7 +9,7 @@ export class EffectsRunner implements OnDestroy { constructor( private effectSources: EffectSources, - private store: Store, + private store: Store ) {} start() { diff --git a/modules/effects/src/on_run_effects.ts b/modules/effects/src/on_run_effects.ts index 96bef7c01a..2fa1fa8a07 100644 --- a/modules/effects/src/on_run_effects.ts +++ b/modules/effects/src/on_run_effects.ts @@ -4,14 +4,14 @@ import { EffectNotification } from './effect_notification'; export interface OnRunEffects { ngrxOnRunEffects( - resolvedEffects$: Observable, + resolvedEffects$: Observable ): Observable; } const onRunEffectsKey: keyof OnRunEffects = 'ngrxOnRunEffects'; export function isOnRunEffects( - sourceInstance: Object, + sourceInstance: Object ): sourceInstance is OnRunEffects { const source = getSourceForInstance(sourceInstance); diff --git a/modules/effects/src/tokens.ts b/modules/effects/src/tokens.ts index 88d04a52d4..330fd8da68 100644 --- a/modules/effects/src/tokens.ts +++ b/modules/effects/src/tokens.ts @@ -1,12 +1,12 @@ import { InjectionToken, Type } from '@angular/core'; export const IMMEDIATE_EFFECTS = new InjectionToken( - 'ngrx/effects: Immediate Effects', + 'ngrx/effects: Immediate Effects' ); export const ROOT_EFFECTS = new InjectionToken[]>( - 'ngrx/effects: Root Effects', + 'ngrx/effects: Root Effects' ); export const FEATURE_EFFECTS = new InjectionToken( - 'ngrx/effects: Feature Effects', + 'ngrx/effects: Feature Effects' ); export const CONSOLE = new InjectionToken('Browser Console'); diff --git a/modules/effects/testing/src/testing.ts b/modules/effects/testing/src/testing.ts index 89c3a4a28a..1e47f45cdd 100644 --- a/modules/effects/testing/src/testing.ts +++ b/modules/effects/testing/src/testing.ts @@ -3,10 +3,11 @@ import { Actions } from '@ngrx/effects'; import { Observable } from 'rxjs/Observable'; import { defer } from 'rxjs/observable/defer'; - export function provideMockActions(source: Observable): Provider; export function provideMockActions(factory: () => Observable): Provider; -export function provideMockActions(factoryOrSource: (() => Observable) | Observable): Provider { +export function provideMockActions( + factoryOrSource: (() => Observable) | Observable +): Provider { return { provide: Actions, useFactory: (): Observable => { diff --git a/modules/router-store/e2e/app.ts b/modules/router-store/e2e/app.ts index 5997bdddd2..0d59bfda88 100644 --- a/modules/router-store/e2e/app.ts +++ b/modules/router-store/e2e/app.ts @@ -3,21 +3,26 @@ import { BrowserModule } from '@angular/platform-browser'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { Router, RouterModule } from '@angular/router'; import { StoreModule } from '@ngrx/store'; -import { ROUTER_NAVIGATION, ROUTER_CANCEL, ROUTER_ERROR, StoreRouterConnectingModule } from '../src/index'; +import { + ROUTER_NAVIGATION, + ROUTER_CANCEL, + ROUTER_ERROR, + StoreRouterConnectingModule, +} from '../src/index'; @Component({ selector: 'test-app', - template: '' + template: '', }) -export class AppCmp { } +export class AppCmp {} @Component({ selector: 'simple-cmp', - template: 'simple' + template: 'simple', }) -export class SimpleCmp { } +export class SimpleCmp {} -export function reducer (state: string = '', action: any) { +export function reducer(state: string = '', action: any) { if (action.type === ROUTER_NAVIGATION) { return action.payload.routerState.url.toString(); } else { @@ -31,12 +36,11 @@ export function reducer (state: string = '', action: any) { BrowserModule, RouterModule.forRoot([ { path: '', component: SimpleCmp }, - { path: 'next', component: SimpleCmp } + { path: 'next', component: SimpleCmp }, ]), StoreModule.forRoot({ reducer }), - StoreRouterConnectingModule + StoreRouterConnectingModule, ], - bootstrap: [AppCmp] + bootstrap: [AppCmp], }) -export class AppModule { -} +export class AppModule {} diff --git a/modules/router-store/e2e/main.ts b/modules/router-store/e2e/main.ts index 48848b2849..4a79776cc1 100644 --- a/modules/router-store/e2e/main.ts +++ b/modules/router-store/e2e/main.ts @@ -1,4 +1,4 @@ -import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; -import {AppModule} from './app'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app'; -platformBrowserDynamic().bootstrapModule(AppModule); \ No newline at end of file +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/modules/router-store/spec/integration.spec.ts b/modules/router-store/spec/integration.spec.ts index a1c725fb40..8f86a9013d 100644 --- a/modules/router-store/spec/integration.spec.ts +++ b/modules/router-store/spec/integration.spec.ts @@ -1,15 +1,24 @@ -import {Component} from '@angular/core'; -import {TestBed} from '@angular/core/testing'; -import {NavigationEnd, Router} from '@angular/router'; -import {RouterTestingModule} from '@angular/router/testing'; -import {Store, StoreModule} from '@ngrx/store'; -import { ROUTER_CANCEL, ROUTER_ERROR, ROUTER_NAVIGATION, routerReducer, StoreRouterConnectingModule, RouterNavigationAction, RouterCancelAction, RouterAction } from '../src/index'; +import { Component } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { NavigationEnd, Router } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { Store, StoreModule } from '@ngrx/store'; +import { + ROUTER_CANCEL, + ROUTER_ERROR, + ROUTER_NAVIGATION, + routerReducer, + StoreRouterConnectingModule, + RouterNavigationAction, + RouterCancelAction, + RouterAction, +} from '../src/index'; import 'rxjs/add/operator/filter'; import 'rxjs/add/operator/first'; import 'rxjs/add/operator/toPromise'; describe('integration spec', () => { - it('should work', (done) => { + it('should work', done => { const reducer = (state: string = '', action: RouterAction) => { if (action.type === ROUTER_NAVIGATION) { return action.payload.routerState.url.toString(); @@ -24,33 +33,39 @@ describe('integration spec', () => { const store = TestBed.get(Store); const log = logOfRouterAndStore(router, store); - router.navigateByUrl('/').then(() => { - expect(log).toEqual([ - { type: 'store', state: '' }, // init event. has nothing to do with the router - { type: 'router', event: 'NavigationStart', url: '/' }, - { type: 'router', event: 'RoutesRecognized', url: '/' }, - { type: 'store', state: '/' }, // ROUTER_NAVIGATION event in the store - { type: 'router', event: 'NavigationEnd', url: '/' } - ]); - }).then(() => { - log.splice(0); - return router.navigateByUrl('next'); - - }).then(() => { - expect(log).toEqual([ - { type: 'router', event: 'NavigationStart', url: '/next' }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, - { type: 'store', state: '/next' }, - { type: 'router', event: 'NavigationEnd', url: '/next' } - ]); - - done(); - }); + router + .navigateByUrl('/') + .then(() => { + expect(log).toEqual([ + { type: 'store', state: '' }, // init event. has nothing to do with the router + { type: 'router', event: 'NavigationStart', url: '/' }, + { type: 'router', event: 'RoutesRecognized', url: '/' }, + { type: 'store', state: '/' }, // ROUTER_NAVIGATION event in the store + { type: 'router', event: 'NavigationEnd', url: '/' }, + ]); + }) + .then(() => { + log.splice(0); + return router.navigateByUrl('next'); + }) + .then(() => { + expect(log).toEqual([ + { type: 'router', event: 'NavigationStart', url: '/next' }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + { type: 'store', state: '/next' }, + { type: 'router', event: 'NavigationEnd', url: '/next' }, + ]); + + done(); + }); }); - it('should support preventing navigation', (done) => { + it('should support preventing navigation', done => { const reducer = (state: string = '', action: RouterAction) => { - if (action.type === ROUTER_NAVIGATION && action.payload.routerState.url.toString() === '/next') { + if ( + action.type === ROUTER_NAVIGATION && + action.payload.routerState.url.toString() === '/next' + ) { throw new Error('You shall not pass!'); } else { return state; @@ -63,30 +78,37 @@ describe('integration spec', () => { const store = TestBed.get(Store); const log = logOfRouterAndStore(router, store); - router.navigateByUrl('/').then(() => { - log.splice(0); - return router.navigateByUrl('next'); - - }).catch((e) => { - expect(e.message).toEqual('You shall not pass!'); - expect(log).toEqual([ - { type: 'router', event: 'NavigationStart', url: '/next' }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, - { type: 'router', event: 'NavigationError', url: '/next' } - ]); - - done(); - }); + router + .navigateByUrl('/') + .then(() => { + log.splice(0); + return router.navigateByUrl('next'); + }) + .catch(e => { + expect(e.message).toEqual('You shall not pass!'); + expect(log).toEqual([ + { type: 'router', event: 'NavigationStart', url: '/next' }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + { type: 'router', event: 'NavigationError', url: '/next' }, + ]); + + done(); + }); }); - it('should support rolling back if navigation gets canceled', (done) => { + it('should support rolling back if navigation gets canceled', done => { const reducer = (state: string = '', action: RouterAction): any => { if (action.type === ROUTER_NAVIGATION) { - return { url: action.payload.routerState.url.toString(), lastAction: ROUTER_NAVIGATION }; - + return { + url: action.payload.routerState.url.toString(), + lastAction: ROUTER_NAVIGATION, + }; } else if (action.type === ROUTER_CANCEL) { - return { url: action.payload.routerState.url.toString(), storeState: action.payload.storeState, lastAction: ROUTER_CANCEL }; - + return { + url: action.payload.routerState.url.toString(), + storeState: action.payload.storeState, + lastAction: ROUTER_CANCEL, + }; } else { return state; } @@ -98,66 +120,106 @@ describe('integration spec', () => { const store = TestBed.get(Store); const log = logOfRouterAndStore(router, store); - router.navigateByUrl('/').then(() => { - log.splice(0); - return router.navigateByUrl('next'); - - }).then((r) => { - expect(r).toEqual(false); - expect(log).toEqual([ - { type: 'router', event: 'NavigationStart', url: '/next' }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, - { type: 'store', state: { url: '/next', lastAction: ROUTER_NAVIGATION } }, - { type: 'store', state: { url: '/next', lastAction: ROUTER_CANCEL, storeState: { reducer: { url: '/next', lastAction: ROUTER_NAVIGATION } } } }, - { type: 'router', event: 'NavigationCancel', url: '/next' } - ]); - - done(); - }); + router + .navigateByUrl('/') + .then(() => { + log.splice(0); + return router.navigateByUrl('next'); + }) + .then(r => { + expect(r).toEqual(false); + expect(log).toEqual([ + { type: 'router', event: 'NavigationStart', url: '/next' }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + { + type: 'store', + state: { url: '/next', lastAction: ROUTER_NAVIGATION }, + }, + { + type: 'store', + state: { + url: '/next', + lastAction: ROUTER_CANCEL, + storeState: { + reducer: { url: '/next', lastAction: ROUTER_NAVIGATION }, + }, + }, + }, + { type: 'router', event: 'NavigationCancel', url: '/next' }, + ]); + + done(); + }); }); - it('should support rolling back if navigation errors', (done) => { + it('should support rolling back if navigation errors', done => { const reducer = (state: string = '', action: RouterAction): any => { if (action.type === ROUTER_NAVIGATION) { - return { url: action.payload.routerState.url.toString(), lastAction: ROUTER_NAVIGATION }; - + return { + url: action.payload.routerState.url.toString(), + lastAction: ROUTER_NAVIGATION, + }; } else if (action.type === ROUTER_ERROR) { - return { url: action.payload.routerState.url.toString(), storeState: action.payload.storeState, lastAction: ROUTER_ERROR }; - + return { + url: action.payload.routerState.url.toString(), + storeState: action.payload.storeState, + lastAction: ROUTER_ERROR, + }; } else { return state; } }; - createTestModule({ reducers: { reducer }, canActivate: () => { throw new Error('BOOM!'); } }); + createTestModule({ + reducers: { reducer }, + canActivate: () => { + throw new Error('BOOM!'); + }, + }); const router: Router = TestBed.get(Router); const store = TestBed.get(Store); const log = logOfRouterAndStore(router, store); - router.navigateByUrl('/').then(() => { - log.splice(0); - return router.navigateByUrl('next'); - - }).catch((e) => { - expect(e.message).toEqual('BOOM!'); - - expect(log).toEqual([ - { type: 'router', event: 'NavigationStart', url: '/next' }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, - { type: 'store', state: { url: '/next', lastAction: ROUTER_NAVIGATION } }, - { type: 'store', state: { url: '/next', lastAction: ROUTER_ERROR, storeState: { reducer: { url: '/next', lastAction: ROUTER_NAVIGATION } } } }, - { type: 'router', event: 'NavigationError', url: '/next' } - ]); - - done(); - }); + router + .navigateByUrl('/') + .then(() => { + log.splice(0); + return router.navigateByUrl('next'); + }) + .catch(e => { + expect(e.message).toEqual('BOOM!'); + + expect(log).toEqual([ + { type: 'router', event: 'NavigationStart', url: '/next' }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + { + type: 'store', + state: { url: '/next', lastAction: ROUTER_NAVIGATION }, + }, + { + type: 'store', + state: { + url: '/next', + lastAction: ROUTER_ERROR, + storeState: { + reducer: { url: '/next', lastAction: ROUTER_NAVIGATION }, + }, + }, + }, + { type: 'router', event: 'NavigationError', url: '/next' }, + ]); + + done(); + }); }); - it('should call navigateByUrl when resetting state of the routerReducer', (done) => { + it('should call navigateByUrl when resetting state of the routerReducer', done => { const reducer = (state: any, action: RouterAction) => { const r = routerReducer(state, action); - return r && r.state ? ({ url: r.state.url, navigationId: r.navigationId }) : null; + return r && r.state + ? { url: r.state.url, navigationId: r.navigationId } + : null; }; createTestModule({ reducers: { routerReducer, reducer } }); @@ -173,66 +235,75 @@ describe('integration spec', () => { } }); - router.navigateByUrl('/').then(() => { - log.splice(0); - return router.navigateByUrl('next'); - - }).then(() => { - expect(log).toEqual([ - { type: 'router', event: 'NavigationStart', url: '/next' }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, - { type: 'store', state: { url: '/next', navigationId: 2 } }, - { type: 'router', event: 'NavigationEnd', url: '/next' } - ]); - log.splice(0); - - store.dispatch({ - type: ROUTER_NAVIGATION, - payload: { routerState: routerReducerStates[0].state, event: { id: routerReducerStates[0].navigationId } } + router + .navigateByUrl('/') + .then(() => { + log.splice(0); + return router.navigateByUrl('next'); + }) + .then(() => { + expect(log).toEqual([ + { type: 'router', event: 'NavigationStart', url: '/next' }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + { type: 'store', state: { url: '/next', navigationId: 2 } }, + { type: 'router', event: 'NavigationEnd', url: '/next' }, + ]); + log.splice(0); + + store.dispatch({ + type: ROUTER_NAVIGATION, + payload: { + routerState: routerReducerStates[0].state, + event: { id: routerReducerStates[0].navigationId }, + }, + }); + return waitForNavigation(router); + }) + .then(() => { + expect(log).toEqual([ + { type: 'router', event: 'NavigationStart', url: '/' }, + { type: 'store', state: { url: '/', navigationId: 1 } }, // restored + { type: 'router', event: 'RoutesRecognized', url: '/' }, + { type: 'router', event: 'NavigationEnd', url: '/' }, + ]); + log.splice(0); + }) + .then(() => { + store.dispatch({ + type: ROUTER_NAVIGATION, + payload: { + routerState: routerReducerStates[1].state, + event: { id: routerReducerStates[1].navigationId }, + }, + }); + return waitForNavigation(router); + }) + .then(() => { + expect(log).toEqual([ + { type: 'store', state: { url: '/next', navigationId: 2 } }, // restored + { type: 'router', event: 'NavigationStart', url: '/next' }, + { type: 'router', event: 'RoutesRecognized', url: '/next' }, + { type: 'router', event: 'NavigationEnd', url: '/next' }, + ]); + done(); }); - return waitForNavigation(router); - - }).then(() => { - expect(log).toEqual([ - { type: 'router', event: 'NavigationStart', url: '/' }, - { type: 'store', state: { url: '/', navigationId: 1 } }, // restored - { type: 'router', event: 'RoutesRecognized', url: '/' }, - { type: 'router', event: 'NavigationEnd', url: '/' } - ]); - log.splice(0); - - }).then(() => { - store.dispatch({ - type: ROUTER_NAVIGATION, - payload: { routerState: routerReducerStates[1].state, event: { id: routerReducerStates[1].navigationId } } - }); - return waitForNavigation(router); - - }).then(() => { - expect(log).toEqual([ - { type: 'store', state: { url: '/next', navigationId: 2 } }, // restored - { type: 'router', event: 'NavigationStart', url: '/next' }, - { type: 'router', event: 'RoutesRecognized', url: '/next' }, - { type: 'router', event: 'NavigationEnd', url: '/next' } - ]); - done(); - }); }); }); -function createTestModule(opts: { reducers?: any, canActivate?: Function } = {}) { +function createTestModule( + opts: { reducers?: any; canActivate?: Function } = {} +) { @Component({ selector: 'test-app', - template: '' + template: '', }) - class AppCmp { - } + class AppCmp {} @Component({ selector: 'pagea-cmp', - template: 'pagea-cmp' + template: 'pagea-cmp', }) - class SimpleCmp { } + class SimpleCmp {} TestBed.configureTestingModule({ declarations: [AppCmp, SimpleCmp], @@ -240,12 +311,19 @@ function createTestModule(opts: { reducers?: any, canActivate?: Function } = {}) StoreModule.forRoot(opts.reducers), RouterTestingModule.withRoutes([ { path: '', component: SimpleCmp }, - { path: 'next', component: SimpleCmp, canActivate: ['CanActivateNext'] } + { + path: 'next', + component: SimpleCmp, + canActivate: ['CanActivateNext'], + }, ]), - StoreRouterConnectingModule + StoreRouterConnectingModule, ], providers: [ - { provide: 'CanActivateNext', useValue: opts.canActivate || (() => true) } + { + provide: 'CanActivateNext', + useValue: opts.canActivate || (() => true), + }, ], }); @@ -253,13 +331,21 @@ function createTestModule(opts: { reducers?: any, canActivate?: Function } = {}) } function waitForNavigation(router: Router): Promise { - return router.events.filter(e => e instanceof NavigationEnd).first().toPromise(); + return router.events + .filter(e => e instanceof NavigationEnd) + .first() + .toPromise(); } function logOfRouterAndStore(router: Router, store: Store): any[] { const log: any[] = []; - router.events. - subscribe(e => log.push({ type: 'router', event: e.constructor.name, url: (e).url.toString() })); + router.events.subscribe(e => + log.push({ + type: 'router', + event: e.constructor.name, + url: (e).url.toString(), + }) + ); store.subscribe(store => log.push({ type: 'store', state: store.reducer })); return log; } diff --git a/modules/router-store/src/index.ts b/modules/router-store/src/index.ts index 73fd97f27b..bcb9e2e004 100644 --- a/modules/router-store/src/index.ts +++ b/modules/router-store/src/index.ts @@ -11,5 +11,5 @@ export { RouterReducerState, RouterCancelPayload, RouterNavigationPayload, - StoreRouterConnectingModule + StoreRouterConnectingModule, } from './router_store_module'; diff --git a/modules/router-store/src/router_store_module.ts b/modules/router-store/src/router_store_module.ts index b3b977f3e1..400455ead5 100644 --- a/modules/router-store/src/router_store_module.ts +++ b/modules/router-store/src/router_store_module.ts @@ -1,7 +1,13 @@ -import {NgModule} from '@angular/core'; -import {NavigationCancel, NavigationError, Router, RouterStateSnapshot, RoutesRecognized} from '@angular/router'; -import {Store} from '@ngrx/store'; -import {of} from 'rxjs/observable/of'; +import { NgModule } from '@angular/core'; +import { + NavigationCancel, + NavigationError, + Router, + RouterStateSnapshot, + RoutesRecognized, +} from '@angular/router'; +import { Store } from '@ngrx/store'; +import { of } from 'rxjs/observable/of'; /** * An action dispatched when the router navigates. @@ -12,16 +18,16 @@ export const ROUTER_NAVIGATION = 'ROUTER_NAVIGATION'; * Payload of ROUTER_NAVIGATION. */ export type RouterNavigationPayload = { - routerState: RouterStateSnapshot, - event: RoutesRecognized + routerState: RouterStateSnapshot; + event: RoutesRecognized; }; /** * An action dispatched when the router navigates. */ export type RouterNavigationAction = { - type: typeof ROUTER_NAVIGATION, - payload: RouterNavigationPayload + type: typeof ROUTER_NAVIGATION; + payload: RouterNavigationPayload; }; /** @@ -33,17 +39,17 @@ export const ROUTER_CANCEL = 'ROUTER_CANCEL'; * Payload of ROUTER_CANCEL. */ export type RouterCancelPayload = { - routerState: RouterStateSnapshot, - storeState: T, - event: NavigationCancel + routerState: RouterStateSnapshot; + storeState: T; + event: NavigationCancel; }; /** * An action dispatched when the router cancel navigation. */ export type RouterCancelAction = { - type: typeof ROUTER_CANCEL, - payload: RouterCancelPayload + type: typeof ROUTER_CANCEL; + payload: RouterCancelPayload; }; /** @@ -55,32 +61,44 @@ export const ROUTER_ERROR = 'ROUTE_ERROR'; * Payload of ROUTER_ERROR. */ export type RouterErrorPayload = { - routerState: RouterStateSnapshot, - storeState: T, - event: NavigationError + routerState: RouterStateSnapshot; + storeState: T; + event: NavigationError; }; /** * An action dispatched when the router errors. */ export type RouterErrorAction = { - type: typeof ROUTER_ERROR, - payload: RouterErrorPayload + type: typeof ROUTER_ERROR; + payload: RouterErrorPayload; }; /** * An union type of router actions. */ -export type RouterAction = RouterNavigationAction | RouterCancelAction | RouterErrorAction; - -export type RouterReducerState = { state: RouterStateSnapshot, navigationId: number }; +export type RouterAction = + | RouterNavigationAction + | RouterCancelAction + | RouterErrorAction; + +export type RouterReducerState = { + state: RouterStateSnapshot; + navigationId: number; +}; -export function routerReducer(state: RouterReducerState, action: RouterAction): RouterReducerState { +export function routerReducer( + state: RouterReducerState, + action: RouterAction +): RouterReducerState { switch (action.type) { case ROUTER_NAVIGATION: case ROUTER_ERROR: case ROUTER_CANCEL: - return ({ state: action.payload.routerState, navigationId: action.payload.event.id }); + return { + state: action.payload.routerState, + navigationId: action.payload.event.id, + }; default: return state; } @@ -144,7 +162,9 @@ export class StoreRouterConnectingModule { } private setUpBeforePreactivationHook(): void { - (this.router).hooks.beforePreactivation = (routerState: RouterStateSnapshot) => { + (this.router).hooks.beforePreactivation = ( + routerState: RouterStateSnapshot + ) => { this.routerState = routerState; if (this.shouldDispatch()) this.dispatchEvent(); return of(true); @@ -161,7 +181,10 @@ export class StoreRouterConnectingModule { private dispatchEvent(): void { this.dispatchTriggeredByRouter = true; try { - const payload = { routerState: this.routerState, event: this.lastRoutesRecognized }; + const payload = { + routerState: this.routerState, + event: this.lastRoutesRecognized, + }; this.store.dispatch({ type: ROUTER_NAVIGATION, payload }); } finally { this.dispatchTriggeredByRouter = false; @@ -197,12 +220,20 @@ export class StoreRouterConnectingModule { } private dispatchRouterCancel(event: NavigationCancel): void { - const payload = { routerState: this.routerState, storeState: this.storeState, event }; + const payload = { + routerState: this.routerState, + storeState: this.storeState, + event, + }; this.store.dispatch({ type: ROUTER_CANCEL, payload }); } private dispatchRouterError(event: NavigationError): void { - const payload = { routerState: this.routerState, storeState: this.storeState, event }; + const payload = { + routerState: this.routerState, + storeState: this.storeState, + event, + }; this.store.dispatch({ type: ROUTER_ERROR, payload }); } } diff --git a/modules/store-devtools/spec/store.spec.ts b/modules/store-devtools/spec/store.spec.ts index 1c9b2907b7..cd14192096 100644 --- a/modules/store-devtools/spec/store.spec.ts +++ b/modules/store-devtools/spec/store.spec.ts @@ -2,47 +2,71 @@ import 'rxjs/add/operator/take'; import { Subscription } from 'rxjs/Subscription'; import { ReflectiveInjector } from '@angular/core'; import { TestBed, getTestBed } from '@angular/core/testing'; -import { StoreModule, Store, StateObservable, ActionReducer, Action, ReducerManager } from '@ngrx/store'; +import { + StoreModule, + Store, + StateObservable, + ActionReducer, + Action, + ReducerManager, +} from '@ngrx/store'; import { StoreDevtools, StoreDevtoolsModule, LiftedState, StoreDevtoolsConfig, - StoreDevtoolsOptions, } from '../'; + StoreDevtoolsOptions, +} from '../'; import { IS_EXTENSION_OR_MONITOR_PRESENT } from '../src/instrument'; -const counter = jasmine.createSpy('counter').and.callFake(function (state = 0, action: Action) { - switch (action.type) { - case 'INCREMENT': return state + 1; - case 'DECREMENT': return state - 1; - default: return state; - } -}); +const counter = jasmine + .createSpy('counter') + .and.callFake(function(state = 0, action: Action) { + switch (action.type) { + case 'INCREMENT': + return state + 1; + case 'DECREMENT': + return state - 1; + default: + return state; + } + }); declare var mistake: any; function counterWithBug(state = 0, action: Action) { switch (action.type) { - case 'INCREMENT': return state + 1; - case 'DECREMENT': return mistake - 1; // mistake is undefined - case 'SET_UNDEFINED': return undefined; - default: return state; + case 'INCREMENT': + return state + 1; + case 'DECREMENT': + return mistake - 1; // mistake is undefined + case 'SET_UNDEFINED': + return undefined; + default: + return state; } } function counterWithAnotherBug(state = 0, action: Action) { switch (action.type) { - case 'INCREMENT': return mistake + 1; // eslint-disable-line no-undef - case 'DECREMENT': return state - 1; - case 'SET_UNDEFINED': return undefined; - default: return state; + case 'INCREMENT': + return mistake + 1; // eslint-disable-line no-undef + case 'DECREMENT': + return state - 1; + case 'SET_UNDEFINED': + return undefined; + default: + return state; } } function doubleCounter(state = 0, action: Action) { switch (action.type) { - case 'INCREMENT': return state + 2; - case 'DECREMENT': return state - 2; - default: return state; + case 'INCREMENT': + return state + 2; + case 'DECREMENT': + return state - 2; + default: + return state; } } @@ -56,15 +80,16 @@ type Fixture = { replaceReducer: (reducer: ActionReducer) => void; }; -function createStore(reducer: ActionReducer, options: StoreDevtoolsOptions = {}): Fixture { +function createStore( + reducer: ActionReducer, + options: StoreDevtoolsOptions = {} +): Fixture { TestBed.configureTestingModule({ imports: [ StoreModule.forRoot({ state: reducer }), - StoreDevtoolsModule.instrument(options) + StoreDevtoolsModule.instrument(options), ], - providers: [ - { provide: IS_EXTENSION_OR_MONITOR_PRESENT, useValue: true }, - ] + providers: [{ provide: IS_EXTENSION_OR_MONITOR_PRESENT, useValue: true }], }); const testbed: TestBed = getTestBed(); @@ -75,8 +100,8 @@ function createStore(reducer: ActionReducer, options: StoreDevtool let liftedValue: LiftedState; let value: any; - const liftedStateSub = devtools.liftedState.subscribe(s => liftedValue = s); - const stateSub = devtools.state.subscribe(s => value = s); + const liftedStateSub = devtools.liftedState.subscribe(s => (liftedValue = s)); + const stateSub = devtools.state.subscribe(s => (value = s)); const getState = (): T => value.state; const getLiftedState = (): LiftedState => liftedValue; @@ -90,8 +115,15 @@ function createStore(reducer: ActionReducer, options: StoreDevtool reducerManager.addReducer('state', reducer); }; - - return { store, state, devtools, cleanup, getState, getLiftedState, replaceReducer }; + return { + store, + state, + devtools, + cleanup, + getState, + getLiftedState, + replaceReducer, + }; } describe('Store Devtools', () => { @@ -114,7 +146,7 @@ describe('Store Devtools', () => { fixture.cleanup(); }); - it('should alias devtools unlifted state to Store\'s state', () => { + it("should alias devtools unlifted state to Store's state", () => { expect(devtools.state).toBe(fixture.state as any); }); @@ -248,9 +280,7 @@ describe('Store Devtools', () => { store.dispatch({ type: 'INCREMENT' }); let { computedStates } = fixture.getLiftedState(); - expect(computedStates[2].error).toMatch( - /ReferenceError/ - ); + expect(computedStates[2].error).toMatch(/ReferenceError/); expect(computedStates[3].error).toMatch( /Interrupted by an error up the chain/ ); @@ -261,9 +291,7 @@ describe('Store Devtools', () => { it('should catch invalid action type', () => { expect(() => { store.dispatch({ type: undefined } as any); - }).toThrowError( - 'Actions must have a type property' - ); + }).toThrowError('Actions must have a type property'); }); it('should not recompute old states when toggling an action', () => { @@ -355,7 +383,6 @@ describe('Store Devtools', () => { }); }); - describe('maxAge option', () => { it('should auto-commit earliest non-@@INIT action when maxAge is reached', () => { const fixture = createStore(counter, { maxAge: 3 }); @@ -444,10 +471,11 @@ describe('Store Devtools', () => { // currentStateIndex should stay at 2 as actions are committed. fixture.store.dispatch({ type: 'INCREMENT' }); const liftedStoreState = fixture.getLiftedState(); - const currentComputedState = liftedStoreState.computedStates[liftedStoreState.currentStateIndex]; + const currentComputedState = + liftedStoreState.computedStates[liftedStoreState.currentStateIndex]; expect(liftedStoreState.currentStateIndex).toBe(2); - expect(currentComputedState.state).toEqual({ state: 3}); + expect(currentComputedState.state).toEqual({ state: 3 }); fixture.cleanup(); }); @@ -462,7 +490,8 @@ describe('Store Devtools', () => { fixture.store.dispatch({ type: 'DECREMENT' }); let liftedStoreState = fixture.getLiftedState(); - let currentComputedState = liftedStoreState.computedStates[liftedStoreState.currentStateIndex]; + let currentComputedState = + liftedStoreState.computedStates[liftedStoreState.currentStateIndex]; expect(liftedStoreState.currentStateIndex).toBe(4); expect(currentComputedState.state).toEqual({ state: 0 }); expect(currentComputedState.error).toBeDefined(); @@ -482,7 +511,8 @@ describe('Store Devtools', () => { // Auto-commit 2 actions by "fixing" reducer bug. fixture.replaceReducer(counter); let liftedStoreState = fixture.getLiftedState(); - let currentComputedState = liftedStoreState.computedStates[liftedStoreState.currentStateIndex]; + let currentComputedState = + liftedStoreState.computedStates[liftedStoreState.currentStateIndex]; expect(liftedStoreState.currentStateIndex).toBe(2); expect(currentComputedState.state).toEqual({ state: -4 }); @@ -502,7 +532,8 @@ describe('Store Devtools', () => { // Auto-commit 2 actions by "fixing" reducer bug. fixture.replaceReducer(counter); let liftedStoreState = fixture.getLiftedState(); - let currentComputedState = liftedStoreState.computedStates[liftedStoreState.currentStateIndex]; + let currentComputedState = + liftedStoreState.computedStates[liftedStoreState.currentStateIndex]; expect(liftedStoreState.currentStateIndex).toBe(0); expect(currentComputedState.state).toEqual({ state: -2 }); diff --git a/modules/store-devtools/src/actions.ts b/modules/store-devtools/src/actions.ts index cb2c985742..8ff1800d48 100644 --- a/modules/store-devtools/src/actions.ts +++ b/modules/store-devtools/src/actions.ts @@ -1,6 +1,5 @@ import { Action } from '@ngrx/store'; - export const PERFORM_ACTION = 'PERFORM_ACTION'; export const RESET = 'RESET'; export const ROLLBACK = 'ROLLBACK'; @@ -11,18 +10,14 @@ export const SET_ACTIONS_ACTIVE = 'SET_ACTIONS_ACTIVE'; export const JUMP_TO_STATE = 'JUMP_TO_STATE'; export const IMPORT_STATE = 'IMPORT_STATE'; - export class PerformAction implements Action { readonly type = PERFORM_ACTION; - constructor( - public action: Action, - public timestamp?: number, - ) { + constructor(public action: Action, public timestamp?: number) { if (typeof action.type === 'undefined') { throw new Error( 'Actions may not have an undefined "type" property. ' + - 'Have you misspelled a constant?' + 'Have you misspelled a constant?' ); } } @@ -31,19 +26,19 @@ export class PerformAction implements Action { export class Reset implements Action { readonly type = RESET; - constructor(public timestamp?: number) { } + constructor(public timestamp?: number) {} } export class Rollback implements Action { readonly type = ROLLBACK; - constructor(public timestamp?: number) { } + constructor(public timestamp?: number) {} } export class Commit implements Action { readonly type = COMMIT; - constructor(public timestamp?: number) { } + constructor(public timestamp?: number) {} } export class Sweep implements Action { @@ -53,7 +48,7 @@ export class Sweep implements Action { export class ToggleAction implements Action { readonly type = TOGGLE_ACTION; - constructor(public id: number) { } + constructor(public id: number) {} } export class SetActionsActive implements Action { @@ -62,25 +57,24 @@ export class SetActionsActive implements Action { constructor( public start: number, public end: number, - public active: boolean = true, - ) { } + public active: boolean = true + ) {} } export class JumpToState implements Action { readonly type = JUMP_TO_STATE; - constructor(public index: number) { } + constructor(public index: number) {} } export class ImportState implements Action { readonly type = IMPORT_STATE; - constructor(public nextLiftedState: any) { } + constructor(public nextLiftedState: any) {} } - -export type All - = PerformAction +export type All = + | PerformAction | Reset | Rollback | Commit @@ -88,5 +82,4 @@ export type All | ToggleAction | SetActionsActive | JumpToState - | ImportState - ; + | ImportState; diff --git a/modules/store-devtools/src/config.ts b/modules/store-devtools/src/config.ts index 70dc3feada..447dd3e543 100644 --- a/modules/store-devtools/src/config.ts +++ b/modules/store-devtools/src/config.ts @@ -1,15 +1,18 @@ import { ActionReducer } from '@ngrx/store'; import { InjectionToken, Type } from '@angular/core'; - export interface StoreDevtoolsConfig { maxAge: number | false; monitor: ActionReducer; -}; +} -export const STORE_DEVTOOLS_CONFIG = new InjectionToken('@ngrx/devtools Options'); -export const INITIAL_OPTIONS = new InjectionToken('@ngrx/devtools Initial Config'); +export const STORE_DEVTOOLS_CONFIG = new InjectionToken( + '@ngrx/devtools Options' +); +export const INITIAL_OPTIONS = new InjectionToken( + '@ngrx/devtools Initial Config' +); -export type StoreDevtoolsOptions - = Partial +export type StoreDevtoolsOptions = + | Partial | (() => Partial); diff --git a/modules/store-devtools/src/devtools.ts b/modules/store-devtools/src/devtools.ts index 7c38171d5f..e5bf6f7b8d 100644 --- a/modules/store-devtools/src/devtools.ts +++ b/modules/store-devtools/src/devtools.ts @@ -1,5 +1,12 @@ import { Injectable, Inject, OnDestroy } from '@angular/core'; -import { State, Action, INITIAL_STATE, ReducerObservable, ActionsSubject, ScannedActionsSubject } from '@ngrx/store'; +import { + State, + Action, + INITIAL_STATE, + ReducerObservable, + ActionsSubject, + ScannedActionsSubject, +} from '@ngrx/store'; import { Observable } from 'rxjs/Observable'; import { ReplaySubject } from 'rxjs/ReplaySubject'; import { Observer } from 'rxjs/Observer'; @@ -19,7 +26,7 @@ import * as Actions from './actions'; import { StoreDevtoolsConfig, STORE_DEVTOOLS_CONFIG } from './config'; @Injectable() -export class DevtoolsDispatcher extends ActionsSubject { } +export class DevtoolsDispatcher extends ActionsSubject {} @Injectable() export class StoreDevtools implements Observer { @@ -38,29 +45,37 @@ export class StoreDevtools implements Observer { @Inject(STORE_DEVTOOLS_CONFIG) config: StoreDevtoolsConfig ) { const liftedInitialState = liftInitialState(initialState, config.monitor); - const liftReducer = liftReducerWith(initialState, liftedInitialState, config.monitor, - config.maxAge ? { maxAge: config.maxAge } : { }); + const liftReducer = liftReducerWith( + initialState, + liftedInitialState, + config.monitor, + config.maxAge ? { maxAge: config.maxAge } : {} + ); const liftedAction$ = applyOperators(actions$.asObservable(), [ - [ skip, 1 ], - [ merge, extension.actions$ ], - [ map, liftAction ], - [ merge, dispatcher, extension.liftedActions$ ], - [ observeOn, queue ] + [skip, 1], + [merge, extension.actions$], + [map, liftAction], + [merge, dispatcher, extension.liftedActions$], + [observeOn, queue], ]); const liftedReducer$ = map.call(reducers$, liftReducer); const liftedStateSubject = new ReplaySubject(1); const liftedStateSubscription = applyOperators(liftedAction$, [ - [ withLatestFrom, liftedReducer$ ], - [ scan, ({ state: liftedState }: any, [ action, reducer ]: any) => { - const state = reducer(liftedState, action); - - extension.notify(action, state); - - return { state, action }; - }, { state: liftedInitialState, action: null }] + [withLatestFrom, liftedReducer$], + [ + scan, + ({ state: liftedState }: any, [action, reducer]: any) => { + const state = reducer(liftedState, action); + + extension.notify(action, state); + + return { state, action }; + }, + { state: liftedInitialState, action: null }, + ], ]).subscribe(({ state, action }) => { liftedStateSubject.next(state); @@ -71,7 +86,9 @@ export class StoreDevtools implements Observer { } }); - const liftedState$ = liftedStateSubject.asObservable() as Observable; + const liftedState$ = liftedStateSubject.asObservable() as Observable< + LiftedState + >; const state$ = map.call(liftedState$, unliftState); this.stateSubscription = liftedStateSubscription; @@ -88,9 +105,9 @@ export class StoreDevtools implements Observer { this.dispatcher.next(action); } - error(error: any) { } + error(error: any) {} - complete() { } + complete() {} performAction(action: any) { this.dispatch(new Actions.PerformAction(action)); diff --git a/modules/store-devtools/src/extension.ts b/modules/store-devtools/src/extension.ts index ce4f610968..b6b3fa2404 100644 --- a/modules/store-devtools/src/extension.ts +++ b/modules/store-devtools/src/extension.ts @@ -14,10 +14,12 @@ export const ExtensionActionTypes = { START: 'START', DISPATCH: 'DISPATCH', STOP: 'STOP', - ACTION: 'ACTION' + ACTION: 'ACTION', }; -export const REDUX_DEVTOOLS_EXTENSION = new InjectionToken('Redux Devtools Extension'); +export const REDUX_DEVTOOLS_EXTENSION = new InjectionToken< + ReduxDevtoolsExtension +>('Redux Devtools Extension'); export interface ReduxDevtoolsExtensionConnection { subscribe(listener: (change: any) => void): void; @@ -26,11 +28,18 @@ export interface ReduxDevtoolsExtensionConnection { } export interface ReduxDevtoolsExtension { - connect(options: { shouldStringify?: boolean, instanceId: string }): ReduxDevtoolsExtensionConnection; - send(action: any, state: any, shouldStringify?: boolean, instanceId?: string): void; + connect(options: { + shouldStringify?: boolean; + instanceId: string; + }): ReduxDevtoolsExtensionConnection; + send( + action: any, + state: any, + shouldStringify?: boolean, + instanceId?: string + ): void; } - @Injectable() export class DevtoolsExtension { private instanceId = `ngrx-store-${Date.now()}`; @@ -60,7 +69,9 @@ export class DevtoolsExtension { } return new Observable(subscriber => { - const connection = this.devtoolsExtension.connect({ instanceId: this.instanceId }); + const connection = this.devtoolsExtension.connect({ + instanceId: this.instanceId, + }); connection.subscribe((change: any) => subscriber.next(change)); @@ -73,21 +84,27 @@ export class DevtoolsExtension { const changes$ = share.call(this.createChangesObservable()); // Listen for the start action - const start$ = filter.call(changes$, (change: any) => change.type === ExtensionActionTypes.START); + const start$ = filter.call( + changes$, + (change: any) => change.type === ExtensionActionTypes.START + ); // Listen for the stop action - const stop$ = filter.call(changes$, (change: any) => change.type === ExtensionActionTypes.STOP); + const stop$ = filter.call( + changes$, + (change: any) => change.type === ExtensionActionTypes.STOP + ); // Listen for lifted actions const liftedActions$ = applyOperators(changes$, [ - [ filter, (change: any) => change.type === ExtensionActionTypes.DISPATCH ], - [ map, (change: any) => this.unwrapAction(change.payload) ] + [filter, (change: any) => change.type === ExtensionActionTypes.DISPATCH], + [map, (change: any) => this.unwrapAction(change.payload)], ]); // Listen for unlifted actions const actions$ = applyOperators(changes$, [ - [ filter, (change: any) => change.type === ExtensionActionTypes.ACTION ], - [ map, (change: any) => this.unwrapAction(change.payload) ] + [filter, (change: any) => change.type === ExtensionActionTypes.ACTION], + [map, (change: any) => this.unwrapAction(change.payload)], ]); const actionsUntilStop$ = takeUntil.call(actions$, stop$); diff --git a/modules/store-devtools/src/instrument.ts b/modules/store-devtools/src/instrument.ts index e19002dd25..101e77479c 100644 --- a/modules/store-devtools/src/instrument.ts +++ b/modules/store-devtools/src/instrument.ts @@ -1,4 +1,9 @@ -import { NgModule, InjectionToken, Injector, ModuleWithProviders } from '@angular/core'; +import { + NgModule, + InjectionToken, + Injector, + ModuleWithProviders, +} from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { StoreModule, @@ -12,11 +17,20 @@ import { ActionReducerFactory, INITIAL_STATE, INITIAL_REDUCERS, - REDUCER_FACTORY } from '@ngrx/store'; + REDUCER_FACTORY, +} from '@ngrx/store'; import { StoreDevtools, DevtoolsDispatcher } from './devtools'; -import { StoreDevtoolsConfig, StoreDevtoolsOptions, STORE_DEVTOOLS_CONFIG, INITIAL_OPTIONS } from './config'; -import { DevtoolsExtension, REDUX_DEVTOOLS_EXTENSION, ReduxDevtoolsExtension } from './extension'; - +import { + StoreDevtoolsConfig, + StoreDevtoolsOptions, + STORE_DEVTOOLS_CONFIG, + INITIAL_OPTIONS, +} from './config'; +import { + DevtoolsExtension, + REDUX_DEVTOOLS_EXTENSION, + ReduxDevtoolsExtension, +} from './extension'; export const IS_EXTENSION_OR_MONITOR_PRESENT = new InjectionToken( 'Is Devtools Extension or Monitor Present' @@ -32,10 +46,12 @@ export function createIsExtensionOrMonitorPresent( export function createReduxDevtoolsExtension() { const extensionKey = '__REDUX_DEVTOOLS_EXTENSION__'; - if (typeof window === 'object' && typeof (window as any)[extensionKey] !== 'undefined') { + if ( + typeof window === 'object' && + typeof (window as any)[extensionKey] !== 'undefined' + ) { return (window as any)[extensionKey]; - } - else { + } else { return null; } } @@ -48,23 +64,27 @@ export function noMonitor(): null { return null; } -export function createConfig(_options: StoreDevtoolsOptions): StoreDevtoolsConfig { +export function createConfig( + _options: StoreDevtoolsOptions +): StoreDevtoolsConfig { const DEFAULT_OPTIONS: StoreDevtoolsConfig = { maxAge: false, - monitor: noMonitor + monitor: noMonitor, }; let options = typeof _options === 'function' ? _options() : _options; const config = Object.assign({}, DEFAULT_OPTIONS, options); if (config.maxAge && config.maxAge < 2) { - throw new Error(`Devtools 'maxAge' cannot be less than 2, got ${config.maxAge}`); + throw new Error( + `Devtools 'maxAge' cannot be less than 2, got ${config.maxAge}` + ); } return config; } -@NgModule({ }) +@NgModule({}) export class StoreDevtoolsModule { static instrument(options: StoreDevtoolsOptions = {}): ModuleWithProviders { return { @@ -75,32 +95,32 @@ export class StoreDevtoolsModule { StoreDevtools, { provide: INITIAL_OPTIONS, - useValue: options + useValue: options, }, { provide: IS_EXTENSION_OR_MONITOR_PRESENT, - deps: [ REDUX_DEVTOOLS_EXTENSION, STORE_DEVTOOLS_CONFIG ], - useFactory: createIsExtensionOrMonitorPresent + deps: [REDUX_DEVTOOLS_EXTENSION, STORE_DEVTOOLS_CONFIG], + useFactory: createIsExtensionOrMonitorPresent, }, { provide: REDUX_DEVTOOLS_EXTENSION, - useFactory: createReduxDevtoolsExtension + useFactory: createReduxDevtoolsExtension, }, { provide: STORE_DEVTOOLS_CONFIG, - deps: [ INITIAL_OPTIONS ], - useFactory: createConfig + deps: [INITIAL_OPTIONS], + useFactory: createConfig, }, { provide: StateObservable, - deps: [ StoreDevtools ], - useFactory: createStateObservable + deps: [StoreDevtools], + useFactory: createStateObservable, }, { provide: ReducerManagerDispatcher, - useExisting: DevtoolsDispatcher + useExisting: DevtoolsDispatcher, }, - ] + ], }; } } diff --git a/modules/store-devtools/src/reducer.ts b/modules/store-devtools/src/reducer.ts index 4f6ad039b8..253ee149d8 100644 --- a/modules/store-devtools/src/reducer.ts +++ b/modules/store-devtools/src/reducer.ts @@ -1,16 +1,22 @@ -import { Action, ActionReducer, ActionsSubject, ReducerManager, UPDATE, INIT } from '@ngrx/store'; +import { + Action, + ActionReducer, + ActionsSubject, + ReducerManager, + UPDATE, + INIT, +} from '@ngrx/store'; import { difference, liftAction } from './utils'; import * as Actions from './actions'; - export type InitAction = { readonly type: typeof INIT; -} +}; export type UpdateReducerAction = { readonly type: typeof UPDATE; -} +}; export type CoreActions = InitAction | UpdateReducerAction; export type Actions = Actions.All | CoreActions; @@ -25,7 +31,7 @@ export interface LiftedState { skippedActionIds: number[]; committedState: any; currentStateIndex: number; - computedStates: { state: any, error: any }[]; + computedStates: { state: any; error: any }[]; } /** @@ -40,7 +46,7 @@ function computeNextEntry( if (error) { return { state, - error: 'Interrupted by an error up the chain' + error: 'Interrupted by an error up the chain', }; } @@ -55,7 +61,7 @@ function computeNextEntry( return { state: nextState, - error: nextError + error: nextError, }; } @@ -63,7 +69,7 @@ function computeNextEntry( * Runs the reducer on invalidated actions to get a fresh computation log. */ function recomputeStates( - computedStates: { state: any, error: any }[], + computedStates: { state: any; error: any }[], minInvalidatedStateIndex: number, reducer: ActionReducer, committedState: any, @@ -90,9 +96,9 @@ function recomputeStates( const previousError = previousEntry ? previousEntry.error : undefined; const shouldSkip = skippedActionIds.indexOf(actionId) > -1; - const entry = shouldSkip ? - previousEntry : - computeNextEntry(reducer, action, previousState, previousError); + const entry = shouldSkip + ? previousEntry + : computeNextEntry(reducer, action, previousState, previousError); nextComputedStates.push(entry); } @@ -100,7 +106,10 @@ function recomputeStates( return nextComputedStates; } -export function liftInitialState(initialCommittedState?: any, monitorReducer?: any): LiftedState { +export function liftInitialState( + initialCommittedState?: any, + monitorReducer?: any +): LiftedState { return { monitorState: monitorReducer(undefined, {}), nextActionId: 1, @@ -109,7 +118,7 @@ export function liftInitialState(initialCommittedState?: any, monitorReducer?: a skippedActionIds: [], committedState: initialCommittedState, currentStateIndex: 0, - computedStates: [] + computedStates: [], }; } @@ -125,7 +134,9 @@ export function liftReducerWith( /** * Manages how the history actions modify the history state. */ - return (reducer: ActionReducer): ActionReducer => (liftedState, liftedAction) => { + return ( + reducer: ActionReducer + ): ActionReducer => (liftedState, liftedAction) => { let { monitorState, actionsById, @@ -134,8 +145,9 @@ export function liftReducerWith( skippedActionIds, committedState, currentStateIndex, - computedStates - } = liftedState || initialLiftedState; + computedStates, + } = + liftedState || initialLiftedState; if (!liftedState) { // Prevent mutating initialLiftedState @@ -158,13 +170,14 @@ export function liftReducerWith( } } - skippedActionIds = skippedActionIds.filter(id => idsToDelete.indexOf(id) === -1); + skippedActionIds = skippedActionIds.filter( + id => idsToDelete.indexOf(id) === -1 + ); stagedActionIds = [0, ...stagedActionIds.slice(excess + 1)]; committedState = computedStates[excess].state; computedStates = computedStates.slice(excess); - currentStateIndex = currentStateIndex > excess - ? currentStateIndex - excess - : 0; + currentStateIndex = + currentStateIndex > excess ? currentStateIndex - excess : 0; } // By default, agressively recompute every state whatever happens. @@ -249,7 +262,10 @@ export function liftReducerWith( // Forget any actions that are currently being skipped. stagedActionIds = difference(stagedActionIds, skippedActionIds); skippedActionIds = []; - currentStateIndex = Math.min(currentStateIndex, stagedActionIds.length - 1); + currentStateIndex = Math.min( + currentStateIndex, + stagedActionIds.length - 1 + ); break; } case Actions.PERFORM_ACTION: { @@ -280,7 +296,7 @@ export function liftReducerWith( skippedActionIds, committedState, currentStateIndex, - computedStates + computedStates, } = liftedAction.nextLiftedState); break; } @@ -336,7 +352,7 @@ export function liftReducerWith( skippedActionIds, committedState, currentStateIndex, - computedStates + computedStates, }; }; } diff --git a/modules/store-devtools/src/utils.ts b/modules/store-devtools/src/utils.ts index 9164d8c6a5..0862ae0c96 100644 --- a/modules/store-devtools/src/utils.ts +++ b/modules/store-devtools/src/utils.ts @@ -28,9 +28,11 @@ export function liftAction(action: Action) { return new Actions.PerformAction(action); } - -export function applyOperators(input$: Observable, operators: any[][]): Observable { - return operators.reduce((source$, [ operator, ...args ]) => { +export function applyOperators( + input$: Observable, + operators: any[][] +): Observable { + return operators.reduce((source$, [operator, ...args]) => { return operator.apply(source$, args); }, input$); -} \ No newline at end of file +} diff --git a/modules/store/spec/edge.spec.ts b/modules/store/spec/edge.spec.ts index 44e04067c8..0c5016dcda 100644 --- a/modules/store/spec/edge.spec.ts +++ b/modules/store/spec/edge.spec.ts @@ -3,28 +3,27 @@ import { todos, todoCount } from './fixtures/edge_todos'; import { createInjector } from './helpers/injector'; import { Store, StoreModule } from '../'; - interface TestAppSchema { counter1: number; counter2: number; counter3: number; } -interface Todo { } +interface Todo {} interface TodoAppSchema { todoCount: number; todos: Todo[]; } - - describe('ngRx Store', () => { describe('basic store actions', () => { let store: Store; beforeEach(() => { - const injector = createInjector(StoreModule.forRoot({ todos, todoCount } as any)); + const injector = createInjector( + StoreModule.forRoot({ todos, todoCount } as any) + ); store = injector.get(Store); }); @@ -33,13 +32,13 @@ describe('ngRx Store', () => { expect(store).toBeDefined(); }); - it('should handle re-entrancy', (done) => { + it('should handle re-entrancy', done => { let todosNextCount = 0; let todosCountNextCount = 0; store.select('todos').subscribe((todos: any[]) => { todosNextCount++; - store.dispatch({ type: 'SET_COUNT', payload: todos.length }) + store.dispatch({ type: 'SET_COUNT', payload: todos.length }); }); store.select('todoCount').subscribe(count => { diff --git a/modules/store/spec/fixtures/counter.ts b/modules/store/spec/fixtures/counter.ts index 2bd8d5eb37..1255e2f70c 100644 --- a/modules/store/spec/fixtures/counter.ts +++ b/modules/store/spec/fixtures/counter.ts @@ -1,6 +1,5 @@ import { Action } from '@ngrx/store'; - export const INCREMENT = 'INCREMENT'; export const DECREMENT = 'DECREMENT'; export const RESET = 'RESET'; @@ -16,4 +15,4 @@ export function counterReducer(state = 0, action: Action) { default: return state; } -}; +} diff --git a/modules/store/spec/fixtures/edge_todos.ts b/modules/store/spec/fixtures/edge_todos.ts index 966427d36f..3ebc751724 100644 --- a/modules/store/spec/fixtures/edge_todos.ts +++ b/modules/store/spec/fixtures/edge_todos.ts @@ -1,5 +1,3 @@ - - interface State { id: string; text: string; @@ -12,7 +10,7 @@ const todo = (state: State | undefined, action: any) => { return { id: action.payload.id, text: action.payload.text, - completed: false + completed: false, }; case 'TOGGLE_TODO': if (state!.id !== action.id) { @@ -20,7 +18,7 @@ const todo = (state: State | undefined, action: any) => { } return Object.assign({}, state, { - completed: !state!.completed + completed: !state!.completed, }); default: @@ -31,21 +29,16 @@ const todo = (state: State | undefined, action: any) => { export const todos = (state = [], action: any) => { switch (action.type) { case 'ADD_TODO': - return [ - ...state, - todo(undefined, action) - ]; + return [...state, todo(undefined, action)]; case 'TOGGLE_TODO': - return state.map(t => - todo(t, action) - ); + return state.map(t => todo(t, action)); default: return state; } }; export const todoCount = (state = 0, action: any) => { - switch (action.type){ + switch (action.type) { case 'SET_COUNT': return action.payload; default: diff --git a/modules/store/spec/fixtures/todos.ts b/modules/store/spec/fixtures/todos.ts index 4a54c8ff96..d00a905e1e 100644 --- a/modules/store/spec/fixtures/todos.ts +++ b/modules/store/spec/fixtures/todos.ts @@ -14,19 +14,25 @@ let _id = 0; export const VisibilityFilters = { SHOW_ALL: 'SHOW_ALL', SHOW_COMPLETED: 'SHOW_COMPLETED', - SHOW_ACTIVE: 'SHOW_ACTIVE' + SHOW_ACTIVE: 'SHOW_ACTIVE', }; -export function visibilityFilter(state = VisibilityFilters.SHOW_ALL, {type, payload}: any) { +export function visibilityFilter( + state = VisibilityFilters.SHOW_ALL, + { type, payload }: any +) { switch (type) { case SET_VISIBILITY_FILTER: return payload; default: return state; } -}; +} -export function todos(state: TodoItem[] = [], {type, payload}: any): TodoItem[] { +export function todos( + state: TodoItem[] = [], + { type, payload }: any +): TodoItem[] { switch (type) { case ADD_TODO: return [ @@ -34,16 +40,16 @@ export function todos(state: TodoItem[] = [], {type, payload}: any): TodoItem[] { id: ++_id, text: payload.text, - completed: false - } + completed: false, + }, ]; case COMPLETE_ALL_TODOS: return state.map(todo => ({ ...todo, completed: true })); case COMPLETE_TODO: - return state.map(todo => - todo.id === payload.id ? { ...todo, completed: true } : todo + return state.map( + todo => (todo.id === payload.id ? { ...todo, completed: true } : todo) ); default: return state; } -}; +} diff --git a/modules/store/spec/helpers/injector.ts b/modules/store/spec/helpers/injector.ts index 1884cd6ac1..c6f0f9e4b9 100644 --- a/modules/store/spec/helpers/injector.ts +++ b/modules/store/spec/helpers/injector.ts @@ -1,18 +1,29 @@ import { ReflectiveInjector, ModuleWithProviders } from '@angular/core'; - -export function createInjector({ ngModule, providers }: ModuleWithProviders): ReflectiveInjector { - const injector = ReflectiveInjector.resolveAndCreate([ ...(providers || []), ngModule ]); +export function createInjector({ + ngModule, + providers, +}: ModuleWithProviders): ReflectiveInjector { + const injector = ReflectiveInjector.resolveAndCreate([ + ...(providers || []), + ngModule, + ]); injector.get(ngModule); return injector; } -export function createChildInjector(parent: ReflectiveInjector, { ngModule, providers }: ModuleWithProviders): ReflectiveInjector { - const injector = parent.resolveAndCreateChild([ ...(providers || []), ngModule ]); +export function createChildInjector( + parent: ReflectiveInjector, + { ngModule, providers }: ModuleWithProviders +): ReflectiveInjector { + const injector = parent.resolveAndCreateChild([ + ...(providers || []), + ngModule, + ]); injector.get(ngModule); return injector; -} \ No newline at end of file +} diff --git a/modules/store/spec/integration.spec.ts b/modules/store/spec/integration.spec.ts index 9811d6b5be..c1ff475465 100644 --- a/modules/store/spec/integration.spec.ts +++ b/modules/store/spec/integration.spec.ts @@ -2,10 +2,30 @@ import 'rxjs/add/observable/combineLatest'; import 'rxjs/add/operator/first'; import { Observable } from 'rxjs/Observable'; import { TestBed } from '@angular/core/testing'; -import { Store, StoreModule, Action, combineReducers, ActionReducer, ActionReducerMap } from '../'; +import { + Store, + StoreModule, + Action, + combineReducers, + ActionReducer, + ActionReducerMap, +} from '../'; import { ReducerManager, INITIAL_STATE, State } from '../src/private_export'; -import { counterReducer, INCREMENT, DECREMENT, RESET } from './fixtures/counter'; -import { todos, visibilityFilter, VisibilityFilters, SET_VISIBILITY_FILTER, ADD_TODO, COMPLETE_TODO, COMPLETE_ALL_TODOS } from './fixtures/todos'; +import { + counterReducer, + INCREMENT, + DECREMENT, + RESET, +} from './fixtures/counter'; +import { + todos, + visibilityFilter, + VisibilityFilters, + SET_VISIBILITY_FILTER, + ADD_TODO, + COMPLETE_TODO, + COMPLETE_ALL_TODOS, +} from './fixtures/todos'; interface Todo { id: number; @@ -19,21 +39,24 @@ interface TodoAppSchema { } describe('ngRx Integration spec', () => { - describe('todo integration spec', function() { let store: Store; let state: State; - const initialState = { todos: [], visibilityFilter: VisibilityFilters.SHOW_ALL }; - const reducers: ActionReducerMap = { todos: todos, visibilityFilter: visibilityFilter }; + const initialState = { + todos: [], + visibilityFilter: VisibilityFilters.SHOW_ALL, + }; + const reducers: ActionReducerMap = { + todos: todos, + visibilityFilter: visibilityFilter, + }; beforeEach(() => { spyOn(reducers, 'todos').and.callThrough(); TestBed.configureTestingModule({ - imports: [ - StoreModule.forRoot(reducers, { initialState }), - ] + imports: [StoreModule.forRoot(reducers, { initialState })], }); store = TestBed.get(Store); @@ -88,7 +111,10 @@ describe('ngRx Integration spec', () => { it('should complete the first todo', () => { store.dispatch({ type: ADD_TODO, payload: { text: 'first todo' } }); - store.dispatch({ type: COMPLETE_TODO, payload: { id: state.value.todos[0].id } }); + store.dispatch({ + type: COMPLETE_TODO, + payload: { id: state.value.todos[0].id }, + }); expect(state.value.todos[0].completed).toEqual(true); }); @@ -96,17 +122,18 @@ describe('ngRx Integration spec', () => { it('should use visibilityFilter to filter todos', () => { store.dispatch({ type: ADD_TODO, payload: { text: 'first todo' } }); store.dispatch({ type: ADD_TODO, payload: { text: 'second todo' } }); - store.dispatch({ type: COMPLETE_TODO, payload: { id: state.value.todos[0].id } }); + store.dispatch({ + type: COMPLETE_TODO, + payload: { id: state.value.todos[0].id }, + }); const filterVisibleTodos = (visibilityFilter: any, todos: any) => { let predicate; if (visibilityFilter === VisibilityFilters.SHOW_ALL) { predicate = () => true; - } - else if (visibilityFilter === VisibilityFilters.SHOW_ACTIVE) { + } else if (visibilityFilter === VisibilityFilters.SHOW_ACTIVE) { predicate = (todo: any) => !todo.completed; - } - else { + } else { predicate = (todo: any) => todo.completed; } return todos.filter(predicate); @@ -114,19 +141,28 @@ describe('ngRx Integration spec', () => { let currentlyVisibleTodos: any; - Observable.combineLatest(store.select('visibilityFilter'), store.select('todos'), filterVisibleTodos) - .subscribe(visibleTodos => { - currentlyVisibleTodos = visibleTodos; - }); + Observable.combineLatest( + store.select('visibilityFilter'), + store.select('todos'), + filterVisibleTodos + ).subscribe(visibleTodos => { + currentlyVisibleTodos = visibleTodos; + }); expect(currentlyVisibleTodos.length).toBe(2); - store.dispatch({ type: SET_VISIBILITY_FILTER, payload: VisibilityFilters.SHOW_ACTIVE }); + store.dispatch({ + type: SET_VISIBILITY_FILTER, + payload: VisibilityFilters.SHOW_ACTIVE, + }); expect(currentlyVisibleTodos.length).toBe(1); expect(currentlyVisibleTodos[0].completed).toBe(false); - store.dispatch({ type: SET_VISIBILITY_FILTER, payload: VisibilityFilters.SHOW_COMPLETED }); + store.dispatch({ + type: SET_VISIBILITY_FILTER, + payload: VisibilityFilters.SHOW_COMPLETED, + }); expect(currentlyVisibleTodos.length).toBe(1); expect(currentlyVisibleTodos[0].completed).toBe(true); @@ -137,10 +173,12 @@ describe('ngRx Integration spec', () => { expect(currentlyVisibleTodos[0].completed).toBe(true); expect(currentlyVisibleTodos[1].completed).toBe(true); - store.dispatch({ type: SET_VISIBILITY_FILTER, payload: VisibilityFilters.SHOW_ACTIVE }); + store.dispatch({ + type: SET_VISIBILITY_FILTER, + payload: VisibilityFilters.SHOW_ACTIVE, + }); expect(currentlyVisibleTodos.length).toBe(0); - }); }); }); diff --git a/modules/store/spec/modules.spec.ts b/modules/store/spec/modules.spec.ts index 26fbcc691f..4a01a25404 100644 --- a/modules/store/spec/modules.spec.ts +++ b/modules/store/spec/modules.spec.ts @@ -3,16 +3,17 @@ import { TestBed } from '@angular/core/testing'; import { NgModule, InjectionToken } from '@angular/core'; import { StoreModule, Store, ActionReducer, ActionReducerMap } from '../'; - describe('Nested Store Modules', () => { type RootState = { fruit: string }; type FeatureAState = number; - type FeatureBState = { list: number[], index: number }; + type FeatureBState = { list: number[]; index: number }; type State = RootState & { a: FeatureAState } & { b: FeatureBState }; let store: Store; - const reducersToken = new InjectionToken>('Root Reducers'); + const reducersToken = new InjectionToken>( + 'Root Reducers' + ); const rootFruitReducer: ActionReducer = () => 'apple'; const featureAReducer: ActionReducer = () => 5; const featureBListReducer: ActionReducer = () => [1, 2, 3]; @@ -23,18 +24,14 @@ describe('Nested Store Modules', () => { }; @NgModule({ - imports: [ - StoreModule.forFeature('a', featureAReducer), - ] + imports: [StoreModule.forFeature('a', featureAReducer)], }) - class FeatureAModule { } + class FeatureAModule {} @NgModule({ - imports: [ - StoreModule.forFeature('b', featureBReducerMap), - ] + imports: [StoreModule.forFeature('b', featureBReducerMap)], }) - class FeatureBModule { } + class FeatureBModule {} @NgModule({ imports: [ @@ -46,16 +43,14 @@ describe('Nested Store Modules', () => { { provide: reducersToken, useValue: { fruit: rootFruitReducer }, - } - ] + }, + ], }) - class RootModule { } + class RootModule {} beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - RootModule, - ] + imports: [RootModule], }); store = TestBed.get(Store); @@ -69,9 +64,8 @@ describe('Nested Store Modules', () => { b: { list: [1, 2, 3], index: 2, - } + }, }); }); }); }); - diff --git a/modules/store/spec/ngc/main.ts b/modules/store/spec/ngc/main.ts index baed338dee..b5c12ff6c2 100644 --- a/modules/store/spec/ngc/main.ts +++ b/modules/store/spec/ngc/main.ts @@ -10,22 +10,16 @@ import { Observable } from 'rxjs/Observable'; selector: 'ngc-spec-child-component', template: ` - ` + `, }) -export class NgcSpecChildComponent { } +export class NgcSpecChildComponent {} @NgModule({ - imports: [ - StoreModule.forFeature('feature', { todos: todos }) - ], - declarations: [ - NgcSpecChildComponent, - ], - exports: [ - NgcSpecChildComponent, - ] + imports: [StoreModule.forFeature('feature', { todos: todos })], + declarations: [NgcSpecChildComponent], + exports: [NgcSpecChildComponent], }) -export class FeatureModule { } +export class FeatureModule {} export interface AppState { count: number; @@ -41,7 +35,7 @@ export const reducerToken = new InjectionToken('Reducers'); - ` + `, }) export class NgcSpecComponent { count: Observable; @@ -61,17 +55,17 @@ export class NgcSpecComponent { BrowserModule, StoreModule.forRoot(reducerToken, { initialState: { count: 0 }, - reducerFactory: combineReducers + reducerFactory: combineReducers, }), - FeatureModule + FeatureModule, ], providers: [ { provide: reducerToken, - useValue: { count: counterReducer } - } + useValue: { count: counterReducer }, + }, ], declarations: [NgcSpecComponent], - bootstrap: [NgcSpecComponent] + bootstrap: [NgcSpecComponent], }) -export class NgcSpecModule { } +export class NgcSpecModule {} diff --git a/modules/store/spec/selector.spec.ts b/modules/store/spec/selector.spec.ts index 7ff4d15de6..d2db3ddb8c 100644 --- a/modules/store/spec/selector.spec.ts +++ b/modules/store/spec/selector.spec.ts @@ -3,7 +3,6 @@ import 'rxjs/add/operator/map'; import { cold } from 'jasmine-marbles'; import { createSelector, createFeatureSelector } from '../'; - describe('Selectors', () => { let countOne: number; let countTwo: number; @@ -35,7 +34,9 @@ describe('Selectors', () => { it('should deliver the value of selectors to the projection function', () => { const projectFn = jasmine.createSpy('projectionFn'); - const selector = createSelector(incrementOne, incrementTwo, projectFn)({ }); + const selector = createSelector(incrementOne, incrementTwo, projectFn)( + {} + ); expect(projectFn).toHaveBeenCalledWith(countOne, countTwo); }); @@ -44,7 +45,12 @@ describe('Selectors', () => { const firstState = { first: 'state' }; const secondState = { second: 'state' }; const projectFn = jasmine.createSpy('projectionFn'); - const selector = createSelector(incrementOne, incrementTwo, incrementThree, projectFn); + const selector = createSelector( + incrementOne, + incrementTwo, + incrementThree, + projectFn + ); selector(firstState); selector(firstState); @@ -99,8 +105,11 @@ describe('Selectors', () => { const secondValue = { secondValue: 'value' }; const secondState = { [featureName]: secondValue }; - const state$ = cold('--a--a--a--b--', { a: firstState, b: secondState }); - const expected$ = cold('--a--------b--', { a: firstValue, b: secondValue }); + const state$ = cold('--a--a--a--b--', { a: firstState, b: secondState }); + const expected$ = cold('--a--------b--', { + a: firstValue, + b: secondValue, + }); const featureState$ = state$.map(featureSelector).distinctUntilChanged(); expect(featureState$).toBeObservable(expected$); diff --git a/modules/store/spec/state.spec.ts b/modules/store/spec/state.spec.ts index 708a9836a5..3daaee21f7 100644 --- a/modules/store/spec/state.spec.ts +++ b/modules/store/spec/state.spec.ts @@ -1,23 +1,28 @@ -import {Observable} from 'rxjs/Observable'; -import {Subject} from 'rxjs/Subject'; -import {ReflectiveInjector} from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { Subject } from 'rxjs/Subject'; +import { ReflectiveInjector } from '@angular/core'; import { createInjector } from './helpers/injector'; import { StoreModule, Store } from '../'; - describe('ngRx State', () => { const initialState = 123; const reducer = jasmine.createSpy('reducer').and.returnValue(initialState); let injector: ReflectiveInjector; beforeEach(() => { - injector = createInjector(StoreModule.forRoot({ key: reducer }, { initialState: { key: initialState } })); + injector = createInjector( + StoreModule.forRoot( + { key: reducer }, + { initialState: { key: initialState } } + ) + ); }); it('should call the reducer to scan over the dispatcher', function() { injector.get(Store); - expect(reducer).toHaveBeenCalledWith(initialState, { type: '@ngrx/store/init' }); + expect(reducer).toHaveBeenCalledWith(initialState, { + type: '@ngrx/store/init', + }); }); - }); diff --git a/modules/store/spec/store.spec.ts b/modules/store/spec/store.spec.ts index 5be892ace6..d737b432c6 100644 --- a/modules/store/spec/store.spec.ts +++ b/modules/store/spec/store.spec.ts @@ -5,8 +5,12 @@ import { hot } from 'jasmine-marbles'; import { createInjector } from './helpers/injector'; import { Store, Action, combineReducers, StoreModule } from '../'; import { ActionsSubject } from '../src/private_export'; -import { counterReducer, INCREMENT, DECREMENT, RESET } from './fixtures/counter'; - +import { + counterReducer, + INCREMENT, + DECREMENT, + RESET, +} from './fixtures/counter'; interface TestAppSchema { counter1: number; @@ -14,7 +18,7 @@ interface TestAppSchema { counter3: number; } -interface Todo { } +interface Todo {} interface TodoAppSchema { visibilityFilter: string; @@ -30,7 +34,7 @@ describe('ngRx Store', () => { const reducers = { counter1: counterReducer, counter2: counterReducer, - counter3: counterReducer + counter3: counterReducer, }; injector = createInjector(StoreModule.forRoot(reducers, { initialState })); @@ -39,7 +43,7 @@ describe('ngRx Store', () => { } describe('initial state', () => { - it('should handle an initial state object', (done) => { + it('should handle an initial state object', done => { setup(); store.take(1).subscribe({ @@ -47,11 +51,11 @@ describe('ngRx Store', () => { expect(val).toEqual({ counter1: 0, counter2: 1, counter3: 0 }); }, error: done, - complete: done + complete: done, }); }); - it('should handle an initial state function', (done) => { + it('should handle an initial state function', done => { setup(() => ({ counter1: 0, counter2: 5 })); store.take(1).subscribe({ @@ -59,7 +63,7 @@ describe('ngRx Store', () => { expect(val).toEqual({ counter1: 0, counter2: 5, counter3: 0 }); }, error: done, - complete: done + complete: done, }); }); }); @@ -77,52 +81,49 @@ describe('ngRx Store', () => { b: { type: INCREMENT }, c: { type: DECREMENT }, d: { type: RESET }, - e: { type: INCREMENT } + e: { type: INCREMENT }, }; it('should let you select state with a key name', function() { - const counterSteps = hot(actionSequence, actionValues); - counterSteps.subscribe((action) => store.dispatch(action)); + counterSteps.subscribe(action => store.dispatch(action)); const counterStateWithString = store.select('counter1'); const stateSequence = 'i-v--w--x--y--z'; const counter1Values = { i: 0, v: 1, w: 2, x: 1, y: 0, z: 1 }; - expect(counterStateWithString).toBeObservable(hot(stateSequence, counter1Values)); - + expect(counterStateWithString).toBeObservable( + hot(stateSequence, counter1Values) + ); }); it('should let you select state with a selector function', function() { - const counterSteps = hot(actionSequence, actionValues); - counterSteps.subscribe((action) => store.dispatch(action)); + counterSteps.subscribe(action => store.dispatch(action)); const counterStateWithFunc = store.select(s => s.counter1); const stateSequence = 'i-v--w--x--y--z'; const counter1Values = { i: 0, v: 1, w: 2, x: 1, y: 0, z: 1 }; - expect(counterStateWithFunc).toBeObservable(hot(stateSequence, counter1Values)); - + expect(counterStateWithFunc).toBeObservable( + hot(stateSequence, counter1Values) + ); }); it('should correctly lift itself', function() { - const result = store.select('counter1'); expect(result instanceof Store).toBe(true); - }); it('should increment and decrement counter1', function() { - const counterSteps = hot(actionSequence, actionValues); - counterSteps.subscribe((action) => store.dispatch(action)); + counterSteps.subscribe(action => store.dispatch(action)); const counterState = store.select('counter1'); @@ -130,14 +131,12 @@ describe('ngRx Store', () => { const counter1Values = { i: 0, v: 1, w: 2, x: 1, y: 0, z: 1 }; expect(counterState).toBeObservable(hot(stateSequence, counter1Values)); - }); it('should increment and decrement counter1 using the dispatcher', function() { - const counterSteps = hot(actionSequence, actionValues); - counterSteps.subscribe((action) => dispatcher.next(action)); + counterSteps.subscribe(action => dispatcher.next(action)); const counterState = store.select('counter1'); @@ -147,12 +146,10 @@ describe('ngRx Store', () => { expect(counterState).toBeObservable(hot(stateSequence, counter1Values)); }); - it('should increment and decrement counter2 separately', function() { - const counterSteps = hot(actionSequence, actionValues); - counterSteps.subscribe((action) => store.dispatch(action)); + counterSteps.subscribe(action => store.dispatch(action)); const counter1State = store.select('counter1'); const counter2State = store.select('counter2'); @@ -161,11 +158,9 @@ describe('ngRx Store', () => { const counter2Values = { i: 1, v: 2, w: 3, x: 2, y: 0, z: 1 }; expect(counter2State).toBeObservable(hot(stateSequence, counter2Values)); - }); it('should implement the observer interface forwarding actions and errors to the dispatcher', function() { - spyOn(dispatcher, 'next'); spyOn(dispatcher, 'error'); @@ -174,11 +169,9 @@ describe('ngRx Store', () => { expect(dispatcher.next).toHaveBeenCalledWith(1); expect(dispatcher.error).toHaveBeenCalledWith(2); - }); it('should not be completable', function() { - const storeSubscription = store.subscribe(); const dispatcherSubscription = dispatcher.subscribe(); diff --git a/modules/store/src/actions_subject.ts b/modules/store/src/actions_subject.ts index 6db69dd8cd..418af4779c 100644 --- a/modules/store/src/actions_subject.ts +++ b/modules/store/src/actions_subject.ts @@ -4,11 +4,11 @@ import { Observable } from 'rxjs/Observable'; import { Observer } from 'rxjs/Observer'; import { Action } from './models'; - export const INIT = '@ngrx/store/init'; @Injectable() -export class ActionsSubject extends BehaviorSubject implements OnDestroy { +export class ActionsSubject extends BehaviorSubject + implements OnDestroy { constructor() { super({ type: INIT }); } @@ -16,21 +16,20 @@ export class ActionsSubject extends BehaviorSubject implements OnDestroy next(action: Action): void { if (typeof action === 'undefined') { throw new Error(`Actions must be objects`); - } - else if (typeof action.type === 'undefined') { + } else if (typeof action.type === 'undefined') { throw new Error(`Actions must have a type property`); } super.next(action); } - complete() { /* noop */ } + complete() { + /* noop */ + } ngOnDestroy() { super.complete(); } } -export const ACTIONS_SUBJECT_PROVIDERS: Provider[] = [ - ActionsSubject -]; +export const ACTIONS_SUBJECT_PROVIDERS: Provider[] = [ActionsSubject]; diff --git a/modules/store/src/index.ts b/modules/store/src/index.ts index 070239fce7..7de2025aaa 100644 --- a/modules/store/src/index.ts +++ b/modules/store/src/index.ts @@ -1,11 +1,36 @@ -export { Action, ActionReducer, ActionReducerMap, ActionReducerFactory, Selector } from './models'; +export { + Action, + ActionReducer, + ActionReducerMap, + ActionReducerFactory, + Selector, +} from './models'; export { StoreModule } from './store_module'; export { Store } from './store'; export { combineReducers, compose } from './utils'; export { ActionsSubject, INIT } from './actions_subject'; -export { ReducerManager, ReducerObservable, ReducerManagerDispatcher, UPDATE } from './reducer_manager'; +export { + ReducerManager, + ReducerObservable, + ReducerManagerDispatcher, + UPDATE, +} from './reducer_manager'; export { ScannedActionsSubject } from './scanned_actions_subject'; -export { createSelector, createFeatureSelector, MemoizedSelector } from './selector'; +export { + createSelector, + createFeatureSelector, + MemoizedSelector, +} from './selector'; export { State, StateObservable, reduceState } from './state'; -export { INITIAL_STATE, REDUCER_FACTORY, INITIAL_REDUCERS, STORE_FEATURES, _INITIAL_STATE } from './tokens'; -export { StoreRootModule, StoreFeatureModule, _initialStateFactory } from './store_module'; +export { + INITIAL_STATE, + REDUCER_FACTORY, + INITIAL_REDUCERS, + STORE_FEATURES, + _INITIAL_STATE, +} from './tokens'; +export { + StoreRootModule, + StoreFeatureModule, + _initialStateFactory, +} from './store_module'; diff --git a/modules/store/src/models.ts b/modules/store/src/models.ts index 1bf2067dbd..412de203b3 100644 --- a/modules/store/src/models.ts +++ b/modules/store/src/models.ts @@ -11,11 +11,14 @@ export interface ActionReducer { } export type ActionReducerMap = { - [p in keyof T]: ActionReducer; + [p in keyof T]: ActionReducer }; export interface ActionReducerFactory { - (reducerMap: ActionReducerMap, initialState?: InitialState): ActionReducer; + ( + reducerMap: ActionReducerMap, + initialState?: InitialState + ): ActionReducer; } export interface StoreFeature { diff --git a/modules/store/src/private_export.ts b/modules/store/src/private_export.ts index b06535b90c..fedc33daeb 100644 --- a/modules/store/src/private_export.ts +++ b/modules/store/src/private_export.ts @@ -2,5 +2,10 @@ export { ActionsSubject } from './actions_subject'; export { ReducerManager, ReducerObservable } from './reducer_manager'; export { ScannedActionsSubject } from './scanned_actions_subject'; export { State, StateObservable, reduceState } from './state'; -export { INITIAL_STATE, REDUCER_FACTORY, INITIAL_REDUCERS, STORE_FEATURES } from './tokens'; +export { + INITIAL_STATE, + REDUCER_FACTORY, + INITIAL_REDUCERS, + STORE_FEATURES, +} from './tokens'; export { StoreRootModule, StoreFeatureModule } from './store_module'; diff --git a/modules/store/src/reducer_manager.ts b/modules/store/src/reducer_manager.ts index cd7e12abca..1b3a1f3d81 100644 --- a/modules/store/src/reducer_manager.ts +++ b/modules/store/src/reducer_manager.ts @@ -1,29 +1,46 @@ import { Injectable, Inject, OnDestroy, Provider } from '@angular/core'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { Observable } from 'rxjs/Observable'; -import { Action, ActionReducer, ActionReducerMap, ActionReducerFactory, StoreFeature } from './models'; +import { + Action, + ActionReducer, + ActionReducerMap, + ActionReducerFactory, + StoreFeature, +} from './models'; import { INITIAL_STATE, INITIAL_REDUCERS, REDUCER_FACTORY } from './tokens'; import { omit } from './utils'; import { ActionsSubject } from './actions_subject'; - -export abstract class ReducerObservable extends Observable> { } -export abstract class ReducerManagerDispatcher extends ActionsSubject { } +export abstract class ReducerObservable extends Observable< + ActionReducer +> {} +export abstract class ReducerManagerDispatcher extends ActionsSubject {} export const UPDATE = '@ngrx/store/update-reducers'; @Injectable() -export class ReducerManager extends BehaviorSubject> implements OnDestroy { +export class ReducerManager extends BehaviorSubject> + implements OnDestroy { constructor( private dispatcher: ReducerManagerDispatcher, @Inject(INITIAL_STATE) private initialState: any, @Inject(INITIAL_REDUCERS) private reducers: ActionReducerMap, - @Inject(REDUCER_FACTORY) private reducerFactory: ActionReducerFactory + @Inject(REDUCER_FACTORY) + private reducerFactory: ActionReducerFactory ) { super(reducerFactory(reducers, initialState)); } - addFeature({ reducers, reducerFactory, initialState, key }: StoreFeature) { - const reducer = typeof reducers === 'function' ? reducers : reducerFactory(reducers, initialState); + addFeature({ + reducers, + reducerFactory, + initialState, + key, + }: StoreFeature) { + const reducer = + typeof reducers === 'function' + ? reducers + : reducerFactory(reducers, initialState); this.addReducer(key, reducer); } diff --git a/modules/store/src/scanned_actions_subject.ts b/modules/store/src/scanned_actions_subject.ts index a66c394612..76a0198659 100644 --- a/modules/store/src/scanned_actions_subject.ts +++ b/modules/store/src/scanned_actions_subject.ts @@ -2,9 +2,9 @@ import { Injectable, Provider, OnDestroy } from '@angular/core'; import { Subject } from 'rxjs/Subject'; import { Action } from './models'; - @Injectable() -export class ScannedActionsSubject extends Subject implements OnDestroy { +export class ScannedActionsSubject extends Subject + implements OnDestroy { ngOnDestroy() { this.complete(); } diff --git a/modules/store/src/selector.ts b/modules/store/src/selector.ts index 7cfa4a8d7c..674d15f242 100644 --- a/modules/store/src/selector.ts +++ b/modules/store/src/selector.ts @@ -1,13 +1,13 @@ import { Selector } from './models'; - -export interface MemoizedSelector extends Selector { +export interface MemoizedSelector + extends Selector { release(): void; } export type AnyFn = (...args: any[]) => any; -export function memoize(t: AnyFn): { memoized: AnyFn, reset: () => void } { +export function memoize(t: AnyFn): { memoized: AnyFn; reset: () => void } { let lastArguments: null | IArguments = null; let lastResult: any = null; @@ -45,20 +45,20 @@ export function createSelector( export function createSelector( s1: Selector, s2: Selector, - projector: (s1: S1, s2: S2) => Result, + projector: (s1: S1, s2: S2) => Result ): MemoizedSelector; export function createSelector( s1: Selector, s2: Selector, s3: Selector, - projector: (s1: S1, s2: S2, s3: S3) => Result, + projector: (s1: S1, s2: S2, s3: S3) => Result ): MemoizedSelector; export function createSelector( s1: Selector, s2: Selector, s3: Selector, s4: Selector, - projector: (s1: S1, s2: S2, s3: S3, s4: S4) => Result, + projector: (s1: S1, s2: S2, s3: S3, s4: S4) => Result ): MemoizedSelector; export function createSelector( s1: Selector, @@ -66,7 +66,7 @@ export function createSelector( s3: Selector, s4: Selector, s5: Selector, - projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5) => Result, + projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5) => Result ): MemoizedSelector; export function createSelector( s1: Selector, @@ -75,7 +75,7 @@ export function createSelector( s4: Selector, s5: Selector, s6: Selector, - projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, s6: S6) => Result, + projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, s6: S6) => Result ): MemoizedSelector; export function createSelector( s1: Selector, @@ -85,7 +85,7 @@ export function createSelector( s5: Selector, s6: Selector, s7: Selector, - projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, s6: S6, s7: S7) => Result, + projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, s6: S6, s7: S7) => Result ): MemoizedSelector; export function createSelector( s1: Selector, @@ -96,14 +96,26 @@ export function createSelector( s6: Selector, s7: Selector, s8: Selector, - projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, s6: S6, s7: S7, s8: S8) => Result, + projector: ( + s1: S1, + s2: S2, + s3: S3, + s4: S4, + s5: S5, + s6: S6, + s7: S7, + s8: S8 + ) => Result ): MemoizedSelector; export function createSelector(...args: any[]): Selector { const selectors = args.slice(0, args.length - 1); const projector = args[args.length - 1]; - const memoizedSelectors = selectors.filter((selector: any) => selector.release && typeof selector.release === 'function'); + const memoizedSelectors = selectors.filter( + (selector: any) => + selector.release && typeof selector.release === 'function' + ); - const { memoized, reset } = memoize(function (state: any) { + const { memoized, reset } = memoize(function(state: any) { const args = selectors.map(fn => fn(state)); return projector.apply(null, args); @@ -118,8 +130,10 @@ export function createSelector(...args: any[]): Selector { return Object.assign(memoized, { release }); } -export function createFeatureSelector(featureName: string): MemoizedSelector { - const { memoized, reset } = memoize(function (state: any): any { +export function createFeatureSelector( + featureName: string +): MemoizedSelector { + const { memoized, reset } = memoize(function(state: any): any { return state[featureName]; }); @@ -127,5 +141,7 @@ export function createFeatureSelector(featureName: string): MemoizedSelector< } export function isSelector(v: any): v is MemoizedSelector { - return typeof v === 'function' && v.release && typeof v.release === 'function'; + return ( + typeof v === 'function' && v.release && typeof v.release === 'function' + ); } diff --git a/modules/store/src/state.ts b/modules/store/src/state.ts index a13a44469e..296e3007fd 100644 --- a/modules/store/src/state.ts +++ b/modules/store/src/state.ts @@ -13,8 +13,7 @@ import { INITIAL_STATE } from './tokens'; import { ReducerObservable } from './reducer_manager'; import { ScannedActionsSubject } from './scanned_actions_subject'; - -export abstract class StateObservable extends Observable { } +export abstract class StateObservable extends Observable {} @Injectable() export class State extends BehaviorSubject implements OnDestroy { @@ -31,14 +30,19 @@ export class State extends BehaviorSubject implements OnDestroy { super(initialState); const actionsOnQueue$: Observable = observeOn.call(actions$, queue); - const withLatestReducer$: Observable<[ Action, ActionReducer ]> = withLatestFrom.call(actionsOnQueue$, reducer$); - const stateAndAction$: Observable<{ state: any, action: Action }> = scan.call(withLatestReducer$, reduceState, initialState); + const withLatestReducer$: Observable< + [Action, ActionReducer] + > = withLatestFrom.call(actionsOnQueue$, reducer$); + const stateAndAction$: Observable<{ + state: any; + action: Action; + }> = scan.call(withLatestReducer$, reduceState, initialState); this.stateSubscription = stateAndAction$.subscribe({ next: ({ state, action }) => { this.next(state); scannedActions.next(action); - } + }, }); } @@ -48,10 +52,13 @@ export class State extends BehaviorSubject implements OnDestroy { } } -export type StateActionPair = { state: T | undefined, action?: V }; +export type StateActionPair = { + state: T | undefined; + action?: V; +}; export function reduceState( { state }: StateActionPair = { state: undefined }, - [ action, reducer ]: [ V, ActionReducer ] + [action, reducer]: [V, ActionReducer] ): StateActionPair { return { state: reducer(state, action), action }; } diff --git a/modules/store/src/store.ts b/modules/store/src/store.ts index 23ec4242e3..b509612712 100644 --- a/modules/store/src/store.ts +++ b/modules/store/src/store.ts @@ -11,7 +11,6 @@ import { StateObservable } from './state'; import { ReducerManager } from './reducer_manager'; import { isSelector, createSelector } from './selector'; - @Injectable() export class Store extends Observable implements Observer { constructor( @@ -26,26 +25,60 @@ export class Store extends Observable implements Observer { select(mapFn: (state: T) => K): Store; select(key: a): Store; - select(key1: a, key2: b): Store - select(key1: a, key2: b, key3: c): Store - select(key1: a, key2: b, key3: c, key4: d): Store - select(key1: a, key2: b, key3: c, key4: d, key5: e): Store - select(key1: a, key2: b, key3: c, key4: d, key5: e, key6: f): Store - select(pathOrMapFn: ((state: T) => any) | string, ...paths: string[]): Store { + select( + key1: a, + key2: b + ): Store; + select( + key1: a, + key2: b, + key3: c + ): Store; + select< + a extends keyof T, + b extends keyof T[a], + c extends keyof T[a][b], + d extends keyof T[a][b][c] + >(key1: a, key2: b, key3: c, key4: d): Store; + select< + a extends keyof T, + b extends keyof T[a], + c extends keyof T[a][b], + d extends keyof T[a][b][c], + e extends keyof T[a][b][c][d] + >(key1: a, key2: b, key3: c, key4: d, key5: e): Store; + select< + a extends keyof T, + b extends keyof T[a], + c extends keyof T[a][b], + d extends keyof T[a][b][c], + e extends keyof T[a][b][c][d], + f extends keyof T[a][b][c][d][e] + >( + key1: a, + key2: b, + key3: c, + key4: d, + key5: e, + key6: f + ): Store; + select( + pathOrMapFn: ((state: T) => any) | string, + ...paths: string[] + ): Store { let mapped$: Store; if (typeof pathOrMapFn === 'string') { mapped$ = pluck.call(this, pathOrMapFn, ...paths); - } - else if (typeof pathOrMapFn === 'function' && isSelector(pathOrMapFn)) { + } else if (typeof pathOrMapFn === 'function' && isSelector(pathOrMapFn)) { mapped$ = map.call(this, pathOrMapFn); - } - else if (typeof pathOrMapFn === 'function') { + } else if (typeof pathOrMapFn === 'function') { mapped$ = map.call(this, createSelector(s => s, pathOrMapFn)); - } - else { - throw new TypeError(`Unexpected type '${typeof pathOrMapFn}' in select operator,` - + ` expected 'string' or 'function'`); + } else { + throw new TypeError( + `Unexpected type '${typeof pathOrMapFn}' in select operator,` + + ` expected 'string' or 'function'` + ); } return distinctUntilChanged.call(mapped$); @@ -74,7 +107,10 @@ export class Store extends Observable implements Observer { this.actionsObserver.complete(); } - addReducer(key: string, reducer: ActionReducer) { + addReducer( + key: string, + reducer: ActionReducer + ) { this.reducerManager.addReducer(key, reducer); } @@ -83,6 +119,4 @@ export class Store extends Observable implements Observer { } } -export const STORE_PROVIDERS: Provider[] = [ - Store -]; +export const STORE_PROVIDERS: Provider[] = [Store]; diff --git a/modules/store/src/store_module.ts b/modules/store/src/store_module.ts index e0964e3375..a246e92f01 100644 --- a/modules/store/src/store_module.ts +++ b/modules/store/src/store_module.ts @@ -1,10 +1,36 @@ -import { NgModule, Inject, ModuleWithProviders, OnDestroy, InjectionToken } from '@angular/core'; -import { Action, ActionReducer, ActionReducerMap, ActionReducerFactory, StoreFeature, InitialState } from './models'; +import { + NgModule, + Inject, + ModuleWithProviders, + OnDestroy, + InjectionToken, +} from '@angular/core'; +import { + Action, + ActionReducer, + ActionReducerMap, + ActionReducerFactory, + StoreFeature, + InitialState, +} from './models'; import { combineReducers } from './utils'; -import { INITIAL_STATE, INITIAL_REDUCERS, REDUCER_FACTORY, STORE_FEATURES, _INITIAL_STATE } from './tokens'; +import { + INITIAL_STATE, + INITIAL_REDUCERS, + REDUCER_FACTORY, + STORE_FEATURES, + _INITIAL_STATE, +} from './tokens'; import { ACTIONS_SUBJECT_PROVIDERS, ActionsSubject } from './actions_subject'; -import { REDUCER_MANAGER_PROVIDERS, ReducerManager, ReducerObservable } from './reducer_manager'; -import { SCANNED_ACTIONS_SUBJECT_PROVIDERS, ScannedActionsSubject } from './scanned_actions_subject'; +import { + REDUCER_MANAGER_PROVIDERS, + ReducerManager, + ReducerObservable, +} from './reducer_manager'; +import { + SCANNED_ACTIONS_SUBJECT_PROVIDERS, + ScannedActionsSubject, +} from './scanned_actions_subject'; import { STATE_PROVIDERS } from './state'; import { STORE_PROVIDERS } from './store'; @@ -13,10 +39,8 @@ export class StoreRootModule { constructor( actions$: ActionsSubject, reducer$: ReducerObservable, - scannedActions$: ScannedActionsSubject, - ) { - - } + scannedActions$: ScannedActionsSubject + ) {} } @NgModule({}) @@ -29,35 +53,71 @@ export class StoreFeatureModule implements OnDestroy { } ngOnDestroy() { - this.features.forEach(feature => this.reducerManager.removeFeature(feature)); + this.features.forEach(feature => + this.reducerManager.removeFeature(feature) + ); } } -export type StoreConfig = { initialState?: InitialState, reducerFactory?: ActionReducerFactory }; +export type StoreConfig = { + initialState?: InitialState; + reducerFactory?: ActionReducerFactory; +}; @NgModule({}) export class StoreModule { - static forRoot(reducers: ActionReducerMap | InjectionToken>, config?: StoreConfig): ModuleWithProviders; - static forRoot(reducers: ActionReducerMap | InjectionToken>, config: StoreConfig = {}): ModuleWithProviders { + static forRoot( + reducers: ActionReducerMap | InjectionToken>, + config?: StoreConfig + ): ModuleWithProviders; + static forRoot( + reducers: + | ActionReducerMap + | InjectionToken>, + config: StoreConfig = {} + ): ModuleWithProviders { return { ngModule: StoreRootModule, providers: [ { provide: _INITIAL_STATE, useValue: config.initialState }, - { provide: INITIAL_STATE, useFactory: _initialStateFactory, deps: [ _INITIAL_STATE ] }, - reducers instanceof InjectionToken ? { provide: INITIAL_REDUCERS, useExisting: reducers } : { provide: INITIAL_REDUCERS, useValue: reducers }, - { provide: REDUCER_FACTORY, useValue: config.reducerFactory ? config.reducerFactory : combineReducers }, + { + provide: INITIAL_STATE, + useFactory: _initialStateFactory, + deps: [_INITIAL_STATE], + }, + reducers instanceof InjectionToken + ? { provide: INITIAL_REDUCERS, useExisting: reducers } + : { provide: INITIAL_REDUCERS, useValue: reducers }, + { + provide: REDUCER_FACTORY, + useValue: config.reducerFactory + ? config.reducerFactory + : combineReducers, + }, ACTIONS_SUBJECT_PROVIDERS, REDUCER_MANAGER_PROVIDERS, SCANNED_ACTIONS_SUBJECT_PROVIDERS, STATE_PROVIDERS, STORE_PROVIDERS, - ] + ], }; } - static forFeature(featureName: string, reducers: ActionReducerMap, config?: StoreConfig): ModuleWithProviders; - static forFeature(featureName: string, reducer: ActionReducer, config?: StoreConfig): ModuleWithProviders; - static forFeature(featureName: string, reducers: ActionReducerMap | ActionReducer, config: StoreConfig = {}): ModuleWithProviders { + static forFeature( + featureName: string, + reducers: ActionReducerMap, + config?: StoreConfig + ): ModuleWithProviders; + static forFeature( + featureName: string, + reducer: ActionReducer, + config?: StoreConfig + ): ModuleWithProviders; + static forFeature( + featureName: string, + reducers: ActionReducerMap | ActionReducer, + config: StoreConfig = {} + ): ModuleWithProviders { return { ngModule: StoreFeatureModule, providers: [ @@ -67,11 +127,13 @@ export class StoreModule { useValue: >{ key: featureName, reducers: reducers, - reducerFactory: config.reducerFactory ? config.reducerFactory : combineReducers, - initialState: config.initialState - } - } - ] + reducerFactory: config.reducerFactory + ? config.reducerFactory + : combineReducers, + initialState: config.initialState, + }, + }, + ], }; } } diff --git a/modules/store/src/utils.ts b/modules/store/src/utils.ts index 155943f529..a5eb0476f4 100644 --- a/modules/store/src/utils.ts +++ b/modules/store/src/utils.ts @@ -1,8 +1,18 @@ -import { Action, ActionReducer, ActionReducerMap, ActionReducerFactory } from './models'; +import { + Action, + ActionReducer, + ActionReducerMap, + ActionReducerFactory, +} from './models'; - -export function combineReducers(reducers: ActionReducerMap, initialState?: Partial): ActionReducer; -export function combineReducers(reducers: any, initialState: any = {}): ActionReducer { +export function combineReducers( + reducers: ActionReducerMap, + initialState?: Partial +): ActionReducer; +export function combineReducers( + reducers: any, + initialState: any = {} +): ActionReducer { const reducerKeys = Object.keys(reducers); const finalReducers: any = {}; @@ -31,7 +41,10 @@ export function combineReducers(reducers: any, initialState: any = {}): ActionRe }; } -export function omit(object: T, keyToRemove: keyof T): Partial { +export function omit( + object: T, + keyToRemove: keyof T +): Partial { return Object.keys(object) .filter(key => key !== keyToRemove) .reduce((result, key) => Object.assign(result, { [key]: object[key] }), {}); @@ -40,9 +53,24 @@ export function omit(object: T, keyToRemove: k export function compose(): (i: A) => A; export function compose(b: (i: A) => B): (i: A) => B; export function compose(c: (i: B) => C, b: (i: A) => B): (i: A) => C; -export function compose(d: (i: C) => D, c: (i: B) => C, b: (i: A) => B): (i: A) => D; -export function compose(e: (i: D) => E, d: (i: C) => D, c: (i: B) => C, b: (i: A) => B): (i: A) => E; -export function compose(f: (i: E) => F, e: (i: D) => E, d: (i: C) => D, c: (i: B) => C, b: (i: A) => B): (i: A) => F; +export function compose( + d: (i: C) => D, + c: (i: B) => C, + b: (i: A) => B +): (i: A) => D; +export function compose( + e: (i: D) => E, + d: (i: C) => D, + c: (i: B) => C, + b: (i: A) => B +): (i: A) => E; +export function compose( + f: (i: E) => F, + e: (i: D) => E, + d: (i: C) => D, + c: (i: B) => C, + b: (i: A) => B +): (i: A) => F; export function compose(...functions: any[]) { return function(arg: any) { if (functions.length === 0) { @@ -53,5 +81,5 @@ export function compose(...functions: any[]) { const rest = functions.slice(0, -1); return rest.reduceRight((composed, fn) => fn(composed), last(arg)); - } + }; } diff --git a/package.json b/package.json index 8223a682f2..9bdf752a43 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "4.0.0-alpha.0", "description": "monorepo for ngrx development", "scripts": { + "precommit": "yarn run prettier", "bootstrap": "lerna bootstrap", "build": "ts-node ./build/index.ts", "deploy:builds": "ts-node ./build/deploy-build.ts", @@ -15,7 +16,8 @@ "cli": "ng", "example:start": "yarn run cli -- serve", "example:test": "yarn run cli -- test --code-coverage", - "ci": "npm run build && npm run test && nyc report --reporter=text-lcov | coveralls" + "ci": "npm run build && npm run test && nyc report --reporter=text-lcov | coveralls", + "prettier": "prettier --parser typescript --single-quote --trailing-comma --write \"./**/*.ts\"" }, "keywords": [ "ngrx", @@ -65,6 +67,7 @@ "fs-extra": "^2.1.2", "glob": "^7.1.1", "hammerjs": "^2.0.8", + "husky": "^0.14.3", "jasmine": "^2.5.3", "jasmine-core": "~2.5.2", "jasmine-marbles": "^0.0.2", @@ -80,6 +83,7 @@ "ngrx-store-freeze": "^0.1.9", "nyc": "^10.1.2", "ora": "^1.2.0", + "prettier": "^1.5.2", "protractor": "~5.1.0", "reflect-metadata": "^0.1.9", "rimraf": "^2.5.4", diff --git a/yarn.lock b/yarn.lock index ed125df317..3dac240b61 100644 --- a/yarn.lock +++ b/yarn.lock @@ -922,6 +922,10 @@ chokidar@^1.4.1, chokidar@^1.4.3, chokidar@^1.6.0: optionalDependencies: fsevents "^1.0.0" +ci-info@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534" + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -2785,6 +2789,14 @@ https-proxy-agent@^1.0.0: debug "2" extend "3" +husky@^0.14.3: + version "0.14.3" + resolved "https://registry.npmjs.org/husky/-/husky-0.14.3.tgz#c69ed74e2d2779769a17ba8399b54ce0b63c12c3" + dependencies: + is-ci "^1.0.10" + normalize-path "^1.0.0" + strip-indent "^2.0.0" + iconv-lite@0.4.15: version "0.4.15" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" @@ -2926,6 +2938,12 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.0.0" +is-ci@^1.0.10: + version "1.0.10" + resolved "https://registry.npmjs.org/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e" + dependencies: + ci-info "^1.0.0" + is-directory@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" @@ -4036,6 +4054,10 @@ normalize-package-data@^2.3.0, normalize-package-data@^2.3.2, normalize-package- semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" +normalize-path@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" + normalize-path@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" @@ -4713,6 +4735,10 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" +prettier@^1.5.2: + version "1.5.2" + resolved "https://registry.npmjs.org/prettier/-/prettier-1.5.2.tgz#7ea0751da27b93bfb6cecfcec509994f52d83bb3" + pretty-error@^2.0.2: version "2.1.1" resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3" @@ -5694,6 +5720,10 @@ strip-indent@^1.0.1: dependencies: get-stdin "^4.0.1" +strip-indent@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" + 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"