@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.
Files changed (79) hide show
  1. package/dist/angular-ts.esm.js +1 -1
  2. package/dist/angular-ts.umd.js +1 -1
  3. package/package.json +4 -1
  4. package/src/exts/messages.md +30 -30
  5. package/src/index.js +1 -0
  6. package/src/public.js +2 -0
  7. package/src/router/adapter/directives/stateDirectives.js +695 -0
  8. package/src/router/adapter/directives/viewDirective.js +514 -0
  9. package/src/router/adapter/injectables.js +314 -0
  10. package/src/router/adapter/interface.js +1 -0
  11. package/src/router/adapter/locationServices.js +84 -0
  12. package/src/router/adapter/services.js +126 -0
  13. package/src/router/adapter/stateFilters.js +43 -0
  14. package/src/router/adapter/stateProvider.js +137 -0
  15. package/src/router/adapter/statebuilders/onEnterExitRetain.js +30 -0
  16. package/src/router/adapter/statebuilders/views.js +146 -0
  17. package/src/router/adapter/templateFactory.js +218 -0
  18. package/src/router/adapter/viewScroll.js +31 -0
  19. package/src/router/core/common/common.js +496 -0
  20. package/src/router/core/common/coreservices.js +15 -0
  21. package/src/router/core/common/glob.js +75 -0
  22. package/src/router/core/common/hof.js +194 -0
  23. package/src/router/core/common/predicates.js +44 -0
  24. package/src/router/core/common/queue.js +41 -0
  25. package/src/router/core/common/safeConsole.js +38 -0
  26. package/src/router/core/common/strings.js +141 -0
  27. package/src/router/core/common/trace.js +232 -0
  28. package/src/router/core/globals.js +29 -0
  29. package/src/router/core/hooks/coreResolvables.js +33 -0
  30. package/src/router/core/hooks/ignoredTransition.js +25 -0
  31. package/src/router/core/hooks/invalidTransition.js +14 -0
  32. package/src/router/core/hooks/lazyLoad.js +102 -0
  33. package/src/router/core/hooks/onEnterExitRetain.js +55 -0
  34. package/src/router/core/hooks/redirectTo.js +36 -0
  35. package/src/router/core/hooks/resolve.js +57 -0
  36. package/src/router/core/hooks/updateGlobals.js +30 -0
  37. package/src/router/core/hooks/url.js +25 -0
  38. package/src/router/core/hooks/views.js +39 -0
  39. package/src/router/core/interface.js +3 -0
  40. package/src/router/core/params/README.md +8 -0
  41. package/src/router/core/params/param.js +232 -0
  42. package/src/router/core/params/paramType.js +139 -0
  43. package/src/router/core/params/paramTypes.js +163 -0
  44. package/src/router/core/params/stateParams.js +35 -0
  45. package/src/router/core/path/pathNode.js +77 -0
  46. package/src/router/core/path/pathUtils.js +199 -0
  47. package/src/router/core/resolve/interface.js +10 -0
  48. package/src/router/core/resolve/resolvable.js +124 -0
  49. package/src/router/core/resolve/resolveContext.js +211 -0
  50. package/src/router/core/router.js +203 -0
  51. package/src/router/core/state/README.md +21 -0
  52. package/src/router/core/state/stateBuilder.js +332 -0
  53. package/src/router/core/state/stateMatcher.js +65 -0
  54. package/src/router/core/state/stateObject.js +117 -0
  55. package/src/router/core/state/stateQueueManager.js +89 -0
  56. package/src/router/core/state/stateRegistry.js +175 -0
  57. package/src/router/core/state/stateService.js +592 -0
  58. package/src/router/core/state/targetState.js +159 -0
  59. package/src/router/core/transition/hookBuilder.js +127 -0
  60. package/src/router/core/transition/hookRegistry.js +175 -0
  61. package/src/router/core/transition/interface.js +14 -0
  62. package/src/router/core/transition/rejectFactory.js +122 -0
  63. package/src/router/core/transition/transition.js +739 -0
  64. package/src/router/core/transition/transitionEventType.js +27 -0
  65. package/src/router/core/transition/transitionHook.js +199 -0
  66. package/src/router/core/transition/transitionService.js +311 -0
  67. package/src/router/core/url/interface.js +1 -0
  68. package/src/router/core/url/urlConfig.js +165 -0
  69. package/src/router/core/url/urlMatcher.js +548 -0
  70. package/src/router/core/url/urlMatcherFactory.js +123 -0
  71. package/src/router/core/url/urlRouter.js +115 -0
  72. package/src/router/core/url/urlRule.js +202 -0
  73. package/src/router/core/url/urlRules.js +348 -0
  74. package/src/router/core/url/urlService.js +268 -0
  75. package/src/router/core/view/interface.js +1 -0
  76. package/src/router/core/view/view.js +312 -0
  77. package/src/router/router.js +58 -0
  78. package/test/module-test.html +6 -2
  79. package/test/module-test.js +0 -0
