/
shared.ts
167 lines (145 loc) Β· 4.5 KB
/
shared.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Route, UrlMatchResult} from './models';
import {UrlSegment, UrlSegmentGroup} from './url_tree';
/**
* The primary routing outlet.
*
* @publicApi
*/
export const PRIMARY_OUTLET = 'primary';
/**
* A private symbol used to store the value of `Route.title` inside the `Route.data` if it is a
* static string or `Route.resolve` if anything else. This allows us to reuse the existing route
* data/resolvers to support the title feature without new instrumentation in the `Router` pipeline.
*/
export const RouteTitleKey = /* @__PURE__ */ Symbol('RouteTitle');
/**
* A collection of matrix and query URL parameters.
* @see {@link convertToParamMap}
* @see {@link ParamMap}
*
* @publicApi
*/
export type Params = {
[key: string]: any;
};
/**
* A map that provides access to the required and optional parameters
* specific to a route.
* The map supports retrieving a single value with `get()`
* or multiple values with `getAll()`.
*
* @see [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
*
* @publicApi
*/
export interface ParamMap {
/**
* Reports whether the map contains a given parameter.
* @param name The parameter name.
* @returns True if the map contains the given parameter, false otherwise.
*/
has(name: string): boolean;
/**
* Retrieves a single value for a parameter.
* @param name The parameter name.
* @return The parameter's single value,
* or the first value if the parameter has multiple values,
* or `null` when there is no such parameter.
*/
get(name: string): string|null;
/**
* Retrieves multiple values for a parameter.
* @param name The parameter name.
* @return An array containing one or more values,
* or an empty array if there is no such parameter.
*
*/
getAll(name: string): string[];
/** Names of the parameters in the map. */
readonly keys: string[];
}
class ParamsAsMap implements ParamMap {
private params: Params;
constructor(params: Params) {
this.params = params || {};
}
has(name: string): boolean {
return Object.prototype.hasOwnProperty.call(this.params, name);
}
get(name: string): string|null {
if (this.has(name)) {
const v = this.params[name];
return Array.isArray(v) ? v[0] : v;
}
return null;
}
getAll(name: string): string[] {
if (this.has(name)) {
const v = this.params[name];
return Array.isArray(v) ? v : [v];
}
return [];
}
get keys(): string[] {
return Object.keys(this.params);
}
}
/**
* Converts a `Params` instance to a `ParamMap`.
* @param params The instance to convert.
* @returns The new map instance.
*
* @publicApi
*/
export function convertToParamMap(params: Params): ParamMap {
return new ParamsAsMap(params);
}
/**
* Matches the route configuration (`route`) against the actual URL (`segments`).
*
* When no matcher is defined on a `Route`, this is the matcher used by the Router by default.
*
* @param segments The remaining unmatched segments in the current navigation
* @param segmentGroup The current segment group being matched
* @param route The `Route` to match against.
*
* @see {@link UrlMatchResult}
* @see {@link Route}
*
* @returns The resulting match information or `null` if the `route` should not match.
* @publicApi
*/
export function defaultUrlMatcher(
segments: UrlSegment[], segmentGroup: UrlSegmentGroup, route: Route): UrlMatchResult|null {
const parts = route.path!.split('/');
if (parts.length > segments.length) {
// The actual URL is shorter than the config, no match
return null;
}
if (route.pathMatch === 'full' &&
(segmentGroup.hasChildren() || parts.length < segments.length)) {
// The config is longer than the actual URL but we are looking for a full match, return null
return null;
}
const posParams: {[key: string]: UrlSegment} = {};
// Check each config part against the actual URL
for (let index = 0; index < parts.length; index++) {
const part = parts[index];
const segment = segments[index];
const isParameter = part.startsWith(':');
if (isParameter) {
posParams[part.substring(1)] = segment;
} else if (part !== segment.path) {
// The actual URL part does not match the config, no match
return null;
}
}
return {consumed: segments.slice(0, parts.length), posParams};
}