Skip to content

Commit 2573cec

Browse files
refactor(StateBuilder): Always manage statebuilder functions as arrays
1 parent ed1e6a5 commit 2573cec

File tree

1 file changed

+25
-46
lines changed

1 file changed

+25
-46
lines changed

src/state/stateBuilder.ts

+25-46
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,20 @@ export function StateBuilder(root, matcher, $urlMatcherFactoryProvider) {
1313

1414
let self = this, builders = {
1515

16-
parent: function(state) {
16+
parent: [function(state) {
1717
if (state === root()) return null;
1818
return matcher.find(self.parentName(state)) || root();
19-
},
19+
}],
2020

21-
data: function(state) {
21+
data: [function(state) {
2222
if (state.parent && state.parent.data) {
2323
state.data = state.self.data = extend({}, state.parent.data, state.data);
2424
}
2525
return state.data;
26-
},
26+
}],
2727

2828
// Build a URLMatcher if necessary, either via a relative or absolute URL
29-
url: function(state) {
29+
url: [function(state) {
3030
const parsed = parseUrl(state.url), parent = state.parent;
3131
const url = !parsed ? state.url : $urlMatcherFactoryProvider.compile(parsed.val, {
3232
params: state.params || {},
@@ -39,26 +39,26 @@ export function StateBuilder(root, matcher, $urlMatcherFactoryProvider) {
3939
if (!url) return null;
4040
if (!$urlMatcherFactoryProvider.isMatcher(url)) throw new Error(`Invalid url '${url}' in state '${state}'`);
4141
return (parsed && parsed.root) ? url : ((parent && parent.navigable) || root()).url.append(url);
42-
},
42+
}],
4343

4444
// Keep track of the closest ancestor state that has a URL (i.e. is navigable)
45-
navigable: function(state) {
45+
navigable: [function(state) {
4646
return (state !== root()) && state.url ? state : (state.parent ? state.parent.navigable : null);
47-
},
47+
}],
4848

49-
params: function(state): { [key: string]: Param } {
49+
params: [function(state): { [key: string]: Param } {
5050
const makeConfigParam = (config: any, id: string) => Param.fromConfig(id, null, config);
5151
let urlParams: Param[] = (state.url && state.url.parameters({ inherit: false })) || [];
5252
let nonUrlParams: Param[] = values(map(omit(state.params || {}, urlParams.map(prop('id'))), makeConfigParam));
5353
return urlParams.concat(nonUrlParams).map(p => [p.id, p]).reduce(applyPairs, {});
54-
},
54+
}],
5555

5656
// If there is no explicit multi-view configuration, make one up so we don't have
5757
// to handle both cases in the view directive later. Note that having an explicit
5858
// 'views' property will mean the default unnamed view properties are ignored. This
5959
// is also a good time to resolve view names to absolute names, so everything is a
6060
// straight lookup at link time.
61-
views: function(state) {
61+
views: [function(state) {
6262
let views = {},
6363
tplKeys = ['templateProvider', 'templateUrl', 'template', 'notify', 'async'],
6464
ctrlKeys = ['controller', 'controllerProvider', 'controllerAs'];
@@ -73,52 +73,31 @@ export function StateBuilder(root, matcher, $urlMatcherFactoryProvider) {
7373
if (Object.keys(config).length > 0) views[name] = config;
7474
});
7575
return views;
76-
},
76+
}],
7777

7878
// Keep a full path from the root down to this state as this is needed for state activation.
79-
path: function(state) {
79+
path: [function(state) {
8080
return state.parent ? state.parent.path.concat(state) : /*root*/ [state];
81-
},
81+
}],
8282

8383
// Speed up $state.includes() as it's used a lot
84-
includes: function(state) {
84+
includes: [function(state) {
8585
let includes = state.parent ? extend({}, state.parent.includes) : {};
8686
includes[state.name] = true;
8787
return includes;
88-
}
88+
}]
8989
};
9090

9191
extend(this, {
92-
builder: function(_name, _func) {
93-
if (isString(_name) && !isDefined(_func)) return builders[_name];
94-
if (!isFunction(_func) || !isString(_name)) return;
95-
96-
function remove(name, func) {
97-
if (!builders[name].length) {
98-
delete builders[name];
99-
return;
100-
}
101-
builders[name].splice(builders[name].indexOf(func, 1));
102-
103-
if (builders[name].length === 1) {
104-
builders[name] = builders[name][0];
105-
}
106-
}
107-
108-
function add(name, func) {
109-
if (!builders[name]) {
110-
builders[name] = func;
111-
return function() { remove(name, func); };
112-
}
113-
114-
if (!isArray(builders[name])) {
115-
builders[name] = [builders[name]];
116-
}
117-
builders[name].push(func);
118-
return function() { remove(name, func); };
119-
}
120-
121-
return add(_name, _func);
92+
builder: function(name, fn) {
93+
let array: Function[] = builders[name] || [];
94+
// Backwards compat: if only one builder exists, return it, else return whole arary.
95+
if (isString(name) && !isDefined(fn)) return array.length > 1 ? array : array[0];
96+
if (!isString(name) || !isFunction(fn)) return;
97+
98+
builders[name] = array;
99+
builders[name].push(fn);
100+
return () => builders[name].splice(builders[name].indexOf(fn, 1))
122101
},
123102

124103
build: function(state) {

0 commit comments

Comments
 (0)