@angular-wave/angular.ts 0.0.11 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular-ts.esm.js +1 -1
- package/dist/angular-ts.umd.js +1 -1
- package/package.json +4 -1
- package/src/exts/messages.md +30 -30
- package/src/index.js +1 -0
- package/src/public.js +2 -0
- package/src/router/adapter/directives/stateDirectives.js +695 -0
- package/src/router/adapter/directives/viewDirective.js +514 -0
- package/src/router/adapter/injectables.js +314 -0
- package/src/router/adapter/interface.js +1 -0
- package/src/router/adapter/locationServices.js +84 -0
- package/src/router/adapter/services.js +126 -0
- package/src/router/adapter/stateFilters.js +43 -0
- package/src/router/adapter/stateProvider.js +137 -0
- package/src/router/adapter/statebuilders/onEnterExitRetain.js +30 -0
- package/src/router/adapter/statebuilders/views.js +146 -0
- package/src/router/adapter/templateFactory.js +218 -0
- package/src/router/adapter/viewScroll.js +31 -0
- package/src/router/core/common/common.js +496 -0
- package/src/router/core/common/coreservices.js +15 -0
- package/src/router/core/common/glob.js +75 -0
- package/src/router/core/common/hof.js +194 -0
- package/src/router/core/common/predicates.js +44 -0
- package/src/router/core/common/queue.js +41 -0
- package/src/router/core/common/safeConsole.js +38 -0
- package/src/router/core/common/strings.js +141 -0
- package/src/router/core/common/trace.js +232 -0
- package/src/router/core/globals.js +29 -0
- package/src/router/core/hooks/coreResolvables.js +33 -0
- package/src/router/core/hooks/ignoredTransition.js +25 -0
- package/src/router/core/hooks/invalidTransition.js +14 -0
- package/src/router/core/hooks/lazyLoad.js +102 -0
- package/src/router/core/hooks/onEnterExitRetain.js +55 -0
- package/src/router/core/hooks/redirectTo.js +36 -0
- package/src/router/core/hooks/resolve.js +57 -0
- package/src/router/core/hooks/updateGlobals.js +30 -0
- package/src/router/core/hooks/url.js +25 -0
- package/src/router/core/hooks/views.js +39 -0
- package/src/router/core/interface.js +3 -0
- package/src/router/core/params/README.md +8 -0
- package/src/router/core/params/param.js +232 -0
- package/src/router/core/params/paramType.js +139 -0
- package/src/router/core/params/paramTypes.js +163 -0
- package/src/router/core/params/stateParams.js +35 -0
- package/src/router/core/path/pathNode.js +77 -0
- package/src/router/core/path/pathUtils.js +199 -0
- package/src/router/core/resolve/interface.js +10 -0
- package/src/router/core/resolve/resolvable.js +124 -0
- package/src/router/core/resolve/resolveContext.js +211 -0
- package/src/router/core/router.js +203 -0
- package/src/router/core/state/README.md +21 -0
- package/src/router/core/state/stateBuilder.js +332 -0
- package/src/router/core/state/stateMatcher.js +65 -0
- package/src/router/core/state/stateObject.js +117 -0
- package/src/router/core/state/stateQueueManager.js +89 -0
- package/src/router/core/state/stateRegistry.js +175 -0
- package/src/router/core/state/stateService.js +592 -0
- package/src/router/core/state/targetState.js +159 -0
- package/src/router/core/transition/hookBuilder.js +127 -0
- package/src/router/core/transition/hookRegistry.js +175 -0
- package/src/router/core/transition/interface.js +14 -0
- package/src/router/core/transition/rejectFactory.js +122 -0
- package/src/router/core/transition/transition.js +739 -0
- package/src/router/core/transition/transitionEventType.js +27 -0
- package/src/router/core/transition/transitionHook.js +199 -0
- package/src/router/core/transition/transitionService.js +311 -0
- package/src/router/core/url/interface.js +1 -0
- package/src/router/core/url/urlConfig.js +165 -0
- package/src/router/core/url/urlMatcher.js +548 -0
- package/src/router/core/url/urlMatcherFactory.js +123 -0
- package/src/router/core/url/urlRouter.js +115 -0
- package/src/router/core/url/urlRule.js +202 -0
- package/src/router/core/url/urlRules.js +348 -0
- package/src/router/core/url/urlService.js +268 -0
- package/src/router/core/view/interface.js +1 -0
- package/src/router/core/view/view.js +312 -0
- package/src/router/router.js +58 -0
- package/test/module-test.html +6 -2
- package/test/module-test.js +0 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Higher order functions
|
|
3
|
+
*
|
|
4
|
+
* These utility functions are exported, but are subject to change without notice.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Returns a new function for [Partial Application](https://en.wikipedia.org/wiki/Partial_application) of the original function.
|
|
10
|
+
*
|
|
11
|
+
* Given a function with N parameters, returns a new function that supports partial application.
|
|
12
|
+
* The new function accepts anywhere from 1 to N parameters. When that function is called with M parameters,
|
|
13
|
+
* where M is less than N, it returns a new function that accepts the remaining parameters. It continues to
|
|
14
|
+
* accept more parameters until all N parameters have been supplied.
|
|
15
|
+
*
|
|
16
|
+
*
|
|
17
|
+
* This contrived example uses a partially applied function as an predicate, which returns true
|
|
18
|
+
* if an object is found in both arrays.
|
|
19
|
+
* @example
|
|
20
|
+
* ```
|
|
21
|
+
* // returns true if an object is in both of the two arrays
|
|
22
|
+
* function inBoth(array1, array2, object) {
|
|
23
|
+
* return array1.indexOf(object) !== -1 &&
|
|
24
|
+
* array2.indexOf(object) !== 1;
|
|
25
|
+
* }
|
|
26
|
+
* let obj1, obj2, obj3, obj4, obj5, obj6, obj7
|
|
27
|
+
* let foos = [obj1, obj3]
|
|
28
|
+
* let bars = [obj3, obj4, obj5]
|
|
29
|
+
*
|
|
30
|
+
* // A curried "copy" of inBoth
|
|
31
|
+
* let curriedInBoth = curry(inBoth);
|
|
32
|
+
* // Partially apply both the array1 and array2
|
|
33
|
+
* let inFoosAndBars = curriedInBoth(foos, bars);
|
|
34
|
+
*
|
|
35
|
+
* // Supply the final argument; since all arguments are
|
|
36
|
+
* // supplied, the original inBoth function is then called.
|
|
37
|
+
* let obj1InBoth = inFoosAndBars(obj1); // false
|
|
38
|
+
*
|
|
39
|
+
* // Use the inFoosAndBars as a predicate.
|
|
40
|
+
* // Filter, on each iteration, supplies the final argument
|
|
41
|
+
* let allObjs = [ obj1, obj2, obj3, obj4, obj5, obj6, obj7 ];
|
|
42
|
+
* let foundInBoth = allObjs.filter(inFoosAndBars); // [ obj3 ]
|
|
43
|
+
*
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @param fn
|
|
47
|
+
* @returns {*|function(): (*|any)}
|
|
48
|
+
*/
|
|
49
|
+
export function curry(fn) {
|
|
50
|
+
return function curried() {
|
|
51
|
+
if (arguments.length >= fn.length) {
|
|
52
|
+
return fn.apply(this, arguments);
|
|
53
|
+
}
|
|
54
|
+
const args = Array.prototype.slice.call(arguments);
|
|
55
|
+
return curried.bind(this, ...args);
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Given a varargs list of functions, returns a function that composes the argument functions, right-to-left
|
|
60
|
+
* given: f(x), g(x), h(x)
|
|
61
|
+
* let composed = compose(f,g,h)
|
|
62
|
+
* then, composed is: f(g(h(x)))
|
|
63
|
+
*/
|
|
64
|
+
export function compose() {
|
|
65
|
+
const args = arguments;
|
|
66
|
+
const start = args.length - 1;
|
|
67
|
+
return function () {
|
|
68
|
+
let i = start,
|
|
69
|
+
result = args[start].apply(this, arguments);
|
|
70
|
+
while (i--) result = args[i].call(this, result);
|
|
71
|
+
return result;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Given a varargs list of functions, returns a function that is composes the argument functions, left-to-right
|
|
76
|
+
* given: f(x), g(x), h(x)
|
|
77
|
+
* let piped = pipe(f,g,h);
|
|
78
|
+
* then, piped is: h(g(f(x)))
|
|
79
|
+
*/
|
|
80
|
+
export function pipe(...funcs) {
|
|
81
|
+
return compose.apply(null, [].slice.call(arguments).reverse());
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Given a property name, returns a function that returns that property from an object
|
|
85
|
+
* let obj = { foo: 1, name: "blarg" };
|
|
86
|
+
* let getName = prop("name");
|
|
87
|
+
* getName(obj) === "blarg"
|
|
88
|
+
*/
|
|
89
|
+
export const prop = (name) => (obj) => obj && obj[name];
|
|
90
|
+
/**
|
|
91
|
+
* Given a property name and a value, returns a function that returns a boolean based on whether
|
|
92
|
+
* the passed object has a property that matches the value
|
|
93
|
+
* let obj = { foo: 1, name: "blarg" };
|
|
94
|
+
* let getName = propEq("name", "blarg");
|
|
95
|
+
* getName(obj) === true
|
|
96
|
+
*/
|
|
97
|
+
export const propEq = curry((name, _val, obj) => obj && obj[name] === _val);
|
|
98
|
+
/**
|
|
99
|
+
* Given a dotted property name, returns a function that returns a nested property from an object, or undefined
|
|
100
|
+
* let obj = { id: 1, nestedObj: { foo: 1, name: "blarg" }, };
|
|
101
|
+
* let getName = prop("nestedObj.name");
|
|
102
|
+
* getName(obj) === "blarg"
|
|
103
|
+
* let propNotFound = prop("this.property.doesnt.exist");
|
|
104
|
+
* propNotFound(obj) === undefined
|
|
105
|
+
*/
|
|
106
|
+
export const parse = (name) => pipe.apply(null, name.split(".").map(prop));
|
|
107
|
+
/**
|
|
108
|
+
* Given a function that returns a truthy or falsey value, returns a
|
|
109
|
+
* function that returns the opposite (falsey or truthy) value given the same inputs
|
|
110
|
+
*/
|
|
111
|
+
export const not =
|
|
112
|
+
(fn) =>
|
|
113
|
+
(...args) =>
|
|
114
|
+
!fn.apply(null, args);
|
|
115
|
+
/**
|
|
116
|
+
* Given two functions that return truthy or falsey values, returns a function that returns truthy
|
|
117
|
+
* if both functions return truthy for the given arguments
|
|
118
|
+
*/
|
|
119
|
+
export function and(fn1, fn2) {
|
|
120
|
+
return (...args) => fn1.apply(null, args) && fn2.apply(null, args);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Given two functions that return truthy or falsey values, returns a function that returns truthy
|
|
124
|
+
* if at least one of the functions returns truthy for the given arguments
|
|
125
|
+
*/
|
|
126
|
+
export function or(fn1, fn2) {
|
|
127
|
+
return (...args) => fn1.apply(null, args) || fn2.apply(null, args);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Check if all the elements of an array match a predicate function
|
|
131
|
+
*
|
|
132
|
+
* @param fn1 a predicate function `fn1`
|
|
133
|
+
* @returns a function which takes an array and returns true if `fn1` is true for all elements of the array
|
|
134
|
+
*/
|
|
135
|
+
export const all = (fn1) => (arr) => arr.reduce((b, x) => b && !!fn1(x), true);
|
|
136
|
+
// tslint:disable-next-line:variable-name
|
|
137
|
+
export const any = (fn1) => (arr) => arr.reduce((b, x) => b || !!fn1(x), false);
|
|
138
|
+
/** Given a class, returns a Predicate function that returns true if the object is of that class */
|
|
139
|
+
export const is = (ctor) => (obj) =>
|
|
140
|
+
(obj != null && obj.constructor === ctor) || obj instanceof ctor;
|
|
141
|
+
/** Given a value, returns a Predicate function that returns true if another value is === equal to the original value */
|
|
142
|
+
export const eq = (value) => (other) => value === other;
|
|
143
|
+
/** Given a value, returns a function which returns the value */
|
|
144
|
+
export const val = (v) => () => v;
|
|
145
|
+
export function invoke(fnName, args) {
|
|
146
|
+
return (obj) => obj[fnName].apply(obj, args);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Sorta like Pattern Matching (a functional programming conditional construct)
|
|
150
|
+
*
|
|
151
|
+
* See http://c2.com/cgi/wiki?PatternMatching
|
|
152
|
+
*
|
|
153
|
+
* This is a conditional construct which allows a series of predicates and output functions
|
|
154
|
+
* to be checked and then applied. Each predicate receives the input. If the predicate
|
|
155
|
+
* returns truthy, then its matching output function (mapping function) is provided with
|
|
156
|
+
* the input and, then the result is returned.
|
|
157
|
+
*
|
|
158
|
+
* Each combination (2-tuple) of predicate + output function should be placed in an array
|
|
159
|
+
* of size 2: [ predicate, mapFn ]
|
|
160
|
+
*
|
|
161
|
+
* These 2-tuples should be put in an outer array.
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```
|
|
165
|
+
*
|
|
166
|
+
* // Here's a 2-tuple where the first element is the isString predicate
|
|
167
|
+
* // and the second element is a function that returns a description of the input
|
|
168
|
+
* let firstTuple = [ angular.isString, (input) => `Heres your string ${input}` ];
|
|
169
|
+
*
|
|
170
|
+
* // Second tuple: predicate "isNumber", mapfn returns a description
|
|
171
|
+
* let secondTuple = [ angular.isNumber, (input) => `(${input}) That's a number!` ];
|
|
172
|
+
*
|
|
173
|
+
* let third = [ (input) => input === null, (input) => `Oh, null...` ];
|
|
174
|
+
*
|
|
175
|
+
* let fourth = [ (input) => input === undefined, (input) => `notdefined` ];
|
|
176
|
+
*
|
|
177
|
+
* let descriptionOf = pattern([ firstTuple, secondTuple, third, fourth ]);
|
|
178
|
+
*
|
|
179
|
+
* console.log(descriptionOf(undefined)); // 'notdefined'
|
|
180
|
+
* console.log(descriptionOf(55)); // '(55) That's a number!'
|
|
181
|
+
* console.log(descriptionOf("foo")); // 'Here's your string foo'
|
|
182
|
+
* ```
|
|
183
|
+
*
|
|
184
|
+
* @param struct A 2D array. Each element of the array should be an array, a 2-tuple,
|
|
185
|
+
* with a Predicate and a mapping/output function
|
|
186
|
+
* @returns {function(any): *}
|
|
187
|
+
*/
|
|
188
|
+
export function pattern(struct) {
|
|
189
|
+
return function (x) {
|
|
190
|
+
for (let i = 0; i < struct.length; i++) {
|
|
191
|
+
if (struct[i][0](x)) return struct[i][1](x);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Predicates
|
|
3
|
+
*
|
|
4
|
+
* These predicates return true/false based on the input.
|
|
5
|
+
* Although these functions are exported, they are subject to change without notice.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
import { and, not, pipe, prop, or } from "./hof";
|
|
10
|
+
const toStr = Object.prototype.toString;
|
|
11
|
+
const tis = (t) => (x) => typeof x === t;
|
|
12
|
+
export const isUndefined = tis("undefined");
|
|
13
|
+
export const isDefined = not(isUndefined);
|
|
14
|
+
export const isNull = (o) => o === null;
|
|
15
|
+
export const isNullOrUndefined = or(isNull, isUndefined);
|
|
16
|
+
export const isFunction = tis("function");
|
|
17
|
+
export const isNumber = tis("number");
|
|
18
|
+
export const isString = tis("string");
|
|
19
|
+
export const isObject = (x) => x !== null && typeof x === "object";
|
|
20
|
+
export const isArray = Array.isArray;
|
|
21
|
+
export const isDate = (x) => toStr.call(x) === "[object Date]";
|
|
22
|
+
export const isRegExp = (x) => toStr.call(x) === "[object RegExp]";
|
|
23
|
+
/**
|
|
24
|
+
* Predicate which checks if a value is injectable
|
|
25
|
+
*
|
|
26
|
+
* A value is "injectable" if it is a function, or if it is an ng1 array-notation-style array
|
|
27
|
+
* where all the elements in the array are Strings, except the last one, which is a Function
|
|
28
|
+
*/
|
|
29
|
+
export function isInjectable(val) {
|
|
30
|
+
if (isArray(val) && val.length) {
|
|
31
|
+
const head = val.slice(0, -1),
|
|
32
|
+
tail = val.slice(-1);
|
|
33
|
+
return !(
|
|
34
|
+
head.filter(not(isString)).length || tail.filter(not(isFunction)).length
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
return isFunction(val);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Predicate which checks if a value looks like a Promise
|
|
41
|
+
*
|
|
42
|
+
* It is probably a Promise if it's an object, and it has a `then` property which is a Function
|
|
43
|
+
*/
|
|
44
|
+
export const isPromise = and(isObject, pipe(prop("then"), isFunction));
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { pushTo } from "./common";
|
|
2
|
+
export class Queue {
|
|
3
|
+
constructor(_items = [], _limit = null) {
|
|
4
|
+
this._items = _items;
|
|
5
|
+
this._limit = _limit;
|
|
6
|
+
this._evictListeners = [];
|
|
7
|
+
this.onEvict = pushTo(this._evictListeners);
|
|
8
|
+
}
|
|
9
|
+
enqueue(item) {
|
|
10
|
+
const items = this._items;
|
|
11
|
+
items.push(item);
|
|
12
|
+
if (this._limit && items.length > this._limit) this.evict();
|
|
13
|
+
return item;
|
|
14
|
+
}
|
|
15
|
+
evict() {
|
|
16
|
+
const item = this._items.shift();
|
|
17
|
+
this._evictListeners.forEach((fn) => fn(item));
|
|
18
|
+
return item;
|
|
19
|
+
}
|
|
20
|
+
dequeue() {
|
|
21
|
+
if (this.size()) return this._items.splice(0, 1)[0];
|
|
22
|
+
}
|
|
23
|
+
clear() {
|
|
24
|
+
const current = this._items;
|
|
25
|
+
this._items = [];
|
|
26
|
+
return current;
|
|
27
|
+
}
|
|
28
|
+
size() {
|
|
29
|
+
return this._items.length;
|
|
30
|
+
}
|
|
31
|
+
remove(item) {
|
|
32
|
+
const idx = this._items.indexOf(item);
|
|
33
|
+
return idx > -1 && this._items.splice(idx, 1)[0];
|
|
34
|
+
}
|
|
35
|
+
peekTail() {
|
|
36
|
+
return this._items[this._items.length - 1];
|
|
37
|
+
}
|
|
38
|
+
peekHead() {
|
|
39
|
+
if (this.size()) return this._items[0];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* workaround for missing console object in IE9 when dev tools haven't been opened o_O
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
/* tslint:disable:no-console */
|
|
6
|
+
import { noop } from "./common";
|
|
7
|
+
const noopConsoleStub = { log: noop, error: noop, table: noop };
|
|
8
|
+
function ie9Console(console) {
|
|
9
|
+
const bound = (fn) => Function.prototype.bind.call(fn, console);
|
|
10
|
+
return {
|
|
11
|
+
log: bound(console.log),
|
|
12
|
+
error: bound(console.log),
|
|
13
|
+
table: bound(console.log),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function fallbackConsole(console) {
|
|
17
|
+
const log = console.log.bind(console);
|
|
18
|
+
const error = console.error ? console.error.bind(console) : log;
|
|
19
|
+
const table = console.table ? console.table.bind(console) : log;
|
|
20
|
+
return { log, error, table };
|
|
21
|
+
}
|
|
22
|
+
function getSafeConsole() {
|
|
23
|
+
// @ts-ignore
|
|
24
|
+
const isIE9 =
|
|
25
|
+
typeof document !== "undefined" &&
|
|
26
|
+
document.documentMode &&
|
|
27
|
+
document.documentMode === 9;
|
|
28
|
+
if (isIE9) {
|
|
29
|
+
return window && window.console
|
|
30
|
+
? ie9Console(window.console)
|
|
31
|
+
: noopConsoleStub;
|
|
32
|
+
} else if (!console.table || !console.error) {
|
|
33
|
+
return fallbackConsole(console);
|
|
34
|
+
} else {
|
|
35
|
+
return console;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export const safeConsole = getSafeConsole();
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Functions that manipulate strings
|
|
3
|
+
*
|
|
4
|
+
* Although these functions are exported, they are subject to change without notice.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
import {
|
|
9
|
+
isArray,
|
|
10
|
+
isFunction,
|
|
11
|
+
isInjectable,
|
|
12
|
+
isNull,
|
|
13
|
+
isObject,
|
|
14
|
+
isPromise,
|
|
15
|
+
isString,
|
|
16
|
+
isUndefined,
|
|
17
|
+
} from "./predicates";
|
|
18
|
+
import { Rejection } from "../transition/rejectFactory";
|
|
19
|
+
import { identity, pushR, tail } from "./common";
|
|
20
|
+
import { pattern, val } from "./hof";
|
|
21
|
+
/**
|
|
22
|
+
* Returns a string shortened to a maximum length
|
|
23
|
+
*
|
|
24
|
+
* If the string is already less than the `max` length, return the string.
|
|
25
|
+
* Else return the string, shortened to `max - 3` and append three dots ("...").
|
|
26
|
+
*
|
|
27
|
+
* @param max the maximum length of the string to return
|
|
28
|
+
* @param str the input string
|
|
29
|
+
*/
|
|
30
|
+
export function maxLength(max, str) {
|
|
31
|
+
if (str.length <= max) return str;
|
|
32
|
+
return str.substr(0, max - 3) + "...";
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Returns a string, with spaces added to the end, up to a desired str length
|
|
36
|
+
*
|
|
37
|
+
* If the string is already longer than the desired length, return the string.
|
|
38
|
+
* Else returns the string, with extra spaces on the end, such that it reaches `length` characters.
|
|
39
|
+
*
|
|
40
|
+
* @param length the desired length of the string to return
|
|
41
|
+
* @param str the input string
|
|
42
|
+
*/
|
|
43
|
+
export function padString(length, str) {
|
|
44
|
+
while (str.length < length) str += " ";
|
|
45
|
+
return str;
|
|
46
|
+
}
|
|
47
|
+
export function kebobString(camelCase) {
|
|
48
|
+
return camelCase
|
|
49
|
+
.replace(/^([A-Z])/, ($1) => $1.toLowerCase()) // replace first char
|
|
50
|
+
.replace(/([A-Z])/g, ($1) => "-" + $1.toLowerCase()); // replace rest
|
|
51
|
+
}
|
|
52
|
+
export function functionToString(fn) {
|
|
53
|
+
const fnStr = fnToString(fn);
|
|
54
|
+
const namedFunctionMatch = fnStr.match(/^(function [^ ]+\([^)]*\))/);
|
|
55
|
+
const toStr = namedFunctionMatch ? namedFunctionMatch[1] : fnStr;
|
|
56
|
+
const fnName = fn["name"] || "";
|
|
57
|
+
if (fnName && toStr.match(/function \(/)) {
|
|
58
|
+
return "function " + fnName + toStr.substr(9);
|
|
59
|
+
}
|
|
60
|
+
return toStr;
|
|
61
|
+
}
|
|
62
|
+
export function fnToString(fn) {
|
|
63
|
+
const _fn = isArray(fn) ? fn.slice(-1)[0] : fn;
|
|
64
|
+
return (_fn && _fn.toString()) || "undefined";
|
|
65
|
+
}
|
|
66
|
+
export function stringify(o) {
|
|
67
|
+
const seen = [];
|
|
68
|
+
const isRejection = Rejection.isRejectionPromise;
|
|
69
|
+
const hasToString = (obj) =>
|
|
70
|
+
isObject(obj) &&
|
|
71
|
+
!isArray(obj) &&
|
|
72
|
+
obj.constructor !== Object &&
|
|
73
|
+
isFunction(obj.toString);
|
|
74
|
+
const stringifyPattern = pattern([
|
|
75
|
+
[isUndefined, val("undefined")],
|
|
76
|
+
[isNull, val("null")],
|
|
77
|
+
[isPromise, val("[Promise]")],
|
|
78
|
+
[isRejection, (x) => x._transitionRejection.toString()],
|
|
79
|
+
[hasToString, (x) => x.toString()],
|
|
80
|
+
[isInjectable, functionToString],
|
|
81
|
+
[val(true), identity],
|
|
82
|
+
]);
|
|
83
|
+
function format(value) {
|
|
84
|
+
if (isObject(value)) {
|
|
85
|
+
if (seen.indexOf(value) !== -1) return "[circular ref]";
|
|
86
|
+
seen.push(value);
|
|
87
|
+
}
|
|
88
|
+
return stringifyPattern(value);
|
|
89
|
+
}
|
|
90
|
+
if (isUndefined(o)) {
|
|
91
|
+
// Workaround for IE & Edge Spec incompatibility where replacer function would not be called when JSON.stringify
|
|
92
|
+
// is given `undefined` as value. To work around that, we simply detect `undefined` and bail out early by
|
|
93
|
+
// manually stringifying it.
|
|
94
|
+
return format(o);
|
|
95
|
+
}
|
|
96
|
+
return JSON.stringify(o, (key, value) => format(value)).replace(/\\"/g, '"');
|
|
97
|
+
}
|
|
98
|
+
/** Returns a function that splits a string on a character or substring */
|
|
99
|
+
export const beforeAfterSubstr = (char) => (str) => {
|
|
100
|
+
if (!str) return ["", ""];
|
|
101
|
+
const idx = str.indexOf(char);
|
|
102
|
+
if (idx === -1) return [str, ""];
|
|
103
|
+
return [str.substr(0, idx), str.substr(idx + 1)];
|
|
104
|
+
};
|
|
105
|
+
export const hostRegex = new RegExp("^(?:[a-z]+:)?//[^/]+/");
|
|
106
|
+
export const stripLastPathElement = (str) => str.replace(/\/[^/]*$/, "");
|
|
107
|
+
export const splitHash = beforeAfterSubstr("#");
|
|
108
|
+
export const splitQuery = beforeAfterSubstr("?");
|
|
109
|
+
export const splitEqual = beforeAfterSubstr("=");
|
|
110
|
+
export const trimHashVal = (str) => (str ? str.replace(/^#/, "") : "");
|
|
111
|
+
/**
|
|
112
|
+
* Splits on a delimiter, but returns the delimiters in the array
|
|
113
|
+
*
|
|
114
|
+
* #### Example:
|
|
115
|
+
* ```js
|
|
116
|
+
* var splitOnSlashes = splitOnDelim('/');
|
|
117
|
+
* splitOnSlashes("/foo"); // ["/", "foo"]
|
|
118
|
+
* splitOnSlashes("/foo/"); // ["/", "foo", "/"]
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export function splitOnDelim(delim) {
|
|
122
|
+
const re = new RegExp("(" + delim + ")", "g");
|
|
123
|
+
return (str) => str.split(re).filter(identity);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Reduce fn that joins neighboring strings
|
|
127
|
+
*
|
|
128
|
+
* Given an array of strings, returns a new array
|
|
129
|
+
* where all neighboring strings have been joined.
|
|
130
|
+
*
|
|
131
|
+
* #### Example:
|
|
132
|
+
* ```js
|
|
133
|
+
* let arr = ["foo", "bar", 1, "baz", "", "qux" ];
|
|
134
|
+
* arr.reduce(joinNeighborsR, []) // ["foobar", 1, "bazqux" ]
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
export function joinNeighborsR(acc, x) {
|
|
138
|
+
if (isString(tail(acc)) && isString(x))
|
|
139
|
+
return acc.slice(0, -1).concat(tail(acc) + x);
|
|
140
|
+
return pushR(acc, x);
|
|
141
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # Transition tracing (debug)
|
|
3
|
+
*
|
|
4
|
+
* Enable transition tracing to print transition information to the console,
|
|
5
|
+
* in order to help debug your application.
|
|
6
|
+
* Tracing logs detailed information about each Transition to your console.
|
|
7
|
+
*
|
|
8
|
+
* To enable tracing, import the [[Trace]] singleton and enable one or more categories.
|
|
9
|
+
*
|
|
10
|
+
* ### ES6
|
|
11
|
+
* ```js
|
|
12
|
+
* import {trace} from "@uirouter/core/index";
|
|
13
|
+
* trace.enable(1, 5); // TRANSITION and VIEWCONFIG
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* ### CJS
|
|
17
|
+
* ```js
|
|
18
|
+
* let trace = require("@uirouter/core").trace;
|
|
19
|
+
* trace.enable("TRANSITION", "VIEWCONFIG");
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* ### Globals
|
|
23
|
+
* ```js
|
|
24
|
+
* let trace = window["@uirouter/core"].trace;
|
|
25
|
+
* trace.enable(); // Trace everything (very verbose)
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* ### Angular 1:
|
|
29
|
+
* ```js
|
|
30
|
+
* app.run($trace => $trace.enable());
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @packageDocumentation
|
|
34
|
+
*/
|
|
35
|
+
import { parse } from "../common/hof";
|
|
36
|
+
import { isNumber } from "../common/predicates";
|
|
37
|
+
import { stringify, functionToString, maxLength, padString } from "./strings";
|
|
38
|
+
import { safeConsole } from "./safeConsole";
|
|
39
|
+
function uiViewString(uiview) {
|
|
40
|
+
if (!uiview) return "ui-view (defunct)";
|
|
41
|
+
const state = uiview.creationContext
|
|
42
|
+
? uiview.creationContext.name || "(root)"
|
|
43
|
+
: "(none)";
|
|
44
|
+
return `[ui-view#${uiview.id} ${uiview.$type}:${uiview.fqn} (${uiview.name}@${state})]`;
|
|
45
|
+
}
|
|
46
|
+
const viewConfigString = (viewConfig) => {
|
|
47
|
+
const view = viewConfig.viewDecl;
|
|
48
|
+
const state = view.$context.name || "(root)";
|
|
49
|
+
return `[View#${viewConfig.$id} from '${state}' state]: target ui-view: '${view.$uiViewName}@${view.$uiViewContextAnchor}'`;
|
|
50
|
+
};
|
|
51
|
+
function normalizedCat(input) {
|
|
52
|
+
return isNumber(input) ? Category[input] : Category[Category[input]];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Trace categories Enum
|
|
56
|
+
*
|
|
57
|
+
* Enable or disable a category using [[Trace.enable]] or [[Trace.disable]]
|
|
58
|
+
*
|
|
59
|
+
* `trace.enable(Category.TRANSITION)`
|
|
60
|
+
*
|
|
61
|
+
* These can also be provided using a matching string, or position ordinal
|
|
62
|
+
*
|
|
63
|
+
* `trace.enable("TRANSITION")`
|
|
64
|
+
*
|
|
65
|
+
* `trace.enable(1)`
|
|
66
|
+
*/
|
|
67
|
+
var Category;
|
|
68
|
+
(function (Category) {
|
|
69
|
+
Category[(Category["RESOLVE"] = 0)] = "RESOLVE";
|
|
70
|
+
Category[(Category["TRANSITION"] = 1)] = "TRANSITION";
|
|
71
|
+
Category[(Category["HOOK"] = 2)] = "HOOK";
|
|
72
|
+
Category[(Category["UIVIEW"] = 3)] = "UIVIEW";
|
|
73
|
+
Category[(Category["VIEWCONFIG"] = 4)] = "VIEWCONFIG";
|
|
74
|
+
})(Category || (Category = {}));
|
|
75
|
+
export { Category };
|
|
76
|
+
const _tid = parse("$id");
|
|
77
|
+
const _rid = parse("router.$id");
|
|
78
|
+
const transLbl = (trans) => `Transition #${_tid(trans)}-${_rid(trans)}`;
|
|
79
|
+
/**
|
|
80
|
+
* Prints UI-Router Transition trace information to the console.
|
|
81
|
+
*/
|
|
82
|
+
export class Trace {
|
|
83
|
+
/** @internal */
|
|
84
|
+
constructor() {
|
|
85
|
+
/** @internal */
|
|
86
|
+
this._enabled = {};
|
|
87
|
+
this.approximateDigests = 0;
|
|
88
|
+
}
|
|
89
|
+
/** @internal */
|
|
90
|
+
_set(enabled, categories) {
|
|
91
|
+
if (!categories.length) {
|
|
92
|
+
categories = Object.keys(Category)
|
|
93
|
+
.map((k) => parseInt(k, 10))
|
|
94
|
+
.filter((k) => !isNaN(k))
|
|
95
|
+
.map((key) => Category[key]);
|
|
96
|
+
}
|
|
97
|
+
categories
|
|
98
|
+
.map(normalizedCat)
|
|
99
|
+
.forEach((category) => (this._enabled[category] = enabled));
|
|
100
|
+
}
|
|
101
|
+
enable(...categories) {
|
|
102
|
+
this._set(true, categories);
|
|
103
|
+
}
|
|
104
|
+
disable(...categories) {
|
|
105
|
+
this._set(false, categories);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Retrieves the enabled stateus of a [[Category]]
|
|
109
|
+
*
|
|
110
|
+
* ```js
|
|
111
|
+
* trace.enabled("VIEWCONFIG"); // true or false
|
|
112
|
+
* ```
|
|
113
|
+
*
|
|
114
|
+
* @returns boolean true if the category is enabled
|
|
115
|
+
*/
|
|
116
|
+
enabled(category) {
|
|
117
|
+
return !!this._enabled[normalizedCat(category)];
|
|
118
|
+
}
|
|
119
|
+
/** @internal called by ui-router code */
|
|
120
|
+
traceTransitionStart(trans) {
|
|
121
|
+
if (!this.enabled(Category.TRANSITION)) return;
|
|
122
|
+
safeConsole.log(`${transLbl(trans)}: Started -> ${stringify(trans)}`);
|
|
123
|
+
}
|
|
124
|
+
/** @internal called by ui-router code */
|
|
125
|
+
traceTransitionIgnored(trans) {
|
|
126
|
+
if (!this.enabled(Category.TRANSITION)) return;
|
|
127
|
+
safeConsole.log(`${transLbl(trans)}: Ignored <> ${stringify(trans)}`);
|
|
128
|
+
}
|
|
129
|
+
/** @internal called by ui-router code */
|
|
130
|
+
traceHookInvocation(step, trans, options) {
|
|
131
|
+
if (!this.enabled(Category.HOOK)) return;
|
|
132
|
+
const event = parse("traceData.hookType")(options) || "internal",
|
|
133
|
+
context =
|
|
134
|
+
parse("traceData.context.state.name")(options) ||
|
|
135
|
+
parse("traceData.context")(options) ||
|
|
136
|
+
"unknown",
|
|
137
|
+
name = functionToString(step.registeredHook.callback);
|
|
138
|
+
safeConsole.log(
|
|
139
|
+
`${transLbl(trans)}: Hook -> ${event} context: ${context}, ${maxLength(200, name)}`,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
/** @internal called by ui-router code */
|
|
143
|
+
traceHookResult(hookResult, trans, transitionOptions) {
|
|
144
|
+
if (!this.enabled(Category.HOOK)) return;
|
|
145
|
+
safeConsole.log(
|
|
146
|
+
`${transLbl(trans)}: <- Hook returned: ${maxLength(200, stringify(hookResult))}`,
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
/** @internal called by ui-router code */
|
|
150
|
+
traceResolvePath(path, when, trans) {
|
|
151
|
+
if (!this.enabled(Category.RESOLVE)) return;
|
|
152
|
+
safeConsole.log(`${transLbl(trans)}: Resolving ${path} (${when})`);
|
|
153
|
+
}
|
|
154
|
+
/** @internal called by ui-router code */
|
|
155
|
+
traceResolvableResolved(resolvable, trans) {
|
|
156
|
+
if (!this.enabled(Category.RESOLVE)) return;
|
|
157
|
+
safeConsole.log(
|
|
158
|
+
`${transLbl(trans)}: <- Resolved ${resolvable} to: ${maxLength(200, stringify(resolvable.data))}`,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
/** @internal called by ui-router code */
|
|
162
|
+
traceError(reason, trans) {
|
|
163
|
+
if (!this.enabled(Category.TRANSITION)) return;
|
|
164
|
+
safeConsole.log(
|
|
165
|
+
`${transLbl(trans)}: <- Rejected ${stringify(trans)}, reason: ${reason}`,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
/** @internal called by ui-router code */
|
|
169
|
+
traceSuccess(finalState, trans) {
|
|
170
|
+
if (!this.enabled(Category.TRANSITION)) return;
|
|
171
|
+
safeConsole.log(
|
|
172
|
+
`${transLbl(trans)}: <- Success ${stringify(trans)}, final state: ${finalState.name}`,
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
/** @internal called by ui-router code */
|
|
176
|
+
traceUIViewEvent(event, viewData, extra = "") {
|
|
177
|
+
if (!this.enabled(Category.UIVIEW)) return;
|
|
178
|
+
safeConsole.log(
|
|
179
|
+
`ui-view: ${padString(30, event)} ${uiViewString(viewData)}${extra}`,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
/** @internal called by ui-router code */
|
|
183
|
+
traceUIViewConfigUpdated(viewData, context) {
|
|
184
|
+
if (!this.enabled(Category.UIVIEW)) return;
|
|
185
|
+
this.traceUIViewEvent(
|
|
186
|
+
"Updating",
|
|
187
|
+
viewData,
|
|
188
|
+
` with ViewConfig from context='${context}'`,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
/** @internal called by ui-router code */
|
|
192
|
+
traceUIViewFill(viewData, html) {
|
|
193
|
+
if (!this.enabled(Category.UIVIEW)) return;
|
|
194
|
+
this.traceUIViewEvent("Fill", viewData, ` with: ${maxLength(200, html)}`);
|
|
195
|
+
}
|
|
196
|
+
/** @internal called by ui-router code */
|
|
197
|
+
traceViewSync(pairs) {
|
|
198
|
+
if (!this.enabled(Category.VIEWCONFIG)) return;
|
|
199
|
+
const uivheader = "uiview component fqn";
|
|
200
|
+
const cfgheader = "view config state (view name)";
|
|
201
|
+
const mapping = pairs
|
|
202
|
+
.map(({ uiView, viewConfig }) => {
|
|
203
|
+
const uiv = uiView && uiView.fqn;
|
|
204
|
+
const cfg =
|
|
205
|
+
viewConfig &&
|
|
206
|
+
`${viewConfig.viewDecl.$context.name}: (${viewConfig.viewDecl.$name})`;
|
|
207
|
+
return { [uivheader]: uiv, [cfgheader]: cfg };
|
|
208
|
+
})
|
|
209
|
+
.sort((a, b) => (a[uivheader] || "").localeCompare(b[uivheader] || ""));
|
|
210
|
+
safeConsole.table(mapping);
|
|
211
|
+
}
|
|
212
|
+
/** @internal called by ui-router code */
|
|
213
|
+
traceViewServiceEvent(event, viewConfig) {
|
|
214
|
+
if (!this.enabled(Category.VIEWCONFIG)) return;
|
|
215
|
+
safeConsole.log(`VIEWCONFIG: ${event} ${viewConfigString(viewConfig)}`);
|
|
216
|
+
}
|
|
217
|
+
/** @internal called by ui-router code */
|
|
218
|
+
traceViewServiceUIViewEvent(event, viewData) {
|
|
219
|
+
if (!this.enabled(Category.VIEWCONFIG)) return;
|
|
220
|
+
safeConsole.log(`VIEWCONFIG: ${event} ${uiViewString(viewData)}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* The [[Trace]] singleton
|
|
225
|
+
*
|
|
226
|
+
* #### Example:
|
|
227
|
+
* ```js
|
|
228
|
+
* import {trace} from "@uirouter/core/index";
|
|
229
|
+
* trace.enable(1, 5);
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
export const trace = new Trace();
|