Skip to content

Commit

Permalink
feat(router): Add UrlTree constructor to public API (#47186)
Browse files Browse the repository at this point in the history
The `UrlTree` is a fundamental concept in the router's API design.
Generally speaking, a `UrlTree` would be constructed via things like
`Router.createUrlTree` or `UrlSerializer#parse`. The second example here
is the core reason to make the constructor public, regardless of how
develpers generally create a `UrlTree` in an application.

Applications can provide their own `UrlSerializer` and may want to implement their
own `parse` method. This means they would also need to create a
`UrlTree` but would not be able to do so effectively because the
constructor is marked `@internal`.

In addition, the `UrlTree` constructor only has 3 parameters, all of
which are already public. There's nothing "special" about it other than
the potential desire to push developers to use other methods for
constructing a `UrlTree` (i.e. `Router.createUrlTree`).

Also see http://b/234604699#comment9 for additional context.

PR Close #47186
  • Loading branch information
atscott authored and alxhub committed Aug 22, 2022
1 parent daac137 commit 5163e3d
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 10 deletions.
2 changes: 2 additions & 0 deletions goldens/public-api/router/errors.md
Expand Up @@ -13,6 +13,8 @@ export const enum RuntimeErrorCode {
// (undocumented)
INVALID_DOUBLE_DOTS = 4005,
// (undocumented)
INVALID_ROOT_URL_SEGMENT = 4015,
// (undocumented)
INVALID_ROUTE_CONFIG = 4014,
// (undocumented)
MISPLACED_OUTLETS_COMMAND = 4004,
Expand Down
4 changes: 4 additions & 0 deletions goldens/public-api/router/index.md
Expand Up @@ -1033,6 +1033,10 @@ export abstract class UrlSerializer {

// @public
export class UrlTree {
constructor(
root?: UrlSegmentGroup,
queryParams?: Params,
fragment?: string | null);
fragment: string | null;
// (undocumented)
get queryParamMap(): ParamMap;
Expand Down
1 change: 1 addition & 0 deletions packages/router/src/errors.ts
Expand Up @@ -25,4 +25,5 @@ export const enum RuntimeErrorCode {
OUTLET_NOT_ACTIVATED = 4012,
OUTLET_ALREADY_ACTIVATED = 4013,
INVALID_ROUTE_CONFIG = 4014,
INVALID_ROOT_URL_SEGMENT = 4015,
}
4 changes: 2 additions & 2 deletions packages/router/src/router.ts
Expand Up @@ -32,7 +32,7 @@ import {ChildrenOutletContexts} from './router_outlet_context';
import {ActivatedRoute, ActivatedRouteSnapshot, createEmptyState, RouterState, RouterStateSnapshot} from './router_state';
import {Params} from './shared';
import {DefaultUrlHandlingStrategy, UrlHandlingStrategy} from './url_handling_strategy';
import {containsTree, createEmptyUrlTree, IsActiveMatchOptions, isUrlTree, UrlSerializer, UrlTree} from './url_tree';
import {containsTree, IsActiveMatchOptions, isUrlTree, UrlSerializer, UrlTree} from './url_tree';
import {flatten} from './utils/collection';
import {standardizeConfig, validateConfig} from './utils/config';
import {Checks, getAllRouteGuards} from './utils/preactivation';
Expand Down Expand Up @@ -582,7 +582,7 @@ export class Router {
this.isNgZoneEnabled = ngZone instanceof NgZone && NgZone.isInAngularZone();

this.resetConfig(config);
this.currentUrlTree = createEmptyUrlTree();
this.currentUrlTree = new UrlTree();
this.rawUrlTree = this.currentUrlTree;
this.browserUrlTree = this.currentUrlTree;

Expand Down
20 changes: 12 additions & 8 deletions packages/router/src/url_tree.ts
Expand Up @@ -14,10 +14,6 @@ import {equalArraysOrString, forEach, shallowEqual} from './utils/collection';

const NG_DEV_MODE = typeof ngDevMode === 'undefined' || ngDevMode;

export function createEmptyUrlTree() {
return new UrlTree(new UrlSegmentGroup([], {}), {}, null);
}

/**
* A set of options which specify how to determine if a `UrlTree` is active, given the `UrlTree`
* for the current router state.
Expand Down Expand Up @@ -196,14 +192,22 @@ export class UrlTree {
// TODO(issue/24571): remove '!'.
_queryParamMap!: ParamMap;

/** @internal */
constructor(
/** The root segment group of the URL tree */
public root: UrlSegmentGroup,
public root: UrlSegmentGroup = new UrlSegmentGroup([], {}),
/** The query params of the URL */
public queryParams: Params,
public queryParams: Params = {},
/** The fragment of the URL */
public fragment: string|null) {}
public fragment: string|null = null) {
if (NG_DEV_MODE) {
if (root.segments.length > 0) {
throw new RuntimeError(
RuntimeErrorCode.INVALID_ROOT_URL_SEGMENT,
'The root `UrlSegmentGroup` should not contain `segments`. ' +
'Instead, these segments belong in the `children` so they can be associated with a named outlet.');
}
}
}

get queryParamMap(): ParamMap {
if (!this._queryParamMap) {
Expand Down

0 comments on commit 5163e3d

Please sign in to comment.