-
Notifications
You must be signed in to change notification settings - Fork 60
/
Copy pathinterface.ts
626 lines (606 loc) · 19.5 KB
/
interface.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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
import { ParamType } from './paramType.js';
/**
* Parameter values
*
* An object containing state parameter key/value pairs
*
* #### Example:
* ```js
* {
* userId: 353474,
* folderId: 'inbox'
* }
* ```
*/
export interface RawParams {
[key: string]: any;
}
/**
* Configuration for a single Parameter
*
* In a [[StateDeclaration.params]], each `ParamDeclaration`
* defines how a single State Parameter should work.
*
* #### Example:
* ```js
* var mystate = {
* template: '<div ui-view/>',
* controller: function() {}
* url: '/mystate/:start?{count:int}',
* params: {
* start: { // <-- ParamDeclaration for `start`
* type: 'date',
* value: new Date(), // <-- Default value
* squash: true,
* },
*
* nonUrlParam: { // <-- ParamDeclaration for 'nonUrlParam'
* type: "int",
* array: true,
* value: []
* },
*
* count: 0, // <-- Default value for 'param1'
* // (shorthand ParamDeclaration.value)
* }
* }
* ```
*/
export interface ParamDeclaration {
/**
* The default value for this parameter.
*
* Specifies the default value for this parameter.
* This implicitly sets this parameter as optional.
*
* When UI-Router routes to a state and no value is specified for this parameter in the URL or transition,
* the default value will be used instead.
* If value is a function, it will be injected and invoked, and the return value used.
*
* Note: `value: undefined` is treated as though **no default value was specified**, while `value: null` is treated
* as **"the default value is null"**.
*
* ```
* // define default values for param1 and param2
* params: {
* param1: {
* value: "defaultValue"
* },
* param2: {
* value: "param2Default;
* }
* }
* ```
*
* ### Shorthand Declaration
*
* If you only want to set the default value of the parameter, you may use a shorthand syntax.
* In the params map, instead mapping the param name to a full parameter configuration object, simply set map it
* to the default parameter value, e.g.:
* ```
* // Normal (non-shorthand) default value syntax
* params: {
* param1: {
* value: "defaultValue"
* },
* param2: {
* value: "param2Default"
* }
* }
*
* // Shorthand default value syntax
* params: {
* param1: "defaultValue",
* param2: "param2Default"
* }
* ```
*
* This defines a default value for the parameter.
* If a parameter value is `undefined`, this default value will be used instead
*
* ---
*
* Default: `undefined`
*/
value?: any;
/**
* The parameter's type
*
* Specifies the [[ParamType]] of the parameter.
* Parameter types can be used to customize the encoding/decoding of parameter values.
*
* Set this property to the name of parameter's type.
* The type may be either one of the built in types, or a custom type that has been registered with the [[UrlMatcherFactory]].
*
* See [[ParamTypes]] for the list of built in types.
*
* ---
*
* Default:
* - Path parameters (`/:fooParam`): `path`
* - Query parameters (`?queryParam`): `query`
* - Non-url parameters (`param: { foo: null }`): `any`
*
*/
type?: string | ParamType;
/**
* The parameter's `array` mode
*
* Explicitly specifies the array mode of a URL parameter
*
* - If `false`, the parameter value will be treated (encoded/decoded) as a single value
* - If `true`, the parameter value will be treated (encoded/decoded) as an array of values.
* - If `auto` (for query parameters only), if multiple values for a single parameter are present
* in the URL (e.g.: /foo?bar=1&bar=2&bar=3) then the values are mapped to an array (e.g.:
* `{ foo: [ '1', '2', '3' ] }`). However, if only one value is present (e.g.: /foo?bar=1)
* then the value is treated as single value (e.g.: { foo: '1' }).
*
* If you specified a [[type]] for the parameter, the value will be treated as an array
* of the specified [[ParamType]].
*
* #### Example:
* ```js
* {
* name: 'foo',
* url: '/foo/{arrayParam:int}`,
* params: {
* arrayParam: { array: true }
* }
* }
*
* // After the transition, URL should be '/foo/1-2-3'
* $state.go("foo", { arrayParam: [ 1, 2, 3 ] });
* ```
*
* @default `false` for path parameters, such as `url: '/foo/:pathParam'`
* @default `auto` for query parameters, such as `url: '/foo?queryParam'`
* @default `true` if the parameter name ends in `[]`, such as `url: '/foo/{implicitArrayParam:int[]}'`
*/
array?: boolean;
/**
* Squash mode: omit default parameter values in URL
*
* Configures how a default parameter value is represented in the URL when the current parameter value
* is the same as the default value.
*
* There are three squash settings:
*
* - `false`: The parameter's default value is not squashed. It is encoded and included in the URL
* - `true`: The parameter's default value is omitted from the URL.
* If the parameter is preceeded and followed by slashes in the state's url declaration, then one of those slashes are omitted.
* This can allow for cleaner looking URLs.
* - `"<arbitrary string>"`: The parameter's default value is replaced with an arbitrary
* placeholder of your choice.
*
* #### Example:
* ```js
* {
* name: 'mystate',
* url: '/mystate/:myparam',
* params: {
* myparam: 'defaultParamValue'
* squash: true
* }
* }
*
* // URL will be `/mystate/`
* $state.go('mystate', { myparam: 'defaultParamValue' });
*
* // URL will be `/mystate/someOtherValue`
* $state.go('mystate', { myparam: 'someOtherValue' });
* ```
*
* #### Example:
* ```js
* {
* name: 'mystate2',
* url: '/mystate2/:myparam2',
* params: {
* myparam2: 'defaultParamValue'
* squash: "~"
* }
* }
*
* // URL will be `/mystate/~`
* $state.go('mystate', { myparam2: 'defaultParamValue' });
*
* // URL will be `/mystate/someOtherValue`
* $state.go('mystate', { myparam2: 'someOtherValue' });
* ```
*
* Default: If squash is not set, it uses the configured default squash policy. (See [[defaultSquashPolicy]]())
*/
squash?: boolean | string;
/**
* @internal
*
* An array of [[Replace]] objects.
*
* When creating a Transition, defines how to handle certain special values, such as `undefined`, `null`,
* or empty string `""`. If the transition is started, and the parameter value is equal to one of the "to"
* values, then the parameter value is replaced with the "from" value.
*
* #### Example:
* ```js
* replace: [
* { from: undefined, to: null },
* { from: "", to: null }
* ]
* ```
*/
replace?: Replace[];
/**
* @internal
* @internal
*
* This is not part of the declaration; it is a calculated value depending on if a default value was specified or not.
*/
isOptional?: boolean;
/**
* Dynamic flag
*
* When `dynamic` is `true`, changes to the parameter value will not cause the state to be entered/exited.
* The resolves will not be re-fetched, nor will views be reloaded.
*
* Normally, if a parameter value changes, the state which declared that the parameter will be reloaded (entered/exited).
* When a parameter is `dynamic`, a transition still occurs, but it does not cause the state to exit/enter.
*
* This can be useful to build UI where the component updates itself when the param values change.
* A common scenario where this is useful is searching/paging/sorting.
*
* ---
*
* Note: this value overrides the `dynamic` value on a custom parameter type ([[ParamTypeDefinition.dynamic]]).
*
* ---
*
* Default: `false`
*/
dynamic?: boolean;
/**
* Disables url-encoding of parameter values
*
* When `true`, parameter values are not url-encoded.
* This is commonly used to allow "slug" urls, with a parameter value including non-semantic slashes.
*
* #### Example:
* ```js
* url: '/product/:slug',
* params: {
* slug: { type: 'string', raw: true }
* }
* ```
*
* This allows a URL parameter of `{ slug: 'camping/tents/awesome_tent' }`
* to serialize to `/product/camping/tents/awesome_tent`
* instead of `/product/camping%2Ftents%2Fawesome_tent`.
*
* ---
*
* Note: this value overrides the `raw` value on a custom parameter type ([[ParamTypeDefinition.raw]]).
*
* ### Decoding warning
*
* The decoding behavior of raw parameters is not defined.
* For example, given a url template such as `/:raw1/:raw2`
* the url `/foo/bar/baz/qux/`, there is no way to determine which slashes belong to which params.
*
* It's generally safe to use a raw parameter at the end of a path, like '/product/:slug'.
* However, beware of the characters you allow in your raw parameter values.
* Avoid unencoded characters that could disrupt normal URL parsing, such as `?` and `#`.
*
* ---
*
* Default: `false`
*/
raw?: boolean;
/**
* Enables/disables inheriting of this parameter's value
*
* When a transition is run with [[TransitionOptions.inherit]] set to
* `true`, the current param values are inherited in the new transition.
* However, parameters values which have `inherit: false` set will *not be inherited*.
*
* #### Example state :
* ```js
* var fooState = {
* name: 'foo',
* url: '/:fooId?mode&refresh',
* params: {
* refresh: { inherit: false }
* }
* }
*
* // Set fooId to 123
* $state.go('fooState', { fooId: 1234, mode: 'list', refresh: true });
* ```
*
* In the component:
* `mode: 'list' is inherited, but refresh: true is not inherited.
* // The param values are thus: `{ fooId: 4567, mode: 'list' }`
* ```
* <ui-sref="foo({ fooId: 4567 })">4567</ui-sref>
* ```
*
* ---
*
* See also [[TransitionOptions.inherit]] and [[ParamTypeDefinition.inherit]]
*
* ---
*
* Default: `true`
*/
inherit?: boolean;
}
/**
* String replacement
*
* Represents an exact match string replacement.
*
* Note: `to` or `from` may be null or undefined, and will be tested using `===`.
*/
export interface Replace {
/**
* The value to replace.
*
* May be `null` or `undefined`.
* The entire value must match using `===`.
* When found, the [[to]] value is used instead.
*/
from: string;
/**
* The new value
*
* Used instead of the [[from]] value.
*/
to: string;
}
/**
* Describes a custom [[ParamType]]
*
* See: [[UrlMatcherFactory.type]]
*
* A developer can create a custom parameter type definition to customize the encoding and decoding of parameter values.
* The definition should implement all the methods of this interface.
*
* Parameter values are parsed from the URL as strings.
* However, it is often useful to parse the string into some other form, such as:
*
* - integer
* - date
* - array of <integer/date/string>
* - custom object
* - some internal string representation
*
* Typed parameter definitions control how parameter values are encoded (to the URL) and decoded (from the URL).
* UI-Router always provides the decoded parameter values to the user (from methods such as [[Transition.params]])).
*
* For example, if a state has a url of `/foo/{fooId:int}` (the `fooId` parameter is of the `int` ParamType)
* and if the browser is at `/foo/123`, then the 123 is parsed as an integer:
*
* ```js
* var fooId = transition.params().fooId;
* fooId === "123" // false
* fooId === 123 // true
* ```
*
*
* #### Examples
*
* This example encodes an array of integers as a dash-delimited string to be used in the URL.
*
* If we call `$state.go('foo', { fooIds: [20, 30, 40] });`, the URL changes to `/foo/20-30-40`.
* If we navigate to `/foo/1-2-3`, the `foo` state's onEnter logs `[1, 2, 3]`.
*
* @example
* ```
*
* $urlMatcherFactoryProvider.type('intarray', {
* // Take an array of ints [1,2,3] and return a string "1-2-3"
* encode: (array) => array.join("-"),
*
* // Take an string "1-2-3" and return an array of ints [1,2,3]
* decode: (str) => str.split("-").map(x => parseInt(x, 10)),
*
* // Match the encoded string in the URL
* pattern: new RegExp("[0-9]+(?:-[0-9]+)*")
*
* // Ensure that the (decoded) object is an array, and that all its elements are numbers
* is: (obj) => Array.isArray(obj) &&
* obj.reduce((acc, item) => acc && typeof item === 'number', true),
*
* // Compare two arrays of integers
* equals: (array1, array2) => array1.length === array2.length &&
* array1.reduce((acc, item, idx) => acc && item === array2[idx], true);
* });
*
* $stateProvider.state('foo', {
* url: "/foo/{fooIds:intarray}",
* onEnter: function($transition$) {
* console.log($transition$.fooIds); // Logs "[1, 2, 3]"
* }
* });
* ```
*
*
* This example decodes an integer from the URL.
* It uses the integer as an index to look up an item from a static list.
* That item from the list is the decoded parameter value.
*
* @example
* ```
*
* var list = ['John', 'Paul', 'George', 'Ringo'];
*
* $urlMatcherFactoryProvider.type('listItem', {
* encode: function(item) {
* // Represent the list item in the URL using its corresponding index
* return list.indexOf(item);
* },
* decode: function(item) {
* // Look up the list item by index
* return list[parseInt(item, 10)];
* },
* is: function(item) {
* // Ensure the item is valid by checking to see that it appears
* // in the list
* return list.indexOf(item) > -1;
* }
* });
*
* $stateProvider.state('list', {
* url: "/list/{item:listItem}",
* controller: function($scope, $stateParams) {
* console.log($stateParams.item);
* }
* });
*
* // ...
*
* // Changes URL to '/list/3', logs "Ringo" to the console
* $state.go('list', { item: "Ringo" });
* ```
*
* See: [[UrlConfig.type]]
*/
export interface ParamTypeDefinition {
/**
* A regular expression that matches the encoded parameter type
*
* This regular expression is used to match an encoded parameter value **in the URL**.
*
* For example, if your type encodes as a dash-separated numbers, match that here:
* `new RegExp("[0-9]+(?:-[0-9]+)*")`.
*
* There are some limitations to these regexps:
*
* - No capturing groups are allowed (use non-capturing groups: `(?: )`)
* - No pattern modifiers like case insensitive
* - No start-of-string or end-of-string: `/^foo$/`
*/
pattern?: RegExp;
/**
* Disables url-encoding of parameter values
*
* If a parameter type is declared `raw`, it will not be url-encoded.
* Custom encoding can still be applied in the [[encode]] function.
*
* ### Decoding warning
*
* The decoding behavior of raw parameters is not defined.
* See: [[ParamDeclaration.raw]] for details
*/
raw?: boolean;
/**
* Enables/disables inheriting of parameter values (of this type)
*
* When a transition is run with [[TransitionOptions.inherit]] set to
* `true`, the current param values are inherited in the new transition.
* However, parameters whose type has `inherit: false` set will *not be inherited*.
*
* The internal parameter type of `hash` has `inherit: false`.
* This is used to disable inheriting of the hash value (`#`) on subsequent transitions.
*
* #### Example:
* ```js
* $state.go('home', { '#': 'inboxAnchor' });
* ...
* // "#" is not inherited.
* // The value of the "#" parameter will be `null`
* // The url's hash will be cleared.
* $state.go('home.nest');
* ```
*
* ---
*
* See also [[TransitionOptions.inherit]] and [[ParamDeclaration.inherit]]
*
*/
inherit?: boolean;
/**
* Dynamic flag
*
* When `dynamic` is `true`, changes to the parameter value will not cause the state to be entered/exited.
*
* Normally, if a parameter value changes, the state which declared that the parameter will be reloaded (entered/exited).
* When a parameter is `dynamic`, a transition still occurs, but it does not cause the state to exit/enter.
*
* Default: `false`
*/
dynamic?: boolean;
/**
* Tests if some object type is compatible with this parameter type
*
* Detects whether some value is of this particular type.
* Accepts a decoded value and determines whether it matches this `ParamType` object.
*
* If your custom type encodes the parameter to a specific type, check for that type here.
* For example, if your custom type decodes the URL parameter value as an array of ints, return true if the
* input is an array of ints:
*
* ```
* is: (val) => Array.isArray(val) && array.reduce((acc, x) => acc && parseInt(val, 10) === val, true)
* ```
*
* If your type decodes the URL parameter value to a custom string, check that the string matches
* the pattern (don't use an arrow fn if you need `this`): `function (val) { return !!this.pattern.exec(val) }`
*
* Note: This method is _not used to check if the URL matches_.
* It's used to check if a _decoded value *is* this type_.
* Use [[pattern]] to check the encoded value in the URL.
*
* @param val The value to check.
* @param key If the type check is happening in the context of a specific [[UrlMatcher]] object,
* this is the name of the parameter in which `val` is stored. Can be used for
* meta-programming of `ParamType` objects.
* @returns `true` if the value matches the type, otherwise `false`.
*/
is(val: any, key?: string): boolean;
/**
* Encodes a custom/native type value to a string that can be embedded in a URL.
*
* Note that the return value does *not* need to be URL-safe (i.e. passed through `encodeURIComponent()`).
* It only needs to be a representation of `val` that has been encoded as a string.
*
* For example, if your custom type decodes to an array of ints, then encode the array of ints to a string here:
*
* ```js
* encode: (intarray) => intarray.join("-")
* ```
*
* Note: in general, [[encode]] and [[decode]] should be symmetrical. That is, `encode(decode(str)) === str`
*
* @param val The value to encode.
* @param key The name of the parameter in which `val` is stored. Can be used for meta-programming of `ParamType` objects.
* @returns a string representation of `val` that can be encoded in a URL.
*/
encode(val: any, key?: string): string | string[];
/**
* Decodes a parameter value string (from URL string or transition param) to a custom/native value.
*
* For example, if your type decodes to an array of ints, then decode the string as an array of ints here:
* ```js
* decode: (str) => str.split("-").map(str => parseInt(str, 10))
* ```
*
* Note: in general, [[encode]] and [[decode]] should be symmetrical. That is, `encode(decode(str)) === str`
*
* @param val The URL parameter value to decode.
* @param key The name of the parameter in which `val` is stored. Can be used for meta-programming of `ParamType` objects.
* @returns a custom representation of the URL parameter value.
*/
decode(val: string, key?: string): any;
/**
* Determines whether two decoded values are equivalent.
*
* For example, if your type decodes to an array of ints, then check if the arrays are equal:
* ```js
* equals: (a, b) => a.length === b.length && a.reduce((acc, x, idx) => acc && x === b[idx], true)
* ```
*
* @param a A value to compare against.
* @param b A value to compare against.
* @returns `true` if the values are equivalent/equal, otherwise `false`.
*/
equals(a: any, b: any): boolean;
}