@@ -0,0 +1,203 @@
1
+ import { UrlMatcherFactory } from "./url/urlMatcherFactory";
2
+ import { UrlRouter } from "./url/urlRouter";
3
+ import { TransitionService } from "./transition/transitionService";
4
+ import { ViewService } from "./view/view";
5
+ import { StateRegistry } from "./state/stateRegistry";
6
+ import { StateService } from "./state/stateService";
7
+ import { UIRouterGlobals } from "./globals";
8
+ import { removeFrom } from "./common/common";
9
+ import { isFunction } from "./common/predicates";
10
+ import { UrlService } from "./url/urlService";
11
+ import { trace } from "./common/trace";
12
+ import { makeStub } from "./common/coreservices";
13
+
14
+ /** @internal
15
+ * @type {number}
16
+ */
17
+ let _routerInstance = 0;
18
+
19
+ /** @internal
20
+ * @type {(keyof LocationServices)[]}
21
+ */
22
+ const locSvcFns = ["url", "path", "search", "hash", "onChange"];
23
+ /** @internal
24
+ * @type {(keyof LocationConfig)[]}
25
+ */
26
+ const locCfgFns = [
27
+ "port",
28
+ "protocol",
29
+ "host",
30
+ "baseHref",
31
+ "html5Mode",
32
+ "hashPrefix",
33
+ ];
34
+ /** @internal
35
+ * @type {any}
36
+ */
37
+ const locationServiceStub = makeStub("LocationServices", locSvcFns);
38
+ /** @internal
39
+ * @type {any}
40
+ */
41
+ const locationConfigStub = makeStub("LocationConfig", locCfgFns);
42
+
43
+ /**
44
+ * An instance of UI-Router.
45
+ *
46
+ * This object contains references to service APIs which define your application's routing behavior.
47
+ */
48
+ export class UIRouter {
49
+ /**
50
+ * Creates a new `UIRouter` object
51
+ *
52
+ * @param locationService a [[LocationServices]] implementation
53
+ * @param locationConfig a [[LocationConfig]] implementation
54
+ * @internal
55
+ */
56
+ constructor(
57
+ locationService = locationServiceStub,
58
+ locationConfig = locationConfigStub,
59
+ ) {
60
+ this.locationService = locationService;
61
+ this.locationConfig = locationConfig;
62
+ /** @internal */ this.$id = _routerInstance++;
63
+ /** @internal */ this._disposed = false;
64
+ /** @internal */ this._disposables = [];
65
+ /** Enable/disable tracing to the javascript console */
66
+ this.trace = trace;
67
+ /** Provides services related to ui-view synchronization */
68
+ this.viewService = new ViewService(this);
69
+ /** An object that contains global router state, such as the current state and params */
70
+ this.globals = new UIRouterGlobals();
71
+ /** A service that exposes global Transition Hooks */
72
+ this.transitionService = new TransitionService(this);
73
+ /**
74
+ * Deprecated for public use. Use [[urlService]] instead.
75
+ * @deprecated Use [[urlService]] instead
76
+ */
77
+ this.urlMatcherFactory = new UrlMatcherFactory(this);
78
+ /**
79
+ * Deprecated for public use. Use [[urlService]] instead.
80
+ * @deprecated Use [[urlService]] instead
81
+ */
82
+ this.urlRouter = new UrlRouter(this);
83
+ /** Provides services related to the URL */
84
+ this.urlService = new UrlService(this);
85
+ /** Provides a registry for states, and related registration services */
86
+ this.stateRegistry = new StateRegistry(this);
87
+ /** Provides services related to states */
88
+ this.stateService = new StateService(this);
89
+ /** @internal plugin instances are registered here */
90
+ this._plugins = {};
91
+ this.viewService._pluginapi._rootViewContext(this.stateRegistry.root());
92
+ this.globals.$current = this.stateRegistry.root();
93
+ this.globals.current = this.globals.$current.self;
94
+ this.disposable(this.globals);
95
+ this.disposable(this.stateService);
96
+ this.disposable(this.stateRegistry);
97
+ this.disposable(this.transitionService);
98
+ this.disposable(this.urlService);
99
+ this.disposable(locationService);
100
+ this.disposable(locationConfig);
101
+ }
102
+
103
+ /**
104
+ * Registers an object to be notified when the router is disposed
105
+ * @param {Disposable} disposable
106
+ * @returns {void}
107
+ */
108
+ disposable(disposable) {
109
+ this._disposables.push(disposable);
110
+ }
111
+ /**
112
+ * Disposes this router instance
113
+ *
114
+ * When called, clears resources retained by the router by calling `dispose(this)` on all
115
+ * registered [[disposable]] objects.
116
+ *
117
+ * Or, if a `disposable` object is provided, calls `dispose(this)` on that object only.
118
+ *
119
+ * @internal
120
+ * @param disposable (optional) the disposable to dispose
121
+ */
122
+ dispose(disposable) {
123
+ if (disposable && isFunction(disposable.dispose)) {
124
+ disposable.dispose(this);
125
+ return undefined;
126
+ }
127
+ this._disposed = true;
128
+ this._disposables.slice().forEach((d) => {
129
+ try {
130
+ typeof d.dispose === "function" && d.dispose(this);
131
+ removeFrom(this._disposables, d);
132
+ } catch (ignored) {}
133
+ });
134
+ }
135
+
136
+ /**
137
+ * Adds a plugin to UI-Router
138
+ *
139
+ * This method adds a UI-Router Plugin.
140
+ * A plugin can enhance or change UI-Router behavior using any public API.
141
+ *
142
+ * #### Example:
143
+ * ```js
144
+ * import { MyCoolPlugin } from "ui-router-cool-plugin";
145
+ *
146
+ * var plugin = router.addPlugin(MyCoolPlugin);
147
+ * ```
148
+ *
149
+ * ### Plugin authoring
150
+ *
151
+ * A plugin is simply a class (or constructor function) which accepts a [[UIRouter]] instance and (optionally) an options object.
152
+ *
153
+ * The plugin can implement its functionality using any of the public APIs of [[UIRouter]].
154
+ * For example, it may configure router options or add a Transition Hook.
155
+ *
156
+ * The plugin can then be published as a separate module.
157
+ *
158
+ * #### Example:
159
+ * ```js
160
+ * export class MyAuthPlugin implements UIRouterPlugin {
161
+ * constructor(router: UIRouter, options: any) {
162
+ * this.name = "MyAuthPlugin";
163
+ * let $transitions = router.transitionService;
164
+ * let $state = router.stateService;
165
+ *
166
+ * let authCriteria = {
167
+ * to: (state) => state.data && state.data.requiresAuth
168
+ * };
169
+ *
170
+ * function authHook(transition: Transition) {
171
+ * let authService = transition.injector().get('AuthService');
172
+ * if (!authService.isAuthenticated()) {
173
+ * return $state.target('login');
174
+ * }
175
+ * }
176
+ *
177
+ * $transitions.onStart(authCriteria, authHook);
178
+ * }
179
+ * }
180
+ * ```
181
+ *
182
+ * @param plugin one of:
183
+ * - a plugin class which implements [[UIRouterPlugin]]
184
+ * - a constructor function for a [[UIRouterPlugin]] which accepts a [[UIRouter]] instance
185
+ * - a factory function which accepts a [[UIRouter]] instance and returns a [[UIRouterPlugin]] instance
186
+ * @param options options to pass to the plugin class/factory
187
+ * @returns the registered plugin instance
188
+ */
189
+ plugin(plugin, options = {}) {
190
+ const pluginInstance = new plugin(this, options);
191
+ if (!pluginInstance.name)
192
+ throw new Error(
193
+ "Required property `name` missing on plugin: " + pluginInstance,
194
+ );
195
+ this._disposables.push(pluginInstance);
196
+ return (this._plugins[pluginInstance.name] = pluginInstance);
197
+ }
198
+ getPlugin(pluginName) {
199
+ return pluginName
200
+ ? this._plugins[pluginName]
201
+ : Object.values(this._plugins);
202
+ }
203
+ }
@@ -0,0 +1,21 @@
1
+ /\*\*
2
+
3
+ - # The state subsystem
4
+ -
5
+ - This subsystem implements the ui-router state tree
6
+ -
7
+ - - The [[StateService]] has state-related service methods such as:
8
+ - - [[StateService.get]]: Get a registered [[StateDeclaration]] object
9
+ - - [[StateService.go]]: Transition from the current state to a new state
10
+ - - [[StateService.reload]]: Reload the current state
11
+ - - [[StateService.target]]: Get a [[TargetState]] (useful when redirecting from a Transition Hook)
12
+ - - [[StateService.onInvalid]]: Register a callback for when a transition to an invalid state is started
13
+ - - [[StateService.defaultErrorHandler]]: Register a global callback for when a transition errors
14
+ - - The [[StateDeclaration]] interface defines the shape of a state declaration
15
+ - - The [[StateRegistry]] contains all the registered states
16
+ - - States can be added/removed using the [[StateRegistry.register]] and [[StateRegistry.deregister]]
17
+ - - Note: Bootstrap state registration differs by front-end framework.
18
+ - - Get notified of state registration/deregistration using [[StateRegistry.onStatesChanged]].
19
+ -
20
+ - @packageDocumentation
21
+ \*/
@@ -0,0 +1,332 @@
1
+ import {
2
+ applyPairs,
3
+ extend,
4
+ identity,
5
+ inherit,
6
+ mapObj,
7
+ noop,
8
+ omit,
9
+ tail,
10
+ copy,
11
+ } from "../common/common";
12
+ import { isArray, isDefined, isFunction, isString } from "../common/predicates";
13
+ import { stringify } from "../common/strings";
14
+ import { is, pattern, pipe, prop, val } from "../common/hof";
15
+ import { Resolvable } from "../resolve/resolvable";
16
+ import { services } from "../common/coreservices";
17
+ const parseUrl = (url) => {
18
+ if (!isString(url)) return false;
19
+ const root = url.charAt(0) === "^";
20
+ return { val: root ? url.substring(1) : url, root };
21
+ };
22
+ function nameBuilder(state) {
23
+ return state.name;
24
+ }
25
+ function selfBuilder(state) {
26
+ state.self.$$state = () => state;
27
+ return state.self;
28
+ }
29
+ function dataBuilder(state) {
30
+ if (state.parent && state.parent.data) {
31
+ state.data = state.self.data = inherit(state.parent.data, state.data);
32
+ }
33
+ return state.data;
34
+ }
35
+ const getUrlBuilder = ($urlMatcherFactoryProvider, root) =>
36
+ function urlBuilder(stateObject) {
37
+ let stateDec = stateObject.self;
38
+ // For future states, i.e., states whose name ends with `.**`,
39
+ // match anything that starts with the url prefix
40
+ if (
41
+ stateDec &&
42
+ stateDec.url &&
43
+ stateDec.name &&
44
+ stateDec.name.match(/\.\*\*$/)
45
+ ) {
46
+ const newStateDec = {};
47
+ copy(stateDec, newStateDec);
48
+ newStateDec.url += "{remainder:any}"; // match any path (.*)
49
+ stateDec = newStateDec;
50
+ }
51
+ const parent = stateObject.parent;
52
+ const parsed = parseUrl(stateDec.url);
53
+ const url = !parsed
54
+ ? stateDec.url
55
+ : $urlMatcherFactoryProvider.compile(parsed.val, { state: stateDec });
56
+ if (!url) return null;
57
+ if (!$urlMatcherFactoryProvider.isMatcher(url))
58
+ throw new Error(`Invalid url '${url}' in state '${stateObject}'`);
59
+ return parsed && parsed.root
60
+ ? url
61
+ : ((parent && parent.navigable) || root()).url.append(url);
62
+ };
63
+ const getNavigableBuilder = (isRoot) =>
64
+ function navigableBuilder(state) {
65
+ return !isRoot(state) && state.url
66
+ ? state
67
+ : state.parent
68
+ ? state.parent.navigable
69
+ : null;
70
+ };
71
+ const getParamsBuilder = (paramFactory) =>
72
+ function paramsBuilder(state) {
73
+ const makeConfigParam = (config, id) =>
74
+ paramFactory.fromConfig(id, null, state.self);
75
+ const urlParams =
76
+ (state.url && state.url.parameters({ inherit: false })) || [];
77
+ const nonUrlParams = Object.values(
78
+ mapObj(
79
+ omit(state.params || {}, urlParams.map(prop("id"))),
80
+ makeConfigParam,
81
+ ),
82
+ );
83
+ return urlParams
84
+ .concat(nonUrlParams)
85
+ .map((p) => [p.id, p])
86
+ .reduce(applyPairs, {});
87
+ };
88
+ function pathBuilder(state) {
89
+ return state.parent ? state.parent.path.concat(state) : /*root*/ [state];
90
+ }
91
+ function includesBuilder(state) {
92
+ const includes = state.parent ? extend({}, state.parent.includes) : {};
93
+ includes[state.name] = true;
94
+ return includes;
95
+ }
96
+ /**
97
+ * This is a [[StateBuilder.builder]] function for the `resolve:` block on a [[StateDeclaration]].
98
+ *
99
+ * When the [[StateBuilder]] builds a [[StateObject]] object from a raw [[StateDeclaration]], this builder
100
+ * validates the `resolve` property and converts it to a [[Resolvable]] array.
101
+ *
102
+ * resolve: input value can be:
103
+ *
104
+ * {
105
+ * // analyzed but not injected
106
+ * myFooResolve: function() { return "myFooData"; },
107
+ *
108
+ * // function.toString() parsed, "DependencyName" dep as string (not min-safe)
109
+ * myBarResolve: function(DependencyName) { return DependencyName.fetchSomethingAsPromise() },
110
+ *
111
+ * // Array split; "DependencyName" dep as string
112
+ * myBazResolve: [ "DependencyName", function(dep) { return dep.fetchSomethingAsPromise() },
113
+ *
114
+ * // Array split; DependencyType dep as token (compared using ===)
115
+ * myQuxResolve: [ DependencyType, function(dep) { return dep.fetchSometingAsPromise() },
116
+ *
117
+ * // val.$inject used as deps
118
+ * // where:
119
+ * // corgeResolve.$inject = ["DependencyName"];
120
+ * // function corgeResolve(dep) { dep.fetchSometingAsPromise() }
121
+ * // then "DependencyName" dep as string
122
+ * myCorgeResolve: corgeResolve,
123
+ *
124
+ * // inject service by name
125
+ * // When a string is found, desugar creating a resolve that injects the named service
126
+ * myGraultResolve: "SomeService"
127
+ * }
128
+ *
129
+ * or:
130
+ *
131
+ * [
132
+ * new Resolvable("myFooResolve", function() { return "myFooData" }),
133
+ * new Resolvable("myBarResolve", function(dep) { return dep.fetchSomethingAsPromise() }, [ "DependencyName" ]),
134
+ * { provide: "myBazResolve", useFactory: function(dep) { dep.fetchSomethingAsPromise() }, deps: [ "DependencyName" ] }
135
+ * ]
136
+ */
137
+ export function resolvablesBuilder(state) {
138
+ /** convert resolve: {} and resolvePolicy: {} objects to an array of tuples */
139
+ const objects2Tuples = (resolveObj, resolvePolicies) =>
140
+ Object.keys(resolveObj || {}).map((token) => ({
141
+ token,
142
+ val: resolveObj[token],
143
+ deps: undefined,
144
+ policy: resolvePolicies[token],
145
+ }));
146
+ /** fetch DI annotations from a function or ng1-style array */
147
+ const annotate = (fn) => {
148
+ const $injector = services.$injector;
149
+ // ng1 doesn't have an $injector until runtime.
150
+ // If the $injector doesn't exist, use "deferred" literal as a
151
+ // marker indicating they should be annotated when runtime starts
152
+ return (
153
+ fn["$inject"] ||
154
+ ($injector && $injector.annotate(fn, $injector.strictDi)) ||
155
+ "deferred"
156
+ );
157
+ };
158
+ /** true if the object has both `token` and `resolveFn`, and is probably a [[ResolveLiteral]] */
159
+ const isResolveLiteral = (obj) => !!(obj.token && obj.resolveFn);
160
+ /** true if the object looks like a provide literal, or a ng2 Provider */
161
+ const isLikeNg2Provider = (obj) =>
162
+ !!(
163
+ (obj.provide || obj.token) &&
164
+ (obj.useValue || obj.useFactory || obj.useExisting || obj.useClass)
165
+ );
166
+ /** true if the object looks like a tuple from obj2Tuples */
167
+ const isTupleFromObj = (obj) =>
168
+ !!(
169
+ obj &&
170
+ obj.val &&
171
+ (isString(obj.val) || isArray(obj.val) || isFunction(obj.val))
172
+ );
173
+ /** extracts the token from a Provider or provide literal */
174
+ const getToken = (p) => p.provide || p.token;
175
+ // prettier-ignore: Given a literal resolve or provider object, returns a Resolvable
176
+ const literal2Resolvable = pattern([
177
+ [
178
+ prop("resolveFn"),
179
+ (p) => new Resolvable(getToken(p), p.resolveFn, p.deps, p.policy),
180
+ ],
181
+ [
182
+ prop("useFactory"),
183
+ (p) =>
184
+ new Resolvable(
185
+ getToken(p),
186
+ p.useFactory,
187
+ p.deps || p.dependencies,
188
+ p.policy,
189
+ ),
190
+ ],
191
+ [
192
+ prop("useClass"),
193
+ (p) => new Resolvable(getToken(p), () => new p.useClass(), [], p.policy),
194
+ ],
195
+ [
196
+ prop("useValue"),
197
+ (p) =>
198
+ new Resolvable(getToken(p), () => p.useValue, [], p.policy, p.useValue),
199
+ ],
200
+ [
201
+ prop("useExisting"),
202
+ (p) => new Resolvable(getToken(p), identity, [p.useExisting], p.policy),
203
+ ],
204
+ ]);
205
+ // prettier-ignore
206
+ const tuple2Resolvable = pattern([
207
+ [pipe(prop('val'), isString), (tuple) => new Resolvable(tuple.token, identity, [tuple.val], tuple.policy)],
208
+ [pipe(prop('val'), isArray), (tuple) => new Resolvable(tuple.token, tail(tuple.val), tuple.val.slice(0, -1), tuple.policy)],
209
+ [pipe(prop('val'), isFunction), (tuple) => new Resolvable(tuple.token, tuple.val, annotate(tuple.val), tuple.policy)],
210
+ ]);
211
+ // prettier-ignore
212
+ const item2Resolvable = pattern([
213
+ [is(Resolvable), (r) => r],
214
+ [isResolveLiteral, literal2Resolvable],
215
+ [isLikeNg2Provider, literal2Resolvable],
216
+ [isTupleFromObj, tuple2Resolvable],
217
+ [val(true), (obj) => { throw new Error('Invalid resolve value: ' + stringify(obj)); },],
218
+ ]);
219
+ // If resolveBlock is already an array, use it as-is.
220
+ // Otherwise, assume it's an object and convert to an Array of tuples
221
+ const decl = state.resolve;
222
+ const items = isArray(decl)
223
+ ? decl
224
+ : objects2Tuples(decl, state.resolvePolicy || {});
225
+ return items.map(item2Resolvable);
226
+ }
227
+ /**
228
+ * A internal global service
229
+ *
230
+ * StateBuilder is a factory for the internal [[StateObject]] objects.
231
+ *
232
+ * When you register a state with the [[StateRegistry]], you register a plain old javascript object which
233
+ * conforms to the [[StateDeclaration]] interface. This factory takes that object and builds the corresponding
234
+ * [[StateObject]] object, which has an API and is used internally.
235
+ *
236
+ * Custom properties or API may be added to the internal [[StateObject]] object by registering a decorator function
237
+ * using the [[builder]] method.
238
+ */
239
+ export class StateBuilder {
240
+ constructor(matcher, urlMatcherFactory) {
241
+ this.matcher = matcher;
242
+ const self = this;
243
+ const root = () => matcher.find("");
244
+ const isRoot = (state) => state.name === "";
245
+ function parentBuilder(state) {
246
+ if (isRoot(state)) return null;
247
+ return matcher.find(self.parentName(state)) || root();
248
+ }
249
+ this.builders = {
250
+ name: [nameBuilder],
251
+ self: [selfBuilder],
252
+ parent: [parentBuilder],
253
+ data: [dataBuilder],
254
+ // Build a URLMatcher if necessary, either via a relative or absolute URL
255
+ url: [getUrlBuilder(urlMatcherFactory, root)],
256
+ // Keep track of the closest ancestor state that has a URL (i.e. is navigable)
257
+ navigable: [getNavigableBuilder(isRoot)],
258
+ params: [getParamsBuilder(urlMatcherFactory.paramFactory)],
259
+ // Each framework-specific ui-router implementation should define its own `views` builder
260
+ // e.g., src/ng1/statebuilders/views.ts
261
+ views: [],
262
+ // Keep a full path from the root down to this state as this is needed for state activation.
263
+ path: [pathBuilder],
264
+ // Speed up $state.includes() as it's used a lot
265
+ includes: [includesBuilder],
266
+ resolvables: [resolvablesBuilder],
267
+ };
268
+ }
269
+ builder(name, fn) {
270
+ const builders = this.builders;
271
+ const array = builders[name] || [];
272
+ // Backwards compat: if only one builder exists, return it, else return whole arary.
273
+ if (isString(name) && !isDefined(fn))
274
+ return array.length > 1 ? array : array[0];
275
+ if (!isString(name) || !isFunction(fn)) return;
276
+ builders[name] = array;
277
+ builders[name].push(fn);
278
+ return () => builders[name].splice(builders[name].indexOf(fn, 1)) && null;
279
+ }
280
+ /**
281
+ * Builds all of the properties on an essentially blank State object, returning a State object which has all its
282
+ * properties and API built.
283
+ *
284
+ * @param state an uninitialized State object
285
+ * @returns the built State object
286
+ */
287
+ build(state) {
288
+ const { matcher, builders } = this;
289
+ const parent = this.parentName(state);
290
+ if (parent && !matcher.find(parent, undefined, false)) {
291
+ return null;
292
+ }
293
+ for (const key in builders) {
294
+ if (!Object.prototype.hasOwnProperty.call(builders, key)) continue;
295
+ const chain = builders[key].reduce(
296
+ (parentFn, step) => (_state) => step(_state, parentFn),
297
+ noop,
298
+ );
299
+ state[key] = chain(state);
300
+ }
301
+ return state;
302
+ }
303
+ parentName(state) {
304
+ // name = 'foo.bar.baz.**'
305
+ const name = state.name || "";
306
+ // segments = ['foo', 'bar', 'baz', '.**']
307
+ const segments = name.split(".");
308
+ // segments = ['foo', 'bar', 'baz']
309
+ const lastSegment = segments.pop();
310
+ // segments = ['foo', 'bar'] (ignore .** segment for future states)
311
+ if (lastSegment === "**") segments.pop();
312
+ if (segments.length) {
313
+ if (state.parent) {
314
+ throw new Error(
315
+ `States that specify the 'parent:' property should not have a '.' in their name (${name})`,
316
+ );
317
+ }
318
+ // 'foo.bar'
319
+ return segments.join(".");
320
+ }
321
+ if (!state.parent) return "";
322
+ return isString(state.parent) ? state.parent : state.parent.name;
323
+ }
324
+ name(state) {
325
+ const name = state.name;
326
+ if (name.indexOf(".") !== -1 || !state.parent) return name;
327
+ const parentName = isString(state.parent)
328
+ ? state.parent
329
+ : state.parent.name;
330
+ return parentName ? parentName + "." + name : name;
331
+ }
332
+ }
@@ -0,0 +1,65 @@
1
+ import { isString } from "../common/predicates";
2
+ import { safeConsole } from "../common/safeConsole";
3
+ export class StateMatcher {
4
+ constructor(_states) {
5
+ this._states = _states;
6
+ }
7
+ isRelative(stateName) {
8
+ stateName = stateName || "";
9
+ return stateName.indexOf(".") === 0 || stateName.indexOf("^") === 0;
10
+ }
11
+ find(stateOrName, base, matchGlob = true) {
12
+ if (!stateOrName && stateOrName !== "") return undefined;
13
+ const isStr = isString(stateOrName);
14
+ let name = isStr ? stateOrName : stateOrName.name;
15
+ if (this.isRelative(name)) name = this.resolvePath(name, base);
16
+ const state = this._states[name];
17
+ if (
18
+ state &&
19
+ (isStr ||
20
+ (!isStr && (state === stateOrName || state.self === stateOrName)))
21
+ ) {
22
+ return state;
23
+ } else if (isStr && matchGlob) {
24
+ const _states = Object.values(this._states);
25
+ const matches = _states.filter(
26
+ (_state) =>
27
+ _state.__stateObjectCache.nameGlob &&
28
+ _state.__stateObjectCache.nameGlob.matches(name),
29
+ );
30
+ if (matches.length > 1) {
31
+ safeConsole.error(
32
+ `stateMatcher.find: Found multiple matches for ${name} using glob: `,
33
+ matches.map((match) => match.name),
34
+ );
35
+ }
36
+ return matches[0];
37
+ }
38
+ return undefined;
39
+ }
40
+ resolvePath(name, base) {
41
+ if (!base) throw new Error(`No reference point given for path '${name}'`);
42
+ const baseState = this.find(base);
43
+ const splitName = name.split(".");
44
+ const pathLength = splitName.length;
45
+ let i = 0,
46
+ current = baseState;
47
+ for (; i < pathLength; i++) {
48
+ if (splitName[i] === "" && i === 0) {
49
+ current = baseState;
50
+ continue;
51
+ }
52
+ if (splitName[i] === "^") {
53
+ if (!current.parent)
54
+ throw new Error(
55
+ `Path '${name}' not valid for state '${baseState.name}'`,
56
+ );
57
+ current = current.parent;
58
+ continue;
59
+ }
60
+ break;
61
+ }
62
+ const relName = splitName.slice(i).join(".");
63
+ return current.name + (current.name && relName ? "." : "") + relName;
64
+ }
65
+ }