From 89f64e58c30389f9896532bfb65bc4138fc19ed1 Mon Sep 17 00:00:00 2001 From: Zaven Muradyan Date: Thu, 8 Mar 2018 12:16:01 -0800 Subject: [PATCH] fix(router): avoid freezing queryParams in-place (#22663) The recognizer code used to call Object.freeze() on queryParams before using them to construct ActivatedRoutes, with the intent being to help avoid common invalid usage. Unfortunately, Object.freeze() works in-place, so this was also freezing the queryParams on the actual UrlTree object, making it more difficult to manipulate UrlTrees in things like UrlHandlingStrategy. This change simply shallow-copies the queryParams before freezing them. Fixes #22617 PR Close #22663 --- packages/router/src/recognize.ts | 9 +++++---- packages/router/test/recognize.spec.ts | 8 ++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/router/src/recognize.ts b/packages/router/src/recognize.ts index 74684f78b0..b6eeded31a 100644 --- a/packages/router/src/recognize.ts +++ b/packages/router/src/recognize.ts @@ -38,8 +38,9 @@ class Recognizer { const children = this.processSegmentGroup(this.config, rootSegmentGroup, PRIMARY_OUTLET); const root = new ActivatedRouteSnapshot( - [], Object.freeze({}), Object.freeze(this.urlTree.queryParams), this.urlTree.fragment !, - {}, PRIMARY_OUTLET, this.rootComponentType, null, this.urlTree.root, -1, {}); + [], Object.freeze({}), Object.freeze({...this.urlTree.queryParams}), + this.urlTree.fragment !, {}, PRIMARY_OUTLET, this.rootComponentType, null, + this.urlTree.root, -1, {}); const rootNode = new TreeNode(root, children); const routeState = new RouterStateSnapshot(this.url, rootNode); @@ -116,7 +117,7 @@ class Recognizer { if (route.path === '**') { const params = segments.length > 0 ? last(segments) !.parameters : {}; snapshot = new ActivatedRouteSnapshot( - segments, params, Object.freeze(this.urlTree.queryParams), this.urlTree.fragment !, + segments, params, Object.freeze({...this.urlTree.queryParams}), this.urlTree.fragment !, getData(route), outlet, route.component !, route, getSourceSegmentGroup(rawSegment), getPathIndexShift(rawSegment) + segments.length, getResolve(route)); } else { @@ -125,7 +126,7 @@ class Recognizer { rawSlicedSegments = segments.slice(result.lastChild); snapshot = new ActivatedRouteSnapshot( - consumedSegments, result.parameters, Object.freeze(this.urlTree.queryParams), + consumedSegments, result.parameters, Object.freeze({...this.urlTree.queryParams}), this.urlTree.fragment !, getData(route), outlet, route.component !, route, getSourceSegmentGroup(rawSegment), getPathIndexShift(rawSegment) + consumedSegments.length, getResolve(route)); diff --git a/packages/router/test/recognize.spec.ts b/packages/router/test/recognize.spec.ts index f224f0e0ab..1db36a1cd1 100644 --- a/packages/router/test/recognize.spec.ts +++ b/packages/router/test/recognize.spec.ts @@ -748,6 +748,14 @@ describe('recognize', () => { expect(Object.isFrozen(s.root.queryParams)).toBeTruthy(); }); }); + + it('should not freeze UrlTree query params', () => { + const url = tree('a?q=11'); + recognize(RootComponent, [{path: 'a', component: ComponentA}], url, 'a?q=11') + .subscribe((s: RouterStateSnapshot) => { + expect(Object.isFrozen(url.queryParams)).toBe(false); + }); + }); }); describe('fragment', () => {