Skip to content

Commit db71947

Browse files
refactor(Transition): Finish refactor APIs to use Path and TargetState
- Transition factory and constructor now take a TargetState - Split invalid target logic between TargetState.exists() and Transition.valid() - Cannot create a Transition to a state which doesn't exist - Can create (but cannot run) a Transition object to an abstract state, or with invalid params feat(ParamValues): now uses constructor function which takes a Path. - It exposes the path as ES5 $$path getter - It exposes $byState() function to retrieve params per refactor(Transition): Moved tree changes functionality to PathFactory refactor($state): Moved inheritParams functionality to PathFactory
1 parent ffd649d commit db71947

21 files changed

+415
-286
lines changed

src/params/interface.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// Without importing something, TSC complains that this file isn't a module
2-
import {noop} from "../common/common";
1+
import ParamValues from "./paramValues";
32

43
export interface IRawParams {
5-
[key: string]: any
6-
}
4+
[key: string]: any
5+
}
6+
export type IParamsOrArray = (IRawParams|IRawParams[]|ParamValues);

src/params/paramValues.ts

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,32 @@ import {IParamsPath, IParamsNode} from "../path/interface"
22
import {IState} from "../state/interface"
33
import {IRawParams} from "../params/interface"
44

5-
import {extend, inherit} from "../common/common"
6-
/**
7-
* This class calculates parameter values from a IParamsPath. The param values for the path
8-
* are available directly on the resulting object. Param values for a specific state in the
9-
* path may be retrieved using the $byState(stateName) function.
5+
import {extend, inherit, find, pairs, prop, zipObject} from "../common/common"
6+
/**
7+
* This class closes over a Path and encapsulates the parameter values from the Path's Nodes.
8+
* The param values for the path are flattened and copied to the resulting ParamValues object.
9+
* Param values for a specific state are exposed with the $byState(stateName) function.
1010
*/
11+
const stateNameMatches = (stateName: string) => (node) => node.state.name === stateName;
12+
1113
export default class ParamValues implements IRawParams {
1214
[key: string]: any
13-
14-
constructor(private _byState) {}
15-
16-
$byState(stateName: string) {
17-
return this._byState[stateName];
15+
private $$path: IParamsPath;
16+
17+
18+
constructor($$path: IParamsPath) {
19+
Object.defineProperty(this, "$$path", { value: $$path });
20+
$$path.nodes().reduce((memo, node) => extend(memo, node.ownParams), this);
1821
}
19-
20-
static paramsByState(path: IParamsPath): IRawParams {
21-
const byState = (memo, node: IParamsNode) => {
22-
memo[node.state.name] = node.ownParams;
23-
return memo;
24-
};
25-
return path.nodes().reduce(byState, {});
22+
23+
/** Gets the param values for a given state (by state name) */
24+
$byState(stateName: string) {
25+
let found = find(this.$$path.nodes(), stateNameMatches(stateName));
26+
return found && found.ownParams;
2627
}
2728

28-
static fromPath(path: IParamsPath): ParamValues {
29-
let $byState = ParamValues.paramsByState(path);
30-
let params = inherit(new ParamValues($byState), {});
31-
const extendParams = (memo, node: IParamsNode) => extend(memo, node.ownParams);
32-
return path.nodes().reduce(extendParams, params);
29+
/** Returns a new ParamValues object which closes over a subpath of this ParamValue's Path. */
30+
$isolateRootTo(stateName: string): ParamValues {
31+
return new ParamValues(this.$$path.pathFromRootTo(stateName));
3332
}
34-
}
33+
}

src/path/interface.ts

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,46 @@
1+
2+
import Path from "./../path/path";
3+
14
import {IState} from "../state/interface";
5+
26
import {IRawParams} from "../params/interface";
7+
import ParamValues from "../params/paramValues";
8+
39
import {IResolvables} from "../resolve/interface";
4-
import Path from "./../path/path";
10+
import ResolveContext from "../resolve/resolveContext";
11+
512

613
/** Base data (contains a state) for a node in a Path */
714
export interface INode {
815
state: IState
916
}
17+
/** A basic Path. Each node contains an IState */
18+
export interface IPath extends Path<INode> {}
1019

11-
/** Data, including raw params values, for a node in a Path */
20+
21+
/** Contains INode base data plus raw params values for the node */
1222
export interface IParamsNode extends INode {
1323
ownParams: IRawParams
1424
}
25+
/** A Path of IParamsNode(s) */
26+
export interface IParamsPath extends Path<IParamsNode> {}
1527

16-
/** Transition Data for a node in a Path (either to path or from path) */
28+
29+
/** Contains IParamsNode data, plus Resolvables for the node */
1730
export interface IResolveNode extends IParamsNode {
1831
ownResolvables: IResolvables
1932
}
33+
/** A Path of IResolveNode(s) */
34+
export interface IResolvePath extends Path<IResolveNode> {}
2035

21-
/** A basic Path. Each node contains the data necessary for a Transition to work. */
22-
export interface IPath extends Path<INode> {}
23-
/** A Params Path. Each node contains raw params data for each state */
24-
export interface IParamsPath extends Path<IParamsNode> {}
25-
/** A Transition Path. Each node contains the data necessary for a Transition to work. */
26-
export interface IResolvePath extends Path<IResolveNode> { }
36+
37+
/** Contains IResolveNode data, plus a ResolveContext and ParamsValues (bound to a full path) for the node, */
38+
export interface ITransNode extends IResolveNode {
39+
resolveContext: ResolveContext,
40+
paramValues: ParamValues
41+
}
42+
/**
43+
* A Path of ITransNode(s). Each node contains raw param values, Resolvables and also a ResolveContext
44+
* and ParamValues which are bound to the overall path, but isolated to the node.
45+
*/
46+
export interface ITransPath extends Path<ITransNode> {}

src/path/path.ts

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
/// <reference path='../../typings/angularjs/angular.d.ts' />
2-
import {extend, isArray, identity, noop,
2+
3+
import {extend, isArray, isString, identity, noop, Predicate,
34
defaults, map, omit, pluck, find, pipe, prop, eq} from "../common/common";
45
import trace from "../common/trace";
56
import {runtime} from "../common/angular1"
67
import {IPromise} from "angular";
78

89
import {INode, IParamsNode, IParamsPath} from "./interface";
910

10-
import {IState} from "../state/interface";
11-
11+
import {IState, IStateDeclaration, IStateOrName} from "../state/interface";
1212
import TargetState from "../state/targetState"
1313

1414
import {IResolvables} from "../resolve/interface";
1515
import Resolvable from "../resolve/resolvable";
1616

17+
const stateMatches = (state: IState|IStateDeclaration) => (node) => node.state === state || node.state.self === state;
18+
const stateNameMatches = (stateName: string) => (node) => node.state.name === stateName;
19+
const shallowNodeCopy = node => extend({}, node);
20+
1721
/**
1822
* A Path Object represents a Path of nested States within the State Hierarchy.
1923
* Each node of the path holds the IState object, and additional data, according
@@ -27,40 +31,62 @@ import Resolvable from "../resolve/resolvable";
2731
export default class Path<NODE extends INode> {
2832
constructor(private _nodes: NODE[]) { }
2933

30-
// returns a subpath of this path from the root path element up to and including the toPathElement parameter
31-
pathFromRootTo(toState: IState): Path<NODE> {
32-
var first = this._nodes.filter((node) => node.state === toState);
33-
var elementIdx = this._nodes.indexOf(first[0]);
34+
/**
35+
* returns a subpath of this path from the root path element up to and including the toState parameter.
36+
* Each node of the subpath is a shallow copy of the original node.
37+
*
38+
* @param toState A state or name of a state
39+
*/
40+
pathFromRootTo(toState: IStateOrName): Path<NODE> {
41+
let predicate = isString(toState) ? stateNameMatches(<string> toState) : stateMatches(<IState> toState);
42+
var node = find(this._nodes, predicate);
43+
var elementIdx = this._nodes.indexOf(node);
3444
if (elementIdx == -1) throw new Error("This Path does not contain the toPathElement");
3545
return this.slice(0, elementIdx + 1);
3646
}
3747

48+
/**
49+
* Returns a new Path which contains this Path's nodes, concatenated with another Path's nodes.
50+
* Each node of the concatenated Path is a shallow copy of the original nodes.
51+
*/
3852
concat(path: Path<NODE>): Path<NODE> {
39-
return new Path(this._nodes.concat(path._nodes));
53+
return new Path(this._nodes.concat(path._nodes).map(shallowNodeCopy));
4054
}
4155

56+
/**
57+
* Returns a new Path which is a subpath of this Path. The new Path contains nodes starting from "start" and
58+
* ending at "end". Each node of the subpath is a shallow copy of the original Path's node.
59+
*/
4260
slice(start: number, end?: number): Path<NODE> {
43-
return new Path(this._nodes.slice(start, end));
61+
return new Path(this._nodes.slice(start, end).map(shallowNodeCopy));
4462
}
4563

64+
/**
65+
* Returns a new Path which is a copy of this Path, but with nodes in reverse order.
66+
* Each node in the reversed path is a shallow copy of the original Path's node.
67+
*/
4668
reverse(): Path<NODE> {
47-
let copy = [].concat(this._nodes);
69+
let copy = [].concat(this._nodes).map(shallowNodeCopy);
4870
copy.reverse();
49-
return new Path(copy)
71+
return new Path(copy);
5072
}
5173

74+
/** Returns the "state" property of each node in this Path */
5275
states(): IState[] {
5376
return this._nodes.map(prop("state"));
5477
}
5578

56-
elementForState(state: IState): NODE {
79+
/** Gets the first node that exactly matches the given state */
80+
nodeForState(state: IState): NODE {
5781
return find(this._nodes, pipe(prop('state'), eq(state)));
5882
}
59-
83+
84+
/** Returns the Path's nodes wrapped in a new array */
6085
nodes(): NODE[] {
6186
return [].concat(this._nodes);
6287
}
6388

89+
/** Returns the last node in the Path */
6490
last(): NODE {
6591
return this._nodes.length ? this._nodes[this._nodes.length - 1] : null;
6692
}

0 commit comments

Comments
 (0)