-
-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathadvise.js
121 lines (114 loc) · 3.56 KB
/
advise.js
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
/* UMD.define */ (typeof define=='function'&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))})
([], function () {
'use strict';
function Node (instance, name) {
this.next_before = this.prev_before =
this.next_after = this.prev_after =
this.next_around = this.prev_around = this;
this.instance = instance;
this.name = name;
}
var p = Node.prototype = {
add: function (before, after, around, original) {
var node = new Node(this.instance, this.name);
node.parent = this;
node.before = before;
this._add('before', node);
node.after = after;
this._add('after', node);
node.around = around;
this._add('around', node, original);
node.original = original;
if (original) {
node.around = advise._instantiate(original, node.prev_around.around, this);
}
return node;
},
_add: function (topic, node, flag) {
if (node[topic] || flag) {
var n = 'next_' + topic, p = 'prev_' + topic;
(node[p] = this[p])[n] = (node[n] = this)[p] = node;
}
},
remove: function (node) {
this._remove('before', node);
this._remove('after', node);
this._remove('around', node);
},
_remove: function (topic, node) {
var n = 'next_' + topic, p = 'prev_' + topic;
node[n][p] = node[p];
node[p][n] = node[n];
},
destroy: function () {
var around = this.prev_around.around, t = this.next_around, parent = this.parent;
this.remove(this);
if (t !== this) {
for (; t !== parent; around = t.around, t = t.next_around) {
if (t.original) {
t.around = advise._instantiate(t.original, around, this);
}
}
}
this.instance = 0;
}
};
p.unadvise = p.destroy; // alias
function makeAOPStub (node) {
var stub = function () {
var result, thrown, p;
// running the before chain
for (p = node.prev_before; p !== node; p = p.prev_before) {
p.before.apply(this, arguments);
}
// running the around chain
if (node.prev_around !== node) {
try {
result = node.prev_around.around.apply(this, arguments);
} catch (error) {
result = error;
thrown = true;
}
}
// running the after chain
for (p = node.next_after; p !== node; p = p.next_after) {
p.after.call(this, arguments, result, makeReturn, makeThrow);
}
if (thrown) {
throw result;
}
return result;
function makeReturn (value) { result = value; thrown = false; }
function makeThrow (value) { result = value; thrown = true; }
};
stub.adviceNode = node;
return stub;
}
function advise (instance, name, advice) {
var f = instance[name], node;
if (f && f.adviceNode && f.adviceNode instanceof Node) {
node = f.adviceNode;
} else {
node = new Node(instance, name);
if (f && f.advices) {
f = f.advices;
f.before.slice(0).reverse().forEach(function (f) { node.add(f); });
f.after.forEach(function (f) { node.add(null, f); });
node.add(null, null, f.around);
} else {
node.add(null, null, f);
}
instance[name] = makeAOPStub(node);
}
if (typeof advice == 'function') {
advice = advice(name, instance);
}
return node.add(advice.before, advice.after, null, advice.around);
}
advise.before = function(instance, name, f){ return advise(instance, name, {before: f}); };
advise.after = function(instance, name, f){ return advise(instance, name, {after: f}); };
advise.around = function(instance, name, f){ return advise(instance, name, {around: f}); };
advise.Node = Node;
advise._instantiate = function(advice, previous, node){ return advice(previous); };
return advise;
});