From dbf59af6a57a9162aa2ff0ab622a93994e4bda4f Mon Sep 17 00:00:00 2001 From: Jason Jean Date: Wed, 16 Jan 2019 20:54:13 -0500 Subject: [PATCH] feat(schematics): update ngrx to 7.2.0 --- package.json | 10 +- packages/nx/spec/data-persistence.spec.ts | 20 +- .../schematics/migrations/migrations.json | 2 +- .../update-7-6-0/update-7-6-0.spec.ts | 222 +++++++++-- .../migrations/update-7-6-0/update-7-6-0.ts | 356 +++++++++++++++++- packages/schematics/src/lib-versions.ts | 2 +- packages/schematics/src/utils/ast-utils.ts | 16 +- yarn.lock | 40 +- 8 files changed, 592 insertions(+), 76 deletions(-) diff --git a/package.json b/package.json index d0148760eb..0b3171582c 100644 --- a/package.json +++ b/package.json @@ -33,11 +33,11 @@ "@angular/platform-browser-dynamic": "^7.2.1", "@angular/router": "^7.2.1", "@angular/upgrade": "^7.2.1", - "@ngrx/effects": "6.1.2", - "@ngrx/router-store": "6.1.2", - "@ngrx/schematics": "6.1.2", - "@ngrx/store": "6.1.2", - "@ngrx/store-devtools": "6.1.2", + "@ngrx/effects": "7.1.0", + "@ngrx/router-store": "7.1.0", + "@ngrx/schematics": "7.1.0", + "@ngrx/store": "7.1.0", + "@ngrx/store-devtools": "7.1.0", "@schematics/angular": "~7.2.2", "@types/jasmine": "~2.8.6", "@types/jasminewd2": "~2.0.3", diff --git a/packages/nx/spec/data-persistence.spec.ts b/packages/nx/spec/data-persistence.spec.ts index 80b694cfdb..7924362c41 100644 --- a/packages/nx/spec/data-persistence.spec.ts +++ b/packages/nx/spec/data-persistence.spec.ts @@ -157,15 +157,17 @@ describe('DataPersistence', () => { const root = TestBed.createComponent(RootCmp); const router: Router = TestBed.get(Router); - let action; - TestBed.get(Actions).subscribe(a => (action = a)); + let actions: any[] = []; + TestBed.get(Actions).subscribe((a: any) => actions.push(a)); router.navigateByUrl('/todo/123'); tick(0); root.detectChanges(false); expect(root.elementRef.nativeElement.innerHTML).not.toContain('ID 123'); - expect(action.type).toEqual('ERROR'); - expect(action.payload.error.message).toEqual('boom'); + expect(actions.map(a => a.type)).toContain('ERROR'); + expect( + actions.find(a => a.type === 'ERROR').payload.error.message + ).toEqual('boom'); // can recover after an error router.navigateByUrl('/todo/456'); @@ -205,15 +207,17 @@ describe('DataPersistence', () => { const root = TestBed.createComponent(RootCmp); const router: Router = TestBed.get(Router); - let action; - TestBed.get(Actions).subscribe(a => (action = a)); + let actions: any[] = []; + TestBed.get(Actions).subscribe((a: any) => actions.push(a)); router.navigateByUrl('/todo/123'); tick(0); root.detectChanges(false); expect(root.elementRef.nativeElement.innerHTML).not.toContain('ID 123'); - expect(action.type).toEqual('ERROR'); - expect(action.payload.error).toEqual('boom'); + expect(actions.map(a => a.type)).toContain('ERROR'); + expect(actions.find(a => a.type === 'ERROR').payload.error).toEqual( + 'boom' + ); router.navigateByUrl('/todo/456'); tick(0); diff --git a/packages/schematics/migrations/migrations.json b/packages/schematics/migrations/migrations.json index 196e8c119f..1f9eaffbf6 100644 --- a/packages/schematics/migrations/migrations.json +++ b/packages/schematics/migrations/migrations.json @@ -57,7 +57,7 @@ }, "update-7.6.0": { "version": "7.6.0", - "description": "Add VSCode Extensions", + "description": "Add VSCode Extensions and Update NgRx", "factory": "./update-7-6-0/update-7-6-0" } } diff --git a/packages/schematics/migrations/update-7-6-0/update-7-6-0.spec.ts b/packages/schematics/migrations/update-7-6-0/update-7-6-0.spec.ts index 30131049a0..8ee5f2921c 100644 --- a/packages/schematics/migrations/update-7-6-0/update-7-6-0.spec.ts +++ b/packages/schematics/migrations/update-7-6-0/update-7-6-0.spec.ts @@ -1,24 +1,96 @@ import { Tree } from '@angular-devkit/schematics'; -import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; +import { + SchematicTestRunner, + UnitTestTree +} from '@angular-devkit/schematics/testing'; import * as path from 'path'; import { serializeJson } from '../../src/utils/fileutils'; import { readJsonInTree, updateJsonInTree } from '../../src/utils/ast-utils'; +import { stripIndents } from '@angular-devkit/core/src/utils/literals'; + +const effectContents = ` +import { Injectable } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { Effect, Actions } from '@ngrx/effects'; +import { DataPersistence } from '@nrwl/nx'; + +import { UserPartialState } from './user.reducer'; +import { + LoadUser, + UserLoaded, + UserLoadError, + UserActionTypes +} from './user.actions'; + +@Injectable() +export class UserEffects { + @Effect() effect$ = this.actions$.ofType(LoadUser).pipe(mapTo(UserLoaded)); + @Effect() effect2$ = this.actions$.ofType(LoadUser).pipe(mapTo(UserLoaded)); + @Effect() effect3$ = this.actions$.ofType(LoadUser).pipe(withLatestFrom(this.store.select(selector)), mapTo(UserLoaded)); + + constructor( + private actions$: Actions, + private dataPersistence: DataPersistence, + private store: Store + ) {} +} + +`; + +const selectorContents = ` +import { Store } from '@ngrx/store'; +import { Component } from '@angular/core'; +import { AppState, selector } from '../+state'; + +@Component({ + selector: 'app', + template: '', + styles: [] +}) +export class AppComponent { + slice$ = this.store.select(selector).pipe( + map(a => a) + ); + + slice2$: Observable; + + slice3$ = Observable.from([]).pipe( + withLatestFrom(this.store.select(selector5)) + ); + + constructor( + private store: Store + ) {} + + ngOnInit() { + this.slice2$ = this.store.select(selector2); + this.store.select(selector3).subscribe(console.log); + } +} + +`; + describe('Update 7.6.0', () => { let initialTree: Tree; let schematicRunner: SchematicTestRunner; beforeEach(() => { - initialTree = Tree.empty(); + initialTree = new UnitTestTree(Tree.empty()); initialTree.create( 'package.json', serializeJson({ + dependencies: { + '@ngrx/effects': '6.1.2', + '@ngrx/router-store': '6.1.2', + '@ngrx/store': '6.1.2' + }, devDependencies: { - '@angular/cli': '7.1.0', - typescript: '~3.1.0' + '@ngrx/schematics': '6.1.2', + '@ngrx/store-devtools': '6.1.2' } }) ); @@ -29,41 +101,125 @@ describe('Update 7.6.0', () => { ); }); - it('should add vscode extension recommendations', async () => { - const result = await schematicRunner - .runSchematicAsync('update-7.6.0', {}, initialTree) - .toPromise(); + describe('VSCode Extension Recommendations', () => { + it('should be added', async () => { + const result = await schematicRunner + .runSchematicAsync('update-7.6.0', {}, initialTree) + .toPromise(); - expect(readJsonInTree(result, '.vscode/extensions.json')).toEqual({ - recommendations: [ - 'nrwl.angular-console', - 'angular.ng-template', - 'esbenp.prettier-vscode' - ] + expect(readJsonInTree(result, '.vscode/extensions.json')).toEqual({ + recommendations: [ + 'nrwl.angular-console', + 'angular.ng-template', + 'esbenp.prettier-vscode' + ] + }); + }); + + it('should be added to existing recommendations', async () => { + initialTree = await schematicRunner + .callRule( + updateJsonInTree('.vscode/extensions.json', () => ({ + recommendations: ['eamodio.gitlens', 'angular.ng-template'] + })), + initialTree + ) + .toPromise(); + + const result = await schematicRunner + .runSchematicAsync('update-7.6.0', {}, initialTree) + .toPromise(); + + expect(readJsonInTree(result, '.vscode/extensions.json')).toEqual({ + recommendations: [ + 'eamodio.gitlens', + 'angular.ng-template', + 'nrwl.angular-console', + 'esbenp.prettier-vscode' + ] + }); }); }); - it('should add to existing vscode extension recommendations', async () => { - initialTree = await schematicRunner - .callRule( - updateJsonInTree('.vscode/extensions.json', () => ({ - recommendations: ['eamodio.gitlens', 'angular.ng-template'] - })), - initialTree - ) - .toPromise(); + describe('NgRx Migration', () => { + it('should update ngrx to 7.1.0', async () => { + const result = await schematicRunner + .runSchematicAsync('update-7.6.0', {}, initialTree) + .toPromise(); - const result = await schematicRunner - .runSchematicAsync('update-7.6.0', {}, initialTree) - .toPromise(); + expect(readJsonInTree(result, 'package.json')).toEqual({ + dependencies: { + '@ngrx/effects': '7.2.0', + '@ngrx/router-store': '7.2.0', + '@ngrx/store': '7.2.0' + }, + devDependencies: { + '@ngrx/schematics': '7.2.0', + '@ngrx/store-devtools': '7.2.0' + } + }); + }); - expect(readJsonInTree(result, '.vscode/extensions.json')).toEqual({ - recommendations: [ - 'eamodio.gitlens', - 'angular.ng-template', - 'nrwl.angular-console', - 'esbenp.prettier-vscode' - ] + it('should convert ofType code', async () => { + initialTree.create('user.effects.ts', effectContents); + const result = await schematicRunner + .runSchematicAsync('update-7.6.0', {}, initialTree) + .toPromise(); + const contents = result.readContent('user.effects.ts'); + expect(contents).toContain( + "import { Effect, Actions, ofType } from '@ngrx/effects';" + ); + expect(stripIndents`${contents}`).toContain( + stripIndents` + @Effect() effect$ = this.actions$.pipe( + ofType(LoadUser), + mapTo(UserLoaded) + );` + ); + expect(stripIndents`${contents}`).toContain( + stripIndents` + @Effect() effect2$ = this.actions$.pipe( + ofType(LoadUser), + mapTo(UserLoaded) + );` + ); + expect(stripIndents`${contents}`).toContain( + stripIndents` + @Effect() effect3$ = this.actions$.pipe( + ofType(LoadUser), + withLatestFrom(this.store.pipe(select(selector))), + mapTo(UserLoaded) + );` + ); + }); + + it('should convert select code', async () => { + initialTree.create('app.component.ts', selectorContents); + const result = await schematicRunner + .runSchematicAsync('update-7.6.0', {}, initialTree) + .toPromise(); + const contents = result.readContent('app.component.ts'); + expect(contents).toContain( + "import { Store, select } from '@ngrx/store';" + ); + expect(stripIndents`${contents}`).toContain( + stripIndents` + slice$ = this.store.pipe( + select(selector), + map(a => a) + );` + ); + expect(contents).toContain( + 'this.slice2$ = this.store.pipe(select(selector2))' + ); + expect(contents).toContain( + 'this.store.pipe(select(selector3)).subscribe(console.log);' + ); + + expect(stripIndents`${contents}`).toContain(stripIndents` + slice3$ = Observable.from([]).pipe( + withLatestFrom(this.store.pipe(select(selector5))) + );`); }); }); }); diff --git a/packages/schematics/migrations/update-7-6-0/update-7-6-0.ts b/packages/schematics/migrations/update-7-6-0/update-7-6-0.ts index 2884a0e71f..9e73b1fbdc 100644 --- a/packages/schematics/migrations/update-7-6-0/update-7-6-0.ts +++ b/packages/schematics/migrations/update-7-6-0/update-7-6-0.ts @@ -1,6 +1,21 @@ -import { Rule, chain, externalSchematic } from '@angular-devkit/schematics'; +import { + Rule, + chain, + SchematicContext, + Tree +} from '@angular-devkit/schematics'; -import { updateJsonInTree } from '../../src/utils/ast-utils'; +import { ReplaceChange } from '@schematics/angular/utility/change'; +import { getSourceNodes } from '@schematics/angular/utility/ast-utils'; + +import * as ts from 'typescript'; + +import { + updateJsonInTree, + readJsonInTree, + insert +} from '../../src/utils/ast-utils'; +import { formatFiles } from '../../src/utils/rules/format-files'; const addExtensionRecommendations = updateJsonInTree( '.vscode/extensions.json', @@ -20,6 +35,339 @@ const addExtensionRecommendations = updateJsonInTree( } ); -export default function(): Rule { - return chain([addExtensionRecommendations]); +function addItemToImport( + path: string, + sourceFile: ts.SourceFile, + printer: ts.Printer, + importStatement: ts.ImportDeclaration, + symbol: string +) { + const newImport = ts.createImportDeclaration( + importStatement.decorators, + importStatement.modifiers, + ts.createImportClause( + importStatement.importClause.name, + ts.createNamedImports([ + ...(importStatement.importClause.namedBindings as ts.NamedImports) + .elements, + ts.createImportSpecifier(undefined, ts.createIdentifier(symbol)) + ]) + ), + importStatement.moduleSpecifier + ); + return new ReplaceChange( + path, + importStatement.getStart(sourceFile), + importStatement.getText(sourceFile), + printer.printNode(ts.EmitHint.Unspecified, newImport, sourceFile) + ); +} + +function isEffectDecorator(decorator: ts.Decorator) { + return ( + ts.isCallExpression(decorator.expression) && + ts.isIdentifier(decorator.expression.expression) && + decorator.expression.expression.text === 'Effect' + ); +} + +function getImport(sourceFile: ts.SourceFile, path: string, symbol: string) { + return sourceFile.statements + .filter(ts.isImportDeclaration) + .filter(statement => + statement.moduleSpecifier.getText(sourceFile).includes(path) + ) + .find(statement => { + if (!ts.isNamedImports(statement.importClause.namedBindings)) { + return false; + } + + return statement.importClause.namedBindings.elements.some( + element => element.getText(sourceFile) === symbol + ); + }); +} + +function updateOfTypeCode(path: string, sourceFile: ts.SourceFile) { + const effectsImport = getImport(sourceFile, '@ngrx/effects', 'Effect'); + if (!effectsImport) { + return []; + } + + const effects: ts.PropertyDeclaration[] = []; + const changes: ReplaceChange[] = []; + + const printer = ts.createPrinter(); + + sourceFile.statements + .filter(ts.isClassDeclaration) + .map(clazz => + clazz.members + .filter(ts.isPropertyDeclaration) + .filter( + member => + member.decorators && member.decorators.some(isEffectDecorator) + ) + ) + .forEach(properties => { + effects.push(...properties); + }); + + effects.forEach(effect => { + if ( + ts.isCallExpression(effect.initializer) && + ts.isPropertyAccessExpression(effect.initializer.expression) && + effect.initializer.expression.name.text === 'pipe' && + ts.isCallExpression(effect.initializer.expression.expression) && + ts.isPropertyAccessExpression( + effect.initializer.expression.expression.expression + ) && + effect.initializer.expression.expression.expression.name.text === 'ofType' + ) { + const originalText = effect.initializer.getText(sourceFile); + + const ofTypeExpression = ts.createCall( + ts.createIdentifier('ofType'), + effect.initializer.expression.expression.typeArguments, + effect.initializer.expression.expression.arguments + ); + + const node = ts.createCall( + ts.createPropertyAccess( + effect.initializer.expression.expression.expression.expression, + 'pipe' + ), + effect.initializer.typeArguments, + ts.createNodeArray([ + ofTypeExpression, + ...(effect.initializer as ts.CallExpression).arguments + ]) + ); + const newEffect = printer.printNode( + ts.EmitHint.Expression, + node, + sourceFile + ); + + const change = new ReplaceChange( + path, + effect.initializer.getStart(sourceFile), + originalText, + newEffect + ); + changes.push(change); + } + }); + + if (changes.length > 0) { + changes.unshift( + addItemToImport(path, sourceFile, printer, effectsImport, 'ofType') + ); + } + + return changes; +} + +function getConstructor( + classDeclaration: ts.ClassDeclaration +): ts.ConstructorDeclaration { + return classDeclaration.members.find(ts.isConstructorDeclaration); +} + +function getStoreProperty( + sourceFile: ts.SourceFile, + constructor: ts.ConstructorDeclaration +): string { + const storeParameter = constructor.parameters.find( + parameter => + parameter.type && parameter.type.getText(sourceFile).includes('Store') + ); + return storeParameter ? storeParameter.name.getText(sourceFile) : null; +} + +function updateSelectorCode(path: string, sourceFile: ts.SourceFile) { + const storeImport = getImport(sourceFile, '@ngrx/store', 'Store'); + if (!storeImport) { + return []; + } + const changes: ReplaceChange[] = []; + + const printer = ts.createPrinter(); + + sourceFile.statements + .filter(ts.isClassDeclaration) + .forEach(classDeclaration => { + const constructor = getConstructor(classDeclaration); + if (!constructor) { + return; + } + + const storeProperty = getStoreProperty(sourceFile, constructor); + getSourceNodes(sourceFile).forEach(node => { + if ( + ts.isCallExpression(node) && + ts.isPropertyAccessExpression(node.expression) && + ts.isPropertyAccessExpression(node.expression.expression) && + ts.isIdentifier(node.expression.name) && + ts.isIdentifier(node.expression.expression.name) && + node.expression.name.getText(sourceFile) === 'select' && + node.expression.expression.name.getText(sourceFile) === + storeProperty && + node.expression.expression.expression.kind === + ts.SyntaxKind.ThisKeyword + ) { + const newExpression = ts.createCall( + ts.createPropertyAccess( + ts.createPropertyAccess( + ts.createIdentifier('this'), + ts.createIdentifier(storeProperty) + ), + ts.createIdentifier('pipe') + ), + [], + [ + ts.createCall( + ts.createIdentifier('select'), + node.typeArguments, + node.arguments + ) + ] + ); + const newNode = printer.printNode( + ts.EmitHint.Expression, + newExpression, + sourceFile + ); + changes.push( + new ReplaceChange( + path, + node.getStart(sourceFile), + node.getText(sourceFile), + newNode + ) + ); + } + }); + }); + + if (changes.length > 0) { + changes.unshift( + addItemToImport(path, sourceFile, printer, storeImport, 'select') + ); + } + + return changes; +} + +function migrateNgrx(host: Tree, context: SchematicContext) { + const ngrxVersion = readJsonInTree(host, 'package.json').dependencies[ + '@ngrx/store' + ]; + if ( + !( + ngrxVersion.startsWith('6.') || + ngrxVersion.startsWith('~6.') || + ngrxVersion.startsWith('^6.') + ) + ) { + return host; + } + + host.visit(path => { + if (!path.endsWith('.ts')) { + return; + } + + let sourceFile = ts.createSourceFile( + path, + host.read(path).toString(), + ts.ScriptTarget.Latest + ); + + if (sourceFile.isDeclarationFile) { + return; + } + + insert(host, path, updateOfTypeCode(path, sourceFile)); + + sourceFile = ts.createSourceFile( + path, + host.read(path).toString(), + ts.ScriptTarget.Latest + ); + + insert(host, path, updateSelectorCode(path, sourceFile)); + + sourceFile = ts.createSourceFile( + path, + host.read(path).toString(), + ts.ScriptTarget.Latest + ); + + insert(host, path, cleanUpDoublePipes(path, sourceFile)); + }); +} + +function cleanUpDoublePipes( + path: string, + sourceFile: ts.SourceFile +): ReplaceChange[] { + const changes: ReplaceChange[] = []; + + const printer = ts.createPrinter(); + + getSourceNodes(sourceFile).forEach(node => { + if ( + ts.isCallExpression(node) && + ts.isPropertyAccessExpression(node.expression) && + ts.isCallExpression(node.expression.expression) && + ts.isPropertyAccessExpression(node.expression.expression.expression) && + node.expression.name.text === 'pipe' && + node.expression.expression.expression.name.text === 'pipe' + ) { + const singlePipe = ts.createCall( + node.expression.expression.expression, + node.typeArguments, + [...node.expression.expression.arguments, ...node.arguments] + ); + changes.push( + new ReplaceChange( + path, + node.getStart(sourceFile), + node.getText(sourceFile), + printer.printNode(ts.EmitHint.Expression, singlePipe, sourceFile) + ) + ); + } + }); + + return changes; +} + +const updateNgrx = updateJsonInTree('package.json', json => { + json.devDependencies = json.devDependencies || {}; + json.dependencies = json.dependencies || {}; + + json.dependencies = { + ...json.dependencies, + '@ngrx/effects': '7.2.0', + '@ngrx/router-store': '7.2.0', + '@ngrx/store': '7.2.0' + }; + + json.devDependencies = { + ...json.devDependencies, + '@ngrx/schematics': '7.2.0', + '@ngrx/store-devtools': '7.2.0' + }; + return json; +}); + +export default function(): Rule { + return chain([ + addExtensionRecommendations, + migrateNgrx, + updateNgrx, + formatFiles() + ]); } diff --git a/packages/schematics/src/lib-versions.ts b/packages/schematics/src/lib-versions.ts index cb21b9b180..3940f0f5b2 100644 --- a/packages/schematics/src/lib-versions.ts +++ b/packages/schematics/src/lib-versions.ts @@ -2,7 +2,7 @@ export const angularCliVersion = '~7.2.2'; export const angularVersion = '^7.0.0'; export const angularDevkitVersion = '~0.11.2'; export const angularJsVersion = '1.6.6'; -export const ngrxVersion = '6.1.2'; +export const ngrxVersion = '7.2.0'; export const ngrxStoreFreezeVersion = '0.2.4'; export const nxVersion = '*'; export const schematicsVersion = '*'; diff --git a/packages/schematics/src/utils/ast-utils.ts b/packages/schematics/src/utils/ast-utils.ts index cf43a09226..894f254e8a 100755 --- a/packages/schematics/src/utils/ast-utils.ts +++ b/packages/schematics/src/utils/ast-utils.ts @@ -248,7 +248,7 @@ export function removeFromNgModule( return [ new RemoveChange( modulePath, - matchingProperty.pos, + matchingProperty.getStart(source), matchingProperty.getFullText(source) ) ]; @@ -545,6 +545,9 @@ export function addGlobal( } export function insert(host: Tree, modulePath: string, changes: Change[]) { + if (changes.length < 1) { + return; + } const recorder = host.beginUpdate(modulePath); for (const change of changes) { if (change instanceof InsertChange) { @@ -555,8 +558,8 @@ export function insert(host: Tree, modulePath: string, changes: Change[]) { // do nothing } else if (change instanceof ReplaceChange) { const action = change; - recorder.remove(action.pos + 1, action.oldText.length); - recorder.insertLeft(action.pos + 1, action.newText); + recorder.remove(action.pos, action.oldText.length); + recorder.insertLeft(action.pos, action.newText); } else { throw new Error(`Unexpected Change '${change}'`); } @@ -941,6 +944,11 @@ export function replaceNodeValue( content: string ) { insert(host, modulePath, [ - new ReplaceChange(modulePath, node.pos, node.getFullText(), content) + new ReplaceChange( + modulePath, + node.getStart(node.getSourceFile()), + node.getFullText(), + content + ) ]); } diff --git a/yarn.lock b/yarn.lock index 4662e77a35..389069b156 100644 --- a/yarn.lock +++ b/yarn.lock @@ -225,30 +225,30 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" -"@ngrx/effects@6.1.2": - version "6.1.2" - resolved "https://registry.yarnpkg.com/@ngrx/effects/-/effects-6.1.2.tgz#602f3ee9798e00179075ddef030ded88c28b1aa1" - integrity sha512-RUuQ5/7ofxGEZnRRdlC1oE9ugVlTYGm92MVj7c6IirHrVN9W5yQjjMTYEYceVCDOYsiXP7Pyw0dcPp6J5wD2EQ== +"@ngrx/effects@7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@ngrx/effects/-/effects-7.1.0.tgz#c42966a92096d605b72a1959599ad6c90a1e15a2" + integrity sha512-0oF9VaixL8TNzIyBfFieLXunoz66uuceGfh5EaepQu+qPcVhnFq5KvYHDQOdCq0uuQYB7rVwNFYjOD7pO5LE5A== -"@ngrx/router-store@6.1.2": - version "6.1.2" - resolved "https://registry.yarnpkg.com/@ngrx/router-store/-/router-store-6.1.2.tgz#63bfcd3710c53ea2c5456b82c57fd433e5af25bc" - integrity sha512-sj083ZYrx0aY+vU/t8Ub0KYDHcMpatXJIOJR/eDNSuH54fPiBM9MrdI3hs/XHoXHxSaHOJoZ7f6I8XcUeptxyA== +"@ngrx/router-store@7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@ngrx/router-store/-/router-store-7.1.0.tgz#931bdc902d806b3d026e99604748ebfefcd82dc3" + integrity sha512-xLTtdLvbgwFyhXU9A/kYsuVruvp8w7WcNorGq0LyWCwI+rk4twaNFJLUx/rVnLbzfXLichU8kHAiRmR8VD438A== -"@ngrx/schematics@6.1.2": - version "6.1.2" - resolved "https://registry.yarnpkg.com/@ngrx/schematics/-/schematics-6.1.2.tgz#52dce7f2d4275791732805576eaf007d1043ef58" - integrity sha512-hiu8rdYAJIfIoJHPlAJr+mBkXab7OLRyg8Z/i5lUpmE382yvESfcVI9hqYsGXWBbyfY5Al+BGzGhBth5gc5AvA== +"@ngrx/schematics@7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@ngrx/schematics/-/schematics-7.1.0.tgz#ddc4faebd506f28ac181df04091b630c70ced713" + integrity sha512-4+drIY4jCMgsOZWo6LTpUL8uLxv8RrbzS5CNEcm8EvwmUrzd/GKoCZ9rKqzoAlF5EyA+1OraMppeOHV0j8DZ3w== -"@ngrx/store-devtools@6.1.2": - version "6.1.2" - resolved "https://registry.yarnpkg.com/@ngrx/store-devtools/-/store-devtools-6.1.2.tgz#b9cb8d6bcd7ee0d171dde86c9bdd5e6a5bc5563a" - integrity sha512-hvWMKcRIAtAFb2lb4woRenPHPgOiLFjy8R2PtCiw4uP3WrBVB4JHqUuP230/iRMcU5XmySp+LhNqhkk1zsoUqQ== +"@ngrx/store-devtools@7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@ngrx/store-devtools/-/store-devtools-7.1.0.tgz#ea5248d616b2bdf7607e9f4a1c80aa4365e0f830" + integrity sha512-r0LUFQKxKOhFIO2TBK7k6eoOCT6WGQFXzOFTWwctU7teQgSSpzyUVQfsULfAyFpGN9f1hog9leY/J/EVjdwBQQ== -"@ngrx/store@6.1.2": - version "6.1.2" - resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-6.1.2.tgz#20fb5ab4d79571b804a348093aa11a167fe2946f" - integrity sha512-W9MbXrwhIRmN1BlINF9BT+rHR046e1HNk7GqykcDJrK9wW74PJW3aE5iuPb2sTPipBMjPHsXzc73E4U/+OTAyw== +"@ngrx/store@7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-7.1.0.tgz#072f22e062e264c62859f37d9807dfac860f161d" + integrity sha512-tM8ZGxbLTyQ5JUHow3/PSFU3FWfYJs/wAVyRlxzTxfY7Krs/TJ64GgI4lOa6gVizi2UiYfLtI31pJrxzXyxEoA== "@ngtools/json-schema@^1.1.0": version "1.1.0"